#pragma once #include #include #include #include #include "loratap.h" namespace roro::files { // What the Storage App's viewers show of the files the firmware writes (F1, Q134). // One row of a hex dump, eight bytes: "00010 4865 6c6c 6f2c 2077 Hello, w". std::string hexRow(uint32_t offset, const uint8_t* data, size_t len); // A Track (.gpx) read a piece at a time: its points, when it started and ended, how far it went. class GpxSummary { public: void feed(const char* data, size_t len); uint32_t points() const { return points_; } int64_t start() const { return first_; } // UTC seconds, 0 if no point carried a time int64_t end() const { return last_; } double meters() const { return meters_; } std::vector lines() const; // for the screen private: void point(const std::string& element); std::string carry_; // the part of a point cut by the end of a piece uint32_t points_ = 0; int64_t first_ = 0, last_ = 0; double meters_ = 0, lat_ = 0, lon_ = 0; }; // "1 h 02 min", "4 min 10 s", "12 s". std::string formatDuration(int64_t seconds); // A Capture (.pcap): the file's header, then one record after another. struct PcapHeader { bool ok = false; uint32_t linkType = 0; // 270: LoRaTap, what the LoRa Scanner writes }; constexpr size_t kPcapHeaderSize = 24, kPcapRecordSize = 16; constexpr uint32_t kLinkLoraTap = 270; PcapHeader parsePcapHeader(const uint8_t* data, size_t len); struct PcapRecord { uint32_t seconds = 0, micros = 0, length = 0; // length: the bytes that follow in the file }; bool parsePcapRecord(const uint8_t* data, size_t len, PcapRecord& out); // false: not a record, stop there // The LoRaTap header a packet starts with; false if `len` is too short for one. bool parseLoraTap(const uint8_t* data, size_t len, lora::RxInfo& out); } // namespace roro::files