monorepo/bike-lights/bike/src/main.rs

188 lines
5.6 KiB
Rust
Raw Normal View History

#![no_main]
#![no_std]
extern crate alloc;
2023-12-14 23:00:45 +00:00
use alloc::boxed::Box;
use az::*;
use core::cell::RefCell;
use cortex_m::delay::Delay;
use embedded_alloc::Heap;
2023-12-14 23:00:45 +00:00
use embedded_hal::{blocking::spi::Write, digital::v2::InputPin};
use fixed::types::I16F16;
use fugit::RateExtU32;
2023-12-14 23:00:45 +00:00
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,
2023-12-14 23:00:45 +00:00
gpio::{FunctionSio, Pin, PinId, PullDown, SioInput},
pac::{CorePeripherals, Peripherals},
spi::{Enabled, Spi, SpiDevice, ValidSpiPinout},
watchdog::Watchdog,
Clock, Sio,
},
Pins,
};
#[global_allocator]
static HEAP: Heap = Heap::empty();
const LIGHT_SCALE: I16F16 = I16F16::lit("256.0");
const GLOBAL_BRIGHTESS: u8 = 1;
2023-12-14 23:00:45 +00:00
struct BikeUI<
D: SpiDevice,
P: ValidSpiPinout<D>,
LeftId: PinId,
RightId: PinId,
PreviousId: PinId,
NextId: PinId,
> {
spi: RefCell<Spi<Enabled, D, P, 8>>,
2023-12-14 23:00:45 +00:00
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>,
}
2023-12-14 23:00:45 +00:00
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),
2023-12-14 23:00:45 +00:00
left_blinker_button,
right_blinker_button,
previous_animation_button,
next_animation_button,
}
}
}
2023-12-14 23:00:45 +00:00
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> {
2023-12-14 23:00:45 +00:00
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];
2023-12-14 23:00:45 +00:00
// 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;
lights[19] = 0xff;
for (idx, rgb) in dashboard_lights.iter().enumerate() {
lights[(idx + 1) * 4 + 0] = 0xe0 + GLOBAL_BRIGHTESS;
lights[(idx + 1) * 4 + 1] = (I16F16::from(rgb.r) * LIGHT_SCALE).saturating_as();
lights[(idx + 1) * 4 + 2] = (I16F16::from(rgb.b) * LIGHT_SCALE).saturating_as();
lights[(idx + 1) * 4 + 3] = (I16F16::from(rgb.g) * LIGHT_SCALE).saturating_as();
}
let mut spi = self.spi.borrow_mut();
spi.write(lights.as_slice());
}
}
#[entry]
fn main() -> ! {
{
use core::mem::MaybeUninit;
const HEAP_SIZE: usize = 8096;
static mut HEAP_MEM: [MaybeUninit<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
unsafe { HEAP.init(HEAP_MEM.as_ptr() as usize, HEAP_SIZE) }
}
let mut pac = Peripherals::take().unwrap();
let core = CorePeripherals::take().unwrap();
let sio = Sio::new(pac.SIO);
let mut watchdog = Watchdog::new(pac.WATCHDOG);
let pins = Pins::new(
pac.IO_BANK0,
pac.PADS_BANK0,
sio.gpio_bank0,
&mut pac.RESETS,
);
let clocks = init_clocks_and_plls(
12_000_000u32,
pac.XOSC,
pac.CLOCKS,
pac.PLL_SYS,
pac.PLL_USB,
&mut pac.RESETS,
&mut watchdog,
)
.ok()
.unwrap();
let mut delay = Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
let mut spi_clk = pins.gpio10.into_function();
let mut spi_sdo = pins.gpio11.into_function();
let spi = Spi::<_, _, _, 8>::new(pac.SPI1, (spi_sdo, spi_clk));
let mut spi = spi.init(
&mut pac.RESETS,
clocks.peripheral_clock.freq(),
1_u32.MHz(),
embedded_hal::spi::MODE_1,
);
2023-12-14 23:00:45 +00:00
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 ui = BikeUI::new(
spi,
left_blinker_button,
right_blinker_button,
previous_animation_button,
next_animation_button,
);
2023-12-14 23:00:45 +00:00
let mut app = App::new(Box::new(ui));
let mut led_pin = pins.led.into_push_pull_output();
2023-12-14 23:00:45 +00:00
let mut time = Instant::default();
let delay_ms = 1000 / (FPS as u32);
loop {
2023-12-14 23:00:45 +00:00
app.tick(time);
delay.delay_ms(delay_ms);
time = time + Instant(delay_ms.into());
}
}