use super::wires::{MasterEvent, MasterOp, MasterWires, SlaveWires, pin};
use super::*;
use alloc::vec;
use alloc::vec::Vec;
use crate::core::state::SliceSource;
use crate::core::sync::{AtomicBool, LockRank, Mutex};
use crate::core::wire::{Level, Wire, WireId, WireSource};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Call {
Address(Address, Direction),
Write(u8),
Read(u8),
ReadAck(Ack),
Stop,
}
#[derive(Debug)]
struct Recorder {
address: Address,
general: bool,
log: Mutex<Vec<Call>>,
replies: Mutex<Vec<u8>>,
stretch: AtomicBool,
refuse: bool,
}
impl Recorder {
fn new(address: Address, replies: &[u8]) -> Arc<Recorder> {
Arc::new(Recorder {
address,
general: false,
log: Mutex::with_rank(LockRank::LEAF, Vec::new()),
replies: Mutex::with_rank(LockRank::LEAF, replies.to_vec()),
stretch: AtomicBool::new(false),
refuse: false,
})
}
fn take_log(&self) -> Vec<Call> {
core::mem::take(&mut *self.log.lock())
}
}
impl I2cSlave for Recorder {
fn address(&self, address: Address, dir: Direction) -> Ack {
self.log.lock().push(Call::Address(address, dir));
if address == GENERAL_CALL && self.general {
return Ack::Ack;
}
if address == self.address {
Ack::Ack
} else {
Ack::Nack
}
}
fn ten_bit_header(&self, high: u8) -> bool {
self.address.ten_bit_high() == Some(high)
}
fn write(&self, byte: u8) -> Ack {
self.log.lock().push(Call::Write(byte));
if self.refuse { Ack::Nack } else { Ack::Ack }
}
fn read(&self) -> u8 {
let byte = self.replies.lock().first().copied().unwrap_or(0xff);
self.log.lock().push(Call::Read(byte));
byte
}
fn read_ack(&self, ack: Ack) {
self.log.lock().push(Call::ReadAck(ack));
if ack.is_ack() {
let mut replies = self.replies.lock();
if !replies.is_empty() {
replies.remove(0);
}
}
}
fn stop(&self) {
self.log.lock().push(Call::Stop);
}
fn stretching(&self) -> bool {
self.stretch.load(crate::core::sync::Ordering::Relaxed)
}
fn peek(&self) -> u8 {
self.replies.lock().first().copied().unwrap_or(0xff)
}
}
struct Harness {
masters: Vec<Arc<MasterWires>>,
slaves: Vec<Arc<SlaveWires>>,
#[allow(dead_code)]
scl: Arc<Wire>,
#[allow(dead_code)]
sda: Arc<Wire>,
}
impl Harness {
fn new(masters: usize, slaves: &[Arc<dyn I2cSlave>]) -> Harness {
let masters: Vec<Arc<MasterWires>> =
(0..masters).map(|_| Arc::new(MasterWires::new())).collect();
let slaves: Vec<Arc<SlaveWires>> = slaves
.iter()
.map(|s| Arc::new(SlaveWires::new(Arc::clone(s))))
.collect();
let total = masters.len() + slaves.len();
let scl_ids: Vec<WireId> = (0..total).map(|i| WireId::new(1 + i as u64)).collect();
let sda_ids: Vec<WireId> = (0..total)
.map(|i| WireId::new(1 + (total + i) as u64))
.collect();
let mut scl = Wire::builder().sources(&scl_ids);
let mut sda = Wire::builder().sources(&sda_ids);
for m in &masters {
scl = scl.sink(m.sink(pin::SCL, &scl_ids), pin::SCL);
sda = sda.sink(m.sink(pin::SDA, &sda_ids), pin::SDA);
}
for s in &slaves {
scl = scl.sink(s.sink(pin::SCL, &scl_ids), pin::SCL);
sda = sda.sink(s.sink(pin::SDA, &sda_ids), pin::SDA);
}
let scl = scl.build_shared();
let sda = sda.build_shared();
for (i, m) in masters.iter().enumerate() {
m.connect(pin::SCL, WireSource::new(Arc::clone(&scl), scl_ids[i]));
m.connect(pin::SDA, WireSource::new(Arc::clone(&sda), sda_ids[i]));
}
for (i, s) in slaves.iter().enumerate() {
let at = masters.len() + i;
s.connect(pin::SCL, WireSource::new(Arc::clone(&scl), scl_ids[at]));
s.connect(pin::SDA, WireSource::new(Arc::clone(&sda), sda_ids[at]));
}
for m in &masters {
m.announce();
}
for s in &slaves {
s.announce();
}
Harness {
masters,
slaves,
scl,
sda,
}
}
fn master(&self) -> &Arc<MasterWires> {
&self.masters[0]
}
fn run(&self, op: MasterOp) -> (MasterEvent, u32) {
assert!(self.master().submit(op), "the engine was already busy");
let mut stretched = 0;
for _ in 0..256 {
match self.master().tick() {
MasterEvent::Working => {}
MasterEvent::Stretched => stretched += 1,
other => return (other, stretched),
}
}
panic!("{op:?} never finished");
}
}
fn wired_script(slave: Arc<Recorder>, script: &[MasterOp]) -> (Vec<Call>, Vec<u8>) {
let harness = Harness::new(1, &[Arc::clone(&slave) as Arc<dyn I2cSlave>]);
let mut got = Vec::new();
for op in script {
let (event, _) = harness.run(*op);
if let MasterEvent::Read(byte) = event {
got.push(byte);
}
}
(slave.take_log(), got)
}
fn transactional_script(slave: Arc<Recorder>, script: &[MasterOp]) -> (Vec<Call>, Vec<u8>) {
let bus = I2cBus::new();
bus.attach(Arc::clone(&slave) as Arc<dyn I2cSlave>)
.expect("room on the bus");
let mut got = Vec::new();
let mut pending_start = false;
for op in script {
match *op {
MasterOp::Start => pending_start = true,
MasterOp::Write(byte) if pending_start => {
pending_start = false;
if Address::is_ten_bit_header(byte) {
let high = (byte >> 1) & 0b11;
match Direction::from_bit(byte) {
Direction::Write => {
let _ = bus.ten_bit_header(high);
pending_start = true;
}
Direction::Read => {
bus.write(byte);
}
}
} else {
bus.start(Address::seven_from_byte(byte), Direction::from_bit(byte));
}
}
MasterOp::Write(byte) => {
bus.write(byte);
}
MasterOp::Read(ack) => got.push(bus.read(ack)),
MasterOp::Stop => bus.stop(),
}
}
(slave.take_log(), got)
}
#[test]
fn an_address_byte_is_the_address_shifted_up_and_the_direction_bit() {
assert_eq!(
Address::Seven(0x50).first_byte(Direction::Write),
0b1010_0000
);
assert_eq!(
Address::Seven(0x50).first_byte(Direction::Read),
0b1010_0001
);
assert_eq!(Address::seven_from_byte(0b1010_0001), Address::Seven(0x50));
assert_eq!(Direction::from_bit(0b1010_0001), Direction::Read);
assert_eq!(Address::Seven(0x50).second_byte(), None);
}
#[test]
fn a_ten_bit_address_is_a_reserved_header_and_a_whole_byte() {
let a = Address::Ten(0x2a5);
assert_eq!(a.first_byte(Direction::Write), 0b1111_0100);
assert_eq!(a.first_byte(Direction::Read), 0b1111_0101);
assert_eq!(a.second_byte(), Some(0xa5));
assert_eq!(a.ten_bit_high(), Some(0b10));
assert!(Address::is_ten_bit_header(0b1111_0100));
assert!(!Address::is_ten_bit_header(0b1111_1000), "1111 1XX is not");
assert!(!Address::is_ten_bit_header(0b1010_0000));
}
#[test]
fn the_two_reserved_groups_are_the_ones_table_4_lists() {
for a in 0..8u8 {
assert!(Address::Seven(a).is_reserved(), "{a:#04x}");
assert!(Address::Seven(0x78 | a).is_reserved(), "{:#04x}", 0x78 | a);
}
assert!(!Address::Seven(0x50).is_reserved());
assert!(!Address::Seven(0x08).is_reserved());
assert!(!Address::Seven(0x77).is_reserved());
assert_eq!(GENERAL_CALL, Address::Seven(0));
assert!(GENERAL_CALL.is_reserved());
}
#[test]
fn an_acknowledge_is_active_low_and_merges_the_way_the_wire_does() {
assert_eq!(Ack::from_level(Level::Low), Ack::Ack);
assert_eq!(Ack::from_level(Level::High), Ack::Nack);
assert_eq!(Ack::Ack.level(), Level::Low);
assert_eq!(Ack::Nack.merge(Ack::Ack), Ack::Ack);
assert_eq!(Ack::Ack.merge(Ack::Nack), Ack::Ack);
assert_eq!(Ack::Nack.merge(Ack::Nack), Ack::Nack);
}
#[test]
fn a_link_round_trips_through_the_name_a_machine_file_writes() {
for name in Link::NAMES {
let link = Link::from_name(name).expect("a known spelling");
assert_eq!(link.name(), *name);
}
assert_eq!(Link::from_name("wired-ish"), None);
}
#[test]
fn only_the_addressed_device_hears_the_bytes() {
let a = Recorder::new(Address::Seven(0x50), &[]);
let b = Recorder::new(Address::Seven(0x51), &[]);
let bus = I2cBus::new();
bus.attach(Arc::clone(&a) as Arc<dyn I2cSlave>).unwrap();
bus.attach(Arc::clone(&b) as Arc<dyn I2cSlave>).unwrap();
assert_eq!(bus.start(Address::Seven(0x50), Direction::Write), Ack::Ack);
assert_eq!(bus.write(0x11), Ack::Ack);
bus.stop();
assert_eq!(
a.take_log(),
vec![
Call::Address(Address::Seven(0x50), Direction::Write),
Call::Write(0x11),
Call::Stop,
]
);
assert_eq!(
b.take_log(),
vec![Call::Address(Address::Seven(0x50), Direction::Write)]
);
}
#[test]
fn a_bus_with_nothing_on_the_address_nacks_and_reads_as_the_pull_up() {
let bus = I2cBus::new();
let a = Recorder::new(Address::Seven(0x50), &[]);
bus.attach(a as Arc<dyn I2cSlave>).unwrap();
assert_eq!(bus.start(Address::Seven(0x22), Direction::Write), Ack::Nack);
assert_eq!(bus.state(), BusState::Unaddressed);
assert!(bus.state().is_busy(), "the bus is busy from the START");
assert_eq!(bus.write(0xaa), Ack::Nack);
assert_eq!(bus.read(Ack::Nack), 0xff, "an undriven SDA is the pull-up");
bus.stop();
assert_eq!(bus.state(), BusState::Free);
}
#[test]
fn the_general_call_reaches_every_device_that_answers_it() {
let mut listener = Recorder::new(Address::Seven(0x50), &[]);
Arc::get_mut(&mut listener).unwrap().general = true;
let deaf = Recorder::new(Address::Seven(0x51), &[]);
let bus = I2cBus::new();
bus.attach(Arc::clone(&listener) as Arc<dyn I2cSlave>)
.unwrap();
bus.attach(Arc::clone(&deaf) as Arc<dyn I2cSlave>).unwrap();
assert_eq!(bus.start(GENERAL_CALL, Direction::Write), Ack::Ack);
assert_eq!(bus.write(0x06), Ack::Ack, "one acknowledge is enough");
bus.stop();
assert_eq!(
listener.take_log(),
vec![
Call::Address(GENERAL_CALL, Direction::Write),
Call::Write(0x06),
Call::Stop,
]
);
assert_eq!(
deaf.take_log(),
vec![Call::Address(GENERAL_CALL, Direction::Write)],
"a device that did not answer hears nothing after the address"
);
assert_eq!(
bus.conflicts(),
0,
"two general-call answers is not a clash"
);
}
#[test]
fn two_devices_on_one_address_are_counted_as_the_wiring_error_they_are() {
let a = Recorder::new(Address::Seven(0x50), &[]);
let b = Recorder::new(Address::Seven(0x50), &[]);
let bus = I2cBus::new();
bus.attach(a as Arc<dyn I2cSlave>).unwrap();
bus.attach(b as Arc<dyn I2cSlave>).unwrap();
assert_eq!(bus.start(Address::Seven(0x50), Direction::Write), Ack::Ack);
assert_eq!(bus.conflicts(), 1);
}
#[test]
fn a_repeated_start_that_goes_elsewhere_ends_the_first_devices_transaction() {
let a = Recorder::new(Address::Seven(0x50), &[]);
let b = Recorder::new(Address::Seven(0x51), &[]);
let bus = I2cBus::new();
bus.attach(Arc::clone(&a) as Arc<dyn I2cSlave>).unwrap();
bus.attach(Arc::clone(&b) as Arc<dyn I2cSlave>).unwrap();
bus.start(Address::Seven(0x50), Direction::Write);
bus.write(0x01);
bus.start(Address::Seven(0x51), Direction::Write);
bus.write(0x02);
bus.stop();
assert_eq!(
a.take_log(),
vec![
Call::Address(Address::Seven(0x50), Direction::Write),
Call::Write(0x01),
Call::Address(Address::Seven(0x51), Direction::Write),
Call::Stop,
]
);
assert_eq!(
b.take_log(),
vec![
Call::Address(Address::Seven(0x50), Direction::Write),
Call::Address(Address::Seven(0x51), Direction::Write),
Call::Write(0x02),
Call::Stop,
]
);
}
#[test]
fn a_debug_peek_moves_no_address_counter() {
let slave = Recorder::new(Address::Seven(0x50), &[0x11, 0x22]);
let bus = I2cBus::new();
bus.attach(Arc::clone(&slave) as Arc<dyn I2cSlave>).unwrap();
bus.start(Address::Seven(0x50), Direction::Read);
slave.take_log();
assert_eq!(bus.peek(), 0x11);
assert_eq!(bus.peek(), 0x11, "and again, because nothing moved");
assert!(
slave.take_log().is_empty(),
"peek is not a call into `read`"
);
assert_eq!(bus.read(Ack::Ack), 0x11);
assert_eq!(bus.peek(), 0x22, "the acknowledge is what advanced it");
}
#[test]
fn both_link_models_produce_identical_traffic() {
let script = [
MasterOp::Start,
MasterOp::Write(Address::Seven(0x50).first_byte(Direction::Write)),
MasterOp::Write(0x04),
MasterOp::Write(0xde),
MasterOp::Write(0xad),
MasterOp::Stop,
];
let (wired, _) = wired_script(Recorder::new(Address::Seven(0x50), &[]), &script);
let (transactional, _) =
transactional_script(Recorder::new(Address::Seven(0x50), &[]), &script);
assert_eq!(wired, transactional);
assert_eq!(
wired,
vec![
Call::Address(Address::Seven(0x50), Direction::Write),
Call::Write(0x04),
Call::Write(0xde),
Call::Write(0xad),
Call::Stop,
],
"and both are the traffic that was asked for"
);
}
#[test]
fn both_link_models_read_the_same_bytes_back() {
let script = [
MasterOp::Start,
MasterOp::Write(Address::Seven(0x50).first_byte(Direction::Read)),
MasterOp::Read(Ack::Ack),
MasterOp::Read(Ack::Ack),
MasterOp::Read(Ack::Nack),
MasterOp::Stop,
];
let replies = [0x11u8, 0x22, 0x33];
let (wired, wired_bytes) = wired_script(Recorder::new(Address::Seven(0x50), &replies), &script);
let (transactional, transactional_bytes) =
transactional_script(Recorder::new(Address::Seven(0x50), &replies), &script);
assert_eq!(wired_bytes, vec![0x11, 0x22, 0x33]);
assert_eq!(wired_bytes, transactional_bytes);
assert_eq!(wired, transactional);
assert!(wired.contains(&Call::ReadAck(Ack::Nack)));
}
#[test]
fn a_wired_master_hears_a_nack_from_an_address_nobody_answers() {
let slave = Recorder::new(Address::Seven(0x50), &[]);
let harness = Harness::new(1, &[Arc::clone(&slave) as Arc<dyn I2cSlave>]);
assert_eq!(harness.run(MasterOp::Start).0, MasterEvent::Started);
let byte = Address::Seven(0x22).first_byte(Direction::Write);
assert_eq!(
harness.run(MasterOp::Write(byte)).0,
MasterEvent::Wrote(Ack::Nack)
);
assert_eq!(harness.run(MasterOp::Stop).0, MasterEvent::Stopped);
assert_eq!(
slave.take_log(),
vec![Call::Address(Address::Seven(0x22), Direction::Write)],
"it compared the address and said nothing more"
);
}
#[test]
fn a_ten_bit_address_takes_two_bytes_and_a_repeated_start_to_read() {
let addr = Address::Ten(0x2a5);
let slave = Recorder::new(addr, &[0x5a]);
let harness = Harness::new(1, &[Arc::clone(&slave) as Arc<dyn I2cSlave>]);
assert_eq!(harness.run(MasterOp::Start).0, MasterEvent::Started);
assert_eq!(
harness
.run(MasterOp::Write(addr.first_byte(Direction::Write)))
.0,
MasterEvent::Wrote(Ack::Ack),
"the header alone is acknowledged (A1)"
);
assert_eq!(
harness.run(MasterOp::Write(addr.second_byte().unwrap())).0,
MasterEvent::Wrote(Ack::Ack),
"and so is the second byte (A2)"
);
assert_eq!(harness.run(MasterOp::Start).0, MasterEvent::Started);
assert_eq!(
harness
.run(MasterOp::Write(addr.first_byte(Direction::Read)))
.0,
MasterEvent::Wrote(Ack::Ack),
"the device remembered that it was addressed before"
);
assert_eq!(
harness.run(MasterOp::Read(Ack::Nack)).0,
MasterEvent::Read(0x5a)
);
assert_eq!(harness.run(MasterOp::Stop).0, MasterEvent::Stopped);
let log = slave.take_log();
assert_eq!(log[0], Call::Address(addr, Direction::Write));
assert_eq!(log[1], Call::Address(addr, Direction::Read));
assert!(log.contains(&Call::Read(0x5a)));
}
#[test]
fn a_slave_that_stretches_the_clock_stalls_a_wired_master() {
let slave = Recorder::new(Address::Seven(0x50), &[]);
let harness = Harness::new(1, &[Arc::clone(&slave) as Arc<dyn I2cSlave>]);
assert_eq!(harness.run(MasterOp::Start).0, MasterEvent::Started);
slave
.stretch
.store(true, crate::core::sync::Ordering::Relaxed);
let byte = Address::Seven(0x50).first_byte(Direction::Write);
assert!(harness.master().submit(MasterOp::Write(byte)));
let mut spins = 0;
let mut finished = None;
for _ in 0..64 {
match harness.master().tick() {
MasterEvent::Working => {}
MasterEvent::Stretched => spins += 1,
other => {
finished = Some(other);
break;
}
}
}
assert_eq!(
finished,
Some(MasterEvent::Wrote(Ack::Ack)),
"the byte itself still completed"
);
assert_eq!(spins, 0, "and nothing was stretched during it");
assert_eq!(
harness.slaves[0].scl().driving(),
Level::Low,
"the slave is holding the clock down"
);
assert!(harness.master().submit(MasterOp::Write(0x42)));
assert_eq!(harness.master().tick(), MasterEvent::Working);
for _ in 0..32 {
assert_eq!(
harness.master().tick(),
MasterEvent::Stretched,
"the master must make no progress while SCL is held"
);
}
assert!(
slave.take_log().iter().all(|c| *c != Call::Write(0x42)),
"and the held byte never arrived"
);
slave
.stretch
.store(false, crate::core::sync::Ordering::Relaxed);
harness.slaves[0].refresh_stretch();
let mut event = None;
for _ in 0..64 {
match harness.master().tick() {
MasterEvent::Working | MasterEvent::Stretched => {}
other => {
event = Some(other);
break;
}
}
}
assert_eq!(event, Some(MasterEvent::Wrote(Ack::Ack)));
assert!(
slave.take_log().contains(&Call::Write(0x42)),
"and now the byte got through"
);
}
#[test]
fn a_released_line_that_reads_low_is_somebody_else_pulling() {
let harness = Harness::new(2, &[]);
assert_eq!(harness.masters[0].sda().net(), Level::High, "the pull-up");
harness.masters[1].sda().drive(Level::Low);
assert_eq!(
harness.masters[0].sda().net(),
Level::Low,
"one low driver takes the whole net down"
);
assert_eq!(
harness.masters[0].sda().driving(),
Level::High,
"while we are still releasing it — which is what arbitration reads"
);
harness.masters[1].sda().drive(Level::High);
assert_eq!(harness.masters[0].sda().net(), Level::High);
}
#[test]
fn two_masters_arbitrate_and_the_loser_lets_go() {
let slave = Recorder::new(Address::Seven(0x40), &[]);
let harness = Harness::new(2, &[Arc::clone(&slave) as Arc<dyn I2cSlave>]);
let (a, b) = (&harness.masters[0], &harness.masters[1]);
assert!(a.submit(MasterOp::Start));
assert!(b.submit(MasterOp::Start));
for _ in 0..8 {
a.tick();
b.tick();
}
assert!(!a.is_working() && !b.is_working(), "both saw a valid START");
assert!(a.submit(MasterOp::Write(
Address::Seven(0x40).first_byte(Direction::Write)
)));
assert!(b.submit(MasterOp::Write(
Address::Seven(0x50).first_byte(Direction::Write)
)));
let mut b_lost = false;
let mut a_result = None;
for _ in 0..64 {
if let MasterEvent::ArbitrationLost = b.tick() {
b_lost = true;
}
match a.tick() {
MasterEvent::Working | MasterEvent::Stretched => {}
other => {
a_result = Some(other);
break;
}
}
}
assert!(b_lost, "the master sending the higher address must lose");
assert_eq!(
a_result,
Some(MasterEvent::Wrote(Ack::Ack)),
"and the winner's transfer is untouched — §3.1.8: no information is lost"
);
assert_eq!(
b.sda().driving(),
Level::High,
"the loser turned off its SDA driver"
);
assert_eq!(
slave.take_log(),
vec![Call::Address(Address::Seven(0x40), Direction::Write)],
"and the device the winner addressed is the one that answered"
);
}
#[test]
fn a_wired_master_holds_the_clock_down_between_operations() {
let harness = Harness::new(1, &[]);
assert_eq!(harness.run(MasterOp::Start).0, MasterEvent::Started);
assert_eq!(
harness.master().scl().driving(),
Level::Low,
"a START ends with the clock held down"
);
assert_eq!(harness.master().scl().net(), Level::Low);
assert_eq!(harness.run(MasterOp::Stop).0, MasterEvent::Stopped);
assert_eq!(harness.master().scl().driving(), Level::High);
assert_eq!(harness.master().sda().driving(), Level::High);
assert!(!harness.master().busy(), "the bus is free after a STOP");
}
#[test]
fn a_wired_transfer_costs_the_half_periods_the_fabric_charges_for_it() {
let harness = Harness::new(1, &[]);
let mut ticks = 0u32;
assert!(harness.master().submit(MasterOp::Start));
while harness.master().is_working() {
harness.master().tick();
ticks += 1;
}
assert_eq!(ticks, START_HALF_PERIODS);
ticks = 0;
assert!(harness.master().submit(MasterOp::Write(0xa5)));
while harness.master().is_working() {
harness.master().tick();
ticks += 1;
}
assert_eq!(ticks, BYTE_HALF_PERIODS);
ticks = 0;
assert!(harness.master().submit(MasterOp::Stop));
while harness.master().is_working() {
harness.master().tick();
ticks += 1;
}
assert_eq!(ticks, STOP_HALF_PERIODS);
}
#[test]
fn the_acknowledge_a_read_will_drive_can_change_until_the_eighth_bit() {
let slave = Recorder::new(Address::Seven(0x50), &[0x77]);
let harness = Harness::new(1, &[Arc::clone(&slave) as Arc<dyn I2cSlave>]);
harness.run(MasterOp::Start);
harness.run(MasterOp::Write(
Address::Seven(0x50).first_byte(Direction::Read),
));
slave.take_log();
assert!(harness.master().submit(MasterOp::Read(Ack::Ack)));
for _ in 0..4 {
harness.master().tick();
}
assert!(harness.master().set_read_ack(Ack::Nack));
let mut event = None;
for _ in 0..64 {
match harness.master().tick() {
MasterEvent::Working | MasterEvent::Stretched => {}
other => {
event = Some(other);
break;
}
}
}
assert_eq!(event, Some(MasterEvent::Read(0x77)));
assert!(
slave.take_log().contains(&Call::ReadAck(Ack::Nack)),
"the slave saw the acknowledge software chose late"
);
}
#[test]
fn a_bit_engines_state_round_trips_through_its_own_codec() {
let slave = Recorder::new(Address::Seven(0x50), &[]);
let harness = Harness::new(1, &[Arc::clone(&slave) as Arc<dyn I2cSlave>]);
harness.run(MasterOp::Start);
assert!(harness.master().submit(MasterOp::Write(0xa0)));
for _ in 0..7 {
harness.master().tick();
}
let m = harness.master().snapshot();
let mut bytes = Vec::new();
m.write(&mut bytes).expect("it encodes");
let mut src = SliceSource::new(&bytes);
let back = super::wires::MasterWiresState::read(&mut src).expect("it decodes");
assert_eq!(m, back);
let s = harness.slaves[0].snapshot();
let mut bytes = Vec::new();
s.write(&mut bytes).expect("it encodes");
let mut src = SliceSource::new(&bytes);
let back = super::wires::SlaveWiresState::read(&mut src).expect("it decodes");
assert_eq!(s, back);
}