#include "can_cali.h"
#include "can_id_deal.h"
#include "utils.h"
#include <stdint.h>

enum
{
    cal_ram = 0,
    cal_eeprom,
    cal_io,
};

enum
{
    read_cal = 0,
    write_cal,
};

enum
{
    cali_data_len_32bit = 0,
    cali_data_len_16bit,
    cali_data_len_8bit,
    cali_data_len_1bit,
    cali_data_len_32bit_float,
};

typedef union cali_msg
{
    uint8_t  u8_data[8];
    uint64_t u64_data;
    struct
    {
        uint64_t cmd_type  : 4;
        uint64_t data_len  : 3;
        uint64_t rw        : 1;
        uint64_t en        : 1;
        uint64_t rsed      : 3;
        uint64_t data_id   : 12;
        uint64_t data      : 32;
        uint64_t check_sum : 8;
    } bit;
} cali_msg_type;

typedef union
{
    float    f_data;
    uint8_t  u8_data[4];
    uint32_t u32_data;
} float_convert;

typedef struct
{
    uint8_t  en_cal;  // 自动退出标定；
    uint8_t *val_cal; // 标定使能位
    uint32_t count;
    uint32_t over_time;
} cali_connect_type;

static cali_connect_type can_cal_mgt[100];

// 标定自动断开设置
static uint8_t can_cali_conneet_set(uint8_t index, uint32_t over_time, uint8_t *p)
{
    if (index < ARR_SIZE(can_cal_mgt))
    {
        can_cal_mgt[index].en_cal    = 1;
        can_cal_mgt[index].val_cal   = p;
        can_cal_mgt[index].count     = 0;
        can_cal_mgt[index].over_time = over_time;
    }
    return 0;
}

// 标定自动断开管理
void can_cal_connect_mgt(void)
{
    uint8_t i;
    for (i = 0; i < ARR_SIZE(can_cal_mgt); i++)
    {
        if (can_cal_mgt[i].en_cal)
        {
            if (++can_cal_mgt[i].count >= can_cal_mgt[i].over_time)
            {
                *can_cal_mgt[i].val_cal = 0; // 超时清除
                can_cal_mgt[i].en_cal   = 0;
            }
        }
        else
        {
            *can_cal_mgt[i].val_cal = 0; // 命令清除
        }
    }
}

uint8_t led_en       = 0;
uint8_t led_en_value = 0;

void cal_write(pdu_tag rec_msg)
{
    pdu_tag       tx_msg;
    cali_msg_type rx_data;
    float_convert data;
    rx_data.u64_data = rec_msg.data.u64_buf;

    switch (rx_data.bit.data_id)
    {
    case 1:
        if ((rx_data.bit.cmd_type == cal_ram) && (rx_data.bit.data_len == cali_data_len_1bit))
        {
            if (rx_data.bit.en == 1)
            {
                led_en = 1;
            }
            else
            {
                led_en = 0;
            }
            led_en_value = (uint8_t)rx_data.bit.data;
            can_cali_conneet_set(rx_data.bit.data_id, 2000, &led_en);
        }
        break;
    default:
        break;
    }
}

void cal_read(pdu_tag rec_msg)
{
    pdu_tag       tx_msg;
    cali_msg_type rx_data, tx_data;
    float_convert data;
    rx_data.u64_data = rec_msg.data.u64_buf;
    tx_data.u64_data = rec_msg.data.u64_buf;
    switch (rx_data.bit.data_id)
    {
    case 1:
        if ((rx_data.bit.cmd_type == cal_ram) && (rx_data.bit.data_len == cali_data_len_1bit))
        {
            rx_data.bit.en == led_en;
            tx_data.bit.data = led_en_value;
        }
        break;
    default:
        break;
    }

    tx_msg.data.u64_buf = tx_data.u64_data;
    push_can_message_to_queue(get_new_can_id(CAN_CALI), 8, tx_msg.data.u8_buf);
}

void can_cali_msg_analysis(pdu_tag rec_msg)
{
    cali_msg_type cal_data;
    cal_data.u64_data = rec_msg.data.u64_buf;

    if (cal_data.bit.rw == read_cal)
    {
        cal_read(rec_msg);
    }
    else if (cal_data.bit.rw == write_cal)
    {
        cal_write(rec_msg);
    }
}