Avionics
Core avionics package for CURE flight computers
Loading...
Searching...
No Matches
Telemetry.cpp
Go to the documentation of this file.
2#include "ArduinoHAL.h"
3#include <algorithm>
4
5// Helpers for checking if the packet has room for more data
6std::size_t bytesNeededForSSD(const SendableSensorData* ssd) {
7 // Each SSD writes 1 label byte (name/label) plus 4 bytes per float value.
8 if (ssd->isSingle()) {
10 }
11 if (ssd->isMulti()) {
12 // label + N floats
13 return 1U + (static_cast<std::size_t>(ssd->multiSDHLength) * TelemetryFmt::kBytesIn32Bit);
14 }
15 return 0U;
16}
17
18bool hasRoom(std::size_t nextIndex, std::size_t bytesToAdd) {
19 return nextIndex + bytesToAdd <= TelemetryFmt::kPacketCapacity;
20}
21
22void Telemetry::preparePacket(std::uint32_t timestamp) {
23 // This write the header of the packet with sync bytes, start byte, and timestamp.
24 // Only clear what we own in the header (whole-packet clearing happens in setPacketToZero()).
25
26 // Fill sync bytes with 0
27 std::fill_n(&this->packet[0], TelemetryFmt::kSyncZeros, static_cast<std::uint8_t>(0));
28
29 // Set the start byte after the sync bytes
31
32 // Write the timestamp in big-endian format
34
35 // Packet counter (4 bytes, big-endian)
37
38 nextEmptyPacketIndex = TelemetryFmt::kHeaderBytes;
39}
40
41void Telemetry::addSingleSDHToPacket(SensorDataHandler* sdh) {
42 float floatData = sdh->getLastDataPointSaved().data;
43 uint32_t data = 0;
44 memcpy(&data, &floatData, sizeof(data)); // Move float data into an uint32_t for bytewise access
45 TelemetryFmt::write_u32_be(&this->packet[nextEmptyPacketIndex], data);
46 nextEmptyPacketIndex += TelemetryFmt::kBytesIn32Bit;
47}
48
49void Telemetry::addSSDToPacket(SendableSensorData* ssd) {
50 if (ssd->isSingle()) {
51 this->packet[nextEmptyPacketIndex] = ssd->singleSDH->getName();
52 nextEmptyPacketIndex += 1;
53 this->addSingleSDHToPacket(ssd->singleSDH);
54 }
55 if (ssd->isMulti()) {
56 this->packet[nextEmptyPacketIndex] = ssd->multiSDHDataLabel;
57 nextEmptyPacketIndex += 1;
58 for (int i = 0; i < ssd->multiSDHLength; i++) {
59 // multiSDHLength comes directly from the array passed in by the client
60 // So, we can ignore this raw pointer indexing warning
61 this->addSingleSDHToPacket(ssd->multiSDH[i]); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
62 }
63 }
64}
65
66void Telemetry::setPacketToZero() {
67 for (int i = 0; i < TelemetryFmt::kPacketCapacity; i++) { //Completely clear packet
68 this->packet[i] = 0;
69 }
70}
71
72void Telemetry::addEndMarker() {
73 // Adds the following 4 bytes to the end of the packet: 0x00 0x00 0x00 (kEndByteValue)
74
75 std::fill_n(&this->packet[nextEmptyPacketIndex], TelemetryFmt::kSyncZeros, static_cast<std::uint8_t>(0));
76 this->packet[nextEmptyPacketIndex+TelemetryFmt::kSyncZeros] = TelemetryFmt::kEndByteValue;
77 nextEmptyPacketIndex += TelemetryFmt::kEndMarkerBytes;
78}
79
80bool Telemetry::tick(uint32_t currentTime) {
81 bool sendingPacketThisTick = false;
82
83 for (std::size_t i = 0; i < streamCount; i++) {
84 // i is safe because streamCount comes from the array passed in by the client
85 if (streams[i]->shouldBeSent(currentTime)) { // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
86
87 if (!sendingPacketThisTick) {
88 setPacketToZero();
89 preparePacket(currentTime);
90 sendingPacketThisTick = true;
91 }
92
93 // Compute how many bytes we need for this stream's payload.
94 const std::size_t payloadBytes = bytesNeededForSSD(streams[i]); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
95 const std::size_t totalBytesIfAdded = payloadBytes + TelemetryFmt::kEndMarkerBytes;
96
97 // Only add if it fits (payload + end marker).
98 if (hasRoom(nextEmptyPacketIndex, totalBytesIfAdded)) {
99 addSSDToPacket(streams[i]); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
100 streams[i]->markWasSent(currentTime); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
101 } else {
102 // Not enough room. Skip this stream for now.
103 // It will be sent on the next tick as long as the packet isn't filled before reaching it again.
104 // If we have too many high-frequency streams, the stream as the end of the list may be starved.
105 }
106 }
107 }
108
109 // Only send if we actually added any payload beyond the header.
110 if (sendingPacketThisTick && nextEmptyPacketIndex > TelemetryFmt::kHeaderBytes) {
111 // Ensure end marker itself fits
112 if (hasRoom(nextEmptyPacketIndex, TelemetryFmt::kEndMarkerBytes)) {
113 addEndMarker();
114
115 // Send used portion
116 for (std::size_t i = 0; i < nextEmptyPacketIndex; i++) {
117 rfdSerialConnection.write(packet[i]);
118 }
119
120 packetCounter++; //Increment after each successful send
121
122 return true;
123 }
124
125 // If somehow we can't fit the end marker, drop the packet.
126 // (This shouldn't happen with the checks above.)
127 }
128
129 return false;
130}
bool hasRoom(std::size_t nextIndex, std::size_t bytesToAdd)
Definition Telemetry.cpp:18
std::size_t bytesNeededForSSD(const SendableSensorData *ssd)
Definition Telemetry.cpp:6
Packs SensorDataHandler values into a fixed-size byte packet and streams over a Stream (UART).
float data
Definition DataPoint.h:14
Buffers sensor samples and forwards them to an IDataSaver at a controlled rate.
DataPoint getLastDataPointSaved() const
uint8_t getName() const
bool tick(std::uint32_t currentTimeMs)
Call every loop to send due telemetry streams.
Definition Telemetry.cpp:80
constexpr std::size_t kStartByteIndex
Definition Telemetry.h:40
constexpr std::size_t kPacketCapacity
Definition Telemetry.h:31
constexpr std::uint8_t kStartByteValue
Definition Telemetry.h:49
constexpr std::size_t kPacketCounterIndex
Definition Telemetry.h:42
void write_u32_be(std::uint8_t *dst, std::uint32_t v)
Write a 32-bit value in big-endian order to dst[0..3].
Definition Telemetry.h:66
constexpr std::size_t kSyncZeros
Definition Telemetry.h:34
constexpr std::size_t kEndMarkerBytes
Definition Telemetry.h:46
constexpr std::size_t kBytesIn32Bit
Definition Telemetry.h:55
constexpr std::size_t kHeaderBytes
Definition Telemetry.h:43
constexpr std::uint8_t kEndByteValue
Definition Telemetry.h:52
constexpr std::size_t kTimestampIndex
Definition Telemetry.h:41
Declares one telemetry "stream" to include in packets.
Definition Telemetry.h:105
const std::size_t multiSDHLength
Definition Telemetry.h:117
bool isMulti() const
Convenience: true if configured as a multi SDH stream.
Definition Telemetry.h:178
bool isSingle() const
Convenience: true if configured as a single SDH stream.
Definition Telemetry.h:175
std::uint8_t multiSDHDataLabel
Definition Telemetry.h:120
SensorDataHandler *const * multiSDH
Definition Telemetry.h:112
SensorDataHandler * singleSDH
Definition Telemetry.h:109