diff --git a/firmware/application/freqman.cpp b/firmware/application/freqman.cpp index 930655b8..0ec47d5d 100644 --- a/firmware/application/freqman.cpp +++ b/firmware/application/freqman.cpp @@ -23,9 +23,6 @@ #include "freqman.hpp" #include -#define FREQMAN_DESC_MAX_LEN 30 -#define FREQMAN_MAX_PER_FILE 256 - std::vector get_freqman_files() { std::vector file_list; @@ -40,9 +37,9 @@ std::vector get_freqman_files() { bool load_freqman_file(std::string& file_stem, freqman_db &db) { File freqman_file; - size_t length, span_end, n = 0; - uint64_t seek_pos = 0; + size_t length, n = 0, file_position = 0; char * pos; + char * line_start; char * line_end; std::string description; rf::Frequency value; @@ -54,43 +51,52 @@ bool load_freqman_file(std::string& file_stem, freqman_db &db) { if (result.is_valid()) return false; - freqman_file.read(file_data, 256); - - while ((pos = strstr(file_data, "f=")) && (n < FREQMAN_MAX_PER_FILE)) { + while (1) { + freqman_file.seek(file_position); - // Trim buffer at end of last complete line - line_end = file_data; - span_end = strcspn(line_end, "\x0A"); - if (span_end) { - if (span_end == strlen(line_end)) - return true; - } - line_end += (span_end + 1); - *line_end = (char)0; + memset(file_data, 0, 256); + auto read_size = freqman_file.read(file_data, 256); + if (read_size.is_error()) + return false; // Read error - // Read frequency - pos += 2; - value = strtoll(pos, nullptr, 10); - - // Read description until , or LF - pos = strstr(file_data, "d="); - if (pos) { - pos += 2; - length = std::min(strcspn(pos, ",\x0A"), (size_t)FREQMAN_DESC_MAX_LEN); - description = string(pos, length); - } else { - description = "-"; + file_position += sizeof(file_data); + + line_start = file_data; + + pos = strstr(file_data, "f="); + if (!pos) break; + + // Look for complete lines in buffer + while ((line_end = strstr(line_start, "\x0A"))) { + // Read frequency + pos = strstr(line_start, "f="); + if (pos) { + pos += 2; + value = strtoll(pos, nullptr, 10); + } else + value = 0; + + // Read description until , or LF + pos = strstr(line_start, "d="); + if (pos) { + pos += 2; + length = std::min(strcspn(pos, ",\x0A"), (size_t)FREQMAN_DESC_MAX_LEN); + description = string(pos, length); + } else + description = "-"; + + db.entries.push_back({ value, "", description }); + n++; + + if (n >= FREQMAN_MAX_PER_FILE) return true; + + line_start = line_end + 1; } - db.entries.push_back({ value, "", description }); - n++; - - seek_pos += (line_end - file_data); - - if (freqman_file.seek(seek_pos).value() == seek_pos) - break; - else - freqman_file.read(file_data, 256); + if (read_size.value() != sizeof(file_data)) + return true; // End of file + + file_position -= (file_data + sizeof(file_data) - line_start); } return true; diff --git a/firmware/application/freqman.hpp b/firmware/application/freqman.hpp index 53c9fe03..527d2089 100644 --- a/firmware/application/freqman.hpp +++ b/firmware/application/freqman.hpp @@ -29,6 +29,10 @@ #ifndef __FREQMAN_H__ #define __FREQMAN_H__ +#define FREQMAN_DESC_MAX_LEN 30 +#define FREQMAN_MAX_PER_FILE 50 +#define FREQMAN_MAX_PER_FILE_STR "50" + using namespace ui; using namespace std; @@ -40,9 +44,9 @@ enum freqman_error { }; struct freqman_entry { - rf::Frequency value; - std::string frequency_str; - std::string description; + rf::Frequency value { 0 }; + std::string frequency_str { }; + std::string description { }; }; struct freqman_db { diff --git a/firmware/application/ui_freqman.cpp b/firmware/application/ui_freqman.cpp index d712d1cc..e91bfa39 100644 --- a/firmware/application/ui_freqman.cpp +++ b/firmware/application/ui_freqman.cpp @@ -35,9 +35,6 @@ FreqManBaseView::FreqManBaseView( { file_list = get_freqman_files(); - if (!file_list.size()) - error_ = ERROR_NOFILES; - add_children({ &label_category, &button_exit @@ -46,7 +43,8 @@ FreqManBaseView::FreqManBaseView( if (file_list.size()) { add_child(&options_category); populate_categories(); - } + } else + error_ = ERROR_NOFILES; // Default function on_change_category = [this](int32_t category_id) { @@ -64,18 +62,23 @@ void FreqManBaseView::focus() { if (error_ == ERROR_ACCESS) { nav_.display_modal("Error", "File acces error", ABORT, nullptr); } else if (error_ == ERROR_NOFILES) { - nav_.display_modal("Error", "No database files", ABORT, nullptr); + nav_.display_modal("Error", "No database files\nin /freqman", ABORT, nullptr); } else { options_category.focus(); } } -bool FreqManBaseView::populate_categories() { +void FreqManBaseView::populate_categories() { categories.clear(); for (size_t n = 0; n < file_list.size(); n++) categories.emplace_back(std::make_pair(file_list[n], n)); + // Alphabetical sort + std::sort(categories.begin(), categories.end(), [](auto &left, auto &right) { + return left.first < right.first; + }); + options_category.set_options(categories); options_category.set_selected_index(0); @@ -83,8 +86,6 @@ bool FreqManBaseView::populate_categories() { if (on_change_category) on_change_category(category_id); }; - - return true; } void FreqManBaseView::change_category(int32_t category_id) { @@ -120,23 +121,40 @@ void FreqManBaseView::refresh_list() { } }); } - + menu_view.set_highlighted(0); // Refresh } } +void FrequencySaveView::save_current_file() { + if (database.entries.size() > FREQMAN_MAX_PER_FILE) { + nav_.display_modal( + "Error", "Too many entries, maximum is\n" FREQMAN_MAX_PER_FILE_STR ". Trim list ?", + YESNO, + [this](bool choice) { + if (choice) { + database.entries.resize(FREQMAN_MAX_PER_FILE); + save_freqman_file(file_list[current_category_id], database); + } + nav_.pop(); + } + ); + } else { + save_freqman_file(file_list[current_category_id], database); + nav_.pop(); + } +} + void FrequencySaveView::on_save_name() { text_prompt(nav_, &desc_buffer, 28, [this](std::string * buffer) { database.entries.push_back({ value_, "", *buffer }); - save_freqman_file(file_list[current_category_id], database); - nav_.pop(); + save_current_file(); }); } void FrequencySaveView::on_save_timestamp() { database.entries.push_back({ value_, "", live_timestamp.string() }); - save_freqman_file(file_list[current_category_id], database); - nav_.pop(); + save_current_file(); } FrequencySaveView::FrequencySaveView( diff --git a/firmware/application/ui_freqman.hpp b/firmware/application/ui_freqman.hpp index 65ff734b..3fc80a47 100644 --- a/firmware/application/ui_freqman.hpp +++ b/firmware/application/ui_freqman.hpp @@ -54,7 +54,7 @@ protected: std::vector file_list { }; int32_t current_category_id { 0 }; - bool populate_categories(); + void populate_categories(); void change_category(int32_t category_id); void refresh_list(); @@ -95,6 +95,7 @@ private: void on_save_name(); void on_save_timestamp(); + void save_current_file(); BigFrequency big_display { { 4, 2 * 16, 28 * 8, 32 }, diff --git a/firmware/portapack-h1-havoc.bin b/firmware/portapack-h1-havoc.bin index f890984b..6be22de3 100644 Binary files a/firmware/portapack-h1-havoc.bin and b/firmware/portapack-h1-havoc.bin differ