#include "stdafx.h"
#include "HFProtocol.h"

#include "Utility.h"

#define STX				0xAA
#define ETX				0xBB
#define STX_LEN			0x01
#define ETX_LEN			0x01
#define ADDRESS_LEN		0x01
#define DATA_LEN		0x01
#define CMD_LEN			0x01
#define BCC_LEN			0x01
#define STATUS_LEN		0x01

CHFProtocol::CHFProtocol(UINT nCom) 
: m_clsTransport(nCom)
{
	m_bAddress = 0x00;
}

CHFProtocol::~CHFProtocol()
{

}

EERROR CHFProtocol::Open()
{
	return m_clsTransport.Open();
}

BYTE tbCmd[] = {	
					0x86,	// get version
					0x25,	// get cards 14443A
					0x20,	// read cards 14443A
				};

EERROR CHFProtocol::SendCmd(EHF_CMD eCmd, BYTE* pData, DWORD dwData)
{
	// total Len = 3 bytes RFE + cmd +  2 bytes len + data + 2 bytes check sum
	DWORD dwCmdLen = STX_LEN + ADDRESS_LEN + DATA_LEN + CMD_LEN +  dwData + BCC_LEN + ETX_LEN;

	BYTE* pDataSend = new BYTE[dwCmdLen];
	ZeroMemory(pDataSend, dwCmdLen);

	pDataSend[0x00]	= STX;
	pDataSend[0x01]	= m_bAddress;
	pDataSend[0x02]	= (BYTE)dwData + ADDRESS_LEN;
	pDataSend[0x03]	= tbCmd[eCmd];

	memcpy_s(pDataSend + 0x04, dwCmdLen, pData, dwData);

	pDataSend[dwCmdLen - 0x02]	= CUtility::CalcBCC(pDataSend + 0x01,  ADDRESS_LEN + DATA_LEN + CMD_LEN +  dwData);
	pDataSend[dwCmdLen - 0x01] = ETX;

	EERROR eRet = m_clsTransport.Write(pDataSend, dwCmdLen);
	delete[] pDataSend;

	return eRet;
}

EERROR CHFProtocol::CheckProtocol(BYTE* pData, DWORD dwSize)
{
	EERROR eRet = ER_CHECK_PROTOCOL;
	if(dwSize >= (STX_LEN + ADDRESS_LEN + DATA_LEN + STATUS_LEN + BCC_LEN + ETX_LEN))
	{
		// if we have this size we can also know the data len
		DWORD dwTotalDataSize = STX_LEN + ADDRESS_LEN + DATA_LEN + pData[0x02] + BCC_LEN + ETX_LEN;
		if(dwSize == dwTotalDataSize)
		{
			// so check protocol chars
			eRet = ER_STX;
			if(pData[0x00] == STX)
			{
				eRet = ER_ADDRESS;
				if(pData[0x01] == m_bAddress)
				{
					eRet = ER_EXEC_CMD;
					if(pData[0x03] == 0x00)
					{
						eRet = ER_ETX;
						if(pData[dwSize - 0x01] == ETX)
						{
							// check bcc
							eRet = ER_BCC;
							if(pData[dwSize - 0x02] == CUtility::CalcBCC(pData + 0x01, dwSize - (STX_LEN + BCC_LEN + ETX_LEN)))
							{
								eRet = ER_OK;
							}
						}
					}
				}
			}
		}
	}
	return eRet;
}

EERROR CHFProtocol::RecvData(BYTE** pData, DWORD& dwSize)
{
	EERROR eRet = ER_INVALID_DATA;
	if(pData != NULL)
	{
		BYTE pBuf[MAX_PATH];
		ZeroMemory(pBuf, MAX_PATH);
		DWORD dwRead = MAX_PATH, dwCount = 0x00;
		eRet = ER_CHECK_PROTOCOL;
		while(eRet == ER_CHECK_PROTOCOL)
		{
			dwRead = 0x01; //MAX_PATH;
			if((eRet = m_clsTransport.Read(pBuf + dwCount, dwRead)) == ER_OK)
			{
				dwCount += dwRead;
				if((eRet = CheckProtocol(pBuf, dwCount)) == ER_OK)
				{
					*pData	= NULL;
					dwSize	= pBuf[0x02] - STATUS_LEN;
					*pData = new BYTE[dwSize];
					ZeroMemory(*pData, dwSize);
					memcpy_s(*pData, dwSize, pBuf + (STX_LEN + ADDRESS_LEN + DATA_LEN + STATUS_LEN), dwSize);
				}
			}
		}
	}
	return eRet;
}

EERROR CHFProtocol::GetFirmware(BYTE* pData, DWORD& dwSize)
{
	EERROR eRet = SendCmd(HF_GET_VERSION, NULL, 0x00);
	if(eRet == ER_OK)
	{
		BYTE* pDataRet = NULL; DWORD dwRet = 0x00;
		if((eRet = RecvData(&pDataRet, dwRet)) == ER_OK)
		{
			eRet = ER_MORE_DATA;
			DWORD dwTransf = dwSize = dwSize > dwRet ? dwRet : dwSize;
			if(dwSize >= dwTransf)
			{
				eRet = ER_OK;
			}

			memcpy_s(pData, dwSize, pDataRet, dwTransf);
			delete[] pDataRet;
		}
	}
	return eRet;
}

EERROR CHFProtocol::GetCards14443A(BYTE** pCards, DWORD& dwSize)
{
	EERROR eRet = ER_INVALID_DATA;
	if(pCards != NULL)
	{
		BYTE pDataSend[0x02];
		pDataSend[0x00] = 0x52;	
		pDataSend[0x01] = 0x00;	
		if((eRet = SendCmd(HF_GET_CARDS14443A, pDataSend, 0x02)) == ER_OK)
		{
			if((eRet = RecvData(pCards, dwSize)) == ER_OK)
			{
				// special behave for 7 bytes cards - card return 7 bytes without nr cards
				// 
				if(dwSize == 0x07)
				{
					BYTE* pNewCards	= new BYTE[0x08];
					pNewCards[0x00] = 0x01;
					memcpy_s(pNewCards + 0x01, 0x07, *pCards, 0x07);
					delete *pCards;
					*pCards = pNewCards;
					dwSize = 0x08;
				}

				if(dwSize == 0x05)
				{
					*pCards[0x00] = 0x01;
				}
				eRet	= ER_OK;
			}
		}
	}
	return eRet;
}

EERROR CHFProtocol::Read14443(BYTE* pKey, BOOL bKeyA, DWORD dwStartBlock, DWORD dwNrBlocks,  BYTE* pData, DWORD& dwData)
{
	EERROR eRet = ER_INVALID_DATA;
	if((pKey != NULL) && (pData != NULL))
	{
		BYTE pDataSend[0x09];
		pDataSend[0x00] = bKeyA ? 0x02 : 0x00;	
		pDataSend[0x01] = (BYTE)(dwNrBlocks & 0xFF);
		pDataSend[0x02] = (BYTE)(dwStartBlock & 0xFF);
		memcpy_s(pDataSend + 0x03, 0x09, pKey, 0x06);
		if((eRet = SendCmd(HF_READ_CARDS14443A, pDataSend, 0x09)) == ER_OK)
		{
			BYTE* pDataRcv = NULL; DWORD dwDataRcv = 0;
			if((eRet = RecvData(&pDataRcv, dwDataRcv)) == ER_OK)
			{
				memcpy_s(pData, dwData, pDataRcv + 0x04, dwDataRcv - 0x04);
				dwData = dwDataRcv - 0x04;
				eRet	= ER_OK;
			}
			delete[] pDataRcv;
		}	
	}
	return eRet;
}

EERROR CHFProtocol::Close()
{
	return m_clsTransport.Close();
}