Skip to content

Commit

Permalink
Merge pull request #138 from card-io-ecg/context
Browse files Browse the repository at this point in the history
Split up Board and make a mess of it
  • Loading branch information
bugadani committed Oct 16, 2023
2 parents 34cfac9 + 1a96387 commit 16a0a10
Show file tree
Hide file tree
Showing 23 changed files with 472 additions and 511 deletions.
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

0 comments on commit 16a0a10

Please sign in to comment.