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///
6/// Implements the RadioDriver interface for the Semtech SX1276 transceiver.
7/// Configures the chip in FSK mode with the IoHomeOn hardware feature that
8/// handles CRC and packet framing specific to the IO-Homecontrol protocol.
9
10#include "radio_interface.h"
11#include "esphome/core/hal.h"
12
13namespace esphome {
14namespace home_io_control {
15
16// ============================================================================
17// SX1276 Register Addresses (subset needed for IO-Homecontrol)
18// Full register map: see Semtech SX1276 datasheet or sx1276Regs-Fsk.h
19// ============================================================================
20
21static constexpr uint8_t REG_FIFO = 0x00; ///< FIFO read/write access
22static constexpr uint8_t REG_OP_MODE = 0x01; ///< Operating mode (sleep/standby/tx/rx)
23static constexpr uint8_t REG_BITRATE_MSB = 0x02; ///< Bit rate MSB = FXOSC / bitrate
24static constexpr uint8_t REG_BITRATE_LSB = 0x03;
25static constexpr uint8_t REG_FDEV_MSB = 0x04; ///< Frequency deviation MSB
26static constexpr uint8_t REG_FDEV_LSB = 0x05;
27static constexpr uint8_t REG_FRF_MSB = 0x06; ///< Carrier frequency MSB (freq = FRF * FXOSC / 2^19)
28static constexpr uint8_t REG_FRF_MID = 0x07;
29static constexpr uint8_t REG_FRF_LSB = 0x08;
30static constexpr uint8_t REG_PA_CONFIG = 0x09; ///< Power amplifier config (pin select + power level)
31static constexpr uint8_t REG_PA_RAMP = 0x0A; ///< PA ramp time and modulation shaping
32static constexpr uint8_t REG_LNA = 0x0C; ///< Low noise amplifier gain and boost
33static constexpr uint8_t REG_RX_CONFIG = 0x0D; ///< Receiver configuration (AFC, AGC, trigger)
34static constexpr uint8_t REG_RSSI_CONFIG = 0x0E; ///< RSSI smoothing
35static constexpr uint8_t REG_RX_BW = 0x12; ///< Receiver bandwidth
36static constexpr uint8_t REG_AFC_FEI = 0x1A; ///< AFC auto clear
37static constexpr uint8_t REG_PREAMBLE_DETECT = 0x1F; ///< Preamble detector config
38static constexpr uint8_t REG_OSC = 0x24; ///< Oscillator / clock output
39static constexpr uint8_t REG_RSSI_VALUE = 0x11; ///< Instant RSSI value in FSK mode
40static constexpr uint8_t REG_PREAMBLE_MSB = 0x25; ///< TX preamble length MSB
41static constexpr uint8_t REG_PREAMBLE_LSB = 0x26;
42static constexpr uint8_t REG_SYNC_CONFIG = 0x27; ///< Sync word config (size, polarity, enable)
43static constexpr uint8_t REG_SYNC_VALUE1 = 0x28; ///< Sync word byte 1 (registers 0x28-0x2F for bytes 1-8)
44static constexpr uint8_t REG_PACKET_CONFIG1 = 0x30; ///< Packet format, CRC, encoding
45static constexpr uint8_t REG_PACKET_CONFIG2 = 0x31; ///< Packet mode, IoHomeOn, PowerFrame
46static constexpr uint8_t REG_PAYLOAD_LENGTH = 0x32; ///< Max payload length
47static constexpr uint8_t REG_FIFO_THRESH = 0x35; ///< FIFO threshold for TX start condition
48static constexpr uint8_t REG_IRQ_FLAGS1 = 0x3E; ///< IRQ flags: mode ready, preamble detect, etc.
49static constexpr uint8_t REG_IRQ_FLAGS2 = 0x3F; ///< IRQ flags: FIFO full/empty, payload ready, CRC ok
50static constexpr uint8_t REG_DIO_MAPPING1 = 0x40; ///< DIO0-DIO3 pin mapping
51static constexpr uint8_t REG_DIO_MAPPING2 = 0x41; ///< DIO4-DIO5 pin mapping
52static constexpr uint8_t REG_VERSION = 0x42; ///< Chip version (should read 0x12 for SX1276)
53static constexpr uint8_t REG_PLLHOP = 0x44; ///< PLL hop: fast frequency change without standby
54static constexpr uint8_t REG_IMAGE_CAL = 0x3B; ///< Image calibration
55
56// SX1276 operating modes (bits [2:0] of REG_OP_MODE)
57static constexpr uint8_t MODE_SLEEP = 0x00;
58static constexpr uint8_t MODE_STDBY = 0x01;
59static constexpr uint8_t MODE_TX = 0x03;
60static constexpr uint8_t MODE_RX = 0x05;
61static constexpr uint8_t MODE_MASK = 0x07;
62
63/// SX1276 crystal oscillator frequency (32 MHz). Used to calculate register values
64/// for bitrate, frequency deviation, and carrier frequency.
65static constexpr uint32_t FXOSC = 32000000U;
66
67// ============================================================================
68// SX1276 Radio Driver
69// ============================================================================
70
71/// @brief SX1276 implementation of RadioDriver.
72///
73/// Manages the SX1276 via SPI using the SpiAccess interface. Configures the chip
74/// in FSK mode with IoHomeOn for hardware CRC and IO‑Homecontrol packet framing.
75class RadioSX1276 : public RadioDriver {
76 public:
77 RadioSX1276(SpiAccess *spi, InternalGPIOPin *rst_pin, InternalGPIOPin *dio0_pin, InternalGPIOPin *dio4_pin,
78 uint8_t tx_power, uint8_t pa_pin)
79 : RadioDriver(rst_pin),
80 spi_(spi),
81 dio0_pin_(dio0_pin),
82 dio4_pin_(dio4_pin),
83 tx_power_(tx_power),
84 pa_pin_(pa_pin) {}
85
86 /// @brief Initialize the SX1276 radio (reset, calibrate, configure registers).
87 /// @return true on success; false on failure (e.g., version check).
88 bool init() override;
89 /// @brief Transmit a frame with specified frequency and preamble.
90 /// @param data Pointer to payload bytes.
91 /// @param len Payload length.
92 /// @param tx_config Transmission config (frequency, preamble).
93 /// @return true if transmit succeeded.
94 bool send_packet(const uint8_t *data, uint8_t len, const RadioTxConfig &tx_config) override;
95 /// @brief Blocking wait for a packet with timeout.
96 /// @param packet Output: received packet (freq, len, data).
97 /// @param timeout_ms Maximum time to wait.
98 /// @return true if a packet was received; false on timeout.
99 bool wait_for_packet(RadioRxPacket &packet, uint32_t timeout_ms) override;
100 /// @brief Non‑blocking check for a received packet (called from loop).
101 /// @param packet Output: received packet if any.
102 /// @return true if a packet was read; false if no interrupt fired.
103 bool check_for_packet(RadioRxPacket &packet) override;
104 /// @brief Change RF frequency using fast hop (no standby needed).
105 /// @param freq_hz New frequency in Hz.
106 void change_frequency(uint32_t freq_hz) override;
107 /// @brief Read instantaneous RSSI (dBm) while in RX mode (used for LBT).
108 /// @return RSSI in dBm (negative).
109 int16_t read_rssi() override;
110 /// @brief Switch radio into continuous receive mode.
111 void set_mode_rx() override;
112 /// @brief Switch radio into standby mode.
113 void set_mode_standby() override;
114 /// @copydoc RadioDriver::is_failed
115 [[nodiscard]] bool is_failed() const override { return this->failed_; }
116 /// @copydoc RadioDriver::chip_name
117 [[nodiscard]] const char *chip_name() const override { return "sx1276"; }
118 /// @brief Dump radio‑specific debug info to log.
119 void dump_debug() override;
120
121 protected:
122 // --- SPI register access ---
123 /// Read an SX1276 register over SPI.
124 /// @param reg Register address (7 bits, MSB clear for read).
125 /// @return Register value.
126 uint8_t read_register_(uint8_t reg);
127 /// Write an SX1276 register over SPI.
128 /// @param reg Register address (7 bits, MSB set for write).
129 /// @param value Byte to write.
130 void write_register_(uint8_t reg, uint8_t value);
131
132 // --- Radio hardware control ---
133 /// Set the operating mode (sleep/standby/tx/rx) and wait for mode completion.
134 /// @param mode One of MODE_SLEEP, MODE_STDBY, MODE_TX, or MODE_RX.
135 void set_mode_(uint8_t mode);
136 /// Perform full radio configuration (called during init).
137 void configure_radio_();
138 /// Run image calibration routine (required after reset).
139 void run_image_cal_();
140 /// Wait until FIFO payload is ready (polling for TX/RX readiness).
141 /// @param timeout_ms How long to wait.
142 /// @param saw_dio0 Output: true if DIO0 fired.
143 /// @param irq1 Output: IRQ flags 1.
144 /// @param irq2 Output: IRQ flags 2.
145 /// @return true if payload ready before timeout; false otherwise.
146 bool poll_until_payload_ready_(uint32_t timeout_ms, bool &saw_dio0, uint8_t &irq1, uint8_t &irq2);
147 /// Read a packet from the RX FIFO into a buffer.
148 /// @param buf Output buffer.
149 /// @param buf_size Size of buf.
150 /// @return Number of bytes read.
151 uint8_t read_fifo_packet_(uint8_t *buf, uint8_t buf_size);
152 /// Populate last_capture_ from raw telemetry.
153 /// @param blocking_wait if this was a blocking receive.
154 /// @param irq1 IRQ flags 1.
155 /// @param irq2 IRQ flags 2.
156 /// @param rssi RSSI value.
157 /// @param raw Pointer to raw bytes (may be nullptr).
158 /// @param raw_len Length of raw buffer.
159 /// @param frame Pointer to parsed frame bytes (may be nullptr).
160 /// @param frame_len Length of parsed frame.
161 void fill_capture_info_(bool blocking_wait, uint8_t irq1, uint8_t irq2, uint8_t rssi, const uint8_t *raw,
162 uint8_t raw_len, const uint8_t *frame, uint8_t frame_len);
163
164 /// DIO0 ISR — sets dio_fired flag. Runs in interrupt context.
165 static void gpio_intr(RadioSX1276 *arg);
166
168 InternalGPIOPin *dio0_pin_;
169 InternalGPIOPin *dio4_pin_;
170 uint8_t tx_power_;
171 uint8_t pa_pin_;
172 bool failed_{false};
173};
174
175} // namespace home_io_control
176} // namespace esphome
RadioDriver(InternalGPIOPin *rst_pin=nullptr)
SX1276 implementation of RadioDriver.
void configure_radio_()
Perform full radio configuration (called during init).
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.
uint8_t read_register_(uint8_t reg)
Read an SX1276 register over SPI.
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.
bool is_failed() const override
Returns true if the radio failed to initialize or encountered a fatal error.
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).
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.
void set_mode_rx() override
Switch radio into continuous receive mode.
uint8_t read_fifo_packet_(uint8_t *buf, uint8_t buf_size)
Read a packet from the RX FIFO into a buffer.
bool send_packet(const uint8_t *data, uint8_t len, const RadioTxConfig &tx_config) override
Transmit a frame with specified frequency and preamble.
bool check_for_packet(RadioRxPacket &packet) override
Non‑blocking check for a received packet (called from loop).
void run_image_cal_()
Run image calibration routine (required after reset).
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.
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 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 MODE_TX
static constexpr uint8_t REG_PA_RAMP
PA ramp time and modulation shaping.
static constexpr uint8_t MODE_STDBY
static constexpr uint8_t REG_PAYLOAD_LENGTH
Max payload length.
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.
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 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).
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 uint8_t REG_BITRATE_LSB
static constexpr uint8_t REG_FRF_LSB
Radio abstraction layer for IO-Homecontrol.
Raw packet received from the radio.
Configuration for transmitting a packet: carrier frequency and preamble length.