#include "stdafx.h"
#include "LegicProtocol.h"
#include "Util.h"

#define CMD_SIZE	0x01
#define DATA_SIZE	0x01
#define ERROR_SIZE	0x01
#define CRC_SIZE	0x02


CLegicProtocol::CLegicProtocol()
{

}

CLegicProtocol::~CLegicProtocol()
{

}

void CLegicProtocol::SetCom(UINT nCom)
{
	m_clsTransport.SetOption(nCom);
}

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

EERROR CLegicProtocol::SendData(ECMDLEGIC eCmd, BYTE* pData, DWORD dwSize)
{
	EERROR eRet = ER_NO_TRANSPORT;

	DWORD dwTotalData = DATA_SIZE + CMD_SIZE + dwSize + CRC_SIZE;
	BYTE* pDataCmd = new BYTE[dwTotalData];

	ZeroMemory(pDataCmd, dwTotalData);
	pDataCmd[0x00]	= (UCHAR)dwTotalData - 1;
	pDataCmd[0x01]	= eCmd;

	memcpy_s(pDataCmd + 0x02, dwTotalData, pData, dwSize);
	dwSize += 0x02;

	UINT nCrc = CUtil::CalcCRC16(pDataCmd);
	pDataCmd[dwSize] = ((nCrc >> 0x08) & 0xFF);
	pDataCmd[dwSize + 0x01] = (nCrc & 0xFF);

	eRet = m_clsTransport.Write(pDataCmd, dwTotalData);

	delete[] pDataCmd;
	return eRet;
}

EERROR CLegicProtocol::RecvData(ECMDLEGIC eCmd, BYTE** pData, DWORD& dwSize)
{
	EERROR eRet = ER_INVALID_DATA;
	if(pData != NULL)
	{
		BYTE pDataRet[MAX_PATH]; DWORD dwSizeRet = 0x01;
		ZeroMemory(pDataRet, MAX_PATH);
		if((eRet = m_clsTransport.Read(pDataRet, dwSizeRet)) == ER_OK)
		{
			dwSizeRet = pDataRet[0x00];
			if((eRet = m_clsTransport.Read(pDataRet + 0x01, dwSizeRet)) == ER_OK)
			{
				// check CRC
				eRet = ER_CRC;
				UINT nCrc = CUtil::CalcCRC16(pDataRet);
				if(nCrc == ((pDataRet[dwSizeRet - 1] << 0x08) + pDataRet[dwSizeRet]))
				{
					eRet = ER_CMD;
					if(pDataRet[0x01] == eCmd)
					{
						if((eRet = CUtil::GetError(pDataRet[0x02])) == ER_OK)
						{
							dwSize = dwSizeRet - (CMD_SIZE + CRC_SIZE + ERROR_SIZE);
							*pData = new BYTE[dwSize];
							memcpy_s(*pData, dwSize, pDataRet + (DATA_SIZE + CMD_SIZE + ERROR_SIZE), dwSize);
						}
					}
				}
			}
		}
	}
	return eRet;
}

EERROR CLegicProtocol::ExecCmd(ECMDLEGIC eCmd, BYTE* pDataIn, DWORD dwSizeIn, BYTE** pDataRet, DWORD& dwSizeRet)
{
	EERROR eRet = SendData(eCmd, pDataIn, dwSizeIn);
	if(eRet == ER_OK)
	{
		eRet = RecvData(eCmd, pDataRet, dwSizeRet);
	}
	return eRet;
}

EERROR CLegicProtocol::GetState(BYTE& bState)
{
	BYTE bStateCur = EGETSTATE;
	BYTE* pDataRet = NULL; DWORD dwDataRet = 0x00;
	EERROR eRet = ExecCmd(ECMD_SETSTATE, &bStateCur, 0x01, &pDataRet, dwDataRet);
	if(eRet == ER_OK)
	{
		bState = pDataRet[0x00];
		delete pDataRet;
	}
	return eRet;
}

EERROR CLegicProtocol::SetState(ESTATE eState)
{
	BYTE bState = eState;
	BYTE* pDataRet = NULL; DWORD dwDataRet = 0x00;
	EERROR eRet = ExecCmd(ECMD_SETSTATE, &bState, 0x01, &pDataRet, dwDataRet);
	if(eRet == ER_OK)
	{
		eRet = ER_STATE;
		if((eState == pDataRet[0x00]) || (pDataRet[0x00] == 0x00))
		{
			eRet = ER_OK;
		}
		delete pDataRet;
	}
	return eRet;
}

EERROR CLegicProtocol::GetCards(ECARDTYPE eCardType, DWORD& dwCards, BYTE** pCards, DWORD& dwSize)
{
	BYTE bCardType = eCardType;
	BYTE* pDataRet = NULL; DWORD dwDataRet = 0x00;
	EERROR eRet = ExecCmd(ECMD_GETCARDS, &bCardType, 0x01, &pDataRet, dwDataRet);
	if(eRet == ER_OK)
	{
		dwCards = pDataRet[0x00];
		dwSize	= dwDataRet - 0x01;
		*pCards = new BYTE[dwDataRet - 0x01];
		memcpy_s(*pCards, dwSize, pDataRet + 0x01, dwSize);
		delete[] pDataRet;
	}
	return eRet;
}

EERROR CLegicProtocol::SelectCard(ECARDTYPE eCardType, DWORD dwCard, DWORD dwSpeed)
{
	BYTE bDataIn[0x04];
	BYTE* pDataRet = NULL; DWORD dwDataRet = 0x00;
	bDataIn[0x00] = eCardType;
	bDataIn[0x01] = (BYTE)dwCard;
	switch(eCardType)
	{
		case ECARD_LEGIC: bDataIn[0x02] = 0x00; break; // mode 0x00
		default: bDataIn[0x02] = 0x01;	// default transparent - should be tested !!!
	}
	bDataIn[0x03] = (BYTE)dwSpeed;

	EERROR eRet = ExecCmd(ECMD_SELECTCARD, bDataIn, 0x04, &pDataRet, dwDataRet);
	if(eRet == ER_OK)
	{
		delete[] pDataRet;
	}
	return eRet;
}

EERROR CLegicProtocol::SelectFile(UINT nSeg, EFILETYPE eFileType, BYTE* pStamp, DWORD dwStamp, DWORD& dwFileSize)
{
	BYTE* pDataIn = new BYTE[0x03 + dwStamp]; DWORD dwDataIn = 0x03 + dwStamp;
	BYTE* pDataRet = NULL; DWORD dwDataRet = 0x00;

	pDataIn[0x00] = (BYTE)nSeg;
	pDataIn[0x01] = eFileType;
	pDataIn[0x02] = (BYTE)dwStamp;
	memcpy_s(pDataIn + 0x03, dwDataIn, pStamp, dwStamp);

	EERROR eRet = ExecCmd(ECMD_SELECTFILE, pDataIn, dwDataIn, &pDataRet, dwDataRet);
	if(eRet == ER_OK)
	{
		DWORD dwDataPos = 0x03 + pDataRet[0x03] + 0x02;	// see docu !!!
		dwFileSize = (pDataRet[dwDataPos] << 0x08) + pDataRet[dwDataPos + 0x01];

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

EERROR CLegicProtocol::ReadFile(DWORD dwAddress, BYTE* pData, DWORD& dwSize)
{
	BYTE bDataIn[0x03];
	BYTE* pDataRet = NULL; DWORD dwDataRet = 0x00;

	bDataIn[0x00] = (BYTE)((dwAddress >> 0x08) & 0xFF);
	bDataIn[0x01] = (BYTE)(dwAddress & 0xFF);
	bDataIn[0x02] = (BYTE)dwSize;

	SetBuzzer(TRUE);
	EERROR eRet = ExecCmd(ECMD_READ, bDataIn, 0x03, &pDataRet, dwDataRet);
	if(eRet == ER_OK)
	{
		dwSize = dwSize > pDataRet[0x00] ? pDataRet[0x00] : dwSize;
		memcpy_s(pData, dwSize, pDataRet + 0x01, dwSize);
		delete[] pDataRet;
	}
	SetBuzzer(FALSE);
	return eRet;
}

EERROR CLegicProtocol::WriteFile(DWORD dwAddress, BYTE* pData, DWORD dwSize)
{
	BYTE* pDataIn = new BYTE[0x03 + dwSize]; DWORD dwDataIn = 0x03 + dwSize;
	BYTE* pDataRet = NULL; DWORD dwDataRet = 0x00;

	pDataIn[0x00] = (BYTE)((dwAddress >> 0x08) & 0xFF);
	pDataIn[0x01] = (BYTE)(dwAddress & 0xFF);
	pDataIn[0x02] = (BYTE)dwSize;
	memcpy_s(pDataIn + 0x03, dwDataIn, pData, dwSize);

	SetBuzzer(TRUE);
	EERROR eRet = ExecCmd(ECMD_WRITE, pDataIn, dwDataIn, &pDataRet, dwDataRet);
	if(eRet != ER_OK)
	{
		delete[] pDataRet;
	}
	delete[] pDataIn;
	SetBuzzer(FALSE);
	return eRet;
}

 EERROR CLegicProtocol::GetIDB(DWORD dwTag, BYTE** pData, DWORD& dwSize)
 {
	 BYTE bTag = (BYTE)dwTag;
	 BYTE* pDataRet = NULL; DWORD dwDataRet = 0x00;
	 EERROR eRet = ExecCmd(ECMD_GETIDB, &bTag, 0x01, &pDataRet, dwDataRet);
	 if(eRet == ER_OK)
	 {
		eRet = ER_NO_TAG;
		if(pDataRet[0x00] == dwTag)
		{
			eRet = ER_OK;
			dwSize = pDataRet[0x01];
			*pData = new BYTE[dwSize];
			memcpy_s(*pData, dwSize, pDataRet + 0x02, dwSize);
		}
		delete[] pDataRet;
	 }
	 return eRet;
 }

 EERROR CLegicProtocol::SetLeds(BOOL bOn)
 {
	BYTE bLed[0x02];
	bLed[0x00] = 0x02;
	bLed[0x01] = bOn ? 0x02 : 0x00;

	BYTE* pDataRet = NULL; DWORD dwDataRet = 0x00;
	EERROR eRet = ExecCmd(ECMD_SETPORT, bLed, 0x02, &pDataRet, dwDataRet);
	delete[] pDataRet;
	return eRet;
 }

 EERROR CLegicProtocol::SetBuzzer(BOOL bOn)
 {
	 /*BYTE bLed[0x02];
	 bLed[0x00] = 0x04;
	 bLed[0x01] = bOn ? 0x04 : 0x00;

	 BYTE* pDataRet = NULL; DWORD dwDataRet = 0x00;
	 EERROR eRet = ExecCmd(ECMD_SETPORT, bLed, 0x02, &pDataRet, dwDataRet);
	 delete[] pDataRet;
	 return eRet;*/

	BYTE bBuzz[0x04];
	bBuzz[0x00] = 0x10;	// freq
	bBuzz[0x01] = 0x00;	// freq
	bBuzz[0x02] = 0x00;	// time
	bBuzz[0x03] = 0x00;	// time

	if(bOn == FALSE)
	{
		bBuzz[0x02] = 0x00;	// time
		bBuzz[0x03] = 0x0D;	// time
	}

	BYTE* pDataRet = NULL; DWORD dwDataRet = 0x00;
	EERROR eRet = ExecCmd(ECMD_SETBUZZ, bBuzz, 0x04, &pDataRet, dwDataRet);
	delete[] pDataRet;
	return eRet;
 }

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