mirror of
https://github.com/meshtastic/firmware.git
synced 2025-09-05 19:19:18 +00:00
Compare commits
2 Commits
7e063c1dda
...
143cdf4572
Author | SHA1 | Date | |
---|---|---|---|
![]() |
143cdf4572 | ||
![]() |
d440dbd522 |
@ -37,6 +37,7 @@ build_flags =
|
|||||||
-DLIBPAX_ARDUINO
|
-DLIBPAX_ARDUINO
|
||||||
-DLIBPAX_WIFI
|
-DLIBPAX_WIFI
|
||||||
-DLIBPAX_BLE
|
-DLIBPAX_BLE
|
||||||
|
-DHAS_UDP_MULTICAST=1
|
||||||
;-DDEBUG_HEAP
|
;-DDEBUG_HEAP
|
||||||
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
|
@ -17,7 +17,7 @@ build_flags =
|
|||||||
-DLFS_NO_ASSERT ; Disable LFS assertions , see https://github.com/meshtastic/firmware/pull/3818
|
-DLFS_NO_ASSERT ; Disable LFS assertions , see https://github.com/meshtastic/firmware/pull/3818
|
||||||
-DMESHTASTIC_EXCLUDE_AUDIO=1
|
-DMESHTASTIC_EXCLUDE_AUDIO=1
|
||||||
-DMESHTASTIC_EXCLUDE_PAXCOUNTER=1
|
-DMESHTASTIC_EXCLUDE_PAXCOUNTER=1
|
||||||
-DMAX_NUM_NODES=80
|
-DMAX_NUM_NODES=70
|
||||||
|
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/wifi/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2xx0> -<mesh/eth/> -<mesh/raspihttp>
|
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/wifi/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2xx0> -<mesh/eth/> -<mesh/raspihttp>
|
||||||
|
12
src/main.cpp
12
src/main.cpp
@ -114,6 +114,11 @@ AccelerometerThread *accelerometerThread = nullptr;
|
|||||||
AudioThread *audioThread = nullptr;
|
AudioThread *audioThread = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAS_UDP_MULTICAST
|
||||||
|
#include "mesh/udp/UdpMulticastThread.h"
|
||||||
|
UdpMulticastThread *udpThread = nullptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(TCXO_OPTIONAL)
|
#if defined(TCXO_OPTIONAL)
|
||||||
float tcxoVoltage = SX126X_DIO3_TCXO_VOLTAGE; // if TCXO is optional, put this here so it can be changed further down.
|
float tcxoVoltage = SX126X_DIO3_TCXO_VOLTAGE; // if TCXO is optional, put this here so it can be changed further down.
|
||||||
#endif
|
#endif
|
||||||
@ -783,6 +788,11 @@ void setup()
|
|||||||
LOG_DEBUG("Start audio thread");
|
LOG_DEBUG("Start audio thread");
|
||||||
audioThread = new AudioThread();
|
audioThread = new AudioThread();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAS_UDP_MULTICAST
|
||||||
|
LOG_DEBUG("Start multicast thread");
|
||||||
|
udpThread = new UdpMulticastThread();
|
||||||
|
#endif
|
||||||
service = new MeshService();
|
service = new MeshService();
|
||||||
service->init();
|
service->init();
|
||||||
|
|
||||||
@ -1278,4 +1288,4 @@ void loop()
|
|||||||
mainDelay.delay(delayMsec);
|
mainDelay.delay(delayMsec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
@ -49,6 +49,11 @@ extern Adafruit_DRV2605 drv;
|
|||||||
extern AudioThread *audioThread;
|
extern AudioThread *audioThread;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAS_UDP_MULTICAST
|
||||||
|
#include "mesh/udp/UdpMulticastThread.h"
|
||||||
|
extern UdpMulticastThread *udpThread;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Global Screen singleton.
|
// Global Screen singleton.
|
||||||
extern graphics::Screen *screen;
|
extern graphics::Screen *screen;
|
||||||
|
|
||||||
|
@ -57,6 +57,7 @@ NodeDB *nodeDB = nullptr;
|
|||||||
// we have plenty of ram so statically alloc this tempbuf (for now)
|
// we have plenty of ram so statically alloc this tempbuf (for now)
|
||||||
EXT_RAM_BSS_ATTR meshtastic_DeviceState devicestate;
|
EXT_RAM_BSS_ATTR meshtastic_DeviceState devicestate;
|
||||||
meshtastic_MyNodeInfo &myNodeInfo = devicestate.my_node;
|
meshtastic_MyNodeInfo &myNodeInfo = devicestate.my_node;
|
||||||
|
meshtastic_NodeDatabase nodeDatabase;
|
||||||
meshtastic_LocalConfig config;
|
meshtastic_LocalConfig config;
|
||||||
meshtastic_DeviceUIConfig uiconfig{.screen_brightness = 153, .screen_timeout = 30};
|
meshtastic_DeviceUIConfig uiconfig{.screen_brightness = 153, .screen_timeout = 30};
|
||||||
meshtastic_LocalModuleConfig moduleConfig;
|
meshtastic_LocalModuleConfig moduleConfig;
|
||||||
@ -144,7 +145,7 @@ uint32_t get_st7789_id(uint8_t cs, uint8_t sck, uint8_t mosi, uint8_t dc, uint8_
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool meshtastic_DeviceState_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field)
|
bool meshtastic_NodeDatabase_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field)
|
||||||
{
|
{
|
||||||
if (ostream) {
|
if (ostream) {
|
||||||
std::vector<meshtastic_NodeInfoLite> const *vec = (std::vector<meshtastic_NodeInfoLite> *)field->pData;
|
std::vector<meshtastic_NodeInfoLite> const *vec = (std::vector<meshtastic_NodeInfoLite> *)field->pData;
|
||||||
@ -193,6 +194,7 @@ NodeDB::NodeDB()
|
|||||||
cleanupMeshDB();
|
cleanupMeshDB();
|
||||||
|
|
||||||
uint32_t devicestateCRC = crc32Buffer(&devicestate, sizeof(devicestate));
|
uint32_t devicestateCRC = crc32Buffer(&devicestate, sizeof(devicestate));
|
||||||
|
uint32_t nodeDatabaseCRC = crc32Buffer(&nodeDatabase, sizeof(nodeDatabase));
|
||||||
uint32_t configCRC = crc32Buffer(&config, sizeof(config));
|
uint32_t configCRC = crc32Buffer(&config, sizeof(config));
|
||||||
uint32_t channelFileCRC = crc32Buffer(&channelFile, sizeof(channelFile));
|
uint32_t channelFileCRC = crc32Buffer(&channelFile, sizeof(channelFile));
|
||||||
|
|
||||||
@ -249,15 +251,15 @@ NodeDB::NodeDB()
|
|||||||
// Ensure macaddr is set to our macaddr as it will be copied in our info below
|
// Ensure macaddr is set to our macaddr as it will be copied in our info below
|
||||||
memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr));
|
memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr));
|
||||||
|
|
||||||
// Include our owner in the node db under our nodenum
|
|
||||||
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(getNodeNum());
|
|
||||||
if (!config.has_security) {
|
if (!config.has_security) {
|
||||||
config.has_security = true;
|
config.has_security = true;
|
||||||
|
config.security = meshtastic_Config_SecurityConfig_init_default;
|
||||||
config.security.serial_enabled = config.device.serial_enabled;
|
config.security.serial_enabled = config.device.serial_enabled;
|
||||||
config.security.is_managed = config.device.is_managed;
|
config.security.is_managed = config.device.is_managed;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !(MESHTASTIC_EXCLUDE_PKI_KEYGEN || MESHTASTIC_EXCLUDE_PKI)
|
#if !(MESHTASTIC_EXCLUDE_PKI_KEYGEN || MESHTASTIC_EXCLUDE_PKI)
|
||||||
|
|
||||||
if (!owner.is_licensed) {
|
if (!owner.is_licensed) {
|
||||||
bool keygenSuccess = false;
|
bool keygenSuccess = false;
|
||||||
if (config.security.private_key.size == 32) {
|
if (config.security.private_key.size == 32) {
|
||||||
@ -284,7 +286,8 @@ NodeDB::NodeDB()
|
|||||||
crypto->setDHPrivateKey(config.security.private_key.bytes);
|
crypto->setDHPrivateKey(config.security.private_key.bytes);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
// Include our owner in the node db under our nodenum
|
||||||
|
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(getNodeNum());
|
||||||
info->user = TypeConversions::ConvertToUserLite(owner);
|
info->user = TypeConversions::ConvertToUserLite(owner);
|
||||||
info->has_user = true;
|
info->has_user = true;
|
||||||
|
|
||||||
@ -299,6 +302,9 @@ NodeDB::NodeDB()
|
|||||||
resetRadioConfig(); // If bogus settings got saved, then fix them
|
resetRadioConfig(); // If bogus settings got saved, then fix them
|
||||||
// nodeDB->LOG_DEBUG("region=%d, NODENUM=0x%x, dbsize=%d", config.lora.region, myNodeInfo.my_node_num, numMeshNodes);
|
// nodeDB->LOG_DEBUG("region=%d, NODENUM=0x%x, dbsize=%d", config.lora.region, myNodeInfo.my_node_num, numMeshNodes);
|
||||||
|
|
||||||
|
// Uncomment below to always enable UDP broadcasts
|
||||||
|
// config.network.enabled_protocols = meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST;
|
||||||
|
|
||||||
// If we are setup to broadcast on the default channel, ensure that the telemetry intervals are coerced to the minimum value
|
// If we are setup to broadcast on the default channel, ensure that the telemetry intervals are coerced to the minimum value
|
||||||
// of 30 minutes or more
|
// of 30 minutes or more
|
||||||
if (channels.isDefaultChannel(channels.getPrimaryIndex())) {
|
if (channels.isDefaultChannel(channels.getPrimaryIndex())) {
|
||||||
@ -318,8 +324,12 @@ NodeDB::NodeDB()
|
|||||||
moduleConfig.neighbor_info.update_interval =
|
moduleConfig.neighbor_info.update_interval =
|
||||||
Default::getConfiguredOrMinimumValue(moduleConfig.neighbor_info.update_interval, min_neighbor_info_broadcast_secs);
|
Default::getConfiguredOrMinimumValue(moduleConfig.neighbor_info.update_interval, min_neighbor_info_broadcast_secs);
|
||||||
|
|
||||||
|
LOG_DEBUG("nodeDatabaseCRC: %u, crc32Buffer(&nodeDatabase, sizeof(nodeDatabase): %u", nodeDatabaseCRC,
|
||||||
|
crc32Buffer(&nodeDatabase, sizeof(nodeDatabase)));
|
||||||
if (devicestateCRC != crc32Buffer(&devicestate, sizeof(devicestate)))
|
if (devicestateCRC != crc32Buffer(&devicestate, sizeof(devicestate)))
|
||||||
saveWhat |= SEGMENT_DEVICESTATE;
|
saveWhat |= SEGMENT_DEVICESTATE;
|
||||||
|
if (nodeDatabaseCRC != crc32Buffer(&nodeDatabase, sizeof(nodeDatabase)))
|
||||||
|
saveWhat |= SEGMENT_NODEDATABASE;
|
||||||
if (configCRC != crc32Buffer(&config, sizeof(config)))
|
if (configCRC != crc32Buffer(&config, sizeof(config)))
|
||||||
saveWhat |= SEGMENT_CONFIG;
|
saveWhat |= SEGMENT_CONFIG;
|
||||||
if (channelFileCRC != crc32Buffer(&channelFile, sizeof(channelFile)))
|
if (channelFileCRC != crc32Buffer(&channelFile, sizeof(channelFile)))
|
||||||
@ -434,6 +444,7 @@ bool NodeDB::factoryReset(bool eraseBleBonds)
|
|||||||
#endif
|
#endif
|
||||||
spiLock->unlock();
|
spiLock->unlock();
|
||||||
// second, install default state (this will deal with the duplicate mac address issue)
|
// second, install default state (this will deal with the duplicate mac address issue)
|
||||||
|
installDefaultNodeDatabase();
|
||||||
installDefaultDeviceState();
|
installDefaultDeviceState();
|
||||||
installDefaultConfig(!eraseBleBonds); // Also preserve the private key if we're not erasing BLE bonds
|
installDefaultConfig(!eraseBleBonds); // Also preserve the private key if we're not erasing BLE bonds
|
||||||
installDefaultModuleConfig();
|
installDefaultModuleConfig();
|
||||||
@ -458,6 +469,15 @@ bool NodeDB::factoryReset(bool eraseBleBonds)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NodeDB::installDefaultNodeDatabase()
|
||||||
|
{
|
||||||
|
LOG_DEBUG("Install default NodeDatabase");
|
||||||
|
nodeDatabase.version = DEVICESTATE_CUR_VER;
|
||||||
|
nodeDatabase.nodes = std::vector<meshtastic_NodeInfoLite>(MAX_NUM_NODES);
|
||||||
|
numMeshNodes = 0;
|
||||||
|
meshNodes = &nodeDatabase.nodes;
|
||||||
|
}
|
||||||
|
|
||||||
void NodeDB::installDefaultConfig(bool preserveKey = false)
|
void NodeDB::installDefaultConfig(bool preserveKey = false)
|
||||||
{
|
{
|
||||||
uint8_t private_key_temp[32];
|
uint8_t private_key_temp[32];
|
||||||
@ -785,9 +805,10 @@ void NodeDB::resetNodes()
|
|||||||
if (!config.position.fixed_position)
|
if (!config.position.fixed_position)
|
||||||
clearLocalPosition();
|
clearLocalPosition();
|
||||||
numMeshNodes = 1;
|
numMeshNodes = 1;
|
||||||
std::fill(devicestate.node_db_lite.begin() + 1, devicestate.node_db_lite.end(), meshtastic_NodeInfoLite());
|
std::fill(nodeDatabase.nodes.begin() + 1, nodeDatabase.nodes.end(), meshtastic_NodeInfoLite());
|
||||||
devicestate.has_rx_text_message = false;
|
devicestate.has_rx_text_message = false;
|
||||||
devicestate.has_rx_waypoint = false;
|
devicestate.has_rx_waypoint = false;
|
||||||
|
saveNodeDatabaseToDisk();
|
||||||
saveDeviceStateToDisk();
|
saveDeviceStateToDisk();
|
||||||
if (neighborInfoModule && moduleConfig.neighbor_info.enabled)
|
if (neighborInfoModule && moduleConfig.neighbor_info.enabled)
|
||||||
neighborInfoModule->resetNeighbors();
|
neighborInfoModule->resetNeighbors();
|
||||||
@ -803,10 +824,10 @@ void NodeDB::removeNodeByNum(NodeNum nodeNum)
|
|||||||
removed++;
|
removed++;
|
||||||
}
|
}
|
||||||
numMeshNodes -= removed;
|
numMeshNodes -= removed;
|
||||||
std::fill(devicestate.node_db_lite.begin() + numMeshNodes, devicestate.node_db_lite.begin() + numMeshNodes + 1,
|
std::fill(nodeDatabase.nodes.begin() + numMeshNodes, nodeDatabase.nodes.begin() + numMeshNodes + 1,
|
||||||
meshtastic_NodeInfoLite());
|
meshtastic_NodeInfoLite());
|
||||||
LOG_DEBUG("NodeDB::removeNodeByNum purged %d entries. Save changes", removed);
|
LOG_DEBUG("NodeDB::removeNodeByNum purged %d entries. Save changes", removed);
|
||||||
saveDeviceStateToDisk();
|
saveNodeDatabaseToDisk();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeDB::clearLocalPosition()
|
void NodeDB::clearLocalPosition()
|
||||||
@ -835,7 +856,7 @@ void NodeDB::cleanupMeshDB()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
numMeshNodes -= removed;
|
numMeshNodes -= removed;
|
||||||
std::fill(devicestate.node_db_lite.begin() + numMeshNodes, devicestate.node_db_lite.begin() + numMeshNodes + removed,
|
std::fill(nodeDatabase.nodes.begin() + numMeshNodes, nodeDatabase.nodes.begin() + numMeshNodes + removed,
|
||||||
meshtastic_NodeInfoLite());
|
meshtastic_NodeInfoLite());
|
||||||
LOG_DEBUG("cleanupMeshDB purged %d entries", removed);
|
LOG_DEBUG("cleanupMeshDB purged %d entries", removed);
|
||||||
}
|
}
|
||||||
@ -845,13 +866,9 @@ void NodeDB::installDefaultDeviceState()
|
|||||||
LOG_INFO("Install default DeviceState");
|
LOG_INFO("Install default DeviceState");
|
||||||
// memset(&devicestate, 0, sizeof(meshtastic_DeviceState));
|
// memset(&devicestate, 0, sizeof(meshtastic_DeviceState));
|
||||||
|
|
||||||
numMeshNodes = 0;
|
|
||||||
meshNodes = &devicestate.node_db_lite;
|
|
||||||
|
|
||||||
// init our devicestate with valid flags so protobuf writing/reading will work
|
// init our devicestate with valid flags so protobuf writing/reading will work
|
||||||
devicestate.has_my_node = true;
|
devicestate.has_my_node = true;
|
||||||
devicestate.has_owner = true;
|
devicestate.has_owner = true;
|
||||||
// devicestate.node_db_lite_count = 0;
|
|
||||||
devicestate.version = DEVICESTATE_CUR_VER;
|
devicestate.version = DEVICESTATE_CUR_VER;
|
||||||
devicestate.receive_queue_count = 0; // Not yet implemented FIXME
|
devicestate.receive_queue_count = 0; // Not yet implemented FIXME
|
||||||
devicestate.has_rx_waypoint = false;
|
devicestate.has_rx_waypoint = false;
|
||||||
@ -905,7 +922,9 @@ void NodeDB::pickNewNodeNum()
|
|||||||
myNodeInfo.my_node_num = nodeNum;
|
myNodeInfo.my_node_num = nodeNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *prefFileName = "/prefs/db.proto";
|
static const char *deviceStateFileName = "/prefs/device.proto";
|
||||||
|
static const char *legacyPrefFileName = "/prefs/db.proto";
|
||||||
|
static const char *nodeDatabaseFileName = "/prefs/nodes.proto";
|
||||||
static const char *configFileName = "/prefs/config.proto";
|
static const char *configFileName = "/prefs/config.proto";
|
||||||
static const char *uiconfigFileName = "/prefs/uiconfig.proto";
|
static const char *uiconfigFileName = "/prefs/uiconfig.proto";
|
||||||
static const char *moduleConfigFileName = "/prefs/module.proto";
|
static const char *moduleConfigFileName = "/prefs/module.proto";
|
||||||
@ -946,20 +965,41 @@ LoadFileResult NodeDB::loadProto(const char *filename, size_t protoSize, size_t
|
|||||||
|
|
||||||
void NodeDB::loadFromDisk()
|
void NodeDB::loadFromDisk()
|
||||||
{
|
{
|
||||||
devicestate.version =
|
// Mark the current device state as completely unusable, so that if we fail reading the entire file from
|
||||||
0; // Mark the current device state as completely unusable, so that if we fail reading the entire file from
|
|
||||||
// disk we will still factoryReset to restore things.
|
// disk we will still factoryReset to restore things.
|
||||||
|
devicestate.version = 0;
|
||||||
|
|
||||||
#ifdef ARCH_ESP32
|
#ifdef ARCH_ESP32
|
||||||
spiLock->lock();
|
spiLock->lock();
|
||||||
|
// If the legacy deviceState exists, start over with a factory reset
|
||||||
|
if (FSCom.exists(legacyPrefFileName)) {
|
||||||
|
rmDir("/prefs");
|
||||||
|
}
|
||||||
if (FSCom.exists("/static/static"))
|
if (FSCom.exists("/static/static"))
|
||||||
rmDir("/static/static"); // Remove bad static web files bundle from initial 2.5.13 release
|
rmDir("/static/static"); // Remove bad static web files bundle from initial 2.5.13 release
|
||||||
spiLock->unlock();
|
spiLock->unlock();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
auto state = loadProto(nodeDatabaseFileName, getMaxNodesAllocatedSize(), sizeof(meshtastic_NodeDatabase),
|
||||||
|
&meshtastic_NodeDatabase_msg, &nodeDatabase);
|
||||||
|
if (nodeDatabase.version < DEVICESTATE_MIN_VER) {
|
||||||
|
LOG_WARN("NodeDatabase %d is old, discard", nodeDatabase.version);
|
||||||
|
installDefaultNodeDatabase();
|
||||||
|
} else {
|
||||||
|
meshNodes = &nodeDatabase.nodes;
|
||||||
|
numMeshNodes = nodeDatabase.nodes.size();
|
||||||
|
LOG_INFO("Loaded saved nodedatabase version %d, with nodes count: %d", nodeDatabase.version, nodeDatabase.nodes.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numMeshNodes > MAX_NUM_NODES) {
|
||||||
|
LOG_WARN("Node count %d exceeds MAX_NUM_NODES %d, truncating", numMeshNodes, MAX_NUM_NODES);
|
||||||
|
numMeshNodes = MAX_NUM_NODES;
|
||||||
|
}
|
||||||
|
meshNodes->resize(MAX_NUM_NODES);
|
||||||
|
|
||||||
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
|
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
|
||||||
auto state = loadProto(prefFileName, sizeof(meshtastic_DeviceState) + MAX_NUM_NODES_FS * sizeof(meshtastic_NodeInfo),
|
state = loadProto(deviceStateFileName, meshtastic_DeviceState_size, sizeof(meshtastic_DeviceState),
|
||||||
sizeof(meshtastic_DeviceState), &meshtastic_DeviceState_msg, &devicestate);
|
&meshtastic_DeviceState_msg, &devicestate);
|
||||||
|
|
||||||
// See https://github.com/meshtastic/firmware/issues/4184#issuecomment-2269390786
|
// See https://github.com/meshtastic/firmware/issues/4184#issuecomment-2269390786
|
||||||
// It is very important to try and use the saved prefs even if we fail to read meshtastic_DeviceState. Because most of our
|
// It is very important to try and use the saved prefs even if we fail to read meshtastic_DeviceState. Because most of our
|
||||||
@ -973,15 +1013,8 @@ void NodeDB::loadFromDisk()
|
|||||||
LOG_WARN("Devicestate %d is old, discard", devicestate.version);
|
LOG_WARN("Devicestate %d is old, discard", devicestate.version);
|
||||||
installDefaultDeviceState();
|
installDefaultDeviceState();
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO("Loaded saved devicestate version %d, with nodecount: %d", devicestate.version, devicestate.node_db_lite.size());
|
LOG_INFO("Loaded saved devicestate version %d", devicestate.version);
|
||||||
meshNodes = &devicestate.node_db_lite;
|
|
||||||
numMeshNodes = devicestate.node_db_lite.size();
|
|
||||||
}
|
}
|
||||||
if (numMeshNodes > MAX_NUM_NODES) {
|
|
||||||
LOG_WARN("Node count %d exceeds MAX_NUM_NODES %d, truncating", numMeshNodes, MAX_NUM_NODES);
|
|
||||||
numMeshNodes = MAX_NUM_NODES;
|
|
||||||
}
|
|
||||||
meshNodes->resize(MAX_NUM_NODES);
|
|
||||||
|
|
||||||
state = loadProto(configFileName, meshtastic_LocalConfig_size, sizeof(meshtastic_LocalConfig), &meshtastic_LocalConfig_msg,
|
state = loadProto(configFileName, meshtastic_LocalConfig_size, sizeof(meshtastic_LocalConfig), &meshtastic_LocalConfig_msg,
|
||||||
&config);
|
&config);
|
||||||
@ -1147,14 +1180,24 @@ bool NodeDB::saveDeviceStateToDisk()
|
|||||||
#endif
|
#endif
|
||||||
// Note: if MAX_NUM_NODES=100 and meshtastic_NodeInfoLite_size=166, so will be approximately 17KB
|
// Note: if MAX_NUM_NODES=100 and meshtastic_NodeInfoLite_size=166, so will be approximately 17KB
|
||||||
// Because so huge we _must_ not use fullAtomic, because the filesystem is probably too small to hold two copies of this
|
// Because so huge we _must_ not use fullAtomic, because the filesystem is probably too small to hold two copies of this
|
||||||
return saveProto(prefFileName, sizeof(devicestate) + numMeshNodes * meshtastic_NodeInfoLite_size, &meshtastic_DeviceState_msg,
|
return saveProto(deviceStateFileName, meshtastic_DeviceState_size, &meshtastic_DeviceState_msg, &devicestate, true);
|
||||||
&devicestate, false);
|
}
|
||||||
|
|
||||||
|
bool NodeDB::saveNodeDatabaseToDisk()
|
||||||
|
{
|
||||||
|
#ifdef FSCom
|
||||||
|
spiLock->lock();
|
||||||
|
FSCom.mkdir("/prefs");
|
||||||
|
spiLock->unlock();
|
||||||
|
#endif
|
||||||
|
size_t nodeDatabaseSize;
|
||||||
|
pb_get_encoded_size(&nodeDatabaseSize, meshtastic_NodeDatabase_fields, &nodeDatabase);
|
||||||
|
return saveProto(nodeDatabaseFileName, nodeDatabaseSize, &meshtastic_NodeDatabase_msg, &nodeDatabase, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NodeDB::saveToDiskNoRetry(int saveWhat)
|
bool NodeDB::saveToDiskNoRetry(int saveWhat)
|
||||||
{
|
{
|
||||||
bool success = true;
|
bool success = true;
|
||||||
|
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
spiLock->lock();
|
spiLock->lock();
|
||||||
FSCom.mkdir("/prefs");
|
FSCom.mkdir("/prefs");
|
||||||
@ -1199,11 +1242,16 @@ bool NodeDB::saveToDiskNoRetry(int saveWhat)
|
|||||||
success &= saveDeviceStateToDisk();
|
success &= saveDeviceStateToDisk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (saveWhat & SEGMENT_NODEDATABASE) {
|
||||||
|
success &= saveNodeDatabaseToDisk();
|
||||||
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NodeDB::saveToDisk(int saveWhat)
|
bool NodeDB::saveToDisk(int saveWhat)
|
||||||
{
|
{
|
||||||
|
LOG_DEBUG("Save to disk %d", saveWhat);
|
||||||
bool success = saveToDiskNoRetry(saveWhat);
|
bool success = saveToDiskNoRetry(saveWhat);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@ -1385,7 +1433,7 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde
|
|||||||
// We just changed something about a User,
|
// We just changed something about a User,
|
||||||
// store our DB unless we just did so less than a minute ago
|
// store our DB unless we just did so less than a minute ago
|
||||||
if (!Throttle::isWithinTimespanMs(lastNodeDbSave, ONE_MINUTE_MS)) {
|
if (!Throttle::isWithinTimespanMs(lastNodeDbSave, ONE_MINUTE_MS)) {
|
||||||
saveToDisk(SEGMENT_DEVICESTATE);
|
saveToDisk(SEGMENT_NODEDATABASE);
|
||||||
lastNodeDbSave = millis();
|
lastNodeDbSave = millis();
|
||||||
} else {
|
} else {
|
||||||
LOG_DEBUG("Defer NodeDB saveToDisk for now");
|
LOG_DEBUG("Defer NodeDB saveToDisk for now");
|
||||||
@ -1399,6 +1447,10 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde
|
|||||||
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
|
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
|
||||||
void NodeDB::updateFrom(const meshtastic_MeshPacket &mp)
|
void NodeDB::updateFrom(const meshtastic_MeshPacket &mp)
|
||||||
{
|
{
|
||||||
|
// if (mp.from == getNodeNum()) {
|
||||||
|
// LOG_DEBUG("Ignore update from self");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag && mp.from) {
|
if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag && mp.from) {
|
||||||
LOG_DEBUG("Update DB node 0x%x, rx_time=%u", mp.from, mp.rx_time);
|
LOG_DEBUG("Update DB node 0x%x, rx_time=%u", mp.from, mp.rx_time);
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <pb_encode.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "MeshTypes.h"
|
#include "MeshTypes.h"
|
||||||
@ -21,11 +22,13 @@ DeviceState versions used to be defined in the .proto file but really only this
|
|||||||
#define SEGMENT_MODULECONFIG 2
|
#define SEGMENT_MODULECONFIG 2
|
||||||
#define SEGMENT_DEVICESTATE 4
|
#define SEGMENT_DEVICESTATE 4
|
||||||
#define SEGMENT_CHANNELS 8
|
#define SEGMENT_CHANNELS 8
|
||||||
|
#define SEGMENT_NODEDATABASE 16
|
||||||
|
|
||||||
#define DEVICESTATE_CUR_VER 23
|
#define DEVICESTATE_CUR_VER 24
|
||||||
#define DEVICESTATE_MIN_VER 22
|
#define DEVICESTATE_MIN_VER 24
|
||||||
|
|
||||||
extern meshtastic_DeviceState devicestate;
|
extern meshtastic_DeviceState devicestate;
|
||||||
|
extern meshtastic_NodeDatabase nodeDatabase;
|
||||||
extern meshtastic_ChannelFile channelFile;
|
extern meshtastic_ChannelFile channelFile;
|
||||||
extern meshtastic_MyNodeInfo &myNodeInfo;
|
extern meshtastic_MyNodeInfo &myNodeInfo;
|
||||||
extern meshtastic_LocalConfig config;
|
extern meshtastic_LocalConfig config;
|
||||||
@ -75,7 +78,8 @@ class NodeDB
|
|||||||
|
|
||||||
/// write to flash
|
/// write to flash
|
||||||
/// @return true if the save was successful
|
/// @return true if the save was successful
|
||||||
bool saveToDisk(int saveWhat = SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS);
|
bool saveToDisk(int saveWhat = SEGMENT_CONFIG | SEGMENT_MODULECONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS |
|
||||||
|
SEGMENT_NODEDATABASE);
|
||||||
|
|
||||||
/** Reinit radio config if needed, because either:
|
/** Reinit radio config if needed, because either:
|
||||||
* a) sometimes a buggy android app might send us bogus settings or
|
* a) sometimes a buggy android app might send us bogus settings or
|
||||||
@ -148,6 +152,15 @@ class NodeDB
|
|||||||
virtual meshtastic_NodeInfoLite *getMeshNode(NodeNum n);
|
virtual meshtastic_NodeInfoLite *getMeshNode(NodeNum n);
|
||||||
size_t getNumMeshNodes() { return numMeshNodes; }
|
size_t getNumMeshNodes() { return numMeshNodes; }
|
||||||
|
|
||||||
|
size_t getMaxNodesAllocatedSize()
|
||||||
|
{
|
||||||
|
meshtastic_NodeDatabase emptyNodeDatabase;
|
||||||
|
emptyNodeDatabase.version = DEVICESTATE_CUR_VER;
|
||||||
|
size_t nodeDatabaseSize;
|
||||||
|
pb_get_encoded_size(&nodeDatabaseSize, meshtastic_NodeDatabase_fields, &emptyNodeDatabase);
|
||||||
|
return nodeDatabaseSize + (MAX_NUM_NODES * meshtastic_NodeInfoLite_size);
|
||||||
|
}
|
||||||
|
|
||||||
// returns true if the maximum number of nodes is reached or we are running low on memory
|
// returns true if the maximum number of nodes is reached or we are running low on memory
|
||||||
bool isFull();
|
bool isFull();
|
||||||
|
|
||||||
@ -188,8 +201,8 @@ class NodeDB
|
|||||||
void cleanupMeshDB();
|
void cleanupMeshDB();
|
||||||
|
|
||||||
/// Reinit device state from scratch (not loading from disk)
|
/// Reinit device state from scratch (not loading from disk)
|
||||||
void installDefaultDeviceState(), installDefaultChannels(), installDefaultConfig(bool preserveKey),
|
void installDefaultDeviceState(), installDefaultNodeDatabase(), installDefaultChannels(),
|
||||||
installDefaultModuleConfig();
|
installDefaultConfig(bool preserveKey), installDefaultModuleConfig();
|
||||||
|
|
||||||
/// write to flash
|
/// write to flash
|
||||||
/// @return true if the save was successful
|
/// @return true if the save was successful
|
||||||
@ -197,6 +210,7 @@ class NodeDB
|
|||||||
|
|
||||||
bool saveChannelsToDisk();
|
bool saveChannelsToDisk();
|
||||||
bool saveDeviceStateToDisk();
|
bool saveDeviceStateToDisk();
|
||||||
|
bool saveNodeDatabaseToDisk();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern NodeDB *nodeDB;
|
extern NodeDB *nodeDB;
|
||||||
|
@ -274,6 +274,11 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
|
|||||||
abortSendAndNak(encodeResult, p);
|
abortSendAndNak(encodeResult, p);
|
||||||
return encodeResult; // FIXME - this isn't a valid ErrorCode
|
return encodeResult; // FIXME - this isn't a valid ErrorCode
|
||||||
}
|
}
|
||||||
|
#if HAS_UDP_MULTICAST
|
||||||
|
if (udpThread && config.network.enabled_protocols & meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST) {
|
||||||
|
udpThread->onSend(const_cast<meshtastic_MeshPacket *>(p));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_MQTT
|
#if !MESHTASTIC_EXCLUDE_MQTT
|
||||||
// Only publish to MQTT if we're the original transmitter of the packet
|
// Only publish to MQTT if we're the original transmitter of the packet
|
||||||
if (moduleConfig.mqtt.enabled && isFromUs(p) && mqtt) {
|
if (moduleConfig.mqtt.enabled && isFromUs(p) && mqtt) {
|
||||||
|
@ -23,8 +23,6 @@
|
|||||||
#define MAX_NUM_NODES 100
|
#define MAX_NUM_NODES 100
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAX_NUM_NODES_FS 100
|
|
||||||
|
|
||||||
/// Max number of channels allowed
|
/// Max number of channels allowed
|
||||||
#define MAX_NUM_CHANNELS (member_size(meshtastic_ChannelFile, channels) / member_size(meshtastic_ChannelFile, channels[0]))
|
#define MAX_NUM_CHANNELS (member_size(meshtastic_ChannelFile, channels) / member_size(meshtastic_ChannelFile, channels[0]))
|
||||||
|
|
||||||
|
70
src/mesh/udp/UdpMulticastThread.h
Normal file
70
src/mesh/udp/UdpMulticastThread.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#pragma once
|
||||||
|
#if HAS_UDP_MULTICAST
|
||||||
|
#include "configuration.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "mesh/Router.h"
|
||||||
|
|
||||||
|
#include <AsyncUDP.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
|
||||||
|
#define UDP_MULTICAST_DEFAUL_PORT 4403 // Default port for UDP multicast is same as TCP api server
|
||||||
|
#define UDP_MULTICAST_THREAD_INTERVAL_MS 15000
|
||||||
|
|
||||||
|
class UdpMulticastThread : public concurrency::OSThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UdpMulticastThread() : OSThread("UdpMulticast") { udpIpAddress = IPAddress(224, 0, 0, 69); }
|
||||||
|
|
||||||
|
void start()
|
||||||
|
{
|
||||||
|
if (udp.listenMulticast(udpIpAddress, UDP_MULTICAST_DEFAUL_PORT)) {
|
||||||
|
LOG_DEBUG("UDP Listening on IP: %s", WiFi.localIP().toString().c_str());
|
||||||
|
udp.onPacket([this](AsyncUDPPacket packet) { onReceive(packet); });
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG("Failed to listen on UDP");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onReceive(AsyncUDPPacket packet)
|
||||||
|
{
|
||||||
|
size_t packetLength = packet.length();
|
||||||
|
LOG_DEBUG("UDP broadcast from: %s, len=%u", packet.remoteIP().toString().c_str(), packetLength);
|
||||||
|
meshtastic_MeshPacket mp;
|
||||||
|
uint8_t bytes[meshtastic_MeshPacket_size]; // Allocate buffer for the data
|
||||||
|
size_t packetSize = packet.readBytes(bytes, packet.length());
|
||||||
|
LOG_DEBUG("Decoding MeshPacket from UDP len=%u", packetSize);
|
||||||
|
bool isPacketDecoded = pb_decode_from_bytes(bytes, packetLength, &meshtastic_MeshPacket_msg, &mp);
|
||||||
|
if (isPacketDecoded && router) {
|
||||||
|
UniquePacketPoolPacket p = packetPool.allocUniqueCopy(mp);
|
||||||
|
// Unset received SNR/RSSI
|
||||||
|
p->rx_snr = 0;
|
||||||
|
p->rx_rssi = 0;
|
||||||
|
router->enqueueReceivedMessage(p.release());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool onSend(const meshtastic_MeshPacket *mp)
|
||||||
|
{
|
||||||
|
if (!mp || WiFi.status() != WL_CONNECTED) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LOG_DEBUG("Broadcasting packet over UDP (id=%u)", mp->id);
|
||||||
|
uint8_t buffer[meshtastic_MeshPacket_size];
|
||||||
|
size_t encodedLength = pb_encode_to_bytes(buffer, sizeof(buffer), &meshtastic_MeshPacket_msg, mp);
|
||||||
|
udp.broadcastTo(buffer, encodedLength, UDP_MULTICAST_DEFAUL_PORT);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int32_t runOnce() override
|
||||||
|
{
|
||||||
|
canSleep = true;
|
||||||
|
// TODO: Implement nodeinfo broadcast
|
||||||
|
return UDP_MULTICAST_THREAD_INTERVAL_MS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
IPAddress udpIpAddress;
|
||||||
|
AsyncUDP udp;
|
||||||
|
};
|
||||||
|
#endif // ARCH_ESP32
|
@ -112,6 +112,12 @@ static void onNetworkConnected()
|
|||||||
APStartupComplete = true;
|
APStartupComplete = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if HAS_UDP_MULTICAST
|
||||||
|
if (udpThread) {
|
||||||
|
udpThread->start();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// FIXME this is kinda yucky, instead we should just have an observable for 'wifireconnected'
|
// FIXME this is kinda yucky, instead we should just have an observable for 'wifireconnected'
|
||||||
#ifndef MESHTASTIC_EXCLUDE_MQTT
|
#ifndef MESHTASTIC_EXCLUDE_MQTT
|
||||||
if (mqtt)
|
if (mqtt)
|
||||||
@ -437,4 +443,4 @@ uint8_t getWifiDisconnectReason()
|
|||||||
{
|
{
|
||||||
return wifiDisconnectReason;
|
return wifiDisconnectReason;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
Loading…
Reference in New Issue
Block a user