mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-07-28 15:19:20 +00:00
Fix issue with packet prefixes getting added to the table.
This commit is contained in:
@@ -119,19 +119,23 @@ This document provides an overview of CLI commands that can be sent to MeshCore
|
||||
**Usage:**
|
||||
- `get recent.repeater`
|
||||
- `get recent.repeater all`
|
||||
- `get recent.repeater all <count> <offset>`
|
||||
- `get recent.repeater first <count>`
|
||||
- `get recent.repeater first <count> <offset>`
|
||||
- `get recent.repeater last <count>`
|
||||
- `get recent.repeater last <count> <offset>`
|
||||
- `set recent.repeater <prefix_hex> <snr_db>`
|
||||
|
||||
**Parameters:**
|
||||
- `prefix_hex`: 1-3 bytes of next-hop prefix (hex)
|
||||
- `snr_db`: SNR in dB (supports decimals; stored at x4 precision)
|
||||
- `count`: number of entries to print
|
||||
- `offset`: zero-based row offset into the selected order
|
||||
|
||||
**Notes:**
|
||||
- `set` is rejected when the prefix already exists in neighbors.
|
||||
- `all` prints oldest to newest; `first` prints the oldest N; `last` prints the newest N.
|
||||
- Remote CLI replies include rows too, but may truncate when the packet payload limit is reached.
|
||||
- Over LoRa remote CLI, replies are packet-size limited; use `offset` to page through all rows.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1372,7 +1372,11 @@ void MyMesh::handleCommand(uint32_t sender_timestamp, char *command, char *reply
|
||||
|
||||
auto* tables = (SimpleMeshTables*)getTables();
|
||||
|
||||
if (is_set || (!is_get && *sub != 0 && strcmp(sub, "all") != 0 && strncmp(sub, "first ", 6) != 0 && strncmp(sub, "last ", 5) != 0)) {
|
||||
bool is_all = (strcmp(sub, "all") == 0 || strncmp(sub, "all ", 4) == 0);
|
||||
bool is_first = (strncmp(sub, "first ", 6) == 0);
|
||||
bool is_last = (strncmp(sub, "last ", 5) == 0);
|
||||
|
||||
if (is_set || (!is_get && *sub != 0 && !is_all && !is_first && !is_last)) {
|
||||
char* params = (char*) sub;
|
||||
char* arg_snr = strchr(params, ' ');
|
||||
if (arg_snr == NULL) {
|
||||
@@ -1409,62 +1413,111 @@ void MyMesh::handleCommand(uint32_t sender_timestamp, char *command, char *reply
|
||||
mesh::Utils::toHex(hex, info->prefix, info->prefix_len);
|
||||
sprintf(reply, "> %s,%s", hex, StrHelper::ftoa(((float)info->snr_x4) / 4.0f));
|
||||
}
|
||||
} else if (strcmp(sub, "all") == 0 || strncmp(sub, "first ", 6) == 0 || strncmp(sub, "last ", 5) == 0) {
|
||||
} else if (is_all || is_first || is_last) {
|
||||
int total = tables->getRecentRepeaterCount();
|
||||
if (total <= 0) {
|
||||
strcpy(reply, "> none");
|
||||
} else {
|
||||
bool newest_first = false;
|
||||
int limit = total;
|
||||
int offset = 0;
|
||||
const char* mode = "all";
|
||||
if (strncmp(sub, "first ", 6) == 0 || strncmp(sub, "last ", 5) == 0) {
|
||||
const char* nstr = sub + (sub[0] == 'f' ? 6 : 5);
|
||||
|
||||
if (is_first || is_last) {
|
||||
const char* nstr = sub + (is_first ? 6 : 5);
|
||||
while (*nstr == ' ') nstr++;
|
||||
if (*nstr == 0) {
|
||||
strcpy(reply, "Err - usage: get recent.repeater first|last <count>");
|
||||
strcpy(reply, "Err - usage: get recent.repeater first|last <count> [offset]");
|
||||
return;
|
||||
}
|
||||
|
||||
char* end_ptr = NULL;
|
||||
long parsed = strtol(nstr, &end_ptr, 10);
|
||||
long parsed_count = strtol(nstr, &end_ptr, 10);
|
||||
while (end_ptr != NULL && *end_ptr == ' ') end_ptr++;
|
||||
if (end_ptr == NULL || *end_ptr != 0 || parsed <= 0) {
|
||||
if (end_ptr == NULL || parsed_count <= 0) {
|
||||
strcpy(reply, "Err - count must be > 0");
|
||||
return;
|
||||
}
|
||||
limit = (int)parsed;
|
||||
if (sub[0] == 'l') {
|
||||
|
||||
if (*end_ptr != 0) {
|
||||
char* end_ptr2 = NULL;
|
||||
long parsed_offset = strtol(end_ptr, &end_ptr2, 10);
|
||||
while (end_ptr2 != NULL && *end_ptr2 == ' ') end_ptr2++;
|
||||
if (end_ptr2 == NULL || *end_ptr2 != 0 || parsed_offset < 0) {
|
||||
strcpy(reply, "Err - offset must be >= 0");
|
||||
return;
|
||||
}
|
||||
offset = (int)parsed_offset;
|
||||
}
|
||||
|
||||
limit = (int)parsed_count;
|
||||
if (is_last) {
|
||||
newest_first = true;
|
||||
mode = "last";
|
||||
} else {
|
||||
mode = "first";
|
||||
}
|
||||
} else if (strncmp(sub, "all ", 4) == 0) {
|
||||
const char* arg = sub + 4;
|
||||
while (*arg == ' ') arg++;
|
||||
if (*arg == 0) {
|
||||
strcpy(reply, "Err - usage: get recent.repeater all <count> <offset>");
|
||||
return;
|
||||
}
|
||||
|
||||
char* end_ptr = NULL;
|
||||
long parsed_a = strtol(arg, &end_ptr, 10);
|
||||
while (end_ptr != NULL && *end_ptr == ' ') end_ptr++;
|
||||
if (end_ptr == NULL || parsed_a <= 0) {
|
||||
strcpy(reply, "Err - count must be > 0");
|
||||
return;
|
||||
}
|
||||
|
||||
char* end_ptr2 = NULL;
|
||||
long parsed_b = strtol(end_ptr, &end_ptr2, 10);
|
||||
while (end_ptr2 != NULL && *end_ptr2 == ' ') end_ptr2++;
|
||||
if (end_ptr2 == NULL || *end_ptr2 != 0 || parsed_b < 0) {
|
||||
strcpy(reply, "Err - usage: get recent.repeater all <count> <offset>");
|
||||
return;
|
||||
}
|
||||
limit = (int)parsed_a;
|
||||
offset = (int)parsed_b;
|
||||
}
|
||||
if (limit > total) {
|
||||
limit = total;
|
||||
|
||||
if (offset >= total) {
|
||||
sprintf(reply, "> none (%s off=%d/%d)", mode, offset, total);
|
||||
return;
|
||||
}
|
||||
|
||||
int available = total - offset;
|
||||
if (limit > available) {
|
||||
limit = available;
|
||||
}
|
||||
|
||||
if (sender_timestamp == 0) {
|
||||
Serial.printf("Recent repeater table (%s %d/%d):\n", mode, limit, total);
|
||||
Serial.printf("Recent repeater table (%s %d/%d, off=%d):\n", mode, limit, total, offset);
|
||||
for (int i = 0; i < limit; i++) {
|
||||
const auto* info = newest_first ? tables->getRecentRepeaterNewestByIdx(i) : tables->getRecentRepeaterOldestByIdx(i);
|
||||
int idx = offset + i;
|
||||
const auto* info = newest_first ? tables->getRecentRepeaterNewestByIdx(idx) : tables->getRecentRepeaterOldestByIdx(idx);
|
||||
if (info == NULL) {
|
||||
continue;
|
||||
}
|
||||
char hex[(MAX_ROUTE_HASH_BYTES * 2) + 1];
|
||||
mesh::Utils::toHex(hex, info->prefix, info->prefix_len);
|
||||
Serial.printf("%02d: %s,%s\n", i + 1, hex, StrHelper::ftoa(((float)info->snr_x4) / 4.0f));
|
||||
Serial.printf("%02d: %s,%s\n", idx + 1, hex, StrHelper::ftoa(((float)info->snr_x4) / 4.0f));
|
||||
}
|
||||
sprintf(reply, "> showing %d/%d (%s)", limit, total, mode);
|
||||
sprintf(reply, "> %s off=%d n=%d/%d", mode, offset, limit, total);
|
||||
} else {
|
||||
// Remote CLI replies are packet-bound, so include as many rows as fit.
|
||||
int written = snprintf(reply, 160, "> showing %d/%d (%s)", limit, total, mode);
|
||||
int written = snprintf(reply, 160, "> %s off=%d n=%d/%d", mode, offset, limit, total);
|
||||
bool truncated = false;
|
||||
if (written < 0) {
|
||||
reply[0] = 0;
|
||||
written = 0;
|
||||
}
|
||||
for (int i = 0; i < limit; i++) {
|
||||
const auto* info = newest_first ? tables->getRecentRepeaterNewestByIdx(i) : tables->getRecentRepeaterOldestByIdx(i);
|
||||
int idx = offset + i;
|
||||
const auto* info = newest_first ? tables->getRecentRepeaterNewestByIdx(idx) : tables->getRecentRepeaterOldestByIdx(idx);
|
||||
if (info == NULL) {
|
||||
continue;
|
||||
}
|
||||
@@ -1474,7 +1527,7 @@ void MyMesh::handleCommand(uint32_t sender_timestamp, char *command, char *reply
|
||||
}
|
||||
char hex[(MAX_ROUTE_HASH_BYTES * 2) + 1];
|
||||
mesh::Utils::toHex(hex, info->prefix, info->prefix_len);
|
||||
int n = snprintf(reply + written, 160 - written, "\n%02d:%s,%s", i + 1, hex, StrHelper::ftoa(((float)info->snr_x4) / 4.0f));
|
||||
int n = snprintf(reply + written, 160 - written, "\n%02d:%s,%s", idx + 1, hex, StrHelper::ftoa(((float)info->snr_x4) / 4.0f));
|
||||
if (n < 0 || n >= (160 - written)) {
|
||||
truncated = true;
|
||||
break;
|
||||
@@ -1482,12 +1535,12 @@ void MyMesh::handleCommand(uint32_t sender_timestamp, char *command, char *reply
|
||||
written += n;
|
||||
}
|
||||
if (truncated && written < 156) {
|
||||
snprintf(reply + written, 160 - written, "\n...");
|
||||
snprintf(reply + written, 160 - written, "\n... use offset");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
strcpy(reply, "Err - usage: get recent.repeater [all|first <count>|last <count>]");
|
||||
strcpy(reply, "Err - usage: get recent.repeater [all|all <count> <offset>|first <count> [offset]|last <count> [offset]]");
|
||||
}
|
||||
} else if (memcmp(command, "discover.neighbors", 18) == 0) {
|
||||
const char* sub = command + 18;
|
||||
|
||||
@@ -70,6 +70,19 @@ private:
|
||||
|
||||
bool extractRecentRepeater(const mesh::Packet* packet, uint8_t* prefix, uint8_t& prefix_len) const {
|
||||
// Learn repeater prefixes only from packet shapes that expose a trustworthy repeater ID.
|
||||
// For flood traffic, the last path entry is the repeater we directly heard.
|
||||
if (packet->isRouteFlood() && packet->getPathHashCount() > 0) {
|
||||
prefix_len = packet->getPathHashSize();
|
||||
if (prefix_len > MAX_ROUTE_HASH_BYTES) {
|
||||
prefix_len = MAX_ROUTE_HASH_BYTES;
|
||||
}
|
||||
|
||||
const uint8_t* last_hop = &packet->path[(packet->getPathHashCount() - 1) * packet->getPathHashSize()];
|
||||
memcpy(prefix, last_hop, prefix_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If there is no flood path to inspect, fall back to payload-derived identities.
|
||||
if (packet->getPayloadType() == PAYLOAD_TYPE_ADVERT && packet->payload_len >= PUB_KEY_SIZE) {
|
||||
memcpy(prefix, packet->payload, MAX_ROUTE_HASH_BYTES);
|
||||
prefix_len = MAX_ROUTE_HASH_BYTES;
|
||||
@@ -86,17 +99,6 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
if (packet->isRouteFlood() && packet->getPathHashCount() > 0) {
|
||||
prefix_len = packet->getPathHashSize();
|
||||
if (prefix_len > MAX_ROUTE_HASH_BYTES) {
|
||||
prefix_len = MAX_ROUTE_HASH_BYTES;
|
||||
}
|
||||
|
||||
const uint8_t* last_hop = &packet->path[(packet->getPathHashCount() - 1) * packet->getPathHashSize()];
|
||||
memcpy(prefix, last_hop, prefix_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user