Windowsのシリアルポートクラスと機能の実現

9955 ワード

今日はいくつかの修士論文を見て、MSCommコントロールで編んでいる人がいるのを見ました.当時はどうやって使うのかよく分かりませんでしたが、実はMFC(visual studio 2013環境)でどう探してもこのコントロールが見つからなかったからです.のよし、サボってはいけない.自分でシリアルクラスを作って機能を実現するしかない.
多くの文献やCSDNの先輩のプログラムを参考にして、最後に小さなものを作りました.大きくはありませんが、設定、送受信、待機、その他の機能も完備しています.
直接コードをつけて、後の人の参考にして、社会に報いましょう.
(p.s.1.シリアルポートは非オーバーラップモード(コードで非同期モードと識別され、両者が厳格に等価であるかどうかは検証される)を使用し、送受信プログラムを実行する際に操作の完了を待つ必要はない.2.シリアル名の実際の名前は\\.COMX,Xはシリアル番号であり,これにより10以上のシリアルポートを作成できる)
ヘッダファイル
#ifndef MYSERIALPORT_H_
#define MYSERIALPORT_H_

#include "stdafx.h"
#include "MyMutex.h"

class CSerialPort
{
private:
	//     
	HANDLE m_hComm;
	//    
	CString m_comName;

	//      
	DWORD m_Baud;

	//        
	DWORD m_dwInQueue;
	DWORD m_dwOutQueue;

	//     
	DWORD m_ReadIntervalTimeout;
	DWORD m_ReadTotalTimeoutMultiplier;
	DWORD m_ReadTotalTimeoutConstant;
	DWORD m_WriteTotalTimeoutMultiplier;
	DWORD m_WriteTotalTimeoutConstant;

	//      
	DWORD m_dwError;

public:
	
	//        
	COMSTAT m_ComStat;
	OVERLAPPED m_ovRead;
	BOOL m_bWaitRead;

	DWORD m_BytesRead;
	BOOL m_IsReadFault;//        ,  TRUE,  FALSE
	DWORD m_ReadError;

	//        
	OVERLAPPED m_ovWrite;
	BOOL m_bWaitWrite;

	DWORD m_BytesSent;
	BOOL m_IsWriteFault;//        ,  TRUE,  FALSE
	DWORD m_WriteError;

	//         
	BOOL IsCreate;
	BOOL IsClose;
	BOOL IsSetBaud;
	BOOL IsSetQueue;
	BOOL IsSetTimeOut;

private:
	//         ,       
	BOOL BaudExeu();
	BOOL QueueExeu();
	BOOL TimeOutExeu();

public:
	//            
	CSerialPort(CString Name = _T("COM1"));
	//       
	CSerialPort(CSerialPort & Obj_port);
	//     
	CSerialPort & operator = (const CString Name);
	//     
	virtual ~CSerialPort();

	//     ,  
	operator HANDLE() { return HANDLE(m_hComm); }

	//             
	BOOL CreatePort();
	void Baud_Config(DWORD Baud = 57600);
	void QueueSize_Config(DWORD inQueueSize = 1024, DWORD outQueueSize = 1024);
	void TimeOut_Config(DWORD RT = 0, DWORD RM = 0, DWORD RC = 0, DWORD WM = 0, DWORD WC = 0);

	//     
	HANDLE GetSerialHANDLE();
	// close handle
	BOOL ReleaseHandle();

	//      
	DWORD GetErrorCode();

	//          
	void InitParamofRW(BOOL IfWaitRead = TRUE, BOOL IfWaitWrite = TRUE);

	//       
	BOOL RecvData(char* bufferRecv);
	BOOL SendData(char* m_szWriteBuffer, UINT num = NULL, BOOL Default = TRUE);

	//       
	BOOL StillOverlappedRead(DWORD timeout = INFINITE);
	BOOL StillOverlappedWrite(DWORD timeout = INFINITE);
};

#endif

ソースファイル
#include "stdafx.h"
#include "MySerialPort.h"

CSerialPort::CSerialPort(CString Name)
{
	m_hComm = NULL;
	m_comName = Name;

	m_Baud = 57600;
	m_dwInQueue = 1024;
	m_dwOutQueue = 1024;

	m_ReadIntervalTimeout = 0;
	m_ReadTotalTimeoutMultiplier = 0;
	m_ReadTotalTimeoutConstant = 0;
	m_WriteTotalTimeoutMultiplier = 0;
	m_WriteTotalTimeoutConstant = 0;

	IsCreate = FALSE;
	IsSetBaud = FALSE;
	IsSetQueue = FALSE;
	IsSetTimeOut = FALSE;

	m_dwError = 0;
}

CSerialPort::CSerialPort(CSerialPort & Obj_port)
{

}

CSerialPort & CSerialPort::operator = (const CString Name)
{
	m_hComm = NULL;
	//m_comName.Format(Name.GetString());
	m_comName = Name;

	m_Baud = 57600;
	m_dwInQueue = 1024;
	m_dwOutQueue = 1024;

	m_ReadIntervalTimeout = 0;
	m_ReadTotalTimeoutMultiplier = 0;
	m_ReadTotalTimeoutConstant = 0;
	m_WriteTotalTimeoutMultiplier = 0;
	m_WriteTotalTimeoutConstant = 0;

	IsCreate = FALSE;
	IsClose = FALSE;
	IsSetBaud = FALSE;
	IsSetQueue = FALSE;
	IsSetTimeOut = FALSE;

	m_dwError = 0;

	return *this;
}

CSerialPort::~CSerialPort()
{
	if (m_hComm != NULL)
	{
		CloseHandle(m_hComm);
		m_hComm = NULL;
	}
}


BOOL CSerialPort::CreatePort()
{
	CString ipszPortName = _T("");
	ipszPortName.Format(_T("\\\\.\\%s"), m_comName);
	m_hComm = CreateFile(ipszPortName,	// COM  
		GENERIC_READ | GENERIC_WRITE,
		0, //     
		NULL,
		OPEN_EXISTING,	//        
		FILE_FLAG_OVERLAPPED,	//     
		NULL);
	if (m_hComm == INVALID_HANDLE_VALUE) // if create failed
	{
		m_dwError = GetLastError();

		CloseHandle(m_hComm);
		m_hComm = NULL;
		IsCreate = FALSE;
		return FALSE;
	}
	IsClose = FALSE;

	// set specific serial port event
	SetCommMask(m_hComm,
		EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RXCHAR | EV_TXEMPTY);

	IsSetBaud = BaudExeu();
	IsSetQueue = QueueExeu();
	IsSetTimeOut = TimeOutExeu();
	InitParamofRW(FALSE, TRUE);

	IsCreate = TRUE;
	return TRUE;
}

inline BOOL CSerialPort::BaudExeu()
{
	DCB dcb;
	memset(&dcb, 0, sizeof(dcb));
	if (!GetCommState(m_hComm, &dcb))//     DCB   
	{
		m_dwError = GetLastError();
		return FALSE;
	}

	//set DCB to configure the serialport
	dcb.DCBlength = sizeof(dcb);

	//Serial Port Config
	dcb.BaudRate = m_Baud;
	dcb.Parity = NOPARITY;
	dcb.fParity = 0;
	dcb.StopBits = ONESTOPBIT;
	dcb.ByteSize = 8;
	dcb.fOutxCtsFlow = 0;
	dcb.fOutxDsrFlow = 0;
	dcb.fDtrControl = DTR_CONTROL_DISABLE;
	dcb.fDsrSensitivity = 0;
	dcb.fRtsControl = RTS_CONTROL_DISABLE;
	dcb.fOutX = 0;
	dcb.fInX = 0;

	//misc parameters
	dcb.fErrorChar = 0;
	dcb.fBinary = 1;
	dcb.fNull = 0;
	dcb.fAbortOnError = 0;
	dcb.wReserved = 0;
	dcb.XonLim = 2;
	dcb.XoffLim = 4;
	dcb.XonChar = 0x13;
	dcb.XoffChar = 0x19;
	dcb.EvtChar = 0;

	//set DCB
	if (!SetCommState(m_hComm, &dcb))
	{
		m_dwError = GetLastError();
		return FALSE;
	}
	return TRUE;
}

inline BOOL CSerialPort::QueueExeu()
{
	// in and out buffer size, byte
	if (!SetupComm(m_hComm, m_dwInQueue, m_dwOutQueue))
	{
		m_dwError = GetLastError();
		return FALSE;
	}
	return TRUE;
}

inline BOOL CSerialPort::TimeOutExeu()
{
	COMMTIMEOUTS TimeOuts;

	TimeOuts.ReadIntervalTimeout = m_ReadIntervalTimeout;
	TimeOuts.ReadTotalTimeoutMultiplier = m_ReadTotalTimeoutMultiplier;
	TimeOuts.ReadTotalTimeoutConstant = m_ReadTotalTimeoutConstant;

	TimeOuts.WriteTotalTimeoutMultiplier = m_WriteTotalTimeoutMultiplier;
	TimeOuts.WriteTotalTimeoutConstant = m_WriteTotalTimeoutConstant;

	if (!SetCommTimeouts(m_hComm, &TimeOuts))	//     
	{
		m_dwError = GetLastError();
		return FALSE;
	}
	return TRUE;
}

void CSerialPort::Baud_Config(DWORD Baud)
{
	m_Baud = Baud;
}

void CSerialPort::QueueSize_Config(DWORD inQueueSize, DWORD outQueueSize)
{
	m_dwInQueue = inQueueSize;
	m_dwOutQueue = outQueueSize;
}

void CSerialPort::TimeOut_Config(DWORD RT, DWORD RM, DWORD RC, DWORD WM, DWORD WC)
{
	m_ReadIntervalTimeout = RT;
	m_ReadTotalTimeoutMultiplier = RM;
	m_ReadTotalTimeoutConstant = RC;

	m_WriteTotalTimeoutMultiplier = WM;
	m_WriteTotalTimeoutConstant = WC;
}

HANDLE CSerialPort::GetSerialHANDLE()
{
	return m_hComm;
}

BOOL CSerialPort::ReleaseHandle()
{
	//if (m_hComm == NULL)
	//{
	//	return FALSE;
	//}
	PurgeComm(m_hComm,
		PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_RXABORT);

	if (!CloseHandle(m_hComm))
	{
		m_dwError = GetLastError();
		return FALSE;
	}

	m_dwError = GetLastError();
	m_hComm = NULL;
	IsCreate = FALSE;
	IsClose = TRUE;
	return TRUE;
}

DWORD CSerialPort::GetErrorCode()
{
	return m_dwError;
}

void CSerialPort::InitParamofRW(BOOL IfWaitRead, BOOL IfWaitWrite)
{
	m_BytesRead = 0;
	m_IsReadFault = FALSE;
	m_ReadError = 0;

	m_bWaitRead = IfWaitRead;// overlapped read
	// read event
	memset(&m_ovRead, 0, sizeof(OVERLAPPED));
	// 2nd param, auto reset; 3rd param, init status no signal
	// when call function ReadFile or WriteFile, 
	m_ovRead.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);


	m_BytesSent = 0;
	m_IsWriteFault = FALSE;
	m_WriteError = 0;

	m_bWaitWrite = IfWaitWrite;// overlapped write
	// write event
	memset(&m_ovWrite, 0, sizeof(OVERLAPPED));
	// 2nd param, auto reset; 3rd param, init status no signal
	// when call function ReadFile or WriteFile, 
	m_ovWrite.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

	// clear in & out buffer in serial port
	PurgeComm(m_hComm,
		PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_RXABORT);
}

BOOL CSerialPort::RecvData(char* bufferRecv)
{
	//       ,        m_ComStat         
	/*if (!ClearCommError(m_hComm, &m_ReadError, &m_ComStat))
	{
	m_ReadError = GetLastError();

	}*/

	if (!ReadFile(m_hComm,//Handle to COMM port
		bufferRecv,//RXBuffer Pointer
		m_ComStat.cbInQue, //Read m_ComStat.cbInQue bytes
		&m_BytesRead,//Stores number of bytes read
		&m_ovRead))//pointer to the m_ov structure
	{
		m_ReadError = GetLastError();
		switch (m_ReadError)
		{
		case ERROR_IO_PENDING:
			//case ERROR_IO_INCOMPLETE:
			m_IsReadFault = FALSE;
			break;
		default:
			m_IsReadFault = TRUE;
			break;
		}
		return FALSE;
	}
	return TRUE;
}

BOOL CSerialPort::StillOverlappedRead(DWORD timeout)
{
	WaitForSingleObject(m_hComm, timeout);
	//           ,           
	if (0 != GetOverlappedResult(m_hComm, //Handle to COMM port
		&m_ovRead,// Overlapped structure
		&m_BytesRead, // Stores number of bytes read
		FALSE)) //Wait flag
	{
		return FALSE;
	}
	return TRUE;
}

BOOL CSerialPort::SendData(char* m_szWriteBuffer, UINT num, BOOL Default)
{
	// Clear buffer
	PurgeComm(m_hComm, PURGE_TXCLEAR | PURGE_TXABORT);

	m_ovWrite.Offset = 0;
	m_ovWrite.OffsetHigh = 0;

	DWORD m_nToSend = 0;
	if (Default)
		m_nToSend = strlen(m_szWriteBuffer);
	else
		m_nToSend = num;

	if (!WriteFile(m_hComm, // Handle to COMM Port
		m_szWriteBuffer, // Pointer to message buffer in calling finction
		m_nToSend, // Length of message to send
		&m_BytesSent, //Where to store the number of bytes sent
		&m_ovWrite))//Overlapped structure
	{
		m_WriteError = GetLastError();
		switch (m_WriteError)
		{
		case ERROR_IO_PENDING:
			//case ERROR_IO_INCOMPLETE:
			m_IsWriteFault = FALSE;
			break;
		default:
			m_IsWriteFault = TRUE;
			break;
		}
		return FALSE;
	}
	return TRUE;
}

BOOL CSerialPort::StillOverlappedWrite(DWORD timeout)
{
	WaitForSingleObject(m_hComm, timeout);
	//           ,           
	if (0 != GetOverlappedResult(m_hComm, //Handle to COMM port
		&m_ovWrite,// Overlapped structure
		&m_BytesSent, //Stores number of bytes sent
		FALSE)) //Waitflag
	{
		return FALSE;
	}
	return TRUE;
}