You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/how-to/custom-framing.md
+69-9Lines changed: 69 additions & 9 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,17 +2,20 @@
2
2
3
3
This How-To Guide provides a step-by-step guide to implementing a custom framing protocol in F Prime Flight Software.
4
4
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.
6
6
7
7
## Overview
8
8
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).
10
10
11
11
A reference implementation of a custom framing protocol (the "Decaf Protocol") is available in the `fprime-examples` repository:
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`.
16
19
17
20
## Prerequisites: Understanding Subtopologies
18
21
@@ -28,12 +31,29 @@ For more information on working with subtopologies, see the [Subtopologies Guide
28
31
## Flight Software Implementation
29
32
30
33
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.
34
40
35
41
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)).
36
42
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
+
37
57
1.**Define the Framer and Deframer FPP Components**
38
58
39
59
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
108
128
instance framer: MyCustomFramer base id 0x1000
109
129
instance deframer: MyCustomDeframer base id 0x2000
110
130
```
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`:
- **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
+
```
111
156
112
157
5. **(Optional) Implement a Frame Detector**
113
158
114
159
_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)
116
163
117
164
_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`.
119
173
120
174
To use the `Svc.FrameAccumulator`, you need to configure it with a FrameDetector that detects when a frame is present:
121
175
**MyCustomFrameDetector.hpp**
@@ -133,6 +187,8 @@ The following examples will walk through the implementation of a custom framer a
// 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
136
192
// Refer to the Svc.FrameDetector documentation for details on how to implement this
137
193
return Svc::FrameDetector::NO_FRAME_DETECTED;
138
194
}
@@ -170,12 +226,16 @@ class MyCustomFramerDeframer(FramerDeframer):
170
226
def deframe(self, data, no_copy=False):
171
227
# TODO: Implement deframing logic
172
228
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"
173
233
```
174
234
175
235
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:
0 commit comments