esp32_nimble/server/
ble_descriptor.rs1use 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}