diff --git a/services/shellchat/README.md b/services/shellchat/README.md index 341fec838..5b576fd5f 100644 --- a/services/shellchat/README.md +++ b/services/shellchat/README.md @@ -12,3 +12,33 @@ Other facilities for handling system-level messages, such as menu configurations and network events, have yet to be implemented. However, they will likely end up with a demo in this application first. +To make your own command, copy the `echo.rs` template or snag the one below, and put +it in the services/shellchat/src/cmds/ directory: + +```Rust +use crate::{ShellCmdApi, CommonEnv}; +use xous::String; + +#[derive(Debug)] +pub struct Echo { +} + +impl<'a> ShellCmdApi<'a> for Echo { + cmd_api!(echo); // inserts boilerplate for command API + + fn process(&mut self, args: String::<1024>, _env: &mut CommonEnv) -> Result>, xous::Error> { + Ok(Some(rest)) + } +} +``` + +The "verb" is the name of your command, and it is the argument to the `cmd_api!()` macro. + +`process()` is your "main" function, and `args` is a string which contains the +rest of the line that was typed into the chat, minus the verb used to identify +your command (the arguments, as they may be, but not tokenized or parsed in +any way). `env` contains some items in a common environment, for example, connections +to the GAM, LLIO server or other resources required by your implementation. + +Once you've added your command to the directory, go to the `cmds.rs` file, and follow +the four-step instructions embedded within the file, starting around line 40. \ No newline at end of file diff --git a/services/shellchat/src/cmds.rs b/services/shellchat/src/cmds.rs index f0135dec6..b21da8449 100644 --- a/services/shellchat/src/cmds.rs +++ b/services/shellchat/src/cmds.rs @@ -1,10 +1,10 @@ use xous::String; use core::fmt::Write; - +/////////////////////////// Common items to all commands pub trait ShellCmdApi<'a> { // user implemented: // called to process the command with the remainder of the string attached - fn process(&mut self, rest: String::<1024>, env: &mut CommonEnv) -> Result>, xous::Error>; + fn process(&mut self, args: String::<1024>, env: &mut CommonEnv) -> Result>, xous::Error>; // created with cmd_api! macro // checks if the command matches the current verb in question @@ -28,41 +28,7 @@ macro_rules! cmd_api { }; } - -/// extract the first token, as delimited by spaces -/// modifies the incoming line by removing the token and returning the remainder -/// returns the found token -/// note: we don't have split() because of nostd -pub fn tokenize(line: &mut String::<1024>) -> Option> { - let mut token = String::<1024>::new(); - let mut retline = String::<1024>::new(); - - let lineiter = line.as_str().unwrap().chars(); - let mut foundspace = false; - let mut foundrest = false; - for ch in lineiter { - if ch != ' ' && !foundspace { - token.push(ch).unwrap(); - } else if foundspace && foundrest { - retline.push(ch).unwrap(); - } else if foundspace && ch != ' ' { - // handle case of multiple spaces in a row - foundrest = true; - retline.push(ch).unwrap(); - } else { - foundspace = true; - // consume the space - } - } - line.clear(); - write!(line, "{}", retline.as_str().unwrap()).unwrap(); - if token.len() > 0 { - Some(token) - } else { - None - } -} - +/////////////////////////// Command shell integration #[derive(Debug)] pub struct CommonEnv { llio: xous::CID, @@ -71,18 +37,29 @@ pub struct CommonEnv { gam: xous::CID, } -mod echo; -use echo::*; -mod test; -use test::*; -mod sleep; -use sleep::*; -mod sensors; -use sensors::*; +/* + To add a new command: + 0. ensure that the command implements the ShellCmdApi (above) + 1. mod/use the new command + 2. create an entry for the command's storage in the CmdEnv structure + 3. initialize the persistant storage here + 4. add it to the "commands" array in the dispatch() routine below + + Side note: if your command doesn't require persistent storage, you could, + technically, generate the command dynamically every time it's called. Echo + demonstrates this. +*/ + +///// 1. add your module here, and pull its namespace into the local crate +mod echo; use echo::*; +mod test; use test::*; +mod sleep; use sleep::*; +mod sensors; use sensors::*; #[derive(Debug)] pub struct CmdEnv { common_env: CommonEnv, + ///// 2. declare storage for your command here. test_cmd: Test, sleep_cmd: Sleep, sensors_cmd: Sensors, @@ -90,18 +67,6 @@ pub struct CmdEnv { impl CmdEnv { pub fn new(gam: xous::CID) -> CmdEnv { let ticktimer_server_id = xous::SID::from_bytes(b"ticktimer-server").unwrap(); - /* - To add a new command: - - ensure that the command implements the ShellCmdApi - - mod/use the new command (above) - - create an entry for the command's storage in the CmdEnv structure - - initialize the persistant storage here - - add it to the "commands" array in the dispatch() routine below - - Side note: if your command doesn't require persistent storage, you could, - technically, generate the command dynamically every time it's called. Echo - demonstrates this. - */ CmdEnv { common_env: CommonEnv { llio: xous_names::request_connection_blocking(xous::names::SERVER_NAME_LLIO).expect("CMD: can't connect to LLIO"), @@ -109,6 +74,7 @@ impl CmdEnv { ticktimer: xous::connect(ticktimer_server_id).unwrap(), gam, }, + ///// 3. initialize your storage, by calling new() test_cmd: Test::new(), sleep_cmd: Sleep::new(), sensors_cmd: Sensors::new(), @@ -120,6 +86,7 @@ impl CmdEnv { let mut echo_cmd = Echo {}; // this command has no persistent storage, so we can "create" it every time we call dispatch (but it's a zero-cost absraction so this doesn't actually create any instructions) let commands: &mut [& mut dyn ShellCmdApi] = &mut [ + ///// 4. add your command to this array, so that it can be looked up and dispatched &mut echo_cmd, &mut self.test_cmd, &mut self.sleep_cmd, @@ -161,4 +128,38 @@ impl CmdEnv { Ok(None) } } -} \ No newline at end of file +} + +/// extract the first token, as delimited by spaces +/// modifies the incoming line by removing the token and returning the remainder +/// returns the found token +/// note: we don't have split() because of nostd +pub fn tokenize(line: &mut String::<1024>) -> Option> { + let mut token = String::<1024>::new(); + let mut retline = String::<1024>::new(); + + let lineiter = line.as_str().unwrap().chars(); + let mut foundspace = false; + let mut foundrest = false; + for ch in lineiter { + if ch != ' ' && !foundspace { + token.push(ch).unwrap(); + } else if foundspace && foundrest { + retline.push(ch).unwrap(); + } else if foundspace && ch != ' ' { + // handle case of multiple spaces in a row + foundrest = true; + retline.push(ch).unwrap(); + } else { + foundspace = true; + // consume the space + } + } + line.clear(); + write!(line, "{}", retline.as_str().unwrap()).unwrap(); + if token.len() > 0 { + Some(token) + } else { + None + } +} diff --git a/services/shellchat/src/cmds/echo.rs b/services/shellchat/src/cmds/echo.rs index 226edefd1..8f64ddedd 100644 --- a/services/shellchat/src/cmds/echo.rs +++ b/services/shellchat/src/cmds/echo.rs @@ -8,7 +8,7 @@ pub struct Echo { impl<'a> ShellCmdApi<'a> for Echo { cmd_api!(echo); // inserts boilerplate for command API - fn process(&mut self, rest: String::<1024>, _env: &mut CommonEnv) -> Result>, xous::Error> { - Ok(Some(rest)) + fn process(&mut self, args: String::<1024>, _env: &mut CommonEnv) -> Result>, xous::Error> { + Ok(Some(args)) } } \ No newline at end of file diff --git a/services/shellchat/src/cmds/sensors.rs b/services/shellchat/src/cmds/sensors.rs index 46e661bb6..286d85653 100644 --- a/services/shellchat/src/cmds/sensors.rs +++ b/services/shellchat/src/cmds/sensors.rs @@ -14,7 +14,7 @@ impl Sensors { impl<'a> ShellCmdApi<'a> for Sensors { cmd_api!(sensors); - fn process(&mut self, _rest: String::<1024>, env: &mut CommonEnv) -> Result>, xous::Error> { + fn process(&mut self, _args: String::<1024>, env: &mut CommonEnv) -> Result>, xous::Error> { use core::fmt::Write; let mut ret = String::<1024>::new(); diff --git a/services/shellchat/src/cmds/sleep.rs b/services/shellchat/src/cmds/sleep.rs index 96b5b1080..96cfd0942 100644 --- a/services/shellchat/src/cmds/sleep.rs +++ b/services/shellchat/src/cmds/sleep.rs @@ -13,7 +13,7 @@ impl Sleep { impl<'a> ShellCmdApi<'a> for Sleep { cmd_api!(sleep); // inserts boilerplate for command API - fn process(&mut self, _rest: String::<1024>, env: &mut CommonEnv) -> Result>, xous::Error> { + fn process(&mut self, _args: String::<1024>, env: &mut CommonEnv) -> Result>, xous::Error> { use core::fmt::Write; let mut ret = String::<1024>::new(); diff --git a/services/shellchat/src/cmds/test.rs b/services/shellchat/src/cmds/test.rs index 81464ccdd..71150a63b 100644 --- a/services/shellchat/src/cmds/test.rs +++ b/services/shellchat/src/cmds/test.rs @@ -16,7 +16,7 @@ impl Test { impl<'a> ShellCmdApi<'a> for Test { cmd_api!(test); - fn process(&mut self, _rest: String::<1024>, _env: &mut CommonEnv) -> Result>, xous::Error> { + fn process(&mut self, _args: String::<1024>, _env: &mut CommonEnv) -> Result>, xous::Error> { use core::fmt::Write; self.state += 1;