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

📄 serialport.cpp

📁 SerialPort_C++Builder
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*
**	FILENAME			CSerialPort.cpp
**
**	PURPOSE				This class can read, write and watch one serial port.
**						It sends messages to its owner when something happends on the port
**						The class creates a thread for reading and writing so the main
**						program is not blocked.
**
**	CREATION DATE		15-09-1997
**	LAST MODIFICATION	12-11-1997
**
**	AUTHOR				Remon Spekreijse
**
**	2006-07-29 modify by lvfeng
**	增添可以手工设置 DTR RTS 的状态 ON OFF
**	读取 CTS DSR RI RLSD(DCD)的状态 
*/
//---------------------------------------------------------------------------
#include <vcl.h>
#include <stdio.h>
#include <assert.h>
#pragma hdrstop
#include "SerialPort.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------

//
// Constructor
//
TSerialPort::TSerialPort()
{ 
	m_hComm = NULL;

	// initialize overlapped structure members to zero 
	m_ov.Offset = 0; 
	m_ov.OffsetHigh = 0; 
	
	// create events 
	m_ov.hEvent = NULL; 
	m_hWriteEvent = NULL; 
	m_hShutdownEvent = NULL; 

	m_szWriteBuffer = NULL; 
	m_nWriteSize=1;
	
	m_bThreadAlive = false;
	m_bCommStatus = false;
} 

// 
// Delete dynamic memory 
// 
TSerialPort::~TSerialPort()
{ 
	do 
	{ 
		SetEvent(m_hShutdownEvent); 
	} while (m_bThreadAlive); 
	
	delete [] m_szWriteBuffer; 
} 

// 
// Initialize the port. This can be port 1 to 4. 
// 
BOOL TSerialPort::InitPort(TForm* pPortOwner,       // the owner (CWnd) of the port (receives message)
						   UINT portnr,             // portnumber (1..4)
						   UINT baud,               // baudrate
						   char parity,             // parity
						   UINT databits,           // databits
						   UINT stopbits,           // stopbits
						   DWORD dwCommEvents,      // EV_RXCHAR, EV_CTS etc 
						   UINT writebuffersize)    // size to the writebuffer
{ 
	//databits should be 6, 7, 8
	//parity should be N (none), E (even), O (odd), S (space),  M (mark)
	//stopbits should be 0, 1, 2

	assert(portnr > 0 && portnr < 100);//由原来的5个改成100个
	assert(pPortOwner != NULL);
	
	// if the thread is alive: Kill 
	if (m_bThreadAlive) 
	{ 
		do 
		{ 
			SetEvent(m_hShutdownEvent); 
		} while (m_bThreadAlive); 
	} 
	
	// create events 
	if (m_ov.hEvent != NULL) 
		ResetEvent(m_ov.hEvent); 
	m_ov.hEvent = CreateEvent(NULL, true, false, NULL);
	
	if (m_hWriteEvent != NULL) 
		ResetEvent(m_hWriteEvent); 
	m_hWriteEvent = CreateEvent(NULL, true, false, NULL);
	
	if (m_hShutdownEvent != NULL) 
		ResetEvent(m_hShutdownEvent); 
	m_hShutdownEvent = CreateEvent(NULL, true, false, NULL);
	
	// initialize the event objects 
	m_hEventArray[0] = m_hShutdownEvent; // highest priority 
	m_hEventArray[1] = m_ov.hEvent; 
	m_hEventArray[2] = m_hWriteEvent; 
	
	// initialize critical section 
	InitializeCriticalSection(&m_csCommunicationSync); 
	
	// set buffersize for writing and save the owner 
	m_pOwner = pPortOwner; 
	
	if (m_szWriteBuffer != NULL) 
		delete [] m_szWriteBuffer; 
	m_szWriteBuffer = new char[writebuffersize]; 
	
	m_nPortNr = portnr; 
	
	m_nWriteBufferSize = writebuffersize; 
	m_dwCommEvents = dwCommEvents; 
	
	//BOOL bResult = false;    //lvfeng delete
	char *szPort = new char[50]; 
	char *szBaud = new char[50]; 
	
	// now it critical! 
	EnterCriticalSection(&m_csCommunicationSync); 
	
	// if the port is already opened: close it 
	if (m_hComm != NULL) 
	{ 
		CloseHandle(m_hComm); 
		m_hComm = NULL; 
	} 
	
	//prepare port strings "\\\\.\\COM%d"
	sprintf(szPort, "\\\\.\\COM%d", portnr); //lvfeng modify from "COM%d" to "\\\\.\\COM%d"
	sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d", baud, parity, databits, stopbits); 
	
	// get a handle to the port 
	m_hComm = CreateFile(szPort,        // communication port string (COMX)
		GENERIC_READ | GENERIC_WRITE,   // read/write types
		0,                              // comm devices must be opened with exclusive access
		NULL,                           // no security attributes
		OPEN_EXISTING,                  // comm devices must use OPEN_EXISTING
		FILE_FLAG_OVERLAPPED,           // Async I/O
		0);                             // template must be 0 for comm devices
	
	if (m_hComm == INVALID_HANDLE_VALUE) 
	{ 
		// port not found 
		delete [] szPort; 
		delete [] szBaud; 
		
		return false;
	} 
	
	// set the timeout values 
	m_CommTimeouts.ReadIntervalTimeout = 1000; 
	m_CommTimeouts.ReadTotalTimeoutMultiplier = 1000; 
	m_CommTimeouts.ReadTotalTimeoutConstant = 1000; 
	m_CommTimeouts.WriteTotalTimeoutMultiplier = 1000; 
	m_CommTimeouts.WriteTotalTimeoutConstant = 1000; 
	
	// configure 
	//如果应用程序只需要修改一部分配置的时候,
	//可以通过GetCommState(HANDLE hFile,LPDCB lpDCB)函数获取当前的BCD结构
	//然后更改DCB结构中的参数,调用SetCommState(HANDLE hFile,LPDCB lpDCB)函数
	//配置修改过的DCB来配置端口
	//hFile 由CreateFile函数返回已经打开的串口的句柄 
	//成功 则返回非零
	if (SetCommTimeouts(m_hComm, &m_CommTimeouts)) 
	{ 
		if (SetCommMask(m_hComm, dwCommEvents)) 
		{ 
			if (GetCommState(m_hComm, &m_dcb)) 
			{ 
				m_dcb.fRtsControl = RTS_CONTROL_ENABLE; // set RTS bit high!
				m_dcb.fDtrControl = DTR_CONTROL_ENABLE;	// set DTR bit high!  lvfeng add
				if (BuildCommDCB(szBaud, &m_dcb)) 
				{
					if (SetCommState(m_hComm, &m_dcb))
					{
						m_bCommStatus = TRUE;
						; // normal operation... continue
					}					
					else 
						ProcessErrorMessage("SetCommState()"); 
				} 
				else 
					ProcessErrorMessage("BuildCommDCB()"); 
			} 
			else 
				ProcessErrorMessage("GetCommState()"); 
		} 
		else 
			ProcessErrorMessage("SetCommMask()"); 
	} 
	else 
		ProcessErrorMessage("SetCommTimeouts()"); 
	
	delete [] szPort; 
	delete [] szBaud; 
	
	// flush the port 
	PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT); 
	
	// release critical section 
	LeaveCriticalSection(&m_csCommunicationSync); 
	
	return true;
}

// 
// The CommThread Function. 
// 
DWORD _stdcall TSerialPort::CommThread(LPVOID pParam)
{ 
	// Cast the void pointer passed to the thread back to 
	// a pointer of TSerialPort class
	TSerialPort *port = (TSerialPort*)pParam;

	// Set the status variable in the dialog class to 
	// TRUE to indicate the thread is running. 
	port->m_bThreadAlive = true;
	
	// Misc. variables 
	//DWORD BytesTransfered = 0;   //lvfeng delete
	DWORD Event = 0; 
	DWORD CommEvent = 0; 
	DWORD dwError = 0;
	COMSTAT comstat; 
	BOOL bResult = true;

	port->ReportModemStat(port,TRUE); //lvfeng add
	
	// Clear comm buffers at startup 
	if (port->m_hComm) // check if the port is opened 
		PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT); 
	
	// begin forever loop. This loop will run as long as the thread is alive. 
	for (;;) 
	{ 
		
		// Make a call to WaitCommEvent().  This call will return immediatly
		// because our port was created as an async port (FILE_FLAG_OVERLAPPED
		// and an m_OverlappedStructerlapped structure specified).  This call will cause the 
		// m_OverlappedStructerlapped element m_OverlappedStruct.hEvent, which is part of the m_hEventArray to 
		// be placed in a non-signeled state if there are no bytes available to be read,
		// or to a signeled state if there are bytes available.  If this event handle 
		// is set to the non-signeled state, it will be set to signeled when a 
		// character arrives at the port.
		
		// we do this for each port!
		
		bResult = WaitCommEvent(port->m_hComm, &Event, &port->m_ov); 
		
		if (!bResult) 
		{ 
			// If WaitCommEvent() returns FALSE, process the last error to determin
			// the reason..
			switch (dwError = GetLastError()) 
			{ 
			case ERROR_IO_PENDING: 
				{ 
					// This is a normal return value if there are no bytes 
					// to read at the port. 
					// Do nothing and continue 
					break; 
				} 
			case 87: 
				{ 
					// Under Windows NT, this value is returned for some reason. 
					// I have not investigated why, but it is also a valid reply 
					// Also do nothing and continue. 
					break;
				} 
			default: 
				{ 
					// All other error codes indicate a serious error has 
					// occured. Process this error. 
					port->ProcessErrorMessage("WaitCommEvent()"); 
					break; 
				} 
			} 
		} 
		else 
		{ 
			// If WaitCommEvent() returns TRUE, check to be sure there are
			// actually bytes in the buffer to read.  
			//
			// If you are reading more than one byte at a time from the buffer 
			// (which this program does not do) you will have the situation occur 
			// where the first byte to arrive will cause the WaitForMultipleObjects() 
			// function to stop waiting.  The WaitForMultipleObjects() function 
			// resets the event handle in m_OverlappedStruct.hEvent to the non-signelead state
			// as it returns.  
			//
			// If in the time between the reset of this event and the call to 
			// ReadFile() more bytes arrive, the m_OverlappedStruct.hEvent handle will be set again
			// to the signeled state. When the call to ReadFile() occurs, it will 
			// read all of the bytes from the buffer, and the program will
			// loop back around to WaitCommEvent().
			// 
			// At this point you will be in the situation where m_OverlappedStruct.hEvent is set,
			// but there are no bytes available to read.  If you proceed and call
			// ReadFile(), it will return immediatly due to the async port setup, but
			// GetOverlappedResults() will not return until the next character arrives.
			//
			// It is not desirable for the GetOverlappedResults() function to be in 
			// this state.  The thread shutdown event (event 0) and the WriteFile()
			// event (Event2) will not work if the thread is blocked by GetOverlappedResults().
			//
			// The solution to this is to check the buffer with a call to ClearCommError().
			// This call will reset the event handle, and if there are no bytes to read
			// we can loop back through WaitCommEvent() again, then proceed.
			// If there are really bytes to read, do nothing and proceed.
			
			port->ReportModemStat(port,FALSE); //lvfeng add
			bResult = ClearCommError(port->m_hComm, &dwError, &comstat); 
			
			if (comstat.cbInQue == 0) 
				continue; 
		} // end if bResult 
		
		port->ReportModemStat(port,FALSE); //lvfeng add
		
		// Main wait function. This function will normally block the thread 
		// until one of nine events occur that require action.
 
		Event = WaitForMultipleObjects(3, port->m_hEventArray, false, INFINITE);
		
		switch (Event) 
		{ 
		case 0: 
			{
				// Shutdown event. This is event zero so it will be 
				// the higest priority and be serviced first.

				CloseHandle(port->m_hComm ); //lvfeng add
				port->m_hComm =NULL; //lvfeng add
				
				port->m_bThreadAlive = false;
				
				// Kill this thread. break is not needed, but makes me feel better. 
				ExitThread(100);
				break; 
			} 
		case 1: // read event 
			{ 
				GetCommMask(port->m_hComm, &CommEvent); 
				port->ReportModemStat(port,FALSE); //lvfeng add
				if (CommEvent & EV_CTS)
					::SendMessage(port->m_pOwner->Handle, WM_COMM_CTS_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
				if (CommEvent & EV_RXFLAG) 
					::SendMessage(port->m_pOwner->Handle, WM_COMM_RXFLAG_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
				if (CommEvent & EV_BREAK) 
					::SendMessage(port->m_pOwner->Handle, WM_COMM_BREAK_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
				if (CommEvent & EV_ERR)
					::SendMessage(port->m_pOwner->Handle, WM_COMM_ERR_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
				if (CommEvent & EV_RING)
					::SendMessage(port->m_pOwner->Handle, WM_COMM_RING_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
				
				if (CommEvent & EV_RXCHAR) 
					// Receive character event from port. 
					ReceiveChar(port, comstat); 
				break; 
			} 
		case 2: // write event 
			{ 
				// Write character event from port
				WriteChar(port); 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -