Public Access
LoRa Scanner: MeshCore searches for nodes and their answers, read
The first two MeshCore packets heard were these: a search for repeaters and a repeater answering. Both are in clear; they are the test's bytes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0162FokPdvY2KsS4NBfwyWPk
This commit is contained in:
@@ -27,7 +27,10 @@ std::string meshcoreRow(const meshcore::Packet& m, size_t room) {
|
||||
std::string out = meshcore::payloadShort(m.type);
|
||||
std::string hops = m.hops ? " " + std::to_string(m.hops) + "h" : "";
|
||||
meshcore::Advert a;
|
||||
if (meshcore::parseAdvert(m, a)) {
|
||||
meshcore::Discover d;
|
||||
if (meshcore::parseDiscover(m, d)) {
|
||||
out = d.response ? "here " + hex(d.id, 2) : "who's there?";
|
||||
} else if (meshcore::parseAdvert(m, a)) {
|
||||
size_t used = out.size() + 1 + hops.size();
|
||||
out += " " + (a.name.empty() ? hex(a.key, 2) : a.name.substr(0, room > used ? room - used : 0));
|
||||
} else if (m.addressed() && m.payloadLen >= 2)
|
||||
@@ -65,7 +68,19 @@ std::vector<std::string> meshcoreLines(const uint8_t* data, size_t len) {
|
||||
lines.push_back(m.flood() ? "Heard first hand: no repeater yet" : "No route in it: to a neighbour");
|
||||
}
|
||||
meshcore::Advert a;
|
||||
if (meshcore::parseAdvert(m, a)) {
|
||||
meshcore::Discover d;
|
||||
if (meshcore::parseDiscover(m, d) && d.response) {
|
||||
lines.push_back(std::string(meshcore::kindName(d.kind)) + " answering a search");
|
||||
lines.push_back("Key " + hex(d.id, 8) + "...");
|
||||
std::snprintf(s, sizeof s, "It heard the search at %.1f dB SNR", d.snr);
|
||||
lines.push_back(s);
|
||||
} else if (meshcore::parseDiscover(m, d)) {
|
||||
std::string who;
|
||||
for (int kind = 1; kind <= 4; ++kind)
|
||||
if (d.kinds & (1 << kind)) who += std::string(who.empty() ? "" : ", ") + meshcore::kindName(static_cast<uint8_t>(kind));
|
||||
lines.push_back("A search for nodes nearby");
|
||||
lines.push_back("Wanted: " + (who.empty() ? std::string("any") : who));
|
||||
} else if (meshcore::parseAdvert(m, a)) {
|
||||
lines.push_back(std::string(meshcore::kindName(a.kind)) + (a.name.empty() ? "" : " " + a.name));
|
||||
lines.push_back("Key " + hex(a.key, 8) + "...");
|
||||
if (a.hasLocation) {
|
||||
|
||||
@@ -22,7 +22,7 @@ struct PacketSummary {
|
||||
|
||||
// One list row, at most about 36 characters: "21:45:07 -97 6.2 5678>all 1/3". Meshtastic nodes by their
|
||||
// default short name (the last 4 hex digits); headerLines() has the full numbers. MeshCore: what
|
||||
// it is, then who ("adv Brussels-R1", "txt a3>7f", "chan #11") and the hops in its path ("2h").
|
||||
// it is, then who ("adv Brussels-R1", "txt a3>7f", "chan #11", "who's there?", "here 18a6") and the hops in its path ("2h").
|
||||
std::string row(const PacketSummary& p, const std::string& time);
|
||||
|
||||
// Eight bytes a line, with the printable ones: "0000 ff ff ff ff 78 56 34 12 ....xV4.".
|
||||
|
||||
@@ -67,6 +67,27 @@ bool parseAdvert(const Packet& p, Advert& out) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parseDiscover(const Packet& p, Discover& out) {
|
||||
if (p.type != Payload::Control || p.payloadLen < 6) return false;
|
||||
uint8_t sub = p.payload[0] >> 4;
|
||||
Discover d;
|
||||
d.tag = static_cast<uint32_t>(le32(p.payload + 2));
|
||||
if (sub == 0x8) {
|
||||
d.kinds = p.payload[1];
|
||||
} else if (sub == 0x9) {
|
||||
d.response = true;
|
||||
d.kind = p.payload[0] & 0x0F;
|
||||
d.snr = static_cast<int8_t>(p.payload[1]) / 4.0f;
|
||||
d.id = p.payload + 6;
|
||||
d.idLen = p.payloadLen - 6;
|
||||
if (d.idLen != 8 && d.idLen != 32) return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
out = d;
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* routeName(Route r) {
|
||||
switch (r) {
|
||||
case Route::TransportFlood: return "flood in a region";
|
||||
|
||||
@@ -58,6 +58,18 @@ struct Advert {
|
||||
};
|
||||
bool parseAdvert(const Packet& p, Advert& out);
|
||||
|
||||
// Control packets that look for nodes nearby, and the answers: sent in clear, to neighbours only.
|
||||
struct Discover {
|
||||
bool response = false;
|
||||
uint8_t kinds = 0; // a request: one bit per kind of node wanted (bit 2: repeaters)
|
||||
uint8_t kind = 0; // a response: what answers, as in an advert
|
||||
float snr = 0; // a response: how well it heard the request, dB
|
||||
uint32_t tag = 0; // random in the request, repeated in its responses
|
||||
const uint8_t* id = nullptr; // a response: the node's key, or its first 8 bytes
|
||||
size_t idLen = 0;
|
||||
};
|
||||
bool parseDiscover(const Packet& p, Discover& out);
|
||||
|
||||
const char* routeName(Route r); // "flood", "direct", ...
|
||||
const char* payloadName(Payload t); // "advert", "text", ...
|
||||
const char* payloadShort(Payload t); // for a list row: "adv", "txt", ...
|
||||
|
||||
Reference in New Issue
Block a user