|
Home IO Control
ESPHome add-on for IO-Homecontrol devices
|
LR1121 implementation of RadioDriver. More...
#include <radio_lr1121.h>
Public Member Functions | |
| RadioLR1121 (SpiAccess *spi, InternalGPIOPin *rst_pin, InternalGPIOPin *irq_pin, InternalGPIOPin *busy_pin, uint8_t tx_power, uint8_t tcxo_voltage_yaml_code) | |
| bool | init () override |
| Initialize the radio hardware. Returns true on success. | |
| void | apply_tuning (const TuningConfig &tuning) override |
| Apply LR1121 runtime tuning: RX bandwidth, response preamble, post-TX settle delay. | |
| uint32_t | exchange_wait_slice_ms () const override |
| Per-channel dwell while waiting for exchange responses (LR1121). | |
| uint16_t | discovery_hop_slice_ms (const TuningConfig &tuning) const override |
| Per-channel dwell while pairing discovery hops (LR1121). | |
| bool | has_fast_tx_rx_turnaround () const override |
| TX→RX turnaround capability (LR1121): slow, same as SX1262. | |
| void | set_mode_rx () override |
| Switch to continuous receive mode. | |
| void | set_mode_standby () override |
| Switch to standby mode. | |
| bool | is_failed () const override |
| Returns true if the radio failed to initialize or encountered a fatal error. | |
| const char * | chip_name () const override |
| Get a human‑readable chip name. | |
| void | dump_debug () override |
| Dump LR1121-specific debug info. | |
| Public Member Functions inherited from esphome::home_io_control::SoftPhyDriverBase | |
| SoftPhyDriverBase (InternalGPIOPin *rst_pin, 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. | |
| Public Member Functions inherited from esphome::home_io_control::RadioDriver | |
| RadioDriver (InternalGPIOPin *rst_pin=nullptr) | |
| virtual | ~RadioDriver ()=default |
| uint32_t | get_current_freq () const |
| Get the current RF frequency. | |
| const RadioCaptureInfo & | get_last_capture () const |
| Get the most recent radio capture info. | |
| 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_rx_bandwidth_ (LR1121RxBandwidth bandwidth) |
| Apply the RX bandwidth selector and rewrite the modulation parameters. | |
| void | wait_busy_ () |
| Wait until BUSY pin is low before any SPI transaction. | |
| void | write_command_ (uint16_t opcode, const uint8_t *params, uint8_t len) |
| Write-only command: opcode + params, single NSS cycle. | |
| void | read_command_ (uint16_t opcode, const uint8_t *params, uint8_t params_len, uint8_t *out, uint8_t out_len) |
| Read-type command: write transaction, wait BUSY, then a second NSS cycle clocks out a Stat1 status byte followed by out_len response bytes. | |
| void | write_buffer_ (const uint8_t *data, uint8_t len) |
| Write into the LR1121 TX buffer (always from the chip's internal write pointer, which resets to the buffer base for a fresh WriteBuffer sequence — unlike SX1262 there is no separate offset parameter here; see design §3.2 "SPI transport"). | |
| void | read_buffer_ (uint8_t offset, uint8_t len, uint8_t *data) |
| Read from the LR1121 RX buffer at a given offset (as reported by GetRxBufferStatus). | |
| void | log_command_status_ (uint16_t opcode) const |
| Log a warning if the most recently observed Stat1 command-status byte indicates the chip rejected the previous command (FAIL/PERR — see radio_lr1121.h §4.4). | |
| void | write_reg_mem_mask32_ (uint32_t addr, uint32_t mask, uint32_t value) |
| WriteRegMemMask32: read-modify-write a 32-bit register through mask/value. | |
| void | apply_high_acp_workaround_ () |
| Apply the Semtech high-ACP TX-quality erratum workaround (analysis §4.1). | |
| void | apply_gfsk_workaround_ () |
| Apply the GFSK modulation workaround register trio (analysis §4.2). | |
| void | calibrate_image_ () |
| Issue a banded image calibration for the 868MHz operating range (analysis §4.3). | |
| void | configure_radio_ () |
| Full radio initialization (called from init()). | |
| void | set_frequency_register (uint32_t freq_hz) override |
| Set RF frequency via the chip's own frequency register/opcode encoding, and update current_freq_. | |
| void | set_packet_params_ (uint16_t preamble_len, uint8_t payload_len, uint8_t packet_type, uint8_t crc_type) |
| Configure GFSK packet parameters (preamble, payload length, CRC). | |
| void | write_modulation_params_ () |
| Apply the runtime bandwidth setting to the LR1121 modulation parameters. | |
| void | set_rx_packet_params () override |
| Configure RX-specific packet parameters (preamble detector length, fixed probe length). | |
| void | set_tx_packet_params (uint16_t preamble_len, uint8_t payload_len) override |
| Configure TX packet parameters for one outgoing UART-encoded frame. | |
| void | clear_irq_status (uint32_t irq_mask) override |
| Clear IRQ status bits. | |
| uint16_t | get_errors_ () |
| Read device error flags (for diagnostics only — see dump_debug()). | |
| void | clear_errors_ () |
| Clear device error flags. | |
| 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) override |
| Populate the RadioCaptureInfo from chip-specific telemetry (RSSI opcode, packet-status byte, and IRQ-word-width narrowing all differ per chip). | |
| uint32_t | read_irq_status_raw () override |
| Read the raw IRQ status word from the radio. | |
| uint32_t | sync_word_valid_bit () const override |
| uint32_t | rx_done_bit () const override |
| uint32_t | tx_done_bit () const override |
| uint32_t | preamble_detected_bit () const override |
| uint32_t | activity_irq_mask () const override |
| IRQ bits that count as "activity" for the internal poll_until_activity_() helper and check_for_packet. | |
| uint8_t | read_rssi_raw_byte () override |
| Read the single raw RSSI byte (chip-specific opcode); formula is shared, see read_rssi. | |
| void | write_tx_buffer (const uint8_t *data, uint8_t len) override |
| Write the UART-encoded TX payload into the chip's TX buffer. | |
| void | get_rx_buffer_status (uint8_t &reported_len, uint8_t &rx_offset) override |
| Read the chip-reported RX length and buffer offset (raw, before any clamping). | |
| void | read_rx_buffer (uint8_t offset, uint8_t *data, uint8_t len) override |
| Read len bytes from the RX buffer starting at offset. | |
| void | start_tx () override |
| 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. | |
| void | before_tx_arm () override |
| Hook run immediately before every SetTx. | |
| Protected Member Functions inherited from esphome::home_io_control::SoftPhyDriverBase | |
| 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. | |
| 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. | |
| 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 void | configure_buffer_base () |
| Hook run as part of reset_rx_state_, before re-entering RX. | |
| Protected Member Functions inherited from esphome::home_io_control::RadioDriver | |
| void | clear_last_capture_ () |
| Clear the last capture info (resets diagnostic buffer). | |
| 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 | 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. | |
Static Protected Member Functions | |
| static void | gpio_intr (RadioLR1121 *arg) |
| IRQ pin (DIO9) ISR — sets dio_fired flag. Runs in interrupt context. | |
Additional Inherited Members | |
| Protected Attributes inherited from esphome::home_io_control::RadioDriver | |
| uint32_t | current_freq_ {FREQ_CH2} |
| RadioCaptureInfo | last_capture_ {} |
| InternalGPIOPin * | rst_pin_ {nullptr} |
| volatile bool | dio_fired_ {false} |
LR1121 implementation of RadioDriver.
Manages the LR1121 via 16-bit-opcode, two-transaction SPI using the SpiAccess interface. Configures the chip in GFSK mode with software CRC-CCITT to match the IO-Homecontrol protocol (the LR1121, like the SX1262, lacks the SX1276's IoHomeOn mode). The IRQ-driven RX/TX orchestration is inherited from SoftPhyDriverBase; this class supplies the SPI transport and every LR1121-specific register/opcode encoding underneath it. See the file header for the driver's relationship to RadioSX1262.
Definition at line 247 of file radio_lr1121.h.
|
inline |
|
inlinenodiscardoverrideprotectedvirtual |
IRQ bits that count as "activity" for the internal poll_until_activity_() helper and check_for_packet.
Default is "any bit" — correct for SX1262, whose SetDioIrqParams mask already excludes PreambleDetected system-wide, so a preamble-only reading can never reach this check in the first place. LR1121 routes PreambleDetected to its IRQ pin for other reasons and overrides 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.
Excludes PREAMBLE_DETECTED, unlike the base's "any bit" default — see LR1121_IRQ_ACTIVITY_MASK's doc comment for why this chip needs the distinction.
Reimplemented from esphome::home_io_control::SoftPhyDriverBase.
Definition at line 386 of file radio_lr1121.h.
|
protected |
Apply the GFSK modulation workaround register trio (analysis §4.2).
Called at the end of write_modulation_params_() so it re-applies on every bandwidth retune too.
Definition at line 114 of file radio_lr1121.cpp.
|
protected |
Apply the Semtech high-ACP TX-quality erratum workaround (analysis §4.1).
Must run before every SetRx/SetTx — called from set_mode_rx() and before_tx_arm rather than once at init, mirroring Semtech's own call sites.
Definition at line 109 of file radio_lr1121.cpp.
|
inlineoverridevirtual |
Apply LR1121 runtime tuning: RX bandwidth, response preamble, post-TX settle delay.
Reimplemented from esphome::home_io_control::RadioDriver.
Definition at line 261 of file radio_lr1121.h.
|
inlineoverrideprotectedvirtual |
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.
High-ACP workaround (analysis §4.1) — Semtech applies this unconditionally before every SetTx, same as before every SetRx (see set_mode_rx()).
Reimplemented from esphome::home_io_control::SoftPhyDriverBase.
Definition at line 401 of file radio_lr1121.h.
|
protected |
Issue a banded image calibration for the 868MHz operating range (analysis §4.3).
Definition at line 123 of file radio_lr1121.cpp.
|
inlinenodiscardoverridevirtual |
Get a human‑readable chip name.
Implements esphome::home_io_control::RadioDriver.
Definition at line 286 of file radio_lr1121.h.
|
protected |
Clear device error flags.
Called both during init (after TCXO configuration, before calibration) and at the end of configure_radio_() to discard init-time noise.
Definition at line 215 of file radio_lr1121.cpp.
|
overrideprotectedvirtual |
Clear IRQ status bits.
| irq_mask | Bitmask of IRQs to clear (each driver narrows to its own IRQ word width). |
Implements esphome::home_io_control::SoftPhyDriverBase.
Definition at line 217 of file radio_lr1121.cpp.
|
protected |
Full radio initialization (called from init()).
Definition at line 320 of file radio_lr1121.cpp.
|
inlinenodiscardoverridevirtual |
Per-channel dwell while pairing discovery hops (LR1121).
LR1121 frequency changes require a standby→SetRfFrequency→RX cycle (no fast hop), same as the SX1262, so discovery needs the equivalent longer dwell. The value comes from the user-facing lr1121_discovery_hop_slice_ms tuning field.
Implements esphome::home_io_control::RadioDriver.
Definition at line 273 of file radio_lr1121.h.
|
overridevirtual |
Dump LR1121-specific debug info.
Reimplemented from esphome::home_io_control::RadioDriver.
Definition at line 299 of file radio_lr1121.cpp.
|
inlinenodiscardoverridevirtual |
Per-channel dwell while waiting for exchange responses (LR1121).
Reimplemented from esphome::home_io_control::RadioDriver.
Definition at line 267 of file radio_lr1121.h.
|
overrideprotectedvirtual |
Populate the RadioCaptureInfo from chip-specific telemetry (RSSI opcode, packet-status byte, and IRQ-word-width narrowing all differ per chip).
Note: RadioCaptureInfo::irq_status is uint16_t; the 32-bit IRQ word is mapped down by taking bits [2..10] and shifting right by 2 (design §3.2 "IRQ-width note").
Implements esphome::home_io_control::SoftPhyDriverBase.
Definition at line 227 of file radio_lr1121.cpp.
|
protected |
Read device error flags (for diagnostics only — see dump_debug()).
Definition at line 209 of file radio_lr1121.cpp.
|
overrideprotectedvirtual |
Read the chip-reported RX length and buffer offset (raw, before any clamping).
Implements esphome::home_io_control::SoftPhyDriverBase.
Definition at line 257 of file radio_lr1121.cpp.
|
staticprotected |
IRQ pin (DIO9) ISR — sets dio_fired flag. Runs in interrupt context.
Definition at line 275 of file radio_lr1121.cpp.
|
inlinenodiscardoverridevirtual |
TX→RX turnaround capability (LR1121): slow, same as SX1262.
See RadioSX1262::has_fast_tx_rx_turnaround for the rationale — the LR1121 needs the same standby/settle cycle between TX and RX.
Implements esphome::home_io_control::RadioDriver.
Definition at line 280 of file radio_lr1121.h.
|
overridevirtual |
Initialize the radio hardware. Returns true on success.
Implements esphome::home_io_control::RadioDriver.
Definition at line 279 of file radio_lr1121.cpp.
|
inlinenodiscardoverridevirtual |
Returns true if the radio failed to initialize or encountered a fatal error.
Implements esphome::home_io_control::RadioDriver.
Definition at line 285 of file radio_lr1121.h.
|
protected |
Log a warning if the most recently observed Stat1 command-status byte indicates the chip rejected the previous command (FAIL/PERR — see radio_lr1121.h §4.4).
Definition at line 85 of file radio_lr1121.cpp.
|
inlinenodiscardoverrideprotectedvirtual |
Implements esphome::home_io_control::SoftPhyDriverBase.
Definition at line 381 of file radio_lr1121.h.
|
protected |
Read from the LR1121 RX buffer at a given offset (as reported by GetRxBufferStatus).
Definition at line 132 of file radio_lr1121.cpp.
|
protected |
Read-type command: write transaction, wait BUSY, then a second NSS cycle clocks out a Stat1 status byte followed by out_len response bytes.
| opcode | LR1121 16-bit opcode. |
| params | Pointer to request parameter buffer (may be nullptr). |
| params_len | Request parameter length. |
| out | Output buffer for the response bytes (excludes Stat1). |
| out_len | Number of response bytes to read. |
Definition at line 69 of file radio_lr1121.cpp.
|
overrideprotectedvirtual |
Read the raw IRQ status word from the radio.
Virtual to allow test doubles (both concrete drivers' tests override this).
Reads the raw 32-bit IRQ status word from the radio (via GetStatus).
Implements esphome::home_io_control::SoftPhyDriverBase.
Definition at line 137 of file radio_lr1121.cpp.
|
overrideprotectedvirtual |
Read the single raw RSSI byte (chip-specific opcode); formula is shared, see read_rssi.
Implements esphome::home_io_control::SoftPhyDriverBase.
Definition at line 251 of file radio_lr1121.cpp.
|
inlineoverrideprotectedvirtual |
Read len bytes from the RX buffer starting at offset.
Implements esphome::home_io_control::SoftPhyDriverBase.
Definition at line 394 of file radio_lr1121.h.
|
inlinenodiscardoverrideprotectedvirtual |
Implements esphome::home_io_control::SoftPhyDriverBase.
Definition at line 377 of file radio_lr1121.h.
|
overrideprotectedvirtual |
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().
Plain Hz, 32-bit — no PLL-step conversion needed on this chip.
Implements esphome::home_io_control::SoftPhyDriverBase.
Definition at line 462 of file radio_lr1121.cpp.
|
overridevirtual |
Switch to continuous receive mode.
Implements esphome::home_io_control::RadioDriver.
Definition at line 452 of file radio_lr1121.cpp.
|
overridevirtual |
Switch to standby mode.
Implements esphome::home_io_control::RadioDriver.
Definition at line 447 of file radio_lr1121.cpp.
|
protected |
Configure GFSK packet parameters (preamble, payload length, CRC).
Definition at line 151 of file radio_lr1121.cpp.
|
protected |
Apply the RX bandwidth selector and rewrite the modulation parameters.
Definition at line 473 of file radio_lr1121.cpp.
|
overrideprotectedvirtual |
Configure RX-specific packet parameters (preamble detector length, fixed probe length).
Implements esphome::home_io_control::SoftPhyDriverBase.
Definition at line 174 of file radio_lr1121.cpp.
|
inlineoverrideprotectedvirtual |
Configure TX packet parameters for one outgoing UART-encoded frame.
| preamble_len | Preamble length in symbols, from the caller's RadioTxConfig. |
| payload_len | UART-encoded payload length in bytes. |
Implements esphome::home_io_control::SoftPhyDriverBase.
Definition at line 349 of file radio_lr1121.h.
|
overrideprotectedvirtual |
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.
Implements esphome::home_io_control::SoftPhyDriverBase.
Definition at line 265 of file radio_lr1121.cpp.
|
inlinenodiscardoverrideprotectedvirtual |
Implements esphome::home_io_control::SoftPhyDriverBase.
Definition at line 375 of file radio_lr1121.h.
|
inlinenodiscardoverrideprotectedvirtual |
Implements esphome::home_io_control::SoftPhyDriverBase.
Definition at line 379 of file radio_lr1121.h.
|
protected |
Wait until BUSY pin is low before any SPI transaction.
Definition at line 38 of file radio_lr1121.cpp.
|
protected |
Write into the LR1121 TX buffer (always from the chip's internal write pointer, which resets to the buffer base for a fresh WriteBuffer sequence — unlike SX1262 there is no separate offset parameter here; see design §3.2 "SPI transport").
Definition at line 128 of file radio_lr1121.cpp.
|
protected |
Write-only command: opcode + params, single NSS cycle.
| opcode | LR1121 16-bit opcode. |
| params | Pointer to parameter buffer (may be nullptr). |
| len | Parameter length. |
Definition at line 56 of file radio_lr1121.cpp.
|
protected |
Apply the runtime bandwidth setting to the LR1121 modulation parameters.
Definition at line 182 of file radio_lr1121.cpp.
|
protected |
WriteRegMemMask32: read-modify-write a 32-bit register through mask/value.
Used by the vendor errata workarounds below; opcode 0x010C (design analysis §4.1/§4.2).
Definition at line 100 of file radio_lr1121.cpp.
|
inlineoverrideprotectedvirtual |
Write the UART-encoded TX payload into the chip's TX buffer.
Implements esphome::home_io_control::SoftPhyDriverBase.
Definition at line 390 of file radio_lr1121.h.