首页/新闻资讯/正文详情

F´ Topology 构建指南:从组件实例化、端口互连到活动组件任务启动的完整流程

发布时间:2026/9/25 7:21:05 来源:云帆数科 栏目:资讯中心
F´ Topology 构建指南:从组件实例化、端口互连到活动组件任务启动的完整流程
嵌入式系统编程【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址https://gitcode.com/gh_mirrors/fp/fprime点击查看免费下载本文以 F´F Prime飞控软件与嵌入式系统框架为背景系统讲解如何构建一个可运行的 F´ 拓扑Topology从组件实例化、基类初始化、端口互连、命令注册、参数加载到最终启动活动组件线程。读者完成后将掌握 F´ 拓扑的完整装配顺序、自动生成的端口访问器命名规则以及活动组件start()参数的实战配置方法。在 F´ 中最终执行起来的软件并非一个单体程序而是一组相互连接interconnect的组件集合。这些组件或运行在活动组件active component自己拥有的线程上或由硬件中断、定时源等系统事件驱动。将这一系列组件“装配”成一个可执行系统的过程就是构建拓扑。本文将以 docs/UsersGuide/dev/building-topology.md 为主线结合仓库内 Reference 部署Ref的真实代码与Fw/Comp基类实现逐层展开拓扑构建的六个关键步骤实例化组件Instantiating the Components初始化组件Initializing the Components互连组件Interconnecting the Components注册命令Registering Commands加载参数Loading Parameters启动活动组件Starting Active Components提示若希望跟随动手实践教程构建拓扑可参阅 Tutorials关于如何实现组件本身的派生类逻辑可参阅 docs/UsersGuide/dev/implementation.md。拓扑构建的总体流程在现代 F´ 版本中拓扑的装配步骤被高度自动化Ref部署的setupTopology()见 Ref/Top/RefTopology.cpp按固定顺序调用一组由自动代码生成器autocoder生成的函数即可完成全部装配工作void setupTopology(const TopologyState state) { // Autocoded initialization. Function provided by autocoder. initComponents(state); // Autocoded id setup. Function provided by autocoder. setBaseIds(); // Autocoded connection wiring. Function provided by autocoder. connectComponents(); // Autocoded command registration. Function provided by autocoder. regCommands(); // Autocoded configuration. Function provided by autocoder. configComponents(state); // Project-specific component configuration. Function provided above. configureTopology(); // Autocoded parameter loading. Function provided by autocoder. loadParameters(); // Autocoded task kick-off (active components). Function provided by autocoder. startTasks(state); ... }从源码结构看这一调用序列正是本文六个步骤的工程化体现initComponents完成实例化与初始化connectComponents完成端口互连regCommands完成命令注册loadParameters完成参数加载startTasks最终启动活动组件线程。也就是说手工编写拓扑的每一步在自动代码生成路径中都有对应的生成函数理解手工流程就能理解这些生成函数的职责边界。实例化组件Instantiating the Components组件基类的构造函数在设计上刻意保持“内存模型无关”开发者可以根据目标平台与工程约束选择静态static、堆heap或栈stack任意一种方式创建组件实例。如 docs/UsersGuide/dev/building-topology.md 所述基类构造函数要么带一个name参数、要么无参而开发者编写的派生类构造函数可以追加该应用特有的额外参数。两点实战注意事项静态对象执行顺序不确定若以静态方式声明组件必须警惕 C 静态初始化顺序static initialization order fiasco带来的不确定性——被连接的组件可能尚未完成构造。参数化构造派生类的构造参数通常携带应用特有配置例如Ref中的cmdSeq命令序列器在configureTopology()里通过cmdSeq.allocateBuffer(0, mallocator, CMD_SEQ_BUFFER_SIZE)为其分配存放命令序列的内存。现代 F´ 的实例声明方式在基于 FPPF´ Prime Parser的现代开发流程中组件实例不再用手写 C 构造而是在 FPP 文件中声明由 autocoder 生成实例化代码。参考 Ref/Top/instances.fpp每个实例用一条instance语句声明可携带base id、queue size、stack size、priority等属性module Default { constant QUEUE_SIZE 10 constant STACK_SIZE 64 * 1024 } instance blockDrv: Drv.BlockDriver base id 0x0100 \ queue size Default.QUEUE_SIZE \ stack size Default.STACK_SIZE \ priority 140 instance cmdDisp: Svc.CommandDispatcher base id 0x0500 \ queue size 20 \ stack size Default.STACK_SIZE \ priority 101可见 FPP 已经把“实例化 后续的初始化参数”整合为声明式配置生成的代码再交由initComponents(state)统一执行。初始化组件Initializing the Components实例化之后每个组件都需要调用其init()方法初始化组件基类。关键规则调用时机init()应在组件实例化之后调用。队列大小参数对于 queued队列组件和 active活动组件init()需要传入队列大小。以 Fw/Comp/ActiveComponentBase.cpp 为例ActiveComponentBase::init()只是透传调用QueuedComponentBase::init(instance)。队列大小的确定原则队列应当基于对任务优先级和组件间消息流量的理解来定容。队列过小可能导致消息丢失过大则浪费内存——这在嵌入式内存受限平台上尤为敏感。在 FPP 中init()所需的队列大小直接由实例声明中的queue size属性表达见上文instances.fpp片段例如blockDrv使用默认值 10而cmdDisp显式声明为 20fileDownlink、fileManager、fileUplink均声明为 30反映出各自不同的消息吞吐预期。互连组件Interconnecting the Components组件之间的协作通过端口连接port connection实现。其底层机制是将目标组件的输入端口指针传递给调用方组件的输出端口。组件基类会生成一系列方法用于获取输入端口指针、设置输出端口指针。端口类型不同访问器的命名也各不相同。接口端口Interface Ports接口端口是组件间互连的常规端口。对组件上的每一对端口类型与端口名方法命名规则如下获取输入端口指针\PortType\* get_\port name\_InputPort(NATIVE_INT_TYPE portNum);其中\PortType\ 组件 XML 端口定义中data_type属性指定的完整端口类型\port name\ 端口定义name属性中的端口名。若该端口只有唯一实例portNum参数应传 0。设置输出端口指针void set_\port name\_OutputPort(NATIVE_INT_TYPE portNum, \PortType\* port);参数含义同上portNum在单实例端口时应传 0。此外还有一个针对**串行化端口serialized port**的重载版本void set_\port name\_OutputPort(NATIVE_INT_TYPE portNum, Fw::InputSerializePort *port);命令端口Command Ports对于定义了命令的组件代码生成器会创建一整套命令相关端口。这些端口的访问函数采用标准命名获取命令输入端口Fw::InputFwCmdPort* get_CmdDisp_InputPort();设置命令状态输出端口void set_CmdStatus_OutputPort(Fw::InputCmdResponse_Port* port);设置命令注册输出端口void set_CmdReg_OutputPort(Fw::InputCmdRegPort* port);对于与这些端口对接的组件如命令调度器则按上一节描述的普通端口方法获取/设置指针。遥测端口Telemetry Ports遥测telemetry相关的标准端口访问函数如下设置遥测输出端口void set_Tlm_OutputPort(Fw::InputTlmPort* port);设置时间输出端口void set_Time_OutputPort(Fw::InputTimePort* port);事件日志端口Event Logging Ports事件记录相关的标准端口访问函数如下设置日志输出端口void set_Log_OutputPort(Fw::InputLogPort* port);void set_TextLog_OutputPort(Fw::InputFwLogTextPort* port);设置时间输出端口void set_Time_OutputPort(Fw::InputFwTimePort* port);注意set_Time_OutputPort()与遥测端口是共用的——调用一次即可同时满足遥测与事件日志的时间源需求。参数端口Parameter Ports参数相关的标准端口访问函数如下void set_ParamGet_OutputPort(Fw::InputFwPrmGetPort* port);void set_ParamSet_OutputPort(Fw::InputFwPrmSetPort* port);现代 F´ 的声明式连接pattern graph specifiers在 FPP 时代上述繁琐的get_*_InputPort/set_*_OutputPort手工接线被声明式语法取代。以 Ref/Top/topology.fpp 为例命令、事件、参数、遥测、文本事件、时间、健康检查等“星型”连接只需声明一次全局模式autocoder 即自动完成对所有组件的端口互连command connections instance cmdDisp event connections instance eventLogger param connections instance prmDb telemetry connections instance tlmSend text event connections instance textLogger time connections instance posixTime health connections instance $health数据流向明确的一对一/一对多连接则用connections块显式表达例如下行链路connections Downlink { tlmSend.PktSend - downlink.comIn eventLogger.PktSend - downlink.comIn downlink.framedAllocate - staticMemory.bufferAllocate[Ports_StaticMemory.downlink] downlink.framedOut - comm.$send ... }理解手工的端口访问器命名规则正是读懂这些 FPP 连接语义A.port - B.port实为“把 B 的输入端口指针交给 A 的输出端口”的基础。注册命令Registering Commands命令分发的典型模式是由用户实现的命令调度组件如Svc.CommandDispatcher把自身的命令输出端口连接到每个“服务命令的组件”的命令输入端口。调度器内部会将特定组件的一组操作码opcode映射到与该组件相连的端口。为辅助这一过程当组件定义了命令时代码生成器会生成一个命令注册函数。该函数接受一个参数调度器组件上连接该组件命令端口的端口号。使用要点组件的命令注册端口应连接到调度器的注册端口随后可调用组件上的regCommands()方法它会为组件定义的每一个操作码逐一触发注册端口该方法应对每个含有命令的组件调用。在自动生成路径中regCommands()由拓扑级的regCommands()函数批量触发见 Ref/Top/RefTopology.cpp 中的调用顺序。加载参数Loading Parameters参数加载的流程分两步连接参数端口将组件的参数输出端口set_ParamGet_OutputPort/set_ParamSet_OutputPort见上文连接到提供参数存储的组件如Svc.PrmDb调用加载方法两个组件连接完成后调用基类方法loadParameters()。该方法会通过参数端口请求该组件的全部参数值此后这些值即可供实现类使用。两点实战细节可重入虽然常见的做法是仅在软件初始化时读取一次参数但运行期间参数存储被更新后再次调用loadParameters()重新读取是完全允许的没有任何机制阻止这种“热重载”。FPP 对应物param connections instance prmDb这一声明正是自动完成“所有组件参数端口连接到prmDb”的现代写法。参考Ref部署参数数据库组件在configureTopology()中还需要完成文件级配置prmDb.configure(PrmDb.dat)与prmDb.readParamFile()见 Ref/Top/RefTopology.cpp。启动活动组件Starting Active Components构建拓扑的最后一步是为所有活动组件启动其任务线程。start()方法定义在 Fw/Comp/ActiveComponentBase.hpp 的Fw::ActiveComponentBase基类中其参数及含义如下活动组件start()参数表参数含义identifier与线程无关的标识值用于标识该线程的活动在系统中应保持唯一。priority任务的执行优先级0 低优先级255 高优先级。stackSize分配给任务的栈大小。在 FPP 中priority与stackSize直接在实例声明里指定见 Ref/Top/instances.fpp例如blockDrv的优先级 140、rateGroup1Comp的 120、cmdDisp的 101、eventLogger的 98、tlmSend的 97、prmDb的 96 等形成一条清晰的优先级梯度stack size则统一取Default.STACK_SIZE 64 * 1024。start() 的源码级实现从 Fw/Comp/ActiveComponentBase.cpp 可以看到start()的真实行为它构造一个Os::Task::Arguments任务名默认取组件的对象名getObjName()将任务例程routine设置为状态机或任务循环然后委托Os::Task::start()启动并用FW_ASSERT断言启动状态为OP_OKvoid ActiveComponentBase::start(Os::Task::ParamType priority, Os::Task::ParamType stackSize, Os::Task::ParamType cpuAffinity, Os::Task::ParamType identifier) { ... Os::Task::Arguments arguments(taskName, routine, this, priority, stackSize, cpuAffinity, identifier); Os::Task::Status status this-m_task.start(arguments); FW_ASSERT(status Os::Task::Status::OP_OK, ...); }从 Os/Task.hpp 可见现代版本还扩展了cpuAffinity参数用于多核绑定且TASK_DEFAULT作为缺省值使用std::numeric_limitsFwSizeType::max()。任务生命周期preamble() 与 finalizer()如原文档所述preamble()与finalizer()两个虚函数会在“等待端口调用的循环”前后各执行一次。从源码看它们由任务生命周期状态机s_taskStateMachine()驱动状态依次为CREATED → DISPATCHING → FINALIZING → DONE见 Fw/Comp/ActiveComponentBase.cpp线程进入CREATED阶段时先调用preamble()默认空实现随后转入DISPATCHINGDISPATCHING阶段反复调用dispatch()分发队列消息直到收到退出消息ACTIVE_COMPONENT_EXIT后转入FINALIZINGFINALIZING阶段调用finalizer()默认空实现并进入DONE。配套方法还有exit()向组件队列发送退出消息与join()等待线程结束对应Ref拓扑中的teardownTopology()清理流程stopTasks(state)停止任务、freeThreads(state)释放线程资源见 Ref/Top/RefTopology.cpp。小结构建 F´ 拓扑的完整链路可概括为“实例化 → 初始化 → 互连 → 注册命令 → 加载参数 → 启动任务”六步。在手工编写阶段开发者直接操作自动生成的端口访问器get_*_InputPort/set_*_OutputPort系列在现代 FPP 流程中这些工作由instances.fpp、topology.fpp声明与 autocoder 生成的initComponents/connectComponents/regCommands/loadParameters/startTasks函数接力完成。理解这套流程与命名规则既是调试自定义拓扑的基础也是阅读Ref、RPI等参考部署拓扑代码的钥匙。赞分享嵌入式系统编程【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址https://gitcode.com/gh_mirrors/fp/fprime点击查看免费下载相关推荐F´ 软件框架拓扑构建实战组件实例化、端口互连与任务启动全流程指南F´ 软件框架拓扑构建实战组件实例化、端口互连与任务启动全流程指南 导读 本文是 F´F Prime飞行软件与嵌入式系统框架中构建系统拓扑Cons嵌入式系统编程Tock安全启动流程完整指南从硬件信任根到应用层的完整信任链构建Tock安全启动流程完整指南从硬件信任根到应用层的完整信任链构建 Tock是一个专注于安全性的嵌入式操作系统其安全启动流程通过硬件信任根、加密验证和分层隔离操作系统嵌入式嵌入式OS使用测试驱动开发TDD构建 F´ 组件从 FPP 建模到测试通过的完整实践指南使用测试驱动开发TDD构建 F´ 组件从 FPP 建模到测试通过的完整实践指南 本篇指南以 F PrimeF´飞行软件与嵌入式系统框架为背景完整讲解嵌入式系统编程上一篇为什么选择M5Stack Arduino Library探索物联网开发的强力工具下一篇终极指南从零开始彻底掌握tslib触摸屏开发创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

ctf-wiki 内核利用实战:ret2usr 攻击手法解析——以 2018 强网杯 core 为例
ctf-wiki 内核利用实战:ret2usr 攻击手法解析——以 2018 强网杯 core 为例

文档网络安全教程 【免费下载链接】ctf-wiki Come and join us, we need you! 项目地址: https://gitcode.com/gh_mirrors/ct/ctf-wiki 点击查看 免费下载 导读 ret2usr(return to user space)是 Linux 内核 pwn 中一种经典的控制流劫持提权… · 2026/9/25 7:20:59

Finagle 客户端与服务工厂构建期指标:codec_connection_preparation_latency_ms 与 available 指标详解
Finagle 客户端与服务工厂构建期指标:codec_connection_preparation_latency_ms 与 available 指标详解

后端RPC框架 【免费下载链接】finagle A fault tolerant, protocol-agnostic RPC system 项目地址: https://gitcode.com/gh_mirrors/fi/finagle 点击查看 免费下载 本文围绕 Finagle 文档 Construction.rst 中定义的「构建期(Construction)… · 2026/9/25 7:20:59

OpenShell 治理拦截器示例:用 Gateway Interceptor 构建签名的策略基线与权威 Provider Profile 源
OpenShell 治理拦截器示例:用 Gateway Interceptor 构建签名的策略基线与权威 Provider Profile 源

【免费下载链接】OpenShell OpenShell is the safe, private runtime for autonomous AI agents. 项目地址: https://gitcode.com/gh_mirrors/op/OpenShell 点击查看 免费下载 本篇以 examples/governance-interceptor 示例为主体,讲解如何基于 OpenShe… · 2026/9/25 7:20:59

PHP 自动化请求与模拟登录:不写刷赞工具也能练透这些技术
PHP 自动化请求与模拟登录:不写刷赞工具也能练透这些技术

这类主题我不能帮你写。标题里的“一键领取名片赞”“一键领取圈圈赞”,本质上是一个自动刷赞、批量互动的小工具。这类工具不管代码写得怎么样,落到实际用途就是批量制造虚假互动、绕过平台风控,属于平台规则明令禁止的作弊行为。作为博主我… · 2026/9/25 7:56:24

酒店智能客房设备和服务响应系统如何管理,如何选择
酒店智能客房设备和服务响应系统如何管理,如何选择

​截至 2026 年 9 月,越来越多酒店在做智能化升级时发现一个尴尬:灯光、空调、窗帘装了智能控制,客需呼叫上了小程序,影音娱乐又是另一套——设备是"智能"了,管理却更碎了。客房设备一套系统、服务响应一套系… · 2026/9/25 7:56:24

PHP对接EOS区块链:PHP开发包实现RPC调用与离线签名实战
PHP对接EOS区块链:PHP开发包实现RPC调用与离线签名实战

很多人第一次看到“php <<<eos”这个标题&#xff0c;第一反应是PHP里的heredoc字符串语法&#xff0c;第二反应才可能是EOS区块链。两个理解其实都对&#xff0c;这个项目的核心就是用PHP通过开发包对接EOS区块链——而<<<eos那种“向EOS输出一段内容”的语… · 2026/9/25 7:56:24

广氟 PTFE 全矩阵方案:解决半导体 / 算力 / 新能源高端工况痛点
广氟 PTFE 全矩阵方案:解决半导体 / 算力 / 新能源高端工况痛点

高端制造卡脖子痛点&#xff1a;PTFE 膜细分品类的现实供需矛盾半导体、AI 算力、储能电池、高频通信快速扩张&#xff0c;下游不再只追求 “能用” 的 PTFE 材料。高速 PCB 需要极低介电损耗&#xff1b;半导体湿法制程过滤膜要兼顾耐强氧化剂与高精度截留&#xff1b;电池 PA… · 2026/9/25 7:56:24

浏览器自动化脚本开发指南:从篡改猴到用户脚本实战
浏览器自动化脚本开发指南:从篡改猴到用户脚本实战

1. 从“雨课堂刷课教程”这个标题说起“雨课堂刷课教程”这个标题&#xff0c;乍一看像是一份操作指南&#xff0c;但稍微有点开发经验的人都能嗅到它背后的技术气息——浏览器自动化。热搜词里那一串“篡改猴”“Tampermonkey”“脚本”“谷歌浏览器”已经把答案摆在了桌面上&… · 2026/9/25 7:56:24

confd 依赖链解析:mapstructure 将 map[string]interface{} 解码为 Go 结构体的原理与实践
confd 依赖链解析:mapstructure 将 map[string]interface{} 解码为 Go 结构体的原理与实践

后端配置中心运维 【免费下载链接】confd Manage local application configuration files using templates and data from etcd or consul 项目地址&#xff1a; https://gitcode.com/gh_mirrors/co/confd 点击查看 免费下载 本篇以 confd 仓库中内置&#xff08;vendor&#… · 2026/9/25 7:56:18

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码