avr-oxide 0.2.1

An extremely simple Rusty operating system for AVR microcontrollers
/* lib.rs
 *
 * Developed by Tim Walls <tim.walls@snowgoons.com>
 * Copyright (c) All Rights Reserved, Tim Walls
 */
#![allow(clippy::needless_doctest_main)]
//! A simple Rust runtime for AVR microcontrollers.
//!
//! AVRoxide is a simple Hardware Abstraction Layer and runtime for
//! developing software for ATmega AVR microcontrollers.
//!
//! It was born out of frustration of the lack of options available for
//! Rust development using the ATmega4809 microcontroller present in
//! Arduino Nano Every embedded processor boards, but is intended to grow
//! to support multiple target devices.
//!
//! Key features include:
//! * Abstractions of the key hardware devices provided by the controller,
//!   like USARTs, timers, and GPIO ports.
//! * Higher-level abstractions - like 'clock' and 'button' - for simple
//!   application programming.
//! * An "Arduino Familiar" way of referring to hardware components,
//!   while also offering complete access to the underlying chip for regular,
//!   non-Arduino, embedded solutions.
//! * A simple runtime for event-based application development, using
//!   interrupt-driven IO for power-efficient operation.
//!
//! # Feature Flags
//! Feature flags are used so you can ensure minimal code size by disabling
//! features that are not required, and also to configure some of those
//! features at compile-time (important in an embedded system.)  Some of these
//! features are mandatory, and describe the type of hardware you are building
//! for.  Others describe optional functionality.
//!
//! ## Mandatory Features
//! It is necessary to tell AVRoxide what device you are supporting by
//! providing both a processor feature, and a clockspeed feature, from the
//! list below.  The CPU feature flag determines which hardware devices are
//! exposed by the HAL, while the clockspeed feature is used to calculate
//! certain constants for things like timer and baud rate calculations.
//!
//! | CPU Feature | Clockspeed features (pick 1) |
//! | ----------- | ---------------------------- |
//! | `atmega4809` | `16MHz`, `20MHz` |
//!
//! ## Optional Features
//! ### Boot segment
//! If the `bootable` feature flag is set, AVRoxide will link in a small boot
//! sector library _including the interrupt vector table_.
//!
//! If you *do not* specify the `bootable` feature, you must provide your
//! own:
//! * Interrupt Vector Table
//! * Inititalisation code to clear BSS and copy static initialisation data
//!   to RAM
//! * Inititalise the global allocator (if enabled with one of the `alloc_`
//!   features (see [Dynamic allocator]) by calling `avr_oxide::alloc::initialise()`
//! * Jump to the `_oxide_main()` function to initialise the runtime.
//!
//! ### Arduino Compatibility
//! If the `arduino` feature flag is set, the `avr_oxide::arduino` module
//! will be exported, enabling access to hardware devices (like GPIO pins)
//! using Arduino naming/numbering conventions.
//!
//! ### Panic handler
//! If the `panic_handler` feature is enabled, a default panic handler will
//! be provided.
//!
//! ### Panic to serial port support
//! You can configure a serial port which will be used by the AVRoxide
//! [panic handler] to output error line information on panic.
//!
//! 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` |
//!
//! > *Important*: Because of the way Rust embeds panic information in your
//! > binary, enabling this feature can take up a fair amount of Flash memory
//! > space.  For example, a simple test app that uses 37882 bytes of Flash
//! > without this feature uses 44330 bytes with it.
//! >
//! > Note also that because Rust embeds absolute pathnames for source files
//! > into the binary, the size of your binary can change depending on where
//! > (the directory path) you compile it on your development machine!
//!
//! ### Dynamic Allocator
//! A dynamic allocator implementation is provided; this will allocate a
//! certain amount of the device's memory as a heap for dynamic data
//! allocation.  More memory allocated to heap means less for stack and
//! mutable constants, so three different memory models (small, medium, large)
//! are available.
//!
//! | For Processor | Allocator flag | RAM allocated to heap |
//! | ------------- | -------------- | --------------------- |
//! | `atmega4809`  | `alloc_small`  | 512 bytes  |
//! |               | `alloc_medium` | 1024 bytes |
//! |               | `alloc_large`  | 3072 bytes |
//!
//! # A Minimal AVRoxide Program
//! This program shows how to access the devices using the Arduino aliases
//! for an Arduino Nano Every, and how to listen to button events from a
//! button attached to pin A2 to toggle an LED attached to pin D7 every time
//! the button is pressed.
//!
//! We also show the use of a software debouncer on the pin, and configuring
//! a serial port.
//!
//! ```no_run
//! #![no_std]
//! #![no_main]
//!
//! use avr_oxide::hal::atmega4809::hardware;
//! use avr_oxide::alloc::boxed::Box;
//! use avr_oxide::devices::UsesPin;
//! use avr_oxide::devices::debouncer::Debouncer;
//! use avr_oxide::devices::{ Handle, OxideLed, OxideButton, OxideSerialPort };
//! use avr_oxide::hal::generic::serial::{BaudRate, DataBits, Parity, SerialPortMode, StopBits};
//! use avr_oxide::io::Write;
//! use avr_oxide::arduino;
//!
//! #[avr_oxide::main(chip="atmega4809")]
//! pub fn main() {
//!   let supervisor = avr_oxide::oxide::instance();
//!   let hardware = hardware::instance();
//!   let arduino = arduino::nanoevery::Arduino::from(hardware);
//!
//!   // Configure the serial port early so we can get any panic!() messages
//!   let mut serial= OxideSerialPort::using_port_and_pins(arduino.usb_serial,
//!                                                        arduino.usb_serial_tx,
//!                                                        arduino.usb_serial_rx).mode(SerialPortMode::Asynch(BaudRate::Baud9600, DataBits::Bits8, Parity::None, StopBits::Bits1));
//!   serial.write(b"Welcome to AVRoxide\n");
//!
//!   let green_led = OxideLed::with_pin(arduino.d7);
//!   let mut green_button = Handle::new(OxideButton::using(Debouncer::with_pin(arduino.a2)));
//!
//!   green_button.on_click(Box::new(move |_pinid, _state|{
//!     green_led.toggle();
//!   }));
//!
//!   // Tell the supervisor which devices to listen to
//!   supervisor.listen_handle(green_button);
//!
//!   // Now enter the event loop
//!   supervisor.run();
//! }
//! ```
//!
//! # Examples and Templates
//! A more comprehensive example program can be found at [https://avroxi.de/post/an-example-program/].
//!
//! 'Empty' templates can be found at the [AVRoxide Templates](https://gitlab.com/snowgoonspub/avr-oxide-templates) gitlab repo,
//! with all the necessary bits and pieces to get up and running quickly.
//!
//! The project homepage is at [avroxi.de](https://avroxi.de), where you'll find
//! more getting-started style guides and documentation.
//!
#![feature(llvm_asm)]
#![feature(abi_avr_interrupt)]
#![feature(naked_functions)]
#![feature(lang_items)]
#![feature(concat_idents)]
#![feature(const_maybe_uninit_assume_init)]
#![feature(maybe_uninit_uninit_array)]
#![feature(maybe_uninit_extra)]
#![feature(maybe_uninit_array_assume_init)]
#![feature(alloc_error_handler)]
#![feature(dropck_eyepatch)]
#![feature(trait_alias)]
#![feature(optimize_attribute)]

// no_std if built for AVR, if built for anything else it'll be for testing
// and then we do want std
#![cfg_attr(target_arch="avr", no_std)]

extern crate self as avr_oxide;

pub mod io;
pub mod devices;
pub mod hal;
pub mod event;
pub mod oxide;
pub mod deviceconsts;
pub mod util;
pub(crate) mod private;
mod mutstatic;

#[cfg(feature="arduino")]
pub mod arduino;

#[cfg(feature="bootable")]
mod boot;

#[cfg(feature="alloc_ftr")]
pub mod alloc;

pub mod time;
pub mod stdout;

pub use oxide_macros::main as main;

/**
 * A macro you can use as a substitute for .unwrap() on Results that will simply panic
 * if the result is an error.  You will want this to avoid hauling in all of
 * the garbage associated with the Debug and Formatter types that comes
 * along with the 'real' unwrap() implementation.  With small EEPROMs/Flash
 * we don't have the room for that luxury.
 */
#[macro_export]
macro_rules! panic_if_err {
  ($result:expr) => {
    match $result {
      Ok(value) => value,
      Err(_) => panic!()
    }
  }
}

/**
 * Same as `panic_if_error!`, but less typing!
 */
#[macro_export]
macro_rules! pie {
  ($result:expr) => {
    match $result {
      Ok(value) => value,
      Err(_) => panic!()
    }
  }
}

/**
 * A macro you can use as a substitute for .unwrap() on Options that will simply
 * panic if the result is None.  You will want this to avoid hauling in all of
 * the garbage associated with the Debug and Formatter types that comes
 * along with the 'real' unwrap() implementation.  With small EEPROMs/Flash
 * we don't have the room for that luxury.
 */
#[macro_export]
macro_rules! panic_if_none {
  ($result:expr) => {
    match $result {
      Some(value) => value,
      None => panic!()
    }
  }
}