More optimization

This commit is contained in:
HarukiToreda
2025-10-15 01:57:51 -04:00
parent 67c24c08cc
commit 62eaabc940
6 changed files with 166 additions and 59 deletions

View File

@@ -9,6 +9,48 @@
#include "graphics/draw/MessageRenderer.h"
#include <cstring> // memcpy
#ifndef MESSAGE_TEXT_POOL_SIZE
#define MESSAGE_TEXT_POOL_SIZE (MAX_MESSAGES_SAVED * MAX_MESSAGE_SIZE)
#endif
// Global message text pool and state
static char g_messagePool[MESSAGE_TEXT_POOL_SIZE];
static size_t g_poolWritePos = 0;
// Reset pool (called on boot or clear)
static inline void resetMessagePool()
{
g_poolWritePos = 0;
memset(g_messagePool, 0, sizeof(g_messagePool));
}
// Allocate text in pool and return offset
// If not enough space remains, wrap around (ring buffer style)
static inline uint16_t storeTextInPool(const char *src, size_t len)
{
if (len >= MAX_MESSAGE_SIZE)
len = MAX_MESSAGE_SIZE - 1;
// Wrap pool if out of space
if (g_poolWritePos + len + 1 >= MESSAGE_TEXT_POOL_SIZE) {
g_poolWritePos = 0;
}
uint16_t offset = g_poolWritePos;
memcpy(&g_messagePool[g_poolWritePos], src, len);
g_messagePool[g_poolWritePos + len] = '\0';
g_poolWritePos += (len + 1);
return offset;
}
// Retrieve a const pointer to message text by offset
static inline const char *getTextFromPool(uint16_t offset)
{
if (offset >= MESSAGE_TEXT_POOL_SIZE)
return "";
return &g_messagePool[offset];
}
// Helper: assign a timestamp (RTC if available, else boot-relative)
static inline void assignTimestamp(StoredMessage &sm)
{
@@ -40,6 +82,7 @@ template <typename T> static inline void pushWithLimit(std::deque<T> &queue, T &
MessageStore::MessageStore(const std::string &label)
{
filename = "/Messages_" + label + ".msgs";
resetMessagePool(); // initialize text pool on boot
}
// Live message handling (RAM only)
@@ -56,24 +99,42 @@ void MessageStore::addLiveMessage(const StoredMessage &msg)
const StoredMessage &MessageStore::addFromPacket(const meshtastic_MeshPacket &packet)
{
StoredMessage sm;
assignTimestamp(sm); // set timestamp (RTC or boot-relative)
assignTimestamp(sm);
sm.channelIndex = packet.channel;
strncpy(sm.text, reinterpret_cast<const char *>(packet.decoded.payload.bytes), MAX_MESSAGE_SIZE - 1);
sm.text[MAX_MESSAGE_SIZE - 1] = '\0';
const char *payload = reinterpret_cast<const char *>(packet.decoded.payload.bytes);
size_t len = strnlen(payload, MAX_MESSAGE_SIZE - 1);
sm.textOffset = storeTextInPool(payload, len);
sm.textLength = len;
uint32_t localNode = nodeDB->getNodeNum();
sm.sender = (packet.from == 0) ? localNode : packet.from;
sm.dest = packet.decoded.dest;
// DM detection: use decoded.dest if valid, otherwise fallback to header 'to'
bool isDM = false;
uint32_t actualDest = sm.dest;
if (actualDest == 0 || actualDest == 0xffffffff) {
actualDest = packet.to;
}
if (actualDest != 0 && actualDest != NODENUM_BROADCAST && actualDest == localNode) {
isDM = true;
}
// Incoming vs outgoing classification
if (packet.from == 0) {
// Outgoing (phone-originated)
sm.sender = nodeDB->getNodeNum();
sm.dest = (packet.decoded.dest == 0) ? NODENUM_BROADCAST : packet.decoded.dest;
sm.type = (sm.dest == NODENUM_BROADCAST) ? MessageType::BROADCAST : MessageType::DM_TO_US;
// Sent by us
sm.type = isDM ? MessageType::DM_TO_US : MessageType::BROADCAST;
sm.ackStatus = AckStatus::NONE;
} else {
// Incoming
sm.sender = packet.from;
sm.dest = packet.decoded.dest;
sm.type = (sm.dest == NODENUM_BROADCAST) ? MessageType::BROADCAST
: (sm.dest == nodeDB->getNodeNum()) ? MessageType::DM_TO_US
: MessageType::BROADCAST;
// Received from another node
if (isDM) {
sm.type = MessageType::DM_TO_US;
} else {
sm.type = MessageType::BROADCAST;
}
sm.ackStatus = AckStatus::ACKED;
}
@@ -91,8 +152,8 @@ void MessageStore::addFromString(uint32_t sender, uint8_t channelIndex, const st
sm.sender = sender;
sm.channelIndex = channelIndex;
strncpy(sm.text, text.c_str(), MAX_MESSAGE_SIZE - 1);
sm.text[MAX_MESSAGE_SIZE - 1] = '\0';
sm.textOffset = storeTextInPool(text.c_str(), text.size());
sm.textLength = text.size();
// Default manual adds to broadcast
sm.dest = NODENUM_BROADCAST;
@@ -106,18 +167,17 @@ void MessageStore::addFromString(uint32_t sender, uint8_t channelIndex, const st
#if ENABLE_MESSAGE_PERSISTENCE
// Use a compile-time constant so the array bound can be used in the struct
static constexpr size_t TEXT_LEN = MAX_MESSAGE_SIZE;
// Compact, fixed-size on-flash representation
// Compact, fixed-size on-flash representation using offset + length
struct __attribute__((packed)) StoredMessageRecord {
uint32_t timestamp;
uint32_t sender;
uint8_t channelIndex;
uint32_t dest;
uint8_t isBootRelative;
uint8_t ackStatus; // static_cast<uint8_t>(AckStatus)
char text[TEXT_LEN]; // null-terminated
uint8_t ackStatus; // static_cast<uint8_t>(AckStatus)
uint8_t type; // static_cast<uint8_t>(MessageType)
uint16_t textLength; // message length
char text[MAX_MESSAGE_SIZE]; // <-- store actual text here
};
// Serialize one StoredMessage to flash
@@ -130,9 +190,14 @@ static inline void writeMessageRecord(SafeFile &f, const StoredMessage &m)
rec.dest = m.dest;
rec.isBootRelative = m.isBootRelative;
rec.ackStatus = static_cast<uint8_t>(m.ackStatus);
rec.type = static_cast<uint8_t>(m.type);
rec.textLength = m.textLength;
// Copy the actual text into the record from RAM pool
const char *txt = getTextFromPool(m.textOffset);
strncpy(rec.text, txt, MAX_MESSAGE_SIZE - 1);
rec.text[MAX_MESSAGE_SIZE - 1] = '\0';
strncpy(rec.text, m.text, TEXT_LEN - 1);
rec.text[TEXT_LEN - 1] = '\0';
f.write(reinterpret_cast<const uint8_t *>(&rec), sizeof(rec));
}
@@ -149,9 +214,13 @@ static inline bool readMessageRecord(File &f, StoredMessage &m)
m.dest = rec.dest;
m.isBootRelative = rec.isBootRelative;
m.ackStatus = static_cast<AckStatus>(rec.ackStatus);
strncpy(m.text, rec.text, MAX_MESSAGE_SIZE - 1);
m.text[MAX_MESSAGE_SIZE - 1] = '\0';
m.type = (m.dest == NODENUM_BROADCAST) ? MessageType::BROADCAST : MessageType::DM_TO_US;
m.type = static_cast<MessageType>(rec.type);
m.textLength = rec.textLength;
// 💡 Re-store text into pool and update offset
m.textLength = strnlen(rec.text, MAX_MESSAGE_SIZE - 1);
m.textOffset = storeTextInPool(rec.text, m.textLength);
return true;
}
@@ -183,6 +252,8 @@ void MessageStore::saveToFlash()
void MessageStore::loadFromFlash()
{
liveMessages.clear();
resetMessagePool(); // reset pool when loading
#ifdef FSCom
concurrency::LockGuard guard(spiLock);
@@ -219,6 +290,7 @@ void MessageStore::loadFromFlash() {}
void MessageStore::clearAllMessages()
{
liveMessages.clear();
resetMessagePool();
#ifdef FSCom
SafeFile f(filename.c_str(), false);
@@ -266,7 +338,7 @@ void MessageStore::dismissOldestMessageInChannel(uint8_t channel)
saveToFlash();
}
// Dismiss oldest message in a direct conversation with a peer
// Dismiss oldest message in a direct chat with a node
void MessageStore::dismissOldestMessageWithPeer(uint32_t peer)
{
auto pred = [peer](const StoredMessage &m) {
@@ -279,7 +351,6 @@ void MessageStore::dismissOldestMessageWithPeer(uint32_t peer)
saveToFlash();
}
// Helper filters for future use
std::deque<StoredMessage> MessageStore::getChannelMessages(uint8_t channel) const
{
std::deque<StoredMessage> result;
@@ -320,12 +391,23 @@ void MessageStore::upgradeBootRelativeTimestamps()
m.timestamp += bootOffset;
m.isBootRelative = false;
}
// else: persisted from old boot → stays ??? forever
}
};
fix(liveMessages);
}
const char *MessageStore::getText(const StoredMessage &msg)
{
// Wrapper around the internal helper
return getTextFromPool(msg.textOffset);
}
uint16_t MessageStore::storeText(const char *src, size_t len)
{
// Wrapper around the internal helper
return storeTextInPool(src, len);
}
// Global definition
MessageStore messageStore("default");
#endif