Add file reader (#1155)

* Add file reader
* Add a simple test example of parsing settings.
* Use new FileLineReader to parse Glass presets
* Trim CRLF from Glass preset name
This commit is contained in:
Kyle Reed
2023-06-15 00:45:13 -07:00
committed by GitHub
parent a5c7eb2fbc
commit 34fefd1cad
11 changed files with 659 additions and 325 deletions

View File

@@ -22,6 +22,8 @@
*/
#include "ui_looking_glass_app.hpp"
#include "file_reader.hpp"
#include "string_format.hpp"
using namespace portapack;
@@ -519,70 +521,42 @@ GlassView::GlassView(
void GlassView::load_Presets() {
File presets_file;
auto result = presets_file.open("LOOKINGGLASS/PRESETS.TXT");
presets_db.clear(); // Start with fresh db
if (result.is_valid()) {
presets_Default(); // There is no txt, store a default range
} else {
std::string line; // There is a txt file
char one_char[1]; // Read it char by char
for (size_t pointer = 0; pointer < presets_file.size(); pointer++) {
presets_file.seek(pointer);
presets_file.read(one_char, 1);
if ((int)one_char[0] > 31) { // ascii space upwards
line += one_char[0]; // Add it to the textline
} else if (one_char[0] == '\n') { // New Line
txtline_process(line); // make sense of this textline
line.clear(); // Ready for next textline
}
auto error = presets_file.open("LOOKINGGLASS/PRESETS.TXT");
presets_db.clear();
if (!error) {
auto reader = FileLineReader(presets_file);
for (const auto& line : reader) {
if (line.length() == 0 || line[0] == '#')
continue;
auto cols = split_string(line, ',');
if (cols.size() != 3)
continue;
// TODO: add some conversion helpers that take string_view.
presets_db.emplace_back(preset_entry{
std::stoi(std::string{cols[0]}),
std::stoi(std::string{cols[1]}),
trimr(std::string{cols[2]})});
}
if (line.length() > 0)
txtline_process(line); // Last line had no newline at end ?
if (!presets_db.size())
presets_Default(); // no antenna on txt, use default
}
// Couldn't load any from the file, load a default instead.
if (presets_db.empty())
presets_Default();
populate_Presets();
}
void GlassView::txtline_process(std::string& line) {
if (line.find("#") != std::string::npos)
return; // Line is just a comment
size_t comma = line.find(","); // Get first comma position
if (comma == std::string::npos)
return; // No comma at all
size_t previous = 0;
preset_entry new_preset;
new_preset.min = std::stoi(line.substr(0, comma));
if (!new_preset.min)
return; // No frequency!
previous = comma + 1;
comma = line.find(",", previous); // Search for next delimiter
if (comma == std::string::npos)
return; // No comma at all
new_preset.max = std::stoi(line.substr(previous, comma - previous));
if (!new_preset.max)
return; // No frequency!
new_preset.label = line.substr(comma + 1);
if (new_preset.label.size() == 0)
return; // No label ?
presets_db.push_back(new_preset); // Add this preset.
}
void GlassView::populate_Presets() {
using option_t = std::pair<std::string, int32_t>;
using options_t = std::vector<option_t>;
options_t entries;
for (preset_entry preset : presets_db) { // go thru all available presets
for (const auto& preset : presets_db)
entries.emplace_back(preset.label, entries.size());
}
range_presets.set_options(entries);
}

View File

@@ -51,10 +51,7 @@ class SIGFRXView : public View {
uint8_t last_channel;
uint8_t detect_counter = 0;
RxRadioState radio_state_{
1750000 /* bandwidth */,
3072000 /* sampling rate */
};
RxRadioState radio_state_{};
const uint16_t sigfrx_marks[18] = {
10, 8, 0,

View File

@@ -115,8 +115,10 @@ bool TextViewer::on_encoder(EncoderEvent delta) {
if (cursor_.dir == ScrollDirection::Horizontal)
updated = apply_scrolling_constraints(0, delta);
else
else {
delta *= 16;
updated = apply_scrolling_constraints(delta, 0);
}
if (updated)
redraw();

View File

@@ -0,0 +1,155 @@
/*
* Copyright (C) 2023 Kyle Reed
*
* 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.
*/
#ifndef __FILE_READER_HPP__
#define __FILE_READER_HPP__
#include "file.hpp"
#include <cstring>
#include <cstdlib>
#include <string>
#include <string_view>
#include <vector>
/* BufferType requires the following members
* Size size()
* Result<Size> read(void* data, Size bytes_to_read)
* Result<Offset> seek(uint32_t offset)
*/
/* Iterates lines in buffer split on '\n'.
* NB: very basic iterator impl, don't try anything fancy with it. */
template <typename BufferType>
class BufferLineReader {
public:
struct iterator {
bool operator!=(const iterator& other) {
return this->pos_ != other.pos_ || this->reader_ != other.reader_;
}
const std::string& operator*() {
if (!cached_) {
bool ok = reader_->read_line(*this);
cached_ = true;
if (!ok) *this = reader_->end();
}
return line_data_;
}
iterator& operator++() {
const auto size = reader_->size();
if (pos_ < size) {
cached_ = false;
pos_ += line_data_.length();
}
if (pos_ >= size)
*this = reader_->end();
return *this;
}
typename BufferType::Size pos_{};
BufferLineReader* reader_{};
bool cached_ = false;
std::string line_data_{};
};
BufferLineReader(BufferType& buffer)
: buffer_{buffer} {}
iterator begin() { return {0, this}; }
iterator end() { return {size(), this}; }
typename BufferType::Size size() const { return buffer_.size(); }
private:
BufferType& buffer_;
bool read_line(iterator& it) {
constexpr size_t buf_size = 0x80;
char buf[buf_size];
uint32_t offset = 0;
it.line_data_.resize(buf_size);
buffer_.seek(it.pos_);
while (true) {
auto read = buffer_.read(buf, buf_size);
if (!read)
return false;
// Find newline.
auto len = 0u;
for (; len < *read; ++len) {
if (buf[len] == '\n') {
++len;
break;
}
}
// Reallocate if needed.
if (offset + len >= it.line_data_.length())
it.line_data_.resize(offset + len);
std::strncpy(&it.line_data_[offset], buf, len);
offset += len;
if (len < buf_size)
break;
}
it.line_data_.resize(offset);
return true;
}
};
using FileLineReader = BufferLineReader<File>;
/* Splits the string on the specified char and returns
* a vector of string_views. NB: the lifetime of the
* string to split must be maintained while the views
* are used or they will dangle. */
std::vector<std::string_view> split_string(std::string_view str, char c) {
std::vector<std::string_view> cols;
size_t start = 0;
while (start < str.length()) {
auto it = str.find(c, start);
if (it == str.npos)
break;
// TODO: allow empty?
cols.emplace_back(&str[start], it - start);
start = it + 1;
}
if (start <= str.length() && !str.empty())
cols.emplace_back(&str[start], str.length() - start);
return cols;
}
#endif

View File

@@ -281,14 +281,16 @@ double get_decimals(double num, int16_t mult, bool round) {
return intnum;
}
static const char* whitespace_str = " \t\r\n";
std::string trim(const std::string& str) {
auto first = str.find_first_not_of(' ');
auto last = str.find_last_not_of(' ');
auto first = str.find_first_not_of(whitespace_str);
auto last = str.find_last_not_of(whitespace_str);
return str.substr(first, last - first);
}
std::string trimr(std::string str) {
size_t last = str.find_last_not_of(' ');
std::string trimr(const std::string& str) {
size_t last = str.find_last_not_of(whitespace_str);
return (last != std::string::npos) ? str.substr(0, last + 1) : ""; // Remove the trailing spaces
}

View File

@@ -68,8 +68,8 @@ std::string to_string_file_size(uint32_t file_size);
std::string unit_auto_scale(double n, const uint32_t base_nano, uint32_t precision);
double get_decimals(double num, int16_t mult, bool round = false); // euquiq added
std::string trim(const std::string& str); // Remove whitespace at ends.
std::string trimr(std::string str); // Remove trailing spaces
std::string trim(const std::string& str); // Remove whitespace at ends.
std::string trimr(const std::string& str); // Remove trailing spaces
std::string truncate(const std::string& str, size_t length);
#endif /*__STRING_FORMAT_H__*/