188 lines
5.6 KiB
Rust
188 lines
5.6 KiB
Rust
//! Screen Output
|
|
|
|
use alloc::vec;
|
|
|
|
use embedded_graphics::prelude::*;
|
|
use embedded_graphics::{geometry, mono_font, pixelcolor, primitives, text};
|
|
|
|
use crate::applogic;
|
|
|
|
pub const WIDTH: u16 = 320;
|
|
pub const HEIGHT: u16 = 172;
|
|
|
|
#[allow(unused)]
|
|
pub fn clear<D>(target: &mut D) -> Result<(), D::Error>
|
|
where
|
|
D: DrawTarget<Color = pixelcolor::Rgb565>,
|
|
{
|
|
let style = primitives::PrimitiveStyleBuilder::new()
|
|
.fill_color(pixelcolor::Rgb565::BLACK)
|
|
.build();
|
|
primitives::Rectangle::new(
|
|
geometry::Point::new(0, 0),
|
|
geometry::Size::new(WIDTH.into(), HEIGHT.into()),
|
|
)
|
|
.into_styled(style)
|
|
.draw(target)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[allow(unused)]
|
|
pub fn test_img<C, D>(target: &mut D) -> Result<(), D::Error>
|
|
where
|
|
D: DrawTarget<Color = C>,
|
|
C: RgbColor,
|
|
{
|
|
mipidsi::TestImage::new().draw(target)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[allow(unused)]
|
|
pub fn draw_glosa<D>(target: &mut D, data: &[applogic::SignalGroupData]) -> Result<(), D::Error>
|
|
where
|
|
D: DrawTarget<Color = pixelcolor::Rgb565>,
|
|
{
|
|
let num_signals = data.len();
|
|
|
|
if num_signals == 0 {
|
|
return clear(target);
|
|
}
|
|
|
|
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
|
|
let sig_width = (WIDTH as i32) / (num_signals as i32);
|
|
|
|
let text_style =
|
|
mono_font::MonoTextStyle::new(&profont::PROFONT_24_POINT, pixelcolor::Rgb565::WHITE);
|
|
let blank_style = primitives::PrimitiveStyleBuilder::new()
|
|
.fill_color(pixelcolor::Rgb565::CSS_GRAY)
|
|
.build();
|
|
let rd_style = primitives::PrimitiveStyleBuilder::new()
|
|
.fill_color(pixelcolor::Rgb565::CSS_RED)
|
|
.build();
|
|
let ye_style = primitives::PrimitiveStyleBuilder::new()
|
|
.fill_color(pixelcolor::Rgb565::CSS_YELLOW) // TODO: select nicer color
|
|
.build();
|
|
let gn_style = primitives::PrimitiveStyleBuilder::new()
|
|
.fill_color(pixelcolor::Rgb565::CSS_GREEN)
|
|
.build();
|
|
|
|
// clear maneuver and timing area
|
|
let style = primitives::PrimitiveStyleBuilder::new()
|
|
.fill_color(pixelcolor::Rgb565::BLACK)
|
|
.build();
|
|
primitives::Rectangle::new(
|
|
geometry::Point::new(0, 105),
|
|
geometry::Size::new(WIDTH.into(), 67),
|
|
)
|
|
.into_styled(style)
|
|
.draw(target)?;
|
|
|
|
for (idx, sig) in data.iter().enumerate() {
|
|
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
|
|
let offset = (idx as i32) * sig_width;
|
|
|
|
let circle_dia = 50;
|
|
let circle_margin = (sig_width - circle_dia) / 2;
|
|
let centerline = offset + (sig_width / 2);
|
|
|
|
// draw phase color
|
|
let style = match sig.phase {
|
|
applogic::SignalPhase::Unknown => blank_style,
|
|
applogic::SignalPhase::Red => rd_style,
|
|
applogic::SignalPhase::Green => gn_style,
|
|
applogic::SignalPhase::RedYellow | applogic::SignalPhase::Yellow => ye_style,
|
|
};
|
|
primitives::Circle::new(
|
|
geometry::Point::new(offset + circle_margin, 10),
|
|
circle_dia as u32,
|
|
)
|
|
.into_styled(style)
|
|
.draw(target)?;
|
|
|
|
// TODO: draw lane type?
|
|
|
|
// draw maneuver
|
|
text::Text::with_alignment(
|
|
&alloc::format!("{}", maneuver_to_str(&sig.maneuver)),
|
|
geometry::Point::new(centerline, 130),
|
|
text_style,
|
|
text::Alignment::Center,
|
|
)
|
|
.draw(target)?;
|
|
|
|
// draw timing indicator
|
|
if let Some(min_end_sec) = sig.min_end_sec {
|
|
text::Text::with_alignment(
|
|
&alloc::format!("{min_end_sec}s"),
|
|
geometry::Point::new(centerline, 160),
|
|
text_style,
|
|
text::Alignment::Center,
|
|
)
|
|
.draw(target)?;
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[allow(unused)]
|
|
pub fn draw_slash_screen<D>(target: &mut D) -> Result<(), D::Error>
|
|
where
|
|
D: DrawTarget<Color = pixelcolor::Rgb565>,
|
|
{
|
|
let text_style =
|
|
mono_font::MonoTextStyle::new(&profont::PROFONT_18_POINT, pixelcolor::Rgb565::WHITE);
|
|
let blank_style = primitives::PrimitiveStyleBuilder::new()
|
|
.fill_color(pixelcolor::Rgb565::CSS_GRAY)
|
|
.build();
|
|
let rd_style = primitives::PrimitiveStyleBuilder::new()
|
|
.fill_color(pixelcolor::Rgb565::CSS_RED)
|
|
.build();
|
|
let ye_style = primitives::PrimitiveStyleBuilder::new()
|
|
.fill_color(pixelcolor::Rgb565::CSS_YELLOW) // TODO: select nicer color
|
|
.build();
|
|
let gn_style = primitives::PrimitiveStyleBuilder::new()
|
|
.fill_color(pixelcolor::Rgb565::CSS_GREEN)
|
|
.build();
|
|
|
|
clear(target)?;
|
|
|
|
let sig_width = (WIDTH as i32) / 3;
|
|
let circle_dia = 50;
|
|
let circle_margin = (sig_width - circle_dia) / 2;
|
|
|
|
for (idx, style) in vec![rd_style, ye_style, gn_style].iter().enumerate() {
|
|
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
|
|
let offset = (idx as i32) * sig_width;
|
|
|
|
primitives::Circle::new(
|
|
geometry::Point::new(offset + circle_margin, 10),
|
|
circle_dia as u32,
|
|
)
|
|
.into_styled(*style)
|
|
.draw(target)?;
|
|
}
|
|
|
|
// draw welcome text
|
|
let centerline = (WIDTH as i32) / 2;
|
|
text::Text::with_alignment(
|
|
"C-ITS Signal Phase Display\nWaiting for GNSS fix...",
|
|
geometry::Point::new(centerline, 130),
|
|
text_style,
|
|
text::Alignment::Center,
|
|
)
|
|
.draw(target)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn maneuver_to_str(value: &applogic::v2x::map::Maneuvers) -> alloc::string::String {
|
|
alloc::format!(
|
|
"{}{}{}",
|
|
if value.left_allowed { "<" } else { " " },
|
|
if value.staight_allowed { "^" } else { " " },
|
|
if value.right_allowed { ">" } else { " " },
|
|
)
|
|
}
|