Add get leds and set leds on|off for Companion, repeater, room server and sensor builds. Preserve the setting across reboots and cover GPIO, RGB, Bluetooth, notification and expander indicators without changing radio amplifier controls or screen backlights. RAK Companions blink while advertising and keep the Bluetooth LED off once connected, including late timer callbacks. Adapted from meshcore-dev/MeshCore#3605 and #2694. Validated with host regressions and firmware builds for SenseCAP Solar, RAK4631, T096, Heltec V4, T-Beam, Xiao S3, Pico W and Wio E5 Mini. Co-authored-by: R0ck <develop@hectospark.co.uk> Co-authored-by: Nick Dunklee <nick@dunklee.org>
85 lines
3.7 KiB
C++
85 lines
3.7 KiB
C++
#include "MyMesh.h"
|
|
#include "target.h"
|
|
#include "NotificationSettingsFile.h"
|
|
|
|
#if COMPANION_FEATURE_NOTIFICATIONS
|
|
// The UI's STATUS_LED_RGB define is local to its own translation unit.
|
|
uint8_t MyMesh::capabilities() const {
|
|
uint8_t bits = _ui ? _ui->notificationCapabilities() : 0;
|
|
#if defined(PIN_STATUS_LED) || \
|
|
(defined(PIN_STATUS_LED_R) && defined(PIN_STATUS_LED_G) && defined(PIN_STATUS_LED_B))
|
|
bits |= mesh::notify::Led;
|
|
#endif
|
|
for(unsigned pin=0;pin<64;++pin)if(gpioAvailable(pin)) { bits|=mesh::notify::Gpio;break; }
|
|
return bits;
|
|
}
|
|
bool MyMesh::gpioAvailable(uint8_t pin) const { return board.isUserGpioAvailable(pin); }
|
|
void MyMesh::pulse(mesh::notify::Output output,bool on,int8_t pin) {
|
|
if(output==mesh::notify::Gpio && pin>=0 && gpioAvailable(pin)) {
|
|
pinMode(pin,OUTPUT);digitalWrite(pin,on?HIGH:LOW);
|
|
} else if(output==mesh::notify::Vibration) {
|
|
if(_ui)_ui->notificationVibration(on);
|
|
} else if(output==mesh::notify::Led) {
|
|
on = on && mesh::leds::enabled();
|
|
#if defined(PIN_STATUS_LED_R) && defined(PIN_STATUS_LED_G) && defined(PIN_STATUS_LED_B)
|
|
analogWrite(PIN_STATUS_LED_R,on?255:0);
|
|
analogWrite(PIN_STATUS_LED_G,on?90:0);
|
|
analogWrite(PIN_STATUS_LED_B,0);
|
|
#elif defined(PIN_STATUS_LED)
|
|
pinMode(PIN_STATUS_LED,OUTPUT);
|
|
#ifdef LED_STATE_ON
|
|
digitalWrite(PIN_STATUS_LED,on?LED_STATE_ON:!LED_STATE_ON);
|
|
#else
|
|
digitalWrite(PIN_STATUS_LED,on?HIGH:LOW);
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
void MyMesh::melody(const char* text) { if(_ui)_ui->notificationMelody(text); }
|
|
void MyMesh::screen(int8_t mode) { if(_ui)_ui->notificationScreen(mode); }
|
|
bool MyMesh::save(const mesh::notify::Settings& settings) {
|
|
return mesh::notify::writeSettings(_store->getPrimaryFS(),settings);
|
|
}
|
|
void MyMesh::setNotificationOutputMute(mesh::notify::Output output,bool muted) {
|
|
if(!_notifications.settings().enabled)return;
|
|
char command[40],reply[160];
|
|
snprintf(command,sizeof(command),"set notify.%s %s",
|
|
output==mesh::notify::Sound?"sound":"vibration",muted?"off":"on");
|
|
_notifications.handle(command,reply,sizeof(reply),millis(),_serial->isConnected());
|
|
}
|
|
bool MyMesh::handleNotificationCommand(const char* command,char* reply,size_t size) {
|
|
if(strncmp(command,"set notify.",11)&&strncmp(command,"get notify",10)
|
|
&&strncmp(command,"notify.",7))return false;
|
|
// Resolve channel slots now and store their secret, so a replaced slot does
|
|
// not inherit a previous channel's VIP/page rule. Full keys also work.
|
|
char normalized[240];
|
|
const char* token=strstr(command,"channel:");
|
|
if(token) {
|
|
const char* value=token+8;const char* end=value;
|
|
while(*end && *end!=' ' && *end!='@')++end;
|
|
if(end-value<4) {
|
|
char digits[4]={};memcpy(digits,value,end-value);uint32_t index;
|
|
ChannelDetails details;
|
|
if(!mesh::notify::unsignedValue(digits,index,MAX_GROUP_CHANNELS-1)
|
|
||!getChannel(index,details)||!details.name[0]) {
|
|
snprintf(reply,size,"Error: channel slot not found");return true;
|
|
}
|
|
char key[33];mesh::Utils::toHex(key,details.channel.secret,16);
|
|
int prefix=value-command;
|
|
int n=snprintf(normalized,sizeof(normalized),"%.*s%s%s",prefix,command,key,end);
|
|
if(n<0||size_t(n)>=sizeof(normalized)) { snprintf(reply,size,"Error: command too long");return true; }
|
|
command=normalized;
|
|
}
|
|
}
|
|
return _notifications.handle(command,reply,size,millis(),_serial->isConnected());
|
|
}
|
|
|
|
#else
|
|
bool MyMesh::handleNotificationCommand(const char* command,char* reply,size_t size) {
|
|
if(strncmp(command,"set notify.",11)&&strncmp(command,"get notify",10)
|
|
&&strncmp(command,"notify.",7))return false;
|
|
snprintf(reply,size,"Error: programmable alerts unavailable on this compact STM32 build");
|
|
return true;
|
|
}
|
|
#endif
|