An applicaiton and simulator for a bike lighting system #245

Merged
savanni merged 16 commits from bike-lights into main 2024-08-01 01:32:29 +00:00
2 changed files with 57 additions and 17 deletions
Showing only changes of commit 06aedc34bb - Show all commits

View File

@ -7,31 +7,30 @@ mod types;
pub use types::{DashboardPattern, Pattern, RGB};
pub trait UI {
fn check_event(&self) -> Option<Event>;
fn update_lights(&self, dashboard_lights: DashboardPattern, lights: Pattern);
}
pub trait Animation {
fn tick(&self, frame: Duration) -> (DashboardPattern, Pattern);
fn tick(&self, time: std::time::Instant) -> (DashboardPattern, Pattern);
}
pub struct DefaultAnimation {}
impl Animation for DefaultAnimation {
fn tick(&self, _: Duration) -> (DashboardPattern, Pattern) {
fn tick(&self, time: std::time::Instant) -> (DashboardPattern, Pattern) {
(PRIDE_DASHBOARD, PRIDE)
}
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub enum Event {
Brake,
BrakeRelease,
LeftBlinker,
LeftBlinkerRelease,
NextPattern,
PreviousPattern,
RightBlinker,
RightBlinkerRelease,
}
#[derive(Clone)]
@ -63,8 +62,12 @@ impl App {
}
}
pub fn tick(&mut self, frame: Duration) {
let (dashboard, lights) = self.current_animation.tick(frame);
pub fn tick(&mut self, time: std::time::Instant) {
match self.ui.check_event() {
Some(event) => println!("event received: {:?}", event),
None => (),
};
let (dashboard, lights) = self.current_animation.tick(time);
self.dashboard_lights = dashboard.clone();
self.lights = lights.clone();
self.ui.update_lights(dashboard, lights);

View File

@ -1,8 +1,13 @@
use adw::prelude::*;
use glib::{Object, Sender};
use gtk::subclass::prelude::*;
use lights_core::{App, DashboardPattern, Pattern, RGB, UI};
use std::{cell::RefCell, env, rc::Rc};
use lights_core::{App, DashboardPattern, Event, Pattern, RGB, UI};
use std::{
cell::RefCell,
env,
rc::Rc,
sync::mpsc::{Receiver, TryRecvError},
};
const WIDTH: i32 = 640;
const HEIGHT: i32 = 480;
@ -202,18 +207,26 @@ impl BikeLights {
}
struct GTKUI {
tx: Rc<RefCell<Option<Sender<Update>>>>,
tx: Sender<Update>,
rx: Receiver<Event>,
}
impl UI for GTKUI {
fn check_event(&self) -> Option<Event> {
match self.rx.try_recv() {
Ok(event) => Some(event),
Err(TryRecvError::Empty) => None,
Err(TryRecvError::Disconnected) => None,
}
}
fn update_lights(&self, dashboard_lights: DashboardPattern, lights: Pattern) {
if let Some(tx) = self.tx.borrow().as_ref() {
tx.send(Update {
self.tx
.send(Update {
dashboard: dashboard_lights,
lights,
})
.unwrap();
}
}
}
@ -223,14 +236,17 @@ fn main() {
.build();
adw_app.connect_activate(move |adw_app| {
let (tx, rx) = gtk::glib::MainContext::channel::<Update>(gtk::glib::Priority::DEFAULT);
let (update_tx, update_rx) =
gtk::glib::MainContext::channel::<Update>(gtk::glib::Priority::DEFAULT);
let (event_tx, event_rx) = std::sync::mpsc::channel();
std::thread::spawn(move || {
let mut bike_app = App::new(Box::new(GTKUI {
tx: Rc::new(RefCell::new(Some(tx))),
tx: update_tx,
rx: event_rx,
}));
loop {
bike_app.tick(std::time::Duration::from_millis(0));
bike_app.tick(std::time::Instant::now());
std::thread::sleep(std::time::Duration::from_millis(100));
}
});
@ -254,6 +270,27 @@ fn main() {
let brake_button = gtk::Button::builder().label("Brakes").build();
let right_button = gtk::Button::builder().label("R").build();
left_button.connect_clicked({
let event_tx = event_tx.clone();
move |_| {
let _ = event_tx.send(Event::LeftBlinker);
}
});
brake_button.connect_clicked({
let event_tx = event_tx.clone();
move |_| {
let _ = event_tx.send(Event::Brake);
}
});
right_button.connect_clicked({
let event_tx = event_tx.clone();
move |_| {
let _ = event_tx.send(Event::RightBlinker);
}
});
controls.append(&left_button);
controls.append(&brake_button);
controls.append(&right_button);
@ -273,7 +310,7 @@ fn main() {
layout.append(&dashboard_lights);
layout.append(&bike_lights);
rx.attach(None, {
update_rx.attach(None, {
let dashboard_lights = dashboard_lights.clone();
let bike_lights = bike_lights.clone();
move |Update { dashboard, lights }| {