Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
radio_sx1276.h
Go to the documentation of this file.
1#pragma once
2
3/// @file radio_sx1276.h
4/// @brief SX1276 radio driver for IO-Homecontrol.
5/// @ingroup hioc_radio
6///
7/// Implements the RadioDriver interface for the Semtech SX1276 transceiver.
8/// Configures the chip in FSK mode with the IoHomeOn hardware feature that
9/// handles CRC and packet framing specific to the IO-Homecontrol protocol.
10
11#include "radio_interface.h"
12#include "proto_timing.h" // LONG_PREAMBLE
13#include "radio_soft_phy.h" // io868_tx_air_time_us(), soft_phy_air_time_us()
14#include "esphome/core/hal.h"
15
16namespace esphome {
17namespace home_io_control {
18
19/// `pa_pin` value that routes the output through the PA_BOOST pin; any other value selects the RFO
20/// pin. Doubles as the PaSelect bit of REG_PA_CONFIG.
21static constexpr uint8_t SX1276_PA_SELECT_PA_BOOST = 0x80;
22
23/// Wait after retuning to the TX channel before the clear-channel RSSI reading. The fast-hop PLL
24/// relocks in tens of µs, and with RssiSmoothing = 8 samples at the 50 kHz RX bandwidth one RSSI
25/// update takes about 40 µs; 250 µs covers both with margin and costs nothing next to a preamble.
26/// \todo Confirm on the bench (Heltec V2): time the retune and compare the reading against one
27/// taken after a long dwell on the same channel.
28static constexpr uint32_t SX1276_CCA_SETTLE_US = 250;
29
30// ============================================================================
31// SX1276 Register Addresses (subset needed for IO-Homecontrol)
32// Full register map: see Semtech SX1276 datasheet or sx1276Regs-Fsk.h
33// ============================================================================
34
35static constexpr uint8_t REG_FIFO = 0x00; ///< FIFO read/write access
36static constexpr uint8_t REG_OP_MODE = 0x01; ///< Operating mode (sleep/standby/tx/rx)
37static constexpr uint8_t REG_BITRATE_MSB = 0x02; ///< Bit rate MSB = FXOSC / bitrate
38static constexpr uint8_t REG_BITRATE_LSB = 0x03;
39static constexpr uint8_t REG_FDEV_MSB = 0x04; ///< Frequency deviation MSB
40static constexpr uint8_t REG_FDEV_LSB = 0x05;
41static constexpr uint8_t REG_FRF_MSB = 0x06; ///< Carrier frequency MSB (freq = FRF * FXOSC / 2^19)
42static constexpr uint8_t REG_FRF_MID = 0x07;
43static constexpr uint8_t REG_FRF_LSB = 0x08;
44static constexpr uint8_t REG_PA_CONFIG = 0x09; ///< Power amplifier config (pin select + power level)
45static constexpr uint8_t REG_PA_RAMP = 0x0A; ///< PA ramp time and modulation shaping
46static constexpr uint8_t REG_LNA = 0x0C; ///< Low noise amplifier gain and boost
47static constexpr uint8_t REG_RX_CONFIG = 0x0D; ///< Receiver configuration (AFC, AGC, trigger)
48static constexpr uint8_t REG_RSSI_CONFIG = 0x0E; ///< RSSI smoothing
49static constexpr uint8_t REG_RX_BW = 0x12; ///< Receiver bandwidth
50static constexpr uint8_t REG_AFC_BW = 0x13; ///< AFC bandwidth
51static constexpr uint8_t REG_AFC_FEI = 0x1A; ///< AFC auto clear
52static constexpr uint8_t REG_PREAMBLE_DETECT = 0x1F; ///< Preamble detector config
53static constexpr uint8_t REG_OSC = 0x24; ///< Oscillator / clock output
54static constexpr uint8_t REG_RSSI_VALUE = 0x11; ///< Instant RSSI value in FSK mode
55static constexpr uint8_t REG_PREAMBLE_MSB = 0x25; ///< TX preamble length MSB
56static constexpr uint8_t REG_PREAMBLE_LSB = 0x26;
57static constexpr uint8_t REG_SYNC_CONFIG = 0x27; ///< Sync word config (size, polarity, enable)
58static constexpr uint8_t REG_SYNC_VALUE1 = 0x28; ///< Sync word byte 1 (registers 0x28-0x2F for bytes 1-8)
59static constexpr uint8_t REG_PACKET_CONFIG1 = 0x30; ///< Packet format, CRC, encoding
60static constexpr uint8_t REG_PACKET_CONFIG2 = 0x31; ///< Packet mode, IoHomeOn, PowerFrame
61static constexpr uint8_t REG_PAYLOAD_LENGTH = 0x32; ///< Max payload length
62static constexpr uint8_t REG_FIFO_THRESH = 0x35; ///< FIFO threshold for TX start condition
63static constexpr uint8_t REG_IRQ_FLAGS1 = 0x3E; ///< IRQ flags: mode ready, preamble detect, etc.
64static constexpr uint8_t REG_IRQ_FLAGS2 = 0x3F; ///< IRQ flags: FIFO full/empty, payload ready, CRC ok
65static constexpr uint8_t REG_DIO_MAPPING1 = 0x40; ///< DIO0-DIO3 pin mapping
66static constexpr uint8_t REG_DIO_MAPPING2 = 0x41; ///< DIO4-DIO5 pin mapping
67static constexpr uint8_t REG_VERSION = 0x42; ///< Chip version (should read 0x12 for SX1276)
68static constexpr uint8_t REG_PLLHOP = 0x44; ///< PLL hop: fast frequency change without standby
69static constexpr uint8_t REG_IMAGE_CAL = 0x3B; ///< Image calibration
70
71// SX1276 operating modes (bits [2:0] of REG_OP_MODE)
72static constexpr uint8_t MODE_SLEEP = 0x00;
73static constexpr uint8_t MODE_STDBY = 0x01;
74static constexpr uint8_t MODE_TX = 0x03;
75static constexpr uint8_t MODE_RX = 0x05;
76static constexpr uint8_t MODE_MASK = 0x07;
77
78/// REG_RX_CONFIG as configured: RestartRxOnCollision | AfcAutoOn | AgcAutoOn | RxTrigger=PreambleDetect.
79static constexpr uint8_t RX_CONFIG_VALUE = 0x9E;
80/// REG_RX_CONFIG bit 5, RestartRxWithPllLock: restarts the receiver chain after a frequency change,
81/// which also clears PreambleDetect and re-arms AGC/AFC for the new channel.
82static constexpr uint8_t RX_CONFIG_RESTART_RX_WITH_PLL_LOCK = 0x20;
83
84/// How long reception_in_progress() holds the idle hop on a channel once PreambleDetect is set:
85/// the longest start preamble (LONG_PREAMBLE, 1024 bytes = 213 ms at 38400 bps) plus margin, so
86/// the sync word at the end of a wake-up preamble arrives while the receiver is still there.
87/// Also the bound on a preamble detection with no frame behind it (noise): after it the hop goes
88/// on, and its receiver restart clears the flag.
89static constexpr uint32_t SX1276_PREAMBLE_HOLD_US = 250000;
90static_assert(SX1276_PREAMBLE_HOLD_US > soft_phy_air_time_us(LONG_PREAMBLE),
91 "the preamble hold must outlast the longest start preamble");
92
93/// SX1276 crystal oscillator frequency (32 MHz). Used to calculate register values
94/// for bitrate, frequency deviation, and carrier frequency.
95static constexpr uint32_t FXOSC = 32000000U;
96
97// ============================================================================
98// SX1276 Radio Driver
99// ============================================================================
100
101/// @brief SX1276 implementation of RadioDriver.
102/// @ingroup hioc_radio
103///
104/// Manages the SX1276 via SPI using the SpiAccess interface. Configures the chip
105/// in FSK mode with IoHomeOn for hardware CRC and IO‑Homecontrol packet framing.
106class RadioSX1276 : public RadioDriver {
107 public:
108 RadioSX1276(SpiAccess *spi, InternalGPIOPin *rst_pin, InternalGPIOPin *dio0_pin, InternalGPIOPin *dio4_pin,
109 uint8_t tx_power, uint8_t pa_pin)
110 : RadioDriver(rst_pin),
111 spi_(spi),
112 dio0_pin_(dio0_pin),
113 dio4_pin_(dio4_pin),
114 tx_power_(tx_power),
115 pa_pin_(pa_pin) {}
116
117 /// @brief Initialize the SX1276 radio (reset, calibrate, configure registers).
118 /// @return true on success; false on failure (e.g., version check).
119 bool init() override;
120 /// @brief Transmit a frame with specified frequency and preamble.
121 /// @param data Pointer to payload bytes.
122 /// @param len Payload length.
123 /// @param tx_config Transmission config (frequency, preamble).
124 /// @return true if transmit succeeded.
125 TxResult send_packet(const uint8_t *data, uint8_t len, const RadioTxConfig &tx_config) override;
126 /// @brief Blocking wait for a packet with timeout.
127 /// @param packet Output: received packet (freq, len, data).
128 /// @param timeout_ms Maximum time to wait.
129 /// @return true if a packet was received; false on timeout.
130 bool wait_for_packet(RadioRxPacket &packet, uint32_t timeout_ms) override;
131 /// @brief Non‑blocking check for a received packet (called from loop).
132 /// @param packet Output: received packet if any.
133 /// @return true if a packet was read; false if no interrupt fired.
134 bool check_for_packet(RadioRxPacket &packet) override;
135 /// @brief Change RF frequency using fast hop (no standby needed).
136 /// @param freq_hz New frequency in Hz.
137 void change_frequency(uint32_t freq_hz) override;
138 /// @brief Read instantaneous RSSI (dBm) while in RX mode (used for LBT).
139 /// @return RSSI in dBm (negative).
140 int16_t read_rssi() override;
141 /// @copydoc RadioDriver::is_sync_detected
142 bool is_sync_detected() override;
143 /// @copydoc RadioDriver::is_preamble_detected
144 bool is_preamble_detected() override;
145 /// @copydoc RadioDriver::reception_in_progress
146 ///
147 /// Read live from REG_IRQ_FLAGS1 rather than recorded from check_for_packet(): DIO0 carries
148 /// PayloadReady only, so this driver's check_for_packet() returns before reading any register
149 /// while a frame is still arriving and has nothing to record (issue #81).
150 ///
151 /// Holds on SyncAddressMatch (the frame itself, bounded by RX_HOP_HOLDOFF_US) and on
152 /// PreambleDetect (a start preamble whose sync word is still to come, bounded by
153 /// SX1276_PREAMBLE_HOLD_US). The preamble hold is meaningful only because change_frequency()
154 /// restarts the receiver, which clears the flag; without that it latches on the first preamble
155 /// (or noise) and stays set across hops.
156 [[nodiscard]] bool reception_in_progress() override;
157 /// @brief Per-channel dwell for a rotating listen (SX1276).
158 ///
159 /// The SX1276 supports FastHop (PllHop), so frequency changes need no standby transition and a
160 /// short slice is enough. Governs discovery and the broadcast roll-call alike (see @ref
161 /// RadioDriver::hop_dwell_ms). The value comes from the user-facing
162 /// `sx1276_discovery_hop_slice_ms` tuning field.
163 [[nodiscard]] uint16_t hop_dwell_ms(const TuningConfig &tuning) const override {
164 return tuning.sx1276_discovery_hop_slice_ms;
165 }
166 /// @brief TX→RX turnaround capability (SX1276): fast.
167 ///
168 /// The IoHomeOn TX path returns to RX quickly enough that immediate replies
169 /// (including the pairing key-confirm 0x33) are caught through the standard
170 /// exchange wait — validated by real-hardware pairing on this driver.
171 [[nodiscard]] bool has_fast_tx_rx_turnaround() const override { return true; }
172 /// @brief Transmit time (SX1276): the preamble, sync word and the IoHomeOn-coded frame at the
173 /// protocol line rate — the same waveform the software PHY produces.
174 [[nodiscard]] uint32_t tx_air_time_us(uint8_t len, const RadioTxConfig &cfg) const override {
175 return io868_tx_air_time_us(cfg.preamble_len, len);
176 }
177 // `SX1276_RESPONSE_PREAMBLE` below is a code span, not \ref: doxygen 1.18 can't resolve \ref
178 // to it in a whole-project build (details in proto_sizes.h). Autolinking still links it.
179 /// @brief Preamble for response/continuation frames (SX1276).
180 ///
181 /// Runtime-tunable; the default and its hardware rationale are documented at
182 /// `SX1276_RESPONSE_PREAMBLE`.
183 [[nodiscard]] uint16_t response_preamble() const override { return this->response_preamble_; }
184 /// @brief Apply SX1276 runtime tuning: RX bandwidth and response preamble.
185 void apply_tuning(const TuningConfig &tuning) override {
188 }
189 /// @brief Switch radio into continuous receive mode.
190 void set_mode_rx() override;
191 /// @brief Switch radio into standby mode.
192 void set_mode_standby() override;
193 /// @copydoc RadioDriver::chip_name
194 [[nodiscard]] const char *chip_name() const override { return "sx1276"; }
195 /// @brief Dump radio‑specific debug info to log.
196 void dump_debug() override;
197
198 protected:
199 // --- Tuning helpers (applied via apply_tuning) ---
200 /// Apply the RX bandwidth selector to REG_RX_BW and REG_AFC_BW.
201 /// @param bandwidth Bandwidth selector enum (register byte written verbatim).
202 void set_rx_bandwidth_(SX1276RxBandwidth bandwidth);
203 /// Set the preamble length used for response/continuation frames within an exchange.
204 /// @param preamble Preamble length in bytes.
205 void set_response_preamble_(uint16_t preamble) { this->response_preamble_ = preamble; }
206
207 /// The PreambleDetect half of reception_in_progress(): true while a fresh preamble detection is
208 /// younger than SX1276_PREAMBLE_HOLD_US.
209 bool preamble_hold_();
210
211 // --- SPI register access ---
212 /// Read an SX1276 register over SPI.
213 /// @param reg Register address (7 bits, MSB clear for read).
214 /// @return Register value.
215 uint8_t read_register_(uint8_t reg);
216 /// Write an SX1276 register over SPI.
217 /// @param reg Register address (7 bits, MSB set for write).
218 /// @param value Byte to write.
219 void write_register_(uint8_t reg, uint8_t value);
220
221 // --- Radio hardware control ---
222 /// Set the operating mode (sleep/standby/tx/rx) and wait for mode completion.
223 /// @param mode One of MODE_SLEEP, MODE_STDBY, MODE_TX, or MODE_RX.
224 void set_mode_(uint8_t mode);
225 /// Perform full radio configuration (called during init).
226 void configure_radio_();
227 /// Run image calibration routine (required after reset).
228 void run_image_cal_();
229 /// Wait until FIFO payload is ready (polling for TX/RX readiness).
230 /// @param timeout_ms How long to wait.
231 /// @param saw_dio0 Output: true if DIO0 fired.
232 /// @param irq1 Output: IRQ flags 1.
233 /// @param irq2 Output: IRQ flags 2.
234 /// @return true if payload ready before timeout; false otherwise.
235 bool poll_until_payload_ready_(uint32_t timeout_ms, bool &saw_dio0, uint8_t &irq1, uint8_t &irq2);
236 /// Read a packet from the RX FIFO into a buffer.
237 /// @param buf Output buffer.
238 /// @param buf_size Size of buf.
239 /// @return Number of bytes read.
240 uint8_t read_fifo_packet_(uint8_t *buf, uint8_t buf_size);
241 /// Populate last_capture_ from raw telemetry.
242 /// Note: `crc_error` is never set on this driver — in IoHomeOn mode the hardware
243 /// silently drops frames with a bad CRC before they reach the FIFO.
244 /// @param blocking_wait if this was a blocking receive.
245 /// @param irq1 IRQ flags 1.
246 /// @param irq2 IRQ flags 2.
247 /// @param rssi RSSI value.
248 /// @param raw Pointer to raw bytes (may be nullptr).
249 /// @param raw_len Length of raw buffer.
250 /// @param frame Pointer to parsed frame bytes (may be nullptr).
251 /// @param frame_len Length of parsed frame.
252 void fill_capture_info_(bool blocking_wait, uint8_t irq1, uint8_t irq2, uint8_t rssi, const uint8_t *raw,
253 uint8_t raw_len, const uint8_t *frame, uint8_t frame_len);
254
255 /// DIO0 ISR — sets dio_fired flag. Runs in interrupt context.
256 static void gpio_intr(RadioSX1276 *arg);
257
258 /// True when TX goes out through PA_BOOST rather than RFO; the PA config and the dump both key on it.
259 [[nodiscard]] bool uses_pa_boost_() const { return this->pa_pin_ == SX1276_PA_SELECT_PA_BOOST; }
260
262 InternalGPIOPin *dio0_pin_;
263 InternalGPIOPin *dio4_pin_;
264 uint8_t tx_power_;
265 uint8_t pa_pin_;
267 uint16_t response_preamble_{SX1276_RESPONSE_PREAMBLE}; ///< Runtime-tunable response preamble.
268 uint32_t sync_hold_since_us_{0}; ///< First-sighting timestamp for reception_in_progress()'s un-stick bound.
269 uint32_t preamble_hold_since_us_{0}; ///< First-sighting timestamp for reception_in_progress()'s preamble hold.
270};
271
272} // namespace home_io_control
273} // namespace esphome
RadioDriver(InternalGPIOPin *rst_pin=nullptr)
SX1276 implementation of RadioDriver.
void configure_radio_()
Perform full radio configuration (called during init).
uint32_t sync_hold_since_us_
First-sighting timestamp for reception_in_progress()'s un-stick bound.
int16_t read_rssi() override
Read instantaneous RSSI (dBm) while in RX mode (used for LBT).
bool wait_for_packet(RadioRxPacket &packet, uint32_t timeout_ms) override
Blocking wait for a packet with timeout.
bool has_fast_tx_rx_turnaround() const override
TX→RX turnaround capability (SX1276): fast.
void set_response_preamble_(uint16_t preamble)
Set the preamble length used for response/continuation frames within an exchange.
uint8_t read_register_(uint8_t reg)
Read an SX1276 register over SPI.
uint16_t hop_dwell_ms(const TuningConfig &tuning) const override
Per-channel dwell for a rotating listen (SX1276).
SX1276RxBandwidth rx_bandwidth_
Runtime-tunable RX bandwidth.
void fill_capture_info_(bool blocking_wait, uint8_t irq1, uint8_t irq2, uint8_t rssi, const uint8_t *raw, uint8_t raw_len, const uint8_t *frame, uint8_t frame_len)
Populate last_capture_ from raw telemetry.
uint16_t response_preamble_
Runtime-tunable response preamble.
void apply_tuning(const TuningConfig &tuning) override
Apply SX1276 runtime tuning: RX bandwidth and response preamble.
uint32_t preamble_hold_since_us_
First-sighting timestamp for reception_in_progress()'s preamble hold.
void set_rx_bandwidth_(SX1276RxBandwidth bandwidth)
Apply the RX bandwidth selector to REG_RX_BW and REG_AFC_BW.
void set_mode_(uint8_t mode)
Set the operating mode (sleep/standby/tx/rx) and wait for mode completion.
RadioSX1276(SpiAccess *spi, InternalGPIOPin *rst_pin, InternalGPIOPin *dio0_pin, InternalGPIOPin *dio4_pin, uint8_t tx_power, uint8_t pa_pin)
void set_mode_standby() override
Switch radio into standby mode.
static void gpio_intr(RadioSX1276 *arg)
DIO0 ISR — sets dio_fired flag. Runs in interrupt context.
bool poll_until_payload_ready_(uint32_t timeout_ms, bool &saw_dio0, uint8_t &irq1, uint8_t &irq2)
Wait until FIFO payload is ready (polling for TX/RX readiness).
void dump_debug() override
Dump radio‑specific debug info to log.
void change_frequency(uint32_t freq_hz) override
Change RF frequency using fast hop (no standby needed).
bool init() override
Initialize the SX1276 radio (reset, calibrate, configure registers).
bool reception_in_progress() override
True while a frame is arriving on the current channel and retuning would destroy it.
void write_register_(uint8_t reg, uint8_t value)
Write an SX1276 register over SPI.
const char * chip_name() const override
Get a human‑readable chip name.
bool uses_pa_boost_() const
True when TX goes out through PA_BOOST rather than RFO; the PA config and the dump both key on it.
void set_mode_rx() override
Switch radio into continuous receive mode.
bool is_sync_detected() override
Check if sync word has been detected (while in RX).
uint16_t response_preamble() const override
Preamble for response/continuation frames (SX1276).
uint8_t read_fifo_packet_(uint8_t *buf, uint8_t buf_size)
Read a packet from the RX FIFO into a buffer.
bool preamble_hold_()
The PreambleDetect half of reception_in_progress(): true while a fresh preamble detection is younger ...
uint32_t tx_air_time_us(uint8_t len, const RadioTxConfig &cfg) const override
Transmit time (SX1276): the preamble, sync word and the IoHomeOn-coded frame at the protocol line rat...
bool check_for_packet(RadioRxPacket &packet) override
Non‑blocking check for a received packet (called from loop).
TxResult send_packet(const uint8_t *data, uint8_t len, const RadioTxConfig &tx_config) override
Transmit a frame with specified frequency and preamble.
void run_image_cal_()
Run image calibration routine (required after reset).
bool is_preamble_detected() override
Check if preamble has been detected (while in RX).
Interface for SPI bus access.
static constexpr uint8_t REG_RX_CONFIG
Receiver configuration (AFC, AGC, trigger).
static constexpr uint8_t REG_IRQ_FLAGS1
IRQ flags: mode ready, preamble detect, etc.
static constexpr uint8_t REG_FRF_MSB
Carrier frequency MSB (freq = FRF * FXOSC / 2^19).
static constexpr uint8_t REG_PACKET_CONFIG2
Packet mode, IoHomeOn, PowerFrame.
constexpr uint32_t soft_phy_air_time_us(uint32_t raw_bytes)
On-air time in microseconds for raw_bytes bytes at the protocol's line rate.
static constexpr uint8_t REG_PA_CONFIG
Power amplifier config (pin select + power level).
static constexpr uint8_t REG_IRQ_FLAGS2
IRQ flags: FIFO full/empty, payload ready, CRC ok.
static constexpr uint8_t RX_CONFIG_VALUE
REG_RX_CONFIG as configured: RestartRxOnCollision | AfcAutoOn | AgcAutoOn | RxTrigger=PreambleDetect.
static constexpr uint8_t MODE_RX
static constexpr uint8_t REG_DIO_MAPPING1
DIO0-DIO3 pin mapping.
static constexpr uint8_t REG_FDEV_LSB
static constexpr uint8_t REG_DIO_MAPPING2
DIO4-DIO5 pin mapping.
static constexpr uint8_t REG_FIFO_THRESH
FIFO threshold for TX start condition.
static constexpr uint8_t REG_FIFO
FIFO read/write access.
static constexpr uint8_t REG_OP_MODE
Operating mode (sleep/standby/tx/rx).
static constexpr uint8_t REG_FDEV_MSB
Frequency deviation MSB.
static constexpr uint8_t MODE_SLEEP
static constexpr uint8_t RX_CONFIG_RESTART_RX_WITH_PLL_LOCK
REG_RX_CONFIG bit 5, RestartRxWithPllLock: restarts the receiver chain after a frequency change,...
static constexpr uint8_t MODE_TX
static constexpr uint8_t REG_PA_RAMP
PA ramp time and modulation shaping.
static constexpr uint32_t SX1276_PREAMBLE_HOLD_US
How long reception_in_progress() holds the idle hop on a channel once PreambleDetect is set: the long...
static constexpr uint8_t MODE_STDBY
static constexpr uint8_t REG_PAYLOAD_LENGTH
Max payload length.
static constexpr uint8_t REG_AFC_BW
AFC bandwidth.
static constexpr uint8_t REG_RX_BW
Receiver bandwidth.
static constexpr uint8_t REG_PACKET_CONFIG1
Packet format, CRC, encoding.
static constexpr uint8_t REG_BITRATE_MSB
Bit rate MSB = FXOSC / bitrate.
static constexpr uint8_t REG_SYNC_CONFIG
Sync word config (size, polarity, enable).
static constexpr uint8_t REG_AFC_FEI
AFC auto clear.
static constexpr uint8_t REG_PREAMBLE_LSB
static constexpr uint8_t REG_PLLHOP
PLL hop: fast frequency change without standby.
uint32_t io868_tx_air_time_us(uint16_t preamble_len, uint8_t frame_len)
Time on air of one 868 MHz transmission: preamble, sync word, and the frame plus its CRC,...
static constexpr uint8_t REG_LNA
Low noise amplifier gain and boost.
static constexpr uint8_t MODE_MASK
static constexpr uint32_t FXOSC
SX1276 crystal oscillator frequency (32 MHz).
static constexpr uint8_t REG_IMAGE_CAL
Image calibration.
static constexpr uint8_t SX1276_PA_SELECT_PA_BOOST
pa_pin value that routes the output through the PA_BOOST pin; any other value selects the RFO pin.
static constexpr uint8_t REG_RSSI_CONFIG
RSSI smoothing.
static constexpr uint8_t REG_OSC
Oscillator / clock output.
static constexpr uint8_t REG_VERSION
Chip version (should read 0x12 for SX1276).
SX1276RxBandwidth
Valid SX1276 RX bandwidth options (RegRxBw register bytes).
@ BW_41_7_KHZ
41.7 kHz — default (validated against real devices).
static constexpr uint8_t REG_PREAMBLE_DETECT
Preamble detector config.
static constexpr uint8_t REG_SYNC_VALUE1
Sync word byte 1 (registers 0x28-0x2F for bytes 1-8).
static constexpr uint8_t REG_RSSI_VALUE
Instant RSSI value in FSK mode.
static constexpr uint8_t REG_FRF_MID
static constexpr uint8_t REG_PREAMBLE_MSB
TX preamble length MSB.
static constexpr uint32_t SX1276_CCA_SETTLE_US
Wait after retuning to the TX channel before the clear-channel RSSI reading.
static constexpr uint8_t REG_BITRATE_LSB
static constexpr uint8_t REG_FRF_LSB
Physical-layer radio and timing parameters for the IO-Homecontrol protocol.
Radio abstraction layer for IO-Homecontrol.
Software PHY for radios without IoHomeOn hardware framing.
Raw packet received from the radio.
Configuration for transmitting a packet: carrier frequency, preamble length, wake-up level and clear-...
uint16_t preamble_len
Preamble length in symbol periods (bytes).
All runtime tunable parameters for pairing and radio diagnostics.
SX1276RxBandwidth sx1276_rx_bandwidth
SX1276 RX bandwidth selector.
uint16_t sx1276_response_preamble
SX1276 response preamble in bytes.
uint16_t sx1276_discovery_hop_slice_ms
Per-channel dwell while SX1276 discovery hops.
What send_packet() did with a frame.