events: finally drop the whole bus garage idea
This commit is contained in:
@@ -18,9 +18,14 @@ use esp_hal::{
|
|||||||
clock::CpuClock, system::{AppCoreGuard, CpuControl, Stack}, timer::{systimer::SystemTimer, timg::{TimerGroup, Wdt}}
|
clock::CpuClock, system::{AppCoreGuard, CpuControl, Stack}, timer::{systimer::SystemTimer, timg::{TimerGroup, Wdt}}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use embassy_sync::{
|
||||||
|
pubsub::PubSubChannel,
|
||||||
|
blocking_mutex::raw::NoopRawMutex
|
||||||
|
};
|
||||||
|
|
||||||
use log::*;
|
use log::*;
|
||||||
use renderbug_embassy::{graphics::display::DisplayControls, logging::RenderbugLogger, tasks::{oled::{OledUI, OledUiSurfacePool, oled_ui}, safetyui::{SafetyUi, safety_ui_main}, ui::UiSurfacePool}};
|
use renderbug_embassy::{events::Prediction, graphics::display::DisplayControls, logging::RenderbugLogger, tasks::{oled::{OledUI, OledUiSurfacePool, oled_ui}, safetyui::{SafetyUi, safety_ui_main}, ui::UiSurfacePool}};
|
||||||
use renderbug_embassy::events::{BusGarage, Measurement};
|
use renderbug_embassy::events::Measurement;
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use esp_backtrace as _;
|
use esp_backtrace as _;
|
||||||
use esp_rtos::embassy::{Executor, InterruptExecutor};
|
use esp_rtos::embassy::{Executor, InterruptExecutor};
|
||||||
@@ -31,7 +36,7 @@ use renderbug_embassy::tasks::{
|
|||||||
ui::{Ui, ui_main}
|
ui::{Ui, ui_main}
|
||||||
};
|
};
|
||||||
|
|
||||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, pubsub::DynSubscriber};
|
||||||
use embassy_sync::channel::Channel;
|
use embassy_sync::channel::Channel;
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
@@ -42,8 +47,6 @@ esp_bootloader_esp_idf::esp_app_desc!();
|
|||||||
|
|
||||||
static STATIC_HI_EXEC: StaticCell<InterruptExecutor<2>> = StaticCell::new();
|
static STATIC_HI_EXEC: StaticCell<InterruptExecutor<2>> = StaticCell::new();
|
||||||
static CORE2_EXEC: StaticCell<Executor> = StaticCell::new();
|
static CORE2_EXEC: StaticCell<Executor> = StaticCell::new();
|
||||||
|
|
||||||
static BUS_GARAGE: StaticCell<BusGarage> = StaticCell::new();
|
|
||||||
static mut CORE2_STACK: Stack<16384> = Stack::new();
|
static mut CORE2_STACK: Stack<16384> = Stack::new();
|
||||||
#[cfg(feature="radio")]
|
#[cfg(feature="radio")]
|
||||||
static WIFI_INIT: StaticCell<esp_radio::Controller<'static>> = StaticCell::new();
|
static WIFI_INIT: StaticCell<esp_radio::Controller<'static>> = StaticCell::new();
|
||||||
@@ -83,13 +86,13 @@ async fn main(spawner: Spawner) {
|
|||||||
let timer0 = TimerGroup::new(peripherals.TIMG0);
|
let timer0 = TimerGroup::new(peripherals.TIMG0);
|
||||||
let mut wdt = timer0.wdt;
|
let mut wdt = timer0.wdt;
|
||||||
wdt.set_timeout(esp_hal::timer::timg::MwdtStage::Stage0, esp_hal::time::Duration::from_secs(5));
|
wdt.set_timeout(esp_hal::timer::timg::MwdtStage::Stage0, esp_hal::time::Duration::from_secs(5));
|
||||||
wdt.enable();
|
//wdt.enable();
|
||||||
|
|
||||||
let swi = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
|
let swi = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
|
||||||
let hi_exec = STATIC_HI_EXEC.init(InterruptExecutor::new(swi.software_interrupt2));
|
//let hi_exec = STATIC_HI_EXEC.init(InterruptExecutor::new(swi.software_interrupt2));
|
||||||
let hi_spawn = hi_exec.start(esp_hal::interrupt::Priority::max());
|
//let hi_spawn = hi_exec.start(esp_hal::interrupt::Priority::max());
|
||||||
|
|
||||||
hi_spawn.must_spawn(renderbug_embassy::tasks::render::render(peripherals.RMT, peripherals.GPIO5.degrade(), surfaces, safety_surfaces, display_controls, wdt));
|
spawner.must_spawn(renderbug_embassy::tasks::render::render(peripherals.RMT, peripherals.GPIO5.degrade(), surfaces, safety_surfaces, display_controls, wdt));
|
||||||
|
|
||||||
#[cfg(feature="motion")]
|
#[cfg(feature="motion")]
|
||||||
{
|
{
|
||||||
@@ -149,28 +152,32 @@ async fn main(spawner: Spawner) {
|
|||||||
info!("Starting core 2");
|
info!("Starting core 2");
|
||||||
|
|
||||||
let core2_main = |spawner: Spawner| {
|
let core2_main = |spawner: Spawner| {
|
||||||
let garage = BUS_GARAGE.init_with(|| { Default::default() });
|
static PREDICTIONS: StaticCell<PubSubChannel<NoopRawMutex, Prediction, 15, 5, 1>> = StaticCell::new();
|
||||||
|
let predictions = PREDICTIONS.init(PubSubChannel::new());
|
||||||
|
|
||||||
info!("Launching motion engine");
|
#[cfg(not(feature="demo"))]
|
||||||
spawner.must_spawn(motion_task(motion_bus.dyn_receiver(), garage.predict.dyn_publisher().unwrap()));
|
|
||||||
|
|
||||||
info!("Launching Safety UI");
|
|
||||||
spawner.must_spawn(safety_ui_main(garage.predict.dyn_subscriber().unwrap(), safety_ui));
|
|
||||||
info!("Launching UI");
|
|
||||||
spawner.must_spawn(ui_main(garage.predict.dyn_subscriber().unwrap(), ui));
|
|
||||||
info!("Launching OLED UI");
|
|
||||||
spawner.must_spawn(oled_ui(garage.predict.dyn_subscriber().unwrap(), oledui));
|
|
||||||
|
|
||||||
#[cfg(feature="radio")]
|
|
||||||
{
|
{
|
||||||
info!("Launching networking stack");
|
info!("Launching motion engine");
|
||||||
spawner.must_spawn(renderbug_embassy::tasks::wifi::wireless_task(garage.predict.dyn_subscriber().unwrap(), wifi_init, peripherals.WIFI));
|
spawner.must_spawn(motion_task(motion_bus.dyn_receiver(), predictions.dyn_publisher().unwrap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature="demo")]
|
#[cfg(feature="demo")]
|
||||||
{
|
{
|
||||||
warn!("Launching with demo sequencer");
|
warn!("Launching with demo sequencer");
|
||||||
spawner.must_spawn(renderbug_embassy::tasks::demo::demo_task(garage.notify.dyn_publisher().unwrap()));
|
spawner.must_spawn(renderbug_embassy::tasks::demo::demo_task(predictions.dyn_publisher().unwrap()));
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Launching Safety UI");
|
||||||
|
spawner.must_spawn(safety_ui_main(predictions.dyn_subscriber().unwrap(), safety_ui));
|
||||||
|
info!("Launching UI");
|
||||||
|
spawner.must_spawn(ui_main(predictions.dyn_subscriber().unwrap(), ui));
|
||||||
|
info!("Launching OLED UI");
|
||||||
|
spawner.must_spawn(oled_ui(predictions.dyn_subscriber().unwrap(), oledui));
|
||||||
|
|
||||||
|
#[cfg(feature="radio")]
|
||||||
|
{
|
||||||
|
info!("Launching networking stack");
|
||||||
|
spawner.must_spawn(renderbug_embassy::tasks::wifi::wireless_task(predictions.dyn_subscriber().unwrap(), wifi_init, peripherals.WIFI));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature="dual-core")]
|
#[cfg(feature="dual-core")]
|
||||||
@@ -184,6 +191,8 @@ async fn main(spawner: Spawner) {
|
|||||||
spawner.must_spawn(wdt_task(ui_wdt));
|
spawner.must_spawn(wdt_task(ui_wdt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spawner.must_spawn(print_telemetry(predictions.dyn_subscriber().unwrap()));
|
||||||
|
|
||||||
info!("System is ready in {}ms", Instant::now().as_millis());
|
info!("System is ready in {}ms", Instant::now().as_millis());
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -207,3 +216,10 @@ async fn wdt_task(mut wdt: Wdt<esp_hal::peripherals::TIMG1<'static>>) {
|
|||||||
Timer::after_secs(3).await;
|
Timer::after_secs(3).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn print_telemetry(mut events: DynSubscriber<'static, Prediction>) {
|
||||||
|
loop {
|
||||||
|
info!("predict={:?}", events.next_message_pure().await);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
|
|
||||||
use embassy_sync::{blocking_mutex::raw::NoopRawMutex, pubsub::PubSubChannel};
|
|
||||||
use embassy_time::Duration;
|
use embassy_time::Duration;
|
||||||
use enum_map::Enum;
|
use enum_map::Enum;
|
||||||
use enumset::EnumSetType;
|
use enumset::EnumSetType;
|
||||||
@@ -67,26 +66,6 @@ pub enum Prediction {
|
|||||||
SetPersonality(Personality)
|
SetPersonality(Personality)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub enum Notification {
|
|
||||||
// The prediction engine has decided the UI should switch to another scene
|
|
||||||
SceneChange(Scene),
|
|
||||||
|
|
||||||
// States of external connections to the world
|
|
||||||
SensorStatus(SensorSource, SensorState),
|
|
||||||
// The prediction engine has decided that the system should be woken up and begin running again
|
|
||||||
WakeUp,
|
|
||||||
// The prediction engine has decided that the system is inactive enough and it should go to low-power sleep
|
|
||||||
Sleep,
|
|
||||||
|
|
||||||
// FIXME: Sor safety purposes, we probably want these two events to be combined and act atomic; if the safety lights are ever on, they should both be on.
|
|
||||||
SetHeadlight(bool),
|
|
||||||
SetBrakelight(bool),
|
|
||||||
|
|
||||||
// TODO: BPM detection via bluetooth
|
|
||||||
Beat,
|
|
||||||
}
|
|
||||||
|
|
||||||
// GPS data = 2, motion data = 1
|
// GPS data = 2, motion data = 1
|
||||||
#[derive(Debug, EnumSetType, Enum)]
|
#[derive(Debug, EnumSetType, Enum)]
|
||||||
pub enum SensorSource {
|
pub enum SensorSource {
|
||||||
@@ -117,18 +96,3 @@ impl From<StreamType> for SensorSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct BusGarage {
|
|
||||||
pub notify: PubSubChannel<NoopRawMutex, Notification, 5, 2, 4>,
|
|
||||||
pub predict: PubSubChannel<NoopRawMutex, Prediction, 15, 3, 3>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for BusGarage {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
notify: PubSubChannel::new(),
|
|
||||||
predict: PubSubChannel::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +1,28 @@
|
|||||||
use embassy_sync::pubsub::DynPublisher;
|
use embassy_sync::pubsub::DynPublisher;
|
||||||
use embassy_time::Timer;
|
use embassy_time::Timer;
|
||||||
|
|
||||||
use crate::events::{Notification, Scene, SensorSource, SensorState};
|
use crate::{ego::engine::MotionState, events::{Personality, Prediction, SensorSource, SensorState}};
|
||||||
|
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
pub async fn demo_task(ui: DynPublisher<'static, Notification>) {
|
pub async fn demo_task(ui: DynPublisher<'static, Prediction>) {
|
||||||
|
ui.publish(Prediction::SensorStatus(SensorSource::Demo, SensorState::AcquiringFix)).await;
|
||||||
Timer::after_secs(10).await;
|
Timer::after_secs(10).await;
|
||||||
ui.publish(Notification::SceneChange(Scene::Idle)).await;
|
ui.publish(Prediction::SetPersonality(crate::events::Personality::Active)).await;
|
||||||
ui.publish(Notification::SetBrakelight(true)).await;
|
|
||||||
ui.publish(Notification::SetHeadlight(true)).await;
|
|
||||||
Timer::after_secs(10).await;
|
Timer::after_secs(10).await;
|
||||||
ui.publish(Notification::SensorStatus(SensorSource::Demo, SensorState::AcquiringFix)).await;
|
ui.publish(Prediction::SensorStatus(SensorSource::Demo, SensorState::Online)).await;
|
||||||
loop {
|
loop {
|
||||||
for scene in [Scene::Accelerating, Scene::Ready, Scene::Decelerating, Scene::Ready] {
|
for personality in [Personality::Active, Personality::Parked] {
|
||||||
ui.publish(Notification::SceneChange(scene)).await;
|
ui.publish(Prediction::SetPersonality(personality)).await;
|
||||||
for state in [SensorState::Offline, SensorState::AcquiringFix, SensorState::Degraded, SensorState::Offline] {
|
for state in [SensorState::Offline, SensorState::AcquiringFix, SensorState::Degraded, SensorState::Offline] {
|
||||||
|
for motion in [MotionState::Accelerating, MotionState::Steady, MotionState::Decelerating, MotionState::Stationary] {
|
||||||
|
ui.publish(Prediction::Motion { prev: motion, next: motion }).await;
|
||||||
for sensor in [SensorSource::ForwardsReference, SensorSource::GPS, SensorSource::GravityReference, SensorSource::IMU, SensorSource::Location] {
|
for sensor in [SensorSource::ForwardsReference, SensorSource::GPS, SensorSource::GravityReference, SensorSource::IMU, SensorSource::Location] {
|
||||||
ui.publish(Notification::SensorStatus(sensor, state)).await;
|
ui.publish(Prediction::SensorStatus(sensor, state)).await;
|
||||||
}
|
}
|
||||||
Timer::after_secs(1).await;
|
Timer::after_secs(1).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user