diff --git a/adafruit_rfm/rfm9x.py b/adafruit_rfm/rfm9x.py index 2848292..5cda864 100644 --- a/adafruit_rfm/rfm9x.py +++ b/adafruit_rfm/rfm9x.py @@ -169,6 +169,8 @@ class RFM9x(RFMSPI): auto_agc = RFMSPI.RegisterBits(_RF95_REG_26_MODEM_CONFIG3, offset=2, bits=1) + header_mode = RFMSPI.RegisterBits(_RF95_REG_1D_MODEM_CONFIG1, offset=0, bits=1) + low_datarate_optimize = RFMSPI.RegisterBits(_RF95_REG_26_MODEM_CONFIG3, offset=3, bits=1) lna_boost_hf = RFMSPI.RegisterBits(_RF95_REG_0C_LNA, offset=0, bits=2) @@ -424,6 +426,11 @@ def signal_bandwidth(self, val: int) -> None: else: self.write_u8(0x2F, 0x44) self.write_u8(0x30, 0) + # set low_datarate_optimize for signal duration > 16 ms + if 1000 / (self.signal_bandwidth / (1 << self.spreading_factor)) > 16: + self.low_datarate_optimize = 1 + else: + self.low_datarate_optimize = 0 @property def coding_rate(self) -> Literal[5, 6, 7, 8]: @@ -461,14 +468,21 @@ def spreading_factor(self, val: Literal[6, 7, 8, 9, 10, 11, 12]) -> None: if val == 6: self.detection_optimize = 0x5 + self.header_mode = 1 # enable implicit header mode else: self.detection_optimize = 0x3 + self.header_mode = 0 # enable exlicit header mode self.write_u8(_RF95_DETECTION_THRESHOLD, 0x0C if val == 6 else 0x0A) self.write_u8( _RF95_REG_1E_MODEM_CONFIG2, ((self.read_u8(_RF95_REG_1E_MODEM_CONFIG2) & 0x0F) | ((val << 4) & 0xF0)), ) + # set low_datarate_optimize for signal duration > 16 ms + if 1000 / (self.signal_bandwidth / (1 << self.spreading_factor)) > 16: + self.low_datarate_optimize = 1 + else: + self.low_datarate_optimize = 0 @property def enable_crc(self) -> bool: @@ -491,6 +505,16 @@ def enable_crc(self, val: bool) -> None: self.read_u8(_RF95_REG_1E_MODEM_CONFIG2) & 0xFB, ) + @property + def payload_length(self) -> int: + """Must be set when using Implicit Header Mode - required for SF = 6""" + return self.read_u8(_RF95_REG_22_PAYLOAD_LENGTH) + + @payload_length.setter + def payload_length(self, val: int) -> None: + # Set payload length + self.write_u8(_RF95_REG_22_PAYLOAD_LENGTH, val) + @property def crc_error(self) -> bool: """crc status""" diff --git a/examples/rfm_lora_sf_base.py b/examples/rfm_lora_sf_base.py new file mode 100644 index 0000000..29aae15 --- /dev/null +++ b/examples/rfm_lora_sf_base.py @@ -0,0 +1,98 @@ +# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-License-Identifier: MIT + +import time + +import board +import busio +import digitalio + +# Define radio parameters. +RADIO_FREQ_MHZ = 915.0 # Frequency of the radio in Mhz. Must match your +# module! Can be a value like 915.0, 433.0, etc. + +# Define pins connected to the chip, use these if wiring up the breakout according to the guide: +CS = digitalio.DigitalInOut(board.CE1) +RESET = digitalio.DigitalInOut(board.D25) + +# Initialize SPI bus. +spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) + +# Initialze RFM radio +# uncommnet the desired import and rfm initialization depending on the radio boards being used + +# Use rfm9x for two RFM9x radios using LoRa + +from adafruit_rfm import rfm9x + +rfm = rfm9x.RFM9x(spi, CS, RESET, RADIO_FREQ_MHZ) + +rfm.radiohead = False # don't appent RadioHead heade +# set spreading factor +rfm.spreading_factor = 7 +print("spreading factor set to :", rfm.spreading_factor) +print("low_datarate_optimize set to: ", rfm.low_datarate_optimize) +# rfm.signal_bandwidth = 500000 +print("signal_bandwidth set to :", rfm.signal_bandwidth) +print("low_datarate_optimize set to: ", rfm.low_datarate_optimize) +if rfm.spreading_factor == 12: + rfm.xmit_timeout = 5 +print("xmit_timeout set to: ", rfm.xmit_timeout) +if rfm.spreading_factor == 12: + rfm.receive_timeout = 5 +elif rfm.spreading_factor > 7: + rfm.receive_timeout = 2 +print("receive_timeout set to: ", rfm.receive_timeout) +rfm.enable_crc = True +# send startup message +message = bytes(f"startup message from base", "UTF-8") +if rfm.spreading_factor == 6: + payload = bytearray(40) + rfm.payload_length = len(payload) + payload[0 : len(message)] = message + rfm.send( + payload, + keep_listening=True, + ) +else: + rfm.send( + message, + keep_listening=True, + ) +# Wait to receive packets. +print("Waiting for packets...") +# initialize flag and timer +# set a delay before sending the echo packet +# avoide multibples of .5 second to minimize chances of node missing +# the packet between receive attempts +transmit_delay = 0.75 +last_transmit_time = 0 +packet_received = False +while True: + if rfm.payload_ready(): + packet_received = False + packet = rfm.receive(timeout=None) + if packet is not None: + # Received a packet! + # Print out the raw bytes of the packet: + print(f"Received (raw payload): {packet}") + print([hex(x) for x in packet]) + print(f"RSSI: {rfm.last_rssi}") + packet_received = True + last_transmit_time = time.monotonic() + if packet_received and ((time.monotonic() - last_transmit_time) > transmit_delay): + # send back the received packet + if rfm.spreading_factor == 6: + payload = bytearray(40) + rfm.payload_length = len(payload) + payload[0 : len(packet)] = packet + rfm.send( + payload, + keep_listening=True, + ) + else: + rfm.send( + packet, + keep_listening=True, + ) + packet_received = False diff --git a/examples/rfm_lora_sf_node.py b/examples/rfm_lora_sf_node.py new file mode 100644 index 0000000..325a4f2 --- /dev/null +++ b/examples/rfm_lora_sf_node.py @@ -0,0 +1,105 @@ +# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-License-Identifier: MIT + +# Example to send a packet periodically between addressed nodes with ACK +# Author: Jerry Needell +# +import time + +import board +import busio +import digitalio + +# Define radio parameters. +RADIO_FREQ_MHZ = 915.0 # Frequency of the radio in Mhz. Must match your +# module! Can be a value like 915.0, 433.0, etc. + +# Define pins connected to the chip, use these if wiring up the breakout according to the guide: +CS = digitalio.DigitalInOut(board.CE1) +RESET = digitalio.DigitalInOut(board.D25) + +# Initialize SPI bus. +spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) + +# Initialze RFM radio +# uncommnet the desired import and rfm initialization depending on the radio boards being used + +# Use rfm9x for two RFM9x radios using LoRa + +from adafruit_rfm import rfm9x + +rfm = rfm9x.RFM9x(spi, CS, RESET, RADIO_FREQ_MHZ) + +rfm.radiohead = False # Do not use RadioHead Header +# set spreading factor +rfm.spreading_factor = 7 +print("spreading factor set to :", rfm.spreading_factor) +print("low_datarate_optimize set to: ", rfm.low_datarate_optimize) +# rfm.signal_bandwidth = 500000 +print("signal_bandwidth set to :", rfm.signal_bandwidth) +print("low_datarate_optimize set to: ", rfm.low_datarate_optimize) +if rfm.spreading_factor == 12: + rfm.xmit_timeout = 5 +print("xmit_timeout set to: ", rfm.xmit_timeout) +if rfm.spreading_factor == 12: + rfm.receive_timeout = 5 +elif rfm.spreading_factor > 7: + rfm.receive_timeout = 2 +print("receive_timeout set to: ", rfm.receive_timeout) +rfm.enable_crc = True +# set the time interval (seconds) for sending packets +transmit_interval = 10 + +# initialize counter +counter = 0 +# send startup message from my_node +message = bytes(f"startup message from node", "UTF-8") +if rfm.spreading_factor == 6: + payload = bytearray(40) + rfm.payload_length = len(payload) + payload[0 : len(message)] = message + rfm.send( + payload, + keep_listening=True, + ) +else: + rfm.send( + message, + keep_listening=True, + ) + +# Wait to receive packets. +print("Waiting for packets...") +# initialize flag and timer +last_transmit_time = time.monotonic() +while True: + # Look for a new packet: only accept if addresses to my_node + packet = rfm.receive() + # If no packet was received during the timeout then None is returned. + if packet is not None: + # Received a packet! + # Print out the raw bytes of the packet: + print(f"Received (raw payload): {packet}") + print([hex(x) for x in packet]) + print(f"RSSI: {rfm.last_rssi}") + # send reading after any packet received + if time.monotonic() - last_transmit_time > transmit_interval: + # reset timeer + last_transmit_time = time.monotonic() + # send a mesage to destination_node from my_node + message = bytes(f"message from node {counter}", "UTF-8") + if rfm.spreading_factor == 6: + payload = bytearray(40) + rfm.payload_length = len(payload) + payload[0 : len(message)] = message + rfm.send( + payload, + keep_listening=True, + ) + else: + rfm.send( + message, + keep_listening=True, + ) + + counter += 1