Understanding the F Prime Parameter System: Architecture and Implementation
The F Prime parameter system is a configurable value framework that enables spacecraft software components to expose modifiable settings through a central database, supporting runtime updates, persistence across reboots, and external storage delegation.
The F Prime parameter system provides a standardized mechanism for components in the nasa/fprime repository to expose configurable values that can be inspected, modified, and persisted across system runs. This architecture separates parameter definition from storage implementation, allowing components to interact with values through generated ports while a central service handles persistence. The system supports both standard database-backed storage and custom external delegates for specialized hardware integration.
Core Architecture Components
Parameter Definition and Code Generation
Parameters are declared in component FPP (F Prime Prime) files using param entries. The code generator creates unique parameter IDs (FwPrmIdType) and accessor ports for each component. In the generated component base class (e.g., MyComponentComponentBase.hpp), the framework implements handlers such as from_getParam_handler and from_setParam_handler that forward requests to the parameter database.
The Parameter Database (PrmDb)
The PrmDb (Svc/PrmDb/PrmDbImpl.hpp) serves as the central repository for parameter values. It maintains an in-memory map (PrmDbStore) implemented as Fw::ArrayMap<FwPrmIdType, Fw::ParamBuffer, PRMDB_NUM_DB_ENTRIES>. At startup, PrmDbImpl::readParamFile() reads the *.prm file to populate this map, while PrmDbImpl::updateAddPrmImpl() handles runtime updates with status tracking (PARAM_ADDED, PARAM_UPDATED).
External Parameter Delegation
Components requiring storage outside the central database (such as EEPROM or remote nodes) inherit from Fw::ParamExternalDelegate defined in Fw/Prm/PrmExternalTypes.hpp. This abstract base class requires implementation of serializeParam and deserializeParam methods, allowing components to bypass the standard PrmDb and interact directly with custom storage mechanisms.
How the F Prime Parameter System Works
Component Generation and Port Creation
When processing component definitions, the FPP generator emits parameter ports (paramGetPort and paramSetPort) and a parameter ID enum. These generated elements appear in the component base class, providing the prmGet_out and prmSet_out interfaces that components use to communicate with the database.
Loading Initial Values at Startup
During initialization, components invoke the generated loadParameters() method, which queries the PrmDb for stored values corresponding to each parameter ID. If a parameter is missing from the database, the component falls back to its default value defined in the component source code.
Runtime Parameter Access
- Getting Parameters: Components call
prmGet_out, which triggersPrmDb'sgetPrm_handler. This handler retrieves the value fromPrmDbStoreand returns aFw::ParamBuffercontaining the serialized data. - Setting Parameters: Components call
prmSet_out, invokingsetPrm_handler. The database updates thePrmDbStoremap entry and optionally persists the change to disk via the*.prmfile.
Persistence and File Management
The PrmDb maintains parameter values in a disk-based file (default name PrmDb.prm) that survives system restarts. The readParamFile() method parses this file at initialization, while updates modify both the in-memory map and the persistent storage.
Implementing External Parameter Storage
For components requiring custom storage, implement the Fw::ParamExternalDelegate interface:
class ExternalStorageComponent : public MyComponentComponentBase,
public Fw::ParamExternalDelegate {
public:
SerializeStatus serializeParam(const FwPrmIdType base_id,
const FwPrmIdType local_id,
SerialBufferBase& buff) const override {
// Read from external storage (e.g., EEPROM)
U8 data[FW_PARAM_BUFFER_MAX_SIZE];
EEPROM.read(local_id * sizeof(data), data, sizeof(data));
buff.setData(data, sizeof(data));
return SerializeStatus::FW_SERIALIZE_OK;
}
SerializeStatus deserializeParam(const FwPrmIdType base_id,
const FwPrmIdType local_id,
const ParamValid prmStat,
SerialBufferBase& buff) override {
// Write to external storage
EEPROM.write(local_id * sizeof(buff.getData()),
buff.getData(),
buff.getSize());
return SerializeStatus::FW_SERIALIZE_OK;
}
};
Practical Code Examples
Declaring Parameters in FPP
module MyApp {
component MyComponent {
param MY_PARAM: U32 = 42 # default value
}
}
Reading Parameters in Component Code
void MyComponent::handleParameterGet(Fw::PrmIdType id) {
Fw::ParamBuffer val;
if (this->prmGet_out(0, id, val) == Fw::FW_SUCCESS) {
U32 myValue = 0;
val.deserialize(myValue);
// Use retrieved value
}
}
Setting Parameters at Runtime
void MyComponent::handleParameterSet(Fw::PrmIdType id, U32 newVal) {
Fw::ParamBuffer buf;
buf.serialize(newVal);
this->prmSet_out(0, id, buf); // Updates PrmDb and persistence
}
Loading Parameters at Startup
void MyComponent::init(NATIVE_INT_TYPE instance) {
ComponentBase::init(instance);
this->loadParameters(); // Generated method to populate from PrmDb
}
Summary
- The F Prime parameter system uses a central PrmDb service (
Svc/PrmDb/PrmDbImpl.hpp) to store configurable values in anFw::ArrayMapstructure. - Components interact with parameters through generated ports (
prmGet_out,prmSet_out) declared in FPP files and implemented in base classes. - The system supports external storage delegation via the
Fw::ParamExternalDelegateabstract class inFw/Prm/PrmExternalTypes.hpp. - Parameters persist across reboots through disk-based
*.prmfiles managed byPrmDbImpl::readParamFile()andupdateAddPrmImpl(). - Default values are defined in FPP and used when parameters are missing from the database.
Frequently Asked Questions
What is the purpose of the PrmDb in F Prime?
The PrmDb (Parameter Database) is a central service that stores the current value of every parameter in an in-memory map (PrmDbStore). It provides a single point of management for configuration values, handles persistence to disk-based *.prm files, and processes get/set requests from components through its getPrm_handler and setPrm_handler methods.
How are parameter IDs generated in F Prime?
Parameter IDs are generated during the FPP code generation process. When a component declares a parameter in its FPP file, the generator creates a unique FwPrmIdType identifier and adds it to the component's parameter ID enum. These IDs are used to route requests between components and the PrmDb.
Can F Prime parameters be stored outside the standard database?
Yes, through the External Parameter Delegation mechanism. Components inherit from Fw::ParamExternalDelegate (defined in Fw/Prm/PrmExternalTypes.hpp) and implement serializeParam and deserializeParam methods. This allows storage in non-volatile memory, remote servers, or other custom locations while maintaining the standard component interface.
Where does F Prime load parameters during system startup?
Parameters are loaded during component initialization through the generated loadParameters() method, typically called from the component's init() function. This method queries the PrmDb for stored values, which were previously loaded from the PrmDb.prm file by PrmDbImpl::readParamFile() during system startup.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →