1#[cfg(not(any(
31 feature = "pcie",
32 feature = "uart",
33 feature = "spi",
34 feature = "ethernet",
35 feature = "usb"
36)))]
37compile_error!("Must enable at least one bridge type: pcie, uart, spi, ethernet, or usb");
38
39pub(crate) mod bridges;
40
41#[doc(hidden)]
42#[cfg(feature = "ethernet")]
43pub use bridges::ethernet::EthernetBridgeInner;
44#[doc(hidden)]
45#[cfg(feature = "pcie")]
46pub use bridges::pcie::PCIeBridgeInner;
47#[doc(hidden)]
48#[cfg(feature = "spi")]
49pub use bridges::spi::SpiBridgeInner;
50#[doc(hidden)]
51#[cfg(feature = "uart")]
52pub use bridges::uart::UartBridgeInner;
53#[doc(hidden)]
54#[cfg(feature = "usb")]
55pub use bridges::usb::UsbBridgeInner;
56
57#[cfg(feature = "ethernet")]
58pub use bridges::ethernet::{EthernetBridge, EthernetBridgeProtocol};
59#[cfg(feature = "pcie")]
60pub use bridges::pcie::PCIeBridge;
61#[cfg(feature = "spi")]
62pub use bridges::spi::SpiBridge;
63#[cfg(feature = "uart")]
64pub use bridges::uart::UartBridge;
65#[cfg(feature = "usb")]
66pub use bridges::usb::UsbBridge;
67
68use log::debug;
69
70use std::io;
71use std::sync::{Arc, Mutex};
72
73#[doc(hidden)]
74#[derive(Clone)]
75pub enum BridgeConfig {
78 None,
82
83 #[cfg(feature = "ethernet")]
87 EthernetBridge(EthernetBridge),
88
89 #[cfg(feature = "pcie")]
93 PCIeBridge(PCIeBridge),
94
95 #[cfg(feature = "spi")]
97 SpiBridge(SpiBridge),
98
99 #[cfg(feature = "uart")]
101 UartBridge(UartBridge),
102
103 #[cfg(feature = "usb")]
105 UsbBridge(UsbBridge),
106}
107
108#[doc(hidden)]
109#[derive(Clone)]
110pub enum BridgeCore {
111 #[cfg(feature = "ethernet")]
112 EthernetBridge(EthernetBridgeInner),
113 #[cfg(feature = "pcie")]
114 PCIeBridge(PCIeBridgeInner),
115 #[cfg(feature = "spi")]
116 SpiBridge(SpiBridgeInner),
117 #[cfg(feature = "uart")]
118 UartBridge(UartBridgeInner),
119 #[cfg(feature = "usb")]
120 UsbBridge(UsbBridgeInner),
121}
122
123#[derive(Clone)]
135pub struct Bridge {
136 core: BridgeCore,
138
139 offset: usize,
141
142 mutex: Arc<Mutex<()>>,
144}
145
146#[derive(Debug)]
148pub enum BridgeError {
149 NoBridgeSpecified,
151
152 LengthError(usize, usize),
154
155 #[cfg(feature = "usb")]
157 USBError(libusb_wishbone_tool::Error),
158
159 IoError(io::Error),
161
162 NotConnected,
164
165 InvalidAddress,
167
168 WrongResponse,
170
171 #[allow(dead_code)]
173 ProtocolNotSupported,
174
175 #[allow(dead_code)]
177 Timeout,
178}
179
180impl ::std::fmt::Display for BridgeError {
181 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
182 use BridgeError::*;
183 match self {
184 LengthError(expected, actual) => {
185 write!(f, "expected {} bytes, but got {} instead", expected, actual)
186 }
187 #[cfg(feature = "usb")]
188 USBError(e) => write!(f, "libusb error {}", e.strerror()),
189 IoError(e) => write!(f, "io error {}", e),
190 NoBridgeSpecified => write!(f, "no bridge was specified"),
191 NotConnected => write!(f, "bridge not connected"),
192 WrongResponse => write!(f, "wrong response received"),
193 InvalidAddress => write!(f, "bad address or path"),
194 ProtocolNotSupported => write!(f, "protocol not supported on this platform"),
195 Timeout => write!(f, "connection timed out"),
196 }
197 }
198}
199
200#[cfg(feature = "usb")]
201impl std::convert::From<libusb_wishbone_tool::Error> for BridgeError {
202 fn from(e: libusb_wishbone_tool::Error) -> BridgeError {
203 BridgeError::USBError(e)
204 }
205}
206
207impl std::convert::From<io::Error> for BridgeError {
208 fn from(e: io::Error) -> BridgeError {
209 BridgeError::IoError(e)
210 }
211}
212
213impl Bridge {
214 pub(crate) fn new(bridge_cfg: BridgeConfig) -> Result<Bridge, BridgeError> {
218 let mutex = Arc::new(Mutex::new(()));
219 match &bridge_cfg {
220 BridgeConfig::None => Err(BridgeError::NoBridgeSpecified),
221 #[cfg(feature = "ethernet")]
222 BridgeConfig::EthernetBridge(bridge_cfg) => Ok(Bridge {
223 mutex,
224 core: BridgeCore::EthernetBridge(EthernetBridgeInner::new(bridge_cfg)?),
225 offset: 0,
226 }),
227 #[cfg(feature = "pcie")]
228 BridgeConfig::PCIeBridge(bridge_cfg) => Ok(Bridge {
229 mutex,
230 core: BridgeCore::PCIeBridge(PCIeBridgeInner::new(bridge_cfg)?),
231 offset: 0,
232 }),
233 #[cfg(feature = "spi")]
234 BridgeConfig::SpiBridge(bridge_cfg) => Ok(Bridge {
235 mutex,
236 core: BridgeCore::SpiBridge(SpiBridgeInner::new(bridge_cfg)?),
237 offset: 0,
238 }),
239 #[cfg(feature = "uart")]
240 BridgeConfig::UartBridge(bridge_cfg) => Ok(Bridge {
241 mutex,
242 core: BridgeCore::UartBridge(UartBridgeInner::new(bridge_cfg)?),
243 offset: 0,
244 }),
245 #[cfg(feature = "usb")]
246 BridgeConfig::UsbBridge(bridge_cfg) => Ok(Bridge {
247 mutex,
248 core: BridgeCore::UsbBridge(UsbBridgeInner::new(bridge_cfg)?),
249 offset: 0,
250 }),
251 }
252 }
253
254 pub fn connect(&self) -> Result<(), BridgeError> {
258 let _mtx = self.mutex.lock().unwrap();
259 match &self.core {
260 #[cfg(feature = "ethernet")]
261 BridgeCore::EthernetBridge(b) => b.connect(),
262 #[cfg(feature = "pcie")]
263 BridgeCore::PCIeBridge(b) => b.connect(),
264 #[cfg(feature = "spi")]
265 BridgeCore::SpiBridge(b) => b.connect(),
266 #[cfg(feature = "uart")]
267 BridgeCore::UartBridge(b) => b.connect(),
268 #[cfg(feature = "usb")]
269 BridgeCore::UsbBridge(b) => b.connect(),
270 }
271 }
272
273 pub fn peek(&self, addr: u32) -> Result<u32, BridgeError> {
281 let _mtx = self.mutex.lock().unwrap();
282 loop {
283 let result = match &self.core {
284 #[cfg(feature = "ethernet")]
285 BridgeCore::EthernetBridge(b) => b.peek(addr),
286 #[cfg(feature = "pcie")]
287 BridgeCore::PCIeBridge(b) => b.peek(addr),
288 #[cfg(feature = "spi")]
289 BridgeCore::SpiBridge(b) => b.peek(addr),
290 #[cfg(feature = "uart")]
291 BridgeCore::UartBridge(b) => b.peek(addr),
292 #[cfg(feature = "usb")]
293 BridgeCore::UsbBridge(b) => b.peek(addr),
294 };
295 #[allow(unreachable_code)] if let Err(e) = result {
297 #[cfg(feature = "usb")]
298 if let BridgeError::USBError(libusb_wishbone_tool::Error::Pipe) = e {
299 debug!("USB device disconnected, forcing early return");
300 return Err(e);
301 }
302 debug!("Peek failed, trying again: {:?}", e);
303 } else {
304 return result;
305 }
306 }
307 }
308
309 pub fn poke(&self, addr: u32, value: u32) -> Result<(), BridgeError> {
318 let _mtx = self.mutex.lock().unwrap();
319 loop {
320 let result = match &self.core {
321 #[cfg(feature = "ethernet")]
322 BridgeCore::EthernetBridge(b) => b.poke(addr, value),
323 #[cfg(feature = "pcie")]
324 BridgeCore::PCIeBridge(b) => b.poke(addr, value),
325 #[cfg(feature = "spi")]
326 BridgeCore::SpiBridge(b) => b.poke(addr, value),
327 #[cfg(feature = "uart")]
328 BridgeCore::UartBridge(b) => b.poke(addr, value),
329 #[cfg(feature = "usb")]
330 BridgeCore::UsbBridge(b) => b.poke(addr, value),
331 };
332 #[allow(unreachable_code)] if let Err(e) = result {
334 match e {
335 #[cfg(feature = "usb")]
336 BridgeError::USBError(libusb_wishbone_tool::Error::Pipe) => {
337 debug!("USB device disconnected (Windows), forcing early return");
338 return Err(e);
339 }
340 #[cfg(feature = "usb")]
341 BridgeError::USBError(libusb_wishbone_tool::Error::Io) => {
342 debug!("USB device disconnected (Posix), forcing early return");
343 return Err(e);
344 }
345 _ => {}
346 }
347 debug!("Poke failed, trying again: {:?}", e);
348 } else {
349 return result;
350 }
351 }
352 }
353
354 pub fn burst_read(&self, addr: u32, length: u32) -> Result<Vec<u8>, BridgeError> {
355 let _mtx = self.mutex.lock().unwrap();
356 loop {
357 let result = match &self.core {
358 #[cfg(feature = "ethernet")]
359 BridgeCore::EthernetBridge(_b) => return Err(BridgeError::ProtocolNotSupported),
360 #[cfg(feature = "pcie")]
361 BridgeCore::PCIeBridge(_b) => return Err(BridgeError::ProtocolNotSupported),
362 #[cfg(feature = "spi")]
363 BridgeCore::SpiBridge(_b) => return Err(BridgeError::ProtocolNotSupported),
364 #[cfg(feature = "uart")]
365 BridgeCore::UartBridge(_b) => return Err(BridgeError::ProtocolNotSupported),
366 #[cfg(feature = "usb")]
367 BridgeCore::UsbBridge(b) => b.burst_read(addr, length),
368 };
369 #[allow(unreachable_code)] if let Err(e) = result {
371 #[cfg(feature = "usb")]
372 if let BridgeError::USBError(libusb_wishbone_tool::Error::Pipe) = e {
373 debug!("USB device disconnected, forcing early return");
374 return Err(e);
375 }
376 debug!("Peek failed, trying again: {:?}", e);
377 } else {
378 return result;
379 }
380 }
381 }
382
383 pub fn burst_write(&self, addr: u32, data: &Vec<u8>) -> Result<(), BridgeError> {
384 let _mtx = self.mutex.lock().unwrap();
385 loop {
386 let result = match &self.core {
387 #[cfg(feature = "ethernet")]
388 BridgeCore::EthernetBridge(_b) => return Err(BridgeError::ProtocolNotSupported),
389 #[cfg(feature = "pcie")]
390 BridgeCore::PCIeBridge(_b) => return Err(BridgeError::ProtocolNotSupported),
391 #[cfg(feature = "spi")]
392 BridgeCore::SpiBridge(_b) => return Err(BridgeError::ProtocolNotSupported),
393 #[cfg(feature = "uart")]
394 BridgeCore::UartBridge(_b) => return Err(BridgeError::ProtocolNotSupported),
395 #[cfg(feature = "usb")]
396 BridgeCore::UsbBridge(b) => b.burst_write(addr, data),
397 };
398 #[allow(unreachable_code)] if let Err(e) = result {
400 #[cfg(feature = "usb")]
401 if let BridgeError::USBError(libusb_wishbone_tool::Error::Pipe) = e {
402 debug!("USB device disconnected, forcing early return");
403 return Err(e);
404 }
405 debug!("Peek failed, trying again: {:?}", e);
406 } else {
407 return result;
408 }
409 }
410 }
411}
412
413impl std::io::Read for Bridge {
414 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
415 let _mtx = self.mutex.lock().unwrap();
416 let addr = self.offset as _;
417 use std::convert::TryInto;
418 use std::io::{Error, ErrorKind};
419
420 fn fill_array(src: &[u8], dest: &mut [u8]) -> usize {
421 let mut fill_bytes = 0;
422 for (s, d) in src.iter().zip(dest) {
423 *d = *s;
424 fill_bytes += 1;
425 }
426 fill_bytes
427 }
428
429 let copied = match &self.core {
430 #[cfg(feature = "ethernet")]
431 BridgeCore::EthernetBridge(b) => {
432 b.peek(addr).map(|v| fill_array(&v.to_le_bytes(), buf))
433 }
434 #[cfg(feature = "pcie")]
435 BridgeCore::PCIeBridge(b) => b.peek(addr).map(|v| fill_array(&v.to_le_bytes(), buf)),
436 #[cfg(feature = "spi")]
437 BridgeCore::SpiBridge(b) => b.peek(addr).map(|v| fill_array(&v.to_le_bytes(), buf)),
438 #[cfg(feature = "uart")]
439 BridgeCore::UartBridge(b) => b.peek(addr).map(|v| fill_array(&v.to_le_bytes(), buf)),
440 #[cfg(feature = "usb")]
441 BridgeCore::UsbBridge(b) => b
442 .burst_read(addr, buf.len().try_into().unwrap())
443 .map(|v| fill_array(&v, buf)),
444 }
445 .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?;
446 self.offset += copied;
447 Ok(copied)
448 }
449}
450
451impl std::io::Seek for Bridge {
452 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
453 use std::convert::TryInto;
454 use std::io::{Error, ErrorKind};
455 let new_offset = match pos {
456 std::io::SeekFrom::End(_) => Err(Error::new(
457 ErrorKind::AddrNotAvailable,
458 "cannot seek from end",
459 ))?,
460 std::io::SeekFrom::Current(add) => {
461 if add > 0 {
462 self.offset + (add as usize)
463 } else {
464 self.offset - (-add as usize)
465 }
466 }
467 std::io::SeekFrom::Start(offset) => offset as usize,
468 };
469 self.offset += new_offset;
470 Ok(self.offset.try_into().unwrap())
471 }
472}
473
474impl std::io::Write for Bridge {
475 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
476 use std::convert::TryInto;
477 use std::io::{Error, ErrorKind};
478 let _mtx = self.mutex.lock().unwrap();
479
480 fn slice_to_u32(buf: &[u8]) -> std::io::Result<u32> {
481 if buf.len() < 3 {
482 Err(Error::new(
483 ErrorKind::InvalidData,
484 "data not a multiple of 4 bytes",
485 ))?;
486 }
487 Ok(u32::from_le_bytes(buf[0..3].try_into().unwrap()))
488 }
489
490 let addr = self.offset as _;
491 let bytes_written = match &self.core {
492 #[cfg(feature = "ethernet")]
493 BridgeCore::EthernetBridge(_) => self.poke(addr, slice_to_u32(buf)?).map(|_| 4),
494 #[cfg(feature = "pcie")]
495 BridgeCore::PCIeBridge(_) => self.poke(addr, slice_to_u32(buf)?).map(|_| 4),
496 #[cfg(feature = "spi")]
497 BridgeCore::SpiBridge(_) => self.poke(addr, slice_to_u32(buf)?).map(|_| 4),
498 #[cfg(feature = "uart")]
499 BridgeCore::UartBridge(_) => self.poke(addr, slice_to_u32(buf)?).map(|_| 4),
500 #[cfg(feature = "usb")]
501 BridgeCore::UsbBridge(b) => b.burst_write(addr, buf).map(|_| buf.len()),
502 }
503 .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?;
504 self.offset += bytes_written;
505 Ok(bytes_written)
506 }
507
508 fn flush(&mut self) -> std::io::Result<()> {
509 Ok(())
510 }
511}