#include "MCDCmdTrans.hpp"

#include "asam/d/MCDAccessKeys.hpp"
#include "asam/d/MCDFlashJob.hpp"
#include "asam/d/MCDRequest.hpp"
#include "asam/mcd/MCDDbProject.hpp"
#include "asam/mcd/MCDLogicalLink.hpp"
#include "asam/mcd/MCDResponseParameter.hpp"
#include "asam/mcd/MCDValue.hpp"
#include "asam/mcd/MCDEventHandler.hpp"
#include "otx/diagcom/asam/MCDApiWrapper.hpp"
#include "otx/diagcom/asam/MCDProjectProvider.hpp"
#include <codecvt>
#include <locale>
#include <iostream>
#include "MCDCmdBoardcast.hpp"
#include "ECUFlasherImpl.hpp"
#include "MyStringUtils.h"
#include "tracer.h"
#include "algorithm.h"

namespace otx {
	namespace flash {

		MCDCmdTrans::MCDCmdTrans(ECU* ecu)
		{
			this->ecu = ecu;
			std::string ecuVariantName = ecu->getName();
			std::string logicalLinkName = ecu->getDbLogicalLinkName();

			if (string::npos != ecuVariantName.find("BGM")) {
				ecuVariantName = "EV_BGM_SOC";
				logicalLinkName = "LL_BGM_SOC_DoIP";
			}
			else if (string::npos != ecuVariantName.find("ACU")) {
				ecuVariantName = "EV_ACU_SOC";
				logicalLinkName = "LL_ACU_SOC_DoIP";
			}
			else if (string::npos != ecuVariantName.find("TCAM")) {
				ecuVariantName = "EV_TCAM";
				logicalLinkName = "LL_TCAM_DoIP";
			}
			else if (string::npos != ecuVariantName.find("CDC")) {
				ecuVariantName = "EV_CDC_SOC";
				logicalLinkName = "LL_CDC_SOC_DoIP";
			}

			mcdSystem = otx::diagcom::MCDProjectProvider::getMCDSystem();
			mcdProject = otx::diagcom::MCDProjectProvider::getSelectedProject();
			mInterface = otx::diagcom::MCDProjectProvider::getConnectedInterface();
			if (mInterface == NULL) {
				Tracer::error("MCDCmdTrans", "mInterface =null");
				isValid = false;
				logicalLink = nullptr;
				return;
			}
			asam::mcd::MCDDatatypeShortName shortNameDbLogicalLink = logicalLinkName;
			asam::mcd::MCDDatatypeShortName variantName = ecuVariantName;

			this->logicalLinkName = logicalLinkName;
			logicalLink = mcdProject->createLogicalLinkByVariantAndInterface(shortNameDbLogicalLink, variantName, *mInterface);
			asam::mcd::MCDLogicalLinkState state = logicalLink->getState();
			try {
				if (state == asam::mcd::MCDLogicalLinkState::eCREATED) {
					logicalLink->open();
					logicalLink->gotoOnline();
				}
			}
			catch (...) {
				Tracer::debug(__FUNCTION__, to_string(__LINE__));
				isValid = false;
				hexCop = nullptr;
				return;
			}
			isValid = true;
			hexCop = logicalLink->createDiagComPrimitiveByType(asam::mcd::MCDObjectType::eMCDHEXSERVICE);
		}

		MCDCmdTrans::MCDCmdTrans(std::string ecuVariantName, std::string logicalLinkName)
		{

			if (string::npos != ecuVariantName.find("BGM")) {
				ecuVariantName = "EV_BGM_SOC";
				logicalLinkName = "LL_BGM_SOC_DoIP";
			}
			else if (string::npos != ecuVariantName.find("ACU")) {
				ecuVariantName = "EV_ACU_SOC";
				logicalLinkName = "LL_ACU_SOC_DoIP";
			}
			else if (string::npos != ecuVariantName.find("TCAM")) {
				ecuVariantName = "EV_TCAM";
				logicalLinkName = "LL_TCAM_DoIP";
			}
			else if (string::npos != ecuVariantName.find("CDC")) {
				ecuVariantName = "EV_CDC_SOC";
				logicalLinkName = "LL_CDC_SOC_DoIP";
			}

			mcdSystem = otx::diagcom::MCDProjectProvider::getMCDSystem();
			mcdProject = otx::diagcom::MCDProjectProvider::getSelectedProject();
			mInterface = otx::diagcom::MCDProjectProvider::getConnectedInterface();
			if (mInterface == NULL) {
				Tracer::error("MCDCmdTrans", "mInterface =null");
				isValid = false;
				logicalLink = nullptr;
				return;
			}
			asam::mcd::MCDDatatypeShortName shortNameDbLogicalLink = logicalLinkName;
			asam::mcd::MCDDatatypeShortName variantName = ecuVariantName;

			this->logicalLinkName = logicalLinkName;
			logicalLink = mcdProject->createLogicalLinkByVariantAndInterface(shortNameDbLogicalLink, variantName, *mInterface);
			asam::mcd::MCDLogicalLinkState state = logicalLink->getState();
			try {
				if (state == asam::mcd::MCDLogicalLinkState::eCREATED) {
					logicalLink->open();
					logicalLink->gotoOnline();
				}
			}
			catch (...) {
				Tracer::debug(__FUNCTION__, to_string(__LINE__));
				isValid = false;
				hexCop = nullptr;
				return;
			}
			isValid = true;
			hexCop = logicalLink->createDiagComPrimitiveByType(asam::mcd::MCDObjectType::eMCDHEXSERVICE);
		}

		MCDCmdTrans::~MCDCmdTrans()
		{
			if (hexCop) {
				logicalLink->removeDiagComPrimitive(*hexCop);
				hexCop = nullptr;
			}
			if (logicalLink) {
				mcdProject->removeLogicalLink(*logicalLink);
				logicalLink = nullptr;
			}
			isValid = false;
		}

		void MCDCmdTrans::delay(int ms)
		{
			std::this_thread::sleep_for(std::chrono::milliseconds(ms));
		}

		CBinary MCDCmdTrans::sendCommand(CBinary binSend)
		{
			CBinary rfData;
			if (!isValid) {
				return rfData;
			}
			asam::d::MCDRequest* request = hexCop->getRequest();
			asam::mcd::MCDValue pdu(asam::mcd::MCDDataType::eA_BYTEFIELD);
			otx::O_BYTEFIELD dSend;
			for (int i = 0; i < binSend.GetSize(); i++) {
				dSend.push_back(binSend.GetAt(i));
			}

			//Tracer::hex(logicalLinkName + ",req=", binSend.GetBuffer(), MIN(16, binSend.GetSize()));
			if (this->ecu != NULL) {
				string strLog = "";
				MyStringUtils::BufferToString(strLog, binSend.GetBuffer(), MIN(16, binSend.GetSize()), 0);
				ecu->addCmd(strLog);
			}

			pdu.setBytefield(dSend);
			request->enterPDU(pdu);

			int retryTimes = 1;
			while (retryTimes > 0) {
				hexCop->getState();
				asam::mcd::MCDResult* result = hexCop->executeSync();
				if (result->getResultState()->getExecutionState() != asam::d::MCDExecutionState::eALL_FAILED) {
					asam::mcd::MCDResponse* response = result->getResponses()->getItemByIndex(0);
					otx::O_BYTEFIELD dRecv;
					dRecv = response->getResponseMessage().getBytefield();
					rfData.Init(dRecv.data(), dRecv.size());

					//Tracer::hex(logicalLinkName + ",res=", rfData.GetBuffer(), MIN(16, rfData.GetSize()));
					if (this->ecu != NULL) {
						string strLog = "";
						MyStringUtils::BufferToString(strLog, rfData.GetBuffer(), MIN(16, rfData.GetSize()), 1);
						ecu->addCmd(strLog);
					}
					retryTimes = 0;
				}
				else {
					retryTimes--;
				}

				//logicalLink->removeDiagComPrimitive(*hexCop);
				delete (result);
			}
			return rfData;
		}

		CBinary MCDCmdTrans::sendCommand(uint8_t* inCmd, uint32_t len)
		{
			CBinary rfData;
			if (!isValid) {
				return rfData;
			}
			asam::d::MCDRequest* request = hexCop->getRequest();
			asam::mcd::MCDValue pdu(asam::mcd::MCDDataType::eA_BYTEFIELD);
			otx::O_BYTEFIELD dSend;
			for (int i = 0; i < len; i++) {
				dSend.push_back(inCmd[i]);
			}

			//Tracer::hex(logicalLinkName + ",req=", inCmd, MIN(16, len));
			if (this->ecu != NULL) {
				string strLog = "";
				MyStringUtils::BufferToString(strLog, inCmd, MIN(16, len), 0);
				ecu->addCmd(strLog);
			}

			pdu.setBytefield(dSend);
			request->enterPDU(pdu);

			int retryTimes = 1;
			while (retryTimes > 0) {
				hexCop->getState();
				asam::mcd::MCDResult* result = hexCop->executeSync();
				if (result->getResultState()->getExecutionState() != asam::d::MCDExecutionState::eALL_FAILED) {
					asam::mcd::MCDResponse* response = result->getResponses()->getItemByIndex(0);
					otx::O_BYTEFIELD dRecv;
					dRecv = response->getResponseMessage().getBytefield();
					rfData.Init(dRecv.data(), dRecv.size());

					//Tracer::hex(logicalLinkName + ",res=", rfData.GetBuffer(), MIN(16, rfData.GetSize()));
					if (this->ecu != NULL) {
						string strLog = "";
						MyStringUtils::BufferToString(strLog, rfData.GetBuffer(), MIN(16, rfData.GetSize()), 1);
						ecu->addCmd(strLog);
					}
					retryTimes = 0;
				}
				else {
					retryTimes--;
				}

				//logicalLink->removeDiagComPrimitive(*hexCop);
				delete (result);
			}
			return rfData;
		}

		CBinary MCDCmdTrans::JIDUZY_SendReceiveFrame_7F78(int nMax7F78)
		{
			CBinary rfData;

			for (int nRetry78 = 1; nRetry78 < nMax7F78; nRetry78++)
			{
				rfData = sendCommand(NULL);
				if (rfData.GetSize() == 0)
				{
					return rfData;
				}
				if (rfData[0] == 0x7F)
				{
					if (rfData.GetSize() >= 3)
					{
						if (rfData.GetSize() == 0x78)
						{
							continue;
						}
					}
				}

				break;
			}

			return rfData;
		}

		CBinary MCDCmdTrans::JIDUZY_SendReceiveFrame(CBinary& binFrame, int nMax7F78)
		{
			CBinary rfData;
			rfData = sendCommand(binFrame);
			return rfData;
		}

		CBinary MCDCmdTrans::SendFrame(CBinary& binSend, int nTryCount)
		{
			CBinary rfData;
			for (int i = 0; i < nTryCount; i++)
			{
				rfData = sendCommand(binSend);
				if (rfData.GetSize() > 0)
				{
					break;
				}
			}

			return rfData;
		}

		CBinary MCDCmdTrans::SendFrame_Cmd36(uint8_t* pSendData, int iFrameLen, int nTryCount /*= 1*/, int nMax7F78 /*= 2*/)
		{
			CBinary rfData;

			for (int i = 0; i < nTryCount; i++)
			{
				rfData = sendCommand(pSendData, iFrameLen);
				if (0 == rfData.GetSize())
				{
					return rfData;
				}
				if (rfData[0] == 0x7F)
				{
					break;
				}

				//delay(100);
			}

			if (rfData[0] == 0x7F)
			{
				rfData.Empty();
			}

			return rfData;
		}



		int32_t MCDCmdTrans::getFrameSize()
		{
			return nFrameSize;
		}

		void MCDCmdTrans::EnterProgramMode()
		{
			//CBinary bin31010206("\x31\x01\x02\x06", 4);
			//sendCommand(bin31010206);
			//delay(1000);

			CBinary binReboot("\x10\x82", 2);
			sendCommand(binReboot);
			delay(1000);
		}

		bool MCDCmdTrans::EnterSystem()
		{
			CBinary response;
			for (int i = 0; i < 3; i++) {
				response = sendCommand(CBinary("\x22\xF1\x86", 3));
				if (response.GetSize() >= 4 && (response[0] == 0x62 && response[3] == 0x02)) {
					break;
				}
			}

			CBinary binEnterCmd("\x10\x02", 2);
			for (int i = 0; i < 3; i++) {
				response = JIDUZY_SendReceiveFrame(binEnterCmd, 2);
				if (!response.IsEmpty() && response[0] == 0x50) {
					break;
				}
				delay(100);
			}

			for (int i = 0; i < 3; i++) {
				response = sendCommand(CBinary("\x22\xF1\x86", 3));
				if (response.GetSize() >= 4 && (response[0] == 0x62 && response[3] == 0x02)) {
					return true;
				}
			}

			return false;
		}

		bool MCDCmdTrans::getEcuSignatureMode(bool& isProd) {

			isProd = false;
			CBinary response = sendCommand(CBinary("\x22\xD0\x1C", 3));
			if (response.GetSize() >= 1 && (response[0] == 0x62))
			{
				isProd = true;
			}
			return isProd;
		}

		int MCDCmdTrans::radix_hex2Array(const char* hex, int hexLen, uint8_t* outBuffer, int outBufferSize) {
			if (0 == strncmp(hex, "0x", 2) || 0 == strncmp(hex, "0X", 2)) {
				Tracer::debug("radix_hex2Array", hex);
				hexLen -= 2;
				memmove((void*)(hex), hex + 2, hexLen);
			}

			if (hexLen % 2 != 0) {
				return -1;
			}

			if (outBufferSize < hexLen / 2) {
				return -1;
			}

			for (size_t i = 0; i < hexLen; i += 2)
			{
				uint8_t highByte = toupper(hex[i]);
				uint8_t lowByte = toupper(hex[i + 1]);

				if (highByte >= 'A' && highByte <= 'F')
					highByte = highByte - 'A' + 10;
				else if (highByte >= '0' && highByte <= '9')
					highByte = highByte - '0';
				else {
					return -1;
				}

				if (lowByte >= 'A' && lowByte <= 'F')
					lowByte = lowByte - 'A' + 10;
				else if (lowByte >= '0' && lowByte <= '9')
					lowByte = lowByte - '0';
				else {
					return -1;
				}

				outBuffer[i / 2] = (highByte << 4) | lowByte;
			}


			return hexLen / 2;
		}

		bool MCDCmdTrans::SecurityAccess(string pinCode, int iLevel)
		{
			bool bRet = true;

			CBinary binSeed;
			CBinary binMask;
			CBinary binKEY = 0;
			CBinary rf;
			//int iLevel = 2;

			CBinary bin10("\x10\x03", 2);
			CBinary bin2701("\x27\x01", 2);
			CBinary bin2702("\x27\x02\x00\x00\x00", 5);

			switch (iLevel)
			{
			case 1:
				bin10.SetAt(1, 0x03);
				bin2701.SetAt(1, 0x03);
				bin2702.SetAt(1, 0x04);
				break;
			case 2:
				bin10.SetAt(1, 0x02);
				bin2701.SetAt(1, 0x01);
				bin2702.SetAt(1, 0x02);
				break;
			case 3:
				bin10.SetAt(1, 0x03);
				bin2701.SetAt(1, 0x05);
				bin2702.SetAt(1, 0x06);
				break;
			case 4:
				bin10.SetAt(1, 0x03);
				bin2701.SetAt(1, 0x01);
				bin2702.SetAt(1, 0x02);
				break;
			case 7: //
				bin10.SetAt(1, 0x03);
				bin2701.SetAt(1, 0x07);
				bin2702.SetAt(1, 0x08);
				break;
			case 11: //
				bin10.SetAt(1, 0x03);
				bin2701.SetAt(1, 0x11);
				bin2702.SetAt(1, 0x12);
				break;
			default:
				break;
			}

			rf = SendFrame(bin2701);

			if (rf.IsEmpty() || (rf[0] == 0x7F))
			{
				return false;
			}

			if (rf.GetSize() < 5)
			{
				return false;
			}

			binSeed.Append(rf.m_pData + 2, 3);
			bool bCheck = false;
			for (int i = 0; i < 3; i++)
			{
				if (binSeed[i] != 0)
				{
					bCheck = true;
				}
			}

			if (bCheck == false)
			{
				return true;
			}

			if ((iLevel == 4) || (iLevel == 11) || (iLevel == 2))//03: 2701,2702,Mask=0xFFFFFFFFFF
			{
				binMask = CBinary("\xFF\xFF\xFF\xFF\xFF", 5);
			}
			else if (iLevel == 7)
			{
				binMask = CBinary("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF", 16);
			}
			else
			{
				uint8_t tempBuffer[16] = { 0 };
				int rLen = radix_hex2Array(pinCode.c_str(), pinCode.size(), tempBuffer, 16);
				binMask.Init(tempBuffer, rLen);
			}

			if (iLevel == 7)
			{
				binKEY = binMask;
				bin2702 = CBinary("\x27\x08", 2);
				bin2702 += binKEY;
			}
			else
			{
				binKEY = SeedToKey(binSeed, binMask);
				bin2702[2] = binKEY[0];
				bin2702[3] = binKEY[1];
				bin2702[4] = binKEY[2];
			}

			rf = JIDUZY_SendReceiveFrame(bin2702);
			if (rf.IsEmpty() || rf.GetSize() < 2)
			{
				return false;
			}
			else if (rf[0] == 0x7F) {
				if (rf.GetSize() == 3)
				{
					if (rf[0] == 0x7F && rf[1] == 0x27 && rf[2] == 0x36)
					{
						delay(10 * 1000);
					}
					else if (rf[0] == 0x7F && rf[1] == 0x27 && rf[2] == 0x35)
					{
						delay(2000);
					}
				}
				return false;
			}

			return true;
		}


		bool MCDCmdTrans::SecurityAccess_ECOS(string pinCode, int iLevel /*= 2*/)
		{
			bool bRet = true;
			CBinary binSeed;

			CBinary binKEY = 0;
			CBinary rf;

			CBinary bin10("\x10\x03", 2);
			CBinary bin2701("\x27\x01", 2);
			CBinary bin2702("\x27\x02\x00\x00\x00", 5);

			switch (iLevel)
			{
			case 1: //
				bin10.SetAt(1, 0x03);
				bin2701.SetAt(1, 0x03);
				bin2702.SetAt(1, 0x04);
				break;
			case 2: //
				bin10.SetAt(1, 0x02);
				bin2701.SetAt(1, 0x01);
				bin2702.SetAt(1, 0x02);
				break;
			case 3: //
				bin10.SetAt(1, 0x03);
				bin2701.SetAt(1, 0x05);
				bin2702.SetAt(1, 0x06);
				break;
			case 4://
				bin10.SetAt(1, 0x03);
				bin2701.SetAt(1, 0x01);
				bin2702.SetAt(1, 0x02);
				break;
			case 7: //
				bin10.SetAt(1, 0x03);
				bin2701.SetAt(1, 0x07);
				bin2702.SetAt(1, 0x08);
				break;
			case 11: //
				bin10.SetAt(1, 0x03);
				bin2701.SetAt(1, 0x11);
				bin2702.SetAt(1, 0x12);
				break;
			default:
				break;
			}

			rf = SendFrame(bin2701);

			if (rf.IsEmpty() || (rf[0] == 0x7F))
			{

				return false;
			}

			if (rf.GetSize() < 5)
			{
				return false;
			}

			binSeed.Append(rf.m_pData + 2, 3);
			bool bCheck = false;
			for (int i = 0; i < 3; i++)
			{
				if (binSeed[i] != 0)
				{
					bCheck = true;
				}
			}

			if (bCheck == false)
			{
				return true;
			}

			uint8_t tempBuffer[16] = { 0 };
			int rLen = radix_hex2Array(pinCode.c_str(), pinCode.size(), tempBuffer, 16);
			CBinary binMask(tempBuffer, rLen);

			binKEY = SeedToKey(binSeed, binMask);
			bin2702[2] = binKEY[0];
			bin2702[3] = binKEY[1];
			bin2702[4] = binKEY[2];

			rf = SendFrame(bin2702);

			if (rf.IsEmpty() || rf.GetSize() < 2)
			{
				return false;
			}
			else if (rf[0] == 0x7F) {
				if (rf.GetSize() == 3)
				{
					if (rf[0] == 0x7F && rf[1] == 0x27 && rf[2] == 0x36)
					{
						delay(10 * 1000);
					}
					else if (rf[0] == 0x7F && rf[1] == 0x27 && rf[2] == 0x35)
					{
						delay(2000);
					}
				}
				return false;
			}

			return true;
		}


		bool MCDCmdTrans::EraseMemory(uint32_t uMem, uint32_t uSize)
		{
			CBinary binSend("\x31\x01\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12);

			binSend[4] = (uMem >> 24) & 0xFF;
			binSend[5] = (uMem >> 16) & 0xFF;
			binSend[6] = (uMem >> 8) & 0xFF;
			binSend[7] = uMem & 0xFF;
			binSend[8] = (uSize >> 24) & 0xFF;
			binSend[9] = (uSize >> 16) & 0xFF;
			binSend[10] = (uSize >> 8) & 0xFF;
			binSend[11] = uSize & 0xFF;

			bool bRet = false;

			CBinary binRecv = SendFrame(binSend, 1);
			if (binRecv.IsEmpty() || binRecv[0] != binSend[0] + 0x40)
			{
				bRet = false;
				return bRet;
			}

			bRet = true;
			return bRet;
		}


		bool MCDCmdTrans::RequestDownload(uint32_t formatIdentifer, uint32_t nMemoryAddr, uint64_t nDataLength)
		{
			this->nDataLength = nDataLength;
			CBinary binRequestDownloadCmd("\x34\x00\x44\x00\x00\x00\x00\x00\x00\x00\x00", 11);
			binRequestDownloadCmd[1] = formatIdentifer & 0xFF;
			bool bRet = false;
			CBinary binSend = binRequestDownloadCmd;

			if (nDataLength <= 0xFFFFFFFF)
			{
				binSend[3] = (nMemoryAddr >> 24) & 0xFF;
				binSend[4] = (nMemoryAddr >> 16) & 0xFF;
				binSend[5] = (nMemoryAddr >> 8) & 0xFF;
				binSend[6] = (nMemoryAddr >> 0) & 0xFF;

				binSend[7] = (nDataLength >> 24) & 0xFF;
				binSend[8] = (nDataLength >> 16) & 0xFF;
				binSend[9] = (nDataLength >> 8) & 0xFF;
				binSend[10] = (nDataLength >> 0) & 0xFF;
			}
			else
			{
				binSend = CBinary(19);
				binSend[0] = 0x34;
				binSend[1] = 0x00;
				binSend[2] = 0x88;
				binSend[3] = 0x00;
				binSend[4] = 0x00;
				binSend[5] = 0x00;
				binSend[6] = 0x00;
				binSend[7] = 0x00;
				binSend[8] = 0x00;
				binSend[9] = 0x00;
				binSend[10] = 0x00;
				binSend[11] = (nDataLength >> 0x38) & 0xFF;
				binSend[12] = (nDataLength >> 0x30) & 0xFF;
				binSend[13] = (nDataLength >> 0x28) & 0xFF;
				binSend[14] = (nDataLength >> 0x20) & 0xFF;
				binSend[15] = (nDataLength >> 0x18) & 0xFF;
				binSend[16] = (nDataLength >> 0x10) & 0xFF;
				binSend[17] = (nDataLength >> 0x08) & 0xFF;
				binSend[18] = (nDataLength >> 0) & 0xFF;
			}

			CBinary binRecv = SendFrame(binSend, 1);

			if ((binRecv.GetSize() < 2) || (binRecv.GetSize() > 0 && binRecv[0] == 0x7F))
			{
				bRet = false;
				return false;
			}

			if (binRecv[1] == 0x20)
			{
				if (binRecv.GetSize() < 4)
				{
					bRet = false;
					return bRet;
				}

				nFrameSize = (binRecv[2] << 8) + binRecv[3];
			}
			else if (binRecv[1] == 0x30)
			{
				if (binRecv.GetSize() < 5)
				{
					bRet = false;
					return bRet;
				}

				nFrameSize = (binRecv[2] << 16) + (binRecv[3] << 8) + binRecv[4];
				//nFrameSize = MIN(0x10000, nFrameSize);//TODO 单包数据大小
			}
			else if (binRecv[1] == 0x40)
			{
				if (binRecv.GetSize() < 6)
				{
					bRet = false;
					return bRet;
				}

				nFrameSize = (binRecv[2] << 24) + (binRecv[3] << 16) + (binRecv[4] << 8) + binRecv[5];
			}

			if (nFrameSize > MAX_FLASH_FRAME_SIZE)
			{
				nFrameSize = MAX_FLASH_FRAME_SIZE;
			}

			nFrameSize -= 2;
			Tracer::info("RequestDownload.nFrameSize", to_string(nFrameSize));

			if (nFrameSize <= 0)
			{
				bRet = false;
			}
			else
			{
				bRet = true;
			}


			return bRet;
		}


		bool MCDCmdTrans::RequestTransferExit()
		{
			CBinary binSend("\x37", 1);
			CBinary binRecv = SendFrame(binSend);
			if (binRecv.IsEmpty() || binRecv[0] != binSend[0] + 0x40)
			{
				Tracer::error("RequestTransferExit", "fail");
				return false;
			}
			return true;
		}

		bool MCDCmdTrans::ActivateSbl(std::string sblAddr) {
			CBinary binSend("\x31\x01\x03\x01\x00\x00\x00\x00", 8);
			uint32_t uAddr = MyStringUtils::toLong(sblAddr, 16);

			binSend[4] = (uAddr >> 24) & 0xFF;
			binSend[5] = (uAddr >> 16) & 0xFF;
			binSend[6] = (uAddr >> 8) & 0xFF;
			binSend[7] = (uAddr >> 0) & 0xFF;

			CBinary binRecv = SendFrame(binSend);
			if (binRecv.GetSize() >= 5 && binRecv[0] == 0x71 && (binRecv[4] & 0x0F) == 0x00)
			{
				return true;
			}

			Tracer::error("ActivateSbl", "fail");
			return false;
		}

		bool MCDCmdTrans::VerifyAuthenticity(string strKeyInfo, bool isDomain)
		{
			CBinary binSend;
			if (isDomain)
			{
				binSend = CBinary("\x31\x01\x02\x08", 4);
				binSend.Append(strKeyInfo.c_str(), strKeyInfo.length());
			}
			else
			{
				uint8_t tempBuffer[4096] = { 0 };
				int rLen = radix_hex2Array(strKeyInfo.c_str(), strKeyInfo.length(), tempBuffer, 4096);
				binSend = CBinary("\x31\x01\x02\x12", 4);
				if (rLen > 0)
					binSend += CBinary(tempBuffer, rLen);
			}

			CBinary binRecv = SendFrame(binSend, 1);

			if (isDomain)
			{
				if (binRecv.GetSize() >= 1 && binRecv[0] == 0x71)
				{
					return true;
				}
			}
			else {
				if (binRecv.GetSize() >= 6 && ((binRecv.GetAt(4) & 0x0F) == 0) && binRecv.GetAt(5) == 0)
				{
					return true;
				}
			}

			return false;
		}

		bool MCDCmdTrans::FinishProgram()
		{
			CBinary binSend("\x31\x01\x02\x05", 4);
			CBinary binRecv = SendFrame(binSend, 1);
			if (binRecv.GetSize() >= 9 && binRecv[0] == 0x71 && binRecv[8] == 0x00)
			{
				return true;
			}

			Tracer::error("FinishProgram", "fail");
			return false;
		}

		unsigned int MCDCmdTrans::Calc_Key(uint8_t* a1)
		{
			uint8_t v2[4] = { 0 };
			int v3;
			signed int v4;
			int v5;
			signed int v6;
			signed int v7;
			int v8;
			int v9;
			char v10;
			unsigned int result = 0;
			uint8_t* v12;

			v12 = a1;
			v3 = 0xC541A9;
			v4 = 0;
			do
			{
				v5 = (uint8_t)v12[v4];
				v6 = 0;
				do
				{
					v7 = 0;
					if (v5 << 31 != v3 << 31)
					{
						v3 |= 0x1000000u;
						v7 = 1085480;
					}
					v5 = v5 >> 1;
					v8 = ((v3 >> 1) ^ v7) & 0x109028;
					v9 = v3 >> 1;
					v3 = (v9 & 0xFFEF6FD7 | v8) & 0xFFFFFF;
					++v6;
				} while (v6 < 8);
				++v4;
			} while (v4 < 8);

			v2[0] = ((v9 & 0xFFEF6FD7 | v8) & 0xFFFFFF) >> 4;
			v10 = (v3 >> 20) & 0xF;
			v2[1] = ((v3 >> 8) & 0xF0) + v10;
			result = ((v3 >> 16) & 0xF) + 16 * v3;
			v2[2] = result;
			result = ((((v9 & 0xFFEF6FD7 | v8) & 0xFFFFFF) >> 4) & 0xFF) << 16 | ((((v3 >> 8) & 0xF0) + ((v3 >> 20) & 0xF)) & 0xFF) << 8 | (result & 0xFF);
			result = v2[0] << 16 | v2[1] << 8 | v2[2];

			return result;
		}

		CBinary MCDCmdTrans::SeedToKey(CBinary binSeed, CBinary binMask)
		{
			uint32_t dwKey = 0;
			CBinary binKey;
			CBinary binData = binSeed + binMask;


#ifdef _VM_PROTECT_
			VMStart();
#endif // _WINDOWS_

			dwKey = Calc_Key(binData.GetBuffer());

			binKey.Add((dwKey >> 16) & 0xff);
			binKey.Add((dwKey >> 8) & 0xff);
			binKey.Add(dwKey & 0xff);

#ifdef _VM_PROTECT_
			VMEnd();
#endif // _WINDOWS_

			return binKey;
		}

		bool MCDCmdTrans::Get_SecurityMask(uint16_t uDOIPAddr, CBinary& binMask)
		{
			binMask = CBinary("\x41\xAA\x42\xBB\x43", 5);

			switch (uDOIPAddr)
			{
			case 0x1001:
				binMask = CBinary("\x19\xB8\x34\xDC\xA2", 5);
				break;
			case 0x1002://234D24C06D
				binMask = CBinary("\x19\xB8\x34\xDC\xA2", 5);
				/*binMask = CBinary("\x23\x4D\x24\xC0\x6D", 5);*/
				break;
			case 0x1201:
				binMask = CBinary("\x71\xCF\x05\xA2\xED", 5);
				break;
			case 0x1202:
				binMask = CBinary("\x71\xCF\x05\xA2\xED", 5);
				break;
			case 0x1401:
				binMask = CBinary("\xA5\x79\xF8\xED\xC1", 5);
				break;
			case 0x1402:
				binMask = CBinary("\xA5\x79\xF8\xED\xC1", 5);
				break;
			case 0x1011:
				binMask = CBinary("\xF5\x6B\x94\xCD\x8A", 5);
				break;
			case 0x1280:
				binMask = CBinary("\xE7\x52\x0B\x1F\x68", 5);
				break;
			case 0x1281:
				binMask = CBinary("\xA3\x5F\xEC\x16\x02", 5);
				break;
			case 0x1444:
				binMask = CBinary("\x29\x64\xA7\xB0\x3C", 5);
				break;
			case 0x14AE:
				binMask = CBinary("\x72\x65\x9F\xBA\x04", 5);
				break;
			case 0x14BE:
				binMask = CBinary("\x72\x65\x9F\xBA\x04", 5);
				break;
			case 0x1460:
				binMask = CBinary("\x61\x9B\xAE\x85\x7D", 5);
				break;
			case 0x1461:
				binMask = CBinary("\x61\x9B\xAE\x85\x7D", 5);
				break;
			case 0x1450:
				binMask = CBinary("\x61\x9B\xAE\x85\x7D", 5);
				break;
			case 0x1451:
				binMask = CBinary("\x61\x9B\xAE\x85\x7D", 5);
				break;
			case 0x1023:
				binMask = CBinary("\x83\x04\x1F\xB6\x2D", 5);
				break;
			case 0x1024:
				binMask = CBinary("\xFA\x0B\x6E\x13\x2C", 5);
				break;
			case 0x1025:
				binMask = CBinary("\x3C\x8E\xB4\x5A\x9F", 5);
				break;
			case 0x1030:
				binMask = CBinary("\x4F\x0C\xB6\xED\x89", 5);
				break;
			case 0x1031:
				binMask = CBinary("\x4F\x0C\xB6\xED\x89", 5);
				break;
			case 0x1032:
				binMask = CBinary("\x4F\x0C\xB6\xED\x89", 5);
				break;
			case 0x1033:
				binMask = CBinary("\x4F\x0C\xB6\xED\x89", 5);
				break;
			case 0x1601:
				binMask = CBinary("\x71\x35\xDB\x03\x7A", 5);
				break;
			case 0x1701:
				binMask = CBinary("\x82\x6D\xA7\x23\xE2", 5);
				break;
			case 0x1C01:
				binMask = CBinary("\x53\x52\x56\x47\x35", 5);
				break;
			case 0x1633:
				binMask = CBinary("\x83\x4D\xFB\x5A\x6E", 5);
				break;
			case 0x1635://BECM1_102
				binMask = CBinary("\x87\x5C\x0E\xB1\x10", 5);
				break;
				//case 0x1635://BECM1_75
				//	binMask = CBinary("\x4C\x1B\x93\xAF\x05", 5);
				//	break;
			case 0x1631:
				binMask = CBinary("\x64\x9A\x72\x5D\x83", 5);
				break;
			case 0x1637:
				binMask = CBinary("\x4A\x0E\x11\x8B\x7F", 5);
				break;
			case 0x1650:
				binMask = CBinary("\x15\x1E\x09\xCA\x8A", 5);
				break;
			case 0x1630:
				binMask = CBinary("\xB6\xA6\x54\x9E\xC3", 5);
				break;
			case 0x1670:
				binMask = CBinary("\x88\xD0\xE5\x81\xE6", 5);
				break;
			case 0x1720:
				binMask = CBinary("\x88\xD0\xE5\x81\xE6", 5);
				break;
			case 0x1672:
				binMask = CBinary("\x3C\xEB\x87\x2A\xD9", 5);
				break;
			case 0x1614:
				binMask = CBinary("\x8D\xF7\x51\x43\xBA", 5);
				break;
			case 0x1A12:
				binMask = CBinary("\xC4\xAC\x3D\x76\x9F", 5);
				break;
			case 0x1A13:
				binMask = CBinary("\x15\xB9\x43\x5B\x61", 5);
				break;
			case 0x1A21:
				binMask = CBinary("\xE6\xA5\xAB\x73\xF9", 5);
				break;
			case 0x1A22:
				binMask = CBinary("\x83\x78\x8B\x67\x7E", 5);
				break;
			case 0x1A40:
				binMask = CBinary("\x9A\x27\xB4\xE8\xF3", 5);
				break;
			case 0x1A41:
				binMask = CBinary("\x9A\x27\xB4\xE8\xF3", 5);
				break;
			case 0x1A42:
				binMask = CBinary("\x9A\x27\xB4\xE8\xF3", 5);
				break;
			case 0x1A43:
				binMask = CBinary("\x9A\x27\xB4\xE8\xF3", 5);
				break;
			case 0x1A11:
				binMask = CBinary("\x30\xA9\x2D\xF9\x01", 5);
				break;
			case 0x1A16:
				binMask = CBinary("\x5A\xC6\x74\xE0\xD1", 5);
				break;
			case 0x1A15:
				binMask = CBinary("\x54\x9E\x18\x7F\x26", 5);
				break;
			case 0x1A27:
				binMask = CBinary("\x4B\xDE\xF2\x69\x06", 5);
				break;
			case 0x1A28:
				binMask = CBinary("\x39\xE4\xAE\xD3\xB1", 5);
				break;
			case 0x1A82:
				binMask = CBinary("\x46\xA9\xE7\x8D\xB3", 5);
				break;
			case 0x1A83:
				binMask = CBinary("\x46\xA9\xE7\x8D\xB3", 5);
				break;
			case 0x1BB3:
				binMask = CBinary("\x3C\xF6\xE5\x4A\x2B", 5);
				break;
			case 0x1BB4:
				binMask = CBinary("\x3C\xF6\xE5\x4A\x2B", 5);
				break;
			case 0x1BB5:
				binMask = CBinary("\x51\x7C\xE6\xAF\x98", 5);
				break;
			case 0x1BB6:
				binMask = CBinary("\x51\x7C\xE6\xAF\x98", 5);
				break;
			case 0x1BB7:
				binMask = CBinary("\x51\x7C\xE6\xAF\x98", 5);
				break;
			default:
				break;
			}

			return true;
		}
	}
}