Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
radio_lr1121.h File Reference

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

#include "radio_soft_phy_driver_base.h"
#include "esphome/core/hal.h"
Include dependency graph for radio_lr1121.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

class  esphome::home_io_control::RadioLR1121
 LR1121 implementation of RadioDriver. More...

Namespaces

namespace  esphome
namespace  esphome::home_io_control

Functions

constexpr bool esphome::home_io_control::lr1121_firmware_is_outdated (uint8_t fw_major, uint8_t fw_minor)
 Pure comparison against the known-latest constants above — no I/O, host-testable.

Variables

static constexpr uint16_t esphome::home_io_control::LR1121_CMD_GET_STATUS = 0x0100
 cross-checked
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_GET_VERSION = 0x0101
 cross-checked
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_GET_ERRORS = 0x010D
 cross-checked (2-byte response)
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_CLEAR_ERRORS
 hardware-verified (called on every init/RX cycle, never rejected — see log_command_status_())
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_WRITE_BUFFER = 0x0109
 cross-checked
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_READ_BUFFER = 0x010A
 cross-checked
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_WRITE_REG_MEM_MASK32
 cross-checked (Semtech SWDR001 lr11xx_radio.c / RadioLib LR11x0_commands.h)
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_CALIBRATE = 0x010F
 cross-checked
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_CALIBRATE_IMAGE = 0x0111
 cross-checked (RadioLib calibrateImageRejection)
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_SET_DIO_AS_RF_SWITCH = 0x0112
 cross-checked
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_SET_DIO_IRQ_PARAMS = 0x0113
 cross-checked
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_CLEAR_IRQ = 0x0114
 cross-checked
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_SET_TCXO_MODE = 0x0117
 cross-checked
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_SET_STANDBY = 0x011C
 cross-checked
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_GET_RX_BUFFER_STATUS = 0x0203
 cross-checked
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_GET_PKT_STATUS
 cross-checked (Semtech SWDR001 lr11xx_radio.c :: lr11xx_radio_get_gfsk_pkt_status — 0 request params, 4-byte GFSK response: [rssi_sync, rssi_avg, rx_len, status_flags], rssi_sync/avg both decode via -(raw>>1) dBm, same formula as LR1121_CMD_GET_RSSI_INST)
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_GET_RSSI_INST = 0x0205
 cross-checked
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_SET_GFSK_SYNC_WORD = 0x0206
 cross-checked
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_SET_RX = 0x0209
 cross-checked
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_SET_TX = 0x020A
 cross-checked
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_SET_RF_FREQUENCY = 0x020B
 cross-checked
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_SET_PACKET_TYPE = 0x020E
 cross-checked
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_SET_MODULATION_PARAMS = 0x020F
 cross-checked
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_SET_PACKET_PARAMS = 0x0210
 cross-checked
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_SET_TX_PARAMS = 0x0211
 cross-checked
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_SET_RX_TX_FALLBACK_MODE = 0x0213
 cross-checked
static constexpr uint16_t esphome::home_io_control::LR1121_CMD_SET_PA_CONFIG = 0x0215
 cross-checked
static constexpr uint32_t esphome::home_io_control::LR1121_IRQ_TX_DONE = 1UL << 2
static constexpr uint32_t esphome::home_io_control::LR1121_IRQ_RX_DONE = 1UL << 3
static constexpr uint32_t esphome::home_io_control::LR1121_IRQ_PREAMBLE_DETECTED = 1UL << 4
static constexpr uint32_t esphome::home_io_control::LR1121_IRQ_SYNC_WORD_VALID = 1UL << 5
static constexpr uint32_t esphome::home_io_control::LR1121_IRQ_CRC_ERR = 1UL << 7
static constexpr uint32_t esphome::home_io_control::LR1121_IRQ_TIMEOUT = 1UL << 10
static constexpr uint32_t esphome::home_io_control::LR1121_IRQ_ACTIVITY_MASK
 IRQ bits that represent a terminal radio event — a frame finished decoding, an outbound frame completed, or the chip gave up on its own.
static constexpr uint32_t esphome::home_io_control::LR1121_IRQ_DIO_ENABLE_MASK
 DIO-routed IRQ enable mask: TxDone|RxDone|PreambleDetected|SyncWordValid|Timeout (design implementation §Step 2, item 2 — deliberately excludes CrcErr from the DIO-routed set, unlike SX1262; CrcErr is still visible in the raw status word for capture diagnostics).
static constexpr uint8_t esphome::home_io_control::LR1121_DEVICE_TYPE = 0x03
 cross-checked (design §1.2 "Identity" row)
static constexpr uint8_t esphome::home_io_control::LR1121_KNOWN_LATEST_FW_MAJOR = 0x01
 Newest LR1121 transceiver firmware known at the time this file was last updated, per the version-numbered filenames and CHANGELOG.md at https://github.com/Lora-net/radio_firmware_images/tree/master/lr1121/transceiver — the same two bytes GetVersion reports as fw_major/fw_minor (e.g.
static constexpr uint8_t esphome::home_io_control::LR1121_KNOWN_LATEST_FW_MINOR = 0x04
static constexpr uint8_t esphome::home_io_control::LR1121_PACKET_TYPE_GFSK = 0x01
 cross-checked (design §3.2 step 5)
static constexpr uint8_t esphome::home_io_control::LR1121_GFSK_CRC_OFF = 0x01
 cross-checked (same encoding as SX126x)
static constexpr uint8_t esphome::home_io_control::LR1121_GFSK_PACKET_FIXED_LENGTH = 0x00
 cross-checked (same encoding as SX126x)
static constexpr uint8_t esphome::home_io_control::LR1121_PREAMBLE_DETECTOR_16_BIT = 0x05
 Preamble detector length selector: 16 bits.
static constexpr uint8_t esphome::home_io_control::LR1121_SYNC_WORD_PARAM_24_BITS = 0x18
 Sync word length: 24 bits, encoded as a literal bit count — cross-checked, identical encoding to SX1262's SX1262_SYNC_WORD_PARAM_24_BITS.
static constexpr uint8_t esphome::home_io_control::LR1121_CALIBRATE_ALL_BLOCKS = 0x3F
 Calibrate "all blocks" bitmask.
static constexpr uint8_t esphome::home_io_control::LR1121_FALLBACK_STDBY_XOSC = 0x02
 SetRxTxFallbackMode value for STDBY_XOSC.
static constexpr uint32_t esphome::home_io_control::LR1121_REG_HIGH_ACP_WORKAROUND_ADDR = 0x00F30054
 High-ACP (adjacent channel power) TX-quality erratum: clear bit 30 of this register before every SetRx/SetTx.
static constexpr uint32_t esphome::home_io_control::LR1121_REG_HIGH_ACP_WORKAROUND_MASK = 1UL << 30
static constexpr uint32_t esphome::home_io_control::LR1121_REG_HIGH_ACP_WORKAROUND_VALUE = 0x00000000
static constexpr uint32_t esphome::home_io_control::LR1121_REG_GFSK_WORKAROUND_1_ADDR = 0x00F20344
 GFSK modulation workaround register trio, standard (non-0.6/1.2kbps) values for our 38.4kbps config — applied after every modulation-params write, mirroring RadioLib's workaroundGFSK() ("always the first step, even when resetting" per its own comment on the first write).
static constexpr uint32_t esphome::home_io_control::LR1121_REG_GFSK_WORKAROUND_1_MASK = 0x00000030
static constexpr uint32_t esphome::home_io_control::LR1121_REG_GFSK_WORKAROUND_1_VALUE = 0x00000010
static constexpr uint32_t esphome::home_io_control::LR1121_REG_GFSK_WORKAROUND_2_ADDR = 0x00F20348
static constexpr uint32_t esphome::home_io_control::LR1121_REG_GFSK_WORKAROUND_2_MASK = 0x00000005
static constexpr uint32_t esphome::home_io_control::LR1121_REG_GFSK_WORKAROUND_2_VALUE = 0x00000001
static constexpr uint32_t esphome::home_io_control::LR1121_REG_GFSK_WORKAROUND_3_ADDR = 0x00F20244
static constexpr uint32_t esphome::home_io_control::LR1121_REG_GFSK_WORKAROUND_3_MASK = 0x0001FF03
static constexpr uint32_t esphome::home_io_control::LR1121_REG_GFSK_WORKAROUND_3_VALUE = 0x00000A01
static constexpr uint8_t esphome::home_io_control::LR1121_IMAGE_CAL_FREQ1 = 0xD7
 Banded image calibration for 868.25-869.85MHz +/-4MHz (~860-876MHz), matching RadioLib's setFrequency() margin.
static constexpr uint8_t esphome::home_io_control::LR1121_IMAGE_CAL_FREQ2 = 0xDB
static constexpr uint8_t esphome::home_io_control::LR1121_RFSWITCH_ENABLE_DIO5_DIO6 = 0x03
 DIO5 + DIO6 are switch pins.
static constexpr uint8_t esphome::home_io_control::LR1121_RFSWITCH_STANDBY = 0x00
 Both low.
static constexpr uint8_t esphome::home_io_control::LR1121_RFSWITCH_RX = 0x01
 DIO5 high.
static constexpr uint8_t esphome::home_io_control::LR1121_RFSWITCH_TX = 0x02
 DIO6 high (both LP and HP PA).
static constexpr uint8_t esphome::home_io_control::LR1121_RFSWITCH_TX_HP = 0x02
 Same as TX (LP PA only used today).
static constexpr uint8_t esphome::home_io_control::LR1121_RFSWITCH_TX_HF = 0x00
 2.4GHz path unused; both low.
static constexpr uint8_t esphome::home_io_control::LR1121_RFSWITCH_GNSS = 0x00
 Unused; both low.
static constexpr uint8_t esphome::home_io_control::LR1121_RFSWITCH_WIFI = 0x00
 Unused; both low.
static constexpr uint8_t esphome::home_io_control::LR1121_TCXO_STARTUP_DELAY_TICKS_MSB = 0x00
 LR1121 TCXO voltage on the T3-S3 board — 3.0V, confirmed on real hardware.
static constexpr uint8_t esphome::home_io_control::LR1121_TCXO_STARTUP_DELAY_TICKS_MID = 0x01
static constexpr uint8_t esphome::home_io_control::LR1121_TCXO_STARTUP_DELAY_TICKS_LSB = 0x40
 0x140 ticks at 30.52us/tick (32.768kHz RTC) is ~9.8ms, not the ~5ms the SX1262-derived comment used to claim (that chip's tick base differs) — harmless either way (longer startup is safe).
static constexpr int32_t esphome::home_io_control::LR1121_EXCHANGE_RESPONSE_WAIT_SLICE_MS = 600
 LR1121-specific per-channel dwell while waiting for authenticated exchange responses.

Detailed Description

LR1121 radio driver for IO-Homecontrol.

Implements the RadioDriver interface for the Semtech LR1121 transceiver on the LilyGo T3-S3 board. Like the SX1262, the LR1121 has no hardware equivalent of the SX1276's IoHomeOn framing, so this driver reuses the shared software PHY (radio_soft_phy.h) wholesale: software UART bit-encoding on TX, a UART-decode probe with CRC-CCITT validation on RX, fixed-length GFSK packets, software CRC. This is a re-plumbed RadioSX1262 with a different SPI command set, not a new bring-up from first principles (design doc §1.2). The IRQ-driven RX/TX orchestration this driver shares with RadioSX1262 lives in SoftPhyDriverBase (see radio_soft_phy_driver_base.h).

The chip-level difference from the SX1262 that actually changes the driver's shape is the SPI transport: the LR1121 uses 16-bit opcodes and a two-transaction command/response protocol (write opcode+params, wait BUSY, then a second transaction clocks out a status byte + response), instead of the SX1262's single-transaction opcode+NOP-then-data pattern.

Hardware bring-up (2026-08) confirmed this driver end-to-end against a real Somfy Sunea IO awning motor: authenticated open/close/stop exchanges complete reliably, with correct position/state feedback decoded from the device's real responses. Every constant below is therefore hardware-verified unless its own comment says otherwise.

Definition in file radio_lr1121.h.