1use core::cell::Cell;
46use core::fmt::{write, Arguments, Result, Write};
47use core::panic::PanicInfo;
48use core::ptr::addr_of_mut;
49use core::str;
50
51use crate::collections::queue::Queue;
52use crate::collections::ring_buffer::RingBuffer;
53use crate::hil;
54use crate::platform::chip::Chip;
55use crate::process::Process;
56use crate::process::ProcessPrinter;
57use crate::processbuffer::ReadableProcessSlice;
58use crate::utilities::binary_write::BinaryToWriteWrapper;
59use crate::utilities::cells::NumericCellExt;
60use crate::utilities::cells::{MapCell, TakeCell};
61use crate::ErrorCode;
62
63pub trait IoWrite {
76 fn write(&mut self, buf: &[u8]) -> usize;
77
78 fn write_ring_buffer(&mut self, buf: &RingBuffer<'_, u8>) -> usize {
79 let (left, right) = buf.as_slices();
80 let mut total = 0;
81 if let Some(slice) = left {
82 total += self.write(slice);
83 }
84 if let Some(slice) = right {
85 total += self.write(slice);
86 }
87 total
88 }
89}
90
91pub unsafe fn panic_print<W: Write + IoWrite, C: Chip, PP: ProcessPrinter>(
106 writer: &mut W,
107 panic_info: &PanicInfo,
108 nop: &dyn Fn(),
109 processes: &'static [Option<&'static dyn Process>],
110 chip: &'static Option<&'static C>,
111 process_printer: &'static Option<&'static PP>,
112) {
113 panic_begin(nop);
114 flush(writer);
116 panic_banner(writer, panic_info);
117 panic_cpu_state(chip, writer);
118
119 chip.map(|c| {
124 use crate::platform::mpu::MPU;
125 c.mpu().disable_app_mpu()
126 });
127 panic_process_info(processes, process_printer, writer);
128}
129
130pub unsafe fn panic<L: hil::led::Led, W: Write + IoWrite, C: Chip, PP: ProcessPrinter>(
137 leds: &mut [&L],
138 writer: &mut W,
139 panic_info: &PanicInfo,
140 nop: &dyn Fn(),
141 processes: &'static [Option<&'static dyn Process>],
142 chip: &'static Option<&'static C>,
143 process_printer: &'static Option<&'static PP>,
144) -> ! {
145 panic_print(writer, panic_info, nop, processes, chip, process_printer);
148
149 panic_blink_forever(leds)
154}
155
156pub unsafe fn panic_begin(nop: &dyn Fn()) {
162 for _ in 0..200000 {
164 nop();
165 }
166}
167
168pub unsafe fn panic_banner<W: Write>(writer: &mut W, panic_info: &PanicInfo) {
172 let _ = writer.write_fmt(format_args!("\r\n{}\r\n", panic_info));
173
174 let _ = writer.write_fmt(format_args!(
176 "\tKernel version {}\r\n",
177 option_env!("TOCK_KERNEL_VERSION").unwrap_or("unknown")
178 ));
179}
180
181pub unsafe fn panic_cpu_state<W: Write, C: Chip>(
185 chip: &'static Option<&'static C>,
186 writer: &mut W,
187) {
188 chip.map(|c| {
189 c.print_state(writer);
190 });
191}
192
193pub unsafe fn panic_process_info<PP: ProcessPrinter, W: Write>(
197 procs: &'static [Option<&'static dyn Process>],
198 process_printer: &'static Option<&'static PP>,
199 writer: &mut W,
200) {
201 process_printer.map(|printer| {
202 let _ = writer.write_fmt(format_args!("\r\n---| App Status |---\r\n"));
204 for proc in procs {
205 proc.map(|process| {
206 printer.print_overview(process, &mut BinaryToWriteWrapper::new(writer), None);
211 process.print_full_process(writer);
213 });
214 }
215 });
216}
217
218pub fn panic_blink_forever<L: hil::led::Led>(leds: &mut [&L]) -> ! {
233 leds.iter_mut().for_each(|led| led.init());
234 loop {
235 for _ in 0..1000000 {
236 leds.iter_mut().for_each(|led| led.on());
237 }
238 for _ in 0..100000 {
239 leds.iter_mut().for_each(|led| led.off());
240 }
241 for _ in 0..1000000 {
242 leds.iter_mut().for_each(|led| led.on());
243 }
244 for _ in 0..500000 {
245 leds.iter_mut().for_each(|led| led.off());
246 }
247 }
248}
249
250pub static mut DEBUG_GPIOS: (
258 Option<&'static dyn hil::gpio::Pin>,
259 Option<&'static dyn hil::gpio::Pin>,
260 Option<&'static dyn hil::gpio::Pin>,
261) = (None, None, None);
262
263pub unsafe fn assign_gpios(
265 gpio0: Option<&'static dyn hil::gpio::Pin>,
266 gpio1: Option<&'static dyn hil::gpio::Pin>,
267 gpio2: Option<&'static dyn hil::gpio::Pin>,
268) {
269 DEBUG_GPIOS.0 = gpio0;
270 DEBUG_GPIOS.1 = gpio1;
271 DEBUG_GPIOS.2 = gpio2;
272}
273
274#[macro_export]
276macro_rules! debug_gpio {
277 ($i:tt, $method:ident $(,)?) => {{
278 #[allow(unused_unsafe)]
279 unsafe {
280 $crate::debug::DEBUG_GPIOS.$i.map(|g| g.$method());
281 }
282 }};
283}
284
285pub struct DebugWriterWrapper {
291 dw: MapCell<&'static DebugWriter>,
292}
293
294pub struct DebugWriter {
296 uart: &'static dyn hil::uart::Transmit<'static>,
298 output_buffer: TakeCell<'static, [u8]>,
300 internal_buffer: TakeCell<'static, RingBuffer<'static, u8>>,
302 count: Cell<usize>,
304}
305
306static mut DEBUG_WRITER: Option<&'static mut DebugWriterWrapper> = None;
311
312unsafe fn try_get_debug_writer() -> Option<&'static mut DebugWriterWrapper> {
313 (*addr_of_mut!(DEBUG_WRITER)).as_deref_mut()
314}
315
316unsafe fn get_debug_writer() -> &'static mut DebugWriterWrapper {
317 try_get_debug_writer().unwrap() }
319
320pub unsafe fn set_debug_writer_wrapper(debug_writer: &'static mut DebugWriterWrapper) {
322 DEBUG_WRITER = Some(debug_writer);
323}
324
325impl DebugWriterWrapper {
326 pub fn new(dw: &'static DebugWriter) -> DebugWriterWrapper {
327 DebugWriterWrapper {
328 dw: MapCell::new(dw),
329 }
330 }
331}
332
333impl DebugWriter {
334 pub fn new(
335 uart: &'static dyn hil::uart::Transmit,
336 out_buffer: &'static mut [u8],
337 internal_buffer: &'static mut RingBuffer<'static, u8>,
338 ) -> DebugWriter {
339 DebugWriter {
340 uart,
341 output_buffer: TakeCell::new(out_buffer),
342 internal_buffer: TakeCell::new(internal_buffer),
343 count: Cell::new(0), }
345 }
346
347 fn increment_count(&self) {
348 self.count.increment();
349 }
350
351 fn get_count(&self) -> usize {
352 self.count.get()
353 }
354
355 fn publish_bytes(&self) -> usize {
358 self.internal_buffer.map_or(0, |ring_buffer| {
361 if let Some(out_buffer) = self.output_buffer.take() {
362 let mut count = 0;
363
364 for dst in out_buffer.iter_mut() {
365 match ring_buffer.dequeue() {
366 Some(src) => {
367 *dst = src;
368 count += 1;
369 }
370 None => {
371 break;
372 }
373 }
374 }
375
376 if count != 0 {
377 if let Err((_err, buf)) = self.uart.transmit_buffer(out_buffer, count) {
379 self.output_buffer.put(Some(buf));
380 } else {
381 self.output_buffer.put(None);
382 }
383 }
384 count
385 } else {
386 0
387 }
388 })
389 }
390
391 fn extract(&self) -> Option<&mut RingBuffer<'static, u8>> {
392 self.internal_buffer.take()
393 }
394
395 fn available_len(&self) -> usize {
396 self.internal_buffer.map_or(0, |rb| rb.available_len())
397 }
398}
399
400impl hil::uart::TransmitClient for DebugWriter {
401 fn transmitted_buffer(
402 &self,
403 buffer: &'static mut [u8],
404 _tx_len: usize,
405 _rcode: core::result::Result<(), ErrorCode>,
406 ) {
407 self.output_buffer.replace(buffer);
409
410 if self.internal_buffer.map_or(false, |buf| buf.has_elements()) {
411 self.publish_bytes();
413 }
414 }
415 fn transmitted_word(&self, _rcode: core::result::Result<(), ErrorCode>) {}
416}
417
418impl DebugWriterWrapper {
420 fn increment_count(&self) {
421 self.dw.map(|dw| {
422 dw.increment_count();
423 });
424 }
425
426 fn get_count(&self) -> usize {
427 self.dw.map_or(0, |dw| dw.get_count())
428 }
429
430 fn publish_bytes(&self) -> usize {
431 self.dw.map_or(0, |dw| dw.publish_bytes())
432 }
433
434 fn extract(&self) -> Option<&mut RingBuffer<'static, u8>> {
435 self.dw.map_or(None, |dw| dw.extract())
436 }
437
438 fn available_len(&self) -> usize {
439 const FULL_MSG: &[u8] = b"\n*** DEBUG BUFFER FULL ***\n";
440 self.dw
441 .map_or(0, |dw| dw.available_len().saturating_sub(FULL_MSG.len()))
442 }
443}
444
445impl IoWrite for DebugWriterWrapper {
446 fn write(&mut self, bytes: &[u8]) -> usize {
447 const FULL_MSG: &[u8] = b"\n*** DEBUG BUFFER FULL ***\n";
448 self.dw.map_or(0, |dw| {
449 dw.internal_buffer.map_or(0, |ring_buffer| {
450 let available_len_for_msg =
451 ring_buffer.available_len().saturating_sub(FULL_MSG.len());
452
453 if available_len_for_msg >= bytes.len() {
454 for &b in bytes {
455 ring_buffer.enqueue(b);
456 }
457 bytes.len()
458 } else {
459 for &b in &bytes[..available_len_for_msg] {
460 ring_buffer.enqueue(b);
461 }
462 for &b in FULL_MSG {
465 ring_buffer.enqueue(b);
466 }
467 available_len_for_msg
468 }
469 })
470 })
471 }
472}
473
474impl Write for DebugWriterWrapper {
475 fn write_str(&mut self, s: &str) -> Result {
476 self.write(s.as_bytes());
477 Ok(())
478 }
479}
480
481pub fn debug_print(args: Arguments) {
483 let writer = unsafe { get_debug_writer() };
484
485 let _ = write(writer, args);
486 writer.publish_bytes();
487}
488
489pub fn debug_println(args: Arguments) {
491 let writer = unsafe { get_debug_writer() };
492
493 let _ = write(writer, args);
494 let _ = writer.write_str("\r\n");
495 writer.publish_bytes();
496}
497
498pub fn debug_slice(slice: &ReadableProcessSlice) -> usize {
500 let writer = unsafe { get_debug_writer() };
501 let mut total = 0;
502 for b in slice.iter() {
503 let buf: [u8; 1] = [b.get(); 1];
504 let count = writer.write(&buf);
505 if count > 0 {
506 total += count;
507 } else {
508 break;
509 }
510 }
511 writer.publish_bytes();
512 total
513}
514
515pub fn debug_available_len() -> usize {
517 let writer = unsafe { get_debug_writer() };
518 writer.available_len()
519}
520
521fn write_header(writer: &mut DebugWriterWrapper, (file, line): &(&'static str, u32)) -> Result {
522 writer.increment_count();
523 let count = writer.get_count();
524 writer.write_fmt(format_args!("TOCK_DEBUG({}): {}:{}: ", count, file, line))
525}
526
527pub fn debug_verbose_print(args: Arguments, file_line: &(&'static str, u32)) {
530 let writer = unsafe { get_debug_writer() };
531
532 let _ = write_header(writer, file_line);
533 let _ = write(writer, args);
534 writer.publish_bytes();
535}
536
537pub fn debug_verbose_println(args: Arguments, file_line: &(&'static str, u32)) {
540 let writer = unsafe { get_debug_writer() };
541
542 let _ = write_header(writer, file_line);
543 let _ = write(writer, args);
544 let _ = writer.write_str("\r\n");
545 writer.publish_bytes();
546}
547
548#[macro_export]
550macro_rules! debug {
551 () => ({
552 debug!("")
554 });
555 ($msg:expr $(,)?) => ({
556 $crate::debug::debug_println(format_args!($msg));
557 });
558 ($fmt:expr, $($arg:tt)+) => ({
559 $crate::debug::debug_println(format_args!($fmt, $($arg)+));
560 });
561}
562
563#[macro_export]
565macro_rules! debug_process_slice {
566 ($msg:expr $(,)?) => {{
567 $crate::debug::debug_slice($msg)
568 }};
569}
570
571#[macro_export]
573macro_rules! debug_verbose {
574 () => ({
575 debug_verbose!("")
577 });
578 ($msg:expr $(,)?) => ({
579 $crate::debug::debug_verbose_println(format_args!($msg), {
580 static _FILE_LINE: (&'static str, u32) = (file!(), line!());
583 &_FILE_LINE
584 })
585 });
586 ($fmt:expr, $($arg:tt)+) => ({
587 $crate::debug::debug_verbose_println(format_args!($fmt, $($arg)+), {
588 static _FILE_LINE: (&'static str, u32) = (file!(), line!());
589 &_FILE_LINE
590 })
591 });
592}
593
594#[macro_export]
602macro_rules! debug_expr {
603 () => {
608 $crate::debug!("[{}:{}]", file!(), line!())
609 };
610 ($val:expr $(,)?) => {
611 match $val {
614 tmp => {
615 $crate::debug!("[{}:{}] {} = {:#?}",
616 file!(), line!(), stringify!($val), &tmp);
617 tmp
618 }
619 }
620 };
621 ($($val:expr),+ $(,)?) => {
622 ($($crate::debug_expr!($val)),+,)
623 };
624}
625
626pub unsafe fn flush<W: Write + IoWrite>(writer: &mut W) {
628 if let Some(debug_writer) = try_get_debug_writer() {
629 if let Some(ring_buffer) = debug_writer.extract() {
630 if ring_buffer.has_elements() {
631 let _ = writer.write_str(
632 "\r\n---| Debug buffer not empty. Flushing. May repeat some of last message(s):\r\n",
633 );
634
635 writer.write_ring_buffer(ring_buffer);
636 }
637 }
638 } else {
639 let _ = writer.write_str(
640 "\r\n---| Global debug writer not registered.\
641 \r\n Call `set_debug_writer_wrapper` in board initialization.\r\n",
642 );
643 }
644}