⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serialbase.cpp

📁 VC++ 串口通信的dll. MsgQue 和SerialBase中重要的数据结构和通信函数,其可以完全复用. SerialComm是具体的应用, 大家实际应用中要做相应的修改. 代码注释详细,书写规
💻 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 + -