Skip to content

Add simavr-based automated test suite#148

Open
GlassOnTin wants to merge 6 commits intoToyKeeper:trunkfrom
GlassOnTin:simavr-test-suite
Open

Add simavr-based automated test suite#148
GlassOnTin wants to merge 6 commits intoToyKeeper:trunkfrom
GlassOnTin:simavr-test-suite

Conversation

@GlassOnTin
Copy link

@GlassOnTin GlassOnTin commented Dec 10, 2025

Summary

Adds a cycle-accurate AVR emulator test infrastructure using simavr. Tests run actual compiled firmware hex files, providing true integration testing rather than mocked unit tests.

Quick Start

# 1. Clone simavr with ATtiny1634 support
git clone https://github.com/GlassOnTin/simavr.git

# 2. Build simavr
cd simavr/simavr && make && cd ../..

# 3. Build firmware and run tests
cd sim && make test

Requirements

# Ubuntu/Debian
sudo apt install gcc make libelf-dev avr-libc gcc-avr

Test Framework

sim/tests/anduril-test.h/c - Test API providing:

  • Button simulation: anduril_click(), anduril_multi_click(), anduril_button_set()
  • PWM state reading: anduril_get_pwm() returns main2, led3, led4 values
  • Timing control: anduril_run_ticks() advances WDT cycles
  • Test macros: TEST_BEGIN, TEST_PASS, TEST_FAIL, ASSERT

Test Suites (18 tests)

Suite Tests Coverage
test_basic_ui.c 8 On/off, hold, 2C turbo, 4C lockout/unlock
test_ramping.c 6 Ramp up/down, floor/ceiling limits, memory
test_channel_modes.c 4 3C mode switching, persistence, cycling

ATtiny1634 Core

Custom simavr core (sim/simavr-core/) for the ATtiny1634 MCU:

  • 16KB Flash, 1KB SRAM, 256B EEPROM
  • Timer0 (8-bit), Timer1 (16-bit) with PWM support
  • GPIO ports A, B, C with proper pin mapping

Usage

make test           # Run all 18 tests
make test-basic     # Run basic UI tests only
make test-ramping   # Run ramping tests only
make test-channel   # Run channel mode tests only
make test-verbose   # Run with debug output

Directory Structure

anduril/
├── sim/
│   ├── README.md           # Full documentation
│   ├── Makefile
│   ├── tests/
│   │   ├── anduril-test.h  # Test framework API
│   │   ├── anduril-test.c  # Test framework implementation
│   │   ├── test_basic_ui.c
│   │   ├── test_ramping.c
│   │   └── test_channel_modes.c
│   └── simavr-core/
│       └── sim_tiny1634.*  # ATtiny1634 core
├── simavr/                 # Clone here (sibling to sim/)
└── hex/
    └── anduril.*.hex       # Compiled firmware

Dependencies

Requires simavr with ATtiny1634 support. Until upstream merges the core:

Test Plan

  • All 18 tests pass on D4K-3ch firmware
  • Tests detect regressions (verified by intentionally breaking firmware)
  • Verbose mode shows button presses and interrupt timing
  • README with setup instructions and API documentation
  • CI integration (future work)

Adds a cycle-accurate AVR emulator test infrastructure using simavr
with ATtiny1634 support. Tests run actual compiled firmware hex files,
providing true integration testing of the firmware.

## Test Framework (sim/tests/)

- anduril-test.h/c: Test API with button simulation, PWM reading, timing
- Macros: TEST_BEGIN, TEST_PASS, TEST_FAIL, ASSERT
- Helpers: anduril_click(), anduril_multi_click(), anduril_get_pwm()

## Test Suites (18 tests total)

- test_basic_ui.c (8 tests): on/off, hold, turbo, lockout
- test_ramping.c (6 tests): ramp up/down, floor/ceiling, memory
- test_channel_modes.c (4 tests): 3C switching, persistence, cycling

## ATtiny1634 Core (sim/simavr-core/)

Custom simavr core for ATtiny1634 MCU used in Anduril flashlights:
- 16KB Flash, 1KB SRAM, 256B EEPROM
- Timer0 (8-bit), Timer1 (16-bit) with PWM
- GPIO ports A, B, C

## Makefile Targets

- make test: Run all 18 tests
- make test-basic/ramping/channel: Run individual suites
- make test-verbose: Debug output with button/interrupt traces

## Dependencies

Requires simavr with ATtiny1634 core support:
- Fork: https://github.com/GlassOnTin/simavr
- Upstream PR: buserror/simavr#568
@ToyKeeper
Copy link
Owner

Hi, it looks like you've been doing some really cool stuff with Anduril. Thanks!

I'm looking forward to checking it out in detail, and hopefully merging it. It might take me a while though, since I've got a lot going on and have a lot to catch up on. Just wanted to let you know, for now, that I see it and it is not being ignored. I'm just slow.

The simavr stuff in particular seems really nice. I briefly tried to simulate things once for testing purposes, and didn't get very far... so it's awesome to see that concept actually implemented. I also set up an automated hardware testing thing at one point, but it didn't end up being very practical for this purpose because button-press and measurement latency was too high, so it never got past an early proof of concept. So I've just been testing manually all this time.

Automated tests will be particularly relevant for some big upcoming changes I'm hoping to do. Specifically, I'd like to expand the simple/advanced mode concept so the user can instead choose from several entirely different interfaces. But that'll greatly expand the amount of testing needed, so automation is very welcome.

@GlassOnTin
Copy link
Author

I'd be happy to write a few tests or discuss them with you when you're looking to implement your new features.

Test Driven Development is a helpful strategy at times when pushing the feature boundaries!

@SiteRelEnby
Copy link
Contributor

Taking a look into this PR, this has been vaguely on my mind for ages but no real experience with simavr, got a bit of time at the moment so might take a dive into it.

SiteRelEnby and others added 2 commits December 26, 2025 17:34
This commit adds a protocol-based simulator interface for external UIs and
fixes a critical bug where the ADC was reading 0V, causing spurious low
voltage protection (LVP) stepdowns.

New Features:
- sim-interface: Protocol-based interface exposing Anduril simulator over
  stdin/stdout for integration with external UIs (Python, web, etc.)
- PROTOCOL.md: Complete documentation of the text-based protocol
- Temperature simulation: SETTEMP/GETTEMP commands with proper sensor emulation
- EEPROM access: GETEEPROM, DUMPEEPROM, SETEEPROM for state inspection
- Debug mode: DEBUG=1 environment variable enables detailed ADC/PWM logging
- Voltage control: SETVOLTAGE command for battery voltage simulation

Critical Bug Fixes:
- Fixed ADC reading 0V which caused firmware to think battery was dead,
  triggering constant LVP stepdowns from turbo
- Root cause: ADC values must be injected BEFORE simavr samples them, not
  in response to ADC_IRQ_OUT_TRIGGER
- Discovered simavr requires 3x voltage scaling for correct ADC conversions
  (e.g., 730mV input requires 2190mV to get correct 678 ADC result)
- Fixed ADC register addresses for ATtiny1634:
  ADCL=0x20, ADCH=0x21, ADCSRA=0x23, ADMUX=0x24

Technical Details:
- ADC now properly reads battery voltage (e.g., 3.7V → 730mV after divider
  → 678 ADC counts with 1.1V ref)
- Temperature sensor emulation uses linear mapping: 25°C = 300mV, ±10mV/°C
- Protocol supports both simple commands (CLICK, RESET) and parameterized
  commands (RUN:50, SETVOLTAGE:3700)
- Responses: OK, ERROR:msg, PWM:main2,led3,led4, EEPROM:hexdata, BYE

Protocol Command Summary:
  INIT:hexfile - Initialize simulator with firmware
  RESET - Reset AVR to power-on state
  CLICK - Single button click (~80ms press + ~128ms gap)
  MULTI:N - Multi-click sequence (2C, 3C, etc.)
  HOLD:N - Press and hold for N WDT ticks (~16ms each)
  PRESS/RELEASE - Manual button control
  RUN:N - Advance simulation by N ticks
  GETPWM - Read current PWM values
  SETVOLTAGE:mV - Set battery voltage (2000-4500mV)
  SETTEMP:C - Set temperature (-40 to 85°C)
  GETTEMP - Read current temperature
  GETEEPROM:offset,len - Read EEPROM bytes
  DUMPEEPROM - Read all 256 EEPROM bytes
  SETEEPROM:offset,value - Write EEPROM byte
  QUIT - Shutdown simulator

Files Changed:
- sim/Makefile: Added sim-interface build target
- sim/sim-interface.c: New protocol handler (479 lines)
- sim/PROTOCOL.md: Complete protocol documentation (711 lines)
- sim/tests/anduril-test.c: Fixed ADC injection, added temp/EEPROM support
- sim/tests/anduril-test.h: Added new API functions

Testing:
  make sim-interface
  echo -e "INIT:../hex/anduril.hex\nRESET\nSETVOLTAGE:3700\nRUN:50\nGETPWM\nQUIT" | ./sim-interface

This enables building external UIs (Python/Tkinter, web-based, etc.) that
communicate with the simulator via a simple text protocol over stdin/stdout.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
  - Move last_adcsra variable declaration outside #if TEST_VERBOSE block
    to fix undeclared variable error with stricter GCC 14 compiler
  - Use dynamic platform detection for simavr obj directory instead of
    hardcoded x86_64-linux-gnu (fixes Void Linux and other distros)"
@SiteRelEnby
Copy link
Contributor

@GlassOnTin really nice work, managed to build some interesting stuff on top of this already. Did run into a use-after-free that caused a few heisenbugs on our part, opened a PR against simavr here: buserror/simavr#569 - would appreciate it if you could test with your toolchain to see if it works with that fix as a sanity check as this is way outside my usual context of dev work 😅

SiteRelEnby and others added 3 commits January 11, 2026 21:09
The CLICK_GAP_TICKS delay made UI clicks feel unresponsive and prevented
rapid clicks from registering as multi-clicks (2C, 3C, etc).

Now anduril_click() only simulates the button press duration, letting
the UI/user control click timing naturally. Multi-click functions still
use gaps for automated testing.
Extend simulator to read and report RGB aux LED states (PA5/PA4/PA3).
Each aux LED can be: off (0), low via pullup (1), or high (2).

Changes:
- Extended pwm_state_t to include aux_r, aux_g, aux_b fields
- Updated anduril_get_pwm() to read DDRA and PUEA registers
- Extended GETPWM protocol to output 6 values instead of 3
- Detects off/low/high states by checking DDR and pullup registers

This enables UI visualization of aux LED states including low-mode
operation using the MCU's internal pullup resistors.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add interactive simulator interface and fix critical ADC bug, fix tests for gcc 14.x
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants