1use core::cell::Cell;
49use core::fmt::{write, Arguments, Result, Write};
50use core::panic::PanicInfo;
51use core::ptr::addr_of_mut;
52use core::str;
53
54use crate::capabilities::SetDebugWriterCapability;
55use crate::collections::queue::Queue;
56use crate::collections::ring_buffer::RingBuffer;
57use crate::hil;
58use crate::platform::chip::Chip;
59use crate::process::Process;
60use crate::process::ProcessPrinter;
61use crate::processbuffer::ReadableProcessSlice;
62use crate::utilities::binary_write::BinaryToWriteWrapper;
63use crate::utilities::cells::NumericCellExt;
64use crate::utilities::cells::{MapCell, TakeCell};
65use crate::ErrorCode;
66
67pub trait IoWrite {
80 fn write(&mut self, buf: &[u8]) -> usize;
81
82 fn write_ring_buffer(&mut self, buf: &RingBuffer<'_, u8>) -> usize {
83 let (left, right) = buf.as_slices();
84 let mut total = 0;
85 if let Some(slice) = left {
86 total += self.write(slice);
87 }
88 if let Some(slice) = right {
89 total += self.write(slice);
90 }
91 total
92 }
93}
94
95pub unsafe fn panic_print<W: Write + IoWrite, C: Chip, PP: ProcessPrinter>(
110 writer: &mut W,
111 panic_info: &PanicInfo,
112 nop: &dyn Fn(),
113 processes: &'static [Option<&'static dyn Process>],
114 chip: &'static Option<&'static C>,
115 process_printer: &'static Option<&'static PP>,
116) {
117 panic_begin(nop);
118 flush(writer);
120 panic_banner(writer, panic_info);
121 panic_cpu_state(chip, writer);
122
123 chip.map(|c| {
128 use crate::platform::mpu::MPU;
129 c.mpu().disable_app_mpu()
130 });
131 panic_process_info(processes, process_printer, writer);
132}
133
134pub unsafe fn panic<L: hil::led::Led, W: Write + IoWrite, C: Chip, PP: ProcessPrinter>(
141 leds: &mut [&L],
142 writer: &mut W,
143 panic_info: &PanicInfo,
144 nop: &dyn Fn(),
145 processes: &'static [Option<&'static dyn Process>],
146 chip: &'static Option<&'static C>,
147 process_printer: &'static Option<&'static PP>,
148) -> ! {
149 panic_print(writer, panic_info, nop, processes, chip, process_printer);
152
153 panic_blink_forever(leds)
158}
159
160pub unsafe fn panic_begin(nop: &dyn Fn()) {
166 for _ in 0..200000 {
168 nop();
169 }
170}
171
172pub unsafe fn panic_banner<W: Write>(writer: &mut W, panic_info: &PanicInfo) {
176 let _ = writer.write_fmt(format_args!("\r\n{}\r\n", panic_info));
177
178 let _ = writer.write_fmt(format_args!(
180 "\tKernel version {}\r\n",
181 option_env!("TOCK_KERNEL_VERSION").unwrap_or("unknown")
182 ));
183}
184
185pub unsafe fn panic_cpu_state<W: Write, C: Chip>(
189 chip: &'static Option<&'static C>,
190 writer: &mut W,
191) {
192 chip.map(|c| {
193 c.print_state(writer);
194 });
195}
196
197pub unsafe fn panic_process_info<PP: ProcessPrinter, W: Write>(
201 procs: &'static [Option<&'static dyn Process>],
202 process_printer: &'static Option<&'static PP>,
203 writer: &mut W,
204) {
205 process_printer.map(|printer| {
206 let _ = writer.write_fmt(format_args!("\r\n---| App Status |---\r\n"));
208 for proc in procs {
209 proc.map(|process| {
210 printer.print_overview(process, &mut BinaryToWriteWrapper::new(writer), None);
215 process.print_full_process(writer);
217 });
218 }
219 });
220}
221
222pub fn panic_blink_forever<L: hil::led::Led>(leds: &mut [&L]) -> ! {
237 leds.iter_mut().for_each(|led| led.init());
238 loop {
239 for _ in 0..1000000 {
240 leds.iter_mut().for_each(|led| led.on());
241 }
242 for _ in 0..100000 {
243 leds.iter_mut().for_each(|led| led.off());
244 }
245 for _ in 0..1000000 {
246 leds.iter_mut().for_each(|led| led.on());
247 }
248 for _ in 0..500000 {
249 leds.iter_mut().for_each(|led| led.off());
250 }
251 }
252}
253
254pub static mut DEBUG_GPIOS: (
262 Option<&'static dyn hil::gpio::Pin>,
263 Option<&'static dyn hil::gpio::Pin>,
264 Option<&'static dyn hil::gpio::Pin>,
265) = (None, None, None);
266
267pub unsafe fn assign_gpios(
269 gpio0: Option<&'static dyn hil::gpio::Pin>,
270 gpio1: Option<&'static dyn hil::gpio::Pin>,
271 gpio2: Option<&'static dyn hil::gpio::Pin>,
272) {
273 DEBUG_GPIOS.0 = gpio0;
274 DEBUG_GPIOS.1 = gpio1;
275 DEBUG_GPIOS.2 = gpio2;
276}
277
278#[macro_export]
280macro_rules! debug_gpio {
281 ($i:tt, $method:ident $(,)?) => {{
282 #[allow(unused_unsafe)]
283 unsafe {
284 $crate::debug::DEBUG_GPIOS.$i.map(|g| g.$method());
285 }
286 }};
287}
288
289pub struct DebugWriterWrapper {
295 dw: MapCell<&'static DebugWriter>,
296}
297
298pub struct DebugWriter {
300 uart: &'static dyn hil::uart::Transmit<'static>,
302 output_buffer: TakeCell<'static, [u8]>,
304 internal_buffer: TakeCell<'static, RingBuffer<'static, u8>>,
306 count: Cell<usize>,
308}
309
310static mut DEBUG_WRITER: Option<&'static mut DebugWriterWrapper> = None;
315
316unsafe fn try_get_debug_writer() -> Option<&'static mut DebugWriterWrapper> {
317 (*addr_of_mut!(DEBUG_WRITER)).as_deref_mut()
318}
319
320unsafe fn get_debug_writer() -> &'static mut DebugWriterWrapper {
321 try_get_debug_writer().unwrap() }
323
324pub fn set_debug_writer_wrapper<C: SetDebugWriterCapability>(
326 debug_writer: &'static mut DebugWriterWrapper,
327 _cap: C,
328) {
329 unsafe {
330 DEBUG_WRITER = Some(debug_writer);
331 }
332}
333
334impl DebugWriterWrapper {
335 pub fn new(dw: &'static DebugWriter) -> DebugWriterWrapper {
336 DebugWriterWrapper {
337 dw: MapCell::new(dw),
338 }
339 }
340}
341
342impl DebugWriter {
343 pub fn new(
344 uart: &'static dyn hil::uart::Transmit,
345 out_buffer: &'static mut [u8],
346 internal_buffer: &'static mut RingBuffer<'static, u8>,
347 ) -> DebugWriter {
348 DebugWriter {
349 uart,
350 output_buffer: TakeCell::new(out_buffer),
351 internal_buffer: TakeCell::new(internal_buffer),
352 count: Cell::new(0), }
354 }
355
356 fn increment_count(&self) {
357 self.count.increment();
358 }
359
360 fn get_count(&self) -> usize {
361 self.count.get()
362 }
363
364 fn publish_bytes(&self) -> usize {
367 self.internal_buffer.map_or(0, |ring_buffer| {
370 if let Some(out_buffer) = self.output_buffer.take() {
371 let mut count = 0;
372
373 for dst in out_buffer.iter_mut() {
374 match ring_buffer.dequeue() {
375 Some(src) => {
376 *dst = src;
377 count += 1;
378 }
379 None => {
380 break;
381 }
382 }
383 }
384
385 if count != 0 {
386 if let Err((_err, buf)) = self.uart.transmit_buffer(out_buffer, count) {
388 self.output_buffer.put(Some(buf));
389 } else {
390 self.output_buffer.put(None);
391 }
392 }
393 count
394 } else {
395 0
396 }
397 })
398 }
399
400 fn extract(&self) -> Option<&mut RingBuffer<'static, u8>> {
401 self.internal_buffer.take()
402 }
403
404 fn available_len(&self) -> usize {
405 self.internal_buffer.map_or(0, |rb| rb.available_len())
406 }
407}
408
409impl hil::uart::TransmitClient for DebugWriter {
410 fn transmitted_buffer(
411 &self,
412 buffer: &'static mut [u8],
413 _tx_len: usize,
414 _rcode: core::result::Result<(), ErrorCode>,
415 ) {
416 self.output_buffer.replace(buffer);
418
419 if self.internal_buffer.map_or(false, |buf| buf.has_elements()) {
420 self.publish_bytes();
422 }
423 }
424 fn transmitted_word(&self, _rcode: core::result::Result<(), ErrorCode>) {}
425}
426
427impl DebugWriterWrapper {
429 fn increment_count(&self) {
430 self.dw.map(|dw| {
431 dw.increment_count();
432 });
433 }
434
435 fn get_count(&self) -> usize {
436 self.dw.map_or(0, |dw| dw.get_count())
437 }
438
439 fn publish_bytes(&self) -> usize {
440 self.dw.map_or(0, |dw| dw.publish_bytes())
441 }
442
443 fn extract(&self) -> Option<&mut RingBuffer<'static, u8>> {
444 self.dw.map_or(None, |dw| dw.extract())
445 }
446
447 fn available_len(&self) -> usize {
448 const FULL_MSG: &[u8] = b"\n*** DEBUG BUFFER FULL ***\n";
449 self.dw
450 .map_or(0, |dw| dw.available_len().saturating_sub(FULL_MSG.len()))
451 }
452}
453
454impl IoWrite for DebugWriterWrapper {
455 fn write(&mut self, bytes: &[u8]) -> usize {
456 const FULL_MSG: &[u8] = b"\n*** DEBUG BUFFER FULL ***\n";
457 self.dw.map_or(0, |dw| {
458 dw.internal_buffer.map_or(0, |ring_buffer| {
459 let available_len_for_msg =
460 ring_buffer.available_len().saturating_sub(FULL_MSG.len());
461
462 if available_len_for_msg >= bytes.len() {
463 for &b in bytes {
464 ring_buffer.enqueue(b);
465 }
466 bytes.len()
467 } else {
468 for &b in &bytes[..available_len_for_msg] {
469 ring_buffer.enqueue(b);
470 }
471 for &b in FULL_MSG {
474 ring_buffer.enqueue(b);
475 }
476 available_len_for_msg
477 }
478 })
479 })
480 }
481}
482
483impl Write for DebugWriterWrapper {
484 fn write_str(&mut self, s: &str) -> Result {
485 self.write(s.as_bytes());
486 Ok(())
487 }
488}
489
490pub fn debug_print(args: Arguments) {
492 let writer = unsafe { get_debug_writer() };
493
494 let _ = write(writer, args);
495 writer.publish_bytes();
496}
497
498pub fn debug_println(args: Arguments) {
500 let writer = unsafe { get_debug_writer() };
501
502 let _ = write(writer, args);
503 let _ = writer.write_str("\r\n");
504 writer.publish_bytes();
505}
506
507pub fn debug_slice(slice: &ReadableProcessSlice) -> usize {
509 let writer = unsafe { get_debug_writer() };
510 let mut total = 0;
511 for b in slice.iter() {
512 let buf: [u8; 1] = [b.get(); 1];
513 let count = writer.write(&buf);
514 if count > 0 {
515 total += count;
516 } else {
517 break;
518 }
519 }
520 writer.publish_bytes();
521 total
522}
523
524pub fn debug_available_len() -> usize {
526 let writer = unsafe { get_debug_writer() };
527 writer.available_len()
528}
529
530fn write_header(writer: &mut DebugWriterWrapper, (file, line): &(&'static str, u32)) -> Result {
531 writer.increment_count();
532 let count = writer.get_count();
533 writer.write_fmt(format_args!("TOCK_DEBUG({}): {}:{}: ", count, file, line))
534}
535
536pub fn debug_verbose_print(args: Arguments, file_line: &(&'static str, u32)) {
539 let writer = unsafe { get_debug_writer() };
540
541 let _ = write_header(writer, file_line);
542 let _ = write(writer, args);
543 writer.publish_bytes();
544}
545
546pub fn debug_verbose_println(args: Arguments, file_line: &(&'static str, u32)) {
549 let writer = unsafe { get_debug_writer() };
550
551 let _ = write_header(writer, file_line);
552 let _ = write(writer, args);
553 let _ = writer.write_str("\r\n");
554 writer.publish_bytes();
555}
556
557#[macro_export]
559macro_rules! debug {
560 () => ({
561 debug!("")
563 });
564 ($msg:expr $(,)?) => ({
565 $crate::debug::debug_println(format_args!($msg));
566 });
567 ($fmt:expr, $($arg:tt)+) => ({
568 $crate::debug::debug_println(format_args!($fmt, $($arg)+));
569 });
570}
571
572#[macro_export]
574macro_rules! debug_process_slice {
575 ($msg:expr $(,)?) => {{
576 $crate::debug::debug_slice($msg)
577 }};
578}
579
580#[macro_export]
582macro_rules! debug_verbose {
583 () => ({
584 debug_verbose!("")
586 });
587 ($msg:expr $(,)?) => ({
588 $crate::debug::debug_verbose_println(format_args!($msg), {
589 static _FILE_LINE: (&'static str, u32) = (file!(), line!());
592 &_FILE_LINE
593 })
594 });
595 ($fmt:expr, $($arg:tt)+) => ({
596 $crate::debug::debug_verbose_println(format_args!($fmt, $($arg)+), {
597 static _FILE_LINE: (&'static str, u32) = (file!(), line!());
598 &_FILE_LINE
599 })
600 });
601}
602
603#[macro_export]
611macro_rules! debug_expr {
612 () => {
617 $crate::debug!("[{}:{}]", file!(), line!())
618 };
619 ($val:expr $(,)?) => {
620 match $val {
623 tmp => {
624 $crate::debug!("[{}:{}] {} = {:#?}",
625 file!(), line!(), stringify!($val), &tmp);
626 tmp
627 }
628 }
629 };
630 ($($val:expr),+ $(,)?) => {
631 ($($crate::debug_expr!($val)),+,)
632 };
633}
634
635pub unsafe fn flush<W: Write + IoWrite>(writer: &mut W) {
637 if let Some(debug_writer) = try_get_debug_writer() {
638 if let Some(ring_buffer) = debug_writer.extract() {
639 if ring_buffer.has_elements() {
640 let _ = writer.write_str(
641 "\r\n---| Debug buffer not empty. Flushing. May repeat some of last message(s):\r\n",
642 );
643
644 writer.write_ring_buffer(ring_buffer);
645 }
646 }
647 } else {
648 let _ = writer.write_str(
649 "\r\n---| Global debug writer not registered.\
650 \r\n Call `set_debug_writer_wrapper` in board initialization.\r\n",
651 );
652 }
653}