mirror of
https://github.com/meshtastic/firmware.git
synced 2025-06-14 17:12:08 +00:00
ExternalNotifications now observe inputBroker
This commit is contained in:
parent
b9f5ff08fc
commit
a4ead96c39
@ -5,7 +5,6 @@
|
||||
#include "GPS.h"
|
||||
#endif
|
||||
#include "MeshService.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "RadioLibInterface.h"
|
||||
#include "buzz.h"
|
||||
#include "input/InputBroker.h"
|
||||
@ -217,174 +216,118 @@ int32_t ButtonThread::runOnce()
|
||||
#endif
|
||||
|
||||
if (btnEvent != BUTTON_EVENT_NONE) {
|
||||
if (screen) {
|
||||
#if HAS_SCREEN
|
||||
switch (btnEvent) {
|
||||
case BUTTON_EVENT_PRESSED: {
|
||||
LOG_WARN("press!");
|
||||
switch (btnEvent) {
|
||||
case BUTTON_EVENT_PRESSED: {
|
||||
LOG_WARN("press!");
|
||||
|
||||
// Play boop sound for every button press
|
||||
playBoop();
|
||||
// Play boop sound for every button press
|
||||
playBoop();
|
||||
|
||||
// Forward single press to InputBroker (but NOT as DOWN/SELECT, just forward a "button press" event)
|
||||
InputEvent evt;
|
||||
evt.source = _originName;
|
||||
evt.kbchar = 0;
|
||||
evt.touchX = 0;
|
||||
evt.touchY = 0;
|
||||
evt.inputEvent = INPUT_BROKER_USER_PRESS;
|
||||
this->notifyObservers(&evt);
|
||||
break;
|
||||
}
|
||||
case BUTTON_EVENT_LONG_PRESSED: {
|
||||
LOG_WARN("Long press!");
|
||||
// Forward single press to InputBroker (but NOT as DOWN/SELECT, just forward a "button press" event)
|
||||
InputEvent evt;
|
||||
evt.source = _originName;
|
||||
evt.kbchar = 0;
|
||||
evt.touchX = 0;
|
||||
evt.touchY = 0;
|
||||
evt.inputEvent = INPUT_BROKER_USER_PRESS;
|
||||
this->notifyObservers(&evt);
|
||||
|
||||
// Play beep sound
|
||||
playBeep();
|
||||
|
||||
// Forward long press to InputBroker (but NOT as DOWN/SELECT, just forward a "button long press" event)
|
||||
if (inputBroker) {
|
||||
InputEvent evt = {"button", INPUT_BROKER_SELECT, 0, 0, 0};
|
||||
this->notifyObservers(&evt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Ignore all other events on screen devices
|
||||
break;
|
||||
}
|
||||
btnEvent = BUTTON_EVENT_NONE;
|
||||
#endif
|
||||
} else {
|
||||
// On devices without screen: full legacy logic
|
||||
switch (btnEvent) {
|
||||
case BUTTON_EVENT_PRESSED: {
|
||||
LOG_BUTTON("press!");
|
||||
|
||||
// Play boop sound for every button press
|
||||
playBoop();
|
||||
|
||||
// If a nag notification is running, stop it and prevent other actions
|
||||
if (moduleConfig.external_notification.enabled && (externalNotificationModule->nagCycleCutoff != UINT32_MAX)) {
|
||||
externalNotificationModule->stopNow();
|
||||
break;
|
||||
}
|
||||
|
||||
// Start tracking for potential combination
|
||||
// Start tracking for potential combination
|
||||
if (!screen) {
|
||||
waitingForLongPress = true;
|
||||
shortPressTime = millis();
|
||||
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BUTTON_EVENT_PRESSED_SCREEN: {
|
||||
LOG_BUTTON("AltPress!");
|
||||
case BUTTON_EVENT_PRESSED_SCREEN: {
|
||||
LOG_BUTTON("AltPress!");
|
||||
|
||||
// Play boop sound for every button press
|
||||
playBoop();
|
||||
// Play boop sound for every button press
|
||||
playBoop();
|
||||
|
||||
// Reset combination tracking
|
||||
waitingForLongPress = false;
|
||||
// Reset combination tracking
|
||||
waitingForLongPress = false;
|
||||
|
||||
#ifdef ELECROW_ThinkNode_M1
|
||||
// If a nag notification is running, stop it and prevent other actions
|
||||
if (moduleConfig.external_notification.enabled && (externalNotificationModule->nagCycleCutoff != UINT32_MAX)) {
|
||||
externalNotificationModule->stopNow();
|
||||
break;
|
||||
}
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
break;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BUTTON_EVENT_DOUBLE_PRESSED: {
|
||||
LOG_BUTTON("Double press!");
|
||||
case BUTTON_EVENT_DOUBLE_PRESSED: { // not wired in if screen detected
|
||||
LOG_BUTTON("Double press!");
|
||||
|
||||
// Play boop sound for every button press
|
||||
playBoop();
|
||||
// Play boop sound for every button press
|
||||
playBoop();
|
||||
|
||||
// Reset combination tracking
|
||||
waitingForLongPress = false;
|
||||
// Reset combination tracking
|
||||
waitingForLongPress = false;
|
||||
|
||||
#ifdef ELECROW_ThinkNode_M1
|
||||
digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW);
|
||||
break;
|
||||
#endif
|
||||
// Send GPS position immediately
|
||||
sendAdHocPosition();
|
||||
|
||||
// Send GPS position immediately
|
||||
sendAdHocPosition();
|
||||
break;
|
||||
}
|
||||
|
||||
// Show temporary on-screen confirmation banner for 3 seconds
|
||||
if (screen)
|
||||
screen->showOverlayBanner("Ad-hoc Ping Sent", 3000);
|
||||
break;
|
||||
}
|
||||
case BUTTON_EVENT_MULTI_PRESSED: { // not wired in when screen is present
|
||||
LOG_BUTTON("Mulitipress! %hux", multipressClickCount);
|
||||
|
||||
case BUTTON_EVENT_MULTI_PRESSED: {
|
||||
LOG_BUTTON("Mulitipress! %hux", multipressClickCount);
|
||||
// Play boop sound for every button press
|
||||
playBoop();
|
||||
|
||||
// Play boop sound for every button press
|
||||
playBoop();
|
||||
// Reset combination tracking
|
||||
waitingForLongPress = false;
|
||||
|
||||
// Reset combination tracking
|
||||
waitingForLongPress = false;
|
||||
|
||||
switch (multipressClickCount) {
|
||||
switch (multipressClickCount) {
|
||||
#if HAS_GPS && !defined(ELECROW_ThinkNode_M1)
|
||||
// 3 clicks: toggle GPS
|
||||
case 3:
|
||||
if (!config.device.disable_triple_click && (gps != nullptr)) {
|
||||
gps->toggleGpsMode();
|
||||
}
|
||||
break;
|
||||
// 3 clicks: toggle GPS
|
||||
case 3:
|
||||
if (!config.device.disable_triple_click && (gps != nullptr)) {
|
||||
gps->toggleGpsMode();
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(USE_EINK) && defined(PIN_EINK_EN) && !defined(ELECROW_ThinkNode_M1) // i.e. T-Echo
|
||||
// 4 clicks: toggle backlight
|
||||
case 4:
|
||||
digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW);
|
||||
break;
|
||||
#endif
|
||||
// No valid multipress action
|
||||
default:
|
||||
break;
|
||||
} // end switch: click count
|
||||
|
||||
// 4 clicks: toggle backlight
|
||||
case 4:
|
||||
digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW);
|
||||
break;
|
||||
} // end multipress event
|
||||
#endif
|
||||
// No valid multipress action
|
||||
default:
|
||||
break;
|
||||
} // end switch: click count
|
||||
|
||||
case BUTTON_EVENT_LONG_PRESSED: {
|
||||
LOG_BUTTON("Long press!");
|
||||
break;
|
||||
} // end multipress event
|
||||
|
||||
// Check if this is part of a short-press + long-press combination
|
||||
if (waitingForLongPress && (millis() - shortPressTime) <= BUTTON_COMBO_TIMEOUT_MS) {
|
||||
LOG_BUTTON("Combo detected: short-press + long-press!");
|
||||
btnEvent = BUTTON_EVENT_COMBO_SHORT_LONG;
|
||||
waitingForLongPress = false;
|
||||
break;
|
||||
}
|
||||
case BUTTON_EVENT_LONG_PRESSED: {
|
||||
LOG_BUTTON("Long press!");
|
||||
|
||||
// Reset combination tracking
|
||||
// Check if this is part of a short-press + long-press combination
|
||||
if (waitingForLongPress && (millis() - shortPressTime) <= BUTTON_COMBO_TIMEOUT_MS) {
|
||||
LOG_BUTTON("Combo detected: short-press + long-press!");
|
||||
btnEvent = BUTTON_EVENT_COMBO_SHORT_LONG;
|
||||
waitingForLongPress = false;
|
||||
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
|
||||
if (screen) {
|
||||
// Show shutdown message as a temporary overlay banner
|
||||
screen->showOverlayBanner("Shutting Down..."); // Display for 3 seconds
|
||||
}
|
||||
|
||||
// Lead-up sound already played during button hold
|
||||
// Just a simple beep to confirm long press threshold reached
|
||||
playBeep();
|
||||
break;
|
||||
}
|
||||
|
||||
// Do actual shutdown when button released, otherwise the button release
|
||||
// may wake the board immediatedly.
|
||||
case BUTTON_EVENT_LONG_RELEASED: {
|
||||
// Forward long press to InputBroker (but NOT as DOWN/SELECT, just forward a "button long press" event)
|
||||
InputEvent evt = {"button", INPUT_BROKER_SELECT, 0, 0, 0};
|
||||
this->notifyObservers(&evt);
|
||||
|
||||
// Reset combination tracking
|
||||
waitingForLongPress = false;
|
||||
|
||||
// Lead-up sound already played during button hold
|
||||
// Just a simple beep to confirm long press threshold reached
|
||||
playBeep();
|
||||
break;
|
||||
}
|
||||
|
||||
// Do actual shutdown when button released, otherwise the button release
|
||||
// may wake the board immediatedly.
|
||||
case BUTTON_EVENT_LONG_RELEASED: {
|
||||
if (!screen) {
|
||||
LOG_INFO("Shutdown from long press");
|
||||
|
||||
// Reset combination tracking
|
||||
@ -394,59 +337,49 @@ int32_t ButtonThread::runOnce()
|
||||
delay(3000);
|
||||
power->shutdown();
|
||||
nodeDB->saveToDisk();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef BUTTON_PIN_TOUCH
|
||||
case BUTTON_EVENT_TOUCH_LONG_PRESSED: {
|
||||
LOG_BUTTON("Touch press!");
|
||||
case BUTTON_EVENT_TOUCH_LONG_PRESSED: {
|
||||
LOG_BUTTON("Touch press!");
|
||||
|
||||
// Play boop sound for every button press
|
||||
playBoop();
|
||||
// Play boop sound for every button press
|
||||
playBoop();
|
||||
|
||||
// Reset combination tracking
|
||||
waitingForLongPress = false;
|
||||
|
||||
// Ignore if: no screen
|
||||
if (!screen)
|
||||
break;
|
||||
// Reset combination tracking
|
||||
waitingForLongPress = false;
|
||||
|
||||
#ifdef TTGO_T_ECHO
|
||||
// Ignore if: TX in progress
|
||||
// Uncommon T-Echo hardware bug, LoRa TX triggers touch button
|
||||
if (!RadioLibInterface::instance || RadioLibInterface::instance->isSending())
|
||||
break;
|
||||
// Ignore if: TX in progress
|
||||
// Uncommon T-Echo hardware bug, LoRa TX triggers touch button
|
||||
if (!RadioLibInterface::instance || RadioLibInterface::instance->isSending())
|
||||
break;
|
||||
#endif
|
||||
|
||||
// Wake if asleep
|
||||
if (powerFSM.getState() == &stateDARK)
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
|
||||
// Update display (legacy behaviour)
|
||||
screen->forceDisplay();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif // BUTTON_PIN_TOUCH
|
||||
|
||||
case BUTTON_EVENT_COMBO_SHORT_LONG: {
|
||||
// Placeholder for short-press + long-press combination
|
||||
LOG_BUTTON("Short-press + Long-press combination detected!");
|
||||
case BUTTON_EVENT_COMBO_SHORT_LONG: {
|
||||
// Placeholder for short-press + long-press combination
|
||||
LOG_BUTTON("Short-press + Long-press combination detected!");
|
||||
|
||||
// Play the combination tune
|
||||
playComboTune();
|
||||
// Play the combination tune
|
||||
playComboTune();
|
||||
|
||||
// Optionally show a message on screen
|
||||
if (screen) {
|
||||
screen->showOverlayBanner("Combo Tune Played", 2000);
|
||||
}
|
||||
break;
|
||||
// Optionally show a message on screen
|
||||
if (screen) {
|
||||
screen->showOverlayBanner("Combo Tune Played", 2000);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
btnEvent = BUTTON_EVENT_NONE;
|
||||
} // (!screen)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
btnEvent = BUTTON_EVENT_NONE;
|
||||
}
|
||||
|
||||
return 50;
|
||||
|
@ -106,7 +106,6 @@ class ButtonThread : public Observable<const InputEvent *>, public concurrency::
|
||||
static void sendAdHocPosition();
|
||||
|
||||
// IRQ callbacks
|
||||
static void userButtonPressed() { btnEvent = BUTTON_EVENT_PRESSED; }
|
||||
static void userButtonPressedScreen() { btnEvent = BUTTON_EVENT_PRESSED_SCREEN; }
|
||||
static void userButtonDoublePressed() { btnEvent = BUTTON_EVENT_DOUBLE_PRESSED; }
|
||||
static void userButtonMultiPressed(void *callerThread); // Retrieve click count from non-static Onebutton while still valid
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include "FSCommon.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h" // needed for button bypass
|
||||
#include "SPILock.h"
|
||||
#include "buzz.h"
|
||||
#include "detect/ScanI2C.h"
|
||||
@ -587,7 +586,6 @@ bool CannedMessageModule::handleMessageSelectorInput(const InputEvent *event, bo
|
||||
|
||||
// Normal canned message selection
|
||||
if (runState == CANNED_MESSAGE_RUN_STATE_INACTIVE || runState == CANNED_MESSAGE_RUN_STATE_DISABLED) {
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
} else {
|
||||
payload = runState;
|
||||
runState = CANNED_MESSAGE_RUN_STATE_ACTION_SELECT;
|
||||
@ -1002,7 +1000,6 @@ int32_t CannedMessageModule::runOnce()
|
||||
}
|
||||
if ((this->messagesCount > this->currentMessageIndex) && (strlen(this->messages[this->currentMessageIndex]) > 0)) {
|
||||
if (strcmp(this->messages[this->currentMessageIndex], "~") == 0) {
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
return INT32_MAX;
|
||||
} else {
|
||||
sendText(this->dest, this->channel, this->messages[this->currentMessageIndex], true);
|
||||
|
@ -350,6 +350,9 @@ ExternalNotificationModule::ExternalNotificationModule()
|
||||
// moduleConfig.external_notification.alert_message_buzzer = true;
|
||||
|
||||
if (moduleConfig.external_notification.enabled) {
|
||||
if (inputBroker) // put our callback in the inputObserver list
|
||||
inputObserver.observe(inputBroker);
|
||||
|
||||
if (nodeDB->loadProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, sizeof(meshtastic_RTTTLConfig),
|
||||
&meshtastic_RTTTLConfig_msg, &rtttlConfig) != LoadFileResult::LOAD_SUCCESS) {
|
||||
memset(rtttlConfig.ringtone, 0, sizeof(rtttlConfig.ringtone));
|
||||
@ -595,4 +598,14 @@ void ExternalNotificationModule::handleSetRingtone(const char *from_msg)
|
||||
if (changed) {
|
||||
nodeDB->saveProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, &meshtastic_RTTTLConfig_msg, &rtttlConfig);
|
||||
}
|
||||
}
|
||||
|
||||
int ExternalNotificationModule::handleInputEvent(const InputEvent *event)
|
||||
{
|
||||
LOG_WARN("ExternalNotification Handle Input");
|
||||
if (nagCycleCutoff != UINT32_MAX) {
|
||||
stopNow();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -3,6 +3,8 @@
|
||||
#include "SinglePortModule.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "configuration.h"
|
||||
#include "input/InputBroker.h"
|
||||
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !defined(CONFIG_IDF_TARGET_ESP32C6)
|
||||
#include <NonBlockingRtttl.h>
|
||||
#else
|
||||
@ -27,11 +29,15 @@ class rtttl
|
||||
*/
|
||||
class ExternalNotificationModule : public SinglePortModule, private concurrency::OSThread
|
||||
{
|
||||
CallbackObserver<ExternalNotificationModule, const InputEvent *> inputObserver =
|
||||
CallbackObserver<ExternalNotificationModule, const InputEvent *>(this, &ExternalNotificationModule::handleInputEvent);
|
||||
uint32_t output = 0;
|
||||
|
||||
public:
|
||||
ExternalNotificationModule();
|
||||
|
||||
int handleInputEvent(const InputEvent *arg);
|
||||
|
||||
uint32_t nagCycleCutoff = 1;
|
||||
|
||||
void setExternalState(uint8_t index = 0, bool on = false);
|
||||
|
Loading…
Reference in New Issue
Block a user