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}