#include <iostream>
#include "deviceBase.h"

using namespace std;

#define DATA_HEAD          (0x40) // 数据头

//控制设备类型
// device_TYPE
#define DEVICE_TYPE_ID        (0x05) // 煤气炮

// 命令类型
// msgId
#define MSG_ID_COMMAND  (0x08) //命令
#define MSG_ID_INQUIRE  (0x04) //查询
#define MSG_ID_DEPLOY   (0x03) //配置
#define MSG_ID_COMMAND_ACK      (0X09) //命令应答
#define MSG_ID_INQUIRE_ACK   (0X0A) //查询应答
#define MSG_ID_DEPLOY_ACK    (0x0b) //配置应答

//data
#define DATA_FIRE               (0x55)//开启
#define DATA_STOP               (0xAA)//停止
#define DATA_INQUIRE            (0xAB)//查询监控数据


class deviceGasV2:public deviceBase
{
    private:
        enum RECV_STEP{
            STEP_HEAD = 0,
            STEP_1 = 1,
            STEP_2 = 2,
            STEP_TYPE = 3,
            STEP_ADDR = 4,
            STEP_COM = 5,
            STEP_ACK = 6,
            STEP_STA = 7,
            STEP_DATA = 8,
            STEP_RLC = 9
        };

        typedef struct {
            uint8_t dataCount;
            uint8_t dataLength;
            uint8_t dataCheckSum;
            uint8_t data[40];
            enum RECV_STEP step = STEP_HEAD;
        }ExpelComm;

        ExpelComm _comm;

    public:
        deviceGasV2():deviceBase(){
            this->setDeviceToken(serial);
            this->setDeviceInfo("兰州中川机场 煤气炮驱动板协议");
            this->setBaudRate(38400);
        }
    public:
        // 电压
        float voltage = 0;
        // 气压
        float pressure = 0;
        // 状态
        int state = 0;
        // 纬度
        float latitude = 0;
        // 经度
        float longitude = 0;
        
        // LRC校验
        static unsigned char LRC_check(unsigned char *pSendBuf,unsigned char num)
        {
            char bylrc = 0,i = 0;
            
            for(i = 0; i < num; i++)
            {
                bylrc += pSendBuf[i];
            }
            bylrc = ~bylrc;
            bylrc++;

            return bylrc;
        }

        static void serialization(const GasV1Control gasV1Control,char *data){
            data[0] =  DATA_HEAD;
            data[1] =  0x23;
            data[2] =  0x24;
            data[3] = DEVICE_TYPE_ID;
            data[4] = gasV1Control.deviceId;
            data[5] = gasV1Control.msgId;
            data[6] = gasV1Control.data;
            if(gasV1Control.msgId == MSG_ID_COMMAND){
                data[7] = 0xb3;
                data[8] = 0xff;
            }else if(gasV1Control.msgId == MSG_ID_INQUIRE){
                data[7] = 0xAA;
                data[8] = 0xAA;
            }
            data[9] = LRC_check((unsigned char *)data, 9);
        }
        bool deserialization()
        {
            return true;
        }

        bool Consumer(uint8_t *data, int len, int &msg_id)
        {
            bool ReceiveSuccessful = false;
            if(this->Type != 1 && len > 0) return true;
            for (int i = 0; i < len; i++)
            {
                switch(_comm.step){
                    case STEP_HEAD:
                        if(data[i] == DATA_HEAD){
                            _comm.data[0] = DATA_HEAD;
                            _comm.step = STEP_1;
                        }
                        break;
                    case STEP_1:
                        if(data[i] == 0x23){
                            _comm.data[1] = data[i];
                            _comm.step = STEP_2;
                        }
                        break;
                    case STEP_2:
                        if(data[i] == 0x24){
                            _comm.data[2] = data[i];
                            _comm.step = STEP_TYPE;
                        }
                        break; 
                    case STEP_TYPE:
                        _comm.data[3] = data[i];
                        _comm.step = STEP_ADDR;
                        break;
                    case STEP_ADDR:
                        _comm.data[4] = data[i];
                        _comm.step = STEP_COM;
                        break;
                    case STEP_COM:
                        _comm.data[5] = data[i];
                        _comm.step = STEP_ACK;
                        break;
                    case STEP_ACK:
                        _comm.data[6] = data[i];
                        _comm.step = STEP_STA;
                        break;
                    case STEP_STA:
                        _comm.data[7] = data[i];
                        _comm.step = STEP_DATA;
                        _comm.dataCount = 8;
                        break;
                    case STEP_DATA:
                        _comm.data[_comm.dataCount++] = data[i];
                        if(_comm.dataCount == 40){
                            ReceiveSuccessful = true;
                            _comm.step = STEP_HEAD;
                        }
                        break;
                    default:
                        _comm.step = STEP_HEAD;
                        break;   
                }
            }
            if(!ReceiveSuccessful) return false;
            return deserialization(_comm.data, _comm.dataCount, msg_id);
        }

        bool deserialization(const uint8_t *data, int len, int &msg_id){
            if(data[0] != DATA_HEAD && data[1] != 0x23 && data[2] != 0x24 && data[3] != DEVICE_TYPE_ID) return false;
            if(deviceGasV2::LRC_check((unsigned char *)data, len - 1) != data[len - 1]) return false;
            setDeviceId(std::to_string(data[4]));
            if(data[5] == 0x00){
                msg_id = data[6];
                switch (msg_id)
                {
                // 命令应答
                case MSG_ID_COMMAND_ACK:
                    break;
                // 查询应答
                case MSG_ID_INQUIRE_ACK:
                    this->voltage = (float)data[8] + (float)(data[9]/100);
                    this->pressure = (float)data[10] + (float)(data[11]/100);
                    this->state = data[12];
                    break;
                // 配置应答
                case MSG_ID_DEPLOY_ACK:
                    break;
                }
                return true;
            }
            return false;
        }

        /**
         * @description: 打开
         * @param {int} deivceId
         * @return {*}
         */    
        int32_t Open(std::string DeviceId, uint8_t* data, int& length){
            GasV1Control gasControl;
            gasControl.deviceId = atoi(DeviceId.c_str());
            gasControl.msgId = 0x00;
            gasControl.data = 0x00;
            length = 11;
            serialization(gasControl, (char *)data);
            return 0;
        }

        /**
         * @description: 关闭
         * @param {int} deivceId
         * @return {*}
         */    
        int32_t Close(std::string DeviceId, uint8_t* data, int& length){
            GasV1Control gasControl;
            gasControl.deviceId = atoi(DeviceId.c_str());
            gasControl.msgId = MSG_ID_COMMAND;
            gasControl.data = DATA_STOP;
            length = 11;
            serialization(gasControl, (char *)data);
            return 0;
        }

        /**
         * @description: 开炮
         * @param {int} deivceId
         * @return {*}
         */    
        int32_t Fire(std::string DeviceId, uint8_t* data, int& length){
            GasV1Control gasControl;
            gasControl.deviceId = atoi(DeviceId.c_str());
            gasControl.msgId = MSG_ID_COMMAND;
            gasControl.data = DATA_FIRE;
            length = 11;
            serialization(gasControl, (char *)data);
            return 0;
        }

        /**
         * @description: 状态
         * @param {int} deivceId
         * @return {*}
         */    
        int32_t Status(std::string DeviceId, uint8_t* data, int& length){
            GasV1Control gasControl;
            gasControl.deviceId = atoi(DeviceId.c_str());
            gasControl.msgId = MSG_ID_INQUIRE;
            gasControl.data = DATA_INQUIRE;
            length = 11;
            serialization(gasControl, (char *)data);
            return 0;
        }

        /**
         * @description: 判定msg是否为status
         * @param {int} &msg_id
         * @return {*}
         */    
        bool getStatusMsg(int &msg_id){
            if(msg_id != MSG_ID_INQUIRE_ACK) return false;
            return true;
        }
    
        /**
         * @description: 构建设备信息
         * @param {SendDevice&} sendDevice
         * @return {*}
         */    
        void BuildDeviceInfo(SendDevice& sendDevice){
            sendDevice.deviceId = atoi(this->getDeviceId().c_str());
            sendDevice.commandCode = "1";
            sendDevice.status = 1;
            sendDevice.workStatus = 1;
            sendDevice.powerStatus = 1;
            sendDevice.batteryStatus = 1;
            sendDevice.num  = 0;
            sendDevice.oxyPressure  = 0;
            sendDevice.gasPressure  = 0;
            sendDevice.remark = "";
            sendDevice.attr1 = std::to_string(this->voltage);     // 电压
            sendDevice.attr2 = std::to_string(this->pressure);     // 声压
        }
};