mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 06:33:51 +00:00 
			
		
		
		
	[sx127x] Add sx127x component (#7490)
Co-authored-by: Jonathan Swoboda <jonathan.swoboda>
This commit is contained in:
		| @@ -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 | ||||
		Reference in New Issue
	
	Block a user