mirror of
https://github.com/meshtastic/firmware.git
synced 2025-10-28 23:34:03 +00:00
Decoupled message packets from screen.cpp and cleaned up
This commit is contained in:
parent
dd7a5cf31f
commit
ebbb8a6f9f
@ -1,9 +1,9 @@
|
|||||||
#include "MessageStore.h"
|
#include "MessageStore.h"
|
||||||
#include "FSCommon.h"
|
#include "FSCommon.h"
|
||||||
#include "NodeDB.h" // for nodeDB->getNodeNum()
|
#include "NodeDB.h"
|
||||||
#include "SPILock.h"
|
#include "SPILock.h"
|
||||||
#include "SafeFile.h"
|
#include "SafeFile.h"
|
||||||
#include "configuration.h" // for millis()
|
#include "configuration.h"
|
||||||
#include "gps/RTC.h"
|
#include "gps/RTC.h"
|
||||||
#include "graphics/draw/MessageRenderer.h"
|
#include "graphics/draw/MessageRenderer.h"
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ MessageStore::MessageStore(const std::string &label)
|
|||||||
filename = "/Messages_" + label + ".msgs";
|
filename = "/Messages_" + label + ".msgs";
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Live message handling (RAM only) ===
|
// Live message handling (RAM only)
|
||||||
void MessageStore::addLiveMessage(const StoredMessage &msg)
|
void MessageStore::addLiveMessage(const StoredMessage &msg)
|
||||||
{
|
{
|
||||||
if (liveMessages.size() >= MAX_MESSAGES_SAVED) {
|
if (liveMessages.size() >= MAX_MESSAGES_SAVED) {
|
||||||
@ -24,7 +24,7 @@ void MessageStore::addLiveMessage(const StoredMessage &msg)
|
|||||||
liveMessages.push_back(msg);
|
liveMessages.push_back(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Persistence queue (used only on shutdown/reboot) ===
|
// Persistence queue (used only on shutdown/reboot)
|
||||||
void MessageStore::addMessage(const StoredMessage &msg)
|
void MessageStore::addMessage(const StoredMessage &msg)
|
||||||
{
|
{
|
||||||
if (messages.size() >= MAX_MESSAGES_SAVED) {
|
if (messages.size() >= MAX_MESSAGES_SAVED) {
|
||||||
@ -32,8 +32,7 @@ void MessageStore::addMessage(const StoredMessage &msg)
|
|||||||
}
|
}
|
||||||
messages.push_back(msg);
|
messages.push_back(msg);
|
||||||
}
|
}
|
||||||
|
const StoredMessage &MessageStore::addFromPacket(const meshtastic_MeshPacket &packet)
|
||||||
void MessageStore::addFromPacket(const meshtastic_MeshPacket &packet)
|
|
||||||
{
|
{
|
||||||
StoredMessage sm;
|
StoredMessage sm;
|
||||||
|
|
||||||
@ -47,11 +46,22 @@ void MessageStore::addFromPacket(const meshtastic_MeshPacket &packet)
|
|||||||
sm.isBootRelative = true; // mark for later upgrade
|
sm.isBootRelative = true; // mark for later upgrade
|
||||||
}
|
}
|
||||||
|
|
||||||
sm.sender = packet.from;
|
|
||||||
sm.channelIndex = packet.channel;
|
sm.channelIndex = packet.channel;
|
||||||
sm.text = std::string(reinterpret_cast<const char *>(packet.decoded.payload.bytes));
|
sm.text = std::string(reinterpret_cast<const char *>(packet.decoded.payload.bytes));
|
||||||
|
|
||||||
// Classification logic
|
if (packet.from == 0) {
|
||||||
|
// Phone-originated (outgoing)
|
||||||
|
sm.sender = nodeDB->getNodeNum(); // our node ID
|
||||||
|
if (packet.decoded.dest == 0 || packet.decoded.dest == NODENUM_BROADCAST) {
|
||||||
|
sm.dest = NODENUM_BROADCAST;
|
||||||
|
sm.type = MessageType::BROADCAST;
|
||||||
|
} else {
|
||||||
|
sm.dest = packet.decoded.dest;
|
||||||
|
sm.type = MessageType::DM_TO_US;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Normal incoming
|
||||||
|
sm.sender = packet.from;
|
||||||
if (packet.to == NODENUM_BROADCAST || packet.decoded.dest == NODENUM_BROADCAST) {
|
if (packet.to == NODENUM_BROADCAST || packet.decoded.dest == NODENUM_BROADCAST) {
|
||||||
sm.dest = NODENUM_BROADCAST;
|
sm.dest = NODENUM_BROADCAST;
|
||||||
sm.type = MessageType::BROADCAST;
|
sm.type = MessageType::BROADCAST;
|
||||||
@ -62,11 +72,15 @@ void MessageStore::addFromPacket(const meshtastic_MeshPacket &packet)
|
|||||||
sm.dest = NODENUM_BROADCAST; // fallback
|
sm.dest = NODENUM_BROADCAST; // fallback
|
||||||
sm.type = MessageType::BROADCAST;
|
sm.type = MessageType::BROADCAST;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
addLiveMessage(sm);
|
addLiveMessage(sm);
|
||||||
|
|
||||||
|
// Return reference to the most recently stored message
|
||||||
|
return liveMessages.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Outgoing/manual message ===
|
// Outgoing/manual message
|
||||||
void MessageStore::addFromString(uint32_t sender, uint8_t channelIndex, const std::string &text)
|
void MessageStore::addFromString(uint32_t sender, uint8_t channelIndex, const std::string &text)
|
||||||
{
|
{
|
||||||
StoredMessage sm;
|
StoredMessage sm;
|
||||||
@ -92,7 +106,7 @@ void MessageStore::addFromString(uint32_t sender, uint8_t channelIndex, const st
|
|||||||
addLiveMessage(sm);
|
addLiveMessage(sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Save RAM queue to flash (called on shutdown) ===
|
// Save RAM queue to flash (called on shutdown)
|
||||||
void MessageStore::saveToFlash()
|
void MessageStore::saveToFlash()
|
||||||
{
|
{
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
@ -128,7 +142,7 @@ void MessageStore::saveToFlash()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Load persisted messages into RAM (called at boot) ===
|
// Load persisted messages into RAM (called at boot)
|
||||||
void MessageStore::loadFromFlash()
|
void MessageStore::loadFromFlash()
|
||||||
{
|
{
|
||||||
messages.clear();
|
messages.clear();
|
||||||
@ -189,7 +203,7 @@ void MessageStore::loadFromFlash()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Clear all messages (RAM + persisted queue) ===
|
// Clear all messages (RAM + persisted queue)
|
||||||
void MessageStore::clearAllMessages()
|
void MessageStore::clearAllMessages()
|
||||||
{
|
{
|
||||||
liveMessages.clear();
|
liveMessages.clear();
|
||||||
@ -203,7 +217,7 @@ void MessageStore::clearAllMessages()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Dismiss oldest message (RAM + persisted queue) ===
|
// Dismiss oldest message (RAM + persisted queue)
|
||||||
void MessageStore::dismissOldestMessage()
|
void MessageStore::dismissOldestMessage()
|
||||||
{
|
{
|
||||||
if (!liveMessages.empty()) {
|
if (!liveMessages.empty()) {
|
||||||
@ -215,7 +229,7 @@ void MessageStore::dismissOldestMessage()
|
|||||||
saveToFlash();
|
saveToFlash();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Dismiss newest message (RAM + persisted queue) ===
|
// Dismiss newest message (RAM + persisted queue)
|
||||||
void MessageStore::dismissNewestMessage()
|
void MessageStore::dismissNewestMessage()
|
||||||
{
|
{
|
||||||
if (!liveMessages.empty()) {
|
if (!liveMessages.empty()) {
|
||||||
@ -227,7 +241,7 @@ void MessageStore::dismissNewestMessage()
|
|||||||
saveToFlash();
|
saveToFlash();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Helper filters for future use ===
|
// Helper filters for future use
|
||||||
std::deque<StoredMessage> MessageStore::getChannelMessages(uint8_t channel) const
|
std::deque<StoredMessage> MessageStore::getChannelMessages(uint8_t channel) const
|
||||||
{
|
{
|
||||||
std::deque<StoredMessage> result;
|
std::deque<StoredMessage> result;
|
||||||
@ -250,7 +264,7 @@ std::deque<StoredMessage> MessageStore::getDirectMessages() const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Upgrade boot-relative timestamps once RTC is valid ===
|
// Upgrade boot-relative timestamps once RTC is valid
|
||||||
// Only same-boot boot-relative messages are healed.
|
// Only same-boot boot-relative messages are healed.
|
||||||
// Persisted boot-relative messages from old boots stay ??? forever.
|
// Persisted boot-relative messages from old boots stay ??? forever.
|
||||||
void MessageStore::upgradeBootRelativeTimestamps()
|
void MessageStore::upgradeBootRelativeTimestamps()
|
||||||
@ -280,5 +294,5 @@ void MessageStore::upgradeBootRelativeTimestamps()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Global definition ===
|
// Global definition
|
||||||
MessageStore messageStore("default");
|
MessageStore messageStore("default");
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "mesh/generated/meshtastic/mesh.pb.h" // for meshtastic_MeshPacket
|
#include "mesh/generated/meshtastic/mesh.pb.h"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -42,32 +42,31 @@ class MessageStore
|
|||||||
public:
|
public:
|
||||||
explicit MessageStore(const std::string &label);
|
explicit MessageStore(const std::string &label);
|
||||||
|
|
||||||
// === Live RAM methods (always current, used by UI and runtime) ===
|
// Live RAM methods (always current, used by UI and runtime)
|
||||||
void addLiveMessage(const StoredMessage &msg);
|
void addLiveMessage(const StoredMessage &msg);
|
||||||
const std::deque<StoredMessage> &getLiveMessages() const { return liveMessages; }
|
const std::deque<StoredMessage> &getLiveMessages() const { return liveMessages; }
|
||||||
|
|
||||||
// === Persistence methods (used only on boot/shutdown) ===
|
// Persistence methods (used only on boot/shutdown)
|
||||||
void addMessage(const StoredMessage &msg); // Add to persistence queue
|
void addMessage(const StoredMessage &msg);
|
||||||
void addFromPacket(const meshtastic_MeshPacket &mp); // Incoming → RAM only
|
const StoredMessage &addFromPacket(const meshtastic_MeshPacket &mp); // Incoming/outgoing → RAM only
|
||||||
void addFromString(uint32_t sender, uint8_t channelIndex,
|
void addFromString(uint32_t sender, uint8_t channelIndex, const std::string &text);
|
||||||
const std::string &text); // Outgoing/manual → RAM only
|
void saveToFlash();
|
||||||
void saveToFlash(); // Persist RAM → flash
|
void loadFromFlash();
|
||||||
void loadFromFlash(); // Restore flash → RAM
|
|
||||||
|
|
||||||
// === Clear all messages (RAM + persisted queue) ===
|
// Clear all messages (RAM + persisted queue)
|
||||||
void clearAllMessages();
|
void clearAllMessages();
|
||||||
|
|
||||||
// === Dismiss helpers ===
|
// Dismiss helpers
|
||||||
void dismissOldestMessage(); // Drop front() from history
|
void dismissOldestMessage();
|
||||||
void dismissNewestMessage(); // Drop back() from history (useful for current screen)
|
void dismissNewestMessage();
|
||||||
|
|
||||||
// === Unified accessor (for UI code, defaults to RAM buffer) ===
|
// Unified accessor (for UI code, defaults to RAM buffer)
|
||||||
const std::deque<StoredMessage> &getMessages() const { return liveMessages; }
|
const std::deque<StoredMessage> &getMessages() const { return liveMessages; }
|
||||||
|
|
||||||
// Optional: direct access to persisted copy (mainly for debugging/inspection)
|
// Optional: direct access to persisted copy (mainly for debugging/inspection)
|
||||||
const std::deque<StoredMessage> &getPersistedMessages() const { return messages; }
|
const std::deque<StoredMessage> &getPersistedMessages() const { return messages; }
|
||||||
|
|
||||||
// === Helper filters for future use ===
|
// Helper filters for future use
|
||||||
std::deque<StoredMessage> getChannelMessages(uint8_t channel) const;
|
std::deque<StoredMessage> getChannelMessages(uint8_t channel) const;
|
||||||
std::deque<StoredMessage> getDirectMessages() const;
|
std::deque<StoredMessage> getDirectMessages() const;
|
||||||
std::deque<StoredMessage> getConversationWith(uint32_t peer) const;
|
std::deque<StoredMessage> getConversationWith(uint32_t peer) const;
|
||||||
@ -76,14 +75,10 @@ class MessageStore
|
|||||||
void upgradeBootRelativeTimestamps();
|
void upgradeBootRelativeTimestamps();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// RAM buffer (always current, main source for UI)
|
|
||||||
std::deque<StoredMessage> liveMessages;
|
std::deque<StoredMessage> liveMessages;
|
||||||
|
std::deque<StoredMessage> messages; // persisted copy
|
||||||
// Persisted storage (only updated on shutdown, loaded at boot)
|
|
||||||
std::deque<StoredMessage> messages;
|
|
||||||
|
|
||||||
std::string filename;
|
std::string filename;
|
||||||
};
|
};
|
||||||
|
|
||||||
// === Global instance (defined in MessageStore.cpp) ===
|
// Global instance (defined in MessageStore.cpp)
|
||||||
extern MessageStore messageStore;
|
extern MessageStore messageStore;
|
||||||
@ -283,12 +283,6 @@ static void drawModuleFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int
|
|||||||
pi.drawFrame(display, state, x, y);
|
pi.drawFrame(display, state, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore messages originating from phone (from the current node 0x0) unless range test or store and forward module are enabled
|
|
||||||
static bool shouldDrawMessage(const meshtastic_MeshPacket *packet)
|
|
||||||
{
|
|
||||||
return packet->from != 0 && !moduleConfig.store_forward.enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a recent lat/lon return a guess of the heading the user is walking on.
|
* Given a recent lat/lon return a guess of the heading the user is walking on.
|
||||||
*
|
*
|
||||||
@ -514,10 +508,10 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
|
|||||||
void Screen::setup()
|
void Screen::setup()
|
||||||
{
|
{
|
||||||
|
|
||||||
// === Enable display rendering ===
|
// Enable display rendering
|
||||||
useDisplay = true;
|
useDisplay = true;
|
||||||
|
|
||||||
// === Load saved brightness from UI config ===
|
// Load saved brightness from UI config
|
||||||
// For OLED displays (SSD1306), default brightness is 255 if not set
|
// For OLED displays (SSD1306), default brightness is 255 if not set
|
||||||
if (uiconfig.screen_brightness == 0) {
|
if (uiconfig.screen_brightness == 0) {
|
||||||
#if defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107)
|
#if defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107)
|
||||||
@ -529,7 +523,7 @@ void Screen::setup()
|
|||||||
brightness = uiconfig.screen_brightness;
|
brightness = uiconfig.screen_brightness;
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Detect OLED subtype (if supported by board variant) ===
|
// Detect OLED subtype (if supported by board variant)
|
||||||
#ifdef AutoOLEDWire_h
|
#ifdef AutoOLEDWire_h
|
||||||
if (isAUTOOled)
|
if (isAUTOOled)
|
||||||
static_cast<AutoOLEDWire *>(dispdev)->setDetected(model);
|
static_cast<AutoOLEDWire *>(dispdev)->setDetected(model);
|
||||||
@ -544,7 +538,7 @@ void Screen::setup()
|
|||||||
static_cast<ST7789Spi *>(dispdev)->setRGB(TFT_MESH);
|
static_cast<ST7789Spi *>(dispdev)->setRGB(TFT_MESH);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// === Initialize display and UI system ===
|
// Initialize display and UI system
|
||||||
ui->init();
|
ui->init();
|
||||||
displayWidth = dispdev->width();
|
displayWidth = dispdev->width();
|
||||||
displayHeight = dispdev->height();
|
displayHeight = dispdev->height();
|
||||||
@ -556,7 +550,7 @@ void Screen::setup()
|
|||||||
ui->disableAllIndicators(); // Disable page indicator dots
|
ui->disableAllIndicators(); // Disable page indicator dots
|
||||||
ui->getUiState()->userData = this; // Allow static callbacks to access Screen instance
|
ui->getUiState()->userData = this; // Allow static callbacks to access Screen instance
|
||||||
|
|
||||||
// === Apply loaded brightness ===
|
// Apply loaded brightness
|
||||||
#if defined(ST7789_CS)
|
#if defined(ST7789_CS)
|
||||||
static_cast<TFTDisplay *>(dispdev)->setDisplayBrightness(brightness);
|
static_cast<TFTDisplay *>(dispdev)->setDisplayBrightness(brightness);
|
||||||
#elif defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SPISSD1306)
|
#elif defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SPISSD1306)
|
||||||
@ -564,20 +558,20 @@ void Screen::setup()
|
|||||||
#endif
|
#endif
|
||||||
LOG_INFO("Applied screen brightness: %d", brightness);
|
LOG_INFO("Applied screen brightness: %d", brightness);
|
||||||
|
|
||||||
// === Set custom overlay callbacks ===
|
// Set custom overlay callbacks
|
||||||
static OverlayCallback overlays[] = {
|
static OverlayCallback overlays[] = {
|
||||||
graphics::UIRenderer::drawNavigationBar // Custom indicator icons for each frame
|
graphics::UIRenderer::drawNavigationBar // Custom indicator icons for each frame
|
||||||
};
|
};
|
||||||
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
||||||
|
|
||||||
// === Enable UTF-8 to display mapping ===
|
// Enable UTF-8 to display mapping
|
||||||
dispdev->setFontTableLookupFunction(customFontTableLookup);
|
dispdev->setFontTableLookupFunction(customFontTableLookup);
|
||||||
|
|
||||||
#ifdef USERPREFS_OEM_TEXT
|
#ifdef USERPREFS_OEM_TEXT
|
||||||
logo_timeout *= 2; // Give more time for branded boot logos
|
logo_timeout *= 2; // Give more time for branded boot logos
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// === Configure alert frames (e.g., "Resuming..." or region name) ===
|
// Configure alert frames (e.g., "Resuming..." or region name)
|
||||||
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Skip slow refresh
|
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Skip slow refresh
|
||||||
alertFrames[0] = [this](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) {
|
alertFrames[0] = [this](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) {
|
||||||
#ifdef ARCH_ESP32
|
#ifdef ARCH_ESP32
|
||||||
@ -593,10 +587,10 @@ void Screen::setup()
|
|||||||
ui->setFrames(alertFrames, 1);
|
ui->setFrames(alertFrames, 1);
|
||||||
ui->disableAutoTransition(); // Require manual navigation between frames
|
ui->disableAutoTransition(); // Require manual navigation between frames
|
||||||
|
|
||||||
// === Log buffer for on-screen logs (3 lines max) ===
|
// Log buffer for on-screen logs (3 lines max)
|
||||||
dispdev->setLogBuffer(3, 32);
|
dispdev->setLogBuffer(3, 32);
|
||||||
|
|
||||||
// === Optional screen mirroring or flipping (e.g. for T-Beam orientation) ===
|
// Optional screen mirroring or flipping (e.g. for T-Beam orientation)
|
||||||
#ifdef SCREEN_MIRROR
|
#ifdef SCREEN_MIRROR
|
||||||
dispdev->mirrorScreen();
|
dispdev->mirrorScreen();
|
||||||
#else
|
#else
|
||||||
@ -612,7 +606,7 @@ void Screen::setup()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// === Generate device ID from MAC address ===
|
// Generate device ID from MAC address
|
||||||
uint8_t dmac[6];
|
uint8_t dmac[6];
|
||||||
getMacAddr(dmac);
|
getMacAddr(dmac);
|
||||||
snprintf(screen->ourId, sizeof(screen->ourId), "%02x%02x", dmac[4], dmac[5]);
|
snprintf(screen->ourId, sizeof(screen->ourId), "%02x%02x", dmac[4], dmac[5]);
|
||||||
@ -621,7 +615,7 @@ void Screen::setup()
|
|||||||
handleSetOn(false); // Ensure proper init for Arduino targets
|
handleSetOn(false); // Ensure proper init for Arduino targets
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// === Turn on display and trigger first draw ===
|
// Turn on display and trigger first draw
|
||||||
handleSetOn(true);
|
handleSetOn(true);
|
||||||
determineResolution(dispdev->height(), dispdev->width());
|
determineResolution(dispdev->height(), dispdev->width());
|
||||||
ui->update();
|
ui->update();
|
||||||
@ -644,7 +638,7 @@ void Screen::setup()
|
|||||||
touchScreenImpl1->init();
|
touchScreenImpl1->init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// === Subscribe to device status updates ===
|
// Subscribe to device status updates
|
||||||
powerStatusObserver.observe(&powerStatus->onNewStatus);
|
powerStatusObserver.observe(&powerStatus->onNewStatus);
|
||||||
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
|
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
|
||||||
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
|
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
|
||||||
@ -652,16 +646,14 @@ void Screen::setup()
|
|||||||
#if !MESHTASTIC_EXCLUDE_ADMIN
|
#if !MESHTASTIC_EXCLUDE_ADMIN
|
||||||
adminMessageObserver.observe(adminModule);
|
adminMessageObserver.observe(adminModule);
|
||||||
#endif
|
#endif
|
||||||
if (textMessageModule)
|
|
||||||
textMessageObserver.observe(textMessageModule);
|
|
||||||
if (inputBroker)
|
if (inputBroker)
|
||||||
inputObserver.observe(inputBroker);
|
inputObserver.observe(inputBroker);
|
||||||
|
|
||||||
// === Load persisted messages into RAM ===
|
// Load persisted messages into RAM
|
||||||
messageStore.loadFromFlash();
|
messageStore.loadFromFlash();
|
||||||
LOG_INFO("MessageStore loaded from flash");
|
LOG_INFO("MessageStore loaded from flash");
|
||||||
|
|
||||||
// === Notify modules that support UI events ===
|
// Notify modules that support UI events
|
||||||
MeshModule::observeUIEvents(&uiFrameEventObserver);
|
MeshModule::observeUIEvents(&uiFrameEventObserver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1130,7 +1122,7 @@ void Screen::setFrames(FrameFocus focus)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fsi.frameCount = numframes; // Total framecount is used to apply FOCUS_PRESERVE
|
fsi.frameCount = numframes; // Total framecount is used to apply FOCUS_PRESERVE
|
||||||
this->frameCount = numframes; // ✅ Save frame count for use in custom overlay
|
this->frameCount = numframes; // Save frame count for use in custom overlay
|
||||||
LOG_DEBUG("Finished build frames. numframes: %d", numframes);
|
LOG_DEBUG("Finished build frames. numframes: %d", numframes);
|
||||||
|
|
||||||
ui->setFrames(normalFrames, numframes);
|
ui->setFrames(normalFrames, numframes);
|
||||||
@ -1150,10 +1142,6 @@ void Screen::setFrames(FrameFocus focus)
|
|||||||
case FOCUS_FAULT:
|
case FOCUS_FAULT:
|
||||||
ui->switchToFrame(fsi.positions.fault);
|
ui->switchToFrame(fsi.positions.fault);
|
||||||
break;
|
break;
|
||||||
case FOCUS_TEXTMESSAGE:
|
|
||||||
hasUnreadMessage = false; // ✅ Clear when message is *viewed*
|
|
||||||
ui->switchToFrame(fsi.positions.textMessage);
|
|
||||||
break;
|
|
||||||
case FOCUS_MODULE:
|
case FOCUS_MODULE:
|
||||||
// Whichever frame was marked by MeshModule::requestFocus(), if any
|
// Whichever frame was marked by MeshModule::requestFocus(), if any
|
||||||
// If no module requested focus, will show the first frame instead
|
// If no module requested focus, will show the first frame instead
|
||||||
@ -1438,120 +1426,6 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// Handles when message is received; will jump to text message frame.
|
|
||||||
int Screen::handleTextMessage(const meshtastic_MeshPacket *packet)
|
|
||||||
{
|
|
||||||
if (!showingNormalScreen)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// === Build stored message ===
|
|
||||||
StoredMessage sm;
|
|
||||||
|
|
||||||
// Always use our local time
|
|
||||||
uint32_t nowSecs = getValidTime(RTCQuality::RTCQualityDevice, true);
|
|
||||||
if (nowSecs > 0) {
|
|
||||||
sm.timestamp = nowSecs;
|
|
||||||
sm.isBootRelative = false;
|
|
||||||
} else {
|
|
||||||
sm.timestamp = millis() / 1000;
|
|
||||||
sm.isBootRelative = true; // mark for later upgrade
|
|
||||||
}
|
|
||||||
|
|
||||||
sm.channelIndex = packet->channel;
|
|
||||||
sm.text = std::string(reinterpret_cast<const char *>(packet->decoded.payload.bytes));
|
|
||||||
|
|
||||||
if (packet->from == 0) {
|
|
||||||
// Outgoing message (sent by us, typically via phone)
|
|
||||||
sm.sender = nodeDB->getNodeNum(); // us
|
|
||||||
if (packet->decoded.dest == 0 || packet->decoded.dest == NODENUM_BROADCAST) {
|
|
||||||
// Fix: treat 0 as broadcast, not DM:00000000
|
|
||||||
sm.dest = NODENUM_BROADCAST;
|
|
||||||
sm.type = MessageType::BROADCAST;
|
|
||||||
} else {
|
|
||||||
sm.dest = packet->decoded.dest;
|
|
||||||
sm.type = MessageType::DM_TO_US;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// === Incoming message ===
|
|
||||||
sm.sender = packet->from;
|
|
||||||
if (packet->to == NODENUM_BROADCAST || packet->decoded.dest == NODENUM_BROADCAST) {
|
|
||||||
sm.dest = NODENUM_BROADCAST;
|
|
||||||
sm.type = MessageType::BROADCAST;
|
|
||||||
} else {
|
|
||||||
sm.dest = nodeDB->getNodeNum(); // our node (we are DM target)
|
|
||||||
sm.type = MessageType::DM_TO_US;
|
|
||||||
}
|
|
||||||
|
|
||||||
hasUnreadMessage = true; // only incoming triggers mail icon
|
|
||||||
|
|
||||||
// Wake/force display if configured
|
|
||||||
if (shouldWakeOnReceivedMessage()) {
|
|
||||||
setOn(true);
|
|
||||||
forceDisplay();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare banner
|
|
||||||
const meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(packet->from);
|
|
||||||
const char *longName = (node && node->has_user) ? node->user.long_name : nullptr;
|
|
||||||
|
|
||||||
const char *msgRaw = reinterpret_cast<const char *>(packet->decoded.payload.bytes);
|
|
||||||
char banner[256];
|
|
||||||
|
|
||||||
bool isAlert = false;
|
|
||||||
for (size_t i = 0; i < packet->decoded.payload.size && i < 100; i++) {
|
|
||||||
if (msgRaw[i] == '\x07') { // bell
|
|
||||||
isAlert = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isAlert) {
|
|
||||||
if (longName && longName[0]) {
|
|
||||||
snprintf(banner, sizeof(banner), "Alert Received from\n%s", longName);
|
|
||||||
} else {
|
|
||||||
strcpy(banner, "Alert Received");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (longName && longName[0]) {
|
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
strcpy(banner, "New Message");
|
|
||||||
#else
|
|
||||||
snprintf(banner, sizeof(banner), "New Message from\n%s", longName);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
strcpy(banner, "New Message");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(M5STACK_UNITC6L)
|
|
||||||
screen->setOn(true);
|
|
||||||
screen->showSimpleBanner(banner, 1500);
|
|
||||||
playLongBeep();
|
|
||||||
#else
|
|
||||||
screen->showSimpleBanner(banner, 3000);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save to store (both outgoing + incoming)
|
|
||||||
messageStore.addLiveMessage(sm);
|
|
||||||
|
|
||||||
// Keep frame set active
|
|
||||||
setFrames(FOCUS_PRESERVE);
|
|
||||||
|
|
||||||
// Auto-switch thread view
|
|
||||||
if (sm.type == MessageType::BROADCAST) {
|
|
||||||
graphics::MessageRenderer::setThreadMode(graphics::MessageRenderer::ThreadMode::CHANNEL, sm.channelIndex);
|
|
||||||
} else if (sm.type == MessageType::DM_TO_US) {
|
|
||||||
uint32_t peer = (packet->from == 0) ? sm.dest : sm.sender;
|
|
||||||
graphics::MessageRenderer::setThreadMode(graphics::MessageRenderer::ThreadMode::DIRECT, -1, peer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset scroll so newest message starts from the top
|
|
||||||
graphics::MessageRenderer::resetScrollState();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Triggered by MeshModules
|
// Triggered by MeshModules
|
||||||
int Screen::handleUIFrameEvent(const UIFrameEvent *event)
|
int Screen::handleUIFrameEvent(const UIFrameEvent *event)
|
||||||
|
|||||||
@ -40,7 +40,6 @@ class Screen
|
|||||||
FOCUS_DEFAULT, // No specific frame
|
FOCUS_DEFAULT, // No specific frame
|
||||||
FOCUS_PRESERVE, // Return to the previous frame
|
FOCUS_PRESERVE, // Return to the previous frame
|
||||||
FOCUS_FAULT,
|
FOCUS_FAULT,
|
||||||
FOCUS_TEXTMESSAGE,
|
|
||||||
FOCUS_MODULE, // Note: target module should call requestFocus(), otherwise no info about which module to focus
|
FOCUS_MODULE, // Note: target module should call requestFocus(), otherwise no info about which module to focus
|
||||||
FOCUS_CLOCK,
|
FOCUS_CLOCK,
|
||||||
FOCUS_SYSTEM,
|
FOCUS_SYSTEM,
|
||||||
@ -209,8 +208,6 @@ class Screen : public concurrency::OSThread
|
|||||||
CallbackObserver<Screen, const meshtastic::Status *>(this, &Screen::handleStatusUpdate);
|
CallbackObserver<Screen, const meshtastic::Status *>(this, &Screen::handleStatusUpdate);
|
||||||
CallbackObserver<Screen, const meshtastic::Status *> nodeStatusObserver =
|
CallbackObserver<Screen, const meshtastic::Status *> nodeStatusObserver =
|
||||||
CallbackObserver<Screen, const meshtastic::Status *>(this, &Screen::handleStatusUpdate);
|
CallbackObserver<Screen, const meshtastic::Status *>(this, &Screen::handleStatusUpdate);
|
||||||
CallbackObserver<Screen, const meshtastic_MeshPacket *> textMessageObserver =
|
|
||||||
CallbackObserver<Screen, const meshtastic_MeshPacket *>(this, &Screen::handleTextMessage);
|
|
||||||
CallbackObserver<Screen, const UIFrameEvent *> uiFrameEventObserver =
|
CallbackObserver<Screen, const UIFrameEvent *> uiFrameEventObserver =
|
||||||
CallbackObserver<Screen, const UIFrameEvent *>(this, &Screen::handleUIFrameEvent); // Sent by Mesh Modules
|
CallbackObserver<Screen, const UIFrameEvent *>(this, &Screen::handleUIFrameEvent); // Sent by Mesh Modules
|
||||||
CallbackObserver<Screen, const InputEvent *> inputObserver =
|
CallbackObserver<Screen, const InputEvent *> inputObserver =
|
||||||
@ -229,7 +226,6 @@ class Screen : public concurrency::OSThread
|
|||||||
FOCUS_DEFAULT, // No specific frame
|
FOCUS_DEFAULT, // No specific frame
|
||||||
FOCUS_PRESERVE, // Return to the previous frame
|
FOCUS_PRESERVE, // Return to the previous frame
|
||||||
FOCUS_FAULT,
|
FOCUS_FAULT,
|
||||||
FOCUS_TEXTMESSAGE,
|
|
||||||
FOCUS_MODULE, // Note: target module should call requestFocus(), otherwise no info about which module to focus
|
FOCUS_MODULE, // Note: target module should call requestFocus(), otherwise no info about which module to focus
|
||||||
FOCUS_CLOCK,
|
FOCUS_CLOCK,
|
||||||
FOCUS_SYSTEM,
|
FOCUS_SYSTEM,
|
||||||
@ -575,7 +571,6 @@ class Screen : public concurrency::OSThread
|
|||||||
|
|
||||||
// Handle observer events
|
// Handle observer events
|
||||||
int handleStatusUpdate(const meshtastic::Status *arg);
|
int handleStatusUpdate(const meshtastic::Status *arg);
|
||||||
int handleTextMessage(const meshtastic_MeshPacket *arg);
|
|
||||||
int handleUIFrameEvent(const UIFrameEvent *arg);
|
int handleUIFrameEvent(const UIFrameEvent *arg);
|
||||||
int handleInputEvent(const InputEvent *arg);
|
int handleInputEvent(const InputEvent *arg);
|
||||||
int handleAdminMessage(AdminModule_ObserverData *arg);
|
int handleAdminMessage(AdminModule_ObserverData *arg);
|
||||||
|
|||||||
@ -1,26 +1,3 @@
|
|||||||
/*
|
|
||||||
BaseUI
|
|
||||||
|
|
||||||
Developed and Maintained By:
|
|
||||||
- Ronald Garcia (HarukiToreda) – Lead development and implementation.
|
|
||||||
- JasonP (Xaositek) – Screen layout and icon design, UI improvements and testing.
|
|
||||||
- TonyG (Tropho) – Project management, structural planning, and testing
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#if HAS_SCREEN
|
#if HAS_SCREEN
|
||||||
#include "MessageRenderer.h"
|
#include "MessageRenderer.h"
|
||||||
@ -28,25 +5,23 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
// Core includes
|
// Core includes
|
||||||
#include "MessageStore.h"
|
#include "MessageStore.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
|
#include "UIRenderer.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "gps/RTC.h"
|
#include "gps/RTC.h"
|
||||||
|
#include "graphics/Screen.h"
|
||||||
#include "graphics/ScreenFonts.h"
|
#include "graphics/ScreenFonts.h"
|
||||||
#include "graphics/SharedUIDisplay.h"
|
#include "graphics/SharedUIDisplay.h"
|
||||||
|
#include "graphics/TimeFormatters.h"
|
||||||
#include "graphics/emotes.h"
|
#include "graphics/emotes.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "meshUtils.h"
|
#include "meshUtils.h"
|
||||||
|
|
||||||
// Additional includes for UI rendering
|
|
||||||
#include "UIRenderer.h"
|
|
||||||
#include "graphics/TimeFormatters.h"
|
|
||||||
|
|
||||||
// Additional includes for dependencies
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
// External declarations
|
// External declarations
|
||||||
extern bool hasUnreadMessage;
|
extern bool hasUnreadMessage;
|
||||||
extern meshtastic_DeviceState devicestate;
|
extern meshtastic_DeviceState devicestate;
|
||||||
|
extern graphics::Screen *screen;
|
||||||
|
|
||||||
using graphics::Emote;
|
using graphics::Emote;
|
||||||
using graphics::emotes;
|
using graphics::emotes;
|
||||||
@ -65,7 +40,7 @@ void drawStringWithEmotes(OLEDDisplay *display, int x, int y, const std::string
|
|||||||
int cursorX = x;
|
int cursorX = x;
|
||||||
const int fontHeight = FONT_HEIGHT_SMALL;
|
const int fontHeight = FONT_HEIGHT_SMALL;
|
||||||
|
|
||||||
// === Step 1: Find tallest emote in the line ===
|
// Step 1: Find tallest emote in the line
|
||||||
int maxIconHeight = fontHeight;
|
int maxIconHeight = fontHeight;
|
||||||
for (size_t i = 0; i < line.length();) {
|
for (size_t i = 0; i < line.length();) {
|
||||||
bool matched = false;
|
bool matched = false;
|
||||||
@ -248,7 +223,7 @@ uint32_t getThreadPeer()
|
|||||||
return currentPeer;
|
return currentPeer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Accessors for menuHandler ===
|
// Accessors for menuHandler
|
||||||
const std::vector<int> &getSeenChannels()
|
const std::vector<int> &getSeenChannels()
|
||||||
{
|
{
|
||||||
return seenChannels;
|
return seenChannels;
|
||||||
@ -656,6 +631,73 @@ void renderMessageContent(OLEDDisplay *display, const std::vector<std::string> &
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void handleNewMessage(const StoredMessage &sm, const meshtastic_MeshPacket &packet)
|
||||||
|
{
|
||||||
|
if (packet.from != 0) {
|
||||||
|
hasUnreadMessage = true;
|
||||||
|
|
||||||
|
if (shouldWakeOnReceivedMessage()) {
|
||||||
|
screen->setOn(true);
|
||||||
|
// screen->forceDisplay(); <-- remove, let Screen handle this
|
||||||
|
}
|
||||||
|
|
||||||
|
// Banner logic
|
||||||
|
const meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(packet.from);
|
||||||
|
const char *longName = (node && node->has_user) ? node->user.long_name : nullptr;
|
||||||
|
const char *msgRaw = reinterpret_cast<const char *>(packet.decoded.payload.bytes);
|
||||||
|
|
||||||
|
char banner[256];
|
||||||
|
bool isAlert = false;
|
||||||
|
for (size_t i = 0; i < packet.decoded.payload.size && i < 100; i++) {
|
||||||
|
if (msgRaw[i] == '\x07') {
|
||||||
|
isAlert = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAlert) {
|
||||||
|
if (longName && longName[0])
|
||||||
|
snprintf(banner, sizeof(banner), "Alert Received from\n%s", longName);
|
||||||
|
else
|
||||||
|
strcpy(banner, "Alert Received");
|
||||||
|
} else {
|
||||||
|
if (longName && longName[0]) {
|
||||||
|
#if defined(M5STACK_UNITC6L)
|
||||||
|
strcpy(banner, "New Message");
|
||||||
|
#else
|
||||||
|
snprintf(banner, sizeof(banner), "New Message from\n%s", longName);
|
||||||
|
#endif
|
||||||
|
} else
|
||||||
|
strcpy(banner, "New Message");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shorter banner if already in a conversation (Channel or Direct)
|
||||||
|
bool inThread = (getThreadMode() != ThreadMode::ALL);
|
||||||
|
|
||||||
|
#if defined(M5STACK_UNITC6L)
|
||||||
|
screen->setOn(true);
|
||||||
|
screen->showSimpleBanner(banner, inThread ? 1000 : 1500);
|
||||||
|
playLongBeep();
|
||||||
|
#else
|
||||||
|
screen->showSimpleBanner(banner, inThread ? 1000 : 3000);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// No setFrames() here anymore
|
||||||
|
setThreadFor(sm, packet);
|
||||||
|
resetScrollState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setThreadFor(const StoredMessage &sm, const meshtastic_MeshPacket &packet)
|
||||||
|
{
|
||||||
|
if (sm.type == MessageType::BROADCAST) {
|
||||||
|
setThreadMode(ThreadMode::CHANNEL, sm.channelIndex);
|
||||||
|
} else if (sm.type == MessageType::DM_TO_US) {
|
||||||
|
uint32_t peer = (packet.from == 0) ? sm.dest : sm.sender;
|
||||||
|
setThreadMode(ThreadMode::DIRECT, -1, peer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace MessageRenderer
|
} // namespace MessageRenderer
|
||||||
} // namespace graphics
|
} // namespace graphics
|
||||||
#endif
|
#endif
|
||||||
@ -1,7 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "MessageStore.h" // for StoredMessage
|
||||||
#include "OLEDDisplay.h"
|
#include "OLEDDisplay.h"
|
||||||
#include "OLEDDisplayUi.h"
|
#include "OLEDDisplayUi.h"
|
||||||
#include "graphics/emotes.h"
|
#include "graphics/emotes.h"
|
||||||
|
#include "mesh/generated/meshtastic/mesh.pb.h" // for meshtastic_MeshPacket
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -10,7 +12,7 @@ namespace graphics
|
|||||||
namespace MessageRenderer
|
namespace MessageRenderer
|
||||||
{
|
{
|
||||||
|
|
||||||
// === Thread filter modes ===
|
// Thread filter modes
|
||||||
enum class ThreadMode { ALL, CHANNEL, DIRECT };
|
enum class ThreadMode { ALL, CHANNEL, DIRECT };
|
||||||
|
|
||||||
// Setter for switching thread mode
|
// Setter for switching thread mode
|
||||||
@ -50,5 +52,11 @@ void renderMessageContent(OLEDDisplay *display, const std::vector<std::string> &
|
|||||||
// Reset scroll state when new messages arrive
|
// Reset scroll state when new messages arrive
|
||||||
void resetScrollState();
|
void resetScrollState();
|
||||||
|
|
||||||
|
// Helper to auto-select the correct thread mode from a message
|
||||||
|
void setThreadFor(const StoredMessage &sm, const meshtastic_MeshPacket &packet);
|
||||||
|
|
||||||
|
// Handles a new incoming/outgoing message: banner, wake, thread select, scroll reset
|
||||||
|
void handleNewMessage(const StoredMessage &sm, const meshtastic_MeshPacket &packet);
|
||||||
|
|
||||||
} // namespace MessageRenderer
|
} // namespace MessageRenderer
|
||||||
} // namespace graphics
|
} // namespace graphics
|
||||||
@ -1,10 +1,13 @@
|
|||||||
#include "TextMessageModule.h"
|
#include "TextMessageModule.h"
|
||||||
#include "MeshService.h"
|
#include "MeshService.h"
|
||||||
|
#include "MessageStore.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
#include "buzz.h"
|
#include "buzz.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "graphics/Screen.h"
|
#include "graphics/Screen.h"
|
||||||
|
#include "graphics/draw/MessageRenderer.h"
|
||||||
|
|
||||||
TextMessageModule *textMessageModule;
|
TextMessageModule *textMessageModule;
|
||||||
|
|
||||||
ProcessMessage TextMessageModule::handleReceived(const meshtastic_MeshPacket &mp)
|
ProcessMessage TextMessageModule::handleReceived(const meshtastic_MeshPacket &mp)
|
||||||
@ -13,15 +16,23 @@ ProcessMessage TextMessageModule::handleReceived(const meshtastic_MeshPacket &mp
|
|||||||
auto &p = mp.decoded;
|
auto &p = mp.decoded;
|
||||||
LOG_INFO("Received text msg from=0x%0x, id=0x%x, msg=%.*s", mp.from, mp.id, p.payload.size, p.payload.bytes);
|
LOG_INFO("Received text msg from=0x%0x, id=0x%x, msg=%.*s", mp.from, mp.id, p.payload.size, p.payload.bytes);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// We only store/display messages destined for us.
|
// We only store/display messages destined for us.
|
||||||
// Keep a copy of the most recent text message.
|
|
||||||
devicestate.rx_text_message = mp;
|
devicestate.rx_text_message = mp;
|
||||||
devicestate.has_rx_text_message = true;
|
devicestate.has_rx_text_message = true;
|
||||||
|
|
||||||
|
// Store in the central message history
|
||||||
|
const StoredMessage &sm = messageStore.addFromPacket(mp);
|
||||||
|
|
||||||
|
// Pass message to renderer (banner + thread switching + scroll reset)
|
||||||
|
graphics::MessageRenderer::handleNewMessage(sm, mp);
|
||||||
|
|
||||||
// Only trigger screen wake if configuration allows it
|
// Only trigger screen wake if configuration allows it
|
||||||
if (shouldWakeOnReceivedMessage()) {
|
if (shouldWakeOnReceivedMessage()) {
|
||||||
powerFSM.trigger(EVENT_RECEIVED_MSG);
|
powerFSM.trigger(EVENT_RECEIVED_MSG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Notify any observers (e.g. external modules that care about packets)
|
||||||
notifyObservers(&mp);
|
notifyObservers(&mp);
|
||||||
|
|
||||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user