Bluetooth Mesh Friendship: Match Low-Power Polling to the Friend Queue Contract
A low-power node can keep a valid friendship while losing queued application messages. PollTimeout limits friendship inactivity; it does not promise that every message will remain buffered until the next poll. Design polling around both the Friend Queue and the application’s freshness requirement.
Applicability: Bluetooth Mesh Protocol 1.1 friendship, with Zephyr 4.2.0 source as an implementation example. The timing and queue examples are hypothetical, and no mesh, current measurement or packet-loss experiment was run. Ordinary connected-BLE peripheral latency is outside this procedure.

1. Record what the Friend actually offers
The Friend Request and Friend Offer definitions distinguish requested criteria from offered resources. Record the selected Friend address, subnet, ReceiveDelay, ReceiveWindow, PollTimeout, QueueSize and SubscriptionListSize. Preserve the friendship generation alongside those values.
MinQueueSizeLog expresses a minimum number of maximum-size Lower Transport PDUs through a logarithmic field. It is not a requested number of arbitrary application transactions. A segmented transaction can consume several stored PDUs, and control traffic also needs space.
In Zephyr 4.2.0 friend.c, the offer uses CONFIG_BT_MESH_FRIEND_QUEUE_SIZE and CONFIG_BT_MESH_FRIEND_RECV_WIN. Record the actual build and offer rather than copying another board’s settings. The source also keeps a last-sent buffer separately; internal allocation counts must not be confused with the advertised queue contract.
Friend selection completes through the protocol exchange. On the low-power side, receiving the expected Friend Update after the initial poll establishes friendship. Merely hearing a strong Friend Offer is insufficient readiness evidence.
2. Keep the response window separate from inactivity timeout
ReceiveDelay and ReceiveWindow describe when the Friend responds after receiving a request. PollTimeout describes how long the friendship may remain without the required communication. These are different timers with different failure consequences.
For a hypothetical ReceiveDelay of 100 ms and ReceiveWindow of 20 ms, the Friend response is constrained by the protocol’s minimum-delay and maximum-delay-plus-window boundaries relative to reception of the Friend Poll. This is not a guarantee that application processing finishes within 120 ms of a user action.
Choose the normal poll schedule with margin for clock error, scheduling delay and supported retries before PollTimeout. A schedule placed exactly on the timeout boundary is not robust. Verify units when decoding the request: PollTimeout uses 100 ms units, unlike the millisecond ReceiveDelay field.
The low-power node should generally keep polling until Friend Update reports MD=0. One successful poll is not proof that all pending work was drained. Conversely, an empty queue says nothing about whether earlier entries were evicted.
3. Understand the FSN acknowledgment boundary
The stack owns the one-bit Friend Sequence Number. A repeated poll with the same FSN requests the previously sent message again, unless that message has been discarded; then the Friend sends the oldest remaining queue entry.
After receiving a nonduplicate response, the low-power node toggles its FSN. A subsequent poll with the changed FSN acknowledges progress and requests the next message. A missing response does not justify toggling forward and skipping the pending item.
The tagged Friend implementation checks equal FSN plus a retained last buffer to resend that buffer. The low-power implementation manages polling and reception state. Use supported stack callbacks and traces instead of inventing application-level FSN control.
This protocol acknowledgment is not proof that the application committed a consequential action. If the product needs command completion, define a separate model or application response and idempotency policy.
4. Test overflow independently of friendship expiry
Section 3.5.5 defines a Friend Queue per low-power node. When room is needed for a new non-Friend-Update message, the oldest entries other than Friend Update are discarded. A valid friendship can therefore retain newer messages while silently losing older application history at this layer.
Consider a simplified fixture with four available slots, six equal unsegmented data entries A–F, no intervening drain and no competing control entry. In arrival order, A and B are evicted and C–F remain. This illustrates FIFO pressure; it is not a claim that every QueueSize of four always provides four usable application slots.
For real qualification, include control messages, varying message sizes and segmented traffic. Segmented messages enter the Friend Queue only after complete reassembly at the Friend and acknowledgment of all segments. A sender’s segment acknowledgment therefore does not establish delivery to the sleeping application.
Measure the largest burst between effective drains, not only average arrival rate. Repeated response loss can delay drain progress despite frequent poll attempts. Reserve capacity for the actual protocol workload and define what the application does when sequence gaps appear.
5. Distinguish three kinds of stale state
| Boundary | Meaning | Required handling |
|---|---|---|
| Queue overflow | Friendship may survive while older entries disappear | Detect gaps and apply application recovery |
| PollTimeout expiry | Friendship terminates and queued entries are discarded | Re-establish friendship and subscriptions |
| Application deadline | A delivered command or sample is too old for its purpose | Reject or reconcile using product semantics |
The protocol also notes that an LPN should collect stored messages at least once every 96 hours because IV Index changes can cause older stored messages to be discarded. That is not a 96-hour retention guarantee: capacity, friendship termination and application age limits may be much tighter.
In the exact Zephyr Friend cleanup path, queued buffers, segment buffers and the retained last buffer are released, and subscription state is cleared. Do not treat friendship re-establishment after Friend loss as recovery of the previous queue.
6. Qualify loss and recovery with explicit outcomes
- Drop one Friend response: verify same-FSN retry and no duplicate application action.
- Inject a burst larger than available queue capacity: verify expected gaps while friendship remains established.
- Delay polling past PollTimeout: verify termination, queue loss and a new establishment sequence.
- Restart the selected Friend: verify explicit loss and re-selection, without claiming old messages were retained.
- Change a group subscription: verify the Friend Subscription List transaction and confirmation before relying on buffered group delivery.
- Deliver a valid but stale application command: verify the product’s expiry policy independently of mesh authentication.
Acceptance combines bounded energy and delivery age with visible gaps, correct retry ownership and controlled Friend-loss recovery. A low poll rate is useful only when the queue and application contracts remain satisfied.