事件从 evlog_put*() 进一个 256 条的 RAM 环(临界区里两条指令,**不阻塞、 不碰 flash**),由最低优先级的 t_log 攒够 16 条或最老那条等满 1 s 时批量写进 新的 `evlog` 分区(17 扇区 × 4 KB = **4335 条**)。A10 的事件出口原样接上, 判据那一层一个字没动。 八条实现约定(详见需求文档 §10.7): · 落盘不用 NVS 也不用 SPIFFS,是一块裸 data 分区 —— NVS 的页式 GC 会把 「写一条事件」变成一次不可预测的搬移。HAL 因此多出第六样 hal_store; · 17 个扇区不是 16:每扇区要拿一个 16 B 的槽当扇区头,4 KB 只装 255 条, 16 扇区 = 4080,差 16 条不到 §10.7 要求的 4096; · 序号 = flash 里的位置(epoch × 255 + 槽号),不是自增计数器 —— 重启接着数 不用存计数器;代价是没落盘的事件还没有序号,A12 读之前要先 flush; · 入队走关中断的临界区,**不是第三把锁**:入队方是最高优先级的 t_safety, 停在一把 t_log 持着的锁上等于让最低优先级的任务决定巡检节拍; · 丢事件可以,悄悄丢不行 —— 缓冲满了盖最旧的,但补一条 LOG_EV_LOST 记着丢了几条; · 每条记录带 CRC-8(见下),写失败就放弃该扇区剩余部分,被放弃的那段在序号 空间里是个洞,读回时给一条空记录占位(跳过的话上位机游标会卡住); · 每次上电记一条 LOG_EV_BOOT:时间戳上电从 0 计,没有它两次上电的记录会穿插。 事件类型的数字是 flash 格式的一部分,只许往末尾加;safety_ev_t → log_ev_t 是显式 switch 不是加偏移。§10.7 里还没人产生的六类号已占住(A12/A15/A16 去填)。 27 个用例;23 条注错逐个跑过,21 条变红。第一版校验和用异或,漏掉的正是最常见 的那条:payload 全 0 的记录被掉电切在第 8 个字节上时,后 8 个字节留在 0xFF, 而 8 个 0xFF 的异或恰好是 0 —— 半条的校验和与整条一模一样,扫描把半条当成 一条真事件。换成 CRC-8 之后拦住。另外两个只在这里才踩得到的坑:「掉电重启」 不能用 sim_hal_reset()(那是换新板子,flash 一起擦,测试永远绿),为此加了 sim_hal_reboot();「读到洞就跳过」这个错被测试里 static 数组的零初始化掩盖过 一次,缓冲要先填成非零。 Co-Authored-By: Claude Opus 5 <[email protected]>
84 行
3.2 KiB
CMake
84 行
3.2 KiB
CMake
# PhoneRail 宿主机构建 —— 不依赖 ESP-IDF,用来跑单元测试(CTest)。
|
||
#
|
||
# bash host/test.sh 配置 + 编译 + ctest
|
||
#
|
||
# 与 IDF 目标共享的源码只有 ../main 里的与硬件无关部分。
|
||
# 新增一个既要上板又要被测的 .c,必须同时加进:
|
||
# ../main/CMakeLists.txt 的 SRCS 和 下面的 PHONERAIL_CORE_SRCS
|
||
# HAL 里新增一路实现则要同时加进:
|
||
# ../components/phonerail_hal/CMakeLists.txt 的 SRCS(esp 那份)
|
||
# 和下面的 PHONERAIL_HAL_SIM_SRCS(sim 那份)
|
||
# 新增一个器件驱动则是:
|
||
# ../components/drv/CMakeLists.txt 的 SRCS 和 下面的 PHONERAIL_DRV_SRCS
|
||
cmake_minimum_required(VERSION 3.16)
|
||
project(phonerail_host C)
|
||
|
||
set(CMAKE_C_STANDARD 11)
|
||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||
add_compile_options(-Wall -Wextra -Werror)
|
||
|
||
set(FW_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/..)
|
||
|
||
# ---- 被测代码 -------------------------------------------------------------
|
||
set(PHONERAIL_CORE_SRCS
|
||
${FW_ROOT}/main/version.c
|
||
${FW_ROOT}/main/rail.c
|
||
${FW_ROOT}/main/rail_cfg.c
|
||
${FW_ROOT}/main/sched.c
|
||
${FW_ROOT}/main/tasks.c
|
||
${FW_ROOT}/main/t_safety.c
|
||
${FW_ROOT}/main/t_actuator.c
|
||
${FW_ROOT}/main/evlog.c
|
||
)
|
||
|
||
# HAL:接口在 include/,宿主机链 sim/ 的实现(esp/ 那份只有 IDF 目标编)。
|
||
set(PHONERAIL_HAL_DIR ${FW_ROOT}/components/phonerail_hal)
|
||
set(PHONERAIL_HAL_SIM_SRCS
|
||
${PHONERAIL_HAL_DIR}/hal_err.c
|
||
${PHONERAIL_HAL_DIR}/hal_i2c_acct.c
|
||
${PHONERAIL_HAL_DIR}/sim/hal_lock_sim.c
|
||
${PHONERAIL_HAL_DIR}/sim/sim_hal.c
|
||
${PHONERAIL_HAL_DIR}/sim/hal_i2c_sim.c
|
||
${PHONERAIL_HAL_DIR}/sim/hal_gpio_sim.c
|
||
${PHONERAIL_HAL_DIR}/sim/sim_sr595.c
|
||
${PHONERAIL_HAL_DIR}/sim/sim_pca9555.c
|
||
${PHONERAIL_HAL_DIR}/sim/hal_pwm_sim.c
|
||
${PHONERAIL_HAL_DIR}/sim/hal_time_sim.c
|
||
${PHONERAIL_HAL_DIR}/sim/hal_store_sim.c
|
||
)
|
||
|
||
# 器件驱动:与平台无关(只经 hal_i2c_*),两个目标编的是同一份源码。
|
||
set(PHONERAIL_DRV_DIR ${FW_ROOT}/components/drv)
|
||
set(PHONERAIL_DRV_SRCS
|
||
${PHONERAIL_DRV_DIR}/ina226.c
|
||
${PHONERAIL_DRV_DIR}/dac63204.c
|
||
${PHONERAIL_DRV_DIR}/sr595.c
|
||
${PHONERAIL_DRV_DIR}/pca9555.c
|
||
)
|
||
|
||
add_library(phonerail_core STATIC
|
||
${PHONERAIL_CORE_SRCS} ${PHONERAIL_HAL_SIM_SRCS} ${PHONERAIL_DRV_SRCS})
|
||
target_include_directories(phonerail_core PUBLIC
|
||
${FW_ROOT}/main
|
||
${PHONERAIL_HAL_DIR}/include
|
||
${PHONERAIL_HAL_DIR}/sim
|
||
${PHONERAIL_DRV_DIR}/include)
|
||
|
||
# ---- 测试框架 Unity(从 ESP-IDF v5.4 原样复制到 third_party/,与上板测试同一套)
|
||
add_library(unity STATIC ${FW_ROOT}/third_party/unity/unity.c)
|
||
target_include_directories(unity PUBLIC ${FW_ROOT}/third_party/unity)
|
||
target_compile_definitions(unity PUBLIC UNITY_OUTPUT_COLOR)
|
||
# 第三方源码不吃本工程的 -Werror
|
||
target_compile_options(unity PRIVATE -w)
|
||
|
||
# ---- 测试用例:test/test_*.c 一个文件一个可执行 + 一条 ctest ---------------
|
||
enable_testing()
|
||
|
||
file(GLOB PHONERAIL_TESTS ${FW_ROOT}/test/test_*.c)
|
||
foreach(test_src ${PHONERAIL_TESTS})
|
||
get_filename_component(test_name ${test_src} NAME_WE)
|
||
add_executable(${test_name} ${test_src})
|
||
target_link_libraries(${test_name} PRIVATE phonerail_core unity)
|
||
add_test(NAME ${test_name} COMMAND ${test_name})
|
||
endforeach()
|