Add packet mode and rx duration

This commit is contained in:
Jonathan Swoboda 2024-10-19 22:08:54 -04:00
parent ff6dd6ea9e
commit 55c14e0d48
3 changed files with 380 additions and 42 deletions

View file

@ -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]))

View file

@ -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<uint8_t> &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<uint8_t> &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<uint8_t> &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<uint8_t> 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");
}

View file

@ -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 <vector>
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<uint8_t> &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<uint8_t> &packet);
Trigger<std::vector<uint8_t>> *get_packet_trigger() const { return this->packet_trigger_; };
protected:
void write_fifo_(const std::vector<uint8_t> &packet);
void read_fifo_(std::vector<uint8_t> &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<std::vector<uint8_t>> *packet_trigger_{new Trigger<std::vector<uint8_t>>()};
std::vector<uint8_t> 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_;
};