SatNOGS-COMMS  4.1.0
A COMMS subsystem for CubeSats
Loading...
Searching...
No Matches
telemetry.hpp
Go to the documentation of this file.
1/*
2 * SatNOGS-COMMS MCU software
3 *
4 * Copyright (C) 2023, Libre Space Foundation <http://libre.space>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * SPDX-License-Identifier: GNU General Public License v3.0 or later
20 */
21
22#pragma once
23
24#include "bsp/bsp.hpp"
25#include "callbacks.hpp"
26#include "error_handler.hpp"
27#include "etl/map.h"
28#include "io.hpp"
29#include "msg_arbiter.hpp"
30#include "ota.hpp"
31#include "settings.hpp"
32#include "storage.hpp"
33#include "telecommand.hpp"
34#include "thermal.hpp"
35#include "time.hpp"
36#include <etl/algorithm.h>
37#include <etl/basic_string.h>
38#include <etl/bit_stream.h>
39#include <etl/string.h>
42#include <satnogs-comms-lib/version.hpp>
43#include <version.hpp>
44#include <zephyr/dfu/mcuboot.h>
45#include <zephyr/kernel.h>
46#include <zephyr/retention/blinfo.h>
47#include <zephyr/sys/byteorder.h>
48#include <zephyr/task_wdt/task_wdt.h>
49
50#if CONFIG_BOOTLOADER_MCUBOOT
51#include <bootutil/boot_status.h>
52#include <bootutil/image.h>
53#endif
54
55namespace scl = satnogs::comms::lib;
56namespace satnogs::comms
57{
58
60{
61public:
62 enum class apid : uint16_t
63 {
64 PING_RESP = 100,
65 CMD_ACK = 101,
66 BASIC = 102,
67 POWER = 103,
68 HEALTH = 104,
69 CONFIG = 105,
70 FPGA = 106,
71 RADIO = 107,
72 TIME = 108,
78 SETTINGS = 114,
81 OTA_RESP = 117,
83 };
84
85 /* Primary traits template for all the telemetry types defined by a specific
86 * APID */
87 template <apid A> class serializer;
88
89 class sensors
90 {
91 public:
92 static void
93 serialize(etl::bit_stream_writer &writer)
94 {
95 auto &board = scl::board::get_instance();
97 board.temperature(scl::temperature_sensor::PCB));
99 board.temperature(scl::temperature_sensor::UHF_PA));
101 writer, board.temperature(scl::temperature_sensor::SBAND_PA));
102 writer.write<bool>(board.alert(scl::temperature_sensor::UHF_PA), 1);
103 writer.write<bool>(board.alert(scl::temperature_sensor::SBAND_PA), 1);
104 }
105 };
106
107 class gnss
108 {
109 public:
110 static void
111 serialize(etl::bit_stream_writer &writer)
112 {
114 struct gnss_data data;
115 time.gnss(data);
116 writer.write<uint32_t>(data.info.satellites_cnt, 32);
117 writer.write<uint32_t>(data.info.hdop, 32);
118 writer.write<uint8_t>(data.info.fix_status, 8);
119 writer.write<uint8_t>(data.info.fix_quality, 8);
120 writer.write<uint32_t>(data.utc.hour, 32);
121 writer.write<uint32_t>(data.utc.minute, 32);
122 writer.write<uint32_t>(data.utc.millisecond, 32);
123 writer.write<uint32_t>(data.utc.month_day, 32);
124 writer.write<uint32_t>(data.utc.month, 32);
125 writer.write<uint32_t>(data.utc.century_year, 32);
126 telemetry::serialize(writer, data.nav_data.latitude * 1e-9f);
127 telemetry::serialize(writer, data.nav_data.longitude * 1e-9f);
128 telemetry::serialize(writer, data.nav_data.bearing * 1e-3f);
129 telemetry::serialize(writer, data.nav_data.speed * 1e-3f);
130 telemetry::serialize(writer, data.nav_data.altitude * 1e-3f);
131
132 writer.write<uint64_t>(time.last_gnss_update_uptime(), 64);
133 writer.write<uint64_t>(time.last_nmea_update_uptime(), 64);
134 }
135 };
136
137 class power
138 {
139 public:
140 static void
141 serialize(etl::bit_stream_writer &writer)
142 {
143 const auto &pwr = scl::board::get_instance().power();
144 // Serialize power_enable
145 writer.write<bool>(pwr.enabled(scl::power::subsys::RF_5V), 1);
146 writer.write<bool>(pwr.enabled(scl::power::subsys::FPGA_5V), 1);
147 writer.write<bool>(pwr.enabled(scl::power::subsys::CAN1), 1);
148 writer.write<bool>(pwr.enabled(scl::power::subsys::CAN1_LPWR), 1);
149 writer.write<bool>(pwr.enabled(scl::power::subsys::CAN2), 1);
150 writer.write<bool>(pwr.enabled(scl::power::subsys::CAN2_LPWR), 1);
151 writer.write<bool>(pwr.enabled(scl::power::subsys::UHF), 1);
152 writer.write<bool>(pwr.enabled(scl::power::subsys::SBAND), 1);
153
160 telemetry::serialize(writer, pwr.get_power(scl::power::sensor::EFUSES));
162
163 writer.write<bool>(pwr.pgood(scl::power::pgood_tp::RAIL_5V), 1);
164 writer.write<bool>(pwr.pgood(scl::power::pgood_tp::RAIL_FPGA), 1);
165 writer.write<bool>(pwr.pgood(scl::power::pgood_tp::RAIL_UHF), 1);
166 writer.write<bool>(pwr.pgood(scl::power::pgood_tp::RAIL_SBAND), 1);
167 }
168 };
169
171 {
172 public:
173 static void
174 serialize(etl::bit_stream_writer &writer)
175 {
176 using scr = scl::radio;
177
178 auto &b = scl::board::get_instance();
179 auto &radio = b.radio();
180 const auto &iface = io::get_instance().radio_ctrl().uhf();
181
182 writer.write(radio.enabled(scr::interface::UHF), 1);
183 writer.write(static_cast<bool>(radio.direction(scr::interface::UHF)), 1);
184 writer.write(static_cast<uint8_t>(iface.get_state()), 2);
185 writer.write(static_cast<uint8_t>(radio.uhf().get_filter()), 1);
186
187 writer.write<uint32_t>(
188 static_cast<uint32_t>(
189 radio.frequency(scr::interface::UHF, scl::rf_frontend::dir::TX)),
190 32);
191 writer.write<uint32_t>(
192 static_cast<uint32_t>(
193 radio.frequency(scr::interface::UHF, scl::rf_frontend::dir::RX)),
194 32);
195 const auto &stats = iface.get_stats();
196 writer.write(stats.tx_frames, 32);
197 writer.write(stats.tx_frames_fail, 32);
198 writer.write(stats.tx_frames_drop, 32);
199 writer.write(stats.rx_frames, 32);
200 writer.write(stats.rx_frames_inval, 32);
201 writer.write(stats.rx_frames_drop, 32);
202 writer.write<uint64_t>(stats.last_rx_ts, 64);
203 telemetry::serialize(writer, stats.last_rssi);
204 writer.write<uint64_t>(stats.last_valid_rx_ts, 64);
205 telemetry::serialize(writer, stats.last_valid_rssi);
206 }
207 };
208
210 {
211 public:
212 static void
213 serialize(etl::bit_stream_writer &writer)
214 {
215 using scr = scl::radio;
216
217 auto &b = scl::board::get_instance();
218 auto &radio = b.radio();
219 const auto &iface = io::get_instance().radio_ctrl().sband();
220
221 writer.write(radio.enabled(scr::interface::SBAND), 1);
222 writer.write(static_cast<bool>(radio.direction(scr::interface::SBAND)),
223 1);
224 writer.write(static_cast<uint8_t>(iface.get_state()), 2);
225 writer.write(radio.sband().mixer_lock(), 1);
226 writer.write(static_cast<uint8_t>(radio.sband().get_filter()), 1);
227
228 writer.write<uint32_t>(
229 static_cast<uint32_t>(radio.frequency(scr::interface::SBAND,
231 32);
232 writer.write<uint32_t>(
233 static_cast<uint32_t>(radio.frequency(scr::interface::SBAND,
235 32);
236
237 const auto &stats = iface.get_stats();
238 writer.write(stats.tx_frames, 32);
239 writer.write(stats.tx_frames_fail, 32);
240 writer.write(stats.tx_frames_drop, 32);
241 writer.write(stats.rx_frames, 32);
242 writer.write(stats.rx_frames_inval, 32);
243 writer.write(stats.rx_frames_drop, 32);
244 writer.write<uint64_t>(stats.last_rx_ts, 64);
245 telemetry::serialize(writer, stats.last_rssi);
246 writer.write<uint64_t>(stats.last_valid_rx_ts, 64);
247 telemetry::serialize(writer, stats.last_valid_rssi);
248 }
249 };
250
252 {
253 public:
254 static constexpr size_t size = 6U;
255 uint8_t version;
256 uint8_t type;
257 uint8_t sec_hdr;
258 uint16_t apid;
259 uint8_t group_flags;
260 uint16_t count;
261 uint16_t length;
262
264 : version(0),
265 type(0),
266 sec_hdr(0),
267 apid(0),
268 group_flags(0b11),
269 count(0),
270 length(0)
271 {
272 }
273
274 void
275 serialize(etl::bit_stream_writer &writer) const
276 {
277 writer.write<uint8_t>(version, 3);
278 writer.write<uint8_t>(type, 1);
279 writer.write<uint8_t>(sec_hdr, 1);
280 writer.write<uint16_t>(apid, 11);
281 writer.write<uint8_t>(group_flags, 2);
282 writer.write<uint16_t>(count, 14);
283 writer.write<uint16_t>(length, 16);
284 }
285 };
286
287 static telemetry &
289 {
290 static telemetry tlm;
291 return tlm;
292 }
293
294 /* Singleton */
295 telemetry(telemetry const &) = delete;
296
297 void
298 operator=(telemetry const &) = delete;
299
300 static void
301 serialize(etl::bit_stream_writer &writer, float x);
302
303 static void
304 serialize(etl::bit_stream_writer &writer, double x);
305
306 template <telemetry::apid Apid, typename... Args>
307 static void
308 tlm(msg_arbiter::msg &m, Args &&...args)
309 {
311 auto &tlc = telecommand::get_instance();
312 tm_header.apid = static_cast<uint16_t>(Apid);
313 tm_header.count = tlc.get_frame_count();
314
315 etl::bit_stream_writer bit_stream_hdr(
316 m.data, telemetry::ccsds_tm_header::size, etl::endian::big);
317 etl::bit_stream_writer bit_stream_pld(
320
321 serializer<Apid>::serialize(bit_stream_pld, std::forward<Args>(args)...);
322
323 tm_header.length = bit_stream_pld.size_bytes() + 1;
324 tm_header.serialize(bit_stream_hdr);
326 }
327
328 static void
329 send_ring_buffer_logs_tlm(msg_arbiter::msg &m, const size_t num_of_logs);
330
331 static void
333
334private:
335 telemetry();
336};
337
339{
340public:
341 static void
342 serialize(etl::bit_stream_writer &writer, uint8_t const buf[], size_t len)
343 {
344 for (size_t i = 0; i < len; ++i) {
345 writer.write<uint8_t>(buf[i], 8);
346 }
347 }
348};
349
351{
352public:
353 static void
354 serialize(etl::bit_stream_writer &writer, bool success)
355 {
356 writer.write<bool>(success, 1);
357 }
358};
359
361{
362public:
363 static void
364 serialize(etl::bit_stream_writer &writer)
365 {
366 auto &s = settings::get_instance();
367 writer.write<uint64_t>(k_uptime_get(), 64);
368 writer.write<uint32_t>(s.get<settings::param::BOOT_COUNT>(), 32);
369 // Serialize uhf_radio
371 // Serialize sband_radio
373 // Serialize power
375 }
376};
377
379{
380public:
381 static void
382 serialize(etl::bit_stream_writer &writer)
383 {
385 }
386};
387
389{
390public:
391 static void
392 serialize(etl::bit_stream_writer &writer)
393 {
394 auto &s = settings::get_instance();
395 auto thermal_state = thermal::get_instance().get_state();
396 writer.write<uint64_t>(k_uptime_get(), 64);
397 writer.write<uint32_t>(s.get<settings::param::BOOT_COUNT>(), 32);
398 // Serialize sensors
400 // Serialize rst_cause
401 writer.write<uint16_t>(error_handler::get_instance().hwinfo_reset_cause(),
402 15);
403 // Serialize power
405 // Serialize thermal state
406 writer.write<bool>(thermal_state.uhf_triggered, 1);
407 writer.write<bool>(thermal_state.sband_triggered, 1);
408 writer.write<bool>(thermal_state.uhf_sensor_valid, 1);
409 writer.write<bool>(thermal_state.sband_sensor_valid, 1);
410 writer.write<bool>(thermal_state.pcb_sensor_valid, 1);
411 // Add padding
412 writer.skip(6);
413 // Serialize latest exception message
414 auto &log = logger::get_instance();
415 auto retained_mem_str = log.get_latest_exception();
416 for (size_t i = 0; i < retained_mem_str.size(); ++i) {
417 writer.write<uint8_t>(static_cast<uint8_t>(retained_mem_str[i]), 8);
418 }
419 // Append the null termination byte for proper render at the MCS
420 writer.write<uint8_t>(0x0, 8);
421 }
422};
423
425{
426public:
427 static constexpr size_t hash_max_len = 256 / 8;
428
429 static void
430 append_git_hash(etl::bit_stream_writer &writer, const char *hash)
431 {
432 size_t hash_len = strnlen(hash, hash_max_len);
433 for (size_t i = 0; i < hash_len; i++) {
434 writer.write<uint8_t>(hash[i], 8);
435 }
436 for (size_t i = hash_len; i < hash_max_len; i++) {
437 writer.write<uint8_t>(0x0, 8);
438 }
439 }
440
441 static void
442 serialize(etl::bit_stream_writer &writer)
443 {
444 auto &s = settings::get_instance();
445 /* harware version */
446 writer.write<uint32_t>(scl::version::hw_major, 32);
447 writer.write<uint32_t>(scl::version::hw_minor, 32);
448 writer.write<uint32_t>(scl::version::hw_patch, 32);
449
450 /* libsatnogs-comms version */
451 writer.write<uint32_t>(scl::version::lib_major, 32);
452 writer.write<uint32_t>(scl::version::lib_minor, 32);
453 writer.write<uint32_t>(scl::version::lib_patch, 32);
454 append_git_hash(writer, scl::version::lib_git_hash);
455
456 /* firmware version */
457 writer.write<uint32_t>(satnogs::comms::version::fw_major, 32);
458 writer.write<uint32_t>(satnogs::comms::version::fw_minor, 32);
459 writer.write<uint32_t>(satnogs::comms::version::fw_patch, 32);
460 append_git_hash(writer, satnogs::comms::version::fw_git_hash);
461
462 writer.write<bool>(!s.get<settings::param::UHF_TX_EN>(), 1);
463 writer.write<bool>(!s.get<settings::param::SBAND_TX_EN>(), 1);
464 }
465};
466
468{
469public:
470 static void
471 serialize(etl::bit_stream_writer &writer)
472 {
473 auto &fpga = scl::board::get_instance().fpga();
474 writer.write<bool>(fpga.enabled(), 1);
475 writer.write<bool>(fpga.get_fpga_done(), 1);
476 // TODO: Add correct methods when implemented in libsatnogs-comms
477 writer.write<bool>(false, 1);
478 writer.write<bool>(false, 1);
479 writer.write<bool>(false, 1);
480 writer.write<uint8_t>(static_cast<uint8_t>(fpga.get_boot_mode()), 2);
481 }
482};
483
485{
486public:
487 static void
488 serialize(etl::bit_stream_writer &writer)
489 {
490 // Serialize uhf_radio
492 // Serialize sband_radio
494 // Serialize PLL clock source
495 writer.write<uint8_t>(
496 static_cast<uint8_t>(scl::board::get_instance().radio().get_clk_src()),
497 1);
498 }
499};
500
502{
503public:
504 static void
505 serialize(etl::bit_stream_writer &writer)
506 {
508 /* Uptime */
509 writer.write<uint64_t>(time.uptime(), 64);
510 uint64_t t;
511 writer.write<uint8_t>(static_cast<uint8_t>(time.get(t)), 8);
512 writer.write<uint64_t>(t, 64);
514 }
515};
516
518{
519public:
520 static void
521 serialize(etl::bit_stream_writer &writer)
522 {
523 auto &s = storage::get_instance();
524 writer.write<bool>(s.enabled(), 1);
525 writer.write<bool>(s.mounted(), 1);
526 writer.write<bool>(static_cast<bool>(s.get_dir()), 1);
527 }
528};
529
531{
532public:
533 static void
534 serialize(etl::bit_stream_writer &writer)
535 {
536#if CONFIG_BOOTLOADER_MCUBOOT
537 char v = 0;
538 blinfo_lookup(BLINFO_MODE, &v, sizeof(v));
539 writer.write<uint8_t>(v, 8);
540 v = 0;
541 blinfo_lookup(BLINFO_SIGNATURE_TYPE, &v, sizeof(v));
542 writer.write<uint8_t>(v, 8);
543 v = 0;
544 blinfo_lookup(BLINFO_RECOVERY, &v, sizeof(v));
545 writer.write<uint8_t>(v, 8);
546 blinfo_lookup(BLINFO_RUNNING_SLOT, &v, sizeof(v));
547 writer.write<uint8_t>(v, 8);
548
549 struct image_version mcuboot_version;
550 blinfo_lookup(BLINFO_BOOTLOADER_VERSION,
551 reinterpret_cast<char *>(&mcuboot_version),
552 sizeof(mcuboot_version));
553 writer.write<uint32_t>(mcuboot_version.iv_major, 32);
554 writer.write<uint32_t>(mcuboot_version.iv_minor, 32);
555 writer.write<uint32_t>(mcuboot_version.iv_revision, 32);
556
557 uint32_t s = 0;
558 blinfo_lookup(BLINFO_MAX_APPLICATION_SIZE, reinterpret_cast<char *>(&s),
559 sizeof(s));
560 writer.write<uint32_t>(s, 32);
561 writer.write<bool>(boot_is_img_confirmed(), 1);
562
563 /* Have a look at ota class for this one */
564 uint8_t areas[2] = {FIXED_PARTITION_ID(slot0_partition),
565 FIXED_PARTITION_ID(slot1_partition)};
566 /* Get the fimrware information for the two available slots */
567 for (uint8_t i = 0; i < 2; i++) {
568 struct mcuboot_img_header mcuboot_hdr;
569 memset(&mcuboot_hdr, 0, sizeof(mcuboot_hdr));
570 boot_read_bank_header(areas[i], &mcuboot_hdr, sizeof(mcuboot_hdr));
571 writer.write<uint32_t>(mcuboot_hdr.h.v1.image_size, 32);
572 writer.write<uint32_t>(mcuboot_hdr.h.v1.sem_ver.major, 32);
573 writer.write<uint32_t>(mcuboot_hdr.h.v1.sem_ver.minor, 32);
574 writer.write<uint32_t>(mcuboot_hdr.h.v1.sem_ver.revision, 32);
575 }
576#endif
577 }
578};
579
581{
582public:
583 static void
584 serialize(etl::bit_stream_writer &writer, etl::istring &path)
585 {
587 etl::string_ext res(reinterpret_cast<char *>(writer.begin()),
588 writer.capacity_bytes());
589 storage.ls(path, res);
590 writer.skip(res.length() * 8 + 8);
591 }
592};
593
595{
596public:
597 static void
598 serialize(etl::bit_stream_writer &writer, etl::istring &path, size_t offset,
599 size_t len)
600 {
602 size_t bytes = storage.read(
603 path, (uint8_t *)(writer.begin() + sizeof(uint32_t)), len, offset);
604 writer.write<uint32_t>(bytes, 32);
605 writer.skip(8 * bytes);
606 }
607};
608
610{
611public:
612 static void
613 serialize(etl::bit_stream_writer &writer, etl::istring &path)
614 {
616 uint32_t ret = storage.du(path);
617 memcpy(writer.begin(), path.c_str(), path.size());
618 writer.skip(8 * path.size());
619 writer.write<char>('\0', 8);
620 writer.write<uint32_t>(ret, 32);
621 writer.write(static_cast<bool>(storage.is_dir(path)), 1);
622 }
623};
624
626{
627public:
628 static void
629 serialize(etl::bit_stream_writer &writer)
630 {
631 auto &s = settings::get_instance();
632 /* Boot count */
633 writer.write<uint32_t>(s.get<settings::param::BOOT_COUNT>(), 32);
634
635 /* WDT period setting */
636 writer.write<uint32_t>(s.get<settings::param::IO_WDG_PERIOD_MINS>(), 32);
637
638 /* PLL reference clock setting */
639 writer.write<uint8_t>(s.get<settings::param::PLL_REF_CLK_SRC>(), 1);
640
641 /* UHF radio settings */
642 writer.write<uint32_t>(s.get<settings::param::UHF_TX_FREQ>(), 32);
643 writer.write<uint32_t>(s.get<settings::param::UHF_RX_FREQ>(), 32);
644 writer.write<bool>(s.get<settings::param::UHF_TX_EN>(), 1);
646 writer.write<uint32_t>(s.get<settings::param::UHF_RX_RANGE_MIN>(), 32);
647 writer.write<uint32_t>(s.get<settings::param::UHF_RX_RANGE_MAX>(), 32);
648 writer.write<uint32_t>(s.get<settings::param::UHF_TX_RANGE_MIN>(), 32);
649 writer.write<uint32_t>(s.get<settings::param::UHF_TX_RANGE_MAX>(), 32);
662 writer.write<uint8_t>(
663 static_cast<uint8_t>(s.get<settings::param::UHF_FILTER>()), 1);
664
665 writer.write<uint8_t>(
666 static_cast<uint8_t>(s.get<settings::param::UHF_GAIN0_MODE>()), 1);
667 writer.write<uint8_t>(
668 static_cast<uint8_t>(s.get<settings::param::UHF_GAIN1_MODE>()), 1);
669
672 auto agc1 = s.get<settings::param::UHF_GAIN1_AGC>();
673 writer.write<uint8_t>(agc1.avg, 2);
674 writer.write<uint8_t>(agc1.input, 1);
675 writer.write<uint8_t>(agc1.tgt, 3);
677
678 writer.write<uint8_t>(
679 static_cast<uint8_t>(s.get<settings::param::UHF_TX_MODULATION>()), 3);
680 writer.write<uint8_t>(
681 static_cast<uint8_t>(s.get<settings::param::UHF_RX_MODULATION>()), 3);
682
683 auto fsk = s.get<settings::param::UHF_FSK_TX>();
684 writer.write<uint8_t>(fsk.baudrate, 3);
685 telemetry::serialize(writer, fsk.mod_idx);
686 telemetry::serialize(writer, fsk.shaping);
687 fsk = s.get<settings::param::UHF_FSK_RX>();
688 writer.write<uint8_t>(fsk.baudrate, 3);
689 telemetry::serialize(writer, fsk.mod_idx);
690 writer.write<bool>(s.get<settings::param::UHF_ENABLE>(), 1);
691 writer.write<uint32_t>(s.get<settings::param::UHF_TRX_TURNAROUND_MS>(), 32);
692 writer.write<uint32_t>(s.get<settings::param::UHF_RX_ON_SECS>(), 32);
693 writer.write<uint32_t>(s.get<settings::param::UHF_RX_OFF_SECS>(), 32);
694 writer.write<uint32_t>(s.get<settings::param::UHF_TX_WAIT_MS>(), 32);
695
696 /* S-band radio settings */
697 writer.write<uint32_t>(s.get<settings::param::SBAND_TX_FREQ>(), 32);
698 writer.write<uint32_t>(s.get<settings::param::SBAND_RX_FREQ>(), 32);
699 writer.write<bool>(s.get<settings::param::SBAND_TX_EN>(), 1);
701 writer.write<uint32_t>(s.get<settings::param::SBAND_RX_RANGE_MIN>(), 32);
702 writer.write<uint32_t>(s.get<settings::param::SBAND_RX_RANGE_MAX>(), 32);
703 writer.write<uint32_t>(s.get<settings::param::SBAND_TX_RANGE_MIN>(), 32);
704 writer.write<uint32_t>(s.get<settings::param::SBAND_TX_RANGE_MAX>(), 32);
721 writer.write<uint8_t>(
722 static_cast<uint8_t>(s.get<settings::param::SBAND_FILTER>()), 1);
723
724 writer.write<uint8_t>(
725 static_cast<uint8_t>(s.get<settings::param::SBAND_GAIN0_MODE>()), 1);
726 writer.write<uint8_t>(
727 static_cast<uint8_t>(s.get<settings::param::SBAND_GAIN1_MODE>()), 1);
728
731 agc1 = s.get<settings::param::SBAND_GAIN1_AGC>();
732 writer.write<uint8_t>(agc1.avg, 2);
733 writer.write<uint8_t>(agc1.input, 1);
734 writer.write<uint8_t>(agc1.tgt, 3);
736
737 writer.write<uint8_t>(
738 static_cast<uint8_t>(s.get<settings::param::SBAND_TX_MODULATION>()), 3);
739 writer.write<uint8_t>(
740 static_cast<uint8_t>(s.get<settings::param::SBAND_RX_MODULATION>()), 3);
741
742 fsk = s.get<settings::param::SBAND_FSK_TX>();
743 writer.write<uint8_t>(fsk.baudrate, 3);
744 telemetry::serialize(writer, fsk.mod_idx);
745 telemetry::serialize(writer, fsk.shaping);
746 fsk = s.get<settings::param::SBAND_FSK_RX>();
747 writer.write<uint8_t>(fsk.baudrate, 3);
748 telemetry::serialize(writer, fsk.mod_idx);
749 writer.write<bool>(s.get<settings::param::SBAND_ENABLE>(), 1);
750 writer.write<uint32_t>(s.get<settings::param::SBAND_TRX_TURNAROUND_MS>(),
751 32);
752 writer.write<uint32_t>(s.get<settings::param::SBAND_RX_ON_SECS>(), 32);
753 writer.write<uint32_t>(s.get<settings::param::SBAND_RX_OFF_SECS>(), 32);
754 writer.write<uint32_t>(s.get<settings::param::SBAND_TX_WAIT_MS>(), 32);
755
756 // Serializing thermal monitor parameters
773 }
774};
775
777{
778public:
779 static void
780 serialize(etl::bit_stream_writer &writer, size_t start_sector, size_t sectors)
781 {
783 /* Clamp to the available response size */
784 size_t nbytes = sectors * storage::SECTOR_SIZE;
785 nbytes = etl::clamp(nbytes, 0U, writer.available<uint8_t>());
786 size_t ret = storage.read_raw(
787 reinterpret_cast<uint8_t *>(writer.end() + sizeof(uint32_t)),
788 start_sector, nbytes / storage::SECTOR_SIZE);
789 writer.write<uint32_t>(ret * storage::SECTOR_SIZE, 32);
790 writer.skip(ret * storage::SECTOR_SIZE * 8);
791 }
792};
793
795{
796public:
797 static void
798 serialize(etl::bit_stream_writer &writer, const ota::response_tlm &resp)
799 {
800 writer.write<uint8_t>(resp.session, 8);
801 writer.write<uint8_t>(static_cast<uint8_t>(resp.s), 8);
802 writer.write<uint32_t>(resp.ack, 32);
803 }
804};
805
806} // namespace satnogs::comms
static error_handler & get_instance()
Singleton access to the error_handler subsystem.
uint32_t hwinfo_reset_cause() const
Retrieves the hardware reset cause from the MCU.
const utils::iface_ctrl & uhf()
Definition io.hpp:163
const utils::iface_ctrl & sband()
Definition io.hpp:169
static io & get_instance()
Definition io.hpp:181
radio & radio_ctrl()
Definition io.cpp:139
comms::lib::power & power()
Returns a reference to the power subsystem.
Definition board.cpp:102
comms::lib::radio & radio()
Returns a reference to the radio subsystem.
Definition board.cpp:80
comms::lib::fpga & fpga()
Returns a reference to the FPGA subsystem.
Definition board.cpp:113
static board & get_instance()
Gets a reference to the single instance of the Board interface class.
Definition board.cpp:66
@ EFUSES
Power measured by eFuses.
Definition power.hpp:67
@ EMC1702
Power measured by the EMC1702 sensor.
Definition power.hpp:68
@ CAN2_LPWR
Low-power mode for CAN Bus 2.
Definition power.hpp:56
@ CAN1_LPWR
Low-power mode for CAN Bus 1.
Definition power.hpp:55
@ RF_5V
RF 5V voltage/current channel.
Definition power.hpp:79
@ V_BAT
Battery voltage channel.
Definition power.hpp:82
@ FPGA
FPGA voltage/current channel.
Definition power.hpp:78
@ DIG_3V3
Digital 3.3V voltage/current channel.
Definition power.hpp:80
@ VIN
Input voltage channel.
Definition power.hpp:81
Radio subsystem providing TX/RX functionality on UHF and S-Band.
Definition radio.hpp:127
clk_src get_clk_src() const
Retrieves the current clock source of the AT86RF215 PLL.
Definition radio.cpp:1104
static logger & get_instance()
Singleton access to the logger subsystem.
Definition logger.hpp:102
uint8_t data[mtu]
Buffer to hold the data.
size_t len
Data size in bytes.
static constexpr size_t mtu
static settings & get_instance()
Get a singleton access to the settings subsystem.
Definition settings.hpp:210
size_t read(const etl::istring &path, uint8_t *b, size_t len, size_t offset)
Reads from a file starting from specific offset.
Definition storage.cpp:730
void ls(const etl::istring &path, etl::istring &res)
Lists the contents of a directory.
Definition storage.cpp:624
uint64_t du(const etl::istring &path)
Calculate the disk usage of a file or directory likewise the 'du' command of Linux.
Definition storage.cpp:562
size_t read_raw(uint8_t *b, size_t start_sector, size_t sectors)
Reads directly raw sectors from the eMMC, bypassing any filesystem.
Definition storage.cpp:855
static storage & get_instance()
Definition storage.hpp:94
bool is_dir(const etl::istring &path)
Check if a path is a directory.
Definition storage.cpp:714
static constexpr size_t SECTOR_SIZE
Definition storage.hpp:36
static telecommand & get_instance()
void serialize(etl::bit_stream_writer &writer) const
static void serialize(etl::bit_stream_writer &writer)
static void serialize(etl::bit_stream_writer &writer)
static void serialize(etl::bit_stream_writer &writer)
static void serialize(etl::bit_stream_writer &writer)
Definition telemetry.hpp:93
static void serialize(etl::bit_stream_writer &writer)
static void serialize(etl::bit_stream_writer &writer, bool success)
static void append_git_hash(etl::bit_stream_writer &writer, const char *hash)
static void serialize(etl::bit_stream_writer &writer)
static void serialize(etl::bit_stream_writer &writer, size_t start_sector, size_t sectors)
static void serialize(etl::bit_stream_writer &writer)
static void serialize(etl::bit_stream_writer &writer)
static void serialize(etl::bit_stream_writer &writer, const ota::response_tlm &resp)
static void serialize(etl::bit_stream_writer &writer, uint8_t const buf[], size_t len)
static void serialize(etl::bit_stream_writer &writer)
static void serialize(etl::bit_stream_writer &writer)
static void serialize(etl::bit_stream_writer &writer)
static void serialize(etl::bit_stream_writer &writer, etl::istring &path)
static void serialize(etl::bit_stream_writer &writer, etl::istring &path)
static void serialize(etl::bit_stream_writer &writer, etl::istring &path, size_t offset, size_t len)
static void serialize(etl::bit_stream_writer &writer)
static void serialize(etl::bit_stream_writer &writer)
static void send_ring_buffer_logs_tlm(msg_arbiter::msg &m, const size_t num_of_logs)
Definition telemetry.cpp:48
void operator=(telemetry const &)=delete
static telemetry & get_instance()
static void send_all_ota_sessions_info_tlm(msg_arbiter::msg &m)
Definition telemetry.cpp:93
static void serialize(etl::bit_stream_writer &writer, float x)
Definition telemetry.cpp:30
static void tlm(msg_arbiter::msg &m, Args &&...args)
telemetry(telemetry const &)=delete
state get_state() const
Definition thermal.hpp:85
static thermal & get_instance()
Definition thermal.hpp:75
Time and position information.
Definition time.hpp:60
void gnss(struct gnss_data &data)
Retrieve latest GNSS information.
Definition time.cpp:237
time_src get(uint64_t &t)
Gets the time in ms.
Definition time.cpp:111
uint64_t uptime()
Gets the current system uptime in milliseconds.
Definition time.cpp:167
uint64_t last_gnss_update_uptime()
Gets the system uptime (in milliseconds) at the time of the last GNSS fix.
Definition time.cpp:179
uint64_t last_nmea_update_uptime()
Definition time.cpp:185
static time & get_instance()
Definition time.hpp:63
@ UHF_PA
UHF PA temperature sensor.
@ SBAND_PA
S-Band PA temperature sensor.
uint8_t buf[chunk_bytes]
scl::radio radio
Definition settings.cpp:30
constexpr off_t offset
Definition settings.cpp:34