use crate::delay::delay_ms;
use bit_field::BitField;
use core::ptr::read_volatile;
use fixed_slice_vec::FixedSliceVec;
use volatile::Volatile;
#[repr(C, packed)]
pub struct Twi {
_twbr: Volatile<u8>,
twcr: Volatile<u8>,
twsr: Volatile<u8>,
twdr: Volatile<u8>,
_twar: Volatile<u8>,
_twamr: Volatile<u8>,
}
const TWINT: u8 = 0;
const TWEA: u8 = 1;
const TWSTA: u8 = 2;
const TWSTO: u8 = 3;
const _TWWC: u8 = 4;
const TWEN: u8 = 5;
const _TWIE: u8 = 7;
static TWI_FREQUENCY: u32 = 100000;
pub fn prescaler() -> (u8, bool, bool) {
if (crate::config::CPU_FREQUENCY_HZ / TWI_FREQUENCY - 16) / (2 * 1) >= 10
&& (crate::config::CPU_FREQUENCY_HZ / TWI_FREQUENCY - 16) / (2 * 1) <= 0xFF
{
return (1, false, false);
} else if (crate::config::CPU_FREQUENCY_HZ / TWI_FREQUENCY - 16) / (2 * 4) >= 10
&& (crate::config::CPU_FREQUENCY_HZ / TWI_FREQUENCY - 16) / (2 * 4) <= 0xFF
{
return (4, true, false);
} else if (crate::config::CPU_FREQUENCY_HZ / TWI_FREQUENCY - 16) / (2 * 16) >= 10
&& (crate::config::CPU_FREQUENCY_HZ / TWI_FREQUENCY - 16) / (2 * 16) <= 0xFF
{
return (16, false, true);
} else if (crate::config::CPU_FREQUENCY_HZ / TWI_FREQUENCY - 16) / (2 * 64) >= 10
&& (crate::config::CPU_FREQUENCY_HZ / TWI_FREQUENCY - 16) / (2 * 64) <= 0xFF
{
return (64, true, true);
} else {
panic!("TWI_FREQUENCY too low!");
}
}
const TWPS1: u8 = 6;
const TWPS0: u8 = 7;
const START: u8 = 0x08;
const REP_START: u8 = 0x10;
const MT_SLA_ACK: u8 = 0x18;
const _MT_SLA_NACK: u8 = 0x20;
const MT_DATA_ACK: u8 = 0x28;
const _MT_DATA_NACK: u8 = 0x30;
const _MT_ARB_LOST: u8 = 0x38;
const _MR_ARB_LOST: u8 = 0x38;
const MR_SLA_ACK: u8 = 0x40;
const _MR_SLA_NACK: u8 = 0x48;
const MR_DATA_ACK: u8 = 0x50;
const MR_DATA_NACK: u8 = 0x58;
const _ST_SLA_ACK: u8 = 0xA8;
const _ST_ARB_LOST_SLA_ACK: u8 = 0xB0;
const _ST_DATA_ACK: u8 = 0xB8;
const _ST_DATA_NACK: u8 = 0xC0;
const _ST_LAST_DATA: u8 = 0xC8;
const _SR_SLA_ACK: u8 = 0x60;
const _SR_ARB_LOST_SLA_ACK: u8 = 0x68;
const _SR_GCALL_ACK: u8 = 0x70;
const _SR_ARB_LOST_GCALL_ACK: u8 = 0x78;
const _SR_DATA_ACK: u8 = 0x80;
const _SR_DATA_NACK: u8 = 0x88;
const _SR_GCALL_DATA_ACK: u8 = 0x90;
const _SR_GCALL_DATA_NACK: u8 = 0x98;
const _SR_STOP: u8 = 0xA0;
const _NO_INFO: u8 = 0xF8;
const _BUS_ERROR: u8 = 0x00;
const _TWCR_CMD_MASK: u8 = 0x0F;
const TWSR_STATUS_MASK: u8 = 0xF8;
const _I2C_OK: u8 = 0x00;
const _I2C_ERROR_NODEV: u8 = 0x01;
const I2C_TIMEOUT: u32 = 100;
pub fn write_sda() {
unsafe {
let port_d = &mut *(0x2A as *mut u8);
let mut ddrd = read_volatile(port_d);
ddrd.set_bit(1, true);
}
}
pub fn read_sda() {
unsafe {
let port_d = &mut *(0x2A as *mut u8);
let mut ddrd = read_volatile(port_d);
ddrd.set_bit(1, false);
}
}
impl Twi {
pub fn new() -> &'static mut Self {
unsafe { &mut *(0xB8 as *mut Self) }
}
pub fn wait_to_complete(&mut self, start: u8) -> bool {
let mut i: u32 = 0;
while !self.twcr.read().get_bit(TWINT) || i <= I2C_TIMEOUT {
unsafe {
llvm_asm!("nop");
}
i += 1;
}
if self.twsr.read() & TWSR_STATUS_MASK != start || i >= I2C_TIMEOUT {
return false;
} else {
return true;
}
}
pub fn init(&mut self) {
self.twsr.update(|sr| {
sr.set_bit(TWPS0, prescaler().1);
sr.set_bit(TWPS1, prescaler().2);
});
self.twcr.update(|cr| {
cr.set_bit(TWEN, true);
})
}
pub fn start(&mut self) -> bool {
write_sda();
self.twcr.update(|x| {
x.set_bit(TWSTA, true);
x.set_bit(TWINT, true);
x.set_bit(TWEN, true);
});
return self.wait_to_complete(START);
}
pub fn stop(&mut self) {
self.twcr.update(|x| {
x.set_bit(TWSTO, true);
x.set_bit(TWINT, true);
x.set_bit(TWEN, true);
});
}
pub fn rep_start(&mut self) -> bool {
self.twcr.update(|x| {
x.set_bit(TWSTA, true);
x.set_bit(TWINT, true);
x.set_bit(TWEN, true);
});
return self.wait_to_complete(REP_START);
}
pub fn address_write(&mut self, address: u8) -> bool {
self.twdr.write(address << 1);
self.twcr.update(|x| {
x.set_bit(TWINT, true);
x.set_bit(TWEN, true);
});
return self.wait_to_complete(MT_SLA_ACK);
}
pub fn address_read(&mut self, address: u8) -> bool {
self.twdr.write(address << 1 | 0x01);
self.twcr.update(|x| {
x.set_bit(TWINT, true);
x.set_bit(TWEN, true);
});
return self.wait_to_complete(MR_SLA_ACK);
}
pub fn read_ack(&mut self, data: &mut FixedSliceVec<u8>) -> bool {
self.twcr.update(|x| {
x.set_bit(TWINT, true);
x.set_bit(TWEA, true);
x.set_bit(TWEN, true);
});
data.push(self.twdr.read());
return self.wait_to_complete(MR_DATA_ACK);
}
pub fn read_ack_burst(&mut self, data: &mut FixedSliceVec<u8>, length: usize) -> usize {
let mut x: usize = 0;
while x < length {
if !self.read_ack(data) {
break;
}
x += 1;
}
return x + 1;
}
pub fn write(&mut self, data: u8) -> bool {
delay_ms(1);
self.twdr.write(data);
self.twcr.update(|x| {
x.set_bit(TWINT, true);
x.set_bit(TWEN, true);
});
return self.wait_to_complete(MT_DATA_ACK);
}
pub fn write_burst(&mut self, data: &FixedSliceVec<u8>) -> usize {
let mut x: usize = 0;
while x < data.len() {
if !self.write(data[x]) {
break;
}
x += 1;
}
return x + 1;
}
pub fn read_nack(&mut self, data: &mut FixedSliceVec<u8>) -> bool {
self.twcr.update(|x| {
x.set_bit(TWINT, true);
x.set_bit(TWEN, true);
});
data.push(self.twdr.read());
return self.wait_to_complete(MR_DATA_NACK);
}
pub fn read_nack_burst(&mut self, data: &mut FixedSliceVec<u8>, length: usize) -> usize {
let mut x: usize = 0;
while x < length {
if !self.read_nack(data) {
break;
}
x += 1;
}
return x + 1;
}
pub fn read_from_slave(
&mut self,
address: u8,
length: usize,
data: &mut FixedSliceVec<u8>,
) -> bool {
delay_ms(1);
read_sda();
if !self.start() {
return false;
}
if !self.address_read(address) {
self.stop();
return false;
}
if length > 1 && self.read_ack_burst(data, length - 1) != length - 1 {
self.stop();
return false;
}
if length > 0 && self.read_nack(data) {
self.stop();
return false;
}
self.stop();
return true;
}
pub fn write_to_slave(&mut self, address: u8, data: &FixedSliceVec<u8>) -> bool {
delay_ms(1);
if !self.start() {
return false;
}
if !self.address_write(address) {
return false;
}
if self.write_burst(data) != data.len() {
self.stop();
return false;
}
self.stop();
return true;
}
}