capsules_core/low_level_debug/
fmt.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/// fmt contains formatting routines for LowLevelDebug's console messages as
6/// well as the buffer size necessary for the messages.
7use super::DebugEntry;
8
9// Messages that may be emitted:
10//   1. LowLevelDebug: Dropped ## entries for app ##\n
11//   2. LowLevelDebug: App ## alert code ##\n
12//   3. LowLevelDebug: App ## prints ##\n
13//   4. LowLevelDebug: App ## prints ## ##\n
14//
15// Each ## above is a usize printed in hexadecimal, with a leading 0x.
16
17// The longest message is either 1 or 4, depending on the size of a usize.
18pub const BUF_LEN: usize = max(45 + 2 * USIZE_DIGITS, 35 + 3 * USIZE_DIGITS);
19
20// Formats the given DebugEntry using the provided buffer. Returns the length of
21// the message.
22pub(crate) fn format_entry(app_num: usize, entry: DebugEntry, buffer: &mut [u8]) -> usize {
23    use core::fmt::write;
24    use DebugEntry::{AlertCode, Dropped, Print1, Print2};
25    let mut adapter = WriteAdapter::new(buffer);
26    let _ = match entry {
27        Dropped(count) => write(
28            &mut adapter,
29            format_args!(
30                "LowLevelDebug: Dropped 0x{:x} entries for app 0x{:x}\n",
31                count, app_num
32            ),
33        ),
34        AlertCode(code) => write(
35            &mut adapter,
36            format_args!(
37                "LowLevelDebug: App 0x{:x} alert code 0x{:x}\n",
38                app_num, code
39            ),
40        ),
41        Print1(num) => write(
42            &mut adapter,
43            format_args!("LowLevelDebug: App 0x{:x} prints 0x{:x}\n", app_num, num),
44        ),
45        Print2(num1, num2) => write(
46            &mut adapter,
47            format_args!(
48                "LowLevelDebug: App 0x{:x} prints 0x{:x} 0x{:x}\n",
49                app_num, num1, num2
50            ),
51        ),
52    };
53    adapter.finish()
54}
55
56// The length of a hex-formatted usize, excluding the leading 0x.
57const USIZE_DIGITS: usize = 2 * core::mem::size_of::<usize>();
58
59// const implementation of max
60const fn max(a: usize, b: usize) -> usize {
61    [a, b][(b > a) as usize]
62}
63
64// Adapter to allow core::fmt::write to write into a u8 slice.
65struct WriteAdapter<'b> {
66    buffer: &'b mut [u8],
67    used: usize,
68}
69
70impl<'b> WriteAdapter<'b> {
71    pub fn new(buffer: &'b mut [u8]) -> WriteAdapter<'b> {
72        WriteAdapter { buffer, used: 0 }
73    }
74
75    pub fn finish(self) -> usize {
76        self.used
77    }
78}
79
80impl core::fmt::Write for WriteAdapter<'_> {
81    fn write_str(&mut self, msg: &str) -> core::fmt::Result {
82        if let Some(slice) = self.buffer.get_mut(self.used..(self.used + msg.len())) {
83            slice.copy_from_slice(msg.as_bytes());
84            self.used += msg.len();
85        }
86        Ok(())
87    }
88}