When contributing to F´ it is important to understand the style guidelines that F´ uses across the various products provided by the team. The information in this guide may not be complete and will evolve as the project continues. When unclear, follow reasonable conventions for the language at hand.
Note: These guidelines are for submissions to the F´ framework. Projects using F´ should adapt them as needed.
F´ is a flight software framework. Flight software is embedded software intended to run on "flight systems" like satellites, spacecraft, instruments, and more. Reliability is one of the most important goals of flight software since these systems are often operating for long durations without the option to service failing software. As such, contributions should be easy to read and easy to review. Remember, complexity and optimization sometimes come at the cost of readability or maintainability and that can mean simpler solutions are more appropriate.
C++ in F´ is written primarily following the embedded C++ style with some notable deviations. In addition, F´ follows the JPL Coding Standards as adapted from C. C++ is written under the C++11 standard, however; some C++11 features are avoided to support some incomplete C++11 implementations. Code format is based on the clang-format Chromium style. There are also a number of "rules-of-thumb" that C++ implementors should know.
F´ is written with a modified embedded C++ style. Please note, unit test implementations often disregard these requirements as they run off-platform in a development context. The core points of embedded C++ that F´ uses are:
- No exceptions, code must compile with
-fno-exceptions
- No uses of templates nor the Standard Template Library
- No typeid or run-time type information
F´ has a few rules that deviate from the embedded C++ standard. This is done to increase safety, increase readability, and enable modern C++ development. These deviations are:
- Use namespaces to reduce naming conflicts.
- Use
std::numeric_limits
for mix/max values. Template implementations ofstd::numeric_limits
have been approved. - Use
static_cast
,reinterpret_cast
, andconst_cast
instead of dangerous C-style anddynamic_cast
casting. - Limited use of multiple inheritance and virtual base classes are permitted. See rules of thumb.
There are additional rules from the software's heritage as NASA/JPL Flight Software (see Power of 10 Rules ) and the framework itself. The guidelines were adapted from C guidelines and are summarized below:
- No recursion; No GOTOs
- Loops must have a fixed-bound
- No dynamic memory allocation after initialization
- Use
FW_ASSERT
to validate function inputs and computation - Restrict data to the smallest necessary scope
- Check function return values or explicit discard with
(void)
- Avoid the preprocessor and especially complex uses of the preprocessor
- Prefer
Fw
andOs
implementations. e.g. useFW_ASSERT
andOs::Mutex
overcassert
andstd::mutex
- Compile without warnings, errors, and static analysis failures (e.g. pass continuous integration)
- Do not use
Os::Task::delay
to synchronize between threads - Explicit enumeration values should be specified for all values or none at all
F´ has been updated to support C++11. Some C++11 implementations are incomplete requiring some deviations from C++11. Thus, there are some things that developers should be aware of when using C++11 features:
- Many C++11 features use templates under the hood. Prefer
Fw
andOs
implementations for these features. - Use of
std::atomic
is known to not work in some cases. Use is avoided.
F´ uses ClangFormat based on Chromium. A .clang-format
file is supplied
at the root of the repository. The fprime-tools command line utility
(>v3.1.1) provides a command wrapping around clang-format. This utility is the preferred way to do formatting because it
handles the PRIVATE
, PROTECTED
, and STATIC
access modifiers used to enable white-box unit testing in F'. See fprime-util format --help
for instructions. New submissions should attempt to format appropriately.
This section will document rules of thumb when developing F´ C++. These augment the formal guidelines to help users develop code that fits well with the entirety of F´.
Components need to be documented through an Software Description Documents (SDD) placed in a docs
subfolder. This SDD
should capture:
- Requirements
- Design
- Implementation and Usage Notes
C++ documentation is generated using doxygen. Doxygen-style comments should be used to annotate functions and variables. C++ APIs and libraries must be documented to produces usable doxygen documentation. Components should be documented in a similar fashion but the SDD captures the primary documentation for components.
Software should operate correctly in the event of off-nominal behavior. Asserts and events can be used to handle and/or
report these occurrences. Runtime asserts (i.e. FW_ASSERT
) are used to ensure software integrity and assumptions.
These are used to ensure that arguments passed to functions are within bounds, return values make since, and other
confidence checks. Runtime assertions should never be used to validate user inputs nor results of hardware interaction
as these may cause errors outside software control.
In these cases, an event should be emitted to report the error, and the software should appropriately continue execution even in the case of erroneous input. The severity of the event emitted should be determined by the following rules:
WARNING_LO
events reflect issues localized to this component where recovery is possible.WARNING_HI
events reflect issues affecting the larger system where recovery is possible.FATAL
events reflect issues where recovery is not possible. The system is typically restarted in this case.WARNING_HI
andFATAL
events must be documented in the SDD and approved as part of the submission review.
Many of F´ constructs are required to inherit from an autocoded class that then inherits from framework base classes. This can present a problem as this precludes inheritance from other structures. Thus limited multiple inheritance is permitted. Basic guidelines are presented here, however; the use of multiple-inheritance will likely be discussed during the submission review.
- Only use multiple-inheritance when absolutely required
- Avoid inheritance from more than one hand-coded class
- Avoid inheritance from hand-coded descendants of autocoded classes and parents (e.g.
Fw::PortBase
andFw::PassiveComponentBase
) not. i.e avoid inheritance from other Components, Ports, or classes that do. - Avoid multiple inheritance paths that derive from a common base class a.k.a the diamond problem
Normal usage for multiple and virtual types of inheritance in F´ is to set up interfaces as is often done in Java. This consists of a virtual C++ base class defining only functions. An F´ class or component would then use multiple-inheritance to inherit those function definitions with the intent of implementing them. This can be used to bridge autocoded F´ functionality and C++ functionality. For example, a component can supply F´ port call functionality to supporting classes through this style of interface.
Python code is much easier as it is provided by the black formatter. Python code must pass a black format check. To
format code using black, install black per the Python Development Guide and run black <path to code>
.