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