ComControl.cpp
上传用户:asikq0571
上传日期:2014-07-12
资源大小:528k
文件大小:10k
- // ComControl.cpp: implementation of the CComControl class.
- //
- //////////////////////////////////////////////////////////////////////
- #include "stdafx.h"
- //#include "MnRTU.h"
- #include "ComControl.h"
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[]=__FILE__;
- #define new DEBUG_NEW
- #endif
- //////////////////////////////////////////////////////////////////////
- // Construction/Destruction
- //////////////////////////////////////////////////////////////////////
- //功能 : 工作线程函数,监测串口事件,当事件发生时给出通知,para是串口对象指针
- UINT ComThreadProc(LPVOID para)
- {
- CComControl* pCom = (CComControl*)para;
- DWORD dwErrWord;
- COMSTAT comstat;
- DWORD dwEventMask;
- OVERLAPPED eov;
- memset( &eov, 0, sizeof( OVERLAPPED ) ) ;
- eov.hEvent = CreateEvent( NULL, // no security attributes
- FALSE, // auto reset event
- FALSE, // not signaled
- NULL // no name
- );
- while(true)
- {
- if(pCom->m_bExit)
- break;
- ClearCommError(pCom->m_hCom, &dwErrWord, &comstat);
- if(comstat.cbInQue)
- {
- SendMessage( pCom->m_hOwner, WM_COMMNOTIFY, EV_RXCHAR,0);
- continue;
- }
- dwEventMask = 0;
- WaitCommEvent(pCom->m_hCom, &dwEventMask, &eov);
- WaitForSingleObject(eov.hEvent, 2000);
- ClearCommError(pCom->m_hCom, &dwErrWord, &comstat);
- if (dwEventMask & EV_ERR) // 线路错误CE_FRAME, CE_OVERRUN, and CE_RXPARITY.
- {
- SendMessage( pCom->m_hOwner, WM_COMMNOTIFY, EV_ERR , dwErrWord);
- }
- if (dwEventMask & EV_TXEMPTY) // 输出缓冲区空
- {
- SendMessage( pCom->m_hOwner, WM_COMMNOTIFY, EV_TXEMPTY ,0 );
- }
- if(dwEventMask & EV_RXCHAR && comstat.cbInQue != 0)
- { // 输入缓冲区接收到一字符
- SendMessage( pCom->m_hOwner, WM_COMMNOTIFY, EV_RXCHAR,0);
- }
- }
- CloseHandle(eov.hEvent);
- return true;
- }
- CComControl::CComControl()
- {
- m_bExit = FALSE;
- //m_hOwner = hOwner;
- InitCom();
- }
- //功能 : 初始化对象数据
- void CComControl::InitCom()
- {
- memset( &m_ovRead, 0, sizeof( OVERLAPPED ) ) ;
- memset( &m_ovWrite, 0, sizeof( OVERLAPPED ) ) ;
- m_ovRead.hEvent = CreateEvent( NULL, // no security
- TRUE, // explicit reset req
- FALSE, // initial event reset
- NULL ) ; // no name
-
- m_ovWrite.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); // See above
- m_szPortName = "COM1";
- m_nBaudRate = 9600;
- m_nParity = NOPARITY;
- m_nDataBits = 8;
- m_nStopBits = ONESTOPBIT;
- m_hCom = INVALID_HANDLE_VALUE;
- m_pThread = AfxBeginThread(ComThreadProc, (LPVOID)this,THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
- }
- CComControl::~CComControl()
- {
- m_bExit = TRUE;
- m_pThread->ResumeThread();
- WaitForSingleObject(m_pThread->m_hThread, INFINITE);
- m_pThread = NULL; //this ensure pCom->ClosePort work correct
- ClosePort();
- CloseHandle(m_ovRead.hEvent);
- CloseHandle(m_ovWrite.hEvent);
- }
- //功能: 返回串口中等待读取的字节数
- DWORD CComControl::BytesInQue()
- {
- DWORD dwErrWord;
- COMSTAT comstat;
- ClearCommError(m_hCom, &dwErrWord, &comstat);
- return comstat.cbInQue;
- }
- //功能: 返回串口中等待写出的字节数
- DWORD CComControl::BytesOutQue()
- {
- DWORD dwErrWord;
- COMSTAT comstat;
- ClearCommError(m_hCom, &dwErrWord, &comstat);
- return comstat.cbOutQue;
- }
- //功能: 打开串口,串口参数是对象缺省的或通过SetParam设置的
- bool CComControl::OpenPort()
- {
- //fill dcb
- DCB dcb;
- memset(&dcb, 0, sizeof(dcb));
- dcb.DCBlength = sizeof(dcb);
- dcb.fBinary = 1;
- dcb.BaudRate = m_nBaudRate;
- dcb.Parity = (BYTE)m_nParity;
- if(m_nParity != NOPARITY)
- dcb.fParity = true;
- dcb.ByteSize = (BYTE)m_nDataBits;
- dcb.StopBits = (BYTE)m_nStopBits;
- dcb.fDtrControl = DTR_CONTROL_DISABLE;
- dcb.fRtsControl = RTS_CONTROL_DISABLE;
-
- //fill timeout
- COMMTIMEOUTS timeouts;
- timeouts.ReadIntervalTimeout = 100*1000 / m_nBaudRate; //100bit传输时间(ms)
- if(timeouts.ReadIntervalTimeout < 50)
- timeouts.ReadIntervalTimeout = 50;
- timeouts.ReadTotalTimeoutConstant = 0;
- timeouts.ReadTotalTimeoutMultiplier = timeouts.ReadIntervalTimeout;
- timeouts.WriteTotalTimeoutConstant = 0;
- timeouts.WriteTotalTimeoutMultiplier= timeouts.ReadIntervalTimeout;
- CString szNo = m_szPortName.Right(m_szPortName.GetLength()-3);
- int PortNo = _ttoi(szNo);
- return OpenPort(PortNo, dcb, timeouts);
- }
- bool CComControl::OpenPort(int nPortNo, DCB& dcb, COMMTIMEOUTS& timeouts)
- {
- CString szErr;
- if(m_hCom != INVALID_HANDLE_VALUE)
- {
- ClosePort();
- Sleep(100); // i don't know reason,if don't do this,OpenPort may fail
- }
- m_szPortName.Format(_T("COM%d"),nPortNo);
- //create file
- int nTryTime = 1;
- while(nTryTime < 4)
- {
- m_hCom = CreateFile( _T("\\.\")+m_szPortName,
- GENERIC_READ|GENERIC_WRITE,
- 0,
- NULL, //lpsa,
- OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED,
- NULL
- );
- if(m_hCom != INVALID_HANDLE_VALUE)
- {
- break;
- }
- nTryTime++;
- Sleep(10);
- }
- if(m_hCom == INVALID_HANDLE_VALUE)
- {
- szErr.Format(_T("CComControl::OpenPort:打开串口错误:%d"), GetLastError());
- //AfxMessageBox(szErr);
- return false;
- }
- //MOXA NPort Server Pro required
- dcb.XonChar = 17;
- dcb.XoffChar = 19;
- m_nBaudRate = dcb.BaudRate;
- m_nParity = dcb.Parity;
- if( !SetCommState(m_hCom, &dcb) || //dcb
- !SetupComm(m_hCom, 2048, 2048) || //communication buffer
- !SetCommTimeouts(m_hCom, &timeouts) || //time out parameter
- !SetCommMask(m_hCom, EV_RXCHAR | EV_TXEMPTY | EV_ERR) || //event mask
- !PurgeComm(m_hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR )
- )
- {
- szErr.Format(_T("CComControl::OpenPort:打开串口错误:%d"), GetLastError());
- //AfxMessageBox(szErr);
- m_pThread->ResumeThread();
- ClosePort();
- return false;
- }
- m_pThread->ResumeThread();
- return true;
- }
- //功能: 关闭串口
- void CComControl::ClosePort()
- {
- if(m_hCom != INVALID_HANDLE_VALUE)
- {
- if(m_pThread)
- m_pThread->SuspendThread();
- PurgeComm(m_hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR );
- CloseHandle(m_hCom);
- m_hCom = INVALID_HANDLE_VALUE;
- }
- }
- //设置串口参数,它显示一对话框,可以设置端口号、波特率、校验方式,它不改变串口的打开状态
- void CComControl::SetParam()
- {
- }
- //功能: 设置串口参数,包括端口号、波特率、校验方式,它不改变串口的打开状态
- void CComControl::SetParam(LPCTSTR szPortName, int nBaudRate, int nParity)
- {
- m_szPortName = szPortName;
- m_nBaudRate = nBaudRate;
- m_nParity = nParity;
- if(m_hCom != INVALID_HANDLE_VALUE)
- {
- ClosePort();
- Sleep(100); // i don't know reason,if don't do this,OpenPort may fail
- OpenPort();
- }
- }
- //下面的读写函数将阻塞调用线程
- //如果读写成功返回TRUE,如果超时或有其他错误返回FALSE
- //通过串口发送数据, pBuff发送缓冲区,dwBytesToSend缓冲区中要发送的字节数
- BOOL CComControl::Send(BYTE* pBuff, DWORD dwBytesToSend)
- {
- DWORD dwBytesSended;
- return Send(pBuff,dwBytesToSend, dwBytesSended);
- }
- //通过串口发送数据, pBuff发送缓冲区,dwBytesToSend缓冲区中要发送的字节数,dwBytesSended为发送的字节数
- BOOL CComControl::Send(BYTE* pBuff, DWORD dwBytesToSend, DWORD& dwBytesSended)
- {
- CString szErr;
- dwBytesSended = 0;
- if(!PortOpened())
- {
- // RecordDAErr(_T("CComControl::Send:端口未打开"));
- return FALSE;
- }
- BOOL wRes;
- wRes = WriteFile(m_hCom, pBuff, dwBytesToSend, &dwBytesSended, &m_ovWrite);
- if(!wRes) { //there are some data not send
- if(GetLastError() == ERROR_IO_PENDING) {
- WaitForSingleObject(m_ovWrite.hEvent, 10*1000); //this block the calling thread
- wRes = GetOverlappedResult(m_hCom, &m_ovWrite,&dwBytesSended,false);
- if(dwBytesSended != dwBytesToSend) {
- wRes = FALSE;
- }
- } else { // an error occured
- wRes = FALSE;
- }
- }
- if(!wRes) {
- szErr.Format(_T("CComControl::Send:发送错误:%d"), GetLastError());
- // RecordDAErr(szErr);
- ClearPort();
- }
- return wRes;
- }
- //通过串口接收数据, pBuff接收缓冲区,dwBytesToRead要接收的字节数
- BOOL CComControl::Receive(BYTE* pBuff, DWORD dwBytesToRead)
- {
- DWORD dwBytesReaded;
- return Receive(pBuff,dwBytesToRead, dwBytesReaded);
- }
- //通过串口接收数据, pBuff接收缓冲区,dwBytesToRead要接收的字节数,dwBytesSended为接收的字节数
- BOOL CComControl::Receive(BYTE* pBuff, DWORD dwBytesToRead, DWORD& dwBytesReaded)
- {
- CString szErr;
- dwBytesReaded = 0;
- if(!PortOpened())
- {
- szErr.Format(_T("CComControl::Receive:端口未打开"));
- // RecordDAErr(szErr);
- return FALSE;
- }
- BOOL rRes = ReadFile(m_hCom, pBuff, dwBytesToRead, &dwBytesReaded, &m_ovRead);
- if(!rRes )
- {
- if (GetLastError() == ERROR_IO_PENDING)
- {
- WaitForSingleObject(m_ovRead.hEvent, 10*1000); //this block the calling thread,if err or timeout it return
- rRes = GetOverlappedResult(m_hCom, &m_ovRead, &dwBytesReaded, false);
- if( dwBytesReaded != dwBytesToRead)
- {
- // an error occurred, i think it most was timeout also it return when line error
- //if an error occurred, we will clear it in our com thread which wait error event.
- rRes = FALSE;
- }
- }
- else
- {
- rRes = FALSE;
- }
- }
- if(!rRes)
- {
- szErr.Format(_T("CComControl::Receive:接收错误:%d"), GetLastError());
- // RecordDAErr(szErr);
- ClearPort();
- }
- return rRes;
- }
- //清除串口错误,放弃正在发送和接收的数据
- void CComControl::ClearPort()
- {
- if(m_hCom == INVALID_HANDLE_VALUE)
- return;
- PurgeComm(m_hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR );
- DWORD dwErr;
- COMSTAT stat;
- ClearCommError(m_hCom, &dwErr, &stat);
- }
- //清除串口错误
- void CComControl::ClearErr()
- {
- DWORD dwErr;
- COMSTAT stat;
- ClearCommError(m_hCom, &dwErr, &stat);
- }
- void CComControl::Serialize(CArchive &ar)
- {
- if(ar.IsStoring())
- {
- ar << m_nStopBits; //停止位
- ar << m_nDataBits; //数据位
- ar << m_szPortName; //串口名
- ar << m_nBaudRate; //波特率
- ar << m_nParity; //校验方式
- }
- else
- {
- ar >> m_nStopBits; //停止位
- ar >> m_nDataBits; //数据位
- ar >> m_szPortName; //串口名
- ar >> m_nBaudRate; //波特率
- ar >> m_nParity; //校验方式
- }
- CObject::Serialize(ar);
- }