Compare commits

..

10 Commits

Author SHA1 Message Date
Matthias Wientapper
4da42d02d4 Disable flood adverts 2026-03-03 20:13:23 +01:00
Matthias Wientapper
16faa821eb Set RAK boot lock voltage to 0V 2026-03-03 20:13:23 +01:00
Matthias Wientapper
08341eb27a Integration of upstrem PR #1810 2026-03-03 20:13:23 +01:00
Matthias Wientapper
4d352d646a Integration of upstrem PR #1338 2026-03-03 20:13:23 +01:00
Matthias Wientapper
aee066dd0f Integration of upstrem PR #1297 2026-03-03 20:13:22 +01:00
Matthias Wientapper
37d3afc17e Disable flood_adverts per default 2026-02-28 15:49:52 +01:00
Matthias Wientapper
516d784087 Add cli config flood.advert.base
0 = forwarding flood adverts off
1 = forwarding flood adverts on (unrestricted)
0.308 (default) = prob. forwarding according to #1338
2026-02-28 15:29:20 +01:00
Matthias Wientapper
3088d1862a Limit flood advert packet forwarding for roomservers as well 2026-02-28 15:29:20 +01:00
Matthias Wientapper
6f1e01a750 Limit flood advert packet forwarding, implements #1223 2026-02-28 15:25:43 +01:00
Matthias Wientapper
b039af0b52 Rak bootlock voltage set to 0x 2026-02-21 19:21:38 +01:00
8 changed files with 31 additions and 113 deletions

View File

@@ -51,7 +51,7 @@
- `time <epoch_seconds>`
**Parameters:**
- `epoch_seconds`: Unix epoch time
- `epoc_seconds`: Unix epoc time
---
@@ -134,7 +134,7 @@
---
### End capture of rx log to node storage
### End capture of rx log to node sotrage
**Usage:** `log stop`
---
@@ -198,7 +198,7 @@
**Default:** Varies by board
**Notes:** This setting only controls the power level of the LoRa chip. Some nodes have an additional power amplifier stage which increases the total output. Refer to the node's manual for the correct setting to use. **Setting a value too high may violate the laws in your country.**
**Notes:** This setting only controls the power level of the LoRa chip. Some nodes have an additional power amplifier stage which increases the total output. Referr to the node's manual for the correct setting to use. **Setting a value too high may violate the laws in your country.**
---
@@ -228,7 +228,6 @@
**Default:** `869.525`
**Note:** Requires reboot to apply
**Serial Only:** `set freq <frequency>`
### System
@@ -294,16 +293,17 @@
#### View or change this node's admin password
**Usage:**
- `password <new_password>`
- `get password`
- `set password <password>`
**Parameters:**
- `new_password`: New admin password
- `password`: Admin password
**Set by build flag:** `ADMIN_PASSWORD`
**Default:** `password`
**Note:** Command reply echoes the updated password for confirmation.
**Note:** Echoed back for confirmation
**Note:** Any node using this password will be added to the admin ACL list.
@@ -768,7 +768,7 @@ region save
- `gps advert <policy>`
**Parameters:**
- `policy`: `none`|`share`|`prefs`
- `policy`: `none`|`shared`|`prefs`
- `none`: don't include location in adverts
- `share`: share gps location (from SensorManager)
- `prefs`: location stored in node's lat and lon settings

View File

@@ -396,23 +396,6 @@ File MyMesh::openAppend(const char *fname) {
#endif
}
static uint8_t max_loop_minimal[] = { 0, /* 1-byte */ 4, /* 2-byte */ 2, /* 3-byte */ 1 };
static uint8_t max_loop_moderate[] = { 0, /* 1-byte */ 2, /* 2-byte */ 1, /* 3-byte */ 1 };
static uint8_t max_loop_strict[] = { 0, /* 1-byte */ 1, /* 2-byte */ 1, /* 3-byte */ 1 };
bool MyMesh::isLooped(const mesh::Packet* packet, const uint8_t max_counters[]) {
uint8_t hash_size = packet->getPathHashSize();
uint8_t hash_count = packet->getPathHashCount();
uint8_t n = 0;
const uint8_t* path = packet->path;
while (hash_count > 0) { // count how many times this node is already in the path
if (self_id.isHashMatch(path, hash_size)) n++;
hash_count--;
path += hash_size;
}
return n >= max_counters[hash_size];
}
bool MyMesh::allowPacketForward(const mesh::Packet *packet) {
if (_prefs.disable_fwd) return false;
if (packet->isRouteFlood() && packet->getPathHashCount() >= _prefs.flood_max) return false;
@@ -420,29 +403,14 @@ bool MyMesh::allowPacketForward(const mesh::Packet *packet) {
MESH_DEBUG_PRINTLN("allowPacketForward: unknown transport code, or wildcard not allowed for FLOOD packet");
return false;
}
if (packet->isRouteFlood() && _prefs.loop_detect != LOOP_DETECT_OFF) {
const uint8_t* maximums;
if (_prefs.loop_detect == LOOP_DETECT_MINIMAL) {
maximums = max_loop_minimal;
} else if (_prefs.loop_detect == LOOP_DETECT_MODERATE) {
maximums = max_loop_moderate;
} else {
maximums = max_loop_strict;
}
if (isLooped(packet, maximums)) {
MESH_DEBUG_PRINTLN("allowPacketForward: FLOOD packet loop detected!");
return false;
}
}
// Limit flood advert paket forwarding using a probabilistic reduction defined by P(h) = 0.308^(hops-1)
// https://github.com/meshcore-dev/MeshCore/issues/1223
if (packet->getPayloadType() == PAYLOAD_TYPE_ADVERT && packet->isRouteFlood()) {
double roll_dice = (double)rand() / RAND_MAX;
double forw_prob = pow(_prefs.flood_advert_base, packet->path_len - 1);
if (roll_dice > forw_prob)
return false;
}
double_t roll_dice = (double)rand() / RAND_MAX;
double_t forw_prob = pow(_prefs.flood_advert_base, packet->path_len - 1);
if (packet->getPayloadType() == PAYLOAD_TYPE_ADVERT && packet->isRouteFlood() && roll_dice > forw_prob)
return false;
// all other packets
return true;
}

View File

@@ -128,7 +128,6 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
mesh::Packet* createSelfAdvert();
File openAppend(const char* fname);
bool isLooped(const mesh::Packet* packet, const uint8_t max_counters[]);
protected:
float getAirtimeBudgetFactor() const override {

View File

@@ -276,17 +276,16 @@ uint32_t MyMesh::getDirectRetransmitDelay(const mesh::Packet *packet) {
bool MyMesh::allowPacketForward(const mesh::Packet *packet) {
if (_prefs.disable_fwd) return false;
if (packet->isRouteFlood() && packet->path_len >= _prefs.flood_max) return false;
if (packet->isRouteFlood() && packet->getPathHashCount() >= _prefs.flood_max) return false;
// Limit flood advert packet forwarding using a probabilistic reduction defined by P(h) = base^(hops-1)
// Limit flood advert paket forwarding using a probabilistic reduction defined by P(h) = 0.308^(hops-1)
// https://github.com/meshcore-dev/MeshCore/issues/1223
if (packet->getPayloadType() == PAYLOAD_TYPE_ADVERT && packet->isRouteFlood()) {
double roll_dice = (double)rand() / RAND_MAX;
double forw_prob = pow(_prefs.flood_advert_base, packet->path_len - 1);
if (roll_dice > forw_prob)
return false;
}
double_t roll_dice = (double)rand() / RAND_MAX;
double_t forw_prob = pow(_prefs.flood_advert_base, packet->path_len - 1);
if (packet->getPayloadType() == PAYLOAD_TYPE_ADVERT && packet->isRouteFlood() && roll_dice > forw_prob)
return false;
// all other packets
return true;
}
@@ -624,7 +623,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
_prefs.tx_power_dbm = LORA_TX_POWER;
_prefs.disable_fwd = 1;
_prefs.advert_interval = 1; // default to 2 minutes for NEW installs
_prefs.flood_advert_interval = 12; // 12 hours
_prefs.flood_advert_interval = 0; // 12 hours
_prefs.flood_advert_base = 0.308f;
_prefs.flood_max = 64;
_prefs.interference_threshold = 0; // disabled

View File

@@ -64,8 +64,7 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
file.read((uint8_t *)&_prefs->bw, sizeof(_prefs->bw)); // 116
file.read((uint8_t *)&_prefs->agc_reset_interval, sizeof(_prefs->agc_reset_interval)); // 120
file.read((uint8_t *)&_prefs->path_hash_mode, sizeof(_prefs->path_hash_mode)); // 121
file.read((uint8_t *)&_prefs->loop_detect, sizeof(_prefs->loop_detect)); // 122
file.read(pad, 1); // 123
file.read(pad, 2); // 122
file.read((uint8_t *)&_prefs->flood_max, sizeof(_prefs->flood_max)); // 124
file.read((uint8_t *)&_prefs->flood_advert_interval, sizeof(_prefs->flood_advert_interval)); // 125
file.read((uint8_t *)&_prefs->interference_threshold, sizeof(_prefs->interference_threshold)); // 126
@@ -155,8 +154,7 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
file.write((uint8_t *)&_prefs->bw, sizeof(_prefs->bw)); // 116
file.write((uint8_t *)&_prefs->agc_reset_interval, sizeof(_prefs->agc_reset_interval)); // 120
file.write((uint8_t *)&_prefs->path_hash_mode, sizeof(_prefs->path_hash_mode)); // 121
file.write((uint8_t *)&_prefs->loop_detect, sizeof(_prefs->loop_detect)); // 122
file.write(pad, 1); // 123
file.write(pad, 2); // 122
file.write((uint8_t *)&_prefs->flood_max, sizeof(_prefs->flood_max)); // 124
file.write((uint8_t *)&_prefs->flood_advert_interval, sizeof(_prefs->flood_advert_interval)); // 125
file.write((uint8_t *)&_prefs->interference_threshold, sizeof(_prefs->interference_threshold)); // 126
@@ -211,10 +209,6 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
// Reset clock
getRTCClock()->setCurrentTime(1715770351); // 15 May 2024, 8:50pm
_board->reboot(); // doesn't return
} else if (memcmp(command, "advert.zerohop", 14) == 0 && (command[14] == 0 || command[14] == ' ')) {
// send zerohop advert
_callbacks->sendSelfAdvertisement(1500, false); // longer delay, give CLI response time to be sent first
strcpy(reply, "OK - zerohop advert sent");
} else if (memcmp(command, "advert", 6) == 0) {
// send flood advert
_callbacks->sendSelfAdvertisement(1500, true); // longer delay, give CLI response time to be sent first
@@ -342,16 +336,6 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
*reply = 0; // set null terminator
} else if (memcmp(config, "path.hash.mode", 14) == 0) {
sprintf(reply, "> %d", (uint32_t)_prefs->path_hash_mode);
} else if (memcmp(config, "loop.detect", 11) == 0) {
if (_prefs->loop_detect == LOOP_DETECT_OFF) {
strcpy(reply, "> off");
} else if (_prefs->loop_detect == LOOP_DETECT_MINIMAL) {
strcpy(reply, "> minimal");
} else if (_prefs->loop_detect == LOOP_DETECT_MODERATE) {
strcpy(reply, "> moderate");
} else {
strcpy(reply, "> strict");
}
} else if (memcmp(config, "tx", 2) == 0 && (config[2] == 0 || config[2] == ' ')) {
sprintf(reply, "> %d", (int32_t) _prefs->tx_power_dbm);
} else if (memcmp(config, "freq", 4) == 0) {
@@ -595,26 +579,6 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
} else {
strcpy(reply, "Error, must be 0,1, or 2");
}
} else if (memcmp(config, "loop.detect ", 12) == 0) {
config += 12;
uint8_t mode;
if (memcmp(config, "off", 3) == 0) {
mode = LOOP_DETECT_OFF;
} else if (memcmp(config, "minimal", 7) == 0) {
mode = LOOP_DETECT_MINIMAL;
} else if (memcmp(config, "moderate", 8) == 0) {
mode = LOOP_DETECT_MODERATE;
} else if (memcmp(config, "strict", 6) == 0) {
mode = LOOP_DETECT_STRICT;
} else {
mode = 0xFF;
strcpy(reply, "Error, must be: off, minimal, moderate, or strict");
}
if (mode != 0xFF) {
_prefs->loop_detect = mode;
savePrefs();
strcpy(reply, "OK");
}
} else if (memcmp(config, "tx ", 3) == 0) {
_prefs->tx_power_dbm = atoi(&config[3]);
savePrefs();
@@ -688,7 +652,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
};
} else if (memcmp(config, "flood.advert.base ", 18) == 0) {
float f = atof(&config[18]);
if(f >= 0 && f <= 1) {
if((f > 0) || (f<1)) {
_prefs->flood_advert_base = f;
savePrefs();
strcpy(reply, "OK");

View File

@@ -13,11 +13,6 @@
#define ADVERT_LOC_SHARE 1
#define ADVERT_LOC_PREFS 2
#define LOOP_DETECT_OFF 0
#define LOOP_DETECT_MINIMAL 1
#define LOOP_DETECT_MODERATE 2
#define LOOP_DETECT_STRICT 3
struct NodePrefs { // persisted to file
float airtime_factor;
char node_name[32];
@@ -59,7 +54,6 @@ struct NodePrefs { // persisted to file
float adc_multiplier;
char owner_info[120];
uint8_t path_hash_mode; // which path mode to use when sending
uint8_t loop_detect;
};
class CommonCLICallbacks {

View File

@@ -683,7 +683,7 @@ void EnvironmentSensorManager::start_gps() {
_location->begin();
_location->reset();
#ifndef PIN_GPS_EN
#ifndef PIN_GPS_RESET
MESH_DEBUG_PRINTLN("Start GPS is N/A on this board. Actual GPS state unchanged");
#endif
}

View File

@@ -1,7 +1,5 @@
[ikoka_handheld_nrf]
extends = nrf52_base
board = seeed-xiao-afruitnrf52-nrf52840
board_build.ldscript = boards/nrf52840_s140_v7.ld
build_flags = ${nrf52_base.build_flags}
${sensor_base.build_flags}
-I lib/nrf52/s140_nrf52_7.3.0_API/include
@@ -50,8 +48,7 @@ build_src_filter = ${ikoka_handheld_nrf.build_src_filter}
+<../examples/companion_radio/*.cpp>
[env:ikoka_handheld_nrf_e22_30dbm_096_companion_radio_ble]
extends = ikoka_handheld_nrf
board_build.ldscript = boards/nrf52840_s140_v7_extrafs.ld
extends = ikoka_nrf52
build_flags = ${ikoka_handheld_nrf_ssd1306_companion.build_flags}
-D BLE_PIN_CODE=123456
-D LORA_TX_POWER=20
@@ -59,8 +56,7 @@ build_src_filter = ${ikoka_handheld_nrf_ssd1306_companion.build_src_filter}
+<helpers/nrf52/SerialBLEInterface.cpp>
[env:ikoka_handheld_nrf_e22_30dbm_096_rotated_companion_radio_ble]
extends = ikoka_handheld_nrf
board_build.ldscript = boards/nrf52840_s140_v7_extrafs.ld
extends = ikoka_nrf52
build_flags = ${ikoka_handheld_nrf_ssd1306_companion.build_flags}
-D BLE_PIN_CODE=123456
-D LORA_TX_POWER=20
@@ -69,22 +65,20 @@ build_src_filter = ${ikoka_handheld_nrf_ssd1306_companion.build_src_filter}
+<helpers/nrf52/SerialBLEInterface.cpp>
[env:ikoka_handheld_nrf_e22_30dbm_096_companion_radio_usb]
extends = ikoka_handheld_nrf
board_build.ldscript = boards/nrf52840_s140_v7_extrafs.ld
extends = ikoka_nrf52
build_flags = ${ikoka_handheld_nrf_ssd1306_companion.build_flags}
-D LORA_TX_POWER=20
build_src_filter = ${ikoka_handheld_nrf_ssd1306_companion.build_src_filter}
[env:ikoka_handheld_nrf_e22_30dbm_096_rotated_companion_radio_usb]
extends = ikoka_handheld_nrf
board_build.ldscript = boards/nrf52840_s140_v7_extrafs.ld
extends = ikoka_nrf52
build_flags = ${ikoka_handheld_nrf_ssd1306_companion.build_flags}
-D LORA_TX_POWER=20
-D DISPLAY_ROTATION=2
build_src_filter = ${ikoka_handheld_nrf_ssd1306_companion.build_src_filter}
[env:ikoka_handheld_nrf_e22_30dbm_repeater]
extends = ikoka_handheld_nrf
extends = ikoka_nrf52
build_flags =
${ikoka_handheld_nrf.build_flags}
-D ADVERT_NAME='"ikoka_handheld Repeater"'
@@ -97,7 +91,7 @@ build_src_filter = ${ikoka_handheld_nrf.build_src_filter}
+<../examples/simple_repeater/*.cpp>
[env:ikoka_handheld_nrf_e22_30dbm_room_server]
extends = ikoka_handheld_nrf
extends = ikoka_nrf52
build_flags =
${ikoka_handheld_nrf.build_flags}
-D ADVERT_NAME='"ikoka_handheld Room"'