fix(vd960Loop): 灵敏度收敛 4 级制 + 运行中配置立即生效 (协议 V1.08)
根因: 设置不同灵敏度感应高度无区别 1. unpack_pkg_set_mcjq_param 未同步 loop_SensLevel → 改灵敏度需重启才生效 2. 9级制映射 sensitvity & 0x03 折叠 (默认7→3, 3→3, 8→0) 3. (测试陷阱) 金属块过大信号饱和, 建议小金属块测临界高度 修复: - 提取 sens_level_from_config() 映射函数, 4级制 0~3 一一对应 (9级制后改) - unpack_pkg_set_mcjq_param 补 loop_SensLevel 同步 (运行中立即生效) - para_store_init 上电路径改用同一函数 - 协议 V1.08: Sensitivity 0~9级 → 4级制 0~3 (默认2) - tests/test_sens_mapping.c gcc 隔离单测 PASS (0~3无折叠/兼容旧默认7→3)
This commit is contained in:
@@ -4,6 +4,43 @@
|
||||
|
||||
---
|
||||
|
||||
## 2026-08-25 — 灵敏度 4 级制修复(协议 V1.08)
|
||||
|
||||
### 背景
|
||||
|
||||
现场用金属块测感应高度,设置不同灵敏度档位**感应高度无区别**。排查发现三个根因:
|
||||
|
||||
| # | 根因 | 位置 |
|
||||
|---|------|------|
|
||||
| 1 | **运行中配置命令不同步检测单元**:`unpack_pkg_set_mcjq_param()` 只更新 `g_loop_cng_info.loop_cng[].sensitvity` + 写 flash,**没有同步 `g_loop_states.loop_unit[].loop_SensLevel`** → 改灵敏度不重启不生效(对比上电路径 `para_store_init()` 有同步) | main.c:576 |
|
||||
| 2 | **9级制映射 `& 0x03` 折叠**:协议 0~9 级(默认 7),`sensitvity & 0x03` 只取低 2 位 → 7→3、**3→3(从默认 7 改到 3 无效)**、8→0(反向折叠) | storage.c:184 |
|
||||
| 3 | 测试陷阱:金属块过大/过近信号饱和,4 档阈值都在饱和区 → 感应高度差异不可见(建议小金属块/测临界距离) | 测试方法 |
|
||||
|
||||
### 修复(方案 B:4 级制)
|
||||
|
||||
- 提取映射函数 `sens_level_from_config()`(storage.c/h):**4级制 0~3 一一对应**,9 级制后续实现时只改这一处
|
||||
- `unpack_pkg_set_mcjq_param()` 补 `loop_SensLevel` 同步 → 运行中配置立即生效
|
||||
- `para_store_init()` 上电路径改用同一函数(消除双处映射漂移)
|
||||
- 协议 V1.08:Sensitivity 语义 0~9 级 → **4 级制 0~3**(默认 2)
|
||||
- 新增 `tests/test_sens_mapping.c` gcc 隔离单测(mock flash.h/FreeRTOS.h/task.h + FLP GPIO 宏):验证 0~3 无折叠、兼容旧默认 7→3、SensTable 单调
|
||||
|
||||
### 改动
|
||||
|
||||
| 文件 | 内容 |
|
||||
|------|------|
|
||||
| `src/storage.c` | 新增 `sens_level_from_config()`;`para_store_init` 改用 |
|
||||
| `src/main.c` | `unpack_pkg_set_mcjq_param` 补 loop_SensLevel 同步(运行中生效) |
|
||||
| `inc/storage.h` | sensitvity 注释 4 级制;函数声明 |
|
||||
| `tests/test_sens_mapping.c` | 新增映射单测(gcc PASS) |
|
||||
| `tests/mock/` | flash.h/FreeRTOS.h/task.h 隔离测试 mock |
|
||||
| `docs/DLD960Loop_串口通信协议.md` | V1.08:灵敏度 4 级制 |
|
||||
|
||||
### 验证
|
||||
|
||||
gcc 单测 PASS:0→0, 1→1, 2→2, 3→3 无折叠;`7&0x0F → 3` 兼容旧默认。实机待金属块复测(建议小金属块测临界感应高度)。
|
||||
|
||||
---
|
||||
|
||||
## 2026-08-25 — variation ↔ ΔL/ΔL-L 物理对应分析与工具
|
||||
|
||||
### 背景
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
/* mock FreeRTOS.h — gcc 隔离测试用空壳 */
|
||||
#ifndef MOCK_FREERTOS_H
|
||||
#define MOCK_FREERTOS_H
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
/* mock flash.h — gcc 隔离测试用 (storage.c 依赖的 flash API + 宏) */
|
||||
#ifndef MOCK_FLASH_H
|
||||
#define MOCK_FLASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define DLD_BUFEER_SIZE 100
|
||||
#define DLD_FLASH_ADDRESS_START (0x08000000 + 1024 * 63 + 512)
|
||||
#define DLD_FLASH_MAX_SIZE (0x08000000 + 1024 * 64)
|
||||
#define MAX_Store_Size DLD_BUFEER_SIZE
|
||||
|
||||
void flash_write(uint32_t addr, uint16_t *buf, uint16_t len);
|
||||
void flash_read(uint32_t addr, uint16_t *buf, uint16_t len);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,4 @@
|
||||
/* mock task.h — gcc 隔离测试用空壳 (TaskHandle_t 由 TaskLoop.h 自行定义) */
|
||||
#ifndef MOCK_TASK_H
|
||||
#define MOCK_TASK_H
|
||||
#endif
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* test_sens_mapping.c — 灵敏度映射 gcc 隔离单测 (vd960Loop)
|
||||
*
|
||||
* 验证对象: storage.c 的 sens_level_from_config() (4级制 0~3 一一对应)
|
||||
* 背景: 2026-08-25 修复 "设置不同灵敏度感应高度无区别"
|
||||
* - 根因1: 运行中配置命令未同步 loop_SensLevel (main.c unpack_pkg_set_mcjq_param)
|
||||
* - 根因2: 9级制映射 &0x03 折叠 (7→3, 8→0 错乱) → 收敛为 4级制
|
||||
* 本测试保护: 9级制后续实现时, 0~3 映射不得破坏
|
||||
*
|
||||
* 编译运行:
|
||||
* gcc -I tests/mock -I utilities/at32f421_freertos_demo/inc \
|
||||
* tests/test_sens_mapping.c -o /tmp/test_sens_mapping && /tmp/test_sens_mapping
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* ---- 被测试对象: include storage.c 使 static 逻辑同编译单元可见 ---- */
|
||||
/* 硬件 GPIO 宏 mock (storage.c 的 set_flp_level 使用, 空实现) */
|
||||
#define FLPA1_HIGH do { } while (0)
|
||||
#define FLPA1_LOW do { } while (0)
|
||||
#define FLPA2_HIGH do { } while (0)
|
||||
#define FLPA2_LOW do { } while (0)
|
||||
#define FLPB1_HIGH do { } while (0)
|
||||
#define FLPB1_LOW do { } while (0)
|
||||
#define FLPB2_HIGH do { } while (0)
|
||||
#define FLPB2_LOW do { } while (0)
|
||||
#define FLPC1_HIGH do { } while (0)
|
||||
#define FLPC1_LOW do { } while (0)
|
||||
#define FLPC2_HIGH do { } while (0)
|
||||
#define FLPC2_LOW do { } while (0)
|
||||
#define FLPD1_HIGH do { } while (0)
|
||||
#define FLPD1_LOW do { } while (0)
|
||||
#define FLPD2_HIGH do { } while (0)
|
||||
#define FLPD2_LOW do { } while (0)
|
||||
|
||||
/* storage.c 引用的系统函数 (消除隐式声明 warning) */
|
||||
void nvic_system_reset(void);
|
||||
void delay_ms(uint32_t ms);
|
||||
|
||||
#include "../utilities/at32f421_freertos_demo/src/storage.c"
|
||||
|
||||
/* ---- 外部符号 stub ---- */
|
||||
#include "flash.h"
|
||||
void flash_write(uint32_t addr, uint16_t *buf, uint16_t len) { (void)addr; (void)buf; (void)len; }
|
||||
void flash_read(uint32_t addr, uint16_t *buf, uint16_t len) { (void)addr; (void)buf; (void)len; }
|
||||
void nvic_system_reset(void) { abort(); }
|
||||
void delay_ms(uint32_t ms) { (void)ms; }
|
||||
|
||||
const uint16_t SensTable[4] = {216, 108, 36, 10};
|
||||
const uint16_t SensTable_1[4] = {108, 72, 18, 9};
|
||||
Loop154_States g_loop_states; /* TaskLoop.c 的全局, 此处提供定义 */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* 4级制: 0~3 一一对应, 无折叠 */
|
||||
assert(sens_level_from_config(0) == 0);
|
||||
assert(sens_level_from_config(1) == 1);
|
||||
assert(sens_level_from_config(2) == 2);
|
||||
assert(sens_level_from_config(3) == 3);
|
||||
|
||||
/* 配置命令链路: pkg 低4位 & 0x0F 后传入 (main.c unpack 语义) */
|
||||
/* 上位机发 0x00~0x03 → 档位 0~3 */
|
||||
assert(sens_level_from_config(0x00 & 0x0F) == 0);
|
||||
assert(sens_level_from_config(0x01 & 0x0F) == 1);
|
||||
assert(sens_level_from_config(0x02 & 0x0F) == 2);
|
||||
assert(sens_level_from_config(0x03 & 0x0F) == 3);
|
||||
/* 兼容旧默认 7 (旧 9 级制默认): 7&0x0F=7 → &0x03=3 最高档, 行为连续 */
|
||||
assert(sens_level_from_config(0x07 & 0x0F) == 3);
|
||||
|
||||
/* 出厂默认 loops_cng_default[0]=2 → SENS=2 (高灵敏度档) */
|
||||
assert(sens_level_from_config(2) == 2);
|
||||
|
||||
/* 灵敏度表逐档单调: sens_in 递减 = 档位越高阈值越低 (越灵敏) */
|
||||
assert(SensTable[0] > SensTable[1]);
|
||||
assert(SensTable[1] > SensTable[2]);
|
||||
assert(SensTable[2] > SensTable[3]);
|
||||
|
||||
printf("PASS: sens_level_from_config 4级映射无折叠\n");
|
||||
printf(" SENS 0→%d, 1→%d, 2→%d, 3→%d\n",
|
||||
sens_level_from_config(0), sens_level_from_config(1),
|
||||
sens_level_from_config(2), sens_level_from_config(3));
|
||||
printf(" SensTable: {216,108,36,10} 单调递减 ✓\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -111,7 +111,7 @@ typedef enum
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t sensitvity; // 高四位表示灵敏度的数量,低四位表示当前灵敏度的序号(从0开始)
|
||||
uint8_t sensitvity; // 灵敏度序号: 4级制 0~3 (值越大越灵敏, 默认2); 9级制后续版本实现
|
||||
uint8_t delay_time;
|
||||
uint8_t output_mode;
|
||||
uint8_t direction_mode; // 方向判别模式,0 触发模式, 非0 表示方向判别模式
|
||||
@@ -171,6 +171,9 @@ typedef struct _DBN_BLE_STATE_
|
||||
|
||||
void set_flp_level(uint8_t loop_num, uint8_t freq_level);
|
||||
|
||||
/* 灵敏度配置 → 检测档位映射 (4级制: 0~3 一一对应; 9级制后续实现) */
|
||||
uint8_t sens_level_from_config(uint8_t sensitvity);
|
||||
|
||||
void set_factory_param(void);
|
||||
void storage_dev(void);
|
||||
void para_store_init(void);
|
||||
|
||||
@@ -584,8 +584,8 @@ static void unpack_pkg_set_mcjq_param(uint8_t *pkg, uint8_t len)
|
||||
for(j = 0; j < _amount; j++)
|
||||
{
|
||||
k = pkg[i++];
|
||||
unit->sensitvity = k & 0x0F;
|
||||
unit->loopFreq_Level = k >> 4;
|
||||
unit->sensitvity = k & 0x0F; // 低4位: 灵敏度序号 (4级制 0~3)
|
||||
unit->loopFreq_Level = k >> 4; // 高4位: 频率档
|
||||
unit->delay_time = pkg[i++];
|
||||
k = pkg[i++];
|
||||
unit->output_mode = k & 0x03;
|
||||
@@ -593,6 +593,9 @@ static void unpack_pkg_set_mcjq_param(uint8_t *pkg, uint8_t len)
|
||||
unit->exist_mode = pkg[i++];
|
||||
unit->direction_mode = pkg[i++];
|
||||
|
||||
// 同步灵敏度到检测单元 (修复: 运行中配置必须立即生效, 不依赖重启)
|
||||
g_loop_states.loop_unit[j].loop_SensLevel = sens_level_from_config(unit->sensitvity);
|
||||
|
||||
unit++;
|
||||
}
|
||||
|
||||
|
||||
@@ -113,6 +113,12 @@ void storage_dev(void)
|
||||
|
||||
}
|
||||
|
||||
/* 灵敏度配置 → 检测档位映射 (4级制: 0~3 一一对应; 9级制后续实现) */
|
||||
uint8_t sens_level_from_config(uint8_t sensitvity)
|
||||
{
|
||||
return sensitvity & 0x03;
|
||||
}
|
||||
|
||||
// set frequent level
|
||||
void set_flp_level(uint8_t loop_num, uint8_t freq_level)
|
||||
{
|
||||
@@ -181,7 +187,7 @@ void para_store_init(void)
|
||||
set_flp_level(i, unitout->loopFreq_Level);
|
||||
|
||||
// 同步灵敏度到检测单元
|
||||
g_loop_states.loop_unit[i].loop_SensLevel = unitout->sensitvity & 0x03;
|
||||
g_loop_states.loop_unit[i].loop_SensLevel = sens_level_from_config(unitout->sensitvity);
|
||||
g_loop_states.loop_unit[i].SET_PLUS = unitout->output_mode & 0x01;
|
||||
g_loop_states.loop_unit[i].SET_DLY = (unitout->output_mode >> 1) & 0x01;
|
||||
g_loop_states.loop_unit[i].hold_time = unitout->exist_mode * 20 * 5;
|
||||
|
||||
Reference in New Issue
Block a user