esp32_nimble/client/
ble_remote_service.rs

1use 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    /// Get the service UUID.
48    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    /// Get the characteristic object for the UUID.
73    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}