blob: 63138a86df11bfa0a00e9b0d644f86fe39a78cd8 [file] [log] [blame]
Brian Silvermanbfbbe872019-02-10 18:00:57 -08001#include "y2019/jevois/uart.h"
2
Brian Silverman2eb89762019-02-17 15:16:37 -08003#include <array>
4
Brian Silverman2eb89762019-02-17 15:16:37 -08005#include "aos/util/bitpacking.h"
6#include "third_party/GSL/include/gsl/gsl"
7#include "y2019/jevois/jevois_crc.h"
Brian Silvermanfdfb3132019-02-24 15:27:27 -08008#ifdef __linux__
9#include "aos/logging/logging.h"
10#else
11#define CHECK(...)
12#define CHECK_GE(...)
13#endif
Brian Silverman2eb89762019-02-17 15:16:37 -080014
Brian Silvermanbfbbe872019-02-10 18:00:57 -080015namespace frc971 {
16namespace jevois {
17
Brian Silvermanc41fb862019-03-02 21:14:46 -080018UartToTeensyBuffer UartPackToTeensy(const CameraFrame &message) {
Brian Silverman2eb89762019-02-17 15:16:37 -080019 std::array<char, uart_to_teensy_size()> buffer;
20 gsl::span<char> remaining_space = buffer;
Brian Silvermana1e4d332019-02-17 22:53:13 -080021 remaining_space[0] = message.targets.size();
22 remaining_space = remaining_space.subspan(1);
23 for (size_t i = 0; i < 3; ++i) {
24 if (i < message.targets.size()) {
25 memcpy(remaining_space.data(), &message.targets[i].distance,
26 sizeof(float));
27 remaining_space = remaining_space.subspan(sizeof(float));
28 memcpy(remaining_space.data(), &message.targets[i].height, sizeof(float));
29 remaining_space = remaining_space.subspan(sizeof(float));
30 memcpy(remaining_space.data(), &message.targets[i].heading,
31 sizeof(float));
32 remaining_space = remaining_space.subspan(sizeof(float));
33 memcpy(remaining_space.data(), &message.targets[i].skew, sizeof(float));
34 remaining_space = remaining_space.subspan(sizeof(float));
35 } else {
36 remaining_space = remaining_space.subspan(sizeof(float) * 4);
37 }
Brian Silverman2eb89762019-02-17 15:16:37 -080038 }
39 remaining_space[0] = message.age.count();
40 remaining_space = remaining_space.subspan(1);
41 {
42 uint16_t crc = jevois_crc_init();
43 crc = jevois_crc_update(crc, buffer.data(),
44 buffer.size() - remaining_space.size());
45 crc = jevois_crc_finalize(crc);
46 CHECK_GE(static_cast<size_t>(remaining_space.size()), sizeof(crc));
47 memcpy(&remaining_space[0], &crc, sizeof(crc));
48 remaining_space = remaining_space.subspan(sizeof(crc));
49 }
50 CHECK(remaining_space.empty());
51 UartToTeensyBuffer result;
52 result.set_size(
53 CobsEncode<uart_to_teensy_size()>(buffer, result.mutable_backing_array())
54 .size());
55 return result;
56}
57
Brian Silvermanc41fb862019-03-02 21:14:46 -080058tl::optional<CameraFrame> UartUnpackToTeensy(gsl::span<const char> encoded_buffer) {
Brian Silverman2eb89762019-02-17 15:16:37 -080059 std::array<char, uart_to_teensy_size()> buffer;
60 if (static_cast<size_t>(
61 CobsDecode<uart_to_teensy_size()>(encoded_buffer, &buffer).size()) !=
62 buffer.size()) {
63 return tl::nullopt;
64 }
65
Brian Silvermanc41fb862019-03-02 21:14:46 -080066 CameraFrame message;
Brian Silverman2eb89762019-02-17 15:16:37 -080067 gsl::span<const char> remaining_input = buffer;
Brian Silvermana1e4d332019-02-17 22:53:13 -080068 const int number_targets = remaining_input[0];
69 remaining_input = remaining_input.subspan(1);
Brian Silverman2eb89762019-02-17 15:16:37 -080070 for (int i = 0; i < 3; ++i) {
Brian Silvermana1e4d332019-02-17 22:53:13 -080071 if (i < number_targets) {
72 message.targets.push_back({});
73 Target *const target = &message.targets.back();
74 memcpy(&target->distance, remaining_input.data(), sizeof(float));
75 remaining_input = remaining_input.subspan(sizeof(float));
76 memcpy(&target->height, remaining_input.data(), sizeof(float));
77 remaining_input = remaining_input.subspan(sizeof(float));
78 memcpy(&target->heading, remaining_input.data(), sizeof(float));
79 remaining_input = remaining_input.subspan(sizeof(float));
80 memcpy(&target->skew, remaining_input.data(), sizeof(float));
81 remaining_input = remaining_input.subspan(sizeof(float));
82 } else {
83 remaining_input = remaining_input.subspan(sizeof(float) * 4);
84 }
Brian Silverman2eb89762019-02-17 15:16:37 -080085 }
86 message.age = camera_duration(remaining_input[0]);
87 remaining_input = remaining_input.subspan(1);
88 {
89 uint16_t calculated_crc = jevois_crc_init();
90 calculated_crc = jevois_crc_update(calculated_crc, buffer.data(),
91 buffer.size() - remaining_input.size());
92 calculated_crc = jevois_crc_finalize(calculated_crc);
93 uint16_t received_crc;
94 CHECK_GE(static_cast<size_t>(remaining_input.size()), sizeof(received_crc));
95 memcpy(&received_crc, &remaining_input[0], sizeof(received_crc));
96 remaining_input = remaining_input.subspan(sizeof(received_crc));
97 CHECK(remaining_input.empty());
98 if (calculated_crc != received_crc) {
99 return tl::nullopt;
100 }
101 }
102 return message;
103}
104
105UartToCameraBuffer UartPackToCamera(const CameraCalibration &message) {
106 std::array<char, uart_to_camera_size()> buffer;
107 gsl::span<char> remaining_space = buffer;
108 for (int i = 0; i < 3; ++i) {
109 for (int j = 0; j < 4; ++j) {
110 memcpy(remaining_space.data(), &message.calibration(i, j), sizeof(float));
111 remaining_space = remaining_space.subspan(sizeof(float));
112 }
113 }
114 {
115 const int64_t teensy_now = message.teensy_now.time_since_epoch().count();
116 memcpy(remaining_space.data(), &teensy_now, sizeof(teensy_now));
117 remaining_space = remaining_space.subspan(sizeof(teensy_now));
118 }
119 {
120 const int64_t realtime_now =
121 message.realtime_now.time_since_epoch().count();
122 memcpy(remaining_space.data(), &realtime_now, sizeof(realtime_now));
123 remaining_space = remaining_space.subspan(sizeof(realtime_now));
124 }
125 memcpy(remaining_space.data(), &message.camera_command, 1);
126 remaining_space = remaining_space.subspan(1);
127 {
128 uint16_t crc = jevois_crc_init();
129 crc = jevois_crc_update(crc, buffer.data(),
130 buffer.size() - remaining_space.size());
131 crc = jevois_crc_finalize(crc);
132 CHECK_GE(static_cast<size_t>(remaining_space.size()), sizeof(crc));
133 memcpy(&remaining_space[0], &crc, sizeof(crc));
134 remaining_space = remaining_space.subspan(sizeof(crc));
135 }
136 CHECK(remaining_space.empty());
137 UartToCameraBuffer result;
138 result.set_size(
139 CobsEncode<uart_to_camera_size()>(buffer, result.mutable_backing_array())
140 .size());
141 return result;
142}
Brian Silvermanbfbbe872019-02-10 18:00:57 -0800143
144tl::optional<CameraCalibration> UartUnpackToCamera(
Parker Schuhd68e1b02019-02-22 20:59:16 -0800145 gsl::span<const char> encoded_buffer) {
Brian Silverman2eb89762019-02-17 15:16:37 -0800146 std::array<char, uart_to_camera_size()> buffer;
147 if (static_cast<size_t>(
148 CobsDecode<uart_to_camera_size()>(encoded_buffer, &buffer).size()) !=
149 buffer.size()) {
150 return tl::nullopt;
151 }
152
153 CameraCalibration message;
154 gsl::span<const char> remaining_input = buffer;
155 for (int i = 0; i < 3; ++i) {
156 for (int j = 0; j < 4; ++j) {
157 memcpy(&message.calibration(i, j), remaining_input.data(), sizeof(float));
158 remaining_input = remaining_input.subspan(sizeof(float));
159 }
160 }
161 {
162 int64_t teensy_now;
163 memcpy(&teensy_now, remaining_input.data(), sizeof(teensy_now));
164 message.teensy_now = aos::monotonic_clock::time_point(
165 aos::monotonic_clock::duration(teensy_now));
166 remaining_input = remaining_input.subspan(sizeof(teensy_now));
167 }
168 {
169 int64_t realtime_now;
170 memcpy(&realtime_now, remaining_input.data(), sizeof(realtime_now));
171 message.realtime_now = aos::realtime_clock::time_point(
172 aos::realtime_clock::duration(realtime_now));
173 remaining_input = remaining_input.subspan(sizeof(realtime_now));
174 }
175 memcpy(&message.camera_command, remaining_input.data(), 1);
176 remaining_input = remaining_input.subspan(1);
177 {
178 uint16_t calculated_crc = jevois_crc_init();
179 calculated_crc = jevois_crc_update(calculated_crc, buffer.data(),
180 buffer.size() - remaining_input.size());
181 calculated_crc = jevois_crc_finalize(calculated_crc);
182 uint16_t received_crc;
183 CHECK_GE(static_cast<size_t>(remaining_input.size()), sizeof(received_crc));
184 memcpy(&received_crc, &remaining_input[0], sizeof(received_crc));
185 remaining_input = remaining_input.subspan(sizeof(received_crc));
186 CHECK(remaining_input.empty());
187 if (calculated_crc != received_crc) {
188 return tl::nullopt;
189 }
190 }
191 return message;
Brian Silvermanbfbbe872019-02-10 18:00:57 -0800192}
193
194} // namespace jevois
195} // namespace frc971