mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-24 18:57:43 +00:00
Resolve conflicts (needs testing)
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_GPS
|
||||
#include "GPS.h"
|
||||
#endif
|
||||
#include "../detect/ScanI2C.h"
|
||||
#include "Channels.h"
|
||||
#include "CryptoEngine.h"
|
||||
#include "Default.h"
|
||||
#include "FSCommon.h"
|
||||
#include "GPS.h"
|
||||
#include "MeshRadio.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PacketHistory.h"
|
||||
@@ -17,22 +19,31 @@
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "modules/NeighborInfoModule.h"
|
||||
#include <ErriezCRC32.h>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <pb_decode.h>
|
||||
#include <pb_encode.h>
|
||||
#include <vector>
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
#include "mesh/http/WiFiAPClient.h"
|
||||
#if !MESHTASTIC_EXCLUDE_WIFI
|
||||
#include "mesh/wifi/WiFiAPClient.h"
|
||||
#endif
|
||||
#include "modules/esp32/StoreForwardModule.h"
|
||||
#include <Preferences.h>
|
||||
#include <nvs_flash.h>
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_PORTDUINO
|
||||
#include "platform/portduino/PortduinoGlue.h"
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_NRF52
|
||||
#include <bluefruit.h>
|
||||
#include <utility/bonding.h>
|
||||
#endif
|
||||
|
||||
NodeDB nodeDB;
|
||||
NodeDB *nodeDB = nullptr;
|
||||
|
||||
// we have plenty of ram so statically alloc this tempbuf (for now)
|
||||
EXT_RAM_ATTR meshtastic_DeviceState devicestate;
|
||||
@@ -42,6 +53,26 @@ meshtastic_LocalModuleConfig moduleConfig;
|
||||
meshtastic_ChannelFile channelFile;
|
||||
meshtastic_OEMStore oemStore;
|
||||
|
||||
bool meshtastic_DeviceState_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field)
|
||||
{
|
||||
if (ostream) {
|
||||
std::vector<meshtastic_NodeInfoLite> *vec = (std::vector<meshtastic_NodeInfoLite> *)field->pData;
|
||||
for (auto item : *vec) {
|
||||
if (!pb_encode_tag_for_field(ostream, field))
|
||||
return false;
|
||||
pb_encode_submessage(ostream, meshtastic_NodeInfoLite_fields, &item);
|
||||
}
|
||||
}
|
||||
if (istream) {
|
||||
meshtastic_NodeInfoLite node; // this gets good data
|
||||
std::vector<meshtastic_NodeInfoLite> *vec = (std::vector<meshtastic_NodeInfoLite> *)field->pData;
|
||||
|
||||
if (istream->bytes_left && pb_decode(istream, meshtastic_NodeInfoLite_fields, &node))
|
||||
vec->push_back(node);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** The current change # for radio settings. Starts at 0 on boot and any time the radio settings
|
||||
* might have changed is incremented. Allows others to detect they might now be on a new channel.
|
||||
*/
|
||||
@@ -64,7 +95,63 @@ uint32_t error_address = 0;
|
||||
|
||||
static uint8_t ourMacAddr[6];
|
||||
|
||||
NodeDB::NodeDB() : meshNodes(devicestate.node_db_lite), numMeshNodes(&devicestate.node_db_lite_count) {}
|
||||
NodeDB::NodeDB()
|
||||
{
|
||||
LOG_INFO("Initializing NodeDB\n");
|
||||
loadFromDisk();
|
||||
cleanupMeshDB();
|
||||
|
||||
uint32_t devicestateCRC = crc32Buffer(&devicestate, sizeof(devicestate));
|
||||
uint32_t configCRC = crc32Buffer(&config, sizeof(config));
|
||||
uint32_t channelFileCRC = crc32Buffer(&channelFile, sizeof(channelFile));
|
||||
|
||||
int saveWhat = 0;
|
||||
|
||||
// likewise - we always want the app requirements to come from the running appload
|
||||
myNodeInfo.min_app_version = 30200; // format is Mmmss (where M is 1+the numeric major number. i.e. 30200 means 2.2.00
|
||||
// Note! We do this after loading saved settings, so that if somehow an invalid nodenum was stored in preferences we won't
|
||||
// keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts)
|
||||
pickNewNodeNum();
|
||||
|
||||
// Set our board type so we can share it with others
|
||||
owner.hw_model = HW_VENDOR;
|
||||
// Ensure user (nodeinfo) role is set to whatever we're configured to
|
||||
owner.role = config.device.role;
|
||||
|
||||
// Include our owner in the node db under our nodenum
|
||||
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(getNodeNum());
|
||||
info->user = owner;
|
||||
info->has_user = true;
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
Preferences preferences;
|
||||
preferences.begin("meshtastic", false);
|
||||
myNodeInfo.reboot_count = preferences.getUInt("rebootCounter", 0);
|
||||
preferences.end();
|
||||
LOG_DEBUG("Number of Device Reboots: %d\n", myNodeInfo.reboot_count);
|
||||
#endif
|
||||
|
||||
resetRadioConfig(); // If bogus settings got saved, then fix them
|
||||
// nodeDB->LOG_DEBUG("region=%d, NODENUM=0x%x, dbsize=%d\n", config.lora.region, myNodeInfo.my_node_num, numMeshNodes);
|
||||
|
||||
if (devicestateCRC != crc32Buffer(&devicestate, sizeof(devicestate)))
|
||||
saveWhat |= SEGMENT_DEVICESTATE;
|
||||
if (configCRC != crc32Buffer(&config, sizeof(config)))
|
||||
saveWhat |= SEGMENT_CONFIG;
|
||||
if (channelFileCRC != crc32Buffer(&channelFile, sizeof(channelFile)))
|
||||
saveWhat |= SEGMENT_CHANNELS;
|
||||
|
||||
if (!devicestate.node_remote_hardware_pins) {
|
||||
meshtastic_NodeRemoteHardwarePin empty[12] = {meshtastic_RemoteHardwarePin_init_default};
|
||||
memcpy(devicestate.node_remote_hardware_pins, empty, sizeof(empty));
|
||||
}
|
||||
|
||||
if (config.position.gps_enabled) {
|
||||
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED;
|
||||
config.position.gps_enabled = 0;
|
||||
}
|
||||
saveToDisk(saveWhat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Most (but not always) of the time we want to treat packets 'from' the local phone (where from == 0), as if they originated on
|
||||
@@ -72,7 +159,7 @@ NodeDB::NodeDB() : meshNodes(devicestate.node_db_lite), numMeshNodes(&devicestat
|
||||
*/
|
||||
NodeNum getFrom(const meshtastic_MeshPacket *p)
|
||||
{
|
||||
return (p->from == 0) ? nodeDB.getNodeNum() : p->from;
|
||||
return (p->from == 0) ? nodeDB->getNodeNum() : p->from;
|
||||
}
|
||||
|
||||
bool NodeDB::resetRadioConfig(bool factory_reset)
|
||||
@@ -93,22 +180,6 @@ bool NodeDB::resetRadioConfig(bool factory_reset)
|
||||
|
||||
channels.onConfigChanged();
|
||||
|
||||
// temp hack for quicker testing
|
||||
// devicestate.no_save = true;
|
||||
if (devicestate.no_save) {
|
||||
LOG_DEBUG("***** DEVELOPMENT MODE - DO NOT RELEASE *****\n");
|
||||
|
||||
// Sleep quite frequently to stress test the BLE comms, broadcast position every 6 mins
|
||||
config.display.screen_on_secs = 10;
|
||||
config.power.wait_bluetooth_secs = 10;
|
||||
config.position.position_broadcast_secs = 6 * 60;
|
||||
config.power.ls_secs = 60;
|
||||
config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_TW;
|
||||
|
||||
// Enter super deep sleep soon and stay there not very long
|
||||
// radioConfig.preferences.sds_secs = 60;
|
||||
}
|
||||
|
||||
// Update the global myRegion
|
||||
initRegion();
|
||||
|
||||
@@ -126,6 +197,9 @@ bool NodeDB::factoryReset()
|
||||
LOG_INFO("Performing factory reset!\n");
|
||||
// first, remove the "/prefs" (this removes most prefs)
|
||||
rmDir("/prefs");
|
||||
if (FSCom.exists("/static/rangetest.csv") && !FSCom.remove("/static/rangetest.csv")) {
|
||||
LOG_ERROR("Could not remove rangetest.csv file\n");
|
||||
}
|
||||
// second, install default state (this will deal with the duplicate mac address issue)
|
||||
installDefaultDeviceState();
|
||||
installDefaultConfig();
|
||||
@@ -159,7 +233,7 @@ void NodeDB::installDefaultConfig()
|
||||
config.has_position = true;
|
||||
config.has_power = true;
|
||||
config.has_network = true;
|
||||
config.has_bluetooth = true;
|
||||
config.has_bluetooth = (HAS_BLUETOOTH ? true : false);
|
||||
config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_ALL;
|
||||
|
||||
config.lora.sx126x_rx_boosted_gain = true;
|
||||
@@ -169,6 +243,7 @@ void NodeDB::installDefaultConfig()
|
||||
config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_UNSET;
|
||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST;
|
||||
config.lora.hop_limit = HOP_RELIABLE;
|
||||
config.lora.ignore_mqtt = false;
|
||||
#ifdef PIN_GPS_EN
|
||||
config.position.gps_en_gpio = PIN_GPS_EN;
|
||||
#endif
|
||||
@@ -177,12 +252,21 @@ void NodeDB::installDefaultConfig()
|
||||
#else
|
||||
config.device.disable_triple_click = true;
|
||||
#endif
|
||||
config.position.gps_enabled = true;
|
||||
#if !HAS_GPS || defined(T_DECK)
|
||||
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT;
|
||||
#elif !defined(GPS_RX_PIN)
|
||||
if (config.position.rx_gpio == 0)
|
||||
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT;
|
||||
else
|
||||
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_DISABLED;
|
||||
#else
|
||||
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED;
|
||||
#endif
|
||||
config.position.position_broadcast_smart_enabled = true;
|
||||
config.position.broadcast_smart_minimum_distance = 100;
|
||||
config.position.broadcast_smart_minimum_interval_secs = 30;
|
||||
if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER)
|
||||
config.device.node_info_broadcast_secs = 3 * 60 * 60;
|
||||
config.device.node_info_broadcast_secs = default_node_info_broadcast_secs;
|
||||
config.device.serial_enabled = true;
|
||||
resetRadioConfig();
|
||||
strncpy(config.network.ntp_server, "0.pool.ntp.org", 32);
|
||||
@@ -191,6 +275,12 @@ void NodeDB::installDefaultConfig()
|
||||
config.bluetooth.fixed_pin = defaultBLEPin;
|
||||
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
|
||||
bool hasScreen = true;
|
||||
#elif ARCH_PORTDUINO
|
||||
bool hasScreen = false;
|
||||
if (settingsMap[displayPanel])
|
||||
hasScreen = true;
|
||||
else
|
||||
hasScreen = screen_found.port != ScanI2C::I2CPort::NO_I2C;
|
||||
#else
|
||||
bool hasScreen = screen_found.port != ScanI2C::I2CPort::NO_I2C;
|
||||
#endif
|
||||
@@ -213,7 +303,6 @@ void NodeDB::installDefaultConfig()
|
||||
void NodeDB::initConfigIntervals()
|
||||
{
|
||||
config.position.gps_update_interval = default_gps_update_interval;
|
||||
config.position.gps_attempt_time = default_gps_attempt_time;
|
||||
config.position.position_broadcast_secs = default_broadcast_interval_secs;
|
||||
|
||||
config.power.ls_secs = default_ls_secs;
|
||||
@@ -222,6 +311,12 @@ void NodeDB::initConfigIntervals()
|
||||
config.power.wait_bluetooth_secs = default_wait_bluetooth_secs;
|
||||
|
||||
config.display.screen_on_secs = default_screen_on_secs;
|
||||
|
||||
#if defined(T_WATCH_S3) || defined(T_DECK)
|
||||
config.power.is_power_saving = true;
|
||||
config.display.screen_on_secs = 30;
|
||||
config.power.wait_bluetooth_secs = 30;
|
||||
#endif
|
||||
}
|
||||
|
||||
void NodeDB::installDefaultModuleConfig()
|
||||
@@ -245,9 +340,21 @@ void NodeDB::installDefaultModuleConfig()
|
||||
moduleConfig.external_notification.output_ms = 1000;
|
||||
moduleConfig.external_notification.nag_timeout = 60;
|
||||
#endif
|
||||
#ifdef T_WATCH_S3
|
||||
// Don't worry about the other settings, we'll use the DRV2056 behavior for notifications
|
||||
#ifdef HAS_I2S
|
||||
// Don't worry about the other settings for T-Watch, we'll also use the DRV2056 behavior for notifications
|
||||
moduleConfig.external_notification.enabled = true;
|
||||
moduleConfig.external_notification.use_i2s_as_buzzer = true;
|
||||
moduleConfig.external_notification.alert_message_buzzer = true;
|
||||
moduleConfig.external_notification.nag_timeout = 60;
|
||||
#endif
|
||||
#ifdef NANO_G2_ULTRA
|
||||
moduleConfig.external_notification.enabled = true;
|
||||
moduleConfig.external_notification.alert_message = true;
|
||||
moduleConfig.external_notification.output_ms = 100;
|
||||
moduleConfig.external_notification.active = true;
|
||||
#endif
|
||||
#ifdef TTGO_T_ECHO
|
||||
config.display.wake_on_tap_or_motion = true; // Enable touch button for screen-on / refresh
|
||||
#endif
|
||||
moduleConfig.has_canned_message = true;
|
||||
|
||||
@@ -282,11 +389,12 @@ void NodeDB::installRoleDefaults(meshtastic_Config_DeviceConfig_Role role)
|
||||
initModuleConfigIntervals();
|
||||
} else if (role == meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
||||
config.display.screen_on_secs = 1;
|
||||
} else if (role == meshtastic_Config_DeviceConfig_Role_TRACKER) {
|
||||
config.position.gps_update_interval = 30;
|
||||
} else if (role == meshtastic_Config_DeviceConfig_Role_SENSOR) {
|
||||
moduleConfig.telemetry.environment_measurement_enabled = true;
|
||||
moduleConfig.telemetry.environment_update_interval = 300;
|
||||
} else if (role == meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND) {
|
||||
config.position.position_broadcast_smart_enabled = false;
|
||||
config.position.position_broadcast_secs = 300; // Every 5 minutes
|
||||
} else if (role == meshtastic_Config_DeviceConfig_Role_TAK) {
|
||||
config.device.node_info_broadcast_secs = ONE_DAY;
|
||||
config.position.position_broadcast_smart_enabled = false;
|
||||
@@ -296,6 +404,26 @@ void NodeDB::installRoleDefaults(meshtastic_Config_DeviceConfig_Role role)
|
||||
(meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE | meshtastic_Config_PositionConfig_PositionFlags_SPEED |
|
||||
meshtastic_Config_PositionConfig_PositionFlags_HEADING | meshtastic_Config_PositionConfig_PositionFlags_DOP);
|
||||
moduleConfig.telemetry.device_update_interval = ONE_DAY;
|
||||
} else if (role == meshtastic_Config_DeviceConfig_Role_TAK_TRACKER) {
|
||||
config.device.node_info_broadcast_secs = ONE_DAY;
|
||||
config.position.position_broadcast_smart_enabled = true;
|
||||
config.position.position_broadcast_secs = 3 * 60; // Every 3 minutes
|
||||
config.position.broadcast_smart_minimum_distance = 20;
|
||||
config.position.broadcast_smart_minimum_interval_secs = 15;
|
||||
// Remove Altitude MSL from flags since CoTs use HAE (height above ellipsoid)
|
||||
config.position.position_flags =
|
||||
(meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE | meshtastic_Config_PositionConfig_PositionFlags_SPEED |
|
||||
meshtastic_Config_PositionConfig_PositionFlags_HEADING | meshtastic_Config_PositionConfig_PositionFlags_DOP);
|
||||
moduleConfig.telemetry.device_update_interval = ONE_DAY;
|
||||
} else if (role == meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN) {
|
||||
config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY;
|
||||
config.device.node_info_broadcast_secs = UINT32_MAX;
|
||||
config.position.position_broadcast_smart_enabled = false;
|
||||
config.position.position_broadcast_secs = UINT32_MAX;
|
||||
moduleConfig.neighbor_info.update_interval = UINT32_MAX;
|
||||
moduleConfig.telemetry.device_update_interval = UINT32_MAX;
|
||||
moduleConfig.telemetry.environment_update_interval = UINT32_MAX;
|
||||
moduleConfig.telemetry.air_quality_interval = UINT32_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,8 +444,9 @@ void NodeDB::installDefaultChannels()
|
||||
|
||||
void NodeDB::resetNodes()
|
||||
{
|
||||
devicestate.node_db_lite_count = 1;
|
||||
std::fill(&devicestate.node_db_lite[1], &devicestate.node_db_lite[MAX_NUM_NODES - 1], meshtastic_NodeInfoLite());
|
||||
numMeshNodes = 1;
|
||||
std::fill(devicestate.node_db_lite.begin() + 1, devicestate.node_db_lite.end(), meshtastic_NodeInfoLite());
|
||||
clearLocalPosition();
|
||||
saveDeviceStateToDisk();
|
||||
if (neighborInfoModule && moduleConfig.neighbor_info.enabled)
|
||||
neighborInfoModule->resetNeighbors();
|
||||
@@ -326,41 +455,56 @@ void NodeDB::resetNodes()
|
||||
void NodeDB::removeNodeByNum(uint nodeNum)
|
||||
{
|
||||
int newPos = 0, removed = 0;
|
||||
for (int i = 0; i < *numMeshNodes; i++) {
|
||||
if (meshNodes[i].num != nodeNum)
|
||||
meshNodes[newPos++] = meshNodes[i];
|
||||
for (int i = 0; i < numMeshNodes; i++) {
|
||||
if (meshNodes->at(i).num != nodeNum)
|
||||
meshNodes->at(newPos++) = meshNodes->at(i);
|
||||
else
|
||||
removed++;
|
||||
}
|
||||
*numMeshNodes -= removed;
|
||||
numMeshNodes -= removed;
|
||||
std::fill(devicestate.node_db_lite.begin() + numMeshNodes, devicestate.node_db_lite.begin() + numMeshNodes + 1,
|
||||
meshtastic_NodeInfoLite());
|
||||
LOG_DEBUG("NodeDB::removeNodeByNum purged %d entries. Saving changes...\n", removed);
|
||||
saveDeviceStateToDisk();
|
||||
}
|
||||
|
||||
void NodeDB::clearLocalPosition()
|
||||
{
|
||||
meshtastic_NodeInfoLite *node = getMeshNode(nodeDB->getNodeNum());
|
||||
node->position.latitude_i = 0;
|
||||
node->position.longitude_i = 0;
|
||||
node->position.altitude = 0;
|
||||
node->position.time = 0;
|
||||
setLocalPosition(meshtastic_Position_init_default);
|
||||
}
|
||||
|
||||
void NodeDB::cleanupMeshDB()
|
||||
{
|
||||
int newPos = 0, removed = 0;
|
||||
for (int i = 0; i < *numMeshNodes; i++) {
|
||||
if (meshNodes[i].has_user)
|
||||
meshNodes[newPos++] = meshNodes[i];
|
||||
for (int i = 0; i < numMeshNodes; i++) {
|
||||
if (meshNodes->at(i).has_user)
|
||||
meshNodes->at(newPos++) = meshNodes->at(i);
|
||||
else
|
||||
removed++;
|
||||
}
|
||||
*numMeshNodes -= removed;
|
||||
numMeshNodes -= removed;
|
||||
std::fill(devicestate.node_db_lite.begin() + numMeshNodes, devicestate.node_db_lite.begin() + numMeshNodes + removed,
|
||||
meshtastic_NodeInfoLite());
|
||||
LOG_DEBUG("cleanupMeshDB purged %d entries\n", removed);
|
||||
}
|
||||
|
||||
void NodeDB::installDefaultDeviceState()
|
||||
{
|
||||
LOG_INFO("Installing default DeviceState\n");
|
||||
memset(&devicestate, 0, sizeof(meshtastic_DeviceState));
|
||||
// memset(&devicestate, 0, sizeof(meshtastic_DeviceState));
|
||||
|
||||
*numMeshNodes = 0;
|
||||
numMeshNodes = 0;
|
||||
meshNodes = &devicestate.node_db_lite;
|
||||
|
||||
// init our devicestate with valid flags so protobuf writing/reading will work
|
||||
devicestate.has_my_node = true;
|
||||
devicestate.has_owner = true;
|
||||
devicestate.node_db_lite_count = 0;
|
||||
// devicestate.node_db_lite_count = 0;
|
||||
devicestate.version = DEVICESTATE_CUR_VER;
|
||||
devicestate.receive_queue_count = 0; // Not yet implemented FIXME
|
||||
|
||||
@@ -370,63 +514,10 @@ void NodeDB::installDefaultDeviceState()
|
||||
pickNewNodeNum(); // based on macaddr now
|
||||
snprintf(owner.long_name, sizeof(owner.long_name), "Meshtastic %02x%02x", ourMacAddr[4], ourMacAddr[5]);
|
||||
snprintf(owner.short_name, sizeof(owner.short_name), "%02x%02x", ourMacAddr[4], ourMacAddr[5]);
|
||||
|
||||
snprintf(owner.id, sizeof(owner.id), "!%08x", getNodeNum()); // Default node ID now based on nodenum
|
||||
memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr));
|
||||
}
|
||||
|
||||
void NodeDB::init()
|
||||
{
|
||||
LOG_INFO("Initializing NodeDB\n");
|
||||
loadFromDisk();
|
||||
cleanupMeshDB();
|
||||
|
||||
uint32_t devicestateCRC = crc32Buffer(&devicestate, sizeof(devicestate));
|
||||
uint32_t configCRC = crc32Buffer(&config, sizeof(config));
|
||||
uint32_t channelFileCRC = crc32Buffer(&channelFile, sizeof(channelFile));
|
||||
|
||||
int saveWhat = 0;
|
||||
|
||||
// likewise - we always want the app requirements to come from the running appload
|
||||
myNodeInfo.min_app_version = 30200; // format is Mmmss (where M is 1+the numeric major number. i.e. 30200 means 2.2.00
|
||||
// Note! We do this after loading saved settings, so that if somehow an invalid nodenum was stored in preferences we won't
|
||||
// keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts)
|
||||
pickNewNodeNum();
|
||||
|
||||
// Set our board type so we can share it with others
|
||||
owner.hw_model = HW_VENDOR;
|
||||
|
||||
// Include our owner in the node db under our nodenum
|
||||
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(getNodeNum());
|
||||
info->user = owner;
|
||||
info->has_user = true;
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
Preferences preferences;
|
||||
preferences.begin("meshtastic", false);
|
||||
myNodeInfo.reboot_count = preferences.getUInt("rebootCounter", 0);
|
||||
preferences.end();
|
||||
LOG_DEBUG("Number of Device Reboots: %d\n", myNodeInfo.reboot_count);
|
||||
#endif
|
||||
|
||||
resetRadioConfig(); // If bogus settings got saved, then fix them
|
||||
LOG_DEBUG("region=%d, NODENUM=0x%x, dbsize=%d\n", config.lora.region, myNodeInfo.my_node_num, *numMeshNodes);
|
||||
|
||||
if (devicestateCRC != crc32Buffer(&devicestate, sizeof(devicestate)))
|
||||
saveWhat |= SEGMENT_DEVICESTATE;
|
||||
if (configCRC != crc32Buffer(&config, sizeof(config)))
|
||||
saveWhat |= SEGMENT_CONFIG;
|
||||
if (channelFileCRC != crc32Buffer(&channelFile, sizeof(channelFile)))
|
||||
saveWhat |= SEGMENT_CHANNELS;
|
||||
|
||||
if (!devicestate.node_remote_hardware_pins) {
|
||||
meshtastic_NodeRemoteHardwarePin empty[12] = {meshtastic_RemoteHardwarePin_init_default};
|
||||
memcpy(devicestate.node_remote_hardware_pins, empty, sizeof(empty));
|
||||
}
|
||||
|
||||
saveToDisk(saveWhat);
|
||||
}
|
||||
|
||||
// We reserve a few nodenums for future use
|
||||
#define NUM_RESERVED 4
|
||||
|
||||
@@ -435,14 +526,12 @@ void NodeDB::init()
|
||||
*/
|
||||
void NodeDB::pickNewNodeNum()
|
||||
{
|
||||
#ifdef ARCH_RASPBERRY_PI
|
||||
getPiMacAddr(ourMacAddr); // Make sure ourMacAddr is set
|
||||
#else
|
||||
NodeNum nodeNum = myNodeInfo.my_node_num;
|
||||
getMacAddr(ourMacAddr); // Make sure ourMacAddr is set
|
||||
#endif
|
||||
|
||||
// Pick an initial nodenum based on the macaddr
|
||||
NodeNum nodeNum = (ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5];
|
||||
if (nodeNum == 0) {
|
||||
// Pick an initial nodenum based on the macaddr
|
||||
nodeNum = (ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5];
|
||||
}
|
||||
|
||||
meshtastic_NodeInfoLite *found;
|
||||
while ((nodeNum == NODENUM_BROADCAST || nodeNum < NUM_RESERVED) ||
|
||||
@@ -451,7 +540,7 @@ void NodeDB::pickNewNodeNum()
|
||||
LOG_WARN("NOTE! Our desired nodenum 0x%x is invalid or in use, so trying for 0x%x\n", nodeNum, candidate);
|
||||
nodeNum = candidate;
|
||||
}
|
||||
LOG_WARN("Using nodenum 0x%x \n", nodeNum);
|
||||
LOG_DEBUG("Using nodenum 0x%x \n", nodeNum);
|
||||
|
||||
myNodeInfo.my_node_num = nodeNum;
|
||||
}
|
||||
@@ -462,12 +551,17 @@ static const char *moduleConfigFileName = "/prefs/module.proto";
|
||||
static const char *channelFileName = "/prefs/channels.proto";
|
||||
static const char *oemConfigFile = "/oem/oem.proto";
|
||||
|
||||
/** Load a protobuf from a file, return true for success */
|
||||
bool NodeDB::loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct)
|
||||
/** Load a protobuf from a file, return LoadFileResult */
|
||||
LoadFileResult NodeDB::loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields,
|
||||
void *dest_struct)
|
||||
{
|
||||
bool okay = false;
|
||||
LoadFileResult state = LoadFileResult::OTHER_FAILURE;
|
||||
#ifdef FSCom
|
||||
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
|
||||
|
||||
if (!FSCom.exists(filename)) {
|
||||
LOG_INFO("File %s not found\n", filename);
|
||||
return LoadFileResult::NOT_FOUND;
|
||||
}
|
||||
|
||||
auto f = FSCom.open(filename, FILE_O_READ);
|
||||
|
||||
@@ -475,42 +569,49 @@ bool NodeDB::loadProto(const char *filename, size_t protoSize, size_t objSize, c
|
||||
LOG_INFO("Loading %s\n", filename);
|
||||
pb_istream_t stream = {&readcb, &f, protoSize};
|
||||
|
||||
// LOG_DEBUG("Preload channel name=%s\n", channelSettings.name);
|
||||
|
||||
memset(dest_struct, 0, objSize);
|
||||
if (!pb_decode(&stream, fields, dest_struct)) {
|
||||
LOG_ERROR("Error: can't decode protobuf %s\n", PB_GET_ERROR(&stream));
|
||||
state = LoadFileResult::DECODE_FAILED;
|
||||
} else {
|
||||
okay = true;
|
||||
LOG_INFO("Loaded %s successfully\n", filename);
|
||||
state = LoadFileResult::SUCCESS;
|
||||
}
|
||||
|
||||
f.close();
|
||||
} else {
|
||||
LOG_INFO("No %s preferences found\n", filename);
|
||||
LOG_ERROR("Could not open / read %s\n", filename);
|
||||
}
|
||||
#else
|
||||
LOG_ERROR("ERROR: Filesystem not implemented\n");
|
||||
state = LoadFileState::NO_FILESYSTEM;
|
||||
#endif
|
||||
return okay;
|
||||
return state;
|
||||
}
|
||||
|
||||
void NodeDB::loadFromDisk()
|
||||
{
|
||||
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
|
||||
if (!loadProto(prefFileName, meshtastic_DeviceState_size, sizeof(meshtastic_DeviceState), &meshtastic_DeviceState_msg,
|
||||
&devicestate)) {
|
||||
auto state = loadProto(prefFileName, sizeof(meshtastic_DeviceState) + MAX_NUM_NODES * sizeof(meshtastic_NodeInfo),
|
||||
sizeof(meshtastic_DeviceState), &meshtastic_DeviceState_msg, &devicestate);
|
||||
|
||||
if (state != LoadFileResult::SUCCESS) {
|
||||
installDefaultDeviceState(); // Our in RAM copy might now be corrupt
|
||||
} else {
|
||||
if (devicestate.version < DEVICESTATE_MIN_VER) {
|
||||
LOG_WARN("Devicestate %d is old, discarding\n", devicestate.version);
|
||||
factoryReset();
|
||||
} else {
|
||||
LOG_INFO("Loaded saved devicestate version %d\n", devicestate.version);
|
||||
LOG_INFO("Loaded saved devicestate version %d, with nodecount: %d\n", devicestate.version,
|
||||
devicestate.node_db_lite.size());
|
||||
meshNodes = &devicestate.node_db_lite;
|
||||
numMeshNodes = devicestate.node_db_lite.size();
|
||||
}
|
||||
}
|
||||
meshNodes->resize(MAX_NUM_NODES);
|
||||
|
||||
if (!loadProto(configFileName, meshtastic_LocalConfig_size, sizeof(meshtastic_LocalConfig), &meshtastic_LocalConfig_msg,
|
||||
&config)) {
|
||||
state = loadProto(configFileName, meshtastic_LocalConfig_size, sizeof(meshtastic_LocalConfig), &meshtastic_LocalConfig_msg,
|
||||
&config);
|
||||
if (state != LoadFileResult::SUCCESS) {
|
||||
installDefaultConfig(); // Our in RAM copy might now be corrupt
|
||||
} else {
|
||||
if (config.version < DEVICESTATE_MIN_VER) {
|
||||
@@ -521,8 +622,9 @@ void NodeDB::loadFromDisk()
|
||||
}
|
||||
}
|
||||
|
||||
if (!loadProto(moduleConfigFileName, meshtastic_LocalModuleConfig_size, sizeof(meshtastic_LocalModuleConfig),
|
||||
&meshtastic_LocalModuleConfig_msg, &moduleConfig)) {
|
||||
state = loadProto(moduleConfigFileName, meshtastic_LocalModuleConfig_size, sizeof(meshtastic_LocalModuleConfig),
|
||||
&meshtastic_LocalModuleConfig_msg, &moduleConfig);
|
||||
if (state != LoadFileResult::SUCCESS) {
|
||||
installDefaultModuleConfig(); // Our in RAM copy might now be corrupt
|
||||
} else {
|
||||
if (moduleConfig.version < DEVICESTATE_MIN_VER) {
|
||||
@@ -533,8 +635,9 @@ void NodeDB::loadFromDisk()
|
||||
}
|
||||
}
|
||||
|
||||
if (!loadProto(channelFileName, meshtastic_ChannelFile_size, sizeof(meshtastic_ChannelFile), &meshtastic_ChannelFile_msg,
|
||||
&channelFile)) {
|
||||
state = loadProto(channelFileName, meshtastic_ChannelFile_size, sizeof(meshtastic_ChannelFile), &meshtastic_ChannelFile_msg,
|
||||
&channelFile);
|
||||
if (state != LoadFileResult::SUCCESS) {
|
||||
installDefaultChannels(); // Our in RAM copy might now be corrupt
|
||||
} else {
|
||||
if (channelFile.version < DEVICESTATE_MIN_VER) {
|
||||
@@ -545,7 +648,8 @@ void NodeDB::loadFromDisk()
|
||||
}
|
||||
}
|
||||
|
||||
if (loadProto(oemConfigFile, meshtastic_OEMStore_size, sizeof(meshtastic_OEMStore), &meshtastic_OEMStore_msg, &oemStore)) {
|
||||
state = loadProto(oemConfigFile, meshtastic_OEMStore_size, sizeof(meshtastic_OEMStore), &meshtastic_OEMStore_msg, &oemStore);
|
||||
if (state == LoadFileResult::SUCCESS) {
|
||||
LOG_INFO("Loaded OEMStore\n");
|
||||
}
|
||||
}
|
||||
@@ -584,9 +688,13 @@ bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_
|
||||
static uint8_t failedCounter = 0;
|
||||
failedCounter++;
|
||||
if (failedCounter >= 2) {
|
||||
FSCom.format();
|
||||
// After formatting, the device needs to be restarted
|
||||
nodeDB.resetRadioConfig(true);
|
||||
LOG_ERROR("Failed to save file twice. Rebooting...\n");
|
||||
delay(100);
|
||||
NVIC_SystemReset();
|
||||
// We used to blow away the filesystem here, but that's a bit extreme
|
||||
// FSCom.format();
|
||||
// // After formatting, the device needs to be restarted
|
||||
// nodeDB->resetRadioConfig(true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -598,68 +706,68 @@ bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_
|
||||
|
||||
void NodeDB::saveChannelsToDisk()
|
||||
{
|
||||
if (!devicestate.no_save) {
|
||||
#ifdef FSCom
|
||||
FSCom.mkdir("/prefs");
|
||||
FSCom.mkdir("/prefs");
|
||||
#endif
|
||||
saveProto(channelFileName, meshtastic_ChannelFile_size, &meshtastic_ChannelFile_msg, &channelFile);
|
||||
}
|
||||
saveProto(channelFileName, meshtastic_ChannelFile_size, &meshtastic_ChannelFile_msg, &channelFile);
|
||||
}
|
||||
|
||||
void NodeDB::saveDeviceStateToDisk()
|
||||
{
|
||||
if (!devicestate.no_save) {
|
||||
#ifdef FSCom
|
||||
FSCom.mkdir("/prefs");
|
||||
FSCom.mkdir("/prefs");
|
||||
#endif
|
||||
saveProto(prefFileName, meshtastic_DeviceState_size, &meshtastic_DeviceState_msg, &devicestate);
|
||||
}
|
||||
saveProto(prefFileName, sizeof(devicestate) + numMeshNodes * meshtastic_NodeInfoLite_size, &meshtastic_DeviceState_msg,
|
||||
&devicestate);
|
||||
}
|
||||
|
||||
void NodeDB::saveToDisk(int saveWhat)
|
||||
{
|
||||
if (!devicestate.no_save) {
|
||||
#ifdef FSCom
|
||||
FSCom.mkdir("/prefs");
|
||||
FSCom.mkdir("/prefs");
|
||||
#endif
|
||||
if (saveWhat & SEGMENT_DEVICESTATE) {
|
||||
saveDeviceStateToDisk();
|
||||
}
|
||||
if (saveWhat & SEGMENT_DEVICESTATE) {
|
||||
saveDeviceStateToDisk();
|
||||
}
|
||||
|
||||
if (saveWhat & SEGMENT_CONFIG) {
|
||||
config.has_device = true;
|
||||
config.has_display = true;
|
||||
config.has_lora = true;
|
||||
config.has_position = true;
|
||||
config.has_power = true;
|
||||
config.has_network = true;
|
||||
config.has_bluetooth = true;
|
||||
saveProto(configFileName, meshtastic_LocalConfig_size, &meshtastic_LocalConfig_msg, &config);
|
||||
}
|
||||
if (saveWhat & SEGMENT_CONFIG) {
|
||||
config.has_device = true;
|
||||
config.has_display = true;
|
||||
config.has_lora = true;
|
||||
config.has_position = true;
|
||||
config.has_power = true;
|
||||
config.has_network = true;
|
||||
config.has_bluetooth = true;
|
||||
|
||||
if (saveWhat & SEGMENT_MODULECONFIG) {
|
||||
moduleConfig.has_canned_message = true;
|
||||
moduleConfig.has_external_notification = true;
|
||||
moduleConfig.has_mqtt = true;
|
||||
moduleConfig.has_range_test = true;
|
||||
moduleConfig.has_serial = true;
|
||||
moduleConfig.has_store_forward = true;
|
||||
moduleConfig.has_telemetry = true;
|
||||
saveProto(moduleConfigFileName, meshtastic_LocalModuleConfig_size, &meshtastic_LocalModuleConfig_msg, &moduleConfig);
|
||||
}
|
||||
saveProto(configFileName, meshtastic_LocalConfig_size, &meshtastic_LocalConfig_msg, &config);
|
||||
}
|
||||
|
||||
if (saveWhat & SEGMENT_CHANNELS) {
|
||||
saveChannelsToDisk();
|
||||
}
|
||||
} else {
|
||||
LOG_DEBUG("***** DEVELOPMENT MODE - DO NOT RELEASE - not saving to flash *****\n");
|
||||
if (saveWhat & SEGMENT_MODULECONFIG) {
|
||||
moduleConfig.has_canned_message = true;
|
||||
moduleConfig.has_external_notification = true;
|
||||
moduleConfig.has_mqtt = true;
|
||||
moduleConfig.has_range_test = true;
|
||||
moduleConfig.has_serial = true;
|
||||
moduleConfig.has_store_forward = true;
|
||||
moduleConfig.has_telemetry = true;
|
||||
moduleConfig.has_neighbor_info = true;
|
||||
moduleConfig.has_detection_sensor = true;
|
||||
moduleConfig.has_ambient_lighting = true;
|
||||
moduleConfig.has_audio = true;
|
||||
moduleConfig.has_paxcounter = true;
|
||||
|
||||
saveProto(moduleConfigFileName, meshtastic_LocalModuleConfig_size, &meshtastic_LocalModuleConfig_msg, &moduleConfig);
|
||||
}
|
||||
|
||||
if (saveWhat & SEGMENT_CHANNELS) {
|
||||
saveChannelsToDisk();
|
||||
}
|
||||
}
|
||||
|
||||
const meshtastic_NodeInfoLite *NodeDB::readNextMeshNode(uint32_t &readIndex)
|
||||
{
|
||||
if (readIndex < *numMeshNodes)
|
||||
return &meshNodes[readIndex++];
|
||||
if (readIndex < numMeshNodes)
|
||||
return &meshNodes->at(readIndex++);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
@@ -689,19 +797,23 @@ uint32_t sinceReceived(const meshtastic_MeshPacket *p)
|
||||
|
||||
#define NUM_ONLINE_SECS (60 * 60 * 2) // 2 hrs to consider someone offline
|
||||
|
||||
size_t NodeDB::getNumOnlineMeshNodes()
|
||||
size_t NodeDB::getNumOnlineMeshNodes(bool localOnly)
|
||||
{
|
||||
size_t numseen = 0;
|
||||
|
||||
// FIXME this implementation is kinda expensive
|
||||
for (int i = 0; i < *numMeshNodes; i++)
|
||||
if (sinceLastSeen(&meshNodes[i]) < NUM_ONLINE_SECS)
|
||||
for (int i = 0; i < numMeshNodes; i++) {
|
||||
if (localOnly && meshNodes->at(i).via_mqtt)
|
||||
continue;
|
||||
if (sinceLastSeen(&meshNodes->at(i)) < NUM_ONLINE_SECS)
|
||||
numseen++;
|
||||
}
|
||||
|
||||
return numseen;
|
||||
}
|
||||
|
||||
#include "MeshModule.h"
|
||||
#include "Throttle.h"
|
||||
|
||||
/** Update position info for this node based on received position data
|
||||
*/
|
||||
@@ -770,22 +882,25 @@ void NodeDB::updateTelemetry(uint32_t nodeId, const meshtastic_Telemetry &t, RxS
|
||||
notifyObservers(true); // Force an update whether or not our node counts have changed
|
||||
}
|
||||
|
||||
/** Update user info for this node based on received user data
|
||||
/** Update user info and channel for this node based on received user data
|
||||
*/
|
||||
bool NodeDB::updateUser(uint32_t nodeId, const meshtastic_User &p)
|
||||
bool NodeDB::updateUser(uint32_t nodeId, const meshtastic_User &p, uint8_t channelIndex)
|
||||
{
|
||||
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(nodeId);
|
||||
if (!info) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_DEBUG("old user %s/%s/%s\n", info->user.id, info->user.long_name, info->user.short_name);
|
||||
LOG_DEBUG("old user %s/%s/%s, channel=%d\n", info->user.id, info->user.long_name, info->user.short_name, info->channel);
|
||||
|
||||
bool changed = memcmp(&info->user, &p,
|
||||
sizeof(info->user)); // Both of these blocks start as filled with zero so I think this is okay
|
||||
// Both of info->user and p start as filled with zero so I think this is okay
|
||||
bool changed = memcmp(&info->user, &p, sizeof(info->user)) || (info->channel != channelIndex);
|
||||
|
||||
info->user = p;
|
||||
LOG_DEBUG("updating changed=%d user %s/%s/%s\n", changed, info->user.id, info->user.long_name, info->user.short_name);
|
||||
if (nodeId != getNodeNum())
|
||||
info->channel = channelIndex; // Set channel we need to use to reach this node (but don't set our own channel)
|
||||
LOG_DEBUG("updating changed=%d user %s/%s/%s, channel=%d\n", changed, info->user.id, info->user.long_name,
|
||||
info->user.short_name, info->channel);
|
||||
info->has_user = true;
|
||||
|
||||
if (changed) {
|
||||
@@ -793,8 +908,10 @@ bool NodeDB::updateUser(uint32_t nodeId, const meshtastic_User &p)
|
||||
powerFSM.trigger(EVENT_NODEDB_UPDATED);
|
||||
notifyObservers(true); // Force an update whether or not our node counts have changed
|
||||
|
||||
// We just changed something important about the user, store our DB
|
||||
saveToDisk(SEGMENT_DEVICESTATE);
|
||||
// We just changed something about the user, store our DB
|
||||
Throttle::execute(
|
||||
&lastNodeDbSave, ONE_MINUTE_MS, []() { nodeDB->saveToDisk(SEGMENT_DEVICESTATE); },
|
||||
[]() { LOG_DEBUG("Deferring NodeDB saveToDisk for now, since we saved less than a minute ago\n"); });
|
||||
}
|
||||
|
||||
return changed;
|
||||
@@ -805,7 +922,7 @@ bool NodeDB::updateUser(uint32_t nodeId, const meshtastic_User &p)
|
||||
void NodeDB::updateFrom(const meshtastic_MeshPacket &mp)
|
||||
{
|
||||
if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag && mp.from) {
|
||||
LOG_DEBUG("Update DB node 0x%x, rx_time=%u, channel=%d\n", mp.from, mp.rx_time, mp.channel);
|
||||
LOG_DEBUG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time);
|
||||
|
||||
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(getFrom(&mp));
|
||||
if (!info) {
|
||||
@@ -818,16 +935,16 @@ void NodeDB::updateFrom(const meshtastic_MeshPacket &mp)
|
||||
if (mp.rx_snr)
|
||||
info->snr = mp.rx_snr; // keep the most recent SNR we received for this node.
|
||||
|
||||
if (mp.decoded.portnum == meshtastic_PortNum_NODEINFO_APP) {
|
||||
info->channel = mp.channel;
|
||||
}
|
||||
info->via_mqtt = mp.via_mqtt; // Store if we received this packet via MQTT
|
||||
|
||||
// If this packet didn't travel any hops, then it was sent directly to us, so we know what to use as next hop to this node
|
||||
if (mp.original_hop_limit == mp.hop_limit) {
|
||||
info->next_hop = getLastByteOfNodeNum(mp.from);
|
||||
} else if (mp.relay_node && (mp.original_hop_limit - mp.hop_limit == 1)) {
|
||||
// This packet traveled one hop, so we can use the relay_node as next_hop
|
||||
info->next_hop = getLastByteOfNodeNum(mp.relay_node);
|
||||
// If hopStart was set and there wasn't someone messing with the limit in the middle, add hopsAway
|
||||
if (mp.hop_start != 0 && mp.hop_limit <= mp.hop_start) {
|
||||
info->hops_away = mp.hop_start - mp.hop_limit;
|
||||
if (info->hops_away == 0) {
|
||||
info->next_hop = getLastByteOfNodeNum(mp.from);
|
||||
} else if (info->hops_away == 1) {
|
||||
info->next_hop = getLastByteOfNodeNum(mp.relay_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -845,9 +962,9 @@ uint8_t NodeDB::getMeshNodeChannel(NodeNum n)
|
||||
/// NOTE: This function might be called from an ISR
|
||||
meshtastic_NodeInfoLite *NodeDB::getMeshNode(NodeNum n)
|
||||
{
|
||||
for (int i = 0; i < *numMeshNodes; i++)
|
||||
if (meshNodes[i].num == n)
|
||||
return &meshNodes[i];
|
||||
for (int i = 0; i < numMeshNodes; i++)
|
||||
if (meshNodes->at(i).num == n)
|
||||
return &meshNodes->at(i);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -858,26 +975,27 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n)
|
||||
meshtastic_NodeInfoLite *lite = getMeshNode(n);
|
||||
|
||||
if (!lite) {
|
||||
if ((*numMeshNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < meshtastic_NodeInfoLite_size * 3)) {
|
||||
if ((numMeshNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < meshtastic_NodeInfoLite_size * 3)) {
|
||||
if (screen)
|
||||
screen->print("warning: node_db_lite full! erasing oldest entry\n");
|
||||
screen->print("Warn: node database full!\nErasing oldest entry\n");
|
||||
LOG_WARN("Node database full! Erasing oldest entry\n");
|
||||
// look for oldest node and erase it
|
||||
uint32_t oldest = UINT32_MAX;
|
||||
int oldestIndex = -1;
|
||||
for (int i = 0; i < *numMeshNodes; i++) {
|
||||
if (meshNodes[i].last_heard < oldest) {
|
||||
oldest = meshNodes[i].last_heard;
|
||||
for (int i = 1; i < numMeshNodes; i++) {
|
||||
if (!meshNodes->at(i).is_favorite && meshNodes->at(i).last_heard < oldest) {
|
||||
oldest = meshNodes->at(i).last_heard;
|
||||
oldestIndex = i;
|
||||
}
|
||||
}
|
||||
// Shove the remaining nodes down the chain
|
||||
for (int i = oldestIndex; i < *numMeshNodes - 1; i++) {
|
||||
meshNodes[i] = meshNodes[i + 1];
|
||||
for (int i = oldestIndex; i < numMeshNodes - 1; i++) {
|
||||
meshNodes->at(i) = meshNodes->at(i + 1);
|
||||
}
|
||||
(*numMeshNodes)--;
|
||||
(numMeshNodes)--;
|
||||
}
|
||||
// add the node at the end
|
||||
lite = &meshNodes[(*numMeshNodes)++];
|
||||
lite = &meshNodes->at((numMeshNodes)++);
|
||||
|
||||
// everything is missing except the nodenum
|
||||
memset(lite, 0, sizeof(*lite));
|
||||
|
||||
Reference in New Issue
Block a user