use embedded_hal::{
delay::DelayNs,
i2c::{AddressMode, I2c},
};
use crate::{
command::{Bits, Command, ReadWriteOp, RegisterSelection, State},
utils::{BitOps, BitState},
};
use super::SendCommand;
pub struct I2cSender<'a, I2cLcd: I2c<A>, A: AddressMode + Clone> {
i2c: &'a mut I2cLcd,
addr: A,
first_command: bool,
backlight_state: State,
}
impl<'a, I2cLcd: I2c<A>, A: AddressMode + Clone> I2cSender<'a, I2cLcd, A> {
pub fn new(i2c: &'a mut I2cLcd, addr: A) -> Self {
Self {
i2c,
addr,
first_command: true,
backlight_state: State::Off,
}
}
}
impl<'a, I2cLcd, A, Delayer> SendCommand<Delayer, true> for I2cSender<'a, I2cLcd, A>
where
I2cLcd: I2c<A>,
A: AddressMode + Clone,
Delayer: DelayNs,
{
fn set_actual_backlight(&mut self, state: State) {
let mut i2c_raw_seq: u8 = 0b1111_1011;
match state {
State::On => i2c_raw_seq.set_bit(3),
State::Off => i2c_raw_seq.clear_bit(3),
};
self.i2c.write(self.addr.clone(), &[i2c_raw_seq]).unwrap();
self.backlight_state = state;
}
fn get_actual_backlight(&mut self) -> State {
let mut buf = [0u8];
self.i2c.read(self.addr.clone(), &mut buf).unwrap();
match buf[0].check_bit(3) {
BitState::Clear => State::Off,
BitState::Set => State::On,
}
}
fn send(&mut self, lcd_command: Command) -> Option<u8> {
if self.first_command {
assert!(
lcd_command.get_data().is_some(),
"first command should has some data to write"
);
match lcd_command.get_data().unwrap() {
Bits::Bit8(_) => panic!("first command should be 4 bit"),
Bits::Bit4(_) => {
let i2c_command = I2cCommand::gen_i2c_cmd(lcd_command, self.backlight_state);
assert!(
i2c_command.0 == 0b0010_0000 || i2c_command.0 == 0b0010_1000,
"first command should be Function set, and should set to 4 bit mode"
);
let I2cRawSeq(len, raw_seq) = i2c_command.into();
self.i2c
.write(self.addr.clone(), &raw_seq[0..len as usize])
.unwrap();
}
}
self.first_command = false;
} else {
if let Some(Bits::Bit4(_)) = lcd_command.get_data() {
panic!("Only first command is 4 bit long, other command should be 8 bit long")
}
match lcd_command.get_read_write_op() {
ReadWriteOp::Write => {
assert!(
lcd_command.get_data().is_some(),
"first command should has some data to write"
);
if lcd_command.get_register_selection() == RegisterSelection::Command {
match lcd_command.get_data().unwrap() {
Bits::Bit8(lcd_command_data) => {
if (lcd_command_data >> 4) == 0b0011 {
panic!("This I2C driver doesn't support 8 bit Data Width Mode")
}
}
_ => unreachable!(),
}
}
let i2c_command = I2cCommand::gen_i2c_cmd(lcd_command, self.backlight_state);
let I2cRawSeq(len, raw_seq) = i2c_command.into();
self.i2c
.write(self.addr.clone(), &raw_seq[0..len as usize])
.unwrap();
}
ReadWriteOp::Read => {
let mut concat_buf = [0u8; 2];
let mut buf = [0u8];
let i2c_command = I2cCommand::gen_i2c_cmd(lcd_command, self.backlight_state);
let I2cRawSeq(len, raw_seq) = i2c_command.into();
assert_eq!(
len, 6,
"Read command will always need to send 6 I2C sequence"
);
self.i2c
.write_read(self.addr.clone(), &raw_seq[0..2], &mut buf)
.unwrap();
concat_buf[0] = buf[0];
self.i2c
.write_read(self.addr.clone(), &raw_seq[2..5], &mut buf)
.unwrap();
self.i2c.write(self.addr.clone(), &raw_seq[5..6]).unwrap();
concat_buf[1] = buf[0];
return Some((concat_buf[0] & 0b1111_0000) | (concat_buf[1] >> 4));
}
};
}
None
}
}
struct I2cCommand(u8, Option<u8>);
impl Default for I2cCommand {
fn default() -> Self {
Self(0, Some(0))
}
}
impl I2cCommand {
fn gen_i2c_cmd(lcd_command: Command, backlight_state: State) -> Self {
let mut i2c_raw_data = I2cCommand::default();
let i2c_raw_data_1_inner = i2c_raw_data.1.as_mut().unwrap();
if lcd_command.get_register_selection() == RegisterSelection::Data {
i2c_raw_data.0.set_bit(0);
i2c_raw_data_1_inner.set_bit(0);
}
match backlight_state {
State::Off => {
i2c_raw_data.0.clear_bit(3);
i2c_raw_data_1_inner.clear_bit(3);
}
State::On => {
i2c_raw_data.0.set_bit(3);
i2c_raw_data_1_inner.set_bit(3);
}
}
match lcd_command.get_read_write_op() {
ReadWriteOp::Write => match lcd_command.get_data() {
None => panic!("Write command should have some data to be send"),
Some(command_data) => match command_data {
Bits::Bit4(raw_data) => {
assert!(raw_data < (1 << 4), "data is overflow 4 bit");
i2c_raw_data.0 |= raw_data << 4;
i2c_raw_data.1 = None;
}
Bits::Bit8(raw_data) => {
i2c_raw_data.0 |= raw_data & 0b1111_0000;
*i2c_raw_data_1_inner |= (raw_data & 0b0000_1111) << 4
}
},
},
ReadWriteOp::Read => {
i2c_raw_data.0.set_bit(1);
i2c_raw_data.0 |= 0b1111 << 4;
i2c_raw_data_1_inner.set_bit(1);
*i2c_raw_data_1_inner |= 0b1111 << 4; }
}
i2c_raw_data
}
}
struct I2cRawSeq(u8, [u8; 6]);
impl From<I2cCommand> for I2cRawSeq {
fn from(i2c_command: I2cCommand) -> Self {
let mut seq = [0u8; 6];
let mut len = 3;
let mut disable_0 = i2c_command.0;
disable_0.clear_bit(2);
let mut enable_0 = disable_0;
enable_0.set_bit(2);
seq[0] = disable_0;
seq[1] = enable_0;
seq[2] = disable_0;
if i2c_command.1.is_some() {
let mut disable_1 = i2c_command.1.unwrap();
disable_1.clear_bit(2);
let mut enable_1 = disable_1;
enable_1.set_bit(2);
seq[3] = disable_1;
seq[4] = enable_1;
seq[5] = disable_1;
len = 6;
}
Self(len, seq)
}
}