#include "pch.h"
#include "OTA.h"
#include "CharEncoding.h"
#include "TCL Copy ToolDlg.h"

std::vector<_SIACP_> g_vtSiacp = {
	{"EnterFactory", "AA", "10", "01", false, 100},
	{"LeaveFactory", "AA", "10", "00", false, 100},
	{"WBInit", "AA", "16", "02", false, 100},//白平衡数据初始化（适用于所有信源）
	{"GetProjectID", "AA", "84", "00", false, 100},
	{"GetSoftVersion", "AA", "57", "00", false, 100},
	{"GetDeviceId", "AA", "BE", "01", true, 100},
	{"GetClientType", "AA", "8C", "00", false, 100},
	{"GetMAC", "AA", "BE", "00", true, 100},
	{"GetHDCPKey", "AA", "EE", "00", false, 100},
	{"GetHDCPKey22", "AA", "E7", "00", false, 100},
	{"GetWidi", "AA", "E7", "00", false, 100},
	{"GetNetflixESN", "AA", "BE", "06", true, 100},
	{"GetWidevine", "AA", "EC", "00", true, 100},
	{"GetCiKey", "AA", "EC", "01", true, 100},
	{"GetOSDLanguage", "AA", "97", "00", true, 100},
	{"GetShopLanguage", "AA", "97", "01", true, 100},
	{"GetChannel", "AA", "97", "13", true, 100},
	// 设置;
	{"SetProjectId", "AA", "70", "", false, 100},
	{"SetDeviceID", "AA", "B2", "", false, 100},
	{"SetMAC", "AA", "B3", "", false, 100},
	{"SetHDCPKey", "AA FE", "86", "", false, 100},
	{"SetHDCPKey22", "AA FE", "E4", "", false, 100},
	{"SetNetflixESN", "AA", "99 00", "", false, 100},
	{"SetWidi", "AA FE", "E4", "", false, 100}, //与hdcp22相同指令
	{"SetWidevine", "AA FE", "E9 00", "", false, 100},
	{"SetCiKey", "AA FE", "E9 01", "", false, 100},
	{"SetOSDLanguage", "AA", "96 00", "", true, 100},
	{"SetShopLanguage", "AA", "96 01", "", true, 100},
	// 设置;
	{"SetChannel", "AA", "15", "", false, 100},
	{"SetWBNormal", "AA", "4D 04 01 01", "", false, 100},
	{"SetWBCool", "AA", "4D 04 02 01", "", false, 100},
	{"SetWBWarm", "AA", "4D 04 03 01", "", false, 100},
	// 检测;
	{"CheckMAC", "AA", "B4", "00", false, 100},
	{"CheckDeviceId", "AA", "B4", "00", false, 100},
	{"CheckHDCP", "AA", "87", "00", false, 100},
	{"CheckNetflixESN", "AA", "9A", "00", true, 100},
	{"CheckWidi", "AA", "E5", "00", false, 100},
	{"CheckWidevine", "AA", "EA", "00", true, 100},

	{"CheckCikey", "AA", "EA", "01", true, 100},
	{"CheckHDCP22", "AA", "E5", "00", false, 100},
	{"StarWarmUpMode", "AA", "13", "01", false, 100},
	{"StopWarmUpMode", "AA", "13", "00", false, 100}
};

const unsigned short CRC16_TABLE[16] = {
	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
	0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF};

unsigned short CRC16Calculate(byte *pBuffer, unsigned int wordLength)
{
	unsigned short wordCRC;
	byte byteTemp;

	wordCRC = 0xFFFF;
	while (wordLength--)
	{
		byteTemp = (byte)(wordCRC >> 0x0C);
		wordCRC <<= 4;
		wordCRC ^= CRC16_TABLE[byteTemp ^ ((*pBuffer) >> 0x04)];
		byteTemp = (byte)(wordCRC >> 0x0C);
		wordCRC <<= 4;
		wordCRC ^= CRC16_TABLE[byteTemp ^ ((*pBuffer) & 0x0F)];
		pBuffer++;
	}

	return wordCRC;
}

unsigned char TwoHexChar2Char(char ch1, char ch2)
{
	char Numb1;
	char Numb2;

	if (ch1 >= 'A')
		Numb1 = (toupper(ch1) - '0' - 7) * 16;
	else
		Numb1 = (ch1 - '0') * 16;

	if (ch2 >= 'A')
		Numb2 = (toupper(ch2) - '0' - 7);
	else
		Numb2 = (ch2 - '0');

	return (Numb1 + Numb2);
}

std::string HexString2Bytes(std::string strHex, const int &len /* = 3 */)
{
	byte value = 0;
	std::string strBytes;
	int nSize = strHex.size();
	for (int i = 0; i < nSize; i += len)
	{
		strBytes.push_back(TwoHexChar2Char(strHex[i], strHex[i + 1]));
	}

	return strBytes;
}

std::string Bytes2HexString(const unsigned char *pbuffer, int nLen, char chSpace)
{
	std::string hex;
	char szhex[5] = {0};
	for (int i = 0; i < nLen; i++)
	{
		memset(szhex, 0, 5);
		_stprintf_s(szhex, "%02X%c", pbuffer[i], chSpace);
		hex.append(szhex);
	}

	return hex.substr(0, hex.size() - 1);
}

std::string Bytes2HexString(const unsigned char *pbuffer, int nLen)
{
	std::string hex;
	char szhex[5] = {0};
	for (int i = 0; i < nLen; i++)
	{
		memset(szhex, 0, 5);
		_stprintf_s(szhex, "%02X", pbuffer[i]);
		hex.append(szhex);
	}

	return hex;
}

BOOL IsValidString(LPCTSTR lpszString)
{
	if (lpszString == NULL)
		return FALSE;

	do
	{
		// ASCII可显示的字符;
		if (*lpszString < 32 || *lpszString > 126)
		{
			return FALSE;
		}
	} while (*++lpszString);

	return TRUE;
}

// 去除空格;
std::string &trim(std::string &str)
{
	int nIndex = 0;
	while ((nIndex = str.find_first_of(' ')) != std::string::npos)
		str.erase(nIndex, 1);

	return str;
}

CSIACP::CSIACP(void) //:m_vtcommand(g_siacp, g_siacp+sizeof(g_siacp)/sizeof(_SIACP_))
{
	m_pMainDlg = nullptr;
	m_pSerial = NULL;
	LoadCommand();
}

CSIACP::~CSIACP(void)
{
	CloseComm();
}

void CSIACP::SetMainDlg(CDialogEx* p)
{
	m_pMainDlg = p;
}

void CSIACP::ShowMessage(LPCTSTR lpMsg, LOG_ENUM logtype)
{
	if (m_pMainDlg && lpMsg)
	{
		CTCLCopyToolDlg* pMainDlg = (CTCLCopyToolDlg*)m_pMainDlg;
		pMainDlg->SetOptionLog(std::string(lpMsg), logtype);
	}
}

void CSIACP::LoadCommand()
{
	// 解析xml;
	tinyxml2::XMLDocument doc;
	if (tinyxml2::XML_SUCCESS != doc.LoadFile(_T("Siacp.xml")))
	{
		SaveCommand(g_vtSiacp, _T("Siacp.xml"));
		return;
	}

	std::string ver;
	std::string desc;
	g_vtSiacp.clear();
	tinyxml2::XMLElement *pXmlRoot = NULL;
	if ((pXmlRoot = doc.RootElement()) != NULL)
	{
		if (_tcsicmp(pXmlRoot->Value(), "CommandList") == 0)
		{
			// 属性;
			const tinyxml2::XMLAttribute *pAttr = pXmlRoot->FirstAttribute();
			while (pAttr)
			{
				if (_tcsicmp(pAttr->Name(), "ver") == 0)
				{
					ver = pAttr->Value();
				}

				if (_tcsicmp(pAttr->Name(), "desc") == 0)
				{
					desc = pAttr->Value();
				}

				pAttr = pAttr->Next();
			}

			// 子项;
			tinyxml2::XMLElement *pXmlElent = pXmlRoot->FirstChildElement();
			while (pXmlElent)
			{
				_SIACP_ siacp;
				if (_tcsicmp(pXmlElent->Value(), _T("Item")) == 0)
				{
					tinyxml2::XMLElement *pItem = pXmlElent->FirstChildElement();
					while (pItem)
					{
						if (_tcsicmp(pItem->Value(), _T("Name")) == 0)
						{
							siacp.name = pItem->GetText();
						}
						else if (_tcsicmp(pItem->Value(), _T("HeadCode")) == 0)
						{
							siacp.head = pItem->GetText();
						}
						else if (_tcsicmp(pItem->Value(), _T("ucCommand")) == 0)
						{
							siacp.code = pItem->GetText();
						}
						else if (_tcsicmp(pItem->Value(), _T("Mark")) == 0)
						{
							siacp.mark = pItem->GetText();
						}
						else if (_tcsicmp(pItem->Value(), _T("MultiParams")) == 0)
						{
							siacp.bMulticode = pItem->BoolText();
						}
						else if (_tcsicmp(pItem->Value(), _T("ReadWaitTime")) == 0)
						{
							siacp.read_wait_time = pItem->IntText();
						}
						else if (_tcsicmp(pItem->Value(), _T("CmdWaitTime")) == 0)
						{
							siacp.cmd_wait_time = pItem->IntText();
						}

						pItem = pItem->NextSiblingElement();
					}
				}
				g_vtSiacp.push_back(siacp);
				pXmlElent = pXmlElent->NextSiblingElement();
			}
		}
	}

	Global::WriteTextLog("Load Comman xml");
}

void CSIACP::SaveCommand(std::vector<_SIACP_> &vtSiacp, std::string path)
{
	tinyxml2::XMLDocument doc;
	//添加申明可以使用如下两行
	tinyxml2::XMLDeclaration *declaration = doc.NewDeclaration();
	doc.InsertFirstChild(declaration);

	tinyxml2::XMLElement *root = doc.NewElement("CommandList");
	root->SetAttribute("ver", "9.5");
	root->SetAttribute("desc", "command info");
	doc.InsertEndChild(root);

	std::vector<_SIACP_>::iterator it = vtSiacp.begin();
	for (; it != vtSiacp.end(); it++)
	{
		tinyxml2::XMLElement *pItem = doc.NewElement("Item");

		tinyxml2::XMLElement *pName = doc.NewElement("Name");
		pName->SetText(it->name.c_str());
		pItem->InsertEndChild(pName);

		tinyxml2::XMLElement *pHeadCode = doc.NewElement("HeadCode");
		pHeadCode->SetText(it->head.c_str());
		pItem->InsertEndChild(pHeadCode);

		tinyxml2::XMLElement *pucCommand = doc.NewElement("ucCommand");
		pucCommand->SetText(it->code.c_str());
		pItem->InsertEndChild(pucCommand);

		tinyxml2::XMLElement *pMark = doc.NewElement("Mark");
		pMark->SetText(it->mark.c_str());
		pItem->InsertEndChild(pMark);

		tinyxml2::XMLElement *pMultiParams = doc.NewElement("MultiParams");
		pMultiParams->SetText(it->bMulticode);
		pItem->InsertEndChild(pMultiParams);

		tinyxml2::XMLElement *pReadWaitTime = doc.NewElement("ReadWaitTime");
		pReadWaitTime->SetText(it->read_wait_time);
		pItem->InsertEndChild(pReadWaitTime);

		tinyxml2::XMLElement* pCmdWaitTime = doc.NewElement("CmdWaitTime");
		pCmdWaitTime->SetText(it->cmd_wait_time);
		pItem->InsertEndChild(pCmdWaitTime);

		root->InsertEndChild(pItem);
	}

	doc.SaveFile(path.c_str());
}

BOOL CSIACP::OpenComm(LPCTSTR lpszCom, DWORD dwBaudrate)
{
	if (lpszCom == NULL || lpszCom[0] == '\0')
	{
		LOG4C((LOG_WARN, "(lpszCom) Invalid parameter!"));
		return FALSE;
	}

	// 释放打开的;
	if (m_pSerial)
		delete m_pSerial;
	m_pSerial = NULL;

	m_pSerial = new CSerialPort();
	if (m_pSerial == NULL)
	{
		LOG4C((LOG_WARN, "(m_pSerial) Fail to create object!"));
		return FALSE;
	}

	m_pSerial->Open(lpszCom, dwBaudrate);
	if (m_pSerial->IsOpen() == FALSE)
	{
		delete m_pSerial;
		m_pSerial = NULL;
		LOG4C((LOG_WARN, "Open Serial Port Fail !"));
		return FALSE;
	}

	// 超时值设置;
	COMMTIMEOUTS comTimeOut;
	comTimeOut.ReadIntervalTimeout = 50;
	comTimeOut.ReadTotalTimeoutConstant = 8000;   // 读取所有字节总超时值;
	comTimeOut.ReadTotalTimeoutMultiplier = 100;  // 读取1个字节超时值;
	comTimeOut.WriteTotalTimeoutConstant = 5000;  // 写所有字节的总超时值;
	comTimeOut.WriteTotalTimeoutMultiplier = 100; // 写1个字节的超时值;
	m_pSerial->SetTimeouts(comTimeOut);

	return TRUE;
}

void CSIACP::CloseComm()
{
	if (m_pSerial)
		delete m_pSerial;
	m_pSerial = NULL;
}

BOOL CSIACP::ExecSerialCommand(const _SIACP_ &siacp, std::string command)
{
	if (m_pSerial == NULL || !m_pSerial->IsOpen())
	{
		LOG4C((LOG_ERROR, "Serial Port un't Open!"));
		return FALSE;
	}

	byte szRecive[BUFFER_LEN] = {0};
	DWORD dwWritten = m_pSerial->Write(command.c_str(), command.size());
	Global::WriteTextLog(_T("COM Write:%s"), Bytes2HexString((const byte *)command.c_str(), command.size(), ' ').c_str());
	if (dwWritten != command.size())
	{
		Global::WriteTextLog("COM Written Error!");
		return FALSE;
	}

	// 暂停时间;// 等待设备响应完成;
	Sleep(siacp.read_wait_time);
	DWORD dwBytesRead = m_pSerial->Read(szRecive, BUFFER_LEN);
	if (dwBytesRead == 0)
	{
		Global::WriteTextLog("COM Read Error!");
		return FALSE;
	}

	Global::WriteTextLog(_T("COM Read:%s\r"), Bytes2HexString(szRecive, dwBytesRead, ' ').c_str());

	// 下一条命令等待时间;
	Sleep(siacp.cmd_wait_time);
	// 解析数据;
	return ParserSerialData(m_vtdata, siacp, szRecive, dwBytesRead);
}

BOOL CSIACP::ParserSerialData(std::vector<RTN> &vtdata, const _SIACP_ &siacp, byte *pbuffer, DWORD dwlen)
{
	vtdata.clear();
	if (pbuffer == NULL || dwlen < 5)
		return FALSE;

	// 返回码;
	byte byReturn = TV_Return;
	byte byHead = (byte)HexString2Bytes(siacp.head)[0];
	byte byCode = (byte)HexString2Bytes(siacp.code)[0];

	if (byHead == TV_Debug)
	{
		byReturn = TV_Return;
	}
	else if (byHead == TV_Panel_Debug)
	{
		byReturn = TV_Panel_Return;
	}
	else if (byHead == TV_Debug_Other)
	{
		byReturn = TV_Other_Return;
	}
	else
	{
		Global::WriteTextLog("COM Read Parser: Invalid return code!");
		return FALSE;
	}

	std::string data;
	data.append((const char *)pbuffer, dwlen);

	int nABFE = 0;
	std::string package;
	int package_len = 0;
	// 已取出的长度;
	int nTookenLen = 0;
	unsigned short usCRCValue;
	while (true)
	{
		// 是否已取完所有数据;
		if (nTookenLen >= dwlen)
			break;

		// 取出长度;
		if ((byte)data.at(nTookenLen + 1) == 0xFE)
		{
			nABFE = 2; //FE占1字节,长度多占1字节;共多占2字节;
			package_len = ((unsigned int)data[nTookenLen + 2] << 8) | (byte)data[nTookenLen + 3];
		}
		else
		{
			nABFE = 0;
			package_len = data[nTookenLen + 1];
		}

		// 包长度是否在有效长度内;
		if (package_len > (dwlen - nTookenLen))
		{
			Global::WriteTextLog("COM Read Parser: Incorrect length of returned data!");
			return FALSE;
		}

		// 取出数据包;
		package = data.substr(nTookenLen, nTookenLen + package_len);

		// 校验包头是否正确;
		if (byte(package[0]) != byReturn)
		{
			Global::WriteTextLog("COM Read Parser: Data Header Check Error!");
			return FALSE;
		}

		// 校验crc;
		usCRCValue = CRC16Calculate((unsigned char *)package.data(), package_len - 2);
		if (((usCRCValue >> 8) & 0xFF) != (unsigned char)package[package_len - 2] || (usCRCValue & 0xFF) != (unsigned char)package[package_len - 1])
		{
			Global::WriteTextLog("COM Read Parser: Data CRC validation failure!");
			return FALSE;
		}

		// 第一组返回，检测结果码
		if (nTookenLen == 0)
		{
			if (package[2] != RC_OK)
			{
				Global::WriteTextLog("COM Read Parser: The return code of the response data is invalid!");
				return FALSE;
			}
		}
		else
		{
			// 响应数据的命令码 = 发送数据的命令码 - 1;
			if (byte(package[2 + nABFE] - 1) != byCode)
			{
				Global::WriteTextLog("COM Read Parser: The command code of response data does not match the command code of sending data!");
				return FALSE;
			}

			RTN rtn;
			// 获取结果值;
			if (siacp.bMulticode)
			{
				rtn.len = package_len - 6 - nABFE;
				rtn.data = package.substr(4 + nABFE, package_len - 6 - nABFE);
			}
			else
			{
				rtn.len = package_len - 5 - nABFE;
				rtn.data = package.substr(3 + nABFE, package_len - 5 - nABFE);
			}
			vtdata.push_back(rtn);
		}

		nTookenLen += package_len;
	}

	return TRUE;
}

const _SIACP_ *CSIACP::GetSiacp(std::string name)
{
	std::vector<_SIACP_>::iterator it = g_vtSiacp.begin();
	for (; it != g_vtSiacp.end(); it++)
	{
		if (_tcsicmp(it->name.c_str(), name.c_str()) == 0)
		{
			return &*it;
		}
	}

	return NULL;
}

std::string CSIACP::GetSiacpCommand(const _SIACP_ &siacp, std::string others, int othersLen)
{
	std::string command;
	command.append(HexString2Bytes(siacp.head).c_str(), (siacp.head.size() + 1) / 3);
	command.append(HexString2Bytes(siacp.code).c_str(), (siacp.code.size() + 1) / 3);
	command.append(HexString2Bytes(siacp.mark).c_str(), (siacp.mark.size() + 1) / 3);
	command.append(others.c_str(), othersLen);

	// 长度;
	byte szlen[2] = {0};
	int len = command.size() + 3; // 3=长度本身占1位+2位crc;
	if ((byte)command[1] == 0xFE)
	{
		szlen[0] = ((len + 1) >> 8) & 0xFF;
		szlen[1] = (len + 1) & 0xFF;
		command.insert(2, (char *)szlen, 2);
	}
	else
	{
		szlen[0] = len & 0xFF;
		command.insert(1, (char *)szlen, 1);
	}

	// crc校验;
	byte szcrc[2] = {0};
	WORD usCRCValue = CRC16Calculate((byte *)command.c_str(), command.size());
	szcrc[0] = (usCRCValue >> 8) & 0xFF;
	szcrc[1] = usCRCValue & 0xFF;
	command.append((char *)szcrc, 2);

	return command;
}

std::string CSIACP::GetSiacpCommand(std::string name, std::string others, int othersLen)
{
	std::string command;
	std::vector<_SIACP_>::iterator it = g_vtSiacp.begin();
	for (; it != g_vtSiacp.end(); it++)
	{
		if (_tcsicmp(name.c_str(), it->name.c_str()) == 0)
		{
			command.append(HexString2Bytes(it->head).c_str(), (it->head.size() + 1) / 3);
			command.append(HexString2Bytes(it->code).c_str(), (it->code.size() + 1) / 3);
			command.append(HexString2Bytes(it->mark).c_str(), (it->mark.size() + 1) / 3);
			command.append(others.c_str(), othersLen);

			// 长度;
			byte szlen[2] = {0};
			int len = command.size() + 3; // 长度本身占1位;
			if ((byte)command[1] == 0xFE)
			{
				szlen[0] = ((len + 1) >> 8) & 0xFF;
				szlen[1] = (len + 1) & 0xFF;
				command.insert(2, (char *)szlen, 2);
			}
			else
			{
				szlen[0] = len & 0xFF;
				command.insert(1, (char *)szlen, 1);
			}

			// crc校验;
			byte szcrc[2] = {0};
			int usCRCValue = CRC16Calculate((byte *)command.c_str(), command.size());
			szcrc[0] = (usCRCValue >> 8) & 0xFF;
			szcrc[1] = usCRCValue & 0xFF;
			command.append((char *)szcrc, 2);

			break;
		}
	}

	return command;
}

BOOL CSIACP::SendCommand(std::string cmd_name, const byte *pszOthers, DWORD dwOthersLen)
{
	std::string others;
	if (pszOthers && dwOthersLen > 0)
	{
		others.append((char *)pszOthers, dwOthersLen);
	}

	// 获取命令协议;
	const _SIACP_ *pSiacp = GetSiacp(cmd_name);
	if (pSiacp == NULL)
	{
		LOG4C((LOG_ERROR, "This command is not supported!"));
		return FALSE;
	}

	std::string command = GetSiacpCommand(*pSiacp, others, dwOthersLen);
	if (command.size() == 0)
	{
		LOG4C((LOG_ERROR, "Generation command failed!"));
		return FALSE;
	}

	return ExecSerialCommand(*pSiacp, command);
}

BOOL CSIACP::SendCommand2(std::string cmd_name, std::string data /* = "" */, size_t nlen /* = 0 */)
{
	// 获取命令协议;
	const _SIACP_ *pSiacp = GetSiacp(cmd_name);
	if (pSiacp == NULL)
	{
		LOG4C((LOG_ERROR, "This command is not supported!"));
		return FALSE;
	}

	std::string command = GetSiacpCommand(*pSiacp, data, nlen);
	if (command.size() == 0)
	{
		LOG4C((LOG_ERROR, "Generation command failed!"));
		return FALSE;
	}

	return ExecSerialCommand(*pSiacp, command);
}

BOOL CSIACP::SCBC_WaitTVBoot()
{
	byte szRecive[BUFFER_LEN] = { 0 };
	DWORD dwBytesRead = m_pSerial->Read(szRecive, BUFFER_LEN);
	if (dwBytesRead == 0)
	{
		if ( SCBC_EnterFactory() )
		{
			SCBC_LeaveFactory();
			Global::WriteTextLog("TV Boot OK!");
			return TRUE;
		}		
	}

	return FALSE;
}

BOOL CSIACP::SCBC_MTKInit()
{
	if (m_pSerial == NULL)
	{
		LOG4C((LOG_ERROR, "CSerialPort对象未初始化"));
		return FALSE;
	}

	if (!m_pSerial->IsOpen())
	{
		LOG4C((LOG_ERROR, "CSerialPort对象未打开串口"));
		return FALSE;
	}

	unsigned char ucBufInitMTK8223[16] = {0x54, 0x8A, 0x51, 0x37, 0x56, 0x92, 0x1C, 0xB2, 0x50, 0x80, 0x50, 0x02, 0x50, 0x01, 0x50, 0xE2};
	m_pSerial->Write(ucBufInitMTK8223, 16);
	Sleep(50);

	return TRUE;
}

// 对外接口;
BOOL CSIACP::SCBC_EnterFactory()
{
	return SendCommand("EnterFactory");
}

BOOL CSIACP::SCBC_LeaveFactory()
{
	return SendCommand("LeaveFactory");
}

BOOL CSIACP::SCBC_WBInit()
{
	return SendCommand("WBInit");
}

BOOL CSIACP::SCBC_GetProjectId(int &pid)
{
	BOOL bRet = SendCommand("GetProjectId");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		if (rtn.len == 2)
		{
			pid = (byte)rtn.data[0] << 8;
			pid += (byte)rtn.data[1];
		}
		else
		{
			pid = (byte)rtn.data[0];
		}
	}

	return bRet;
}

BOOL CSIACP::SCBC_GetSoftVersion(std::string &strVer)
{
	BOOL bRet = SendCommand("GetSoftVersion");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		if (!IsValidString(rtn.data.c_str()))
		{
			LOG4C((LOG_WARN, "tv version string is invalid!"));
			return FALSE;
		}

		strVer.append(rtn.data.c_str(), rtn.len);
	}

	return bRet;
}

BOOL CSIACP::SCBC_GetDeviceId(std::string &strDid)
{
	BOOL bRet = SendCommand("GetDeviceId");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		strDid.append(rtn.data.c_str(), rtn.len);
	}

	return bRet;
}

BOOL CSIACP::SCBC_GetClientType(std::string &strClt)
{
	BOOL bRet = SendCommand("GetClientType");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		if (!IsValidString(rtn.data.c_str()))
		{
			LOG4C((LOG_WARN, "tv client type string is invalid!"));
			return FALSE;
		}
		strClt.append(rtn.data.c_str(), rtn.len);
	}

	return bRet;
}

BOOL CSIACP::SCBC_GetMAC(std::string &strMac)
{
	BOOL bRet = SendCommand("GetMAC");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		strMac = Bytes2HexString((const byte *)rtn.data.c_str(), rtn.len, '-');
	}

	return bRet;
}

BOOL CSIACP::SCBC_GetHDCPKey(std::string &strHDCP)
{
	BOOL bRet = SendCommand("GetHDCPKey");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		//strHDCP.append(rtn.data.c_str(), rtn.len);
		strHDCP = Bytes2HexString((const byte *)rtn.data.c_str(), rtn.len);
	}

	return bRet;
}

BOOL CSIACP::SCBC_GetHDCPKey22(std::string &strHDCP22)
{
	BOOL bRet = SendCommand("GetHDCPKey22");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		//strHDCP22.append(rtn.data.c_str(), rtn.len);
		strHDCP22 = Bytes2HexString((const byte *)rtn.data.c_str(), rtn.len);
	}

	return bRet;
}

BOOL CSIACP::SCBC_GetWidi(std::string &strWidi)
{
	BOOL bRet = SendCommand("GetWidi");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		//strWidi.append(rtn.data.c_str(), rtn.len);
		strWidi = Bytes2HexString((const byte *)rtn.data.c_str(), rtn.len);
	}

	return bRet;
}

BOOL CSIACP::SCBC_GetNetflixESN(std::string &strESN)
{
	BOOL bRet = SendCommand("GetNetflixESN");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		strESN.append(rtn.data.c_str(), rtn.len);
		//strESN = Bytes2HexString((const byte*)rtn.data.c_str(), rtn.len, ' ');
	}

	return bRet;
}

BOOL CSIACP::SCBC_GetWidevine(std::string &strWidevine)
{
	BOOL bRet = SendCommand("GetWidevine");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		//strWidevine.append(rtn.data.c_str(), rtn.len);
		strWidevine = Bytes2HexString((const byte *)rtn.data.c_str(), rtn.len);
	}

	return bRet;
}

BOOL CSIACP::SCBC_GetCiKey(std::string &strCikey)
{
	BOOL bRet = SendCommand("GetCiKey");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		//strCikey.append(rtn.data.c_str(), rtn.len);
		strCikey = Bytes2HexString((const byte *)rtn.data.c_str(), rtn.len);
	}

	return bRet;
}

BOOL CSIACP::SCBC_GetOSDLanguage(std::string &strOSDLan)
{
	BOOL bRet = SendCommand("GetOSDLanguage");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		strOSDLan.append(rtn.data.c_str(), rtn.len);
		strOSDLan = Bytes2HexString((const byte*)rtn.data.c_str(), rtn.len, ' ');
	}

	return bRet;
}

BOOL CSIACP::SCBC_GetShopLanguage(std::string &strShopLan)
{
	BOOL bRet = SendCommand("GetShopLanguage");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		strShopLan.append(rtn.data.c_str(), rtn.len);
		strShopLan = Bytes2HexString((const byte*)rtn.data.c_str(), rtn.len, ' ');
	}

	return bRet;
}

BOOL CSIACP::SCBC_GetChannel(std::string& channel)
{
	BOOL bRet = SendCommand("GetChannel");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		channel.append(rtn.data.c_str(), rtn.len);
		channel = Bytes2HexString((const byte*)rtn.data.c_str(), rtn.len, ' ');
	}

	return bRet;
}

BOOL CSIACP::SCBC_SetProjectId(const int &pid)
{
	std::string data;
	if (pid > 0xFF)
	{
		data.append(1, (pid >> 8) & 0xFF);
		data.append(1, pid & 0xFF);
	}
	else
	{
		data.append(1, pid & 0xFF);
	}

	return SendCommand2("SetProjectId", data, data.size());
}

BOOL CSIACP::SCBC_SetProjectId(std::string pid)
{
	return SCBC_SetProjectId(atoi(pid.c_str()));
}

BOOL CSIACP::SCBC_SetProjectId(const byte *pBuffer, const int &nLen)
{
	return SendCommand("SetProjectId", pBuffer, nLen);
}

BOOL CSIACP::SCBC_SetDeviceId(std::string strDeviceId)
{
	if (strDeviceId.size() < 40)
	{
		return FALSE;
	}

	return SendCommand2("SetDeviceId", strDeviceId, strDeviceId.size());
}

BOOL CSIACP::SCBC_SetDeviceId(const byte *pBuffer, const int &nLen)
{
	return SendCommand("SetDeviceId", pBuffer, nLen);
}

BOOL CSIACP::SCBC_SetMAC(std::string strMac)
{
	if (strMac.size() < 16)
		return FALSE;

	std::string data = HexString2Bytes(strMac);
	return SendCommand2("SetMAC", data, (strMac.size() + 1) / 3);
}

BOOL CSIACP::SCBC_SetMAC(const byte *pBuffer, const int &nLen)
{
	return SendCommand("SetMAC", pBuffer, nLen);
}

BOOL CSIACP::SCBC_SetHDCPKey(std::string strHDCP, BOOL bHasSpace /* = TRUE */)
{
	std::string data = HexString2Bytes(strHDCP, bHasSpace ? 3 : 2);
	return SendCommand2("SetHDCPKey", data, (strHDCP.size() + 1) / (bHasSpace ? 3 : 2));
}

BOOL CSIACP::SCBC_SetHDCPKey(const byte *pBuffer, const int &nLen)
{
	return SendCommand("SetHDCPKey", pBuffer, nLen);
}

BOOL CSIACP::SCBC_SetHDCPKey22(std::string strHDCP22, BOOL bHasSpace /* = TRUE */)
{
	std::string data = HexString2Bytes(strHDCP22, bHasSpace ? 3 : 2);
	return SendCommand2("SetHDCPKey22", data, (strHDCP22.size() + 1) / (bHasSpace ? 3 : 2));
}

BOOL CSIACP::SCBC_SetHDCPKey22(const byte *pBuffer, const int &nLen)
{
	return SendCommand("SetHDCPKey22", pBuffer, nLen);
}

BOOL CSIACP::SCBC_SetNetflixESN(std::string strESN, BOOL bHasSpace /* = TRUE */)
{
	std::string data = HexString2Bytes(strESN, bHasSpace ? 3 : 2);
	return SendCommand2("SetNetflixESN", data, (strESN.size() + 1) / (bHasSpace ? 3 : 2));
}

BOOL CSIACP::SCBC_SetNetflixESN(const byte *pBuffer, const int &nLen)
{
	return SendCommand("SetNetflixESN", pBuffer, nLen);
}

BOOL CSIACP::SCBC_SetWidi(std::string strWidi, BOOL bHasSpace /* = TRUE */)
{
	std::string data = HexString2Bytes(strWidi, bHasSpace ? 3 : 2);
	return SendCommand2("SetWidi", data, (strWidi.size() + 1) / (bHasSpace ? 3 : 2));
}

BOOL CSIACP::SCBC_SetWidi(const byte *pBuffer, const int &nLen)
{
	return SendCommand("SetWidi", pBuffer, nLen);
}

BOOL CSIACP::SCBC_SetWidevine(std::string strWidevine, BOOL bHasSpace /* = TRUE */)
{
	std::string data = HexString2Bytes(strWidevine, bHasSpace ? 3 : 2);
	return SendCommand2("SetWidevine", data, (strWidevine.size() + 1) / (bHasSpace ? 3 : 2));
}

BOOL CSIACP::SCBC_SetWidevine(const byte *pBuffer, const int &nLen)
{
	return SendCommand("SetWidevine", pBuffer, nLen);
}

BOOL CSIACP::SCBC_SetCiKey(std::string strCiKey, BOOL bHasSpace /* = TRUE */)
{
	std::string data = HexString2Bytes(strCiKey, bHasSpace ? 3 : 2);
	return SendCommand2("SetCiKey", data, (strCiKey.size() + 1) / (bHasSpace ? 3 : 2));
}

BOOL CSIACP::SCBC_SetCiKey(const byte *pBuffer, const int &nLen)
{
	return SendCommand("SetCiKey", pBuffer, nLen);
}

BOOL CSIACP::SCBC_SetOSDLanguage(std::string lan, BOOL bHasSpace /* = TRUE */)
{
	std::string data = HexString2Bytes(lan, bHasSpace ? 3 : 2);
	return SendCommand2("SetOSDLanguage", data, data.size());
}

BOOL CSIACP::SCBC_SetOSDLanguage(const byte *pBuffer, const int &nLen)
{
	return SendCommand("SetOSDLanguage", pBuffer, nLen);
}

BOOL CSIACP::SCBC_SetShopLanguage(std::string lan, BOOL bHasSpace /* = TRUE */)
{
	std::string data = HexString2Bytes(lan, bHasSpace ? 3 : 2);
	return SendCommand2("SetShopLanguage", data, data.size());
}

BOOL CSIACP::SCBC_SetShopLanguage(const byte *pBuffer, const int &nLen)
{
	return SendCommand("SetShopLanguage", pBuffer, nLen);
}

BOOL CSIACP::SCBC_SetChannel(std::string channel, BOOL bHasSpace /* = TRUE */)
{
	std::string data = HexString2Bytes(channel, bHasSpace ? 3 : 2);
	return SendCommand2("SetChannel", data, data.size());
}

BOOL CSIACP::SCBC_SetChannel(const byte *pBuffer, const int &nLen)
{
	return SendCommand("SetChannel", pBuffer, nLen);
}

BOOL CSIACP::SCBC_SetWBNormal(std::string data)
{
	return SendCommand2("SetWBNormal", data, data.size());
}

BOOL CSIACP::SCBC_SetWBNormal(const byte *pBuffer, const int &nLen)
{
	return SendCommand("SetWBNormal", pBuffer, nLen);
}

BOOL CSIACP::SCBC_SetWBCool(std::string data)
{
	return SendCommand2("SetWBCool", data, data.size());
}

BOOL CSIACP::SCBC_SetWBCool(const byte *pBuffer, const int &nLen)
{
	return SendCommand("SetWBCool", pBuffer, nLen);
}

BOOL CSIACP::SCBC_SetWBWarm(std::string data)
{
	return SendCommand2("SetWBWarm", data, data.size());
}

BOOL CSIACP::SCBC_SetWBWarm(const byte *pBuffer, const int &nLen)
{
	return SendCommand("SetWBWarm", pBuffer, nLen);
}

BOOL CSIACP::SCBC_CheckDeviceId()
{
	BOOL bRet = SendCommand("CheckDeviceId");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		if (rtn.data.size() == 0)
		{
			return FALSE;
		}

		byte bydata = (byte)rtn.data.at(0);
		if (bydata == 0x03 || bydata == 0x02)
			return TRUE;
		else
			return FALSE;
	}

	return bRet;
}

BOOL CSIACP::SCBC_CheckMAC()
{
	BOOL bRet = SendCommand("CheckMAC");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		if (rtn.data.size() == 0)
		{
			return FALSE;
		}

		byte bydata = (byte)rtn.data.at(0);
		if (bydata == 0x03 || bydata == 0x01)
			return TRUE;
		else
			return FALSE;
	}

	return bRet;
}

BOOL CSIACP::SCBC_CheckHDCP()
{
	BOOL bRet = SendCommand("CheckHDCP");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		if (rtn.data.size() == 0)
		{
			return FALSE;
		}

		byte bydata = (byte)rtn.data.at(0);
		if (bydata == 0x01)
			return TRUE;
		else
			return FALSE;
	}

	return bRet;
}

BOOL CSIACP::SCBC_CheckHDCP22()
{
	BOOL bRet = SendCommand("CheckHDCP22");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		if (rtn.data.size() == 0)
		{
			return FALSE;
		}

		byte bydata = (byte)rtn.data.at(0);
		if (bydata == 0x01)
			return TRUE;
		else
			return FALSE;
	}

	return bRet;
}

BOOL CSIACP::SCBC_CheckNetflixESN()
{
	BOOL bRet = SendCommand("CheckNetflixESN");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		if (rtn.data.size() == 0)
		{
			return FALSE;
		}

		byte bydata = (byte)rtn.data.at(0);
		if (bydata == 0x01)
			return TRUE;
		else
			return FALSE;
	}

	return bRet;
}

BOOL CSIACP::SCBC_CheckWidi()
{
	BOOL bRet = SendCommand("CheckWidi");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		if (rtn.data.size() == 0)
		{
			return FALSE;
		}

		byte bydata = (byte)rtn.data.at(0);
		if (bydata == 0x01)
			return TRUE;
		else
			return FALSE;
	}

	return bRet;
}

BOOL CSIACP::SCBC_CheckWidevine()
{
	BOOL bRet = SendCommand("CheckWidevine");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		if (rtn.data.size() == 0)
		{
			return FALSE;
		}

		byte bydata = (byte)rtn.data.at(0);
		if (bydata == 0x01)
			return TRUE;
		else
			return FALSE;
	}

	return bRet;
}

BOOL CSIACP::SCBC_CheckCikey()
{
	BOOL bRet = SendCommand("CheckCikey");
	if (bRet)
	{
		if (m_vtdata.size() == 0)
		{
			LOG4C((LOG_WARN, "No data return!"));
			return FALSE;
		}

		RTN rtn = m_vtdata.at(0);
		if (rtn.data.size() == 0)
		{
			return FALSE;
		}

		byte bydata = (byte)rtn.data.at(0);
		if (bydata == 0x01)
			return TRUE;
		else
			return FALSE;
	}

	return bRet;
}

BOOL CSIACP::SCBC_StarWarmUpMode()
{
	return SendCommand("StarWarmUpMode");
}

BOOL CSIACP::SCBC_StopWarmUpMode()
{
	return SendCommand("StopWarmUpMode");
}

//////////////////////////////////////////////////////////////////////////
COTA::COTA()
{
	m_pMainDlg = nullptr;
	m_curl.Initialize();
}

COTA::~COTA()
{
}

void COTA::SetMainDlg(CDialogEx* p)
{
	m_pMainDlg = p;
}

void COTA::ShowMessage(LPCTSTR lpMsg, LOG_ENUM logtype)
{
	if (m_pMainDlg && lpMsg)
	{
		CTCLCopyToolDlg* pMainDlg = (CTCLCopyToolDlg*)m_pMainDlg;
		pMainDlg->SetOptionLog(std::string(lpMsg), logtype);
	}
}

BOOL COTA::HttpGet(std::string host, std::string context, std::string &result, DATATYPE dt)
{
	AUTOTIMING;
	//AutoTiming at(host+"；"+context);
	CharEncoding::ASCII2UTF8(context.c_str(), context);
	m_curl.SetHeaders("Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/x-silverlight, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocument, application/xaml+xml, */*");
	m_curl.SetHeaders("Accept-Language: zh-cn");
	if (dt == DATA_JSON)
		m_curl.SetHeaders("Content-Type: application/json;charset=utf-8");

	int nRecCode = CURLE_OK;
	if (_tcsstr(host.c_str(), "https://"))
		nRecCode = m_curl.Gets(host + context, result);
	else
		nRecCode = m_curl.Get(host + context, result);

	if (CURLE_OK != nRecCode)
		LOG4C((LOG_NOTICE, "请求失败：%s, 错误码=%ld", context.c_str(), nRecCode));

	return CURLE_OK == nRecCode;
}

BOOL COTA::HttpPost(std::string host, std::string context, std::string &result, DATATYPE dt)
{
	AUTOTIMING;
	CharEncoding::ASCII2UTF8(context.c_str(), context);
	m_curl.SetHeaders("Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/x-silverlight, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocument, application/xaml+xml, */*");
	m_curl.SetHeaders("Accept-Language: zh-cn");
	if (dt == DATA_JSON)
		m_curl.SetHeaders("Content-Type: application/json;charset=utf-8");

	int nRecCode = CURLE_OK;
	if (_tcsstr(host.c_str(), "https://"))
		nRecCode = m_curl.Posts(host, context, result);
	else
		nRecCode = m_curl.Posts(host, context, result);

	result = CharEncoding::DeCode_URLUTF8(result.c_str());

	if (CURLE_OK != nRecCode)
	{
		TCHAR szMsg[250] = {0};
		_stprintf_s(szMsg, _T("http request failed, curl error code = %d\r"), nRecCode);
		ShowMessage(szMsg);
		LOG4C((LOG_NOTICE, "请求失败：%s, 错误码=%ld\n", context.c_str(), nRecCode));
	}

	std::string api = host.substr(host.find_last_of('/') + 1);
#ifdef _DEBUG
	LOG4C((LOG_NOTSET, "\n地址：%s\n报文：%s\n结果：%s\n", host.c_str(), context.size() > 256 ? std::string(context.substr(0, 256) + (" ……")).c_str() : context.c_str(), result.c_str()));
#else
	LOG4C((LOG_NOTSET, "\n地址：%s\n报文：%s\n结果：%s\n", api.c_str(), context.size() > 256 ? std::string(context.substr(0, 256)+(" ……")).c_str() : context.c_str(), result.c_str()));
#endif
	return CURLE_OK == nRecCode;
}

BOOL COTA::GetMIDInfo(MIDInfo &mid, std::string bid, std::string strMacs, std::string iptvid, std::string version)
{
	AUTOTIMING;
	// Json数据;
	cJSON *pJson = cJSON_CreateObject();
	cJSON_AddStringToObject(pJson, "clientType", iptvid.c_str());
	cJSON_AddStringToObject(pJson, "version", version.c_str());
	cJSON_AddStringToObject(pJson, "mac", strMacs.c_str());
	cJSON_AddStringToObject(pJson, "bid", trim(bid).c_str());
	char *pJsonText = cJSON_Print(pJson);

	// post请求;
	std::string name, type;
	std::string host, result, context;
	context = pJsonText;

	if (pJsonText)
		delete pJsonText;
	pJsonText = NULL;
	cJSON_Delete(pJson);
	pJson = NULL;

	host = Global::g_bTestHost ? _T("http://test.admin.uc.qhmoka.com/scbc-server/clientType/getMessage.do") : _T("https://cn.uc.qhmoka.com/scbc-server/clientType/getMessage.do");
	BOOL bRet = HttpPost(host, context, result, DATA_JSON);
	if (!bRet)
	{
		LOG4C((LOG_WARN, "Post request failed！"));
		goto end;
	}

	// 解析返回值;
	pJson = cJSON_Parse(result.c_str());
	if (pJson == NULL)
	{
		bRet = FALSE;
		LOG4C((LOG_WARN, "JSON parsing failure：post=%s;return=%s\n", context.c_str(), result.c_str()));
		goto end;
	}

	mid.message = cJSON_GetObjectItem(pJson, "message") ? cJSON_GetObjectItem(pJson, "message")->valuestring : "";
	mid.code = cJSON_GetObjectItem(pJson, "code") ? cJSON_GetObjectItem(pJson, "code")->valuestring : "";
	mid.factoryname = cJSON_GetObjectItem(pJson, "factoryName") ? (cJSON_GetObjectItem(pJson, "factoryName")->valuestring != NULL ? cJSON_GetObjectItem(pJson, "factoryName")->valuestring : "") : "";
	mid.factoryNum = cJSON_GetObjectItem(pJson, "factoryNum") ? (cJSON_GetObjectItem(pJson, "factoryNum")->valuestring != NULL ? cJSON_GetObjectItem(pJson, "factoryNum")->valuestring : "") : "";
	mid.version = cJSON_GetObjectItem(pJson, "version") ? (cJSON_GetObjectItem(pJson, "version")->valuestring != NULL ? cJSON_GetObjectItem(pJson, "version")->valuestring : "") : "";
	mid.projectid = cJSON_GetObjectItem(pJson, "projectId") ? (cJSON_GetObjectItem(pJson, "projectId")->valuestring != NULL ? cJSON_GetObjectItem(pJson, "projectId")->valuestring : "") : "";
	mid.clienttype = cJSON_GetObjectItem(pJson, "clientType") ? (cJSON_GetObjectItem(pJson, "clientType")->valuestring != NULL ? cJSON_GetObjectItem(pJson, "clientType")->valuestring : "") : "";
	mid.host = cJSON_GetObjectItem(pJson, "host") ? (cJSON_GetObjectItem(pJson, "host")->valuestring != NULL ? cJSON_GetObjectItem(pJson, "host")->valuestring : "") : "";
	cJSON *pObj = cJSON_GetObjectItem(pJson, "obj");
	if (pObj == NULL)
	{
		bRet = FALSE;
		LOG4C((LOG_WARN, "JSON parsing failure：post=%s;return=%s\n", context.c_str(), result.c_str()));
		goto end;
	}

	if (_tcsicmp(mid.code.c_str(), "1000") != 0)
	{
		bRet = FALSE;
		LOG4C((LOG_WARN, "return invalid data：post=%s;return=%s\n", context.c_str(), result.c_str()));
		goto end;
	}

	if (mid.host.size() == 0)
	{
		bRet = FALSE;
		LOG4C((LOG_WARN, "return invalid data：post=%s;return=%s\n", context.c_str(), result.c_str()));
		goto end;
	}

	// 清空
	Global::g_AutoOnlineChassis = Global::CHASSIS();
	Global::g_AutoOnlineChassis.ProjectID = _ttoi(mid.projectid.c_str());
	Global::g_AutoOnlineChassis.url = mid.host;
	Global::g_AutoOnlineChassis.name = bid;

	mid.obj.clear();
	cJSON *pItem = NULL;
	int nSize = cJSON_GetArraySize(pObj);
	for (int i = 0; i < nSize; i++)
	{
		pItem = cJSON_GetArrayItem(pObj, i);
		if (pItem)
		{
			name = cJSON_GetObjectItem(pItem, "name") ? cJSON_GetObjectItem(pItem, "name")->valuestring : "";
			type = cJSON_GetObjectItem(pItem, "type") ? cJSON_GetObjectItem(pItem, "type")->valuestring : "";
			mid.obj.insert(pair<std::string, std::string>(name,type));

			if ( _tcsicmp(name.c_str(), _T("DeviceID")) == 0 )
			{
				Global::g_AutoOnlineChassis.IsCopyDID = true;
				Global::g_AutoOnlineChassis.ClientType = type;
				if (_tcsicmp(type.c_str(), _T("SCBC")) == 0 || _tcsicmp(type.c_str(), _T("新用户系统")) == 0)
					Global::g_AutoOnlineChassis.ClientType = "tcl_unknown_model";;
			}
			else if (_tcsicmp(name.c_str(), _T("MAC")) == 0)
			{
				Global::g_AutoOnlineChassis.IsCopyMAC = true;
				Global::g_AutoOnlineChassis.MACType = type;
			}
			else if (_tcsicmp(name.c_str(), _T("HDCP_KEY")) == 0)
			{
				Global::g_AutoOnlineChassis.IsCopyKEY = true;
				Global::g_AutoOnlineChassis.HDCPKeyType = type;
			}
			else if (_tcsicmp(name.c_str(), _T("CI_PLUS_KEY")) == 0)
			{
				Global::g_AutoOnlineChassis.IsCopyCikey = true;
				Global::g_AutoOnlineChassis.CIKeyType = type;
			}
			else if (_tcsicmp(name.c_str(), _T("WiDi")) == 0)
			{
				Global::g_AutoOnlineChassis.IsCopyWiDi = true;
				Global::g_AutoOnlineChassis.WiDiType = type;
			}
			else if (_tcsicmp(name.c_str(), _T("Widevine_KEY")) == 0)
			{
				Global::g_AutoOnlineChassis.IsCopyWidevine = true;
				Global::g_AutoOnlineChassis.WidevineType = type;
			}
			else if (_tcsicmp(name.c_str(), _T("HDCP2.2_KEY")) == 0)
			{
				Global::g_AutoOnlineChassis.IsCopyKEY2_2 = true;
				Global::g_AutoOnlineChassis.HDCPKey22Type = type;
			}
			else if (_tcsicmp(name.c_str(), _T("NETFILX_ESN")) == 0)
			{
				Global::g_AutoOnlineChassis.IsCopyESN = true;
				Global::g_AutoOnlineChassis.ESNType = type;
			}
		}
	}

	if ( mid.projectid.size() != 0 )
	{
		Global::g_AutoOnlineChassis.IsWritePID = true;
	}

	LOG4C((LOG_NOTSET, "post success：post=%s;return=%s\n", context.c_str(), result.c_str()));

end:
	// 释放Json;
	if (pJsonText)
		delete pJsonText;
	pJsonText = NULL;
	cJSON_Delete(pJson);

	if ( mid.factoryname.size() )
		UpgradeCheck(mid.factoryNum);

	if (!bRet)
	{
		std::map<std::string, std::string> report_data;
		report_data.insert(std::pair<std::string, std::string>("host", host));
		report_data.insert(std::pair<std::string, std::string>("context", context));
		report_data.insert(std::pair<std::string, std::string>("result", result));
		g_db.InsertReportInfo("GetMIDInfo", report_data);
	}

	return bRet;
}

BOOL COTA::GetKeyInfo(std::string host, std::string context, std::string keyname, std::string valuename, std::string &value)
{
	AUTOTIMING;
	std::string result;
	if (!HttpPost(host, context, result))
	{
		return FALSE;
	}

	// 无数据;
	if (result.size() == 0)
	{
		LOG4C((LOG_ERROR, "(http=%s) No data return!", context.c_str()));
		ShowMessage(_T("http No data return!\r"));
		return FALSE;
	}

	// 解析xml;
	tinyxml2::XMLDocument doc;
	if (tinyxml2::XML_SUCCESS != doc.Parse(result.c_str()))
	{
		LOG4C((LOG_ERROR, "(http=%s) this post return xml invalid!", context.c_str()));
		ShowMessage(_T("http return invalid xml data!\r"));
		return FALSE;
	}

	std::string code;
	std::string desc;
	tinyxml2::XMLElement *pXmlRoot = NULL;
	if ((pXmlRoot = doc.RootElement()) != NULL)
	{
		if (_tcsicmp(pXmlRoot->Value(), "response") == 0)
		{
			// 属性;
			const tinyxml2::XMLAttribute *pAttr = pXmlRoot->FirstAttribute();
			while (pAttr)
			{
				if (_tcsicmp(pAttr->Name(), "code") == 0)
				{
					code = pAttr->Value();
				}

				if (_tcsicmp(pAttr->Name(), "desc") == 0)
				{
					desc = pAttr->Value();
				}

				pAttr = pAttr->Next();
			}

			if (_tcsicmp(code.c_str(), "200") != 0)
			{
				LOG4C((LOG_ERROR, "(http=%s) Code is not equal to 200, desc=%s!", context.c_str(), desc.c_str()));
				TCHAR szMsg[250] = { 0 };
				_stprintf_s(szMsg, _T("http Code is not equal to 200, desc=%s\r"), desc.c_str());
				ShowMessage(szMsg);
				// 如果是上报接口，500表示成功;
				if (host.rfind("/report.do?") != std::string::npos && _tcsicmp(code.c_str(), "500") == 0)
					return TRUE;
				return FALSE;
			}

			if (keyname.size() == 0 || valuename.size() == 0)
				return TRUE;

			// 子项;
			std::string name; // std::string value;
			tinyxml2::XMLElement *pXmlElent = pXmlRoot->FirstChildElement();
			while (pXmlElent)
			{
				// 中文;
				CharEncoding::UTF82ASCII(pXmlElent->Value(), name);
				if (_tcsicmp(name.c_str(), keyname.c_str()) == 0)
				{
					pAttr = pXmlElent->FirstAttribute();
					while (pAttr)
					{
						if (_tcsicmp(pAttr->Name(), valuename.c_str()) == 0)
						{
							value = pAttr->Value();
							break;
						}
						pAttr = pAttr->Next();
					}

					break;
				}
				pXmlElent = pXmlElent->NextSiblingElement();
			}

			if (value.size() == 0)
			{
				LOG4C((LOG_ERROR, "(http=%s)xml value is empty!", context.c_str()));
				ShowMessage(_T("http xml value is empty!\r"));
				return FALSE;
			}
		}
	}

	return TRUE;
}

void COTA::UpgradeCheck(std::string factoryNum)
{
	AUTOTIMING;
	// 当前文件版本号、产品版本号;
	WORD sFileVersion[4] = {0};
	WORD sProductVerion[4] = {0};
	Global::GetVersion(Global::g_szCurModulePath, sFileVersion, sProductVerion);
	TCHAR szVersion[128] = {0};
	_stprintf_s(szVersion, _T("%d.%d.%d.%d"), sFileVersion[0], sFileVersion[1], sFileVersion[2], sFileVersion[3]);

	// Json数据;
	cJSON *pJson = cJSON_CreateObject();
	cJSON_AddStringToObject(pJson, "appid", "SCBC_Factory_Tools");
	cJSON_AddStringToObject(pJson, "devicemodel", "SCBC_Factory_Tools");
	cJSON_AddStringToObject(pJson, "dnum", factoryNum.c_str()); //工厂名;
	cJSON_AddStringToObject(pJson, "ver", szVersion);
	cJSON_AddStringToObject(pJson, "type", "pc");
	char *pJsonText = cJSON_Print(pJson);

	// post请求;
	std::string strHttpUrl, strResHttp, strContext, strErrCode, strErrValue, strCount;
	strContext = pJsonText;
	// 正式上线地址;
	strHttpUrl = _T("https://cn.ota.qhmoka.com/ota-services/upmp/upgradeInterfaceForPC");
	HttpPost(strHttpUrl.c_str(), pJsonText, strResHttp, DATA_JSON);

	// 释放Json;
	if (pJsonText)
		delete pJsonText;
	pJsonText = NULL;
	cJSON_Delete(pJson);
	pJson = NULL;

	if (strResHttp.size() == 0)
	{
		LOG4C((LOG_WARN, "返回结果空：post=%s;return=%s", strContext.c_str(), strResHttp.c_str()));
		ReportUpgrade(FALSE, szVersion, factoryNum);
		return;
	}

	// 将json结果转换成结构体;
	Global::__update_result__ upresult;
	pJson = cJSON_Parse(strResHttp.c_str());
	if (pJson == NULL)
	{
		cJSON_Delete(pJson);
		LOG4C((LOG_WARN, "cJSON解析时出错：post=%s;return=%s", strContext.c_str(), strResHttp.c_str()));
		ReportUpgrade(FALSE, szVersion, factoryNum);
		return;
	}
	upresult.servertime = cJSON_GetObjectItem(pJson, "servertime") ? cJSON_GetObjectItem(pJson, "servertime")->valuestring : "";
	upresult.callid = cJSON_GetObjectItem(pJson, "callid") ? cJSON_GetObjectItem(pJson, "callid")->valuestring : "";
	upresult.note = cJSON_GetObjectItem(pJson, "note") ? cJSON_GetObjectItem(pJson, "note")->valuestring : "";
	upresult.status = cJSON_GetObjectItem(pJson, "state") ? cJSON_GetObjectItem(pJson, "state")->valuestring : "";
	upresult.language = cJSON_GetObjectItem(pJson, "language") ? cJSON_GetObjectItem(pJson, "language")->valuestring : "";
	upresult.apiversion = cJSON_GetObjectItem(pJson, "apiversion") ? cJSON_GetObjectItem(pJson, "apiversion")->valuestring : "";
	cJSON *pUpdate = cJSON_GetObjectItem(pJson, "upgrade");
	if (pUpdate == NULL)
	{
		cJSON_Delete(pJson);
		LOG4C((LOG_WARN, "升级接口没有升级内容：post=%s;return=%s", strContext.c_str(), strResHttp.c_str()));
		//ReportUpdateResult(FALSE, strVer);
		return;
	}
	upresult.upcontent.now = cJSON_GetObjectItem(pUpdate, "now") ? cJSON_GetObjectItem(pUpdate, "now")->valuestring : "";
	upresult.upcontent.type = cJSON_GetObjectItem(pUpdate, "type") ? cJSON_GetObjectItem(pUpdate, "type")->valuestring : "";
	upresult.upcontent.appid = cJSON_GetObjectItem(pUpdate, "appid") ? cJSON_GetObjectItem(pUpdate, "appid")->valuestring : "";
	upresult.upcontent.apptype = cJSON_GetObjectItem(pUpdate, "apptype") ? cJSON_GetObjectItem(pUpdate, "apptype")->valuestring : "";
	upresult.upcontent.version = cJSON_GetObjectItem(pUpdate, "version") ? cJSON_GetObjectItem(pUpdate, "version")->valuestring : "";
	upresult.upcontent.verid = cJSON_GetObjectItem(pUpdate, "verid") ? cJSON_GetObjectItem(pUpdate, "verid")->valuestring : "";
	upresult.upcontent.md5 = cJSON_GetObjectItem(pUpdate, "md5") ? cJSON_GetObjectItem(pUpdate, "md5")->valuestring : "";
	upresult.upcontent.size = cJSON_GetObjectItem(pUpdate, "size") ? cJSON_GetObjectItem(pUpdate, "size")->valuestring : "";
	upresult.upcontent.minicon = cJSON_GetObjectItem(pUpdate, "minicon") ? cJSON_GetObjectItem(pUpdate, "minicon")->valuestring : "";
	upresult.upcontent.midicon = cJSON_GetObjectItem(pUpdate, "midicon") ? cJSON_GetObjectItem(pUpdate, "midicon")->valuestring : "";
	upresult.upcontent.fileurl = cJSON_GetObjectItem(pUpdate, "fileurl") ? cJSON_GetObjectItem(pUpdate, "fileurl")->valuestring : "";
	upresult.upcontent.increment = cJSON_GetObjectItem(pUpdate, "increment") ? cJSON_GetObjectItem(pUpdate, "increment")->valuestring : "";
	upresult.upcontent.appendver = cJSON_GetObjectItem(pUpdate, "appendver") ? cJSON_GetObjectItem(pUpdate, "appendver")->valuestring : "";
	upresult.upcontent.updatetime = cJSON_GetObjectItem(pUpdate, "updatetime") ? cJSON_GetObjectItem(pUpdate, "updatetime")->valuestring : "";
	// 释放cJSON资源;
	cJSON_Delete(pJson);
	pJson = NULL;

	if (upresult.status.compare("0000") != 0)
	{
		LOG4C((LOG_WARN, "升级接口http返回出错：post=%s;return=%s", strContext.c_str(), strResHttp.c_str()));
		ReportUpgrade(FALSE, szVersion, factoryNum);
		return;
	}

	// 下载文件;
	TCHAR szNewPath[MAX_PATH] = {0};
	_stprintf_s(szNewPath, _T("%s%s.exe"), Global::g_szCurModuleDir, upresult.upcontent.version.c_str());
	if (_tcsicmp(szVersion , upresult.upcontent.version.c_str()) > 0 )
	{
		LOG4C((LOG_NOTICE, "当前版本(%s)比服务器版本(%s)新", szVersion, upresult.upcontent.version.c_str()));
		return;
	}

	if (MessageBox(NULL, _T("found out lastest software version, you have to update."), _T("Tips"), MB_YESNO | MB_TOPMOST | MB_ICONINFORMATION) == IDNO)
		return;

	// 保存成文件;
	if (!DownloadFile(upresult.upcontent.fileurl, szNewPath))
	{
		LOG4C((LOG_NOTICE, "下载升级文件失败"));
		MessageBox(NULL, _T("Download failure."), _T("Tips"), MB_OK | MB_TOPMOST | MB_ICONINFORMATION);
		ReportUpgrade(FALSE, szVersion, factoryNum);
		return;
	}
	else
	{
		ReportUpgrade(TRUE, szVersion, factoryNum);
	}

	Sleep(500);

	MessageBox(NULL, _T("Complete the download, you need restart apps."), _T("Tips"), MB_OK | MB_TOPMOST | MB_ICONINFORMATION);

	// 启动程序;
	::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); //某些情况下要初始化COM才能使用ShellExecuteEx;
	SHELLEXECUTEINFO stuExecInfo = {0};
	CString strParamters;
	strParamters.Format(_T("--pid %ld --oldpath \"%s\" --newpath \"%s\" --killproc 1"), GetCurrentProcessId(), Global::g_szCurModulePath, szNewPath);
	//strParamters.Format(_T("--pid %ld --oldpath \"%s\" --newpath \"%s\" --killproc 0"), GetCurrentProcessId(), g_szCurModulePath, szNewPath);
	stuExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
	stuExecInfo.lpFile = _T("rename.exe");
	stuExecInfo.nShow = SW_HIDE;
	stuExecInfo.lpParameters = strParamters;
	stuExecInfo.lpVerb = _T("open");
	stuExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI;

	if (!ShellExecuteEx(&stuExecInfo))
	{
		DWORD dwError = GetLastError();
		LOG4C((LOG_ERROR, "执行rename程序失败，错误码=%d", dwError));
		MessageBox(NULL, _T("Upgrade failure."), _T("Tips"), MB_OK | MB_TOPMOST | MB_ICONINFORMATION);
		return;
	}

	HANDLE hProcess = stuExecInfo.hProcess;
	if (hProcess != NULL)
		CloseHandle(hProcess);
	else
		LOG4C((LOG_WARN, "执行rename程序失败，进程句柄空"));

	// 提示升级程序执行;
	LOG4C((LOG_NOTICE, "后台升级程序执行成功，程序退出后自动覆盖文件"));
}

void COTA::ReportUpgrade(BOOL bUpgrade, std::string ver, std::string num)
{
	AUTOTIMING;
	// Json数据;
	cJSON *pJson = cJSON_CreateObject();
	cJSON_AddStringToObject(pJson, "appid", "SCBC_Factory_Tools");
	cJSON_AddStringToObject(pJson, "devmodel", "SCBC_Factory_Tools");
	cJSON_AddStringToObject(pJson, "dnum", num.c_str());
	cJSON_AddStringToObject(pJson, "ver", ver.c_str());
	cJSON_AddStringToObject(pJson, "result", bUpgrade ? "Success" : "FAILURE");
	cJSON_AddStringToObject(pJson, "type", "pc");
	char *pJsonText = cJSON_Print(pJson);

	// post请求;
	std::string strHttpUrl, strResHttp, strContext, strErrCode, strErrValue, strCount;
	strContext = pJsonText;
	strHttpUrl = _T("https://cn.ota.qhmoka.com/ota-services/upmp/operateInterfaceForPC");
	HttpPost(strHttpUrl.c_str(), strContext.c_str(), strResHttp, DATA_JSON);

	// 释放Json;
	if (pJsonText)
		delete pJsonText;
	pJsonText = NULL;
	cJSON_Delete(pJson);
	pJson = NULL;

	pJson = cJSON_Parse(strResHttp.c_str());
	if (pJson == NULL)
	{
		LOG4C((LOG_WARN, "解析JSON失败：post=%s;return=%s", strContext.c_str(), strResHttp.c_str()));
		return;
	}

	std::string result = cJSON_GetObjectItem(pJson, "state") ? cJSON_GetObjectItem(pJson, "state")->valuestring : "";
	cJSON_Delete(pJson);
	pJson = NULL;
}

BOOL COTA::DownloadFile(std::string url, std::string savePath)
{
	AUTOTIMING;
	std::string result;
	if (HttpGet(url, "", result))
	{
		FILE* pf = nullptr;
		if (fopen_s(&pf, savePath.c_str(), "wb") == 0 )
		{
			if ( pf )
			{
				fwrite(result.data(), result.size(), 1, pf);
				fclose(pf);
				return TRUE;
			}
		}
	}

	return FALSE;
}

BOOL COTA::ReportLog(TReportData& repdata)
{
	AUTOTIMING;
	// Json数据;
	cJSON* pJson = cJSON_CreateObject();
	cJSON_AddStringToObject(pJson, "reportType", repdata.report_type.c_str());

	cJSON *pObj = cJSON_AddObjectToObject(pJson, _T("reportData"));
	for ( auto it : repdata.report_data)
	{
		cJSON_AddStringToObject(pObj, it.first.c_str(), it.second.c_str());
	}
	
	char* pJsonText = cJSON_Print(pJson);

	// post请求;
	std::string strHttpUrl, strResHttp, strContext;
	strContext = pJsonText;
	strHttpUrl = _T("https://cn.ota.qhmoka.com/ota-services/upmp/reportToolsLog.do");
	HttpPost(strHttpUrl.c_str(), strContext.c_str(), strResHttp, DATA_JSON);

	// 释放Json;
	if (pJsonText)
		delete pJsonText;
	pJsonText = NULL;
	cJSON_Delete(pJson);
	pJson = NULL;

	pJson = cJSON_Parse(strResHttp.c_str());
	if (pJson == NULL)
	{
		LOG4C((LOG_WARN, "解析JSON失败：post=%s;return=%s", strContext.c_str(), strResHttp.c_str()));
		return FALSE;
	}

	std::string result = cJSON_GetObjectItem(pJson, "code") ? cJSON_GetObjectItem(pJson, "code")->valuestring : "";
	cJSON_Delete(pJson);
	pJson = NULL;
	if ( _tcsicmp(result.c_str(), _T("200")) == 0 )
	{
		return TRUE;
	}

	return FALSE;
}

BOOL COTA::GetVCode(std::string mac, std::string& vcode)
{
	std::string result;
	std::string host = _T("http://test.admin.ota.qhmoka.com/IDManage/export/getvcode.do?");
	std::string context = _T("macAddress=");
	context.append(mac);
	if (!HttpPost(host, context, result))
		return FALSE;

	// 无数据;
	if (result.size() == 0)
	{
		LOG4C((LOG_ERROR, "(http=%s) No data return!", context.c_str()));
		return FALSE;
	}

	// 解析xml;
	tinyxml2::XMLDocument doc;
	if (tinyxml2::XML_SUCCESS != doc.Parse(result.c_str()))
	{
		LOG4C((LOG_ERROR, "(http=%s) this post return xml invalid!", context.c_str()));
		return FALSE;
	}
}
