diff --git a/esphome/components/sx127x/__init__.py b/esphome/components/sx127x/__init__.py index 1568c310cf..6bc55a97cd 100644 --- a/esphome/components/sx127x/__init__.py +++ b/esphome/components/sx127x/__init__.py @@ -1,23 +1,34 @@ -from esphome import pins +from esphome import automation, pins import esphome.codegen as cg from esphome.components import spi import esphome.config_validation as cv from esphome.const import CONF_FREQUENCY, CONF_ID +from esphome.core import TimePeriod CODEOWNERS = ["@swoboda1337"] DEPENDENCIES = ["spi"] CONF_PA_POWER = "pa_power" CONF_PA_PIN = "pa_pin" +CONF_DIO0_PIN = "dio0_pin" +CONF_DIO2_PIN = "dio2_pin" CONF_NSS_PIN = "nss_pin" CONF_RST_PIN = "rst_pin" CONF_MODULATION = "modulation" +CONF_SHAPING = "shaping" CONF_RX_FLOOR = "rx_floor" CONF_RX_START = "rx_start" CONF_RX_BANDWIDTH = "rx_bandwidth" +CONF_RX_DURATION = "rx_duration" +CONF_BITRATE = "bitrate" +CONF_PAYLOAD_LENGTH = "payload_length" +CONF_PREAMBLE_SIZE = "preamble_size" +CONF_PREAMBLE_POLARITY = "preamble_polarity" +CONF_PREAMBLE_ERRORS = "preamble_errors" +CONF_SYNC_VALUE = "sync_value" CONF_FSK_FDEV = "fsk_fdev" CONF_FSK_RAMP = "fsk_ramp" -CONF_FSK_SHAPING = "fsk_shaping" +CONF_ON_PACKET = "on_packet" sx127x_ns = cg.esphome_ns.namespace("sx127x") SX127x = sx127x_ns.class_("SX127x", cg.Component, spi.SPIDevice) @@ -32,10 +43,12 @@ PA_PIN = { } SHAPING = { - "BT_0_3": SX127xPaRamp.SHAPING_BT_0_3, - "BT_0_5": SX127xPaRamp.SHAPING_BT_0_5, - "BT_1_0": SX127xPaRamp.SHAPING_BT_1_0, - "NONE": SX127xPaRamp.SHAPING_NONE, + "CUTOFF_BR_X_2": SX127xPaRamp.CUTOFF_BR_X_2, + "CUTOFF_BR_X_1": SX127xPaRamp.CUTOFF_BR_X_1, + "GAUSSIAN_BT_0_3": SX127xPaRamp.GAUSSIAN_BT_0_3, + "GAUSSIAN_BT_0_5": SX127xPaRamp.GAUSSIAN_BT_0_5, + "GAUSSIAN_BT_1_0": SX127xPaRamp.GAUSSIAN_BT_1_0, + "NO_SHAPING": SX127xPaRamp.NO_SHAPING, } RAMP = { @@ -89,18 +102,33 @@ RX_BW = { CONFIG_SCHEMA = cv.Schema( { cv.GenerateID(): cv.declare_id(SX127x), + cv.Optional(CONF_DIO0_PIN): pins.internal_gpio_input_pin_schema, + cv.Optional(CONF_DIO2_PIN): pins.internal_gpio_input_pin_schema, cv.Required(CONF_RST_PIN): pins.internal_gpio_output_pin_schema, cv.Required(CONF_NSS_PIN): pins.internal_gpio_output_pin_schema, cv.Required(CONF_FREQUENCY): cv.int_range(min=137000000, max=1020000000), cv.Required(CONF_MODULATION): cv.enum(MOD), + cv.Optional(CONF_SHAPING, default="NO_SHAPING"): cv.enum(SHAPING), + cv.Optional(CONF_BITRATE, default=0): cv.int_range(min=0, max=300000), cv.Optional(CONF_FSK_FDEV, default=5000): cv.int_range(min=0, max=100000), cv.Optional(CONF_FSK_RAMP, default="40us"): cv.enum(RAMP), - cv.Optional(CONF_FSK_SHAPING, default="NONE"): cv.enum(SHAPING), + cv.Optional(CONF_SYNC_VALUE, default=[]): cv.ensure_list(cv.hex_uint8_t), + cv.Optional(CONF_PAYLOAD_LENGTH, default=0): cv.int_range(min=0, max=64), + cv.Optional(CONF_PREAMBLE_SIZE, default=0): cv.int_range(min=0, max=7), + cv.Optional(CONF_PREAMBLE_POLARITY, default=0xAA): cv.All( + cv.hex_int, cv.one_of(0xAA, 0x55) + ), + cv.Optional(CONF_PREAMBLE_ERRORS, default=0): cv.int_range(min=0, max=31), cv.Optional(CONF_RX_FLOOR, default=-94): cv.float_range(min=-128, max=-1), cv.Optional(CONF_RX_START, default=True): cv.boolean, cv.Optional(CONF_RX_BANDWIDTH, default="50_0kHz"): cv.enum(RX_BW), + cv.Optional(CONF_RX_DURATION, default="0ms"): cv.All( + cv.positive_time_period_microseconds, + cv.Range(max=TimePeriod(microseconds=1000000000)), + ), cv.Optional(CONF_PA_PIN, default="BOOST"): cv.enum(PA_PIN), cv.Optional(CONF_PA_POWER, default=17): cv.int_range(min=0, max=17), + cv.Optional(CONF_ON_PACKET): automation.validate_automation(single=True), } ).extend(spi.spi_device_schema(False, 8e6, "mode0")) @@ -109,17 +137,36 @@ async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) await spi.register_spi_device(var, config) + if CONF_ON_PACKET in config: + await automation.build_automation( + var.get_packet_trigger(), + [(cg.std_vector.template(cg.uint8), "x")], + config[CONF_ON_PACKET], + ) + if CONF_DIO0_PIN in config: + dio0_pin = await cg.gpio_pin_expression(config[CONF_DIO0_PIN]) + cg.add(var.set_dio0_pin(dio0_pin)) + if CONF_DIO2_PIN in config: + dio2_pin = await cg.gpio_pin_expression(config[CONF_DIO2_PIN]) + cg.add(var.set_dio2_pin(dio2_pin)) rst_pin = await cg.gpio_pin_expression(config[CONF_RST_PIN]) cg.add(var.set_rst_pin(rst_pin)) nss_pin = await cg.gpio_pin_expression(config[CONF_NSS_PIN]) cg.add(var.set_nss_pin(nss_pin)) cg.add(var.set_frequency(config[CONF_FREQUENCY])) cg.add(var.set_modulation(config[CONF_MODULATION])) + cg.add(var.set_shaping(config[CONF_SHAPING])) + cg.add(var.set_bitrate(config[CONF_BITRATE])) + cg.add(var.set_payload_length(config[CONF_PAYLOAD_LENGTH])) + cg.add(var.set_preamble_size(config[CONF_PREAMBLE_SIZE])) + cg.add(var.set_preamble_polarity(config[CONF_PREAMBLE_POLARITY])) + cg.add(var.set_preamble_errors(config[CONF_PREAMBLE_ERRORS])) + cg.add(var.set_sync_value(config[CONF_SYNC_VALUE])) cg.add(var.set_rx_floor(config[CONF_RX_FLOOR])) cg.add(var.set_rx_start(config[CONF_RX_START])) cg.add(var.set_rx_bandwidth(config[CONF_RX_BANDWIDTH])) + cg.add(var.set_rx_duration(config[CONF_RX_DURATION])) cg.add(var.set_pa_pin(config[CONF_PA_PIN])) cg.add(var.set_pa_power(config[CONF_PA_POWER])) cg.add(var.set_fsk_fdev(config[CONF_FSK_FDEV])) cg.add(var.set_fsk_ramp(config[CONF_FSK_RAMP])) - cg.add(var.set_fsk_shaping(config[CONF_FSK_SHAPING])) diff --git a/esphome/components/sx127x/sx127x.cpp b/esphome/components/sx127x/sx127x.cpp index 5672d007c0..773ac10503 100644 --- a/esphome/components/sx127x/sx127x.cpp +++ b/esphome/components/sx127x/sx127x.cpp @@ -7,7 +7,15 @@ namespace sx127x { static const char *const TAG = "sx127x"; -uint8_t SX127x::read_register_(uint8_t reg) { return this->single_transfer_((uint8_t) reg & 0x7f, 0x00); } +void IRAM_ATTR HOT SX127xStore::gpio_intr(SX127xStore *arg) { + if (arg->dio2_toggle) { + arg->dio2_pin.pin_mode(gpio::FLAG_INPUT); + } + arg->dio0_micros = micros(); + arg->dio0_irq = true; +} + +uint8_t SX127x::read_register_(uint8_t reg) { return this->single_transfer_((uint8_t) reg & 0x7F, 0x00); } void SX127x::write_register_(uint8_t reg, uint8_t value) { this->single_transfer_((uint8_t) reg | 0x80, value); } @@ -22,6 +30,28 @@ uint8_t SX127x::single_transfer_(uint8_t reg, uint8_t value) { return response; } +void SX127x::read_fifo_(std::vector &packet) { + this->delegate_->begin_transaction(); + this->nss_pin_->digital_write(false); + this->delegate_->transfer(REG_FIFO & 0x7F); + for (uint32_t i = 0; i < this->payload_length_; i++) { + packet.push_back(this->delegate_->transfer(0x00)); + } + this->nss_pin_->digital_write(true); + this->delegate_->end_transaction(); +} + +void SX127x::write_fifo_(const std::vector &packet) { + this->delegate_->begin_transaction(); + this->nss_pin_->digital_write(false); + this->delegate_->transfer(REG_FIFO | 0x80); + for (uint32_t i = 0; i < this->payload_length_; i++) { + this->delegate_->transfer(packet[i]); + } + this->nss_pin_->digital_write(true); + this->delegate_->end_transaction(); +} + void SX127x::setup() { ESP_LOGCONFIG(TAG, "Setting up SX127x..."); @@ -32,6 +62,20 @@ void SX127x::setup() { // setup reset this->rst_pin_->setup(); + // setup dio0 + if (this->dio0_pin_) { + this->dio0_pin_->setup(); + this->dio0_pin_->attach_interrupt(SX127xStore::gpio_intr, &this->store_, gpio::INTERRUPT_RISING_EDGE); + } + + // setup dio2 + if (this->dio2_pin_) { + this->dio2_pin_->setup(); + this->dio2_pin_->pin_mode(gpio::FLAG_OPEN_DRAIN); + this->store_.dio2_pin = this->dio2_pin_->to_isr(); + this->store_.dio2_toggle = true; + } + // start spi this->spi_setup(); @@ -40,6 +84,8 @@ void SX127x::setup() { } void SX127x::configure() { + uint8_t bit_sync = BIT_SYNC_OFF; + // toggle chip reset this->rst_pin_->digital_write(false); delay(1); @@ -53,7 +99,7 @@ void SX127x::configure() { } // set modulation and make sure transceiver is in sleep mode - this->write_register_(REG_OP_MODE, this->modulation_ | MODE_LF_ON | MODE_SLEEP); + this->write_register_(REG_OP_MODE, this->modulation_ | MODE_SLEEP); delay(1); // set freq @@ -70,6 +116,47 @@ void SX127x::configure() { // set the channel bw this->write_register_(REG_RX_BW, this->rx_bandwidth_); + // set bitrate + if (this->bitrate_ > 0) { + uint64_t bitrate = (32000000u + this->bitrate_ / 2) / this->bitrate_; + this->write_register_(REG_BITRATE_MSB, (uint8_t) ((bitrate >> 8) & 0xFF)); + this->write_register_(REG_BITRATE_LSB, (uint8_t) ((bitrate >> 0) & 0xFF)); + bit_sync = BIT_SYNC_ON; + } + + // configure dio mapping + if (this->payload_length_ > 0) { + this->write_register_(REG_DIO_MAPPING1, DIO0_MAPPING_00); + } else if (this->rx_duration_ > 0) { + this->write_register_(REG_DIO_MAPPING1, DIO0_MAPPING_01); + } else { + this->write_register_(REG_DIO_MAPPING1, DIO0_MAPPING_11); + } + if (this->preamble_size_ > 0) { + this->write_register_(REG_DIO_MAPPING2, MAP_PREAMBLE_INT); + } else { + this->write_register_(REG_DIO_MAPPING2, MAP_RSSI_INT); + } + + // configure rx and afc + uint8_t trigger = (this->preamble_size_ > 0) ? TRIGGER_PREAMBLE : TRIGGER_RSSI; + this->write_register_(REG_AFC_FEI, AFC_AUTO_CLEAR_ON); + if (this->modulation_ == MOD_FSK) { + this->rx_config_ = AFC_AUTO_ON | AGC_AUTO_ON | trigger; + } else { + this->rx_config_ = AGC_AUTO_ON | trigger; + } + this->write_register_(REG_RX_CONFIG, this->rx_config_); + + // configure packet mode + this->write_register_(REG_PACKET_CONFIG_1, 0x00); + if (this->payload_length_ > 0) { + this->write_register_(REG_PACKET_CONFIG_2, PACKET_MODE); + } else { + this->write_register_(REG_PACKET_CONFIG_2, CONTINUOUS_MODE); + } + this->write_register_(REG_PAYLOAD_LENGTH, this->payload_length_); + // config pa if (this->pa_pin_ == PA_PIN_BOOST) { this->pa_power_ = std::max(this->pa_power_, (uint32_t) 2); @@ -79,23 +166,42 @@ void SX127x::configure() { this->pa_power_ = std::min(this->pa_power_, (uint32_t) 14); this->write_register_(REG_PA_CONFIG, (this->pa_power_ - 0) | this->pa_pin_ | PA_MAX_POWER); } - if (this->modulation_ == MOD_FSK) { - this->write_register_(REG_PA_RAMP, this->fsk_ramp_ | this->fsk_shaping_); + this->write_register_(REG_PA_RAMP, this->shaping_ | this->fsk_ramp_); + this->write_register_(REG_FIFO_THRESH, TX_START_FIFO_EMPTY); + + // config bit synchronizer + if (this->sync_value_.size() > 0) { + uint8_t polarity = (this->preamble_polarity_ == 0xAA) ? PREAMBLE_AA : PREAMBLE_55; + uint8_t size = this->sync_value_.size() - 1; + this->write_register_(REG_SYNC_CONFIG, SYNC_ON | polarity | size); + for (uint32_t i = 0; i < this->sync_value_.size(); i++) { + this->write_register_(REG_SYNC_VALUE1 + i, this->sync_value_[i]); + } } else { - this->write_register_(REG_PA_RAMP, this->fsk_ramp_); + this->write_register_(REG_SYNC_CONFIG, SYNC_OFF); } - // disable packet mode - this->write_register_(REG_PACKET_CONFIG_1, 0x00); - this->write_register_(REG_PACKET_CONFIG_2, 0x00); + // config preamble detector + if (this->preamble_size_ > 0 && this->preamble_size_ < 4) { + uint8_t size = (this->preamble_size_ - 1) << PREAMBLE_BYTES_SHIFT; + uint8_t errors = this->preamble_errors_; + this->write_register_(REG_PREAMBLE_DETECT, PREAMBLE_DETECTOR_ON | size | errors); + } else { + this->write_register_(REG_PREAMBLE_DETECT, PREAMBLE_DETECTOR_OFF); + } + this->write_register_(REG_PREAMBLE_MSB, 0); + this->write_register_(REG_PREAMBLE_LSB, this->preamble_size_); - // disable bit synchronizer, disable sync generation and setup threshold - this->write_register_(REG_SYNC_CONFIG, 0x00); - this->write_register_(REG_OOK_PEAK, OOK_THRESH_STEP_0_5 | OOK_THRESH_PEAK); + // config sync generation and setup ook threshold + this->write_register_(REG_OOK_PEAK, bit_sync | OOK_THRESH_STEP_0_5 | OOK_THRESH_PEAK); this->write_register_(REG_OOK_AVG, OOK_THRESH_DEC_1_8); - // set ook floor + // set rx floor this->write_register_(REG_OOK_FIX, 256 + int(this->rx_floor_ * 2.0)); + this->write_register_(REG_RSSI_THRESH, std::abs(int(this->rx_floor_ * 2.0))); + + // clear irq flag + this->store_.dio0_irq = false; // enable standby mode this->set_mode_standby(); @@ -108,18 +214,68 @@ void SX127x::configure() { } } -void SX127x::set_mode_standby() { this->write_register_(REG_OP_MODE, this->modulation_ | MODE_LF_ON | MODE_STDBY); } +void SX127x::transmit_packet(const std::vector &packet) { + this->write_register_(REG_OP_MODE, this->modulation_ | MODE_STDBY); + delay(1); + this->write_fifo_(packet); + this->write_register_(REG_OP_MODE, this->modulation_ | MODE_TX_FS); + delay(1); + this->write_register_(REG_OP_MODE, this->modulation_ | MODE_TX); + while (!this->store_.dio0_irq) + ; + this->write_register_(REG_OP_MODE, this->modulation_ | MODE_STDBY); + delay(1); + if (this->rx_start_) { + this->set_mode_rx(); + delay(1); + } +} + +void SX127x::loop() { + if (this->store_.dio0_irq) { + if (this->payload_length_ > 0) { + // read packet, reset the receiver and call the trigger + std::vector packet; + this->read_fifo_(packet); + this->store_.dio0_irq = false; + this->write_register_(REG_RX_CONFIG, RESTART_PLL_LOCK | this->rx_config_); + this->packet_trigger_->trigger(packet); + } else { + // wait until rx duration expires then reset rx and change dio2 mode to avoid overloading + // remote receiver with too much noise + if ((micros() - this->store_.dio0_micros) >= this->rx_duration_) { + if (this->dio2_pin_) { + this->dio2_pin_->pin_mode(gpio::FLAG_OPEN_DRAIN); + } + this->store_.dio0_irq = false; + this->write_register_(REG_RX_CONFIG, RESTART_PLL_LOCK | this->rx_config_); + } + } + } +} + +void SX127x::set_mode_standby() { this->write_register_(REG_OP_MODE, this->modulation_ | MODE_STDBY); } void SX127x::set_mode_rx() { - this->write_register_(REG_OP_MODE, this->modulation_ | MODE_LF_ON | MODE_RX_FS); + if (this->dio2_pin_) { + this->write_register_(REG_OP_MODE, this->modulation_ | MODE_STDBY); + delay(1); + this->dio2_pin_->pin_mode(this->modulation_ == MOD_OOK ? gpio::FLAG_INPUT : gpio::FLAG_OPEN_DRAIN); + } + this->write_register_(REG_OP_MODE, this->modulation_ | MODE_RX_FS); delay(1); - this->write_register_(REG_OP_MODE, this->modulation_ | MODE_LF_ON | MODE_RX); + this->write_register_(REG_OP_MODE, this->modulation_ | MODE_RX); } void SX127x::set_mode_tx() { - this->write_register_(REG_OP_MODE, this->modulation_ | MODE_LF_ON | MODE_TX_FS); + if (this->dio2_pin_) { + this->write_register_(REG_OP_MODE, this->modulation_ | MODE_STDBY); + delay(1); + this->dio2_pin_->pin_mode(gpio::FLAG_OUTPUT); + } + this->write_register_(REG_OP_MODE, this->modulation_ | MODE_TX_FS); delay(1); - this->write_register_(REG_OP_MODE, this->modulation_ | MODE_LF_ON | MODE_TX); + this->write_register_(REG_OP_MODE, this->modulation_ | MODE_TX); } void SX127x::dump_config() { @@ -130,24 +286,33 @@ void SX127x::dump_config() { ESP_LOGCONFIG(TAG, "SX127x:"); LOG_PIN(" NSS Pin: ", this->nss_pin_); LOG_PIN(" RST Pin: ", this->rst_pin_); - ESP_LOGCONFIG(TAG, " PA Pin: %s", this->pa_pin_ == PA_PIN_BOOST ? "BOOST" : "RFO"); - ESP_LOGCONFIG(TAG, " PA Power: %" PRIu32 " dBm", this->pa_power_); + LOG_PIN(" DIO0 Pin: ", this->dio0_pin_); + LOG_PIN(" DIO2 Pin: ", this->dio2_pin_); ESP_LOGCONFIG(TAG, " Frequency: %f MHz", (float) this->frequency_ / 1000000); ESP_LOGCONFIG(TAG, " Modulation: %s", this->modulation_ == MOD_FSK ? "FSK" : "OOK"); + ESP_LOGCONFIG(TAG, " Bitrate: %" PRIu32 "b/s", this->bitrate_); + ESP_LOGCONFIG(TAG, " Rx Duration: %" PRIu32 " us", this->rx_duration_); ESP_LOGCONFIG(TAG, " Rx Bandwidth: %.1f kHz", (float) rx_bw / 1000); ESP_LOGCONFIG(TAG, " Rx Start: %s", this->rx_start_ ? "true" : "false"); ESP_LOGCONFIG(TAG, " Rx Floor: %.1f dBm", this->rx_floor_); + ESP_LOGCONFIG(TAG, " Payload Length: %" PRIu32, this->payload_length_); + ESP_LOGCONFIG(TAG, " Preamble Polarity: 0x%X", this->preamble_polarity_); + ESP_LOGCONFIG(TAG, " Preamble Size: %" PRIu8, this->preamble_size_); + ESP_LOGCONFIG(TAG, " Preamble Errors: %" PRIu8, this->preamble_errors_); + if (this->sync_value_.size() > 0) { + ESP_LOGCONFIG(TAG, " Sync Value: 0x%s", format_hex(this->sync_value_).c_str()); + } + if (this->modulation_ == MOD_FSK) { + static const char *SHAPING_LUT[4] = {"NO_SHAPING", "GAUSSIAN_BT_1_0", "GAUSSIAN_BT_0_5", "GAUSSIAN_BT_0_3"}; + ESP_LOGCONFIG(TAG, " Shaping: %s", SHAPING_LUT[this->shaping_ >> 5]); + } else { + static const char *SHAPING_LUT[4] = {"NO_SHAPING", "CUTOFF_BR_X_1", "CUTOFF_BR_X_2", "ERROR"}; + ESP_LOGCONFIG(TAG, " Shaping: %s", SHAPING_LUT[this->shaping_ >> 5]); + } + ESP_LOGCONFIG(TAG, " PA Pin: %s", this->pa_pin_ == PA_PIN_BOOST ? "BOOST" : "RFO"); + ESP_LOGCONFIG(TAG, " PA Power: %" PRIu32 " dBm", this->pa_power_); ESP_LOGCONFIG(TAG, " FSK Fdev: %" PRIu32 " Hz", this->fsk_fdev_); ESP_LOGCONFIG(TAG, " FSK Ramp: %" PRIu16 " us", RAMP_LUT[this->fsk_ramp_]); - if (this->fsk_shaping_ == SHAPING_BT_1_0) { - ESP_LOGCONFIG(TAG, " FSK Shaping: BT_1_0"); - } else if (this->fsk_shaping_ == SHAPING_BT_0_5) { - ESP_LOGCONFIG(TAG, " FSK Shaping: BT_0_5"); - } else if (this->fsk_shaping_ == SHAPING_BT_0_3) { - ESP_LOGCONFIG(TAG, " FSK Shaping: BT_0_3"); - } else { - ESP_LOGCONFIG(TAG, " FSK Shaping: NONE"); - } if (this->is_failed()) { ESP_LOGE(TAG, "Configuring SX127x failed"); } diff --git a/esphome/components/sx127x/sx127x.h b/esphome/components/sx127x/sx127x.h index aaa4b41eab..b01fbcac96 100644 --- a/esphome/components/sx127x/sx127x.h +++ b/esphome/components/sx127x/sx127x.h @@ -1,12 +1,20 @@ #pragma once #include "esphome/components/spi/spi.h" +#include "esphome/core/automation.h" +#include "esphome/core/component.h" +#include "esphome/core/hal.h" +#include "esphome/core/log.h" +#include namespace esphome { namespace sx127x { enum SX127xReg : uint8_t { + REG_FIFO = 0x00, REG_OP_MODE = 0x01, + REG_BITRATE_MSB = 0x02, + REG_BITRATE_LSB = 0x03, REG_FDEV_MSB = 0x04, REG_FDEV_LSB = 0x05, REG_FRF_MSB = 0x06, @@ -14,16 +22,64 @@ enum SX127xReg : uint8_t { REG_FRF_LSB = 0x08, REG_PA_CONFIG = 0x09, REG_PA_RAMP = 0x0A, + REG_RX_CONFIG = 0x0D, + REG_RSSI_THRESH = 0x10, REG_RX_BW = 0x12, REG_OOK_PEAK = 0x14, REG_OOK_FIX = 0x15, REG_OOK_AVG = 0x16, + REG_AFC_FEI = 0x1A, + REG_PREAMBLE_DETECT = 0x1F, + REG_PREAMBLE_MSB = 0x25, + REG_PREAMBLE_LSB = 0x26, REG_SYNC_CONFIG = 0x27, + REG_SYNC_VALUE1 = 0x28, + REG_SYNC_VALUE2 = 0x29, + REG_SYNC_VALUE3 = 0x2A, + REG_SYNC_VALUE4 = 0x2B, + REG_SYNC_VALUE5 = 0x2C, + REG_SYNC_VALUE6 = 0x2D, + REG_SYNC_VALUE7 = 0x2E, + REG_SYNC_VALUE8 = 0x2F, REG_PACKET_CONFIG_1 = 0x30, REG_PACKET_CONFIG_2 = 0x31, + REG_PAYLOAD_LENGTH = 0x32, + REG_FIFO_THRESH = 0x35, + REG_DIO_MAPPING1 = 0x40, + REG_DIO_MAPPING2 = 0x41, REG_VERSION = 0x42 }; +enum SX127xRxConfig : uint8_t { + RESTART_NO_LOCK = 0x40, + RESTART_PLL_LOCK = 0x20, + AFC_AUTO_ON = 0x10, + AGC_AUTO_ON = 0x08, + TRIGGER_NONE = 0x00, + TRIGGER_RSSI = 0x01, + TRIGGER_PREAMBLE = 0x06, + TRIGGER_ALL = 0x07, +}; + +enum SX127xFifoThresh : uint8_t { + TX_START_FIFO_EMPTY = 0x80, + TX_START_FIFO_LEVEL = 0x00, +}; + +enum SX127xAfcFei : uint8_t { + AFC_AUTO_CLEAR_ON = 0x01, +}; + +enum SX127xSyncConfig : uint8_t { + AUTO_RESTART_OFF = 0x00, + AUTO_RESTART_NO_LOCK = 0x80, + AUTO_RESTART_PLL_LOCK = 0x40, + PREAMBLE_AA = 0x00, + PREAMBLE_55 = 0x20, + SYNC_OFF = 0x00, + SYNC_ON = 0x10, +}; + enum SX127xOpMode : uint8_t { MOD_FSK = 0x00, MOD_OOK = 0x20, @@ -36,6 +92,35 @@ enum SX127xOpMode : uint8_t { MODE_SLEEP = 0x00 }; +enum SX127xDioMapping1 : uint8_t { + DIO0_MAPPING_00 = 0x00, + DIO0_MAPPING_01 = 0x40, + DIO0_MAPPING_10 = 0x80, + DIO0_MAPPING_11 = 0xC0, + DIO1_MAPPING_00 = 0x00, + DIO1_MAPPING_01 = 0x10, + DIO1_MAPPING_10 = 0x20, + DIO1_MAPPING_11 = 0x30, + DIO2_MAPPING_00 = 0x00, + DIO2_MAPPING_01 = 0x04, + DIO2_MAPPING_10 = 0x08, + DIO2_MAPPING_11 = 0x0C, +}; + +enum SX127xPreambleDetect : uint8_t { + PREAMBLE_DETECTOR_ON = 0x80, + PREAMBLE_DETECTOR_OFF = 0x00, + PREAMBLE_BYTES_1 = 0x00, + PREAMBLE_BYTES_2 = 0x20, + PREAMBLE_BYTES_3 = 0x40, + PREAMBLE_BYTES_SHIFT = 0x05, +}; + +enum SX127xDioMapping2 : uint8_t { + MAP_PREAMBLE_INT = 0x01, + MAP_RSSI_INT = 0x00, +}; + enum SX127xOokPeak : uint8_t { BIT_SYNC_ON = 0x20, BIT_SYNC_OFF = 0x00, @@ -63,6 +148,11 @@ enum SX127xOokAvg : uint8_t { OOK_THRESH_DEC_1 = 0x00 }; +enum SX127xPacketConfig2 : uint8_t { + CONTINUOUS_MODE = 0x00, + PACKET_MODE = 0x40, +}; + enum SX127xRxBw : uint8_t { RX_BW_2_6 = 0x17, RX_BW_3_1 = 0x0F, @@ -88,10 +178,12 @@ enum SX127xRxBw : uint8_t { }; enum SX127xPaRamp : uint8_t { - SHAPING_BT_0_3 = 0x60, - SHAPING_BT_0_5 = 0x40, - SHAPING_BT_1_0 = 0x20, - SHAPING_NONE = 0x00, + CUTOFF_BR_X_2 = 0x40, + CUTOFF_BR_X_1 = 0x20, + GAUSSIAN_BT_0_3 = 0x60, + GAUSSIAN_BT_0_5 = 0x40, + GAUSSIAN_BT_1_0 = 0x20, + NO_SHAPING = 0x00, PA_RAMP_10 = 0x0F, PA_RAMP_12 = 0x0E, PA_RAMP_15 = 0x0D, @@ -110,6 +202,14 @@ enum SX127xPaRamp : uint8_t { PA_RAMP_3400 = 0x00 }; +struct SX127xStore { + static void gpio_intr(SX127xStore *arg); + volatile uint32_t dio0_micros{0}; + volatile bool dio0_irq{false}; + volatile bool dio2_toggle{false}; + ISRInternalGPIOPin dio2_pin; +}; + enum SX127xPaConfig : uint8_t { PA_PIN_RFO = 0x00, PA_PIN_BOOST = 0x80, PA_MAX_POWER = 0x70 }; class SX127x : public Component, @@ -118,38 +218,64 @@ class SX127x : public Component, public: float get_setup_priority() const override { return setup_priority::HARDWARE; } void setup() override; + void loop() override; void dump_config() override; + void set_dio0_pin(InternalGPIOPin *dio0_pin) { this->dio0_pin_ = dio0_pin; } + void set_dio2_pin(InternalGPIOPin *dio2_pin) { this->dio2_pin_ = dio2_pin; } void set_rst_pin(InternalGPIOPin *rst_pin) { this->rst_pin_ = rst_pin; } void set_nss_pin(InternalGPIOPin *nss_pin) { this->nss_pin_ = nss_pin; } void set_frequency(uint32_t frequency) { this->frequency_ = frequency; } + void set_bitrate(uint32_t bitrate) { this->bitrate_ = bitrate; } void set_modulation(SX127xOpMode modulation) { this->modulation_ = modulation; } - void set_fsk_shaping(SX127xPaRamp shaping) { this->fsk_shaping_ = shaping; } + void set_shaping(SX127xPaRamp shaping) { this->shaping_ = shaping; } void set_fsk_ramp(SX127xPaRamp ramp) { this->fsk_ramp_ = ramp; } void set_fsk_fdev(uint32_t fdev) { this->fsk_fdev_ = fdev; } void set_rx_start(bool start) { this->rx_start_ = start; } void set_rx_floor(float floor) { this->rx_floor_ = floor; } void set_rx_bandwidth(SX127xRxBw bandwidth) { this->rx_bandwidth_ = bandwidth; } + void set_rx_duration(uint32_t duration) { this->rx_duration_ = duration; } void set_pa_pin(SX127xPaConfig pin) { this->pa_pin_ = pin; } void set_pa_power(uint32_t power) { this->pa_power_ = power; } + void set_sync_value(const std::vector &sync_value) { this->sync_value_ = sync_value; } + void set_payload_length(uint8_t payload_length) { this->payload_length_ = payload_length; } + void set_preamble_polarity(uint8_t preamble_polarity) { this->preamble_polarity_ = preamble_polarity; } + void set_preamble_size(uint8_t preamble_size) { this->preamble_size_ = preamble_size; } + void set_preamble_errors(uint8_t preamble_errors) { this->preamble_errors_ = preamble_errors; } void set_mode_standby(); void set_mode_tx(); void set_mode_rx(); void configure(); + void transmit_packet(const std::vector &packet); + Trigger> *get_packet_trigger() const { return this->packet_trigger_; }; protected: + void write_fifo_(const std::vector &packet); + void read_fifo_(std::vector &packet); void write_register_(uint8_t reg, uint8_t value); uint8_t single_transfer_(uint8_t reg, uint8_t value); uint8_t read_register_(uint8_t reg); + Trigger> *packet_trigger_{new Trigger>()}; + std::vector sync_value_; + InternalGPIOPin *dio0_pin_{nullptr}; + InternalGPIOPin *dio2_pin_{nullptr}; InternalGPIOPin *rst_pin_{nullptr}; InternalGPIOPin *nss_pin_{nullptr}; + SX127xStore store_; SX127xPaConfig pa_pin_; SX127xRxBw rx_bandwidth_; SX127xOpMode modulation_; - SX127xPaRamp fsk_shaping_; + SX127xPaRamp shaping_; SX127xPaRamp fsk_ramp_; uint32_t fsk_fdev_; uint32_t frequency_; + uint32_t bitrate_; + uint32_t rx_duration_; uint32_t pa_power_; + uint32_t payload_length_; + uint8_t preamble_polarity_; + uint8_t preamble_size_; + uint8_t preamble_errors_; + uint8_t rx_config_; float rx_floor_; bool rx_start_; };