#include "pch.h"
#include "GpibNi.h"
#include <locale.h>
#include <mmsystem.h>
#include "ni4882.h"

// コンストラクタ
CGpibNi::CGpibNi()
	: m_GpibDevice(0)
	, m_TransferBuffer()
	, m_ReceiveData(_T(""))
{
}

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

// (1)接続
BOOL CGpibNi::OpenInterface(int BoardID, int DeviceAddress)
{
	CString ErrorMessage;

	m_GpibDevice = ibdev(BoardID, DeviceAddress, 0, T1s, 1, 0);							// GPIBデバイスの初期化
	if ((Ibsta() & ERR) != 0) {
		ErrorMessage = GetNIErrorMessage();
		MessageBox(NULL, ErrorMessage, AfxGetAppName(), MB_ICONERROR | MB_OK);
		return FALSE;
	}

	ibclr(m_GpibDevice);																// GPIBデバイスのクリア
	if ((Ibsta() & ERR) != 0) {
		ErrorMessage = GetNIErrorMessage();
		MessageBox(NULL, ErrorMessage, AfxGetAppName(), MB_ICONERROR | MB_OK);
		return FALSE;
	}

	return TRUE;
}

// (2)切断
BOOL CGpibNi::CloseInterface()
{
	CString ErrorMessage;

	ibonl(m_GpibDevice, 0);																// GPIBデバイスをオフラインにする
	if ((Ibsta() & ERR) != 0) {
		ErrorMessage = GetNIErrorMessage();
		MessageBox(NULL, ErrorMessage, AfxGetAppName(), MB_ICONERROR | MB_OK);
		return FALSE;
	}

	return TRUE;
}

// (3)コマンド送信
BOOL CGpibNi::SendMsg(CString SendData)
{
	size_t Length;
	CString ErrorMessage;

#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
	ibwrt(m_GpibDevice, m_TransferBuffer, Length);										// 送信データを書き込み
	if ((Ibsta() & ERR) != 0) {
		ErrorMessage = GetNIErrorMessage();
		MessageBox(NULL, ErrorMessage, AfxGetAppName(), MB_ICONERROR | MB_OK);
		return FALSE;
	}

	return TRUE;
}

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

	m_ReceiveData = _T("");																// 受信データをクリア
	StartTime = timeGetTime();
	// ターミネータ「LF」を受信するまでループ
	for (;;) {
		ibrd(m_GpibDevice, m_TransferBuffer, sizeof(m_TransferBuffer) - 1);				// 受信バッファに読み込み
		if ((Ibsta() & ERR) != 0) {
			if ((Ibsta() & TIMO) == 0) {
				// タイムアウト以外のエラー
				m_ReceiveData = _T("Error");
				ErrorMessage = GetNIErrorMessage();
				MessageBox(NULL, ErrorMessage, AfxGetAppName(), MB_ICONERROR | MB_OK);
				Result = FALSE;
				break;
			}
			if (Ibcnt() != 0) {
				m_TransferBuffer[Ibcnt()] = '\0';
				CString strText(m_TransferBuffer, Ibcnt());
				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 {
			if (Ibcnt() != 0) {
				m_TransferBuffer[Ibcnt()] = '\0';
				CString strText(m_TransferBuffer, Ibcnt());
				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;							// 受信データを保存
				}
			}
		}
		// タイムアウト処理
		if (timeGetTime() > StartTime + Timeout) {
			m_ReceiveData = _T("Timeout");
			ErrorMessage = GetLastErrorMessage(ERROR_TIMEOUT);
			MessageBox(NULL, ErrorMessage, AfxGetAppName(), MB_ICONERROR | MB_OK);
			Result = FALSE;
			break;
		}
	}

	return TRUE;
}

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

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

	return Result;
}

// エラーメッセージ取得
CString CGpibNi::GetNIErrorMessage()
{
	CString strMessage;
	const static TCHAR *pErrorMnemonic[] = {
		_T("EDVR"),	_T("ECIC"),	_T("ENOL"),	_T("EADR"),	_T("EARG"),
		_T("ESAC"),	_T("EABO"),	_T("ENEB"),	_T("EDMA"),	_T(""),
		_T("EOIP"),	_T("ECAP"),	_T("EFSO"),	_T(""),		_T("EBUS"),
		_T("ESTB"),	_T("ESRQ"),	_T(""),		_T(""),		_T(""),
		_T("ETAB"),	_T("ELCK"),	_T("EARM"),	_T("EHDL"),	_T(""),
		_T(""),		_T("EWIP"),	_T("ERST"),	_T("EPWR")
	};

	strMessage.Format(_T("ibsta = 0x%04x, iberr = %d, %s"), Ibsta(), Iberr(), pErrorMnemonic[Iberr()]);

	return strMessage;
}

// エラーメッセージ取得
CString CGpibNi::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;
}
