diff --git a/.pylintrc b/.pylintrc index 039eaec..3e561cd 100644 --- a/.pylintrc +++ b/.pylintrc @@ -156,7 +156,7 @@ ignored-classes=optparse.Values,thread._local,_thread._local # (useful for modules/projects where namespaces are manipulated during runtime # and thus existing member attributes cannot be deduced by static analysis. It # supports qualified module names, as well as Unix pattern matching. -ignored-modules=board +ignored-modules=board,RPi.GPIO # Show a hint with possible names when a member name was not found. The aspect # of finding the hint is based on edit distance. diff --git a/adafruit_rfm69.py b/adafruit_rfm69.py index da73423..2fe8184 100644 --- a/adafruit_rfm69.py +++ b/adafruit_rfm69.py @@ -674,7 +674,7 @@ def frequency_deviation(self, val): self._write_u8(_REG_FDEV_MSB, fdev >> 8) self._write_u8(_REG_FDEV_LSB, fdev & 0xFF) - def send(self, data, timeout=2., + def send(self, data, timeout=2., keep_listening=False, tx_header=(_RH_BROADCAST_ADDRESS, _RH_BROADCAST_ADDRESS, 0, 0)): """Send a string of data using the transmitter. You can only send 60 bytes at a time @@ -683,6 +683,8 @@ def send(self, data, timeout=2., The tx_header defaults to using the Broadcast addresses. It may be overidden by specifying a 4-tuple of bytes containing (To,From,ID,Flags) The timeout is just to prevent a hang (arbitrarily set to 2 seconds) + The keep_listening argument should be set to True if you want to start listening + automatically after the packet is sent. The default setting is False. """ # Disable pylint warning to not use length as a check for zero. # This is a puzzling warning as the below code is clearly the most @@ -717,8 +719,12 @@ def send(self, data, timeout=2., while not timed_out and not self.packet_sent: if (time.monotonic() - start) >= timeout: timed_out = True - # Go back to idle mode after transmit. - self.idle() + # Listen again if necessary and return the result packet. + if keep_listening: + self.listen() + else: + # Enter idle mode to stop receiving other packets. + self.idle() if timed_out: raise RuntimeError('Timeout during packet send') @@ -727,7 +733,7 @@ def receive(self, timeout=0.5, keep_listening=True, with_header=False, """Wait to receive a packet from the receiver. Will wait for up to timeout_s amount of seconds for a packet to be received and decoded. If a packet is found the payload bytes are returned, otherwise None is returned (which indicates the timeout elapsed with no - reception). + reception). If timeout is None then it is not used ( for use with interrupts) If keep_listening is True (the default) the chip will immediately enter listening mode after reception of a packet, otherwise it will fall back to idle mode and ignore any future reception. @@ -744,17 +750,19 @@ def receive(self, timeout=0.5, keep_listening=True, with_header=False, If rx_filter is not 0xff and packet[0] does not match rx_filter then the packet is ignored and None is returned. """ - # Make sure we are listening for packets. - self.listen() - # Wait for the payload_ready interrupt. This is not ideal and will - # surely miss or overflow the FIFO when packets aren't read fast - # enough, however it's the best that can be done from Python without - # interrupt supports. - start = time.monotonic() timed_out = False - while not timed_out and not self.payload_ready: - if (time.monotonic() - start) >= timeout: - timed_out = True + if timeout is not None: + # Make sure we are listening for packets. + self.listen() + # Wait for the payload_ready interrupt. This is not ideal and will + # surely miss or overflow the FIFO when packets aren't read fast + # enough, however it's the best that can be done from Python without + # interrupt supports. + start = time.monotonic() + timed_out = False + while not timed_out and not self.payload_ready: + if (time.monotonic() - start) >= timeout: + timed_out = True # Payload ready is set, a packet is in the FIFO. packet = None # Enter idle mode to stop receiving other packets. diff --git a/examples/rfm69_rpi_interrupt.py b/examples/rfm69_rpi_interrupt.py new file mode 100644 index 0000000..0118fd5 --- /dev/null +++ b/examples/rfm69_rpi_interrupt.py @@ -0,0 +1,84 @@ +# Example using Interrupts to send a message and then wait indefinitely for messages +# to be received. Interrupts are used only for receive. sending is done with polling. +# This example is for systems that support interrupts like the Raspberry Pi with "blinka" +# CircuitPython does not support interrupts so it will not work on Circutpython boards +# Author: Tony DiCola, Jerry Needell +import time +import board +import busio +import digitalio +import RPi.GPIO as io +import adafruit_rfm69 + +# setup interrupt callback function +def rfm69_callback(rfm69_irq): + global packet_received #pylint: disable=global-statement + print("IRQ detected on pin {0} payload_ready {1} ".format(rfm69_irq, rfm69.payload_ready)) + # see if this was a payload_ready interrupt ignore if not + if rfm69.payload_ready: + packet = rfm69.receive(timeout = None) + if packet is not None: + # Received a packet! + packet_received = True + # Print out the raw bytes of the packet: + print('Received (raw bytes): {0}'.format(packet)) + print([hex(x) for x in packet]) + print('RSSI: {0}'.format(rfm69.rssi)) + + +# 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 +rfm69 = adafruit_rfm69.RFM69(spi, CS, RESET, RADIO_FREQ_MHZ) + +# Optionally set an encryption key (16 byte AES key). MUST match both +# on the transmitter and receiver (or be set to None to disable/the default). +rfm69.encryption_key = b'\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08' + +# Print out some chip state: +print('Temperature: {0}C'.format(rfm69.temperature)) +print('Frequency: {0}mhz'.format(rfm69.frequency_mhz)) +print('Bit rate: {0}kbit/s'.format(rfm69.bitrate/1000)) +print('Frequency deviation: {0}hz'.format(rfm69.frequency_deviation)) + +# configure the interrupt pin and event handling. +RFM69_G0 = 22 +io.setmode(io.BCM) +io.setup(RFM69_G0, io.IN,pull_up_down=io.PUD_DOWN) # activate input +io.add_event_detect(RFM69_G0,io.RISING) +io.add_event_callback(RFM69_G0,rfm69_callback) +packet_received = False + +# Send a packet. Note you can only send a packet up to 60 bytes in length. +# This is a limitation of the radio packet size, so if you need to send larger +# amounts of data you will need to break it into smaller send calls. Each send +# call will wait for the previous one to finish before continuing. +rfm69.send(bytes('Hello world!\r\n',"utf-8"), keep_listening = True) +print('Sent hello world message!') +# If you don't wawnt to send a message to start you can just start lintening +# rmf69.listen() + +# Wait to receive packets. Note that this library can't receive data at a fast +# rate, in fact it can only receive and process one 60 byte packet at a time. +# This means you should only use this for low bandwidth scenarios, like sending +# and receiving a single message at a time. +print('Waiting for packets...') + +# the loop is where you can do any desire processing +# the global variable packet_received can be used to determine if a packet was received. +while True: + # the sleep time is arbitrary since any incomming packe will trigger an interrupt + # and be received. + time.sleep(.1) + if packet_received: + print('received message!') + packet_received = False diff --git a/examples/rfm69_transmit.py b/examples/rfm69_transmit.py new file mode 100644 index 0000000..edb2f84 --- /dev/null +++ b/examples/rfm69_transmit.py @@ -0,0 +1,56 @@ +# Example to send a packet periodically +# Author: Jerry Needell +# +import time +import board +import busio +import digitalio +import adafruit_rfm69 + +# set the time interval (seconds) for sending packets +transmit_interval=10 + +# 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. +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 +rfm69 = adafruit_rfm69.RFM69(spi, CS, RESET, RADIO_FREQ_MHZ) + +# Optionally set an encryption key (16 byte AES key). MUST match both +# on the transmitter and receiver (or be set to None to disable/the default). +rfm69.encryption_key = b'\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08' + +# initialize counter +counter = 0 +#send a broadcast mesage +rfm69.send(bytes("message number {}".format(counter),"UTF-8")) + +# Wait to receive packets. +print('Waiting for packets...') +#initialize flag and timer +send_reading=False +time_now=time.monotonic() +while True: + # Look for a new packet - wait up to 5 seconds: + packet = rfm69.receive(timeout=5.0) + # 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('Received (raw bytes): {0}'.format(packet)) + # send reading after any packet received + if time.monotonic()-time_now>transmit_interval: + #reset timeer + time_now=time.monotonic() + #clear flag to send data + send_reading=False + counter = counter + 1 + rfm69.send(bytes("message number {}".format(counter),"UTF-8"))