Arduino CLI build system with HAL-based test architecture
Build and upload tool (arduino-build.sh): - Compile, upload, and monitor via arduino-cli - Device discovery with USB ID identification (--devices) - Persistent reconnecting serial monitor (--watch) - Split compile/upload workflow (--verify, --upload-only) - First-time setup wizard (--setup) - Comprehensive --help with troubleshooting and RedBoard specs Testable application architecture: - Hardware abstraction layer (lib/hal/) decouples logic from Arduino API - Google Mock HAL for unit tests (exact call verification) - Simulated HAL for system tests (GPIO state, virtual clock, I2C devices) - Example I2C temperature sensor simulator (TMP102) - Host-side test suite via CMake + Google Test (21 tests) Example sketch: - blink/ -- LED blink with button-controlled speed, wired through HAL
This commit is contained in:
88
lib/app/blink_app.h
Normal file
88
lib/app/blink_app.h
Normal file
@@ -0,0 +1,88 @@
|
||||
#ifndef BLINK_APP_H
|
||||
#define BLINK_APP_H
|
||||
|
||||
#include <hal.h>
|
||||
|
||||
/*
|
||||
* BlinkApp -- Testable blink logic, decoupled from hardware.
|
||||
*
|
||||
* Blinks an LED and reads a button. When the button is pressed,
|
||||
* the blink rate doubles (toggles between normal and fast mode).
|
||||
*
|
||||
* All hardware access goes through the injected Hal pointer. This
|
||||
* class has no dependency on Arduino.h and compiles on any host.
|
||||
*/
|
||||
class BlinkApp {
|
||||
public:
|
||||
static constexpr uint8_t DEFAULT_LED_PIN = LED_BUILTIN; // pin 13
|
||||
static constexpr uint8_t DEFAULT_BUTTON_PIN = 2;
|
||||
static constexpr unsigned long SLOW_INTERVAL_MS = 500;
|
||||
static constexpr unsigned long FAST_INTERVAL_MS = 125;
|
||||
|
||||
BlinkApp(Hal* hal,
|
||||
uint8_t led_pin = DEFAULT_LED_PIN,
|
||||
uint8_t button_pin = DEFAULT_BUTTON_PIN)
|
||||
: hal_(hal)
|
||||
, led_pin_(led_pin)
|
||||
, button_pin_(button_pin)
|
||||
, led_state_(LOW)
|
||||
, fast_mode_(false)
|
||||
, last_toggle_ms_(0)
|
||||
, last_button_state_(HIGH) // pulled up, so HIGH = not pressed
|
||||
{}
|
||||
|
||||
// Call once from setup()
|
||||
void begin() {
|
||||
hal_->pinMode(led_pin_, OUTPUT);
|
||||
hal_->pinMode(button_pin_, INPUT_PULLUP);
|
||||
hal_->serialBegin(115200);
|
||||
hal_->serialPrintln("BlinkApp started");
|
||||
last_toggle_ms_ = hal_->millis();
|
||||
}
|
||||
|
||||
// Call repeatedly from loop()
|
||||
void update() {
|
||||
handleButton();
|
||||
handleBlink();
|
||||
}
|
||||
|
||||
// -- Accessors for testing ----------------------------------------------
|
||||
bool ledState() const { return led_state_ == HIGH; }
|
||||
bool fastMode() const { return fast_mode_; }
|
||||
unsigned long interval() const {
|
||||
return fast_mode_ ? FAST_INTERVAL_MS : SLOW_INTERVAL_MS;
|
||||
}
|
||||
|
||||
private:
|
||||
void handleButton() {
|
||||
uint8_t reading = hal_->digitalRead(button_pin_);
|
||||
|
||||
// Detect falling edge (HIGH -> LOW = button press with INPUT_PULLUP)
|
||||
if (last_button_state_ == HIGH && reading == LOW) {
|
||||
fast_mode_ = !fast_mode_;
|
||||
hal_->serialPrintln(fast_mode_ ? "FAST" : "SLOW");
|
||||
}
|
||||
last_button_state_ = reading;
|
||||
}
|
||||
|
||||
void handleBlink() {
|
||||
unsigned long now = hal_->millis();
|
||||
unsigned long target = fast_mode_ ? FAST_INTERVAL_MS : SLOW_INTERVAL_MS;
|
||||
|
||||
if (now - last_toggle_ms_ >= target) {
|
||||
led_state_ = (led_state_ == HIGH) ? LOW : HIGH;
|
||||
hal_->digitalWrite(led_pin_, led_state_);
|
||||
last_toggle_ms_ = now;
|
||||
}
|
||||
}
|
||||
|
||||
Hal* hal_;
|
||||
uint8_t led_pin_;
|
||||
uint8_t button_pin_;
|
||||
uint8_t led_state_;
|
||||
bool fast_mode_;
|
||||
unsigned long last_toggle_ms_;
|
||||
uint8_t last_button_state_;
|
||||
};
|
||||
|
||||
#endif // BLINK_APP_H
|
||||
Reference in New Issue
Block a user