|
33 | 33 | import digitalio
|
34 | 34 | from micropython import const
|
35 | 35 |
|
| 36 | +try: |
| 37 | + from warnings import warn |
| 38 | +except ImportError: |
| 39 | + def warn(msg, **kwargs): |
| 40 | + "Issue a warning to stdout." |
| 41 | + print("%s: %s" % ("Warning" if kwargs.get("cat") is None else kwargs["cat"].__name__, msg)) |
| 42 | + |
36 | 43 | import adafruit_bus_device.spi_device as spidev
|
37 | 44 |
|
38 | 45 |
|
|
192 | 199 | _RH_RF95_LOW_DATA_RATE_OPTIMIZE = const(0x01)
|
193 | 200 |
|
194 | 201 | # RH_RF95_REG_1E_MODEM_CONFIG2 0x1e
|
| 202 | +_RH_RF95_DETECTION_OPTIMIZE = const(0x31) |
| 203 | +_RH_RF95_DETECTION_THRESHOLD = const(0x37) |
195 | 204 | _RH_RF95_SPREADING_FACTOR = const(0xf0)
|
196 | 205 | _RH_RF95_SPREADING_FACTOR_64CPS = const(0x60)
|
197 | 206 | _RH_RF95_SPREADING_FACTOR_128CPS = const(0x70)
|
@@ -333,6 +342,10 @@ def __set__(self, obj, val):
|
333 | 342 |
|
334 | 343 | rx_done = _RegisterBits(_RH_RF95_REG_12_IRQ_FLAGS, offset=6, bits=1)
|
335 | 344 |
|
| 345 | + crc_error = _RegisterBits(_RH_RF95_REG_12_IRQ_FLAGS, offset=5, bits=1) |
| 346 | + |
| 347 | + bw_bins = (7800, 10400, 15600, 20800, 31250, 41700, 62500, 125000, 250000) |
| 348 | + |
336 | 349 | def __init__(self, spi, cs, reset, frequency, *, preamble_length=8,
|
337 | 350 | high_power=True, baudrate=5000000):
|
338 | 351 | self.high_power = high_power
|
@@ -367,10 +380,13 @@ def __init__(self, spi, cs, reset, frequency, *, preamble_length=8,
|
367 | 380 | self._write_u8(_RH_RF95_REG_0F_FIFO_RX_BASE_ADDR, 0x00)
|
368 | 381 | # Set mode idle
|
369 | 382 | self.idle()
|
370 |
| - # Set modem config to RadioHead compatible Bw125Cr45Sf128 mode. |
| 383 | + # Defaults set modem config to RadioHead compatible Bw125Cr45Sf128 mode. |
| 384 | + self.signal_bandwidth = 125000 |
| 385 | + self.coding_rate = 5 |
| 386 | + self.spreading_factor = 7 |
| 387 | + # Default to disable CRC checking on incoming packets. |
| 388 | + self.enable_crc = False |
371 | 389 | # Note no sync word is set for LoRa mode either!
|
372 |
| - self._write_u8(_RH_RF95_REG_1D_MODEM_CONFIG1, 0x72) # Fei msb? |
373 |
| - self._write_u8(_RH_RF95_REG_1E_MODEM_CONFIG2, 0x74) # Fei lsb? |
374 | 390 | self._write_u8(_RH_RF95_REG_26_MODEM_CONFIG3, 0x00) # Preamble lsb?
|
375 | 391 | # Set preamble length (default 8 bytes to match radiohead).
|
376 | 392 | self.preamble_length = preamble_length
|
@@ -533,6 +549,100 @@ def rssi(self):
|
533 | 549 | # Remember in LoRa mode the payload register changes function to RSSI!
|
534 | 550 | return self._read_u8(_RH_RF95_REG_1A_PKT_RSSI_VALUE) - 137
|
535 | 551 |
|
| 552 | + @property |
| 553 | + def signal_bandwidth(self): |
| 554 | + """The signal bandwidth used by the radio (try setting to a higher |
| 555 | + value to increase throughput or to a lower value to increase the |
| 556 | + likelihood of successfully received payloads). Valid values are |
| 557 | + listed in RFM9x.bw_bins.""" |
| 558 | + bw_id = (self._read_u8(_RH_RF95_REG_1D_MODEM_CONFIG1) & 0xf0) >> 4 |
| 559 | + if bw_id >= len(self.bw_bins): |
| 560 | + current_bandwidth = 500000 |
| 561 | + else: |
| 562 | + current_bandwidth = self.bw_bins[bw_id] |
| 563 | + return current_bandwidth |
| 564 | + |
| 565 | + @signal_bandwidth.setter |
| 566 | + def signal_bandwidth(self, val): |
| 567 | + # Set signal bandwidth (set to 125000 to match RadioHead Bw125). |
| 568 | + for bw_id, cutoff in enumerate(self.bw_bins): |
| 569 | + if val <= cutoff: |
| 570 | + break |
| 571 | + else: |
| 572 | + bw_id = 9 |
| 573 | + self._write_u8( |
| 574 | + _RH_RF95_REG_1D_MODEM_CONFIG1, |
| 575 | + (self._read_u8(_RH_RF95_REG_1D_MODEM_CONFIG1) & 0x0f) | (bw_id << 4) |
| 576 | + ) |
| 577 | + |
| 578 | + @property |
| 579 | + def coding_rate(self): |
| 580 | + """The coding rate used by the radio to control forward error |
| 581 | + correction (try setting to a higher value to increase tolerance of |
| 582 | + short bursts of interference or to a lower value to increase bit |
| 583 | + rate). Valid values are limited to 5, 6, 7, or 8.""" |
| 584 | + cr_id = (self._read_u8(_RH_RF95_REG_1D_MODEM_CONFIG1) & 0x0e) >> 1 |
| 585 | + denominator = cr_id + 4 |
| 586 | + return denominator |
| 587 | + |
| 588 | + @coding_rate.setter |
| 589 | + def coding_rate(self, val): |
| 590 | + # Set coding rate (set to 5 to match RadioHead Cr45). |
| 591 | + denominator = min(max(val, 5), 8) |
| 592 | + cr_id = denominator - 4 |
| 593 | + self._write_u8( |
| 594 | + _RH_RF95_REG_1D_MODEM_CONFIG1, |
| 595 | + (self._read_u8(_RH_RF95_REG_1D_MODEM_CONFIG1) & 0xf1) | (cr_id << 1) |
| 596 | + ) |
| 597 | + |
| 598 | + @property |
| 599 | + def spreading_factor(self): |
| 600 | + """The spreading factor used by the radio (try setting to a higher |
| 601 | + value to increase the receiver's ability to distinguish signal from |
| 602 | + noise or to a lower value to increase the data transmission rate). |
| 603 | + Valid values are limited to 6, 7, 8, 9, 10, 11, or 12.""" |
| 604 | + sf_id = (self._read_u8(_RH_RF95_REG_1E_MODEM_CONFIG2) & 0xf0) >> 4 |
| 605 | + return sf_id |
| 606 | + |
| 607 | + @spreading_factor.setter |
| 608 | + def spreading_factor(self, val): |
| 609 | + # Set spreading factor (set to 7 to match RadioHead Sf128). |
| 610 | + val = min(max(val, 6), 12) |
| 611 | + self._write_u8( |
| 612 | + _RH_RF95_DETECTION_OPTIMIZE, 0xc5 if val == 6 else 0xc3 |
| 613 | + ) |
| 614 | + self._write_u8( |
| 615 | + _RH_RF95_DETECTION_THRESHOLD, 0x0c if val == 6 else 0x0a |
| 616 | + ) |
| 617 | + self._write_u8( |
| 618 | + _RH_RF95_REG_1E_MODEM_CONFIG2, |
| 619 | + ( |
| 620 | + (self._read_u8(_RH_RF95_REG_1E_MODEM_CONFIG2) & 0x0f) | |
| 621 | + ((val << 4) & 0xf0) |
| 622 | + ) |
| 623 | + ) |
| 624 | + |
| 625 | + @property |
| 626 | + def enable_crc(self): |
| 627 | + """Set to True to enable hardware CRC checking of incoming packets. |
| 628 | + Incoming packets that fail the CRC check are not processed. Set to |
| 629 | + False to disable CRC checking and process all incoming packets.""" |
| 630 | + return (self._read_u8(_RH_RF95_REG_1E_MODEM_CONFIG2) & 0x04) == 0x04 |
| 631 | + |
| 632 | + @enable_crc.setter |
| 633 | + def enable_crc(self, val): |
| 634 | + # Optionally enable CRC checking on incoming packets. |
| 635 | + if val: |
| 636 | + self._write_u8( |
| 637 | + _RH_RF95_REG_1E_MODEM_CONFIG2, |
| 638 | + self._read_u8(_RH_RF95_REG_1E_MODEM_CONFIG2) | 0x04 |
| 639 | + ) |
| 640 | + else: |
| 641 | + self._write_u8( |
| 642 | + _RH_RF95_REG_1E_MODEM_CONFIG2, |
| 643 | + self._read_u8(_RH_RF95_REG_1E_MODEM_CONFIG2) & 0xfb |
| 644 | + ) |
| 645 | + |
536 | 646 | def send(self, data, timeout=2.,
|
537 | 647 | tx_header=(_RH_BROADCAST_ADDRESS, _RH_BROADCAST_ADDRESS, 0, 0)):
|
538 | 648 | """Send a string of data using the transmitter.
|
@@ -617,25 +727,28 @@ def receive(self, timeout=0.5, keep_listening=True, with_header=False,
|
617 | 727 | # Payload ready is set, a packet is in the FIFO.
|
618 | 728 | packet = None
|
619 | 729 | if not timed_out:
|
620 |
| - # Grab the length of the received packet and check it has at least 5 |
621 |
| - # bytes to indicate the 4 byte header and at least 1 byte of user data. |
622 |
| - length = self._read_u8(_RH_RF95_REG_13_RX_NB_BYTES) |
623 |
| - if length < 5: |
624 |
| - packet = None |
| 730 | + if self.enable_crc and self.crc_error: |
| 731 | + warn("CRC error, packet ignored") |
625 | 732 | else:
|
626 |
| - # Have a good packet, grab it from the FIFO. |
627 |
| - # Reset the fifo read ptr to the beginning of the packet. |
628 |
| - current_addr = self._read_u8(_RH_RF95_REG_10_FIFO_RX_CURRENT_ADDR) |
629 |
| - self._write_u8(_RH_RF95_REG_0D_FIFO_ADDR_PTR, current_addr) |
630 |
| - packet = bytearray(length) |
631 |
| - # Read the packet. |
632 |
| - self._read_into(_RH_RF95_REG_00_FIFO, packet) |
633 |
| - if (rx_filter != _RH_BROADCAST_ADDRESS and packet[0] != _RH_BROADCAST_ADDRESS |
634 |
| - and packet[0] != rx_filter): |
| 733 | + # Grab the length of the received packet and check it has at least 5 |
| 734 | + # bytes to indicate the 4 byte header and at least 1 byte of user data. |
| 735 | + length = self._read_u8(_RH_RF95_REG_13_RX_NB_BYTES) |
| 736 | + if length < 5: |
635 | 737 | packet = None
|
636 |
| - elif not with_header: # skip the header if not wanted |
637 |
| - packet = packet[4:] |
638 |
| - # Listen again if necessary and return the result packet. |
| 738 | + else: |
| 739 | + # Have a good packet, grab it from the FIFO. |
| 740 | + # Reset the fifo read ptr to the beginning of the packet. |
| 741 | + current_addr = self._read_u8(_RH_RF95_REG_10_FIFO_RX_CURRENT_ADDR) |
| 742 | + self._write_u8(_RH_RF95_REG_0D_FIFO_ADDR_PTR, current_addr) |
| 743 | + packet = bytearray(length) |
| 744 | + # Read the packet. |
| 745 | + self._read_into(_RH_RF95_REG_00_FIFO, packet) |
| 746 | + if (rx_filter != _RH_BROADCAST_ADDRESS and packet[0] != _RH_BROADCAST_ADDRESS |
| 747 | + and packet[0] != rx_filter): |
| 748 | + packet = None |
| 749 | + elif not with_header: # skip the header if not wanted |
| 750 | + packet = packet[4:] |
| 751 | + # Listen again if necessary and return the result packet. |
639 | 752 | if keep_listening:
|
640 | 753 | self.listen()
|
641 | 754 | else:
|
|
0 commit comments