WIP screen: Show min and max end time
TODO: only on big screen!?
This commit is contained in:
parent
ba344f5e22
commit
cc7b49ee90
4 changed files with 125 additions and 35 deletions
|
|
@ -106,7 +106,54 @@ pub struct GlosaSignalInfo {
|
||||||
pub struct SignalGroupData {
|
pub struct SignalGroupData {
|
||||||
pub phase: SignalPhase,
|
pub phase: SignalPhase,
|
||||||
pub maneuver: map::Maneuvers,
|
pub maneuver: map::Maneuvers,
|
||||||
pub end_sec: Option<i16>,
|
pub timing: Option<TimingData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "spat")]
|
||||||
|
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||||
|
pub struct TimingData {
|
||||||
|
pub min_end_sec: i16,
|
||||||
|
pub likely_end_sec: Option<i16>,
|
||||||
|
pub max_end_sec: Option<i16>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TimingData {
|
||||||
|
pub fn new(value: &map::SignalGroup, now: chrono::DateTime<chrono::Utc>) -> Option<Self> {
|
||||||
|
let min = value
|
||||||
|
.min_end_time()
|
||||||
|
.map(|val| Self::time_to_duration_sec(now, val));
|
||||||
|
let likely_end_sec = value
|
||||||
|
.likely_time()
|
||||||
|
.map(|val| Self::time_to_duration_sec(now, val));
|
||||||
|
let max_end_sec = value
|
||||||
|
.min_end_time()
|
||||||
|
.map(|val| Self::time_to_duration_sec(now, val));
|
||||||
|
|
||||||
|
if let Some(min_end_sec) = min {
|
||||||
|
Some(Self {
|
||||||
|
min_end_sec,
|
||||||
|
likely_end_sec,
|
||||||
|
max_end_sec,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn time_to_duration_sec(
|
||||||
|
now: chrono::DateTime<chrono::Utc>,
|
||||||
|
time_point: chrono::DateTime<chrono::Utc>,
|
||||||
|
) -> i16 {
|
||||||
|
use core::ops::Sub as _;
|
||||||
|
|
||||||
|
use num_traits::Float as _;
|
||||||
|
|
||||||
|
let dur = time_point.sub(now).as_seconds_f32();
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
let duration_sec = dur.round() as i16;
|
||||||
|
|
||||||
|
duration_sec
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "spat")]
|
#[cfg(feature = "spat")]
|
||||||
|
|
@ -357,33 +404,17 @@ impl State {
|
||||||
let sig_grps = approach_sig_grps
|
let sig_grps = approach_sig_grps
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|sig| {
|
.filter_map(|sig| {
|
||||||
if let Some(manv) = sig.maneuvers() {
|
if let Some(maneuver) = sig.maneuvers() {
|
||||||
use core::ops::Sub;
|
|
||||||
|
|
||||||
use num_traits::Float;
|
|
||||||
|
|
||||||
let phase = sig
|
let phase = sig
|
||||||
.phase()
|
.phase()
|
||||||
.map(core::convert::Into::into)
|
.map(core::convert::Into::into)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
let timing = TimingData::new(*sig, self.time.and_utc());
|
||||||
let end_sec = sig
|
|
||||||
.likely_time()
|
|
||||||
.or_else(|| sig.min_end_time())
|
|
||||||
.map(|time| {
|
|
||||||
let dur =
|
|
||||||
time.sub(self.time.and_utc()).as_seconds_f32();
|
|
||||||
|
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
|
||||||
let end_sec = dur.round() as i16;
|
|
||||||
|
|
||||||
end_sec
|
|
||||||
});
|
|
||||||
|
|
||||||
Some(SignalGroupData {
|
Some(SignalGroupData {
|
||||||
phase,
|
phase,
|
||||||
maneuver: manv,
|
maneuver,
|
||||||
end_sec,
|
timing,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
||||||
|
|
@ -173,6 +173,12 @@ impl Intersection {
|
||||||
{
|
{
|
||||||
sig_grp.likely_time = Some(likely.to_datetime_from_moy(moy, year));
|
sig_grp.likely_time = Some(likely.to_datetime_from_moy(moy, year));
|
||||||
}
|
}
|
||||||
|
if let Some(max) = &timing.max_end_time
|
||||||
|
&& !max.is_out_of_range()
|
||||||
|
&& !max.is_unknown()
|
||||||
|
{
|
||||||
|
sig_grp.max_end_time = Some(max.to_datetime_from_moy(moy, year));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -223,6 +229,7 @@ impl Intersection {
|
||||||
target_lanes,
|
target_lanes,
|
||||||
phase: None,
|
phase: None,
|
||||||
min_end_time: None,
|
min_end_time: None,
|
||||||
|
max_end_time: None,
|
||||||
likely_time: None,
|
likely_time: None,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -410,7 +417,7 @@ pub struct SignalGroup {
|
||||||
/// current signal phase
|
/// current signal phase
|
||||||
phase: Option<etsi_its_dsrc::MovementPhaseState>,
|
phase: Option<etsi_its_dsrc::MovementPhaseState>,
|
||||||
min_end_time: Option<chrono::DateTime<chrono::Utc>>,
|
min_end_time: Option<chrono::DateTime<chrono::Utc>>,
|
||||||
// max_end_time: Option<chrono::DateTime<chrono::Utc>>,
|
max_end_time: Option<chrono::DateTime<chrono::Utc>>,
|
||||||
likely_time: Option<chrono::DateTime<chrono::Utc>>,
|
likely_time: Option<chrono::DateTime<chrono::Utc>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -443,6 +450,9 @@ impl SignalGroup {
|
||||||
pub fn likely_time(&self) -> Option<chrono::prelude::DateTime<chrono::prelude::Utc>> {
|
pub fn likely_time(&self) -> Option<chrono::prelude::DateTime<chrono::prelude::Utc>> {
|
||||||
self.likely_time
|
self.likely_time
|
||||||
}
|
}
|
||||||
|
pub fn max_end_time(&self) -> Option<chrono::prelude::DateTime<chrono::prelude::Utc>> {
|
||||||
|
self.max_end_time
|
||||||
|
}
|
||||||
|
|
||||||
pub fn phase_to_str(&self) -> Option<String> {
|
pub fn phase_to_str(&self) -> Option<String> {
|
||||||
self.phase.map(|v| {
|
self.phase.map(|v| {
|
||||||
|
|
|
||||||
33
src/main.rs
33
src/main.rs
|
|
@ -207,7 +207,33 @@ async fn main(spawner: Spawner) -> ! {
|
||||||
staight_allowed: false,
|
staight_allowed: false,
|
||||||
right_allowed: false
|
right_allowed: false
|
||||||
},
|
},
|
||||||
end_sec: Some(23)
|
timing: Some(applogic::TimingData {
|
||||||
|
min_end_sec: 23,
|
||||||
|
likely_end_sec: None,
|
||||||
|
max_end_sec: None
|
||||||
|
})
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
))
|
||||||
|
.inspect_err(log_screen_error);
|
||||||
|
embassy_time::Timer::after(embassy_time::Duration::from_secs(2)).await;
|
||||||
|
|
||||||
|
let _ = screen
|
||||||
|
.update(screen::ScreenState::GlosaLocked(
|
||||||
|
applogic::GlosaSignalInfo {
|
||||||
|
intersection_id: 1234,
|
||||||
|
signal_groups: alloc::vec![applogic::SignalGroupData {
|
||||||
|
phase: applogic::SignalPhase::Red,
|
||||||
|
maneuver: applogic::v2x::map::Maneuvers {
|
||||||
|
left_allowed: true,
|
||||||
|
staight_allowed: false,
|
||||||
|
right_allowed: false
|
||||||
|
},
|
||||||
|
timing: Some(applogic::TimingData {
|
||||||
|
min_end_sec: 23,
|
||||||
|
likely_end_sec: Some(24),
|
||||||
|
max_end_sec: Some(42)
|
||||||
|
})
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
|
@ -508,8 +534,9 @@ async fn main(spawner: Spawner) -> ! {
|
||||||
if let applogic::GlosaOutput::Locked(data) = &glosa_data {
|
if let applogic::GlosaOutput::Locked(data) = &glosa_data {
|
||||||
for sig in &data.signal_groups {
|
for sig in &data.signal_groups {
|
||||||
let duration_str = sig
|
let duration_str = sig
|
||||||
.end_sec
|
.timing
|
||||||
.map(|v| alloc::format!("for {v} s"))
|
.as_ref()
|
||||||
|
.map(|v| alloc::format!("for {} s", v.min_end_sec))
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
println!("GLOSA: {} {} {duration_str}", sig.maneuver, sig.phase);
|
println!("GLOSA: {} {} {duration_str}", sig.maneuver, sig.phase);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,8 @@ where
|
||||||
|
|
||||||
const DEFAULT_TEXT_STYLE: mono_font::MonoTextStyle<'static, pixelcolor::Rgb565> =
|
const DEFAULT_TEXT_STYLE: mono_font::MonoTextStyle<'static, pixelcolor::Rgb565> =
|
||||||
mono_font::MonoTextStyle::new(&profont::PROFONT_24_POINT, Self::COLOR_FG);
|
mono_font::MonoTextStyle::new(&profont::PROFONT_24_POINT, Self::COLOR_FG);
|
||||||
|
const MID_TEXT_STYLE: mono_font::MonoTextStyle<'static, pixelcolor::Rgb565> =
|
||||||
|
mono_font::MonoTextStyle::new(&profont::PROFONT_18_POINT, Self::COLOR_FG);
|
||||||
const SMALL_TEXT_STYLE: mono_font::MonoTextStyle<'static, pixelcolor::Rgb565> =
|
const SMALL_TEXT_STYLE: mono_font::MonoTextStyle<'static, pixelcolor::Rgb565> =
|
||||||
mono_font::MonoTextStyle::new(&profont::PROFONT_14_POINT, Self::COLOR_FG);
|
mono_font::MonoTextStyle::new(&profont::PROFONT_14_POINT, Self::COLOR_FG);
|
||||||
|
|
||||||
|
|
@ -169,7 +171,7 @@ where
|
||||||
self.gnss_hb_state
|
self.gnss_hb_state
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: print on screen!
|
// TODO: print on screen?
|
||||||
|
|
||||||
self.gnss_hb_state = !self.gnss_hb_state;
|
self.gnss_hb_state = !self.gnss_hb_state;
|
||||||
|
|
||||||
|
|
@ -324,18 +326,38 @@ where
|
||||||
)
|
)
|
||||||
.draw(&mut self.target)?;
|
.draw(&mut self.target)?;
|
||||||
|
|
||||||
// draw timing indicator
|
// draw timing indicator(s)
|
||||||
if let Some(end_sec) = sig.end_sec {
|
if let Some(timing) = &sig.timing {
|
||||||
text::Text::with_alignment(
|
if let (Some(likely), Some(max)) = (timing.likely_end_sec, timing.max_end_sec) {
|
||||||
&alloc::format!("{end_sec}s"),
|
text::Text::with_alignment(
|
||||||
geometry::Point::new(centerline, 160 + self.size.offset_top),
|
&alloc::format!("{likely}s"),
|
||||||
Self::DEFAULT_TEXT_STYLE,
|
geometry::Point::new(centerline, 160 + self.size.offset_top),
|
||||||
text::Alignment::Center,
|
Self::DEFAULT_TEXT_STYLE,
|
||||||
)
|
text::Alignment::Center,
|
||||||
.draw(&mut self.target)?;
|
)
|
||||||
|
.draw(&mut self.target)?;
|
||||||
|
|
||||||
|
text::Text::with_alignment(
|
||||||
|
&alloc::format!("{}-{max}s", timing.min_end_sec),
|
||||||
|
geometry::Point::new(centerline, 185 + self.size.offset_top),
|
||||||
|
Self::MID_TEXT_STYLE,
|
||||||
|
text::Alignment::Center,
|
||||||
|
)
|
||||||
|
.draw(&mut self.target)?;
|
||||||
|
} else {
|
||||||
|
text::Text::with_alignment(
|
||||||
|
&alloc::format!("{}s", timing.min_end_sec),
|
||||||
|
geometry::Point::new(centerline, 160 + self.size.offset_top),
|
||||||
|
Self::DEFAULT_TEXT_STYLE,
|
||||||
|
text::Alignment::Center,
|
||||||
|
)
|
||||||
|
.draw(&mut self.target)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Add current speed and ETA
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue