#include "soft_bms.h"
#include "main.h"
#include "soft_engine.h"
#include "string.h"
#include "stdio.h"
#include "stdlib.h"
#include "soft_crc.h"
#include "common.h"
#include "soft_device.h"
#include "usart_data_handle.h"
#include "soft_version.h"
#include "soft_adc.h"
#include "soft_can.h"
#include "crc.h"
#include "soft_timer.h"





/************************************herewin******************************************/
/**
  * @file    HerewinCanRecvHookFunction
  * @brief   herewin bms 解析
  * @param   none
  * @details 
  * @author  Zhang Sir 
 **/
herewin_bms herewin_info;
Connect_check Herewin_Link;
herewin_can_info can_info;
void HerewinCanRecvHookFunction(uint32_t cellCanID, uint8_t data[], uint8_t len)
{
    Herewin_Link.recv_time = HAL_GetTick();
    Herewin_Link.connect_status = COMP_NORMAL;

    uint8_t i = 0;
    uint8_t canid_pf = (cellCanID >> 16) & 0xff;

    switch (canid_pf)
    {
    //定值查询包
    case 0x81:
        if((data[0] == 8 )&& (0x80 == data[2]))
        {
           herewin_info.battery_num = data[4];
        }
        break;

    case 0x83:
        herewin_info.get_temp_flag = true;
        //电芯温度传感器只有三个，取前三个字节，传给APP取平均值
        memcpy(&herewin_info.battery_temp[0],&data[0],1); 
        memcpy(&herewin_info.battery_temp[1],&data[1],1);  
        memcpy(&herewin_info.battery_temp[2],&data[2],1);   
        break;
    //单体电压
    case 0x85:
        can_info.message_num = data[0];
        //第一包
        if(can_info.message_num == 1)
        {   
            memset(&can_info,0,sizeof(can_info));
            can_info.byte_num = data[2] + data[3] * 256;
            can_info.message_total = data[1];
            //算出最后一包的有效字节数
            can_info.last_frame_num = can_info.byte_num - 4 -(can_info.message_total - 2) * 7;
            memcpy(&can_info.herewin_buf[0],&data[4],4);
            for(i = 0;i < 4;i++)
            {
                can_info.crc += can_info.herewin_buf[i];
            }
            can_info.i += 4;
        }
        //最后一包 协议校验码是最后发，12S的电池校验会单独占一个字节发送
        //14s
        else if(can_info.message_num == can_info.message_total &&  can_info.last_frame_num <= 5
                && can_info.last_frame_num > 0 )
        {
            memcpy(&can_info.herewin_buf[can_info.i],&data[1],can_info.last_frame_num);
            for(i = 0;i < can_info.last_frame_num;i++)
            {
                can_info.crc += can_info.herewin_buf[can_info.i + i];
            }
            //校验
            if(can_info.crc == data[ 1 + can_info.last_frame_num] + 256 * data[ 2 + can_info.last_frame_num])
            {
                memcpy(&herewin_info.battery_vol[0],&can_info.herewin_buf[0],can_info.byte_num);
            }
            memset(&can_info,0,sizeof(can_info));
        }
        //12s电池  最后一包有效字节-1
        else if(can_info.message_num == can_info.message_total && can_info.last_frame_num <= 0 )
        {   
            //最后一包只有1字节校验
            if(can_info.last_frame_num == -1)
            {
                memcpy(&can_info.herewin_buf[can_info.i],&data[1],1);
                can_info.crc -= can_info.herewin_buf[can_info.i - 1];
                //校验
                if(can_info.crc == can_info.herewin_buf[can_info.i - 1] + 256 * can_info.herewin_buf[can_info.i])
                {
                    memcpy(&herewin_info.battery_vol[0],&can_info.herewin_buf[0],can_info.byte_num);
                }
            }
            //最后一包只有两字节校验
            else if(can_info.last_frame_num == 0)
            {   
                memcpy(&can_info.herewin_buf[can_info.i],&data[1],2);
                //校验
                if(can_info.crc == can_info.herewin_buf[can_info.i] + 256 * can_info.herewin_buf[can_info.i + 1])
                {
                    memcpy(&herewin_info.battery_vol[0],&can_info.herewin_buf[0],can_info.byte_num);
                }
            }
            memset(&can_info,0,sizeof(can_info));

        }
        else
        {
            memcpy(&can_info.herewin_buf[can_info.i],&data[1],7);
            for(i = 0;i < 7;i++)
            {
                can_info.crc += can_info.herewin_buf[can_info.i + i];
            }
            can_info.i += 7;
        }
        break;
    //电池循环次数查询
    case 0x87:
        memcpy(&herewin_info.circulation_num,&data[0],2);
        break;
    //充电请求
    case 0x22:
        memcpy(&herewin_info.re_vol,&data[0],2);
        memcpy(&herewin_info.re_ele,&data[2],2);
        memcpy(&herewin_info.max_vol,&data[4],2);
        memcpy(&herewin_info.power_status,&data[6],2);
        break;
    //告警信息
    case 0x24:
        memcpy(&herewin_info.alarm_info,&data[0],2);
        memcpy(&herewin_info.warn_info,&data[2],2);
        break;
    //电流 电压信息
    case 0x26:
        memcpy(&herewin_info.total_vol,&data[0],2);
        memcpy(&herewin_info.tolal_ele,&data[2],2);
        memcpy(&herewin_info.SOC_info,&data[4],1);
        memcpy(&herewin_info.SOH_info,&data[5],1);
        memcpy(&herewin_info.SOP_info,&data[6],2);
        break;
    default:
        break;
    }
}


/**
  * @file    send_msg_to_herewin
  * @brief   herewin 发送信息
  * @param   none
  * @details 海盈电池收不到心跳包20分后停止主动发送数据 2000ms周期给海盈电池发送心跳包
  * @author  Zhang Sir 
 **/
void send_msg_to_herewin(void)
{   
    static uint32_t herewin_heart_time = 0;
    static uint32_t herewin_vol_time = 0;

    static uint8_t heart_num_count = 0;

    if(Herewin_Link.connect_status == COMP_NORMAL)
    {
        //2000ms发送心跳包
        if(HAL_GetTick() - herewin_heart_time > 2000)
        {   
            uint8_t heart_buf[8] = {0x00,0x00,0x00,0x01,
                                    0x00,0x00,0x00,0x01};
            Can_Send_Msg_Func(CANID2, heart_buf, 8, HEREWIN_HEART_ID, CAN_ID_EXT);                       
       
            herewin_heart_time = HAL_GetTick();
        }
        //1000ms发送单体电压请求 和单体温度请求  发送5次电芯个数
        if(HAL_GetTick() - herewin_vol_time > 1000)
        {
            uint8_t herewin_num = 8;
            Can_Send_Msg_Func(CANID2, 0, 0, HEREWIN_VOL_ID, CAN_ID_EXT); 
            Can_Send_Msg_Func(CANID2, 0, 0, HEREWIN_TEM_ID, CAN_ID_EXT); 
            //请求5次电芯个数 5次循环次数
            Can_Send_Msg_Func(CANID2, &herewin_num, 1, HEREWIN_SEARCH_ID, CAN_ID_EXT);   
            Can_Send_Msg_Func(CANID2, 0, 0, HEREWIN_CIRCULATION_ID, CAN_ID_EXT);   

            herewin_vol_time = HAL_GetTick();
            
        }

    }
    else
    {
        //上电时先发送5次心跳包 防止电池休眠
        if(HAL_GetTick() - herewin_heart_time  > 2000 && heart_num_count > 0)
        {
            uint8_t heart_buf[8] = {0x00,0x00,0x00,0x01,
                                    0x00,0x00,0x00,0x01};

            Can_Send_Msg_Func(CANID2, heart_buf, 8, HEREWIN_HEART_ID, CAN_ID_EXT);   
       
            herewin_heart_time = HAL_GetTick();

            heart_num_count--;
        }
    }
    
}
/**************************************************************************************/

/************************************Okcell*******************************************/
/**
  * @file    update_bms_data
  * @brief   更新电池信息
  * @param   none
  * @details 
  * @author  Zhang Sir 
 **/

uint8_t group_num = 0; //电池组数

#define RESET_OKIDCODE_DELAY  (3)
unsigned char okcell_sha1_out[20] = {0};
//结构体指针类型
_OKCELL_DEVICE okcell_device1 = {.Okcell_Link.connect_status = COMP_NOEXIST,
                                 .Okcell_get_s = false,
                                 .okcell_inf.cell_D0.cell_d0[6] = 0}, 
               okcell_device2 = {.Okcell_Link.connect_status = COMP_NOEXIST,
                                 .Okcell_get_s = false,
                                 .okcell_inf.cell_D0.cell_d0[6] = 0};


void OkcellCanRecvHookFunction(uint32_t cellCanID, uint8_t data[], uint8_t len)
{
    _OKCELL_DEVICE *OKptr = NULL;
    //添加兼容两组电池
    static uint8_t OKIdCode1counts = 0,OKIdCode2counts = 0;
    //判断是哪个电池的ID，通过ID来区分电池。并支持飞控不断电更换电池
    if(cellCanID != okcell_device1.deviceCanID && cellCanID != okcell_device2.deviceCanID)
    {
        //分配给1号结构体
        if(OKIdCode1counts == 0){
            OKIdCode1counts = RESET_OKIDCODE_DELAY;
            
            OKptr = &okcell_device1;
            OKptr->deviceCanID = cellCanID;

            group_num = 1;
        }
        //分配给2号结构体
        else if(OKIdCode2counts == 0) {
            OKIdCode2counts = RESET_OKIDCODE_DELAY;
            
            OKptr = &okcell_device2;
            OKptr->deviceCanID = cellCanID;

            group_num = 2;
        }
        //不分配结构体
        else{
            OKIdCode1counts>0 ? OKIdCode1counts-- : OKIdCode1counts;
            OKIdCode2counts>0 ? OKIdCode2counts-- : OKIdCode2counts;
        }
    }
    else if(cellCanID == okcell_device1.deviceCanID)
    {
        OKIdCode1counts = RESET_OKIDCODE_DELAY;
            
        OKptr = &okcell_device1;
        OKptr->deviceCanID = cellCanID;
    }
    else if(cellCanID == okcell_device2.deviceCanID)
    {
        OKIdCode2counts = RESET_OKIDCODE_DELAY;
        
        OKptr = &okcell_device2;
        OKptr->deviceCanID = cellCanID;
    }
    
    
    //如果指针找到了存放数据的结构体
    if(OKptr != NULL)
    {
        //找到开头，开始接收
        //strncmp比较字符串，遇到'\0'会结束，所以不适合用字数组比较
        if(memcmp(data,"ZFKJ",4) == 0){
            OKptr->Okcell_recv_index = 0;
            OKptr->Okcell_get_s = true;
        }

        //溢出检测
        if(OKptr->Okcell_recv_index + len > OKCELL_MAXLEN)
        {
            memset(OKptr->Okcell_recv_buf,0,OKptr->Okcell_recv_index);
            OKptr->Okcell_recv_index = 0;
            OKptr->Okcell_get_s = false;
        }
        
        //接收到起始标志后开始存数组
        if(OKptr->Okcell_get_s == true){
            //复制数据
            memcpy(&OKptr->Okcell_recv_buf[OKptr->Okcell_recv_index], data, len);
            OKptr->Okcell_recv_index += len;
        }

        
        //找到结尾，开始解析,不能用strstr
        if(OKptr->Okcell_get_s == true && findStrInArray(OKptr->Okcell_recv_buf, OKptr->Okcell_recv_index, "END") != 0)
        {
            OKptr->Okcell_get_s = false;
            
            unsigned char loadflag = OKptr->Okcell_recv_buf[7];
            //负载标识为固定的OxBB
            if(loadflag == 0xBB)
            {
                unsigned char cellLoadLen = OKptr->Okcell_recv_buf[6];
                
                //避免错误数据造成的数组溢出
                if(cellLoadLen < OKCELL_MAXLEN-9)
                {
                    unsigned int cellCheck = OKptr->Okcell_recv_buf[8+cellLoadLen]*256 + OKptr->Okcell_recv_buf[9+cellLoadLen];
                    //校验通过,测试没通过
                    if(((crc_ccitt(&OKptr->Okcell_recv_buf[8], cellLoadLen))&0xffff) == cellCheck)
                    {
                        unsigned short cellCmd = (OKptr->Okcell_recv_buf[4]<<8) + OKptr->Okcell_recv_buf[5];
                        
                        OKptr->Okcell_Link.connect_status = COMP_NORMAL;
                        
                        //用于判断电池波特率锁定，实测只要给电池发送数据，电池收到后就会锁定波特率
                        //由于锁定波特率缺少反馈应答，5s内收到多于10包正确的数据则认为波特率锁定成功。
                        if(OKptr->cell_bps_lock_success == false)
                        {
                            OKptr->recv_celldata_counts++;
                            if(OKptr->recv_celldata_counts == 1){
                                OKptr->recv_celldata_time = HAL_GetTick();
                            }
                            else if(OKptr->recv_celldata_counts >= 10)
                            {
                                OKptr->recv_celldata_counts = 0;
                                uint32_t timeperiod = HAL_GetTick() - OKptr->recv_celldata_time;
                                if(timeperiod < 5000000)
                                {
                                    OKptr->cell_bps_lock_success = true;
                                }
                            }
                        }
                        
                        //更新电池数据到来时间
                        OKptr->Okcell_Link.recv_time = HAL_GetTick();
                        
                        switch(cellCmd)
                        {
                            case 0x0000:
                                //stm32为小段模式，OKCELL发送过来的数据为大端模式，不能使用memcpy
                                //memcpy(&cell_D0,&Okcell_recv_buf[8],cellLoadLen);
                                //避免电池厂家私自增加协议造成的数组溢出
                                if(cellLoadLen <= sizeof(_CELL_D0))
                                {
                                    for(unsigned char i=0; i<cellLoadLen/2; i++)
                                    {
                                        OKptr->okcell_inf.cell_D0.cell_d0[i] = (OKptr->Okcell_recv_buf[8 + i*2] << 8) + OKptr->Okcell_recv_buf[9 + i*2];
                                    }
                                }
                                break;
                            case 0x0300:
                                //cell_inf1.cell_D3.cell_d3[4] = (Okcell_recv_buf[16] << 8) + Okcell_recv_buf[17];
                                //避免电池厂家私自增加协议造成的数组溢出
                                if(cellLoadLen <= sizeof(_CELL_D3))
                                {
                                    for(unsigned char i=0; i<cellLoadLen/2; i++)
                                    {
                                        OKptr->okcell_inf.cell_D3.cell_d3[i] = (OKptr->Okcell_recv_buf[8 + i*2] << 8) + OKptr->Okcell_recv_buf[9 + i*2];
                                    }
                                }
                                break;
                            case 0x8200://SHA1加密文密码查询
                                //避免电池厂家私自增加协议造成的数组溢出
                                if(cellLoadLen <= sizeof(_CELL_P2))
                                {
                                    for(unsigned char i=0; i<cellLoadLen; i++)
                                    {
                                        OKptr->okcell_inf.cell_P2.cell_p2[i] = OKptr->Okcell_recv_buf[8 + i];
                                    }
                                }
                                
                                if(memcmp(OKptr->okcell_inf.cell_P2.cell_p2, okcell_sha1_out, sizeof(_CELL_P2)) == 0)
                                {
                                    //收到了正确密文
                                    OKptr->get_cellEncryption = true;
                                }
                                break;
                            case 0x8300://获取电池编号
                                OKptr->get_cellNumber = true;
                                //避免电池厂家私自增加协议造成的数组溢出
                                if(cellLoadLen <= sizeof(_CELL_P3))
                                {
                                    for(uint8_t i=0; i<cellLoadLen; i++)
                                    {
                                        OKptr->okcell_inf.cell_P3.cell_p3[i] = OKptr->Okcell_recv_buf[8 + i];
                                    }
                                }
                                break;
                            default:
                                break;
                        }
                    }
                }
            }
            
            //清理buff
            memset(OKptr->Okcell_recv_buf,0,OKptr->Okcell_recv_index);
            
            //包数完整重新计数
            OKptr->Okcell_recv_index = 0;
        }
    }
}


struct OkCell_P80 okcell_p80;
struct OkCell_P82 okcell_p82;
struct OkCell_P83 okcell_p83;

uint32_t time_okcell_p80 = 0;
uint32_t time_okcell_p82 = 0;
uint32_t time_okcell_p83 = 0;
bool send_okcell_p80data = false;
bool send_okcell_p82data = false;
bool send_okcell_p83data = false;

void send_msg_to_okcell(void)
{
    //自动锁定波特率，正方电池开机自动循环500K/1M发送数据。正方电池缺少一个波特率锁定的反馈应答
    //电池开机会自动1M/500k切换波特率给飞控发信息，所以不用用是否连接来判断。
    if(/*okcell_device1.okcell_link_status == COMP_NOEXIST &&*/ send_okcell_p80data == false && 
        okcell_device1.cell_bps_lock_success == false && HAL_GetTick() < 30000 && 
        HAL_GetTick() - time_okcell_p80 > 250)
    {
        time_okcell_p80 = HAL_GetTick();

        okcell_p80.ok_s[0] = 'Z';
        okcell_p80.ok_s[1] = 'F';
        okcell_p80.ok_s[2] = 'K';
        okcell_p80.ok_s[3] = 'J';
        
        okcell_p80.ok_cmd[0] = 0x80;
        okcell_p80.ok_cmd[1] = 0x00;
        okcell_p80.ok_len = 1;
        okcell_p80.ok_flag = 0xbb;
        okcell_p80.ok_data = 0x79;
        
        short OKcellCRC = crc_ccitt((uint8_t *)&okcell_p80.ok_data,okcell_p80.ok_len);
        okcell_p80.ok_crc[0] = (OKcellCRC>>8) & 0xff;
        okcell_p80.ok_crc[1] = OKcellCRC & 0xff;
        
        okcell_p80.ok_e[0] = 'E';
        okcell_p80.ok_e[1] = 'N';
        okcell_p80.ok_e[2] = 'D';
        
        send_okcell_p80data = true;
    }
    
    if(send_okcell_p80data == true){
        send_okcell_p80data =false;
        Can_Send_Msg_Func(CANID2, (unsigned char *)&okcell_p80, sizeof(okcell_p80), CAN_OKCELL_SEND_ID, CAN_ID_EXT);   
    }
    
    if(send_okcell_p82data == true){
        send_okcell_p82data =false;
        Can_Send_Msg_Func(CANID2, (unsigned char *)&okcell_p82, sizeof(okcell_p82), okcell_device1.deviceCanID, CAN_ID_EXT);
    }
    
    
    
    //获取电池编号
    if(okcell_device1.Okcell_Link.connect_status == COMP_NORMAL && okcell_device1.cell_bps_lock_success == true && 
        okcell_device1.get_cellNumber == false && 
        send_okcell_p83data == false && HAL_GetTick() - time_okcell_p83 > 1000)
    {
        time_okcell_p83 = HAL_GetTick();
        
        okcell_p83.ok_s[0] = 'Z';
        okcell_p83.ok_s[1] = 'F';
        okcell_p83.ok_s[2] = 'K';
        okcell_p83.ok_s[3] = 'J';
        
        okcell_p83.ok_cmd[0] = 0x83;
        okcell_p83.ok_cmd[1] = 0x00;
        okcell_p83.ok_len = 0;
        okcell_p83.ok_flag = 0xbb;
        okcell_p83.ok_crc[0] = 0xff;
        okcell_p83.ok_crc[1] = 0xff;
        
        okcell_p83.ok_e[0] = 'E';
        okcell_p83.ok_e[1] = 'N';
        okcell_p83.ok_e[2] = 'D';
        
        send_okcell_p83data = true;
    }
    
    if(send_okcell_p83data == true){
        send_okcell_p83data =false;
        Can_Send_Msg_Func(CANID2, (unsigned char *)&okcell_p83, sizeof(okcell_p83), okcell_device1.deviceCanID, CAN_ID_EXT);
    }
}

/**************************************************************************************/


/************************************VKBMS*******************************************/
/**
  * @file    Send_VKbms_info
  * @brief   VK智能电池协议飞控端发送
  * @param   none
  * @details 
  * @author  Zhang Sir 
 **/
uint8_t bms_step = 0;
void send_msg_to_VKbms(void)
{   
    static uint8_t change_dev = 1;
    Vkbms_Device *ptr = NULL;

    //处理 有问题，如果不是同时上电，后上电的电池2无法读取电池设备信息。
    static uint32_t bms_heart_time = 0;;
    unsigned int can_id = 0;
    uint8_t len = 0, msg_id = 0,i = 0;
    uint8_t bms_can_buf[8] = {0};
    uint16_t crc = 0;

    if(change_dev == 1)
    {
        change_dev = 2;
        ptr = &Device1;
    }
    else if(change_dev == 2)
    {
        change_dev = 1;
        ptr = &Device2;
    }

    if(ptr->Vkbms_Link.connect_status != COMP_NORMAL)
        return;

    //握手应答
    if(ptr->ack_to_bms == true)
    {
        msg_id = 0x01;
        can_id = msg_id << 20 | 0x7 << 17 | ptr->source_id << 11 | 0x1 << 5 | 0x1 << 4 | 0x1 << 3 | 1;
        len = 2;
        bms_can_buf[0] = 0x56;
        bms_can_buf[1] = 0x31;
        Can_Send_Msg_Func(CANID2, bms_can_buf, len, can_id, CAN_ID_EXT);
        
        ptr->ack_to_bms = false;
    }

    if(ptr->get_bms3_ack == false)
    {
        len = 0;
        msg_id = 0x03;//canid 4083768 3E5039
        can_id = msg_id << 20 | 0x7 << 17 | ptr->source_id << 11 | 0x1 << 5 | 0x1 << 4 | 0x1 << 3 | 1;
        Can_Send_Msg_Func(CANID2, bms_can_buf, len, can_id, CAN_ID_EXT);
    }
    else if(ptr->get_bms4_ack == false)
    {
        len = 0;
        msg_id = 0x04; //canid 5132344 4E5039
        can_id = msg_id << 20 | 0x7 << 17 | ptr->source_id << 11 | 0x1 << 5 | 0x1 << 4 | 0x1 << 3 | 1;
        Can_Send_Msg_Func(CANID2, bms_can_buf, len, can_id, CAN_ID_EXT);
    }
    else if(ptr->get_bms5_ack == false)
    {
        len = 0;
        msg_id = 0x05;//canid 6180920 5E5039
        can_id = msg_id << 20 | 0x7 << 17 | ptr->source_id << 11 | 0x1 << 5 | 0x1 << 4 | 0x1 << 3 | 1;
        Can_Send_Msg_Func(CANID2, bms_can_buf, len, can_id, CAN_ID_EXT);
    }


    if(start_msg.key_to_bms == true)
    {
        msg_id = 0x07;

        crc = Get_Crc16(&start_msg.key_data[0],20);

        memcpy(&bms_can_buf[0],&crc,2);
        memcpy(&bms_can_buf[2],&start_msg.key_data[i],6);

        can_id = msg_id << 20 | 0x7 << 17 | ptr->source_id << 11 | 0x1 << 5 | 0x1 << 4 | 0x0 << 3 | 1;
        Can_Send_Msg_Func(CANID2, &bms_can_buf[0], 8, can_id, CAN_ID_EXT);
        i += 6;
        
        can_id = msg_id << 20 | 0x7 << 17 | ptr->source_id << 11 | 0x1 << 5 | 0x0 << 4 | 0x0 << 3 | 2;
        Can_Send_Msg_Func(CANID2, &start_msg.key_data[i], 8, can_id, CAN_ID_EXT);
        i += 8;

        can_id = msg_id << 20 | 0x7 << 17 | ptr->source_id << 11 | 0x1 << 5 | 0x0 << 4 | 0x1 << 3 | 3;
        Can_Send_Msg_Func(CANID2, &start_msg.key_data[i], 6, can_id, CAN_ID_EXT);
    }
    //开启mos
    else if(start_msg.mos_status == true)
    {
        msg_id = 0x08;

        can_id = msg_id << 20 | 0x7 << 17 | ptr->source_id << 11 | 0x1 << 5 | 0x1 << 4 | 0x1 << 3 | 1;
        bms_can_buf[0] = 0x01;
        Can_Send_Msg_Func(CANID2, bms_can_buf, 1, can_id, CAN_ID_EXT);
    }
    else if(utc_time != 0 && utc_send_time > 0 )
    {
        msg_id = 0x09;
        can_id = msg_id << 20 | 0x7 << 17 | ptr->source_id << 11 | 0x1 << 5 | 0x1 << 4 | 0x1 << 3 | 1;
        memcpy(&bms_can_buf[0],&utc_time,4);
        Can_Send_Msg_Func(CANID2, bms_can_buf, 4, can_id, CAN_ID_EXT);

        utc_send_time--;
    }
    else if(HAL_GetTick() - bms_heart_time > 500)//实时信息应答包
    {
        msg_id = 0x02;
        can_id = msg_id << 20 | 0x7 << 17 | ptr->source_id << 11 | 0x1 << 5 | 0x1 << 4 | 0x1 << 3 | 1;
        Can_Send_Msg_Func(CANID2, bms_can_buf, 0, can_id, CAN_ID_EXT);
        bms_heart_time = HAL_GetTick();
    }  



    // if(Device1.Vkbms_Link.connect_status == COMP_NORMAL || Device2.Vkbms_Link.connect_status == COMP_NORMAL)
    // {
    //     static uint8_t bsm_step_num = 6;
    //     static uint32_t bms_heart_time = 0;;
    //     unsigned int can_id = 0;
    //     uint8_t len = 0, msg_id = 0,i = 0;
    //     uint8_t bms_can_buf[8] = {0};
    //     uint16_t crc = 0;

    //     //上电握手
    //     if(Device1.ack_to_bms == true || Device2.ack_to_bms == true)
    //     {
    //         msg_id = 0x01;

    //         if(Device1.ack_to_bms == true)
    //         {
    //             can_id = msg_id << 20 | 0x7 << 17 | Device1.source_id << 11 | 0x1 << 5 | 0x1 << 4 | 0x1 << 3 | 1;
    //             Device1.ack_to_bms = false;
    //         }
    //         else if (Device2.ack_to_bms == true)
    //         {
    //             can_id = msg_id << 20 | 0x7 << 17 | Device2.source_id << 11 | 0x1 << 5 | 0x1 << 4 | 0x1 << 3 | 1;
    //             Device2.ack_to_bms = false;
    //         }
    //         len = 2;
    //         bms_can_buf[0] = 0x56;
    //         bms_can_buf[1] = 0x31;
    //         Can_Send_Msg_Func(CANID2, bms_can_buf, len, can_id, CAN_ID_EXT);
    //     }

    //     //读取电池信息
    //     if(bms_step <= 2)
    //     {
    //         //上电发送的信息
    //         switch (bms_step)
    //         {
    //         case 0:
    //             if(bsm_step_num > 0)
    //             {
    //                 len = 0;
    //                 msg_id = 0x03;//canid 4083768 3E5038
    //                 can_id = msg_id << 20 | 0x7 << 17 | Device1.source_id << 11 | 0x1 << 5 | 0x1 << 4 | 0x1 << 3 | 1;
    //                 Can_Send_Msg_Func(CANID2, bms_can_buf, len, can_id, CAN_ID_EXT);
    //                 if(Device2.Vkbms_Link.connect_status == COMP_NORMAL)
    //                 {
    //                     can_id = msg_id << 20 | 0x7 << 17 | Device2.source_id << 11 | 0x1 << 5 | 0x1 << 4 | 0x1 << 3 | 1;
    //                     Can_Send_Msg_Func(CANID2, bms_can_buf, len, can_id, CAN_ID_EXT);
    //                 }
    //                 bsm_step_num--;
    //             }
    //             else
    //             {
    //                 bsm_step_num = 5;
    //                 bms_step = 1; 
    //             }
    //             break;
    //         case 1:
    //             if(bsm_step_num > 0)
    //             {
    //                 len = 0;
    //                 msg_id = 0x04; //canid 5132344 4E5038
    //                 can_id = msg_id << 20 | 0x7 << 17 | Device1.source_id << 11 | 0x1 << 5 | 0x1 << 4 | 0x1 << 3 | 1;
    //                 Can_Send_Msg_Func(CANID2, bms_can_buf, len, can_id, CAN_ID_EXT);
    //                 if(Device2.Vkbms_Link.connect_status == COMP_NORMAL)
    //                 {
    //                     can_id = msg_id << 20 | 0x7 << 17 | Device2.source_id << 11 | 0x1 << 5 | 0x1 << 4 | 0x1 << 3 | 1;
    //                     Can_Send_Msg_Func(CANID2, bms_can_buf, len, can_id, CAN_ID_EXT);
    //                 }
    //                 bsm_step_num--;
    //             }
    //             else
    //             {
    //                 bsm_step_num = 5;
    //                 bms_step = 2; 
    //             }
    //             break;
    //         case 2:
    //             if(bsm_step_num > 0)
    //             {
    //                 len = 0;
    //                 msg_id = 0x05;//canid 6180920 5E5038
    //                 can_id = msg_id << 20 | 0x7 << 17 | Device1.source_id << 11 | 0x1 << 5 | 0x1 << 4 | 0x1 << 3 | 1;
    //                 Can_Send_Msg_Func(CANID2, bms_can_buf, len, can_id, CAN_ID_EXT);
    //                 if(Device2.Vkbms_Link.connect_status == COMP_NORMAL)
    //                 {
    //                     can_id = msg_id << 20 | 0x7 << 17 | Device2.source_id << 11 | 0x1 << 5 | 0x1 << 4 | 0x1 << 3 | 1;
    //                     Can_Send_Msg_Func(CANID2, bms_can_buf, len, can_id, CAN_ID_EXT);
    //                 }
    //                 bsm_step_num--;
    //             }
    //             else
    //             {
    //                 bsm_step_num = 5;
    //                 bms_step = 3; 
    //             }
    //             break;
        
    //         default:
    //             break;
    //         }
    //     }
    //     //秘钥匹配
    //     else if(start_msg.key_to_bms == true && bsm_step_num > 0 && bms_step == 3 ) //上个if语句发完再发
    //     {
    //         msg_id = 0x07;

    //         crc = Get_Crc16(&start_msg.key_data[0],20);

    //         memcpy(&bms_can_buf[0],&crc,2);
    //         memcpy(&bms_can_buf[2],&start_msg.key_data[i],6);

    //         can_id = msg_id << 20 | 0x7 << 17 | Device1.source_id << 11 | 0x1 << 5 | 0x1 << 4 | 0x0 << 3 | 1;
    //         Can_Send_Msg_Func(CANID2, bms_can_buf, len, can_id, CAN_ID_EXT);
    //         i += 6;
            
    //         can_id = msg_id << 20 | 0x7 << 17 | Device1.source_id << 11 | 0x1 << 5 | 0x0 << 4 | 0x0 << 3 | 2;
    //         Can_Send_Msg_Func(CANID2, start_msg.key_data, len, can_id, CAN_ID_EXT);
    //         i += 8;

    //         can_id = msg_id << 20 | 0x7 << 17 | Device1.source_id << 11 | 0x1 << 5 | 0x0 << 4 | 0x1 << 3 | 3;
    //         Can_Send_Msg_Func(CANID2, start_msg.key_data, len, can_id, CAN_ID_EXT);

    //         bsm_step_num--;
    //         if(bsm_step_num == 0)
    //         {
    //             bsm_step_num = 5;
    //             bms_step = 4; 
    //         }
    //     }
    //     //开启mos
    //     else if(start_msg.mos_status == true && bsm_step_num > 0 && (bms_step == 4 || start_msg.mos_status == true))
    //     {
    //         msg_id = 0x08;

    //         can_id = msg_id << 20 | 0x7 << 17 | Device1.source_id << 11 | 0x1 << 5 | 0x1 << 4 | 0x1 << 3 | 1;
    //         bms_can_buf[0] = 0x01;
    //         Can_Send_Msg_Func(CANID2, bms_can_buf, len, can_id, CAN_ID_EXT);
    //         bsm_step_num--;
    //     }
    //     else if(HAL_GetTick() - bms_heart_time > 1000)
    //     {
    //         msg_id = 0x02;
    //         can_id = msg_id << 20 | 0x7 << 17 | Device1.source_id << 11 | 0x1 << 5 | 0x1 << 4 | 0x1 << 3 | 1;
    //         Can_Send_Msg_Func(CANID2, bms_can_buf, 0, can_id, CAN_ID_EXT);
    //         if(Device2.Vkbms_Link.connect_status == COMP_NORMAL)
    //         {
    //             can_id = msg_id << 20 | 0x7 << 17 | Device2.source_id << 11 | 0x1 << 5 | 0x1 << 4 | 0x1 << 3 | 1;
    //             Can_Send_Msg_Func(CANID2, bms_can_buf, 0, can_id, CAN_ID_EXT);
    //         }
    //         bms_heart_time = HAL_GetTick();
    //     }
    // }
        
    
}

/**
  * @file    BMSCanRecvHookFunction
  * @brief   VK智能电池协议
  * @param   none
  * @details 
  * @author  Zhang Sir 
 **/
uint16_t bms_test = 0;
uint16_t bms_re = 0;
uint8_t fmu_send_vkbms_msgid = 0;
void BMSCanRecvHookFunction(uint32_t CanID, uint8_t data[], uint8_t len)
{
    uint32_t source_id = 0, msg_id = 0;
    uint8_t bms_SOF = 0, bms_EOF = 0, frame_num = 0;
    static uint32_t bms1_source_id = 0;
    static uint32_t pack_msg_id = 0;

    Vkbms_Device *Bmspointer = NULL;

    msg_id = (CanID & VK_MSG_MASK_ID) >> 20;
    source_id = (CanID & VK_SRC_MASK_ID) >> 5;
    bms_SOF = (CanID >> 4) & 0x1;
    bms_EOF = (CanID >> 3) & 0x1;
    frame_num = CanID & 0x7;

    if(source_id == bms1_source_id || bms1_source_id == 0)
    {
        bms1_source_id = source_id;
        Bmspointer = &Device1;
        Bmspointer->source_id = source_id;
    }
    else
    {
        Bmspointer = &Device2;
        Bmspointer->source_id = source_id;
    }

    Bmspointer->Vkbms_Link.connect_status = COMP_NORMAL;
    Bmspointer->Vkbms_Link.recv_time = HAL_GetTick();

    //单帧
    if(bms_SOF == 1 && bms_EOF == 1)
    {
        memcpy(&Bmspointer->bms_can_buf[0],&data[0],len);
    }
    //多帧 帧头
    else if(bms_SOF == 1 && bms_EOF == 0)
    {   
        Bmspointer->mul_frame_i = 0;
        Bmspointer->mul_frame_num = 2;
        Bmspointer->if_mul_frame = true;
        Bmspointer->recv_mul_freme_complete = false;
        memcpy(&Bmspointer->bms_can_buf[Bmspointer->mul_frame_i],&data[0],len);
        Bmspointer->mul_frame_i += len;

        pack_msg_id = msg_id;
    }
    // 中间帧
    else if(Bmspointer->if_mul_frame == true && bms_SOF == 0 && bms_EOF == 0 && pack_msg_id == msg_id)
    {
        if(Bmspointer->mul_frame_num == frame_num || ( Bmspointer->mul_frame_num == 0 && frame_num == 1)
            /*&& ((Bmspointer->mul_frame_i + len) <= sizeof(vkbms2))*/ )
        {
            memcpy(&Bmspointer->bms_can_buf[Bmspointer->mul_frame_i],&data[0],len);
            
            if(( Bmspointer->mul_frame_num == 0 && frame_num == 1))
            {
                Bmspointer->mul_frame_num++;
            }
            Bmspointer->mul_frame_i += len;
            Bmspointer->mul_frame_num++;

            if(Bmspointer->mul_frame_num >= 8)
            {
                Bmspointer->mul_frame_num = 0;
            }
        }
        else
        {
            Bmspointer->if_mul_frame = false;
        }
    }
    //帧尾
    else if(bms_SOF == 0 && bms_EOF == 1 && Bmspointer->if_mul_frame == true && pack_msg_id == msg_id)
    {
        memcpy(&Bmspointer->bms_can_buf[Bmspointer->mul_frame_i],&data[0],len);
        Bmspointer->mul_frame_i += len;
        Bmspointer->if_mul_frame = false;

        //bms_test = Get_Crc16(&Bmspointer->bms_can_buf[2], Bmspointer->mul_frame_i - 2); 
        //bms_re =  Bmspointer->bms_can_buf[0] + (Bmspointer->bms_can_buf[1] << 8);
        if(Get_Crc16(&Bmspointer->bms_can_buf[2], Bmspointer->mul_frame_i - 2) == (Bmspointer->bms_can_buf[0] + (Bmspointer->bms_can_buf[1] << 8)))
        {
            Bmspointer->recv_mul_freme_complete = true;
        }
    }

    switch (msg_id)
    {
    case 0X01:
        if(Bmspointer->bms_can_buf[0] == 0x56 && Bmspointer->bms_can_buf[1] == 0x31)
        {
            Bmspointer->ack_to_bms = true;
            Bmspointer->source_id = source_id;
        }
        break;
    case 0X02:
        if(Bmspointer->recv_mul_freme_complete == true)
        {   
            memcpy(&Bmspointer->vk_bms2.voltage, &Bmspointer->bms_can_buf[2], sizeof(vkbms2));
            Bmspointer->recv_mul_freme_complete = false;
        }
        break; 
    case 0X03:
        if(Bmspointer->recv_mul_freme_complete == true)
        {   
            memcpy(&Bmspointer->vk_bms3.bms_company_info, &Bmspointer->bms_can_buf[2], sizeof(vkbms3));
            Bmspointer->recv_mul_freme_complete = false;

            Bmspointer->get_bms3_ack = true;
        }
        break;
    case 0X04:
        memcpy(&Bmspointer->vk_bms4.capacity, &Bmspointer->bms_can_buf[0], sizeof(vkbms4));
        Bmspointer->recv_mul_freme_complete = false;
        Bmspointer->get_bms4_ack = true;
        break;
    case 0X05:
        if(Bmspointer->recv_mul_freme_complete == true)
        {   
            memcpy(&Bmspointer->vk_bms5.health_percent, &Bmspointer->bms_can_buf[2], sizeof(vkbms5));
            Bmspointer->recv_mul_freme_complete = false;
            Bmspointer->get_bms5_ack = true;
        }
        break;
    //秘钥是否匹配
    case 0x07:
        start_msg.key_to_bms = false;
        if(Bmspointer->bms_can_buf[0] == 0)
        {
            start_msg.mos_status = true;
            start_msg.Id_content = 1;
        }
        else
        {
            start_msg.Id_content = 2;
        }
        start_msg.Id = 3;
        start_msg.key_info_checking = true;

        break;
    case 0x08:
         start_msg.Id = 4;
         start_msg.Id_content = Bmspointer->bms_can_buf[0];
         start_msg.key_info_checking = true;
        break;
    default:
        break;
    }
}
/**************************************************************************************/


/************************************tattu*******************************************/

#pragma pack(1)
typedef struct 
{
    unsigned char  canid_prio    :5;
    unsigned short canid_msgid   :16;
    unsigned char canid_som      :1;
    unsigned char canid_srcid    :7;
    /*unsigned char canid_desid:7;
    unsigned char canid_rnr:1;*/
}_TATTU_CANID;
#pragma pack()

_TATTU_DEVICE tattu_device1 = {.Tattu_Link.connect_status = COMP_NOEXIST}, 
               tattu_device2 = {.Tattu_Link.connect_status = COMP_NOEXIST};

void TattuCanRecvHookFunction(uint32_t ttuCanID, uint8_t data[], uint8_t len)
{
    //获取数据中的最后一位
    _TATTU_DEVICE *taptr = NULL;
    uint8_t can_msgid = 0;
    can_msgid = ttuCanID & 0x7f;

    if(can_msgid == 0x16)
    {
        taptr = &tattu_device1;
    }
    else
    {
        taptr = &tattu_device2;
    }

    memcpy(&taptr->ttu_tailbyte, &data[len - 1], sizeof(uint8_t));

    //找到开头
    if(taptr->ttu_tailbyte.tail_start == 1){
        taptr->Tattu_recv_index = 0;
        taptr->Tattu_get_s = true;
    }
    
    //溢出检测
    if(taptr->Tattu_recv_index + len > TATTU_MAXLEN)
    {
        memset(taptr->Tattu_recv_buf,0,taptr->Tattu_recv_index);
        taptr->Tattu_recv_index = 0;
        taptr->Tattu_get_s = false;
    }
    
    //获取到正确的开始位则接收数据
    if(taptr->Tattu_get_s == true){
        //复制有效数据,最后一个字节不是有效数据
        memcpy(&taptr->Tattu_recv_buf[taptr->Tattu_recv_index], data, len-1);
        taptr->Tattu_recv_index += (len-1);
    }

    
    //找到结尾，开始解析
    if(taptr->Tattu_get_s == true && taptr->ttu_tailbyte.tail_end == 1)
    {
        taptr->Tattu_get_s = false;
        
        taptr->Tattu_Link.connect_status = COMP_NORMAL;
        //更新电池数据到来时间
        taptr->Tattu_Link.recv_time = HAL_GetTick();
            
        //如果是单帧完整数据
        if(taptr->ttu_tailbyte.tail_start == 1 || taptr->Tattu_recv_index <= 7)
        {
            //单帧数据不需要校验
        }
        //多帧拼包
        else
        {
            //CRC校验，验证通过，暂不开启
            CCITT_CRC16Init(&taptr->Tattu_recv_buf[2],taptr->Tattu_recv_index-2);
            if(CCITT_CRC16 == (taptr->Tattu_recv_buf[0] + (taptr->Tattu_recv_buf[1]<<8)))
            {
                //避免电池单方面增加协议造成溢出,格式电池12s跟14s兼容有问题，飞控自己做处理
                //后两个字节是自己添加的用来识别电池串数
                if(taptr->Tattu_recv_index-2 <= (sizeof(_TATTU_INFO)-2))
                {
                    //stm32为小段模式，TATTU发送过来的数据为小端模式，可直接使用memcpy
                    //12S
                    if(taptr->Tattu_recv_index-2 == (sizeof(_TATTU_INFO)-2-4-16))
                    {
                        taptr->ttu_inf.tattu_cnum = 12;
                        //前12s信息
                        memcpy(&taptr->ttu_inf,&taptr->Tattu_recv_buf[2],40);
                        //后边信息
                        memcpy(&taptr->ttu_inf.tattu_descapa,&taptr->Tattu_recv_buf[40+2],8);
                        
                    }
                    //添加序列号后的12s
                    else if(taptr->Tattu_recv_index-2 == (sizeof(_TATTU_INFO)-2-4))
                    {
                        taptr->ttu_inf.tattu_cnum = 12;
                        //前12s信息
                        memcpy(&taptr->ttu_inf,&taptr->Tattu_recv_buf[2],40);
                        //后边信息
                        memcpy(&taptr->ttu_inf.tattu_descapa,&taptr->Tattu_recv_buf[40+2],24);
                    }
                    //14s
                    else if(taptr->Tattu_recv_index-2 == (sizeof(_TATTU_INFO)-2-16) || taptr->Tattu_recv_index-2 == (sizeof(_TATTU_INFO)-2))
                    {
                        taptr->ttu_inf.tattu_cnum = 14;
                        
                        //14s信息
                        memcpy(&taptr->ttu_inf,&taptr->Tattu_recv_buf[2],taptr->Tattu_recv_index-2);
                    }
                    
                }else{
                    //清空电池信息数据
                    memset(&taptr->ttu_inf, 0, sizeof(_TATTU_INFO));
                }
            }
        }
        //清理buff
        memset(taptr->Tattu_recv_buf,0,taptr->Tattu_recv_index);
        
        //包数完整重新计数
        taptr->Tattu_recv_index = 0;
    }
}

/*
格氏电池的CRC校验
*/
#define CRC_CCITT_INIT 0xFFFF
#define CRC_CCITT_POLY 0x1021U

uint16_t CCITT_CRC16 = 0;

void CCITT_CRC16Init(uint8_t const *bytes, uint16_t len)
{
    CCITT_CRC16 = CRC_CCITT_INIT;
    CCITT_CRC_ARRAY(bytes, len);
}


void CCITT_CRCStep(uint8_t byte)
{
    uint32_t j;
    CCITT_CRC16 ^= ((uint16_t)byte << 8);
    for (j = 0; j < 8; j++)
    {
        CCITT_CRC16=(CCITT_CRC16 & 0x8000U)?((CCITT_CRC16 << 1) ^ CRC_CCITT_POLY):(CCITT_CRC16 << 1);
    }
}


void CCITT_CRC_ARRAY(uint8_t const * bytes, uint16_t len)
{
    while (len--)   CCITT_CRCStep(*bytes++);
} 

/**************************************************************************************/

Vkbms_Device Device1 = {.Vkbms_Link.connect_status = COMP_NOEXIST};
Vkbms_Device Device2 = {.Vkbms_Link.connect_status = COMP_NOEXIST};

uint8_t bms_group_num = 0; //电池组数

struct BMS_DATA bms_data = {.bms_ss = 0xFFFF}, bms_data2 = {.bms_ss = 0xFFFF};

/**
  * @file    update_bms_data
  * @brief   更新电池信息
  * @param   none
  * @details 
  * @author  Zhang Sir 
 **/
void update_bms_data( void )
{
    //正方电池
    Check_dev_link(&okcell_device1.Okcell_Link,5000,(char *)&okcell_device1.okcell_inf,sizeof(_CELL_INF));
    Check_dev_link(&okcell_device2.Okcell_Link,5000,(char *)&okcell_device2.okcell_inf,sizeof(_CELL_INF));
    //格式电池
    Check_dev_link(&tattu_device1.Tattu_Link,5000,(char *)&tattu_device1.ttu_inf,sizeof(_TATTU_INFO));
    Check_dev_link(&tattu_device2.Tattu_Link,5000,(char *)&tattu_device2.ttu_inf,sizeof(_TATTU_INFO));
    //海盈电池
    Check_dev_link(&Herewin_Link,5000,(char *)&herewin_info,sizeof(herewin_bms));
    //VK电池
    Check_dev_link(&Device1.Vkbms_Link,5000,(char *)&Device1,sizeof(Vkbms_Device));
    Check_dev_link(&Device2.Vkbms_Link,5000,(char *)&Device2,sizeof(Vkbms_Device));

    if ( okcell_device1.Okcell_Link.connect_status == COMP_NORMAL || okcell_device2.Okcell_Link.connect_status == COMP_NORMAL )
    {
        Dev.Bms_Link.connect_status = COMP_NORMAL;

        //第一组电池
        if ( okcell_device1.Okcell_Link.connect_status == COMP_NORMAL )
        {
            bms_data.bms_cycle = okcell_device1.okcell_inf.cell_D3.cell_d3[4];
            if(okcell_device1.okcell_inf.cell_D0.cell_d0[6] >= 18) //正方超18S电池10mv发送
            {
                bms_data.bms_volt = okcell_device1.okcell_inf.cell_D0.cell_d0[0];
            }
            else
            {
                bms_data.bms_volt = okcell_device1.okcell_inf.cell_D0.cell_d0[0] / 10;
            }
            bms_data.bms_temp = okcell_device1.okcell_inf.cell_D0.cell_d0[2];
            bms_data.bms_vs = okcell_device1.okcell_inf.cell_D0.cell_d0[3];
            //正方电池只关心飞控对接异常不让解锁，不关心异常5
            bms_data.bms_ss = ( ( okcell_device1.okcell_inf.cell_D0.cell_d0[5] >> 8 ) != 5 ) ? ( okcell_device1.okcell_inf.cell_D0.cell_d0[5] >> 8 ) : 0;
            bms_data.bms_num = okcell_device1.okcell_inf.cell_D0.cell_d0[6];

            bms_data.bms_v1 = okcell_device1.okcell_inf.cell_D0.cell_d0[7];
            bms_data.bms_v2 = okcell_device1.okcell_inf.cell_D0.cell_d0[8];
            bms_data.bms_v3 = okcell_device1.okcell_inf.cell_D0.cell_d0[9];
            bms_data.bms_v4 = okcell_device1.okcell_inf.cell_D0.cell_d0[10];
            bms_data.bms_v5 = okcell_device1.okcell_inf.cell_D0.cell_d0[11];
            bms_data.bms_v6 = okcell_device1.okcell_inf.cell_D0.cell_d0[12];
            bms_data.bms_v7 = okcell_device1.okcell_inf.cell_D0.cell_d0[13];
            bms_data.bms_v8 = okcell_device1.okcell_inf.cell_D0.cell_d0[14];
            bms_data.bms_v9 = okcell_device1.okcell_inf.cell_D0.cell_d0[15];
            bms_data.bms_v10 = okcell_device1.okcell_inf.cell_D0.cell_d0[16];
            bms_data.bms_v11 = okcell_device1.okcell_inf.cell_D0.cell_d0[17];
            bms_data.bms_v12 = okcell_device1.okcell_inf.cell_D0.cell_d0[18];
            bms_data.bms_v13 = okcell_device1.okcell_inf.cell_D0.cell_d0[19];
            bms_data.bms_v14 = okcell_device1.okcell_inf.cell_D0.cell_d0[20];
            bms_data.bms_v15 = okcell_device1.okcell_inf.cell_D0.cell_d0[21];
            bms_data.bms_v16 = okcell_device1.okcell_inf.cell_D0.cell_d0[22];
            bms_data.bms_v17 = okcell_device1.okcell_inf.cell_D0.cell_d0[23];
            bms_data.bms_v18 = okcell_device1.okcell_inf.cell_D0.cell_d0[24];
            bms_data.bms_v19 = okcell_device1.okcell_inf.cell_D0.cell_d0[25];
            bms_data.bms_v20 = okcell_device1.okcell_inf.cell_D0.cell_d0[26];
            bms_data.bms_v21 = okcell_device1.okcell_inf.cell_D0.cell_d0[27];
            bms_data.bms_v22 = okcell_device1.okcell_inf.cell_D0.cell_d0[28];
            bms_data.bms_v23 = okcell_device1.okcell_inf.cell_D0.cell_d0[29];
            bms_data.bms_v24 = okcell_device1.okcell_inf.cell_D0.cell_d0[30];
            bms_data.bms_v25 = okcell_device1.okcell_inf.cell_D0.cell_d0[31];
            bms_data.bms_v26 = okcell_device1.okcell_inf.cell_D0.cell_d0[32];

            bms_data.bms_ids[0] = okcell_device1.okcell_inf.cell_P3.cell_p3[0];
            bms_data.bms_ids[1] = okcell_device1.okcell_inf.cell_P3.cell_p3[1];
            for(int i = 1; i< 11; i++){
                // bms_data.bms_ids[2*i] = ((okcell_device1.okcell_inf.cell_P3.cell_p3[2 + i] >> 4) & 0xf) + '0';
                // bms_data.bms_ids[2*i+1] = (okcell_device1.okcell_inf.cell_P3.cell_p3[2 + i] & 0xf )+ '0';
                bms_data.bms_ids[2*i] = ((okcell_device1.okcell_inf.cell_P3.cell_p3[1 + i] >> 4) & 0xf) + '0';
                bms_data.bms_ids[2*i+1] = (okcell_device1.okcell_inf.cell_P3.cell_p3[1 + i] & 0xf )+ '0';
            }
            //memcpy( bms_data.bms_ids, "okcell", 6 );
            bms_data.bms_ac = okcell_device1.okcell_inf.cell_D0.cell_d0[1];
            bms_data.serial_num = FAC_OKCELL;

            //注册
            if(StrArrayNull( &bms_data.bms_ids[0], sizeof( bms_data.bms_ids ) ) == false && dev_bms1.regist.sn == false)
                regist_dev_info(&dev_bms1,DEVICE_BMS1,false,(char *)bms_data.bms_ids,32,NULL,0,NULL,0,"okcell1",8);
        }
        else
        {
            memset( &bms_data, 0, sizeof( bms_data ) );
        }

        //第二组电池
        if ( okcell_device2.Okcell_Link.connect_status == COMP_NORMAL )
        {
            bms_data2.bms_cycle = okcell_device2.okcell_inf.cell_D3.cell_d3[4];
            if(okcell_device2.okcell_inf.cell_D0.cell_d0[6] >= 18)
            {
                bms_data2.bms_volt = okcell_device2.okcell_inf.cell_D0.cell_d0[0];
            }
            else
            {
                bms_data2.bms_volt = okcell_device2.okcell_inf.cell_D0.cell_d0[0] / 10;
            }
            bms_data2.bms_temp = okcell_device2.okcell_inf.cell_D0.cell_d0[2];
            bms_data2.bms_vs = okcell_device2.okcell_inf.cell_D0.cell_d0[3];
            //正方电池只关心飞控对接异常不让解锁，不关心异常5
            bms_data2.bms_ss = ( ( okcell_device2.okcell_inf.cell_D0.cell_d0[5] >> 8 ) != 5 ) ? ( okcell_device2.okcell_inf.cell_D0.cell_d0[5] >> 8 ) : 0;
            bms_data2.bms_num = okcell_device2.okcell_inf.cell_D0.cell_d0[6];

            bms_data2.bms_v1 = okcell_device2.okcell_inf.cell_D0.cell_d0[7];
            bms_data2.bms_v2 = okcell_device2.okcell_inf.cell_D0.cell_d0[8];
            bms_data2.bms_v3 = okcell_device2.okcell_inf.cell_D0.cell_d0[9];
            bms_data2.bms_v4 = okcell_device2.okcell_inf.cell_D0.cell_d0[10];
            bms_data2.bms_v5 = okcell_device2.okcell_inf.cell_D0.cell_d0[11];
            bms_data2.bms_v6 = okcell_device2.okcell_inf.cell_D0.cell_d0[12];
            bms_data2.bms_v7 = okcell_device2.okcell_inf.cell_D0.cell_d0[13];
            bms_data2.bms_v8 = okcell_device2.okcell_inf.cell_D0.cell_d0[14];
            bms_data2.bms_v9 = okcell_device2.okcell_inf.cell_D0.cell_d0[15];
            bms_data2.bms_v10 = okcell_device2.okcell_inf.cell_D0.cell_d0[16];
            bms_data2.bms_v11 = okcell_device2.okcell_inf.cell_D0.cell_d0[17];
            bms_data2.bms_v12 = okcell_device2.okcell_inf.cell_D0.cell_d0[18];
            bms_data2.bms_v13 = okcell_device2.okcell_inf.cell_D0.cell_d0[19];
            bms_data2.bms_v14 = okcell_device2.okcell_inf.cell_D0.cell_d0[20];
            bms_data2.bms_v15 = okcell_device2.okcell_inf.cell_D0.cell_d0[21];
            bms_data2.bms_v16 = okcell_device2.okcell_inf.cell_D0.cell_d0[22];
            bms_data2.bms_v17 = okcell_device2.okcell_inf.cell_D0.cell_d0[23];
            bms_data2.bms_v18 = okcell_device2.okcell_inf.cell_D0.cell_d0[24];
            bms_data2.bms_v19 = okcell_device2.okcell_inf.cell_D0.cell_d0[25];
            bms_data2.bms_v20 = okcell_device2.okcell_inf.cell_D0.cell_d0[26];
            bms_data2.bms_v21 = okcell_device2.okcell_inf.cell_D0.cell_d0[27];
            bms_data2.bms_v22 = okcell_device2.okcell_inf.cell_D0.cell_d0[28];
            bms_data2.bms_v23 = okcell_device2.okcell_inf.cell_D0.cell_d0[29];
            bms_data2.bms_v24 = okcell_device2.okcell_inf.cell_D0.cell_d0[30];
            bms_data2.bms_v25 = okcell_device2.okcell_inf.cell_D0.cell_d0[31];
            bms_data2.bms_v26 = okcell_device2.okcell_inf.cell_D0.cell_d0[32];

            bms_data2.bms_ids[0] = okcell_device1.okcell_inf.cell_P3.cell_p3[0];
            bms_data2.bms_ids[1] = okcell_device1.okcell_inf.cell_P3.cell_p3[1];
            for(int i = 1; i< 11; i++){
                bms_data2.bms_ids[2*i] = ((okcell_device2.okcell_inf.cell_P3.cell_p3[1 + i] >> 4) & 0xf) + '0';
                bms_data2.bms_ids[2*i+1] = (okcell_device2.okcell_inf.cell_P3.cell_p3[1 + i] & 0xf )+ '0';
            }
            //memcpy( bms_data2.bms_ids, "okcell2", 7 );
            bms_data2.bms_ac = okcell_device2.okcell_inf.cell_D0.cell_d0[1];
            bms_data2.serial_num = FAC_OKCELL;

            if(StrArrayNull( &bms_data2.bms_ids[0], sizeof( bms_data2.bms_ids ) ) == false && dev_bms2.regist.sn == false)
                regist_dev_info(&dev_bms2,DEVICE_BMS2,false,(char *)bms_data2.bms_ids,32,NULL,0,NULL,0,"okcell2",8);
        }
        else
        {
            memset( &bms_data2, 0, sizeof( bms_data2 ) );
        }
    }
    else if(tattu_device1.Tattu_Link.connect_status == COMP_NORMAL || tattu_device2.Tattu_Link.connect_status == COMP_NORMAL)
    {
        Dev.Bms_Link.connect_status = COMP_NORMAL;
        
        if(tattu_device1.Tattu_Link.connect_status  == COMP_NORMAL)
        {
            group_num = 1;
            bms_data.bms_cycle = tattu_device1.ttu_inf.tattu_cycle;
            bms_data.bms_volt = tattu_device1.ttu_inf.tattu_volt /10;
            bms_data.bms_temp = tattu_device1.ttu_inf.tattu_temp * 10;
            bms_data.bms_vs = tattu_device1.ttu_inf.tattu_perc;
            bms_data.bms_ss = 0;//ttu_inf.def_info[24] & 0xc00;//格式电池只关心部分报警不让解锁
            bms_data.bms_num = tattu_device1.ttu_inf.tattu_cnum;
            bms_data.bms_v1 = tattu_device1.ttu_inf.tattu_v1;
            bms_data.bms_v2 = tattu_device1.ttu_inf.tattu_v2;
            bms_data.bms_v3 = tattu_device1.ttu_inf.tattu_v3;
            bms_data.bms_v4 = tattu_device1.ttu_inf.tattu_v4;
            bms_data.bms_v5 = tattu_device1.ttu_inf.tattu_v5;
            bms_data.bms_v6 = tattu_device1.ttu_inf.tattu_v6;
            bms_data.bms_v7 = tattu_device1.ttu_inf.tattu_v7;
            bms_data.bms_v8 = tattu_device1.ttu_inf.tattu_v8;
            bms_data.bms_v9 = tattu_device1.ttu_inf.tattu_v9;
            bms_data.bms_v10 = tattu_device1.ttu_inf.tattu_v10;
            bms_data.bms_v11 = tattu_device1.ttu_inf.tattu_v11;
            bms_data.bms_v12 = tattu_device1.ttu_inf.tattu_v12;
            bms_data.bms_v13 = tattu_device1.ttu_inf.tattu_v13;
            bms_data.bms_v14 = tattu_device1.ttu_inf.tattu_v14;
            memcpy(bms_data.bms_ids,&tattu_device1.ttu_inf.tuattu_id[0],16);
            //memcpy(bms_data.bms_ids, "Tattu1", 6);
            bms_data.bms_ac = tattu_device1.ttu_inf.tattu_cur;
            bms_data.serial_num = FAC_TATTU;

            if(StrArrayNull( &bms_data.bms_ids[0], sizeof( bms_data.bms_ids ) ) == false && dev_bms1.regist.sn == false)
                regist_dev_info(&dev_bms1,DEVICE_BMS1,false,(char *)bms_data.bms_ids,16,NULL,0,NULL,0,"tattu1",7);
        }
        else
        {
            memset( &bms_data, 0, sizeof(bms_data));
        }

        if(tattu_device2.Tattu_Link.connect_status == COMP_NORMAL)
        {
            group_num = 2;
            bms_data2.bms_cycle = tattu_device2.ttu_inf.tattu_cycle;
            bms_data2.bms_volt = tattu_device2.ttu_inf.tattu_volt / 10;
            bms_data2.bms_temp = tattu_device2.ttu_inf.tattu_temp * 10;
            bms_data2.bms_vs = tattu_device2.ttu_inf.tattu_perc;
            bms_data2.bms_ss = 0;//ttu_inf.def_info[24] & 0xc00;//格式电池只关心部分报警不让解锁
            bms_data2.bms_num = tattu_device2.ttu_inf.tattu_cnum;
            bms_data2.bms_v1 = tattu_device2.ttu_inf.tattu_v1;
            bms_data2.bms_v2 = tattu_device2.ttu_inf.tattu_v2;
            bms_data2.bms_v3 = tattu_device2.ttu_inf.tattu_v3;
            bms_data2.bms_v4 = tattu_device2.ttu_inf.tattu_v4;
            bms_data2.bms_v5 = tattu_device2.ttu_inf.tattu_v5;
            bms_data2.bms_v6 = tattu_device2.ttu_inf.tattu_v6;
            bms_data2.bms_v7 = tattu_device2.ttu_inf.tattu_v7;
            bms_data2.bms_v8 = tattu_device2.ttu_inf.tattu_v8;
            bms_data2.bms_v9 = tattu_device2.ttu_inf.tattu_v9;
            bms_data2.bms_v10 = tattu_device2.ttu_inf.tattu_v10;
            bms_data2.bms_v11 = tattu_device2.ttu_inf.tattu_v11;
            bms_data2.bms_v12 = tattu_device2.ttu_inf.tattu_v12;
            bms_data2.bms_v13 = tattu_device2.ttu_inf.tattu_v13;
            bms_data2.bms_v14 = tattu_device2.ttu_inf.tattu_v14;
            memcpy(bms_data2.bms_ids,&tattu_device2.ttu_inf.tuattu_id[0],16);
            //memcpy(bms_data2.bms_ids, "Tattu2", 6);
            bms_data2.bms_ac = tattu_device2.ttu_inf.tattu_cur;
            bms_data2.serial_num = FAC_TATTU;

            if(StrArrayNull( &bms_data2.bms_ids[0], sizeof( bms_data2.bms_ids ) ) == false && dev_bms2.regist.sn == false)
                regist_dev_info(&dev_bms2,DEVICE_BMS2,false,(char *)bms_data2.bms_ids,16,NULL,0,NULL,0,"tattu2",7);
        }
        else
        {
            memset( &bms_data2, 0, sizeof( bms_data2 ) );
        }
    }
    else if ( Herewin_Link.connect_status == COMP_NORMAL )
    {
        Dev.Bms_Link.connect_status = COMP_NORMAL;
        group_num = 1;

        bms_data.bms_cycle = herewin_info.circulation_num;
        bms_data.bms_volt = herewin_info.total_vol;
        
        if(herewin_info.get_temp_flag == true)
            bms_data.bms_temp = ( ( herewin_info.battery_temp[0] + herewin_info.battery_temp[1] + herewin_info.battery_temp[2] ) / 3 - 40 ) * 10;
        
        bms_data.bms_vs = herewin_info.SOC_info;

        bms_data.bms_ss = herewin_info.warn_info;
        bms_data.bms_num = herewin_info.battery_num;

        bms_data.bms_v1 = herewin_info.battery_vol[0];
        bms_data.bms_v2 = herewin_info.battery_vol[1];
        bms_data.bms_v3 = herewin_info.battery_vol[2];
        bms_data.bms_v4 = herewin_info.battery_vol[3];
        bms_data.bms_v5 = herewin_info.battery_vol[4];
        bms_data.bms_v6 = herewin_info.battery_vol[5];
        bms_data.bms_v7 = herewin_info.battery_vol[6];
        bms_data.bms_v8 = herewin_info.battery_vol[7];
        bms_data.bms_v9 = herewin_info.battery_vol[8];
        bms_data.bms_v10 = herewin_info.battery_vol[9];
        bms_data.bms_v11 = herewin_info.battery_vol[10];
        bms_data.bms_v12 = herewin_info.battery_vol[11];
        bms_data.bms_v13 = herewin_info.battery_vol[12];
        bms_data.bms_v14 = herewin_info.battery_vol[13];
        memcpy( bms_data.bms_ids, "herewin", 7 );
        bms_data.bms_ac = herewin_info.tolal_ele;
        bms_data.serial_num = FAC_HEREWIN;

        if(dev_bms1.regist.dev == false)
            regist_dev_info(&dev_bms1,DEVICE_BMS1,false,NULL,0,NULL,0,NULL,0,"herewin",8);
    }
    else if(Device1.Vkbms_Link.connect_status == COMP_NORMAL || Device2.Vkbms_Link.connect_status == COMP_NORMAL)
    {
        Dev.Bms_Link.connect_status = COMP_NORMAL;

        //第一组电池
        if ( Device1.Vkbms_Link.connect_status == COMP_NORMAL )
        {
            group_num = 1;
            bms_data.bms_cycle = Device1.vk_bms5.circulation_time;
            bms_data.bms_volt = Device1.vk_bms2.voltage;
            bms_data.bms_temp = Device1.vk_bms2.tempture;
            bms_data.bms_vs = Device1.vk_bms2.persent / 10;
            bms_data.bms_ss = Device1.vk_bms2.warn_flag;
            bms_data.bms_num = Device1.vk_bms2.bms_num;

            memcpy(&bms_data.bms_v1,&Device1.vk_bms2.bms_v1,26 * 2);
            
            memcpy(&bms_data.bms_ids[0],&Device1.vk_bms3.bms_id[0],20);
            // bms_data.bms_ids[0] = Device1.vk_bms3.bms_id[0];
            // bms_data.bms_ids[1] = Device1.vk_bms3.bms_id[1];
            // for(int i = 1; i< 11; i++){
            //     bms_data.bms_ids[2*i] = ((Device1.vk_bms3.bms_id[1 + i] >> 4) & 0xf) + '0';
            //     bms_data.bms_ids[2*i+1] = (Device1.vk_bms3.bms_id[1 + i] & 0xf )+ '0';
            // }
            bms_data.bms_ac = (short)(Device1.vk_bms2.current / 10);
            bms_data.serial_num = FAC_VK_BMS;
            // if( Device1.vk_bms3.bms_type_info[0] == 'S' && Device1.vk_bms3.bms_type_info[0] == 'H'
            // && Device1.vk_bms3.bms_type_info[0] == 'A' && Device1.vk_bms3.bms_type_info[0] == '1')
            // {
            //     bms_data.serial_num = 11; //???
            // }

            //厂家还没加
            if(StrArrayNull( &bms_data.bms_ids[0], sizeof( bms_data.bms_ids ) ) == false && dev_bms1.regist.sn == false)
                regist_dev_info(&dev_bms1,DEVICE_BMS1,false,(char *)bms_data.bms_ids,32,NULL,0,NULL,0,"vk",3);
        }
        else
        {
            memset( &Device1, 0, sizeof( Device1 ) );
        }

        //第二组电池
        if ( Device2.Vkbms_Link.connect_status == COMP_NORMAL )
        {
            group_num = 2;
            bms_data2.bms_cycle = Device2.vk_bms5.circulation_time;
            bms_data2.bms_volt = Device2.vk_bms2.voltage;
            bms_data2.bms_temp = Device2.vk_bms2.tempture;
            bms_data2.bms_vs = Device2.vk_bms2.persent / 10;
            bms_data2.bms_ss = Device2.vk_bms2.warn_flag;
            bms_data2.bms_num = Device2.vk_bms2.bms_num;

            memcpy(&bms_data2.bms_v1,&Device2.vk_bms2.bms_v1,26 * 2);
            
            memcpy(&bms_data2.bms_ids[0],&Device2.vk_bms3.bms_id[0],20);

            bms_data2.bms_ac = (short)(Device2.vk_bms2.current / 10);
            bms_data2.serial_num = FAC_VK_BMS;
            // if( Device2.vk_bms3.bms_type_info[0] == 'S' && Device2.vk_bms3.bms_type_info[0] == 'H'
            // && Device2.vk_bms3.bms_type_info[0] == 'A' && Device2.vk_bms3.bms_type_info[0] == '1')
            // {
            //     bms_data2.serial_num = 11; //???
            // }
            if(StrArrayNull( &bms_data2.bms_ids[0], sizeof( bms_data2.bms_ids ) ) == false && dev_bms2.regist.sn == false)
                regist_dev_info(&dev_bms2,DEVICE_BMS2,false,(char *)bms_data2.bms_ids,32,NULL,0,NULL,0,"vk",3);
        }
        else
        {
            memset( &bms_data2, 0, sizeof( bms_data2 ) );
        }   
    }
    else
    {
        if ( Dev.Bms_Link.connect_status == COMP_NORMAL )
        {
            Dev.Bms_Link.connect_status = COMP_LOST;
            //memset(&bms_data, 0, sizeof(bms_data));
            //状态未置异常
            bms_data.bms_ss = 0xFFFF;
        }
    }
}

/**
  * @file    bms_function
  * @brief   智能电池检测函数
  * @param   none
  * @details 
  * @author  Zhang Sir 
 **/
void bms_function()
{
    static uint32_t bms_time = 0;
    static uint32_t bms_5hz_time = 0;
    if(Check_Timer_Ready(&bms_time,_10_HZ_))
    {
        update_bms_data();
        send_msg_to_VKbms();
    }
    
    if(Check_Timer_Ready(&bms_5hz_time,_5_HZ_))
    {
        //给智能电池发送上电信息
        //send_msg_to_okcell(); 
        send_msg_to_herewin();
    }
}