Thunderbots Project
Loading...
Searching...
No Matches
uart_framing.hpp
1#pragma once
2
3#include <pb_decode.h>
4
5#include <cstdint>
6#include <vector>
7
8#ifdef PLATFORMIO_BUILD
9#include <power_frame_msg_platformio.h>
10#else // PLATFORMIO_BUILD
11#include "proto/message_translation/power_frame_msg.hpp"
12extern "C"
13{
14#include "proto/power_frame_msg.nanopb.h"
15}
16#endif // PLATFORMIO_BUILD
17
18const uint8_t START_END_FLAG_BYTE = 0x00;
19
20namespace
21{
29 uint16_t crc16(const std::vector<uint8_t>& data, uint16_t length)
30 {
31 uint8_t x;
32 uint16_t crc = 0xFFFF;
33 int i = 0;
34
35 while (length--)
36 {
37 x = static_cast<uint8_t>(crc >> 8u) ^ data[i++];
38 x ^= static_cast<uint8_t>(x >> 4u);
39 crc = static_cast<uint16_t>((crc << 8u) ^ (x << 12u) ^ (x << 5u) ^ x);
40 }
41
42 return crc;
43 }
44
52 bool verifyLengthAndCrc(const TbotsProto_PowerFrame& frame)
53 {
54 uint16_t expected_length;
55 std::vector<uint8_t> bytes;
56 switch (frame.which_power_msg)
57 {
58 case TbotsProto_PowerFrame_power_control_tag:
59 expected_length = TbotsProto_PowerPulseControl_size;
60 bytes = serializeToVector(frame.power_msg.power_control);
61 break;
62 case TbotsProto_PowerFrame_power_status_tag:
63 expected_length = TbotsProto_PowerStatus_size;
64 bytes = serializeToVector(frame.power_msg.power_status);
65 break;
66 default:
67 return false;
68 }
69 uint16_t expected_crc = crc16(bytes, static_cast<uint16_t>(frame.length));
70 return frame.crc == expected_crc && frame.length == expected_length;
71 }
72
82 std::vector<uint8_t> cobsEncoding(const std::vector<uint8_t>& to_encode)
83 {
84 auto encoded = std::vector<uint8_t>();
85 encoded.emplace_back(START_END_FLAG_BYTE);
86
87 size_t overhead_location = 1;
88 uint8_t overhead = 0x01;
89
90 for (auto byte : to_encode)
91 {
92 if (byte == START_END_FLAG_BYTE)
93 {
94 encoded.insert(encoded.begin() + overhead_location, overhead);
95 overhead_location = encoded.size();
96 overhead = 0x01;
97 }
98 else
99 {
100 encoded.emplace_back(byte);
101 if (++overhead == 0xFF)
102 {
103 encoded.insert(encoded.begin() + overhead_location, overhead);
104 overhead_location = encoded.size();
105 overhead = 0x01;
106 }
107 }
108 }
109 encoded.insert(encoded.begin() + overhead_location, overhead);
110 encoded.emplace_back(START_END_FLAG_BYTE);
111
112 return encoded;
113 }
114
126 bool cobsDecoding(const std::vector<uint8_t>& to_decode,
127 std::vector<uint8_t>& decoded)
128 {
129 if (to_decode.front() != START_END_FLAG_BYTE ||
130 to_decode.back() != START_END_FLAG_BYTE)
131 {
132 return false;
133 }
134
135 uint16_t i = 1;
136 while (i < to_decode.size())
137 {
138 uint8_t overhead = to_decode[i++];
139 // Check that overhead does not point to past the end of the vector
140 if (overhead + i > to_decode.size())
141 {
142 return false;
143 }
144 // Check that instances of the START_END_FLAG_BYTE are not in the middle of
145 // the vector
146 if (overhead == START_END_FLAG_BYTE && i != to_decode.size())
147 {
148 return false;
149 }
150 for (uint16_t j = 1; i < to_decode.size() && j < overhead; j++)
151 {
152 decoded.emplace_back(to_decode[i++]);
153 }
154 if (overhead < 0xFF && i != to_decode.size() - 1 &&
155 overhead != START_END_FLAG_BYTE)
156 {
157 decoded.emplace_back(START_END_FLAG_BYTE);
158 }
159 }
160
161 return true;
162 }
163} // anonymous namespace
164
173template <typename T>
174TbotsProto_PowerFrame createUartFrame(const T& power_msg)
175{
176 TbotsProto_PowerFrame frame = TbotsProto_PowerFrame_init_default;
177 auto buffer = serializeToVector(power_msg);
178 frame.length = static_cast<uint32_t>(buffer.size());
179 frame.crc = crc16(buffer, static_cast<uint16_t>(frame.length));
180 setPowerMsg(frame, power_msg);
181 return frame;
182}
183
191std::vector<uint8_t> inline marshallUartPacket(const TbotsProto_PowerFrame& frame)
192{
193 auto bytes = serializeToVector(frame);
194 return cobsEncoding(bytes);
195}
196
205bool inline unmarshalUartPacket(const std::vector<uint8_t>& data,
206 TbotsProto_PowerFrame& frame)
207{
208 std::vector<uint8_t> decoded;
209 if (!cobsDecoding(data, decoded))
210 {
211 return false;
212 }
213 if (decoded.size() != TbotsProto_PowerFrame_size)
214 {
215 return false;
216 }
217 frame = TbotsProto_PowerFrame_init_default;
218 pb_istream_t stream =
219 pb_istream_from_buffer(static_cast<uint8_t*>(decoded.data()), decoded.size());
220 if (!pb_decode(&stream, TbotsProto_PowerFrame_fields, &frame))
221 {
222 return false;
223 }
224 return verifyLengthAndCrc(frame);
225}
234template <typename T>
235size_t getMarshalledSize(const T& power_msg)
236{
237 auto frame = createUartFrame(power_msg);
238 auto buffer = serializeToVector(frame);
239 return cobsEncoding(buffer).size();
240}