Skip to content

Commit 1ff13ac

Browse files
authored
Address student feedback for How-To Framing protocol (#4314)
* Address student review feedback for How-To Framing protocol * last couple nits * fix spelling * ugh * add review comments
1 parent a8328b9 commit 1ff13ac

File tree

2 files changed

+70
-9
lines changed

2 files changed

+70
-9
lines changed

.github/actions/spelling/expect.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,7 @@ wrs
736736
wxgui
737737
wxy
738738
Xapian
739+
XBee
739740
xdf
740741
xdffe
741742
xsltproc

docs/how-to/custom-framing.md

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,20 @@
22

33
This How-To Guide provides a step-by-step guide to implementing a custom framing protocol in F Prime Flight Software.
44

5-
The default [F Prime Protocol](../../Svc/FprimeProtocol/docs/sdd.md) is a lightweight protocol used to get development started quickly with a low-overhead communications protocol that the [F Prime GDS](https://github.com/nasa/fprime-gds) understands. However, as projects mature, there may be a need to implement a framing protocol that fits mission requirements. This document provides an overview of how to implement a custom framing protocol in F Prime Flight Software, and how to integrate it with the F Prime GDS.
5+
Modern F´ deployments use the CCSDS protocol by default via the `Svc.ComCcsds` subtopology. The lightweight [F Prime Protocol](../../Svc/FprimeProtocol/docs/sdd.md) (available via `Svc.ComFprime`) is also available as an alternative low-overhead communications protocol that the [F Prime GDS](https://github.com/nasa/fprime-gds) understands. However, some projects choose to implement another framing protocol that fits their mission requirements. This document provides an overview of how to implement a custom framing protocol in F Prime Flight Software, and how to integrate it with the F Prime GDS.
66

77
## Overview
88

9-
This guide demonstrates how to implement a custom framing protocol, referred to here as **MyCustomProtocol**. The protocol defines how data is wrapped (framed) for transmission and how frames are validated and unpacked (deframed) on reception.
9+
This guide demonstrates how to implement a custom framing protocol, referred to here as **MyCustomProtocol**. The protocol defines how data is wrapped (framed) for transmission and how frames are validated and unpacked (deframed) on reception. For a bi-directional framing implementation (uplink and downlink), you will need to implement both a framer and a deframer component. A framer is required for downlink (flight software → GDS). A deframer (and optionally a FrameDetector) is needed for deframing uplink messages (GDS → flight software).
1010

1111
A reference implementation of a custom framing protocol (the "Decaf Protocol") is available in the `fprime-examples` repository:
1212
- [C++ CustomFraming Example](https://github.com/nasa/fprime-examples/tree/devel/FlightExamples/CustomFraming)
1313
- [GDS Plugin Example](https://github.com/nasa/fprime-examples/tree/devel/GdsExamples/gds-plugins/src/framing)
1414

15-
This guide is divided into two main sections: flight software implementation and GDS integration. Note that if you are aiming to integrate with another GDS and do not wish to use the F´ GDS, you can skip the GDS section.
15+
This guide is divided into two main sections: flight software implementation and GDS integration. If you are aiming to integrate with another GDS and do not wish to use the F´ GDS, you can skip the GDS section.
16+
17+
> [!NOTE]
18+
> When using the reference examples, it is recommended to check out the `fprime-examples` repository **at the same release tag** as your F´ core installation to ensure compatibility. You can find which version of F´ you are using with `fprime-util version-check`.
1619
1720
## Prerequisites: Understanding Subtopologies
1821

@@ -28,12 +31,29 @@ For more information on working with subtopologies, see the [Subtopologies Guide
2831
## Flight Software Implementation
2932

3033
To implement a custom framing protocol in F´, will need to implement the following:
31-
- **Framer**: A component that wraps payload data into frames for transmission.
32-
- **Deframer**: A component that unpacks received frames, extracts the payload data, and validate the frame.
33-
- **FrameDetector** (optional): A helper class that detects the start and end of frames in a stream of data, if your transport is stream-based (e.g., TCP, UART).
34+
- **Framer**: An F´ component that wraps payload data into frames for transmission.
35+
- **Deframer**: An F´ component that unpacks received frames, extracts the payload data, and validates the frame.
36+
- **FrameDetector** Helper Class (optional): A C++ helper class (not an F´ component) that detects the start and end of frames in a stream of data, if your transport does not guarantee complete packets (e.g., TCP, UART).
37+
38+
> [!TIP]
39+
> When creating framer/deframer components using `fprime-util new --component`, the recommended settings are to use passive components with events enabled.
3440
3541
The following examples will walk through the implementation of a custom framer and deframer for a hypothetical **MyCustomProtocol** protocol. Implementation details are left to the reader, but examples of such implementations can be found in the [fprime-examples repository](https://github.com/nasa/fprime-examples/tree/devel/FlightExamples/CustomFraming), or within the F´ codebase itself ([Svc.FprimeFramer](../../Svc/FprimeFramer/docs/sdd.md) and [Svc.FprimeDeframer](../../Svc/FprimeDeframer/docs/sdd.md)).
3642

43+
### Pitfalls and Best Practices
44+
45+
Before implementing, consider these best practices:
46+
47+
1. **Centralize Protocol Constants**: Define protocol constants (e.g., start word, header structure, field sizes) in a dedicated `.fpp` types file (e.g., `Types/Types.fpp`). This allows constants like start words, field types, or spacecraft IDs to be reused consistently across your framer, deframer, and frame detector.
48+
49+
2. **Endianness Convention**: F´ serializes all integer types in big-endian by default (network byte order), as defined in `Fw::Serializable`. If your protocol requires little-endian fields, you must specify so during serialization with the `Fw::Endianness::LITTLE` mode, or manually order bytes as needed.
50+
51+
3. **Set the APID in the Deframer**: Your deframer **must** extract and set the APID (Application ID) in the `FrameContext` before emitting packets downstream via `dataOut`. Without this, the `Svc.FprimeRouter` will not know where to route packets to. This is a critical requirement, unless you are also implementing a custom router and define your own requirements (not recommended and outside the scope of this guide).
52+
53+
4. **Payload vs. Frame Structure**: A framing protocol should only define the outer frame structure (headers and trailers). The internal payload structure is determined by the upper-layer protocols and applications that produce and consume the data, not by the framing protocol itself.
54+
55+
### Implementation Steps
56+
3757
1. **Define the Framer and Deframer FPP Components**
3858

3959
Framer and Deframer components should implement the FPP interfaces by including them.
@@ -108,14 +128,48 @@ The following examples will walk through the implementation of a custom framer a
108128
instance framer: MyCustomFramer base id 0x1000
109129
instance deframer: MyCustomDeframer base id 0x2000
110130
```
131+
132+
**Troubleshooting Common Integration Issues**:
133+
134+
After removing the CCSDS subtopology and adding your custom framing components, you may encounter compilation errors:
135+
136+
- **Missing header errors** (e.g., `fatal error: Svc/Subtopologies/ComCcsds/ComCcsdsConfig/FppConstantsAc.hpp: No such file or directory`):
137+
- Remove all mentions of `ComCcsds` from your auto-generated `<DeploymentName>TopologyDefs.hpp` file (located in `<deployment>/Top/`).
138+
- After significant topology changes, you may need to do a clean rebuild with `fprime-util generate --force`
139+
140+
- **Undeclared port enum errors** (e.g., `error: 'Ports_ComPacketQueue' has not been declared`):
141+
- Include the generated port headers in your `<DeploymentName>TopologyDefs.hpp`:
142+
```cpp
143+
#include <MyDeployment/Top/Ports_ComPacketQueueEnumAc.hpp>
144+
#include <MyDeployment/Top/Ports_ComBufferQueueEnumAc.hpp>
145+
```
146+
147+
- **Linker errors** (e.g., `undefined reference to 'vtable for CustomFraming::MyCustomFrameDetector'`):
148+
- Ensure your custom Detector is added as a dependency of your Deframer or deployment, using the `DEPENDS` keyword. In your Deframer's `CMakeLists.txt`, add:
149+
```cmake
150+
register_fprime_module(
151+
[...]
152+
DEPENDS
153+
CustomFraming_DecafFrameDetector # This is a helper module and cannot be resolved by FPP dependencies alone
154+
)
155+
```
111156
112157
5. **(Optional) Implement a Frame Detector**
113158
114159
_When is this not needed?_
115-
If your communications manager component always receives complete frames, you do not need to implement frame detection. This can be the case when using radios with built-in frame synchronization or when another subsystem handles frame delimiting.
160+
If your communications manager component always receives complete frames, you do not need to implement frame detection. This can be the case when using:
161+
- Radios with built-in frame synchronization
162+
- Message-oriented transport-layer protocols where frame boundaries are guaranteed (e.g. UDP)
116163
117164
_When is this needed?_
118-
If your data transport is stream-based (for example, relying on TCP or UART), or if you cannot guarantee that frames will always be received in full, you must implement a mechanism to delimit frames. F Prime provides this capability with the [Svc.FrameAccumulator](../../Svc/FrameAccumulator/docs/sdd.md) component, which uses a circular buffer and a helper `FrameDetector` to identify complete frames in the data stream.
165+
If your data transport is stream-based and does not preserve message boundaries, you must implement a mechanism to delimit frames. Examples include:
166+
- TCP connections (stream-based, no inherent message boundaries)
167+
- UART/serial connections (e.g. UART radios such as XBee)
168+
169+
F Prime provides this capability with the [Svc.FrameAccumulator](../../Svc/FrameAccumulator/docs/sdd.md) component, which uses a circular buffer and a helper `FrameDetector` to identify complete frames in the data stream.
170+
171+
> [!NOTE]
172+
> The `FrameDetector` is a C++ helper class, not an FPP component. It does not have an `.fpp` definition and is used internally by `Svc.FrameAccumulator`.
119173
120174
To use the `Svc.FrameAccumulator`, you need to configure it with a FrameDetector that detects when a frame is present:
121175
**MyCustomFrameDetector.hpp**
@@ -133,6 +187,8 @@ The following examples will walk through the implementation of a custom framer a
133187
// ...existing code...
134188
Svc::FrameDetector::Status MyCustomFrameDetector::detect(const Types::CircularBuffer& data, FwSizeType& size_out) const {
135189
// TODO: Implement frame boundary detection
190+
// This can include searching for start words, validating headers, checking lengths, checking CRC and hashes, etc.
191+
// Utilities exist for CRC under Utils/Hash, and examples are shown in Svc/Ccsds/Utils or in fprime-examples repo
136192
// Refer to the Svc.FrameDetector documentation for details on how to implement this
137193
return Svc::FrameDetector::NO_FRAME_DETECTED;
138194
}
@@ -170,12 +226,16 @@ class MyCustomFramerDeframer(FramerDeframer):
170226
def deframe(self, data, no_copy=False):
171227
# TODO: Implement deframing logic
172228
return packet, leftover_data, discarded_data
229+
230+
def get_name(self):
231+
# TODO: Return the protocol name for selection with `fprime-gds --framing-selection <selection>`
232+
return "MyCustomProtocol"
173233
```
174234

175235
Make sure to [package and install the plugin in your virtual environment](./develop-gds-plugins.md#packaging-and-testing-plugins) for the GDS to be able to load it, then run it:
176236

177237
```
178-
fprime-gds --framing-selection MyCustomFramerDeframer
238+
fprime-gds --framing-selection MyCustomProtocol
179239
```
180240

181241
## References

0 commit comments

Comments
 (0)