#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdint.h>
#include <syslog.h>

#include "bmser_can_init.h"
#include "xieneng_can_component.h"
#include "xieneng_can_supervisor.h"
#include "xieneng_can_mqtt.h"
#include "can_inf.h"
#include "bmser_log.h"
#include "bmser_dev.h"
#include "cJSON.h"
#include "bmser_utils.h"
#include "bmser_error_code.h"
#include "bcu_db_addr.h"
#include "bmser_project_para.h"

#define MAX_CAN_SEND_FAIL_CNT 10
static uint32_t g_can_send_fail_cnt = 0;
const char * g_protName[CAN_OBJ_ID_MAX] = {"CANBUS_0","CANBUS_1"};
static bmser_canrbus_ver_s g_ver_msg = {0};

static int32_t xieneng_canInf_sendMsg(uint32_t canObjId, CanMsg *txMsg)
{
    int32_t ret = 0;
    ret = canInf_sendMsg(canObjId, txMsg);
    if (ret < 0) {
        g_can_send_fail_cnt++;
    } else {
        g_can_send_fail_cnt = 0;
    }

    if (g_can_send_fail_cnt >= MAX_CAN_SEND_FAIL_CNT) { //can总线异常，退出进程，由守护进程重新自启动
        dy_syslog(LOG_ERR, "recv max send fail, restart xieneng_can");
        exit(1);
    }

    return ret;
}

static uint32_t xieneng_can_checkPortIndex(char *buf)
{
    uint32_t port_index = 0;
    if (!strcmp(buf, g_protName[CAN_OBJ_ID_1]))
    {
        port_index = CAN_OBJ_ID_1;
    }
    else if(!strcmp(buf, g_protName[CAN_OBJ_ID_2]))
    {
        port_index = CAN_OBJ_ID_2;
    }else{}

    return port_index;
}

const char *port_enum2char(int portIndex)
{
    if(portIndex >= CAN_OBJ_ID_MAX )
    {
        dy_syslog(LOG_ERR,"protIndex Error");
        return g_protName[0];
    }
    return g_protName[portIndex];
}

void convertArrayToLittleEndian(uint16_t *data, uint16_t length)
{
    if(NULL == data)
    {
        return;
    }
    int i = 0;
    for (i = 0; i < length; i++) 
    {
        *(data + i) = LITTLE_TO_BIG_ENDIAN_16(*(data + i));
    }
}

int can_canrbusMsgFlowHeader(uint32_t canId, canrbus_header_t *canrbusHeadr)
{
    canrbusHeadr->func = GET_FUNC_CODE(canId);
    canrbusHeadr->msgFlowBauId = GET_BAU_ID(canId);
    canrbusHeadr->msgFlowBcuId = GET_BCU_ID(canId);
    canrbusHeadr->msgFlowBmuId = GET_BMU_ID(canId);
    canrbusHeadr->msgFlowWorkId = GET_WORK_ID(canId);
    canrbusHeadr->msgFlowUpdateType = GET_UPDATE_TYPE(canId);
    return 0;
}

static int32_t updateDevCanRecvTimeStamp(uint16_t bankId, uint16_t rackId)
{
    xieneng_can_var_t *var = get_xieneng_can_var();
    if(var == NULL){ return -1; }

    uint16_t devId = 0,racks = bmser_jsonGetRackNum();
    devId = bankId * racks + rackId;
    // pthread_mutex_lock(&var->mutex); //多线程加互斥锁
    var->can_bus_tables[devId].last_rcv = bmser_get_time_stamp_ms();
    var->can_bus_tables[devId].is_timeout = 0;
    var->can_bus_tables[devId].in_use = 1;
    // pthread_mutex_unlock(&var->mutex);
    return 0;
}

int get_cache(uint32_t canObjId, uint16_t bankId, uint16_t rackId, unsigned short start_addr, unsigned short reg_cnt, unsigned char *buf, int len)
{
    int port_index = canObjId;
    int i = 0, ret = 0;
    char valid[1024] = {0};
    EMS_DEV_REG_DATA_S regData = {0};

    if (len < reg_cnt * 2)
    {
        dy_syslog(LOG_ERR, "buf length not enough");
        return -1;
    }

    regData.bankId = bankId;
    regData.rackId = rackId;
    regData.startAddr = start_addr;
    regData.regCount = reg_cnt;
    regData.len = len;
    regData.dbValid = valid;
    ret = BmserProtocolExt_ReadRegisterDb(&regData, buf, len);
    if (0 != ret) {
        #ifdef LOCAL_DEBUG
        dy_syslog(LOG_ERR, "read db fail, ret = %d, devId = %u, startAddr = %u", ret, regData.rackId, regData.startAddr);
        #endif
        return ret;
    }
    
    return reg_cnt * 2;
}

static bool dev_addr_check(uint16_t bankId, uint16_t rackId)
{
    uint8_t dev_id = 0;
    bool check_result = false;
    uint16_t devId = 0,racks = bmser_jsonGetRackNum();
    devId = bankId * racks + rackId;
    if(devId < BMS_CFG_ROCKSNUM_MAX)
    {
        check_result = true;
    }   
    return check_result;
}

int set_cache(uint32_t canObjId, uint16_t bankId, uint16_t rackId, unsigned short start_addr, unsigned short reg_cnt, unsigned char *data, int len)
{
    int i = 0, ret = 0;
    int port_index = canObjId;
    if (len < reg_cnt * 2)
    {
        dy_syslog(LOG_ERR, "buf length not enough");
        return -1;
    }

    if (!dev_addr_check(bankId,rackId))
    {
        //term_addr层级或dev_id错误
        #ifdef LOCAL_DEBUG
        dy_syslog(LOG_ERR, "dev addr illegal, bankId: %d, rackId: %d\n");
        #endif
        return -1;
    }
    start_addr = start_addr & REG_ADDR_MASK;
    if ((start_addr*2 + len ) > SHM_SIZE) {
        dy_syslog(LOG_ERR, "regsiter over range,reg_addr:%04X len:%d",start_addr,len);
        return -1;
    }

    EMS_DEV_REG_DATA_S regData = {0};
    //实际设备的ID由libdb接口内部自动转换，这里只需要感知堆ID与堆下簇ID
    regData.bankId = bankId;
    regData.rackId = rackId;
    regData.startAddr = start_addr;
    regData.regCount = reg_cnt;
    regData.len = len;
    regData.data = data;
    ret = BmserProtocolExt_UpdateRegisterDb(&regData);
    if (0 != ret) {
        #ifdef LOCAL_DEBUG
        dy_syslog(LOG_ERR, "set cache fail, ret = %d", ret);
        #endif
        return ret;
    }
    
    updateDevCanRecvTimeStamp(bankId,rackId);
    return 0;
}

static uint32_t can_combinaCanidByHeader(canrbus_header_t *xieneng_header)
{
    uint32_t canId = 0;

    canId |= ((xieneng_header->func << 16)&0x70000);
    if (xieneng_header->func == FUNC_CODE_MSG_FLOW || FUNC_CODE_MSG_FLOW_RSP == xieneng_header->func)
    {
        canId |= (((xieneng_header->msgFlowBauId << 25)&0xE000000) | ((xieneng_header->msgFlowBcuId<<19)&0x1F80000) | ((xieneng_header->msgFlowBmuId<<9)&0xFE00));
        canId |= (((xieneng_header->msgFlowWorkId << 7)& 0x180) | ((xieneng_header->msgFlowUpdateType << 6)&0x40));
    }
    else
    {
        // dy_syslog(LOG_ERR, "func:%d, start_addr:%x, dev_id:%d, layer:%d.", xieneng_header->func, xieneng_header->start_addr, xieneng_header->dev_id, xieneng_header->layer);
        canId |= ((ENDIAN_TYPE_CONVERT_16(xieneng_header->start_addr) & 0xFFFF) | ((xieneng_header->dev_id<<19) & 0x1F80000) | ((xieneng_header->layer<<25) & 0xE000000));
    }

    return canId;
}

static int send_data_to_dev(const struct mosquitto_message *mqtt_msg, int32_t port_index)
{
    if (NULL == mqtt_msg) {
        return -1;
    }

    int ret = 0;
    uint8_t msg_data[MAX_FLOW_DATA_LEN] = {0};
    uint16_t i = 0;
    CanMsg can = {0};
    uint16_t len = mqtt_msg->payloadlen - (sizeof(canrbus_header_t));
    canrbus_header_t *xieneng_header = (canrbus_header_t *)mqtt_msg->payload;
    
    if (NULL == xieneng_header) {
        return -1;
    }

    //偏移到实际数据首地址
    //偏移地址,由于CAN 拆包,第一帧需要带长度,要多一个字
    if (xieneng_header->func == FUNC_CODE_MSG_FLOW || xieneng_header->func == FUNC_CODE_MSG_FLOW_RSP) {
        msg_data[0] = (len);
        memcpy(msg_data + 1, mqtt_msg->payload + sizeof(canrbus_header_t), len);
        len += 1;

    } else {
        memcpy(msg_data, mqtt_msg->payload + sizeof(canrbus_header_t), len);
    }

    can.CanId = can_combinaCanidByHeader(xieneng_header);
    can.IDE = CAN_ID_EXT;
    can.DLC = CAN_BUF_LEN;

    for (i = 0; i < len; i += CAN_BUF_LEN)
    {
        memcpy(can.Data, &msg_data[i], MIN(CAN_BUF_LEN,(len - i)));
        can.DLC = MIN(CAN_BUF_LEN,(len - i));
        ret = xieneng_canInf_sendMsg(port_index,&can);
        can.CanId++;
        // usleep(10000);
    }

    return ret;
}

int send_data_to_can_bus(uint32_t canObjId, unsigned short term_addr, BMS_FUNC_CODE_E func, unsigned short start_addr, unsigned short reg_cnt, unsigned char *data, int len)
{
    int port_idx = canObjId;
    CanMsg can;
    unsigned int can_id = 0;
    unsigned char dev_id = term_addr & 0xFF;
    unsigned char layer = (term_addr >> 8) & 0xFF;

    if (bmser_can_cfg_file_enable()) {
        port_idx = bmser_can_get_can_obj_id(dev_id);
        if (port_idx < 0) {
            return -1;
        }
    }

    if (func == WRITE)
    {
        int cnt = 0;
        can_id = can_id | (1 << 16);
        can_id = can_id | ((unsigned int)dev_id << 19);
        can_id = can_id | ((unsigned int)layer << 25);
        can.IDE = CAN_ID_EXT;
        if (data == NULL || len == 0)
        {
            dy_syslog(LOG_ERR, "data is empty");
            return -1;
        }

        while (cnt < reg_cnt)
        {
            can_id = (can_id & 0xFFFF0000) | ((start_addr + cnt) & 0xFFFF);
            if ((reg_cnt - cnt) >= 4)
            {
                memcpy(can.Data, data, 8);
                can.DLC = 8;
                data = data + 8;
                cnt += 4;
            }
            else
            {
                memcpy(can.Data, data, (reg_cnt - cnt) * 2);
                can.DLC = (reg_cnt - cnt) * 2;
                cnt = reg_cnt;
            }
            can.CanId = can_id;
            usleep(50*1000); //每次发送50ms延时，防止将bms fifo 写满导致数据丢失
            xieneng_canInf_sendMsg(port_idx,&can);
        }
    }
    else if (func == READ)
    {
        // FIXME:BDU可能会出现DB地址超出的问题，但是外部传入的时候已经保证了DB地址
        can_id = start_addr & 0xFFFF;
        can_id = can_id | (3 << 16);
        can_id = can_id | ((unsigned int)dev_id << 19);
        can_id = can_id | ((unsigned int)layer << 25);
        can.IDE = CAN_ID_EXT;

        can.CanId = can_id;
        can.DLC = 2;
        can.Data[0] = (reg_cnt >> 8) & 0xFF;
        can.Data[1] = reg_cnt & 0xFF;
        xieneng_canInf_sendMsg(port_idx,&can);
    }
    return 0;
}

int xieneng_can_send_to_dev(const struct mosquitto_message *mqtt_msg)
{
    //发送下行数
    int32_t ret = 0;
    char buf[BUF_LEN] = {0};
    uint8_t i = 0;
    int port_index = -1;
    canrbus_header_t *xieneng_header = (canrbus_header_t *)mqtt_msg->payload;
    //ipc/[GW SN]/bms/[Dev_Sn]/upgrade/Set/binaryFlow
    //sscanf(mqtt_msg->topic, "to_dev/%*[^/]/%[^/]/data/Set_Rglt_Raw", buf);
    //port_index = xieneng_can_checkPortIndex(buf);
    if (true != bmser_can_cfg_file_enable())
    {
        return -1;
    }
    //根据canrbus_header_t确定port_index
    // dy_syslog(LOG_DEBUG, "msgFlowBauId = %hhu, msgFlowBcuId = %hhu, msgFlowBmuId = %hhu.", xieneng_header->msgFlowBauId, xieneng_header->msgFlowBcuId, xieneng_header->msgFlowBmuId);
    if (0x3f == xieneng_header->msgFlowBcuId) {
        //广播升级所有簇数, 向所有的使能的CAN发广播报文
        BMSER_CAN_BUS_CFG_TABLE_S *cfg_table = bmser_can_get_cfg_tables_mgr();
        for (i = 0; i < cfg_table->num; i++) {
            if (cfg_table->can_cfg[i].disable) {
                continue;
            }
            sscanf(cfg_table->can_cfg[i].name, "can%d", &port_index);
            if (-1 == port_index) {
                continue;
            }
            // dy_syslog(LOG_DEBUG, "send to dev by can%d.", port_index);
            send_data_to_dev(mqtt_msg, port_index);
        }
        return ret;
    } else if (0 == xieneng_header->msgFlowBcuId) {
        //只查总控, 通过总主CAN main CAN接口发包
        port_index = bmser_can_get_can_obj_id(xieneng_header->msgFlowBauId - 1);
    } else {
        //定向查某一簇
        port_index = bmser_can_get_can_obj_id(xieneng_header->msgFlowBcuId);
    }
    if(port_index < 0)
    {
        return -1;
    }
    send_data_to_dev(mqtt_msg, port_index);
    return ret;
}

static int xieneng_can_add_period_cmd(period_table_t *period_tables, uint32_t canObjId, unsigned short term_addr, unsigned short start_addr, unsigned short reg_cnt, unsigned short period)
{
    period_node_t *node = NULL;
    int i;
    int port_index = canObjId;
    if (port_index >= CAN_OBJ_ID_MAX)
    {
        dy_syslog(LOG_ERR, "port not support, port:%d", port_index);
        return -1;
    }
    period_table_t *period_table = &period_tables[port_index];
    // first check duplicate
    for (i = 0; i < period_table->size; i++)
    {
        if (period_table->nodes[i].used == 1)
        {
            node = &period_table->nodes[i];
            if (node->term_addr == term_addr && node->start_addr == start_addr && node->reg_cnt == reg_cnt)
            {
                node->period = period;
                goto find;
            }
        }
    }

    if (period_table->cnt == 0 || period_table->nodes == NULL)
    {
        period_table->nodes = calloc(4, sizeof(period_node_t));
        period_table->size = 4;
    }
    else if (period_table->cnt == period_table->size)
    {
        period_table->nodes = realloc(period_table->nodes, (period_table->size + 4) * (sizeof(period_node_t)));
        memset(&period_table->nodes[period_table->size], 0, 4 * (sizeof(period_node_t)));
        period_table->size += 4;
    }

    for (i = 0; i < period_table->size; i++)
    {
        if (period_table->nodes[i].used == 0)
        {
            node = &period_table->nodes[i];
            node->start_addr = start_addr;
            node->term_addr = term_addr;
            node->reg_cnt = reg_cnt;
            node->period = period;
            node->used = 1;
            node->last_send = 0;
            period_table->cnt++;
            goto find;
        }
    }

find:
    return 0;
}

int xieneng_can_msg_handle_binary(uint16_t devId, const struct mosquitto_message *mqtt_msg)
{
    xieneng_header_t *xieneng_header = (xieneng_header_t *)mqtt_msg->payload;
    unsigned char layer, dev_id, start_addr_hi, start_addr_lo, reg_cnt_hi, reg_cnt_lo;
    unsigned char func = RESERVERED;
    unsigned short term_addr = 0;
    unsigned short start_addr = 0;
    unsigned short reg_cnt = 0;
    int port_index = 0;
    char buf[BUF_LEN] = {0};
    int len;
    int i;
    xieneng_can_var_t *var = get_xieneng_can_var();
    if (var->upgradeflag == 1)
    {
        //  dy_syslog(LOG_DEBUG, "rcv topic:%s upgrading!!!!!", mqtt_msg->topic);
        return -1;
    }
    // dy_syslog(LOG_DEBUG, "rcv topic:%s", mqtt_msg->topic);

    layer = xieneng_header->layer;
    // dev_id = xieneng_header->dev_id;
    dev_id = devId;
    func = xieneng_header->func;
    start_addr_hi = xieneng_header->start_addr_hi;
    start_addr_lo = xieneng_header->start_addr_lo;
    reg_cnt_hi = xieneng_header->reg_cnt_hi;
    reg_cnt_lo = xieneng_header->reg_cnt_lo;
    //"to_dev/"：匹配字符串中的字面值"to_dev/"。
    //"%[^/]"：匹配任意数量的非'/'字符，但由于有一个'*'修饰符，这部分匹配的内容将被忽略。
    //"/%[^/]"：匹配一个'/'字符，然后匹配任意数量的非'/'字符。这部分匹配的内容将被存储在buf中。
    //"/data/Set_Rglt_Raw"：匹配字符串中的字面值"/data/Set_Rglt_Raw"。
    //sscanf(mqtt_msg->topic, "to_dev/%*[^/]/%[^/]/data/binary_data", buf);
    //port_index = xieneng_can_checkPortIndex(buf);
    port_index = bmser_can_get_can_obj_id(dev_id);
    if (port_index < 0) {
        return -1;
    }
    term_addr = ((unsigned int)layer) << 8 | dev_id;
    start_addr = ((((unsigned int)start_addr_hi) << 8) & 0xFF00) + start_addr_lo;
    reg_cnt = ((((unsigned int)reg_cnt_hi) << 8) & 0xFF00) + reg_cnt_lo;


    if (func == READ)
    {
        EMS_DEV_REG_DATA_S regData = {0};
        int ret = 0;
        // char valid = 0;
        uint16_t c_data[READ_DATA_LEN] = {0};
        xieneng_header = (xieneng_header_t *)buf;
        regData.bankId = 0;
        regData.rackId = (term_addr & 0xFF);
        regData.startAddr = start_addr;
        regData.regCount = reg_cnt;
        regData.len = regData.regCount*2;
        // regData.dbValid = &valid;
        if(regData.regCount > READ_DATA_LEN)
        {
            /* 单次查询数量限制为READ_DATA_LEN */
            dy_syslog(LOG_DEBUG, "func READ: regCount over the limit(%d)!\n",READ_DATA_LEN);
            return -1;
        }
        ret = BmserProtocolExt_ReadRegisterDb(&regData, (uint8_t *)c_data, regData.len);
        if(ret != 0)
        {
            dy_syslog(LOG_ERR, "read reg db fail addr = 0x%x, ret = %d.\n", regData.startAddr, ret);
            /* 读取失败再向下位机请求一次 */
            send_data_to_can_bus(port_index, term_addr, func, start_addr, reg_cnt, NULL, 0);
            return 0;
        }

        xieneng_header->layer = layer;
        xieneng_header->dev_id = dev_id;
        xieneng_header->func = READ_RSP;
        xieneng_header->start_addr_hi = start_addr_hi;
        xieneng_header->start_addr_lo = start_addr_lo;
        xieneng_header->reg_cnt_hi = reg_cnt_hi;
        xieneng_header->reg_cnt_lo = reg_cnt_lo;
        memcpy(xieneng_header->data, c_data, reg_cnt * 2);
        publish_binaryCmd_func_read(buf, reg_cnt, xieneng_header->dev_id);
    }
    else if (func == PERIOD_READ)
    {
        if (!bmser_can_cfg_file_enable()) {
            unsigned short period = (((unsigned short)xieneng_header->data[0]) << 8) + xieneng_header->data[1];
            xieneng_can_add_period_cmd(var->period_tables, port_index, term_addr, start_addr, reg_cnt, period);
        }
    }
    else if (func == WRITE)
    {
        send_data_to_can_bus(port_index, term_addr, func, start_addr, reg_cnt, mqtt_msg->payload + sizeof(xieneng_header_t), reg_cnt * 2);
    }

    return 0;
}

#ifdef WITH_BMSER_PRODUCT_TEST
int xieneng_can_send_to_dev_7ff(const struct mosquitto_message *mqtt_msg)
{
    //发送下行数据
    CanMsg can = {0};
    char *data = NULL;
    unsigned char reg_cnt_hi, reg_cnt_lo;
    unsigned short len = 0, i;
    int port_index = 0;
    char buf[BUF_LEN] = {0};
    xieneng_header_t *xieneng_header = (xieneng_header_t *)mqtt_msg->payload;
    reg_cnt_hi = xieneng_header->reg_cnt_hi;
    reg_cnt_lo = xieneng_header->reg_cnt_lo;

    data = mqtt_msg->payload + sizeof(xieneng_header_t);
    sscanf(mqtt_msg->topic, "to_dev/%*[^/]/%[^/]/data/Set_Rglt_7FF_Raw", buf);
    port_index = xieneng_can_checkPortIndex(buf);
    len = ((((unsigned int)reg_cnt_hi) << 8) & 0xFF00) + reg_cnt_lo;

    can.CanId = 0x7ff;
    can.IDE = CAN_ID_EXT;
    can.DLC = CAN_BUF_LEN;
    dy_syslog(LOG_DEBUG, "xieneng_can_send_to_dev_7ff: len=%d ", len);
    for (i = 0; i < len; i += CAN_BUF_LEN)
    {
        memcpy(can.Data, &data[i], MIN(CAN_BUF_LEN,(len - i)));
        can.DLC = MIN(CAN_BUF_LEN,(len - i));
        xieneng_canInf_sendMsg(port_index, &can);
    }
    return 0;
}
#endif

int xieneng_can_set_config_para(const struct mosquitto_message *mqtt_msg)
{
    if (!mqtt_msg)
    {
        dy_syslog(LOG_ERR, "para is null.");
        return -1;
    }
    return bmser_can_set_mqtt_project_para((const char *)mqtt_msg->payload, mqtt_msg->payloadlen);
}

// 需要和td_mqtt保持一致，后续考虑其他处理方式
summary_datainsert_cfg_info g_RackSummaryDatatypeCfg[] =
{
    { BMS_SAMPLE_BATTERY_TOTAL_VOL, DATA_TYPE_SUMMARY_TOTAL_VOL},           //总电压
    { BMS_SAMPLE_TOTAL_CURRENT, DATA_TYPE_SUMMARY_TOTAL_CURRENT},           //总电流
    { BMS_SUMMARY_DISPLAY_SOC_VALUE, DATA_TYPE_SUMMARY_SOC},                //显示SOC
    // { 0x0B07, DATA_TYPE_SUMMARY_POWER},  目前主控无该DB
    { BMS_SUMMARY_MAX_SINGLE_VOLTAGE_VALUE, DATA_TYPE_SUMMARY_HIGHEST_VOL}, //最大单体电压
    { BMS_SUMMARY_MIN_SINGLE_VOLTAGE_VALUE, DATA_TYPE_SUMMARY_LOWEST_VOL},  //最小单体电压
    { BMS_SUMMARY_CELL_AVERAGE_VOL_VALUE, DATA_TYPE_SUMMARY_AVE_VOL},       //单体平均电压
    { BMS_SUMMARY_MAX_SINGLE_TEMP_VALUE, DATA_TYPE_SUMMARY_HIGHEST_TEMP},   //最大温度
    { BMS_SUMMARY_MIN_SINGLE_TEMP_VALUE, DATA_TYPE_SUMMARY_LOWEST_TEMP},    //最小温度
    { BMS_SUMMARY_ENVIRONMENT_TEMP, DATA_TYPE_SUMMARY_AVE_TEMP}             //平均温度
};
#define TD_Summary_Data_NUM         SIZE_OF_ARRAY(g_RackSummaryDatatypeCfg)

int32_t getDataTypeByDbAddr(uint32_t dbAddr)
{
    int i;
    for (i = 0; i < TD_Summary_Data_NUM; i++)
    {
        if (g_RackSummaryDatatypeCfg[i].DbAddr == dbAddr)
        {
            return g_RackSummaryDatatypeCfg[i].dataType;
        }
    }
    
    // 如果未找到匹配的DbAddr，返回DATA_TYPE_MAX
    return DATA_TYPE_MAX;
}

/**
 * @brief       请求canrbus协议版本
 * @param[in]   portIdx canid
 * @param[in]   rack_num 簇数
 * @return      返回值
 * @retval      true:success; -1:fail
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023/07/06       XXXXX        创建初始版本     \n
 */
int bmser_can_canrbus_protocol_ver_req(uint32_t portIdx, uint8_t rack_num)
{
    int ret = 0;
    int i;
    CanMsg pMsg = {0};
    CANRBUS_PROTORCOL_MSG_BUF_STRU *pInfo = NULL;
    pMsg.CanId = PROTOCOL_VERSION_CHECK;
    pMsg.IDE = CAN_ID_EXT;
    pMsg.DLC = CAN_BUF_LEN;

    pInfo = (CANRBUS_PROTORCOL_MSG_BUF_STRU *)pMsg.Data;
    pInfo->cmd = 0x00;
    pInfo->devType = 0x02;  //0x01:BMU; 0x02:BCU; 0x03:BAU
    for(i = 0; i <= rack_num; i++)
    {
        pInfo->devType = 0x02;
        pInfo->devId = i;
        //总控devType, devId修正
        if(i == 0)
        {
            pInfo->devType = 0x03;
            pInfo->devId = 1;
        }
        usleep(1000*50);
        ret |= canInf_sendMsg(portIdx, &pMsg);
    }
    // dy_syslog(LOG_DEBUG, "bmser_can_canrbus_protocol_ver_get,ret=%d!\n",ret);
    return ret;
}

int bmser_can_get_canrbus_protocol_ver(CanMsg *rxcan)
{
    static int16_t bauVer = 0, bcuVer = 0;
    int16_t bmuVer, bduVer;
    static int16_t old_bcuVer = CAN_BUS_VER_BUTT;
    static bool isChange = false;
    CANRBUS_PROTORCOL_MSG_BUF_STRU *pStru = (CANRBUS_PROTORCOL_MSG_BUF_STRU *)rxcan->Data;
    //BAU,BCU取最低版本canrbus组包；BMU只支持4.0; BDU只支持5.0
    if(CHECK_VERSION_CMD == pStru->cmd)
    {
        if(0x02 == pStru->devType){
            if(old_bcuVer > pStru->protocolVersion){
                //取最低版本
                bcuVer = pStru->protocolVersion;
                old_bcuVer = bcuVer;
                isChange = true;
            }
        }
        else if(0x03 == pStru->devType){
            bauVer = pStru->protocolVersion;
        }
    }
    // bmu仅支持4.0；bdu仅支持5.0
    bmuVer = CAN_BUS_VER_0x41;
    bduVer = CAN_BUS_VER_0x50;

    if(isChange){
        g_ver_msg.bau_ver = bauVer;
        g_ver_msg.bcu_ver = bcuVer;
        g_ver_msg.bmu_ver = bmuVer;
        g_ver_msg.bdu_ver = bduVer;
        publish_canrbusVer_Info(g_ver_msg);   //发生改变or上电主动publish
        isChange = false;
    }
    return 0;
}

int bmser_canrbus_protocol_ver_publish()
{
    publish_canrbusVer_Info(g_ver_msg);
    return 0;
}