Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support BLE advertisement listening #324

Merged
merged 17 commits into from
Dec 15, 2023
3 changes: 2 additions & 1 deletion crates/api-desc/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Minor

- Add `radio` module
- Add `platform::update::is_supported()`
- Add `platform::update` module
- Add `platform` module with `platform::reboot()` function
Expand Down Expand Up @@ -78,4 +79,4 @@

## 0.1.0

<!-- Increment to skip CHANGELOG.md test: 11 -->
<!-- Increment to skip CHANGELOG.md test: 12 -->
2 changes: 2 additions & 0 deletions crates/api-desc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ mod id;
mod led;
mod macros;
mod platform;
mod radio;
mod rng;
mod scheduling;
mod store;
Expand All @@ -47,6 +48,7 @@ impl Default for Api {
debug::new(),
led::new(),
platform::new(),
radio::new(),
rng::new(),
scheduling::new(),
store::new(),
Expand Down
63 changes: 63 additions & 0 deletions crates/api-desc/src/radio.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::*;

pub(crate) fn new() -> Item {
let docs = docs! {
/// Radio operations.
};
let name = "radio".into();
ia0 marked this conversation as resolved.
Show resolved Hide resolved
let items = vec![
item! {
/// Reads radio packet into a buffer.
fn read "rr" {
/// Address of the buffer.
ptr: *mut u8,

/// Length of the buffer in bytes.
len: usize,
} -> {
/// Number of bytes read (or negative value for errors).
///
/// This function does not block and may return zero.
len: isize,
}
},
item! {
/// Register a handler for radio events.
fn register "re" {
/// Function called on radio events.
///
/// The function takes its opaque `data` as argument.
handler_func: fn { data: *mut u8 },

/// The opaque data to use when calling the handler function.
handler_data: *mut u8,
} -> {}
},
item! {
/// Unregister handlers for radio events.
fn unregister "rd" {
} -> {}
ia0 marked this conversation as resolved.
Show resolved Hide resolved
},
item! {
/// Describes errors on radio operations.
enum Error {
Unknown = 0,
}
},
];
Item::Mod(Mod { docs, name, items })
}
1 change: 1 addition & 0 deletions crates/board/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Major

- Add `radio` module
ia0 marked this conversation as resolved.
Show resolved Hide resolved
- Add `platform::Api::Update` (fix #47)
- Add `Api::Platform` with `platform::Api::reboot()` function
- Require the APIs to be `Send` and the top-level API to be `'static` too
Expand Down
7 changes: 7 additions & 0 deletions crates/board/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub mod crypto;
pub mod debug;
pub mod led;
pub mod platform;
pub mod radio;
pub mod rng;
mod storage;
pub mod timer;
Expand Down Expand Up @@ -71,6 +72,7 @@ pub trait Api: Send + 'static {
type Debug: debug::Api;
type Led: led::Api;
type Platform: platform::Api;
type Radio: radio::Api;
type Rng: rng::Api;
type Storage: Singleton + wasefire_store::Storage + Send;
type Timer: timer::Api;
Expand Down Expand Up @@ -107,6 +109,9 @@ pub enum Event<B: Api + ?Sized> {
/// Button event.
Button(button::Event<B>),

/// Radio event.
Radio(radio::Event),

/// Timer event.
Timer(timer::Event<B>),

Expand Down Expand Up @@ -137,6 +142,7 @@ pub type Crypto<B> = <B as Api>::Crypto;
pub type Debug<B> = <B as Api>::Debug;
pub type Led<B> = <B as Api>::Led;
pub type Platform<B> = <B as Api>::Platform;
pub type Radio<B> = <B as Api>::Radio;
pub type Rng<B> = <B as Api>::Rng;
pub type Storage<B> = <B as Api>::Storage;
pub type Timer<B> = <B as Api>::Timer;
Expand Down Expand Up @@ -224,6 +230,7 @@ mod tests {
type Debug = Unsupported;
type Led = Unsupported;
type Platform = Unsupported;
type Radio = Unsupported;
type Rng = Unsupported;
type Storage = Unsupported;
type Timer = Unsupported;
Expand Down
58 changes: 58 additions & 0 deletions crates/board/src/radio.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Radio interface.

use crate::{Error, Support, Unsupported};

/// Radio event.
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum Event {
/// A radio packet has been received
ia0 marked this conversation as resolved.
Show resolved Hide resolved
Received,
}

impl<B: crate::Api> From<Event> for crate::Event<B> {
fn from(event: Event) -> Self {
crate::Event::Radio(event)
}
}

/// Radio interface.
pub trait Api: Support<bool> {
/// Enables radio events
ia0 marked this conversation as resolved.
Show resolved Hide resolved
fn enable() -> Result<(), Error>;

/// Disables radio events
ia0 marked this conversation as resolved.
Show resolved Hide resolved
fn disable() -> Result<(), Error>;

/// Reads from the radio receive queue into a buffer.
///
/// Returns the number of bytes read. It could be zero if there's nothing to read.
fn read(output: &mut [u8]) -> Result<usize, Error>;
}

impl Api for Unsupported {
fn enable() -> Result<(), Error> {
unreachable!()
}

fn disable() -> Result<(), Error> {
unreachable!()
}

fn read(_: &mut [u8]) -> Result<usize, Error> {
unreachable!()
}
}
1 change: 1 addition & 0 deletions crates/prelude/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Major

- Add `radio` module
- Rename `native` to `test` and use `native` for native applets

### Minor
Expand Down
1 change: 1 addition & 0 deletions crates/prelude/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pub mod crypto;
pub mod debug;
pub mod led;
pub mod platform;
pub mod radio;
pub mod rng;
pub mod scheduling;
pub mod serial;
Expand Down
98 changes: 98 additions & 0 deletions crates/prelude/src/radio.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use alloc::boxed::Box;

use wasefire_applet_api::radio as api;
use wasefire_applet_api::radio::Error;

/// Reads from radio packet queue into a buffer without blocking.
///
/// Returns how many bytes were read (and thus written to the buffer). This function does not block,
/// so if there are no data available for read, zero is returned.
pub fn read(buf: &mut [u8]) -> Result<usize, Error> {
let params = api::read::Params { ptr: buf.as_mut_ptr(), len: buf.len() };
let api::read::Results { len } = unsafe { api::read(params) };
if len < 0 {
return Err(Error::Unknown);
}
Ok(len as usize)
}

/// Provides callback support for radio events.
pub trait Handler: 'static {
/// Called when a radio packet is received.
fn event(&self);
}

impl<F: Fn() + 'static> Handler for F {
fn event(&self) {
self()
}
}

/// Provides listening support for radio events.
#[must_use]
pub struct Listener<H: Handler> {
handler: *mut H,
}

impl<H: Handler> Listener<H> {
/// Starts listening for radio events.
///
/// The listener stops listening when dropped.
///
/// # Examples
///
/// ```ignore
/// Listener::new(|| debug!("Radio packet has been received"))
/// ```
pub fn new(handler: H) -> Self {
let handler_func = Self::call;
let handler = Box::into_raw(Box::new(handler));
let handler_data = handler as *mut u8;
unsafe { api::register(api::register::Params { handler_func, handler_data }) };
Listener { handler }
}

/// Stops listening.
///
/// This is equivalent to calling `core::mem::drop()`.
pub fn stop(self) {
core::mem::drop(self);
}

/// Drops the listener but continues listening.
///
/// This is equivalent to calling `core::mem::forget()`. This can be useful if the listener is
/// created deeply in the stack but the callback must continue processing events until the
/// applet exits or traps.
pub fn leak(self) {
core::mem::forget(self);
}

extern "C" fn call(data: *mut u8) {
let handler = unsafe { &mut *(data as *mut H) };
handler.event();
}
}

impl<H: Handler> Drop for Listener<H> {
fn drop(&mut self) {
unsafe { api::unregister() };
unsafe {
let _ = Box::from_raw(self.handler);
}
}
}
1 change: 1 addition & 0 deletions crates/runner-host/src/board.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ impl Api for Board {
type Debug = debug::Impl;
type Led = led::Impl;
type Platform = Unsupported;
type Radio = Unsupported;
type Rng = rng::Impl;
type Storage = storage::Impl;
type Timer = timer::Impl;
Expand Down
Loading