/ adafruit_rfm69.py
adafruit_rfm69.py
  1  # The MIT License (MIT)
  2  #
  3  # Copyright (c) 2017 Tony DiCola for Adafruit Industries
  4  #
  5  # Permission is hereby granted, free of charge, to any person obtaining a copy
  6  # of this software and associated documentation files (the "Software"), to deal
  7  # in the Software without restriction, including without limitation the rights
  8  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9  # copies of the Software, and to permit persons to whom the Software is
 10  # furnished to do so, subject to the following conditions:
 11  #
 12  # The above copyright notice and this permission notice shall be included in
 13  # all copies or substantial portions of the Software.
 14  #
 15  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 21  # THE SOFTWARE.
 22  """
 23  `adafruit_rfm69`
 24  ====================================================
 25  
 26  CircuitPython RFM69 packet radio module. This supports basic RadioHead-compatible sending and
 27  receiving of packets with RFM69 series radios (433/915Mhz).
 28  
 29  .. warning:: This is NOT for LoRa radios!
 30  
 31  .. note:: This is a 'best effort' at receiving data using pure Python code--there is not interrupt
 32      support so you might lose packets if they're sent too quickly for the board to process them.
 33      You will have the most luck using this in simple low bandwidth scenarios like sending and
 34      receiving a 60 byte packet at a time--don't try to receive many kilobytes of data at a time!
 35  
 36  * Author(s): Tony DiCola, Jerry Needell
 37  
 38  Implementation Notes
 39  --------------------
 40  
 41  **Hardware:**
 42  
 43  * Adafruit `RFM69HCW Transceiver Radio Breakout - 868 or 915 MHz - RadioFruit
 44    <https://www.adafruit.com/product/3070>`_ (Product ID: 3070)
 45  
 46  * Adafruit `RFM69HCW Transceiver Radio Breakout - 433 MHz - RadioFruit
 47    <https://www.adafruit.com/product/3071>`_ (Product ID: 3071)
 48  
 49  * Adafruit `Feather M0 RFM69HCW Packet Radio - 868 or 915 MHz - RadioFruit
 50    <https://www.adafruit.com/product/3176>`_ (Product ID: 3176)
 51  
 52  * Adafruit `Feather M0 RFM69HCW Packet Radio - 433 MHz - RadioFruit
 53    <https://www.adafruit.com/product/3177>`_ (Product ID: 3177)
 54  
 55  * Adafruit `Radio FeatherWing - RFM69HCW 900MHz - RadioFruit
 56    <https://www.adafruit.com/product/3229>`_ (Product ID: 3229)
 57  
 58  * Adafruit `Radio FeatherWing - RFM69HCW 433MHz - RadioFruit
 59    <https://www.adafruit.com/product/3230>`_ (Product ID: 3230)
 60  
 61  **Software and Dependencies:**
 62  
 63  * Adafruit CircuitPython firmware for the ESP8622 and M0-based boards:
 64    https://github.com/adafruit/circuitpython/releases
 65  * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
 66  """
 67  import time
 68  import random
 69  
 70  from micropython import const
 71  
 72  import adafruit_bus_device.spi_device as spidev
 73  
 74  
 75  __version__ = "0.0.0-auto.0"
 76  __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_RFM69.git"
 77  
 78  
 79  # Internal constants:
 80  _REG_FIFO = const(0x00)
 81  _REG_OP_MODE = const(0x01)
 82  _REG_DATA_MOD = const(0x02)
 83  _REG_BITRATE_MSB = const(0x03)
 84  _REG_BITRATE_LSB = const(0x04)
 85  _REG_FDEV_MSB = const(0x05)
 86  _REG_FDEV_LSB = const(0x06)
 87  _REG_FRF_MSB = const(0x07)
 88  _REG_FRF_MID = const(0x08)
 89  _REG_FRF_LSB = const(0x09)
 90  _REG_VERSION = const(0x10)
 91  _REG_PA_LEVEL = const(0x11)
 92  _REG_RX_BW = const(0x19)
 93  _REG_AFC_BW = const(0x1A)
 94  _REG_RSSI_VALUE = const(0x24)
 95  _REG_DIO_MAPPING1 = const(0x25)
 96  _REG_IRQ_FLAGS1 = const(0x27)
 97  _REG_IRQ_FLAGS2 = const(0x28)
 98  _REG_PREAMBLE_MSB = const(0x2C)
 99  _REG_PREAMBLE_LSB = const(0x2D)
100  _REG_SYNC_CONFIG = const(0x2E)
101  _REG_SYNC_VALUE1 = const(0x2F)
102  _REG_PACKET_CONFIG1 = const(0x37)
103  _REG_FIFO_THRESH = const(0x3C)
104  _REG_PACKET_CONFIG2 = const(0x3D)
105  _REG_AES_KEY1 = const(0x3E)
106  _REG_TEMP1 = const(0x4E)
107  _REG_TEMP2 = const(0x4F)
108  _REG_TEST_PA1 = const(0x5A)
109  _REG_TEST_PA2 = const(0x5C)
110  _REG_TEST_DAGC = const(0x6F)
111  
112  _TEST_PA1_NORMAL = const(0x55)
113  _TEST_PA1_BOOST = const(0x5D)
114  _TEST_PA2_NORMAL = const(0x70)
115  _TEST_PA2_BOOST = const(0x7C)
116  
117  # The crystal oscillator frequency and frequency synthesizer step size.
118  # See the datasheet for details of this calculation.
119  _FXOSC = 32000000.0
120  _FSTEP = _FXOSC / 524288
121  
122  # RadioHead specific compatibility constants.
123  _RH_BROADCAST_ADDRESS = const(0xFF)
124  # The acknowledgement bit in the FLAGS
125  # The top 4 bits of the flags are reserved for RadioHead. The lower 4 bits are reserved
126  # for application layer use.
127  _RH_FLAGS_ACK = const(0x80)
128  _RH_FLAGS_RETRY = const(0x40)
129  
130  # User facing constants:
131  SLEEP_MODE = 0b000
132  STANDBY_MODE = 0b001
133  FS_MODE = 0b010
134  TX_MODE = 0b011
135  RX_MODE = 0b100
136  
137  # Disable the silly too many instance members warning.  Pylint has no knowledge
138  # of the context and is merely guessing at the proper amount of members.  This
139  # is a complex chip which requires exposing many attributes and state.  Disable
140  # the warning to work around the error.
141  # pylint: disable=too-many-instance-attributes
142  
143  
144  class RFM69:
145      """Interface to a RFM69 series packet radio.  Allows simple sending and
146      receiving of wireless data at supported frequencies of the radio
147      (433/915mhz).
148  
149      :param busio.SPI spi: The SPI bus connected to the chip.  Ensure SCK, MOSI, and MISO are
150          connected.
151      :param ~digitalio.DigitalInOut cs: A DigitalInOut object connected to the chip's CS/chip select
152          line.
153      :param ~digitalio.DigitalInOut reset: A DigitalInOut object connected to the chip's RST/reset
154          line.
155      :param int frequency: The center frequency to configure for radio transmission and reception.
156          Must be a frequency supported by your hardware (i.e. either 433 or 915mhz).
157      :param bytes sync_word: A byte string up to 8 bytes long which represents the syncronization
158          word used by received and transmitted packets. Read the datasheet for a full understanding
159          of this value! However by default the library will set a value that matches the RadioHead
160          Arduino library.
161      :param int preamble_length: The number of bytes to pre-pend to a data packet as a preamble.
162          This is by default 4 to match the RadioHead library.
163      :param bytes encryption_key: A 16 byte long string that represents the AES encryption key to use
164          when encrypting and decrypting packets.  Both the transmitter and receiver MUST have the
165          same key value! By default no encryption key is set or used.
166      :param bool high_power: Indicate if the chip is a high power variant that supports boosted
167          transmission power.  The default is True as it supports the common RFM69HCW modules sold by
168          Adafruit.
169  
170      .. note:: The D0/interrupt line is currently unused by this module and can remain unconnected.
171  
172      Remember this library makes a best effort at receiving packets with pure Python code.  Trying
173      to receive packets too quickly will result in lost data so limit yourself to simple scenarios
174      of sending and receiving single packets at a time.
175  
176      Also note this library tries to be compatible with raw RadioHead Arduino library communication.
177      This means the library sets up the radio modulation to match RadioHead's default of GFSK
178      encoding, 250kbit/s bitrate, and 250khz frequency deviation. To change this requires explicitly
179      setting the radio's bitrate and encoding register bits. Read the datasheet and study the init
180      function to see an example of this--advanced users only! Advanced RadioHead features like
181      address/node specific packets or "reliable datagram" delivery are supported however due to the
182      limitations noted, "reliable datagram" is still subject to missed packets but with it, the
183      sender is notified if a packe has potentially been missed.
184      """
185  
186      # Global buffer for SPI commands.
187      _BUFFER = bytearray(4)
188  
189      class _RegisterBits:
190          # Class to simplify access to the many configuration bits avaialable
191          # on the chip's registers.  This is a subclass here instead of using
192          # a higher level module to increase the efficiency of memory usage
193          # (all of the instances of this bit class will share the same buffer
194          # used by the parent RFM69 class instance vs. each having their own
195          # buffer and taking too much memory).
196  
197          # Quirk of pylint that it requires public methods for a class.  This
198          # is a decorator class in Python and by design it has no public methods.
199          # Instead it uses dunder accessors like get and set below.  For some
200          # reason pylint can't figure this out so disable the check.
201          # pylint: disable=too-few-public-methods
202  
203          # Again pylint fails to see the true intent of this code and warns
204          # against private access by calling the write and read functions below.
205          # This is by design as this is an internally used class.  Disable the
206          # check from pylint.
207          # pylint: disable=protected-access
208  
209          def __init__(self, address, *, offset=0, bits=1):
210              assert 0 <= offset <= 7
211              assert 1 <= bits <= 8
212              assert (offset + bits) <= 8
213              self._address = address
214              self._mask = 0
215              for _ in range(bits):
216                  self._mask <<= 1
217                  self._mask |= 1
218              self._mask <<= offset
219              self._offset = offset
220  
221          def __get__(self, obj, objtype):
222              reg_value = obj._read_u8(self._address)
223              return (reg_value & self._mask) >> self._offset
224  
225          def __set__(self, obj, val):
226              reg_value = obj._read_u8(self._address)
227              reg_value &= ~self._mask
228              reg_value |= (val & 0xFF) << self._offset
229              obj._write_u8(self._address, reg_value)
230  
231      # Control bits from the registers of the chip:
232      data_mode = _RegisterBits(_REG_DATA_MOD, offset=5, bits=2)
233      modulation_type = _RegisterBits(_REG_DATA_MOD, offset=3, bits=2)
234      modulation_shaping = _RegisterBits(_REG_DATA_MOD, offset=0, bits=2)
235      temp_start = _RegisterBits(_REG_TEMP1, offset=3)
236      temp_running = _RegisterBits(_REG_TEMP1, offset=2)
237      sync_on = _RegisterBits(_REG_SYNC_CONFIG, offset=7)
238      sync_size = _RegisterBits(_REG_SYNC_CONFIG, offset=3, bits=3)
239      aes_on = _RegisterBits(_REG_PACKET_CONFIG2, offset=0)
240      pa_0_on = _RegisterBits(_REG_PA_LEVEL, offset=7)
241      pa_1_on = _RegisterBits(_REG_PA_LEVEL, offset=6)
242      pa_2_on = _RegisterBits(_REG_PA_LEVEL, offset=5)
243      output_power = _RegisterBits(_REG_PA_LEVEL, offset=0, bits=5)
244      rx_bw_dcc_freq = _RegisterBits(_REG_RX_BW, offset=5, bits=3)
245      rx_bw_mantissa = _RegisterBits(_REG_RX_BW, offset=3, bits=2)
246      rx_bw_exponent = _RegisterBits(_REG_RX_BW, offset=0, bits=3)
247      afc_bw_dcc_freq = _RegisterBits(_REG_AFC_BW, offset=5, bits=3)
248      afc_bw_mantissa = _RegisterBits(_REG_AFC_BW, offset=3, bits=2)
249      afc_bw_exponent = _RegisterBits(_REG_AFC_BW, offset=0, bits=3)
250      packet_format = _RegisterBits(_REG_PACKET_CONFIG1, offset=7, bits=1)
251      dc_free = _RegisterBits(_REG_PACKET_CONFIG1, offset=5, bits=2)
252      crc_on = _RegisterBits(_REG_PACKET_CONFIG1, offset=4, bits=1)
253      crc_auto_clear_off = _RegisterBits(_REG_PACKET_CONFIG1, offset=3, bits=1)
254      address_filter = _RegisterBits(_REG_PACKET_CONFIG1, offset=1, bits=2)
255      mode_ready = _RegisterBits(_REG_IRQ_FLAGS1, offset=7)
256      rx_ready = _RegisterBits(_REG_IRQ_FLAGS1, offset=6)
257      tx_ready = _RegisterBits(_REG_IRQ_FLAGS1, offset=5)
258      dio_0_mapping = _RegisterBits(_REG_DIO_MAPPING1, offset=6, bits=2)
259      packet_sent = _RegisterBits(_REG_IRQ_FLAGS2, offset=3)
260      payload_ready = _RegisterBits(_REG_IRQ_FLAGS2, offset=2)
261  
262      def __init__(
263          self,
264          spi,
265          cs,
266          reset,
267          frequency,
268          *,
269          sync_word=b"\x2D\xD4",
270          preamble_length=4,
271          encryption_key=None,
272          high_power=True,
273          baudrate=5000000
274      ):
275          self._tx_power = 13
276          self.high_power = high_power
277          # Device support SPI mode 0 (polarity & phase = 0) up to a max of 10mhz.
278          self._device = spidev.SPIDevice(spi, cs, baudrate=baudrate, polarity=0, phase=0)
279          # Setup reset as a digital output that's low.
280          self._reset = reset
281          self._reset.switch_to_output(value=False)
282          self.reset()  # Reset the chip.
283          # Check the version of the chip.
284          version = self._read_u8(_REG_VERSION)
285          if version != 0x24:
286              raise RuntimeError(
287                  "Failed to find RFM69 with expected version, check wiring!"
288              )
289          self.idle()  # Enter idle state.
290          # Setup the chip in a similar way to the RadioHead RFM69 library.
291          # Set FIFO TX condition to not empty and the default FIFO threshold to 15.
292          self._write_u8(_REG_FIFO_THRESH, 0b10001111)
293          # Configure low beta off.
294          self._write_u8(_REG_TEST_DAGC, 0x30)
295          # Disable boost.
296          self._write_u8(_REG_TEST_PA1, _TEST_PA1_NORMAL)
297          self._write_u8(_REG_TEST_PA2, _TEST_PA2_NORMAL)
298          # Set the syncronization word.
299          self.sync_word = sync_word
300          self.preamble_length = preamble_length  # Set the preamble length.
301          self.frequency_mhz = frequency  # Set frequency.
302          self.encryption_key = encryption_key  # Set encryption key.
303          # set radio configuration parameters
304          self._configure_radio()
305          # initialize last RSSI reading
306          self.last_rssi = 0.0
307          """The RSSI of the last received packet. Stored when the packet was received.
308             This instantaneous RSSI value may not be accurate once the
309             operating mode has been changed.
310          """
311          # initialize timeouts and delays delays
312          self.ack_wait = 0.5
313          """The delay time before attempting a retry after not receiving an ACK"""
314          self.receive_timeout = 0.5
315          """The amount of time to poll for a received packet.
316             If no packet is received, the returned packet will be None
317          """
318          self.xmit_timeout = 2.0
319          """The amount of time to wait for the HW to transmit the packet.
320             This is mainly used to prevent a hang due to a HW issue
321          """
322          self.ack_retries = 5
323          """The number of ACK retries before reporting a failure."""
324          self.ack_delay = None
325          """The delay time before attemting to send an ACK.
326             If ACKs are being missed try setting this to .1 or .2.
327          """
328          # initialize sequence number counter for reliabe datagram mode
329          self.sequence_number = 0
330          # create seen Ids list
331          self.seen_ids = bytearray(256)
332          # initialize packet header
333          # node address - default is broadcast
334          self.node = _RH_BROADCAST_ADDRESS
335          """The default address of this Node. (0-255).
336             If not 255 (0xff) then only packets address to this node will be accepted.
337             First byte of the RadioHead header.
338          """
339          # destination address - default is broadcast
340          self.destination = _RH_BROADCAST_ADDRESS
341          """The default destination address for packet transmissions. (0-255).
342             If 255 (0xff) then any receiving node should accept the packet.
343             Second byte of the RadioHead header.
344          """
345          # ID - contains seq count for reliable datagram mode
346          self.identifier = 0
347          """Automatically set to the sequence number when send_with_ack() used.
348             Third byte of the RadioHead header.
349          """
350          # flags - identifies ack/reetry packet for reliable datagram mode
351          self.flags = 0
352          """Upper 4 bits reserved for use by Reliable Datagram Mode.
353             Lower 4 bits may be used to pass information.
354             Fourth byte of the RadioHead header.
355          """
356  
357      def _configure_radio(self):
358          # Configure modulation for RadioHead library GFSK_Rb250Fd250 mode
359          # by default.  Users with advanced knowledge can manually reconfigure
360          # for any other mode (consulting the datasheet is absolutely
361          # necessary!).
362          self.data_mode = 0b00  # Packet mode
363          self.modulation_type = 0b00  # FSK modulation
364          self.modulation_shaping = 0b01  # Gaussian filter, BT=1.0
365          self.bitrate = 250000  # 250kbs
366          self.frequency_deviation = 250000  # 250khz
367          self.rx_bw_dcc_freq = 0b111  # RxBw register = 0xE0
368          self.rx_bw_mantissa = 0b00
369          self.rx_bw_exponent = 0b000
370          self.afc_bw_dcc_freq = 0b111  # AfcBw register = 0xE0
371          self.afc_bw_mantissa = 0b00
372          self.afc_bw_exponent = 0b000
373          self.packet_format = 1  # Variable length.
374          self.dc_free = 0b10  # Whitening
375          self.crc_on = 1  # CRC enabled
376          self.crc_auto_clear = 0  # Clear FIFO on CRC fail
377          self.address_filtering = 0b00  # No address filtering
378          # Set transmit power to 13 dBm, a safe value any module supports.
379          self.tx_power = 13
380  
381      # pylint: disable=no-member
382      # Reconsider this disable when it can be tested.
383      def _read_into(self, address, buf, length=None):
384          # Read a number of bytes from the specified address into the provided
385          # buffer.  If length is not specified (the default) the entire buffer
386          # will be filled.
387          if length is None:
388              length = len(buf)
389          with self._device as device:
390              self._BUFFER[0] = address & 0x7F  # Strip out top bit to set 0
391              # value (read).
392              device.write(self._BUFFER, end=1)
393              device.readinto(buf, end=length)
394  
395      def _read_u8(self, address):
396          # Read a single byte from the provided address and return it.
397          self._read_into(address, self._BUFFER, length=1)
398          return self._BUFFER[0]
399  
400      def _write_from(self, address, buf, length=None):
401          # Write a number of bytes to the provided address and taken from the
402          # provided buffer.  If no length is specified (the default) the entire
403          # buffer is written.
404          if length is None:
405              length = len(buf)
406          with self._device as device:
407              self._BUFFER[0] = (address | 0x80) & 0xFF  # Set top bit to 1 to
408              # indicate a write.
409              device.write(self._BUFFER, end=1)
410              device.write(buf, end=length)  # send data
411  
412      def _write_fifo_from(self, buf, length=None):
413          # Write a number of bytes to the transmit FIFO and taken from the
414          # provided buffer.  If no length is specified (the default) the entire
415          # buffer is written.
416          if length is None:
417              length = len(buf)
418          with self._device as device:
419              self._BUFFER[0] = (_REG_FIFO | 0x80) & 0xFF  # Set top bit to 1 to
420              # indicate a write.
421              self._BUFFER[1] = length & 0xFF  # Set packt length
422              device.write(self._BUFFER, end=2)  # send address and lenght)
423              device.write(buf, end=length)  # send data
424  
425      def _write_u8(self, address, val):
426          # Write a byte register to the chip.  Specify the 7-bit address and the
427          # 8-bit value to write to that address.
428          with self._device as device:
429              self._BUFFER[0] = (address | 0x80) & 0xFF  # Set top bit to 1 to
430              # indicate a write.
431              self._BUFFER[1] = val & 0xFF
432              device.write(self._BUFFER, end=2)
433  
434      def reset(self):
435          """Perform a reset of the chip."""
436          # See section 7.2.2 of the datasheet for reset description.
437          self._reset.value = True
438          time.sleep(0.0001)  # 100 us
439          self._reset.value = False
440          time.sleep(0.005)  # 5 ms
441  
442      def idle(self):
443          """Enter idle standby mode (switching off high power amplifiers if necessary)."""
444          # Like RadioHead library, turn off high power boost if enabled.
445          if self._tx_power >= 18:
446              self._write_u8(_REG_TEST_PA1, _TEST_PA1_NORMAL)
447              self._write_u8(_REG_TEST_PA2, _TEST_PA2_NORMAL)
448          self.operation_mode = STANDBY_MODE
449  
450      def sleep(self):
451          """Enter sleep mode."""
452          self.operation_mode = SLEEP_MODE
453  
454      def listen(self):
455          """Listen for packets to be received by the chip.  Use :py:func:`receive` to listen, wait
456             and retrieve packets as they're available.
457          """
458          # Like RadioHead library, turn off high power boost if enabled.
459          if self._tx_power >= 18:
460              self._write_u8(_REG_TEST_PA1, _TEST_PA1_NORMAL)
461              self._write_u8(_REG_TEST_PA2, _TEST_PA2_NORMAL)
462          # Enable payload ready interrupt for D0 line.
463          self.dio_0_mapping = 0b01
464          # Enter RX mode (will clear FIFO!).
465          self.operation_mode = RX_MODE
466  
467      def transmit(self):
468          """Transmit a packet which is queued in the FIFO.  This is a low level function for
469             entering transmit mode and more.  For generating and transmitting a packet of data use
470             :py:func:`send` instead.
471          """
472          # Like RadioHead library, turn on high power boost if enabled.
473          if self._tx_power >= 18:
474              self._write_u8(_REG_TEST_PA1, _TEST_PA1_BOOST)
475              self._write_u8(_REG_TEST_PA2, _TEST_PA2_BOOST)
476          # Enable packet sent interrupt for D0 line.
477          self.dio_0_mapping = 0b00
478          # Enter TX mode (will clear FIFO!).
479          self.operation_mode = TX_MODE
480  
481      @property
482      def temperature(self):
483          """The internal temperature of the chip in degrees Celsius. Be warned this is not
484             calibrated or very accurate.
485  
486             .. warning:: Reading this will STOP any receiving/sending that might be happening!
487          """
488          # Start a measurement then poll the measurement finished bit.
489          self.temp_start = 1
490          while self.temp_running > 0:
491              pass
492          # Grab the temperature value and convert it to Celsius.
493          # This uses the same observed value formula from the Radiohead library.
494          temp = self._read_u8(_REG_TEMP2)
495          return 166.0 - temp
496  
497      @property
498      def operation_mode(self):
499          """The operation mode value.  Unless you're manually controlling the chip you shouldn't
500             change the operation_mode with this property as other side-effects are required for
501             changing logical modes--use :py:func:`idle`, :py:func:`sleep`, :py:func:`transmit`,
502             :py:func:`listen` instead to signal intent for explicit logical modes.
503          """
504          op_mode = self._read_u8(_REG_OP_MODE)
505          return (op_mode >> 2) & 0b111
506  
507      @operation_mode.setter
508      def operation_mode(self, val):
509          assert 0 <= val <= 4
510          # Set the mode bits inside the operation mode register.
511          op_mode = self._read_u8(_REG_OP_MODE)
512          op_mode &= 0b11100011
513          op_mode |= val << 2
514          self._write_u8(_REG_OP_MODE, op_mode)
515          # Wait for mode to change by polling interrupt bit.
516          while not self.mode_ready:
517              pass
518  
519      @property
520      def sync_word(self):
521          """The synchronization word value.  This is a byte string up to 8 bytes long (64 bits)
522             which indicates the synchronization word for transmitted and received packets. Any
523             received packet which does not include this sync word will be ignored. The default value
524             is 0x2D, 0xD4 which matches the RadioHead RFM69 library. Setting a value of None will
525             disable synchronization word matching entirely.
526          """
527          # Handle when sync word is disabled..
528          if not self.sync_on:
529              return None
530          # Sync word is not disabled so read the current value.
531          sync_word_length = self.sync_size + 1  # Sync word size is offset by 1
532          # according to datasheet.
533          sync_word = bytearray(sync_word_length)
534          self._read_into(_REG_SYNC_VALUE1, sync_word)
535          return sync_word
536  
537      @sync_word.setter
538      def sync_word(self, val):
539          # Handle disabling sync word when None value is set.
540          if val is None:
541              self.sync_on = 0
542          else:
543              # Check sync word is at most 8 bytes.
544              assert 1 <= len(val) <= 8
545              # Update the value, size and turn on the sync word.
546              self._write_from(_REG_SYNC_VALUE1, val)
547              self.sync_size = len(val) - 1  # Again sync word size is offset by
548              # 1 according to datasheet.
549              self.sync_on = 1
550  
551      @property
552      def preamble_length(self):
553          """The length of the preamble for sent and received packets, an unsigned 16-bit value.
554             Received packets must match this length or they are ignored! Set to 4 to match the
555             RadioHead RFM69 library.
556          """
557          msb = self._read_u8(_REG_PREAMBLE_MSB)
558          lsb = self._read_u8(_REG_PREAMBLE_LSB)
559          return ((msb << 8) | lsb) & 0xFFFF
560  
561      @preamble_length.setter
562      def preamble_length(self, val):
563          assert 0 <= val <= 65535
564          self._write_u8(_REG_PREAMBLE_MSB, (val >> 8) & 0xFF)
565          self._write_u8(_REG_PREAMBLE_LSB, val & 0xFF)
566  
567      @property
568      def frequency_mhz(self):
569          """The frequency of the radio in Megahertz. Only the allowed values for your radio must be
570             specified (i.e. 433 vs. 915 mhz)!
571          """
572          # FRF register is computed from the frequency following the datasheet.
573          # See section 6.2 and FRF register description.
574          # Read bytes of FRF register and assemble into a 24-bit unsigned value.
575          msb = self._read_u8(_REG_FRF_MSB)
576          mid = self._read_u8(_REG_FRF_MID)
577          lsb = self._read_u8(_REG_FRF_LSB)
578          frf = ((msb << 16) | (mid << 8) | lsb) & 0xFFFFFF
579          frequency = (frf * _FSTEP) / 1000000.0
580          return frequency
581  
582      @frequency_mhz.setter
583      def frequency_mhz(self, val):
584          assert 290 <= val <= 1020
585          # Calculate FRF register 24-bit value using section 6.2 of the datasheet.
586          frf = int((val * 1000000.0) / _FSTEP) & 0xFFFFFF
587          # Extract byte values and update registers.
588          msb = frf >> 16
589          mid = (frf >> 8) & 0xFF
590          lsb = frf & 0xFF
591          self._write_u8(_REG_FRF_MSB, msb)
592          self._write_u8(_REG_FRF_MID, mid)
593          self._write_u8(_REG_FRF_LSB, lsb)
594  
595      @property
596      def encryption_key(self):
597          """The AES encryption key used to encrypt and decrypt packets by the chip. This can be set
598             to None to disable encryption (the default), otherwise it must be a 16 byte long byte
599             string which defines the key (both the transmitter and receiver must use the same key
600             value).
601          """
602          # Handle if encryption is disabled.
603          if self.aes_on == 0:
604              return None
605          # Encryption is enabled so read the key and return it.
606          key = bytearray(16)
607          self._read_into(_REG_AES_KEY1, key)
608          return key
609  
610      @encryption_key.setter
611      def encryption_key(self, val):
612          # Handle if unsetting the encryption key (None value).
613          if val is None:
614              self.aes_on = 0
615          else:
616              # Set the encryption key and enable encryption.
617              assert len(val) == 16
618              self._write_from(_REG_AES_KEY1, val)
619              self.aes_on = 1
620  
621      @property
622      def tx_power(self):
623          """The transmit power in dBm. Can be set to a value from -2 to 20 for high power devices
624             (RFM69HCW, high_power=True) or -18 to 13 for low power devices. Only integer power
625             levels are actually set (i.e. 12.5 will result in a value of 12 dBm).
626          """
627          # Follow table 10 truth table from the datasheet for determining power
628          # level from the individual PA level bits and output power register.
629          pa0 = self.pa_0_on
630          pa1 = self.pa_1_on
631          pa2 = self.pa_2_on
632          if pa0 and not pa1 and not pa2:
633              # -18 to 13 dBm range
634              return -18 + self.output_power
635          if not pa0 and pa1 and not pa2:
636              # -2 to 13 dBm range
637              return -18 + self.output_power
638          if not pa0 and pa1 and pa2 and not self.high_power:
639              # 2 to 17 dBm range
640              return -14 + self.output_power
641          if not pa0 and pa1 and pa2 and self.high_power:
642              # 5 to 20 dBm range
643              return -11 + self.output_power
644          raise RuntimeError("Power amplifiers in unknown state!")
645  
646      @tx_power.setter
647      def tx_power(self, val):
648          val = int(val)
649          # Determine power amplifier and output power values depending on
650          # high power state and requested power.
651          pa_0_on = 0
652          pa_1_on = 0
653          pa_2_on = 0
654          output_power = 0
655          if self.high_power:
656              # Handle high power mode.
657              assert -2 <= val <= 20
658              if val <= 13:
659                  pa_1_on = 1
660                  output_power = val + 18
661              elif 13 < val <= 17:
662                  pa_1_on = 1
663                  pa_2_on = 1
664                  output_power = val + 14
665              else:  # power >= 18 dBm
666                  # Note this also needs PA boost enabled separately!
667                  pa_1_on = 1
668                  pa_2_on = 1
669                  output_power = val + 11
670          else:
671              # Handle non-high power mode.
672              assert -18 <= val <= 13
673              # Enable only power amplifier 0 and set output power.
674              pa_0_on = 1
675              output_power = val + 18
676          # Set power amplifiers and output power as computed above.
677          self.pa_0_on = pa_0_on
678          self.pa_1_on = pa_1_on
679          self.pa_2_on = pa_2_on
680          self.output_power = output_power
681          self._tx_power = val
682  
683      @property
684      def rssi(self):
685          """The received strength indicator (in dBm).
686             May be inaccuate if not read immediatey. last_rssi contains the value read immediately
687             receipt of the last packet.
688          """
689          # Read RSSI register and convert to value using formula in datasheet.
690          return -self._read_u8(_REG_RSSI_VALUE) / 2.0
691  
692      @property
693      def bitrate(self):
694          """The modulation bitrate in bits/second (or chip rate if Manchester encoding is enabled).
695             Can be a value from ~489 to 32mbit/s, but see the datasheet for the exact supported
696             values.
697          """
698          msb = self._read_u8(_REG_BITRATE_MSB)
699          lsb = self._read_u8(_REG_BITRATE_LSB)
700          return _FXOSC / ((msb << 8) | lsb)
701  
702      @bitrate.setter
703      def bitrate(self, val):
704          assert (_FXOSC / 65535) <= val <= 32000000.0
705          # Round up to the next closest bit-rate value with addition of 0.5.
706          bitrate = int((_FXOSC / val) + 0.5) & 0xFFFF
707          self._write_u8(_REG_BITRATE_MSB, bitrate >> 8)
708          self._write_u8(_REG_BITRATE_LSB, bitrate & 0xFF)
709  
710      @property
711      def frequency_deviation(self):
712          """The frequency deviation in Hertz."""
713          msb = self._read_u8(_REG_FDEV_MSB)
714          lsb = self._read_u8(_REG_FDEV_LSB)
715          return _FSTEP * ((msb << 8) | lsb)
716  
717      @frequency_deviation.setter
718      def frequency_deviation(self, val):
719          assert 0 <= val <= (_FSTEP * 16383)  # fdev is a 14-bit unsigned value
720          # Round up to the next closest integer value with addition of 0.5.
721          fdev = int((val / _FSTEP) + 0.5) & 0x3FFF
722          self._write_u8(_REG_FDEV_MSB, fdev >> 8)
723          self._write_u8(_REG_FDEV_LSB, fdev & 0xFF)
724  
725      def send(
726          self,
727          data,
728          *,
729          keep_listening=False,
730          destination=None,
731          node=None,
732          identifier=None,
733          flags=None
734      ):
735          """Send a string of data using the transmitter.
736             You can only send 60 bytes at a time
737             (limited by chip's FIFO size and appended headers).
738             This appends a 4 byte header to be compatible with the RadioHead library.
739             The header defaults to using the initialized attributes:
740             (destination,node,identifier,flags)
741             It may be temporarily overidden via the kwargs - destination,node,identifier,flags.
742             Values passed via kwargs do not alter the attribute settings.
743             The keep_listening argument should be set to True if you want to start listening
744             automatically after the packet is sent. The default setting is False.
745  
746             Returns: True if success or False if the send timed out.
747          """
748          # Disable pylint warning to not use length as a check for zero.
749          # This is a puzzling warning as the below code is clearly the most
750          # efficient and proper way to ensure a precondition that the provided
751          # buffer be within an expected range of bounds.  Disable this check.
752          # pylint: disable=len-as-condition
753          assert 0 < len(data) <= 60
754          # pylint: enable=len-as-condition
755          self.idle()  # Stop receiving to clear FIFO and keep it clear.
756          # Fill the FIFO with a packet to send.
757          # Combine header and data to form payload
758          payload = bytearray(4)
759          if destination is None:  # use attribute
760              payload[0] = self.destination
761          else:  # use kwarg
762              payload[0] = destination
763          if node is None:  # use attribute
764              payload[1] = self.node
765          else:  # use kwarg
766              payload[1] = node
767          if identifier is None:  # use attribute
768              payload[2] = self.identifier
769          else:  # use kwarg
770              payload[2] = identifier
771          if flags is None:  # use attribute
772              payload[3] = self.flags
773          else:  # use kwarg
774              payload[3] = flags
775          payload = payload + data
776          # Write payload to transmit fifo
777          self._write_fifo_from(payload)
778          # Turn on transmit mode to send out the packet.
779          self.transmit()
780          # Wait for packet sent interrupt with explicit polling (not ideal but
781          # best that can be done right now without interrupts).
782          start = time.monotonic()
783          timed_out = False
784          while not timed_out and not self.packet_sent:
785              if (time.monotonic() - start) >= self.xmit_timeout:
786                  timed_out = True
787          # Listen again if requested.
788          if keep_listening:
789              self.listen()
790          else:  # Enter idle mode to stop receiving other packets.
791              self.idle()
792          return not timed_out
793  
794      def send_with_ack(self, data):
795          """Reliable Datagram mode:
796             Send a packet with data and wait for an ACK response.
797             The packet header is automatically generated.
798             If enabled, the packet transmission will be retried on failure
799          """
800          if self.ack_retries:
801              retries_remaining = self.ack_retries
802          else:
803              retries_remaining = 1
804          got_ack = False
805          self.sequence_number = (self.sequence_number + 1) & 0xFF
806          while not got_ack and retries_remaining:
807              self.identifier = self.sequence_number
808              self.send(data, keep_listening=True)
809              # Don't look for ACK from Broadcast message
810              if self.destination == _RH_BROADCAST_ADDRESS:
811                  got_ack = True
812              else:
813                  # wait for a packet from our destination
814                  ack_packet = self.receive(timeout=self.ack_wait, with_header=True)
815                  if ack_packet is not None:
816                      if ack_packet[3] & _RH_FLAGS_ACK:
817                          # check the ID
818                          if ack_packet[2] == self.identifier:
819                              got_ack = True
820                              break
821              # pause before next retry -- random delay
822              if not got_ack:
823                  # delay by random amount before next try
824                  time.sleep(self.ack_wait + self.ack_wait * random.random())
825              retries_remaining = retries_remaining - 1
826              # set retry flag in packet header
827              self.flags |= _RH_FLAGS_RETRY
828          self.flags = 0  # clear flags
829          return got_ack
830  
831      # pylint: disable=too-many-branches
832      def receive(
833          self, *, keep_listening=True, with_ack=False, timeout=None, with_header=False
834      ):
835          """Wait to receive a packet from the receiver. If a packet is found the payload bytes
836             are returned, otherwise None is returned (which indicates the timeout elapsed with no
837             reception).
838             If keep_listening is True (the default) the chip will immediately enter listening mode
839             after reception of a packet, otherwise it will fall back to idle mode and ignore any
840             future reception.
841             All packets must have a 4 byte header for compatibilty with the
842             RadioHead library.
843             The header consists of 4 bytes (To,From,ID,Flags). The default setting will  strip
844             the header before returning the packet to the caller.
845             If with_header is True then the 4 byte header will be returned with the packet.
846             The payload then begins at packet[4].
847             If with_ack is True, send an ACK after receipt (Reliable Datagram mode)
848          """
849          timed_out = False
850          if timeout is None:
851              timeout = self.receive_timeout
852          if timeout is not None:
853              # Wait for the payload_ready signal.  This is not ideal and will
854              # surely miss or overflow the FIFO when packets aren't read fast
855              # enough, however it's the best that can be done from Python without
856              # interrupt supports.
857              # Make sure we are listening for packets.
858              self.listen()
859              start = time.monotonic()
860              timed_out = False
861              while not timed_out and not self.payload_ready:
862                  if (time.monotonic() - start) >= timeout:
863                      timed_out = True
864          # Payload ready is set, a packet is in the FIFO.
865          packet = None
866          # save last RSSI reading
867          self.last_rssi = self.rssi
868          # Enter idle mode to stop receiving other packets.
869          self.idle()
870          if not timed_out:
871              # Read the length of the FIFO.
872              fifo_length = self._read_u8(_REG_FIFO)
873              # Handle if the received packet is too small to include the 4 byte
874              # RadioHead header and at least one byte of data --reject this packet and ignore it.
875              if fifo_length > 0:  # read and clear the FIFO if anything in it
876                  packet = bytearray(fifo_length)
877                  self._read_into(_REG_FIFO, packet)
878              if fifo_length < 5:
879                  packet = None
880              else:
881                  if (
882                      self.node != _RH_BROADCAST_ADDRESS
883                      and packet[0] != _RH_BROADCAST_ADDRESS
884                      and packet[0] != self.node
885                  ):
886                      packet = None
887                  # send ACK unless this was an ACK or a broadcast
888                  elif (
889                      with_ack
890                      and ((packet[3] & _RH_FLAGS_ACK) == 0)
891                      and (packet[0] != _RH_BROADCAST_ADDRESS)
892                  ):
893                      # delay before sending Ack to give receiver a chance to get ready
894                      if self.ack_delay is not None:
895                          time.sleep(self.ack_delay)
896                      # send ACK packet to sender
897                      data = bytes("!", "UTF-8")
898                      self.send(
899                          data,
900                          destination=packet[1],
901                          node=packet[0],
902                          identifier=packet[2],
903                          flags=(packet[3] | _RH_FLAGS_ACK),
904                      )
905                      # reject Retries if we have seen this idetifier from this source before
906                      if (self.seen_ids[packet[1]] == packet[2]) and (
907                          packet[3] & _RH_FLAGS_RETRY
908                      ):
909                          packet = None
910                      else:  # save the packet identifier for this source
911                          self.seen_ids[packet[1]] = packet[2]
912                  if (
913                      not with_header and packet is not None
914                  ):  # skip the header if not wanted
915                      packet = packet[4:]
916          # Listen again if necessary and return the result packet.
917          if keep_listening:
918              self.listen()
919          else:
920              # Enter idle mode to stop receiving other packets.
921              self.idle()
922          return packet