use core::cell::RefCell;
use avr_oxide::util::datatypes::{BitField, BitFieldAccess, BitIndex};
use avrox_display::gfx::{Renderable, RenderPlane, XCoord, Point, YCoord, Area};
use avrox_display::{GfxError, GfxResult};
use avrox_display::gfx::dynamic::{OptionalDisplayAs};
use avr_oxide::OxideResult::{Err,Ok};
#[derive(Clone,Copy)]
pub struct SevenSegmentHexDigit<PIX>
where
PIX: Clone
{
value: Option<u8>,
on_colour: PIX,
off_colour: PIX
}
pub struct SevenSegmentDisplay<const DIGITS: usize,const RADIX: u8,PIX,VALUE>
where
PIX: Clone,
VALUE: OptionalDisplayAs<u32> + Clone
{
value: VALUE,
digit_renderer: RefCell<SevenSegmentHexDigit<PIX>>
}
static SEGMENT_MAP : [BitField; 16] = [
BitField::with_initial(0b00111111), BitField::with_initial(0b00000110), BitField::with_initial(0b01011011), BitField::with_initial(0b01001111), BitField::with_initial(0b01100110), BitField::with_initial(0b01101101), BitField::with_initial(0b01111101), BitField::with_initial(0b00000111), BitField::with_initial(0b01111111), BitField::with_initial(0b01101111), BitField::with_initial(0b01011111), BitField::with_initial(0b01111100), BitField::with_initial(0b00111001), BitField::with_initial(0b01011110), BitField::with_initial(0b01111001), BitField::with_initial(0b01110001), ];
const SEG_A : BitIndex = BitIndex::bit_c(0);
const SEG_B : BitIndex = BitIndex::bit_c(1);
const SEG_C : BitIndex = BitIndex::bit_c(2);
const SEG_D : BitIndex = BitIndex::bit_c(3);
const SEG_E : BitIndex = BitIndex::bit_c(4);
const SEG_F : BitIndex = BitIndex::bit_c(5);
const SEG_G : BitIndex = BitIndex::bit_c(6);
const SEG_DP : BitIndex = BitIndex::bit_c(7);
impl<PIX: Clone> SevenSegmentHexDigit<PIX> {
pub const WIDTH: XCoord = 6;
pub const HEIGHT: YCoord = 7;
pub fn new(on_colour: PIX, off_colour: PIX) -> Self {
SevenSegmentHexDigit {
value: None,
on_colour: on_colour,
off_colour: off_colour
}
}
pub fn new_digit(on_colour: PIX, off_colour: PIX, digit: u8) -> Self {
SevenSegmentHexDigit {
value: Some(digit & 0x0f),
on_colour: on_colour,
off_colour: off_colour
}
}
pub fn get_digit(&self) -> Option<u8> {
self.value
}
pub fn set_digit(&mut self, digit: u8){
self.value = Some(digit & 0x0f)
}
pub fn set_digit_o(&mut self, digit: Option<u8>){
self.value = digit
}
pub fn clr_digit(&mut self){
self.value = None
}
const fn segment_for_pixel(coord: Point) -> Option<BitIndex> {
match ( coord.1, coord.0 ) { (6, 5) => Some(SEG_DP), (0, 1) |
(0, 2) |
(0, 3) => Some(SEG_A),
(3, 0) | (1, 0) |
(2, 0) => Some(SEG_F),
(1, 4) |
(2, 4) => Some(SEG_B),
(3, 1) |
(3, 2) |
(3, 3) => Some(SEG_G),
(4, 0) |
(5, 0) => Some(SEG_E),
(3, 4) | (4, 4) |
(5, 4) => Some(SEG_C),
(6, 1) |
(6, 2) |
(6, 3) => Some(SEG_D),
_ => None }
}
}
impl<PIX> Renderable for SevenSegmentHexDigit<PIX>
where
PIX: Clone
{
type PIXEL = PIX;
fn get_pixel_at<P: RenderPlane>(&self, coord: Point) -> GfxResult<Self::PIXEL> {
match (self.value, Self::segment_for_pixel(coord)) {
(None,Some(_segment)) => Ok(self.off_colour.clone()),
(Some(digit),Some(segment)) => {
if SEGMENT_MAP[digit as usize].is_set(segment) {
Ok(self.on_colour.clone())
} else {
Ok(self.off_colour.clone())
}
},
_ => Err(GfxError::OutOfBounds)
}
}
fn get_dimensions<P: RenderPlane>(&self) -> GfxResult<(XCoord, YCoord)> {
Ok((Self::WIDTH, Self::HEIGHT))
}
}
impl<const DIGITS: usize,const RADIX: u8,PIX,VALUE> SevenSegmentDisplay<DIGITS,RADIX,PIX,VALUE>
where
PIX: Clone,
VALUE: OptionalDisplayAs<u32> + Clone
{
pub const WIDTH: XCoord = SevenSegmentHexDigit::<PIX>::WIDTH * DIGITS as u16;
pub const HEIGHT: XCoord = SevenSegmentHexDigit::<PIX>::HEIGHT;
pub const CHAR_WIDTH: XCoord = SevenSegmentHexDigit::<PIX>::WIDTH;
pub const CHAR_HEIGHT: XCoord = SevenSegmentHexDigit::<PIX>::HEIGHT;
pub fn new(on_colour: PIX, off_colour: PIX, value: VALUE) -> Self {
SevenSegmentDisplay {
value: value,
digit_renderer: RefCell::new(SevenSegmentHexDigit::new(on_colour,off_colour))
}
}
pub fn set_value(&mut self, value: VALUE){
self.value = value
}
}
impl<const DIGITS: usize,const RADIX: u8,PIX,VALUE> Renderable for SevenSegmentDisplay<DIGITS,RADIX,PIX,VALUE>
where
PIX: Clone,
VALUE: OptionalDisplayAs<u32> + Clone
{
type PIXEL = PIX;
fn get_pixel_at<P: RenderPlane>(&self, coord: Point) -> GfxResult<Self::PIXEL> {
let mut renderer = self.digit_renderer.borrow_mut();
if self.value.is_displayed() {
let digit_pos = (coord.0 / Self::CHAR_WIDTH) as usize;
if digit_pos < DIGITS {
let digit_lsf_pos = DIGITS - digit_pos - 1; let value : u32 = self.value.display_value();
let scale = (RADIX as u32).pow(digit_lsf_pos as u32);
let digit = (if scale > 0 { value / scale } else { value }) % RADIX as u32;
renderer.set_digit((digit as u8) & 0x0f);
renderer.get_pixel_at::<P>(Point(coord.0 % Self::CHAR_WIDTH, coord.1))
} else {
Err(GfxError::OutOfBounds)
}
} else {
Err(GfxError::OutOfBounds)
}
}
fn get_dimensions<P: RenderPlane>(&self) -> GfxResult<(XCoord, YCoord)> {
Ok((Self::CHAR_WIDTH * DIGITS as XCoord, Self::CHAR_HEIGHT))
}
fn has_changes<P: RenderPlane>(&self) -> bool {
self.value.is_mutable()
}
fn get_change_area<P: RenderPlane>(&self) -> GfxResult<Option<Area>> {
#[cfg(test)]
println!("SevenSegmentDisplay get_change_area");
if self.value.is_mutable() {
#[cfg(test)]
println!("Volatile value");
let dims = self.get_dimensions::<P>()?;
#[cfg(test)]
println!(" SSD Dims = {:?}", dims);
Ok(Some(Area {
tl: Point(0,0),
w: dims.0,
h: dims.1
}))
} else {
#[cfg(test)]
println!("Non-Volatile value");
Ok(None)
}
}
}
#[cfg(test)]
mod tests {
use core::cell::RefCell;
use avrox_display::gfx::fills::SolidFill;
use avrox_display::gfx::pixels::Monochromatic;
use avrox_display::gfx::primitives::{Overlay, Rectangle};
use avrox_display::gfx::sevenseg::{SevenSegmentDisplay, SevenSegmentHexDigit};
use avrox_display::gfx::test::MonochromeTestRenderer;
#[test]
fn test_7seg_digit() {
let renderer = MonochromeTestRenderer::new();
for d in 0x00u8..=0x0fu8 {
let scene =
Overlay::new(
SevenSegmentHexDigit::new_digit(Monochromatic::WHITE,
Monochromatic::BLACK,
d),
SolidFill::new(Monochromatic::BLACK));
renderer.render_scene(&scene);
}
}
#[test]
fn test_7seg_display() {
let renderer = MonochromeTestRenderer::new();
let mut display = SevenSegmentDisplay::<6,10,_,_>::new(Monochromatic::WHITE, Monochromatic::BLACK, Some(1234u32));
let scene = Overlay::new(
display,
SolidFill::new(Monochromatic::BLACK));
renderer.render_scene(&scene);
let mut display = SevenSegmentDisplay::<6,16,_,_>::new(Monochromatic::WHITE, Monochromatic::BLACK, Some(1234u32));
let scene = Overlay::new(
display,
SolidFill::new(Monochromatic::BLACK));
renderer.render_scene(&scene);
let mut display = SevenSegmentDisplay::<6,2,_,_>::new(Monochromatic::WHITE, Monochromatic::BLACK, Some(1234u32));
let scene = Overlay::new(
display,
SolidFill::new(Monochromatic::BLACK));
renderer.render_scene(&scene);
}
#[test]
fn test_7seg_dynamic_data() {
let renderer = MonochromeTestRenderer::new();
let value = RefCell::new(Some(123u32));
let display = SevenSegmentDisplay::<8,10,_,_>::new(Monochromatic::WHITE, Monochromatic::BLACK, &value);
let scene = Overlay::new(
display,
SolidFill::new(Monochromatic::BLACK));
renderer.render_scene(&scene);
*value.borrow_mut() = Some(80081355);
renderer.render_scene(&scene);
*value.borrow_mut() = None;
renderer.render_scene(&scene);
}
}