6#include <etl/algorithm.h>
22 k_work_init(&m_work, &iface_ctrl::timer_work_handler);
23 k_timer_init(&m_timer, &iface_ctrl::timer_handler,
nullptr);
24 k_timer_user_data_set(&m_timer,
this);
26 k_condvar_init(&m_cond_var);
28 m_state_list[0] = &m_disabled_state;
29 m_state_list[1] = &m_tx_state;
30 m_state_list[2] = &m_rx_state;
31 m_state_list[3] = &m_idle_state;
33 set_states(m_state_list, 4);
64 receive(disable_msg());
113 wait_pending_operation();
116 receive(tx_frame_msg());
131iface_ctrl::wait_pending_operation()
135 k_condvar_wait(&m_cond_var, &m_mtx, K_FOREVER);
146iface_ctrl::frame_sent(
bool success)
149 if (m_stats.
tx_frames < std::numeric_limits<size_t>::max()) {
153 if (m_stats.tx_frames_fail < std::numeric_limits<size_t>::max()) {
154 m_stats.tx_frames_fail++;
164iface_ctrl::tx_frame_dropped()
166 if (m_stats.tx_frames_drop < std::numeric_limits<size_t>::max()) {
167 m_stats.tx_frames_drop++;
180iface_ctrl::duty_cycle_enabled()
185 : s.get<settings::param::SBAND_RX_ON_SECS>();
189 return on_secs > 0 && off_secs > 0;
201 m_stats.last_rssi = rssi;
202 m_stats.last_rx_ts = k_uptime_get();
206 if (m_stats.rx_frames < std::numeric_limits<size_t>::max()) {
209 m_stats.last_valid_rssi = rssi;
210 m_stats.last_valid_rx_ts = k_uptime_get();
212 if (m_stats.rx_frames_inval < std::numeric_limits<size_t>::max()) {
213 m_stats.rx_frames_inval++;
225 if (m_stats.rx_frames_drop < std::numeric_limits<size_t>::max()) {
226 m_stats.rx_frames_drop++;
231iface_ctrl::timer_handler(k_timer *t)
238 if (k_work_is_pending(&ctx->m_work)) {
241 k_work_submit(&ctx->m_work);
245iface_ctrl::timer_work_handler(k_work *item)
247 auto ctx = CONTAINER_OF(item,
iface_ctrl, m_work);
249 scoped_lock lock(&ctx->m_mtx);
250 while (ctx->m_pending) {
251 k_condvar_wait(&ctx->m_cond_var, &ctx->m_mtx, K_FOREVER);
256 ctx->receive(rx_msg());
260 ctx->receive(rx_msg());
262 ctx->receive(idle_msg());
273iface_ctrl::disabled_state::on_enter_state()
275 auto &ctx = get_fsm_context();
279 ?
"iface_ctrl<UHF>: disabled iface. enter disabled state"
280 :
"iface_ctrl<S-Band>: disabled iface. enter disabled state");
282 k_timer_stop(&ctx.m_timer);
284 return No_State_Change;
288iface_ctrl::disabled_state::on_event(
const rx_msg &msg)
294iface_ctrl::disabled_state::on_event(
const tx_frame_msg &msg)
297 auto &ctx = get_fsm_context();
300 ?
"iface_ctrl<UHF>: disabled iface. Dropping TX msg"
301 :
"iface_ctrl<S-Band>: disabled iface. Dropping TX msg");
302 ctx.tx_frame_dropped();
303 return No_State_Change;
307iface_ctrl::disabled_state::on_event_unknown(
const etl::imessage &msg)
309 auto &ctx = get_fsm_context();
313 ?
"iface_ctrl<UHF>: disabled state unknown msg"
314 :
"iface_ctrl<S-Band>: disabled state unknown msg");
315 return No_State_Change;
325iface_ctrl::tx_state::on_enter_state()
327 auto &ctx = get_fsm_context();
330 scoped_lock lock(&ctx.m_mtx);
331 ctx.m_pending =
true;
334 ?
"iface_ctrl<UHF>: enter TX state"
335 :
"iface_ctrl<S-Band>: enter TX state");
354 lib::radio::tx_conf cnf;
355 s.get_tx_conf(ctx.m_iface, cnf);
359 auto crc = etl::crc32_c(ctx.m_tx_msg.
data, ctx.m_tx_msg.
data +
371 ctx.frame_sent(
true);
380 : s.get<settings::param::SBAND_TX_WAIT_MS>();
381 k_timer_start(&ctx.m_timer, K_MSEC(wait_ms), K_NO_WAIT);
383 ctx.m_pending =
false;
384 k_condvar_broadcast(&ctx.m_cond_var);
385 return No_State_Change;
387 ctx.m_pending =
false;
388 k_condvar_broadcast(&ctx.m_cond_var);
391 }
catch (
const scl::exception &e) {
392 ctx.frame_sent(
false);
395 ?
"iface_ctrl<UHF>: Exception occurred"
396 :
"iface_ctrl<S-Band>: Exception occurred");
399 ctx.m_pending =
false;
400 k_condvar_broadcast(&ctx.m_cond_var);
406iface_ctrl::tx_state::on_exit_state()
408 auto &ctx = get_fsm_context();
409 k_timer_stop(&ctx.m_timer);
410 ctx.wait_pending_operation();
414iface_ctrl::tx_state::on_event(
const disable_msg &msg)
416 auto &ctx = get_fsm_context();
421 k_timer_stop(&ctx.m_timer);
423 ctx.wait_pending_operation();
428iface_ctrl::tx_state::on_event(
const tx_frame_msg &msg)
430 auto &ctx = get_fsm_context();
435 k_timer_stop(&ctx.m_timer);
437 scoped_lock lock(&ctx.m_mtx);
438 ctx.m_pending =
true;
442 auto crc = etl::crc32_c(ctx.m_tx_msg.
data, ctx.m_tx_msg.
data +
454 ctx.frame_sent(
true);
463 : s.get<settings::param::SBAND_TX_WAIT_MS>();
465 k_timer_start(&ctx.m_timer, K_MSEC(wait_ms), K_NO_WAIT);
467 ctx.m_pending =
false;
468 k_condvar_broadcast(&ctx.m_cond_var);
469 return No_State_Change;
471 k_timer_stop(&ctx.m_timer);
472 ctx.m_pending =
false;
473 k_condvar_broadcast(&ctx.m_cond_var);
478 catch (
const scl::timeout_exception &e) {
479 ctx.frame_sent(
false);
483 ?
"iface_ctrl<UHF>: Exception occurred"
484 :
"iface_ctrl<S-Band>: Exception occurred");
486 ctx.m_pending =
false;
487 k_condvar_broadcast(&ctx.m_cond_var);
489 }
catch (
const scl::exception &e) {
490 ctx.frame_sent(
false);
494 ?
"iface_ctrl<UHF>: Exception occurred"
495 :
"iface_ctrl<S-Band>: Exception occurred");
497 ctx.m_pending =
false;
498 k_condvar_broadcast(&ctx.m_cond_var);
504iface_ctrl::tx_state::on_event(
const rx_msg &msg)
506 auto &ctx = get_fsm_context();
511 k_timer_stop(&ctx.m_timer);
513 ctx.wait_pending_operation();
518iface_ctrl::tx_state::on_event_unknown(
const etl::imessage &msg)
520 auto &ctx = get_fsm_context();
524 ?
"iface_ctrl<UHF>:TX state unknown msg"
525 :
"iface_ctrl<S-Band>: TX state unknown msg");
526 return No_State_Change;
536iface_ctrl::rx_state::on_enter_state()
538 auto &ctx = get_fsm_context();
542 k_timer_stop(&ctx.m_timer);
546 ?
"iface_ctrl<UHF>: enter RX state"
547 :
"iface_ctrl<S-Band>: enter RX state");
566 lib::radio::rx_conf cnf;
567 s.get_rx_conf(ctx.m_iface, cnf);
576 if (ctx.duty_cycle_enabled()) {
579 : s.get<settings::param::SBAND_RX_ON_SECS>();
580 k_timer_start(&ctx.m_timer, K_SECONDS(on_secs), K_NO_WAIT);
583 return No_State_Change;
588 }
catch (
const scl::exception &e) {
592 ?
"iface_ctrl<UHF>: Exception occurred"
593 :
"iface_ctrl<S-Band>: Exception occurred");
600iface_ctrl::rx_state::on_event(
const disable_msg &msg)
602 auto &ctx = get_fsm_context();
607 k_timer_stop(&ctx.m_timer);
609 ctx.wait_pending_operation();
614iface_ctrl::rx_state::on_event(
const tx_frame_msg &msg)
616 auto &ctx = get_fsm_context();
620 k_timer_stop(&ctx.m_timer);
629 : s.get<settings::param::SBAND_TRX_TURNAROUND_MS>();
630 int64_t now = k_uptime_get();
631 if (now - ctx.m_stats.
last_rx_ts < trx_time) {
632 k_msleep(etl::clamp<uint64_t>(trx_time - (now - ctx.m_stats.
last_rx_ts),
636 }
catch (
const scl::exception &e) {
639 ?
"iface_ctrl<UHF>: Exception occurred"
640 :
"iface_ctrl<S-Band>: Exception occurred");
648iface_ctrl::rx_state::on_event(
const idle_msg &msg)
650 auto &ctx = get_fsm_context();
651 k_timer_stop(&ctx.m_timer);
653 ctx.wait_pending_operation();
658iface_ctrl::rx_state::on_event(
const frame_received_msg &msg)
660 auto &ctx = get_fsm_context();
663 if (ctx.duty_cycle_enabled()) {
666 : s.get<settings::param::SBAND_RX_ON_SECS>();
667 k_timer_start(&ctx.m_timer, K_SECONDS(on_secs), K_NO_WAIT);
669 return No_State_Change;
673iface_ctrl::rx_state::on_event_unknown(
const etl::imessage &msg)
675 auto &ctx = get_fsm_context();
679 ?
"iface_ctrl<UHF>: RX state unknown msg"
680 :
"iface_ctrl<S-Band>: RX state unknown msg");
681 return No_State_Change;
691iface_ctrl::idle_state::on_enter_state()
693 auto &ctx = get_fsm_context();
696 k_timer_stop(&ctx.m_timer);
701 ?
"iface_ctrl<UHF>: enter IDLE state"
702 :
"iface_ctrl<S-Band>: enter IDLE state");
714 : s.get<settings::param::SBAND_RX_OFF_SECS>();
715 k_timer_start(&ctx.m_timer, K_SECONDS(std::max(1U, off_secs)), K_NO_WAIT);
721 }
catch (
const scl::exception &e) {
724 ?
"iface_ctrl<UHF>: Exception occurred"
725 :
"iface_ctrl<S-Band>: Exception occurred");
731 : s.get<settings::param::SBAND_RX_OFF_SECS>();
732 k_timer_start(&ctx.m_timer, K_SECONDS(std::max(1U, off_secs)), K_NO_WAIT);
734 return No_State_Change;
738iface_ctrl::idle_state::on_exit_state()
741 auto &ctx = get_fsm_context();
742 k_timer_stop(&ctx.m_timer);
746iface_ctrl::idle_state::on_event(
const disable_msg &msg)
748 auto &ctx = get_fsm_context();
753 k_timer_stop(&ctx.m_timer);
755 ctx.wait_pending_operation();
760iface_ctrl::idle_state::on_event(
const tx_frame_msg &msg)
767iface_ctrl::idle_state::on_event(
const rx_msg &msg)
773iface_ctrl::idle_state::on_event_unknown(
const etl::imessage &msg)
775 auto &ctx = get_fsm_context();
779 ?
"iface_ctrl<UHF>: RX state unknown msg"
780 :
"iface_ctrl<S-Band>: RX state unknown msg");
781 return No_State_Change;
static void scrambler(uint8_t *data, size_t len)
static error_handler & get_instance()
Singleton access to the error_handler subsystem.
static io_wdg & get_instance()
Singleton access to the io_wdg subsystem.
void reset()
Resets the watchdog timer.
comms::lib::radio & radio()
Returns a reference to the radio subsystem.
static board & get_instance()
Gets a reference to the single instance of the Board interface class.
void rx_async(interface iface, const rx_conf &conf)
Sets the radio in reception mode asynchronously.
void tx(interface iface, const uint8_t *b)
Performs a TX in blocking mode.
interface
Radio interface identifier.
void set_tx_conf(interface iface, const tx_conf &conf)
Performs the configuration of a specific interface for TX.
void stop(interface iface, size_t timeout_ms=1000)
Sets the FSM of the AT86RF215 interface to TRXOFF.
void enable(bool yes=true)
Enable/disable the radio chain.
uint32_t tx_len(interface iface) const
Retrieves the configured TX frame size for a specific interface.
bool enabled() const
Checks if the radio transceiver is in an operational state. This means that their powesr sources are ...
@ RTT
Real-Time Transfer logging (Segger RTT).
static logger & get_instance()
Singleton access to the logger subsystem.
uint8_t data[mtu]
Buffer to hold the data.
Implements a scoped lock utilizing the Zephyr mutex.
static settings & get_instance()
Get a singleton access to the settings subsystem.
Radio interface statistics.
uint64_t last_rx_ts
The timestamp of the RX frame.
size_t tx_frames
TX frames successfully sent.
void restart()
Restarts the interface by disabling and enabling it again.
void frame_received(bool valid, float rssi)
Updates the RX stats.
const stats & get_stats() const
Returns the statistics class of the interface.
void reset_stats()
Resets the TX/RX statistics of the interface.
void rx_frame_dropped()
Increments the RX drop counter.
@ DISABLED
Interface is disabled.
@ TX
Interface is either TX a frame or wait to TX the next frame.
@ RX
Interface is in RX mode.
void tx(const msg_arbiter::msg &msg, bool more=false)
void enable()
Enables the interface and set it automatically to RX state.
static constexpr uint32_t MAX_TRX_MS
iface_ctrl(satnogs::comms::lib::radio::interface iface)
void disable()
Disables the interface.
iface_ctrl::state get_state() const
Returns the current state of the interface.