capsules_core/low_level_debug/
fmt.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.

/// fmt contains formatting routines for LowLevelDebug's console messages as
/// well as the buffer size necessary for the messages.
use super::DebugEntry;

// Messages that may be emitted:
//   1. LowLevelDebug: Dropped ## entries for app ##\n
//   2. LowLevelDebug: App ## alert code ##\n
//   3. LowLevelDebug: App ## prints ##\n
//   4. LowLevelDebug: App ## prints ## ##\n
//
// Each ## above is a usize printed in hexadecimal, with a leading 0x.

// The longest message is either 1 or 4, depending on the size of a usize.
pub const BUF_LEN: usize = max(45 + 2 * USIZE_DIGITS, 35 + 3 * USIZE_DIGITS);

// Formats the given DebugEntry using the provided buffer. Returns the length of
// the message.
pub(crate) fn format_entry(app_num: usize, entry: DebugEntry, buffer: &mut [u8]) -> usize {
    use core::fmt::write;
    use DebugEntry::{AlertCode, Dropped, Print1, Print2};
    let mut adapter = WriteAdapter::new(buffer);
    let _ = match entry {
        Dropped(count) => write(
            &mut adapter,
            format_args!(
                "LowLevelDebug: Dropped 0x{:x} entries for app 0x{:x}\n",
                count, app_num
            ),
        ),
        AlertCode(code) => write(
            &mut adapter,
            format_args!(
                "LowLevelDebug: App 0x{:x} alert code 0x{:x}\n",
                app_num, code
            ),
        ),
        Print1(num) => write(
            &mut adapter,
            format_args!("LowLevelDebug: App 0x{:x} prints 0x{:x}\n", app_num, num),
        ),
        Print2(num1, num2) => write(
            &mut adapter,
            format_args!(
                "LowLevelDebug: App 0x{:x} prints 0x{:x} 0x{:x}\n",
                app_num, num1, num2
            ),
        ),
    };
    adapter.finish()
}

// The length of a hex-formatted usize, excluding the leading 0x.
const USIZE_DIGITS: usize = 2 * core::mem::size_of::<usize>();

// const implementation of max
const fn max(a: usize, b: usize) -> usize {
    [a, b][(b > a) as usize]
}

// Adapter to allow core::fmt::write to write into a u8 slice.
struct WriteAdapter<'b> {
    buffer: &'b mut [u8],
    used: usize,
}

impl<'b> WriteAdapter<'b> {
    pub fn new(buffer: &'b mut [u8]) -> WriteAdapter<'b> {
        WriteAdapter { buffer, used: 0 }
    }

    pub fn finish(self) -> usize {
        self.used
    }
}

impl core::fmt::Write for WriteAdapter<'_> {
    fn write_str(&mut self, msg: &str) -> core::fmt::Result {
        if let Some(slice) = self.buffer.get_mut(self.used..(self.used + msg.len())) {
            slice.copy_from_slice(msg.as_bytes());
            self.used += msg.len();
        };
        Ok(())
    }
}