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