#include "pch.h"
#include "Rs232cUsb.h"
#include <locale.h>
#include <mmsystem.h>

// コンストラクタ
CRs232cUsb::CRs232cUsb()
	: m_SerialPort(NULL)
	, m_TransferBuffer()
	, m_ReceiveBuffer()
	, m_ReceiveData(_T(""))
{
}

// デストラクタ
CRs232cUsb::~CRs232cUsb()
{
}

// (1)接続
BOOL CRs232cUsb::OpenInterface(CString PortName, DWORD BaudRate)
{
	CString ErrorMessage;
	int ErrorCode;

	// COMポートハンドルの取得
	PortName = _T("\\\\.\\") + PortName;
	m_SerialPort = CreateFile(PortName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (m_SerialPort == INVALID_HANDLE_VALUE) {
		ErrorCode = GetLastError();
		ErrorMessage = GetLastErrorMessage(ErrorCode);
		MessageBox(NULL, ErrorMessage, AfxGetAppName(), MB_ICONERROR | MB_OK);
		return FALSE;
	}
	// 通信条件の設定
	DCB Dcb;
	memset(&Dcb, 0, sizeof(DCB));
	Dcb.DCBlength = sizeof(DCB);
	Dcb.BaudRate = BaudRate;
	Dcb.fBinary = 1;
	Dcb.fParity = 1;
	Dcb.ByteSize = 8;
	Dcb.Parity = NOPARITY;
	Dcb.StopBits = ONESTOPBIT;
	SetCommState(m_SerialPort, &Dcb);
	// バッファの設定
	if (SetupComm(m_SerialPort, 15536, 15536) == FALSE) {
		ErrorCode = GetLastError();
		ErrorMessage = GetLastErrorMessage(ErrorCode);
		MessageBox(NULL, ErrorMessage, AfxGetAppName(), MB_ICONERROR | MB_OK);
		return FALSE;
	}
	// バッファのクリア
	if (PurgeComm(m_SerialPort, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR) == FALSE) {
		ErrorCode = GetLastError();
		ErrorMessage = GetLastErrorMessage(ErrorCode);
		MessageBox(NULL, ErrorMessage, AfxGetAppName(), MB_ICONERROR | MB_OK);
		return FALSE;
	}
	// タイムアウトの設定
	COMMTIMEOUTS Commtimeouts;
	Commtimeouts.ReadIntervalTimeout = 50;
	Commtimeouts.ReadTotalTimeoutConstant = 1000;
	Commtimeouts.ReadTotalTimeoutMultiplier = 0;
	Commtimeouts.WriteTotalTimeoutConstant = 50;
	Commtimeouts.WriteTotalTimeoutMultiplier = 0;
	SetCommTimeouts(m_SerialPort, &Commtimeouts);

	return TRUE;
}

// (2)切断
BOOL CRs232cUsb::CloseInterface()
{
	CString ErrorMessage;
	int ErrorCode;
	BOOL Result;

	Result = CloseHandle(m_SerialPort);													// COMポートのクローズ
	if (Result == FALSE) {
		ErrorCode = GetLastError();
		ErrorMessage = GetLastErrorMessage(ErrorCode);
		MessageBox(NULL, ErrorMessage, AfxGetAppName(), MB_ICONERROR | MB_OK);
	}

	return Result;
}

// (3)コマンド送信
BOOL CRs232cUsb::SendMsg(CString SendData)
{
	size_t Length;
	DWORD Bytes;
	BOOL Result = FALSE;

	SendData = SendData + _T("\r\n");													// ターミネータ「CR+LF」を付加
#ifdef _UNICODE
	wcstombs_s(&Length, m_TransferBuffer, sizeof(m_TransferBuffer), SendData, _TRUNCATE);	// ワイド文字列をマルチバイト文字列に変換
	Length = strlen(m_TransferBuffer);
#else
	_tcscpy_s(m_TransferBuffer, sizeof(m_TransferBuffer), SendData);
	Length = _tcslen(m_TransferBuffer);
#endif
	Bytes = 0;
	Result = WriteFile(m_SerialPort, m_TransferBuffer, static_cast<DWORD>(Length), &Bytes, NULL);	// 送信データを書き込み

	return Result;
}

// (4)応答受信
BOOL CRs232cUsb::ReceiveMsg(DWORD Timeout)
{
	DWORD StartTime;
	CString ErrorMessage;
	int ErrorCode;
	BOOL Result = FALSE;

	m_ReceiveData = _T("");																// 受信データをクリア
	StartTime = timeGetTime();
	// ターミネータ「LF」を受信するまでループ
	for (;;) {
		DWORD NumberOfBytesRead = 0;
		if (ReadFile(m_SerialPort, m_ReceiveBuffer, sizeof(m_ReceiveBuffer), &NumberOfBytesRead, NULL) != FALSE) {	// 受信バッファに読み込み
			CString strText(m_ReceiveBuffer, NumberOfBytesRead);
			strText.Replace(_T("\r"), _T(""));											// 受信データ内の「CR」を削除
			int Index = strText.Find(_T("\n"));
			if (Index >= 0) {															// ターミネータ「LF」を受信したら終了
				m_ReceiveData = m_ReceiveData + strText.Mid(0, Index);					// 「LF」の手前までの受信データを保存
				Result = TRUE;
				break;
			}
			else {
				m_ReceiveData = m_ReceiveData + strText;								// 受信データを保存
			}
		}
		else {
			m_ReceiveData = _T("Error");
			ErrorCode = GetLastError();
			ErrorMessage = GetLastErrorMessage(ErrorCode);
			MessageBox(NULL, ErrorMessage, AfxGetAppName(), MB_ICONERROR | MB_OK);
			Result = FALSE;
			break;
		}
		// タイムアウト処理
		if (timeGetTime() > StartTime + Timeout) {
			m_ReceiveData = _T("Timeout");
			ErrorMessage = GetLastErrorMessage(ERROR_TIMEOUT);
			MessageBox(NULL, ErrorMessage, AfxGetAppName(), MB_ICONERROR | MB_OK);
			Result = FALSE;
			break;
		}
	}

	return Result;
}

// (5)コマンド送受信
BOOL CRs232cUsb::SendQueryMsg(CString SendData, DWORD Timeout)
{
	BOOL Result;

	Result = SendMsg(SendData);															// コマンド送信
	if (Result == TRUE) {
		if (SendData.Find(_T("?")) != -1) {
			Result = ReceiveMsg(Timeout);												// 送信が成功したら応答を受信
		}
	}

	return Result;
}

// エラーメッセージ取得
CString CRs232cUsb::GetLastErrorMessage(DWORD MessageId)
{
	PVOID pBuffer = NULL;
	CString ErrorMessage;

	if (FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
		NULL, MessageId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<PTSTR>(&pBuffer), 0, NULL) == 0 || pBuffer == NULL) {
		return ErrorMessage;
	}
	ErrorMessage = static_cast<PTSTR>(pBuffer);
	LocalFree(pBuffer);

	return ErrorMessage;
}
