cFS与SB学习记录(七):启用EDS以后,消息身份和命令分发变在哪里

前面几篇一直在讲管道、路由和缓冲区。这些机制在 EDS 模式下仍然存在。我接着想弄清的是:既然发送接收主线没有换,CFE_EDS_ENABLED 到底改变了什么?为什么独立运行 SB,还要带上 EdsLib、MissionLib 和一套生成数据库?

把这一层展开,也就能把之前学过的 EDS 与这次的 SB 阅读接起来。这里尤其要区分“用 EDS 描述的 native 消息在 SB 中流转”和“把对象打包成线上字节”,两者不能仅凭一个 EDS 开关混为一谈。

系列目录 · 上一篇:管理任务

先看构建时到底选了什么

SB 的构建脚本把主要公共实现放在一起,再按模式选择两组文件:

作用 默认实现 EDS 实现
SB 管理消息分发 cfe_sb_dispatch.c cfe_sb_eds_dispatch.c
消息头大小与身份工具 cfe_sb_msg_id_util.c cfe_sb_eds_msg_id_util.c

管道创建、订阅、发送、接收、缓冲区管理和管理动作函数,仍然来自共用的 SB 文件。

不过差异不止这两个文件名。CFE_MSG_* 的实现也要与模式匹配:独立 EDS 基线使用 EDSMSG,而不是把默认 cfe_msg 和 EDSMSG 同时链接。它们提供同名的消息 API,作用是把上层和具体头布局隔开。

1
2
3
4
5
SB 公共机制
├─ 管道 / 订阅 / 发送 / 接收 / 缓冲区
└─ 通过 MSG 和接口工具理解消息
├─ 默认实现与任务配置
└─ EDSMSG + EdsLib / MissionLib + 任务数据库

因此只加 -DCFE_EDS_ENABLED 而不选择匹配源码、配置和数据库,不是一套完整 EDS 构建。

先分清三种 ID

EDS 集成里最容易混的是 TopicId、MsgId 和 EdsLib Type ID。我把它们分别放在三个问题里:

标识 回答什么问题
TopicId 任务接口中的哪一种主题/端点关系
MsgId SB 用什么消息身份订阅、查路由和投递
EdsLib Type ID 数据库中的哪一个类型,用哪些成员、尺寸与约束解释对象

命令功能码又是另一项信息,用于一组命令中的具体操作。它既不是 TopicId,也不是 RouteId。

消息身份应通过 CFE_MSG_GetMsgId()、CFE_SB_ValueToMsgId() 等接口访问。默认消息实现中某些位可以对应 CCSDS Stream ID,其他消息实现可能使用不同编码,不能把“某几位永远表示处理器号”写成 SB API 的普遍保证。

同一个 TopicId 为什么还需要处理器实例

EDS 模式的本地遥测映射入口大致是:

1
CFE_SB_LocalTlmTopicIdToMsgId(TopicId);

它继续调用带实例号的映射,把 TopicId 和 CFE_PSP_GetProcessorId() 提供的实例交给 MissionLib Publisher 映射。命令方向则走 Listener 映射。全局入口使用约定的全局实例号,不能把它与本地实例随意混用。

1
2
3
TopicId + 实例 + Publisher/Listener 方向
→ 任务的 MissionLib 映射规则
→ SB MsgId

这次 SampleMission 基线中,本地 STATS 的 TopicId 是 275,处理器实例取 1 时得到 MsgId 0x80a。275 不等于 0x80a,也不能把这对数值推广到另一套任务数据库。最初实例号不匹配时映射无效,正说明这个“平台小接口”确实参与了消息身份的形成。

代码里最好引用生成的 TopicId/MsgId 定义,并在初始化时核对两种入口得到一致结果。只在测试程序中手写 0x80a,会掩盖映射层是否可用。

SB 里传的仍然是可访问的 native 对象

Linux 示例构造的是生成的 C 消息类型,再把 native 大小传给 CFE_MSG_Init() 和 SB。TransmitMsg() 复制这份 native 内容,两个 OSAL 队列传递内部描述符指针。

这条流程里没有自动调用 EdsLib_DataTypeDB_PackCompleteObject()。它不因此证明跨大小端、位字段紧凑编码或网络 PEC 的正确性。若接下来要发送到异构机器或实际链路,需要在相应边界加入匹配的 Pack/Unpack 或传输适配。

1
2
当前路径:生成的 C 类型 → native 消息 → SB 池和指针队列
线包路径:native 对象 → EDS Pack → packed bytes → 传输

同样,CFE_MSG_Init() 也不能简单等同于“按 EdsLib 初始化完整业务对象的所有约束”。当前 EDSMSG 实现会清零给定范围,设置 MsgId、分段和大小等头部信息;业务字段及其类型身份仍要按具体生成定义正确填写。

消息头大小也可能需要数据库帮助

应用有时要从消息头找到 payload。默认实现可以按所选头类型计算;EDS 路径则尝试从消息发布/监听参数找到 Topic,查询对应接口和参数类型,再根据派生约束识别具体类型,取得真实数据成员的 native 偏移。

这里取得的是 native 对象中的字节偏移,不是 packed 位流的 bit offset。把这两种偏移混用,得到的指针即使落在分配范围里,也可能指向另一个字段。

这版 CFE_SB_MsgHdrSize() 还保留了查表失败时按传统消息头大小退回的逻辑。因此“启用了 EDS”也不意味着所有经过 SB 的消息都已经被完整登记和严格验证过。判断某一次调用的行为,仍要看它实际走了哪条分支。

一条 NOOP 怎样走到处理函数

默认分发主要靠 MsgId 和功能码判断,再按具体命令结构检查长度。EDS 版本在 SB 层的入口短得多:

1
2
Status = EdsDispatch_EdsComponent_CFE_SB_Application_Telecommand(
SBBufPtr, &CFE_SB_TC_DISPATCH_TABLE);

短代码把工作交给生成包装和 EDSMSG 分发器。主要过程仍然能逐步拆开:

1
2
3
4
5
6
7
从消息头取得 PubSub 参数
→ 找到 Topic 和组件接口
→ 找到参数基类型
→ 按功能码等约束识别具体派生类型
→ 对照 native 类型大小
→ 选择分发表中的处理函数
→ CFE_SB_NoopCmd

CFE_SB_TC_DISPATCH_TABLE 把生成的成员位置关联到实际 C 函数。例如 NOOP 最后仍调用前一篇看到的 CFE_SB_NoopCmd();EDS 没有替它生成“增加计数并上报事件”的全部服务动作。

这也是类型数据库和函数实现必须匹配的原因。若只更换生成头,却没有更新接口数据库与分发表,代码可能仍能编译,运行时却无法按原来的位置识别和分发。

读分发器时记下的一处指针错误

表驱动减少了手写分支,但不保证每个失败出口都正确。当前复用的 EDSMSG 分发源码中,CFE_EDSMSG_Dispatch_GetTopicInfo() 有一个分支写成:

1
memset(&TopicInfo, 0, sizeof(TopicInfo));

这里的 TopicInfo 已经是指向输出结构的指针。&TopicInfo 是局部指针变量自身的地址,sizeof(TopicInfo) 也是指针大小。这一行清掉的是局部指针,不是调用者的输出结构。若意图是清输出,形状应是:

1
memset(TopicInfo, 0, sizeof(*TopicInfo));

还需要结合参数非空约定和辅助查询的返回状态一起处理,不能只改一行就宣称失败路径全部正确。两条 Topic 查询辅助函数的错误也需要明确传回或阻止后续继续使用无效结果。

我把它记录在这里,是因为它恰好说明源码学习里“函数注释说了什么”和“这一行实际写到哪里”必须同时检查。当前 Linux 正常示例走通 NOOP,不会自动覆盖这些无效 Topic 分支;本文也没有把它写成已经修复并回归过的功能。

数据库在运行时被查询,不代表运行时生成 XML

独立基线里的 eds/generated 来自固定 SampleMission 构建快照。C 编译器重新编译生成的 C/H 和运行库,程序启动后查询编译进来的数据结构;普通构建不运行 sedstool,也不在运行中解析 XML。

1
2
主机生成阶段:任务 XML / 规则 → 生成类型、数据库、接口与映射
目标运行阶段:编译后的数据库 + 运行库 → 查询、识别与分发

更换任务定义时,需要重新生成并匹配类型、接口、Topic 映射和配置。把某个 XML 复制到目录里,再执行一次现有 cmake --build,不会自动改变这份已固化的数据库。

这次我借 EDS 模式读到的重点,已经从“XML 能生成结构体”往前走了一步:生成物还参与消息身份、类型识别和接口分发。与此同时,任务间传递、服务动作和线包编码仍各有自己的执行边界。

对照源码可从 SB 构建选择、EDS 身份工具和 NASA EdsLib进入。下一篇:Linux 独立移植记录。

cFS与SB学习记录(七):启用EDS以后,消息身份和命令分发变在哪里

https://goko-son626.github.io/post/cfs-sb-06-eds.html

作者

GoKo Mell

发布于

2026-10-23

更新于

2026-10-23

许可协议

评论