/*
 * @Author: qianziyang qianzy@bmser.com
 * @Date: 2023-12-15 10:53:21
 * @LastEditors: chensong chens@bmser.com
 * @LastEditTime: 2024-06-20 09:28:18
 * @FilePath: /rk3568_sdk_1018/bmser_app/bmser_upgrade/src/app/ota/dtc_export.h
 * @Description: 记录导出
 */

#include "dtc_export.h"
#include "bmser_log.h"
#include "bmser_dev.h"
#include "bmser_ems_db_control_db.h"
#include "dtc_db3_common.h"
#include "define_base.h"
#include "event_process.h"
#include "bmser_project_para.h"
#include "dtc_export_cfg_parse.h"
#include "bmser_canrbus.h"
#include "bmser_canrbus_comm.h"
#include "bmser_mqtt.h"
#include "communication.h"
#include <stdio.h>
#include <sqlite3.h>
#include <pthread.h>
#include"wave_record_queue.h"
#include "cJSON.h"
#define TOPIC_MAX_LEN            256      /*topic长度*/
#define MAX_DTC_DEV_NUM           64      /*设备数量最大值*/

#define MAX_MULTI_PKG_NUM         16      /*dtc多包 最多包个数(0xF+1)*/
#define MAX_MULTI_PKG_LENGTH     300      /*dtc多包 单个包最大长度*/

#define ALL_CRC_LEN                4      /*canrbus框架 CRC长度 + binaryFlow mqtt CRC长度*/
#define BINARYFLOW_HEADER_LEN     10      /*binaryFlow mqtt头长度*/
#define DTC_RECV_BUF_HEADER_LEN    7      /*dtc接收报文buf 头长度*/

#define BINARY_FLOW_SET_TOPIC    "ipc/%s/bms/00000000/upgrade/Set/binaryFlow"


typedef struct
{
    uint16_t waitTime;
    uint16_t tryTimes;
    int DBIndexValue;               /*当前索引DB*/
    int DBMaxDtcNum;                /*DB中获取的最大dtc条数*/
    int inquireIndex;
    char tableName[32];
    DTC_Export_Step_Enum exportStep;
    int  sleepTime;                 /*休眠时间*/
    int  isRecvd;                   /*接收标志*/
    bool isMultiPkg;                /*是否为多包*/
    bool isRotating;                /*是否为轮转状态*/
} Dtc_Export_Record_Run_Infor;
Dtc_Export_Record_Run_Infor g_dtcInfor = {0};

typedef struct 
{
    int rackNum;
    int curDevId;
    int curRecordType;
    int singleWaitTime;      /*从配置json中获取的单包等待时间*/
    int mulitWaitTime;       /*从配置json中获取的多包等待时间*/
    uint32_t recordId;       /*记录条目ID持续递增, 作为主键，避免轮转时条目被覆盖*/
    int oldTableIndex[MAX_DTC_DEV_NUM][DTC_RECORD_TYPE_MAX]; /*记录对应设备上一次的表中DBIndexID*/
}Dtc_Export_Record_Init_Infor;
Dtc_Export_Record_Init_Infor g_dtcInit = {0};

typedef struct
{
    uint8_t  buf[MAX_MULTI_PKG_NUM][MAX_MULTI_PKG_LENGTH];     /*单条dtc消息内容buf*/
    uint8_t  flag[MAX_MULTI_PKG_NUM];                          /*对应pkgIndex是否已经接收标志*/
    uint8_t  dataLen[MAX_MULTI_PKG_NUM];                       /*每条dtc消息的长度*/
    uint16_t inquire_index[MAX_MULTI_PKG_NUM];                 /*每条dtc消息的请求index，用于校验*/
    uint8_t  devID[MAX_MULTI_PKG_NUM];                         /*每条dtc消息的设备ID，用于校验*/
    uint8_t  allBuf[MAX_MULTI_PKG_NUM * MAX_MULTI_PKG_LENGTH]; /*多包dtc消息汇总buf*/
}Dtc_Export_Record_MultiPkg_Infor;
Dtc_Export_Record_MultiPkg_Infor g_dtcMulit = {0};

/**
 * @brief 确定devid, bankid, rackid
 * @param[in]   CanrbusFlow_Mqtt_t* payload 
 * @param[out]  uint16_t bankid
 * @param[out]  uint16_t rackid
 * @retval      0
 */
static int getCurDevID(CanrbusFlow_Mqtt_t *payload, uint16_t *bankid, uint16_t *rackid, uint16_t *devid)
{
    int devId = 0;
    if(payload->layer == BMS_HW_LEVEL_2) {
        //BCU
        devId = payload->msgFlowBcuId;
    } else if(payload->layer == BMS_HW_LEVEL_3) {
        //BAU
        devId = 0;
    }
    *devid = devId;
    bmser_dev_calcBankIdAndRackIdByDevId(devId, bankid, rackid);
    return 0;
}

/* 下位机unix时间戳处理，并转标准时间 */
static void unixTimestampToDateTime(time_t timestamp, char* sysTime, uint32_t *unixTime)
{
    time_t new_timestatmp = timestamp - bmser_jsonGetTimeZoneOffset();
    struct tm *timeinfo = localtime((time_t*)&new_timestatmp);

    strftime(sysTime, STR_VAL_MAX_LEN, "%Y-%m-%d %H:%M:%S", timeinfo);
    // 返回修改后的Unix时间戳
    if (unixTime != NULL) {
        *unixTime = (uint32_t)new_timestatmp;
    }
}

/* 版本号处理 */
static void intToVersionString(uint32_t version, char *versionStr)
{
    // 获取主、次、修订和构建号
    int major = version & 0xFF;
    int minor = (version >> 8) & 0xFF;
    int revision = (version >> 16) & 0xFF;
    int build = (version >> 24) & 0xFF;

    // 将版本号格式化为字符串
    sprintf(versionStr, "%d.%d.%d.%d", major, minor, revision, build);
}

/* 根据evId获取triggerEventName */
IdNameMap_Stru eventMappings[] = 
{
    {0, 0, "电流变化", "Current Changes"},
    {4, 0, "告警", "Alarm"},
    {5, 0, "告警恢复", "Alarm Recovery"},
    {8, 0, "故障", "Fault"},
    {9, 0, "故障恢复", "Fault Recovery"},
    {-1, 0, "未知事件", "Unknown Event"} // 默认映射
};
static void getTriggerEventName(uint8_t evId, char *evName_zh, char *evName_en)
{
    for (size_t i = 0; i < sizeof(eventMappings) / sizeof(eventMappings[0]); ++i)
    {
        if (eventMappings[i].Id == evId)
        {
            snprintf(evName_zh, STR_VAL_MAX_LEN, "%s", eventMappings[i].name_zh_CN);
            snprintf(evName_en, STR_VAL_MAX_LEN, "%s", eventMappings[i].name_en_US);
            return;
        }
    }
    // 如果找不到匹配项，使用默认映射
    snprintf(evName_zh, STR_VAL_MAX_LEN, "%s", eventMappings[sizeof(eventMappings) / sizeof(eventMappings[0]) - 1].name_zh_CN);
    snprintf(evName_en, STR_VAL_MAX_LEN, "%s", eventMappings[sizeof(eventMappings) / sizeof(eventMappings[0]) - 1].name_en_US);
}

static int check_bit(unsigned int value, int bit_position)
{
    unsigned int mask = 1 << bit_position;
    return (value & mask) != 0;
}

static void process_DataType0_info(ValueReasonInfo_Stru Info, uint16_t fault, char *extSnapMsg)
{
    // Hex 格式
    if (Info.HexFlag) {
        snprintf(extSnapMsg + strlen(extSnapMsg), EXTMSG_MAX_LEN - strlen(extSnapMsg), "0x%x", fault);
        return;
    }

    double value = 0.0;
    if (strcmp(Info.ValueFormat, "0.0") == 0 || strcmp(Info.ValueFormat, "0") == 0) {
        value = (int)fault * Info.Factor + Info.Offset;
    } else if (strcmp(Info.ValueFormat, "-0.0") == 0 || strcmp(Info.ValueFormat, "-0") == 0) {
        value = (int16_t)fault * Info.Factor + Info.Offset;
    } else {
        // 没有匹配项，默认
        value = (int)fault * Info.Factor + Info.Offset;
    }

    if (strcmp(Info.ValueFormat, "0.0") == 0 || strcmp(Info.ValueFormat, "-0.0") == 0) {
        snprintf(extSnapMsg + strlen(extSnapMsg), EXTMSG_MAX_LEN - strlen(extSnapMsg), "%.1f%s", value, Info.Unit);
    } else {
        snprintf(extSnapMsg + strlen(extSnapMsg), EXTMSG_MAX_LEN - strlen(extSnapMsg), "%d%s", (int)value, Info.Unit);
    }
}

static void process_value_info(ValueReasonInfo_Stru Info, uint16_t fault, char *extSnapMsg_CN, char *extSnapMsg_US)
{
    bool isFound = false;
    if(strcmp(Info.EnTitle, "NULL") != 0 && strcmp(Info.ZhTitle ,"NULL") != 0)
    {
        int bitIndex, k;

        snprintf(extSnapMsg_CN + strlen(extSnapMsg_CN), EXTMSG_MAX_LEN - strlen(extSnapMsg_CN), "%s:", Info.ZhTitle);
        snprintf(extSnapMsg_US + strlen(extSnapMsg_US), EXTMSG_MAX_LEN - strlen(extSnapMsg_US), "%s:", Info.EnTitle);

        switch (Info.DataType)
        {
            case 0:  // 数值 DataType: 0
                process_DataType0_info(Info, fault, extSnapMsg_CN);
                process_DataType0_info(Info, fault, extSnapMsg_US);
                break;

            case 1:  // 映射 DataType: 1
                for (k = 0; k < DTC_MEANLIST_MAX_COUNT; k++) {
                    if (fault == Info.MeaningList[k].DataOrBitIndex) {
                        snprintf(extSnapMsg_CN + strlen(extSnapMsg_CN), EXTMSG_MAX_LEN - strlen(extSnapMsg_CN), "%s", Info.MeaningList[k].ZhTitle);
                        snprintf(extSnapMsg_US + strlen(extSnapMsg_US), EXTMSG_MAX_LEN - strlen(extSnapMsg_US), "%s", Info.MeaningList[k].EnTitle);
                        isFound = true;
                        break;
                    }
                }
                if (!isFound) {
                    // 未找到则添加NULL字符串
                    snprintf(extSnapMsg_CN + strlen(extSnapMsg_CN), EXTMSG_MAX_LEN - strlen(extSnapMsg_CN), "NULL");
                    snprintf(extSnapMsg_US + strlen(extSnapMsg_US), EXTMSG_MAX_LEN - strlen(extSnapMsg_US), "NULL");
                }
                break;

            case 2:  // bit DataType: 2
                for (bitIndex = 0; bitIndex < 16; ++bitIndex) {
                    if (check_bit(fault, bitIndex)) {
                        snprintf(extSnapMsg_CN + strlen(extSnapMsg_CN), EXTMSG_MAX_LEN - strlen(extSnapMsg_CN), "%s|", Info.MeaningList[bitIndex].ZhTitle);
                        snprintf(extSnapMsg_US + strlen(extSnapMsg_US), EXTMSG_MAX_LEN - strlen(extSnapMsg_US), "%s|", Info.MeaningList[bitIndex].EnTitle);
                        isFound = true;
                    }
                }
                if (!isFound) {
                    // 未找到则添加NULL
                    snprintf(extSnapMsg_CN + strlen(extSnapMsg_CN), EXTMSG_MAX_LEN - strlen(extSnapMsg_CN), "NULL");
                    snprintf(extSnapMsg_US + strlen(extSnapMsg_US), EXTMSG_MAX_LEN - strlen(extSnapMsg_US), "NULL");
                }
                break;
        }
        strncat(extSnapMsg_CN, ";", 2);
        strncat(extSnapMsg_US, ";", 2);
    }
}

/* 根据extSnapMsg解析详细定位信息 */
static void getDtcExtSnapMsg(DTC_Export_Record_Stru *record, char *extSnapMsg_CN, char *extSnapMsg_US)
{
    int i, j, k = 0;
    int bitIndex = 0;
    double value_type0;
    SubDtcInfoList_Stru *SubDtcInfo = getSubDtcInfoListBySubDID(record->DID);
    if(SubDtcInfo == NULL) {
        return;
    }

    //先填充对内故障名称
    memset(extSnapMsg_CN, 0 ,sizeof(extSnapMsg_CN));
    memset(extSnapMsg_US, 0 ,sizeof(extSnapMsg_US));
    snprintf(extSnapMsg_CN+strlen(extSnapMsg_CN), EXTMSG_MAX_LEN - strlen(extSnapMsg_CN), "%s;", \
                        SubDtcInfo->subDtcName);
    snprintf(extSnapMsg_US+strlen(extSnapMsg_US), EXTMSG_MAX_LEN - strlen(extSnapMsg_US), "%s;", \
                        SubDtcInfo->subDtcName_en);

    // 类型1
    if(record->ext_snap_type == DTC_EXT_SNAP_TYPE_1) {
        DTC_Export_Ext_Snap_1_Stru *msg1 = (DTC_Export_Ext_Snap_1_Stru *)record->buf;
        for(j = 0; j < record->ext_records_num; j++)
        {
            // pack编号，单体编号
            snprintf(extSnapMsg_CN+strlen(extSnapMsg_CN), EXTMSG_MAX_LEN - strlen(extSnapMsg_CN), "pack编号: %u|单体编号: %u;", \
                        msg1->extMsg1[j].pack_id, msg1->extMsg1[j].pos_id);
            snprintf(extSnapMsg_US+strlen(extSnapMsg_US), EXTMSG_MAX_LEN - strlen(extSnapMsg_US), "pack_id: %u|pos_id: %u;", \
                        msg1->extMsg1[j].pack_id, msg1->extMsg1[j].pos_id);

            /* ValueInfoList处理 */
            if (SubDtcInfo->value_info_valid_length > 0 && j < SubDtcInfo->value_info_valid_length) {
                process_value_info(SubDtcInfo->ValueInfoList[j], msg1->extMsg1[j].fault_value, extSnapMsg_CN, extSnapMsg_US);
            }
            /* ReasonInfoList处理 */
            if (SubDtcInfo->reason_info_valid_length > 0 && j < SubDtcInfo->reason_info_valid_length) {
                process_value_info(SubDtcInfo->ReasonInfoList[j], msg1->extMsg1[j].fault_cause, extSnapMsg_CN, extSnapMsg_US);
            }
        }
    } else if(record->ext_snap_type == DTC_EXT_SNAP_TYPE_2) {
        DTC_Export_Ext_Snap_2_Stru *msg2 = (DTC_Export_Ext_Snap_2_Stru *)record->buf;
        for(j = 0; j < record->ext_records_num; j++)
        {
            /* ValueInfoList处理 */
            if (SubDtcInfo->value_info_valid_length > 0 && j < SubDtcInfo->value_info_valid_length) {
                process_value_info(SubDtcInfo->ValueInfoList[j], msg2->extMsg2[j].fault_value, extSnapMsg_CN, extSnapMsg_US);
            }
            /* ReasonInfoList处理 */
            if (SubDtcInfo->reason_info_valid_length > 0 && j < SubDtcInfo->reason_info_valid_length) {
                process_value_info(SubDtcInfo->ReasonInfoList[j], msg2->extMsg2[j].fault_cause, extSnapMsg_CN, extSnapMsg_US);
            }
        }
    }
}

/**
 * @brief 组装错误响应值
 * @param[in] uint16_t bankid
 * @param[in] uint16_t rackid
 * @param[in] DTC_Export_Receive_Content_t *recvContent
 * @param[out] DTC_Export_Table_Stru *info
 * @retval 
 */
static int DTC_Export_GetErrInfo(uint16_t bankid, uint16_t rackid, uint8_t record_type, uint16_t inquire_index, DTC_Export_Table_Stru *info)
{
    // 组装table结构体
    info->id = ++g_dtcInit.recordId;
    info->bankID = bankid;
    info->rackID = rackid;
    info->recordType = record_type;
    info->DBIndexID = inquire_index;
    info->unixTime = 0xFFFFFFFF;
    return 0;
}

/**
 * @brief     插入DB表
 * @param[in] uint16_t bankid
 * @param[in] uint16_t rackid
 * @param[in] DTC_Export_Receive_Content_t *recvContent
 * @param[out] DTC_Export_Table_Stru *info
 * @retval 
 */
static void DTC_Export_DB3_dataUpdate(DTC_Export_Table_Stru *info)
{
    // DTC插入前作一次对应记录类型空间清理
    DTC_Export_DB3_space_cleaning(info->recordType);
    DTC_Export_DB3_dataInsert(info);
}


extern int g_language;
/**
 * @brief 接收DTC_Export_Table_Stru的数据，将告警通过mqtt上抛：（简捷项目）
 * @param[int] DTC_Export_Table_Stru *info
 * @retval 0 成功，-1失败 1 非关注事件
 */
static int DTC_Export_LNXALL_Project(const DTC_Export_Table_Stru *info){
    int status = 0;
    static unsigned long long msgID = 1;
    if(info->eventId == 4 || info->eventId == 8){
        status =  1 ;
    }
    else if(info->eventId == 5 || info->eventId == 9){
        status = 0;
    }
    else{
        return 1;
    }
    cJSON *root = cJSON_CreateObject();
    if (!root) {
        dy_syslog(LOG_ERR,"Failed to create root object\n");
        return -1;
    }

    // 添加根对象的字段
    cJSON_AddStringToObject(root, "identifier", "ImmediateAlarm");
    cJSON_AddNumberToObject(root, "time", time(NULL));
    cJSON_AddNumberToObject(root, "mi", msgID);

    char sn[SN_MAX_LEN] = {0};
    if (0 != bmser_dev_get_board_sn(sn)) {
        dy_syslog(LOG_ERR,"fail to get sn");
        return -1;
    }
    cJSON_AddStringToObject(root, "sn", "00000000");

    // 创建frames数组
    cJSON *framesArray = cJSON_CreateArray();
    if (!framesArray) {
        dy_syslog(LOG_ERR,"Failed to create frames array\n");
        cJSON_Delete(root);
        return -1;
    }

    // 创建一个frame对象
    cJSON *frameObj = cJSON_CreateObject();
    if (!frameObj) {
        dy_syslog(LOG_ERR,"Failed to create frame object\n");
        cJSON_Delete(framesArray);
        cJSON_Delete(root);
        return -1;
    }

    // 创建regs数组
    cJSON *regsArray = cJSON_CreateArray();
    if (!regsArray) {
        dy_syslog(LOG_ERR,"Failed to create regs array\n");
        cJSON_Delete(frameObj);
        cJSON_Delete(framesArray);
        cJSON_Delete(root);
        return -1;
    }

    // 创建一个reg对象
    cJSON *regObj = cJSON_CreateObject();
    if (!regObj) {
        dy_syslog(LOG_ERR,"Failed to create reg object\n");
        cJSON_Delete(regsArray);
        cJSON_Delete(frameObj);
        cJSON_Delete(framesArray);
        cJSON_Delete(root);
        return -1;
    }


    // 添加reg对象的字段
    cJSON_AddNumberToObject(regObj, "status", status);

    cJSON_AddNumberToObject(regObj, "continerId", bmser_jsonGetContainerNum());
    cJSON_AddNumberToObject(regObj, "bankid", info->bankID);
    cJSON_AddNumberToObject(regObj, "rackid", info->rackID);

    if(g_language == 0){
        cJSON_AddStringToObject(regObj, "alarmitem", info->dtcName);
        cJSON_AddStringToObject(regObj, "extra", info->issueDetails_zh_CN);
    }
    else{
        cJSON_AddStringToObject(regObj, "alarmitem", info->dtcName_en);
        cJSON_AddStringToObject(regObj, "extra", info->issueDetails_en_US);
    }

    cJSON_AddNumberToObject(regObj, "level", info->alarm_level);
    cJSON_AddNumberToObject(regObj, "settime", info->unixTime);

    // 创建translation数组
    cJSON *translationArray = cJSON_CreateArray();
    if (!translationArray) {
        dy_syslog(LOG_ERR,"Failed to create translation array\n");
        cJSON_Delete(regObj);
        cJSON_Delete(regsArray);
        cJSON_Delete(frameObj);
        cJSON_Delete(framesArray);
        cJSON_Delete(root);
        return -1;
    }

    // 创建并添加每个翻译项
    cJSON *item1 = cJSON_CreateObject();
    cJSON_AddStringToObject(item1, "Lang", "zh");
    cJSON_AddStringToObject(item1, "alarmitem", info->dtcName);
    cJSON_AddItemToArray(translationArray, item1);

    cJSON *item2 = cJSON_CreateObject();
    cJSON_AddStringToObject(item2, "Lang", "en");
    cJSON_AddStringToObject(item2, "alarmitem", info->dtcName_en);
    cJSON_AddItemToArray(translationArray, item2);

    cJSON *item3 = cJSON_CreateObject();
    cJSON_AddStringToObject(item3, "Lang", "zh");
    cJSON_AddStringToObject(item3, "extra", info->issueDetails_zh_CN);
    cJSON_AddItemToArray(translationArray, item3);

    cJSON *item4 = cJSON_CreateObject();
    cJSON_AddStringToObject(item4, "Lang", "en");
    cJSON_AddStringToObject(item4, "extra", info->issueDetails_en_US);
    cJSON_AddItemToArray(translationArray, item4);

    cJSON_AddItemToObject(regObj,"translation",translationArray);

    cJSON_AddItemToArray(regsArray,regObj);
    cJSON_AddItemToObject(frameObj,"regs",regsArray);
    cJSON_AddItemToArray(framesArray,frameObj);
    cJSON_AddItemToObject(root,"frames",framesArray);

    char topic[64] = {0};
    snprintf(topic,sizeof(topic),"ipc/%s/bms/00000000/data/Set/ImmediateAlarm",sn);
    char* msg = cJSON_Print(root);
    struct ipc_topic t = {0};
    struct ipc_payload p = {0};
    t.name = topic;
    p.buf = msg;
    p.len = strlen(msg);
    communication_publish(&t,&p);
    cJSON_Delete(root);
    cJSON_free(msg);

    // 维护msgID
    msgID++;
    return 0;
}


/**
 * @brief 组装值
 * @param[in] uint16_t bankid
 * @param[in] uint16_t rackid
 * @param[in] DTC_Export_Receive_Content_t *recvContent
 * @param[out] DTC_Export_Table_Stru *info
 * @retval 
 */
static int DTC_Export_GetTableInfo(uint16_t bankid, uint16_t rackid, DTC_Export_Receive_Content_t *recvContent, uint8_t *multiBuf, DTC_Export_Table_Stru *info)
{
    if (recvContent == NULL) {
        return -1;
    }
    DTC_Export_Record_Stru *record = NULL;
    // 获取记录内容, 多包情况时buf从多包汇总缓存中取
    if (!g_dtcInfor.isMultiPkg) {
        record = (DTC_Export_Record_Stru *)recvContent->buf;
    } else {
        record = (DTC_Export_Record_Stru *)multiBuf;
    }

    // 索引为非法值
    if(record->indexID < 0) {
        return -1;
    }

    // 非错误响应，时间戳异常，请求到的为下位机未写入过的DTC信息，不处理
    if (record->sysTime == 0xFFFFFFFF) {
        return -1;
    }

    // 组装table结构体
    info->bankID = bankid;
    info->rackID = rackid;
    info->recordType = recvContent->record_type;
    info->DBIndexID = recvContent->inquire_index;
    info->dtcIndexID = record->indexID;
    // 处理时间戳
    unixTimestampToDateTime(record->sysTime, info->sysTime, &(info->unixTime));

    int count = 0;
    // 查重；设备信息，类型，索引，时间戳都相同的记录条目不处理，仅记录特殊行
    DTC_Export_DB3_getSameRecord(info->bankID, info->rackID, info->recordType, info->DBIndexID, info->unixTime, &count);
    if (count > 0) {
        DTC_Export_GetErrInfo(bankid, rackid, recvContent->record_type, recvContent->inquire_index, info);
        DTC_Export_DB3_dataUpdate(info);
        return -1;
    }

    info->id = ++g_dtcInit.recordId;
    // 处理软件版本号
    intToVersionString(record->softwareVersion, info->softwareVersion);
    info->DID = record->DID;
    getDtcNameBySubDID(record->DID, info->dtcName);       // 处理dtc名(中文)
    getDtcNameEnBySubDID(record->DID, info->dtcName_en);  // 处理dtc名(英文)
    info->eventId = record->evId;
    getTriggerEventName(record->evId, info->eventName_zh_CN, info->eventName_en_US);  // 处理触发事件名
    // 恢复事件拼接恢复字段至dtc名后
    if (info->eventId == 5 || info->eventId == 9)
    {
        strncat(info->dtcName, "-恢复", sizeof(info->dtcName) - strlen(info->dtcName) - 1);
        strncat(info->dtcName_en, "-Rec", sizeof(info->dtcName_en) - strlen(info->dtcName_en) - 1);
    }
    info->alert1 = record->alert1;
    info->alarm1 = record->alarm1;
    info->stop1 = record->stop1;
    info->alert2 = record->alert2;
    info->alarm2 = record->alarm2;
    info->stop2 = record->stop2;
    info->resetCount = record->reset_count;
    // uptime 保留一位小数，转成字符串储存
    float uptime = record->uptime * 0.1;
    snprintf(info->uptime, sizeof(info->uptime), "%.1f", uptime);
    info->extSnapType = record->ext_snap_type;
    info->clusterId = record->cluster_id;
    info->extRecordsNum = record->ext_records_num;
    getDtcExtSnapMsg(record, info->issueDetails_zh_CN, info->issueDetails_en_US); // 处理扩展信息
    info->alarm_level = getDtcLevelBySubDID(record->DID);                         // 获取告警等级

    return 0;
}

static bool is_dtcMulti_all_recved(int packNum, Dtc_Export_Record_MultiPkg_Infor *dtcMulti)
{
    int i = 0;
    uint8_t first_devID = 0;
    uint16_t first_inq_index = 0;

    for(i = 1; i <= packNum; i++) {
        if (!dtcMulti->flag[i]) {
            return false;
        }

        if (i == 1) {
            first_devID = dtcMulti->devID[i];
            first_inq_index = dtcMulti->inquire_index[i];
        } else if ((dtcMulti->devID[i] != first_devID) || (dtcMulti->inquire_index[i] != first_inq_index)) {
            return false;
        }
    }
    return true;
}

/**
 * @brief       记录导出binaryFlow报文处理
 * @param[in]   payload         消息流
 * @param[in]   flowHeadLen     消息流头长度
 * @retval
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2023-12-27           QZY        创建初始版本          \n
 * 2024-05-22           QZY        适配canrbus独立库     \n
 * 2024-10-25           QZY        多包增加校验          \n
*/
static void DTC_Export_db_update(CanrbusFlow_Mqtt_t *payload, uint32_t payload_len, int flowHeadLen)
{
    DTC_Export_Receive_Content_t *recvContent = (DTC_Export_Receive_Content_t* )(payload->data + flowHeadLen);
    DTC_Export_Table_Stru info = {0};
    uint16_t bankid, rackid, devid = 0;
    getCurDevID(payload, &bankid, &rackid, &devid);

    int dataLen = payload_len - BINARYFLOW_HEADER_LEN - flowHeadLen - ALL_CRC_LEN;
    // 报文校验(TCP流协议可能收到workid正确，但报文内容不对应的报文)
    if ((recvContent->export_type != DTC_EXPORT_TYPE_OTHER) || \
       ((recvContent->record_type != DTC_RECORD_TYPE_EVENT) && (recvContent->record_type != DTC_RECORD_TYPE_ALARM)) || \
       (dataLen - DTC_RECV_BUF_HEADER_LEN <= 0)) {
        return;
    }

    // 错误响应处理
    if (recvContent->inquire_index == DTC_INQUIRE_INDEX_ERR) {
        //数据库中插入特殊行，标识该index已请求过
        DTC_Export_GetErrInfo(bankid, rackid, recvContent->record_type, g_dtcInfor.inquireIndex, &info);
        DTC_Export_DB3_dataUpdate(&info);
        g_dtcInfor.isRecvd = DTC_INQUIRE_INDEX_ERR;
        return;
    }

    // 多包情况处理
    int packNum = (int)(recvContent->sendOK_flag & 0x0F);
    if (packNum > 1) {
        int packIndex = (int)((recvContent->sendOK_flag >> 4) & 0x0F);
        // dtc信息报文长度 = mqtt报文长度 - 消息流mqtt头长度 - canrbus框架头长度 - (canrbus框架CRC + mqttCRC)
        int i = 0, currentOffset = 0;

        g_dtcInfor.isMultiPkg = true;
        // 多包时接收buf头部信息一致，去掉头部信息
        memcpy(g_dtcMulit.buf[packIndex], recvContent->buf, dataLen - DTC_RECV_BUF_HEADER_LEN);
        g_dtcMulit.inquire_index[packIndex] = recvContent->inquire_index;
        g_dtcMulit.devID[packIndex] = devid;
        g_dtcMulit.flag[packIndex] = true;
        g_dtcMulit.dataLen[packIndex] = dataLen - DTC_RECV_BUF_HEADER_LEN;
        if (is_dtcMulti_all_recved(packNum, &g_dtcMulit)) {
            for(i = 1; i <= packNum; i++) {
                // 将所有packindex对应的buf，按长度，序号，拼装到总buf
                memcpy(g_dtcMulit.allBuf + currentOffset, g_dtcMulit.buf[i], g_dtcMulit.dataLen[i]);
                currentOffset += g_dtcMulit.dataLen[i];
            }
        } else {
            return;
        }
    }

    // 组装table结构, 并插入数据库
    if (DTC_Export_GetTableInfo(bankid, rackid, recvContent, g_dtcMulit.allBuf, &info) != -1) {
        if(DTC_export_get_mode() == 1){
            DTC_Export_LNXALL_Project(&info);
        }
        else{
            DTC_Export_DB3_dataUpdate(&info);
        }
        // 使用故障录波提供的回调函数, 将收到的info发送到录波缓冲区
        if(waveGetDtcIssueCallback != NULL) {
            waveGetDtcIssueCallback(&info);
        }
    }
    // 清空多包缓存
    if (g_dtcInfor.isMultiPkg) {
        g_dtcInfor.isMultiPkg = false;
        memset(&g_dtcMulit, 0, sizeof(Dtc_Export_Record_MultiPkg_Infor));
    }
    g_dtcInfor.isRecvd = recvContent->inquire_index;
    // dy_syslog(LOG_DEBUG, "devId: %d, inquire_index: %d, record_type: %d\n", getCurDevID(payload), recvContent->inquire_index, recvContent->record_type);
}

/**
 * @brief       流消息响应报文记录导出处理
 * @param[in]   struct ipc_message *msg
 * @return      int
 * @retval      0:正常  !0:错误
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2024-05-22           QZY        创建初始版本          \n
*/
int DTC_Export_flow_data_process(struct ipc_message *msg)
{
    if (msg == NULL) {
        return -1;
    }
    uint8_t flowHeadLen = 0;
    CanrbusFlow_Mqtt_t *canrbus = (CanrbusFlow_Mqtt_t *)msg->p.buf;

    if (canrbus->msgFlowWorkId != CMD_TYPE_RECORD) {
        return 0;
    }

    // 由于不能保证报文中的canrbus->layer正确，需要根据设备ID自行解析层级
    if (canrbus->msgFlowBauId > 0 && 0 == canrbus->msgFlowBcuId && 0 == canrbus->msgFlowBmuId) {
        // bau
        canrbus->layer = BMS_HW_LEVEL_3;
    } else if (canrbus->msgFlowBauId > 0 && canrbus->msgFlowBcuId > 0 && 0 == canrbus->msgFlowBmuId) {
        // bcu
        canrbus->layer = BMS_HW_LEVEL_2;
    } else if (canrbus->msgFlowBcuId > 0 && canrbus->msgFlowBmuId > 0) {
        canrbus->layer = BMS_HW_LEVEL_1;
    } else {
        return -1;
    }

    // 根据层级获取框架头长度
    flowHeadLen = CanrbusFlowGetHeaderLen(canrbus->layer);
    DTC_Export_db_update(canrbus, msg->p.len, flowHeadLen);
    return 0;
}

static int DTC_Export_get_DB(int indexDbAddr, uint16_t bankid, uint16_t rackid)
{
    uint16_t dataBuf = 0;
    int value = 0;
    EMS_DEV_REG_DATA_S regData = {0};
    char valid = 0;
    regData.bankId = bankid;
    regData.rackId = rackid;
    regData.startAddr = indexDbAddr;
    regData.regCount = 1;
    regData.len = 2;
    regData.dbValid = &valid;
    int ret = BmserProtocolExt_ReadRegisterDb(&regData, (uint8_t*)&dataBuf, regData.len);
    value = (int)BIG_TO_LITTLE_ENDIAN_16(dataBuf);
    return value;
}

// 请求接口
void DTC_Export_Send_Inquire(uint8_t record_type, uint16_t inquire_index, uint8_t devid)
{
    uint32_t len = 0, payload_len = 0;
    uint8_t data[4] = {0};
    uint8_t payload[256]= {0};
    char topic[TOPIC_MAX_LEN] = {0};
    char sn[SN_MAX_LEN] = {0};
    struct ipc_topic t = {0};
    struct ipc_payload p = {0};

    if (0 != bmser_dev_get_board_sn(sn)) {
        return;
    }
    CanrbusFlow_Infor_t pCanrInfor = {0};
    DTC_Export_Inquire_Content_t *InqData = (DTC_Export_Inquire_Content_t*)data;
    InqData->export_type = DTC_EXPORT_TYPE_OTHER;
    InqData->record_type = record_type; 
    InqData->inquire_index = inquire_index;
    len = sizeof(data);
    // DTC记录导出仅支持单播
    pCanrInfor.isHierMode = Std_False;
    pCanrInfor.bmuId = 0;
    pCanrInfor.bauId = 1;
    if(devid == 0) {
        // bank 
        pCanrInfor.bcuId = 0;
        pCanrInfor.devlevel = BMS_HW_LEVEL_3;
        pCanrInfor.devType = BROADCAST_LEVEL_3_HUB; // 该选项与devlevel绑定，考虑库中去除
    } else {
        // rack
        pCanrInfor.bcuId = devid;
        pCanrInfor.devlevel = BMS_HW_LEVEL_2;
        pCanrInfor.devType = BROADCAST_LEVEL_2_IBU;
    }
    pCanrInfor.cmdCode = CMD_TYPE_RECORD;

    CanrbusFlowPackPayload(&pCanrInfor, data, len, payload, &payload_len);
    snprintf(topic, TOPIC_MAX_LEN, BINARY_FLOW_SET_TOPIC, sn);
    t.name = topic;
    p.buf = payload;
    p.len = payload_len;
    communication_publish(&t,&p);
}

void DtcExport_Maintaince(int recordType, int devid)
{
    int tableIndexValue = 0;
    int indexDbAddr = 0, maxNumDbAddr = 0;
    int maxNum, diffNum;
    int dtc_waitTime = 0;

    uint16_t bankid, rackid = 0;
    switch (g_dtcInfor.exportStep)
    {
        case DTC_Export_Step_Check_Index_DB:
        {
            bmser_dev_calcBankIdAndRackIdByDevId(devid, &bankid, &rackid);
            // 处理index DB地址，最大数量DB地址
            if (devid == 0) {
                indexDbAddr = (recordType == DTC_RECORD_TYPE_ALARM) ? BAU_ALARM_INDEX_DB_ADDR : BAU_EVENT_INDEX_DB_ADDR;
                maxNumDbAddr = (recordType == DTC_RECORD_TYPE_ALARM) ? BAU_ALARM_MAX_DTC_NUM_ADDR : BAU_EVENT_MAX_DTC_NUM_ADDR;
            } else if (devid > 0) {
                indexDbAddr = (recordType == DTC_RECORD_TYPE_ALARM) ? BCU_ALARM_INDEX_DB_ADDR : BCU_EVENT_INDEX_DB_ADDR;
                maxNumDbAddr = (recordType == DTC_RECORD_TYPE_ALARM) ? BCU_ALARM_MAX_DTC_NUM_ADDR : BCU_EVENT_MAX_DTC_NUM_ADDR;
            }
            g_dtcInfor.DBIndexValue = DTC_Export_get_DB(indexDbAddr, bankid, rackid);
            g_dtcInfor.DBMaxDtcNum  = DTC_Export_get_DB(maxNumDbAddr, bankid, rackid);
            // DB索引值与上一次的表中索引相比未发生变化，跳过查表获取
            if (g_dtcInfor.DBIndexValue == g_dtcInit.oldTableIndex[devid][recordType]) {
                tableIndexValue = g_dtcInfor.DBIndexValue;
            } else {
                DTC_Export_DB3_getIndexID(bankid, rackid, recordType, &tableIndexValue);
                g_dtcInit.oldTableIndex[devid][recordType] = tableIndexValue;
            }

            // 处理起始请求index
            if (recordType == DTC_RECORD_TYPE_ALARM) {
                maxNum = DTC_EXPORT_ALARM_NUM;
            } else {
                maxNum = DTC_EXPORT_EVENT_NUM;
            }
            // XXX: 当前逻辑基于最新主控，需删除旧的DTC记录;
            // 计算DB值与表中记录的最大DBindex差值
            diffNum = g_dtcInfor.DBIndexValue - tableIndexValue;
            if (diffNum >= maxNum) {
                // 差值大于等于最大单次请求数量, 起始请求index取DB值 - 最大单次请求数量 + 1(即最新maxNum条)
                g_dtcInfor.inquireIndex = g_dtcInfor.DBIndexValue - maxNum + 1;
            } else if (diffNum >= 0) {
                // 差值在[0 - 最大单次请求数量)区间内, 起始请求index取表中记录的最大DBindex + 1
                g_dtcInfor.inquireIndex = tableIndexValue + 1;
            } else {
                // 差值小于0, 说明下位机DB索引值发生了轮转(或者主控发生变动)
                if (g_dtcInfor.DBIndexValue > maxNum) {
                    // 下位机索引DB增长较快, 仅请求最新maxNum条
                    g_dtcInfor.inquireIndex = g_dtcInfor.DBIndexValue - maxNum + 1;
                } else {
                    if (g_dtcInfor.DBMaxDtcNum > tableIndexValue) {
                        // 请求[tableIndexValue+1, 最大DTC数量]区间内的记录(最大10条)
                        g_dtcInfor.isRotating = true;
                        if (g_dtcInfor.DBMaxDtcNum - tableIndexValue > maxNum) {
                            g_dtcInfor.inquireIndex = g_dtcInfor.DBMaxDtcNum + g_dtcInfor.DBIndexValue - maxNum;
                        } else {
                            g_dtcInfor.inquireIndex = tableIndexValue + 1;
                        }
                    } else {
                        // 异常情况(表中记录的条目index >= 主控最大DTC数量)
                        if(g_dtcInfor.DBIndexValue - maxNum + 1 >= 0) {
                            g_dtcInfor.inquireIndex = g_dtcInfor.DBIndexValue - maxNum + 1;
                        } else {
                            g_dtcInfor.inquireIndex = 0;
                        }
                    }
                }
            }
            g_dtcInfor.exportStep = DTC_Export_Step_Send_Inquire;
            g_dtcInfor.sleepTime = 0;
            // printf("devid: %d, record_type: %d, tableIndexValue: %d, dbIndexValue: %d, indexValue: %d, isRotating: %d\n",
            //     devid, recordType, tableIndexValue, g_dtcInfor.DBIndexValue, g_dtcInfor.inquireIndex, g_dtcInfor.isRotating);
            break;
        }
        // 发送请求
        case DTC_Export_Step_Send_Inquire:
            if((g_dtcInfor.inquireIndex <= g_dtcInfor.DBIndexValue) || \
            (g_dtcInfor.isRotating && (g_dtcInfor.inquireIndex <= g_dtcInfor.DBMaxDtcNum))) {
                DTC_Export_Send_Inquire(recordType, g_dtcInfor.inquireIndex, devid);
                g_dtcInfor.exportStep = DTC_Export_Step_Recvd_Ack;
                g_dtcInfor.sleepTime = DTC_INQ_SLEEP_TIME - DTC_BASE_SLEEP_TIME;
            } else {
                g_dtcInfor.exportStep = DTC_Export_Step_OK;
                g_dtcInfor.sleepTime = 0;
            }
            break;
        case DTC_Export_Step_Recvd_Ack:
            if (g_dtcInfor.isRecvd == g_dtcInfor.inquireIndex || g_dtcInfor.isRecvd == DTC_INQUIRE_INDEX_ERR) {
                // 上一条记录已处理完，或收到错误响应；请求下一条
                g_dtcInfor.inquireIndex++;
                g_dtcInfor.isRecvd = -1;
                g_dtcInfor.waitTime = 0;
                g_dtcInfor.tryTimes = 0;
                g_dtcInfor.exportStep = DTC_Export_Step_Send_Inquire;
                g_dtcInfor.sleepTime = DTC_INQ_SLEEP_TIME - DTC_BASE_SLEEP_TIME;
            } else {
                g_dtcInfor.waitTime += 1;
                //超时，根据是否为多包确定等待时间
                if(g_dtcInfor.isMultiPkg) {
                    dtc_waitTime = g_dtcInit.mulitWaitTime;
                } else {
                    dtc_waitTime = g_dtcInit.singleWaitTime;
                }
                if(g_dtcInfor.waitTime >= dtc_waitTime) {
                    g_dtcInfor.exportStep =  DTC_Export_Step_Send_Inquire;
                    g_dtcInfor.waitTime = 0;
                    ++g_dtcInfor.tryTimes;
                    g_dtcInfor.sleepTime = 0;
                    if(g_dtcInfor.tryTimes >= DTC_MAX_RETRY_TIMES) {
                        // HACK: 超过重传次数后考虑重读DB索引值，判断索引值是否较上次读取产生较大变化；这种情况可能是更换了主控或主控修改了ID，考虑解决方案
                        // 超过最大重传次数，仍未收到响应，视为该簇主控断连，进入下一阶段请求
                        g_dtcInfor.exportStep = DTC_Export_Step_OK;
                        g_dtcInfor.sleepTime = DTC_BASE_SLEEP_TIME;
                    }
                }
            }
            break;
        case DTC_Export_Step_OK:
            // 清空多包缓存
            if (g_dtcInfor.isMultiPkg) {
                g_dtcInfor.isMultiPkg = false;
                memset(&g_dtcMulit, 0, sizeof(Dtc_Export_Record_MultiPkg_Infor));
            }
            g_dtcInfor.isRecvd = 0;
            g_dtcInfor.inquireIndex = 0;
            g_dtcInfor.waitTime = 0;
            g_dtcInfor.tryTimes = 0;
            break;
        default:
            break;
    }
}

void DTC_Export_Runnable()
{
    if (g_dtcInit.curDevId <= g_dtcInit.rackNum)
    {
        DtcExport_Maintaince(g_dtcInit.curRecordType, g_dtcInit.curDevId);
        if (g_dtcInfor.exportStep == DTC_Export_Step_OK)
        {
            // 告警、事件类记录交替请求处理
            if (g_dtcInit.curRecordType == DTC_RECORD_TYPE_ALARM)
            {
                g_dtcInit.curRecordType = DTC_RECORD_TYPE_EVENT;
            }
            else
            {
                g_dtcInit.curDevId++;
                g_dtcInit.curRecordType = DTC_RECORD_TYPE_ALARM;
            }
            memset(&g_dtcInfor, 0, sizeof(Dtc_Export_Record_Run_Infor));
            g_dtcInfor.exportStep = DTC_Export_Step_Check_Index_DB;
        }
    }
    else
    {
        if (bmser_jsonGetScene() == SCENE_MCU_AND_CAN)
        {
            g_dtcInit.curDevId = 0;
        }
        else
        {
            g_dtcInit.curDevId = 1;
        }
        memset(&g_dtcInfor, 0, sizeof(Dtc_Export_Record_Run_Infor));
        g_dtcInfor.exportStep = DTC_Export_Step_Check_Index_DB;
    }
}

/* DTC记录导出主线程 */
void* dtc_runnable_thread(void* param)
{
    while (1)
    {
        DTC_Export_Runnable();
        /*
            当前休眠时间：
            无dtc要查询间隔：50ms(每簇两种类型)
            dtc查询间隔：2s
            最后一簇至第一簇：75ms
        */
        usleep(DTC_BASE_SLEEP_TIME + g_dtcInfor.sleepTime);
    }
    dy_syslog(LOG_ERR,"dtc export runnable encount error \n");
    DTC_Export_DB3_deinit();
    pthread_exit(NULL);
    return (void*)0;
}

int DTC_EXport_run_init()
{
    pthread_t dtc_runnable_threads;
    int tid, ret = 0, Id = 0;
    bool isBAUEnabled = false, isBCUEnabled = false;

    memset(&g_dtcInfor, 0, sizeof(Dtc_Export_Record_Run_Infor));
    memset(&g_dtcInit, 0, sizeof(Dtc_Export_Record_Init_Infor));
    g_dtcInit.rackNum = bmser_jsonGetRackNum();
    g_dtcInit.curRecordType = DTC_RECORD_TYPE_ALARM;

    // 根据应用场景初始化
    if (bmser_jsonGetScene() == SCENE_MCU_AND_CAN)
    {
        // MCU+CAN场景, BAU,BCU均开启dtc, 设备ID从0开始
        g_dtcInit.curDevId = 0;
    }
    else
    {
        // Linux + CAN / Linux + TCP 场景, 仅BCU开启dtc, 设备ID从1开始
        g_dtcInit.curDevId = 1;
    }

   // 从json配置中获取单包与多包等待时间
    g_dtcInit.singleWaitTime = DTC_export_get_single_wait_time();
    if (g_dtcInit.singleWaitTime == 0)
    {
        g_dtcInit.singleWaitTime = DTC_MAX_WAIT_TIME;
    }
    g_dtcInit.mulitWaitTime = DTC_export_get_multi_wait_time();
    if (g_dtcInit.mulitWaitTime == 0)
    {
        g_dtcInit.mulitWaitTime = DTC_MULTI_MAX_WAIT_TIME;
    }

    ret |= DTC_Export_DB3_init();
    dy_syslog(LOG_DEBUG, "scene: %d.\n", bmser_jsonGetScene());

    // 初始化完成后作一次DB3清理
    DTC_Export_DB3_space_cleaning(DTC_RECORD_TYPE_ALARM);
    DTC_Export_DB3_space_cleaning(DTC_RECORD_TYPE_EVENT);

    // 获取表中记录的最大条目Id
    DTC_Export_DB3_getMaxID(&Id);
    g_dtcInit.recordId = Id;

    tid = pthread_create(&dtc_runnable_threads, NULL, dtc_runnable_thread, NULL);
    if (tid < 0)
    {
        ret = -1;
        dy_syslog(LOG_ERR,"dtc runnable thread create failed \r\n");
    }
    else
    {
        pthread_detach(dtc_runnable_threads);
    }

    return ret;
}