Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- [Code](guidelines/code.md)
- [Style](guidelines/style.md)
- [Embedded Development](guidelines/embedded.md)
- [Version Control](guidelines/version-control.md)
- [Communication](guidelines/communication.md)
- [AI Prompting](guidelines/ai-prompting.md)
Expand Down
94 changes: 94 additions & 0 deletions guidelines/embedded.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Embedded Development Guidelines

These guidelines apply to embedded and safety-critical firmware projects. Follow project-
specific rules first (e.g., ArduPilot and JSF style guide), then apply the rules below for any gaps.
When these rules conflict with a project standard, the project standard wins.

## General

- Follow the project code style and keep it consistent within each file.
- Prefer small, focused functions over long procedural blocks.
- Prefer compile-time checksm add run-time checks for safety-critical paths.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Prefer compile-time checksm add run-time checks for safety-critical paths.
- Prefer compile-time checks, and add run-time checks only for safety-critical paths.

- Encapsulate low-level or hardware-specific code behind clear interfaces.
- Do not add unused or commented-out code unless it is justified and documented.

## Core constraints (JSF AV-inspired)

- Keep functions under 200 logical source lines.
- Keep cyclomatic complexity at or below 20 (exceptions only for large switch statements).
- Do not use self-modifying code. (Up to discussion)
- Use ISO/IEC 14882:2017-compliant C++ (C++17) or newer, do not rely on compiler extensions.
- When possible, pass the compiler flag to disable extensions (e.g., `-fno-gnu-extensions` for GCC/Clang).
- Use only the basic C++ source character set, do not use trigraphs, digraphs, multibyte
characters, or wide string literals.

## Preprocessor rules

- Only use `#pragma once` and `#include`
- Do not use `#define` for inline macros or constants, use `inline`, `const`, `constexpr`, or `consteval` instead.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assumes that C++ only code is being used, do we want to broad this for maybe Rust/C?

- `#include` only header files (template implementations may be included by headers).

## Header and implementation structure

- `.h` for headers, `.cpp` for implementations.
- Headers contain declarations only, no non-const data or function definitions.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Headers contain declarations only, no non-const data or function definitions.
- Headers should contain declarations only; by default, they must not contain non-const data or function definitions, except for:
- inline functions
- templates
- `constexpr` or `consteval` definitions

- Exceptions: inline functions and templates.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Exceptions: inline functions and templates.

Join this with suggestion above

- Each `.cpp` includes the headers that define all inline functions, types, and templates it uses.
- Header files should include only what they need, keep implementation-only includes in `.cpp`.

## Style and naming

- Avoid tabs, indent consistently (use 2 or four spaces, be consistent with the project).
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Avoid tabs, indent consistently (use 2 or four spaces, be consistent with the project).
- Avoid tabs; use spaces for indentation. The exact width (2 or 4 spaces) must follow the project standard and remain consistent within a file.

- Use braces for all control statements.
- Braces for blocks on their own lines and aligned.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this include starting braces, and braces that are part of block continuations?

I'm personally more inclined to

if (condition) {
    ...
} else {
    ...
}

than

if (condition)
{
    ...
}
else
{
    ...
}

- No spaces around `.` or `->`, and no spaces around unary operators.
- Naming rules follow the project standard. If none is defined, use:
- `lower_snake_case` for functions and variables
- `UpperCamel_Case` for classes, structs, enums, and typedefs (e.g., `AP_Compass`)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a valid UpperCamelCase (PascalCase); it is a mixture of naming conventions.
Unless dictated by a specific project style, we should avoid this and try to maintain a single, consistent naming convention.
Mixing conventions or having different rules tends to reduce readability and maintainability, as seen in APIs such as OpenGL.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `UpperCamel_Case` for classes, structs, enums, and typedefs (e.g., `AP_Compass`)
- `UpperCamelCase` for classes, structs, enums, and typedefs
- Acronyms can be separated by underscores (e.g. `AP_AdvancedFailsafe`)

- lowercase constants and enumerators
- uppercase acronyms inside identifiers (e.g., `GCS_MAVLink`)
- use underscore for private properties
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is against AV Rule 47

Image

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we expect to use lots of libraries in our embedded code?
I suspect the compiler would catch any name collisions caused by this, and it seems potentially valuable to indicate throughout the code when something is private 🤷‍♂️

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- use underscore for private properties
- use a preceding underscore for private properties (e.g. `_internal_var`)

Not sure if this was the intent (or double preceding underscore, or one before + one after, etc), but it should be clarified.


## Class design

- Use `struct` for plain data, `class` for invariants and encapsulation.
- Keep data members private, avoid public/protected data in classes.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of C++ references tends to use member variables/functions to address properties and methods.

Suggested change
- Keep data members private, avoid public/protected data in classes.
- Keep **member variables** private; avoid use of public or protected **member variables** in C++ classes.

- Declare member functions as `const` by default.
- Use `constexpr` or `consteval` for functions and variables that can be evaluated at compile time.
- Do not call virtual functions from constructors or destructors.
- Use member initializer lists for non-static members.
- Declare copy/assignment when owning pointers or nontrivial destructors.
- Base classes with virtual functions must have virtual destructors.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Base classes with virtual functions must have virtual destructors.
- Base classes with virtual functions must have virtual destructors, unless the class is
explicitly marked as `final`.


## Documentation

- Document units in names or comments for physical quantities.
- Prefer doxygen-style comments for C++ projects.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we also have preferences for other languages?


## Embedded-specific constraints

- Avoid the C++ standard library (`std::vector`, `std::string`, `std::unordered_map`)
unless the platform and toolchain explicitly support it and memory costs are measured.
- Prefer fixed-size arrays, if dynamic containers are needed, use project-approved
alternatives.
- Avoid bit fields, use plain booleans.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accordingly to JSF AV Rules [154, 155, 156]

Suggested change
- Avoid bit fields, use plain booleans.
- Avoid using bit-fields for data packing or space optimization.
- For general state and control logic, prefer plain boolean or integer members over bit-fields.
- Bit-fields may be used only when required for hardware register mapping or protocol conformance, and shall use explicitly unsigned integral or enumeration types.
- Do not rely on implementation-defined bit-field behavior.

- Remove dead code, do not comment out unused code.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it acceptable/recommended to include "TODO" comments in the place of code that is not yet in use elsewhere?

- Prefer multiplication over division for unit conversions.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How strong is this preference / how spelled out should conversions be?
As an example, should converting from degrees to radians be angle_deg * tau / 360, or angle_deg * 0.01745329251 (which then likely requires an explanatory comment), or something else? Or are they considered equivalent because the conversion factor is likely evaluated at compile time?

Suggested change
- Prefer multiplication over division for unit conversions.
- Prefer multiplication over division for unit conversions, unless it is less clear.

- Use `constexpr` for compile-time constants and lookup tables, use `consteval` (C++20+)
when a value must be evaluated at compile time.

## Testing and verification

- Tests must exercise safety-critical paths and any new hardware interactions.
- Add logging or assertions that can be compiled out for production builds.
- Ensure CI covers at least one supported target and simulator when available.

## Portability and build

- Target multiple embedded platforms when feasible, avoid vendor-locked toolchains.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Target multiple embedded platforms when feasible, avoid vendor-locked toolchains.
- Target multiple embedded platforms when feasible.
- Avoid vendor-locked toolchains.

- Make dependencies and build steps explicit and reproducible.

## References

- JSF Air Vehicle C++ Coding Standards (Stroustrup): https://www.stroustrup.com/JSF-AV-rules.pdf
- ArduPilot Style Guide: https://ardupilot.org/dev/docs/style-guide.html
2 changes: 1 addition & 1 deletion guidelines/style.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Style Guidelines

When contributing to projects owned by other entities, adhere to any guidelines set forth by those entities (eg. ardupilot). The style guidelines for projects owned by Blue Robotics is documented here.
When contributing to projects owned by other entities, adhere to any guidelines set forth by those entities (eg. ArduPilot). The style guidelines for projects owned by Blue Robotics is documented here.

## Code

Expand Down