pub mod wires;
#[cfg(test)]
mod tests;
use alloc::sync::Arc;
use alloc::vec::Vec;
use core::fmt;
use crate::core::sync::{LockRank, Mutex};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum Direction {
#[default]
Write,
Read,
}
impl Direction {
#[must_use]
pub const fn bit(self) -> u8 {
match self {
Direction::Write => 0,
Direction::Read => 1,
}
}
#[must_use]
pub const fn from_bit(bit: u8) -> Direction {
if bit & 1 == 0 {
Direction::Write
} else {
Direction::Read
}
}
}
impl fmt::Display for Direction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Direction::Write => "write",
Direction::Read => "read",
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum Ack {
#[default]
Ack,
Nack,
}
impl Ack {
#[must_use]
pub const fn from_level(level: crate::core::wire::Level) -> Ack {
if level.is_low() { Ack::Ack } else { Ack::Nack }
}
#[must_use]
pub const fn level(self) -> crate::core::wire::Level {
match self {
Ack::Ack => crate::core::wire::Level::Low,
Ack::Nack => crate::core::wire::Level::High,
}
}
#[must_use]
pub const fn is_ack(self) -> bool {
matches!(self, Ack::Ack)
}
#[must_use]
pub const fn merge(self, other: Ack) -> Ack {
match (self, other) {
(Ack::Nack, Ack::Nack) => Ack::Nack,
_ => Ack::Ack,
}
}
}
impl fmt::Display for Ack {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Ack::Ack => "ack",
Ack::Nack => "nack",
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Address {
Seven(u8),
Ten(u16),
}
pub const GENERAL_CALL: Address = Address::Seven(0x00);
const TEN_BIT_HEADER: u8 = 0b1111_0000;
const TEN_BIT_HEADER_MASK: u8 = 0b1111_1000;
impl Address {
#[must_use]
pub const fn seven(address: u8) -> Option<Address> {
if address > 0x7f {
None
} else {
Some(Address::Seven(address))
}
}
#[must_use]
pub const fn ten(address: u16) -> Option<Address> {
if address > 0x3ff {
None
} else {
Some(Address::Ten(address))
}
}
#[must_use]
pub const fn bits(self) -> u16 {
match self {
Address::Seven(a) => a as u16,
Address::Ten(a) => a,
}
}
#[must_use]
pub const fn is_ten_bit(self) -> bool {
matches!(self, Address::Ten(_))
}
#[must_use]
pub const fn first_byte(self, dir: Direction) -> u8 {
match self {
Address::Seven(a) => (a << 1) | dir.bit(),
Address::Ten(a) => TEN_BIT_HEADER | (((a >> 8) as u8 & 0b11) << 1) | dir.bit(),
}
}
#[must_use]
pub const fn second_byte(self) -> Option<u8> {
match self {
Address::Seven(_) => None,
Address::Ten(a) => Some(a as u8),
}
}
#[must_use]
pub const fn ten_bit_high(self) -> Option<u8> {
match self {
Address::Seven(_) => None,
Address::Ten(a) => Some((a >> 8) as u8 & 0b11),
}
}
#[must_use]
pub const fn is_ten_bit_header(byte: u8) -> bool {
byte & TEN_BIT_HEADER_MASK == TEN_BIT_HEADER
}
#[must_use]
pub const fn seven_from_byte(byte: u8) -> Address {
Address::Seven(byte >> 1)
}
#[must_use]
pub const fn is_reserved(self) -> bool {
match self {
Address::Seven(a) => a & 0b111_1000 == 0 || a & 0b111_1000 == 0b111_1000,
Address::Ten(_) => false,
}
}
}
impl fmt::Display for Address {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Address::Seven(a) => write!(f, "{a:#04x}"),
Address::Ten(a) => write!(f, "{a:#05x}/10"),
}
}
}
pub const START_HALF_PERIODS: u32 = 4;
pub const BYTE_HALF_PERIODS: u32 = 18;
pub const STOP_HALF_PERIODS: u32 = 2;
pub trait I2cSlave: Send + Sync + fmt::Debug {
fn address(&self, address: Address, dir: Direction) -> Ack;
fn ten_bit_header(&self, high: u8) -> bool {
let _ = high;
false
}
fn write(&self, byte: u8) -> Ack;
fn read(&self) -> u8;
fn read_ack(&self, ack: Ack) {
let _ = ack;
}
fn stop(&self);
fn stretching(&self) -> bool {
false
}
fn peek(&self) -> u8 {
0xff
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub enum Link {
#[default]
Transactional,
Wired,
}
impl Link {
#[must_use]
pub fn from_name(name: &str) -> Option<Link> {
match name {
"transactional" => Some(Link::Transactional),
"wired" => Some(Link::Wired),
_ => None,
}
}
#[must_use]
pub const fn name(self) -> &'static str {
match self {
Link::Transactional => "transactional",
Link::Wired => "wired",
}
}
pub const NAMES: &'static [&'static str] = &["transactional", "wired"];
}
impl fmt::Display for Link {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.name())
}
}
pub const FABRIC_RANK: LockRank = LockRank::new(0x4500);
pub const WIRES_RANK: LockRank = LockRank::new(0x4900);
pub const MAX_SLAVES: usize = 128;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BusState {
Free,
Unaddressed,
Addressed {
dir: Direction,
responders: usize,
},
}
impl BusState {
#[must_use]
pub const fn is_busy(self) -> bool {
!matches!(self, BusState::Free)
}
}
pub struct I2cBus {
inner: Mutex<Inner>,
}
#[derive(Debug, Default)]
struct Inner {
slaves: Vec<Arc<dyn I2cSlave>>,
addressed: Vec<usize>,
started: bool,
dir: Direction,
conflicts: u32,
}
impl fmt::Debug for I2cBus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut s = f.debug_struct("I2cBus");
match self.inner.try_lock() {
Some(inner) => s
.field("attached", &inner.slaves.len())
.field("started", &inner.started)
.field("addressed", &inner.addressed.len()),
None => s.field("state", &"<in use>"),
};
s.finish()
}
}
impl I2cBus {
#[must_use]
pub fn new() -> I2cBus {
I2cBus {
inner: Mutex::with_rank(FABRIC_RANK, Inner::default()),
}
}
pub fn attach(&self, slave: Arc<dyn I2cSlave>) -> crate::Result<()> {
let mut inner = self.inner.lock();
if inner.slaves.len() >= MAX_SLAVES {
return Err(crate::Error::Config {
at: alloc::string::String::from("i2c bus"),
message: alloc::format!("an I2C bus in rsemu routes at most {MAX_SLAVES} devices"),
});
}
inner.slaves.push(slave);
Ok(())
}
#[must_use]
pub fn len(&self) -> usize {
self.inner.lock().slaves.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[must_use]
pub fn conflicts(&self) -> u32 {
self.inner.lock().conflicts
}
#[must_use]
pub fn state(&self) -> BusState {
let inner = self.inner.lock();
if !inner.started {
return BusState::Free;
}
if inner.addressed.is_empty() {
return BusState::Unaddressed;
}
BusState::Addressed {
dir: inner.dir,
responders: inner.addressed.len(),
}
}
pub fn start(&self, address: Address, dir: Direction) -> Ack {
let (previous, candidates) = {
let inner = self.inner.lock();
let previous: Vec<Arc<dyn I2cSlave>> = inner
.addressed
.iter()
.filter_map(|i| inner.slaves.get(*i).cloned())
.collect();
(previous, inner.slaves.clone())
};
let mut taken: Vec<usize> = Vec::new();
let mut answer = Ack::Nack;
for (i, slave) in candidates.iter().enumerate() {
if let (Address::Ten(_), Some(high)) = (address, address.ten_bit_high())
&& !slave.ten_bit_header(high)
{
continue;
}
if slave.address(address, dir).is_ack() {
taken.push(i);
answer = Ack::Ack;
}
}
for (i, slave) in candidates.iter().enumerate() {
if !taken.contains(&i) && previous.iter().any(|p| Arc::ptr_eq(p, slave)) {
slave.stop();
}
}
let mut inner = self.inner.lock();
if taken.len() > 1 && address != GENERAL_CALL {
inner.conflicts = inner.conflicts.saturating_add(1);
}
inner.addressed = taken;
inner.started = true;
inner.dir = dir;
answer
}
#[must_use]
pub fn ten_bit_header(&self, high: u8) -> Ack {
let slaves = self.inner.lock().slaves.clone();
if slaves.iter().any(|s| s.ten_bit_header(high & 0b11)) {
Ack::Ack
} else {
Ack::Nack
}
}
pub fn write(&self, byte: u8) -> Ack {
let addressed = self.addressed();
let mut answer = Ack::Nack;
for slave in addressed {
answer = answer.merge(slave.write(byte));
}
answer
}
pub fn read(&self, ack: Ack) -> u8 {
let addressed = self.addressed();
let Some(slave) = addressed.first() else {
return 0xff;
};
let byte = slave.read();
slave.read_ack(ack);
byte
}
#[must_use]
pub fn peek(&self) -> u8 {
self.addressed().first().map_or(0xff, |s| s.peek())
}
pub fn stop(&self) {
let addressed = self.addressed();
{
let mut inner = self.inner.lock();
inner.addressed.clear();
inner.started = false;
}
for slave in addressed {
slave.stop();
}
}
#[must_use]
pub fn stretching(&self) -> bool {
let slaves = self.inner.lock().slaves.clone();
slaves.iter().any(|s| s.stretching())
}
fn addressed(&self) -> Vec<Arc<dyn I2cSlave>> {
let inner = self.inner.lock();
inner
.addressed
.iter()
.filter_map(|i| inner.slaves.get(*i).cloned())
.collect()
}
}
impl Default for I2cBus {
fn default() -> I2cBus {
I2cBus::new()
}
}
pub mod buses {
use super::I2cBus;
use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec::Vec;
use crate::core::error::Result;
use crate::core::hosts::{HostKind, HostObjects};
use crate::core::props::Props;
pub const KIND: HostKind = HostKind::new("i2c-bus");
pub fn open(hosts: &HostObjects, name: &str) -> Result<Arc<I2cBus>> {
hosts.open(KIND, name, I2cBus::new)
}
pub fn attach(props: &Props, name: &str) -> Result<Arc<I2cBus>> {
props.host(KIND, name, I2cBus::new)
}
pub fn get(hosts: &HostObjects, name: &str) -> Result<Option<Arc<I2cBus>>> {
hosts.get(KIND, name)
}
pub fn close(hosts: &HostObjects, name: &str) -> bool {
hosts.close(KIND, name)
}
#[must_use]
pub fn names(hosts: &HostObjects) -> Vec<String> {
hosts.names(KIND)
}
}