In my article on reading and writing GPIO pins from a driver (see Windows CE: Using a Driver to Read/Write Hardware Registers) I developed a driver that exposes GPIO pins through DeviceIoControl() calls to the driver’s XXX_IOControl() function.   Using DeviceIoControl() can be messy, so developing wrapper functions helps clean that up, but if the driver developer also created the wrapper and provided it as an API that would help.
An API is really just a lib file, or DLL, that exposes some functions.   In this case, we will expose the functions from a statically linked library, but it would be a very minor change to provide them as a DLL included in the OS.
To start, this API will provide a init and deinit functions that will gain access to the driver through CreateFile() and then clean up with CloseHandle():
HANDLE InitGPIOAPI()
{
                HANDLE hDriver;
 
                // Get a handle to the driver. Which causes the driver's XXX_Open function to be called
                hDriver = CreateFile( TEXT("XXX1:"), GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
               
                return hDriver;
}
 
void DeinitGPIOAPI( HANDLE hDriver )
{
                CloseHandle( hDriver );
}
Now we wrapper each of the IOCTL calls:
BOOL SetGPIOPin( HANDLE hDriver, DWORD PinNumber )
{
                DWORD BytesHandled;
 
                return DeviceIoControl( hDriver,
                                IOCTL_SET_GPIO,
                                &PinNumber,
                                sizeof( PinNumber ),
                                NULL,
                                0,
                                &BytesHandled,
                                NULL );
}
 
BOOL ClearGPIOPin( HANDLE hDriver, DWORD PinNumber )
{
                DWORD BytesHandled;
 
                return DeviceIoControl( hDriver,
                                IOCTL_CLEAR_GPIO,
                                &PinNumber,
                                sizeof( PinNumber ),
                                NULL,
                                0,
                                &BytesHandled,
                                NULL );
}
 
BOOL SetInputGPIOPin( HANDLE hDriver, DWORD PinNumber )
{
                DWORD BytesHandled;
 
                return DeviceIoControl( hDriver,
                                IOCTL_SET_INPUT_GPIO,
                                &PinNumber,
                                sizeof( PinNumber ),
                                NULL,
                                0,
                                &BytesHandled,
                                NULL );
}
 
BOOL SetOutputGPIOPin( HANDLE hDriver, DWORD PinNumber )
{
                DWORD BytesHandled;
 
                return DeviceIoControl( hDriver,
                                IOCTL_SET_OUTPUT_GPIO,
                                &PinNumber,
                                sizeof( PinNumber ),
                                NULL,
                                0,
                                &BytesHandled,
                                NULL );
}
 
BOOL ReadGPIOPin( HANDLE hDriver, DWORD PinNumber )
{
                DWORD BytesHandled;
                DWORD GPIOValue;
 
                DeviceIoControl( hDriver,
                                IOCTL_READ_GPIO,
                                &PinNumber,
                                sizeof( PinNumber ),
                                &GPIOValue,
                                sizeof(GPIOValue),
                                &BytesHandled,
                                NULL );
 
                return GPIOValue & 1;
}
See how simple that was? And our application developers will love us for it because their code can be very simple. This code will even be easy for them to use from C# with a simple P/Invoke.
The sources file is straight forward for those of you using Platform Builder:
TARGETNAME=GPIO_API
TARGETTYPE=LIBRARY
RELEASETYPE=PLATFORM
 
SOURCES= \
                GPIO_API.c
 
INCLUDES=$(INCLUDES);..\Inc
To turn this into a DLL, simply change the TARGETTYPE to DYNLINK and add a def file.
Copyright © 2010 – Bruce Eitman
All Rights Reserved