22#include "esphome/core/log.h"
23#include "esphome/core/application.h"
28static const char *
const TAG =
"home_io_control.sx1262";
35 this->spi_->spi_enable();
36 this->spi_->spi_transfer(opcode);
37 for (uint8_t i = 0; i < len; i++)
38 this->spi_->spi_transfer(params[i]);
39 this->spi_->spi_disable();
44 this->spi_->spi_enable();
45 this->spi_->spi_transfer(opcode);
46 this->spi_->spi_transfer(0x00);
47 for (uint8_t i = 0; i < len; i++)
48 data[i] = this->spi_->spi_transfer(0x00);
49 this->spi_->spi_disable();
53 uint8_t irq_raw[2] = {0};
55 return (
static_cast<uint32_t
>(irq_raw[0]) << 8) |
static_cast<uint32_t
>(irq_raw[1]);
60 this->spi_->spi_enable();
62 this->spi_->spi_transfer((addr >> 8) & 0xFF);
63 this->spi_->spi_transfer(addr & 0xFF);
64 for (uint8_t i = 0; i < len; i++)
65 this->spi_->spi_transfer(data[i]);
66 this->spi_->spi_disable();
71 this->spi_->spi_enable();
73 this->spi_->spi_transfer((addr >> 8) & 0xFF);
74 this->spi_->spi_transfer(addr & 0xFF);
75 this->spi_->spi_transfer(0x00);
76 for (uint8_t i = 0; i < len; i++)
77 data[i] = this->spi_->spi_transfer(0x00);
78 this->spi_->spi_disable();
83 this->spi_->spi_enable();
85 this->spi_->spi_transfer(offset);
86 for (uint8_t i = 0; i < len; i++)
87 this->spi_->spi_transfer(data[i]);
88 this->spi_->spi_disable();
93 this->spi_->spi_enable();
95 this->spi_->spi_transfer(offset);
96 this->spi_->spi_transfer(0x00);
97 for (uint8_t i = 0; i < len; i++)
98 data[i] = this->spi_->spi_transfer(0x00);
99 this->spi_->spi_disable();
111 .preamble_detector = 0x04,
113 .packet_type = packet_type,
114 .payload_len = payload_len,
115 .crc_type = crc_type},
140 uint8_t mod_params[8] = {
145 static_cast<uint8_t
>(this->rx_bandwidth_),
154 uint8_t clear_irq[2] = {
155 (uint8_t) ((irq_mask >> 8) & 0xFF),
156 (uint8_t) (irq_mask & 0xFF),
162 uint8_t errors_raw[2] = {0};
164 return (uint16_t) (((uint16_t) errors_raw[0] << 8) | errors_raw[1]);
168 uint8_t clear_errors[2] = {0x00, 0x00};
178 const uint8_t *raw, uint8_t raw_len,
const uint8_t *frame, uint8_t frame_len) {
179 uint8_t packet_status[3] = {0};
186 this->
last_capture_.irq_status =
static_cast<uint16_t
>(irq_status);
199 uint8_t rx_status[2] = {0};
201 reported_len = rx_status[0];
202 rx_offset = rx_status[1];
207 uint8_t tx_modulation = 0;
215 uint8_t tx_timeout[3] = {0x03, 0xE8, 0x00};
228 this->dio1_pin_->setup();
232 if (this->fem_en_pin_ !=
nullptr) {
233 this->fem_en_pin_->setup();
234 this->fem_en_pin_->digital_write(
true);
236 if (this->vfem_pin_ !=
nullptr) {
237 this->vfem_pin_->setup();
238 this->vfem_pin_->digital_write(
true);
240 if (this->fem_pa_pin_ !=
nullptr) {
241 this->fem_pa_pin_->setup();
242 this->fem_pa_pin_->digital_write(
true);
255 ESP_LOGI(
TAG,
"SX1262 initialized");
261 this->spi_->spi_enable();
263 this->spi_->spi_transfer(0x00);
264 this->spi_->spi_disable();
266 uint8_t
const chip_mode = (chip_status >> 4) & 0x07;
267 uint8_t
const cmd_status = (chip_status >> 1) & 0x07;
268 const char *mode_str =
"?";
271 mode_str =
"STDBY_RC";
274 mode_str =
"STDBY_XOSC";
294 uint16_t
const irq = ((uint16_t) irq_raw[0] << 8) | irq_raw[1];
297 ESP_LOGCONFIG(
TAG,
" SX1262 Diagnostic:");
298 ESP_LOGCONFIG(
TAG,
" Chip status: 0x%02X (mode=%s, cmd=%u)", chip_status, mode_str, cmd_status);
299 ESP_LOGCONFIG(
TAG,
" BUSY=%d DIO1=%d", this->
busy_pin_->digital_read(), this->dio1_pin_->digital_read());
300 ESP_LOGCONFIG(
TAG,
" Sync word: %02X %02X %02X (expect 57 FD 99)", sync[0], sync[1], sync[2]);
301 ESP_LOGCONFIG(
TAG,
" IRQ status: 0x%04X", irq);
302 ESP_LOGCONFIG(
TAG,
" Device errors: 0x%04X", errors);
307 uint8_t
const stdby_rc = 0x00;
311 uint8_t tcxo_params[4] = {this->tcxo_voltage_, 0x00, 0x01, 0x40};
315 uint8_t
const cal = 0x7F;
320 uint8_t
const stdby_xosc = 0x01;
324 uint8_t
const reg_mode = 0x01;
328 uint8_t
const dio2_rf = 0x01;
336 uint8_t
const pkt_type = 0x00;
343 uint8_t cal_img[2] = {0xD7, 0xDB};
347 uint8_t
const rx_gain = 0x96;
360 uint8_t sync_word[8] = {0x57, 0xFD, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00};
366 uint8_t crc_init[2] = {0x1D, 0x0F};
368 uint8_t crc_poly[2] = {0x10, 0x21};
375 uint8_t pa_config[4] = {0x04, 0x07, 0x00, 0x01};
379 uint8_t tx_clamp = 0;
385 int8_t
const power = std::max((int8_t) -9, std::min((int8_t) 22, (int8_t) this->tx_power_));
386 uint8_t tx_params[2] = {(uint8_t) power, 0x04};
397 uint8_t irq_params[8] = {
416 if (init_errors != 0)
417 ESP_LOGW(
TAG,
"SX1262 device errors after init: 0x%04X — check tcxo_voltage for this board", init_errors);
421 uint8_t rx_continuous[3] = {0xFF, 0xFF, 0xFF};
428 uint8_t
const stdby = 0x01;
433 uint8_t rx_continuous[3] = {0xFF, 0xFF, 0xFF};
440 auto freq_reg = (uint32_t) ((
double) freq_hz * (1 << 25) / 32e6);
441 uint8_t params[4] = {
442 (uint8_t) (freq_reg >> 24),
443 (uint8_t) (freq_reg >> 16),
444 (uint8_t) (freq_reg >> 8),
452 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 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).
void wait_busy_()
Wait until busy_pin_ reads low, feeding the watchdog while polling.
static void build_gfsk_packet_params(const SoftPhyPacketParams &p, uint8_t out[GFSK_PACKET_PARAMS_LEN])
Fill the nine-byte GFSK SetPacketParams payload shared by both chips.
bool failed_
Set on a BUSY timeout or a chip-identity check failing; see is_failed.
InternalGPIOPin * busy_pin_
BUSY line, read directly by both concrete drivers' own dump_debug() in addition to wait_busy_,...
static constexpr uint8_t GFSK_PACKET_PARAMS_LEN
Byte count of the GFSK SetPacketParams payload — identical on both software-PHY chips.
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.