wasefire_board_api/platform.rs
1// Copyright 2023 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//! Platform interface.
16
17use alloc::string::String;
18
19use usb_device::bus::{UsbBus, UsbBusAllocator};
20use usb_device::device::{StringDescriptors, UsbDevice, UsbDeviceBuilder, UsbVidPid};
21use wasefire_sync::Once;
22
23use crate::Error;
24
25pub mod protocol;
26
27/// Platform event.
28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29#[derive(Debug, PartialEq, Eq)]
30pub enum Event {
31 /// Protocol event.
32 Protocol(protocol::Event),
33}
34
35impl<B: crate::Api> From<Event> for crate::Event<B> {
36 fn from(event: Event) -> Self {
37 crate::Event::Platform(event)
38 }
39}
40
41/// Platform interface.
42pub trait Api: Send {
43 /// Platform protocol interface.
44 type Protocol: protocol::Api;
45
46 /// Platform update interface.
47 ///
48 /// Calling `finish()` will reboot if the update is successful and thus only returns in case of
49 /// errors or in dry-run mode.
50 type Update: crate::transfer::Api;
51
52 /// Returns the platform serial.
53 fn serial() -> alloc::borrow::Cow<'static, [u8]>;
54
55 /// Returns the platform running side.
56 fn running_side() -> wasefire_common::platform::Side;
57
58 /// Returns the platform information of the running side.
59 fn running_info() -> wasefire_protocol::platform::SideInfo0<'static>;
60
61 /// Returns the platform information of the opposite side, if any.
62 ///
63 /// # Errors
64 ///
65 /// There is a precise meaning to the following errors:
66 /// - `World:NotEnough`: This platform has only one side.
67 /// - `World:NotFound`: The other side is empty.
68 fn opposite_info() -> Result<wasefire_protocol::platform::SideInfo0<'static>, Error>;
69
70 /// Reboots the device (thus platform and applets).
71 fn reboot() -> Result<!, Error>;
72}
73
74/// Platform protocol interface.
75pub type Protocol<B> = <super::Platform<B> as Api>::Protocol;
76
77/// Platform update interface.
78pub type Update<B> = <super::Platform<B> as Api>::Update;
79
80/// Builds a Wasefire USB device.
81///
82/// The USB bus should have the Wasefire protocol registered. It may have additional USB classes.
83pub fn usb_device<U: UsbBus, B: crate::Api>(usb_bus: &UsbBusAllocator<U>) -> UsbDevice<'_, U> {
84 static SERIAL: Once<String> = Once::new();
85 let serial = SERIAL.call_once(|| data_encoding::HEXLOWER.encode(&B::Platform::serial()));
86 UsbDeviceBuilder::new(usb_bus, UsbVidPid(0x18d1, 0x0239))
87 .strings(&[StringDescriptors::new(usb_device::LangID::EN_US)
88 .manufacturer("Google Inc.")
89 .product("Wasefire")
90 .serial_number(serial)])
91 .unwrap()
92 .build()
93}