当前位置: 首页 > news >正文

上海做营销网站哪个公司好网站外部外链建设

上海做营销网站哪个公司好,网站外部外链建设,薛城区住房和城乡建设局网站,网站设计是什么出处#xff1a;http://blog.csdn.net/firehood_/article/details/6195558 现在的车载和PND设备都有自动校正系统时间的功能#xff0c;实现方法一般是通过GPS较时#xff08;当然对于有CMMB模块的设备也可以通过CMMB校时#xff09;。 但由于串口设备是一个独占设备http://blog.csdn.net/firehood_/article/details/6195558   现在的车载和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_MASKIOCTL_SERIAL_WAIT_ON_MASK、IOCTL_SERIAL_GET_COMMSTATUS、IOCTL_SERIAL_PURGE等。 MonitorCommEventProc监听线程参考代码 [cpp]  view plain copy //we use this program to always read the  physical serial data   DWORD MonitorCommEventProc(LPVOID pParam)   {        InterlockedExchange(reinterpret_castLONG *(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_bComState1COM_STATUS_OPEN)               {                   WriteBuffer(g_ucDateBuf1,READ_BUFFER_LENGTH,vtBufRead,dwRead, g_dwDateBufHead1,g_dwDateBufTail1);               }               if(g_bComState2COM_STATUS_OPEN)               {                   WriteBuffer(g_ucDateBuf2,READ_BUFFER_LENGTH,vtBufRead,dwRead, g_dwDateBufHead2,g_dwDateBufTail2);               }                           LeaveCriticalSection(g_csRead2);               LeaveCriticalSection(g_csRead1);               InterlockedExchange(reinterpret_castLONG *(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_castLONG *(g_bMonitorProcRunning),FALSE);        return 0;   }   COM_IOControl()函数多数控制码的实现可以直接调用物理串口DeviceIoControl()来处理但有些控制码需要自己实现比如清空缓存不能直接调用DeviceIoControl()来清空物理串口的数据而是应该清空虚拟串口Buffer中的数据。几个重要控制码实现的参考代码 [cpp]  view plain copy 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_uiOpenCount1)               {                   g_dwWaitMask  *reinterpret_castDWORD *(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_castLONG *(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(循环队列)读写操作参考代码 [cpp]  view plain copy void WriteBuffer(PUCHAR targetBuffer,DWORD LongOfTarget,PUCHAR sourceBuffer,       DWORD NumInSource,DWORD *BufferHead,DWORD *BufferTail)   {       BOOL ChangeHead  FALSE;       DWORD i*BufferTail;       DWORD j0;       if(NumInSource  LongOfTarget)       {           memcpy(targetBuffer,sourceBuffer,LongOfTarget);           *BufferHead0;           *BufferTailLongOfTarget-1;           return;       }       else       {           for(;jNumInSource;j)           {               targetBuffer[i]sourceBuffer[j];               if(iLongOfTarget)               {                   i0;               }               if(i(*BufferHead))               {                   ChangeHeadTRUE;               }              }           if(ChangeHeadFALSE)           {                              *BufferTaili;               return;           }           else           {               *BufferTaili;               *BufferHeadi1;               return;           }       }   }      DWORD ReadBuffer(PUCHAR targetBuffer,PUCHAR sourceBuffer,DWORD SizeOfTargeBuf,       DWORD LongOfSourceBuf,DWORD *BufferHead,DWORD *BufferTail)   {       DWORD i0;       DWORD j*BufferHead;       BOOL IsEmptyFALSE;       for(i0;iSizeOfTargeBuf;i)       {           if(j(*BufferTail))           {               IsEmptyTRUE;               break;           }           targetBuffer[i]sourceBuffer[j];           if(jLongOfSourceBuf)           {               j0;           }       }       if(IsEmptyFALSE)       {           *BufferHeadj;       }       else       {           (*BufferHead)(*BufferTail)0;       }       return i;   }   参考资料《WinCE虚拟串口驱动》http://blog.csdn.net/norains/archive/2009/03/28/4032257.aspx  作者norains 感谢 norains大侠无私的奉献。 关于虚拟串口 出处http://blog.csdn.net/lovelynn/article/details/4466215 我们有一个GPS模块连接在COM3上现在有两个应用程序都需要读取COM3的内容然而WinCE的串口为独占式的串口因此我们需要一个驱动程序将COM3虚拟成COM4和COM5来供应用程序使用。下面我来介绍一下驱动程序的设计。 首先我们要解决虚拟串口驱动加载的问题 加载方法一 在本程序中加载过程需要两个函数来完成一个是虚拟串口驱动的 COM_Init()另一个是 RegisterDevice()我们将在应用程序中使用RegisterDevice()来启动COM_Init()完成虚拟串口驱动的加载。在应用程序中加载虚拟串口驱动的代码如下 DWORD VirComNO 4;     HANDLE hRes RegisterDevice (LCOM, VirComNO, LGPSCOM.dll, (DWORD) VirComNO); RegisterDevice函数的用法参见文档说明。 通过这个函数我们就会调用device.exe在系统中添加了一个名为COM4的设备GPSCOM.dll中的流接口COM_Init()会被调用。 加载方法二 当然我们也可以在系统启动时让device.exe直接加载本驱动。 下面我们来看COM_Init()的实现 HANDLE COM_Init(         ULONG   Identifier         ) {              PHW_INDEP_INFO  pSerialHead NULL;     // Allocate our control structure. //创建一个结构体用来记录设备信息     pSerialHead    (PHW_INDEP_INFO)LocalAlloc(LPTR, sizeof(HW_INDEP_INFO));     pSerialHead-pAccessOwner NULL;         ...... //add com Identifier //如果我们创建的是COM5这个设备那么把COM5的相关信息记录在pSerialHead中。         if(5Identifier)         {               RETAILMSG(DEBUG_COM2,(L PLATFORM      fwq  COM_init5  /r/n));                 pSerialHead-COMNUM 5;                 g_pCircleBuffer5 CP_CreateCircleBuffer(8192);                          }         //如果我们创建的是COM4这个设备那么把COM4的相关信息记录在pSerialHead中。                 if(4Identifier)         {               RETAILMSG(DEBUG_COM2,(L PLATFORM      fwq  COM_init 4  /r/n));               pSerialHead-COMNUM  4;                 // init circlebuffer for com4                 g_pCircleBuffer4 CP_CreateCircleBuffer(8192);         }         ...... //返回pSerialHead这个pSerialHead将会被COM_Open()所得到。 return(pSerialHead);  } 通过RegisterDevice()和COM_Init()的配合我们可以看到每添加一个设备COM_Init()就会在device.exe的进程空间内分配一段空间用来存放相应设备的信息这些信息被记录在pSerialHead所指向的结构体中。 至此设备的加载过程就完成我们可以灵活的根据我们的需要在pSerialHead所指向的结构体中添加需要的变量这个结构体也可以我们自己来定义但在本程序中我直接引用了系统代码中定义好的结构体并在此结构体中添加了自己需要的变量。 第二驱动程序加载成功之后我们就可以通过应用程序来打开虚拟串口了。下面我们来完成COM_Open()函数。 HANDLE COM_Open(         HANDLE  pHead,          // parm Handle returned by COM_Init.         DWORD   AccessCode,     // parm access code.         DWORD   ShareMode       // parm share mode - Not used in this driver.         ) {     RETAILMSG(DEBUG_COM2,(L PLATFORM      fwq  COM_Open  /r/n)); // 系统会根据CreateFile的第一个参数把devcie.exe内存空间中的与具体设备相关的     //PHW_INDEP_INFO结构体通过pHead参数传递过来。 //比如CreateFile的第一个参数是COM4文件系统就回把我们在COM_Init()中创建好的用来存    //贮COM4设备信息的PHW_INDEP_INFO结构体地址传递过来。     PHW_INDEP_INFO  pSerialHead (PHW_INDEP_INFO)pHead;     PHW_OPEN_INFO   pOpenHead NULL;      ......     // 为pOpenHead分配空间这个空间内用来存放打开设备的一些信息比如运行时的状态等都可以存储在此空间内。     pOpenHead      (PHW_OPEN_INFO)LocalAlloc(LPTR, sizeof(HW_OPEN_INFO));         RETAILMSG(DEBUG_COM,(LPLATFORM   **()()()**        pOpenHead%d ,pOpenHead));         if ( !pOpenHead ) {         DEBUGMSG( DEBUG_COM,                  (TEXT(  PLATFORMError allocating memory for pOpenHead, COM_Open failed/n/r)));         return(NULL);     }     // Init the structure //我们要把在COM_Init()中和当前打开设备相关的pSerialHead的地址保存在pOpenHead中。 // 设备打开后其他流接口函数被调用时都会获得pOpenHead所指向的结构体地址。这样我们就可以在驱动中控制 //应用程序打开的设备状态了     pOpenHead-pSerialHead pSerialHead;        ......     //InitializeCriticalSection((pOpenHead-CommEvents.EventCS));     EnterCriticalSection(g_csOpen); // 如果串口3已经被打开了 就不在继续打开。  if(g_uiOpenCount ! 0)     {        goto SET_SUCCEED_FLAG;     }    BOOL resFALSE; // 打开串口3  res g_SerialPort.Open(3,4800);  if(res FALSE )     {      RETAILMSG(DEBUG_COM,(TEXT(Failed to map 3/r/n)));      goto CleanUp;     }     else    {      RETAILMSG(DEBUG_COM,(TEXT(Succeed to map to 3/r/n)));     }     g_hReadEvent4 CreateEvent(NULL,FALSE,FALSE,LWaitCommGPS4); SET_SUCCEED_FLAG:                     if(pSerialHead-COMNUM 4)         {                 RETAILMSG(DEBUG_COM3,(L PLATFORM       open com4  /r/n));               g_ComOpenFlag4 1;                       pSerialHead-COMOpenFlag 1;         }         if(pSerialHead-COMNUM 5)         {               RETAILMSG(DEBUG_COM3,(L PLATFORM       open com5  /r/n));               g_ComOpenFlag5 1;                 pSerialHead-COMOpenFlag 1;         }  // 记录串口3被打开的次数    g_uiOpenCount ;              LeaveCriticalSection(g_csOpen); /     return(pOpenHead);  CleanUp:         LeaveCriticalSection(g_csOpen);         RETAILMSG(DEBUG_COM,(L PLATFORM      readqueue faild  and exit COM_Open/r/n));          return(NULL); } 第三现在我们可以在应用程序中通过打开的串口来监听串口数据了应用程序会通过 WaitCommEvent函数来等待串口事件。 那么驱动程序中我们是如何知道应用程序在等待哪个串口呢应用程序调用WaitCommEvent函数实际上是掉用驱动的 COM_IOControl()函数。 下面来看流接口COM_IOControl()的设计 BOOL COM_IOControl(PHW_OPEN_INFO pOpenHead,               DWORD dwCode, PBYTE pBufIn,               DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut,               PDWORD pdwActualOut){       ...... // 通过文件系统传来的pOpenHead参数获得应用程序所调用设备的结构体指针获取当前设       备信息。     PHW_INDEP_INFO  pSerialHead pOpenHead-pSerialHead;     switch ( dwCode ) {                      case IOCTL_SERIAL_WAIT_ON_MASK :                 // 应用程序调用WaitCommEvent()函数会进入这个分支                 if(4 pSerialHead-COMNUM)                 {     // WaitCommEvent4调用了WaitForSingleObject来等待事件                      WaitCommEvent4(pOpenHead, (DWORD *)pBufOut, NULL);                 }                 if(5 pSerialHead-COMNUM)                 {                          WaitCommEvent5(pOpenHead, (DWORD *)pBufOut, NULL);                 }               *pdwActualOut sizeof(DWORD);         break;     default :                 RETAILMSG (DEBUG_COM, (TEXT(  PLATFORM    Invalid ioctl %d/r/n), dwCode));                  break;     }    ......     return TRUE; } 通过这个COM_IOControl()函数我们就能对COM4和COM5两个串口事件分别进行监听。 第四监听COM3 并将COM3的数据分别发送给COM4和COM5针对COM4和COM5我分别为其分配了一段循环缓冲区当COM3有数据时如果COM4为打开状态就将数据放入COM4的循环缓冲区中COM5同理。 这部分工作由一个线程来完成下面是COM3数据监听线程代码。 static DWORD WINAPI     ThreadReadCOM(LPVOID lpParam) {         RETAILMSG(DEBUG_CODE,(LThreadReadCOM/r/n));         DWORD   dwCommModemStatus        0;         BOOL            bRet FALSE;         int             pdwBytesRead 0;         BYTE            pBuffer [1024];         _try         {                                  while(INVALID_HANDLE_VALUE ! g_hComFile)                 {                         //RETAILMSG(DEBUG_CODE,(LCOM1 Wait Comm Event/r/n));                         SetCommMask(g_hComFile,EV_RXCHAR);                         WaitCommEvent (g_hComFile,dwCommModemStatus,0);                                                  //RETAILMSG(DEBUG_CODE,(L第%d次收到数据/r/n,count));                                                  bRet          ReadFile(g_hComFile,pBuffer,128,(LPDWORD)pdwBytesRead,0);                                              if(1 g_ComOpenFlag4)                     { // 设置事件有效通过COM4收到数据                         SetEvent(g_hReadEvent4); //将数据存放在专为COM4准备的循环缓冲区中                         g_pCircleBuffer4-Write(g_pCircleBuffer4,pBuffer,pdwBytesRead);                                              }                     if(1 g_ComOpenFlag5)                     { // 设置事件有效通过COM5收到数据 // 这里不添加SetEvent语句串口5依然会得到响应而且响应速度很快添加了 // SetEvent后com5的响应反而会变慢这里我猜测是实串口驱动的SetEvent事件引起 //了应用程序对com5的WaitCommEvent响应希望有了解的朋友给与指正                         SetEvent(g_hReadEvent5); //将数据存放在专为COM5准备的循环缓冲区中                         g_pCircleBuffer5-Write(g_pCircleBuffer5,pBuffer,pdwBytesRead);                                              }                 }         }                 __except(EXCEPTION_EXECUTE_HANDLER)         {                 RETAILMSG(DEBUG_CODE,(LException! call Serial Thread/r/n));         }      RETAILMSG(DEBUG_CODE,(Lreadcom Thread exit/r/n));         return 1; } 第五实现COM_Read()应用程序调用ReadFile后驱动中的COM_Read()会被调用下面是具体实现代码 ULONG COM_Read(         HANDLE      pHead,          //parm [IN]         HANDLE returned by COM_Open            PUCHAR      pTargetBuffer,  //parm [IN,OUT] Pointer to valid memory.              ULONG       BufferLength    //parm [IN]         Size in bytes of pTargetBuffer.         ) {     PHW_OPEN_INFO   pOpenHead (PHW_OPEN_INFO)pHead;     PHW_INDEP_INFO  pSerialHead pOpenHead-pSerialHead;     ULONG           BytesRead 0;            ...... if(4 pSerialHead-COMNUM)          { //从COM4的循环缓冲区中读取数据              g_pCircleBuffer4-Read(g_pCircleBuffer4,pTargetBuffer,BufferLength,(unsigned int*)BytesRead);                                return BytesRead;          }                             if(5 pSerialHead-COMNUM)          {    //从COM5的循环缓冲区中读取数据              g_pCircleBuffer5-Read(g_pCircleBuffer5,pTargetBuffer,BufferLength,(unsigned int*)BytesRead);                              return BytesRead;          }         return -1;     } 至此我们的虚拟串口驱动就基本完成当然目前本驱动只具备串口读功能如果要实现写功能还需要完成COM_Write的 代码。 还有一个重要的函数COM_Close()需要实现在这个函数中我们要把被关闭的串口占用的资源释放将某些状态位设为默认值等还要在所有虚拟串口都关闭后关闭实串口COM3结束COM3的监听线程在这里就不具体说明了。 红色字体部分是本驱动存在问题的地方希望有了解的朋友给与指正。
http://www.dnsts.com.cn/news/170309.html

相关文章:

  • 网站备案信息被注销运营计划方案怎么写
  • 网站新闻关键词网站建设的分阶段步骤
  • 为什么要建设商城网站网络媒体广告代理
  • 如何配置 网站二级域名热门手机网站
  • 做好公司网站建设银行企业理念
  • 企业网站建设需要考虑内容免费咨询聊天
  • 东莞网站SEO优化推广淘客网站难做吗
  • 新昌品牌网站建设三亚网站外包
  • 哈尔滨网站建设设计wordpress Honey 主题
  • 精通网站建设工资多少钱济南建设管理局官网
  • 网站做直播吗安全狗网站白名单指什么
  • 上海嘉定区网站建设公司谷歌入口
  • 一个页面对网站如何建设网络工程专业毕业生设计
  • 网站留言短信提醒深圳公司网站制作企业
  • 原创文章的网站被降权或无排名的原因有哪些商标logo设计免费生成
  • 广西建设工会网站昆明婚恋网站价格
  • 与小学生一起做网站做墙绘一般在哪个网站
  • 西昌网站制作牡丹江哪个网络好
  • 网站开发和美工的区别中国住房和城乡建设局官网
  • 东莞平台网站建设设计公司黑果云免费虚拟主机
  • dedecms网站模板免费下载网站的开发公司倒闭对网站使用
  • 网站空间搭建2014年网站开发语言
  • 做酒的网站有哪些织梦dedecms5.6 网站搬家详细教程
  • 网站建设公司itcask长沙制作网站的公司
  • 永嘉移动网站建设公司哪个网站做外链视频好
  • 做网站没有创意仿照一个国外的网站要多少钱
  • 不用模板 网站免费地方网站
  • 明星个人网站建设方案私人兼职做网站开发
  • 护肤品网站建设分析商务网站建设怎样收费
  • 做网站有什么必要建设工程网站教程