View on GitHub

Flight Software & Embedded Systems Framework

F´ Numerical Types

On physical hardware, numerical types have a size in bits. The sizes of these integers are either explicitly set by the programmer or implicitly set by the compiler. i.e. uint32_t is explicitly 32-bits whereas int is implicitly set by the compiler. Flight software practice encourages use of explicitly sized types because there is less risk of an unintentional overflow when using explicitly sized types. However, in-practice it is nice to also use logical types that represent concepts in the system (e.g. size) and are configured to use a specific size as determined by the platform.

This document describes: fixed-width types and logical types.

Fixed Width Types

In F´, fixed width types map to the standard definitions either in the C standard or in the stdint.h header as seen below. Since platforms are not guaranteed to support all types (e.g. 64bits integers) these types can be turned off by setting a configuration field to 0 in the platform-supplied PlatformTypes.h header. These types are on by default and users must turn off types their compiler or platform does not support.

F´ Type Equivalent PlatformTypes.h Configuration Field
I8 int8_t n/a
I16 int16_t FW_HAS_16_BIT
I32 int32_t FW_HAS_32_BIT
I64 int64_t FW_HAS_64_BIT
U8 uint8_t n/a
U16 uint16_t FW_HAS_16_BIT
U32 uint32_t FW_HAS_32_BIT
U64 uint64_t FW_HAS_64_BIT
F32 float n/a
F64 double FW_HAS_F64

Platform developers should include stdint.h or equivalent in their PlatformTypes.h to ensure F´ can construct a mapping from the C equivalents to the F´ type. If for some reason that header does not exist or does not define all types, then developers must define the missing C equivalent types directly in that header.

To print these types, users may use the standard C++ PRI macros as shown described: https://cplusplus.com/reference/cinttypes/.

The limits of these types can be obtained by using std::numeric_limits<T>::min() and std::numeric_limits<T>::min() for the defined type T.

U32 value = 10;
U32 my_max = std::numeric_limits<U32>::max();
printf("My value: %" PRIu32 " could store a max of: %" PRIu32 "\n", value, my_max);

F´ Logical Integer Type Design

Typically, in flight software we try to use fixed-sized types wherever possible as this produces consistent results across platforms. However, when building components for use on multiple different architectures it is nice to be able to use logical integer types whose exact widths are determined by the platform and project instead of needing to pick a one-size-fits-all fixed with type. For example, representing a size as an unsigned 64-bit integer is logical on some systems that have 64-bit data widths, but will not compile on systems that do not define 64-bit integers at all (8-bit systems often lack this data size).

Thus, for these logical types the actual data size needs to be configured. This configuration needs to be available from two sources: a given project, and a given platform. Platforms need to set the idea size for these types, and projects need to be able to control these sizes when operating across multiple platforms.

It is important to check against type limits when using these types to ensure compatibility across systems.

Platform Configured Types

Platform developers must define the following logical types in the PlatformTypes.h header provided alongside their CMake platform and toolchain files. Each type also defines a format specifier for use with the printf family of functions.

Platform Logical Type Format Specifier Notes
PlatformIndexType PRI_PlatformIndexType Ports indices
PlatformSizeType PRI_PlatformSizeType Sizes
PlatformPointerCastType PRI_PlatformPointerCastType Pointers stored as integers
PlatformAssertArgType PRI_PlatformAssertArgType Argument to FW_ASSERT
PlatformIntType PRI_PlatformIntType Deprecated (see note)
PlatformUIntType PRI_PlatformUIntType Deprecated (see note)

A complete definition of each type for a given platform must be supplied within PlatformTypes.h as shown in the example below. Notice the type is defined along with a format specifier.

typedef int32_t PlatformIndexType;
#define PRI_PlatformIndexType PRId32
...

Limits for these types are obtained using the std::numeric_limits<T>::min() and std::numeric_limits<T>::max() constants defined in the limits header.

In order to print these types, developers can use the following example as a basis for using the PRI_* macros. This example also shows the use of the type’s minimum limit.

PlatformIndexType index = 3;
// Print the above index type, and the minimum value supported by the same type
printf("Index %" PRI_PlatformIndexType ". Min %" PRI_PlatformIndexType, index, std::numeric_limits<PlatformIndexType>::min());

Note: in order for F´ to compile without warnings it is necessary that each of the platform types are elements in the set of integers supplied by the C standard integers header (stdint.h). i.e. each type must be an int8_t, int16_t, int32_t, int64_t or unsigned variants. On some compilers int and unsigned int are not members of that set and on those platforms it is imperative that both PlatformIntType and PlatformUIntType be set to some fixed size type instead.

Configurable Integer Types

Project may configure the framework types that the framework and components use for implementation through FpConfig.h. The default configuration as supplied with F´ uses the above platform types where applicable.

Framework Type Logical Usage Default Format Specifier Notes
FwIndexType Port indices PlatformIndexType PRI_FwIndexType  
FwSizeType Sizes PlatformSizeType PRI_FwSizeType  
FwAssertArgType Arguments to asserts PlatformAssertArgType PRI_FwAssertArgType  

There is also a set of framework types that are used across F´ deployments and specifically interact with ground data systems. These GDS types have defaults based on configurable platform independent fixed-widths as shown below:

GDS Type Logical Usage Default Format Specifier
FwBuffSizeType Fw::Buffer sizes U16 PRI_FwBuffSizeType
FwEnumStoreType Enumeration values I32 PRI_FwEnumStoreType
FwTimeBaseStoreType Time base U16 PRI_FwTimeBaseStoreType
FwTimeContextStoreType Time context U8 PRI_FwTimeContextStoreType
FwPacketDescriptorType F´ packet descriptor field U32 PRI_FwPacketDescriptorType
FwOpcodeType F´ command opcodes U32 PRI_FwOpcodeType
FwChanIdType F´ channel ids U32 PRI_FwChanIdType
FwEventIdType F´ event ids U32 PRI_FwEventIdType
FwPrmIdType F´ parameter ids U32 PRI_FwPrmIdType
FwTlmPacketizeIdType F´ telemetry packet ids U16 PRI_FwTlmPacketizeIdType

Note: the F´ GDS expects the above types to use their default setting. Users intending to use the F´ GDS should not stray from the above definitions.

All defaults can be overridden via project specific configuration supplying a custom FpConfig.h. A complete definition of a framework/GDS type in FpConfig.h would look like:

#include <BasicTypes.hpp>
...
typedef U32 FwSizeType;
#define PRI_FwSizeType PRIu32
...