Skip to content

enable usage of interrupts with received packets #33

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
39 changes: 23 additions & 16 deletions adafruit_rfm9x.py
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ def enable_crc(self, val):
self._read_u8(_RH_RF95_REG_1E_MODEM_CONFIG2) & 0xfb
)

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 252 bytes at a time
Expand All @@ -655,11 +655,13 @@ 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
# efficient and proper way to ensure a precondition that the provided
# buffer be within an expected range of bounds. Disable this check.
# buffer be within an expected range of bounds. Disable this check.
# pylint: disable=len-as-condition
assert 0 < len(data) <= 252
assert len(tx_header) == 4, "tx header must be 4-tuple (To,From,ID,Flags)"
Expand All @@ -685,9 +687,13 @@ def send(self, data, timeout=2.,
while not timed_out and not self.tx_done:
if (time.monotonic() - start) >= timeout:
timed_out = True
# Go back to idle mode after transmit.
self.idle()
# Clear interrupts.
# 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()
# Clear interrupt.
self._write_u8(_RH_RF95_REG_12_IRQ_FLAGS, 0xFF)
if timed_out:
raise RuntimeError('Timeout during packet send')
Expand All @@ -699,7 +705,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 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.
Expand All @@ -716,17 +722,18 @@ 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 rx done 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.rx_done:
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 rx done 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()
while not timed_out and not self.rx_done:
if (time.monotonic() - start) >= timeout:
timed_out = True
# Payload ready is set, a packet is in the FIFO.
packet = None
if not timed_out:
Expand Down
75 changes: 75 additions & 0 deletions examples/rfm9x_rpi_interrupt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# 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_rfm9x


# setup interrupt callback function
def rfm9x_callback(rfm9x_irq):
global packet_received #pylint: disable=global-statement
print("IRQ detected ",rfm9x_irq, rfm9x.rx_done)
# check to see if this was a rx interrupt - ignore tx
if rfm9x.rx_done:
packet = rfm9x.receive(timeout = None)
if packet is not None:
packet_received = True
# Received a packet!
# 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(rfm9x.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
rfm9x = adafruit_rfm9x.RFM9x(spi, CS, RESET, RADIO_FREQ_MHZ)

# Note that the radio is configured in LoRa mode so you can't control sync
# word, encryption, frequency deviation, or other settings!

# You can however adjust the transmit power (in dB). The default is 13 dB but
# high power radios like the RFM95 can go up to 23 dB:
rfm9x.tx_power = 23

# configure the interrupt pin and event handling.
RFM9X_G0 = 22
io.setmode(io.BCM)
io.setup(RFM9X_G0, io.IN,pull_up_down=io.PUD_DOWN) # activate input
io.add_event_detect(RFM9X_G0,io.RISING)
io.add_event_callback(RFM9X_G0,rfm9x_callback)

packet_received = False
# Send a packet. Note you can only send a packet up to 252 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.
rfm9x.send(bytes("Hello world!\r\n","utf-8"), keep_listening = True)
print('Sent Hello World message!')

# 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 252 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...')
while True:
time.sleep(.1)
if packet_received:
print('received message!')
packet_received = False
60 changes: 60 additions & 0 deletions examples/rfm9x_transmit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Example to send a packet periodically
# Author: Jerry Needell
#
import time
import board
import busio
import digitalio
import adafruit_rfm9x

# 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
rfm9x = adafruit_rfm9x.RFM9x(spi, CS, RESET, RADIO_FREQ_MHZ)

# Note that the radio is configured in LoRa mode so you can't control sync
# word, encryption, frequency deviation, or other settings!

# You can however adjust the transmit power (in dB). The default is 13 dB but
# high power radios like the RFM95 can go up to 23 dB:
rfm9x.tx_power = 23


# initialize counter
counter = 0
#send a broadcast mesage
rfm9x.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 = rfm9x.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
rfm9x.send(bytes("message number {}".format(counter),"UTF-8"))