news 2026/9/25 10:59:20

F´(F Prime)Fw::Time 端口深度解析:飞行软件时间戳的传递、序列化与比较机制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
F´(F Prime)Fw::Time 端口深度解析:飞行软件时间戳的传递、序列化与比较机制
  • 嵌入式
  • 系统编程

【免费下载链接】fprime

F´ - A flight software and embedded systems framework

项目地址:https://gitcode.com/gh_mirrors/fpri/fprime
点击查看免费下载

导读:Fw::Time是 F´(F Prime)飞行软件与嵌入式系统框架中用于在系统内传递时间戳(time stamp)的标准端口,遥测(telemetry)、事件(events)以及其他需要时间信息的组件都依赖它。本文将围绕 Fw/Time/docs/sdd.md 的设计文档,结合仓库内端口定义、Fw::Time数据类型实现、配置项与单元测试,完整解析该端口的作用、Fw::Time类的内部结构与运算语义,以及它如何通过序列化在组件间流转。读完本文,你将掌握Fw::Time端口的定义方式、时间基准(Time Base)与时间上下文(Time Context)的配置含义、时间戳序列化格式,以及时间比较/加减运算的边界行为,能够在自己的 F´ 组件中正确使用或扩展这一机制。

1. 端口定位与核心职责

根据 Fw/Time/docs/sdd.md 的说明:

TheFw::Timeport is used to pass time stamps around the system, either for telemetry and events or other uses.

Fw::Time端口用于在系统各处传递时间戳——无论是遥测数据、事件(EVENT)报文,还是其他需要时间信息的用途。它是 F´ 中时间信息流通的标准管道:负责提供时间的组件(如Svc::Time)通过该端口对外输出当前时间,遥测/事件采集链路则通过该端口获取时间戳并打入下行报文。

1.1 FPP 端口定义

端口在 FPP 语言中的定义位于 Fw/Time/Time.fpp:

module Fw { type Time @ Time port port Time( ref $time: Fw.Time @< The U32 cmd argument ) }

关键点:

  • 端口名与数据类型同名,均为Time,归属Fw模块;
  • 端口通过引用(ref)传递一个Fw.Time类型的参数$time,即调用方传入一个Fw::Time对象引用,由被调用方填充/读取;
  • 该端口没有返回值(无return子句),时间值完全依靠引用参数带出,这与后续Svc::Time组件中timeGetPort的同步调用模式一致。

2. 端口设计上下文(Design)

2.1 端口图

设计文档给出的端口框图如上图所示(图片源文件为 Fw/Time/docs/img/TimeBDD.jpg),其含义可以解读为:

  • 左侧<<PortType>> Time(命名空间Fw)描述了端口类型Time,其关联操作return() : Time表明该端口最终返回一个Fw::Time类型的值;
  • 右侧<<DataType>> Time是端口使用的数据类型,明确标注其来源头文件为Fw/Time/Time.hpp、命名空间为Fw,与左侧端口引用的Time类型完全对应。

2.2 端口使用的可序列化类型:Fw::Time

设计文档指出:

Fw::Timeis a class that stores the time base (project specific), seconds and microseconds of the time stamp.

即Fw::Time是一个类,存储了时间戳的时间基准(time base,项目相关)、秒与微秒三部分信息。在仓库实现中,Fw/Time/Time.hpp 进一步表明它继承自Fw::Serializable,是一个标准的可序列化对象,内部还额外维护了一个时间上下文(time context)字段,用于记录如重启计数、节点编号等用户自定义信息。

3. Fw::Time 数据类型源码级剖析

3.1 内部成员与内存布局

Fw/Time/Time.hpp 定义了其序列化后的尺寸常量:

enum { SERIALIZED_SIZE = sizeof(FwTimeBaseStoreType) + sizeof(FwTimeContextStoreType) + sizeof(U32) + sizeof(U32) };

四个成员分别为(见 Fw/Time/Time.hpp):

成员类型含义
m_secondsU32秒部分
m_usecondsU32微秒部分
m_timeBaseTimeBase(枚举)时间基准,由系统/项目定义
m_timeContextFwTimeContextStoreType(U8)用户可设值,如重启计数、节点号等

在默认配置(FW_USE_TIME_BASE = 1、FW_USE_TIME_CONTEXT = 1)下,时间戳序列化占用2 + 1 + 4 + 4 = 11字节;若在 config/FpConfig.hpp 中关闭时间基准或时间上下文特性,序列化体积可相应缩减。

3.2 时间基准与存储类型定义(config/FpConfig.hpp)

时间基准枚举与配套存储类型定义在 config/FpConfig.hpp:

enum TimeBase { TB_NONE, //!< No time base has been established TB_PROC_TIME, //!< Indicates time is processor cycle time. Not tied to external time TB_WORKSTATION_TIME, //!< Time as reported on workstation where software is running. For testing. TB_DONT_CARE = 0xFFFF //!< Don't care value for sequences. If FwTimeBaseStoreType is changed, value should be changed }; #define FW_CONTEXT_DONT_CARE 0xFF //!< Don't care value for time contexts in sequences typedef U16 FwTimeBaseStoreType; typedef U8 FwTimeContextStoreType;

需要理解的关键语义:

  • TB_NONE:尚未建立时间基准,Fw::Time的默认构造状态即为此值(Time()构造时将m_timeBase置为TB_NONE);
  • TB_PROC_TIME:处理器周期时间,不绑定外部时钟,适合嵌入式环境下的相对计时;
  • TB_WORKSTATION_TIME:软件运行所在工作站的系统时间,主要用于主机/桌面测试场景;
  • TB_DONT_CARE与FW_CONTEXT_DONT_CARE:序列(sequence)等场景中表示"不关心"的占位值,用于指令序列文件中的时间匹配;
  • FwTimeBaseStoreType(U16)与FwTimeContextStoreType(U8)是时间基准与上下文的存储类型,保证其在序列化与跨平台传输时尺寸确定。

此外 config/FpConfig.hpp 提供了两个特性开关,直接影响Fw::Time的序列化行为与比较逻辑:

#ifndef FW_USE_TIME_BASE #define FW_USE_TIME_BASE 1 //!< Whether or not to use the time base #endif #ifndef FW_USE_TIME_CONTEXT #define FW_USE_TIME_CONTEXT 1 //!< Whether or not to serialize the time context #endif

从 Fw/Time/Time.cpp 的实现可以看到:当FW_USE_TIME_BASE关闭时,反序列化会将m_timeBase强制置为TB_NONE;当FW_USE_TIME_CONTEXT关闭时,上下文被强制置 0——这说明这两个特性开关既控制序列化字节流,也决定了对端解析后的默认值。

3.3 构造与赋值 API

Fw/Time/Time.hpp 提供了多组构造与设置方法,覆盖从"仅秒/微秒"到"基准+上下文+秒/微秒"的完整组合:

Time(); // 默认构造:0 秒、0 微秒、TB_NONE、上下文 0 Time(U32 seconds, U32 useconds); // 仅秒与微秒(基准为 TB_NONE) Time(TimeBase timeBase, U32 seconds, U32 useconds); Time(TimeBase timeBase, FwTimeContextStoreType context, U32 seconds, U32 useconds); void set(U32 seconds, U32 useconds); // 覆盖设置,保留原基准与上下文 void set(TimeBase timeBase, U32 seconds, U32 useconds); void set(TimeBase timeBase, FwTimeContextStoreType context, U32 seconds, U32 useconds);

配套的读取接口为getSeconds()、getUSeconds()、getTimeBase()、getContext()。set(U32, U32)这类"只传秒/微秒"的重载会保留对象已有的基准与上下文,而不是重置为默认值,这一点在复用时间对象时应特别注意。

3.4 序列化与反序列化

Fw::Time作为Fw::Serializable的派生类,实现了serialize/deserialize(见 Fw/Time/Time.cpp),其字节流顺序为:

  1. (可选,FW_USE_TIME_BASE)时间基准FwTimeBaseStoreType;
  2. (可选,FW_USE_TIME_CONTEXT)时间上下文FwTimeContextStoreType;
  3. 秒U32;
  4. 微秒U32。

每一步都检查SerializeStatus,任一环节失败即立即返回错误状态。正是因为实现了这套标准序列化接口,Fw::Time才能被嵌入遥测通道(Tlm)、事件(Log)等报文缓冲区,随下行数据一起传回地面。

3.5 比较运算:基准不同则不可比

Fw::Time实现了==、!=、>、<、>=、<=全部比较运算符,底层统一委托给静态方法Time::compare(Fw/Time/Time.cpp):

  • 比较结果类型为Time::Comparison枚举:LT = -1、EQ = 0、GT = 1、INCOMPARABLE = 2;
  • 在FW_USE_TIME_BASE开启时,若两个时间基准不同,返回INCOMPARABLE;
  • 在FW_USE_TIME_CONTEXT开启时,若上下文不同,同样返回INCOMPARABLE;
  • 仅当基准与上下文一致时,才按"先比秒、后比微秒"的字典序给出LT/EQ/GT。

因此,在业务代码中跨基准(例如把TB_PROC_TIME与TB_WORKSTATION_TIME的时间戳直接比较)会得到"不可比"结论,这是设计上防止语义错乱时间比较的刻意约束。

3.6 时间算术:add / sub / add(seconds, useconds)

Fw/Time/Time.cpp 提供了三种时间运算:

  • static Time add(const Time& a, const Time& b):两个时间相加,要求基准与上下文相同(否则触发FW_ASSERT断言);微秒部分相加后若>= 1000000则向秒进位(并断言结果微秒uSeconds < 1999999,防止溢出);
  • static Time sub(const Time& minuend, const Time& subtrahend):被减数减减数,断言被减数不小于减数;若微秒不够减,则从秒借 1(等价于微秒 +1000000 再减),正确实现跨秒借位;
  • void add(U32 seconds, U32 useconds):就地增加秒与微秒,同样处理微秒进位,并断言m_useconds < 1999999。

这些运算在测量任务执行耗时、计算时间差等场景中非常实用,其借位/进位逻辑已被单元测试覆盖(见第 5 节)。

3.7 零时间与全局常量

  • 静态工厂方法static Time zero(TimeBase timeBase = TB_NONE)返回"基准可指定、秒/微秒/上下文全为 0"的时间对象;
  • 全局常量extern const Time ZERO_TIME;(定义于 Fw/Time/Time.cpp)是默认构造的零时间,Fw::ZERO_TIME可直接用于"时间是否已初始化"的判断——例如 Fw/Time/test/ut/TimeTest.cpp 中验证了非默认构造的时间与ZERO_TIME不相等、默认构造的时间与ZERO_TIME相等。

4. 在系统中的应用:Svc::Time 与遥测/事件链路

Fw::Time端口在实际部署中由时间服务组件对外提供。仓库中的 Svc/Time/Time.fpp 给出了标准用法:

passive component Time { ... sync input port timeGetPort: Fw.Time ... }

Svc::Time组件暴露名为timeGetPort的同步输入端口,端口类型正是Fw.Time。外部组件(如遥测通道Svc::TlmChan、事件记录器Svc::ActiveLogger、命令调度器等)在生成遥测或事件报文时,通过该端口同步获取当前时间戳并填入报文。整套链路可以概括为:

  1. 时间源(Svc::Time及其平台实现,如Svc::LinuxTime)维护并持续更新时间;
  2. 需要时间戳的组件通过Fw::Time端口同步调用timeGetPort,传入Fw::Time引用参数;
  3. 时间服务填充引用对象的秒/微秒/基准/上下文后返回;
  4. 调用方将Fw::Time序列化进 Tlm/Log 报文缓冲区,随遥测或事件下行到地面系统。

这一"端口传递引用 + 对象可序列化"的组合,正是Fw::Time在整个框架中通用性强的根本原因——它不绑定任何特定组件,任何模块都可以声明并使用该端口获取或转发时间戳。

5. 单元测试验证

仓库的单元测试位于 Fw/Time/test/ut/TimeTest.cpp,覆盖了该数据类型的全部核心行为:

测试用例验证内容
InstantiateTest构造Time(TB_NONE, 1, 2)后,基准、上下文、秒、微秒字段取值正确
MathTest相等/不等/大于/小于/大于等于比较;add求和(1000s1000us + 4000s2000us = 5000s3000us);常规减法;微秒借位减法(2s1us - 1s999999us = 0s2us)
CopyTest拷贝构造、赋值运算符、set方法均能完整复制四个字段
ZeroTimeEquality非零时间与Fw::ZERO_TIME不等;默认构造时间与Fw::ZERO_TIME相等

其中MathTest对微秒进位(加法)与借位(减法)的断言,正是对 Fw/Time/Time.cpp 中进位/借位分支的直接验证,可作为理解Fw::Time时间运算语义的最佳示例。

6. 变更记录

设计文档末尾给出了本模块的变更历史(见 Fw/Time/docs/sdd.md):

DateDescription
6/19/2015Initial Version

小结与实战要点

  • 端口形态:Fw::Time是无返回值、以ref引用方式传递Fw.Time参数的端口,FPP 定义见 Fw/Time/Time.fpp;
  • 数据类型:Fw::Time存储"时间基准 + 时间上下文 + 秒 + 微秒"四个字段,序列化尺寸与字段取舍受 config/FpConfig.hpp 中的TimeBase枚举、FW_USE_TIME_BASE、FW_USE_TIME_CONTEXT控制;
  • 运算语义:比较运算要求基准与上下文一致,否则返回INCOMPARABLE;add/sub内置微秒进位/借位逻辑,均以断言保护;
  • 接入方式:参照 Svc/Time/Time.fpp 声明sync input port timeGetPort: Fw.Time,即可在自己的组件中接收系统时间戳;
  • 验证手段:阅读并运行 Fw/Time/test/ut/TimeTest.cpp 可快速理解构造、比较、算术与零时间语义。

如需进一步了解时间在遥测与事件报文中的落地方式,可继续阅读 Fw/Tlm 与 Fw/Log 目录下的相关实现与文档。

  • 嵌入式
  • 系统编程

【免费下载链接】fprime

F´ - A flight software and embedded systems framework

项目地址:https://gitcode.com/gh_mirrors/fpri/fprime
点击查看免费下载

相关推荐

上一篇:模拟人生1宽屏补丁完整指南:让经典游戏完美适配现代显示器
下一篇:ESPHome 配置避坑:3 步从 YAML 跑通第一台设备固件

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 10:47:55

16个高效AI论文写作网站,TaoToken统一API接入与配置全解析

/* 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 10:34:15

Win7老机器提速实战:从诊断到优化的完整指南

简介&#xff1a;这份资源面向仍在使用Windows 7、希望在不重装系统的前提下提升运行流畅度的普通用户与初级运维人员&#xff0c;围绕系统响应变慢、开机与关机耗时偏长等常见问题&#xff0c;整理了一套可落地的优化思路。内容涵盖关闭窗口动画、优化启动与关机速度、删除多余…

作者头像 李华