/** ****************************************************************************** * @file system_data.c * @brief 系统数据交互模块实现(简化版) * * 该模块负责系统信息、充电信息获取、充电控制等功能 * 为参数配置、文件获取等功能预留接口 ****************************************************************************** */ #include "system_data.h" #include #include #include "FreeRTOS.h" #include "task.h" #include "semphr.h" #include "publicdata/type.h" #include "publicdata/public_define.h" #if TCP_DEBUG_EN #include "tcp_ser/tcp_server.h" #include "tcp_ser/tcp_protocol.h" #include "flash_file_mgr/fault_flash_impl.h" #include "plat_comm/impl/bs_public_impl.h" #include "publicdata/publicdata.h" #include "flowctrl/flowctrl_task.h" #include "collect_ctrl/collect_task.h" #include "bms/bms_interface.h" #include "meter_calculate/meter_calculate_impl.h" #include "flash_file_mgr/meter_calculate_flash_impl.h" #include "fault_cheak/fault_interface.h" #include "app_fatfs/fatfs_card.h" /** * @brief 获取默认系统信息(从system_data模块获取) * @param systemInfo 输出系统信息结构体 */ void tcp_get_default_system_info(tcp_system_info_data_t *systemInfo) { REAL_FAULT_DATA_T rl_data; if (systemInfo == NULL) { return; } v_get_fault_data(&rl_data); memset(systemInfo, 0, sizeof(tcp_system_info_data_t)); /* 从system_data模块获取系统信息 */ strcpy(systemInfo->systemModel, (char *)Device_Model); //设备型号 systemInfo->gunCount = GUN_MAX_CNT; //最大支持枪数量 systemInfo->devicePower = g_t_share_data.t_sys_fix_cfg.u16_ratePow; //设备功率 kW systemInfo->networkStatus = u8_bs_get_log_on_flag(); systemInfo->faultCount = rl_data.u8_fault_cnt; strcpy(systemInfo->version, (char *)Software_Version); } static void tcp_copy_log_field(char *dst, size_t dst_sz, const U8_T *src, size_t src_sz) { size_t i; if ((dst == NULL) || (dst_sz == 0U)) { return; } dst[0] = '\0'; if (src == NULL) { return; } for (i = 0U; i + 1U < dst_sz && i < src_sz; i++) { U8_T b = src[i]; if (b == 0U) { break; } if (b < 0x20U || b > 0x7EU) { break; } dst[i] = (char)b; } dst[i] = '\0'; } /** * @brief 获取默认充电枪数据(从system_data模块获取) * @param gunData 输出充电枪数据结构体 * @param gunNumber 枪编号 (1-2) */ void tcp_get_default_gun_data(tcp_gun_data_t *gunData, uint8_t gunNumber) { U8_T u8_gunNo = gunNumber -1; U8_T u8_gunState = u16_flow_put_data(u8_gunNo , E_FLOW_PUT_DATA_GUN_REAL_STATE,0); //0空闲 1充电启动 2绝缘启动 3绝缘计算完成 4绝缘检测模块停止 5开始预充 6预充完成 7充电中 8BMS通讯超时 9充电停止 10充电停止完成 U8_T u8_gunLink = u8_get_gun_yx_data(YX_GUN_LINK,u8_gunNo); U16_T u16_needVol = u16_bms_put_data(u8_gunNo,E_BMS_PUT_DATA_BMS_NEED_VOL,0); U16_T u16_needCur = u16_bms_put_data(u8_gunNo,E_BMS_PUT_DATA_BMS_NEED_CUR,0); U16_T u16_outVol = (U16_T)(u64_get_meter_data(u8_gunNo,0,E_METER_DATA_VOL)/1000); //充电电压 精度 0.1V U16_T u16_outCur = (U16_T)(u64_get_meter_data(u8_gunNo,0,E_METER_DATA_CUR)/1000); //充电电流 精度 0.1A S_LOG_DATA s_log; char user_field[32]; memset(&s_log , 0 ,sizeof(S_LOG_DATA)); v_meterlog_put_char_log_data(u8_gunNo,&s_log); //获取订单信息 if (gunData == NULL) { return; } memset(gunData, 0, sizeof(tcp_gun_data_t)); /* 设置枪编号 */ gunData->gunNumber = gunNumber; /* 从system_data模块获取枪信息 */ if(u8_gunState == 0 && u8_gunLink == 0) gunData->chargingStatus = CHARGING_STATUS_IDLE; /* 空闲 */ else if(u8_gunState == 0 && u8_gunLink == 1) gunData->chargingStatus = CHARGING_STATUS_CONNECTED; /* 已连接 */ else if(u8_gunState > 0 && u8_gunState < 7) gunData->chargingStatus = CHARGING_STATUS_STARTING; /* 启动中 */ else if(u8_gunState >= 7 && u8_gunState <= 8) gunData->chargingStatus = CHARGING_STATUS_CHARGING; /* 充电中 */ else if(u8_gunState > 8) gunData->chargingStatus = CHARGING_STATUS_FINISHED; /* 充电完成 */ gunData->gunConnectionStatus = u8_gunLink; gunData->demandVoltage = u16_needVol / 10.0f; gunData->demandCurrent = u16_needCur / 10.0f; gunData->actualVoltage = u16_outVol / 10.0f; gunData->actualCurrent = u16_outCur / 10.0f; /* 空闲/仅插枪:不上送无效订单残留,避免 JSON 过长导致 BLE 分片异常 */ if (gunData->chargingStatus <= CHARGING_STATUS_CONNECTED) { gunData->energy = 0.0f; gunData->cost = 0.0f; gunData->batterySOC = 0.0f; gunData->charge_time = 0U; gunData->userId[0] = '\0'; gunData->orderNumber[0] = '\0'; return; } gunData->energy = (float)s_log.u32_used_energy * 0.0001f; gunData->cost = (float)s_log.u32_used_money * 0.0001f; gunData->batterySOC = (s_log.u8_endSoc <= 100U) ? (float)s_log.u8_endSoc : 100.0f; gunData->charge_time = s_log.u16_ChargedTime; tcp_copy_log_field(user_field, sizeof(user_field), s_log.u8_user_id, sizeof(s_log.u8_user_id)); if (user_field[0] != '\0') { (void)snprintf(gunData->userId, sizeof(gunData->userId), "USER_%s", user_field); } tcp_copy_log_field(gunData->orderNumber, sizeof(gunData->orderNumber), s_log.u8_preTradeNo, sizeof(s_log.u8_preTradeNo)); //测试 // if(u8_gunNo == 0) gunData->chargingStatus = CHARGING_STATUS_CONNECTED; // else gunData->chargingStatus = CHARGING_STATUS_CHARGING; // gunData->gunConnectionStatus = 1; } void v_mydebug_char_ctrl(U8_T u8_gunNo, U8_T u8_flag, U16_T u16_res) { S_FLOW_CHARGE_CTRL_INFO e_charge_ctrl_info; memset(&e_charge_ctrl_info, 0, sizeof(S_FLOW_CHARGE_CTRL_INFO)); e_charge_ctrl_info.e_cmd = u8_flag; if (u8_flag == CMD_ON) { e_charge_ctrl_info.e_start_res = CTR_CMD_DEBUG; e_charge_ctrl_info.e_sdk_chargMode = E_SDK_CHGMOD_NONE; } else { e_charge_ctrl_info.e_stop_res = E_NORMAL_1001; } v_flow_start_stop_ctrl(u8_gunNo, &e_charge_ctrl_info); TCP_PRINT("[%d]gun charge ctrl[%d],[%d]\n", u8_gunNo, u8_flag, u16_res); if (u8_flag == CMD_OFF) { v_meterlog_set_stop_char_log_info(u8_gunNo, E_NORMAL_1001); } else { S_CHAR_LOG_START_DATA s_log_start_data; memset(&s_log_start_data, 0, sizeof(S_CHAR_LOG_START_DATA)); s_log_start_data.e_start_reason = e_charge_ctrl_info.e_start_res; strncpy((char *)s_log_start_data.u8_user_id, "DEBUG_001", EVS_MAX_TRADE_LEN); v_meterlog_set_start_char_log_info(u8_gunNo, &s_log_start_data); } } /** * @brief 停止充电(模拟实现) * @param gunNumber 枪编号 (1-2) * @param message 输出消息 * @retval 0成功,-1失败 */ int system_data_stop_charge(uint8_t gunNumber, char *message) { if (gunNumber < 1 || gunNumber > GUN_MAX_CNT) { if (message) strcpy(message, "参数错误:枪编号无效"); return -1; } v_mydebug_char_ctrl(gunNumber-1 , CMD_OFF ,0); if (message) strcpy(message, "充电停止成功(模拟)"); return 0; } /** * @brief 启动充电(模拟实现) * @param gunNumber 枪编号 (1-2) * @param userId 用户ID * @param orderNumber 订单号 * @param message 输出消息 * @retval 0成功,-1失败 */ int system_data_start_charge(uint8_t gunNumber, const char *userId, const char *orderNumber, char *message) { if (gunNumber < 1 || gunNumber > GUN_MAX_CNT) { if (message) strcpy(message, "参数错误:枪编号无效"); return -1; } v_mydebug_char_ctrl(gunNumber-1 , CMD_ON ,0); if (message) strcpy(message, "充电启动成功(模拟)"); return 0; } /** * @brief 获取系统故障数据 * @param response 输出故障信息响应结构体 * @retval 无 */ void tcp_get_system_fault_data(tcp_fault_info_response_t *response) { REAL_FAULT_DATA_T rl_data; U8_T valid_fault_count = 0; int i, j; if (response == NULL) { return; } memset(response, 0, sizeof(tcp_fault_info_response_t)); v_get_fault_data(&rl_data); //获取故障信息 /* 首先统计有效故障数量(e_mag != 0) */ for (i = 0; i < CURR_FAULT_MAX_CNT; i++) { if (rl_data.fault_data[i].e_mag != 0) { valid_fault_count++; } } /* 填充响应结构体 */ response->faultCount = valid_fault_count; /* 分配故障项数组内存 */ if (valid_fault_count > 0) { response->faults = (tcp_fault_item_t *)pvPortMalloc(valid_fault_count * sizeof(tcp_fault_item_t)); if (response->faults == NULL) { TCP_PRINT("Failed to allocate memory for fault items\r\r\n"); response->faultCount = 0; return; } memset(response->faults, 0, valid_fault_count * sizeof(tcp_fault_item_t)); /* 转换故障数据格式 */ for (i = 0, j = 0; i < CURR_FAULT_MAX_CNT && j < valid_fault_count; i++) { Fault_data *fault = &rl_data.fault_data[i]; /* 跳过无效故障(e_mag == 0) */ if (fault->e_mag == 0) { continue; } /* 转换故障位置 */ /* E_WHOLE_PILE = 0, //整桩-终端 E_WHOLE_HOST = 500, //整桩-主机-功率分配 E_GUN = 1000, //枪地址 E_CHAR_MDU = 2000, //充电模块地址 E_SWH_MDU = 3000, //开关模块地址 E_OTHER = 4000, //其他位置 */ /* 根据E_FAULT_SITE枚举值判断故障位置 */ if (fault->e_ingun >= E_OTHER) { snprintf(response->faults[j].location,sizeof(response->faults[j].location) -1, "其他故障"); } else if (fault->e_ingun >= E_SWH_MDU) { snprintf(response->faults[j].location,sizeof(response->faults[j].location) -1, "开关模块 %d",fault->e_ingun - E_SWH_MDU); } else if (fault->e_ingun >= E_CHAR_MDU) { snprintf(response->faults[j].location,sizeof(response->faults[j].location) -1, "充电模块 %d",fault->e_ingun - E_CHAR_MDU); } else if (fault->e_ingun >= E_GUN) { snprintf(response->faults[j].location,sizeof(response->faults[j].location) -1, "充电枪 %d",fault->e_ingun - E_GUN); } else if (fault->e_ingun >= E_WHOLE_HOST) { snprintf(response->faults[j].location,sizeof(response->faults[j].location) -1, "整桩主机 %d",fault->e_ingun - E_WHOLE_HOST); } else { snprintf(response->faults[j].location,sizeof(response->faults[j].location) -1, "整桩终端 %d",fault->e_ingun); } snprintf(response->faults[j].code,sizeof(response->faults[j].code) -1, "%d",fault->e_mag); char mag[FAULT_GET_MAG_MAX_LEN]= {0}; v_get_fault_info(fault->e_mag , mag ,FAULT_GET_MAG_MAX_LEN); snprintf(response->faults[j].description,sizeof(response->faults[j].description) -1, "%s",mag); /* 转换时间格式 */ snprintf(response->faults[j].time, sizeof(response->faults[j].time), "%04d-%02d-%02d %02d:%02d:%02d", fault->time.iYear, fault->time.ucMonth, fault->time.ucDay, fault->time.ucHour, fault->time.ucMin, fault->time.ucSec); j++; /* 移动到下一个有效故障项 */ } } else { response->faults = NULL; } TCP_PRINT("Got %u valid faults from 0 total faults\r\r\n", valid_fault_count); } /** * @brief 处理自定义数据 * @param request 自定义数据请求 * @param response 自定义数据响应 * @retval 0成功,-1失败 */ int tcp_process_custom_data(const tcp_custom_data_t *request, tcp_custom_data_t *response) { if (request == NULL || response == NULL) { return -1; } TCP_PRINT("Processing custom data:\r\r\n"); TCP_PRINT(" functionContent: %s\r\r\n", request->functionContent); TCP_PRINT(" functionField: %s\r\r\n", request->functionField); TCP_PRINT(" functionParams: %s\r\r\n", request->functionParams); /* 复制请求数据到响应(根据用户要求,字段内容可以自定义) */ memset(response, 0, sizeof(tcp_custom_data_t)); /* 这里可以根据实际需求处理自定义数据 */ /* 示例:如果functionContent是"哈哈哈",则回复"呵呵呵" */ if(request->functionField[0] == '\0') //无数据 { TCP_PRINT("functionField is null\r\n"); //request->functionField //response->functionContent //request->functionParams } else if(strcmp(request->functionField, "reboot") == 0) { v_sys_reboot(); } else if(strcmp(request->functionField, "paramInit") == 0) { v_public_param_init(); strncpy(response->functionField , request->functionField , sizeof(response->functionField)-1); strncpy(response->functionContent , "success" , sizeof(response->functionContent)-1); strncpy(response->functionParams , "success" , sizeof(response->functionParams)-1); } #if BS_OCPP_EN else if(strcmp(request->functionField, "ocpp_cfg") == 0) // { strncpy(response->functionField , request->functionField , sizeof(response->functionField)-1); strncpy(response->functionContent , request->functionContent , sizeof(response->functionContent)-1); if(strcmp(request->functionContent, "getInfo") == 0) //获取信息 { v_get_ocpp_cfg_info(response->functionParams ,sizeof(response->functionParams)-1); } else if(request->functionContent[0] != '\0') //不为空 则是设置命令 { if(u8_set_ocpp_cfg_info(request->functionContent,request->functionParams) == 1) { strncpy(response->functionParams ,success , sizeof(response->functionContent)-1); } else { strncpy(response->functionParams ,failure , sizeof(response->functionContent)-1); } } } #endif else { strncpy(response->functionField , request->functionField , sizeof(response->functionField)-1); strncpy(response->functionContent , "unknown" , sizeof(response->functionContent)-1); } TCP_PRINT("Custom data processed:\r\r\n"); TCP_PRINT(" functionContent: %s\r\r\n", response->functionContent); TCP_PRINT(" functionField: %s\r\r\n", response->functionField); TCP_PRINT(" functionParams: %s\r\r\n", response->functionParams); return 0; } uint16_t tcp_history_get_total_count(const char *historyType) { if (historyType == NULL) { return 0u; } if (strcmp(historyType, "fault") == 0) { return u16_fault_get_his_count(); } if (strcmp(historyType, "charging") == 0) { v_chg_order_flash_init(); return v_get_chg_order_count(); } if (strcmp(historyType, "card") == 0) { uint32_t cnt = 0u; card_init(); if (card_get_count(&cnt) == CARD_STATUS_OK) { if (cnt > 0xFFFFu) { return 0xFFFFu; } return (uint16_t)cnt; } return 0u; } return 0u; } static void tcp_history_sanitize_commas(char *s) { /* 协议content字段内不得出现英文逗号,否则上位机会split(',')解析出错 */ if (s == NULL) { return; } while (*s != '\0') { if (*s == ',') { *s = ';'; } s++; } } static void tcp_history_format_comm_time(const Comm_Time *t, char *buf, size_t bufSize) { if (t == NULL || buf == NULL || bufSize == 0u) { return; } (void)snprintf(buf, bufSize, "%04d-%02d-%02d %02d:%02d:%02d", (int)t->iYear, (int)t->ucMonth, (int)t->ucDay, (int)t->ucHour, (int)t->ucMin, (int)t->ucSec); buf[bufSize - 1u] = '\0'; } /* 将订单中的停止原因转为可读文本:仅取 e_stop_reason[] 中第一个非空项(与多条 | 拼接相比更短,利于协议长度) */ static void tcp_history_build_stop_reason_text(const S_LOG_DATA *order, char *dst, size_t dstSize) { if (order == NULL || dst == NULL || dstSize == 0u) { return; } dst[0] = '\0'; for (int i = 0; i < NUM_1; i++) { E_FAULT_INFO code = order->e_stop_reason[i]; if (code == E_FAULT_NULL) { continue; } char frag[128] = {0}; v_get_fault_info(code, frag, (U16_T)sizeof(frag)); if (frag[0] == '\0') { (void)snprintf(frag, sizeof(frag), "%d", (int)code); } tcp_history_sanitize_commas(frag); (void)strncpy(dst, frag, dstSize - 1u); dst[dstSize - 1u] = '\0'; return; } (void)strncpy(dst, "-", dstSize - 1u); dst[dstSize - 1u] = '\0'; } uint16_t tcp_history_build_records(const char *historyType, uint16_t startIndex, uint16_t fetchCount, char (*time_buf)[HISTORY_TIME_STR_SIZE], char (*content_buf)[HISTORY_CONTENT_STR_SIZE], uint8_t *outIncludeTime, uint16_t *outTotalCount) { uint16_t totalCount = 0u; uint16_t wantedCount = 0u; uint16_t filledCount = 0u; uint8_t includeTime = 0u; if (historyType == NULL || time_buf == NULL || content_buf == NULL || outIncludeTime == NULL || outTotalCount == NULL) { return 0u; } memset(time_buf, 0, (size_t)HISTORY_QUERY_MAX_RECORDS * (size_t)HISTORY_TIME_STR_SIZE); memset(content_buf, 0, (size_t)HISTORY_QUERY_MAX_RECORDS * (size_t)HISTORY_CONTENT_STR_SIZE); if (strcmp(historyType, "fault") == 0) { includeTime = 1u; totalCount = u16_fault_get_his_count(); } else if (strcmp(historyType, "charging") == 0) { includeTime = 1u; v_chg_order_flash_init(); totalCount = v_get_chg_order_count(); } else if (strcmp(historyType, "card") == 0) { includeTime = 0u; uint32_t cnt = 0u; card_init(); if (card_get_count(&cnt) == CARD_STATUS_OK) { totalCount = (cnt > 0xFFFFu) ? 0xFFFFu : (uint16_t)cnt; } else { totalCount = 0u; } } else { *outIncludeTime = 0u; *outTotalCount = 0u; return 0u; } *outIncludeTime = includeTime; *outTotalCount = totalCount; if (fetchCount == 0u || totalCount == 0u) { return 0u; } wantedCount = fetchCount; if (wantedCount > HISTORY_QUERY_MAX_RECORDS) { wantedCount = HISTORY_QUERY_MAX_RECORDS; } if (startIndex >= totalCount) { return 0u; } if (wantedCount > (uint16_t)(totalCount - startIndex)) { wantedCount = (uint16_t)(totalCount - startIndex); } if (strcmp(historyType, "fault") == 0) { HIS_FAULT_DATA_T hisFault; memset(&hisFault, 0, sizeof(hisFault)); for (uint16_t i = 0u; i < wantedCount; i++) { uint16_t newest_pos = (uint16_t)(startIndex + i); if (u8_fault_read_his_by_newest(newest_pos, &hisFault) == 0u) { break; } snprintf(time_buf[i], HISTORY_TIME_STR_SIZE, "%04d-%02d-%02d %02d:%02d:%02d", hisFault.s_occur_time.iYear, hisFault.s_occur_time.ucMonth, hisFault.s_occur_time.ucDay, hisFault.s_occur_time.ucHour, hisFault.s_occur_time.ucMin, hisFault.s_occur_time.ucSec); char location[64] = {0}; char code[16] = {0}; char desc[128] = {0}; char actionTypeStr[16] = {0}; char value1Str[32] = {0}; char value2Str[32] = {0}; char field_content[HISTORY_CONTENT_STR_SIZE] = {0}; if (hisFault.e_site >= E_OTHER) { snprintf(location, sizeof(location), "其他故障"); } else if (hisFault.e_site >= E_SWH_MDU) { snprintf(location, sizeof(location), "开关模块 %d", hisFault.e_site - E_SWH_MDU); } else if (hisFault.e_site >= E_CHAR_MDU) { snprintf(location, sizeof(location), "充电模块 %d", hisFault.e_site - E_CHAR_MDU); } else if (hisFault.e_site >= E_GUN) { snprintf(location, sizeof(location), "充电枪 %d", hisFault.e_site - E_GUN); } else if (hisFault.e_site >= E_WHOLE_HOST) { snprintf(location, sizeof(location), "整桩主机 %d", hisFault.e_site - E_WHOLE_HOST); } else { snprintf(location, sizeof(location), "整桩终端 %d", hisFault.e_site); } snprintf(code, sizeof(code), "%d", (int)hisFault.e_fault_info); v_get_fault_info(hisFault.e_fault_info, desc, (U16_T)sizeof(desc)); snprintf(actionTypeStr, sizeof(actionTypeStr), "%d", (int)hisFault.ActType); snprintf(value1Str, sizeof(value1Str), "%d", (int)hisFault.s16_value1); snprintf(value2Str, sizeof(value2Str), "%d", (int)hisFault.s16_value2); tcp_history_sanitize_commas(location); tcp_history_sanitize_commas(desc); snprintf(field_content, sizeof(field_content), "%s,%s,%s,%s,%s,%s", location, code, desc, actionTypeStr, value1Str, value2Str); strncpy(content_buf[i], field_content, HISTORY_CONTENT_STR_SIZE - 1); content_buf[i][HISTORY_CONTENT_STR_SIZE - 1] = '\0'; filledCount++; } } else if (strcmp(historyType, "charging") == 0) { S_LOG_DATA order; memset(&order, 0, sizeof(order)); U32_T lastIndex = v_get_chg_order_last_index(); if (lastIndex == 0u) { return 0u; } for (uint16_t i = 0u; i < wantedCount; i++) { U32_T offset = (U32_T)(startIndex + i); if (lastIndex <= offset) { break; } U32_T index = lastIndex - offset; if (v_read_chg_order_record(&order, index) != 0u) { break; } snprintf(time_buf[i], HISTORY_TIME_STR_SIZE, "%04d-%02d-%02d %02d:%02d:%02d", order.EndChargeTime.iYear, order.EndChargeTime.ucMonth, order.EndChargeTime.ucDay, order.EndChargeTime.ucHour, order.EndChargeTime.ucMin, order.EndChargeTime.ucSec); char userId[40] = {0}; char stopCmd[16] = {0}; char tradeNoStr[EVS_MAX_TRADE_LEN + 4] = {0}; char preTradeStr[EVS_MAX_TRADE_LEN + 4] = {0}; char startTimeStr[HISTORY_TIME_STR_SIZE] = {0}; char stopTimeStr[HISTORY_TIME_STR_SIZE] = {0}; char stopReasonText[256] = {0}; const char *uid_src = (const char *)order.u8_user_id; uint16_t n = 0u; while (n < 32u && n < (uint16_t)(sizeof(userId) - 1u) && uid_src[n] != '\0') { userId[n] = uid_src[n]; n++; } userId[n] = '\0'; /* 停机码为 4 字节原始码,可能含 0x00,不能按 C 字符串拷贝,否则上位机看到为空 */ (void)snprintf(stopCmd, sizeof(stopCmd), "%d", (unsigned int)order.e_stop_reason[0]); { const char *ts = (const char *)order.u8_tradeNo; n = 0u; while (n < (uint16_t)(EVS_MAX_TRADE_LEN - 1u) && n < (uint16_t)(sizeof(tradeNoStr) - 1u) && ts[n] != '\0') { tradeNoStr[n] = ts[n]; n++; } tradeNoStr[n] = '\0'; } { const char *ps = (const char *)order.u8_preTradeNo; n = 0u; while (n < (uint16_t)(EVS_MAX_TRADE_LEN - 1u) && n < (uint16_t)(sizeof(preTradeStr) - 1u) && ps[n] != '\0') { preTradeStr[n] = ps[n]; n++; } preTradeStr[n] = '\0'; } tcp_history_format_comm_time(&order.StartChargeTime, startTimeStr, sizeof(startTimeStr)); tcp_history_format_comm_time(&order.EndChargeTime, stopTimeStr, sizeof(stopTimeStr)); tcp_history_sanitize_commas(userId); tcp_history_sanitize_commas(stopCmd); tcp_history_sanitize_commas(tradeNoStr); tcp_history_sanitize_commas(preTradeStr); tcp_history_build_stop_reason_text(&order, stopReasonText, sizeof(stopReasonText)); tcp_history_sanitize_commas(stopReasonText); char usedMoneyStr[64] = {0}; char usedEnergyStr[64] = {0}; snprintf(usedMoneyStr, sizeof(usedMoneyStr), "%u.%04u", (unsigned int)(order.u32_used_money / 10000u), (unsigned int)(order.u32_used_money % 10000u)); snprintf(usedEnergyStr, sizeof(usedEnergyStr), "%u.%04u", (unsigned int)(order.u32_used_energy / 10000u), (unsigned int)(order.u32_used_energy % 10000u)); /* * content 逗号分隔字段顺序(上位机表格不单独展示“停止时间”,与 JSON time 同源): * 订单索引,枪号,开始时间,停止时间,充电时长(分钟),开始SOC,停止SOC,用电量,金额, * 用户ID,设备流水号,平台流水号,停机原因(仅e_stop_reason首条),停机码(u8_stop_cmd四字节HEX共8位) */ char field_content[HISTORY_CONTENT_STR_SIZE] = {0}; snprintf(field_content, sizeof(field_content), "%u,%u,%s,%s,%u,%u,%u,%s,%s,%s,%s,%s,%s,%s", (unsigned int)order.u32_index, (unsigned int)order.u8_gunNo, startTimeStr, stopTimeStr, (unsigned int)order.u16_ChargedTime, (unsigned int)order.u8_startSoc, (unsigned int)order.u8_endSoc, usedEnergyStr, usedMoneyStr, userId, tradeNoStr, preTradeStr, stopReasonText, stopCmd); strncpy(content_buf[i], field_content, HISTORY_CONTENT_STR_SIZE - 1); content_buf[i][HISTORY_CONTENT_STR_SIZE - 1] = '\0'; filledCount++; } } else if (strcmp(historyType, "card") == 0) { uint32_t cnt = 0u; CardInfo *card_list = NULL; if (totalCount == 0u) { return 0u; } card_list = (CardInfo *)pvPortMalloc(sizeof(CardInfo) * (size_t)totalCount); if (card_list == NULL) { return 0u; } memset(card_list, 0, sizeof(CardInfo) * (size_t)totalCount); if (card_get_all(card_list, &cnt, totalCount) != CARD_STATUS_OK) { vPortFree(card_list); return 0u; } uint16_t u16_cnt = (uint16_t)cnt; if (u16_cnt < totalCount) { totalCount = u16_cnt; *outTotalCount = totalCount; } for (uint16_t i = 0u; i < wantedCount; i++) { uint16_t ascPos = (uint16_t)(totalCount - 1u - (uint16_t)(startIndex + i)); if (ascPos >= u16_cnt) { break; } char cardNum[40] = {0}; strncpy(cardNum, card_list[ascPos].card_num, 31); cardNum[31] = '\0'; tcp_history_sanitize_commas(cardNum); char field_content[HISTORY_CONTENT_STR_SIZE] = {0}; snprintf(field_content, sizeof(field_content), "%s,%u,%u", cardNum, (unsigned int)card_list[ascPos].balance, (unsigned int)card_list[ascPos].status); strncpy(content_buf[i], field_content, HISTORY_CONTENT_STR_SIZE - 1); content_buf[i][HISTORY_CONTENT_STR_SIZE - 1] = '\0'; filledCount++; } vPortFree(card_list); card_list = NULL; } return filledCount; } int tcp_history_clear_records(const char *historyType, char *outMessage, uint32_t outMessageSize) { if (historyType == NULL) { if (outMessage && outMessageSize > 0u) { strncpy(outMessage, "未知historyType", outMessageSize - 1u); outMessage[outMessageSize - 1u] = '\0'; } return -1; } if (strcmp(historyType, "fault") == 0) { v_fault_clear_his_fault(); if (outMessage && outMessageSize > 0u) { strncpy(outMessage, "Fault records cleared", outMessageSize - 1u); outMessage[outMessageSize - 1u] = '\0'; } return 0; } if (strcmp(historyType, "charging") == 0) { v_chg_order_clear_all(); if (outMessage && outMessageSize > 0u) { strncpy(outMessage, "Charge records cleared", outMessageSize - 1u); outMessage[outMessageSize - 1u] = '\0'; } return 0; } if (strcmp(historyType, "card") == 0) { CardStatus st = card_clear_all(); if (st == CARD_STATUS_OK) { if (outMessage && outMessageSize > 0u) { strncpy(outMessage, "卡信息已清除", outMessageSize - 1u); outMessage[outMessageSize - 1u] = '\0'; } return 0; } if (outMessage && outMessageSize > 0u) { snprintf(outMessage, outMessageSize, "Card info clear failed: %d", (int)st); } return -1; } if (outMessage && outMessageSize > 0u) { strncpy(outMessage, "未知historyType", outMessageSize - 1u); outMessage[outMessageSize - 1u] = '\0'; } return -1; } #endif