#include "logic.h"
#include "CoatVolumeSensor.h"
#include <array>
#define  MAX_COMMAND_LEN 16
CCoatVolumeSensor::CCoatVolumeSensor(const QString& name,int32_t id)
	: CDriverCard(name, id)
{
	m_pSerialPort = new CMSerialPort(QString("COMPORT"), 0);

	//皮重
	m_Variants.add_Variant(Var_CoatVolume_TareValue,
		QObject::trUtf8("GlueTareValue"),double(0),false,
		Variant::TOXML);

	//密度
	m_Variants.add_Variant(Var_CoatVolume_GlueDensity,
		QObject::trUtf8("GlueDensity"),double(1),false,
		Variant::TOXML);

	//报警阈值
	m_Variants.add_Variant(Var_CoatVolume_AlarmVolume,
		QObject::trUtf8("GlueAlarmVolume"),double(1),false,
		Variant::TOXML);

	//提醒阈值
	m_Variants.add_Variant(Var_CoatVolume_WarningVolume,
		QObject::trUtf8("GlueWarningVolume"),double(1),false,
		Variant::TOXML);

	//失效日期 日
	m_Variants.add_Variant(Var_CoatVolume_ReplaceDate,
		QObject::trUtf8("LastReplaceDate"),(QString)QDate::currentDate().toString("yyyy-MM-dd"),false,
		Variant::TOXML);

	//失效天数
	m_Variants.add_Variant(Var_CoatVolume_InvalidDays,
		QObject::trUtf8("InvalidDays"),int(30),false,
		Variant::TOXML);

	//报警阈值
	m_Variants.add_Variant(Var_CoatVolume_AlarmDiffVolume, 
		QObject::trUtf8("AlarmDiffVolume"),double(10),false,
		Variant::TOXML);

	m_dGrams = 0;
}

CCoatVolumeSensor::~CCoatVolumeSensor(void)
{
	delete m_pSerialPort;
}

void CCoatVolumeSensor::do_msg(int iID,QVariantList& vlInput,V_MsgOutput* pvlOutput)
{
	Q_UNUSED(vlInput);
	Q_UNUSED(pvlOutput);
	if(iID == MeasureVolume)	
	{
		ReadGrams();
	}
	else if (iID == MSG_ZeroSensor)
	{
		ZeroSensor();
	}
}

int CCoatVolumeSensor::ReadConfig(QDomElement &root)
{
	int iIndex = CDriverCard::ReadConfig(root);

	QDomNodeList List=root.childNodes();
	//int iSizeList=List.size();

	iIndex = m_pSerialPort->ReadConfig(List.at(iIndex).toElement());

	return iIndex;
}
QDomElement CCoatVolumeSensor::WriteConfig(QDomDocument &doc, QDomElement &root)
{
	//QString rootInfo = root.text();
	QDomElement element = CDriverCard::WriteConfig(doc, root);
	//HACK:如果m_pSerialPort.m_sName 为空则不会保存
	QDomElement ele1 = m_pSerialPort->WriteConfig(doc, element);
	//QString parent = element.text();
	//QString info = ele1.text();
	//element.appendChild(ele1);

	return element;
}

int32_t CCoatVolumeSensor::init_driver()
{

    if (!m_gSystem.IsSimulator()) {
        m_pSerialPort->open();
    }

    //ReadGrams();
	return CDriverCard::init_driver();
}

int32_t CCoatVolumeSensor::exit_driver()
{
	m_pSerialPort->close();
	return CDriverCard::init_driver();
}

bool CCoatVolumeSensor::ReadGrams(int times/*=1*/)
{
    if (m_gSystem.IsSimulator()) {
        m_dGrams = 700;
        return true;
    }
	//unsigned char pResponse[MAX_COMMAND_LEN]={0};
	std::array<byte, MAX_COMMAND_LEN> pResponse = { 0 };
	while(times>0){
		
		int sendLength = 8;
		std::array<byte, 8> sendBuff = {0x01, 0x03, 0x00, 0x50, 0x00, 0x02, 0xC4, 0x1A};
	
		//测试CRC校验
		//byte sendBuff1[9] = {0x01, 0x03, 0x04, 0x00, 0x00, 0x0D, 0x4B, 0xBE, 0x94};
		//unsigned short crc=CRC16(sendBuff1, 7);
		//CheckResponse(sendBuff1, 9);
		//byte low = crc;
		//byte high = crc>>8;
		try{
			QMutexLocker locker(&m_CardMutex);
			LogRecord(fmt::format("send:{}", (char*)sendBuff.data()));
			m_pSerialPort->send((char*)sendBuff.data(), sendBuff.size());

			int irtn = m_pSerialPort->wait();
			m_pSerialPort->receive((char*)pResponse.data(),irtn);
			LogRecord(fmt::format("receive:{}", (char*)sendBuff.data()));
			locker.unlock();
		}catch(const QString& ex){

			LogRecord(ex.toLocal8Bit().data());
			//处理通信异常时，不直接抛出，做times次尝试
			if(times<=0){
				MQT_THROW_CODESTR(ALARM_WEIGHT_SENSOR_COMMNUNICATION, ex);
			}else{
				times--;
				continue;
			}
		}
		
		times--;
		//返回值示例 {0x01, 0x03, 0x04, 0x00, 0x00, 0x0D, 0x4B, 0xBE, 0x94}
		//其中 0x0D 0x4B 是读取值，以g为单位 10进制为3403克
		int recvLength = 9;
		if(false == CheckResponse(pResponse.data(), recvLength))
		{
			if(times<=0){
				LogRecord("error: command response error");
				MQT_THROW_CODESTR(ALARM_WEIGHT_SENSOR_COMMNUNICATION, (QObject::trUtf8("Send command response error. Driver:%1 Command:%2 Response:%3")
					.arg(m_sName).arg((char*)sendBuff.data()).arg((char*)pResponse.data())));

				return false;
			}else{
				//重试一次
				continue;
			}
		}else
		{
			//通信成功了直接返回
			break;
		}
	}

	int totalGrams = (pResponse[3] << 24) ^ (pResponse[4] << 16) ^ (pResponse[5] << 8) ^ pResponse[6];

	double density = m_Variants.get_VData(Var_CoatVolume_GlueDensity)->toDouble();
	double tarValue = m_Variants.get_VData(Var_CoatVolume_TareValue)->toDouble();
	totalGrams -= tarValue;
	m_dGrams = totalGrams*density;

	LogRecord(fmt::format("data:{}", m_dGrams));
	return true;
	
}

//传感器归零
bool CCoatVolumeSensor::ZeroSensor()
{
	QMutexLocker locker(&m_CardMutex);
	int sendLength = 11;
	byte sendBuff[11] = {0x01, 0x10, 0x00, 0x5E, 0x00, 0x01, 0x02, 0x00, 0x01, 0x6A, 0xEE};
	m_pSerialPort->send((char*)sendBuff,sendLength);

	int irtn = m_pSerialPort->wait();

	unsigned char pResponse[MAX_COMMAND_LEN]={0};
	m_pSerialPort->receive((char*)pResponse,irtn);

	//返回值示例 {0x01, 0x03, 0x04, 0x00, 0x00, 0x0D, 0x4B, 0xBE, 0x94}
	//其中 0x0D 0x4B 是读取值，以g为单位 10进制为3403克
	int recvLength = 8;
	if(false == CheckResponse((byte*)pResponse, recvLength))
	{
		MQT_THROW_CODESTR(ALARM_WEIGHT_SENSOR_COMMNUNICATION, (QObject::trUtf8("Send command response error. Driver:%1 Command:%2 Response:%3")
			.arg(m_sName).arg((char*)sendBuff).arg((char*)pResponse)));

		return false;
	}

	return true;
}

unsigned short CCoatVolumeSensor::CRC16(byte* pDataIn, int iLenIn)
{
	byte buf;
	unsigned short crc16 = 0xFFFF;
	static const unsigned short crc16Table[] =
	{
		0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
		0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
		0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
		0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
		0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
		0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
		0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
		0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
		0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
		0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
		0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
		0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
		0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
		0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
		0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
		0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
		0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
		0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
		0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
		0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
		0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
		0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
		0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
		0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
		0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
		0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
		0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
		0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
		0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
		0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
		0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
		0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
	};

	for ( auto i = 0; i < iLenIn; ++i )
	{
		buf = pDataIn[i]^crc16;
		crc16 >>= 8;
		crc16 ^= crc16Table[ buf ];
	}
	return (crc16);
}

bool CCoatVolumeSensor::CheckResponse(byte *pResponse, int recvLength)
{
	unsigned short crc=CRC16((byte*)pResponse,recvLength-2);
	if(pResponse[recvLength-2]==(byte)crc
		&& pResponse[recvLength-1]==(crc>>8))
	{
		return true;
	}

	return false;
}


