/** * @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]; }