mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-20 09:43:03 +00:00
Merge branch 'master' into arduino-esp32-v3.2
This commit is contained in:
5
.github/actions/setup-base/action.yml
vendored
5
.github/actions/setup-base/action.yml
vendored
@@ -11,11 +11,6 @@ runs:
|
|||||||
ref: ${{github.event.pull_request.head.ref}}
|
ref: ${{github.event.pull_request.head.ref}}
|
||||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||||
|
|
||||||
- name: Uncomment build epoch
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
sed -i 's/#-DBUILD_EPOCH=$UNIX_TIME/-DBUILD_EPOCH=$UNIX_TIME/' platformio.ini
|
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
sed -i 's/#-DBUILD_EPOCH=$UNIX_TIME/-DBUILD_EPOCH=$UNIX_TIME/' platformio.ini
|
|
||||||
|
|
||||||
export PIP_BREAK_SYSTEM_PACKAGES=1
|
export PIP_BREAK_SYSTEM_PACKAGES=1
|
||||||
|
|
||||||
if (echo $2 | grep -q "esp32"); then
|
if (echo $2 | grep -q "esp32"); then
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ from os.path import join
|
|||||||
import subprocess
|
import subprocess
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
|
import time
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from readprops import readProps
|
from readprops import readProps
|
||||||
|
|
||||||
@@ -125,11 +127,16 @@ for pref in userPrefs:
|
|||||||
pref_flags.append("-D" + pref + "=" + env.StringifyMacro(userPrefs[pref]) + "")
|
pref_flags.append("-D" + pref + "=" + env.StringifyMacro(userPrefs[pref]) + "")
|
||||||
|
|
||||||
# General options that are passed to the C and C++ compilers
|
# General options that are passed to the C and C++ compilers
|
||||||
|
# Calculate unix epoch for current day (midnight)
|
||||||
|
current_date = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
|
build_epoch = int(current_date.timestamp())
|
||||||
|
|
||||||
flags = [
|
flags = [
|
||||||
"-DAPP_VERSION=" + verObj["long"],
|
"-DAPP_VERSION=" + verObj["long"],
|
||||||
"-DAPP_VERSION_SHORT=" + verObj["short"],
|
"-DAPP_VERSION_SHORT=" + verObj["short"],
|
||||||
"-DAPP_ENV=" + env.get("PIOENV"),
|
"-DAPP_ENV=" + env.get("PIOENV"),
|
||||||
"-DAPP_REPO=" + repo_owner,
|
"-DAPP_REPO=" + repo_owner,
|
||||||
|
"-DBUILD_EPOCH=" + str(build_epoch),
|
||||||
] + pref_flags
|
] + pref_flags
|
||||||
|
|
||||||
print ("Using flags:")
|
print ("Using flags:")
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ build_flags = -Wno-missing-field-initializers
|
|||||||
-DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware
|
-DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware
|
||||||
-DMESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE=1
|
-DMESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE=1
|
||||||
-D MAX_THREADS=40 ; As we've split modules, we have more threads to manage
|
-D MAX_THREADS=40 ; As we've split modules, we have more threads to manage
|
||||||
#-DBUILD_EPOCH=$UNIX_TIME
|
#-DBUILD_EPOCH=$UNIX_TIME ; set in platformio-custom.py now
|
||||||
#-D OLED_PL=1
|
#-D OLED_PL=1
|
||||||
|
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
@@ -117,7 +117,7 @@ lib_deps =
|
|||||||
[device-ui_base]
|
[device-ui_base]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
|
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
|
||||||
https://github.com/meshtastic/device-ui/archive/233d18ef42e9d189f90fdfe621f0cd7edff2d221.zip
|
https://github.com/meshtastic/device-ui/archive/3677476c8a823ee85056b5fb1d146a3e193f8276.zip
|
||||||
|
|
||||||
; Common libs for environmental measurements in telemetry module
|
; Common libs for environmental measurements in telemetry module
|
||||||
[environmental_base]
|
[environmental_base]
|
||||||
|
|||||||
@@ -2,6 +2,12 @@
|
|||||||
|
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
#if defined(DEBUG_HEAP)
|
||||||
|
class MemGet;
|
||||||
|
extern MemGet memGet;
|
||||||
|
#endif
|
||||||
|
|
||||||
// DEBUG LED
|
// DEBUG LED
|
||||||
#ifndef LED_STATE_ON
|
#ifndef LED_STATE_ON
|
||||||
#define LED_STATE_ON 1
|
#define LED_STATE_ON 1
|
||||||
@@ -23,6 +29,7 @@
|
|||||||
#define MESHTASTIC_LOG_LEVEL_ERROR "ERROR"
|
#define MESHTASTIC_LOG_LEVEL_ERROR "ERROR"
|
||||||
#define MESHTASTIC_LOG_LEVEL_CRIT "CRIT "
|
#define MESHTASTIC_LOG_LEVEL_CRIT "CRIT "
|
||||||
#define MESHTASTIC_LOG_LEVEL_TRACE "TRACE"
|
#define MESHTASTIC_LOG_LEVEL_TRACE "TRACE"
|
||||||
|
#define MESHTASTIC_LOG_LEVEL_HEAP "HEAP"
|
||||||
|
|
||||||
#include "SerialConsole.h"
|
#include "SerialConsole.h"
|
||||||
|
|
||||||
@@ -62,6 +69,25 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(DEBUG_HEAP)
|
||||||
|
#define LOG_HEAP(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_HEAP, __VA_ARGS__)
|
||||||
|
|
||||||
|
// Macro-based heap debugging
|
||||||
|
#define DEBUG_HEAP_BEFORE auto heapBefore = memGet.getFreeHeap();
|
||||||
|
#define DEBUG_HEAP_AFTER(context, ptr) \
|
||||||
|
do { \
|
||||||
|
auto heapAfter = memGet.getFreeHeap(); \
|
||||||
|
if (heapBefore != heapAfter) { \
|
||||||
|
LOG_HEAP("Alloc in %s pointer 0x%x, size: %u, free: %u", context, ptr, heapBefore - heapAfter, heapAfter); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define LOG_HEAP(...)
|
||||||
|
#define DEBUG_HEAP_BEFORE
|
||||||
|
#define DEBUG_HEAP_AFTER(context, ptr)
|
||||||
|
#endif
|
||||||
|
|
||||||
/// A C wrapper for LOG_DEBUG that can be used from arduino C libs that don't know about C++ or meshtastic
|
/// A C wrapper for LOG_DEBUG that can be used from arduino C libs that don't know about C++ or meshtastic
|
||||||
extern "C" void logLegacy(const char *level, const char *fmt, ...);
|
extern "C" void logLegacy(const char *level, const char *fmt, ...);
|
||||||
|
|
||||||
|
|||||||
@@ -851,9 +851,9 @@ void Power::readPowerStatus()
|
|||||||
running++;
|
running++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG_DEBUG(threadlist);
|
LOG_HEAP(threadlist);
|
||||||
LOG_DEBUG("Heap status: %d/%d bytes free (%d), running %d/%d threads", memGet.getFreeHeap(), memGet.getHeapSize(),
|
LOG_HEAP("Heap status: %d/%d bytes free (%d), running %d/%d threads", memGet.getFreeHeap(), memGet.getHeapSize(),
|
||||||
memGet.getFreeHeap() - lastheap, running, concurrency::mainController.size(false));
|
memGet.getFreeHeap() - lastheap, running, concurrency::mainController.size(false));
|
||||||
lastheap = memGet.getFreeHeap();
|
lastheap = memGet.getFreeHeap();
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_HEAP_MQTT
|
#ifdef DEBUG_HEAP_MQTT
|
||||||
|
|||||||
@@ -86,9 +86,9 @@ void OSThread::run()
|
|||||||
#ifdef DEBUG_HEAP
|
#ifdef DEBUG_HEAP
|
||||||
auto newHeap = memGet.getFreeHeap();
|
auto newHeap = memGet.getFreeHeap();
|
||||||
if (newHeap < heap)
|
if (newHeap < heap)
|
||||||
LOG_DEBUG("------ Thread %s leaked heap %d -> %d (%d) ------", ThreadName.c_str(), heap, newHeap, newHeap - heap);
|
LOG_HEAP("------ Thread %s leaked heap %d -> %d (%d) ------", ThreadName.c_str(), heap, newHeap, newHeap - heap);
|
||||||
if (heap < newHeap)
|
if (heap < newHeap)
|
||||||
LOG_DEBUG("++++++ Thread %s freed heap %d -> %d (%d) ++++++", ThreadName.c_str(), heap, newHeap, newHeap - heap);
|
LOG_HEAP("++++++ Thread %s freed heap %d -> %d (%d) ++++++", ThreadName.c_str(), heap, newHeap, newHeap - heap);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
runned();
|
runned();
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#include <cstring> // Include for strstr
|
#include <cstring> // Include for strstr
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
@@ -1370,34 +1369,42 @@ GnssModel_t GPS::probe(int serialSpeed)
|
|||||||
|
|
||||||
GnssModel_t GPS::getProbeResponse(unsigned long timeout, const std::vector<ChipInfo> &responseMap)
|
GnssModel_t GPS::getProbeResponse(unsigned long timeout, const std::vector<ChipInfo> &responseMap)
|
||||||
{
|
{
|
||||||
String response = "";
|
char response[256] = {0}; // Fixed buffer instead of String
|
||||||
|
uint16_t responseLen = 0;
|
||||||
unsigned long start = millis();
|
unsigned long start = millis();
|
||||||
while (millis() - start < timeout) {
|
while (millis() - start < timeout) {
|
||||||
if (_serial_gps->available()) {
|
if (_serial_gps->available()) {
|
||||||
response += (char)_serial_gps->read();
|
char c = _serial_gps->read();
|
||||||
|
|
||||||
if (response.endsWith(",") || response.endsWith("\r\n")) {
|
// Add char to buffer if there's space
|
||||||
|
if (responseLen < sizeof(response) - 1) {
|
||||||
|
response[responseLen++] = c;
|
||||||
|
response[responseLen] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == ',' || (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n')) {
|
||||||
#ifdef GPS_DEBUG
|
#ifdef GPS_DEBUG
|
||||||
LOG_DEBUG(response.c_str());
|
LOG_DEBUG(response);
|
||||||
#endif
|
#endif
|
||||||
// check if we can see our chips
|
// check if we can see our chips
|
||||||
for (const auto &chipInfo : responseMap) {
|
for (const auto &chipInfo : responseMap) {
|
||||||
if (strstr(response.c_str(), chipInfo.detectionString.c_str()) != nullptr) {
|
if (strstr(response, chipInfo.detectionString.c_str()) != nullptr) {
|
||||||
LOG_INFO("%s detected", chipInfo.chipName.c_str());
|
LOG_INFO("%s detected", chipInfo.chipName.c_str());
|
||||||
return chipInfo.driver;
|
return chipInfo.driver;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (response.endsWith("\r\n")) {
|
if (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n') {
|
||||||
response.trim();
|
// Reset the response buffer for the next potential message
|
||||||
response = ""; // Reset the response string for the next potential message
|
responseLen = 0;
|
||||||
|
response[0] = '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef GPS_DEBUG
|
#ifdef GPS_DEBUG
|
||||||
LOG_DEBUG(response.c_str());
|
LOG_DEBUG(response);
|
||||||
#endif
|
#endif
|
||||||
return GNSS_MODEL_UNKNOWN; // Return empty string on timeout
|
return GNSS_MODEL_UNKNOWN; // Return unknown on timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
GPS *GPS::createGps()
|
GPS *GPS::createGps()
|
||||||
|
|||||||
@@ -88,4 +88,16 @@ uint32_t MemGet::getPsramSize()
|
|||||||
#else
|
#else
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayPercentHeapFree()
|
||||||
|
{
|
||||||
|
uint32_t freeHeap = memGet.getFreeHeap();
|
||||||
|
uint32_t totalHeap = memGet.getHeapSize();
|
||||||
|
if (totalHeap == 0 || totalHeap == UINT32_MAX) {
|
||||||
|
LOG_INFO("Heap size unavailable");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int percent = (int)((freeHeap * 100) / totalHeap);
|
||||||
|
LOG_INFO("Heap free: %d%% (%u/%u bytes)", percent, freeHeap, totalHeap);
|
||||||
}
|
}
|
||||||
@@ -84,6 +84,8 @@ template <class T> class MemoryDynamic : public Allocator<T>
|
|||||||
virtual void release(T *p) override
|
virtual void release(T *p) override
|
||||||
{
|
{
|
||||||
assert(p);
|
assert(p);
|
||||||
|
LOG_HEAP("Freeing 0x%x", p);
|
||||||
|
|
||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,6 @@ void MeshModule::callModules(meshtastic_MeshPacket &mp, RxSource src)
|
|||||||
// Was this message directed to us specifically? Will be false if we are sniffing someone elses packets
|
// Was this message directed to us specifically? Will be false if we are sniffing someone elses packets
|
||||||
auto ourNodeNum = nodeDB->getNodeNum();
|
auto ourNodeNum = nodeDB->getNodeNum();
|
||||||
bool toUs = isBroadcast(mp.to) || isToUs(&mp);
|
bool toUs = isBroadcast(mp.to) || isToUs(&mp);
|
||||||
bool fromUs = mp.from == ourNodeNum;
|
|
||||||
|
|
||||||
for (auto i = modules->begin(); i != modules->end(); ++i) {
|
for (auto i = modules->begin(); i != modules->end(); ++i) {
|
||||||
auto &pi = **i;
|
auto &pi = **i;
|
||||||
|
|||||||
@@ -61,8 +61,10 @@ Allocator<meshtastic_QueueStatus> &queueStatusPool = staticQueueStatusPool;
|
|||||||
#include "Router.h"
|
#include "Router.h"
|
||||||
|
|
||||||
MeshService::MeshService()
|
MeshService::MeshService()
|
||||||
: toPhoneQueue(MAX_RX_TOPHONE), toPhoneQueueStatusQueue(MAX_RX_TOPHONE), toPhoneMqttProxyQueue(MAX_RX_TOPHONE),
|
#ifdef ARCH_PORTDUINO
|
||||||
toPhoneClientNotificationQueue(MAX_RX_TOPHONE / 2)
|
: toPhoneQueue(MAX_RX_TOPHONE), toPhoneQueueStatusQueue(MAX_RX_QUEUESTATUS_TOPHONE),
|
||||||
|
toPhoneMqttProxyQueue(MAX_RX_MQTTPROXY_TOPHONE), toPhoneClientNotificationQueue(MAX_RX_NOTIFICATION_TOPHONE)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
lastQueueStatus = {0, 0, 16, 0};
|
lastQueueStatus = {0, 0, 16, 0};
|
||||||
}
|
}
|
||||||
@@ -191,8 +193,10 @@ void MeshService::handleToRadio(meshtastic_MeshPacket &p)
|
|||||||
// (so we update our nodedb for the local node)
|
// (so we update our nodedb for the local node)
|
||||||
|
|
||||||
// Send the packet into the mesh
|
// Send the packet into the mesh
|
||||||
|
DEBUG_HEAP_BEFORE;
|
||||||
sendToMesh(packetPool.allocCopy(p), RX_SRC_USER);
|
auto a = packetPool.allocCopy(p);
|
||||||
|
DEBUG_HEAP_AFTER("MeshService::handleToRadio", a);
|
||||||
|
sendToMesh(a, RX_SRC_USER);
|
||||||
|
|
||||||
bool loopback = false; // if true send any packet the phone sends back itself (for testing)
|
bool loopback = false; // if true send any packet the phone sends back itself (for testing)
|
||||||
if (loopback) {
|
if (loopback) {
|
||||||
@@ -248,7 +252,11 @@ void MeshService::sendToMesh(meshtastic_MeshPacket *p, RxSource src, bool ccToPh
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((res == ERRNO_OK || res == ERRNO_SHOULD_RELEASE) && ccToPhone) { // Check if p is not released in case it couldn't be sent
|
if ((res == ERRNO_OK || res == ERRNO_SHOULD_RELEASE) && ccToPhone) { // Check if p is not released in case it couldn't be sent
|
||||||
sendToPhone(packetPool.allocCopy(*p));
|
DEBUG_HEAP_BEFORE;
|
||||||
|
auto a = packetPool.allocCopy(*p);
|
||||||
|
DEBUG_HEAP_AFTER("MeshService::sendToMesh", a);
|
||||||
|
|
||||||
|
sendToPhone(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Router may ask us to release the packet if it wasn't sent
|
// Router may ask us to release the packet if it wasn't sent
|
||||||
|
|||||||
@@ -9,7 +9,12 @@
|
|||||||
#include "MeshRadio.h"
|
#include "MeshRadio.h"
|
||||||
#include "MeshTypes.h"
|
#include "MeshTypes.h"
|
||||||
#include "Observer.h"
|
#include "Observer.h"
|
||||||
|
#ifdef ARCH_PORTDUINO
|
||||||
#include "PointerQueue.h"
|
#include "PointerQueue.h"
|
||||||
|
#else
|
||||||
|
#include "StaticPointerQueue.h"
|
||||||
|
#endif
|
||||||
|
#include "mesh-pb-constants.h"
|
||||||
#if defined(ARCH_PORTDUINO)
|
#if defined(ARCH_PORTDUINO)
|
||||||
#include "../platform/portduino/SimRadio.h"
|
#include "../platform/portduino/SimRadio.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -37,16 +42,32 @@ class MeshService
|
|||||||
/// FIXME, change to a DropOldestQueue and keep a count of the number of dropped packets to ensure
|
/// FIXME, change to a DropOldestQueue and keep a count of the number of dropped packets to ensure
|
||||||
/// we never hang because android hasn't been there in a while
|
/// we never hang because android hasn't been there in a while
|
||||||
/// FIXME - save this to flash on deep sleep
|
/// FIXME - save this to flash on deep sleep
|
||||||
|
#ifdef ARCH_PORTDUINO
|
||||||
PointerQueue<meshtastic_MeshPacket> toPhoneQueue;
|
PointerQueue<meshtastic_MeshPacket> toPhoneQueue;
|
||||||
|
#else
|
||||||
|
StaticPointerQueue<meshtastic_MeshPacket, MAX_RX_TOPHONE> toPhoneQueue;
|
||||||
|
#endif
|
||||||
|
|
||||||
// keep list of QueueStatus packets to be send to the phone
|
// keep list of QueueStatus packets to be send to the phone
|
||||||
|
#ifdef ARCH_PORTDUINO
|
||||||
PointerQueue<meshtastic_QueueStatus> toPhoneQueueStatusQueue;
|
PointerQueue<meshtastic_QueueStatus> toPhoneQueueStatusQueue;
|
||||||
|
#else
|
||||||
|
StaticPointerQueue<meshtastic_QueueStatus, MAX_RX_QUEUESTATUS_TOPHONE> toPhoneQueueStatusQueue;
|
||||||
|
#endif
|
||||||
|
|
||||||
// keep list of MqttClientProxyMessages to be send to the client for delivery
|
// keep list of MqttClientProxyMessages to be send to the client for delivery
|
||||||
|
#ifdef ARCH_PORTDUINO
|
||||||
PointerQueue<meshtastic_MqttClientProxyMessage> toPhoneMqttProxyQueue;
|
PointerQueue<meshtastic_MqttClientProxyMessage> toPhoneMqttProxyQueue;
|
||||||
|
#else
|
||||||
|
StaticPointerQueue<meshtastic_MqttClientProxyMessage, MAX_RX_MQTTPROXY_TOPHONE> toPhoneMqttProxyQueue;
|
||||||
|
#endif
|
||||||
|
|
||||||
// keep list of ClientNotifications to be send to the client (phone)
|
// keep list of ClientNotifications to be send to the client (phone)
|
||||||
|
#ifdef ARCH_PORTDUINO
|
||||||
PointerQueue<meshtastic_ClientNotification> toPhoneClientNotificationQueue;
|
PointerQueue<meshtastic_ClientNotification> toPhoneClientNotificationQueue;
|
||||||
|
#else
|
||||||
|
StaticPointerQueue<meshtastic_ClientNotification, MAX_RX_NOTIFICATION_TOPHONE> toPhoneClientNotificationQueue;
|
||||||
|
#endif
|
||||||
|
|
||||||
// This holds the last QueueStatus send
|
// This holds the last QueueStatus send
|
||||||
meshtastic_QueueStatus lastQueueStatus;
|
meshtastic_QueueStatus lastQueueStatus;
|
||||||
|
|||||||
@@ -175,12 +175,18 @@ bool NextHopRouter::stopRetransmission(GlobalPacketId key)
|
|||||||
config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER_LATE)) {
|
config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER_LATE)) {
|
||||||
// remove the 'original' (identified by originator and packet->id) from the txqueue and free it
|
// remove the 'original' (identified by originator and packet->id) from the txqueue and free it
|
||||||
cancelSending(getFrom(p), p->id);
|
cancelSending(getFrom(p), p->id);
|
||||||
// now free the pooled copy for retransmission too
|
|
||||||
packetPool.release(p);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Regardless of whether or not we canceled this packet from the txQueue, remove it from our pending list so it doesn't
|
||||||
|
// get scheduled again. (This is the core of stopRetransmission.)
|
||||||
auto numErased = pending.erase(key);
|
auto numErased = pending.erase(key);
|
||||||
assert(numErased == 1);
|
assert(numErased == 1);
|
||||||
|
|
||||||
|
// When we remove an entry from pending, always be sure to release the copy of the packet that was allocated in the call
|
||||||
|
// to startRetransmission.
|
||||||
|
packetPool.release(p);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else
|
} else
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ void PhoneAPI::close()
|
|||||||
config_nonce = 0;
|
config_nonce = 0;
|
||||||
config_state = 0;
|
config_state = 0;
|
||||||
pauseBluetoothLogging = false;
|
pauseBluetoothLogging = false;
|
||||||
|
heartbeatReceived = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "Default.h"
|
#include "Default.h"
|
||||||
#include "MeshTypes.h"
|
#include "MeshTypes.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#include "memGet.h"
|
||||||
#include "mesh-pb-constants.h"
|
#include "mesh-pb-constants.h"
|
||||||
#include "modules/NodeInfoModule.h"
|
#include "modules/NodeInfoModule.h"
|
||||||
#include "modules/RoutingModule.h"
|
#include "modules/RoutingModule.h"
|
||||||
@@ -21,8 +22,10 @@ ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p)
|
|||||||
if (p->hop_limit == 0) {
|
if (p->hop_limit == 0) {
|
||||||
p->hop_limit = Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit);
|
p->hop_limit = Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit);
|
||||||
}
|
}
|
||||||
|
DEBUG_HEAP_BEFORE;
|
||||||
auto copy = packetPool.allocCopy(*p);
|
auto copy = packetPool.allocCopy(*p);
|
||||||
|
DEBUG_HEAP_AFTER("ReliableRouter::send", copy);
|
||||||
|
|
||||||
startRetransmission(copy, NUM_RELIABLE_RETX);
|
startRetransmission(copy, NUM_RELIABLE_RETX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -275,7 +275,10 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
|
|||||||
// If the packet is not yet encrypted, do so now
|
// If the packet is not yet encrypted, do so now
|
||||||
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
|
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
|
||||||
ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it
|
ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it
|
||||||
|
|
||||||
|
DEBUG_HEAP_BEFORE;
|
||||||
meshtastic_MeshPacket *p_decoded = packetPool.allocCopy(*p);
|
meshtastic_MeshPacket *p_decoded = packetPool.allocCopy(*p);
|
||||||
|
DEBUG_HEAP_AFTER("Router::send", p_decoded);
|
||||||
|
|
||||||
auto encodeResult = perhapsEncode(p);
|
auto encodeResult = perhapsEncode(p);
|
||||||
if (encodeResult != meshtastic_Routing_Error_NONE) {
|
if (encodeResult != meshtastic_Routing_Error_NONE) {
|
||||||
@@ -607,8 +610,11 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
|
|||||||
bool skipHandle = false;
|
bool skipHandle = false;
|
||||||
// Also, we should set the time from the ISR and it should have msec level resolution
|
// Also, we should set the time from the ISR and it should have msec level resolution
|
||||||
p->rx_time = getValidTime(RTCQualityFromNet); // store the arrival timestamp for the phone
|
p->rx_time = getValidTime(RTCQualityFromNet); // store the arrival timestamp for the phone
|
||||||
|
|
||||||
// Store a copy of encrypted packet for MQTT
|
// Store a copy of encrypted packet for MQTT
|
||||||
|
DEBUG_HEAP_BEFORE;
|
||||||
meshtastic_MeshPacket *p_encrypted = packetPool.allocCopy(*p);
|
meshtastic_MeshPacket *p_encrypted = packetPool.allocCopy(*p);
|
||||||
|
DEBUG_HEAP_AFTER("Router::handleReceived", p_encrypted);
|
||||||
|
|
||||||
// Take those raw bytes and convert them back into a well structured protobuf we can understand
|
// Take those raw bytes and convert them back into a well structured protobuf we can understand
|
||||||
auto decodedState = perhapsDecode(p);
|
auto decodedState = perhapsDecode(p);
|
||||||
@@ -656,7 +662,7 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
|
|||||||
|
|
||||||
// call modules here
|
// call modules here
|
||||||
// If this could be a spoofed packet, don't let the modules see it.
|
// If this could be a spoofed packet, don't let the modules see it.
|
||||||
if (!skipHandle && p->from != nodeDB->getNodeNum()) {
|
if (!skipHandle) {
|
||||||
MeshModule::callModules(*p, src);
|
MeshModule::callModules(*p, src);
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_MQTT
|
#if !MESHTASTIC_EXCLUDE_MQTT
|
||||||
@@ -670,8 +676,6 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
|
|||||||
!isFromUs(p) && mqtt)
|
!isFromUs(p) && mqtt)
|
||||||
mqtt->onSend(*p_encrypted, *p, p->channel);
|
mqtt->onSend(*p_encrypted, *p, p->channel);
|
||||||
#endif
|
#endif
|
||||||
} else if (p->from == nodeDB->getNodeNum() && !skipHandle) {
|
|
||||||
MeshModule::callModules(*p, src);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
packetPool.release(p_encrypted); // Release the encrypted packet
|
packetPool.release(p_encrypted); // Release the encrypted packet
|
||||||
|
|||||||
77
src/mesh/StaticPointerQueue.h
Normal file
77
src/mesh/StaticPointerQueue.h
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "concurrency/OSThread.h"
|
||||||
|
#include "freertosinc.h"
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A static circular buffer queue for pointers.
|
||||||
|
* This provides the same interface as PointerQueue but uses a statically allocated
|
||||||
|
* buffer instead of dynamic allocation.
|
||||||
|
*/
|
||||||
|
template <class T, int MaxElements> class StaticPointerQueue
|
||||||
|
{
|
||||||
|
static_assert(MaxElements > 0, "MaxElements must be greater than 0");
|
||||||
|
|
||||||
|
T *buffer[MaxElements];
|
||||||
|
int head = 0;
|
||||||
|
int tail = 0;
|
||||||
|
int count = 0;
|
||||||
|
concurrency::OSThread *reader = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
StaticPointerQueue()
|
||||||
|
{
|
||||||
|
// Initialize all buffer elements to nullptr to silence warnings and ensure clean state
|
||||||
|
for (int i = 0; i < MaxElements; i++) {
|
||||||
|
buffer[i] = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int numFree() const { return MaxElements - count; }
|
||||||
|
|
||||||
|
bool isEmpty() const { return count == 0; }
|
||||||
|
|
||||||
|
int numUsed() const { return count; }
|
||||||
|
|
||||||
|
bool enqueue(T *x, TickType_t maxWait = portMAX_DELAY)
|
||||||
|
{
|
||||||
|
if (count >= MaxElements) {
|
||||||
|
return false; // Queue is full
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reader) {
|
||||||
|
reader->setInterval(0);
|
||||||
|
concurrency::mainDelay.interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[tail] = x;
|
||||||
|
tail = (tail + 1) % MaxElements;
|
||||||
|
count++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dequeue(T **p, TickType_t maxWait = portMAX_DELAY)
|
||||||
|
{
|
||||||
|
if (count == 0) {
|
||||||
|
return false; // Queue is empty
|
||||||
|
}
|
||||||
|
|
||||||
|
*p = buffer[head];
|
||||||
|
head = (head + 1) % MaxElements;
|
||||||
|
count--;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns a ptr or null if the queue was empty
|
||||||
|
T *dequeuePtr(TickType_t maxWait = portMAX_DELAY)
|
||||||
|
{
|
||||||
|
T *p;
|
||||||
|
return dequeue(&p, maxWait) ? p : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setReader(concurrency::OSThread *t) { reader = t; }
|
||||||
|
|
||||||
|
// For compatibility with PointerQueue interface
|
||||||
|
int getMaxLen() const { return MaxElements; }
|
||||||
|
};
|
||||||
@@ -18,6 +18,21 @@
|
|||||||
#define MAX_RX_TOPHONE 32
|
#define MAX_RX_TOPHONE 32
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// max number of QueueStatus packets which can be waiting for delivery to phone
|
||||||
|
#ifndef MAX_RX_QUEUESTATUS_TOPHONE
|
||||||
|
#define MAX_RX_QUEUESTATUS_TOPHONE 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// max number of MqttClientProxyMessage packets which can be waiting for delivery to phone
|
||||||
|
#ifndef MAX_RX_MQTTPROXY_TOPHONE
|
||||||
|
#define MAX_RX_MQTTPROXY_TOPHONE 32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// max number of ClientNotification packets which can be waiting for delivery to phone
|
||||||
|
#ifndef MAX_RX_NOTIFICATION_TOPHONE
|
||||||
|
#define MAX_RX_NOTIFICATION_TOPHONE 4
|
||||||
|
#endif
|
||||||
|
|
||||||
/// Verify baseline assumption of node size. If it increases, we need to reevaluate
|
/// Verify baseline assumption of node size. If it increases, we need to reevaluate
|
||||||
/// the impact of its memory footprint, notably on MAX_NUM_NODES.
|
/// the impact of its memory footprint, notably on MAX_NUM_NODES.
|
||||||
static_assert(sizeof(meshtastic_NodeInfoLite) <= 200, "NodeInfoLite size increased. Reconsider impact on MAX_NUM_NODES.");
|
static_assert(sizeof(meshtastic_NodeInfoLite) <= 200, "NodeInfoLite size increased. Reconsider impact on MAX_NUM_NODES.");
|
||||||
|
|||||||
@@ -6,9 +6,12 @@
|
|||||||
#include "input/RotaryEncoderImpl.h"
|
#include "input/RotaryEncoderImpl.h"
|
||||||
#include "input/RotaryEncoderInterruptImpl1.h"
|
#include "input/RotaryEncoderInterruptImpl1.h"
|
||||||
#include "input/SerialKeyboardImpl.h"
|
#include "input/SerialKeyboardImpl.h"
|
||||||
#include "input/TrackballInterruptImpl1.h"
|
|
||||||
#include "input/UpDownInterruptImpl1.h"
|
#include "input/UpDownInterruptImpl1.h"
|
||||||
#include "modules/SystemCommandsModule.h"
|
#include "modules/SystemCommandsModule.h"
|
||||||
|
#if HAS_TRACKBALL
|
||||||
|
#include "input/TrackballInterruptImpl1.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_I2C
|
#if !MESHTASTIC_EXCLUDE_I2C
|
||||||
#include "input/cardKbI2cImpl.h"
|
#include "input/cardKbI2cImpl.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -135,13 +138,20 @@ void setupModules()
|
|||||||
traceRouteModule = new TraceRouteModule();
|
traceRouteModule = new TraceRouteModule();
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_NEIGHBORINFO
|
#if !MESHTASTIC_EXCLUDE_NEIGHBORINFO
|
||||||
neighborInfoModule = new NeighborInfoModule();
|
if (moduleConfig.has_neighbor_info && moduleConfig.neighbor_info.enabled) {
|
||||||
|
neighborInfoModule = new NeighborInfoModule();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_DETECTIONSENSOR
|
#if !MESHTASTIC_EXCLUDE_DETECTIONSENSOR
|
||||||
detectionSensorModule = new DetectionSensorModule();
|
if (moduleConfig.has_detection_sensor && moduleConfig.detection_sensor.enabled) {
|
||||||
|
detectionSensorModule = new DetectionSensorModule();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_ATAK
|
#if !MESHTASTIC_EXCLUDE_ATAK
|
||||||
atakPluginModule = new AtakPluginModule();
|
if (IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_TAK,
|
||||||
|
meshtastic_Config_DeviceConfig_Role_TAK_TRACKER)) {
|
||||||
|
atakPluginModule = new AtakPluginModule();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_PKI
|
#if !MESHTASTIC_EXCLUDE_PKI
|
||||||
keyVerificationModule = new KeyVerificationModule();
|
keyVerificationModule = new KeyVerificationModule();
|
||||||
@@ -207,7 +217,7 @@ void setupModules()
|
|||||||
aLinuxInputImpl->init();
|
aLinuxInputImpl->init();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_INPUTBROKER
|
#if !MESHTASTIC_EXCLUDE_INPUTBROKER && HAS_TRACKBALL
|
||||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||||
trackballInterruptImpl1 = new TrackballInterruptImpl1();
|
trackballInterruptImpl1 = new TrackballInterruptImpl1();
|
||||||
trackballInterruptImpl1->init(TB_DOWN, TB_UP, TB_LEFT, TB_RIGHT, TB_PRESS);
|
trackballInterruptImpl1->init(TB_DOWN, TB_UP, TB_LEFT, TB_RIGHT, TB_PRESS);
|
||||||
@@ -227,11 +237,14 @@ void setupModules()
|
|||||||
#if HAS_TELEMETRY
|
#if HAS_TELEMETRY
|
||||||
new DeviceTelemetryModule();
|
new DeviceTelemetryModule();
|
||||||
#endif
|
#endif
|
||||||
// TODO: How to improve this?
|
|
||||||
#if HAS_SENSOR && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
#if HAS_SENSOR && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||||
new EnvironmentTelemetryModule();
|
if (moduleConfig.has_telemetry &&
|
||||||
|
(moduleConfig.telemetry.environment_measurement_enabled || moduleConfig.telemetry.environment_screen_enabled)) {
|
||||||
|
new EnvironmentTelemetryModule();
|
||||||
|
}
|
||||||
#if __has_include("Adafruit_PM25AQI.h")
|
#if __has_include("Adafruit_PM25AQI.h")
|
||||||
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I].first > 0) {
|
if (moduleConfig.has_telemetry && moduleConfig.telemetry.air_quality_enabled &&
|
||||||
|
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I].first > 0) {
|
||||||
new AirQualityTelemetryModule();
|
new AirQualityTelemetryModule();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -243,12 +256,16 @@ void setupModules()
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_POWER_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_POWER_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||||
new PowerTelemetryModule();
|
if (moduleConfig.has_telemetry &&
|
||||||
|
(moduleConfig.telemetry.power_measurement_enabled || moduleConfig.telemetry.power_screen_enabled)) {
|
||||||
|
new PowerTelemetryModule();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_STM32WL)) && \
|
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_STM32WL)) && \
|
||||||
!defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
!defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
#if !MESHTASTIC_EXCLUDE_SERIAL
|
#if !MESHTASTIC_EXCLUDE_SERIAL
|
||||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
if (moduleConfig.has_serial && moduleConfig.serial.enabled &&
|
||||||
|
config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||||
new SerialModule();
|
new SerialModule();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -259,19 +276,26 @@ void setupModules()
|
|||||||
audioModule = new AudioModule();
|
audioModule = new AudioModule();
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_PAXCOUNTER
|
#if !MESHTASTIC_EXCLUDE_PAXCOUNTER
|
||||||
paxcounterModule = new PaxcounterModule();
|
if (moduleConfig.has_paxcounter && moduleConfig.paxcounter.enabled) {
|
||||||
|
paxcounterModule = new PaxcounterModule();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#if defined(ARCH_ESP32) || defined(ARCH_PORTDUINO)
|
#if defined(ARCH_ESP32) || defined(ARCH_PORTDUINO)
|
||||||
#if !MESHTASTIC_EXCLUDE_STOREFORWARD
|
#if !MESHTASTIC_EXCLUDE_STOREFORWARD
|
||||||
storeForwardModule = new StoreForwardModule();
|
if (moduleConfig.has_store_forward && moduleConfig.store_forward.enabled) {
|
||||||
|
storeForwardModule = new StoreForwardModule();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION
|
#if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION
|
||||||
externalNotificationModule = new ExternalNotificationModule();
|
if (moduleConfig.has_external_notification && moduleConfig.external_notification.enabled) {
|
||||||
|
externalNotificationModule = new ExternalNotificationModule();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_RANGETEST && !MESHTASTIC_EXCLUDE_GPS
|
#if !MESHTASTIC_EXCLUDE_RANGETEST && !MESHTASTIC_EXCLUDE_GPS
|
||||||
new RangeTestModule();
|
if (moduleConfig.has_range_test && moduleConfig.range_test.enabled)
|
||||||
|
new RangeTestModule();
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
#if !MESHTASTIC_EXCLUDE_ADMIN
|
#if !MESHTASTIC_EXCLUDE_ADMIN
|
||||||
|
|||||||
@@ -12,12 +12,12 @@ NodeInfoModule *nodeInfoModule;
|
|||||||
|
|
||||||
bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_User *pptr)
|
bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_User *pptr)
|
||||||
{
|
{
|
||||||
auto p = *pptr;
|
|
||||||
|
|
||||||
if (mp.from == nodeDB->getNodeNum()) {
|
if (mp.from == nodeDB->getNodeNum()) {
|
||||||
LOG_WARN("Ignoring packet supposed to be from our own node: %08x", mp.from);
|
LOG_WARN("Ignoring packet supposed to be from our own node: %08x", mp.from);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto p = *pptr;
|
||||||
if (p.is_licensed != owner.is_licensed) {
|
if (p.is_licensed != owner.is_licensed) {
|
||||||
LOG_WARN("Invalid nodeInfo detected, is_licensed mismatch!");
|
LOG_WARN("Invalid nodeInfo detected, is_licensed mismatch!");
|
||||||
return true;
|
return true;
|
||||||
@@ -44,7 +44,10 @@ void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies, uint8_t cha
|
|||||||
if (prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal)
|
if (prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal)
|
||||||
service->cancelSending(prevPacketId);
|
service->cancelSending(prevPacketId);
|
||||||
shorterTimeout = _shorterTimeout;
|
shorterTimeout = _shorterTimeout;
|
||||||
|
DEBUG_HEAP_BEFORE;
|
||||||
meshtastic_MeshPacket *p = allocReply();
|
meshtastic_MeshPacket *p = allocReply();
|
||||||
|
DEBUG_HEAP_AFTER("NodeInfoModule::sendOurNodeInfo", p);
|
||||||
|
|
||||||
if (p) { // Check whether we didn't ignore it
|
if (p) { // Check whether we didn't ignore it
|
||||||
p->to = dest;
|
p->to = dest;
|
||||||
p->decoded.want_response = (config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER &&
|
p->decoded.want_response = (config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER &&
|
||||||
|
|||||||
@@ -172,7 +172,10 @@ bool DeviceTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
|||||||
telemetry.variant.device_metrics.battery_level, telemetry.variant.device_metrics.voltage,
|
telemetry.variant.device_metrics.battery_level, telemetry.variant.device_metrics.voltage,
|
||||||
telemetry.variant.device_metrics.uptime_seconds);
|
telemetry.variant.device_metrics.uptime_seconds);
|
||||||
|
|
||||||
|
DEBUG_HEAP_BEFORE;
|
||||||
meshtastic_MeshPacket *p = allocDataProtobuf(telemetry);
|
meshtastic_MeshPacket *p = allocDataProtobuf(telemetry);
|
||||||
|
DEBUG_HEAP_AFTER("DeviceTelemetryModule::sendTelemetry", p);
|
||||||
|
|
||||||
p->to = dest;
|
p->to = dest;
|
||||||
p->decoded.want_response = false;
|
p->decoded.want_response = false;
|
||||||
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
|
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
|
||||||
|
|||||||
@@ -1,42 +1,105 @@
|
|||||||
#include "../test_helpers.h"
|
#include "../test_helpers.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
// Helper function to test common packet fields and structure
|
||||||
|
void verify_text_message_packet_structure(const std::string &json, const char *expected_text)
|
||||||
|
{
|
||||||
|
TEST_ASSERT_TRUE(json.length() > 0);
|
||||||
|
|
||||||
|
// Use smart pointer for automatic memory management
|
||||||
|
std::unique_ptr<JSONValue> root(JSON::Parse(json.c_str()));
|
||||||
|
TEST_ASSERT_NOT_NULL(root.get());
|
||||||
|
TEST_ASSERT_TRUE(root->IsObject());
|
||||||
|
|
||||||
|
JSONObject jsonObj = root->AsObject();
|
||||||
|
|
||||||
|
// Check basic packet fields - use helper function to reduce duplication
|
||||||
|
auto check_field = [&](const char *field, uint32_t expected_value) {
|
||||||
|
auto it = jsonObj.find(field);
|
||||||
|
TEST_ASSERT_TRUE(it != jsonObj.end());
|
||||||
|
TEST_ASSERT_EQUAL(expected_value, (uint32_t)it->second->AsNumber());
|
||||||
|
};
|
||||||
|
|
||||||
|
check_field("from", 0x11223344);
|
||||||
|
check_field("to", 0x55667788);
|
||||||
|
check_field("id", 0x9999);
|
||||||
|
|
||||||
|
// Check message type
|
||||||
|
auto type_it = jsonObj.find("type");
|
||||||
|
TEST_ASSERT_TRUE(type_it != jsonObj.end());
|
||||||
|
TEST_ASSERT_EQUAL_STRING("text", type_it->second->AsString().c_str());
|
||||||
|
|
||||||
|
// Check payload
|
||||||
|
auto payload_it = jsonObj.find("payload");
|
||||||
|
TEST_ASSERT_TRUE(payload_it != jsonObj.end());
|
||||||
|
TEST_ASSERT_TRUE(payload_it->second->IsObject());
|
||||||
|
|
||||||
|
JSONObject payload = payload_it->second->AsObject();
|
||||||
|
auto text_it = payload.find("text");
|
||||||
|
TEST_ASSERT_TRUE(text_it != payload.end());
|
||||||
|
TEST_ASSERT_EQUAL_STRING(expected_text, text_it->second->AsString().c_str());
|
||||||
|
|
||||||
|
// No need for manual delete with smart pointer
|
||||||
|
}
|
||||||
|
|
||||||
// Test TEXT_MESSAGE_APP port
|
// Test TEXT_MESSAGE_APP port
|
||||||
void test_text_message_serialization()
|
void test_text_message_serialization()
|
||||||
{
|
{
|
||||||
const char *test_text = "Hello Meshtastic!";
|
const char *test_text = "Hello Meshtastic!";
|
||||||
meshtastic_MeshPacket packet =
|
meshtastic_MeshPacket packet =
|
||||||
create_test_packet(meshtastic_PortNum_TEXT_MESSAGE_APP, (const uint8_t *)test_text, strlen(test_text));
|
create_test_packet(meshtastic_PortNum_TEXT_MESSAGE_APP, reinterpret_cast<const uint8_t *>(test_text), strlen(test_text));
|
||||||
|
|
||||||
std::string json = MeshPacketSerializer::JsonSerialize(&packet, false);
|
std::string json = MeshPacketSerializer::JsonSerialize(&packet, false);
|
||||||
TEST_ASSERT_TRUE(json.length() > 0);
|
verify_text_message_packet_structure(json, test_text);
|
||||||
|
|
||||||
JSONValue *root = JSON::Parse(json.c_str());
|
|
||||||
TEST_ASSERT_NOT_NULL(root);
|
|
||||||
TEST_ASSERT_TRUE(root->IsObject());
|
|
||||||
|
|
||||||
JSONObject jsonObj = root->AsObject();
|
|
||||||
|
|
||||||
// Check basic packet fields
|
|
||||||
TEST_ASSERT_TRUE(jsonObj.find("from") != jsonObj.end());
|
|
||||||
TEST_ASSERT_EQUAL(0x11223344, (uint32_t)jsonObj["from"]->AsNumber());
|
|
||||||
|
|
||||||
TEST_ASSERT_TRUE(jsonObj.find("to") != jsonObj.end());
|
|
||||||
TEST_ASSERT_EQUAL(0x55667788, (uint32_t)jsonObj["to"]->AsNumber());
|
|
||||||
|
|
||||||
TEST_ASSERT_TRUE(jsonObj.find("id") != jsonObj.end());
|
|
||||||
TEST_ASSERT_EQUAL(0x9999, (uint32_t)jsonObj["id"]->AsNumber());
|
|
||||||
|
|
||||||
// Check message type
|
|
||||||
TEST_ASSERT_TRUE(jsonObj.find("type") != jsonObj.end());
|
|
||||||
TEST_ASSERT_EQUAL_STRING("text", jsonObj["type"]->AsString().c_str());
|
|
||||||
|
|
||||||
// Check payload
|
|
||||||
TEST_ASSERT_TRUE(jsonObj.find("payload") != jsonObj.end());
|
|
||||||
TEST_ASSERT_TRUE(jsonObj["payload"]->IsObject());
|
|
||||||
|
|
||||||
JSONObject payload = jsonObj["payload"]->AsObject();
|
|
||||||
TEST_ASSERT_TRUE(payload.find("text") != payload.end());
|
|
||||||
TEST_ASSERT_EQUAL_STRING("Hello Meshtastic!", payload["text"]->AsString().c_str());
|
|
||||||
|
|
||||||
delete root;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test with nullptr to check robustness
|
||||||
|
void test_text_message_serialization_null()
|
||||||
|
{
|
||||||
|
meshtastic_MeshPacket packet = create_test_packet(meshtastic_PortNum_TEXT_MESSAGE_APP, nullptr, 0);
|
||||||
|
|
||||||
|
std::string json = MeshPacketSerializer::JsonSerialize(&packet, false);
|
||||||
|
verify_text_message_packet_structure(json, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test TEXT_MESSAGE_APP port with very long message (boundary testing)
|
||||||
|
void test_text_message_serialization_long_text()
|
||||||
|
{
|
||||||
|
// Test with actual message size limits
|
||||||
|
constexpr size_t MAX_MESSAGE_SIZE = 200; // Typical LoRa payload limit
|
||||||
|
std::string long_text(MAX_MESSAGE_SIZE, 'A');
|
||||||
|
|
||||||
|
meshtastic_MeshPacket packet = create_test_packet(meshtastic_PortNum_TEXT_MESSAGE_APP,
|
||||||
|
reinterpret_cast<const uint8_t *>(long_text.c_str()), long_text.length());
|
||||||
|
|
||||||
|
std::string json = MeshPacketSerializer::JsonSerialize(&packet, false);
|
||||||
|
verify_text_message_packet_structure(json, long_text.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test with message over size limit (should fail)
|
||||||
|
void test_text_message_serialization_oversized()
|
||||||
|
{
|
||||||
|
constexpr size_t OVERSIZED_MESSAGE = 250; // Over the limit
|
||||||
|
std::string oversized_text(OVERSIZED_MESSAGE, 'B');
|
||||||
|
|
||||||
|
meshtastic_MeshPacket packet = create_test_packet(
|
||||||
|
meshtastic_PortNum_TEXT_MESSAGE_APP, reinterpret_cast<const uint8_t *>(oversized_text.c_str()), oversized_text.length());
|
||||||
|
|
||||||
|
// Should fail or return empty/error
|
||||||
|
std::string json = MeshPacketSerializer::JsonSerialize(&packet, false);
|
||||||
|
// Should only verify first 234 characters for oversized messages
|
||||||
|
std::string expected_text = oversized_text.substr(0, 234);
|
||||||
|
verify_text_message_packet_structure(json, expected_text.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add test for malformed UTF-8 sequences
|
||||||
|
void test_text_message_serialization_invalid_utf8()
|
||||||
|
{
|
||||||
|
const uint8_t invalid_utf8[] = {0xFF, 0xFE, 0xFD, 0x00}; // Invalid UTF-8
|
||||||
|
meshtastic_MeshPacket packet =
|
||||||
|
create_test_packet(meshtastic_PortNum_TEXT_MESSAGE_APP, invalid_utf8, sizeof(invalid_utf8) - 1);
|
||||||
|
|
||||||
|
// Should not crash, may produce replacement characters
|
||||||
|
std::string json = MeshPacketSerializer::JsonSerialize(&packet, false);
|
||||||
|
TEST_ASSERT_TRUE(json.length() > 0);
|
||||||
|
}
|
||||||
@@ -70,6 +70,7 @@ build_flags =
|
|||||||
${ft5x06.build_flags}
|
${ft5x06.build_flags}
|
||||||
-D LGFX_SCREEN_WIDTH=240
|
-D LGFX_SCREEN_WIDTH=240
|
||||||
-D LGFX_SCREEN_HEIGHT=320
|
-D LGFX_SCREEN_HEIGHT=320
|
||||||
|
-D DISPLAY_SIZE=320x240 ; landscape mode
|
||||||
-D LGFX_PANEL=ST7789
|
-D LGFX_PANEL=ST7789
|
||||||
-D LGFX_ROTATION=1
|
-D LGFX_ROTATION=1
|
||||||
-D LGFX_TOUCH_X_MIN=0
|
-D LGFX_TOUCH_X_MIN=0
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
#define CANNED_MESSAGE_MODULE_ENABLE 1
|
#define CANNED_MESSAGE_MODULE_ENABLE 1
|
||||||
#define HAS_GPS 1
|
#define HAS_GPS 1
|
||||||
#define MAX_RX_TOPHONE settingsMap[maxtophone]
|
#define MAX_RX_TOPHONE settingsMap[maxtophone]
|
||||||
#define MAX_NUM_NODES settingsMap[maxnodes]
|
#define MAX_NUM_NODES settingsMap[maxnodes]
|
||||||
|
|||||||
Reference in New Issue
Block a user