events: rewrite how sensor statuses are reported, and implement some oled UI icons for it
This commit is contained in:
@@ -1,14 +1,15 @@
|
||||
use core::f32::consts::PI;
|
||||
use core::fmt::Binary;
|
||||
|
||||
use alloc::format;
|
||||
use embedded_graphics::image::ImageRaw;
|
||||
use embedded_graphics::mono_font::ascii::*;
|
||||
use embedded_graphics::mono_font::{MonoTextStyle, MonoTextStyleBuilder};
|
||||
use embedded_graphics::pixelcolor::BinaryColor;
|
||||
use embedded_graphics::prelude::Size;
|
||||
use embedded_graphics::prelude::{DrawTarget, Size};
|
||||
use embedded_graphics::primitives::{Line, PrimitiveStyle, PrimitiveStyleBuilder, StyledDrawable};
|
||||
use embedded_graphics::text::{Alignment, Text};
|
||||
use embedded_graphics::{image::Image, prelude::Point, Drawable};
|
||||
use enum_map::EnumMap;
|
||||
use figments::liber8tion::trig::sin8;
|
||||
use figments::mappings::embedded_graphics::Matrix2DSpace;
|
||||
use figments::{liber8tion::trig::cos8, mappings::embedded_graphics::EmbeddedGraphicsSampler};
|
||||
@@ -17,6 +18,7 @@ use nalgebra::Vector2;
|
||||
use micromath::F32Ext;
|
||||
use embedded_graphics::geometry::OriginDimensions;
|
||||
|
||||
use crate::events::{SensorSource, SensorState};
|
||||
use crate::graphics::images;
|
||||
use crate::{ego::engine::MotionState, events::Scene};
|
||||
|
||||
@@ -26,8 +28,7 @@ pub struct OledUI {
|
||||
pub motion: MotionState,
|
||||
pub brakelight: bool,
|
||||
pub headlight: bool,
|
||||
pub gps_online: bool,
|
||||
pub imu_online: bool,
|
||||
pub sensor_states: EnumMap<SensorSource, SensorState>,
|
||||
pub velocity: f32,
|
||||
pub location: Vector2<f64>,
|
||||
pub sleep: bool,
|
||||
@@ -50,6 +51,90 @@ pub enum Screen {
|
||||
Waking
|
||||
}
|
||||
|
||||
struct SensorImage {
|
||||
source: SensorSource,
|
||||
on: &'static ImageRaw<'static, BinaryColor>,
|
||||
off: &'static ImageRaw<'static, BinaryColor>,
|
||||
}
|
||||
|
||||
struct SensorIcon<'a> {
|
||||
anchor: embedded_graphics::geometry::Point,
|
||||
image: &'a SensorImage,
|
||||
state: SensorState,
|
||||
frame: usize
|
||||
}
|
||||
|
||||
impl<'a> SensorIcon<'a> {
|
||||
pub const fn new(image: &'a SensorImage, state: SensorState, frame: usize, anchor: embedded_graphics::geometry::Point) -> Self {
|
||||
Self {
|
||||
anchor,
|
||||
image,
|
||||
state,
|
||||
frame
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw<T: DrawTarget<Color = BinaryColor>>(&self, target: &mut T) -> Result<(), T::Error> {
|
||||
match self.state {
|
||||
SensorState::AcquiringFix => {
|
||||
if (self.frame / 10) % 2 == 0 {
|
||||
Image::new(self.image.off, self.anchor).draw(target)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
SensorState::Online => {
|
||||
Image::new(self.image.on, self.anchor).draw(target)
|
||||
},
|
||||
SensorState::Offline => {
|
||||
Image::new(self.image.off, self.anchor).draw(target)
|
||||
},
|
||||
SensorState::Degraded => {
|
||||
if (self.frame / 10) % 2 == 0 {
|
||||
Image::new(self.image.on, self.anchor).draw(target)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const SENSOR_IMAGES: &[SensorImage] = &[
|
||||
SensorImage {
|
||||
source: SensorSource::GPS,
|
||||
on: &images::GPS_ON, off: &images::GPS_OFF,
|
||||
},
|
||||
SensorImage {
|
||||
source: SensorSource::IMU,
|
||||
on: &images::IMU_ON, off: &images::IMU_OFF,
|
||||
},
|
||||
SensorImage {
|
||||
source: SensorSource::GravityReference,
|
||||
on: &images::GRAVITY_LOCATED, off: &images::GRAVITY_MISSING,
|
||||
},
|
||||
SensorImage {
|
||||
source: SensorSource::Location,
|
||||
on: &images::LOCATION_ON, off: &images::LOCATION_OFF,
|
||||
},
|
||||
#[cfg(feature="demo")]
|
||||
SensorImage {
|
||||
source: SensorSource::Demo,
|
||||
on: &images::DEMO, off: &images::DEMO,
|
||||
},
|
||||
#[cfg(feature="simulation")]
|
||||
SensorImage {
|
||||
source: SensorSource::Simulation,
|
||||
on: &images::TAPE, off: &images::TAPE
|
||||
},
|
||||
];
|
||||
|
||||
const DISPLAY_SIZE: Size = Size::new(128, 64);
|
||||
const SENSOR_ICON_SIZE: u32 = 16;
|
||||
const SENSOR_ICON_SPACING: u32 = 2;
|
||||
const SENSOR_TRAY_SIZE: Size = Size::new(SENSOR_IMAGES.len() as u32 * (SENSOR_ICON_SIZE + SENSOR_ICON_SPACING), SENSOR_ICON_SIZE + SENSOR_ICON_SPACING);
|
||||
const SPEEDO_TRAY_SIZE: Size = Size::new(DISPLAY_SIZE.width - SENSOR_TRAY_SIZE.width, SENSOR_TRAY_SIZE.height);
|
||||
|
||||
impl Screen {
|
||||
pub fn draw_screen<'a, T>(&self, sampler: &mut EmbeddedGraphicsSampler<'a, T>, state: &OledUniforms) where T: Sample<'a, Matrix2DSpace>, T::Output: PixelSink<BinaryColor> {
|
||||
match self {
|
||||
@@ -74,36 +159,22 @@ impl Screen {
|
||||
Screen::Home => {
|
||||
// Status bar
|
||||
// Sensor indicators
|
||||
let gps_img = if state.ui.gps_online {
|
||||
&images::GPS_ON
|
||||
} else {
|
||||
&images::GPS_OFF
|
||||
};
|
||||
let imu_img = if state.ui.imu_online {
|
||||
&images::IMU_ON
|
||||
} else {
|
||||
&images::IMU_OFF
|
||||
};
|
||||
Image::new(gps_img, Point::zero()).draw(sampler).unwrap();
|
||||
Image::new(imu_img, Point::new((gps_img.size().width + 2) as i32, 0)).draw(sampler).unwrap();
|
||||
for (idx, sensor) in SENSOR_IMAGES.iter().enumerate() {
|
||||
let offset = idx * (16 + 2);
|
||||
let position = Point::new(offset as i32, 0);
|
||||
SensorIcon::new(sensor, state.ui.sensor_states[sensor.source], state.frame, position)
|
||||
.draw(sampler).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(feature="demo")]
|
||||
Text::with_alignment("Demo", Point::new(128, 10), TEXT_STYLE, Alignment::Right)
|
||||
.draw(sampler)
|
||||
.unwrap();
|
||||
let speedo_center = SENSOR_TRAY_SIZE.width + SPEEDO_TRAY_SIZE.width / 2;
|
||||
|
||||
#[cfg(feature="simulation")]
|
||||
Text::with_alignment("Sim", Point::new(128, 10), TEXT_STYLE, Alignment::Right)
|
||||
// Speed display at the top
|
||||
Text::with_alignment(&format!("{}", state.ui.velocity), Point::new(speedo_center as i32, 12), SPEED_STYLE, Alignment::Center)
|
||||
.draw(sampler)
|
||||
.unwrap();
|
||||
|
||||
// Separates the status bar from the UI
|
||||
Line::new(Point::new(0, 18), Point::new(128, 18)).draw_styled(&INACTIVE_STYLE, sampler).unwrap();
|
||||
|
||||
// Speed display at the top
|
||||
Text::with_alignment(&format!("{}", state.ui.velocity), Point::new(128 / 2, 12), SPEED_STYLE, Alignment::Center)
|
||||
.draw(sampler)
|
||||
.unwrap();
|
||||
Line::new(Point::new(0, SENSOR_TRAY_SIZE.height as i32), Point::new(128, SENSOR_TRAY_SIZE.height as i32)).draw_styled(&INACTIVE_STYLE, sampler).unwrap();
|
||||
|
||||
// The main UI content
|
||||
Image::new(&images::BIKE, Point::new((128 / 2 - images::BIKE.size().width / 2) as i32, 24)).draw(sampler).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user