Skip to content

BLE publishes: no lost packets, no per-packet copy, a byte limit on the queue - #12

Merged
robdobsn merged 2 commits into
mainfrom
fix/ble-publish-large-msgs
Oct 25, 2026
Merged

robdobsn merged 2 commits into
mainfrom
fix/ble-publish-large-msgs

Conversation

@robdobsn

@robdobsn robdobsn commented Oct 25, 2026 •

Copy link
Copy Markdown
Owner

Live camera frames over BLE never arrived in the dashboard ("Waiting for frames..."), and the main loop was held for 30-40 ms while frames were published.

Changes

  • Lost packets with notifications: when NimBLE's buffer pool was used up, ble_hs_mbuf_from_flat() returned null and that was passed to ble_gatts_notify_custom(). NimBLE takes a null buffer to mean "send the characteristic's value" (empty here) and reports success, so the packet was silently lost and the message failed its HDLC CRC at the central. It is now sent again later and counted (txNoBuf in the BLEMan stats). This is the cause of the earlier finding that notifications of 4 KB or more lost a packet.
  • Copying: each packet sent copied the whole queued message (under the queue lock). The packet is now copied out with peekWith, and messages are moved into the queue. A message just encoded for sending (RaftCore's isBufTakeable()) has its buffer taken rather than copied.
  • Byte limit on the publish queue: pubQMaxBytes (default 32768). One message may go over it, so a larger message is still sent when the queue is empty.
  • The send position is 32-bit (16-bit broke messages of 64 KB or more, e.g. UXGA frames).
  • Log flood: StatePublisher asks again each loop while the queue is full, and each refusal was counted as a drop and logged (about 300 lines a second). A drop (pubDrpOp) is now counted once each time the queue fills, and the warning ("PUBLISH QUEUE FULL") is limited to one a second, with the number of refusals.

Depends on robdobsn/RaftCore#31 (const ProtocolRawMsg::getBuf()/getBufLen(), takeBuffer() and CommsChannelMsg::isBufTakeable()).

Tested

Plant growth board (ESP32-S3, OV2640), raftjs dashboard live view over BLE from Windows:

Before After
Live view no frames frames arrive
Longest loop 36-41 ms about 7 ms
Longest publish 36 ms about 5.5 ms (10 KB frames)
Average loop about 5 ms 1-2 ms
SLOW warnings many none
PUBLISH warnings about 300/s 1/s

txNoBuf counted 30-75 a second: each of those packets would have been lost before.

🤖 Generated with Claude Code

…byte limit

- A null buffer from ble_hs_mbuf_from_flat() (NimBLE's pool used up, which notifications sent faster than the
  link takes them do) was passed on: NimBLE takes a null buffer to mean "send the characteristic's value", which
  is empty, and reports success, so the packet was lost from the message and its HDLC CRC failed at the central.
  It is now sent again later, and counted (txNoBuf in the stats). This was the loss seen with notifications of
  messages of 4 KB or more.
- Each packet sent copied the whole message out of the queue (and held the queue locked meanwhile) - over 1.5 MB
  of copying for a 28 KB camera frame, and loops of 10-15 ms. The packet is now copied out with peekWith, and
  messages are moved into the queue rather than copied again.
- The publish queue also has a byte limit (pubQMaxBytes, default 32 KB): limited only by count, large messages
  piled up for many seconds of link time.
- The position in the message being sent is 32 bits (16 bits broke messages of 64 KB or more).
- Publishes refused while the queue is full are counted once each time it fills, and the warning is limited to
  one a second (a publisher asks again each loop, which logged hundreds of lines a second).

Needs RaftCore's const ProtocolRawMsg::getBuf()/getBufLen().

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A message whose buffer may be taken (RaftCore's CommsChannelMsg::isBufTakeable(), set on a RICREST message just
encoded for sending) is queued without copying - one less copy of each camera frame published. Other messages
are copied as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@robdobsn
robdobsn merged commit e05ccbb into main Oct 25, 2026
1 check passed
@robdobsn
robdobsn deleted the fix/ble-publish-large-msgs branch October 25, 2026 17:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant