Krolyxon
Commit 3120783

Branches

Tags

Refs →

orion-rf.piolibdepsesp32-s3-n16r8RF24examplesencodeRadioDetailsprint_details.py

196 lines · 6.6 KB · Python

1"""A simple script to take all data dumped from the nRF24L01 registers and
2output it in human readable form.
3
4Example usage:
5 print_details.py "0e 3f 02 03 00 02 00 0e"
6
7Notes:
8 * The radio's power state is represented under the assumption that
9 the radio's CE pin is inactive low.
10"""
11# pylint: disable=consider-using-f-string
12import struct
13import argparse
14
15
16def hex_str_to_bytes(s_in: str) -> bytes:
17 """Used to convert a string from CLI to a bytearray object.
18
19 .. warning:: This function assumes that the string consists of only
20 hexadecimal characters.
21 """
22 return bytes([int(i, 16) for i in s_in.split()])
23
24
25argparser = argparse.ArgumentParser(
26 description=__doc__,
27 formatter_class=argparse.RawDescriptionHelpFormatter,
28)
29argparser.add_argument(
30 "buffer",
31 type=hex_str_to_bytes,
32 help="The encoded buffer from the Arduino Serial Monitor. The string passed is "
33 "expected to contain only hexadecimal digits. It should be 38 words long "
34 "(separated by spaces).",
35)
36
37
38def address_repr(buf, reverse: bool = True, delimit: str = "") -> str:
39 """Convert a buffer into a hexadecimal string."""
40 order = range(len(buf) - 1, -1, -1) if reverse else range(len(buf))
41 return delimit.join(["%02X" % buf[byte] for byte in order])
42
43
44# pylint: disable=too-many-locals,too-many-statements
45def print_details(encoded_buf: bytearray):
46 """This debugging function outputs all details about the nRF24L01."""
47 # declare sequences
48 pipes = [bytearray(5)] * 2 + [0] * 4
49 pl_len = [0] * 6
50
51 # unpack bytearray
52 (
53 config, # 0x00
54 auto_ack, # 0x01
55 open_pipes, # 0x02
56 addr_len, # 0x03
57 retry_setup, # 0x04
58 channel, # 0x05
59 rf_setup, # 0x06
60 status, # 0x07
61 observer, # 0x08
62 rpd, # 0x09
63 ) = struct.unpack("10B", encoded_buf[:10])
64 pipes[0] = encoded_buf[10:15] # 0x0A
65 pipes[1] = encoded_buf[15:20] # 0x0B
66 (
67 pipes[2], # 0x0C
68 pipes[3], # 0x0D
69 pipes[4], # 0x0E
70 pipes[5], # 0x0F
71 ) = struct.unpack("4B", encoded_buf[20:24])
72 tx_address = encoded_buf[24:29] # 0x10
73 (
74 pl_len[0], # 0x11
75 pl_len[1], # 0x12
76 pl_len[2], # 0x13
77 pl_len[3], # 0x14
78 pl_len[4], # 0x15
79 pl_len[5], # 0x16
80 fifo, # 0x17
81 dyn_pl, # 0x1C
82 features, # 0x1D
83 ) = struct.unpack("9B", encoded_buf[29:38])
84 ce_pin, csn_pin, spi_speed = struct.unpack(">2H1B", encoded_buf[38:44])
85
86 # do some deciphering arithmetic
87 addr_len += 2
88 crc = (2 if config & 4 else 1) if auto_ack else max(0, ((config & 0x0C) >> 2) - 1)
89 d_rate = rf_setup & 0x28
90 d_rate = (2 if d_rate == 8 else 250) if d_rate else 1
91 pa_level = (3 - ((rf_setup & 6) >> 1)) * -6
92 pa_level = (
93 "MIN"
94 if pa_level == -18
95 else ("LOW" if pa_level == -12 else ("HIGH" if pa_level == -6 else "MAX"))
96 )
97 dyn_p = (
98 ("_Enabled" if dyn_pl else "Disabled")
99 if dyn_pl == 0x3F or not dyn_pl
100 else "0b" + "0" * (8 - len(bin(dyn_pl))) + bin(dyn_pl)[2:]
101 )
102 auto_ack = (
103 ("Enabled" if auto_ack else "Disabled")
104 if auto_ack == 0x3F or not auto_ack
105 else "0b" + "0" * (8 - len(bin(auto_ack))) + bin(auto_ack)[2:]
106 )
107 pwr = "Standby" if config & 2 else "Off"
108 is_plus_variant = bool(spi_speed >> 4)
109 spi_speed = spi_speed & 0xF
110
111 # print it all out
112 print("CE pin____________________{}".format(ce_pin))
113 print("CSN pin___________________{}".format(csn_pin))
114 print("SPI speed_________________{} MHz".format(spi_speed))
115 print("Is a plus variant_________{}".format(is_plus_variant))
116 print(
117 "Channel___________________{}".format(channel),
118 "~ {} GHz".format((channel + 2400) / 1000),
119 )
120 print(
121 "RF Data Rate______________{}".format(d_rate),
122 "Mbps" if d_rate != 250 else "Kbps",
123 )
124 print("RF Power Amplifier________PA_{}".format(pa_level))
125 print(
126 "RF Low Noise Amplifier____{}abled".format(
127 "En" if bool(rf_setup & 1) else "Dis"
128 )
129 )
130 print("CRC Length________________{} bits".format(crc * 8))
131 print("Address length____________{} bytes".format(addr_len))
132 print("TX Payload lengths________{} bytes".format(pl_len[0]))
133 print(
134 "Auto retry delay__________{} microseconds".format(
135 ((retry_setup & 0xF0) >> 4) * 250 + 250
136 )
137 )
138 print("Auto retry attempts_______{} maximum".format(retry_setup & 0x0F))
139 print("Re-use TX FIFO____________{}".format(bool(fifo & 64)))
140 print("Received Power Detected___{}".format(bool(rpd)))
141 print(
142 "Packets lost on current channel_____________________{}".format(observer >> 4)
143 )
144 print(
145 "Retry attempts made for last transmission___________{}".format(observer & 0xF)
146 )
147 print(
148 "IRQ on Data Ready__{}abled".format("Dis" if config & 64 else "_En"),
149 " Data Ready___________{}".format(bool(status & 0x40)),
150 )
151 print(
152 "IRQ on Data Sent___{}abled".format("Dis" if config & 32 else "_En"),
153 " Data Sent____________{}".format(bool(status & 0x20)),
154 )
155 print(
156 "IRQ on Data Fail___{}abled".format("Dis" if config & 16 else "_En"),
157 " Data Failed__________{}".format(bool(status & 0x10)),
158 )
159 print(
160 "TX FIFO full__________{}e".format("_Tru" if fifo & 0x20 else "Fals"),
161 " TX FIFO empty________{}".format(bool(fifo & 0x10)),
162 )
163 print(
164 "RX FIFO full__________{}e".format("_Tru" if fifo & 2 else "Fals"),
165 " RX FIFO empty________{}".format(bool(fifo & 1)),
166 )
167 print(
168 "Multicast__________{}ed Custom ACK Payload___{}abled".format(
169 "_Allow" if features & 1 else "Disabl",
170 "En" if features & 2 else "Dis",
171 ),
172 )
173 print("Dynamic Payloads___{} Auto Acknowledgment__{}".format(dyn_p, auto_ack))
174 print(
175 "Primary Mode_____________{}X".format("R" if config & 1 else "T"),
176 " Power Mode___________{}".format(pwr),
177 )
178 print("TX address____________ 0x{}".format(address_repr(tx_address)))
179 for i in range(6):
180 is_open = open_pipes & (1 << i)
181 address = pipes[i] if i < 2 else bytes([pipes[i]]) + pipes[1][1:]
182 print(
183 "Pipe {} ({}) bound: 0x{}".format(
184 i, " open " if is_open else "closed", address_repr(address)
185 ),
186 )
187 if is_open and not dyn_pl & (1 << i):
188 print("\t\texpecting {} byte static payloads".format(pl_len[i]))
189
190
191# pylint: enable=too-many-locals,too-many-statements
192
193
194if __name__ == "__main__":
195 args = argparser.parse_args()
196 print_details(args.buffer)