19bool hasRoom(std::size_t nextIndex, std::size_t bytesToAdd) {
24 return static_cast<std::int32_t
>(lhs - rhs) > 0;
28 return static_cast<std::int32_t
>(current - target) >= 0;
31void Telemetry::checkForRadioCommandSequence(std::uint32_t currentTime_ms) {
36 while (rfdSerialConnection_.available() > 0) {
37 const char receivedChar =
static_cast<char>(rfdSerialConnection_.read());
40 ++commandEntryProgress_;
42 enterCommandMode(currentTime_ms);
46 rfdSerialConnection_.print(
"Received char '");
47 rfdSerialConnection_.print(receivedChar);
48 rfdSerialConnection_.print(
"' which does not match command entry char '");
50 rfdSerialConnection_.println(
"'. Resetting command entry progress.");
51 commandEntryProgress_ = 0;
56void Telemetry::enterCommandMode(std::uint32_t currentTime_ms) {
57 inCommandMode_ =
true;
58 commandModeEnteredTimestamp_ms_ = currentTime_ms;
59 commandModeLastInputTimestamp_ms_ = currentTime_ms;
60 commandEntryProgress_ = 0;
61 commandModeTimeoutLocked_ =
false;
62 commandModeTimeoutLockDeadline_ms_ = 0;
64 if (commandLine_ !=
nullptr) {
65 commandLine_->switchUART(&rfdSerialConnection_);
70void Telemetry::exitCommandMode() {
71 inCommandMode_ =
false;
72 commandModeTimeoutLocked_ =
false;
73 commandModeTimeoutLockDeadline_ms_ = 0;
75 if (commandLine_ !=
nullptr) {
76 commandLine_->useDefaultUART();
81 if (!inCommandMode_ || lockDuration_ms == 0) {
85 const auto now_ms =
static_cast<std::uint32_t
>(millis());
86 commandModeTimeoutLocked_ =
true;
87 commandModeTimeoutLockDeadline_ms_ = now_ms + lockDuration_ms;
88 commandModeLastInputTimestamp_ms_ = now_ms;
92 commandModeTimeoutLocked_ =
false;
93 commandModeTimeoutLockDeadline_ms_ = 0;
96 commandModeLastInputTimestamp_ms_ =
static_cast<std::uint32_t
>(millis());
101 if (!inCommandMode_) {
108bool Telemetry::shouldPauseTelemetryForCommandMode(std::uint32_t currentTime_ms) {
109 if (!inCommandMode_) {
113 if (commandLine_ !=
nullptr) {
114 const std::uint32_t lastInteractionTimestamp = commandLine_->getLastInteractionTimestamp();
115 if (
isTimestampNewer(lastInteractionTimestamp, commandModeLastInputTimestamp_ms_)) {
116 commandModeLastInputTimestamp_ms_ = lastInteractionTimestamp;
126 if (commandModeTimeoutLocked_) {
131 commandModeTimeoutLocked_ =
false;
132 commandModeTimeoutLockDeadline_ms_ = 0;
133 commandModeLastInputTimestamp_ms_ = currentTime_ms;
145void Telemetry::preparePacket(std::uint32_t timestamp_ms) {
167 memcpy(&data, &floatData,
sizeof(data));
175 nextEmptyPacketIndex_ += 1;
176 this->addSingleSDHToPacket(ssd->
singleSDH);
180 nextEmptyPacketIndex_ += 1;
184 this->addSingleSDHToPacket(ssd->
multiSDH[i]);
189void Telemetry::setPacketToZero() {
191 this->packet_[i] = 0;
195void Telemetry::addEndMarker() {
208void Telemetry::tryAppendStream(
SendableSensorData* stream, std::uint32_t currentTime_ms,
bool& payloadAdded) {
213 if (!canFitStreamWithEndMarker(stream)) {
217 addSSDToPacket(stream);
222bool Telemetry::finalizeAndSendPacket() {
232 for (std::size_t i = 0; i < nextEmptyPacketIndex_; i++) {
233 rfdSerialConnection_.write(packet_[i]);
242 checkForRadioCommandSequence(currentTime_ms);
244 if (shouldPauseTelemetryForCommandMode(currentTime_ms)) {
249 preparePacket(currentTime_ms);
251 bool payloadAdded =
false;
253 for (std::size_t i = 0; i < streamCount_; i++) {
255 tryAppendStream(streams_[i], currentTime_ms, payloadAdded);
262 return finalizeAndSendPacket();
bool isTimestampReachedOrPassed(std::uint32_t current, std::uint32_t target)
bool isTimestampNewer(std::uint32_t lhs, std::uint32_t rhs)
bool hasRoom(std::size_t nextIndex, std::size_t bytesToAdd)
std::size_t bytesNeededForSSD(const SendableSensorData *ssd)
Packs SensorDataHandler values into a fixed-size byte packet and streams them over a Stream (UART).
constexpr const char * kShellPrompt
Buffers sensor samples and forwards them to an IDataSaver at a controlled rate.
DataPoint getLastDataPointSaved() const
void forceExitCommandMode()
Immediately exit command mode if currently active.
void lockCommandModeTimeout(std::uint32_t lockDuration_ms)
Temporarily disable command-mode inactivity timeout.
void unlockCommandModeTimeout()
Re-enable command-mode inactivity timeout immediately.
bool tick(std::uint32_t currentTime_ms)
Call every loop to send due telemetry streams.
void writeU32Be(std::uint8_t *dst, std::uint32_t v)
Write a 32-bit value in big-endian order to dst[0..3].
constexpr std::size_t kPacketCapacity_bytes
constexpr std::size_t kStartByteIndex
constexpr char kCommandEntryChar
constexpr std::size_t kHeaderSize_bytes
constexpr std::size_t kBytesInU32_bytes
constexpr std::size_t kCommandEntrySequenceLength
constexpr std::uint8_t kStartByteValue
constexpr std::size_t kPacketCounterIndex
constexpr std::size_t kEndMarkerSize_bytes
constexpr std::uint32_t kCommandModeInactivityTimeout_ms
constexpr std::size_t kSyncZeroCount_bytes
constexpr std::uint8_t kEndByteValue
constexpr std::size_t kTimestampIndex
Declares one telemetry "stream" to include in packets.
const std::size_t multiSDHLength
bool isMulti() const
Convenience: true if configured as a multi SDH stream.
bool isSingle() const
Convenience: true if configured as a single SDH stream.
void markWasSent(std::uint32_t now_ms)
Update internal state after sending.
std::uint8_t multiSDHDataLabel
bool shouldBeSent(std::uint32_t now_ms) const
Return true if enough time has elapsed such that this stream wants to be sent again.
SensorDataHandler *const * multiSDH
SensorDataHandler * singleSDH