1use core::borrow::Borrow;
2
3use super::ble_client::BLEClientState;
4use super::ble_remote_service::BLERemoteServiceState;
5use super::{BLEReader, BLEWriter};
6use crate::BLEAttribute;
7use crate::utilities::OsMBuf;
8use crate::{
9 BLEError, BLERemoteDescriptor, Signal, ble,
10 utilities::{ArcUnsafeCell, BleUuid, WeakUnsafeCell, as_void_ptr, voidp_to_ref},
11};
12use alloc::{boxed::Box, vec::Vec};
13use bitflags::bitflags;
14use core::ffi::c_void;
15use esp_idf_svc::sys as esp_idf_sys;
16
17bitflags! {
18 #[repr(transparent)]
19 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
20 pub struct GattCharacteristicProperties: u8 {
21 const BROADCAST = esp_idf_sys::BLE_GATT_CHR_PROP_BROADCAST as _;
22 const READ = esp_idf_sys::BLE_GATT_CHR_PROP_READ as _;
23 const WRITE_NO_RSP = esp_idf_sys::BLE_GATT_CHR_PROP_WRITE_NO_RSP as _;
24 const WRITE = esp_idf_sys::BLE_GATT_CHR_PROP_WRITE as _;
25 const NOTIFY = esp_idf_sys::BLE_GATT_CHR_PROP_NOTIFY as _;
26 const INDICATE = esp_idf_sys::BLE_GATT_CHR_PROP_INDICATE as _;
27 const AUTH_SIGN_WRITE = esp_idf_sys::BLE_GATT_CHR_PROP_AUTH_SIGN_WRITE as _;
28 const EXTENDED = esp_idf_sys::BLE_GATT_CHR_PROP_EXTENDED as _;
29 }
30}
31
32#[allow(clippy::type_complexity)]
33pub struct BLERemoteCharacteristicState {
34 pub(crate) service: WeakUnsafeCell<BLERemoteServiceState>,
35 pub(crate) uuid: BleUuid,
36 pub handle: u16,
37 end_handle: u16,
38 properties: GattCharacteristicProperties,
39 descriptors: Option<Vec<BLERemoteDescriptor>>,
40 signal: Signal<u32>,
41 on_notify: Option<Box<dyn FnMut(&[u8]) + Send + Sync>>,
42}
43
44impl BLEAttribute for BLERemoteCharacteristicState {
45 fn get_client(&self) -> Option<ArcUnsafeCell<BLEClientState>> {
46 match self.service.upgrade() {
47 Some(x) => x.get_client(),
48 None => None,
49 }
50 }
51}
52
53impl BLERemoteCharacteristicState {
54 pub fn conn_handle(&self) -> u16 {
55 match self.service.upgrade() {
56 Some(x) => x.conn_handle(),
57 None => esp_idf_sys::BLE_HS_CONN_HANDLE_NONE as _,
58 }
59 }
60}
61
62#[derive(Clone)]
63pub struct BLERemoteCharacteristic {
64 state: ArcUnsafeCell<BLERemoteCharacteristicState>,
65}
66
67impl BLERemoteCharacteristic {
68 pub(crate) fn new(
69 service: WeakUnsafeCell<BLERemoteServiceState>,
70 chr: &esp_idf_sys::ble_gatt_chr,
71 ) -> Self {
72 Self {
73 state: ArcUnsafeCell::new(BLERemoteCharacteristicState {
74 service,
75 uuid: BleUuid::from(chr.uuid),
76 handle: chr.val_handle,
77 end_handle: 0,
78 properties: GattCharacteristicProperties::from_bits_truncate(chr.properties),
79 descriptors: None,
80 signal: Signal::new(),
81 on_notify: None,
82 }),
83 }
84 }
85
86 pub(crate) fn state(&self) -> &BLERemoteCharacteristicState {
87 &self.state
88 }
89
90 pub fn uuid(&self) -> BleUuid {
91 self.state.uuid
92 }
93
94 pub fn properties(&self) -> GattCharacteristicProperties {
95 self.state.properties
96 }
97
98 pub async fn get_descriptors(
99 &mut self,
100 ) -> Result<core::slice::IterMut<'_, BLERemoteDescriptor>, BLEError> {
101 if self.state.descriptors.is_none() {
102 self.state.descriptors = Some(Vec::new());
103
104 if self.state.end_handle == 0 {
105 unsafe {
106 ble!(esp_idf_sys::ble_gattc_disc_all_chrs(
107 self.state.conn_handle(),
108 self.state.handle,
109 self.state.service.upgrade().unwrap().end_handle,
110 Some(Self::next_char_cb),
111 as_void_ptr(self),
112 ))?;
113 }
114
115 ble!(self.state.signal.wait().await)?;
116 }
117
118 if self.state.handle != self.state.end_handle {
119 unsafe {
120 ble!(esp_idf_sys::ble_gattc_disc_all_dscs(
121 self.state.conn_handle(),
122 self.state.handle,
123 self.state.end_handle,
124 Some(Self::descriptor_disc_cb),
125 as_void_ptr(self),
126 ))?;
127 }
128 ble!(self.state.signal.wait().await)?;
129 }
130 }
131
132 Ok(self.state.descriptors.as_mut().unwrap().iter_mut())
133 }
134
135 pub async fn get_descriptor(
136 &mut self,
137 uuid: BleUuid,
138 ) -> Result<&mut BLERemoteDescriptor, BLEError> {
139 let mut iter = self.get_descriptors().await?;
140 iter.find(|x| x.uuid() == uuid)
141 .ok_or_else(|| BLEError::fail().unwrap_err())
142 }
143
144 extern "C" fn next_char_cb(
145 conn_handle: u16,
146 error: *const esp_idf_sys::ble_gatt_error,
147 chr: *const esp_idf_sys::ble_gatt_chr,
148 arg: *mut c_void,
149 ) -> i32 {
150 let characteristic = unsafe { voidp_to_ref::<Self>(arg) };
151 if characteristic.state.conn_handle() != conn_handle {
152 return 0;
153 }
154
155 let error = unsafe { &*error };
156 if error.status == 0 {
157 characteristic.state.end_handle = unsafe { (*chr).def_handle - 1 };
158 } else if error.status == esp_idf_sys::BLE_HS_EDONE as _ {
159 characteristic.state.end_handle =
160 characteristic.state.service.upgrade().unwrap().end_handle;
161 }
162
163 characteristic.state.signal.signal(error.status as _);
164 esp_idf_sys::BLE_HS_EDONE as _
165 }
166
167 extern "C" fn descriptor_disc_cb(
168 conn_handle: u16,
169 error: *const esp_idf_sys::ble_gatt_error,
170 _chr_val_handle: u16,
171 dsc: *const esp_idf_sys::ble_gatt_dsc,
172 arg: *mut c_void,
173 ) -> i32 {
174 let characteristic = unsafe { voidp_to_ref::<Self>(arg) };
175 if characteristic.state.conn_handle() != conn_handle {
176 return 0;
177 }
178
179 let error = unsafe { &*error };
180
181 if error.status == 0 {
182 let dsc = unsafe { &*dsc };
183 let descriptor =
184 BLERemoteDescriptor::new(ArcUnsafeCell::downgrade(&characteristic.state), dsc);
185 characteristic
186 .state
187 .descriptors
188 .as_mut()
189 .unwrap()
190 .push(descriptor);
191 return 0;
192 }
193
194 characteristic.state.signal.signal(error.status as _);
195 esp_idf_sys::BLE_HS_EDONE as _
196 }
197
198 pub async fn read_value(&mut self) -> Result<Vec<u8>, BLEError> {
199 let mut reader = BLEReader::new(self.state.conn_handle(), self.state.handle);
200 reader.read_value().await
201 }
202
203 pub async fn write_value(&mut self, data: &[u8], response: bool) -> Result<(), BLEError> {
204 let mut writer = BLEWriter::new(self.state.conn_handle(), self.state.handle);
205 writer.write_value(data, response).await
206 }
207
208 pub async fn subscribe_notify(&mut self, response: bool) -> Result<(), BLEError> {
209 self.set_notify(0x01, response).await
210 }
211
212 pub async fn subscribe_indicate(&mut self, response: bool) -> Result<(), BLEError> {
213 self.set_notify(0x02, response).await
214 }
215
216 pub async fn unsubscribe(&mut self, response: bool) -> Result<(), BLEError> {
217 self.set_notify(0x00, response).await
218 }
219
220 async fn set_notify(&mut self, val: u16, response: bool) -> Result<(), BLEError> {
221 let desc = self.get_descriptor(BleUuid::from_uuid16(0x2902)).await?;
222 desc.write_value(&val.to_ne_bytes(), response).await
223 }
224
225 pub fn on_notify(&mut self, callback: impl FnMut(&[u8]) + Send + Sync + 'static) -> &mut Self {
226 self.state.on_notify = Some(Box::new(callback));
227 self
228 }
229
230 pub fn can_notify(&self) -> bool {
231 self.properties()
232 .contains(GattCharacteristicProperties::NOTIFY)
233 }
234
235 pub fn can_indicate(&self) -> bool {
236 self.properties()
237 .contains(GattCharacteristicProperties::INDICATE)
238 }
239
240 pub fn can_read(&self) -> bool {
241 self.properties()
242 .contains(GattCharacteristicProperties::READ)
243 }
244
245 pub fn can_write(&self) -> bool {
246 self.properties()
247 .contains(GattCharacteristicProperties::WRITE)
248 }
249
250 pub fn can_write_no_response(&self) -> bool {
251 self.properties()
252 .contains(GattCharacteristicProperties::WRITE_NO_RSP)
253 }
254
255 pub fn can_broadcast(&self) -> bool {
256 self.properties()
257 .contains(GattCharacteristicProperties::BROADCAST)
258 }
259
260 pub(crate) unsafe fn notify(&mut self, om: *mut esp_idf_sys::os_mbuf) {
261 if let Some(no_notify) = self.state.on_notify.as_mut() {
262 let om = OsMBuf(om);
263 no_notify(om.as_flat().as_slice());
264 }
265 }
266}
267
268impl core::fmt::Display for BLERemoteCharacteristic {
269 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
270 write!(f, "BLERemoteCharacteristic[{}]", self.state.uuid)
271 }
272}
273
274impl core::fmt::Debug for BLERemoteCharacteristic {
275 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
276 f.debug_struct("BLERemoteCharacteristic")
277 .field("uuid", &self.state.uuid)
278 .field(
279 "service",
280 &self.state.service.upgrade().map(|svc| svc.borrow().uuid),
281 )
282 .field("handle", &self.state.handle)
283 .field("end_handle", &self.state.end_handle)
284 .field("properties", &self.state.properties)
285 .finish()
286 }
287}