This module wraps the BTstack GAP APIs with C++ classes and event handlers. It is designed for embedded BLE peripherals where advertising and connection state are managed by a single owner.
Core Classes
c7222::Gap (libs/elec_c7222/ble/gap/include/gap.hpp)
- Singleton wrapper for BTstack GAP.
- Owns advertising parameters/data, scan response data, and connection state.
- Parses HCI events and dispatches them to registered
c7222::Gap::EventHandler instances.
- Provides legacy advertising configuration and convenience builders.
c7222::Gap::EventHandler
- Event interface for advertising start/stop, connection/disconnection, and scan reports.
- Stored as raw pointers; handlers must outlive the
Gap instance.
Utility Types Used by GAP
Design Principles
- Singleton ownership: GAP is a singleton because the controller exposes a single GAP state machine.
- Event‑driven: The module relies on HCI event dispatch to drive state and user callbacks.
- Thin wrapper: GAP retains BTstack semantics; it does not hide advertising or connection details.
- Runtime configurability: Advertising data and parameters can be updated without rebooting.
Assumed Usage Scenarios
- Embedded BLE peripheral that advertises a custom service and accepts a single connection.
- Applications that need to update advertising/scan response data based on runtime state (sensor readings, device name updates, etc.).
Event Dispatch Requirement
Your platform glue must forward HCI packets to c7222::Gap::DispatchBleHciPacket() (or via c7222::Ble::DispatchBleHciPacket() which fans out to GAP). Without this, callbacks will never fire.
Event Handling in Detail
How to Register
- Implement
c7222::Gap::EventHandler and override the callbacks you need.
- Register with
c7222::Gap::AddEventHandler(handler) before calling c7222::Ble::TurnOn() or starting advertising.
- Handlers are stored as raw pointers. The handler object must outlive the
Gap singleton.
When Handlers Are Called
Handlers are invoked when GAP‑related HCI events are dispatched into c7222::Gap::DispatchBleHciPacket() (directly or via c7222::Ble::DispatchBleHciPacket()):
- Advertising start/stop status
- Connection complete and disconnection events
- Advertising reports (scanning events) when enabled on the controller
- Connection parameter updates (if supported by the platform glue)
If the platform layer does not forward HCI events, handlers will never be called.
What Type of Objects Are Passed
c7222::Gap::EventHandler callbacks receive strongly‑typed values such as:
These are plain value types or references to stack‑owned buffers that are only valid during the callback.
Multiple Handlers
- You can register more than one handler with
c7222::Gap::AddEventHandler().
- Internally, the module stores a list of handler pointers and iterates through them in registration order.
- All registered handlers receive the event; no handler short‑circuits the others.
- You can remove a handler with
c7222::Gap::RemoveEventHandler() if needed.
Typical Pattern
public:
uint16_t, uint16_t, uint16_t) const override {
(void)handle;
if (status == 0) {
}
}
};
static MyGapHandler handler;
gap.AddEventHandler(handler);
BLE address container with an associated address type.
Definition ble_address.hpp:43
static Gap * GetInstance()
Get the singleton instance.
uint16_t ConnectionHandle
Definition gap.hpp:23
virtual void OnConnectionComplete(uint8_t status, ConnectionHandle con_handle, const BleAddress &address, uint16_t conn_interval, uint16_t conn_latency, uint16_t supervision_timeout) const
Definition gap.hpp:741
Why This Event Handler Design
The GAP module uses an OOP event handler interface instead of a flat list of function pointers or free‑function callbacks for practical embedded reasons:
- Cohesive state: A handler can hold state (counters, configuration, references) without global variables. This keeps GAP‑related logic together and testable.
- Multiple listeners: A list of handler objects allows more than one subsystem to observe the same event stream (e.g., logging + application logic) without a custom multiplexer.
- Extensibility: Adding new events only requires adding virtual methods with default no‑ops, preserving source compatibility for existing handlers.
- Lifecycle clarity: Handlers are registered and removed explicitly, which is easier to reason about than scattered callback function pointers.
- Consistent API: The same pattern is used for GAP, GATT, and Security Manager, reducing cognitive load and integration mistakes.
Alternative designs (global function callbacks, single function pointer tables, or switch‑based dispatch) are smaller but become harder to scale as events grow, and they complicate multi‑consumer use cases. The OOP approach is a deliberate tradeoff favoring maintainability and composability.
Advertisement Data Types and Builders
AdvertisementData (AD Structure)
c7222::AdvertisementData represents a single AD structure: a length byte, a type byte, and a payload. This is the unit the BLE controller expects inside the 31‑byte legacy advertising payload.
Key ideas:
- One AD structure per instance. The class builds
length + type + value into a contiguous byte vector.
- Type‑safe payload construction. Overloads accept:
std::vector<uint8_t> for raw payload bytes.
- Pointer to a concrete POD object (payload is
sizeof(T)).
- Pointer + count for arrays of POD objects.
- Reference to a concrete object (payload is
sizeof(T)).
- Type identification. The AD type is one of
AdvertisementDataType (Flags, Local Name, Manufacturer Specific, etc.).
This class is not the full advertising payload; it is a single fragment you can combine with others.
AdvertisementDataBuilder (Payload Builder)
c7222::AdvertisementDataBuilder assembles multiple AdvertisementData objects into a complete advertising payload and enforces the 31‑byte legacy limit.
Key behaviors:
- Add / ReplaceOrAdd. You can add multiple AD structures or replace an existing one of the same type.
- Validation. The builder validates total size and AD structure correctness.
- Build + decode. It can also decode a raw payload back into AD structures for inspection.
- Uniqueness enforcement.
operator+= and merge operators assert if duplicate AD structures are added.
How They Interact
- Build one or more
AdvertisementData structures (flags, name, manufacturer data, etc.).
- Add them to an
AdvertisementDataBuilder.
- Pass the builder to
c7222::Gap::SetAdvertisingData() or c7222::Gap::SetScanResponseData().
Runtime Configuration Updates
The Gap class supports live updates to advertising and scan response data. When you call:
SetAdvertisingData(...)
SetScanResponseData(...)
the implementation copies the payload into local storage and then forwards it to BTstack. On the Pico port:
SetAdvertisingData(...) applies the new advertising payload directly.
SetScanResponseData(...) stops and restarts advertising if needed before applying the new scan response payload.
This means scan response updates preserve the previous advertising state automatically, while advertising data updates are pushed without an explicit stop/start cycle in the wrapper.
Typical Flow
gap.SetAdvertisingData(ad);
gap.StartAdvertising();
Builder for assembling a complete advertising payload.
Definition advertisement_data.hpp:304
@ kLeGeneralDiscoverableMode
Updating While Advertising
gap.SetAdvertisingData(ad);
Basic Types and Payload Support
AdvertisementData supports:
- Flags: using
c7222::AdvertisementData::Flags bitmask (discoverable mode, BR/EDR not supported, etc.).
- Local Names: shortened or complete, as UTF‑8 strings.
- Manufacturer Specific Data: raw bytes (company ID + payload).
- Service Data: raw bytes for 16‑bit UUID service data.
- Custom binary payloads: via POD structs or raw byte buffers.
These are all represented as AD structures with a specific AdvertisementDataType and a payload you supply.
Example
const uint8_t flags = static_cast<uint8_t>(
const std::string name = "PicoW-BLE";
reinterpret_cast<const uint8_t*>(name.data()),
name.size());
gap.SetAdvertisingData(builder);
bool Add(const std::list< AdvertisementData > &ads)
Add a list of AD structures to the payload.
Generic advertisement data structure builder.
Definition advertisement_data.hpp:46