#[cfg(not(any(
feature = "pcie",
feature = "uart",
feature = "spi",
feature = "ethernet",
feature = "usb"
)))]
compile_error!("Must enable at least one bridge type: pcie, uart, spi, ethernet, or usb");
pub(crate) mod bridges;
#[doc(hidden)]
#[cfg(feature = "ethernet")]
pub use bridges::ethernet::EthernetBridgeInner;
#[doc(hidden)]
#[cfg(feature = "pcie")]
pub use bridges::pcie::PCIeBridgeInner;
#[doc(hidden)]
#[cfg(feature = "spi")]
pub use bridges::spi::SpiBridgeInner;
#[doc(hidden)]
#[cfg(feature = "uart")]
pub use bridges::uart::UartBridgeInner;
#[doc(hidden)]
#[cfg(feature = "usb")]
pub use bridges::usb::UsbBridgeInner;
#[cfg(feature = "ethernet")]
pub use bridges::ethernet::{EthernetBridge, EthernetBridgeProtocol};
#[cfg(feature = "pcie")]
pub use bridges::pcie::PCIeBridge;
#[cfg(feature = "spi")]
pub use bridges::spi::SpiBridge;
#[cfg(feature = "uart")]
pub use bridges::uart::UartBridge;
#[cfg(feature = "usb")]
pub use bridges::usb::UsbBridge;
use log::debug;
use std::io;
use std::sync::{Arc, Mutex};
#[doc(hidden)]
#[derive(Clone)]
pub enum BridgeConfig {
None,
#[cfg(feature = "ethernet")]
EthernetBridge(EthernetBridge),
#[cfg(feature = "pcie")]
PCIeBridge(PCIeBridge),
#[cfg(feature = "spi")]
SpiBridge(SpiBridge),
#[cfg(feature = "uart")]
UartBridge(UartBridge),
#[cfg(feature = "usb")]
UsbBridge(UsbBridge),
}
#[doc(hidden)]
#[derive(Clone)]
pub enum BridgeCore {
#[cfg(feature = "ethernet")]
EthernetBridge(EthernetBridgeInner),
#[cfg(feature = "pcie")]
PCIeBridge(PCIeBridgeInner),
#[cfg(feature = "spi")]
SpiBridge(SpiBridgeInner),
#[cfg(feature = "uart")]
UartBridge(UartBridgeInner),
#[cfg(feature = "usb")]
UsbBridge(UsbBridgeInner),
}
#[derive(Clone)]
pub struct Bridge {
core: BridgeCore,
mutex: Arc<Mutex<()>>,
}
#[derive(Debug)]
pub enum BridgeError {
NoBridgeSpecified,
LengthError(usize, usize),
#[cfg(feature = "usb")]
USBError(libusb_wishbone_tool::Error),
IoError(io::Error),
NotConnected,
InvalidAddress,
WrongResponse,
#[allow(dead_code)]
ProtocolNotSupported,
#[allow(dead_code)]
Timeout,
}
impl ::std::fmt::Display for BridgeError {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
use BridgeError::*;
match self {
LengthError(expected, actual) => {
write!(f, "expected {} bytes, but got {} instead", expected, actual)
}
#[cfg(feature = "usb")]
USBError(e) => write!(f, "libusb error {}", e.strerror()),
IoError(e) => write!(f, "io error {}", e),
NoBridgeSpecified => write!(f, "no bridge was specified"),
NotConnected => write!(f, "bridge not connected"),
WrongResponse => write!(f, "wrong response received"),
InvalidAddress => write!(f, "bad address or path"),
ProtocolNotSupported => write!(f, "protocol not supported on this platform"),
Timeout => write!(f, "connection timed out"),
}
}
}
#[cfg(feature = "usb")]
impl std::convert::From<libusb_wishbone_tool::Error> for BridgeError {
fn from(e: libusb_wishbone_tool::Error) -> BridgeError {
BridgeError::USBError(e)
}
}
impl std::convert::From<io::Error> for BridgeError {
fn from(e: io::Error) -> BridgeError {
BridgeError::IoError(e)
}
}
impl Bridge {
pub(crate) fn new(bridge_cfg: BridgeConfig) -> Result<Bridge, BridgeError> {
let mutex = Arc::new(Mutex::new(()));
match &bridge_cfg {
BridgeConfig::None => Err(BridgeError::NoBridgeSpecified),
#[cfg(feature = "ethernet")]
BridgeConfig::EthernetBridge(bridge_cfg) => Ok(Bridge {
mutex,
core: BridgeCore::EthernetBridge(EthernetBridgeInner::new(bridge_cfg)?),
}),
#[cfg(feature = "pcie")]
BridgeConfig::PCIeBridge(bridge_cfg) => Ok(Bridge {
mutex,
core: BridgeCore::PCIeBridge(PCIeBridgeInner::new(bridge_cfg)?),
}),
#[cfg(feature = "spi")]
BridgeConfig::SpiBridge(bridge_cfg) => Ok(Bridge {
mutex,
core: BridgeCore::SpiBridge(SpiBridgeInner::new(bridge_cfg)?),
}),
#[cfg(feature = "uart")]
BridgeConfig::UartBridge(bridge_cfg) => Ok(Bridge {
mutex,
core: BridgeCore::UartBridge(UartBridgeInner::new(bridge_cfg)?),
}),
#[cfg(feature = "usb")]
BridgeConfig::UsbBridge(bridge_cfg) => Ok(Bridge {
mutex,
core: BridgeCore::UsbBridge(UsbBridgeInner::new(bridge_cfg)?),
}),
}
}
pub fn connect(&self) -> Result<(), BridgeError> {
let _mtx = self.mutex.lock().unwrap();
match &self.core {
#[cfg(feature = "ethernet")]
BridgeCore::EthernetBridge(b) => b.connect(),
#[cfg(feature = "pcie")]
BridgeCore::PCIeBridge(b) => b.connect(),
#[cfg(feature = "spi")]
BridgeCore::SpiBridge(b) => b.connect(),
#[cfg(feature = "uart")]
BridgeCore::UartBridge(b) => b.connect(),
#[cfg(feature = "usb")]
BridgeCore::UsbBridge(b) => b.connect(),
}
}
pub fn peek(&self, addr: u32) -> Result<u32, BridgeError> {
let _mtx = self.mutex.lock().unwrap();
loop {
let result = match &self.core {
#[cfg(feature = "ethernet")]
BridgeCore::EthernetBridge(b) => b.peek(addr),
#[cfg(feature = "pcie")]
BridgeCore::PCIeBridge(b) => b.peek(addr),
#[cfg(feature = "spi")]
BridgeCore::SpiBridge(b) => b.peek(addr),
#[cfg(feature = "uart")]
BridgeCore::UartBridge(b) => b.peek(addr),
#[cfg(feature = "usb")]
BridgeCore::UsbBridge(b) => b.peek(addr),
};
#[allow(unreachable_code)]
if let Err(e) = result {
#[cfg(feature = "usb")]
if let BridgeError::USBError(libusb_wishbone_tool::Error::Pipe) = e {
debug!("USB device disconnected, forcing early return");
return Err(e);
}
debug!("Peek failed, trying again: {:?}", e);
} else {
return result;
}
}
}
pub fn poke(&self, addr: u32, value: u32) -> Result<(), BridgeError> {
let _mtx = self.mutex.lock().unwrap();
loop {
let result = match &self.core {
#[cfg(feature = "ethernet")]
BridgeCore::EthernetBridge(b) => b.poke(addr, value),
#[cfg(feature = "pcie")]
BridgeCore::PCIeBridge(b) => b.poke(addr, value),
#[cfg(feature = "spi")]
BridgeCore::SpiBridge(b) => b.poke(addr, value),
#[cfg(feature = "uart")]
BridgeCore::UartBridge(b) => b.poke(addr, value),
#[cfg(feature = "usb")]
BridgeCore::UsbBridge(b) => b.poke(addr, value),
};
#[allow(unreachable_code)]
if let Err(e) = result {
match e {
#[cfg(feature = "usb")]
BridgeError::USBError(libusb_wishbone_tool::Error::Pipe) => {
debug!("USB device disconnected (Windows), forcing early return");
return Err(e);
}
#[cfg(feature = "usb")]
BridgeError::USBError(libusb_wishbone_tool::Error::Io) => {
debug!("USB device disconnected (Posix), forcing early return");
return Err(e);
}
_ => {}
}
debug!("Poke failed, trying again: {:?}", e);
} else {
return result;
}
}
}
}