Network Topology¶
Network Levels¶
Because of the hardware limitation’s of the nRF24L01 transceiver, each network is arranged in a levels where a parent can have up to 5 children. And each child can also have up to 5 other children. This is not limitless because this network is designed for low-memory devices. Consequently, all node’s Logical Address are limited to 12-bit integers and use an octal counting scheme.
The master node (designated with the Logical Address
0o0
) is always the only node in the lowest level (denoted as level 0).Child nodes are designated by the most significant octal digit in their Logical Address. A child node address’ least significant digits are the inherited address of it’s parent node. Nodes on level 1 only have 1 digit because they are children of the master node.
Hopefully, you should see the pattern. There can be up to a maximum of 5 network levels (that’s 0-4 ordered from lowest to highest).
For a message to travel from node 0o124
to node 0o3
, it must be passed through any applicable
network levels. So, the message flows 0o124
-> 0o24
-> 0o4
-> 0o0
-> 0o3
.
A single network can potentially have a maximum of 781 nodes (all operating on the same
channel
), but for readability reasons, the following
graph only demonstrates
the master node (level 0) and it’s 5 children (level 1)
level 2 only shows the 1st and 2nd children of parents on level 1
level 3 only shows the 3rd and 4th children of parents on level 2
level 4 only shows the 5th children of parents on level 3
Physical addresses vs Logical addresses¶
The Physical address is the 5-byte address assigned to the radio’s data pipes.
The Logical address is the 12-bit integer representing a network node. The Logical address uses an octal counting scheme. A valid Logical Address must only contain octal digits in range [1, 5]. The master node is the exception for it uses the number
0
Tip
Use the
is_address_valid()
function to programatically check a Logical Address for validity.
Note
Remember that the nRF24L01 only has 6 data pipes for which to receive or transmit. Since only data pipe 0 can be used to transmit, the other other data pipes 1-5 are devoted to receiving transmissions from other network nodes; data pipe 0 also receives multicasted messages about the node’s network level).
Translating Logical to Physical¶
Before translating the Logical address, a single byte is used reptitively as the
base case for all bytes of any Physical Address. This byte is the address_prefix
attribute (stored as a mutable bytearray
) in the RF24Network
class. By default the
address_prefix
has a single byte value of b"\xCC"
.
The RF24Network
class also has a predefined list of bytes used for translating
unique Logical addresses into unique Physical addresses. This list is called
address_suffix
(also stored as a mutable bytearray
). By default the address_suffix
has 6-byte value of b"\xC3\x3C\x33\xCE\x3E\xE3"
where the order of bytes pertains to the
data pipe number and child node’s most significant byte in its Physical Address.
- For example:
The Logical Address of the network’s master node is
0
. The radio’s pipes 1-5 start with theaddress_prefix
. To make each pipe’s Phsyical address unique to a child node’s Physical address, theaddress_suffix
is used.The Logical address of the master node:
0o0
pipe
Phsyical Address (hexadecimal)
1
CC CC CC CC 3C
2
CC CC CC CC 33
3
CC CC CC CC CE
4
CC CC CC CC 3E
5
CC CC CC CC E3
The Logical address of the master node’s first child:
0o1
pipe
Phsyical Address (hexadecimal)
1
CC CC CC 3C 3C
2
CC CC CC 3C 33
3
CC CC CC 3C CE
4
CC CC CC 3C 3E
5
CC CC CC 3C E3
The Logical address of the master node’s second child:
0o2
pipe
Phsyical Address (hexadecimal)
1
CC CC CC 33 3C
2
CC CC CC 33 33
3
CC CC CC 33 CE
4
CC CC CC 33 3E
5
CC CC CC 33 E3
The Logical address of the master node’s third child’s second child’s first child:
0o123
pipe
Phsyical Address (hexadecimal)
1
CC 3C 33 CE 3C
2
CC 3C 33 CE 33
3
CC 3C 33 CE CE
4
CC 3C 33 CE 3E
5
CC 3C 33 CE E3
Two networks coexisting on the same channel¶
Warning
The following section is an advanced tutorial. The default values for address_prefix
and address_suffix
were carefully chosen by TMRh20 to demonstrate best practices in
terms of choosing a data pipe’s address for transmissions. Bad practices can be avoided
by heeding ManiacBug’s advice in his
detailed blog post
about the topic.
In theory, the address_prefix
and address_suffix
attributes could be changed to
allow 2 separate networks to coexist on the same
channel
. The following are example code
snippets to use as a template for such a scenario.
from circuitpython_nrf24l01.rf24_network import RF24Network
# ... declare SPI_BUS, CE_PIN, and CSN_PIN objects
network_a_master = RF24Network(SPI_BUS, CSN_PIN, CE_PIN, 0)
# let network_a use the default values for address_prefix and address_suffix
while True:
network_a_master.update()
if network_a_master.available():
recv_frame = network_a_master.read()
print(
"received {}: {}".format(
recv_frame.header.to_string(), recv_frame.message.decode()
)
)
# emit frames as needed
from circuitpython_nrf24l01.rf24_network import RF24Network
# ... declare SPI_BUS, CE_PIN, and CSN_PIN objects
network_b_master = RF24Network(SPI_BUS, CSN_PIN, CE_PIN, 0)
# let network_b use different values for address_prefix and address_suffix
network_b_master.address_prefix = bytearray([0xDB])
network_b_master.address_suffix = bytearray([0xDD, 0x99, 0xB6, 0xD9, 0x9D, 0x66])
# re-assign the node_address for the different physical addresses to be used
network_b_master.node_address = 0
while True:
network_b_master.update()
if network_b_master.available():
recv_frame = network_b_master.read()
print(
"received {}: {}".format(
recv_frame.header.to_string(), recv_frame.message.decode()
)
)
# emit frames as needed
from circuitpython_nrf24l01.rf24_network import RF24Network
# ... declare SPI_BUS, CE_PIN, and CSN_PIN objects
network_b_node = RF24Network(SPI_BUS, CSN_PIN, CE_PIN, 5)
network_a_node = RF24Network(SPI_BUS, CSN_PIN, CE_PIN, 1)
# let network_b use different values for address_prefix and address_suffix
with network_b_node as net_b:
net_b.address_prefix = bytearray([0xDB])
net_b.address_suffix = bytearray([0xDD, 0x99, 0xB6, 0xD9, 0x9D, 0x66])
# re-assign the node_address for the different physical addresses to be used
net_b.node_address = 5
while True:
# do something with network_a
with network_a_node as net_a:
net_a.update()
net_a.send(RF24NetworkHeader(0, "T"), b"data for net A master")
# do something with network_b
with network_b_node as net_b:
net_b.update()
net_b.send(RF24NetworkHeader(0, "T"), b"data for net B master")