esp32_nimble/client/
ble_remote_service.rs1use super::ble_client::BLEClientState;
2use crate::{
3 BLEAttribute, BLEError, BLERemoteCharacteristic, Signal, ble,
4 utilities::{ArcUnsafeCell, BleUuid, WeakUnsafeCell, as_void_ptr, voidp_to_ref},
5};
6use alloc::vec::Vec;
7use core::ffi::c_void;
8use esp_idf_svc::sys as esp_idf_sys;
9
10pub struct BLERemoteServiceState {
11 client: WeakUnsafeCell<BLEClientState>,
12 pub(crate) uuid: BleUuid,
13 start_handle: u16,
14 pub(crate) end_handle: u16,
15 pub(crate) characteristics: Option<Vec<BLERemoteCharacteristic>>,
16 signal: Signal<u32>,
17}
18
19impl BLEAttribute for BLERemoteServiceState {
20 fn get_client(&self) -> Option<ArcUnsafeCell<BLEClientState>> {
21 self.client.upgrade()
22 }
23}
24
25#[derive(Clone)]
26pub struct BLERemoteService {
27 pub(crate) state: ArcUnsafeCell<BLERemoteServiceState>,
28}
29
30impl BLERemoteService {
31 pub(crate) fn new(
32 client: WeakUnsafeCell<BLEClientState>,
33 service: &esp_idf_sys::ble_gatt_svc,
34 ) -> Self {
35 Self {
36 state: ArcUnsafeCell::new(BLERemoteServiceState {
37 client,
38 uuid: BleUuid::from(service.uuid),
39 start_handle: service.start_handle,
40 end_handle: service.end_handle,
41 characteristics: None,
42 signal: Signal::new(),
43 }),
44 }
45 }
46
47 pub fn uuid(&self) -> BleUuid {
49 self.state.uuid
50 }
51
52 pub async fn get_characteristics(
53 &mut self,
54 ) -> Result<core::slice::IterMut<'_, BLERemoteCharacteristic>, BLEError> {
55 if self.state.characteristics.is_none() {
56 self.state.characteristics = Some(Vec::new());
57 unsafe {
58 ble!(esp_idf_sys::ble_gattc_disc_all_chrs(
59 self.state.conn_handle(),
60 self.state.start_handle,
61 self.state.end_handle,
62 Some(Self::characteristic_disc_cb),
63 as_void_ptr(self),
64 ))?;
65 }
66 ble!(self.state.signal.wait().await)?;
67 }
68
69 Ok(self.state.characteristics.as_mut().unwrap().iter_mut())
70 }
71
72 pub async fn get_characteristic(
74 &mut self,
75 uuid: BleUuid,
76 ) -> Result<&mut BLERemoteCharacteristic, BLEError> {
77 let mut iter = self.get_characteristics().await?;
78 iter.find(|x| x.uuid() == uuid)
79 .ok_or_else(|| BLEError::fail().unwrap_err())
80 }
81
82 extern "C" fn characteristic_disc_cb(
83 conn_handle: u16,
84 error: *const esp_idf_sys::ble_gatt_error,
85 chr: *const esp_idf_sys::ble_gatt_chr,
86 arg: *mut c_void,
87 ) -> i32 {
88 let service = unsafe { voidp_to_ref::<Self>(arg) };
89 if service.state.conn_handle() != conn_handle {
90 return 0;
91 }
92 let error = unsafe { &*error };
93
94 if error.status == 0 {
95 let chr = unsafe { &*chr };
96 let chr = BLERemoteCharacteristic::new(ArcUnsafeCell::downgrade(&service.state), chr);
97 service.state.characteristics.as_mut().unwrap().push(chr);
98 return 0;
99 }
100
101 service.state.signal.signal(error.status as _);
102 error.status as _
103 }
104}
105
106impl core::fmt::Display for BLERemoteService {
107 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
108 write!(f, "BLERemoteService[{}]", self.state.uuid)
109 }
110}
111
112impl core::fmt::Debug for BLERemoteService {
113 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
114 f.debug_struct("BLERemoteService")
115 .field("uuid", &self.state.uuid)
116 .field("start_handle", &self.state.start_handle)
117 .field("end_handle", &self.state.end_handle)
118 .field(
119 "characteristics",
120 &self
121 .state
122 .characteristics
123 .as_ref()
124 .map(|chars| chars.iter().map(|c| c.uuid()).collect::<Vec<_>>()),
125 )
126 .finish()
127 }
128}