components/
debug_writer.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//! Component for DebugWriter, the implementation for `debug!()`.
6//!
7//! This provides components for attaching the kernel debug output (for panic!,
8//! print!, debug!, etc.) to the output. `DebugWriterComponent` uses a UART mux,
9//! and `DebugWriterNoMuxComponent` just uses a UART interface directly.
10//!
11//! Usage
12//! -----
13//! ```rust
14//! let debug_wrapper = components::debug_writer::DebugWriterComponent::new(
15//!     uart_mux,
16//!     create_capability!(kernel::capabilities::SetDebugWriterCapability),
17//! )
18//! .finalize(components::debug_writer_component_static!());
19//!
20//! let debug_wrapper = components::debug_writer::DebugWriterNoMuxComponent::new(
21//!     &nrf52::uart::UARTE0,
22//!     create_capability!(kernel::capabilities::SetDebugWriterCapability),
23//! )
24//! .finalize(components::debug_writer_no_mux_component_static!());
25//! ```
26
27// Author: Brad Campbell <bradjc@virginia.edu>
28// Last modified: 11/07/2019
29
30use capsules_core::virtualizers::virtual_uart::{MuxUart, UartDevice};
31use core::mem::MaybeUninit;
32use kernel::capabilities;
33use kernel::capabilities::SetDebugWriterCapability;
34use kernel::collections::ring_buffer::RingBuffer;
35use kernel::component::Component;
36use kernel::hil;
37use kernel::hil::uart;
38
39// The sum of the output_buf and internal_buf is set to a multiple of 1024 bytes in order to avoid excessive
40// padding between kernel memory and application memory (which often needs to be aligned to at
41// least a 1 KiB boundary). This is not _semantically_ critical, but helps keep buffers on 1 KiB
42// boundaries in some cases. Of course, these definitions are only advisory, and individual boards
43// can choose to pass in their own buffers with different lengths.
44pub const DEFAULT_DEBUG_BUFFER_KBYTE: usize = 2;
45
46// Bytes [0, DEBUG_BUFFER_SPLIT) are used for output_buf while bytes
47// [DEBUG_BUFFER_SPLIT, DEFAULT_DEBUG_BUFFER_KBYTE * 1024) are used for internal_buf.
48const DEBUG_BUFFER_SPLIT: usize = 64;
49
50/// The optional argument to this macro allows boards to specify the size of the in-RAM
51/// buffer used for storing debug messages.
52///
53/// Increase this value to be able to send more debug messages in
54/// quick succession.
55#[macro_export]
56macro_rules! debug_writer_component_static {
57    ($BUF_SIZE_KB:expr) => {{
58        let uart = kernel::static_buf!(capsules_core::virtualizers::virtual_uart::UartDevice);
59        let ring = kernel::static_buf!(kernel::collections::ring_buffer::RingBuffer<'static, u8>);
60        let buffer = kernel::static_buf!([u8; 1024 * $BUF_SIZE_KB]);
61        let debug = kernel::static_buf!(kernel::debug::DebugWriter);
62        let debug_wrapper = kernel::static_buf!(kernel::debug::DebugWriterWrapper);
63
64        (uart, ring, buffer, debug, debug_wrapper)
65    };};
66    () => {{
67        $crate::debug_writer_component_static!($crate::debug_writer::DEFAULT_DEBUG_BUFFER_KBYTE)
68    };};
69}
70
71/// The optional argument to this macro allows boards to specify the size of the in-RAM
72/// buffer used for storing debug messages.
73///
74/// Increase this value to be able to send more debug messages in
75/// quick succession.
76#[macro_export]
77macro_rules! debug_writer_no_mux_component_static {
78    ($BUF_SIZE_KB:expr) => {{
79        let ring = kernel::static_buf!(kernel::collections::ring_buffer::RingBuffer<'static, u8>);
80        let buffer = kernel::static_buf!([u8; 1024 * $BUF_SIZE_KB]);
81        let debug = kernel::static_buf!(kernel::debug::DebugWriter);
82        let debug_wrapper = kernel::static_buf!(kernel::debug::DebugWriterWrapper);
83
84        (ring, buffer, debug, debug_wrapper)
85    };};
86    () => {{
87        use $crate::debug_writer::DEFAULT_DEBUG_BUFFER_KBYTE;
88        $crate::debug_writer_no_mux_component_static!(DEFAULT_DEBUG_BUFFER_KBYTE)
89    };};
90}
91
92pub struct DebugWriterComponent<const BUF_SIZE_BYTES: usize, C: SetDebugWriterCapability> {
93    uart_mux: &'static MuxUart<'static>,
94    marker: core::marker::PhantomData<[u8; BUF_SIZE_BYTES]>,
95    capability: C,
96}
97
98impl<const BUF_SIZE_BYTES: usize, C: SetDebugWriterCapability>
99    DebugWriterComponent<BUF_SIZE_BYTES, C>
100{
101    pub fn new(uart_mux: &'static MuxUart, capability: C) -> Self {
102        Self {
103            uart_mux,
104            marker: core::marker::PhantomData,
105            capability,
106        }
107    }
108}
109
110pub struct Capability;
111unsafe impl capabilities::ProcessManagementCapability for Capability {}
112
113impl<const BUF_SIZE_BYTES: usize, C: SetDebugWriterCapability> Component
114    for DebugWriterComponent<BUF_SIZE_BYTES, C>
115{
116    type StaticInput = (
117        &'static mut MaybeUninit<UartDevice<'static>>,
118        &'static mut MaybeUninit<RingBuffer<'static, u8>>,
119        &'static mut MaybeUninit<[u8; BUF_SIZE_BYTES]>,
120        &'static mut MaybeUninit<kernel::debug::DebugWriter>,
121        &'static mut MaybeUninit<kernel::debug::DebugWriterWrapper>,
122    );
123    type Output = ();
124
125    fn finalize(self, s: Self::StaticInput) -> Self::Output {
126        let buf = s.2.write([0; BUF_SIZE_BYTES]);
127
128        let (output_buf, internal_buf) = buf.split_at_mut(DEBUG_BUFFER_SPLIT);
129
130        // Create virtual device for kernel debug.
131        let debugger_uart = s.0.write(UartDevice::new(self.uart_mux, false));
132        debugger_uart.setup();
133        let ring_buffer = s.1.write(RingBuffer::new(internal_buf));
134        let debugger = s.3.write(kernel::debug::DebugWriter::new(
135            debugger_uart,
136            output_buf,
137            ring_buffer,
138        ));
139        hil::uart::Transmit::set_transmit_client(debugger_uart, debugger);
140
141        let debug_wrapper = s.4.write(kernel::debug::DebugWriterWrapper::new(debugger));
142        kernel::debug::set_debug_writer_wrapper(debug_wrapper, self.capability);
143    }
144}
145
146pub struct DebugWriterNoMuxComponent<
147    U: uart::Uart<'static> + uart::Transmit<'static> + 'static,
148    const BUF_SIZE_BYTES: usize,
149    C: SetDebugWriterCapability,
150> {
151    uart: &'static U,
152    marker: core::marker::PhantomData<[u8; BUF_SIZE_BYTES]>,
153    capability: C,
154}
155
156impl<
157        U: uart::Uart<'static> + uart::Transmit<'static> + 'static,
158        const BUF_SIZE_BYTES: usize,
159        C: SetDebugWriterCapability,
160    > DebugWriterNoMuxComponent<U, BUF_SIZE_BYTES, C>
161{
162    pub fn new(uart: &'static U, capability: C) -> Self {
163        Self {
164            uart,
165            marker: core::marker::PhantomData,
166            capability,
167        }
168    }
169}
170
171impl<
172        U: uart::Uart<'static> + uart::Transmit<'static> + 'static,
173        const BUF_SIZE_BYTES: usize,
174        C: SetDebugWriterCapability,
175    > Component for DebugWriterNoMuxComponent<U, BUF_SIZE_BYTES, C>
176{
177    type StaticInput = (
178        &'static mut MaybeUninit<RingBuffer<'static, u8>>,
179        &'static mut MaybeUninit<[u8; BUF_SIZE_BYTES]>,
180        &'static mut MaybeUninit<kernel::debug::DebugWriter>,
181        &'static mut MaybeUninit<kernel::debug::DebugWriterWrapper>,
182    );
183    type Output = ();
184
185    fn finalize(self, s: Self::StaticInput) -> Self::Output {
186        let buf = s.1.write([0; BUF_SIZE_BYTES]);
187        let (output_buf, internal_buf) = buf.split_at_mut(DEBUG_BUFFER_SPLIT);
188
189        // Create virtual device for kernel debug.
190        let ring_buffer = s.0.write(RingBuffer::new(internal_buf));
191        let debugger = s.2.write(kernel::debug::DebugWriter::new(
192            self.uart,
193            output_buf,
194            ring_buffer,
195        ));
196        hil::uart::Transmit::set_transmit_client(self.uart, debugger);
197
198        let debug_wrapper = s.3.write(kernel::debug::DebugWriterWrapper::new(debugger));
199        kernel::debug::set_debug_writer_wrapper(debug_wrapper, self.capability);
200
201        let _ = self.uart.configure(uart::Parameters {
202            baud_rate: 115200,
203            width: uart::Width::Eight,
204            stop_bits: uart::StopBits::One,
205            parity: uart::Parity::None,
206            hw_flow_control: false,
207        });
208    }
209}