*/
use buffer::Buffer;
-use storage::Storage;
+use logger::Logger;
+use yencode::Yencode;
+use systick;
pub struct Shell<'a> {
tx_buf: &'a mut Buffer,
}
}
+fn atoi32(s: &[u8]) -> Option<u32> {
+ let mut u = 0u32;
+
+ for o in 0..s.len() {
+ let c = s[o];
+ let zero = b'0' as u8;
+ let nine = b'9' as u8;
+
+ if c < zero || c > nine {
+ return None;
+ }
+
+ let d = (c - zero) as u32;
+
+ if let Some(u2) = u.checked_mul(10) {
+ if let Some(u3) = u2.checked_add(d) {
+ u = u3;
+ } else {
+ return None;
+ }
+ } else {
+ return None;
+ }
+ }
+
+ Some(u)
+}
+
+fn atoi16(s: &[u8]) -> Option<u16> {
+ atoi32(s).and_then(|u| {
+ if u <= u16::max_value() as u32 {
+ Some(u as u16)
+ } else {
+ None
+ }
+ })
+}
+
fn read_char() -> Option<u8> {
unsafe {
let mut c = b'\0';
}
}
-struct Context<'a> {
- storage: &'a mut dyn Storage,
+fn read_char_delay_ms(limit_ms: u32) -> Option<u8> {
+ let mut total_delay_ms = 0u32;
+
+ while total_delay_ms < limit_ms {
+ if let Some(c) = read_char() {
+ return Some(c);
+ }
+
+ let ms = 50;
+
+ systick::delay_ms(ms);
+ total_delay_ms += ms;
+ }
+
+ None
}
impl<'a> Shell<'a> {
}
}
- pub fn update(&mut self, storage: &mut dyn Storage) {
- let mut context = Context {
- storage: storage,
- };
-
+ pub fn update(&mut self, logger: &mut Logger) {
while let Some(c) = read_char() {
if c != b'\n' {
if self.command_offset != self.command_buffer.len() {
self.command_buffer[command_length] = b'\0';
if command_length != 0 {
- self.dispatch(command_length, &mut context);
+ self.dispatch(command_length, logger);
}
} else {
self.command_buffer[self.command_offset] = b'\0';
}
}
- fn dispatch(&mut self, command_length: usize, mut context: &mut Context) {
+ fn dispatch(&mut self, command_length: usize, logger: &mut Logger) {
let command : [u8; 32] = self.command_buffer;
let mut args_iter = ArgumentIter {
let usage = b"\
Supported commands:
help Show this help message.
+ ls List recordings.
+ get REC_ID Retrieve recording.
clear_storage Fully erase the flash's contents.
+ dump_storage Dump the flash's contents.
";
self.tx_buf.write(usage);
},
- Some(b"clear_storage") => self.run_clear_storage(&mut context),
+ Some(b"ls") => self.run_ls(logger),
+ Some(b"get") => self.run_get(logger, &mut args_iter),
+ Some(b"clear_storage") => self.run_clear_storage(logger),
+ Some(b"dump_storage") => self.run_dump_storage(logger),
Some(ref other) => {
self.tx_buf.write(b"unknown_command: ");
}
}
- fn run_clear_storage(&self, context: &mut Context) {
- context.storage.clear();
+ fn run_ls(&mut self, logger: &mut Logger) {
+ logger.list_recordings(self.tx_buf);
+ }
+
+ fn run_get(&mut self, logger: &mut Logger, args_iter: &mut ArgumentIter) {
+ if let Some(recording_id_s) = args_iter.next() {
+ if let Some(recording_id) = atoi16(recording_id_s) {
+ if logger.has_recording(recording_id) {
+ self.tx_buf.write(b"waiting for receiver to start...\n");
+ self.tx_buf.flush();
+
+ let have_receiver = read_char_delay_ms(5000).map(|c| {
+ c == b'R'
+ }).map_or_else(|| {
+ false
+ }, |_| {
+ let result = logger.get_recording(recording_id,
+ self.tx_buf);
+
+ if result.is_err() {
+ self.tx_buf.write(b"get: failed to retrieve recording\n");
+ }
+
+ true
+ });
+
+ if !have_receiver {
+ self.tx_buf.write(b"no signal from receiver\n");
+ }
+ } else {
+ self.tx_buf.write(b"get: no such recording\n");
+ }
+ } else {
+ self.tx_buf.write(b"get: invalid argument\n");
+ }
+ } else {
+ self.tx_buf.write(b"get: missing argument\n");
+ }
+
+ self.tx_buf.flush();
+ }
+
+ fn run_clear_storage(&self, logger: &mut Logger) {
+ logger.storage.clear();
+ }
+
+ fn run_dump_storage(&mut self, logger: &mut Logger) {
+ self.tx_buf.write(b"waiting for receiver to start...\n");
+ self.tx_buf.flush();
+
+ let have_receiver = read_char_delay_ms(5000).map(|c| {
+ c == b'R'
+ }).map_or_else(|| {
+ false
+ }, |_| {
+ let mut yenc = Yencode::new(&mut self.tx_buf);
+
+ yenc.start(b"gps-watch-storage.bin");
+
+ const CHUNK_SIZE: usize = 1024;
+ let num_chunks = logger.storage.size() / CHUNK_SIZE;
+
+ for i in 0..num_chunks {
+ let mut buf = [0u8; CHUNK_SIZE];
+
+ logger.storage.read(i * CHUNK_SIZE, &mut buf);
+
+ yenc.data(&buf);
+ }
+
+ yenc.finish();
+
+ true
+ });
+
+ if !have_receiver {
+ self.tx_buf.write(b"no signal from receiver\n");
+ }
+
+ self.tx_buf.flush();
}
}