Skip to main content

BleDriver

Struct BleDriver 

Source
pub struct BleDriver<'ble, S = ()> { /* private fields */ }
Expand description

The NimBLE host handle and primary entrypoint to BLE.

It is role-agnostic: the type parameter S is the GATT-server service table, defaulting to () (no server). A central or broadcaster uses new (S = ()); a GATT server uses new_with_services, whose S: Deref<Target = [ble_gatt_svc_def]> owns the table and keeps it alive — drop order guarantees nimble_port_deinit (in Drop) runs before the table field is freed, so NimBLE never sees a dangling pointer.

The GAP / GATT-server / GATT-client operations are grouped into separate impl blocks (gap.rs, gatt/gatts.rs, and — later — the client), each mirroring a NimBLE subsystem; the GATT ones are #[cfg]-gated on the corresponding Kconfig. start takes &self (interior started-flag).

Implementations§

Source§

impl<'d, S> BleDriver<'d, S>

GAP operations on the BleDriver: advertising, the device name, and GAP event subscription. Available for any role (S). &self, so callable re-entrantly from within the GAP event callback.

Source

pub fn set_device_name(&self, name: &str) -> Result<(), BleError>

Set the device name exposed via the GAP service.

Source

pub fn gap_subscribe<F>(&self, callback: F)
where F: FnMut(GapEvent) -> i32 + Send + 'static,

Subscribe to GAP events (connect / disconnect / subscribe / MTU / notify-tx / — for a client — notify-rx). The callback runs on the NimBLE host task and returns the GAP status code (0 on success). The trampoline is wired at adv_start (server) or at connect time (client), so this only needs to be set before whichever of those you use.

Source

pub unsafe fn gap_subscribe_nonstatic<F>(&self, callback: F)
where F: FnMut(GapEvent) -> i32 + Send + 'd,

§Safety

The non-'static counterpart of gap_subscribe: the callback may borrow data that lives as long as the BleDriver. It stays registered until the driver is dropped, which un-subscribes it, so the driver must not be core::mem::forget-ten. See BleDriver::host_subscribe_nonstatic.

Source

pub fn gap_unsubscribe(&self)

Stop delivering GAP events to the subscribed callback.

Source

pub fn adv_set_data(&self, data: &[u8]) -> Result<(), BleError>

Set the raw advertising payload.

Source

pub fn adv_set_fields(&self, fields: &BleAdvFields<'_>) -> Result<(), BleError>

Encode fields into the advertising payload.

Source

pub fn adv_start( &self, own_addr_type: u8, params: &BleAdvParams, ) -> Result<(), BleError>

Start a legacy advertising procedure. Drive this from an host_subscribe closure once the host has synced, and restart it from a GapEvent::Disconnect handler. Events for the resulting connection are delivered to the gap_subscribe callback.

Source

pub fn adv_stop(&self) -> Result<(), BleError>

Source§

impl<'d, S> BleDriver<'d, S>

GATT-client operations on the BleDriver. Available for any role (S) — a device can be both a server and a client. &self, so callable re-entrantly from within the client callback.

Source

pub fn gattc_subscribe<F>(&self, callback: F)
where F: for<'a> FnMut(GattcEvent<'a>) + Send + 'static,

Subscribe to GATT-client events (GattcEvent): per-operation completions plus received notifications/indications.

Source

pub unsafe fn gattc_subscribe_nonstatic<F>(&self, callback: F)
where F: for<'a> FnMut(GattcEvent<'a>) + Send + 'd,

§Safety

The non-'static counterpart of gattc_subscribe. See BleDriver::host_subscribe_nonstatic for the borrowing rules and the core::mem::forget hazard.

Source

pub fn gattc_unsubscribe(&self)

Stop delivering GATT-client events to the subscribed hook.

Source

pub fn connect(&self, own_addr_type: u8, peer: &BleAddr) -> Result<(), BleError>

Initiate a connection to peer. The connect/disconnect outcome arrives on the GAP hook (gap_subscribe); the connection’s received notifications arrive on the GATTC hook.

Source

pub fn disconnect(&self, conn_handle: ConnHandle) -> Result<(), BleError>

Terminate the connection conn_handle.

Source

pub fn discover_services(&self, conn_handle: ConnHandle) -> Result<(), BleError>

Discover all of the peer’s primary services. Results arrive as GattcEvent::Service.

Source

pub fn discover_characteristics( &self, conn_handle: ConnHandle, start_handle: AttrHandle, end_handle: AttrHandle, ) -> Result<(), BleError>

Discover the peer’s characteristics in the attribute-handle range [start_handle, end_handle] (e.g. a service’s range). Results arrive as GattcEvent::Characteristic.

Source

pub fn read( &self, conn_handle: ConnHandle, attr_handle: AttrHandle, ) -> Result<(), BleError>

Read the value of attr_handle on the peer (a Read Request). The result arrives as GattcEvent::ReadComplete.

Source

pub fn write( &self, conn_handle: ConnHandle, attr_handle: AttrHandle, data: &[u8], ) -> Result<(), BleError>

Write data to attr_handle on the peer as a Write Request (acknowledged): the peer sends a Write Response, and its completion arrives as GattcEvent::WriteComplete.

Source

pub fn write_cmd( &self, conn_handle: ConnHandle, attr_handle: AttrHandle, data: &[u8], ) -> Result<(), BleError>

Write data to attr_handle on the peer as a Write Command (unacknowledged): the peer sends no response, so this is fire-and-forget — there is no completion event. The returned Result only reflects whether the command was accepted for transmission.

Source§

impl<'d, S> BleDriver<'d, S>
where S: AsRef<[ble_gatt_svc_def]>,

GATT-server operations on the BleDriver, available only when the driver was built with a service table (S: AsRef<[ble_gatt_svc_def]>) via new_with_services. &self, so callable re-entrantly.

Source

pub fn gatts_subscribe<F>(&self, callback: F)
where F: for<'a> FnMut(GattsEvent<'a>) -> u8 + Send + 'static,

Subscribe to GATT-server events (GattsEvent). Set this before start: the Register events (carrying the attribute handles NimBLE assigned) fire during host start.

Source

pub unsafe fn gatts_subscribe_nonstatic<F>(&self, callback: F)
where F: for<'a> FnMut(GattsEvent<'a>) -> u8 + Send + 'd,

§Safety

The non-'static counterpart of gatts_subscribe. See BleDriver::host_subscribe_nonstatic for the borrowing rules and the core::mem::forget hazard.

Source

pub fn gatts_unsubscribe(&self)

Stop delivering GATT-server events to the subscribed hook.

Source

pub fn indicate( &self, conn_handle: ConnHandle, val_handle: AttrHandle, data: &[u8], ) -> Result<(), BleError>

Send a “free-form” characteristic indication to conn_handle.

Source§

impl<'d, S> BleDriver<'d, S>

L2CAP CoC operations on the BleDriver. Available for any role (S); a channel just needs a GAP connection underneath. &self, so callable re-entrantly from within the L2CAP hook (e.g. calling l2cap_recv_ready from an Accept).

Source

pub fn l2cap_subscribe<F>(&self, callback: F)
where F: for<'a> FnMut(L2capEvent<'a>) -> i32 + Send + 'static,

Subscribe to L2CAP CoC events (L2capEvent) — connection lifecycle, received SDUs, and flow-control notifications for every channel.

Source

pub unsafe fn l2cap_subscribe_nonstatic<F>(&self, callback: F)
where F: for<'a> FnMut(L2capEvent<'a>) -> i32 + Send + 'd,

§Safety

The non-'static counterpart of l2cap_subscribe. See BleDriver::host_subscribe_nonstatic for the borrowing rules and the core::mem::forget hazard.

Source

pub fn l2cap_unsubscribe(&self)

Stop delivering L2CAP events to the subscribed hook.

Source

pub fn l2cap_create_server(&self, psm: u16, mtu: u16) -> Result<(), BleError>

Listen for incoming L2CAP CoC connections on psm, negotiating an MTU of mtu. Incoming connections arrive as L2capEvent::Accept on the L2CAP hook. May be called at runtime (unlike a GATT service table, which is fixed at construction).

Source

pub fn l2cap_connect( &self, conn_handle: ConnHandle, psm: u16, mtu: u16, ) -> Result<(), BleError>

Open an L2CAP CoC to the peer’s psm over the existing connection conn_handle, negotiating an MTU of mtu. The outcome arrives as L2capEvent::Connected. The initial receive buffer is allocated internally (mtu bytes from os_msys).

Source

pub fn l2cap_send( &self, chan: L2capChan, data: &[u8], ) -> Result<SendOutcome, BleError>

Send data as one SDU over chan. On success returns SendOutcome::Sent; if the peer’s credits run out mid-SDU it returns SendOutcome::Stalled and the remainder resumes on L2capEvent::TxUnstalled (do not call again until then).

Source

pub fn l2cap_recv_ready( &self, chan: L2capChan, sdu_size: u16, ) -> Result<(), BleError>

Signal readiness to receive another SDU of up to sdu_size bytes on chan, replenishing the peer’s credits. Call this to provide the first buffer on L2capEvent::Accept and to re-arm after each L2capEvent::Received. The buffer is allocated internally from os_msys.

Source

pub fn l2cap_disconnect(&self, chan: L2capChan) -> Result<(), BleError>

Disconnect the L2CAP channel chan. The completion arrives as L2capEvent::Disconnected.

Source§

impl<'ble> BleDriver<'ble, ()>

Source

pub fn new<M: BluetoothModemPeripheral + 'ble>( modem: M, ) -> Result<Self, EspError>

Initialize the NimBLE host with no GATT server — the role-agnostic form used by a central, a broadcaster, or an observer. Performs nimble_port_init and the standard GAP/GATT service init, but does not start the host task; configure callbacks/security, then call start.

Source§

impl<'ble, S> BleDriver<'ble, S>
where S: AsRef<[ble_gatt_svc_def]>,

Source

pub fn new_with_services<M: BluetoothModemPeripheral + 'ble>( modem: M, services: S, ) -> Result<Self, EspError>

Initialize the NimBLE host as a GATT server, registering services in NimBLE’s pre-start window (this is why service registration is a construction concern, not a runtime one — see ble_gatts_add_svcs). S may be an owned bundle built at runtime (e.g. BleGattServices), a Box<[ble_gatt_svc_def]>, a &'static [ble_gatt_svc_def], or a &'static static table built with the gatt_services! macro; whatever it is, it must keep the entire pointer graph the table references (characteristics, UUIDs) alive and at stable addresses for as long as it is held. The driver owns it, so drop order does the rest.

Does not start the host task; hook gatts_subscribe (to learn the assigned attribute handles), configure security/callbacks, then call start.

Source§

impl<'ble, S> BleDriver<'ble, S>

Source

pub fn host_subscribe<F>(&self, callback: F)
where F: FnMut(HostEvent) + Send + 'static,

Subscribe to host-lifecycle events (HostEvent): Sync when the host and controller are synchronized (you must delay BLE operations until then), and Reset when the host resets. The hook must be re-entrant — a reset is followed by another Sync once re-synced. See https://mynewt.apache.org/latest/network/ble_setup/ble_sync_cb.html

Source

pub unsafe fn host_subscribe_nonstatic<F>(&self, callback: F)
where F: FnMut(HostEvent) + Send + 'ble,

§Safety

The non-'static counterpart of host_subscribe: the callback may borrow variables that live as long as this BleDriver. It stays registered with the running NimBLE host task until the driver is dropped, which un-subscribes it.

Care must be taken NOT to core::mem::forget the driver: that skips the un-subscription, leaving the host task holding a callback with dangling borrows. This “local borrowing” can only be expressed safely once/if !Leak types are introduced to Rust.

Source

pub fn host_unsubscribe(&self)

Stop delivering host-lifecycle events to the subscribed hook.

Source

pub fn set_security(&mut self, security: &BleSecurity) -> Result<(), EspError>

Configure the Security Manager (SMP) parameters. Must be called before start; the settings take effect once the host task runs.

This writes the global ble_hs_cfg, which the running host task reads on its own thread with no lock we could share — so it is refused (with ESP_ERR_INVALID_STATE) once the host has started. It takes &mut self rather than &self so this write cannot race a concurrent config call from another thread; the operational, post-start API is all &self (and the driver is Sync).

Source

pub fn start(&self) -> Result<(), EspError>

Start the NimBLE host task. It runs in the background and calls the Sync via host_subscribe callback once the stack is ready for use. Call this once services, security and callbacks are set up; you must retain the driver, as the BLE stack is stopped when it drops.

Takes &self (flipping an interior started-flag) rather than consuming the driver, so the service table it owns and every subscribed callback stay put across the call.

Source

pub fn stop(&self) -> Result<(), EspError>

Stop the NimBLE host task.

Takes &self (flipping an interior started-flag) rather than consuming the driver, so the service table it owns and every subscribed callback stay put across the call.

Trait Implementations§

Source§

impl<S> Drop for BleDriver<'_, S>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more
Source§

impl<S> Send for BleDriver<'_, S>

Source§

impl<S> Sync for BleDriver<'_, S>

Auto Trait Implementations§

§

impl<'ble, S = ()> !Freeze for BleDriver<'ble, S>

§

impl<'ble, S = ()> !UnwindSafe for BleDriver<'ble, S>

§

impl<'ble, S> RefUnwindSafe for BleDriver<'ble, S>
where S: RefUnwindSafe,

§

impl<'ble, S> Unpin for BleDriver<'ble, S>
where S: Unpin,

§

impl<'ble, S> UnsafeUnpin for BleDriver<'ble, S>
where S: UnsafeUnpin,

Blanket Implementations§

§

impl<T> Any for T
where T: 'static + ?Sized,

§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> Borrow<T> for T
where T: ?Sized,

§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
§

impl<T> BorrowMut<T> for T
where T: ?Sized,

§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> From<T> for T

§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T, U> Into<U> for T
where U: From<T>,

§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of [From]<T> for U chooses to do.

§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = !

The type returned in the event of a conversion error.
§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.