diff --git a/lcd-writer/src/lcd.rs b/lcd-writer/src/lcd.rs new file mode 100644 index 0000000..10b2a88 --- /dev/null +++ b/lcd-writer/src/lcd.rs @@ -0,0 +1,81 @@ +use rppal::{i2c, i2c::I2c}; +use std::io; + +const C0: u8 = 7; +const A0: u8 = 6; + +#[allow(unused)] +#[repr(u8)] +enum LcdCommand { + Clear = 1, + ReturnHome = 2, + DisplayOn = 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, + FunctionSet = 1 << 5 | 1 << 4 | 1 << 3, + EntryModeSet = 1 << 2 | 1 << 1, +} + +#[allow(unused)] +#[repr(u8)] +enum ControlByte { + Normal = 1 << C0, + Last = 0 << C0, + Data = 0 << C0 | 1 << A0, +} + +fn i2c_err_to_io_err(err: i2c::Error) -> io::Error { + match err { + i2c::Error::Io(v) => v, + i2c::Error::InvalidSlaveAddress(addr) => io::Error::new( + io::ErrorKind::ConnectionRefused, + format!("invalid slave address {}", addr), + ), + i2c::Error::FeatureNotSupported => io::Error::new( + io::ErrorKind::ConnectionRefused, + "invalid slave address {}".to_owned(), + ), + i2c::Error::UnknownModel => io::Error::new( + io::ErrorKind::ConnectionRefused, + "invalid slave address {}".to_owned(), + ), + } +} + +pub struct Lcd { + bus: I2c, +} + +impl Lcd { + pub fn new() -> io::Result { + let mut bus = I2c::with_bus(1).map_err(i2c_err_to_io_err)?; + bus.set_slave_address(60).map_err(i2c_err_to_io_err)?; + let setup = [ + ControlByte::Last as u8, + LcdCommand::FunctionSet as u8, + LcdCommand::DisplayOn as u8, + LcdCommand::EntryModeSet as u8, + LcdCommand::Clear as u8, + ]; + bus.write(&setup).map_err(i2c_err_to_io_err)?; + Ok(Self { bus }) + } + + pub fn write(&mut self, value: &str) -> io::Result<()> { + let mut data = vec![ControlByte::Data as u8]; + data.extend(value.bytes()); + let _ = self.bus.write(&data).map_err(i2c_err_to_io_err)?; + Ok(()) + } + + pub fn set_cursor(&mut self, col: u8, row: u8) -> io::Result<()> { + let pos = col | (row * 0x40) | 1 << 7; + let data = vec![ControlByte::Last as u8, pos]; + let _ = self.bus.write(&data).map_err(i2c_err_to_io_err)?; + Ok(()) + } + + pub fn clear(&mut self) -> io::Result<()> { + let data = vec![ControlByte::Last as u8, LcdCommand::Clear as u8]; + let _ = self.bus.write(&data).map_err(i2c_err_to_io_err)?; + Ok(()) + } +} diff --git a/lcd-writer/src/lib.rs b/lcd-writer/src/lib.rs new file mode 100644 index 0000000..04b1350 --- /dev/null +++ b/lcd-writer/src/lib.rs @@ -0,0 +1 @@ +pub mod lcd; diff --git a/lcd-writer/src/main.rs b/lcd-writer/src/main.rs index ed5f3fc..99b8f76 100644 --- a/lcd-writer/src/main.rs +++ b/lcd-writer/src/main.rs @@ -1,79 +1,21 @@ -use rppal::{i2c, i2c::I2c}; use std::io::{self, stdin, stdout, BufRead, Write}; -const C0: u8 = 7; -const A0: u8 = 6; +use lcd::Lcd; -#[allow(unused)] -#[repr(u8)] -enum LcdCommand { - Clear = 1, - ReturnHome = 2, - DisplayOn = 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0, - FunctionSet = 1 << 5 | 1 << 4 | 1 << 3, - EntryModeSet = 1 << 2 | 1 << 1, -} - -#[allow(unused)] -#[repr(u8)] -enum ControlByte { - Normal = 1 << C0, - Last = 0 << C0, - Data = 0 << C0 | 1 << A0, -} - -struct Lcd { - bus: I2c, -} - -impl Lcd { - pub fn new() -> Result { - let mut bus = I2c::with_bus(1)?; - bus.set_slave_address(60)?; - let setup = [ - ControlByte::Last as u8, - LcdCommand::FunctionSet as u8, - LcdCommand::DisplayOn as u8, - LcdCommand::EntryModeSet as u8, - LcdCommand::Clear as u8, - ]; - bus.write(&setup)?; - Ok(Self { bus }) - } - - pub fn write(&mut self, value: &str) -> Result<(), i2c::Error> { - let mut data = vec![ControlByte::Data as u8]; - data.extend(value.bytes()); - let _ = self.bus.write(&data)?; - Ok(()) - } - - pub fn set_cursor(&mut self, col: u8, row: u8) -> Result<(), i2c::Error> { - let pos = col | (row * 0x40) | 1 << 7; - let data = vec![ControlByte::Last as u8, pos]; - let _ = self.bus.write(&data)?; - Ok(()) - } - - pub fn clear(&mut self) -> Result<(), i2c::Error> { - let data = vec![ControlByte::Last as u8, LcdCommand::Clear as u8]; - let _ = self.bus.write(&data)?; - Ok(()) - } -} +mod lcd; fn main() -> io::Result<()> { - let mut lcd = Lcd::new().unwrap(); + let mut lcd = Lcd::new()?; loop { print!("> "); stdout().lock().flush()?; let mut line = String::new(); stdin().lock().read_line(&mut line)?; if line.starts_with("clear") { - lcd.clear().unwrap(); - lcd.set_cursor(0, 0).unwrap(); + lcd.clear()?; + lcd.set_cursor(0, 0)?; } else if line.starts_with("print") { - lcd.write(&line[6..]).unwrap(); + lcd.write(&line[6..])?; } else { println!("unrecognized command \"{line}\""); }