diff --git a/POC_in_rust/Cargo.toml b/POC_in_rust/Cargo.toml index f2a6aa8..c5a5661 100644 --- a/POC_in_rust/Cargo.toml +++ b/POC_in_rust/Cargo.toml @@ -6,4 +6,8 @@ edition = "2024" [dependencies] env_logger = "0.11.8" futures-lite = "2.6.0" +iced = {"git"= "https://github.com/iced-rs/iced.git", "features"=["tokio", "auto-detect-theme", "fira-sans", "tiny-skia", "wgpu", "sipper"]} nusb = "0.1.13" +serde = {version = "1.0.219", features=["derive"]} +serde_json = "1.0.140" +tokio = {version = "1.45.0", features=["time"]} diff --git a/POC_in_rust/src/main.rs b/POC_in_rust/src/main.rs index d5c39a2..2277c1d 100644 --- a/POC_in_rust/src/main.rs +++ b/POC_in_rust/src/main.rs @@ -1,38 +1,142 @@ -use futures_lite::future::block_on; -use nusb::{transfer::{ RequestBuffer, TransferError }, Interface}; -use std::{thread, time}; +use iced::time::{self, Duration, Instant, milliseconds}; +use std::collections::HashMap; +use std::fmt::{Formatter, Error}; +use serde::{Deserialize, Serialize}; +use iced::widget::{center, column, row, text}; +use iced::{Element, Subscription, Theme, Center}; -static USB_VENDOR: u16 = 0xffff; -static USB_PRODUCT: u16 = 0x0035; +mod card_reader; +mod approx_time; -fn get_interface() -> Option { - let dev = nusb::list_devices().ok()?.find(|dev| dev.vendor_id() == USB_VENDOR && dev.product_id() == USB_PRODUCT)?; - let device = dev.open().ok()?; - device.detach_and_claim_interface(0).ok() + +static DURATION: u64 = 60; + +#[derive(Serialize, Deserialize)] +struct RacerTime{ + #[serde(with = "approx_time")] + time: Instant, + racer: Racer, } -fn main() { - env_logger::init(); - let mut interface = get_interface().unwrap(); - loop { - let buf = RequestBuffer::new(8); - let data = block_on(interface.interrupt_in( - 0x81, buf - )); - match data.status { - Err(TransferError::Disconnected) => { - interface = (||{loop{ - if let Some(intfc) = get_interface(){ - return intfc; - } - let ten_milis = time::Duration::from_millis(10); - thread::sleep(ten_milis); - }})() - } - Ok(()) => { - println!("{:?}", data.data); - } - _ => todo!() +#[derive(Serialize, Deserialize)] +struct State{ + racers: Vec, + db: HashMap, + #[serde(with = "approx_time")] + time: Instant, +} + +impl Default for State { + fn default() -> Self { + Self { + racers: vec![RacerTime{time: Instant::now(), racer: Racer{starting_number:11,racer_id: 0, card_id: 0}}], + db: Default::default(), + time: Instant::now(), } } -} \ No newline at end of file +} + +impl State{ + fn update(&mut self, message: Message){ + match message { + Message::RacerAdded(racer) => { + self.db.insert(racer.card_id, racer); + }, + Message::Tick(time) => { + if let Some(racer_time) = self.racers.iter().next() { + if time - racer_time.time > Duration::new(DURATION + 10, 0){ + self.racers.remove(0); + } + } + self.time = time; + }, + Message::CardReader(card_reader::Event::ReadedCardId(card_id)) => { + if let Some(racer) = self.db.get(&card_id){ + self.racers.push(RacerTime{time: Instant::now(), racer: racer.clone()}) + }else{ + println!("Racer {} not found in db!", card_id) + } + }, + Message::CardReader(card_reader::Event::Connected) => { + println!("Card Reader Connected!") + } + Message::CardReader(card_reader::Event::Disconnected) => { + println!("Card Reader Disconnected!") + } + } + } + fn view(&self) -> Element { + let mut content = column![ + row![ + text("Číslo závodníka").width(120).align_x(Center).align_y(Center), text("čas").size(20).width(120).align_x(Center).align_y(Center) + ], + ]; + for racer_time in &self.racers { + const MINUTE: u64 = 60; + + + let time = self.time - racer_time.time; + let duration = Duration::new(DURATION, 0); + let (duration, negative) = if duration < time { + (time - duration, true) + } else { + (duration - time, false) + }; + + + let seconds = duration.as_secs(); + + let duration = text!( + "{}{:0>2}:{:0>2}.{:0>2}", + if negative {"-"} else {""}, + seconds / MINUTE, + seconds % MINUTE, + duration.subsec_millis() / 10, + ).size(20).width(120).align_x(Center).align_y(Center); + content = content.push( + row![ + text(racer_time.racer.starting_number.to_string()).size(20).width(120).align_x(Center).align_y(Center), duration + ] + ); + } + center(content).into() + } + fn subscription(&self) -> Subscription { + Subscription::batch(vec![ + time::every(milliseconds(10)).map(Message::Tick), + Subscription::run(card_reader::connect).map(Message::CardReader) + ]) + } + fn theme(&self) -> Theme { + Theme::Dark + } +} + +#[derive(Serialize, Deserialize, Clone)] +struct Racer{ + racer_id: usize, + starting_number: usize, + card_id: usize, +} + +enum Message{ + CardReader(card_reader::Event), + RacerAdded(Racer), + Tick(Instant), +} + +impl std::fmt::Debug for Message { + // Required method + fn fmt(&self, _f: &mut Formatter<'_>) -> Result<(), Error>{ + todo!() + } +} + + +pub fn main() -> iced::Result { + env_logger::init(); + iced::application(State::default, State::update, State::view) + .subscription(State::subscription) + .theme(State::theme) + .run() +}