EDS与PUS实践(四):用EDS描述服务类型17的四种消息

  • 真正开始写服务类型 17 的 EDS XML 后才发现,难点不在 XML 语法,而在于区分标准固定内容和任务需要自行声明的内容。把公共包头、服务约束和业务字段分层后,文件会清楚很多。

上一篇已经把 CCSDS 主头、PUS-C 次头和 PUS 服务类型 17 的服务语义拆开。本文继续把这些规则落到 EDS 模型中,重点不是记 XML 标签,而是建立“标准条款 → 任务剖面 → 类型约束 → 生成结果”的对应关系。

本章要记录的实现过程

前三篇已经分别完成概念分层、生成流程和协议分析。现在才开始写服务类型 17 的 XML,是因为模型应当由需求推导,而不是由“能用哪些标签”反推需求。

本章按下面顺序完成建模:

  1. 把标准固定项、任务声明项和运行时行为分开;
  2. 确定 XML 文件之间的依赖层次;
  3. 先建立 CCSDS/PUS 公共包,再建立 ST17 抽象基类;
  4. 定义四种具体消息和 Application Process ID;
  5. 用 Interface 描述请求与报告关系;
  6. 从 resolved XML、生成头和数据库反查结果;
  7. 用尺寸、字段、PEC 和负向测试证明模型不是“只会生成”。

本章实现的是消息数据契约和接口元数据,不实现进程登记、连接测试回调和失败报告状态机。后者属于服务运行时,留到独立实现验证时处理。

写 XML 前先冻结任务剖面

标准允许任务声明若干字段,若不先冻结,XML 与 Python 对端很容易各用一套默认值。当前示例明确采用:

项目 当前选择 性质
PUS 版本 PUS-C,字段值 2 标准版本选择
TC Source ID 16 bit 任务声明
TM Destination ID 16 bit 任务声明
TM 时间 CUC 4+2,无线上 preamble 任务声明
Message Type Counter 不存在 任务裁剪
PEC CRC-16-CCITT,2 byte 任务选择/模型声明
Application Process ID 16 bit 大端枚举 ST17 任务声明

只有 Service Type=17 和四个 Message Subtype 是服务标准固定值。上表其他宽度不能写成“PUS-C 对所有任务都规定如此”。

文件为什么要拆开

最小实验最初只有三份 XML:

1
2
3
base_types.xml
ccsds_spacepacket.xml
pus17.xml

后面加入多个服务时,又把共用的 PUS-C 主头/次头抽到 pus_common.xml。目前更适合扩展的关系是:

1
2
3
4
5
6
7
base_types.xml

ccsds_spacepacket.xml

pus_common.xml

st01.xml / st17.xml / stXX.xml

这样 APID、序列号、PUS 版本、Source ID 和 PEC 类型不会在每个服务里复制一遍。

每层只拥有自己的变化原因

base_types.xml 只因基础标量约定变化而改变;ccsds_spacepacket.xml 只因空间包公共结构变化而改变;pus_common.xml 保存 PUS-C 任务剖面;st17.xml 只描述测试服务。这样增加 ST03 不需要复制或修改 ST17,调整 ST17 进程枚举也不会碰公共包头。

文件拆分不是为了目录好看,而是让依赖方向单向:上层可以引用下层,下层不应反向知道某个服务。若 pus_common.xml 出现 Tc17_1,说明公共层已经被具体服务污染。

XML 包名比文件名更关键

EDS 引用通常使用 PACKAGE/Type 这样的逻辑名称。文件名用于构建系统发现输入,Package name 则参与类型命名空间。重命名文件却不改包名,与改包名却不更新引用,影响不同。

排查“类型找不到”时应同时确认:文件是否进入 EdsTool 输入列表、Package 名是否正确、引用路径是否与包名一致、依赖文件是否在解析阶段可见。

为什么服务专属枚举不放进 common

Application Process ID 只被 ST17 使用,并且不同任务可能采用不同列表。把它放进 common 会让其他服务无意义地依赖 ST17 任务选择。除非多个服务真的共享同一任务级应用过程标识类型,否则优先留在 st17.xml

先定义服务类型 17 的公共基类

TC 的公共约束可以写成一个抽象容器:

1
2
3
4
5
6
7
8
9
10
11
<ContainerDataType name="TcSt17Base"
baseType="PUS_COMMON/PusTcPacket"
abstract="true">
<ConstraintSet>
<ValueConstraint entry="PriHdr.VersionId" value="0"/>
<ValueConstraint entry="PriHdr.PacketType" value="TC"/>
<ValueConstraint entry="PriHdr.SecHdrFlag" value="true"/>
<ValueConstraint entry="SecHdr.PusVersionId" value="2"/>
<ValueConstraint entry="SecHdr.ServiceType" value="17"/>
</ConstraintSet>
</ContainerDataType>

TM 也有对应的 TmSt17Base。具体消息只需要继续约束消息子类型号,不必重复整套公共字段。

这种继承不仅减少 XML,也让 EdsLib 能通过约束识别派生类型。

约束如何形成类型判别链

以 TC[17,3] 为例,类型身份由多层约束共同组成:

1
2
3
4
PUS_COMMON/PusTcPacket
└─ PacketType=TC、SecHdrFlag=true、PusVersionId=2
└─ PUS17/TcSt17Base:ServiceType=17
└─ PUS17/Tc17_3:SubserviceType=3

运行库从基类对象读取约束字段时,可以逐层识别更具体类型。abstract="true" 表示 TcSt17Base 只是分类和复用节点,不应作为完整可发送消息。

哪些字段适合做 ValueConstraint

只有“选择了这个类型就必须恒定”的字段才适合做约束,例如方向、协议版本、服务号和消息子类型。APID、序列计数和 Source ID 往往随任务实例或每个包变化,不应为方便初始化而错误固定。

约束过少会让派生类型无法唯一识别;约束过多会把本应运行时变化的字段写死。判断标准是:这个值是类型身份,还是消息实例数据?

17.1 和 17.2 为什么没有业务字段

TC[17,1] 是 are-you-alive 请求,TM[17,2] 是响应。按照 41C 的数据结构,它们没有 application/source data。

“没有业务字段”并不等于空包。完整线包仍然包含:

1
CCSDS 主头 + PUS 次头 + PEC

TC[17,1] 的具体类型只需要增加 Message Subtype 约束和包尾 CRC:

1
2
3
4
5
6
7
8
9
10
<ContainerDataType name="Tc17_1" baseType="TcSt17Base">
<ConstraintSet>
<ValueConstraint entry="SecHdr.SubserviceType" value="1"/>
</ConstraintSet>
<TrailerEntryList>
<ErrorControlEntry name="Pec"
type="BASE_TYPES/uint16"
errorControlType="CRC16_CCITT"/>
</TrailerEntryList>
</ContainerDataType>

“省略 application data”要体现在模型结构里

最直接的表达是具体类型不增加普通 EntryList,只继承公共头并增加 Trailer。不要为了让结构看起来完整,加入一个长度为 0 的占位字段或保留字节;那会改变 packed layout,独立实现也会把它当真实应用数据。

对当前剖面,TC[17,1] 的长度可手算为:

1
2
3
4
5
6 byte CCSDS primary header
+ 5 byte PUS TC secondary header
+ 0 byte application data
+ 2 byte PEC
= 13 byte

TM[17,2] 虽然同样没有 source data,但 TM 次头包含 Destination ID 和时间,所以不能照搬 TC 的总长度。无正文只说明服务专用数据为零,不说明 TC/TM 总包同长。

Trailer 为什么属于具体消息

公共基类不带 PEC,可以让每个具体消息明确决定是否存在错误控制,并避免基类与派生类型重复追加。当前四种 ST17 消息都在具体类型末尾声明同一 ErrorControlEntry,这是任务剖面的选择。

17.3 为什么必须有进程 ID

TC[17,3] 要求对指定应用过程做连接测试,因此业务数据不能省略。当前任务把它声明成 16 位枚举:

1
2
3
4
5
6
7
8
9
10
<EnumeratedDataType name="ApplicationProcessId">
<EnumerationList>
<Enumeration label="DemoProcess1" value="1"/>
<Enumeration label="DemoProcess2" value="2"/>
</EnumerationList>
<IntegerDataEncoding
encoding="unsigned"
byteOrder="bigEndian"
sizeInBits="16"/>
</EnumeratedDataType>

然后在 TC[17,3] 和 TM[17,4] 中都加入:

1
2
3
4
<EntryList>
<Entry name="ApplicationProcessId"
type="ApplicationProcessId"/>
</EntryList>

标准规定它是任务声明的枚举,并没有替所有任务决定 16 位。选择 16 位是当前数据契约的一部分,换任务时可以调整,但发送端、接收端和独立参考实现必须保持一致。

TC 和 TM 必须引用同一个类型

若 TC[17,3] 使用 16 bit 而 TM[17,4] 另定义一个 8 bit 类型,两个文件都可能通过 Schema,服务却无法“原样返回同一标识”。让两者引用同一个 ApplicationProcessId,编译期模型就能防止宽度漂移。

枚举表与可测试列表不是一回事

XML 枚举表定义线上值的符号含义;服务运行时注册表定义当前可以测试的目标及回调。DemoProcess2=2 存在于枚举中,不代表进程 2 当前已注册或连接正常。

因此解包 TC[17,3] 时,值 2 可以是格式合法的枚举;服务执行时仍要查注册表。未登记目标的失败属于业务有效性判断,不应让 EdsLib CRC/结构解包承担。

未声明枚举值怎样处理要显式决定

数据类型层可通过范围或枚举约束表达允许值,但不同工具对未知枚举的解析和显示策略可能不同。服务层无论如何都要把“目标是否在可测试列表”作为权威判断,并返回标准要求的执行阶段失败报告。

接口关系也写进 XML

数据类型说明“包长什么样”,接口则说明哪条请求对应哪条报告:

1
2
3
4
5
6
7
8
9
10
11
12
<Interface name="Test" level="functional">
<CommandSet>
<Command name="AreYouAlive">
<Argument name="request" type="Tc17_1" mode="in"/>
<Argument name="report" type="Tm17_2" mode="out"/>
</Command>
<Command name="OnBoardConnectionTest">
<Argument name="request" type="Tc17_3" mode="in"/>
<Argument name="report" type="Tm17_4" mode="out"/>
</Command>
</CommandSet>
</Interface>

EdsLib 的 IntfDB 可以查询这些关系,但它不会替应用调用 UDP,也不会自动执行连接测试。

为什么仍值得声明 Interface

固定示例可以直接在 C 代码里写 Type ID,但当服务增多后,通用工具希望按 Test/AreYouAlive 找到请求和报告类型。Interface 把这种关系保存在可查询元数据中,避免工具维护第二张手写映射表。

它还可以作为模型审查点:若 OnBoardConnectionTest 的报告误指向 Tm17_2,即使四个数据类型各自正确,接口关系仍然错误。IntfDB 让这类错误能够被程序化检查。

Interface 不是函数调用描述的全部实现

Command 中的 mode="in"/mode="out" 表达参数方向,不等于 C 函数原型,也不承诺同步调用。PUS 请求与报告可能跨网络、异步到达。应用仍需建立关联、队列、超时和路由机制。

写完 XML 后怎样自查

目前使用的检查顺序:

  1. sedstool 能否解析全部引用;
  2. 生成的 packed bit size 是否符合手工计算;
  3. 初始化后服务号、消息子类型号、TC/TM 方向是否正确;
  4. 17.1/17.2 是否没有多余业务字节;
  5. 17.3/17.4 是否都有相同宽度的进程 ID;
  6. 长度字段能否由 EdsLib 自动填写;
  7. PEC 是否随报文内容变化;
  8. 改坏约束或 CRC 后是否会解包失败。

自查要从静态证据走到动态证据

可以把八项检查分为四层:

  • 解析层:输入文件、引用、Schema、resolved XML;
  • 生成层:C 类型、Type ID、数据库表项和尺寸;
  • 运行层:Initialize、Pack、Unpack、字段输出;
  • 对照层:手算长度、golden vector、独立实现和负向包。

只跑最外层脚本并看到 PASS,无法知道前面哪项真正被检查。一个好的测试日志应至少显示类型名、packed bits、完整 hex、关键字段和坏包拒绝结果。

四种消息都要单独检查

17.1 和 17.2 能发现 TC/TM 公共头差异;17.3 和 17.4 能发现业务枚举位置与方向差异。只测 17.1,无法证明 TM 时间字段正确,也无法证明 Application Process ID 已进入模型。

先做一张“标准要求—模型位置”对照表

写 XML 前先把每条要求放到正确层次,可以避免把所有字段都塞进 st17.xml

要求 应放位置 原因
主头 6 字节与字段位宽 ccsds_spacepacket.xml 所有空间包共用
Packet Type、APID、序列、长度 CCSDS 公共类型 与具体 PUS 服务无关
PUS 版本、ACK、Source/Destination ID pus_common.xml 多个 PUS 服务共用
Service Type 固定为 17 服务类型 17 的抽象基类约束 四种消息共用
Message Subtype 1/2/3/4 四种具体消息约束 用于区分消息类型
17.3/17.4 进程 ID 两个具体消息正文 17.1/17.2 不允许有该字段
请求与报告对应关系 服务类型 17 的 Interface 描述接口,不实现行为
可测试进程列表与成功判据 服务实现代码/配置 属于运行时行为,不是线格式

这张表也适用于其他服务:先区分公共线格式、服务固定约束、消息正文和运行时行为,再开始写类型。

为每条表项指定证据

“主头 6 byte”可以由 CCSDS 标准与 packed size 证明;“17.3 有进程 ID”可由 8.17.2.3、resolved XML 和生成类型证明;“未登记目标返回开始执行失败”必须由服务测试日志证明。把证据类型写在设计表中,能够防止用 XML 截图代替行为验证。

公共包类型怎样组合

一个可复用的公共模型通常包含三层:

1
2
3
4
5
6
7
8
9
10
11
PusPriHdr
├─ PacketVersion / PacketType / SecHdrFlag / APID
├─ SequenceFlags / SequenceCount
└─ PacketDataLength(由完整包尺寸计算)

PusTcSecHdr
└─ PUSVersion+AckFlags / Service / Message Subtype / SourceId

PusTmSecHdr
└─ PUSVersion+TimeRef / Service / Message Subtype
/ [可选消息类型计数器] / DestinationId / Time

方括号中的字段必须按任务剖面决定。早期最小模型保留了 16 位 Message Type Counter;另一份合并后的剖面将它裁剪为不存在。二者都不能孤立地称为“唯一 PUS-C 格式”,但同一条交叉验证链路两端必须选同一种。

公共头也要避免重复定义 CCSDS 类型

VersionId、APID、Sequence Flags、Sequence Count 和 Length 等标量应引用 CCSDS 包已有类型;PUS common 只组合它们并增加 PUS 次头字段。这样空间包位宽有单一来源,多个服务不会各自维护 11 bit APID。

TC 与 TM 公共次头不要强行合并

TC 有 ACK Flags 和 Source ID,TM 有 Time Reference Status、Destination ID 和时间等任务字段。为了“少一个类型”把二者做成同一结构,通常会引入无意义字段或条件布局。共享基础标量即可,TC/TM 容器应分别清晰表达各自线格式。

长度字段为什么适合由模型计算

CCSDS Packet Data Length 是“整包字节数减 7”。如果业务代码先打包正文,再手工回写长度,容易出现三个问题:

  1. 修改正文后忘记同步长度;
  2. 把整包长或数据域长直接写入;
  3. CRC 先于长度计算,导致 PEC 覆盖的是错误内容。

EDS 的 LengthEntry 能把长度与容器最终尺寸关联起来。完整打包会先完成长度等特殊字段,再完成依赖整个对象的 Error Control。具体 XML 标定表达式需要结合工具链的换算方向核对,不能只凭常数名字猜测;最可靠的检查仍是对 13 字节包验证长度字段等于 6。

为什么仅看公式名字不够

LengthEntry 的校准表达式可能描述“字段值到实际长度”的正向关系,工具在打包时再做逆向求值。看到常数 7 不能仅凭直觉判断应加还是减,应结合生成数据库语义和实际包验证。

最稳妥的三个断言是:

1
2
3
TC[17,1] total = 13 byte → length field = 6
TC[17,3] total = 15 byte → length field = 8
received total = decoded length field + 7

若这三条同时成立,才能证明模型、打包和接收端解释一致。

长度与可变消息的后续问题

ST17 当前四种消息都是固定长度,因此 CompleteObject API 足够。其他 PUS 服务可能包含可变数组或可选数据,需要 VarSize API 与更复杂的 LengthEntry 关系。不要把固定长度实现直接推广到所有服务。

PEC 应放在具体消息的 Trailer

当前模型在具体 TC/TM 类型末尾声明 ErrorControlEntry。这样 CRC 自然覆盖此前已编码的主头、次头和正文,同时 PEC 自身不参与输入。

把 PEC 定义成普通可写 uint16 会留下两个隐患:应用可能忘记计算,解包也不一定执行错误控制验证。ErrorControlEntry 的意义正是告诉运行库“这是特殊字段,不是普通业务参数”。

CRC 初始化是运行时前置条件

应用启动时必须调用 EdsLib_Initialize()。EdsLib 头文件明确说明 DataTypeDB 初始化会建立错误控制算法需要的查找表。漏调时,XML 仍可生成、普通字段也可能打包,但 PEC 结果没有可靠保证。

PEC 变化应成为测试断言

改变 APID、序列计数、Source ID 或 Application Process ID 后,PEC 都应随受保护字节变化。测试可以固定其他字段,只改一个值,确认新包仍能 Complete Unpack,而把旧 PEC 强行放回时会失败。

不要在 Pack 之后再改长度或正文

Complete Pack 已经按照最终内容计算 CRC。之后对 packed buffer 的任何受保护 byte 修改,都会使 PEC 失效。若测试要构造合法变体,应修改 native object 后重新 Pack;若要测试坏包,才在 Pack 后故意翻 bit。

17.3/17.4 的进程 ID 要满足四个一致

若任务选择 16 位大端枚举,至少检查:

  • TC[17,3] 和 TM[17,4] 引用同一个 EDS 类型;
  • puslib 或另一独立实现也按 2 字节大端解释;
  • 成功响应原样返回请求中的值;
  • 未声明枚举值的处理策略清楚。

标准要求目标标识是任务声明的枚举,但服务实现还必须维护“可测试进程列表”。枚举中存在一个值,不自动意味着该进程当前可测试;线格式合法性与运行时可用性是两个判断。

再增加两个行为一致性

除了文中四点,完整服务还应检查:

  • 未登记 ID 产生 TM[1,4],而不是伪造 TM[17,4];
  • 已登记但测试失败产生 TM[1,8],而不是静默超时。

前四点偏向数据契约,后两点属于服务状态机。把它们放在同一测试计划中,但不要假装都由 XML 完成。

Interface 声明能带来什么

Interface 中的 Command 把请求和报告类型放在同一语义入口下。配合 IntfDB,通用程序可以查询:

  • Test 接口有哪些命令;
  • AreYouAlive 的输入类型是 TC[17,1];
  • 对应输出类型是 TM[17,2];
  • OnBoardConnectionTest 的参数/返回类型是什么。

它不会创建线程、打开 UDP、调用回调或等待响应。Interface 是可查询的接口元数据,不是 RPC 框架。把这一点弄清后,就不会期待“XML 写了 Command,服务就能自动运行”。

什么时候 IntfDB 值得进入目标系统

若目标程序编译期就固定调用四个消息类型,直接使用生成宏最小;若需要按接口名加载服务、生成命令帮助或动态发现参数,IntfDB 才带来明显收益。是否链接 IntfDB 应由产品需求决定,而不是因为 XML 中存在 Interface 就强制带入。

从生成物反查模型是否落地

生成完成后,建议依次检查:

  1. *_eds_datatypes.h 中是否生成四种具体 native 类型;
  2. *_eds_defines.h 中是否存在相应类型索引;
  3. DataTypeDB 中 17.3/17.4 的 packed size 是否比 17.1/17.2 多 16 bit;
  4. DisplayDB 中是否能按完整名字查到类型和 ApplicationProcessId
  5. IntfDB 中两个 Command 是否分别关联正确请求/报告;
  6. resolved XML 中的基类、约束和引用是否与源模型一致。

若生成头里字段正确但 packed size 不对,应优先看编码和容器布局;若类型根本没生成,再回到输入源清单、包名和引用解析阶段。

生成物审查不等于手工修改生成物

审查的目的是验证模型被工具正确解释。发现字段或尺寸错误后,修改源 XML、任务配置或生成插件,再重新生成。直接改 *_eds_datatypes.h 只会让下一次构建覆盖,并造成头文件与数据库不一致。

用 TypeInfo 做尺寸表

可以写一个很小的工具,对四种类型调用 GetTypeInfo() 并打印 native bytes 与 packed bits。预期关系比绝对值更重要:TC[17,3] 比 TC[17,1] 多 16 bit,TM[17,4] 比 TM[17,2] 多 16 bit;TC 与 TM 的绝对长度因次头不同而不同。

这张表若与手算一致,说明业务字段确实进入 packed layout,而不是只出现在 native struct 中。

XML 建模中最常见的四个反模式

把 APID 当成 17.3 进程 ID。 两者层级不同,前者在主头,后者在正文。

给 17.1 添加目标进程参数。 标准规定 TC[17,1] 无参数;带目标的是 TC[17,3]。

每个服务复制完整包头。 短期看文件自包含,长期会让字段宽度、时间格式和 CRC 定义发生漂移。

只检查 XML 是否能生成。 两端共同使用错误模型时仍可往返成功,必须加入手算尺寸、已知向量、坏包和独立实现测试。

把任务选择写成标准事实。 16 bit Process ID、CUC 4+2 和无 Message Type Counter 都是当前剖面,不是 PUS-C 对所有任务的固定格式。

在公共层加入服务专属字段。 这会让其他服务被迫依赖 ST17,并使后续修改影响范围扩大。

用 Interface 代替服务实现。 元数据只能描述关系,不能执行进程测试或产生失败报告。

扩展到其他服务时可以复用什么

增加新服务时通常保留 base_types.xmlccsds_spacepacket.xmlpus_common.xml,新增 stXX.xml

  1. 建立该服务的 TC/TM 抽象基类并固定 Service Type;
  2. 为每种消息子类型建立具体派生类型;
  3. 按标准表格定义各自正文;
  4. 在 Interface 中声明请求、报告与参数关系;
  5. 生成后按同一套尺寸、约束、PEC 和独立实现流程验证。

能够复用的是建模方法和公共协议层,不能机械复制的是每个服务的业务字段、状态机与失败语义。

扩展新服务的最小工作单

例如加入 ST03 时,不先复制 st17.xml,而是重新从标准列出:消息清单、每种消息的数据结构、任务声明项、周期/按需行为、失败条件和与 ST01 的关系。然后只复用 CCSDS/PUS common、生成基础设施和 Pack/Unpack 测试框架。

这种方式表面比改服务号慢,实际能避免把 ST17 的无正文消息、进程 ID 和测试回调错误带进完全不同的服务。

一次可复现的模型验证流程

最终流程可以整理成:

1
2
3
4
5
6
7
8
9
10
1. 清理并重新配置构建目录
2. 运行 sedstool,保存生成日志与 resolved XML
3. 编译 Runtime、DataTypeDB、DisplayDB/IntfDB(按需)
4. 打印四种消息的 Type ID 与尺寸
5. 初始化并打包固定输入
6. 对照字段表解释完整 hex
7. Complete Unpack 并比较关键字段
8. 分别破坏 subtype、length、正文、PEC
9. 与独立实现交换 TC/TM
10. 记录任务剖面和工具版本

前 3 步证明生成链可复现,4~8 步证明 EDS/EdsLib 内部行为,9 步降低共同错误风险,10 步保证结果以后仍可解释。

本章小结

服务类型 17 的 EDS 模型不是“四个结构体加一个服务号”。它由公共空间包、任务 PUS 次头、ST17 抽象约束、四个具体消息、任务枚举、特殊长度/错误控制和接口关系共同组成。

最重要的建模原则是让每项要求只出现在正确层次:协议公共字段进入 common,类型身份进入 ValueConstraint,消息正文进入具体 EntryList,PEC 进入 Trailer,运行状态和成功判据留给服务代码。下一篇只把已经生成并验证的 packed TC 通过 UDP 送到另一进程,观察传输层是否保持字节不变。

这里可以放一张四种消息生成类型的截图:

图片预留:截取生成头文件中 TC[17,1]、TM[17,2]、TC[17,3]、TM[17,4] 四种类型,保存为 eds-pus-04-service-type-17-eds-model/st17-generated-types.png

一个阶段性结论

XML 正确不等于只通过 Schema。真正有用的验证是:标准条款能在模型中定位、生成尺寸正确、固定字段正确、字节正确、坏包能拒绝,并且另一套实现能读懂。

下一篇先做一个更小的闭环:把 EdsLib 产生的 TC packed bytes 通过 UDP 交给另一个 C 进程,再由 EdsLib 解包。它还不执行服务类型 17 的请求—报告行为,但能把“模型与编解码”同“进程间传输”分开验证。

参考资料

EDS与PUS实践(四):用EDS描述服务类型17的四种消息

https://goko-son626.github.io/post/eds-pus-04-service-type-17-eds-model.html

作者

GoKo Mell

发布于

2026-08-16

更新于

2026-09-20

许可协议

评论

:D 一言句子获取中...