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

Shared RX/TX driver flow for the software-PHY radios (SX1262, LR1121). More...

#include <radio_soft_phy_driver_base.h>

Inheritance diagram for esphome::home_io_control::SoftPhyDriverBase:
Collaboration diagram for esphome::home_io_control::SoftPhyDriverBase:

Classes

struct  SoftPhyPacketParams
 The GFSK SetPacketParams fields both software-PHY chips program identically. More...

Public Member Functions

 SoftPhyDriverBase (InternalGPIOPin *rst_pin, InternalGPIOPin *busy_pin, uint32_t busy_timeout_ms, uint16_t default_response_preamble, uint16_t default_post_tx_settle_us)
bool send_packet (const uint8_t *data, uint8_t len, const RadioTxConfig &tx_config) override
 Send a packet using the specified carrier frequency and preamble settings.
bool wait_for_packet (RadioRxPacket &packet, uint32_t timeout_ms) override
 Wait (blocking) for a packet with timeout.
bool check_for_packet (RadioRxPacket &packet) override
 Non-blocking check for a received packet.
void change_frequency (uint32_t freq_hz) override
 Change the carrier frequency using fast hop (no standby transition needed).
int16_t read_rssi () override
 Read instantaneous RSSI (in dBm) while in RX mode.
bool is_sync_detected () override
 Check if sync word has been detected (while in RX).
bool is_preamble_detected () override
 Check if preamble has been detected (while in RX).
uint16_t response_preamble () const override
 Preamble for response/continuation frames — shared storage, see the concrete drivers' constructors/tuning defaults for the chip-specific rationale and value.
uint16_t default_start_preamble () const override
 Default preamble for a directed start frame, when the user has not set normal_start_preamble in YAML.
Public Member Functions inherited from esphome::home_io_control::RadioDriver
 RadioDriver (InternalGPIOPin *rst_pin=nullptr)
virtual ~RadioDriver ()=default
virtual bool init ()=0
 Initialize the radio hardware. Returns true on success.
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 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 set_response_preamble_ (uint16_t preamble)
 Set the preamble length used for response/continuation frames within an exchange.
void set_post_tx_settle_us_ (uint16_t delay_us)
 Set the delay between TX completion and re-entering RX.
uint32_t get_busy_timeout_ms_ () const
 Current wait_busy_ timeout, in milliseconds.
void set_busy_timeout_ms_ (uint32_t timeout_ms)
 Set the wait_busy_ timeout, in milliseconds.
void wait_busy_ ()
 Wait until busy_pin_ reads low, feeding the watchdog while polling.
void record_init_device_errors_ (const char *tag, const char *chip_label, uint16_t errors, DeviceErrorFormatter format)
 Keep the device-error word read at the end of configure_radio_() and warn if it is non-zero.
virtual int8_t front_end_rx_gain_db () const
 Gain (dB) of the board's external receive front end that the chip's RSSI includes.
int16_t raw_rssi_to_dbm_ (uint8_t raw) const
 Convert a chip's raw RSSI byte to an antenna-referred dBm reading.
void dump_init_device_errors_ (const char *tag, DeviceErrorFormatter format) const
 Log the init-time device errors under tag, or nothing when there were none.
virtual bool read_rx_packet (RadioRxPacket &packet, bool blocking_wait, uint32_t irq_status)
 Read a received packet from the buffer and return the raw bytes reported by the chip.
void reset_rx_state_ (bool force_standby=true)
 Reset RX state machine and buffer. Optionally force standby first.
void rearm_rx_after_tx_ ()
 Minimal path back into RX immediately after a transmission — see the definition for why this is deliberately not reset_rx_state_.
virtual uint32_t read_irq_status_raw ()=0
 Read the raw IRQ status word from the radio.
virtual void clear_irq_status (uint32_t irq_mask)=0
 Clear IRQ status bits.
virtual uint32_t activity_irq_mask () const
 IRQ bits that count as "activity" for the internal poll_until_activity_() helper and check_for_packet.
virtual int16_t early_rx_read_offset () const
 Data-buffer offset an in-flight reception is being written to, or a negative value when this chip must not be read before RX_DONE.
virtual uint32_t idle_rx_completion_budget_ms () const
 Blocking budget for the idle-path length-driven receive, in milliseconds (issue #81).
virtual void set_frequency_register (uint32_t freq_hz)=0
 Set RF frequency via the chip's own frequency register/opcode encoding, and update current_freq_.
virtual void set_rx_packet_params ()=0
 Configure RX-specific packet parameters (preamble detector length, fixed probe length).
virtual void set_tx_packet_params (uint16_t preamble_len, uint8_t payload_len)=0
 Configure TX packet parameters for one outgoing UART-encoded frame.
virtual uint8_t read_rssi_raw_byte ()=0
 Read the single raw RSSI byte (chip-specific opcode); formula is shared, see read_rssi.
virtual void write_tx_buffer (const uint8_t *data, uint8_t len)=0
 Write the UART-encoded TX payload into the chip's TX buffer.
virtual void get_rx_buffer_status (uint8_t &reported_len, uint8_t &rx_offset)=0
 Read the chip-reported RX length and buffer offset (raw, before any clamping).
virtual void read_rx_buffer (uint8_t offset, uint8_t *data, uint8_t len)=0
 Read len bytes from the RX buffer starting at offset.
virtual void start_tx ()=0
 Issue the SetTx opcode with the fixed TX timeout — identical 3-byte payload on both chips, differing only in opcode/transport, so this stays a thin chip-specific wrapper.
virtual void fill_capture_info (bool blocking_wait, uint32_t irq_status, uint8_t rx_offset, uint8_t reported_len, const uint8_t *raw, uint8_t raw_len, const uint8_t *frame, uint8_t frame_len)=0
 Populate the RadioCaptureInfo from chip-specific telemetry (RSSI opcode, packet-status byte, and IRQ-word-width narrowing all differ per chip).
virtual void before_tx_arm ()
 Hook run immediately before every SetTx.
virtual void configure_buffer_base ()
 Hook run as part of reset_rx_state_, before re-entering RX.
virtual void invalidate_stale_rx_content_after_tx ()
 Hook run from rearm_rx_after_tx_, after a transmission and before re-entering RX.
Chip-specific IRQ bit values

Each driver's own IRQ bit constants, exposed as accessors so the shared RX/TX orchestration never needs to name a chip-specific constant directly.

virtual uint32_t sync_word_valid_bit () const =0
virtual uint32_t rx_done_bit () const =0
virtual uint32_t tx_done_bit () const =0
virtual uint32_t preamble_detected_bit () const =0
Protected Member Functions inherited from esphome::home_io_control::RadioDriver
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.

Static Protected Member Functions

static void build_gfsk_packet_params (const SoftPhyPacketParams &p, uint8_t out[GFSK_PACKET_PARAMS_LEN])
 Fill the nine-byte GFSK SetPacketParams payload shared by both chips.

Protected Attributes

uint16_t init_device_errors_ {0}
 Device-error word a driver reads at the end of configure_radio_(), before it clears the chip's register.
InternalGPIOPin * busy_pin_
 BUSY line, read directly by both concrete drivers' own dump_debug() in addition to wait_busy_, so this stays protected rather than folding entirely into the private wait-loop state below.
Protected Attributes inherited from esphome::home_io_control::RadioDriver
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}

Static Protected Attributes

static constexpr uint8_t GFSK_PACKET_PARAMS_LEN = 9
 Byte count of the GFSK SetPacketParams payload — identical on both software-PHY chips.

Detailed Description

Shared RX/TX driver flow for the software-PHY radios (SX1262, LR1121).

Definition at line 189 of file radio_soft_phy_driver_base.h.

Constructor & Destructor Documentation

◆ SoftPhyDriverBase()

esphome::home_io_control::SoftPhyDriverBase::SoftPhyDriverBase ( InternalGPIOPin * rst_pin,
InternalGPIOPin * busy_pin,
uint32_t busy_timeout_ms,
uint16_t default_response_preamble,
uint16_t default_post_tx_settle_us )
inline
Parameters
rst_pinActive-low hardware reset pin, forwarded to RadioDriver.
busy_pinBUSY line polled by wait_busy_ before every SPI transaction — both concrete drivers are opcode-based chips that require this, unlike the register-based SX1276.
busy_timeout_msHow long wait_busy_ waits for BUSY to drop before declaring the chip failed. Chip-specific (SX1262: 10 ms: RC-oscillator timing; LR1121: 3000 ms, matched to RadioLib's post-reset boot-ROM wait) — this class has no opinion on the value, only on where it's stored and how it's used.
default_response_preambleChip-specific default for response_preamble (each concrete driver passes its own validated constant — this class has no opinion on the value, only on where it's stored).
default_post_tx_settle_usChip-specific default post-TX settling delay, same rationale.

Definition at line 203 of file radio_soft_phy_driver_base.h.

Here is the call graph for this function:

Member Function Documentation

◆ activity_irq_mask()

virtual uint32_t esphome::home_io_control::SoftPhyDriverBase::activity_irq_mask ( ) const
inlinenodiscardprotectedvirtual

IRQ bits that count as "activity" for the internal poll_until_activity_() helper and check_for_packet.

Default is "any bit" — safe only for a driver whose SetDioIrqParams-equivalent mask never includes PreambleDetected in the first place, so a preamble-only reading can never reach this check. Neither current driver qualifies: both SX1262 and LR1121 unmask PreambleDetected (each for its own reason) and override this to exclude it — a preamble-only reading means a frame may still be arriving, and treating it as terminal activity would tear down RX mid-reception.

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

Definition at line 373 of file radio_soft_phy_driver_base.h.

◆ before_tx_arm()

virtual void esphome::home_io_control::SoftPhyDriverBase::before_tx_arm ( )
inlineprotectedvirtual

Hook run immediately before every SetTx.

No-op by default; LR1121 overrides this to apply its high-ACP TX-quality workaround, which Semtech's own reference applies unconditionally before every SetRx/SetTx.

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

Definition at line 432 of file radio_soft_phy_driver_base.h.

◆ build_gfsk_packet_params()

void esphome::home_io_control::SoftPhyDriverBase::build_gfsk_packet_params ( const SoftPhyPacketParams & p,
uint8_t out[GFSK_PACKET_PARAMS_LEN] )
staticprotected

Fill the nine-byte GFSK SetPacketParams payload shared by both chips.

Owns the field order and the ×8 preamble conversion: the SetPacketParams preamble field is bit-denominated on both chips (Semtech names it preamble_len_in_bits / pbl_len_in_bit), but every caller in this codebase passes a byte count. Address comparison and whitening are always off.

Parameters
pThe chip-independent field values (byte-denominated preamble, chip constants).
outBuffer for exactly GFSK_PACKET_PARAMS_LEN bytes.

Named without the trailing _ the file's other protected helpers carry: it uses no instance state, so clang-tidy's readability-convert-member-functions-to-static wants it static, and .clang-tidy's ClassMethodCase = lower_case then rejects a trailing _ on a static method. Leaving it static and dropping the underscore keeps clang-tidy quiet without a suppression.

Definition at line 267 of file radio_soft_phy_driver_base.cpp.

◆ change_frequency()

void esphome::home_io_control::SoftPhyDriverBase::change_frequency ( uint32_t freq_hz)
overridevirtual

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

Implements esphome::home_io_control::RadioDriver.

Definition at line 561 of file radio_soft_phy_driver_base.cpp.

Here is the call graph for this function:

◆ check_for_packet()

bool esphome::home_io_control::SoftPhyDriverBase::check_for_packet ( RadioRxPacket & packet)
overridevirtual

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.

Implements esphome::home_io_control::RadioDriver.

Definition at line 394 of file radio_soft_phy_driver_base.cpp.

Here is the call graph for this function:

◆ clear_irq_status()

virtual void esphome::home_io_control::SoftPhyDriverBase::clear_irq_status ( uint32_t irq_mask)
protectedpure virtual

Clear IRQ status bits.

Parameters
irq_maskBitmask of IRQs to clear (each driver narrows to its own IRQ word width).

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

◆ configure_buffer_base()

virtual void esphome::home_io_control::SoftPhyDriverBase::configure_buffer_base ( )
inlineprotectedvirtual

Hook run as part of reset_rx_state_, before re-entering RX.

No-op by default; SX1262 overrides this to (re-)write its buffer base address, which LR1121 doesn't need.

Reimplemented in esphome::home_io_control::RadioSX1262.

Definition at line 435 of file radio_soft_phy_driver_base.h.

◆ default_start_preamble()

uint16_t esphome::home_io_control::SoftPhyDriverBase::default_start_preamble ( ) const
inlinenodiscardoverridevirtual

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.

This PHY puts less usable preamble on air than its programmed length suggests, so it asks for more than the protocol's documented value (SOFT_PHY_START_PREAMBLE, which carries the measurement). The override belongs here rather than on each concrete driver because the shared PHY is the level the effect follows: SX1262 and LR1121 measured the same as each other and both differed from the register PHY, so a per-driver value would invent a difference the evidence does not show. See ADR 0042.

Reimplemented from esphome::home_io_control::RadioDriver.

Definition at line 244 of file radio_soft_phy_driver_base.h.

◆ dump_init_device_errors_()

void esphome::home_io_control::SoftPhyDriverBase::dump_init_device_errors_ ( const char * tag,
DeviceErrorFormatter format ) const
protected

Log the init-time device errors under tag, or nothing when there were none.

Parameters
tagLog tag of the calling driver, so the line stays inside its own dump section.
formatThe calling chip's decoder for its device-error word.

Definition at line 623 of file radio_soft_phy_driver_base.cpp.

◆ early_rx_read_offset()

virtual int16_t esphome::home_io_control::SoftPhyDriverBase::early_rx_read_offset ( ) const
inlinenodiscardprotectedvirtual

Data-buffer offset an in-flight reception is being written to, or a negative value when this chip must not be read before RX_DONE.

Neither chip's RX_DONE marks the end of the frame: with no hardware framing, RX runs in fixed-length mode at SOFT_PHY_RX_PROBE_PACKET_LEN, so RX_DONE arrives a fixed ~10 ms after the sync word no matter how short the frame actually was. That delay lands squarely on the protocol's tightest turnaround — the hub's reply to a device's challenge — so a driver that can read its buffer while reception is still running opts in here and the shared flow finishes on the frame's own air time instead (see try_early_completion_).

Default is -1: wait for RX_DONE exactly as before. SX1262 overrides it with the RX base address it programs in configure_buffer_base(), which is where a single in-flight packet always starts. LR1121 also opts in, at the base of its one shared TX/RX buffer — see RadioLR1121::early_rx_read_offset for why a wrong guess there is safe only in combination with invalidate_stale_rx_content_after_tx.

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

Definition at line 392 of file radio_soft_phy_driver_base.h.

◆ fill_capture_info()

virtual void esphome::home_io_control::SoftPhyDriverBase::fill_capture_info ( bool blocking_wait,
uint32_t irq_status,
uint8_t rx_offset,
uint8_t reported_len,
const uint8_t * raw,
uint8_t raw_len,
const uint8_t * frame,
uint8_t frame_len )
protectedpure virtual

Populate the RadioCaptureInfo from chip-specific telemetry (RSSI opcode, packet-status byte, and IRQ-word-width narrowing all differ per chip).

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

◆ front_end_rx_gain_db()

virtual int8_t esphome::home_io_control::SoftPhyDriverBase::front_end_rx_gain_db ( ) const
inlinenodiscardprotectedvirtual

Gain (dB) of the board's external receive front end that the chip's RSSI includes.

A low-noise amplifier ahead of the radio raises every RSSI reading by its gain, which makes an idle channel look busy against a threshold defined at the antenna (listen-before-talk) and makes signal levels incomparable between boards. Drivers whose board has such a front end override this; raw_rssi_to_dbm_ then reports antenna-referred values. Boards without one keep the default of 0.

Reimplemented in esphome::home_io_control::RadioSX1262.

Definition at line 283 of file radio_soft_phy_driver_base.h.

◆ get_busy_timeout_ms_()

uint32_t esphome::home_io_control::SoftPhyDriverBase::get_busy_timeout_ms_ ( ) const
inlinenodiscardprotected

Current wait_busy_ timeout, in milliseconds.

Definition at line 253 of file radio_soft_phy_driver_base.h.

◆ get_rx_buffer_status()

virtual void esphome::home_io_control::SoftPhyDriverBase::get_rx_buffer_status ( uint8_t & reported_len,
uint8_t & rx_offset )
protectedpure virtual

Read the chip-reported RX length and buffer offset (raw, before any clamping).

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

◆ idle_rx_completion_budget_ms()

virtual uint32_t esphome::home_io_control::SoftPhyDriverBase::idle_rx_completion_budget_ms ( ) const
inlinenodiscardprotectedvirtual

Blocking budget for the idle-path length-driven receive, in milliseconds (issue #81).

Virtual only so tests can widen it. The host clock stubs advance millis()/micros() by one unit per call (tests/include/esphome/core/hal.h), so a frame's few thousand microseconds of air time also burns a few thousand fake milliseconds — any production-sized budget expires inside wait_for_air_time()'s first stage and the whole path becomes untestable. The existing blocking-path early-completion tests dodge this by passing wait_for_packet() a 20000 ms timeout; this path has no caller-supplied timeout to widen, so the seam has to live here.

Definition at line 402 of file radio_soft_phy_driver_base.h.

◆ invalidate_stale_rx_content_after_tx()

virtual void esphome::home_io_control::SoftPhyDriverBase::invalidate_stale_rx_content_after_tx ( )
inlineprotectedvirtual

Hook run from rearm_rx_after_tx_, after a transmission and before re-entering RX.

No-op by default.

SX1262 has a real address split written once at init (configure_buffer_base): TX always builds at its own base, RX always lands at a different one, so nothing a transmission wrote can ever appear where a length-driven receive (early_rx_read_offset) later reads from. LR1121 has no such split — one shared 256-byte buffer for both directions, and WriteBuffer always starts from the buffer base (see write_buffer_'s doc comment) — so after every LR1121 transmission, the offset a length-driven receive will read from holds a real, CRC-valid, UART-encoded copy of the hub's own last-sent frame. That is not noise: if early_rx_read_offset()'s offset guess ever turns out to be wrong, reading that residue back would pass every stage of try_early_completion_() and hand back the hub's own transmission as a phantom received packet — worse than doing nothing, since check_for_packet() would then tear down and re-arm RX (issue #81's force_standby path) over whatever real reception was actually in progress. RadioLR1121 overrides this to overwrite that offset with a few non-frame-shaped bytes after every TX, so a wrong offset guess degrades back to reading genuine garbage — which correctly fails the length-driven receive's stage 1 or stage 3 — instead of a valid-looking phantom frame.

Reimplemented in esphome::home_io_control::RadioLR1121.

Definition at line 454 of file radio_soft_phy_driver_base.h.

◆ is_preamble_detected()

bool esphome::home_io_control::SoftPhyDriverBase::is_preamble_detected ( )
overridevirtual

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

Used together with sync detection to gate frequency hopping.

Consults the private preamble_latched_at_timeout_ flag first; see that member's declaration for why.

Implements esphome::home_io_control::RadioDriver.

Definition at line 575 of file radio_soft_phy_driver_base.cpp.

Here is the call graph for this function:

◆ is_sync_detected()

bool esphome::home_io_control::SoftPhyDriverBase::is_sync_detected ( )
overridevirtual

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

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

Implements esphome::home_io_control::RadioDriver.

Definition at line 573 of file radio_soft_phy_driver_base.cpp.

Here is the call graph for this function:

◆ preamble_detected_bit()

virtual uint32_t esphome::home_io_control::SoftPhyDriverBase::preamble_detected_bit ( ) const
nodiscardprotectedpure virtual

◆ raw_rssi_to_dbm_()

int16_t esphome::home_io_control::SoftPhyDriverBase::raw_rssi_to_dbm_ ( uint8_t raw) const
inlinenodiscardprotected

Convert a chip's raw RSSI byte to an antenna-referred dBm reading.

Parameters
rawRaw byte from the chip (dBm = -raw / 2 at the radio's input, on both chips).
Returns
The reading with front_end_rx_gain_db removed. Used for every RSSI this driver reports — live (read_rssi) and per received packet — so they share one scale.

Definition at line 288 of file radio_soft_phy_driver_base.h.

Here is the call graph for this function:

◆ read_irq_status_raw()

virtual uint32_t esphome::home_io_control::SoftPhyDriverBase::read_irq_status_raw ( )
protectedpure virtual

Read the raw IRQ status word from the radio.

Virtual to allow test doubles (both concrete drivers' tests override this).

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

◆ read_rssi()

int16_t esphome::home_io_control::SoftPhyDriverBase::read_rssi ( )
overridevirtual

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).

Same formula on both chips (-(int16_t) raw / 2, see raw_rssi_to_dbm_); only the opcode used to read the single raw byte differs, via read_rssi_raw_byte. Antenna-referred: the gain of an external receive front end is removed, see front_end_rx_gain_db.

Implements esphome::home_io_control::RadioDriver.

Definition at line 571 of file radio_soft_phy_driver_base.cpp.

Here is the call graph for this function:

◆ read_rssi_raw_byte()

virtual uint8_t esphome::home_io_control::SoftPhyDriverBase::read_rssi_raw_byte ( )
protectedpure virtual

Read the single raw RSSI byte (chip-specific opcode); formula is shared, see read_rssi.

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

◆ read_rx_buffer()

virtual void esphome::home_io_control::SoftPhyDriverBase::read_rx_buffer ( uint8_t offset,
uint8_t * data,
uint8_t len )
protectedpure virtual

Read len bytes from the RX buffer starting at offset.

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

◆ read_rx_packet()

bool esphome::home_io_control::SoftPhyDriverBase::read_rx_packet ( RadioRxPacket & packet,
bool blocking_wait,
uint32_t irq_status )
protectedvirtual

Read a received packet from the buffer and return the raw bytes reported by the chip.

Virtual to allow test doubles (both concrete drivers' tests override this).

Definition at line 302 of file radio_soft_phy_driver_base.cpp.

Here is the call graph for this function:

◆ rearm_rx_after_tx_()

void esphome::home_io_control::SoftPhyDriverBase::rearm_rx_after_tx_ ( )
protected

Minimal path back into RX immediately after a transmission — see the definition for why this is deliberately not reset_rx_state_.

Definition at line 242 of file radio_soft_phy_driver_base.cpp.

Here is the call graph for this function:

◆ record_init_device_errors_()

void esphome::home_io_control::SoftPhyDriverBase::record_init_device_errors_ ( const char * tag,
const char * chip_label,
uint16_t errors,
DeviceErrorFormatter format )
protected

Keep the device-error word read at the end of configure_radio_() and warn if it is non-zero.

Parameters
tagLog tag of the calling driver.
chip_labelChip name for the warning, e.g. "SX1262".
errorsThe word read from the chip, before the caller clears its register.
formatThe calling chip's decoder for its device-error word.

Definition at line 612 of file radio_soft_phy_driver_base.cpp.

◆ reset_rx_state_()

void esphome::home_io_control::SoftPhyDriverBase::reset_rx_state_ ( bool force_standby = true)
protected

Reset RX state machine and buffer. Optionally force standby first.

Definition at line 285 of file radio_soft_phy_driver_base.cpp.

Here is the call graph for this function:

◆ response_preamble()

uint16_t esphome::home_io_control::SoftPhyDriverBase::response_preamble ( ) const
inlinenodiscardoverridevirtual

Preamble for response/continuation frames — shared storage, see the concrete drivers' constructors/tuning defaults for the chip-specific rationale and value.

Reimplemented from esphome::home_io_control::RadioDriver.

Definition at line 234 of file radio_soft_phy_driver_base.h.

◆ rx_done_bit()

virtual uint32_t esphome::home_io_control::SoftPhyDriverBase::rx_done_bit ( ) const
nodiscardprotectedpure virtual

◆ send_packet()

bool esphome::home_io_control::SoftPhyDriverBase::send_packet ( const uint8_t * data,
uint8_t len,
const RadioTxConfig & tx_config )
overridevirtual

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).

Implements esphome::home_io_control::RadioDriver.

Definition at line 461 of file radio_soft_phy_driver_base.cpp.

Here is the call graph for this function:

◆ set_busy_timeout_ms_()

void esphome::home_io_control::SoftPhyDriverBase::set_busy_timeout_ms_ ( uint32_t timeout_ms)
inlineprotected

Set the wait_busy_ timeout, in milliseconds.

Exposed so a concrete driver can widen it around a bring-up step that legitimately holds BUSY far longer than the steady-state value (SX1262 TCXO startup runs up to 50 ms against a 10 ms default) and then restore it. Pair every widen with a restore.

Definition at line 259 of file radio_soft_phy_driver_base.h.

◆ set_frequency_register()

virtual void esphome::home_io_control::SoftPhyDriverBase::set_frequency_register ( uint32_t freq_hz)
protectedpure virtual

Set RF frequency via the chip's own frequency register/opcode encoding, and update current_freq_.

Called from both change_frequency and the shared send_packet().

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

◆ set_post_tx_settle_us_()

void esphome::home_io_control::SoftPhyDriverBase::set_post_tx_settle_us_ ( uint16_t delay_us)
inlineprotected

Set the delay between TX completion and re-entering RX.

Definition at line 251 of file radio_soft_phy_driver_base.h.

◆ set_response_preamble_()

void esphome::home_io_control::SoftPhyDriverBase::set_response_preamble_ ( uint16_t preamble)
inlineprotected

Set the preamble length used for response/continuation frames within an exchange.

Definition at line 249 of file radio_soft_phy_driver_base.h.

◆ set_rx_packet_params()

virtual void esphome::home_io_control::SoftPhyDriverBase::set_rx_packet_params ( )
protectedpure virtual

Configure RX-specific packet parameters (preamble detector length, fixed probe length).

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

◆ set_tx_packet_params()

virtual void esphome::home_io_control::SoftPhyDriverBase::set_tx_packet_params ( uint16_t preamble_len,
uint8_t payload_len )
protectedpure virtual

Configure TX packet parameters for one outgoing UART-encoded frame.

Parameters
preamble_lenPreamble length in symbols, from the caller's RadioTxConfig.
payload_lenUART-encoded payload length in bytes.

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

◆ start_tx()

virtual void esphome::home_io_control::SoftPhyDriverBase::start_tx ( )
protectedpure virtual

Issue the SetTx opcode with the fixed TX timeout — identical 3-byte payload on both chips, differing only in opcode/transport, so this stays a thin chip-specific wrapper.

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

◆ sync_word_valid_bit()

virtual uint32_t esphome::home_io_control::SoftPhyDriverBase::sync_word_valid_bit ( ) const
nodiscardprotectedpure virtual

◆ tx_done_bit()

virtual uint32_t esphome::home_io_control::SoftPhyDriverBase::tx_done_bit ( ) const
nodiscardprotectedpure virtual

◆ wait_busy_()

void esphome::home_io_control::SoftPhyDriverBase::wait_busy_ ( )
protected

Wait until busy_pin_ reads low, feeding the watchdog while polling.

Shared verbatim between SX1262 and LR1121 — the two chips differ only in how long they're willing to wait (busy_timeout_ms_). A call short-circuits once the driver has latched failed_: without that guard, every remaining configure_radio_() step after the first failure would re-run the full timeout, turning one bad boot into tens of seconds of hang at the LR1121's 3000 ms timeout (harmless but still pointless at the SX1262's 10 ms one).

Definition at line 49 of file radio_soft_phy_driver_base.cpp.

Here is the call graph for this function:

◆ wait_for_packet()

bool esphome::home_io_control::SoftPhyDriverBase::wait_for_packet ( RadioRxPacket & packet,
uint32_t timeout_ms )
overridevirtual

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).

Implements esphome::home_io_control::RadioDriver.

Definition at line 69 of file radio_soft_phy_driver_base.cpp.

Here is the call graph for this function:

◆ write_tx_buffer()

virtual void esphome::home_io_control::SoftPhyDriverBase::write_tx_buffer ( const uint8_t * data,
uint8_t len )
protectedpure virtual

Write the UART-encoded TX payload into the chip's TX buffer.

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

Member Data Documentation

◆ busy_pin_

InternalGPIOPin* esphome::home_io_control::SoftPhyDriverBase::busy_pin_
protected

BUSY line, read directly by both concrete drivers' own dump_debug() in addition to wait_busy_, so this stays protected rather than folding entirely into the private wait-loop state below.

Definition at line 303 of file radio_soft_phy_driver_base.h.

◆ GFSK_PACKET_PARAMS_LEN

uint8_t esphome::home_io_control::SoftPhyDriverBase::GFSK_PACKET_PARAMS_LEN = 9
staticconstexprprotected

Byte count of the GFSK SetPacketParams payload — identical on both software-PHY chips.

Definition at line 330 of file radio_soft_phy_driver_base.h.

◆ init_device_errors_

uint16_t esphome::home_io_control::SoftPhyDriverBase::init_device_errors_ {0}
protected

Device-error word a driver reads at the end of configure_radio_(), before it clears the chip's register.

The chip still initializes and transmits with some of these set (PLL lock, calibration, TCXO start), so the config dump reports the captured value: a later read of the register would only ever see the cleared state.

Definition at line 299 of file radio_soft_phy_driver_base.h.


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