ESPHome 2025.7.1
Loading...
Searching...
No Matches
sx127x.cpp
Go to the documentation of this file.
1#include "sx127x.h"
2#include "esphome/core/hal.h"
3#include "esphome/core/log.h"
4
5namespace esphome {
6namespace sx127x {
7
8static const char *const TAG = "sx127x";
9static const uint32_t FXOSC = 32000000u;
10static const uint16_t RAMP[16] = {3400, 2000, 1000, 500, 250, 125, 100, 62, 50, 40, 31, 25, 20, 15, 12, 10};
11static const uint32_t BW_HZ[22] = {2604, 3125, 3906, 5208, 6250, 7812, 10416, 12500, 15625, 20833, 25000,
12 31250, 41666, 50000, 62500, 83333, 100000, 125000, 166666, 200000, 250000, 500000};
13static const uint8_t BW_LORA[22] = {BW_7_8, BW_7_8, BW_7_8, BW_7_8, BW_7_8, BW_7_8, BW_10_4, BW_15_6,
16static const uint8_t BW_FSK_OOK[22] = {RX_BW_2_6, RX_BW_3_1, RX_BW_3_9, RX_BW_5_2, RX_BW_6_3, RX_BW_7_8,
20static const int32_t RSSI_OFFSET_HF = 157;
21static const int32_t RSSI_OFFSET_LF = 164;
22
23uint8_t SX127x::read_register_(uint8_t reg) {
24 this->enable();
25 this->write_byte(reg & 0x7F);
26 uint8_t value = this->read_byte();
27 this->disable();
28 return value;
29}
30
31void SX127x::write_register_(uint8_t reg, uint8_t value) {
32 this->enable();
33 this->write_byte(reg | 0x80);
34 this->write_byte(value);
35 this->disable();
36}
37
38void SX127x::read_fifo_(std::vector<uint8_t> &packet) {
39 this->enable();
40 this->write_byte(REG_FIFO & 0x7F);
41 this->read_array(packet.data(), packet.size());
42 this->disable();
43}
44
45void SX127x::write_fifo_(const std::vector<uint8_t> &packet) {
46 this->enable();
47 this->write_byte(REG_FIFO | 0x80);
48 this->write_array(packet.data(), packet.size());
49 this->disable();
50}
51
53 ESP_LOGCONFIG(TAG, "Running setup");
54
55 // setup reset
56 this->rst_pin_->setup();
57
58 // setup dio0
59 if (this->dio0_pin_) {
60 this->dio0_pin_->setup();
61 }
62
63 // start spi
64 this->spi_setup();
65
66 // configure rf
67 this->configure();
68}
69
71 // toggle chip reset
72 this->rst_pin_->digital_write(false);
74 this->rst_pin_->digital_write(true);
75 delayMicroseconds(10000);
76
77 // check silicon version to make sure hw is ok
78 if (this->read_register_(REG_VERSION) != 0x12) {
79 this->mark_failed();
80 return;
81 }
82
83 // enter sleep mode
85
86 // set freq
87 uint64_t frf = ((uint64_t) this->frequency_ << 19) / FXOSC;
88 this->write_register_(REG_FRF_MSB, (uint8_t) ((frf >> 16) & 0xFF));
89 this->write_register_(REG_FRF_MID, (uint8_t) ((frf >> 8) & 0xFF));
90 this->write_register_(REG_FRF_LSB, (uint8_t) ((frf >> 0) & 0xFF));
91
92 // enter standby mode
94
95 // run image cal
96 this->run_image_cal();
97
98 // go back to sleep
99 this->set_mode_sleep();
100
101 // config pa
102 if (this->pa_pin_ == PA_PIN_BOOST) {
103 this->pa_power_ = std::max(this->pa_power_, (uint8_t) 2);
104 this->pa_power_ = std::min(this->pa_power_, (uint8_t) 17);
105 this->write_register_(REG_PA_CONFIG, (this->pa_power_ - 2) | this->pa_pin_ | PA_MAX_POWER);
106 } else {
107 this->pa_power_ = std::min(this->pa_power_, (uint8_t) 14);
108 this->write_register_(REG_PA_CONFIG, (this->pa_power_ - 0) | this->pa_pin_ | PA_MAX_POWER);
109 }
110 if (this->modulation_ != MOD_LORA) {
111 this->write_register_(REG_PA_RAMP, this->pa_ramp_ | this->shaping_);
112 } else {
114 }
115
116 // configure modem
117 if (this->modulation_ != MOD_LORA) {
118 this->configure_fsk_ook_();
119 } else {
120 this->configure_lora_();
121 }
122
123 // switch to rx or sleep
124 if (this->rx_start_) {
125 this->set_mode_rx();
126 } else {
127 this->set_mode_sleep();
128 }
129}
130
132 // set the channel bw
133 this->write_register_(REG_RX_BW, BW_FSK_OOK[this->bandwidth_]);
134
135 // set fdev
136 uint32_t fdev = std::min((this->deviation_ * 4096) / 250000, (uint32_t) 0x3FFF);
137 this->write_register_(REG_FDEV_MSB, (uint8_t) ((fdev >> 8) & 0xFF));
138 this->write_register_(REG_FDEV_LSB, (uint8_t) ((fdev >> 0) & 0xFF));
139
140 // set bitrate
141 uint64_t bitrate = (FXOSC + this->bitrate_ / 2) / this->bitrate_; // round up
142 this->write_register_(REG_BITRATE_MSB, (uint8_t) ((bitrate >> 8) & 0xFF));
143 this->write_register_(REG_BITRATE_LSB, (uint8_t) ((bitrate >> 0) & 0xFF));
144
145 // configure rx and afc
146 uint8_t trigger = (this->preamble_detect_ > 0) ? TRIGGER_PREAMBLE : TRIGGER_RSSI;
148 if (this->modulation_ == MOD_FSK) {
150 } else {
151 this->write_register_(REG_RX_CONFIG, AGC_AUTO_ON | trigger);
152 }
153
154 // configure packet mode
155 if (this->packet_mode_) {
156 uint8_t crc_mode = (this->crc_enable_) ? CRC_ON : CRC_OFF;
158 if (this->payload_length_ > 0) {
161 } else {
164 }
166 } else {
168 }
170
171 // config bit synchronizer
172 uint8_t polarity = (this->preamble_polarity_ == 0xAA) ? PREAMBLE_AA : PREAMBLE_55;
173 if (!this->sync_value_.empty()) {
174 uint8_t size = this->sync_value_.size() - 1;
176 for (uint32_t i = 0; i < this->sync_value_.size(); i++) {
177 this->write_register_(REG_SYNC_VALUE1 + i, this->sync_value_[i]);
178 }
179 } else {
181 }
182
183 // config preamble detector
184 if (this->preamble_detect_ > 0) {
185 uint8_t size = (this->preamble_detect_ - 1) << PREAMBLE_DETECTOR_SIZE_SHIFT;
186 uint8_t tol = this->preamble_errors_ << PREAMBLE_DETECTOR_TOL_SHIFT;
188 } else {
190 }
193
194 // config sync generation and setup ook threshold
195 uint8_t bitsync = this->bitsync_ ? BIT_SYNC_ON : BIT_SYNC_OFF;
198
199 // set rx floor
200 this->write_register_(REG_OOK_FIX, 256 + int(this->rx_floor_ * 2.0));
201 this->write_register_(REG_RSSI_THRESH, std::abs(int(this->rx_floor_ * 2.0)));
202}
203
205 // config modem
206 uint8_t header_mode = this->payload_length_ > 0 ? IMPLICIT_HEADER : EXPLICIT_HEADER;
207 uint8_t crc_mode = (this->crc_enable_) ? RX_PAYLOAD_CRC_ON : RX_PAYLOAD_CRC_OFF;
208 uint8_t spreading_factor = this->spreading_factor_ << SPREADING_FACTOR_SHIFT;
209 this->write_register_(REG_MODEM_CONFIG1, BW_LORA[this->bandwidth_] | this->coding_rate_ | header_mode);
210 this->write_register_(REG_MODEM_CONFIG2, spreading_factor | crc_mode);
211
212 // config fifo and payload length
215 this->write_register_(REG_PAYLOAD_LENGTH, std::max(this->payload_length_, (uint32_t) 1));
216
217 // config preamble
218 if (this->preamble_size_ >= 6) {
221 }
222
223 // optimize detection
224 float duration = 1000.0f * std::pow(2, this->spreading_factor_) / BW_HZ[this->bandwidth_];
225 if (duration > 16) {
227 } else {
229 }
230 if (this->spreading_factor_ == 6) {
233 } else {
236 }
237
238 // config sync word
239 if (!this->sync_value_.empty()) {
241 }
242}
243
245 if (this->payload_length_ > 0) {
246 return this->payload_length_;
247 }
248 if (this->modulation_ == MOD_LORA) {
249 return 256;
250 } else {
251 return 64;
252 }
253}
254
255SX127xError SX127x::transmit_packet(const std::vector<uint8_t> &packet) {
256 if (this->payload_length_ > 0 && this->payload_length_ != packet.size()) {
257 ESP_LOGE(TAG, "Packet size does not match config");
259 }
260 if (packet.empty() || packet.size() > this->get_max_packet_size()) {
261 ESP_LOGE(TAG, "Packet size out of range");
263 }
264
266 if (this->modulation_ == MOD_LORA) {
267 this->set_mode_standby();
268 if (this->payload_length_ == 0) {
269 this->write_register_(REG_PAYLOAD_LENGTH, packet.size());
270 }
271 this->write_register_(REG_IRQ_FLAGS, 0xFF);
273 this->write_fifo_(packet);
274 this->set_mode_tx();
275 } else {
276 this->set_mode_standby();
277 if (this->payload_length_ == 0) {
278 this->write_register_(REG_FIFO, packet.size());
279 }
280 this->write_fifo_(packet);
281 this->set_mode_tx();
282 }
283
284 // wait until transmit completes, typically the delay will be less than 100 ms
285 uint32_t start = millis();
286 while (!this->dio0_pin_->digital_read()) {
287 if (millis() - start > 4000) {
288 ESP_LOGE(TAG, "Transmit packet failure");
290 break;
291 }
292 }
293 if (this->rx_start_) {
294 this->set_mode_rx();
295 } else {
296 this->set_mode_sleep();
297 }
298 return ret;
299}
300
301void SX127x::call_listeners_(const std::vector<uint8_t> &packet, float rssi, float snr) {
302 for (auto &listener : this->listeners_) {
303 listener->on_packet(packet, rssi, snr);
304 }
305 this->packet_trigger_->trigger(packet, rssi, snr);
306}
307
309 if (this->dio0_pin_ == nullptr || !this->dio0_pin_->digital_read()) {
310 return;
311 }
312
313 if (this->modulation_ == MOD_LORA) {
314 uint8_t status = this->read_register_(REG_IRQ_FLAGS);
315 this->write_register_(REG_IRQ_FLAGS, 0xFF);
316 if ((status & PAYLOAD_CRC_ERROR) == 0) {
317 uint8_t bytes = this->read_register_(REG_NB_RX_BYTES);
318 uint8_t addr = this->read_register_(REG_FIFO_RX_CURR_ADDR);
319 uint8_t rssi = this->read_register_(REG_PKT_RSSI_VALUE);
320 int8_t snr = (int8_t) this->read_register_(REG_PKT_SNR_VALUE);
321 this->packet_.resize(bytes);
323 this->read_fifo_(this->packet_);
324 if (this->frequency_ > 700000000) {
325 this->call_listeners_(this->packet_, (float) rssi - RSSI_OFFSET_HF, (float) snr / 4);
326 } else {
327 this->call_listeners_(this->packet_, (float) rssi - RSSI_OFFSET_LF, (float) snr / 4);
328 }
329 }
330 } else if (this->packet_mode_) {
331 uint8_t payload_length = this->payload_length_;
332 if (payload_length == 0) {
333 payload_length = this->read_register_(REG_FIFO);
334 }
335 this->packet_.resize(payload_length);
336 this->read_fifo_(this->packet_);
337 this->call_listeners_(this->packet_, 0.0f, 0.0f);
338 }
339}
340
342 if (this->modulation_ == MOD_LORA) {
345 }
346 if (this->auto_cal_) {
348 } else {
350 }
351 uint32_t start = millis();
353 if (millis() - start > 20) {
354 ESP_LOGE(TAG, "Image cal failure");
355 this->mark_failed();
356 break;
357 }
358 }
359 if (this->modulation_ == MOD_LORA) {
360 this->set_mode_(this->modulation_, MODE_SLEEP);
361 this->set_mode_(this->modulation_, MODE_STDBY);
362 }
363}
364
365void SX127x::set_mode_(uint8_t modulation, uint8_t mode) {
366 uint32_t start = millis();
367 this->write_register_(REG_OP_MODE, modulation | mode);
368 while (true) {
369 uint8_t curr = this->read_register_(REG_OP_MODE) & MODE_MASK;
370 if ((curr == mode) || (mode == MODE_RX && curr == MODE_RX_FS)) {
371 if (mode == MODE_SLEEP) {
372 this->write_register_(REG_OP_MODE, modulation | mode);
373 }
374 break;
375 }
376 if (millis() - start > 20) {
377 ESP_LOGE(TAG, "Set mode failure");
378 this->mark_failed();
379 break;
380 }
381 }
382}
383
385 this->set_mode_(this->modulation_, MODE_RX);
386 if (this->modulation_ == MOD_LORA) {
389 }
390}
391
393 this->set_mode_(this->modulation_, MODE_TX);
394 if (this->modulation_ == MOD_LORA) {
397 }
398}
399
401
403
405 ESP_LOGCONFIG(TAG, "SX127x:");
406 LOG_PIN(" CS Pin: ", this->cs_);
407 LOG_PIN(" RST Pin: ", this->rst_pin_);
408 LOG_PIN(" DIO0 Pin: ", this->dio0_pin_);
409 const char *pa_pin = "RFO";
410 if (this->pa_pin_ == PA_PIN_BOOST) {
411 pa_pin = "BOOST";
412 }
413 ESP_LOGCONFIG(TAG,
414 " Auto Cal: %s\n"
415 " Frequency: %" PRIu32 " Hz\n"
416 " Bandwidth: %" PRIu32 " Hz\n"
417 " PA Pin: %s\n"
418 " PA Power: %" PRIu8 " dBm\n"
419 " PA Ramp: %" PRIu16 " us",
420 TRUEFALSE(this->auto_cal_), this->frequency_, BW_HZ[this->bandwidth_], pa_pin, this->pa_power_,
421 RAMP[this->pa_ramp_]);
422 if (this->modulation_ == MOD_FSK) {
423 ESP_LOGCONFIG(TAG, " Deviation: %" PRIu32 " Hz", this->deviation_);
424 }
425 if (this->modulation_ == MOD_LORA) {
426 const char *cr = "4/8";
427 if (this->coding_rate_ == CODING_RATE_4_5) {
428 cr = "4/5";
429 } else if (this->coding_rate_ == CODING_RATE_4_6) {
430 cr = "4/6";
431 } else if (this->coding_rate_ == CODING_RATE_4_7) {
432 cr = "4/7";
433 }
434 ESP_LOGCONFIG(TAG,
435 " Modulation: LORA\n"
436 " Preamble Size: %" PRIu16 "\n"
437 " Spreading Factor: %" PRIu8 "\n"
438 " Coding Rate: %s\n"
439 " CRC Enable: %s",
440 this->preamble_size_, this->spreading_factor_, cr, TRUEFALSE(this->crc_enable_));
441 if (this->payload_length_ > 0) {
442 ESP_LOGCONFIG(TAG, " Payload Length: %" PRIu32, this->payload_length_);
443 }
444 if (!this->sync_value_.empty()) {
445 ESP_LOGCONFIG(TAG, " Sync Value: 0x%02x", this->sync_value_[0]);
446 }
447 } else {
448 const char *shaping = "NONE";
449 if (this->modulation_ == MOD_FSK) {
450 if (this->shaping_ == GAUSSIAN_BT_0_3) {
451 shaping = "GAUSSIAN_BT_0_3";
452 } else if (this->shaping_ == GAUSSIAN_BT_0_5) {
453 shaping = "GAUSSIAN_BT_0_5";
454 } else if (this->shaping_ == GAUSSIAN_BT_1_0) {
455 shaping = "GAUSSIAN_BT_1_0";
456 }
457 } else {
458 if (this->shaping_ == CUTOFF_BR_X_2) {
459 shaping = "CUTOFF_BR_X_2";
460 } else if (this->shaping_ == CUTOFF_BR_X_1) {
461 shaping = "CUTOFF_BR_X_1";
462 }
463 }
464 ESP_LOGCONFIG(TAG,
465 " Shaping: %s\n"
466 " Modulation: %s\n"
467 " Bitrate: %" PRIu32 "b/s\n"
468 " Bitsync: %s\n"
469 " Rx Start: %s\n"
470 " Rx Floor: %.1f dBm\n"
471 " Packet Mode: %s",
472 shaping, this->modulation_ == MOD_FSK ? "FSK" : "OOK", this->bitrate_, TRUEFALSE(this->bitsync_),
473 TRUEFALSE(this->rx_start_), this->rx_floor_, TRUEFALSE(this->packet_mode_));
474 if (this->packet_mode_) {
475 ESP_LOGCONFIG(TAG, " CRC Enable: %s", TRUEFALSE(this->crc_enable_));
476 }
477 if (this->payload_length_ > 0) {
478 ESP_LOGCONFIG(TAG, " Payload Length: %" PRIu32, this->payload_length_);
479 }
480 if (!this->sync_value_.empty()) {
481 ESP_LOGCONFIG(TAG, " Sync Value: 0x%s", format_hex(this->sync_value_).c_str());
482 }
483 if (this->preamble_size_ > 0 || this->preamble_detect_ > 0) {
484 ESP_LOGCONFIG(TAG,
485 " Preamble Polarity: 0x%X\n"
486 " Preamble Size: %" PRIu16 "\n"
487 " Preamble Detect: %" PRIu8 "\n"
488 " Preamble Errors: %" PRIu8,
490 }
491 }
492 if (this->is_failed()) {
493 ESP_LOGE(TAG, "Configuring SX127x failed");
494 }
495}
496
497} // namespace sx127x
498} // namespace esphome
BedjetMode mode
BedJet operating mode.
uint8_t status
Definition bl0942.h:8
virtual void mark_failed()
Mark this component as failed.
bool is_failed() const
virtual void setup()=0
virtual void digital_write(bool value)=0
virtual bool digital_read()=0
void trigger(Ts... x)
Inform the parent automation that the event has triggered.
Definition automation.h:145
InternalGPIOPin * rst_pin_
Definition sx127x.h:102
uint8_t preamble_polarity_
Definition sx127x.h:116
InternalGPIOPin * dio0_pin_
Definition sx127x.h:101
Trigger< std::vector< uint8_t >, float, float > * packet_trigger_
Definition sx127x.h:97
std::vector< SX127xListener * > listeners_
Definition sx127x.h:98
void write_fifo_(const std::vector< uint8_t > &packet)
Definition sx127x.cpp:45
SX127xError transmit_packet(const std::vector< uint8_t > &packet)
Definition sx127x.cpp:255
std::vector< uint8_t > sync_value_
Definition sx127x.h:100
uint32_t payload_length_
Definition sx127x.h:107
void dump_config() override
Definition sx127x.cpp:404
uint8_t read_register_(uint8_t reg)
Definition sx127x.cpp:23
void loop() override
Definition sx127x.cpp:308
void set_mode_(uint8_t modulation, uint8_t mode)
Definition sx127x.cpp:365
void read_fifo_(std::vector< uint8_t > &packet)
Definition sx127x.cpp:38
uint16_t preamble_size_
Definition sx127x.h:108
std::vector< uint8_t > packet_
Definition sx127x.h:99
size_t get_max_packet_size()
Definition sx127x.cpp:244
void write_register_(uint8_t reg, uint8_t value)
Definition sx127x.cpp:31
void call_listeners_(const std::vector< uint8_t > &packet, float rssi, float snr)
Definition sx127x.cpp:301
void setup() override
Definition sx127x.cpp:52
uint8_t spreading_factor_
Definition sx127x.h:118
uint8_t duration
Definition msa3xx.h:0
const char *const TAG
Definition spi.cpp:8
@ PREAMBLE_DETECTOR_TOL_SHIFT
Definition sx127x_reg.h:209
@ PREAMBLE_DETECTOR_SIZE_SHIFT
Definition sx127x_reg.h:208
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string format_hex(const uint8_t *data, size_t length)
Format the byte array data of length len in lowercased hex.
Definition helpers.cpp:249
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)
Definition core.cpp:31
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:28