Skip to content

Commit bc7da6c

Browse files
authored
Merge pull request #33 from jerryneedell/jerryn_interrupt
enable usage of interrupts with received packets
2 parents 8b70dc1 + d0b79ae commit bc7da6c

File tree

4 files changed

+159
-17
lines changed

4 files changed

+159
-17
lines changed

.pylintrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ ignored-classes=optparse.Values,thread._local,_thread._local
156156
# (useful for modules/projects where namespaces are manipulated during runtime
157157
# and thus existing member attributes cannot be deduced by static analysis. It
158158
# supports qualified module names, as well as Unix pattern matching.
159-
ignored-modules=board
159+
ignored-modules=board,RPi.GPIO
160160

161161
# Show a hint with possible names when a member name was not found. The aspect
162162
# of finding the hint is based on edit distance.

adafruit_rfm9x.py

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,7 @@ def enable_crc(self, val):
646646
self._read_u8(_RH_RF95_REG_1E_MODEM_CONFIG2) & 0xfb
647647
)
648648

649-
def send(self, data, timeout=2.,
649+
def send(self, data, timeout=2., keep_listening=False,
650650
tx_header=(_RH_BROADCAST_ADDRESS, _RH_BROADCAST_ADDRESS, 0, 0)):
651651
"""Send a string of data using the transmitter.
652652
You can only send 252 bytes at a time
@@ -655,11 +655,13 @@ def send(self, data, timeout=2.,
655655
The tx_header defaults to using the Broadcast addresses. It may be overidden
656656
by specifying a 4-tuple of bytes containing (To,From,ID,Flags)
657657
The timeout is just to prevent a hang (arbitrarily set to 2 seconds)
658+
The keep_listening argument should be set to True if you want to start listening
659+
automatically after the packet is sent. The default setting is False.
658660
"""
659661
# Disable pylint warning to not use length as a check for zero.
660662
# This is a puzzling warning as the below code is clearly the most
661663
# efficient and proper way to ensure a precondition that the provided
662-
# buffer be within an expected range of bounds. Disable this check.
664+
# buffer be within an expected range of bounds. Disable this check.
663665
# pylint: disable=len-as-condition
664666
assert 0 < len(data) <= 252
665667
assert len(tx_header) == 4, "tx header must be 4-tuple (To,From,ID,Flags)"
@@ -685,9 +687,13 @@ def send(self, data, timeout=2.,
685687
while not timed_out and not self.tx_done:
686688
if (time.monotonic() - start) >= timeout:
687689
timed_out = True
688-
# Go back to idle mode after transmit.
689-
self.idle()
690-
# Clear interrupts.
690+
# Listen again if necessary and return the result packet.
691+
if keep_listening:
692+
self.listen()
693+
else:
694+
# Enter idle mode to stop receiving other packets.
695+
self.idle()
696+
# Clear interrupt.
691697
self._write_u8(_RH_RF95_REG_12_IRQ_FLAGS, 0xFF)
692698
if timed_out:
693699
raise RuntimeError('Timeout during packet send')
@@ -699,7 +705,7 @@ def receive(self, timeout=0.5, keep_listening=True, with_header=False,
699705
"""Wait to receive a packet from the receiver. Will wait for up to timeout_s amount of
700706
seconds for a packet to be received and decoded. If a packet is found the payload bytes
701707
are returned, otherwise None is returned (which indicates the timeout elapsed with no
702-
reception).
708+
reception). If timeout is None it is not used ( for use with interrupts)
703709
If keep_listening is True (the default) the chip will immediately enter listening mode
704710
after reception of a packet, otherwise it will fall back to idle mode and ignore any
705711
future reception.
@@ -716,17 +722,18 @@ def receive(self, timeout=0.5, keep_listening=True, with_header=False,
716722
If rx_filter is not 0xff and packet[0] does not match rx_filter then
717723
the packet is ignored and None is returned.
718724
"""
719-
# Make sure we are listening for packets.
720-
self.listen()
721-
# Wait for the rx done interrupt. This is not ideal and will
722-
# surely miss or overflow the FIFO when packets aren't read fast
723-
# enough, however it's the best that can be done from Python without
724-
# interrupt supports.
725-
start = time.monotonic()
726725
timed_out = False
727-
while not timed_out and not self.rx_done:
728-
if (time.monotonic() - start) >= timeout:
729-
timed_out = True
726+
if timeout is not None:
727+
# Make sure we are listening for packets.
728+
self.listen()
729+
# Wait for the rx done interrupt. This is not ideal and will
730+
# surely miss or overflow the FIFO when packets aren't read fast
731+
# enough, however it's the best that can be done from Python without
732+
# interrupt supports.
733+
start = time.monotonic()
734+
while not timed_out and not self.rx_done:
735+
if (time.monotonic() - start) >= timeout:
736+
timed_out = True
730737
# Payload ready is set, a packet is in the FIFO.
731738
packet = None
732739
if not timed_out:

examples/rfm9x_rpi_interrupt.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Example using Interrupts to send a message and then wait indefinitely for messages
2+
# to be received. Interrupts are used only for receive. sending is done with polling.
3+
# This example is for systems that support interrupts like the Raspberry Pi with "blinka"
4+
# CircuitPython does not support interrupts so it will not work on Circutpython boards
5+
# Author: Tony DiCola, Jerry Needell
6+
import time
7+
import board
8+
import busio
9+
import digitalio
10+
import RPi.GPIO as io
11+
import adafruit_rfm9x
12+
13+
14+
# setup interrupt callback function
15+
def rfm9x_callback(rfm9x_irq):
16+
global packet_received #pylint: disable=global-statement
17+
print("IRQ detected ",rfm9x_irq, rfm9x.rx_done)
18+
# check to see if this was a rx interrupt - ignore tx
19+
if rfm9x.rx_done:
20+
packet = rfm9x.receive(timeout = None)
21+
if packet is not None:
22+
packet_received = True
23+
# Received a packet!
24+
# Print out the raw bytes of the packet:
25+
print('Received (raw bytes): {0}'.format(packet))
26+
print([hex(x) for x in packet])
27+
print('RSSI: {0}'.format(rfm9x.rssi))
28+
29+
30+
# Define radio parameters.
31+
RADIO_FREQ_MHZ = 915.0 # Frequency of the radio in Mhz. Must match your
32+
# module! Can be a value like 915.0, 433.0, etc.
33+
34+
# Define pins connected to the chip, use these if wiring up the breakout according to the guide:
35+
CS = digitalio.DigitalInOut(board.CE1)
36+
RESET = digitalio.DigitalInOut(board.D25)
37+
38+
# Initialize SPI bus.
39+
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
40+
41+
# Initialze RFM radio
42+
rfm9x = adafruit_rfm9x.RFM9x(spi, CS, RESET, RADIO_FREQ_MHZ)
43+
44+
# Note that the radio is configured in LoRa mode so you can't control sync
45+
# word, encryption, frequency deviation, or other settings!
46+
47+
# You can however adjust the transmit power (in dB). The default is 13 dB but
48+
# high power radios like the RFM95 can go up to 23 dB:
49+
rfm9x.tx_power = 23
50+
51+
# configure the interrupt pin and event handling.
52+
RFM9X_G0 = 22
53+
io.setmode(io.BCM)
54+
io.setup(RFM9X_G0, io.IN,pull_up_down=io.PUD_DOWN) # activate input
55+
io.add_event_detect(RFM9X_G0,io.RISING)
56+
io.add_event_callback(RFM9X_G0,rfm9x_callback)
57+
58+
packet_received = False
59+
# Send a packet. Note you can only send a packet up to 252 bytes in length.
60+
# This is a limitation of the radio packet size, so if you need to send larger
61+
# amounts of data you will need to break it into smaller send calls. Each send
62+
# call will wait for the previous one to finish before continuing.
63+
rfm9x.send(bytes("Hello world!\r\n","utf-8"), keep_listening = True)
64+
print('Sent Hello World message!')
65+
66+
# Wait to receive packets. Note that this library can't receive data at a fast
67+
# rate, in fact it can only receive and process one 252 byte packet at a time.
68+
# This means you should only use this for low bandwidth scenarios, like sending
69+
# and receiving a single message at a time.
70+
print('Waiting for packets...')
71+
while True:
72+
time.sleep(.1)
73+
if packet_received:
74+
print('received message!')
75+
packet_received = False

examples/rfm9x_transmit.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Example to send a packet periodically
2+
# Author: Jerry Needell
3+
#
4+
import time
5+
import board
6+
import busio
7+
import digitalio
8+
import adafruit_rfm9x
9+
10+
# set the time interval (seconds) for sending packets
11+
transmit_interval=10
12+
13+
# Define radio parameters.
14+
RADIO_FREQ_MHZ = 915.0 # Frequency of the radio in Mhz. Must match your
15+
# module! Can be a value like 915.0, 433.0, etc.
16+
17+
# Define pins connected to the chip.
18+
CS = digitalio.DigitalInOut(board.CE1)
19+
RESET = digitalio.DigitalInOut(board.D25)
20+
21+
# Initialize SPI bus.
22+
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
23+
24+
# Initialze RFM radio
25+
rfm9x = adafruit_rfm9x.RFM9x(spi, CS, RESET, RADIO_FREQ_MHZ)
26+
27+
# Note that the radio is configured in LoRa mode so you can't control sync
28+
# word, encryption, frequency deviation, or other settings!
29+
30+
# You can however adjust the transmit power (in dB). The default is 13 dB but
31+
# high power radios like the RFM95 can go up to 23 dB:
32+
rfm9x.tx_power = 23
33+
34+
35+
# initialize counter
36+
counter = 0
37+
#send a broadcast mesage
38+
rfm9x.send(bytes("message number {}".format(counter),"UTF-8"))
39+
40+
# Wait to receive packets.
41+
print('Waiting for packets...')
42+
#initialize flag and timer
43+
send_reading=False
44+
time_now=time.monotonic()
45+
while True:
46+
# Look for a new packet - wait up to 5 seconds:
47+
packet = rfm9x.receive(timeout=5.0)
48+
# If no packet was received during the timeout then None is returned.
49+
if packet is not None:
50+
# Received a packet!
51+
# Print out the raw bytes of the packet:
52+
print('Received (raw bytes): {0}'.format(packet))
53+
# send reading after any packet received
54+
if time.monotonic()-time_now>transmit_interval:
55+
#reset timeer
56+
time_now=time.monotonic()
57+
#clear flag to send data
58+
send_reading=False
59+
counter = counter + 1
60+
rfm9x.send(bytes("message number {}".format(counter),"UTF-8"))

0 commit comments

Comments
 (0)