blob: 102b36052f245e378b8c06bf5338a79ca61d65fe [file] [log] [blame] [edit]
//! Module to provide simple ble functions as scanning and advertising
use crate::ble_composer::BlePayload;
use crate::callback::CallbackSubscription;
use crate::callback::Consumer;
use crate::result::TockError;
use crate::result::TockResult;
use crate::shared_memory::SharedMemory;
use crate::syscalls;
use core::cell::Cell;
use core::future::Future;
const DRIVER_NUMBER: usize = 0x30000;
pub const MAX_PAYLOAD_SIZE: usize = 9;
pub const BUFFER_SIZE_ADVERTISE: usize = 39;
pub(crate) const BUFFER_SIZE_SCAN: usize = 39;
mod command_nr {
pub const START_ADVERTISING: usize = 0;
pub const PASSIVE_SCAN: usize = 5;
}
mod subscribe_nr {
pub const BLE_PASSIVE_SCAN_SUB: usize = 0;
}
mod allow_nr {
pub const ALLOW_ADVERTISMENT_BUFFER: usize = 0;
pub const ALLOW_SCAN_BUFFER: usize = 1;
}
mod gap_flags {
pub const BLE_DISCOVERABLE: usize = 0x02;
}
pub mod gap_data {
pub const COMPLETE_LIST_16BIT_SERVICE_IDS: usize = 0x03;
pub const COMPLETE_LOCAL_NAME: usize = 0x09;
pub const SET_FLAGS: usize = 1;
pub const SERVICE_DATA: usize = 0x16;
}
#[non_exhaustive]
pub struct BleAdvertisingDriverFactory;
impl BleAdvertisingDriverFactory {
pub fn create_driver(&mut self) -> BleAdvertisingDriver {
// Unfortunately, there is no way to check the availability of the ble advertising driver
BleAdvertisingDriver
}
}
#[non_exhaustive]
pub struct BleAdvertisingDriver;
impl BleAdvertisingDriver {
pub fn create_advertising_buffer() -> [u8; BUFFER_SIZE_ADVERTISE] {
[0; BUFFER_SIZE_ADVERTISE]
}
pub fn initialize<'a>(
&'a mut self,
interval: usize,
service_payload: &BlePayload,
advertising_buffer: &'a mut [u8; BUFFER_SIZE_ADVERTISE],
) -> TockResult<SharedMemory<'a>> {
let mut shared_memory = syscalls::allow(
DRIVER_NUMBER,
allow_nr::ALLOW_ADVERTISMENT_BUFFER,
advertising_buffer,
)?;
shared_memory.write_bytes(service_payload);
Self::start_advertising(gap_flags::BLE_DISCOVERABLE, interval)?;
Ok(shared_memory)
}
fn start_advertising(pdu_type: usize, interval: usize) -> TockResult<()> {
syscalls::command(
DRIVER_NUMBER,
command_nr::START_ADVERTISING,
pdu_type,
interval,
)?;
Ok(())
}
}
struct BleCallback<'a> {
read_value: &'a Cell<Option<ScanBuffer>>,
shared_buffer: SharedMemory<'a>,
}
pub(crate) type ScanBuffer = [u8; BUFFER_SIZE_SCAN];
const EMPTY_SCAN_BUFFER: ScanBuffer = [0; BUFFER_SIZE_SCAN];
#[non_exhaustive]
pub struct BleScanningDriverFactory;
impl BleScanningDriverFactory {
pub fn create_driver(&mut self) -> BleScanningDriver {
BleScanningDriver {
shared_buffer: EMPTY_SCAN_BUFFER,
read_value: Cell::new(None),
}
}
}
/// Uninitialized Ble Scanning Driver
///
/// Usage:
/// ```no_run
/// # use futures::stream::StreamExt;
/// # use libtock::ble_parser;
/// # use libtock::result::TockResult;
/// # use libtock::simple_ble;
/// # async fn doc() -> TockResult<()> {
/// let mut drivers = libtock::retrieve_drivers()?;
/// let led_driver = drivers.leds.init_driver()?;
/// let mut ble_scanning_driver_factory = drivers.ble_scanning;
/// let mut ble_scanning_driver = ble_scanning_driver_factory.create_driver();
/// let mut ble_scanning_driver_sharing = ble_scanning_driver.share_memory()?;
/// let ble_scanning_driver_scanning = ble_scanning_driver_sharing.start()?;
///
/// let value = ble_scanning_driver_scanning.stream_values().await;
/// # Ok(())
/// # }
/// ```
pub struct BleScanningDriver {
shared_buffer: ScanBuffer,
read_value: Cell<Option<ScanBuffer>>,
}
impl BleScanningDriver {
/// Prepare Ble Scanning Driver to share memory with the ble capsule
pub fn share_memory(&mut self) -> TockResult<BleScanningDriverShared> {
let shared_buffer: SharedMemory = syscalls::allow(
DRIVER_NUMBER,
allow_nr::ALLOW_SCAN_BUFFER,
&mut self.shared_buffer,
)
.map_err(Into::<TockError>::into)?;
Ok(BleScanningDriverShared {
read_value: &self.read_value,
callback: BleCallback {
read_value: &self.read_value,
shared_buffer,
},
})
}
}
/// Ble Scanning Driver in "shared buffer" state
pub struct BleScanningDriverShared<'a> {
callback: BleCallback<'a>,
read_value: &'a Cell<Option<ScanBuffer>>,
}
impl<'a> BleScanningDriverShared<'a> {
/// Start scanning for ble advertising events
pub fn start(&mut self) -> TockResult<BleScanningDriverScanning> {
let subscription = syscalls::subscribe::<BleCallback<'a>, BleCallback<'a>>(
DRIVER_NUMBER,
subscribe_nr::BLE_PASSIVE_SCAN_SUB,
&mut self.callback,
)?;
syscalls::command(DRIVER_NUMBER, command_nr::PASSIVE_SCAN, 1, 0)?;
Ok(BleScanningDriverScanning {
_subscription: subscription,
read_value: self.read_value,
})
}
}
/// Ble Scanning Driver in "scanning" state
pub struct BleScanningDriverScanning<'a> {
_subscription: CallbackSubscription<'a>,
read_value: &'a Cell<Option<ScanBuffer>>,
}
impl<'a> BleScanningDriverScanning<'a> {
/// Create stream of ble scanning packets
pub fn stream_values(&'a self) -> impl Future<Output = ScanBuffer> + 'a {
crate::futures::wait_for_value(move || {
if let Some(temp_buffer) = self.read_value.get() {
self.read_value.set(None);
Some(temp_buffer)
} else {
None
}
})
}
}
impl<'a> Consumer<Self> for BleCallback<'a> {
fn consume(callback: &mut Self, _: usize, _: usize, _: usize) {
let mut temporary_buffer: ScanBuffer = EMPTY_SCAN_BUFFER;
callback.shared_buffer.read_bytes(&mut temporary_buffer[..]);
callback.read_value.set(Some(temporary_buffer));
}
}