diff --git a/CHANGELOG.md b/CHANGELOG.md index 888609be..368e4297 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ SSD1306 monochrome OLED display. ## [Unreleased] - ReleaseDate +### Changed + +- [#195](https://github.com/jamwaffles/ssd1306/pull/195) Changed `BasicMode::clear` to clear in small batches instead of + one big write. This drops RAM requirement by ~900b and fixes issues on MCUs with less than 1Kb of RAM. +- [#195](https://github.com/jamwaffles/ssd1306/pull/195) Changed `TerminalMode` to use lookup by ASCII code instead of + per-character match when searching for glyph. This may save up to 3.5Kb of compiled code on AVR MCUs. + ## [0.8.2] - 2023-09-29 ### Fixed diff --git a/src/command.rs b/src/command.rs index d786deef..e291a735 100644 --- a/src/command.rs +++ b/src/command.rs @@ -95,14 +95,14 @@ impl Command { where DI: WriteOnlyDataCommand, { - // Transform command into a fixed size array of 7 u8 and the real length for sending - let (data, len) = match self { - Command::Contrast(val) => ([0x81, val, 0, 0, 0, 0, 0], 2), - Command::AllOn(on) => ([0xA4 | (on as u8), 0, 0, 0, 0, 0, 0], 1), - Command::Invert(inv) => ([0xA6 | (inv as u8), 0, 0, 0, 0, 0, 0], 1), - Command::DisplayOn(on) => ([0xAE | (on as u8), 0, 0, 0, 0, 0, 0], 1), - Command::HScrollSetup(dir, start, end, rate) => ( - [ + match self { + Command::Contrast(val) => Self::send_commands(iface, &[0x81, val]), + Command::AllOn(on) => Self::send_commands(iface, &[0xA4 | (on as u8)]), + Command::Invert(inv) => Self::send_commands(iface, &[0xA6 | (inv as u8)]), + Command::DisplayOn(on) => Self::send_commands(iface, &[0xAE | (on as u8)]), + Command::HScrollSetup(dir, start, end, rate) => Self::send_commands( + iface, + &[ 0x26 | (dir as u8), 0, start as u8, @@ -111,72 +111,63 @@ impl Command { 0, 0xFF, ], - 7, ), - Command::VHScrollSetup(dir, start, end, rate, offset) => ( - [ + Command::VHScrollSetup(dir, start, end, rate, offset) => Self::send_commands( + iface, + &[ 0x28 | (dir as u8), 0, start as u8, rate as u8, end as u8, offset, - 0, - ], - 6, - ), - Command::EnableScroll(en) => ([0x2E | (en as u8), 0, 0, 0, 0, 0, 0], 1), - Command::VScrollArea(above, lines) => ([0xA3, above, lines, 0, 0, 0, 0], 3), - Command::LowerColStart(addr) => ([0xF & addr, 0, 0, 0, 0, 0, 0], 1), - Command::UpperColStart(addr) => ([0x10 | (0xF & addr), 0, 0, 0, 0, 0, 0], 1), - Command::ColStart(addr) => ([0xF & addr, 0x10 | (0xF & (addr >> 4)), 0, 0, 0, 0, 0], 2), - Command::AddressMode(mode) => ([0x20, mode as u8, 0, 0, 0, 0, 0], 2), - Command::ColumnAddress(start, end) => ([0x21, start, end, 0, 0, 0, 0], 3), - Command::PageAddress(start, end) => ([0x22, start as u8, end as u8, 0, 0, 0, 0], 3), - Command::PageStart(page) => ([0xB0 | (page as u8), 0, 0, 0, 0, 0, 0], 1), - Command::StartLine(line) => ([0x40 | (0x3F & line), 0, 0, 0, 0, 0, 0], 1), - Command::SegmentRemap(remap) => ([0xA0 | (remap as u8), 0, 0, 0, 0, 0, 0], 1), - Command::Multiplex(ratio) => ([0xA8, ratio, 0, 0, 0, 0, 0], 2), - Command::ReverseComDir(rev) => ([0xC0 | ((rev as u8) << 3), 0, 0, 0, 0, 0, 0], 1), - Command::DisplayOffset(offset) => ([0xD3, offset, 0, 0, 0, 0, 0], 2), - Command::ComPinConfig(alt, lr) => ( - [ - 0xDA, - 0x2 | ((alt as u8) << 4) | ((lr as u8) << 5), - 0, - 0, - 0, - 0, - 0, ], - 2, ), + Command::EnableScroll(en) => Self::send_commands(iface, &[0x2E | (en as u8)]), + Command::VScrollArea(above, lines) => Self::send_commands(iface, &[0xA3, above, lines]), + Command::LowerColStart(addr) => Self::send_commands(iface, &[0xF & addr]), + Command::UpperColStart(addr) => Self::send_commands(iface, &[0x10 | (0xF & addr)]), + Command::ColStart(addr) => { + Self::send_commands(iface, &[0xF & addr, 0x10 | (0xF & (addr >> 4))]) + } + Command::AddressMode(mode) => Self::send_commands(iface, &[0x20, mode as u8]), + Command::ColumnAddress(start, end) => Self::send_commands(iface, &[0x21, start, end]), + Command::PageAddress(start, end) => { + Self::send_commands(iface, &[0x22, start as u8, end as u8]) + } + Command::PageStart(page) => Self::send_commands(iface, &[0xB0 | (page as u8)]), + Command::StartLine(line) => Self::send_commands(iface, &[0x40 | (0x3F & line)]), + Command::SegmentRemap(remap) => Self::send_commands(iface, &[0xA0 | (remap as u8)]), + Command::Multiplex(ratio) => Self::send_commands(iface, &[0xA8, ratio]), + Command::ReverseComDir(rev) => Self::send_commands(iface, &[0xC0 | ((rev as u8) << 3)]), + Command::DisplayOffset(offset) => Self::send_commands(iface, &[0xD3, offset]), + Command::ComPinConfig(alt, lr) => { + Self::send_commands(iface, &[0xDA, 0x2 | ((alt as u8) << 4) | ((lr as u8) << 5)]) + } Command::DisplayClockDiv(fosc, div) => { - ([0xD5, ((0xF & fosc) << 4) | (0xF & div), 0, 0, 0, 0, 0], 2) + Self::send_commands(iface, &[0xD5, ((0xF & fosc) << 4) | (0xF & div)]) } - Command::PreChargePeriod(phase1, phase2) => ( - [0xD9, ((0xF & phase2) << 4) | (0xF & phase1), 0, 0, 0, 0, 0], - 2, - ), - Command::VcomhDeselect(level) => ([0xDB, (level as u8) << 4, 0, 0, 0, 0, 0], 2), - Command::Noop => ([0xE3, 0, 0, 0, 0, 0, 0], 1), - Command::ChargePump(en) => ([0x8D, 0x10 | ((en as u8) << 2), 0, 0, 0, 0, 0], 2), - Command::InternalIref(en, current) => ( - [ - 0xAD, - ((current as u8) << 5) | ((en as u8) << 4), - 0, - 0, - 0, - 0, - 0, - ], - 2, - ), - }; + Command::PreChargePeriod(phase1, phase2) => { + Self::send_commands(iface, &[0xD9, ((0xF & phase2) << 4) | (0xF & phase1)]) + } + Command::VcomhDeselect(level) => { + Self::send_commands(iface, &[0xDB, (level as u8) << 4]) + } + Command::Noop => Self::send_commands(iface, &[0xE3]), + Command::ChargePump(en) => { + Self::send_commands(iface, &[0x8D, 0x10 | ((en as u8) << 2)]) + } + Command::InternalIref(en, current) => { + Self::send_commands(iface, &[0xAD, ((current as u8) << 5) | ((en as u8) << 4)]) + } + } + } - // Send command over the interface - iface.send_commands(U8(&data[0..len])) + fn send_commands(iface: &mut DI, data: &[u8]) -> Result<(), DisplayError> + where + DI: WriteOnlyDataCommand, + { + iface.send_commands(U8(data)) } } diff --git a/src/mode/mod.rs b/src/mode/mod.rs index 0cfbae4c..68244376 100644 --- a/src/mode/mod.rs +++ b/src/mode/mod.rs @@ -31,11 +31,32 @@ where { /// Clear the display. pub fn clear(&mut self) -> Result<(), DisplayError> { - self.set_draw_area((0, 0), self.dimensions())?; + let old_addr_mode = self.addr_mode; + if old_addr_mode != AddrMode::Horizontal { + self.set_addr_mode(AddrMode::Horizontal)?; + } - // TODO: If const generics allows this, replace `1024` with computed W x H value for current - // `SIZE`. - self.draw(&[0u8; 1024]) + let dim = self.dimensions(); + self.set_draw_area((0, 0), dim)?; + + let num_pixels = dim.0 as u16 * dim.1 as u16; + + const BITS_PER_BYTE: u16 = 8; + const BYTES_PER_BATCH: u16 = 64; + const PIXELS_PER_BATCH: u16 = BITS_PER_BYTE * BYTES_PER_BATCH; + + // Not all screens have number of pixels divisible by 512, so add 1 to cover tail + let num_batches = num_pixels / PIXELS_PER_BATCH + 1; + + for _ in 0..num_batches { + self.draw(&[0; BYTES_PER_BATCH as usize])?; + } + + if old_addr_mode != AddrMode::Horizontal { + self.set_addr_mode(old_addr_mode)?; + } + + Ok(()) } } diff --git a/src/mode/terminal.rs b/src/mode/terminal.rs index 63f30b48..2545cbad 100644 --- a/src/mode/terminal.rs +++ b/src/mode/terminal.rs @@ -301,104 +301,205 @@ where } fn char_to_bitmap(input: char) -> [u8; 8] { - // Populate the array with the data from the character array at the right index - match input { - '!' => [0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00], - '"' => [0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00], - '#' => [0x00, 0x12, 0x3f, 0x12, 0x12, 0x3f, 0x12, 0x00], - '$' => [0x00, 0x2e, 0x2a, 0x7f, 0x2a, 0x3a, 0x00, 0x00], - '%' => [0x00, 0x23, 0x13, 0x08, 0x04, 0x32, 0x31, 0x00], - '&' => [0x00, 0x10, 0x2a, 0x25, 0x2a, 0x10, 0x20, 0x00], - '\'' => [0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00], - '(' => [0x00, 0x1e, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00], - ')' => [0x00, 0x21, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00], - '*' => [0x00, 0x08, 0x2a, 0x1c, 0x2a, 0x08, 0x00, 0x00], - '+' => [0x00, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00], - ',' => [0x00, 0x80, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00], - '-' => [0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00], - '.' => [0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00], - '/' => [0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00], - '0' => [0x00, 0x1e, 0x31, 0x29, 0x25, 0x23, 0x1e, 0x00], - '1' => [0x00, 0x22, 0x21, 0x3f, 0x20, 0x20, 0x20, 0x00], - '2' => [0x00, 0x32, 0x29, 0x29, 0x29, 0x29, 0x26, 0x00], - '3' => [0x00, 0x12, 0x21, 0x21, 0x25, 0x25, 0x1a, 0x00], - '4' => [0x00, 0x18, 0x14, 0x12, 0x3f, 0x10, 0x00, 0x00], - '5' => [0x00, 0x17, 0x25, 0x25, 0x25, 0x25, 0x19, 0x00], - '6' => [0x00, 0x1e, 0x25, 0x25, 0x25, 0x25, 0x18, 0x00], - '7' => [0x00, 0x01, 0x01, 0x31, 0x09, 0x05, 0x03, 0x00], - '8' => [0x00, 0x1a, 0x25, 0x25, 0x25, 0x25, 0x1a, 0x00], - '9' => [0x00, 0x06, 0x29, 0x29, 0x29, 0x29, 0x1e, 0x00], - ':' => [0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], - ';' => [0x00, 0x80, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00], - '<' => [0x00, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00], - '=' => [0x00, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00], - '>' => [0x00, 0x22, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00], - '?' => [0x00, 0x02, 0x01, 0x01, 0x29, 0x05, 0x02, 0x00], - '@' => [0x00, 0x1e, 0x21, 0x2d, 0x2b, 0x2d, 0x0e, 0x00], - 'A' => [0x00, 0x3e, 0x09, 0x09, 0x09, 0x09, 0x3e, 0x00], - 'B' => [0x00, 0x3f, 0x25, 0x25, 0x25, 0x25, 0x1a, 0x00], - 'C' => [0x00, 0x1e, 0x21, 0x21, 0x21, 0x21, 0x12, 0x00], - 'D' => [0x00, 0x3f, 0x21, 0x21, 0x21, 0x12, 0x0c, 0x00], - 'E' => [0x00, 0x3f, 0x25, 0x25, 0x25, 0x25, 0x21, 0x00], - 'F' => [0x00, 0x3f, 0x05, 0x05, 0x05, 0x05, 0x01, 0x00], - 'G' => [0x00, 0x1e, 0x21, 0x21, 0x21, 0x29, 0x1a, 0x00], - 'H' => [0x00, 0x3f, 0x04, 0x04, 0x04, 0x04, 0x3f, 0x00], - 'I' => [0x00, 0x21, 0x21, 0x3f, 0x21, 0x21, 0x00, 0x00], - 'J' => [0x00, 0x10, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x00], - 'K' => [0x00, 0x3f, 0x04, 0x0c, 0x0a, 0x11, 0x20, 0x00], - 'L' => [0x00, 0x3f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00], - 'M' => [0x00, 0x3f, 0x02, 0x04, 0x04, 0x02, 0x3f, 0x00], - 'N' => [0x00, 0x3f, 0x02, 0x04, 0x08, 0x10, 0x3f, 0x00], - 'O' => [0x00, 0x1e, 0x21, 0x21, 0x21, 0x21, 0x1e, 0x00], - 'P' => [0x00, 0x3f, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00], - 'Q' => [0x00, 0x1e, 0x21, 0x29, 0x31, 0x21, 0x5e, 0x00], - 'R' => [0x00, 0x3f, 0x09, 0x09, 0x09, 0x19, 0x26, 0x00], - 'S' => [0x00, 0x12, 0x25, 0x25, 0x25, 0x25, 0x18, 0x00], - 'T' => [0x00, 0x01, 0x01, 0x01, 0x3f, 0x01, 0x01, 0x00], - 'U' => [0x00, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x1f, 0x00], - 'V' => [0x00, 0x0f, 0x10, 0x20, 0x20, 0x10, 0x0f, 0x00], - 'W' => [0x00, 0x1f, 0x20, 0x10, 0x10, 0x20, 0x1f, 0x00], - 'X' => [0x00, 0x21, 0x12, 0x0c, 0x0c, 0x12, 0x21, 0x00], - 'Y' => [0x00, 0x01, 0x02, 0x3c, 0x02, 0x01, 0x00, 0x00], - 'Z' => [0x00, 0x21, 0x31, 0x29, 0x25, 0x23, 0x21, 0x00], - '[' => [0x00, 0x3f, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00], - '\\' => [0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00], - ']' => [0x00, 0x21, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00], - '^' => [0x00, 0x04, 0x02, 0x3f, 0x02, 0x04, 0x00, 0x00], - '_' => [0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00], - '`' => [0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00], - 'a' => [0x00, 0x10, 0x2a, 0x2a, 0x2a, 0x3c, 0x00, 0x00], - 'b' => [0x00, 0x3f, 0x24, 0x24, 0x24, 0x18, 0x00, 0x00], - 'c' => [0x00, 0x1c, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00], - 'd' => [0x00, 0x18, 0x24, 0x24, 0x24, 0x3f, 0x00, 0x00], - 'e' => [0x00, 0x1c, 0x2a, 0x2a, 0x2a, 0x24, 0x00, 0x00], - 'f' => [0x00, 0x00, 0x3e, 0x05, 0x01, 0x00, 0x00, 0x00], - 'g' => [0x00, 0x18, 0xa4, 0xa4, 0xa4, 0x7c, 0x00, 0x00], - 'h' => [0x00, 0x3f, 0x04, 0x04, 0x04, 0x38, 0x00, 0x00], - 'i' => [0x00, 0x00, 0x24, 0x3d, 0x20, 0x00, 0x00, 0x00], - 'j' => [0x00, 0x20, 0x40, 0x40, 0x3d, 0x00, 0x00, 0x00], - 'k' => [0x00, 0x3f, 0x0c, 0x12, 0x20, 0x00, 0x00, 0x00], - 'l' => [0x00, 0x1f, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00], - 'm' => [0x00, 0x3e, 0x02, 0x3c, 0x02, 0x3c, 0x00, 0x00], - 'n' => [0x00, 0x3e, 0x02, 0x02, 0x02, 0x3c, 0x00, 0x00], - 'o' => [0x00, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00], - 'p' => [0x00, 0xfc, 0x24, 0x24, 0x24, 0x18, 0x00, 0x00], - 'q' => [0x00, 0x18, 0x24, 0x24, 0x24, 0xfc, 0x00, 0x00], - 'r' => [0x00, 0x3e, 0x04, 0x02, 0x02, 0x00, 0x00, 0x00], - 's' => [0x00, 0x24, 0x2a, 0x2a, 0x2a, 0x10, 0x00, 0x00], - 't' => [0x00, 0x02, 0x1f, 0x22, 0x20, 0x00, 0x00, 0x00], - 'u' => [0x00, 0x1e, 0x20, 0x20, 0x20, 0x1e, 0x00, 0x00], - 'v' => [0x00, 0x06, 0x18, 0x20, 0x18, 0x06, 0x00, 0x00], - 'w' => [0x00, 0x1e, 0x30, 0x1c, 0x30, 0x1e, 0x00, 0x00], - 'x' => [0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00], - 'y' => [0x00, 0x1c, 0xa0, 0xa0, 0xa0, 0x7c, 0x00, 0x00], - 'z' => [0x00, 0x22, 0x32, 0x2a, 0x26, 0x22, 0x00, 0x00], - '{' => [0x00, 0x0c, 0x3f, 0x21, 0x00, 0x00, 0x00, 0x00], - '|' => [0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], - '}' => [0x00, 0x21, 0x3f, 0x0c, 0x00, 0x00, 0x00, 0x00], - '~' => [0x00, 0x02, 0x01, 0x02, 0x01, 0x00, 0x00, 0x00], - _ => [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], - } + const CHARS: [[u8; 6]; 95] = [ + // ! + [0x00, 0x2f, 0x00, 0x00, 0x00, 0x00], + // " + [0x03, 0x00, 0x03, 0x00, 0x00, 0x00], + // # + [0x12, 0x3f, 0x12, 0x12, 0x3f, 0x12], + // $ + [0x2e, 0x2a, 0x7f, 0x2a, 0x3a, 0x00], + // % + [0x23, 0x13, 0x08, 0x04, 0x32, 0x31], + // & + [0x10, 0x2a, 0x25, 0x2a, 0x10, 0x20], + // ' + [0x02, 0x01, 0x00, 0x00, 0x00, 0x00], + // ( + [0x1e, 0x21, 0x00, 0x00, 0x00, 0x00], + // ) + [0x21, 0x1e, 0x00, 0x00, 0x00, 0x00], + // * + [0x08, 0x2a, 0x1c, 0x2a, 0x08, 0x00], + // + + [0x08, 0x08, 0x3e, 0x08, 0x08, 0x00], + // , + [0x80, 0x60, 0x00, 0x00, 0x00, 0x00], + // - + [0x08, 0x08, 0x08, 0x08, 0x08, 0x00], + // . + [0x30, 0x30, 0x00, 0x00, 0x00, 0x00], + // / + [0x20, 0x10, 0x08, 0x04, 0x02, 0x00], + // 0 + [0x1e, 0x31, 0x29, 0x25, 0x23, 0x1e], + // 1 + [0x22, 0x21, 0x3f, 0x20, 0x20, 0x20], + // 2 + [0x32, 0x29, 0x29, 0x29, 0x29, 0x26], + // 3 + [0x12, 0x21, 0x21, 0x25, 0x25, 0x1a], + // 4 + [0x18, 0x14, 0x12, 0x3f, 0x10, 0x00], + // 5 + [0x17, 0x25, 0x25, 0x25, 0x25, 0x19], + // 6 + [0x1e, 0x25, 0x25, 0x25, 0x25, 0x18], + // 7 + [0x01, 0x01, 0x31, 0x09, 0x05, 0x03], + // 8 + [0x1a, 0x25, 0x25, 0x25, 0x25, 0x1a], + // 9 + [0x06, 0x29, 0x29, 0x29, 0x29, 0x1e], + // : + [0x24, 0x00, 0x00, 0x00, 0x00, 0x00], + // ; + [0x80, 0x64, 0x00, 0x00, 0x00, 0x00], + // < + [0x08, 0x14, 0x22, 0x00, 0x00, 0x00], + // = + [0x14, 0x14, 0x14, 0x14, 0x14, 0x00], + // > + [0x22, 0x14, 0x08, 0x00, 0x00, 0x00], + // ? + [0x02, 0x01, 0x01, 0x29, 0x05, 0x02], + // @ + [0x1e, 0x21, 0x2d, 0x2b, 0x2d, 0x0e], + // A + [0x3e, 0x09, 0x09, 0x09, 0x09, 0x3e], + // B + [0x3f, 0x25, 0x25, 0x25, 0x25, 0x1a], + // C + [0x1e, 0x21, 0x21, 0x21, 0x21, 0x12], + // D + [0x3f, 0x21, 0x21, 0x21, 0x12, 0x0c], + // E + [0x3f, 0x25, 0x25, 0x25, 0x25, 0x21], + // F + [0x3f, 0x05, 0x05, 0x05, 0x05, 0x01], + // G + [0x1e, 0x21, 0x21, 0x21, 0x29, 0x1a], + // H + [0x3f, 0x04, 0x04, 0x04, 0x04, 0x3f], + // I + [0x21, 0x21, 0x3f, 0x21, 0x21, 0x00], + // J + [0x10, 0x20, 0x20, 0x20, 0x20, 0x1f], + // K + [0x3f, 0x04, 0x0c, 0x0a, 0x11, 0x20], + // L + [0x3f, 0x20, 0x20, 0x20, 0x20, 0x20], + // M + [0x3f, 0x02, 0x04, 0x04, 0x02, 0x3f], + // N + [0x3f, 0x02, 0x04, 0x08, 0x10, 0x3f], + // O + [0x1e, 0x21, 0x21, 0x21, 0x21, 0x1e], + // P + [0x3f, 0x09, 0x09, 0x09, 0x09, 0x06], + // Q + [0x1e, 0x21, 0x29, 0x31, 0x21, 0x5e], + // R + [0x3f, 0x09, 0x09, 0x09, 0x19, 0x26], + // S + [0x12, 0x25, 0x25, 0x25, 0x25, 0x18], + // T + [0x01, 0x01, 0x01, 0x3f, 0x01, 0x01], + // U + [0x1f, 0x20, 0x20, 0x20, 0x20, 0x1f], + // V + [0x0f, 0x10, 0x20, 0x20, 0x10, 0x0f], + // W + [0x1f, 0x20, 0x10, 0x10, 0x20, 0x1f], + // X + [0x21, 0x12, 0x0c, 0x0c, 0x12, 0x21], + // Y + [0x01, 0x02, 0x3c, 0x02, 0x01, 0x00], + // Z + [0x21, 0x31, 0x29, 0x25, 0x23, 0x21], + // [ + [0x3f, 0x21, 0x00, 0x00, 0x00, 0x00], + // \ + [0x02, 0x04, 0x08, 0x10, 0x20, 0x00], + // ] + [0x21, 0x3f, 0x00, 0x00, 0x00, 0x00], + // ^ + [0x04, 0x02, 0x3f, 0x02, 0x04, 0x00], + // _ + [0x40, 0x40, 0x40, 0x40, 0x40, 0x40], + // ` + [0x01, 0x02, 0x00, 0x00, 0x00, 0x00], + // a + [0x10, 0x2a, 0x2a, 0x2a, 0x3c, 0x00], + // b + [0x3f, 0x24, 0x24, 0x24, 0x18, 0x00], + // c + [0x1c, 0x22, 0x22, 0x22, 0x00, 0x00], + // d + [0x18, 0x24, 0x24, 0x24, 0x3f, 0x00], + // e + [0x1c, 0x2a, 0x2a, 0x2a, 0x24, 0x00], + // f + [0x00, 0x3e, 0x05, 0x01, 0x00, 0x00], + // g + [0x18, 0xa4, 0xa4, 0xa4, 0x7c, 0x00], + // h + [0x3f, 0x04, 0x04, 0x04, 0x38, 0x00], + // i + [0x00, 0x24, 0x3d, 0x20, 0x00, 0x00], + // j + [0x20, 0x40, 0x40, 0x3d, 0x00, 0x00], + // k + [0x3f, 0x0c, 0x12, 0x20, 0x00, 0x00], + // l + [0x1f, 0x20, 0x20, 0x00, 0x00, 0x00], + // m + [0x3e, 0x02, 0x3c, 0x02, 0x3c, 0x00], + // n + [0x3e, 0x02, 0x02, 0x02, 0x3c, 0x00], + // o + [0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00], + // p + [0xfc, 0x24, 0x24, 0x24, 0x18, 0x00], + // q + [0x18, 0x24, 0x24, 0x24, 0xfc, 0x00], + // r + [0x3e, 0x04, 0x02, 0x02, 0x00, 0x00], + // s + [0x24, 0x2a, 0x2a, 0x2a, 0x10, 0x00], + // t + [0x02, 0x1f, 0x22, 0x20, 0x00, 0x00], + // u + [0x1e, 0x20, 0x20, 0x20, 0x1e, 0x00], + // v + [0x06, 0x18, 0x20, 0x18, 0x06, 0x00], + // w + [0x1e, 0x30, 0x1c, 0x30, 0x1e, 0x00], + // x + [0x22, 0x14, 0x08, 0x14, 0x22, 0x00], + // y + [0x1c, 0xa0, 0xa0, 0xa0, 0x7c, 0x00], + // z + [0x22, 0x32, 0x2a, 0x26, 0x22, 0x00], + // { + [0x0c, 0x3f, 0x21, 0x00, 0x00, 0x00], + // | + [0x3f, 0x00, 0x00, 0x00, 0x00, 0x00], + // } + [0x21, 0x3f, 0x0c, 0x00, 0x00, 0x00], + // ~ + [0x02, 0x01, 0x02, 0x01, 0x00, 0x00], + // blank + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + ]; + + let g = (input as usize) + .checked_sub(b'!'.into()) + .and_then(|idx| CHARS.get(idx)) + .unwrap_or(&CHARS[CHARS.len() - 1]); + + [0, g[0], g[1], g[2], g[3], g[4], g[5], 0] } fn rotate_bitmap(bitmap: [u8; 8]) -> [u8; 8] {