www.gusucode.com > 串口监视软件源程序,用于监视串口的读写操作(VC++7 > 串口监视软件源程序,用于监视串口的读写操作(VC++7.0版)-/ComPort.cpp
// ComPort.cpp : 实现文件 // #include "stdafx.h" #include "ComPort.h" namespace LsComm{ // CComPort CComPort::CComPort() { this->m_pfnOnReceiveData = NULL; this->m_pfnOnComBreak =NULL; this->m_pPort = NULL; this->m_pReadThread = NULL; ::ZeroMemory(&this->m_WriteOverlapped,sizeof(this->m_WriteOverlapped)); this->m_hWriteEvent = NULL; } CComPort::~CComPort() { if(this->m_pPort) { if(this->m_pPort->IsOpen()) { this->Close(); } } if(this->m_pPort) { delete this->m_pPort; this->m_pPort = NULL; } } // CComPort 成员函数 void CComPort::Open(int nPort,ReceiveMode mode, DWORD dwBaud, Parity parity, BYTE DataBits, StopBits stopbits,FlowControl fc) { //1.新建串口 this->m_pPort = new CSerialPort(); //2.判断收发模式 if(mode==ReceiveMode::ManualReceiveByQuery) { this->m_IsOverlapped = false; } else { this->m_IsOverlapped = true; } this->m_RecvMode = mode; //3.转换参数,打开串口 int index; index=parity-CComPort::EvenParity; CSerialPort::Parity spParity=(CSerialPort::Parity)(CSerialPort::EvenParity+index); index=stopbits-CComPort::OneStopBit; CSerialPort::StopBits spStopbits=(CSerialPort::StopBits)(CSerialPort::OneStopBit+index); index=fc-CComPort::NoFlowControl; CSerialPort::FlowControl spFC=(CSerialPort::FlowControl)(CSerialPort::NoFlowControl+index) ; this->m_pPort->Open(nPort,dwBaud,spParity,DataBits,spStopbits,spFC,m_IsOverlapped); this->m_pPort->Setup(4096,4096); this->m_pPort->Purge(PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); //it is important!! COMMTIMEOUTS timeouts; this->m_pPort->GetTimeouts(timeouts); timeouts.ReadIntervalTimeout=100; this->m_pPort->SetTimeouts(timeouts); this->m_CurPortNum = nPort; //创建关闭事件 this->m_hCloseEvent = CreateEvent(NULL,true,false,NULL); ASSERT(this->m_hCloseEvent); //4.创建线程类 this->m_pReadThread = new CReadComThread(); this->m_pReadThread->BandSerialPort(this); this->m_pReadThread->Create(); this->m_pReadThread->Resume(); if(this->IsOverlapped()) { this->m_hWriteEvent = ::CreateEvent(NULL,false,false,NULL); } } void CComPort::Close() { //1.串口 if(this->m_pPort==NULL) return; if(!this->m_pPort->IsOpen()) return; //2.事件 ::SetEvent(this->m_hCloseEvent);//通知关闭系统 Sleep(1000); //3.结束读线程 try { this->m_pReadThread->Terminate(); delete this->m_pReadThread; this->m_pReadThread = NULL; } catch(char e[150]) { ::AfxMessageBox(e); } //4.结束关闭线程 ::CloseHandle(this->m_hCloseEvent); this->m_pPort->Close(); //5.结束写事件 if(this->m_hWriteEvent) { ::CloseHandle(this->m_hWriteEvent); this->m_hWriteEvent = NULL; } //6.释放串口对象 if(this->m_pPort) { delete this->m_pPort; this->m_pPort = NULL; } } void CComPort::ReceiveData(void* pBuf,DWORD InBufferCount) { if(this->m_pfnOnReceiveData) this->m_pfnOnReceiveData(this->m_pSender,pBuf,InBufferCount); } void CComPort::SetReceiveFunc(FOnReceiveData pfnOnReceiveData,LPVOID pSender) { this->m_pfnOnReceiveData = pfnOnReceiveData; this->m_pSender = pSender; } void CComPort::ComBreak(DWORD dwMask) { if(this->m_pfnOnComBreak) { COMSTAT stat; this->m_pPort->GetStatus(stat); this->m_pfnOnComBreak(this->m_pPort,dwMask,stat); } } void CComPort::SetBreakHandleFunc(FOnComBreak pfnOnComBreak) { this->m_pfnOnComBreak = pfnOnComBreak; } CComPort::ReceiveMode CComPort::GetReceiveMode() { return this->m_RecvMode; } DWORD CComPort::GetInBufferCount() { if(this->IsOverlapped()) { ::AfxMessageBox("this methord is only used for ManualQueryMode!"); return 0; } COMSTAT stat; ::ZeroMemory(&stat,sizeof(stat)); this->m_pPort->GetStatus(stat); return stat.cbInQue; } DWORD CComPort::GetInput(void* pBuf,DWORD Count,DWORD dwMilliseconds) { //不能在自动模式下getinput if(this->GetReceiveMode()==CComPort::AutoReceiveByBreak|| this->GetReceiveMode()==CComPort::AutoReceiveBySignal) { ::AfxMessageBox("Can't use GetInput methord in this mode!"); return 0; } if(this->IsOverlapped()) { ASSERT(this->m_pReadThread); DWORD dwBytes = this->m_pReadThread->ReadInput(pBuf,Count,dwMilliseconds); this->m_pPort->TerminateOutstandingReads(); return dwBytes; } else return this->m_pPort->Read(pBuf,Count); } DWORD CComPort::Output(void* pBuf,DWORD Count) { DWORD dwWriteBytes=0; if(this->IsOverlapped())//异步模式 { this->m_pPort->Write(pBuf,Count,this->m_WriteOverlapped); if(WaitForSingleObject(this->m_WriteOverlapped.hEvent,INFINITE)==WAIT_OBJECT_0) { this->m_pPort->GetOverlappedResult(this->m_WriteOverlapped,dwWriteBytes,false); } } else dwWriteBytes= this->m_pPort->Write(pBuf,Count); return dwWriteBytes; } CSerialPort* CComPort::GetSerialPort() { ASSERT(m_pPort); return m_pPort; } HANDLE CComPort::GetCloseHandle() { ASSERT(this->m_hCloseEvent); return this->m_hCloseEvent; } //CReadComThread CReadComThread::CReadComThread() { this->m_hThread = NULL; this->m_pPort = NULL; this->IsClose =false; ::ZeroMemory(&this->m_BreakOverlapped,sizeof(this->m_BreakOverlapped)); ::ZeroMemory(&this->m_ReadOverlapped,sizeof(this->m_ReadOverlapped)); memset(this->m_InputBuffer,0,2048); } CReadComThread::~CReadComThread() { this->m_hThread = NULL; } // CReadComThread 成员函数 bool CReadComThread::SetReadEvent(OVERLAPPED& overlapped) { BeginSet: if(this->m_pPort->GetSerialPort()->Read(this->m_InputBuffer,2048,overlapped,&this->m_InBufferCount)) { if(!this->HandleData()) return false; ::ResetEvent(this->m_ReadOverlapped.hEvent); goto BeginSet; } DWORD error=::GetLastError(); if(error==ERROR_IO_PENDING) { return true; } else { return false; } } bool CReadComThread::HandleData() //处理读取数据 { if(this->m_InBufferCount>0) { this->m_pBuffer = new byte[this->m_InBufferCount]; for(int i=0;i<(int)this->m_InBufferCount;i++) { this->m_pBuffer[i] = this->m_InputBuffer[i]; } //this->m_pSerialPort-> this->m_pPort->ReceiveData(this->m_pBuffer,this->m_InBufferCount); delete[] this->m_pBuffer; } return true; } bool CReadComThread::HandleReadEvent(OVERLAPPED& overlapped) { if(this->m_pPort->GetSerialPort()->GetOverlappedResult(overlapped,this->m_InBufferCount,false)) { return this->HandleData(); } DWORD dwError = ::GetLastError(); if(dwError==ERROR_INVALID_HANDLE) return false; else return true; } bool CReadComThread::SetBreakEvent(DWORD& dwMask ) { SetBegin: if(this->m_pPort->GetSerialPort()->WaitEvent(dwMask,this->m_BreakOverlapped)) { if(!this->HandleBreakEvent(dwMask)) return false; goto SetBegin; } DWORD error=::GetLastError(); if(error==ERROR_IO_PENDING) { return true; } else { return false; } //::AfxBeginThread( } bool CReadComThread::HandleBreakEvent(DWORD dwMask) { DWORD dwReadBytes; bool successed= this->m_pPort->GetSerialPort()->GetOverlappedResult(this->m_BreakOverlapped,dwReadBytes,false); if(successed) { this->m_pPort->ComBreak(dwMask); //调用处理过程 return true; } return false; } void CReadComThread::Execute() { if(this->m_pPort->GetReceiveMode()==CComPort::ManualReceiveByQuery) { this->ExecuteByManualQueryRecvMode(); } else if(this->m_pPort->GetReceiveMode()==CComPort::ManualReceiveByConst) { this->ExecuteByManualConstRecvMode(); } else if(this->m_pPort->GetReceiveMode()==CComPort::AutoReceiveBySignal) { this->ExecuteByAutoSignalRecvMode(); } else//中断模式 { this->ExecuteByAutoBreakRecvMode(); } } void CReadComThread::ExecuteByAutoSignalRecvMode() { DWORD dwMask=0; HANDLE WaitHandles[3]; //监听事件数组 DWORD dwSignaledHandle; WaitHandles[0] = this->m_pPort->GetCloseHandle(); WaitHandles[1] = this->m_ReadOverlapped.hEvent; WaitHandles[2] = this->m_BreakOverlapped.hEvent; this->m_pPort->GetSerialPort()->SetMask(EV_ERR | EV_RLSD | EV_RING ); if(!SetBreakEvent(dwMask)) goto EndThread; //设置读事件 if(!SetReadEvent(this->m_ReadOverlapped)) goto EndThread; //设置comEvent for(;;) { dwSignaledHandle=::WaitForMultipleObjects(3,WaitHandles,false,INFINITE); switch(dwSignaledHandle) { case WAIT_OBJECT_0: goto EndThread; break; case WAIT_OBJECT_0+1: if(!this->HandleReadEvent(this->m_ReadOverlapped)) goto EndThread; if(!this->SetReadEvent(this->m_ReadOverlapped)) goto EndThread; break; case WAIT_OBJECT_0+2: if(!this->HandleBreakEvent(dwMask)) goto EndThread; if(!this->SetBreakEvent(dwMask)) goto EndThread; break; default: //goto EndThread; break; } } EndThread: this->m_pPort->GetSerialPort()->Purge(PURGE_RXABORT | PURGE_RXCLEAR); ::CloseHandle(this->m_ReadOverlapped.hEvent); ::CloseHandle(this->m_BreakOverlapped.hEvent); return ; } void CReadComThread::ExecuteByManualQueryRecvMode() { DWORD dwMask=0; HANDLE WaitHandles[2]; //监听事件数组 DWORD dwSignaledHandle; WaitHandles[0] = this->m_pPort->GetCloseHandle(); this->m_pPort->GetSerialPort()->SetMask(EV_ERR | EV_RLSD | EV_RING ); this->m_pPort->GetSerialPort()->SetBreak(); for(;;) { dwSignaledHandle=::WaitForMultipleObjects(1,WaitHandles,false,INFINITE); switch(dwSignaledHandle) { case WAIT_OBJECT_0: goto EndThread; break; default: //goto EndThread; break; } this->m_pPort->GetSerialPort()->GetMask(dwMask); if(dwMask>0) { this->m_pPort->ComBreak(dwMask); } } EndThread: this->m_pPort->GetSerialPort()->Purge(PURGE_RXABORT | PURGE_RXCLEAR); return ; } void CReadComThread::ExecuteByManualConstRecvMode() { DWORD dwMask=0; HANDLE WaitHandles[2]; //监听事件数组 DWORD dwSignaledHandle; WaitHandles[0] = this->m_pPort->GetCloseHandle(); WaitHandles[1] = this->m_BreakOverlapped.hEvent; this->m_pPort->GetSerialPort()->SetMask(EV_ERR | EV_RLSD | EV_RING ); if(!SetBreakEvent(dwMask)) goto EndThread; //设置comEvent for(;;) { dwSignaledHandle=::WaitForMultipleObjects(2,WaitHandles,false,INFINITE); switch(dwSignaledHandle) { case WAIT_OBJECT_0: goto EndThread; break; case WAIT_OBJECT_0+1: if(!this->HandleBreakEvent(dwMask)) goto EndThread; if(!this->SetBreakEvent(dwMask)) goto EndThread; break; default: //goto EndThread; break; } } EndThread: this->m_pPort->GetSerialPort()->Purge(PURGE_RXABORT | PURGE_RXCLEAR); ::CloseHandle(this->m_ReadOverlapped.hEvent); ::CloseHandle(this->m_BreakOverlapped.hEvent); return ; } void CReadComThread::ExecuteByAutoBreakRecvMode() { DWORD dwMask=0; HANDLE WaitHandles[2]; //监听事件数组 DWORD dwSignaledHandle; WaitHandles[0] = this->m_pPort->GetCloseHandle(); WaitHandles[1] = this->m_BreakOverlapped.hEvent; this->m_pPort->GetSerialPort()->SetMask(EV_ERR | EV_RLSD | EV_RING | EV_RXCHAR); if(!SetBreakEvent(dwMask)) goto EndThread; //设置读事件 if(!SetReadEvent(this->m_BreakOverlapped)) goto EndThread; //设置comEvent for(;;) { dwSignaledHandle=::WaitForMultipleObjects(2,WaitHandles,false,INFINITE); switch(dwSignaledHandle) { case WAIT_OBJECT_0: goto EndThread; break; case WAIT_OBJECT_0+1: if((dwMask&EV_RXCHAR)==EV_RXCHAR) { if(!this->HandleReadEvent(this->m_BreakOverlapped)) goto EndThread; if(!SetReadEvent(this->m_BreakOverlapped)) goto EndThread; } else { if(!this->HandleBreakEvent(dwMask)) goto EndThread; if(!this->SetBreakEvent(dwMask)) goto EndThread; } break; default: //goto EndThread; break; } } EndThread: this->m_pPort->GetSerialPort()->Purge(PURGE_RXABORT | PURGE_RXCLEAR); ::CloseHandle(this->m_ReadOverlapped.hEvent); ::CloseHandle(this->m_BreakOverlapped.hEvent); return ; } DWORD WINAPI ThreadFunc(LPVOID lpParam ) { CReadComThread* pThread =(CReadComThread*)lpParam; ASSERT(pThread); pThread->m_IsTerminated = false; pThread->Execute(); pThread->m_IsTerminated = true; return 0; } void CReadComThread::Create() { m_hThread = CreateThread( NULL, // no security attributes 0, // use default stack size ThreadFunc, // thread function this, // argument to thread function CREATE_SUSPENDED, // use default creation flags &dwThreadId); // returns the thread identifier ::SetThreadPriority(m_hThread,THREAD_PRIORITY_HIGHEST); } void CReadComThread::Terminate() { char szMsg[80]; if (m_hThread == NULL) { wsprintf( szMsg, "CreateThread failed." ); ::MessageBox(NULL,szMsg,"ok",0); } else { if(!this->IsTerminated()) { Sleep(1000); } if(!this->IsTerminated()) { Sleep(1000); //::TerminateThread(m_hThread,0); } CloseHandle( m_hThread ); } } void CReadComThread::Resume() { ResumeThread(this->m_hThread); } void CReadComThread::BandSerialPort(CComPort* pPort) { ASSERT(pPort); this->m_pPort = pPort; //创建异步读取事件 if(this->m_pPort->IsOverlapped()) { this->m_ReadOverlapped.hEvent =::CreateEvent(NULL,false,false,NULL); ASSERT(this->m_ReadOverlapped.hEvent); this->m_BreakOverlapped.hEvent = ::CreateEvent(NULL,false,false,NULL); ASSERT(this->m_BreakOverlapped.hEvent); } } DWORD CReadComThread::ReadInput(void* pBuf,DWORD Count,DWORD dwMilliseconds) { DWORD dwRead=0; if(!this->m_pPort->GetSerialPort()->Read(pBuf,Count,this->m_ReadOverlapped,&dwRead)) { if(WaitForSingleObject(this->m_ReadOverlapped.hEvent,dwMilliseconds)==WAIT_OBJECT_0) { this->m_pPort->GetSerialPort()->GetOverlappedResult(this->m_ReadOverlapped,dwRead,false); } } return dwRead; } }