lcd1602-driver 0.3.0

A LCD1602 driver
Documentation
use crate::command::{DataWidth, Font, LineMode, MoveDirection, RAMType, ShiftType, State};

#[derive(Default)]
pub(crate) struct LcdState {
    data_width: DataWidth,
    line: LineMode,
    font: Font,
    display_on: State,
    cursor_on: State,
    cursor_blink: State,
    direction: MoveDirection,
    shift_type: ShiftType,
    cursor_pos: (u8, u8),
    display_offset: u8,
    ram_type: RAMType,
    backlight: State,
}

impl LcdState {
    pub(crate) fn get_backlight(&self) -> State {
        self.backlight
    }

    pub(crate) fn set_backlight(&mut self, backlight: State) {
        self.backlight = backlight;
    }

    pub(crate) fn get_data_width(&self) -> DataWidth {
        self.data_width
    }

    pub(crate) fn set_data_width(&mut self, data_width: DataWidth) {
        self.data_width = data_width;
    }

    pub(crate) fn get_line_mode(&self) -> LineMode {
        self.line
    }

    pub(crate) fn set_line_mode(&mut self, line: LineMode) {
        if self.get_font() == Font::Font5x11 {
            assert!(
                line == LineMode::OneLine,
                "Font is 5x11, LineMode cannot be TwoLine"
            )
        }
        self.line = line;
    }

    pub(crate) fn get_line_capacity(&self) -> u8 {
        match self.get_line_mode() {
            LineMode::OneLine => 80,
            LineMode::TwoLine => 40,
        }
    }

    pub(crate) fn get_font(&self) -> Font {
        self.font
    }

    pub(crate) fn set_font(&mut self, font: Font) {
        if self.get_line_mode() == LineMode::TwoLine {
            assert!(
                font == Font::Font5x8,
                "LineMode is TwoLine, Font cannot be 5x11"
            )
        }
        self.font = font;
    }

    pub(crate) fn get_display_state(&self) -> State {
        self.display_on
    }

    pub(crate) fn set_display_state(&mut self, display: State) {
        self.display_on = display;
    }

    pub(crate) fn get_cursor_state(&self) -> State {
        self.cursor_on
    }

    pub(crate) fn set_cursor_state(&mut self, cursor: State) {
        self.cursor_on = cursor;
    }

    pub(crate) fn get_cursor_blink(&self) -> State {
        self.cursor_blink
    }

    pub(crate) fn set_cursor_blink(&mut self, blink: State) {
        self.cursor_blink = blink;
    }

    pub(crate) fn get_direction(&self) -> MoveDirection {
        self.direction
    }

    pub(crate) fn set_direction(&mut self, dir: MoveDirection) {
        self.direction = dir;
    }

    pub(crate) fn get_shift_type(&self) -> ShiftType {
        self.shift_type
    }

    pub(crate) fn set_shift_type(&mut self, shift: ShiftType) {
        self.shift_type = shift;
    }

    pub(crate) fn get_cursor_pos(&self) -> (u8, u8) {
        self.cursor_pos
    }

    pub(crate) fn set_cursor_pos(&mut self, pos: (u8, u8)) {
        let line_capacity = self.get_line_capacity();
        match self.line {
            LineMode::OneLine => {
                assert!(pos.0 < line_capacity, "x offset too big");
                assert!(pos.1 < 1, "always keep y as 0 on OneLine mode");
            }
            LineMode::TwoLine => {
                assert!(pos.0 < line_capacity, "x offset too big");
                assert!(pos.1 < 2, "y offset too big");
            }
        }

        self.cursor_pos = pos;
    }

    pub(crate) fn get_display_offset(&self) -> u8 {
        self.display_offset
    }

    pub(crate) fn set_display_offset(&mut self, offset: u8) {
        if offset >= self.get_line_capacity() {
            match self.get_line_mode() {
                LineMode::OneLine => panic!("Display Offset too big, should not bigger than 79"),
                LineMode::TwoLine => panic!("Display Offset too big, should not bigger than 39"),
            }
        }

        self.display_offset = offset;
    }

    pub(crate) fn shift_cursor_or_display(&mut self, st: ShiftType, dir: MoveDirection) {
        let cur_display_offset = self.get_display_offset();
        let cur_cursor_pos = self.get_cursor_pos();
        let line_capacity = self.get_line_capacity();

        match st {
            ShiftType::CursorOnly => match dir {
                MoveDirection::LeftToRight => match self.get_line_mode() {
                    LineMode::OneLine => {
                        if cur_cursor_pos.0 == line_capacity - 1 {
                            self.set_cursor_pos((0, 0));
                        } else {
                            self.set_cursor_pos((cur_cursor_pos.0 + 1, 0));
                        }
                    }
                    LineMode::TwoLine => {
                        if cur_cursor_pos.0 == line_capacity - 1 {
                            if cur_cursor_pos.1 == 0 {
                                self.set_cursor_pos((0, 1));
                            } else {
                                self.set_cursor_pos((0, 0));
                            }
                        } else {
                            self.set_cursor_pos((cur_cursor_pos.0 + 1, cur_cursor_pos.1));
                        }
                    }
                },
                MoveDirection::RightToLeft => match self.get_line_mode() {
                    LineMode::OneLine => {
                        if cur_cursor_pos.0 == 0 {
                            self.set_cursor_pos((line_capacity - 1, 0));
                        } else {
                            self.set_cursor_pos((cur_cursor_pos.0 - 1, 0));
                        }
                    }
                    LineMode::TwoLine => {
                        if cur_cursor_pos.0 == 0 {
                            if cur_cursor_pos.1 == 0 {
                                self.set_cursor_pos((line_capacity - 1, 1));
                            } else {
                                self.set_cursor_pos((line_capacity - 1, 0));
                            }
                        } else {
                            self.set_cursor_pos((cur_cursor_pos.0 - 1, cur_cursor_pos.1));
                        }
                    }
                },
            },
            ShiftType::CursorAndDisplay => match dir {
                MoveDirection::LeftToRight => {
                    if cur_display_offset == line_capacity - 1 {
                        self.set_display_offset(0)
                    } else {
                        self.set_display_offset(cur_display_offset + 1)
                    };
                }
                MoveDirection::RightToLeft => {
                    if cur_display_offset == 0 {
                        self.set_display_offset(line_capacity - 1)
                    } else {
                        self.set_display_offset(cur_display_offset - 1)
                    };
                }
            },
        }
    }

    pub(crate) fn get_ram_type(&self) -> RAMType {
        self.ram_type
    }

    pub(crate) fn set_ram_type(&mut self, ram_type: RAMType) {
        self.ram_type = ram_type;
    }

    pub(crate) fn calculate_pos_by_offset(
        &self,
        original_pos: (u8, u8),
        offset: (i8, i8),
    ) -> (u8, u8) {
        let line_capacity = self.get_line_capacity();

        match self.get_line_mode() {
            LineMode::OneLine => {
                assert!(
                    offset.0.unsigned_abs() < line_capacity,
                    "x offset too big, should greater than -80 and less than 80"
                );
                assert!(offset.1 == 0, "y offset should always be 0 on OneLine Mode")
            }
            LineMode::TwoLine => {
                assert!(
                    offset.0.unsigned_abs() < line_capacity,
                    "x offset too big, should greater than -40 and less than 40"
                );
                assert!(
                    offset.1.abs() < 2,
                    "y offset too big, should between -1 and 1"
                )
            }
        }

        match self.get_line_mode() {
            LineMode::OneLine => {
                let raw_x_pos = (original_pos.0 as i8) + offset.0;
                if raw_x_pos < 0 {
                    ((raw_x_pos + line_capacity as i8) as u8, 0)
                } else if raw_x_pos > line_capacity as i8 {
                    ((raw_x_pos - line_capacity as i8) as u8, 0)
                } else {
                    (raw_x_pos as u8, 0)
                }
            }
            LineMode::TwoLine => {
                let mut x_overflow: i8 = 0;

                // this likes a "adder" in logic circuit design

                let mut raw_x_pos = (original_pos.0 as i8) + offset.0;

                if raw_x_pos < 0 {
                    raw_x_pos += 2;
                    x_overflow = -1;
                } else if raw_x_pos > line_capacity as i8 {
                    raw_x_pos -= 2;
                    x_overflow = 1;
                }

                let mut raw_y_pos = (original_pos.1 as i8) + offset.1 + x_overflow;
                if raw_y_pos < 0 {
                    raw_y_pos += 2
                } else if raw_y_pos > 2 {
                    raw_y_pos -= 2
                };

                (raw_x_pos as u8, raw_y_pos as u8)
            }
        }
    }
}