Download Latest Version v4.4.0 source code.zip (23.3 MB) Google Add to Preferred Sources
Home / v4.4.0
Name Modified Size InfoDownloads / Week
Parent folder
README.md 2026-09-30 21.8 kB
v4.4.0 source code.tar.gz 2026-09-30 21.6 MB
v4.4.0 source code.zip 2026-09-30 23.3 MB
Totals: 3 Items   45.0 MB 0

Highlights

Major Features

  • WebAssembly Sequencer: new Svc::WasmSequencer runs sequences compiled to WebAssembly (via the spacewasm interpreter, built as an external Rust/C library). Supports load/run/pause/resume/cancel, timeouts, commands with response tracking, telemetry and parameter reads, time, events, sleeps, and serial I/O. Driven by two FPP state machines and configured with a project-supplied Fw::MemAllocator. A Rust toolchain is required only when the component is built.
  • CCSDS TM packet spanning: Svc::ComAggregator can now split Space Packets across TM transfer frames (First Header Pointer reported through ComCfg::FrameContext.firstHeaderPointer). Opt-in via ComCcsdsConfig.Aggregator.enablePacketSpanning; requires Svc.Ccsds.TmFramer and a ground deframer that reassembles spanned packets.
  • AES-256-GCM for CCSDS SDLS: new Svc::Ccsds::AesGcmEncryptor / AesGcmDecryptor implement the SDLS encryptor/decryptor interfaces on top of OpenSSL, replacing the clear-text null ciphers for deployments that need confidentiality and authentication. The ClearText* components now emit a throttled NullCipherInUse WARNING_HI event so an unauthenticated link is never silent.
  • Data products: new Svc::ComLoggerDp records Fw::ComBuffers into data-product containers (an alternative to file-based Svc::ComLogger); Svc::DpWriter gains matched [DpWriterNumPorts] port arrays so one instance can serve multiple fused data-product paths; Svc::DpCatalog skips products already marked TRANSMITTED in its state file.
  • Time: new passive Svc::TimeConverter converts Fw::Time values between time bases using runtime-supplied offsets (commands, ports, fixed-capacity offset table). Os::Posix::RawTime now honours Os::RawTimeSource (REALTIME, MONOTONIC, and BOOTTIME on Linux); intervals between different clock sources return INVALID_PARAMS instead of a meaningless difference.
  • Command dispatch: Svc::CmdDispatcher reports CLEARED to callers whose tracking entries are cleared, and can optionally dispatch commands when its sequence tracker is full (cmdDisp.configure(true), reported as DISPATCHED_UNTRACKED). Its dropped-command counter is now safe under concurrent overflow.
  • OSAL: Os::Mutex / Os::ConditionVariable join Os::RawTime as configurable aliases (default: link-time Os::Delegate*), allowing platform-specific implementations to be selected at compile time and devirtualized; all three selections now live in a single config/OsSelection.hpp. New Os::Posix::TASK_PRIORITY_NON_REALTIME selects SCHED_OTHER for tasks that must not run under real-time scheduling.
  • Drivers: Drv::LinuxUartDriver becomes Drv::PosixUartDriver (available on all POSIX platforms). TCP sends to a disconnected peer no longer raise SIGPIPE, and send timeouts return SOCK_INTERRUPTED_TRY_AGAIN for retry.
  • File security: fail-closed path sandboxing extended to Svc::FileManager (new configure(sandboxDir)), Svc::FileDownlink, and the whole of Svc::PrmDb; Os::SandboxedFile rejects every open until configured. See Breaking Changes for the default subtopology behaviour.

Security Fixes

This release continues the hardening effort begun in v4.3.0 — upgrading is recommended:

  • Fail-closed sandboxing of every path-bearing command in Svc::FileManager (PathOutsideSandbox event + VALIDATION_ERROR), of FileDownlink reads, and of all PrmDb file access; Os::SandboxedFile is fail-closed until configured.
  • Overflow-safe bounds checks in Fw::LinearBufferBase serialization and Svc::BufferManager allocation sizing; Os::Generic::PriorityQueue returns SIZE_MISMATCH without consuming an undersized message.
  • Asserts on externally-reachable inputs replaced with events/errors: overlong CRC hash-file names (Utils::CRCChecker, Svc::FileWorker), stale fileDone callbacks in Svc::DpCatalog, PRM_LOAD_FILE with an empty file name, FLUSH_QUEUE/SET_QUEUE_PRIORITY index validation in Svc::ComQueue, FpySequencer deserialize failures, WasmSequencer host-call failures.
  • Svc::FileWorker and Svc::BufferLogger truncate existing files on non-append writes (no stale trailing bytes).
  • SIGPIPE-safe TCP sends in Drv::IpSocket (MSG_NOSIGNAL / SO_NOSIGPIPE).
  • Clear-text SDLS ciphers announce themselves with NullCipherInUse; documentation now instructs replacing, not augmenting, the null ciphers.

Breaking Changes

Configuration Changes

ComCfg.AggregationSize removed; aggregator size moves to ComCcsdsConfig.Aggregator

Svc::ComAggregator now owns idle filling and sizes its buffer from an allocator. The ComCfg.AggregationSize dictionary constant is gone; the ComCcsds subtopology configures the aggregator from new constants. Projects overriding ComCfg.fpp must delete the constant, and projects overriding ComCcsdsConfig.fpp must add the Aggregator module.

Migration details :::diff # ComCfg.fpp - @ Size of the aggregation buffer - dictionary constant AggregationSize = Svc.Ccsds.TmDataFieldSize - ... :::diff # ComCcsdsConfig.fpp module ComCcsdsConfig { + module Aggregator { + @ Size in bytes of every aggregate emitted by the aggregator (must equal Svc.Ccsds.TmDataFieldSize + @ unless a layer between the aggregator and the framer adds bytes, e.g. SDLS) + constant aggregationSize = Svc.Ccsds.TmDataFieldSize + @ Span packets across TM transfer frames (requires Svc.Ccsds.TmFramer and a spanning-aware ground deframer) + constant enablePacketSpanning = false + } Projects using `ComCcsdsSdls` must reserve the SA index (and any per-frame encryptor overhead) so that the encrypted data field is exactly frame-sized: :::fpp constant aggregationSize = Svc.Ccsds.TmDataFieldSize - Svc.Ccsds.SdlsSaIndexSize Every emitted aggregate is now exactly `aggregationSize` bytes and idle-filled — including in the frame-less Space Packet variant of the subtopology, where each flush costs a full aggregate. `Svc.Ccsds.TmFramer` no longer inserts idle packets and asserts if it receives anything other than an exactly-sized data field.

New fields in ComCfg::FrameContext

FrameContext gained the Space Packet type bit and the TM First Header Pointer. Projects overriding ComCfg.fpp must add the enum, the fields, and their defaults.

Migration details :::diff + @ Packet type in the Space Packet Primary Header + enum SppPacketType : U8 { + SPP_TELEMETRY = 0 @< Telemetry / data packet (downlink) + SPP_COMMAND = 1 @< Telecommand packet (uplink) + } default SPP_TELEMETRY + struct FrameContext { comQueueIndex: FwIndexType apid: Apid + pktType: SppPacketType @< 1 bit packet type in space packet primary header hasSecHdr: bool ... saIndex: U16 + firstHeaderPointer: U16 @< TM First Header Pointer, set by ComAggregator, consumed by TmFramer } default { comQueueIndex = 0 apid = Apid.FW_PACKET_UNKNOWN + pktType = SppPacketType.SPP_TELEMETRY ... + firstHeaderPointer = 0 } `Svc.Ccsds.SpacePacketFramer` now sets the primary-header packet-type bit from `pktType` (previously always 0).

Default FwSizeStoreType is now FwSizeType

The serialized width of string lengths and buffer sizes changes from U16 to the width of FwSizeType (U64 on 64-bit platforms by default).

Migration details :::diff # FpConfig.fpp -dictionary type FwSizeStoreType = U16 +dictionary type FwSizeStoreType = FwSizeType > [!WARNING] > This change is a **required** change to ensure that assumptions the framework makes on sizes hold correctly. Using any other configuration is at a project's own risk. This changes the on-wire and on-disk format of anything carrying a string or size-prefixed buffer (command arguments, events, telemetry, parameter database, data products, sequence files).

File sandboxes are configured by the subtopologies (default: unrestricted)

Svc::FileUplink, Svc::FileDownlink, Svc::FileManager, and Svc::PrmDb are fail-closed until configured. The FileHandling subtopology now configures all four from a new constant (default "/", i.e. the historical unrestricted behaviour) and also calls prmDb.configure(FileHandlingConfig::Paths::prmDbFile) for you.

Migration details :::fpp # FileHandlingConfig.fpp module Paths { constant prmDbFile = "PrmDb.dat" # Parameter database storage file constant sandboxDir = "/" # "/" = unrestricted } Deployments that previously called `FileHandling::prmDb.configure(...)` / `FileHandling::fileUplink.configure(...)` from `configureTopology()` may remove those calls (the `prmDb.configure` call is now redundant). To actually confine file access, override `sandboxDir` or re-configure after the autocoded `configComponents` phase: :::diff void configureTopology() { - FileHandling::fileUplink.configure("/tmp/uplink/"); - FileHandling::prmDb.configure("PrmDb.dat"); + // Restrict file access to the working directory (where PrmDb.dat lives) + FileHandling::fileUplink.configure("."); + FileHandling::fileDownlink.configure("."); + FileHandling::fileManager.configure("."); + FileHandling::prmDb.configureSandbox("."); } Deployments instantiating these components outside the subtopology **must** call `configure()` / `configureSandbox()` or every file operation will fail with `OUTSIDE_SANDBOX`. `FileHandlingConfig` is no longer an `INTERFACE` config module (it now generates C++ constants).

Svc::ComAggregator must be configured with an allocator

ComAggregator::configure() now takes the aggregation size, spanning flag, allocation ID, and a Fw::MemAllocator, and cleanup() must be called at teardown; the ComCcsds subtopology does this for you, deployments wiring the aggregator directly must add the calls.

Migration details :::diff - aggregator.configure(false); + aggregator.configure(ComCcsdsConfig::Aggregator::aggregationSize, + ComCcsdsConfig::Aggregator::enablePacketSpanning, + allocationId, memAllocator); + ... + aggregator.cleanup(); // in tearDownComponents The `ComCcsds` subtopology does this itself and requires the deployment to provide `ComCcsds::Allocation::memAllocator` (as in v4.3.0).

OSAL implementation selection consolidated into config/OsSelection.hpp

Os::Mutex and Os::ConditionVariable are now configurable aliases like Os::RawTime, and the per-service selection headers are collapsed into one: default/config/OsDelegateRawTime.hpp is removed (along with the interim OsDelegateMutex.hpp) and replaced by default/config/OsSelection.hpp. Projects that override OsDelegateRawTime.hpp for compile-time RawTime selection must rename their override to OsSelection.hpp and, because the override replaces the whole default, define every alias and OS_*_HEADER macro — not just the service being changed.

Migration details :::diff -// my-project/config/OsDelegateRawTime.hpp -#ifndef CONFIG_OS_DELEGATERAWTIME_HPP -#define CONFIG_OS_DELEGATERAWTIME_HPP +// my-project/config/OsSelection.hpp +#ifndef CONFIG_OSSELECTION_HPP +#define CONFIG_OSSELECTION_HPP namespace Va416x0Os { class TimerRawTime; } namespace Os { using RawTime = Va416x0Os::TimerRawTime; +class DelegateMutex; +class DelegateConditionVariable; +using Mutex = DelegateMutex; +using ConditionVariable = DelegateConditionVariable; } #define OS_RAW_TIME_HEADER "Va416x0/Os/TimerRawTime/TimerRawTime.hpp" +#define OS_MUTEX_HEADER <os delegatemutex.hpp> +#define OS_CONDITION_VARIABLE_HEADER <os delegateconditionvariable.hpp> -#endif // CONFIG_OS_DELEGATERAWTIME_HPP +#endif // CONFIG_OSSELECTION_HPP :::diff # my-project/config/CMakeLists.txt register_fprime_config( ... - "${CMAKE_CURRENT_LIST_DIR}/OsDelegateRawTime.hpp" + "${CMAKE_CURRENT_LIST_DIR}/OsSelection.hpp" `Os::Mutex` and `Os::ConditionVariable` must be overridden together with a compatible pair (the condition variable operates on the mutex's handle); `Os/ConditionVariableInterface.hpp` `static_assert`s that either both or neither are the link-time delegates. The aliased implementation module must still be in the link (`CHOOSES_IMPLEMENTATIONS` / `DEPENDS`).

Os::RawTimeSource on POSIX

default/config/Os/RawTimeSource.hpp now maps RAWTIME_DEFAULT/REALTIME/MONOTONIC/BOOTTIME onto POSIX clock IDs. Projects overriding this header should re-base on the new default.

Drv.LinuxUartDriver renamed to Drv.PosixUartDriver

The component, its directory, and its header are renamed; update topology instances and #includes.

Migration details :::diff - instance uartDriver: Drv.LinuxUartDriver base id 0x4C00 + instance uartDriver: Drv.PosixUartDriver base id 0x4C00 :::diff -#include "Drv/LinuxUartDriver/LinuxUartDriver.hpp" +#include "Drv/PosixUartDriver/PosixUartDriver.hpp"

register_fprime_config(BASE_CONFIG) deprecated

Replace with GLOBAL_IMPLICIT_DEPENDENCY; BASE_CONFIG still works but emits a CMake warning. FPRIME_ENABLE_JSON_MODEL_GENERATION is deprecated in favour of the native FPP Python bindings.

User Breaking Changes

parameterUpdated is now invoked for every parameter at load (FPP 3.4.0)

The generated parametersLoaded() hook now calls parameterUpdated(id) once per parameter after loadParameters(). Handlers written assuming a parameter is only VALID will assert on the DEFAULT case. Use the new FW_PARAM_OK macro, which accepts both VALID and DEFAULT.

Migration details :::diff +#include "Fw/Prm/ParamValid.hpp" ... void Led::parameterUpdated(FwPrmIdType id) { Fw::ParamValid isValid = Fw::ParamValid::INVALID; U32 interval = this->paramGet_BLINK_INTERVAL(isValid); - FW_ASSERT(isValid == Fw::ParamValid::VALID, static_cast<fwassertargtype>(isValid)); + FW_ASSERT(FW_PARAM_OK(isValid), static_cast<fwassertargtype>(isValid)); Components that already iterate their parameters in `parametersLoaded()` should remove that loop (or override `parametersLoaded()` to restore the previous no-op) to avoid double handling.

New Fw::CmdResponse values

Fw::CmdResponse gains CLEARED = 6 and DISPATCHED_UNTRACKED = 7; exhaustive switches over command responses must handle them.

Migration details :::diff enum CmdResponse { ... BUSY = 5 + CLEARED = 6 @< Command tracking was cleared before the command completed + DISPATCHED_UNTRACKED = 7 @< Dispatched with a full sequence tracker; completion status is unknown } Sequencers and ground tooling that switch exhaustively over command responses must handle the new values.

FileAnnounce / FileDispatch port file names are fixed-size

The file-name arguments of Svc.FileAnnounce and Svc.FileDispatch are now string size FileNameStringSize (default 240) rather than the unsized string (256 default). Handler implementations still receive const Fw::StringBase&, but the serialized port ABI and maximum file-name length change; file names longer than FileNameStringSize are rejected instead of truncated.

Svc.Ping input ports drop on overflow

PingIn on ActiveRateGroup, BufferAccumulator, BufferLogger, CmdDispatcher, CmdSequencer, ComLogger, EventManager, FileDownlink, FileManager, FileUplink, FpySequencer, PrmDb, TlmChan, and TlmPacketizer is now drop instead of asserting on queue overflow, so Svc::Health can report the wedged component.

Svc::TlmPacketizer accepts zero-channel packets

A packet definition with no channels is now valid (sent header-only on SEND_PKT); a non-empty packet with a null channel list still asserts. Projects that relied on the assert as a check must validate their packet definitions elsewhere.

Svc::ComQueue depth 0 disables a queue

Previously an assertion failure; now the entry is treated as full (messages are dropped through the QueueOverflow path and buffers returned). An all-zero table still asserts.

Svc::FileManager command paths are canonicalized

All ten path-bearing commands resolve their arguments with Os::FilePathUtils::resolveFromCwd before touching the filesystem and reject paths outside the sandbox with a PathOutsideSandbox WARNING_HI event and VALIDATION_ERROR. Errors telemetry increments on rejection.

.CRC32 files are endian-independent

Utils::CRCChecker now writes and reads the CRC through F Prime serialization (big-endian), matching Utils::Hash, Os::ValidatedFile, and Svc::ComLogger. .CRC32 sidecar files written by CRCChecker in earlier releases on little-endian hosts will fail validation and must be regenerated.

Developer Breaking Changes

Os::Mutex / Os::ConditionVariable are no longer concrete classes

Os/Mutex.hpp and Os/Condition.hpp now provide Os::Mutex / Os::ConditionVariable as aliases selected via config/OsSelection.hpp; Os::MutexInterface / Os::MutexHandle moved to Os/MutexInterface.hpp, Os::ConditionVariableInterface to Os/ConditionVariableInterface.hpp, and Os/Mutex.cpp was removed. lock()/unLock()/ScopeLock and wait() are defined inline on the interfaces. Code that forward-declared class Os::Mutex or subclassed it must include the new headers and use the alias; OSAL implementations of Os_Mutex must derive from Os::MutexInterface.

Svc.Ccsds.TmFramer serializes only

The framer no longer idle-fills; it asserts data.getSize() == TmDataFieldSize. Components feeding it directly must emit exactly-sized data fields (use Svc::Ccsds::Utils::IdlePacket for filling).

Os::RawTime::getTimeInterval across clock sources returns INVALID_PARAMS

Two Os::RawTime values read from different Os::RawTimeSource clocks no longer produce a meaningless difference; getTimeInterval()/getDiffUsec() return INVALID_PARAMS and leave the output unwritten, so callers must initialize and check. Utils::RateLimiter and Utils::TokenBucket no longer assert when driven with Fw::Time values in a different time base; they adopt the caller's base.

Os::Generic::PriorityQueue::receive size mismatch

Returns SIZE_MISMATCH and leaves the message on the queue rather than dropping it; callers must retry with a sufficiently large buffer.

Utils::CRCChecker new status

crc_stat_t gains FAILED_FILE_NAME_TOO_LONG (appended); switch statements over the enum need the new case.

Fw::LinearBufferBase bool serialization

Booleans are serialized through the U8 path and pointer size is static_asserted; custom serializable types with hand-written serialization should mirror this.

Unit tests and FwSizeStoreType

Tests that compare serialized sizes or offsets against literal byte counts (assuming a two-byte length prefix) must be expressed in terms of sizeof(FwSizeStoreType); the framework's own tests were updated accordingly.

Deprecations

  • register_fprime_config(BASE_CONFIG) — use GLOBAL_IMPLICIT_DEPENDENCY.
  • FPRIME_ENABLE_JSON_MODEL_GENERATION — the FPP JSON model is superseded by the native FPP Python bindings.
  • Drv/LinuxUartDriver — use Drv/PosixUartDriver.
  • Svc::WasmSequencer host import args (fprime_wasm_get_args) is a no-op: sequence arguments were removed pending typed variant/vector argument support.

New Contributors

Full Changelog: https://github.com/nasa/fprime/compare/v4.3.0...v4.4.0

Source: README.md, updated 2026-09-30