# avr-tester   [![crates-badge]][crates-link] [![docs-badge]][docs-link]
[crates-badge]: https://img.shields.io/crates/v/avr-tester.svg
[crates-link]: https://crates.io/crates/avr-tester
[docs-badge]: https://img.shields.io/docsrs/avr-tester
[docs-link]: https://docs.rs/avr-tester
Framework for testing [AVR] binaries, powered by [simavr].
tl;dr get your microcontroller's firmware black-box-tested in seconds!
[AVR]: https://en.wikipedia.org/wiki/AVR_microcontrollers
[simavr]: https://github.com/buserror/simavr
## Getting started
Create a crate dedicated to your firmware's tests:
```shell
$ cargo new firmware-tests --lib
```
... add `avr-tester` as its dependency:
```toml
# firmware-tests/Cargo.toml
[dependencies]
avr-tester = "0.6"
```
... and start writing tests:
```rust
// firmware-tests/src/lib.rs
use avr_tester::*;
fn avr() -> AvrTester {
AvrTester::atmega328p()
.with_clock_of_16_mhz()
.load("../../firmware/target/avr-none/release/firmware.elf")
}
// Assuming `firmware` implements a ROT-13 encoder:
#[test]
fn short_text() {
let mut avr = avr();
// Let's give our firmware a moment to initialize:
avr.run_for_ms(1);
// Now, let's send the string:
avr.uart0().write("Hello, World!");
// ... give the AVR a moment to retrieve it & send back, encoded:
avr.run_for_ms(1);
// ... and, finally, let's assert the outcome:
assert_eq!("Uryyb, Jbeyq!", avr.uart0().read::<String>());
}
#[test]
fn long_text() {
let mut avr = avr();
avr.run_for_ms(1);
avr.uart0().write("Lorem ipsum dolor sit amet, consectetur adipiscing elit");
avr.run_for_ms(10);
assert_eq!(
"Yberz vcfhz qbybe fvg nzrg, pbafrpgrghe nqvcvfpvat ryvg",
avr.uart0().read::<String>(),
);
}
```
... having the tests ready, just run `cargo test` inside `firmware-tests`.
Since AvrTester emulates an actual AVR, you don't have to modify your firmware
at all - it can use timers, GPIOs etc. and everything should just work ™.
In fact, your project doesn't even have to be written in Rust - you can create
Rust tests for a firmware written in C, Zig and anything else!
## Features
- [Analog pins](avr-tester/tests/examples/analog_pins.rs),
- [Custom components](avr-tester/tests/examples/shift_register.rs),
- [Digital pins](avr-tester/tests/examples/digital_pins.rs),
- [SPIs](avr-tester/tests/examples/spi.rs),
- [TWIs](avr-tester/tests/examples/twi.rs) (aka I2C),
- [Timeouts](avr-tester/tests/examples/timeout.rs),
- [UARTs](avr-tester/tests/examples/uart.rs).
See more: [./avr-tester/tests/examples](./avr-tester/tests/examples).
## Supported platforms
See: [simavr-ffi](https://codeberg.org/pwy/simavr-ffi).
## Roadmap
Following features are supported by simavr, but haven't been yet exposed in
AvrTester:
- Interrupts,
- EEPROM,
- Watchdog,
- USB.
Your firmware can use those features, you just won't be able to test them.
## Caveats
- Triggering AVR's sleep mode will cause the Rust code to panic, because the
only way to wake an AVR is to trigger an interrupt and those are not yet
supported.
## Contributing
Pull requests are very much welcome!
### Tests
Use `just test` to test AvrTester (so meta!) -- note that you might need some
additional dependencies:
#### ... using Nix (Linux / Mac)
```shell
$ nix develop
# and then `just test`
```
#### ... on Ubuntu
```shell
$ sudo apt install avr-libc build-essential clang elfutils gcc-avr libelf-dev pkg-config
# and then `just test`
```
See also: [.devcontainer](./.devcontainer).
## License
Copyright (c) 2022 Patryk Wychowaniec <pwychowaniec@pm.me>.
Licensed under the MIT license.