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