-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathbluetil.rs
102 lines (89 loc) · 3.5 KB
/
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())
}
}