Improve File error handling. Massive effects...

API is somewhat stolen from Rust std::fs::File. Static factories didn't work out so well, though. Move semantics made my head explode.
TODO: Still a lot of places where errors aren't handled, but it's an improvement...
This commit is contained in:
Jared Boone 2016-05-16 14:01:44 -07:00
parent d905c446bf
commit 682a1706a3
18 changed files with 328 additions and 235 deletions

View File

@ -126,25 +126,17 @@ static std::string true_heading(const TrueHeading value) {
} /* namespace format */ } /* namespace format */
} /* namespace ais */ } /* namespace ais */
AISLogger::AISLogger(
const std::string& file_path
) : log_file { file_path }
{
}
void AISLogger::on_packet(const ais::Packet& packet) { void AISLogger::on_packet(const ais::Packet& packet) {
// TODO: Unstuff here, not in baseband! // TODO: Unstuff here, not in baseband!
if( log_file.is_open() ) { std::string entry;
std::string entry; entry.reserve((packet.length() + 3) / 4);
entry.reserve((packet.length() + 3) / 4);
for(size_t i=0; i<packet.length(); i+=4) { for(size_t i=0; i<packet.length(); i+=4) {
const auto nibble = packet.read(i, 4); const auto nibble = packet.read(i, 4);
entry += (nibble >= 10) ? ('W' + nibble) : ('0' + nibble); entry += (nibble >= 10) ? ('W' + nibble) : ('0' + nibble);
}
log_file.write_entry(packet.received_at(), entry);
} }
log_file.write_entry(packet.received_at(), entry);
} }
void AISRecentEntry::update(const ais::Packet& packet) { void AISRecentEntry::update(const ais::Packet& packet) {
@ -332,7 +324,10 @@ AISAppView::AISAppView(NavigationView&) {
this->on_show_list(); this->on_show_list();
}; };
logger = std::make_unique<AISLogger>("ais.txt"); logger = std::make_unique<AISLogger>();
if( logger ) {
logger->append("ais.txt");
}
} }
AISAppView::~AISAppView() { AISAppView::~AISAppView() {

View File

@ -92,7 +92,9 @@ using AISRecentEntries = RecentEntries<ais::Packet, AISRecentEntry>;
class AISLogger { class AISLogger {
public: public:
AISLogger(const std::string& file_path); Optional<File::Error> append(const std::string& filename) {
return log_file.append(filename);
}
void on_packet(const ais::Packet& packet); void on_packet(const ais::Packet& packet);

View File

@ -98,13 +98,8 @@ CaptureThread::~CaptureThread() {
} }
} }
Optional<std::string> CaptureThread::error() const { const Optional<File::Error>& CaptureThread::error() const {
const auto error = writer->error(); return last_error;
if( error.is_valid() ) {
return { error.value().what() };
} else {
return { };
}
} }
void CaptureThread::check_fifo_isr() { void CaptureThread::check_fifo_isr() {
@ -118,14 +113,15 @@ void CaptureThread::check_fifo_isr() {
} }
} }
msg_t CaptureThread::run() { Optional<File::Error> CaptureThread::run() {
StreamOutput stream { &config }; StreamOutput stream { &config };
while( !chThdShouldTerminate() ) { while( !chThdShouldTerminate() ) {
if( stream.available() ) { if( stream.available() ) {
auto buffer = stream.get_buffer(); auto buffer = stream.get_buffer();
if( !writer->write(buffer->data(), buffer->size()) ) { auto write_result = writer->write(buffer->data(), buffer->size());
return false; if( write_result.is_error() ) {
return write_result.error();
} }
stream.release_buffer(buffer); stream.release_buffer(buffer);
} else { } else {
@ -133,5 +129,5 @@ msg_t CaptureThread::run() {
} }
} }
return true; return { };
} }

View File

@ -35,8 +35,7 @@
class Writer { class Writer {
public: public:
virtual bool write(const void* const buffer, const size_t bytes) = 0; virtual File::Result<size_t> write(const void* const buffer, const size_t bytes) = 0;
virtual Optional<std::filesystem::filesystem_error> error() const = 0;
virtual ~Writer() = default; virtual ~Writer() = default;
}; };
@ -53,21 +52,23 @@ public:
return config; return config;
} }
Optional<std::string> error() const; const Optional<File::Error>& error() const;
static void check_fifo_isr(); static void check_fifo_isr();
private: private:
CaptureConfig config; CaptureConfig config;
std::unique_ptr<Writer> writer; std::unique_ptr<Writer> writer;
Optional<File::Error> last_error;
static Thread* thread; static Thread* thread;
static msg_t static_fn(void* arg) { static msg_t static_fn(void* arg) {
auto obj = static_cast<CaptureThread*>(arg); auto obj = static_cast<CaptureThread*>(arg);
return obj->run(); obj->last_error = obj->run();
return 0;
} }
msg_t run(); Optional<File::Error> run();
}; };
#endif/*__CAPTURE_THREAD_H__*/ #endif/*__CAPTURE_THREAD_H__*/

View File

@ -57,17 +57,9 @@ std::string commodity_type(CommodityType value) {
} /* namespace ert */ } /* namespace ert */
ERTLogger::ERTLogger(
const std::string& file_path
) : log_file { file_path }
{
}
void ERTLogger::on_packet(const ert::Packet& packet) { void ERTLogger::on_packet(const ert::Packet& packet) {
if( log_file.is_open() ) { const auto formatted = packet.symbols_formatted();
const auto formatted = packet.symbols_formatted(); log_file.write_entry(packet.received_at(), formatted.data + "/" + formatted.errors);
log_file.write_entry(packet.received_at(), formatted.data + "/" + formatted.errors);
}
} }
const ERTRecentEntry::Key ERTRecentEntry::invalid_key { }; const ERTRecentEntry::Key ERTRecentEntry::invalid_key { };
@ -148,7 +140,10 @@ ERTAppView::ERTAppView(NavigationView&) {
.decimation_factor = 1, .decimation_factor = 1,
}); });
logger = std::make_unique<ERTLogger>("ert.txt"); logger = std::make_unique<ERTLogger>();
if( logger ) {
logger->append("ert.txt");
}
} }
ERTAppView::~ERTAppView() { ERTAppView::~ERTAppView() {

View File

@ -87,7 +87,9 @@ struct ERTRecentEntry {
class ERTLogger { class ERTLogger {
public: public:
ERTLogger(const std::string& file_path); Optional<File::Error> append(const std::string& filename) {
return log_file.append(filename);
}
void on_packet(const ert::Packet& packet); void on_packet(const ert::Packet& packet);

View File

@ -28,99 +28,93 @@ static_assert(sizeof(FIL::err) == 1, "FatFs FIL::err size not expected.");
#define FR_DISK_FULL (0x100) #define FR_DISK_FULL (0x100)
#define FR_EOF (0x101) #define FR_EOF (0x101)
#define FR_BAD_SEEK (0x102) #define FR_BAD_SEEK (0x102)
#define FR_UNEXPECTED (0x103)
File::File( Optional<File::Error> File::open_fatfs(const std::string& filename, BYTE mode) {
const std::string& filename, auto result = f_open(&f, filename.c_str(), mode);
openmode mode if( result == FR_OK ) {
) : err { FR_OK } if( mode & FA_OPEN_ALWAYS ) {
{ const auto result = f_lseek(&f, f_size(&f));
BYTE fatfs_mode = 0; if( result != FR_OK ) {
if( mode & openmode::in ) {
fatfs_mode |= FA_READ;
}
if( mode & openmode::out ) {
fatfs_mode |= FA_WRITE;
}
if( mode & openmode::trunc ) {
fatfs_mode |= FA_CREATE_ALWAYS;
}
if( mode & openmode::ate ) {
fatfs_mode |= FA_OPEN_ALWAYS;
}
err = f_open(&f, filename.c_str(), fatfs_mode);
if( err == FR_OK ) {
if( mode & openmode::ate ) {
err = f_lseek(&f, f_size(&f));
if( err != FR_OK ) {
f_close(&f); f_close(&f);
} }
} }
} }
if( result == FR_OK ) {
return { };
} else {
return { result };
}
}
Optional<File::Error> File::open(const std::string& filename) {
return open_fatfs(filename, FA_READ);
}
Optional<File::Error> File::append(const std::string& filename) {
return open_fatfs(filename, FA_WRITE | FA_OPEN_ALWAYS);
}
Optional<File::Error> File::create(const std::string& filename) {
return open_fatfs(filename, FA_WRITE | FA_CREATE_ALWAYS);
} }
File::~File() { File::~File() {
f_close(&f); f_close(&f);
} }
bool File::read(void* const data, const size_t bytes_to_read) { File::Result<size_t> File::read(void* const data, const size_t bytes_to_read) {
if( err != FR_OK ) {
return false;
}
UINT bytes_read = 0; UINT bytes_read = 0;
err = f_read(&f, data, bytes_to_read, &bytes_read); const auto result = f_read(&f, data, bytes_to_read, &bytes_read);
if( bytes_read != bytes_to_read ) { if( result == FR_OK ) {
err = FR_EOF; return { static_cast<size_t>(bytes_read) };
} else {
return { static_cast<Error>(result) };
} }
return (err == FR_OK);
} }
bool File::write(const void* const data, const size_t bytes_to_write) { File::Result<size_t> File::write(const void* const data, const size_t bytes_to_write) {
if( err != FR_OK ) {
return false;
}
UINT bytes_written = 0; UINT bytes_written = 0;
err = f_write(&f, data, bytes_to_write, &bytes_written); const auto result = f_write(&f, data, bytes_to_write, &bytes_written);
if( bytes_written != bytes_to_write ) { if( result == FR_OK ) {
err = FR_DISK_FULL; return { static_cast<size_t>(bytes_written) };
} else {
return { static_cast<Error>(result) };
} }
return (err == FR_OK);
} }
uint64_t File::seek(const uint64_t new_position) { File::Result<uint64_t> File::seek(const uint64_t new_position) {
if( err != FR_OK ) { /* NOTE: Returns *old* position, not new position */
return false;
}
const auto old_position = f_tell(&f); const auto old_position = f_tell(&f);
err = f_lseek(&f, new_position); const auto result = f_lseek(&f, new_position);
if( err != FR_OK ) { if( result != FR_OK ) {
f_close(&f); return { static_cast<Error>(result) };
} }
if( f_tell(&f) != new_position ) { if( f_tell(&f) != new_position ) {
err = FR_BAD_SEEK; return { static_cast<Error>(FR_BAD_SEEK) };
f_close(&f);
} }
return old_position; return { static_cast<uint64_t>(old_position) };
} }
bool File::puts(const std::string& string) { File::Result<size_t> File::puts(const std::string& string) {
const auto result = f_puts(string.c_str(), &f); const auto result = f_puts(string.c_str(), &f);
if( result != (int)string.size() ) { if( result >= 0 ) {
err = FR_DISK_FULL; return { static_cast<size_t>(result) };
} else if( result == EOF ) {
return { static_cast<Error>(f_error(&f)) };
} else {
return { static_cast<Error>(FR_UNEXPECTED) };
} }
return (result >= 0);
} }
bool File::sync() { Optional<File::Error> File::sync() {
if( err != FR_OK ) { const auto result = f_sync(&f);
return false; if( result == FR_OK ) {
return { };
} else {
return { result };
} }
err = f_sync(&f);
return (err == FR_OK);
} }
static std::string find_last_file_matching_pattern(const std::string& pattern) { static std::string find_last_file_matching_pattern(const std::string& pattern) {
@ -181,7 +175,7 @@ namespace filesystem {
std::string filesystem_error::what() const { std::string filesystem_error::what() const {
switch(err) { switch(err) {
case FR_OK: return ""; case FR_OK: return "ok";
case FR_DISK_ERR: return "disk error"; case FR_DISK_ERR: return "disk error";
case FR_INT_ERR: return "insanity detected"; case FR_INT_ERR: return "insanity detected";
case FR_NOT_READY: return "not ready"; case FR_NOT_READY: return "not ready";
@ -204,6 +198,7 @@ std::string filesystem_error::what() const {
case FR_EOF: return "end of file"; case FR_EOF: return "end of file";
case FR_DISK_FULL: return "disk full"; case FR_DISK_FULL: return "disk full";
case FR_BAD_SEEK: return "bad seek"; case FR_BAD_SEEK: return "bad seek";
case FR_UNEXPECTED: return "unexpected";
default: return "unknown"; default: return "unknown";
} }
} }

View File

@ -24,6 +24,8 @@
#include "ff.h" #include "ff.h"
#include "optional.hpp"
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <string> #include <string>
@ -37,9 +39,27 @@ namespace std {
namespace filesystem { namespace filesystem {
struct filesystem_error { struct filesystem_error {
const uint32_t err; constexpr filesystem_error(
) : err { FR_OK }
{
}
constexpr filesystem_error(
FRESULT fatfs_error
) : err { fatfs_error }
{
}
constexpr filesystem_error(
unsigned int other_error
) : err { other_error }
{
}
std::string what() const; std::string what() const;
private:
uint32_t err;
}; };
using path = std::string; using path = std::string;
@ -109,51 +129,89 @@ space_info space(const path& p);
class File { class File {
public: public:
enum openmode { using Error = std::filesystem::filesystem_error;
app = 0x100,
binary = 0x200, template<typename T>
in = FA_READ, struct Result {
out = FA_WRITE, enum class Type {
trunc = FA_CREATE_ALWAYS, Success,
ate = FA_OPEN_ALWAYS, Error,
} type;
union {
T value_;
Error error_;
};
bool is_ok() const {
return type == Type::Success;
}
bool is_error() const {
return type == Type::Error;
}
const T& value() {
return value_;
}
Error error() const {
return error_;
}
Result() = delete;
constexpr Result(
T value
) : type { Type::Success },
value_ { value }
{
}
constexpr Result(
Error error
) : type { Type::Error },
error_ { error }
{
}
~Result() {
if( type == Type::Success ) {
value_.~T();
}
}
}; };
File(const std::string& filename, openmode mode); File() { };
~File(); ~File();
bool is_open() const { /* Prevent copies */
return err == FR_OK; File(const File&) = delete;
} File& operator=(const File&) = delete;
bool bad() const { // TODO: Return Result<>.
return err != FR_OK; Optional<Error> open(const std::string& filename);
} Optional<Error> append(const std::string& filename);
Optional<Error> create(const std::string& filename);
std::filesystem::filesystem_error error() const { Result<size_t> read(void* const data, const size_t bytes_to_read);
return { err }; Result<size_t> write(const void* const data, const size_t bytes_to_write);
}
bool read(void* const data, const size_t bytes_to_read); Result<uint64_t> seek(const uint64_t new_position);
bool write(const void* const data, const size_t bytes_to_write);
uint64_t seek(const uint64_t new_position);
template<size_t N> template<size_t N>
bool write(const std::array<uint8_t, N>& data) { Result<size_t> write(const std::array<uint8_t, N>& data) {
return write(data.data(), N); return write(data.data(), N);
} }
bool puts(const std::string& string); Result<size_t> puts(const std::string& string);
bool sync(); // TODO: Return Result<>.
Optional<Error> sync();
private: private:
FIL f; FIL f;
uint32_t err;
Optional<Error> open_fatfs(const std::string& filename, BYTE mode);
}; };
inline constexpr File::openmode operator|(File::openmode a, File::openmode b) {
return File::openmode(static_cast<int>(a) | static_cast<int>(b));
}
#endif/*__FILE_H__*/ #endif/*__FILE_H__*/

View File

@ -23,21 +23,15 @@
#include "string_format.hpp" #include "string_format.hpp"
LogFile::LogFile( File::Result<size_t> LogFile::write_entry(const rtc::RTC& datetime, const std::string& entry) {
const std::string& file_path
) : file { file_path, File::openmode::out | File::openmode::ate }
{
}
bool LogFile::is_open() const {
return file.is_open();
}
bool LogFile::write_entry(const rtc::RTC& datetime, const std::string& entry) {
std::string timestamp = to_string_timestamp(datetime); std::string timestamp = to_string_timestamp(datetime);
return write(timestamp + " " + entry + "\r\n"); return write(timestamp + " " + entry + "\r\n");
} }
bool LogFile::write(const std::string& message) { File::Result<size_t> LogFile::write(const std::string& message) {
return file.puts(message) && file.sync(); auto puts_result = file.puts(message);
if( puts_result.is_ok() ) {
file.sync();
}
return puts_result;
} }

View File

@ -31,16 +31,16 @@ using namespace lpc43xx;
class LogFile { class LogFile {
public: public:
LogFile(const std::string& file_path); Optional<File::Error> append(const std::string& filename) {
return file.append(filename);
}
bool is_open() const; File::Result<size_t> write_entry(const rtc::RTC& datetime, const std::string& entry);
bool write_entry(const rtc::RTC& datetime, const std::string& entry);
private: private:
File file; File file;
bool write(const std::string& message); File::Result<size_t> write(const std::string& message);
}; };
#endif/*__LOG_FILE_H__*/ #endif/*__LOG_FILE_H__*/

View File

@ -51,22 +51,14 @@ std::string temperature(Temperature temperature) {
} /* namespace tpms */ } /* namespace tpms */
TPMSLogger::TPMSLogger(
const std::string& file_path
) : log_file { file_path }
{
}
void TPMSLogger::on_packet(const tpms::Packet& packet, const uint32_t target_frequency) { void TPMSLogger::on_packet(const tpms::Packet& packet, const uint32_t target_frequency) {
const auto hex_formatted = packet.symbols_formatted(); const auto hex_formatted = packet.symbols_formatted();
if( log_file.is_open() ) { // TODO: function doesn't take uint64_t, so when >= 1<<32, weirdness will ensue!
// TODO: function doesn't take uint64_t, so when >= 1<<32, weirdness will ensue! const auto tuning_frequency_str = to_string_dec_uint(target_frequency, 10);
const auto tuning_frequency_str = to_string_dec_uint(target_frequency, 10);
std::string entry = tuning_frequency_str + " FSK 38.4 19.2 " + hex_formatted.data + "/" + hex_formatted.errors; std::string entry = tuning_frequency_str + " FSK 38.4 19.2 " + hex_formatted.data + "/" + hex_formatted.errors;
log_file.write_entry(packet.received_at(), entry); log_file.write_entry(packet.received_at(), entry);
}
} }
const TPMSRecentEntry::Key TPMSRecentEntry::invalid_key = { tpms::Reading::Type::None, 0 }; const TPMSRecentEntry::Key TPMSRecentEntry::invalid_key = { tpms::Reading::Type::None, 0 };
@ -165,7 +157,10 @@ TPMSAppView::TPMSAppView(NavigationView&) {
.decimation_factor = 1, .decimation_factor = 1,
}); });
logger = std::make_unique<TPMSLogger>("tpms.txt"); logger = std::make_unique<TPMSLogger>();
if( logger ) {
logger->append("tpms.txt");
}
} }
TPMSAppView::~TPMSAppView() { TPMSAppView::~TPMSAppView() {

View File

@ -72,7 +72,9 @@ using TPMSRecentEntries = RecentEntries<tpms::Reading, TPMSRecentEntry>;
class TPMSLogger { class TPMSLogger {
public: public:
TPMSLogger(const std::string& file_path); Optional<File::Error> append(const std::string& filename) {
return log_file.append(filename);
}
void on_packet(const tpms::Packet& packet, const uint32_t target_frequency); void on_packet(const tpms::Packet& packet, const uint32_t target_frequency);

View File

@ -86,7 +86,11 @@ void SystemStatusView::on_camera() {
return; return;
} }
PNGWriter png { filename_stem + ".PNG" }; PNGWriter png;
auto create_error = png.create(filename_stem + ".PNG");
if( create_error.is_valid() ) {
return;
}
for(int i=0; i<320; i++) { for(int i=0; i<320; i++) {
std::array<ColorRGB888, 240> row; std::array<ColorRGB888, 240> row;

View File

@ -34,26 +34,23 @@ using namespace portapack;
class FileWriter : public Writer { class FileWriter : public Writer {
public: public:
FileWriter( FileWriter() = default;
const std::string& filename
) : file { filename, File::openmode::out | File::openmode::binary | File::openmode::trunc } FileWriter(const FileWriter&) = delete;
{ FileWriter& operator=(const FileWriter&) = delete;
FileWriter(FileWriter&& file) = delete;
FileWriter& operator=(FileWriter&&) = delete;
Optional<File::Error> create(const std::string& filename) {
return file.create(filename);
} }
Optional<std::filesystem::filesystem_error> error() const override { File::Result<size_t> write(const void* const buffer, const size_t bytes) override {
if( file.bad() ) { auto write_result = file.write(buffer, bytes) ;
return { file.error() }; if( write_result.is_ok() ) {
} else { bytes_written += write_result.value();
return { };
} }
} return write_result;
bool write(const void* const buffer, const size_t bytes) override {
const auto success = file.write(buffer, bytes) ;
if( success ) {
bytes_written += bytes;
}
return success;
} }
protected: protected:
@ -66,18 +63,33 @@ using RawFileWriter = FileWriter;
class WAVFileWriter : public FileWriter { class WAVFileWriter : public FileWriter {
public: public:
WAVFileWriter( WAVFileWriter(
const std::string& filename,
size_t sampling_rate size_t sampling_rate
) : RawFileWriter { filename }, ) : header { sampling_rate }
header { sampling_rate }
{ {
update_header();
} }
WAVFileWriter(const WAVFileWriter&) = delete;
WAVFileWriter& operator=(const WAVFileWriter&) = delete;
WAVFileWriter(WAVFileWriter&&) = delete;
WAVFileWriter& operator=(WAVFileWriter&&) = delete;
~WAVFileWriter() { ~WAVFileWriter() {
update_header(); update_header();
} }
Optional<File::Error> create(
const std::string& filename
) {
const auto create_error = FileWriter::create(filename);
if( create_error.is_valid() ) {
return create_error;
} else {
update_header();
return { };
}
}
private: private:
struct fmt_pcm_t { struct fmt_pcm_t {
constexpr fmt_pcm_t( constexpr fmt_pcm_t(
@ -132,7 +144,11 @@ private:
void update_header() { void update_header() {
header.set_data_size(bytes_written); header.set_data_size(bytes_written);
const auto old_position = file.seek(0); auto seek_result = file.seek(0);
if( seek_result.is_error() ) {
return;
}
const auto old_position = seek_result.value();
file.write(&header, sizeof(header)); file.write(&header, sizeof(header));
file.seek(old_position); file.seek(old_position);
} }
@ -206,17 +222,39 @@ void RecordView::start() {
std::unique_ptr<Writer> writer; std::unique_ptr<Writer> writer;
switch(file_type) { switch(file_type) {
case FileType::WAV: case FileType::WAV:
writer = std::make_unique<WAVFileWriter>( {
filename_stem + ".WAV", auto p = std::make_unique<WAVFileWriter>(
sampling_rate sampling_rate
); );
auto create_error = p->create(
filename_stem + ".WAV"
);
if( create_error.is_valid() ) {
report_error(create_error.value().what());
} else {
writer = std::move(p);
}
}
break; break;
case FileType::RawS16: case FileType::RawS16:
write_metadata_file(filename_stem + ".TXT"); {
writer = std::make_unique<RawFileWriter>( const auto metadata_file_error = write_metadata_file(filename_stem + ".TXT");
filename_stem + ".C16" if( metadata_file_error.is_valid() ) {
); report_error(metadata_file_error.value().what());
return;
}
auto p = std::make_unique<RawFileWriter>();
auto create_error = p->create(
filename_stem + ".C16"
);
if( create_error.is_valid() ) {
report_error(create_error.value().what());
} else {
writer = std::move(p);
}
}
break; break;
default: default:
@ -224,19 +262,12 @@ void RecordView::start() {
}; };
if( writer ) { if( writer ) {
const auto error = writer->error(); text_record_filename.set(filename_stem);
if( error.is_valid() ) { button_record.set_bitmap(&bitmap_stop);
report_error(error.value().what()); capture_thread = std::make_unique<CaptureThread>(
} else { std::move(writer),
text_record_filename.set(filename_stem); write_size, buffer_count
button_record.set_bitmap(&bitmap_stop); );
capture_thread = std::make_unique<CaptureThread>(
std::move(writer),
write_size, buffer_count
);
}
} else {
report_error("file type");
} }
} }
@ -247,10 +278,22 @@ void RecordView::stop() {
} }
} }
void RecordView::write_metadata_file(const std::string& filename) { Optional<File::Error> RecordView::write_metadata_file(const std::string& filename) {
File file { filename, File::openmode::out | File::openmode::trunc }; File file;
file.puts("sample_rate=" + to_string_dec_uint(sampling_rate) + "\n"); const auto create_error = file.create(filename);
file.puts("center_frequency=" + to_string_dec_uint(receiver_model.tuning_frequency()) + "\n"); if( create_error.is_valid() ) {
return create_error;
} else {
const auto puts_result1 = file.puts("sample_rate=" + to_string_dec_uint(sampling_rate) + "\n");
if( puts_result1.is_error() ) {
return { puts_result1.error() };
}
const auto puts_result2 = file.puts("center_frequency=" + to_string_dec_uint(receiver_model.tuning_frequency()) + "\n");
if( puts_result2.is_error() ) {
return { puts_result2.error() };
}
return { };
}
} }
void RecordView::on_tick_second() { void RecordView::on_tick_second() {
@ -258,7 +301,7 @@ void RecordView::on_tick_second() {
const auto error = capture_thread->error(); const auto error = capture_thread->error();
if( error.is_valid() ) { if( error.is_valid() ) {
stop(); stop();
report_error(error.value()); report_error(error.value().what());
} }
const auto dropped_percent = std::min(99U, capture_thread->state().dropped_percent()); const auto dropped_percent = std::min(99U, capture_thread->state().dropped_percent());
const auto s = to_string_dec_uint(dropped_percent, 2, ' ') + "\%"; const auto s = to_string_dec_uint(dropped_percent, 2, ' ') + "\%";

View File

@ -69,7 +69,7 @@ public:
private: private:
void toggle(); void toggle();
void write_metadata_file(const std::string& filename); Optional<File::Error> write_metadata_file(const std::string& filename);
void on_tick_second(); void on_tick_second();

View File

@ -134,22 +134,24 @@ private:
return Result::FailHeap; return Result::FailHeap;
} }
File file { filename, File::openmode::out | File::openmode::binary | File::openmode::trunc }; File file;
if( !file.is_open() ) { auto file_create_error = file.create(filename);
if( file_create_error.is_valid() ) {
return Result::FailFileOpenWrite; return Result::FailFileOpenWrite;
} }
lfsr_word_t v = 1; lfsr_word_t v = 1;
const halrtcnt_t test_start = halGetCounterValue(); const halrtcnt_t test_start = halGetCounterValue();
while( !chThdShouldTerminate() && file.is_open() && (_stats.write_bytes < bytes_to_write) ) { while( !chThdShouldTerminate() && (_stats.write_bytes < bytes_to_write) ) {
lfsr_fill(v, lfsr_fill(v,
reinterpret_cast<lfsr_word_t*>(buffer->data()), reinterpret_cast<lfsr_word_t*>(buffer->data()),
sizeof(*buffer.get()) / sizeof(lfsr_word_t) sizeof(*buffer.get()) / sizeof(lfsr_word_t)
); );
const halrtcnt_t write_start = halGetCounterValue(); const halrtcnt_t write_start = halGetCounterValue();
if( !file.write(buffer->data(), buffer->size()) ) { const auto result_write = file.write(buffer->data(), buffer->size());
if( result_write.is_error() ) {
break; break;
} }
const halrtcnt_t write_end = halGetCounterValue(); const halrtcnt_t write_end = halGetCounterValue();
@ -179,17 +181,19 @@ private:
return Result::FailHeap; return Result::FailHeap;
} }
File file { filename, File::openmode::in | File::openmode::binary }; File file;
if( !file.is_open() ) { auto file_open_error = file.open(filename);
if( file_open_error.is_valid() ) {
return Result::FailFileOpenRead; return Result::FailFileOpenRead;
} }
lfsr_word_t v = 1; lfsr_word_t v = 1;
const halrtcnt_t test_start = halGetCounterValue(); const halrtcnt_t test_start = halGetCounterValue();
while( !chThdShouldTerminate() && file.is_open() && (_stats.read_bytes < bytes_to_read) ) { while( !chThdShouldTerminate() && (_stats.read_bytes < bytes_to_read) ) {
const halrtcnt_t read_start = halGetCounterValue(); const halrtcnt_t read_start = halGetCounterValue();
if( !file.read(buffer->data(), buffer->size()) ) { const auto result_read = file.read(buffer->data(), buffer->size());
if( result_read.is_error() ) {
break; break;
} }
const halrtcnt_t read_end = halGetCounterValue(); const halrtcnt_t read_end = halGetCounterValue();

View File

@ -49,10 +49,14 @@ static constexpr std::array<uint8_t, 12> png_iend { {
0xae, 0x42, 0x60, 0x82, // CRC 0xae, 0x42, 0x60, 0x82, // CRC
} }; } };
PNGWriter::PNGWriter( Optional<File::Error> PNGWriter::create(
const std::string& filename const std::string& filename
) : file { filename, File::openmode::out | File::openmode::binary | File::openmode::trunc } ) {
{ const auto create_error = file.create(filename);
if( create_error.is_valid() ) {
return create_error;
}
file.write(png_file_header); file.write(png_file_header);
file.write(png_ihdr_screen_capture); file.write(png_ihdr_screen_capture);
@ -63,6 +67,8 @@ PNGWriter::PNGWriter(
constexpr std::array<uint8_t, 2> zlib_header { 0x78, 0x01 }; // Zlib CM, CINFO, FLG. constexpr std::array<uint8_t, 2> zlib_header { 0x78, 0x01 }; // Zlib CM, CINFO, FLG.
write_chunk_content(zlib_header); write_chunk_content(zlib_header);
return { };
} }
PNGWriter::~PNGWriter() { PNGWriter::~PNGWriter() {

View File

@ -33,9 +33,10 @@
class PNGWriter { class PNGWriter {
public: public:
explicit PNGWriter(const std::string& filename);
~PNGWriter(); ~PNGWriter();
Optional<File::Error> create(const std::string& filename);
void write_scanline(const std::array<ui::ColorRGB888, 240>& scanline); void write_scanline(const std::array<ui::ColorRGB888, 240>& scanline);
private: private: