implement basics
parent
a97250d9ac
commit
a999746c69
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "digitals"
|
||||
version = "0.1.0"
|
||||
authors = ["Ales Katona <ales@katona.me>"]
|
||||
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"
|
@ -0,0 +1,280 @@
|
||||
#![no_std]
|
||||
|
||||
use embedded_graphics::prelude::*;
|
||||
use embedded_graphics::primitives::Rectangle;
|
||||
use embedded_graphics::style::PrimitiveStyle;
|
||||
|
||||
pub struct Digitals<C>
|
||||
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<C>,
|
||||
}
|
||||
|
||||
#[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<u8> 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<char> 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<C: PixelColor>(self, digitals: &Digitals<C>) -> 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<C> Digitals<C>
|
||||
where
|
||||
C: PixelColor,
|
||||
{
|
||||
pub fn new(height: i32, style: PrimitiveStyle<C>) -> 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<D: DrawTarget<C>>(
|
||||
&self,
|
||||
line: &str,
|
||||
mut offset: Point,
|
||||
display: &mut D,
|
||||
) -> Result<u8, D::Error> {
|
||||
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<D: DrawTarget<C>>(
|
||||
&self,
|
||||
previous_line: &str,
|
||||
line: &str,
|
||||
mut offset: Point,
|
||||
display: &mut D,
|
||||
) -> Result<u8, D::Error> {
|
||||
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<D: DrawTarget<C>>(&self, offset: Point, display: &mut D) -> Result<bool, D::Error> {
|
||||
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<D: DrawTarget<C>>(
|
||||
&self,
|
||||
offset: Point,
|
||||
display: &mut D,
|
||||
) -> Result<bool, D::Error> {
|
||||
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<D: DrawTarget<C>>(
|
||||
&self,
|
||||
offset: Point,
|
||||
display: &mut D,
|
||||
) -> Result<bool, D::Error> {
|
||||
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<D: DrawTarget<C>>(
|
||||
&self,
|
||||
offset: Point,
|
||||
display: &mut D,
|
||||
) -> Result<bool, D::Error> {
|
||||
Ok(false) // TODO
|
||||
}
|
||||
|
||||
fn draw_segment<D: DrawTarget<C>>(
|
||||
&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<D: DrawTarget<C>>(
|
||||
&self,
|
||||
segments: u8,
|
||||
offset: Point,
|
||||
display: &mut D,
|
||||
) -> Result<bool, D::Error> {
|
||||
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<D: DrawTarget<C>>(
|
||||
&self,
|
||||
symbol: Symbol,
|
||||
offset: Point,
|
||||
display: &mut D,
|
||||
) -> Result<bool, D::Error> {
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue