📄 serialcommlayer.cpp
字号:
if(!PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
{
// If there are no messages pending, wait for a message or
// the CloseEvent.
if(CompleteOneWriteRequire)
{
if(!PostMessage( hComm32Window, PWM_SENDDATAEMPTY, 0, 0 ))
{
goto EndWriteThread;
}
}
//CompleteOneWriteRequire的用处在于:即使RCCComm向WriteThread发送了一个
//非PWM_COMMWRITE的消息,也不会导致WriteThread又向RCCComm发送一个
//PWM_SENDDATAEMPTY消息.
CompleteOneWriteRequire = FALSE;
dwHandleSignaled = MsgWaitForMultipleObjects(1, &hCloseEvent, FALSE,
INFINITE, QS_ALLINPUT);
switch(dwHandleSignaled)
{
case WAIT_OBJECT_0: // CloseEvent signaled!
// Time to exit.
goto EndWriteThread;
case WAIT_OBJECT_0 + 1: // New message was received.
// Get the message that woke us up by looping again.
continue;
case WAIT_FAILED: // Wait failed. Shouldn't happen.
goto EndWriteThread;
default: // This case should never occur.
goto EndWriteThread;
}
}
// Make sure the CloseEvent isn't signaled while retrieving messages.
if (WaitForSingleObject(hCloseEvent,0) != WAIT_TIMEOUT)
goto EndWriteThread;
// Handle the message.
switch(msg.message)
{
case PWM_COMMWRITE: // New string to write to Comm port.
// Write the string to the comm port. HandleWriteData
// does not return until the whole string has been written,
// an error occurs or until the CloseEvent is signaled.
if(!HandleWriteData( &overlappedWrite,
(LPSTR)msg.lParam, (DWORD)msg.wParam ))
{
// If it failed, either we got a signal to end or there
// really was a failure.
LocalFree( HLOCAL(msg.lParam) );
goto EndWriteThread;
}
CompleteOneWriteRequire = TRUE;
// Data was sent in a LocalAlloc()d buffer. Must free it.
LocalFree( HLOCAL(msg.lParam) );
break;
}
}//{main loop}
EndWriteThread:
PostHangupCall();
PurgeComm(hCommFile, PURGE_TXABORT | PURGE_TXCLEAR);
CloseHandle(overlappedWrite.hEvent);
return 0; //CWinThread::Run();
}
void CCommWriteThread::PostHangupCall()
{
PostMessage( hComm32Window, PWM_REQUESTHANGUP, 0, 0 );
}
//(******************************************************************************)
// CRCCComm
//(******************************************************************************)
CRCCComm::CRCCComm()
{
hCommFile = INVALID_HANDLE;
hCloseEvent = INVALID_HANDLE;
ReadThread = NULL;
WriteThread = NULL;
Init();
}
CRCCComm::~CRCCComm()
{
if (hCommFile != INVALID_HANDLE)
Close();
}
void CRCCComm::Init()
{
LastError = RCC_ERROR_SUCCESS;
}
BOOL CRCCComm::StartComm(char * lpCommNo, DWORD dwBaudRate, BYTE byByteSize, BYTE byParity, BYTE byStopBits)
{
HANDLE hNewCommFile;
// 如果已经启动COMM口,则返回
if (hCommFile != INVALID_HANDLE)
{
LastError = RCC_ERROR_ALREADY_OPEN;
return FALSE;
}
hNewCommFile = CreateFile(lpCommNo, GENERIC_READ|GENERIC_WRITE,
0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0 );
if (hNewCommFile == INVALID_HANDLE_VALUE)
{
LastError = RCC_ERROR_OPEN;
return FALSE;
}
// 检查新句柄是否是一个适当的设备
if (GetFileType( hNewCommFile ) != FILE_TYPE_CHAR)
{
CloseHandle(hNewCommFile);
LastError = RCC_ERROR_INVALID_COMM;
return FALSE;
}
if( !SetupComm(hNewCommFile, 8192, 8192) )
{
CloseHandle( hNewCommFile );
LastError = RCC_ERROR_SET_BUFFER;
return FALSE;
}
hCommFile = hNewCommFile;
// 删除系统缓冲区内的任何东西
PurgeComm( hCommFile, PURGE_TXABORT | PURGE_RXABORT |
PURGE_TXCLEAR | PURGE_RXCLEAR ) ;
DCB dcb;
if ( !::GetCommState(hCommFile, &dcb) )
{
CloseHandle( hCommFile );
hCommFile = INVALID_HANDLE;
LastError = RCC_ERROR_GETCOMMSTATE;
return FALSE;
}
dcb.BaudRate = dwBaudRate;
dcb.ByteSize = byByteSize;
dcb.Parity = byParity;
dcb.StopBits = byStopBits;
if ( !::SetCommState(hCommFile, &dcb) )
{
CloseHandle( hCommFile );
hCommFile = INVALID_HANDLE;
LastError = RCC_ERROR_SETCOMMSTATE;
return FALSE;
}
//设置底层超时参数
COMMTIMEOUTS commtimeouts;
GetCommTimeouts(hCommFile, &commtimeouts);
commtimeouts.ReadIntervalTimeout = 20;
commtimeouts.ReadTotalTimeoutMultiplier = 0;
commtimeouts.ReadTotalTimeoutConstant = 0;
commtimeouts.WriteTotalTimeoutMultiplier = 30;
commtimeouts.WriteTotalTimeoutConstant = 400;
SetCommTimeouts(hCommFile, &commtimeouts);
//Sends the DTR (data-terminal-ready) signal.
::EscapeCommFunction(hCommFile,SETDTR);
hCloseEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (hCloseEvent == INVALID_HANDLE)
{
CloseHandle( hCommFile );
hCommFile = INVALID_HANDLE;
LastError = RCC_ERROR_CREATE_CLOSE_EVENT;
return FALSE;
}
// 创建串口读写线程.
ReadThread = new CCommReadThread();
WriteThread = new CCommWriteThread();
if(ReadThread == NULL || WriteThread == NULL)
{
LastError = RCC_ERROR_CREATE_THREAD;
if(ReadThread)
{
delete ReadThread;
ReadThread = NULL;
}
if(WriteThread)
{
delete WriteThread;
WriteThread = NULL;
}
CloseHandle( hCloseEvent );
hCloseEvent=INVALID_HANDLE;
CloseHandle( hCommFile );
hCommFile=INVALID_HANDLE;
return FALSE;
}
if( !ReadThread->CreateThread(CREATE_SUSPENDED) ||
!WriteThread->CreateThread(CREATE_SUSPENDED) )
{
LastError = RCC_ERROR_CREATE_THREAD;
if(ReadThread)
{
delete ReadThread;
ReadThread = NULL;
}
if(WriteThread)
{
delete WriteThread;
WriteThread = NULL;
}
CloseHandle( hCloseEvent );
hCloseEvent=INVALID_HANDLE;
CloseHandle( hCommFile );
hCommFile=INVALID_HANDLE;
return FALSE;
}
ReadThread -> SetThreadPriority(THREAD_PRIORITY_HIGHEST);
WriteThread->SetThreadPriority(THREAD_PRIORITY_HIGHEST);
ReadThread->hCommFile = hCommFile;
ReadThread->hCloseEvent = hCloseEvent;
ReadThread->hComm32Window = m_hWnd;
ReadThread->m_bAutoDelete = FALSE;
WriteThread->hCommFile = hCommFile;
WriteThread->hCloseEvent = hCloseEvent;
WriteThread->hComm32Window = m_hWnd;
WriteThread->m_bAutoDelete = FALSE;
//启动线程
ReadThread->ResumeThread();
WriteThread->ResumeThread();
return TRUE;
}
BOOL CRCCComm::StopComm()
{
if (hCommFile == INVALID_HANDLE)
return TRUE;
// 关闭读写线程.
CloseReadThread();
CloseWriteThread();
// 关闭事件句柄.
CloseHandle( hCloseEvent );
hCloseEvent = INVALID_HANDLE;
// 关闭通讯端口.
CloseHandle( hCommFile );
hCommFile = INVALID_HANDLE;
return TRUE;
}
//
// 函数: CloseWriteThread CloseReadThread
// 用途: 关闭读写线程.
// 参数: 无
// 返回值:无
// 备注:
// 关闭串口读写线程,并且清除在串口上的任何写操作
// 如果强制关闭一个线程可能导致内存汇漏,但是本程序是通过
// 关闭事件触发的方式去关闭线程,线程在检测到关闭事件触发
// 时会自动退出,因此不会出现强制关闭一个线程的情况
//
void CRCCComm::CloseReadThread(void) //关闭读线程
{
if (ReadThread != NULL)
{
// 触发事件去关闭工作线程.
SetEvent(hCloseEvent);
// 清除在串口上的任何读操作.
PurgeComm(hCommFile, PURGE_RXABORT|PURGE_RXCLEAR);
// 等待10秒线程关闭.
if (WaitForSingleObject( ReadThread->m_hThread, 10000 ) == WAIT_TIMEOUT)
TerminateThread(ReadThread->m_hThread,-1);
delete ReadThread;
ReadThread = NULL;
}
}
void CRCCComm::CloseWriteThread()
{
if (WriteThread != NULL)
{
// 触发事件去关闭工作线程.
SetEvent(hCloseEvent);
// 清除在串口上的任何写操作.
PurgeComm(hCommFile, PURGE_TXABORT|PURGE_TXCLEAR);
// 等待10秒线程关闭,因为不会发生,所以注释掉.
if (WaitForSingleObject( WriteThread->m_hThread, 10000 ) == WAIT_TIMEOUT)
TerminateThread(WriteThread->m_hThread,-1);
delete WriteThread;
WriteThread = NULL;
}
}
int CRCCComm::Send(char *Buffer,int BufLen)
{
if(Buffer == NULL || BufLen <= 0)
{
return 1;
}
LPBYTE lpszStringToWrite = (LPBYTE)LocalAlloc(LPTR, BufLen);
memcpy(lpszStringToWrite, Buffer, BufLen);
if (WriteThread->PostThreadMessage(PWM_COMMWRITE,
(WPARAM)BufLen, (LPARAM)lpszStringToWrite))
{
return 0;
}
LocalFree(lpszStringToWrite);
return 1;
}
//
// 函数: int CRCCComm::Close(void)
// 用途: 关闭串口链接,重新初始化缓冲区,同时关闭串口.
// 参数: 无
// 返回值:
// 0 表示成功,即串口关闭成功进行
// 其它表示失败
// 备注:
// 对该函数的理解,可参照CAsyncSocket::Close函数
// 在MODEM连线方式下,需要将该MODEM转入命令状态之下,再进行
// 挂断操作;在RS232方式下,只做内部缓冲区初始化操作。
//
int CRCCComm::Close(void)
{
if(hCommFile == INVALID_HANDLE)
return 0;
EscapeCommFunction(hCommFile,CLRDTR); //Clears the DTR (data-terminal-ready) signal.
Init();
StopComm();
return 0;
}
//
// 函数: LRESULT CRCCComm::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
// 用途: 底层通讯消息截获函数
// 参数:
// 返回值:
// 备注:
// 本底层主要的通讯方式基于消息,所有的消息分发都通过本函数
LRESULT CRCCComm::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case PWM_GOTCOMMDATA:
OnRawReceive((LPSTR)lParam,(DWORD)wParam);
return 1;
case PWM_REQUESTHANGUP: //关闭链接
Close();
return 1;
}
return CWnd::WindowProc(message, wParam, lParam);
}
//
// 函数: int CRCCComm::OnRawReceive(LPSTR lpNewString,DWORD dwSizeOfNewString)
// 用途: 原始数据的接收,本函数是进行RCC协议解析的函数。
// 参数:
// lpNewString 接收到的新数据
// dwSizeOfNewString 新数据的长度
// 返回值: 目前无具体涵义
// 备注:
// 如果应用程序想直接获取原始数据,可稍做修改,派生本函数
int CRCCComm::OnRawReceive(LPSTR lpNewString, DWORD dwSizeOfNewString)
{
SM_PARAM SmParam;
char DbgMsg[500];
int nMsg; // 短消息计数值
char * ptr; // 内部用的数据指针
char * ptr_tmp;
strcpy(smsResponseBuf, lpNewString);
smsResponseBuf_length = dwSizeOfNewString;
DisplayMessage(smsResponseBuf);
delete lpNewString;
if (smsResponseBuf[0] = '+')
{
if (strstr(smsResponseBuf, "+CMT") != NULL)
{
DisplayMessage("*** you have new message. ***");
}
else if (strstr(smsResponseBuf, "+CMGL:") != NULL)
{
nMsg = 0;
ptr = smsResponseBuf;
// 循环读取每一条短消息, 以"+CMGL:"开头
while ((ptr = strstr(ptr, "+CMGL:")) != NULL)
{
memset(&SmParam, 0, sizeof(SM_PARAM));
ptr += 6; // 跳过"+CMGL:", 定位到序号
ptr++; // skip space.
sscanf(ptr, "%d", &(SmParam.index)); // 读取序号
ptr = strstr(ptr, "\r\n"); // 找下一行
if (ptr != NULL)
{
ptr += 2; // 跳过"\r\n", 定位到PDU
gsmDecodePdu(ptr, &SmParam); // PDU串解码
sprintf(DbgMsg, "index=%d,SCA=%s,TPA=%s,SCTS=%s,TP_UD=%s",
SmParam.index, SmParam.SCA, SmParam.TPA, SmParam.TP_SCTS, SmParam.TP_UD);
DisplayMessage(DbgMsg);
nMsg++; // 短消息计数加1
}
}
}
else if (strstr(smsResponseBuf, "+CMGR:") != NULL)
{
memset(&SmParam, 0, sizeof(SM_PARAM));
ptr = smsResponseBuf;
ptr = strstr(ptr, "+CMGR:");
//ptr++; //skip a space.
//sscanf(ptr, "%d", ((SM_PARAM *)&SmParam)->index); // 读取序号
//skip first <CR><LF>
for ( ; (ptr != 0) && (*ptr != 0x0D); ptr++);
if ((*ptr) == 0)
return 0;
ptr++;
if ((*ptr) != 0x0A)
return 0;
ptr++;
ptr_tmp = &smsResponseBuf[smsResponseBuf_length - 1];
if ((*ptr_tmp) != 0x0A)
return 0;
ptr_tmp--;
if ((*ptr_tmp) != 0x0D)
return 0;
ptr_tmp--;
if ((*ptr_tmp) != 0x4B)
return 0;
ptr_tmp--;
if ((*ptr_tmp) != 0x4F)
return 0;
if ((ptr_tmp - ptr) == 2)
{
sprintf(DbgMsg, "OK");
DisplayMessage(DbgMsg);
return 0;
}
gsmDecodePdu(ptr, &SmParam); // PDU串解码
sprintf(DbgMsg, "SCA=%s,TPA=%s,SCTS=%s,TP_UD=%s",
SmParam.SCA, SmParam.TPA, SmParam.TP_SCTS, SmParam.TP_UD);
DisplayMessage(DbgMsg);
}
}
return 0;
}
/////////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -