#include "services/lora_capture_service.h" #include #include "loratap.h" #include "platform/console.h" namespace roro { std::string LoraCaptureService::start(uint32_t nowMs) { if (capturing()) return ""; if (!radio_.present()) return "No LoRa radio"; StorageState card = storage_.state(); if (!card.present) return "No SD card"; if (!card.capturesAllowed) return "The SD card is full"; int64_t now = clock_.utcNow(); if (now < 0) return "Waiting for the time (GNSS or Wi-Fi)"; path_ = lora::capturePath(now); std::vector header; lora::appendPcapHeader(header); storage_.appendBytes(path_, std::string(header.begin(), header.end()), true); startUtc_ = now; startMs_ = nowMs; written_ = radio_.received(); // from now on packets_ = 0; radio_.listen(RadioService::Capture, true); console.printf("lora: Capture %s started\n", path_.c_str()); notify("LoRa Capture started"); return ""; } void LoraCaptureService::stop() { if (!capturing()) return; radio_.listen(RadioService::Capture, false); console.printf("lora: Capture %s stopped, %lu packets\n", path_.c_str(), (unsigned long)packets_); notify("LoRa Capture stopped: " + std::to_string(packets_) + " packets"); path_.clear(); } void LoraCaptureService::tick(uint32_t nowMs) { (void)nowMs; if (!capturing()) return; uint32_t newest = radio_.received(); for (uint32_t seq = written_ + 1; seq <= newest; ++seq) { RadioPacket p; if (!radio_.packet(seq, p)) continue; // already left the ring: too many at once uint32_t sinceStart = p.ms - startMs_; std::vector record; record.reserve(lora::kRecordOverhead + p.len); lora::appendRecord(record, static_cast(startUtc_ + sinceStart / 1000), (sinceStart % 1000) * 1000, p.rx, p.data, p.len); storage_.appendBytes(path_, std::string(record.begin(), record.end()), true); ++packets_; } written_ = newest; } void LoraCaptureService::notify(const std::string& text) { bus_.publish(Event::withText(EventType::Notification, text.c_str(), static_cast(NotificationLevel::Info))); } } // namespace roro