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::ProcessPrinter;
60use crate::process::ProcessSlot;
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 [ProcessSlot],
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 [ProcessSlot],
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 if crate::KERNEL_PRERELEASE_VERSION != 0 {
180 let _ = writer.write_fmt(format_args!(
181 "\tKernel version {}.{}.{}-dev{}\r\n",
182 crate::KERNEL_MAJOR_VERSION,
183 crate::KERNEL_MINOR_VERSION,
184 crate::KERNEL_PATCH_VERSION,
185 crate::KERNEL_PRERELEASE_VERSION,
186 ));
187 } else {
188 let _ = writer.write_fmt(format_args!(
189 "\tKernel version {}.{}.{}\r\n",
190 crate::KERNEL_MAJOR_VERSION,
191 crate::KERNEL_MINOR_VERSION,
192 crate::KERNEL_PATCH_VERSION,
193 ));
194 }
195}
196
197pub unsafe fn panic_cpu_state<W: Write, C: Chip>(
201 chip: &'static Option<&'static C>,
202 writer: &mut W,
203) {
204 chip.map(|c| {
205 c.print_state(writer);
206 });
207}
208
209pub unsafe fn panic_process_info<PP: ProcessPrinter, W: Write>(
213 processes: &'static [ProcessSlot],
214 process_printer: &'static Option<&'static PP>,
215 writer: &mut W,
216) {
217 process_printer.map(|printer| {
218 let _ = writer.write_fmt(format_args!("\r\n---| App Status |---\r\n"));
220 for slot in processes {
221 slot.proc.get().map(|process| {
222 printer.print_overview(process, &mut BinaryToWriteWrapper::new(writer), None);
227 process.print_full_process(writer);
229 });
230 }
231 });
232}
233
234pub fn panic_blink_forever<L: hil::led::Led>(leds: &mut [&L]) -> ! {
249 leds.iter_mut().for_each(|led| led.init());
250 loop {
251 for _ in 0..1000000 {
252 leds.iter_mut().for_each(|led| led.on());
253 }
254 for _ in 0..100000 {
255 leds.iter_mut().for_each(|led| led.off());
256 }
257 for _ in 0..1000000 {
258 leds.iter_mut().for_each(|led| led.on());
259 }
260 for _ in 0..500000 {
261 leds.iter_mut().for_each(|led| led.off());
262 }
263 }
264}
265
266pub static mut DEBUG_GPIOS: (
274 Option<&'static dyn hil::gpio::Pin>,
275 Option<&'static dyn hil::gpio::Pin>,
276 Option<&'static dyn hil::gpio::Pin>,
277) = (None, None, None);
278
279pub unsafe fn assign_gpios(
281 gpio0: Option<&'static dyn hil::gpio::Pin>,
282 gpio1: Option<&'static dyn hil::gpio::Pin>,
283 gpio2: Option<&'static dyn hil::gpio::Pin>,
284) {
285 DEBUG_GPIOS.0 = gpio0;
286 DEBUG_GPIOS.1 = gpio1;
287 DEBUG_GPIOS.2 = gpio2;
288}
289
290#[macro_export]
292macro_rules! debug_gpio {
293 ($i:tt, $method:ident $(,)?) => {{
294 #[allow(unused_unsafe)]
295 unsafe {
296 $crate::debug::DEBUG_GPIOS.$i.map(|g| g.$method());
297 }
298 }};
299}
300
301pub struct DebugWriterWrapper {
307 dw: MapCell<&'static DebugWriter>,
308}
309
310pub struct DebugWriter {
312 uart: &'static dyn hil::uart::Transmit<'static>,
314 output_buffer: TakeCell<'static, [u8]>,
316 internal_buffer: TakeCell<'static, RingBuffer<'static, u8>>,
318 count: Cell<usize>,
320}
321
322static mut DEBUG_WRITER: Option<&'static mut DebugWriterWrapper> = None;
327
328unsafe fn try_get_debug_writer() -> Option<&'static mut DebugWriterWrapper> {
329 (*addr_of_mut!(DEBUG_WRITER)).as_deref_mut()
330}
331
332unsafe fn get_debug_writer() -> &'static mut DebugWriterWrapper {
333 try_get_debug_writer().unwrap() }
335
336pub fn set_debug_writer_wrapper<C: SetDebugWriterCapability>(
338 debug_writer: &'static mut DebugWriterWrapper,
339 _cap: C,
340) {
341 unsafe {
342 DEBUG_WRITER = Some(debug_writer);
343 }
344}
345
346impl DebugWriterWrapper {
347 pub fn new(dw: &'static DebugWriter) -> DebugWriterWrapper {
348 DebugWriterWrapper {
349 dw: MapCell::new(dw),
350 }
351 }
352}
353
354impl DebugWriter {
355 pub fn new(
356 uart: &'static dyn hil::uart::Transmit,
357 out_buffer: &'static mut [u8],
358 internal_buffer: &'static mut RingBuffer<'static, u8>,
359 ) -> DebugWriter {
360 DebugWriter {
361 uart,
362 output_buffer: TakeCell::new(out_buffer),
363 internal_buffer: TakeCell::new(internal_buffer),
364 count: Cell::new(0), }
366 }
367
368 fn increment_count(&self) {
369 self.count.increment();
370 }
371
372 fn get_count(&self) -> usize {
373 self.count.get()
374 }
375
376 fn publish_bytes(&self) -> usize {
379 self.internal_buffer.map_or(0, |ring_buffer| {
382 if let Some(out_buffer) = self.output_buffer.take() {
383 let mut count = 0;
384
385 for dst in out_buffer.iter_mut() {
386 match ring_buffer.dequeue() {
387 Some(src) => {
388 *dst = src;
389 count += 1;
390 }
391 None => {
392 break;
393 }
394 }
395 }
396
397 if count != 0 {
398 if let Err((_err, buf)) = self.uart.transmit_buffer(out_buffer, count) {
400 self.output_buffer.put(Some(buf));
401 } else {
402 self.output_buffer.put(None);
403 }
404 }
405 count
406 } else {
407 0
408 }
409 })
410 }
411
412 fn extract(&self) -> Option<&mut RingBuffer<'static, u8>> {
413 self.internal_buffer.take()
414 }
415
416 fn available_len(&self) -> usize {
417 self.internal_buffer.map_or(0, |rb| rb.available_len())
418 }
419}
420
421impl hil::uart::TransmitClient for DebugWriter {
422 fn transmitted_buffer(
423 &self,
424 buffer: &'static mut [u8],
425 _tx_len: usize,
426 _rcode: core::result::Result<(), ErrorCode>,
427 ) {
428 self.output_buffer.replace(buffer);
430
431 if self.internal_buffer.map_or(false, |buf| buf.has_elements()) {
432 self.publish_bytes();
434 }
435 }
436 fn transmitted_word(&self, _rcode: core::result::Result<(), ErrorCode>) {}
437}
438
439impl DebugWriterWrapper {
441 fn increment_count(&self) {
442 self.dw.map(|dw| {
443 dw.increment_count();
444 });
445 }
446
447 fn get_count(&self) -> usize {
448 self.dw.map_or(0, |dw| dw.get_count())
449 }
450
451 fn publish_bytes(&self) -> usize {
452 self.dw.map_or(0, |dw| dw.publish_bytes())
453 }
454
455 fn extract(&self) -> Option<&mut RingBuffer<'static, u8>> {
456 self.dw.map_or(None, |dw| dw.extract())
457 }
458
459 fn available_len(&self) -> usize {
460 const FULL_MSG: &[u8] = b"\n*** DEBUG BUFFER FULL ***\n";
461 self.dw
462 .map_or(0, |dw| dw.available_len().saturating_sub(FULL_MSG.len()))
463 }
464}
465
466impl IoWrite for DebugWriterWrapper {
467 fn write(&mut self, bytes: &[u8]) -> usize {
468 const FULL_MSG: &[u8] = b"\n*** DEBUG BUFFER FULL ***\n";
469 self.dw.map_or(0, |dw| {
470 dw.internal_buffer.map_or(0, |ring_buffer| {
471 let available_len_for_msg =
472 ring_buffer.available_len().saturating_sub(FULL_MSG.len());
473
474 if available_len_for_msg >= bytes.len() {
475 for &b in bytes {
476 ring_buffer.enqueue(b);
477 }
478 bytes.len()
479 } else {
480 for &b in &bytes[..available_len_for_msg] {
481 ring_buffer.enqueue(b);
482 }
483 for &b in FULL_MSG {
486 ring_buffer.enqueue(b);
487 }
488 available_len_for_msg
489 }
490 })
491 })
492 }
493}
494
495impl Write for DebugWriterWrapper {
496 fn write_str(&mut self, s: &str) -> Result {
497 self.write(s.as_bytes());
498 Ok(())
499 }
500}
501
502pub fn debug_print(args: Arguments) {
504 let writer = unsafe { get_debug_writer() };
505
506 let _ = write(writer, args);
507 writer.publish_bytes();
508}
509
510pub fn debug_println(args: Arguments) {
512 let writer = unsafe { get_debug_writer() };
513
514 let _ = write(writer, args);
515 let _ = writer.write_str("\r\n");
516 writer.publish_bytes();
517}
518
519pub fn debug_slice(slice: &ReadableProcessSlice) -> usize {
521 let writer = unsafe { get_debug_writer() };
522 let mut total = 0;
523 for b in slice.iter() {
524 let buf: [u8; 1] = [b.get(); 1];
525 let count = writer.write(&buf);
526 if count > 0 {
527 total += count;
528 } else {
529 break;
530 }
531 }
532 writer.publish_bytes();
533 total
534}
535
536pub fn debug_available_len() -> usize {
538 let writer = unsafe { get_debug_writer() };
539 writer.available_len()
540}
541
542fn write_header(writer: &mut DebugWriterWrapper, (file, line): &(&'static str, u32)) -> Result {
543 writer.increment_count();
544 let count = writer.get_count();
545 writer.write_fmt(format_args!("TOCK_DEBUG({}): {}:{}: ", count, file, line))
546}
547
548pub fn debug_verbose_print(args: Arguments, file_line: &(&'static str, u32)) {
551 let writer = unsafe { get_debug_writer() };
552
553 let _ = write_header(writer, file_line);
554 let _ = write(writer, args);
555 writer.publish_bytes();
556}
557
558pub fn debug_verbose_println(args: Arguments, file_line: &(&'static str, u32)) {
561 let writer = unsafe { get_debug_writer() };
562
563 let _ = write_header(writer, file_line);
564 let _ = write(writer, args);
565 let _ = writer.write_str("\r\n");
566 writer.publish_bytes();
567}
568
569#[macro_export]
571macro_rules! debug {
572 () => ({
573 debug!("")
575 });
576 ($msg:expr $(,)?) => ({
577 $crate::debug::debug_println(format_args!($msg));
578 });
579 ($fmt:expr, $($arg:tt)+) => ({
580 $crate::debug::debug_println(format_args!($fmt, $($arg)+));
581 });
582}
583
584#[macro_export]
586macro_rules! debug_process_slice {
587 ($msg:expr $(,)?) => {{
588 $crate::debug::debug_slice($msg)
589 }};
590}
591
592#[macro_export]
594macro_rules! debug_verbose {
595 () => ({
596 debug_verbose!("")
598 });
599 ($msg:expr $(,)?) => ({
600 $crate::debug::debug_verbose_println(format_args!($msg), {
601 static _FILE_LINE: (&'static str, u32) = (file!(), line!());
604 &_FILE_LINE
605 })
606 });
607 ($fmt:expr, $($arg:tt)+) => ({
608 $crate::debug::debug_verbose_println(format_args!($fmt, $($arg)+), {
609 static _FILE_LINE: (&'static str, u32) = (file!(), line!());
610 &_FILE_LINE
611 })
612 });
613}
614
615#[macro_export]
623macro_rules! debug_expr {
624 () => {
629 $crate::debug!("[{}:{}]", file!(), line!())
630 };
631 ($val:expr $(,)?) => {
632 match $val {
635 tmp => {
636 $crate::debug!("[{}:{}] {} = {:#?}",
637 file!(), line!(), stringify!($val), &tmp);
638 tmp
639 }
640 }
641 };
642 ($($val:expr),+ $(,)?) => {
643 ($($crate::debug_expr!($val)),+,)
644 };
645}
646
647pub unsafe fn flush<W: Write + IoWrite>(writer: &mut W) {
649 if let Some(debug_writer) = try_get_debug_writer() {
650 if let Some(ring_buffer) = debug_writer.extract() {
651 if ring_buffer.has_elements() {
652 let _ = writer.write_str(
653 "\r\n---| Debug buffer not empty. Flushing. May repeat some of last message(s):\r\n",
654 );
655
656 writer.write_ring_buffer(ring_buffer);
657 }
658 }
659 } else {
660 let _ = writer.write_str(
661 "\r\n---| Global debug writer not registered.\
662 \r\n Call `set_debug_writer_wrapper` in board initialization.\r\n",
663 );
664 }
665}