A src/clock_display.rs => src/clock_display.rs +183 -0
@@ 0,0 1,183 @@
+use stm32f1xx_hal::timer;
+
+use crate::{display::Display, seven_segments::SevenSegments};
+
+const MAIN_DISPLAY_OFFSET: usize = 2;
+const MAIN_DISPLAY_SIZE: usize = 4;
+const SIDE_DISPLAY_1_OFFSET: usize = 0;
+const SIDE_DISPLAY_1_SIZE: usize = 2;
+const SIDE_DISPLAY_2_OFFSET: usize = 6;
+const SIDE_DISPLAY_2_SIZE: usize = 2;
+
+const COLON_DIGIT_1: usize = 3;
+const COLON_DIGIT_2: usize = 4;
+
+pub struct ClockDisplay {
+ display: Display<8>,
+ colon: bool,
+}
+
+#[derive(Copy, Clone)]
+pub enum DisplayPart {
+ Whole,
+ MainDisplay,
+ SideDisplay1,
+ SideDisplay2,
+}
+
+#[derive(Debug)]
+pub enum DisplayError {
+ DoesNotFit,
+}
+
+impl ClockDisplay {
+ pub fn new(display: Display<8>) -> Self {
+ Self {
+ display,
+ colon: false,
+ }
+ }
+
+ pub fn display(&mut self) -> &mut Display<8> {
+ &mut self.display
+ }
+
+ pub fn show_ordinal(
+ &mut self,
+ part: DisplayPart,
+ number: u32,
+ pad: bool,
+ ) -> Result<(), DisplayError> {
+ self.show_number(part, number, pad)?;
+
+ let offset = Self::get_part_offset(part);
+ let size = Self::get_part_size(part);
+ let target_index = offset + size - 1;
+
+ let data = self.display.data()[target_index];
+ self.display.set_digit(target_index, data | 1);
+
+ Ok(())
+ }
+
+ pub fn show_number(
+ &mut self,
+ part: DisplayPart,
+ number: u32,
+ pad: bool,
+ ) -> Result<(), DisplayError> {
+ let offset = Self::get_part_offset(part);
+ let size = Self::get_part_size(part);
+ let mut data = self.display.data();
+
+ let mut number = number;
+ for i in 1..=size {
+ let digit = number % 10;
+ number /= 10;
+
+ data[offset + size - i] = if number != 0 || digit != 0 || pad {
+ SevenSegments::digit_to_segments(digit as u8)
+ } else {
+ 0
+ };
+ }
+
+ if number > 0 {
+ return Err(DisplayError::DoesNotFit);
+ }
+
+ self.display.set_data(data);
+ self.update_colon();
+ Ok(())
+ }
+
+ pub fn show_text(&mut self, part: DisplayPart, text: &str) -> Result<(), DisplayError> {
+ let offset = Self::get_part_offset(part);
+ let size = Self::get_part_size(part);
+
+ if text.len() > size {
+ return Err(DisplayError::DoesNotFit);
+ }
+
+ let mut data = self.display.data();
+ for (i, c) in text.chars().enumerate() {
+ data[offset + i] = SevenSegments::letter_to_segments(c);
+ }
+
+ self.display.set_data(data);
+ self.update_colon();
+ Ok(())
+ }
+
+ pub fn hide(&mut self, part: DisplayPart) {
+ let offset = Self::get_part_offset(part);
+ let size = Self::get_part_size(part);
+
+ let mut data = self.display.data();
+ for current_data in data.iter_mut().skip(offset).take(size) {
+ *current_data = 0;
+ }
+
+ self.display.set_data(data);
+ }
+
+ pub fn brightness(&self, part: DisplayPart) -> &[u16] {
+ let offset = Self::get_part_offset(part);
+ let size = Self::get_part_size(part);
+ &self.display.ref_brightness()[offset..offset + size]
+ }
+
+ pub fn set_brightness(&mut self, part: DisplayPart, brightness: u16) {
+ let offset = Self::get_part_offset(part);
+ let size = Self::get_part_size(part);
+ let mut brightnesses = self.display.brightness();
+
+ for current_brightness in brightnesses.iter_mut().skip(offset).take(size) {
+ *current_brightness = brightness;
+ }
+
+ self.display.set_brightness(brightnesses);
+ }
+
+ pub fn set_colon(&mut self, colon: bool) {
+ self.colon = colon;
+ self.update_colon();
+ }
+
+ pub fn update(&mut self) -> nb::Result<(), timer::Error> {
+ self.display.update()
+ }
+
+ fn update_colon(&mut self) {
+ let data = self.display.data();
+ if self.colon {
+ self.display
+ .set_digit(COLON_DIGIT_1, data[COLON_DIGIT_1] | 0b1);
+ self.display
+ .set_digit(COLON_DIGIT_2, data[COLON_DIGIT_2] | 0b1);
+ } else {
+ self.display
+ .set_digit(COLON_DIGIT_1, data[COLON_DIGIT_1] & 0xFE);
+ self.display
+ .set_digit(COLON_DIGIT_2, data[COLON_DIGIT_2] & 0xFE);
+ }
+ }
+
+ fn get_part_size(part: DisplayPart) -> usize {
+ match part {
+ DisplayPart::Whole => SIDE_DISPLAY_1_SIZE + MAIN_DISPLAY_SIZE + SIDE_DISPLAY_2_SIZE,
+ DisplayPart::MainDisplay => MAIN_DISPLAY_SIZE,
+ DisplayPart::SideDisplay1 => SIDE_DISPLAY_1_SIZE,
+ DisplayPart::SideDisplay2 => SIDE_DISPLAY_2_SIZE,
+ }
+ }
+
+ fn get_part_offset(part: DisplayPart) -> usize {
+ match part {
+ DisplayPart::Whole => 0,
+ DisplayPart::MainDisplay => MAIN_DISPLAY_OFFSET,
+ DisplayPart::SideDisplay1 => SIDE_DISPLAY_1_OFFSET,
+ DisplayPart::SideDisplay2 => SIDE_DISPLAY_2_OFFSET,
+ }
+ }
+}
A src/clock_display_viewer.rs => src/clock_display_viewer.rs +57 -0
@@ 0,0 1,57 @@
+use crate::{
+ clock_display::ClockDisplay,
+ clock_state::ClockState,
+ display_view::{
+ clock_display_view::ClockDisplayView, date_display_view::DateDisplayView, DisplayView,
+ DisplayViews,
+ },
+};
+use alloc::{boxed::Box, vec, vec::Vec};
+use stm32f1xx_hal::timer;
+
+pub struct ClockDisplayViewer {
+ clock_display: ClockDisplay,
+ views: Vec<Box<dyn DisplayView + Send>>,
+ current_view: Option<DisplayViews>,
+}
+
+impl ClockDisplayViewer {
+ pub fn new(clock_display: ClockDisplay) -> Self {
+ Self {
+ clock_display,
+ views: vec![
+ Box::new(ClockDisplayView::new()),
+ Box::new(ClockDisplayView::with_seconds()),
+ Box::new(ClockDisplayView::with_date()),
+ Box::new(DateDisplayView::new()),
+ ],
+ current_view: None,
+ }
+ }
+
+ pub fn clock_display<'a>(&'a mut self) -> &'a mut ClockDisplay {
+ &mut self.clock_display
+ }
+
+ pub fn current_view(&self) -> Option<DisplayViews> {
+ self.current_view
+ }
+
+ pub fn set_current_view(&mut self, view: DisplayViews) {
+ self.current_view = Some(view);
+ }
+
+ pub fn clear_current_view(&mut self) {
+ self.current_view = None;
+ }
+
+ pub fn update(&mut self, state: &ClockState) -> nb::Result<(), timer::Error> {
+ self.clock_display.update()?;
+
+ if let Some(view) = self.current_view {
+ let view = &mut self.views[view as usize];
+ view.update_display(state, &mut self.clock_display).unwrap(); // TODO: get rid of the unwrap
+ }
+ Ok(())
+ }
+}
A src/display.rs => src/display.rs +134 -0
@@ 0,0 1,134 @@
+use core::convert::Infallible;
+
+use alloc::boxed::Box;
+use embedded_hal::PwmPin;
+use fugit::MicrosDurationU32;
+use stm32f1xx_hal::timer;
+
+use crate::count_down::CountDown;
+
+type OutputPin = dyn embedded_hal::digital::v2::OutputPin<Error = Infallible> + Send;
+
+// How long to turn on a digit to show a number
+// (every digit will be turned on for this time, so this number shouldn't bee to large - so it's not flickering,
+// and it shouldn't be too small to allow the transistor and LED operate)
+const DIGIT_ON_TIME: MicrosDurationU32 = MicrosDurationU32::micros(1490);
+
+// How long to turn off the digits when moving from one digit to another
+// This is important to close off the previous transistor before next digit
+// is lit up.
+const DIGITS_OFF_TIME: MicrosDurationU32 = MicrosDurationU32::micros(500);
+
+struct DisplayState<const DIGITS: usize> {
+ digit_index: usize,
+ next_show: bool, // if 1, next timer step is to show, if 0, next timer step is to hide
+}
+
+impl<const DIGITS: usize> DisplayState<DIGITS> {
+ fn empty() -> Self {
+ Self {
+ digit_index: 0,
+ next_show: true,
+ }
+ }
+
+ fn step(&mut self) {
+ self.next_show = !self.next_show;
+ if self.next_show {
+ self.digit_index = (self.digit_index + 1) % DIGITS;
+ }
+ }
+}
+
+pub struct Display<const DIGITS: usize> {
+ segments: [Box<OutputPin>; 8],
+ digits: [Box<dyn PwmPin<Duty = u16> + Send>; DIGITS],
+ timer: Box<dyn CountDown<Time = MicrosDurationU32> + Send>,
+ data: [u8; DIGITS],
+ brightness: [u16; DIGITS],
+
+ state: DisplayState<DIGITS>,
+}
+
+impl<const DIGITS: usize> Display<DIGITS> {
+ pub fn new(
+ segments: [Box<OutputPin>; 8],
+ mut digits: [Box<dyn PwmPin<Duty = u16> + Send>; DIGITS],
+ timer: Box<dyn CountDown<Time = MicrosDurationU32> + Send>,
+ ) -> Self {
+ for digit in digits.iter_mut() {
+ digit.enable();
+ }
+
+ Self {
+ segments,
+ digits,
+ timer,
+ data: [0; DIGITS],
+ brightness: [0xFFFF; DIGITS],
+ state: DisplayState::<DIGITS>::empty(),
+ }
+ }
+
+ pub fn data(&self) -> [u8; DIGITS] {
+ self.data
+ }
+
+ pub fn set_data(&mut self, digits: [u8; DIGITS]) {
+ self.data = digits;
+ }
+
+ pub fn set_digit(&mut self, digit: usize, set: u8) {
+ self.data[digit] = set;
+ }
+
+ pub fn brightness(&self) -> [u16; DIGITS] {
+ self.brightness
+ }
+
+ pub fn ref_brightness(&self) -> &[u16] {
+ &self.brightness
+ }
+
+ pub fn set_brightness(&mut self, brightness: [u16; DIGITS]) {
+ self.brightness = brightness;
+ }
+
+ pub fn set_digit_brightness(&mut self, digit: usize, brightness: u16) {
+ self.brightness[digit] = brightness;
+ }
+
+ pub fn update(&mut self) -> nb::Result<(), timer::Error> {
+ self.timer.wait()?;
+ let now_show = self.state.next_show;
+ let digit_index = self.state.digit_index;
+
+ // turn every digit off
+ for digit in self.digits.iter_mut() {
+ digit.set_duty(0xFFFF);
+ }
+
+ if now_show {
+ let digit = &mut self.digits[digit_index];
+ let data = self.data[digit_index];
+ let brightness = self.brightness[digit_index];
+
+ for (i, segment) in self.segments.iter_mut().enumerate() {
+ segment
+ .set_state((!(data & (1 << (7 - i)) > 0)).into())
+ .unwrap();
+ }
+
+ digit.set_duty(0xFFFF - brightness);
+ }
+
+ self.timer.start(if now_show {
+ DIGIT_ON_TIME
+ } else {
+ DIGITS_OFF_TIME
+ });
+ self.state.step();
+
+ Ok(())
+ }
+}
A src/display_view.rs => src/display_view.rs +54 -0
@@ 0,0 1,54 @@
+use crate::{
+ clock_display::{ClockDisplay, DisplayError},
+ clock_state::ClockState,
+};
+
+pub mod clock_display_view;
+pub mod date_display_view;
+
+#[derive(Copy, Clone, PartialEq, Eq)]
+#[repr(usize)]
+pub enum DisplayViews {
+ ClockView = 0,
+ ClockSecondsView = 1,
+ ClockDateView = 2,
+ DateView = 3,
+}
+
+impl DisplayViews {
+ pub fn count() -> usize {
+ 4
+ }
+}
+
+impl From<usize> for DisplayViews {
+ fn from(value: usize) -> Self {
+ match value {
+ 0 => Self::ClockView,
+ 1 => Self::ClockSecondsView,
+ 2 => Self::ClockDateView,
+ 3 => Self::DateView,
+ _ => panic!(),
+ }
+ }
+}
+
+#[derive(Debug)]
+pub enum DisplayViewError {
+ Unknown,
+ DisplayError(DisplayError),
+}
+
+impl From<DisplayError> for DisplayViewError {
+ fn from(value: DisplayError) -> Self {
+ Self::DisplayError(value)
+ }
+}
+
+pub trait DisplayView {
+ fn update_display(
+ &mut self,
+ state: &ClockState,
+ display: &mut ClockDisplay,
+ ) -> Result<(), DisplayViewError>;
+}
A src/display_view/clock_display_view.rs => src/display_view/clock_display_view.rs +69 -0
@@ 0,0 1,69 @@
+use crate::{
+ clock_display::{ClockDisplay, DisplayPart},
+ clock_state::ClockState,
+};
+
+use super::{DisplayView, DisplayViewError};
+
+pub struct ClockDisplayView {
+ show_seconds: bool,
+ show_date: bool,
+}
+
+impl Default for ClockDisplayView {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl ClockDisplayView {
+ pub fn new() -> Self {
+ Self {
+ show_date: false,
+ show_seconds: false,
+ }
+ }
+
+ pub fn with_seconds() -> Self {
+ Self {
+ show_date: false,
+ show_seconds: true,
+ }
+ }
+
+ pub fn with_date() -> Self {
+ Self {
+ show_date: true,
+ show_seconds: false,
+ }
+ }
+}
+
+impl DisplayView for ClockDisplayView {
+ fn update_display(
+ &mut self,
+ state: &ClockState,
+ display: &mut ClockDisplay,
+ ) -> Result<(), DisplayViewError> {
+ let calendar = state.calendar();
+
+ if self.show_seconds {
+ display.hide(DisplayPart::SideDisplay1);
+ display.show_number(DisplayPart::SideDisplay2, calendar.seconds() as u32, true)?;
+ } else if self.show_date {
+ display.show_ordinal(DisplayPart::SideDisplay1, calendar.day() as u32, true)?;
+ display.show_ordinal(DisplayPart::SideDisplay2, calendar.month() as u32, true)?;
+ } else {
+ display.hide(DisplayPart::SideDisplay1);
+ display.hide(DisplayPart::SideDisplay2);
+ }
+
+ display.set_colon(calendar.seconds() % 2 == 0);
+ display.show_number(
+ DisplayPart::MainDisplay,
+ (calendar.hours() as u32) * 100 + (calendar.minutes() as u32),
+ true,
+ )?;
+ Ok(())
+ }
+}
A src/display_view/date_display_view.rs => src/display_view/date_display_view.rs +33 -0
@@ 0,0 1,33 @@
+use crate::clock_display::DisplayPart;
+
+use super::DisplayView;
+
+pub struct DateDisplayView;
+
+impl DateDisplayView {
+ pub fn new() -> Self {
+ Self
+ }
+}
+
+impl Default for DateDisplayView {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl DisplayView for DateDisplayView {
+ fn update_display(
+ &mut self,
+ state: &crate::clock_state::ClockState,
+ display: &mut crate::clock_display::ClockDisplay,
+ ) -> Result<(), super::DisplayViewError> {
+ let calendar = state.calendar();
+
+ display.show_ordinal(DisplayPart::SideDisplay1, calendar.day() as u32, true)?;
+ display.show_ordinal(DisplayPart::SideDisplay2, calendar.month() as u32, true)?;
+ display.show_number(DisplayPart::MainDisplay, calendar.year() as u32, false)?;
+ display.set_colon(false);
+ Ok(())
+ }
+}
A src/number_digits.rs => src/number_digits.rs +33 -0
@@ 0,0 1,33 @@
+pub trait NumberDigits {
+ fn get_digit(self, digit_index: u8) -> u8;
+}
+
+impl NumberDigits for u8 {
+ fn get_digit(self, digit_index: u8) -> u8 {
+ let mut number = self;
+ for _ in 0..digit_index {
+ number /= 10;
+ }
+ (number % 10) as u8
+ }
+}
+
+impl NumberDigits for u16 {
+ fn get_digit(self, digit_index: u8) -> u8 {
+ let mut number = self;
+ for _ in 0..digit_index {
+ number /= 10;
+ }
+ (number % 10) as u8
+ }
+}
+
+impl NumberDigits for u32 {
+ fn get_digit(self, digit_index: u8) -> u8 {
+ let mut number = self;
+ for _ in 0..digit_index {
+ number /= 10;
+ }
+ (number % 10) as u8
+ }
+}
A src/seven_segments.rs => src/seven_segments.rs +28 -0
@@ 0,0 1,28 @@
+pub struct SevenSegments;
+
+impl SevenSegments {
+ pub fn digit_to_segments(digit: u8) -> u8 {
+ (match digit {
+ 0 => 0b1111110,
+ 1 => 0b0110000,
+ 2 => 0b1101101,
+ 3 => 0b1111001,
+ 4 => 0b0110011,
+ 5 => 0b1011011,
+ 6 => 0b1011111,
+ 7 => 0b1110000,
+ 8 => 0b1111111,
+ 9 => 0b1111011,
+ _ => 0b0000001,
+ }) << 1
+ }
+
+ pub fn letter_to_segments(letter: char) -> u8 {
+ (match letter {
+ 'E' => 0b1001111,
+ 'r' => 0b0000101,
+ 'o' => 0b0011101,
+ _ => 0b0000001,
+ }) << 1
+ }
+}