#ifndef __BMSER_CANRBUS_H__
#define __BMSER_CANRBUS_H__

#include "define_base.h"

/* devType 设备类型(V41目的地址广播类型), 为同一层级下的不同设备类型 */
#define BROADCAST_LEVEL_1_SLAVE                   1u        /*广播层级1的从控(BMU)*/
#define BROADCAST_LEVEL_1_BALANCE16               2u        /*广播层级1的均衡1.6*/
#define BROADCAST_LEVEL_2_MASTER                  1u        /*广播层级2的主控*/
#define BROADCAST_LEVEL_2_IBU                     2u        /*广播层级2的一体机(BCU)*/
#define BROADCAST_LEVEL_3_HUB                     1u        /*广播层级3的总控(BAU)*/

#define CANRBUS_FLOW_HEADER_V41                 0xD0        /*4.1传输框架起始帧数据*/
#define CANRBUS_FLOW_HEADER_V50                 0xD1        /*5.0传输框架起始帧数据*/

#define ONCE_DATA_SIZE                           192                                   /*一次传输的有效数据体最大长度*/
#define ONCE_PACKED_DATA_SIZE_V40  (ONCE_DATA_SIZE+TRANSFER_FRAMEWORK_LENGTH + 10)     /*一次传输的最大包的长度(V40协议)*/
#define ONCE_PACKED_DATA_SIZE_V50  (ONCE_DATA_SIZE+TRANSFER_FRAMEWORK_LENGTH_V50 + 10) /*一次传输的最大包的长度(V50协议)*/
#define ONCE_PACKED_DATA_SIZE      MAX(ONCE_PACKED_DATA_SIZE_V40, ONCE_PACKED_DATA_SIZE_V50)/*一次传输的最大包的长度*/

#define TRANSFER_FRAMEWORK_LENGTH_V50              17       /*5.0传输框架字节数(包含CRC)*/
#define TRANSFER_FRAMEWORK_LENGTH                   7       /*4.1传输框架字节数(包含CRC)*/
#define FRAME_CRC_LENGTH                            2       /*组包框架CRC字节数*/

/*协议版本*/
// 0x01 ---0x41
// 0x02 ---0x50
typedef enum
{
    CANRBUS_FLOW_VER_0x41 = 1,           /*canrbus 4.1*/
    CANRBUS_FLOW_VER_0x50,               /*canrbus 5.0*/

    CANRBUS_FLOW_VER_BUTT
}CANRBUS_FLOW_VER_ENUM;

/*流协议中功能码/CMD指令类型*/
typedef enum
{
    CMD_TYPE_UPDATE        = 0x00,    /*升级*/
    CMD_TYPE_RECORD        = 0x01,    /*记录导出*/
    CMD_TYPE_RWDB          = 0x02,    /*读写db*/
    CMD_TYPE_DEBUG         = 0x03,    /*debug消息*/
    CMD_TYPE_HMI_CONFIG    = 0X04,    /*HMI配置信息在线升级*/
    CMD_TYPE_MSG           = 0X05,    /*信息交互(V50)*/

    CMD_TYPE_BUTT                     /*最大的支持的类型*/
}CMD_CODE_ENUM;

/*CMD指令3 debug消息类型*/
typedef enum
{
    DEBUG_CMD_RESET = 0,              /*复位*/
    DEBUG_CMD_STARTPRG,               /*请求升级*/
    DEBUG_CMD_SHOWVERSION,            /*获取版本号*/
    DEBUG_CMD_ENDPRG,                 /*结束升级*/
    DEBUG_CMD_CANRBUSVERSION,         /*查询canbus协议版本*/
    DEBUG_CMD_BALANCECHECKCOUNT,      /*均衡检测次数打印*/
    DEBUG_CMD_ASSERTINFO,             /*获取dbgAssert信息*/
    DEBUG_CMD_BUTT
}DEBUG_CMD_ENUM;

/*
    1. 升级总控: bauId: 1; bcuId: 0; bmuId: 0;(总控仅支持单播)
    2. 升级主控: bauId: 固定1; bcuId: 单播时为簇设备ID, 广播时固定为63;
    3. 升级从控: bauId: 固定1; bcuId: 单播时为簇设备ID, 广播时固定为63; bmuId固定为127(bmu仅支持广播)
*/
typedef struct
{
    uint8_t bmuId;
    uint8_t bcuId;
    uint8_t bauId;
    uint8_t devType;                /* 设备类型(V41) */
    uint8_t devlevel;               /* 设备层级 */
    uint8_t cmdCode;                /* canrbusflow命令码(enum CMD_CODE_ENUM) */
    uint8_t isHierMode;             /* CANID或者消息流中是否分层管理方式, 决定是否是广播 */
}CanrbusFlow_Infor_t;

typedef struct
{
    int bau_ver;                    /* bau_canrbus 版本 */
    int bcu_ver;                    /* bcu_canrbus 版本 */
    int bmu_ver;                    /* bmu_canrbus 版本 */
    int bdu_ver;                    /* bdu_canrbus 版本 */
}CanrbusFlow_Ver_t;

/*!
 * @brief       canrbus消息流初始化，确定canrbus消息流版本
 *
 * @return      0: 成功; !0: 失败
 * @retval      None
 *
 * @par         modify    log
 * Date        Author     Description             \n
 * 2024-02-05     qzy      Create             \n
 */
int32_t CanrbusFlowInit(void);

/*!
 * @brief       按照canrbus 流协议打包
 *
 * @param[in]      CanrbusFlow_Infor_t *pCanrInfor
 * @param[in]      uint32_t in_len     有效数据体长度
 * @param[in]      uint8_t *in_data    有效数据体buf
 * @param[out]     uint32_t out_len    组装完成的buf长度
 * @param[out]     uint8_t *out_data   组装完成的buf
 * 
 * @return
 * @retval      None
 *
 * @par         modify    log
 * Date        Author     Description             \n
 * 2024-01-29     qzy      Create             \n
 * 2024-02-19     qzy      入参出参修改         \n
 */
int32_t CanrbusFlowPackData(CanrbusFlow_Infor_t *pCanrInfor, uint32_t in_len, uint8_t *in_data,\
                                    uint32_t *out_len, uint8_t *out_data);

/*!
 * @brief       组装Debug指令字符串(事务3 debug指令)
 *
 * @param[in]   CanrbusFlow_Infor_t *p_upinfor
 * @param[in]   uint8_t dbg_cmd       debug指令类型
 * @param[out]  void    *buff         命令字符串buf
 * @param[out]  int32_t *realLen      命令字符串长度
 * @return      Std_True
 * @retval      None
 *
 * @par         modify    log
 * Date        Author     Description             \n
 * 2024-01-29     qzy      Create             \n
 */
int32_t CanrbusFlowPackDebugCmdStr(CanrbusFlow_Infor_t *pCanrInfor, uint8_t dbg_cmd, void* buff, int32_t* realLen);

/*!
 * @brief       检查响应包是否合法(升级)
 *
 * @param[in]   uint8_t  devlevel   设备层级(根据层级确定协议版本)
 * @param[in]   uint8_t  *buf       响应数据包
 * @param[in]   uint16_t  len       包长度
 * @return      true: match ; false: not match
 * @retval      None
 *
 * @par         modify    log
 * Date        Author     Description             \n
 * 2024-01-29     qzy      Create             \n
 */
int32_t CanrbusFlowIsFlowContentMatch(uint8_t devlevel, uint8_t *buf, uint16_t len);

/*!
 * @brief       根据响应包获取功能码
 *
 * @param[in]   uint8_t devlevel    设备层级
 * @param[in]   uint8_t *buf        响应数据包
 * @return      cmd_code            功能码
 * @retval      uint8_t
 *
 * @par         modify    log
 * Date        Author     Description             \n
 * 2024-01-29     qzy      Create             \n
 */
uint8_t CanrbusFlowGetCmdCode(uint8_t devlevel, uint8_t *buf);

/*!
 * @brief       根据响应包获取设备level_id
 *
 * @param[in]   CanrbusFlow_Infor_t *pCanrInfor
 * @param[in]   uint8_t *buf                  响应数据包
 * @return      Select_VD_Id                  level_id
 * @retval      uint8_t
 *
 * @par         modify    log
 * Date        Author     Description             \n
 * 2024-01-29     qzy      Create             \n
 */
uint8_t CanrbusFlowSelectVDId(CanrbusFlow_Infor_t *pCanrInfor, uint8_t *buf);

/*!
 * @brief       获取传输框架长度(不包含CRC)
 *
 * @param[in]   uint8_t devlevel         设备层级
 * @return      length
 * @retval      uint8_t
 *
 * @par         modify    log
 * Date        Author     Description             \n
 * 2024-01-29     qzy      Create             \n
 */
uint8_t CanrbusFlowGetHeaderLen(uint8_t devlevel);

/* 协议组包接口开放给canrbus_util使用 */
/*!
 * @brief       按照canrbus V41协议打包binary_flow mqtt
 * @param[in]      CanrbusFlow_Infor_t *pCanrInfor
 * @param[in]      uint32_t data_len    有效数据体长度
 * @param[in]      uint8_t *data_frame  有效数据体buf
 * @param[out]     uint32_t out_len     组装完成的buf长度
 * @param[out]     uint8_t *out_frame   组装完成的buf
 * @return
 * @retval      0
 *
 * @par         modify    log
 * Date        Author     Description             \n
 * 2024-01-26     qzy      Create             \n
 */
int32_t packTransferFrame_V41(CanrbusFlow_Infor_t *pCanrInfor, uint32_t in_len, uint8_t *in_frame, \
                                    uint32_t *out_len, uint8_t *out_frame);

/*!
 * @brief       按照canrbus 5.0协议打包
 *
 * @param[in]   UPSP_Infor_Stru *pUPSPInfor
 * @param[in]   uint32_t msgType     命令码(cmd_code)
 * @param[out]  uint8_t *frame       组装完成的buf
 * @param[in]   uint32_t len         有效数据长度
 * @return
 * @retval      None
 *
 * @par         modify    log
 * Date        Author     Description             \n
 * 2023-08-08     qzy      Create             \n
 */
int32_t packTransferFrame_V50(CanrbusFlow_Infor_t *pCanrInfor, uint32_t in_len, uint8_t *in_frame, \
                                    uint32_t *out_len, uint8_t *out_frame);

/*!
 * @brief       按照canrbus 4.1协议解包
 *
 * @param[out]  CanrbusFlow_Infor_t *pCanrInfor
 * @param[in]   uint8_t *in_frame       组装完成的buf
 * @return
 * @retval      None
 *
 * @par         modify    log
 * Date        Author     Description             \n
 * 2024-11-05     tk      Create             \n
 */
int32_t ParsepackTransferFrame_V41(CanrbusFlow_Infor_t *pCanrInfor, uint8_t *in_frame);

/*!
 * @brief       按照canrbus 5.0协议解包
 *
 * @param[out]  CanrbusFlow_Infor_t *pCanrInfor
 * @param[in]   uint8_t *in_frame       组装完成的buf
 * @return
 * @retval      None
 *
 * @par         modify    log
 * Date        Author     Description             \n
 * 2024-11-05     tk      Create             \n
 */
int32_t ParsepackTransferFrame_V50(CanrbusFlow_Infor_t *pCanrInfor, uint8_t *in_frame);

#endif /*__CANRBUS_H__*/
