capsules_core/low_level_debug/
mod.rs1mod fmt;
9
10use core::cell::Cell;
11
12use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
13use kernel::hil::uart::{Transmit, TransmitClient};
14use kernel::syscall::CommandReturn;
15use kernel::{ErrorCode, ProcessId};
16
17pub use fmt::BUF_LEN;
19
20pub const DRIVER_NUM: usize = crate::driver::NUM::LowLevelDebug as usize;
21
22pub struct LowLevelDebug<'u, U: Transmit<'u>> {
23    buffer: Cell<Option<&'static mut [u8]>>,
24    grant: Grant<AppData, UpcallCount<0>, AllowRoCount<0>, AllowRwCount<0>>,
25    grant_failed: Cell<bool>,
32    uart: &'u U,
33}
34
35impl<'u, U: Transmit<'u>> LowLevelDebug<'u, U> {
36    pub fn new(
37        buffer: &'static mut [u8],
38        uart: &'u U,
39        grant: Grant<AppData, UpcallCount<0>, AllowRoCount<0>, AllowRwCount<0>>,
40    ) -> LowLevelDebug<'u, U> {
41        LowLevelDebug {
42            buffer: Cell::new(Some(buffer)),
43            grant,
44            grant_failed: Cell::new(false),
45            uart,
46        }
47    }
48}
49
50impl<'u, U: Transmit<'u>> kernel::syscall::SyscallDriver for LowLevelDebug<'u, U> {
51    fn command(
52        &self,
53        minor_num: usize,
54        r2: usize,
55        r3: usize,
56        caller_id: ProcessId,
57    ) -> CommandReturn {
58        match minor_num {
59            0 => return CommandReturn::success(),
60            1 => self.push_entry(DebugEntry::AlertCode(r2), caller_id),
61            2 => self.push_entry(DebugEntry::Print1(r2), caller_id),
62            3 => self.push_entry(DebugEntry::Print2(r2, r3), caller_id),
63            _ => return CommandReturn::failure(ErrorCode::NOSUPPORT),
64        }
65        CommandReturn::success()
66    }
67
68    fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
69        self.grant.enter(processid, |_, _| {})
70    }
71}
72
73impl<'u, U: Transmit<'u>> TransmitClient for LowLevelDebug<'u, U> {
74    fn transmitted_buffer(
75        &self,
76        tx_buffer: &'static mut [u8],
77        _tx_len: usize,
78        _rval: Result<(), ErrorCode>,
79    ) {
80        if self.grant_failed.take() {
86            const MESSAGE: &[u8] = b"LowLevelDebug: grant init failed\n";
87            tx_buffer[..MESSAGE.len()].copy_from_slice(MESSAGE);
88
89            let _ = self.uart.transmit_buffer(tx_buffer, MESSAGE.len()).map_err(
90                |(_, returned_buffer)| {
91                    self.buffer.set(Some(returned_buffer));
92                },
93            );
94            return;
95        }
96
97        for process_grant in self.grant.iter() {
98            let processid = process_grant.processid();
99            let (app_num, first_entry) = process_grant.enter(|owned_app_data, _| {
100                owned_app_data.queue.rotate_left(1);
101                (processid.id(), owned_app_data.queue[QUEUE_SIZE - 1].take())
102            });
103            let to_print = match first_entry {
104                None => continue,
105                Some(to_print) => to_print,
106            };
107            self.transmit_entry(tx_buffer, app_num, to_print);
108            return;
109        }
110        self.buffer.set(Some(tx_buffer));
111    }
112}
113
114impl<'u, U: Transmit<'u>> LowLevelDebug<'u, U> {
119    fn push_entry(&self, entry: DebugEntry, processid: ProcessId) {
122        use DebugEntry::Dropped;
123
124        if let Some(buffer) = self.buffer.take() {
125            self.transmit_entry(buffer, processid.id(), entry);
126            return;
127        }
128
129        let result = self.grant.enter(processid, |borrow, _| {
130            for queue_entry in &mut borrow.queue {
131                if queue_entry.is_none() {
132                    *queue_entry = Some(entry);
133                    return;
134                }
135            }
136            borrow.queue[QUEUE_SIZE - 1] = match borrow.queue[QUEUE_SIZE - 1] {
141                Some(Dropped(count)) => Some(Dropped(count + 1)),
142                _ => Some(Dropped(2)),
143            };
144        });
145
146        if result.is_err() {
150            self.grant_failed.set(true);
151        }
152    }
153
154    fn transmit_entry(&self, buffer: &'static mut [u8], app_num: usize, entry: DebugEntry) {
156        let msg_len = fmt::format_entry(app_num, entry, buffer);
157        let _ = self
160            .uart
161            .transmit_buffer(buffer, msg_len)
162            .map_err(|(_, returned_buffer)| {
163                self.buffer.set(Some(returned_buffer));
164            });
165    }
166}
167
168const QUEUE_SIZE: usize = 4;
172
173#[derive(Default)]
174pub struct AppData {
175    queue: [Option<DebugEntry>; QUEUE_SIZE],
176}
177
178#[derive(Clone, Copy)]
179pub(crate) enum DebugEntry {
180    Dropped(usize),       AlertCode(usize),     Print1(usize),        Print2(usize, usize), }