wasefire_board_api/
lib.rs

1// Copyright 2022 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Board interface.
16//!
17//! A board provides hierarchy of interfaces under the root [`Api`] trait. Some of these interfaces
18//! support triggering [events][Event].
19
20#![no_std]
21#![feature(doc_auto_cfg)]
22#![feature(never_type)]
23
24extern crate alloc;
25
26use core::marker::PhantomData;
27use core::ops::Deref;
28
29use derive_where::derive_where;
30use wasefire_error::Code;
31pub use wasefire_error::Error;
32
33pub mod applet;
34#[cfg(feature = "api-button")]
35pub mod button;
36#[cfg(feature = "api-clock")]
37pub mod clock;
38#[cfg(feature = "internal-api-crypto")]
39pub mod crypto;
40pub mod debug;
41#[cfg(feature = "internal-api-fingerprint")]
42pub mod fingerprint;
43#[cfg(feature = "api-gpio")]
44pub mod gpio;
45#[cfg(feature = "api-led")]
46pub mod led;
47pub mod platform;
48#[cfg(feature = "api-rng")]
49pub mod rng;
50#[cfg(feature = "api-timer")]
51pub mod timer;
52pub mod transfer;
53#[cfg(feature = "api-uart")]
54pub mod uart;
55#[cfg(feature = "internal-api-usb")]
56pub mod usb;
57#[cfg(feature = "api-vendor")]
58pub mod vendor;
59
60/// Board interface.
61///
62/// This is essentially a type hierarchy. The implementation is responsible for handling a possible
63/// explicit global state. The type implementing this API may be equivalent to the never type (e.g.
64/// an empty enum) because it is never used, i.e. there are no functions which take `self`.
65pub trait Api: Send + 'static {
66    /// Returns the oldest triggered event, if any.
67    ///
68    /// This function is non-blocking. See [`Self::wait_event()`] for a blocking version.
69    fn try_event() -> Option<Event<Self>>;
70
71    /// Returns the oldest triggered event, possibly waiting until one triggers.
72    ///
73    /// This function is non-blocking if an event already triggered. However, if there are no event
74    /// available, this function blocks and enters a power-saving state until an event triggers.
75    fn wait_event() -> Event<Self>;
76
77    /// Applet interface.
78    type Applet: applet::Api;
79
80    /// Button interface.
81    #[cfg(feature = "api-button")]
82    type Button: button::Api;
83
84    /// Clock interface.
85    #[cfg(feature = "api-clock")]
86    type Clock: clock::Api;
87
88    /// Cryptography interface.
89    #[cfg(feature = "internal-api-crypto")]
90    type Crypto: crypto::Api;
91
92    /// Debugging and testing interface.
93    type Debug: debug::Api;
94
95    /// Fingerprint interface.
96    #[cfg(feature = "internal-api-fingerprint")]
97    type Fingerprint: fingerprint::Api;
98
99    /// Low-level GPIO interface.
100    #[cfg(feature = "api-gpio")]
101    type Gpio: gpio::Api;
102
103    /// LED interface.
104    #[cfg(feature = "api-led")]
105    type Led: led::Api;
106
107    /// Platform interface.
108    type Platform: platform::Api;
109
110    /// Random number generator interface.
111    #[cfg(feature = "api-rng")]
112    type Rng: rng::Api;
113
114    /// Persistent storage interface.
115    #[cfg(feature = "api-storage")]
116    type Storage: Singleton + wasefire_store::Storage + Send;
117
118    /// Timer interface.
119    #[cfg(feature = "api-timer")]
120    type Timer: timer::Api;
121
122    /// UART interface.
123    #[cfg(feature = "api-uart")]
124    type Uart: uart::Api;
125
126    /// USB interface.
127    #[cfg(feature = "internal-api-usb")]
128    type Usb: usb::Api;
129
130    /// Vendor interface.
131    #[cfg(feature = "api-vendor")]
132    type Vendor: vendor::Api;
133}
134
135/// Describes how an API is supported.
136///
137/// The `Value` type parameter is usually `bool`. It may also be `usize` for APIs that have multiple
138/// similar things like buttons, leds, and timers.
139pub trait Support<Value> {
140    /// Whether and how the API is supported.
141    const SUPPORT: Value;
142}
143
144/// Marker trait for supported API.
145pub trait Supported {}
146
147/// Provides access to a singleton API.
148pub trait Singleton: Sized {
149    /// Returns the singleton.
150    ///
151    /// Returns `None` if the API is not supported. Returns `None` if called more than once.
152    fn take() -> Option<Self>;
153}
154
155/// Events that interfaces may trigger.
156///
157/// Events are de-duplicated if the previous one was not processed yet, because some events may
158/// trigger repeatedly.
159#[cfg_attr(feature = "defmt", derive(defmt::Format))]
160#[derive_where(Debug, PartialEq, Eq)]
161pub enum Event<B: Api + ?Sized> {
162    /// Button event.
163    #[cfg(feature = "api-button")]
164    Button(button::Event<B>),
165
166    /// Fingerprint event.
167    #[cfg(feature = "internal-api-fingerprint")]
168    Fingerprint(fingerprint::Event),
169
170    /// GPIO event.
171    #[cfg(feature = "api-gpio")]
172    Gpio(gpio::Event<B>),
173
174    /// Platform event.
175    Platform(platform::Event),
176
177    /// Timer event.
178    #[cfg(feature = "api-timer")]
179    Timer(timer::Event<B>),
180
181    /// UART event.
182    #[cfg(feature = "api-uart")]
183    Uart(uart::Event<B>),
184
185    /// USB event.
186    #[cfg(feature = "internal-api-usb")]
187    Usb(usb::Event),
188
189    /// Vendor event.
190    #[cfg(feature = "api-vendor")]
191    Vendor(vendor::Event<B>),
192
193    /// Dummy event for typing purposes.
194    Impossible(Impossible<B>),
195}
196
197/// Impossible type with board parameter.
198///
199/// This type is useful when the type parameter `B` needs to be mentioned in an enum. This type can
200/// be destructed by calling its unreachable method.
201#[derive_where(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
202pub struct Impossible<B: Api + ?Sized>(!, PhantomData<B>);
203
204#[cfg(feature = "defmt")]
205impl<B: Api + ?Sized> defmt::Format for Impossible<B> {
206    fn format(&self, fmt: defmt::Formatter) {
207        defmt::write!(fmt, "Impossible");
208    }
209}
210
211impl<B: Api + ?Sized> Impossible<B> {
212    /// Provides a static proof of dead code.
213    pub fn unreachable(&self) -> ! {
214        match self.0 {}
215    }
216}
217
218/// Applet interface.
219pub type Applet<B> = <B as Api>::Applet;
220
221/// Button interface.
222#[cfg(feature = "api-button")]
223pub type Button<B> = <B as Api>::Button;
224
225/// Clock interface.
226#[cfg(feature = "api-clock")]
227pub type Clock<B> = <B as Api>::Clock;
228
229/// Cryptography interface.
230#[cfg(feature = "internal-api-crypto")]
231pub type Crypto<B> = <B as Api>::Crypto;
232
233/// Debugging and testing interface.
234pub type Debug<B> = <B as Api>::Debug;
235
236/// Fingerprint interface.
237#[cfg(feature = "internal-api-fingerprint")]
238pub type Fingerprint<B> = <B as Api>::Fingerprint;
239
240/// Low-level GPIO interface.
241#[cfg(feature = "api-gpio")]
242pub type Gpio<B> = <B as Api>::Gpio;
243
244/// LED interface.
245#[cfg(feature = "api-led")]
246pub type Led<B> = <B as Api>::Led;
247
248/// Platform interface.
249pub type Platform<B> = <B as Api>::Platform;
250
251/// Random number generator interface.
252#[cfg(feature = "api-rng")]
253pub type Rng<B> = <B as Api>::Rng;
254
255/// Persistent storage interface.
256#[cfg(feature = "api-storage")]
257pub type Storage<B> = <B as Api>::Storage;
258
259/// Timer interface.
260#[cfg(feature = "api-timer")]
261pub type Timer<B> = <B as Api>::Timer;
262
263/// UART interface.
264#[cfg(feature = "api-uart")]
265pub type Uart<B> = <B as Api>::Uart;
266
267/// USB interface.
268#[cfg(feature = "internal-api-usb")]
269pub type Usb<B> = <B as Api>::Usb;
270
271/// Vendor interface.
272#[cfg(feature = "api-vendor")]
273pub type Vendor<B> = <B as Api>::Vendor;
274
275/// Valid identifier for a countable API.
276#[derive_where(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
277pub struct Id<T: Support<usize> + ?Sized> {
278    // Invariant: value < T::SUPPORT
279    value: usize,
280    count: PhantomData<T>,
281}
282
283#[cfg(feature = "defmt")]
284impl<T: Support<usize> + ?Sized> defmt::Format for Id<T> {
285    fn format(&self, fmt: defmt::Formatter) {
286        self.value.format(fmt)
287    }
288}
289
290impl<T: Support<usize>> Id<T> {
291    /// Creates a safe identifier for an API with countable support.
292    pub fn new(value: usize) -> Result<Self, Error> {
293        match value < T::SUPPORT {
294            true => Ok(Self { value, count: PhantomData }),
295            false => Err(Error::user(Code::OutOfBounds)),
296        }
297    }
298}
299
300impl<T: Support<usize>> Deref for Id<T> {
301    type Target = usize;
302
303    fn deref(&self) -> &Self::Target {
304        &self.value
305    }
306}
307
308impl<T: Supported> Support<bool> for T {
309    const SUPPORT: bool = true;
310}
311
312/// An applet trap.
313pub struct Trap;
314
315/// An applet failure (either an error or a trap).
316#[derive(Default, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
317#[repr(transparent)]
318pub struct Failure(u32);
319
320impl Failure {
321    /// The failure indicating that the applet should trap.
322    pub const TRAP: Self = Failure(0x100_0000);
323
324    /// Returns `None` for traps and `Some` for errors.
325    pub fn split(self) -> Option<Error> {
326        if self == Self::TRAP {
327            return None;
328        }
329        // SAFETY: Error is a repr(transparent) of u32. This is a private contract within Wasefire.
330        Some(unsafe { core::mem::transmute::<u32, Error>(self.0) })
331    }
332}
333
334impl From<Trap> for Failure {
335    fn from(Trap: Trap) -> Self {
336        Failure::TRAP
337    }
338}
339
340impl From<Error> for Failure {
341    fn from(value: Error) -> Self {
342        // SAFETY: Error is a repr(transparent) of u32. This is a private contract within Wasefire.
343        Failure(unsafe { core::mem::transmute::<Error, u32>(value) })
344    }
345}