/* * 模块名称: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 #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(®, 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(®); } /* * 函数功能:取生效公共地址 * 返回值:RAM 副本 ca,带外回退工厂默认;恒 ∈ IEC104_COMM_CA_MIN..MAX uint16_t * 限定条件:无(任意上下文,纯读) */ uint16_t iec104_comm_ca(void) { uint16_t v = s_comm.ca; if ((v < IEC104_COMM_CA_MIN) || (v > IEC104_COMM_CA_MAX)) { 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) || (v > IEC104_COMM_PORT_MAX)) { 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) || (ca > IEC104_COMM_CA_MAX)) { 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) || (port > IEC104_COMM_PORT_MAX)) { return -1; } s_comm.port = port; return 0; }