📄 serialbase.cpp
字号:
// SerialBase.cpp: implementation of the CSerialBase class.
//
//////////////////////////////////////////////////////////////////////
//History
//*Data *Name *comments.
//2008-Feb-03 Rock Li Initialization
#include "stdafx.h"
#include "SerialBase.h"
#include <windows.h>
#include <malloc.h>
DWORD WINAPI CommWatchPorc(LPVOID pParam);
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
static char m_szComName[12]; // Serial port name, such as COM1 and COM2
static bool m_bComDevOpen; //True for being open; False for being close. Serail device.
static HANDLE m_hComDev; //com port
static HANDLE m_hComEvent; //com port event of receiving and errors.
static HANDLE m_hProExit; // program exit event; it should be passed by the caller.
static HANDLE m_hOpSem; // Operation semaphore; 0/1 semaphore
static HANDLE m_hCommWatchThread; // identification for CommWatchPorc;
static HANDLE m_hCommWatchThreadExit; // the flag of the exit of CommWatchPorc thread;
static SafeMsgQue m_AckMsgQue; //the responsive message from APP CPU
static SafeMsgQue m_RxMsgQue; //the message received from APP CPU. it is not a responsive message
static unsigned char m_szAckCmd[129];
static OVERLAPPED m_ovRead; // read overlapped
static OVERLAPPED m_ovWrite; //write overlapped
bool Init(HANDLE hProExit, unsigned char szAckCmd[],char szComName[])
{
m_bComDevOpen = false;
if(szComName == NULL)
{
strcpy(m_szComName,"COM1");
}
else
{
strcpy(m_szComName,szComName);
}
m_hComDev = CreateFile( m_szComName, //the name of the COM port
GENERIC_READ|GENERIC_WRITE, //RW attribute
0, //unshared
NULL, //default safe attribute
OPEN_EXISTING, //the com device exists.
FILE_FLAG_OVERLAPPED,//FILE_ATTRIBUTE_NORMAL,//non-synchronization
NULL); // no template file for com port
if(m_hComDev == INVALID_HANDLE_VALUE)
{
return FALSE;
}
//To set the parameters for com port I can edit it in source insight.
//set timeout
COMMTIMEOUTS timeout;
timeout.ReadIntervalTimeout = 1000;
timeout.ReadTotalTimeoutMultiplier = 500;
timeout.ReadTotalTimeoutConstant = 5000;
timeout.WriteTotalTimeoutMultiplier = 500;
timeout.WriteTotalTimeoutConstant = 2000;
SetupComm(m_hComDev,512,512); // 4k buffer to read and write separately
// other parameters
DCB dcb;
GetCommState(m_hComDev,&dcb); //to get the default configuration of the Com port
//now, to change the default configuration of the Com port
dcb.BaudRate = CBR_9600; // Baud Rate is set at 9600
dcb.fParity = NOPARITY; //no parity check
dcb.ByteSize = 8; //byte size is 8
dcb.StopBits = ONESTOPBIT; // one stop bit for COM communication
DWORD dwMask =0;
GetCommMask(m_hComDev,&dwMask);
SetCommMask(m_hComDev, EV_ERR|EV_RXCHAR|EV_TXEMPTY);//|EV_CTS);//EV_TXEMPTY
SetCommState(m_hComDev,&dcb); //to set the configuration of the comm port.
// PurgeComm(m_hComDev,PURGE_TXCLEAR);
// PurgeComm(m_hComDev,PURGE_TXCLEAR|PURGE_RXCLEAR);//
PurgeComm( m_hComDev, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR );
// Safe Operation semaphore; 0/1 semaphore
HANDLE m_hOpSem = CreateSemaphore(
NULL, // default security attributes
0, // initial count
1, // maximum count
NULL); // unnamed semaphore
if (m_hOpSem == NULL)
{
return false; //failure to Create
}
m_hProExit = hProExit; // program exit event; it should be passed by the caller.
SafeMsgQueInit(m_hProExit, &m_AckMsgQue);
SafeMsgQueInit(m_hProExit, &m_RxMsgQue);
m_ovRead.Offset =0;
m_ovRead.OffsetHigh =0;
m_ovRead.hEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // initial state is not signaled
"ovRead" // object name
);
if (m_ovRead.hEvent == NULL)
{
return false; //failure to Create
}
m_ovWrite.Offset =0;
m_ovWrite.OffsetHigh =0;
m_ovWrite.hEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // initial state is not signaled
"ovWrite" // object name
);
if (m_ovWrite.hEvent == NULL)
{
return false; //failure to Create
}
//m_szAckCmd
memset((void*)m_szAckCmd, 0, sizeof(m_szAckCmd));
unsigned char *pCmd =m_szAckCmd;
while((*pCmd++ = *szAckCmd++) != 0x00) ;
m_bComDevOpen = true;
//To start a new thread to watch the received data.
DWORD dwThreadId;
m_hCommWatchThread = NULL;
m_hCommWatchThread = CreateThread(
NULL, // default security attributes
0, // use default stack size
CommWatchPorc, // thread function
NULL, // the argument for thread function
0, // use default creation flags
&dwThreadId); // returns the thread identifier
// Check the return value for success.
if (m_hCommWatchThread== NULL)
{
return false;
}
m_hCommWatchThreadExit = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
TRUE, // initial state is signaled
"CommWatchThreadExit" // object name
);
if (m_hCommWatchThreadExit == NULL)
{
return false; //failure to Create
}
return true;
}
bool CleanUp()
{
m_bComDevOpen = false;
//To destroy the Operation handle identify.
if(m_hOpSem != NULL)
{
CloseHandle(m_hOpSem);
m_hOpSem = NULL;
}
//To destroy the Com port handle identify.
// if(m_hComDev != NULL)
{
//After we change the configuration, some errors Event should happen.
SetCommMask(m_hComDev,0);
CloseHandle(m_hComDev); //Maybe it works. try
//To wait for exit of CommWatch thread and destroy the handle identify.
if(m_hCommWatchThreadExit != NULL)
{
//To wait the exit of CommWatch Thread
DWORD dwWaitResult = WaitForSingleObject(
m_hCommWatchThreadExit, //To handle exit of CommWatch Thread
INFINITE); // To wait forever until the thread exits.
CloseHandle(m_hCommWatchThreadExit);
m_hCommWatchThreadExit = NULL;
}
m_hComDev = NULL;
}
//To destroy the Com essential Event handle identify.
if(m_hComEvent != NULL)
{
CloseHandle(m_hComEvent);
m_hComEvent = NULL;
}
if(m_ovWrite.hEvent != NULL)
{
CloseHandle(m_ovWrite.hEvent);
m_ovWrite.hEvent = NULL;
}
if(m_ovRead.hEvent != NULL)
{
CloseHandle(m_ovRead.hEvent);
m_ovRead.hEvent = NULL;
}
return true;
}
//This function is to send data to com port
//Parameters:
//lpBuffer : the data to be sent
//dwBytesToWrite : the length of the data
bool WriteComm(unsigned char* lpBuffer, const DWORD dwBytesToWrite)
{
//only if the Com device is initialized correctly, and it has been open, it can work.
if(!m_bComDevOpen)
{
return false;
}
DWORD dwBytesWritten = 0; // the length of data is sent by one time.
DWORD dwBytesSent = 0; // the length of data is sent to COM port
DWORD dwRemainderBytesToWrite = dwBytesToWrite;
BOOL bWriteStatus = true;
bWriteStatus = WriteFile (m_hComDev,lpBuffer,dwBytesToWrite,&dwBytesWritten,&m_ovWrite);
//this is another way to deal with waiting.
/*
if (!bWriteStatus )
{
WaitForSingleObject(m_ovWrite.hEvent ,INFINITE);
}
*/
if(!bWriteStatus)
{
if(GetLastError() == ERROR_IO_PENDING)
{
while(!GetOverlappedResult(m_hComDev,&m_ovWrite,&dwBytesWritten,true))
{
if(GetLastError() == ERROR_IO_PENDING)
{
//normal result if not finished
dwBytesSent += dwBytesWritten;
continue;
}
else
{
//some error occurs.
}
}
dwBytesSent += dwBytesWritten;
if(dwBytesSent != dwBytesToWrite)
{
//some error occurs. It will never happen.
}
}
else
{
//some error occurs. It will never happen
}
}
return true;
}
//This function is to write a message into acknowledged message queue or common message queue;
//if the message is a responsive message, it will be insert into acked message queue.
//if the message if a message originally sent by APP CPU, such as urgent messages,
// it will be insert received message queue.
bool WriteOneMsgIntoQue(unsigned char szMessage[])
{
if(!m_bComDevOpen)
{
return false;
}
bool bAckCmd = false; // whether the message is an original upload command.
unsigned char *pAckCmd = m_szAckCmd;
while(*pAckCmd != '\0' )
{
if (*szMessage == *pAckCmd) //the first character holds the command.
{
bAckCmd = true;
break;
}
pAckCmd++;
}
if(bAckCmd)
{
MsgNode* pMsgNode = (MsgNode*)malloc(sizeof(MsgNode));
memset((void*)pMsgNode,0,sizeof(MsgNode));
pMsgNode->next = NULL;
memcpy(pMsgNode->Buf, szMessage,szMessage[1]); ////the first character holds the length of the data.
InsertOneMsg(pMsgNode, &m_AckMsgQue);
}
else
{
MsgNode* pMsgNode = (MsgNode*)malloc(sizeof(MsgNode));
memset((void*)pMsgNode,0,sizeof(MsgNode));
pMsgNode->next = NULL;
memcpy(pMsgNode->Buf, szMessage,szMessage[1]);
InsertOneMsg(pMsgNode, &m_RxMsgQue);
}
return true;
}
//This function is to Receive a whole message from APP CPU.
//If the data received is not a message, we should pack some data into a message.
//If the Message is a responsive message from APP CPU, it will be insert into m_AckedMsgQue (the acked message queue).
//the function that has sent data to APP CPU, should wait the responsive message by waiting for an semaphore.
//if the message is a initial message from APP CPU, it will be insert into RxMsgQue(the received message queue).
//
//Parameters: none.
//This function should be advanced by the change of the Serial code of APP CPU
//we can make this function read 80 characters one time.
bool ReadComm()
{
const DWORD dwMsgLen = 78; //the whole length of data 78
static bool bNewMessage = true;
static unsigned char szRevBuf[79]; //dwMsgLen + 1
static DWORD dwBytesToRead = dwMsgLen; //the length of data to be read by one time.
static DWORD dwAllBytesRead =0; //the length of data that has been read.
DWORD dwBytesRead =0; //the length of data to have been read by one time.
if(!m_bComDevOpen)
{
return false;
}
if(bNewMessage)
{
memset((void*)szRevBuf, 0, sizeof(szRevBuf));
dwBytesToRead = dwMsgLen;
dwAllBytesRead = 0;
}
COMSTAT comStat;
DWORD dwErrorCode;
ClearCommError(m_hComDev,&dwErrorCode,&comStat);
dwBytesToRead = dwBytesToRead < comStat.cbInQue ? dwBytesToRead:comStat.cbInQue;
if(dwBytesToRead >0)
{
BOOL bReadStatus =ReadFile(m_hComDev, szRevBuf, dwBytesToRead,&dwBytesRead,&m_ovRead);
if(!bReadStatus)
{
if(GetLastError() == ERROR_IO_PENDING)
{
DWORD dwBytesReadInPening =0;
while(!GetOverlappedResult(m_hComDev,&m_ovRead,&dwBytesReadInPening,true))
{
if(GetLastError() == ERROR_IO_PENDING)
{
//normal result if not finished
dwBytesRead += dwBytesReadInPening;
continue;
}
else
{
//some error occurs.
}
}//end while
dwBytesRead += dwBytesReadInPening;
if(dwBytesRead != dwBytesToRead)
{
//some error occurs.
}
}//end of ERROR_IO_PENDING
}//end of !bReadStatus
else
{
// bNewMessage = true;
// WriteOneMsgIntoQue(szRevBuf);
//read the message by one time; no pending. very good.
}
}//end of dwBytesToRead >0
dwAllBytesRead += dwBytesRead; // all the bytes that has been read from UART
dwBytesToRead = dwMsgLen - dwAllBytesRead; //The remained bytes to be read next time
if(dwAllBytesRead == dwMsgLen)
{
bNewMessage = true;
WriteOneMsgIntoQue(szRevBuf);
}
else
{
bNewMessage = false;
}
return true;
}
DWORD WINAPI CommWatchPorc(LPVOID pParam)
{
while(m_bComDevOpen)
{
DWORD dwEventMask = 0;
SetCommMask( m_hComDev, EV_RXCHAR|EV_TXEMPTY );
WaitCommEvent(m_hComDev, &dwEventMask, NULL);
if((dwEventMask & EV_RXCHAR) == EV_RXCHAR)
{
ReadComm();
}
}
// HANDLE hCommWatchThreadExit = self->GethCommWatchThreadExit();
if(m_hCommWatchThreadExit != NULL)
{
SetEvent(m_hCommWatchThreadExit);
}
return 0;
}
//This function is to get a whole message from Ack Message that is sent by App CPU as an answer.
//Parameters:
//szMessage : the buffer to store one message. the length of buffer should not be less than 78.
//msgLen: the length of data
bool GetAckMessage(pMsgQue* msg)
{
return ReadOneMsg(msg, &m_AckMsgQue);
}
//This function is to get a whole message from Ack Message that is sent by App CPU as an answer.
//Parameters:
//szMessage : the buffer to store one message. the length of buffer should not be less than 78.
//msgLen: the length of data
bool GetRxMessage(pMsgQue* msg)
{
return ReadOneMsg(msg, &m_RxMsgQue);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -