F´ 中的 Fw::FilePacketCFDP 风格的文件分包协议与 C 实现解析【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址: https://gitcode.com/gh_mirrors/fp/fprime导读Fw::FilePacket 是 F´F Prime飞行软件框架中用于表示“ISF 文件分组包file packet”的核心类型它定义了将任意文件切分成可在遥测/通信链路上传输的数据包的标准二进制格式。本文以 Fw/FilePacket/docs/sdd.md 设计文档为主体结合 FilePacket.hpp 及各实现文件完整讲解 START / DATA / END / CANCEL 四种包的字节布局、序列化与反序列化原理、CFDP 校验和算法并给出基于 Svc/FileDownlink 的真实调用场景帮助你直接掌握该格式的构造与解析方法。1 设计背景与 CFDP PDU 同源的包格式Fw::FilePacket 的格式设计参考了 CCSDS 文件传输协议CFDP第 5 节中定义的协议数据单元PDU结构因此它与航天工程中广泛使用的 CFDP 具有相似的骨架每个包以包类型 序号构成的头部开始头部之后是随类型而变的载荷data整个文件通过一串带序号的包顺序传输接收方可以据此重组文件并校验完整性。在 F´ 中这个类型被Svc::FileDownlink文件下传组件用来把本地文件分片发送也可被对应的上行/地面侧解析。其核心头文件为 Fw/FilePacket/FilePacket.hpp实现在 Fw/FilePacket 目录下的各.cpp文件中。2 总体结构一个包包含什么从 sdd.md 与 FilePacket.hpp 可以看出每个文件包包含以下数据字段长度说明包类型Packet type1 字节START(0)、DATA(1)、END(2)、CANCEL(3)另有内部占位T_NONE(255)序号Sequence index4 字节无符号整数每个文件从 0 开始后续每包递增 1包数据Packet data可变具体格式取决于包类型在代码层面FilePacket被实现为一个联合union内部同时包含Header、StartPacket、DataPacket、EndPacket、CancelPacket五种结构通过m_header.m_type区分当前“视图”这与 C 中“判别式联合tagged union”的经典做法一致。2.1 头部Header的序列化头部总是最先出现在每个包中其缓冲区大小固定为 5 字节sizeof(U8) sizeof(U32)见 FilePacket.hpp 中HEADERSIZE与 Header.cpp 的bufferSize()。序列化时先写类型字节强制转成U8再写 4 字节序号Header.cpp反序列化时依次读回并用static_castType还原类型Header.cpp。这一对toSerialBuffer/fromSerialBuffer是所有包类型共用的基础能力。3 四种包类型的载荷格式3.1 START 包类型 0声明文件传输开始START 包的包类型为START序号恒为0用于宣告一个新文件传输的开始。其载荷依次为字段长度说明文件大小File size4 字节整个文件的字节数U32源路径长度1 字节源路径source path的字节数U8源路径可变源端文件路径目的路径长度1 字节目的路径destination path的字节数U8目的路径可变目标端文件路径对应实现见 StartPacket.cpp 的initialize头部以T_START与序号 0 初始化随后保存文件大小并分别初始化源、目的两个路径。路径的序列化在 PathName.cpp 中完成initialize用StringUtils::string_length(value, MAX_LENGTH)截取路径长度MAX_LENGTH 255见 FilePacket.hpp写入m_length1 字节与指向路径的指针序列化时先写 1 字节长度、再写入对应字节数的路径内容反序列化时同样先读长度再把m_value指向缓冲区中的字符串地址PathName.cpp。因此路径长度上限为 255 字节。3.2 DATA 包类型 1传输文件数据分片DATA 包承载文件的实际内容分片载荷为字段长度说明字节偏移Byte offset4 字节本包数据在整个文件中的起始字节位置U32数据长度Data size2 字节本包携带的文件数据字节数U16文件数据File data可变实际数据内容实现见 DataPacket.cpp 的initialize其签名接收sequenceIndex、byteOffset、dataSize与指向数据的指针。序列化顺序为头部 → 4 字节偏移 → 2 字节数据长度 → 原始数据DataPacket.cpp。数据指针在反序列化时被直接指向输入缓冲区内的地址DataPacket.cpp因此反序列化得到的 DATA 包不拷贝数据其生命周期与源缓冲区绑定使用时需注意。3.3 END 包类型 2结束并携带校验和END 包宣告文件传输结束其载荷只有一个字段字段长度说明32 位哈希值Checksum4 字节按 CFDP 协议规则由文件数据计算得到的 32 位校验和实现见 EndPacket.cppinitialize(sequenceIndex, checksum)将传入的CFDP::Checksum对象的值getValue()保存为m_checksumValue序列化/反序列化时直接读写该 4 字节值EndPacket.cpp。接收方可用它验证整个文件在传输过程中是否发生损坏。3.4 CANCEL 包类型 3取消传输CANCEL 包用于中止传输不携带任何数据仅由头部构成类型CANCEL 序号。实现见 CancelPacket.cppbufferSize()直接返回头部大小反序列化时要求缓冲区剩余字节数为 0否则返回FW_DESERIALIZE_SIZE_MISMATCHCancelPacket.cpp保证格式的严格性。4 统一入口FilePacket 的 toBuffer / fromBufferFilePacket对外提供两个统一接口FilePacket.cppfromBuffer(const Buffer buffer)将一段原始字节解析为文件包。内部先构造SerialBuffer并fill()然后读头部再依据m_type分派给对应的StartPacket::fromSerialBuffer/DataPacket::fromSerialBuffer/EndPacket::fromSerialBuffer/CancelPacket::fromSerialBuffer若读到T_NONE返回FW_DESERIALIZE_TYPE_MISMATCH未知类型触发FW_ASSERT(0)FilePacket.cpp。toBuffer(Buffer buffer)把当前包写入字节缓冲区同样按类型分派。bufferSize()按类型返回所需的缓冲区大小T_NONE时返回 0。asStartPacket()/asDataPacket()/asEndPacket()/asCancelPacket()以对应类型视图读取包内容内部均先断言类型匹配FilePacket.cpp。fromStartPacket()/fromDataPacket()/fromEndPacket()/fromCancelPacket()从具体包对象构造FilePacketFilePacket.cpp。因此使用方式非常直观发送方构造具体包 →toBuffer编码接收方拿到字节 →fromBuffer解码 →asXxxPacket读取字段。5 END 包背后的 CFDP 校验和算法END 包携带的 32 位校验和由 CFDP/Checksum/Checksum.hpp 与 CFDP/Checksum/Checksum.cpp 实现。其核心是update(data, offset, length)把文件视为连续的 4 字节“字word”序列逐字累加到m_value32 位无符号溢出累加具体分三阶段处理若offset % 4 ! 0先按非对齐方式累加第一个不满 4 字节的“字”addWordUnaligned中间对齐部分以 4 字节为单位直接累加addWordAligned末尾不足 4 字节的部分再以非对齐方式收尾。addByteAtOffset将字节按其在 4 字节字内的位置左移8*(3-offset)位后加到校验和上Checksum.cpp。注意update的offset是相对文件起始的字节偏移——这与 DATA 包中的byteOffset语义一致发送方应按文件全局偏移逐片更新校验和接收方才能在 END 包中做整体比对。Checksum还提供构造默认 0 / 指定值 / 拷贝、getValue()、operator/operator!便于在测试中直接比较校验和值Checksum.hpp。6 在 Svc::FileDownlink 中的实际用法Fw::FilePacket在仓库中最重要的消费者是文件下传组件Svc::FileDownlink。在 Svc/FileDownlink/FileDownlink.cpp 中可以找到两处关键调用发送数据分片时构造Fw::FilePacket::DataPacket并调用filePacket.fromDataPacket(dataPacket)生成可发送的包FileDownlink.cpp发送起始声明时构造StartPacket后调用filePacket.fromStartPacket(startPacket)FileDownlink.cpp。即业务组件负责构造携带具体字段的包对象再由FilePacket统一完成编码与类型管理这正好呼应了第 4 节介绍的“构造 → fromXxxPacket → toBuffer”流程。若需了解完整的分片、调度与校验逻辑可继续阅读 Svc/FileDownlink/docs/sdd.md 及测试 Svc/FileDownlink/test/ut/FileDownlinkTester.cpp。7 测试验证四种包的往返一致性仓库在 Fw/FilePacket/test/ut/FilePacketMain.cpp 中提供了覆盖四种包类型的 GTest 用例均遵循“构造 → 序列化 → 反序列化 → 逐字段比较”的往返测试模式TEST(FilePacket, Header)以类型T_DATA、序号 10 构造头部往返后断言一致FilePacketMain.cppTEST(FilePacket, StartPacket)文件大小 10、源路径source、目的路径destFilePacketMain.cppTEST(FilePacket, DataPacket)序号 3、字节偏移 42、数据长度 10FilePacketMain.cppTEST(FilePacket, EndPacket)序号 15、校验和值 42FilePacketMain.cppTEST(FilePacket, CancelPacket)序号 10验证无载荷包可正确往返FilePacketMain.cpp。比较断言由 GTest 辅助命名空间提供Fw::GTest::FilePackets定义了各包类型的compare函数见 Fw/FilePacket/GTest/FilePackets.hpp 及其实现如 GTest/StartPacket.cpp通过ASSERT_EQ逐一比对头部、文件大小、路径、偏移、数据长度与校验和等字段。若要运行该模块测试可在构建目录中启用对应的 CMake 目标模块定义见 Fw/FilePacket/CMakeLists.txt。8 小结Fw::FilePacket是 F´ 内文件传输的统一分组格式格式骨架取自 CFDP PDUsdd.md每个包由 5 字节头部1 字节类型 4 字节序号与类型相关载荷组成四种类型分别为 START文件大小 双路径、DATA偏移 长度 数据、ENDCFDP 32 位校验和、CANCEL无载荷路径采用“1 字节长度 内容”的自描述编码最长 255 字节编解码入口统一为fromBuffer/toBuffer配合asXxxPacket/fromXxxPacket使用DATA 包反序列化不拷贝数据需注意缓冲区生命周期END 包校验和由CFDP::Checksum::update按 4 字节字累加得到偏移语义与 DATA 包byteOffset一致仓库内通过Svc::FileDownlink实际使用该类型并有完整的 GTest 往返测试保证格式的稳定性。如需进一步掌握文件传输的端到端流程如何分片、如何驱动发送、如何重组与校验可继续阅读 Svc/FileDownlink/docs/sdd.md 与 Svc/FileUplink 相关文档。【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址: https://gitcode.com/gh_mirrors/fp/fprime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
