macro_rules! gatt_services {
(@uuid_ptr $uuid:expr) => { ... };
(@chr $uuid:expr, $($flag:ident)|+ ) => { ... };
(@primary primary) => { ... };
(@primary secondary) => { ... };
(@unit $_t:expr) => { ... };
(
$vis:vis $NAME:ident {
$(
$kind:ident ( $svc_uuid:expr ) {
$( chr ( $chr_uuid:expr, $($flag:ident)|+ ) ; )*
}
)+
}
) => { ... };
}Expand description
Define a static (compile-time, heap-free) GATT service table.
Expands to a static NAME holding the null-terminated NimBLE ble_gatt_svc_def tree (services,
characteristics, UUIDs), all in flash. Pass &NAME to
new_with_services. Reads and writes are serviced
the same way as the runtime table — through the single
gatts_subscribe hook, keyed by the value handle
reported in the Register events (so learn handles there, exactly as the runtime example does).
Each UUID slot is any const BleUuid expression — declare your UUIDs as
const FOO: BleUuid = BleUuid::uuid128(..) (or uuid16) and name them. Characteristic flags are
any |-separated BleGattCharFlag variants (Read,
Write, Notify, Indicate). Services are primary(..) or secondary(..).
The NAME and the body live inside the one macro group (a macro invocation is a single token
tree), so it reads gatt_services!(NAME { .. }); — use !{ .. } to drop the trailing ;.
use esp_idf_svc::ble::BleUuid;
use esp_idf_svc::gatt_services;
const SVC: BleUuid = BleUuid::uuid128(0xad91b201_73474047_9e173bed_82d75f9d);
const RECV: BleUuid = BleUuid::uuid128(0xb6fccb50_87be44f3_ae22f854_85ea42c4);
const HR: BleUuid = BleUuid::uuid16(0x2A37);
gatt_services!(SERVICES {
primary(SVC) {
chr(RECV, Write);
chr(HR, Notify | Indicate);
}
});
// ... let driver = BleDriver::new_with_services(modem, &SERVICES)?;