use crate::{enums::PowerType, utilities::BleUuid, BLEDevice};
use alloc::{string::String, vec::Vec};
use esp_idf_svc::sys as esp_idf_sys;
pub struct BLEAdvertisementData {
pub(crate) flags: u8,
service_uuids_16: Vec<esp_idf_sys::ble_uuid16_t>,
uuids16_is_complete: bool,
service_uuids_32: Vec<esp_idf_sys::ble_uuid32_t>,
uuids32_is_complete: bool,
service_uuids_128: Vec<esp_idf_sys::ble_uuid128_t>,
uuids128_is_complete: bool,
name: String,
name_is_complete: bool,
tx_pwr_lvl_is_present: bool,
svc_data_uuid16: Vec<u8>,
appearance: Option<u16>,
svc_data_uuid32: Vec<u8>,
svc_data_uuid128: Vec<u8>,
mfg_data: Vec<u8>,
}
impl BLEAdvertisementData {
pub fn new() -> Self {
Self {
flags: (esp_idf_sys::BLE_HS_ADV_F_DISC_GEN | esp_idf_sys::BLE_HS_ADV_F_BREDR_UNSUP) as _,
service_uuids_16: Vec::new(),
uuids16_is_complete: true,
service_uuids_32: Vec::new(),
uuids32_is_complete: true,
service_uuids_128: Vec::new(),
uuids128_is_complete: true,
name: String::new(),
name_is_complete: true,
tx_pwr_lvl_is_present: false,
svc_data_uuid16: Vec::new(),
appearance: None,
svc_data_uuid32: Vec::new(),
svc_data_uuid128: Vec::new(),
mfg_data: Vec::new(),
}
}
pub fn name(&mut self, name: &str) -> &mut Self {
self.name.clear();
self.name.push_str(name);
self
}
pub fn add_service_uuid(&mut self, uuid: BleUuid) -> &mut Self {
let x = esp_idf_sys::ble_uuid_any_t::from(uuid);
match uuid {
BleUuid::Uuid16(_) => {
self.service_uuids_16.push(unsafe { x.u16_ });
}
BleUuid::Uuid32(_) => {
self.service_uuids_32.push(unsafe { x.u32_ });
}
BleUuid::Uuid128(_) => {
self.service_uuids_128.push(unsafe { x.u128_ });
}
}
self
}
pub fn service_data(&mut self, uuid: BleUuid, data: &[u8]) {
match uuid {
BleUuid::Uuid16(uuid) => {
self.svc_data_uuid16.clear();
self.svc_data_uuid16.extend_from_slice(&uuid.to_ne_bytes());
self.svc_data_uuid16.extend_from_slice(data);
}
BleUuid::Uuid32(uuid) => {
self.svc_data_uuid32.clear();
self.svc_data_uuid32.extend_from_slice(&uuid.to_ne_bytes());
self.svc_data_uuid32.extend_from_slice(data);
}
BleUuid::Uuid128(uuid) => {
self.svc_data_uuid128.clear();
self.svc_data_uuid128.extend_from_slice(&uuid);
self.svc_data_uuid128.extend_from_slice(data);
}
}
}
pub fn appearance(&mut self, appearance: u16) -> &mut Self {
self.appearance = Some(appearance);
self
}
pub fn add_tx_power(&mut self) -> &mut Self {
self.tx_pwr_lvl_is_present = true;
self
}
pub fn manufacturer_data(&mut self, data: &[u8]) -> &mut Self {
self.mfg_data.clear();
self.mfg_data.extend_from_slice(data);
self
}
pub(crate) fn payload_len(&self) -> usize {
let mut payload_len: usize = if self.flags > 0 { 2 + 1 } else { 0 };
if !self.service_uuids_16.is_empty() {
payload_len += 2 + 2 * self.service_uuids_16.len();
}
if !self.service_uuids_32.is_empty() {
payload_len += 2 + 4 * self.service_uuids_32.len();
}
if !self.service_uuids_128.is_empty() {
payload_len += 2 + 16 * self.service_uuids_128.len();
}
if !self.name.is_empty() {
payload_len += 2 + self.name.len();
}
if self.tx_pwr_lvl_is_present {
payload_len += 2 + (esp_idf_sys::BLE_HS_ADV_TX_PWR_LVL_LEN as usize);
}
if !self.svc_data_uuid16.is_empty() {
payload_len += 2 + self.svc_data_uuid16.len();
}
if !self.svc_data_uuid32.is_empty() {
payload_len += 2 + self.svc_data_uuid32.len();
}
if !self.svc_data_uuid128.is_empty() {
payload_len += 2 + self.svc_data_uuid128.len();
}
if self.appearance.is_some() {
payload_len += 2 + (esp_idf_sys::BLE_HS_ADV_APPEARANCE_LEN as usize);
}
if !self.mfg_data.is_empty() {
payload_len += 2 + self.mfg_data.len();
}
payload_len
}
pub(crate) fn as_ble_hs_adv_fields(&self) -> esp_idf_sys::ble_hs_adv_fields {
let mut ret = esp_idf_sys::ble_hs_adv_fields {
flags: self.flags,
..Default::default()
};
if !self.service_uuids_16.is_empty() {
ret.set_uuids16_is_complete(self.uuids16_is_complete as _);
ret.uuids16 = self.service_uuids_16.as_ptr();
ret.num_uuids16 = self.service_uuids_16.len() as _;
}
if !self.service_uuids_32.is_empty() {
ret.set_uuids32_is_complete(self.uuids32_is_complete as _);
ret.uuids32 = self.service_uuids_32.as_ptr();
ret.num_uuids32 = self.service_uuids_32.len() as _;
}
if !self.service_uuids_128.is_empty() {
ret.set_uuids128_is_complete(self.uuids128_is_complete as _);
ret.uuids128 = self.service_uuids_128.as_ptr();
ret.num_uuids128 = self.service_uuids_128.len() as _;
}
if !self.name.is_empty() {
ret.name = self.name.as_ptr().cast();
ret.name_len = self.name.len() as _;
ret.set_name_is_complete(self.name_is_complete as _);
}
if self.tx_pwr_lvl_is_present {
ret.set_tx_pwr_lvl_is_present(1);
let ble_device = BLEDevice::take();
ret.tx_pwr_lvl = ble_device.get_power(PowerType::Advertising).to_dbm();
}
if !self.svc_data_uuid16.is_empty() {
ret.svc_data_uuid16 = self.svc_data_uuid16.as_ptr();
ret.svc_data_uuid16_len = self.svc_data_uuid16.len() as _;
}
if !self.svc_data_uuid32.is_empty() {
ret.svc_data_uuid32 = self.svc_data_uuid32.as_ptr();
ret.svc_data_uuid32_len = self.svc_data_uuid32.len() as _;
}
if !self.svc_data_uuid128.is_empty() {
ret.svc_data_uuid128 = self.svc_data_uuid128.as_ptr();
ret.svc_data_uuid128_len = self.svc_data_uuid128.len() as _;
}
if let Some(appearance) = self.appearance {
ret.set_appearance_is_present(1);
ret.appearance = appearance;
}
if !self.mfg_data.is_empty() {
ret.mfg_data = self.mfg_data.as_ptr();
ret.mfg_data_len = self.mfg_data.len() as _;
}
ret
}
}