mirror of
https://github.com/eried/portapack-mayhem.git
synced 2025-01-26 22:37:13 -05:00
Consolidate metadata file parsing (#1173)
* Add metadata file helper and replace old code * Finish updating metadata read/write
This commit is contained in:
parent
fa06df1400
commit
63b0093321
@ -184,6 +184,7 @@ set(CPPSRC
|
|||||||
irq_lcd_frame.cpp
|
irq_lcd_frame.cpp
|
||||||
irq_rtc.cpp
|
irq_rtc.cpp
|
||||||
log_file.cpp
|
log_file.cpp
|
||||||
|
metadata_file.cpp
|
||||||
portapack.cpp
|
portapack.cpp
|
||||||
qrcodegen.cpp
|
qrcodegen.cpp
|
||||||
radio.cpp
|
radio.cpp
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include "ui_fileman.hpp"
|
#include "ui_fileman.hpp"
|
||||||
#include "io_file.hpp"
|
#include "io_file.hpp"
|
||||||
|
#include "metadata_file.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
#include "baseband_api.hpp"
|
#include "baseband_api.hpp"
|
||||||
@ -33,6 +34,7 @@
|
|||||||
#include "portapack_persistent_memory.hpp"
|
#include "portapack_persistent_memory.hpp"
|
||||||
|
|
||||||
using namespace portapack;
|
using namespace portapack;
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
@ -40,51 +42,38 @@ void GpsSimAppView::set_ready() {
|
|||||||
ready_signal = true;
|
ready_signal = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GpsSimAppView::on_file_changed(std::filesystem::path new_file_path) {
|
void GpsSimAppView::on_file_changed(const fs::path& new_file_path) {
|
||||||
File data_file, info_file;
|
file_path = fs::path(u"/") + new_file_path;
|
||||||
char file_data[257];
|
File::Size file_size{};
|
||||||
|
|
||||||
// Get file size
|
{ // Get the size of the data file.
|
||||||
auto data_open_error = data_file.open("/" + new_file_path.string());
|
File data_file;
|
||||||
if (data_open_error.is_valid()) {
|
auto error = data_file.open(file_path);
|
||||||
|
if (error) {
|
||||||
file_error();
|
file_error();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_path = new_file_path;
|
file_size = data_file.size();
|
||||||
|
}
|
||||||
|
|
||||||
// Get original record frequency if available
|
// Get original record frequency if available.
|
||||||
std::filesystem::path info_file_path = file_path;
|
auto metadata_path = get_metadata_path(file_path);
|
||||||
info_file_path.replace_extension(u".TXT");
|
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;
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UI Fixup.
|
||||||
text_sample_rate.set(unit_auto_scale(sample_rate, 3, 1) + "Hz");
|
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);
|
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));
|
text_duration.set(to_string_time_ms(duration));
|
||||||
|
|
||||||
button_play.focus();
|
button_play.focus();
|
||||||
|
@ -71,7 +71,7 @@ class GpsSimAppView : public View {
|
|||||||
const size_t read_size{16384};
|
const size_t read_size{16384};
|
||||||
const size_t buffer_count{3};
|
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 on_tx_progress(const uint32_t progress);
|
||||||
|
|
||||||
void toggle();
|
void toggle();
|
||||||
|
@ -27,11 +27,13 @@
|
|||||||
#include "ui_fileman.hpp"
|
#include "ui_fileman.hpp"
|
||||||
#include "io_file.hpp"
|
#include "io_file.hpp"
|
||||||
#include "baseband_api.hpp"
|
#include "baseband_api.hpp"
|
||||||
|
#include "metadata_file.hpp"
|
||||||
#include "portapack.hpp"
|
#include "portapack.hpp"
|
||||||
#include "portapack_persistent_memory.hpp"
|
#include "portapack_persistent_memory.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
using namespace portapack;
|
using namespace portapack;
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
@ -39,51 +41,41 @@ void ReplayAppView::set_ready() {
|
|||||||
ready_signal = true;
|
ready_signal = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReplayAppView::on_file_changed(std::filesystem::path new_file_path) {
|
void ReplayAppView::on_file_changed(const fs::path& new_file_path) {
|
||||||
File data_file, info_file;
|
file_path = fs::path(u"/") + new_file_path;
|
||||||
char file_data[257];
|
File::Size file_size{};
|
||||||
|
|
||||||
// Get file size
|
{ // Get the size of the data file.
|
||||||
auto data_open_error = data_file.open("/" + new_file_path.string());
|
File data_file;
|
||||||
if (data_open_error.is_valid()) {
|
auto error = data_file.open(file_path);
|
||||||
|
if (error) {
|
||||||
file_error();
|
file_error();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_path = new_file_path;
|
file_size = data_file.size();
|
||||||
|
}
|
||||||
|
|
||||||
// Get original record frequency if available
|
// Get original record frequency if available.
|
||||||
std::filesystem::path info_file_path = file_path;
|
auto metadata_path = get_metadata_path(file_path);
|
||||||
info_file_path.replace_extension(u".TXT");
|
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;
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UI Fixup.
|
||||||
text_sample_rate.set(unit_auto_scale(sample_rate, 3, 0) + "Hz");
|
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);
|
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));
|
text_duration.set(to_string_time_ms(duration));
|
||||||
|
|
||||||
button_play.focus();
|
button_play.focus();
|
||||||
@ -200,7 +192,7 @@ ReplayAppView::ReplayAppView(
|
|||||||
|
|
||||||
button_open.on_select = [this, &nav](Button&) {
|
button_open.on_select = [this, &nav](Button&) {
|
||||||
auto open_view = nav.push<FileLoadView>(".C16");
|
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);
|
on_file_changed(new_file_path);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -67,7 +67,7 @@ class ReplayAppView : public View {
|
|||||||
const size_t read_size{16384};
|
const size_t read_size{16384};
|
||||||
const size_t buffer_count{3};
|
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 on_tx_progress(const uint32_t progress);
|
||||||
|
|
||||||
void toggle();
|
void toggle();
|
||||||
|
@ -40,7 +40,9 @@ using namespace portapack;
|
|||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
/* TODO: wouldn't it be easier if the playlist were just a list of C16 files
|
/* 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 {
|
namespace ui {
|
||||||
|
|
||||||
|
89
firmware/application/metadata_file.cpp
Normal file
89
firmware/application/metadata_file.cpp
Normal 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;
|
||||||
|
}
|
39
firmware/application/metadata_file.hpp
Normal file
39
firmware/application/metadata_file.hpp
Normal 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__
|
@ -28,6 +28,7 @@ using namespace portapack;
|
|||||||
#include "io_wave.hpp"
|
#include "io_wave.hpp"
|
||||||
|
|
||||||
#include "baseband_api.hpp"
|
#include "baseband_api.hpp"
|
||||||
|
#include "metadata_file.hpp"
|
||||||
#include "rtc_time.hpp"
|
#include "rtc_time.hpp"
|
||||||
#include "string_format.hpp"
|
#include "string_format.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
@ -194,7 +195,9 @@ void RecordView::start() {
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case FileType::RawS16: {
|
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()) {
|
if (metadata_file_error.is_valid()) {
|
||||||
handle_error(metadata_file_error.value());
|
handle_error(metadata_file_error.value());
|
||||||
return;
|
return;
|
||||||
@ -246,24 +249,6 @@ void RecordView::stop() {
|
|||||||
update_status_display();
|
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() {
|
void RecordView::on_tick_second() {
|
||||||
update_status_display();
|
update_status_display();
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,6 @@ class RecordView : public View {
|
|||||||
private:
|
private:
|
||||||
void toggle();
|
void toggle();
|
||||||
// void toggle_pitch_rssi();
|
// void toggle_pitch_rssi();
|
||||||
Optional<File::Error> write_metadata_file(const std::filesystem::path& filename);
|
|
||||||
|
|
||||||
void on_tick_second();
|
void on_tick_second();
|
||||||
void update_status_display();
|
void update_status_display();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user