class SX127x: default_parameters = { 'frequency': 868E6, 'tx_power_level': 2, 'signal_bandwidth': 125E3, 'spreading_factor': 8, 'coding_rate': 5, 'preamble_length': 8, 'implicit_header': False, 'sync_word': 0x12, 'enable_CRC': False, 'invert_IQ': False, } frfs = { 169E6: (42, 64, 0), 433E6: (108, 64, 0), 434E6: (108, 128, 0), 866E6: (216, 128, 0), 868E6: (217, 0, 0), 915E6: (228, 192, 0) } def __init__(self, spi, pins, parameters=default_parameters): self._spi = spi self._pins = pins self._parameters = parameters self._lock = False # setting pins if "dio_0" in self._pins: self._pin_rx_done = Pin(self._pins["dio_0"], Pin.IN) if "ss" in self._pins: self._pin_ss = Pin(self._pins["ss"], Pin.OUT) if "led" in self._pins: self._led_status = Pin(self._pins["led"], Pin.OUT) # check hardware version init_try = True re_try = 0 while init_try and re_try < 5: version = self.read_register(REG_VERSION) re_try = re_try + 1 if version != 0: init_try = False if version != 0x12: raise Exception('Invalid version.') if __DEBUG__: print("SX version: {}".format(version)) # put in LoRa and sleep mode self.sleep() # config self.set_frequency(self._parameters['frequency']) self.set_signal_bandwidth(self._parameters['signal_bandwidth']) # set LNA boost self.write_register(REG_LNA, self.read_register(REG_LNA) | 0x03) # set auto AGC self.write_register(REG_MODEM_CONFIG_3, 0x04) self.set_tx_power(self._parameters['tx_power_level']) self._implicit_header_mode = None self.implicit_header_mode(self._parameters['implicit_header']) self.set_spreading_factor(self._parameters['spreading_factor']) self.set_coding_rate(self._parameters['coding_rate']) self.set_preamble_length(self._parameters['preamble_length']) self.set_sync_word(self._parameters['sync_word']) self.enable_CRC(self._parameters['enable_CRC']) self.invert_IQ(self._parameters["invert_IQ"]) # set LowDataRateOptimize flag if symbol time > 16ms (default disable on reset) # self.write_register(REG_MODEM_CONFIG_3, self.read_register(REG_MODEM_CONFIG_3) & 0xF7) # default disable on reset bw_parameter = self._parameters["signal_bandwidth"] sf_parameter = self._parameters["spreading_factor"] if 1000 / (bw_parameter / 2**sf_parameter) > 16: self.write_register(REG_MODEM_CONFIG_3, self.read_register(REG_MODEM_CONFIG_3) | 0x08) # set base addresses self.write_register(REG_FIFO_TX_BASE_ADDR, FifoTxBaseAddr) self.write_register(REG_FIFO_RX_BASE_ADDR, FifoRxBaseAddr) self.standby() def begin_packet(self, implicit_header_mode=False): self.standby() self.implicit_header_mode(implicit_header_mode) # reset FIFO address and paload length self.write_register(REG_FIFO_ADDR_PTR, FifoTxBaseAddr) self.write_register(REG_PAYLOAD_LENGTH, 0) def end_packet(self): # put in TX mode self.write_register(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX) # wait for TX done, standby automatically on TX_DONE while self.read_register(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK == 0: pass # clear IRQ's self.write_register(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK) self.collect_garbage() def write(self, buffer): currentLength = self.read_register(REG_PAYLOAD_LENGTH) size = len(buffer) # check size size = min(size, (MAX_PKT_LENGTH - FifoTxBaseAddr - currentLength)) # write data for i in range(size): self.write_register(REG_FIFO, buffer[i]) # update length self.write_register(REG_PAYLOAD_LENGTH, currentLength + size) return size def set_lock(self, lock=False): self._lock = lock def println(self, msg, implicit_header=False): self.set_lock(True) # wait until RX_Done, lock and begin writing. self.begin_packet(implicit_header) if isinstance(msg, str): message = msg.encode() self.write(message) self.end_packet() self.set_lock(False) # unlock when done writing self.collect_garbage() def get_irq_flags(self): irq_flags = self.read_register(REG_IRQ_FLAGS) self.write_register(REG_IRQ_FLAGS, irq_flags) return irq_flags def packet_rssi(self): rssi = self.read_register(REG_PKT_RSSI_VALUE) return (rssi - (164 if self._frequency < 868E6 else 157)) def packet_snr(self): snr = self.read_register(REG_PKT_SNR_VALUE) return snr * 0.25 def standby(self): self.write_register(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_STDBY) def sleep(self): self.write_register(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_SLEEP) def set_tx_power(self, level, outputPin=PA_OUTPUT_PA_BOOST_PIN): self._tx_power_level = level if (outputPin == PA_OUTPUT_RFO_PIN): # RFO level = min(max(level, 0), 14) self.write_register(REG_PA_CONFIG, 0x70 | level) else: # PA BOOST level = min(max(level, 2), 17) self.write_register(REG_PA_CONFIG, PA_BOOST | (level - 2)) def set_frequency(self, frequency, freq_table=frfs): self._frequency = frequency self.write_register(REG_FRF_MSB, freq_table[frequency][0]) self.write_register(REG_FRF_MID, freq_table[frequency][1]) self.write_register(REG_FRF_LSB, freq_table[frequency][2]) def set_spreading_factor(self, sf): sf = min(max(sf, 6), 12) self.write_register(REG_DETECTION_OPTIMIZE, 0xc5 if sf == 6 else 0xc3) self.write_register(REG_DETECTION_THRESHOLD, 0x0c if sf == 6 else 0x0a) self.write_register(REG_MODEM_CONFIG_2, (self.read_register(REG_MODEM_CONFIG_2) & 0x0f) | ((sf << 4) & 0xf0)) def set_signal_bandwidth(self, sbw): bins = (7.8E3, 10.4E3, 15.6E3, 20.8E3, 31.25E3, 41.7E3, 62.5E3, 125E3, 250E3) bw = 9 if sbw < 10: bw = sbw else: for i in range(len(bins)): if sbw <= bins[i]: bw = i break self.write_register(REG_MODEM_CONFIG_1, (self.read_register(REG_MODEM_CONFIG_1) & 0x0f) | (bw << 4)) def set_coding_rate(self, denominator): denominator = min(max(denominator, 5), 8) cr = denominator - 4 self.write_register(REG_MODEM_CONFIG_1, (self.read_register(REG_MODEM_CONFIG_1) & 0xf1) | (cr << 1)) def set_preamble_length(self, length): self.write_register(REG_PREAMBLE_MSB, (length >> 8) & 0xff) self.write_register(REG_PREAMBLE_LSB, (length >> 0) & 0xff) def enable_CRC(self, enable_CRC=False): modem_config_2 = self.read_register(REG_MODEM_CONFIG_2) config = modem_config_2 | 0x04 if enable_CRC else modem_config_2 & 0xfb self.write_register(REG_MODEM_CONFIG_2, config) def invert_IQ(self, invert_IQ): self._parameters["invertIQ"] = invert_IQ if invert_IQ: self.write_register( REG_INVERTIQ, ((self.read_register(REG_INVERTIQ) & RFLR_INVERTIQ_TX_MASK & RFLR_INVERTIQ_RX_MASK) | RFLR_INVERTIQ_RX_ON | RFLR_INVERTIQ_TX_ON), ) self.write_register(REG_INVERTIQ2, RFLR_INVERTIQ2_ON) else: self.write_register( REG_INVERTIQ, ((self.read_register(REG_INVERTIQ) & RFLR_INVERTIQ_TX_MASK & RFLR_INVERTIQ_RX_MASK) | RFLR_INVERTIQ_RX_OFF | RFLR_INVERTIQ_TX_OFF), ) self.write_register(REG_INVERTIQ2, RFLR_INVERTIQ2_OFF) def set_sync_word(self, sw): self.write_register(REG_SYNC_WORD, sw) def set_channel(self, parameters): self.standby() for key in parameters: if key == "frequency": self.set_frequency(parameters[key]) continue if key == "invert_IQ": self.invert_IQ(parameters[key]) continue if key == "tx_power_level": self.set_tx_power(parameters[key]) continue def dump_registers(self): for i in range(128): print("0x{:02X}: {:02X}".format(i, self.read_register(i)), end="") if (i + 1) % 4 == 0: print() else: print(" | ", end="") def implicit_header_mode(self, implicit_header_mode=False): if self._implicit_header_mode != implicit_header_mode: # set value only if different. self._implicit_header_mode = implicit_header_mode modem_config_1 = self.read_register(REG_MODEM_CONFIG_1) config = (modem_config_1 | 0x01 if implicit_header_mode else modem_config_1 & 0xfe) self.write_register(REG_MODEM_CONFIG_1, config) def receive(self, size=0): self.implicit_header_mode(size > 0) if size > 0: self.write_register(REG_PAYLOAD_LENGTH, size & 0xff) # The last packet always starts at FIFO_RX_CURRENT_ADDR # no need to reset FIFO_ADDR_PTR self.write_register(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS) def on_receive(self, callback): self._on_receive = callback if self._pin_rx_done: if callback: self.write_register(REG_DIO_MAPPING_1, 0x00) self._pin_rx_done.irq(trigger=Pin.IRQ_RISING, handler=self.handle_on_receive) else: self._pin_rx_done.detach_irq() def handle_on_receive(self, event_source): self.set_lock(True) # lock until TX_Done irq_flags = self.get_irq_flags() if (irq_flags == IRQ_RX_DONE_MASK ): # RX_DONE only, irq_flags should be 0x40 # automatically standby when RX_DONE if self._on_receive: payload = self.read_payload() self._on_receive(self, payload) elif self.read_register(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE): # no packet received. # reset FIFO address / # enter single RX mode self.write_register(REG_FIFO_ADDR_PTR, FifoRxBaseAddr) self.write_register(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE) self.set_lock(False) # unlock in any case. self.collect_garbage() return True def received_packet(self, size=0): irq_flags = self.get_irq_flags() self.implicit_header_mode(size > 0) if size > 0: self.write_register(REG_PAYLOAD_LENGTH, size & 0xff) # if (irq_flags & IRQ_RX_DONE_MASK) and \ # (irq_flags & IRQ_RX_TIME_OUT_MASK == 0) and \ # (irq_flags & IRQ_PAYLOAD_CRC_ERROR_MASK == 0): if (irq_flags == IRQ_RX_DONE_MASK): # RX_DONE only, irq_flags should be 0x40 # automatically standby when RX_DONE return True elif self.read_register(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE): # no packet received. # reset FIFO address / # enter single RX mode self.write_register(REG_FIFO_ADDR_PTR, FifoRxBaseAddr) self.write_register(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE) def read_payload(self): # set FIFO address to current RX address # fifo_rx_current_addr = self.read_register(REG_FIFO_RX_CURRENT_ADDR) self.write_register(REG_FIFO_ADDR_PTR, self.read_register(REG_FIFO_RX_CURRENT_ADDR)) # read packet length if self._implicit_header_mode: packet_length = self.read_register(REG_PAYLOAD_LENGTH) else: packet_length = self.read_register(REG_RX_NB_BYTES) payload = bytearray() for i in range(packet_length): payload.append(self.read_register(REG_FIFO)) self.collect_garbage() return bytes(payload) def read_register(self, address, byteorder='big', signed=False): response = self.transfer(address & 0x7f) return int.from_bytes(response, byteorder) def write_register(self, address, value): self.transfer(address | 0x80, value) def transfer(self, address, value=0x00): response = bytearray(1) self._pin_ss.value(0) self._spi.write(bytes([address])) self._spi.write_readinto(bytes([value]), response) self._pin_ss.value(1) return response def blink_led(self, times=1, on_seconds=0.1, off_seconds=0.1): for i in range(times): if self._led_status: self._led_status.value(True) sleep(on_seconds) self._led_status.value(False) sleep(off_seconds) def collect_garbage(self): gc.collect() if __DEBUG__: print('[Memory - free: {} allocated: {}]'.format( gc.mem_free(), gc.mem_alloc()))
class SX127x: _default_parameters = { 'tx_power_level': 2, 'signal_bandwidth': 'SF7BW125', 'spreading_factor': 7, 'coding_rate': 5, 'sync_word': 0x34, 'implicit_header': False, 'preamble_length': 8, 'enable_CRC': False, 'invert_IQ': False, } _data_rates = { "SF7BW125": (0x74, 0x72, 0x04), "SF7BW250": (0x74, 0x82, 0x04), "SF8BW125": (0x84, 0x72, 0x04), "SF9BW125": (0x94, 0x72, 0x04), "SF10BW125": (0xA4, 0x72, 0x04), "SF11BW125": (0xB4, 0x72, 0x0C), "SF12BW125": (0xC4, 0x72, 0x0C) } def __init__( self, spi, pins, ttn_config, channel=0, # compatibility with Dragino LG02, set to None otherwise fport=1, lora_parameters=_default_parameters): self._spi = spi self._pins = pins self._parameters = lora_parameters self._lock = False self._log = ExtLogging.Create("SX127x") # setting pins if "dio_0" in self._pins: self._pin_rx_done = Pin(self._pins["dio_0"], Pin.IN) self._irq = Pin(self._pins["dio_0"], Pin.IN) if "ss" in self._pins: self._pin_ss = Pin(self._pins["ss"], Pin.OUT) if "led" in self._pins: self._led_status = Pin(self._pins["led"], Pin.OUT) # check hardware version init_try = True re_try = 0 while init_try and re_try < 5: version = self.read_register(REG_VERSION) re_try = re_try + 1 self._log.info("SX version: {}".format(version)) if version == 0x12: init_try = False else: utime.sleep_ms(1000) if version != 0x12: raise Exception('Invalid version.') # Set frequency registers self._rfm_msb = None self._rfm_mid = None self._rfm_lsb = None # init framecounter self.frame_counter = 0 self._fport = fport # Set datarate registers self._sf = None self._bw = None self._modemcfg = None # ttn configuration if "US" in ttn_config.country: from ttn.ttn_usa import TTN_FREQS self._frequencies = TTN_FREQS elif ttn_config.country == "AS": from ttn.ttn_as import TTN_FREQS self._frequencies = TTN_FREQS elif ttn_config.country == "AU": from ttn.ttn_au import TTN_FREQS self._frequencies = TTN_FREQS elif ttn_config.country == "EU": from ttn.ttn_eu import TTN_FREQS self._frequencies = TTN_FREQS else: raise TypeError("Country Code Incorrect/Unsupported") # Give the uLoRa object ttn configuration self._ttn_config = ttn_config # put in LoRa and sleep mode self.sleep() # set channel number self._channel = channel self._actual_channel = channel if self._channel is not None: self.set_frequency(self._channel) # set data rate and bandwidth self.set_bandwidth(self._parameters["signal_bandwidth"]) # set LNA boost self.write_register(REG_LNA, self.read_register(REG_LNA) | 0x03) # set auto AGC self.write_register(REG_MODEM_CONFIG, 0x04) self.implicit_header_mode(self._parameters['implicit_header']) self.set_tx_power(self._parameters['tx_power_level']) self.set_coding_rate(self._parameters['coding_rate']) self.set_sync_word(self._parameters['sync_word']) self.enable_CRC(self._parameters['enable_CRC']) #self.invert_IQ(self._parameters["invert_IQ"]) self.set_preamble_length(self._parameters['preamble_length']) self.set_spreading_factor(self._parameters['spreading_factor']) # set LowDataRateOptimize flag if symbol time > 16ms (default disable on reset) # self.write_register(REG_MODEM_CONFIG, self.read_register(REG_MODEM_CONFIG) & 0xF7) # default disable on reset #bw_parameter = self._parameters["signal_bandwidth"] #sf_parameter = self._parameters["spreading_factor"] #if 1000 / (bw_parameter / 2**sf_parameter) > 16: # self.write_register( # REG_MODEM_CONFIG, # self.read_register(REG_MODEM_CONFIG) | 0x08 # ) # set base addresses self.write_register(REG_FIFO_TX_BASE_ADDR, FifoTxBaseAddr) self.write_register(REG_FIFO_RX_BASE_ADDR, FifoRxBaseAddr) self.standby() def begin_packet(self, implicit_header_mode=False): self.standby() self.implicit_header_mode(implicit_header_mode) #self.write_register(REG_DIO_MAPPING_1, 0x40) # Check for multi-channel configuration if self._channel is None: self._actual_channel = urandom.getrandbits(3) self.set_frequency(self._actual_channel) # reset FIFO address and paload length self.write_register(REG_FIFO_ADDR_PTR, FifoTxBaseAddr) self.write_register(REG_PAYLOAD_LENGTH, 0) def end_packet(self, timeout=5): # put in TX mode self.write_register(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX) start = utime.time() timed_out = False # wait for TX done, standby automatically on TX_DONE #self.read_register(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK == 0 and \ irq_value = self.read_register(REG_IRQ_FLAGS) while not timed_out and \ irq_value & IRQ_TX_DONE_MASK == 0: if utime.time() - start >= timeout: timed_out = True else: irq_value = self.read_register(REG_IRQ_FLAGS) if timed_out: raise RuntimeError("Timeout during packet send") # clear IRQ's self.write_register(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK) self.collect_garbage() def write(self, buffer, buffer_length): # update length self.write_register(REG_PAYLOAD_LENGTH, buffer_length) # write data for i in range(buffer_length): self.write_register(REG_FIFO, buffer[i]) def set_lock(self, lock=False): self._lock = lock def send_data(self, data, data_length, frame_counter, timeout=5): # Data packet enc_data = bytearray(data_length) lora_pkt = bytearray(64) # Copy bytearray into bytearray for encryption enc_data[0:data_length] = data[0:data_length] # Encrypt data (enc_data is overwritten in this function) self.frame_counter = frame_counter aes = AES(self._ttn_config.device_address, self._ttn_config.app_key, self._ttn_config.network_key, self.frame_counter) enc_data = aes.encrypt(enc_data) # Construct MAC Layer packet (PHYPayload) # MHDR (MAC Header) - 1 byte lora_pkt[ 0] = REG_DIO_MAPPING_1 # MType: unconfirmed data up, RFU / Major zeroed # MACPayload # FHDR (Frame Header): DevAddr (4 bytes) - short device address lora_pkt[1] = self._ttn_config.device_address[3] lora_pkt[2] = self._ttn_config.device_address[2] lora_pkt[3] = self._ttn_config.device_address[1] lora_pkt[4] = self._ttn_config.device_address[0] # FHDR (Frame Header): FCtrl (1 byte) - frame control lora_pkt[5] = 0x00 # FHDR (Frame Header): FCnt (2 bytes) - frame counter lora_pkt[6] = self.frame_counter & 0x00FF lora_pkt[7] = (self.frame_counter >> 8) & 0x00FF # FPort - port field lora_pkt[8] = self._fport # Set length of LoRa packet lora_pkt_len = 9 self._log.debug("PHYPayload", ubinascii.hexlify(lora_pkt)) # load encrypted data into lora_pkt lora_pkt[lora_pkt_len:lora_pkt_len + data_length] = enc_data[0:data_length] self._log.debug("PHYPayload with FRMPayload", ubinascii.hexlify(lora_pkt)) # Recalculate packet length lora_pkt_len += data_length # Calculate Message Integrity Code (MIC) # MIC is calculated over: MHDR | FHDR | FPort | FRMPayload mic = bytearray(4) mic = aes.calculate_mic(lora_pkt, lora_pkt_len, mic) # Load MIC in package lora_pkt[lora_pkt_len:lora_pkt_len + 4] = mic[0:4] # Recalculate packet length (add MIC length) lora_pkt_len += 4 self._log.debug("PHYPayload with FRMPayload + MIC ({}): {}".format( lora_pkt_len, ubinascii.hexlify(lora_pkt))) self.send_packet(lora_pkt, lora_pkt_len, timeout) def send_packet(self, lora_packet, packet_length, timeout): """ Sends a LoRa packet using the SX1276 module. """ self._log.info( "Sending LoRa packet of length {}".format(packet_length)) self.set_lock(True) # wait until RX_Done, lock and begin writing. self.begin_packet() # Fill the FIFO buffer with the LoRa payload self.write(lora_packet, packet_length) # Send the package self.end_packet(timeout) self.set_lock(False) # unlock when done writing self.blink_led() self.collect_garbage() def get_irq_flags(self): irq_flags = self.read_register(REG_IRQ_FLAGS) irq_dict = dict( rx_timeout=irq_flags >> 7 & 0x01, rx_done=irq_flags >> 6 & 0x01, crc_error=irq_flags >> 5 & 0x01, valid_header=irq_flags >> 4 & 0x01, tx_done=irq_flags >> 3 & 0x01, cad_done=irq_flags >> 2 & 0x01, fhss_change_ch=irq_flags >> 1 & 0x01, cad_detected=irq_flags >> 0 & 0x01, ) self._log.debug(irq_dict) self.write_register(REG_IRQ_FLAGS, irq_flags) return irq_flags def packet_rssi(self): # TODO rssi = self.read_register(REG_PKT_RSSI_VALUE) return rssi #return (rssi - (164 if self._frequency < 868E6 else 157)) def packet_snr(self): snr = self.read_register(REG_PKT_SNR_VALUE) return snr * 0.25 def standby(self): self.write_register(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_STDBY) utime.sleep_ms(10) def sleep(self): self._log.info("Setting modem into sleep mode") self.write_register(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_SLEEP) utime.sleep_ms(10) def set_tx_power(self, level, outputPin=PA_OUTPUT_PA_BOOST_PIN): self._tx_power_level = level if (outputPin == PA_OUTPUT_RFO_PIN): # RFO level = min(max(level, 0), 14) self.write_register(REG_PA_CONFIG, 0x70 | level) else: # PA BOOST level = min(max(level, 2), 17) self.write_register(REG_PA_CONFIG, PA_BOOST | (level - 2)) def set_frequency(self, channel): self.write_register(REG_FRF_MSB, self._frequencies[channel][0]) self.write_register(REG_FRF_MID, self._frequencies[channel][1]) self.write_register(REG_FRF_LSB, self._frequencies[channel][2]) def set_coding_rate(self, denominator): denominator = min(max(denominator, 5), 8) cr = denominator - 4 self.write_register( REG_FEI_MSB, (self.read_register(REG_FEI_MSB) & 0xf1) | (cr << 1)) def set_preamble_length(self, length): self.write_register(REG_PREAMBLE_MSB, (length >> 8) & 0xff) self.write_register(REG_PREAMBLE_LSB, (length >> 0) & 0xff) def set_spreading_factor(self, sf): sf = min(max(sf, 6), 12) self.write_register(REG_DETECTION_OPTIMIZE, 0xc5 if sf == 6 else 0xc3) self.write_register(REG_DETECTION_THRESHOLD, 0x0c if sf == 6 else 0x0a) self.write_register(REG_FEI_LSB, (self.read_register(REG_FEI_LSB) & 0x0f) | ((sf << 4) & 0xf0)) def set_bandwidth(self, datarate): try: sf, bw, modemcfg = self._data_rates[datarate] self.write_register(REG_FEI_LSB, sf) self.write_register(REG_FEI_MSB, bw) self.write_register(REG_MODEM_CONFIG, modemcfg) except KeyError: raise KeyError("Invalid or Unsupported Datarate.") def enable_CRC(self, enable_CRC=False): modem_config_2 = self.read_register(REG_FEI_LSB) config = modem_config_2 | 0x04 if enable_CRC else modem_config_2 & 0xfb self.write_register(REG_FEI_LSB, config) def invert_IQ(self, invert_IQ): self._parameters["invertIQ"] = invert_IQ if invert_IQ: self.write_register( REG_INVERTIQ, ((self.read_register(REG_INVERTIQ) & RFLR_INVERTIQ_TX_MASK & RFLR_INVERTIQ_RX_MASK) | RFLR_INVERTIQ_RX_ON | RFLR_INVERTIQ_TX_ON), ) self.write_register(REG_INVERTIQ2, RFLR_INVERTIQ2_ON) else: self.write_register( REG_INVERTIQ, ((self.read_register(REG_INVERTIQ) & RFLR_INVERTIQ_TX_MASK & RFLR_INVERTIQ_RX_MASK) | RFLR_INVERTIQ_RX_OFF | RFLR_INVERTIQ_TX_OFF), ) self.write_register(REG_INVERTIQ2, RFLR_INVERTIQ2_OFF) def set_sync_word(self, sw): self.write_register(REG_SYNC_WORD, sw) def dump_registers(self): for i in range(128): print("0x{:02X}: {:02X}".format(i, self.read_register(i)), end="") if (i + 1) % 4 == 0: print() else: print(" | ", end="") def implicit_header_mode(self, implicit_header_mode=False): self._implicit_header_mode = implicit_header_mode modem_config_1 = self.read_register(REG_FEI_MSB) config = (modem_config_1 | 0x01 if implicit_header_mode else modem_config_1 & 0xfe) self.write_register(REG_FEI_MSB, config) def receive(self, size=0): self.implicit_header_mode(size > 0) if size > 0: self.write_register(REG_PAYLOAD_LENGTH, size & 0xff) # The last packet always starts at FIFO_RX_CURRENT_ADDR # no need to reset FIFO_ADDR_PTR self.write_register(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS) def on_receive(self, callback): self._on_receive = callback if self._pin_rx_done: if callback: print("Callback attached") self.write_register(REG_DIO_MAPPING_1, 0x00) self._pin_rx_done.irq(trigger=Pin.IRQ_RISING, handler=self.handle_on_receive) else: self._pin_rx_done.detach_irq() def handle_on_receive(self, event_source): self.set_lock(True) # lock until TX_Done print("Received packet.") aes = AES(self._ttn_config.device_address, self._ttn_config.app_key, self._ttn_config.network_key, self.frame_counter) # irqFlags = self.getIrqFlags() should be 0x50 if (self.get_irq_flags() & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0: if self._on_receive: payload = self.read_payload() self.set_lock(False) # unlock when done reading data = aes.decrypt_payload(payload) self._on_receive(self, data) self.set_lock(False) # unlock in any case. self.collect_garbage() """ def handle_on_receive(self, event_source): self.set_lock(True) # lock until TX_Done aes = AES( self._ttn_config.device_address, self._ttn_config.app_key, self._ttn_config.network_key, self.frame_counter ) irq_flags = self.get_irq_flags() if (irq_flags == IRQ_RX_DONE_MASK): # RX_DONE only, irq_flags should be 0x40 # automatically standby when RX_DONE print("yeah" + str(irq_flags)) if self._on_receive: payload = self.read_payload() data = aes.decrypt_payload(payload) self._on_receive(self, data) elif self.read_register(REG_OP_MODE) != ( MODE_LONG_RANGE_MODE | MODE_RX_SINGLE ): print("nada" + str(irq_flags)) # no packet received. # reset FIFO address / # enter single RX mode self.write_register(REG_FIFO_ADDR_PTR, FifoRxBaseAddr) self.write_register( REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE ) self.set_lock(False) # unlock in any case. self.collect_garbage() return True """ def received_packet(self, size=0): irq_flags = self.get_irq_flags() self.implicit_header_mode(size > 0) if size > 0: self.write_register(REG_PAYLOAD_LENGTH, size & 0xff) #if (irq_flags & IRQ_RX_DONE_MASK) and \ # (irq_flags & IRQ_RX_TIME_OUT_MASK == 0) and \ # (irq_flags & IRQ_PAYLOAD_CRC_ERROR_MASK == 0): if (irq_flags == IRQ_RX_DONE_MASK): # RX_DONE only, irq_flags should be 0x40 # automatically standby when RX_DONE return True elif self.read_register(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE): # no packet received. # reset FIFO address / # enter single RX mode self.write_register(REG_FIFO_ADDR_PTR, FifoRxBaseAddr) self.write_register(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE) def read_payload(self): # set FIFO address to current RX address # fifo_rx_current_addr = self.read_register(REG_FIFO_RX_CURRENT_ADDR) self.write_register(REG_FIFO_ADDR_PTR, self.read_register(REG_FIFO_RX_CURRENT_ADDR)) # read packet length if self._implicit_header_mode: packet_length = self.read_register(REG_PAYLOAD_LENGTH) else: packet_length = self.read_register(REG_RX_NB_BYTES) print("Received packet length: {}".format(packet_length)) payload = bytearray() for i in range(packet_length): payload.append(self.read_register(REG_FIFO)) self.collect_garbage() return bytes(payload) def read_register(self, address, byteorder='big', signed=False): response = self.transfer(address & 0x7f) return int.from_bytes(response, byteorder) def write_register(self, address, value): self.transfer(address | 0x80, value) def transfer(self, address, value=0x00): response = bytearray(1) self._pin_ss.value(0) self._spi.write(bytes([address])) self._spi.write_readinto(bytes([value]), response) self._pin_ss.value(1) return response def blink_led(self, times=1, on_seconds=0.1, off_seconds=0.1): for i in range(times): if self._led_status: self._led_status.value(True) utime.sleep(on_seconds) self._led_status.value(False) utime.sleep(off_seconds) def collect_garbage(self): gc.collect() self._log.debug('[Memory - free: {} allocated: {}]'.format( gc.mem_free(), gc.mem_alloc()))