|
Home IO Control
ESPHome add-on for IO-Homecontrol devices
|
Abstract radio driver for IO-Homecontrol. More...
#include <radio_interface.h>
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} |
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.
|
inlineexplicit |
Definition at line 158 of file radio_interface.h.
|
virtualdefault |
|
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.
| tuning | Current 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.
|
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.
|
pure virtual |
Non-blocking check for a received packet.
Called from loop(). Returns true if a packet was read into packet. Contract:
Implemented in esphome::home_io_control::RadioSX1276, and esphome::home_io_control::SoftPhyDriverBase.
|
nodiscardpure virtual |
Get a human‑readable chip name.
Implemented in esphome::home_io_control::RadioLR1121, esphome::home_io_control::RadioSX1262, and esphome::home_io_control::RadioSX1276.
|
inline |
Definition at line 348 of file radio_interface.h.
|
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.
|
inlineprotected |
Drop the holdoff: the reception ended, was delivered, or was torn down deliberately.
Definition at line 390 of file radio_interface.h.
|
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).
Reimplemented in esphome::home_io_control::SoftPhyDriverBase.
Definition at line 227 of file radio_interface.h.
|
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.
|
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.
|
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.
| reason | String literal (stored by pointer, not copied). |
Definition at line 427 of file radio_interface.h.
|
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.
|
inlinenodiscard |
Get the current RF frequency.
Definition at line 300 of file radio_interface.h.
|
inlinenodiscard |
Get the most recent radio capture info.
Definition at line 303 of file radio_interface.h.
|
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.
Implemented in esphome::home_io_control::RadioLR1121, esphome::home_io_control::RadioSX1262, and esphome::home_io_control::RadioSX1276.
|
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.
| tuning | Current tuning configuration. |
Implemented in esphome::home_io_control::RadioLR1121, esphome::home_io_control::RadioSX1262, and esphome::home_io_control::RadioSX1276.
|
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.
|
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.
|
inlinenodiscardvirtual |
Returns true if the radio failed to initialize or encountered a fatal error.
Definition at line 276 of file radio_interface.h.
|
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.
|
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.
|
inline |
Definition at line 358 of file radio_interface.h.
|
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.
|
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.
| blocking_wait | if this was a blocking receive. |
| freq_hz | RF frequency of the capture. |
| rssi_dbm | Received signal strength. |
| raw | Pointer to raw bytes (may be nullptr). |
| raw_len | Length of raw buffer. |
| frame | Pointer to parsed frame bytes (may be nullptr). |
| frame_len | Length of parsed frame. |
Definition at line 406 of file radio_interface.h.
|
inlineprotected |
Common preamble for blocking receive: clear diagnostics and output packet.
| packet | Output packet buffer to zero and prepare. |
Definition at line 370 of file radio_interface.h.
|
inlineprotected |
Common preamble for non‑blocking receive: clear diagnostics, output packet, and DIO latch.
| packet | Output packet buffer to zero and prepare. |
Definition at line 377 of file radio_interface.h.
|
pure virtual |
Read instantaneous RSSI (in dBm) while in RX mode.
Used for listen-before-talk (LBT) carrier sense before transmitting.
Implemented in esphome::home_io_control::RadioSX1276, and esphome::home_io_control::SoftPhyDriverBase.
|
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.
|
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.
|
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).
Reimplemented in esphome::home_io_control::RadioSX1276, and esphome::home_io_control::SoftPhyDriverBase.
Definition at line 210 of file radio_interface.h.
|
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.
|
pure virtual |
Switch to continuous receive mode.
Implemented in esphome::home_io_control::RadioLR1121, esphome::home_io_control::RadioSX1262, and esphome::home_io_control::RadioSX1276.
|
pure virtual |
Switch to standby mode.
Implemented in esphome::home_io_control::RadioLR1121, esphome::home_io_control::RadioSX1262, and esphome::home_io_control::RadioSX1276.
|
pure virtual |
Wait (blocking) for a packet with timeout.
Returns true if a packet was received. Contract:
Implemented in esphome::home_io_control::RadioSX1276, and esphome::home_io_control::SoftPhyDriverBase.
|
protected |
Definition at line 433 of file radio_interface.h.
|
protected |
Definition at line 446 of file radio_interface.h.
|
protected |
Latched by fail_; see is_failed.
Definition at line 437 of file radio_interface.h.
|
protected |
First failure cause, see failure_reason.
Definition at line 438 of file radio_interface.h.
|
protected |
Definition at line 434 of file radio_interface.h.
|
protected |
Definition at line 435 of file radio_interface.h.
|
protected |
Idle-hop holdoff latch — see reception_in_progress().
Definition at line 440 of file radio_interface.h.
|
protected |
micros() timestamp the holdoff was last (re-)armed at.
Definition at line 441 of file radio_interface.h.