Merge branch 'master' into tft-gui-work

This commit is contained in:
Manuel 2024-07-12 18:04:42 +02:00 committed by GitHub
commit 5c8fd379a4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 264 additions and 66 deletions

View File

@ -25,13 +25,9 @@ pio run --environment $1 # -v
SRCELF=.pio/build/$1/firmware.elf
cp $SRCELF $OUTDIR/$basename.elf
if (echo $1 | grep -q "wio-sdk-wm1110"); then
echo "Skipping dfu file"
else
echo "Generating NRF52 dfu file"
DFUPKG=.pio/build/$1/firmware.zip
cp $DFUPKG $OUTDIR/$basename-ota.zip
fi
echo "Generating NRF52 dfu file"
DFUPKG=.pio/build/$1/firmware.zip
cp $DFUPKG $OUTDIR/$basename-ota.zip
echo "Generating NRF52 uf2 file"
SRCHEX=.pio/build/$1/firmware.hex

View File

@ -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) {}

View File

@ -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();

View File

@ -5,6 +5,7 @@
#define ONE_MINUTE_MS 60 * 1000
#define default_gps_update_interval IF_ROUTER(ONE_DAY, 2 * 60)
#define default_telemetry_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 30 * 60)
#define default_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 15 * 60)
#define default_wait_bluetooth_secs IF_ROUTER(1, 60)
#define default_sds_secs IF_ROUTER(ONE_DAY, UINT32_MAX) // Default to forever super deep sleep

View File

@ -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

View File

@ -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

View File

@ -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: {

View File

@ -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

View File

@ -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
@ -915,11 +923,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;
@ -941,6 +951,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...");
@ -949,7 +960,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
@ -1032,16 +1043,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);

View File

@ -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;
}
@ -142,7 +141,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;

View File

@ -47,7 +47,8 @@ int32_t AirQualityTelemetryModule::runOnce()
uint32_t now = millis();
if (((lastSentToMesh == 0) ||
((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.air_quality_interval))) &&
((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.air_quality_interval,
default_telemetry_broadcast_interval_secs))) &&
airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) &&
airTime->isTxAllowedAirUtil()) {
sendTelemetry();

View File

@ -17,7 +17,8 @@ int32_t DeviceTelemetryModule::runOnce()
{
refreshUptime();
if (((lastSentToMesh == 0) ||
((uptimeLastMs - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval))) &&
((uptimeLastMs - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval,
default_telemetry_broadcast_interval_secs))) &&
airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) &&
airTime->isTxAllowedAirUtil() && config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER &&
config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN) {

View File

@ -63,7 +63,8 @@ int32_t EnvironmentTelemetryModule::runOnce()
{
if (sleepOnNextExecution == true) {
sleepOnNextExecution = false;
uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval);
uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval,
default_telemetry_broadcast_interval_secs);
LOG_DEBUG("Sleeping for %ims, then awaking to send metrics again.\n", nightyNightMs);
doDeepSleep(nightyNightMs, true);
}
@ -144,7 +145,8 @@ int32_t EnvironmentTelemetryModule::runOnce()
uint32_t now = millis();
if (((lastSentToMesh == 0) ||
((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval))) &&
((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval,
default_telemetry_broadcast_interval_secs))) &&
airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) &&
airTime->isTxAllowedAirUtil()) {
sendTelemetry();

View File

@ -24,7 +24,8 @@ int32_t PowerTelemetryModule::runOnce()
{
if (sleepOnNextExecution == true) {
sleepOnNextExecution = false;
uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval);
uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval,
default_telemetry_broadcast_interval_secs);
LOG_DEBUG("Sleeping for %ims, then awaking to send metrics again.\n", nightyNightMs);
doDeepSleep(nightyNightMs, true);
}
@ -70,7 +71,8 @@ int32_t PowerTelemetryModule::runOnce()
uint32_t now = millis();
if (((lastSentToMesh == 0) ||
((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval))) &&
((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval,
default_telemetry_broadcast_interval_secs))) &&
airTime->isTxAllowedAirUtil()) {
sendTelemetry();
lastSentToMesh = now;

View File

@ -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
}

View File

@ -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);
}
}

View File

@ -101,7 +101,7 @@ int32_t PaxcounterModule::runOnce()
sendInfo(NODENUM_BROADCAST);
}
return Default::getConfiguredOrDefaultMs(moduleConfig.paxcounter.paxcounter_update_interval,
default_broadcast_interval_secs);
default_telemetry_broadcast_interval_secs);
} else {
return disable();
}

View File

@ -286,5 +286,10 @@ void clearBonds()
void enterDfuMode()
{
// SDK kit does not have native USB like almost all other NRF52 boards
#ifdef NRF_USE_SERIAL_DFU
enterSerialDfu();
#else
enterUf2Dfu();
#endif
}

View File

@ -20,7 +20,7 @@ debug_tool = jlink
; No need to reflash if the binary hasn't changed
debug_load_mode = modified
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
upload_protocol = jlink
upload_protocol = nrfutil
;upload_protocol = stlink
; we prefer to stop in setup() because we are an 'ardiuno' app
debug_init_break = tbreak setup

View File

@ -107,6 +107,8 @@ extern "C" {
#define LR1110_GNSS_ANT_PIN (32 + 5) // P1.05 37
#define NRF_USE_SERIAL_DFU
#ifdef __cplusplus
}
#endif