From 0871390c5b1e3a48169af1aa545951bca7c8253f Mon Sep 17 00:00:00 2001 From: Tilman Sauerbeck Date: Wed, 8 Jan 2020 11:09:36 +0100 Subject: [PATCH] common: Add the shell module. It implements no useful functionality yet. --- SConscript.libcommon | 1 + src/common/lib.rs | 1 + src/common/shell.rs | 157 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 159 insertions(+) create mode 100644 src/common/shell.rs diff --git a/SConscript.libcommon b/SConscript.libcommon index 5f9ffe2..a7c5aff 100644 --- a/SConscript.libcommon +++ b/SConscript.libcommon @@ -24,6 +24,7 @@ source_files_rs = [ 'src/common/time.rs', 'src/common/storage.rs', 'src/common/mx25l.rs', + 'src/common/shell.rs', ] source_files_c = [ diff --git a/src/common/lib.rs b/src/common/lib.rs index 72b261a..dd33c68 100644 --- a/src/common/lib.rs +++ b/src/common/lib.rs @@ -46,3 +46,4 @@ pub mod fmt; pub mod time; pub mod storage; pub mod mx25l; +pub mod shell; diff --git a/src/common/shell.rs b/src/common/shell.rs new file mode 100644 index 0000000..09c7907 --- /dev/null +++ b/src/common/shell.rs @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2020 Tilman Sauerbeck (tilman at code-monkey de) + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +use buffer::Buffer; + +pub struct Shell<'a> { + tx_buf: &'a mut Buffer, + command_offset: usize, + command_buffer: [u8; 32], +} + +extern { + fn usb_serial_read(c: *mut u8) -> bool; +} + +struct ArgumentIter<'a> { + command: &'a [u8], + offset: usize, +} + +impl<'a> Iterator for ArgumentIter<'a> { + type Item = &'a [u8]; + + fn next(&mut self) -> Option<&'a [u8]> { + let delimiter = b' '; + let mut start : Option = None; + + // Find the start of the substring. + for o in self.offset..self.command.len() { + if self.command[o] != delimiter { + start = Some(o); + break + } + } + + start.and_then(|start2| { + let mut end : Option = None; + + // Find the end of the substring. + for o in start2..self.command.len() { + if self.command[o] == delimiter { + break + } + + end = Some(o); + } + + end.and_then(|end2| { + let end3 = end2 + 1; + + self.offset = end3; + + Some(&self.command[start2..end3]) + }) + }) + } +} + +fn read_char() -> Option { + unsafe { + let mut c = b'\0'; + + if usb_serial_read(&mut c) { + Some(c) + } else { + None + } + } +} + +impl<'a> Shell<'a> { + pub fn new(tx_buf: &mut Buffer) -> Shell { + Shell { + tx_buf: tx_buf, + command_offset: 0, + command_buffer: [0; 32], + } + } + + pub fn update(&mut self) { + while let Some(c) = read_char() { + if c != b'\n' { + if self.command_offset != self.command_buffer.len() { + self.command_buffer[self.command_offset] = c; + self.command_offset += 1; + } + } else { + let command_length = self.command_offset; + self.command_offset = 0; + + if command_length != self.command_buffer.len() { + self.command_buffer[command_length] = b'\0'; + + if command_length != 0 { + self.dispatch(command_length); + } + } else { + self.command_buffer[self.command_offset] = b'\0'; + + self.tx_buf.write(b"maximum command length exceeded.\n"); + } + + self.tx_buf.write(b"$ "); + self.tx_buf.flush(); + } + } + } + + fn dispatch(&mut self, command_length: usize) { + let command : [u8; 32] = self.command_buffer; + + let mut args_iter = ArgumentIter { + command: &command[0..command_length], + offset: 0, + }; + + match args_iter.next() { + Some(b"help") => { + let usage = b"\ +Supported commands: + help Show this help message. +"; + + self.tx_buf.write(usage); + }, + + Some(ref other) => { + self.tx_buf.write(b"unknown_command: "); + self.tx_buf.write(other); + self.tx_buf.write(b"\n"); + }, + + None => { + } + } + } +} -- 2.30.2