riot_wrappers/bluetil.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
//! [Bluetil](https://doc.riot-os.org/group__ble__bluetil__ad.html) tools for BLE Advertising Data (AD)
use crate::error::NegativeErrorExt;
use core::convert::TryInto;
use riot_sys::bluetil_ad_t;
/// Wrapper around [bluetil_ad](https://doc.riot-os.org/group__ble__bluetil__ad.html) (BLE Advertising Data)
///
/// This is implemented as a possibly owned buffer, as that should make usage straightforward both
/// for read-only data (not practically usable yet) and for writing; it remains to be seen whether
/// that's viable.
pub struct Ad<B: AsRef<[u8]>>(B);
impl<B: AsRef<[u8]>> Ad<B> {
/// Reclaim the buffer that the AD was built around.
///
/// This is particularly useful when an AD object was populated, and in the end the buffer
/// needs to be obtained in order to send it.
pub fn destroy(self) -> B {
self.0
}
}
// FIXME: Test this with actual read-only data
#[derive(Debug)]
pub enum Error {
NotFound,
NoMem,
}
impl From<crate::error::NumericError> for Error {
fn from(e: crate::error::NumericError) -> Error {
match e.number() as _ {
riot_sys::BLUETIL_AD_NOTFOUND => Error::NotFound,
riot_sys::BLUETIL_AD_NOMEM => Error::NoMem,
_ => panic!("Invalid bluetil error"),
}
}
// FIXME: Add all the find functions
}
// FIXME: flags and type are u32 because the riot_sys constants are; wrap?
impl<const L: usize> Ad<heapless::Vec<u8, L>> {
/// Create an empty AD object around owned memory; the size is given by the type parameter.
pub fn new() -> Self {
Self(heapless::Vec::new())
}
/// Construct a bluetil_ad_t that represent the current vec state
///
/// This is not unsafe in itself, but usually used with functions that are, and when they
/// write into the buffer, it needs the unsafe [heapless::Vec::set_len] to propagate that write.
fn build(&self) -> bluetil_ad_t {
bluetil_ad_t {
buf: self.0.as_ptr() as _,
pos: self.0.len() as _,
// As this is checked here, all the other casts of pos are OK too
size: self.0.capacity().try_into().unwrap(),
}
}
/// Add a "flags" field with the given flag value to the AD (convenience function)
#[doc(alias = "bluetil_ad_add_flags")]
pub fn add_flags(&mut self, flags: u32) -> Result<(), Error> {
let mut ad = self.build();
// unsafe: regular C call
unsafe {
riot_sys::bluetil_ad_add_flags(crate::inline_cast_mut(&mut ad as *mut _), flags as _)
}
.negative_to_error()?;
// unsafe: bluetil doesn't set pos after size
unsafe { self.0.set_len(ad.pos as _) };
Ok(())
}
/// Add an arbitrary typed field to the AD
#[doc(alias = "bluetil_ad_add")]
pub fn add(&mut self, type_: u32, data: &[u8]) -> Result<(), Error> {
let mut ad = self.build();
// unsafe: regular C call
unsafe {
riot_sys::bluetil_ad_add(&mut ad, type_ as _, data.as_ptr() as _, data.len() as _)
}
.negative_to_error()?;
// unsafe: bluetil doesn't set pos after size
unsafe { self.0.set_len(ad.pos as _) };
Ok(())
}
}
// FIXME: 31 is expanded from BLE_HCI_MAX_ADV_DATA_LEN
impl Ad<heapless::Vec<u8, 31>> {
/// Create an empty AD object around owned memory with the maximum sendable size.
///
/// This is often more convenient than `new` as it's not too large anyway (31 bytes).
pub fn new_maximal() -> Self {
Self(heapless::Vec::new())
}
}