From a999746c698fe5262ca4ebbd710597accf68c41a Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Sat, 29 Feb 2020 21:27:18 -0700 Subject: [PATCH] implement basics --- .gitignore | 13 +++ Cargo.toml | 12 +++ src/lib.rs | 280 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 305 insertions(+) create mode 100644 Cargo.toml create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore index 62bd1a4..1488475 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,16 @@ Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk + + +#Added by cargo + +/target + + +#Added by cargo +# +#already existing elements were commented out + +#/target +#Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..1757f22 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "digitals" +version = "0.1.0" +authors = ["Ales Katona "] +edition = "2018" +license = "Apache-2" +repository = "https://git.bitsmart.ltd/almindor/digitals.git" +readme = "README.md" +documentation = "https://docs.rs/digitals" + +[dependencies] +embedded-graphics = "0.6.0-beta.1" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..a1c4e1b --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,280 @@ +#![no_std] + +use embedded_graphics::prelude::*; +use embedded_graphics::primitives::Rectangle; +use embedded_graphics::style::PrimitiveStyle; + +pub struct Digitals +where + C: PixelColor, +{ + width: i32, // pixel width (calculated from height) + height: i32, // pixel height (set by user) + stroke: i32, // pixel stroke size for segments, calculated from height + style: PrimitiveStyle, +} + +#[derive(Clone, Copy)] +enum Symbol { + Dot, + Colon, + Exclamation, + Question, + Segments(u8), + Invalid, +} + +enum Segment { + Top, + Bottom, + Middle, + TopLeft, + BottomLeft, + TopRight, + BottomRight, +} + +// u8 single bit to single Segment enum +impl From for Segment { + fn from(bit: u8) -> Self { + match bit { + 1 => Segment::Top, + 2 => Segment::Bottom, + 4 => Segment::Middle, + 8 => Segment::TopLeft, + 16 => Segment::BottomLeft, + 32 => Segment::TopRight, + 64 => Segment::BottomRight, + _ => panic!("Invalid segment bit"), // this is used only internally, shouldn't be possible + } + } +} + +impl From for Symbol { + fn from(value: char) -> Self { + match value { + ' ' => Self::Segments(0b0000_0000), + '0' | 'D' | 'O' => Self::Segments(0b0111_1011), + '1' => Self::Segments(0b0001_1000), + '2' => Self::Segments(0b0011_0111), + '3' => Self::Segments(0b0110_0111), + '4' => Self::Segments(0b0110_1100), + '5' | 'S' => Self::Segments(0b0100_1111), + '6' => Self::Segments(0b0101_1111), + '7' => Self::Segments(0b0110_0001), + '8' | 'B' => Self::Segments(0b0111_1111), + '9' => Self::Segments(0b0110_1111), + '-' => Self::Segments(0b0000_0100), + '_' => Self::Segments(0b0000_0010), + 'A' => Self::Segments(0b0111_1101), + 'C' => Self::Segments(0b0001_1011), + 'E' => Self::Segments(0b0001_1111), + 'F' => Self::Segments(0b0001_1101), + 'H' => Self::Segments(0b0111_1100), + 'I' => Self::Segments(0b0110_0000), + 'L' => Self::Segments(0b0001_1010), + 'P' => Self::Segments(0b0011_1101), + 'U' => Self::Segments(0b0111_1010), + 'Ξ' => Self::Segments(0b0000_0111), + '.' => Self::Dot, + ':' => Self::Colon, + '!' => Self::Exclamation, + '?' => Self::Question, + _ => Self::Invalid, + } + } +} + +impl Symbol { + fn width(self, digitals: &Digitals) -> i32 { + match self { + Self::Dot => digitals.width / 2, + Self::Colon | Self::Exclamation => digitals.width + digitals.stroke + 1, + Self::Question => 0, // TODO + Self::Segments(_) => digitals.width + digitals.stroke + 1, + Self::Invalid => panic!("Invalid symbol encountered"), + } + } +} + +impl Digitals +where + C: PixelColor, +{ + pub fn new(height: i32, style: PrimitiveStyle) -> Self { + assert!(height > 7); // ensure we don't divide to 0 and have width / 2 > 1 + + Self { + width: height / 2, + height, + stroke: height / 16, + style, + } + } + + pub fn draw_str>( + &self, + line: &str, + mut offset: Point, + display: &mut D, + ) -> Result { + let mut count = 0; + + for c in line.chars() { + let symbol = Symbol::from(c); + + if self.draw_symbol(symbol, offset, display)? { + count += 1; // keep count of symbols that made it + } + + offset.x += symbol.width(&self) + } + + Ok(count) + } + + pub fn draw_str_diff>( + &self, + previous_line: &str, + line: &str, + mut offset: Point, + display: &mut D, + ) -> Result { + assert!(previous_line.len() == line.len()); + + let mut count = 0; + + for pair in line.chars().zip(previous_line.chars()) { + let symbol = Symbol::from(pair.0); + + if pair.0 != pair.1 && self.draw_symbol(symbol, offset, display)? { + count += 1; // keep count of symbols that made it + } + + offset.x += symbol.width(&self) + } + + Ok(count) + } + + fn draw_dot>(&self, offset: Point, display: &mut D) -> Result { + let x = self.width / 4 - self.stroke; + let y = self.height - self.stroke; + let s = self.stroke; + + let mut rect = Rectangle::new(Point::new(x, y), Point::new(x + s, y + s)); + rect.translate_mut(offset); + display.draw_rectangle(&rect.into_styled(self.style))?; + + Ok(true) + } + + fn draw_colon>( + &self, + offset: Point, + display: &mut D, + ) -> Result { + let mut draw_dot = |x, y, s| -> Result<(), D::Error> { + let mut rect = Rectangle::new(Point::new(x - s, y - s), Point::new(x + s, y + s)); + rect.translate_mut(offset); + display.draw_rectangle(&rect.into_styled(self.style)) + }; + + draw_dot(self.width / 2, self.height / 3, self.stroke / 2)?; + draw_dot(self.width / 2, self.height / 3 * 2, self.stroke / 2)?; + + Ok(true) + } + + fn draw_exclamation>( + &self, + offset: Point, + display: &mut D, + ) -> Result { + let mut rect = Rectangle::new( + Point::new(self.width / 2 - self.stroke / 2, 0), + Point::new(self.width / 2 + self.stroke / 2, self.height / 3 * 2), + ); + rect.translate_mut(offset); + display.draw_rectangle(&rect.into_styled(self.style))?; + + let mut rect = Rectangle::new( + Point::new(self.width / 2 - self.stroke / 2, self.height - self.stroke), + Point::new(self.width / 2 + self.stroke / 2, self.height), + ); + rect.translate_mut(offset); + display.draw_rectangle(&rect.into_styled(self.style))?; + + Ok(true) + } + + fn draw_question>( + &self, + offset: Point, + display: &mut D, + ) -> Result { + Ok(false) // TODO + } + + fn draw_segment>( + &self, + segment: Segment, + offset: Point, + display: &mut D, + ) -> Result<(), D::Error> { + let w = self.width; + let h = self.height; + let s = self.stroke; + + let (sx, sy, ex, ey) = match segment { + Segment::Top => (0, 0, w, s), + Segment::Bottom => (0, h - s, w, h), + Segment::Middle => (0, h / 2 - s / 2, w, h / 2 + s / 2), + Segment::TopLeft => (0, 0, s, h / 2), + Segment::TopRight => (w - s, 0, w, h / 2), + Segment::BottomLeft => (0, h / 2, s, h), + Segment::BottomRight => (w - s, h / 2, w, h), + }; + + let mut rect = Rectangle::new(Point::new(sx, sy), Point::new(ex, ey)); + rect.translate_mut(offset); + display.draw_rectangle(&rect.into_styled(self.style)) + } + + fn draw_segments>( + &self, + segments: u8, + offset: Point, + display: &mut D, + ) -> Result { + let mut mask = 0b0000_0001; + + for _ in 0..8 { + // loop all 8 bits of u8/segments + if segments & mask > 0 { + // if i_th bit is set, draw given segment + let segment = Segment::from(mask); + self.draw_segment(segment, offset, display)?; + } + mask <<= 1; + } + + Ok(true) + } + + fn draw_symbol>( + &self, + symbol: Symbol, + offset: Point, + display: &mut D, + ) -> Result { + match symbol { + Symbol::Dot => self.draw_dot(offset, display), + Symbol::Colon => self.draw_colon(offset, display), + Symbol::Exclamation => self.draw_exclamation(offset, display), + Symbol::Question => self.draw_question(offset, display), + Symbol::Segments(segments) => self.draw_segments(segments, offset, display), + Symbol::Invalid => Ok(false), + } + } +}