Files
esp32-racer/software/zig_main/imports/nimble.zig

159 lines
5.2 KiB
Zig

// NimBLE wrapper — requires CONFIG_BT_NIMBLE_ENABLED in sdkconfig.
//
// Enable via:
// idf.py menuconfig → Component config → Bluetooth → NimBLE
//
// When enabled, re-run `idf.py reconfigure` to regenerate the bindings.
// NimBLE symbols (ble_hs_*, ble_gap_*, ble_gatt_*) will appear in idf-sys.zig.
const sys = @import("sys");
comptime {
if (!@hasDecl(sys, "CONFIG_BT_NIMBLE_ENABLED"))
@compileError(
\\NimBLE is not enabled. Enable it via:
\\ idf.py menuconfig → Component config → Bluetooth
\\ → Host → NimBLE - BLE stack
\\Then run: idf.py reconfigure
);
}
// ---------------------------------------------------------------------------
// NimBLE type aliases (available only when CONFIG_BT_NIMBLE_ENABLED=y)
// ---------------------------------------------------------------------------
pub const HsCfg = sys.ble_hs_cfg_t;
pub const GapConnDesc = sys.ble_gap_conn_desc;
pub const GapAdvParams = sys.ble_gap_adv_params;
pub const GapConnParams = sys.ble_gap_conn_params;
pub const GattSvcDef = sys.ble_gatt_svc_def;
pub const GattCharDef = sys.ble_gatt_chr_def;
pub const GattDscrDef = sys.ble_gatt_dsc_def;
pub const Uuid16 = sys.ble_uuid16_t;
pub const Uuid128 = sys.ble_uuid128_t;
// ---------------------------------------------------------------------------
// Host stack
// ---------------------------------------------------------------------------
pub const Host = struct {
/// Initialize the NimBLE host stack (call before syncing).
pub fn init() void {
sys.nimble_port_init();
}
/// Start the NimBLE host task.
pub fn run() void {
sys.nimble_port_run();
}
/// Free task resources (call from host task on exit).
pub fn freeThenResume() void {
sys.nimble_port_freertos_deinit();
}
};
// ---------------------------------------------------------------------------
// GAP (Generic Access Profile)
// ---------------------------------------------------------------------------
pub const Gap = struct {
pub const AdvType = sys.ble_gap_adv_type;
pub const EventCb = sys.ble_gap_event_fn;
pub fn setDeviceName(name: [*:0]const u8) !void {
const rc = sys.ble_svc_gap_device_name_set(name);
if (rc != 0) return error.NimbleError;
}
pub fn advStart(
own_addr_type: u8,
direct_addr: ?*const sys.ble_addr_t,
duration_ms: i32,
params: ?*const GapAdvParams,
cb: ?EventCb,
cb_arg: ?*anyopaque,
) !void {
const rc = sys.ble_gap_adv_start(own_addr_type, direct_addr, duration_ms, params, cb, cb_arg);
if (rc != 0) return error.NimbleError;
}
pub fn advStop() !void {
const rc = sys.ble_gap_adv_stop();
if (rc != 0) return error.NimbleError;
}
pub fn connect(
own_addr_type: u8,
peer_addr: *const sys.ble_addr_t,
duration_ms: i32,
params: ?*const GapConnParams,
cb: EventCb,
cb_arg: ?*anyopaque,
) !void {
const rc = sys.ble_gap_connect(own_addr_type, peer_addr, duration_ms, params, cb, cb_arg);
if (rc != 0) return error.NimbleError;
}
pub fn terminate(conn_handle: u16, hci_reason: u8) !void {
const rc = sys.ble_gap_terminate(conn_handle, hci_reason);
if (rc != 0) return error.NimbleError;
}
};
// ---------------------------------------------------------------------------
// GATT Server
// ---------------------------------------------------------------------------
pub const GattServer = struct {
pub fn registerSvcs(svcs: []const GattSvcDef) !void {
const rc = sys.ble_gatts_add_svcs(svcs.ptr);
if (rc != 0) return error.NimbleError;
}
pub fn count(svcs: []const GattSvcDef, out: *sys.ble_gatt_svc_def_iter) !void {
_ = svcs;
_ = out;
}
pub fn notify(conn_handle: u16, attr_handle: u16) !void {
const rc = sys.ble_gatts_notify(conn_handle, attr_handle);
if (rc != 0) return error.NimbleError;
}
pub fn indicate(conn_handle: u16, attr_handle: u16) !void {
const rc = sys.ble_gatts_indicate(conn_handle, attr_handle);
if (rc != 0) return error.NimbleError;
}
};
// ---------------------------------------------------------------------------
// Advertising data builder (OOP API)
// ---------------------------------------------------------------------------
pub const AdvFields = struct {
fields: sys.ble_hs_adv_fields = .{},
pub fn setFlags(self: *AdvFields, flags: u8) void {
self.fields.flags = flags;
self.fields.flags_is_present = 1;
}
pub fn setName(self: *AdvFields, name: [*:0]const u8, complete: bool) void {
self.fields.name = name;
self.fields.name_len = @intCast(std.mem.len(name));
self.fields.name_is_complete = @intFromBool(complete);
}
pub fn setTxPwrLvl(self: *AdvFields, level: i8) void {
self.fields.tx_pwr_lvl = level;
self.fields.tx_pwr_lvl_is_present = 1;
}
pub fn build(self: *AdvFields, buf: []u8, out_len: *u8) !void {
const rc = sys.ble_hs_adv_set_fields(&self.fields, buf.ptr, out_len, @intCast(buf.len));
if (rc != 0) return error.NimbleError;
}
};
const std = @import("std");