GithubHelp home page GithubHelp logo

avr-tester's Introduction

avr-tester   crates-badge docs-badge

Functional testing framework for AVR firmware, powered by simavr.

tl;dr get your microcontroller's firmware black-box-tested in seconds!

Getting Started

Create a crate dedicated to your project's tests:

$ cargo new yourproject-tests --lib

... add avr-tester as its dependency:

# yourproject-tests/Cargo.toml

[dependencies]
avr-tester = "0.2"

... and, just like that, start writing tests:

// yourproject-tests/src/lib.rs

use avr_tester::*;

fn avr() -> AvrTester {
    AvrTester::atmega328p()
        .with_clock_of_16_mhz()
        .load("../../yourproject/target/atmega328p/release/yourproject.elf")
}

// Assuming `yourproject` 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 yourproject-tests :-)

Note that because AvrTester simulates an actual AVR, you don't have to modify yourproject at all - it's free to use timers, GPIOs etc. and everything should just work ™.

In fact, yourproject doesn't even have to be written in Rust - you can create Rust-based tests for a firmware written in C, Zig or anything else!

Examples

Requirements & supported platforms

See: simavr-ffi.

Roadmap

Following features seem to be supported by simavr, but haven't been yet exposed in AvrTester:

(your firmware can use those features, but 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

AvrTester's integration tests lay in avr-tester/tests - you can run them with:

$ cd avr-tester
$ cargo test

Note that for those tests to work, you might need some additional dependencies:

... on Nix (Linux / MacOS)

$ nix-shell
# and then `cargo test`

... on Ubuntu

$ sudo apt install avr-libc gcc-avr
# and then `cargo test`

License

Copyright (c) 2022 Patryk Wychowaniec [email protected].
Licensed under the MIT license.

avr-tester's People

Contributors

nilclass avatar patryk27 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

avr-tester's Issues

FFI errors on cargo test

Hello @Patryk27, thanks for this crate, I was really glad to see there was a simavr wrapper for my project:

https://github.com/brainstorm/embassy-as5600/tree/avr_tester

But I'm facing some FFI/compile issues before reaching the tests themselves (barebones for now):

$ cargo test
   Compiling embedded-hal v1.0.0
   Compiling critical-section v1.1.2
   Compiling vcell v0.1.3
   Compiling bare-metal v1.0.0
   Compiling nb v1.1.0
   Compiling cfg-if v1.0.0
   Compiling simavr-ffi v0.1.0
   Compiling ufmt-write v0.1.0
   Compiling void v1.0.2
error[E0152]: duplicate lang item in crate `core` (which `rustc_std_workspace_core` depends on): `sized`.
  |
  = note: the lang item is first defined in crate `core` (which `critical_section` depends on)
  = note: first definition in `core` loaded from /home/rvalls/dev/personal/embassy-avr-as5600-encoder/target/avr-atmega2560/debug/deps/libcore-f59a350232ae0162.rmeta
  = note: second definition in `core` loaded from /home/rvalls/dev/personal/embassy-avr-as5600-encoder/target/avr-atmega2560/debug/deps/libcore-3afaea4e527ac9e0.rmeta

error[E0152]: duplicate lang item in crate `core` (which `rustc_std_workspace_core` depends on): `sized`.
  |
  = note: the lang item is first defined in crate `core` (which `vcell` depends on)
  = note: first definition in `core` loaded from /home/rvalls/dev/personal/embassy-avr-as5600-encoder/target/avr-atmega2560/debug/deps/libcore-f59a350232ae0162.rmeta
  = note: second definition in `core` loaded from /home/rvalls/dev/personal/embassy-avr-as5600-encoder/target/avr-atmega2560/debug/deps/libcore-3afaea4e527ac9e0.rmeta

For more information about this error, try `rustc --explain E0152`.
error[E0152]: duplicate lang item in crate `core` (which `rustc_std_workspace_core` depends on): `sized`.
  |
  = note: the lang item is first defined in crate `core` (which `bare_metal` depends on)
  = note: first definition in `core` loaded from /home/rvalls/dev/personal/embassy-avr-as5600-encoder/target/avr-atmega2560/debug/deps/libcore-f59a350232ae0162.rmeta
  = note: second definition in `core` loaded from /home/rvalls/dev/personal/embassy-avr-as5600-encoder/target/avr-atmega2560/debug/deps/libcore-3afaea4e527ac9e0.rmeta

error: could not compile `vcell` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...
error: could not compile `critical-section` (lib) due to 1 previous error
error: could not compile `critical-section` (lib) due to 1 previous error
error[E0152]: duplicate lang item in crate `core` (which `rustc_std_workspace_core` depends on): `sized`.
  |
  = note: the lang item is first defined in crate `core` (which `cfg_if` depends on)
  = note: first definition in `core` loaded from /home/rvalls/dev/personal/embassy-avr-as5600-encoder/target/avr-atmega2560/debug/deps/libcore-f59a350232ae0162.rmeta
  = note: second definition in `core` loaded from /home/rvalls/dev/personal/embassy-avr-as5600-encoder/target/avr-atmega2560/debug/deps/libcore-3afaea4e527ac9e0.rmeta

error: could not compile `bare-metal` (lib) due to 1 previous error
error[E0152]: duplicate lang item in crate `core` (which `rustc_std_workspace_core` depends on): `sized`.
  |
  = note: the lang item is first defined in crate `core` (which `nb` depends on)
  = note: first definition in `core` loaded from /home/rvalls/dev/personal/embassy-avr-as5600-encoder/target/avr-atmega2560/debug/deps/libcore-f59a350232ae0162.rmeta
  = note: second definition in `core` loaded from /home/rvalls/dev/personal/embassy-avr-as5600-encoder/target/avr-atmega2560/debug/deps/libcore-3afaea4e527ac9e0.rmeta

error: could not compile `vcell` (lib) due to 1 previous error
error[E0152]: duplicate lang item in crate `core` (which `rustc_std_workspace_core` depends on): `sized`.
  |
  = note: the lang item is first defined in crate `core` (which `embedded_hal` depends on)
  = note: first definition in `core` loaded from /home/rvalls/dev/personal/embassy-avr-as5600-encoder/target/avr-atmega2560/debug/deps/libcore-f59a350232ae0162.rmeta
  = note: second definition in `core` loaded from /home/rvalls/dev/personal/embassy-avr-as5600-encoder/target/avr-atmega2560/debug/deps/libcore-3afaea4e527ac9e0.rmeta

error: could not compile `cfg-if` (lib) due to 1 previous error
error: could not compile `nb` (lib) due to 1 previous error
error: could not compile `cfg-if` (lib) due to 1 previous error
error[E0152]: duplicate lang item in crate `core` (which `rustc_std_workspace_core` depends on): `sized`.
  |
  = note: the lang item is first defined in crate `core` (which `ufmt_write` depends on)
  = note: first definition in `core` loaded from /home/rvalls/dev/personal/embassy-avr-as5600-encoder/target/avr-atmega2560/debug/deps/libcore-f59a350232ae0162.rmeta
  = note: second definition in `core` loaded from /home/rvalls/dev/personal/embassy-avr-as5600-encoder/target/avr-atmega2560/debug/deps/libcore-3afaea4e527ac9e0.rmeta

error: could not compile `embedded-hal` (lib) due to 1 previous error
error: could not compile `embedded-hal` (lib) due to 1 previous error
error: could not compile `ufmt-write` (lib) due to 1 previous error
error[E0152]: duplicate lang item in crate `core` (which `rustc_std_workspace_core` depends on): `sized`.
  |
  = note: the lang item is first defined in crate `core` (which `void` depends on)
  = note: first definition in `core` loaded from /home/rvalls/dev/personal/embassy-avr-as5600-encoder/target/avr-atmega2560/debug/deps/libcore-f59a350232ae0162.rmeta
  = note: second definition in `core` loaded from /home/rvalls/dev/personal/embassy-avr-as5600-encoder/target/avr-atmega2560/debug/deps/libcore-3afaea4e527ac9e0.rmeta

error: could not compile `void` (lib) due to 1 previous error
error: could not compile `bare-metal` (lib) due to 1 previous error
error: could not compile `nb` (lib) due to 1 previous error
error: could not compile `ufmt-write` (lib) due to 1 previous error
error: failed to run custom build command for `simavr-ffi v0.1.0`

Caused by:
  process didn't exit successfully: `/home/rvalls/dev/personal/embassy-avr-as5600-encoder/target/debug/build/simavr-ffi-5c0c3354040de387/build-script-build` (exit status: 101)
  --- stdout
  cargo:rerun-if-changed=build.rs
  => Building simavr
  make: Nothing to be done for 'libsimavr'.
  cargo:rustc-link-search=/home/rvalls/dev/personal/embassy-avr-as5600-encoder/target/avr-atmega2560/debug/build/simavr-ffi-a1a32d682dd698ec/out/simavr
  cargo:rustc-link-lib=static=simavr
  => Generating simavr bindings
  -> Found header: vendor/simavr/simavr/sim/sim_gdb.h
  -> Found header: vendor/simavr/simavr/sim/avr_usb.h
  -> Found header: vendor/simavr/simavr/sim/sim_elf.h
  -> Found header: vendor/simavr/simavr/sim/sim_utils.h
  -> Found header: vendor/simavr/simavr/sim/sim_io.h
  -> Found header: vendor/simavr/simavr/sim/avr_adc.h
  -> Found header: vendor/simavr/simavr/sim/avr_lin.h
  -> Found header: vendor/simavr/simavr/sim/avr_twi.h
  -> Found header: vendor/simavr/simavr/sim/sim_vcd_file.h
  -> Found header: vendor/simavr/simavr/sim/sim_avr_types.h
  -> Found header: vendor/simavr/simavr/sim/avr_watchdog.h
  -> Found header: vendor/simavr/simavr/sim/avr_spi.h
  -> Found header: vendor/simavr/simavr/sim/avr_bitbang.h
  -> Found header: vendor/simavr/simavr/sim/avr_extint.h
  -> Found header: vendor/simavr/simavr/sim/avr_timer.h
  -> Found header: vendor/simavr/simavr/sim/sim_hex.h
  -> Found header: vendor/simavr/simavr/sim/avr_ioport.h
  -> Found header: vendor/simavr/simavr/sim/avr_acomp.h
  -> Found header: vendor/simavr/simavr/sim/sim_irq.h
  -> Found header: vendor/simavr/simavr/sim/sim_interrupts.h
  -> Found header: vendor/simavr/simavr/sim/sim_regbit.h
  -> Found header: vendor/simavr/simavr/sim/sim_cycle_timers.h
  -> Found header: vendor/simavr/simavr/sim/avr_flash.h
  -> Found header: vendor/simavr/simavr/sim/avr_eeprom.h
  -> Found header: vendor/simavr/simavr/sim/sim_avr.h
  -> Found header: vendor/simavr/simavr/sim/fifo_declare.h
  -> Found header: vendor/simavr/simavr/sim/sim_network.h
  -> Found header: vendor/simavr/simavr/sim/avr_uart.h
  -> Found header: vendor/simavr/simavr/sim/sim_time.h

  --- stderr
  fatal: No names found, cannot describe anything.
  warning: no target microcontroller specified on command line, cannot link standard libraries, please pass -mmcu=<mcu name> [-Wavr-rtlib-linking-quirks]
  ./vendor/simavr/simavr/sim/sim_gdb.h:40:18: error: unknown type name 'avr_t'
  ./vendor/simavr/simavr/sim/sim_gdb.h:42:21: error: unknown type name 'avr_t'
  ./vendor/simavr/simavr/sim/sim_gdb.h:45:23: error: unknown type name 'avr_t'
  ./vendor/simavr/simavr/sim/sim_gdb.h:48:33: error: unknown type name 'avr_t'
  ./vendor/simavr/simavr/sim/sim_gdb.h:48:44: error: unknown type name 'uint16_t'
  ./vendor/simavr/simavr/sim/sim_gdb.h:49:27: error: unknown type name 'avr_t'
  /usr/include/features-time64.h:20:10: fatal error: 'bits/wordsize.h' file not found
  warning: no target microcontroller specified on command line, cannot link standard libraries, please pass -mmcu=<mcu name> [-Wavr-rtlib-linking-quirks], err: false
  ./vendor/simavr/simavr/sim/sim_gdb.h:40:18: error: unknown type name 'avr_t', err: true
  ./vendor/simavr/simavr/sim/sim_gdb.h:42:21: error: unknown type name 'avr_t', err: true
  ./vendor/simavr/simavr/sim/sim_gdb.h:45:23: error: unknown type name 'avr_t', err: true
  ./vendor/simavr/simavr/sim/sim_gdb.h:48:33: error: unknown type name 'avr_t', err: true
  ./vendor/simavr/simavr/sim/sim_gdb.h:48:44: error: unknown type name 'uint16_t', err: true
  ./vendor/simavr/simavr/sim/sim_gdb.h:49:27: error: unknown type name 'avr_t', err: true
  /usr/include/features-time64.h:20:10: fatal error: 'bits/wordsize.h' file not found, err: true
  thread 'main' panicked at /home/rvalls/.cargo/registry/src/index.crates.io-6f17d22bba15001f/simavr-ffi-0.1.0/build.rs:105:10:
  Couldn't generate simavr's bindings: ()
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

I do have all the Ubuntu 23.10 dependencies listed in simavr-ffi and simavr works fine independently for this project.

Before I dig into this more deeply I wanted to ask if you have you seen those errors before or perhaps can spot right away what am I doing wrong?

Thanks in advance!

/cc @jubeormk1

UART starts buffering only after first read?

This is what I experienced: I had a call to avr.uart0().read::<String>() in a test, but the call happened only after a bit of other code ran. The effect was that the output read was incomplete.
At first I thought the buffer size was limited, but then I realized that I was only seeing output that was generated after the first bit of code had finished, and everything works correctly when I added avr.uart0().try_read_byte() before the first call to avr.run().

So, it seems to me that the buffer is only filled after uart0 is first used.

Is this by design or by accident? If it's by design, probably good to document it.

I love this project btw, great work!

PWM?

Does avr-tester provide an PI for testing PWM-driving firmwares? Of course, one way would be to "co-bitbang" (observe bit-by-bit) the output on some PWM pin, but for performance considerations I would hope for something higher-level that would emulate a "DAC", i.e. something that can be queried at a point in the simulation for its frequency and duty cycle.

The context of this is I would like to interactively and in real time simulate a circuit that does one-bit sound synthesis. If I could get access to the frequency and duty cycle of its PWM-driven pins, I could use that information to synthesize a square wave in the simulation environment. But if I had to run the simulation for one cycle, read the one-bit sound output pin, then run the simulation again for one cycle, etc., then this has no chance of producing enough observations in time to fill my output audio buffer.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.