英创信息技术嵌入式系统设备驱动接口的C#编程

英创arm9系列嵌入式主板,均预装了wince 5.0、wince 6.0操作系统,用户可使用标准的c/c++或c#进行应用程序的开发。英创的嵌入式板卡一大特色就是提供了丰富的通讯接口,并实现了相应的驱动程序,用户只需直接调用相应的接口函数即可实现。
在使用c#进行应用程序开发时,由于c#无法使用c++的静态库函数,对于一些流式驱动设备,比如isa,gpio,wdt,can,spi,irq等,没有封装好的库函数可操作,如果希望控制它们,一种办法是使用c编写com组件,在com组件中调用英创提供的相应主板sdk包里的静态库函数;另一种方法是直接调用api函数来访问设备驱动。
对于大多数的流式驱动设备,应用程序使用的一般过程:
1、通过creatfile打开设备,获得设备句柄。
2、使用readfile读取数据,使用writefile发送数据,以及使用deviceiocontrol对设备驱动进行设置、读写等操作。
3、使用完毕,用closehandle关闭设备。
在一般情况下,设备的专用功能都是通过deviceiocontrol来实现的,因此如何通过c#编程来操作deviceiocontrol尤为重要。本文以英创arm9嵌入式主板em9170为例,介绍如何使用deviceiocontrol来操作主板的isa接口进行读写。gpio,wdt,can,spi,irq等其他流式设备的操作请参看英创开发光盘内提供的相关例程。
1、deviceiocontrol函数的定义
在wince中核心库为coredll.dll,相当于window的kernel32.dll和user32.dll。要调用核心库,首先需要在代码中添加引用:
using system.runtime.interopservices;
在c#中deviceiocontrol及creatfiles,closehandle函数声明,及相关变量定义方法如下(该写法并不固定)。
[dllimport('coredll.dll', entrypoint = 'createfile', charset = charset.unicode)]
private static extern int createfile(string lpfilename,
uint dwdesiredaccess,
uint dwsharemode,
int lpsecurityattributes,
int dwcreationdisposition,
int dwflagsandattributes,
int htemplatefile);
[dllimport('coredll.dll', entrypoint = 'closehandle')]
private static extern int closehandle(int hobject);
[dllimport('coredll.dll', entrypoint = 'deviceiocontrol')]
private static extern bool deviceiocontrol(int hdevice,
uint dwiocontrolcode,
byte[] lpinbuf,
uint ninbufsize,
byte[] lpoutbuf,
uint noutbufsize,
ref uint lpbytesreturned,
uint lpoverlapped);
deviceiocontrol函数参数分析:
参数 定义
hdevice 设备句柄
handle类型
c#中可以对应成int或uint或intptr
通过creatfiles获得
dwiocontrolcode 驱动控制命令
dword类型
c#中可以对应成int或uint
不同设备该值定义不同,根据该参数lpinbuffer,ninbufsize,lpoutbuf,noutbufsize参数定义也不同,在c中,该值的宏定义为
#define ctl_code(devicetype, function, method, access) (
((devicetype) << 16) | ((access) << 14) | ((function) << 2) | (method) )
根据devicetype, function, method, access转换而来
在前面代码中为英创嵌入式主板em9170的isa及gpio的ctl_code值定义,比如gpio输出控制的ctl_code定义
private const uint gpio_ioctl_out_enable = (file_device_bus_extender << 16) | (file_any_access << 14) | ( 3900<< 2) | (method_buffered);
更多的dwiocontrolcode值定义和输入输出参数定义请参看英创相关例程
lpinbuffer 输入buffer
lpvoid类型
c#中可以对应成byte[]或ref struct等,也可以使用unsafe传递指针
应用程序传递给驱动的数据指针
一般用byte[]的通用性好些,对于需要传递结构体指针的地方,可以使用marshal类的方法拷贝结构体到byte数组内,或者直接根据struct成员值修改byte数组的相应位
ninbufsize 输入buffer长度
dword类型
如果deviceiocontrol操作无输出buffer,一般lpinbuffer为null,ninbufsize为0
lpoutbuf 输出buffer
lpvoid类型
noutbufsize 输入buffer长度
dword类型
lpbytesreturned 操作程序实际返回的字节数指针
lpdword类型
c#中一般对应为ref uint
lpoverlapped 重叠操作结构
没有使用,定为uint传0,或者intptr传intptr.zero
在c#调用外部dll时,可以用uint来对应dword,用ref uint来对应lpdword,用intptr来对应各种指针,更通用的,可以直接使用byte[]来对应各种指针。
2、deviceiocontrol函数的操作实例
以英创嵌入式主板em9170的isa操作为例,以下代码包括了creatfile需要的参数定义,isa操作的ioctl定义,和isa的deviceiocontrol操作传入参数结构体的定义,和封装deviceiocontrol的两个isa函数定义。
主函数操作程序打开isa设备,并操作isa输出输入,最后关闭设备。
private const uint generic_read = 0x80000000;
private const uint generic_write = 0x40000000;
private const uint file_share_read = 0x00000001;
private const uint file_share_write = 0x00000002;
private const int open_existing = 3;
private const int file_flag_random_access = 0x10000000;
//------------------------bsp_drivers----------------------------------
//winioctl
private const uint file_device_bus_extender = 0x0000002a;
private const uint method_buffered = 0;
private const uint file_any_access = 0;
// isa io control codes
private const uint isa_ioctl_read_write = (file_device_bus_extender << 16) | (file_any_access << 14) | (3910 << 2) | (method_buffered);
private const uint isa_ioctl_bus_reset = (file_device_bus_extender << 16) | (file_any_access << 14) | (3911 << 2) | (method_buffered);
//------------------------bsp_drivers_end------------------------------
[structlayout(layoutkind.explicit, size = 16)]
public struct isa_bus_access
{
[fieldoffset(0)]public uint dwcmd; // = 0: read, = 1: write
[fieldoffset(4)]public uint dwseg; // = 0: isa_cs0, = 1: isa_cs1
[fieldoffset(8)]public uint dwoffset;
[fieldoffset(12)]public uint dwvalue; // only lower byte valid
}
public static int openisa_dio(string devname)
{
int handle;
handle = createfile(devname,
generic_read | generic_write,
file_share_read | file_share_write, // sharing mode
0, // security attributes (ignored)
open_existing, // creation disposition
file_flag_random_access, // flags/attributes
0);
return handle;
}
public static bool closeisa_dio(int hisa_dio)
{
if (hisa_dio != 0)
{
if (closehandle(hisa_dio) != 0)
{
return false;
}
}
return true;
}
public static bool isa_read(int hisa_dio, int nseg, uint noffset, ref byte prdvalue)
{
isa_bus_access isabus;
uint lpbytesreturned = 0;
isabus.dwcmd = 0;
isabus.dwseg = (uint)nseg;
isabus.dwoffset = noffset;
isabus.dwvalue = 0;
int size = marshal.sizeof(typeof(isa_bus_access));
byte[] lpintbuf = new byte[size];
intptr buffer = marshal.allochglobal(size);
try
{
marshal.structuretoptr(isabus, buffer, false);
marshal.copy(buffer, lpintbuf, 0, size);
}
finally
{
marshal.freehglobal(buffer);
}
byte[] lpoutbuf = new byte[sizeof(byte)];
if (!deviceiocontrol(hisa_dio, // file handle to the driver
isa_ioctl_read_write, // i/o control code
lpintbuf, // in buffer
(uint)size, // in buffer size
lpoutbuf, // out buffer
sizeof(byte), // out buffer size
ref lpbytesreturned, // pointer to number of bytes returned
0)) // ignored (=null)
{
return false;
}
prdvalue = lpoutbuf[0];
return true;
}
public static bool isa_write(int hisa_dio, int nseg, uint noffset, byte ucwrvalue)
{
isa_bus_access isabus;
uint lpbytesreturned = 0;
isabus.dwcmd = 1;
isabus.dwseg = (uint)nseg;
isabus.dwoffset = noffset;
isabus.dwvalue = (uint)ucwrvalue;
int size = marshal.sizeof(typeof(isa_bus_access));
byte[] lpintbuf = new byte[size];
intptr buffer = marshal.allochglobal(size);
try
{
marshal.structuretoptr(isabus, buffer, false);
marshal.copy(buffer, lpintbuf, 0, size);
}
finally
{
marshal.freehglobal(buffer);
}
if (!deviceiocontrol(hisa_dio, // file handle to the driver
isa_ioctl_read_write, // i/o control code
lpintbuf, // in buffer
(uint)size, // in buffer size
null, // out buffer
0, // out buffer size
ref lpbytesreturned, // pointer to number of bytes returned
0)) // ignored (=null)
{
return false;
}
return true;
}
static void main(string[] args)
{
const int isa_cs1 = 1;
int hisa;
hisa = openisa_dio('isa1:');
if( hisa == -1 )
{
console.write('open isa_dio device fail!');
return;
}
bret = isa_write(hisa, isa_cs1, 0, b);
bret = isa_read(hisa, isa_cs1, 0, ref b);
closeisa_dio(hisa);
return;
}
3、传递结构体的操作说明
该例程的isa_read,isa_write和函数中,deviceiocontrol的参数lpintbuf需要传递一个结构体指针,关于结构体的操作需要按以下步骤。
所以首先需要定义一个和接口定义相同的结构体,在c#中定义与c接口的结构体需要使用structlayout字段声明结构体的大小,和对齐规则。
在每个成员前面用fieldoffset字段设定该成员在结构体中的偏移。
[structlayout(layoutkind.explicit, size = 16)]
public struct isa_bus_access
{
[fieldoffset(0)]public uint dwcmd; // = 0: read, = 1: write
[fieldoffset(4)]public uint dwseg; // = 0: isa_cs0, = 1: isa_cs1
[fieldoffset(8)]public uint dwoffset;
[fieldoffset(12)]public uint dwvalue; // only lower byte valid
}
然后设定结构体各成员值,将结构体拷贝到byte[]中,在c#中将结构体拷贝到byte数组需要使用marshal类。
首先计算结构体大小
int size = marshal.sizeof(typeof(isa_bus_access));
创建一个byte[]
byte[] lpintbuf = new byte[size];
用allochglobal申请一块非托管空间,并获得该空间的指针
intptr buffer = marshal.allochglobal(size);
然后用structuretoptr将结构体拷贝到指针位置,再用copy将指针位置数据拷贝到byte数组。因为之前申请了内存空间,使用try-finally确报用freehglobal释放空间
try
{
marshal.structuretoptr(isabus, buffer, false);
marshal.copy(buffer, lpintbuf, 0, size);
}
finally
{
marshal.freehglobal(buffer);
}
以上操作包括空间申请与释放,效率并不高,为提高效率,应当将结构体成员变量值直接赋值到byte数组相应位置,如:
isa_bus_access isabus;
isabus.dwcmd = 1;
修改为
lpintbuf[3] = 1;
注意整数的低位在高地址。
4、英创em9170其他使用deviceiocontrol操作的设备dwiocontrolcode值定义
//------------------------bsp_drivers----------------------------------
//winioctl
private const uint file_device_bus_extender = 0x0000002a;
private const uint method_buffered = 0;
private const uint file_any_access = 0;
// gpio io control codes
private const uint gpio_ioctl_out_enable = (file_device_bus_extender << 16) | (file_any_access << 14) | ( 3900<< 2) | (method_buffered);
private const uint gpio_ioctl_out_disable = (file_device_bus_extender << 16) | (file_any_access << 14) | (3901 << 2) | (method_buffered);
private const uint gpio_ioctl_out_set = (file_device_bus_extender << 16) | (file_any_access << 14) | (3902 << 2) | (method_buffered);
private const uint gpio_ioctl_out_clear = (file_device_bus_extender << 16) | (file_any_access << 14) | (3903 << 2) | (method_buffered);
private const uint gpio_ioctl_pin_state = (file_device_bus_extender << 16) | (file_any_access << 14) | (3904 << 2) | (method_buffered);
// isa io control codes
private const uint isa_ioctl_read_write = (file_device_bus_extender << 16) | (file_any_access << 14) | (3910 << 2) | (method_buffered);
private const uint isa_ioctl_bus_reset = (file_device_bus_extender << 16) | (file_any_access << 14) | (3911 << 2) | (method_buffered);
//private const uint isa_ioctl_reda_cs1 = (file_device_bus_extender << 16) | (file_any_access << 14) | (3912 << 2) | (method_buffered);
//private const uint isa_ioctl_write_cs1 = (file_device_bus_extender << 16) | (file_any_access << 14) | (3913 << 2) | (method_buffered);
// spi io control codes
private const uint cspi_ioctl_exchange = (file_device_bus_extender << 16) | (file_any_access << 14) | (3030 << 2) | (method_buffered);
// irq io control codes
private const uint ioctl_wait_for_irq = (file_device_bus_extender << 16) | (file_any_access << 14) | (3920 << 2) | (method_buffered);
private const uint ioctl_send_eoi = (file_device_bus_extender << 16) | (file_any_access << 14) | (3921 << 2) | (method_buffered);
//------------------------bsp_drivers_end------------------------------

三星、Moto接连发布折叠屏手机新品,产品升级高价依旧
Google即将停止其Chrome浏览器的付费扩展
人工智能和5G网络时代即将来临,给高多层板带来新的增长点
福建安芯半导体再次出货一台光刻机 实现60%至70%的国产化
智能锁行业一片蓝海 市场前景非常广阔
英创信息技术嵌入式系统设备驱动接口的C#编程
魅族Pro7、魅族MX7最新消息:魅族Pro7、魅族MX7渲染图曝光就长这样!或采用双屏幕交互!
带你们认识一下早期的电子技术
巍泰技术毫米波客流统计雷达在门店、商场、购物中心客流统计中除保护隐私外,还有哪些应用优势?
无功补偿柜更换电容器需要注意啥
在“红四月”的高歌猛进中 空调市场已经走过“忐忑”的第一季度
时间敏感网络解决方案弥合了工业物联网中的通信缺口
智慧医院助力医疗资源再分配 政策为智慧医疗插上双翼
物联网设备的过去和未来以及用途分析
峰米在《LED智能投影仪技术规范》讨论会中给出专业意见
恒生电子总裁刘曙峰:一个特别重要的挑战就是能不能跟得上这个变化
智能制造的技术变革和管理变革两者之间有什么关系
石化行业挥发性有机物VOCs在线监测解决方案
德国电信运营商Deutsche Telekom推自制云游戏服务
承德科胜半自动浆糊贴标机|白酒贴标机|河北贴标机