STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
DiabloPacketUtils.cpp
Go to the documentation of this file.
1#include "DiabloPacketUtils.h"
2#include "daq-protocol.h"
3#include <cstring> // For memcpy
4#include <cstddef> // For size_t
5
6namespace daq {
7
8//==============================================================================
9// PACKET SERIALIZATION IMPLEMENTATIONS
10//==============================================================================
11
12
13size_t create_board_heartbeat_packet(const BoardHeartbeatPacket &data,
14 uint32_t timestamp_ms,
15 uint8_t *buffer, size_t buffer_size) {
16 // Calculate the total packet size
17 const size_t header_size = sizeof(PacketHeader);
18 const size_t body_size = sizeof(BoardHeartbeatPacket);
19 const size_t total_size = header_size + body_size;
20
21 // Check if buffer is large enough
22 if (buffer_size < total_size) {
23 return 0; // Error: buffer too small
24 }
25
26 // Create the packet header
27 PacketHeader header;
28 header.packet_type = PacketType::BOARD_HEARTBEAT;
29 header.version = DIABLO_COMMS_VERSION; // Current protocol version
30 header.timestamp = timestamp_ms;
31
32 // Copy header to buffer
33 memcpy(buffer, &header, header_size);
34
35 // Copy body data to buffer
36 memcpy(buffer + header_size, &data, body_size);
37
38 return total_size;
39}
40
41size_t create_sensor_data_packet(const std::vector<SensorDataChunkCollection> &chunks, const uint8_t num_sensors,
42 uint32_t timestamp_ms,
43 uint8_t *buffer, size_t buffer_size) {
44 const size_t header_size = sizeof(PacketHeader);
45 const size_t body_header_size = sizeof(SensorDataPacket);
46
47 const size_t num_chunks = chunks.size();
48
49 // Compute total size: header + body + per-chunk (timestamp + datapoints)
50 const size_t per_chunk_size = sizeof(SensorDataChunk) + (static_cast<size_t>(num_sensors) * sizeof(SensorDatapoint));
51 const size_t total_size = header_size + body_header_size + (num_chunks * per_chunk_size);
52
53 if (buffer_size < total_size) {
54 return 0; // Buffer too small
55 }
56
57 // Prepare header
58 PacketHeader header;
59 header.packet_type = PacketType::SENSOR_DATA;
60 header.version = DIABLO_COMMS_VERSION;
61 header.timestamp = timestamp_ms;
62
63 // Write header
64 uint8_t *ptr = buffer;
65 memcpy(ptr, &header, header_size);
66 ptr += header_size;
67
68 // Write body header
69 SensorDataPacket body;
70 body.num_chunks = num_chunks;
71 body.num_sensors = num_sensors;
72 memcpy(ptr, &body, body_header_size);
73 ptr += body_header_size;
74
75 // Write chunks and datapoints
76 for (uint8_t i = 0; i < num_chunks; ++i) {
77 // Chunk header (timestamp)
78 SensorDataChunk chunk_hdr;
79 chunk_hdr.timestamp = chunks[i].timestamp;
80 memcpy(ptr, &chunk_hdr, sizeof(SensorDataChunk));
81 ptr += sizeof(SensorDataChunk);
82
83 // Datapoints (assume exactly num_sensors datapoints are present)
84 const SensorDatapoint *dp = chunks[i].datapoints.data();
85 size_t datapoints_total_size = static_cast<size_t>(num_sensors) * sizeof(SensorDatapoint);
86 memcpy(ptr, dp, datapoints_total_size);
87 ptr += datapoints_total_size;
88 }
89
90 return total_size;
91}
92
93size_t create_abort_done_packet(uint32_t timestamp_ms,
94 uint8_t *buffer, size_t buffer_size) {
95 // Calculate the total packet size (header only, no body)
96 const size_t header_size = sizeof(PacketHeader);
97
98 // Check if buffer is large enough
99 if (buffer_size < header_size) {
100 return 0; // Error: buffer too small
101 }
102
103 // Create the packet header
104 PacketHeader header;
105 header.packet_type = PacketType::ABORT_DONE;
106 header.version = 1; // Current protocol version
107 header.timestamp = timestamp_ms;
108
109 // Copy header to buffer
110 memcpy(buffer, &header, header_size);
111
112 return header_size;
113}
114
115size_t create_actuator_command_packet(const std::vector<ActuatorCommand> &commands,
116 uint32_t timestamp_ms,
117 uint8_t *buffer, size_t buffer_size) {
118 const size_t header_size = sizeof(PacketHeader);
119 const size_t body_size = sizeof(ActuatorCommandPacket);
120 const size_t num_commands = commands.size();
121
122 if (num_commands > 255 || num_commands == 0) {
123 return 0; // num_commands must be between 1 and 255
124 }
125
126 const size_t commands_bytes = num_commands * sizeof(ActuatorCommand);
127 const size_t total_size = header_size + body_size + commands_bytes;
128
129 if (buffer_size < total_size) {
130 return 0; // Buffer too small
131 }
132
133 // Header
134 PacketHeader header;
135 header.packet_type = PacketType::ACTUATOR_COMMAND;
136 header.version = DIABLO_COMMS_VERSION;
137 header.timestamp = timestamp_ms;
138
139 uint8_t *ptr = buffer;
140 memcpy(ptr, &header, header_size);
141 ptr += header_size;
142
143 // Body
144 ActuatorCommandPacket body;
145 body.num_commands = static_cast<uint8_t>(num_commands);
146 memcpy(ptr, &body, body_size);
147 ptr += body_size;
148
149 // Commands array
150 if (num_commands) {
151 memcpy(ptr, commands.data(), commands_bytes);
152 }
153
154 return total_size;
155}
156
157size_t create_self_test_packet(uint8_t adc_good,
158 const std::vector<SelfTestResult> &results,
159 uint32_t timestamp_ms,
160 uint8_t *buffer, size_t buffer_size) {
161 const size_t header_size = sizeof(PacketHeader);
162 const size_t body_size = sizeof(SelfTestPacket);
163 const size_t num_sensors = results.size();
164
165 if (num_sensors > 255) {
166 return 0; // num_sensors must be <= 255
167 }
168
169 const size_t results_bytes = num_sensors * sizeof(SelfTestResult);
170 const size_t total_size = header_size + body_size + results_bytes;
171
172 if (buffer_size < total_size) {
173 return 0; // Buffer too small
174 }
175
176 // Header
177 PacketHeader header;
178 header.packet_type = PacketType::SELF_TEST;
179 header.version = DIABLO_COMMS_VERSION;
180 header.timestamp = timestamp_ms;
181
182 uint8_t *ptr = buffer;
183 memcpy(ptr, &header, header_size);
184 ptr += header_size;
185
186 // Body: adc_good byte first, then num_sensors
187 SelfTestPacket body;
188 body.adc_good = adc_good;
189 body.num_sensors = static_cast<uint8_t>(num_sensors);
190 memcpy(ptr, &body, body_size);
191 ptr += body_size;
192
193 // Results array
194 if (num_sensors) {
195 memcpy(ptr, results.data(), results_bytes);
196 }
197
198 return total_size;
199}
200
201size_t create_environmental_data_packet(float temperature_c,
202 uint32_t pressure_pa,
203 float humidity_rh,
204 uint32_t timestamp_ms,
205 uint8_t *buffer, size_t buffer_size) {
206 const size_t header_size = sizeof(PacketHeader);
207 const size_t body_size = sizeof(EnvironmentalDataPacket);
208 const size_t total_size = header_size + body_size;
209
210 if (!buffer || buffer_size < total_size) {
211 return 0;
212 }
213
214 PacketHeader header;
215 header.packet_type = PacketType::ENVIRONMENTAL_DATA;
216 header.version = DIABLO_COMMS_VERSION;
217 header.timestamp = timestamp_ms;
218
219 EnvironmentalDataPacket body;
220 body.temperature_c = temperature_c;
221 body.pressure_pa = pressure_pa;
222 body.humidity_rh = humidity_rh;
223
224 uint8_t *ptr = buffer;
225 memcpy(ptr, &header, header_size);
226 ptr += header_size;
227 memcpy(ptr, &body, body_size);
228 return total_size;
229}
230
231size_t create_stacklight_command_packet(const StacklightCommandPacket &data,
232 uint32_t timestamp_ms,
233 uint8_t *buffer, size_t buffer_size) {
234 const size_t header_size = sizeof(PacketHeader);
235 const size_t body_size = sizeof(StacklightCommandPacket);
236 const size_t total_size = header_size + body_size;
237
238 if (!buffer || buffer_size < total_size) {
239 return 0;
240 }
241
242 PacketHeader header;
243 header.packet_type = PacketType::STACKLIGHT_COMMAND;
244 header.version = DIABLO_COMMS_VERSION;
245 header.timestamp = timestamp_ms;
246
247 uint8_t *ptr = buffer;
248 memcpy(ptr, &header, header_size);
249 ptr += header_size;
250 memcpy(ptr, &data, body_size);
251 return total_size;
252}
253
254bool parse_board_heartbeat_packet(const uint8_t *buffer, size_t buffer_size,
255 PacketHeader &header_out,
256 BoardHeartbeatPacket &data_out) {
257 const size_t header_size = sizeof(PacketHeader);
258 const size_t body_size = sizeof(BoardHeartbeatPacket);
259 const size_t total_size = header_size + body_size;
260 if (!buffer || buffer_size < total_size) return false;
261
262 // Read header
263 PacketHeader hdr;
264 memcpy(&hdr, buffer, header_size);
265 if (hdr.packet_type != PacketType::BOARD_HEARTBEAT) return false;
266
267 // Read body
268 memcpy(&data_out, buffer + header_size, body_size);
269 header_out = hdr;
270 return true;
271}
272
273bool parse_server_heartbeat_packet(const uint8_t *buffer, size_t buffer_size,
274 PacketHeader &header_out,
275 ServerHeartbeatPacket &data_out) {
276 const size_t header_size = sizeof(PacketHeader);
277 const size_t body_size = sizeof(ServerHeartbeatPacket);
278 const size_t total_size = header_size + body_size;
279 if (!buffer || buffer_size < total_size) return false;
280
281 // Read header
282 PacketHeader hdr;
283 memcpy(&hdr, buffer, header_size);
284 if (hdr.packet_type != PacketType::SERVER_HEARTBEAT) return false;
285
286 // Read body
287 memcpy(&data_out, buffer + header_size, body_size);
288 header_out = hdr;
289 return true;
290}
291
292bool parse_environmental_data_packet(const uint8_t *buffer, size_t buffer_size,
293 PacketHeader &header_out,
294 EnvironmentalDataPacket &data_out) {
295 const size_t header_size = sizeof(PacketHeader);
296 const size_t body_size = sizeof(EnvironmentalDataPacket);
297 const size_t total_size = header_size + body_size;
298 if (!buffer || buffer_size < total_size) return false;
299
300 PacketHeader hdr;
301 memcpy(&hdr, buffer, header_size);
302 if (hdr.packet_type != PacketType::ENVIRONMENTAL_DATA) return false;
303
304 memcpy(&data_out, buffer + header_size, body_size);
305 header_out = hdr;
306 return true;
307}
308
309bool parse_stacklight_command_packet(const uint8_t *buffer, size_t buffer_size,
310 PacketHeader &header_out,
311 StacklightCommandPacket &data_out) {
312 const size_t header_size = sizeof(PacketHeader);
313 const size_t body_size = sizeof(StacklightCommandPacket);
314 const size_t total_size = header_size + body_size;
315 if (!buffer || buffer_size < total_size) return false;
316
317 PacketHeader hdr;
318 memcpy(&hdr, buffer, header_size);
319 if (hdr.packet_type != PacketType::STACKLIGHT_COMMAND) return false;
320
321 memcpy(&data_out, buffer + header_size, body_size);
322 header_out = hdr;
323 return true;
324}
325
326bool parse_sensor_data_packet(const uint8_t *buffer, size_t buffer_size,
327 PacketHeader &header_out,
328 std::vector<SensorDataChunkCollection> &chunks_out) {
329 const size_t header_size = sizeof(PacketHeader);
330 const size_t body_hdr_size = sizeof(SensorDataPacket);
331
332 if (!buffer || buffer_size < header_size + body_hdr_size) return false;
333
334 // Header
335 PacketHeader hdr;
336 memcpy(&hdr, buffer, header_size);
337 if (hdr.packet_type != PacketType::SENSOR_DATA) return false;
338
339 const uint8_t *ptr = buffer + header_size;
340 // Body header
341 SensorDataPacket body;
342 memcpy(&body, ptr, body_hdr_size);
343 ptr += body_hdr_size;
344
345 const size_t per_chunk_size = sizeof(SensorDataChunk) + (static_cast<size_t>(body.num_sensors) * sizeof(SensorDatapoint));
346 const size_t expected_size = header_size + body_hdr_size + (static_cast<size_t>(body.num_chunks) * per_chunk_size);
347 if (buffer_size < expected_size) return false;
348
349 chunks_out.clear();
350 chunks_out.reserve(body.num_chunks);
351
352 for (uint8_t c = 0; c < body.num_chunks; ++c) {
353 // Chunk header
354 SensorDataChunk chunk_hdr;
355 memcpy(&chunk_hdr, ptr, sizeof(SensorDataChunk));
356 ptr += sizeof(SensorDataChunk);
357
358 // Datapoints
359 SensorDataChunkCollection col(chunk_hdr.timestamp, body.num_sensors);
360 if (body.num_sensors) {
361 col.datapoints.resize(body.num_sensors);
362 memcpy(col.datapoints.data(), ptr, static_cast<size_t>(body.num_sensors) * sizeof(SensorDatapoint));
363 ptr += static_cast<size_t>(body.num_sensors) * sizeof(SensorDatapoint);
364 }
365 chunks_out.push_back(std::move(col));
366 }
367
368 header_out = hdr;
369 return true;
370}
371
372bool parse_abort_done_packet(const uint8_t *buffer, size_t buffer_size,
373 PacketHeader &header_out) {
374 const size_t header_size = sizeof(PacketHeader);
375 if (!buffer || buffer_size < header_size) return false;
376
377 PacketHeader hdr;
378 memcpy(&hdr, buffer, header_size);
379 if (hdr.packet_type != PacketType::ABORT_DONE) return false;
380 header_out = hdr;
381 return true;
382}
383
384bool parse_actuator_command_packet(const uint8_t *buffer, size_t buffer_size,
385 PacketHeader &header_out,
386 std::vector<ActuatorCommand> &commands_out) {
387 const size_t header_size = sizeof(PacketHeader);
388 const size_t body_size = sizeof(ActuatorCommandPacket);
389 if (!buffer || buffer_size < header_size + body_size) return false;
390
391 PacketHeader hdr;
392 memcpy(&hdr, buffer, header_size);
393 if (hdr.packet_type != PacketType::ACTUATOR_COMMAND) return false;
394
395 const uint8_t *ptr = buffer + header_size;
396 ActuatorCommandPacket body;
397 memcpy(&body, ptr, body_size);
398 ptr += body_size;
399
400 const size_t commands_bytes = static_cast<size_t>(body.num_commands) * sizeof(ActuatorCommand);
401 const size_t expected_size = header_size + body_size + commands_bytes;
402 if (buffer_size < expected_size) return false;
403
404 commands_out.clear();
405 if (body.num_commands) {
406 commands_out.resize(body.num_commands);
407 memcpy(commands_out.data(), ptr, commands_bytes);
408 }
409
410 header_out = hdr;
411 return true;
412}
413
414bool parse_self_test_packet(const uint8_t *buffer, size_t buffer_size,
415 PacketHeader &header_out,
416 uint8_t &adc_good_out,
417 std::vector<SelfTestResult> &results_out) {
418 const size_t header_size = sizeof(PacketHeader);
419 const size_t body_size = sizeof(SelfTestPacket);
420 if (!buffer || buffer_size < header_size + body_size) return false;
421
422 PacketHeader hdr;
423 memcpy(&hdr, buffer, header_size);
424 if (hdr.packet_type != PacketType::SELF_TEST) return false;
425
426 const uint8_t *ptr = buffer + header_size;
427 SelfTestPacket body;
428 memcpy(&body, ptr, body_size);
429 ptr += body_size;
430
431 const size_t results_bytes = static_cast<size_t>(body.num_sensors) * sizeof(SelfTestResult);
432 const size_t expected_size = header_size + body_size + results_bytes;
433 if (buffer_size < expected_size) return false;
434
435 adc_good_out = body.adc_good;
436
437 results_out.clear();
438 if (body.num_sensors) {
439 results_out.resize(body.num_sensors);
440 memcpy(results_out.data(), ptr, results_bytes);
441 }
442
443 header_out = hdr;
444 return true;
445}
446
447size_t create_pwm_actuator_packet(const std::vector<PWMActuatorCommand> &commands,
448 uint32_t timestamp_ms,
449 uint8_t *buffer, size_t buffer_size) {
450 const size_t header_size = sizeof(PacketHeader);
451 const size_t body_size = sizeof(PWMActuatorCommandPacket);
452 const size_t num_commands = commands.size();
453
454 if (num_commands > 255 || num_commands == 0) {
455 return 0; // num_commands must be between 1 and 255
456 }
457
458 const size_t commands_bytes = num_commands * sizeof(PWMActuatorCommand);
459 const size_t total_size = header_size + body_size + commands_bytes;
460
461 if (buffer_size < total_size) {
462 return 0; // Buffer too small
463 }
464
465 // Header
466 PacketHeader header;
467 header.packet_type = PacketType::PWM_ACTUATOR_COMMAND;
468 header.version = DIABLO_COMMS_VERSION;
469 header.timestamp = timestamp_ms;
470
471 uint8_t *ptr = buffer;
472 memcpy(ptr, &header, header_size);
473 ptr += header_size;
474
475 // Body
476 PWMActuatorCommandPacket body;
477 body.num_commands = static_cast<uint8_t>(num_commands);
478 memcpy(ptr, &body, body_size);
479 ptr += body_size;
480
481 // Commands array
482 if (num_commands) {
483 memcpy(ptr, commands.data(), commands_bytes);
484 }
485
486 return total_size;
487}
488
489bool parse_pwm_actuator_packet(const uint8_t *buffer, size_t buffer_size,
490 PacketHeader &header_out,
491 std::vector<PWMActuatorCommand> &commands_out) {
492 const size_t header_size = sizeof(PacketHeader);
493 const size_t body_size = sizeof(PWMActuatorCommandPacket);
494 if (!buffer || buffer_size < header_size + body_size) return false;
495
496 PacketHeader hdr;
497 memcpy(&hdr, buffer, header_size);
498 if (hdr.packet_type != PacketType::PWM_ACTUATOR_COMMAND) return false;
499
500 const uint8_t *ptr = buffer + header_size;
501 PWMActuatorCommandPacket body;
502 memcpy(&body, ptr, body_size);
503 ptr += body_size;
504
505 const size_t commands_bytes = static_cast<size_t>(body.num_commands) * sizeof(PWMActuatorCommand);
506 const size_t expected_size = header_size + body_size + commands_bytes;
507 if (buffer_size < expected_size) return false;
508
509 commands_out.clear();
510 if (body.num_commands) {
511 commands_out.resize(body.num_commands);
512 memcpy(commands_out.data(), ptr, commands_bytes);
513 }
514
515 header_out = hdr;
516 return true;
517}
518
519size_t create_sensor_config_packet(const std::vector<uint8_t> &sensor_ids,
520 uint8_t reference_voltage,
521 bool necessary_for_abort,
522 uint32_t controller_ip,
523 uint8_t enable_serial_printing,
524 uint32_t timestamp_ms,
525 uint8_t *buffer, size_t buffer_size) {
526 const size_t header_size = sizeof(PacketHeader);
527 const size_t num_sensors = sensor_ids.size();
528
529 if (num_sensors > 255) {
530 return 0;
531 }
532
533 const size_t body_size = 1u // num_sensors
534 + num_sensors // sensor_ids
535 + 1u // reference_voltage
536 + 1u // necessary_for_abort
537 + (necessary_for_abort ? 4u : 0u) // controller_ip (conditional)
538 + 1u; // enable_serial_printing
539 const size_t total_size = header_size + body_size;
540
541 if (buffer_size < total_size) {
542 return 0;
543 }
544
545 PacketHeader header;
546 header.packet_type = PacketType::SENSOR_CONFIG;
547 header.version = DIABLO_COMMS_VERSION;
548 header.timestamp = timestamp_ms;
549
550 uint8_t *ptr = buffer;
551 memcpy(ptr, &header, header_size);
552 ptr += header_size;
553
554 *ptr = static_cast<uint8_t>(num_sensors);
555 ptr += 1;
556
557 if (num_sensors) {
558 memcpy(ptr, sensor_ids.data(), num_sensors);
559 ptr += num_sensors;
560 }
561
562 *ptr = reference_voltage;
563 ptr += 1;
564
565 *ptr = necessary_for_abort ? 1u : 0u;
566 ptr += 1;
567
568 if (necessary_for_abort) {
569 memcpy(ptr, &controller_ip, sizeof(uint32_t));
570 ptr += sizeof(uint32_t);
571 }
572
573 *ptr = enable_serial_printing;
574
575 return total_size;
576}
577
578bool parse_sensor_config_packet(const uint8_t *buffer, size_t buffer_size,
579 PacketHeader &header_out,
580 std::vector<uint8_t> &sensor_ids_out,
581 uint8_t &reference_voltage_out,
582 bool &necessary_for_abort_out,
583 uint32_t &controller_ip_out,
584 uint8_t &enable_serial_printing_out) {
585 const size_t header_size = sizeof(PacketHeader);
586 // Minimum body: num_sensors(1) + ref_voltage(1) + necessary_for_abort(1) + enable_serial(1)
587 const size_t min_body = 4u;
588
589 if (!buffer || buffer_size < header_size + min_body) {
590 return false;
591 }
592
593 PacketHeader hdr;
594 memcpy(&hdr, buffer, header_size);
595 if (hdr.packet_type != PacketType::SENSOR_CONFIG) {
596 return false;
597 }
598
599 const uint8_t *ptr = buffer + header_size;
600
601 const uint8_t num_sensors = *ptr;
602 ptr += 1;
603
604 // Verify remaining bytes can hold sensor_ids + fixed tail
605 // fixed tail = ref_voltage(1) + necessary_for_abort(1) + enable_serial(1) = 3
606 const size_t min_remaining = static_cast<size_t>(num_sensors) + 3u;
607 if (buffer_size < header_size + 1u + min_remaining) {
608 return false;
609 }
610
611 sensor_ids_out.clear();
612 if (num_sensors) {
613 sensor_ids_out.resize(num_sensors);
614 memcpy(sensor_ids_out.data(), ptr, num_sensors);
615 ptr += num_sensors;
616 }
617
618 reference_voltage_out = *ptr;
619 ptr += 1;
620
621 const uint8_t abort_flag = *ptr;
622 ptr += 1;
623 necessary_for_abort_out = (abort_flag != 0);
624
625 if (necessary_for_abort_out) {
626 // Need 4 more bytes for controller_ip + 1 for enable_serial_printing
627 const size_t consumed = static_cast<size_t>(ptr - buffer);
628 if (buffer_size < consumed + sizeof(uint32_t) + 1u) {
629 return false;
630 }
631 memcpy(&controller_ip_out, ptr, sizeof(uint32_t));
632 ptr += sizeof(uint32_t);
633 } else {
634 controller_ip_out = 0;
635 }
636
637 // Final byte: enable_serial_printing
638 const size_t consumed = static_cast<size_t>(ptr - buffer);
639 if (buffer_size < consumed + 1u) {
640 return false;
641 }
642 enable_serial_printing_out = *ptr;
643
644 header_out = hdr;
645 return true;
646}
647
649 uint8_t is_abort_controller,
650 const std::vector<AbortActuatorLocation> &abort_actuators,
651 const std::vector<AbortPTLocation> &abort_pts,
652 uint8_t enable_serial_printing,
653 uint32_t timestamp_ms,
654 uint8_t *buffer, size_t buffer_size) {
655 const size_t header_size = sizeof(PacketHeader);
656 const size_t config_header_size = sizeof(ActuatorConfigPacket);
657 const size_t N = abort_actuators.size();
658 const size_t X = abort_pts.size();
659
660 if (N > MAX_ABORT_ACTUATORS || X > MAX_ABORT_PTS) {
661 return 0;
662 }
663
664 const size_t actuator_bytes = N * sizeof(AbortActuatorLocation);
665 const size_t pt_count_size = sizeof(AbortPTSectionHeader);
666 const size_t pt_entries_bytes = X * sizeof(AbortPTLocation);
667 const size_t trailer_size = 1u; // enable_serial_printing
668 const size_t body_size = config_header_size + actuator_bytes + pt_count_size + pt_entries_bytes + trailer_size;
669 const size_t total_size = header_size + body_size;
670
671 if (buffer_size < total_size) {
672 return 0;
673 }
674
675 PacketHeader header;
676 header.packet_type = PacketType::ACTUATOR_CONFIG;
677 header.version = DIABLO_COMMS_VERSION;
678 header.timestamp = timestamp_ms;
679
680 uint8_t *ptr = buffer;
681 memcpy(ptr, &header, header_size);
682 ptr += header_size;
683
684 ActuatorConfigPacket config;
685 config.is_abort_controller = is_abort_controller;
686 config.num_abort_actuators = static_cast<uint8_t>(N);
687 memcpy(ptr, &config, config_header_size);
688 ptr += config_header_size;
689
690 if (N) {
691 memcpy(ptr, abort_actuators.data(), actuator_bytes);
692 ptr += actuator_bytes;
693 }
694
695 AbortPTSectionHeader pt_header;
696 pt_header.num_abort_pts = static_cast<uint8_t>(X);
697 memcpy(ptr, &pt_header, pt_count_size);
698 ptr += pt_count_size;
699
700 if (X) {
701 memcpy(ptr, abort_pts.data(), pt_entries_bytes);
702 ptr += pt_entries_bytes;
703 }
704
705 *ptr = enable_serial_printing;
706
707 return total_size;
708}
709
710bool parse_actuator_config_packet(const uint8_t *buffer, size_t buffer_size,
711 PacketHeader &header_out,
712 uint8_t &is_abort_controller_out,
713 std::vector<AbortActuatorLocation> &abort_actuators_out,
714 std::vector<AbortPTLocation> &abort_pts_out,
715 uint8_t &enable_serial_printing_out) {
716 const size_t header_size = sizeof(PacketHeader);
717 const size_t config_header_size = sizeof(ActuatorConfigPacket);
718 const size_t pt_count_size = sizeof(AbortPTSectionHeader);
719 const size_t trailer_size = 1u; // enable_serial_printing
720
721 if (!buffer || buffer_size < header_size + config_header_size + pt_count_size + trailer_size) {
722 return false;
723 }
724
725 PacketHeader hdr;
726 memcpy(&hdr, buffer, header_size);
727 if (hdr.packet_type != PacketType::ACTUATOR_CONFIG) {
728 return false;
729 }
730
731 const uint8_t *ptr = buffer + header_size;
732 ActuatorConfigPacket config;
733 memcpy(&config, ptr, config_header_size);
734 ptr += config_header_size;
735
736 const size_t N = config.num_abort_actuators;
737 const size_t actuator_bytes = N * sizeof(AbortActuatorLocation);
738 const size_t min_size_after_config = actuator_bytes + pt_count_size + trailer_size;
739 if (buffer_size < header_size + config_header_size + min_size_after_config) {
740 return false;
741 }
742
743 abort_actuators_out.clear();
744 if (N > MAX_ABORT_ACTUATORS) {
745 return false;
746 }
747 if (N) {
748 abort_actuators_out.resize(N);
749 memcpy(abort_actuators_out.data(), ptr, actuator_bytes);
750 ptr += actuator_bytes;
751 }
752
753 AbortPTSectionHeader pt_header;
754 memcpy(&pt_header, ptr, pt_count_size);
755 ptr += pt_count_size;
756
757 const size_t X = pt_header.num_abort_pts;
758 const size_t pt_entries_bytes = X * sizeof(AbortPTLocation);
759 const size_t expected_total = header_size + config_header_size + actuator_bytes + pt_count_size + pt_entries_bytes + trailer_size;
760 if (buffer_size < expected_total) {
761 return false;
762 }
763 if (X > MAX_ABORT_PTS) {
764 return false;
765 }
766
767 abort_pts_out.clear();
768 if (X) {
769 abort_pts_out.resize(X);
770 memcpy(abort_pts_out.data(), ptr, pt_entries_bytes);
771 ptr += pt_entries_bytes;
772 }
773
774 enable_serial_printing_out = *ptr;
775 is_abort_controller_out = config.is_abort_controller;
776 header_out = hdr;
777 return true;
778}
779
780size_t create_log_packet(uint8_t flags, const uint8_t *text, uint16_t text_len,
781 uint32_t timestamp_ms,
782 uint8_t *buffer, size_t buffer_size) {
783 const size_t header_size = sizeof(PacketHeader);
784 const size_t total_size = header_size + 1 /*flags*/ + 2 /*text_len*/ + text_len;
785 if (buffer_size < total_size) {
786 return 0; // Buffer too small
787 }
788
789 PacketHeader header;
790 header.packet_type = PacketType::LOGS;
791 header.version = DIABLO_COMMS_VERSION;
792 header.timestamp = timestamp_ms;
793
794 uint8_t *ptr = buffer;
795 memcpy(ptr, &header, header_size);
796 ptr += header_size;
797
798 *ptr++ = flags;
799 memcpy(ptr, &text_len, sizeof(text_len)); // uint16 LE (host is little-endian)
800 ptr += sizeof(text_len);
801 if (text_len && text) {
802 memcpy(ptr, text, text_len);
803 }
804 return total_size;
805}
806
807bool parse_log_packet(const uint8_t *buffer, size_t buffer_size,
808 PacketHeader &header_out,
809 uint8_t &flags_out,
810 const uint8_t *&text_out,
811 uint16_t &text_len_out) {
812 const size_t header_size = sizeof(PacketHeader);
813 const size_t fixed_body = 1u /*flags*/ + 2u /*text_len*/;
814 if (!buffer || buffer_size < header_size + fixed_body) return false;
815
816 PacketHeader hdr;
817 memcpy(&hdr, buffer, header_size);
818 if (hdr.packet_type != PacketType::LOGS) return false;
819
820 const uint8_t *ptr = buffer + header_size;
821 const uint8_t flags = *ptr++;
822
823 uint16_t text_len;
824 memcpy(&text_len, ptr, sizeof(text_len)); // uint16 LE (host is little-endian)
825 ptr += sizeof(text_len);
826
827 if (buffer_size < header_size + fixed_body + text_len) return false;
828
829 header_out = hdr;
830 flags_out = flags;
831 text_len_out = text_len;
832 text_out = ptr;
833 return true;
834}
835
836} // namespace daq
#define MAX_ABORT_ACTUATORS
#define DIABLO_COMMS_VERSION
Definition daq-protocol.h:4
#define MAX_ABORT_PTS
std::vector< daq::SensorDataChunkCollection > chunks
Definition main.cpp:55
static bool is_abort_controller
Definition main.cpp:63
static osMessageQueueId_t commands
Definition idle_task.c:28
static const idle_config_t config
Definition idle_task.c:17
*brief write string representation of the JSON pointer to stream *sa const json_pointer & ptr
Definition json.hpp:13895
bool parse_self_test_packet(const uint8_t *buffer, size_t buffer_size, PacketHeader &header_out, uint8_t &adc_good_out, std::vector< SelfTestResult > &results_out)
Parses a Self Test packet from buffer.
size_t create_sensor_data_packet(const std::vector< SensorDataChunkCollection > &chunks, const uint8_t num_sensors, uint32_t timestamp_ms, uint8_t *buffer, size_t buffer_size)
Creates a complete Sensor Data packet in the provided buffer.
bool parse_server_heartbeat_packet(const uint8_t *buffer, size_t buffer_size, PacketHeader &header_out, ServerHeartbeatPacket &data_out)
Parses a Server Heartbeat packet from buffer.
bool parse_log_packet(const uint8_t *buffer, size_t buffer_size, PacketHeader &header_out, uint8_t &flags_out, const uint8_t *&text_out, uint16_t &text_len_out)
Parses a LOGS packet (type 15) from buffer.
size_t create_abort_done_packet(uint32_t timestamp_ms, uint8_t *buffer, size_t buffer_size)
Creates a simple Abort Done packet.
bool parse_sensor_config_packet(const uint8_t *buffer, size_t buffer_size, PacketHeader &header_out, std::vector< uint8_t > &sensor_ids_out, uint8_t &reference_voltage_out, bool &necessary_for_abort_out, uint32_t &controller_ip_out, uint8_t &enable_serial_printing_out)
Parses a Sensor Config packet from buffer.
size_t create_log_packet(uint8_t flags, const uint8_t *text, uint16_t text_len, uint32_t timestamp_ms, uint8_t *buffer, size_t buffer_size)
Creates a LOGS packet (type 15): buffered board log text for the server.
bool parse_board_heartbeat_packet(const uint8_t *buffer, size_t buffer_size, PacketHeader &header_out, BoardHeartbeatPacket &data_out)
Parses a Board Heartbeat packet from buffer.
size_t create_board_heartbeat_packet(const BoardHeartbeatPacket &data, uint32_t timestamp_ms, uint8_t *buffer, size_t buffer_size)
Creates a complete Board Heartbeat packet in the provided buffer.
bool parse_pwm_actuator_packet(const uint8_t *buffer, size_t buffer_size, PacketHeader &header_out, std::vector< PWMActuatorCommand > &commands_out)
Parses a PWM Actuator Command packet from buffer.
size_t create_pwm_actuator_packet(const std::vector< PWMActuatorCommand > &commands, uint32_t timestamp_ms, uint8_t *buffer, size_t buffer_size)
Creates a complete PWM Actuator Command packet in the provided buffer.
size_t create_stacklight_command_packet(const StacklightCommandPacket &data, uint32_t timestamp_ms, uint8_t *buffer, size_t buffer_size)
Creates a complete Stacklight Command packet in the provided buffer.
bool parse_stacklight_command_packet(const uint8_t *buffer, size_t buffer_size, PacketHeader &header_out, StacklightCommandPacket &data_out)
Parses a Stacklight Command packet from buffer.
size_t create_environmental_data_packet(float temperature_c, uint32_t pressure_pa, float humidity_rh, uint32_t timestamp_ms, uint8_t *buffer, size_t buffer_size)
Creates a complete Environmental Data packet in the provided buffer.
bool parse_actuator_command_packet(const uint8_t *buffer, size_t buffer_size, PacketHeader &header_out, std::vector< ActuatorCommand > &commands_out)
Parses an Actuator Command packet from buffer.
size_t create_sensor_config_packet(const std::vector< uint8_t > &sensor_ids, uint8_t reference_voltage, bool necessary_for_abort, uint32_t controller_ip, uint8_t enable_serial_printing, uint32_t timestamp_ms, uint8_t *buffer, size_t buffer_size)
Creates a complete Sensor Config packet in the provided buffer.
bool parse_environmental_data_packet(const uint8_t *buffer, size_t buffer_size, PacketHeader &header_out, EnvironmentalDataPacket &data_out)
Parses an Environmental Data packet from buffer.
size_t create_self_test_packet(uint8_t adc_good, const std::vector< SelfTestResult > &results, uint32_t timestamp_ms, uint8_t *buffer, size_t buffer_size)
Creates a complete Self Test packet in the provided buffer.
bool parse_abort_done_packet(const uint8_t *buffer, size_t buffer_size, PacketHeader &header_out)
Parses an Abort Done packet from buffer.
size_t create_actuator_config_packet(uint8_t is_abort_controller, const std::vector< AbortActuatorLocation > &abort_actuators, const std::vector< AbortPTLocation > &abort_pts, uint8_t enable_serial_printing, uint32_t timestamp_ms, uint8_t *buffer, size_t buffer_size)
Creates a complete Actuator Config packet in the provided buffer.
bool parse_actuator_config_packet(const uint8_t *buffer, size_t buffer_size, PacketHeader &header_out, uint8_t &is_abort_controller_out, std::vector< AbortActuatorLocation > &abort_actuators_out, std::vector< AbortPTLocation > &abort_pts_out, uint8_t &enable_serial_printing_out)
Parses an Actuator Config packet from buffer.
bool parse_sensor_data_packet(const uint8_t *buffer, size_t buffer_size, PacketHeader &header_out, std::vector< SensorDataChunkCollection > &chunks_out)
Parses a Sensor Data packet from buffer into chunk collections.
size_t create_actuator_command_packet(const std::vector< ActuatorCommand > &commands, uint32_t timestamp_ms, uint8_t *buffer, size_t buffer_size)
Creates a complete Actuator Command packet in the provided buffer.
Represents a single data chunk with timestamp and sensor datapoints.
std::vector< SensorDatapoint > datapoints