WINCE下虚拟串口驱动设计

http://www.pe168.com/com/verygo/news/itemid-403369.html

 

现在的车载和pnd设备都有自动校正系统时间的功能,实现方法一般是通过gps较时(当然对于有cmmb模块的设备也可以通过cmmb校时)。 但由于串口设备是一个独占设备,gps串口不能同时被导航软件和校时程序使用。如果此时导航软件正在运行,gps校时程序是无法访问gps串口的。

在这样的情况下,我们就需要创建一个非独占性质的串口设备,将一个物理串口虚拟成多个串口来使用。 虚拟串口驱动通过打开物理串口并监听物理串口事件,当物理串口有数据过来是将数据保存到缓存中供多个不同的虚拟串口使用。这样通过虚拟的方式实现了同一物理串口在多个程序之间的数据共享。

基于上述思想,采用了如下设计。(这里设定驱动的前缀为com,与物理串口驱动的前缀保持一致,这样应用层可以像访问物理串口驱动一样访问虚拟串口驱动。)

1. 在com_open()函数中打开物理串口,并创建线程monitorcommeventproc用于监听并处理物理串口数据。

2. 定义两个buffer,分别保存两个虚拟串口的数据信息,buffer的设计采用循环队列的方式。

3. 在监听线程monitorcommeventproc中监听物理串口事件,当物理串口有数据过来时读取数据并将数据分别保存到两个buffer里。

4. 在com_read()函数中实现读取buffer中的数据。

5. 在com_iocontrol()函数中实现相应控制码接口。如ioctl_serial_set_wait_mask,ioctl_serial_wait_on_mask、ioctl_serial_get_commstatus、ioctl_serial_purge等。

monitorcommeventproc监听线程参考代码:

5. 在com_iocontrol()函数中实现相应控制码接口。如ioctl_serial_set_wait_mask,ioctl_serial_wait_on_mask、ioctl_serial_get_commstatus、ioctl_serial_purge等。

monitorcommeventproc监听线程参考代码:

code: select all
//we use this program to always read the physical serial data
dword monitorcommeventproc(lpvoid PParam)
{
interlockedexchange(reinterpret_cast<long *>(&g_bmonitorprocrunning),true);
unsigned char vtbufread[read_buffer_length];
while(true)
{
if(g_bexitmonitorproc != false)
{
retailmsg(true,(text("monitorcommeventproc stop!,r,n")));
//if com is closed,we will stop to read
break;
}

dword dwevtmask = 0;
setcommmask (g_hcom, g_dwwaitmask | ev_rxchar);
// wait the physical serial event
if(waitcommevent(g_hcom,&dwevtmask,null)&&(dwevtmask & ev_rxchar))
{
setcommmask (g_hcom, g_dwwaitmask | ev_rxchar); {
comstat cmstate;
dword dwreaderrors;
clearcommerror(g_hcom,&dwreaderrors,&cmstate);
dword willreadlen = cmstate.cbinque ;
if (willreadlen <= 0)
continue;
dword dwread = 0;
readfile(g_hcom,vtbufread,willreadlen,&dwread,null);
entercriticalsection(&g_csread1);
entercriticalsection(&g_csread2);
if(g_bcomstate1==com_status_open)
{
writebuffer(g_ucdatebuf1,read_buffer_length,vtbufread,dwread, &g_dwdatebufhead1,&g_dwdatebuftail1);
}
if(g_bcomstate2==com_status_open)
{
writebuffer(g_ucdatebuf2,read_buffer_length,vtbufread,dwread, &g_dwdatebufhead2,&g_dwdatebuftail2);
}
leavecriticalsection(&g_csread2);
leavecriticalsection(&g_csread1);
interlockedexchange(reinterpret_cast<long *>(&g_dwevtmask),dwevtmask);
pulseevent(g_hcanreadevent);
printf("pulseevent g_hcanreadevent...,n");
// sleep for other thread to respond to the event,very important..
sleep(1);
}
}
interlockedexchange(reinterpret_cast<long *>(&g_bmonitorprocrunning),false);
return 0;
}

com_iocontrol()函数多数控制码的实现可以直接调用物理串口deviceiocontrol()来处理,但有些控制码需要自己实现,比如清空缓存,不能直接调用deviceiocontrol()来清空物理串口的数据,而是应该清空虚拟串口buffer中的数据。几个重要控制码实现的参考代码:
bool
com_iocontrol(handle dwhandle,
dword dwiocontrolcode, pbyte pbufin,
dword dwbufinsize, pbyte pbufout, dword dwbufoutsize,
pdword pbytesreturned)

{
switch(dwiocontrolcode)
{
case ioctl_serial_set_wait_mask:
//printf("serial command: serial_set_wait_mask,n");
if(g_uiopencount==1)
{
g_dwwaitmask = *reinterpret_cast<dword *>(pbufin);
return deviceiocontrol(g_hcom, ioctl_serial_set_wait_mask,pbufin, dwbufinsize,pbufout,dwbufoutsize,pbytesreturned,null);
}
else
return true;
case ioctl_serial_wait_on_mask:
{
pvsp_info popenhead = (pvsp_info) dwhandle;
// return immediately if the buffer has the available data
if(*(popenhead->bufferhead)!=*(popenhead->buffertail))
return true;
if(dwbufoutsize < sizeof(dword) || waitforsingleobject(g_hcanreadevent,infinite) == wait_timeout)
{
*pbytesreturned = 0;
return false;
}
else
{
interlockedexchange(reinterpret_cast<long *>(pbufout),g_dwevtmask);
*pbytesreturned = sizeof(dword);
return true;
}
}
case ioctl_serial_purge:
{
//clean the virtual serial buffer
pvsp_info popenhead = (pvsp_info) dwhandle;
*(popenhead->bufferhead)=0;
*(popenhead->buffertail)=0;
return true;
}
.....
}
return false;
}
buffer(循环队列)读写操作参考代码:

void writebuffer(puchar targetbuffer,dword longoftarget,puchar sourcebuffer,
dword numinsource,dword *bufferhead,dword *buffertail)
{
bool changehead = false;
dword i=*buffertail;
dword j=0;
if(numinsource >= longoftarget)
{
memcpy(targetbuffer,sourcebuffer,longoftarget);
*bufferhead=0;
*buffertail=longoftarget-1;
return;
}
else
{
for(;j<numinsource;j++)
{
targetbuffer[i++]=sourcebuffer[j];
if(i>=longoftarget)
{
i=0;
}
if(i==(*bufferhead))
{
changehead=true;
}
}
if(changehead==false)
{

*buffertail=i;
return;
}
else
{
*buffertail=i;
*bufferhead=i+1;
return;
}
}
}

dword readbuffer(puchar targetbuffer,puchar sourcebuffer,dword sizeoftargebuf,
dword longofsourcebuf,dword *bufferhead,dword *buffertail)
{
dword i=0;
dword j=*bufferhead;
bool isempty=false;
for(i=0;i<sizeoftargebuf;i++)
{
if(j==(*buffertail))
{
isempty=true;
break;
}
targetbuffer[i]=sourcebuffer[j++];
if(j>=longofsourcebuf)
{
j=0;
}
}
if(isempty==false)
{
*bufferhead=j;
}
else
{
(*bufferhead)=(*buffertail)=0;
}
return i;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值