esp32_nimble/server/
ble_service.rs

1use alloc::{sync::Arc, vec::Vec};
2use esp_idf_svc::sys as esp_idf_sys;
3use esp_idf_sys::ble_uuid_any_t;
4
5use crate::{
6    BLECharacteristic, BLEError, ble,
7    utilities::{BleUuid, mutex::Mutex},
8};
9
10use super::ble_characteristic::NimbleProperties;
11
12const NULL_HANDLE: u16 = 0xFFFF;
13
14pub struct BLEService {
15    pub(crate) uuid: ble_uuid_any_t,
16    pub(crate) handle: u16,
17    pub(crate) characteristics: Vec<Arc<Mutex<BLECharacteristic>>>,
18    svc_def: Option<[esp_idf_sys::ble_gatt_svc_def; 2]>,
19    svc_def_characteristics: Vec<esp_idf_sys::ble_gatt_chr_def>,
20}
21
22impl BLEService {
23    pub(crate) fn new(uuid: BleUuid) -> Self {
24        Self {
25            uuid: ble_uuid_any_t::from(uuid),
26            handle: NULL_HANDLE,
27            characteristics: Vec::new(),
28            svc_def: None,
29            svc_def_characteristics: Vec::new(),
30        }
31    }
32
33    pub fn uuid(&self) -> BleUuid {
34        BleUuid::from(self.uuid)
35    }
36
37    pub(crate) fn start(&mut self) -> Result<(), BLEError> {
38        let svc_def = self.svc_def.get_or_insert_with(|| {
39            let mut svc = [esp_idf_sys::ble_gatt_svc_def::default(); 2];
40            svc[0].type_ = esp_idf_sys::BLE_GATT_SVC_TYPE_PRIMARY as _;
41            svc[0].uuid = unsafe { &self.uuid.u };
42            svc[0].includes = core::ptr::null_mut();
43
44            if self.characteristics.is_empty() {
45            } else {
46                for chr in &mut self.characteristics {
47                    let arg =
48                        unsafe { Arc::get_mut_unchecked(chr) } as *mut Mutex<BLECharacteristic>;
49                    let mut chr = chr.lock();
50                    self.svc_def_characteristics
51                        .push(esp_idf_sys::ble_gatt_chr_def {
52                            uuid: unsafe { &chr.uuid.u },
53                            access_cb: Some(BLECharacteristic::handle_gap_event),
54                            arg: arg as _,
55                            descriptors: chr.construct_svc_def_descriptors(),
56                            flags: chr.properties.bits(),
57                            min_key_size: 0,
58                            val_handle: &mut chr.handle,
59                            #[cfg(cpfd)]
60                            cpfd: chr.cpfd.as_mut_ptr(),
61                        });
62                }
63                self.svc_def_characteristics
64                    .push(esp_idf_sys::ble_gatt_chr_def::default());
65                svc[0].characteristics = self.svc_def_characteristics.as_ptr();
66            }
67
68            svc[1].type_ = 0;
69            svc
70        });
71
72        unsafe {
73            ble!(esp_idf_sys::ble_gatts_count_cfg(svc_def.as_ptr()))?;
74            ble!(esp_idf_sys::ble_gatts_add_svcs(svc_def.as_ptr()))?;
75        }
76        Ok(())
77    }
78
79    pub fn create_characteristic(
80        &mut self,
81        uuid: BleUuid,
82        properties: NimbleProperties,
83    ) -> Arc<Mutex<BLECharacteristic>> {
84        let characteristic = Arc::new(Mutex::new(BLECharacteristic::new(uuid, properties)));
85        self.characteristics.push(characteristic.clone());
86        characteristic
87    }
88
89    /// Get the characteristic object for the UUID.
90    pub async fn get_characteristic(
91        &self,
92        uuid: BleUuid,
93    ) -> Option<&Arc<Mutex<BLECharacteristic>>> {
94        self.characteristics
95            .iter()
96            .find(|x| unsafe { x.raw() }.uuid() == uuid)
97    }
98}
99
100unsafe impl Send for BLEService {}