1use core::ffi::c_int;
4use core::ptr;
5
6use alloc::ffi::CString;
7
8use crate::sys::*;
9
10use super::{BleAddr, BleDriver, BleError, ConnHandle};
11
12#[cfg(not(esp_idf_bt_nimble_ext_adv))]
20#[derive(Clone, Copy, Default)]
21pub struct BleAdvParams {
22 pub conn_mode: u8,
23 pub disc_mode: u8,
24 pub itvl_min: u16,
25 pub itvl_max: u16,
26 pub channel_map: u8,
27 pub filter_policy: u8,
28 pub high_duty_cycle: bool,
29}
30
31#[cfg(not(esp_idf_bt_nimble_ext_adv))]
32impl From<&BleAdvParams> for ble_gap_adv_params {
33 fn from(params: &BleAdvParams) -> Self {
34 let mut raw: ble_gap_adv_params = unsafe { core::mem::zeroed() };
35
36 raw.conn_mode = params.conn_mode;
37 raw.disc_mode = params.disc_mode;
38 raw.itvl_min = params.itvl_min;
39 raw.itvl_max = params.itvl_max;
40 raw.channel_map = params.channel_map;
41 raw.filter_policy = params.filter_policy;
42 raw.set_high_duty_cycle(params.high_duty_cycle as _);
43
44 raw
45 }
46}
47
48#[cfg(esp_idf_bt_nimble_ext_adv)]
53#[derive(Clone, Copy, Default)]
54pub struct BleExtAdvParams {
55 pub connectable: bool,
56 pub scannable: bool,
57 pub legacy_pdu: bool,
58 pub directed: bool,
59 pub anonymous: bool,
60 pub high_duty_directed: bool,
61 pub include_tx_power: bool,
62 pub itvl_min: u32,
63 pub itvl_max: u32,
64 pub channel_map: u8,
65 pub own_addr_type: u8,
66 pub primary_phy: u8,
67 pub secondary_phy: u8,
68 pub tx_power: i8,
69 pub sid: u8,
70}
71
72#[cfg(esp_idf_bt_nimble_ext_adv)]
73impl From<&BleExtAdvParams> for ble_gap_ext_adv_params {
74 fn from(params: &BleExtAdvParams) -> Self {
75 let mut raw: ble_gap_ext_adv_params = unsafe { core::mem::zeroed() };
76
77 raw.set_connectable(params.connectable as _);
78 raw.set_scannable(params.scannable as _);
79 raw.set_legacy_pdu(params.legacy_pdu as _);
80 raw.set_directed(params.directed as _);
81 raw.set_anonymous(params.anonymous as _);
82 raw.set_high_duty_directed(params.high_duty_directed as _);
83 raw.set_include_tx_power(params.include_tx_power as _);
84
85 raw.itvl_min = params.itvl_min;
86 raw.itvl_max = params.itvl_max;
87 raw.channel_map = params.channel_map;
88 raw.own_addr_type = params.own_addr_type;
89 raw.primary_phy = params.primary_phy;
90 raw.secondary_phy = params.secondary_phy;
91 raw.tx_power = params.tx_power;
92 raw.sid = params.sid;
93
94 raw
95 }
96}
97
98#[cfg_attr(esp_idf_bt_nimble_ext_adv, doc = "[`BleDriver::ext_adv_set_data`],")]
103#[cfg_attr(not(esp_idf_bt_nimble_ext_adv), doc = "[`BleDriver::adv_set_data`],")]
104#[derive(Clone, Copy, Default)]
106pub struct BleAdvFields<'a> {
107 pub flags: u8,
108 pub name: Option<&'a str>,
109 pub tx_power_level: Option<i8>,
110 pub appearance: Option<u16>,
111 pub service_data_uuid16: Option<&'a [u8]>,
112 pub manufacturer_data: Option<&'a [u8]>,
113}
114
115impl From<&BleAdvFields<'_>> for ble_hs_adv_fields {
116 fn from(fields: &BleAdvFields) -> Self {
117 let mut raw: ble_hs_adv_fields = unsafe { core::mem::zeroed() };
118
119 raw.flags = fields.flags;
120
121 if let Some(name) = fields.name {
122 raw.name = name.as_ptr();
123 raw.name_len = name.len() as _;
124 raw.set_name_is_complete(1);
125 }
126
127 if let Some(tx_power_level) = fields.tx_power_level {
128 raw.tx_pwr_lvl = tx_power_level;
129 raw.set_tx_pwr_lvl_is_present(1);
130 }
131
132 if let Some(appearance) = fields.appearance {
133 raw.appearance = appearance;
134 raw.set_appearance_is_present(1);
135 }
136
137 if let Some(service_data) = fields.service_data_uuid16 {
138 raw.svc_data_uuid16 = service_data.as_ptr();
139 raw.svc_data_uuid16_len = service_data.len() as _;
140 }
141
142 if let Some(manufacturer_data) = fields.manufacturer_data {
143 raw.mfg_data = manufacturer_data.as_ptr();
144 raw.mfg_data_len = manufacturer_data.len() as _;
145 }
146
147 raw
148 }
149}
150
151pub enum GapEvent {
156 Connect {
157 conn_handle: ConnHandle,
158 status: Result<(), BleError>,
159 },
160 Disconnect {
161 conn_handle: ConnHandle,
162 reason: BleError,
163 },
164 Mtu {
165 conn_handle: ConnHandle,
166 value: u16,
167 },
168 Other,
169}
170
171impl From<&ble_gap_event> for GapEvent {
172 fn from(event: &ble_gap_event) -> Self {
173 let anon = &event.__bindgen_anon_1;
174
175 match event.type_ as u32 {
176 BLE_GAP_EVENT_CONNECT => {
177 let connect = unsafe { &anon.connect };
178 Self::Connect {
179 conn_handle: connect.conn_handle,
180 status: BleError::from_raw(connect.status),
181 }
182 }
183 BLE_GAP_EVENT_DISCONNECT => {
184 let disconnect = unsafe { &anon.disconnect };
185 Self::Disconnect {
186 conn_handle: disconnect.conn.conn_handle,
187 reason: BleError::new(disconnect.reason),
188 }
189 }
190 BLE_GAP_EVENT_MTU => {
191 let mtu = unsafe { &anon.mtu };
192 Self::Mtu {
193 conn_handle: mtu.conn_handle,
194 value: mtu.value,
195 }
196 }
197 _ => Self::Other,
198 }
199 }
200}
201
202#[derive(Clone, Copy)]
203#[repr(transparent)]
204pub struct BleConnDesc(ble_gap_conn_desc);
205
206impl BleConnDesc {
207 pub const fn peer_addr(&self) -> BleAddr {
208 BleAddr::new(self.0.peer_id_addr.type_, self.0.peer_id_addr.val)
209 }
210}
211
212pub fn conn_find(conn_handle: ConnHandle) -> Result<BleConnDesc, BleError> {
217 let mut desc: ble_gap_conn_desc = unsafe { core::mem::zeroed() };
218 BleError::from_raw(unsafe { ble_gap_conn_find(conn_handle, &mut desc) })?;
219
220 Ok(BleConnDesc(desc))
221}
222
223impl<'d, S> BleDriver<'d, S> {
227 pub fn set_device_name(&self, name: &str) -> Result<(), BleError> {
229 let name = CString::new(name).map_err(|_| BleError::new(BLE_HS_EINVAL as c_int))?;
230
231 BleError::from_raw(unsafe { ble_svc_gap_device_name_set(name.as_ptr()) })
233 }
234
235 pub fn gap_subscribe<F>(&self, callback: F)
240 where
241 F: FnMut(GapEvent) -> i32 + Send + 'static,
242 {
243 unsafe { self.gap_subscribe_nonstatic(callback) }
244 }
245
246 pub unsafe fn gap_subscribe_nonstatic<F>(&self, callback: F)
253 where
254 F: FnMut(GapEvent) -> i32 + Send + 'd,
255 {
256 unsafe { super::SINGLETON.gap.subscribe_nonstatic(callback) };
257 }
258
259 pub fn gap_unsubscribe(&self) {
261 super::SINGLETON.gap.unsubscribe();
262 }
263
264 #[cfg(not(esp_idf_bt_nimble_ext_adv))]
266 pub fn adv_set_data(&self, data: &[u8]) -> Result<(), BleError> {
267 BleError::from_raw(unsafe { ble_gap_adv_set_data(data.as_ptr(), data.len() as c_int) })
269 }
270
271 #[cfg(not(esp_idf_bt_nimble_ext_adv))]
273 pub fn adv_set_fields(&self, fields: &BleAdvFields) -> Result<(), BleError> {
274 let raw: ble_hs_adv_fields = fields.into();
275
276 BleError::from_raw(unsafe { ble_gap_adv_set_fields(&raw) })
277 }
278
279 #[cfg(not(esp_idf_bt_nimble_ext_adv))]
285 pub fn adv_start(&self, own_addr_type: u8, params: &BleAdvParams) -> Result<(), BleError> {
286 let raw: ble_gap_adv_params = params.into();
287
288 const BLE_HS_FOREVER: c_int = i32::MAX;
291
292 let rc = unsafe {
293 ble_gap_adv_start(
294 own_addr_type,
295 ptr::null(),
296 BLE_HS_FOREVER as _,
297 &raw,
298 Some(super::BleSingleton::gap_event_cb),
299 ptr::null_mut(),
300 )
301 };
302 if rc == BLE_HS_EALREADY as c_int {
303 return Ok(());
304 }
305
306 BleError::from_raw(rc)
307 }
308
309 #[cfg(not(esp_idf_bt_nimble_ext_adv))]
310 pub fn adv_stop(&self) -> Result<(), BleError> {
311 BleError::from_raw(unsafe { ble_gap_adv_stop() })
312 }
313
314 #[cfg(esp_idf_bt_nimble_ext_adv)]
315 pub fn ext_adv_configure(
316 &self,
317 instance: u8,
318 params: &BleExtAdvParams,
319 ) -> Result<i8, BleError> {
320 let raw: ble_gap_ext_adv_params = params.into();
321 let mut selected_tx_power: i8 = 0;
322
323 BleError::from_raw(unsafe {
324 ble_gap_ext_adv_configure(
325 instance,
326 &raw,
327 &mut selected_tx_power,
328 Some(super::BleSingleton::gap_event_cb),
329 ptr::null_mut(),
330 )
331 })?;
332
333 Ok(selected_tx_power)
334 }
335
336 #[cfg(esp_idf_bt_nimble_ext_adv)]
337 pub fn ext_adv_set_addr(&self, instance: u8, addr: &BleAddr) -> Result<(), BleError> {
338 BleError::from_raw(unsafe { ble_gap_ext_adv_set_addr(instance, addr.raw()) })
339 }
340
341 #[cfg(esp_idf_bt_nimble_ext_adv)]
342 pub fn ext_adv_set_data(&self, instance: u8, data: &[u8]) -> Result<(), BleError> {
343 let om = super::mbuf::mbuf_from_slice(data)?;
344
345 BleError::from_raw(unsafe { ble_gap_ext_adv_set_data(instance, om) })
347 }
348
349 #[cfg(esp_idf_bt_nimble_ext_adv)]
351 pub fn ext_adv_set_fields(&self, instance: u8, fields: &BleAdvFields) -> Result<(), BleError> {
352 let raw: ble_hs_adv_fields = fields.into();
353
354 let mut buf = [0u8; BLE_HS_ADV_MAX_SZ as usize];
355 let mut len: u8 = 0;
356 BleError::from_raw(unsafe {
357 ble_hs_adv_set_fields(&raw, buf.as_mut_ptr(), &mut len, buf.len() as u8)
358 })?;
359
360 self.ext_adv_set_data(instance, &buf[..len as usize])
361 }
362
363 #[cfg(esp_idf_bt_nimble_ext_adv)]
364 pub fn ext_adv_start(&self, instance: u8) -> Result<(), BleError> {
365 let rc = unsafe { ble_gap_ext_adv_start(instance, 0, 0) };
366 if rc == BLE_HS_EALREADY as c_int {
367 return Ok(());
368 }
369
370 BleError::from_raw(rc)
371 }
372
373 #[cfg(esp_idf_bt_nimble_ext_adv)]
374 pub fn ext_adv_stop(&self, instance: u8) -> Result<(), BleError> {
375 BleError::from_raw(unsafe { ble_gap_ext_adv_stop(instance) })
376 }
377}