Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 8 additions & 28 deletions examples/companion_radio/ui-new/UITask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,6 @@
#endif
#define BOOT_SCREEN_MILLIS 3000 // 3 seconds

#ifdef PIN_STATUS_LED
#define LED_ON_MILLIS 20
#define LED_ON_MSG_MILLIS 200
#define LED_CYCLE_MILLIS 4000
#endif

#define LONG_PRESS_MILLIS 1200

#ifndef UI_RECENT_LIST_SIZE
Expand Down Expand Up @@ -577,6 +571,10 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
vibration.begin();
#endif

#ifdef PIN_STATUS_LED
status_led.begin();
#endif

ui_started_at = millis();
_alert_expiry = 0;

Expand Down Expand Up @@ -645,27 +643,6 @@ void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, i
}
}

void UITask::userLedHandler() {
#ifdef PIN_STATUS_LED
int cur_time = millis();
if (cur_time > next_led_change) {
if (led_state == 0) {
led_state = 1;
if (_msgcount > 0) {
last_led_increment = LED_ON_MSG_MILLIS;
} else {
last_led_increment = LED_ON_MILLIS;
}
next_led_change = cur_time + last_led_increment;
} else {
led_state = 0;
next_led_change = cur_time + LED_CYCLE_MILLIS - last_led_increment;
}
digitalWrite(PIN_STATUS_LED, led_state == LED_STATE_ON);
}
#endif
}

void UITask::setCurrScreen(UIScreen* c) {
curr = c;
_next_refresh = 100;
Expand Down Expand Up @@ -776,7 +753,10 @@ void UITask::loop() {
_next_refresh = 100; // trigger refresh
}

userLedHandler();
#ifdef PIN_STATUS_LED
status_led.setAlert(_msgcount > 0);
status_led.loop();
#endif

#ifdef PIN_BUZZER
if (buzzer.isPlaying()) buzzer.loop();
Expand Down
16 changes: 8 additions & 8 deletions examples/companion_radio/ui-new/UITask.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
#include <Arduino.h>
#include <helpers/sensors/LPPDataHelpers.h>

#ifndef LED_STATE_ON
#define LED_STATE_ON 1
#ifdef PIN_STATUS_LED
#include <helpers/StatusLED.h>
#endif

#ifdef PIN_BUZZER
Expand Down Expand Up @@ -39,9 +39,7 @@ class UITask : public AbstractUITask {
unsigned long ui_started_at, next_batt_chck;
int next_backlight_btn_check = 0;
#ifdef PIN_STATUS_LED
int led_state = 0;
int next_led_change = 0;
int last_led_increment = 0;
StatusLED status_led;
#endif

#ifdef PIN_USER_BTN_ANA
Expand All @@ -53,8 +51,6 @@ class UITask : public AbstractUITask {
UIScreen* msg_preview;
UIScreen* curr;

void userLedHandler();

// Button action handlers
char checkDisplayOn(char c);
char handleLongPress(char c);
Expand All @@ -65,7 +61,11 @@ class UITask : public AbstractUITask {

public:

UITask(mesh::MainBoard* board, BaseSerialInterface* serial) : AbstractUITask(board, serial), _display(NULL), _sensors(NULL) {
UITask(mesh::MainBoard* board, BaseSerialInterface* serial) : AbstractUITask(board, serial), _display(NULL), _sensors(NULL)
#ifdef PIN_STATUS_LED
, status_led(PIN_STATUS_LED)
#endif
{
next_batt_chck = _next_refresh = 0;
ui_started_at = 0;
curr = NULL;
Expand Down
45 changes: 11 additions & 34 deletions examples/companion_radio/ui-orig/UITask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,6 @@
#define AUTO_OFF_MILLIS 15000 // 15 seconds
#define BOOT_SCREEN_MILLIS 3000 // 3 seconds

#ifdef PIN_STATUS_LED
#define LED_ON_MILLIS 20
#define LED_ON_MSG_MILLIS 200
#define LED_CYCLE_MILLIS 4000
#endif

#ifndef USER_BTN_PRESSED
#define USER_BTN_PRESSED LOW
#endif
Expand Down Expand Up @@ -59,6 +53,10 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
buzzer.quiet(_node_prefs->buzzer_quiet);
#endif

#ifdef PIN_STATUS_LED
status_led.begin();
#endif

// Initialize digital button if available
#ifdef PIN_USER_BTN
_userButton = new Button(PIN_USER_BTN, USER_BTN_PRESSED);
Expand Down Expand Up @@ -260,33 +258,8 @@ void UITask::renderCurrScreen() {
_need_refresh = false;
}

void UITask::userLedHandler() {
#ifdef PIN_STATUS_LED
static int state = 0;
static int next_change = 0;
static int last_increment = 0;

int cur_time = millis();
if (cur_time > next_change) {
if (state == 0) {
state = 1;
if (_msgcount > 0) {
last_increment = LED_ON_MSG_MILLIS;
} else {
last_increment = LED_ON_MILLIS;
}
next_change = cur_time + last_increment;
} else {
state = 0;
next_change = cur_time + LED_CYCLE_MILLIS - last_increment;
}
digitalWrite(PIN_STATUS_LED, state == LED_STATE_ON);
}
#endif
}

/*
hardware-agnostic pre-shutdown activity should be done here
/*
hardware-agnostic pre-shutdown activity should be done here
*/
void UITask::shutdown(bool restart){

Expand Down Expand Up @@ -322,7 +295,11 @@ void UITask::loop() {
_userButtonAnalog->update();
}
#endif
userLedHandler();

#ifdef PIN_STATUS_LED
status_led.setAlert(_msgcount > 0);
status_led.loop();
#endif

#ifdef PIN_BUZZER
if (buzzer.isPlaying()) buzzer.loop();
Expand Down
13 changes: 11 additions & 2 deletions examples/companion_radio/ui-orig/UITask.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
#ifdef PIN_BUZZER
#include <helpers/ui/buzzer.h>
#endif
#ifdef PIN_STATUS_LED
#include <helpers/StatusLED.h>
#endif

#include "../AbstractUITask.h"
#include "../NodePrefs.h"
Expand All @@ -30,6 +33,9 @@ class UITask : public AbstractUITask {
bool _need_refresh = true;
bool _displayWasOn = false; // Track display state before button press
unsigned long ui_started_at;
#ifdef PIN_STATUS_LED
StatusLED status_led;
#endif

// Button handlers
#ifdef PIN_USER_BTN
Expand All @@ -40,7 +46,6 @@ class UITask : public AbstractUITask {
#endif

void renderCurrScreen();
void userLedHandler();
void renderBatteryIndicator(uint16_t batteryMilliVolts);

// Button action handlers
Expand All @@ -54,7 +59,11 @@ class UITask : public AbstractUITask {

public:

UITask(mesh::MainBoard* board, BaseSerialInterface* serial) : AbstractUITask(board, serial), _display(NULL), _sensors(NULL) {
UITask(mesh::MainBoard* board, BaseSerialInterface* serial) : AbstractUITask(board, serial), _display(NULL), _sensors(NULL)
#ifdef PIN_STATUS_LED
, status_led(PIN_STATUS_LED)
#endif
{
_next_refresh = 0;
ui_started_at = 0;
}
Expand Down
12 changes: 12 additions & 0 deletions examples/simple_repeater/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@

#include "MyMesh.h"

#ifdef PIN_STATUS_LED
#include <helpers/StatusLED.h>
static StatusLED status_led(PIN_STATUS_LED);
#endif

#ifdef DISPLAY_CLASS
#include "UITask.h"
static UITask ui_task(display);
Expand Down Expand Up @@ -35,6 +40,10 @@ void setup() {
delay(5000);
#endif

#ifdef PIN_STATUS_LED
status_led.begin();
#endif

// For power saving
lastActive = millis(); // mark last active time since boot

Expand Down Expand Up @@ -133,6 +142,9 @@ void loop() {
ui_task.loop();
#endif
rtc_clock.tick();
#ifdef PIN_STATUS_LED
status_led.loop();
#endif

if (the_mesh.getNodePrefs()->powersaving_enabled && !the_mesh.hasPendingWork()) {
#if defined(NRF52_PLATFORM)
Expand Down
51 changes: 51 additions & 0 deletions src/helpers/StatusLED.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#pragma once

#include <Arduino.h>

#ifndef LED_ON_MILLIS
#define LED_ON_MILLIS 20
#endif
#ifndef LED_ON_MSG_MILLIS
#define LED_ON_MSG_MILLIS 200
#endif
#ifndef LED_CYCLE_MILLIS
#define LED_CYCLE_MILLIS 4000
#endif
#ifndef LED_STATE_ON
#define LED_STATE_ON 1
#endif

class StatusLED {
uint8_t _pin;
uint8_t _active;
unsigned long _next_change = 0;
unsigned long _last_on_duration = 0;
uint8_t _state = 0;
bool _alert = false;

public:
StatusLED(uint8_t pin, uint8_t active = LED_STATE_ON) : _pin(pin), _active(active) { }

void begin() {
pinMode(_pin, OUTPUT);
digitalWrite(_pin, _active ? LOW : HIGH); // Start with LED off
}

void setAlert(bool alert) { _alert = alert; }
bool isAlert() const { return _alert; }

void loop() {
unsigned long now = millis();
if (now > _next_change) {
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

millis() rollover isn’t handled safely here: if (now > _next_change) will break after wraparound (~49 days). Use a wrap-safe comparison like (long)(now - _next_change) >= 0 (and keep _next_change as unsigned long) so the blink timing continues working across rollovers (see VolatileRTCClock::tick using unsigned subtraction in src/helpers/ArduinoHelpers.h).

Suggested change
if (now > _next_change) {
if ((long)(now - _next_change) >= 0) {

Copilot uses AI. Check for mistakes.
if (_state == 0) {
_state = 1;
_last_on_duration = _alert ? LED_ON_MSG_MILLIS : LED_ON_MILLIS;
_next_change = now + _last_on_duration;
} else {
_state = 0;
_next_change = now + LED_CYCLE_MILLIS - _last_on_duration;
}
digitalWrite(_pin, (_state == _active) ? HIGH : LOW);
}
}
};