1use core::cell::UnsafeCell;
4use core::ffi::{c_int, c_void};
5use core::fmt;
6use core::marker::PhantomData;
7use core::sync::atomic::{AtomicBool, Ordering};
8
9use alloc::boxed::Box;
10use alloc::sync::Arc;
11
12use crate::hal::modem::BluetoothModemPeripheral;
13use crate::private::mutex::Mutex;
14use crate::sys::*;
15
16pub mod gap;
17pub mod gatt;
18#[cfg(not(esp_idf_bt_nimble_l2cap_coc_max_num = "0"))]
19pub mod l2cap;
20#[cfg(any(
21 esp_idf_bt_nimble_gatt_server,
22 esp_idf_bt_nimble_gatt_client,
23 not(esp_idf_bt_nimble_l2cap_coc_max_num = "0")
24))]
25pub mod mbuf;
26
27pub type ConnHandle = u16;
31
32pub const CONN_HANDLE_NONE: ConnHandle = BLE_HS_CONN_HANDLE_NONE as ConnHandle;
37
38#[derive(Clone, Copy, Debug)]
40pub enum BleUuid {
41 Uuid16(ble_uuid16_t),
42 Uuid128(ble_uuid128_t),
43}
44
45impl BleUuid {
46 pub const fn uuid16(uuid: u16) -> Self {
47 Self::Uuid16(ble_uuid16_t {
48 u: ble_uuid_t {
49 type_: BLE_UUID_TYPE_16 as u8,
50 },
51 value: uuid,
52 })
53 }
54
55 pub const fn uuid128(uuid: u128) -> Self {
56 Self::Uuid128(ble_uuid128_t {
57 u: ble_uuid_t {
58 type_: BLE_UUID_TYPE_128 as u8,
59 },
60 value: uuid.to_le_bytes(),
61 })
62 }
63
64 pub const fn as_ptr(&self) -> *const ble_uuid_t {
65 match self {
66 Self::Uuid16(uuid) => &uuid.u as *const ble_uuid_t,
67 Self::Uuid128(uuid) => &uuid.u as *const ble_uuid_t,
68 }
69 }
70
71 pub(crate) unsafe fn from_raw(uuid: *const ble_uuid_t) -> Self {
76 match unsafe { (*uuid).type_ } as u32 {
77 BLE_UUID_TYPE_128 => Self::Uuid128(unsafe { *uuid.cast::<ble_uuid128_t>() }),
78 _ => Self::Uuid16(unsafe { *uuid.cast::<ble_uuid16_t>() }),
80 }
81 }
82}
83
84impl PartialEq for BleUuid {
85 fn eq(&self, other: &Self) -> bool {
86 unsafe { ble_uuid_cmp(self.as_ptr(), other.as_ptr()) == 0 }
87 }
88}
89
90impl Eq for BleUuid {}
91
92#[derive(Clone, Copy)]
93#[repr(transparent)]
94pub struct BleAddr(ble_addr_t);
95
96impl BleAddr {
97 pub const fn new(kind: u8, val: [u8; 6]) -> Self {
98 Self(ble_addr_t { type_: kind, val })
99 }
100
101 pub const fn raw(&self) -> &ble_addr_t {
102 &self.0
103 }
104
105 pub const fn kind(&self) -> u8 {
106 self.0.type_
107 }
108
109 pub const fn val(&self) -> [u8; 6] {
110 self.0.val
111 }
112}
113
114impl fmt::Display for BleAddr {
115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116 let v = &self.0.val;
117 write!(
118 f,
119 "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
120 v[5], v[4], v[3], v[2], v[1], v[0]
121 )
122 }
123}
124
125impl From<ble_addr_t> for BleAddr {
126 fn from(addr: ble_addr_t) -> Self {
127 Self(addr)
128 }
129}
130
131impl From<BleAddr> for ble_addr_t {
132 fn from(addr: BleAddr) -> Self {
133 addr.0
134 }
135}
136
137pub fn ensure_addr(prefer_random: bool) -> Result<(), BleError> {
140 BleError::from_raw(unsafe { ble_hs_util_ensure_addr(prefer_random as c_int) })
141}
142
143pub fn id_copy_addr(kind: u8) -> Result<BleAddr, BleError> {
145 let mut val = [0u8; 6];
146 BleError::from_raw(unsafe {
147 ble_hs_id_copy_addr(kind, val.as_mut_ptr(), core::ptr::null_mut())
148 })?;
149
150 Ok(BleAddr::new(kind, val))
151}
152
153#[derive(Clone, Copy, PartialEq, Eq)]
154#[repr(transparent)]
155pub struct BleError(c_int);
156
157impl BleError {
158 pub const fn new(rc: c_int) -> Self {
159 Self(rc)
160 }
161
162 pub const fn code(&self) -> c_int {
163 self.0
164 }
165
166 pub fn from_raw(rc: c_int) -> Result<(), Self> {
167 if rc == 0 {
168 Ok(())
169 } else {
170 Err(Self(rc))
171 }
172 }
173
174 fn name(&self) -> &'static str {
175 match self.0 as u32 {
176 BLE_HS_EALREADY => "BLE_HS_EALREADY",
177 BLE_HS_EDONE => "BLE_HS_EDONE",
178 BLE_HS_ENOMEM => "BLE_HS_ENOMEM",
179 BLE_HS_ETIMEOUT => "BLE_HS_ETIMEOUT",
180 _ => "BLE_HS_E*",
181 }
182 }
183}
184
185impl fmt::Debug for BleError {
186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 write!(f, "BleError({}, {})", self.0, self.name())
188 }
189}
190
191impl fmt::Display for BleError {
192 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193 write!(f, "NimBLE error {} ({})", self.0, self.name())
194 }
195}
196
197#[cfg(feature = "std")]
198impl std::error::Error for BleError {}
199
200impl From<BleError> for EspError {
201 fn from(_err: BleError) -> Self {
205 EspError::from_infallible::<ESP_FAIL>()
206 }
207}
208
209#[derive(Clone, Copy)]
212pub struct BleSecurity {
213 pub io_cap: u8,
215 pub oob_data_flag: bool,
216 pub bonding: bool,
217 pub mitm: bool,
218 pub secure_connections: bool,
220 pub secure_connections_only: bool,
222 pub keypress: bool,
223 pub min_sec_level: u8,
225 pub our_key_dist: u8,
227 pub their_key_dist: u8,
229}
230
231impl BleSecurity {
232 pub const fn new() -> Self {
233 Self {
234 io_cap: BLE_HS_IO_NO_INPUT_OUTPUT as u8,
235 oob_data_flag: false,
236 bonding: false,
237 mitm: false,
238 secure_connections: false,
239 secure_connections_only: false,
240 keypress: false,
241 min_sec_level: 0,
242 our_key_dist: 0,
243 their_key_dist: 0,
244 }
245 }
246}
247
248impl Default for BleSecurity {
249 fn default() -> Self {
250 Self::new()
251 }
252}
253
254pub enum HostEvent {
256 Sync,
259 Reset { reason: i32 },
262}
263
264#[allow(dead_code)]
265#[allow(clippy::type_complexity)]
266pub(crate) struct BleCallback<A, R> {
267 callback: Mutex<Option<Arc<UnsafeCell<Box<dyn FnMut(A) -> R>>>>>,
268 default_result: R,
269}
270
271#[allow(dead_code)]
272impl<A, R> BleCallback<A, R>
273where
274 R: Clone,
275{
276 pub const fn new(default_result: R) -> Self {
277 Self {
278 callback: Mutex::new(None),
279 default_result,
280 }
281 }
282
283 pub fn subscribe<F>(&self, callback: F)
284 where
285 F: FnMut(A) -> R + Send + 'static,
286 {
287 unsafe { self.subscribe_nonstatic(callback) }
288 }
289
290 pub unsafe fn subscribe_nonstatic<'a, F>(&self, callback: F)
296 where
297 F: FnMut(A) -> R + Send + 'a,
298 {
299 let callback: Box<dyn FnMut(A) -> R + 'a> = Box::new(callback);
300 let callback: Box<dyn FnMut(A) -> R + 'static> = unsafe { core::mem::transmute(callback) };
301 *self.callback.lock() = Some(Arc::new(UnsafeCell::new(callback)));
302 }
303
304 pub fn unsubscribe(&self) {
305 *self.callback.lock() = None;
306 }
307
308 pub unsafe fn call(&self, arg: A) -> R {
312 let callback = self
317 .callback
318 .lock()
319 .as_ref()
320 .map(|callback| callback.clone());
321 if let Some(callback) = callback {
322 ((callback.get()).as_mut().unwrap())(arg)
323 } else {
324 self.default_result.clone()
325 }
326 }
327}
328
329unsafe impl<A, R> Sync for BleCallback<A, R> {}
330unsafe impl<A, R> Send for BleCallback<A, R> {}
331
332#[cfg(esp_idf_bt_nimble_gatt_server)]
338#[allow(clippy::type_complexity)]
339pub(crate) struct GattsCallback {
340 callback: Mutex<
341 Option<Arc<UnsafeCell<Box<dyn for<'a> FnMut(gatt::server::GattsEvent<'a>) -> u8 + Send>>>>,
342 >,
343}
344
345#[cfg(esp_idf_bt_nimble_gatt_server)]
346impl GattsCallback {
347 pub const fn new() -> Self {
348 Self {
349 callback: Mutex::new(None),
350 }
351 }
352
353 #[allow(clippy::arc_with_non_send_sync)]
361 pub unsafe fn subscribe_nonstatic<'a, F>(&self, callback: F)
362 where
363 F: for<'e> FnMut(gatt::server::GattsEvent<'e>) -> u8 + Send + 'a,
364 {
365 let callback: Box<dyn for<'e> FnMut(gatt::server::GattsEvent<'e>) -> u8 + Send + 'a> =
366 Box::new(callback);
367 let callback: Box<dyn for<'e> FnMut(gatt::server::GattsEvent<'e>) -> u8 + Send + 'static> =
368 unsafe { core::mem::transmute(callback) };
369 *self.callback.lock() = Some(Arc::new(UnsafeCell::new(callback)));
370 }
371
372 pub fn unsubscribe(&self) {
373 *self.callback.lock() = None;
374 }
375
376 pub unsafe fn call(&self, event: gatt::server::GattsEvent<'_>) -> u8 {
380 let callback = self
382 .callback
383 .lock()
384 .as_ref()
385 .map(|callback| callback.clone());
386 if let Some(callback) = callback {
387 unsafe { ((callback.get()).as_mut().unwrap())(event) }
388 } else {
389 0
390 }
391 }
392}
393
394#[cfg(esp_idf_bt_nimble_gatt_server)]
395unsafe impl Sync for GattsCallback {}
396#[cfg(esp_idf_bt_nimble_gatt_server)]
397unsafe impl Send for GattsCallback {}
398
399#[cfg(esp_idf_bt_nimble_gatt_client)]
403#[allow(clippy::type_complexity)]
404pub(crate) struct GattcCallback {
405 callback:
406 Mutex<Option<Arc<UnsafeCell<Box<dyn for<'a> FnMut(gatt::client::GattcEvent<'a>) + Send>>>>>,
407}
408
409#[cfg(esp_idf_bt_nimble_gatt_client)]
410impl GattcCallback {
411 pub const fn new() -> Self {
412 Self {
413 callback: Mutex::new(None),
414 }
415 }
416
417 #[allow(clippy::arc_with_non_send_sync)]
421 pub unsafe fn subscribe_nonstatic<'a, F>(&self, callback: F)
422 where
423 F: for<'e> FnMut(gatt::client::GattcEvent<'e>) + Send + 'a,
424 {
425 let callback: Box<dyn for<'e> FnMut(gatt::client::GattcEvent<'e>) + Send + 'a> =
426 Box::new(callback);
427 let callback: Box<dyn for<'e> FnMut(gatt::client::GattcEvent<'e>) + Send + 'static> =
428 unsafe { core::mem::transmute(callback) };
429 *self.callback.lock() = Some(Arc::new(UnsafeCell::new(callback)));
430 }
431
432 pub fn unsubscribe(&self) {
433 *self.callback.lock() = None;
434 }
435
436 pub unsafe fn call(&self, event: gatt::client::GattcEvent<'_>) {
440 let callback = self
442 .callback
443 .lock()
444 .as_ref()
445 .map(|callback| callback.clone());
446 if let Some(callback) = callback {
447 unsafe { ((callback.get()).as_mut().unwrap())(event) }
448 }
449 }
450}
451
452#[cfg(esp_idf_bt_nimble_gatt_client)]
453unsafe impl Sync for GattcCallback {}
454#[cfg(esp_idf_bt_nimble_gatt_client)]
455unsafe impl Send for GattcCallback {}
456
457#[cfg(not(esp_idf_bt_nimble_l2cap_coc_max_num = "0"))]
461#[allow(clippy::type_complexity)]
462pub(crate) struct L2capCallback {
463 callback:
464 Mutex<Option<Arc<UnsafeCell<Box<dyn for<'a> FnMut(l2cap::L2capEvent<'a>) -> i32 + Send>>>>>,
465}
466
467#[cfg(not(esp_idf_bt_nimble_l2cap_coc_max_num = "0"))]
468impl L2capCallback {
469 pub const fn new() -> Self {
470 Self {
471 callback: Mutex::new(None),
472 }
473 }
474
475 #[allow(clippy::arc_with_non_send_sync)]
479 pub unsafe fn subscribe_nonstatic<'a, F>(&self, callback: F)
480 where
481 F: for<'e> FnMut(l2cap::L2capEvent<'e>) -> i32 + Send + 'a,
482 {
483 let callback: Box<dyn for<'e> FnMut(l2cap::L2capEvent<'e>) -> i32 + Send + 'a> =
484 Box::new(callback);
485 let callback: Box<dyn for<'e> FnMut(l2cap::L2capEvent<'e>) -> i32 + Send + 'static> =
486 unsafe { core::mem::transmute(callback) };
487 *self.callback.lock() = Some(Arc::new(UnsafeCell::new(callback)));
488 }
489
490 pub fn unsubscribe(&self) {
491 *self.callback.lock() = None;
492 }
493
494 pub unsafe fn call(&self, event: l2cap::L2capEvent<'_>) -> i32 {
498 let callback = self
500 .callback
501 .lock()
502 .as_ref()
503 .map(|callback| callback.clone());
504 if let Some(callback) = callback {
505 unsafe { ((callback.get()).as_mut().unwrap())(event) }
506 } else {
507 0
508 }
509 }
510}
511
512#[cfg(not(esp_idf_bt_nimble_l2cap_coc_max_num = "0"))]
513unsafe impl Sync for L2capCallback {}
514#[cfg(not(esp_idf_bt_nimble_l2cap_coc_max_num = "0"))]
515unsafe impl Send for L2capCallback {}
516
517#[allow(dead_code)]
521pub(crate) struct BleSingleton {
522 initialized: AtomicBool,
523 host: BleCallback<HostEvent, ()>,
524 gap: BleCallback<gap::GapEvent, i32>,
525 #[cfg(esp_idf_bt_nimble_gatt_server)]
526 gatts: GattsCallback,
527 #[cfg(esp_idf_bt_nimble_gatt_client)]
528 gattc: GattcCallback,
529 #[cfg(not(esp_idf_bt_nimble_l2cap_coc_max_num = "0"))]
530 l2cap: L2capCallback,
531}
532
533#[allow(dead_code)]
534impl BleSingleton {
535 pub const fn new() -> Self {
536 Self {
537 initialized: AtomicBool::new(false),
538 host: BleCallback::new(()),
539 gap: BleCallback::new(0),
540 #[cfg(esp_idf_bt_nimble_gatt_server)]
541 gatts: GattsCallback::new(),
542 #[cfg(esp_idf_bt_nimble_gatt_client)]
543 gattc: GattcCallback::new(),
544 #[cfg(not(esp_idf_bt_nimble_l2cap_coc_max_num = "0"))]
545 l2cap: L2capCallback::new(),
546 }
547 }
548
549 pub fn take(&self) -> Result<(), EspError> {
550 self.initialized
551 .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
552 .map_err(|_| EspError::from_infallible::<ESP_ERR_INVALID_STATE>())?;
553
554 Ok(())
555 }
556
557 pub fn release(&self) -> Result<(), EspError> {
558 self.initialized
559 .compare_exchange(true, false, Ordering::SeqCst, Ordering::SeqCst)
560 .map_err(|_| EspError::from_infallible::<ESP_ERR_INVALID_STATE>())?;
561
562 Ok(())
563 }
564
565 unsafe extern "C" fn host_sync_cb() {
570 unsafe { SINGLETON.host.call(HostEvent::Sync) }
571 }
572
573 unsafe extern "C" fn host_reset_cb(reason: i32) {
574 unsafe { SINGLETON.host.call(HostEvent::Reset { reason }) }
575 }
576
577 unsafe extern "C" fn gap_event_cb(event: *mut ble_gap_event, _arg: *mut c_void) -> c_int {
583 let event = unsafe { &*event };
584
585 match event.type_ as u32 {
586 #[cfg(esp_idf_bt_nimble_gatt_server)]
587 BLE_GAP_EVENT_SUBSCRIBE | BLE_GAP_EVENT_NOTIFY_TX => {
588 if let Some(event) = gatt::server::GattsEvent::from_gap(event) {
589 unsafe { SINGLETON.gatts.call(event) };
590 }
591 0
592 }
593 #[cfg(esp_idf_bt_nimble_gatt_client)]
594 BLE_GAP_EVENT_NOTIFY_RX => {
595 unsafe {
596 SINGLETON
597 .gattc
598 .call(gatt::client::GattcEvent::from_notify_rx(event))
599 };
600 0
601 }
602 _ => unsafe { SINGLETON.gap.call(gap::GapEvent::from(event)) },
603 }
604 }
605
606 #[cfg(esp_idf_bt_nimble_gatt_server)]
607 unsafe extern "C" fn gatts_register_cb(ctxt: *mut ble_gatt_register_ctxt, _arg: *mut c_void) {
608 let event =
609 gatt::server::GattsEvent::Register(gatt::server::BleGattRegister::from(unsafe {
610 &*ctxt
611 }));
612
613 unsafe {
615 SINGLETON.gatts.call(event);
616 }
617 }
618
619 #[cfg(esp_idf_bt_nimble_gatt_server)]
623 unsafe extern "C" fn gatts_access_cb(
624 conn_handle: u16,
625 attr_handle: u16,
626 ctxt: *mut ble_gatt_access_ctxt,
627 _arg: *mut c_void,
628 ) -> c_int {
629 let mbuf = mbuf::Mbuf::from_raw(unsafe { (*ctxt).om });
630
631 let event = match unsafe { (*ctxt).op } as u32 {
632 BLE_GATT_ACCESS_OP_READ_CHR => {
633 #[cfg(esp_idf_version_at_least_5_3_0)]
636 let offset = unsafe { (*ctxt).offset };
637 #[cfg(not(esp_idf_version_at_least_5_3_0))]
638 let offset = 0;
639
640 gatt::server::GattsEvent::Read {
641 conn_handle,
642 attr_handle,
643 offset,
644 reply: mbuf,
645 }
646 }
647 BLE_GATT_ACCESS_OP_WRITE_CHR => gatt::server::GattsEvent::Write {
650 conn_handle,
651 attr_handle,
652 data: mbuf,
653 },
654 _ => return BLE_ATT_ERR_UNLIKELY as c_int,
655 };
656
657 unsafe { SINGLETON.gatts.call(event) as c_int }
658 }
659
660 #[cfg(esp_idf_bt_nimble_gatt_client)]
665 unsafe extern "C" fn gattc_disc_svc_cb(
666 conn_handle: u16,
667 error: *const ble_gatt_error,
668 service: *const ble_gatt_svc,
669 _arg: *mut c_void,
670 ) -> c_int {
671 let status = if error.is_null() {
672 0
673 } else {
674 unsafe { (*error).status }
675 };
676 let service =
677 (!service.is_null()).then(|| gatt::client::GattcService::from(unsafe { &*service }));
678
679 unsafe {
680 SINGLETON.gattc.call(gatt::client::GattcEvent::Service {
681 conn_handle,
682 status,
683 service,
684 });
685 }
686 0
687 }
688
689 #[cfg(esp_idf_bt_nimble_gatt_client)]
690 unsafe extern "C" fn gattc_disc_chr_cb(
691 conn_handle: u16,
692 error: *const ble_gatt_error,
693 chr: *const ble_gatt_chr,
694 _arg: *mut c_void,
695 ) -> c_int {
696 let status = if error.is_null() {
697 0
698 } else {
699 unsafe { (*error).status }
700 };
701 let chr = (!chr.is_null()).then(|| gatt::client::GattcChr::from(unsafe { &*chr }));
702
703 unsafe {
704 SINGLETON
705 .gattc
706 .call(gatt::client::GattcEvent::Characteristic {
707 conn_handle,
708 status,
709 chr,
710 });
711 }
712 0
713 }
714
715 #[cfg(esp_idf_bt_nimble_gatt_client)]
716 unsafe extern "C" fn gattc_read_cb(
717 conn_handle: u16,
718 error: *const ble_gatt_error,
719 attr: *mut ble_gatt_attr,
720 _arg: *mut c_void,
721 ) -> c_int {
722 let status = if error.is_null() {
723 0
724 } else {
725 unsafe { (*error).status }
726 };
727 let (attr_handle, om) = if attr.is_null() {
728 (0, core::ptr::null_mut())
729 } else {
730 unsafe { ((*attr).handle, (*attr).om) }
731 };
732
733 unsafe {
734 SINGLETON
735 .gattc
736 .call(gatt::client::GattcEvent::ReadComplete {
737 conn_handle,
738 status,
739 attr_handle,
740 data: mbuf::Mbuf::from_raw(om),
741 });
742 }
743 0
744 }
745
746 #[cfg(esp_idf_bt_nimble_gatt_client)]
747 unsafe extern "C" fn gattc_write_cb(
748 conn_handle: u16,
749 error: *const ble_gatt_error,
750 attr: *mut ble_gatt_attr,
751 _arg: *mut c_void,
752 ) -> c_int {
753 let status = if error.is_null() {
754 0
755 } else {
756 unsafe { (*error).status }
757 };
758 let attr_handle = if attr.is_null() {
759 0
760 } else {
761 unsafe { (*attr).handle }
762 };
763
764 unsafe {
765 SINGLETON
766 .gattc
767 .call(gatt::client::GattcEvent::WriteComplete {
768 conn_handle,
769 status,
770 attr_handle,
771 });
772 }
773 0
774 }
775
776 #[cfg(not(esp_idf_bt_nimble_l2cap_coc_max_num = "0"))]
780 unsafe extern "C" fn l2cap_event_cb(event: *mut ble_l2cap_event, _arg: *mut c_void) -> c_int {
781 let event = unsafe { &*event };
782
783 let received_sdu = if event.type_ as u32 == BLE_L2CAP_EVENT_COC_DATA_RECEIVED {
785 Some(unsafe { event.__bindgen_anon_1.receive.sdu_rx })
786 } else {
787 None
788 };
789
790 let status = match l2cap::L2capEvent::from_raw(event) {
791 Some(event) => unsafe { SINGLETON.l2cap.call(event) },
792 None => 0,
793 };
794
795 if let Some(om) = received_sdu {
796 l2cap::free_mbuf(om);
797 }
798
799 status as c_int
800 }
801
802 unsafe extern "C" fn host_task(_arg: *mut c_void) {
803 unsafe {
804 nimble_port_run();
805 nimble_port_freertos_deinit();
806 }
807 }
808}
809
810static SINGLETON: BleSingleton = BleSingleton::new();
811
812pub struct BleDriver<'ble, S = ()> {
825 started: AtomicBool,
826 #[allow(dead_code)]
833 services: S,
834 _p: PhantomData<&'ble mut ()>,
835}
836
837impl<'ble> BleDriver<'ble, ()> {
838 pub fn new<M: BluetoothModemPeripheral + 'ble>(modem: M) -> Result<Self, EspError> {
843 Self::host_init(modem, ())
844 }
845}
846
847#[cfg(esp_idf_bt_nimble_gatt_server)]
848impl<'ble, S> BleDriver<'ble, S>
849where
850 S: AsRef<[ble_gatt_svc_def]>,
851{
852 pub fn new_with_services<M: BluetoothModemPeripheral + 'ble>(
864 modem: M,
865 services: S,
866 ) -> Result<Self, EspError> {
867 let this = Self::host_init(modem, services)?;
868
869 unsafe {
873 (*core::ptr::addr_of_mut!(ble_hs_cfg)).gatts_register_cb =
874 Some(BleSingleton::gatts_register_cb);
875 }
876
877 let defs = this.services.as_ref().as_ptr();
879 BleError::from_raw(unsafe { ble_gatts_count_cfg(defs) })?;
880 BleError::from_raw(unsafe { ble_gatts_add_svcs(defs) })?;
881
882 Ok(this)
883 }
884}
885
886impl<'ble, S> BleDriver<'ble, S> {
887 pub fn host_subscribe<F>(&self, callback: F)
892 where
893 F: FnMut(HostEvent) + Send + 'static,
894 {
895 unsafe { self.host_subscribe_nonstatic(callback) }
896 }
897
898 pub unsafe fn host_subscribe_nonstatic<F>(&self, callback: F)
908 where
909 F: FnMut(HostEvent) + Send + 'ble,
910 {
911 unsafe { SINGLETON.host.subscribe_nonstatic(callback) };
915 }
916
917 pub fn host_unsubscribe(&self) {
919 SINGLETON.host.unsubscribe();
920 }
921
922 pub fn set_security(&mut self, security: &BleSecurity) -> Result<(), EspError> {
931 if self.started.load(Ordering::SeqCst) {
934 return Err(EspError::from_infallible::<ESP_ERR_INVALID_STATE>());
935 }
936
937 unsafe {
938 let cfg = core::ptr::addr_of_mut!(ble_hs_cfg);
939 (*cfg).sm_io_cap = security.io_cap;
940 (*cfg).set_sm_oob_data_flag(security.oob_data_flag as _);
941 (*cfg).set_sm_bonding(security.bonding as _);
942 (*cfg).set_sm_mitm(security.mitm as _);
943 (*cfg).set_sm_sc(security.secure_connections as _);
944 (*cfg).set_sm_sc_only(security.secure_connections_only as _);
945 (*cfg).set_sm_keypress(security.keypress as _);
946 (*cfg).sm_sec_lvl = security.min_sec_level;
947 (*cfg).sm_our_key_dist = security.our_key_dist;
948 (*cfg).sm_their_key_dist = security.their_key_dist;
949 }
950
951 Ok(())
952 }
953
954 pub fn start(&self) -> Result<(), EspError> {
962 if !self.started.swap(true, Ordering::SeqCst) {
967 unsafe { nimble_port_freertos_init(Some(BleSingleton::host_task)) };
968 }
969
970 Ok(())
971 }
972
973 pub fn stop(&self) -> Result<(), EspError> {
978 if self.started.swap(false, Ordering::SeqCst) {
983 let _ = unsafe { nimble_port_stop() };
984 }
985
986 Ok(())
987 }
988
989 fn host_init<M: BluetoothModemPeripheral>(_modem: M, services: S) -> Result<Self, EspError> {
992 SINGLETON.take()?;
993
994 esp!(unsafe { nimble_port_init() })?;
995
996 unsafe {
997 ble_svc_gap_init();
998 ble_svc_gatt_init();
999
1000 let cfg = core::ptr::addr_of_mut!(ble_hs_cfg);
1007 (*cfg).sync_cb = Some(BleSingleton::host_sync_cb);
1008 (*cfg).reset_cb = Some(BleSingleton::host_reset_cb);
1009 }
1010
1011 let mut this = Self {
1012 started: AtomicBool::new(false),
1013 services,
1014 _p: PhantomData,
1015 };
1016
1017 this.set_security(&BleSecurity::new())?;
1018
1019 Ok(this)
1020 }
1021}
1022
1023unsafe impl<S> Send for BleDriver<'_, S> {}
1041unsafe impl<S> Sync for BleDriver<'_, S> {}
1042
1043impl<S> Drop for BleDriver<'_, S> {
1044 fn drop(&mut self) {
1045 let _ = self.stop();
1046
1047 esp!(unsafe { nimble_port_deinit() }).unwrap();
1050
1051 unsafe {
1052 let cfg = core::ptr::addr_of_mut!(ble_hs_cfg);
1053 (*cfg).sync_cb = None;
1054 (*cfg).reset_cb = None;
1055 #[cfg(esp_idf_bt_nimble_gatt_server)]
1056 {
1057 (*cfg).gatts_register_cb = None;
1058 }
1059 }
1060
1061 SINGLETON.host.unsubscribe();
1062 SINGLETON.gap.unsubscribe();
1063 #[cfg(esp_idf_bt_nimble_gatt_server)]
1064 SINGLETON.gatts.unsubscribe();
1065 #[cfg(esp_idf_bt_nimble_gatt_client)]
1066 SINGLETON.gattc.unsubscribe();
1067 #[cfg(not(esp_idf_bt_nimble_l2cap_coc_max_num = "0"))]
1068 SINGLETON.l2cap.unsubscribe();
1069 let _ = SINGLETON.release();
1070 }
1071}