Files

853 lines
30 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
******************************************************************************
* @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