#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()
{
	m_bAddress	= 0x00;
	m_eCardType	= ECARD_UNKNOWN;

	memset(m_stInfoIso14443A.pKey, 0xFF, ISO14443A_KEY_LENGTH);
	m_stInfoIso14443A.bKeyA			= TRUE;
	m_stInfoIso14443A.dwStartBlock	= 0x00;
	m_stInfoIso14443A.dwNrBlocks	= 0x01;

	ZeroMemory(&m_stInfoIso15693, sizeof(ISO15693_INFO));
	m_stInfoIso15693.dwStartBlock	= 0x00;
	m_stInfoIso15693.dwNrBlocks		= 0x01;
}

CHFProtocol::~CHFProtocol()
{

}

void CHFProtocol::SetCom(UINT nCom, UINT nSpeed)
{
	m_clsTransport.SetOption(nCom, nSpeed);
}

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

BYTE tbCmd[] = {	0x80,	// set address
					0x81,	// set speed
					0x82,	// set serial
					0x83,	// get serial nr
					0x85,	// get user info
					0x86,	// get version
					0x87,	// set led on 1
					0x88,	// set led on 2
					0x89,	// set buzz on

					0x10,	// get cards
					0x11,	// read card
					0x12,	// write card

					0x14,	// stay quiet
					0x15,	// select card
					0x16,	// reset card
					
					0x17,	// write AFI
					0x18,	// lock AFI
					0x19,	// write DSFID
					0x1A,	// lock DSFID

					0x1B,	// sys info

					0x25,	// get cards 14443A
					0x20,	// read cards 14443A
					0x21,	// write cards 14443A
					0x22,	// init value 14443A
					0x23,	// decrease value 14443A
					0x24,	// increase value 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;
			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;
}

void CHFProtocol::SetIso14443Info(ISO14443A_INFO* pstIso14443AInfo)
{
	if(pstIso14443AInfo != NULL)
	{
		m_stInfoIso14443A	= *pstIso14443AInfo;
		m_eCardType			= ECARD_ISO14443A;
	}
}

void CHFProtocol::SetIso15693Info(ISO15693_INFO* pstIso15693Info)
{
	if(pstIso15693Info != NULL)
	{
		m_stInfoIso15693	= *pstIso15693Info;
		m_eCardType			= ECARD_ISO15693;
	}
}

ECARDTYPE CHFProtocol::GetCardType()
{
	return m_eCardType;
}

EERROR CHFProtocol::SetAddress(BYTE bAddress)
{
	EERROR eRet = SendCmd(HF_SET_ADDRESS, &bAddress, 0x01);
	if(eRet == ER_OK)
	{
		BYTE* pData = NULL; DWORD dwRet = 0x00;
		if((eRet = RecvData(&pData, dwRet)) == ER_OK)
		{
			eRet = (pData[0x01] == bAddress) ? ER_OK : ER_ADDRESS;
			delete[] pData;
		}
	}
	return eRet;
}

EERROR CHFProtocol::SetSpeed(BYTE bSpeed)
{
	EERROR eRet = SendCmd(HF_SET_SPEED, &bSpeed, 0x01);
	if(eRet == ER_OK)
	{
		BYTE* pData = NULL; DWORD dwRet = 0x00;
		if((eRet = RecvData(&pData, dwRet)) == ER_OK)
		{
			eRet = (pData[0x01] == bSpeed) ? ER_OK : ER_ADDRESS;
			delete[] pData;
		}
	}
	return eRet;
}

EERROR CHFProtocol::GetSerial(BYTE* pData, DWORD& dwSize)
{
	EERROR eRet = SendCmd(HF_GET_SERIAL, 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 + 0x01, dwTransf - 0x01);
			delete[] pDataRet;
		}
	}
	return eRet;
}

EERROR CHFProtocol::SetSerial(BYTE* pData, DWORD dwSize)
{
	BYTE pDataIn[0x08];
	ZeroMemory(pDataIn, 0x08);
	memcpy_s(pDataIn, 0x08, pData, dwSize > 0x08 ? 0x08 : dwSize);

	EERROR eRet = SendCmd(HF_SET_SERIAL, pDataIn, dwSize > 0x08 ? 0x08 : dwSize);
	if(eRet == ER_OK)
	{
		BYTE* pDataRet = NULL; DWORD dwRet = 0x00;
		if((eRet = RecvData(&pDataRet, dwRet)) == ER_OK)
		{
			eRet = ER_INVALID_DATA;
			if(pDataRet != pData)
			{
				eRet = ER_NAK;
				if(pDataRet[0x00] == 0x80)
				{
					eRet = ER_OK;
				}
			}
			delete[] pDataRet;
		}
	}
	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::SetLed(UINT nLed, DWORD dwTimeUnit, DWORD dwTime)
{
	EERROR eRet = ER_INVALID_DATA;
	nLed--;
	if((nLed < 0x02) && (dwTimeUnit < 50) && (dwTime < 0xFF))
	{
		BYTE pData[0x02]; pData[0x00] = (BYTE)dwTimeUnit; pData[0x01] = (BYTE)dwTime;
		eRet = SendCmd(nLed == 0x00 ? HF_SET_LED1 : HF_SET_LED2, pData, 0x02);
		if(eRet == ER_OK)
		{
			BYTE* pDataRet = NULL; DWORD dwRet = 0x00;
			if((eRet = RecvData(&pDataRet, dwRet)) == ER_OK)
			{
				eRet = ER_OK;
				eRet = ER_INVALID_DATA;
				if(pDataRet != pData)
				{
					eRet = ER_NAK;
					if(pDataRet[0x00] == 0x80)
					{
						eRet = ER_OK;
					}
				}

				delete[] pDataRet;
			}
		}
	}
	return eRet;
}

EERROR CHFProtocol::SetBuzz(DWORD dwTimeUnit, DWORD dwTime)
{
	EERROR eRet = ER_INVALID_DATA;
	if((dwTimeUnit < 50) && (dwTime < 0xFF))
	{
		BYTE pData[0x02]; pData[0x00] = (BYTE)dwTimeUnit; pData[0x01] = (BYTE)dwTime;
		eRet = SendCmd(HF_SET_BUZZ, pData, 0x02);
		if(eRet == ER_OK)
		{
			BYTE* pDataRet = NULL; DWORD dwRet = 0x00;
			if((eRet = RecvData(&pDataRet, dwRet)) == ER_OK)
			{
				eRet = ER_OK;
				eRet = ER_INVALID_DATA;
				if(pDataRet != pData)
				{
					eRet = ER_NAK;
					if(pDataRet[0x00] == 0x80)
					{
						eRet = ER_OK;
					}
				}

				delete[] pDataRet;
			}
		}
	}
	return eRet;
}

#define CARD_ID_LEN	0x08
EERROR CHFProtocol::GetCards15693(BYTE** pCards, DWORD& dwSize)
{
	EERROR eRet = ER_INVALID_DATA;
	if(pCards != NULL)
	{
		BYTE pData[0x03];

		pData[0x00]	= 0x06;	// max nr cards
		pData[0x01]	= 0x00;	// masklen
		pData[0x02] = 0x00;	// mask

		if((eRet = SendCmd(HF_GET_CARDS, pData, 0x03)) == ER_OK)
		{
			BYTE* pDataRcv = NULL; DWORD dwRcvSize = 0x00;
			if((eRet = RecvData(&pDataRcv, dwRcvSize)) == ER_OK)
			{
				dwSize = pDataRcv[0x00] * CARD_ID_LEN + 0x01;
				*pCards = new BYTE[dwSize];
				*pCards[0x00] = pDataRcv[0x00];
				BYTE* pDataNav = *pCards + 0x01;
				for(UINT nCount = 0x00; nCount < pDataRcv[0x00]; nCount++)
				{
					memcpy_s(pDataNav, dwSize, pDataRcv + 0x03 + nCount * (CARD_ID_LEN + 0x02), CARD_ID_LEN);
					pDataNav += CARD_ID_LEN;
				}
				delete[] pDataRcv;
			}
		}
	}
	return eRet;
}

EERROR CHFProtocol::ReadBlock15693(DWORD dwStartBlock, DWORD dwNrBlocks,  BYTE** pData, DWORD& dwData)
{
	EERROR eRet = ER_INVALID_DATA;
	if(pData != NULL)
	{
		BYTE pDataSend[0x03];
		pDataSend[0x00] = 0x02;	// send uid
		pDataSend[0x01] = (BYTE)(dwStartBlock & 0xFF);
		pDataSend[0x02] = (BYTE)(dwNrBlocks & 0xFF);
		// memcpy_s(pDataSend + 0x03, 0x0B, pCard, dwCard);
		if((eRet = SendCmd(HF_READ_CARD, pDataSend, 0x03)) == ER_OK)
		{
			BYTE* pDataRcv = NULL; DWORD dwDataRcv = 0x00;
			if((eRet = RecvData(&pDataRcv, dwDataRcv)) == ER_OK)
			{
				dwData = dwDataRcv - 0x01;
				*pData = new BYTE[dwData];
				memcpy_s(*pData, dwData, pDataRcv + 0x01, dwData);
				eRet = ER_OK;
			}
			delete[] pDataRcv;
		}
	}
	return eRet;
}

#define MAX_NR_BLOCKS	0x0F
EERROR CHFProtocol::Read15693(BYTE** pData, DWORD& dwData)
{
	EERROR eRet = ER_INVALID_DATA;
	if(pData != NULL)
	{
		*pData = NULL; dwData = 0x00;
		eRet = ER_OK;

		DWORD dwStartBlock  = m_stInfoIso15693.dwStartBlock;
		DWORD dwNrBlocks	= m_stInfoIso15693.dwNrBlocks;
		while((eRet == ER_OK) && (dwNrBlocks > 0x00))
		{
			DWORD dwTmpReadBlock = dwNrBlocks > MAX_NR_BLOCKS ? MAX_NR_BLOCKS : dwNrBlocks;
			BYTE* pDataTmp = NULL; DWORD dwDataTmp = 0x00;
			if((eRet = ReadBlock15693(dwStartBlock, dwTmpReadBlock, &pDataTmp, dwDataTmp)) == ER_OK)
			{
				BYTE* pMemMove = new BYTE[dwData + dwDataTmp];
				memcpy_s(pMemMove, dwData + dwDataTmp, *pData, dwData);
				memcpy_s(pMemMove + dwData, dwData + dwDataTmp, pDataTmp, dwDataTmp);
				delete[] *pData;
				delete[] pDataTmp;

				*pData = pMemMove;
				dwData = dwData + dwDataTmp;

				dwStartBlock += dwTmpReadBlock;
				dwNrBlocks -= dwTmpReadBlock;
				Sleep(100);
			}
		}
	}
	return eRet;
}

EERROR CHFProtocol::WriteBlock15693(DWORD dwStartBlock, BYTE* pData, DWORD dwSize)
{
	EERROR eRet = ER_INVALID_DATA;
	if(pData != NULL)
	{
		BYTE pDataSend[0x0F];
		pDataSend[0x00] = 0x02;// 0x20;	// send uid
		pDataSend[0x01] = (BYTE)(dwStartBlock & 0xFF);
		pDataSend[0x02] = 0x01;
		// memcpy_s(pDataSend + 0x03, 0x0B, pCard, dwCard);
		memcpy_s(pDataSend + 0x03, 0x0F, pData, dwSize);
		if((eRet = SendCmd(HF_WRITE_CARD, pDataSend, dwSize + 0x04)) == ER_OK)
		{
			BYTE* pDataRcv = NULL; DWORD dwDataRcv = 0x00;
			if((eRet = RecvData(&pDataRcv, dwDataRcv)) == ER_OK)
			{
				eRet = ER_OK;
			}
			delete[] pDataRcv;
		}
	}
	return eRet;
}

// write block with block because manual said some chips doesn't support more blocks to write
//
EERROR CHFProtocol::Write15693(BYTE* pData, DWORD dwSize)
{
	EERROR eRet = ER_UNKNOWN;
	DWORD dwCount		= 0x00;

	DWORD dwStartBlock	= m_stInfoIso15693.dwStartBlock;
	DWORD dwNrBlocks	= m_stInfoIso15693.dwNrBlocks;

	DWORD dwBlockSize	= dwSize / dwNrBlocks;

	while((dwCount != dwNrBlocks) && ((eRet = WriteBlock15693(dwStartBlock, pData, dwBlockSize)) == ER_OK))
	{
		Sleep(100);
		dwCount++;
		pData += dwBlockSize;
		dwStartBlock++;
	}
	return eRet;
}

EERROR CHFProtocol::Lock15693(DWORD dwAntena, CHAR* szCard, DWORD dwStartBlock, DWORD dwNrBlocks)
{
	return ER_NOT_IMPLEMENTED;
}

EERROR CHFProtocol::Reset(CHAR* szCard)
{	
	EERROR eRet = ER_INVALID_DATA;
	BYTE* pCard = NULL; DWORD dwCard = 0x00;
	CUtility::HexToByte((BYTE*)szCard, (UINT)strlen(szCard), &pCard, dwCard);
	if((pCard != NULL) && (dwCard == 0x08))
	{
		BYTE pDataSend[0x09];
		pDataSend[0x00] = 0x20;	// send uid
		memcpy_s(pDataSend + 0x01, 0x09, pCard, dwCard);
		if((eRet = SendCmd(HF_RESET_CARD, pDataSend, 0x09)) == ER_OK)
		{
			BYTE* pDataRcv = NULL; DWORD dwDataRcv = 0x00;
			if((eRet = RecvData(&pDataRcv, dwDataRcv)) == ER_OK)
			{
				eRet = ER_OK;
			}
			delete[] pDataRcv;
		}
	}
	delete[] pCard;
	return eRet;
}

EERROR CHFProtocol::StayQuiet(CHAR* szCard)
{
	EERROR eRet = ER_INVALID_DATA;
	BYTE* pCard = NULL; DWORD dwCard = 0x00;
	CUtility::HexToByte((BYTE*)szCard, (UINT)strlen(szCard), &pCard, dwCard);
	if((pCard != NULL) && (dwCard == 0x08))
	{
		BYTE pDataSend[0x09];
		pDataSend[0x00] = 0x20;	// send uid
		memcpy_s(pDataSend + 0x01, 0x09, pCard, dwCard);
		if((eRet = SendCmd(HF_STAY_QUIET, pDataSend, 0x09)) == ER_OK)
		{
			BYTE* pDataRcv = NULL; DWORD dwDataRcv = 0x00;
			if((eRet = RecvData(&pDataRcv, dwDataRcv)) == ER_OK)
			{
				eRet = ER_OK;
			}
			delete[] pDataRcv;
		}
	}
	delete[] pCard;
	return eRet;
}

EERROR  CHFProtocol::Select(CHAR* szCard)
{
	EERROR eRet = ER_INVALID_DATA;
	BYTE* pCard = NULL; DWORD dwCard = 0x00;
	CUtility::HexToByte((BYTE*)szCard, (UINT)strlen(szCard), &pCard, dwCard);
	if((pCard != NULL) && (dwCard == 0x08))
	{
		BYTE pDataSend[0x09];
		pDataSend[0x00] = 0x20;	// send uid
		memcpy_s(pDataSend + 0x01, 0x09, pCard, dwCard);
		if((eRet = SendCmd(HF_SELECT_CARD, pDataSend, 0x09)) == ER_OK)
		{
			BYTE* pDataRcv = NULL; DWORD dwDataRcv = 0x00;
			if((eRet = RecvData(&pDataRcv, dwDataRcv)) == ER_OK)
			{
				eRet = ER_OK;
			}
			delete[] pDataRcv;
		}
	}
	delete[] pCard;
	return eRet;
}

EERROR CHFProtocol::GetUserDataInfo(CHAR* szCard, DWORD& dwBlocks, DWORD& dwBlockSize)
{
	EERROR eRet = ER_INVALID_DATA;
	BYTE* pCard = NULL; DWORD dwCard = 0x00;
	CUtility::HexToByte((BYTE*)szCard, (UINT)strlen(szCard), &pCard, dwCard);
	if((pCard != NULL) && (dwCard == 0x08))
	{
		BYTE pDataSend[0x09];
		pDataSend[0x00] = 0x20;	// send uid
		memcpy_s(pDataSend + 0x01, 0x09, pCard, dwCard);
		if((eRet = SendCmd(HF_SYS_INFO, pDataSend, 0x09)) == ER_OK)
		{
			BYTE* pDataRcv = NULL; DWORD dwDataRcv = 0x00;
			if((eRet = RecvData(&pDataRcv, dwDataRcv)) == ER_OK)
			{
				dwBlocks	= pDataRcv[0x0C] + 1;
				dwBlockSize	= pDataRcv[0x0D] + 1;
				eRet	= ER_OK;
			}
			delete[] pDataRcv;
		}
	}
	delete[] pCard;
	return eRet;
}

EERROR CHFProtocol::ReadAFI_DSFID(BYTE& bAFI, BYTE& bDSFID)
{
	EERROR eRet = ER_INVALID_DATA;
	BYTE pDataSend[0x01];
	pDataSend[0x00] = 0x02;	// send uid
	if((eRet = SendCmd(HF_SYS_INFO, pDataSend, 0x01)) == ER_OK)
	{
		BYTE* pDataRcv = NULL; DWORD dwDataRcv = 0x00;
		if((eRet = RecvData(&pDataRcv, dwDataRcv)) == ER_OK)
		{
			bDSFID	= pDataRcv[0x0A];
			bAFI	= pDataRcv[0x0B];
			eRet	= ER_OK;
		}
		delete[] pDataRcv;
	}

	return eRet;
}

EERROR CHFProtocol::WriteAFI(BYTE bAFI)
{
	EERROR eRet = ER_INVALID_DATA;

	BYTE pDataSend[0x0A];
	pDataSend[0x00] = 0x02;	// send uid
	pDataSend[0x01] = bAFI;	// send uid

	if((eRet = SendCmd(HF_WRITE_AFI, pDataSend, 0x02)) == ER_OK)
	{
		BYTE* pDataRcv = NULL; DWORD dwDataRcv = 0x00;
		if((eRet = RecvData(&pDataRcv, dwDataRcv)) == ER_OK)
		{
			eRet	= ER_OK;
		}
		delete[] pDataRcv;
	}

	return eRet;
}

EERROR CHFProtocol::WriteDSFID(BYTE bDSFID)
{
	EERROR eRet = ER_INVALID_DATA;

	BYTE pDataSend[0x0A];
	pDataSend[0x00] = 0x02;	// send uid
	pDataSend[0x01] = bDSFID;	// send uid
	if((eRet = SendCmd(HF_WRITE_DSFID, pDataSend, 0x02)) == ER_OK)
	{
		BYTE* pDataRcv = NULL; DWORD dwDataRcv = 0x00;
		if((eRet = RecvData(&pDataRcv, dwDataRcv)) == ER_OK)
		{
			eRet	= ER_OK;
		}
		delete[] pDataRcv;
	}

	return eRet;
}

EERROR CHFProtocol::LockAFI()
{
	EERROR eRet = ER_INVALID_DATA;

	BYTE pDataSend[0x09];
	pDataSend[0x00] = 0x42;	// send uid
	if((eRet = SendCmd(HF_LOCK_AFI, pDataSend, 0x01)) == ER_OK)
	{
		BYTE* pDataRcv = NULL; DWORD dwDataRcv = 0x00;
		if((eRet = RecvData(&pDataRcv, dwDataRcv)) == ER_OK)
		{
			eRet	= ER_OK;
		}
		delete[] pDataRcv;
	}

	return eRet;
}

EERROR CHFProtocol::LockDSFID()
{
	EERROR eRet = ER_INVALID_DATA;

	BYTE pDataSend[0x09];
	pDataSend[0x00] = 0x42;	// send uid
	if((eRet = SendCmd(HF_LOCK_DSFID, pDataSend, 0x01)) == ER_OK)
	{
		BYTE* pDataRcv = NULL; DWORD dwDataRcv = 0x00;
		if((eRet = RecvData(&pDataRcv, dwDataRcv)) == ER_OK)
		{
			eRet	= ER_OK;
		}
		delete[] pDataRcv;
	}

	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)
			{
				*pCards[0x00] = 0x01;
				eRet	= ER_OK;
			}
		}
	}
	return eRet;
}

#define MAX_READ_BLOCK		0x04
#define BLOCK_SIZE_14443	0x10

EERROR CHFProtocol::Read14443AMaxBlock(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::Read14443A(BYTE** pData, DWORD& dwData)
{
	EERROR eRet = ER_INVALID_DATA;
	if(pData != NULL)
	{
		// calculate nr max read
		// 
		DWORD dwStartBlock	= m_stInfoIso14443A.dwStartBlock;
		DWORD dwNrBlocks	= m_stInfoIso14443A.dwNrBlocks;
		*pData = new BYTE[dwNrBlocks * BLOCK_SIZE_14443]; dwData = 0x00;
		eRet = ER_OK;
		DWORD dwNrReadBlock = 0x00, dwDataTmp = 0x00, dwNrBlockPerRead = 0x00;
		while((eRet == ER_OK) && (dwNrReadBlock != dwNrBlocks))
		{
			dwNrBlockPerRead = dwNrBlocks - dwNrReadBlock;
			if(dwNrReadBlock == 0x00 && (dwStartBlock % MAX_READ_BLOCK))
			{
				DWORD dwRestBlock = MAX_READ_BLOCK - (dwStartBlock % MAX_READ_BLOCK);
				dwNrBlockPerRead = dwNrBlocks > dwRestBlock ? dwRestBlock : dwNrBlocks;
			}

			if(dwNrBlockPerRead > MAX_READ_BLOCK)
			{
				dwNrBlockPerRead = MAX_READ_BLOCK;
			}

			dwDataTmp = dwNrBlockPerRead * BLOCK_SIZE_14443;
			eRet = Read14443AMaxBlock(m_stInfoIso14443A.pKey, m_stInfoIso14443A.bKeyA, dwStartBlock, dwNrBlockPerRead, *pData + dwData, dwDataTmp);
			Sleep(100);

			// ASSERT(dwDataTmp == (BLOCK_SIZE_14443 * dwNrBlockPerRead));
			dwData += dwDataTmp;
			dwNrReadBlock += dwNrBlockPerRead;
			dwStartBlock += dwNrBlockPerRead;
		}
	}
	return eRet;
}

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

EERROR CHFProtocol::Write14443A(BYTE* pData, DWORD dwData)
{
	EERROR eRet = ER_INVALID_DATA;
	if(pData != NULL)
	{
		// calculate nr max read
		// 
		eRet = ER_OK;

		DWORD dwStartBlock	= m_stInfoIso14443A.dwStartBlock;
		DWORD dwNrBlocks	= m_stInfoIso14443A.dwNrBlocks;

		DWORD dwNrWriteBlock = 0x00, dwDataTmp = 0x00, dwNrBlockPerWrite = 0x00; BYTE* pDataNav = pData;
		while((eRet == ER_OK) && (dwNrWriteBlock != dwNrBlocks))
		{
			dwNrBlockPerWrite = dwNrBlocks - dwNrWriteBlock;
			if(dwNrBlockPerWrite > MAX_READ_BLOCK)
			{
				dwNrBlockPerWrite = MAX_READ_BLOCK;
			}

			dwDataTmp = dwNrBlockPerWrite * BLOCK_SIZE_14443;
			eRet = Write14443AMaxBlock(m_stInfoIso14443A.pKey, m_stInfoIso14443A.bKeyA, dwStartBlock, dwNrBlockPerWrite, pDataNav, dwDataTmp);
			Sleep(100);

			// ASSERT(dwDataTmp == (BLOCK_SIZE_14443 * dwNrBlockPerWrite));
			pDataNav += dwDataTmp;
			dwNrWriteBlock += dwNrBlockPerWrite;
			dwStartBlock += dwNrBlockPerWrite;
		}
	}
	return eRet;
}

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