2 * Copyright (c) 2020 Tilman Sauerbeck (tilman at code-monkey de)
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 pub struct Shell<'a> {
30 tx_buf: &'a mut Buffer,
31 command_offset: usize,
32 command_buffer: [u8; 32],
36 fn usb_serial_read(c: *mut u8) -> bool;
39 struct ArgumentIter<'a> {
44 impl<'a> Iterator for ArgumentIter<'a> {
47 fn next(&mut self) -> Option<&'a [u8]> {
49 let mut start : Option<usize> = None;
51 // Find the start of the substring.
52 for o in self.offset..self.command.len() {
53 if self.command[o] != delimiter {
59 start.and_then(|start2| {
60 let mut end : Option<usize> = None;
62 // Find the end of the substring.
63 for o in start2..self.command.len() {
64 if self.command[o] == delimiter {
76 Some(&self.command[start2..end3])
82 fn atoi32(s: &[u8]) -> Option<u32> {
87 let zero = b'0' as u8;
88 let nine = b'9' as u8;
90 if c < zero || c > nine {
94 let d = (c - zero) as u32;
96 if let Some(u2) = u.checked_mul(10) {
97 if let Some(u3) = u2.checked_add(d) {
110 fn atoi16(s: &[u8]) -> Option<u16> {
111 atoi32(s).and_then(|u| {
112 if u <= u16::max_value() as u32 {
120 fn read_char() -> Option<u8> {
124 if usb_serial_read(&mut c) {
132 fn read_char_delay_ms(limit_ms: u32) -> Option<u8> {
133 let mut total_delay_ms = 0u32;
135 while total_delay_ms < limit_ms {
136 if let Some(c) = read_char() {
142 systick::delay_ms(ms);
143 total_delay_ms += ms;
150 pub fn new(tx_buf: &mut Buffer) -> Shell {
154 command_buffer: [0; 32],
158 pub fn update(&mut self, logger: &mut Logger) {
159 while let Some(c) = read_char() {
161 if self.command_offset != self.command_buffer.len() {
162 self.command_buffer[self.command_offset] = c;
163 self.command_offset += 1;
166 let command_length = self.command_offset;
167 self.command_offset = 0;
169 if command_length != self.command_buffer.len() {
170 self.command_buffer[command_length] = b'\0';
172 if command_length != 0 {
173 self.dispatch(command_length, logger);
176 self.command_buffer[self.command_offset] = b'\0';
178 self.tx_buf.write(b"maximum command length exceeded.\n");
181 self.tx_buf.write(b"$ ");
187 fn dispatch(&mut self, command_length: usize, logger: &mut Logger) {
188 let command : [u8; 32] = self.command_buffer;
190 let mut args_iter = ArgumentIter {
191 command: &command[0..command_length],
195 match args_iter.next() {
199 help Show this help message.
201 get REC_ID Retrieve recording.
202 rm REC_ID Remove recording.
203 clear_storage Fully erase the flash's contents.
204 dump_storage Dump the flash's contents.
207 self.tx_buf.write(usage);
210 Some(b"ls") => self.run_ls(logger),
211 Some(b"get") => self.run_get(logger, &mut args_iter),
212 Some(b"rm") => self.run_rm(logger, &mut args_iter),
213 Some(b"clear_storage") => self.run_clear_storage(logger),
214 Some(b"dump_storage") => self.run_dump_storage(logger),
217 self.tx_buf.write(b"unknown_command: ");
218 self.tx_buf.write(other);
219 self.tx_buf.write(b"\n");
227 fn run_ls(&mut self, logger: &mut Logger) {
228 logger.list_recordings(self.tx_buf);
231 fn run_get(&mut self, logger: &mut Logger, args_iter: &mut ArgumentIter) {
232 if let Some(recording_id_s) = args_iter.next() {
233 if let Some(recording_id) = atoi16(recording_id_s) {
234 if logger.has_recording(recording_id) {
235 self.tx_buf.write(b"waiting for receiver to start...\n");
238 let have_receiver = read_char_delay_ms(5000).map(|c| {
243 let result = logger.get_recording(recording_id,
247 self.tx_buf.write(b"get: failed to retrieve recording\n");
254 self.tx_buf.write(b"no signal from receiver\n");
257 self.tx_buf.write(b"get: no such recording\n");
260 self.tx_buf.write(b"get: invalid argument\n");
263 self.tx_buf.write(b"get: missing argument\n");
269 fn run_rm(&mut self, logger: &mut Logger, args_iter: &mut ArgumentIter) {
270 if let Some(recording_id_s) = args_iter.next() {
271 if let Some(recording_id) = atoi16(recording_id_s) {
272 if logger.has_recording(recording_id) {
273 let result = logger.remove_recording(recording_id);
276 self.tx_buf.write(b"rm: failed to remove recording\n");
279 self.tx_buf.write(b"rm: no such recording\n");
282 self.tx_buf.write(b"rm: invalid argument\n");
285 self.tx_buf.write(b"rm: missing argument\n");
291 fn run_clear_storage(&self, logger: &mut Logger) {
292 logger.storage.clear();
295 fn run_dump_storage(&mut self, logger: &mut Logger) {
296 self.tx_buf.write(b"waiting for receiver to start...\n");
299 let have_receiver = read_char_delay_ms(5000).map(|c| {
304 let mut yenc = Yencode::new(&mut self.tx_buf);
306 yenc.start(b"gps-watch-storage.bin");
308 const CHUNK_SIZE: usize = 1024;
309 let num_chunks = logger.storage.size() / CHUNK_SIZE;
311 for i in 0..num_chunks {
312 let mut buf = [0u8; CHUNK_SIZE];
314 logger.storage.read(i * CHUNK_SIZE, &mut buf);
325 self.tx_buf.write(b"no signal from receiver\n");