14.3. The radio and the link layer¶
The bottom two layers of the BLE stack are almost entirely automatic from Python’s perspective – the radio silicon and the layers MicroPython runs on top of it handle everything from picking a channel to retransmitting a lost packet. Three of the choices they make still show through into the user-facing API: power, range, and throughput.
14.3.1. The radio¶
BLE uses the same 2.4 GHz Industrial-Scientific-Medical (ISM) band as Wi-Fi, microwave ovens, and most other short-range wireless. The band is split into 40 channels 2 MHz wide.
Three of the 40 channels are reserved for advertising – short broadcasts that announce a device’s presence to anyone listening. They are spaced out across the band so a listener can sweep all three quickly and so interference on any one is unlikely to knock the device off the air entirely.
Thirty-seven are data channels. Once two devices connect, they exchange packets on these, hopping between them on a pseudo-random sequence the two sides agree on at connection time. Adaptive frequency hopping lets either side mark a channel as bad (heavy Wi-Fi interference, microwave, neighbouring BLE network) so the sequence skips it.
The 40 BLE channels on the 2.4 GHz band. Three are for advertising, the rest carry traffic on an open connection.¶
The radio transmits brief packets – at most a couple of milliseconds long – and sleeps in between. That sleep is what makes the technology low energy. A typical BLE peripheral spends well under one percent of its time actually transmitting; the rest is the radio powered down between scheduled events.
14.3.2. The link layer¶
The link layer is the smallest unit of BLE that talks to its counterpart on another device. It handles four jobs.
Packet framing. Each packet carries a short header (channel access address, packet length, control bits), a payload, and a CRC. The receiver checks the CRC and drops anything corrupted.
Addressing. Every BLE device has a 48-bit device address that identifies it on the radio. Some are public – a hardware identifier the manufacturer has assigned, traceable forever. Some are random – generated on the device, rotated periodically, and optionally encrypted so that an eavesdropper cannot link two transmissions to the same physical hardware. Addresses come up again in Advertising and scanning.
Connection scheduling. Once two devices connect, the link layer schedules periodic radio events on the hopping sequence – a fixed connection interval apart – and packs whatever data is queued from the GATT layer above into each one. Both sides go back to sleep between events. The connection interval is a knob the application can request (see Connections).
Reliability. Each packet on a connection is acknowledged by the other side. The link layer retransmits anything that did not get a response, so the layers above see an ordered, lossless byte stream. Unlike UDP – send a packet, hope for the best on the networking side, BLE does not have a separate unreliable mode in normal use – every packet on an open connection is retried until it arrives or the link is declared lost.
The link layer is also where encryption runs once a pair of devices has agreed on a key during pairing (see Pairing and bonding). Every packet on an encrypted link is decrypted at the receiver before the layers above ever see it.
14.3.4. What Python sees of all this¶
Almost nothing. The bluetooth and aioble
APIs do not expose channels, hopping sequences, packet
CRCs, or retransmission timers; those are all handled
inside the BLE port and the radio. The pieces that do
show through are the ones the connection-time
negotiation exposes – connection interval, MTU,
address type.