diff options
author | Agathe Porte <microjoe@microjoe.org> | 2020-01-11 12:34:49 +0100 |
---|---|---|
committer | Agathe Porte <microjoe@microjoe.org> | 2020-02-08 12:26:23 +0100 |
commit | 61a61f3907e802f0be9bc0039a84ebaabba7b372 (patch) | |
tree | 02fdc99a4a88858ed522727efb1f3a508fc081a1 /src/lib.rs | |
download | charlcd-61a61f3907e802f0be9bc0039a84ebaabba7b372.tar.gz charlcd-61a61f3907e802f0be9bc0039a84ebaabba7b372.zip |
initial version
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..f849712 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,201 @@ +mod codes; + +use std::fs::{File, OpenOptions}; +use std::path::Path; + +use std::io::BufWriter; +use std::io::Result; +use std::io::Write; + +use codes::SpecialCode; +use codes::WriteInto; + +/// A screen that allows you to send commands to a charlcd driver (or whatever +/// that implements the `Write` trait). +/// +/// Nominal usage: +/// +/// ```rust +/// use charlcd::Screen; +/// +/// fn main() -> std::io::Result<()> { +/// let mut screen = Screen::default(); // will use "/dev/lcd" charlcd driver +/// +/// screen.clear()?; +/// screen.write(b"hello, world!")?; +/// screen.flash_backlight()?; +/// screen.flush()?; // send all the previous commands to the driver at once +/// } +/// ``` +pub struct Screen<T> { + writer: T, +} + +macro_rules! write_simple_code { + ($self:expr, $code:expr) => {{ + $code.write_into(&mut $self.writer)?; + Ok(()) + }}; +} + +impl<T> Screen<T> +where + T: Write, +{ + /// Create a new display instance that will use the provided Writer under + /// the hood to send commands. + pub fn new(writer: T) -> Screen<T> { + Screen { writer } + } + + /// Clean the rest of the current line, from cursor's position. + pub fn kill_eol(&mut self) -> std::io::Result<()> { + write_simple_code!(self, SpecialCode::KillEndOfLine) + } + + /// Reinitialize the display to its default values. + pub fn reinit(&mut self) -> std::io::Result<()> { + write_simple_code!(self, SpecialCode::ReinitializeDisplay) + } + + /// Enable the display text output. + pub fn display_on(&mut self) -> std::io::Result<()> { + write_simple_code!(self, SpecialCode::DisplayOn) + } + + /// Disable the display text output. + pub fn display_off(&mut self) -> std::io::Result<()> { + write_simple_code!(self, SpecialCode::DisplayOff) + } + + /// Enable the underscore cursor (independent of blinking cursor). + pub fn cursor_on(&mut self) -> std::io::Result<()> { + write_simple_code!(self, SpecialCode::CursorOn) + } + + /// Disable the underscore cursor (independent of blinking cursor). + pub fn cursor_off(&mut self) -> std::io::Result<()> { + write_simple_code!(self, SpecialCode::CursorOff) + } + + /// Enable the blinking cursor (independent of underscore cursor). + pub fn blink_on(&mut self) -> std::io::Result<()> { + write_simple_code!(self, SpecialCode::BlinkOn) + } + + /// Disable the blinking cursor (independent of underscore cursor). + pub fn blink_off(&mut self) -> std::io::Result<()> { + write_simple_code!(self, SpecialCode::BlinkOff) + } + + /// Enable the backlight. + pub fn backlight_on(&mut self) -> std::io::Result<()> { + write_simple_code!(self, SpecialCode::BacklightOn) + } + + /// Disable the backlight. + pub fn backlight_off(&mut self) -> std::io::Result<()> { + write_simple_code!(self, SpecialCode::BacklightOff) + } + + /// Flash the backlight during a small duration. + pub fn flash_backlight(&mut self) -> std::io::Result<()> { + write_simple_code!(self, SpecialCode::FlashBacklight) + } + + /// Clear the screen and return the cursor at original (0, 0) XY position. + pub fn clear(&mut self) -> std::io::Result<()> { + self.write(&[0x0c])?; // '\f' escape not defined in Rust + Ok(()) + } + + /// Move the cursor back one character. + pub fn back(&mut self) -> std::io::Result<()> { + self.write(&[0x08])?; // '\b' escape not defined in Rust + Ok(()) + } + + // Less-used (and some non-working?) methods below + + /// Shift cursor left. + pub fn shift_cursor_left(&mut self) -> std::io::Result<()> { + write_simple_code!(self, SpecialCode::ShiftCursorLeft) + } + + /// Shift cursor right. + pub fn shift_cursor_right(&mut self) -> std::io::Result<()> { + write_simple_code!(self, SpecialCode::ShiftCursorRight) + } + + /// Shift display left. + pub fn shift_display_left(&mut self) -> std::io::Result<()> { + write_simple_code!(self, SpecialCode::ShiftDisplayLeft) + } + + /// Shift display right. + pub fn shift_display_right(&mut self) -> std::io::Result<()> { + write_simple_code!(self, SpecialCode::ShiftDisplayRight) + } + + /// Enable one line mode. + /// + /// ![test](https://blog.microjoe.org/images/hd44780-lcd-i2c-screen-using-linux-mainline-charlcd-driver/linux_419.medium.jpg) + pub fn one_line(&mut self) -> std::io::Result<()> { + write_simple_code!(self, SpecialCode::OneLine) + } + + /// Enable two lines mode. + pub fn two_lines(&mut self) -> std::io::Result<()> { + write_simple_code!(self, SpecialCode::TwoLines) + } + + /// Enable small font mode. + /// + /// Seems to have no effect on the screen given the tests with multiple + /// screen variants. + pub fn small_font(&mut self) -> std::io::Result<()> { + write_simple_code!(self, SpecialCode::SmallFont) + } + + /// Enable big font mode. + /// + /// Seems to have no effect on the screen given the tests with multiple + /// screen variants. + pub fn large_font(&mut self) -> std::io::Result<()> { + write_simple_code!(self, SpecialCode::LargeFont) + } +} + +// Reimplement Write trait for Screen, so that user can call the write and +// flush methods of the inner writer. +impl<T> Write for Screen<T> +where + T: Write, +{ + fn write(&mut self, buf: &[u8]) -> Result<usize> { + self.writer.write(buf) + } + fn flush(&mut self) -> Result<()> { + self.writer.flush() + } +} + +// Concrete screen based on a File, to write to the real charlcd driver (or to +// another file). +type FileScreen = Screen<BufWriter<File>>; + +const DEFAULT_SCREEN_DEV_PATH: &str = "/dev/lcd"; + +impl FileScreen { + /// Create a Screen instance based on the passed path to the device. + pub fn from_dev_path(path: &Path) -> std::io::Result<FileScreen> { + let file = OpenOptions::new().write(true).open(path)?; + let buf = BufWriter::new(file); + Ok(Screen::new(buf)) + } + + /// Create a default Screen instance based on `"/dev/lcd"` path. + pub fn default() -> std::io::Result<FileScreen> { + Screen::from_dev_path(&Path::new(DEFAULT_SCREEN_DEV_PATH)) + } +} |