diff --git a/firmware/application/apps/ui_flash_utility.cpp b/firmware/application/apps/ui_flash_utility.cpp index be9e0dce..0ea1f2b6 100644 --- a/firmware/application/apps/ui_flash_utility.cpp +++ b/firmware/application/apps/ui_flash_utility.cpp @@ -25,6 +25,8 @@ namespace ui { +static const char16_t* firmware_folder = u"/FIRMWARE"; + Thread* FlashUtilityView::thread{nullptr}; static constexpr size_t max_filename_length = 26; @@ -35,7 +37,9 @@ FlashUtilityView::FlashUtilityView(NavigationView& nav) menu_view.set_parent_rect({0, 3 * 8, 240, 33 * 8}); - for (const auto& entry : std::filesystem::directory_iterator(u"FIRMWARE", u"*.bin")) { + ensure_directory(firmware_folder); + + for (const auto& entry : std::filesystem::directory_iterator(firmware_folder, u"*.bin")) { auto filename = entry.path().filename(); auto path = entry.path().native(); diff --git a/firmware/application/apps/ui_playlist.cpp b/firmware/application/apps/ui_playlist.cpp index 2d1c816b..466a067f 100644 --- a/firmware/application/apps/ui_playlist.cpp +++ b/firmware/application/apps/ui_playlist.cpp @@ -40,6 +40,10 @@ using namespace portapack; namespace fs = std::filesystem; +/* TODO + * - Should frequency overrides be saved in the playlist? + */ + namespace ui { void PlaylistView::load_file(const fs::path& playlist_path) { @@ -79,11 +83,9 @@ Optional PlaylistView::load_entry(fs::path&& path) auto metadata_path = get_metadata_path(path); auto metadata = read_metadata_file(metadata_path); - // TODO: For now, require a metadata file. Eventually, - // allow a user-defined center_freq like there was in Replay. - // metadata = {0, 500'000}; + // If no metadata found, fallback to the TX frequency. if (!metadata) - return {}; + metadata = {transmitter_model.target_frequency(), 500'000}; return playlist_entry{ std::move(path), @@ -126,6 +128,8 @@ void PlaylistView::save_file(bool show_dialogs) { if (!playlist_dirty_ || playlist_path_.empty()) return; + ensure_directory(playlist_path_.parent_path()); + File playlist_file; auto error = playlist_file.create(playlist_path_.string()); @@ -185,7 +189,7 @@ void PlaylistView::show_file_error(const fs::path& path, const std::string& mess nav_.display_modal("Error", "Error opening file \n" + path.string() + "\n" + message); } -const PlaylistView::playlist_entry* PlaylistView::current() const { +PlaylistView::playlist_entry* PlaylistView::current() { return playlist_db_.empty() ? nullptr : &playlist_db_[current_index_]; } @@ -289,10 +293,9 @@ void PlaylistView::stop() { void PlaylistView::update_ui() { if (playlist_db_.empty()) { - text_filename.set(""); + text_filename.set("-"); text_sample_rate.set("-"); text_duration.set("-"); - text_frequency.set("-"); if (playlist_path_.empty()) text_track.set("Open playlist or add capture."); @@ -311,7 +314,7 @@ void PlaylistView::update_ui() { auto duration = ms_duration(current()->file_size, current()->metadata.sample_rate, 4); text_duration.set(to_string_time_ms(duration)); - text_frequency.set(to_string_short_freq(current()->metadata.center_frequency)); + field_frequency.set_value(current()->metadata.center_frequency); text_track.set( to_string_dec_uint(current_index_ + 1) + "/" + @@ -355,7 +358,7 @@ PlaylistView::PlaylistView( &text_duration, &progressbar_track, &progressbar_transmit, - &text_frequency, + &field_frequency, &tx_view, &check_loop, &button_play, @@ -371,6 +374,18 @@ PlaylistView::PlaylistView( waterfall.show_audio_spectrum_view(false); + field_frequency.set_value(100'000'000); + field_frequency.on_change = [this](rf::Frequency f) { + if (current()) + current()->metadata.center_frequency = f; + }; + field_frequency.on_edit = [this]() { + auto freq_view = nav_.push(field_frequency.value()); + freq_view->on_changed = [this](rf::Frequency f) { + field_frequency.set_value(f); + }; + }; + button_play.on_select = [this](ImageButton&) { toggle(); }; diff --git a/firmware/application/apps/ui_playlist.hpp b/firmware/application/apps/ui_playlist.hpp index b086d1b6..c965838d 100644 --- a/firmware/application/apps/ui_playlist.hpp +++ b/firmware/application/apps/ui_playlist.hpp @@ -90,7 +90,7 @@ class PlaylistView : public View { const std::filesystem::path& path, const std::string& message); - const playlist_entry* current() const; + playlist_entry* current(); bool is_active() const; bool at_end() const; @@ -110,10 +110,8 @@ class PlaylistView : public View { Text text_filename{ {0 * 8, 0 * 16, 30 * 8, 16}}; - // TODO: delay duration field. - // TODO: TxFrequencyField to edit entry frequency. - Text text_frequency{ - {0 * 8, 1 * 16, 9 * 8, 16}}; + FrequencyField field_frequency{ + {0 * 8, 1 * 16}}; Text text_sample_rate{ {10 * 8, 1 * 16, 7 * 8, 16}}; @@ -127,6 +125,8 @@ class PlaylistView : public View { Text text_duration{ {0 * 8, 2 * 16, 5 * 8, 16}}; + // TODO: delay duration field. + TransmitterView2 tx_view{ 9 * 8, 1 * 8, SHORT_UI}; diff --git a/firmware/common/optional.hpp b/firmware/common/optional.hpp index d382b957..38e492f6 100644 --- a/firmware/common/optional.hpp +++ b/firmware/common/optional.hpp @@ -34,6 +34,17 @@ class Optional { constexpr Optional(T&& value) : value_{std::move(value)}, valid_{true} {} + constexpr Optional& operator=(const T& value) { + value_ = value; + valid_ = true; + return *this; + } + constexpr Optional& operator=(T&& value) { + value_ = std::move(value); + valid_ = true; + return *this; + } + bool is_valid() const { return valid_; } operator bool() const { return valid_; }