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
+441
View File
@@ -0,0 +1,441 @@
/**
* @file unsettled_order_mng.c
* @brief 未结算订单列表:EEPROM 持久化与 CRC 校验
*
* 功能说明:
* - 在 EEPROM `EEPROM_ADDR_UNSETTLED_MNG` 保存 `S_UNSETTLED_ORDER_MNG`:头标志 `UNSETTLED_HEADER`、
* 未结条数、以及除 CRC 字段外的 CRC-16 校验(与 `u16_calculate_crc` 一致)。
* - 每条未结订单仅保存其 Flash 订单号(`u32_chg_order_save_record` 返回的 `u32_index`)的 24 位压缩形式,
* 最多 `UNSETTLED_MAX_CNT` 条;列表按顺序追加,删除时前移尾部元素。
* - `u8_check_order_settled`:返回 1 表示该索引仍在未结列表中(未结算),0 表示不在列表中(视为已结或从未登记)。
* 命名与注释以头文件为准。
*/
#include "unsettled_order_mng.h"
#include "mylog/mylog.h"
/* 本文件打印使能:0=不编译打印,1=编译打印 */
#ifndef UNSETTLED_MNG_LOG_EN
#define UNSETTLED_MNG_LOG_EN (1)
#endif
#if UNSETTLED_MNG_LOG_EN
#define UNSETTLED_MNG_LOG(fmt, ...) MYLOG_MSG(TASK_ID_Meterfee, fmt, ##__VA_ARGS__)
#else
#define UNSETTLED_MNG_LOG(fmt, ...) ((void)0)
#endif
/*------ Local variables(局部变量) ----------------------*/
// 未结算订单管理信息全局变量
S_UNSETTLED_ORDER_MNG s_unsettledOrderMng;
/*------ Local function prototypes(局部函数声明) ---------*/
static void v_write_eeprom_unsettledMng(S_UNSETTLED_ORDER_MNG *unsettledMng);
static void v_read_eeprom_unsettledMng(S_UNSETTLED_ORDER_MNG *unsettledMng);
static U16_T u16_calculate_unsettled_crc(S_UNSETTLED_ORDER_MNG *unsettledMng);
static U8_T u8_find_order_index(U32_T orderIndex, U16_T *position);
static void v_uint32_to_3bytes(U32_T value, U8_T *bytes);
static U32_T u32_3bytes_to_uint32(const U8_T *bytes);
/*------ Exported functions(导出函数实现) ----------------*/
/**
* @brief 初始化未结算订单管理模块
*/
void v_unsettled_order_init(void)
{
// 读取EEPROM中的管理信息
v_read_eeprom_unsettledMng(&s_unsettledOrderMng);
// 检查数据完整性
if (s_unsettledOrderMng.u16_head != UNSETTLED_HEADER)
{
// 头标志错误,初始化默认值
s_unsettledOrderMng.u16_head = UNSETTLED_HEADER;
s_unsettledOrderMng.u16_unsettledCnt = 0;
// 清空索引数组(3字节数组)
for (U16_T i = 0; i < UNSETTLED_MAX_CNT; i++)
{
s_unsettledOrderMng.u8_unsettledIndexes[i][0] = 0;
s_unsettledOrderMng.u8_unsettledIndexes[i][1] = 0;
s_unsettledOrderMng.u8_unsettledIndexes[i][2] = 0;
}
// 计算并保存CRC
s_unsettledOrderMng.u16_crc = u16_calculate_unsettled_crc(&s_unsettledOrderMng);
v_write_eeprom_unsettledMng(&s_unsettledOrderMng);
UNSETTLED_MNG_LOG("UnsettledMng: init default");
}
else
{
// 验证CRC
U16_T calculatedCrc = u16_calculate_unsettled_crc(&s_unsettledOrderMng);
if (calculatedCrc != s_unsettledOrderMng.u16_crc)
{
// CRC校验失败,恢复默认值
UNSETTLED_MNG_LOG("UnsettledMng: CRC fail, reset default");
s_unsettledOrderMng.u16_unsettledCnt = 0;
// 清空索引数组(3字节数组)
for (U16_T i = 0; i < UNSETTLED_MAX_CNT; i++)
{
s_unsettledOrderMng.u8_unsettledIndexes[i][0] = 0;
s_unsettledOrderMng.u8_unsettledIndexes[i][1] = 0;
s_unsettledOrderMng.u8_unsettledIndexes[i][2] = 0;
}
// 重新计算CRC并保存
s_unsettledOrderMng.u16_crc = u16_calculate_unsettled_crc(&s_unsettledOrderMng);
v_write_eeprom_unsettledMng(&s_unsettledOrderMng);
}
else
{
#if 0 // 测试读取
s_unsettledOrderMng.u16_unsettledCnt = 1;
s_unsettledOrderMng.u8_unsettledIndexes[0][0] = 0;
s_unsettledOrderMng.u8_unsettledIndexes[0][1] = 0;
s_unsettledOrderMng.u8_unsettledIndexes[0][2] = 1;
s_unsettledOrderMng.u8_unsettledIndexes[1][0] = 0;
s_unsettledOrderMng.u8_unsettledIndexes[1][1] = 0;
s_unsettledOrderMng.u8_unsettledIndexes[1][2] = 0;
#endif
UNSETTLED_MNG_LOG("UnsettledMng: init ok, cnt=%u",
s_unsettledOrderMng.u16_unsettledCnt);
}
}
}
/**
* @brief 添加未结算订单索引
*/
U8_T u8_add_unsettled_order(U32_T orderIndex)
{
// 检查订单索引是否有效
if (orderIndex == 0)
{
UNSETTLED_MNG_LOG("UnsettledMng: invalid index");
return 1;
}
// 检查索引是否超过3字节范围(最大16,777,215
if (orderIndex > 0xFFFFFF)
{
UNSETTLED_MNG_LOG("UnsettledMng: index >24b, idx=%u", orderIndex);
return 1;
}
// 检查是否已存在
U16_T position;
if (u8_find_order_index(orderIndex, &position) == 0)
{
UNSETTLED_MNG_LOG("UnsettledMng: index exists, idx=%u", orderIndex);
return 0; // 已存在,不算失败
}
// 检查列表是否已满
if (s_unsettledOrderMng.u16_unsettledCnt >= UNSETTLED_MAX_CNT)
{
UNSETTLED_MNG_LOG("UnsettledMng: list full, add reject");
return 1;
}
// 添加到列表末尾(使用3字节存储)
v_uint32_to_3bytes(orderIndex, s_unsettledOrderMng.u8_unsettledIndexes[s_unsettledOrderMng.u16_unsettledCnt]);
s_unsettledOrderMng.u16_unsettledCnt++;
// 更新CRC并保存到EEPROM
s_unsettledOrderMng.u16_crc = u16_calculate_unsettled_crc(&s_unsettledOrderMng);
v_write_eeprom_unsettledMng(&s_unsettledOrderMng);
UNSETTLED_MNG_LOG("UnsettledMng: add ok, idx=%u, cnt=%u",
orderIndex, s_unsettledOrderMng.u16_unsettledCnt);
return 0;
}
/**
* @brief 移除已结算订单索引
*/
U8_T u8_remove_unsettled_order(U32_T orderIndex)
{
// 查找订单索引位置
U16_T position;
if (u8_find_order_index(orderIndex, &position) != 0)
{
UNSETTLED_MNG_LOG("UnsettledMng: idx not found, idx=%u", orderIndex);
return 1;
}
// 从列表中移除(将后面的元素前移)
for (U16_T i = position; i < s_unsettledOrderMng.u16_unsettledCnt - 1; i++)
{
// 复制3字节索引
s_unsettledOrderMng.u8_unsettledIndexes[i][0] = s_unsettledOrderMng.u8_unsettledIndexes[i + 1][0];
s_unsettledOrderMng.u8_unsettledIndexes[i][1] = s_unsettledOrderMng.u8_unsettledIndexes[i + 1][1];
s_unsettledOrderMng.u8_unsettledIndexes[i][2] = s_unsettledOrderMng.u8_unsettledIndexes[i + 1][2];
}
// 清空最后一个元素
s_unsettledOrderMng.u8_unsettledIndexes[s_unsettledOrderMng.u16_unsettledCnt - 1][0] = 0;
s_unsettledOrderMng.u8_unsettledIndexes[s_unsettledOrderMng.u16_unsettledCnt - 1][1] = 0;
s_unsettledOrderMng.u8_unsettledIndexes[s_unsettledOrderMng.u16_unsettledCnt - 1][2] = 0;
s_unsettledOrderMng.u16_unsettledCnt--;
// 更新CRC并保存到EEPROM
s_unsettledOrderMng.u16_crc = u16_calculate_unsettled_crc(&s_unsettledOrderMng);
v_write_eeprom_unsettledMng(&s_unsettledOrderMng);
UNSETTLED_MNG_LOG("UnsettledMng: rm ok, idx=%u, cnt=%u",
orderIndex, s_unsettledOrderMng.u16_unsettledCnt);
return 0;
}
/**
* @brief 检查订单是否已结算
*/
U8_T u8_check_order_settled(U32_T orderIndex)
{
U16_T position;
// 在未结算列表中查找
if (u8_find_order_index(orderIndex, &position) == 0)
{
return 1; // 找到,说明未结算
}
return 0; // 未找到,说明已结算
}
/**
* @brief 获取未结算订单数量
*/
U16_T u16_get_unsettled_order_count(void)
{
return s_unsettledOrderMng.u16_unsettledCnt;
}
/**
* @brief 获取所有未结算订单索引
*/
void v_get_unsettled_order_indexes(U32_T *indexArray, U16_T *count)
{
if (indexArray == NULL || count == NULL)
{
return;
}
*count = s_unsettledOrderMng.u16_unsettledCnt;
for (U16_T i = 0; i < s_unsettledOrderMng.u16_unsettledCnt; i++)
{
// 将3字节索引转换为32位整数
indexArray[i] = u32_3bytes_to_uint32(s_unsettledOrderMng.u8_unsettledIndexes[i]);
}
}
/**
* @brief 清除所有未结算订单记录
*/
void v_clear_all_unsettled_orders(void)
{
s_unsettledOrderMng.u16_unsettledCnt = 0;
// 清空索引数组(3字节数组)
for (U16_T i = 0; i < UNSETTLED_MAX_CNT; i++)
{
s_unsettledOrderMng.u8_unsettledIndexes[i][0] = 0;
s_unsettledOrderMng.u8_unsettledIndexes[i][1] = 0;
s_unsettledOrderMng.u8_unsettledIndexes[i][2] = 0;
}
// 更新CRC并保存到EEPROM
s_unsettledOrderMng.u16_crc = u16_calculate_unsettled_crc(&s_unsettledOrderMng);
v_write_eeprom_unsettledMng(&s_unsettledOrderMng);
UNSETTLED_MNG_LOG("UnsettledMng: clear all");
}
/**
* @brief 打印未结算订单状态(调试用)
*/
void v_print_unsettled_order_status(void)
{
UNSETTLED_MNG_LOG("=== Unsettled status ===");
UNSETTLED_MNG_LOG("Unsettled cnt: %u", s_unsettledOrderMng.u16_unsettledCnt);
if (s_unsettledOrderMng.u16_unsettledCnt > 0)
{
UNSETTLED_MNG_LOG("Unsettled idx list:");
for (U16_T i = 0; i < s_unsettledOrderMng.u16_unsettledCnt; i++)
{
U32_T orderIndex = u32_3bytes_to_uint32(s_unsettledOrderMng.u8_unsettledIndexes[i]);
UNSETTLED_MNG_LOG(" [%u] index=%u", i, orderIndex);
}
}
else
{
UNSETTLED_MNG_LOG("No unsettled order");
}
UNSETTLED_MNG_LOG("=====================");
}
/**
* @brief 计算CRC校验值
*/
U16_T u16_calculate_crc(const U8_T *data, U16_T length)
{
U16_T crc = 0xFFFF;
if (data == NULL || length == 0)
{
return crc;
}
for (U16_T i = 0; i < length; i++)
{
crc ^= (U16_T)data[i] << 8;
for (U8_T j = 0; j < 8; j++)
{
if (crc & 0x8000)
{
crc = (crc << 1) ^ UNSETTLED_CRC_POLY;
}
else
{
crc <<= 1;
}
}
}
return crc;
}
/*------ Local functions(局部函数实现) -------------------*/
/**
* @brief 写入未结算订单管理信息到EEPROM
*/
static void v_write_eeprom_unsettledMng(S_UNSETTLED_ORDER_MNG *unsettledMng)
{
if (unsettledMng == NULL)
{
return;
}
// 先计算CRC
unsettledMng->u16_crc = u16_calculate_unsettled_crc(unsettledMng);
// 写入到EEPROM
eeprom_write(EEPROM_ADDR_UNSETTLED_MNG, (U8_T *)unsettledMng, sizeof(S_UNSETTLED_ORDER_MNG));
}
/**
* @brief 从EEPROM读取未结算订单管理信息
*/
static void v_read_eeprom_unsettledMng(S_UNSETTLED_ORDER_MNG *unsettledMng)
{
if (unsettledMng == NULL)
{
return;
}
// 从EEPROM读取,eeprom_read返回HAL_OK(0)表示成功
if (eeprom_read(EEPROM_ADDR_UNSETTLED_MNG, (U8_T *)unsettledMng, sizeof(S_UNSETTLED_ORDER_MNG)) != HAL_OK)
{
// 读取失败,初始化默认值
unsettledMng->u16_head = 0;
unsettledMng->u16_unsettledCnt = 0;
unsettledMng->u16_crc = 0;
for (U16_T i = 0; i < UNSETTLED_MAX_CNT; i++)
{
unsettledMng->u8_unsettledIndexes[i][0] = 0;
unsettledMng->u8_unsettledIndexes[i][1] = 0;
unsettledMng->u8_unsettledIndexes[i][2] = 0;
}
}
}
/**
* @brief 计算未结算订单管理信息的CRC
*/
static U16_T u16_calculate_unsettled_crc(S_UNSETTLED_ORDER_MNG *unsettledMng)
{
if (unsettledMng == NULL)
{
return 0;
}
// 手动计算结构体大小,避免结构体对齐问题
// 结构体布局:u16_head(2) + u16_unsettledCnt(2) + u16_crc(2) + u8_unsettledIndexes[30][3](90)
// 总大小:2 + 2 + 2 + 90 = 96字节
// 计算除CRC字段外的数据:u16_head + u16_unsettledCnt + u8_unsettledIndexes
U8_T tempBuffer[94]; // 2 + 2 + 90 = 94字节
U16_T offset = 0;
// 复制头标志
tempBuffer[offset++] = (unsettledMng->u16_head >> 8) & 0xFF;
tempBuffer[offset++] = unsettledMng->u16_head & 0xFF;
// 复制未结算订单数量
tempBuffer[offset++] = (unsettledMng->u16_unsettledCnt >> 8) & 0xFF;
tempBuffer[offset++] = unsettledMng->u16_unsettledCnt & 0xFF;
// 复制索引数组(3字节数组)
for (U16_T i = 0; i < UNSETTLED_MAX_CNT; i++)
{
for (U8_T j = 0; j < 3; j++)
{
tempBuffer[offset++] = unsettledMng->u8_unsettledIndexes[i][j];
}
}
// 计算CRC
return u16_calculate_crc(tempBuffer, offset);
}
/**
* @brief 在未结算订单列表中查找订单索引
*/
static U8_T u8_find_order_index(U32_T orderIndex, U16_T *position)
{
for (U16_T i = 0; i < s_unsettledOrderMng.u16_unsettledCnt; i++)
{
U32_T storedIndex = u32_3bytes_to_uint32(s_unsettledOrderMng.u8_unsettledIndexes[i]);
if (storedIndex == orderIndex)
{
if (position != NULL)
{
*position = i;
}
return 0; // 找到
}
}
return 1; // 未找到
}
/**
* @brief 将32位整数转换为3字节数组
*/
static void v_uint32_to_3bytes(U32_T value, U8_T *bytes)
{
bytes[0] = (value >> 16) & 0xFF; // 最高字节
bytes[1] = (value >> 8) & 0xFF; // 中间字节
bytes[2] = value & 0xFF; // 最低字节
}
/**
* @brief 将3字节数组转换为32位整数
*/
static U32_T u32_3bytes_to_uint32(const U8_T *bytes)
{
return ((U32_T)bytes[0] << 16) | ((U32_T)bytes[1] << 8) | (U32_T)bytes[2];
}