summaryrefslogtreecommitdiffstats
path: root/src/lib.rs
diff options
context:
space:
mode:
authorAgathe Porte <microjoe@microjoe.org>2020-01-11 12:34:49 +0100
committerAgathe Porte <microjoe@microjoe.org>2020-02-08 12:26:23 +0100
commit61a61f3907e802f0be9bc0039a84ebaabba7b372 (patch)
tree02fdc99a4a88858ed522727efb1f3a508fc081a1 /src/lib.rs
downloadcharlcd-61a61f3907e802f0be9bc0039a84ebaabba7b372.tar.gz
charlcd-61a61f3907e802f0be9bc0039a84ebaabba7b372.zip
initial version
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs201
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))
+ }
+}