- begin(mode, deviceName, securityMode) – Initialize BLE stack, create service & characteristics, start advertising.
- begin(mode, deviceName, securityMode, pairingPolicy) – Same as above, with explicit onboarding policy for new peers.
- end() – Stop advertising, disconnect client (if any), free resources, reset internal state.
Supported modes are Fast, LongRange, LowPower, and Balanced. Fast adapts between
2M and 1M PHY; LongRange remains coded and adapts between S=2 and S=8;
LowPower and Balanced remain on 1M. See Operation_Modes.md for connection,
MTU, power, and pacing defaults. PHY changes require consecutive filtered-RSSI
decisions and use separate downgrade and upgrade confirmation counts.
Supported security is None, JustWorks and PasskeyDisplay.
Supported pairing policies are AlwaysOpen, Windowed and BondedOnly.
- available() / readAvailable() – Bytes currently buffered in RX ring.
- read() / read(dst, n) – Pop one / up to n bytes from RX ring.
- peek() / peek(dst, n) – Inspect one / up to n bytes without consuming.
- write(b) / write(buf, n) – Reliable bounded enqueue to TX ring using the configured write timeout. Returns the actual number of bytes queued.
- write(const char*) / print(str) / println(str) – Reliable bounded text output.
println()adds CRLF only after the payload is accepted. - printf(fmt, ...) – Reliable bounded formatted print into TX ring; truncates at the local formatting buffer size.
- writeNonBlocking(...) / printfNonBlocking(fmt, ...) – Explicit non-blocking TX enqueue for high-rate streaming; may be partial if flow control blocks.
- writeTimeout(buf, n, timeoutMs) – Attempt to enqueue up to n bytes within timeout; cooperatively waits for buffer space/unlock; decoupled from in-flight notifies (pop-based staging).
- setWriteTimeoutMs(timeoutMs) / getWriteTimeoutMs() – Configure/query the
default timeout used by
write(),print(),println(), andprintf(). The default is 250 ms. - writeReady() – True if a client is subscribed and producer lock is not asserted.
- writeAvailable() – Remaining free space in TX ring (capacity - used).
- Normal Arduino
Printpaths are reliable and bounded by default.write(),print(),println(), andprintf()wait up togetWriteTimeoutMs()for TX ring space before returning a short count. - The timeout applies only to enqueueing bytes into BLESerial's TX ring. Actual BLE notification delivery remains asynchronous and is handled by the TX state machine and pump mode.
- High-rate streaming code should use
writeReady()pluswriteNonBlocking()orprintfNonBlocking()to preserve the high-water / low-water producer lock behavior without blocking the producer loop. - Always check the returned byte count. A short count means only that many bytes
were queued; the unqueued remainder is counted in
TxDropswhen the write started while subscribed.
- update() – Call periodically when in Polling pump mode (non-ESP32 or when PumpMode::Polling selected) to advance TX/RSSI logic.
- flush() – Drain queued and in-flight TX within its bounded wait. In task mode it wakes the TX worker; in polling mode it pumps locally.
- setPumpMode(Polling | Task) – Select manual loop pumping or ESP32 FreeRTOS background task. If task creation fails, the library falls back to Polling; use
getPumpMode()in the loop. - getPumpMode() – Current mode.
- Successful notifications establish the last-known-good (LKG) pacing interval. After a clean success window, bounded probes may reduce the interval toward the negotiated connection-event share.
- An isolated congestion result such as
ENOMEMcancels an active probe and returns to the exact confirmed LKG. The connection-event share is used only when no confirmed LKG exists. - General congestion must continue for at least one second before increasing the LKG. High-water congestion may react sooner, but requires at least eight consecutive high-water congestion events spanning 250 ms.
- Congestion escalation is gradual and capped at four times the computed pacing floor. After 64 successful notifications, probing may resume.
getBytesTx()is a cumulative count of successfully transmitted application payload bytes. The library does not calculate a bytes-per-second rate.
- setPreferredMTU(newMtu) – Set the local preferred ATT MTU, clamped to 23–517. Call before
begin()when possible. This does not initiate MTU exchange; a connected central negotiates the active MTU. Beforebegin()it returns configuration success; after initialization it returns the underlying NimBLE result. - getPreferredMTU() – Local ATT MTU preference used for future peer exchanges.
- requestMTU(newMtu) – Deprecated compatibility alias for
setPreferredMTU(). - setPower(dBm, scope) – Adjust transmit power for Advertising, Scanning, Connection, or All.
Security::None– No BLE pairing or link encryption required.Security::JustWorks– Encrypted bonded LE Secure Connections link without passkey entry.Security::PasskeyDisplay– Encrypted bonded connection with displayed 6-digit passkey and MITM protection.PairingPolicy::AlwaysOpen– Current/default behavior. New peers may pair whenever they connect.PairingPolicy::Windowed– New peers may pair only while a temporary pairing window is open. Bonded peers may always reconnect.PairingPolicy::BondedOnly– New peers are rejected by default. Bonded peers may reconnect. A temporary pairing window can still be opened manually.setPairingPolicy(policy)– Change onboarding policy at runtime.getPairingPolicy()– Return current onboarding policy.openPairingWindow(durationMs)– Temporarily allow new peers to pair, typically after a physical button press.closePairingWindow()– Close the temporary pairing window immediately.isPairingWindowOpen()– True while the temporary pairing window is still active.
Notes:
- Pairing policies matter only for secure modes (
JustWorks,PasskeyDisplay). WithSecurity::None, the library does not gate clients by bond state. - Existing users do not need to change code.
begin(mode, deviceName, securityMode)still behaves as before because the default pairing policy isAlwaysOpen. - Typical appliance flow: initialize with
BondedOnly, then callopenPairingWindow(60000)when a hardware button is pressed.
- setLogLevel(level) / getLogLevel() – Control the shared
UUtzinger_loggerverbosity (LOG_LEVEL_NONE,LOG_LEVEL_ERROR,LOG_LEVEL_WARN,LOG_LEVEL_INFO,LOG_LEVEL_DEBUG). A sketch may instead calllogSetLevel()directly;begin()preserves that global setting. Debug output is compiled only whenDEBUGis defined before including the logger. - setDiagnosticOutput(output) – Select the dedicated
Printdestination for BLESerial-owned diagnostics. It defaults toSerial, accepts UARTs and customPrintimplementations such as a flash-file adapter, and returnsfalsewithout changing the destination when passed the BLESerial object itself. Configure it beforebegin()and keep the supplied object alive while BLESerial may emit diagnostics. - BLESerial diagnostics do not follow the global
logSetOutput()destination. ApplicationLOG()/LOGln()output is unaffected and may target BLE. - printStats([stream]) – Emit current link, buffer, and error counters.
- isConnected() – True if a client connection is active.
- isSubscribed() – True if client subscribed to TX characteristic (notify/indicate enabled).
- getMode() – Configured operating Mode (Fast, LowPower, LongRange, Balanced).
- getMtu() – Active negotiated ATT MTU; returns 23 while disconnected.
- isEncrypted() – True if connection has active encryption.
- getPhy() – "1M", "2M", or "Coded" (current PHY).
- getChunkSize() – Current notify payload chunk size (bytes per notification attempt).
- getInterval() – Current pacing interval in microseconds between notifications.
- getLkgInterval() – Current last-known-good pacing interval (floor for probing/backoff).
- getMinInterval() – Current computed minimum viable send interval based on negotiated link parameters.
- getRSSI() – Smoothed RSSI average.
- getMac() – Device MAC address string.
- getllTxOctets() / getllTxTimeUs() – Negotiated Link Layer TX octets and DLE
maximum TX time. The maximum time is a controller capability, not actual PDU
airtime;
printStats()reports estimated TX airtime separately. - getllRxOctets() / getllRxTimeUs() – Negotiated Link Layer RX octets and DLE maximum RX time.
- getBytesTx() / getBytesRx() – Cumulative application payload bytes transmitted / received.
- getTxUsed() / getRxUsed() – Bytes currently queued in TX / RX rings.
- getTxCapacity() / getRxCapacity() – Total ring capacities.
- getTxFree() / getRxFree() – Remaining free space in TX / RX rings.
- getTxDrops() / getRxDrops() – Dropped bytes. TX drops include producer-side write timeout remainders and discarded staged TX bytes. RX drops include evicted queued bytes and received bytes beyond ring capacity.
- getLowWaterMark() / getHighWaterMark() – Current low/high water marks used for TX flow control.
- getPairingPolicy() – Current onboarding policy for new peers.
- isPairingWindowOpen() – True while new peer pairing is temporarily permitted.
- Tx state machine – Internal: transmission advances through Waiting → Staging → Pending → Recovering/Discarding based on notify outcomes
- txLocked – Internal: producer lock engaged (high-water limit reached; unlocks at low-water). Use writeReady() before writeNonBlocking()/printfNonBlocking() and check if all data was successfully written.
- setLogLevel(level) – Shared logger verbosity (defaults to Serial unless redirected with
logSetOutput());begin()does not change a sketch-selected level. - setDiagnosticOutput(output) – Dedicated BLESerial diagnostic
Print; defaults toSerialand rejects the BLESerial object itself. - setPreferredMTU(mtu) – Set the local ATT MTU preference; a central initiates any MTU exchange.
- getPreferredMTU() – Local ATT MTU preference.
- requestMTU(mtu) – Deprecated compatibility alias for
setPreferredMTU(). - getPumpMode() – Current pump mode
- setPumpMode(Polling|Task) – Polling, or ESP32 task mode which runs a background FreeRTOS TX pump; task creation failure falls back to Polling
- setPower() – sets power level for Advertising, Scanning or Connection
- setInterval(interval) – sets transmission interval in microseconds, auto adjusted during runtime
- getInterval() – current pacing interval (µs)
- setWriteTimeoutMs(timeoutMs) / getWriteTimeoutMs() – default bounded wait used by
write(),print(),println(), andprintf()
- isConnected() – true if client is connected
- isSubscribed() – true if client has TX notify/indicate enabled
- getMtu() – current negotiated MTU
- getMode() – Fast, LongRange, LowPower, or Balanced
- getBytesRx() / getBytesTx() – total bytes received/sent
- getRxDrops() / getTxDrops() – dropped bytes
- getLkgInterval() / getMinInterval() – current LKG and minimum intervals (µs)
- getRSSI() – smoothed RSSI
- getMac() – device MAC address
- getTxUsed() / getRxUsed() – bytes currently buffered in TX/RX rings
- getTxCapacity() / getRxCapacity() – ring capacities
- getTxFree() / getRxFree() – free space in rings
- isEncrypted() – connection encryption status
- getllTxOctets() / getllTxTimeUs() / getllRxOctets() / getllRxTimeUs() – link-layer negotiated octets/time
- getChunkSize() – current notify payload chunk size
- getPhy() – "1M", "2M", or "Coded"
- setOnClientConnect(cb(addr)) – your custom hook
- setOnClientDisconnect(cb(addr, reason)) – your custom hook
- setOnMtuChanged(cb(mtu)) – your custom hook
- setOnSubscribeChanged(cb(subscribed)) – your custom hook
- setOnDataReceived(cb(data, len)) – your custom hook;
datais valid only during the callback, so copy it if it must be retained - setOnRxOverflow(cb(lost)) – called with the number of received or queued bytes the RX ring could not retain
- Hooks are additive: your callbacks do not replace internal logic; they run after built-in handling. Keep them fast or defer heavy work to your loop/task.
- Pump mode: On ESP32, Task mode uses a FreeRTOS background TX pump; in Polling mode, call update() regularly from loop().