Virtual serial port driver design under WINCE

Source: Internet
Author: User

Currently, both the on-board and PND devices have the function of automatically correcting the system time. The implementation method is generally when GPS is used (of course, for devices with CMMB module, you can also use CMMB for calibration ). However, because the serial port device is an exclusive device, the GPS serial port cannot be used by the navigation software and calibration program at the same time. If the navigation software is running at this time, the program cannot access the GPS serial port during GPS calibration.

In this case, we need to create a non-exclusive serial port device and Virtualize a physical serial port into multiple serial ports for use. The virtual serial port Driver opens the physical serial port and listens to the physical serial port events. When the physical serial port has data, it saves the data to the cache for multiple virtual serial ports to use. In this way, data is shared between multiple programs through the same physical serial port through virtual means.

Based on the above ideas, the following design is adopted. (Here, the prefix of the driver is set to COM, which is consistent with the prefix of the physical serial driver. In this way, the application layer can access the virtual serial driver just like the physical serial driver .)

1. Open the physical serial port in the COM_Open () function, and create the MonitorCommEventProc thread to listen and process the physical serial port data.

2. Define two buffers to save the data information of two virtual serial ports respectively. The Buffer design adopts the cyclic queue method.

3. Listen to physical serial port events in the listening thread MonitorCommEventProc. When there is data in the physical serial port, read the data and save the data to the two buffers respectively.

4. Read the data in the Buffer in the COM_Read () function.

5. Implement the corresponding control code interface in the COM_IOControl () function. For example, IOCTL_SERIAL_SET_WAIT_MASK, IOCTL_SERIAL_WAIT_ON_MASK, IOCTL_SERIAL_GET_COMMSTATUS, and IOCTL_SERIAL_PURGE.

MonitorCommEventProc listener thread reference code:

// We use this program to always read the physical serial data <br/> DWORD MonitorCommEventProc (LPVOID pParam) <br/>{< br/> InterlockedExchange (reinterpret_cast <LONG *> (& g_bMonitorProcRunning), TRUE); <br/> unsigned char vtBufRead [READ_BUFFER_LENGTH]; <br/> while (TRUE) <br/> {<br/> if (g_bExitMonitorProc! = FALSE) <br/>{< br/> RETAILMSG (TRUE, (TEXT ("MonitorCommEventProc Stop! /R/n "); <br/> // if com is closed, we will stop to read <br/> break; <br/>}</p> <p> DWORD dwEvtMask = 0; <br/> SetCommMask (g_hCom, g_dwWaitMask | EV_RXCHAR ); <br/> // wait the physical serial event <br/> if (WaitCommEvent (g_hCom, & dwEvtMask, NULL) & (dwEvtMask & EV_RXCHAR )) <br/>{< br/> SetCommMask (g_hCom, g_dwWaitMask | EV_RXCHAR); {<br/> COMSTATcmState; <br/> DWORD dwReadErrors; <br/> ClearCommError (g_hCom, & dwReadErrors, & cmState); <br/> DWORD willReadLen = cmState. cbInQue; <br/> if (willReadLen <= 0) <br/> continue; <br/> DWORD dwRead = 0; <br/> ReadFile (g_hCom, vtBufRead, willReadLen, & dwRead, NULL); <br/> EnterCriticalSection (& g_csRead1); <br/> EnterCriticalSection (& g_csRead2); <br/> if (g_bComState1 = COM_STATUS_OPEN) <br/>{< br/> WriteBuffer (g_ucDateBuf1, READ_BUFFER_LENGTH, vtBufRead, dwRead, & g_dwDateBufHead1, & g_dwDateBufTail1 ); <br/>}< br/> if (g_bComState2 = COM_STATUS_OPEN) <br/> {<br/> WriteBuffer (g_ucDateBuf2, READ_BUFFER_LENGTH, vtBufRead, dwRead, & g_dwDateBufHead2, & g_dwDateBufTail2); <br/>}< br/> LeaveCriticalSection (& g_csRead2); <br/> LeaveCriticalSection (& g_csRead1 ); <br/> InterlockedExchange (reinterpret_cast <LONG *> (& g_dwEvtMask), dwEvtMask); <br/> PulseEvent (g_hCanReadEvent); <br/> printf ("PulseEvent g_hCanReadEvent... /n "); <br/> // sleep for other thread to respond to the event, very important .. <br/> Sleep (1); <br/>}< br/> InterlockedExchange (reinterpret_cast <LONG *> (& g_bMonitorProcRunning), FALSE ); <br/> return 0; <br/>}

 

The COM_IOControl () function can call the physical serial DeviceIoControl () to process most control codes. However, some control codes need to be implemented by themselves. For example, to clear the cache, you cannot directly call DeviceIoControl () to clear the data of the physical serial port, but to clear the data in the Buffer of the virtual serial port. Reference code for the implementation of several important control codes:

BOOL <br/> COM_IOControl (HANDLE dwHandle, <br/> DWORD dwIoControlCode, PBYTE pBufIn, <br/> DWORD dwBufInSize, PBYTE pBufOut, DWORD finished, <br/> PDWORD finished) </p> <p >{< br/> switch (dwIoControlCode) <br/>{< br/> case IOCTL_SERIAL_SET_WAIT_MASK: <br/> // printf ("Serial Command: SERIAL_SET_WAIT_MASK/n "); <br/> if (g_uiOpenCount = 1) <br/>{< br/> g_dwWaitMask = * reinterpret_cast <DWORD *> (pBufIn ); <Br/> return DeviceIoControl (g_hCom, IOCTL_SERIAL_SET_WAIT_MASK, pBufIn, dwBufInSize, pBufOut, dwBufOutSize, pBytesReturned, NULL ); <br/>}< br/> else <br/> return TRUE; <br/> case IOCTL_SERIAL_WAIT_ON_MASK: <br/>{< br/> PVSP_INFO pOpenHead = (PVSP_INFO) dwHandle; <br/> // return immediately if the buffer has the available data <br/> if (* (pOpenHead-> BufferHead )! = * (POpenHead-> BufferTail) <br/> return TRUE; <br/> if (dwBufOutSize <sizeof (DWORD) | WaitForSingleObject (g_hCanReadEvent, INFINITE) = WAIT_TIMEOUT) <br/>{< br/> * pBytesReturned = 0; <br/> return FALSE; <br/>}< br/> else <br/> {<br/> InterlockedExchange (reinterpret_cast <LONG *> (pBufOut), g_dwEvtMask ); <br/> * pBytesReturned = sizeof (DWORD); <br/> return TRUE; <br/>}< br/> case IOCTL_SERIAL_PURGE: <br/>{< br/> // clean the virtual serial buffer <br/> PVSP_INFO pOpenHead = (PVSP_INFO) dwHandle; <br/> * (pOpenHead-> BufferHead) = 0; <br/> * (pOpenHead-> BufferTail) = 0; <br/> return TRUE; <br/>}< br/> ..... <br/>}< br/> return FALSE; <br/>}

 

Reference code for read/write operations on Buffer (cyclic queue:

Void writebuffer (puchar targetbuffer, DWORD longoftarget, puchar sourcebuffer, <br/> DWORD numinsource, DWORD * bufferhead, DWORD * buffertail) <br/>{< br/> bool changehead = false; <br/> DWORD I = * buffertail; <br/> DWORD J = 0; <br/> If (numinsource> = longoftarget) <br/> {<br/> memcpy (targetbuffer, sourcebuffer, longoftarget); <br/> * bufferhead = 0; <br/> * buffertail = LongOfTarget-1; <br/> return; <br/>}< br/> else <br/>{< br/> (; j <numinsource; j ++) <br/>{< br/> targetbuffer [I ++] = sourcebuffer [J]; <br/> if (I> = longoftarget) <br/>{< br/> I = 0; <br/>}< br/> if (I = (* bufferhead )) <br/>{< br/> changehead = true; <br/>}< br/> If (changehead = false) <br/>{</P> <p> * buffertail = I; <br/> return; <br/>}< br/> else <br/> {<br/> * buffertail = I; <br/> * bufferhead = I + 1; <br/> return; <br/>}</P> <p> DWORD readbuffer (puchar targetbuffer, puchar sourcebuffer, DWORD sizeoftargebuf, <br/> DWORD longofsourcebuf, DWORD * bufferhead, DWORD * buffertail) <br/>{< br/> DWORD I = 0; <br/> DWORD J = * bufferhead; <br/> bool isempty = false; <br/> for (I = 0; I <sizeoftargebuf; I ++) <br/>{< br/> If (j = (* buffertail) <br/>{< br/> isempty = true; <br/> break; <br/>}< br/> targetbuffer [I] = sourcebuffer [J ++]; <br/> If (j> = longofsourcebuf) <br/>{< br/> J = 0; <br/>}< br/> If (isempty = false) <br/>{< br/> * bufferhead = J; <br/>}< br/> else <br/>{< br/> (* bufferhead) = (* buffertail) = 0; <br/>}< br/> return I; <br/>} 

Author: norains thanks to norains hero selfless dedication.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.