use crate::device::remoteusb::{DEFAULT_ADDR, DEFAULT_PORT};
use crate::{Bus, BusRecoveryType, BUS_DEFAULT_TIMEOUT};
use crate::{DeviceAccessError, Error};
use crate::{DeviceConfig, DeviceType, RemoteUsbDeviceConfig, UsbDeviceConfig};
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use rusb::{Context, UsbContext};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
use std::str::FromStr;
use std::time::Duration;
pub struct BusBuilder {
usb_context: Option<rusb::Context>,
serial_num: Option<u8>,
remote_addr: Option<SocketAddr>,
timeout: Option<Duration>,
recovery_type: BusRecoveryType,
}
impl Default for BusBuilder {
fn default() -> Self {
BusBuilder {
usb_context: None,
serial_num: None,
remote_addr: None,
timeout: None,
recovery_type: BusRecoveryType::default(),
}
}
}
#[allow(dead_code)]
impl BusBuilder {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn build(&mut self) -> Result<Bus, Error> {
let device = if self.remote_addr.is_some() {
trace!("Creating remote USB device");
self.create_remote_device()
} else {
trace!("Creating local USB device");
self.create_usb_device()
}?;
let timeout = self.timeout.unwrap_or(BUS_DEFAULT_TIMEOUT);
let mut bus = Bus::new(device, timeout);
bus.set_recovery_type(self.recovery_type.clone());
Ok(bus)
}
pub fn serial(&mut self, serial: u8) -> &mut Self {
self.serial_num = Some(serial);
self
}
pub fn timeout(&mut self, duration: Duration) -> &mut Self {
self.timeout = Some(duration);
self
}
pub fn recovery(&mut self, recovery_type: BusRecoveryType) -> &mut Self {
self.recovery_type = recovery_type;
self
}
}
impl BusBuilder {
#[must_use]
pub fn context(mut self, context: Context) -> Self {
self.usb_context = Some(context);
self
}
fn create_usb_device(&mut self) -> Result<DeviceType, Error> {
if self.usb_context.is_none() {
let mut context = rusb::Context::new()?;
context.set_log_level(rusb::LogLevel::Info);
self.usb_context = Some(context);
};
let device_config = UsbDeviceConfig {
context: self.usb_context.take(),
serial_num: self.serial_num,
};
DeviceType::new(DeviceConfig::Usb(device_config))
}
}
impl BusBuilder {
pub fn remote_default(&mut self) -> Result<&mut Self, Error> {
self.remote_str(&format!("{DEFAULT_ADDR}:{DEFAULT_PORT}"))
}
pub fn remote(&mut self, addr: SocketAddr) -> Result<&mut Self, Error> {
if self.usb_context.is_none() {
self.remote_addr = Some(addr);
Ok(self)
} else {
Err(Error::Init {
message: "Cannot set remote address when (local) USB context is already configured"
.to_string(),
})
}
}
pub fn remote_str(&mut self, addr: &str) -> Result<&mut Self, Error> {
let addr = addr
.to_socket_addrs()
.map_err(|e| Error::DeviceAccess {
kind: DeviceAccessError::AddressResolution {
message: format!("Failed to resolve address: {e}"),
errno: e.raw_os_error().unwrap_or(libc::EINVAL),
},
})?
.next()
.ok_or_else(|| Error::DeviceAccess {
kind: DeviceAccessError::AddressResolution {
message: "Could not resolve address".to_string(),
errno: libc::EAI_NONAME,
},
})?;
self.remote(addr)
}
pub fn remote_ipv4_str(&mut self, addr: &str, port: u16) -> Result<&mut Self, Error> {
let ip = Ipv4Addr::from_str(addr).map_err(|e| Error::DeviceAccess {
kind: DeviceAccessError::AddressResolution {
message: format!("Invalid IPv4 address: {e}"),
errno: libc::EINVAL,
},
})?;
self.remote(SocketAddr::new(IpAddr::V4(ip), port))
}
pub fn remote_ipv6_str(&mut self, addr: &str, port: u16) -> Result<&mut Self, Error> {
let ip = Ipv6Addr::from_str(addr).map_err(|e| Error::DeviceAccess {
kind: DeviceAccessError::AddressResolution {
message: format!("Invalid IPv6 address: {e}"),
errno: libc::EINVAL,
},
})?;
self.remote(SocketAddr::new(IpAddr::V6(ip), port))
}
fn create_remote_device(&mut self) -> Result<DeviceType, Error> {
let device_config = RemoteUsbDeviceConfig {
serial_num: self.serial_num,
remote_addr: self.remote_addr,
};
DeviceType::new(DeviceConfig::RemoteUsb(device_config))
}
}