esp32_nimble/server/
ble_advertisement_data.rs

1use crate::{BLEDevice, enums::PowerType, utilities::BleUuid};
2use alloc::{string::String, vec::Vec};
3use esp_idf_svc::sys as esp_idf_sys;
4
5pub struct BLEAdvertisementData {
6    // 0x01 - Flags
7    pub(crate) flags: u8,
8    // 0x02,0x03 - 16-bit service class UUIDs
9    service_uuids_16: Vec<esp_idf_sys::ble_uuid16_t>,
10    uuids16_is_complete: bool,
11    // 0x04,0x05 - 32-bit service class UUIDs
12    service_uuids_32: Vec<esp_idf_sys::ble_uuid32_t>,
13    uuids32_is_complete: bool,
14    // 0x06,0x07 - 128-bit service class UUIDs.
15    service_uuids_128: Vec<esp_idf_sys::ble_uuid128_t>,
16    uuids128_is_complete: bool,
17    // 0x08,0x09 - Local name
18    name: String,
19    name_is_complete: bool,
20    // 0x0a - Tx power level
21    tx_pwr_lvl_is_present: bool,
22    // Not Implemented: 0x0d - Slave connection interval range
23
24    // 0x16 - Service data - 16-bit UUID
25    svc_data_uuid16: Vec<u8>,
26    // Not Implemented: 0x17 - Public target address
27
28    // 0x19 - Appearance
29    appearance: Option<u16>,
30    // Not Implemented: 0x1a - Advertising interval
31
32    // 0x20 - Service data - 32-bit UUID
33    svc_data_uuid32: Vec<u8>,
34    // 0x21 - Service data - 128-bit UUID
35    svc_data_uuid128: Vec<u8>,
36    // Not Implemented: 0x24 - URI
37    // 0xff - Manufacturer specific data.
38    mfg_data: Vec<u8>,
39}
40
41impl BLEAdvertisementData {
42    pub fn new() -> Self {
43        Self {
44            flags: (esp_idf_sys::BLE_HS_ADV_F_DISC_GEN | esp_idf_sys::BLE_HS_ADV_F_BREDR_UNSUP)
45                as _,
46            service_uuids_16: Vec::new(),
47            uuids16_is_complete: true,
48            service_uuids_32: Vec::new(),
49            uuids32_is_complete: true,
50            service_uuids_128: Vec::new(),
51            uuids128_is_complete: true,
52            name: String::new(),
53            name_is_complete: true,
54            tx_pwr_lvl_is_present: false,
55            svc_data_uuid16: Vec::new(),
56            appearance: None,
57            svc_data_uuid32: Vec::new(),
58            svc_data_uuid128: Vec::new(),
59            mfg_data: Vec::new(),
60        }
61    }
62
63    /// Set the advertised name of the device.
64    pub fn name(&mut self, name: &str) -> &mut Self {
65        self.name.clear();
66        self.name.push_str(name);
67
68        self
69    }
70
71    pub fn add_service_uuid(&mut self, uuid: BleUuid) -> &mut Self {
72        let x = esp_idf_sys::ble_uuid_any_t::from(uuid);
73        match uuid {
74            BleUuid::Uuid16(_) => {
75                self.service_uuids_16.push(unsafe { x.u16_ });
76            }
77            BleUuid::Uuid32(_) => {
78                self.service_uuids_32.push(unsafe { x.u32_ });
79            }
80            BleUuid::Uuid128(_) => {
81                self.service_uuids_128.push(unsafe { x.u128_ });
82            }
83        }
84
85        self
86    }
87
88    pub fn service_data(&mut self, uuid: BleUuid, data: &[u8]) {
89        match uuid {
90            BleUuid::Uuid16(uuid) => {
91                self.svc_data_uuid16.clear();
92                self.svc_data_uuid16.extend_from_slice(&uuid.to_ne_bytes());
93                self.svc_data_uuid16.extend_from_slice(data);
94            }
95            BleUuid::Uuid32(uuid) => {
96                self.svc_data_uuid32.clear();
97                self.svc_data_uuid32.extend_from_slice(&uuid.to_ne_bytes());
98                self.svc_data_uuid32.extend_from_slice(data);
99            }
100            BleUuid::Uuid128(uuid) => {
101                self.svc_data_uuid128.clear();
102                self.svc_data_uuid128.extend_from_slice(&uuid);
103                self.svc_data_uuid128.extend_from_slice(data);
104            }
105        }
106    }
107
108    /// Set the device appearance in the advertising data.
109    pub fn appearance(&mut self, appearance: u16) -> &mut Self {
110        self.appearance = Some(appearance);
111
112        self
113    }
114
115    /// Add the transmission power level to the advertisement packet.
116    pub fn add_tx_power(&mut self) -> &mut Self {
117        self.tx_pwr_lvl_is_present = true;
118
119        self
120    }
121
122    pub fn manufacturer_data(&mut self, data: &[u8]) -> &mut Self {
123        self.mfg_data.clear();
124        self.mfg_data.extend_from_slice(data);
125
126        self
127    }
128
129    pub(crate) fn payload_len(&self) -> usize {
130        let mut payload_len: usize = if self.flags > 0 { 2 + 1 } else { 0 };
131
132        if !self.service_uuids_16.is_empty() {
133            payload_len += 2 + 2 * self.service_uuids_16.len();
134        }
135        if !self.service_uuids_32.is_empty() {
136            payload_len += 2 + 4 * self.service_uuids_32.len();
137        }
138        if !self.service_uuids_128.is_empty() {
139            payload_len += 2 + 16 * self.service_uuids_128.len();
140        }
141
142        if !self.name.is_empty() {
143            payload_len += 2 + self.name.len();
144        }
145
146        if self.tx_pwr_lvl_is_present {
147            payload_len += 2 + (esp_idf_sys::BLE_HS_ADV_TX_PWR_LVL_LEN as usize);
148        }
149
150        if !self.svc_data_uuid16.is_empty() {
151            payload_len += 2 + self.svc_data_uuid16.len();
152        }
153
154        if !self.svc_data_uuid32.is_empty() {
155            payload_len += 2 + self.svc_data_uuid32.len();
156        }
157
158        if !self.svc_data_uuid128.is_empty() {
159            payload_len += 2 + self.svc_data_uuid128.len();
160        }
161
162        if self.appearance.is_some() {
163            payload_len += 2 + (esp_idf_sys::BLE_HS_ADV_APPEARANCE_LEN as usize);
164        }
165
166        if !self.mfg_data.is_empty() {
167            payload_len += 2 + self.mfg_data.len();
168        }
169
170        // if self.uri_len > 0 {
171        //   payload_len += 2 + adv_data.uri_len;
172        // }
173
174        // if !adv_data.slave_itvl_range.is_null() {
175        //   payload_len += 2 + (esp_idf_sys::BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN as _);
176        // }
177
178        payload_len
179    }
180
181    pub(crate) fn as_ble_hs_adv_fields(&self) -> esp_idf_sys::ble_hs_adv_fields {
182        let mut ret = esp_idf_sys::ble_hs_adv_fields {
183            flags: self.flags,
184            ..Default::default()
185        };
186
187        if !self.service_uuids_16.is_empty() {
188            ret.set_uuids16_is_complete(self.uuids16_is_complete as _);
189            ret.uuids16 = self.service_uuids_16.as_ptr();
190            ret.num_uuids16 = self.service_uuids_16.len() as _;
191        }
192        if !self.service_uuids_32.is_empty() {
193            ret.set_uuids32_is_complete(self.uuids32_is_complete as _);
194            ret.uuids32 = self.service_uuids_32.as_ptr();
195            ret.num_uuids32 = self.service_uuids_32.len() as _;
196        }
197        if !self.service_uuids_128.is_empty() {
198            ret.set_uuids128_is_complete(self.uuids128_is_complete as _);
199            ret.uuids128 = self.service_uuids_128.as_ptr();
200            ret.num_uuids128 = self.service_uuids_128.len() as _;
201        }
202
203        if !self.name.is_empty() {
204            ret.name = self.name.as_ptr().cast();
205            ret.name_len = self.name.len() as _;
206            ret.set_name_is_complete(self.name_is_complete as _);
207        }
208
209        if self.tx_pwr_lvl_is_present {
210            ret.set_tx_pwr_lvl_is_present(1);
211            let ble_device = BLEDevice::take();
212            ret.tx_pwr_lvl = ble_device.get_power(PowerType::Advertising).to_dbm();
213        }
214
215        if !self.svc_data_uuid16.is_empty() {
216            ret.svc_data_uuid16 = self.svc_data_uuid16.as_ptr();
217            ret.svc_data_uuid16_len = self.svc_data_uuid16.len() as _;
218        }
219
220        if !self.svc_data_uuid32.is_empty() {
221            ret.svc_data_uuid32 = self.svc_data_uuid32.as_ptr();
222            ret.svc_data_uuid32_len = self.svc_data_uuid32.len() as _;
223        }
224
225        if !self.svc_data_uuid128.is_empty() {
226            ret.svc_data_uuid128 = self.svc_data_uuid128.as_ptr();
227            ret.svc_data_uuid128_len = self.svc_data_uuid128.len() as _;
228        }
229
230        if let Some(appearance) = self.appearance {
231            ret.set_appearance_is_present(1);
232            ret.appearance = appearance;
233        }
234
235        if !self.mfg_data.is_empty() {
236            ret.mfg_data = self.mfg_data.as_ptr();
237            ret.mfg_data_len = self.mfg_data.len() as _;
238        }
239
240        ret
241    }
242}