Performance¶
There's a persistent myth in the Arduino world: object-oriented programming means overhead.
Like most myths, this one contains a grain of truth—but only a grain.
The overhead in OOP comes almost exclusively from one feature: virtual methods.
The eva-core-sk library is designed around this reality. Look at how buttons are built:
template <int PIN, int PINMODE, int ACTIVATES_ON>
using PinButton = Button<BinarizeEqDecor<DebounceDecor<DigitalPinReader<PIN, PINMODE>>, ACTIVATES_ON>>;
This entire chain resolves at compile time.
Efficiency Through Composition¶
Multiple Discrete Buttons via One Reader¶
Sometimes you have several discrete buttons but want to handle them through Switch or Button for unified event handling. Create a custom reader that checks each pin and returns a unique code:
#include <evaSwitch.h>
#include <evaTac.h>
#include <evaHandler.h>
using namespace eva;
class MyBankReader {
public:
ButtonBankReader() {
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
}
signed short getValue() {
if (digitalRead(2) == LOW) return 'u'; // Up button
if (digitalRead(3) == LOW) return 'd'; // Down button
if (digitalRead(4) == LOW) return 'l'; // Left button
if (digitalRead(5) == LOW) return 'r'; // Right button
return 0; // No button
}
};
class App {
private:
Switch<DebounceDecor<MyBankReader>> navButtons;
void onButtonPress(void* sender, CallbackInfo cbInfo) {
char button = cbInfo.eventArg; // 'u', 'd', 'l', or 'r'
Serial.print("Pressed: ");
switch(button) {
case 'u': Serial.println("UP"); break;
case 'd': Serial.println("DOWN"); break;
case 'l': Serial.println("LEFT"); break;
case 'r': Serial.println("RIGHT"); break;
}
}
public:
App() : navButtons() {
navButtons.setListener(
new Handler<App>(this, &App::onButtonPress),
ON_PRESS // Only care about presses
);
}
};
void setup() {
Serial.begin(9600);
static App app;
}
void loop() {
eva::tac();
}
What's happening
Pin configuration lives in the reader's constructor—hardware setup stays with the component that owns it. The reader translates physical pins into meaningful codes ('u', 'd', 'l', 'r'). Button handles all the timing—you just react to clean ON_PRESS events with the button identity already decoded.
This approach is highly memory-efficient compared to using multiple Switch objects. On memory-constrained devices like Arduino, this can make the difference between fitting your program or running out of space.
Multiple Paths to the Same Goal¶
The library offers different ways to handle events, each with different trade-offs:
Handler Templates (Convenient)¶
class App{
RepeatTimer pt = {1000, new Handler<App>(this, &App::onTimer)};
void onTimer(void* sender, CallbackInfo cbInfo) {
// Handle event directly
}
};
-
Clean, readable, refactor-friendly
-
Perfect for prototypes and memory consumption careless cases
Direct IHandler Implementation (Minimal)¶
class App : public IHandler {
RepeatTimer pt = {1000, this};
void invoke(void* sender, CallbackInfo cbInfo) override {
// Handle event directly
}
};
- For the cases when RAM matters
Heartbeat Subclass (Periodic simplicity)¶
class App : public Heartbeat {
public:
App(unsigned long periodMs) : Heartbeat(1000) {}
protected:
void onHeartbeat() override {
// Called automatically every 1000ms milliseconds
// No need to manage timers or check millis()
}
};
-
Fixed period set once, never changes (immutable)
-
No timer objects to manage, no handlers to register
-
Perfect for periodic tasks
Tickable Subclass (Tightest control)¶
class App : public Tickable {
void tick() override {
// Called on every loop() iteration
// Do your own timing
return 0;
}
};
-
One virtual call per
loop()iteration -
Maximum control, minimum abstraction
-
Ideal for performance-critical or continuously monitored logic
Choose the Right Tool: Hierarchies Built for Efficiency¶
The library provides class hierarchies that let you pick the exact level of functionality you need—no more, no less.
Buttons: From Lightweight to Feature-Rich¶
| Class | When to Use |
|---|---|
Switch |
For simple active/inactive state tracking |
Button |
When you need click detection (short/long press, click) |
ScrollButton |
For auto-repeating keys (like keyboard keys) |
Timers: From Lightweight to Feature-Rich¶
| Class | When to Use |
|---|---|
DelayTimer |
For one-shot delays and timeouts |
RepeatTimer |
For periodic tasks and heartbeats |
CountdownTimer |
For retry logic and countdown sequences |
Indicators: From Simple to Smart¶
| Class | When to Use |
|---|---|
Indicator |
For basic on/off LED control |
BlinkingIndicator |
When you need blinking with period/duty cycle |
CountdownIndicator |
For N blinks followed by notification |
Choose the right abstraction for each job, and pay only for what you actually need.