avr-oxide 0.3.1

An extremely simple Rusty operating system for AVR microcontrollers
/* stdout.rs
 *
 * Developed by Tim Walls <tim.walls@snowgoons.com>
 * Copyright (c) All Rights Reserved, Tim Walls
 */
//! Simple macros and container for a static reference to a global
//! SerialPort instance, so we can use print!()/println!() style macros.
//!
//! `format!()` style printing is provided by the wonderful `ufmt` crate,
//! and we provide a couple of `print!`/`println!` macros that use this,
//! so you can write your code in a familar Rusty way.
//!
//! Note that these macros are infallible - any errors will be swallowed
//! whole and ignored.
//!
//! # Usage
//! Before you can use the `print!`/`println!` macros, you need to use the
//! `set_stdout` (or `set_stdout_handle`) function to pass a reference to the
//! serial port you wish to use.  (Actually, anything that implements Write
//! will do, but this will typically be a serial port.)
//!
//! ```rust,no_run
//! #![no_std]
//! #![no_main]
//! use avr_oxide::hal::generic::serial::{BaudRate, DataBits, Parity, SerialPortMode, StopBits};
//! use avr_oxide::devices::{UsesPin, OxideSerialPort, Handle};
//! use avr_oxide::{boards::board, print, println};
//!
//! #[avr_oxide::main(chip="atmega4809")]
//! pub fn main() -> ! {
//!   let supervisor = avr_oxide::oxide::instance();
//!
//!   let mut serial= Handle::new(OxideSerialPort::using_port_and_pins(board::usb_serial(),
//!                                                                    board::usb_serial_pins().0,
//!                                                                    board::usb_serial_pins().1).mode(SerialPortMode::Asynch(BaudRate::Baud9600, DataBits::Bits8, Parity::None, StopBits::Bits1)));
//!
//!   // Set the serial port to use for STDOUT
//!   avr_oxide::stdout::set_stdout_handle(serial.clone());
//!
//!   println!("Welcome to AVRoxide");
//!
//!   supervisor.run();
//! }
//! ```

// Imports ===================================================================
use core::convert::Infallible;
use ufmt_write::uWrite;
use avr_oxide::devices::internal::StaticShareable;
use avr_oxide::devices::Handle;


// Declarations ==============================================================
pub type Stdout = dyn uWrite<Error = Infallible>;

pub static mut STDOUT : Option<&'static mut Stdout> = None;


// Code ======================================================================
/**
 * Set a global reference that can be used by the `print!`/`println!`
 * macros for easy output to serial ports.
 */
pub fn set_stdout<W: uWrite<Error = Infallible>>(output: &'static mut W) {
  unsafe {
    STDOUT.replace(output);
  }
}

/**
 * Set a global reference that can be used by the `print!`/`println!`
 * macros for easy output to serial ports.
 */
pub fn set_stdout_handle<W: 'static + uWrite<Error = Infallible> + StaticShareable>(output: Handle<W>) {
  set_stdout(Handle::static_deref_mut(&output));
}

pub fn get_stdout() -> Option<&'static mut Stdout> {
  unsafe {
    match &mut STDOUT {
      None => None,
      Some(reference) => {
        Some(*reference)
      }
    }
  }
}

/**
 * Print the given output to the standard out writer device previously set
 * with the `set_stdout()` function.
 *
 * This method is infallible.
 */
#[macro_export]
macro_rules! print {
  ($($params:expr),*) => {
    match avr_oxide::stdout::get_stdout(){
      None => { },
      Some(stdout) => {
        let _ = ufmt::uwrite!(stdout,$($params),*);
      }
    }
  }
}

/**
 * Print the given output to the standard out writer device previously set
 * with the `set_stdout()` function, followed by a newline character.
 *
 * This method is infallible.
 */
#[macro_export]
macro_rules! println {
  ($($params:expr),*) => {
    match avr_oxide::stdout::get_stdout(){
      None => { },
      Some(stdout) => {
        let _ = ufmt::uwriteln!(stdout,$($params),*);
      }
    }
  }
}

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