esp32_nimble/server/
ble_descriptor.rs

1use crate::{BLEConnDesc, utilities::OsMBuf};
2use alloc::boxed::Box;
3use bitflags::bitflags;
4use core::{cell::UnsafeCell, ffi::c_void};
5use esp_idf_svc::sys as esp_idf_sys;
6use esp_idf_sys::{ble_uuid_any_t, ble_uuid_cmp};
7
8use crate::{
9    AttValue, OnWriteDescriptorArgs,
10    utilities::{
11        BleUuid, ble_npl_hw_enter_critical, ble_npl_hw_exit_critical, mutex::Mutex, voidp_to_ref,
12    },
13};
14
15bitflags! {
16  #[repr(transparent)]
17  pub struct DescriptorProperties: u8 {
18    const READ = esp_idf_sys::BLE_ATT_F_READ as _;
19    const READ_ENC = esp_idf_sys::BLE_ATT_F_READ_ENC as _;
20    const READ_AUTHEN = esp_idf_sys::BLE_ATT_F_READ_AUTHEN as _;
21    const READ_AUTHOR = esp_idf_sys::BLE_ATT_F_READ_AUTHOR  as _;
22    const WRITE = esp_idf_sys::BLE_ATT_F_WRITE  as _;
23    const WRITE_ENC = esp_idf_sys::BLE_ATT_F_WRITE_ENC as _;
24    const WRITE_AUTHEN = esp_idf_sys::BLE_ATT_F_WRITE_AUTHEN  as _;
25    const WRITE_AUTHOR = esp_idf_sys::BLE_ATT_F_WRITE_AUTHOR  as _;
26  }
27}
28
29#[allow(clippy::type_complexity)]
30pub struct BLEDescriptor {
31    pub(crate) uuid: ble_uuid_any_t,
32    pub(crate) properties: DescriptorProperties,
33    value: AttValue,
34    on_read: Option<Box<dyn FnMut(&mut AttValue, &BLEConnDesc) + Send + Sync>>,
35    on_write: Option<Box<dyn FnMut(&mut OnWriteDescriptorArgs) + Send + Sync>>,
36}
37
38impl BLEDescriptor {
39    pub(super) fn new(uuid: BleUuid, properties: DescriptorProperties) -> Self {
40        Self {
41            uuid: ble_uuid_any_t::from(uuid),
42            properties,
43            value: AttValue::new(),
44            on_read: None,
45            on_write: None,
46        }
47    }
48
49    pub fn set_value(&mut self, value: &[u8]) -> &mut Self {
50        self.value.set_value(value);
51        self
52    }
53
54    #[deprecated(note = "Please use `set_value` + zerocopy::IntoBytes")]
55    pub fn set_from<T: Sized>(&mut self, value: &T) -> &mut Self {
56        #[allow(deprecated)]
57        self.value.set_from(value);
58        self
59    }
60
61    pub fn value_mut(&mut self) -> &mut AttValue {
62        &mut self.value
63    }
64
65    pub fn on_read(
66        &mut self,
67        callback: impl FnMut(&mut AttValue, &BLEConnDesc) + Send + Sync + 'static,
68    ) -> &mut Self {
69        self.on_read = Some(Box::new(callback));
70        self
71    }
72
73    pub fn on_write(
74        &mut self,
75        callback: impl FnMut(&mut OnWriteDescriptorArgs) + Send + Sync + 'static,
76    ) -> &mut Self {
77        self.on_write = Some(Box::new(callback));
78        self
79    }
80
81    pub(super) extern "C" fn handle_gap_event(
82        conn_handle: u16,
83        _attr_handle: u16,
84        ctxt: *mut esp_idf_sys::ble_gatt_access_ctxt,
85        arg: *mut c_void,
86    ) -> i32 {
87        let ctxt = unsafe { &*ctxt };
88
89        let mutex = unsafe { voidp_to_ref::<Mutex<Self>>(arg) };
90        let mut descriptor = mutex.lock();
91
92        if unsafe { ble_uuid_cmp((*ctxt.__bindgen_anon_1.chr).uuid, &descriptor.uuid.u) != 0 } {
93            return esp_idf_sys::BLE_ATT_ERR_UNLIKELY as _;
94        }
95
96        match ctxt.op as _ {
97            esp_idf_sys::BLE_GATT_ACCESS_OP_READ_DSC => {
98                let desc = crate::utilities::ble_gap_conn_find(conn_handle).unwrap();
99
100                unsafe {
101                    if (*(ctxt.om)).om_pkthdr_len > 8
102                        || descriptor.value.len() <= (desc.mtu() - 3) as _
103                    {
104                        let descriptor = UnsafeCell::new(&mut descriptor);
105                        if let Some(callback) = &mut (&mut (*descriptor.get())).on_read {
106                            callback(&mut (&mut (*descriptor.get())).value, &desc);
107                        }
108                    }
109                }
110
111                ble_npl_hw_enter_critical();
112                let value = descriptor.value.as_slice();
113                let rc = OsMBuf(ctxt.om).append(value);
114                ble_npl_hw_exit_critical();
115                if rc == 0 {
116                    0
117                } else {
118                    esp_idf_sys::BLE_ATT_ERR_INSUFFICIENT_RES as _
119                }
120            }
121            esp_idf_sys::BLE_GATT_ACCESS_OP_WRITE_DSC => {
122                let om = OsMBuf(ctxt.om);
123                let buf = om.as_flat();
124
125                unsafe {
126                    let descriptor = UnsafeCell::new(&mut descriptor);
127                    if let Some(callback) = &mut (&mut (*descriptor.get())).on_write {
128                        let desc = crate::utilities::ble_gap_conn_find(conn_handle).unwrap();
129                        let mut arg = OnWriteDescriptorArgs {
130                            current_data: (&(*descriptor.get())).value.as_slice(),
131                            recv_data: buf.as_slice(),
132                            desc: &desc,
133                            reject: false,
134                            error_code: 0,
135                        };
136                        callback(&mut arg);
137
138                        if arg.reject {
139                            return arg.error_code as _;
140                        }
141                    }
142                }
143                descriptor.set_value(buf.as_slice());
144
145                0
146            }
147            _ => esp_idf_sys::BLE_ATT_ERR_UNLIKELY as _,
148        }
149    }
150}