| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| use anyhow::{anyhow, Result}; |
| use bitflags::bitflags; |
| |
| use crate::io::gpio::Gpio; |
| use crate::io::spi::Target; |
| use crate::io::uart::Uart; |
| |
| bitflags! { |
| /// A bitmap of capabilities which may be provided by a transport. |
| pub struct Capability: u32 { |
| const NONE = 0x00000000; |
| const UART = 0x00000001; |
| const SPI = 0x00000002; |
| const GPIO = 0x00000004; |
| } |
| } |
| |
| /// A struct which can check that needed capability requirements are met. |
| pub struct Capabilities { |
| capabilities: Capability, |
| needed: Capability, |
| } |
| |
| impl Capabilities { |
| /// Create a new Capabilities object representing a provider of |
| /// capabilities specified by `cap`. |
| pub fn new(cap: Capability) -> Self { |
| Self { |
| capabilities: cap, |
| needed: Capability::NONE, |
| } |
| } |
| |
| /// Request the capabilities specified by `cap`. |
| pub fn request(&mut self, cap: Capability) -> &mut Self { |
| self.needed |= cap; |
| self |
| } |
| |
| /// Checks that the requested capabilities are provided. |
| pub fn ok(&self) -> Result<()> { |
| if self.capabilities & self.needed != self.needed { |
| Err(anyhow!( |
| "Requested capabilities {:?}, but capabilities {:?} are supplied", |
| self.needed, |
| self.capabilities |
| )) |
| } else { |
| Ok(()) |
| } |
| } |
| } |
| |
| /// A transport object is a factory for the low-level interfaces provided |
| /// by a given communications backend. |
| pub trait Transport { |
| /// Returns a `Capabilities` object to check the capabilities of this |
| /// transport object. |
| fn capabilities(&self) -> Capabilities; |
| |
| /// Returns a SPI [`Target`] implementation. |
| fn spi(&self) -> Result<Box<dyn Target>> { |
| unimplemented!(); |
| } |
| /// Returns a [`Uart`] implementation. |
| fn uart(&self) -> Result<Box<dyn Uart>> { |
| unimplemented!(); |
| } |
| /// Returns a [`Gpio`] implementation. |
| fn gpio(&self) -> Result<Box<dyn Gpio>> { |
| unimplemented!(); |
| } |
| } |
| |
| /// An `EmptyTransport` provides no communications backend. |
| pub struct EmptyTransport; |
| |
| impl Transport for EmptyTransport { |
| fn capabilities(&self) -> Capabilities { |
| Capabilities::new(Capability::NONE) |
| } |
| } |
| |
| #[cfg(test)] |
| pub mod tests { |
| use super::*; |
| |
| #[test] |
| fn test_capabilities_met() -> Result<()> { |
| let mut cap = Capabilities::new(Capability::UART | Capability::SPI); |
| assert!(cap.request(Capability::UART).ok().is_ok()); |
| Ok(()) |
| } |
| |
| #[test] |
| fn test_capabilities_not_met() -> Result<()> { |
| let mut cap = Capabilities::new(Capability::UART | Capability::SPI); |
| assert!(cap.request(Capability::GPIO).ok().is_err()); |
| Ok(()) |
| } |
| } |