Bluetooth Low Energy (BLE)

BLE is a thin class: new BLE('name') carries the advertised device name, the GATT database is declared with service()/char() chains, and every verb maps onto Zephyr’s own bt_* calls (the NimBLE-derived stack). Handlers bind to the characteristic they immediately follow in the chain — declare them right where the characteristic is declared.

BLE requires a board with a BLE radio and Zephyr board support for it; the Seeed XIAO nRF52840 (xiao_ble target) is the primary target.


Advertising a GATT server

Minimum server

Construct the peripheral, declare one readable characteristic with its read handler, and start:

import { BLE, BleValueType, BlePerm, Time } from '@typecad/hal';
import { UART0 } from '@typecad/board';

const ble = new BLE('TempSensor');

ble.char('2A6E', BleValueType.Int16, BlePerm.Read)
   .onRead(() => 2180);      // 21.80 °C — int16, 0.01 °C units per GATT 2A6E

ble.start();                 // register the database, enable the stack, advertise

while (true) {
  Time.sleep(1000);
}

char() without a preceding service() attaches to the default Environmental Sensing service — the common single-service case.

Multiple services and characteristics

Chain declarations; each service() begins a grouping, and each char() appends to the most recent one:

ble.service('180F')                          // Battery Service
   .char('2A19', BleValueType.Uint8, BlePerm.Read | BlePerm.Notify)
   .onRead(() => batteryPercent());

ble.notify(0, batteryPercent());             // push to subscribers — index is
                                             // declaration order, 0-based

Read and write handlers:

ble.service('180A')
   .char('2A56', BleValueType.Int32, BlePerm.Write)
   .onWrite((value) => { setpoint = value; });

Permissions and value types

BlePerm flags combine with |: Read, Write, Notify. Value types are BleValueType.Int8/Int16/Int32/Uint8/Uint16/Uint32 — pick the GATT spec’s type for the characteristic you implement.

Connection events

ble.onConnect(() => UART0.writeLine('central connected'));
ble.onDrop(() => UART0.writeLine('central disconnected'));   // advertising stays armed

linked() is true while a central is connected; clients() reports the count (the shim is single-connection, so 0 or 1). stop() stops advertising; the database and any link stay up.


API Reference

MemberDescription
new BLE(name)Construct the peripheral; the name is the advertised identity.
service(uuid)Begin a service grouping for subsequent char() calls.
char(uuid, type, perms)Append a characteristic (to the default service when no service() precedes it).
.onRead(fn) / .onWrite(fn)Handlers for the most recently declared characteristic; chainable.
start()Register the GATT database, enable the stack, begin advertising.
stop()Stop advertising.
linked() / clients()Connection state and count.
onConnect(fn) / onDrop(fn)Connection callbacks.
notify(index, value)Push a value to subscribers — index is declaration order (0-based).