1use core::sync::atomic::{AtomicU8, Ordering};
15
16use embassy_sync::blocking_mutex::raw::RawMutex;
17use embassy_sync::mutex::Mutex;
18use embassy_time::{Duration, with_timeout};
19use embedded_hal_async::i2c::{Error as _, ErrorKind, I2c, NoAcknowledgeSource, Operation};
20use umsh_ulcp::Status;
21use umsh_ulcp::i2c::{Op, ScanRequest, TransferRequest, TransferShape};
22use umsh_ulcp_device::{I2C_DATA_MAX, I2C_MAX_OPS};
23
24pub async fn transfer_with<I: I2c>(
34 bus: &mut I,
35 request: TransferRequest<'_>,
36 out: &mut [u8],
37) -> Result<usize, Status> {
38 let mut writes = [0u8; I2C_DATA_MAX];
39 let mut written = 0;
40 for op in request.ops() {
41 if let Op::Write(data) = op.map_err(|error| error.status())? {
42 let end = written + data.len();
43 writes
44 .get_mut(written..end)
45 .ok_or(Status::INVALID_ARGUMENT)?
46 .copy_from_slice(data);
47 written = end;
48 }
49 }
50 let mut write_rest = &writes[..written];
51 let mut operations: heapless::Vec<Operation<'_>, I2C_MAX_OPS> = heapless::Vec::new();
52 let mut rest = out;
53 let mut read_len = 0usize;
54 let mut ops = request.ops().peekable();
55 while let Some(op) = ops.next() {
56 let operation = match op.map_err(|error| error.status())? {
57 Op::Write(data) => {
58 let mut len = data.len();
59 while let Some(Ok(Op::Write(next))) = ops.peek() {
60 len += next.len();
61 ops.next();
62 }
63 let (head, tail) = write_rest.split_at(len);
64 write_rest = tail;
65 Operation::Write(head)
66 }
67 Op::Read(mut len) => {
68 while let Some(Ok(Op::Read(next))) = ops.peek() {
69 len = len.checked_add(*next).ok_or(Status::NOMEM)?;
70 ops.next();
71 }
72 if rest.len() < len {
73 return Err(Status::NOMEM);
74 }
75 let (head, tail) = core::mem::take(&mut rest).split_at_mut(len);
76 rest = tail;
77 read_len += len;
78 Operation::Read(head)
79 }
80 };
81 operations
82 .push(operation)
83 .map_err(|_| Status::INVALID_ARGUMENT)?;
84 }
85 bus.transaction(request.addr, &mut operations)
86 .await
87 .map_err(|error| status_for(error.kind()))?;
88 Ok(read_len)
89}
90
91pub async fn scan_with<I: I2c>(
99 bus: &mut I,
100 request: ScanRequest,
101 out: &mut [u8],
102) -> Result<usize, Status> {
103 let mut found = 0usize;
104 for addr in request.first..=request.last {
105 let mut probe = [0u8; 1];
106 match bus.read(addr, &mut probe).await {
107 Ok(()) => {
108 let slot = out.get_mut(found).ok_or(Status::NOMEM)?;
109 *slot = addr;
110 found += 1;
111 }
112 Err(error) => match error.kind() {
113 ErrorKind::NoAcknowledge(_) => {}
114 other => return Err(status_for(other)),
115 },
116 }
117 }
118 Ok(found)
119}
120
121pub const fn status_for(kind: ErrorKind) -> Status {
128 match kind {
129 ErrorKind::NoAcknowledge(NoAcknowledgeSource::Address) => Status::NO_DEVICE,
130 ErrorKind::NoAcknowledge(_) => Status::NACK,
131 _ => Status::BUS_ERROR,
132 }
133}
134
135pub struct Reservation(AtomicU8);
147
148impl Reservation {
149 const NONE: u8 = 0xFF;
150
151 pub const fn new() -> Self {
152 Self(AtomicU8::new(Self::NONE))
153 }
154
155 #[must_use = "the reservation lasts as long as the guard"]
158 pub fn hold(&self, addr: u8) -> Held<'_> {
159 self.0.store(addr, Ordering::Release);
160 Held(self)
161 }
162
163 pub fn holds(&self, addr: u8) -> bool {
165 let held = self.0.load(Ordering::Acquire);
166 held != Self::NONE && held == addr
167 }
168
169 pub fn covers(&self, range: &ScanRequest) -> bool {
171 let held = self.0.load(Ordering::Acquire);
172 held != Self::NONE && range.covers(held)
173 }
174}
175
176impl Default for Reservation {
177 fn default() -> Self {
178 Self::new()
179 }
180}
181
182pub struct Held<'a>(&'a Reservation);
184
185impl Drop for Held<'_> {
186 fn drop(&mut self) {
187 self.0.0.store(Reservation::NONE, Ordering::Release);
188 }
189}
190
191pub trait Reservations {
193 fn holds(&self, addr: u8) -> bool;
194 fn covers(&self, range: &ScanRequest) -> bool;
195}
196
197impl Reservations for Reservation {
198 fn holds(&self, addr: u8) -> bool {
199 Reservation::holds(self, addr)
200 }
201 fn covers(&self, range: &ScanRequest) -> bool {
202 Reservation::covers(self, range)
203 }
204}
205
206impl<const N: usize> Reservations for [&Reservation; N] {
207 fn holds(&self, addr: u8) -> bool {
208 self.iter().any(|r| r.holds(addr))
209 }
210 fn covers(&self, range: &ScanRequest) -> bool {
211 self.iter().any(|r| r.covers(range))
212 }
213}
214
215const DEADLINE_FLOOR: Duration = Duration::from_millis(100);
219
220pub const fn deadline_for(octets: usize, speed_khz: u16) -> Duration {
227 let speed_khz = if speed_khz == 0 { 1 } else { speed_khz as u64 };
230 let nominal_us = (octets as u64 * 9 * 1000) / speed_khz;
231 Duration::from_micros(DEADLINE_FLOOR.as_micros() + 10 * nominal_us)
232}
233
234pub const fn transfer_deadline(shape: TransferShape, speed_khz: u16) -> Duration {
237 deadline_for(shape.data_len + shape.ops + 1, speed_khz)
238}
239
240pub const fn scan_deadline(request: &ScanRequest, speed_khz: u16) -> Duration {
243 deadline_for(request.len() * 2, speed_khz)
244}
245
246pub async fn guarded_transfer<M: RawMutex, I: I2c>(
257 bus: &Mutex<M, I>,
258 reserved: &impl Reservations,
259 lock_timeout: Duration,
260 deadline: Duration,
261 request: TransferRequest<'_>,
262 out: &mut [u8],
263) -> Result<usize, Status> {
264 let mut bus = with_timeout(lock_timeout, bus.lock())
265 .await
266 .map_err(|_| Status::BUSY)?;
267 if reserved.holds(request.addr) {
268 return Err(Status::BUSY);
269 }
270 with_timeout(deadline, transfer_with(&mut *bus, request, out))
271 .await
272 .map_err(|_| Status::BUS_ERROR)?
273}
274
275pub async fn guarded_scan<M: RawMutex, I: I2c>(
279 bus: &Mutex<M, I>,
280 reserved: &impl Reservations,
281 lock_timeout: Duration,
282 deadline: Duration,
283 request: ScanRequest,
284 out: &mut [u8],
285) -> Result<usize, Status> {
286 let mut bus = with_timeout(lock_timeout, bus.lock())
287 .await
288 .map_err(|_| Status::BUSY)?;
289 if reserved.covers(&request) {
290 return Err(Status::BUSY);
291 }
292 with_timeout(deadline, scan_with(&mut *bus, request, out))
293 .await
294 .map_err(|_| Status::BUS_ERROR)?
295}
296
297#[cfg(test)]
298mod tests {
299 use super::*;
300 use core::pin::pin;
301 use core::task::{Context, Poll, Waker};
302 use embassy_futures::block_on;
303 use embassy_sync::blocking_mutex::raw::NoopRawMutex;
304 use embedded_hal_async::i2c::ErrorType;
305 use std::vec::Vec;
306
307 const LOCK_TIMEOUT: Duration = Duration::from_millis(30);
308 const DEADLINE: Duration = Duration::from_millis(30);
309 const NEVER: Duration = Duration::from_secs(60);
311
312 struct Expected {
315 addr: u8,
316 ops: Vec<(bool, Vec<u8>)>,
317 result: Result<(), ErrorKind>,
318 }
319
320 #[derive(Default)]
321 struct Bus {
322 expected: std::collections::VecDeque<Expected>,
323 transactions: usize,
324 }
325
326 impl ErrorType for Bus {
327 type Error = ErrorKind;
328 }
329
330 impl I2c for Bus {
331 async fn transaction(
332 &mut self,
333 address: u8,
334 operations: &mut [Operation<'_>],
335 ) -> Result<(), Self::Error> {
336 self.transactions += 1;
337 let expected = self.expected.pop_front().expect("unexpected transaction");
338 assert_eq!(address, expected.addr);
339 assert_eq!(operations.len(), expected.ops.len(), "operation count");
340 for (operation, (is_read, octets)) in operations.iter_mut().zip(&expected.ops) {
341 match operation {
342 Operation::Write(data) => {
343 assert!(!is_read, "expected a read");
344 assert_eq!(*data, octets.as_slice());
345 }
346 Operation::Read(buffer) => {
347 assert!(*is_read, "expected a write");
348 assert_eq!(buffer.len(), octets.len());
349 buffer.copy_from_slice(octets);
350 }
351 }
352 }
353 expected.result
354 }
355 }
356
357 fn request(bus: u8, addr: u8, ops: &[Op<'_>]) -> Vec<u8> {
358 let mut buf = [0u8; 300];
359 let len = umsh_ulcp::i2c::encode_transfer(&mut buf, 0, bus, addr, ops).unwrap();
360 buf[2..len].to_vec()
363 }
364
365 #[test]
366 fn reads_are_carved_out_of_the_result_in_order() {
367 let mut bus = Bus::default();
368 bus.expected.push_back(Expected {
369 addr: 0x55,
370 ops: vec![
371 (false, vec![0x08]),
372 (true, vec![0x34, 0x12]),
373 (false, vec![0x0A]),
374 (true, vec![0xEF, 0xBE, 0xAD]),
375 ],
376 result: Ok(()),
377 });
378 let payload = request(
379 0,
380 0x55,
381 &[
382 Op::Write(&[0x08]),
383 Op::Read(2),
384 Op::Write(&[0x0A]),
385 Op::Read(3),
386 ],
387 );
388 let request = TransferRequest::parse(&payload).unwrap();
389 let mut out = [0u8; 8];
390 let len = block_on(transfer_with(&mut bus, request, &mut out)).unwrap();
391 assert_eq!(&out[..len], &[0x34, 0x12, 0xEF, 0xBE, 0xAD]);
392 assert_eq!(bus.transactions, 1);
393 }
394
395 #[test]
396 fn consecutive_reads_and_writes_are_merged_without_crossing_direction_changes() {
397 let cases = [
398 (
399 vec![Op::Read(2), Op::Read(2)],
400 vec![(true, vec![1, 2, 3, 4])],
401 vec![1, 2, 3, 4],
402 ),
403 (
404 vec![Op::Write(&[8]), Op::Write(&[9, 10])],
405 vec![(false, vec![8, 9, 10])],
406 vec![],
407 ),
408 (
409 vec![
410 Op::Read(1),
411 Op::Read(2),
412 Op::Write(&[8]),
413 Op::Write(&[9, 10]),
414 Op::Read(2),
415 Op::Read(1),
416 ],
417 vec![
418 (true, vec![1, 2, 3]),
419 (false, vec![8, 9, 10]),
420 (true, vec![4, 5, 6]),
421 ],
422 vec![1, 2, 3, 4, 5, 6],
423 ),
424 ];
425 for (ops, expected, read) in cases {
426 let mut bus = Bus::default();
427 bus.expected.push_back(Expected {
428 addr: 0x55,
429 ops: expected,
430 result: Ok(()),
431 });
432 let payload = request(0, 0x55, &ops);
433 let request = TransferRequest::parse(&payload).unwrap();
434 let mut out = [0xFF; 8];
435 let len = block_on(transfer_with(&mut bus, request, &mut out)).unwrap();
436 assert_eq!(&out[..len], read);
437 assert!(out[len..].iter().all(|byte| *byte == 0xFF));
438 assert_eq!(bus.transactions, 1);
439 }
440 }
441
442 #[test]
443 fn merged_writes_fill_the_entire_transfer_limit() {
444 let first = [0xA5; 127];
445 let second = [0x5A; 128];
446 let expected = [first.as_slice(), second.as_slice()].concat();
447 let mut bus = Bus::default();
448 bus.expected.push_back(Expected {
449 addr: 0x55,
450 ops: vec![(false, expected)],
451 result: Ok(()),
452 });
453 let payload = request(0, 0x55, &[Op::Write(&first), Op::Write(&second)]);
454 let request = TransferRequest::parse(&payload).unwrap();
455 assert_eq!(block_on(transfer_with(&mut bus, request, &mut [])), Ok(0));
456 assert_eq!(bus.transactions, 1);
457 }
458
459 #[test]
460 fn merged_reads_check_the_combined_output_capacity_before_the_bus() {
461 let mut bus = Bus::default();
462 let payload = request(0, 0x55, &[Op::Read(2), Op::Read(3)]);
463 let request = TransferRequest::parse(&payload).unwrap();
464 let mut out = [0u8; 4];
465 assert_eq!(
466 block_on(transfer_with(&mut bus, request, &mut out)),
467 Err(Status::NOMEM)
468 );
469 assert_eq!(bus.transactions, 0);
470 }
471
472 #[test]
473 fn a_write_only_transfer_reads_nothing() {
474 let mut bus = Bus::default();
475 bus.expected.push_back(Expected {
476 addr: 0x6B,
477 ops: vec![(false, vec![0x00, 0x14])],
478 result: Ok(()),
479 });
480 let payload = request(0, 0x6B, &[Op::Write(&[0x00, 0x14])]);
481 let request = TransferRequest::parse(&payload).unwrap();
482 let mut out = [0u8; 4];
483 assert_eq!(
484 block_on(transfer_with(&mut bus, request, &mut out)).unwrap(),
485 0
486 );
487 }
488
489 #[test]
490 fn bus_errors_become_the_statuses_the_table_names() {
491 let cases = [
492 (
493 ErrorKind::NoAcknowledge(NoAcknowledgeSource::Address),
494 Status::NO_DEVICE,
495 ),
496 (
497 ErrorKind::NoAcknowledge(NoAcknowledgeSource::Data),
498 Status::NACK,
499 ),
500 (
501 ErrorKind::NoAcknowledge(NoAcknowledgeSource::Unknown),
502 Status::NACK,
503 ),
504 (ErrorKind::Bus, Status::BUS_ERROR),
505 (ErrorKind::ArbitrationLoss, Status::BUS_ERROR),
506 (ErrorKind::Overrun, Status::BUS_ERROR),
507 (ErrorKind::Other, Status::BUS_ERROR),
508 ];
509 for (kind, status) in cases {
510 assert_eq!(status_for(kind), status, "{kind:?}");
511 let mut bus = Bus::default();
512 bus.expected.push_back(Expected {
513 addr: 0x50,
514 ops: vec![(true, vec![0])],
515 result: Err(kind),
516 });
517 let payload = request(0, 0x50, &[Op::Read(1)]);
518 let request = TransferRequest::parse(&payload).unwrap();
519 let mut out = [0u8; 4];
520 assert_eq!(
521 block_on(transfer_with(&mut bus, request, &mut out)),
522 Err(status)
523 );
524 }
525 }
526
527 #[test]
528 fn a_result_buffer_too_small_is_refused_before_the_bus() {
529 let mut bus = Bus::default();
530 let payload = request(0, 0x50, &[Op::Read(5)]);
531 let request = TransferRequest::parse(&payload).unwrap();
532 let mut out = [0u8; 4];
533 assert_eq!(
534 block_on(transfer_with(&mut bus, request, &mut out)),
535 Err(Status::NOMEM)
536 );
537 assert_eq!(bus.transactions, 0);
538 }
539
540 #[test]
541 fn a_scan_reports_who_acknowledged_and_skips_who_did_not() {
542 let mut bus = Bus::default();
543 for addr in 0x50..=0x53u8 {
544 bus.expected.push_back(Expected {
545 addr,
546 ops: vec![(true, vec![0])],
547 result: if addr % 2 == 0 {
548 Ok(())
549 } else {
550 Err(ErrorKind::NoAcknowledge(NoAcknowledgeSource::Address))
551 },
552 });
553 }
554 let mut out = [0u8; 8];
555 let request = ScanRequest {
556 bus: 0,
557 first: 0x50,
558 last: 0x53,
559 };
560 let len = block_on(scan_with(&mut bus, request, &mut out)).unwrap();
561 assert_eq!(&out[..len], &[0x50, 0x52]);
562 assert_eq!(bus.transactions, 4);
563 }
564
565 #[test]
566 fn a_scan_stops_at_the_first_bus_error() {
567 let mut bus = Bus::default();
568 bus.expected.push_back(Expected {
569 addr: 0x50,
570 ops: vec![(true, vec![0])],
571 result: Ok(()),
572 });
573 bus.expected.push_back(Expected {
574 addr: 0x51,
575 ops: vec![(true, vec![0])],
576 result: Err(ErrorKind::ArbitrationLoss),
577 });
578 let mut out = [0u8; 8];
579 let request = ScanRequest {
580 bus: 0,
581 first: 0x50,
582 last: 0x5F,
583 };
584 assert_eq!(
585 block_on(scan_with(&mut bus, request, &mut out)),
586 Err(Status::BUS_ERROR)
587 );
588 assert_eq!(bus.transactions, 2);
589 }
590 struct Stuck;
593
594 impl ErrorType for Stuck {
595 type Error = ErrorKind;
596 }
597
598 impl I2c for Stuck {
599 async fn transaction(
600 &mut self,
601 _address: u8,
602 _operations: &mut [Operation<'_>],
603 ) -> Result<(), Self::Error> {
604 core::future::pending().await
605 }
606 }
607
608 fn poll_once<F: core::future::Future>(fut: core::pin::Pin<&mut F>) -> Poll<F::Output> {
609 fut.poll(&mut Context::from_waker(Waker::noop()))
610 }
611
612 fn successful_probe(addr: u8) -> Expected {
613 Expected {
614 addr,
615 ops: vec![(true, vec![0])],
616 result: Ok(()),
617 }
618 }
619
620 #[test]
621 fn independent_procedures_reserve_without_replacing_the_gauge() {
622 let bus: Mutex<NoopRawMutex, Bus> = Mutex::new(Bus::default());
623 let gauge = Reservation::new();
624 let codec = Reservation::new();
625 let haptic = Reservation::new();
626 let reservations = [&gauge, &codec, &haptic];
627 let _gauge = gauge.hold(0x55);
628 let codec_guard = codec.hold(0x18);
629 let _haptic = haptic.hold(0x5a);
630 for addr in [0x55, 0x18, 0x5a] {
631 let payload = request(0, addr, &[Op::Write(&[0])]);
632 let req = TransferRequest::parse(&payload).unwrap();
633 assert_eq!(
634 block_on(guarded_transfer(
635 &bus,
636 &reservations,
637 NEVER,
638 NEVER,
639 req,
640 &mut []
641 )),
642 Err(Status::BUSY)
643 );
644 }
645 drop(codec_guard);
646 assert!(!reservations.holds(0x18));
647 assert!(reservations.holds(0x55));
648 assert!(reservations.holds(0x5a));
649 assert!(!reservations.holds(0x34));
650 }
651
652 #[test]
656 fn a_transfer_parked_on_the_bus_sees_a_reservation_published_meanwhile() {
657 let bus: Mutex<NoopRawMutex, Bus> = Mutex::new(Bus::default());
658 let reserved = Reservation::new();
659 let codec = Reservation::new();
660 let _codec = codec.hold(0x18);
661 let reservations = [&reserved, &codec];
662 let payload = request(0, 0x55, &[Op::Write(&[0x00]), Op::Read(2)]);
663 let transfer = TransferRequest::parse(&payload).unwrap();
664 let mut out = [0u8; 4];
665
666 let holder = block_on(bus.lock());
668 let held = {
669 let mut fut = pin!(guarded_transfer(
671 &bus,
672 &reservations,
673 NEVER,
674 NEVER,
675 transfer,
676 &mut out
677 ));
678 assert!(poll_once(fut.as_mut()).is_pending(), "waiting for the bus");
679 let held = reserved.hold(0x55);
681 drop(holder);
682 assert_eq!(block_on(fut.as_mut()), Err(Status::BUSY));
684 held
685 };
686 assert_eq!(block_on(bus.lock()).transactions, 0);
687 drop(held);
689 block_on(bus.lock()).expected.push_back(Expected {
690 addr: 0x55,
691 ops: vec![(false, vec![0x00]), (true, vec![0xAA, 0xBB])],
692 result: Ok(()),
693 });
694 let len = block_on(guarded_transfer(
695 &bus,
696 &reservations,
697 NEVER,
698 NEVER,
699 transfer,
700 &mut out,
701 ))
702 .unwrap();
703 assert_eq!(&out[..len], &[0xAA, 0xBB]);
704 }
705
706 #[test]
707 fn a_scan_parked_on_the_bus_is_refused_whole_when_its_range_covers_the_reservation() {
708 let bus: Mutex<NoopRawMutex, Bus> = Mutex::new(Bus::default());
709 let reserved = Reservation::new();
710 let codec = Reservation::new();
711 let _codec = codec.hold(0x18);
712 let reservations = [&reserved, &codec];
713 let scan = ScanRequest {
714 bus: 0,
715 first: 0x50,
716 last: 0x57,
717 };
718 let mut out = [0u8; 8];
719
720 let holder = block_on(bus.lock());
721 let held = {
722 let mut fut = pin!(guarded_scan(
723 &bus,
724 &reservations,
725 NEVER,
726 NEVER,
727 scan,
728 &mut out
729 ));
730 assert!(poll_once(fut.as_mut()).is_pending());
731 let held = reserved.hold(0x55);
732 drop(holder);
733 assert_eq!(block_on(fut.as_mut()), Err(Status::BUSY));
734 held
735 };
736 assert_eq!(
737 block_on(bus.lock()).transactions,
738 0,
739 "no address was probed"
740 );
741
742 drop(held);
743 for addr in 0x50..=0x57u8 {
744 block_on(bus.lock())
745 .expected
746 .push_back(successful_probe(addr));
747 }
748 let len = block_on(guarded_scan(
749 &bus,
750 &reservations,
751 NEVER,
752 NEVER,
753 scan,
754 &mut out,
755 ))
756 .unwrap();
757 assert_eq!(len, 8);
758 }
759
760 #[test]
761 fn a_reservation_elsewhere_on_the_bus_does_not_get_in_the_way() {
762 let bus: Mutex<NoopRawMutex, Bus> = Mutex::new(Bus::default());
763 let reserved = Reservation::new();
764 let _held = reserved.hold(0x55);
765 block_on(bus.lock()).expected.push_back(Expected {
766 addr: 0x6B,
767 ops: vec![(false, vec![0x00, 0x14])],
768 result: Ok(()),
769 });
770 let payload = request(0, 0x6B, &[Op::Write(&[0x00, 0x14])]);
771 let transfer = TransferRequest::parse(&payload).unwrap();
772 let mut out = [0u8; 8];
773 assert_eq!(
774 block_on(guarded_transfer(
775 &bus, &reserved, NEVER, NEVER, transfer, &mut out
776 )),
777 Ok(0)
778 );
779 let scan = ScanRequest {
781 bus: 0,
782 first: 0x50,
783 last: 0x54,
784 };
785 for addr in 0x50..=0x54u8 {
786 block_on(bus.lock())
787 .expected
788 .push_back(successful_probe(addr));
789 }
790 assert_eq!(
791 block_on(guarded_scan(&bus, &reserved, NEVER, NEVER, scan, &mut out)),
792 Ok(5)
793 );
794 }
795
796 #[test]
797 fn the_guard_releases_the_reservation_on_every_exit() {
798 let reserved = Reservation::new();
799 {
800 let _held = reserved.hold(0x55);
801 assert!(reserved.holds(0x55));
802 assert!(!reserved.holds(0x54));
803 }
804 assert!(!reserved.holds(0x55));
805 assert!(!reserved.holds(0xFF));
807 assert!(!reserved.covers(&ScanRequest {
808 bus: 0,
809 first: 0x00,
810 last: 0x7F,
811 }));
812 }
813
814 #[test]
815 fn a_bus_that_stays_busy_is_reported_as_busy_not_as_broken() {
816 let bus: Mutex<NoopRawMutex, Bus> = Mutex::new(Bus::default());
817 let reserved = Reservation::new();
818 let _holder = block_on(bus.lock());
819 let payload = request(0, 0x50, &[Op::Read(1)]);
820 let transfer = TransferRequest::parse(&payload).unwrap();
821 let mut out = [0u8; 4];
822 assert_eq!(
823 block_on(guarded_transfer(
824 &bus,
825 &reserved,
826 LOCK_TIMEOUT,
827 NEVER,
828 transfer,
829 &mut out
830 )),
831 Err(Status::BUSY)
832 );
833 }
834
835 #[test]
836 fn a_transaction_that_never_completes_is_a_bus_error_and_frees_the_bus() {
837 let bus: Mutex<NoopRawMutex, Stuck> = Mutex::new(Stuck);
838 let reserved = Reservation::new();
839 let payload = request(0, 0x50, &[Op::Read(1)]);
840 let transfer = TransferRequest::parse(&payload).unwrap();
841 let mut out = [0u8; 4];
842 assert_eq!(
843 block_on(guarded_transfer(
844 &bus, &reserved, NEVER, DEADLINE, transfer, &mut out
845 )),
846 Err(Status::BUS_ERROR)
847 );
848 let scan = ScanRequest::new(0);
849 assert_eq!(
850 block_on(guarded_scan(
851 &bus, &reserved, NEVER, DEADLINE, scan, &mut out
852 )),
853 Err(Status::BUS_ERROR)
854 );
855 assert!(bus.try_lock().is_ok());
857 }
858
859 #[test]
860 fn deadlines_scale_with_the_wire_time_above_a_floor() {
861 let short = transfer_deadline(
862 TransferShape {
863 ops: 2,
864 data_len: 3,
865 read_len: 2,
866 },
867 400,
868 );
869 assert!(short >= DEADLINE_FLOOR && short < Duration::from_millis(110));
870 let long = transfer_deadline(
871 TransferShape {
872 ops: 16,
873 data_len: 255,
874 read_len: 0,
875 },
876 100,
877 );
878 assert!(long > Duration::from_millis(300) && long < Duration::from_millis(400));
881 let scan = scan_deadline(&ScanRequest::new(0), 400);
882 assert!(scan > DEADLINE_FLOOR && scan < Duration::from_millis(200));
883 let _ = deadline_for(10, 0);
885 }
886}