ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

F´ 子拓扑(Subtopologies)设计模式:模块化组件分组、配置覆盖与核心子拓扑实战指南

F´ 子拓扑(Subtopologies)设计模式:模块化组件分组、配置覆盖与核心子拓扑实战指南 F´ 子拓扑Subtopologies设计模式模块化组件分组、配置覆盖与核心子拓扑实战指南【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址: https://gitcode.com/GitHub_Trending/fpr/fprime子拓扑Subtopology是 FPP 建模语言提供的一种可复用设计模式把一组组件实例与组件间连接打包成一个独立单元随后导入到更大的部署拓扑中复用从而避免在每个项目中手工重复接线。本文以 F´ 仓库中的 CdhCore、ComCcsds、ComFprime、FileHandling、DataProducts 等核心子拓扑为实例讲解子拓扑的定义、导入、参数化配置与构建期覆盖机制读者学完后可在自己的部署中直接导入、定制并接线这些官方子拓扑。什么是子拓扑在 FPPF´ Prime Prime中拓扑topology是组件实例与连接的集合而**子拓扑subtopology**则是其中可以被整体复用的一小块。它的核心理念与 UML/SysML 中的 composite block复合块类似把“设计上就要协同工作”的一组组件封装成一个可导入的单元上层拓扑只需一次import即可自动带入该单元内部的全部实例与连接。子拓扑带来的直接收益模块化功能边界清晰例如“命令与数据处理CDH”“CCSDS 通信栈”“文件处理”各自成块可复用同一子拓扑可在多个部署中反复导入无需重写内部接线易管理复杂系统的组件与连接被组织成有名字、有文档的结构而非一张庞大的扁平网。一个最小示例ManagerWorker 子拓扑关联文档使用 ManagerWorker 示例说明子拓扑的基本形态该示例位于 fprime-examples 仓库的 FlightExamples/ManagerWorkermodule ManagerWorker { # Defining the instances to be used in subtopology instance manager: ManagerWorker.Manager base id ManagerWorkerSubtopologyConfig.ManagerWorkerSubtopology_BASE_ID 0x0000 \ queue size ManagerWorkerSubtopologyConfig.Defaults.QUEUE_SIZE \ stack size ManagerWorkerSubtopologyConfig.Defaults.STACK_SIZE \ priority ManagerWorkerSubtopologyConfig.Priorities.manager instance worker: ManagerWorker.Worker base id ManagerWorkerSubtopologyConfig.ManagerWorkerSubtopology_BASE_ID 0x1000 \ queue size ManagerWorkerSubtopologyConfig.Defaults.QUEUE_SIZE \ stack size ManagerWorkerSubtopologyConfig.Defaults.STACK_SIZE \ priority ManagerWorkerSubtopologyConfig.Priorities.worker Subtopology for connecting manager/worker topology Subtopology { # Instantiation in subtopology instance manager instance worker connections ManagerWorker { manager.startWorker - worker.startWork manager.cancelWorker - worker.cancelWork worker.workDone - manager.doneRecv } } # end Subtopology } # end ManagerWorker这个示例展示了子拓扑的两个核心组成部分实例定义manager与worker两个组件实例在模块ManagerWorker中声明。注意它们的base id、队列大小、栈大小、优先级都引用了一个独立的配置模块ManagerWorkerSubtopologyConfig中的常量——这正是后面要讲的“参数化配置”思想的雏形。子拓扑定义topology Subtopology中列出要纳入的实例instance manager、instance worker并通过connections ManagerWorker块描述三者之间的连接关系startWorker、cancelWorker、workDone三个端口。定义完成后设计好的“管理/工作”组件对就可以像搭积木一样被整体引入任何上层拓扑topology ExamplesDeployment { import ManagerWorker.Subtopology [...] }导入后上层拓扑通过**限定名qualified name**引用子拓扑内部的实例与端口topology ExamplesDeployment { import ManagerWorker.Subtopology instance otherComponent connections Other { otherComponent.cancelAll - ManagerWorker.worker.cancelWork } }从源码结构看这种“模块内实例 Subtopology拓扑 上层import 限定名引用”的四步模式正是 F´ 官方所有核心子拓扑遵循的统一约定。子拓扑的参数化配置机制配置总览子拓扑在设计中就预留了“可配置性”可以在子拓扑定义层定义参数并在用户实例化子拓扑时覆盖这些参数。这一能力依赖 F´ 构建系统提供的register_fprime_configAPI见 cmake/API.cmake它允许子拓扑开发者提供默认配置文件项目在构建时可选地覆盖这些默认文件。register_fprime_config的底层实现fprime_add_config_build_target见 cmake/API.cmake会执行一次“配置替换”把配置源文件拷贝进构建缓存用拷贝后的版本替代原始源文件参与编译。因此只要覆盖文件的模块名与常量名保持不变子拓扑源码在编译时就会自动使用新值——这正是整个覆盖机制能够生效的原理。从实现看该函数还支持CONFIGURATION_OVERRIDES、BASE_CONFIG将配置链接进全局接口目标、CHOOSES_IMPLEMENTATIONS等指令并以FPRIME_CONFIG_MODULES全局属性登记所有配置模块。三类可配置要素关联文档以 Svc.CdhCore 子拓扑为例归纳出三种典型的可配置要素1. 可配置参数Configurable parametersCdhCoreConfig/CdhCoreConfig.fpp中存放了队列大小、BASE_ID等配置常量子拓扑实例定义直接引用它们例如 CdhCore.fpp 中的instance events: Svc.EventManager base id CdhCoreConfig.BASE_ID 0x001000 # notice the use of BASE_ID覆盖BASE_ID或队列大小会直接影响组件实例的 ID 布局与运行时资源占用。2. 组件实例Component instances组件实例本身也可以是配置的一部分。CdhCore 使用的tlmSend实例并不定义在子拓扑主文件中而是定义在CdhCoreConfig/CdhCoreTlmConfig.fpp中。查看该文件CdhCoreTlmConfig.fpp可见默认实现是Svc.TlmChan文件内还以注释形式保留了切换到Svc.TlmPacketizer的备选实例定义。用户只需在项目中覆盖该配置文件即可替换整个遥测发送实例。3. 可配置 C 代码Configurable C覆盖机制同样作用于 C 源文件与头文件用于定制组件在拓扑中的构造与装配方式。典型例子是 Svc.ComFprime 子拓扑其ComFprimeConfig/CMakeLists.txt见 CMakeLists.txt通过SOURCES/HEADERS引入ComFprimeSubtopologyConfig.cpp/.hpp其中提供了内存分配器ComFprime::Allocation::memAllocator而 ComFprime.fpp 中的configComponents阶段把该分配器传入comQueue.configure(...)从而让项目可以选择自己的内存分配方式。四步配置覆盖流程关联文档给出了在部署中覆盖子拓扑配置的完整步骤以下结合仓库实际文件逐条展开。Step 1创建配置目录在部署目录下为自定义配置模块建一个目录mkdir MyDeployment/MyCdhCoreConfigStep 2创建配置覆盖文件拷贝与原配置文件同名的文件到该目录覆盖依赖“同名 同模块名”机制。例如覆盖CdhCoreConfig.fpp# File: MyDeployment/MyCdhCoreConfig/CdhCoreConfig.fpp module CdhCoreConfig { constant BASE_ID 0x01000000 module QueueSizes { constant cmdDisp 10 constant events 10 constant tlmSend 10 } ... }对照仓库默认值CdhCoreConfig.fpp默认BASE_ID 0x01000000队列大小cmdDisp/events/tlmSend 10、$health 25栈大小统一64 * 1024字节优先级cmdDisp 35、$health 24、events 23、tlmSend 22CPU 亲和性默认Os.TASK_DEFAULT不绑定核心。覆盖时建议对照这些默认值逐项调整避免遗漏。Step 3注册配置模块在配置模块自己的CMakeLists.txt中调用register_fprime_config()第一个参数配置名必须唯一且不能是config# File: MyDeployment/MyCdhCoreConfig/CMakeLists.txt register_fprime_config( MyCdhCoreConfig CONFIGURATION_OVERRIDES ${CMAKE_CURRENT_LIST_DIR}/CdhCoreConfig.fpp EXCLUDE_FROM_ALL INTERFACE )CONFIGURATION_OVERRIDES声明哪些文件属于“配置覆盖”构建系统据此执行源文件替换EXCLUDE_FROM_ALL该模块不作为默认构建目标的一部分只在被依赖时构建INTERFACE声明为纯接口配置不产生编译产物若同时提供SOURCES/AUTOCODER_INPUTS则会构成静态库参见 cmake/API.cmake 中关于库类型的自动判定逻辑。作为对照官方子拓扑的配置模块如 CdhCore/CdhCoreConfig/CMakeLists.txt 同时列出了三个AUTOCODER_INPUTSCdhCoreConfig.fpp、CdhCoreFatalHandlerConfig.fpp、CdhCoreTlmConfig.fpp说明一个配置模块可以包含多个 FPP 配置源文件。Step 4加入部署依赖将配置模块注册为部署拓扑模块的依赖# File: MyDeployment/Top/CMakeLists.txt register_fprime_module( AUTOCODER_INPUTS ${CMAKE_CURRENT_LIST_DIR}/instances.fpp ${CMAKE_CURRENT_LIST_DIR}/topology.fpp SOURCES ${CMAKE_CURRENT_LIST_DIR}/ExampleTopology.cpp DEPENDS MyCdhCoreConfig )关联文档指出ExampleCdhCoreConfigfprime-examples 仓库中的参考实现正是通过这四步把 CdhCore 的遥测发送从TlmChan替换为TlmPacketizer。结合 CdhCoreTlmConfig.fpp 中预留的切换注释可以印证这套流程的实际用途。F´ 核心子拓扑速览F´ 在 Svc/Subtopologies 目录下提供了一批可配置的官方子拓扑其中多数会出现在fprime-util new --deployment生成的默认部署中。目录注册见 Svc/Subtopologies/CMakeLists.txt其中DpCompression因依赖 zlib 而按需加入find_package(ZLIB)失败时会跳过并打印提示。Svc.CdhCore核心命令与数据处理CdhCore 打包了几乎所有 F´ 部署都需要的核心服务命令分发Svc.CommandDispatcher、事件管理Svc.EventManager、健康监控Svc.Health、版本与配置上报Svc.Version、文本日志Svc.PassiveTextLogger、断言转致命错误Svc.AssertFatalAdapter以及两个可配置实例tlmSend遥测发送与fatalHandler致命错误处理。其实例清单与配置钩子详见其设计文档 Svc/Subtopologies/CdhCore/docs/sdd.md。从其拓扑定义CdhCore.fpp可以看到 CdhCore 的完整结构实例cmdDisp、events、$health、version、textLogger、fatalAdapter、tlmSend、fatalHandler内部连接仅有一条故障保护链路events.FatalAnnounce - fatalHandler.FatalReceive暴露的拓扑端口seqCmdBuff/seqCmdStatus命令输入/状态回传、eventsPktSend事件包输出、tlmSendPktSend/tlmSendRun遥测包输出与调度、cmdDispRun/healthRun/eventsRun各组件调度输入。值得注意的细节$health与version的实例定义中内嵌了phase Fpp.ToCpp.Phases.configComponents/startTasks等自动代码生成阶段的 C 片段用于注入健康 ping 表与版本上报逻辑详见 CdhCore.fpp。Svc.ComCcsdsCCSDS 通信栈使用 CCSDS 协议栈实现上下行通信内部组件包括ComQueue、FrameAccumulator配CcsdsTcFrameDetector、TmFramer/SpacePacketFramer、Deframer、路由器等并通过ComStub对外暴露 ByteStream 驱动接口。其配置模块 ComCcsdsConfig.fpp 除常规的BASE_ID/队列/栈/优先级/CPU 亲和性外还包含QueueDepths/QueuePriorities事件、遥测、文件三条队列的深度与优先级事件优先级最高取值 0遥测 2文件 1Aggregator.enablePacketSpanning是否跨传输帧拆装分组包默认false需要 TmFramer 与地面解帧器配合BuffMgr帧累加器大小、通信缓冲大小/数量、缓冲管理器 ID 等。Svc.ComCcsdsSdls带 SDLS 加密/解密的 CCSDS 栈在 CCSDS 通信栈基础上叠加 SDLSSpace Data Link Security加密/解密层配置模块见 Svc/Subtopologies/ComCcsdsSdls/ComCcsdsSdlsConfig。Svc.ComFprime轻量 F´ 协议通信栈使用 F´ 自有轻量协议组帧/解帧。其结构值得细看ComFprime.fpp内部定义了两个端口枚举Ports_ComPacketQueueEVENTS/TELEMETRY与Ports_ComBufferQueueFILE上层拓扑用它们索引comPacketQueueIn/bufferQueueIn数组端口FramingSubtopology子拓扑封装了comQueue、frameAccumulator、commsBufferManager、deframer、framer、fprimeRouter并明确注释导入方需要与实现了Svc.Com接口的组件建立 5 条连接framer 数据出、frameAccumulator 数据返回出、framer 数据返回入、framer 状态入、frameAccumulator 数据入外层Subtopology再import FramingSubtopology并加入comStub形成完整的“F´ 协议 ComStub”组合对外暴露commandOut、fileUplinkOut、comPacketQueueIn、bufferQueueIn、drvReceiveIn、drvSendOut、comQueueRun等端口组件装配大量使用 C phase 片段comQueue.configure()配置三级队列事件/遥测/文件深度与优先级来自 ComFprimeConfig.fpp 的QueueDepths/QueuePrioritiesframeAccumulator.configure()与commsBufferManager.setup()配置缓冲池BuffMgr模块并在tearDownComponents阶段cleanup()。Svc.DataProducts数据产品处理打包数据产品Data Product相关服务dpMgrDpManager服务客户端的产品获取/请求/发送、dpWriterDpWriter写入文件系统、dpCatDpCatalog编目并按优先级下行、dpBufferAccumulatorBufferAccumulator产品缓冲累加、dpBufferManagerBufferManager缓冲分配被动组件。内部接线包括dpMgr.bufferGetOut - dpBufferManager.bufferGetCallee、dpMgr.productSendOut - dpBufferAccumulator.bufferSendInFill、dpWriter.dpWrittenOut[0] - dpCat.addToCat等完整说明见 Svc/Subtopologies/DataProducts/docs/sdd.md。其配置模块 DataProductsConfig.fpp 除实例属性外还定义BufferAccumulator分配器 ID 301、最多缓存 10 个缓冲、BuffMgr产品缓冲存储大小 10000、数量 10、管理器 ID 300与Paths产品目录./DpCat、编目状态文件./DpCat/DpState.dat。Svc.DpCompression数据产品无损压缩对数据产品做无损压缩处理依赖 zlibSvc/Subtopologies/CMakeLists.txt 中按可用性条件注册通过dpWriterProcOut处理钩子接入 DataProducts 管线。Svc.FileHandling文件处理打包文件上行FileUplink、文件下行FileDownlink、板载文件管理FileManager与基于文件系统的参数管理PrmDb。配置模块 FileHandlingConfig.fpp 在实例属性之外还定义Paths.prmDbFile参数数据库存储文件名默认PrmDb.datPaths.sandboxDir文件访问沙箱目录默认/即不限制DownlinkConfig下行冷却时间1000 ms、下行周期1000 ms、文件队列深度10。[!WARNING] 安全提示该子拓扑默认并非安全配置。默认sandboxDir /意味着任何进程可访问的绝对路径都可能被地面指令读写或加载底层Os::SandboxedFile在未配置时是 fail-closed 的而该子拓扑主动将其配置为开放。需要限制文件安全时必须在拓扑启动代码中自动生成的configComponents阶段之后对fileUplink、fileManager、fileDownlink、prmDb分别调用configure(directory)/configureSandbox(directory)收紧目录或覆盖Paths::sandboxDir为单一受限目录。相关细节与../路径穿越拒绝行为见 Svc/Subtopologies/FileHandling/docs/sdd.md。实战接线如何在部署拓扑中组合多个子拓扑关联文档以 CdhCore 为例说明了子拓扑在更大拓扑中的用法。仓库自带的 Ref 参考部署TestDeploymentsProject/Ref/Top/topology.fpp给出了同时组合四个官方子拓扑的完整范例是学习子拓扑接线的第一手素材。1. 实例化子拓扑instance CdhCore.Subtopology instance ComCcsds.Subtopology instance FileHandling.Subtopology instance DataProducts.Subtopology #instance DpCompression.Subtopology2. 声明模式连接pattern connections子拓扑内部的组件通过“限定实例名”参与模式连接command connections instance CdhCore.cmdDisp event connections instance CdhCore.events telemetry connections instance CdhCore.tlmSend text event connections instance CdhCore.textLogger health connections instance CdhCore.$health param connections instance FileHandling.prmDb time connections instance posixTime3. 通过暴露端口接线调度Rate Groups把速率组输出接到子拓扑暴露的调度端口例如CdhCore.Subtopology.tlmSendRun、CdhCore.Subtopology.healthRun、CdhCore.Subtopology.cmdDispRun、CdhCore.Subtopology.eventsRun、FileHandling.Subtopology.fileDownlinkRun、ComCcsds.Subtopology.comQueueRun、DataProducts.Subtopology.dpMgrSchedIn等跨子拓扑数据流ComCcsds ↔ CdhCoreCdhCore.Subtopology.eventsPktSend - ComCcsds.Subtopology.comPacketQueueIn[ComCcsds.Ports_ComPacketQueue.EVENTS] CdhCore.Subtopology.tlmSendPktSend - ComCcsds.Subtopology.comPacketQueueIn[ComCcsds.Ports_ComPacketQueue.TELEMETRY] ComCcsds.Subtopology.commandOut - CdhCore.Subtopology.seqCmdBuff CdhCore.Subtopology.seqCmdStatus - ComCcsds.Subtopology.cmdResponseIn跨子拓扑数据流ComCcsds ↔ FileHandling ↔ DataProducts文件下行包经bufferQueueIn[FILE]进入通信队列文件上行从fileUplinkOut流入fileUplinkBufferSendIn数据产品编目后经dpCatFileOut - FileHandling.Subtopology.fileDownlinkSendFile下行见 topology.fpp。4. 连接外部基础设施ComDrivercomDriver.$recv - ComCcsds.Subtopology.drvReceiveIn ComCcsds.Subtopology.drvSendOut - comDriver.$send comDriver.ready - ComCcsds.Subtopology.drvConnected从以上接线可以看出子拓扑的“端口即契约”设计每个官方子拓扑把需要外部接入的点调度、数据流、驱动、缓冲显式暴露为命名端口上层拓扑只需按名字连接内部组件完全隔离这正是其模块化价值所在。小结子拓扑是 F´ 系统建模中实现“分而治之”的关键设计模式它让组件实例与连接以可复用单元的形式存在通过import与限定名引用集成进部署拓扑配合register_fprime_config构建期配置覆盖机制开发者既可以使用官方子拓扑的默认行为也可以在保持内部接线不变的前提下替换参数、组件实例乃至 C 装配逻辑。F´ 仓库在 Svc/Subtopologies 下提供了覆盖 CDH、CCSDS/SDLS 通信、F´ 协议通信、数据产品、压缩、文件处理等场景的官方子拓扑Ref 参考部署 则是将它们组合使用的完整范例可直接作为新部署的起点。【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址: https://gitcode.com/GitHub_Trending/fpr/fprime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表