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 read_char() -> Option<u8> {
86 if usb_serial_read(&mut c) {
94 fn read_char_delay_ms(limit_ms: u32) -> Option<u8> {
95 let mut total_delay_ms = 0u32;
97 while total_delay_ms < limit_ms {
98 if let Some(c) = read_char() {
104 systick::delay_ms(ms);
105 total_delay_ms += ms;
112 storage: &'a mut dyn Storage,
116 pub fn new(tx_buf: &mut Buffer) -> Shell {
120 command_buffer: [0; 32],
124 pub fn update(&mut self, storage: &mut dyn Storage) {
125 let mut context = Context {
129 while let Some(c) = read_char() {
131 if self.command_offset != self.command_buffer.len() {
132 self.command_buffer[self.command_offset] = c;
133 self.command_offset += 1;
136 let command_length = self.command_offset;
137 self.command_offset = 0;
139 if command_length != self.command_buffer.len() {
140 self.command_buffer[command_length] = b'\0';
142 if command_length != 0 {
143 self.dispatch(command_length, &mut context);
146 self.command_buffer[self.command_offset] = b'\0';
148 self.tx_buf.write(b"maximum command length exceeded.\n");
151 self.tx_buf.write(b"$ ");
157 fn dispatch(&mut self, command_length: usize, mut context: &mut Context) {
158 let command : [u8; 32] = self.command_buffer;
160 let mut args_iter = ArgumentIter {
161 command: &command[0..command_length],
165 match args_iter.next() {
169 help Show this help message.
170 clear_storage Fully erase the flash's contents.
171 dump_storage Dump the flash's contents.
174 self.tx_buf.write(usage);
177 Some(b"clear_storage") => self.run_clear_storage(&mut context),
178 Some(b"dump_storage") => self.run_dump_storage(&mut context),
181 self.tx_buf.write(b"unknown_command: ");
182 self.tx_buf.write(other);
183 self.tx_buf.write(b"\n");
191 fn run_clear_storage(&self, context: &mut Context) {
192 context.storage.clear();
195 fn run_dump_storage(&mut self, context: &mut Context) {
196 self.tx_buf.write(b"waiting for receiver to start...\n");
199 let have_receiver = read_char_delay_ms(5000).map(|c| {
204 let mut yenc = Yencode::new(&mut self.tx_buf);
206 yenc.start(b"gps-watch-storage.bin");
208 const CHUNK_SIZE: usize = 1024;
209 let num_chunks = context.storage.size() / CHUNK_SIZE;
211 for i in 0..num_chunks {
212 let mut buf = [0u8; CHUNK_SIZE];
214 context.storage.read(i * CHUNK_SIZE, &mut buf);
225 self.tx_buf.write(b"no signal from receiver\n");