Public Access
M3 step 4: the LoRa Scanner App, Sniffer and Captures
The Sniffer lists packets newest first (time, RSSI, SNR, and for Meshtastic the sender, receiver and hops), with the clear header and a hex dump on Enter (Q96); `p` picks an EU868 preset, kept in Settings (Q95). `c` starts a Capture: pcap with LoRaTap in /captures/lora, its own Clean-up category, recorded by a small Service so it carries on with the App closed (Q97, Q100). The Status Bar shows L while listening, bright on each packet, and CAP while capturing (Q101). StorageService gains raw appends for binary files. Debug Builds get `lora inject` to test all of this with no transmitter in range: a Capture made on the device reads back in TShark field for field. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
#include "packet_view.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
|
||||
#include "meshtastic_header.h"
|
||||
#include "meshtastic_presets.h"
|
||||
|
||||
namespace roro::lora {
|
||||
|
||||
using namespace meshtastic;
|
||||
|
||||
std::string row(const PacketSummary& p, const std::string& time) {
|
||||
char s[64];
|
||||
int n = std::snprintf(s, sizeof s, "%s %ld %.1f ", time.c_str(), std::lround(p.rssi), p.snr);
|
||||
std::string out(s, n);
|
||||
PacketHeader h;
|
||||
if (!p.crcOk) return out + "bad CRC, " + std::to_string(p.len) + " B";
|
||||
if (!p.meshtastic || !parseHeader(p.data, p.len, h)) return out + std::to_string(p.len) + " B";
|
||||
auto shortId = [](uint32_t node) {
|
||||
if (node == kBroadcast) return std::string("all");
|
||||
char id[8];
|
||||
std::snprintf(id, sizeof id, "%04x", static_cast<unsigned>(node & 0xFFFF));
|
||||
return std::string(id);
|
||||
};
|
||||
out += shortId(h.from) + ">" + shortId(h.to);
|
||||
if (h.hopsAway() >= 0) out += " " + std::to_string(h.hopsAway()) + "/" + std::to_string(h.hopStart());
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<std::string> hexDump(const uint8_t* data, size_t len) {
|
||||
std::vector<std::string> lines;
|
||||
for (size_t at = 0; at < len; at += 8) {
|
||||
char s[48];
|
||||
int n = std::snprintf(s, sizeof s, "%04x", static_cast<unsigned>(at));
|
||||
std::string text;
|
||||
for (size_t i = 0; i < 8; ++i) {
|
||||
if (at + i < len) {
|
||||
n += std::snprintf(s + n, sizeof s - n, " %02x", data[at + i]);
|
||||
uint8_t b = data[at + i];
|
||||
text += b >= 0x20 && b < 0x7F ? static_cast<char>(b) : '.';
|
||||
} else {
|
||||
n += std::snprintf(s + n, sizeof s - n, " ");
|
||||
}
|
||||
}
|
||||
lines.push_back(std::string(s, n) + " " + text);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
std::vector<std::string> headerLines(const uint8_t* data, size_t len) {
|
||||
PacketHeader h;
|
||||
if (!parseHeader(data, len, h)) return {};
|
||||
char s[64];
|
||||
std::vector<std::string> lines;
|
||||
lines.push_back("From " + nodeId(h.from) + " to " + nodeId(h.to));
|
||||
std::snprintf(s, sizeof s, "Packet %08x%s%s", static_cast<unsigned>(h.id), h.wantAck() ? ", wants an ack" : "",
|
||||
h.viaMqtt() ? ", via MQTT" : "");
|
||||
lines.push_back(s);
|
||||
if (h.hopsAway() >= 0)
|
||||
std::snprintf(s, sizeof s, "Hops %d of %u, limit %u left", h.hopsAway(), h.hopStart(), h.hopLimit());
|
||||
else
|
||||
std::snprintf(s, sizeof s, "Hop limit %u left (old firmware)", h.hopLimit());
|
||||
lines.push_back(s);
|
||||
// Which preset's default Channel (named after it, with the public key) has this hash.
|
||||
std::string channel;
|
||||
for (size_t i = 0; i < kEu868PresetCount && channel.empty(); ++i)
|
||||
if (channelHash(kEu868Presets[i].name, kDefaultKey, sizeof kDefaultKey) == h.channelHash)
|
||||
channel = std::string(" (") + kEu868Presets[i].name + ", default key)";
|
||||
std::snprintf(s, sizeof s, "Channel 0x%02x%s", h.channelHash, channel.c_str());
|
||||
lines.push_back(s);
|
||||
if (h.relayNode) {
|
||||
std::snprintf(s, sizeof s, "Relayed by ..%02x", h.relayNode);
|
||||
lines.push_back(s);
|
||||
}
|
||||
if (h.nextHop) {
|
||||
std::snprintf(s, sizeof s, "Next hop ..%02x", h.nextHop);
|
||||
lines.push_back(s);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
} // namespace roro::lora
|
||||
Reference in New Issue
Block a user