Skip to content

Commit

Permalink
feat: add optional buzzer noises
Browse files Browse the repository at this point in the history
  • Loading branch information
zabackary committed Nov 2, 2023
1 parent 6f2f390 commit 6d830e0
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 16 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ How do I use this chess clock?
5. If the game needs to be paused at any time, press the START button. To
unpause, press the the P1 or P2 buttons depending on who is going next with
the same schematics as the start screen.
6. When the game is over, press START to go back to the time selection screen.
6. When the game is over (the buzzer will sound one long beep if it's
connected), press START to go back to the time selection screen.

## States

Expand Down Expand Up @@ -101,6 +102,8 @@ Time's up! [P2]
Down button => Arduino d2 & GND (also functions as P1 button)
Start button => Arduino d3 & GND
Up button => Arduino d4 & GND (also functions as P2 button)
3. **Buzzer** (optional)
Buzzer anode => Arduino d6

## Build Instructions

Expand Down
44 changes: 34 additions & 10 deletions src/countdown.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use core::cell::RefCell;

use arduino_hal::{delay_ms, Delay};
use embedded_hal::digital::v2::InputPin;
use embedded_hal::digital::v2::{InputPin, OutputPin};
use hd44780_driver::{bus::DataBus, HD44780};
use ufmt::uwrite;

Expand All @@ -14,6 +14,7 @@ use crate::{
};

const LOOP_DELAY: u16 = 5;
const BUZZER_LENGTH: u16 = 20;

pub enum CountdownResult {
FinishedP1,
Expand All @@ -27,10 +28,11 @@ pub enum Turn {
P2,
}

pub fn countdown<DP: InputPin, UP: InputPin, SP: InputPin, B: DataBus>(
pub fn countdown<DP: InputPin, UP: InputPin, SP: InputPin, BP: OutputPin, B: DataBus>(
down_pin: &mut DP,
up_pin: &mut UP,
start_pin: &mut SP,
buzzer_pin: &mut BP,
delay: &mut Delay,
lcd: &RefCell<HD44780<B>>,
writer: &mut LcdWriter<'_, B>,
Expand All @@ -50,30 +52,52 @@ pub fn countdown<DP: InputPin, UP: InputPin, SP: InputPin, B: DataBus>(
let mut last_turn = turn.clone();

let mut last_change_time = millis();
let mut remaining_buzzer_duration = 0;
Ok(loop {
let time_since_change = millis() - last_change_time;
let new_p1_time = if *turn == Turn::P1 {
convert_time(match p1_ms_at_change.checked_sub(time_since_change) {
let new_p1_ms = if *turn == Turn::P1 {
match p1_ms_at_change.checked_sub(time_since_change) {
Some(x) => x,
None => {
p1_ms_at_change = 0;
break finish_countdown(p1_ms_at_change, p2_ms_at_change, p1_time, p2_time);
}
})
}
} else {
convert_time(p1_ms_at_change)
p1_ms_at_change
};
let new_p2_time = if *turn == Turn::P2 {
convert_time(match p2_ms_at_change.checked_sub(time_since_change) {
let new_p1_time = convert_time(new_p1_ms);
let new_p2_ms = if *turn == Turn::P2 {
match p2_ms_at_change.checked_sub(time_since_change) {
Some(x) => x,
None => {
p2_ms_at_change = 0;
break finish_countdown(p1_ms_at_change, p2_ms_at_change, p1_time, p2_time);
}
})
}
} else {
convert_time(p2_ms_at_change)
p2_ms_at_change
};
let new_p2_time = convert_time(new_p2_ms);

// Update the buzzer
if remaining_buzzer_duration == 1 {
buzzer_pin
.set_low()
.map_err(|_| RuntimeError::PinWriteError)?;
}
if remaining_buzzer_duration > 0 {
remaining_buzzer_duration -= 1;
}
if (new_p1_ms <= 1000 * 10 && new_p1_ms % 1000 == 0)
|| (new_p2_ms <= 1000 * 10 && new_p2_ms % 1000 == 0)
{
buzzer_pin
.set_high()
.map_err(|_| RuntimeError::PinWriteError)?;
remaining_buzzer_duration = BUZZER_LENGTH;
}

// Lazy render
if *turn != last_turn || new_p1_time != last_p1_time || new_p2_time != last_p2_time {
last_turn = turn.clone();
Expand Down
1 change: 1 addition & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
pub enum RuntimeError {
LcdError,
PinReadError,
PinWriteError,
}
18 changes: 16 additions & 2 deletions src/finish.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
use core::cell::RefCell;

use arduino_hal::{delay_ms, Delay};
use embedded_hal::digital::v2::InputPin;
use embedded_hal::digital::v2::{InputPin, OutputPin};
use hd44780_driver::{bus::DataBus, HD44780};
use ufmt::uwrite;

use crate::{countdown::Turn, error::RuntimeError, lcd_writer::LcdWriter};

const LOOP_DELAY: u16 = 5;
const BUZZER_LENGTH: u16 = 120;

pub fn finish<SP: InputPin, B: DataBus>(
pub fn finish<SP: InputPin, BP: OutputPin, B: DataBus>(
loser: &Turn,
delay: &mut Delay,
lcd: &RefCell<HD44780<B>>,
writer: &mut LcdWriter<'_, B>,
start_pin: &mut SP,
buzzer_pin: &mut BP,
) -> Result<(), RuntimeError> {
buzzer_pin
.set_high()
.map_err(|_| RuntimeError::PinWriteError)?;

lcd.borrow_mut()
.set_cursor_pos(0, delay)
.map_err(|_| RuntimeError::LcdError)?;
Expand All @@ -25,7 +31,15 @@ pub fn finish<SP: InputPin, B: DataBus>(
uwrite!(writer, "Time's up! [P2]").map_err(|_| RuntimeError::LcdError)?;
}
let mut start = debouncr::debounce_4(false);
let mut i = 0;
loop {
if i < BUZZER_LENGTH {
i += 1;
} else {
buzzer_pin
.set_low()
.map_err(|_| RuntimeError::PinWriteError)?;
}
if start.update(start_pin.is_low().map_err(|_| RuntimeError::PinReadError)?)
== Some(debouncr::Edge::Rising)
{
Expand Down
12 changes: 9 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use core::cell::RefCell;

use arduino_hal::{delay_ms, Delay};
use countdown::Turn;
use embedded_hal::digital::v2::InputPin;
use embedded_hal::digital::v2::{InputPin, OutputPin};
use error::RuntimeError;
use hd44780_driver::{bus::DataBus, DisplayMode, HD44780};
use lcd_writer::LcdWriter;
Expand Down Expand Up @@ -38,6 +38,8 @@ fn main() -> ! {
let up_btn = pins.d4.into_pull_up_input(); // Also P2 button
let start_btn = pins.d3.into_pull_up_input();

let buzzer = pins.d6.into_output();

let mut lcd_delay = Delay::new();
let lcd_d4 = pins.d9.into_output();
let lcd_d5 = pins.d10.into_output();
Expand Down Expand Up @@ -73,10 +75,12 @@ fn main() -> ! {
// Turn off the init light to show the successful end of initialization
builtin_led.set_low();

// The main runtime is in a wrapper to handle errors properly
if let Err(err) = runtime(
down_btn,
up_btn,
start_btn,
buzzer,
&mut lcd_delay,
&lcd,
&mut writer,
Expand All @@ -96,10 +100,11 @@ fn main() -> ! {
}
}

fn runtime<DP: InputPin, UP: InputPin, SP: InputPin, B: DataBus>(
fn runtime<DP: InputPin, UP: InputPin, SP: InputPin, BP: OutputPin, B: DataBus>(
mut down_btn: DP,
mut up_btn: UP,
mut start_btn: SP,
mut buzzer: BP,
lcd_delay: &mut Delay,
lcd: &RefCell<HD44780<B>>,
writer: &mut LcdWriter<'_, B>,
Expand Down Expand Up @@ -149,6 +154,7 @@ fn runtime<DP: InputPin, UP: InputPin, SP: InputPin, B: DataBus>(
&mut down_btn,
&mut up_btn,
&mut start_btn,
&mut buzzer,
lcd_delay,
&lcd,
writer,
Expand Down Expand Up @@ -176,6 +182,6 @@ fn runtime<DP: InputPin, UP: InputPin, SP: InputPin, B: DataBus>(
pause::PauseResult::Stopped => continue 'main,
}
};
finish::finish(&loser, lcd_delay, &lcd, writer, &mut start_btn)?;
finish::finish(&loser, lcd_delay, &lcd, writer, &mut start_btn, &mut buzzer)?;
}
}

0 comments on commit 6d830e0

Please sign in to comment.