24
Dec
It’s a tiny bit early for a Christmas present here, but I guess it’s already Christmas Day somewhere in the world - so, I’m happy to announce AVRoxide has reached something of a milestone: Release 0.1.0.
It’s still very much a work-in-progress, but we’re at a point where I think the event handling mechanism is basically something I’m happy with, and where - with all the caveats elsewhere about a working toolchain and gotchas and warnings - it is actually possible to build and run an application using AVRoxide.
An example application
You can see the code in the source repo, in the ondevice-testapp
directory,
or here below in all its glory…
- Happy Christmas! *
main.rs
#![no_std]
#![no_main]
use avr_oxide::alloc::vec::Vec;
use avr_oxide::alloc::boxed::Box;
use avr_oxide::hal::atmega4809::hardware;
use avr_oxide::{arduino, panic_if_err};
use avr_oxide::devices::debouncer::Debouncer;
use avr_oxide::devices::{OxideMasterClock, OxideLed, OxideButton, OxideSerialPort, OxideWallClock};
use avr_oxide::devices::masterclock::TickEvents;
use avr_oxide::hal::generic::debugled::DebugLed;
use avr_oxide::hal::generic::serial::{BaudRate, DataBits, Parity, SerialPortMode, StopBits};
use avr_oxide::io::{IoError, Write};
// Code ======================================================================
/**
* 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")]
pub fn main() -> ! {
let supervisor = avr_oxide::oxide::instance();
// Get access to our hardware
let hardware = hardware::instance();
// Translate it into the more familiar Arduino pin naming
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));
panic_if_err!(serial.write(b"AVRoxide On-Device Test App running...\n"));
panic_if_err!(test_memory_allocator(&mut serial));
// Buttons and LEDs setup
let mut green_button = Box::new(OxideButton::using(Debouncer::with_pin(arduino.a2)));
let mut yellow_button = Box::new(OxideButton::using(Debouncer::with_pin(arduino.a3)));
let green_led = OxideLed::with_pin(arduino.d7);
let yellow_led = OxideLed::with_pin(arduino.d8);
let red_led = OxideLed::with_pin(arduino.d11);
let blue_led = OxideLed::with_pin(arduino.d12);
// Clock setup
let mut master_clock = Box::new(OxideMasterClock::with_timer::<20>(arduino.timer0));
let mut wall_clock = Box::new(OxideWallClock::with_timer(arduino.rtc));
// Set an event handler to be called every time someone presses the button
green_button.on_click(Box::new(move |pinid, state|{
green_led.toggle();
}));
// An event handler every time the master clock ticks
master_clock.on_tick(Box::new(move |timerid, ticks|{
red_led.toggle();
}));
// And another one for the once-a-second wallclock ticks
wall_clock.on_tick(Box::new(move |timerid, seconds|{
blue_led.toggle();
}));
// Tell the supervisor what devices to pay attention to, and then enter
// the main loop.
supervisor.listen(green_button);
supervisor.listen(master_clock);
supervisor.listen(wall_clock);
supervisor.run();
}
fn print_u16<W: Write>(out: &mut W, val: u16) -> Result<(),IoError> {
if val > 9 {
print_u16(out,val/10)?;
}
let buf = [((val % 10) + 0x30) as u8];
out.write(&buf)?;
Ok(())
}
/**
* Do a test of the memory allocation routines. We need this to find the
* <strikethrough>myriad code generation bugs in LLVM :facepalm:</strikethrough>
* ...to find the bugs in my own idiotic code. :facepalm: :innocent:
*/
fn test_memory_allocator<W: Write>(out: &mut W) -> Result<(),IoError> {
out.write(b"Memory allocation test\n")?;
let mut failed:bool = false;
// The stepsize of 13 is a reasonable compromise in terms of how long it
// takes to run a complete test.
for blocksize in (16u16..128).step_by(13) {
out.write(b"Blocksize ")?;
print_u16(out,blocksize)?;
out.write(b"\n")?;
let mut blocks : Vec<Vec<u8>> = Vec::with_capacity(avr_oxide::deviceconsts::memory::alloc::HEAPSIZE/16);
out.write(b" Allocating:\n")?;
let mut i:u16 = 0;
loop {
let mut block = Vec::new();
if block.try_reserve(blocksize as usize).is_ok(){
for _j in 0u16..blocksize {
block.push(0xde);
}
blocks.push(block);
} else {
out.write(b" Out of memory at block ")?;
print_u16(out, i)?;
out.write(b"\n")?;
// We ran out of space to allocate blocks
break;
}
i += 1;
}
out.write(b" Validating:\n")?;
i = 0;
for block in blocks {
for char in block {
if char != 0xde {
out.write(b" Block ")?;
print_u16(out, i)?;
out.write(b" *** BLOCK CORRUPTED ***\n")?;
failed = true;
break;
}
}
i += 1;
}
}
match failed {
true => {
out.write(b"\nMemory allocation tests completed with failures.\n\n")?;
panic!()
}
false => out.write(b"\nMemory allocation tests completed with success.\n\n")?
};
Ok(())
}