diff --git a/apps/ball/src/main.rs b/apps/ball/src/main.rs index 1f4b203e7..99857dfba 100644 --- a/apps/ball/src/main.rs +++ b/apps/ball/src/main.rs @@ -81,7 +81,6 @@ fn xmain() -> ! { }), Some(AppOp::FocusChange) => xous::msg_scalar_unpack!(msg, new_state_code, _, _, _, { let new_state = gam::FocusState::convert_focus_change(new_state_code); - log::info!("got focus change with new state: {:?}", new_state); match new_state { gam::FocusState::Background => { allow_redraw = false; // this instantly terminates future updates, even if Pump messages are in our input queue diff --git a/apps/repl/locales/i18n.json b/apps/repl/locales/i18n.json index c43e12d9d..1ae2ad0cc 100644 --- a/apps/repl/locales/i18n.json +++ b/apps/repl/locales/i18n.json @@ -1,4 +1,14 @@ { + "replapp.greeting": { + "en": "Welcome to the simple REPL demo.", + "zh": "简单的 repl 演示活动", + "en-audio": "Welcome to the simple REPL demo." + }, + "replapp.beep.start": { + "en": "beep started...", + "zh": "哔声开始...", + "en-audio": "beep started..." + }, "replapp.beep.help": { "en": "beep [tone [freq [duration]]]", "zh": "beep [tone [音频 [时长]]]", diff --git a/apps/repl/src/cmds.rs b/apps/repl/src/cmds.rs index 5abbca064..ecfcaa12b 100644 --- a/apps/repl/src/cmds.rs +++ b/apps/repl/src/cmds.rs @@ -89,6 +89,7 @@ pub struct CmdEnv { impl CmdEnv { pub fn new(xns: &xous_names::XousNames) -> CmdEnv { let ticktimer = ticktimer_server::Ticktimer::new().expect("Couldn't connect to Ticktimer"); + log::info!("creating CommonEnv"); let common = CommonEnv { llio: llio::Llio::new(&xns), com: com::Com::new(&xns).expect("could't connect to COM"), @@ -99,7 +100,7 @@ impl CmdEnv { trng: Trng::new(&xns).unwrap(), xns: xous_names::XousNames::new().unwrap(), }; - + log::info!("done creating CommonEnv"); CmdEnv { common_env: common, lastverb: String::<256>::new(), diff --git a/apps/repl/src/cmds/beep.rs b/apps/repl/src/cmds/beep.rs index d8e59d68f..bbab40d60 100644 --- a/apps/repl/src/cmds/beep.rs +++ b/apps/repl/src/cmds/beep.rs @@ -15,8 +15,9 @@ pub struct Beep { } impl Beep { pub fn new(xns: &xous_names::XousNames) -> Self { + log::info!("initializing beep"); let callback_conn = xns.request_connection_blocking(crate::SERVER_NAME_REPL).unwrap(); - + log::info!("beep init returning"); Beep { callback_id: None, callback_conn, @@ -27,6 +28,7 @@ impl Beep { } } +const STOP_ID: usize = 1; const SAMPLE_RATE_HZ: f32 = 8000.0; // note to self: A4 = 440.0, E4 = 329.63, C4 = 261.63 @@ -75,17 +77,18 @@ impl<'a> ShellCmdApi<'a> for Beep { env.codec.resume().unwrap(); - env.ticktimer.sleep_ms((duration * 1000.0) as usize).unwrap(); - - env.codec.pause().unwrap(); // this should stop callbacks from occurring too. - write!(ret, "{} {} {}.", - t!("replapp.beep.completion_a", xous::LANG), - self.framecount, - t!("replapp.beep.completion_b", xous::LANG), - ).unwrap(); - self.framecount = 0; - self.play_sample = 0.0; - env.codec.power_off().unwrap(); + // kick off a thread that stops the playback, after the designated delay + std::thread::spawn({ + let cb_id = self.callback_id.unwrap().clone(); + let conn = self.callback_conn.clone(); + let duration = duration.clone(); + move || { + let ticktimer = ticktimer_server::Ticktimer::new().unwrap(); + ticktimer.sleep_ms((duration * 1000.0) as usize).unwrap(); + xous::send_message(conn, Message::new_scalar(cb_id as usize, 0, 0, 0, STOP_ID)).unwrap(); + } + }); + write!(ret, "{}", t!("replapp.beep.start", xous::LANG)).unwrap(); } _ => { write!(ret, "{}", helpstring).unwrap(); @@ -100,32 +103,46 @@ impl<'a> ShellCmdApi<'a> for Beep { const AMPLITUDE: f32 = 0.8; match &msg.body { - Message::Scalar(xous::ScalarMessage{id: _, arg1: free_play, arg2: _avail_rec, arg3: _, arg4: _}) => { - let mut frames: FrameRing = FrameRing::new(); - let frames_to_push = if frames.writeable_count() < *free_play { - frames.writeable_count() - } else { - *free_play - }; - self.framecount += frames_to_push as u32; + Message::Scalar(xous::ScalarMessage{id: _, arg1: free_play, arg2: _avail_rec, arg3: _, arg4: routing_id}) => { + if *routing_id == codec::AUDIO_CB_ROUTING_ID { + let mut frames: FrameRing = FrameRing::new(); + let frames_to_push = if frames.writeable_count() < *free_play { + frames.writeable_count() + } else { + *free_play + }; + self.framecount += frames_to_push as u32; + + log::debug!("f{} p{}", self.framecount, frames_to_push); + for _ in 0..frames_to_push { + let mut frame: [u32; codec::FIFO_DEPTH] = [ZERO_PCM as u32 | (ZERO_PCM as u32) << 16; codec::FIFO_DEPTH]; + // put the "expensive" f32 comparison outside the cosine wave table computation loop + let omega = self.freq * 2.0 * std::f32::consts::PI / SAMPLE_RATE_HZ; + for sample in frame.iter_mut() { + let raw_sine: i16 = (AMPLITUDE * f32::cos( self.play_sample * omega ) * i16::MAX as f32) as i16; + let left = raw_sine as u16; + let right = raw_sine as u16; + *sample = right as u32 | (left as u32) << 16; + self.play_sample += 1.0; + } + + frames.nq_frame(frame).unwrap(); - log::debug!("f{} p{}", self.framecount, frames_to_push); - for _ in 0..frames_to_push { - let mut frame: [u32; codec::FIFO_DEPTH] = [ZERO_PCM as u32 | (ZERO_PCM as u32) << 16; codec::FIFO_DEPTH]; - // put the "expensive" f32 comparison outside the cosine wave table computation loop - let omega = self.freq * 2.0 * std::f32::consts::PI / SAMPLE_RATE_HZ; - for sample in frame.iter_mut() { - let raw_sine: i16 = (AMPLITUDE * f32::cos( self.play_sample * omega ) * i16::MAX as f32) as i16; - let left = raw_sine as u16; - let right = raw_sine as u16; - *sample = right as u32 | (left as u32) << 16; - self.play_sample += 1.0; } - - frames.nq_frame(frame).unwrap(); - + env.codec.swap_frames(&mut frames).unwrap(); + } else if *routing_id == STOP_ID { + let mut ret = String::<1024>::new(); + env.codec.pause().unwrap(); // this should stop callbacks from occurring too. + write!(ret, "{} {} {}.", + t!("replapp.beep.completion_a", xous::LANG), + self.framecount, + t!("replapp.beep.completion_b", xous::LANG), + ).unwrap(); + self.framecount = 0; + self.play_sample = 0.0; + env.codec.power_off().unwrap(); + return Ok(Some(ret)); } - env.codec.swap_frames(&mut frames).unwrap(); }, Message::Move(_mm) => { log::error!("received memory message when not expected") diff --git a/apps/repl/src/main.rs b/apps/repl/src/main.rs index b3949da61..e205cfd32 100644 --- a/apps/repl/src/main.rs +++ b/apps/repl/src/main.rs @@ -14,6 +14,8 @@ pub(crate) enum ReplOp { Line = 0, // make sure we occupy opcodes with discriminants < 1000, as the rest are used for callbacks /// redraw our UI Redraw, + /// change focus + ChangeFocus, /// exit the application Quit, } @@ -29,12 +31,13 @@ fn xmain() -> ! { let xns = xous_names::XousNames::new().unwrap(); // unlimited connections allowed, this is a user app and it's up to the app to decide its policy let sid = xns.register_name(SERVER_NAME_REPL, None).expect("can't register server"); - //log::trace!("registered with NS -- {:?}", sid); + log::trace!("registered with NS -- {:?}", sid); let mut repl = Repl::new(&xns, sid); - let mut update_repl = false; + let mut update_repl = true; let mut was_callback = false; - + let mut allow_redraw = false; + log::trace!("entering main loop"); loop { let msg = xous::receive_message(sid).unwrap(); log::debug!("got message {:?}", msg); @@ -48,9 +51,22 @@ fn xmain() -> ! { was_callback = false; } Some(ReplOp::Redraw) => { - log::trace!("got Redraw"); - repl.redraw().expect("REPL couldn't redraw"); + if allow_redraw { + repl.redraw().expect("REPL couldn't redraw"); + } } + Some(ReplOp::ChangeFocus) => xous::msg_scalar_unpack!(msg, new_state_code, _, _, _, { + let new_state = gam::FocusState::convert_focus_change(new_state_code); + match new_state { + gam::FocusState::Background => { + allow_redraw = false; + } + gam::FocusState::Foreground => { + allow_redraw = true; + update_repl = true; + } + } + }), Some(ReplOp::Quit) => { log::error!("got Quit"); break; diff --git a/apps/repl/src/repl.rs b/apps/repl/src/repl.rs index e0b9b69be..ac22b5412 100644 --- a/apps/repl/src/repl.rs +++ b/apps/repl/src/repl.rs @@ -4,6 +4,7 @@ use graphics_server::{Gid, Point, Rectangle, TextBounds, TextView, DrawStyle, Pi use graphics_server::api::GlyphStyle; use xous::MessageEnvelope; use core::fmt::Write; +use locales::t; #[derive(Debug)] struct History { @@ -54,7 +55,7 @@ impl Repl{ gotinput_id: Some(ReplOp::Line.to_u32().unwrap()), audioframe_id: None, rawkeys_id: None, - focuschange_id: None, // repl will keep running in the background even if it has lost focus + focuschange_id: Some(ReplOp::Redraw.to_u32().unwrap()), }).expect("couldn't register Ux context for repl"); let content = gam.request_content_canvas(token.unwrap()).expect("couldn't get content canvas"); @@ -62,7 +63,7 @@ impl Repl{ Repl { input: None, msg: None, - history: Vec::new(), + history: vec![History{text: String::from(t!("replapp.greeting", xous::LANG)), is_input: false}], history_len: 10, content, gam, @@ -208,7 +209,6 @@ impl Repl{ } } self.gam.redraw().expect("couldn't redraw screen"); - // self.gam.request_ime_redraw().expect("couldn't redraw the IME area"); Ok(()) } } \ No newline at end of file diff --git a/services/codec/src/lib.rs b/services/codec/src/lib.rs index 027fb2cbb..7f66d91f1 100644 --- a/services/codec/src/lib.rs +++ b/services/codec/src/lib.rs @@ -6,6 +6,8 @@ use num_traits::{ToPrimitive, FromPrimitive}; use xous_ipc::Buffer; pub use api::*; +/// This is a keyword reserved for the "arg4" slot of a scalar callback, where args are numbered 1-4. +pub const AUDIO_CB_ROUTING_ID: usize = 0; #[derive(Debug)] pub struct Codec { conn: CID, @@ -145,7 +147,7 @@ fn frame_cb_server(sid0: usize, sid1: usize, sid2: usize, sid3: usize) { Some(EventCallback::Event) => xous::msg_scalar_unpack!(msg, cid, id, free_play, avail_rec, { // directly pass the scalar message onto the CID with the ID memorized in the original hook send_message(cid as u32, - Message::new_scalar(id, free_play, avail_rec, 0, 0) + Message::new_scalar(id, free_play, avail_rec, 0, AUDIO_CB_ROUTING_ID) ).unwrap(); }), Some(EventCallback::Drop) => { diff --git a/services/gam/src/contexts.rs b/services/gam/src/contexts.rs index b417da3f6..133726103 100644 --- a/services/gam/src/contexts.rs +++ b/services/gam/src/contexts.rs @@ -323,6 +323,7 @@ impl ContextManager { None }; let maybe_new_focus = self.get_context_by_token_mut(token); + log::trace!("resolving visibility rules"); if let Some(context) = maybe_new_focus { if let Some(leaving_focused_context) = maybe_leaving_focused_context { if token != leaving_focused_context.app_token { @@ -355,6 +356,7 @@ impl ContextManager { } } } + log::trace!("hiding old context"); { // let all the previous operations go out of scope, so we can "check out" the old copy and modify it if self.focused_context.is_some() { @@ -367,6 +369,7 @@ impl ContextManager { } } } + log::trace!("rewiring IMEF and recomputing canvases"); { // now re-check-out the new context and finalize things let maybe_new_focus = self.get_context_by_token(token); @@ -404,6 +407,7 @@ impl ContextManager { *canvases = recompute_canvases(canvases, Rectangle::new(Point::new(0, 0), screensize)); } } + log::trace!("foregrounding new context"); { // now re-check-out the new context and finalize things let maybe_new_focus = self.get_context_by_token(token); @@ -427,6 +431,7 @@ impl ContextManager { self.last_context = self.focused_context; self.focused_context = Some(last_token); } + log::trace!("defacing old canvases prior to redraw"); // run the defacement before we redraw all the canvases deface(gfx, &self.trng, canvases); log::trace!("activate redraw"); diff --git a/services/gam/src/main.rs b/services/gam/src/main.rs index 772dd1c43..e39c848ba 100644 --- a/services/gam/src/main.rs +++ b/services/gam/src/main.rs @@ -38,7 +38,7 @@ fn imef_cb(s: String::<4000>) { #[xous::xous_main] fn xmain() -> ! { log_server::init_wait().unwrap(); - log::set_max_level(log::LevelFilter::Trace); + log::set_max_level(log::LevelFilter::Info); info!("my PID is {}", xous::process::id()); let xns = xous_names::XousNames::new().unwrap(); @@ -484,15 +484,6 @@ fn xmain() -> ! { Some(Opcode::RevertFocusNb) => { context_mgr.revert_focus(&gfx, &mut canvases); }, - /* - Some(Opcode::RequestFocus) => msg_blocking_scalar_unpack!(msg, t0, t1, t2, t3, { - // TODO: add some limitations around who can request focus - // for now, it's the boot set so we just trust the requestor - context_mgr.activate(&gfx, &mut canvases, [t0 as u32, t1 as u32, t2 as u32, t3 as u32], true); - - // this is a blocking scalar, so return /something/ so we know to move on - xous::return_scalar(msg.sender, 1).expect("couldn't confirm focus activation"); - }), */ Some(Opcode::QueryGlyphProps) => msg_blocking_scalar_unpack!(msg, style, _, _, _, { let height = gfx.glyph_height_hint(GlyphStyle::from(style)).expect("couldn't query glyph height from gfx"); xous::return_scalar(msg.sender, height).expect("could not return QueryGlyphProps request");