mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-09-14 15:16:40 +00:00
Add RGB LED and haptic notifications for SenseCAP MeshTracker X1
This commit is contained in:
@@ -28,6 +28,7 @@ public:
|
||||
uint32_t ble_pin = 0;
|
||||
uint8_t advert_loc_policy = 0;
|
||||
uint8_t buzzer_quiet = 0;
|
||||
uint8_t vibe_quiet = 0;
|
||||
uint8_t gps_enabled = 0; // GPS enabled flag (0=disabled, 1=enabled)
|
||||
uint32_t gps_interval = 0; // GPS read interval in seconds
|
||||
uint8_t autoadd_config = 0; // bitmask for auto-add contacts config
|
||||
@@ -101,6 +102,7 @@ private:
|
||||
def("defs_key", (void *) _parent->default_scope_key, sizeof(_parent->default_scope_key));
|
||||
def("pin", _parent->ble_pin);
|
||||
def("buzz_q", _parent->buzzer_quiet);
|
||||
def("vibe_q", _parent->vibe_quiet);
|
||||
def("auto_add", _parent->autoadd_config); // bitmask for auto-add contacts config
|
||||
def("man_add", _parent->manual_add_contacts);
|
||||
def("tel_base", _parent->telemetry_mode_base);
|
||||
|
||||
@@ -6,12 +6,19 @@
|
||||
#define AUTO_OFF_MILLIS 15000 // 15 seconds
|
||||
#define BOOT_SCREEN_MILLIS 3000 // 3 seconds
|
||||
|
||||
#ifdef PIN_STATUS_LED
|
||||
#if defined(PIN_STATUS_LED) || defined(PIN_STATUS_LED_R)
|
||||
#define LED_ON_MILLIS 20
|
||||
#define LED_ON_MSG_MILLIS 200
|
||||
#define LED_CYCLE_MILLIS 4000
|
||||
#endif
|
||||
|
||||
#if defined(PIN_STATUS_LED_R) && defined(PIN_STATUS_LED_G) && defined(PIN_STATUS_LED_B)
|
||||
#define STATUS_LED_RGB 1
|
||||
#ifndef LOW_BATT_MILLIVOLTS
|
||||
#define LOW_BATT_MILLIVOLTS 3500
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef USER_BTN_PRESSED
|
||||
#define USER_BTN_PRESSED LOW
|
||||
#endif
|
||||
@@ -60,6 +67,11 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
|
||||
buzzer.startup();
|
||||
#endif
|
||||
|
||||
#ifdef HAS_DRV2605
|
||||
vibration.begin();
|
||||
vibration.quiet(_node_prefs->vibe_quiet);
|
||||
#endif
|
||||
|
||||
// Initialize digital button if available
|
||||
#ifdef PIN_USER_BTN
|
||||
_userButton = new Button(PIN_USER_BTN, USER_BTN_PRESSED);
|
||||
@@ -130,6 +142,10 @@ void UITask::clearMsgPreview() {
|
||||
void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) {
|
||||
_msgcount = msgcount;
|
||||
|
||||
#ifdef HAS_DRV2605
|
||||
vibration.trigger(); // vibrate even while the app is connected (honors quiet + cooldown)
|
||||
#endif
|
||||
|
||||
if (path_len == 0xFF) {
|
||||
sprintf(_origin, "(F) %s", from_name);
|
||||
} else {
|
||||
@@ -260,8 +276,88 @@ void UITask::renderCurrScreen() {
|
||||
_need_refresh = false;
|
||||
}
|
||||
|
||||
#ifdef STATUS_LED_RGB
|
||||
static void statusLedWrite(uint8_t r, uint8_t g, uint8_t b) {
|
||||
analogWrite(PIN_STATUS_LED_R, r);
|
||||
analogWrite(PIN_STATUS_LED_G, g);
|
||||
analogWrite(PIN_STATUS_LED_B, b);
|
||||
}
|
||||
|
||||
static void statusLedWheel(uint8_t pos) { // smooth hue sweep, 0..255
|
||||
if (pos < 85) {
|
||||
statusLedWrite(255 - pos * 3, pos * 3, 0);
|
||||
} else if (pos < 170) {
|
||||
pos -= 85;
|
||||
statusLedWrite(0, 255 - pos * 3, pos * 3);
|
||||
} else {
|
||||
pos -= 170;
|
||||
statusLedWrite(pos * 3, 0, 255 - pos * 3);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void UITask::userLedHandler() {
|
||||
#ifdef PIN_STATUS_LED
|
||||
#ifdef STATUS_LED_RGB
|
||||
static bool booted = false;
|
||||
static bool flourish_active = false;
|
||||
static unsigned long flourish_until = 0;
|
||||
static int prev_msgcount = 0;
|
||||
static int state = 0;
|
||||
static unsigned long next_change = 0;
|
||||
static int last_increment = 0;
|
||||
static unsigned long next_batt_check = 0;
|
||||
static bool low_batt = false;
|
||||
|
||||
unsigned long cur_time = millis();
|
||||
|
||||
if (!booted) { // color sweep on boot
|
||||
booted = true;
|
||||
flourish_until = cur_time + 1200;
|
||||
flourish_active = true;
|
||||
}
|
||||
if (_msgcount > prev_msgcount) { // color sweep when a new message arrives
|
||||
flourish_until = cur_time + 800;
|
||||
flourish_active = true;
|
||||
}
|
||||
prev_msgcount = _msgcount;
|
||||
|
||||
if (flourish_active) {
|
||||
if (cur_time < flourish_until) {
|
||||
statusLedWheel((cur_time % 1200) * 255 / 1200);
|
||||
return;
|
||||
}
|
||||
statusLedWrite(0, 0, 0);
|
||||
flourish_active = false;
|
||||
state = 0;
|
||||
next_change = cur_time;
|
||||
}
|
||||
|
||||
if (cur_time > next_batt_check) { // battery reads are not free, keep them rare
|
||||
low_batt = _board->getBattMilliVolts() < LOW_BATT_MILLIVOLTS;
|
||||
next_batt_check = cur_time + 60000;
|
||||
}
|
||||
|
||||
if (cur_time > next_change) {
|
||||
if (state == 0) {
|
||||
state = 1;
|
||||
last_increment = (_msgcount > 0) ? LED_ON_MSG_MILLIS : LED_ON_MILLIS;
|
||||
next_change = cur_time + last_increment;
|
||||
if (low_batt) {
|
||||
statusLedWrite(255, 0, 0); // red: battery low
|
||||
} else if (_msgcount > 0) {
|
||||
statusLedWrite(255, 90, 0); // amber: unread messages
|
||||
} else if (_connected) {
|
||||
statusLedWrite(0, 0, 255); // blue: app connected
|
||||
} else {
|
||||
statusLedWrite(0, 255, 0); // green: heartbeat
|
||||
}
|
||||
} else {
|
||||
state = 0;
|
||||
next_change = cur_time + LED_CYCLE_MILLIS - last_increment;
|
||||
statusLedWrite(0, 0, 0);
|
||||
}
|
||||
}
|
||||
#elif defined(PIN_STATUS_LED)
|
||||
static int state = 0;
|
||||
static int next_change = 0;
|
||||
static int last_increment = 0;
|
||||
@@ -406,8 +502,26 @@ void UITask::handleButtonDoublePress() {
|
||||
|
||||
void UITask::handleButtonTriplePress() {
|
||||
MESH_DEBUG_PRINTLN("UITask: triple press triggered");
|
||||
// Toggle buzzer quiet mode
|
||||
#ifdef PIN_BUZZER
|
||||
#if defined(PIN_BUZZER) && defined(HAS_DRV2605)
|
||||
// cycle alert modes: Buzz+Vibe -> Buzz only -> Vibe only -> Silent
|
||||
int mode = (_node_prefs->buzzer_quiet ? 2 : 0) | (_node_prefs->vibe_quiet ? 1 : 0);
|
||||
mode = (mode + 1) & 3;
|
||||
_node_prefs->buzzer_quiet = (mode & 2) ? 1 : 0;
|
||||
_node_prefs->vibe_quiet = (mode & 1) ? 1 : 0;
|
||||
buzzer.quiet(_node_prefs->buzzer_quiet);
|
||||
vibration.quiet(_node_prefs->vibe_quiet);
|
||||
// audible/tactile confirmation of the new mode (no screen on some boards)
|
||||
if (!_node_prefs->buzzer_quiet) notify(UIEventType::ack);
|
||||
if (!_node_prefs->vibe_quiet) vibration.trigger(true);
|
||||
switch (mode) {
|
||||
case 0: sprintf(_alert, "Alerts: Buzz+Vibe"); break;
|
||||
case 1: sprintf(_alert, "Alerts: Buzz only"); break;
|
||||
case 2: sprintf(_alert, "Alerts: Vibe only"); break;
|
||||
default: sprintf(_alert, "Alerts: Silent"); break;
|
||||
}
|
||||
the_mesh.savePrefs();
|
||||
_need_refresh = true;
|
||||
#elif defined(PIN_BUZZER)
|
||||
if (buzzer.isQuiet()) {
|
||||
buzzer.quiet(false);
|
||||
notify(UIEventType::ack);
|
||||
@@ -419,7 +533,7 @@ void UITask::handleButtonTriplePress() {
|
||||
_node_prefs->buzzer_quiet = buzzer.isQuiet();
|
||||
the_mesh.savePrefs();
|
||||
_need_refresh = true;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void UITask::handleButtonQuadruplePress() {
|
||||
|
||||
@@ -14,11 +14,18 @@
|
||||
|
||||
#include "Button.h"
|
||||
|
||||
#ifdef HAS_DRV2605
|
||||
#include <helpers/ui/DRV2605Vibration.h>
|
||||
#endif
|
||||
|
||||
class UITask : public AbstractUITask {
|
||||
DisplayDriver* _display;
|
||||
SensorManager* _sensors;
|
||||
#ifdef PIN_BUZZER
|
||||
genericBuzzer buzzer;
|
||||
#endif
|
||||
#ifdef HAS_DRV2605
|
||||
DRV2605Vibration vibration;
|
||||
#endif
|
||||
unsigned long _next_refresh, _auto_off;
|
||||
NodePrefs* _node_prefs;
|
||||
|
||||
Reference in New Issue
Block a user