View on GitHub

Flight Software & Embedded Systems Framework

Recommended F′ Development Process

The purpose of this guide is to layout the standard F´ development process. This is the process used by most developers who use F´ and, as such, many of the F´ tools are written to support the stages of the process. This guild will walk through each step in this process.

The process:

  1. High Level Design: Draft high level requirements and architecture.
  2. Setup Deployment: Setup project F´ deployment
  3. Develop Components: Create individual project components
  4. Assemble Topology: Compose a F´ deployment from individual components
  5. Integration Testing: Verify high-level project behaviors

High Level Design

The first step of the development process is to establish the high-level design for the project. This involves specifying system-level requirements and a block diagram that represents the key system functionality. Once complete the project should break this functionality into discrete units of functionality that represent the system. In addition, the interface between these units should be defined. The units of functionality are Components and the interfaces are further broken down into discrete call or actions through that interface. These are F´ ports. The full design of the system of components and ports is the Topology. See: Ports Components and Topologies

Next, the project should review the components provided by the F´ framework to see what functionality can be inherited for free. This usually consists of the basic command and data handling components, the Os layer, drivers, and other Svc components. Where possible, these components should be used as-is to support a project to minimize extra work, but these may be cloned-and-owned if they fall short of project requirements.

The project now has a list of what components they must provide, and what they will inherit.

Setup Deployment

The next step for most projects is to prepare for development. This means getting enough of a deployment setup such that the developers can be assigned components and ports to implement, and test within a working deployment.

There are two options for creating a deployment:

You can create an in-tree deployment, where a deployment is created within the F´ git repository. This is convenient and requires minimal setup, but placing your code within the F´ source tree can make it harder to update F´ in the future if the project wants to take advantage of future bug fixes and features. To create a in-tree deployment, the Ref application can be copied and used as a starting point.

Another option is creating an standalone deployment, where the deployment is setup by itself and points to a F´ installation. This requires more upfront work to setup, but provides the benefit of separating mission code from F´ framework code.

The layout for a git repository for a standalone repository might look something like:

mission
├── mission_deployment_1
├── fprime (git submodule to fprime repository)
├── ...
└── library (git submodule to an external library)

After creating the project layout, an external deployments can also be created by coping the Ref application.

After copying the Ref app, both in-tree and standalone deployments need to create and modify a settings.ini file in the root of the deployment to set the deployment toolchain, library locations, and for standalone deployments, the location of the F´ framework.

For details on configuring the settings.ini file, see the user guide page.

Develop Ports and Components

Next, each developer is typically assigned a set of components to develop. This development starts with the ports that are defined to be used by the component, and then the component itself. This development is described in the following sections.

Design and Requirements

Using the high level requirements, the developer should define requirements for an individual component. These requirements should define the behaviors of the component, as well as the interfaces with other components.

Creating a Port

Once the interfaces between components have been defined, ports should be created to implement those interfaces.

It’s recommended that ports are kept in their own directories separate from components.

To create a new port:

  1. If necessary, create new port directory
  2. Create a new port *Ai.xml file, possibly by copying from an existing port.
  3. Add the new port xml file to SOURCE_FILES in the CMakeLists.txt file in the directory
  4. If necessary, add port directory to the deployment’s cmake file with add_fprime_subdirectory.

Creating a Component Definition

The first step in creating a component is to create the component xml definition, which defines which interfaces it implements, what commands it supports, which telemetry it provides, and what events it produces.

To create a new component definition:

  1. Create a new component directory
  2. Create a new component *Ai.xml file, possibly by copying from an existing component.
  3. Optional, create a commands xml file for GDS commands and include it in the component xml file.
  4. Optional, create an events xml file and include it in the component xml file.
  5. Optional, create a telemetry xml for telemetry channels and include it in the component xml file.
  6. Create a component CMakeLists.txt test file and add the component xml file to SOURCE_FILES variable in the file.
  7. Add component directory to the deployment’s cmake file with add_fprime_subdirectory.

Component Implementation

Next, the developer typically runs fprime-util impl to produce -template files of the hand-coded .cpp and .hpp files. These can be used as a basis for implementation with all the stubs in place for the developer to implement the design. Developers then fill in these files and stubs with an implementation that supports the functionality of the design.

The component can then be built as development proceeds to look for errors. Ports are entirely autogenerated and do not need an implementation.

Component Unit Testing

Along with implementation, unit tests can be templated and implemented to test against the requirements of the component. These should be developed an run often to ensure the implemented component works.

To add unit tests to a component:

  1. Create a test directory within the component (usually called test).
  2. Run fprime-util impl --ut to generate unit testing code skeleton
  3. Add unit test sources to UT_SOURCE_FILES and register unit tests with register_fprime_ut() in the component CMakeLists.txt.
  4. Run fprime-util check in the component directory to run unit tests.

Assemble Topology

As components are completed, it is helpful to add them to the topology. As more components are completed, the topology is slowly built up over time. This can enable integration tests early on in the project. The full deployment should be built at this stage to ensure that there are no errors.

To add a component to the topology:

  1. In the topology *Ai.xml file
    • Import the component *Ai.xml xml file.
    • Instantiate the component as many time as necessary.
    • Connect component output ports with the corresponding input port and vice versa.
  2. In the topology Components.hpp file, declare the component with the same name as the topology xml file.
  3. In the topology Topology.cpp file:
    • Instantiate the component.
    • Call the component’s init function.
    • If additional setup is required, call a user defined setup function.
    • If using commands, register component’s commands.
    • If using health checking, add component to ping entries.
    • If using an active component, start component with start function and call exit when exiting.

Integration Testing

As the topology comes together, it is helpful to write system level tests for subsystems of the overall deployment. This makes sure that as a system, top-level requirements are met.

The fprime-gds has a python API that can be used to write integration test cases, supporting sending commands, checking for events, and getting telemetry channel readings. To get started writing integration test, check out the GDS integration test guide.

Conclusion

This guide was an overview of the workflow most F´ developers follow, from the start to completion of a project. These workflows can be applied to any F´ project and should hopefully provide the smoothest development experience.