Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split up Board and make a mess of it #138

Merged
merged 12 commits into from
Oct 16, 2023
43 changes: 22 additions & 21 deletions gui/examples/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use embedded_graphics_simulator::{
BinaryColorTheme, OutputSettingsBuilder, SimulatorDisplay, SimulatorEvent, Window,
};
use gui::{
screens::{init::StartupScreen, screen::Screen, BatteryInfo, ChargingState},
screens::{init::StartupScreen, BatteryInfo, ChargingState},
widgets::{
battery_small::{Battery, BatteryStyle},
status_bar::StatusBar,
Expand All @@ -31,31 +31,32 @@ fn main() -> Result<(), Infallible> {
'running: loop {
display.clear(BinaryColor::Off).unwrap();

Screen {
content: StartupScreen {
label: "Release to shutdown",
progress: if progress > 255 {
510 - progress
} else {
progress
},
},
status_bar: StatusBar {
battery: Battery::with_style(
Some(BatteryInfo {
voltage: 4100,
percentage: 90,
charging_state: ChargingState::Charging,
is_low: false,
}),
BatteryStyle::Percentage,
),
wifi: WifiStateView::enabled(WifiState::Connected),
StartupScreen {
label: "Release to shutdown",
progress: if progress > 255 {
510 - progress
} else {
progress
},
}
.draw(&mut display)
.unwrap();

StatusBar {
battery: Battery::with_style(
Some(BatteryInfo {
voltage: 4100,
percentage: 90,
charging_state: ChargingState::Charging,
is_low: false,
}),
BatteryStyle::Percentage,
),
wifi: WifiStateView::enabled(WifiState::Connected),
}
.draw(&mut display)
.unwrap();

progress = (progress + 1) % 510;

window.update(&display);
Expand Down
1 change: 0 additions & 1 deletion gui/src/screens/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ pub mod init;
pub mod measure;
pub mod message;
pub mod qr;
pub mod screen;
pub mod wifi_ap;

pub const fn menu_style<R>(
Expand Down
30 changes: 0 additions & 30 deletions gui/src/screens/screen.rs

This file was deleted.

165 changes: 121 additions & 44 deletions src/board/initialized.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
use core::ops::{Deref, DerefMut};

use crate::{
board::{
config::Config,
drivers::battery_monitor::BatteryMonitor,
hal::clock::Clocks,
storage::FileSystem,
wifi::{ap::Ap, sta::Sta, WifiDriver},
wifi::{ap::Ap, sta::Sta, GenericConnectionState, WifiDriver},
ChargerStatus, EcgFrontend, PoweredDisplay, VbusDetect,
},
saved_measurement_exists,
states::MESSAGE_MIN_DURATION,
};
use display_interface::DisplayError;
use embassy_executor::SendSpawner;
use embassy_net::{Config as NetConfig, Ipv4Address, Ipv4Cidr, StaticConfigV4};
use embassy_time::Instant;
use embassy_time::{Duration, Instant, Timer};
use embedded_graphics::{pixelcolor::BinaryColor, prelude::DrawTarget, Drawable};
use gui::{
screens::message::MessageScreen,
widgets::{
battery_small::Battery,
status_bar::StatusBar,
wifi::{WifiState, WifiStateView},
},
};
use norfs::OnCollision;

#[derive(Debug, Clone, Copy, PartialEq)]
Expand All @@ -20,21 +33,39 @@ pub enum StaMode {
OnDemand,
}

pub struct Board {
pub struct InnerContext {
pub display: PoweredDisplay,
pub frontend: EcgFrontend,
pub clocks: Clocks<'static>,
pub high_prio_spawner: SendSpawner,
pub battery_monitor: BatteryMonitor<VbusDetect, ChargerStatus>,
pub wifi: &'static mut WifiDriver,
pub config: &'static mut Config,
pub config_changed: bool,
pub storage: Option<FileSystem>,
pub sta_work_available: Option<bool>,
pub message_displayed_at: Option<Instant>,
}

impl Board {
pub struct Context {
pub frontend: EcgFrontend,
pub storage: Option<FileSystem>,
pub inner: InnerContext,
}

impl Deref for Context {
type Target = InnerContext;

fn deref(&self) -> &Self::Target {
&self.inner
}
}

impl DerefMut for Context {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}

impl Context {
pub async fn save_config(&mut self) {
if !self.config_changed {
return;
Expand All @@ -45,7 +76,7 @@ impl Board {

if let Some(storage) = self.storage.as_mut() {
if let Err(e) = storage
.store_writer("config", self.config, OnCollision::Overwrite)
.store_writer("config", self.inner.config, OnCollision::Overwrite)
.await
{
error!("Failed to save config: {:?}", e);
Expand All @@ -55,21 +86,21 @@ impl Board {
}
}

async fn enable_sta(&mut self, can_enable: bool) -> Option<Sta> {
if !can_enable {
warn!("Not enabling STA");
self.wifi.stop_if().await;
return None;
}

let sta = self
.wifi
.configure_sta(NetConfig::dhcpv4(Default::default()), &self.clocks)
.await;
pub async fn sta_has_work(&mut self) -> bool {
// TODO: we can do a flag that is true on boot, so that entering the menu will always
// connect and look for update, etc. We can also use a flag to see if we have ongoing
// communication, so we can keep wifi on. Question is: when/how do we disable wifi if
// it is in on-demand mode?

sta.update_known_networks(&self.config.known_networks).await;
if self.inner.sta_work_available.is_none() {
if let Some(storage) = self.storage.as_mut() {
if saved_measurement_exists(storage).await {
self.inner.sta_work_available = Some(true);
}
}
}

Some(sta)
self.inner.sta_work_available.unwrap_or(false)
}

pub async fn enable_wifi_sta(&mut self, mode: StaMode) -> Option<Sta> {
Expand All @@ -90,6 +121,62 @@ impl Board {

self.enable_sta(can_enable).await
}
}

impl InnerContext {
pub async fn apply_hw_config_changes(&mut self) {
if !self.config_changed {
return;
}

let brightness = self.config.display_brightness();
let _ = self.display.update_brightness_async(brightness).await;
}

pub async fn with_status_bar(
&mut self,
draw: impl FnOnce(&mut PoweredDisplay) -> Result<(), DisplayError>,
) {
unwrap!(self.display.clear(BinaryColor::Off).ok());

let status_bar = self.status_bar();
unwrap!(status_bar.draw(&mut self.display).ok());
unwrap!(draw(&mut self.display).ok());

unwrap!(self.display.flush().await.ok());
}

pub async fn wait_for_message(&mut self, duration: Duration) {
if let Some(message_at) = self.message_displayed_at.take() {
Timer::at(message_at + duration).await;
}
}

pub async fn display_message(&mut self, message: &str) {
self.wait_for_message(MESSAGE_MIN_DURATION).await;
self.message_displayed_at = Some(Instant::now());

info!("Displaying message: {}", message);
self.with_status_bar(|display| MessageScreen { message }.draw(display))
.await;
}

async fn enable_sta(&mut self, can_enable: bool) -> Option<Sta> {
if !can_enable {
warn!("Not enabling STA");
self.wifi.stop_if().await;
return None;
}

let sta = self
.wifi
.configure_sta(NetConfig::dhcpv4(Default::default()), &self.clocks)
.await;

sta.update_known_networks(&self.config.known_networks).await;

Some(sta)
}

pub async fn enable_wifi_ap(&mut self) -> Option<Ap> {
if !self.can_enable_wifi() {
Expand Down Expand Up @@ -124,34 +211,10 @@ impl Board {
.unwrap_or(false)
}

pub async fn sta_has_work(&mut self) -> bool {
// TODO: we can do a flag that is true on boot, so that entering the menu will always
// connect and look for update, etc. We can also use a flag to see if we have ongoing
// communication, so we can keep wifi on. Question is: when/how do we disable wifi if
// it is in on-demand mode?

if self.sta_work_available.is_none() {
if let Some(storage) = self.storage.as_mut() {
if saved_measurement_exists(storage).await {
self.sta_work_available = Some(true);
}
}
}

self.sta_work_available.unwrap_or(false)
}

pub fn signal_sta_work_available(&mut self, available: bool) {
self.sta_work_available = Some(available);
}

pub async fn apply_hw_config_changes(&mut self) {
let _ = self
.display
.update_brightness_async(self.config.display_brightness())
.await;
}

pub fn update_config(&mut self, cb: impl FnOnce(&mut Config)) {
struct ConfigWriter<'a> {
config: &'a mut Config,
Expand Down Expand Up @@ -181,4 +244,18 @@ impl Board {

self.config_changed |= wrapper.changed;
}

pub fn status_bar(&mut self) -> StatusBar {
let battery_data = self.battery_monitor.battery_data();
let connection_state = match self.wifi.connection_state() {
GenericConnectionState::Sta(state) => Some(WifiState::from(state)),
GenericConnectionState::Ap(state) => Some(WifiState::from(state)),
GenericConnectionState::Disabled => None,
};

StatusBar {
battery: Battery::with_style(battery_data, self.config.battery_style()),
wifi: WifiStateView::new(connection_state),
}
}
}
7 changes: 3 additions & 4 deletions src/board/wifi/sta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ use core::{alloc::AllocError, ptr::addr_of, sync::atomic::Ordering};
use crate::{
board::{
hal::{radio::Wifi, Rng},
initialized::Board,
initialized::Context,
wifi::{net_task, StackWrapper},
},
states::display_message,
task_control::{TaskControlToken, TaskController},
timeout::Timeout,
Shared,
Expand Down Expand Up @@ -151,7 +150,7 @@ impl Sta {
self.state.wait().await.into()
}

pub async fn wait_for_connection(&self, board: &mut Board) -> bool {
pub async fn wait_for_connection(&self, context: &mut Context) -> bool {
if self.connection_state() != ConnectionState::Connected {
debug!("Waiting for network connection");

Expand All @@ -174,7 +173,7 @@ impl Sta {
async {
loop {
// A message is displayed for at least 300ms so we don't need to wait here.
display_message(board, "Connecting...").await;
context.display_message("Connecting...").await;
}
},
)
Expand Down
Loading