use alloc::sync::Arc;
use alloc::vec::Vec;
use core::fmt;
use super::{Ack, Address, Direction, I2cSlave, WIRES_RANK};
use crate::core::error::Result;
use crate::core::state::{Sink, Source};
use crate::core::sync::{AtomicBool, LockRank, Mutex, Ordering};
use crate::core::wire::{FanIn, Level, Resolve, WireId, WireSink, WireSource};
pub mod pin {
pub const SCL: u32 = 0;
pub const SDA: u32 = 1;
pub const SCL_NAME: &str = "scl";
pub const SDA_NAME: &str = "sda";
}
pub struct OpenDrain {
fan: Mutex<Option<FanIn>>,
port: Mutex<Option<WireSource>>,
driving: AtomicBool,
net: AtomicBool,
}
impl fmt::Debug for OpenDrain {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OpenDrain")
.field("driving", &self.driving())
.field("net", &self.net())
.finish()
}
}
impl Default for OpenDrain {
fn default() -> OpenDrain {
OpenDrain::new()
}
}
impl OpenDrain {
#[must_use]
pub fn new() -> OpenDrain {
OpenDrain {
fan: Mutex::with_rank(LockRank::LEAF, None),
port: Mutex::with_rank(LockRank::WIRE, None),
driving: AtomicBool::new(true),
net: AtomicBool::new(true),
}
}
pub fn learn_sources(&self, sources: &[WireId]) {
*self.fan.lock() = Some(FanIn::new(sources));
}
pub fn connect(&self, source: WireSource) {
*self.port.lock() = Some(source);
}
#[must_use]
pub fn is_connected(&self) -> bool {
self.port.lock().is_some()
}
#[must_use]
pub fn driving(&self) -> Level {
Level::from_bool(self.driving.load(Ordering::Relaxed))
}
#[must_use]
pub fn net(&self) -> Level {
Level::from_bool(self.net.load(Ordering::Relaxed))
}
pub fn drive(&self, level: Level) {
if self.driving.swap(level.as_bool(), Ordering::Relaxed) == level.as_bool() {
return;
}
self.publish(level);
}
pub fn announce(&self) {
self.publish(self.driving());
}
fn publish(&self, level: Level) {
let port = self.port.lock().clone();
match port {
Some(port) => {
port.set(level);
}
None => {
self.net.store(level.as_bool(), Ordering::Relaxed);
}
}
}
pub fn observe(&self, src: WireId, level: Level) -> Option<Level> {
let resolved = {
let fan = self.fan.lock();
match fan.as_ref() {
Some(fan) => {
fan.set(src, level);
fan.resolve(Resolve::And)
}
None => level,
}
};
if self.net.swap(resolved.as_bool(), Ordering::Relaxed) == resolved.as_bool() {
return None;
}
Some(resolved)
}
#[must_use]
pub fn snapshot(&self) -> (bool, bool) {
(
self.driving.load(Ordering::Relaxed),
self.net.load(Ordering::Relaxed),
)
}
pub fn restore(&self, state: (bool, bool)) {
self.driving.store(state.0, Ordering::Relaxed);
self.net.store(state.1, Ordering::Relaxed);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Emit {
Sda(Level),
Scl(Level),
}
trait LineObserver: Send + Sync + fmt::Debug {
fn observe_line(&self, line: u32, src: WireId, level: Level);
}
struct PinSink {
owner: Arc<dyn LineObserver>,
line: u32,
}
impl fmt::Debug for PinSink {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PinSink").field("line", &self.line).finish()
}
}
impl WireSink for PinSink {
fn set_level(&self, src: WireId, _line: u32, level: Level) {
self.owner.observe_line(self.line, src, level);
}
}
fn tx_bit(byte: u8, n: u8) -> Level {
Level::from_bool(byte & (0x80 >> n.min(7)) != 0)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Phase {
Idle,
Addr1,
Addr2,
Rx,
Tx,
NotUs,
}
const fn phase_code(phase: Phase) -> u8 {
match phase {
Phase::Idle => 0,
Phase::Addr1 => 1,
Phase::Addr2 => 2,
Phase::Rx => 3,
Phase::Tx => 4,
Phase::NotUs => 5,
}
}
const fn phase_from_code(code: u8) -> Phase {
match code {
1 => Phase::Addr1,
2 => Phase::Addr2,
3 => Phase::Rx,
4 => Phase::Tx,
5 => Phase::NotUs,
_ => Phase::Idle,
}
}
#[derive(Debug)]
struct SlaveBits {
phase: Phase,
next: Phase,
shift: u8,
count: u8,
ten_high: u8,
dir: Direction,
ten_last: Option<u16>,
was_addressed: bool,
master_nacked: bool,
scl: Level,
sda: Level,
}
impl Default for SlaveBits {
fn default() -> SlaveBits {
SlaveBits {
phase: Phase::Idle,
next: Phase::Idle,
shift: 0,
count: 0,
ten_high: 0,
dir: Direction::Write,
ten_last: None,
was_addressed: false,
master_nacked: false,
scl: Level::High,
sda: Level::High,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SlaveWiresState {
pub phase: u8,
pub next: u8,
pub shift: u8,
pub count: u8,
pub ten_high: u8,
pub read: bool,
pub ten_last: Option<u16>,
pub was_addressed: bool,
pub master_nacked: bool,
pub scl: bool,
pub sda: bool,
pub scl_out: (bool, bool),
pub sda_out: (bool, bool),
}
impl SlaveWiresState {
pub fn write<S: Sink + ?Sized>(self, w: &mut S) -> Result<()> {
w.write_u8(self.phase)?;
w.write_u8(self.next)?;
w.write_u8(self.shift)?;
w.write_u8(self.count)?;
w.write_u8(self.ten_high)?;
w.write_bool(self.read)?;
w.write_bool(self.ten_last.is_some())?;
w.write_u16(self.ten_last.unwrap_or(0))?;
w.write_bool(self.was_addressed)?;
w.write_bool(self.master_nacked)?;
w.write_bool(self.scl)?;
w.write_bool(self.sda)?;
w.write_bool(self.scl_out.0)?;
w.write_bool(self.scl_out.1)?;
w.write_bool(self.sda_out.0)?;
w.write_bool(self.sda_out.1)
}
pub fn read<'a, S: Source<'a> + ?Sized>(r: &mut S) -> Result<SlaveWiresState> {
let phase = r.read_u8()?;
let next = r.read_u8()?;
let shift = r.read_u8()?;
let count = r.read_u8()?;
let ten_high = r.read_u8()?;
let read = r.read_bool()?;
let has_ten = r.read_bool()?;
let ten = r.read_u16()?;
Ok(SlaveWiresState {
phase,
next,
shift,
count,
ten_high,
read,
ten_last: has_ten.then_some(ten),
was_addressed: r.read_bool()?,
master_nacked: r.read_bool()?,
scl: r.read_bool()?,
sda: r.read_bool()?,
scl_out: (r.read_bool()?, r.read_bool()?),
sda_out: (r.read_bool()?, r.read_bool()?),
})
}
}
pub struct SlaveWires {
slave: Arc<dyn I2cSlave>,
bits: Mutex<SlaveBits>,
scl: OpenDrain,
sda: OpenDrain,
pins: Mutex<Vec<Arc<PinSink>>>,
}
impl fmt::Debug for SlaveWires {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SlaveWires")
.field("slave", &self.slave)
.field("scl", &self.scl)
.field("sda", &self.sda)
.finish_non_exhaustive()
}
}
impl LineObserver for SlaveWires {
fn observe_line(&self, line: u32, src: WireId, level: Level) {
let moved = match line {
pin::SCL => self.scl.observe(src, level).map(|l| (pin::SCL, l)),
pin::SDA => self.sda.observe(src, level).map(|l| (pin::SDA, l)),
_ => None,
};
let Some((line, resolved)) = moved else {
return;
};
let emits = {
let mut bits = self.bits.lock();
if line == pin::SCL {
self.on_scl(&mut bits, resolved)
} else {
self.on_sda(&mut bits, resolved)
}
};
for emit in emits {
match emit {
Emit::Sda(level) => self.sda.drive(level),
Emit::Scl(level) => self.scl.drive(level),
}
}
}
}
impl SlaveWires {
#[must_use]
pub fn new(slave: Arc<dyn I2cSlave>) -> SlaveWires {
SlaveWires {
slave,
bits: Mutex::with_rank(WIRES_RANK, SlaveBits::default()),
scl: OpenDrain::new(),
sda: OpenDrain::new(),
pins: Mutex::with_rank(LockRank::WIRE, Vec::new()),
}
}
#[must_use]
pub fn slave(&self) -> &Arc<dyn I2cSlave> {
&self.slave
}
#[must_use]
pub fn scl(&self) -> &OpenDrain {
&self.scl
}
#[must_use]
pub fn sda(&self) -> &OpenDrain {
&self.sda
}
#[must_use]
pub fn sink(self: &Arc<Self>, line: u32, sources: &[WireId]) -> Arc<dyn WireSink> {
match line {
pin::SCL => self.scl.learn_sources(sources),
pin::SDA => self.sda.learn_sources(sources),
_ => {}
}
let pin = Arc::new(PinSink {
owner: Arc::clone(self) as Arc<dyn LineObserver>,
line,
});
self.pins.lock().push(Arc::clone(&pin));
pin as Arc<dyn WireSink>
}
pub fn connect(&self, line: u32, source: WireSource) {
match line {
pin::SCL => self.scl.connect(source),
pin::SDA => self.sda.connect(source),
_ => {}
}
}
pub fn announce(&self) {
self.sda.announce();
self.scl.announce();
}
pub fn refresh_stretch(&self) {
let want = if self.slave.stretching() {
Level::Low
} else {
Level::High
};
self.scl.drive(want);
}
pub fn reset(&self) {
*self.bits.lock() = SlaveBits::default();
self.sda.drive(Level::High);
self.scl.drive(Level::High);
}
fn on_sda(&self, bits: &mut SlaveBits, level: Level) -> Vec<Emit> {
let was = bits.sda;
bits.sda = level;
if bits.scl.is_low() || was == level {
return Vec::new();
}
if level.is_low() {
bits.was_addressed = matches!(bits.phase, Phase::Rx | Phase::Tx);
bits.phase = Phase::Addr1;
bits.next = Phase::Idle;
bits.shift = 0;
bits.count = 0;
bits.master_nacked = false;
Vec::new()
} else {
let ending = matches!(bits.phase, Phase::Rx | Phase::Tx);
*bits = SlaveBits {
ten_last: bits.ten_last,
..SlaveBits::default()
};
bits.scl = Level::High;
bits.sda = Level::High;
if ending {
self.slave.stop();
}
alloc::vec![Emit::Sda(Level::High)]
}
}
fn on_scl(&self, bits: &mut SlaveBits, level: Level) -> Vec<Emit> {
let was = bits.scl;
bits.scl = level;
if was == level {
return Vec::new();
}
if level.is_high() {
self.on_scl_rising(bits);
Vec::new()
} else {
self.on_scl_falling(bits)
}
}
fn on_scl_rising(&self, bits: &mut SlaveBits) {
let sda = bits.sda;
match bits.phase {
Phase::Idle | Phase::NotUs => return,
Phase::Addr1 | Phase::Addr2 | Phase::Rx if bits.count < 8 => {
bits.shift = (bits.shift << 1) | u8::from(sda.is_high());
}
Phase::Tx if bits.count == 8 => {
let ack = Ack::from_level(sda);
bits.master_nacked = !ack.is_ack();
self.slave.read_ack(ack);
}
_ => {}
}
if bits.count < 9 {
bits.count += 1;
}
}
fn on_scl_falling(&self, bits: &mut SlaveBits) -> Vec<Emit> {
match bits.phase {
Phase::Idle | Phase::NotUs => Vec::new(),
_ => match bits.count {
8 => self.begin_ack(bits),
9 => self.end_slot(bits),
n => {
if bits.phase == Phase::Tx && n < 8 {
alloc::vec![Emit::Sda(tx_bit(bits.shift, n))]
} else {
Vec::new()
}
}
},
}
}
fn begin_ack(&self, bits: &mut SlaveBits) -> Vec<Emit> {
let byte = bits.shift;
let (ack, next) = match bits.phase {
Phase::Addr1 if Address::is_ten_bit_header(byte) => {
let high = (byte >> 1) & 0b11;
bits.dir = Direction::from_bit(byte);
match bits.dir {
Direction::Write => {
if self.slave.ten_bit_header(high) {
bits.ten_high = high;
(Ack::Ack, Phase::Addr2)
} else {
(Ack::Nack, Phase::NotUs)
}
}
Direction::Read => match bits.ten_last {
Some(full) if (full >> 8) as u8 == high => {
bits.ten_high = high;
let ack = self.slave.address(Address::Ten(full), Direction::Read);
(
ack,
if ack.is_ack() {
Phase::Tx
} else {
Phase::NotUs
},
)
}
_ => (Ack::Nack, Phase::NotUs),
},
}
}
Phase::Addr1 => {
bits.dir = Direction::from_bit(byte);
let ack = self.slave.address(Address::seven_from_byte(byte), bits.dir);
let next = match (ack, bits.dir) {
(Ack::Nack, _) => Phase::NotUs,
(Ack::Ack, Direction::Write) => Phase::Rx,
(Ack::Ack, Direction::Read) => Phase::Tx,
};
(ack, next)
}
Phase::Addr2 => {
let full = (u16::from(bits.ten_high) << 8) | u16::from(byte);
let ack = self.slave.address(Address::Ten(full), bits.dir);
if ack.is_ack() {
bits.ten_last = Some(full);
}
let next = match (ack, bits.dir) {
(Ack::Nack, _) => Phase::NotUs,
(Ack::Ack, Direction::Write) => Phase::Rx,
(Ack::Ack, Direction::Read) => Phase::Tx,
};
(ack, next)
}
Phase::Rx => {
let ack = self.slave.write(byte);
(
ack,
if ack.is_ack() {
Phase::Rx
} else {
Phase::NotUs
},
)
}
Phase::Tx => {
bits.next = Phase::Tx;
return alloc::vec![Emit::Sda(Level::High)];
}
Phase::Idle | Phase::NotUs => return Vec::new(),
};
bits.next = next;
alloc::vec![Emit::Sda(ack.level())]
}
fn end_slot(&self, bits: &mut SlaveBits) -> Vec<Emit> {
let mut out = alloc::vec![Emit::Sda(Level::High)];
bits.count = 0;
bits.shift = 0;
let was_ours = matches!(bits.phase, Phase::Rx | Phase::Tx);
bits.phase = match bits.next {
Phase::Tx if bits.master_nacked => Phase::NotUs,
next => next,
};
if (bits.was_addressed || was_ours) && bits.phase == Phase::NotUs {
self.slave.stop();
bits.was_addressed = false;
}
if matches!(bits.phase, Phase::Rx | Phase::Tx) {
bits.was_addressed = true;
}
if bits.phase == Phase::Tx {
bits.shift = self.slave.read();
out.push(Emit::Sda(tx_bit(bits.shift, 0)));
}
if self.slave.stretching() {
out.push(Emit::Scl(Level::Low));
}
out
}
#[must_use]
pub fn snapshot(&self) -> SlaveWiresState {
let bits = self.bits.lock();
SlaveWiresState {
phase: phase_code(bits.phase),
next: phase_code(bits.next),
shift: bits.shift,
count: bits.count,
ten_high: bits.ten_high,
read: bits.dir == Direction::Read,
ten_last: bits.ten_last,
was_addressed: bits.was_addressed,
master_nacked: bits.master_nacked,
scl: bits.scl.is_high(),
sda: bits.sda.is_high(),
scl_out: self.scl.snapshot(),
sda_out: self.sda.snapshot(),
}
}
pub fn restore(&self, state: SlaveWiresState) {
{
let mut bits = self.bits.lock();
bits.phase = phase_from_code(state.phase);
bits.next = phase_from_code(state.next);
bits.shift = state.shift;
bits.count = state.count.min(9);
bits.ten_high = state.ten_high & 0b11;
bits.dir = if state.read {
Direction::Read
} else {
Direction::Write
};
bits.ten_last = state.ten_last.filter(|a| *a <= 0x3ff);
bits.was_addressed = state.was_addressed;
bits.master_nacked = state.master_nacked;
bits.scl = Level::from_bool(state.scl);
bits.sda = Level::from_bool(state.sda);
}
self.scl.restore(state.scl_out);
self.sda.restore(state.sda_out);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MasterOp {
Start,
Write(u8),
Read(Ack),
Stop,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MasterEvent {
Idle,
Working,
Stretched,
ArbitrationLost,
Started,
Wrote(Ack),
Read(u8),
Stopped,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct MasterBits {
op: Option<MasterOp>,
phase: u8,
count: u8,
shift: u8,
ack: Ack,
arbitrating: bool,
driven: Level,
busy: bool,
saw_high: bool,
scl: Level,
sda: Level,
}
impl Default for MasterBits {
fn default() -> MasterBits {
MasterBits {
op: None,
phase: 0,
count: 0,
shift: 0,
ack: Ack::Nack,
arbitrating: false,
driven: Level::High,
busy: false,
saw_high: false,
scl: Level::High,
sda: Level::High,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MasterWiresState {
pub op: u8,
pub operand: u8,
pub phase: u8,
pub count: u8,
pub shift: u8,
pub ack: bool,
pub arbitrating: bool,
pub driven: bool,
pub busy: bool,
pub saw_high: bool,
pub scl: bool,
pub sda: bool,
pub scl_out: (bool, bool),
pub sda_out: (bool, bool),
}
impl MasterWiresState {
pub fn write<S: Sink + ?Sized>(self, w: &mut S) -> Result<()> {
w.write_u8(self.op)?;
w.write_u8(self.operand)?;
w.write_u8(self.phase)?;
w.write_u8(self.count)?;
w.write_u8(self.shift)?;
w.write_bool(self.ack)?;
w.write_bool(self.arbitrating)?;
w.write_bool(self.driven)?;
w.write_bool(self.busy)?;
w.write_bool(self.saw_high)?;
w.write_bool(self.scl)?;
w.write_bool(self.sda)?;
w.write_bool(self.scl_out.0)?;
w.write_bool(self.scl_out.1)?;
w.write_bool(self.sda_out.0)?;
w.write_bool(self.sda_out.1)
}
pub fn read<'a, S: Source<'a> + ?Sized>(r: &mut S) -> Result<MasterWiresState> {
Ok(MasterWiresState {
op: r.read_u8()?,
operand: r.read_u8()?,
phase: r.read_u8()?,
count: r.read_u8()?,
shift: r.read_u8()?,
ack: r.read_bool()?,
arbitrating: r.read_bool()?,
driven: r.read_bool()?,
busy: r.read_bool()?,
saw_high: r.read_bool()?,
scl: r.read_bool()?,
sda: r.read_bool()?,
scl_out: (r.read_bool()?, r.read_bool()?),
sda_out: (r.read_bool()?, r.read_bool()?),
})
}
}
pub struct MasterWires {
bits: Mutex<MasterBits>,
scl: OpenDrain,
sda: OpenDrain,
pins: Mutex<Vec<Arc<PinSink>>>,
}
impl fmt::Debug for MasterWires {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut s = f.debug_struct("MasterWires");
match self.bits.try_lock() {
Some(bits) => s.field("bits", &*bits),
None => s.field("bits", &"<in use>"),
};
s.field("scl", &self.scl).field("sda", &self.sda).finish()
}
}
impl Default for MasterWires {
fn default() -> MasterWires {
MasterWires::new()
}
}
impl LineObserver for MasterWires {
fn observe_line(&self, line: u32, src: WireId, level: Level) {
let moved = match line {
pin::SCL => self.scl.observe(src, level).map(|l| (pin::SCL, l)),
pin::SDA => self.sda.observe(src, level).map(|l| (pin::SDA, l)),
_ => None,
};
let Some((line, resolved)) = moved else {
return;
};
let mut bits = self.bits.lock();
if line == pin::SCL {
bits.scl = resolved;
if resolved.is_high() {
bits.saw_high = true;
}
} else {
let was = bits.sda;
bits.sda = resolved;
if bits.scl.is_high() && was.is_low() && resolved.is_high() {
bits.busy = false;
}
}
if resolved.is_low() {
bits.busy = true;
}
}
}
impl MasterWires {
#[must_use]
pub fn new() -> MasterWires {
MasterWires {
bits: Mutex::with_rank(WIRES_RANK, MasterBits::default()),
scl: OpenDrain::new(),
sda: OpenDrain::new(),
pins: Mutex::with_rank(LockRank::WIRE, Vec::new()),
}
}
#[must_use]
pub fn scl(&self) -> &OpenDrain {
&self.scl
}
#[must_use]
pub fn sda(&self) -> &OpenDrain {
&self.sda
}
#[must_use]
pub fn sink(self: &Arc<Self>, line: u32, sources: &[WireId]) -> Arc<dyn WireSink> {
match line {
pin::SCL => self.scl.learn_sources(sources),
pin::SDA => self.sda.learn_sources(sources),
_ => {}
}
let pin = Arc::new(PinSink {
owner: Arc::clone(self) as Arc<dyn LineObserver>,
line,
});
self.pins.lock().push(Arc::clone(&pin));
pin as Arc<dyn WireSink>
}
pub fn connect(&self, line: u32, source: WireSource) {
match line {
pin::SCL => self.scl.connect(source),
pin::SDA => self.sda.connect(source),
_ => {}
}
}
pub fn announce(&self) {
self.sda.announce();
self.scl.announce();
}
#[must_use]
pub fn busy(&self) -> bool {
self.bits.lock().busy
}
#[must_use]
pub fn is_working(&self) -> bool {
self.bits.lock().op.is_some()
}
pub fn submit(&self, op: MasterOp) -> bool {
let mut bits = self.bits.lock();
if bits.op.is_some() {
return false;
}
bits.op = Some(op);
bits.phase = 0;
bits.count = 0;
bits.shift = 0;
bits.ack = Ack::Nack;
bits.arbitrating = false;
true
}
pub fn set_read_ack(&self, ack: Ack) -> bool {
let mut bits = self.bits.lock();
if bits.count > 8 || !matches!(bits.op, Some(MasterOp::Read(_))) {
return false;
}
bits.op = Some(MasterOp::Read(ack));
true
}
pub fn abort(&self) {
self.bits.lock().op = None;
self.sda.drive(Level::High);
self.scl.drive(Level::High);
}
pub fn reset(&self) {
*self.bits.lock() = MasterBits::default();
self.sda.drive(Level::High);
self.scl.drive(Level::High);
}
pub fn tick(&self) -> MasterEvent {
let (event, emits) = {
let mut bits = self.bits.lock();
match bits.op {
None => (MasterEvent::Idle, Vec::new()),
Some(MasterOp::Start) => self.step_start(&mut bits),
Some(MasterOp::Write(byte)) => self.step_byte(&mut bits, Some(byte), Ack::Nack),
Some(MasterOp::Read(ack)) => self.step_byte(&mut bits, None, ack),
Some(MasterOp::Stop) => self.step_stop(&mut bits),
}
};
for emit in emits {
match emit {
Emit::Sda(level) => self.sda.drive(level),
Emit::Scl(level) => self.scl.drive(level),
}
}
event
}
fn step_start(&self, bits: &mut MasterBits) -> (MasterEvent, Vec<Emit>) {
match bits.phase {
0 => {
bits.phase = 1;
(MasterEvent::Working, alloc::vec![Emit::Sda(Level::High)])
}
1 => {
bits.phase = 2;
(MasterEvent::Working, alloc::vec![Emit::Scl(Level::High)])
}
2 => {
if self.scl.net().is_low() {
return (MasterEvent::Stretched, Vec::new());
}
if self.sda.net().is_low() {
return (MasterEvent::ArbitrationLost, self.give_up(bits));
}
bits.phase = 3;
(MasterEvent::Working, alloc::vec![Emit::Sda(Level::Low)])
}
_ => {
bits.op = None;
bits.phase = 0;
(MasterEvent::Started, alloc::vec![Emit::Scl(Level::Low)])
}
}
}
fn step_byte(
&self,
bits: &mut MasterBits,
byte: Option<u8>,
ack: Ack,
) -> (MasterEvent, Vec<Emit>) {
if bits.phase == 0 {
let (level, defend) = match (byte, bits.count) {
(Some(v), n) if n < 8 => (tx_bit(v, n), true),
(Some(_), _) => (Level::High, false),
(None, n) if n < 8 => (Level::High, false),
(None, _) => (ack.level(), true),
};
bits.arbitrating = defend;
bits.driven = level;
bits.phase = 1;
bits.saw_high = false;
return (
MasterEvent::Working,
alloc::vec![Emit::Sda(level), Emit::Scl(Level::High)],
);
}
if self.scl.net().is_low() && !bits.saw_high {
return (MasterEvent::Stretched, Vec::new());
}
let sda = self.sda.net();
if bits.arbitrating && bits.driven.is_high() && sda.is_low() {
return (MasterEvent::ArbitrationLost, self.give_up(bits));
}
match (byte, bits.count) {
(Some(_), n) if n >= 8 => bits.ack = Ack::from_level(sda),
(None, n) if n < 8 => bits.shift = (bits.shift << 1) | u8::from(sda.is_high()),
_ => {}
}
bits.count += 1;
bits.phase = 0;
let done = bits.count > 8;
let out = alloc::vec![Emit::Scl(Level::Low)];
if !done {
return (MasterEvent::Working, out);
}
let event = match byte {
Some(_) => MasterEvent::Wrote(bits.ack),
None => MasterEvent::Read(bits.shift),
};
bits.op = None;
bits.count = 0;
(event, out)
}
fn step_stop(&self, bits: &mut MasterBits) -> (MasterEvent, Vec<Emit>) {
if bits.phase == 0 {
bits.phase = 1;
return (
MasterEvent::Working,
alloc::vec![Emit::Sda(Level::Low), Emit::Scl(Level::High)],
);
}
if self.scl.net().is_low() {
return (MasterEvent::Stretched, Vec::new());
}
bits.op = None;
bits.phase = 0;
(MasterEvent::Stopped, alloc::vec![Emit::Sda(Level::High)])
}
fn give_up(&self, bits: &mut MasterBits) -> Vec<Emit> {
bits.op = None;
bits.phase = 0;
bits.count = 0;
alloc::vec![Emit::Sda(Level::High), Emit::Scl(Level::High)]
}
#[must_use]
pub fn snapshot(&self) -> MasterWiresState {
let bits = self.bits.lock();
let (op, operand) = match bits.op {
None => (0, 0),
Some(MasterOp::Start) => (1, 0),
Some(MasterOp::Write(b)) => (2, b),
Some(MasterOp::Read(a)) => (3, u8::from(a.is_ack())),
Some(MasterOp::Stop) => (4, 0),
};
MasterWiresState {
op,
operand,
phase: bits.phase,
count: bits.count,
shift: bits.shift,
ack: bits.ack.is_ack(),
arbitrating: bits.arbitrating,
driven: bits.driven.is_high(),
busy: bits.busy,
saw_high: bits.saw_high,
scl: bits.scl.is_high(),
sda: bits.sda.is_high(),
scl_out: self.scl.snapshot(),
sda_out: self.sda.snapshot(),
}
}
pub fn restore(&self, state: MasterWiresState) {
{
let mut bits = self.bits.lock();
bits.op = match state.op {
1 => Some(MasterOp::Start),
2 => Some(MasterOp::Write(state.operand)),
3 => Some(MasterOp::Read(if state.operand != 0 {
Ack::Ack
} else {
Ack::Nack
})),
4 => Some(MasterOp::Stop),
_ => None,
};
bits.phase = state.phase.min(3);
bits.count = state.count.min(9);
bits.shift = state.shift;
bits.ack = if state.ack { Ack::Ack } else { Ack::Nack };
bits.arbitrating = state.arbitrating;
bits.driven = Level::from_bool(state.driven);
bits.busy = state.busy;
bits.saw_high = state.saw_high;
bits.scl = Level::from_bool(state.scl);
bits.sda = Level::from_bool(state.sda);
}
self.scl.restore(state.scl_out);
self.sda.restore(state.sda_out);
}
}