Newer
Older
PrismSoftware / ECTrainer2 / ComPort.cpp
#include "ComPort.h"

namespace nkc {

// コンストラクタ
ComPort::ComPort(void) :
	_ComHandle(INVALID_HANDLE_VALUE)
{
}

// デストラクタ(終了処理)
ComPort::~ComPort(void)
{
	this->Close();
}

// ポートを探して開く(sendStrを送信して,checkStrを返すポートを探す)
// TCHAR* config : シリアルポート設定文字列 例)""
// char* sendStr : 送信文字列(バイナリデータ可)
// int sendLen : 送信文字列の長さ (byte)
// char* checkStr : チェック文字列(バイナリデータ可)
// int checkLen : チェック文字列の長さ (byte)
// 戻り値 : 発見したポート番号(未発見時は0)
int ComPort::Open(TCHAR* config, char* sendStr, int sendLen, char* checkStr, int checkLen)
{
	for (int findPort = 1; findPort <= COM_SEARCH_MAX; findPort++) {
		if (this->Open(findPort, config)) {
			this->Send((BYTE*)sendStr, sendLen);
			::Sleep(100); // 少し待つ
			BYTE buf[256];
			this->Receive(buf, 256);
			if (!::strncmp((char*)buf, checkStr, checkLen)) return findPort;
		}
	}
	return 0;
}

// ポートを開く
bool ComPort::Open(int port, const TCHAR* config)
{
	this->Close();

	// ポート番号文字列生成
	if (port < 1) return false;
	TCHAR portStr[16];
	::wsprintf(portStr, _T("\\\\.\\COM%d"), port);

	// Comポートを開く
	_ComHandle = ::CreateFile(portStr, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL, NULL);
	if (_ComHandle == INVALID_HANDLE_VALUE) return false;

	// ポート設定
	DCB dcb;
	::GetCommState(_ComHandle, &dcb);
	::BuildCommDCB(config, &dcb);
	dcb.fRtsControl = RTS_CONTROL_DISABLE;
	dcb.fOutxDsrFlow = FALSE;
	dcb.fDsrSensitivity = FALSE;
	dcb.fAbortOnError = FALSE;
	::SetCommState(_ComHandle, &dcb);

	// タイムアウト設定
	COMMTIMEOUTS timeout;
	::GetCommTimeouts(_ComHandle, &timeout);
	timeout.ReadIntervalTimeout = MAXDWORD;
	timeout.ReadTotalTimeoutMultiplier = 1;
	timeout.ReadTotalTimeoutConstant = 500;
	timeout.WriteTotalTimeoutMultiplier = 1;
	timeout.WriteTotalTimeoutConstant = 500;
	::SetCommTimeouts(_ComHandle, &timeout);

	return true;
}

// ポートを閉じる
void ComPort::Close()
{
	if (_ComHandle != INVALID_HANDLE_VALUE)
	{
		::CloseHandle(_ComHandle);
		_ComHandle = INVALID_HANDLE_VALUE;
	}
}

// データ送信
DWORD ComPort::Send(const BYTE* data, DWORD dataLen)
{
	if (_ComHandle == INVALID_HANDLE_VALUE) return 0;

	DWORD sendSize; // 送信したバイト数
	::WriteFile(_ComHandle, data, dataLen, &sendSize, NULL);

	return sendSize;
}

// データ受信
DWORD ComPort::Receive(BYTE* buffer, DWORD bufferLen)
{
	if (_ComHandle == INVALID_HANDLE_VALUE) return 0;

	DWORD errors;
	COMSTAT stat;
	::ClearCommError(_ComHandle, &errors, &stat);

	DWORD queSize = stat.cbInQue;
	if (queSize < 1) return 0;
	if (bufferLen < queSize) queSize = bufferLen;

	// バッファのクリア
	::memset(buffer, 0, bufferLen);

	// 受信
	DWORD receiveSize; // 受信したバイト数
	::ReadFile(_ComHandle, buffer, queSize, &receiveSize, NULL);

	return receiveSize;
}

// タイムアウト付きデータ受信
DWORD ComPort::WaitReceive(BYTE* buffer, DWORD bufferLen, const int timeout)
{
	if (_ComHandle == INVALID_HANDLE_VALUE) return 0;

	int receiveSize;
	for (int i = 0; i < timeout &&
		(receiveSize = this->Receive(buffer, bufferLen)) < 1; i++) ::Sleep(1);

	return receiveSize;
}

}; // namespace nkc