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

feat: show boot process notifications for PDDB #270

Merged
merged 8 commits into from
Nov 5, 2022
2 changes: 2 additions & 0 deletions services/gam/src/contexts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ impl ContextManager {
token: [u32; 4],
clear: bool,
) -> Result<(), xous::Error> {
//log::set_max_level(log::LevelFilter::Trace);
self.notify_app_switch(token).ok();

let mut leaving_visibility: bool = false;
Expand Down Expand Up @@ -483,6 +484,7 @@ impl ContextManager {
self.redraw().expect("couldn't redraw the currently focused app");
}
}
//log::set_max_level(log::LevelFilter::Info);
Ok(())
}
pub(crate) fn set_pred_api_token(&mut self, at: ApiToken) {
Expand Down
2 changes: 1 addition & 1 deletion services/gam/src/layouts/modal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use graphics_server::*;
use crate::{LayoutApi, LayoutBehavior};

use crate::contexts::MISC_CONTEXT_DEFAULT_TRUST;
const TRUST_OFFSET: u8 = 1;
const TRUST_OFFSET: u8 = 16;

#[derive(Debug, Copy, Clone)]
pub(crate) struct ModalLayout {
Expand Down
3 changes: 3 additions & 0 deletions services/graphics-server/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ pub(crate) enum Opcode {
/// SuspendResume callback
SuspendResume,

/// draw the boot logo (for continuity as apps initialize)
DrawBootLogo,

Quit,
}

Expand Down
3 changes: 2 additions & 1 deletion services/graphics-server/src/backend/betrusted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ impl XousDisplay {
display
.susres
.push(RegOrField::Field(utra::memlcd::PRESCALER_PRESCALER), None);
display.sync_clear();

/*
use log::{error, info};
Expand Down Expand Up @@ -255,6 +254,7 @@ impl XousDisplay {

/// "synchronous clear" -- must be called on init, so that the state of the LCD
/// internal memory is consistent with the state of the frame buffer
/*
fn sync_clear(&mut self) {
let framebuffer = self.fb.as_mut_ptr() as *mut u32;
for words in 0..FB_SIZE {
Expand All @@ -267,6 +267,7 @@ impl XousDisplay {
self.update_all(); // because we force an all update here
while self.busy() {}
}
*/

fn busy(&self) -> bool {
self.csr.rf(utra::memlcd::BUSY_BUSY) == 1
Expand Down
8 changes: 8 additions & 0 deletions services/graphics-server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,14 @@ impl Gfx {
.map(|_| ())
}

pub fn draw_boot_logo(&self) -> Result<(), xous::Error> {
send_message(
self.conn,
Message::new_scalar(Opcode::DrawBootLogo.to_usize().unwrap(), 0, 0, 0, 0),
)
.map(|_| ())
}

pub fn screen_size(&self) -> Result<Point, xous::Error> {
let response = send_message(
self.conn,
Expand Down
8 changes: 6 additions & 2 deletions services/graphics-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ fn wrapped_main() -> ! {
log::info!("my PID is {}", xous::process::id());

let mut display = XousDisplay::new();
draw_boot_logo(&mut display); // bring this up as soon as possible
let fontregion = map_fonts();

// install the graphical panic handler. It won't catch really early panics, or panics in this crate,
Expand Down Expand Up @@ -139,8 +140,6 @@ fn wrapped_main() -> ! {
.register_name(api::SERVER_NAME_GFX, Some(1))
.expect("can't register server");

draw_boot_logo(&mut display);

let screen_clip = Rectangle::new(Point::new(0, 0), display.screen_size());

display.redraw();
Expand Down Expand Up @@ -459,6 +458,11 @@ fn wrapped_main() -> ! {
display.update();
display.redraw();
}),
Some(Opcode::DrawBootLogo) => msg_scalar_unpack!(msg, _, _, _, _, {
display.blit_screen(&poweron::LOGO_MAP);
display.update();
display.redraw();
}),
Some(Opcode::Devboot) => msg_scalar_unpack!(msg, ena, _, _, _, {
if ena != 0 {
display.set_devboot(true);
Expand Down
7 changes: 7 additions & 0 deletions services/pddb/locales/i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@
"ja": "パスワードを認証失敗でした。\n\nもう一度実行しください。",
"zh": "密码错误。"
},
"pddb.waitmount": {
"en": "Mounting PDDB, please wait...",
"en-tts": "Mounting PDDB, please wait...",
"fr": "Montage de PDDB, veuillez patienter...*MT*",
"ja": "PDDB をマウントしています。お待ちください...",
"zh": "正在挂载 PDDB,请稍候..."
},
"pddb.basisname": {
"en": "Basis Name:",
"en-tts": "Enter name of Basis",
Expand Down
7 changes: 6 additions & 1 deletion services/pddb/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1927,11 +1927,14 @@ fn ensure_password(modals: &modals::Modals, pddb_os: &mut PddbOs, _pw_cid: xous:
fn try_mount_or_format(modals: &modals::Modals, pddb_os: &mut PddbOs, basis_cache: &mut BasisCache, pw_state: PasswordState, time_resetter: xous::CID) -> bool {
log::info!("Attempting to mount the PDDB");
if pw_state == PasswordState::Correct {
modals.dynamic_notification(Some(t!("pddb.waitmount", xous::LANG)), None).unwrap();
if let Some(sys_basis) = pddb_os.pddb_mount() {
log::info!("PDDB mount operation finished successfully");
basis_cache.basis_add(sys_basis);
modals.dynamic_notification_close().unwrap();
return true
}
modals.dynamic_notification_close().unwrap();
}
// correct password but no mount -> offer to format; uninit -> offer to format
if pw_state == PasswordState::Correct || pw_state == PasswordState::Uninit {
Expand Down Expand Up @@ -1988,12 +1991,14 @@ fn try_mount_or_format(modals: &modals::Modals, pddb_os: &mut PddbOs, basis_cach
0, 0, 0, 0
)
).expect("couldn't reset time");

modals.dynamic_notification(Some(t!("pddb.waitmount", xous::LANG)), None).unwrap();
if let Some(sys_basis) = pddb_os.pddb_mount() {
log::info!("PDDB mount operation finished successfully");
basis_cache.basis_add(sys_basis);
modals.dynamic_notification_close().unwrap();
true
} else {
modals.dynamic_notification_close().unwrap();
log::error!("Despite formatting, no PDDB was found!");
let mut err = String::from(t!("pddb.internalerror", xous::LANG));
err.push_str(" #1"); // punt and leave an error code, because this "should" be rare
Expand Down
7 changes: 7 additions & 0 deletions services/shellchat/locales/i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,12 @@
"fr": "",
"ja": "",
"zh": ""
},
"shellchat.bootwait": {
"en": "Please wait...",
"en-tts": "Please wait...",
"fr": "S'il vous plaît, attendez*MT*",
"ja": "お待ちください...",
"zh": "请稍等..."
}
}
86 changes: 79 additions & 7 deletions services/shellchat/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,18 @@ Check for more detailed docs under Modules/cmds "Shell Chat" below
use log::info;

use core::fmt::Write;
use core::sync::atomic::{AtomicBool, Ordering};

use gam::UxRegistration;
use graphics_server::{Gid, Point, Rectangle, TextBounds, TextView, DrawStyle, PixelColor};
use graphics_server::api::GlyphStyle;
use xous::MessageEnvelope;
use xous_ipc::Buffer;

use locales::t;
use std::thread;
use std::sync::Arc;

#[doc = include_str!("../README.md")]
mod cmds;
use cmds::*;
Expand Down Expand Up @@ -202,7 +207,7 @@ impl Repl{
}

/// update the loop, in response to various inputs
fn update(&mut self, was_callback: bool) -> Result<(), xous::Error> {
fn update(&mut self, was_callback: bool, init_done: bool) -> Result<(), xous::Error> {
let debug1 = false;
// if we had an input string, do something
if let Some(local) = &self.input {
Expand All @@ -219,7 +224,7 @@ impl Repl{

// redraw UI once upon accepting all input
if !was_callback { // don't need to redraw on a callback, save some cycles
self.redraw().expect("can't redraw");
self.redraw(init_done).expect("can't redraw");
}

let mut dirty = true;
Expand Down Expand Up @@ -265,7 +270,7 @@ impl Repl{
self.msg = None;
// redraw UI now that we've responded
if dirty {
self.redraw().expect("can't redraw");
self.redraw(init_done).expect("can't redraw");
}

if debug1 {
Expand All @@ -286,10 +291,28 @@ impl Repl{
}
)).expect("can't clear content area");
}
fn redraw(&mut self) -> Result<(), xous::Error> {
fn redraw(&mut self, init_done: bool) -> Result<(), xous::Error> {
log::trace!("going into redraw");
self.clear_area();

if !init_done {
let mut init_tv = TextView::new(
self.content,
TextBounds::CenteredTop(
Rectangle::new(
Point::new(0, self.screensize.y / 3 - 64),
Point::new(self.screensize.x, self.screensize.y / 3)
)
)
);
init_tv.style = GlyphStyle::Bold;
init_tv.draw_border = false;
write!(init_tv.text, "{}", t!("shellchat.bootwait", xous::LANG)).ok();
self.gam.post_textview(&mut init_tv).expect("couldn't render wait text");
self.gam.redraw().expect("couldn't redraw screen");
return Ok(())
}

// this defines the bottom border of the text bubbles as they stack up wards
let mut bubble_baseline = self.screensize.y - self.margin.y;

Expand Down Expand Up @@ -393,8 +416,57 @@ fn wrapped_main() -> ! {
let mut was_callback = false;

let mut allow_redraw = true;
log::trace!("starting main loop");
let pddb_init_done = Arc::new(AtomicBool::new(false));

// spawn a thread to auto-mount the PDDB. It's important that this spawn happens after
// our GAM context has been registered (which happened in the `Repl::new()` call above)
repl.redraw(false).ok();
let _ = thread::spawn({
let pddb_init_done = pddb_init_done.clone();
let main_conn = xous::connect(shch_sid).unwrap();
move || {
let tt = ticktimer_server::Ticktimer::new().unwrap();
let xns = xous_names::XousNames::new().unwrap();
let gam = gam::Gam::new(&xns).unwrap();
while !gam.trusted_init_done().unwrap() {
tt.sleep_ms(50).ok();
}
loop {
let (no_retry_failure, count) = pddb::Pddb::new().try_mount();
pddb_init_done.store(true, Ordering::SeqCst);
if no_retry_failure {
// this includes both successfully mounted, and user abort of mount attempt
break;
} else {
// this indicates system was guttered due to a retry failure
let xns = xous_names::XousNames::new().unwrap();
let susres = susres::Susres::new_without_hook(&xns).unwrap();
let llio = llio::Llio::new(&xns);
if ((llio.adc_vbus().unwrap() as u32) * 503) < 150_000 {
// try to force suspend if possible, so that users who are just playing around with
// the device don't run the battery down accidentally.
susres.initiate_suspend().ok();
tt.sleep_ms(1000).unwrap();
let modals = modals::Modals::new(&xns).unwrap();
modals.show_notification(
&t!("login.fail", xous::LANG).replace("{fails}", &count.to_string()),
None
).ok();
} else {
// otherwise force a reboot cycle to slow down guessers
susres.reboot(true).expect("Couldn't reboot after too many failed password attempts");
tt.sleep_ms(5000).unwrap();
}
}
}
tt.sleep_ms(100).ok(); // this allows the shellchat context to foreground before calling the redraw
xous::send_message(main_conn,
xous::Message::new_scalar(ShellOpcode::Redraw.to_usize().unwrap(), 0, 0, 0, 0)
).ok();
}
});

log::trace!("starting main loop");
#[cfg(feature = "autobasis-ci")]
{
log::info!("starting autobasis CI launcher");
Expand All @@ -420,7 +492,7 @@ fn wrapped_main() -> ! {
}
Some(ShellOpcode::Redraw) => {
if allow_redraw {
repl.redraw().expect("REPL couldn't redraw");
repl.redraw(pddb_init_done.load(Ordering::SeqCst)).expect("REPL couldn't redraw");
}
}
Some(ShellOpcode::ChangeFocus) => xous::msg_scalar_unpack!(msg, new_state_code, _, _, _, {
Expand All @@ -446,7 +518,7 @@ fn wrapped_main() -> ! {
}
}
if update_repl {
repl.update(was_callback).expect("REPL had problems updating");
repl.update(was_callback, pddb_init_done.load(Ordering::SeqCst)).expect("REPL had problems updating");
update_repl = false;
}
log::trace!("reached bottom of main loop");
Expand Down
35 changes: 0 additions & 35 deletions services/status/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -633,41 +633,6 @@ fn wrapped_main() -> ! {
#[cfg(any(feature="precursor", feature="renode"))]
llio.clear_wakeup_alarm().unwrap(); // this is here to clear any wake-up alarms that were set by a prior coldboot command

// spawn a thread to auto-mount the PDDB
let _ = thread::spawn({
move || {
let tt = ticktimer_server::Ticktimer::new().unwrap();
tt.sleep_ms(2000).unwrap(); // a brief pause, to allow the other startup bits to finish running
loop {
let (no_retry_failure, count) = pddb::Pddb::new().try_mount();
if no_retry_failure {
// this includes both successfully mounted, and user abort of mount attempt
break;
} else {
// this indicates system was guttered due to a retry failure
let xns = xous_names::XousNames::new().unwrap();
let susres = susres::Susres::new_without_hook(&xns).unwrap();
let llio = llio::Llio::new(&xns);
if ((llio.adc_vbus().unwrap() as u32) * 503) < 150_000 {
// try to force suspend if possible, so that users who are just playing around with
// the device don't run the battery down accidentally.
susres.initiate_suspend().ok();
tt.sleep_ms(1000).unwrap();
let modals = modals::Modals::new(&xns).unwrap();
modals.show_notification(
&t!("login.fail", xous::LANG).replace("{fails}", &count.to_string()),
None
).ok();
} else {
// otherwise force a reboot cycle to slow down guessers
susres.reboot(true).expect("Couldn't reboot after too many failed password attempts");
tt.sleep_ms(5000).unwrap();
}
}
}
}
});

pump_run.store(true, Ordering::Relaxed); // start status thread updating
loop {
let msg = xous::receive_message(status_sid).unwrap();
Expand Down