Optimized high speed nRF24L01+ driver class documentation v1.4.9
TMRh20 2020 - Optimized fork of the nRF24L01+ driver
Loading...
Searching...
No Matches
examples_linux/acknowledgement_payloads.py

Written by 2bndy5 in 2020

This is a simple example of using the RF24 class on a Raspberry Pi to transmit and retrieve custom automatic acknowledgment payloads.

Remember to install the Python wrapper, then navigate to the "RF24/examples_linux" folder.
To run this example, enter

python3 acknowledgement_payloads.py

and follow the prompts.

Note
this example requires python v3.7 or newer because it measures transmission time with time.monotonic_ns().
1"""
2A simple example of sending data from 1 nRF24L01 transceiver to another
3with Acknowledgement (ACK) payloads attached to ACK packets.
4
5This example was written to be used on 2 devices acting as 'nodes'.
6
7See documentation at https://nRF24.github.io/RF24
8"""
9
10import time
11from RF24 import RF24, RF24_PA_LOW, RF24_DRIVER
12
13print(__file__) # print example name
14
15
21CSN_PIN = 0 # GPIO8 aka CE0 on SPI bus 0: /dev/spidev0.0
22if RF24_DRIVER == "MRAA":
23 CE_PIN = 15 # for GPIO22
24elif RF24_DRIVER == "wiringPi":
25 CE_PIN = 3 # for GPIO22
26else:
27 CE_PIN = 22
28radio = RF24(CE_PIN, CSN_PIN)
29
30# initialize the nRF24L01 on the spi bus
31if not radio.begin():
32 raise RuntimeError("radio hardware is not responding")
33
34# For this example, we will use different addresses
35# An address need to be a buffer protocol object (bytearray)
36address = [b"1Node", b"2Node"]
37# It is very helpful to think of an address as a path instead of as
38# an identifying device destination
39
40radio_number = bool(
41 int(input("Which radio is this? Enter '0' or '1'. Defaults to '0' ") or 0)
42)
43
44# ACK payloads are dynamically sized.
45radio.enableDynamicPayloads() # to use ACK payloads
46
47# to enable the custom ACK payload feature
48radio.enableAckPayload()
49
50# set the Power Amplifier level to -12 dBm since this test example is
51# usually run with nRF24L01 transceivers in close proximity of each other
52radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default
53
54# set the TX address of the RX node into the TX pipe
55radio.openWritingPipe(address[radio_number]) # always uses pipe 0
56
57# set the RX address of the TX node into a RX pipe
58radio.openReadingPipe(1, address[not radio_number]) # using pipe 1
59
60# for debugging, we have 2 options that print a large block of details
61# (smaller) function that prints raw register values
62# radio.printDetails()
63# (larger) function that prints human readable data
64# radio.printPrettyDetails()
65
66# using the python keyword global is bad practice. Instead we'll use a
67# 1 item list to store our integer number for the payloads' counter
68counter = [0]
69
70
71def master():
72 """Transmits a message and an incrementing integer every second."""
73 radio.stopListening() # put radio in TX mode
74 failures = 0
75 while failures < 6:
76 # construct a payload to send
77 buffer = b"Hello \x00" + bytes(counter)
78
79 # send the payload and prompt
80 start_timer = time.monotonic_ns() # start timer
81 result = radio.write(buffer) # save the report
82 end_timer = time.monotonic_ns() # stop timer
83 if result:
84 # print timer results upon transmission success
85 decoded = buffer[:6].decode("utf-8")
86 print(
87 "Transmission successful! Time to transmit:",
88 f"{int((end_timer - start_timer) / 1000)} us.",
89 f"Sent: {decoded}{counter[0]}",
90 end=" ",
91 )
92 has_payload, pipe_number = radio.available_pipe()
93 if has_payload:
94 # print the received ACK that was automatically sent
95 length = radio.getDynamicPayloadSize()
96 response = radio.read(length)
97 decoded = bytes(response[:6]).decode("utf-8")
98 print(
99 f"Received {length} on pipe {pipe_number}:",
100 f"{decoded}{response[7:8][0]}",
101 )
102 # increment counter from received payload
103 if response[7:8][0] < 255:
104 counter[0] = response[7:8][0] + 1
105 else:
106 counter[0] = 0
107 else:
108 print("Received an empty ACK packet")
109 else:
110 failures += 1
111 print("Transmission failed or timed out")
112 time.sleep(1) # let the RX node prepare a new ACK payload
113 print(failures, "failures detected. Leaving TX role.")
114
115
116def slave(timeout: int = 6):
117 """Listen for any payloads and print the transaction
118
119 :param int timeout: The number of seconds to wait (with no transmission)
120 until exiting function.
121 """
122 radio.startListening() # put radio in RX mode
123
124 # setup the first transmission's ACK payload
125 buffer = b"World \x00" + bytes(counter)
126 # we must set the ACK payload data and corresponding
127 # pipe number [0,5]
128 radio.writeAckPayload(1, buffer) # load ACK for first response
129
130 start_timer = time.monotonic() # start timer
131 while (time.monotonic() - start_timer) < timeout:
132 has_payload, pipe_number = radio.available_pipe()
133 if has_payload:
134 length = radio.getDynamicPayloadSize() # grab the payload length
135 received = radio.read(length) # fetch 1 payload from RX FIFO
136 # increment counter from received payload
137 counter[0] = received[7:8][0] + 1 if received[7:8][0] < 255 else 0
138 decoded = [bytes(received[:6]).decode("utf-8")]
139 decoded.append(buffer[:6].decode("utf-8"))
140 print(
141 f"Received {length} bytes on pipe {pipe_number}:",
142 f"{decoded[0]}{received[7:8][0]}",
143 f"Sent: {decoded[1]}{buffer[7:8][0]}",
144 )
145 buffer = b"World \x00" + bytes(counter) # build a new ACK payload
146 radio.writeAckPayload(1, buffer) # load ACK for next response
147 start_timer = time.monotonic() # reset timer
148
149 print("Nothing received in", timeout, "seconds. Leaving RX role")
150 # recommended behavior is to keep in TX mode while idle
151 radio.stopListening() # put radio in TX mode & flush unused ACK payloads
152
153
154def set_role() -> bool:
155 """Set the role using stdin stream. Timeout arg for slave() can be
156 specified using a space delimiter (e.g. 'R 10' calls `slave(10)`)
157
158 :return:
159 - True when role is complete & app should continue running.
160 - False when app should exit
161 """
162 user_input = (
163 input(
164 "*** Enter 'R' for receiver role.\n"
165 "*** Enter 'T' for transmitter role.\n"
166 "*** Enter 'Q' to quit example.\n"
167 )
168 or "?"
169 )
170 user_input = user_input.split()
171 if user_input[0].upper().startswith("R"):
172 if len(user_input) > 1:
173 slave(int(user_input[1]))
174 else:
175 slave()
176 return True
177 if user_input[0].upper().startswith("T"):
178 master()
179 return True
180 if user_input[0].upper().startswith("Q"):
181 radio.powerDown()
182 return False
183 print(user_input[0], "is an unrecognized input. Please try again.")
184 return set_role()
185
186
187if __name__ == "__main__":
188 try:
189 while set_role():
190 pass # continue example until 'Q' is entered
191 except KeyboardInterrupt:
192 print(" Keyboard Interrupt detected. Exiting...")
193 radio.powerDown()
194else:
195 print(" Run slave() on receiver\n Run master() on transmitter")
Driver class for nRF24L01(+) 2.4GHz Wireless Transceiver.
Definition RF24.h:116