15,471
社区成员
发帖
与我相关
我的任务
分享
CCom_C1::CCom_C1(void)
: m_strData(_T(""))
,m_nTimeOut(10000)
,m_bSending(FALSE)
, m_hWnd(NULL)
{
hComm = NULL;
m_nPort= 0;
m_nBaud= 0;
m_nData= 0;
m_nParity= 0;
m_nStop = 0;
m_bComOpen= FALSE;
m_bThreadAlive = FALSE;
///初始化异步结构体
m_ov.Offset = 0;
m_ov.OffsetHigh = 0;
// create events
m_ov.hEvent = NULL;
m_hWriteEvent = NULL;
m_hShutdownEvent = NULL;
// create events
m_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
m_hEventArray[0] = m_hShutdownEvent; // highest priority
m_hEventArray[1] = m_hWriteEvent;
m_hEventArray[2] = m_ov.hEvent;
InitializeCriticalSection(&m_csCommunicationSync);
}
CCom_C1::~CCom_C1(void)
{
// close Handles
if (m_hShutdownEvent != NULL)
{
CloseHandle(m_hShutdownEvent);
}
if (m_ov.hEvent != NULL)
{
CloseHandle(m_ov.hEvent);
}
if (m_hWriteEvent != NULL)
{
CloseHandle(m_hWriteEvent);
}
//释放临界资源
DeleteCriticalSection(&m_csCommunicationSync);
}
BOOL CCom_C1::OpenPort(HWND hWnd)
{
if(!IsWindow(hWnd)) return false;
if (IsOpen())
{
return true;
}
m_hWnd = hWnd;
m_bSending = FALSE;
m_strData = _T("");
m_strData.Empty();
//进入临界区
EnterCriticalSection(&m_csCommunicationSync);
CString szCom;
szCom.Format(_T("\\\\.\\COM%d"), m_nPort);
hComm = CreateFile(szCom.GetBuffer(50),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL|
FILE_FLAG_OVERLAPPED, // Async I/O
NULL);
if(hComm==INVALID_HANDLE_VALUE)
{
DWORD dwErr= GetLastError();
::MessageBox(NULL,_T("Cannot Open Communication Port.Please Check Communication Port Setting Whether Correctly."),_T("PLC Com Port Error"),MB_OK+MB_ICONERROR);
m_bComOpen=false;
return FALSE;
}
DCB m_dcb;
memset(&m_dcb,0,sizeof(m_dcb));
if(GetCommDCB(&m_dcb))///获取当前DCB参数
{
if (!SetCommDCB(&m_dcb))//设置新参数
{
//错误处理
CloseHandle(hComm);
hComm=NULL;
m_bComOpen =false;
return FALSE;
}
}
else//错误处理,不能获取当前配置
{
CloseHandle(hComm);
hComm=NULL;
m_bComOpen =false;
return FALSE;
}
COMMTIMEOUTS m_CommTimeouts;
if(GetCommTimeouts(hComm, &m_CommTimeouts))
{
m_CommTimeouts.ReadIntervalTimeout =MAXDWORD;//指定了在接收字符间的最大时间,如果超过了这个时间,ReadFile立即返回
m_CommTimeouts.ReadTotalTimeoutConstant = 0;//表示读数据总时间常量
m_CommTimeouts.ReadTotalTimeoutMultiplier = 0;//表示平均读一个字节的时间上限
m_CommTimeouts.WriteTotalTimeoutConstant = 2000;//表示写数据总超时常量
m_CommTimeouts.WriteTotalTimeoutMultiplier =50;//表示平均写一个字节的时间上限
}
else
{
m_bComOpen =false;
return FALSE;
}
//给定串口读与操作限时
if(!SetCommTimeouts(hComm, &m_CommTimeouts))
{
TRACE(_T("SetCommTimeouts Error!"));
CloseHandle(hComm);
hComm=NULL;
m_bComOpen =false;
return FALSE;
}
// 设置串口缓冲区,输入/输出大小(字节数)
SetupComm(hComm, 1024, 1024);
// 用来指定程序接收特定的串口事件_收到字符放入缓冲区
SetCommMask(hComm, EV_RXCHAR) ;//监视串口中有无数据,一旦就激活WaitCommEvent。(设置我们关心的事件)
//刷清缓冲区,终止读写并清空接收和发送
PurgeComm(hComm, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ) ;
LeaveCriticalSection(&m_csCommunicationSync);
m_bComOpen=true;
m_Thread = ::CreateThread(NULL, 0, ThreadProc_C1, this, 0, NULL);
m_bThreadAlive=TRUE;
return TRUE;
}
void CCom_C1::ClosePort()
{
MSG message;
if (!IsOpen())//当端口未打开时
{
return;
}
m_bSending = FALSE;
m_bThreadAlive=FALSE;
//设置所有事件无效无效
SetCommMask(hComm, 0);
//清空所有将要读的数据
PurgeComm( hComm, PURGE_RXCLEAR |PURGE_RXABORT|PURGE_TXCLEAR|PURGE_TXABORT);
if (SuspendThread(m_Thread)!=-1)
{
ResumeThread(m_Thread);
}
do
{
SetEvent(m_hShutdownEvent);//通知关闭系统
Sleep(1000);
if (::PeekMessage(&message, m_hWnd, 0, 0, PM_REMOVE))
{
::TranslateMessage(&message);
::DispatchMessage(&message);
}
} while (m_bThreadAlive);
//关闭串口句柄
if(hComm = INVALID_HANDLE_VALUE)
{
m_bComOpen =false;
}
else
{
CloseHandle(hComm);
hComm = NULL;
}
}
void CCom_C1::WriteChar(CCom_C1* pThis)
{
DWORD dwStartTime = 0;
while(pThis->m_bThreadAlive)
{
PC1_CMD_SEND_INFO pCmdInfo = pThis->GetNextCmd();
if(pCmdInfo)
{
pThis->m_nCmdSending = pCmdInfo->nCmd;
PBYTE sendData=(LPBYTE)pCmdInfo->szCmd;
int sendLen= strlen(pCmdInfo->szCmd);
DWORD BytesSend=0;
DWORD dwError;
COMSTAT m_comstat;
EnterCriticalSection(&pThis->m_csCommunicationSync);
ResetEvent(pThis->m_hWriteEvent);
// Initailize variables
pThis->m_ov.Offset = 0;
pThis->m_ov.OffsetHigh = 0;
PurgeComm(pThis->hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
ClearCommError(pThis->hComm,&dwError,&m_comstat);
if (!WriteFile(pThis->hComm,sendData, sendLen,&BytesSend,&pThis->m_ov))
{
DWORD dwError = GetLastError();
}
GetOverlappedResult(pThis->hComm,&pThis->m_ov,&BytesSend,TRUE); // Wait flag
LeaveCriticalSection(&pThis->m_csCommunicationSync);
delete []pCmdInfo->szCmd;
pCmdInfo->szCmd = NULL;
delete pCmdInfo;
}
}
}
//响应函数
void CCom_C1::ReceiveStr(CCom_C1* pThis)
{
DWORD dwRealRead;
DWORD dwError;
DWORD dwWantRead;
COMSTAT m_comstat;
for (;;)
{
EnterCriticalSection(&pThis->m_csCommunicationSync);
//防止死锁
if (WaitForSingleObject(pThis->m_hShutdownEvent, 0) == WAIT_OBJECT_0)
return;
if(pThis->m_nCmdSending == C1_No)//此时没有任何指令
{
pThis->ClearReadBuffer();
return;
}
pThis->m_bSending = true;//发送接受进行时
ClearCommError(pThis->hComm,&dwError,&m_comstat);
dwWantRead=m_comstat.cbInQue;
if (m_comstat.cbInQue == 0 || m_comstat.cbInQue == 0xcccccccc)
{
break;
}
//如果遇到'\0',那么数据会被截断,实际数据全部读取只是没有显示完全,这个时候使用memcpy才能全部获取
char RXBuff[512];
memset(RXBuff,0,sizeof(char)*512);
dwWantRead = min(dwWantRead,512);
RXBuff[dwWantRead] = '\0';//附加字符串结束符
ReadFile(pThis->hComm,RXBuff,dwWantRead,&dwRealRead,&pThis->m_ov);
pThis->m_strData += RXBuff;
GetOverlappedResult(pThis->hComm,&pThis->m_ov,&dwRealRead,TRUE);
::PostMessage(pThis->m_hWnd , WM_PEEKCOMDATA, MAKEWPARAM(0,pThis->m_nCmdSending), 1); //工作线程中不要修改主界面,发送消息响应
LeaveCriticalSection(&pThis->m_csCommunicationSync);
pThis->ClearReadBuffer();
pThis->m_strData = _T("");
pThis->m_bSending = false;
}
}
DWORD WINAPI CCom_C1::ThreadProc_C1(LPVOID lParam)//LPVOID没有类型的指针
{
CCom_C1 * pThis = (CCom_C1 *) lParam;
DWORD BytesTransfered = 0;
DWORD Event;
DWORD CommEvent;
DWORD dwError = 0;
COMSTAT comstat;
BOOL bResult = TRUE;
if (pThis->hComm) // check if the port is opened
{
PurgeComm(pThis->hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
}
for (;;)
{
bResult = WaitCommEvent(pThis->hComm, &Event, &pThis->m_ov);///表示该函数是异步的
if (!bResult)
{
switch (dwError = GetLastError())
{
case ERROR_IO_PENDING: ///正常情况,没有字符可读 erroe code:997
{
break;
}
case ERROR_INVALID_PARAMETER:///系统错误 erroe code:87
{
break;
}
case ERROR_ACCESS_DENIED:///拒绝访问 erroe code:5
{
pThis->hComm = INVALID_HANDLE_VALUE;
TCHAR Temp[200] = { 0 };
_stprintf_s(Temp, 200, _T("COM%d ERROR_ACCESS_DENIED,WaitCommEvent() Error Code:%d"), pThis->m_nPort, GetLastError());
::MessageBox(NULL, Temp, _T("COM WaitCommEvent Error"), MB_ICONERROR);
break;
}
case ERROR_INVALID_HANDLE:///打开串口失败 erroe code:6
{
pThis->hComm = INVALID_HANDLE_VALUE;
::MessageBox(NULL, _T("Open COM Failed"), _T("COM Error"), MB_ICONERROR);
break;
}
case ERROR_BAD_COMMAND:///连接过程中非法断开 erroe code:22
{
pThis->hComm = INVALID_HANDLE_VALUE;
TCHAR Temp[200] = {0};
_stprintf_s(Temp, 200, _T("COM%d ERROR_BAD_COMMAND,WaitCommEvent() Error Code:%d"), pThis->m_nPort, GetLastError());
::MessageBox(NULL, Temp, _T("COM WaitCommEvent Error"), MB_ICONERROR);
break;
}
default:///发生其他错误,其中有串口读写中断开串口连接的错误(错误22)
{
//发生错误时,将串口句柄置为无效句柄
pThis->hComm = INVALID_HANDLE_VALUE;
::MessageBox(NULL, _T("COM Other Problem"), _T("COM Error"), MB_ICONERROR);
break;
}
}
}
else ///WaitCommEvent()能正确返回
{
bResult = ClearCommError(pThis->hComm, &dwError, &comstat);
if (comstat.cbInQue == 0)
continue;
} // end if bResult
Event = MsgWaitForMultipleObjects(3, ///3个事件
pThis->m_hEventArray, ///事件数组
FALSE, ///有一个事件发生就返回
INFINITE,
QS_ALLEVENTS);///超时时间
if (Event >= WAIT_OBJECT_0 && Event < WAIT_OBJECT_0 + 3)
{
for (int i = Event - WAIT_OBJECT_0 - 1; i < 3; i++)
{
if (WaitForSingleObject(pThis->m_hEventArray[i], 0) == WAIT_OBJECT_0)
{
switch (Event)
{
case WAIT_OBJECT_0 + 0:
{
///关断事件,关闭串口
CloseHandle(pThis->hComm);
pThis->hComm = NULL;
pThis->m_bThreadAlive = FALSE;
pThis->m_bComOpen=false;
pThis->RemoveAllCmdFromList();
::ExitThread(1000);
break;
}
case WAIT_OBJECT_0 + 1: // write event 发送数据
{
// Write character event from port
WriteChar(pThis);
break;
}
case WAIT_OBJECT_0 + 2: // read event 将定义的各种消息发送出去
{
GetCommMask(pThis->hComm, &CommEvent);
if (CommEvent & EV_RXCHAR) //接收到字符,并置于输入缓冲区中
{
ReceiveStr(pThis);
}
break;
}
} // end switch
}
}
}
}
return 0;
}