From 682a1706a3425bea9f441a702479ed9ba34b7eaf Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Mon, 16 May 2016 14:01:44 -0700 Subject: [PATCH] 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... --- firmware/application/ais_app.cpp | 27 ++--- firmware/application/ais_app.hpp | 6 +- firmware/application/capture_thread.cpp | 18 ++- firmware/application/capture_thread.hpp | 11 +- firmware/application/ert_app.cpp | 17 +-- firmware/application/ert_app.hpp | 6 +- firmware/application/file.cpp | 123 +++++++++---------- firmware/application/file.hpp | 118 +++++++++++++----- firmware/application/log_file.cpp | 20 ++-- firmware/application/log_file.hpp | 10 +- firmware/application/tpms_app.cpp | 21 ++-- firmware/application/tpms_app.hpp | 4 +- firmware/application/ui_navigation.cpp | 6 +- firmware/application/ui_record_view.cpp | 139 ++++++++++++++-------- firmware/application/ui_record_view.hpp | 2 +- firmware/application/ui_sd_card_debug.cpp | 20 ++-- firmware/common/png_writer.cpp | 12 +- firmware/common/png_writer.hpp | 3 +- 18 files changed, 328 insertions(+), 235 deletions(-) diff --git a/firmware/application/ais_app.cpp b/firmware/application/ais_app.cpp index 964ddf8d6..f8e948789 100644 --- a/firmware/application/ais_app.cpp +++ b/firmware/application/ais_app.cpp @@ -126,25 +126,17 @@ static std::string true_heading(const TrueHeading value) { } /* namespace format */ } /* namespace ais */ -AISLogger::AISLogger( - const std::string& file_path -) : log_file { file_path } -{ -} - void AISLogger::on_packet(const ais::Packet& packet) { // TODO: Unstuff here, not in baseband! - if( log_file.is_open() ) { - std::string entry; - entry.reserve((packet.length() + 3) / 4); + std::string entry; + entry.reserve((packet.length() + 3) / 4); - for(size_t i=0; i= 10) ? ('W' + nibble) : ('0' + nibble); - } - - log_file.write_entry(packet.received_at(), entry); + for(size_t i=0; i= 10) ? ('W' + nibble) : ('0' + nibble); } + + log_file.write_entry(packet.received_at(), entry); } void AISRecentEntry::update(const ais::Packet& packet) { @@ -332,7 +324,10 @@ AISAppView::AISAppView(NavigationView&) { this->on_show_list(); }; - logger = std::make_unique("ais.txt"); + logger = std::make_unique(); + if( logger ) { + logger->append("ais.txt"); + } } AISAppView::~AISAppView() { diff --git a/firmware/application/ais_app.hpp b/firmware/application/ais_app.hpp index a166f47dc..19286e6de 100644 --- a/firmware/application/ais_app.hpp +++ b/firmware/application/ais_app.hpp @@ -92,8 +92,10 @@ using AISRecentEntries = RecentEntries; class AISLogger { public: - AISLogger(const std::string& file_path); - + Optional append(const std::string& filename) { + return log_file.append(filename); + } + void on_packet(const ais::Packet& packet); private: diff --git a/firmware/application/capture_thread.cpp b/firmware/application/capture_thread.cpp index 0dbc4c1a2..50ed7a276 100644 --- a/firmware/application/capture_thread.cpp +++ b/firmware/application/capture_thread.cpp @@ -98,13 +98,8 @@ CaptureThread::~CaptureThread() { } } -Optional CaptureThread::error() const { - const auto error = writer->error(); - if( error.is_valid() ) { - return { error.value().what() }; - } else { - return { }; - } +const Optional& CaptureThread::error() const { + return last_error; } void CaptureThread::check_fifo_isr() { @@ -118,14 +113,15 @@ void CaptureThread::check_fifo_isr() { } } -msg_t CaptureThread::run() { +Optional CaptureThread::run() { StreamOutput stream { &config }; while( !chThdShouldTerminate() ) { if( stream.available() ) { auto buffer = stream.get_buffer(); - if( !writer->write(buffer->data(), buffer->size()) ) { - return false; + auto write_result = writer->write(buffer->data(), buffer->size()); + if( write_result.is_error() ) { + return write_result.error(); } stream.release_buffer(buffer); } else { @@ -133,5 +129,5 @@ msg_t CaptureThread::run() { } } - return true; + return { }; } diff --git a/firmware/application/capture_thread.hpp b/firmware/application/capture_thread.hpp index 25c092262..6842982ca 100644 --- a/firmware/application/capture_thread.hpp +++ b/firmware/application/capture_thread.hpp @@ -35,8 +35,7 @@ class Writer { public: - virtual bool write(const void* const buffer, const size_t bytes) = 0; - virtual Optional error() const = 0; + virtual File::Result write(const void* const buffer, const size_t bytes) = 0; virtual ~Writer() = default; }; @@ -53,21 +52,23 @@ public: return config; } - Optional error() const; + const Optional& error() const; static void check_fifo_isr(); private: CaptureConfig config; std::unique_ptr writer; + Optional last_error; static Thread* thread; static msg_t static_fn(void* arg) { auto obj = static_cast(arg); - return obj->run(); + obj->last_error = obj->run(); + return 0; } - msg_t run(); + Optional run(); }; #endif/*__CAPTURE_THREAD_H__*/ diff --git a/firmware/application/ert_app.cpp b/firmware/application/ert_app.cpp index 86b93339d..61501b473 100644 --- a/firmware/application/ert_app.cpp +++ b/firmware/application/ert_app.cpp @@ -57,17 +57,9 @@ std::string commodity_type(CommodityType value) { } /* namespace ert */ -ERTLogger::ERTLogger( - const std::string& file_path -) : log_file { file_path } -{ -} - void ERTLogger::on_packet(const ert::Packet& packet) { - if( log_file.is_open() ) { - const auto formatted = packet.symbols_formatted(); - log_file.write_entry(packet.received_at(), formatted.data + "/" + formatted.errors); - } + const auto formatted = packet.symbols_formatted(); + log_file.write_entry(packet.received_at(), formatted.data + "/" + formatted.errors); } const ERTRecentEntry::Key ERTRecentEntry::invalid_key { }; @@ -148,7 +140,10 @@ ERTAppView::ERTAppView(NavigationView&) { .decimation_factor = 1, }); - logger = std::make_unique("ert.txt"); + logger = std::make_unique(); + if( logger ) { + logger->append("ert.txt"); + } } ERTAppView::~ERTAppView() { diff --git a/firmware/application/ert_app.hpp b/firmware/application/ert_app.hpp index 403d9b63f..b74d599ed 100644 --- a/firmware/application/ert_app.hpp +++ b/firmware/application/ert_app.hpp @@ -87,8 +87,10 @@ struct ERTRecentEntry { class ERTLogger { public: - ERTLogger(const std::string& file_path); - + Optional append(const std::string& filename) { + return log_file.append(filename); + } + void on_packet(const ert::Packet& packet); private: diff --git a/firmware/application/file.cpp b/firmware/application/file.cpp index 25eeda296..bcca37429 100644 --- a/firmware/application/file.cpp +++ b/firmware/application/file.cpp @@ -28,99 +28,93 @@ static_assert(sizeof(FIL::err) == 1, "FatFs FIL::err size not expected."); #define FR_DISK_FULL (0x100) #define FR_EOF (0x101) #define FR_BAD_SEEK (0x102) +#define FR_UNEXPECTED (0x103) -File::File( - const std::string& filename, - openmode mode -) : err { FR_OK } -{ - BYTE fatfs_mode = 0; - 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 ) { +Optional File::open_fatfs(const std::string& filename, BYTE mode) { + auto result = f_open(&f, filename.c_str(), mode); + if( result == FR_OK ) { + if( mode & FA_OPEN_ALWAYS ) { + const auto result = f_lseek(&f, f_size(&f)); + if( result != FR_OK ) { f_close(&f); } } } + + if( result == FR_OK ) { + return { }; + } else { + return { result }; + } +} + +Optional File::open(const std::string& filename) { + return open_fatfs(filename, FA_READ); +} + +Optional File::append(const std::string& filename) { + return open_fatfs(filename, FA_WRITE | FA_OPEN_ALWAYS); +} + +Optional File::create(const std::string& filename) { + return open_fatfs(filename, FA_WRITE | FA_CREATE_ALWAYS); } File::~File() { f_close(&f); } -bool File::read(void* const data, const size_t bytes_to_read) { - if( err != FR_OK ) { - return false; - } - +File::Result File::read(void* const data, const size_t bytes_to_read) { UINT bytes_read = 0; - err = f_read(&f, data, bytes_to_read, &bytes_read); - if( bytes_read != bytes_to_read ) { - err = FR_EOF; + const auto result = f_read(&f, data, bytes_to_read, &bytes_read); + if( result == FR_OK ) { + return { static_cast(bytes_read) }; + } else { + return { static_cast(result) }; } - return (err == FR_OK); } -bool File::write(const void* const data, const size_t bytes_to_write) { - if( err != FR_OK ) { - return false; - } - +File::Result File::write(const void* const data, const size_t bytes_to_write) { UINT bytes_written = 0; - err = f_write(&f, data, bytes_to_write, &bytes_written); - if( bytes_written != bytes_to_write ) { - err = FR_DISK_FULL; + const auto result = f_write(&f, data, bytes_to_write, &bytes_written); + if( result == FR_OK ) { + return { static_cast(bytes_written) }; + } else { + return { static_cast(result) }; } - return (err == FR_OK); } -uint64_t File::seek(const uint64_t new_position) { - if( err != FR_OK ) { - return false; - } - +File::Result File::seek(const uint64_t new_position) { + /* NOTE: Returns *old* position, not new position */ const auto old_position = f_tell(&f); - err = f_lseek(&f, new_position); - if( err != FR_OK ) { - f_close(&f); + const auto result = f_lseek(&f, new_position); + if( result != FR_OK ) { + return { static_cast(result) }; } if( f_tell(&f) != new_position ) { - err = FR_BAD_SEEK; - f_close(&f); + return { static_cast(FR_BAD_SEEK) }; } - return old_position; + return { static_cast(old_position) }; } -bool File::puts(const std::string& string) { +File::Result File::puts(const std::string& string) { const auto result = f_puts(string.c_str(), &f); - if( result != (int)string.size() ) { - err = FR_DISK_FULL; + if( result >= 0 ) { + return { static_cast(result) }; + } else if( result == EOF ) { + return { static_cast(f_error(&f)) }; + } else { + return { static_cast(FR_UNEXPECTED) }; } - return (result >= 0); } -bool File::sync() { - if( err != FR_OK ) { - return false; +Optional File::sync() { + const auto result = f_sync(&f); + 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) { @@ -181,7 +175,7 @@ namespace filesystem { std::string filesystem_error::what() const { switch(err) { - case FR_OK: return ""; + case FR_OK: return "ok"; case FR_DISK_ERR: return "disk error"; case FR_INT_ERR: return "insanity detected"; 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_DISK_FULL: return "disk full"; case FR_BAD_SEEK: return "bad seek"; + case FR_UNEXPECTED: return "unexpected"; default: return "unknown"; } } diff --git a/firmware/application/file.hpp b/firmware/application/file.hpp index d8c711f28..6d3453e69 100644 --- a/firmware/application/file.hpp +++ b/firmware/application/file.hpp @@ -24,6 +24,8 @@ #include "ff.h" +#include "optional.hpp" + #include #include #include @@ -37,9 +39,27 @@ namespace std { namespace filesystem { 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; + +private: + uint32_t err; }; using path = std::string; @@ -109,51 +129,89 @@ space_info space(const path& p); class File { public: - enum openmode { - app = 0x100, - binary = 0x200, - in = FA_READ, - out = FA_WRITE, - trunc = FA_CREATE_ALWAYS, - ate = FA_OPEN_ALWAYS, + using Error = std::filesystem::filesystem_error; + + template + struct Result { + enum class Type { + Success, + 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(); - bool is_open() const { - return err == FR_OK; - } + /* Prevent copies */ + File(const File&) = delete; + File& operator=(const File&) = delete; - bool bad() const { - return err != FR_OK; - } + // TODO: Return Result<>. + Optional open(const std::string& filename); + Optional append(const std::string& filename); + Optional create(const std::string& filename); - std::filesystem::filesystem_error error() const { - return { err }; - } + Result read(void* const data, const size_t bytes_to_read); + Result write(const void* const data, const size_t bytes_to_write); - bool read(void* const data, const size_t bytes_to_read); - bool write(const void* const data, const size_t bytes_to_write); - - uint64_t seek(const uint64_t new_position); + Result seek(const uint64_t new_position); template - bool write(const std::array& data) { + Result write(const std::array& data) { return write(data.data(), N); } - bool puts(const std::string& string); + Result puts(const std::string& string); - bool sync(); + // TODO: Return Result<>. + Optional sync(); private: FIL f; - uint32_t err; + + Optional open_fatfs(const std::string& filename, BYTE mode); }; -inline constexpr File::openmode operator|(File::openmode a, File::openmode b) { - return File::openmode(static_cast(a) | static_cast(b)); -} - #endif/*__FILE_H__*/ diff --git a/firmware/application/log_file.cpp b/firmware/application/log_file.cpp index 06e56246c..a761650fe 100644 --- a/firmware/application/log_file.cpp +++ b/firmware/application/log_file.cpp @@ -23,21 +23,15 @@ #include "string_format.hpp" -LogFile::LogFile( - 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) { +File::Result LogFile::write_entry(const rtc::RTC& datetime, const std::string& entry) { std::string timestamp = to_string_timestamp(datetime); return write(timestamp + " " + entry + "\r\n"); } -bool LogFile::write(const std::string& message) { - return file.puts(message) && file.sync(); +File::Result LogFile::write(const std::string& message) { + auto puts_result = file.puts(message); + if( puts_result.is_ok() ) { + file.sync(); + } + return puts_result; } diff --git a/firmware/application/log_file.hpp b/firmware/application/log_file.hpp index 70a1651cd..2aa515fab 100644 --- a/firmware/application/log_file.hpp +++ b/firmware/application/log_file.hpp @@ -31,16 +31,16 @@ using namespace lpc43xx; class LogFile { public: - LogFile(const std::string& file_path); + Optional append(const std::string& filename) { + return file.append(filename); + } - bool is_open() const; - - bool write_entry(const rtc::RTC& datetime, const std::string& entry); + File::Result write_entry(const rtc::RTC& datetime, const std::string& entry); private: File file; - bool write(const std::string& message); + File::Result write(const std::string& message); }; #endif/*__LOG_FILE_H__*/ diff --git a/firmware/application/tpms_app.cpp b/firmware/application/tpms_app.cpp index 46f045377..d6e1ef9fe 100644 --- a/firmware/application/tpms_app.cpp +++ b/firmware/application/tpms_app.cpp @@ -51,22 +51,14 @@ std::string temperature(Temperature temperature) { } /* 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) { 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! - const auto tuning_frequency_str = to_string_dec_uint(target_frequency, 10); + // 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); - 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); - } + 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); } const TPMSRecentEntry::Key TPMSRecentEntry::invalid_key = { tpms::Reading::Type::None, 0 }; @@ -165,7 +157,10 @@ TPMSAppView::TPMSAppView(NavigationView&) { .decimation_factor = 1, }); - logger = std::make_unique("tpms.txt"); + logger = std::make_unique(); + if( logger ) { + logger->append("tpms.txt"); + } } TPMSAppView::~TPMSAppView() { diff --git a/firmware/application/tpms_app.hpp b/firmware/application/tpms_app.hpp index ea0e9b391..e4f00b7ac 100644 --- a/firmware/application/tpms_app.hpp +++ b/firmware/application/tpms_app.hpp @@ -72,7 +72,9 @@ using TPMSRecentEntries = RecentEntries; class TPMSLogger { public: - TPMSLogger(const std::string& file_path); + Optional append(const std::string& filename) { + return log_file.append(filename); + } void on_packet(const tpms::Packet& packet, const uint32_t target_frequency); diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 943d522a1..bc1a7734d 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -86,7 +86,11 @@ void SystemStatusView::on_camera() { 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++) { std::array row; diff --git a/firmware/application/ui_record_view.cpp b/firmware/application/ui_record_view.cpp index cc87f0d52..6922a3e4c 100644 --- a/firmware/application/ui_record_view.cpp +++ b/firmware/application/ui_record_view.cpp @@ -34,26 +34,23 @@ using namespace portapack; class FileWriter : public Writer { public: - FileWriter( - const std::string& filename - ) : file { filename, File::openmode::out | File::openmode::binary | File::openmode::trunc } - { + FileWriter() = default; + + FileWriter(const FileWriter&) = delete; + FileWriter& operator=(const FileWriter&) = delete; + FileWriter(FileWriter&& file) = delete; + FileWriter& operator=(FileWriter&&) = delete; + + Optional create(const std::string& filename) { + return file.create(filename); } - Optional error() const override { - if( file.bad() ) { - return { file.error() }; - } else { - return { }; + File::Result write(const void* const buffer, const size_t bytes) override { + auto write_result = file.write(buffer, bytes) ; + if( write_result.is_ok() ) { + bytes_written += write_result.value(); } - } - - 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; + return write_result; } protected: @@ -66,18 +63,33 @@ using RawFileWriter = FileWriter; class WAVFileWriter : public FileWriter { public: WAVFileWriter( - const std::string& filename, 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() { update_header(); } + Optional 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: struct fmt_pcm_t { constexpr fmt_pcm_t( @@ -132,7 +144,11 @@ private: void update_header() { 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.seek(old_position); } @@ -206,17 +222,39 @@ void RecordView::start() { std::unique_ptr writer; switch(file_type) { case FileType::WAV: - writer = std::make_unique( - filename_stem + ".WAV", - sampling_rate - ); + { + auto p = std::make_unique( + 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; case FileType::RawS16: - write_metadata_file(filename_stem + ".TXT"); - writer = std::make_unique( - filename_stem + ".C16" - ); + { + const auto metadata_file_error = write_metadata_file(filename_stem + ".TXT"); + if( metadata_file_error.is_valid() ) { + report_error(metadata_file_error.value().what()); + return; + } + + auto p = std::make_unique(); + 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; default: @@ -224,19 +262,12 @@ void RecordView::start() { }; if( writer ) { - const auto error = writer->error(); - if( error.is_valid() ) { - report_error(error.value().what()); - } else { - text_record_filename.set(filename_stem); - button_record.set_bitmap(&bitmap_stop); - capture_thread = std::make_unique( - std::move(writer), - write_size, buffer_count - ); - } - } else { - report_error("file type"); + text_record_filename.set(filename_stem); + button_record.set_bitmap(&bitmap_stop); + capture_thread = std::make_unique( + std::move(writer), + write_size, buffer_count + ); } } @@ -247,10 +278,22 @@ void RecordView::stop() { } } -void RecordView::write_metadata_file(const std::string& filename) { - File file { filename, File::openmode::out | File::openmode::trunc }; - file.puts("sample_rate=" + to_string_dec_uint(sampling_rate) + "\n"); - file.puts("center_frequency=" + to_string_dec_uint(receiver_model.tuning_frequency()) + "\n"); +Optional RecordView::write_metadata_file(const std::string& filename) { + File file; + const auto create_error = file.create(filename); + 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() { @@ -258,7 +301,7 @@ void RecordView::on_tick_second() { const auto error = capture_thread->error(); if( error.is_valid() ) { stop(); - report_error(error.value()); + report_error(error.value().what()); } const auto dropped_percent = std::min(99U, capture_thread->state().dropped_percent()); const auto s = to_string_dec_uint(dropped_percent, 2, ' ') + "\%"; diff --git a/firmware/application/ui_record_view.hpp b/firmware/application/ui_record_view.hpp index 8f987b3d2..af21987d3 100644 --- a/firmware/application/ui_record_view.hpp +++ b/firmware/application/ui_record_view.hpp @@ -69,7 +69,7 @@ public: private: void toggle(); - void write_metadata_file(const std::string& filename); + Optional write_metadata_file(const std::string& filename); void on_tick_second(); diff --git a/firmware/application/ui_sd_card_debug.cpp b/firmware/application/ui_sd_card_debug.cpp index 668c814ba..eac201eaf 100644 --- a/firmware/application/ui_sd_card_debug.cpp +++ b/firmware/application/ui_sd_card_debug.cpp @@ -134,22 +134,24 @@ private: return Result::FailHeap; } - File file { filename, File::openmode::out | File::openmode::binary | File::openmode::trunc }; - if( !file.is_open() ) { + File file; + auto file_create_error = file.create(filename); + if( file_create_error.is_valid() ) { return Result::FailFileOpenWrite; } lfsr_word_t v = 1; 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, reinterpret_cast(buffer->data()), sizeof(*buffer.get()) / sizeof(lfsr_word_t) ); 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; } const halrtcnt_t write_end = halGetCounterValue(); @@ -179,17 +181,19 @@ private: return Result::FailHeap; } - File file { filename, File::openmode::in | File::openmode::binary }; - if( !file.is_open() ) { + File file; + auto file_open_error = file.open(filename); + if( file_open_error.is_valid() ) { return Result::FailFileOpenRead; } lfsr_word_t v = 1; 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(); - if( !file.read(buffer->data(), buffer->size()) ) { + const auto result_read = file.read(buffer->data(), buffer->size()); + if( result_read.is_error() ) { break; } const halrtcnt_t read_end = halGetCounterValue(); diff --git a/firmware/common/png_writer.cpp b/firmware/common/png_writer.cpp index c1d592440..e1667f14b 100644 --- a/firmware/common/png_writer.cpp +++ b/firmware/common/png_writer.cpp @@ -49,10 +49,14 @@ static constexpr std::array png_iend { { 0xae, 0x42, 0x60, 0x82, // CRC } }; -PNGWriter::PNGWriter( +Optional PNGWriter::create( 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_ihdr_screen_capture); @@ -63,6 +67,8 @@ PNGWriter::PNGWriter( constexpr std::array zlib_header { 0x78, 0x01 }; // Zlib CM, CINFO, FLG. write_chunk_content(zlib_header); + + return { }; } PNGWriter::~PNGWriter() { diff --git a/firmware/common/png_writer.hpp b/firmware/common/png_writer.hpp index 90fc20863..37bede47d 100644 --- a/firmware/common/png_writer.hpp +++ b/firmware/common/png_writer.hpp @@ -33,9 +33,10 @@ class PNGWriter { public: - explicit PNGWriter(const std::string& filename); ~PNGWriter(); + Optional create(const std::string& filename); + void write_scanline(const std::array& scanline); private: