use num::*;
use std::time::{Duration,Instant};
use esp_idf_hal::i2c::*;
use esp_idf_hal::ledc::*;
use esp_idf_hal::gpio::*;
use esp_idf_hal::prelude::*;
use esp_idf_sys::ledc_set_freq;
use esp_idf_hal::delay::FreeRtos;
use ssd1306::mode::BufferedGraphicsMode;
use esp_idf_hal::peripherals::Peripherals;
use esp_idf_hal::ledc::config::TimerConfig;
use esp_idf_sys::ledc_mode_t_LEDC_LOW_SPEED_MODE;
use ssd1306::{prelude::*, I2CDisplayInterface, Ssd1306};
use embedded_graphics::{
prelude::*,
text::{Baseline, Text},
pixelcolor::BinaryColor,
mono_font::{ascii::FONT_6X10, MonoTextStyleBuilder},
primitives::{Circle, PrimitiveStyleBuilder, Rectangle}
};
const SCORE_LIMIT: u32 = 5;
const WIN_NOTES: [u32; 12] = [
880, 988, 523, 988, 523, 587,
523, 587, 659, 587, 659, 659
];
const LOSE_NOTES: [u32; 12] = [
500, 450, 400, 350, 300, 250,
500, 450, 400, 350, 300, 250
];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Player {
One,
Two,
}
struct ChessClock {
player1_time: Duration,
player2_time: Duration,
active_player: Player,
start_time: Instant,
winner: Option<Player>,
}
impl ChessClock {
fn new(initial_time: Duration) -> Self {
ChessClock {
player1_time: initial_time,
player2_time: initial_time,
active_player: Player::One,
start_time: Instant::now(),
winner: None,
}
}
fn switch_and_start_player1(&mut self) {
self.update_active_player_time();
self.active_player = Player::Two;
self.start_time = Instant::now();
}
fn switch_and_start_player2(&mut self) {
self.update_active_player_time();
self.active_player = Player::One;
self.start_time = Instant::now();
}
fn reset(&mut self, initial_time: Duration) {
self.player1_time = initial_time;
self.player2_time = initial_time;
self.active_player = Player::One;
self.start_time = Instant::now();
self.winner = None;
}
fn get_winner(&self) -> Option<Player> {
self.winner
}
fn update_active_player_time(&mut self) {
// Check if a winner has been determined
if self.winner.is_none() {
match self.active_player {
Player::One => {
self.player1_time -= self.start_time.elapsed();
if self.player1_time <= Duration::new(0, 0) {
self.winner = Some(Player::One);
}
}
Player::Two => {
self.player2_time -= self.start_time.elapsed();
if self.player2_time <= Duration::new(0, 0) {
self.winner = Some(Player::Two);
}
}
}
}
self.start_time = Instant::now();
}
}
fn main() -> anyhow::Result<()> {
let mut mcu_dir = 0;
let mut mcu_score = 0;
let mut player_score = 0;
let mut ball_pos: [i32; 2] = [60, 28];
let mut mcu_pos: [i32; 2] = [12, 24];
let mut player_pos: [i32; 2] = [110, 24];
let mut mcu_impact = Instant::now();
let mut player_impact = Instant::now();
let peripherals = Peripherals::take().unwrap();
let up = PinDriver::input(peripherals.pins.gpio2)?;
let down = PinDriver::input(peripherals.pins.gpio3)?;
let i2c0 = peripherals.i2c0;
let sda = peripherals.pins.gpio9;
let scl = peripherals.pins.gpio8;
let disp = DisplaySize128x64;
let rot = DisplayRotation::Rotate0;
let config = I2cConfig::new().baudrate(100.kHz().into());
let i2c = I2cDriver::new(i2c0, sda, scl, &config)?;
let interface = I2CDisplayInterface::new(i2c);
let mut display = Ssd1306::new(interface, disp, rot)
.into_buffered_graphics_mode();
let on = PrimitiveStyleBuilder::new()
.stroke_width(1)
.stroke_color(BinaryColor::On)
.build();
display.init().unwrap();
Rectangle::new(Point::new(0, 0), Size::new(127, 63))
.into_styled(on)
.draw(&mut display)
.unwrap();
let initial_time = Duration::from_secs(15); // 5 minutes initial time per player
let mut chess_clock = ChessClock::new(initial_time);
loop {
//clear_field(&mut display, player_pos, mcu_pos, ball_pos);
chess_clock.update_active_player_time();
show_time(&mut display, &chess_clock);
let u = up.is_low();
let d = down.is_low();
match (u, d) {
(true, false) => {
chess_clock.switch_and_start_player1();
}
(false, true) => {
chess_clock.switch_and_start_player2();
}
_ => (),
}
display.flush().unwrap();
}
}
fn clear_field(
display: &mut Ssd1306<
I2CInterface<esp_idf_hal::i2c::I2cDriver<'_>>,
DisplaySize128x64,
BufferedGraphicsMode<DisplaySize128x64>
>,
player_pos: [i32; 2],
mcu_pos: [i32; 2],
ball_pos: [i32; 2]
) {
let off = PrimitiveStyleBuilder::new()
.stroke_width(2)
.stroke_color(BinaryColor::Off)
.build();
Rectangle::new(Point::new(player_pos[0], player_pos[1]), Size::new(4, 16))
.into_styled(off)
.draw(display)
.unwrap();
Rectangle::new(Point::new(mcu_pos[0], mcu_pos[1]), Size::new(4, 16))
.into_styled(off)
.draw(display)
.unwrap();
Circle::new(Point::new(ball_pos[0], ball_pos[1]), 4)
.into_styled(off)
.draw(display)
.unwrap();
}
fn show_time(
display: &mut Ssd1306<
I2CInterface<esp_idf_hal::i2c::I2cDriver<'_>>,
DisplaySize128x64,
BufferedGraphicsMode<DisplaySize128x64>,
>,
chess_clock: &ChessClock,
) {
let on = PrimitiveStyleBuilder::new()
.stroke_width(1)
.stroke_color(BinaryColor::On)
.build();
let text_style = MonoTextStyleBuilder::new()
.font(&FONT_6X10)
.text_color(BinaryColor::On)
.build();
let score = if let Some(winner) = chess_clock.get_winner() {
match winner {
Player::One => format!("Player One wins!"),
Player::Two => format!("Player Two wins!"),
}
} else {
format!("{:?} | {:?}", chess_clock.player1_time, chess_clock.player2_time)
};
Text::with_baseline(&score, Point::new(10, 24), text_style, Baseline::Top)
.draw(display)
.unwrap();
display.flush().unwrap();
//FreeRtos::delay_ms(1000);
display.clear();
Rectangle::new(Point::new(0, 0), Size::new(127, 63))
.into_styled(on)
.draw(display)
.unwrap();
}