Files
STM32F4-Base/App/protocol/iec104/iec104_comm.c
T
wandering1 c1e7e8c42c
CI / L0 静态门禁 (pre-commit) (push) Failing after 3s
CI / L0.5 主机侧单测 (MSVC) (push) Failing after 2s
fix(104): 拆掉四处恒假的上界判断——合法带只改判下界,口径不变
L0 的 cppcheck 在 --all-files 下恒红四处,全在同一文件:
App/protocol/iec104/iec104_comm.c 的 80 / 94 / 107 / 121 行,诊断为
compareValueOutOfTypeRangeError —— 拿 unsigned short 与 65535 比较,
Condition is always false。根因是 IEC104_COMM_CA_MAX 与 PORT_MAX 都等于
65535u,而被比较的量是 uint16_t:那个上界判断在类型上就不可能成立。
这四处随上游 iec104_comm 落地进来,本地提交只跑暂存文件所以没人看见,
CI 跑 --all-files 就每轮都红(同族盲区:暂存面与全量面不等价)。

处置走「语义不动」那一支(用户裁定 2026-10-27:A):只删恒假的半边、
改判 if (v < MIN),合法带口径一字未改(仍照 iec104_comm.h 的常量注释:
ca 1..65535、port 1024..65535),只在第一处写清为何不再写上界、其余三处
短引用。没有把 MAX 改成 65534(按 60870-5-104 的 65535 = 未编址),因为
test/host/iec104/iec104_test.c:1521 明确断言 ca 设成 IEC104_COMM_CA_MAX
必须被接受——那会同时打断这条断言并改变现场设备行为(配 65535 的站会
突然回退工厂默认),属协议决定,不在本次范围;要改请单独裁。

验证:单文件 cppcheck 原样复刻钩子参数 → RC=0;cppcheck --all-files 由
红转绿;iec104-unit-test Passed(即 65535 那条合同照过);@build 0 错误
0 警告(Code 231732→231720,减 12 B,RO/RW/ZI 不变);凭证与两份台账
随之重盖(ER_IROM1 257,292→257,280、Flash 合计 258,812→258,800);
本次触发的 13 根钩子全 Passed,含 test-coverage(删掉 4 行已覆盖代码
未被判成回退)。
2026-10-27 10:34:39 +08:00

131 lines
5.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 模块名称:IEC 60870-5-104 通讯参数段([comm] 配置)实现
* 模块功能:/config.ini [comm] 段的 RAM 副本 / 工厂默认 / 键表与注册 +
* getter 合法带自愈 + setter 守卫。契约、线程约定与生效语义
* (改后重启生效、不挂回调不置事件位、主站地址不做)→
* iec104_comm.h 文件头;键表口径 → docs/子系统设计/网络配置说明.md
* §3.6;热生效代价分析 → docs/子系统设计/IEC104上行设计说明.md §8。
* 适用平台:STM32F407ZGTx / PC 模拟器(双端编译:模拟器运行期无 104 任务,
* 本 TU 不产生行为,按双端注册口径入 CMakeLists 保持构建事实一致)
* 创建日期:2026-10-26(道G task-8,「UI 补齐」第 5 项非 UI 前置)
* 修改记录:
* 2026-10-26 DTU 项目组 创建:实现体自 iec104_pts.c 尾段**同笔整体迁移**
* (零逻辑改动)。动因 = coding-standard
* CODE-RULE-17 (2.2)「非 static 函数须在配对头文件
* 声明」按文件名配对判定——初版把实现放 iec104_pts.c
* 而声明在 iec104_comm.h,钩子按规则判红;本模块
* 本就是独立配置段,配对拆分即正解。
*/
#include "iec104_comm.h"
#include <string.h>
#include "cfg_file.h"
/* ---------------- [comm] RAM 副本与工厂默认 ----------------
* 引擎属主 = defaultTask:本段只被 cfg_file_load/save/poll 通用遍历,本文件
* 不触引擎任何写路径;内核前注册点 = app_main.c(「先注册后 load」契约,同
* adc_cal_init / run_par_init)。App/protocol 零日志惯例保持——注册失败留痕
* 由调用方 app_main.c 锚点负责,getter/setter 纯 RAM 不打日志(iec104Task
* 深链省栈,AGENTS 日志成本口径)。 */
/* RAM 副本(引擎原地更新;u16 半字对齐读原子,撕裂域 = 单字段新旧值) */
typedef struct {
uint16_t ca; /* 公共地址(= 链路地址,ASDU 头 2B,点表 §1.5 口径) */
uint16_t port; /* 被控站 TCP 监听端口 */
} iec104_comm_t;
static iec104_comm_t s_comm;
static const iec104_comm_t s_comm_rom = {
IEC104_COMM_DEF_CA, IEC104_COMM_DEF_PORT
};
/* 键表(s_comm 布局内偏移,同 net_cfg/ftp_cfg 写法) */
static const cfg_key_def_t s_comm_keys[] = {
{ "ca", CFG_VAL_UINT, offsetof(iec104_comm_t, ca), 2u },
{ "port", CFG_VAL_UINT, offsetof(iec104_comm_t, port), 2u },
};
/* 函数定义区 */
/*
* 函数功能:置工厂默认并向引擎注册 [comm] 段(幂等,内核前)
* 返回值:0 注册成功;-1 重复注册/段数超限(RAM 副本已复位,adc_cal 同款) int
* 限定条件:先于 defaultTask 的 cfg_file_load;不挂回调(改后重启生效)
*/
int iec104_comm_init(void) {
cfg_section_reg_t reg;
(void)memcpy(&s_comm, &s_comm_rom, sizeof(s_comm));
(void)memset(&reg, 0, sizeof(reg));
reg.name = IEC104_COMM_SEC;
reg.p_data = &s_comm;
reg.p_defaults = &s_comm_rom;
reg.data_size = sizeof(s_comm);
reg.p_keys = s_comm_keys;
reg.key_count = (uint8_t)(sizeof(s_comm_keys) / sizeof(s_comm_keys[0]));
reg.p_cb = NULL; /* 不挂回调:iec104Task 启动读 getter(D5 口径) */
return cfg_file_register(&reg);
}
/*
* 函数功能:取生效公共地址
* 返回值:RAM 副本 ca,带外回退工厂默认;恒 ∈ IEC104_COMM_CA_MIN..MAX uint16_t
* 限定条件:无(任意上下文,纯读)
*/
uint16_t iec104_comm_ca(void) {
uint16_t v = s_comm.ca;
/* 只判下界。上界 IEC104_COMM_CA_MAX 就是 uint16_t 的最大值,写成
* 「v > 65535」对 uint16_t 恒假(cppcheck compareValueOutOfTypeRangeError),
* 留着只会让下一个读代码的人以为上界真被守过。合法带口径不变,
* 仍照 iec104_comm.h 的常量注释(ca 1..65535 / port 1024..65535)。 */
if (v < IEC104_COMM_CA_MIN) {
return IEC104_COMM_DEF_CA;
}
return v;
}
/*
* 函数功能:取生效监听端口
* 返回值:RAM 副本 port,带外回退工厂默认;恒 ∈ IEC104_COMM_PORT_MIN..MAX uint16_t
* 限定条件:无(任意上下文,纯读)
*/
uint16_t iec104_comm_port(void) {
uint16_t v = s_comm.port;
if (v < IEC104_COMM_PORT_MIN) { /* 上界恒假,同 iec104_comm_ca 处注释 */
return IEC104_COMM_DEF_PORT;
}
return v;
}
/*
* 函数功能:写 ca 进 RAM 副本(守卫 = getter 同带;非法不提交)
* 入口参数:ca - 公共地址 uint16_t
* 返回值:0 提交;-1 带外(副本不动) int
* 限定条件:UI 保存交接路(task-9);落盘走 SYS_EVT_CFG_SAVE 整档外科 save
*/
int iec104_comm_ca_set(uint16_t ca) {
if (ca < IEC104_COMM_CA_MIN) { /* 上界恒假,同 iec104_comm_ca 处注释 */
return -1;
}
s_comm.ca = ca;
return 0;
}
/*
* 函数功能:写 port 进 RAM 副本(守卫 = getter 同带;非法不提交)
* 入口参数:port - 监听端口 uint16_t
* 返回值:0 提交;-1 带外(副本不动) int
* 限定条件:同 iec104_comm_ca_set
*/
int iec104_comm_port_set(uint16_t port) {
if (port < IEC104_COMM_PORT_MIN) { /* 上界恒假,同 iec104_comm_ca 处注释 */
return -1;
}
s_comm.port = port;
return 0;
}