avr-oxide 0.3.1

An extremely simple Rusty operating system for AVR microcontrollers
/* debug.rs
 *
 * Developed by Tim Walls <tim.walls@snowgoons.com>
 * Copyright (c) All Rights Reserved, Tim Walls
 */
//! Helpful debugging utilities.
//!
//! These are used to output to the serial port that was configured using
//! one of the `panicout` feature flags.
//!
//! It is your responsibility to initialise that port with a
//! suitable baud rate/serial protocol as early as possible in your program.
//!
//! | For Processor  | Available panic output Features (pick 1) |
//! | -------------- | ---------------------------------------- |
//! | `atmega4809`   | `panicout_usart0`, `panicout_usart1`, `panicout_usart2`, `panicout_usart3` |
//! | `atmega328p`   | `panicout_usart0` |
//!
//! # Synchronous/Blocking
//! These functions all use synchronous transmit functions, and will block
//! the processor entirely (disabling interrupts) during execution.  This
//! makes them resilient to any failures (e.g. deadlocks or similar)
//! in the operating system, helpful for debugging - but means they are
//! absolutely NOT to be used for general I/O.


use avr_oxide::concurrency::util::ThreadId;
use avr_oxide::deviceconsts::oxide;
// Imports ===================================================================
#[cfg(feature="panicout")]
use avr_oxide::hal::generic::serial::SerialNoInterruptTx;

// Declarations ==============================================================

// Code ======================================================================

/// Print a string to the serial port configured with a `panic_stdout`
/// feature.
/// If no such feature is enabled, this call does nothing.
pub fn print(string: &str){
  #[cfg(all(feature="panicout",target_arch="avr"))]
  if avr_oxide::panic_stdout!().can_write() {
    avr_oxide::panic_stdout!().blocking_write_slice(string.as_bytes());
  }
}

/// Print a u16 to the serial port configured with a `panic_stdout`
/// feature, as a decimal.
///
/// If no such feature is enabled, this call does nothing.
pub fn print_u16(val: u16){
  if val > 9 {
    print_u16(val/10);
  }
  #[cfg(all(feature="panicout",target_arch="avr"))]
  if avr_oxide::panic_stdout!().can_write() {
    avr_oxide::panic_stdout!().blocking_write_u8(((val % 10) + 0x30) as u8);
  }
}

/// Print a u32 to the serial port configured with a `panic_stdout`
/// feature, as a decimal.
///
/// If no such feature is enabled, this call does nothing.
pub fn print_u32(val: u32){
  if val > 9 {
    print_u32(val/10);
  }
  #[cfg(all(feature="panicout",target_arch="avr"))]
  if avr_oxide::panic_stdout!().can_write() {
    avr_oxide::panic_stdout!().blocking_write_u8(((val % 10) + 0x30) as u8);
  }
}

/// Print a summary of all currently loaded threads and their state to
/// the serial port configured by the `panic_stdout` feature.
///
/// A description of how to interpret the provided data can be found
/// on the [AVRoxide Site](https://avroxi.de/post/thread-dump-format/)
pub fn print_thread_state() {
  use avr_oxide::concurrency::scheduler;

  #[cfg(all(feature="panicout",target_arch="avr"))]
  avr_oxide::concurrency::interrupt::isolated(|isotoken|{
    if avr_oxide::panic_stdout!().can_write() {
      unsafe {
        for thread_id in ThreadId::MIN..oxide::MAX_THREADS {

          match scheduler::try_get_thread_by_id(thread_id){
            None => {},
            Some(thread) => {
              print("\r\n\nT");
              print_u16(thread_id as u16);
              print(":\r\n  ");
              print(thread.state.to_debug_str());
              print("\r\n  RC: ");
              print_u16(thread.returncode as u16);
              print("\r\n  Wt: ");

              thread.waiting_threads.do_each(isotoken, |_isotoken,waiting_id|{
                print_u16(waiting_id as u16);
                print(" ");
                true
              });
              print("\r\n  ST:");
              match &thread.stack {
                None => {
                  print("\r\n    DISP");
                },
                Some(stack) => {
                  if stack.is_stack_guard_valid() {
                    print("\r\n    OK");
                  } else {
                    print("\r\n    BAD");
                  }
                  print("\r\n    S: ");
                  print_u16(stack.get_size() as u16);
                  print("\r\n    T: ");
                  print_u16(stack.get_stack_top() as u16);
                  print("\r\n    F: ");
                  print_u16(stack.get_stack_free() as u16);
                }
              }
            }
          }
        }
        print("\r\n\n");
      }
    }
  });
}


// Tests =====================================================================