SatNOGS-COMMS  4.1.0
A COMMS subsystem for CubeSats
Loading...
Searching...
No Matches
io.cpp
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#include "io.hpp"
23#include <dsp/ccsds.hpp>
24#include <etl/crc.h>
25
26namespace satnogs::comms
27{
28
29static constexpr bool pc104_uart_en =
30 DT_NODE_HAS_STATUS(DT_NODELABEL(usart3), okay);
31
32static struct k_thread radio_rx_thread_data;
33K_THREAD_STACK_DEFINE(radio_rx_thread_stack, CONFIG_RADIO_RX_THREAD_STACK_SIZE);
34static struct k_thread uhf_tx_thread_data;
35K_THREAD_STACK_DEFINE(uhf_tx_thread_stack, CONFIG_UHF_TX_THREAD_STACK_SIZE);
36static struct k_thread sband_tx_thread_data;
37K_THREAD_STACK_DEFINE(sband_tx_thread_stack, CONFIG_SBAND_TX_THREAD_STACK_SIZE);
38
39#if CONFIG_IO_CAN1_ENABLE
40static const struct device *can1_dev = DEVICE_DT_GET(DT_NODELABEL(fdcan1));
41
42static struct k_thread can1_tx_thread_data;
43static struct k_thread can1_rx_thread_data;
44K_THREAD_STACK_DEFINE(can1_tx_thread_stack, CONFIG_CAN1_TX_THREAD_STACK_SIZE);
45K_THREAD_STACK_DEFINE(can1_rx_thread_stack, CONFIG_CAN1_RX_THREAD_STACK_SIZE);
46
47/* We want to accept messages from everyone */
48static const struct isotp_msg_id can1_rx_filter = {
49 .std_id = CONFIG_CAN1_ISOTP_REMOTE_PEER_RX_ADDR,
50 .ext_addr = 0,
51 .dl = 8,
52 .flags = 0};
53
54static const struct isotp_msg_id can1_tx_conf = {
55 .std_id = CONFIG_CAN1_ISOTP_TX_ADDR, .ext_addr = 0, .dl = 8, .flags = 0};
56static const struct isotp_msg_id can1_tx_remote_conf = {
57 .std_id = CONFIG_CAN1_ISOTP_REMOTE_PEER_TX_ADDR,
58 .ext_addr = 0,
59 .dl = 8,
60 .flags = 0};
61
62static const struct isotp_msg_id can1_rx_conf = {
63 .std_id = CONFIG_CAN1_ISOTP_RX_ADDR, .ext_addr = 0, .dl = 8, .flags = 0};
64/*
65 * Set the BS to 0 for receiving the ISOTP frame in a single isotp_recv_net()
66 * call
67 */
68const struct isotp_fc_opts can1_fc_opts = {.bs = 8, .stmin = 0};
69
70static struct isotp_recv_ctx can1_recv_ctx;
71static struct isotp_send_ctx can1_send_ctx;
72
73#endif
74
75#if CONFIG_IO_CAN2_ENABLE
76static const struct device *can2_dev = DEVICE_DT_GET(DT_NODELABEL(fdcan2));
77
78static struct k_thread can2_tx_thread_data;
79static struct k_thread can2_rx_thread_data;
80K_THREAD_STACK_DEFINE(can2_tx_thread_stack, CONFIG_CAN2_TX_THREAD_STACK_SIZE);
81K_THREAD_STACK_DEFINE(can2_rx_thread_stack, CONFIG_CAN2_RX_THREAD_STACK_SIZE);
82
83static const struct isotp_msg_id can2_rx_filter = {
84 .std_id = CONFIG_CAN2_ISOTP_REMOTE_PEER_RX_ADDR,
85 .ext_addr = 0,
86 .dl = 8,
87 .flags = 0};
88
89static const struct isotp_msg_id can2_tx_conf = {
90 .std_id = CONFIG_CAN2_ISOTP_TX_ADDR, .ext_addr = 0, .dl = 8, .flags = 0};
91static const struct isotp_msg_id can2_tx_remote_conf = {
92 .std_id = CONFIG_CAN2_ISOTP_REMOTE_PEER_TX_ADDR,
93 .ext_addr = 0,
94 .dl = 8,
95 .flags = 0};
96
97static const struct isotp_msg_id can2_rx_conf = {
98 .std_id = CONFIG_CAN2_ISOTP_RX_ADDR, .ext_addr = 0, .dl = 8, .flags = 0};
99/*
100 * Set the BS to 0 for receiving the ISOTP frame in a single isotp_recv_net()
101 * call
102 */
103const struct isotp_fc_opts can2_fc_opts = {.bs = 8, .stmin = 0};
104
105static struct isotp_recv_ctx can2_recv_ctx;
106static struct isotp_send_ctx can2_send_ctx;
107
108#endif
109/*
110 * Those messages are quite large and we do not want to take the memory from the
111 * task stack
112 */
113#if CONFIG_IO_CAN1_ENABLE
114static msg_arbiter::msg can1_tx_msg;
115static msg_arbiter::msg can1_rx_msg;
116#endif
117
118#if CONFIG_IO_CAN2_ENABLE
119static msg_arbiter::msg can2_tx_msg;
120static msg_arbiter::msg can2_rx_msg;
121#endif
122
123static scl::radio::rx_msg radio_rx_msg;
124static msg_arbiter::msg radio_msg_to_arb;
125static msg_arbiter::msg uhf_msg_from_arb;
126static msg_arbiter::msg sband_msg_from_arb;
127
128#if DT_NODE_HAS_STATUS(DT_ALIAS(pc104_usart3), okay)
129static void
130uart_handling_callback(const struct device *dev, struct uart_event *evt,
131 void *user_data);
132#endif
133
134#if DT_NODE_HAS_STATUS(DT_ALIAS(pc104_usart3), okay)
136#endif
137
138io::radio &
140{
141 return m_radio;
142}
143
144void
146{
147 /* Register necessary callbacks */
148 auto drop_clbk = etl::delegate<void(scl::radio::interface)>::create<
149 io, &io::radio_rx_drop_callback>(io::get_instance());
151
152 auto &err = error_handler::get_instance();
153 auto &pwr = scl::board::get_instance().power();
154 int ret = 0;
155
156 /*
157 * By default both radio interfaces are enabled. It's the responsibility of
158 * the mission to disable any of them if not needed
159 */
160 m_radio.enable();
161
162#if CONFIG_IO_CAN1_ENABLE
163 /* Enable the power line before doing anything */
164 pwr.enable(scl::power::subsys::CAN1);
165 k_msleep(10);
166 ret = can_start(can1_dev);
167 err.assert_error<can_enable_exception>((ret == 0), __FILE__, __LINE__);
168
169 ret = isotp_bind(&can1_recv_ctx, can1_dev, &can1_rx_filter, &can1_rx_conf,
170 &can1_fc_opts, K_FOREVER);
171 err.assert_error<isotp_bind_exception>((ret == 0), __FILE__, __LINE__);
172
173 m_can1_tx_tid = k_thread_create(&can1_tx_thread_data, can1_tx_thread_stack,
174 K_THREAD_STACK_SIZEOF(can1_tx_thread_stack),
175 can1_tx_thread, NULL, NULL, NULL,
176 CONFIG_CAN1_TX_THREAD_PRIO, 0, K_NO_WAIT);
177 if (!m_can1_tx_tid) {
178 k_oops();
179 }
180 k_thread_name_set(m_can1_tx_tid, "can1_tx");
181
182 m_can1_rx_tid = k_thread_create(&can1_rx_thread_data, can1_rx_thread_stack,
183 K_THREAD_STACK_SIZEOF(can1_rx_thread_stack),
184 can1_rx_thread, NULL, NULL, NULL,
185 CONFIG_CAN1_RX_THREAD_PRIO, 0, K_NO_WAIT);
186 if (!m_can1_rx_tid) {
187 k_oops();
188 }
189 k_thread_name_set(m_can1_rx_tid, "can1_rx");
190#endif
191
192#if CONFIG_IO_CAN2_ENABLE
193 /* Enable the power line before doing anything */
194 pwr.enable(scl::power::subsys::CAN2);
195 k_msleep(10);
196 ret = can_start(can2_dev);
197 err.assert_error<can_enable_exception>((ret == 0), __FILE__, __LINE__);
198
199 ret = isotp_bind(&can2_recv_ctx, can2_dev, &can2_rx_filter, &can2_rx_conf,
200 &can2_fc_opts, K_FOREVER);
201 err.assert_error<isotp_bind_exception>((ret == 0), __FILE__, __LINE__);
202
203 m_can2_tx_tid = k_thread_create(&can2_tx_thread_data, can2_tx_thread_stack,
204 K_THREAD_STACK_SIZEOF(can2_tx_thread_stack),
205 can2_tx_thread, NULL, NULL, NULL,
206 CONFIG_CAN2_TX_THREAD_PRIO, 0, K_NO_WAIT);
207 if (!m_can2_tx_tid) {
208 k_oops();
209 }
210 k_thread_name_set(m_can2_tx_tid, "can2_tx");
211
212 m_can2_rx_tid = k_thread_create(&can2_rx_thread_data, can2_rx_thread_stack,
213 K_THREAD_STACK_SIZEOF(can2_rx_thread_stack),
214 can2_rx_thread, NULL, NULL, NULL,
215 CONFIG_CAN2_RX_THREAD_PRIO, 0, K_NO_WAIT);
216 if (!m_can2_rx_tid) {
217 k_oops();
218 }
219 k_thread_name_set(m_can2_rx_tid, "can2_rx");
220#endif
221
222 m_radio_rx_tid = k_thread_create(&radio_rx_thread_data, radio_rx_thread_stack,
223 K_THREAD_STACK_SIZEOF(radio_rx_thread_stack),
224 radio_rx_thread, NULL, NULL, NULL,
225 CONFIG_RADIO_RX_THREAD_PRIO, 0, K_NO_WAIT);
226
227 m_uhf_tx_tid = k_thread_create(&uhf_tx_thread_data, uhf_tx_thread_stack,
228 K_THREAD_STACK_SIZEOF(uhf_tx_thread_stack),
229 uhf_tx_thread, NULL, NULL, NULL,
230 CONFIG_UHF_TX_THREAD_PRIO, 0, K_NO_WAIT);
231
232 m_sband_tx_tid = k_thread_create(&sband_tx_thread_data, sband_tx_thread_stack,
233 K_THREAD_STACK_SIZEOF(sband_tx_thread_stack),
234 sband_tx_thread, NULL, NULL, NULL,
235 CONFIG_SBAND_TX_THREAD_PRIO, 0, K_NO_WAIT);
236
237 if (!m_radio_rx_tid) {
238 k_oops();
239 }
240 if (!m_uhf_tx_tid) {
241 k_oops();
242 }
243
244 if (!m_sband_tx_tid) {
245 k_oops();
246 }
247 k_thread_name_set(m_radio_rx_tid, "radio_rx");
248 k_thread_name_set(m_uhf_tx_tid, "uhf_tx");
249 k_thread_name_set(m_sband_tx_tid, "sband_tx");
250
251#if DT_NODE_HAS_STATUS(DT_ALIAS(pc104_usart3), okay)
252 const struct device *uart_dev = DEVICE_DT_GET(DT_ALIAS(pc104_usart3));
253
254 const struct uart_config uart_cfg = {.baudrate = CONFIG_PC104_UART_BAUDRATE,
255 .parity = UART_CFG_PARITY_NONE,
256 .stop_bits = UART_CFG_STOP_BITS_1,
257 .data_bits = UART_CFG_DATA_BITS_8,
258 .flow_ctrl = UART_CFG_FLOW_CTRL_NONE};
259 uart_rx_disable(uart_dev);
260 uart_configure(uart_dev, &uart_cfg);
261 uart_callback_set(uart_dev, uart_handling_callback, &usart3);
262 uart_rx_enable(uart_dev, usart3.buf[usart3.buf_idx], io::uart::buf_len,
263 CONFIG_PC104_UART_RX_TIMEOUT_MS);
264#endif
265}
266
267#if CONFIG_IO_CAN1_ENABLE
268void
269io::can1_tx_thread(void *arg1, void *arg2, void *arg3)
270{
271 auto &err = error_handler::get_instance();
272 int task_wdt_id = task_wdt_add(CONFIG_WATCHDOG_PERIOD_CAN1_TX,
273 task_wdt_callback, (void *)k_current_get());
275 int ret;
276 while (1) {
277 try {
278 task_wdt_feed(task_wdt_id);
279 ret = arb.pull(can1_tx_msg, msg_arbiter::subsys::CAN1, K_MSEC(100));
280 if (ret == 0) {
281 isotp_send(&can1_send_ctx, can1_dev, can1_tx_msg.data, can1_tx_msg.len,
282 &can1_tx_conf, &can1_tx_remote_conf, NULL, NULL);
283 }
284 } catch (const scl::exception &e) {
285 err.handle(e);
286 } catch (const std::exception &e) {
287 err.handle(e);
288 }
289 }
290}
291
292void
293io::can1_rx_thread(void *arg1, void *arg2, void *arg3)
294{
295 auto &err = error_handler::get_instance();
296 int task_wdt_id = task_wdt_add(CONFIG_WATCHDOG_PERIOD_CAN1_RX,
297 task_wdt_callback, (void *)k_current_get());
298 msg_arbiter &arb = msg_arbiter::get_instance();
299 struct net_buf *buf;
300 int ret;
301
302 while (1) {
303 try {
304 task_wdt_feed(task_wdt_id);
305 can1_rx_msg.iface = msg_arbiter::subsys::CAN1;
306 can1_rx_msg.len = 0;
307 do {
308 ret = isotp_recv_net(&can1_recv_ctx, &buf, K_MSEC(100));
309 if (ret == ISOTP_RECV_TIMEOUT) {
310 /* This is ok! */
311 break;
312 }
313 if (ret < 0) {
314 err.assert_error<isotp_recv_exception>(__FILE__, __LINE__);
315 break;
316 }
317 while (buf != nullptr) {
318 /* Clamp to the available MTU */
319 size_t ncpy =
320 std::min<size_t>(msg_arbiter::mtu - can1_rx_msg.len, buf->len);
321
322 std::memcpy(can1_rx_msg.data + can1_rx_msg.len, buf->data, ncpy);
323 can1_rx_msg.len += ncpy;
324 buf = net_buf_frag_del(NULL, buf);
325 }
326 } while (ret > 0);
327 if (can1_rx_msg.len > 0) {
328 arb.push(can1_rx_msg);
329 }
330 } catch (const scl::exception &e) {
331 err.handle(e);
332 } catch (const std::exception &e) {
333 err.handle(e);
334 }
335 }
336}
337
338#endif
339
340#if CONFIG_IO_CAN2_ENABLE
341void
342io::can2_tx_thread(void *arg1, void *arg2, void *arg3)
343{
344 auto &err = error_handler::get_instance();
345 int task_wdt_id = task_wdt_add(CONFIG_WATCHDOG_PERIOD_CAN2_TX,
346 task_wdt_callback, (void *)k_current_get());
347 msg_arbiter &arb = msg_arbiter::get_instance();
348 int ret;
349 while (1) {
350 try {
351 task_wdt_feed(task_wdt_id);
352 ret = arb.pull(can2_tx_msg, msg_arbiter::subsys::CAN2, K_MSEC(100));
353 if (ret == 0) {
354 isotp_send(&can2_send_ctx, can2_dev, can2_tx_msg.data, can2_tx_msg.len,
355 &can2_tx_conf, &can2_tx_remote_conf, NULL, NULL);
356 }
357 } catch (const scl::exception &e) {
358 err.handle(e);
359 } catch (const std::exception &e) {
360 err.handle(e);
361 }
362 }
363}
364
365void
366io::can2_rx_thread(void *arg1, void *arg2, void *arg3)
367{
368 auto &err = error_handler::get_instance();
369 int task_wdt_id = task_wdt_add(CONFIG_WATCHDOG_PERIOD_CAN2_RX,
370 task_wdt_callback, (void *)k_current_get());
371 msg_arbiter &arb = msg_arbiter::get_instance();
372 struct net_buf *buf;
373 int ret;
374
375 while (1) {
376 try {
377 task_wdt_feed(task_wdt_id);
378 can2_rx_msg.iface = msg_arbiter::subsys::CAN2;
379 can2_rx_msg.len = 0;
380 do {
381 ret = isotp_recv_net(&can2_recv_ctx, &buf, K_MSEC(100));
382 if (ret == ISOTP_RECV_TIMEOUT) {
383 /* This is ok! */
384 break;
385 }
386 if (ret < 0) {
387 err.assert_error<isotp_recv_exception>(__FILE__, __LINE__);
388 break;
389 }
390 while (buf != nullptr) {
391 /* Clamp to the available MTU */
392 size_t ncpy =
393 std::min<size_t>(msg_arbiter::mtu - can2_rx_msg.len, buf->len);
394
395 std::memcpy(can2_rx_msg.data + can2_rx_msg.len, buf->data, ncpy);
396 can2_rx_msg.len += ncpy;
397 buf = net_buf_frag_del(NULL, buf);
398 }
399 } while (ret > 0);
400 if (can2_rx_msg.len > 0) {
401 arb.push(can2_rx_msg);
402 }
403 } catch (const scl::exception &e) {
404 err.handle(e);
405 } catch (const std::exception &e) {
406 err.handle(e);
407 }
408 }
409}
410#endif
411
412static uint32_t
413received_crc(const uint8_t *b, uint32_t len)
414{
415 return (b[len - sizeof(uint32_t)] << 24) |
416 (b[len - sizeof(uint32_t) + 1] << 16) |
417 (b[len - sizeof(uint32_t) + 2] << 8) | (b[len - sizeof(uint32_t) + 3]);
418}
419
420void
421io::radio_rx_thread(void *arg1, void *arg2, void *arg3)
422{
423 int task_wdt_id = task_wdt_add(CONFIG_WATCHDOG_PERIOD_RADIO_RX,
424 task_wdt_callback, (void *)k_current_get());
426 msg_arbiter &arb = msg_arbiter::get_instance();
427 while (1) {
428 try {
429 task_wdt_feed(task_wdt_id);
430 int ret = radio.recv_msg(radio_rx_msg, 1000);
431 if (ret == 0) {
432 /* Perform descrambling first */
433 dsp::ccsds::descrambler(radio_rx_msg.pdu, radio_rx_msg.info.len);
434
435 /* Check the validity of the frame */
436 auto crc = etl::crc32_c(radio_rx_msg.pdu, radio_rx_msg.pdu +
437 radio_rx_msg.info.len -
438 sizeof(uint32_t))
439 .value();
440 uint32_t recv_crc =
441 received_crc(radio_rx_msg.pdu, radio_rx_msg.info.len);
442 /* Update the internal statistics of the interface */
443 io::get_instance().update_radio_rx_stats(
444 radio_rx_msg.info.iface, crc == recv_crc, radio_rx_msg.info.rssi);
445
446 /* Forward the frame to the message arbiter only if the CRC was valid */
447 if (crc == recv_crc) {
448 radio_msg_to_arb.iface =
449 radio_rx_msg.info.iface == scl::radio::interface::UHF
452 std::copy_n(radio_rx_msg.pdu, radio_rx_msg.info.len,
453 radio_msg_to_arb.data);
454
455 radio_msg_to_arb.len = radio_rx_msg.info.len;
456 arb.push(radio_msg_to_arb);
457 }
458 }
459 } catch (const scl::exception &e) {
460 auto &err = error_handler::get_instance();
461 err.handle(e);
462 } catch (const std::exception &e) {
463 auto &err = error_handler::get_instance();
464 err.handle(e);
465 }
466 }
467}
468
469void
470io::uhf_tx_thread(void *arg1, void *arg2, void *arg3)
471{
472 int task_wdt_id = task_wdt_add(CONFIG_WATCHDOG_PERIOD_RADIO_TX,
473 task_wdt_callback, (void *)k_current_get());
475 msg_arbiter &arb = msg_arbiter::get_instance();
476
477 while (1) {
478 try {
479 task_wdt_feed(task_wdt_id);
480 int ret = arb.pull(uhf_msg_from_arb, msg_arbiter::subsys::RADIO_UHF,
481 K_MSEC(1000));
482 // Nothing received probably. Try again
483 if (ret) {
484 continue;
485 }
486 radio_ctrl.tx(scl::radio::interface::UHF, uhf_msg_from_arb,
487 arb.backpressure(msg_arbiter::subsys::RADIO_UHF) > 0);
488 } catch (const scl::exception &e) {
489 auto &err = error_handler::get_instance();
490 err.handle(e);
491 } catch (const std::exception &e) {
492 auto &err = error_handler::get_instance();
493 err.handle(e);
494 }
495 }
496}
497
498void
499io::sband_tx_thread(void *arg1, void *arg2, void *arg3)
500{
501 int task_wdt_id = task_wdt_add(CONFIG_WATCHDOG_PERIOD_RADIO_TX,
502 task_wdt_callback, (void *)k_current_get());
504 msg_arbiter &arb = msg_arbiter::get_instance();
505
506 while (1) {
507 try {
508 task_wdt_feed(task_wdt_id);
509 int ret = arb.pull(sband_msg_from_arb, msg_arbiter::subsys::RADIO_SBAND,
510 K_MSEC(1000));
511 if (ret) {
512 continue;
513 }
514 radio_ctrl.tx(scl::radio::interface::SBAND, sband_msg_from_arb,
515 arb.backpressure(msg_arbiter::subsys::RADIO_SBAND) > 0);
516 } catch (const scl::exception &e) {
517 auto &err = error_handler::get_instance();
518 err.handle(e);
519 } catch (const std::exception &e) {
520 auto &err = error_handler::get_instance();
521 err.handle(e);
522 }
523 }
524}
525
526void
527io::radio_rx_drop_callback(scl::radio::interface iface)
528{
529 switch (iface) {
531 m_radio.m_uhf.rx_frame_dropped();
532 return;
534 m_radio.m_sband.rx_frame_dropped();
535 return;
536 }
537}
538
539void
540io::update_radio_rx_stats(scl::radio::interface iface, bool valid, float rssi)
541{
542 switch (iface) {
544 m_radio.m_uhf.frame_received(valid, rssi);
545 return;
547 m_radio.m_sband.frame_received(valid, rssi);
548 return;
549 }
550}
551
552#if DT_NODE_HAS_STATUS(DT_ALIAS(pc104_usart3), okay)
553static void
554uart_handling_callback(const struct device *dev, struct uart_event *evt,
555 void *user_data)
556{
557 io::uart *uart = reinterpret_cast<io::uart *>(user_data);
558
559 switch (evt->type) {
560 case UART_TX_DONE:
561 break;
562 case UART_TX_ABORTED:
563 break;
564 case UART_RX_RDY: {
565 /* Ensure no overflow can happen */
566 size_t ncopy =
567 std::min<size_t>(CONFIG_MAX_MTU - uart->msg_idx, evt->data.rx.len);
568 std::copy_n(&evt->data.rx.buf[evt->data.rx.offset], ncopy,
569 &uart->msg.data[uart->msg_idx]);
570 uart->msg_idx += ncopy;
572 uart->msg.iface = msg_arbiter::subsys::UART_PC104;
573 uart->msg.len = uart->msg_idx;
574 arb.push(uart->msg);
575 uart->msg_idx = 0;
576 } break;
577 case UART_RX_BUF_RELEASED:
578 break;
579 case UART_RX_BUF_REQUEST:
580 uart->buf_idx = (uart->buf_idx + 1) % 2;
581 uart_rx_buf_rsp(dev, uart->buf[uart->buf_idx], io::uart::buf_len);
582 break;
583 case UART_RX_DISABLED:
584 break;
585 default:
586 break;
587 }
588}
589#endif
590
591} // namespace satnogs::comms
static void descrambler(uint8_t *data, size_t len)
Definition ccsds.cpp:76
static error_handler & get_instance()
Singleton access to the error_handler subsystem.
static constexpr size_t buf_len
Definition io.hpp:54
io(io const &)=delete
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
static board & get_instance()
Gets a reference to the single instance of the Board interface class.
Definition board.cpp:66
Exception base class.
Definition exception.hpp:63
void enable(subsys sys, bool en=true)
Enable/disable the power of subsystems.
Definition power.cpp:35
uint32_t len
The frame length.
Definition radio.hpp:278
The RX message accompanied by its metadata.
Definition radio.hpp:289
uint8_t pdu[AT86RF215_MAX_PDU]
Buffer to hold the received frame.
Definition radio.hpp:291
void register_rx_drop_callback(etl::delegate< void(interface)> callback)
Registers a callback for the RX drop message event.
Definition radio.cpp:1147
interface
Radio interface identifier.
Definition radio.hpp:177
uint8_t data[mtu]
Buffer to hold the data.
size_t len
Data size in bytes.
subsys iface
The interface from which the msg was received.
Incoming/Outgoing Message Arbiter.
int pull(msg_arbiter::msg &m, subsys s, k_timeout_t wait=K_MSEC(CONFIG_MSG_ARBITER_TIMEOUT_MS))
Pulls a message for a specific IO interface.
static constexpr size_t mtu
static msg_arbiter & get_instance()
Singleton access to a unique and global msg_arbiter instance.
uint8_t buf[chunk_bytes]
void task_wdt_callback(int channel_id, void *user_data)
Definition callbacks.cpp:37
K_THREAD_STACK_DEFINE(radio_rx_thread_stack, CONFIG_RADIO_RX_THREAD_STACK_SIZE)