From c5b95ed3c0daf55d1f459e3bb94fc0fe330d3989 Mon Sep 17 00:00:00 2001 From: Balazs Kelemen <10376327+prampec@users.noreply.github.com> Date: Thu, 13 Jan 2022 09:19:36 +0100 Subject: [PATCH] Screen update event. --- src/graphics/Screen.cpp | 24 ++++++++++++------- src/graphics/Screen.h | 7 +++--- src/mesh/MeshPlugin.cpp | 15 ++++++++++++ src/mesh/MeshPlugin.h | 10 ++++++++ src/plugins/CannedMessagePlugin.cpp | 8 ++++--- src/plugins/CannedMessagePlugin.h | 4 +++- .../input/RotaryEncoderInterruptBase.cpp | 6 ++--- 7 files changed, 55 insertions(+), 19 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 4e4a98454..c7bc0fe36 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -34,7 +34,6 @@ along with this program. If not, see . #include "mesh-pb-constants.h" #include "mesh/Channels.h" #include "plugins/TextMessagePlugin.h" -#include "plugins/CannedMessagePlugin.h" #include "sleep.h" #include "target_specific.h" #include "utils.h" @@ -821,9 +820,9 @@ void Screen::setup() nodeStatusObserver.observe(&nodeStatus->onNewStatus); if (textMessagePlugin) textMessageObserver.observe(textMessagePlugin); - // TODO: find a nicer way to notify screen about refresh - if (cannedMessagePlugin) - cannedMessageObserver.observe(cannedMessagePlugin); + + // Plugins can notify screen about refresh + MeshPlugin::observeUIEvents(&uiFrameEventObserver); } void Screen::forceDisplay() @@ -1461,14 +1460,21 @@ int Screen::handleTextMessage(const MeshPacket *packet) return 0; } -int Screen::handleCannedMessage(const meshtastic::Status *packet) +int Screen::handleUIFrameEvent(const UIFrameEvent *event) { if (showingNormalScreen) { - setFrames(); // Regen the list of screens (will show new text message) + if (event->frameChanged) + { + setFrames(); // Regen the list of screens (will show new text message) + } + else if (event->needRedraw) + { + setFastFramerate(); + // TODO: We might also want switch to corresponding frame, + // but we don't know the exact frame number. + //ui.switchToFrame(0); + } } - // TODO: We might also want switch to corresponding frame, - // but we don't know the exact frame number. - //ui.switchToFrame(0); return 0; } diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 68815328e..10b2b6ff7 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -40,6 +40,7 @@ class Screen #include "concurrency/OSThread.h" #include "power.h" #include +#include "mesh/MeshPlugin.h" // 0 to 255, though particular variants might define different defaults #ifndef BRIGHTNESS_DEFAULT @@ -90,8 +91,8 @@ class Screen : public concurrency::OSThread CallbackObserver(this, &Screen::handleStatusUpdate); CallbackObserver textMessageObserver = CallbackObserver(this, &Screen::handleTextMessage); - CallbackObserver cannedMessageObserver = - CallbackObserver(this, &Screen::handleCannedMessage); + CallbackObserver uiFrameEventObserver = + CallbackObserver(this, &Screen::handleUIFrameEvent); public: Screen(uint8_t address, int sda = -1, int scl = -1); @@ -220,7 +221,7 @@ class Screen : public concurrency::OSThread int handleStatusUpdate(const meshtastic::Status *arg); int handleTextMessage(const MeshPacket *arg); - int handleCannedMessage(const meshtastic::Status *arg); + int handleUIFrameEvent(const UIFrameEvent *arg); /// Used to force (super slow) eink displays to draw critical frames void forceDisplay(); diff --git a/src/mesh/MeshPlugin.cpp b/src/mesh/MeshPlugin.cpp index 85988ec7b..985a7060f 100644 --- a/src/mesh/MeshPlugin.cpp +++ b/src/mesh/MeshPlugin.cpp @@ -235,3 +235,18 @@ std::vector MeshPlugin::GetMeshPluginsWithUIFrames() } return pluginsWithUIFrames; } + +void MeshPlugin::observeUIEvents( + Observer *observer) +{ + std::vector pluginsWithUIFrames; + for (auto i = plugins->begin(); i != plugins->end(); ++i) { + auto &pi = **i; + Observable *observable = + pi.getUIFrameObservable(); + if (observable != NULL) { + DEBUG_MSG("Plugin wants a UI Frame\n"); + observer->observe(observable); + } + } +} diff --git a/src/mesh/MeshPlugin.h b/src/mesh/MeshPlugin.h index 0143814a7..b6bcf22b8 100644 --- a/src/mesh/MeshPlugin.h +++ b/src/mesh/MeshPlugin.h @@ -21,6 +21,14 @@ enum class ProcessMessage STOP = 1, }; +/* + * This struct is used by Screen to figure out whether screen frame should be updated. + */ +typedef struct _UIFrameEvent { + bool frameChanged; + bool needRedraw; +} UIFrameEvent; + /** A baseclass for any mesh "plugin". * * A plugin allows you to add new features to meshtastic device code, without needing to know messaging details. @@ -48,6 +56,7 @@ class MeshPlugin static void callPlugins(const MeshPacket &mp, RxSource src = RX_SRC_RADIO); static std::vector GetMeshPluginsWithUIFrames(); + static void observeUIEvents(Observer *observer); #ifndef NO_SCREEN virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { return; } #endif @@ -119,6 +128,7 @@ class MeshPlugin * @return true if you want to be alloced a UI screen frame */ virtual bool wantUIFrame() { return false; } + virtual Observable* getUIFrameObservable() { return NULL; } MeshPacket *allocAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex); diff --git a/src/plugins/CannedMessagePlugin.cpp b/src/plugins/CannedMessagePlugin.cpp index 251a9c2f5..26ef6cce8 100644 --- a/src/plugins/CannedMessagePlugin.cpp +++ b/src/plugins/CannedMessagePlugin.cpp @@ -146,17 +146,19 @@ int32_t CannedMessagePlugin::runOnce() return 30000; // TODO: should return MAX_VAL } DEBUG_MSG("Check status\n"); + UIFrameEvent e = {false, true}; if (this->sendingState == SENDING_STATE_ACTIVE) { // TODO: might have some feedback of sendig state this->sendingState = SENDING_STATE_NONE; - this->notifyObservers(NULL); + this->notifyObservers(&e); } else if ((this->action != CANNED_MESSAGE_ACTION_NONE) && (this->currentMessageIndex == -1)) { this->currentMessageIndex = 0; DEBUG_MSG("First touch.\n"); + e.frameChanged = true; } else if (this->action == CANNED_MESSAGE_ACTION_SELECT) { @@ -166,7 +168,7 @@ int32_t CannedMessagePlugin::runOnce() true); this->sendingState = SENDING_STATE_ACTIVE; this->currentMessageIndex = -1; - this->notifyObservers(NULL); + this->notifyObservers(&e); return 2000; } else if (this->action == CANNED_MESSAGE_ACTION_UP) @@ -182,7 +184,7 @@ int32_t CannedMessagePlugin::runOnce() if (this->action != CANNED_MESSAGE_ACTION_NONE) { this->action = CANNED_MESSAGE_ACTION_NONE; - this->notifyObservers(NULL); + this->notifyObservers(&e); } return 30000; // TODO: should return MAX_VAL diff --git a/src/plugins/CannedMessagePlugin.h b/src/plugins/CannedMessagePlugin.h index 91c394466..10b8f6742 100644 --- a/src/plugins/CannedMessagePlugin.h +++ b/src/plugins/CannedMessagePlugin.h @@ -17,11 +17,12 @@ enum cannedMessagePluginSendigState SENDING_STATE_ACTIVE }; + #define CANNED_MESSAGE_PLUGIN_MESSAGE_MAX_COUNT 50 class CannedMessagePlugin : public SinglePortPlugin, - public Observable, + public Observable, private concurrency::OSThread { CallbackObserver inputObserver = @@ -53,6 +54,7 @@ class CannedMessagePlugin : int handleInputEvent(const InputEvent *event); virtual bool wantUIFrame() { return this->shouldDraw(); } + virtual Observable* getUIFrameObservable() { return this; } virtual void drawFrame( OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); diff --git a/src/plugins/input/RotaryEncoderInterruptBase.cpp b/src/plugins/input/RotaryEncoderInterruptBase.cpp index bff01edb2..e4635eb1a 100644 --- a/src/plugins/input/RotaryEncoderInterruptBase.cpp +++ b/src/plugins/input/RotaryEncoderInterruptBase.cpp @@ -65,7 +65,7 @@ int32_t RotaryEncoderInterruptBase::runOnce() this->action = ROTARY_ACTION_NONE; - return 30000; + return 30000; // TODO: technically this can be MAX_INT } @@ -73,7 +73,7 @@ void RotaryEncoderInterruptBase::intPressHandler() { this->action = ROTARY_ACTION_PRESSED; runned(millis()); - setInterval(20); + setInterval(20); // TODO: this modifies a non-volatile variable! } void RotaryEncoderInterruptBase::intAHandler() @@ -144,7 +144,7 @@ RotaryEncoderInterruptBaseStateType RotaryEncoderInterruptBase::intHandler( newState = ROTARY_EVENT_CLEARED; } runned(millis()); - setInterval(50); + setInterval(50); // TODO: this modifies a non-volatile variable! return newState; }