1use std::io::{self, Read, Write};
17use std::sync::{Arc, Mutex, PoisonError};
18use std::time::Duration;
19
20use embedded_hal::digital::{self, OutputPin};
21use embedded_hal::spi::{self, Operation, SpiDevice};
22
23use super::bridge::{
24 self, BridgeError, Bulk, Header, Identity, Replies, Status, ACK, GPIO_PORT, HEADER_LEN,
25 MAX_MESSAGE, ORDER_ERROR, ORDER_PING, ORDER_RESET, ORDER_SPI, ORDER_STATUS, ORDER_WRITE_GPIO,
26 PIN_POWER, PIN_RADIO_RESET, PIN_RESET, TARGET_CONCENTRATOR, TARGET_LISTENER,
27};
28
29#[derive(Debug)]
31pub enum UsbError {
32 Io(io::Error),
34 Bridge(BridgeError),
36 TooLong {
38 size: usize,
40 room: usize,
42 },
43 FrameTooLong {
45 len: usize,
47 },
48 Rejected,
50 Poisoned,
52}
53
54impl core::fmt::Display for UsbError {
55 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
56 match self {
57 UsbError::Io(error) => write!(f, "the port failed: {error}"),
58 UsbError::Bridge(error) => error.fmt(f),
59 UsbError::TooLong { size, room } => {
60 write!(
61 f,
62 "the bridge answered {size} bytes and there was room for {room}"
63 )
64 }
65 UsbError::FrameTooLong { len } => {
66 write!(
67 f,
68 "a {len} byte frame does not fit one message to the bridge"
69 )
70 }
71 UsbError::Rejected => f.write_str("the bridge could not read the order"),
72 UsbError::Poisoned => f.write_str("the bridge was left locked by a panic"),
73 }
74 }
75}
76
77impl std::error::Error for UsbError {}
78
79impl From<io::Error> for UsbError {
80 fn from(error: io::Error) -> UsbError {
81 UsbError::Io(error)
82 }
83}
84
85impl From<BridgeError> for UsbError {
86 fn from(error: BridgeError) -> UsbError {
87 UsbError::Bridge(error)
88 }
89}
90
91impl<T> From<PoisonError<T>> for UsbError {
92 fn from(_: PoisonError<T>) -> UsbError {
93 UsbError::Poisoned
94 }
95}
96
97impl spi::Error for UsbError {
98 fn kind(&self) -> spi::ErrorKind {
99 spi::ErrorKind::Other
100 }
101}
102
103impl digital::Error for UsbError {
104 fn kind(&self) -> digital::ErrorKind {
105 digital::ErrorKind::Other
106 }
107}
108
109pub struct Bridge<P> {
111 port: P,
112 next_id: u8,
113}
114
115impl<P: Read + Write> Bridge<P> {
116 pub fn new(port: P) -> Bridge<P> {
126 Bridge { port, next_id: 0 }
127 }
128
129 pub fn ping(&mut self) -> Result<Identity, UsbError> {
139 self.send(ORDER_PING, &[])?;
140 let mut answer = [0u8; bridge::PING_LEN];
141 let got = self.receive(ORDER_PING, &mut answer)?;
142 Ok(Identity::parse(&answer[..got])?)
143 }
144
145 pub fn status(&mut self) -> Result<Status, UsbError> {
155 self.send(ORDER_STATUS, &[])?;
156 let mut answer = [0u8; bridge::STATUS_LEN];
157 let got = self.receive(ORDER_STATUS, &mut answer)?;
158 Ok(Status::parse(&answer[..got])?)
159 }
160
161 pub fn write_gpio(&mut self, pin: u8, high: bool) -> Result<(), UsbError> {
172 self.send(ORDER_WRITE_GPIO, &bridge::write_gpio(GPIO_PORT, pin, high))?;
173 let mut answer = [0u8; 1];
174 let got = self.receive(ORDER_WRITE_GPIO, &mut answer)?;
175 Ok(bridge::took(&answer[..got])?)
176 }
177
178 pub fn reset_card(&mut self) -> Result<(), UsbError> {
184 self.send(ORDER_RESET, &bridge::reset())?;
185 let mut answer = [0u8; 1];
186 let got = self.receive(ORDER_RESET, &mut answer)?;
187 Ok(bridge::took(&answer[..got])?)
188 }
189
190 pub fn power_up(&mut self) -> Result<(), UsbError> {
199 self.write_gpio(PIN_POWER, true)?;
200 self.write_gpio(PIN_RESET, true)?;
201 self.write_gpio(PIN_RESET, false)?;
202 self.write_gpio(PIN_RADIO_RESET, false)?;
203 self.write_gpio(PIN_RADIO_RESET, true)
204 }
205
206 pub fn bulk(&mut self, bulk: &Bulk, into: &mut [u8]) -> Result<usize, UsbError> {
222 self.send(ORDER_SPI, bulk.as_bytes())?;
223 self.receive(ORDER_SPI, into)
224 }
225
226 fn send(&mut self, order: u8, payload: &[u8]) -> Result<(), UsbError> {
228 if payload.len() > MAX_MESSAGE {
229 return Err(UsbError::FrameTooLong { len: payload.len() });
230 }
231 let header = Header {
232 id: self.next_id,
233 size: payload.len() as u16,
234 order,
235 };
236 self.next_id = self.next_id.wrapping_add(1);
237 self.port.write_all(&header.to_bytes())?;
238 if !payload.is_empty() {
239 self.port.write_all(payload)?;
240 }
241 self.port.flush()?;
242 Ok(())
243 }
244
245 fn receive(&mut self, order: u8, into: &mut [u8]) -> Result<usize, UsbError> {
247 let mut raw = [0u8; HEADER_LEN];
248 self.port.read_exact(&mut raw)?;
249 let header = Header::from_bytes(raw);
250 if header.order == ORDER_ERROR {
251 return Err(UsbError::Rejected);
252 }
253 if !header.answers(order) {
254 return Err(BridgeError::WrongAnswer {
255 asked: order,
256 answered: header.order.wrapping_sub(ACK),
257 }
258 .into());
259 }
260 let size = usize::from(header.size);
261 if size > into.len() {
262 return Err(UsbError::TooLong {
263 size,
264 room: into.len(),
265 });
266 }
267 self.port.read_exact(&mut into[..size])?;
268 Ok(size)
269 }
270}
271
272pub struct Shared<P>(Arc<Mutex<Bridge<P>>>);
277
278impl<P> Clone for Shared<P> {
279 fn clone(&self) -> Shared<P> {
280 Shared(Arc::clone(&self.0))
281 }
282}
283
284impl<P: Read + Write> Shared<P> {
285 pub fn new(bridge: Bridge<P>) -> Shared<P> {
295 Shared(Arc::new(Mutex::new(bridge)))
296 }
297
298 pub fn concentrator(&self) -> BridgeSpi<P> {
305 BridgeSpi {
306 bridge: self.clone(),
307 target: TARGET_CONCENTRATOR,
308 }
309 }
310
311 pub fn listener(&self) -> BridgeSpi<P> {
317 BridgeSpi {
318 bridge: self.clone(),
319 target: TARGET_LISTENER,
320 }
321 }
322
323 pub fn pin(&self, pin: u8) -> BridgePin<P> {
333 BridgePin {
334 bridge: self.clone(),
335 pin,
336 }
337 }
338
339 pub fn with<T>(
353 &self,
354 with: impl FnOnce(&mut Bridge<P>) -> Result<T, UsbError>,
355 ) -> Result<T, UsbError> {
356 let mut bridge = self.0.lock()?;
357 with(&mut bridge)
358 }
359}
360
361pub struct BridgeSpi<P> {
363 bridge: Shared<P>,
364 target: u8,
365}
366
367impl<P> spi::ErrorType for BridgeSpi<P> {
368 type Error = UsbError;
369}
370
371impl<P: Read + Write> SpiDevice<u8> for BridgeSpi<P> {
372 fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), UsbError> {
377 let mut frame = Vec::new();
378 for operation in operations.iter() {
379 match operation {
380 Operation::Write(bytes) | Operation::Transfer(_, bytes) => {
381 frame.extend_from_slice(bytes);
382 }
383 Operation::Read(buffer) => frame.resize(frame.len() + buffer.len(), 0),
384 Operation::TransferInPlace(buffer) => frame.extend_from_slice(buffer),
385 Operation::DelayNs(_) => {}
386 }
387 }
388 if frame.len() + 5 > bridge::BULK_CHUNK {
389 return Err(UsbError::FrameTooLong { len: frame.len() });
390 }
391
392 let mut bulk = Bulk::new();
393 bulk.transfer(self.target, &frame)?;
394 let mut answer = vec![0u8; frame.len() + 5];
395 let got = self.bridge.with(|bridge| bridge.bulk(&bulk, &mut answer))?;
396
397 let echoed = Replies::new(&answer[..got])
398 .next()
399 .ok_or(BridgeError::Short { got, needs: 5 })??
400 .frame;
401 if echoed.len() < frame.len() {
402 return Err(BridgeError::Short {
403 got: echoed.len(),
404 needs: frame.len(),
405 }
406 .into());
407 }
408
409 let mut at = 0;
410 for operation in operations.iter_mut() {
411 match operation {
412 Operation::Write(bytes) => at += bytes.len(),
413 Operation::Transfer(read, write) => {
414 let take = read.len().min(write.len());
415 read[..take].copy_from_slice(&echoed[at..at + take]);
416 at += write.len();
417 }
418 Operation::Read(buffer) => {
419 buffer.copy_from_slice(&echoed[at..at + buffer.len()]);
420 at += buffer.len();
421 }
422 Operation::TransferInPlace(buffer) => {
423 buffer.copy_from_slice(&echoed[at..at + buffer.len()]);
424 at += buffer.len();
425 }
426 Operation::DelayNs(ns) => std::thread::sleep(Duration::from_nanos(u64::from(*ns))),
427 }
428 }
429 Ok(())
430 }
431}
432
433pub struct BridgePin<P> {
435 bridge: Shared<P>,
436 pin: u8,
437}
438
439impl<P> digital::ErrorType for BridgePin<P> {
440 type Error = UsbError;
441}
442
443impl<P: Read + Write> OutputPin for BridgePin<P> {
444 fn set_low(&mut self) -> Result<(), UsbError> {
445 let pin = self.pin;
446 self.bridge.with(|bridge| bridge.write_gpio(pin, false))
447 }
448
449 fn set_high(&mut self) -> Result<(), UsbError> {
450 let pin = self.pin;
451 self.bridge.with(|bridge| bridge.write_gpio(pin, true))
452 }
453}
454
455#[cfg(test)]
456mod tests {
457 use super::*;
458 use crate::sx1302::spi as frame;
459 use std::collections::VecDeque;
460
461 struct FakePort {
463 written: Vec<u8>,
464 answers: VecDeque<u8>,
465 }
466
467 impl FakePort {
468 fn answering(answers: &[&[u8]]) -> FakePort {
469 FakePort {
470 written: Vec::new(),
471 answers: answers.iter().flat_map(|a| a.iter().copied()).collect(),
472 }
473 }
474 }
475
476 impl Read for FakePort {
477 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
478 let mut n = 0;
479 while n < buf.len() {
480 match self.answers.pop_front() {
481 Some(byte) => {
482 buf[n] = byte;
483 n += 1;
484 }
485 None => break,
486 }
487 }
488 Ok(n)
489 }
490 }
491
492 impl Write for FakePort {
493 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
494 self.written.extend_from_slice(buf);
495 Ok(buf.len())
496 }
497 fn flush(&mut self) -> io::Result<()> {
498 Ok(())
499 }
500 }
501
502 fn answer(order: u8, payload: &[u8]) -> Vec<u8> {
503 let mut out = Header {
504 id: 0,
505 size: payload.len() as u16,
506 order: order + ACK,
507 }
508 .to_bytes()
509 .to_vec();
510 out.extend_from_slice(payload);
511 out
512 }
513
514 #[test]
515 fn a_ping_goes_out_as_an_empty_message_and_the_identity_comes_back() {
516 let mut ping = [0u8; bridge::PING_LEN];
517 ping[12..].copy_from_slice(b"V01.00.00");
518 let mut bridge = Bridge::new(FakePort::answering(&[&answer(ORDER_PING, &ping)]));
519
520 let identity = bridge.ping().expect("the bridge answers");
521 assert!(identity.matches_firmware());
522 assert_eq!(bridge.port.written, [0, 0, 0, ORDER_PING], "no payload");
523 }
524
525 #[test]
526 fn a_register_read_through_the_driver_path_finds_the_chip_id() {
527 let out = frame::read(frame::TARGET_CONCENTRATOR, 0x5600);
530 let mut echoed = out.to_vec();
531 *echoed.last_mut().unwrap() = 0x60;
532 let mut reply = vec![0u8, 0x01, 0, 0, echoed.len() as u8];
533 reply.extend_from_slice(&echoed);
534
535 let shared = Shared::new(Bridge::new(FakePort::answering(&[&answer(
536 ORDER_SPI, &reply,
537 )])));
538 let mut spi = shared.concentrator();
539
540 let mut back = [0u8; frame::READ_LEN];
541 spi.transfer(&mut back, &out).expect("the transfer runs");
542 assert_eq!(frame::read_value(&back), Some(0x60));
543
544 let written = shared.with(|b| Ok(b.port.written.clone())).unwrap();
547 assert_eq!(&written[..4], &[0, 0, (5 + out.len()) as u8, ORDER_SPI]);
548 assert_eq!(
549 &written[4..9],
550 &[0, 0x01, TARGET_CONCENTRATOR, 0, out.len() as u8]
551 );
552 assert_eq!(&written[9..], &out);
553 }
554
555 #[test]
556 fn a_burst_read_is_one_frame_and_the_read_takes_its_own_slice_of_the_echo() {
557 let header = frame::burst_read_header(frame::TARGET_CONCENTRATOR, 0x1000);
558 let data = [0x11u8, 0x22, 0x33];
559 let mut echoed = header.to_vec();
560 echoed.extend_from_slice(&data);
561 let mut reply = vec![0u8, 0x01, 0, 0, echoed.len() as u8];
562 reply.extend_from_slice(&echoed);
563
564 let shared = Shared::new(Bridge::new(FakePort::answering(&[&answer(
565 ORDER_SPI, &reply,
566 )])));
567 let mut spi = shared.concentrator();
568
569 let mut buffer = [0u8; 3];
570 spi.transaction(&mut [Operation::Write(&header), Operation::Read(&mut buffer)])
571 .expect("the transfer runs");
572 assert_eq!(buffer, data);
573 }
574
575 #[test]
576 fn the_second_radio_goes_out_under_its_own_target() {
577 let out = [0xc0u8, 0x00];
578 let mut reply = vec![0u8, 0x01, 0, 0, 2];
579 reply.extend_from_slice(&[0xc0, 0x22]);
580 let shared = Shared::new(Bridge::new(FakePort::answering(&[&answer(
581 ORDER_SPI, &reply,
582 )])));
583 let mut spi = shared.listener();
584
585 let mut back = [0u8; 2];
586 spi.transfer(&mut back, &out).unwrap();
587 let written = shared.with(|b| Ok(b.port.written.clone())).unwrap();
588 assert_eq!(written[6], TARGET_LISTENER);
589 }
590
591 #[test]
592 fn a_pin_write_is_a_port_a_pin_and_a_level_and_a_refusal_is_an_error() {
593 let shared = Shared::new(Bridge::new(FakePort::answering(&[
594 &answer(ORDER_WRITE_GPIO, &[0]),
595 &answer(ORDER_WRITE_GPIO, &[1]),
596 ])));
597 let mut reset = shared.pin(PIN_RESET);
598
599 reset.set_high().expect("the bridge took it");
600 let written = shared.with(|b| Ok(b.port.written.clone())).unwrap();
601 assert_eq!(&written[4..], &[GPIO_PORT, PIN_RESET, 1]);
602
603 assert!(matches!(
604 reset.set_low(),
605 Err(UsbError::Bridge(BridgeError::Refused { status: 1 }))
606 ));
607 }
608
609 #[test]
610 fn powering_up_pulses_the_pins_in_the_order_the_reference_does() {
611 let ok = answer(ORDER_WRITE_GPIO, &[0]);
612 let mut bridge = Bridge::new(FakePort::answering(&[&ok, &ok, &ok, &ok, &ok]));
613 bridge.power_up().expect("every write takes");
614
615 let pins: Vec<[u8; 3]> = bridge
616 .port
617 .written
618 .chunks(7)
619 .map(|message| [message[4], message[5], message[6]])
620 .collect();
621 assert_eq!(
622 pins,
623 [
624 [0, PIN_POWER, 1],
625 [0, PIN_RESET, 1],
626 [0, PIN_RESET, 0],
627 [0, PIN_RADIO_RESET, 0],
628 [0, PIN_RADIO_RESET, 1],
629 ]
630 );
631 }
632
633 #[test]
634 fn an_answer_to_a_different_order_is_refused() {
635 let mut bridge = Bridge::new(FakePort::answering(&[&answer(ORDER_PING, &[0u8; 21])]));
636 assert!(matches!(
637 bridge.status(),
638 Err(UsbError::Bridge(BridgeError::WrongAnswer {
639 asked: ORDER_STATUS,
640 answered: ORDER_PING
641 }))
642 ));
643
644 let mut bridge = Bridge::new(FakePort::answering(&[&[0u8, 0, 0, ORDER_ERROR]]));
645 assert!(matches!(bridge.ping(), Err(UsbError::Rejected)));
646 }
647
648 #[test]
649 fn message_identifiers_count_up_so_a_trace_can_be_followed() {
650 let ok = answer(ORDER_WRITE_GPIO, &[0]);
651 let mut bridge = Bridge::new(FakePort::answering(&[&ok, &ok, &ok]));
652 for _ in 0..3 {
653 bridge.write_gpio(PIN_POWER, true).unwrap();
654 }
655 let ids: Vec<u8> = bridge.port.written.chunks(7).map(|m| m[0]).collect();
656 assert_eq!(ids, [0, 1, 2]);
657 }
658}