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), }