11
Apr
The example below gives a guide to some of the possibilities that AVRoxide offers you as an application developer.
#![no_std]
#![no_main]
use avr_oxide::alloc::vec::Vec;
use avr_oxide::alloc::boxed::Box;
use avr_oxide::{panic_if_err, print, println, pie};
use avr_oxide::devices::debouncer::Debouncer;
use avr_oxide::devices::inverter::Inverter;
use avr_oxide::devices::{UsesPin, OxideMasterClock, OxideLed, OxideButton, OxideSerialPort, OxideWallClock, Handle};
use avr_oxide::devices::button::ButtonState;
use avr_oxide::devices::masterclock::{DelayEvents, TickEvents};
use avr_oxide::devices::serialport::SerialOptions;
use avr_oxide::hal::generic::eeprom::EepromSpace;
use avr_oxide::hal::generic::serial::{BaudRate, DataBits, Parity, SerialPortMode, StopBits};
use avr_oxide::io::{IoError, Read};
use avr_oxide::util::persist::derive::Persist;
use avr_oxide::util::persist::Persist;
use avr_oxide::time::Duration;
use avr_oxide::boards::board;
use avr_oxide::hal::generic::watchdog::WatchdogPeriod;
use avr_oxide::hal::generic::watchdog::WatchdogController;
use avr_oxide::hardware;
use avr_oxide::thread;
// Code ======================================================================
#[derive(Persist)]
#[persist(magicnumber = 2)]
struct MyPersistentData {
number_of_boots: u16,
username: Option<Vec<u8>>
}
impl Default for MyPersistentData {
fn default() -> Self {
MyPersistentData {
number_of_boots: 0,
username: Option::None
}
}
}
/**
* Main function demonstrating the simple on_event based approach to handling
* device IO. This approach requires one of the allocator features to be
* enabled.
*/
#[avr_oxide::main(chip="atmega4809",stacksize=512)]
pub fn main() -> ! {
let supervisor = avr_oxide::oxide::instance();
// Configure the serial port early so we can get any panic!() messages
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)));
let mut options = SerialOptions::default();
options.set_interactive(true);
options.set_lf_to_crlf(true);
options.set_echo(true);
options.set_blocking_read(true);
options.set_read_to_eol(true);
serial.set_options(options);
avr_oxide::stdout::set_stdout_handle(serial.clone());
println!("AVRoxide ATmega4809XPlained On-Device Test App running...");
// Launch a background thread to talk to the user on the serial port
let _jh =
avr_oxide::concurrency::thread::Builder::new().stack_size(256).spawn(move ||{
// Load and save from EEPROM
let eeprom = &mut hardware::nvm::eeprom::instance();
let mut my_data : MyPersistentData = Persist::load_with_or_default(eeprom.reader());
if my_data.number_of_boots == 0 {
println!("It's the first time I've been booted!\n\n");
} else {
println!("I have been booted {} times before.\n\n", my_data.number_of_boots);
}
my_data.number_of_boots += 1;
// Reading from the serial port
let name = read_name_from_serial(&mut serial);
match my_data.username {
Some(oldname) => {
println!("\n\nHmm. The last guy was {}, but hello {} - nice to meet you!",
pie!(core::str::from_utf8(oldname.as_slice())),
pie!(core::str::from_utf8(name.as_slice())));
},
None => {
println!("\n\nWelcome to AVRoxide, {}!\n\n",
pie!(core::str::from_utf8(name.as_slice())));
}
}
my_data.username = Some(name);
panic_if_err!(my_data.save_with(eeprom.writer()));
123
});
// Buttons and LEDs setup
let green_led = Handle::new(OxideLed::with_pin(hardware::port::porta::pin(1)));
let yellow_led = Handle::new(OxideLed::with_pin(hardware::port::porte::pin(3)));
let red_led = OxideLed::with_pin(hardware::port::porte::pin(0));
let blue_led = OxideLed::with_pin(hardware::port::porte::pin(1));
let button0 = Handle::new(OxideButton::using(Inverter::using(Debouncer::with_pin(board::sw0()))));
let button1 = Handle::new(OxideButton::using(Inverter::using(Debouncer::with_pin(board::sw1()))));
// Clock setup
let master_clock = Handle::new(OxideMasterClock::with_timer::<200>(hardware::timer::tcb0::instance()));
let wall_clock = Handle::new(OxideWallClock::with_timer(hardware::timer::rtc::instance()));
// Print the time every time someone clicks SW0
button0.on_click(Box::new(move |_pinid, state|{
match state {
ButtonState::Pressed => {
println!("Total runtime: {:?} seconds", wall_clock.runtime());
avr_oxide::util::debug::print_thread_state();
},
_ => {}
}
}));
// An event handler every time the master clock ticks
master_clock.on_tick(Box::new(move |_timerid, _duration|{
red_led.toggle();
}));
// And another one for the once-a-second wallclock ticks
wall_clock.on_tick(Box::new(move |_timerid, _duration|{
blue_led.toggle();
}));
// Let's trigger a callback that will occur after a delay
wall_clock.after_delay(Duration::from_secs(30), Box::new(move|_timerid|{
println!("Thirty Seconds!\n");
}));
// Tell the supervisor what devices to pay attention to, and then enter
// the main loop.
supervisor.listen_handle(button0);
supervisor.listen_handle(button1);
supervisor.listen_handle(master_clock);
supervisor.listen_handle(wall_clock);
// Let's show a different style of programming - instead of the
// event-oriented style we've been used to, let's use a threaded style
// with blocking I/O methods
let _jh = thread::Builder::new().stack_size(256).spawn(move ||{
let white_led = OxideLed::with_pin(hardware::port::portb::pin(1));
loop {
match button1.wait_for_change() {
ButtonState::Pressed => {
white_led.set_on();
wall_clock.wait(Duration::from_millis(3000));
white_led.set_off();
},
_ => {
}
}
}
});
// Enable the watchdog
let wdt = avr_oxide::hardware::watchdog::instance();
wdt.enable(WatchdogPeriod::Off, WatchdogPeriod::Millis4096);
supervisor.run_with_prehandler(|_event|{
wdt.kick();
true
});
}
pub fn read_name_from_serial<S: Read>(port: &mut S) -> Vec<u8> {
print!("Please enter your name: ");
let mut name : Vec<u8> = Vec::new();
loop {
let mut buf = [ 0u8; 16 ];
let mut done = false;
match port.read(&mut buf) {
Ok(bytes) => {
for i in 0..bytes {
if buf[i] == b'\r' {
done = true;
break;
} else {
name.push(buf[i] as u8);
}
}
}
Err(_e) => {
println!("Error reading name!");
panic!();
}
}
if done {
break;
}
}
name
}