mirror of
https://github.com/esphome/esphome.git
synced 2025-07-28 14:16:40 +00:00
[sx127x] Add sx127x component (#7490)
Co-authored-by: Jonathan Swoboda <jonathan.swoboda>
This commit is contained in:
parent
107304b274
commit
1ef7b2d64f
@ -441,6 +441,7 @@ esphome/components/sun/* @OttoWinter
|
||||
esphome/components/sun_gtil2/* @Mat931
|
||||
esphome/components/switch/* @esphome/core
|
||||
esphome/components/switch/binary_sensor/* @ssieb
|
||||
esphome/components/sx127x/* @swoboda1337
|
||||
esphome/components/syslog/* @clydebarrow
|
||||
esphome/components/t6615/* @tylermenezes
|
||||
esphome/components/tc74/* @sethgirvan
|
||||
|
325
esphome/components/sx127x/__init__.py
Normal file
325
esphome/components/sx127x/__init__.py
Normal file
@ -0,0 +1,325 @@
|
||||
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_DATA, CONF_FREQUENCY, CONF_ID
|
||||
|
||||
MULTI_CONF = True
|
||||
CODEOWNERS = ["@swoboda1337"]
|
||||
DEPENDENCIES = ["spi"]
|
||||
|
||||
CONF_SX127X_ID = "sx127x_id"
|
||||
|
||||
CONF_AUTO_CAL = "auto_cal"
|
||||
CONF_BANDWIDTH = "bandwidth"
|
||||
CONF_BITRATE = "bitrate"
|
||||
CONF_BITSYNC = "bitsync"
|
||||
CONF_CODING_RATE = "coding_rate"
|
||||
CONF_CRC_ENABLE = "crc_enable"
|
||||
CONF_DEVIATION = "deviation"
|
||||
CONF_DIO0_PIN = "dio0_pin"
|
||||
CONF_MODULATION = "modulation"
|
||||
CONF_ON_PACKET = "on_packet"
|
||||
CONF_PA_PIN = "pa_pin"
|
||||
CONF_PA_POWER = "pa_power"
|
||||
CONF_PA_RAMP = "pa_ramp"
|
||||
CONF_PACKET_MODE = "packet_mode"
|
||||
CONF_PAYLOAD_LENGTH = "payload_length"
|
||||
CONF_PREAMBLE_DETECT = "preamble_detect"
|
||||
CONF_PREAMBLE_ERRORS = "preamble_errors"
|
||||
CONF_PREAMBLE_POLARITY = "preamble_polarity"
|
||||
CONF_PREAMBLE_SIZE = "preamble_size"
|
||||
CONF_RST_PIN = "rst_pin"
|
||||
CONF_RX_FLOOR = "rx_floor"
|
||||
CONF_RX_START = "rx_start"
|
||||
CONF_SHAPING = "shaping"
|
||||
CONF_SPREADING_FACTOR = "spreading_factor"
|
||||
CONF_SYNC_VALUE = "sync_value"
|
||||
|
||||
sx127x_ns = cg.esphome_ns.namespace("sx127x")
|
||||
SX127x = sx127x_ns.class_("SX127x", cg.Component, spi.SPIDevice)
|
||||
SX127xListener = sx127x_ns.class_("SX127xListener")
|
||||
SX127xBw = sx127x_ns.enum("SX127xBw")
|
||||
SX127xOpMode = sx127x_ns.enum("SX127xOpMode")
|
||||
SX127xPaConfig = sx127x_ns.enum("SX127xPaConfig")
|
||||
SX127xPaRamp = sx127x_ns.enum("SX127xPaRamp")
|
||||
SX127xModemCfg1 = sx127x_ns.enum("SX127xModemCfg1")
|
||||
|
||||
BW = {
|
||||
"2_6kHz": SX127xBw.SX127X_BW_2_6,
|
||||
"3_1kHz": SX127xBw.SX127X_BW_3_1,
|
||||
"3_9kHz": SX127xBw.SX127X_BW_3_9,
|
||||
"5_2kHz": SX127xBw.SX127X_BW_5_2,
|
||||
"6_3kHz": SX127xBw.SX127X_BW_6_3,
|
||||
"7_8kHz": SX127xBw.SX127X_BW_7_8,
|
||||
"10_4kHz": SX127xBw.SX127X_BW_10_4,
|
||||
"12_5kHz": SX127xBw.SX127X_BW_12_5,
|
||||
"15_6kHz": SX127xBw.SX127X_BW_15_6,
|
||||
"20_8kHz": SX127xBw.SX127X_BW_20_8,
|
||||
"25_0kHz": SX127xBw.SX127X_BW_25_0,
|
||||
"31_3kHz": SX127xBw.SX127X_BW_31_3,
|
||||
"41_7kHz": SX127xBw.SX127X_BW_41_7,
|
||||
"50_0kHz": SX127xBw.SX127X_BW_50_0,
|
||||
"62_5kHz": SX127xBw.SX127X_BW_62_5,
|
||||
"83_3kHz": SX127xBw.SX127X_BW_83_3,
|
||||
"100_0kHz": SX127xBw.SX127X_BW_100_0,
|
||||
"125_0kHz": SX127xBw.SX127X_BW_125_0,
|
||||
"166_7kHz": SX127xBw.SX127X_BW_166_7,
|
||||
"200_0kHz": SX127xBw.SX127X_BW_200_0,
|
||||
"250_0kHz": SX127xBw.SX127X_BW_250_0,
|
||||
"500_0kHz": SX127xBw.SX127X_BW_500_0,
|
||||
}
|
||||
|
||||
CODING_RATE = {
|
||||
"CR_4_5": SX127xModemCfg1.CODING_RATE_4_5,
|
||||
"CR_4_6": SX127xModemCfg1.CODING_RATE_4_6,
|
||||
"CR_4_7": SX127xModemCfg1.CODING_RATE_4_7,
|
||||
"CR_4_8": SX127xModemCfg1.CODING_RATE_4_8,
|
||||
}
|
||||
|
||||
MOD = {
|
||||
"LORA": SX127xOpMode.MOD_LORA,
|
||||
"FSK": SX127xOpMode.MOD_FSK,
|
||||
"OOK": SX127xOpMode.MOD_OOK,
|
||||
}
|
||||
|
||||
PA_PIN = {
|
||||
"RFO": SX127xPaConfig.PA_PIN_RFO,
|
||||
"BOOST": SX127xPaConfig.PA_PIN_BOOST,
|
||||
}
|
||||
|
||||
RAMP = {
|
||||
"10us": SX127xPaRamp.PA_RAMP_10,
|
||||
"12us": SX127xPaRamp.PA_RAMP_12,
|
||||
"15us": SX127xPaRamp.PA_RAMP_15,
|
||||
"20us": SX127xPaRamp.PA_RAMP_20,
|
||||
"25us": SX127xPaRamp.PA_RAMP_25,
|
||||
"31us": SX127xPaRamp.PA_RAMP_31,
|
||||
"40us": SX127xPaRamp.PA_RAMP_40,
|
||||
"50us": SX127xPaRamp.PA_RAMP_50,
|
||||
"62us": SX127xPaRamp.PA_RAMP_62,
|
||||
"100us": SX127xPaRamp.PA_RAMP_100,
|
||||
"125us": SX127xPaRamp.PA_RAMP_125,
|
||||
"250us": SX127xPaRamp.PA_RAMP_250,
|
||||
"500us": SX127xPaRamp.PA_RAMP_500,
|
||||
"1000us": SX127xPaRamp.PA_RAMP_1000,
|
||||
"2000us": SX127xPaRamp.PA_RAMP_2000,
|
||||
"3400us": SX127xPaRamp.PA_RAMP_3400,
|
||||
}
|
||||
|
||||
SHAPING = {
|
||||
"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,
|
||||
"NONE": SX127xPaRamp.SHAPING_NONE,
|
||||
}
|
||||
|
||||
RunImageCalAction = sx127x_ns.class_(
|
||||
"RunImageCalAction", automation.Action, cg.Parented.template(SX127x)
|
||||
)
|
||||
SendPacketAction = sx127x_ns.class_(
|
||||
"SendPacketAction", automation.Action, cg.Parented.template(SX127x)
|
||||
)
|
||||
SetModeTxAction = sx127x_ns.class_(
|
||||
"SetModeTxAction", automation.Action, cg.Parented.template(SX127x)
|
||||
)
|
||||
SetModeRxAction = sx127x_ns.class_(
|
||||
"SetModeRxAction", automation.Action, cg.Parented.template(SX127x)
|
||||
)
|
||||
SetModeSleepAction = sx127x_ns.class_(
|
||||
"SetModeSleepAction", automation.Action, cg.Parented.template(SX127x)
|
||||
)
|
||||
SetModeStandbyAction = sx127x_ns.class_(
|
||||
"SetModeStandbyAction", automation.Action, cg.Parented.template(SX127x)
|
||||
)
|
||||
|
||||
|
||||
def validate_raw_data(value):
|
||||
if isinstance(value, str):
|
||||
return value.encode("utf-8")
|
||||
if isinstance(value, list):
|
||||
return cv.Schema([cv.hex_uint8_t])(value)
|
||||
raise cv.Invalid(
|
||||
"data must either be a string wrapped in quotes or a list of bytes"
|
||||
)
|
||||
|
||||
|
||||
def validate_config(config):
|
||||
if config[CONF_MODULATION] == "LORA":
|
||||
bws = [
|
||||
"7_8kHz",
|
||||
"10_4kHz",
|
||||
"15_6kHz",
|
||||
"20_8kHz",
|
||||
"31_3kHz",
|
||||
"41_7kHz",
|
||||
"62_5kHz",
|
||||
"125_0kHz",
|
||||
"250_0kHz",
|
||||
"500_0kHz",
|
||||
]
|
||||
if config[CONF_BANDWIDTH] not in bws:
|
||||
raise cv.Invalid(f"{config[CONF_BANDWIDTH]} is not available with LORA")
|
||||
if CONF_DIO0_PIN not in config:
|
||||
raise cv.Invalid("Cannot use LoRa without dio0_pin")
|
||||
if 0 < config[CONF_PREAMBLE_SIZE] < 6:
|
||||
raise cv.Invalid("Minimum preamble size is 6 with LORA")
|
||||
if config[CONF_SPREADING_FACTOR] == 6 and config[CONF_PAYLOAD_LENGTH] == 0:
|
||||
raise cv.Invalid("Payload length must be set when spreading factor is 6")
|
||||
else:
|
||||
if config[CONF_BANDWIDTH] == "500_0kHz":
|
||||
raise cv.Invalid(f"{config[CONF_BANDWIDTH]} is only available with LORA")
|
||||
if CONF_BITSYNC not in config:
|
||||
raise cv.Invalid("Config 'bitsync' required with FSK/OOK")
|
||||
if CONF_PACKET_MODE not in config:
|
||||
raise cv.Invalid("Config 'packet_mode' required with FSK/OOK")
|
||||
if config[CONF_PACKET_MODE] and CONF_DIO0_PIN not in config:
|
||||
raise cv.Invalid("Config 'dio0_pin' required in packet mode")
|
||||
if config[CONF_PAYLOAD_LENGTH] > 64:
|
||||
raise cv.Invalid("Payload length must be <= 64 with FSK/OOK")
|
||||
if config[CONF_PA_PIN] == "RFO" and config[CONF_PA_POWER] > 15:
|
||||
raise cv.Invalid("PA power must be <= 15 dbm when using the RFO pin")
|
||||
if config[CONF_PA_PIN] == "BOOST" and config[CONF_PA_POWER] < 2:
|
||||
raise cv.Invalid("PA power must be >= 2 dbm when using the BOOST pin")
|
||||
return config
|
||||
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(SX127x),
|
||||
cv.Optional(CONF_AUTO_CAL, default=True): cv.boolean,
|
||||
cv.Optional(CONF_BANDWIDTH, default="125_0kHz"): cv.enum(BW),
|
||||
cv.Optional(CONF_BITRATE, default=4800): cv.int_range(min=500, max=300000),
|
||||
cv.Optional(CONF_BITSYNC): cv.boolean,
|
||||
cv.Optional(CONF_CODING_RATE, default="CR_4_5"): cv.enum(CODING_RATE),
|
||||
cv.Optional(CONF_CRC_ENABLE, default=False): cv.boolean,
|
||||
cv.Optional(CONF_DEVIATION, default=5000): cv.int_range(min=0, max=100000),
|
||||
cv.Optional(CONF_DIO0_PIN): pins.internal_gpio_input_pin_schema,
|
||||
cv.Required(CONF_FREQUENCY): cv.int_range(min=137000000, max=1020000000),
|
||||
cv.Required(CONF_MODULATION): cv.enum(MOD),
|
||||
cv.Optional(CONF_ON_PACKET): automation.validate_automation(single=True),
|
||||
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_PA_RAMP, default="40us"): cv.enum(RAMP),
|
||||
cv.Optional(CONF_PACKET_MODE): cv.boolean,
|
||||
cv.Optional(CONF_PAYLOAD_LENGTH, default=0): cv.int_range(min=0, max=256),
|
||||
cv.Optional(CONF_PREAMBLE_DETECT, default=0): cv.int_range(min=0, max=3),
|
||||
cv.Optional(CONF_PREAMBLE_ERRORS, default=0): cv.int_range(min=0, max=31),
|
||||
cv.Optional(CONF_PREAMBLE_POLARITY, default=0xAA): cv.All(
|
||||
cv.hex_int, cv.one_of(0xAA, 0x55)
|
||||
),
|
||||
cv.Optional(CONF_PREAMBLE_SIZE, default=0): cv.int_range(min=0, max=65535),
|
||||
cv.Required(CONF_RST_PIN): pins.internal_gpio_output_pin_schema,
|
||||
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_SHAPING, default="NONE"): cv.enum(SHAPING),
|
||||
cv.Optional(CONF_SPREADING_FACTOR, default=7): cv.int_range(min=6, max=12),
|
||||
cv.Optional(CONF_SYNC_VALUE, default=[]): cv.ensure_list(cv.hex_uint8_t),
|
||||
},
|
||||
)
|
||||
.extend(cv.COMPONENT_SCHEMA)
|
||||
.extend(spi.spi_device_schema(True, 8e6, "mode0"))
|
||||
.add_extra(validate_config)
|
||||
)
|
||||
|
||||
|
||||
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"),
|
||||
(cg.float_, "rssi"),
|
||||
(cg.float_, "snr"),
|
||||
],
|
||||
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))
|
||||
rst_pin = await cg.gpio_pin_expression(config[CONF_RST_PIN])
|
||||
cg.add(var.set_rst_pin(rst_pin))
|
||||
cg.add(var.set_auto_cal(config[CONF_AUTO_CAL]))
|
||||
cg.add(var.set_bandwidth(config[CONF_BANDWIDTH]))
|
||||
cg.add(var.set_frequency(config[CONF_FREQUENCY]))
|
||||
cg.add(var.set_deviation(config[CONF_DEVIATION]))
|
||||
cg.add(var.set_modulation(config[CONF_MODULATION]))
|
||||
if config[CONF_MODULATION] != "LORA":
|
||||
cg.add(var.set_bitrate(config[CONF_BITRATE]))
|
||||
cg.add(var.set_bitsync(config[CONF_BITSYNC]))
|
||||
cg.add(var.set_packet_mode(config[CONF_PACKET_MODE]))
|
||||
cg.add(var.set_pa_pin(config[CONF_PA_PIN]))
|
||||
cg.add(var.set_pa_ramp(config[CONF_PA_RAMP]))
|
||||
cg.add(var.set_pa_power(config[CONF_PA_POWER]))
|
||||
cg.add(var.set_shaping(config[CONF_SHAPING]))
|
||||
cg.add(var.set_crc_enable(config[CONF_CRC_ENABLE]))
|
||||
cg.add(var.set_payload_length(config[CONF_PAYLOAD_LENGTH]))
|
||||
cg.add(var.set_preamble_detect(config[CONF_PREAMBLE_DETECT]))
|
||||
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_coding_rate(config[CONF_CODING_RATE]))
|
||||
cg.add(var.set_spreading_factor(config[CONF_SPREADING_FACTOR]))
|
||||
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]))
|
||||
|
||||
|
||||
NO_ARGS_ACTION_SCHEMA = automation.maybe_simple_id(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(SX127x),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"sx127x.run_image_cal", RunImageCalAction, NO_ARGS_ACTION_SCHEMA
|
||||
)
|
||||
@automation.register_action(
|
||||
"sx127x.set_mode_tx", SetModeTxAction, NO_ARGS_ACTION_SCHEMA
|
||||
)
|
||||
@automation.register_action(
|
||||
"sx127x.set_mode_rx", SetModeRxAction, NO_ARGS_ACTION_SCHEMA
|
||||
)
|
||||
@automation.register_action(
|
||||
"sx127x.set_mode_sleep", SetModeSleepAction, NO_ARGS_ACTION_SCHEMA
|
||||
)
|
||||
@automation.register_action(
|
||||
"sx127x.set_mode_standby", SetModeStandbyAction, NO_ARGS_ACTION_SCHEMA
|
||||
)
|
||||
async def no_args_action_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
await cg.register_parented(var, config[CONF_ID])
|
||||
return var
|
||||
|
||||
|
||||
SEND_PACKET_ACTION_SCHEMA = cv.maybe_simple_value(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(SX127x),
|
||||
cv.Required(CONF_DATA): cv.templatable(validate_raw_data),
|
||||
},
|
||||
key=CONF_DATA,
|
||||
)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"sx127x.send_packet", SendPacketAction, SEND_PACKET_ACTION_SCHEMA
|
||||
)
|
||||
async def send_packet_action_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
await cg.register_parented(var, config[CONF_ID])
|
||||
data = config[CONF_DATA]
|
||||
if isinstance(data, bytes):
|
||||
data = list(data)
|
||||
if cg.is_template(data):
|
||||
templ = await cg.templatable(data, args, cg.std_vector.template(cg.uint8))
|
||||
cg.add(var.set_data_template(templ))
|
||||
else:
|
||||
cg.add(var.set_data_static(data))
|
||||
return var
|
62
esphome/components/sx127x/automation.h
Normal file
62
esphome/components/sx127x/automation.h
Normal file
@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/components/sx127x/sx127x.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace sx127x {
|
||||
|
||||
template<typename... Ts> class RunImageCalAction : public Action<Ts...>, public Parented<SX127x> {
|
||||
public:
|
||||
void play(Ts... x) override { this->parent_->run_image_cal(); }
|
||||
};
|
||||
|
||||
template<typename... Ts> class SendPacketAction : public Action<Ts...>, public Parented<SX127x> {
|
||||
public:
|
||||
void set_data_template(std::function<std::vector<uint8_t>(Ts...)> func) {
|
||||
this->data_func_ = func;
|
||||
this->static_ = false;
|
||||
}
|
||||
|
||||
void set_data_static(const std::vector<uint8_t> &data) {
|
||||
this->data_static_ = data;
|
||||
this->static_ = true;
|
||||
}
|
||||
|
||||
void play(Ts... x) override {
|
||||
if (this->static_) {
|
||||
this->parent_->transmit_packet(this->data_static_);
|
||||
} else {
|
||||
this->parent_->transmit_packet(this->data_func_(x...));
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
bool static_{false};
|
||||
std::function<std::vector<uint8_t>(Ts...)> data_func_{};
|
||||
std::vector<uint8_t> data_static_{};
|
||||
};
|
||||
|
||||
template<typename... Ts> class SetModeTxAction : public Action<Ts...>, public Parented<SX127x> {
|
||||
public:
|
||||
void play(Ts... x) override { this->parent_->set_mode_tx(); }
|
||||
};
|
||||
|
||||
template<typename... Ts> class SetModeRxAction : public Action<Ts...>, public Parented<SX127x> {
|
||||
public:
|
||||
void play(Ts... x) override { this->parent_->set_mode_rx(); }
|
||||
};
|
||||
|
||||
template<typename... Ts> class SetModeSleepAction : public Action<Ts...>, public Parented<SX127x> {
|
||||
public:
|
||||
void play(Ts... x) override { this->parent_->set_mode_sleep(); }
|
||||
};
|
||||
|
||||
template<typename... Ts> class SetModeStandbyAction : public Action<Ts...>, public Parented<SX127x> {
|
||||
public:
|
||||
void play(Ts... x) override { this->parent_->set_mode_standby(); }
|
||||
};
|
||||
|
||||
} // namespace sx127x
|
||||
} // namespace esphome
|
26
esphome/components/sx127x/packet_transport/__init__.py
Normal file
26
esphome/components/sx127x/packet_transport/__init__.py
Normal file
@ -0,0 +1,26 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components.packet_transport import (
|
||||
PacketTransport,
|
||||
new_packet_transport,
|
||||
transport_schema,
|
||||
)
|
||||
import esphome.config_validation as cv
|
||||
from esphome.cpp_types import PollingComponent
|
||||
|
||||
from .. import CONF_SX127X_ID, SX127x, SX127xListener, sx127x_ns
|
||||
|
||||
SX127xTransport = sx127x_ns.class_(
|
||||
"SX127xTransport", PacketTransport, PollingComponent, SX127xListener
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = transport_schema(SX127xTransport).extend(
|
||||
{
|
||||
cv.GenerateID(CONF_SX127X_ID): cv.use_id(SX127x),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var, _ = await new_packet_transport(config)
|
||||
sx127x = await cg.get_variable(config[CONF_SX127X_ID])
|
||||
cg.add(var.set_parent(sx127x))
|
@ -0,0 +1,26 @@
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "sx127x_transport.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace sx127x {
|
||||
|
||||
static const char *const TAG = "sx127x_transport";
|
||||
|
||||
void SX127xTransport::setup() {
|
||||
PacketTransport::setup();
|
||||
this->parent_->register_listener(this);
|
||||
}
|
||||
|
||||
void SX127xTransport::update() {
|
||||
PacketTransport::update();
|
||||
this->updated_ = true;
|
||||
this->resend_data_ = true;
|
||||
}
|
||||
|
||||
void SX127xTransport::send_packet(const std::vector<uint8_t> &buf) const { this->parent_->transmit_packet(buf); }
|
||||
|
||||
void SX127xTransport::on_packet(const std::vector<uint8_t> &packet, float rssi, float snr) { this->process_(packet); }
|
||||
|
||||
} // namespace sx127x
|
||||
} // namespace esphome
|
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/sx127x/sx127x.h"
|
||||
#include "esphome/components/packet_transport/packet_transport.h"
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace sx127x {
|
||||
|
||||
class SX127xTransport : public packet_transport::PacketTransport, public Parented<SX127x>, public SX127xListener {
|
||||
public:
|
||||
void setup() override;
|
||||
void update() override;
|
||||
void on_packet(const std::vector<uint8_t> &packet, float rssi, float snr) override;
|
||||
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
|
||||
|
||||
protected:
|
||||
void send_packet(const std::vector<uint8_t> &buf) const override;
|
||||
bool should_send() override { return true; }
|
||||
size_t get_max_packet_size() override { return this->parent_->get_max_packet_size(); }
|
||||
};
|
||||
|
||||
} // namespace sx127x
|
||||
} // namespace esphome
|
493
esphome/components/sx127x/sx127x.cpp
Normal file
493
esphome/components/sx127x/sx127x.cpp
Normal file
@ -0,0 +1,493 @@
|
||||
#include "sx127x.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace sx127x {
|
||||
|
||||
static const char *const TAG = "sx127x";
|
||||
static const uint32_t FXOSC = 32000000u;
|
||||
static const uint16_t RAMP[16] = {3400, 2000, 1000, 500, 250, 125, 100, 62, 50, 40, 31, 25, 20, 15, 12, 10};
|
||||
static const uint32_t BW_HZ[22] = {2604, 3125, 3906, 5208, 6250, 7812, 10416, 12500, 15625, 20833, 25000,
|
||||
31250, 41666, 50000, 62500, 83333, 100000, 125000, 166666, 200000, 250000, 500000};
|
||||
static 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,
|
||||
BW_15_6, BW_20_8, BW_31_3, BW_31_3, BW_41_7, BW_62_5, BW_62_5, BW_125_0,
|
||||
BW_125_0, BW_125_0, BW_250_0, BW_250_0, BW_250_0, BW_500_0};
|
||||
static 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,
|
||||
RX_BW_10_4, RX_BW_12_5, RX_BW_15_6, RX_BW_20_8, RX_BW_25_0, RX_BW_31_3,
|
||||
RX_BW_41_7, RX_BW_50_0, RX_BW_62_5, RX_BW_83_3, RX_BW_100_0, RX_BW_125_0,
|
||||
RX_BW_166_7, RX_BW_200_0, RX_BW_250_0, RX_BW_250_0};
|
||||
static const int32_t RSSI_OFFSET_HF = 157;
|
||||
static const int32_t RSSI_OFFSET_LF = 164;
|
||||
|
||||
uint8_t SX127x::read_register_(uint8_t reg) {
|
||||
this->enable();
|
||||
this->write_byte(reg & 0x7F);
|
||||
uint8_t value = this->read_byte();
|
||||
this->disable();
|
||||
return value;
|
||||
}
|
||||
|
||||
void SX127x::write_register_(uint8_t reg, uint8_t value) {
|
||||
this->enable();
|
||||
this->write_byte(reg | 0x80);
|
||||
this->write_byte(value);
|
||||
this->disable();
|
||||
}
|
||||
|
||||
void SX127x::read_fifo_(std::vector<uint8_t> &packet) {
|
||||
this->enable();
|
||||
this->write_byte(REG_FIFO & 0x7F);
|
||||
this->read_array(packet.data(), packet.size());
|
||||
this->disable();
|
||||
}
|
||||
|
||||
void SX127x::write_fifo_(const std::vector<uint8_t> &packet) {
|
||||
this->enable();
|
||||
this->write_byte(REG_FIFO | 0x80);
|
||||
this->write_array(packet.data(), packet.size());
|
||||
this->disable();
|
||||
}
|
||||
|
||||
void SX127x::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
|
||||
// setup reset
|
||||
this->rst_pin_->setup();
|
||||
|
||||
// setup dio0
|
||||
if (this->dio0_pin_) {
|
||||
this->dio0_pin_->setup();
|
||||
}
|
||||
|
||||
// start spi
|
||||
this->spi_setup();
|
||||
|
||||
// configure rf
|
||||
this->configure();
|
||||
}
|
||||
|
||||
void SX127x::configure() {
|
||||
// toggle chip reset
|
||||
this->rst_pin_->digital_write(false);
|
||||
delayMicroseconds(1000);
|
||||
this->rst_pin_->digital_write(true);
|
||||
delayMicroseconds(10000);
|
||||
|
||||
// check silicon version to make sure hw is ok
|
||||
if (this->read_register_(REG_VERSION) != 0x12) {
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
// enter sleep mode
|
||||
this->set_mode_(MOD_FSK, MODE_SLEEP);
|
||||
|
||||
// set freq
|
||||
uint64_t frf = ((uint64_t) this->frequency_ << 19) / FXOSC;
|
||||
this->write_register_(REG_FRF_MSB, (uint8_t) ((frf >> 16) & 0xFF));
|
||||
this->write_register_(REG_FRF_MID, (uint8_t) ((frf >> 8) & 0xFF));
|
||||
this->write_register_(REG_FRF_LSB, (uint8_t) ((frf >> 0) & 0xFF));
|
||||
|
||||
// enter standby mode
|
||||
this->set_mode_(MOD_FSK, MODE_STDBY);
|
||||
|
||||
// run image cal
|
||||
this->run_image_cal();
|
||||
|
||||
// go back to sleep
|
||||
this->set_mode_sleep();
|
||||
|
||||
// config pa
|
||||
if (this->pa_pin_ == PA_PIN_BOOST) {
|
||||
this->pa_power_ = std::max(this->pa_power_, (uint8_t) 2);
|
||||
this->pa_power_ = std::min(this->pa_power_, (uint8_t) 17);
|
||||
this->write_register_(REG_PA_CONFIG, (this->pa_power_ - 2) | this->pa_pin_ | PA_MAX_POWER);
|
||||
} else {
|
||||
this->pa_power_ = std::min(this->pa_power_, (uint8_t) 14);
|
||||
this->write_register_(REG_PA_CONFIG, (this->pa_power_ - 0) | this->pa_pin_ | PA_MAX_POWER);
|
||||
}
|
||||
if (this->modulation_ != MOD_LORA) {
|
||||
this->write_register_(REG_PA_RAMP, this->pa_ramp_ | this->shaping_);
|
||||
} else {
|
||||
this->write_register_(REG_PA_RAMP, this->pa_ramp_);
|
||||
}
|
||||
|
||||
// configure modem
|
||||
if (this->modulation_ != MOD_LORA) {
|
||||
this->configure_fsk_ook_();
|
||||
} else {
|
||||
this->configure_lora_();
|
||||
}
|
||||
|
||||
// switch to rx or sleep
|
||||
if (this->rx_start_) {
|
||||
this->set_mode_rx();
|
||||
} else {
|
||||
this->set_mode_sleep();
|
||||
}
|
||||
}
|
||||
|
||||
void SX127x::configure_fsk_ook_() {
|
||||
// set the channel bw
|
||||
this->write_register_(REG_RX_BW, BW_FSK_OOK[this->bandwidth_]);
|
||||
|
||||
// set fdev
|
||||
uint32_t fdev = std::min((this->deviation_ * 4096) / 250000, (uint32_t) 0x3FFF);
|
||||
this->write_register_(REG_FDEV_MSB, (uint8_t) ((fdev >> 8) & 0xFF));
|
||||
this->write_register_(REG_FDEV_LSB, (uint8_t) ((fdev >> 0) & 0xFF));
|
||||
|
||||
// set bitrate
|
||||
uint64_t bitrate = (FXOSC + this->bitrate_ / 2) / this->bitrate_; // round up
|
||||
this->write_register_(REG_BITRATE_MSB, (uint8_t) ((bitrate >> 8) & 0xFF));
|
||||
this->write_register_(REG_BITRATE_LSB, (uint8_t) ((bitrate >> 0) & 0xFF));
|
||||
|
||||
// configure rx and afc
|
||||
uint8_t trigger = (this->preamble_detect_ > 0) ? TRIGGER_PREAMBLE : TRIGGER_RSSI;
|
||||
this->write_register_(REG_AFC_FEI, AFC_AUTO_CLEAR_ON);
|
||||
if (this->modulation_ == MOD_FSK) {
|
||||
this->write_register_(REG_RX_CONFIG, AFC_AUTO_ON | AGC_AUTO_ON | trigger);
|
||||
} else {
|
||||
this->write_register_(REG_RX_CONFIG, AGC_AUTO_ON | trigger);
|
||||
}
|
||||
|
||||
// configure packet mode
|
||||
if (this->packet_mode_) {
|
||||
uint8_t crc_mode = (this->crc_enable_) ? CRC_ON : CRC_OFF;
|
||||
this->write_register_(REG_FIFO_THRESH, TX_START_FIFO_EMPTY);
|
||||
if (this->payload_length_ > 0) {
|
||||
this->write_register_(REG_PAYLOAD_LENGTH_LSB, this->payload_length_);
|
||||
this->write_register_(REG_PACKET_CONFIG_1, crc_mode | FIXED_LENGTH);
|
||||
} else {
|
||||
this->write_register_(REG_PAYLOAD_LENGTH_LSB, this->get_max_packet_size() - 1);
|
||||
this->write_register_(REG_PACKET_CONFIG_1, crc_mode | VARIABLE_LENGTH);
|
||||
}
|
||||
this->write_register_(REG_PACKET_CONFIG_2, PACKET_MODE);
|
||||
} else {
|
||||
this->write_register_(REG_PACKET_CONFIG_2, CONTINUOUS_MODE);
|
||||
}
|
||||
this->write_register_(REG_DIO_MAPPING1, DIO0_MAPPING_00);
|
||||
|
||||
// config bit synchronizer
|
||||
uint8_t polarity = (this->preamble_polarity_ == 0xAA) ? PREAMBLE_AA : PREAMBLE_55;
|
||||
if (!this->sync_value_.empty()) {
|
||||
uint8_t size = this->sync_value_.size() - 1;
|
||||
this->write_register_(REG_SYNC_CONFIG, AUTO_RESTART_PLL_LOCK | polarity | SYNC_ON | 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_SYNC_CONFIG, AUTO_RESTART_PLL_LOCK | polarity);
|
||||
}
|
||||
|
||||
// config preamble detector
|
||||
if (this->preamble_detect_ > 0) {
|
||||
uint8_t size = (this->preamble_detect_ - 1) << PREAMBLE_DETECTOR_SIZE_SHIFT;
|
||||
uint8_t tol = this->preamble_errors_ << PREAMBLE_DETECTOR_TOL_SHIFT;
|
||||
this->write_register_(REG_PREAMBLE_DETECT, PREAMBLE_DETECTOR_ON | size | tol);
|
||||
} else {
|
||||
this->write_register_(REG_PREAMBLE_DETECT, PREAMBLE_DETECTOR_OFF);
|
||||
}
|
||||
this->write_register_(REG_PREAMBLE_SIZE_MSB, this->preamble_size_ >> 16);
|
||||
this->write_register_(REG_PREAMBLE_SIZE_LSB, this->preamble_size_ & 0xFF);
|
||||
|
||||
// config sync generation and setup ook threshold
|
||||
uint8_t bitsync = this->bitsync_ ? BIT_SYNC_ON : BIT_SYNC_OFF;
|
||||
this->write_register_(REG_OOK_PEAK, bitsync | OOK_THRESH_STEP_0_5 | OOK_THRESH_PEAK);
|
||||
this->write_register_(REG_OOK_AVG, OOK_AVG_RESERVED | OOK_THRESH_DEC_1_8);
|
||||
|
||||
// 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)));
|
||||
}
|
||||
|
||||
void SX127x::configure_lora_() {
|
||||
// config modem
|
||||
uint8_t header_mode = this->payload_length_ > 0 ? IMPLICIT_HEADER : EXPLICIT_HEADER;
|
||||
uint8_t crc_mode = (this->crc_enable_) ? RX_PAYLOAD_CRC_ON : RX_PAYLOAD_CRC_OFF;
|
||||
uint8_t spreading_factor = this->spreading_factor_ << SPREADING_FACTOR_SHIFT;
|
||||
this->write_register_(REG_MODEM_CONFIG1, BW_LORA[this->bandwidth_] | this->coding_rate_ | header_mode);
|
||||
this->write_register_(REG_MODEM_CONFIG2, spreading_factor | crc_mode);
|
||||
|
||||
// config fifo and payload length
|
||||
this->write_register_(REG_FIFO_TX_BASE_ADDR, 0x00);
|
||||
this->write_register_(REG_FIFO_RX_BASE_ADDR, 0x00);
|
||||
this->write_register_(REG_PAYLOAD_LENGTH, std::max(this->payload_length_, (uint32_t) 1));
|
||||
|
||||
// config preamble
|
||||
if (this->preamble_size_ >= 6) {
|
||||
this->write_register_(REG_PREAMBLE_LEN_MSB, this->preamble_size_ >> 16);
|
||||
this->write_register_(REG_PREAMBLE_LEN_LSB, this->preamble_size_ & 0xFF);
|
||||
}
|
||||
|
||||
// optimize detection
|
||||
float duration = 1000.0f * std::pow(2, this->spreading_factor_) / BW_HZ[this->bandwidth_];
|
||||
if (duration > 16) {
|
||||
this->write_register_(REG_MODEM_CONFIG3, MODEM_AGC_AUTO_ON | LOW_DATA_RATE_OPTIMIZE_ON);
|
||||
} else {
|
||||
this->write_register_(REG_MODEM_CONFIG3, MODEM_AGC_AUTO_ON);
|
||||
}
|
||||
if (this->spreading_factor_ == 6) {
|
||||
this->write_register_(REG_DETECT_OPTIMIZE, 0xC5);
|
||||
this->write_register_(REG_DETECT_THRESHOLD, 0x0C);
|
||||
} else {
|
||||
this->write_register_(REG_DETECT_OPTIMIZE, 0xC3);
|
||||
this->write_register_(REG_DETECT_THRESHOLD, 0x0A);
|
||||
}
|
||||
|
||||
// config sync word
|
||||
if (!this->sync_value_.empty()) {
|
||||
this->write_register_(REG_SYNC_WORD, this->sync_value_[0]);
|
||||
}
|
||||
}
|
||||
|
||||
size_t SX127x::get_max_packet_size() {
|
||||
if (this->payload_length_ > 0) {
|
||||
return this->payload_length_;
|
||||
}
|
||||
if (this->modulation_ == MOD_LORA) {
|
||||
return 256;
|
||||
} else {
|
||||
return 64;
|
||||
}
|
||||
}
|
||||
|
||||
void SX127x::transmit_packet(const std::vector<uint8_t> &packet) {
|
||||
if (this->payload_length_ > 0 && this->payload_length_ != packet.size()) {
|
||||
ESP_LOGE(TAG, "Packet size does not match config");
|
||||
return;
|
||||
}
|
||||
if (packet.empty() || packet.size() > this->get_max_packet_size()) {
|
||||
ESP_LOGE(TAG, "Packet size out of range");
|
||||
return;
|
||||
}
|
||||
if (this->modulation_ == MOD_LORA) {
|
||||
this->set_mode_standby();
|
||||
if (this->payload_length_ == 0) {
|
||||
this->write_register_(REG_PAYLOAD_LENGTH, packet.size());
|
||||
}
|
||||
this->write_register_(REG_IRQ_FLAGS, 0xFF);
|
||||
this->write_register_(REG_FIFO_ADDR_PTR, 0);
|
||||
this->write_fifo_(packet);
|
||||
this->set_mode_tx();
|
||||
} else {
|
||||
this->set_mode_standby();
|
||||
if (this->payload_length_ == 0) {
|
||||
this->write_register_(REG_FIFO, packet.size());
|
||||
}
|
||||
this->write_fifo_(packet);
|
||||
this->set_mode_tx();
|
||||
}
|
||||
// wait until transmit completes, typically the delay will be less than 100 ms
|
||||
uint32_t start = millis();
|
||||
while (!this->dio0_pin_->digital_read()) {
|
||||
if (millis() - start > 4000) {
|
||||
ESP_LOGE(TAG, "Transmit packet failure");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (this->rx_start_) {
|
||||
this->set_mode_rx();
|
||||
} else {
|
||||
this->set_mode_sleep();
|
||||
}
|
||||
}
|
||||
|
||||
void SX127x::call_listeners_(const std::vector<uint8_t> &packet, float rssi, float snr) {
|
||||
for (auto &listener : this->listeners_) {
|
||||
listener->on_packet(packet, rssi, snr);
|
||||
}
|
||||
this->packet_trigger_->trigger(packet, rssi, snr);
|
||||
}
|
||||
|
||||
void SX127x::loop() {
|
||||
if (this->dio0_pin_ == nullptr || !this->dio0_pin_->digital_read()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->modulation_ == MOD_LORA) {
|
||||
uint8_t status = this->read_register_(REG_IRQ_FLAGS);
|
||||
this->write_register_(REG_IRQ_FLAGS, 0xFF);
|
||||
if ((status & PAYLOAD_CRC_ERROR) == 0) {
|
||||
uint8_t bytes = this->read_register_(REG_NB_RX_BYTES);
|
||||
uint8_t addr = this->read_register_(REG_FIFO_RX_CURR_ADDR);
|
||||
uint8_t rssi = this->read_register_(REG_PKT_RSSI_VALUE);
|
||||
int8_t snr = (int8_t) this->read_register_(REG_PKT_SNR_VALUE);
|
||||
std::vector<uint8_t> packet(bytes);
|
||||
this->write_register_(REG_FIFO_ADDR_PTR, addr);
|
||||
this->read_fifo_(packet);
|
||||
if (this->frequency_ > 700000000) {
|
||||
this->call_listeners_(packet, (float) rssi - RSSI_OFFSET_HF, (float) snr / 4);
|
||||
} else {
|
||||
this->call_listeners_(packet, (float) rssi - RSSI_OFFSET_LF, (float) snr / 4);
|
||||
}
|
||||
}
|
||||
} else if (this->packet_mode_) {
|
||||
std::vector<uint8_t> packet;
|
||||
uint8_t payload_length = this->payload_length_;
|
||||
if (payload_length == 0) {
|
||||
payload_length = this->read_register_(REG_FIFO);
|
||||
}
|
||||
packet.resize(payload_length);
|
||||
this->read_fifo_(packet);
|
||||
this->call_listeners_(packet, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void SX127x::run_image_cal() {
|
||||
uint32_t start = millis();
|
||||
uint8_t mode = this->read_register_(REG_OP_MODE);
|
||||
if ((mode & MODE_MASK) != MODE_STDBY) {
|
||||
ESP_LOGE(TAG, "Need to be in standby for image cal");
|
||||
return;
|
||||
}
|
||||
if (mode & MOD_LORA) {
|
||||
this->set_mode_(MOD_FSK, MODE_SLEEP);
|
||||
this->set_mode_(MOD_FSK, MODE_STDBY);
|
||||
}
|
||||
if (this->auto_cal_) {
|
||||
this->write_register_(REG_IMAGE_CAL, IMAGE_CAL_START | AUTO_IMAGE_CAL_ON | TEMP_THRESHOLD_10C);
|
||||
} else {
|
||||
this->write_register_(REG_IMAGE_CAL, IMAGE_CAL_START);
|
||||
}
|
||||
while (this->read_register_(REG_IMAGE_CAL) & IMAGE_CAL_RUNNING) {
|
||||
if (millis() - start > 20) {
|
||||
ESP_LOGE(TAG, "Image cal failure");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mode & MOD_LORA) {
|
||||
this->set_mode_(this->modulation_, MODE_SLEEP);
|
||||
this->set_mode_(this->modulation_, MODE_STDBY);
|
||||
}
|
||||
}
|
||||
|
||||
void SX127x::set_mode_(uint8_t modulation, uint8_t mode) {
|
||||
uint32_t start = millis();
|
||||
this->write_register_(REG_OP_MODE, modulation | mode);
|
||||
while (true) {
|
||||
uint8_t curr = this->read_register_(REG_OP_MODE) & MODE_MASK;
|
||||
if ((curr == mode) || (mode == MODE_RX && curr == MODE_RX_FS)) {
|
||||
if (mode == MODE_SLEEP) {
|
||||
this->write_register_(REG_OP_MODE, modulation | mode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (millis() - start > 20) {
|
||||
ESP_LOGE(TAG, "Set mode failure");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SX127x::set_mode_rx() {
|
||||
this->set_mode_(this->modulation_, MODE_RX);
|
||||
if (this->modulation_ == MOD_LORA) {
|
||||
this->write_register_(REG_IRQ_FLAGS_MASK, 0x00);
|
||||
this->write_register_(REG_DIO_MAPPING1, DIO0_MAPPING_00);
|
||||
}
|
||||
}
|
||||
|
||||
void SX127x::set_mode_tx() {
|
||||
this->set_mode_(this->modulation_, MODE_TX);
|
||||
if (this->modulation_ == MOD_LORA) {
|
||||
this->write_register_(REG_IRQ_FLAGS_MASK, 0x00);
|
||||
this->write_register_(REG_DIO_MAPPING1, DIO0_MAPPING_01);
|
||||
}
|
||||
}
|
||||
|
||||
void SX127x::set_mode_standby() { this->set_mode_(this->modulation_, MODE_STDBY); }
|
||||
|
||||
void SX127x::set_mode_sleep() { this->set_mode_(this->modulation_, MODE_SLEEP); }
|
||||
|
||||
void SX127x::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "SX127x:");
|
||||
LOG_PIN(" CS Pin: ", this->cs_);
|
||||
LOG_PIN(" RST Pin: ", this->rst_pin_);
|
||||
LOG_PIN(" DIO0 Pin: ", this->dio0_pin_);
|
||||
const char *shaping = "NONE";
|
||||
if (this->shaping_ == CUTOFF_BR_X_2) {
|
||||
shaping = "CUTOFF_BR_X_2";
|
||||
} else if (this->shaping_ == CUTOFF_BR_X_1) {
|
||||
shaping = "CUTOFF_BR_X_1";
|
||||
} else if (this->shaping_ == GAUSSIAN_BT_0_3) {
|
||||
shaping = "GAUSSIAN_BT_0_3";
|
||||
} else if (this->shaping_ == GAUSSIAN_BT_0_5) {
|
||||
shaping = "GAUSSIAN_BT_0_5";
|
||||
} else if (this->shaping_ == GAUSSIAN_BT_1_0) {
|
||||
shaping = "GAUSSIAN_BT_1_0";
|
||||
}
|
||||
const char *pa_pin = "RFO";
|
||||
if (this->pa_pin_ == PA_PIN_BOOST) {
|
||||
pa_pin = "BOOST";
|
||||
}
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Auto Cal: %s\n"
|
||||
" Frequency: %" PRIu32 " Hz\n"
|
||||
" Bandwidth: %" PRIu32 " Hz\n"
|
||||
" PA Pin: %s\n"
|
||||
" PA Power: %" PRIu8 " dBm\n"
|
||||
" PA Ramp: %" PRIu16 " us\n"
|
||||
" Shaping: %s",
|
||||
TRUEFALSE(this->auto_cal_), this->frequency_, BW_HZ[this->bandwidth_], pa_pin, this->pa_power_,
|
||||
RAMP[this->pa_ramp_], shaping);
|
||||
if (this->modulation_ == MOD_FSK) {
|
||||
ESP_LOGCONFIG(TAG, " Deviation: %" PRIu32 " Hz", this->deviation_);
|
||||
}
|
||||
if (this->modulation_ == MOD_LORA) {
|
||||
const char *cr = "4/8";
|
||||
if (this->coding_rate_ == CODING_RATE_4_5) {
|
||||
cr = "4/5";
|
||||
} else if (this->coding_rate_ == CODING_RATE_4_6) {
|
||||
cr = "4/6";
|
||||
} else if (this->coding_rate_ == CODING_RATE_4_7) {
|
||||
cr = "4/7";
|
||||
}
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Modulation: LORA\n"
|
||||
" Preamble Size: %" PRIu16 "\n"
|
||||
" Spreading Factor: %" PRIu8 "\n"
|
||||
" Coding Rate: %s\n"
|
||||
" CRC Enable: %s",
|
||||
this->preamble_size_, this->spreading_factor_, cr, TRUEFALSE(this->crc_enable_));
|
||||
if (this->payload_length_ > 0) {
|
||||
ESP_LOGCONFIG(TAG, " Payload Length: %" PRIu32, this->payload_length_);
|
||||
}
|
||||
if (!this->sync_value_.empty()) {
|
||||
ESP_LOGCONFIG(TAG, " Sync Value: 0x%02x", this->sync_value_[0]);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Modulation: %s\n"
|
||||
" Bitrate: %" PRIu32 "b/s\n"
|
||||
" Bitsync: %s\n"
|
||||
" Rx Start: %s\n"
|
||||
" Rx Floor: %.1f dBm\n"
|
||||
" Packet Mode: %s",
|
||||
this->modulation_ == MOD_FSK ? "FSK" : "OOK", this->bitrate_, TRUEFALSE(this->bitsync_),
|
||||
TRUEFALSE(this->rx_start_), this->rx_floor_, TRUEFALSE(this->packet_mode_));
|
||||
if (this->packet_mode_) {
|
||||
ESP_LOGCONFIG(TAG, " CRC Enable: %s", TRUEFALSE(this->crc_enable_));
|
||||
}
|
||||
if (this->payload_length_ > 0) {
|
||||
ESP_LOGCONFIG(TAG, " Payload Length: %" PRIu32, this->payload_length_);
|
||||
}
|
||||
if (!this->sync_value_.empty()) {
|
||||
ESP_LOGCONFIG(TAG, " Sync Value: 0x%s", format_hex(this->sync_value_).c_str());
|
||||
}
|
||||
if (this->preamble_size_ > 0 || this->preamble_detect_ > 0) {
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Preamble Polarity: 0x%X\n"
|
||||
" Preamble Size: %" PRIu16 "\n"
|
||||
" Preamble Detect: %" PRIu8 "\n"
|
||||
" Preamble Errors: %" PRIu8,
|
||||
this->preamble_polarity_, this->preamble_size_, this->preamble_detect_, this->preamble_errors_);
|
||||
}
|
||||
}
|
||||
if (this->is_failed()) {
|
||||
ESP_LOGE(TAG, "Configuring SX127x failed");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sx127x
|
||||
} // namespace esphome
|
125
esphome/components/sx127x/sx127x.h
Normal file
125
esphome/components/sx127x/sx127x.h
Normal file
@ -0,0 +1,125 @@
|
||||
#pragma once
|
||||
|
||||
#include "sx127x_reg.h"
|
||||
#include "esphome/components/spi/spi.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace sx127x {
|
||||
|
||||
enum SX127xBw : uint8_t {
|
||||
SX127X_BW_2_6,
|
||||
SX127X_BW_3_1,
|
||||
SX127X_BW_3_9,
|
||||
SX127X_BW_5_2,
|
||||
SX127X_BW_6_3,
|
||||
SX127X_BW_7_8,
|
||||
SX127X_BW_10_4,
|
||||
SX127X_BW_12_5,
|
||||
SX127X_BW_15_6,
|
||||
SX127X_BW_20_8,
|
||||
SX127X_BW_25_0,
|
||||
SX127X_BW_31_3,
|
||||
SX127X_BW_41_7,
|
||||
SX127X_BW_50_0,
|
||||
SX127X_BW_62_5,
|
||||
SX127X_BW_83_3,
|
||||
SX127X_BW_100_0,
|
||||
SX127X_BW_125_0,
|
||||
SX127X_BW_166_7,
|
||||
SX127X_BW_200_0,
|
||||
SX127X_BW_250_0,
|
||||
SX127X_BW_500_0,
|
||||
};
|
||||
|
||||
class SX127xListener {
|
||||
public:
|
||||
virtual void on_packet(const std::vector<uint8_t> &packet, float rssi, float snr) = 0;
|
||||
};
|
||||
|
||||
class SX127x : public Component,
|
||||
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
|
||||
spi::DATA_RATE_8MHZ> {
|
||||
public:
|
||||
size_t get_max_packet_size();
|
||||
float get_setup_priority() const override { return setup_priority::PROCESSOR; }
|
||||
void setup() override;
|
||||
void loop() override;
|
||||
void dump_config() override;
|
||||
void set_auto_cal(bool auto_cal) { this->auto_cal_ = auto_cal; }
|
||||
void set_bandwidth(SX127xBw bandwidth) { this->bandwidth_ = bandwidth; }
|
||||
void set_bitrate(uint32_t bitrate) { this->bitrate_ = bitrate; }
|
||||
void set_bitsync(bool bitsync) { this->bitsync_ = bitsync; }
|
||||
void set_coding_rate(uint8_t coding_rate) { this->coding_rate_ = coding_rate; }
|
||||
void set_crc_enable(bool crc_enable) { this->crc_enable_ = crc_enable; }
|
||||
void set_deviation(uint32_t deviation) { this->deviation_ = deviation; }
|
||||
void set_dio0_pin(InternalGPIOPin *dio0_pin) { this->dio0_pin_ = dio0_pin; }
|
||||
void set_frequency(uint32_t frequency) { this->frequency_ = frequency; }
|
||||
void set_mode_rx();
|
||||
void set_mode_tx();
|
||||
void set_mode_standby();
|
||||
void set_mode_sleep();
|
||||
void set_modulation(uint8_t modulation) { this->modulation_ = modulation; }
|
||||
void set_pa_pin(uint8_t pin) { this->pa_pin_ = pin; }
|
||||
void set_pa_power(uint8_t power) { this->pa_power_ = power; }
|
||||
void set_pa_ramp(uint8_t ramp) { this->pa_ramp_ = ramp; }
|
||||
void set_packet_mode(bool packet_mode) { this->packet_mode_ = packet_mode; }
|
||||
void set_payload_length(uint8_t payload_length) { this->payload_length_ = payload_length; }
|
||||
void set_preamble_errors(uint8_t preamble_errors) { this->preamble_errors_ = preamble_errors; }
|
||||
void set_preamble_polarity(uint8_t preamble_polarity) { this->preamble_polarity_ = preamble_polarity; }
|
||||
void set_preamble_size(uint16_t preamble_size) { this->preamble_size_ = preamble_size; }
|
||||
void set_preamble_detect(uint8_t preamble_detect) { this->preamble_detect_ = preamble_detect; }
|
||||
void set_rst_pin(InternalGPIOPin *rst_pin) { this->rst_pin_ = rst_pin; }
|
||||
void set_rx_floor(float floor) { this->rx_floor_ = floor; }
|
||||
void set_rx_start(bool start) { this->rx_start_ = start; }
|
||||
void set_shaping(uint8_t shaping) { this->shaping_ = shaping; }
|
||||
void set_spreading_factor(uint8_t spreading_factor) { this->spreading_factor_ = spreading_factor; }
|
||||
void set_sync_value(const std::vector<uint8_t> &sync_value) { this->sync_value_ = sync_value; }
|
||||
void run_image_cal();
|
||||
void configure();
|
||||
void transmit_packet(const std::vector<uint8_t> &packet);
|
||||
void register_listener(SX127xListener *listener) { this->listeners_.push_back(listener); }
|
||||
Trigger<std::vector<uint8_t>, float, float> *get_packet_trigger() const { return this->packet_trigger_; };
|
||||
|
||||
protected:
|
||||
void configure_fsk_ook_();
|
||||
void configure_lora_();
|
||||
void set_mode_(uint8_t modulation, uint8_t mode);
|
||||
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);
|
||||
void call_listeners_(const std::vector<uint8_t> &packet, float rssi, float snr);
|
||||
uint8_t read_register_(uint8_t reg);
|
||||
Trigger<std::vector<uint8_t>, float, float> *packet_trigger_{new Trigger<std::vector<uint8_t>, float, float>()};
|
||||
std::vector<SX127xListener *> listeners_;
|
||||
std::vector<uint8_t> sync_value_;
|
||||
InternalGPIOPin *dio0_pin_{nullptr};
|
||||
InternalGPIOPin *rst_pin_{nullptr};
|
||||
SX127xBw bandwidth_;
|
||||
uint32_t bitrate_;
|
||||
uint32_t deviation_;
|
||||
uint32_t frequency_;
|
||||
uint32_t payload_length_;
|
||||
uint16_t preamble_size_;
|
||||
uint8_t coding_rate_;
|
||||
uint8_t modulation_;
|
||||
uint8_t pa_pin_;
|
||||
uint8_t pa_power_;
|
||||
uint8_t pa_ramp_;
|
||||
uint8_t preamble_detect_;
|
||||
uint8_t preamble_errors_;
|
||||
uint8_t preamble_polarity_;
|
||||
uint8_t shaping_;
|
||||
uint8_t spreading_factor_;
|
||||
float rx_floor_;
|
||||
bool auto_cal_{false};
|
||||
bool bitsync_{false};
|
||||
bool crc_enable_{false};
|
||||
bool packet_mode_{false};
|
||||
bool rx_start_{false};
|
||||
};
|
||||
|
||||
} // namespace sx127x
|
||||
} // namespace esphome
|
295
esphome/components/sx127x/sx127x_reg.h
Normal file
295
esphome/components/sx127x/sx127x_reg.h
Normal file
@ -0,0 +1,295 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace sx127x {
|
||||
|
||||
enum SX127xReg : uint8_t {
|
||||
// Common registers
|
||||
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,
|
||||
REG_FRF_MID = 0x07,
|
||||
REG_FRF_LSB = 0x08,
|
||||
REG_PA_CONFIG = 0x09,
|
||||
REG_PA_RAMP = 0x0A,
|
||||
REG_DIO_MAPPING1 = 0x40,
|
||||
REG_DIO_MAPPING2 = 0x41,
|
||||
REG_VERSION = 0x42,
|
||||
// FSK/OOK registers
|
||||
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_SIZE_MSB = 0x25,
|
||||
REG_PREAMBLE_SIZE_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_LSB = 0x32,
|
||||
REG_FIFO_THRESH = 0x35,
|
||||
REG_IMAGE_CAL = 0x3B,
|
||||
// LoRa registers
|
||||
REG_FIFO_ADDR_PTR = 0x0D,
|
||||
REG_FIFO_TX_BASE_ADDR = 0x0E,
|
||||
REG_FIFO_RX_BASE_ADDR = 0x0F,
|
||||
REG_FIFO_RX_CURR_ADDR = 0x10,
|
||||
REG_IRQ_FLAGS_MASK = 0x11,
|
||||
REG_IRQ_FLAGS = 0x12,
|
||||
REG_NB_RX_BYTES = 0x13,
|
||||
REG_MODEM_STAT = 0x18,
|
||||
REG_PKT_SNR_VALUE = 0x19,
|
||||
REG_PKT_RSSI_VALUE = 0x1A,
|
||||
REG_RSSI_VALUE = 0x1B,
|
||||
REG_HOP_CHANNEL = 0x1C,
|
||||
REG_MODEM_CONFIG1 = 0x1D,
|
||||
REG_MODEM_CONFIG2 = 0x1E,
|
||||
REG_SYMB_TIMEOUT_LSB = 0x1F,
|
||||
REG_PREAMBLE_LEN_MSB = 0x20,
|
||||
REG_PREAMBLE_LEN_LSB = 0x21,
|
||||
REG_PAYLOAD_LENGTH = 0x22,
|
||||
REG_HOP_PERIOD = 0x24,
|
||||
REG_FIFO_RX_BYTE_ADDR = 0x25,
|
||||
REG_MODEM_CONFIG3 = 0x26,
|
||||
REG_FEI_MSB = 0x28,
|
||||
REG_FEI_MIB = 0x29,
|
||||
REG_FEI_LSB = 0x2A,
|
||||
REG_DETECT_OPTIMIZE = 0x31,
|
||||
REG_INVERT_IQ = 0x33,
|
||||
REG_DETECT_THRESHOLD = 0x37,
|
||||
REG_SYNC_WORD = 0x39,
|
||||
};
|
||||
|
||||
enum SX127xOpMode : uint8_t {
|
||||
MOD_LORA = 0x80,
|
||||
ACCESS_FSK_REGS = 0x40,
|
||||
ACCESS_LORA_REGS = 0x00,
|
||||
MOD_OOK = 0x20,
|
||||
MOD_FSK = 0x00,
|
||||
ACCESS_LF_REGS = 0x08,
|
||||
ACCESS_HF_REGS = 0x00,
|
||||
MODE_CAD = 0x07,
|
||||
MODE_RX_SINGLE = 0x06,
|
||||
MODE_RX = 0x05,
|
||||
MODE_RX_FS = 0x04,
|
||||
MODE_TX = 0x03,
|
||||
MODE_TX_FS = 0x02,
|
||||
MODE_STDBY = 0x01,
|
||||
MODE_SLEEP = 0x00,
|
||||
MODE_MASK = 0x07,
|
||||
};
|
||||
|
||||
enum SX127xPaConfig : uint8_t {
|
||||
PA_PIN_BOOST = 0x80,
|
||||
PA_PIN_RFO = 0x00,
|
||||
PA_MAX_POWER = 0x70,
|
||||
};
|
||||
|
||||
enum SX127xPaRamp : uint8_t {
|
||||
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,
|
||||
SHAPING_NONE = 0x00,
|
||||
PA_RAMP_10 = 0x0F,
|
||||
PA_RAMP_12 = 0x0E,
|
||||
PA_RAMP_15 = 0x0D,
|
||||
PA_RAMP_20 = 0x0C,
|
||||
PA_RAMP_25 = 0x0B,
|
||||
PA_RAMP_31 = 0x0A,
|
||||
PA_RAMP_40 = 0x09,
|
||||
PA_RAMP_50 = 0x08,
|
||||
PA_RAMP_62 = 0x07,
|
||||
PA_RAMP_100 = 0x06,
|
||||
PA_RAMP_125 = 0x05,
|
||||
PA_RAMP_250 = 0x04,
|
||||
PA_RAMP_500 = 0x03,
|
||||
PA_RAMP_1000 = 0x02,
|
||||
PA_RAMP_2000 = 0x01,
|
||||
PA_RAMP_3400 = 0x00,
|
||||
};
|
||||
|
||||
enum SX127xDioMapping1 : uint8_t {
|
||||
DIO0_MAPPING_00 = 0x00,
|
||||
DIO0_MAPPING_01 = 0x40,
|
||||
DIO0_MAPPING_10 = 0x80,
|
||||
DIO0_MAPPING_11 = 0xC0,
|
||||
};
|
||||
|
||||
enum SX127xRxConfig : uint8_t {
|
||||
RESTART_ON_COLLISION = 0x80,
|
||||
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 SX127xRxBw : uint8_t {
|
||||
RX_BW_2_6 = 0x17,
|
||||
RX_BW_3_1 = 0x0F,
|
||||
RX_BW_3_9 = 0x07,
|
||||
RX_BW_5_2 = 0x16,
|
||||
RX_BW_6_3 = 0x0E,
|
||||
RX_BW_7_8 = 0x06,
|
||||
RX_BW_10_4 = 0x15,
|
||||
RX_BW_12_5 = 0x0D,
|
||||
RX_BW_15_6 = 0x05,
|
||||
RX_BW_20_8 = 0x14,
|
||||
RX_BW_25_0 = 0x0C,
|
||||
RX_BW_31_3 = 0x04,
|
||||
RX_BW_41_7 = 0x13,
|
||||
RX_BW_50_0 = 0x0B,
|
||||
RX_BW_62_5 = 0x03,
|
||||
RX_BW_83_3 = 0x12,
|
||||
RX_BW_100_0 = 0x0A,
|
||||
RX_BW_125_0 = 0x02,
|
||||
RX_BW_166_7 = 0x11,
|
||||
RX_BW_200_0 = 0x09,
|
||||
RX_BW_250_0 = 0x01,
|
||||
};
|
||||
|
||||
enum SX127xOokPeak : uint8_t {
|
||||
BIT_SYNC_ON = 0x20,
|
||||
BIT_SYNC_OFF = 0x00,
|
||||
OOK_THRESH_AVG = 0x10,
|
||||
OOK_THRESH_PEAK = 0x08,
|
||||
OOK_THRESH_FIXED = 0x00,
|
||||
OOK_THRESH_STEP_6_0 = 0x07,
|
||||
OOK_THRESH_STEP_5_0 = 0x06,
|
||||
OOK_THRESH_STEP_4_0 = 0x05,
|
||||
OOK_THRESH_STEP_3_0 = 0x04,
|
||||
OOK_THRESH_STEP_2_0 = 0x03,
|
||||
OOK_THRESH_STEP_1_5 = 0x02,
|
||||
OOK_THRESH_STEP_1_0 = 0x01,
|
||||
OOK_THRESH_STEP_0_5 = 0x00,
|
||||
};
|
||||
|
||||
enum SX127xOokAvg : uint8_t {
|
||||
OOK_THRESH_DEC_16 = 0xE0,
|
||||
OOK_THRESH_DEC_8 = 0xC0,
|
||||
OOK_THRESH_DEC_4 = 0xA0,
|
||||
OOK_THRESH_DEC_2 = 0x80,
|
||||
OOK_THRESH_DEC_1_8 = 0x60,
|
||||
OOK_THRESH_DEC_1_4 = 0x40,
|
||||
OOK_THRESH_DEC_1_2 = 0x20,
|
||||
OOK_THRESH_DEC_1 = 0x00,
|
||||
OOK_AVG_RESERVED = 0x10,
|
||||
};
|
||||
|
||||
enum SX127xAfcFei : uint8_t {
|
||||
AFC_AUTO_CLEAR_ON = 0x01,
|
||||
};
|
||||
|
||||
enum SX127xPreambleDetect : uint8_t {
|
||||
PREAMBLE_DETECTOR_ON = 0x80,
|
||||
PREAMBLE_DETECTOR_OFF = 0x00,
|
||||
PREAMBLE_DETECTOR_SIZE_SHIFT = 5,
|
||||
PREAMBLE_DETECTOR_TOL_SHIFT = 0,
|
||||
};
|
||||
|
||||
enum SX127xSyncConfig : uint8_t {
|
||||
AUTO_RESTART_PLL_LOCK = 0x80,
|
||||
AUTO_RESTART_NO_LOCK = 0x40,
|
||||
AUTO_RESTART_OFF = 0x00,
|
||||
PREAMBLE_55 = 0x20,
|
||||
PREAMBLE_AA = 0x00,
|
||||
SYNC_ON = 0x10,
|
||||
SYNC_OFF = 0x00,
|
||||
};
|
||||
|
||||
enum SX127xPacketConfig1 : uint8_t {
|
||||
VARIABLE_LENGTH = 0x80,
|
||||
FIXED_LENGTH = 0x00,
|
||||
CRC_ON = 0x10,
|
||||
CRC_OFF = 0x00,
|
||||
};
|
||||
|
||||
enum SX127xPacketConfig2 : uint8_t {
|
||||
CONTINUOUS_MODE = 0x00,
|
||||
PACKET_MODE = 0x40,
|
||||
};
|
||||
|
||||
enum SX127xFifoThresh : uint8_t {
|
||||
TX_START_FIFO_EMPTY = 0x80,
|
||||
TX_START_FIFO_LEVEL = 0x00,
|
||||
};
|
||||
|
||||
enum SX127xImageCal : uint8_t {
|
||||
AUTO_IMAGE_CAL_ON = 0x80,
|
||||
IMAGE_CAL_START = 0x40,
|
||||
IMAGE_CAL_RUNNING = 0x20,
|
||||
TEMP_CHANGE = 0x08,
|
||||
TEMP_THRESHOLD_20C = 0x06,
|
||||
TEMP_THRESHOLD_15C = 0x04,
|
||||
TEMP_THRESHOLD_10C = 0x02,
|
||||
TEMP_THRESHOLD_5C = 0x00,
|
||||
TEMP_MONITOR_OFF = 0x01,
|
||||
TEMP_MONITOR_ON = 0x00,
|
||||
};
|
||||
|
||||
enum SX127xIrqFlags : uint8_t {
|
||||
RX_TIMEOUT = 0x80,
|
||||
RX_DONE = 0x40,
|
||||
PAYLOAD_CRC_ERROR = 0x20,
|
||||
VALID_HEADER = 0x10,
|
||||
TX_DONE = 0x08,
|
||||
CAD_DONE = 0x04,
|
||||
FHSS_CHANGE_CHANNEL = 0x02,
|
||||
CAD_DETECTED = 0x01,
|
||||
};
|
||||
|
||||
enum SX127xModemCfg1 : uint8_t {
|
||||
BW_7_8 = 0x00,
|
||||
BW_10_4 = 0x10,
|
||||
BW_15_6 = 0x20,
|
||||
BW_20_8 = 0x30,
|
||||
BW_31_3 = 0x40,
|
||||
BW_41_7 = 0x50,
|
||||
BW_62_5 = 0x60,
|
||||
BW_125_0 = 0x70,
|
||||
BW_250_0 = 0x80,
|
||||
BW_500_0 = 0x90,
|
||||
CODING_RATE_4_5 = 0x02,
|
||||
CODING_RATE_4_6 = 0x04,
|
||||
CODING_RATE_4_7 = 0x06,
|
||||
CODING_RATE_4_8 = 0x08,
|
||||
IMPLICIT_HEADER = 0x01,
|
||||
EXPLICIT_HEADER = 0x00,
|
||||
};
|
||||
|
||||
enum SX127xModemCfg2 : uint8_t {
|
||||
SPREADING_FACTOR_SHIFT = 4,
|
||||
TX_CONTINOUS_MODE = 0x08,
|
||||
RX_PAYLOAD_CRC_ON = 0x04,
|
||||
RX_PAYLOAD_CRC_OFF = 0x00,
|
||||
};
|
||||
|
||||
enum SX127xModemCfg3 : uint8_t {
|
||||
LOW_DATA_RATE_OPTIMIZE_ON = 0x08,
|
||||
MODEM_AGC_AUTO_ON = 0x04,
|
||||
};
|
||||
|
||||
} // namespace sx127x
|
||||
} // namespace esphome
|
45
tests/components/sx127x/common.yaml
Normal file
45
tests/components/sx127x/common.yaml
Normal file
@ -0,0 +1,45 @@
|
||||
spi:
|
||||
clk_pin: ${clk_pin}
|
||||
mosi_pin: ${mosi_pin}
|
||||
miso_pin: ${miso_pin}
|
||||
|
||||
sx127x:
|
||||
cs_pin: ${cs_pin}
|
||||
rst_pin: ${rst_pin}
|
||||
dio0_pin: ${dio0_pin}
|
||||
pa_pin: BOOST
|
||||
pa_power: 17
|
||||
pa_ramp: 40us
|
||||
bitsync: true
|
||||
bitrate: 4800
|
||||
bandwidth: 50_0kHz
|
||||
frequency: 433920000
|
||||
modulation: FSK
|
||||
deviation: 5000
|
||||
rx_start: true
|
||||
rx_floor: -90
|
||||
packet_mode: true
|
||||
payload_length: 8
|
||||
sync_value: [0x33, 0x33]
|
||||
shaping: NONE
|
||||
preamble_size: 2
|
||||
preamble_detect: 2
|
||||
preamble_errors: 8
|
||||
preamble_polarity: 0x55
|
||||
on_packet:
|
||||
then:
|
||||
- sx127x.send_packet:
|
||||
data: [0xC5, 0x51, 0x78, 0x82, 0xB7, 0xF9, 0x9C, 0x5C]
|
||||
|
||||
button:
|
||||
- platform: template
|
||||
name: "SX127x Button"
|
||||
on_press:
|
||||
then:
|
||||
- sx127x.set_mode_standby
|
||||
- sx127x.run_image_cal
|
||||
- sx127x.set_mode_tx
|
||||
- sx127x.set_mode_sleep
|
||||
- sx127x.set_mode_rx
|
||||
- sx127x.send_packet:
|
||||
data: [0xC5, 0x51, 0x78, 0x82, 0xB7, 0xF9, 0x9C, 0x5C]
|
9
tests/components/sx127x/test.esp32-ard.yaml
Normal file
9
tests/components/sx127x/test.esp32-ard.yaml
Normal file
@ -0,0 +1,9 @@
|
||||
substitutions:
|
||||
clk_pin: GPIO5
|
||||
mosi_pin: GPIO27
|
||||
miso_pin: GPIO19
|
||||
cs_pin: GPIO18
|
||||
rst_pin: GPIO23
|
||||
dio0_pin: GPIO26
|
||||
|
||||
<<: !include common.yaml
|
9
tests/components/sx127x/test.esp32-c3-ard.yaml
Normal file
9
tests/components/sx127x/test.esp32-c3-ard.yaml
Normal file
@ -0,0 +1,9 @@
|
||||
substitutions:
|
||||
clk_pin: GPIO5
|
||||
mosi_pin: GPIO18
|
||||
miso_pin: GPIO19
|
||||
cs_pin: GPIO1
|
||||
rst_pin: GPIO2
|
||||
dio0_pin: GPIO3
|
||||
|
||||
<<: !include common.yaml
|
9
tests/components/sx127x/test.esp32-c3-idf.yaml
Normal file
9
tests/components/sx127x/test.esp32-c3-idf.yaml
Normal file
@ -0,0 +1,9 @@
|
||||
substitutions:
|
||||
clk_pin: GPIO5
|
||||
mosi_pin: GPIO18
|
||||
miso_pin: GPIO19
|
||||
cs_pin: GPIO1
|
||||
rst_pin: GPIO2
|
||||
dio0_pin: GPIO3
|
||||
|
||||
<<: !include common.yaml
|
9
tests/components/sx127x/test.esp32-idf.yaml
Normal file
9
tests/components/sx127x/test.esp32-idf.yaml
Normal file
@ -0,0 +1,9 @@
|
||||
substitutions:
|
||||
clk_pin: GPIO5
|
||||
mosi_pin: GPIO27
|
||||
miso_pin: GPIO19
|
||||
cs_pin: GPIO18
|
||||
rst_pin: GPIO23
|
||||
dio0_pin: GPIO26
|
||||
|
||||
<<: !include common.yaml
|
9
tests/components/sx127x/test.esp8266-ard.yaml
Normal file
9
tests/components/sx127x/test.esp8266-ard.yaml
Normal file
@ -0,0 +1,9 @@
|
||||
substitutions:
|
||||
clk_pin: GPIO5
|
||||
mosi_pin: GPIO13
|
||||
miso_pin: GPIO12
|
||||
cs_pin: GPIO1
|
||||
rst_pin: GPIO2
|
||||
dio0_pin: GPIO3
|
||||
|
||||
<<: !include common.yaml
|
9
tests/components/sx127x/test.rp2040-ard.yaml
Normal file
9
tests/components/sx127x/test.rp2040-ard.yaml
Normal file
@ -0,0 +1,9 @@
|
||||
substitutions:
|
||||
clk_pin: GPIO2
|
||||
mosi_pin: GPIO3
|
||||
miso_pin: GPIO4
|
||||
cs_pin: GPIO5
|
||||
rst_pin: GPIO6
|
||||
dio0_pin: GPIO7
|
||||
|
||||
<<: !include common.yaml
|
Loading…
x
Reference in New Issue
Block a user