diff --git a/firmware/application/apps/ui_search.cpp b/firmware/application/apps/ui_search.cpp index 86e041ac1..05138b1e5 100644 --- a/firmware/application/apps/ui_search.cpp +++ b/firmware/application/apps/ui_search.cpp @@ -31,6 +31,10 @@ using namespace portapack; namespace ui { +void SearchLogger::log_data(SearchRecentEntry& data) { + log_file.write_entry(";" + to_string_short_freq(data.frequency) + ";" + std::to_string(data.duration)); +} + template <> void RecentEntriesTable::draw( const Entry& entry, @@ -75,6 +79,7 @@ SearchView::SearchView( &check_snap, &options_snap, &big_display, + &check_log, &recent_entries_view}); baseband::set_spectrum(SEARCH_SLICE_WIDTH, 31); @@ -100,6 +105,14 @@ SearchView::SearchView( on_range_changed(); }); + check_log.on_select = [this](Checkbox&, bool v) { + logging = v; + if (logging) { + logger.append(logs_dir.string() + "/SEARCH_" + to_string_timestamp(rtc_time::now()) + ".CSV"); + logger.write_header(); + } + }; + bind(field_threshold, settings_.power_threshold); bind(check_snap, settings_.snap_search); bind(options_snap, settings_.snap_step); @@ -192,7 +205,6 @@ void SearchView::do_detection() { locked = true; locked_bin = bin_max; - // TODO: open Audio. } else text_infos.set("Out of range"); @@ -210,6 +222,7 @@ void SearchView::do_detection() { auto& entry = ::on_packet(recent, resolved_frequency); entry.set_duration(duration); + if (logging) logger.log_data(entry); recent_entries_view.set_dirty(); text_infos.set("Listening"); diff --git a/firmware/application/apps/ui_search.hpp b/firmware/application/apps/ui_search.hpp index 6d7c3afd1..cbcb46e71 100644 --- a/firmware/application/apps/ui_search.hpp +++ b/firmware/application/apps/ui_search.hpp @@ -26,6 +26,8 @@ #include "radio_state.hpp" #include "gradient.hpp" #include "ui_receiver.hpp" +#include "log_file.hpp" +#include "file_path.hpp" namespace ui { @@ -70,6 +72,21 @@ struct SearchRecentEntry { using SearchRecentEntries = RecentEntries; +class SearchLogger { + public: + Optional append(const std::filesystem::path& filename) { + return log_file.append(filename); + } + + void log_data(SearchRecentEntry& data); + void write_header() { + log_file.write_raw("Time;Freq;Duration;"); + } + + private: + LogFile log_file{}; +}; + class SearchView : public View { public: SearchView(NavigationView& nav); @@ -148,6 +165,8 @@ class SearchView : public View { uint16_t locked_bin = 0; uint8_t search_counter = 0; bool locked = false; + bool logging = false; + SearchLogger logger{}; void do_detection(); void do_timers(); @@ -169,6 +188,12 @@ class SearchView : public View { {{1 * 8, 25 * 8}, "Accuracy +/-4.9kHz", Theme::getInstance()->fg_light->foreground}, {{26 * 8, 25 * 8}, "MHz", Theme::getInstance()->fg_light->foreground}}; + Checkbox check_log{ + {24 * 8, 10 * 8}, + 3, + "LOG", + true}; + FrequencyField field_frequency_min{ {1 * 8, 1 * 16}}; FrequencyField field_frequency_max{