Consolidate metadata file parsing (#1173)

* Add metadata file helper and replace old code
* Finish updating metadata read/write
This commit is contained in:
Kyle Reed 2023-06-20 00:32:37 -07:00 committed by GitHub
parent fa06df1400
commit 63b0093321
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 198 additions and 102 deletions

View File

@ -184,6 +184,7 @@ set(CPPSRC
irq_lcd_frame.cpp
irq_rtc.cpp
log_file.cpp
metadata_file.cpp
portapack.cpp
qrcodegen.cpp
radio.cpp

View File

@ -26,6 +26,7 @@
#include "ui_fileman.hpp"
#include "io_file.hpp"
#include "metadata_file.hpp"
#include "utility.hpp"
#include "baseband_api.hpp"
@ -33,6 +34,7 @@
#include "portapack_persistent_memory.hpp"
using namespace portapack;
namespace fs = std::filesystem;
namespace ui {
@ -40,51 +42,38 @@ void GpsSimAppView::set_ready() {
ready_signal = true;
}
void GpsSimAppView::on_file_changed(std::filesystem::path new_file_path) {
File data_file, info_file;
char file_data[257];
void GpsSimAppView::on_file_changed(const fs::path& new_file_path) {
file_path = fs::path(u"/") + new_file_path;
File::Size file_size{};
// Get file size
auto data_open_error = data_file.open("/" + new_file_path.string());
if (data_open_error.is_valid()) {
file_error();
return;
}
file_path = new_file_path;
// Get original record frequency if available
std::filesystem::path info_file_path = file_path;
info_file_path.replace_extension(u".TXT");
sample_rate = 500000;
auto info_open_error = info_file.open("/" + info_file_path.string());
if (!info_open_error.is_valid()) {
memset(file_data, 0, 257);
auto read_size = info_file.read(file_data, 256);
if (!read_size.is_error()) {
auto pos1 = strstr(file_data, "center_frequency=");
if (pos1) {
pos1 += 17;
field_frequency.set_value(strtoll(pos1, nullptr, 10));
}
auto pos2 = strstr(file_data, "sample_rate=");
if (pos2) {
pos2 += 12;
sample_rate = strtoll(pos2, nullptr, 10);
}
{ // Get the size of the data file.
File data_file;
auto error = data_file.open(file_path);
if (error) {
file_error();
return;
}
file_size = data_file.size();
}
// Get original record frequency if available.
auto metadata_path = get_metadata_path(file_path);
auto metadata = read_metadata_file(metadata_path);
if (metadata) {
field_frequency.set_value(metadata->center_frequency);
sample_rate = metadata->sample_rate;
} else {
sample_rate = 500000;
}
// UI Fixup.
text_sample_rate.set(unit_auto_scale(sample_rate, 3, 1) + "Hz");
auto file_size = data_file.size();
auto duration = ms_duration(file_size, sample_rate, 2);
progressbar.set_max(file_size / 1024);
text_filename.set(file_path.filename().string().substr(0, 12));
text_filename.set(truncate(file_path.filename().string(), 12));
auto duration = ms_duration(file_size, sample_rate, 2);
text_duration.set(to_string_time_ms(duration));
button_play.focus();

View File

@ -71,7 +71,7 @@ class GpsSimAppView : public View {
const size_t read_size{16384};
const size_t buffer_count{3};
void on_file_changed(std::filesystem::path new_file_path);
void on_file_changed(const std::filesystem::path& new_file_path);
void on_tx_progress(const uint32_t progress);
void toggle();

View File

@ -27,11 +27,13 @@
#include "ui_fileman.hpp"
#include "io_file.hpp"
#include "baseband_api.hpp"
#include "metadata_file.hpp"
#include "portapack.hpp"
#include "portapack_persistent_memory.hpp"
#include "utility.hpp"
using namespace portapack;
namespace fs = std::filesystem;
namespace ui {
@ -39,51 +41,41 @@ void ReplayAppView::set_ready() {
ready_signal = true;
}
void ReplayAppView::on_file_changed(std::filesystem::path new_file_path) {
File data_file, info_file;
char file_data[257];
void ReplayAppView::on_file_changed(const fs::path& new_file_path) {
file_path = fs::path(u"/") + new_file_path;
File::Size file_size{};
// Get file size
auto data_open_error = data_file.open("/" + new_file_path.string());
if (data_open_error.is_valid()) {
file_error();
return;
}
file_path = new_file_path;
// Get original record frequency if available
std::filesystem::path info_file_path = file_path;
info_file_path.replace_extension(u".TXT");
sample_rate = 500000;
auto info_open_error = info_file.open("/" + info_file_path.string());
if (!info_open_error.is_valid()) {
memset(file_data, 0, 257);
auto read_size = info_file.read(file_data, 256);
if (!read_size.is_error()) {
auto pos1 = strstr(file_data, "center_frequency=");
if (pos1) {
pos1 += 17;
field_frequency.set_value(strtoll(pos1, nullptr, 10));
}
auto pos2 = strstr(file_data, "sample_rate=");
if (pos2) {
pos2 += 12;
sample_rate = strtoll(pos2, nullptr, 10);
}
{ // Get the size of the data file.
File data_file;
auto error = data_file.open(file_path);
if (error) {
file_error();
return;
}
file_size = data_file.size();
}
// Get original record frequency if available.
auto metadata_path = get_metadata_path(file_path);
auto metadata = read_metadata_file(metadata_path);
if (metadata) {
field_frequency.set_value(metadata->center_frequency);
sample_rate = metadata->sample_rate;
} else {
// TODO: This is interesting because it implies that the
// The capture will just be replayed at the freq set on the
// FrequencyField. Is that an intentional behavior?
sample_rate = 500000;
}
// UI Fixup.
text_sample_rate.set(unit_auto_scale(sample_rate, 3, 0) + "Hz");
auto file_size = data_file.size();
auto duration = ms_duration(file_size, sample_rate, 4);
progressbar.set_max(file_size);
text_filename.set(file_path.filename().string().substr(0, 12));
text_filename.set(truncate(file_path.filename().string(), 12));
auto duration = ms_duration(file_size, sample_rate, 4);
text_duration.set(to_string_time_ms(duration));
button_play.focus();
@ -200,7 +192,7 @@ ReplayAppView::ReplayAppView(
button_open.on_select = [this, &nav](Button&) {
auto open_view = nav.push<FileLoadView>(".C16");
open_view->on_changed = [this](std::filesystem::path new_file_path) {
open_view->on_changed = [this](fs::path new_file_path) {
on_file_changed(new_file_path);
};
};

View File

@ -67,7 +67,7 @@ class ReplayAppView : public View {
const size_t read_size{16384};
const size_t buffer_count{3};
void on_file_changed(std::filesystem::path new_file_path);
void on_file_changed(const std::filesystem::path& new_file_path);
void on_tx_progress(const uint32_t progress);
void toggle();

View File

@ -40,7 +40,9 @@ using namespace portapack;
namespace fs = std::filesystem;
/* TODO: wouldn't it be easier if the playlist were just a list of C16 files
* (and maybe delays) and then read the data file next to the C16 file? */
* (and maybe delays) and then read the metadata file next to the C16 file?
* TODO: use metadata_file.hpp to read the metadata.
* TODO: change PPL format to only allow paths, and !<number> for delay. */
namespace ui {

View File

@ -0,0 +1,89 @@
/*
* 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.
*/
#include "metadata_file.hpp"
#include "convert.hpp"
#include "file_reader.hpp"
#include "string_format.hpp"
#include <string_view>
namespace fs = std::filesystem;
using namespace std::literals;
const std::string_view center_freq_name = "center_frequency"sv;
const std::string_view sample_rate_name = "sample_rate"sv;
fs::path get_metadata_path(const fs::path& capture_path) {
auto temp = capture_path;
return temp.replace_extension(u".TXT");
}
Optional<File::Error> write_metadata_file(const fs::path& path, capture_metadata metadata) {
File f;
auto error = f.create(path);
if (error)
return error;
error = f.write_line(std::string{center_freq_name} + "=" +
to_string_dec_uint(metadata.center_frequency));
if (error)
return error;
// TODO: Why does this divide by 8? Leaving as is for back-compat, but it's odd.
error = f.write_line(std::string{sample_rate_name} + "=" +
to_string_dec_uint(metadata.sample_rate / 8));
if (error)
return error;
return {};
}
Optional<capture_metadata> read_metadata_file(const fs::path& path) {
File f;
auto error = f.open(path);
if (error)
return {};
capture_metadata metadata{};
auto reader = FileLineReader(f);
for (const auto& line : reader) {
auto cols = split_string(line, '=');
if (cols.size() != 2)
continue; // Bad line.
if (cols[0] == center_freq_name)
parse_int(cols[1], metadata.center_frequency);
else if (cols[0] == sample_rate_name)
parse_int(cols[1], metadata.sample_rate);
else
continue;
}
if (metadata.center_frequency == 0 || metadata.sample_rate == 0)
return {}; // Parse failed.
return metadata;
}

View File

@ -0,0 +1,39 @@
/*
* 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 __METADATA_FILE_HPP__
#define __METADATA_FILE_HPP__
#include "file.hpp"
#include "optional.hpp"
#include "rf_path.hpp"
struct capture_metadata {
rf::Frequency center_frequency;
uint32_t sample_rate;
};
std::filesystem::path get_metadata_path(const std::filesystem::path& capture_path);
Optional<File::Error> write_metadata_file(const std::filesystem::path& path, capture_metadata metadata);
Optional<capture_metadata> read_metadata_file(const std::filesystem::path& path);
#endif // __METADATA_FILE_HPP__

View File

@ -28,6 +28,7 @@ using namespace portapack;
#include "io_wave.hpp"
#include "baseband_api.hpp"
#include "metadata_file.hpp"
#include "rtc_time.hpp"
#include "string_format.hpp"
#include "utility.hpp"
@ -194,7 +195,9 @@ void RecordView::start() {
} break;
case FileType::RawS16: {
const auto metadata_file_error = write_metadata_file(base_path.replace_extension(u".TXT"));
const auto metadata_file_error =
write_metadata_file(get_metadata_path(base_path),
{receiver_model.target_frequency(), sampling_rate});
if (metadata_file_error.is_valid()) {
handle_error(metadata_file_error.value());
return;
@ -246,24 +249,6 @@ void RecordView::stop() {
update_status_display();
}
Optional<File::Error> RecordView::write_metadata_file(const std::filesystem::path& filename) {
File file;
const auto create_error = file.create(filename);
if (create_error.is_valid()) {
return create_error;
} else {
const auto error_line1 = file.write_line("sample_rate=" + to_string_dec_uint(sampling_rate / 8));
if (error_line1.is_valid()) {
return error_line1;
}
const auto error_line2 = file.write_line("center_frequency=" + to_string_dec_uint(receiver_model.target_frequency()));
if (error_line2.is_valid()) {
return error_line2;
}
return {};
}
}
void RecordView::on_tick_second() {
update_status_display();
}

View File

@ -68,7 +68,6 @@ class RecordView : public View {
private:
void toggle();
// void toggle_pitch_rssi();
Optional<File::Error> write_metadata_file(const std::filesystem::path& filename);
void on_tick_second();
void update_status_display();