22#include "esphome/core/log.h"
23#include "esphome/core/application.h"
28static const char *
const TAG =
"home_io_control.sx1262";
34 uint32_t
const start = millis();
35 while (this->busy_pin_->digital_read()) {
36 if (millis() - start > 10) {
37 ESP_LOGE(
TAG,
"BUSY timeout");
47 this->spi_->spi_enable();
48 this->spi_->spi_transfer(opcode);
49 for (uint8_t i = 0; i < len; i++)
50 this->spi_->spi_transfer(params[i]);
51 this->spi_->spi_disable();
56 this->spi_->spi_enable();
57 this->spi_->spi_transfer(opcode);
58 this->spi_->spi_transfer(0x00);
59 for (uint8_t i = 0; i < len; i++)
60 data[i] = this->spi_->spi_transfer(0x00);
61 this->spi_->spi_disable();
65 uint8_t irq_raw[2] = {0};
67 return (
static_cast<uint32_t
>(irq_raw[0]) << 8) |
static_cast<uint32_t
>(irq_raw[1]);
72 this->spi_->spi_enable();
74 this->spi_->spi_transfer((addr >> 8) & 0xFF);
75 this->spi_->spi_transfer(addr & 0xFF);
76 for (uint8_t i = 0; i < len; i++)
77 this->spi_->spi_transfer(data[i]);
78 this->spi_->spi_disable();
83 this->spi_->spi_enable();
85 this->spi_->spi_transfer((addr >> 8) & 0xFF);
86 this->spi_->spi_transfer(addr & 0xFF);
87 this->spi_->spi_transfer(0x00);
88 for (uint8_t i = 0; i < len; i++)
89 data[i] = this->spi_->spi_transfer(0x00);
90 this->spi_->spi_disable();
95 this->spi_->spi_enable();
97 this->spi_->spi_transfer(offset);
98 for (uint8_t i = 0; i < len; i++)
99 this->spi_->spi_transfer(data[i]);
100 this->spi_->spi_disable();
105 this->spi_->spi_enable();
107 this->spi_->spi_transfer(offset);
108 this->spi_->spi_transfer(0x00);
109 for (uint8_t i = 0; i < len; i++)
110 data[i] = this->spi_->spi_transfer(0x00);
111 this->spi_->spi_disable();
123 const uint16_t preamble_bits = preamble_len * 8;
124 uint8_t params[9] = {
125 (uint8_t) (preamble_bits >> 8),
126 (uint8_t) preamble_bits,
158 uint8_t mod_params[8] = {
163 static_cast<uint8_t
>(this->rx_bandwidth_),
172 uint8_t clear_irq[2] = {
173 (uint8_t) ((irq_mask >> 8) & 0xFF),
174 (uint8_t) (irq_mask & 0xFF),
180 uint8_t errors_raw[2] = {0};
182 return (uint16_t) (((uint16_t) errors_raw[0] << 8) | errors_raw[1]);
186 uint8_t clear_errors[2] = {0x00, 0x00};
196 const uint8_t *raw, uint8_t raw_len,
const uint8_t *frame, uint8_t frame_len) {
197 uint8_t packet_status[3] = {0};
204 this->
last_capture_.irq_status =
static_cast<uint16_t
>(irq_status);
217 uint8_t rx_status[2] = {0};
219 reported_len = rx_status[0];
220 rx_offset = rx_status[1];
225 uint8_t tx_modulation = 0;
233 uint8_t tx_timeout[3] = {0x03, 0xE8, 0x00};
246 this->dio1_pin_->setup();
247 this->busy_pin_->setup();
250 if (this->fem_en_pin_ !=
nullptr) {
251 this->fem_en_pin_->setup();
252 this->fem_en_pin_->digital_write(
true);
254 if (this->vfem_pin_ !=
nullptr) {
255 this->vfem_pin_->setup();
256 this->vfem_pin_->digital_write(
true);
258 if (this->fem_pa_pin_ !=
nullptr) {
259 this->fem_pa_pin_->setup();
260 this->fem_pa_pin_->digital_write(
true);
273 ESP_LOGI(
TAG,
"SX1262 initialized");
279 this->spi_->spi_enable();
281 this->spi_->spi_transfer(0x00);
282 this->spi_->spi_disable();
284 uint8_t
const chip_mode = (chip_status >> 4) & 0x07;
285 uint8_t
const cmd_status = (chip_status >> 1) & 0x07;
286 const char *mode_str =
"?";
289 mode_str =
"STDBY_RC";
292 mode_str =
"STDBY_XOSC";
312 uint16_t
const irq = ((uint16_t) irq_raw[0] << 8) | irq_raw[1];
315 ESP_LOGCONFIG(
TAG,
" SX1262 Diagnostic:");
316 ESP_LOGCONFIG(
TAG,
" Chip status: 0x%02X (mode=%s, cmd=%u)", chip_status, mode_str, cmd_status);
317 ESP_LOGCONFIG(
TAG,
" BUSY=%d DIO1=%d", this->busy_pin_->digital_read(), this->dio1_pin_->digital_read());
318 ESP_LOGCONFIG(
TAG,
" Sync word: %02X %02X %02X (expect 57 FD 99)", sync[0], sync[1], sync[2]);
319 ESP_LOGCONFIG(
TAG,
" IRQ status: 0x%04X", irq);
320 ESP_LOGCONFIG(
TAG,
" Device errors: 0x%04X", errors);
325 uint8_t
const stdby_rc = 0x00;
329 uint8_t tcxo_params[4] = {this->tcxo_voltage_, 0x00, 0x01, 0x40};
333 uint8_t
const cal = 0x7F;
338 uint8_t
const stdby_xosc = 0x01;
342 uint8_t
const reg_mode = 0x01;
346 uint8_t
const dio2_rf = 0x01;
354 uint8_t
const pkt_type = 0x00;
361 uint8_t cal_img[2] = {0xD7, 0xDB};
365 uint8_t
const rx_gain = 0x96;
375 uint8_t sync_word[8] = {0x57, 0xFD, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00};
381 uint8_t crc_init[2] = {0x1D, 0x0F};
383 uint8_t crc_poly[2] = {0x10, 0x21};
390 uint8_t pa_config[4] = {0x04, 0x07, 0x00, 0x01};
394 uint8_t tx_clamp = 0;
400 int8_t
const power = std::max((int8_t) -9, std::min((int8_t) 22, (int8_t) this->tx_power_));
401 uint8_t tx_params[2] = {(uint8_t) power, 0x04};
405 uint8_t irq_params[8] = {
423 if (init_errors != 0)
424 ESP_LOGW(
TAG,
"SX1262 device errors after init: 0x%04X — check tcxo_voltage for this board", init_errors);
428 uint8_t rx_continuous[3] = {0xFF, 0xFF, 0xFF};
435 uint8_t
const stdby = 0x01;
440 uint8_t rx_continuous[3] = {0xFF, 0xFF, 0xFF};
447 auto freq_reg = (uint32_t) ((
double) freq_hz * (1 << 25) / 32e6);
448 uint8_t params[4] = {
449 (uint8_t) (freq_reg >> 24),
450 (uint8_t) (freq_reg >> 16),
451 (uint8_t) (freq_reg >> 8),
459 this->rx_bandwidth_ = bandwidth;
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.
InternalGPIOPin * rst_pin_
void mark_dio_fired_from_isr()
void reset_hardware_()
Shared hardware reset sequence for chips with an active-low RST pin.
RadioCaptureInfo last_capture_
void set_rx_packet_params() override
Configure RX-specific packet parameters (preamble detector length, fixed probe length).
void wait_busy_()
Wait until BUSY pin is low before any SPI transaction.
void set_mode_rx() override
Switch to continuous receive mode.
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 write_opcode_(uint8_t opcode, const uint8_t *params, uint8_t len)
Write an opcode with optional parameter bytes.
void set_mode_standby() override
Switch to standby mode.
void clear_irq_status(uint32_t irq_mask) override
Clear IRQ status bits.
RadioSX1262(SpiAccess *spi, InternalGPIOPin *rst_pin, InternalGPIOPin *dio1_pin, InternalGPIOPin *busy_pin, uint8_t tx_power, uint8_t tcxo_voltage, InternalGPIOPin *fem_en_pin=nullptr, InternalGPIOPin *vfem_pin=nullptr, InternalGPIOPin *fem_pa_pin=nullptr)
void write_modulation_params_()
Apply the runtime bandwidth setting to the SX1262 modulation parameters.
void write_buffer_(uint8_t offset, const uint8_t *data, uint8_t len)
Write into the SX1262 TX/RX buffer at a given offset.
uint8_t read_rssi_raw_byte() override
Read the single raw RSSI byte (chip-specific opcode); formula is shared, see read_rssi.
uint32_t read_irq_status_raw() override
Read the raw IRQ status word from the radio.
void clear_device_errors_()
Clear device error flags.
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 write_register_(uint16_t addr, const uint8_t *data, uint8_t len)
Write to a register (SX1262 uses opcodes for register access).
void configure_buffer_base() override
Hook run as part of reset_rx_state_, before re-entering RX.
void set_packet_params_(uint16_t preamble_len, uint8_t payload_len, uint8_t packet_type, uint8_t crc_type)
Configure packet parameters (preamble, payload length, CRC).
void dump_debug() override
Dump SX1262‑specific debug info.
void configure_radio_()
Full radio initialization (called from init()).
void start_tx() override
Issue the SetTx opcode with the fixed TX timeout — identical 3-byte payload on both chips,...
void apply_tx_modulation_workaround_()
Apply the Semtech TX modulation-quality erratum workaround (datasheet §15.1).
static void gpio_intr(RadioSX1262 *arg)
DIO1 ISR — sets dio_fired flag. Runs in interrupt context.
void read_opcode_(uint8_t opcode, uint8_t *data, uint8_t len)
Read response from an opcode.
bool init() override
Initialize the radio hardware. Returns true on success.
void set_rx_bandwidth_(SX1262RxBandwidth bandwidth)
Apply the RX bandwidth selector and rewrite the modulation parameters.
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,...
void read_buffer_(uint8_t offset, uint8_t *data, uint8_t len)
Read from the SX1262 RX buffer.
void read_register_(uint16_t addr, uint8_t *data, uint8_t len)
Read from a register.
uint16_t get_device_errors_()
Read device error flags (and clear them).
static constexpr uint8_t SX1262_SET_DIO3_AS_TCXO_CTRL
static constexpr uint8_t SX1262_CALIBRATE
static constexpr uint16_t SX1262_REG_RX_GAIN
static constexpr uint8_t SOFT_PHY_RX_PROBE_PACKET_LEN
Fixed raw-RX probe length: chosen from captures of 23-25 byte protocol frames after UART packing and ...
static constexpr uint8_t SX1262_SET_BUFFER_BASE_ADDRESS
static constexpr uint8_t SX1262_CLEAR_DEVICE_ERRORS
static constexpr uint8_t SX1262_GFSK_CRC_OFF
SX1262RxBandwidth
Valid SX1262 RX bandwidth options (kHz register values).
static constexpr uint8_t SX1262_READ_REGISTER
static constexpr uint8_t SX1262_SET_PACKET_TYPE
static constexpr uint8_t SX1262_GET_DEVICE_ERRORS
static constexpr const char * TAG
static constexpr uint16_t SX1262_IRQ_CRC_ERR
static constexpr uint8_t SX1262_SET_MODULATION_PARAMS
static constexpr uint8_t SX1262_GET_RX_BUFFER_STATUS
static constexpr uint16_t SX1262_REG_TX_MODULATION
TX modulation-quality erratum register (SX1262 datasheet §15.1, "Modulation Quality with500 kHz LoRa ...
static constexpr uint8_t SX1262_CLEAR_IRQ_STATUS
static constexpr uint8_t SX1262_SET_RX
static constexpr uint8_t SX1262_SET_TX
static constexpr uint8_t SX1262_GFSK_PACKET_TYPE_KNOWN_LENGTH
static constexpr uint8_t SX1262_CALIBRATE_IMAGE
static constexpr uint8_t SX1262_SET_DIO2_AS_RF_SWITCH_CTRL
static constexpr uint8_t SX1262_WRITE_BUFFER
static constexpr uint8_t SX1262_READ_BUFFER
static constexpr uint16_t SX1262_IRQ_RX_DONE
static constexpr uint8_t SX1262_SET_PA_CONFIG
static constexpr uint8_t SX1262_SET_TX_PARAMS
static constexpr uint8_t SX1262_SET_DIO_IRQ_PARAMS
static constexpr uint32_t FREQ_CH2
Channel 2: 868.95 MHz (1W and 2W, TX channel).
static constexpr uint8_t SX1262_SET_PACKET_PARAMS
static constexpr uint8_t SX1262_TX_MODULATION_GFSK_BIT
Bit 2 of SX1262_REG_TX_MODULATION — the (G)FSK-correct value is 1.
static constexpr uint8_t SX1262_GET_STATUS
static constexpr uint16_t SX1262_REG_TX_CLAMP_CONFIG
static constexpr uint8_t SX1262_SET_RX_TX_FALLBACK_MODE
static constexpr uint8_t SX1262_TX_BUFFER_BASE
Data-buffer split programmed by configure_buffer_base(): TX packets build from 0x00,...
static constexpr uint8_t SX1262_RX_BUFFER_BASE
static constexpr uint8_t SX1262_GET_IRQ_STATUS
static constexpr uint8_t SX1262_SET_REGULATOR_MODE
static constexpr uint8_t SX1262_GET_PACKET_STATUS
static constexpr uint16_t SX1262_REG_SYNC_WORD
static constexpr uint8_t SX1262_FALLBACK_STDBY_XOSC
static constexpr uint8_t SX1262_SET_RF_FREQUENCY
static const uint8_t SX1262_SYNC_WORD_PARAM_24_BITS
static constexpr uint8_t SX1262_SET_STANDBY
static constexpr uint8_t SX1262_WRITE_REGISTER
static constexpr uint8_t SX1262_GET_RSSI_INST
SX1262 radio driver for IO-Homecontrol.