events: rewrite how sensor statuses are reported, and implement some oled UI icons for it
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use embassy_sync::pubsub::DynPublisher;
|
||||
use embassy_time::Timer;
|
||||
|
||||
use crate::events::{Notification, Scene};
|
||||
use crate::events::{Notification, Scene, SensorSource, SensorState};
|
||||
|
||||
|
||||
#[embassy_executor::task]
|
||||
@@ -11,10 +11,16 @@ pub async fn demo_task(ui: DynPublisher<'static, Notification>) {
|
||||
ui.publish(Notification::SetBrakelight(true)).await;
|
||||
ui.publish(Notification::SetHeadlight(true)).await;
|
||||
Timer::after_secs(10).await;
|
||||
ui.publish(Notification::SensorStatus(SensorSource::Demo, SensorState::AcquiringFix)).await;
|
||||
loop {
|
||||
for scene in [Scene::Accelerating, Scene::Ready, Scene::Decelerating, Scene::Ready] {
|
||||
Timer::after_secs(8).await;
|
||||
ui.publish(Notification::SceneChange(scene)).await
|
||||
};
|
||||
ui.publish(Notification::SceneChange(scene)).await;
|
||||
for state in [SensorState::Offline, SensorState::AcquiringFix, SensorState::Degraded, SensorState::Offline] {
|
||||
for sensor in [SensorSource::ForwardsReference, SensorSource::GPS, SensorSource::GravityReference, SensorSource::IMU, SensorSource::Location] {
|
||||
ui.publish(Notification::SensorStatus(sensor, state)).await;
|
||||
}
|
||||
Timer::after_secs(1).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
use embassy_sync::{channel::{DynamicReceiver, DynamicSender}, pubsub::DynPublisher};
|
||||
use log::*;
|
||||
|
||||
use crate::{ego::engine::BikeStates, events::{Measurement, Notification, Prediction}};
|
||||
use crate::{ego::engine::BikeStates, events::{Measurement, Notification, Prediction, SensorSource, SensorState}};
|
||||
|
||||
#[embassy_executor::task]
|
||||
pub async fn motion_task(src: DynamicReceiver<'static, Measurement>, ui_sink: DynPublisher<'static, Notification>, prediction_sink: DynamicSender<'static, Prediction>) {
|
||||
@@ -24,8 +24,10 @@ pub async fn motion_task(src: DynamicReceiver<'static, Measurement>, ui_sink: Dy
|
||||
states.has_gps_fix.set(false);
|
||||
},
|
||||
// FIXME: This needs harmonized with the automatic data timeout from above, somehow?
|
||||
Measurement::SensorOnline(source) => warn!("Sensor {source:?} reports online!"),
|
||||
Measurement::SensorOffline(source) => warn!("Sensor {source:?} reports offline!"),
|
||||
Measurement::SensorHardwareStatus(source, state) => {
|
||||
warn!("Sensor {source:?} reports {state:?}!");
|
||||
ui_sink.publish(Notification::SensorStatus(source, state)).await;
|
||||
},
|
||||
Measurement::SimulationProgress(source, duration, _pct) => debug!("{source:?} simulation time: {}", duration.as_secs()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ fn gyro_raw_to_rads(raw: i16) -> f32 {
|
||||
|
||||
#[esp_hal::ram(rtc_fast, persistent)]
|
||||
static mut MPU_WAS_CALIBRATED: u8 = 0;
|
||||
//static mut MPU_CALIBRATION: Option<(Accel, Gyro)> = None;
|
||||
|
||||
#[embassy_executor::task]
|
||||
pub async fn mpu_task(events: DynamicSender<'static, Measurement>, bus: I2cDevice<'static, CriticalSectionRawMutex, I2c<'static, Async>>) {
|
||||
@@ -39,6 +38,7 @@ pub async fn mpu_task(events: DynamicSender<'static, Measurement>, bus: I2cDevic
|
||||
let busref = RefCell::new(Some(bus));
|
||||
|
||||
backoff.forever().attempt::<_, (), ()>(async || {
|
||||
events.send(Measurement::SensorHardwareStatus(SensorSource::IMU, crate::events::SensorState::Offline)).await;
|
||||
let mut sensor = backoff.forever().attempt(async || {
|
||||
warn!("Initializing connection to MPU");
|
||||
match Mpu6050::new(busref.replace(None).unwrap(), Address::default()).await.map_err(|e| { e.i2c }) {
|
||||
@@ -47,6 +47,7 @@ pub async fn mpu_task(events: DynamicSender<'static, Measurement>, bus: I2cDevic
|
||||
Err(())
|
||||
},
|
||||
Ok(mut sensor) => {
|
||||
events.send(Measurement::SensorHardwareStatus(SensorSource::IMU, crate::events::SensorState::AcquiringFix)).await;
|
||||
match backoff.attempt(async || { mpu_init(&mut sensor).await }).await {
|
||||
Err(_) => {
|
||||
busref.replace(Some(sensor.release()));
|
||||
@@ -60,7 +61,7 @@ pub async fn mpu_task(events: DynamicSender<'static, Measurement>, bus: I2cDevic
|
||||
|
||||
let sensor_ref = &mut sensor;
|
||||
|
||||
events.send(Measurement::SensorOnline(SensorSource::IMU)).await;
|
||||
events.send(Measurement::SensorHardwareStatus(SensorSource::IMU, crate::events::SensorState::Online)).await;
|
||||
//TODO: Need to read in a constant buffer of accelerometer measurements, which we can then use to determine where "forward" points in the body frame when converting from the sensor frame.
|
||||
// From there, we can rotate the body frame into the world frame using gps headings to generate a compass north
|
||||
fn lowpass(prev: f32, current: f32, alpha: f32) -> f32 {
|
||||
|
||||
@@ -7,7 +7,7 @@ use figments::{mappings::embedded_graphics::Matrix2DSpace, prelude::{Coordinates
|
||||
use figments_render::output::{Brightness, OutputAsync};
|
||||
use log::*;
|
||||
|
||||
use crate::{animation::Animation, backoff::Backoff, events::{Notification, Prediction, SensorSource, Telemetry}, graphics::{display::DisplayControls, oled_ui::{OledUniforms, Screen}}};
|
||||
use crate::{animation::Animation, backoff::Backoff, events::{Notification, Prediction, SensorSource, SensorState, Telemetry}, graphics::{display::DisplayControls, oled_ui::{OledUniforms, Screen}}};
|
||||
|
||||
#[cfg(feature="oled")]
|
||||
pub type OledUiSurfacePool = BufferedSurfacePool<OledUniforms, Matrix2DSpace, BinaryColor>;
|
||||
@@ -84,10 +84,7 @@ impl<S: core::fmt::Debug + Surface<CoordinateSpace = Matrix2DSpace, Pixel = Bina
|
||||
Telemetry::Notification(Notification::SceneChange(scene)) => self.with_uniforms(|state| {state.ui.scene = scene}).await,
|
||||
Telemetry::Notification(Notification::SetBrakelight(b)) => self.with_uniforms(|state| {state.ui.brakelight = b}).await,
|
||||
Telemetry::Notification(Notification::SetHeadlight(b)) => self.with_uniforms(|state| {state.ui.headlight = b}).await,
|
||||
Telemetry::Notification(Notification::SensorOffline(SensorSource::IMU)) => self.with_uniforms(|state| {state.ui.imu_online = false}).await,
|
||||
Telemetry::Notification(Notification::SensorOnline(SensorSource::IMU)) => self.with_uniforms(|state| {state.ui.imu_online = true}).await,
|
||||
Telemetry::Notification(Notification::SensorOffline(SensorSource::GPS)) => self.with_uniforms(|state| {state.ui.gps_online = false}).await,
|
||||
Telemetry::Notification(Notification::SensorOnline(SensorSource::GPS)) => self.with_uniforms(|state| {state.ui.gps_online = true}).await,
|
||||
Telemetry::Notification(Notification::SensorStatus(src, sensor_state)) => self.with_uniforms(|state| {state.ui.sensor_states[src] = sensor_state}).await,
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use core::fmt::Debug;
|
||||
use futures::join;
|
||||
use log::*;
|
||||
|
||||
use crate::{animation::{AnimatedSurface, Animation}, graphics::display::{SegmentSpace, Uniforms}, events::{Notification, Scene, SensorSource, Telemetry}, graphics::shaders::*};
|
||||
use crate::{animation::{AnimatedSurface, Animation}, events::{Notification, Scene, SensorSource, SensorState, Telemetry}, graphics::{display::{SegmentSpace, Uniforms}, shaders::*}};
|
||||
|
||||
pub struct Ui<S: Surface> {
|
||||
// Background layer provides an always-running background for everything to draw on
|
||||
@@ -139,19 +139,13 @@ impl<S: Debug + Surface<Uniforms = Uniforms, CoordinateSpace = SegmentSpace, Pix
|
||||
}
|
||||
match event {
|
||||
// TODO: We probably also want some events to indicate when the ESP has no calibration data or otherwise needs re-calibrated and is waiting for the bike to stand still
|
||||
Notification::SensorOnline(SensorSource::IMU) => self.flash_notification_color(Rgb::new(0, 255, 0)).await,
|
||||
Notification::SensorOffline(SensorSource::GPS) => self.flash_notification_color(Rgb::new(255, 0, 0)).await,
|
||||
Notification::SensorOnline(SensorSource::GPS) => self.flash_notification_color(Rgb::new(0, 255, 255)).await,
|
||||
Notification::SensorStatus(SensorSource::IMU, SensorState::Online) => self.flash_notification_color(Rgb::new(0, 255, 0)).await,
|
||||
Notification::SensorStatus(SensorSource::Location, SensorState::Degraded) => self.flash_notification_color(Rgb::new(255, 0, 0)).await,
|
||||
Notification::SensorStatus(SensorSource::GPS, SensorState::Online) => self.flash_notification_color(Rgb::new(0, 255, 255)).await,
|
||||
|
||||
// Scene change
|
||||
Notification::SceneChange(scene) => self.apply_scene(scene).await,
|
||||
|
||||
Notification::SensorsOffline => {
|
||||
self.flash_notification_color(Rgb::new(255, 0, 0)).await;
|
||||
self.flash_notification_color(Rgb::new(0, 255, 0)).await;
|
||||
self.flash_notification_color(Rgb::new(0, 0, 255)).await;
|
||||
}
|
||||
|
||||
Notification::WakeUp => self.show().await,
|
||||
_ => ()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user