I am working on an embedded ARM platform and wish to have control over some of the GPIO pins. I've experience in C and am a newcomer to C#. It seems that controlling low-level hardware is difficult from managed-code applications. I have Windows CE6.0 and .NET Compact Framework 2 running on my hardware.
I've found an example, written in C++ that would allow me access to GPIO port pins, however, I am struggling to implement the example in C#.
The following snippet shows how DeviceIOcontrol is used to control port pins:
const struct pio_desc hw_pio[] =
{
{"LED1", AT91C_PIN_PA(13), 0, PIO_DEFAULT, PIO_OUTPUT},
{"LED2", AT91C_PIN_PA(14), 0, PIO_DEFAULT, PIO_OUTPUT},
};
T_GPIOIOCTL_STATE * pSetState;
T_GPIOIOCTL_STATE * pGetState;
// Configure PIOs
bSuccessDevIOC = DeviceIoControl(hGPIO, IOCTL_GPIO_CONFIGURE, (LPBYTE*)hw_pio, sizeof(hw_pio), NULL, 0, NULL, NULL);
Other definitions:
struct pio_desc
{
const char *pin_name; /* Pin Name */
unsigned int pin_num; /* Pin number */
uns开发者_开发技巧igned int dft_value; /* Default value for outputs */
unsigned char attribute;
enum pio_type type;
};
/* I/O type */
enum pio_type
{
PIO_PERIPH_A,
PIO_PERIPH_B,
PIO_INPUT,
PIO_OUTPUT,
PIO_UNDEFINED
};
/* I/O attributes */
#define PIO_DEFAULT (0 << 0)
#define PIO_PULLUP (1 << 0)
#define PIO_DEGLITCH (1 << 1)
#define PIO_OPENDRAIN (1 << 2)
The following is the C# definition of DeviceIOControl. The problem parameter is lpInBuffer.
[DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
internal static extern bool DeviceIoControlCE(int hDevice,
int dwIoControlCode,
byte[] lpInBuffer,
int nInBufferSize,
byte[] lpOutBuffer,
int nOutBufferSize,
ref int lpBytesReturned,
IntPtr lpOverlapped);
The questions:
How does one create these equivalent structures in C#? How does one pass these as a byte array (byte[] lpInBuffer) to the DeviceIOControl function?
Any assistance appreciated!
Use some interop decoration, for instance, a structure like following:
typedef struct
{
char Data[MAXCHARS];//assuming a #define MAXCHARS 15
int Values[MAXCHARS];
} StSomeData;
would look like following in C#:
[StructLayout(LayoutKind.Sequential)]
private struct StSomeData
{
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 15)]
public string Data;
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 15)]
public int[] Values;
}
And use it like: StSomeData[] array = new StSomeData[3];
Note that you can use IntPtr
when dealing with pointers.
For instance your call to:
DeviceIoControl(hGPIO, IOCTL_GPIO_CONFIGURE, (LPBYTE*)hw_pio
, sizeof(hw_pio), NULL, 0, NULL, NULL);
may look something like following:
IntPtr ipByte;
Marshal.StructureToPtr(StLPByte, ipByte,false);
IntPtr ipConfig;
Marshal.StructureToPtr(StIOCTL_GPIO_CONFIGURE, ipConfig, false);
IntPtr iphGPIO;
Marshal.StructureToPtr(SthGPIO, iphGPIO, false);
bool bSuccessDevIOC = DeviceIoControl(iphGPIO
, ipConfig
, ipByte
, Marshal.SizeOf(typeof(StLPByte))
, IntPtr.Zero
, IntPtr.Zero
, IntPtr.Zero
, IntPtr.Zero);
Also, you can look into the usage of unsafe
keyword and try put your code within unsafe blocks; this may be a dirty solution since this code wont be a managed code.
a byte[] is converted to LPBYTE automatically
a char* in c# is equivalent to unsigned short* in c++
a byte* in c# is a unsigned char* in c++
c#-enums behave similar enough to c++ enums. you may just write it
one important thing:
[StructLayout(LayoutKind.Sequential,Pack=1)]
精彩评论