Show specific frame when updating screen (#4264)

* Updated setFrames in Screen.cpp

Added code to attempt to revert back to the same frame that user was on prior to setFrame reload.

* Space added Screen.cpp

* Update Screen.cpp

Make screen to revert to Frame 0 if the originally displayed frame is no longer there.

* Update Screen.cpp

Inserted boolean holdPosition into setFrames to indicate the requirement to stay on the same frame ( if =true) or else it will switch to new frame .
Only Screen::handleStatusUpdate calls with setFrame(true). ( For Node Updates)
All other types of updates call as before setFrame(), so it will change focus as needed.

* Hold position, even if number of frames increases

* Hold position, if handling an outgoing text message

* Update Screen.cpp

* Reverted chnages related to devicestate.has_rx_text_message

* Reset to master

* CannedMessages only handles routing packets when waiting for ACK
Previously, this was calling Screen::setFrames at unexpected times

* Gather position info about screen frames while regenerating

* Make admin module observable
Notify only when relevant. Currently: only to handle remove_nodenum.

* Optionally specify which frame to focus when setFrames runs

* UIFrameEvent uses enum instead of multiple booleans

* Allow modules to request their own frame to be focussed
This is done internally by calling MeshModule::requestFocus()
Easier this way, insteady of passing the info in the UIFrameEvent:
* Modules don't always know whether they should be focussed until after the UIFrameEvent has been raised, in dramFrame
* Don't have to pass reference to module instance as parameter though several methods

* E-Ink screensaver uses FOCUS_PRESERVE
Previously, it had its own basic implementation of this.

* Spelling: regional variant

* trunk

* Fix HAS_SCREEN guarding

* More HAS_SCREEN guarding

---------

Co-authored-by: BIST <77391720+slash-bit@users.noreply.github.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: slash-bit <v-b2@live.com>
pull/4274/head^2
todd-herbert 2024-07-12 11:51:26 +12:00 zatwierdzone przez GitHub
rodzic df194ca0f0
commit eabec5ae34
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
10 zmienionych plików z 239 dodań i 51 usunięć

Wyświetl plik

@ -41,6 +41,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "mesh/Channels.h"
#include "mesh/generated/meshtastic/deviceonly.pb.h"
#include "meshUtils.h"
#include "modules/AdminModule.h"
#include "modules/ExternalNotificationModule.h"
#include "modules/TextMessageModule.h"
#include "sleep.h"
@ -1725,6 +1726,7 @@ void Screen::setup()
powerStatusObserver.observe(&powerStatus->onNewStatus);
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
adminMessageObserver.observe(adminModule);
if (textMessageModule)
textMessageObserver.observe(textMessageModule);
if (inputBroker)
@ -1953,9 +1955,6 @@ void Screen::setWelcomeFrames()
/// Determine which screensaver frame to use, then set the FrameCallback
void Screen::setScreensaverFrames(FrameCallback einkScreensaver)
{
// Remember current frame, restore position at power-on
uint8_t frameNumber = ui->getUiState()->currentFrame;
// Retain specified frame / overlay callback beyond scope of this method
static FrameCallback screensaverFrame;
static OverlayCallback screensaverOverlay;
@ -1993,9 +1992,8 @@ void Screen::setScreensaverFrames(FrameCallback einkScreensaver)
#endif
// Prepare now for next frame, shown when display wakes
ui->setOverlays(NULL, 0); // Clear overlay
setFrames(); // Return to normal display updates
ui->switchToFrame(frameNumber); // Attempt to return to same frame after power-on
ui->setOverlays(NULL, 0); // Clear overlay
setFrames(FOCUS_PRESERVE); // Return to normal display updates, showing same frame as before screensaver, ideally
// Pick a refresh method, for when display wakes
#ifdef EINK_HASQUIRK_GHOSTING
@ -2006,9 +2004,13 @@ void Screen::setScreensaverFrames(FrameCallback einkScreensaver)
}
#endif
// restore our regular frame list
void Screen::setFrames()
// Regenerate the normal set of frames, focusing a specific frame if requested
// Called when a frame should be added / removed, or custom frames should be cleared
void Screen::setFrames(FrameFocus focus)
{
uint8_t originalPosition = ui->getUiState()->currentFrame;
FramesetInfo fsi; // Location of specific frames, for applying focus parameter
LOG_DEBUG("showing standard frames\n");
showingNormalScreen = true;
@ -2042,20 +2044,33 @@ void Screen::setFrames()
// is the same offset into the moduleFrames vector
// so that we can invoke the module's callback
for (auto i = moduleFrames.begin(); i != moduleFrames.end(); ++i) {
normalFrames[numframes++] = drawModuleFrame;
// Draw the module frame, using the hack described above
normalFrames[numframes] = drawModuleFrame;
// Check if the module being drawn has requested focus
// We will honor this request later, if setFrames was triggered by a UIFrameEvent
MeshModule *m = *i;
if (m->isRequestingFocus())
fsi.positions.focusedModule = numframes;
numframes++;
}
LOG_DEBUG("Added modules. numframes: %d\n", numframes);
// If we have a critical fault, show it first
if (error_code)
fsi.positions.fault = numframes;
if (error_code) {
normalFrames[numframes++] = drawCriticalFaultFrame;
focus = FOCUS_FAULT; // Change our "focus" parameter, to ensure we show the fault frame
}
#ifdef T_WATCH_S3
normalFrames[numframes++] = screen->digitalWatchFace ? &Screen::drawDigitalClockFrame : &Screen::drawAnalogClockFrame;
#endif
// If we have a text message - show it next, unless it's a phone message and we aren't using any special modules
fsi.positions.textMessage = numframes;
if (devicestate.has_rx_text_message && shouldDrawMessage(&devicestate.rx_text_message)) {
normalFrames[numframes++] = drawTextMessageFrame;
}
@ -2070,11 +2085,14 @@ void Screen::setFrames()
//
// Since frames are basic function pointers, we have to use a helper to
// call a method on debugInfo object.
fsi.positions.log = numframes;
normalFrames[numframes++] = &Screen::drawDebugInfoTrampoline;
// call a method on debugInfoScreen object (for more details)
fsi.positions.settings = numframes;
normalFrames[numframes++] = &Screen::drawDebugInfoSettingsTrampoline;
fsi.positions.wifi = numframes;
#if HAS_WIFI && !defined(ARCH_PORTDUINO)
if (isWifiAvailable()) {
// call a method on debugInfoScreen object (for more details)
@ -2082,6 +2100,7 @@ void Screen::setFrames()
}
#endif
fsi.frameCount = numframes; // Total framecount is used to apply FOCUS_PRESERVE
LOG_DEBUG("Finished building frames. numframes: %d\n", numframes);
ui->setFrames(normalFrames, numframes);
@ -2095,6 +2114,55 @@ void Screen::setFrames()
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list
// just changed)
// Focus on a specific frame, in the frame set we just created
switch (focus) {
case FOCUS_DEFAULT:
ui->switchToFrame(0); // First frame
break;
case FOCUS_FAULT:
ui->switchToFrame(fsi.positions.fault);
break;
case FOCUS_TEXTMESSAGE:
ui->switchToFrame(fsi.positions.textMessage);
break;
case FOCUS_MODULE:
// Whichever frame was marked by MeshModule::requestFocus(), if any
// If no module requested focus, will show the first frame instead
ui->switchToFrame(fsi.positions.focusedModule);
break;
case FOCUS_PRESERVE:
// If we can identify which type of frame "originalPosition" was, can move directly to it in the new frameset
FramesetInfo &oldFsi = this->framesetInfo;
if (originalPosition == oldFsi.positions.log)
ui->switchToFrame(fsi.positions.log);
else if (originalPosition == oldFsi.positions.settings)
ui->switchToFrame(fsi.positions.settings);
else if (originalPosition == oldFsi.positions.wifi)
ui->switchToFrame(fsi.positions.wifi);
// If frame count has decreased
else if (fsi.frameCount < oldFsi.frameCount) {
uint8_t numDropped = oldFsi.frameCount - fsi.frameCount;
// Move n frames backwards
if (numDropped <= originalPosition)
ui->switchToFrame(originalPosition - numDropped);
// Unless that would put us "out of bounds" (< 0)
else
ui->switchToFrame(0);
}
// If we're not sure exactly which frame we were on, at least return to the same frame number
// (node frames; module frames)
else
ui->switchToFrame(originalPosition);
break;
}
// Store the info about this frameset, for future setFrames calls
this->framesetInfo = fsi;
setFastFramerate(); // Draw ASAP
}
@ -2549,7 +2617,7 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg)
switch (arg->getStatusType()) {
case STATUS_TYPE_NODE:
if (showingNormalScreen && nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal()) {
setFrames(); // Regen the list of screens
setFrames(FOCUS_PRESERVE); // Regen the list of screen frames (returning to same frame, if possible)
}
nodeDB->updateGUI = false;
break;
@ -2561,23 +2629,33 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg)
int Screen::handleTextMessage(const meshtastic_MeshPacket *packet)
{
if (showingNormalScreen) {
setFrames(); // Regen the list of screens (will show new text message)
// Outgoing message
if (packet->from == 0)
setFrames(FOCUS_PRESERVE); // Return to same frame (quietly hiding the rx text message frame)
// Incoming message
else
setFrames(FOCUS_TEXTMESSAGE); // Focus on the new message
}
return 0;
}
// Triggered by MeshModules
int Screen::handleUIFrameEvent(const UIFrameEvent *event)
{
if (showingNormalScreen) {
if (event->frameChanged) {
setFrames(); // Regen the list of screens (will show new text message)
} else if (event->needRedraw) {
// Regenerate the frameset, potentially honoring a module's internal requestFocus() call
if (event->action == UIFrameEvent::Action::REGENERATE_FRAMESET)
setFrames(FOCUS_MODULE);
// Regenerate the frameset, while attempting to maintain focus on the current frame
else if (event->action == UIFrameEvent::Action::REGENERATE_FRAMESET_BACKGROUND)
setFrames(FOCUS_PRESERVE);
// Don't regenerate the frameset, just re-draw whatever is on screen ASAP
else if (event->action == UIFrameEvent::Action::REDRAW_ONLY)
setFastFramerate();
// TODO: We might also want switch to corresponding frame,
// but we don't know the exact frame number.
// ui->switchToFrame(0);
}
}
return 0;
@ -2612,6 +2690,24 @@ int Screen::handleInputEvent(const InputEvent *event)
return 0;
}
int Screen::handleAdminMessage(const meshtastic_AdminMessage *arg)
{
// Note: only selected admin messages notify this observer
// If you wish to handle a new type of message, you should modify AdminModule.cpp first
switch (arg->which_payload_variant) {
// Node removed manually (i.e. via app)
case meshtastic_AdminMessage_remove_by_nodenum_tag:
setFrames(FOCUS_PRESERVE);
break;
// Default no-op, in case the admin message observable gets used by other classes in future
default:
break;
}
return 0;
}
} // namespace graphics
#else
graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {}

Wyświetl plik

@ -173,9 +173,11 @@ class Screen : public concurrency::OSThread
CallbackObserver<Screen, const meshtastic_MeshPacket *> textMessageObserver =
CallbackObserver<Screen, const meshtastic_MeshPacket *>(this, &Screen::handleTextMessage);
CallbackObserver<Screen, const UIFrameEvent *> uiFrameEventObserver =
CallbackObserver<Screen, const UIFrameEvent *>(this, &Screen::handleUIFrameEvent);
CallbackObserver<Screen, const UIFrameEvent *>(this, &Screen::handleUIFrameEvent); // Sent by Mesh Modules
CallbackObserver<Screen, const InputEvent *> inputObserver =
CallbackObserver<Screen, const InputEvent *>(this, &Screen::handleInputEvent);
CallbackObserver<Screen, const meshtastic_AdminMessage *> adminMessageObserver =
CallbackObserver<Screen, const meshtastic_AdminMessage *>(this, &Screen::handleAdminMessage);
public:
explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY);
@ -394,6 +396,7 @@ class Screen : public concurrency::OSThread
int handleTextMessage(const meshtastic_MeshPacket *arg);
int handleUIFrameEvent(const UIFrameEvent *arg);
int handleInputEvent(const InputEvent *arg);
int handleAdminMessage(const meshtastic_AdminMessage *arg);
/// Used to force (super slow) eink displays to draw critical frames
void forceDisplay(bool forceUiUpdate = false);
@ -450,8 +453,34 @@ class Screen : public concurrency::OSThread
void handleShowPrevFrame();
void handlePrint(const char *text);
void handleStartFirmwareUpdateScreen();
/// Rebuilds our list of frames (screens) to default ones.
void setFrames();
// Info collected by setFrames method.
// Index location of specific frames. Used to apply the FrameFocus parameter of setFrames
struct FramesetInfo {
struct FramePositions {
uint8_t fault = 0;
uint8_t textMessage = 0;
uint8_t focusedModule = 0;
uint8_t log = 0;
uint8_t settings = 0;
uint8_t wifi = 0;
} positions;
uint8_t frameCount = 0;
} framesetInfo;
// Which frame we want to be displayed, after we regen the frameset by calling setFrames
enum FrameFocus : uint8_t {
FOCUS_DEFAULT, // No specific frame
FOCUS_PRESERVE, // Return to the previous frame
FOCUS_FAULT,
FOCUS_TEXTMESSAGE,
FOCUS_MODULE, // Note: target module should call requestFocus(), otherwise no info about which module to focus
};
// Regenerate the normal set of frames, focusing a specific frame if requested
// Call when a frame should be added / removed, or custom frames should be cleared
void setFrames(FrameFocus focus = FOCUS_DEFAULT);
/// Try to start drawing ASAP
void setFastFramerate();

Wyświetl plik

@ -284,4 +284,17 @@ AdminMessageHandleResult MeshModule::handleAdminMessageForAllModules(const mesht
}
}
return handled;
}
}
#if HAS_SCREEN
// Would our module like its frame to be focused after Screen::setFrames has regenerated the list of frames?
// Only considered if setFrames is triggered by a UIFrameEvent
bool MeshModule::isRequestingFocus()
{
if (_requestingFocus) {
_requestingFocus = false; // Consume the request
return true;
} else
return false;
}
#endif

Wyświetl plik

@ -35,10 +35,16 @@ enum class AdminMessageHandleResult {
/*
* This struct is used by Screen to figure out whether screen frame should be updated.
*/
typedef struct _UIFrameEvent {
bool frameChanged;
bool needRedraw;
} UIFrameEvent;
struct UIFrameEvent {
// What do we actually want to happen?
enum Action {
REDRAW_ONLY, // Don't change which frames are show, just redraw, asap
REGENERATE_FRAMESET, // Regenerate (change? add? remove?) screen frames, honoring requestFocus()
REGENERATE_FRAMESET_BACKGROUND, // Regenerate screen frames, attempting to remain on the same frame throughout
} action = REDRAW_ONLY;
// We might want to pass additional data inside this struct at some point
};
/** A baseclass for any mesh "module".
*
@ -73,6 +79,7 @@ class MeshModule
meshtastic_AdminMessage *response);
#if HAS_SCREEN
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { return; }
virtual bool isRequestingFocus(); // Checked by screen, when regenerating frameset
#endif
protected:
const char *name;
@ -176,6 +183,19 @@ class MeshModule
return AdminMessageHandleResult::NOT_HANDLED;
};
#if HAS_SCREEN
/** Request that our module's screen frame be focused when Screen::setFrames runs
* Only considered if Screen::setFrames is triggered via a UIFrameEvent
*
* Having this as a separate call, instead of part of the UIFrameEvent, allows the module to delay decision
* until drawFrame() is called. This required less restructuring.
*/
bool _requestingFocus = false;
void requestFocus() { _requestingFocus = true; }
#else
void requestFocus(){}; // No-op
#endif
private:
/**
* If any of the current chain of modules has already sent a reply, it will be here. This is useful to allow

Wyświetl plik

@ -200,6 +200,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
case meshtastic_AdminMessage_remove_by_nodenum_tag: {
LOG_INFO("Client is receiving a remove_nodenum command.\n");
nodeDB->removeNodeByNum(r->remove_by_nodenum);
this->notifyObservers(r); // Observed by screen
break;
}
case meshtastic_AdminMessage_set_favorite_node_tag: {

Wyświetl plik

@ -7,7 +7,7 @@
/**
* Admin module for admin messages
*/
class AdminModule : public ProtobufModule<meshtastic_AdminMessage>
class AdminModule : public ProtobufModule<meshtastic_AdminMessage>, public Observable<const meshtastic_AdminMessage *>
{
public:
/** Constructor

Wyświetl plik

@ -148,8 +148,9 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
if (this->currentMessageIndex == 0) {
this->runState = CANNED_MESSAGE_RUN_STATE_FREETEXT;
UIFrameEvent e = {false, true};
e.frameChanged = true;
requestFocus(); // Tell Screen::setFrames to move to our module's frame, next time it runs
UIFrameEvent e;
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen
this->notifyObservers(&e);
return 0;
@ -166,8 +167,8 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
}
}
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL)) {
UIFrameEvent e = {false, true};
e.frameChanged = true;
UIFrameEvent e;
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen
this->currentMessageIndex = -1;
#if !defined(T_WATCH_S3) && !defined(RAK14014)
@ -353,6 +354,8 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
}
if (validEvent) {
requestFocus(); // Tell Screen::setFrames to move to our module's frame, next time it runs
// Let runOnce to be called immediately.
if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_SELECT) {
setIntervalFromNow(0); // on fast keypresses, this isn't fast enough.
@ -378,6 +381,11 @@ void CannedMessageModule::sendText(NodeNum dest, ChannelIndex channel, const cha
p->decoded.payload.size++;
}
// Only receive routing messages when expecting ACK for a canned message
// Prevents the canned message module from regenerating the screen's frameset at unexpected times,
// or raising a UIFrameEvent before another module has the chance
this->waitingForAck = true;
LOG_INFO("Sending message id=%d, dest=%x, msg=%.*s\n", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes);
service.sendToMesh(
@ -393,13 +401,13 @@ int32_t CannedMessageModule::runOnce()
return INT32_MAX;
}
// LOG_DEBUG("Check status\n");
UIFrameEvent e = {false, true};
UIFrameEvent e;
if ((this->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) ||
(this->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) || (this->runState == CANNED_MESSAGE_RUN_STATE_MESSAGE)) {
// TODO: might have some feedback of sending state
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
temporaryMessage = "";
e.frameChanged = true;
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen
this->currentMessageIndex = -1;
this->freetext = ""; // clear freetext
this->cursor = 0;
@ -412,7 +420,7 @@ int32_t CannedMessageModule::runOnce()
} else if (((this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT)) &&
((millis() - this->lastTouchMillis) > INACTIVATE_AFTER_MS)) {
// Reset module
e.frameChanged = true;
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen
this->currentMessageIndex = -1;
this->freetext = ""; // clear freetext
this->cursor = 0;
@ -449,7 +457,7 @@ int32_t CannedMessageModule::runOnce()
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
}
}
e.frameChanged = true;
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen
this->currentMessageIndex = -1;
this->freetext = ""; // clear freetext
this->cursor = 0;
@ -463,7 +471,7 @@ int32_t CannedMessageModule::runOnce()
} else if ((this->runState != CANNED_MESSAGE_RUN_STATE_FREETEXT) && (this->currentMessageIndex == -1)) {
this->currentMessageIndex = 0;
LOG_DEBUG("First touch (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage());
e.frameChanged = true;
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen
this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE;
} else if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_UP) {
if (this->messagesCount > 0) {
@ -567,7 +575,7 @@ int32_t CannedMessageModule::runOnce()
break;
}
if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
e.frameChanged = true;
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen
switch (this->payload) { // code below all trigger the freetext window (where you type to send a message) or reset the
// display back to the default window
case 0x08: // backspace
@ -706,8 +714,8 @@ int CannedMessageModule::getPrevIndex()
void CannedMessageModule::showTemporaryMessage(const String &message)
{
temporaryMessage = message;
UIFrameEvent e = {false, true};
e.frameChanged = true;
UIFrameEvent e;
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen
notifyObservers(&e);
runState = CANNED_MESSAGE_RUN_STATE_MESSAGE;
// run this loop again in 2 seconds, next iteration will clear the display
@ -914,11 +922,13 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
char buffer[50];
if (temporaryMessage.length() != 0) {
requestFocus(); // Tell Screen::setFrames to move to our module's frame
LOG_DEBUG("Drawing temporary message: %s", temporaryMessage.c_str());
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_MEDIUM);
display->drawString(display->getWidth() / 2 + x, 0 + y + 12, temporaryMessage);
} else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) {
requestFocus(); // Tell Screen::setFrames to move to our module's frame
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_MEDIUM);
String displayString;
@ -940,6 +950,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
display->drawStringf(display->getWidth() / 2 + x, y + 130, buffer, rssiString, this->lastRxRssi);
}
} else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) {
requestFocus(); // Tell Screen::setFrames to move to our module's frame
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_MEDIUM);
display->drawString(display->getWidth() / 2 + x, 0 + y + 12, "Sending...");
@ -948,7 +959,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
display->setFont(FONT_SMALL);
display->drawString(10 + x, 0 + y + FONT_HEIGHT_SMALL, "Canned Message\nModule disabled.");
} else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
requestFocus(); // Tell Screen::setFrames to move to our module's frame
#if defined(T_WATCH_S3) || defined(RAK14014)
drawKeyboard(display, state, 0, 0);
#else
@ -1030,16 +1041,18 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
ProcessMessage CannedMessageModule::handleReceived(const meshtastic_MeshPacket &mp)
{
if (mp.decoded.portnum == meshtastic_PortNum_ROUTING_APP) {
if (mp.decoded.portnum == meshtastic_PortNum_ROUTING_APP && waitingForAck) {
// look for a request_id
if (mp.decoded.request_id != 0) {
UIFrameEvent e = {false, true};
e.frameChanged = true;
UIFrameEvent e;
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen
requestFocus(); // Tell Screen::setFrames that our module's frame should be shown, even if not "first" in the frameset
this->runState = CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED;
this->incoming = service.getNodenumFromRequestId(mp.decoded.request_id);
meshtastic_Routing decoded = meshtastic_Routing_init_default;
pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, meshtastic_Routing_fields, &decoded);
this->ack = decoded.error_reason == meshtastic_Routing_Error_NONE;
waitingForAck = false; // No longer want routing packets
this->notifyObservers(&e);
// run the next time 2 seconds later
setIntervalFromNow(2000);

Wyświetl plik

@ -81,9 +81,8 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
}
switch (p->decoded.portnum) {
case meshtastic_PortNum_TEXT_MESSAGE_APP:
case meshtastic_PortNum_ROUTING_APP:
return true;
return waitingForAck;
default:
return false;
}
@ -140,7 +139,8 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
uint8_t numChannels = 0;
ChannelIndex indexChannels[MAX_NUM_CHANNELS] = {0};
NodeNum incoming = NODENUM_BROADCAST;
bool ack = false; // True means ACK, false means NAK (error_reason != NONE)
bool ack = false; // True means ACK, false means NAK (error_reason != NONE)
bool waitingForAck = false; // Are currently interested in routing packets?
float lastRxSnr = 0;
int32_t lastRxRssi = 0;

Wyświetl plik

@ -16,15 +16,31 @@ ProcessMessage WaypointModule::handleReceived(const meshtastic_MeshPacket &mp)
auto &p = mp.decoded;
LOG_INFO("Received waypoint msg from=0x%0x, id=0x%x, msg=%.*s\n", mp.from, mp.id, p.payload.size, p.payload.bytes);
#endif
UIFrameEvent e = {true, true};
// We only store/display messages destined for us.
// Keep a copy of the most recent text message.
devicestate.rx_waypoint = mp;
devicestate.has_rx_waypoint = true;
powerFSM.trigger(EVENT_RECEIVED_MSG);
#if HAS_SCREEN
UIFrameEvent e;
// New or updated waypoint: focus on this frame next time Screen::setFrames runs
if (shouldDraw()) {
requestFocus();
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET;
}
// Deleting an old waypoint: remove the frame quietly, don't change frame position if possible
else
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET_BACKGROUND;
notifyObservers(&e);
#endif
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
}

Wyświetl plik

@ -190,13 +190,13 @@ int32_t AudioModule::runOnce()
firstTime = false;
} else {
UIFrameEvent e = {false, true};
UIFrameEvent e;
// Check if PTT is pressed. TODO hook that into Onebutton/Interrupt drive.
if (digitalRead(moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN) == HIGH) {
if (radio_state == RadioState::rx) {
LOG_INFO("PTT pressed, switching to TX\n");
radio_state = RadioState::tx;
e.frameChanged = true;
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen
this->notifyObservers(&e);
}
} else {
@ -209,7 +209,7 @@ int32_t AudioModule::runOnce()
}
tx_encode_frame_index = sizeof(tx_header);
radio_state = RadioState::rx;
e.frameChanged = true;
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen
this->notifyObservers(&e);
}
}