运行环境: WinCE5.0
我们有一个GPS模块连接在COM3上,现在有两个应用程序都需要读取COM3的内容,然而WinCE的串口为独占式的串口,因此我们需要一个驱动程序,将COM3虚拟成COM4和COM5来供应用程序使用。下面我来介绍一下驱动程序的设计。
HANDLE hRes = RegisterDevice (L"COM", VirComNO, L"GPSCOM.dll", (DWORD) VirComNO);
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
if(5==Identifier)
{
RETAILMSG(DEBUG_COM2,(L" PLATFORM fwq COM_init5 /r/n"));
pSerialHead->COMNUM = 5;
g_pCircleBuffer5 =CP_CreateCircleBuffer(8192);
}
//如果我们创建的是COM4这个设备,那么把COM4的相关信息记录在pSerialHead中。
if(4==Identifier)
{
RETAILMSG(DEBUG_COM2,(L" PLATFORM fwq COM_init 4 /r/n"));
pSerialHead->COMNUM = 4;
// init circlebuffer for com4
g_pCircleBuffer4 =CP_CreateCircleBuffer(8192);
}
......
}
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"));
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,(L"PLATFORM **()()()** pOpenHead=%d ",pOpenHead));
if ( !pOpenHead ) {
DEBUGMSG( DEBUG_COM,
(TEXT(" PLATFORMError allocating memory for pOpenHead, COM_Open failed/n/r")));
return(NULL);
}
// Init the structure
pOpenHead->pSerialHead = pSerialHead;
......
//InitializeCriticalSection(&(pOpenHead->CommEvents.EventCS));
EnterCriticalSection(&g_csOpen);
if(g_uiOpenCount != 0)
{
goto SET_SUCCEED_FLAG;
}
BOOL res=FALSE;
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,L"WaitCommGPS4");
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);
}
COM_IOControl(PHW_OPEN_INFO pOpenHead,
DWORD dwCode, PBYTE pBufIn,
DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut,
PDWORD pdwActualOut){
......
PHW_INDEP_INFO pSerialHead= pOpenHead->pSerialHead;
switch ( dwCode ) {
case IOCTL_SERIAL_WAIT_ON_MASK :
// 应用程序调用WaitCommEvent()函数会进入这个分支
if(4 == pSerialHead->COMNUM)
{
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;
}
{
RETAILMSG(DEBUG_CODE,(L"ThreadReadCOM/r/n"));
DWORD dwCommModemStatus = 0;
BOOL bRet = FALSE;
int pdwBytesRead =0;
BYTE pBuffer [1024];
_try
{
while(INVALID_HANDLE_VALUE != g_hComFile)
{
//RETAILMSG(DEBUG_CODE,(L"COM1 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)
{
SetEvent(g_hReadEvent4);
g_pCircleBuffer4->Write(g_pCircleBuffer4,pBuffer,pdwBytesRead);
}
if(1 == g_ComOpenFlag5)
{
SetEvent(g_hReadEvent5);
g_pCircleBuffer5->Write(g_pCircleBuffer5,pBuffer,pdwBytesRead);
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
RETAILMSG(DEBUG_CODE,(L"Exception! call Serial Thread/r/n"));
}
RETAILMSG(DEBUG_CODE,(L"readcom Thread exit/r/n"));
return 1;
}
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)
{
g_pCircleBuffer4->Read(g_pCircleBuffer4,pTargetBuffer,BufferLength,(unsigned int*)&BytesRead);
return BytesRead;
}
if(5 ==pSerialHead->COMNUM)
{
g_pCircleBuffer5->Read(g_pCircleBuffer5,pTargetBuffer,BufferLength,(unsigned int*)&BytesRead);
return BytesRead;
}
return -1;
}