HERMES Modem
Hermes ARQ/Broadcast modem
Loading...
Searching...
No Matches
Macros | Functions | Variables
arq_fsm.c File Reference
#include "arq_fsm.h"
#include "arq_protocol.h"
#include "arq_timing.h"
#include "arq.h"
#include <limits.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include "../common/hermes_log.h"
#include "../modem/framer.h"
#include "../modem/freedv/freedv_api.h"
Include dependency graph for arq_fsm.c:

Macros

#define LOG_COMP   "arq-fsm"
 
#define INT_BUFFER_SIZE   4096
 

Functions

const char * arq_conn_state_name (arq_conn_state_t s)
 Human-readable name for a connection state (for log output).
 
const char * arq_dflow_state_name (arq_dflow_state_t s)
 Human-readable name for a data-flow state (for log output).
 
const char * arq_event_name (arq_event_id_t ev)
 Human-readable name for an event (for log output).
 
void arq_fsm_set_callbacks (const arq_fsm_callbacks_t *cbs)
 Register FSM action callbacks (call once before first dispatch).
 
void arq_fsm_set_timing (arq_timing_ctx_t *timing)
 Register timing context for recording (call once at init).
 
void arq_fsm_init (arq_session_t *sess)
 Initialise a session structure to DISCONNECTED state.
 
int arq_fsm_timeout_ms (const arq_session_t *sess, uint64_t now)
 Return milliseconds until the next deadline, or INT_MAX if idle.
 
static void sess_enter (arq_session_t *sess, arq_conn_state_t new_state, uint64_t deadline_ms, arq_event_id_t deadline_event)
 
static void dflow_enter (arq_session_t *sess, arq_dflow_state_t new_state, uint64_t deadline_ms, arq_event_id_t deadline_event)
 
static void send_frame (int ptype, int mode, size_t len, const uint8_t *frame)
 
static uint64_t deadline_from_s (float seconds)
 
static void update_local_snr (arq_session_t *sess, const arq_event_t *ev)
 Update local_snr_x10 EMA from the SNR carried in a received frame event.
 
static void update_peer_snr (arq_session_t *sess, const arq_event_t *ev)
 Update peer_snr_x10 from the sender's SNR feedback carried in a received frame.
 
static void send_mode_negotiation (arq_session_t *sess, arq_subtype_t subtype, int mode)
 Build and send a MODE_REQ or MODE_ACK control frame.
 
static int mode_rank (int mode)
 Map a FreeDV payload mode to a comparable rank: higher rank = faster/more aggressive mode.
 
static void record_tx_outcome (arq_session_t *sess, bool clean)
 Record the outcome of a TX frame.
 
static int select_best_mode (const arq_session_t *sess, int backlog)
 Compute desired payload mode based on peer_snr_x10 and TX backlog.
 
static bool maybe_upgrade_mode (arq_session_t *sess)
 Check whether a mode upgrade/downgrade is warranted.
 
static bool deliver_rx_checked (arq_session_t *sess, const arq_event_t *ev)
 Deliver RX payload to the application only if the sequence number matches what we expect.
 
static void send_call_accept (arq_session_t *sess, bool is_accept)
 
static void send_ctrl_frame (arq_session_t *sess, arq_subtype_t subtype)
 
static void send_ack (arq_session_t *sess, uint8_t ack_delay_raw)
 
static void send_data_frame (arq_session_t *sess)
 
static void fsm_dflow (arq_session_t *sess, const arq_event_t *ev)
 
static void enter_idle_iss (arq_session_t *sess, bool gained_turn)
 
static void enter_idle_iss_guarded (arq_session_t *sess, bool gained_turn)
 
static void enter_idle_irs (arq_session_t *sess)
 
static void fsm_disconnected (arq_session_t *sess, const arq_event_t *ev)
 
static void fsm_listening (arq_session_t *sess, const arq_event_t *ev)
 
static void fsm_calling (arq_session_t *sess, const arq_event_t *ev)
 
static void fsm_accepting (arq_session_t *sess, const arq_event_t *ev)
 
static void fsm_disconnecting (arq_session_t *sess, const arq_event_t *ev)
 
static void fsm_connected (arq_session_t *sess, const arq_event_t *ev)
 
void arq_fsm_dispatch (arq_session_t *sess, const arq_event_t *ev)
 Dispatch an event through both FSM levels.
 

Variables

static arq_fsm_callbacks_t g_cbs
 
static arq_timing_ctx_tg_timing
 

Macro Definition Documentation

◆ INT_BUFFER_SIZE

#define INT_BUFFER_SIZE   4096

◆ LOG_COMP

#define LOG_COMP   "arq-fsm"

Function Documentation

◆ arq_conn_state_name()

const char * arq_conn_state_name ( arq_conn_state_t  s)

Human-readable name for a connection state (for log output).

◆ arq_dflow_state_name()

const char * arq_dflow_state_name ( arq_dflow_state_t  s)

Human-readable name for a data-flow state (for log output).

◆ arq_event_name()

const char * arq_event_name ( arq_event_id_t  ev)

Human-readable name for an event (for log output).

◆ arq_fsm_dispatch()

void arq_fsm_dispatch ( arq_session_t sess,
const arq_event_t event 
)

Dispatch an event through both FSM levels.

Runs transition logic, calls action callbacks, and updates deadlines. Must be called from the single ARQ event-loop thread (no locking inside).

Parameters
sessActive session.
eventEvent to process.

◆ arq_fsm_init()

void arq_fsm_init ( arq_session_t sess)

Initialise a session structure to DISCONNECTED state.

Parameters
sessSession to initialise.

◆ arq_fsm_set_callbacks()

void arq_fsm_set_callbacks ( const arq_fsm_callbacks_t cbs)

Register FSM action callbacks (call once before first dispatch).

◆ arq_fsm_set_timing()

void arq_fsm_set_timing ( arq_timing_ctx_t timing)

Register timing context for recording (call once at init).

Parameters
timingPointer to the arq_timing_ctx_t to record into.

◆ arq_fsm_timeout_ms()

int arq_fsm_timeout_ms ( const arq_session_t sess,
uint64_t  now 
)

Return milliseconds until the next deadline, or INT_MAX if idle.

Used by the event loop's blocking wait to set a poll timeout.

Parameters
sessActive session.
nowCurrent monotonic time in milliseconds.
Returns
Milliseconds to wait (0 = fire immediately, INT_MAX = no deadline).

◆ deadline_from_s()

static uint64_t deadline_from_s ( float  seconds)
static

◆ deliver_rx_checked()

static bool deliver_rx_checked ( arq_session_t sess,
const arq_event_t ev 
)
static

Deliver RX payload to the application only if the sequence number matches what we expect.

Returns true if data was delivered (new frame), false if it was a duplicate that was silently dropped.

◆ dflow_enter()

static void dflow_enter ( arq_session_t sess,
arq_dflow_state_t  new_state,
uint64_t  deadline_ms,
arq_event_id_t  deadline_event 
)
static

◆ enter_idle_irs()

static void enter_idle_irs ( arq_session_t sess)
static

◆ enter_idle_iss()

static void enter_idle_iss ( arq_session_t sess,
bool  gained_turn 
)
static

◆ enter_idle_iss_guarded()

static void enter_idle_iss_guarded ( arq_session_t sess,
bool  gained_turn 
)
static

◆ fsm_accepting()

static void fsm_accepting ( arq_session_t sess,
const arq_event_t ev 
)
static

◆ fsm_calling()

static void fsm_calling ( arq_session_t sess,
const arq_event_t ev 
)
static

◆ fsm_connected()

static void fsm_connected ( arq_session_t sess,
const arq_event_t ev 
)
static

◆ fsm_dflow()

static void fsm_dflow ( arq_session_t sess,
const arq_event_t ev 
)
static

◆ fsm_disconnected()

static void fsm_disconnected ( arq_session_t sess,
const arq_event_t ev 
)
static

◆ fsm_disconnecting()

static void fsm_disconnecting ( arq_session_t sess,
const arq_event_t ev 
)
static

◆ fsm_listening()

static void fsm_listening ( arq_session_t sess,
const arq_event_t ev 
)
static

◆ maybe_upgrade_mode()

static bool maybe_upgrade_mode ( arq_session_t sess)
static

Check whether a mode upgrade/downgrade is warranted.

If yes, send MODE_REQ and enter MODE_REQ_TX. Returns true when negotiation started.

◆ mode_rank()

static int mode_rank ( int  mode)
static

Map a FreeDV payload mode to a comparable rank: higher rank = faster/more aggressive mode.

DATAC1 (=10) is fastest, DATAC3 (=12) is medium, and DATAC4 (=18) is slowest — the numeric constants decrease as throughput increases, so direct integer comparisons between them are misleading.

◆ record_tx_outcome()

static void record_tx_outcome ( arq_session_t sess,
bool  clean 
)
static

Record the outcome of a TX frame.

Called once per frame when its fate is known: clean=true when ACK arrived with no retries consumed, clean=false when the frame was retransmitted at least once. Steps speed_level ladder up (slowly, after consecutive clean ACKs) or down (immediately on any non-clean outcome).

◆ select_best_mode()

static int select_best_mode ( const arq_session_t sess,
int  backlog 
)
static

Compute desired payload mode based on peer_snr_x10 and TX backlog.

Returns current payload_mode if no change is warranted.

Hybrid SNR + delivery-feedback mode selection. Upgrades require SNR above the mode threshold plus a hysteresis margin. Downgrades happen when SNR drops below the current mode's base threshold, OR when consecutive retries indicate the channel can't support the current mode (catches deep fades where SNR is stale). After a retry-forced downgrade, a hold timer prevents re-upgrade oscillation.

◆ send_ack()

static void send_ack ( arq_session_t sess,
uint8_t  ack_delay_raw 
)
static

◆ send_call_accept()

static void send_call_accept ( arq_session_t sess,
bool  is_accept 
)
static

◆ send_ctrl_frame()

static void send_ctrl_frame ( arq_session_t sess,
arq_subtype_t  subtype 
)
static

◆ send_data_frame()

static void send_data_frame ( arq_session_t sess)
static

◆ send_frame()

static void send_frame ( int  ptype,
int  mode,
size_t  len,
const uint8_t *  frame 
)
static

◆ send_mode_negotiation()

static void send_mode_negotiation ( arq_session_t sess,
arq_subtype_t  subtype,
int  mode 
)
static

Build and send a MODE_REQ or MODE_ACK control frame.

◆ sess_enter()

static void sess_enter ( arq_session_t sess,
arq_conn_state_t  new_state,
uint64_t  deadline_ms,
arq_event_id_t  deadline_event 
)
static

◆ update_local_snr()

static void update_local_snr ( arq_session_t sess,
const arq_event_t ev 
)
static

Update local_snr_x10 EMA from the SNR carried in a received frame event.

Called in all RX_DATA handlers to avoid cross-thread race with the modem thread's arq_update_link_metrics() call.

◆ update_peer_snr()

static void update_peer_snr ( arq_session_t sess,
const arq_event_t ev 
)
static

Update peer_snr_x10 from the sender's SNR feedback carried in a received frame.

The DATA frame's snr_encoded = sender's local_snr_x10 = what the sender (current ISS) receives from us (current IRS).

Variable Documentation

◆ g_cbs

arq_fsm_callbacks_t g_cbs
static

◆ g_timing

arq_timing_ctx_t* g_timing
static