capsules_core/process_console.rs
1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Implements a text console over the UART that allows
6//! a terminal to inspect and control userspace processes.
7//!
8//! For a more in-depth documentation check /doc/Process_Console.md
9use core::cell::Cell;
10use core::cmp;
11use core::fmt;
12use core::fmt::write;
13use core::str;
14use kernel::capabilities::ProcessManagementCapability;
15use kernel::capabilities::ProcessStartCapability;
16use kernel::hil::time::ConvertTicks;
17use kernel::utilities::cells::MapCell;
18use kernel::utilities::cells::TakeCell;
19use kernel::ProcessId;
20
21use kernel::debug;
22use kernel::hil::time::{Alarm, AlarmClient};
23use kernel::hil::uart;
24use kernel::introspection::KernelInfo;
25use kernel::process::{ProcessPrinter, ProcessPrinterContext, State};
26use kernel::utilities::binary_write::BinaryWrite;
27use kernel::ErrorCode;
28use kernel::Kernel;
29
30/// Buffer to hold outgoing data that is passed to the UART hardware.
31pub const WRITE_BUF_LEN: usize = 500;
32/// Buffer responses are initially held in until copied to the TX buffer and
33/// transmitted.
34pub const QUEUE_BUF_LEN: usize = 300;
35/// Since reads are byte-by-byte, to properly echo what's typed,
36/// we can use a very small read buffer.
37pub const READ_BUF_LEN: usize = 4;
38/// Commands can be up to 32 bytes long: since commands themselves are 4-5
39/// characters, limiting arguments to 25 bytes or so seems fine for now.
40pub const COMMAND_BUF_LEN: usize = 64;
41/// Default size for the history command.
42pub const DEFAULT_COMMAND_HISTORY_LEN: usize = 10;
43
44/// List of valid commands for printing help. Consolidated as these are
45/// displayed in a few different cases.
46const VALID_COMMANDS_STR: &[u8] =
47 b"help status list stop start fault boot terminate process kernel reset panic console-start console-stop\r\n";
48
49/// Escape character for ANSI escape sequences.
50const ESC: u8 = b'\x1B';
51
52/// End of line character.
53const EOL: u8 = b'\x00';
54
55/// Backspace ANSI character
56const BACKSPACE: u8 = b'\x08';
57
58/// Delete ANSI character
59const DEL: u8 = b'\x7F';
60
61/// Space ANSI character
62const SPACE: u8 = b'\x20';
63
64/// Carriage return ANSI character
65const CR: u8 = b'\x0D';
66
67/// Newline ANSI character
68const NLINE: u8 = b'\x0A';
69
70/// Upper limit for ASCII characters
71const ASCII_LIMIT: u8 = 128;
72
73/// States used for state machine to allow printing large strings asynchronously
74/// across multiple calls. This reduces the size of the buffer needed to print
75/// each section of the debug message.
76#[derive(PartialEq, Eq, Copy, Clone, Default)]
77enum WriterState {
78 #[default]
79 Empty,
80 KernelStart,
81 KernelBss,
82 KernelInit,
83 KernelStack,
84 KernelRoData,
85 KernelText,
86 ProcessPrint {
87 process_id: ProcessId,
88 context: Option<ProcessPrinterContext>,
89 },
90 List {
91 index: isize,
92 total: isize,
93 },
94}
95
96/// Key that can be part from an escape sequence.
97#[derive(Copy, Clone)]
98enum EscKey {
99 Up,
100 Down,
101 Left,
102 Right,
103 Home,
104 End,
105 Delete,
106 Backspace,
107}
108
109/// Escape state machine to check if
110/// an escape sequence has occured
111#[derive(Copy, Clone)]
112enum EscState {
113 /// This state is reached when the character is a normal
114 /// ANSI character, and the escape sequence is bypassed.
115 Bypass,
116
117 /// This state is reached when an escape sequence
118 /// is completed, and the corresponding EscKey is processed.
119 Complete(EscKey),
120
121 /// This state is reached when an escape sequence has
122 /// just started and is waiting for the next
123 /// character to complete the sequence.
124 Started,
125
126 /// This state is reached when the escape sequence
127 /// starts with a bracket character '[' and is waiting
128 /// for the next character to determine the corresponding EscKey.
129 Bracket,
130 Bracket3,
131
132 /// This state is reached when the current character does not match
133 /// any of the expected characters in the escape sequence.
134 /// Once entered in this state, the escape sequence cannot be processed
135 /// and is waiting for an ascii alphabetic character to complete
136 /// the unrecognized sequence.
137 Unrecognized,
138
139 /// This state is reached when the escape sequence has ended with
140 /// an unrecognized character. This state waits for an ascii
141 /// alphabetic character to terminate the unrecognized sequence.
142 UnrecognizedDone,
143}
144
145impl EscState {
146 fn next_state(self, data: u8) -> Self {
147 use self::{
148 EscKey::{Backspace, Delete, Down, End, Home, Left, Right, Up},
149 EscState::{
150 Bracket, Bracket3, Bypass, Complete, Started, Unrecognized, UnrecognizedDone,
151 },
152 };
153 match (self, data) {
154 (Bypass, ESC) | (UnrecognizedDone, ESC) | (Complete(_), ESC) => Started,
155 // This is a short-circuit.
156 // ASCII DEL and ANSI Escape Sequence "Delete" should be treated the same way.
157 (Bypass, DEL) | (UnrecognizedDone, DEL) | (Complete(_), DEL) => Complete(Backspace),
158 (Bypass, _) | (UnrecognizedDone, _) | (Complete(_), _) => Bypass,
159 (Started, b'[') => Bracket,
160 (Bracket, b'A') => Complete(Up),
161 (Bracket, b'B') => Complete(Down),
162 (Bracket, b'D') => Complete(Left),
163 (Bracket, b'C') => Complete(Right),
164 (Bracket, b'H') => Complete(Home),
165 (Bracket, b'F') => Complete(End),
166 (Bracket, b'3') => Bracket3,
167 (Bracket3, b'~') => Complete(Delete),
168 _ => {
169 if EscState::terminator_esc_char(data) {
170 UnrecognizedDone
171 } else {
172 Unrecognized
173 }
174 }
175 }
176 }
177
178 /// Checks if the escape state machine is in the middle
179 /// of an escape sequence
180 fn in_progress(&self) -> bool {
181 matches!(self, EscState::Bracket) || matches!(self, EscState::Bracket3)
182 }
183
184 /// Checks if the escape state machine is at the start
185 /// of processing an escape sequence
186 fn has_started(&self) -> bool {
187 matches!(self, EscState::Started)
188 }
189
190 fn terminator_esc_char(data: u8) -> bool {
191 data.is_ascii_alphabetic() || data == b'~'
192 }
193}
194
195/// Data structure to hold addresses about how the kernel is stored in memory on
196/// the chip.
197///
198/// All "end" addresses are the memory addresses immediately following the end
199/// of the memory region.
200pub struct KernelAddresses {
201 pub stack_start: *const u8,
202 pub stack_end: *const u8,
203 pub text_start: *const u8,
204 pub text_end: *const u8,
205 pub read_only_data_start: *const u8,
206 pub relocations_start: *const u8,
207 pub relocations_end: *const u8,
208 pub bss_start: *const u8,
209 pub bss_end: *const u8,
210}
211
212/// Track the operational state of the process console.
213#[derive(Clone, Copy, PartialEq)]
214enum ProcessConsoleState {
215 /// The console has not been started and is not listening for UART commands.
216 Off,
217 /// The console has been started and is running normally.
218 Active,
219 /// The console has been started (i.e. it has called receive), but it is not
220 /// actively listening to commands or showing the prompt. This mode enables
221 /// the console to be installed on a board but to not interfere with a
222 /// console-based app.
223 Hibernating,
224}
225
226pub struct ProcessConsole<
227 'a,
228 const COMMAND_HISTORY_LEN: usize,
229 A: Alarm<'a>,
230 C: ProcessManagementCapability + ProcessStartCapability,
231> {
232 uart: &'a dyn uart::UartData<'a>,
233 alarm: &'a A,
234 process_printer: &'a dyn ProcessPrinter,
235 tx_in_progress: Cell<bool>,
236 tx_buffer: TakeCell<'static, [u8]>,
237 queue_buffer: TakeCell<'static, [u8]>,
238 queue_size: Cell<usize>,
239 writer_state: Cell<WriterState>,
240 rx_buffer: TakeCell<'static, [u8]>,
241 command_buffer: TakeCell<'static, [u8]>,
242 command_index: Cell<usize>,
243
244 /// Operational mode the console is in. This includes if it is actively
245 /// responding to commands.
246 mode: Cell<ProcessConsoleState>,
247
248 /// Escape state machine in order to process an escape sequence
249 esc_state: Cell<EscState>,
250
251 /// Keep a history of inserted commands
252 command_history: MapCell<CommandHistory<'static, COMMAND_HISTORY_LEN>>,
253
254 /// Cursor index in the current typing command
255 cursor: Cell<usize>,
256
257 /// Keep the previously read byte to consider \r\n sequences
258 /// as a single \n.
259 previous_byte: Cell<u8>,
260
261 /// Internal flag that the process console should parse the command it just
262 /// received after finishing echoing the last newline character.
263 execute: Cell<bool>,
264
265 /// Reference to the kernel object so we can access process state.
266 kernel: &'static Kernel,
267
268 /// Memory addresses of where the kernel is placed in memory on chip.
269 kernel_addresses: KernelAddresses,
270
271 /// Function used to reset the device in bootloader mode
272 reset_function: Option<fn() -> !>,
273
274 /// This capsule needs to use potentially dangerous APIs related to
275 /// processes, and requires a capability to access those APIs.
276 capability: C,
277}
278
279#[derive(Copy, Clone)]
280pub struct Command {
281 buf: [u8; COMMAND_BUF_LEN],
282 len: usize,
283}
284
285impl Command {
286 /// Write the buffer with the provided data.
287 /// If the provided data's length is smaller than the buffer length,
288 /// the left over bytes are not modified due to '\0' termination.
289 fn write(&mut self, buf: &[u8; COMMAND_BUF_LEN]) {
290 self.len = buf
291 .iter()
292 .position(|a| *a == EOL)
293 .unwrap_or(COMMAND_BUF_LEN);
294
295 (self.buf).copy_from_slice(buf);
296 }
297
298 fn insert_byte(&mut self, byte: u8, pos: usize) {
299 for i in (pos..self.len).rev() {
300 self.buf[i + 1] = self.buf[i];
301 }
302
303 if let Some(buf_byte) = self.buf.get_mut(pos) {
304 *buf_byte = byte;
305 self.len += 1;
306 }
307 }
308
309 fn delete_byte(&mut self, pos: usize) {
310 for i in pos..self.len {
311 self.buf[i] = self.buf[i + 1];
312 }
313
314 if let Some(buf_byte) = self.buf.get_mut(self.len - 1) {
315 *buf_byte = EOL;
316 self.len -= 1;
317 }
318 }
319
320 fn clear(&mut self) {
321 self.buf.iter_mut().for_each(|x| *x = EOL);
322 self.len = 0;
323 }
324}
325
326impl Default for Command {
327 fn default() -> Self {
328 Command {
329 buf: [EOL; COMMAND_BUF_LEN],
330 len: 0,
331 }
332 }
333}
334
335impl PartialEq<[u8; COMMAND_BUF_LEN]> for Command {
336 fn eq(&self, other_buf: &[u8; COMMAND_BUF_LEN]) -> bool {
337 self.buf
338 .iter()
339 .zip(other_buf.iter())
340 .take_while(|(a, b)| **a != EOL || **b != EOL)
341 .all(|(a, b)| *a == *b)
342 }
343}
344
345struct CommandHistory<'a, const COMMAND_HISTORY_LEN: usize> {
346 cmds: &'a mut [Command; COMMAND_HISTORY_LEN],
347 cmd_idx: usize,
348 cmd_is_modified: bool,
349}
350
351impl<'a, const COMMAND_HISTORY_LEN: usize> CommandHistory<'a, COMMAND_HISTORY_LEN> {
352 fn new(cmds_buffer: &'a mut [Command; COMMAND_HISTORY_LEN]) -> Self {
353 Self {
354 cmds: cmds_buffer,
355 cmd_idx: 0,
356 cmd_is_modified: false,
357 }
358 }
359
360 /// Creates an empty space in the history for the next command
361 fn make_space(&mut self, cmd: &[u8]) {
362 let mut cmd_arr = [0; COMMAND_BUF_LEN];
363 cmd_arr.copy_from_slice(cmd);
364
365 if self.cmds[1] != cmd_arr {
366 self.cmds.rotate_right(1);
367 self.cmds[0].clear();
368 self.cmds[1].write(&cmd_arr);
369 }
370 }
371
372 fn write_to_first(&mut self, cmd: &[u8]) {
373 let mut cmd_arr = [0; COMMAND_BUF_LEN];
374 cmd_arr.copy_from_slice(cmd);
375 self.cmds[0].write(&cmd_arr);
376 }
377
378 // Set the next index in the command history
379 fn next_cmd_idx(&mut self) -> Option<usize> {
380 if self.cmd_idx + 1 >= COMMAND_HISTORY_LEN {
381 None
382 } else if self.cmds[self.cmd_idx + 1].len == 0 {
383 None
384 } else {
385 self.cmd_idx += 1;
386
387 Some(self.cmd_idx)
388 }
389 }
390
391 // Set the previous index in the command history
392 fn prev_cmd_idx(&mut self) -> Option<usize> {
393 if self.cmd_idx > 0 {
394 self.cmd_idx -= 1;
395
396 Some(self.cmd_idx)
397 } else {
398 None
399 }
400 }
401}
402
403pub struct ConsoleWriter {
404 buf: [u8; 500],
405 size: usize,
406}
407impl ConsoleWriter {
408 pub fn new() -> ConsoleWriter {
409 ConsoleWriter {
410 buf: [EOL; 500],
411 size: 0,
412 }
413 }
414 pub fn clear(&mut self) {
415 self.size = 0;
416 }
417}
418impl fmt::Write for ConsoleWriter {
419 fn write_str(&mut self, s: &str) -> fmt::Result {
420 let curr = s.len();
421 self.buf[self.size..self.size + curr].copy_from_slice(s.as_bytes());
422 self.size += curr;
423 Ok(())
424 }
425}
426
427impl BinaryWrite for ConsoleWriter {
428 fn write_buffer(&mut self, buffer: &[u8]) -> Result<usize, ()> {
429 let start = self.size;
430 let remaining = self.buf.len() - start;
431 let to_send = core::cmp::min(buffer.len(), remaining);
432 self.buf[start..start + to_send].copy_from_slice(&buffer[..to_send]);
433 self.size += to_send;
434 Ok(to_send)
435 }
436}
437
438impl<
439 'a,
440 const COMMAND_HISTORY_LEN: usize,
441 A: Alarm<'a>,
442 C: ProcessManagementCapability + ProcessStartCapability,
443 > ProcessConsole<'a, COMMAND_HISTORY_LEN, A, C>
444{
445 pub fn new(
446 uart: &'a dyn uart::UartData<'a>,
447 alarm: &'a A,
448 process_printer: &'a dyn ProcessPrinter,
449 tx_buffer: &'static mut [u8],
450 rx_buffer: &'static mut [u8],
451 queue_buffer: &'static mut [u8],
452 cmd_buffer: &'static mut [u8],
453 cmd_history_buffer: &'static mut [Command; COMMAND_HISTORY_LEN],
454 kernel: &'static Kernel,
455 kernel_addresses: KernelAddresses,
456 reset_function: Option<fn() -> !>,
457 capability: C,
458 ) -> ProcessConsole<'a, COMMAND_HISTORY_LEN, A, C> {
459 ProcessConsole {
460 uart,
461 alarm,
462 process_printer,
463 tx_in_progress: Cell::new(false),
464 tx_buffer: TakeCell::new(tx_buffer),
465 queue_buffer: TakeCell::new(queue_buffer),
466 queue_size: Cell::new(0),
467 writer_state: Cell::new(WriterState::Empty),
468 rx_buffer: TakeCell::new(rx_buffer),
469 command_buffer: TakeCell::new(cmd_buffer),
470 command_index: Cell::new(0),
471 mode: Cell::new(ProcessConsoleState::Off),
472 esc_state: Cell::new(EscState::Bypass),
473 command_history: MapCell::new(CommandHistory::new(cmd_history_buffer)),
474 cursor: Cell::new(0),
475 previous_byte: Cell::new(EOL),
476 execute: Cell::new(false),
477 kernel,
478 kernel_addresses,
479 reset_function,
480 capability,
481 }
482 }
483
484 /// Start the process console listening for user commands.
485 pub fn start(&self) -> Result<(), ErrorCode> {
486 if self.mode.get() == ProcessConsoleState::Off {
487 self.alarm
488 .set_alarm(self.alarm.now(), self.alarm.ticks_from_ms(100));
489 self.mode.set(ProcessConsoleState::Active);
490 }
491 Ok(())
492 }
493
494 /// Start the process console listening but in a hibernated state.
495 ///
496 /// The process console will not respond to commands, but can be activated
497 /// with the `console-start` command.
498 pub fn start_hibernated(&self) -> Result<(), ErrorCode> {
499 if self.mode.get() == ProcessConsoleState::Off {
500 self.alarm
501 .set_alarm(self.alarm.now(), self.alarm.ticks_from_ms(100));
502 self.mode.set(ProcessConsoleState::Hibernating)
503 }
504 Ok(())
505 }
506
507 /// Print base information about the kernel version installed and the help
508 /// message.
509 pub fn display_welcome(&self) {
510 // Start if not already started.
511 if self.mode.get() == ProcessConsoleState::Off {
512 self.rx_buffer.take().map(|buffer| {
513 let _ = self.uart.receive_buffer(buffer, 1);
514 self.mode.set(ProcessConsoleState::Active);
515 });
516 }
517
518 // Display pconsole info.
519 let mut console_writer = ConsoleWriter::new();
520 let _ = write(
521 &mut console_writer,
522 format_args!(
523 "Kernel version: {}.{} (build {})\r\n",
524 kernel::KERNEL_MAJOR_VERSION,
525 kernel::KERNEL_MINOR_VERSION,
526 option_env!("TOCK_KERNEL_VERSION").unwrap_or("unknown"),
527 ),
528 );
529 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
530
531 let _ = self.write_bytes(b"Welcome to the process console.\r\n");
532 let _ = self.write_bytes(b"Valid commands are: ");
533 let _ = self.write_bytes(VALID_COMMANDS_STR);
534 self.prompt();
535 }
536
537 /// Simple state machine helper function that identifies the next state for
538 /// printing log debug messages.
539 fn next_state(&self, state: WriterState) -> WriterState {
540 match state {
541 WriterState::KernelStart => WriterState::KernelBss,
542 WriterState::KernelBss => WriterState::KernelInit,
543 WriterState::KernelInit => WriterState::KernelStack,
544 WriterState::KernelStack => WriterState::KernelRoData,
545 WriterState::KernelRoData => WriterState::KernelText,
546 WriterState::KernelText => WriterState::Empty,
547 WriterState::ProcessPrint {
548 process_id,
549 context,
550 } => WriterState::ProcessPrint {
551 process_id,
552 context,
553 },
554 WriterState::List { index, total } => {
555 // Next state just increments index, unless we are at end in
556 // which next state is just the empty state.
557 if index + 1 == total {
558 WriterState::Empty
559 } else {
560 WriterState::List {
561 index: index + 1,
562 total,
563 }
564 }
565 }
566 WriterState::Empty => WriterState::Empty,
567 }
568 }
569
570 /// Create the debug message for each state in the state machine.
571 fn create_state_buffer(&self, state: WriterState) {
572 match state {
573 WriterState::KernelBss => {
574 let mut console_writer = ConsoleWriter::new();
575
576 let bss_start = self.kernel_addresses.bss_start as usize;
577 let bss_end = self.kernel_addresses.bss_end as usize;
578 let bss_size = bss_end - bss_start;
579
580 let _ = write(
581 &mut console_writer,
582 format_args!(
583 "\r\n ╔═══════════╤══════════════════════════════╗\
584 \r\n ║ Address │ Region Name Used (bytes) ║\
585 \r\n ╚{:#010X}═╪══════════════════════════════╝\
586 \r\n │ BSS {:6}",
587 bss_end, bss_size
588 ),
589 );
590
591 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
592 }
593 WriterState::KernelInit => {
594 let mut console_writer = ConsoleWriter::new();
595
596 let relocate_start = self.kernel_addresses.relocations_start as usize;
597 let relocate_end = self.kernel_addresses.relocations_end as usize;
598 let relocate_size = relocate_end - relocate_start;
599
600 let _ = write(
601 &mut console_writer,
602 format_args!(
603 "\
604 \r\n {:#010X} ┼─────────────────────────────── S\
605 \r\n │ Relocate {:6} R",
606 relocate_end, relocate_size
607 ),
608 );
609 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
610 }
611 WriterState::KernelStack => {
612 let mut console_writer = ConsoleWriter::new();
613
614 let stack_start = self.kernel_addresses.stack_start as usize;
615 let stack_end = self.kernel_addresses.stack_end as usize;
616 let stack_size = stack_end - stack_start;
617
618 let _ = write(
619 &mut console_writer,
620 format_args!(
621 "\
622 \r\n {:#010X} ┼─────────────────────────────── A\
623 \r\n │ ▼ Stack {:6} M\
624 \r\n {:#010X} ┼───────────────────────────────",
625 stack_end, stack_size, stack_start
626 ),
627 );
628 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
629 }
630 WriterState::KernelRoData => {
631 let mut console_writer = ConsoleWriter::new();
632
633 let rodata_start = self.kernel_addresses.read_only_data_start as usize;
634 let text_end = self.kernel_addresses.text_end as usize;
635 let rodata_size = text_end - rodata_start;
636
637 let _ = write(
638 &mut console_writer,
639 format_args!(
640 "\
641 \r\n .....\
642 \r\n {:#010X} ┼─────────────────────────────── F\
643 \r\n │ RoData {:6} L",
644 text_end, rodata_size
645 ),
646 );
647 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
648 }
649 WriterState::KernelText => {
650 let mut console_writer = ConsoleWriter::new();
651
652 let code_start = self.kernel_addresses.text_start as usize;
653 let code_end = self.kernel_addresses.read_only_data_start as usize;
654 let code_size = code_end - code_start;
655
656 let _ = write(
657 &mut console_writer,
658 format_args!(
659 "\
660 \r\n {:#010X} ┼─────────────────────────────── A\
661 \r\n │ Code {:6} S\
662 \r\n {:#010X} ┼─────────────────────────────── H\
663 \r\n",
664 code_end, code_size, code_start
665 ),
666 );
667 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
668 }
669 WriterState::ProcessPrint {
670 process_id,
671 context,
672 } => {
673 self.kernel
674 .process_each_capability(&self.capability, |process| {
675 if process_id == process.processid() {
676 let mut console_writer = ConsoleWriter::new();
677 let new_context = self.process_printer.print_overview(
678 process,
679 &mut console_writer,
680 context,
681 );
682
683 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
684
685 if new_context.is_some() {
686 self.writer_state.replace(WriterState::ProcessPrint {
687 process_id,
688 context: new_context,
689 });
690 } else {
691 self.writer_state.replace(WriterState::Empty);
692 // As setting the next state here to Empty does not
693 // go through this match again before reading a new command,
694 // we have to print the prompt here.
695 self.prompt();
696 }
697 }
698 });
699 }
700 WriterState::List { index, total: _ } => {
701 let mut local_index = -1;
702 self.kernel
703 .process_each_capability(&self.capability, |process| {
704 local_index += 1;
705 if local_index == index {
706 let info: KernelInfo = KernelInfo::new(self.kernel);
707
708 let pname = process.get_process_name();
709 let process_id = process.processid();
710 let short_id = process.short_app_id();
711
712 let (grants_used, grants_total) =
713 info.number_app_grant_uses(process_id, &self.capability);
714 let mut console_writer = ConsoleWriter::new();
715
716 // Display process id.
717 let _ = write(&mut console_writer, format_args!(" {:<7?}", process_id));
718 // Display short id.
719 match short_id {
720 kernel::process::ShortId::LocallyUnique => {
721 let _ = write(
722 &mut console_writer,
723 format_args!("{}", "Unique ",),
724 );
725 }
726 kernel::process::ShortId::Fixed(id) => {
727 let _ =
728 write(&mut console_writer, format_args!("0x{:<8x} ", id));
729 }
730 }
731 // Display everything else.
732 let _ = write(
733 &mut console_writer,
734 format_args!(
735 "{:<20}{:6}{:10}{:10} {:2}/{:2} {:?}\r\n",
736 pname,
737 process.debug_timeslice_expiration_count(),
738 process.debug_syscall_count(),
739 process.get_restart_count(),
740 grants_used,
741 grants_total,
742 process.get_state(),
743 ),
744 );
745
746 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
747 }
748 });
749 }
750 WriterState::Empty => {
751 self.prompt();
752 }
753 _ => {}
754 }
755 }
756
757 // Process the command in the command buffer and clear the buffer.
758 fn read_command(&self) {
759 self.command_buffer.map(|command| {
760 let terminator = command.iter().position(|&x| x == 0).unwrap_or(0);
761
762 // A command is valid only if it starts inside the buffer,
763 // ends before the beginning of the buffer, and ends after
764 // it starts.
765 if terminator > 0 {
766 let cmd_str = str::from_utf8(&command[0..terminator]);
767
768 match cmd_str {
769 Ok(s) => {
770 let clean_str = s.trim();
771
772 // Check if the command history is enabled by the user
773 // and check if the command is not full of whitespaces
774 if COMMAND_HISTORY_LEN > 1 {
775 if clean_str.len() > 0 {
776 self.command_history.map(|ht| {
777 ht.make_space(command);
778 });
779 }
780 }
781
782 if clean_str.starts_with("console-start") {
783 self.mode.set(ProcessConsoleState::Active);
784 } else if self.mode.get() == ProcessConsoleState::Hibernating {
785 // Ignore all commands in hibernating mode. We put
786 // this case early so we ensure we get stuck here
787 // even if the user typed a valid command.
788 } else if clean_str.starts_with("help") {
789 let _ = self.write_bytes(b"Welcome to the process console.\r\n");
790 let _ = self.write_bytes(b"Valid commands are: ");
791 let _ = self.write_bytes(VALID_COMMANDS_STR);
792 } else if clean_str.starts_with("console-stop") {
793 let _ = self.write_bytes(b"Disabling the process console.\r\n");
794 let _ = self.write_bytes(b"Run console-start to reactivate.\r\n");
795 self.mode.set(ProcessConsoleState::Hibernating);
796 } else if clean_str.starts_with("start") {
797 let argument = clean_str.split_whitespace().nth(1);
798 argument.map(|name| {
799 self.kernel
800 .process_each_capability(&self.capability, |proc| {
801 let proc_name = proc.get_process_name();
802 if proc_name == name {
803 proc.resume();
804 let mut console_writer = ConsoleWriter::new();
805 let _ = write(
806 &mut console_writer,
807 format_args!("Process {} resumed.\r\n", name),
808 );
809
810 let _ = self.write_bytes(
811 &(console_writer.buf)[..console_writer.size],
812 );
813 }
814 });
815 });
816 } else if clean_str.starts_with("stop") {
817 let argument = clean_str.split_whitespace().nth(1);
818 argument.map(|name| {
819 self.kernel
820 .process_each_capability(&self.capability, |proc| {
821 let proc_name = proc.get_process_name();
822 if proc_name == name {
823 proc.stop();
824 let mut console_writer = ConsoleWriter::new();
825 let _ = write(
826 &mut console_writer,
827 format_args!("Process {} stopped\r\n", proc_name),
828 );
829
830 let _ = self.write_bytes(
831 &(console_writer.buf)[..console_writer.size],
832 );
833 }
834 });
835 });
836 } else if clean_str.starts_with("fault") {
837 let argument = clean_str.split_whitespace().nth(1);
838 argument.map(|name| {
839 self.kernel
840 .process_each_capability(&self.capability, |proc| {
841 let proc_name = proc.get_process_name();
842 if proc_name == name {
843 proc.set_fault_state();
844 let mut console_writer = ConsoleWriter::new();
845 let _ = write(
846 &mut console_writer,
847 format_args!(
848 "Process {} now faulted\r\n",
849 proc_name
850 ),
851 );
852
853 let _ = self.write_bytes(
854 &(console_writer.buf)[..console_writer.size],
855 );
856 }
857 });
858 });
859 } else if clean_str.starts_with("terminate") {
860 let argument = clean_str.split_whitespace().nth(1);
861 argument.map(|name| {
862 self.kernel
863 .process_each_capability(&self.capability, |proc| {
864 let proc_name = proc.get_process_name();
865 if proc_name == name {
866 proc.terminate(None);
867 let mut console_writer = ConsoleWriter::new();
868 let _ = write(
869 &mut console_writer,
870 format_args!(
871 "Process {} terminated\r\n",
872 proc_name
873 ),
874 );
875
876 let _ = self.write_bytes(
877 &(console_writer.buf)[..console_writer.size],
878 );
879 }
880 });
881 });
882 } else if clean_str.starts_with("boot") {
883 let argument = clean_str.split_whitespace().nth(1);
884 argument.map(|name| {
885 self.kernel
886 .process_each_capability(&self.capability, |proc| {
887 let proc_name = proc.get_process_name();
888 if proc_name == name
889 && proc.get_state() == State::Terminated
890 {
891 proc.start(&self.capability);
892 }
893 });
894 });
895 } else if clean_str.starts_with("list") {
896 let _ = self
897 .write_bytes(b" PID ShortID Name Quanta ");
898 let _ = self.write_bytes(b"Syscalls Restarts Grants State\r\n");
899
900 // Count the number of current processes.
901 let mut count = 0;
902 self.kernel.process_each_capability(&self.capability, |_| {
903 count += 1;
904 });
905
906 if count > 0 {
907 // Start the state machine to print each separately.
908 self.write_state(WriterState::List {
909 index: -1,
910 total: count,
911 });
912 }
913 } else if clean_str.starts_with("status") {
914 let info: KernelInfo = KernelInfo::new(self.kernel);
915 let mut console_writer = ConsoleWriter::new();
916 let _ = write(
917 &mut console_writer,
918 format_args!(
919 "Total processes: {}\r\n",
920 info.number_loaded_processes(&self.capability)
921 ),
922 );
923 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
924 console_writer.clear();
925 let _ = write(
926 &mut console_writer,
927 format_args!(
928 "Active processes: {}\r\n",
929 info.number_active_processes(&self.capability)
930 ),
931 );
932 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
933 console_writer.clear();
934 let _ = write(
935 &mut console_writer,
936 format_args!(
937 "Timeslice expirations: {}\r\n",
938 info.timeslice_expirations(&self.capability)
939 ),
940 );
941 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
942 } else if clean_str.starts_with("process") {
943 let argument = clean_str.split_whitespace().nth(1);
944 argument.map(|name| {
945 // If two processes have the same name, only
946 // print the first one we find.
947 let mut found = false;
948 self.kernel
949 .process_each_capability(&self.capability, |proc| {
950 if found {
951 return;
952 }
953 let proc_name = proc.get_process_name();
954 if proc_name == name {
955 let mut console_writer = ConsoleWriter::new();
956 let mut context: Option<ProcessPrinterContext> = None;
957 context = self.process_printer.print_overview(
958 proc,
959 &mut console_writer,
960 context,
961 );
962
963 let _ = self.write_bytes(
964 &(console_writer.buf)[..console_writer.size],
965 );
966
967 if context.is_some() {
968 self.writer_state.replace(
969 WriterState::ProcessPrint {
970 process_id: proc.processid(),
971 context,
972 },
973 );
974 }
975
976 found = true;
977 }
978 });
979 });
980 } else if clean_str.starts_with("kernel") {
981 let mut console_writer = ConsoleWriter::new();
982 let _ = write(
983 &mut console_writer,
984 format_args!(
985 "Kernel version: {}.{} (build {})\r\n",
986 kernel::KERNEL_MAJOR_VERSION,
987 kernel::KERNEL_MINOR_VERSION,
988 option_env!("TOCK_KERNEL_VERSION").unwrap_or("unknown")
989 ),
990 );
991 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
992 console_writer.clear();
993
994 // Prints kernel memory by moving the writer to the
995 // start state.
996 self.writer_state.replace(WriterState::KernelStart);
997 } else if clean_str.starts_with("reset") {
998 self.reset_function.map_or_else(
999 || {
1000 let _ = self.write_bytes(b"Reset function is not implemented");
1001 },
1002 |f| {
1003 f();
1004 },
1005 );
1006 } else if clean_str.starts_with("panic") {
1007 panic!("Process Console forced a kernel panic.");
1008 } else {
1009 let _ = self.write_bytes(b"Valid commands are: ");
1010 let _ = self.write_bytes(VALID_COMMANDS_STR);
1011 }
1012 }
1013 Err(_e) => {
1014 let mut console_writer = ConsoleWriter::new();
1015 let _ = write(
1016 &mut console_writer,
1017 format_args!("Invalid command: {:?}", command),
1018 );
1019 let _ = self.write_bytes(&(console_writer.buf)[..console_writer.size]);
1020 }
1021 }
1022 }
1023 });
1024 self.command_buffer.map(|command| {
1025 command[0] = 0;
1026 });
1027 self.command_index.set(0);
1028 if self.writer_state.get() == WriterState::Empty {
1029 self.prompt();
1030 }
1031 }
1032
1033 fn prompt(&self) {
1034 // Only display the prompt in active mode.
1035 if self.mode.get() == ProcessConsoleState::Active {
1036 let _ = self.write_bytes(b"tock$ ");
1037 }
1038 }
1039
1040 /// Start or iterate the state machine for an asynchronous write operation
1041 /// spread across multiple callback cycles.
1042 fn write_state(&self, state: WriterState) {
1043 self.writer_state.replace(self.next_state(state));
1044 self.create_state_buffer(self.writer_state.get());
1045 }
1046
1047 fn write_byte(&self, byte: u8) -> Result<(), ErrorCode> {
1048 if self.tx_in_progress.get() {
1049 self.queue_buffer.map(|buf| {
1050 buf[self.queue_size.get()] = byte;
1051 self.queue_size.set(self.queue_size.get() + 1);
1052 });
1053 Err(ErrorCode::BUSY)
1054 } else {
1055 self.tx_in_progress.set(true);
1056 self.tx_buffer.take().map(|buffer| {
1057 buffer[0] = byte;
1058 let _ = self.uart.transmit_buffer(buffer, 1);
1059 });
1060 Ok(())
1061 }
1062 }
1063
1064 fn write_bytes(&self, bytes: &[u8]) -> Result<(), ErrorCode> {
1065 if self.tx_in_progress.get() {
1066 self.queue_buffer.map(|buf| {
1067 let size = self.queue_size.get();
1068 let len = cmp::min(bytes.len(), buf.len() - size);
1069 (buf[size..size + len]).copy_from_slice(&bytes[..len]);
1070 self.queue_size.set(size + len);
1071 });
1072 Err(ErrorCode::BUSY)
1073 } else {
1074 self.tx_in_progress.set(true);
1075 self.tx_buffer.take().map(|buffer| {
1076 let len = cmp::min(bytes.len(), buffer.len());
1077 // Copy elements of `bytes` into `buffer`
1078 (buffer[..len]).copy_from_slice(&bytes[..len]);
1079 let _ = self.uart.transmit_buffer(buffer, len);
1080 });
1081 Ok(())
1082 }
1083 }
1084
1085 /// If there is anything in the queue, copy it to the TX buffer and send
1086 /// it to the UART.
1087 ///
1088 /// Returns Ok(usize) with the number of bytes sent from the queue. If Ok(0)
1089 /// is returned, nothing was sent and the UART is free.
1090 fn handle_queue(&self) -> Result<usize, ErrorCode> {
1091 if self.tx_in_progress.get() {
1092 // This shouldn't happen because we should only try to handle the
1093 // queue when nothing else is happening, but still have the check
1094 // for safety.
1095 return Err(ErrorCode::BUSY);
1096 }
1097
1098 self.queue_buffer.map_or(Err(ErrorCode::FAIL), |qbuf| {
1099 let qlen = self.queue_size.get();
1100
1101 if qlen > 0 {
1102 self.tx_buffer.take().map_or(Err(ErrorCode::FAIL), |txbuf| {
1103 let txlen = cmp::min(qlen, txbuf.len());
1104
1105 // Copy elements of the queue into the TX buffer.
1106 (txbuf[..txlen]).copy_from_slice(&qbuf[..txlen]);
1107
1108 // TODO: If the queue needs to print over multiple TX
1109 // buffers, we need to shift the remaining contents of the
1110 // queue back to index 0.
1111 // if qlen > txlen {
1112 // (&mut qbuf[txlen..qlen]).copy_from_slice(&qbuf[txlen..qlen]);
1113 // }
1114
1115 // Mark that we sent at least some of the queue.
1116 let remaining = qlen - txlen;
1117 self.queue_size.set(remaining);
1118
1119 self.tx_in_progress.set(true);
1120 let _ = self.uart.transmit_buffer(txbuf, txlen);
1121 Ok(txlen)
1122 })
1123 } else {
1124 // Queue was empty, nothing to do.
1125 Ok(0)
1126 }
1127 })
1128 }
1129}
1130
1131impl<
1132 'a,
1133 const COMMAND_HISTORY_LEN: usize,
1134 A: Alarm<'a>,
1135 C: ProcessManagementCapability + ProcessStartCapability,
1136 > AlarmClient for ProcessConsole<'a, COMMAND_HISTORY_LEN, A, C>
1137{
1138 fn alarm(&self) {
1139 self.prompt();
1140 self.rx_buffer.take().map(|buffer| {
1141 let _ = self.uart.receive_buffer(buffer, 1);
1142 });
1143 }
1144}
1145
1146impl<
1147 'a,
1148 const COMMAND_HISTORY_LEN: usize,
1149 A: Alarm<'a>,
1150 C: ProcessManagementCapability + ProcessStartCapability,
1151 > uart::TransmitClient for ProcessConsole<'a, COMMAND_HISTORY_LEN, A, C>
1152{
1153 fn transmitted_buffer(
1154 &self,
1155 buffer: &'static mut [u8],
1156 _tx_len: usize,
1157 _rcode: Result<(), ErrorCode>,
1158 ) {
1159 // Reset state now that we no longer have an active transmission on the
1160 // UART.
1161 self.tx_buffer.replace(buffer);
1162 self.tx_in_progress.set(false);
1163
1164 // Check if we have anything queued up. If we do, let the queue
1165 // empty.
1166 let ret = self.handle_queue();
1167 if ret.ok() == Some(0) || ret.is_err() {
1168 // The queue was empty or we couldn't print the queue.
1169
1170 let current_state = self.writer_state.get();
1171 if current_state != WriterState::Empty {
1172 self.write_state(current_state);
1173 return;
1174 }
1175
1176 // Check if we just received and echoed a newline character, and
1177 // therefore need to process the received message.
1178 if self.execute.get() {
1179 self.execute.set(false);
1180 self.read_command();
1181 }
1182 }
1183 }
1184}
1185
1186impl<
1187 'a,
1188 const COMMAND_HISTORY_LEN: usize,
1189 A: Alarm<'a>,
1190 C: ProcessManagementCapability + ProcessStartCapability,
1191 > uart::ReceiveClient for ProcessConsole<'a, COMMAND_HISTORY_LEN, A, C>
1192{
1193 fn received_buffer(
1194 &self,
1195 read_buf: &'static mut [u8],
1196 rx_len: usize,
1197 _rcode: Result<(), ErrorCode>,
1198 error: uart::Error,
1199 ) {
1200 if error == uart::Error::None {
1201 match rx_len {
1202 0 => debug!("ProcessConsole had read of 0 bytes"),
1203 1 => {
1204 self.command_buffer.map(|command| {
1205 let esc_state = self.esc_state.get().next_state(read_buf[0]);
1206 self.esc_state.set(esc_state);
1207
1208 let previous_byte = self.previous_byte.get();
1209 self.previous_byte.set(read_buf[0]);
1210 let index = self.command_index.get();
1211
1212 let cursor = self.cursor.get();
1213
1214 if let EscState::Complete(key) = esc_state {
1215 match key {
1216 EscKey::Up | EscKey::Down if COMMAND_HISTORY_LEN >= 1 => {
1217 self.command_history.map(|ht| {
1218 if let Some(next_index) = if matches!(key, EscKey::Up) {
1219 ht.next_cmd_idx()
1220 } else {
1221 ht.prev_cmd_idx()
1222 } {
1223 let next_command_len = ht.cmds[next_index].len;
1224
1225 for _ in cursor..index {
1226 let _ = self.write_byte(SPACE);
1227 }
1228
1229 // Clear the displayed command
1230 for _ in 0..index {
1231 let _ = self
1232 .write_bytes(&[BACKSPACE, SPACE, BACKSPACE]);
1233 }
1234
1235 // Display the new command
1236 for i in 0..next_command_len {
1237 let byte = ht.cmds[next_index].buf[i];
1238 let _ = self.write_byte(byte);
1239 command[i] = byte;
1240 }
1241
1242 ht.cmd_is_modified = true;
1243 self.command_index.set(next_command_len);
1244 self.cursor.set(next_command_len);
1245 command[next_command_len] = EOL;
1246 }
1247 });
1248 }
1249 EscKey::Left if cursor > 0 => {
1250 let _ = self.write_byte(BACKSPACE);
1251 self.cursor.set(cursor - 1);
1252 }
1253 EscKey::Right if cursor < index => {
1254 let _ = self.write_byte(command[cursor]);
1255 self.cursor.set(cursor + 1);
1256 }
1257 EscKey::Home if cursor > 0 => {
1258 for _ in 0..cursor {
1259 let _ = self.write_byte(BACKSPACE);
1260 }
1261
1262 self.cursor.set(0);
1263 }
1264 EscKey::End if cursor < index => {
1265 for i in cursor..index {
1266 let _ = self.write_byte(command[i]);
1267 }
1268
1269 self.cursor.set(index);
1270 }
1271 EscKey::Backspace if cursor > 0 && cursor <= index => {
1272 // Move the bytes one position to left
1273 for i in (cursor - 1)..index {
1274 command[i] = command[i + 1];
1275 let _ = self.write_byte(command[i]);
1276 }
1277
1278 // Now that we copied all bytes to the left, we are left over with
1279 // a duplicate "ghost" character of the last byte,
1280 // In case we deleted the first character, this doesn't do anything as
1281 // the duplicate is not there.
1282 // |abcdef -> abcdef (won't enter this match case)
1283 // a|bcdef -> bcdef
1284 // abc|def -> abdeff -> abdef
1285
1286 let _ = self.write_bytes(&[BACKSPACE, SPACE, BACKSPACE]);
1287
1288 // The following for statements are mandatory for correctly displaying
1289 // the command and cursor
1290 //
1291 // Move the cursor to the correct position (without this,
1292 // it will get sent all the way right)
1293 for _ in (cursor - 1)..(index - 1) {
1294 let _ = self.write_byte(BACKSPACE);
1295 }
1296 // Rewrite the command, this will move the cursor right (skipping this
1297 // step will cause the command to not get updated correctly, for example
1298 // abc|def -> ab|cde. This is just a visual mismatch)
1299 for i in (cursor - 1)..(index - 1) {
1300 let _ = self.write_byte(command[i]);
1301 }
1302 // Move the cursor left again (previously, the cursor was sent to the
1303 // right by the previous for statement, so we need to move it left)
1304 for _ in (cursor - 1)..(index - 1) {
1305 let _ = self.write_byte(BACKSPACE);
1306 }
1307
1308 self.cursor.set(cursor - 1);
1309 self.command_index.set(index - 1);
1310
1311 // Remove the byte from the command in order
1312 // not to permit accumulation of the text
1313 if COMMAND_HISTORY_LEN > 1 {
1314 self.command_history.map(|ht| {
1315 if ht.cmd_is_modified {
1316 // Copy the last command into the unfinished command
1317
1318 ht.cmds[0].clear();
1319 ht.write_to_first(command);
1320 ht.cmd_is_modified = false;
1321 } else {
1322 ht.cmds[0].delete_byte(cursor);
1323 }
1324 });
1325 }
1326 }
1327 EscKey::Delete if cursor < index => {
1328 // Move the bytes one position to left
1329 for i in cursor..(index - 1) {
1330 command[i] = command[i + 1];
1331 let _ = self.write_byte(command[i]);
1332 }
1333 // We don't want to write the EOL byte, but we want to copy it to the left
1334 command[index - 1] = command[index];
1335
1336 // Now that we copied all bytes to the left, we are left over with
1337 // a duplicate "ghost" character of the last byte,
1338 // In case we deleted the first character, this doesn't do anything as
1339 // the duplicate is not there.
1340 // |abcdef -> bcdef
1341 // abc|def -> abceff -> abcef
1342 let _ = self.write_bytes(&[SPACE, BACKSPACE]);
1343
1344 // Move the cursor to last position
1345 for _ in cursor..(index - 1) {
1346 let _ = self.write_byte(BACKSPACE);
1347 }
1348
1349 self.command_index.set(index - 1);
1350
1351 // Remove the byte from the command in order
1352 // not to permit accumulation of the text
1353 if COMMAND_HISTORY_LEN > 1 {
1354 self.command_history.map(|ht| {
1355 if ht.cmd_is_modified {
1356 // Copy the last command into the unfinished command
1357
1358 ht.cmds[0].clear();
1359 ht.write_to_first(command);
1360 ht.cmd_is_modified = false;
1361 } else {
1362 ht.cmds[0].delete_byte(cursor);
1363 }
1364 });
1365 }
1366 }
1367 _ => {}
1368 }
1369 } else if read_buf[0] == NLINE || read_buf[0] == CR {
1370 if (previous_byte == NLINE || previous_byte == CR)
1371 && previous_byte != read_buf[0]
1372 {
1373 // Reset the sequence, when \r\n is received
1374 self.previous_byte.set(EOL);
1375 } else {
1376 self.cursor.set(0);
1377 self.execute.set(true);
1378
1379 let _ = self.write_bytes(&[CR, NLINE]);
1380
1381 if COMMAND_HISTORY_LEN > 1 {
1382 // Clear the unfinished command
1383 self.command_history.map(|ht| {
1384 ht.cmd_idx = 0;
1385 ht.cmd_is_modified = false;
1386 ht.cmds[0].clear();
1387 });
1388 }
1389 }
1390 } else if read_buf[0] == BACKSPACE {
1391 if cursor > 0 {
1392 // Backspace, echo and remove the byte
1393 // preceding the cursor
1394 // Note echo is '\b \b' to erase
1395 let _ = self.write_bytes(&[BACKSPACE, SPACE, BACKSPACE]);
1396
1397 // Move the bytes one position to left
1398 for i in (cursor - 1)..(index - 1) {
1399 command[i] = command[i + 1];
1400 let _ = self.write_byte(command[i]);
1401 }
1402 // We don't want to write the EOL byte, but we want to copy it to the left
1403 command[index - 1] = command[index];
1404
1405 // Now that we copied all bytes to the left, we are left over with
1406 // a duplicate "ghost" character of the last byte,
1407 // In case we deleted the last character, this doesn't do anything as
1408 // the duplicate is not there.
1409 // abcdef| -> abcdef
1410 // abcd|ef -> abceff -> abcef
1411 let _ = self.write_bytes(&[SPACE, BACKSPACE]);
1412
1413 // Move the cursor to last position
1414 for _ in cursor..index {
1415 let _ = self.write_byte(BACKSPACE);
1416 }
1417
1418 self.command_index.set(index - 1);
1419 self.cursor.set(cursor - 1);
1420
1421 // Remove the byte from the command in order
1422 // not to permit accumulation of the text
1423 if COMMAND_HISTORY_LEN > 1 {
1424 self.command_history.map(|ht| {
1425 if ht.cmd_is_modified {
1426 // Copy the last command into the unfinished command
1427
1428 ht.cmds[0].clear();
1429 ht.write_to_first(command);
1430 ht.cmd_is_modified = false;
1431 } else {
1432 ht.cmds[0].delete_byte(cursor - 1);
1433 }
1434 });
1435 }
1436 }
1437 } else if index < (command.len() - 1)
1438 && read_buf[0] < ASCII_LIMIT
1439 && !esc_state.has_started()
1440 && !esc_state.in_progress()
1441 {
1442 // For some reason, sometimes reads return > 127 but no error,
1443 // which causes utf-8 decoding failure, so check byte is < 128. -pal
1444
1445 // Echo the typed byte
1446 let _ = self.write_byte(read_buf[0]);
1447
1448 // Echo the rest of the bytes from the command
1449 for i in cursor..index {
1450 let _ = self.write_byte(command[i]);
1451 }
1452
1453 // Make space for the newest byte
1454 for i in (cursor..(index + 1)).rev() {
1455 command[i + 1] = command[i];
1456 }
1457
1458 // Move the cursor to the last position
1459 for _ in cursor..index {
1460 let _ = self.write_byte(BACKSPACE);
1461 }
1462
1463 command[cursor] = read_buf[0];
1464 self.cursor.set(cursor + 1);
1465 self.command_index.set(index + 1);
1466
1467 if COMMAND_HISTORY_LEN > 1 {
1468 self.command_history.map(|ht| {
1469 if ht.cmd_is_modified {
1470 // Copy the last command into the unfinished command
1471
1472 ht.cmds[0].clear();
1473 ht.write_to_first(command);
1474 ht.cmd_is_modified = false;
1475 } else {
1476 ht.cmds[0].insert_byte(read_buf[0], cursor);
1477 }
1478 });
1479 }
1480 }
1481 });
1482 }
1483 _ => debug!(
1484 "ProcessConsole issues reads of 1 byte, but receive_complete was length {}",
1485 rx_len
1486 ),
1487 }
1488 }
1489 let _ = self.uart.receive_buffer(read_buf, 1);
1490 }
1491}