v4.0.0a1 Draft Release Notes - LeStarch/fprime GitHub Wiki
F Prime is removing the NATIVE_INT_TYPE
, PlatformIntType
, etc. Additionally, F Prime has begun ensuring that configurable types (e.g. FwIndexType
) are configured to fixed-width values. The requirements (signed, minimum sizes) can be found in the numerical types document.
Users needing non-default values for configurable types should set them as type aliases in FPP using the new configuration system.
Users of older F Prime code may still have NATIVE_INT_TYPE
used as port indices. This is now required to be FwIndexType
. Other uses of NATIVE_INT_TYPE
must also be replaced.
Before:
const NATIVE_INT_TYPE portNum
After:
const FwIndexType portNum
Rate group context has been changed to the fixed-width type U32
.
Before
NATIVE_INT_TYPE rateGroup1Context[Svc::ActiveRateGroup::CONNECTION_COUNT_MAX] = {};
NATIVE_INT_TYPE rateGroup2Context[Svc::ActiveRateGroup::CONNECTION_COUNT_MAX] = {};
NATIVE_INT_TYPE rateGroup3Context[Svc::ActiveRateGroup::CONNECTION_COUNT_MAX] = {};
After:
U32 rateGroup1Context[Svc::ActiveRateGroup::CONNECTION_COUNT_MAX] = {};
U32 rateGroup2Context[Svc::ActiveRateGroup::CONNECTION_COUNT_MAX] = {};
U32 rateGroup3Context[Svc::ActiveRateGroup::CONNECTION_COUNT_MAX] = {};
In the same capacity as above, unit test constants of NATIVE_INT_TYPE
are not supported
Before:
static const NATIVE_INT_TYPE MAX_HISTORY_SIZE = 10;
// Instance ID supplied to the component instance under test
static const NATIVE_INT_TYPE TEST_INSTANCE_ID = 0;
// Queue depth supplied to the component instance under test
static const NATIVE_INT_TYPE TEST_INSTANCE_QUEUE_DEPTH = 10;
After:
// Maximum size of histories storing events, telemetry, and port outputs
static const U32 MAX_HISTORY_SIZE = 10;
// Instance ID supplied to the component instance under test
static const FwEnumStoreType TEST_INSTANCE_ID = 0;
// Queue depth supplied to the component instance under test
static const FwSizeType TEST_INSTANCE_QUEUE_DEPTH = 10;
The old module registration structure in F Prime had one primary limitation: SOURCE_FILES and MOD_DEPS were variables and thus could bleed into other module registrations if not unset. This pollution of CMake's variable namespace, high chance for user error, and poor choice of the name "MOD_DEPS" led to a need to refactor how modules are done. To fit in with modern CMake practices, all module inputs are arguments to the registration calls with individual variables specified by directive arguments (e.g. SOURCES, DEPENDS).
Tip
register_fprime_module
, register_fprime_deployment
and register_fprime_ut
still support MOD_DEPS
, SOURCE_FILES
, UT_MOD_DEPS
, UT_SOURCE_FILES
. Updating to the new structure is only required for register_fprime_configuration
calls. However, new features will only be supported with the new structure and as such, users are encouraged to update when needed.
The new register_fprime_*
calls are provided arguments lists separated by argument directives to specify sources (SOURCES
), dependencies (DEPENDS
) etc.
The first argument is an optional explicit module name followed by directives and their argument lists.
Before:
set(SOURCE_FILES
"${CMAKE_CURRENT_LIST_DIR}/source1.cpp"
"${CMAKE_CURRENT_LIST_DIR}/source2.cpp"
"${CMAKE_CURRENT_LIST_DIR}/source1.fpp"
"${CMAKE_CURRENT_LIST_DIR}/source2.fpp"
)
set(HEADER_FILES
"${CMAKE_CURRENT_LIST_DIR}/header1.hpp"
"${CMAKE_CURRENT_LIST_DIR}/header2.hpp"
)
set(MOD_DEPS Fw_Types)
register_fprime_module(MyModule)
After:
register_fprime_modules(
SOURCES
"${CMAKE_CURRENT_LIST_DIR}/source1.cpp"
"${CMAKE_CURRENT_LIST_DIR}/source2.cpp"
HEADERS
"${CMAKE_CURRENT_LIST_DIR}/header1.hpp"
"${CMAKE_CURRENT_LIST_DIR}/header2.hpp"
AUTOCODER_INPUTS
"${CMAKE_CURRENT_LIST_DIR}/source1.fpp"
"${CMAKE_CURRENT_LIST_DIR}/source2.fpp"
DEPENDS
Fw_Types
)
Tip
Notice that autocoder inputs are now specifically called out separately from compiled source files.
Warning
Do not specify an explicit module name when autocoding FPP.
Old variable usage can be translated to new directives using the following table:
Old Structure's Variable | Directive | Purpose |
---|---|---|
SOURCE_FILES | SOURCES | Source files supplied to cc , c++ , or other compiler |
SOURCE_FILES | AUTOCODER_INPUTS | Autocoder input files used to generate file |
MOD_DEPS | DEPENDS | Module build target dependencies |
HEADER_FILES | HEADERS | Header files supplied by the module |
UT_SOURCE_FILES (built) | SOURCES | Unit test source files to supplied to compiler |
UT_SOURCE_FILES (autocode inputs) | AUTOCODER_INPUTS | Unit test autocoder input files |
UT_MOD_DEPS | DEPENDS | Unit test module dependencies |
UT_HEADER_FILES | HEADERS | Unit test headers |
Since deployments in F Prime do recursive detection of items like unit tests, etc, deployments now check for the existence of F Prime modules that support them. This means F Prime deployments must be defined last in the CMake structure.
Before:
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Components/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/MathDeployment/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Types/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Ports/")
After:
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Components/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Types/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Ports/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/MathDeployment/")
One of the flaws of historical F Prime is that configuration was an all-or-nothing copy. It meant that projects, libraries, etc could not just override what was changed. This presented projects with a maintenance issue: owning unchanged code provided by F Prime while tracking their own minor changes.
With v4.0.0
projects choose to override specific files and the rest are inherited from underlying configuration modules.
Additionally, each configuration is specified as a module. Use the CONFIGURATION_OVERRIDES
directive to override existing config. User SOURCES
, HEADERS
, and AUTOCODER_INPUTS
as usual to specify new configuration (i.e. new configuration for your library). Modules specifying only CONFIGURATION_OVERRIDES
must also use the INTERFACE
specifier.
To specify a new configuration module, ensure that some directory added to the project with add_fprime_subdirectory
contains a CMakeLists.txt
including a register_fprime_config
call.
See changes in cmake module structure to understand the format of the register_fprime_config
call.
CMakeLists.txt
register_fprime_config(
CONFIGURATION_OVERRIDES
"${CMAKE_CURRENT_LIST_DIRECTORY}/FpConfig.fpp"
"${CMAKE_CURRENT_LIST_DIRECTORY}/IpCfg.hpp"
)
This example shows how to override just FpConifg.fpp
and IpCfg.hpp
from fprime.
Tip
Configurations are overridden by filename, so remember to keep your filenames consistent with the file you wish to override.
Tip
Default F Prime configuration lives at fprime/default/config
projects will use these settings unless the filename is included in a projects configuration module via CONFIGURATION_OVERRIDES
.
Warning
F Prime only has the notion of a single configuration per project (i.e. build). You still may not specify different configurations for different modules built by the same project.
All configuration headers used from the F Prime configuration directory default/config
, a library configuration directory, or a project configuration directory must specify the path including the parent folder.
Before:
#include "IpCfg.hpp"
After:
#include "config/IpCfg.hpp"
Additionally, components wanting to depend on and use core F Prime configured types must depend on Fw_Types
and include Fw/FPrimeBasicTypes.h
or Fw/FPrimeBasicTypes.hpp
.
Before: C++
#include "FpConfig.hpp"
After: C++
#include "Fw/FPrimeBasicTypes.hpp
Before: CMakeLists.txt
set(MOD_DEPS
SomeDependency
)
After: CMakeLists.txt
set(MOD_DEPS
Fw_Types
SomeDependency
)
Tip
Fw_Types
is auto-detected for FPP-based modules. Add this dependency when not using FPP autocoding on your module.
Platforms have had several major changes in v4.0.0
:
- Platform types have been moved into FPP as type aliases
- Platform types are expected to use fixed-with types
- Platform setup should now be a configuration module via
register_fprime_config
Platform types were previously defined as header typedefs, however; this meant these types (which flow into configurable types) are not available to FPP models. These types are now aliases within FPP.
Before (PlatformTypes.h)
typedef uint64_t PlatformSizeType;
...
After (PlatformTypes.fpp)
@ The unsigned type of larger sizes internal to the software,
@ e.g., memory buffer sizes, file sizes. Must be unsigned.
@ Supplied by platform, overridable by project.
type PlatformSizeType = U64
...
Warning
Since PlatfromPointerCast
should not be used in the model, it is kept in PlatformTypes.h
The requirements on these types, and the complete list are found in the numerical types documentation.
Platform definitions are defined in cmake/platform/<name-of-platform>.cmake
. This file must now define an fprime configuration module that performs the autocoding for the new PlatformTypes.fpp
Before
include_directories(SYSTEM "${CMAKE_CURRENT_LIST_DIR}/types")
After
register_fprime_config(
AUTOCODER_INPUTS
"${CMAKE_CURRENT_LIST_DIR}/PlatformTypes.fpp"
HEADERS
"${CMAKE_CURRENT_LIST_DIR}/PlatformTypes.h"
INTERFACE # No buildable files generated
)
The Uplink and Downlink components have been updated for better modularity and to allow for easy support of other communication protocols.
If using a standard Uplink/Downlink stack as generated by fprime-util new --deployment
, the full change-set that users need to apply to their topology is shown in the LedBlinker change log
Click to Expand changes to a topology.fpp
Before (topology.fpp)
connections Uplink {
comDriver.allocate -> bufferManager.bufferGetCallee
comDriver.$recv -> comStub.drvDataIn
comStub.comDataOut -> deframer.framedIn
deframer.framedDeallocate -> bufferManager.bufferSendIn
deframer.comOut -> cmdDisp.seqCmdBuff
cmdDisp.seqCmdStatus -> deframer.cmdResponseIn
deframer.bufferAllocate -> bufferManager.bufferGetCallee
deframer.bufferOut -> fileUplink.bufferSendIn
deframer.bufferDeallocate -> bufferManager.bufferSendIn
fileUplink.bufferSendOut -> bufferManager.bufferSendIn
}
connections Downlink {
eventLogger.PktSend -> comQueue.comQueueIn[0]
tlmSend.PktSend -> comQueue.comQueueIn[1]
fileDownlink.bufferSendOut -> comQueue.buffQueueIn[0]
comQueue.comQueueSend -> framer.comIn
comQueue.buffQueueSend -> framer.bufferIn
framer.framedAllocate -> bufferManager.bufferGetCallee
framer.framedOut -> comStub.comDataIn
framer.bufferDeallocate -> fileDownlink.bufferReturn
comDriver.deallocate -> bufferManager.bufferSendIn
comDriver.ready -> comStub.drvConnected
comStub.comStatus -> framer.comStatusIn
framer.comStatusOut -> comQueue.comStatusIn
comStub.drvDataOut -> comDriver.$send
}
After (topology.fpp)
enum Ports_ComPacketQueue {
EVENTS,
TELEMETRY
}
enum Ports_ComBufferQueue {
FILE_DOWNLINK
}
connections Uplink {
# ComDriver buffer allocations
comDriver.allocate -> bufferManager.bufferGetCallee
comDriver.deallocate -> bufferManager.bufferSendIn
# ComDriver <-> ComStub
comDriver.$recv -> comStub.drvReceiveIn
comStub.drvReceiveReturnOut -> comDriver.recvReturnIn
# ComStub <-> FrameAccumulator
comStub.dataOut -> frameAccumulator.dataIn
frameAccumulator.dataReturnOut -> comStub.dataReturnIn
# FrameAccumulator buffer allocations
frameAccumulator.bufferDeallocate -> bufferManager.bufferSendIn
frameAccumulator.bufferAllocate -> bufferManager.bufferGetCallee
# FrameAccumulator <-> Deframer
frameAccumulator.dataOut -> deframer.dataIn
deframer.dataReturnOut -> frameAccumulator.dataReturnIn
# Deframer <-> Router
deframer.dataOut -> fprimeRouter.dataIn
fprimeRouter.dataReturnOut -> deframer.dataReturnIn
# Router buffer allocations
fprimeRouter.bufferAllocate -> bufferManager.bufferGetCallee
fprimeRouter.bufferDeallocate -> bufferManager.bufferSendIn
# Router <-> CmdDispatcher/FileUplink
fprimeRouter.commandOut -> cmdDisp.seqCmdBuff
cmdDisp.seqCmdStatus -> fprimeRouter.cmdResponseIn
fprimeRouter.fileOut -> fileUplink.bufferSendIn
fileUplink.bufferSendOut -> fprimeRouter.fileBufferReturnIn
}
connections Downlink {
# Inputs to ComQueue (events, telemetry, file)
eventLogger.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.EVENTS]
tlmSend.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.TELEMETRY]
fileDownlink.bufferSendOut -> comQueue.bufferQueueIn[Ports_ComBufferQueue.FILE_DOWNLINK]
comQueue.bufferReturnOut[Ports_ComBufferQueue.FILE_DOWNLINK] -> fileDownlink.bufferReturn
# ComQueue <-> Framer
comQueue.dataOut -> fprimeFramer.dataIn
fprimeFramer.dataReturnOut -> comQueue.dataReturnIn
# Buffer Management for Framer
fprimeFramer.bufferAllocate -> commsBufferManager.bufferGetCallee
fprimeFramer.bufferDeallocate -> commsBufferManager.bufferSendIn
# Framer <-> ComStub
fprimeFramer.dataOut -> comStub.dataIn
comStub.dataReturnOut -> fprimeFramer.dataReturnIn
# ComStub <-> ComDriver
comStub.drvSendOut -> comDriver.$send
comDriver.sendReturnOut -> comStub.drvSendReturnIn
comDriver.ready -> comStub.drvConnected
# ComStatus
comStub.comStatusOut -> fprimeFramer.comStatusIn
fprimeFramer.comStatusOut -> comQueue.comStatusIn
}
Click to Expand changes to a instances.fpp
Diff (instances.fpp)
# Note: Make sure to adjust the base IDs to fit in your deployment
- instance framer: Svc.Framer base id 0x4100
+ instance framer: Svc.FprimeFramer base id 0x4100
- instance deframer: Svc.Deframer base id 0x4900
+ instance deframer: Svc.FprimeDeframer base id 0x4900
+ instance frameAccumulator: Svc.FrameAccumulator base id 0x4D00
+ instance fprimeRouter: Svc.FprimeRouter base id 0x4E00
Click to Expand changes to a Topology.cpp
The following removes the old framing/deframing protocols, and introduces the new FprimeFrameDetector
.
Diff (Topology.cpp)
- #include <Svc/FramingProtocol/FprimeProtocol.hpp>
+ #include <Svc/FrameAccumulator/FrameDetector/FprimeFrameDetector.hpp>
- Svc::FprimeFraming framing;
- Svc::FprimeDeframing deframing;
+ Svc::FrameDetectors::FprimeFrameDetector frameDetector;
[...]
- framer.setup(framing);
- deframer.setup(deframing);
+ frameAccumulator.configure(frameDetector, 1, mallocator, 2048);
The old Svc.Deframer
was performing 3 functionalities: (1) accumulating bytes in a circular buffer until it detects a full frame, (2) validating the frame and extracting the payload data, and (3) routing payload data to its destination.
In the new Uplink stack, these 3 functionalities have been split into 3 distinct components: (1) Svc.FrameAccumulator
, (2) Svc.FprimeDeframer
, and (3) Svc.FprimeRouter
. To learn more about these components, please check out their SDDs on the website!
Each component implements an FPP Interface (in Svc/Interfaces/
) so that they can be swapped with project-specific components, allowing for custom Deframing / Routing.
Memory management in the Uplink/Downlink stack has been updated so that a buffer coming out of a component on dataOut
shall come back on dataReturnIn
. This allows for components to allocate/deallocate memory as they see fit, and for the Topology Engineer not to have to track down memory management of each component to make sure they are wired correctly with the appropriate BufferManagers.
In the Downlink stack, the port connections have been modified to fit the new memory management pattern. The Framer now implements the FramerInterface.fppi
to allow projects to implement custom Framing easily.
FileUplink and FileDownlink now prepend the buffers (file packets) they send out with the appropriate FW_PACKET_FILE
marker, as it is expected for all F´ data packets.
ComQueue has been updated to handle buffer management according the "Data Return" pattern mentioned above.