mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-09-01 20:09:17 +00:00
sync to vanilla 1.16
This commit is contained in:
@@ -394,6 +394,14 @@ project(zephcore)
|
||||
string(TIMESTAMP ZEPHCORE_BUILD_DATE "%Y %b %d" UTC)
|
||||
add_definitions(-DFIRMWARE_BUILD_DATE="${ZEPHCORE_BUILD_DATE}")
|
||||
|
||||
# Single source of truth for the firmware version string (vMAJOR.MINOR.PATCH-zephyr).
|
||||
# Injected globally like FIRMWARE_BUILD_DATE above, so every app TU sees the same
|
||||
# value; the per-app `#ifndef FIRMWARE_VERSION` fallbacks only apply to builds that
|
||||
# bypass this injection. NOTE: the BLE DIS value in boards/common/zephcore_common.conf
|
||||
# (CONFIG_BT_DIS_FW_REV_STR) is Kconfig, not C, so it must be bumped here AND there.
|
||||
set(ZEPHCORE_FIRMWARE_VERSION "v1.16.0-zephyr")
|
||||
add_definitions(-DFIRMWARE_VERSION="${ZEPHCORE_FIRMWARE_VERSION}")
|
||||
|
||||
add_subdirectory(lib/monocypher)
|
||||
target_link_libraries(app PRIVATE monocypher)
|
||||
|
||||
|
||||
@@ -187,6 +187,7 @@ All `set uplink.*` changes are saved immediately and only applied after reboot.
|
||||
| `get backoff.multiplier` | Per-dupe reactive backoff multiplier |
|
||||
| `get flood.max` | Max flood retransmit hops |
|
||||
| `get flood.max.unscoped` | Max retransmit hops for un-scoped floods |
|
||||
| `get flood.max.advert` | Max retransmit hops for ADVERT floods |
|
||||
| `get flood.advert.interval` | Flood advertisement interval in hours |
|
||||
| `get advert.interval` | Local advertisement interval in minutes |
|
||||
| `get apc.margin` | Adaptive Power Control target RSSI margin in dB |
|
||||
@@ -229,6 +230,7 @@ Changes are persisted immediately unless noted. Some require a reboot.
|
||||
| `set backoff.multiplier <m>` | 0.0–2.0 | Per-dupe reactive backoff multiplier (0 = disable reactive backoff) |
|
||||
| `set flood.max <count>` | 0–64 | Maximum flood retransmit hops |
|
||||
| `set flood.max.unscoped <count>` | 0–64 | Hop limit for un-scoped floods only (default 64 = same as flood.max); scoped/transport floods still use flood.max |
|
||||
| `set flood.max.advert <count>` | 0–64 | Hop limit for ADVERT floods only (default 8); curbs advert churn independent of flood.max |
|
||||
| `set flood.advert.interval <hours>` | 3–168 | How often the repeater floods its own advertisement |
|
||||
| `set advert.interval <mins>` | min–240 | How often the repeater sends local advertisements |
|
||||
| `set apc.margin <db>` | 6–30 | Target RSSI margin for Adaptive Power Control |
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include "ZephyrDataStore.h"
|
||||
#include <AdvertDataHelpers.h> // ADV_TYPE_NONE (transient/anon contacts)
|
||||
#include <zephyr/fs/fs.h>
|
||||
#include <zephyr/fs/littlefs.h>
|
||||
#include <zephyr/storage/flash_map.h>
|
||||
@@ -702,18 +703,25 @@ void ZephyrDataStore::saveContacts(DataStoreHost *host)
|
||||
|
||||
struct fs_file_t file;
|
||||
uint8_t rec[CONTACT_DATA_SZ];
|
||||
uint32_t idx = 0;
|
||||
uint32_t idx = 0; // contacts iterated (incl. skipped anon)
|
||||
uint32_t written = 0; // records actually written to the file
|
||||
ContactInfo c;
|
||||
bool write_ok = true;
|
||||
|
||||
auto write_contacts = [&](struct fs_file_t *dst) -> bool {
|
||||
while (host->getContactForSave(idx, c)) {
|
||||
// Don't persist transient/anon contacts (non-contact requests)
|
||||
if (c.type == ADV_TYPE_NONE) {
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
contact_to_record(c, rec);
|
||||
if (fs_write(dst, rec, CONTACT_DATA_SZ) != (ssize_t)CONTACT_DATA_SZ) {
|
||||
LOG_ERR("saveContacts: write failed at record %u", idx);
|
||||
return false;
|
||||
}
|
||||
idx++;
|
||||
written++;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
@@ -749,7 +757,7 @@ void ZephyrDataStore::saveContacts(DataStoreHost *host)
|
||||
return;
|
||||
}
|
||||
LOG_INF("saveContacts: mode=%s saved %u contacts to %s (%u bytes)",
|
||||
save_mode, idx, path, idx * CONTACT_DATA_SZ);
|
||||
save_mode, written, path, written * CONTACT_DATA_SZ);
|
||||
}
|
||||
|
||||
/* ── Channels ──────────────────────────────────────────────────────── */
|
||||
|
||||
@@ -552,8 +552,9 @@ bool CompanionMesh::continueContactIteration()
|
||||
if (_contact_iter_idx < getNumContacts()) {
|
||||
ContactInfo c;
|
||||
if (getContactByIdx(_contact_iter_idx, c)) {
|
||||
// Skip transient/anon contacts (ADV_TYPE_NONE) — never synced to the app.
|
||||
// Apply 'since' filter - only send contacts modified after the timestamp
|
||||
if (c.lastmod > _contact_iter_since) {
|
||||
if (c.type != ADV_TYPE_NONE && c.lastmod > _contact_iter_since) {
|
||||
if (c.lastmod > _contact_iter_lastmod) {
|
||||
_contact_iter_lastmod = c.lastmod;
|
||||
}
|
||||
@@ -2226,6 +2227,9 @@ bool CompanionMesh::handleProtocolFrame(const uint8_t *data, size_t len)
|
||||
#ifndef FIRMWARE_BUILD_DATE
|
||||
#define FIRMWARE_BUILD_DATE __DATE__
|
||||
#endif
|
||||
#ifndef FIRMWARE_VERSION
|
||||
#define FIRMWARE_VERSION "v0.0.0-dev" // real value injected by CMakeLists.txt
|
||||
#endif
|
||||
/* Wire format reserves 40 bytes for the board name. Require room
|
||||
* for a null terminator within those 40 bytes so a phone parsing
|
||||
* it as a C-string never reads past the field. */
|
||||
@@ -2233,10 +2237,10 @@ bool CompanionMesh::handleProtocolFrame(const uint8_t *data, size_t len)
|
||||
"CONFIG_ZEPHCORE_BOARD_NAME must fit in 40 bytes including null terminator");
|
||||
static const uint8_t fw_build[12] = FIRMWARE_BUILD_DATE;
|
||||
static const uint8_t model[40] = CONFIG_ZEPHCORE_BOARD_NAME;
|
||||
static const uint8_t version[20] = "v1.15.9-zephyr";
|
||||
static const uint8_t version[20] = FIRMWARE_VERSION; // injected by CMakeLists.txt
|
||||
uint8_t rsp[82];
|
||||
rsp[0] = PACKET_DEVICE_INFO;
|
||||
rsp[1] = 12; // FIRMWARE_VER_CODE - v12 = CMD_SET_FLOOD_SCOPE_KEY [0x36, 0x01] unscoped variant
|
||||
rsp[1] = 13; // FIRMWARE_VER_CODE - v13 = CMD_SEND_ANON_REQ to non-contact pubkey (transient anon contacts)
|
||||
rsp[2] = (MAX_CONTACTS / 2 > 255) ? 255 : (MAX_CONTACTS / 2); // protocol byte, app multiplies by 2
|
||||
rsp[3] = MAX_GROUP_CHANNELS;
|
||||
put_le32(&rsp[4], prefs.ble_pin ? prefs.ble_pin : 123456); // BLE PIN
|
||||
@@ -2952,6 +2956,19 @@ bool CompanionMesh::handleProtocolFrame(const uint8_t *data, size_t len)
|
||||
case CMD_SEND_ANON_REQ:
|
||||
if (len >= 1 + PUB_KEY_SIZE + 1) {
|
||||
ContactInfo *contact = lookupContactByPubKey(&data[1], PUB_KEY_SIZE);
|
||||
if (contact == nullptr) {
|
||||
/* FIRMWARE_VER_CODE 13+: allow requests to a non-contact pubkey by
|
||||
* creating a transient "anon" contact (ADV_TYPE_NONE). These are never
|
||||
* persisted or synced to the app; re-lookup to get the stable slot. */
|
||||
ContactInfo anon;
|
||||
memset(&anon, 0, sizeof(anon));
|
||||
memcpy(anon.id.pub_key, &data[1], PUB_KEY_SIZE);
|
||||
anon.out_path_len = 0; // zero-hop direct by default
|
||||
anon.type = ADV_TYPE_NONE; // transient/unknown
|
||||
if (addContact(anon)) {
|
||||
contact = lookupContactByPubKey(&data[1], PUB_KEY_SIZE);
|
||||
}
|
||||
}
|
||||
if (contact) {
|
||||
uint32_t tag, est_timeout;
|
||||
int result = sendAnonReq(*contact, &data[1 + PUB_KEY_SIZE], len - 1 - PUB_KEY_SIZE, tag, est_timeout);
|
||||
@@ -2963,7 +2980,7 @@ bool CompanionMesh::handleProtocolFrame(const uint8_t *data, size_t len)
|
||||
sendPacketError(ERR_BAD_STATE);
|
||||
}
|
||||
} else {
|
||||
sendPacketError(ERR_NOT_FOUND);
|
||||
sendPacketError(ERR_TABLE_FULL);
|
||||
}
|
||||
} else {
|
||||
sendPacketError(ERR_ILLEGAL_ARG);
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
#include "observer_creds.h"
|
||||
|
||||
#ifndef FIRMWARE_VERSION
|
||||
#define FIRMWARE_VERSION "v1.15.9-zephyr"
|
||||
// Real version injected by CMakeLists.txt (-DFIRMWARE_VERSION); this fallback
|
||||
// only applies to builds that bypass that injection and should never surface.
|
||||
#define FIRMWARE_VERSION "v0.0.0-dev"
|
||||
#endif
|
||||
|
||||
#ifndef FIRMWARE_BUILD_DATE
|
||||
|
||||
@@ -195,6 +195,10 @@ bool RepeaterDataStore::loadPrefs(NodePrefs& prefs) {
|
||||
fs_read(&file, &prefs.rx_duty_cycle, sizeof(prefs.rx_duty_cycle));
|
||||
fs_read(&file, &prefs.apc_enabled, sizeof(prefs.apc_enabled));
|
||||
fs_read(&file, &prefs.apc_margin, sizeof(prefs.apc_margin));
|
||||
/* Flood hop-ceiling extensions (absent in <296-byte files; the no-op EOF
|
||||
* read leaves the constructor defaults flood_max_unscoped=64, flood_max_advert=8). */
|
||||
fs_read(&file, &prefs.flood_max_unscoped, sizeof(prefs.flood_max_unscoped));
|
||||
fs_read(&file, &prefs.flood_max_advert, sizeof(prefs.flood_max_advert));
|
||||
|
||||
fs_close(&file);
|
||||
|
||||
@@ -234,7 +238,7 @@ bool RepeaterDataStore::loadPrefs(NodePrefs& prefs) {
|
||||
prefs.path_hash_mode = 1;
|
||||
prefs.loop_detect = LOOP_DETECT_MODERATE;
|
||||
savePrefs(prefs);
|
||||
LOG_INF("loadPrefs: upgraded prefs format (%d -> 294 bytes)", (int)entry.size);
|
||||
LOG_INF("loadPrefs: upgraded prefs format (%d -> 296 bytes)", (int)entry.size);
|
||||
}
|
||||
|
||||
/* One-time migration: disable RX duty cycle if it was previously enabled. */
|
||||
@@ -313,6 +317,9 @@ bool RepeaterDataStore::savePrefs(const NodePrefs& prefs) {
|
||||
fs_write(&file, &prefs.rx_duty_cycle, sizeof(prefs.rx_duty_cycle));
|
||||
fs_write(&file, &prefs.apc_enabled, sizeof(prefs.apc_enabled));
|
||||
fs_write(&file, &prefs.apc_margin, sizeof(prefs.apc_margin));
|
||||
/* Flood hop-ceiling extensions (extend the format past 294 bytes) */
|
||||
fs_write(&file, &prefs.flood_max_unscoped, sizeof(prefs.flood_max_unscoped));
|
||||
fs_write(&file, &prefs.flood_max_advert, sizeof(prefs.flood_max_advert));
|
||||
|
||||
ret = fs_sync(&file);
|
||||
fs_close(&file);
|
||||
|
||||
@@ -532,6 +532,8 @@ bool RepeaterMesh::allowPacketForward(const mesh::Packet* packet) {
|
||||
if (packet->getPathHashCount() >= _prefs.flood_max) return false;
|
||||
// un-scoped floods can be clamped to a lower hop limit than scoped (transport) floods
|
||||
if (packet->getRouteType() == ROUTE_TYPE_FLOOD && packet->getPathHashCount() >= _prefs.flood_max_unscoped) return false;
|
||||
// ADVERT floods get their own (typically tighter) hop ceiling to curb advert churn
|
||||
if (packet->getPayloadType() == PAYLOAD_TYPE_ADVERT && packet->getPathHashCount() >= _prefs.flood_max_advert) return false;
|
||||
}
|
||||
if (packet->isRouteFlood() && recv_pkt_region == nullptr) return false;
|
||||
if (packet->isRouteFlood() && _prefs.loop_detect != LOOP_DETECT_OFF) {
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
#endif
|
||||
|
||||
#ifndef FIRMWARE_VERSION
|
||||
#define FIRMWARE_VERSION "v1.15.9-zephyr"
|
||||
// Real version injected by CMakeLists.txt (-DFIRMWARE_VERSION); this fallback
|
||||
// only applies to builds that bypass that injection and should never surface.
|
||||
#define FIRMWARE_VERSION "v0.0.0-dev"
|
||||
#endif
|
||||
|
||||
#ifndef FIRMWARE_BUILD_DATE
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
#include "RepeaterDataStore.h"
|
||||
|
||||
#ifndef FIRMWARE_VERSION
|
||||
#define FIRMWARE_VERSION "v1.15.9-zephyr"
|
||||
// Real version injected by CMakeLists.txt (-DFIRMWARE_VERSION); this fallback
|
||||
// only applies to builds that bypass that injection and should never surface.
|
||||
#define FIRMWARE_VERSION "v0.0.0-dev"
|
||||
#endif
|
||||
|
||||
#ifndef FIRMWARE_BUILD_DATE
|
||||
|
||||
@@ -147,10 +147,11 @@ CONFIG_BT_DIS_MANUF_NAME_STR="ZephCore"
|
||||
CONFIG_BT_DIS_MODEL_NUMBER=y
|
||||
CONFIG_BT_DIS_MODEL_NUMBER_STR="ZephCore"
|
||||
CONFIG_BT_DIS_FW_REV=y
|
||||
# Keep in sync with the version string in CompanionMesh.cpp CMD_DEVICE_QUERY
|
||||
# response (the v1.15.9-zephyr literal). Phones that read DIS and phones
|
||||
# Keep in sync with ZEPHCORE_FIRMWARE_VERSION in CMakeLists.txt (the single source
|
||||
# of truth for the C side, injected as -DFIRMWARE_VERSION). This Kconfig value can't
|
||||
# read a C macro, so it must be bumped here too. Phones that read DIS and phones
|
||||
# that query CMD_DEVICE_QUERY should see the same version.
|
||||
CONFIG_BT_DIS_FW_REV_STR="v1.15.9-zephyr"
|
||||
CONFIG_BT_DIS_FW_REV_STR="v1.16.0-zephyr"
|
||||
CONFIG_BT_DIS_SW_REV=y
|
||||
CONFIG_BT_DIS_SW_REV_STR="Zephyr"
|
||||
CONFIG_BT_DIS_PNP=n
|
||||
|
||||
@@ -82,18 +82,27 @@ void BaseChatMesh::bootstrapRTCfromContacts()
|
||||
}
|
||||
}
|
||||
|
||||
ContactInfo *BaseChatMesh::allocateContactSlot()
|
||||
ContactInfo *BaseChatMesh::allocateContactSlot(bool transient_only)
|
||||
{
|
||||
if (num_contacts < MAX_CONTACTS) {
|
||||
return &contacts[num_contacts++];
|
||||
} else if (shouldOverwriteWhenFull()) {
|
||||
} else if (transient_only || shouldOverwriteWhenFull()) {
|
||||
int oldest_idx = -1;
|
||||
uint32_t oldest_lastmod = 0xFFFFFFFF;
|
||||
for (int i = 0; i < num_contacts; i++) {
|
||||
bool is_favourite = (contacts[i].flags & 0x01) != 0;
|
||||
if (!is_favourite && contacts[i].lastmod < oldest_lastmod) {
|
||||
oldest_lastmod = contacts[i].lastmod;
|
||||
oldest_idx = i;
|
||||
if (transient_only) {
|
||||
// transient/anon requests only ever recycle an existing anon slot
|
||||
if (contacts[i].type == ADV_TYPE_NONE && contacts[i].lastmod < oldest_lastmod) {
|
||||
oldest_lastmod = contacts[i].lastmod;
|
||||
oldest_idx = i;
|
||||
}
|
||||
} else {
|
||||
// never evict favourites or transient/anon contacts
|
||||
bool is_favourite = (contacts[i].flags & 0x01) != 0;
|
||||
if (!is_favourite && contacts[i].lastmod < oldest_lastmod && contacts[i].type != ADV_TYPE_NONE) {
|
||||
oldest_lastmod = contacts[i].lastmod;
|
||||
oldest_idx = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oldest_idx >= 0) {
|
||||
@@ -740,7 +749,7 @@ ContactInfo *BaseChatMesh::lookupContactByPubKey(const uint8_t *pub_key, int pre
|
||||
|
||||
bool BaseChatMesh::addContact(const ContactInfo &contact)
|
||||
{
|
||||
ContactInfo *dest = allocateContactSlot();
|
||||
ContactInfo *dest = allocateContactSlot(contact.type == ADV_TYPE_NONE);
|
||||
if (dest) {
|
||||
*dest = contact;
|
||||
dest->shared_secret_valid = false;
|
||||
|
||||
@@ -19,6 +19,11 @@
|
||||
#define MAX_CONTACTS 32
|
||||
#endif
|
||||
|
||||
/* Headroom for transient "anon" contacts (type ADV_TYPE_NONE) created to service
|
||||
* non-contact requests (CMD_SEND_ANON_REQ to a pubkey not in the contact list).
|
||||
* These are never persisted or synced to the app. Mirrors upstream. */
|
||||
#define MAX_ANON_CONTACTS 8
|
||||
|
||||
#ifdef CONFIG_ZEPHCORE_MAX_CHANNELS
|
||||
#define MAX_GROUP_CHANNELS CONFIG_ZEPHCORE_MAX_CHANNELS
|
||||
#else
|
||||
@@ -78,9 +83,9 @@ public:
|
||||
class BaseChatMesh : public mesh::Mesh {
|
||||
friend class ContactsIterator;
|
||||
|
||||
ContactInfo contacts[MAX_CONTACTS];
|
||||
ContactInfo contacts[MAX_CONTACTS + MAX_ANON_CONTACTS];
|
||||
int num_contacts;
|
||||
int sort_array[MAX_CONTACTS];
|
||||
int sort_array[MAX_CONTACTS + MAX_ANON_CONTACTS];
|
||||
int matching_peer_indexes[MAX_SEARCH_RESULTS];
|
||||
unsigned long txt_send_timeout;
|
||||
|
||||
@@ -117,7 +122,7 @@ protected:
|
||||
void bootstrapRTCfromContacts();
|
||||
void resetContacts() { num_contacts = 0; }
|
||||
void populateContactFromAdvert(ContactInfo &ci, const mesh::Identity &id, const AdvertDataParser &parser, uint32_t timestamp);
|
||||
ContactInfo *allocateContactSlot();
|
||||
ContactInfo *allocateContactSlot(bool transient_only = false);
|
||||
|
||||
// UI concepts for subclasses to implement
|
||||
virtual bool isAutoAddEnabled() const { return true; }
|
||||
|
||||
@@ -116,6 +116,7 @@ void CommonCLI::loadPrefs(const char* path) {
|
||||
ok = ok && prefs_read(&file, &_prefs->apc_enabled, sizeof(_prefs->apc_enabled)); // 292
|
||||
ok = ok && prefs_read(&file, &_prefs->apc_margin, sizeof(_prefs->apc_margin)); // 293
|
||||
ok = ok && prefs_read(&file, &_prefs->flood_max_unscoped, sizeof(_prefs->flood_max_unscoped)); // 294
|
||||
ok = ok && prefs_read(&file, &_prefs->flood_max_advert, sizeof(_prefs->flood_max_advert)); // 295
|
||||
|
||||
if (!ok) {
|
||||
LOG_WRN("Prefs file %s truncated, some fields use defaults", path);
|
||||
@@ -160,6 +161,7 @@ void CommonCLI::loadPrefs(const char* path) {
|
||||
_prefs->apc_enabled = constrain(_prefs->apc_enabled, (uint8_t)0, (uint8_t)1);
|
||||
_prefs->apc_margin = constrain(_prefs->apc_margin, (uint8_t)6, (uint8_t)30);
|
||||
_prefs->flood_max_unscoped = constrain(_prefs->flood_max_unscoped, (uint8_t)0, (uint8_t)64);
|
||||
_prefs->flood_max_advert = constrain(_prefs->flood_max_advert, (uint8_t)0, (uint8_t)64);
|
||||
|
||||
LOG_INF("Loaded prefs from %s", path);
|
||||
}
|
||||
@@ -226,6 +228,7 @@ void CommonCLI::savePrefs(const char* path) {
|
||||
fs_write(&file, &_prefs->apc_enabled, sizeof(_prefs->apc_enabled));
|
||||
fs_write(&file, &_prefs->apc_margin, sizeof(_prefs->apc_margin));
|
||||
fs_write(&file, &_prefs->flood_max_unscoped, sizeof(_prefs->flood_max_unscoped));
|
||||
fs_write(&file, &_prefs->flood_max_advert, sizeof(_prefs->flood_max_advert));
|
||||
|
||||
fs_close(&file);
|
||||
LOG_INF("Saved prefs to %s", path);
|
||||
@@ -451,6 +454,8 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
||||
(double)est, (double)ff);
|
||||
} else if (memcmp(config, "apc.margin", 10) == 0) {
|
||||
snprintf(reply, CLI_REPLY_SIZE, "> %d dB", (int)_callbacks->getAPCTargetMargin());
|
||||
} else if (memcmp(config, "flood.max.advert", 16) == 0) {
|
||||
snprintf(reply, CLI_REPLY_SIZE, "> %u", (uint32_t)_prefs->flood_max_advert);
|
||||
} else if (memcmp(config, "flood.max.unscoped", 18) == 0) {
|
||||
snprintf(reply, CLI_REPLY_SIZE, "> %u", (uint32_t)_prefs->flood_max_unscoped);
|
||||
} else if (memcmp(config, "flood.max", 9) == 0) {
|
||||
@@ -679,6 +684,15 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
||||
_prefs->tx_delay_factor = atof(&config[8]);
|
||||
savePrefs();
|
||||
strcpy(reply, "OK (ignored: txdelay is now adaptive)");
|
||||
} else if (memcmp(config, "flood.max.advert ", 17) == 0) {
|
||||
int m = atoi(&config[17]);
|
||||
if (m >= 0 && m <= 64) {
|
||||
_prefs->flood_max_advert = (uint8_t)m;
|
||||
savePrefs();
|
||||
strcpy(reply, "OK");
|
||||
} else {
|
||||
strcpy(reply, "Error: range 0-64");
|
||||
}
|
||||
} else if (memcmp(config, "flood.max.unscoped ", 19) == 0) {
|
||||
int m = atoi(&config[19]);
|
||||
if (m >= 0 && m <= 64) {
|
||||
|
||||
@@ -48,6 +48,7 @@ struct NodePrefs {
|
||||
float bw;
|
||||
uint8_t flood_max;
|
||||
uint8_t flood_max_unscoped; // hop limit for un-scoped (ROUTE_TYPE_FLOOD) floods
|
||||
uint8_t flood_max_advert; // hop limit for ADVERT floods (curbs advert churn)
|
||||
uint8_t interference_threshold;
|
||||
uint8_t agc_reset_interval; // stored as secs / 4
|
||||
// Power saving
|
||||
@@ -120,6 +121,7 @@ static inline void initNodePrefs(NodePrefs* prefs) {
|
||||
prefs->multi_acks = 0;
|
||||
prefs->flood_max = 64; // max hops for flood packets (0 = blocking all!)
|
||||
prefs->flood_max_unscoped = 64; // un-scoped flood hop limit (defaults to flood_max)
|
||||
prefs->flood_max_advert = 8; // ADVERT flood hop limit (upstream default)
|
||||
prefs->interference_threshold = 0;
|
||||
prefs->agc_reset_interval = 0;
|
||||
prefs->powersaving_enabled = 0;
|
||||
|
||||
@@ -581,7 +581,7 @@ public:
|
||||
void savePrefs() override {
|
||||
data_store.savePrefs(companion_mesh.prefs);
|
||||
}
|
||||
const char* getFirmwareVer() override { return "v1.15.9-zephyr"; }
|
||||
const char* getFirmwareVer() override { return FIRMWARE_VERSION; }
|
||||
const char* getBuildDate() override { return FIRMWARE_BUILD_DATE; }
|
||||
const char* getRole() override { return "companion"; }
|
||||
bool formatFileSystem() override { return data_store.formatFileSystem(); }
|
||||
|
||||
Reference in New Issue
Block a user