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 97 additions and 24 deletions
Showing only changes of commit ef5415303b - Show all commits

View File

@ -3,21 +3,21 @@
extern crate alloc;
use alloc::boxed::Box;
use az::*;
use core::cell::RefCell;
use cortex_m::delay::Delay;
use embedded_alloc::Heap;
use embedded_hal::{blocking::spi::Write, digital::v2::OutputPin};
use embedded_hal::{blocking::spi::Write, digital::v2::InputPin};
use fixed::types::I16F16;
use fugit::RateExtU32;
use lights_core::{
BodyPattern, DashboardPattern, Event, TRANS_PRIDE_BODY, TRANS_PRIDE_DASHBOARD, UI,
};
use lights_core::{App, BodyPattern, DashboardPattern, Event, Instant, State, FPS, UI};
use panic_halt as _;
use rp_pico::{
entry,
hal::{
clocks::init_clocks_and_plls,
gpio::{FunctionSio, Pin, PinId, PullDown, SioInput},
pac::{CorePeripherals, Peripherals},
spi::{Enabled, Spi, SpiDevice, ValidSpiPinout},
watchdog::Watchdog,
@ -32,25 +32,74 @@ static HEAP: Heap = Heap::empty();
const LIGHT_SCALE: I16F16 = I16F16::lit("256.0");
const GLOBAL_BRIGHTESS: u8 = 1;
struct BikeUI<D: SpiDevice, P: ValidSpiPinout<D>> {
struct BikeUI<
D: SpiDevice,
P: ValidSpiPinout<D>,
LeftId: PinId,
RightId: PinId,
PreviousId: PinId,
NextId: PinId,
> {
spi: RefCell<Spi<Enabled, D, P, 8>>,
left_blinker_button: Pin<LeftId, FunctionSio<SioInput>, PullDown>,
right_blinker_button: Pin<RightId, FunctionSio<SioInput>, PullDown>,
previous_animation_button: Pin<PreviousId, FunctionSio<SioInput>, PullDown>,
next_animation_button: Pin<NextId, FunctionSio<SioInput>, PullDown>,
}
impl<D: SpiDevice, P: ValidSpiPinout<D>> BikeUI<D, P> {
fn new(spi: Spi<Enabled, D, P, 8>) -> Self {
impl<
D: SpiDevice,
P: ValidSpiPinout<D>,
LeftId: PinId,
RightId: PinId,
PreviousId: PinId,
NextId: PinId,
> BikeUI<D, P, LeftId, RightId, PreviousId, NextId>
{
fn new(
spi: Spi<Enabled, D, P, 8>,
left_blinker_button: Pin<LeftId, FunctionSio<SioInput>, PullDown>,
right_blinker_button: Pin<RightId, FunctionSio<SioInput>, PullDown>,
previous_animation_button: Pin<PreviousId, FunctionSio<SioInput>, PullDown>,
next_animation_button: Pin<NextId, FunctionSio<SioInput>, PullDown>,
) -> Self {
Self {
spi: RefCell::new(spi),
left_blinker_button,
right_blinker_button,
previous_animation_button,
next_animation_button,
}
}
}
impl<D: SpiDevice, P: ValidSpiPinout<D>> UI for BikeUI<D, P> {
impl<
D: SpiDevice,
P: ValidSpiPinout<D>,
LeftId: PinId,
RightId: PinId,
PreviousId: PinId,
NextId: PinId,
> UI for BikeUI<D, P, LeftId, RightId, PreviousId, NextId>
{
fn check_event(&self) -> Option<Event> {
None
if self.left_blinker_button.is_high().unwrap_or(false) {
Some(Event::LeftBlinker)
} else if self.right_blinker_button.is_high().unwrap_or(false) {
Some(Event::RightBlinker)
} else if self.previous_animation_button.is_high().unwrap_or(false) {
Some(Event::PreviousPattern)
} else if self.next_animation_button.is_high().unwrap_or(false) {
Some(Event::NextPattern)
} else {
None
}
}
fn update_lights(&self, dashboard_lights: DashboardPattern, body_lights: BodyPattern) {
let mut lights: [u8; 20] = [0; 20];
// Check https://www.pololu.com/product/3089 for the end frame calculations. It is not what
// I thought.
lights[16] = 0xff;
lights[17] = 0xff;
lights[18] = 0xff;
@ -110,25 +159,29 @@ fn main() -> ! {
embedded_hal::spi::MODE_1,
);
let ui = BikeUI::new(spi);
let left_blinker_button = pins.gpio18.into_pull_down_input();
let right_blinker_button = pins.gpio19.into_function();
let previous_animation_button = pins.gpio20.into_function();
let next_animation_button = pins.gpio21.into_pull_down_input();
// let app = App::new(Box::new(ui));
// app.tick(TRANS_PRIDE_DASHBOARD, TRANS_PRIDE_BODY);
ui.update_lights(TRANS_PRIDE_DASHBOARD, TRANS_PRIDE_BODY);
let ui = BikeUI::new(
spi,
left_blinker_button,
right_blinker_button,
previous_animation_button,
next_animation_button,
);
/*
spi.write(&[
0, 0, 0, 0, 0xe1, 0x80, 0x00, 0x00, 0xe1, 0x00, 0x80, 0x00, 0xe1, 0x00, 0x00, 0x80, 0xff,
0xff, 0xff, 0xff,
]);
*/
let mut app = App::new(Box::new(ui));
let mut led_pin = pins.led.into_push_pull_output();
let mut time = Instant::default();
let delay_ms = 1000 / (FPS as u32);
loop {
led_pin.set_high().unwrap();
delay.delay_ms(500);
led_pin.set_low().unwrap();
delay.delay_ms(500);
app.tick(time);
delay.delay_ms(delay_ms);
time = time + Instant(delay_ms.into());
}
}

View File

@ -3,7 +3,13 @@
extern crate alloc;
use alloc::boxed::Box;
use az::*;
use core::{clone::Clone, cmp::PartialEq, ops::Sub, option::Option};
use core::{
clone::Clone,
cmp::PartialEq,
default::Default,
ops::{Add, Sub},
option::Option,
};
use fixed::types::{I48F16, I8F8, U128F0, U16F0};
mod patterns;
@ -30,6 +36,20 @@ fn linear_ease(value: I8F8, frames: U16F0, slope: I8F8) -> I8F8 {
#[derive(Clone, Copy)]
pub struct Instant(pub U128F0);
impl Default for Instant {
fn default() -> Self {
Self(U128F0::from(0 as u8))
}
}
impl Add for Instant {
type Output = Self;
fn add(self, r: Self) -> Self::Output {
Self(self.0 + r.0)
}
}
impl Sub for Instant {
type Output = Self;