Skip to content

Commit c316502

Browse files
authored
Merge pull request #19 from jerryneedell/jerryn_interrupt
enable interrupt handling for received packets
2 parents bfb9150 + 716fd5b commit c316502

File tree

4 files changed

+163
-15
lines changed

4 files changed

+163
-15
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_rfm69.py

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,7 @@ def frequency_deviation(self, val):
674674
self._write_u8(_REG_FDEV_MSB, fdev >> 8)
675675
self._write_u8(_REG_FDEV_LSB, fdev & 0xFF)
676676

677-
def send(self, data, timeout=2.,
677+
def send(self, data, timeout=2., keep_listening=False,
678678
tx_header=(_RH_BROADCAST_ADDRESS, _RH_BROADCAST_ADDRESS, 0, 0)):
679679
"""Send a string of data using the transmitter.
680680
You can only send 60 bytes at a time
@@ -683,6 +683,8 @@ def send(self, data, timeout=2.,
683683
The tx_header defaults to using the Broadcast addresses. It may be overidden
684684
by specifying a 4-tuple of bytes containing (To,From,ID,Flags)
685685
The timeout is just to prevent a hang (arbitrarily set to 2 seconds)
686+
The keep_listening argument should be set to True if you want to start listening
687+
automatically after the packet is sent. The default setting is False.
686688
"""
687689
# Disable pylint warning to not use length as a check for zero.
688690
# This is a puzzling warning as the below code is clearly the most
@@ -717,8 +719,12 @@ def send(self, data, timeout=2.,
717719
while not timed_out and not self.packet_sent:
718720
if (time.monotonic() - start) >= timeout:
719721
timed_out = True
720-
# Go back to idle mode after transmit.
721-
self.idle()
722+
# Listen again if necessary and return the result packet.
723+
if keep_listening:
724+
self.listen()
725+
else:
726+
# Enter idle mode to stop receiving other packets.
727+
self.idle()
722728
if timed_out:
723729
raise RuntimeError('Timeout during packet send')
724730

@@ -727,7 +733,7 @@ def receive(self, timeout=0.5, keep_listening=True, with_header=False,
727733
"""Wait to receive a packet from the receiver. Will wait for up to timeout_s amount of
728734
seconds for a packet to be received and decoded. If a packet is found the payload bytes
729735
are returned, otherwise None is returned (which indicates the timeout elapsed with no
730-
reception).
736+
reception). If timeout is None then it is not used ( for use with interrupts)
731737
If keep_listening is True (the default) the chip will immediately enter listening mode
732738
after reception of a packet, otherwise it will fall back to idle mode and ignore any
733739
future reception.
@@ -744,17 +750,19 @@ def receive(self, timeout=0.5, keep_listening=True, with_header=False,
744750
If rx_filter is not 0xff and packet[0] does not match rx_filter then
745751
the packet is ignored and None is returned.
746752
"""
747-
# Make sure we are listening for packets.
748-
self.listen()
749-
# Wait for the payload_ready interrupt. This is not ideal and will
750-
# surely miss or overflow the FIFO when packets aren't read fast
751-
# enough, however it's the best that can be done from Python without
752-
# interrupt supports.
753-
start = time.monotonic()
754753
timed_out = False
755-
while not timed_out and not self.payload_ready:
756-
if (time.monotonic() - start) >= timeout:
757-
timed_out = True
754+
if timeout is not None:
755+
# Make sure we are listening for packets.
756+
self.listen()
757+
# Wait for the payload_ready interrupt. This is not ideal and will
758+
# surely miss or overflow the FIFO when packets aren't read fast
759+
# enough, however it's the best that can be done from Python without
760+
# interrupt supports.
761+
start = time.monotonic()
762+
timed_out = False
763+
while not timed_out and not self.payload_ready:
764+
if (time.monotonic() - start) >= timeout:
765+
timed_out = True
758766
# Payload ready is set, a packet is in the FIFO.
759767
packet = None
760768
# Enter idle mode to stop receiving other packets.

examples/rfm69_rpi_interrupt.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
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_rfm69
12+
13+
# setup interrupt callback function
14+
def rfm69_callback(rfm69_irq):
15+
global packet_received #pylint: disable=global-statement
16+
print("IRQ detected on pin {0} payload_ready {1} ".format(rfm69_irq, rfm69.payload_ready))
17+
# see if this was a payload_ready interrupt ignore if not
18+
if rfm69.payload_ready:
19+
packet = rfm69.receive(timeout = None)
20+
if packet is not None:
21+
# Received a packet!
22+
packet_received = True
23+
# Print out the raw bytes of the packet:
24+
print('Received (raw bytes): {0}'.format(packet))
25+
print([hex(x) for x in packet])
26+
print('RSSI: {0}'.format(rfm69.rssi))
27+
28+
29+
# Define radio parameters.
30+
RADIO_FREQ_MHZ = 915.0 # Frequency of the radio in Mhz. Must match your
31+
# module! Can be a value like 915.0, 433.0, etc.
32+
33+
# Define pins connected to the chip, use these if wiring up the breakout according to the guide:
34+
CS = digitalio.DigitalInOut(board.CE1)
35+
RESET = digitalio.DigitalInOut(board.D25)
36+
37+
# Initialize SPI bus.
38+
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
39+
40+
# Initialze RFM radio
41+
rfm69 = adafruit_rfm69.RFM69(spi, CS, RESET, RADIO_FREQ_MHZ)
42+
43+
# Optionally set an encryption key (16 byte AES key). MUST match both
44+
# on the transmitter and receiver (or be set to None to disable/the default).
45+
rfm69.encryption_key = b'\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08'
46+
47+
# Print out some chip state:
48+
print('Temperature: {0}C'.format(rfm69.temperature))
49+
print('Frequency: {0}mhz'.format(rfm69.frequency_mhz))
50+
print('Bit rate: {0}kbit/s'.format(rfm69.bitrate/1000))
51+
print('Frequency deviation: {0}hz'.format(rfm69.frequency_deviation))
52+
53+
# configure the interrupt pin and event handling.
54+
RFM69_G0 = 22
55+
io.setmode(io.BCM)
56+
io.setup(RFM69_G0, io.IN,pull_up_down=io.PUD_DOWN) # activate input
57+
io.add_event_detect(RFM69_G0,io.RISING)
58+
io.add_event_callback(RFM69_G0,rfm69_callback)
59+
packet_received = False
60+
61+
# Send a packet. Note you can only send a packet up to 60 bytes in length.
62+
# This is a limitation of the radio packet size, so if you need to send larger
63+
# amounts of data you will need to break it into smaller send calls. Each send
64+
# call will wait for the previous one to finish before continuing.
65+
rfm69.send(bytes('Hello world!\r\n',"utf-8"), keep_listening = True)
66+
print('Sent hello world message!')
67+
# If you don't wawnt to send a message to start you can just start lintening
68+
# rmf69.listen()
69+
70+
# Wait to receive packets. Note that this library can't receive data at a fast
71+
# rate, in fact it can only receive and process one 60 byte packet at a time.
72+
# This means you should only use this for low bandwidth scenarios, like sending
73+
# and receiving a single message at a time.
74+
print('Waiting for packets...')
75+
76+
# the loop is where you can do any desire processing
77+
# the global variable packet_received can be used to determine if a packet was received.
78+
while True:
79+
# the sleep time is arbitrary since any incomming packe will trigger an interrupt
80+
# and be received.
81+
time.sleep(.1)
82+
if packet_received:
83+
print('received message!')
84+
packet_received = False

examples/rfm69_transmit.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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_rfm69
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+
rfm69 = adafruit_rfm69.RFM69(spi, CS, RESET, RADIO_FREQ_MHZ)
26+
27+
# Optionally set an encryption key (16 byte AES key). MUST match both
28+
# on the transmitter and receiver (or be set to None to disable/the default).
29+
rfm69.encryption_key = b'\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08'
30+
31+
# initialize counter
32+
counter = 0
33+
#send a broadcast mesage
34+
rfm69.send(bytes("message number {}".format(counter),"UTF-8"))
35+
36+
# Wait to receive packets.
37+
print('Waiting for packets...')
38+
#initialize flag and timer
39+
send_reading=False
40+
time_now=time.monotonic()
41+
while True:
42+
# Look for a new packet - wait up to 5 seconds:
43+
packet = rfm69.receive(timeout=5.0)
44+
# If no packet was received during the timeout then None is returned.
45+
if packet is not None:
46+
# Received a packet!
47+
# Print out the raw bytes of the packet:
48+
print('Received (raw bytes): {0}'.format(packet))
49+
# send reading after any packet received
50+
if time.monotonic()-time_now>transmit_interval:
51+
#reset timeer
52+
time_now=time.monotonic()
53+
#clear flag to send data
54+
send_reading=False
55+
counter = counter + 1
56+
rfm69.send(bytes("message number {}".format(counter),"UTF-8"))

0 commit comments

Comments
 (0)