Compare commits
88 Commits
125ff11431
...
e99fd4787a
Author | SHA1 | Date |
---|---|---|
summermorningdream | e99fd4787a | |
summermorningdream | 9f0a0c55e5 | |
zxkmm | 6c37d883a0 | |
zxkmm | 5d7cfda97b | |
zxkmm | 9fc45b32c9 | |
sommermorgentraum | b27a313118 | |
zxkmm | f2c86862c0 | |
sommermorgentraum | 8c0715408d | |
sommermorgentraum | 3eb6cf47ae | |
sommermorgentraum | c288f703da | |
zxkmm | 208a89090a | |
zxkmm | 6b3ea87d86 | |
zxkmm | 17b9231601 | |
zxkmm | cc89e2af9e | |
zxkmm | 77ba7bde98 | |
zxkmm | e2940a52f2 | |
zxkmm | 348ef17131 | |
zxkmm | c00dfeed3f | |
zxkmm | 7cbba2d2e7 | |
zxkmm | c36c9c9389 | |
zxkmm | a00543b4f8 | |
zxkmm | 75a930c1fa | |
zxkmm | d3f618fa5b | |
zxkmm | 6d2b290daa | |
zxkmm | 9e67e250b2 | |
zxkmm | 6b4abbc5f7 | |
zxkmm | 1b410675f6 | |
zxkmm | 24ff586155 | |
zxkmm | 6cdcb16a3a | |
zxkmm | 7a3b4966b4 | |
zxkmm | 50af3c605f | |
zxkmm | 6a56d743fc | |
zxkmm | 2a903bf9e4 | |
zxkmm | d150e39852 | |
zxkmm | d3e8260318 | |
zxkmm | fa596227ef | |
zxkmm | d4296ed434 | |
zxkmm | 923324e931 | |
zxkmm | 98c1b05e81 | |
zxkmm | 4ab6a38507 | |
zxkmm | 7d48624a78 | |
zxkmm | 6c36d45005 | |
zxkmm | 940c2d7682 | |
sommermorgentraum | a08ccf4f2e | |
zxkmm | 5e10a41331 | |
zxkmm | a0a2ff9724 | |
zxkmm | 04966f2e0f | |
zxkmm | 5b5b5333e9 | |
sommermorgentraum | 8d032438bd | |
zxkmm | 9460177fc9 | |
zxkmm | 675925269c | |
zxkmm | 119ebfe90e | |
zxkmm | 457eb71014 | |
sommermorgentraum | 6fb09f6d59 | |
not tre mann | e38c370d7d | |
not tre mann | b04bd4c0d9 | |
zxkmm | c5039f2eb0 | |
zxkmm | 93825234f3 | |
zxkmm | 5181923fc6 | |
zxkmm | 1451d49f8a | |
not tre mann | 3cd9faa24d | |
not tre mann | 6d638698d2 | |
zxkmm | 3a3c79a8ab | |
zxkmm | fa8ed6e9dd | |
not tre mann | 7b4a79ee38 | |
not tre mann | 7307703692 | |
zxkmm | 7a52068de8 | |
zxkmm | 30965ef083 | |
zxkmm | 75eeab2368 | |
zxkmm | 5f5aeb96f3 | |
zxkmm | bb774d362d | |
zxkmm | 4573a78ce0 | |
zxkmm | 62b8e86381 | |
zxkmm | 77145d0514 | |
zxkmm | 8bd2f5bc1f | |
zxkmm | 7c61e65c0b | |
zxkmm | 38c001bd1d | |
zxkmm | 19f5d3db93 | |
zxkmm | dc7f5ae35a | |
zxkmm | a95871162d | |
zxkmm | 30b4cc4e60 | |
not tre mann | 94ca23fc01 | |
zxkmm | 3167b584de | |
zxkmm | e7543d102c | |
not tre mann | 53b667abca | |
zxkmm | 8c9e64e61f | |
zxkmm | 1f26de2f4a | |
zxkmm | 78e6ba9f70 |
|
@ -9,10 +9,16 @@
|
|||
/firmware/application/portapack_cpld_data.cpp
|
||||
/firmware/application/hackrf_cpld_data.cpp
|
||||
/firmware/application/hackrf_cpld_data.hpp
|
||||
/sdcard/SYS/ADSB/world_map.bin
|
||||
/sdcard/SYS/FREQMAN/BHT*
|
||||
/sdcard/SYS/FREQMAN/R.TXT
|
||||
/sdcard/SYS/FREQMAN/XXX.TXT
|
||||
/sdcard/ADSB/world_map.bin
|
||||
/sdcard/FREQMAN/BHT*
|
||||
/sdcard/FREQMAN/R.TXT
|
||||
/sdcard/FREQMAN/XXX.TXT
|
||||
|
||||
# Toolchain binaries
|
||||
/armbin
|
||||
|
||||
# Compiled Object files
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "app_settings.hpp"
|
||||
#include "radio_state.hpp"
|
||||
#include "tone_key.hpp"
|
||||
#include "file_path.hpp"
|
||||
|
||||
namespace ui {
|
||||
|
||||
|
@ -226,7 +227,7 @@ class AnalogAudioView : public View {
|
|||
RecordView record_view{
|
||||
{0 * 8, 2 * 16, 30 * 8, 1 * 16},
|
||||
u"AUD",
|
||||
u"AUDIO",
|
||||
audio_dir_user,
|
||||
RecordView::FileType::WAV,
|
||||
4096,
|
||||
4};
|
||||
|
|
|
@ -470,7 +470,7 @@ BLERxView::BLERxView(NavigationView& nav)
|
|||
logging = v;
|
||||
|
||||
if (logger && logging)
|
||||
logger->append(blerx_dir.string() + "/Logs/BLELOG_" + to_string_timestamp(rtc_time::now()) + ".TXT");
|
||||
logger->append(blerx_dir_user.string() + "/Logs/BLELOG_" + to_string_timestamp(rtc_time::now()) + ".TXT");
|
||||
};
|
||||
check_log.set_value(logging);
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ class BleRecentEntryDetailView : public View {
|
|||
void on_save_file(const std::string value, BLETxPacket packetToSave);
|
||||
bool saveFile(const std::filesystem::path& path, BLETxPacket packetToSave);
|
||||
std::string packetFileBuffer{};
|
||||
std::filesystem::path packet_save_path{blerx_dir / u"Lists/????.csv"};
|
||||
std::filesystem::path packet_save_path{blerx_dir_user / u"Lists/????.csv"};
|
||||
|
||||
static constexpr uint8_t total_data_lines{5};
|
||||
|
||||
|
@ -251,9 +251,9 @@ class BLERxView : public View {
|
|||
uint64_t total_count = 0;
|
||||
std::vector<std::string> searchList{};
|
||||
|
||||
std::filesystem::path find_packet_path{blerx_dir / u"Find/????.TXT"};
|
||||
std::filesystem::path log_packets_path{blerx_dir / u"Logs/????.TXT"};
|
||||
std::filesystem::path packet_save_path{blerx_dir / u"Lists/????.csv"};
|
||||
std::filesystem::path find_packet_path{blerx_dir_user / u"Find/????.TXT"};
|
||||
std::filesystem::path log_packets_path{blerx_dir_user / u"Logs/????.TXT"};
|
||||
std::filesystem::path packet_save_path{blerx_dir_user / u"Lists/????.csv"};
|
||||
|
||||
static constexpr auto header_height = 4 * 16;
|
||||
static constexpr auto switch_button_height = 3 * 16;
|
||||
|
|
|
@ -139,7 +139,7 @@ class BLETxView : public View {
|
|||
uint32_t prev_value{0};
|
||||
|
||||
std::filesystem::path file_path{};
|
||||
std::filesystem::path packet_save_path{bletx_dir / u"BLETX_????.TXT"};
|
||||
std::filesystem::path packet_save_path{bletx_dir_user / u"BLETX_????.TXT"};
|
||||
uint8_t channel_number = 37;
|
||||
bool auto_channel = false;
|
||||
|
||||
|
@ -166,7 +166,7 @@ class BLETxView : public View {
|
|||
|
||||
std::unique_ptr<FileWrapper> dataFileWrapper{};
|
||||
File dataFile{};
|
||||
std::filesystem::path dataTempFilePath{bletx_dir / u"dataFileTemp.TXT"};
|
||||
std::filesystem::path dataTempFilePath{bletx_dir_resources / u"dataFileTemp.TXT"};
|
||||
std::vector<uint16_t> markedBytes{};
|
||||
CursorPos cursor_pos{};
|
||||
uint8_t marked_counter = 0;
|
||||
|
|
|
@ -102,7 +102,7 @@ class CaptureAppView : public View {
|
|||
RecordView record_view{
|
||||
{0 * 8, 2 * 16, 30 * 8, 1 * 16},
|
||||
u"BBD_????.*",
|
||||
captures_dir,
|
||||
captures_dir_user,
|
||||
RecordView::FileType::RawS16,
|
||||
16384,
|
||||
3};
|
||||
|
|
|
@ -95,9 +95,11 @@ void SoundBoardView::start_tx(const uint32_t id) {
|
|||
|
||||
stop();
|
||||
|
||||
if (!reader->open(u"/WAV/" + file_list[id].native())) {
|
||||
file_error();
|
||||
return;
|
||||
if (!reader->open(wav_dir_resources + u"/" + file_list[id].native())) {
|
||||
if (!reader->open(wav_dir_user + u"/" + file_list[id].native())) {
|
||||
file_error();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
playing_id = id;
|
||||
|
@ -164,28 +166,34 @@ void SoundBoardView::refresh_list() {
|
|||
c_page = page;
|
||||
|
||||
// List directories and files, put directories up top
|
||||
std::filesystem::path file_list_index[2];
|
||||
file_list_index[0] = wav_dir_user;
|
||||
file_list_index[1] = wav_dir_resources;
|
||||
uint32_t count = 0;
|
||||
for (const auto& entry : std::filesystem::directory_iterator(wav_dir, u"*")) {
|
||||
if (std::filesystem::is_regular_file(entry.status())) {
|
||||
if (entry.path().string().length()) {
|
||||
auto entry_extension = entry.path().extension().string();
|
||||
// tempnewnote: need test
|
||||
for (const auto& now_path : file_list_index) {
|
||||
for (const auto& entry : std::filesystem::directory_iterator(now_path, u"*")) {
|
||||
if (std::filesystem::is_regular_file(entry.status())) {
|
||||
if (entry.path().string().length()) {
|
||||
auto entry_extension = entry.path().extension().string();
|
||||
|
||||
for (auto& c : entry_extension)
|
||||
c = toupper(c);
|
||||
for (auto& c : entry_extension)
|
||||
c = toupper(c);
|
||||
|
||||
if (entry_extension == ".WAV") {
|
||||
if (reader->open(wav_dir / entry.path())) {
|
||||
if ((reader->channels() == 1) && ((reader->bits_per_sample() == 8) || (reader->bits_per_sample() == 16))) {
|
||||
// sounds[c].ms_duration = reader->ms_duration();
|
||||
// sounds[c].path = u"WAV/" + entry.path().native();
|
||||
if (count >= (page - 1) * 100 && count < page * 100) {
|
||||
file_list.push_back(entry.path());
|
||||
if (file_list.size() == 100) {
|
||||
page++;
|
||||
break;
|
||||
if (entry_extension == ".WAV") {
|
||||
if (reader->open(now_path / entry.path().native())) {
|
||||
if ((reader->channels() == 1) && ((reader->bits_per_sample() == 8) || (reader->bits_per_sample() == 16))) {
|
||||
// sounds[c].ms_duration = reader->ms_duration();
|
||||
// sounds[c].path = u"/SYS/WAV/" + entry.path().native();
|
||||
if (count >= (page - 1) * 100 && count < page * 100) {
|
||||
file_list.push_back(entry.path());
|
||||
if (file_list.size() == 100) {
|
||||
page++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -233,7 +233,7 @@ class APRSRxView : public View {
|
|||
RecordView record_view{
|
||||
{0 * 8, 1 * 16, 30 * 8, 1 * 16},
|
||||
u"AFS_????.WAV",
|
||||
aprs_dir,
|
||||
aprs_dir_user,
|
||||
RecordView::FileType::WAV,
|
||||
4096,
|
||||
4};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2017 Furrtek
|
||||
* Copyleft (ɔ) 2024 zxkmm with the GPL license
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
|
@ -49,6 +50,7 @@ static const fs::path cxx_ext{u".C*"};
|
|||
static const fs::path png_ext{u".PNG"};
|
||||
static const fs::path bmp_ext{u".BMP"};
|
||||
static const fs::path rem_ext{u".REM"};
|
||||
|
||||
} // namespace ui
|
||||
|
||||
namespace {
|
||||
|
@ -227,7 +229,7 @@ void FileManBaseView::load_directory_contents(const fs::path& dir_path) {
|
|||
auto filtering = !extension_filter.empty();
|
||||
bool cxx_file = path_iequal(cxx_ext, extension_filter);
|
||||
|
||||
text_current.set(dir_path.empty() ? "(sd root)" : truncate(dir_path, 24));
|
||||
text_current.set(current_path.empty() ? "/" : truncate(dir_path, 24));
|
||||
|
||||
for (const auto& entry : fs::directory_iterator(dir_path, u"*")) {
|
||||
// Hide files starting with '.' (hidden / tmp).
|
||||
|
@ -237,6 +239,7 @@ void FileManBaseView::load_directory_contents(const fs::path& dir_path) {
|
|||
if (fs::is_regular_file(entry.status())) {
|
||||
if (!filtering || path_iequal(entry.path().extension(), extension_filter) || (cxx_file && is_cxx_capture_file(entry.path())))
|
||||
insert_sorted(entry_list, {entry.path().string(), (uint32_t)entry.size(), false});
|
||||
|
||||
} else if (fs::is_directory(entry.status())) {
|
||||
insert_sorted(entry_list, {entry.path().string(), 0, true});
|
||||
}
|
||||
|
@ -291,6 +294,8 @@ FileManBaseView::FileManBaseView(
|
|||
extension_filter{filter} {
|
||||
add_children({&labels,
|
||||
&text_current,
|
||||
&option_profile_switch,
|
||||
&label_profile,
|
||||
&button_exit});
|
||||
|
||||
button_exit.on_select = [this](Button&) {
|
||||
|
@ -313,6 +318,24 @@ FileManBaseView::FileManBaseView(
|
|||
pop_dir();
|
||||
};
|
||||
}
|
||||
|
||||
option_profile_switch.on_change = [this](size_t, uint8_t profiles) {
|
||||
switch (static_cast<DirProfiles>(profiles)) {
|
||||
case DirProfiles::User:
|
||||
jumping_between_profiles(current_path, DirProfiles::User);
|
||||
option_profile_switch.set_style(nullptr);
|
||||
|
||||
break;
|
||||
|
||||
case DirProfiles::System:
|
||||
jumping_between_profiles(current_path, DirProfiles::System);
|
||||
option_profile_switch.set_style(&Styles::red);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
reload_current();
|
||||
};
|
||||
}
|
||||
|
||||
void FileManBaseView::focus() {
|
||||
|
@ -324,8 +347,29 @@ void FileManBaseView::focus() {
|
|||
}
|
||||
|
||||
void FileManBaseView::push_dir(const fs::path& path) {
|
||||
// if you want it freely jump between profiles when picking files in your app, don't use this
|
||||
// , you should use push_fake_dir, which handle and call back the dir automatically
|
||||
if (path == parent_dir_path) {
|
||||
pop_dir();
|
||||
} else if (path == system_dir || path == apps_dir || path == firmware_dir) {
|
||||
nav_.push<ModalMessageView>(
|
||||
"Warning",
|
||||
"It is not recommended to\n"
|
||||
"modify system files,\n"
|
||||
"so you can easily\n"
|
||||
"update sdcard content.\n"
|
||||
"You can add all the custom\n"
|
||||
"files in root folders.\n"
|
||||
"Continue anyway?",
|
||||
YESNO,
|
||||
[this, path](bool choice) {
|
||||
if (choice) {
|
||||
current_path /= path;
|
||||
saved_index_stack.push_back(menu_view.highlighted_index());
|
||||
menu_view.set_highlighted(0);
|
||||
reload_current();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
current_path /= path;
|
||||
saved_index_stack.push_back(menu_view.highlighted_index());
|
||||
|
@ -334,14 +378,33 @@ void FileManBaseView::push_dir(const fs::path& path) {
|
|||
}
|
||||
}
|
||||
|
||||
void FileManBaseView::pop_dir() {
|
||||
if (saved_index_stack.empty())
|
||||
return;
|
||||
void FileManBaseView::push_fake_dir(const fs::path& path) {
|
||||
// the one this accepted is just a flag (e.g. CAPTURE, instead of /SYS/CAPTURE nor /CAPTURE), not real dir
|
||||
// after passing the flag here, this func will handle it automatically and make callback automatically
|
||||
fs::path first_level = path.extract_first_level();
|
||||
const fs::path default_mother_dir = user_dir;
|
||||
|
||||
current_path = current_path.parent_path();
|
||||
reload_current(true);
|
||||
menu_view.set_highlighted(saved_index_stack.back());
|
||||
saved_index_stack.pop_back();
|
||||
if (first_level != user_dir && first_level != system_dir) {
|
||||
current_path = default_mother_dir / path;
|
||||
saved_index_stack.push_back(
|
||||
menu_view.highlighted_index()); // TODO: do we really want to allow user to redirect to other dir tho?
|
||||
menu_view.set_highlighted(0);
|
||||
reload_current();
|
||||
}
|
||||
}
|
||||
|
||||
void FileManBaseView::pop_dir() {
|
||||
if (saved_index_stack.empty() && current_path == u"/") {
|
||||
return;
|
||||
} else if (saved_index_stack.empty()) {
|
||||
current_path = u"";
|
||||
reload_current();
|
||||
} else {
|
||||
current_path = current_path.parent_path();
|
||||
reload_current();
|
||||
menu_view.set_highlighted(saved_index_stack.back());
|
||||
saved_index_stack.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_extension(std::string t) {
|
||||
|
@ -388,8 +451,10 @@ void FileManBaseView::refresh_list() {
|
|||
}
|
||||
|
||||
menu_view.add_item(
|
||||
{entry_name.substr(0, max_filename_length) + std::string(21 - entry_name.length(), ' ') + size_str,
|
||||
ui::Color::yellow(),
|
||||
|
||||
{entry_name + std::string(21 - entry_name.length(), ' ') + size_str,
|
||||
(entry.path == system_dir || entry.path == apps_dir || entry.path == firmware_dir) ? Color::red() : Color::yellow(),
|
||||
|
||||
&bitmap_icon_dir,
|
||||
[this](KeyEvent key) {
|
||||
if (on_select_entry)
|
||||
|
@ -420,6 +485,31 @@ void FileManBaseView::reload_current(bool reset_pagination) {
|
|||
refresh_list();
|
||||
}
|
||||
|
||||
fs::path FileManBaseView::jumping_between_profiles(fs::path& path, DirProfiles profile) {
|
||||
fs::path first_level = path.extract_first_level();
|
||||
const fs::path null_path = u"";
|
||||
|
||||
if (profile == DirProfiles::User) {
|
||||
if (first_level == system_dir) { // /SYS/abcdef
|
||||
path = path.remove_first_level();
|
||||
} else if (first_level == null_path) { // /abcdef
|
||||
// this is for: after user redirected to other dir and then switch to user profile
|
||||
path = user_dir;
|
||||
}
|
||||
|
||||
} else if (profile == DirProfiles::System) {
|
||||
if (first_level == null_path && path != system_dir) { // /abcdef
|
||||
// the second argument is for preventing circuling enter system dir
|
||||
path = system_dir / path;
|
||||
} else if (first_level == system_dir) { // /SYS/abcdef
|
||||
// this is for: after user redirected to other dir and then switch to system profile
|
||||
path = system_dir;
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
const FileManBaseView::file_assoc_t& FileManBaseView::get_assoc(
|
||||
const fs::path& ext) const {
|
||||
size_t index = 0;
|
||||
|
@ -547,7 +637,8 @@ void FileManagerView::refresh_widgets(const bool v) {
|
|||
button_paste.hidden(v);
|
||||
button_new_dir.hidden(v);
|
||||
button_new_file.hidden(v);
|
||||
|
||||
option_profile_switch.hidden(!v);
|
||||
label_profile.hidden(!v);
|
||||
set_dirty();
|
||||
}
|
||||
|
||||
|
@ -752,7 +843,8 @@ FileManagerView::FileManagerView(
|
|||
} else {
|
||||
text_date.set_style(&Styles::grey);
|
||||
if (selected_is_valid())
|
||||
text_date.set((is_directory(get_selected_full_path()) ? "Created " : "Modified ") + to_string_FAT_timestamp(file_created_date(get_selected_full_path())));
|
||||
text_date.set((is_directory(get_selected_full_path()) ? "Created " : "Modified ") +
|
||||
to_string_FAT_timestamp(file_created_date(get_selected_full_path())));
|
||||
else
|
||||
text_date.set("");
|
||||
}
|
||||
|
@ -862,5 +954,4 @@ FileManagerView::FileManagerView(
|
|||
reload_current();
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
|
|
|
@ -48,6 +48,11 @@ enum class ClipboardMode : uint8_t {
|
|||
Copy
|
||||
};
|
||||
|
||||
enum class DirProfiles : uint8_t {
|
||||
User = 1,
|
||||
System = 2
|
||||
};
|
||||
|
||||
class FileManBaseView : public View {
|
||||
public:
|
||||
FileManBaseView(
|
||||
|
@ -59,6 +64,7 @@ class FileManBaseView : public View {
|
|||
void focus() override;
|
||||
std::string title() const override { return "Fileman"; };
|
||||
void push_dir(const std::filesystem::path& path);
|
||||
void push_fake_dir(const std::filesystem::path& path);
|
||||
|
||||
protected:
|
||||
uint32_t prev_highlight = 0;
|
||||
|
@ -95,6 +101,9 @@ class FileManBaseView : public View {
|
|||
void reload_current(bool reset_pagination = false);
|
||||
void load_directory_contents(const std::filesystem::path& dir_path);
|
||||
void load_directory_contents_unordered(const std::filesystem::path& dir_path, size_t file_cnt);
|
||||
|
||||
std::filesystem::path jumping_between_profiles(std::filesystem::path& path, DirProfiles profile);
|
||||
|
||||
const file_assoc_t& get_assoc(const std::filesystem::path& ext) const;
|
||||
|
||||
NavigationView& nav_;
|
||||
|
@ -106,6 +115,7 @@ class FileManBaseView : public View {
|
|||
const std::string str_back{"<--"};
|
||||
const std::string str_next{"-->"};
|
||||
const std::string str_full{"Can't load more.."};
|
||||
|
||||
const std::filesystem::path parent_dir_path{u".."};
|
||||
std::filesystem::path current_path{u""};
|
||||
std::filesystem::path extension_filter{u""};
|
||||
|
@ -116,10 +126,10 @@ class FileManBaseView : public View {
|
|||
bool show_hidden_files{false};
|
||||
|
||||
Labels labels{
|
||||
{{0, 0}, "Path:", Color::light_grey()}};
|
||||
{{0, 0}, "\u007F", Color::white()}};
|
||||
|
||||
Text text_current{
|
||||
{6 * 8, 0 * 8, 24 * 8, 16},
|
||||
{1 * 8, 0 * 8, 20 * 8, 16},
|
||||
"",
|
||||
};
|
||||
|
||||
|
@ -127,6 +137,16 @@ class FileManBaseView : public View {
|
|||
{0, 2 * 8, 240, 26 * 8},
|
||||
true};
|
||||
|
||||
OptionsField option_profile_switch{
|
||||
{11 * 8, 32 * 8},
|
||||
16,
|
||||
{{"User Directory ", 1},
|
||||
{"System Directory", 2}}};
|
||||
|
||||
Labels label_profile{
|
||||
{{0 * 8, 32 * 8}, "Profile: ", Color::light_grey()},
|
||||
{{9 * 8, 32 * 8}, "\u007F/", Color::white()}};
|
||||
|
||||
Button button_exit{
|
||||
{22 * 8, 34 * 8, 8 * 8, 32},
|
||||
"Exit"};
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2023 Kyle Reed
|
||||
* copyleft (ɔ) 2024 zxkmm with the GPL license
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
|
@ -96,7 +97,11 @@ void FreqManBaseView::focus() {
|
|||
if (error_ == ERROR_ACCESS) {
|
||||
nav_.display_modal("Error", "File access error", ABORT);
|
||||
} else if (error_ == ERROR_NOFILES) {
|
||||
nav_.display_modal("Error", "No database files\nin /FREQMAN", ABORT);
|
||||
nav_.display_modal("Error",
|
||||
"No database files\nin either" +
|
||||
freqman_dir_user.string() +
|
||||
"\nor" + freqman_dir_resources.string(),
|
||||
ABORT);
|
||||
} else {
|
||||
options_category.focus();
|
||||
}
|
||||
|
@ -107,7 +112,15 @@ void FreqManBaseView::change_category(size_t new_index) {
|
|||
return;
|
||||
|
||||
current_category_index = new_index;
|
||||
if (!db_.open(get_freqman_path(current_category()))) {
|
||||
|
||||
current_is_system_item = false;
|
||||
if (!db_.open(get_freqman_path(current_category(), dir_profile::ProfileUser))) {
|
||||
current_is_system_item = true;
|
||||
}
|
||||
|
||||
if (current_is_system_item && // <<< this means that entered previus condition, it's a work around to save 1 byte of ram
|
||||
(!db_.open(
|
||||
get_freqman_path(current_category(), dir_profile::ProfileSystem)))) {
|
||||
error_ = ERROR_ACCESS;
|
||||
}
|
||||
|
||||
|
@ -117,15 +130,20 @@ void FreqManBaseView::change_category(size_t new_index) {
|
|||
void FreqManBaseView::refresh_categories() {
|
||||
OptionsField::options_t new_categories;
|
||||
|
||||
scan_root_files(
|
||||
freqman_dir, u"*.TXT", [&new_categories](const fs::path& path) {
|
||||
// Skip temp/hidden files.
|
||||
if (path.empty() || path.native()[0] == u'.')
|
||||
return;
|
||||
auto load_files = [&new_categories](const fs::path& dir) {
|
||||
scan_root_files(
|
||||
dir, u"*.TXT", [&new_categories](const fs::path& path) {
|
||||
// Skip temp/hidden files.
|
||||
if (path.empty() || path.native()[0] == u'.')
|
||||
return;
|
||||
|
||||
// The UI layer will truncate long file names when displaying.
|
||||
new_categories.emplace_back(path.stem().string(), new_categories.size());
|
||||
});
|
||||
// The UI layer will truncate long file names when displaying.
|
||||
new_categories.emplace_back(path.stem().string(), new_categories.size());
|
||||
});
|
||||
};
|
||||
|
||||
load_files(freqman_dir_resources);
|
||||
load_files(freqman_dir_user);
|
||||
|
||||
// Alphabetically sort the categories.
|
||||
std::sort(new_categories.begin(), new_categories.end(), [](auto& left, auto& right) {
|
||||
|
@ -163,9 +181,17 @@ FrequencySaveView::FrequencySaveView(
|
|||
|
||||
bind(field_description, entry_.description, nav);
|
||||
|
||||
button_save.on_select = [this, &nav](Button&) {
|
||||
db_.insert_entry(db_.entry_count(), entry_);
|
||||
nav_.pop();
|
||||
button_save.on_select = [this, &nav](Button&) { // TODO: don't list system category here
|
||||
if (current_is_system_item) {
|
||||
nav.display_modal("Forbid",
|
||||
"Can't save to\n"
|
||||
"system category.\n"
|
||||
"Please save to \n"
|
||||
"a user category.");
|
||||
} else {
|
||||
db_.insert_entry(db_.entry_count(), entry_);
|
||||
nav_.pop();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -238,6 +264,7 @@ void FrequencyManagerView::on_edit_desc() {
|
|||
}
|
||||
|
||||
void FrequencyManagerView::on_add_category() {
|
||||
ensure_directory(freqman_dir_user);
|
||||
temp_buffer_.clear();
|
||||
text_prompt(nav_, temp_buffer_, 20, [this](std::string& new_name) {
|
||||
if (!new_name.empty()) {
|
||||
|
@ -252,8 +279,8 @@ void FrequencyManagerView::on_del_category() {
|
|||
"Delete", "Delete " + current_category() + "\nAre you sure?", YESNO,
|
||||
[this](bool choice) {
|
||||
if (choice) {
|
||||
db_.close(); // Ensure file is closed.
|
||||
auto path = get_freqman_path(current_category());
|
||||
db_.close(); // Ensure file is closed.
|
||||
auto path = get_freqman_path(current_category(), dir_profile::ProfileUser); // only allow del user's
|
||||
delete_file(path);
|
||||
refresh_categories();
|
||||
}
|
||||
|
@ -285,6 +312,19 @@ void FrequencyManagerView::on_del_entry() {
|
|||
}
|
||||
});
|
||||
}
|
||||
bool FrequencyManagerView::forbid_delete_system_item_helper(NavigationView& nav) {
|
||||
// this is just a modal, however, it's been forbidden in those handler.
|
||||
|
||||
if (current_is_system_item) {
|
||||
nav.display_modal("Forbid",
|
||||
"Can't do that to \n"
|
||||
"system item.\n"
|
||||
"If you have to,\n"
|
||||
"do it with File Manager");
|
||||
}
|
||||
|
||||
return current_is_system_item;
|
||||
}
|
||||
|
||||
FrequencyManagerView::FrequencyManagerView(
|
||||
NavigationView& nav)
|
||||
|
@ -309,31 +349,44 @@ FrequencyManagerView::FrequencyManagerView(
|
|||
};
|
||||
|
||||
button_add_category.on_select = [this]() {
|
||||
// this one will only directly add to /FREQMAN
|
||||
on_add_category();
|
||||
};
|
||||
|
||||
button_del_category.on_select = [this]() {
|
||||
on_del_category();
|
||||
button_del_category.on_select = [this, &nav]() {
|
||||
if (!forbid_delete_system_item_helper(nav)) {
|
||||
on_del_category();
|
||||
}
|
||||
};
|
||||
|
||||
button_edit_entry.on_select = [this](Button&) {
|
||||
on_edit_entry();
|
||||
button_edit_entry.on_select = [this, &nav](Button&) {
|
||||
if (!forbid_delete_system_item_helper(nav)) {
|
||||
on_edit_entry();
|
||||
}
|
||||
};
|
||||
|
||||
button_edit_freq.on_select = [this](Button&) {
|
||||
on_edit_freq();
|
||||
button_edit_freq.on_select = [this, &nav](Button&) {
|
||||
if (!forbid_delete_system_item_helper(nav)) {
|
||||
on_edit_freq();
|
||||
}
|
||||
};
|
||||
|
||||
button_edit_desc.on_select = [this](Button&) {
|
||||
on_edit_desc();
|
||||
button_edit_desc.on_select = [this, &nav](Button&) {
|
||||
if (!forbid_delete_system_item_helper(nav)) {
|
||||
on_edit_desc();
|
||||
}
|
||||
};
|
||||
|
||||
button_add_entry.on_select = [this]() {
|
||||
on_add_entry();
|
||||
button_add_entry.on_select = [this, &nav]() {
|
||||
if (!forbid_delete_system_item_helper(nav)) {
|
||||
on_add_entry();
|
||||
}
|
||||
};
|
||||
|
||||
button_del_entry.on_select = [this]() {
|
||||
on_del_entry();
|
||||
button_del_entry.on_select = [this, &nav]() {
|
||||
if (!forbid_delete_system_item_helper(nav)) {
|
||||
on_del_entry();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2023 Kyle Reed
|
||||
* copyleft (ɔ) 2024 zxkmm with the GPL license
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
|
@ -123,6 +124,7 @@ class FrequencyManagerView : public FreqManBaseView {
|
|||
std::string title() const override { return "Freqman"; }
|
||||
|
||||
private:
|
||||
bool forbid_delete_system_item_helper(NavigationView& nav);
|
||||
std::string temp_buffer_{};
|
||||
|
||||
void on_edit_entry();
|
||||
|
|
|
@ -38,6 +38,8 @@
|
|||
#include "radio_state.hpp"
|
||||
#include "pocsag_app.hpp"
|
||||
|
||||
#include "file_path.hpp"
|
||||
|
||||
#include <functional>
|
||||
|
||||
class FskRxLogger {
|
||||
|
@ -160,7 +162,7 @@ class FskxRxMainView : public View {
|
|||
RecordView record_view{
|
||||
{0 * 8, 4 * 16, 30 * 8, 1 * 16},
|
||||
u"FSKRX_????.C16",
|
||||
u"FSKRX",
|
||||
fskrx_dir_user,
|
||||
RecordView::FileType::RawS16,
|
||||
16384,
|
||||
3};
|
||||
|
|
|
@ -48,7 +48,7 @@ IQTrimView::IQTrimView(NavigationView& nav)
|
|||
|
||||
field_path.on_select = [this](TextField&) {
|
||||
auto open_view = nav_.push<FileLoadView>(".C*");
|
||||
open_view->push_dir(captures_dir);
|
||||
open_view->push_fake_dir(captures_dir);
|
||||
open_view->on_changed = [this](fs::path path) {
|
||||
open_file(path);
|
||||
};
|
||||
|
|
|
@ -573,6 +573,8 @@ void GlassView::set_spec_iq_phase_calibration_value(uint8_t cal_value) { // def
|
|||
void GlassView::load_presets() {
|
||||
File presets_file;
|
||||
auto error = presets_file.open(looking_glass_dir / u"PRESETS.TXT");
|
||||
// TODO: this app originally ain't support user load list.
|
||||
// should support, but ain't have funtionality loss in sdcard refactor PR.
|
||||
presets_db.clear();
|
||||
|
||||
// Add the "Manual" entry.
|
||||
|
|
|
@ -131,7 +131,7 @@ void PlaylistView::open_file(bool prompt_save) {
|
|||
}
|
||||
|
||||
auto open_view = nav_.push<FileLoadView>(".PPL");
|
||||
open_view->push_dir(playlist_dir);
|
||||
open_view->push_fake_dir(playlist_dir);
|
||||
open_view->on_changed = [this](fs::path new_file_path) {
|
||||
on_file_changed(new_file_path);
|
||||
};
|
||||
|
@ -170,7 +170,7 @@ void PlaylistView::save_file(bool show_dialogs) {
|
|||
|
||||
void PlaylistView::add_entry(fs::path&& path) {
|
||||
if (playlist_path_.empty()) {
|
||||
playlist_path_ = next_filename_matching_pattern(playlist_dir / u"PLAY_????.PPL");
|
||||
playlist_path_ = next_filename_matching_pattern(playlist_dir_user / u"PLAY_????.PPL");
|
||||
|
||||
// Hack around focus getting called by ctor before parent is set.
|
||||
if (parent())
|
||||
|
@ -388,7 +388,7 @@ PlaylistView::PlaylistView(
|
|||
&waterfall,
|
||||
});
|
||||
|
||||
ensure_directory(playlist_dir);
|
||||
ensure_fake_directories(playlist_dir);
|
||||
waterfall.show_audio_spectrum_view(false);
|
||||
|
||||
field_frequency.set_value(transmitter_model.target_frequency());
|
||||
|
@ -411,7 +411,7 @@ PlaylistView::PlaylistView(
|
|||
if (is_active())
|
||||
return;
|
||||
auto open_view = nav_.push<FileLoadView>(".C*");
|
||||
open_view->push_dir(captures_dir);
|
||||
open_view->push_fake_dir(captures_dir);
|
||||
open_view->on_changed = [this](fs::path path) {
|
||||
add_entry(std::move(path));
|
||||
};
|
||||
|
|
|
@ -337,7 +337,7 @@ ReconView::ReconView(NavigationView& nav)
|
|||
|
||||
// set record View
|
||||
record_view = std::make_unique<RecordView>(Rect{0, 0, 30 * 8, 1 * 16},
|
||||
u"AUTO_AUDIO", audio_dir,
|
||||
u"AUTO_AUDIO", audio_dir_user,
|
||||
RecordView::FileType::WAV, 4096, 4);
|
||||
record_view->set_filename_date_frequency(true);
|
||||
record_view->set_auto_trim(false);
|
||||
|
@ -680,7 +680,7 @@ ReconView::ReconView(NavigationView& nav)
|
|||
open_view->on_changed = [this](std::vector<std::string> result) {
|
||||
input_file = result[0];
|
||||
output_file = result[1];
|
||||
freq_file_path = get_freqman_path(output_file).string();
|
||||
freq_file_path = get_freqman_path(output_file, dir_profile::ProfileUser).string();
|
||||
|
||||
load_persisted_settings();
|
||||
ui_settings.save();
|
||||
|
@ -731,7 +731,7 @@ ReconView::ReconView(NavigationView& nav)
|
|||
file_name.set("=>");
|
||||
|
||||
// Loading input and output file from settings
|
||||
freq_file_path = get_freqman_path(output_file).string();
|
||||
freq_file_path = get_freqman_path(output_file, dir_profile::ProfileUser).string();
|
||||
|
||||
field_recon_match_mode.set_selected_index(recon_match_mode);
|
||||
field_squelch.set_value(squelch);
|
||||
|
@ -790,7 +790,10 @@ void ReconView::frequency_file_load() {
|
|||
.load_ranges = load_ranges,
|
||||
.load_hamradios = load_hamradios,
|
||||
.load_repeaters = load_repeaters};
|
||||
if (!load_freqman_file(file_input, frequency_list, options) || frequency_list.empty()) {
|
||||
if (
|
||||
(!load_freqman_file(file_input, frequency_list, options, dir_profile::ProfileSystem) &&
|
||||
!load_freqman_file(file_input, frequency_list, options, dir_profile::ProfileUser)) ||
|
||||
frequency_list.empty()) {
|
||||
file_name.set_style(&Styles::red);
|
||||
desc_cycle.set("...empty file...");
|
||||
frequency_list.clear();
|
||||
|
@ -1170,18 +1173,18 @@ size_t ReconView::change_mode(freqman_index_t new_mod) {
|
|||
if (new_mod == SPEC_MODULATION) {
|
||||
if (persistent_memory::recon_repeat_recorded()) {
|
||||
record_view = std::make_unique<RecordView>(Rect{0, 0, 30 * 8, 1 * 16},
|
||||
u"RECON_REPEAT.C16", captures_dir,
|
||||
u"RECON_REPEAT.C16", captures_dir_user,
|
||||
RecordView::FileType::RawS16, 16384, 3);
|
||||
record_view->set_filename_as_is(true);
|
||||
} else {
|
||||
record_view = std::make_unique<RecordView>(Rect{0, 0, 30 * 8, 1 * 16},
|
||||
u"AUTO_RAW", captures_dir,
|
||||
u"AUTO_RAW", captures_dir_user,
|
||||
RecordView::FileType::RawS16, 16384, 3);
|
||||
record_view->set_filename_date_frequency(true);
|
||||
}
|
||||
} else {
|
||||
record_view = std::make_unique<RecordView>(Rect{0, 0, 30 * 8, 1 * 16},
|
||||
u"AUTO_AUDIO", audio_dir,
|
||||
u"AUTO_AUDIO", audio_dir_user,
|
||||
RecordView::FileType::WAV, 4096, 4);
|
||||
record_view->set_filename_date_frequency(true);
|
||||
}
|
||||
|
|
|
@ -182,6 +182,7 @@ class ReconView : public View {
|
|||
|
||||
const std::filesystem::path repeat_rec_file = u"RECON_REPEAT.C16";
|
||||
const std::filesystem::path repeat_rec_meta = u"RECON_REPEAT.TXT";
|
||||
// tempnote: path const var removed
|
||||
const size_t repeat_read_size{16384};
|
||||
const size_t repeat_buffer_count{3};
|
||||
int8_t repeat_cur_rep = 0;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2023 gullradriel, Nilorea Studio Inc.
|
||||
* Copyleft (ɔ) 2024 zxkmm with the GPL license
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
|
@ -57,26 +58,30 @@ ReconSetupViewMain::ReconSetupViewMain(NavigationView& nav, Rect parent_rect, st
|
|||
|
||||
button_input_file.on_select = [this, &nav](Button&) {
|
||||
auto open_view = nav.push<FileLoadView>(".TXT");
|
||||
open_view->push_dir(freqman_dir);
|
||||
open_view->push_fake_dir(freqman_dir); // the argu that push fake dir accepted is just a flag, so can safely hard coded
|
||||
open_view->on_changed = [this, &nav](std::filesystem::path new_file_path) {
|
||||
if (new_file_path.native().find((u"/" / freqman_dir).native()) == 0) {
|
||||
if ((new_file_path.native().find((u"/" / freqman_dir_resources).native()) == 0) || new_file_path.native().find((freqman_dir_user).native()) == 0) {
|
||||
_input_file = new_file_path.stem().string();
|
||||
text_input_file.set(_input_file);
|
||||
} else {
|
||||
nav.display_modal("LOAD ERROR", "A valid file from\nFREQMAN directory is\nrequired.");
|
||||
nav.display_modal("LOAD ERROR", "A valid file from\n" +
|
||||
freqman_dir_user.string() +
|
||||
"\nor\n" +
|
||||
freqman_dir_resources.string() +
|
||||
"\ndirectories is\nrequired.");
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
button_choose_output_file.on_select = [this, &nav](Button&) {
|
||||
auto open_view = nav.push<FileLoadView>(".TXT");
|
||||
open_view->push_dir(freqman_dir);
|
||||
open_view->push_fake_dir(freqman_dir); // the argu that push fake dir accepted is just a flag, so can safely hard coded
|
||||
open_view->on_changed = [this, &nav](std::filesystem::path new_file_path) {
|
||||
if (new_file_path.native().find((u"/" / freqman_dir).native()) == 0) {
|
||||
if (new_file_path.native().find((freqman_dir_user).native()) == 0) {
|
||||
_output_file = new_file_path.stem().string();
|
||||
button_choose_output_name.set_text(_output_file);
|
||||
} else {
|
||||
nav.display_modal("SAVE ERROR", "A valid file from\nFREQMAN directory is\nrequired.");
|
||||
nav.display_modal("SAVE ERROR", "A valid file from\n" + freqman_dir_user.string() + "\ndirectories is\nrequired.");
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
|
||||
// screen size helper
|
||||
#define SCREEN_W 240
|
||||
//#define SCREEN_H 320
|
||||
// #define SCREEN_H 320
|
||||
|
||||
// recon settings nb params
|
||||
#define RECON_SETTINGS_NB_PARAMS 7
|
||||
|
|
|
@ -247,7 +247,7 @@ RemoteEntryEditView::RemoteEntryEditView(
|
|||
|
||||
field_path.on_select = [this, &nav](TextField&) {
|
||||
auto open_view = nav.push<FileLoadView>(".C*");
|
||||
open_view->push_dir(captures_dir);
|
||||
open_view->push_fake_dir(captures_dir);
|
||||
open_view->on_changed = [this](fs::path path) {
|
||||
load_path(std::move(path));
|
||||
refresh_ui();
|
||||
|
@ -356,7 +356,7 @@ RemoteView::RemoteView(
|
|||
Dim waterfall_height = waterfall_bottom - waterfall_top;
|
||||
waterfall.set_parent_rect({0, waterfall_top, screen_width, waterfall_height});
|
||||
|
||||
ensure_directory(remotes_dir);
|
||||
ensure_fake_directories(remotes_dir);
|
||||
|
||||
// Load the previously loaded remote if exists.
|
||||
if (!load_remote(settings_.remote_path))
|
||||
|
@ -528,7 +528,7 @@ void RemoteView::new_remote() {
|
|||
|
||||
void RemoteView::open_remote() {
|
||||
auto open_view = nav_.push<FileLoadView>(".REM");
|
||||
open_view->push_dir(remotes_dir);
|
||||
open_view->push_fake_dir(remotes_dir);
|
||||
open_view->on_changed = [this](fs::path path) {
|
||||
save_remote();
|
||||
load_remote(std::move(path));
|
||||
|
@ -539,7 +539,7 @@ void RemoteView::open_remote() {
|
|||
void RemoteView::init_remote() {
|
||||
model_ = {"<Unnamed Remote>", {}};
|
||||
reset_buttons();
|
||||
set_remote_path(next_filename_matching_pattern(remotes_dir / u"REMOTE_????.REM"));
|
||||
set_remote_path(next_filename_matching_pattern(remotes_dir_user / u"REMOTE_????.REM"));
|
||||
set_needs_save(false);
|
||||
|
||||
if (remote_path_.empty())
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2018 Furrtek
|
||||
* Copyright (C) 2023 Mark Thompson
|
||||
* Copyleft (ɔ) 2024 zxkmm with the GPL license
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
|
@ -336,13 +337,13 @@ ScannerView::ScannerView(
|
|||
// Button to load a Freqman file.
|
||||
button_load.on_select = [this, &nav](Button&) {
|
||||
auto open_view = nav.push<FileLoadView>(".TXT");
|
||||
open_view->push_dir(freqman_dir);
|
||||
open_view->push_fake_dir(freqman_dir); // the argu that push fake dir accepted is just a flag, so can safely hard coded
|
||||
open_view->on_changed = [this, &nav](std::filesystem::path new_file_path) {
|
||||
if (new_file_path.native().find((u"/" / freqman_dir).native()) == 0) {
|
||||
if ((new_file_path.native().find((u"/" / freqman_dir_resources).native()) == 0) || new_file_path.native().find((freqman_dir_user).native()) == 0) {
|
||||
scan_pause();
|
||||
frequency_file_load(new_file_path);
|
||||
} else {
|
||||
nav.display_modal("LOAD ERROR", "A valid file from\nFREQMAN directory is\nrequired.");
|
||||
nav.display_modal("LOAD ERROR", "A valid file from\nFREQMAN directories is\nrequired.");
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -491,7 +492,7 @@ ScannerView::ScannerView(
|
|||
// Button to add current frequency (found during Search) to the Scan Frequency List
|
||||
button_add.on_select = [this](Button&) {
|
||||
FreqmanDB db;
|
||||
if (db.open(get_freqman_path(freqman_file), /*create*/ true)) {
|
||||
if (db.open(get_freqman_path(freqman_file, dir_profile::ProfileUser), /*create*/ true)) {
|
||||
freqman_entry entry{
|
||||
.frequency_a = current_frequency,
|
||||
.type = freqman_type::Single,
|
||||
|
@ -537,7 +538,7 @@ ScannerView::ScannerView(
|
|||
receiver_model.set_squelch_level(0);
|
||||
|
||||
// LOAD FREQUENCIES
|
||||
frequency_file_load(get_freqman_path(freqman_file));
|
||||
frequency_file_load(get_freqman_path(freqman_file, dir_profile::ProfileUser));
|
||||
}
|
||||
|
||||
void ScannerView::frequency_file_load(const fs::path& path) {
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
#define SCANNER_SLEEP_MS 50 // ms that Scanner Thread sleeps per loop
|
||||
#define STATISTICS_UPDATES_PER_SEC 10
|
||||
#define MAX_FREQ_LOCK 10 //# of 50ms cycles scanner locks into freq when signal detected, to verify signal is not spurious
|
||||
#define MAX_FREQ_LOCK 10 // # of 50ms cycles scanner locks into freq when signal detected, to verify signal is not spurious
|
||||
|
||||
namespace ui {
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Copyright (C) 2023 Kyle Reed
|
||||
* Copyright (C) 2024 Mark Thompson
|
||||
* Copyright (C) 2024 u-foka
|
||||
* Copyleft (ɔ) 2024 zxkmm under GPL license
|
||||
* Copyleft (ɔ) 2024 zxkmm with the GPL license
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Copyright (C) 2023 Kyle Reed
|
||||
* Copyright (C) 2024 Mark Thompson
|
||||
* Copyright (C) 2024 u-foka
|
||||
* Copyleft (ɔ) 2024 zxkmm under GPL license
|
||||
* Copyleft (ɔ) 2024 zxkmm with the GPL license
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace fs = std::filesystem;
|
|||
|
||||
namespace ui {
|
||||
|
||||
const std::filesystem::path splash_dot_bmp{u"/splash.bmp"};
|
||||
const std::filesystem::path current_using_splash_image{u"/splash.bmp"};
|
||||
|
||||
ScreenshotViewer::ScreenshotViewer(
|
||||
NavigationView& nav,
|
||||
|
@ -108,8 +108,8 @@ SplashViewer::SplashViewer(
|
|||
|
||||
bool SplashViewer::on_key(const KeyEvent key) {
|
||||
if (valid_image && key == KeyEvent::Right) {
|
||||
delete_file(splash_dot_bmp);
|
||||
copy_file(path_, splash_dot_bmp);
|
||||
delete_file(current_using_splash_image);
|
||||
copy_file(path_, current_using_splash_image);
|
||||
}
|
||||
|
||||
nav_.pop();
|
||||
|
@ -125,7 +125,7 @@ void SplashViewer::paint(Painter& painter) {
|
|||
}
|
||||
|
||||
// Show option to set splash screen if it's not already the splash screen
|
||||
if (!path_iequal(path_, splash_dot_bmp)) {
|
||||
if (!path_iequal(path_, current_using_splash_image)) {
|
||||
painter.draw_string({0, 0}, Styles::white, "*RIGHT BUTTON UPDATES SPLASH*");
|
||||
valid_image = true;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
namespace ui {
|
||||
|
||||
extern const std::filesystem::path splash_dot_bmp;
|
||||
extern const std::filesystem::path current_using_splash_image;
|
||||
|
||||
class ScreenshotViewer : public View {
|
||||
public:
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "portapack.hpp"
|
||||
#include "hackrf_hal.hpp"
|
||||
#include "file_path.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <stdio.h>
|
||||
|
@ -35,7 +36,13 @@ namespace ui {
|
|||
|
||||
void SSTVTXView::focus() {
|
||||
if (file_error)
|
||||
nav_.display_modal("No files", "No valid bitmaps\nin /sstv directory.", ABORT);
|
||||
nav_.display_modal("No files",
|
||||
"No valid bitmaps\nin either" +
|
||||
sstv_dir.string() +
|
||||
"\nor\n" +
|
||||
sstv_dir_resources.string() +
|
||||
"directory.",
|
||||
ABORT);
|
||||
else
|
||||
options_bitmaps.focus();
|
||||
}
|
||||
|
@ -172,7 +179,10 @@ void SSTVTXView::start_tx() {
|
|||
}
|
||||
|
||||
void SSTVTXView::on_bitmap_changed(const size_t index) {
|
||||
bmp_file.open("/sstv/" + bitmaps[index].string());
|
||||
auto open_system_dir = bmp_file.open(sstv_dir_user + u"/" + bitmaps[index].string());
|
||||
if (!open_system_dir->ok()) {
|
||||
bmp_file.open(sstv_dir_resources + u"/" + bitmaps[index].string());
|
||||
}
|
||||
bmp_file.read(&bmp_header, sizeof(bmp_header));
|
||||
set_dirty();
|
||||
}
|
||||
|
@ -200,31 +210,47 @@ SSTVTXView::SSTVTXView(
|
|||
NavigationView& nav)
|
||||
: nav_(nav) {
|
||||
std::vector<std::filesystem::path> file_list;
|
||||
std::filesystem::path file_list_index[2];
|
||||
using option_t = std::pair<std::string, int32_t>;
|
||||
using options_t = std::vector<option_t>;
|
||||
options_t bitmap_options;
|
||||
options_t mode_options;
|
||||
uint32_t c;
|
||||
|
||||
// Search for valid bitmaps
|
||||
file_list = scan_root_files(u"/sstv", u"*.bmp");
|
||||
if (!file_list.size()) {
|
||||
file_error = true;
|
||||
return;
|
||||
}
|
||||
for (const auto& file_name : file_list) {
|
||||
if (!bmp_file.open("/sstv/" + file_name.string()).is_valid()) {
|
||||
bmp_file.read(&bmp_header, sizeof(bmp_header));
|
||||
if ((bmp_header.signature == 0x4D42) && // "BM"
|
||||
(bmp_header.width == 320) && // Must be exactly 320x256 pixels for now
|
||||
(bmp_header.height == 256) &&
|
||||
(bmp_header.planes == 1) &&
|
||||
(bmp_header.bpp == 24) && // 24 bpp only
|
||||
(bmp_header.compression == 0)) { // No compression
|
||||
bitmaps.push_back(file_name);
|
||||
file_list_index[0] = sstv_dir_user;
|
||||
file_list_index[1] = u"/" + sstv_dir_resources;
|
||||
|
||||
bool found_files = false;
|
||||
|
||||
for (const auto& now_path : file_list_index) {
|
||||
file_list = scan_root_files(now_path, u"*.bmp");
|
||||
|
||||
if (!file_list.size()) {
|
||||
continue; // Skip to the next path if no files found
|
||||
}
|
||||
|
||||
found_files = true; // Mark that we found some files
|
||||
|
||||
for (const auto& file_name : file_list) {
|
||||
if (!bmp_file.open(now_path / file_name).is_valid()) {
|
||||
bmp_file.read(&bmp_header, sizeof(bmp_header));
|
||||
if ((bmp_header.signature == 0x4D42) && // "BM"
|
||||
(bmp_header.width == 320) && // Must be exactly 320x256 pixels for now
|
||||
(bmp_header.height == 256) &&
|
||||
(bmp_header.planes == 1) &&
|
||||
(bmp_header.bpp == 24) && // 24 bpp only
|
||||
(bmp_header.compression == 0)) { // No compression
|
||||
bitmaps.push_back(file_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_files) {
|
||||
file_error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bitmaps.size()) {
|
||||
file_error = true;
|
||||
return;
|
||||
|
|
|
@ -80,8 +80,14 @@ class SSTVTXView : public View {
|
|||
void prepare_scanline();
|
||||
|
||||
Labels labels{
|
||||
{{1 * 8, 1 * 8}, "File:", Color::light_grey()},
|
||||
{{1 * 8, 3 * 8}, "Mode:", Color::light_grey()}};
|
||||
{{1 * 8, 1 * 8}, "Profile:", Color::light_grey()},
|
||||
{{1 * 8, 3 * 8}, "File:", Color::light_grey()},
|
||||
{{1 * 8, 5 * 8}, "Mode:", Color::light_grey()}};
|
||||
|
||||
OptionsField options_profile{
|
||||
{6 * 8, 1 * 8},
|
||||
16,
|
||||
{}};
|
||||
|
||||
OptionsField options_bitmaps{
|
||||
{6 * 8, 1 * 8},
|
||||
|
|
|
@ -144,7 +144,6 @@ WhipCalcView::WhipCalcView(NavigationView& nav)
|
|||
void WhipCalcView::load_antenna_db() {
|
||||
File antennas_file;
|
||||
auto error = antennas_file.open(whipcalc_dir / u"ANTENNAS.TXT");
|
||||
|
||||
if (error)
|
||||
return;
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ SpectrumInputImageView::SpectrumInputImageView(NavigationView& nav) {
|
|||
|
||||
ensure_directory(spectrum_dir);
|
||||
open_view->push_dir(spectrum_dir);
|
||||
// tempnewnote: const var removed
|
||||
|
||||
open_view->on_changed = [this](std::filesystem::path new_file_path) {
|
||||
this->file = new_file_path.string();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyleft (ɔ) 2024 zxkmm with the GPL license
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
|
@ -22,6 +23,7 @@
|
|||
|
||||
#include "file.hpp"
|
||||
#include "complex.hpp"
|
||||
#include "file_path.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <codecvt>
|
||||
|
@ -368,6 +370,15 @@ std::filesystem::filesystem_error ensure_directory(
|
|||
return make_new_directory(dir_path);
|
||||
}
|
||||
|
||||
void ensure_fake_directories(
|
||||
const std::filesystem::path& dir_path) {
|
||||
std::filesystem::path combined_user_dir = user_dir / dir_path;
|
||||
std::filesystem::path combimed_system_dir = system_dir / dir_path;
|
||||
|
||||
ensure_directory(combimed_system_dir);
|
||||
ensure_directory(combined_user_dir);
|
||||
}
|
||||
|
||||
namespace std {
|
||||
namespace filesystem {
|
||||
|
||||
|
@ -454,6 +465,49 @@ path path::filename() const {
|
|||
}
|
||||
}
|
||||
|
||||
path path::remove_first_level() const { // /abc/def/ghi/hjk.q to /def/ghi/hjk.q
|
||||
|
||||
std::size_t start_index = _s.find(preferred_separator);
|
||||
if (start_index == _s.npos) {
|
||||
return _s;
|
||||
} else {
|
||||
start_index += 1; // To move past the first slash
|
||||
std::size_t end_index = _s.find(preferred_separator, start_index);
|
||||
if (end_index == _s.npos) {
|
||||
end_index = _s.length(); // If there's no more slashes, end at the end of the string
|
||||
}
|
||||
return _s.substr(end_index);
|
||||
}
|
||||
}
|
||||
|
||||
path path::extract_first_level() const { // /abc/def/ghi/hjk.q to /abc
|
||||
|
||||
const auto first_separator = _s.find_first_of(preferred_separator);
|
||||
if (first_separator == _s.npos) {
|
||||
return _s;
|
||||
} else {
|
||||
const auto second_separator = _s.find_first_of(preferred_separator, first_separator + 1);
|
||||
if (second_separator == _s.npos) {
|
||||
return _s.substr(0, first_separator);
|
||||
} else {
|
||||
return _s.substr(0, second_separator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
path path::absolute_trimmed_path() const {
|
||||
basic_string<char16_t> path_str = _s.substr();
|
||||
|
||||
if (path_str.front() == '/') {
|
||||
path_str.erase(0, 1);
|
||||
}
|
||||
if (path_str.back() == '/') {
|
||||
path_str.pop_back();
|
||||
}
|
||||
|
||||
return path{path_str};
|
||||
}
|
||||
|
||||
path path::stem() const {
|
||||
const auto t = filename().native();
|
||||
const auto index = t.find_last_of(u'.');
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyleft (ɔ) 2024 zxkmm with the GPL license
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
|
@ -116,6 +117,9 @@ struct path {
|
|||
path parent_path() const;
|
||||
path extension() const;
|
||||
path filename() const;
|
||||
path remove_first_level() const;
|
||||
path extract_first_level() const;
|
||||
path absolute_trimmed_path() const;
|
||||
path stem() const;
|
||||
|
||||
bool empty() const {
|
||||
|
@ -276,6 +280,7 @@ std::filesystem::filesystem_error file_update_date(const std::filesystem::path&
|
|||
std::filesystem::filesystem_error make_new_file(const std::filesystem::path& file_path);
|
||||
std::filesystem::filesystem_error make_new_directory(const std::filesystem::path& dir_path);
|
||||
std::filesystem::filesystem_error ensure_directory(const std::filesystem::path& dir_path);
|
||||
void ensure_fake_directories(const std::filesystem::path& dir_path);
|
||||
|
||||
template <typename TCallback>
|
||||
void scan_root_files(const std::filesystem::path& directory, const std::filesystem::path& extension, const TCallback& fn) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Mark Thompson
|
||||
* copyleft (ɔ) 2024 zxkmm with the GPL license
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
|
@ -22,28 +23,104 @@
|
|||
#include "file_path.hpp"
|
||||
#include "file.hpp"
|
||||
|
||||
const std::filesystem::path adsb_dir = u"ADSB";
|
||||
const std::filesystem::path ais_dir = u"AIS";
|
||||
const std::filesystem::path apps_dir = u"APPS";
|
||||
const std::filesystem::path aprs_dir = u"APRS";
|
||||
const std::filesystem::path audio_dir = u"AUDIO";
|
||||
const std::filesystem::path blerx_dir = u"BLERX";
|
||||
const std::filesystem::path bletx_dir = u"BLETX";
|
||||
const std::filesystem::path captures_dir = u"CAPTURES";
|
||||
const std::filesystem::path debug_dir = u"DEBUG";
|
||||
const std::filesystem::path firmware_dir = u"FIRMWARE";
|
||||
const std::filesystem::path freqman_dir = u"FREQMAN";
|
||||
const std::filesystem::path gps_dir = u"GPS";
|
||||
const std::filesystem::path logs_dir = u"LOGS";
|
||||
const std::filesystem::path looking_glass_dir = u"LOOKINGGLASS";
|
||||
const std::filesystem::path playlist_dir = u"PLAYLIST";
|
||||
const std::filesystem::path remotes_dir = u"REMOTES";
|
||||
const std::filesystem::path repeat_rec_path = u"CAPTURES";
|
||||
const std::filesystem::path samples_dir = u"SAMPLES";
|
||||
const std::filesystem::path screenshots_dir = u"SCREENSHOTS";
|
||||
const std::filesystem::path settings_dir = u"SETTINGS";
|
||||
const std::filesystem::path spectrum_dir = u"SPECTRUM";
|
||||
const std::filesystem::path splash_dir = u"SPLASH";
|
||||
const std::filesystem::path sstv_dir = u"SSTV";
|
||||
const std::filesystem::path wav_dir = u"WAV";
|
||||
const std::filesystem::path whipcalc_dir = u"WHIPCALC";
|
||||
const std::filesystem::path adsb_dir = u"SYS/ADSB"; // this dir no need to seperate profiles since all are resources
|
||||
|
||||
const std::filesystem::path ais_dir = u"SYS/AIS"; // this dir no need to seperate profiles since all are resources
|
||||
|
||||
const std::filesystem::path apps_dir = u"APPS"; // currently in root
|
||||
|
||||
// APRS
|
||||
const std::filesystem::path aprs_dir = u"APRS"; // fake path
|
||||
const std::filesystem::path aprs_dir_user = u"/APRS";
|
||||
const std::filesystem::path aprs_dir_resources = u"SYS/APRS";
|
||||
|
||||
// AUDIO
|
||||
const std::filesystem::path audio_dir = u"AUDIO"; // fake path
|
||||
const std::filesystem::path audio_dir_user = u"/AUDIO";
|
||||
const std::filesystem::path audio_dir_resources = u"SYS/AUDIO";
|
||||
|
||||
// BLERX
|
||||
const std::filesystem::path blerx_dir = u"BLERX"; // fake path
|
||||
const std::filesystem::path blerx_dir_user = u"/BLERX";
|
||||
const std::filesystem::path blerx_dir_resources = u"SYS/BLERX";
|
||||
|
||||
// BLETX
|
||||
const std::filesystem::path bletx_dir = u"BLETX"; // fake path
|
||||
const std::filesystem::path bletx_dir_user = u"/BLETX";
|
||||
const std::filesystem::path bletx_dir_resources = u"SYS/BLETX";
|
||||
|
||||
// CAPTURES
|
||||
const std::filesystem::path captures_dir = u"CAPTURES"; // fake path
|
||||
const std::filesystem::path captures_dir_user = u"/CAPTURES"; // used by recon and capture apps to save capture C16 into USR
|
||||
const std::filesystem::path captures_dir_resources = u"SYS/CAPTURES";
|
||||
|
||||
const std::filesystem::path debug_dir = u"DEBUG"; // in root
|
||||
|
||||
const std::filesystem::path firmware_dir = u"FIRMWARE"; // in root
|
||||
|
||||
// FREQMAN
|
||||
const std::filesystem::path freqman_dir = u"FREQMAN"; // fake path
|
||||
const std::filesystem::path freqman_dir_user = u"/FREQMAN";
|
||||
const std::filesystem::path freqman_dir_resources = u"SYS/FREQMAN";
|
||||
|
||||
const std::filesystem::path fskrx_dir_user = u"/FSKRX";
|
||||
|
||||
const std::filesystem::path gps_dir = u"/GPS";
|
||||
|
||||
const std::filesystem::path logs_dir = u"/LOGS";
|
||||
|
||||
const std::filesystem::path looking_glass_dir = u"SYS/LOOKINGGLASS";
|
||||
|
||||
// PLAYLIST
|
||||
const std::filesystem::path playlist_dir = u"PLAYLIST"; // fake dir
|
||||
const std::filesystem::path playlist_dir_user = u"/PLAYLIST"; // used by playlist aka replay app, to save nre created PPL files into USR
|
||||
const std::filesystem::path playlist_dir_resources = u"SYS/PLAYLIST"; //
|
||||
|
||||
// REMOTE
|
||||
const std::filesystem::path remotes_dir = u"REMOTES"; // fake dir
|
||||
const std::filesystem::path remotes_dir_user = u"/REMOTES";
|
||||
const std::filesystem::path remotes_dir_resources = u"SYS/REMOTES";
|
||||
|
||||
// recon app
|
||||
const std::filesystem::path repeat_rec_path = u"/CAPTURES"; // this is for recon captures files
|
||||
|
||||
const std::filesystem::path samples_dir = u"SYS/CAPTURES"; // TODO: rename var name
|
||||
|
||||
const std::filesystem::path screenshots_dir = u"/SCREENSHOTS"; // TODO: rename var name to screenshots_dir
|
||||
|
||||
const std::filesystem::path settings_dir = u"/SETTINGS";
|
||||
|
||||
const std::filesystem::path spectrum_dir = u"SPECTRUM"; // fake dir
|
||||
|
||||
const std::filesystem::path splash_dir = u"/SPLASH";
|
||||
|
||||
const std::filesystem::path sstv_dir = u"SSTV"; // fake path
|
||||
const std::filesystem::path sstv_dir_user = u"/SSTV";
|
||||
const std::filesystem::path sstv_dir_resources = u"SYS/SSTV";
|
||||
|
||||
const std::filesystem::path system_dir = u"/SYS"; // in root
|
||||
const std::filesystem::path user_dir = u"/"; // root
|
||||
|
||||
// WAV
|
||||
const std::filesystem::path wav_dir = u"WAV"; // fake path
|
||||
const std::filesystem::path wav_dir_user = u"/WAV";
|
||||
const std::filesystem::path wav_dir_resources = u"SYS/WAV";
|
||||
|
||||
const std::filesystem::path whipcalc_dir = u"SYS/WHIPCALC";
|
||||
|
||||
// vector
|
||||
|
||||
const std::vector<std::string> allow_dirs = {
|
||||
"ADSB",
|
||||
"AIS",
|
||||
"BLETX",
|
||||
"GPS",
|
||||
"LOOKINGGLASS",
|
||||
"PLAYLIST",
|
||||
"REMOTES",
|
||||
"SPLASH",
|
||||
"SSTV",
|
||||
"WAV",
|
||||
"WHIPCALC",
|
||||
"SAMPLES",
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Mark Thompson
|
||||
* copyleft (ɔ) 2024 zxkmm with the GPL license
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
|
@ -25,29 +26,83 @@
|
|||
#include "file.hpp"
|
||||
|
||||
extern const std::filesystem::path adsb_dir;
|
||||
|
||||
extern const std::filesystem::path ais_dir;
|
||||
|
||||
extern const std::filesystem::path apps_dir;
|
||||
|
||||
extern const std::filesystem::path aprs_dir;
|
||||
extern const std::filesystem::path aprs_dir_user;
|
||||
extern const std::filesystem::path aprs_dir_resources;
|
||||
|
||||
extern const std::filesystem::path audio_dir;
|
||||
extern const std::filesystem::path audio_dir_user;
|
||||
extern const std::filesystem::path audio_dir_resources;
|
||||
|
||||
extern const std::filesystem::path blerx_dir;
|
||||
extern const std::filesystem::path blerx_dir_user;
|
||||
extern const std::filesystem::path blerx_dir_resources;
|
||||
|
||||
extern const std::filesystem::path bletx_dir;
|
||||
extern const std::filesystem::path bletx_dir_user;
|
||||
extern const std::filesystem::path bletx_dir_resources;
|
||||
|
||||
extern const std::filesystem::path captures_dir;
|
||||
extern const std::filesystem::path captures_dir_user;
|
||||
extern const std::filesystem::path captures_dir_resources;
|
||||
|
||||
extern const std::filesystem::path debug_dir;
|
||||
|
||||
extern const std::filesystem::path firmware_dir;
|
||||
|
||||
extern const std::filesystem::path freqman_dir;
|
||||
extern const std::filesystem::path freqman_dir_user;
|
||||
extern const std::filesystem::path freqman_dir_resources;
|
||||
|
||||
extern const std::filesystem::path fskrx_dir_user;
|
||||
|
||||
extern const std::filesystem::path gps_dir;
|
||||
|
||||
extern const std::filesystem::path logs_dir;
|
||||
|
||||
extern const std::filesystem::path looking_glass_dir;
|
||||
|
||||
extern const std::filesystem::path playlist_dir;
|
||||
extern const std::filesystem::path playlist_dir_user;
|
||||
extern const std::filesystem::path playlist_dir_resources;
|
||||
|
||||
extern const std::filesystem::path remotes_dir;
|
||||
extern const std::filesystem::path remotes_dir_user;
|
||||
extern const std::filesystem::path remotes_dir_resources;
|
||||
|
||||
extern const std::filesystem::path repeat_rec_path;
|
||||
|
||||
extern const std::filesystem::path samples_dir;
|
||||
|
||||
extern const std::filesystem::path screenshots_dir;
|
||||
|
||||
extern const std::filesystem::path settings_dir;
|
||||
|
||||
extern const std::filesystem::path spectrum_dir;
|
||||
|
||||
extern const std::filesystem::path splash_dir;
|
||||
|
||||
extern const std::filesystem::path sstv_dir;
|
||||
extern const std::filesystem::path sstv_dir_user;
|
||||
extern const std::filesystem::path sstv_dir_resources;
|
||||
|
||||
extern const std::filesystem::path system_dir;
|
||||
|
||||
extern const std::filesystem::path user_dir;
|
||||
|
||||
extern const std::filesystem::path wav_dir;
|
||||
|
||||
extern const std::filesystem::path wav_dir_user;
|
||||
|
||||
extern const std::filesystem::path wav_dir_resources;
|
||||
|
||||
extern const std::filesystem::path whipcalc_dir;
|
||||
|
||||
extern const std::vector<std::string> allow_dirs;
|
||||
|
||||
#endif /* __FILE_PATH_H__ */
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2023 gullradriel, Nilorea Studio Inc.
|
||||
* Copyright (C) 2023 Kyle Reed
|
||||
* copyleft (ɔ) 2024 zxkmm with the GPL license
|
||||
*
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
|
@ -39,6 +41,7 @@
|
|||
namespace fs = std::filesystem;
|
||||
|
||||
const std::filesystem::path freqman_extension{u".TXT"};
|
||||
bool current_is_system_item{true};
|
||||
|
||||
// NB: Don't include UI headers to keep this code unit testable.
|
||||
using option_t = std::pair<std::string, int32_t>;
|
||||
|
@ -218,21 +221,32 @@ std::string freqman_entry_get_step_string_short(freqman_index_t step) {
|
|||
return {};
|
||||
}
|
||||
|
||||
const std::filesystem::path get_freqman_path(const std::string& stem) {
|
||||
return freqman_dir / stem + freqman_extension;
|
||||
const std::filesystem::path get_freqman_path(const std::string& stem, dir_profile profile) {
|
||||
switch (profile) {
|
||||
case dir_profile::ProfileSystem:
|
||||
return freqman_dir_resources / stem + freqman_extension;
|
||||
break;
|
||||
case dir_profile::ProfileUser:
|
||||
return freqman_dir_user / stem + freqman_extension;
|
||||
break;
|
||||
default:
|
||||
// throw ?
|
||||
return freqman_dir_user / stem + freqman_extension;
|
||||
}
|
||||
}
|
||||
|
||||
bool create_freqman_file(const std::string& file_stem) {
|
||||
auto fs_error = make_new_file(get_freqman_path(file_stem));
|
||||
// always create in user dir, so no judgement here
|
||||
auto fs_error = make_new_file(get_freqman_path(file_stem, dir_profile::ProfileUser)); // only allow create on usr dir
|
||||
return fs_error.ok();
|
||||
}
|
||||
|
||||
bool load_freqman_file(const std::string& file_stem, freqman_db& db, freqman_load_options options) {
|
||||
return parse_freqman_file(get_freqman_path(file_stem), db, options);
|
||||
bool load_freqman_file(const std::string& file_stem, freqman_db& db, freqman_load_options options, dir_profile profile) {
|
||||
return parse_freqman_file(get_freqman_path(file_stem, profile), db, options);
|
||||
}
|
||||
|
||||
void delete_freqman_file(const std::string& file_stem) {
|
||||
delete_file(get_freqman_path(file_stem));
|
||||
delete_file(get_freqman_path(file_stem, dir_profile::ProfileUser)); // don't allow to delete sys files
|
||||
}
|
||||
|
||||
std::string pretty_string(const freqman_entry& entry, size_t max_length) {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2023 gullradriel, Nilorea Studio Inc.
|
||||
* Copyright (C) 2023 Kyle Reed
|
||||
* copyleft (ɔ) 2024 zxkmm with the GPL license
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
|
@ -37,6 +38,7 @@
|
|||
|
||||
/* Defined in freqman_db.cpp */
|
||||
extern const std::filesystem::path freqman_extension;
|
||||
extern bool current_is_system_item;
|
||||
|
||||
using freqman_index_t = uint8_t;
|
||||
constexpr freqman_index_t freqman_invalid_index = static_cast<freqman_index_t>(-1);
|
||||
|
@ -60,6 +62,11 @@ enum class freqman_type : uint8_t {
|
|||
Unknown,
|
||||
};
|
||||
|
||||
enum class dir_profile : uint8_t {
|
||||
ProfileUser = 1,
|
||||
ProfileSystem = 2
|
||||
};
|
||||
|
||||
/* Tables for next round of changes.
|
||||
* // TODO: attempt to consolidate all of these values
|
||||
* // and settings into a single location.
|
||||
|
@ -177,9 +184,9 @@ using freqman_entry_ptr = std::unique_ptr<freqman_entry>;
|
|||
using freqman_db = std::vector<freqman_entry_ptr>;
|
||||
|
||||
/* Gets the full path for a given file stem (no extension). */
|
||||
const std::filesystem::path get_freqman_path(const std::string& stem);
|
||||
const std::filesystem::path get_freqman_path(const std::string& stem, dir_profile profile);
|
||||
bool create_freqman_file(const std::string& file_stem);
|
||||
bool load_freqman_file(const std::string& file_stem, freqman_db& db, freqman_load_options options);
|
||||
bool load_freqman_file(const std::string& file_stem, freqman_db& db, freqman_load_options options, dir_profile profile);
|
||||
void delete_freqman_file(const std::string& file_stem);
|
||||
|
||||
/* Gets a pretty string representation for an entry. */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* copyleft (ɔ) 2023 zxkmm under GPL license
|
||||
* copyleft (ɔ) 2023 zxkmm with the GPL license
|
||||
* Copyright (C) 2023 u-foka
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* copyleft (ɔ) 2023 zxkmm under GPL license
|
||||
* copyleft (ɔ) 2023 zxkmm with the GPL license
|
||||
* Copyright (C) 2023 u-foka
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2024 u-foka
|
||||
* Copyleft (ɔ) 2024 zxkmm under GPL license
|
||||
* Copyleft (ɔ) 2024 zxkmm with the GPL license
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
|
@ -465,6 +465,11 @@ void SystemStatusView::set_back_hidden(bool new_value) {
|
|||
void SystemStatusView::set_title_image_enabled(bool new_value) {
|
||||
if (new_value) {
|
||||
add_child(&button_title);
|
||||
if (!already_shown_sdcard_warning_in_this_boot) {
|
||||
// the modal warning can't be called from constructor since the nav isn't valid at that time, so putting here as a work around
|
||||
new_sdcard_structure_checker();
|
||||
already_shown_sdcard_warning_in_this_boot = true;
|
||||
}
|
||||
} else {
|
||||
remove_child(&button_title);
|
||||
}
|
||||
|
@ -599,6 +604,93 @@ void SystemStatusView::rtc_battery_workaround() {
|
|||
}
|
||||
}
|
||||
|
||||
void SystemStatusView::new_sdcard_structure_checker() {
|
||||
const std::filesystem::path root_dir = u"/";
|
||||
const std::filesystem::path resources_dir = u"SYS";
|
||||
std::vector<std::filesystem::path> directories = scan_root_directories(root_dir);
|
||||
|
||||
auto scan_result = std::find(directories.begin(), directories.end(), resources_dir);
|
||||
|
||||
auto sd_status = sd_card::status();
|
||||
|
||||
if (
|
||||
nav_.is_valid() &&
|
||||
(scan_result == directories.end()) &&
|
||||
(sd_status == sd_card::Status::Mounted)) {
|
||||
nav_.display_modal(
|
||||
"Warning",
|
||||
" WARNING!!!\n"
|
||||
"SD Card content changed\n"
|
||||
"in this update,\n"
|
||||
"Press YES to auto move.\n"
|
||||
"After finished,\n"
|
||||
"you should move your own\n"
|
||||
"files back into\n"
|
||||
"original folders,\n"
|
||||
"which are now only for users.\n"
|
||||
"You can also choose NO,\n"
|
||||
"and then manually merge\n"
|
||||
"following the Wiki.\n"
|
||||
"Details:\n"
|
||||
"Mayhem wiki - Updating",
|
||||
YESNO,
|
||||
[this](bool choice) {
|
||||
if (choice) {
|
||||
new_sdcard_structure_worker();
|
||||
}
|
||||
},
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
void SystemStatusView::new_sdcard_structure_worker() {
|
||||
const std::filesystem::path root_dir = u"/";
|
||||
const std::filesystem::path system_dir = u"SYS";
|
||||
|
||||
/// worker log
|
||||
std::filesystem::path filename{};
|
||||
File automove_dump_file{};
|
||||
ensure_directory(logs_dir);
|
||||
filename = next_filename_matching_pattern(logs_dir + "/AUTOMOVE_LOG_????.TXT");
|
||||
automove_dump_file.create(filename);
|
||||
|
||||
std::vector<std::filesystem::path> root_dirs = scan_root_directories(root_dir);
|
||||
|
||||
std::vector<std::string> scan_result_string_vec;
|
||||
for (const auto& e : root_dirs) {
|
||||
scan_result_string_vec.push_back(e.string());
|
||||
}
|
||||
|
||||
std::string scan_result_string = "";
|
||||
for (const auto& e : scan_result_string_vec) {
|
||||
scan_result_string += e + "\n";
|
||||
}
|
||||
|
||||
automove_dump_file.write_line(scan_result_string + "\n\n");
|
||||
|
||||
/// worker moving folders
|
||||
ensure_directory(system_dir);
|
||||
|
||||
auto directories = scan_root_directories(root_dir);
|
||||
|
||||
for (const auto& e : root_dirs) {
|
||||
for (const auto& d : allow_dirs) {
|
||||
if (e.absolute_trimmed_path().string() == d) {
|
||||
std::filesystem::path new_path = system_dir / d;
|
||||
rename_file(e, new_path);
|
||||
automove_dump_file.write_line("Moved: " + e.string() + " to " + new_path.string() + "\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// worker renaming
|
||||
rename_file(u"/SYS/SAMPLES", u"/SYS/CAPTURES"); // it's because, make it easier to use the sample folder.
|
||||
|
||||
/// worker check adding flag
|
||||
make_new_file(U"/AUTO_MOVED"); // add a flag to check in case if need something as flag to check in the future
|
||||
}
|
||||
|
||||
/* Information View *****************************************************/
|
||||
|
||||
InformationView::InformationView(
|
||||
|
@ -1006,7 +1098,7 @@ BMPView::BMPView(NavigationView& nav) {
|
|||
}
|
||||
|
||||
void BMPView::paint(Painter&) {
|
||||
if (!portapack::display.drawBMP2({0, 0}, splash_dot_bmp))
|
||||
if (!portapack::display.drawBMP2({0, 0}, current_using_splash_image))
|
||||
portapack::display.drawBMP({(240 - 230) / 2, (320 - 50) / 2 - 10}, splash_bmp, false);
|
||||
}
|
||||
|
||||
|
@ -1079,15 +1171,17 @@ void ModalMessageView::paint(Painter& painter) {
|
|||
auto lines = split_string(message_, '\n');
|
||||
for (size_t i = 0; i < lines.size(); ++i) {
|
||||
painter.draw_string(
|
||||
|
||||
{1 * 8, (Coord)(((compact) ? 8 * 3 : 120) + (i * 16))},
|
||||
|
||||
style(),
|
||||
lines[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void ModalMessageView::focus() {
|
||||
if ((type_ == YESNO)) {
|
||||
button_yes.focus();
|
||||
if (type_ == YESNO) {
|
||||
button_no.focus(); // it should default to NO like all the operating system
|
||||
} else {
|
||||
button_ok.focus();
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2024 u-foka
|
||||
* Copyleft (ɔ) 2024 zxkmm under GPL license
|
||||
* Copyleft (ɔ) 2024 zxkmm with the GPL license
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
|
@ -191,6 +191,7 @@ class SystemStatusView : public View {
|
|||
void set_title(const std::string new_value);
|
||||
|
||||
private:
|
||||
bool already_shown_sdcard_warning_in_this_boot{false};
|
||||
static constexpr auto default_title = "";
|
||||
bool batt_info_up = false; // to prevent show multiple batt info dialog
|
||||
NavigationView& nav_;
|
||||
|
@ -289,6 +290,10 @@ class SystemStatusView : public View {
|
|||
void refresh();
|
||||
void on_clk();
|
||||
void rtc_battery_workaround();
|
||||
|
||||
void new_sdcard_structure_checker();
|
||||
void new_sdcard_structure_worker();
|
||||
|
||||
void on_battery_data(const BatteryStateMessage* msg);
|
||||
void on_battery_details();
|
||||
|
||||
|
@ -447,17 +452,17 @@ class ModalMessageView : public View {
|
|||
const bool compact;
|
||||
|
||||
Button button_ok{
|
||||
{10 * 8, 14 * 16, 10 * 8, 48},
|
||||
{0, screen_height - 8 * 8, screen_width, 48},
|
||||
"OK",
|
||||
};
|
||||
|
||||
Button button_yes{
|
||||
{5 * 8, 14 * 16, 8 * 8, 48},
|
||||
{0, screen_height - 8 * 8, screen_width / 2, 48},
|
||||
"YES",
|
||||
};
|
||||
|
||||
Button button_no{
|
||||
{17 * 8, 14 * 16, 8 * 8, 48},
|
||||
{screen_width / 2, screen_height - 8 * 8, screen_width / 2, 48},
|
||||
"NO",
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyleft (ɔ) 2024 zxkmm under GPL license
|
||||
* Copyleft (ɔ) 2024 zxkmm with the GPL license
|
||||
* Copyright (C) 2024 u-foka
|
||||
* Copyright (C) 2024 Mark Thompson
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyleft (ɔ) 2024 zxkmm under GPL license
|
||||
* Copyleft (ɔ) 2024 zxkmm with the GPL license
|
||||
* Copyright (C) 2024 u-foka
|
||||
* Copyright (C) 2024 Mark Thompson
|
||||
*
|
||||
|
@ -347,42 +347,6 @@ class IO {
|
|||
addr(1); /* Set up for data phase (most likely after a command) */
|
||||
}
|
||||
|
||||
// void high_contrast(ui::Color& pixel, size_t contrast_level_shift) { // TODO
|
||||
// uint16_t r = (pixel.v >> 11) & 0x1F;
|
||||
// uint16_t g = (pixel.v >> 5) & 0x3F;
|
||||
// uint16_t b = pixel.v & 0x1F;
|
||||
//
|
||||
// if ((r << contrast_level_shift) > 0x1F) { // should be slightly smaller, need more obverse...
|
||||
// r = 0x1F;
|
||||
// } else {
|
||||
// r = r << contrast_level_shift;
|
||||
// }
|
||||
//
|
||||
// if ((g << contrast_level_shift) > 0x3F) { // same as above
|
||||
// g = 0x3F;
|
||||
// } else {
|
||||
// g = g << contrast_level_shift;
|
||||
// }
|
||||
//
|
||||
// if ((b << contrast_level_shift) > 0x1F) { // same as above
|
||||
// b = 0x1F;
|
||||
// } else {
|
||||
// b = b << contrast_level_shift;
|
||||
// }
|
||||
//
|
||||
// pixel.v = (r << 11) | (g << 5) | b;
|
||||
// }
|
||||
//
|
||||
// void gray_scale(ui::Color& pixel) { // TODO: the blackwhite not looks right....
|
||||
// uint16_t r = (pixel.v >> 11) & 0x1F;
|
||||
// uint16_t g = (pixel.v >> 5) & 0x3F;
|
||||
// uint16_t b = pixel.v & 0x1F;
|
||||
//
|
||||
// uint16_t average = (r + g + b) / 3;
|
||||
//
|
||||
// pixel.v = (average << 11) | (average << 5) | average;
|
||||
// }
|
||||
|
||||
void lcd_write_data(const uint32_t value) __attribute__((always_inline)) {
|
||||
// NOTE: Assumes and DIR=0 and ADDR=1 from command phase.
|
||||
data_write_high(value); /* Drive high byte */
|
||||
|
|
|
@ -23,11 +23,11 @@ import sys
|
|||
import struct
|
||||
from PIL import Image
|
||||
|
||||
outfile = open('../../sdcard/ADSB/world_map.bin', 'wb')
|
||||
outfile = open('../../sdcard/SYS/ADSB/world_map.bin', 'wb')
|
||||
|
||||
# Allow for bigger images
|
||||
Image.MAX_IMAGE_PIXELS = None
|
||||
im = Image.open("../../sdcard/ADSB/world_map.jpg")
|
||||
im = Image.open("../../sdcard/SYS/ADSB/world_map.jpg")
|
||||
pix = im.load()
|
||||
# Write as unsigned short (2 bytes) as little endian
|
||||
outfile.write(struct.pack('<H', im.size[0]))
|
||||
|
|
Loading…
Reference in New Issue