#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define CONCAT(a, b) ((std::string(a) + b).c_str()) SDRPP_MOD_INFO { /* Name: */ "falcon9_decoder", /* Description: */ "Falcon9 telemetry decoder for SDR++", /* Author: */ "Ryzerth", /* Version: */ 0, 1, 0, /* Max instances */ -1 }; #define INPUT_SAMPLE_RATE 6000000 std::ofstream file("output.ts"); class Falcon9DecoderModule : public ModuleManager::Instance { public: Falcon9DecoderModule(std::string name) { this->name = name; vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, 4000000, INPUT_SAMPLE_RATE, 4000000, 4000000, true); // dsp::Splitter split; // dsp::Reshaper reshape; // dsp::HandlerSink symSink; // dsp::stream thrInput; // dsp::Threshold thr; demod.init(vfo->output, INPUT_SAMPLE_RATE, 2000000.0f); recov.init(&demod.out, (float)INPUT_SAMPLE_RATE / 3571400.0f, powf(0.01f, 2) / 4.0f, 0.01, 100e-6f); // 0.00765625f, 0.175f, 0.005f split.init(&recov.out); split.bindStream(&reshapeInput); split.bindStream(&thrInput); reshape.init(&reshapeInput, 1024, 198976); symSink.init(&reshape.out, symSinkHandler, this); thr.init(&thrInput); deframe.init(&thr.out, 10232, syncWord, 32); falconRS.init(&deframe.out); pkt.init(&falconRS.out); sink.init(&pkt.out, sinkHandler, this); demod.start(); recov.start(); split.start(); reshape.start(); symSink.start(); sink.start(); pkt.start(); falconRS.start(); deframe.start(); thr.start(); #ifdef _WIN32 ffplay = _popen("ffplay -framedrop -infbuf -hide_banner -loglevel panic -window_title \"Falcon 9 Cameras\" -", "wb"); #else ffplay = popen("ffplay -framedrop -infbuf -hide_banner -loglevel panic -window_title \"Falcon 9 Cameras\" -", "wb"); #endif gui::menu.registerEntry(name, menuHandler, this, this); } ~Falcon9DecoderModule() { } void postInit() {} void enable() { vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, 4000000, INPUT_SAMPLE_RATE, 4000000, 4000000, true); demod.setInput(vfo->output); demod.start(); recov.start(); split.start(); reshape.start(); symSink.start(); sink.start(); pkt.start(); falconRS.start(); deframe.start(); thr.start(); enabled = true; } void disable() { demod.stop(); recov.stop(); split.stop(); reshape.stop(); symSink.stop(); sink.stop(); pkt.stop(); falconRS.stop(); deframe.stop(); thr.stop(); sigpath::vfoManager.deleteVFO(vfo); enabled = false; } bool isEnabled() { return enabled; } private: static void menuHandler(void* ctx) { Falcon9DecoderModule* _this = (Falcon9DecoderModule*)ctx; float menuWidth = ImGui::GetContentRegionAvailWidth(); if (!_this->enabled) { style::beginDisabled(); } ImGui::SetNextItemWidth(menuWidth); _this->symDiag.draw(); if (_this->logsVisible) { if (ImGui::Button("Hide logs", ImVec2(menuWidth, 0))) { _this->logsVisible = false; } } else { if (ImGui::Button("Show logs", ImVec2(menuWidth, 0))) { _this->logsVisible = true; } } if (_this->logsVisible) { std::lock_guard lck(_this->logsMtx); ImGui::Begin("Falcon9 Telemetry"); ImGui::BeginTabBar("Falcon9Tabs"); // GPS Logs ImGui::BeginTabItem("GPS"); if (ImGui::Button("Clear logs##GPSClear")) { _this->gpsLogs.clear(); } ImGui::BeginChild(ImGuiID("GPSChild")); ImGui::TextUnformatted(_this->gpsLogs.c_str()); ImGui::SetScrollHereY(1.0f); ImGui::EndChild(); ImGui::EndTabItem(); // STMM1A Logs ImGui::BeginTabItem("STMM1A"); ImGui::EndTabItem(); // STMM1B Logs ImGui::BeginTabItem("STMM1B"); ImGui::EndTabItem(); // STMM1C Logs ImGui::BeginTabItem("STMM1C"); ImGui::EndTabItem(); ImGui::EndTabBar(); ImGui::End(); } if (!_this->enabled) { style::endDisabled(); } } static void sinkHandler(uint8_t* data, int count, void* ctx) { Falcon9DecoderModule* _this = (Falcon9DecoderModule*)ctx; uint16_t length = (((data[0] & 0b1111) << 8) | data[1]) + 2; uint64_t pktId = ((uint64_t)data[2] << 56) | ((uint64_t)data[3] << 48) | ((uint64_t)data[4] << 40) | ((uint64_t)data[5] << 32) | ((uint64_t)data[6] << 24) | ((uint64_t)data[7] << 16) | ((uint64_t)data[8] << 8) | data[9]; if (pktId == 0x0117FE0800320303 || pktId == 0x0112FA0800320303) { data[length - 2] = 0; _this->logsMtx.lock(); _this->gpsLogs += (char*)(data + 25); _this->logsMtx.unlock(); } else if (pktId == 0x01123201042E1403) { fwrite(data + 25, 1, 940, _this->ffplay); file.write((char*)(data + 25), 940); } //printf("%016" PRIX64 ": %d bytes, %d full\n", pktId, length, count); } static void symSinkHandler(float* data, int count, void* ctx) { Falcon9DecoderModule* _this = (Falcon9DecoderModule*)ctx; float* buf = _this->symDiag.acquireBuffer(); memcpy(buf, data, 1024*sizeof(float)); _this->symDiag.releaseBuffer(); } std::string name; bool enabled = true; bool logsVisible = false; std::mutex logsMtx; std::string gpsLogs = ""; // DSP Chain dsp::FloatFMDemod demod; dsp::MMClockRecovery recov; dsp::Splitter split; dsp::stream reshapeInput; dsp::Reshaper reshape; dsp::HandlerSink symSink; dsp::stream thrInput; dsp::Threshold thr; uint8_t syncWord[32] = {0,0,0,1,1,0,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,0,1}; dsp::Deframer deframe; dsp::FalconRS falconRS; dsp::FalconPacketSync pkt; dsp::HandlerSink sink; FILE* ffplay; VFOManager::VFO* vfo; ImGui::SymbolDiagram symDiag; }; MOD_EXPORT void _INIT_() { // Nothing } MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) { return new Falcon9DecoderModule(name); } MOD_EXPORT void _DELETE_INSTANCE_(void* instance) { delete (Falcon9DecoderModule*)instance; } MOD_EXPORT void _END_() { // Nothing either }