|
ELEC-C7222
Libraries for ELEC C7222 Course Work
|
This document provides a full reference for defining, generating, and integrating BLE GATT services on the Raspberry Pi Pico using the BTstack framework. It assumes you are comfortable with embedded C/C++, binary layouts, and the BLE ATT/GATT model.
BTstack uses a simplified comma-separated values (CSV) Domain Specific Language to define the Attribute Protocol (ATT) database. Files are typically stored in:
libs/elec_c7222/ble/gatt/platform/rpi_pico/services/custom/.
// are comments.#import <name.gatt> loads built-in BTstack service definitions.#import "name.gatt" loads a local .gatt alongside your file."Pico") or space-separated hex bytes (01 02 03).bluetooth_gatt.h).| Keyword | Syntax | Description |
|---|---|---|
| PRIMARY_SERVICE | PRIMARY_SERVICE, <uuid> | Starts a new Primary Service. |
| SECONDARY_SERVICE | SECONDARY_SERVICE, <uuid> | Starts a Secondary Service. |
| INCLUDE_SERVICE | INCLUDE_SERVICE, <uuid> | Includes a previously defined service by UUID (uses its handle range). |
| CHARACTERISTIC | CHARACTERISTIC, <uuid>, <properties>, <value> | Defines a characteristic declaration + value (declaration + value handle). |
| CHARACTERISTIC_USER_DESCRIPTION | CHARACTERISTIC_USER_DESCRIPTION, <properties> | Adds the 0x2901 descriptor (dynamic descriptor in BTstack). |
| CLIENT_CHARACTERISTIC_CONFIGURATION | CLIENT_CHARACTERISTIC_CONFIGURATION | Reserved token; CCCD is auto-added when NOTIFY/INDICATE is set. |
| SERVER_CHARACTERISTIC_CONFIGURATION | SERVER_CHARACTERISTIC_CONFIGURATION, <properties> | Adds the 0x2903 SCCD descriptor (dynamic). |
| CHARACTERISTIC_FORMAT | CHARACTERISTIC_FORMAT, <id>, <format>, <exponent>, <unit_uuid>, <namespace>, <description_uuid> | Adds the 0x2904 presentation format descriptor. |
| CHARACTERISTIC_AGGREGATE_FORMAT | CHARACTERISTIC_AGGREGATE_FORMAT, <id1>, <id2>, ... | Aggregates multiple presentation formats (0x2905). |
| VALID_RANGE | VALID_RANGE, <properties> | Adds 0x2906 descriptor (dynamic, read-only). |
| EXTERNAL_REPORT_REFERENCE | EXTERNAL_REPORT_REFERENCE, <properties>, <report_uuid16> | Adds 0x2907 descriptor. |
| REPORT_REFERENCE | REPORT_REFERENCE, <properties>, <report_id>, <report_type> | Adds 0x2908 descriptor. |
| NUMBER_OF_DIGITALS | NUMBER_OF_DIGITALS, <count> | Adds 0x2909 descriptor. |
| VALUE_TRIGGER_SETTING | VALUE_TRIGGER_SETTING, <properties> | Adds 0x290A descriptor (dynamic). |
| ENVIRONMENTAL_SENSING_CONFIGURATION | ENVIRONMENTAL_SENSING_CONFIGURATION, <properties> | Adds 0x290B descriptor (dynamic). |
| ENVIRONMENTAL_SENSING_MEASUREMENT | ENVIRONMENTAL_SENSING_MEASUREMENT, <properties> | Adds 0x290C descriptor (dynamic, read-only). |
| ENVIRONMENTAL_SENSING_TRIGGER_SETTING | ENVIRONMENTAL_SENSING_TRIGGER_SETTING, <properties> | Adds 0x290D descriptor (dynamic). |
Properties control how a client interacts with the data. Multiple properties are separated by the pipe | symbol.
BROADCAST, READ, WRITE_WITHOUT_RESPONSE, WRITE, NOTIFY, INDICATE, AUTHENTICATED_SIGNED_WRITE, EXTENDED_PROPERTIES.DYNAMIC (route through callbacks, no static value storage).RELIABLE_WRITE, AUTHENTICATION_REQUIRED, AUTHORIZATION_REQUIRED.READ_ANYBODY, READ_ENCRYPTED, READ_AUTHENTICATED, READ_AUTHENTICATED_SC, READ_AUTHORIZED.WRITE_ANYBODY, WRITE_ENCRYPTED, WRITE_AUTHENTICATED, WRITE_AUTHENTICATED_SC, WRITE_AUTHORIZED.ENCRYPTION_KEY_SIZE_7 through ENCRYPTION_KEY_SIZE_16.READ_PERMISSION_BIT_0, READ_PERMISSION_BIT_1, WRITE_PERMISSION_BIT_0, WRITE_PERMISSION_BIT_1, READ_PERMISSION_SC, WRITE_PERMISSION_SC.CHARACTERISTIC, 2A29, READ, "Manufacturer Name"CHARACTERISTIC, 2A04, READ, 06 00 08 00 (Connection Parameters)CHARACTERISTIC, FF01, READ | DYNAMIC, (Value is provided by C++ logic)BTstack lets you use well-known service/characteristic UUIDs as named tokens instead of raw hex. These come from the assigned numbers list in bluetooth_gatt.h.
Example:
BTstack’s docs also outline a practical way to build services from official Bluetooth SIG profile specs:
https://www.bluetooth.com/specifications/specs/ (or the GATT XML listing)..gatt entries:PRIMARY_SERVICECHARACTERISTIC.gatt descriptor keywords.gatt file and generate the header with compile_gatt.py.BTstack’s documented workflow for GATT services is:
.gatt file that defines your services/characteristics.compile_gatt.py (directly or via CMake) to generate a header containing the ATT DB blob (profile_data/att_db).att_server_init(...) and register your read/write callbacks.*_init(...) functions after registering the ATT DB.att_server_notify(...) / att_server_indicate(...) to send updates to subscribed clients.Add your service definition under services/custom/your_service.gatt. In CMakeLists.txt (after pico_sdk_init()):
Run from the repository root to generate the header for manual inspection or check-in:
The project uses a custom C++ layer to wrap the raw BTstack ATT callbacks into an object-oriented structure.
AttributeServer (libs/elec_c7222/ble/gatt/include/attribute_server.hpp)Service list.att_db blob).Characteristic or service-level Attribute handlers.Service (libs/elec_c7222/ble/gatt/include/service.hpp)Attribute, optional Included Service Declarations, and a list of Characteristic objects.ParseFromAttributes() consumes the ordered attribute list and builds services in discovery order.Characteristic (libs/elec_c7222/ble/gatt/include/characteristic.hpp)Attribute, Value Attribute, and optional descriptors (CCCD, SCCD, User Description, Extended Properties, and custom descriptors).EventHandlers for high-level application callbacks.Attribute (libs/elec_c7222/ble/gatt/include/attribute.hpp)std::vector storage.compile_gatt.py produces a binary array att_db. c7222::AttributeServer::Init (libs/elec_c7222/ble/gatt/platform/rpi_pico/attribute_server.cpp) receives this pointer and registers it with the BTstack core via att_server_init(...).db + 1 (BTstack reserves the first byte).entry_size (uint16, little-endian). A size of 0 terminates the list.flags (uint16), handle (uint16), then UUID (2 or 16 bytes).ParseEntry() constructs an Attribute from (uuid, flags, value_ptr, value_len, handle).InitServices() calls c7222::Service::ParseFromAttributes(), which walks the ordered list.c7222::Characteristic::ParseFromAttributes() groups:att_read_callback / att_write_callback.AttributeServer finds the matching handle:Characteristic, it calls c7222::Characteristic::HandleAttributeRead/Write().c7222::Attribute::InvokeRead/WriteCallback().BleError back to BTstack ATT error codes.There are two main handler families: low-level attribute callbacks and high-level characteristic events.
1) Attribute callbacks (data access + validation)
Registered on Attribute instances:
c7222::Attribute::SetReadCallback(ReadCallback) c7222::Attribute::SetWriteCallback(WriteCallback) Where used:
Notes:
InvokeReadCallback() returns stored bytes for static or dynamic attributes.BleError.2) Characteristic EventHandlers (semantic events)
Registered via c7222::Characteristic::AddEventHandler(EventHandlers&):
OnUpdatesEnabled(bool is_indication) / OnUpdatesDisabled() OnBroadcastEnabled() / OnBroadcastDisabled() OnRead() SetValue().OnWrite(const std::vector<uint8_t>& data) OnIndicationComplete(uint8_t status) / OnConfirmationReceived(bool status) DispatchBleHciPacket() being fed HCI packets.Notes:
SetReadCallback()/SetWriteCallback(), the default handlers (and therefore OnRead/OnWrite) are bypassed.