diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index 6a6adaa26..8e2c1e341 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -47,7 +47,6 @@ along with this program. If not, see .
#include "graphics/SharedUIDisplay.h"
#include "graphics/emotes.h"
#include "graphics/images.h"
-#include "input/ButtonThread.h"
#include "input/ScanAndSelect.h"
#include "input/TouchScreenImpl1.h"
#include "main.h"
@@ -836,7 +835,6 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
if (on != screenOn) {
if (on) {
LOG_INFO("Turn on screen");
- buttonThread->setScreenFlag(true);
powerMon->setState(meshtastic_PowerMon_State_Screen_On);
#ifdef T_WATCH_S3
PMU->enablePowerOutput(XPOWERS_ALDO2);
@@ -880,8 +878,6 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
// eInkScreensaver parameter is usually NULL (default argument), default frame used instead
setScreensaverFrames(einkScreensaver);
#endif
- LOG_INFO("Turn off screen");
- buttonThread->setScreenFlag(false);
#ifdef ELECROW_ThinkNode_M1
if (digitalRead(PIN_EINK_EN) == HIGH) {
digitalWrite(PIN_EINK_EN, LOW);
@@ -1761,6 +1757,7 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
int Screen::handleInputEvent(const InputEvent *event)
{
+ LOG_WARN("event %u", event->inputEvent);
if (NotificationRenderer::isOverlayBannerShowing()) {
NotificationRenderer::inEvent = event->inputEvent;
diff --git a/src/input/ButtonThread.cpp b/src/input/ButtonThread.cpp
index 55a1aa77a..05e38b5ca 100644
--- a/src/input/ButtonThread.cpp
+++ b/src/input/ButtonThread.cpp
@@ -27,17 +27,14 @@
using namespace concurrency;
-ButtonThread *buttonThread; // Declared extern in header
-#if HAS_SCREEN
-extern CannedMessageModule *cannedMessageModule;
-#endif
volatile ButtonThread::ButtonEventType ButtonThread::btnEvent = ButtonThread::BUTTON_EVENT_NONE;
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO) || defined(USERPREFS_BUTTON_PIN)
OneButton ButtonThread::userButton; // Get reference to static member
#endif
-ButtonThread::ButtonThread() : OSThread("Button")
+ButtonThread::ButtonThread(const char *name) : OSThread(name)
{
+ _originName = name;
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO) || defined(USERPREFS_BUTTON_PIN)
#if defined(ARCH_PORTDUINO)
@@ -55,7 +52,7 @@ ButtonThread::ButtonThread() : OSThread("Button")
#if defined(HELTEC_CAPSULE_SENSOR_V3) || defined(HELTEC_SENSOR_HUB)
this->userButton = OneButton(pin, false, false);
#elif defined(BUTTON_ACTIVE_LOW)
- this->userButton = OneButton(pin, BUTTON_ACTIVE_LOW, BUTTON_ACTIVE_PULLUP);
+ userButton = OneButton(pin, BUTTON_ACTIVE_LOW, BUTTON_ACTIVE_PULLUP);
#else
this->userButton = OneButton(pin, true, true);
#endif
@@ -72,20 +69,20 @@ ButtonThread::ButtonThread() : OSThread("Button")
#endif
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO) || defined(USERPREFS_BUTTON_PIN)
- userButton.attachClick(userButtonPressed);
- userButton.setPressMs(BUTTON_LONGPRESS_MS);
+ userButton.attachClick([]() { btnEvent = BUTTON_EVENT_PRESSED; });
+
userButton.setDebounceMs(1);
if (screen) {
userButton.setClickMs(20);
+ userButton.setPressMs(500);
} else {
+ userButton.setPressMs(BUTTON_LONGPRESS_MS);
userButton.setClickMs(BUTTON_CLICK_MS);
userButton.attachDoubleClick(userButtonDoublePressed);
userButton.attachMultiClick(userButtonMultiPressed,
this); // Reference to instance: get click count from non-static OneButton
}
-#if !defined(T_DECK) && \
- !defined( \
- ELECROW_ThinkNode_M2) // T-Deck immediately wakes up after shutdown, Thinknode M2 has this on the smaller ALT button
+#if !defined(ELECROW_ThinkNode_M2) // T-Deck immediately wakes up after shutdown, Thinknode M2 has this on the smaller ALT button
userButton.attachLongPressStart(userButtonPressedLongStart);
userButton.attachLongPressStop(userButtonPressedLongStop);
#endif
@@ -230,10 +227,13 @@ int32_t ButtonThread::runOnce()
playBoop();
// Forward single press to InputBroker (but NOT as DOWN/SELECT, just forward a "button press" event)
- if (inputBroker) {
- InputEvent evt = {"button", INPUT_BROKER_USER_PRESS, 0, 0, 0};
- inputBroker->injectInputEvent(&evt);
- }
+ 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: {
@@ -245,7 +245,7 @@ int32_t ButtonThread::runOnce()
// 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};
- inputBroker->injectInputEvent(&evt);
+ this->notifyObservers(&evt);
}
break;
}
@@ -269,10 +269,6 @@ int32_t ButtonThread::runOnce()
externalNotificationModule->stopNow();
break;
}
-#ifdef ELECROW_ThinkNode_M1
- sendAdHocPosition();
- break;
-#endif
// Start tracking for potential combination
waitingForLongPress = true;
@@ -300,10 +296,6 @@ int32_t ButtonThread::runOnce()
powerFSM.trigger(EVENT_PRESS);
break;
#endif
- // turn screen on or off
- screen_flag = !screen_flag;
- if (screen)
- screen->setOn(screen_flag);
break;
}
@@ -325,7 +317,8 @@ int32_t ButtonThread::runOnce()
sendAdHocPosition();
// Show temporary on-screen confirmation banner for 3 seconds
- screen->showOverlayBanner("Ad-hoc Ping Sent", 3000);
+ if (screen)
+ screen->showOverlayBanner("Ad-hoc Ping Sent", 3000);
break;
}
@@ -344,25 +337,8 @@ int32_t ButtonThread::runOnce()
case 3:
if (!config.device.disable_triple_click && (gps != nullptr)) {
gps->toggleGpsMode();
-
- const char *statusMsg = (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED)
- ? "GPS Enabled"
- : "GPS Disabled";
-
- if (screen) {
- screen->forceDisplay(true); // Force a new UI frame, then force an EInk update
- screen->showOverlayBanner(statusMsg, 3000);
- }
}
break;
-#elif defined(ELECROW_ThinkNode_M1) || defined(ELECROW_ThinkNode_M2)
- case 3:
- LOG_INFO("3 clicks: toggle buzzer");
- buzzer_flag = !buzzer_flag;
- if (!buzzer_flag)
- noTone(PIN_BUZZER);
- break;
-
#endif
#if defined(USE_EINK) && defined(PIN_EINK_EN) && !defined(ELECROW_ThinkNode_M1) // i.e. T-Echo
@@ -370,20 +346,6 @@ int32_t ButtonThread::runOnce()
case 4:
digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW);
break;
-#endif
-#if !MESHTASTIC_EXCLUDE_SCREEN && HAS_SCREEN
- // 5 clicks: start accelerometer/magenetometer calibration for 30 seconds
- case 5:
- if (accelerometerThread) {
- accelerometerThread->calibrate(30);
- }
- break;
- // 6 clicks: start accelerometer/magenetometer calibration for 60 seconds
- case 6:
- if (accelerometerThread) {
- accelerometerThread->calibrate(60);
- }
- break;
#endif
// No valid multipress action
default:
diff --git a/src/input/ButtonThread.h b/src/input/ButtonThread.h
index fe42e9f74..937bb93e4 100644
--- a/src/input/ButtonThread.h
+++ b/src/input/ButtonThread.h
@@ -1,5 +1,6 @@
#pragma once
+#include "InputBroker.h"
#include "OneButton.h"
#include "concurrency/OSThread.h"
#include "configuration.h"
@@ -29,9 +30,10 @@
#define BUTTON_LEADUP_MS 2200 // Play lead-up sound after 2.5 seconds of holding
#endif
-class ButtonThread : public concurrency::OSThread
+class ButtonThread : public Observable, public concurrency::OSThread
{
public:
+ const char *_originName;
static const uint32_t c_holdOffTime = 30000; // hold off 30s after boot
enum ButtonEventType {
@@ -46,15 +48,11 @@ class ButtonThread : public concurrency::OSThread
BUTTON_EVENT_COMBO_SHORT_LONG,
};
- ButtonThread();
+ ButtonThread(const char *name);
int32_t runOnce() override;
void attachButtonInterrupts();
void detachButtonInterrupts();
void storeClickCount();
- bool isBuzzing() { return buzzer_flag; }
- void setScreenFlag(bool flag) { screen_flag = flag; }
- bool getScreenFlag() { return screen_flag; }
- bool isInterceptingAndFocused();
bool isButtonPressed(int buttonPin)
{
#ifdef BUTTON_ACTIVE_LOW
@@ -90,8 +88,6 @@ class ButtonThread : public concurrency::OSThread
// set during IRQ
static volatile ButtonEventType btnEvent;
- bool buzzer_flag = false;
- bool screen_flag = true;
// Store click count during callback, for later use
volatile int multipressClickCount = 0;
diff --git a/src/input/ButtonThreadImpl.cpp b/src/input/ButtonThreadImpl.cpp
new file mode 100644
index 000000000..c57f1c8f0
--- /dev/null
+++ b/src/input/ButtonThreadImpl.cpp
@@ -0,0 +1,17 @@
+#include "ButtonThreadImpl.h"
+#include "InputBroker.h"
+#include "configuration.h"
+
+#if defined(BUTTON_PIN)
+
+ButtonThreadImpl *aButtonThreadImpl;
+
+ButtonThreadImpl::ButtonThreadImpl() : ButtonThread("UserButton") {}
+
+void ButtonThreadImpl::init() // init should give the pin number and the action to perform and whether to do the legacy actions
+{
+ if (inputBroker)
+ inputBroker->registerSource(this);
+}
+
+#endif // INPUTBROKER_SERIAL_TYPE
\ No newline at end of file
diff --git a/src/input/ButtonThreadImpl.h b/src/input/ButtonThreadImpl.h
new file mode 100644
index 000000000..470dd46d4
--- /dev/null
+++ b/src/input/ButtonThreadImpl.h
@@ -0,0 +1,19 @@
+#pragma once
+#include "ButtonThread.h"
+#include "main.h"
+
+/**
+ * @brief The idea behind this class to have static methods for the event handlers.
+ * Check attachInterrupt() at RotaryEncoderInteruptBase.cpp
+ * Technically you can have as many rotary encoders hardver attached
+ * to your device as you wish, but you always need to have separate event
+ * handlers, thus you need to have a RotaryEncoderInterrupt implementation.
+ */
+class ButtonThreadImpl : public ButtonThread
+{
+ public:
+ ButtonThreadImpl();
+ void init();
+};
+
+extern ButtonThreadImpl *aButtonThreadImpl;
\ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index a8bd4971a..976eefcfc 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -99,7 +99,7 @@ NRF52Bluetooth *nrf52Bluetooth = nullptr;
#endif
#if HAS_BUTTON || defined(ARCH_PORTDUINO)
-#include "input/ButtonThread.h"
+#include "input/ButtonThreadImpl.h"
#endif
#include "AmbientLightingThread.h"
@@ -220,64 +220,6 @@ const char *getDeviceName()
return name;
}
-#if defined(ELECROW_ThinkNode_M1) || defined(ELECROW_ThinkNode_M2)
-static int32_t ledBlinkCount = 0;
-
-static int32_t elecrowLedBlinker()
-{
- // are we in alert buzzer mode?
-#if HAS_BUTTON
- if (buttonThread->isBuzzing()) {
- // blink LED three times for 3 seconds, then 3 times for a second, with one second pause
- if (ledBlinkCount % 2) { // odd means LED OFF
- ledBlink.set(false);
- ledBlinkCount++;
- if (ledBlinkCount >= 12)
- ledBlinkCount = 0;
- noTone(PIN_BUZZER);
- return 1000;
- } else {
- if (ledBlinkCount < 6) {
- ledBlink.set(true);
- tone(PIN_BUZZER, 4000, 3000);
- ledBlinkCount++;
- return 3000;
- } else {
- ledBlink.set(true);
- tone(PIN_BUZZER, 4000, 1000);
- ledBlinkCount++;
- return 1000;
- }
- }
- } else {
-#endif
- ledBlinkCount = 0;
- if (config.device.led_heartbeat_disabled)
- return 1000;
-
- static bool ledOn;
- // remain on when fully charged or discharging above 10%
- if ((powerStatus->getIsCharging() && powerStatus->getBatteryChargePercent() >= 100) ||
- (!powerStatus->getIsCharging() && powerStatus->getBatteryChargePercent() >= 10)) {
- ledOn = true;
- } else {
- ledOn ^= 1;
- }
- ledBlink.set(ledOn);
- // when charging, blink 0.5Hz square wave rate to indicate that
- if (powerStatus->getIsCharging()) {
- return 500;
- }
- // Blink rapidly when almost empty or if battery is not connected
- if ((!powerStatus->getIsCharging() && powerStatus->getBatteryChargePercent() < 10) || !powerStatus->getHasBattery()) {
- return 250;
- }
-#if HAS_BUTTON
- }
-#endif
- return 1000;
-}
-#else
static int32_t ledBlinker()
{
// Still set up the blinking (heartbeat) interval but skip code path below, so LED will blink if
@@ -293,7 +235,6 @@ static int32_t ledBlinker()
// have a very sparse duty cycle of LED being on, unless charging, then blink 0.5Hz square wave rate to indicate that
return powerStatus->getIsCharging() ? 1000 : (ledOn ? 1 : 1000);
}
-#endif
uint32_t timeLastPowered = 0;
@@ -861,11 +802,6 @@ void setup()
}
#endif // HAS_SCREEN
-#if HAS_BUTTON || defined(ARCH_PORTDUINO)
- // Buttons. Moved here cause we need NodeDB to be initialized
- buttonThread = new ButtonThread();
-#endif
-
// setup TZ prior to time actions.
#if !MESHTASTIC_EXCLUDE_TZ
LOG_DEBUG("Use compiled/slipstreamed %s", slipstreamTZString); // important, removing this clobbers our magic string
@@ -932,6 +868,13 @@ void setup()
// Now that the mesh service is created, create any modules
setupModules();
+// buttons are now inputBroker, so have to come after setupModules
+#if HAS_BUTTON || defined(ARCH_PORTDUINO)
+ // Buttons. Moved here cause we need NodeDB to be initialized
+ aButtonThreadImpl = new ButtonThreadImpl();
+ aButtonThreadImpl->init();
+#endif
+
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
// After modules are setup, so we can observe modules
setupNicheGraphics();
diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp
index 0eb68470c..2cddb42cd 100644
--- a/src/modules/CannedMessageModule.cpp
+++ b/src/modules/CannedMessageModule.cpp
@@ -310,8 +310,6 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
case CANNED_MESSAGE_RUN_STATE_INACTIVE:
if (isSelect) {
- // When inactive, call the onebutton shortpress instead. Activate module only on up/down
- powerFSM.trigger(EVENT_PRESS);
return 0; // Main button press no longer runs through powerFSM
}
// Let LEFT/RIGHT pass through so frame navigation works