/**
 * @file        xieneng_can_component.h
 * @brief
 * @details     component: mqtt接收消息处理,toolkit
 * @author      JHC
 * @date        2022-10-21
 * @version     V1.0
 * @copyright   Copyright (C) 2001-2022 BMSER Technology
********************************************************************************
 * @attention
 * 系统平台: LINUX4.15 \n
 * @par :
 * <table>
 * <tr><th>Date        <th>Version  <th>Author    <th>Description
 * <tr><td>2022-10-21  <td>1.0      <td>JHC  <td>
 * </table>
 *
********************************************************************************
*/
#ifndef XIENENG_CAN_COMPONENT_H_
#define XIENENG_CAN_COMPONENT_H_

#include <string.h>
#include <syslog.h>
#include "bmser_mqtt.h"
#include "bmser_ems_db_control_db.h"

/******************MACRO********************/
#define DATA_LEN 256
#define CAN_BUF_LEN 8
#define BUF_LEN 4096 
#define TERM_ADDR_MASK 0xff //地址
#define SHM_SIZE 0x10000 * 2 //映射内存
#define READ_DATA_LEN 1024 //单次读取DB数量最大值
#define MAX_FLOW_DATA_LEN 512 // 单次处理消息流data长度最大值

typedef struct
{
    unsigned char layer;
    unsigned char dev_id;
    unsigned char func;
    unsigned char start_addr_hi;
    unsigned char start_addr_lo;
    unsigned char reg_cnt_hi;
    unsigned char reg_cnt_lo;
    unsigned char data[0];
} __attribute__((packed)) xieneng_header_t;

typedef struct
{
    unsigned short term_addr;
    unsigned short start_addr;
    unsigned short reg_cnt;
    unsigned short period; // 周期
    long long last_send;   // 上次发送时
    bool used;             // 节点是否在使用中
} period_node_t;

typedef struct
{
    period_node_t *nodes;
    unsigned short size; // 总的节点数目
    unsigned short cnt;  // 在使用的节点数目
} period_table_t;

/******** td_mqtt ********/
typedef enum
{
    DATA_TYPE_CELL_VOL,             // 单体电压详细信息
    DATA_TYPE_CELL_TEMP,            // 单体温度详细信息
    DATA_TYPE_SUMMARY_TOTAL_VOL,
    DATA_TYPE_SUMMARY_TOTAL_CURRENT,
    DATA_TYPE_SUMMARY_SOC,
    DATA_TYPE_SUMMARY_POWER,
    DATA_TYPE_SUMMARY_HIGHEST_VOL,
    DATA_TYPE_SUMMARY_LOWEST_VOL,
    DATA_TYPE_SUMMARY_AVE_VOL,
    DATA_TYPE_SUMMARY_HIGHEST_TEMP,
    DATA_TYPE_SUMMARY_LOWEST_TEMP,
    DATA_TYPE_SUMMARY_AVE_TEMP,
    DATA_TYPE_ANODE_TEMP,           // 正极柱温度详细信息
    DATA_TYPE_CATHODE_TEMP,         // 负极柱温度详细信息
    DATA_TYPE_HVBOX_TEMP,
    DATA_TYPE_SUMMARY_ALL,          // 概要数据(请求)
    DATA_TYPE_OUTLIER_ANALYSIS,
    DATA_TYPE_MAX,
} TD_MQTT_DATA_TYPE_ENUM;

typedef struct
{
    uint8_t    reserved;    // 预留
    uint8_t    datatype;    // 数据类型
    uint8_t    dev_id;      // 设备id
    uint8_t    dev_type;    // 设备类型
    uint16_t   data_count;  // 数据个数
    uint8_t    data[0];     // 数据buf
} datainsert_header_t;

// 概要数据mqtt DbAddr - datatype对应表，用于确定datatype
typedef struct
{
    uint32_t DbAddr;        // 共享内存数据地址
    int32_t  dataType;      // 数据具体的类型，用于确定对应的数据表
} summary_datainsert_cfg_info;

/************************************* CANRBUS ************************************/
///< 0:保留 1:写寄存器 2:写寄存器响应 3:读寄存器 4:读寄存器响应 5:差错响应 6:消息流 7:消息流响应
#define GET_FUNC_CODE(canId)  ((canId & 0x70000) >> 16)

/*********************************CANRBUS 协议类型*********************************/
#define CANRBUS_PROTOCOL_TYPE_J1939           (0)  /*SAE-J1939-21*/
#define CANRBUS_PROTOCOL_TYPE_BMSER           (1)  /*内部自定义协议*/

/*********************************消息流CAN ID解析*********************************/
///< 功能扩展位，用于区分CANRBUS协议与J1939协议
#define GET_EXTFUNC_ID(canId)   ((canId & 0x10000000) >> 28)
///< 协议标志位
#define GET_PROTOCOL_TYPE(canId)  ((canId & 0x2000000) >> 25)
///< 0:升级 1:文件操作 2:读写DB 3:DEBUG 
#define GET_WORK_ID(canId)  ((canId & 0x180) >> 7)
#define GET_UPDATE_TYPE(canId)  ((canId & 0x40) >> 6)
///< 组包序号
#define GET_PACK_ID(canId)  (canId & 0x3F)
#define GET_BMU_ID(canId)   ((canId & 0xFE00) >> 9)
#define GET_BCU_ID(canId)   ((canId & 0x1F80000) >> 19)
#define GET_BAU_ID(canId)   ((canId & 0xE000000) >> 25)

typedef enum
{
    FUNC_CODE_RESERVE,
    FUNC_CODE_WRITE,
    FUNC_CODE_WRITE_RSP,
    FUNC_CODE_READ,
    FUNC_CODE_READ_RSP,
    FUNC_CODE_ERR_RSP,
    FUNC_CODE_MSG_FLOW,
    FUNC_CODE_MSG_FLOW_RSP,
}CANRBUS_FUNC_CODE_ENUM;

typedef enum
{
    WORK_ID_UPDATE,
    WORK_ID_FILE,
    WORK_ID_DB,
    WORK_ID_DEBUG,
}WORK_ID_ENUM;

#define UP_CMD_TYPE          0xD0
#define UP_CMD_TYPE_V50      0xD1
#define MAX_UPDATE_DEV_NUM   128
#define ENDIAN_TYPE_CONVERT_16(num)  ((((uint16_t)(num) & 0xff00U) >> 8) | \
                                      (((uint16_t)(num) & 0x00ffU) << 8))
typedef struct
{
    uint8_t buf[DATA_LEN];       /*消息内容*/
    uint8_t flag[DATA_LEN/8];      /*消息帧号是否已经接收的标志位*/
    uint16_t validPackNum;
    uint16_t dataLen;
    uint32_t combinaId;//组合ID将总控 主控 从控ID组合作为找各个设备组包的依据
    uint64_t lastMsgFlowRspTime;
}MSG_FLOW_INFO_STRU;

#pragma pack(1)
typedef struct
{
    uint8_t  func;
    //以下信息只有func为DB操作时有效
    uint8_t  layer;
    uint8_t  dev_id;
    uint16_t start_addr;
    //以下信息只有func等于6或者7时才有效
    uint8_t msgFlowBauId;
    uint8_t msgFlowBcuId;
    uint8_t msgFlowBmuId;
    uint8_t msgFlowWorkId;
    uint8_t msgFlowUpdateType;
    //实际数据起始字节
    uint8_t data[0];
}canrbus_header_t;
#pragma pack()

/***************************以下为CANRBUS 0x7e2特殊帧定义*******************************************/
#define PROTOCOL_VERSION_CHECK        0x7E2
#define PROTOCOL_VERSION_CHECK_RES    0x7E3
#define CHECK_VERSION_CMD             0x00

typedef enum
{
    CAN_BUS_VER_0x41=1,
    CAN_BUS_VER_0x50,
    CAN_BUS_VER_0x60,

    CAN_BUS_VER_BUTT
}PROTOCOL_VERSION_ENUM;

#pragma pack(1)
typedef struct
{
    uint8_t cmd;                /*0x7e2命令*/
    uint8_t devType;            /*0x7e2设备类型*/
    uint8_t devId;              /*0x7e2设备ID*/
    uint16_t protocolVersion;   /*协议版本*/
    uint16_t dbVersion;         /*DB协议版本*/
    uint8_t reserved;
}CANRBUS_PROTORCOL_MSG_BUF_STRU;

typedef struct
{
    int bau_ver;                           /* bau_canrbus 版本 */
    int bcu_ver;                           /* bcu_canrbus 版本 */
    int bmu_ver;                           /* bmu_canrbus 版本 */
    int bdu_ver;                           /* bdu_canrbus 版本 */
}bmser_canrbus_ver_s;
#pragma pack()
/********************************CANRBUS 0x7e2特殊帧定义end*******************************************/

/**
 * @brief       canport名枚举转char
 * @param[in]   portIndex
 * @return      char
 * @retval      "CANBUS_0","CANBUS_1"
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023/07/06       XXXXX        创建初始版本     \n
 */
const char *port_enum2char(int portIndex);

/**
 * @brief       数据批量转小端
 * @param[in]   *data   数据
 * @param[in]   length  数据个数
 * @return
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023/08/24       qzy        创建初始版本     \n
 */
void convertArrayToLittleEndian(uint16_t *data, uint16_t length);

/**
 * @brief       解析canrbusMsgFlowHead
 * @param[in]   canid
 * @return      返回值
 * @retval      0:success
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023/07/06       XXXXX        创建初始版本     \n
 */
int can_canrbusMsgFlowHeader(uint32_t canId, canrbus_header_t *canrbusHeadr);

/**
 * @brief       从缓存中获取数据
 * @param[in]   canObjId    CAN 对象 ID
 * @param[in]   bankId      bankId
 * @param[in]   rackId      rackId
 * @param[in]   start_addr  起始地址
 * @param[in]   reg_cnt     数量
 * @param[out]  buf         存储数据buf
 * @param[in]   len         长度
 * @return      int         成功时返回读取的字节数，失败时返回 -1
 * @par         修改日志:
 * Date         Author     Description           \n
 * 2023/07/06  XXXXX      创建初始版本     \n
 * 2023/12/16  JHC        多堆重构       \n
 */
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);

/**
 * @brief       更新数据至缓存
 * @param[in]   canObjId    CAN 对象 ID
 * @param[in]   bankId      bankId
 * @param[in]   rackId      rackId
 * @param[in]   start_addr  起始地址
 * @param[in]   reg_cnt     数量
 * @param[in]   data        存储数据buf
 * @param[in]   len         长度
 * @return      int         成功时返回读取的字节数，失败时返回 -1
 * @par         修改日志:
 * Date         Author     Description           \n
 * 2023/07/06  XXXXX      创建初始版本     \n
 * 2023/08/23  qzy        互斥锁放到接口外,term_addr增加校验      \n
 * 2023/12/16  jhc        多堆重构 \n
 */
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);

/**
 * @brief 发送数据到CAN总线
 * @param[in]   canObjId    CAN对象ID
 * @param[in]   term_addr   终端地址
 * @param[in]   func        功能码
 * @param[in]   start_addr  起始地址
 * @param[in]   reg_cnt     寄存器数量
 * @param[in]   data        data
 * @param[in]   len         数据长度
 * @return      int         0:success; -1:fail
 * @par         修改日志:
 * Date         Author     Description           \n
 * 2023/07/06  XXXXX      创建初始版本     \n
 */
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);

/**
 * @brief       TOPIC_BINARY_FLOW(binaryFlow) 处理
 * @param[in]   mqtt_msg
 * @return      返回值
 * @retval      0:success; -1:fail
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023/07/06       XXXXX        创建初始版本     \n
 */
int xieneng_can_send_to_dev(const struct mosquitto_message *mqtt_msg);

/**
 * @brief       TOPIC_BINARY_CMD(binary_cmd) 处理
 * @param[in]   mqtt_msg
 * @param[in]   uint16_t devId
 * @return      返回值
 * @retval      0:success; -1:fail
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023/07/06       XXXXX        创建初始版本     \n
 * 2023/12/16        jhc        多堆重构 \n
 */
int xieneng_can_msg_handle_binary(uint16_t devId, const struct mosquitto_message *mqtt_msg);

/**
 * @brief       TOPIC_SEND_RGLT_SIGNAL_RAW_DATA_7FF(Set_Rglt_7FF_Raw) 处理
 * @param[in]   mqtt_msg
 * @return      返回值
 * @retval      0:success; -1:fail
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023/07/06       XXXXX        创建初始版本     \n
 */
#ifdef WITH_BMSER_PRODUCT_TEST
int xieneng_can_send_to_dev_7ff(const struct mosquitto_message *mqtt_msg);
#endif

/**
 * @brief       TOPIC_SET_PROJECT_PARA (systemParameterConfig) 处理
 * @param[in]   mqtt_msg
 * @return      返回值
 * @retval      0:success; -1:fail
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023/07/06       XXXXX        创建初始版本     \n
 */
int xieneng_can_set_config_para(const struct mosquitto_message *mqtt_msg);
#endif 

/**
 * @brief       根据DbAddr确定DataType,用于向td_mqtt发布
 * @param[in]   dbAddr
 * @return      返回值
 * @retval      0:success; -1:fail
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023/07/06       XXXXX        创建初始版本     \n
 */
int32_t getDataTypeByDbAddr(uint32_t dbAddr);

/**
 * @brief       请求canrbus协议版本；
 * @param[in]   portIdx canid
 * @param[in]   rack_num 簇数
 * @return      返回值
 * @retval      true:success; -1:fail
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023/10/30       qzy        创建初始版本     \n
 */
int bmser_can_canrbus_protocol_ver_req(uint32_t portIdx, uint8_t rack_num);

/**
 * @brief       解析并获取canrbus协议版本
 * @param[in]   CanMsg
 * @return      返回值
 * @retval      
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023/10/30       qzy        创建初始版本     \n
 */
int bmser_can_get_canrbus_protocol_ver(CanMsg *rxcan);

/**
 * @brief       获取canrbus协议版本mqtt响应
 * @return      返回值
 * @retval      
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023/10/31       qzy        创建初始版本     \n
 */
int bmser_canrbus_protocol_ver_publish();