Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
esphome::home_io_control::RadioDriver Class Referenceabstract

Abstract radio driver for IO-Homecontrol. More...

#include <radio_interface.h>

Inheritance diagram for esphome::home_io_control::RadioDriver:
Collaboration diagram for esphome::home_io_control::RadioDriver:

Public Member Functions

 RadioDriver (InternalGPIOPin *rst_pin=nullptr)
virtual ~RadioDriver ()=default
virtual bool init ()=0
 Initialize the radio hardware. Returns true on success.
virtual bool send_packet (const uint8_t *data, uint8_t len, const RadioTxConfig &tx_config)=0
 Send a packet using the specified carrier frequency and preamble settings.
virtual bool wait_for_packet (RadioRxPacket &packet, uint32_t timeout_ms)=0
 Wait (blocking) for a packet with timeout.
virtual bool check_for_packet (RadioRxPacket &packet)=0
 Non-blocking check for a received packet.
virtual int16_t read_rssi ()=0
 Read instantaneous RSSI (in dBm) while in RX mode.
virtual bool is_sync_detected ()=0
 Check if sync word has been detected (while in RX).
virtual bool is_preamble_detected ()=0
 Check if preamble has been detected (while in RX).
virtual uint16_t response_preamble () const
 Return the preamble length for response/continuation frames.
virtual uint16_t default_start_preamble () const
 Default preamble for a directed start frame, when the user has not set normal_start_preamble in YAML.
virtual void apply_tuning (const TuningConfig &tuning)
 Apply runtime tuning parameters to the driver.
virtual uint16_t hop_dwell_ms (const TuningConfig &tuning) const =0
 Per-channel dwell for a rotating listen that does not name its own dwell.
virtual bool has_fast_tx_rx_turnaround () const =0
 Whether the chip re-enters RX fast enough after a TX to catch an immediate reply through the standard exchange wait.
virtual void change_frequency (uint32_t freq_hz)=0
 Change the carrier frequency using fast hop (no standby transition needed).
virtual void set_mode_rx ()=0
 Switch to continuous receive mode.
virtual void set_mode_standby ()=0
 Switch to standby mode.
virtual bool is_failed () const
 Returns true if the radio failed to initialize or encountered a fatal error.
virtual const char * chip_name () const =0
 Get a human‑readable chip name.
const char * failure_reason () const
 Short, human-readable reason the driver latched is_failed, or nullptr if it has not.
virtual void dump_front_end ()
 Optional board front-end-module (external PA/LNA) summary emitted from dump_config, as its own section ahead of dump_debug().
virtual void dump_debug ()
 Optional chip-specific diagnostics emitted from dump_config.
uint32_t get_current_freq () const
 Get the current RF frequency.
const RadioCaptureInfo & get_last_capture () const
 Get the most recent radio capture info.
void clear_last_capture ()
 Reset the diagnostic capture buffer.
virtual bool reception_in_progress ()
 True while a frame is arriving on the current channel and retuning would destroy it.
bool is_dio_fired () const
 Set by the ISR when DIO fires.
void clear_dio_fired ()
void mark_dio_fired_from_isr ()

Protected Member Functions

void prepare_blocking_receive_ (RadioRxPacket &packet)
 Common preamble for blocking receive: clear diagnostics and output packet.
void prepare_nonblocking_receive_ (RadioRxPacket &packet)
 Common preamble for non‑blocking receive: clear diagnostics, output packet, and DIO latch.
void note_reception_in_progress_ ()
 Record that a frame is arriving right now.
void clear_reception_in_progress_ ()
 Drop the holdoff: the reception ended, was delivered, or was torn down deliberately.
void reset_hardware_ ()
 Shared hardware reset sequence for chips with an active-low RST pin.
void populate_capture_base_ (bool blocking_wait, uint32_t freq_hz, int16_t rssi_dbm, const uint8_t *raw, uint8_t raw_len, const uint8_t *frame, uint8_t frame_len)
 Populate the common fields of RadioCaptureInfo from raw telemetry.
void fail_ (const char *reason)
 Latch the failed state and record why, so is_failed and failure_reason can never disagree.

Protected Attributes

uint32_t current_freq_ {FREQ_CH2}
RadioCaptureInfo last_capture_ {}
InternalGPIOPin * rst_pin_ {nullptr}
bool failed_ {false}
 Latched by fail_; see is_failed.
const char * failure_reason_ {nullptr}
 First failure cause, see failure_reason.
bool rx_hold_armed_ {false}
 Idle-hop holdoff latch — see reception_in_progress().
uint32_t rx_hold_since_us_ {0}
 micros() timestamp the holdoff was last (re-)armed at.
volatile bool dio_fired_ {false}

Detailed Description

Abstract radio driver for IO-Homecontrol.

Encapsulates all chip-specific operations: initialization, packet TX/RX, frequency control, and mode switching. Concrete implementations (RadioSX1276, RadioSX1262, RadioLR1121) handle the register-level details for each chip.

Definition at line 156 of file radio_interface.h.

Constructor & Destructor Documentation

◆ RadioDriver()

esphome::home_io_control::RadioDriver::RadioDriver ( InternalGPIOPin * rst_pin = nullptr)
inlineexplicit

Definition at line 158 of file radio_interface.h.

◆ ~RadioDriver()

virtual esphome::home_io_control::RadioDriver::~RadioDriver ( )
virtualdefault

Member Function Documentation

◆ apply_tuning()

virtual void esphome::home_io_control::RadioDriver::apply_tuning ( const TuningConfig & tuning)
inlinevirtual

Apply runtime tuning parameters to the driver.

Each driver consumes only the fields it understands; the default is a no-op for chips with no runtime-tunable radio parameters. This keeps the hub free of chip-specific tuning knowledge — it hands over the whole config and lets the driver pick what it needs.

Parameters
tuningCurrent tuning configuration.

Reimplemented in esphome::home_io_control::RadioLR1121, esphome::home_io_control::RadioSX1262, and esphome::home_io_control::RadioSX1276.

Definition at line 236 of file radio_interface.h.

◆ change_frequency()

virtual void esphome::home_io_control::RadioDriver::change_frequency ( uint32_t freq_hz)
pure virtual

Change the carrier frequency using fast hop (no standby transition needed).

Implemented in esphome::home_io_control::RadioSX1276, and esphome::home_io_control::SoftPhyDriverBase.

◆ check_for_packet()

virtual bool esphome::home_io_control::RadioDriver::check_for_packet ( RadioRxPacket & packet)
pure virtual

Non-blocking check for a received packet.

Called from loop(). Returns true if a packet was read into packet. Contract:

  • Returns false immediately if no DIO interrupt has fired.
  • On success: populates packet and last_capture_, returns true.
  • On failure: may populate last_capture_ for diagnostics, returns false.

Implemented in esphome::home_io_control::RadioSX1276, and esphome::home_io_control::SoftPhyDriverBase.

◆ chip_name()

virtual const char * esphome::home_io_control::RadioDriver::chip_name ( ) const
nodiscardpure virtual

Get a human‑readable chip name.

Returns
Short lowercase identifier (e.g. "sx1276").

Implemented in esphome::home_io_control::RadioLR1121, esphome::home_io_control::RadioSX1262, and esphome::home_io_control::RadioSX1276.

◆ clear_dio_fired()

void esphome::home_io_control::RadioDriver::clear_dio_fired ( )
inline

Definition at line 348 of file radio_interface.h.

◆ clear_last_capture()

void esphome::home_io_control::RadioDriver::clear_last_capture ( )
inline

Reset the diagnostic capture buffer.

Public because ExchangeEngine blanks it at the start of every exchange: the radio only clears this buffer when it actually begins a listen, so without an explicit reset a fully-silent exchange's failure report would inherit the previous exchange's capture (frame length, RSSI, IRQ bits) and claim "we heard something" when nothing was on air.

Definition at line 311 of file radio_interface.h.

◆ clear_reception_in_progress_()

void esphome::home_io_control::RadioDriver::clear_reception_in_progress_ ( )
inlineprotected

Drop the holdoff: the reception ended, was delivered, or was torn down deliberately.

Definition at line 390 of file radio_interface.h.

◆ default_start_preamble()

virtual uint16_t esphome::home_io_control::RadioDriver::default_start_preamble ( ) const
inlinenodiscardvirtual

Default preamble for a directed start frame, when the user has not set normal_start_preamble in YAML.

A start frame has to be found by a peer that is not yet listening to us, so it needs enough preamble for that peer to lock. How much is enough is not purely a protocol question: it also depends on what the driver's transmit path actually puts on air, which is why this is a driver property rather than one constant. Drivers whose emitted preamble gives the peer less usable synchronization than its programmed length suggests override this with a longer value (see the override for the measurement behind it).

The default is the protocol's documented preamble, 256 bits. An explicit normal_start_preamble: always wins over this — including a shorter value, so a reporter can still bisect downward in the field (ADR 0029).

Returns
Preamble length in bytes.

Reimplemented in esphome::home_io_control::SoftPhyDriverBase.

Definition at line 227 of file radio_interface.h.

◆ dump_debug()

virtual void esphome::home_io_control::RadioDriver::dump_debug ( )
inlinevirtual

Optional chip-specific diagnostics emitted from dump_config.

Reimplemented in esphome::home_io_control::RadioLR1121, esphome::home_io_control::RadioSX1262, and esphome::home_io_control::RadioSX1276.

Definition at line 296 of file radio_interface.h.

◆ dump_front_end()

virtual void esphome::home_io_control::RadioDriver::dump_front_end ( )
inlinevirtual

Optional board front-end-module (external PA/LNA) summary emitted from dump_config, as its own section ahead of dump_debug().

The front end belongs to the board rather than to the radio chip, so it gets its own section instead of sharing the chip's diagnostic block.

Reimplemented in esphome::home_io_control::RadioSX1262.

Definition at line 293 of file radio_interface.h.

◆ fail_()

void esphome::home_io_control::RadioDriver::fail_ ( const char * reason)
inlineprotected

Latch the failed state and record why, so is_failed and failure_reason can never disagree.

Only the first reason sticks; see failure_reason.

Parameters
reasonString literal (stored by pointer, not copied).

Definition at line 427 of file radio_interface.h.

◆ failure_reason()

const char * esphome::home_io_control::RadioDriver::failure_reason ( ) const
inlinenodiscard

Short, human-readable reason the driver latched is_failed, or nullptr if it has not.

The first recorded reason wins, so it names the root cause rather than a later cascade (a dead chip makes every later transaction fail too). Always a string literal: it outlives the driver, which the hub deletes when init() fails. The hub prints it from dump_config, so it reaches log clients that connect after boot and never saw the driver's own ESP_LOGE at the failure site.

Definition at line 288 of file radio_interface.h.

◆ get_current_freq()

uint32_t esphome::home_io_control::RadioDriver::get_current_freq ( ) const
inlinenodiscard

Get the current RF frequency.

Returns
Frequency in Hz.

Definition at line 300 of file radio_interface.h.

◆ get_last_capture()

const RadioCaptureInfo & esphome::home_io_control::RadioDriver::get_last_capture ( ) const
inlinenodiscard

Get the most recent radio capture info.

Returns
const reference to RadioCaptureInfo.

Definition at line 303 of file radio_interface.h.

◆ has_fast_tx_rx_turnaround()

virtual bool esphome::home_io_control::RadioDriver::has_fast_tx_rx_turnaround ( ) const
nodiscardpure virtual

Whether the chip re-enters RX fast enough after a TX to catch an immediate reply through the standard exchange wait.

Some chips need a standby/settle cycle between TX and RX, so a device's immediate response (e.g. the pairing key-confirm 0x33) can arrive while the receiver is still settling and be lost. Callers choose between the standard exchange wait and a dedicated wait-and-retrigger strategy based on this. There is no safe generic default — each driver must declare it.

Returns
true if an immediate reply after TX is reliably received.

Implemented in esphome::home_io_control::RadioLR1121, esphome::home_io_control::RadioSX1262, and esphome::home_io_control::RadioSX1276.

◆ hop_dwell_ms()

virtual uint16_t esphome::home_io_control::RadioDriver::hop_dwell_ms ( const TuningConfig & tuning) const
nodiscardpure virtual

Per-channel dwell for a rotating listen that does not name its own dwell.

Every ListenPolicy::ROTATE_ALL_CHANNELS or ListenPolicy::ROTATE_SKIPPING_REQUEST listen falls back to this when ListenSpec::dwell_ms is left at 0 — which is every call site today: pairing discovery and the broadcast roll-call both rotate, and neither has a measured reason to dwell differently from the other. The right dwell is inherently chip-specific — it depends on how fast the chip can retune (fast hop vs. a standby→retune→RX cycle) — so there is no generic default: each driver must return its value, normally from its user-facing tuning field. This answers a chip question ("how long must this radio sit on a channel before it can hear anything at all"), never a protocol one — a loop with a measured reason to dwell differently sets ListenSpec::dwell_ms instead of asking for a second driver virtual.

Parameters
tuningCurrent tuning configuration.
Returns
Dwell length in milliseconds.

Implemented in esphome::home_io_control::RadioLR1121, esphome::home_io_control::RadioSX1262, and esphome::home_io_control::RadioSX1276.

◆ init()

virtual bool esphome::home_io_control::RadioDriver::init ( )
pure virtual

Initialize the radio hardware. Returns true on success.

Implemented in esphome::home_io_control::RadioLR1121, esphome::home_io_control::RadioSX1262, and esphome::home_io_control::RadioSX1276.

◆ is_dio_fired()

bool esphome::home_io_control::RadioDriver::is_dio_fired ( ) const
inlinenodiscard

Set by the ISR when DIO fires.

Using access helpers instead of touching the flag directly keeps the ISR/main-loop handoff explicit and lets ESP32 builds use atomic storage.

Definition at line 340 of file radio_interface.h.

◆ is_failed()

virtual bool esphome::home_io_control::RadioDriver::is_failed ( ) const
inlinenodiscardvirtual

Returns true if the radio failed to initialize or encountered a fatal error.

Returns
true once a driver has latched a failure with fail_; the state is sticky.

Definition at line 276 of file radio_interface.h.

◆ is_preamble_detected()

virtual bool esphome::home_io_control::RadioDriver::is_preamble_detected ( )
pure virtual

Check if preamble has been detected (while in RX).

Used together with sync detection to gate frequency hopping.

Implemented in esphome::home_io_control::RadioSX1276, and esphome::home_io_control::SoftPhyDriverBase.

◆ is_sync_detected()

virtual bool esphome::home_io_control::RadioDriver::is_sync_detected ( )
pure virtual

Check if sync word has been detected (while in RX).

Used to gate frequency hopping — prevents hopping away mid-frame.

Implemented in esphome::home_io_control::RadioSX1276, and esphome::home_io_control::SoftPhyDriverBase.

◆ mark_dio_fired_from_isr()

void esphome::home_io_control::RadioDriver::mark_dio_fired_from_isr ( )
inline

Definition at line 358 of file radio_interface.h.

◆ note_reception_in_progress_()

void esphome::home_io_control::RadioDriver::note_reception_in_progress_ ( )
inlineprotected

Record that a frame is arriving right now.

Re-arming refreshes the deadline, so a driver may call this on every poll that still sees the reception.

Definition at line 385 of file radio_interface.h.

◆ populate_capture_base_()

void esphome::home_io_control::RadioDriver::populate_capture_base_ ( bool blocking_wait,
uint32_t freq_hz,
int16_t rssi_dbm,
const uint8_t * raw,
uint8_t raw_len,
const uint8_t * frame,
uint8_t frame_len )
inlineprotected

Populate the common fields of RadioCaptureInfo from raw telemetry.

Chip‑specific fields (rx_done, crc_error, irq_flags*, irq_status, packet_status, etc.) must be set by the derived driver after calling this helper.

Parameters
blocking_waitif this was a blocking receive.
freq_hzRF frequency of the capture.
rssi_dbmReceived signal strength.
rawPointer to raw bytes (may be nullptr).
raw_lenLength of raw buffer.
framePointer to parsed frame bytes (may be nullptr).
frame_lenLength of parsed frame.

Definition at line 406 of file radio_interface.h.

◆ prepare_blocking_receive_()

void esphome::home_io_control::RadioDriver::prepare_blocking_receive_ ( RadioRxPacket & packet)
inlineprotected

Common preamble for blocking receive: clear diagnostics and output packet.

Parameters
packetOutput packet buffer to zero and prepare.

Definition at line 370 of file radio_interface.h.

Here is the call graph for this function:

◆ prepare_nonblocking_receive_()

void esphome::home_io_control::RadioDriver::prepare_nonblocking_receive_ ( RadioRxPacket & packet)
inlineprotected

Common preamble for non‑blocking receive: clear diagnostics, output packet, and DIO latch.

Parameters
packetOutput packet buffer to zero and prepare.

Definition at line 377 of file radio_interface.h.

Here is the call graph for this function:

◆ read_rssi()

virtual int16_t esphome::home_io_control::RadioDriver::read_rssi ( )
pure virtual

Read instantaneous RSSI (in dBm) while in RX mode.

Used for listen-before-talk (LBT) carrier sense before transmitting.

Returns
RSSI in dBm (negative value).

Implemented in esphome::home_io_control::RadioSX1276, and esphome::home_io_control::SoftPhyDriverBase.

◆ reception_in_progress()

virtual bool esphome::home_io_control::RadioDriver::reception_in_progress ( )
inlinenodiscardvirtual

True while a frame is arriving on the current channel and retuning would destroy it.

Consulted by ExchangeEngine::maybe_hop() — the idle-path hop — which is purely time-gated and otherwise fires on essentially every loop() pass (issue #81). Not consulted by hop_frequency() itself: the blocking listen() loop does its own, differently-shaped gating through preamble_or_sync_incoming(), and a caller that asked for a hop explicitly must get one.

The default implementation is the recorded-state one: a driver reports a reception by calling note_reception_in_progress_() from wherever it can actually observe one, and the holdoff expires by itself after RX_HOP_HOLDOFF_US. That default is correct for any driver whose RX path passes through check_for_packet() while the frame is still arriving, and it is what both software-PHY drivers use. A driver that cannot observe a reception from check_for_packet() overrides this and reads the chip at hop time instead — see RadioSX1276.

Non-const because it expires its own latch, and because an override may do SPI.

Reimplemented in esphome::home_io_control::RadioSX1276.

Definition at line 328 of file radio_interface.h.

◆ reset_hardware_()

void esphome::home_io_control::RadioDriver::reset_hardware_ ( )
protected

Shared hardware reset sequence for chips with an active-low RST pin.

Drives RST pin low → 10 ms → high → 10 ms. Called from derived driver init().

Definition at line 18 of file radio_interface.cpp.

◆ response_preamble()

virtual uint16_t esphome::home_io_control::RadioDriver::response_preamble ( ) const
inlinenodiscardvirtual

Return the preamble length for response/continuation frames.

Callers use this instead of hardcoding SHORT_PREAMBLE for any frame sent as an immediate reply within an exchange (challenge responses, key transfers, and any future non-START continuation frames — i.e. tight RX→TX turnaround).

The default is the protocol's standard SHORT_PREAMBLE. Drivers whose TX waveform gives the peer device less synchronization margin override this with a longer preamble (see the concrete drivers for the chip-specific rationale).

Returns
Preamble length in bytes.

Reimplemented in esphome::home_io_control::RadioSX1276, and esphome::home_io_control::SoftPhyDriverBase.

Definition at line 210 of file radio_interface.h.

◆ send_packet()

virtual bool esphome::home_io_control::RadioDriver::send_packet ( const uint8_t * data,
uint8_t len,
const RadioTxConfig & tx_config )
pure virtual

Send a packet using the specified carrier frequency and preamble settings.

The driver is responsible for appending the protocol CRC on the air (in hardware or software, depending on the chip).

Implemented in esphome::home_io_control::RadioSX1276, and esphome::home_io_control::SoftPhyDriverBase.

◆ set_mode_rx()

virtual void esphome::home_io_control::RadioDriver::set_mode_rx ( )
pure virtual

◆ set_mode_standby()

virtual void esphome::home_io_control::RadioDriver::set_mode_standby ( )
pure virtual

◆ wait_for_packet()

virtual bool esphome::home_io_control::RadioDriver::wait_for_packet ( RadioRxPacket & packet,
uint32_t timeout_ms )
pure virtual

Wait (blocking) for a packet with timeout.

Returns true if a packet was received. Contract:

  • Clears last_capture_ and output packet before waiting.
  • On success: populates packet and last_capture_, returns true.
  • On timeout/failure: may populate last_capture_ for diagnostics, returns false.
  • Radio remains in RX mode on return (regardless of outcome).

Implemented in esphome::home_io_control::RadioSX1276, and esphome::home_io_control::SoftPhyDriverBase.

Member Data Documentation

◆ current_freq_

uint32_t esphome::home_io_control::RadioDriver::current_freq_ {FREQ_CH2}
protected

Definition at line 433 of file radio_interface.h.

◆ dio_fired_

volatile bool esphome::home_io_control::RadioDriver::dio_fired_ {false}
protected

Definition at line 446 of file radio_interface.h.

◆ failed_

bool esphome::home_io_control::RadioDriver::failed_ {false}
protected

Latched by fail_; see is_failed.

Definition at line 437 of file radio_interface.h.

◆ failure_reason_

const char* esphome::home_io_control::RadioDriver::failure_reason_ {nullptr}
protected

First failure cause, see failure_reason.

Definition at line 438 of file radio_interface.h.

◆ last_capture_

RadioCaptureInfo esphome::home_io_control::RadioDriver::last_capture_ {}
protected

Definition at line 434 of file radio_interface.h.

◆ rst_pin_

InternalGPIOPin* esphome::home_io_control::RadioDriver::rst_pin_ {nullptr}
protected

Definition at line 435 of file radio_interface.h.

◆ rx_hold_armed_

bool esphome::home_io_control::RadioDriver::rx_hold_armed_ {false}
protected

Idle-hop holdoff latch — see reception_in_progress().

Definition at line 440 of file radio_interface.h.

◆ rx_hold_since_us_

uint32_t esphome::home_io_control::RadioDriver::rx_hold_since_us_ {0}
protected

micros() timestamp the holdoff was last (re-)armed at.

Definition at line 441 of file radio_interface.h.


The documentation for this class was generated from the following files: