ARTICLE DETAIL

资讯详情

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

F´ 遥测分组组件 Svc::TlmPacketizer 深入解析:基于数据包的遥测缓存、哈希查找与双缓冲发送机制

F´ 遥测分组组件 Svc::TlmPacketizer 深入解析:基于数据包的遥测缓存、哈希查找与双缓冲发送机制 嵌入式系统编程【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址https://gitcode.com/gh_mirrors/fpri/fprime点击查看免费下载导读Svc::TlmPacketizer是 F´F Prime飞行软件与嵌入式系统框架中负责将遥测通道telemetry channel按预定义分组打包的组件它接收系统中其他组件写入的通道更新以序列化形式缓存在内部缓冲区并在调度周期触发时按数据包packet整体输出。本文以官方组件设计文档Svc/TlmPacketizer/docs/sdd.md为主体结合 FPP 组件定义、实现源码 与 单元测试完整讲解其端口接口、双缓冲发送流程、哈希表缓存算法、配置调优方法以及命令/事件接口帮助你掌握在 F´ 部署中配置与使用该组件并理解其相对Svc::TlmChan的取舍。1. 组件定位与 TlmChan 的关键差异sdd.md明确指出Svc::TlmPacketizer用于存储其他组件写入的遥测值值以序列化形式保存。它与Svc::TlmChan的本质区别在于存储与输出模型TlmChan通道更新随到随发streaming每个通道变化都会独立产生遥测更新输出TlmPacketizer通道值被写入预定义的数据包只有当日志周期Run()端口被调用到来时才把所有定义的数据包整体发送到输出端口。该组件正是为更紧凑的数据包格式场景设计的用于替代 TlmChan。其代价是无论通道是否被更新过所有定义在包内的通道都会随包被推送出去不过通过PACKET_UPDATE_MODE配置可以在仅更新时发送与始终发送之间选择详见第 5 节。遥测分组在 F´ 中的典型链路是组件产生遥测 → 基类生成的代码将类型化通道值序列化 → 通过TlmRecv端口送入TlmPacketizer→Run周期触发 →PktSend输出整包数据。2. 需求定义Requirementssdd.md第 2 节给出了该组件的顶层需求及验证方法其中 TPK-001 至 TPK-005 均由单元测试验证需求描述验证方法TPK-001组件应提供提交遥测数据的接口单元测试TPK-002组件应为每个数据包打上时间标签单元测试TPK-003组件应保留每个通道的最新值单元测试TPK-004组件应唯一标识每个数据包单元测试TPK-005调度调用到来时组件应写出所有数据包单元测试在源码层面TPK-001 对应同步输入端口TlmRecvFw::Tlm类型TPK-002 对应发送时序列化Fw::Time时间标签TPK-004 对应数据包头的FwTlmPacketizeIdType包 IDTPK-005 对应异步输入端口RunSvc::Sched类型驱动的发送逻辑。3. 架构设计3.1 组件图与端口sdd.md给出的组件框图图片源文件Svc::TlmPacketizer 组件框图组件主要端口依据 sdd 端口表并结合 TlmPacketizer.fpp 的完整定义端口数据类型名称方向类型用途Svc::SchedRun输入异步执行一个周期写出更新的遥测数据包Fw::TlmTlmRecv输入同步更新一个遥测通道Fw::ComPktSend输出—写出一组含最新遥测的数据包Svc::PingpingIn / pingOut输入/输出异步组件健康检查收到 ping 原样回传 key命令三端口cmdIn / cmdRegOut / cmdResponseOut——命令接收、注册与应答事件/遥测/时间eventOut / tlmOut / timeGetOut 等——事件上报、自身遥测输出、时间获取Fw::Tlm端口在 Fw/Tlm/Tlm.fpp 中定义Fw::Com端口及通信包类型见 Fw/Com/Com.fpp 与 Fw/Com/ComPacket.hpp。3.2 FPP 定义中的命令、事件与遥测TlmPacketizer.fpp 中组件被声明为active component除了端口外还定义了命令SET_LEVEL(level: U32)opcode 0设置遥测发送级别SEND_PKT(id: U32)opcode 1强制发送某个数据包。事件5 个NoChanwarning low遥测 ID 不属于任何数据包格式Telemetry ID 0x{x} not packetizedLevelSetactivity high遥测发送级别已设置MaxLevelExceedwarning low请求级别高于最大包级别PacketSentactivity low数据包被手动发送PacketNotFoundwarning low找不到要发送的数据包。自身遥测SendLevel: U32id 0上报当前发送级别。完整的命令/事件/遥测字典含 ID 与参数类型见组件字典 Svc/TlmPacketizer/docs/TlmPacketizer.md例如TPK_SET_LEVEL (0x0)、TPK_SEND_PKT (0x1)、事件TPK_NoChan~TPK_PacketNotFoundid 0~4。4. 工作原理4.1 通道写入TlmRecv 处理流程其他组件产生的遥测值由基类生成代码序列化后调用TlmRecv_handler见 TlmPacketizer.cpp流程为用通道 ID 计算哈希值在哈希表槽中查找通道条目若条目不存在说明该通道不属于任何数据包调用missingChannel()只对前TLMPACKETIZER_MAX_MISSING_TLM_CHECK个缺失通道各发一次NoChan告警事件去重机制若条目被标记为ignored来自 ignore 列表直接丢弃不发告警遍历该通道在所有数据包中的偏移packetOffset[pkt]对每个包含该通道的数据包加锁 → 标记updated→ 记录最新时间标签latestTime→ 将序列化值memcpy到对应偏移处 → 解锁。一个通道可以出现在多个数据包中这是通过TlmEntry::packetOffset[MAX_PACKETIZER_PACKETS]数组实现的——每个数据包各有一个偏移值为-1表示该包不含此通道。传入的时间标签被剥离通道自身时间标签最终会成为整帧发送时的时间标签对应需求 TPK-002。4.2 周期发送Run 与双缓冲机制sdd.md第 3.2 节描述了双缓冲设计当Run()被调用时发送过程锁定包写入把所有数据包从填充缓冲区m_fillBuffers复制到发送缓冲区m_sendBuffers复制完成后解锁再为目标包写入当前时间标签并通过PktSend端口发出。实现细节TlmPacketizer.cpp若PktSend输出端口未连接直接返回加锁复制期间TlmRecv的通道写入被阻塞避免边写边发的竞态复制条件updated true且level m_startLevel或requested true。即只有已更新的包且包级别不大于当前发送级别或被手动请求才会被复制发送复制完成后在包头的固定偏移处描述符 包 ID 之后序列化latestTime随后PktSend_out(0, buffer, 0)发出PACKET_UPDATE_MODE决定updated标志的清除策略见第 5.2 节。4.3 数据包格式从 setPacketList 实现 可以看出每个数据包缓冲区的布局为FwPacketDescriptorType包描述符固定为 FW_PACKET_PACKETIZED_TLM FwTlmPacketizeIdType包 ID固定不变初始化时写入 Fw::Time时间标签发送前由 Run 写入 各通道的序列化值按表顺序依次排列初始化时校验描述符 时间标签大小 包ID大小 各通道 size之和不得超过FW_COM_BUFFER_MAX_SIZE否则触发断言。这一点在单元测试sendPacketsTest中有直接验证——测试构造的期望缓冲依次序列化为FW_PACKET_PACKETIZED_TLM → 包ID(4) → m_testTime → U32(20) → U16(15) → U8(14)见 Tester.cpp。5. 配置与哈希算法5.1 配置文件与参数说明sdd.md第 3.5 节提到的配置项位于仓库 config/TlmPacketizerCfg.hpp工程配置目录下源码注释中引用的TlmPacketizerImplCfg.hpp即对应此文件各参数含义与默认值配置项默认值含义与调优建议MAX_PACKETIZER_PACKETS200系统可定义的最大数据包数量TLMPACKETIZER_NUM_TLM_HASH_SLOTS15哈希表槽数。注释建议设为产生遥测的组件数量的约两倍以获得较好的分布TLMPACKETIZER_HASH_MOD_VALUE99哈希函数取模值。注释建议略低于通道 ID 的间隔ID gaps使条目均匀散布TLMPACKETIZER_HASH_BUCKETS1000可分配给哈希槽的桶数。必须大于等于系统中的遥测通道总数否则FW_ASSERT会触发TLMPACKETIZER_MAX_MISSING_TLM_CHECK25缺失未分组通道告警的最大去重数量系统通道总数可用 sdd 给出的命令确定在部署目录deployment directory执行make comp_report_gen。随后通过调整TLMPACKETIZER_NUM_TLM_HASH_SLOTS与TLMPACKETIZER_HASH_MOD_VALUE在槽内存占用与桶到槽的分布之间取得平衡。5.2 哈希函数与发送模式哈希函数实现TlmPacketizer.cpp为双重取模NATIVE_UINT_TYPE TlmPacketizer::doHash(FwChanIdType id) { return (id % TLMPACKETIZER_HASH_MOD_VALUE) % TLMPACKETIZER_NUM_TLM_HASH_SLOTS; }槽内用链表挂桶TlmEntry::next查找与插入见findBucket()。由于哈希槽数量远小于通道数冲突通过桶链表解决因此TLMPACKETIZER_HASH_BUCKETS必须覆盖全部通道。数据包更新模式由枚举PacketUpdateMode配置PACKET_UPDATE_MODE默认PACKET_UPDATE_ON_CHANGEPACKET_UPDATE_ALWAYS无论通道是否变化都发送原文档所述的全量推送行为PACKET_UPDATE_ON_CHANGE仅当包内任一通道被更新时才发送默认值发送后清除updatedPACKET_UPDATE_AFTER_FIRST_CHANGE从首次更新后开始持续发送不清除updated标志。对应逻辑见 Run_handlerPACKET_UPDATE_ON_CHANGE时复制后清updatedPACKET_UPDATE_ALWAYS时即使未更新也复制并置updated true。5.3 分组表配置setPacketList数据包定义通过公开方法setPacketList()传入声明数据结构定义在 TlmPacketizerTypes.hppTlmPacketizerChannelEntry { id, size }通道 ID 与其序列化字节大小TlmPacketizerPacket { list, id, level, numEntries }一个数据包含通道数组指针、包 ID、发送级别level与通道数TlmPacketizerPacketList { list[], numEntries }整组分包表。调用形式为setPacketList(packetList, ignoreList, startLevel)其中ignoreList是忽略通道列表出现在列表中但不需要分组、也不触发缺失告警的通道例如测试中的{25, 0}, {50, 0}见 Tester.cppstartLevel为初始发送级别。级别level机制用于按需分层发送只有level m_startLevel的包才会随周期发送可通过SET_LEVEL命令动态调整。setPacketList会一次性完成校验包数量 ≤MAX_PACKETIZER_PACKETS、校验每包长度 ≤FW_COM_BUFFER_MAX_SIZE、填充哈希表、序列化固定包头描述符 包 ID、记录每包 ID/级别并计算m_maxLevel。调用前需保证m_configured未配置时TlmRecv_handler/Run_handler均会断言失败。6. 命令与事件详解6.1 SET_LEVEL发送级别设置实现见 SET_LEVEL_cmdHandler更新m_startLevel若level m_maxLevel发出MaxLevelExceed告警事件warning low通过tlmWrite_SendLevel(level)上报自身遥测SendLevel发出LevelSet事件activity high命令应答 OK。6.2 SEND_PKT强制发送数据包实现见 SEND_PKT_cmdHandler按包 ID 在m_fillBuffers中查找找到后加锁设置updated true、以当前系统时间getTime()作为latestTime、置requested true发PacketSent事件并应答 OK未找到则发PacketNotFound告警事件并以Fw::CmdResponse::VALIDATION_ERROR应答。该命令使操作者可以在非调度周期强制下发某个包且被请求的包不受level m_startLevel条件限制复制条件中的or this-m_fillBuffers[pkt].requested分支。7. 单元测试验证组件测试位于 Svc/TlmPacketizer/test/ut/测试入口 main.cpp 注册的用例与 sdd 需求一一对应测试用例覆盖内容Initialization100.1.1initTest配置分组表后组件正常初始化PushTlm100.1.2pushTlmTest通过invoke_to_TlmRecv推送多个通道值SendPackets100.1.2sendPacketsTest调用invoke_to_Run后断言PktSend输出 2 个包并逐字节比对包内容UpdatePacketsTest100.1.4updatePacketsTest更新通道后重新发送PingTest100.1.5pingTestpingIn原样回传 keyIgnoredChannelTest100.1.6ignoreTest忽略列表中的通道被丢弃且不告警SendPacketTest100.1.7sendManualPacketTestSEND_PKT手动发送NonPacketizedChannelTest100.2.1nonPacketizedChannelTest未分组通道触发NoChan告警测试表构造Tester.cpp给出了一个可直接复用的分组示例packet1 {通道10(4B), 通道100(2B), 通道333(1B)}packet2 {通道10(4B), 通道13(8B), 通道250(2B), 通道22(1B)}其中通道 10 同时出现在两个包中直观演示了多包归属能力。8. 在部署中的接入方式sdd.md说明该组件设计用于替换 TlmChan。在部署拓扑中需完成定义分组表TlmPacketizerPacketList并调用setPacketList(list, ignore, startLevel)参考 Ref/Top/RefTopology.cpp 中被注释的调用示例将调度端口如RateGroupDriver/周期任务连接到Run端口将组件遥测端口连接到TlmChan/TlmPacketizer上游的遥测源将PktSend连接到下行链路Framer/ComQueue 等按第 5 节调整config/TlmPacketizerCfg.hpp的哈希参数与发送模式通过make comp_report_gen确认通道总数不超过TLMPACKETIZER_HASH_BUCKETS。注意本组件是active component异步队列组件init()时需要传入队列深度如测试中的QUEUE_DEPTH 10见 Tester.cpp。9. 变更记录sdd.md记录的变更日志2017-12-14 初始版本Initial version。参考文档组件设计文档Svc/TlmPacketizer/docs/sdd.md组件字典Svc/TlmPacketizer/docs/TlmPacketizer.md组件实现Svc/TlmPacketizer/TlmPacketizer.cpp / TlmPacketizer.hpp配置头文件config/TlmPacketizerCfg.hpp数据结构Svc/TlmPacketizer/TlmPacketizerTypes.hpp单元测试Svc/TlmPacketizer/test/ut/Tester.cpp / main.cpp赞分享嵌入式系统编程【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址https://gitcode.com/gh_mirrors/fpri/fprime点击查看免费下载相关推荐F´ 遥测打包组件 Svc::TlmPacketizer 深入解析基于哈希槽的分组遥测架构与调优指南F´ 遥测打包组件 Svc::TlmPacketizer 深入解析基于哈希槽的分组遥测架构与调优指南 F´F Prime飞行软件与嵌入式系统框架提供了两种嵌入式系统编程F´ 遥测通道存储组件 Svc::TlmChan 深度解析哈希表设计、双缓冲机制与配置调优F´ 遥测通道存储组件 Svc::TlmChan 深度解析哈希表设计、双缓冲机制与配置调优 Svc::TlmChan 是 F´F Prime飞行软件与嵌入嵌入式系统编程F´ 飞行软件框架中的遥测存储组件 Svc::TlmChan双缓冲哈希表、处理上限与种子化哈希机制解析F´ 飞行软件框架中的遥测存储组件 Svc::TlmChan双缓冲哈希表、处理上限与种子化哈希机制解析 Svc::TlmChan 是 F´F Prime飞嵌入式系统编程上一篇Crane源码解析深入理解Nix库的增量缓存实现原理下一篇Voron-Tap常见问题解答从安装到调试的10个关键问题解决方法创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表