Initial commit: CCU621_M firmware project with BLE debug link support.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-08 17:28:36 +08:00
commit 9ceb218f80
1597 changed files with 724159 additions and 0 deletions
+853
View File
@@ -0,0 +1,853 @@
/**
******************************************************************************
* @file system_data.c
* @brief 系统数据交互模块实现(简化版)
*
* 该模块负责系统信息、充电信息获取、充电控制等功能
* 为参数配置、文件获取等功能预留接口
******************************************************************************
*/
#include "system_data.h"
#include <string.h>
#include <stdio.h>
#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