#ifndef MOCK_ARDUINO_H #define MOCK_ARDUINO_H /* * mock_arduino.h -- Arduino API mock for host-side (x86_64) testing. * * Provides the core Arduino vocabulary (types, constants, functions, * Serial) so that application code compiles and runs on a PC without * any AVR toolchain. All state is captured in a global MockArduino * instance that tests can inspect and manipulate. * * This file replaces in the test build. The CMakeLists.txt * adds the mocks/ directory to the include path, so any code that does * #include will pick up this file instead. * * Usage in tests: * * #include "mock_arduino.h" * * TEST(MyTest, ReadsAnalogSensor) { * mock_arduino_reset(); * mock_arduino_set_analog(A0, 512); * int val = analogRead(A0); * EXPECT_EQ(val, 512); * } * * Generated by Anvil -- https://github.com/nexus-workshops/anvil */ #include #include #include #include #include #include #include // ============================================================================ // Arduino types // ============================================================================ typedef uint8_t byte; typedef uint16_t word; typedef bool boolean; // ============================================================================ // Pin mode and logic constants // ============================================================================ #ifndef INPUT #define INPUT 0x0 #define OUTPUT 0x1 #define INPUT_PULLUP 0x2 #endif #ifndef LOW #define LOW 0x0 #define HIGH 0x1 #endif #ifndef LED_BUILTIN #define LED_BUILTIN 13 #endif // Analog pins (map to digital pin numbers, Uno layout by default) #ifndef A0 #define A0 14 #define A1 15 #define A2 16 #define A3 17 #define A4 18 #define A5 19 #define A6 20 #define A7 21 // Extended for Mega #define A8 54 #define A9 55 #define A10 56 #define A11 57 #define A12 58 #define A13 59 #define A14 60 #define A15 61 #endif // ============================================================================ // Math constants // ============================================================================ #ifndef PI #define PI 3.14159265358979323846 #define HALF_PI 1.57079632679489661923 #define TWO_PI 6.28318530717958647692 #define DEG_TO_RAD 0.017453292519943295 #define RAD_TO_DEG 57.29577951308232 #endif // ============================================================================ // Interrupt constants // ============================================================================ #ifndef CHANGE #define CHANGE 1 #define FALLING 2 #define RISING 3 #endif // ============================================================================ // MockArduino -- global state for all Arduino functions // ============================================================================ static const int MOCK_ARDUINO_MAX_PINS = 70; // Enough for Mega struct MockArduinoState { // Pin state uint8_t pin_modes[MOCK_ARDUINO_MAX_PINS]; int pin_digital[MOCK_ARDUINO_MAX_PINS]; // digital values int pin_analog[MOCK_ARDUINO_MAX_PINS]; // analog read values (0-1023) int pin_pwm[MOCK_ARDUINO_MAX_PINS]; // analogWrite values (0-255) // Timing unsigned long millis_value; unsigned long micros_value; // Serial capture std::string serial_output; std::vector serial_input; unsigned long serial_baud; bool serial_begun; // Interrupt tracking struct InterruptHandler { void (*callback)(); int mode; bool attached; }; InterruptHandler interrupts[8]; // INT0-INT7 bool interrupts_enabled; // GPIO event log struct GpioEvent { unsigned long timestamp; uint8_t pin; int value; bool is_analog; // true = analogWrite, false = digitalWrite }; std::vector gpio_log; // Delay log (to verify timing behavior) std::vector delay_log; }; // Global state -- tests access this directly extern MockArduinoState _mock_arduino; // ============================================================================ // Test control API -- call from tests to set up / inspect state // ============================================================================ // Reset all state to defaults void mock_arduino_reset(); // Clock control void mock_arduino_advance_millis(unsigned long ms); void mock_arduino_set_millis(unsigned long ms); // Input injection void mock_arduino_set_digital(uint8_t pin, int value); void mock_arduino_set_analog(uint8_t pin, int value); // Output inspection int mock_arduino_get_digital(uint8_t pin); int mock_arduino_get_pwm(uint8_t pin); uint8_t mock_arduino_get_pin_mode(uint8_t pin); // Serial inspection const std::string& mock_arduino_serial_output(); void mock_arduino_inject_serial(const std::string& data); void mock_arduino_clear_serial(); // GPIO log const std::vector& mock_arduino_gpio_log(); void mock_arduino_clear_gpio_log(); int mock_arduino_count_writes(uint8_t pin, int value); // ============================================================================ // Arduino core functions -- called by application code // ============================================================================ // Digital I/O void pinMode(uint8_t pin, uint8_t mode); void digitalWrite(uint8_t pin, uint8_t val); int digitalRead(uint8_t pin); // Analog I/O int analogRead(uint8_t pin); void analogWrite(uint8_t pin, int val); // Timing unsigned long millis(); unsigned long micros(); void delay(unsigned long ms); void delayMicroseconds(unsigned long us); // Math helpers long map(long value, long fromLow, long fromHigh, long toLow, long toHigh); long constrain(long value, long low, long high); long random(long max); long random(long min, long max); void randomSeed(unsigned long seed); // Interrupts void attachInterrupt(uint8_t interrupt, void (*callback)(), int mode); void detachInterrupt(uint8_t interrupt); void noInterrupts(); void interrupts(); uint8_t digitalPinToInterrupt(uint8_t pin); // Bit manipulation (Arduino built-ins) #ifndef bitRead #define bitRead(value, bit) (((value) >> (bit)) & 0x01) #define bitSet(value, bit) ((value) |= (1UL << (bit))) #define bitClear(value, bit) ((value) &= ~(1UL << (bit))) #define bitWrite(value, bit, b) ((b) ? bitSet(value, bit) : bitClear(value, bit)) #define bit(n) (1UL << (n)) #define lowByte(w) ((uint8_t)((w) & 0xFF)) #define highByte(w) ((uint8_t)((w) >> 8)) #endif // ============================================================================ // MockSerial -- replaces Serial global // ============================================================================ class MockSerial { public: void begin(unsigned long baud); void end(); size_t print(const char* str); size_t print(char c); size_t print(int val, int base = 10); size_t print(unsigned int val, int base = 10); size_t print(long val, int base = 10); size_t print(unsigned long val, int base = 10); size_t print(double val, int decimals = 2); size_t print(const std::string& str); size_t println(const char* str = ""); size_t println(char c); size_t println(int val, int base = 10); size_t println(unsigned int val, int base = 10); size_t println(long val, int base = 10); size_t println(unsigned long val, int base = 10); size_t println(double val, int decimals = 2); size_t println(const std::string& str); size_t write(uint8_t b); size_t write(const uint8_t* buf, size_t len); int available(); int read(); int peek(); void flush(); explicit operator bool() const { return _mock_arduino.serial_begun; } }; // Global Serial instance (matches Arduino's global) extern MockSerial Serial; // ============================================================================ // Minimal String class (Arduino-compatible subset) // ============================================================================ class String { public: String() : data_() {} String(const char* s) : data_(s ? s : "") {} String(const std::string& s) : data_(s) {} String(char c) : data_(1, c) {} String(int val, int base = 10); String(unsigned int val, int base = 10); String(long val, int base = 10); String(unsigned long val, int base = 10); String(double val, int decimals = 2); // Access unsigned int length() const { return (unsigned int)data_.size(); } const char* c_str() const { return data_.c_str(); } char charAt(unsigned int index) const; void setCharAt(unsigned int index, char c); // Comparison bool equals(const String& other) const { return data_ == other.data_; } bool equalsIgnoreCase(const String& other) const; int compareTo(const String& other) const; // Search int indexOf(char ch, unsigned int fromIndex = 0) const; int indexOf(const String& str, unsigned int fromIndex = 0) const; int lastIndexOf(char ch) const; // Modification String substring(unsigned int from, unsigned int to = 0xFFFFFFFF) const; void toLowerCase(); void toUpperCase(); void trim(); void replace(const String& from, const String& to); void remove(unsigned int index, unsigned int count = 1); // Conversion long toInt() const; float toFloat() const; double toDouble() const; // Concatenation String& concat(const String& other); String& concat(const char* s); String& concat(char c); String& concat(int val); String& concat(unsigned long val); // Operators String& operator+=(const String& rhs) { return concat(rhs); } String& operator+=(const char* rhs) { return concat(rhs); } String& operator+=(char rhs) { return concat(rhs); } String operator+(const String& rhs) const; bool operator==(const String& rhs) const { return data_ == rhs.data_; } bool operator==(const char* rhs) const { return data_ == (rhs ? rhs : ""); } bool operator!=(const String& rhs) const { return data_ != rhs.data_; } bool operator<(const String& rhs) const { return data_ < rhs.data_; } char operator[](unsigned int index) const; char& operator[](unsigned int index); // Interop with std::string operator std::string() const { return data_; } private: std::string data_; }; // ============================================================================ // Arduino.h compatibility alias // ============================================================================ // So that #include resolves to this file via include path, // we provide this comment as a note. The CMakeLists.txt adds the mocks/ // directory to the include path, so #include becomes: // #include "mock_arduino.h" (via the Arduino.h shim in this directory) #endif // MOCK_ARDUINO_H