Externalize Remote (#2370)

* externalize Remote app, disabling fileman integration (need workaround)

* regenerate bitmap.hpp

* added external HOME apps to HOME
This commit is contained in:
gullradriel 2024-11-19 21:02:29 +01:00 committed by GitHub
parent 4a83118557
commit 24d15c1643
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 835 additions and 594 deletions

View File

@ -303,7 +303,6 @@ set(CPPSRC
apps/ui_rds.cpp apps/ui_rds.cpp
apps/ui_recon_settings.cpp apps/ui_recon_settings.cpp
apps/ui_recon.cpp apps/ui_recon.cpp
apps/ui_remote.cpp
apps/ui_scanner.cpp apps/ui_scanner.cpp
apps/ui_sd_over_usb.cpp apps/ui_sd_over_usb.cpp
apps/ui_sd_wipe.cpp apps/ui_sd_wipe.cpp

View File

@ -27,7 +27,6 @@
#include <algorithm> #include <algorithm>
#include "ui_fileman.hpp" #include "ui_fileman.hpp"
#include "ui_playlist.hpp" #include "ui_playlist.hpp"
#include "ui_remote.hpp"
#include "ui_ss_viewer.hpp" #include "ui_ss_viewer.hpp"
#include "ui_bmp_file_viewer.hpp" #include "ui_bmp_file_viewer.hpp"
#include "ui_text_editor.hpp" #include "ui_text_editor.hpp"
@ -704,10 +703,11 @@ bool FileManagerView::handle_file_open() {
reload_current(false); reload_current(false);
return true; return true;
} else if (path_iequal(rem_ext, ext)) { }
/*else if (path_iequal(rem_ext, ext)) {
nav_.push<RemoteView>(path); nav_.push<RemoteView>(path);
return true; return true;
} }*/
return false; return false;
} }

File diff suppressed because it is too large Load Diff

View File

@ -126,7 +126,10 @@ set(EXTCPPSRC
#flippertx #flippertx
external/flippertx/main.cpp external/flippertx/main.cpp
external/flippertx/ui_flippertx.cpp external/flippertx/ui_flippertx.cpp
#remote
external/remote/main.cpp
external/remote/ui_remote.cpp
) )
set(EXTAPPLIST set(EXTAPPLIST
@ -160,4 +163,5 @@ set(EXTAPPLIST
ook_editor ook_editor
shoppingcart_lock shoppingcart_lock
flippertx flippertx
remote
) )

View File

@ -53,6 +53,7 @@ MEMORY
ram_external_app_ookbrute(rwx) : org = 0xADCC0000, len = 32k ram_external_app_ookbrute(rwx) : org = 0xADCC0000, len = 32k
ram_external_app_flippertx(rwx) : org = 0xADCD0000, len = 32k ram_external_app_flippertx(rwx) : org = 0xADCD0000, len = 32k
ram_external_app_ook_editor(rwx) : org = 0xADCE0000, len = 32k ram_external_app_ook_editor(rwx) : org = 0xADCE0000, len = 32k
ram_external_app_remote(rwx) : org = 0xADCF0000, len = 32k
} }
SECTIONS SECTIONS
@ -238,4 +239,9 @@ SECTIONS
*(*ui*external_app*flippertx*); *(*ui*external_app*flippertx*);
} > ram_external_app_flippertx } > ram_external_app_flippertx
.external_app_remote : ALIGN(4) SUBALIGN(4)
{
KEEP(*(.external_app.app_remote.application_information));
*(*ui*external_app*remote*);
} > ram_external_app_remote
} }

View File

@ -0,0 +1,82 @@
/*
* Copyright (C) 2024 gullradriel
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui.hpp"
#include "ui_remote.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::remote {
void initialize_app(ui::NavigationView& nav) {
nav.push<RemoteAppView>();
}
} // namespace ui::external_app::remote
extern "C" {
__attribute__((section(".external_app.app_remote.application_information"), used)) application_information_t _application_information_remote = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::remote::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "Remote",
/*.bitmap_data = */ {
0x20,
0x00,
0x20,
0x00,
0x20,
0x00,
0x20,
0x00,
0xE0,
0x07,
0xF0,
0x0F,
0x30,
0x0C,
0x30,
0x0C,
0xF0,
0x0F,
0xF0,
0x0F,
0x70,
0x0D,
0xB0,
0x0E,
0x70,
0x0D,
0xB0,
0x0E,
0xF0,
0x0F,
0xE0,
0x07,
},
/*.icon_color = */ ui::Color::green().v,
/*.menu_location = */ app_location_t::HOME,
/*.m4_app_tag = portapack::spi_flash::image_tag_replay */ {'P', 'R', 'E', 'P'},
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
};
}

View File

@ -20,7 +20,6 @@
*/ */
#include "ui_remote.hpp" #include "ui_remote.hpp"
#include "binder.hpp" #include "binder.hpp"
#include "convert.hpp" #include "convert.hpp"
#include "file_reader.hpp" #include "file_reader.hpp"
@ -34,11 +33,11 @@
#include "utility.hpp" #include "utility.hpp"
#include "file_path.hpp" #include "file_path.hpp"
namespace ui::external_app::remote {
using namespace portapack; using namespace portapack;
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace ui {
static constexpr uint8_t text_edit_max = 30; static constexpr uint8_t text_edit_max = 30;
/* RemoteEntryModel **************************************/ /* RemoteEntryModel **************************************/
@ -309,9 +308,9 @@ void RemoteEntryEditView::load_path(std::filesystem::path&& path) {
entry_.metadata = {transmitter_model.target_frequency(), 500'000}; entry_.metadata = {transmitter_model.target_frequency(), 500'000};
} }
/* RemoteView ********************************************/ /* RemoteAppView ********************************************/
RemoteView::RemoteView( RemoteAppView::RemoteAppView(
NavigationView& nav) NavigationView& nav)
: nav_{nav} { : nav_{nav} {
baseband::run_image(portapack::spi_flash::image_tag_replay); baseband::run_image(portapack::spi_flash::image_tag_replay);
@ -365,27 +364,27 @@ RemoteView::RemoteView(
refresh_ui(); refresh_ui();
} }
RemoteView::RemoteView(NavigationView& nav, fs::path path) RemoteAppView::RemoteAppView(NavigationView& nav, fs::path path)
: RemoteView(nav) { : RemoteAppView(nav) {
load_remote(std::move(path)); load_remote(std::move(path));
refresh_ui(); refresh_ui();
} }
RemoteView::~RemoteView() { RemoteAppView::~RemoteAppView() {
stop(); stop();
baseband::shutdown(); baseband::shutdown();
save_remote(/*show_error*/ false); save_remote(/*show_error*/ false);
} }
void RemoteView::focus() { void RemoteAppView::focus() {
if (model_.entries.empty()) if (model_.entries.empty())
button_add.focus(); button_add.focus();
else else
buttons_[0]->focus(); buttons_[0]->focus();
} }
void RemoteView::create_buttons() { void RemoteAppView::create_buttons() {
// Handler callbacks. // Handler callbacks.
auto handle_send = [this](RemoteButton& btn) { auto handle_send = [this](RemoteButton& btn) {
if (btn.entry()->path.empty()) if (btn.entry()->path.empty())
@ -420,7 +419,7 @@ void RemoteView::create_buttons() {
} }
} }
void RemoteView::reset_buttons() { void RemoteAppView::reset_buttons() {
// Whever the model's entries instance is invalidated, // Whever the model's entries instance is invalidated,
// all the pointers in the buttons will end up dangling. // all the pointers in the buttons will end up dangling.
// TODO: This is pretty lame. Could maybe static alloc? // TODO: This is pretty lame. Could maybe static alloc?
@ -428,7 +427,7 @@ void RemoteView::reset_buttons() {
btn->set_entry(nullptr); btn->set_entry(nullptr);
} }
void RemoteView::refresh_ui() { void RemoteAppView::refresh_ui() {
field_title.set_text(model_.name); field_title.set_text(model_.name);
field_filename.set_text(remote_path_.stem().string()); field_filename.set_text(remote_path_.stem().string());
@ -441,7 +440,7 @@ void RemoteView::refresh_ui() {
} }
} }
void RemoteView::add_button() { void RemoteAppView::add_button() {
if (model_.entries.size() >= max_buttons) if (model_.entries.size() >= max_buttons)
return; return;
@ -454,7 +453,7 @@ void RemoteView::add_button() {
set_needs_save(); set_needs_save();
} }
void RemoteView::edit_button(RemoteButton& btn) { void RemoteAppView::edit_button(RemoteButton& btn) {
// Don't let replay thread read the model while editing. // Don't let replay thread read the model while editing.
stop(); stop();
@ -471,7 +470,7 @@ void RemoteView::edit_button(RemoteButton& btn) {
}; };
} }
void RemoteView::send_button(RemoteButton& btn) { void RemoteAppView::send_button(RemoteButton& btn) {
// TODO: If this is called while is_sending() == true, // TODO: If this is called while is_sending() == true,
// it just stops and doesn't start the new button? // it just stops and doesn't start the new button?
@ -510,14 +509,14 @@ void RemoteView::send_button(RemoteButton& btn) {
}); });
} }
void RemoteView::stop() { void RemoteAppView::stop() {
// This terminates the underlying chThread. // This terminates the underlying chThread.
replay_thread_.reset(); replay_thread_.reset();
transmitter_model.disable(); transmitter_model.disable();
ready_signal_ = false; ready_signal_ = false;
} }
void RemoteView::new_remote() { void RemoteAppView::new_remote() {
save_remote(); save_remote();
init_remote(); init_remote();
refresh_ui(); refresh_ui();
@ -526,7 +525,7 @@ void RemoteView::new_remote() {
set_dirty(); set_dirty();
} }
void RemoteView::open_remote() { void RemoteAppView::open_remote() {
auto open_view = nav_.push<FileLoadView>(".REM"); auto open_view = nav_.push<FileLoadView>(".REM");
open_view->push_dir(remotes_dir); open_view->push_dir(remotes_dir);
open_view->on_changed = [this](fs::path path) { open_view->on_changed = [this](fs::path path) {
@ -536,7 +535,7 @@ void RemoteView::open_remote() {
}; };
} }
void RemoteView::init_remote() { void RemoteAppView::init_remote() {
model_ = {"<Unnamed Remote>", {}}; model_ = {"<Unnamed Remote>", {}};
reset_buttons(); reset_buttons();
set_remote_path(next_filename_matching_pattern(remotes_dir / u"REMOTE_????.REM")); set_remote_path(next_filename_matching_pattern(remotes_dir / u"REMOTE_????.REM"));
@ -546,14 +545,14 @@ void RemoteView::init_remote() {
show_error("Couldn't make new remote file."); show_error("Couldn't make new remote file.");
} }
bool RemoteView::load_remote(fs::path&& path) { bool RemoteAppView::load_remote(fs::path&& path) {
set_remote_path(std::move(path)); set_remote_path(std::move(path));
set_needs_save(false); set_needs_save(false);
reset_buttons(); reset_buttons();
return model_.load(remote_path_); return model_.load(remote_path_);
} }
void RemoteView::save_remote(bool show_errors) { void RemoteAppView::save_remote(bool show_errors) {
if (!needs_save_) if (!needs_save_)
return; return;
@ -564,7 +563,7 @@ void RemoteView::save_remote(bool show_errors) {
set_needs_save(false); set_needs_save(false);
} }
void RemoteView::rename_remote(const std::string& new_name) { void RemoteAppView::rename_remote(const std::string& new_name) {
auto folder = remote_path_.parent_path(); auto folder = remote_path_.parent_path();
auto ext = remote_path_.extension(); auto ext = remote_path_.extension();
auto new_path = folder / new_name + ext; auto new_path = folder / new_name + ext;
@ -581,7 +580,7 @@ void RemoteView::rename_remote(const std::string& new_name) {
set_remote_path(std::move(new_path)); set_remote_path(std::move(new_path));
} }
void RemoteView::handle_replay_thread_done(uint32_t return_code) { void RemoteAppView::handle_replay_thread_done(uint32_t return_code) {
if (return_code == ReplayThread::END_OF_FILE) { if (return_code == ReplayThread::END_OF_FILE) {
if (check_loop.value() && current_btn_) { if (check_loop.value() && current_btn_) {
send_button(*current_btn_); send_button(*current_btn_);
@ -598,15 +597,15 @@ void RemoteView::handle_replay_thread_done(uint32_t return_code) {
stop(); stop();
} }
void RemoteView::set_remote_path(fs::path&& path) { void RemoteAppView::set_remote_path(fs::path&& path) {
// Unfortunately, have to keep these two in sync because // Unfortunately, have to keep these two in sync because
// settings doesn't know about fs::path. // settings doesn't know about fs::path.
remote_path_ = std::move(path); remote_path_ = std::move(path);
settings_.remote_path = remote_path_.string(); settings_.remote_path = remote_path_.string();
} }
void RemoteView::show_error(const std::string& msg) const { void RemoteAppView::show_error(const std::string& msg) const {
nav_.display_modal("Error", msg); nav_.display_modal("Error", msg);
} }
} /* namespace ui */ } // namespace ui::external_app::remote

View File

@ -41,7 +41,7 @@
#include <string_view> #include <string_view>
#include <vector> #include <vector>
namespace ui { namespace ui::external_app::remote {
/* Maps icon index to bitmap. */ /* Maps icon index to bitmap. */
class RemoteIcons { class RemoteIcons {
@ -257,14 +257,14 @@ class RemoteEntryEditView : public View {
}; };
/* App that allows for buttons to be bound to captures for playback. */ /* App that allows for buttons to be bound to captures for playback. */
class RemoteView : public View { class RemoteAppView : public View {
public: public:
RemoteView(NavigationView& nav); RemoteAppView(NavigationView& nav);
RemoteView(NavigationView& nav, std::filesystem::path path); RemoteAppView(NavigationView& nav, std::filesystem::path path);
~RemoteView(); ~RemoteAppView();
RemoteView(const RemoteView&) = delete; RemoteAppView(const RemoteAppView&) = delete;
RemoteView& operator=(const RemoteView&) = delete; RemoteAppView& operator=(const RemoteAppView&) = delete;
std::string title() const override { return "Remote"; }; std::string title() const override { return "Remote"; };
void focus() override; void focus() override;
@ -385,4 +385,4 @@ class RemoteView : public View {
}}; }};
}; };
} /* namespace ui */ } // namespace ui::external_app::remote

View File

@ -52,7 +52,6 @@
#include "ui_pocsag_tx.hpp" #include "ui_pocsag_tx.hpp"
#include "ui_rds.hpp" #include "ui_rds.hpp"
#include "ui_recon.hpp" #include "ui_recon.hpp"
#include "ui_remote.hpp"
#include "ui_scanner.hpp" #include "ui_scanner.hpp"
#include "ui_sd_over_usb.hpp" #include "ui_sd_over_usb.hpp"
#include "ui_sd_wipe.hpp" #include "ui_sd_wipe.hpp"
@ -126,7 +125,6 @@ const NavigationView::AppList NavigationView::appList = {
{nullptr, "Transmit", HOME, Color::cyan(), &bitmap_icon_transmit, new ViewFactory<TransmittersMenuView>()}, {nullptr, "Transmit", HOME, Color::cyan(), &bitmap_icon_transmit, new ViewFactory<TransmittersMenuView>()},
{"capture", "Capture", HOME, Color::red(), &bitmap_icon_capture, new ViewFactory<CaptureAppView>()}, {"capture", "Capture", HOME, Color::red(), &bitmap_icon_capture, new ViewFactory<CaptureAppView>()},
{"replay", "Replay", HOME, Color::green(), &bitmap_icon_replay, new ViewFactory<PlaylistView>()}, {"replay", "Replay", HOME, Color::green(), &bitmap_icon_replay, new ViewFactory<PlaylistView>()},
{"remote", "Remote", HOME, ui::Color::green(), &bitmap_icon_remote, new ViewFactory<RemoteView>()},
{"scanner", "Scanner", HOME, Color::green(), &bitmap_icon_scanner, new ViewFactory<ScannerView>()}, {"scanner", "Scanner", HOME, Color::green(), &bitmap_icon_scanner, new ViewFactory<ScannerView>()},
{"microphone", "Microphone", HOME, Color::green(), &bitmap_icon_microphone, new ViewFactory<MicTXView>()}, {"microphone", "Microphone", HOME, Color::green(), &bitmap_icon_microphone, new ViewFactory<MicTXView>()},
{"lookingglass", "Looking Glass", HOME, Color::green(), &bitmap_icon_looking, new ViewFactory<GlassView>()}, {"lookingglass", "Looking Glass", HOME, Color::green(), &bitmap_icon_looking, new ViewFactory<GlassView>()},
@ -851,6 +849,7 @@ SystemMenuView::SystemMenuView(NavigationView& nav)
void SystemMenuView::on_populate() { void SystemMenuView::on_populate() {
add_apps(nav_, *this, HOME); add_apps(nav_, *this, HOME);
addExternalItems(nav_, app_location_t::HOME, *this);
add_item({"HackRF", Theme::getInstance()->fg_cyan->foreground, &bitmap_icon_hackrf, [this]() { hackrf_mode(nav_); }}); add_item({"HackRF", Theme::getInstance()->fg_cyan->foreground, &bitmap_icon_hackrf, [this]() { hackrf_mode(nav_); }});
} }