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

using namespace std;


// 超声波驱鸟炮
#define EXPEL_WRITE             (0x15)
#define EXPEL_READ              (0x05)

#define EXPEL_POWER_OFF         (0)
#define EXPEL_POWER_ON          (1<<7)
#define EXPEL_PLAY_DISPEL       (1<<6)
#define EXPEL_TURN_OFF_DISPEL   (0)
#define EXPEL_NOT_FIRE          (0)
#define EXPEL_SINGLE_FIRE       (1<<4)
#define EXPEL_BURST_FIRE        (2<<4)
#define EXPEL_TURN_LEFT_CANCEL  (0)
#define EXPEL_TURN_LEFT_ENABLE  (1<<3)
#define EXPEL_TURN_RIGHT_CANCEL (0)
#define EXPEL_TURN_RIGHT_ENABLE (1<<2)
#define EXPEL_TURN_UP_CANCEL    (0)
#define EXPEL_TURN_UP_ENABLE    (1<<1)
#define EXPEL_TURN_DOWN_CANCEL  (0)
#define EXPEL_TURN_DOWM_ENABLE  (1)

#define EXPEL_STAUS_ACK  0x05


typedef struct{
    int deviceId;
    uint8_t cmd;
}UltControl;


class deviceUlt:public deviceBase
{
private:
    uint8_t pressure;
    uint8_t commamd;
    int16_t current;
    uint16_t voltage;

    enum RECV_STEP{
        STEP_HEAD = 0,
        STEP_ADDR = 1,
        STEP_LEN = 2,
        STEP_DIR = 3,
        STEP_DATA = 4
    };

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

    ExpelComm _comm;
public:
    deviceUlt():deviceBase()
    {
        this->setDeviceToken(serial);
        this->setDeviceInfo("北京首都机场 民航大板协议");
        this->setBaudRate(115200);
    }
    ~deviceUlt(){}

    void serialization(){}
    bool deserialization(){
        return true;
    }

    void setPressure(uint8_t Pressure){
        pressure = Pressure;
    }
    void setCommamd(uint8_t Commamd){
        commamd = Commamd;
    }
    void setCurrent(int16_t Current){
        current = Current;
    }
    void setVoltage(uint16_t Voltage){
        voltage = Voltage;
    }

    uint8_t getPressure(){
       return pressure;
    }
    uint8_t getCommamd(){
       return commamd;
    }
    int16_t getCurrent(){
        return current;
    }
    uint16_t getVoltage(){
        return voltage;
    }

    static void serialization(UltControl ultControl, char *data, bool status = false){
        data[0] = 0xaa;
        data[1] = (uint8_t)ultControl.deviceId;
        data[2] = 0x06;
        if(status) data[3] = 0x05;
        else data[3] = 0x15;
        data[4] = ultControl.cmd;
        data[5] = 0;

        for (int i = 0; i < 5; i++) {
            data[5] += data[i];
        }
    }

    bool deserialization(const uint8_t *data, int len, int &msg_id){
        if(data[0] != 0xbb){
            return false;
        }
        uint8_t dataCheckSum = 0;
        for(int i = 0; i < len - 1; i++){
            dataCheckSum += data[i];
        }
        if(dataCheckSum != data[len - 1]){
            return false;
        }
        msg_id = data[3];
        if(msg_id == EXPEL_STAUS_ACK){
            this->setDeviceId(to_string(data[1]));
            this->pressure = (data[9]&0x80) >> 7;
            this->commamd = (data[4]);
            this->current = (int16_t)(data[8]<<8 || data[7]);
            this->voltage = uint16_t(data[6]<<8 || data[5]);
        }
        
        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] == 0xbb){
                        _comm.data[0] = 0xbb;
                        _comm.step = STEP_ADDR;
                    }
                    break;
                case STEP_ADDR:
                    _comm.data[1] = data[i];
                    _comm.step = STEP_LEN;
                    break;
                case STEP_LEN:
                    if (data[i] == 0x0B) {
                        _comm.data[2] = 0x0B;
                        _comm.dataLength = 0x0B;
                        _comm.step = STEP_DIR;
                    } else {
                        _comm.step = STEP_HEAD;
                    }
                    break; 
                case STEP_DIR:
                    if (data[i] == 0x05) {
                        _comm.data[3] = 0x05;
                        _comm.step = STEP_DATA;
                        _comm.dataCount = 4;
                    } else {
                        _comm.step = STEP_HEAD;
                    }
                    break;
                case STEP_DATA:
                    _comm.data[_comm.dataCount++] = data[i];
                    if(_comm.dataCount == _comm.dataLength){
                        ReceiveSuccessful = true;
                        _comm.step = STEP_HEAD;
                    }
                    break;
                default:
                    _comm.step = STEP_HEAD;
                    break;   
            }
        }
        if(!ReceiveSuccessful) {
            return false;
        }
        return deserialization(_comm.data, _comm.dataLength, msg_id);
    }

    /**
     * @description: 打开
     * @param {int} deivceId
     * @return {*}
     */    
    int32_t Open(std::string DeviceId, uint8_t* data, int& length){
        UltControl ultControl;
        ultControl.deviceId = std::atoi(DeviceId.c_str());
        ultControl.cmd = EXPEL_POWER_ON | EXPEL_PLAY_DISPEL | EXPEL_BURST_FIRE;
        length = 6;
        serialization(ultControl, (char*)data);

        return 0;
    }

    /**
     * @description: 关闭
     * @param {int} deivceId
     * @return {*}
     */    
    int32_t Close(std::string DeviceId, uint8_t* data, int& length){
        UltControl ultControl;
        ultControl.deviceId = std::atoi(DeviceId.c_str());
        ultControl.cmd = EXPEL_POWER_OFF | EXPEL_TURN_OFF_DISPEL | EXPEL_NOT_FIRE;
        length = 6;
        serialization(ultControl, (char*)data);
        return 0;
    }

    /**
     * @description: 开炮
     * @param {int} deivceId
     * @return {*}
     */    
    int32_t Fire(std::string DeviceId, uint8_t* data, int& length){
        return Open(DeviceId, data, length);
    }

    /**
     * @description: 状态
     * @param {int} deivceId
     * @return {*}
     */    
    int32_t Status(std::string DeviceId, uint8_t* data, int& length){
        UltControl ultControl;
        ultControl.deviceId = std::atoi(DeviceId.c_str());
        ultControl.cmd = 0;
        length = 6;
        bool staus = true;
        serialization(ultControl, (char*)data, staus);
        return 0;
    }

    /**
     * @description: 判定msg是否为status
     * @param {int} &msg_id
     * @return {*}
     */    
    bool getStatusMsg(int &msg_id){
        if(msg_id != EXPEL_STAUS_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->getVoltage());     // 电压
        sendDevice.attr2 = std::to_string(this->getCurrent());     // 电流
        sendDevice.attr3 = std::to_string(this->getPressure());    // 声压
    }
};


