// alertled.ino
// MIT License (see file LICENSE)
// LED is active high
#define LED1 12
#define LED2 13
#define LED3 14
//
// AlertLED class to drive LED
//
class AlertLED {
TimerHandle_t thandle = nullptr; // Handle for the timer
volatile bool state; // LED state (on/off)
volatile unsigned count; // Blink counter
unsigned period_ms; // Period in milliseconds
int gpio; // GPIO pin for LED
void reset(bool s); // Internal method to reset values
public:
AlertLED(int gpio, unsigned period_ms = 1000); // Constructor
void alert(); // Start alert
void cancel(); // Stop alert
static void callback(TimerHandle_t th); // Static callback for timer
};
//
// Constructor:
// gpio - GPIO pin to drive LED
// period_ms - Overall period in ms
//
AlertLED::AlertLED(int gpio, unsigned period_ms) {
this->gpio = gpio;
this->period_ms = period_ms;
pinMode(this->gpio, OUTPUT); // Set GPIO as output
digitalWrite(this->gpio, LOW); // Turn LED off initially
}
//
// Internal method to reset values
//
void AlertLED::reset(bool s) {
state = s; // Set LED state
count = 0; // Reset counter
digitalWrite(this->gpio, s ? HIGH : LOW); // Set initial GPIO state
}
//
// Method to start the alert
//
void AlertLED::alert() {
if (!thandle) {
thandle = xTimerCreate(
"alert_tmr",
pdMS_TO_TICKS(period_ms / 20), // Timer period
pdTRUE, // Auto-reload
this, // Timer ID
AlertLED::callback // Callback function
);
assert(thandle); // Ensure timer creation succeeded
}
reset(true); // Initialize alert state
xTimerStart(thandle, portMAX_DELAY); // Start timer
}
//
// Method to stop an alert
//
void AlertLED::cancel() {
if (thandle) {
xTimerStop(thandle, portMAX_DELAY); // Stop timer
digitalWrite(gpio, LOW); // Turn off LED
}
}
//
// Static method, acting as the timer callback
//
void AlertLED::callback(TimerHandle_t th) {
AlertLED *obj = (AlertLED *)pvTimerGetTimerID(th); // Retrieve object pointer
assert(obj->thandle == th);
obj->state ^= true; // Toggle LED state
digitalWrite(obj->gpio, obj->state ? HIGH : LOW);
if (++obj->count >= 5 * 2) { // Reset after 5 blinks
obj->reset(true);
xTimerChangePeriod(th, pdMS_TO_TICKS(obj->period_ms / 20), portMAX_DELAY);
} else if (obj->count == 5 * 2 - 1) { // Adjust for pause
xTimerChangePeriod(
th,
pdMS_TO_TICKS(obj->period_ms / 20 + obj->period_ms / 2),
portMAX_DELAY);
assert(!obj->state); // Ensure LED is off
}
}
//
// Global objects
//
static AlertLED alert1(LED1, 250); // Create AlertLED instance
static AlertLED alert2(LED2, 500);
static AlertLED alert3(LED3, 1000);
static unsigned loop_count = 0; // Loop counter
//
// Initialization
//
void setup() {
// delay(2000); // Allow USB to connect, uncomment for debugging
alert1.alert(); // Start alert
alert2.alert();
alert3.alert();
}
void loop() {
if (loop_count >= 70) {
alert1.alert(); // Restart alert after 70 loops
alert2.alert();
alert3.alert();
loop_count = 0;
}
delay(100); // Wait 100 ms
if (++loop_count >= 50) {
alert1.cancel(); // Stop alert after 50 loops
alert2.cancel();
alert3.cancel();
}
}