PoC in Rust Card Reader working
This commit is contained in:
parent
c832a15c16
commit
47b5eaa972
@ -6,4 +6,8 @@ edition = "2024"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
env_logger = "0.11.8"
|
env_logger = "0.11.8"
|
||||||
futures-lite = "2.6.0"
|
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"
|
nusb = "0.1.13"
|
||||||
|
serde = {version = "1.0.219", features=["derive"]}
|
||||||
|
serde_json = "1.0.140"
|
||||||
|
tokio = {version = "1.45.0", features=["time"]}
|
||||||
|
@ -1,38 +1,142 @@
|
|||||||
use futures_lite::future::block_on;
|
use iced::time::{self, Duration, Instant, milliseconds};
|
||||||
use nusb::{transfer::{ RequestBuffer, TransferError }, Interface};
|
use std::collections::HashMap;
|
||||||
use std::{thread, time};
|
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;
|
mod card_reader;
|
||||||
static USB_PRODUCT: u16 = 0x0035;
|
mod approx_time;
|
||||||
|
|
||||||
fn get_interface() -> Option<Interface> {
|
|
||||||
let dev = nusb::list_devices().ok()?.find(|dev| dev.vendor_id() == USB_VENDOR && dev.product_id() == USB_PRODUCT)?;
|
static DURATION: u64 = 60;
|
||||||
let device = dev.open().ok()?;
|
|
||||||
device.detach_and_claim_interface(0).ok()
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct RacerTime{
|
||||||
|
#[serde(with = "approx_time")]
|
||||||
|
time: Instant,
|
||||||
|
racer: Racer,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct State{
|
||||||
|
racers: Vec<RacerTime>,
|
||||||
|
db: HashMap<usize, Racer>,
|
||||||
|
#[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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Message> {
|
||||||
|
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<Message> {
|
||||||
|
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();
|
env_logger::init();
|
||||||
let mut interface = get_interface().unwrap();
|
iced::application(State::default, State::update, State::view)
|
||||||
loop {
|
.subscription(State::subscription)
|
||||||
let buf = RequestBuffer::new(8);
|
.theme(State::theme)
|
||||||
let data = block_on(interface.interrupt_in(
|
.run()
|
||||||
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!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user