多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

F´ 组件命令字典详解:以 Test1 命令组件为例,读懂 XML 命令定义与字典生成

F´ 组件命令字典详解:以 Test1 命令组件为例,读懂 XML 命令定义与字典生成 嵌入式系统编程【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址https://gitcode.com/gh_mirrors/fpri/fprime点击查看免费下载组件命令字典Component Dictionary是 F´ 飞行软件框架中一类由 Autocoder 自动生成的文档它把组件对外暴露的命令Command以表格形式固化下来是地面系统Ground System与飞行软件之间关于命令协议的唯一事实来源。本文以仓库中 Test1 组件命令字典 为主体结合其定义源文件 Test1ComponentAi.xml、实现代码与单元测试完整讲解 F´ 命令从 XML 声明、opcode 计算、参数序列化、命令分发到响应回传的整条链路。读完本文你将能够独立解读 F´ 中任意组件生成的命令字典并知道如何为自己的组件声明并实现带多个类型参数的命令。一、关联文档概览Test1 组件命令字典长什么样Autocoders/Python/test/command1是 Autocoder 测试套件中的一个最小化命令组件示例。它通过main.cpp将两个组件命令实现组件TestCommand1Impl与命令源组件TestCommandSourceImpl连接起来验证 XML 命令定义能否被正确转换、序列化、分发并返回状态。该目录下的 docs/Test1.md 就是 Autocoder 根据组件定义自动生成并输出的命令字典文档其完整内容如下Test1 Component Dictionary ## Command List |Mnemonic|ID|Description|Arg Name|Arg Type|Comment |---|---|---|---|---|---| |TEST_CMD_1|272 (0x110)|A test command| | | | | | |arg1|I32|The I32 command argument| | | | |arg2|F32|The F32 command argument| | | | |arg3|U8|The U8 command argument|这份文档虽然篇幅不长却是理解 F´ 命令体系的最佳切入点一张表浓缩了命令助记符、有效 opcode、命令语义以及每个参数的名称、类型与说明。下文将从它的上游XML 定义和下游实现、发送、测试两个方向把它彻底展开。二、命令字典的源头Test1ComponentAi.xml 中的命令声明命令字典不是手写的而是 Autocoder 解析组件 XML 定义后生成的。Test1 组件的全部命令定义都位于 Test1ComponentAi.xml第 1533 行component nameTest1 kindpassive namespaceCmd import_port_typeAutocoders/Python/test/command1/Test2PortAi.xml/import_port_type import_port_typeFw/Cmd/CmdPortAi.xml/import_port_type import_port_typeFw/Cmd/CmdRegPortAi.xml/import_port_type import_port_typeFw/Cmd/CmdResponsePortAi.xml/import_port_type commentA component with a single command/comment commands opcode_base0x10 command kindguarded opcode0x100 mnemonicTEST_CMD_1 commentA test command/comment args arg namearg1 typeI32commentThe I32 command argument/comment/arg arg namearg2 typeF32commentThe F32 command argument/comment/arg arg namearg3 typeU8commentThe U8 command argument/comment/arg /args /command /commands ... /component这段 XML 是命令字典的母版几个关键属性决定了最终字典里的每一列XML 属性/元素值在字典中的体现command的mnemonicTEST_CMD_1表格Mnemonic列commands的opcode_base0x10参与有效 opcode 的计算见第三节command的opcode0x100参与有效 opcode 的计算command的kindguarded决定命令处理语义见第四节commentA test command表格Description列arg的namearg1/arg2/arg3表格Arg Name列arg的typeI32/F32/U8表格Arg Type列arg的commentThe I32 ... argument等表格Comment列从源码结构看opcode_base是组件级的偏移量opcode是单条命令的偏移量两者相加得到命令在整机命令空间中的有效 opcode见第三节的数值验证。此外XML 头部注释还说明了 Autocoder 支持的组件与命令属性组件kind可为active或passive命令kind可为sync、async或guardedpriority可为high、medium、low或interrupt仅对 active 组件的输入端口有效。三、字典核心列解读Mnemonic、ID 与 opcode 的计算规则命令字典的 Command List 表是整个文档的核心。逐列解读如下Mnemonic命令的助记符即代码与地面系统中引用该命令的符号名本例为TEST_CMD_1。ID命令的有效 opcode字典中记为272 (0x110)。它由 XML 中的opcode_base0x10与命令opcode0x100相加得出0x10 0x100 0x110而0x110的十进制正是272。这与生成字典中的数值完全吻合是验证 Autocoder opcode 合成逻辑最直接的证据。Description命令的一句话语义说明来自命令的comment本例为 A test command。Arg Name / Arg Type / Comment命令参数的名称、类型与注释。一个命令可以携带多个参数每个参数占用表格中一行首行仅列出 Mnemonic/ID/Description本例展示了三个参数arg1I32、arg2F32、arg3U8。这里的类型I32、F32、U8直接映射到 F´ 的基础整数/浮点类型体系定义于 Fw/Types/BasicTypes.hpp 及 Fw/Types/Types.fpp分别表示 32 位有符号整数、32 位单精度浮点数与 8 位无符号整数。命令参数类型与 F´ 串行化类型Fw::SerializeBufferBase支持的serialize重载一一对应因此字典中的类型列同时也是命令参数在Fw::CmdArgBuffer中序列化布局的依据。四、命令的实现侧cmdHandler 与命令响应状态字典只描述命令是什么命令怎么执行则在组件实现类的cmdHandler中完成。Test1 的命令实现位于 TestCommand1Impl.cpp 第 2830 行void TestCommand1Impl::TEST_CMD_1_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, I32 arg1, F32 arg2, U8 arg3) { printf(Got command args: %d %f %d\n, arg1, arg2, arg3 ); this-cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); }可以观察到 Autocoder 生成的命令处理方法命名约定Mnemonic_cmdHandler其参数顺序为opCode命令有效 opcode、cmdSeq命令序列号用于地面系统匹配响应以及紧跟其后的、与 XML 中args声明顺序完全一致的类型化参数arg1/arg2/arg3。实现体内除了处理命令逻辑还必须调用输出端口cmdResponse_out向命令源回传执行结果本例在打印参数后回传Fw::CmdResponse::OK。Fw::CmdResponse的完整状态枚举在 TestCommandSourceImpl.cpp 第 3556 行的printStatus中得到了全景展示包括状态值含义Fw::CmdResponse::OK命令执行成功Fw::CmdResponse::INVALID_OPCODE收到的 opcode 未注册Fw::CmdResponse::VALIDATION_ERROR参数校验失败Fw::CmdResponse::FORMAT_ERROR参数反序列化格式错误Fw::CmdResponse::EXECUTION_ERROR命令执行过程出错这与 Fw/Cmd/docs/sdd.md 对三个命令端口的定义相互印证Fw::Cmd端口用于向组件发送携带编码参数的命令Fw::CmdResponse端口用于组件回报命令完成状态Fw::CmdReg端口用于组件注册其全部命令 opcode。另外需要说明命令kindguarded的语义从源码结构看guarded 命令会在处理前持有组件内部互斥锁保证多个命令并发到达时串行执行相比sync同步执行与async放入队列异步执行它是 F´ 中兼顾实时性与线程安全的常用选择。该组件的实现类 TestCommand1Impl.hpp 继承自 Autocoder 生成的Test1ComponentBase这也解释了实现类本身只需关注业务逻辑、无需关心端口连接细节的设计。五、命令的发送侧CmdArgBuffer 序列化与边界条件测试命令字典中定义的参数最终需要被序列化进命令缓冲才能发送。命令源组件 TestCommandSourceImpl.cpp 第 5893 行的test_TEST_CMD_1函数演示了完整流程void TestCommandSourceImpl::test_TEST_CMD_1(I32 arg1, F32 arg2, U8 arg3) { if (!this-isConnected_cmdSendPort_OutputPort(0)) { printf(Test command port not connected.); return; } Fw::CmdArgBuffer argBuff; // 正常场景三个参数依次序列化 argBuff.serialize(arg1); argBuff.serialize(arg2); argBuff.serialize(arg3); this-cmdSendPort_out(0, 0x100, 1, argBuff); // 异常场景 1参数过多多序列化一次 arg3 argBuff.resetSer(); argBuff.serialize(arg1); argBuff.serialize(arg2); argBuff.serialize(arg3); argBuff.serialize(arg3); this-cmdSendPort_out(0, 0x100, 1, argBuff); // 异常场景 2参数过少只序列化两个 argBuff.resetSer(); argBuff.serialize(arg1); argBuff.serialize(arg2); this-cmdSendPort_out(0, 0x100, 1, argBuff); }这段代码揭示了命令发送的三个要点发送前必须检查端口连接通过isConnected_cmdSendPort_OutputPort(0)判断输出端口是否已连接未连接则直接返回避免空调用。参数顺序即序列化顺序arg1 → arg2 → arg3与 XMLargs声明顺序一致接收端会按同一顺序反序列化。参数个数是运行时校验点函数刻意构造了参数过多与参数过少两种畸形缓冲用于验证命令接收端CmdDispatcher的FORMAT_ERROR处理路径。命令参数缓冲的底层实现在 Fw/Cmd/CmdArgBuffer.hpp 中Fw::CmdArgBuffer继承自Fw::SerializeBufferBase内部持有U8 m_bufferData[FW_CMD_ARG_BUFFER_MAX_SIZE]的定长数组其序列化后大小为FW_CMD_ARG_BUFFER_MAX_SIZE sizeof(I32)缓冲内容 长度前缀最大容量由config/FpConfig.hpp中的FW_CMD_ARG_BUFFER_MAX_SIZE决定。也就是说命令字典中参数的类型与个数必须保证序列化后不超出该容量这也是地面系统生成命令时需遵循的约束。六、命令端口拓扑CmdDisp / CmdReg / CmdStatus 的角色分工一份命令字典之所以能够落地执行离不开组件声明的一组命令端口。在 Test1ComponentAi.xml 第 3443 行中Test1 组件声明了如下端口ports port nameCmdDisp kindinput data_typeFw::Cmd max_number1 roleCmd/ port nameCmdReg kindoutput data_typeFw::CmdReg max_number1 roleCmdRegistration/ port nameCmdStatus kindoutput data_typeFw::CmdResponse max_number1 roleCmdResponse/ port nameaport data_typeAnother::Test2 kindsync_input/ /ports三个命令相关端口构成了标准的命令三件套CmdDisp输入Fw::Cmd命令分发入口命令源通常是 CmdDispatcher通过它把携带 opcode 与参数缓冲的命令送入组件。CmdReg输出Fw::CmdReg命令注册端口组件通过它向 CmdDispatcher 注册自己的全部 opcode注册成功后地面系统才允许发送这些命令。CmdStatus输出Fw::CmdResponse命令响应端口组件执行完命令后通过它回传Fw::CmdResponse状态OK、EXECUTION_ERROR 等。此外aport是引用 Test2PortAi.xml 中Another::Test2接口的同步输入端口参数为arg4 (I32)、arg5 (F32)、arg6 (U8)用于验证跨命名空间端口类型的导入其对应的空实现aport_handler也出现在 TestCommand1Impl.cpp 第 25 行。从组件基类继承的角度看regCommands()与cmdResponse_out()等成员均由 Autocoder 根据以上端口声明生成。Fw::Cmd三个端口的类型定义与设计说明可进一步查阅 Fw/Cmd/Cmd.fpp 与 Fw/Cmd/docs/sdd.md。七、集成与验证main.cpp 接线、UT 框架与 CMake 构建7.1 main.cpp 中的端口接线main.cpp 第 1529 行演示了命令链路的完整接线过程TestCommand1Impl testImpl(TestCmdImpl); testImpl.init(); TestCommandSourceImpl cmdSrc(TestCmdSource); cmdSrc.init(); testImpl.set_CmdStatus_OutputPort(0, cmdSrc.get_cmdStatusPort_InputPort(0)); testImpl.set_CmdReg_OutputPort(0, cmdSrc.get_cmdRegPort_InputPort(0)); cmdSrc.set_cmdSendPort_OutputPort(0, testImpl.get_CmdDisp_InputPort(0)); testImpl.regCommands(); cmdSrc.test_TEST_CMD_1(10, 25.6, 5);接线逻辑清晰对应第六节的端口拓扑命令源cmdSrc的命令发送端口连到testImpl的命令分发端口 CmdDisptestImpl的注册端口 CmdReg 与响应端口 CmdStatus 分别连回cmdSrc的cmdRegPort与cmdStatusPort。之后调用testImpl.regCommands()注册命令最后以参数(10, 25.6, 5)调用test_TEST_CMD_1触发一次完整命令流程——预期在终端打印参数并返回COMMAND OK。另外TestCommandSourceImpl.cpp 第 2129 行的cmdStatusPort_handler与cmdRegPort_handler分别打印响应状态与注册的 opcode验证了注册与响应两条回传链路。7.2 单元测试框架test/ut/Tester.cpp 是标准的 F´ GTest 测试接线框架Tester继承自Test1GTestBase由 Autocoder 为 UT 生成的基类构造时调用initComponents()与connectPorts()在connectPorts()中逐一连接aport、CmdDisp、CmdStatus、CmdReg四个端口第 5381 行。这表明 UT 环境下命令字典所描述的命令会经由生成的测试基类自动获得发送与响应捕获能力开发者只需在测试用例中调用对应命令并断言历史记录。7.3 CMake 中的 Autocoder 输入注册CMakeLists.txt 展示了 XML 定义在构建体系中的位置set(SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/Test1ComponentAi.xml ${CMAKE_CURRENT_LIST_DIR}/Test2PortAi.xml ${CMAKE_CURRENT_LIST_DIR}/TestCommand1Impl.cpp ${CMAKE_CURRENT_LIST_DIR}/TestCommandSourceImpl.cpp ${CMAKE_CURRENT_LIST_DIR}/main.cpp ) set(MOD_DEPS Autocoders/Python/test/command_tester Os ) register_fprime_module()Test1ComponentAi.xml与Test2PortAi.xml被作为 Autocoder 输入文件列入SOURCE_FILESregister_fprime_module()触发 Autocoder 生成Test1ComponentBase、Cmd::CommandTesterComponentBase等基类代码与 docs/Test1.md 这份命令字典文档。模块依赖Autocoders/Python/test/command_tester指向 CommandTestComponentAi.xml后者定义了Cmd::CommandTester组件的cmdSendPort输出、cmdStatusPort同步输入、cmdRegPort同步输入三个端口与第六节的接线一一对应。八、小结从命令字典反推 F´ 命令体系的设计范式回到本文的主体文档 Test1 组件命令字典可以总结出 F´ 命令体系的一整套设计范式声明即文档命令在 XML或新版 FPP见 Fw/Cmd/Cmd.fpp中声明一次Autocoder 同时产出 C 基类、命令处理桩与命令字典文档三者必然一致。opcode 两级合成组件opcode_base 命令opcode 有效 opcode如0x10 0x100 0x110 272字典中的 ID 列就是地面系统的寻址依据。参数契约先行args中参数的类型、个数与顺序定义了CmdArgBuffer的序列化布局也定义了cmdHandler的函数签名字典中的 Arg Type 列即这份契约的明文。三端口闭环CmdDisp收命令、CmdReg注册 opcode、CmdStatus回状态共同构成命令生命周期任何一份命令字典背后都对应这样一组端口拓扑。对于想要在 F´ 项目中新增命令的开发者标准的操作路径是在组件定义文件XML 或 FPP中按本文第二节的语法添加command与args→ 重新运行构建触发 Autocoder → 在生成的组件实现类中实现MNEMONIC_cmdHandler并调用cmdResponse_out回传状态 → 查阅新生成的命令字典确认 opcode 与参数无误。这一流程从 Test1 组件的源码与测试 中即可获得完整、可运行的最小验证。赞分享嵌入式系统编程【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址https://gitcode.com/gh_mirrors/fpri/fprime点击查看免费下载相关推荐从 FASTA 到 PDB用 Python API 调用 AlphaFold 蛋白质结构预测实战指南从 FASTA 到 PDB用 Python API 调用 AlphaFold 蛋白质结构预测实战指南 用 AlphaFold 的 Python API 做蛋白嵌入式系统编程F´ BufferAccumulator 组件完全指南缓冲区积压/释放组件字典、命令与实现原理F´ BufferAccumulator 组件完全指南缓冲区积压/释放组件字典、命令与实现原理 F´F Prime是 NASA 喷气推进实验室开源的飞行软嵌入式系统编程F´ 框架遥测组件字典解析以 TestTlm 为例掌握通道定义与字符串遥测实现F´ 框架遥测组件字典解析以 TestTlm 为例掌握通道定义与字符串遥测实现 本指南以 F´F Prime飞行软件与嵌入式系统框架中 autocoder嵌入式系统编程上一篇如何成为rrweb核心贡献者从入门到精通的完整指南下一篇OpenProject 平板分屏导航实测列表与详情同屏工作包审阅不用来回翻屏创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表