Initial commit: CCU621_M firmware project with BLE debug link support.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
#include "app_init.h"
|
||||
#include "app_init/task_lock.h"
|
||||
|
||||
#include "mylog/mylog.h"
|
||||
#include "bms/bms_task.h"
|
||||
#include "collect_ctrl/collect_task.h"
|
||||
#include "flowctrl/flowctrl_task.h"
|
||||
#include "fault_cheak/faultcheck_task.h"
|
||||
#include "mdu_comm/mdu_comm_task.h"
|
||||
|
||||
#include "plat_comm/plat_comm_task.h"
|
||||
#include "ui/ui_task.h"
|
||||
#include "wdt_task/wdt_task.h"
|
||||
#include "meter_calculate/meter_coll_task.h"
|
||||
#include "meter_calculate/calculate_task.h"
|
||||
#include "tcp_ser/tcp_ser_task.h"
|
||||
|
||||
#include "sys_drv_init.h"
|
||||
#include "publicdata/publicdata.h"
|
||||
#include "bsp_include.h"
|
||||
|
||||
#if SYSTEM_TYPE == SYSTEM_TYPE_CCU601E_D
|
||||
extern struct netif gnetif;
|
||||
|
||||
#include "adc/app_adc.h"
|
||||
#include "app_fatfs/fatfs_init.h"
|
||||
#include "net_lwip/ethernetif.h"
|
||||
#elif SYSTEM_TYPE == SYSTEM_TYPE_CCU621_M
|
||||
#include "netconf.h"
|
||||
#include "net_init.h"
|
||||
#include "eth_link.h"
|
||||
#include "sub_comm/sub_comm_task.h"
|
||||
#else
|
||||
|
||||
#endif
|
||||
|
||||
#if SD_CARD_EN
|
||||
#include "sdmmc/sdmmc_sd_drv.h"
|
||||
#include "sdmmc/app_sdmmc.h"
|
||||
#endif
|
||||
|
||||
#if(MY_SHELL_EN) //Shell 使能
|
||||
#include "letter_shell/shell_port.h"
|
||||
#endif
|
||||
|
||||
void v_fault_blink_code_loop(uint32_t blink_count)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
if (blink_count == 0U) {
|
||||
blink_count = 1U;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
for (i = 0U; i < blink_count; i++) {
|
||||
RUN_LED_ON();
|
||||
delay_ms(200U);
|
||||
RUN_LED_OFF();
|
||||
delay_ms(200U);
|
||||
}
|
||||
/* 码间隔:灭 500ms,便于快速识别状态 */
|
||||
RUN_LED_OFF();
|
||||
delay_ms(1000U);
|
||||
}
|
||||
}
|
||||
|
||||
void delay_ms(uint32_t ms)
|
||||
{
|
||||
uint32_t start;
|
||||
uint32_t ticks;
|
||||
|
||||
/* 基于 DWT CYCCNT 的精确延时:按 SystemCoreClock 计时 */
|
||||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
||||
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
|
||||
|
||||
start = DWT->CYCCNT;
|
||||
ticks = (SystemCoreClock / 1000U) * ms;
|
||||
|
||||
while ((DWT->CYCCNT - start) < ticks) {
|
||||
__NOP();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
### CMSIS-RTOS2 优先级与任务周期匹配表
|
||||
|
||||
| 优先级范围 | 适用任务类型 | 典型执行周期 | 说明 |
|
||||
| **osPriorityRealtime**<br>(48~55) | 硬件中断延迟处理、安全关键任务 | **<1ms** | 最高优先级,用于不能容忍任何延迟的任务(如电机紧急停止) |
|
||||
| **osPriorityHigh**<br>(40~47) | 实时控制、高频传感器处理 | **1~10ms** | 要求严格定时执行的任务(如PID控制、IMU数据融合) |
|
||||
| **osPriorityAboveNormal**<br>(32~39) | 通信协议栈、用户输入响应 | **10~50ms** | 需要快速响应但允许轻微抖动的任务(如UART命令解析、触摸屏响应) |
|
||||
| **osPriorityNormal**<br>(24~31) | 主要业务逻辑、中等频率任务 | **50~200ms** | 常规任务(如状态机更新、中等频率数据采集) |
|
||||
| **osPriorityBelowNormal**<br>(16~23) | 后台处理、低优先级服务 | **200ms~1s** | 允许延迟的任务(如日志写入、非实时数据分析) |
|
||||
| **osPriorityLow**<br>(8~15) | 维护性任务 | **1s~10s** | 对时间不敏感的任务(如LED心跳灯、内存碎片整理) |
|
||||
| **osPriorityIdle**<br>(1) | 空闲任务 | **无固定周期** | 仅当系统空闲时运行(如低功耗模式准备) |
|
||||
|
||||
#### 配置原则
|
||||
1. **周期越短 → 优先级越高**
|
||||
- 例:100us级电机控制 → `osPriorityRealtime7` (55)
|
||||
|
||||
2. **关键性补偿**
|
||||
- 重要但低频的任务(如看门狗)可提高1-2级优先级
|
||||
|
||||
3. **避免优先级反转**
|
||||
- 共享资源的任务间优先级差建议≤8级
|
||||
|
||||
*/
|
||||
const MY_TASK_DATA my_task_data[MY_TASK_NUM] =
|
||||
{
|
||||
/* 格式:{名称, 优先级, 栈大小(字节), 执行周期(ms), 任务入口, 任务参数} */
|
||||
/* FreeRTOS 优先级规则(重要):
|
||||
* - 数值越大,优先级越高;0 为最低优先级(通常是 IDLE)。
|
||||
* - 当前工程 configMAX_PRIORITIES=32,可用范围 0~31。
|
||||
* - 现场要求任务优先级不重复,以下按周期和关键性分配唯一优先级。 */
|
||||
{"EthIf", (UBaseType_t)(tskIDLE_PRIORITY + 30U), TASK_SIZE_SIZE_2048, TASK_SLEEP_MS_1, NULL, NULL},
|
||||
{"TCP/IP", (UBaseType_t)(tskIDLE_PRIORITY + 29U), TASK_SIZE_SIZE_8k, TASK_SLEEP_MS_1, NULL, NULL},
|
||||
{"BmsComm", (UBaseType_t)(tskIDLE_PRIORITY + 27U), TASK_SIZE_SIZE_4k, TASK_SLEEP_MS_5, v_bms_task, NULL},
|
||||
{"DataColl",(UBaseType_t)(tskIDLE_PRIORITY + 26U), TASK_SIZE_SIZE_2048, TASK_SLEEP_MS_10, v_collect_task, NULL},
|
||||
{"FlowCtrl",(UBaseType_t)(tskIDLE_PRIORITY + 25U), TASK_SIZE_SIZE_4k, TASK_SLEEP_MS_20, v_flowctrl_task, NULL},
|
||||
{"FaultCheck",(UBaseType_t)(tskIDLE_PRIORITY + 24U), TASK_SIZE_SIZE_6k, TASK_SLEEP_MS_50, v_fault_task, NULL},
|
||||
{"MduComm", (UBaseType_t)(tskIDLE_PRIORITY + 23U), TASK_SIZE_SIZE_2048, TASK_SLEEP_MS_50, v_Mdu_Comm_task, NULL},
|
||||
{"SubComm", (UBaseType_t)(tskIDLE_PRIORITY + 22U), TASK_SIZE_SIZE_2048, TASK_SLEEP_MS_50, v_sub_comm_task, NULL},
|
||||
{"PlatComm",(UBaseType_t)(tskIDLE_PRIORITY + 21U), TASK_SIZE_SIZE_8k*2, TASK_SLEEP_MS_100, v_plat_comm_task, NULL},
|
||||
#if (MY_SHELL_EN)
|
||||
{"MyShell", (UBaseType_t)(tskIDLE_PRIORITY + 20U), TASK_SIZE_SIZE_4k, TASK_SLEEP_MS_100, v_myshell_task, &shell},
|
||||
#endif
|
||||
{"UiComm", (UBaseType_t)(tskIDLE_PRIORITY + 19U), TASK_SIZE_SIZE_3k, TASK_SLEEP_MS_100, v_ui_task, NULL},
|
||||
/* WatchDog 放在 EthIf/TCP-IP 之后,保留较高优先级 */
|
||||
{"WatchDog",(UBaseType_t)(tskIDLE_PRIORITY + 28U), TASK_SIZE_SIZE_1024, TASK_SLEEP_MS_150, v_wdt_task, NULL},
|
||||
{"MeterColl",(UBaseType_t)(tskIDLE_PRIORITY + 18U), TASK_SIZE_SIZE_2048, TASK_SLEEP_MS_200, v_Meter_Coll_task, NULL},
|
||||
{"Meterfee",(UBaseType_t)(tskIDLE_PRIORITY + 17U), TASK_SIZE_SIZE_3k, TASK_SLEEP_MS_200, v_meterfee_task, NULL},
|
||||
{"MyLog", (UBaseType_t)(tskIDLE_PRIORITY + 16U), TASK_SIZE_SIZE_8k*2, TASK_SLEEP_MS_200, v_mylog_task, NULL},
|
||||
#if TCP_DEBUG_EN
|
||||
{"TcpSer", (UBaseType_t)(tskIDLE_PRIORITY + 15U), TASK_SIZE_SIZE_8k*2, TASK_SLEEP_MS_200, v_tcp_ser_task, NULL},
|
||||
#endif
|
||||
{"EthLink", (UBaseType_t)(tskIDLE_PRIORITY + 1U), TASK_SIZE_SIZE_1024, TASK_SLEEP_MS_1000, ethernet_link_thread, NETCONF_ETH_NETIF}
|
||||
};
|
||||
|
||||
void app_os_init(void)
|
||||
{
|
||||
BaseType_t create_ret;
|
||||
|
||||
v_public_cfg_data_init(); //参数初始化
|
||||
|
||||
|
||||
|
||||
#if (MY_SHELL_EN)
|
||||
userShellInit();
|
||||
#endif
|
||||
|
||||
#if SYSTEM_TYPE == SYSTEM_TYPE_CCU601E_D
|
||||
v_adc_data_init();
|
||||
|
||||
extern void Netif_Config_init(void);
|
||||
Netif_Config_init(); //网络及lwip 初始化 内部创建3个线程 分别是EthIf TCP/IP EthLink
|
||||
|
||||
CANSPI_Initialize(); //SPI CAN 配置
|
||||
#elif SYSTEM_TYPE == SYSTEM_TYPE_CCU621_M
|
||||
create_ret = net_init_task_create();
|
||||
if (create_ret != pdPASS) {
|
||||
MYLOG_MSG(0xFFU, "NetInit create failed, ret=%ld", (long)create_ret);
|
||||
} else {
|
||||
MYLOG_MSG(0xFFU, "NetInit create ok");
|
||||
}
|
||||
#else
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
for (uint32_t i = 0U; i < (uint32_t)MY_TASK_NUM; ++i) {
|
||||
if (my_task_data[i].task_entry == NULL) {
|
||||
continue;
|
||||
}
|
||||
create_ret = xTaskCreate(my_task_data[i].task_entry,
|
||||
my_task_data[i].task_name,
|
||||
(uint16_t)(my_task_data[i].task_size / sizeof(StackType_t)),
|
||||
my_task_data[i].task_arg,
|
||||
my_task_data[i].task_prio,
|
||||
NULL);
|
||||
if (create_ret != pdPASS) {
|
||||
MYLOG_MSG(0xFFU, "Task[%s] create FAILED! ret=%ld", my_task_data[i].task_name, (long)create_ret);
|
||||
} else {
|
||||
MYLOG_MSG(0xFFU, "Task[%s] create ok", my_task_data[i].task_name);
|
||||
}
|
||||
}
|
||||
#if SD_CARD_EN
|
||||
sdmmc_sd_drv_init();
|
||||
app_sdmmc_init();
|
||||
#endif
|
||||
#if SD_CARD_EN
|
||||
fatfs_init();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
#ifndef APP_INIT_H
|
||||
#define APP_INIT_H
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "publicdata/public_define.h"
|
||||
|
||||
//任务最小堆栈空间大小 --注意单位是字节!!!!
|
||||
#define TASK_SIZE_SIZE_512 (configMINIMAL_STACK_SIZE*4) //512字节
|
||||
#define TASK_SIZE_SIZE_1024 (configMINIMAL_STACK_SIZE*8) //1024字节=1k
|
||||
#define TASK_SIZE_SIZE_2048 (TASK_SIZE_SIZE_1024*2) //2048字节=2k
|
||||
#define TASK_SIZE_SIZE_3k (TASK_SIZE_SIZE_1024*3) //3k
|
||||
#define TASK_SIZE_SIZE_4k (TASK_SIZE_SIZE_1024*4) //4k
|
||||
#define TASK_SIZE_SIZE_5k (TASK_SIZE_SIZE_1024*5) //5k
|
||||
#define TASK_SIZE_SIZE_6k (TASK_SIZE_SIZE_1024*6) //6k
|
||||
#define TASK_SIZE_SIZE_7k (TASK_SIZE_SIZE_1024*7) //7k
|
||||
#define TASK_SIZE_SIZE_8k (TASK_SIZE_SIZE_1024*8) //8k
|
||||
//任务延时周期
|
||||
#define TASK_SLEEP_MS_1000 (1000U)
|
||||
#define TASK_SLEEP_MS_500 (500U)
|
||||
#define TASK_SLEEP_MS_300 (300U)
|
||||
#define TASK_SLEEP_MS_200 (200U)
|
||||
#define TASK_SLEEP_MS_150 (150U)
|
||||
#define TASK_SLEEP_MS_100 (100U)
|
||||
#define TASK_SLEEP_MS_50 (50U)
|
||||
#define TASK_SLEEP_MS_30 (30U)
|
||||
#define TASK_SLEEP_MS_20 (20U)
|
||||
#define TASK_SLEEP_MS_10 (10U)
|
||||
#define TASK_SLEEP_MS_5 (5U)
|
||||
#define TASK_SLEEP_MS_1 (1U)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char task_name[16];
|
||||
UBaseType_t task_prio;
|
||||
uint16_t task_size;
|
||||
uint16_t task_timer;
|
||||
TaskFunction_t task_entry;
|
||||
void *task_arg;
|
||||
} MY_TASK_DATA;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TASK_ID_EthIf = 0,
|
||||
TASK_ID_TCPIP,
|
||||
TASK_ID_BmsComm,
|
||||
TASK_ID_DataColl,
|
||||
TASK_ID_FlowCtrl,
|
||||
TASK_ID_FaultCheck,
|
||||
TASK_ID_MduComm,
|
||||
TASK_ID_SubComm,
|
||||
TASK_ID_PlatComm,
|
||||
#if (MY_SHELL_EN)
|
||||
TASK_ID_MyShell,
|
||||
#endif
|
||||
TASK_ID_UI,
|
||||
TASK_ID_WATCHDOG,
|
||||
TASK_ID_MeterColl,
|
||||
TASK_ID_Meterfee,
|
||||
TASK_ID_MyLog,
|
||||
#if (TCP_DEBUG_EN)
|
||||
TASK_ID_TcpSer,
|
||||
#endif
|
||||
|
||||
TASK_ID_EthLink,
|
||||
MY_TASK_NUM
|
||||
} TASK_ID;
|
||||
|
||||
extern const MY_TASK_DATA my_task_data[MY_TASK_NUM];
|
||||
|
||||
/* lwIP TCP/IP 线程:任务表与 lwipopts.h 中 TCPIP_THREAD_* 须一致(lwipopts 不可再 include 本头文件) */
|
||||
#define MY_TCPIP_NAME (my_task_data[TASK_ID_TCPIP].task_name)
|
||||
#define MY_TCPIP_PRIO (my_task_data[TASK_ID_TCPIP].task_prio)
|
||||
#define MY_TCPIP_SIZE (my_task_data[TASK_ID_TCPIP].task_size)
|
||||
|
||||
/* 兼容参考工程的任务访问宏 */
|
||||
#ifndef mSleep
|
||||
#define mSleep(x) (vTaskDelay(pdMS_TO_TICKS((x))))
|
||||
#endif
|
||||
|
||||
#define MY_TASK_NEW(task_id, func, para) \
|
||||
xTaskCreate((func), \
|
||||
my_task_data[(task_id)].task_name, \
|
||||
(uint16_t)(my_task_data[(task_id)].task_size / sizeof(StackType_t)), \
|
||||
(para), \
|
||||
my_task_data[(task_id)].task_prio, \
|
||||
NULL)
|
||||
|
||||
#define MY_SLEEP_TIME(task_id) mSleep(my_task_data[(task_id)].task_timer)
|
||||
#define MY_GET_SLEEP_TIME(task_id) (my_task_data[(task_id)].task_timer)
|
||||
#define MY_GET_TASK_NAME(task_id) (my_task_data[(task_id)].task_name)
|
||||
|
||||
void app_os_init(void);
|
||||
void delay_ms(uint32_t ms);
|
||||
void v_fault_blink_code_loop(uint32_t blink_count);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,129 @@
|
||||
# app_init 模块说明(app_init.c / app_init.h)
|
||||
|
||||
> 本文档描述 `CCU621_M` 工程中 `app_init.c` 与 `app_init.h` 的职责、接口与使用约束。
|
||||
|
||||
[返回主说明](./../../README.md)
|
||||
|
||||
## 快速跳转
|
||||
|
||||
- [1. 模块职责](#1-模块职责)
|
||||
- [2. 涉及文件](#2-涉及文件)
|
||||
- [3. 对外接口](#3-对外接口)
|
||||
- [4. app_os_init 初始化流程](#4-app_os_init-初始化流程)
|
||||
- [5. 任务表说明(当前版本)](#5-任务表说明当前版本)
|
||||
- [6. 依赖关系](#6-依赖关系)
|
||||
- [7. 维护注意事项](#7-维护注意事项)
|
||||
- [返回主说明 README](./../../README.md)
|
||||
|
||||
---
|
||||
|
||||
## 1. 模块职责
|
||||
|
||||
`app_init` 是应用层任务初始化总入口,负责:
|
||||
|
||||
- 维护统一任务表 `my_task_data[]`(名称/优先级/栈/周期/入口函数/参数);
|
||||
- 在 `app_os_init()` 中统一创建任务(`xTaskCreate`);
|
||||
- 维护任务ID枚举 `TASK_ID` 与任务表下标一一对应;
|
||||
- 提供任务周期、任务名称等统一访问宏;
|
||||
- 为 lwIP 提供 `MY_TCPIP_NAME/MY_TCPIP_PRIO/MY_TCPIP_SIZE` 参数来源。
|
||||
|
||||
> 说明:当前工程是“集中创建任务”模式,不同于 `CCU601E_D` 的“各模块内部 `*_init()` 分散创建”模式。
|
||||
|
||||
---
|
||||
|
||||
## 2. 涉及文件
|
||||
|
||||
| 文件 | 说明 |
|
||||
|---|---|
|
||||
| `app/app_init/app_init.c` | 任务表定义 + `app_os_init()` 创建逻辑 |
|
||||
| `app/app_init/app_init.h` | 栈/周期宏、`TASK_ID`、任务结构体、访问宏 |
|
||||
| `app/app_init/task_lock.c/h` | 任务锁统一接口(每任务一个锁句柄) |
|
||||
|
||||
---
|
||||
|
||||
## 3. 对外接口
|
||||
|
||||
### 3.1 函数
|
||||
|
||||
| 符号 | 说明 |
|
||||
|---|---|
|
||||
| `void app_os_init(void)` | 应用任务初始化总入口(由 `main.c` 调用) |
|
||||
|
||||
### 3.2 全局数据
|
||||
|
||||
| 符号 | 说明 |
|
||||
|---|---|
|
||||
| `const MY_TASK_DATA my_task_data[MY_TASK_NUM]` | 全部任务配置表 |
|
||||
|
||||
### 3.3 关键类型与宏
|
||||
|
||||
- `MY_TASK_DATA`:任务名称、优先级、栈(字节)、周期(ms)、入口函数、入口参数;
|
||||
- `TASK_ID`:任务ID,**必须与 `my_task_data[]` 顺序一致**;
|
||||
- `MY_TASK_NUM`:任务数量(由 `TASK_ID` 枚举尾项决定);
|
||||
- `mSleep(x)`:`vTaskDelay(pdMS_TO_TICKS(x))` 封装;
|
||||
- `MY_GET_SLEEP_TIME(task_id)`:取任务周期;
|
||||
- `MY_GET_TASK_NAME(task_id)`:取任务名称;
|
||||
- `MY_TCPIP_NAME/MY_TCPIP_PRIO/MY_TCPIP_SIZE`:由 `my_task_data[TASK_ID_TCPIP]` 映射得出,供 lwIP 配置使用。
|
||||
|
||||
---
|
||||
|
||||
## 4. `app_os_init()` 初始化流程
|
||||
|
||||
当前流程(以 `app_init.c` 为准):
|
||||
|
||||
1. 若 `MY_SHELL_EN=1`:执行 `userShellInit()`;
|
||||
2. 遍历 `my_task_data[]`;
|
||||
3. 对 `task_entry != NULL` 的任务执行 `xTaskCreate(...)`;
|
||||
4. 忽略 `task_entry == NULL` 的条目(如 `EthIf`、`TCP/IP` 由 lwIP 内部创建)。
|
||||
|
||||
---
|
||||
|
||||
## 5. 任务表说明(当前版本)
|
||||
|
||||
`my_task_data[]` 当前主要任务:
|
||||
|
||||
- `EthIf`(占位,lwIP线程)
|
||||
- `TCP/IP`(占位,lwIP线程)
|
||||
- `DataColl`
|
||||
- `FaultCheck`
|
||||
- `MduComm`
|
||||
- `MyShell`(条件编译)
|
||||
- `UiComm`
|
||||
- `WatchDog`
|
||||
- `MeterColl`
|
||||
- `MyLog`
|
||||
- `EthLink`
|
||||
|
||||
> `EthIf`、`TCP/IP` 仅用于参数对齐与状态展示,不由 `app_os_init` 直接创建。
|
||||
|
||||
---
|
||||
|
||||
## 6. 依赖关系
|
||||
|
||||
- 被 `main.c` 调用:`app_os_init()`
|
||||
- 依赖模块:
|
||||
- `mylog/collect_ctrl/fault_cheak/mdu_comm/ui/meter_calculate/wdt_task`
|
||||
- `BSP/net_lwip`(`eth_link_thread`)
|
||||
- `BSP/letter_shell`(条件编译)
|
||||
|
||||
---
|
||||
|
||||
## 7. 维护注意事项
|
||||
|
||||
1. 新增任务时必须同步修改:
|
||||
- `TASK_ID` 枚举;
|
||||
- `my_task_data[]` 表项;
|
||||
- 相关任务源文件中的任务ID宏(若使用模板化风格)。
|
||||
2. `my_task_data[]` 与 `TASK_ID` 顺序不一致会导致:
|
||||
- 周期读取错误;
|
||||
- 日志任务名错误;
|
||||
- 看门狗计数映射异常。
|
||||
3. 若调整 `TCP/IP` 参数,建议只改任务表对应项,不在其他位置重复写常量。
|
||||
4. `MY_SHELL_EN` 会影响任务数量与任务ID布局(`TASK_ID_MyShell` 条件编译)。
|
||||
|
||||
---
|
||||
|
||||
## 关联文档
|
||||
|
||||
- 主索引:[`CCU621_M/README.md`](./../../README.md)
|
||||
- 本文位置:`app/app_init/app_init模块说明.md`
|
||||
@@ -0,0 +1,905 @@
|
||||
#include "app_init/app_test.h"
|
||||
#include "app_init/app_init.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "portable.h"
|
||||
|
||||
#include "flash_external_data.h"
|
||||
#include "fm24cl16.h"
|
||||
#include "app_rtc/app_rtc.h"
|
||||
#include "usart.h"
|
||||
#include "can.h"
|
||||
#include "publicdata/publicdata.h"
|
||||
#include "mylog/mylog.h"
|
||||
#include "collect_ctrl/collect_task.h"
|
||||
#include "sys_drv_init.h"
|
||||
|
||||
#define APP_TEST_LOG(fmt, ...) MYLOG_MSG(TASK_ID_MyLog, (fmt), ##__VA_ARGS__)
|
||||
|
||||
#ifndef APP_TEST_ENABLE
|
||||
#define APP_TEST_ENABLE (0U)
|
||||
#endif
|
||||
|
||||
#define APP_TEST_FLASH_ADDR (0x00010000U)
|
||||
#define APP_TEST_FLASH_RW_SIZE (1024U)
|
||||
#define APP_TEST_FLASH_PERIOD_S (10U)
|
||||
#define APP_TEST_MIN_TEST_MS (1U)
|
||||
#define APP_TEST_ALIGN (32U)
|
||||
#define APP_TEST_GUARD_SIZE (32U)
|
||||
#define APP_TEST_FLASH_TOTAL_32M (0x02000000U)
|
||||
#define APP_TEST_FLASH_STEP_1M (0x00100000U)
|
||||
#define APP_TEST_ENABLE_FLASH_SPEED (0U)
|
||||
#define APP_TEST_EEPROM_ADDR (0x0600U)
|
||||
#define APP_TEST_EEPROM_SIZE (32U)
|
||||
|
||||
#define APP_TEST_EEPROM_MULTI_SIZE (64U)
|
||||
#define APP_TEST_EEPROM_SPEED_SIZE (64U)
|
||||
#define APP_TEST_EEPROM_SPEED_LOOP (10U)
|
||||
#define APP_TEST_EEPROM_SPEED_RETRY (3U)
|
||||
/* Use dedicated test window, avoid business hot partitions (e.g. 0x0100/0x0400). */
|
||||
#define APP_TEST_EEPROM_TEST_ADDR_BASE (0x0600U)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
APP_TEST_STEP_RTC = 0,
|
||||
APP_TEST_STEP_EEPROM_BASIC,
|
||||
APP_TEST_STEP_EEPROM_MULTI,
|
||||
APP_TEST_STEP_EEPROM_SPEED,
|
||||
APP_TEST_STEP_CAN,
|
||||
APP_TEST_STEP_UART,
|
||||
#if (APP_TEST_ENABLE_FLASH_SPEED)
|
||||
APP_TEST_STEP_FLASH_SPEED,
|
||||
#endif
|
||||
APP_TEST_STEP_FLASH_STRIDE,
|
||||
APP_TEST_STEP_DONE
|
||||
} APP_TEST_STEP_T;
|
||||
|
||||
#if (APP_TEST_ENABLE)
|
||||
|
||||
/**
|
||||
* @brief 将指针向上对齐到指定字节边界。
|
||||
* @param p 原始指针。
|
||||
* @param align 对齐值(2 的幂)。
|
||||
* @return 对齐后的指针。
|
||||
*/
|
||||
static uint8_t *align_up_u8(uint8_t *p, uint32_t align)
|
||||
{
|
||||
uintptr_t v = (uintptr_t)p;
|
||||
v = (v + (align - 1U)) & ~(uintptr_t)(align - 1U);
|
||||
return (uint8_t *)v;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 为 Flash DMA 测试申请对齐缓冲。
|
||||
* @param tx_raw 输出:TX 原始指针(用于释放)。
|
||||
* @param rx_raw 输出:RX 原始指针(用于释放)。
|
||||
* @param tx_buf 输出:对齐后的 TX 指针(用于读写)。
|
||||
* @param rx_buf 输出:对齐后的 RX 指针(用于读写)。
|
||||
* @return 1 成功,0 失败。
|
||||
*/
|
||||
static uint8_t app_test_alloc_aligned_buffers(uint8_t **tx_raw, uint8_t **rx_raw, uint8_t **tx_buf, uint8_t **rx_buf)
|
||||
{
|
||||
uint32_t alloc_size = APP_TEST_FLASH_RW_SIZE + APP_TEST_ALIGN + APP_TEST_GUARD_SIZE;
|
||||
|
||||
*tx_raw = (uint8_t *)pvPortMalloc(alloc_size);
|
||||
*rx_raw = (uint8_t *)pvPortMalloc(alloc_size);
|
||||
if ((*tx_raw == NULL) || (*rx_raw == NULL)) {
|
||||
if (*tx_raw != NULL) {
|
||||
vPortFree(*tx_raw);
|
||||
}
|
||||
if (*rx_raw != NULL) {
|
||||
vPortFree(*rx_raw);
|
||||
}
|
||||
*tx_raw = NULL;
|
||||
*rx_raw = NULL;
|
||||
*tx_buf = NULL;
|
||||
*rx_buf = NULL;
|
||||
return 0U;
|
||||
}
|
||||
|
||||
*tx_buf = align_up_u8(*tx_raw, APP_TEST_ALIGN);
|
||||
*rx_buf = align_up_u8(*rx_raw, APP_TEST_ALIGN);
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 释放由 app_test_alloc_aligned_buffers 申请的原始缓冲。
|
||||
* @param tx_raw TX 原始指针。
|
||||
* @param rx_raw RX 原始指针。
|
||||
*/
|
||||
static void app_test_free_aligned_buffers(uint8_t *tx_raw, uint8_t *rx_raw)
|
||||
{
|
||||
if (tx_raw != NULL) {
|
||||
vPortFree(tx_raw);
|
||||
}
|
||||
if (rx_raw != NULL) {
|
||||
vPortFree(rx_raw);
|
||||
}
|
||||
}
|
||||
|
||||
#if (APP_TEST_ENABLE_FLASH_SPEED)
|
||||
/**
|
||||
* @brief 单次 Flash 擦写读回测速与校验。
|
||||
* @details
|
||||
* - 使用 1KB 数据块在固定地址做擦除/写入/读取;
|
||||
* - 打印 erase/write/read 耗时与吞吐;
|
||||
* - 读回校验失败会打印 seed 便于复现。
|
||||
*/
|
||||
static void v_app_test_flash_rw_speed_once(void)
|
||||
{
|
||||
uint32_t i;
|
||||
uint64_t t0;
|
||||
uint64_t t1;
|
||||
uint32_t seed;
|
||||
uint32_t erase_ms;
|
||||
uint32_t write_ms;
|
||||
uint32_t read_ms;
|
||||
uint32_t write_kbs;
|
||||
uint32_t read_kbs;
|
||||
uint8_t *tx_raw;
|
||||
uint8_t *rx_raw;
|
||||
uint8_t *tx_buf;
|
||||
uint8_t *rx_buf;
|
||||
|
||||
if (app_test_alloc_aligned_buffers(&tx_raw, &rx_raw, &tx_buf, &rx_buf) == 0U) {
|
||||
APP_TEST_LOG("[APP_TEST] exflash malloc fail, size=%u\r\n", (unsigned int)APP_TEST_FLASH_RW_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
seed = (uint32_t)u64_get_current_millis();
|
||||
for (i = 0U; i < APP_TEST_FLASH_RW_SIZE; i++) {
|
||||
tx_buf[i] = (uint8_t)((seed + i) & 0xFFU);
|
||||
}
|
||||
(void)memset(rx_buf, 0, APP_TEST_FLASH_RW_SIZE);
|
||||
|
||||
t0 = u64_get_current_millis();
|
||||
(void)s32_flash_dataflash_erase_sector(APP_TEST_FLASH_ADDR);
|
||||
t1 = u64_get_current_millis();
|
||||
erase_ms = (uint32_t)(t1 - t0);
|
||||
|
||||
t0 = u64_get_current_millis();
|
||||
(void)s32_flash_dataflash_write(APP_TEST_FLASH_ADDR, tx_buf, APP_TEST_FLASH_RW_SIZE);
|
||||
t1 = u64_get_current_millis();
|
||||
write_ms = (uint32_t)(t1 - t0);
|
||||
if (write_ms < APP_TEST_MIN_TEST_MS) {
|
||||
write_ms = APP_TEST_MIN_TEST_MS;
|
||||
}
|
||||
|
||||
t0 = u64_get_current_millis();
|
||||
(void)s32_flash_dataflash_read(APP_TEST_FLASH_ADDR, rx_buf, APP_TEST_FLASH_RW_SIZE);
|
||||
t1 = u64_get_current_millis();
|
||||
read_ms = (uint32_t)(t1 - t0);
|
||||
if (read_ms < APP_TEST_MIN_TEST_MS) {
|
||||
read_ms = APP_TEST_MIN_TEST_MS;
|
||||
}
|
||||
|
||||
if (memcmp(tx_buf, rx_buf, APP_TEST_FLASH_RW_SIZE) != 0) {
|
||||
APP_TEST_LOG("[APP_TEST] exflash rw verify fail, seed=%lu\r\n", (unsigned long)seed);
|
||||
app_test_free_aligned_buffers(tx_raw, rx_raw);
|
||||
return;
|
||||
}
|
||||
|
||||
write_kbs = (APP_TEST_FLASH_RW_SIZE * 1000U) / (write_ms * 1024U);
|
||||
read_kbs = (APP_TEST_FLASH_RW_SIZE * 1000U) / (read_ms * 1024U);
|
||||
|
||||
APP_TEST_LOG("[APP_TEST] exflash speed seed=%lu, erase=%lums, write=%lums(%luKB/s), read=%lums(%luKB/s)\r\n",
|
||||
(unsigned long)seed,
|
||||
(unsigned long)erase_ms,
|
||||
(unsigned long)write_ms,
|
||||
(unsigned long)write_kbs,
|
||||
(unsigned long)read_ms,
|
||||
(unsigned long)read_kbs);
|
||||
|
||||
app_test_free_aligned_buffers(tx_raw, rx_raw);
|
||||
}
|
||||
#endif
|
||||
|
||||
void v_app_test_rtc_rw_once(void)
|
||||
{
|
||||
Comm_Time backup_time;
|
||||
Comm_Time write_time;
|
||||
Comm_Time read_time;
|
||||
|
||||
GetCurrentTime(&backup_time);
|
||||
|
||||
write_time = backup_time;
|
||||
write_time.ucSec = (uint8_t)((write_time.ucSec + 1U) % 60U);
|
||||
if ((write_time.ucSec == 0U) && (write_time.ucMin < 59U)) {
|
||||
write_time.ucMin++;
|
||||
}
|
||||
|
||||
v_rtc_set_time(&write_time);
|
||||
GetCurrentTime(&read_time);
|
||||
|
||||
APP_TEST_LOG("[APP_TEST] rtc rw test, write=%04u-%02u-%02u %02u:%02u:%02u, read=%04u-%02u-%02u %02u:%02u:%02u\r\n",
|
||||
write_time.iYear, write_time.ucMonth, write_time.ucDay,
|
||||
write_time.ucHour, write_time.ucMin, write_time.ucSec,
|
||||
read_time.iYear, read_time.ucMonth, read_time.ucDay,
|
||||
read_time.ucHour, read_time.ucMin, read_time.ucSec);
|
||||
|
||||
v_rtc_set_time(&backup_time);
|
||||
}
|
||||
|
||||
#if defined(__CC_ARM)
|
||||
#pragma diag_suppress 177
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief EEPROM(FM24CL16) 单次读写校验测试。
|
||||
* @return 1 通过,0 失败。
|
||||
*/
|
||||
uint8_t u8_app_test_eeprom_rw_once(void)
|
||||
{
|
||||
uint8_t tx[APP_TEST_EEPROM_SIZE];
|
||||
uint8_t rx[APP_TEST_EEPROM_SIZE];
|
||||
uint32_t i;
|
||||
int32_t first_mismatch = -1;
|
||||
uint8_t probe_ret;
|
||||
uint32_t err_after_write;
|
||||
uint32_t err_after_read;
|
||||
uint8_t pr;
|
||||
|
||||
APP_TEST_LOG("[APP_TEST] eeprom rw test start, addr=0x%02X size=%u\r\n",
|
||||
(unsigned int)APP_TEST_EEPROM_ADDR,
|
||||
(unsigned int)APP_TEST_EEPROM_SIZE);
|
||||
|
||||
for (i = 0U; i < APP_TEST_EEPROM_SIZE; i++) {
|
||||
tx[i] = (uint8_t)(0xA0U + i);
|
||||
}
|
||||
(void)memset(rx, 0, sizeof(rx));
|
||||
|
||||
probe_ret = eeprom_probe((uint16_t)APP_TEST_EEPROM_ADDR);
|
||||
APP_TEST_LOG("[APP_TEST] eeprom probe ret=%u last_err=%lu\r\n",
|
||||
(unsigned int)probe_ret,
|
||||
(unsigned long)eeprom_get_last_error());
|
||||
|
||||
/* quick probe different blocks to verify dev-addr mapping */
|
||||
pr = eeprom_probe(0x0000U);
|
||||
APP_TEST_LOG("[APP_TEST] eeprom probe @0x0000 ret=%u err=%lu\r\n",
|
||||
(unsigned int)pr, (unsigned long)eeprom_get_last_error());
|
||||
pr = eeprom_probe(0x0100U);
|
||||
APP_TEST_LOG("[APP_TEST] eeprom probe @0x0100 ret=%u err=%lu\r\n",
|
||||
(unsigned int)pr, (unsigned long)eeprom_get_last_error());
|
||||
pr = eeprom_probe(0x0200U);
|
||||
APP_TEST_LOG("[APP_TEST] eeprom probe @0x0200 ret=%u err=%lu\r\n",
|
||||
(unsigned int)pr, (unsigned long)eeprom_get_last_error());
|
||||
pr = eeprom_probe(0x0700U);
|
||||
APP_TEST_LOG("[APP_TEST] eeprom probe @0x0700 ret=%u err=%lu\r\n",
|
||||
(unsigned int)pr, (unsigned long)eeprom_get_last_error());
|
||||
|
||||
eeprom_buffer_write(tx, (uint16_t)APP_TEST_EEPROM_ADDR, (uint16_t)APP_TEST_EEPROM_SIZE);
|
||||
err_after_write = eeprom_get_last_error();
|
||||
eeprom_buffer_read(rx, (uint16_t)APP_TEST_EEPROM_ADDR, (uint16_t)APP_TEST_EEPROM_SIZE);
|
||||
err_after_read = eeprom_get_last_error();
|
||||
|
||||
if (memcmp(tx, rx, APP_TEST_EEPROM_SIZE) != 0) {
|
||||
for (i = 0U; i < APP_TEST_EEPROM_SIZE; i++) {
|
||||
if (tx[i] != rx[i]) {
|
||||
first_mismatch = (int32_t)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
APP_TEST_LOG("[APP_TEST] eeprom rw verify fail, addr=0x%02X size=%u\r\n",
|
||||
(unsigned int)APP_TEST_EEPROM_ADDR,
|
||||
(unsigned int)APP_TEST_EEPROM_SIZE);
|
||||
APP_TEST_LOG("[APP_TEST] eeprom err write=%lu read=%lu\r\n",
|
||||
(unsigned long)err_after_write,
|
||||
(unsigned long)err_after_read);
|
||||
APP_TEST_LOG("[APP_TEST] eeprom dump first16 @0x%02X:\r\n",
|
||||
(unsigned int)APP_TEST_EEPROM_ADDR);
|
||||
for (i = 0U; i < 16U; i++) {
|
||||
APP_TEST_LOG(" [%02u] wr=0x%02X rd=0x%02X\r\n",
|
||||
(unsigned int)i,
|
||||
(unsigned int)tx[i],
|
||||
(unsigned int)rx[i]);
|
||||
}
|
||||
if (first_mismatch >= 0) {
|
||||
APP_TEST_LOG("[APP_TEST] eeprom mismatch idx=%ld wr=0x%02X rd=0x%02X\r\n",
|
||||
(long)first_mismatch,
|
||||
(unsigned int)tx[(uint32_t)first_mismatch],
|
||||
(unsigned int)rx[(uint32_t)first_mismatch]);
|
||||
}
|
||||
return 0U;
|
||||
}
|
||||
|
||||
APP_TEST_LOG("[APP_TEST] eeprom rw verify pass, addr=0x%02X size=%u\r\n",
|
||||
(unsigned int)APP_TEST_EEPROM_ADDR,
|
||||
(unsigned int)APP_TEST_EEPROM_SIZE);
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief EEPROM 多地址点读写校验(覆盖关键分区起点与页边界)。
|
||||
* @return 1 通过,0 失败。
|
||||
*/
|
||||
uint8_t u8_app_test_eeprom_multi_addr_rw_once(void)
|
||||
{
|
||||
static const uint16_t rw_addrs[] = {
|
||||
0x0000U,
|
||||
0x0040U,
|
||||
0x0070U,
|
||||
0x0080U,
|
||||
0x00C0U,
|
||||
0x00E0U,
|
||||
0x00F0U,
|
||||
0x0580U,
|
||||
0x0600U,
|
||||
0x0680U,
|
||||
0x07C0U
|
||||
};
|
||||
static const uint16_t observe_addrs[] = {
|
||||
(uint16_t)EEPROM_ADDR_HISALARM_MNG,
|
||||
(uint16_t)EEPROM_ADDR_CARD_MNG,
|
||||
(uint16_t)EEPROM_ADDR_A_LOG_DATA,
|
||||
(uint16_t)EEPROM_ADDR_B_LOG_DATA
|
||||
};
|
||||
|
||||
uint8_t tx[APP_TEST_EEPROM_MULTI_SIZE];
|
||||
uint8_t rx[APP_TEST_EEPROM_MULTI_SIZE];
|
||||
uint8_t bk[APP_TEST_EEPROM_MULTI_SIZE];
|
||||
uint32_t i;
|
||||
uint32_t a;
|
||||
uint16_t addr;
|
||||
|
||||
for (i = 0U; i < APP_TEST_EEPROM_MULTI_SIZE; i++) {
|
||||
tx[i] = (uint8_t)(0x55U ^ (uint8_t)i);
|
||||
}
|
||||
|
||||
APP_TEST_LOG("[APP_TEST] eeprom multi-addr rw test start, size=%u, points=%u\r\n",
|
||||
(unsigned int)APP_TEST_EEPROM_MULTI_SIZE,
|
||||
(unsigned int)(sizeof(rw_addrs) / sizeof(rw_addrs[0])));
|
||||
|
||||
for (a = 0U; a < (uint32_t)(sizeof(rw_addrs) / sizeof(rw_addrs[0])); a++) {
|
||||
addr = rw_addrs[a];
|
||||
if (!EEPROM_ADDR_IN_RANGE(addr) || !EEPROM_ADDR_IN_RANGE((uint16_t)(addr + APP_TEST_EEPROM_MULTI_SIZE - 1U))) {
|
||||
APP_TEST_LOG("[APP_TEST] eeprom multi-addr skip out-of-range addr=0x%04X\r\n",
|
||||
(unsigned int)addr);
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)memset(rx, 0, sizeof(rx));
|
||||
(void)memset(bk, 0, sizeof(bk));
|
||||
|
||||
/* backup original content to avoid corrupting real partitions */
|
||||
eeprom_buffer_read(bk, addr, (uint16_t)APP_TEST_EEPROM_MULTI_SIZE);
|
||||
if (eeprom_get_last_error() != 0U) {
|
||||
APP_TEST_LOG("[APP_TEST] eeprom multi-addr backup read fail addr=0x%04X err=%lu\r\n",
|
||||
(unsigned int)addr, (unsigned long)eeprom_get_last_error());
|
||||
return 0U;
|
||||
}
|
||||
|
||||
eeprom_buffer_write(tx, addr, (uint16_t)APP_TEST_EEPROM_MULTI_SIZE);
|
||||
if (eeprom_get_last_error() != 0U) {
|
||||
APP_TEST_LOG("[APP_TEST] eeprom multi-addr write fail addr=0x%04X err=%lu\r\n",
|
||||
(unsigned int)addr, (unsigned long)eeprom_get_last_error());
|
||||
/* best-effort restore */
|
||||
eeprom_buffer_write(bk, addr, (uint16_t)APP_TEST_EEPROM_MULTI_SIZE);
|
||||
return 0U;
|
||||
}
|
||||
eeprom_buffer_read(rx, addr, (uint16_t)APP_TEST_EEPROM_MULTI_SIZE);
|
||||
if (eeprom_get_last_error() != 0U) {
|
||||
APP_TEST_LOG("[APP_TEST] eeprom multi-addr read fail addr=0x%04X err=%lu\r\n",
|
||||
(unsigned int)addr, (unsigned long)eeprom_get_last_error());
|
||||
/* best-effort restore */
|
||||
eeprom_buffer_write(bk, addr, (uint16_t)APP_TEST_EEPROM_MULTI_SIZE);
|
||||
return 0U;
|
||||
}
|
||||
|
||||
if (memcmp(tx, rx, APP_TEST_EEPROM_MULTI_SIZE) != 0) {
|
||||
for (i = 0U; i < APP_TEST_EEPROM_MULTI_SIZE; i++) {
|
||||
if (tx[i] != rx[i]) {
|
||||
APP_TEST_LOG("[APP_TEST] eeprom multi-addr mismatch addr=0x%04X idx=%lu wr=0x%02X rd=0x%02X\r\n",
|
||||
(unsigned int)addr,
|
||||
(unsigned long)i,
|
||||
(unsigned int)tx[i],
|
||||
(unsigned int)rx[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* restore original before returning */
|
||||
eeprom_buffer_write(bk, addr, (uint16_t)APP_TEST_EEPROM_MULTI_SIZE);
|
||||
return 0U;
|
||||
}
|
||||
APP_TEST_LOG("[APP_TEST] eeprom multi-addr pass addr=0x%04X\r\n", (unsigned int)addr);
|
||||
|
||||
/* restore original content */
|
||||
eeprom_buffer_write(bk, addr, (uint16_t)APP_TEST_EEPROM_MULTI_SIZE);
|
||||
if (eeprom_get_last_error() != 0U) {
|
||||
APP_TEST_LOG("[APP_TEST] eeprom multi-addr restore fail addr=0x%04X err=%lu\r\n",
|
||||
(unsigned int)addr, (unsigned long)eeprom_get_last_error());
|
||||
return 0U;
|
||||
}
|
||||
}
|
||||
|
||||
/* Observe-only check for business hot partitions (no write/restore). */
|
||||
for (a = 0U; a < (uint32_t)(sizeof(observe_addrs) / sizeof(observe_addrs[0])); a++) {
|
||||
addr = observe_addrs[a];
|
||||
if (!EEPROM_ADDR_IN_RANGE(addr) || !EEPROM_ADDR_IN_RANGE((uint16_t)(addr + APP_TEST_EEPROM_MULTI_SIZE - 1U))) {
|
||||
continue;
|
||||
}
|
||||
(void)memset(bk, 0, sizeof(bk));
|
||||
eeprom_buffer_read(bk, addr, (uint16_t)APP_TEST_EEPROM_MULTI_SIZE);
|
||||
if (eeprom_get_last_error() != 0U) {
|
||||
APP_TEST_LOG("[APP_TEST] eeprom multi-addr observe fail addr=0x%04X err=%lu\r\n",
|
||||
(unsigned int)addr, (unsigned long)eeprom_get_last_error());
|
||||
return 0U;
|
||||
}
|
||||
APP_TEST_LOG("[APP_TEST] eeprom multi-addr observe pass addr=0x%04X\r\n", (unsigned int)addr);
|
||||
}
|
||||
|
||||
APP_TEST_LOG("[APP_TEST] eeprom multi-addr rw test pass\r\n");
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief EEPROM 读写速度测试(循环读写固定大小并统计吞吐)。
|
||||
* @return 1 通过,0 失败。
|
||||
*/
|
||||
uint8_t u8_app_test_eeprom_speed_once(void)
|
||||
{
|
||||
uint8_t tx[APP_TEST_EEPROM_SPEED_SIZE];
|
||||
uint8_t rx[APP_TEST_EEPROM_SPEED_SIZE];
|
||||
uint8_t bk[APP_TEST_EEPROM_SPEED_SIZE];
|
||||
uint32_t i;
|
||||
uint32_t j;
|
||||
uint32_t r;
|
||||
int32_t first_mismatch;
|
||||
uint64_t t0;
|
||||
uint64_t t1;
|
||||
uint64_t write_ms;
|
||||
uint64_t read_ms;
|
||||
uint32_t write_kbs;
|
||||
uint32_t read_kbs;
|
||||
uint32_t loops = APP_TEST_EEPROM_SPEED_LOOP;
|
||||
uint16_t addr = (uint16_t)APP_TEST_EEPROM_TEST_ADDR_BASE;
|
||||
|
||||
if (!EEPROM_ADDR_IN_RANGE(addr) || !EEPROM_ADDR_IN_RANGE((uint16_t)(addr + APP_TEST_EEPROM_SPEED_SIZE - 1U))) {
|
||||
APP_TEST_LOG("[APP_TEST] eeprom speed addr out-of-range\r\n");
|
||||
return 0U;
|
||||
}
|
||||
|
||||
for (i = 0U; i < APP_TEST_EEPROM_SPEED_SIZE; i++) {
|
||||
tx[i] = (uint8_t)(i & 0xFFU);
|
||||
}
|
||||
|
||||
APP_TEST_LOG("[APP_TEST] eeprom speed test start, addr=0x%04X size=%u loop=%u\r\n",
|
||||
(unsigned int)addr,
|
||||
(unsigned int)APP_TEST_EEPROM_SPEED_SIZE,
|
||||
(unsigned int)loops);
|
||||
|
||||
/* backup original test window and restore at the end */
|
||||
(void)memset(bk, 0, sizeof(bk));
|
||||
eeprom_buffer_read(bk, addr, (uint16_t)APP_TEST_EEPROM_SPEED_SIZE);
|
||||
if (eeprom_get_last_error() != 0U) {
|
||||
APP_TEST_LOG("[APP_TEST] eeprom speed backup read fail err=%lu\r\n",
|
||||
(unsigned long)eeprom_get_last_error());
|
||||
return 0U;
|
||||
}
|
||||
|
||||
t0 = u64_get_current_millis();
|
||||
for (i = 0U; i < loops; i++) {
|
||||
for (r = 0U; r < APP_TEST_EEPROM_SPEED_RETRY; r++) {
|
||||
eeprom_buffer_write(tx, addr, (uint16_t)APP_TEST_EEPROM_SPEED_SIZE);
|
||||
if (eeprom_get_last_error() == 0U) {
|
||||
break;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(2U));
|
||||
}
|
||||
if (eeprom_get_last_error() != 0U) {
|
||||
APP_TEST_LOG("[APP_TEST] eeprom speed write fail loop=%lu retry=%lu err=%lu\r\n",
|
||||
(unsigned long)i,
|
||||
(unsigned long)r,
|
||||
(unsigned long)eeprom_get_last_error());
|
||||
eeprom_buffer_write(bk, addr, (uint16_t)APP_TEST_EEPROM_SPEED_SIZE);
|
||||
return 0U;
|
||||
}
|
||||
/* Allow write cycle settle time under stress loops. */
|
||||
vTaskDelay(pdMS_TO_TICKS(2U));
|
||||
}
|
||||
t1 = u64_get_current_millis();
|
||||
write_ms = (t1 >= t0) ? (t1 - t0) : 0U;
|
||||
if (write_ms < APP_TEST_MIN_TEST_MS) {
|
||||
write_ms = APP_TEST_MIN_TEST_MS;
|
||||
}
|
||||
|
||||
t0 = u64_get_current_millis();
|
||||
for (i = 0U; i < loops; i++) {
|
||||
for (r = 0U; r < APP_TEST_EEPROM_SPEED_RETRY; r++) {
|
||||
(void)memset(rx, 0, sizeof(rx));
|
||||
eeprom_buffer_read(rx, addr, (uint16_t)APP_TEST_EEPROM_SPEED_SIZE);
|
||||
if ((eeprom_get_last_error() == 0U) &&
|
||||
(memcmp(tx, rx, APP_TEST_EEPROM_SPEED_SIZE) == 0)) {
|
||||
break;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(2U));
|
||||
}
|
||||
|
||||
if ((eeprom_get_last_error() != 0U) || (memcmp(tx, rx, APP_TEST_EEPROM_SPEED_SIZE) != 0)) {
|
||||
first_mismatch = -1;
|
||||
for (j = 0U; j < APP_TEST_EEPROM_SPEED_SIZE; j++) {
|
||||
if (tx[j] != rx[j]) {
|
||||
first_mismatch = (int32_t)j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (first_mismatch >= 0) {
|
||||
APP_TEST_LOG("[APP_TEST] eeprom speed verify fail loop=%lu retry=%lu idx=%ld wr=0x%02X rd=0x%02X err=%lu\r\n",
|
||||
(unsigned long)i,
|
||||
(unsigned long)r,
|
||||
(long)first_mismatch,
|
||||
(unsigned int)tx[(uint32_t)first_mismatch],
|
||||
(unsigned int)rx[(uint32_t)first_mismatch],
|
||||
(unsigned long)eeprom_get_last_error());
|
||||
} else {
|
||||
APP_TEST_LOG("[APP_TEST] eeprom speed verify fail loop=%lu retry=%lu err=%lu\r\n",
|
||||
(unsigned long)i,
|
||||
(unsigned long)r,
|
||||
(unsigned long)eeprom_get_last_error());
|
||||
}
|
||||
eeprom_buffer_write(bk, addr, (uint16_t)APP_TEST_EEPROM_SPEED_SIZE);
|
||||
return 0U;
|
||||
}
|
||||
}
|
||||
t1 = u64_get_current_millis();
|
||||
read_ms = (t1 >= t0) ? (t1 - t0) : 0U;
|
||||
if (read_ms < APP_TEST_MIN_TEST_MS) {
|
||||
read_ms = APP_TEST_MIN_TEST_MS;
|
||||
}
|
||||
|
||||
write_kbs = (uint32_t)(((uint64_t)APP_TEST_EEPROM_SPEED_SIZE * (uint64_t)loops * 1000ULL) / (write_ms * 1024ULL));
|
||||
read_kbs = (uint32_t)(((uint64_t)APP_TEST_EEPROM_SPEED_SIZE * (uint64_t)loops * 1000ULL) / (read_ms * 1024ULL));
|
||||
|
||||
APP_TEST_LOG("[APP_TEST] eeprom speed result: write=%llums(%luKB/s) read=%llums(%luKB/s)\r\n",
|
||||
(unsigned long long)write_ms,
|
||||
(unsigned long)write_kbs,
|
||||
(unsigned long long)read_ms,
|
||||
(unsigned long)read_kbs);
|
||||
eeprom_buffer_write(bk, addr, (uint16_t)APP_TEST_EEPROM_SPEED_SIZE);
|
||||
return 1U;
|
||||
}
|
||||
|
||||
#define APP_TEST_CAN_TX_PERIOD_MS (1000ULL)
|
||||
#define APP_TEST_CAN_EXT_ID_BASE (0x18FEE000U)
|
||||
|
||||
/* ================= USART 单路测试(可改参数) =================
|
||||
* 简化版:每次执行 UART step 时
|
||||
* - 发送一次(固定数据,可改)
|
||||
* - 接收一次并打印(如有数据)
|
||||
* 每次仅测试一个串口。
|
||||
*/
|
||||
static E_USART_ID s_uart_test_port = E_USART_3; /* 可改:E_USART_0/2/3/4/5/6/7 */
|
||||
static uint8_t s_uart_test_tx_data[16] = { 0x55U, 0xAAU, 0x00U, 0x01U, 0x02U, 0x03U, 0x04U, 0x05U };
|
||||
static uint16_t s_uart_test_tx_len = 8U;
|
||||
|
||||
static void v_app_test_uart_poll(void)
|
||||
{
|
||||
uint8_t rx_buf[128];
|
||||
uint16_t rx_len;
|
||||
uint16_t send_len = s_uart_test_tx_len;
|
||||
|
||||
if (send_len > (uint16_t)sizeof(s_uart_test_tx_data)) {
|
||||
send_len = (uint16_t)sizeof(s_uart_test_tx_data);
|
||||
}
|
||||
|
||||
if (send_len > 0U) {
|
||||
(void)u16_usart_send(s_uart_test_port, s_uart_test_tx_data, send_len);
|
||||
APP_TEST_LOG("[APP_TEST] uart tx port=%u len=%u\r\n",
|
||||
(unsigned int)s_uart_test_port,
|
||||
(unsigned int)send_len);
|
||||
}
|
||||
|
||||
rx_len = u16_usart_recv(s_uart_test_port, rx_buf, (uint16_t)sizeof(rx_buf));
|
||||
if (rx_len > 0U) {
|
||||
char hex[3U * sizeof(rx_buf) + 4U];
|
||||
uint32_t pos = 0U;
|
||||
uint16_t i;
|
||||
|
||||
hex[0] = '\0';
|
||||
for (i = 0U; i < rx_len && pos + 3U < sizeof(hex); i++) {
|
||||
(void)snprintf(&hex[pos], sizeof(hex) - pos, "%02X ", (unsigned int)rx_buf[i]);
|
||||
pos = (uint32_t)strlen(hex);
|
||||
}
|
||||
APP_TEST_LOG("[APP_TEST] uart rx port=%u len=%u %s\r\n",
|
||||
(unsigned int)s_uart_test_port,
|
||||
(unsigned int)rx_len,
|
||||
hex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 读空三路 CAN 软件缓存并打印(扩展帧由驱动层标记)。
|
||||
*/
|
||||
static void v_app_test_can_rx_drain(void)
|
||||
{
|
||||
uint8_t port;
|
||||
CAN_DATA rx[CAN_RX_BUFFER_SIZE];
|
||||
uint8_t rx_cnt;
|
||||
uint8_t i;
|
||||
uint8_t k;
|
||||
|
||||
for (port = 0U; port < 3U; port++) {
|
||||
rx_cnt = u8_can_rx((E_CAN_ID)port, &rx[0]);
|
||||
for (k = 0U; k < rx_cnt; k++) {
|
||||
char hex[3U * 8U + 4U] = {0};
|
||||
uint32_t pos = 0U;
|
||||
|
||||
for (i = 0U; i < rx[k].Len && i < 8U && pos + 3U < sizeof(hex); i++) {
|
||||
(void)snprintf(&hex[pos], sizeof(hex) - pos, "%02X ", (unsigned int)rx[k].Data[i]);
|
||||
pos = (uint32_t)strlen(hex);
|
||||
}
|
||||
APP_TEST_LOG("[APP_TEST] can rx port=%u id=0x%08lX dlc=%u %s\r\n",
|
||||
(unsigned int)port, (unsigned long)rx[k].ID, (unsigned int)rx[k].Len, hex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 三路 CAN 各发一帧扩展数据帧(8 字节,前 4 字节为递增序号)。
|
||||
*/
|
||||
static void v_app_test_can_tx_all_ports(uint32_t seq)
|
||||
{
|
||||
uint8_t port;
|
||||
CAN_DATA tx;
|
||||
|
||||
for (port = 0U; port < 3U; port++) {
|
||||
(void)memset(&tx, 0, sizeof(tx));
|
||||
tx.ID = APP_TEST_CAN_EXT_ID_BASE + (uint32_t)port;
|
||||
tx.Len = 8U;
|
||||
tx.Data[0] = (uint8_t)(seq & 0xFFU);
|
||||
tx.Data[1] = (uint8_t)((seq >> 8) & 0xFFU);
|
||||
tx.Data[2] = (uint8_t)((seq >> 16) & 0xFFU);
|
||||
tx.Data[3] = (uint8_t)((seq >> 24) & 0xFFU);
|
||||
tx.Data[4] = port;
|
||||
tx.Data[5] = 0xC0U;
|
||||
tx.Data[6] = 0xAAU;
|
||||
tx.Data[7] = 0x55U;
|
||||
v_can_tx((E_CAN_ID)port, &tx);
|
||||
}
|
||||
APP_TEST_LOG("[APP_TEST] can tx 3ch ext seq=%lu base_id=0x%08lX\r\n",
|
||||
(unsigned long)seq, (unsigned long)APP_TEST_CAN_EXT_ID_BASE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CAN 周期任务:每 1s 三路各发一帧扩展帧;每次调用先收完并打印。
|
||||
* @note 挂在 v_app_test_periodic 入口,随 MyLog 任务节拍轮询(不受 10s 自检节流影响)。
|
||||
*/
|
||||
static void v_app_test_can_poll(void)
|
||||
{
|
||||
static uint64_t s_next_tx_ms = 0ULL;
|
||||
static uint32_t s_tx_seq = 0U;
|
||||
uint64_t now_ms;
|
||||
|
||||
v_app_test_can_rx_drain();
|
||||
|
||||
if (u8_can_is_initialized() == 0U) {
|
||||
v_can_interface_init();
|
||||
}
|
||||
|
||||
now_ms = u64_get_current_millis();
|
||||
if (s_next_tx_ms == 0ULL) {
|
||||
s_next_tx_ms = now_ms;
|
||||
}
|
||||
if (now_ms < s_next_tx_ms) {
|
||||
return;
|
||||
}
|
||||
|
||||
s_next_tx_ms = now_ms + APP_TEST_CAN_TX_PERIOD_MS;
|
||||
v_app_test_can_tx_all_ports(s_tx_seq);
|
||||
s_tx_seq++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 通过 u8_get_yxyc_data 读取整桩/枪实时采集结构并打印(与 collect_task 内数据源一致)。
|
||||
*/
|
||||
static void v_app_test_collect_yxyc_snapshot_print(void)
|
||||
{
|
||||
SYS_RT_DATA pile;
|
||||
GUN_RT_DATA gun;
|
||||
U8_T gun_cnt;
|
||||
U8_T i;
|
||||
|
||||
if (u8_get_yxyc_data(&pile, NULL, 0U) == 0U) {
|
||||
APP_TEST_LOG("[APP_TEST] coll get sys fail (lock/busy)\r\n");
|
||||
return;
|
||||
}
|
||||
APP_TEST_LOG("[APP_TEST] ****************************************************** start ******************************************************\r\n");
|
||||
APP_TEST_LOG("[APP_TEST] coll SYS yx_raw=0x%08lX\r\n",
|
||||
(unsigned long)pile.yx_sys_data.u32_yx_sys_data);
|
||||
APP_TEST_LOG("[APP_TEST] SYS_yx estp=%u door=%u water=%u smoke=%u busKM=%u spd=%u acKM=%u qf=%u\r\n",
|
||||
(unsigned int)pile.yx_sys_data.bit_yx_sys_data.yx_emergency,
|
||||
(unsigned int)pile.yx_sys_data.bit_yx_sys_data.yx_door,
|
||||
(unsigned int)pile.yx_sys_data.bit_yx_sys_data.yx_water,
|
||||
(unsigned int)pile.yx_sys_data.bit_yx_sys_data.yx_smoke,
|
||||
(unsigned int)pile.yx_sys_data.bit_yx_sys_data.yx_bus_KM,
|
||||
(unsigned int)pile.yx_sys_data.bit_yx_sys_data.yx_spd,
|
||||
(unsigned int)pile.yx_sys_data.bit_yx_sys_data.yx_KM,
|
||||
(unsigned int)pile.yx_sys_data.bit_yx_sys_data.yx_QF);
|
||||
APP_TEST_LOG("[APP_TEST] SYS_yc temp1_x1000=%ld temp2_x1000=%ld\r\n",
|
||||
(long)(pile.f32_yc_sys_temp1 * 1000.0f),
|
||||
(long)(pile.f32_yc_sys_temp2 * 1000.0f));
|
||||
|
||||
APP_TEST_LOG("[APP_TEST] hw_DOgpio(1=H 0=L) K1-K5 : %u %u %u %u %u\r\n",
|
||||
(unsigned int)DO1_READ(), (unsigned int)DO2_READ(), (unsigned int)DO3_READ(),
|
||||
(unsigned int)DO4_READ(), (unsigned int)DO5_READ());
|
||||
APP_TEST_LOG("[APP_TEST] hw_DOgpio(1=H 0=L) K6-K10: %u %u %u %u %u | ELOCK_A=%u ELOCK_B=%u\r\n",
|
||||
(unsigned int)DO6_READ(), (unsigned int)DO7_READ(), (unsigned int)DO8_READ(),
|
||||
(unsigned int)DO9_READ(), (unsigned int)DO10_READ(),
|
||||
(unsigned int)ELOCK_A_READ(), (unsigned int)ELOCK_B_READ());
|
||||
|
||||
gun_cnt = (U8_T)GUN_MAX_CNT;
|
||||
|
||||
for (i = 0U; i < gun_cnt; i++) {
|
||||
if (u8_get_yxyc_data(NULL, &gun, i) == 0U) {
|
||||
APP_TEST_LOG("[APP_TEST] coll get gun%u fail\r\n", (unsigned int)i);
|
||||
continue;
|
||||
}
|
||||
APP_TEST_LOG("[APP_TEST] coll GUN%u link=%u\r\n",
|
||||
(unsigned int)i,
|
||||
(unsigned int)gun.u8_gunlink_state);
|
||||
APP_TEST_LOG("[APP_TEST] GUN_yx raw=0x%08lX lock=%u dcP=%u dcN=%u rlf=%u fuse=%u apw=%u home=%u\r\n",
|
||||
(unsigned long)gun.yx_gun_data.u32_yx_gun_data,
|
||||
(unsigned int)gun.yx_gun_data.bit_yx_gun_data.yx_gun_lock,
|
||||
(unsigned int)gun.yx_gun_data.bit_yx_gun_data.yx_switch_pos,
|
||||
(unsigned int)gun.yx_gun_data.bit_yx_gun_data.yx_switch_neg,
|
||||
(unsigned int)gun.yx_gun_data.bit_yx_gun_data.yx_relief_swich,
|
||||
(unsigned int)gun.yx_gun_data.bit_yx_gun_data.yx_fuse,
|
||||
(unsigned int)gun.yx_gun_data.bit_yx_gun_data.yx_gun_power,
|
||||
(unsigned int)gun.yx_gun_data.bit_yx_gun_data.yx_gun_homing);
|
||||
APP_TEST_LOG("[APP_TEST] GUN_yc bus_mV V+=%ld V-=%ld I_mA=%ld\r\n",
|
||||
(long)(gun.f32_yc_gun_vol_pos * 1000.0f),
|
||||
(long)(gun.f32_yc_gun_vol_neg * 1000.0f),
|
||||
(long)(gun.f32_yc_gun_curr * 1000.0f));
|
||||
APP_TEST_LOG("[APP_TEST] GUN_yc bat_mV V+=%ld V-=%ld | gunTemp_x1000 Tpos=%ld Tneg=%ld\r\n",
|
||||
(long)(gun.f32_yc_bat_vol_pos * 1000.0f),
|
||||
(long)(gun.f32_yc_bat_vol_neg * 1000.0f),
|
||||
(long)(gun.f32_yc_gun_temp_pos * 1000.0f),
|
||||
(long)(gun.f32_yc_gun_temp_neg * 1000.0f));
|
||||
}
|
||||
APP_TEST_LOG("[APP_TEST] ****************************************************** end ******************************************************\r\n");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 对外:以 1MB 步长扫描 32MB 地址空间读写校验。
|
||||
* @details
|
||||
* - 每个步长点执行:扇区擦除 -> 写入 1KB 模式数据 -> 读回校验;
|
||||
* - 任一点失败立即返回并打印失败地址;
|
||||
* - 全部通过后打印总耗时。
|
||||
* @return 1 通过,0 失败。
|
||||
*/
|
||||
uint8_t u8_app_test_flash_32m_stride_rw(void)
|
||||
{
|
||||
uint32_t addr;
|
||||
uint32_t i;
|
||||
uint32_t seed;
|
||||
uint64_t t0;
|
||||
uint64_t t1;
|
||||
uint64_t elapsed_ms;
|
||||
uint8_t *tx_raw;
|
||||
uint8_t *rx_raw;
|
||||
uint8_t *tx_buf;
|
||||
uint8_t *rx_buf;
|
||||
|
||||
if (app_test_alloc_aligned_buffers(&tx_raw, &rx_raw, &tx_buf, &rx_buf) == 0U) {
|
||||
APP_TEST_LOG("[APP_TEST] 32M stride malloc fail\r\n");
|
||||
return 0U;
|
||||
}
|
||||
|
||||
APP_TEST_LOG("[APP_TEST] 32M stride test start, step=0x%08X, size=%u\r\n",
|
||||
(unsigned int)APP_TEST_FLASH_STEP_1M,
|
||||
(unsigned int)APP_TEST_FLASH_RW_SIZE);
|
||||
|
||||
t0 = u64_get_current_millis();
|
||||
for (addr = 0U; addr < APP_TEST_FLASH_TOTAL_32M; addr += APP_TEST_FLASH_STEP_1M) {
|
||||
seed = (uint32_t)(addr ^ 0x5A5A0000U);
|
||||
for (i = 0U; i < APP_TEST_FLASH_RW_SIZE; i++) {
|
||||
tx_buf[i] = (uint8_t)((seed + i) & 0xFFU);
|
||||
}
|
||||
(void)memset(rx_buf, 0, APP_TEST_FLASH_RW_SIZE);
|
||||
|
||||
(void)s32_flash_dataflash_erase_sector(addr);
|
||||
(void)s32_flash_dataflash_write(addr, tx_buf, APP_TEST_FLASH_RW_SIZE);
|
||||
(void)s32_flash_dataflash_read(addr, rx_buf, APP_TEST_FLASH_RW_SIZE);
|
||||
|
||||
if (memcmp(tx_buf, rx_buf, APP_TEST_FLASH_RW_SIZE) != 0) {
|
||||
APP_TEST_LOG("[APP_TEST] 32M stride verify fail, addr=0x%08lX, seed=0x%08lX\r\n",
|
||||
(unsigned long)addr,
|
||||
(unsigned long)seed);
|
||||
app_test_free_aligned_buffers(tx_raw, rx_raw);
|
||||
return 0U;
|
||||
}
|
||||
}
|
||||
t1 = u64_get_current_millis();
|
||||
elapsed_ms = t1 - t0;
|
||||
|
||||
APP_TEST_LOG("[APP_TEST] 32M stride test pass, range=0x00000000~0x01FFFFFF, elapsed=%llums\r\n", elapsed_ms);
|
||||
|
||||
app_test_free_aligned_buffers(tx_raw, rx_raw);
|
||||
return 1U;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 周期触发综合测试(RTC/EEPROM/Flash)。
|
||||
* @details 首次调用仅记录起始时间,不立即执行测试。
|
||||
*/
|
||||
void v_app_test_periodic(void)
|
||||
{
|
||||
static uint32_t s_last_test_sec = 0U;
|
||||
static uint8_t s_test_step = (uint8_t)APP_TEST_STEP_RTC;
|
||||
uint32_t now_sec;
|
||||
|
||||
if (s_last_test_sec == 0U) {
|
||||
s_last_test_sec = get_current_seconds();
|
||||
return;
|
||||
}
|
||||
|
||||
now_sec = get_current_seconds();
|
||||
/* 改为 1 秒节拍执行一次 step(按你的要求)。 */
|
||||
if (u32_safe_seconds_since(s_last_test_sec) < 1U) {
|
||||
return;
|
||||
}
|
||||
|
||||
// APP_TEST_LOG("[APP_TEST] app test periodic\r\n");
|
||||
/* 改用“数字递增 step”的方式,避免 bitmask 维护成本。 */
|
||||
switch ((APP_TEST_STEP_T)s_test_step) {
|
||||
case APP_TEST_STEP_RTC:
|
||||
// v_app_test_rtc_rw_once();
|
||||
test_rtc(); //测试RTC
|
||||
s_test_step++;
|
||||
break;
|
||||
case APP_TEST_STEP_EEPROM_BASIC:
|
||||
// (void)u8_app_test_eeprom_rw_once();
|
||||
s_test_step++;
|
||||
break;
|
||||
case APP_TEST_STEP_EEPROM_MULTI:
|
||||
// (void)u8_app_test_eeprom_multi_addr_rw_once();
|
||||
s_test_step++;
|
||||
break;
|
||||
case APP_TEST_STEP_EEPROM_SPEED:
|
||||
// (void)u8_app_test_eeprom_speed_once();
|
||||
s_test_step++;
|
||||
break;
|
||||
case APP_TEST_STEP_CAN:
|
||||
/* 每秒发送一次 + 周期接收打印(函数内部有 1s 节拍控制)。 */
|
||||
// v_app_test_can_poll();
|
||||
s_test_step++;
|
||||
break;
|
||||
case APP_TEST_STEP_UART:
|
||||
// v_app_test_uart_poll();
|
||||
v_app_test_collect_yxyc_snapshot_print();
|
||||
s_test_step++;
|
||||
break;
|
||||
#if (APP_TEST_ENABLE_FLASH_SPEED)
|
||||
case APP_TEST_STEP_FLASH_SPEED:
|
||||
// v_app_test_flash_rw_speed_once();
|
||||
s_test_step++;
|
||||
break;
|
||||
#endif
|
||||
case APP_TEST_STEP_FLASH_STRIDE:
|
||||
// if (u8_app_test_flash_32m_stride_rw() == 0U) {
|
||||
// APP_TEST_LOG("[APP_TEST] 32M stride test failed in periodic flow\r\n");
|
||||
// }
|
||||
s_test_step++;
|
||||
break;
|
||||
case APP_TEST_STEP_DONE:
|
||||
s_test_step = (uint8_t)APP_TEST_STEP_RTC;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
s_last_test_sec = now_sec;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void v_app_test_periodic(void)
|
||||
{
|
||||
/* test disabled by APP_TEST_ENABLE */
|
||||
}
|
||||
|
||||
#endif /* APP_TEST_ENABLE */
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef APP_TEST_H
|
||||
#define APP_TEST_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void v_app_test_periodic(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,102 @@
|
||||
#include "app_init/task_lock.h"
|
||||
|
||||
/**
|
||||
* @brief 每任务锁句柄数组(外部可见)。
|
||||
*
|
||||
* @details
|
||||
* - 下标与 `TASK_ID` 一一对应;
|
||||
* - 每个任务默认预留一个 mutex;
|
||||
* - 具体何时初始化由各任务自行调用 `u8_task_lock_ctrl(..., TASK_LOCK_OP_INIT)`。
|
||||
*/
|
||||
static SemaphoreHandle_t g_task_lock_handles[MY_TASK_NUM] = {0};
|
||||
|
||||
/**
|
||||
* @brief 自定义锁句柄控制接口。
|
||||
*
|
||||
* @details
|
||||
* 通过外部传入的 `SemaphoreHandle_t` 句柄指针执行统一锁操作:
|
||||
* - INIT:若句柄为空则创建 mutex;
|
||||
* - TAKE:阻塞获取 mutex;
|
||||
* - GIVE:释放 mutex;
|
||||
* - DELETE:删除 mutex 并清空句柄。
|
||||
*
|
||||
* @param p_handle 外部锁句柄地址。
|
||||
* @param op 锁操作动作(初始化、上锁、解锁、删除)。
|
||||
* @return uint8_t 1-成功,0-失败(指针非法/句柄为空/RTOS调用失败)。
|
||||
*/
|
||||
uint8_t u8_task_lock_handle_ctrl(SemaphoreHandle_t *p_handle, TASK_LOCK_OP_E op)
|
||||
{
|
||||
if (p_handle == NULL) {
|
||||
return 0U;
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case TASK_LOCK_OP_INIT:
|
||||
if (*p_handle == NULL) {
|
||||
*p_handle = xSemaphoreCreateMutex();
|
||||
}
|
||||
return (*p_handle != NULL) ? 1U : 0U;
|
||||
|
||||
case TASK_LOCK_OP_TAKE:
|
||||
if (*p_handle == NULL) {
|
||||
return 0U;
|
||||
}
|
||||
return (xSemaphoreTake(*p_handle, portMAX_DELAY) == pdPASS) ? 1U : 0U;
|
||||
|
||||
case TASK_LOCK_OP_GIVE:
|
||||
if (*p_handle == NULL) {
|
||||
return 0U;
|
||||
}
|
||||
return (xSemaphoreGive(*p_handle) == pdTRUE) ? 1U : 0U;
|
||||
|
||||
case TASK_LOCK_OP_DELETE:
|
||||
if (*p_handle != NULL) {
|
||||
vSemaphoreDelete(*p_handle);
|
||||
*p_handle = NULL;
|
||||
}
|
||||
return 1U;
|
||||
|
||||
default:
|
||||
return 0U;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 统一线程锁控制接口。
|
||||
*
|
||||
* @details
|
||||
* 根据任务ID选择对应互斥锁句柄,并执行指定动作:
|
||||
* - INIT:若未创建则创建 mutex;
|
||||
* - TAKE:阻塞获取 mutex;
|
||||
* - GIVE:释放 mutex;
|
||||
* - DELETE:删除 mutex 并清空句柄。
|
||||
*
|
||||
* @param task_id 任务ID(`TASK_ID` 枚举,作为锁数组下标)。
|
||||
* @param op 锁操作动作(初始化、上锁、解锁、删除)。
|
||||
* @return uint8_t 1-成功,0-失败(ID非法/句柄为空/RTOS调用失败)。
|
||||
*/
|
||||
uint8_t u8_task_lock_ctrl(TASK_ID task_id, TASK_LOCK_OP_E op)
|
||||
{
|
||||
uint8_t id = (uint8_t)task_id;
|
||||
|
||||
if (id >= (uint8_t)MY_TASK_NUM) {
|
||||
return 0U;
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case TASK_LOCK_OP_INIT:
|
||||
return u8_task_lock_handle_ctrl(&g_task_lock_handles[id], TASK_LOCK_OP_INIT);
|
||||
|
||||
case TASK_LOCK_OP_TAKE:
|
||||
return u8_task_lock_handle_ctrl(&g_task_lock_handles[id], TASK_LOCK_OP_TAKE);
|
||||
|
||||
case TASK_LOCK_OP_GIVE:
|
||||
return u8_task_lock_handle_ctrl(&g_task_lock_handles[id], TASK_LOCK_OP_GIVE);
|
||||
|
||||
case TASK_LOCK_OP_DELETE:
|
||||
return u8_task_lock_handle_ctrl(&g_task_lock_handles[id], TASK_LOCK_OP_DELETE);
|
||||
|
||||
default:
|
||||
return 0U;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef TASK_LOCK_H
|
||||
#define TASK_LOCK_H
|
||||
|
||||
#include "app_init/app_init.h"
|
||||
#include "semphr.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TASK_LOCK_OP_INIT = 0,
|
||||
TASK_LOCK_OP_TAKE,
|
||||
TASK_LOCK_OP_GIVE,
|
||||
TASK_LOCK_OP_DELETE
|
||||
} TASK_LOCK_OP_E;
|
||||
|
||||
uint8_t u8_task_lock_ctrl(TASK_ID task_id, TASK_LOCK_OP_E op);
|
||||
uint8_t u8_task_lock_handle_ctrl(SemaphoreHandle_t *p_handle, TASK_LOCK_OP_E op);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user