rtcm_framer.h
Go to the documentation of this file.
1 /**************************************************************************/ /**
2  * @brief RTCM 3 message framer.
3  * @file
4  ******************************************************************************/
5 
6 #pragma once
7 
8 #include <cstddef> // For size_t
9 #include <cstdint>
10 
11 #include "point_one/fusion_engine/common/portability.h" // For macros.
12 
13 namespace point_one {
14 namespace rtcm {
15 
16 /**
17  * @brief Frame and validate incoming RTCM 3 messages.
18  *
19  * This class locates and validates RTCM 3 messages within a stream of binary
20  * data. Data may be stored in an internally allocated buffer, or in an external
21  * buffer supplied by the user.
22  *
23  * The callback function provided to @ref SetMessageCallback() will be called
24  * each time a complete message is received. Any messages that do not pass the
25  * CRC check, or that are too big to be stored in the data buffer, will be
26  * discarded.
27  *
28  * Example usage:
29  * ```cpp
30  * void MessageReceived(uint16_t message_type, const void* data, size_t data_len) {
31  * ...
32  * }
33  *
34  * RTCMFramer framer(1024);
35  * framer.SetMessageCallback(MessageReceived);
36  * framer.OnData(my_data, my_data_size);
37  * ```
38  */
40  public:
41  using MessageCallback = void (*)(uint16_t, const void*, size_t);
42 
43  /**
44  * @brief Construct a framer instance with no buffer allocated.
45  *
46  * @note
47  * You must call @ref SetBuffer() to assign a buffer, otherwise all incoming
48  * data will be discarded.
49  */
50  RTCMFramer() = default;
51 
52  /**
53  * @brief Construct a framer instance with an internally allocated buffer.
54  *
55  * @param capacity_bytes The maximum framing buffer capacity (in bytes).
56  */
57  explicit RTCMFramer(size_t capacity_bytes)
58  : RTCMFramer(nullptr, capacity_bytes) {}
59 
60  /**
61  * @brief Construct a framer instance with a user-specified buffer.
62  *
63  * @post
64  * `buffer` must exist for the lifetime of this instance.
65  *
66  * @param buffer The framing buffer to use. Set to `nullptr` to allocate a
67  * buffer internally.
68  * @param capacity_bytes The maximum framing buffer capacity (in bytes).
69  */
70  RTCMFramer(void* buffer, size_t capacity_bytes);
71 
72  ~RTCMFramer();
73 
74  // Don't allow copying or moving to avoid issues with managed buffer_.
75  RTCMFramer(const RTCMFramer&) = delete; // Copy constructor
76  RTCMFramer(RTCMFramer&&) = delete; // Move constructor
77  RTCMFramer& operator=(const RTCMFramer&) = delete; // Copy assignment operator
78  RTCMFramer& operator=(RTCMFramer&&) = delete; // Move assignment operator
79 
80  /**
81  * @brief Set the buffer to use for message framing.
82  *
83  * @post
84  * `buffer` must exist for the lifetime of this instance.
85  *
86  * @param buffer The framing buffer to use. Set to `nullptr` to allocate a
87  * buffer internally.
88  * @param capacity_bytes The maximum framing buffer capacity (in bytes).
89  */
90  void SetBuffer(void* buffer, size_t capacity_bytes);
91 
92  /**
93  * @brief Enable/disable warnings for CRC and "message too large" failures.
94  *
95  * This is typically used when the incoming stream has multiple types of
96  * binary content (e.g., interleaved FusionEngine and RTCM messages), and the
97  * RTCM message preamble is expected to appear in the non-RTCM content
98  * occasionally.
99  *
100  * @param enabled If `true`, issue warnings on errors.
101  */
102  void WarnOnError(bool enabled) { warn_on_error_ = enabled; }
103 
104  /**
105  * @brief Specify a function to be called when a message is framed.
106  *
107  * @param callback The function to be called with the message header and a
108  * pointer to the message payload.
109  */
110  void SetMessageCallback(MessageCallback callback) { callback_ = callback; }
111 
112  /**
113  * @brief Reset the framer and discard all pending data.
114  */
115  void Reset();
116 
117  /**
118  * @brief Process incoming data.
119  *
120  * @param buffer A buffer containing data to be framed.
121  * @param length_bytes The number of bytes to be framed.
122  *
123  * @return The total size of all valid, complete messages, or 0 if no messages
124  * were completed.
125  */
126  size_t OnData(const uint8_t* buffer, size_t length_bytes);
127 
128  /**
129  * @brief Get the number of decoded messages.
130  *
131  * @return The number of RTCM messages successfully decoded.
132  */
133  uint32_t GetNumDecodedMessages() const { return decoded_msg_count_; }
134 
135  /**
136  * @brief Get the number of preamble synchronizations that resulted in errors.
137  *
138  * This is not an accurate count of failed messages since the RTCM preamble is
139  * not unique and may appear anywhere in the data stream, but gives an
140  * approximate count.
141  *
142  * @return The number of length or CRC failures found in decoding so far.
143  */
144  uint32_t GetNumErrors() const { return error_count_; }
145 
146  private:
147  enum class State {
148  SYNC = 0,
149  HEADER = 1,
150  DATA = 2,
151  };
152 
153  MessageCallback callback_ = nullptr;
154 
155  bool warn_on_error_ = true;
156  bool is_buffer_managed_ = false;
157  uint8_t* buffer_{nullptr};
158  uint32_t capacity_bytes_{0};
159 
160  State state_{State::SYNC};
161  uint32_t next_byte_index_{0};
162  size_t current_message_size_{0};
163 
164  uint32_t error_count_{0};
165  uint32_t decoded_msg_count_{0};
166 
167  /**
168  * @brief Process a single byte.
169  *
170  * @pre
171  * The byte must be located at `buffer_[next_byte_index_ - 1]`.
172  *
173  * @param quiet If `true`, suppress failure warning messages.
174  *
175  * @return The total size of all valid, complete messages, 0 if no messages
176  * were completed, or <0 CRC or "message too large" error.
177  */
178  int32_t OnByte(bool quiet);
179 
180  /**
181  * @brief Perform a resynchronization operation starting at `buffer_[1]`.
182  *
183  * @return The total size of all valid, complete messages, or 0 if no messages
184  * were completed.
185  */
186  uint32_t Resync();
187 
188  /**
189  * @brief Free the @ref buffer_ if it's being managed internally.
190  */
191  void ClearManagedBuffer();
192 };
193 
194 } // namespace rtcm
195 } // namespace point_one
Library portability helper definitions.
RTCMFramer(size_t capacity_bytes)
Construct a framer instance with an internally allocated buffer.
Definition: rtcm_framer.h:57
#define P1_EXPORT
Definition: portability.h:33
RTCMFramer & operator=(const RTCMFramer &)=delete
void(*)(uint16_t, const void *, size_t) MessageCallback
Definition: rtcm_framer.h:41
Frame and validate incoming RTCM 3 messages.
Definition: rtcm_framer.h:39
uint32_t GetNumDecodedMessages() const
Get the number of decoded messages.
Definition: rtcm_framer.h:133
GNSS signal and frequency type definitions.
Definition: logging.h:38
RTCMFramer(const RTCMFramer &)=delete
RTCMFramer()=default
Construct a framer instance with no buffer allocated.
RTCMFramer(RTCMFramer &&)=delete
RTCMFramer & operator=(RTCMFramer &&)=delete
void SetMessageCallback(MessageCallback callback)
Specify a function to be called when a message is framed.
Definition: rtcm_framer.h:110
void WarnOnError(bool enabled)
Enable/disable warnings for CRC and "message too large" failures.
Definition: rtcm_framer.h:102
uint32_t GetNumErrors() const
Get the number of preamble synchronizations that resulted in errors.
Definition: rtcm_framer.h:144
State
Definition: rtcm_framer.h:147