generated from sirlilpanda/kicad-project-template-actionless
521 lines
18 KiB
Zig
521 lines
18 KiB
Zig
const sys = @import("sys");
|
|
const errors = @import("error");
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Shim — BT_CONTROLLER_INIT_CONFIG_DEFAULT() macro cannot be translated by
|
|
// zig translate-c; placeholder.c exposes it as a regular C function.
|
|
// ---------------------------------------------------------------------------
|
|
extern fn zig_bt_controller_default_cfg() sys.esp_bt_controller_config_t;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// BT mode
|
|
// ---------------------------------------------------------------------------
|
|
|
|
pub const Mode = enum(sys.esp_bt_mode_t) {
|
|
idle = sys.ESP_BT_MODE_IDLE,
|
|
ble = sys.ESP_BT_MODE_BLE,
|
|
classic = sys.ESP_BT_MODE_CLASSIC_BT,
|
|
dual = sys.ESP_BT_MODE_BTDM,
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// BLE power
|
|
// ---------------------------------------------------------------------------
|
|
|
|
pub const PowerType = sys.esp_ble_power_type_t;
|
|
pub const PowerLevel = sys.esp_power_level_t;
|
|
|
|
pub fn txPowerSet(power_type: PowerType, level: PowerLevel) !void {
|
|
try errors.espCheckError(sys.esp_ble_tx_power_set(power_type, level));
|
|
}
|
|
|
|
pub fn txPowerGet(power_type: PowerType) PowerLevel {
|
|
return sys.esp_ble_tx_power_get(power_type);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Controller lifecycle
|
|
// ---------------------------------------------------------------------------
|
|
|
|
pub const Controller = struct {
|
|
/// Return the default controller config.
|
|
/// Wraps the BT_CONTROLLER_INIT_CONFIG_DEFAULT() macro via a static
|
|
/// inline C function in include/bt_stubs.h (translated by translate-c).
|
|
pub fn defaultConfig() sys.esp_bt_controller_config_t {
|
|
return sys.zig_bt_controller_default_cfg();
|
|
}
|
|
|
|
pub fn init(cfg: *sys.esp_bt_controller_config_t) !void {
|
|
try errors.espCheckError(sys.esp_bt_controller_init(cfg));
|
|
}
|
|
|
|
pub fn deinit() !void {
|
|
try errors.espCheckError(sys.esp_bt_controller_deinit());
|
|
}
|
|
|
|
pub fn enable(mode: Mode) !void {
|
|
try errors.espCheckError(sys.esp_bt_controller_enable(@intFromEnum(mode)));
|
|
}
|
|
|
|
pub fn disable() !void {
|
|
try errors.espCheckError(sys.esp_bt_controller_disable());
|
|
}
|
|
|
|
pub fn getStatus() sys.esp_bt_controller_status_t {
|
|
return sys.esp_bt_controller_get_status();
|
|
}
|
|
|
|
/// Release memory for a BT mode that won't be used (saves heap).
|
|
/// Call before `init` when only BLE or only Classic BT is needed.
|
|
pub fn memRelease(mode: Mode) !void {
|
|
try errors.espCheckError(sys.esp_bt_controller_mem_release(@intFromEnum(mode)));
|
|
}
|
|
|
|
/// Release both controller and host memory for unused BT mode.
|
|
pub fn memReleaseAll(mode: Mode) !void {
|
|
try errors.espCheckError(sys.esp_bt_mem_release(@intFromEnum(mode)));
|
|
}
|
|
|
|
pub fn sleepEnable() !void {
|
|
try errors.espCheckError(sys.esp_bt_sleep_enable());
|
|
}
|
|
|
|
pub fn sleepDisable() !void {
|
|
try errors.espCheckError(sys.esp_bt_sleep_disable());
|
|
}
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Bluedroid host stack lifecycle
|
|
// ---------------------------------------------------------------------------
|
|
|
|
pub const Bluedroid = struct {
|
|
pub fn init() !void {
|
|
try errors.espCheckError(sys.esp_bluedroid_init());
|
|
}
|
|
|
|
pub fn initWithCfg(cfg: *sys.esp_bluedroid_config_t) !void {
|
|
try errors.espCheckError(sys.esp_bluedroid_init_with_cfg(cfg));
|
|
}
|
|
|
|
pub fn deinit() !void {
|
|
try errors.espCheckError(sys.esp_bluedroid_deinit());
|
|
}
|
|
|
|
pub fn enable() !void {
|
|
try errors.espCheckError(sys.esp_bluedroid_enable());
|
|
}
|
|
|
|
pub fn disable() !void {
|
|
try errors.espCheckError(sys.esp_bluedroid_disable());
|
|
}
|
|
|
|
pub fn getStatus() sys.esp_bluedroid_status_t {
|
|
return sys.esp_bluedroid_get_status();
|
|
}
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Convenience: full BLE init / deinit sequence
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/// Initialise BT controller (BLE-only mode) + Bluedroid stack.
|
|
/// Typical call sequence for BLE applications:
|
|
/// 1. `idf.nvs.flashInitOrErase()`
|
|
/// 2. `bluetooth.bleInit()`
|
|
/// 3. Register GAP + GATT callbacks
|
|
/// 4. `bluetooth.Gap.startAdvertising(¶ms)`
|
|
pub fn bleInit() !void {
|
|
var cfg = Controller.defaultConfig();
|
|
// Release Classic BT memory — we only need BLE.
|
|
try Controller.memRelease(.classic);
|
|
try Controller.init(&cfg);
|
|
try Controller.enable(.ble);
|
|
try Bluedroid.init();
|
|
try Bluedroid.enable();
|
|
}
|
|
|
|
/// Graceful BLE teardown (reverse of `bleInit`).
|
|
pub fn bleDeinit() !void {
|
|
try Bluedroid.disable();
|
|
try Bluedroid.deinit();
|
|
try Controller.disable();
|
|
try Controller.deinit();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Device
|
|
// ---------------------------------------------------------------------------
|
|
|
|
pub const Device = struct {
|
|
/// Register a callback for generic BT device events.
|
|
pub fn registerCallback(cb: sys.esp_bt_dev_cb_t) !void {
|
|
try errors.espCheckError(sys.esp_bt_dev_register_callback(cb));
|
|
}
|
|
|
|
/// Get the local BT/BLE MAC address (6 bytes, big-endian).
|
|
pub fn getAddress() [*]const u8 {
|
|
return sys.esp_bt_dev_get_address();
|
|
}
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// GAP BLE
|
|
// ---------------------------------------------------------------------------
|
|
|
|
pub const Gap = struct {
|
|
pub const CbT = sys.esp_gap_ble_cb_t;
|
|
pub const AdvData = sys.esp_ble_adv_data_t;
|
|
pub const AdvParams = sys.esp_ble_adv_params_t;
|
|
pub const ScanParams = sys.esp_ble_scan_params_t;
|
|
pub const ConnUpdateParams = sys.esp_ble_conn_update_params_t;
|
|
pub const AddrType = sys.esp_ble_addr_type_t;
|
|
pub const SmParam = sys.esp_ble_sm_param_t;
|
|
pub const BondDev = sys.esp_ble_bond_dev_t;
|
|
|
|
pub fn registerCallback(cb: CbT) !void {
|
|
try errors.espCheckError(sys.esp_ble_gap_register_callback(cb));
|
|
}
|
|
|
|
// -- Advertising ---------------------------------------------------------
|
|
|
|
pub fn configAdvData(adv_data: *AdvData) !void {
|
|
try errors.espCheckError(sys.esp_ble_gap_config_adv_data(adv_data));
|
|
}
|
|
|
|
pub fn configAdvDataRaw(raw_data: []u8) !void {
|
|
try errors.espCheckError(sys.esp_ble_gap_config_adv_data_raw(raw_data.ptr, @intCast(raw_data.len)));
|
|
}
|
|
|
|
pub fn configScanRspDataRaw(raw_data: []u8) !void {
|
|
try errors.espCheckError(sys.esp_ble_gap_config_scan_rsp_data_raw(raw_data.ptr, @intCast(raw_data.len)));
|
|
}
|
|
|
|
pub fn startAdvertising(params: *AdvParams) !void {
|
|
try errors.espCheckError(sys.esp_ble_gap_start_advertising(params));
|
|
}
|
|
|
|
pub fn stopAdvertising() !void {
|
|
try errors.espCheckError(sys.esp_ble_gap_stop_advertising());
|
|
}
|
|
|
|
// -- Scanning ------------------------------------------------------------
|
|
|
|
pub fn setScanParams(scan_params: *ScanParams) !void {
|
|
try errors.espCheckError(sys.esp_ble_gap_set_scan_params(scan_params));
|
|
}
|
|
|
|
/// Start scanning for `duration` seconds (0 = indefinite).
|
|
pub fn startScanning(duration: u32) !void {
|
|
try errors.espCheckError(sys.esp_ble_gap_start_scanning(duration));
|
|
}
|
|
|
|
pub fn stopScanning() !void {
|
|
try errors.espCheckError(sys.esp_ble_gap_stop_scanning());
|
|
}
|
|
|
|
// -- Connection ----------------------------------------------------------
|
|
|
|
pub fn updateConnParams(params: *ConnUpdateParams) !void {
|
|
try errors.espCheckError(sys.esp_ble_gap_update_conn_params(params));
|
|
}
|
|
|
|
pub fn disconnect(remote_bda: []u8) !void {
|
|
try errors.espCheckError(sys.esp_ble_gap_disconnect(remote_bda.ptr));
|
|
}
|
|
|
|
pub fn readRssi(remote_addr: []u8) !void {
|
|
try errors.espCheckError(sys.esp_ble_gap_read_rssi(remote_addr.ptr));
|
|
}
|
|
|
|
// -- Local identity ------------------------------------------------------
|
|
|
|
pub fn setDeviceName(name: [*:0]const u8) !void {
|
|
try errors.espCheckError(sys.esp_ble_gap_set_device_name(name));
|
|
}
|
|
|
|
pub fn configLocalPrivacy(enable: bool) !void {
|
|
try errors.espCheckError(sys.esp_ble_gap_config_local_privacy(enable));
|
|
}
|
|
|
|
// -- Security ------------------------------------------------------------
|
|
|
|
pub fn setSecurityParam(param: SmParam, value: *anyopaque, len: u8) !void {
|
|
try errors.espCheckError(sys.esp_ble_gap_set_security_param(param, value, len));
|
|
}
|
|
|
|
pub fn securityReply(bd_addr: []u8, accept: bool) !void {
|
|
try errors.espCheckError(sys.esp_ble_gap_security_rsp(bd_addr.ptr, accept));
|
|
}
|
|
|
|
pub fn passkeyReply(bd_addr: []u8, accept: bool, passkey: u32) !void {
|
|
try errors.espCheckError(sys.esp_ble_passkey_reply(bd_addr.ptr, accept, passkey));
|
|
}
|
|
|
|
pub fn confirmReply(bd_addr: []u8, accept: bool) !void {
|
|
try errors.espCheckError(sys.esp_ble_confirm_reply(bd_addr.ptr, accept));
|
|
}
|
|
|
|
// -- Bond management -----------------------------------------------------
|
|
|
|
pub fn removeBondDevice(bd_addr: []u8) !void {
|
|
try errors.espCheckError(sys.esp_ble_remove_bond_device(bd_addr.ptr));
|
|
}
|
|
|
|
pub fn getBondDeviceNum() c_int {
|
|
return sys.esp_ble_get_bond_device_num();
|
|
}
|
|
|
|
pub fn getBondDeviceList(dev_num: *c_int, dev_list: [*]BondDev) !void {
|
|
try errors.espCheckError(sys.esp_ble_get_bond_device_list(dev_num, dev_list));
|
|
}
|
|
|
|
// -- Whitelist -----------------------------------------------------------
|
|
|
|
pub fn updateWhitelist(add: bool, remote_bda: []u8, addr_type: sys.esp_ble_wl_addr_type_t) !void {
|
|
try errors.espCheckError(sys.esp_ble_gap_update_whitelist(add, remote_bda.ptr, addr_type));
|
|
}
|
|
|
|
pub fn clearWhitelist() !void {
|
|
try errors.espCheckError(sys.esp_ble_gap_clear_whitelist());
|
|
}
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// GATT common
|
|
// ---------------------------------------------------------------------------
|
|
|
|
pub const GattIf = sys.esp_gatt_if_t;
|
|
pub const Uuid = sys.esp_bt_uuid_t;
|
|
pub const GattStatus = sys.esp_gatt_status_t;
|
|
pub const GattPerm = sys.esp_gatt_perm_t;
|
|
pub const GattProp = sys.esp_gatt_char_prop_t;
|
|
pub const AttrValue = sys.esp_attr_value_t;
|
|
pub const AttrControl = sys.esp_attr_control_t;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// GATT Server (GATTS)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
pub const GattServer = struct {
|
|
pub const CbT = sys.esp_gatts_cb_t;
|
|
pub const SrvcId = sys.esp_gatt_srvc_id_t;
|
|
pub const AttrDb = sys.esp_gatts_attr_db_t;
|
|
pub const Rsp = sys.esp_gatt_rsp_t;
|
|
|
|
pub fn registerCallback(cb: CbT) !void {
|
|
try errors.espCheckError(sys.esp_ble_gatts_register_callback(cb));
|
|
}
|
|
|
|
pub fn appRegister(app_id: u16) !void {
|
|
try errors.espCheckError(sys.esp_ble_gatts_app_register(app_id));
|
|
}
|
|
|
|
pub fn appUnregister(gatts_if: GattIf) !void {
|
|
try errors.espCheckError(sys.esp_ble_gatts_app_unregister(gatts_if));
|
|
}
|
|
|
|
pub fn createService(gatts_if: GattIf, service_id: *SrvcId, num_handle: u16) !void {
|
|
try errors.espCheckError(sys.esp_ble_gatts_create_service(gatts_if, service_id, num_handle));
|
|
}
|
|
|
|
/// Create all attributes in one call using an attribute table.
|
|
pub fn createAttrTab(attr_db: []const AttrDb, gatts_if: GattIf, srvc_inst_id: u8) !void {
|
|
try errors.espCheckError(sys.esp_ble_gatts_create_attr_tab(attr_db.ptr, gatts_if, @intCast(attr_db.len), srvc_inst_id));
|
|
}
|
|
|
|
pub fn addChar(
|
|
service_handle: u16,
|
|
char_uuid: *Uuid,
|
|
perm: GattPerm,
|
|
property: GattProp,
|
|
char_val: ?*AttrValue,
|
|
control: ?*AttrControl,
|
|
) !void {
|
|
try errors.espCheckError(sys.esp_ble_gatts_add_char(service_handle, char_uuid, perm, property, char_val, control));
|
|
}
|
|
|
|
pub fn addCharDescr(
|
|
service_handle: u16,
|
|
descr_uuid: *Uuid,
|
|
perm: GattPerm,
|
|
val: ?*AttrValue,
|
|
control: ?*AttrControl,
|
|
) !void {
|
|
try errors.espCheckError(sys.esp_ble_gatts_add_char_descr(service_handle, descr_uuid, perm, val, control));
|
|
}
|
|
|
|
pub fn deleteService(service_handle: u16) !void {
|
|
try errors.espCheckError(sys.esp_ble_gatts_delete_service(service_handle));
|
|
}
|
|
|
|
pub fn startService(service_handle: u16) !void {
|
|
try errors.espCheckError(sys.esp_ble_gatts_start_service(service_handle));
|
|
}
|
|
|
|
pub fn stopService(service_handle: u16) !void {
|
|
try errors.espCheckError(sys.esp_ble_gatts_stop_service(service_handle));
|
|
}
|
|
|
|
/// Send a notification or indication to a connected client.
|
|
pub fn sendIndicate(
|
|
gatts_if: GattIf,
|
|
conn_id: u16,
|
|
attr_handle: u16,
|
|
value: []u8,
|
|
need_confirm: bool,
|
|
) !void {
|
|
try errors.espCheckError(sys.esp_ble_gatts_send_indicate(
|
|
gatts_if,
|
|
conn_id,
|
|
attr_handle,
|
|
@intCast(value.len),
|
|
value.ptr,
|
|
need_confirm,
|
|
));
|
|
}
|
|
|
|
pub fn sendResponse(
|
|
gatts_if: GattIf,
|
|
conn_id: u16,
|
|
trans_id: u32,
|
|
status: GattStatus,
|
|
rsp: *Rsp,
|
|
) !void {
|
|
try errors.espCheckError(sys.esp_ble_gatts_send_response(gatts_if, conn_id, trans_id, status, rsp));
|
|
}
|
|
|
|
pub fn setAttrValue(attr_handle: u16, value: []const u8) !void {
|
|
try errors.espCheckError(sys.esp_ble_gatts_set_attr_value(attr_handle, @intCast(value.len), value.ptr));
|
|
}
|
|
|
|
pub fn getAttrValue(attr_handle: u16, length: *u16, value: *[*]const u8) GattStatus {
|
|
return sys.esp_ble_gatts_get_attr_value(attr_handle, length, value);
|
|
}
|
|
|
|
pub fn open(gatts_if: GattIf, remote_bda: []u8, is_direct: bool) !void {
|
|
try errors.espCheckError(sys.esp_ble_gatts_open(gatts_if, remote_bda.ptr, is_direct));
|
|
}
|
|
|
|
pub fn close(gatts_if: GattIf, conn_id: u16) !void {
|
|
try errors.espCheckError(sys.esp_ble_gatts_close(gatts_if, conn_id));
|
|
}
|
|
|
|
pub fn showLocalDatabase() !void {
|
|
try errors.espCheckError(sys.esp_ble_gatts_show_local_database());
|
|
}
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// GATT Client (GATTC)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
pub const GattClient = struct {
|
|
pub const CbT = sys.esp_gattc_cb_t;
|
|
pub const SvcElem = sys.esp_gattc_service_elem_t;
|
|
pub const CharElem = sys.esp_gattc_char_elem_t;
|
|
pub const DescrElem = sys.esp_gattc_descr_elem_t;
|
|
pub const WriteType = sys.esp_gatt_write_type_t;
|
|
pub const AuthReq = sys.esp_gatt_auth_req_t;
|
|
|
|
pub fn registerCallback(cb: CbT) !void {
|
|
try errors.espCheckError(sys.esp_ble_gattc_register_callback(cb));
|
|
}
|
|
|
|
pub fn appRegister(app_id: u16) !void {
|
|
try errors.espCheckError(sys.esp_ble_gattc_app_register(app_id));
|
|
}
|
|
|
|
pub fn appUnregister(gattc_if: GattIf) !void {
|
|
try errors.espCheckError(sys.esp_ble_gattc_app_unregister(gattc_if));
|
|
}
|
|
|
|
pub fn open(
|
|
gattc_if: GattIf,
|
|
remote_bda: []u8,
|
|
addr_type: sys.esp_ble_addr_type_t,
|
|
is_direct: bool,
|
|
) !void {
|
|
try errors.espCheckError(sys.esp_ble_gattc_open(gattc_if, remote_bda.ptr, addr_type, is_direct));
|
|
}
|
|
|
|
pub fn close(gattc_if: GattIf, conn_id: u16) !void {
|
|
try errors.espCheckError(sys.esp_ble_gattc_close(gattc_if, conn_id));
|
|
}
|
|
|
|
pub fn sendMtuReq(gattc_if: GattIf, conn_id: u16) !void {
|
|
try errors.espCheckError(sys.esp_ble_gattc_send_mtu_req(gattc_if, conn_id));
|
|
}
|
|
|
|
pub fn searchService(gattc_if: GattIf, conn_id: u16, filter_uuid: ?*Uuid) !void {
|
|
try errors.espCheckError(sys.esp_ble_gattc_search_service(gattc_if, conn_id, filter_uuid));
|
|
}
|
|
|
|
pub fn readChar(gattc_if: GattIf, conn_id: u16, handle: u16, auth_req: AuthReq) !void {
|
|
try errors.espCheckError(sys.esp_ble_gattc_read_char(gattc_if, conn_id, handle, auth_req));
|
|
}
|
|
|
|
pub fn writeChar(
|
|
gattc_if: GattIf,
|
|
conn_id: u16,
|
|
handle: u16,
|
|
value: []u8,
|
|
write_type: WriteType,
|
|
auth_req: AuthReq,
|
|
) !void {
|
|
try errors.espCheckError(sys.esp_ble_gattc_write_char(
|
|
gattc_if,
|
|
conn_id,
|
|
handle,
|
|
@intCast(value.len),
|
|
value.ptr,
|
|
write_type,
|
|
auth_req,
|
|
));
|
|
}
|
|
|
|
pub fn writeCharDescr(
|
|
gattc_if: GattIf,
|
|
conn_id: u16,
|
|
handle: u16,
|
|
value: []u8,
|
|
write_type: WriteType,
|
|
auth_req: AuthReq,
|
|
) !void {
|
|
try errors.espCheckError(sys.esp_ble_gattc_write_char_descr(
|
|
gattc_if,
|
|
conn_id,
|
|
handle,
|
|
@intCast(value.len),
|
|
value.ptr,
|
|
write_type,
|
|
auth_req,
|
|
));
|
|
}
|
|
|
|
pub fn registerForNotify(gattc_if: GattIf, server_bda: []u8, handle: u16) !void {
|
|
try errors.espCheckError(sys.esp_ble_gattc_register_for_notify(gattc_if, server_bda.ptr, handle));
|
|
}
|
|
|
|
pub fn unregisterForNotify(gattc_if: GattIf, server_bda: []u8, handle: u16) !void {
|
|
try errors.espCheckError(sys.esp_ble_gattc_unregister_for_notify(gattc_if, server_bda.ptr, handle));
|
|
}
|
|
|
|
pub fn cacheRefresh(remote_bda: []u8) !void {
|
|
try errors.espCheckError(sys.esp_ble_gattc_cache_refresh(remote_bda.ptr));
|
|
}
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// WiFi/BT power domain (shared with wifi.zig)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
pub const PowerDomain = struct {
|
|
pub fn on() void {
|
|
sys.esp_wifi_bt_power_domain_on();
|
|
}
|
|
pub fn off() void {
|
|
sys.esp_wifi_bt_power_domain_off();
|
|
}
|
|
};
|