From b71f86bd7b19c1e06c8b1dea88d73caeee5e7a69 Mon Sep 17 00:00:00 2001 From: Aang23 Date: Thu, 24 Jul 2025 21:55:57 +0200 Subject: [PATCH] Experimental stuff --- plugins/bitview_app/main.cpp | 4 +- .../official_products_support/CMakeLists.txt | 2 +- .../official_products_support/main_loader.cpp | 7 +- .../main_loader_handle.cpp | 350 ++++++++++++++++++ plugins/tools_app/main.cpp | 4 +- plugins/wip_settings_editor_app/main.cpp | 4 +- plugins/wip_tracking_app/main.cpp | 4 +- src-interface/explorer/explorer.cpp | 106 ++++-- src-interface/explorer/explorer.h | 50 ++- src-testing/main.cpp | 228 ++++++------ src-testing/main_sqlite.cpp | 166 +++++++++ 11 files changed, 746 insertions(+), 179 deletions(-) create mode 100644 plugins/official_products_support/main_loader_handle.cpp create mode 100644 src-testing/main_sqlite.cpp diff --git a/plugins/bitview_app/main.cpp b/plugins/bitview_app/main.cpp index 6b33bf9b1..63f224e59 100644 --- a/plugins/bitview_app/main.cpp +++ b/plugins/bitview_app/main.cpp @@ -13,10 +13,10 @@ public: void init() { // TODOREWORK maybe a way to call up/init a handler? - satdump::eventBus->register_handler(renderExplorerLoaderButton); + satdump::eventBus->register_handler(renderExplorerLoaderButton); } - static void renderExplorerLoaderButton(const satdump::explorer::ExplorerApplication::RenderLoadMenuElementsEvent &evt) + static void renderExplorerLoaderButton(const satdump::explorer::RenderLoadMenuElementsEvent &evt) { if (ImGui::BeginMenu("File")) { diff --git a/plugins/official_products_support/CMakeLists.txt b/plugins/official_products_support/CMakeLists.txt index 7e6559578..b9466eee1 100644 --- a/plugins/official_products_support/CMakeLists.txt +++ b/plugins/official_products_support/CMakeLists.txt @@ -41,7 +41,7 @@ if(${HDF5_FOUND}) # TODOREWORK Maybe actually yes ANDROID? # Loader plugin if(BUILD_GUI) - file(GLOB_RECURSE loader_CPPS main_loader.cpp loader/*.cpp) + file(GLOB_RECURSE loader_CPPS main_loader.cpp loader/*.cpp main_loader_handle.cpp) add_library(official_products_loader_support SHARED ${loader_CPPS}) target_link_libraries(official_products_loader_support PUBLIC official_products_support satdump_interface) diff --git a/plugins/official_products_support/main_loader.cpp b/plugins/official_products_support/main_loader.cpp index a927146ef..904fb8516 100644 --- a/plugins/official_products_support/main_loader.cpp +++ b/plugins/official_products_support/main_loader.cpp @@ -15,6 +15,8 @@ namespace std::unique_ptr _loader = nullptr; } // namespace +void provideExplorerFileLoader(const satdump::explorer::ExplorerRequestFileLoad &evt); + class OfficalProductsLoaderSupport : public satdump::Plugin { public: @@ -23,7 +25,8 @@ public: void init() { satdump::eventBus->register_handler(registerConfigHandler); - satdump::eventBus->register_handler(renderExplorerLoaderButton); + satdump::eventBus->register_handler(renderExplorerLoaderButton); + satdump::eventBus->register_handler(provideExplorerFileLoader); if (satdump::satdump_cfg.main_cfg.contains("plugin_settings") && satdump::satdump_cfg.main_cfg["plugin_settings"].contains("official_products")) if (satdump::satdump_cfg.main_cfg["plugin_settings"]["official_products"].contains("enable_loader")) @@ -81,7 +84,7 @@ public: cfg["enable_loader"] = _enable_loader; } - static void renderExplorerLoaderButton(const satdump::explorer::ExplorerApplication::RenderLoadMenuElementsEvent &evt) + static void renderExplorerLoaderButton(const satdump::explorer::RenderLoadMenuElementsEvent &evt) { if (!_enable_loader) return; diff --git a/plugins/official_products_support/main_loader_handle.cpp b/plugins/official_products_support/main_loader_handle.cpp new file mode 100644 index 000000000..5404bcd80 --- /dev/null +++ b/plugins/official_products_support/main_loader_handle.cpp @@ -0,0 +1,350 @@ +#include "common/repack.h" +#include "core/resources.h" +#include "explorer/explorer.h" +#include "handlers/product/image_product_handler.h" +#include "nat2pro/formats/formats.h" +#include "nlohmann/json.hpp" +#include "nlohmann/json_utils.h" +#include "products/image_product.h" +#include "projection/standard/proj.h" +#include "projection/standard/proj_json.h" + +// TODOREWORK move somewhere else +namespace nat2pro +{ + inline int get_i4(uint8_t *buff) + { + // if (isbig) return *((int_4 *) buff); + uint8_t i4[4]; + i4[0] = buff[3]; + i4[1] = buff[2]; + i4[2] = buff[1]; + i4[3] = buff[0]; + return *((int *)i4); + } + + double get_r8(uint8_t *buff); + + std::shared_ptr decodeMSGNat(std::vector &msg_file) + { + uint8_t *buf = msg_file.data(); + + // Parse header + std::string mh_strs[48]; + mh_strs[0] = (char *)buf; + mh_strs[1] = (char *)buf + 80; + mh_strs[2] = (char *)buf + 160; + mh_strs[3] = (char *)buf + 240; + mh_strs[4] = (char *)buf + 320; + mh_strs[5] = (char *)buf + 400; + mh_strs[6] = (char *)buf + 480; + mh_strs[6] += (char *)buf + 526; + mh_strs[7] = (char *)buf + 542; + mh_strs[7] += (char *)buf + 588; + mh_strs[8] = (char *)buf + 604; + mh_strs[8] += (char *)buf + 650; + mh_strs[9] = (char *)buf + 666; + mh_strs[9] += (char *)buf + 712; + mh_strs[10] = (char *)buf + 728; + mh_strs[10] += (char *)buf + 774; + mh_strs[11] = (char *)buf + 2154; + mh_strs[12] = (char *)buf + 2234; + mh_strs[13] = (char *)buf + 2314; + mh_strs[14] = (char *)buf + 2394; + mh_strs[15] = (char *)buf + 2474; + mh_strs[16] = (char *)buf + 2554; + mh_strs[17] = (char *)buf + 2634; + mh_strs[18] = (char *)buf + 2714; + mh_strs[19] = (char *)buf + 2794; + mh_strs[20] = (char *)buf + 2874; + mh_strs[21] = (char *)buf + 2954; + mh_strs[22] = (char *)buf + 3034; + mh_strs[23] = (char *)buf + 3114; + mh_strs[24] = (char *)buf + 3194; + mh_strs[25] = (char *)buf + 3274; + mh_strs[26] = (char *)buf + 3354; + mh_strs[27] = (char *)buf + 3434; + mh_strs[28] = (char *)buf + 3514; + mh_strs[29] = (char *)buf + 3594; + mh_strs[30] = (char *)buf + 3674; + mh_strs[31] = (char *)buf + 3754; + mh_strs[32] = (char *)buf + 3834; + mh_strs[33] = (char *)buf + 3914; + mh_strs[34] = (char *)buf + 3994; + mh_strs[35] = (char *)buf + 4074; + mh_strs[36] = (char *)buf + 4154; + mh_strs[37] = (char *)buf + 4234; + mh_strs[38] = (char *)buf + 4314; + mh_strs[39] = (char *)buf + 4394; + mh_strs[40] = (char *)buf + 4474; + mh_strs[41] = (char *)buf + 4554; + mh_strs[42] = (char *)buf + 4634; + mh_strs[43] = (char *)buf + 4714; + mh_strs[44] = (char *)buf + 4794; + mh_strs[45] = (char *)buf + 4874; + mh_strs[46] = (char *)buf + 4954; + mh_strs[47] = (char *)buf + 5034; + + for (int i = 0; i < 48; i++) + logger->debug("L%d %s", i, mh_strs[i].substr(0, mh_strs[i].size() - 1).c_str()); + + // IMG Size + int vis_ir_x_size, vis_ir_y_size; + int hrv_x_size, hrv_y_size; + float longitude; + sscanf(mh_strs[44].c_str(), "NumberLinesVISIR : %d", &vis_ir_y_size); + sscanf(mh_strs[45].c_str(), "NumberColumnsVISIR : %d", &vis_ir_x_size); + sscanf(mh_strs[46].c_str(), "NumberLinesHRV : %d", &hrv_y_size); + sscanf(mh_strs[47].c_str(), "NumberColumnsHRV : %d", &hrv_x_size); + sscanf(mh_strs[14].c_str(), "LLOS : %f", &longitude); + + logger->warn("VIS/IR Size : %dx%d", vis_ir_x_size, vis_ir_y_size); + logger->warn("HRV Size : %dx%d", hrv_x_size, hrv_y_size); + logger->warn("Longitude : %f", longitude); + + // Product Timestamp & satellite name + std::string satellite_name = "Unknown MSG"; + time_t prod_timestamp = time(0); + { + std::tm timeS; + memset(&timeS, 0, sizeof(std::tm)); + if (sscanf(mh_strs[17].c_str(), "SSBT : %4d%2d%2d%2d%2d%2d.%*dZ", &timeS.tm_year, &timeS.tm_mon, &timeS.tm_mday, &timeS.tm_hour, &timeS.tm_min, &timeS.tm_sec) == 6) + { + timeS.tm_year -= 1900; + timeS.tm_mon -= 1; + timeS.tm_isdst = -1; + prod_timestamp = timegm(&timeS); + } + + int satnum = -1; + if (sscanf(mh_strs[13].c_str(), "ASTI : MSG%d", &satnum) == 1) + { + if (satnum == 1) + satellite_name = "MSG-1"; + else if (satnum == 2) + satellite_name = "MSG-2"; + else if (satnum == 3) + satellite_name = "MSG-3"; + else if (satnum == 4) + satellite_name = "MSG-4"; + } + } + + // Other data + long int headerpos, datapos, trailerpos; + sscanf(mh_strs[8].c_str(), "%*s : %*d %ld\n", &headerpos); + sscanf(mh_strs[9].c_str(), "%*s : %*d %ld\n", &datapos); + sscanf(mh_strs[10].c_str(), "%*s : %*d %ld\n", &trailerpos); + + char bandsel[16]; + sscanf(mh_strs[39].c_str(), "%*s : %s", bandsel); + + image::Image vis_ir_imgs[12]; + for (int channel = 0; channel < 12; channel++) + { + if (bandsel[channel] != 'X') + continue; + + vis_ir_imgs[channel].init(16, (channel == 11 ? hrv_x_size : vis_ir_x_size), (channel == 11 ? hrv_y_size : vis_ir_y_size), 1); + } + + // Read Trailer + //{ + uint8_t *header_ptr = buf + 38 + headerpos; + int hoffset = 1 + 60134 + 700 + 326058 + 101 + 72; + + logger->critical("-------------------------- %d", headerpos); + + double calibration_slope[12]; + double calibration_offset[12]; + + for (int i = 0; i < 12; i++) + { + calibration_slope[i] = get_r8(&header_ptr[hoffset + (i * 2 + 0) * 8]); + calibration_offset[i] = get_r8(&header_ptr[hoffset + (i * 2 + 1) * 8]); + logger->trace("Channel %d Calibration Slope %f Offset %f", i + 1, calibration_slope[i], calibration_offset[i]); + } + //} + + // Read Trailer + //{ + uint8_t *trailer_ptr = buf + 38 + trailerpos; + + // int trailer_version = trailer_ptr[0]; + + int offset = 1 + 2 + 14 + 12 + 192 + 6 * 12 + 16; + + int LowerSouthLineActual = get_i4(&trailer_ptr[offset + 0]); + int LowerNorthLineActual = get_i4(&trailer_ptr[offset + 4]); + int LowerEastColumnActual = get_i4(&trailer_ptr[offset + 8]); + int LowerWestColumnActual = get_i4(&trailer_ptr[offset + 12]); + + int UpperSouthLineActual = get_i4(&trailer_ptr[offset + 16]); + // int UpperNorthLineActual = get_i4(&trailer_ptr[offset + 20]); + int UpperEastColumnActual = get_i4(&trailer_ptr[offset + 24]); + // int UpperWestColumnActual = get_i4(&trailer_ptr[offset + 28]); + + logger->critical("LowerSouthLineActual : %d, LowerNorthLineActual : %d, LowerEastColumnActual : %d, LowerWestColumnActual : %d", LowerSouthLineActual, LowerNorthLineActual, + LowerEastColumnActual, LowerWestColumnActual); + //} + + uint16_t repacked_line[81920]; + + // Read line data + // uint8_t pkt_hdr[48]; + uint8_t *data_ptr = buf + datapos; + for (int line = 0; line < vis_ir_y_size; line++) + { + for (int channel = 0; channel < 12; channel++) + { + if (bandsel[channel] != 'X') + continue; + + for (int i = 0; i < (channel == 11 ? 3 : 1); i++) + { + // uint16_t seq_cnt = (data_ptr + 16)[0] << 8 | (data_ptr + 16)[1]; + uint32_t pkt_len = (data_ptr + 18)[0] << 24 | (data_ptr + 18)[1] << 16 | (data_ptr + 18)[2] << 8 | (data_ptr + 18)[3]; + + // logger->info("PKT %d CHANNEL %d SEQ %d LEN %d", line, channel, seq_cnt, pkt_len); + + int datasize = pkt_len - 15 - 27; + + repackBytesTo10bits(data_ptr + 38 + 27, datasize, repacked_line); + + if (channel < 11) + { + for (int x = 0; x < vis_ir_x_size; x++) + vis_ir_imgs[channel].set(line * vis_ir_x_size + x, repacked_line[x] << 6); + } + else + { + for (int x = 0; x < hrv_x_size; x++) + { + if (line * 3 + 4 > UpperSouthLineActual) + { + int xpos = x + UpperEastColumnActual; + if (xpos >= 0 && xpos < hrv_x_size) + vis_ir_imgs[channel].set((line * 3 + i) * hrv_x_size + xpos, repacked_line[x] << 6); + } + else + { + int xpos = x + LowerEastColumnActual; + if (xpos >= 0 && xpos < hrv_x_size) + vis_ir_imgs[channel].set((line * 3 + i) * hrv_x_size + xpos, repacked_line[x] << 6); + } + } + } + + data_ptr += 38 + 27 + datasize; + } + } + } + + // Saving + std::shared_ptr seviri_products = std::make_shared(); + seviri_products->instrument_name = "seviri"; + seviri_products->set_product_timestamp(prod_timestamp); + seviri_products->set_product_source(satellite_name); + + proj::projection_t proj; + proj.type = proj::ProjType_Geos; + proj.params.sweep_x = false; + proj.params.altitude = 35785831.00; + proj.proj_offset_x = -5568748.275756353; // 6378169; + proj.proj_offset_y = vis_ir_y_size == 1392 ? /*RSS CASE*/ 5572548.275756 : 5568748.275756353; // 6356583.80; + proj.proj_scalar_x = 3000.403165817; + proj.proj_scalar_y = -3000.403165817; + proj.lam0 = longitude * DEG2RAD; + nlohmann::json proj_cfg = proj; + proj_cfg["width"] = 3712; + proj_cfg["height"] = vis_ir_y_size; // 3712; + // proj_cfg["type"] = "geos"; + // proj_cfg["lon"] = longitude; + // proj_cfg["alt"] = 35792.74; + // proj_cfg["scale_x"] = 1.145; + // proj_cfg["scale_y"] = 1.145; + // proj_cfg["offset_x"] = -0.0005; + // proj_cfg["offset_y"] = 0.0005; + // proj_cfg["sweep_x"] = false; + seviri_products->set_proj_cfg(proj_cfg); + + nlohmann::json sev_config = loadJsonFile(resources::getResourcePath("calibration/SEVIRI_table.json")); + + for (int channel = 0; channel < 12; channel++) + { + if (bandsel[channel] != 'X') + continue; + vis_ir_imgs[channel].mirror(true, true); + + // Special case for RSS + if (channel == 11 && vis_ir_y_size == 1392) + { + auto img = vis_ir_imgs[channel]; + vis_ir_imgs[channel].fill(0); + for (int i = 0; i < hrv_x_size; i++) + { + for (int c = 0; c < hrv_y_size; c++) + { + int offset = i - 2690; + if (offset >= 0 && offset < hrv_x_size) + vis_ir_imgs[channel].set(0, offset, c, img.get(0, i, c)); + } + } + } + + double ratiox = double(vis_ir_x_size) / double(hrv_x_size); + double ratioy = double(vis_ir_y_size) / double(hrv_y_size); + seviri_products->images.push_back({channel, "SEVIRI-" + std::to_string(channel + 1), std::to_string(channel + 1), vis_ir_imgs[channel], 10, + channel == 11 ? satdump::ChannelTransform().init_affine(ratiox, ratioy, 0, 0) : satdump::ChannelTransform().init_none()}); + + if (channel < 3 || channel == 11) + seviri_products->set_channel_unit(channel, CALIBRATION_ID_REFLECTIVE_RADIANCE); + else + seviri_products->set_channel_unit(channel, CALIBRATION_ID_EMISSIVE_RADIANCE); + + seviri_products->set_channel_wavenumber(channel, freq_to_wavenumber(299792458.0 / (sev_config["wavelengths"][channel].get()))); + } + + nlohmann::json calib_cfg; + for (int i = 0; i < 12; i++) + { + calib_cfg["vars"]["slope"][i] = calibration_slope[i]; + calib_cfg["vars"]["offset"][i] = calibration_offset[i]; + } + + seviri_products->set_calibration("msg_nat_seviri", calib_cfg); + + return seviri_products; + } +} // namespace nat2pro + +void provideExplorerFileLoader(const satdump::explorer::ExplorerRequestFileLoad &evt) +{ + logger->critical(evt.file_name); + + int sat_num; + int len; + if (sscanf(evt.file_name.c_str(), "MSG%d-SEVI-MSG15-%*d-NA-%*d.%*dZ-NA.nat%n", &sat_num, &len) == 1 && len == evt.file_name.size()) + { + evt.loaders.push_back({"Official Products", [](std::string p, satdump::explorer::ExplorerApplication *e) + { + std::vector v; + { + std::ifstream f(p, std::ios::binary); + char c; + while (!f.eof()) + { + f.read(&c, 1); + v.push_back(c); + } + f.close(); + } + + auto pi = nat2pro::decodeMSGNat(v); + + e->addHandler(std::make_shared(pi)); + }}); + + logger->trace("MSG SEVIRI Images"); + } +} \ No newline at end of file diff --git a/plugins/tools_app/main.cpp b/plugins/tools_app/main.cpp index ed7f8047e..d5901350e 100644 --- a/plugins/tools_app/main.cpp +++ b/plugins/tools_app/main.cpp @@ -10,10 +10,10 @@ public: void init() { // TODOREWORK maybe a way to call up/init a handler? - satdump::eventBus->register_handler(renderExplorerLoaderButton); + satdump::eventBus->register_handler(renderExplorerLoaderButton); } - static void renderExplorerLoaderButton(const satdump::explorer::ExplorerApplication::RenderLoadMenuElementsEvent &evt) + static void renderExplorerLoaderButton(const satdump::explorer::RenderLoadMenuElementsEvent &evt) { if (ImGui::BeginMenu("File")) { diff --git a/plugins/wip_settings_editor_app/main.cpp b/plugins/wip_settings_editor_app/main.cpp index 7bae17371..aae4fb5f1 100644 --- a/plugins/wip_settings_editor_app/main.cpp +++ b/plugins/wip_settings_editor_app/main.cpp @@ -9,9 +9,9 @@ class WipSettingsEditorAppPlugin : public satdump::Plugin public: std::string getID() { return "wipsettings_app"; } - void init() { satdump::eventBus->register_handler(renderExplorerLoaderButton); } + void init() { satdump::eventBus->register_handler(renderExplorerLoaderButton); } - static void renderExplorerLoaderButton(const satdump::explorer::ExplorerApplication::RenderLoadMenuElementsEvent &evt) + static void renderExplorerLoaderButton(const satdump::explorer::RenderLoadMenuElementsEvent &evt) { if (ImGui::BeginMenu("File")) { diff --git a/plugins/wip_tracking_app/main.cpp b/plugins/wip_tracking_app/main.cpp index ecc3bcc97..e4334c56d 100644 --- a/plugins/wip_tracking_app/main.cpp +++ b/plugins/wip_tracking_app/main.cpp @@ -12,10 +12,10 @@ public: void init() { // TODOREWORK maybe a way to call up/init a handler? - satdump::eventBus->register_handler(renderExplorerLoaderButton); + satdump::eventBus->register_handler(renderExplorerLoaderButton); } - static void renderExplorerLoaderButton(const satdump::explorer::ExplorerApplication::RenderLoadMenuElementsEvent &evt) + static void renderExplorerLoaderButton(const satdump::explorer::RenderLoadMenuElementsEvent &evt) { if (ImGui::BeginMenu("File")) { diff --git a/src-interface/explorer/explorer.cpp b/src-interface/explorer/explorer.cpp index b23e3f335..09780271f 100644 --- a/src-interface/explorer/explorer.cpp +++ b/src-interface/explorer/explorer.cpp @@ -6,6 +6,7 @@ // #include "products/dataset.h" #include "common/utils.h" // #include "core/resources.h" +#include "core/exception.h" #include "core/plugin.h" #include "core/style.h" @@ -300,57 +301,80 @@ namespace satdump try { - if (!std::filesystem::path(path).has_extension()) - { - logger->error("Invalid file, no extension!"); - return; - } + // Get available loaders + std::vector>> loaders; + // Default stuff if (std::filesystem::path(path).extension().string() == ".cbor") - { - logger->trace("Explorer loading product " + path); + loaders.push_back({"Product Loader", [](std::string path, ExplorerApplication *e) + { + logger->trace("Explorer loading product " + path); - try - { - auto prod_h = handlers::getProductHandlerForProduct(products::loadProduct(path)); - addHandler(prod_h); - } - catch (std::exception &e) - { - logger->error("Error loading product! Maybe not a valid product? (Reminder : Pre-2.0.0 products are NOT compatible with 2.0.0) Details : %s", e.what()); - } - } + try + { + auto prod_h = handlers::getProductHandlerForProduct(products::loadProduct(path)); + e->addHandler(prod_h); + } + catch (std::exception &e) + { + logger->error("Error loading product! Maybe not a valid product? (Reminder : Pre-2.0.0 products are NOT compatible with 2.0.0) Details : %s", + e.what()); + } + }}); else if (std::filesystem::path(path).extension().string() == ".json") - { - logger->trace("Viewer loading dataset " + path); + loaders.push_back( + {"Dataset Loader", [](std::string path, ExplorerApplication *e) + { + logger->trace("Viewer loading dataset " + path); - try - { - products::DataSet dataset; - dataset.load(path); - std::shared_ptr dat_h = std::make_shared(std::filesystem::path(path).parent_path().string(), dataset); - addHandler(dat_h); - } - catch (std::exception &e) - { - logger->error("Error loading dataset! Maybe not a valid dataset? (Reminder : Pre-2.0.0 datasets are NOT compatible with 2.0.0) Details : %s", e.what()); - } - } + try + { + products::DataSet dataset; + dataset.load(path); + std::shared_ptr dat_h = std::make_shared(std::filesystem::path(path).parent_path().string(), dataset); + e->addHandler(dat_h); + } + catch (std::exception &e) + { + logger->error("Error loading dataset! Maybe not a valid dataset? (Reminder : Pre-2.0.0 datasets are NOT compatible with 2.0.0) Details : %s", e.what()); + } + }}); else if (std::filesystem::path(path).extension().string() == ".shp") + loaders.push_back({"Shapefile Loader", [](std::string path, ExplorerApplication *e) + { + logger->trace("Viewer loading shapefile " + path); + e->addHandler(std::make_shared(path)); + }}); +#if 0 // TODOREWORK ADD MENU + else if (std::filesystem::path(path).has_extension()) + loaders.push_back({"Image Loader", [](std::string path, ExplorerApplication *e) + { + logger->trace("Viewer loading image " + path); + + image::Image img; + image::load_img(img, path); + if (img.size() > 0) + e->addHandler(std::make_shared(img, std::filesystem::path(path).stem().string())); + else + logger->error("Could not open this file as image!"); + }}); +#endif + + // Plugin loaders + eventBus->fire_event({std::filesystem::path(path).stem().string() + std::filesystem::path(path).extension().string(), loaders}); + + // Load it + if (loaders.size() == 1) { - logger->trace("Viewer loading shapefile " + path); - addHandler(std::make_shared(path)); + loaders[0].second(path, this); + } + else if (loaders.size() > 1) + { + throw satdump_exception("More than one loader available! TODO SELECTION MENU!"); } else { - logger->trace("Viewer loading image " + path); - - image::Image img; - image::load_img(img, path); - if (img.size() > 0) - addHandler(std::make_shared(img, std::filesystem::path(path).stem().string())); - else - logger->error("Could not open this file as image!"); + throw satdump_exception("No loader found for file : " + path + "!"); } } catch (std::exception &e) diff --git a/src-interface/explorer/explorer.h b/src-interface/explorer/explorer.h index 4aaf54be9..f51b6f43e 100644 --- a/src-interface/explorer/explorer.h +++ b/src-interface/explorer/explorer.h @@ -11,15 +11,38 @@ namespace satdump { namespace explorer { + // Predef + class ExplorerApplication; + + // Events + struct RenderLoadMenuElementsEvent + { + std::shared_ptr &curr_handler; + std::shared_ptr &master_handler; + }; + + struct GetLastSelectedOfTypeEvent + { + std::string type; + std::shared_ptr &h; + }; + + struct ExplorerAddHandlerEvent + { + std::shared_ptr h; + bool open = false; + bool is_processing = false; + }; + + struct ExplorerRequestFileLoad + { + std::string file_name; + std::vector>> &loaders; + }; + + // Actual explorer class ExplorerApplication { - public: - struct RenderLoadMenuElementsEvent - { - std::shared_ptr &curr_handler; - std::shared_ptr &master_handler; - }; - public: void draw(); @@ -65,18 +88,5 @@ namespace satdump ~ExplorerApplication(); }; - // Events - struct GetLastSelectedOfTypeEvent - { - std::string type; - std::shared_ptr &h; - }; - - struct ExplorerAddHandlerEvent - { - std::shared_ptr h; - bool open = false; - bool is_processing = false; - }; } // namespace explorer }; // namespace satdump \ No newline at end of file diff --git a/src-testing/main.cpp b/src-testing/main.cpp index 87ef493b9..b163ae2e0 100644 --- a/src-testing/main.cpp +++ b/src-testing/main.cpp @@ -10,88 +10,138 @@ * Don't judge the code you might see in there! :) **********************************************************************/ -#include "common/tracking/tle.h" #include "core/exception.h" #include "init.h" +#include "libs/miniz/miniz.h" +#include "libs/miniz/miniz_zip.h" #include "logger.h" +#include +#include +#include +#include +#include -#include -#include -#include -#include -#include +class FilesIteratorItem +{ +public: + const std::string name; + FilesIteratorItem(std::string name) : name(name) {} + virtual std::vector getPayload() = 0; +}; -class SQLiteHandler +class FilesIterator +{ +public: + virtual bool getNext(std::unique_ptr &v) = 0; + virtual void reset() = 0; +}; + +class FolderFileIteratorItem : public FilesIteratorItem { private: - sqlite3 *db = nullptr; - - bool run_sql(std::string sql) - { - char *err = NULL; - if (sqlite3_exec(db, sql.c_str(), NULL, 0, &err)) - { - logger->error(err); - sqlite3_free(err); - return true; - } - return false; - } + const std::string path; public: - SQLiteHandler(std::string path) + FolderFileIteratorItem(std::string path, std::string name) : FilesIteratorItem(name), path(path) {} + + std::vector getPayload() { - // Open - if (sqlite3_open(path.c_str(), &db)) - throw satdump_exception("Couldn't open SQLite database! " + std::string(sqlite3_errmsg(db))); - else - logger->info("Opened SQLite Database!"); - sqlite3_busy_timeout(db, 1000); + std::vector v; + std::ifstream f(path, std::ios::binary); + char c; + while (!f.eof()) + { + f.read(&c, 1); + v.push_back(c); + } + f.close(); + return v; + } +}; - // Init - if (run_sql("PRAGMA journal_mode=WAL;")) - throw satdump_exception("Failed setting database to WAL mode!"); +class FolderFilesIterator : public FilesIterator +{ +private: + const std::string folder; + std::filesystem::recursive_directory_iterator filesIterator; + std::error_code iteratorError; - // Create TLE Table - std::string sql_create_tle = "CREATE TABLE IF NOT EXISTS tle(" - "norad INT PRIMARY KEY NOT NULL," - "name TEXT NOT NULL," - "line1 TEXT NOT NULL," - "line2 TEXT);"; - if (run_sql(sql_create_tle)) - throw satdump_exception("Failed creating TLE database!"); +public: + FolderFilesIterator(std::string folder) : folder(folder) { filesIterator = std::filesystem::recursive_directory_iterator(folder); } - // Create general settings table - std::string sql_create_settings = "CREATE TABLE IF NOT EXISTS settings(" - "id TEXT PRIMARY KEY NOT NULL," - "val TEXT NOT NULL);"; - if (run_sql(sql_create_settings)) - throw satdump_exception("Failed creating Settings database!"); + bool getNext(std::unique_ptr &v) + { + v.reset(); + + std::string path = filesIterator->path(); + + if (std::filesystem::is_regular_file(path)) + v = std::make_unique(path, std::filesystem::path(path).stem().string() + std::filesystem::path(path).extension().string()); + + filesIterator.increment(iteratorError); + if (iteratorError) + throw satdump_exception(iteratorError.message()); + + return filesIterator != std::filesystem::recursive_directory_iterator(); } - ~SQLiteHandler() { sqlite3_close(db); } + void reset() { filesIterator = std::filesystem::recursive_directory_iterator(folder); } +}; - sqlite3 *getdb() { return db; } +class ZipFileIteratorItem : public FilesIteratorItem +{ +private: + const mz_zip_archive *zip; + const int num; - satdump::TLE get_tle_from_norad(int norad) +public: + ZipFileIteratorItem(mz_zip_archive *zip, int num, std::string name) : FilesIteratorItem(name), zip(zip), num(num) {} + + std::vector getPayload() { - satdump::TLE r; - sqlite3_stmt *res; + size_t filesize = 0; + void *file_ptr = mz_zip_reader_extract_to_heap((mz_zip_archive *)&zip, num, &filesize, 0); + std::vector vec((uint8_t *)file_ptr, (uint8_t *)file_ptr + filesize); + mz_free(file_ptr); + return vec; + } +}; - if (sqlite3_prepare_v2(db, ("SELECT name,line1,line2 from tle where norad=" + std::to_string(norad)).c_str(), -1, &res, 0)) - throw satdump_exception("Couldn't fetch TLE from DB! " + std::string(sqlite3_errmsg(db))); +class ZipFilesIterator : public FilesIterator +{ +private: + mz_zip_archive zip{}; + int numfiles; + int file_index; - if (sqlite3_step(res) == SQLITE_ROW) +public: + ZipFilesIterator(std::string zipfile) + { + if (!mz_zip_reader_init_file(&zip, zipfile.c_str(), 0)) + throw satdump_exception("Invalid zip file! " + zipfile); + numfiles = mz_zip_reader_get_num_files(&zip); + file_index = 0; + } + + ~ZipFilesIterator() { mz_zip_reader_end(&zip); } + + bool getNext(std::unique_ptr &v) + { + v.reset(); + + if (mz_zip_reader_is_file_supported(&zip, file_index)) { - r.norad = norad; - r.name = (char *)sqlite3_column_text(res, 0); - r.line1 = (char *)sqlite3_column_text(res, 1); - r.line2 = (char *)sqlite3_column_text(res, 2); + char filename[2000]; + if (mz_zip_reader_get_filename(&zip, file_index, filename, 2000)) + v = std::make_unique(&zip, file_index, std::filesystem::path(filename).stem().string() + std::filesystem::path(filename).extension().string()); } - sqlite3_finalize(res); - return r; + file_index++; + + return file_index < numfiles; } + + void reset() { file_index = 0; } }; int main(int argc, char *argv[]) @@ -103,64 +153,28 @@ int main(int argc, char *argv[]) completeLoggerInit(); logger->set_level(slog::LOG_TRACE); - SQLiteHandler d("test.db"); + // std::unique_ptr fit = std::make_unique( + // "/tmp/satdump_official/W_XX-EUMETSAT-Darmstadt,IMG+SAT,MTI1+FCI-1C-RRAD-FDHSI-FD--x-x---x_C_EUMT_20250724111342_IDPFI_OPE_20250724111007_20250724111935_N__O_0068_0000 (2)"); - auto db = d.getdb(); + std::unique_ptr fit = std::make_unique( + "/tmp/satdump_official/W_XX-EUMETSAT-Darmstadt,IMG+SAT,MTI1+FCI-1C-RRAD-FDHSI-FD--x-x---x_C_EUMT_20250724120349_IDPFI_OPE_20250724120007_20250724120935_N__O_0073_0000.zip"); + std::unique_ptr f; + + while (fit->getNext(f)) { - nlohmann::json v; - v["test"] = 4384328; - v["v2"] = "djisoadjsoa"; - v["df"] = 5.66546; - char *err = NULL; - std::string sql = "INSERT INTO settings (id, val) VALUES ('testval', '" + v.dump() + "') ON CONFLICT(id) DO UPDATE SET val='" + v.dump() + "';"; - if (sqlite3_exec(db, sql.c_str(), NULL, 0, &err)) + if (f) { - logger->error(err); - sqlite3_free(err); - } - } -#if 1 - { - { - char *err = NULL; - std::string sql = "BEGIN;"; - if (sqlite3_exec(db, sql.c_str(), NULL, 0, &err)) + uint32_t test1, test2, test3; + if (sscanf(f->name.c_str(), "W_XX-EUMETSAT-Darmstadt,IMG+SAT,MTI%*d+FCI-1C-RRAD-FDHSI-FD--CHK-BODY---NC4E_C_EUMT_%14u_IDPFI_OPE_%14u_%14u_N__O_%*d_%*d.nc", &test1, &test2, &test3) == 3) { - logger->error(err); - sqlite3_free(err); + logger->trace(f->name + " MTG FCI Images"); } - } - - logger->info("INSERT"); - for (auto &tle : *satdump::general_tle_registry) - { - std::string sql = "INSERT INTO tle (norad, name, line1, line2) VALUES (" + std::to_string(tle.norad) + ", \"" + tle.name + "\", '" + tle.line1 + "', '" + tle.line2 + - "') ON CONFLICT(norad) DO UPDATE SET name=\"" + tle.name + "\", line1='" + tle.line1 + "', line2='" + tle.line2 + "';"; - - char *err = NULL; - if (sqlite3_exec(db, sql.c_str(), NULL, 0, &err)) + else { - logger->error(err); - logger->info(nlohmann::json(tle).dump()); - sqlite3_free(err); - } - } - logger->info("DONE"); - - { - char *err = NULL; - std::string sql = "END;"; - if (sqlite3_exec(db, sql.c_str(), NULL, 0, &err)) - { - logger->error(err); - sqlite3_free(err); + logger->info(f->name); } } } -#endif - - auto tle = d.get_tle_from_norad(40069); - logger->info(nlohmann::json(tle).dump()); } diff --git a/src-testing/main_sqlite.cpp b/src-testing/main_sqlite.cpp new file mode 100644 index 000000000..87ef493b9 --- /dev/null +++ b/src-testing/main_sqlite.cpp @@ -0,0 +1,166 @@ +/********************************************************************** + * This file is used for testing random stuff without running the + * whole of SatDump, which comes in handy for debugging individual + * elements before putting them all together in modules... + * + * If you are an user, ignore this file which will not be built by + * default, and if you're a developper in need of doing stuff here... + * Go ahead! + * + * Don't judge the code you might see in there! :) + **********************************************************************/ + +#include "common/tracking/tle.h" +#include "core/exception.h" +#include "init.h" +#include "logger.h" + +#include +#include +#include +#include +#include + +class SQLiteHandler +{ +private: + sqlite3 *db = nullptr; + + bool run_sql(std::string sql) + { + char *err = NULL; + if (sqlite3_exec(db, sql.c_str(), NULL, 0, &err)) + { + logger->error(err); + sqlite3_free(err); + return true; + } + return false; + } + +public: + SQLiteHandler(std::string path) + { + // Open + if (sqlite3_open(path.c_str(), &db)) + throw satdump_exception("Couldn't open SQLite database! " + std::string(sqlite3_errmsg(db))); + else + logger->info("Opened SQLite Database!"); + sqlite3_busy_timeout(db, 1000); + + // Init + if (run_sql("PRAGMA journal_mode=WAL;")) + throw satdump_exception("Failed setting database to WAL mode!"); + + // Create TLE Table + std::string sql_create_tle = "CREATE TABLE IF NOT EXISTS tle(" + "norad INT PRIMARY KEY NOT NULL," + "name TEXT NOT NULL," + "line1 TEXT NOT NULL," + "line2 TEXT);"; + if (run_sql(sql_create_tle)) + throw satdump_exception("Failed creating TLE database!"); + + // Create general settings table + std::string sql_create_settings = "CREATE TABLE IF NOT EXISTS settings(" + "id TEXT PRIMARY KEY NOT NULL," + "val TEXT NOT NULL);"; + if (run_sql(sql_create_settings)) + throw satdump_exception("Failed creating Settings database!"); + } + + ~SQLiteHandler() { sqlite3_close(db); } + + sqlite3 *getdb() { return db; } + + satdump::TLE get_tle_from_norad(int norad) + { + satdump::TLE r; + sqlite3_stmt *res; + + if (sqlite3_prepare_v2(db, ("SELECT name,line1,line2 from tle where norad=" + std::to_string(norad)).c_str(), -1, &res, 0)) + throw satdump_exception("Couldn't fetch TLE from DB! " + std::string(sqlite3_errmsg(db))); + + if (sqlite3_step(res) == SQLITE_ROW) + { + r.norad = norad; + r.name = (char *)sqlite3_column_text(res, 0); + r.line1 = (char *)sqlite3_column_text(res, 1); + r.line2 = (char *)sqlite3_column_text(res, 2); + } + + sqlite3_finalize(res); + return r; + } +}; + +int main(int argc, char *argv[]) +{ + initLogger(); + + logger->set_level(slog::LOG_OFF); + satdump::initSatdump(); + completeLoggerInit(); + logger->set_level(slog::LOG_TRACE); + + SQLiteHandler d("test.db"); + + auto db = d.getdb(); + + { + nlohmann::json v; + v["test"] = 4384328; + v["v2"] = "djisoadjsoa"; + v["df"] = 5.66546; + char *err = NULL; + std::string sql = "INSERT INTO settings (id, val) VALUES ('testval', '" + v.dump() + "') ON CONFLICT(id) DO UPDATE SET val='" + v.dump() + "';"; + if (sqlite3_exec(db, sql.c_str(), NULL, 0, &err)) + { + logger->error(err); + sqlite3_free(err); + } + } + +#if 1 + { + { + char *err = NULL; + std::string sql = "BEGIN;"; + if (sqlite3_exec(db, sql.c_str(), NULL, 0, &err)) + { + logger->error(err); + sqlite3_free(err); + } + } + + logger->info("INSERT"); + for (auto &tle : *satdump::general_tle_registry) + { + std::string sql = "INSERT INTO tle (norad, name, line1, line2) VALUES (" + std::to_string(tle.norad) + ", \"" + tle.name + "\", '" + tle.line1 + "', '" + tle.line2 + + "') ON CONFLICT(norad) DO UPDATE SET name=\"" + tle.name + "\", line1='" + tle.line1 + "', line2='" + tle.line2 + "';"; + + char *err = NULL; + if (sqlite3_exec(db, sql.c_str(), NULL, 0, &err)) + { + logger->error(err); + logger->info(nlohmann::json(tle).dump()); + sqlite3_free(err); + } + } + logger->info("DONE"); + + { + char *err = NULL; + std::string sql = "END;"; + if (sqlite3_exec(db, sql.c_str(), NULL, 0, &err)) + { + logger->error(err); + sqlite3_free(err); + } + } + } +#endif + + auto tle = d.get_tle_from_norad(40069); + logger->info(nlohmann::json(tle).dump()); +}