use core::any::Any;
use ufmt::derive::uDebug;
use avr_oxide::concurrency::Isolated;
use avr_oxide::hal::generic::callback::IsrCallback;
use avr_oxide::io::IoError;
use avr_oxide::util::{OwnOrBorrow, OwnOrBorrowMut};
use oxide_macros::Persist;
use avr_oxide::OxideResult;
use avr_oxide::OxideResult::{Ok,Err};
#[derive(Clone,Copy,PartialEq,Eq,uDebug,Persist)]
pub enum TwiIdentity {
Twi0master,
Twi0slave,
Twi1master,
Twi1slave,
}
#[derive(Clone,Copy,PartialEq,Eq,uDebug,Persist)]
pub enum InterfaceMode {
I2C,
SMBus
}
#[derive(Clone,Copy,PartialEq,Eq,uDebug,Persist)]
pub enum PortSpeed {
Standard,
Fast,
FastPlus
}
#[derive(Clone,Copy,PartialEq,Eq)]
#[cfg_attr(not(target_arch="avr"), derive(Debug))]
#[cfg_attr(target_arch="avr", derive(ufmt::derive::uDebug))]
pub enum TwiError {
DeviceBusy,
BusError,
NotAcknowledged,
BufferOverflow
}
#[derive(Clone,Copy,PartialEq,Eq,uDebug,Persist)]
pub struct TwiAddr(u8);
pub type TwiCommandCompleteFunction = fn(Isolated, TwiIdentity, OxideResult<(Command<'static>, usize),TwiError>, Option<*const dyn Any>) -> ();
pub type TwiCommandCompleteCallback = IsrCallback<TwiCommandCompleteFunction,()>;
pub trait TwoWireMaster {
fn command(&mut self, command: Command<'static>);
fn try_command(&mut self, command: Command<'static>) -> OxideResult<(),(TwiError, Command<'static>)>;
fn set_command_complete_callback(&self, handler: TwiCommandCompleteCallback);
}
pub trait TwoWireSlave {
fn set_address(&mut self, address: TwiAddr);
}
pub type CommandBuffer = OwnOrBorrow<'static,[u8]>;
pub type ResponseBuffer = OwnOrBorrowMut<'static,[u8]>;
pub type CommandBufferStaticSet = &'static[&'static [u8]];
#[derive(Copy,Clone,Eq,PartialEq)]
pub enum RetryStrategy {
None,
UntilComplete,
UntilAcknowledged
}
pub enum NoneOneOrManyBuffer<'omb,T>
where
T: Clone
{
None,
One(&'omb [T]),
Many(&'omb [&'omb [T]])
}
pub enum NoneOneOrManyMutBuffer<'omb,T>
where
T: Clone
{
None,
One(&'omb mut [T]),
Many(&'omb [&'omb mut [T]])
}
pub struct Command<'c> {
retry_strategy: RetryStrategy,
address: TwiAddr,
tx_buffer: NoneOneOrManyBuffer<'c,u8>,
rx_buffer: NoneOneOrManyMutBuffer<'c,u8>
}
#[derive(Clone)]
pub struct CommandBuilder {
retry_strategy: RetryStrategy,
base_address: TwiAddr
}
pub trait TwiTransaction {
fn get_retry_strategy(&self, isotoken: Isolated) -> RetryStrategy;
fn get_initial_addr_bin(&self, isotoken: Isolated) -> u8;
fn get_read_addr_bin(&self, isotoken: Isolated) -> Option<u8>;
fn get_tx_byte(&self, isotoken: Isolated, index: usize) -> OxideResult<u8,IoError>;
fn set_rx_byte(&mut self, isotoken: Isolated, index: usize, byte: u8) -> OxideResult<usize,IoError>;
}
impl CommandBuilder {
pub fn new(addr: TwiAddr) -> Self {
CommandBuilder {
retry_strategy: RetryStrategy::UntilComplete,
base_address: addr
}
}
pub fn address(self, addr: TwiAddr) -> Self {
CommandBuilder {
retry_strategy: self.retry_strategy,
base_address: addr
}
}
pub fn get_address(&self) -> TwiAddr {
self.base_address
}
pub fn retry(&mut self, retry: RetryStrategy) -> &mut Self {
self.retry_strategy = retry;
self
}
pub fn write_cmd<'b>(&self, buffer: &'b[u8]) -> Command<'b> {
Command {
retry_strategy: self.retry_strategy.clone(),
address: self.base_address.clone(),
tx_buffer: NoneOneOrManyBuffer::One(buffer),
rx_buffer: NoneOneOrManyMutBuffer::None
}
}
pub fn write_multiple_cmd<'b>(&self, buffers: &'b[&'b[u8]]) -> Command<'b> {
Command {
retry_strategy: self.retry_strategy.clone(),
address: self.base_address.clone(),
tx_buffer: NoneOneOrManyBuffer::Many(buffers),
rx_buffer: NoneOneOrManyMutBuffer::None
}
}
pub fn read_cmd<'b>(&self, buffer: &'b mut [u8]) -> Command<'b> {
Command {
retry_strategy: self.retry_strategy.clone(),
address: self.base_address.clone(),
tx_buffer: NoneOneOrManyBuffer::None,
rx_buffer: NoneOneOrManyMutBuffer::One(buffer)
}
}
pub fn wtr_cmd<'b>(&self, write_buffer: &'b [u8], read_buffer: &'b mut [u8]) -> Command<'b> {
Command {
retry_strategy: self.retry_strategy.clone(),
address: self.base_address.clone(),
tx_buffer: NoneOneOrManyBuffer::One(write_buffer),
rx_buffer: NoneOneOrManyMutBuffer::One(read_buffer)
}
}
pub fn wmtr_cmd<'b>(&self, write_buffers: &'b[&'b[u8]], read_buffer: &'b mut [u8]) -> Command<'b> {
Command {
retry_strategy: self.retry_strategy.clone(),
address: self.base_address.clone(),
tx_buffer: NoneOneOrManyBuffer::Many(write_buffers),
rx_buffer: NoneOneOrManyMutBuffer::One(read_buffer)
}
}
}
impl<'omb,T> NoneOneOrManyBuffer<'omb,T>
where
T: Clone
{
#[optimize(speed)]
fn len(&self) -> usize {
match self {
Self::None => 0,
Self::One(buf) => buf.len(),
Self::Many(bufs) => {
let mut len = 0usize;
for slice in *bufs {
len += slice.len();
}
len
}
}
}
#[optimize(speed)]
fn read_at(&self, mut index: usize) -> OxideResult<T,IoError>
where
T: Default
{
if index >= self.len() {
Err(IoError::EndOfFile)
} else {
Ok(match self {
Self::None => panic!(), Self::One(buf) => {
buf[index].clone()
},
Self::Many(bufs) => {
let mut val = T::default();
for slice in *bufs {
if index < slice.len() {
val = slice[index].clone();
break;
} else {
index -= slice.len()
}
}
val
}
})
}
}
#[optimize(speed)]
fn is_none(&self) -> bool {
match self {
NoneOneOrManyBuffer::None => true,
_ => false
}
}
}
impl<'omb,T> NoneOneOrManyMutBuffer<'omb,T>
where
T: Clone
{
#[optimize(speed)]
fn len(&self) -> usize {
match self {
Self::None => 0,
Self::One(buf) => buf.len(),
Self::Many(bufs) => {
let mut len = 0usize;
for slice in *bufs {
len += slice.len();
}
len
}
}
}
#[optimize(speed)]
fn write_at(&mut self, index: usize, value: T) -> OxideResult<(),IoError> {
if index >= self.len() {
Err(IoError::NoFreeSpace)
} else {
match self {
Self::None => {}, Self::One(buf) => {
buf[index] = value;
},
Self::Many(_bufs) => {
unimplemented!()
}
};
Ok(())
}
}
#[optimize(speed)]
fn is_none(&self) -> bool {
match self {
NoneOneOrManyMutBuffer::None => true,
_ => false
}
}
}
impl<'c> TwiTransaction for Command<'c> {
fn get_retry_strategy(&self, _isotoken: Isolated) -> RetryStrategy {
self.retry_strategy.clone()
}
fn get_initial_addr_bin(&self, _isotoken: Isolated) -> u8 {
if self.tx_buffer.is_none() {
self.address.read_addr()
} else {
self.address.write_addr()
}
}
fn get_read_addr_bin(&self, _isotoken: Isolated) -> Option<u8> {
if self.rx_buffer.is_none() {
None
} else {
Some(self.address.read_addr())
}
}
fn get_tx_byte(&self, _isotoken: Isolated, index: usize) -> OxideResult<u8, IoError> {
self.tx_buffer.read_at(index)
}
fn set_rx_byte(&mut self, _isotoken: Isolated, index: usize, byte: u8) -> OxideResult<usize, IoError> {
self.rx_buffer.write_at(index, byte)?;
Ok(self.rx_buffer.len() - index - 1)
}
}
impl TwiAddr {
pub const fn addr(addr: u8) -> Self {
TwiAddr(addr & 0b11111110)
}
pub const fn addr_7bit(addr: u8) -> Self {
TwiAddr(addr << 1)
}
pub fn write_addr(&self) -> u8 {
self.0 & 0b11111110
}
pub fn read_addr(&self) -> u8 {
self.0 | 0b00000001
}
}
impl RetryStrategy {
pub fn should_retry(&self, error: &TwiError) -> bool {
match ( self, error ) {
( RetryStrategy::None, _ ) => false,
( _, TwiError::BufferOverflow ) => false, ( RetryStrategy::UntilComplete, _ ) => true,
( RetryStrategy::UntilAcknowledged, TwiError::NotAcknowledged ) => true,
_ => false
}
}
}
impl From<u8> for TwiAddr {
fn from(val: u8) -> Self {
TwiAddr(val & 0b11111110)
}
}
pub mod base {
use avr_oxide::hal::generic::twi::TwiError;
pub(crate) enum TwiState {
Idle,
Ready,
WaitingAddrAck,
Writing(usize),
Reading(usize),
TransactionComplete(usize),
TransactionError(TwiError),
Reset,
Unknown
}
#[allow(dead_code)]
pub mod zeroseries {
use core::cell::Cell;
use core::marker::PhantomData;
use avr_oxide::concurrency::Isolated;
use avr_oxide::deviceconsts::clock::{MASTER_CLOCK_HZ, MASTER_CLOCK_PRESCALER};
use avr_oxide::hal::generic::MuxControl;
use avr_oxide::hal::generic::twi::{Command, InterfaceMode, PortSpeed, TwiCommandCompleteCallback, TwiError, TwiIdentity, TwiTransaction, TwoWireMaster};
use avr_oxide::hal::generic::twi::base::TwiState;
use avr_oxide::{isr_cb_invoke, OxideResult, panic_if_none, sleepctrl};
use avr_oxide::hal::generic::cpu::private::PermitStandbyToken;
use avr_oxide::hal::generic::cpu::SleepControl;
use avr_oxide::util::datatypes::{BitFieldAccess, BitIndex, BitRange, Volatile, VolatileBitField};
use avr_oxide::OxideResult::{Ok,Err};
#[repr(C)]
pub struct TwoWireInterfaceControlBlock {
pub(crate) ctrla: VolatileBitField,
pub(crate) dualctrl: VolatileBitField,
pub(crate) dbgctrl: VolatileBitField,
pub(crate) mctrla: VolatileBitField,
pub(crate) mctrlb: VolatileBitField,
pub(crate) mstatus: VolatileBitField,
pub(crate) mbaud: Volatile<u8>,
pub(crate) maddr: Volatile<u8>,
pub(crate) mdata: Volatile<u8>,
pub(crate) sctrla: VolatileBitField,
pub(crate) sctrlb: VolatileBitField,
pub(crate) sstatus: VolatileBitField,
pub(crate) saddr: Volatile<u8>,
pub(crate) sdata: Volatile<u8>,
pub(crate) saddrmask: VolatileBitField
}
pub(crate) const SDASETUP : BitIndex = BitIndex::bit_c(4);
pub(crate) const FMPEN : BitIndex = BitIndex::bit_c(1);
pub(crate) const ENABLE : BitIndex = BitIndex::bit_c(0);
pub(crate) const ADDREN : BitIndex = BitIndex::bit_c(0);
pub(crate) const SDAHOLD : BitRange = BitRange::range_c(2,3);
pub(crate) const TIMEOUT : BitRange = BitRange::range_c(2,3);
pub(crate) const SMEN : BitIndex = BitIndex::bit_c(1);
pub(crate) const PMEN : BitIndex = BitIndex::bit_c(2);
pub(crate) const QCEN : BitIndex = BitIndex::bit_c(4);
pub(crate) const WIEN : BitIndex = BitIndex::bit_c(6);
pub(crate) const RIEN : BitIndex = BitIndex::bit_c(7);
pub(crate) const PIEN : BitIndex = BitIndex::bit_c(5);
pub(crate) const APIEN : BitIndex = BitIndex::bit_c(6);
pub(crate) const DIEN : BitIndex = BitIndex::bit_c(7);
pub(crate) const WIF : BitIndex = BitIndex::bit_c(6);
pub(crate) const RIF : BitIndex = BitIndex::bit_c(7);
pub(crate) const APIF : BitIndex = BitIndex::bit_c(6);
pub(crate) const DIF : BitIndex = BitIndex::bit_c(7);
pub(crate) const MCMD : BitRange = BitRange::range_c(0,1);
pub(crate) const ACKACT : BitIndex = BitIndex::bit_c(2);
pub(crate) const FLUSH : BitIndex = BitIndex::bit_c(3);
pub(crate) const BUSSTATE : BitRange = BitRange::range_c(0,1);
pub(crate) const BUSERR : BitIndex = BitIndex::bit_c(2);
pub(crate) const ARBLOST : BitIndex = BitIndex::bit_c(3);
pub(crate) const RXACK : BitIndex = BitIndex::bit_c(4);
pub(crate) const CLKHOLD : BitIndex = BitIndex::bit_c(5);
pub(crate) const MCMD_NOACT : u8 = 0x00;
pub(crate) const MCMD_REPSTART : u8 = 0x01;
pub(crate) const MCMD_RECVTRANS : u8 = 0x02;
pub(crate) const MCMD_SENDTRANS : u8 = 0x02;
pub(crate) const MCMD_STOP : u8 = 0x03;
impl TwoWireInterfaceControlBlock {
#[cfg(target_arch="avr")]
pub(crate) unsafe fn instance_from_addr(addr: u16) -> &'static mut Self {
core::mem::transmute(addr)
}
#[cfg(not(target_arch="avr"))]
pub(crate) unsafe fn instance_from_addr(addr: u16) -> &'static mut Self {
static mut INSTANCE: TwoWireInterfaceControlBlock = TwoWireInterfaceControlBlock {
ctrla: VolatileBitField::all_clr(),
dualctrl: VolatileBitField::all_clr(),
dbgctrl: VolatileBitField::all_clr(),
mctrla: VolatileBitField::all_clr(),
mctrlb: VolatileBitField::all_clr(),
mstatus: VolatileBitField::all_clr(),
mbaud: Volatile::<u8>::zero(),
maddr: Volatile::<u8>::zero(),
mdata: Volatile::<u8>::zero(),
sctrla: VolatileBitField::all_clr(),
sctrlb: VolatileBitField::all_clr(),
sstatus: VolatileBitField::all_clr(),
saddr: Volatile::<u8>::zero(),
sdata: Volatile::<u8>::zero(),
saddrmask: VolatileBitField::all_clr(),
};
&mut INSTANCE
}
}
impl PortSpeed {
const fn to_master_baud(&self) -> u8 {
let f_clk_per = MASTER_CLOCK_HZ / MASTER_CLOCK_PRESCALER as u32;
(match self {
PortSpeed::Standard => {
(f_clk_per - ( 100_000u32 * 10)) / (100_000u32 * 2)
},
PortSpeed::Fast => {
(f_clk_per - ( 400_000u32 * 10)) / (400_000u32 * 2)
},
PortSpeed::FastPlus => {
(f_clk_per - ( 1_000_000u32 * 10)) / (1_000_000u32 * 2)
}
}) as u8
}
}
pub struct AtmelTwi<M>
where
M: MuxControl
{
pub(crate) control: &'static mut TwoWireInterfaceControlBlock,
pub(crate) command_complete_handler: Cell<TwiCommandCompleteCallback>,
pub(crate) phantom: PhantomData<M>,
pub(crate) master_src_id: TwiIdentity,
pub(crate) slave_src_id: TwiIdentity,
pub(crate) command: Option<Command<'static>>,
pub(crate) state: TwiState,
pub(crate) sleep_inhibitor: Option<PermitStandbyToken>
}
impl<M> AtmelTwi<M>
where
M: MuxControl
{
pub fn mux(&mut self, mux: M) -> &mut Self {
mux.route();
self
}
pub fn mode(&mut self, mode: InterfaceMode, speed: PortSpeed) -> &mut Self {
avr_oxide::concurrency::interrupt::isolated(|isotoken|{
match mode {
InterfaceMode::I2C => {
self.control.ctrla.set_to_isolated(isotoken, SDAHOLD, 0x01);
self.control.mctrla.set_to_isolated(isotoken, TIMEOUT, 0x00);
},
InterfaceMode::SMBus => {
self.control.ctrla.set_to_isolated(isotoken, SDAHOLD, 0x03);
self.control.mctrla.set_to_isolated(isotoken, TIMEOUT, 0x01);
}
}
match speed {
PortSpeed::FastPlus => {
self.control.ctrla.set_isolated(isotoken, FMPEN);
self.control.mbaud.write(speed.to_master_baud());
},
_ => {
self.control.ctrla.clr_isolated(isotoken, FMPEN);
self.control.mbaud.write(speed.to_master_baud());
}
}
self.control.mctrla.set_isolated(isotoken, ENABLE);
self.control.mctrla.clr_isolated(isotoken, SMEN);
self.state = TwiState::Reset;
self.master_process(isotoken);
});
self
}
}
impl<M> TwoWireMaster for AtmelTwi<M>
where
M: MuxControl
{
fn command(&mut self, mut command: Command<'static>) {
loop {
match self.try_command(command) {
Ok(()) => {
return;
},
Err((TwiError::DeviceBusy, cmd)) => {
command = cmd;
},
_ => {
avr_oxide::oserror::halt(avr_oxide::oserror::OsError::InternalError);
}
}
}
}
fn try_command(&mut self, command: Command<'static>) -> OxideResult<(), (TwiError, Command<'static>)> {
avr_oxide::concurrency::interrupt::isolated(|isotoken|{
match self.state {
TwiState::Idle => {
self.command = Some(command);
self.state = TwiState::Ready;
self.master_process(isotoken);
Ok(())
}
_ => {
Err((TwiError::DeviceBusy,command))
}
}
})
}
fn set_command_complete_callback(&self, callback: TwiCommandCompleteCallback) {
avr_oxide::concurrency::interrupt::isolated(|_isotoken|{
self.command_complete_handler.replace(callback);
});
}
}
impl<M> AtmelTwi<M>
where
M: MuxControl
{
pub(crate) fn invoke_command_complete_callback(&mut self, isotoken: Isolated, result: OxideResult<(Command<'static>, usize),TwiError>) {
isr_cb_invoke!(isotoken, self.command_complete_handler.get(), self.master_src_id, result)
}
pub(crate) fn master_process(&mut self, isotoken: Isolated) {
const ERROR_FLAGS : u8 = ARBLOST.binary() | BUSERR.binary();
const ERROR_AND_NOACK_FLAGS : u8 = ARBLOST.binary() | BUSERR.binary() | RXACK.binary();
loop {
let mut finished = false;
let mut enable_ints = true;
let mstatus = self.control.mstatus.snapshot();
let next_state= match self.state {
TwiState::Ready => {
if self.sleep_inhibitor.is_none() {
self.sleep_inhibitor = Some(sleepctrl!(isotoken).inhibit_standby());
}
let addr = panic_if_none!(&self.command).get_initial_addr_bin(isotoken);
self.control.maddr.write(addr);
finished = true;
TwiState::WaitingAddrAck
},
TwiState::WaitingAddrAck => {
if mstatus.is_set(WIF) {
if (mstatus & ERROR_AND_NOACK_FLAGS) > 0 {
enable_ints = false;
TwiState::TransactionError(TwiError::NotAcknowledged)
} else {
TwiState::Writing(0)
}
} else if mstatus.is_set(RIF) {
if (mstatus & ERROR_FLAGS) > 0 {
enable_ints = false;
TwiState::TransactionError(TwiError::BusError)
} else {
TwiState::Reading(0)
}
} else {
finished = true;
TwiState::WaitingAddrAck
}
},
TwiState::Writing(index) => {
if (mstatus & ERROR_FLAGS) > 0 {
enable_ints = false;
TwiState::TransactionError(TwiError::BusError)
} else {
if mstatus.is_set(WIF) && mstatus.is_clr(RXACK) {
match panic_if_none!(&self.command).get_tx_byte(isotoken, index) {
Ok(byte) => {
self.control.mctrlb.set_to(MCMD, MCMD_SENDTRANS);
self.control.mdata.write(byte);
finished = true;
TwiState::Writing(index+1)
},
Err(_) => {
match panic_if_none!(&self.command).get_read_addr_bin(isotoken) {
Some(addr) => {
self.control.maddr.write(addr);
self.control.mctrlb.set_to(MCMD, MCMD_REPSTART);
finished = true;
TwiState::WaitingAddrAck
},
None => {
self.control.mctrlb.set_to(MCMD, MCMD_STOP);
enable_ints = false;
TwiState::TransactionComplete(index+1)
}
}
}
}
} else {
finished = true;
TwiState::Writing(index)
}
}
},
TwiState::Reading(index) => {
if (mstatus & ERROR_FLAGS) > 0 {
enable_ints = false;
TwiState::TransactionError(TwiError::BusError)
} else {
if mstatus.is_set(RIF) {
match panic_if_none!(&mut self.command).set_rx_byte(isotoken, index, self.control.mdata.read()) {
Ok(bytes_left) => {
if bytes_left > 0 {
self.control.mctrlb.clr(ACKACT);
self.control.mctrlb.set_to(MCMD, MCMD_RECVTRANS);
finished = true;
TwiState::Reading(index+1)
} else {
self.control.mctrlb.set(ACKACT);
self.control.mctrlb.set_to(MCMD, MCMD_STOP);
enable_ints = false;
TwiState::TransactionComplete(index+1)
}
},
Err(_) => {
self.control.mctrlb.set(ACKACT);
self.control.mctrlb.set_to(MCMD, MCMD_STOP);
enable_ints = false;
TwiState::TransactionError(TwiError::BufferOverflow)
}
}
} else {
finished = true;
TwiState::Reading(index)
}
}
},
TwiState::TransactionError(err) => {
if panic_if_none!(&self.command).get_retry_strategy(isotoken).should_retry(&err) {
enable_ints = false;
TwiState::Ready
} else {
self.command.take();
self.invoke_command_complete_callback(isotoken, Err(err));
enable_ints = false;
TwiState::Reset
}
}
TwiState::TransactionComplete(bytes) => {
let command = panic_if_none!(self.command.take());
self.invoke_command_complete_callback(isotoken, Ok((command,bytes)));
enable_ints = false;
TwiState::Idle
},
TwiState::Reset => {
self.control.mstatus.set_to(BUSSTATE, 0x01);
self.control.mctrlb.set(FLUSH);
enable_ints = false;
TwiState::Idle
}
TwiState::Idle => {
match self.sleep_inhibitor.take() {
None => {},
Some(token) => {
sleepctrl!(isotoken).permit_standby(token);
}
}
finished = true;
enable_ints = false;
TwiState::Idle
}
_ => {
enable_ints = false;
TwiState::Reset
}
};
self.state = next_state;
if finished {
if enable_ints {
self.control.mctrla.set_isolated(isotoken, WIEN);
self.control.mctrla.set_isolated(isotoken, RIEN);
} else {
self.control.mctrla.clr_isolated(isotoken, WIEN);
self.control.mctrla.clr_isolated(isotoken, RIEN);
}
break;
}
}
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! atmel_twi_tpl {
($twiref:expr, $mastersrcref:expr, $slavesrcref:expr, $implementation: ty, $isr_master:expr, $isr_slave:expr) => {
use core::cell::Cell;
use core::marker::PhantomData;
use avr_oxide::hal::generic::twi::base::TwiState;
use avr_oxide::hal::generic::twi::base::zeroseries::AtmelTwi;
use avr_oxide::hal::generic::twi::TwiCommandCompleteCallback;
use avr_oxide::hal::generic::twi::base::zeroseries::TwoWireInterfaceControlBlock;
use avr_oxide::mut_singleton_explicit_init;
pub type TwiImpl = $implementation;
mut_singleton_explicit_init!(
$implementation,
__INSTANCE,
initialise, instance, instance_isolated,
AtmelTwi {
control: TwoWireInterfaceControlBlock::instance_from_addr($twiref),
command_complete_handler: Cell::new(TwiCommandCompleteCallback::Nop(())),
phantom: PhantomData::default(),
master_src_id: $mastersrcref,
slave_src_id: $slavesrcref,
command: None,
state: TwiState::Unknown,
sleep_inhibitor: None
});
#[oxide_macros::interrupt(isr=$isr_master)]
fn twi_master_interrupt(isotoken: avr_oxide::concurrency::Isolated) {
let atmeltwi = instance_isolated(isotoken);
atmeltwi.master_process(isotoken);
}
#[oxide_macros::interrupt(isr=$isr_slave)]
fn twi_slave_interrupt(isotoken: avr_oxide::concurrency::Isolated) {
}
}
}
}
}
#[cfg(test)]
mod tests {
use avr_oxide::hal::generic::twi::{NoneOneOrManyBuffer, NoneOneOrManyMutBuffer};
#[test]
fn test_none_one_or_many() {
let test_data1 = [ 0x01u8, 0x02, 0x03, 0x04 ];
let test_data2 = [ 0x05u8, 0x06, 0x07 ];
let test_data3 = [ 0x08u8, 0x09, 0x0a, 0x0b, 0x0c ];
let combined_test_data = [ &test_data1[..], &test_data2[..], &test_data3[..] ];
let buffer = NoneOneOrManyBuffer::<u8>::None;
assert_eq!(buffer.len(), 0);
assert!(buffer.read_at(0).is_err());
let buffer = NoneOneOrManyBuffer::One(&test_data1);
assert_eq!(buffer.len(), test_data1.len());
println!("Read at 0 == {:?}", buffer.read_at(0));
assert_eq!(buffer.read_at(0).unwrap(), 0x01u8);
println!("Read at 2 == {:?}", buffer.read_at(2));
assert_eq!(buffer.read_at(2).unwrap(), 0x03u8);
assert!(buffer.read_at(4).is_err());
let buffer = NoneOneOrManyBuffer::Many(&combined_test_data);
assert_eq!(buffer.len(), test_data1.len() + test_data2.len() + test_data3.len());
for i in 0..buffer.len() {
assert_eq!(buffer.read_at(i).unwrap(), (i+1) as u8);
}
assert!(buffer.read_at(buffer.len()).is_err());
}
#[test]
fn test_none_one_or_many_mut() {
let mut test_data = [ 0x00u8, 0x00, 0x00, 0x00 ];
let mut buffer = NoneOneOrManyMutBuffer::<u8>::None;
assert_eq!(buffer.len(), 0);
assert!(buffer.write_at(0,0x01).is_err());
let mut buffer = NoneOneOrManyMutBuffer::One(&mut test_data);
buffer.write_at(0, 0xde).unwrap();
buffer.write_at(1, 0xad).unwrap();
buffer.write_at(2, 0xbe).unwrap();
buffer.write_at(3, 0xef).unwrap();
assert!(buffer.write_at(4,0x01).is_err());
assert_eq!(test_data, [ 0xde, 0xad, 0xbe, 0xef ]);
}
}