diff --git a/services/gam/src/contexts.rs b/services/gam/src/contexts.rs index c45bc1241..b50647c3d 100644 --- a/services/gam/src/contexts.rs +++ b/services/gam/src/contexts.rs @@ -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; @@ -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) { diff --git a/services/gam/src/layouts/modal.rs b/services/gam/src/layouts/modal.rs index 76b0803b0..1c432743c 100644 --- a/services/gam/src/layouts/modal.rs +++ b/services/gam/src/layouts/modal.rs @@ -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 { diff --git a/services/graphics-server/src/api.rs b/services/graphics-server/src/api.rs index b83abe479..9fc8232c5 100644 --- a/services/graphics-server/src/api.rs +++ b/services/graphics-server/src/api.rs @@ -119,6 +119,9 @@ pub(crate) enum Opcode { /// SuspendResume callback SuspendResume, + /// draw the boot logo (for continuity as apps initialize) + DrawBootLogo, + Quit, } diff --git a/services/graphics-server/src/backend/betrusted.rs b/services/graphics-server/src/backend/betrusted.rs index fe0125510..120c87571 100644 --- a/services/graphics-server/src/backend/betrusted.rs +++ b/services/graphics-server/src/backend/betrusted.rs @@ -68,7 +68,6 @@ impl XousDisplay { display .susres .push(RegOrField::Field(utra::memlcd::PRESCALER_PRESCALER), None); - display.sync_clear(); /* use log::{error, info}; @@ -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 { @@ -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 diff --git a/services/graphics-server/src/lib.rs b/services/graphics-server/src/lib.rs index f895b230c..e98db6bbc 100644 --- a/services/graphics-server/src/lib.rs +++ b/services/graphics-server/src/lib.rs @@ -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 { let response = send_message( self.conn, diff --git a/services/graphics-server/src/main.rs b/services/graphics-server/src/main.rs index 00029f6cc..a0bb3181f 100644 --- a/services/graphics-server/src/main.rs +++ b/services/graphics-server/src/main.rs @@ -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, @@ -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(); @@ -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); diff --git a/services/pddb/locales/i18n.json b/services/pddb/locales/i18n.json index f24517070..d7d59450e 100644 --- a/services/pddb/locales/i18n.json +++ b/services/pddb/locales/i18n.json @@ -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", diff --git a/services/pddb/src/main.rs b/services/pddb/src/main.rs index 4e4944e70..6e8773aee 100644 --- a/services/pddb/src/main.rs +++ b/services/pddb/src/main.rs @@ -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 { @@ -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 diff --git a/services/shellchat/locales/i18n.json b/services/shellchat/locales/i18n.json index 7560abb66..8854bab5d 100644 --- a/services/shellchat/locales/i18n.json +++ b/services/shellchat/locales/i18n.json @@ -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": "请稍等..." } } diff --git a/services/shellchat/src/main.rs b/services/shellchat/src/main.rs index 85e5d5bc6..061d31fc3 100644 --- a/services/shellchat/src/main.rs +++ b/services/shellchat/src/main.rs @@ -32,6 +32,7 @@ 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}; @@ -39,6 +40,10 @@ 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::*; @@ -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 { @@ -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; @@ -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 { @@ -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; @@ -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"); @@ -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, _, _, _, { @@ -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"); diff --git a/services/status/src/main.rs b/services/status/src/main.rs index ec77fb239..b9c592242 100644 --- a/services/status/src/main.rs +++ b/services/status/src/main.rs @@ -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();