📄 serial.cpp
字号:
//读取串口事件、退出线程信号
HANDLE handle[2];
handle[0] = pSerial->m_end_analysis_thread;
handle[1] = pSerial->m_event_come_event;
//保存WaitForMultipleObjects返回值
DWORD dwRet;
//用来判断之前是否有过字符消息,两个字符消息之间是否超时
bool bHasMessageBefore = false;
::WaitForSingleObject(pSerial->m_start_analysis_thread,INFINITE);
TRACE("analysis event thread start!\n");
SetEvent(pSerial->m_start_event_thread);//启动接收事件线程
while(!bQuit)
{
// bHasMessageBefore=false;//在下边已经变为FALSE了
dwRet=::WaitForMultipleObjects(2,handle,false,INFINITE);
switch(dwRet-WAIT_OBJECT_0)
{
case 0://退出
{
bQuit=true;
}
continue;
case 1://数据到来,进入下一级循环
{
TRACE0("一个数据包的第一个字符到达!\n");
ResetEvent(handle[1]);
if(!bHasMessageBefore)bHasMessageBefore=true;
}
break;
default:
{
ResetEvent(handle[0]);
ResetEvent(handle[1]);
}
continue;
}
while(!bQuit && bHasMessageBefore )
{
dwRet=::WaitForMultipleObjects(2,handle,false,DATA_READ_TIMEOUT);
if(dwRet==WAIT_TIMEOUT)//成功接收到一个数据包
{
if(bHasMessageBefore)
{
TRACE0("完整地接收到了一个数据包!通知数据接收线程进行接收!\n");
bHasMessageBefore=false;
SetEvent(pSerial->m_data_come_event);//通知数据接收线程接收数据
}
continue;
}
switch(dwRet-WAIT_OBJECT_0)
{
case 0://退出
{
bQuit=true;
}
break;
case 1://数据到来
{
// TRACE0("事件分析线程接收到了一个字符!\n");
ResetEvent(handle[1]);
}
break;
default://出错了
{
ResetEvent(handle[0]);
ResetEvent(handle[1]);
}
break;
}
}
}
TRACE("analysis event thread end\n");
//AfxMessageBox("analysis event thread end");
SetEvent(pSerial->m_end_data_thread);
SetEvent(pSerial->m_analysis_thread_end);
return 1;
}
/******************************************************************************
*功能:读取数据线程
*说明: 成功收到一个数据包后,这个线程会得到消息。开始读取这个数据包
成功读取一包数据后,会把数据放到g_read_data_group中,同时向调用者发出一个消息
此消息由调用者初始化时传入.
*参数:lpParam:即:CSerial类对象本身
*返回:0
******************************************************************************/
UINT CSerial::ReadDataProc(LPVOID lpParam)
{
CSerial * pSerial = (CSerial *)lpParam;
bool bQuit=false;
DWORD dwEventMask=0;
//接收到重叠消息
OVERLAPPED ov;
memset(&ov,0,sizeof(OVERLAPPED));
ov.hEvent = CreateEvent(0,true,0,0);
//读取串口事件、退出线程信号
HANDLE event_handle[2];
event_handle[0] = pSerial->m_end_data_thread;
event_handle[1] = pSerial->m_data_come_event;
HANDLE read_handle[2];
read_handle[0] = pSerial->m_end_data_thread;
read_handle[1] = ov.hEvent;
//想要读取的字节数
BOOL bRet;
DWORD dwBytesWantRead;
DWORD dwBytesRead;
char temp_buf[2*MAX_COMM_BUF_LEN];
bool bReadOverlapping = false;
bool bReadDataSuccess = false;
//想知道系统读缓冲区里共有多少字节
DWORD dwErrors=0;//需要这个参数,但是根本没有使用它的返回值,我们不关心它的返回值.
COMSTAT comstate;
memset(&comstate,0,sizeof(COMSTAT));
//保存WaitForMultipleObjects返回值
DWORD dwRet;
::WaitForSingleObject(pSerial->m_start_data_thread,INFINITE);
TRACE("read data thread start\n");
SetEvent(pSerial->m_start_analysis_thread);//启动分析线程
while(!bQuit)
{
dwRet=::WaitForMultipleObjects(2,event_handle,false,INFINITE);
switch(dwRet-WAIT_OBJECT_0)
{
case 0://退出
{
bQuit=true;
}
break;
case 1://数据到来
{
ResetEvent(event_handle[1]);//每次都是先恢复信号
//得到总计有多少字节在系统接收缓冲区里
bRet=::ClearCommError(pSerial->m_hCommPort,&dwErrors,&comstate);
if(!bRet)
{
continue;//失败就丢弃!
}
dwBytesWantRead=comstate.cbInQue;//得到在系统读缓冲区中共有多少字节。
bRet=::ReadFile(pSerial->m_hCommPort,temp_buf,dwBytesWantRead,&dwBytesRead,&ov);
if(bRet) //成功读取数据
{
bReadDataSuccess=true;
}
else //看看是否开始了重叠操作?
{
if(GetLastError()==ERROR_IO_PENDING)
{
bReadOverlapping=true;
}
else//发生错误
{
TRACE("ReadFile(pSerial->m_hCommPort,temp_buf,dwBytesWantRead,&dwBytesRead,&ov);\n");
continue;
}
}
if(bReadOverlapping)
{
bReadOverlapping=false;
dwRet=::WaitForMultipleObjects(2,read_handle,false,DATA_READ_TIMEOUT);
if(dwRet==WAIT_TIMEOUT)
{
continue;//如果读取数据超时,就认为是错误数据,丢弃!
}
switch(dwRet-WAIT_OBJECT_0)
{
case 0://退出
{
bQuit=true;
}
break;
case 1://读数据重叠操作完成
{
// ResetEvent(read_handle[1]);//恢复读取数据信号
//需要判断是否成功读取了数据
bRet=::GetOverlappedResult(pSerial->m_hCommPort,&ov,&dwBytesRead,false);
if(!bRet)//读重叠操作失败!
{
TRACE0("读重叠操作失败!\n");
}
else
{
bReadDataSuccess=true;//成功读取了数据
}
}
break;
default:
{
}
break;
}
}
if(bReadDataSuccess)//如果成功读取了数据
{
bReadDataSuccess=false;//恢复状态
if(dwBytesWantRead==dwBytesRead)//如果没有少读取数据字节数,才是真正的正确读取了数据
{
LPDATA lpdata=g_read_data_group.GetBlank();
//如果读取的字节数超过了MAX_COMM_BUF_LEN-1,则只能接收到MAX_COMM_BUF_LEN-1个字节了
lpdata->m_n_len=dwBytesRead>MAX_COMM_BUF_LEN-1?MAX_COMM_BUF_LEN-1:dwBytesRead;
memcpy(lpdata->m_sz_buf,temp_buf,lpdata->m_n_len);
lpdata->m_sz_buf[lpdata->m_n_len]=0;
pSerial->NotifyReadData();
TRACE("数据接收线程接收到了一个数据包!len=[%d]\n",lpdata->m_n_len);
}
else
{
TRACE0("少读取数据字节数\n");
}
}
continue;//成功读取了数据
}
break;
default:
{
}
break;
}
}
pSerial->CloseAndCleanHandle(ov.hEvent);
TRACE("read data thread end\n");
// AfxMessageBox("read data thread end");
SetEvent(pSerial->m_data_thread_end);
return 2;
}
/******************************************************************************
*功能:通知调用都,成功读取了一个数据包
*说明:
*参数:
*返回:
******************************************************************************/
void CSerial::NotifyReadData()
{
::PostMessage(m_h_father_wnd,m_u_message,MSG_READ,0);
}
/******************************************************************************
*功能:通知调用都,成功发送了一个数据包
*说明:
*参数:
*返回:
******************************************************************************/
void CSerial::NotifyWriteData(void*lpdata)
{
::PostMessage(m_h_father_wnd,m_u_message,MSG_WRITE,(LPARAM)lpdata);
}
void CSerial::ClearSysReadBufferContent()
{
int nRet;
DWORD dwErrors=0;
COMSTAT comstate;
memset(&comstate,0,sizeof(COMSTAT));
nRet=::ClearCommError(m_hCommPort,&dwErrors,&comstate);
if(!nRet)return;
char buf[4096];
DWORD dwBytesRead;
::ReadFile(m_hCommPort,buf,comstate.cbInQue,&dwBytesRead,NULL);
TRACE("已经清空了系统接收缓冲区!len=[%ld]\n",comstate.cbInQue);
//也清空一下保存数据的缓冲区
g_read_data_group.PutToBlank();
g_send_data_group.PutToBlank();
}
UINT CSerial::SendDataProc(LPVOID lpParam)
{
CSerial * pSerial = (CSerial *)lpParam;
//一些返回值
BOOL bRet;
DWORD dwError=0;
DWORD dwRet;
//重叠结构
OVERLAPPED ov;
memset(&ov,0,sizeof(OVERLAPPED));
ov.hEvent=CreateEvent(0,true,0,0);
HANDLE event_handle[2],handle[2];
event_handle[0]=pSerial->m_end_send_thread;
event_handle[1]=pSerial->m_send_data_event;
handle[0]=pSerial->m_end_send_thread;
handle[1]=ov.hEvent;
//错误处理用的
COMSTAT comstate;
memset(&comstate,0,sizeof(COMSTAT));
//是否开始了重叠操作?
bool bWantToSendSomething=false;
bool bHasOverlapped=false;
bool bHasFinishedOverlapped=false;
//一共写了多少字节?
DWORD dwBytesWrite=0;
bool bQuit=false;
TRACE0("send data thread start!!!!!\n");
while(!bQuit)
{
dwRet=::WaitForMultipleObjects(2,event_handle,false,INFINITE);
switch(dwRet-WAIT_OBJECT_0)
{
case 0:
{
bQuit=true;
}
continue;
case 1:
{
bWantToSendSomething=true;
}
break;
default:
{
}
continue;
}
if(!bWantToSendSomething)continue;
bWantToSendSomething=false;
//得到要发送的数据结点
LPDATA lpdata=g_send_data_group.GetNext();
//一直把所有需要发送的数据全都发送完
while(lpdata!=NULL)
{
bRet=::WriteFile(pSerial->m_hCommPort,lpdata->m_sz_buf,lpdata->m_n_len,&dwBytesWrite,&ov);
if(!bRet)
{
if(GetLastError()==ERROR_IO_PENDING)
{
bHasOverlapped=true;
}
else//出错处理,必须,否则所有IO操作都会被锁死!
{
::ClearCommError(pSerial->m_hCommPort,&dwError,&comstate);
}
}
if(bHasOverlapped)
{
bHasOverlapped=false;
dwRet=::WaitForMultipleObjects(2,handle,false,INFINITE);
switch(dwRet-WAIT_OBJECT_0)
{
case 0://退出
{
bQuit=true;
}
continue;
case 1://数据到来
{
TRACE0("发送数据重叠操作完成\n");
bHasFinishedOverlapped=true;
}
break;
default://出错了
{
}
continue;
}
}
if(bHasFinishedOverlapped)
{
bHasFinishedOverlapped=false;
bRet=::GetOverlappedResult(pSerial->m_hCommPort,&ov,&dwBytesWrite,false);
if(bRet)
{
TRACE("重叠操作完成!发送了[%d]字节数据\n",dwBytesWrite);
pSerial->NotifyWriteData(lpdata->m_sz_buf);
}
else
{
TRACE("没有得到重叠操作结果!\n");
}
}
//再取没有发送的数据
lpdata=g_send_data_group.GetNext();
}
//恢复发送数据的信号,以便再接收发送数据的消息
ResetEvent(event_handle[1]);
}
pSerial->CloseAndCleanHandle(ov.hEvent);
TRACE0("send data thread end!\n");
SetEvent(pSerial->m_send_thread_end);
return 3;
}
bool CSerial::ReadData(char szData[], int &len)
{
LPDATA lpdata=g_read_data_group.GetNext();
if(lpdata==NULL)return false;
len=len>lpdata->m_n_len+1?lpdata->m_n_len+1:len;
memcpy(szData,lpdata->m_sz_buf,len);
szData[len]=0;
return true;
}
bool CSerial::SendData(char szData[], int len)
{
LPDATA lpdata=g_send_data_group.GetBlank();
lpdata->m_n_len=len;
memcpy(lpdata->m_sz_buf,szData,len);
lpdata->m_sz_buf[len]=0;
SetEvent(m_send_data_event);
return true;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -