From f7bfde73b63c0bb17d7f64e0468bf279bbfd0776 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sun, 21 Aug 2016 18:06:39 -0700 Subject: [PATCH] FatFs: Enable long file name support. Lots of re-plumbing to make this work, including a bunch of Unicode stuff now in the binary. Bloat City, I'm sure. TODO: FatFs using unsigned (uint16_t) for UTF16 representation is kinda inconvenient. Lots of reinterpret_cast<>(). --- firmware/application/ais_app.cpp | 2 +- firmware/application/ais_app.hpp | 2 +- firmware/application/analog_audio_app.hpp | 2 +- firmware/application/capture_app.hpp | 2 +- firmware/application/ert_app.cpp | 2 +- firmware/application/ert_app.hpp | 2 +- firmware/application/ffconf.h | 4 +-- firmware/application/file.cpp | 34 +++++++++---------- firmware/application/file.hpp | 21 +++++++----- firmware/application/log_file.hpp | 2 +- firmware/application/sd_card.cpp | 2 +- firmware/application/tpms_app.cpp | 2 +- firmware/application/tpms_app.hpp | 2 +- firmware/application/ui_navigation.cpp | 4 +-- firmware/application/ui_record_view.cpp | 24 ++++++++----- firmware/application/ui_record_view.hpp | 6 ++-- firmware/application/ui_sd_card_debug.cpp | 8 ++--- .../os/various/fatfs_bindings/fatfs.cmake | 1 + firmware/common/png_writer.cpp | 2 +- firmware/common/png_writer.hpp | 2 +- 20 files changed, 68 insertions(+), 58 deletions(-) diff --git a/firmware/application/ais_app.cpp b/firmware/application/ais_app.cpp index 189ecacc..1b04bc18 100644 --- a/firmware/application/ais_app.cpp +++ b/firmware/application/ais_app.cpp @@ -331,7 +331,7 @@ AISAppView::AISAppView(NavigationView&) { logger = std::make_unique(); if( logger ) { - logger->append("ais.txt"); + logger->append(u"ais.txt"); } } diff --git a/firmware/application/ais_app.hpp b/firmware/application/ais_app.hpp index b38a2146..10da06a2 100644 --- a/firmware/application/ais_app.hpp +++ b/firmware/application/ais_app.hpp @@ -95,7 +95,7 @@ using AISRecentEntries = RecentEntries; class AISLogger { public: - Optional append(const std::string& filename) { + Optional append(const std::filesystem::path& filename) { return log_file.append(filename); } diff --git a/firmware/application/analog_audio_app.hpp b/firmware/application/analog_audio_app.hpp index a91e8059..697a199a 100644 --- a/firmware/application/analog_audio_app.hpp +++ b/firmware/application/analog_audio_app.hpp @@ -143,7 +143,7 @@ private: RecordView record_view { { 0 * 8, 2 * 16, 30 * 8, 1 * 16 }, - "AUD_????", RecordView::FileType::WAV, 4096, 4 + u"AUD_????", RecordView::FileType::WAV, 4096, 4 }; spectrum::WaterfallWidget waterfall; diff --git a/firmware/application/capture_app.hpp b/firmware/application/capture_app.hpp index a7d04859..76d287f0 100644 --- a/firmware/application/capture_app.hpp +++ b/firmware/application/capture_app.hpp @@ -89,7 +89,7 @@ private: RecordView record_view { { 0 * 8, 1 * 16, 30 * 8, 1 * 16 }, - "BBD_????", RecordView::FileType::RawS16, 16384, 3 + u"BBD_????", RecordView::FileType::RawS16, 16384, 3 }; spectrum::WaterfallWidget waterfall; diff --git a/firmware/application/ert_app.cpp b/firmware/application/ert_app.cpp index 4ec70f93..5bed3782 100644 --- a/firmware/application/ert_app.cpp +++ b/firmware/application/ert_app.cpp @@ -146,7 +146,7 @@ ERTAppView::ERTAppView(NavigationView&) { logger = std::make_unique(); if( logger ) { - logger->append("ert.txt"); + logger->append(u"ert.txt"); } } diff --git a/firmware/application/ert_app.hpp b/firmware/application/ert_app.hpp index 1d901f45..cba9e74a 100644 --- a/firmware/application/ert_app.hpp +++ b/firmware/application/ert_app.hpp @@ -90,7 +90,7 @@ struct ERTRecentEntry { class ERTLogger { public: - Optional append(const std::string& filename) { + Optional append(const std::filesystem::path& filename) { return log_file.append(filename); } diff --git a/firmware/application/ffconf.h b/firmware/application/ffconf.h index a02d51b0..cfe0e890 100644 --- a/firmware/application/ffconf.h +++ b/firmware/application/ffconf.h @@ -101,7 +101,7 @@ */ -#define _USE_LFN 0 +#define _USE_LFN 2 #define _MAX_LFN 255 /* The _USE_LFN switches the support of long file name (LFN). / @@ -119,7 +119,7 @@ / ff_memfree(), must be added to the project. */ -#define _LFN_UNICODE 0 +#define _LFN_UNICODE 1 /* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16) / To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1. / This option also affects behavior of string I/O functions. */ diff --git a/firmware/application/file.cpp b/firmware/application/file.cpp index f4415452..4ceb51aa 100644 --- a/firmware/application/file.cpp +++ b/firmware/application/file.cpp @@ -30,8 +30,8 @@ static_assert(sizeof(FIL::err) == 1, "FatFs FIL::err size not expected."); #define FR_BAD_SEEK (0x102) #define FR_UNEXPECTED (0x103) -Optional File::open_fatfs(const std::string& filename, BYTE mode) { - auto result = f_open(&f, filename.c_str(), mode); +Optional File::open_fatfs(const std::filesystem::path& filename, BYTE mode) { + auto result = f_open(&f, reinterpret_cast(filename.c_str()), mode); if( result == FR_OK ) { if( mode & FA_OPEN_ALWAYS ) { const auto result = f_lseek(&f, f_size(&f)); @@ -48,15 +48,15 @@ Optional File::open_fatfs(const std::string& filename, BYTE mode) { } } -Optional File::open(const std::string& filename) { +Optional File::open(const std::filesystem::path& filename) { return open_fatfs(filename, FA_READ); } -Optional File::append(const std::string& filename) { +Optional File::append(const std::filesystem::path& filename) { return open_fatfs(filename, FA_WRITE | FA_OPEN_ALWAYS); } -Optional File::create(const std::string& filename) { +Optional File::create(const std::filesystem::path& filename) { return open_fatfs(filename, FA_WRITE | FA_CREATE_ALWAYS); } @@ -124,9 +124,9 @@ Optional File::sync() { } } -static std::string find_last_file_matching_pattern(const std::string& pattern) { - std::string last_match; - for(const auto& entry : std::filesystem::directory_iterator("", pattern.c_str())) { +static std::filesystem::path find_last_file_matching_pattern(const std::filesystem::path& pattern) { + std::filesystem::path last_match; + for(const auto& entry : std::filesystem::directory_iterator(u"", pattern.c_str())) { if( std::filesystem::is_regular_file(entry.status()) ) { const auto match = entry.path(); if( match > last_match ) { @@ -137,13 +137,13 @@ static std::string find_last_file_matching_pattern(const std::string& pattern) { return last_match; } -static std::string remove_filename_extension(const std::string& filename) { +static std::filesystem::path remove_filename_extension(const std::filesystem::path& filename) { const auto extension_index = filename.find_last_of('.'); return filename.substr(0, extension_index); } -static std::string increment_filename_stem_ordinal(const std::string& filename_stem) { - std::string result { filename_stem }; +static std::filesystem::path increment_filename_stem_ordinal(const std::filesystem::path& filename_stem) { + std::filesystem::path result { filename_stem }; auto it = result.rbegin(); @@ -165,8 +165,8 @@ static std::string increment_filename_stem_ordinal(const std::string& filename_s return result; } -std::string next_filename_stem_matching_pattern(const std::string& filename_stem_pattern) { - const auto filename = find_last_file_matching_pattern(filename_stem_pattern + ".*"); +std::filesystem::path next_filename_stem_matching_pattern(const std::filesystem::path& filename_stem_pattern) { + const auto filename = find_last_file_matching_pattern(filename_stem_pattern + u".*"); auto filename_stem = remove_filename_extension(filename); if( filename_stem.empty() ) { filename_stem = filename_stem_pattern; @@ -211,11 +211,11 @@ std::string filesystem_error::what() const { } directory_iterator::directory_iterator( - const char* path, - const char* wild + const std::filesystem::path::value_type* path, + const std::filesystem::path::value_type* wild ) { impl = std::make_shared(); - const auto result = f_findfirst(&impl->dir, &impl->filinfo, path, wild); + const auto result = f_findfirst(&impl->dir, &impl->filinfo, reinterpret_cast(path), reinterpret_cast(wild)); if( result != FR_OK ) { impl.reset(); // TODO: Throw exception if/when I enable exceptions... @@ -237,7 +237,7 @@ bool is_regular_file(const file_status s) { space_info space(const path& p) { DWORD free_clusters { 0 }; FATFS* fs; - if( f_getfree(p.c_str(), &free_clusters, &fs) == FR_OK ) { + if( f_getfree(reinterpret_cast(p.c_str()), &free_clusters, &fs) == FR_OK ) { #if _MAX_SS != _MIN_SS static_assert(false, "FatFs not configured for fixed sector size"); #else diff --git a/firmware/application/file.hpp b/firmware/application/file.hpp index f3739317..62813e21 100644 --- a/firmware/application/file.hpp +++ b/firmware/application/file.hpp @@ -33,8 +33,6 @@ #include #include -std::string next_filename_stem_matching_pattern(const std::string& filename_stem_pattern); - namespace std { namespace filesystem { @@ -66,9 +64,12 @@ private: uint32_t err; }; -using path = std::string; +using path = std::u16string; using file_status = BYTE; +static_assert(sizeof(path::value_type) == 2, "sizeof(std::filesystem::path::value_type) != 2"); +static_assert(sizeof(path::value_type) == sizeof(TCHAR), "FatFs TCHAR size != std::filesystem::path::value_type"); + struct space_info { static_assert(sizeof(std::uintmax_t) >= 8, "std::uintmax_t too small ((fname); }; }; class directory_iterator { @@ -107,7 +108,7 @@ public: using iterator_category = std::input_iterator_tag; directory_iterator() noexcept { }; - directory_iterator(const char* path, const char* wild); + directory_iterator(const std::filesystem::path::value_type* path, const std::filesystem::path::value_type* wild); ~directory_iterator() { } @@ -131,6 +132,8 @@ space_info space(const path& p); } /* namespace filesystem */ } /* namespace std */ +std::filesystem::path next_filename_stem_matching_pattern(const std::filesystem::path& filename_stem_pattern); + class File { public: using Error = std::filesystem::filesystem_error; @@ -193,9 +196,9 @@ public: File& operator=(const File&) = delete; // TODO: Return Result<>. - Optional open(const std::string& filename); - Optional append(const std::string& filename); - Optional create(const std::string& filename); + Optional open(const std::filesystem::path& filename); + Optional append(const std::filesystem::path& filename); + Optional create(const std::filesystem::path& filename); Result read(void* const data, const size_t bytes_to_read); Result write(const void* const data, const size_t bytes_to_write); @@ -215,7 +218,7 @@ public: private: FIL f; - Optional open_fatfs(const std::string& filename, BYTE mode); + Optional open_fatfs(const std::filesystem::path& filename, BYTE mode); }; #endif/*__FILE_H__*/ diff --git a/firmware/application/log_file.hpp b/firmware/application/log_file.hpp index 1e1f667a..5f222a79 100644 --- a/firmware/application/log_file.hpp +++ b/firmware/application/log_file.hpp @@ -31,7 +31,7 @@ using namespace lpc43xx; class LogFile { public: - Optional append(const std::string& filename) { + Optional append(const std::filesystem::path& filename) { return file.append(filename); } diff --git a/firmware/application/sd_card.cpp b/firmware/application/sd_card.cpp index ed2a90b2..b7846152 100644 --- a/firmware/application/sd_card.cpp +++ b/firmware/application/sd_card.cpp @@ -36,7 +36,7 @@ Status status_ { Status::NotPresent }; FATFS fs; FRESULT mount() { - return f_mount(&fs, "", 0); + return f_mount(&fs, reinterpret_cast(_T("")), 0); } } /* namespace */ diff --git a/firmware/application/tpms_app.cpp b/firmware/application/tpms_app.cpp index cc55f276..2a13e2f2 100644 --- a/firmware/application/tpms_app.cpp +++ b/firmware/application/tpms_app.cpp @@ -193,7 +193,7 @@ TPMSAppView::TPMSAppView(NavigationView&) { logger = std::make_unique(); if( logger ) { - logger->append("tpms.txt"); + logger->append(u"tpms.txt"); } } diff --git a/firmware/application/tpms_app.hpp b/firmware/application/tpms_app.hpp index fc9e0c35..98715219 100644 --- a/firmware/application/tpms_app.hpp +++ b/firmware/application/tpms_app.hpp @@ -76,7 +76,7 @@ using TPMSRecentEntries = RecentEntries; class TPMSLogger { public: - Optional append(const std::string& filename) { + Optional append(const std::filesystem::path& filename) { return log_file.append(filename); } diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 4238af12..ba8e783c 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -81,13 +81,13 @@ void SystemStatusView::set_title(const std::string new_value) { } void SystemStatusView::on_camera() { - const auto filename_stem = next_filename_stem_matching_pattern("SCR_????"); + const auto filename_stem = next_filename_stem_matching_pattern(u"SCR_????"); if( filename_stem.empty() ) { return; } PNGWriter png; - auto create_error = png.create(filename_stem + ".PNG"); + auto create_error = png.create(filename_stem + u".PNG"); if( create_error.is_valid() ) { return; } diff --git a/firmware/application/ui_record_view.cpp b/firmware/application/ui_record_view.cpp index bf7ec391..42e0d374 100644 --- a/firmware/application/ui_record_view.cpp +++ b/firmware/application/ui_record_view.cpp @@ -32,6 +32,9 @@ using namespace portapack; #include +#include +#include + class FileWriter : public Writer { public: FileWriter() = default; @@ -41,7 +44,7 @@ public: FileWriter(FileWriter&& file) = delete; FileWriter& operator=(FileWriter&&) = delete; - Optional create(const std::string& filename) { + Optional create(const std::filesystem::path& filename) { return file.create(filename); } @@ -79,7 +82,7 @@ public: } Optional create( - const std::string& filename + const std::filesystem::path& filename ) { const auto create_error = FileWriter::create(filename); if( create_error.is_valid() ) { @@ -164,7 +167,7 @@ namespace ui { RecordView::RecordView( const Rect parent_rect, - std::string filename_stem_pattern, + std::filesystem::path filename_stem_pattern, const FileType file_type, const size_t write_size, const size_t buffer_count @@ -251,7 +254,7 @@ void RecordView::start() { sampling_rate ); auto create_error = p->create( - filename_stem + ".WAV" + filename_stem + u".WAV" ); if( create_error.is_valid() ) { handle_error(create_error.value()); @@ -263,7 +266,7 @@ void RecordView::start() { case FileType::RawS16: { - const auto metadata_file_error = write_metadata_file(filename_stem + ".TXT"); + const auto metadata_file_error = write_metadata_file(filename_stem + u".TXT"); if( metadata_file_error.is_valid() ) { handle_error(metadata_file_error.value()); return; @@ -271,7 +274,7 @@ void RecordView::start() { auto p = std::make_unique(); auto create_error = p->create( - filename_stem + ".C16" + filename_stem + u".C16" ); if( create_error.is_valid() ) { handle_error(create_error.value()); @@ -286,7 +289,10 @@ void RecordView::start() { }; if( writer ) { - text_record_filename.set(filename_stem); + std::wstring_convert, std::filesystem::path::value_type> conv; + const auto filename_stem_s = conv.to_bytes(filename_stem); + + text_record_filename.set(filename_stem_s); button_record.set_bitmap(&bitmap_stop); capture_thread = std::make_unique( std::move(writer), @@ -314,7 +320,7 @@ void RecordView::stop() { update_status_display(); } -Optional RecordView::write_metadata_file(const std::string& filename) { +Optional RecordView::write_metadata_file(const std::filesystem::path& filename) { File file; const auto create_error = file.create(filename); if( create_error.is_valid() ) { @@ -344,7 +350,7 @@ void RecordView::update_status_display() { } if( sampling_rate ) { - const auto space_info = std::filesystem::space(""); + const auto space_info = std::filesystem::space(u""); const uint32_t bytes_per_second = file_type == FileType::WAV ? (sampling_rate * 2) : (sampling_rate * 4); const uint32_t available_seconds = space_info.free / bytes_per_second; const uint32_t seconds = available_seconds % 60; diff --git a/firmware/application/ui_record_view.hpp b/firmware/application/ui_record_view.hpp index 023fb0d5..203d334c 100644 --- a/firmware/application/ui_record_view.hpp +++ b/firmware/application/ui_record_view.hpp @@ -46,7 +46,7 @@ public: RecordView( const Rect parent_rect, - std::string filename_stem_pattern, + std::filesystem::path filename_stem_pattern, FileType file_type, const size_t write_size, const size_t buffer_count @@ -64,7 +64,7 @@ public: private: void toggle(); - Optional write_metadata_file(const std::string& filename); + Optional write_metadata_file(const std::filesystem::path& filename); void on_tick_second(); void update_status_display(); @@ -72,7 +72,7 @@ private: void handle_capture_thread_done(const File::Error error); void handle_error(const File::Error error); - const std::string filename_stem_pattern; + const std::filesystem::path filename_stem_pattern; const FileType file_type; const size_t write_size; const size_t buffer_count; diff --git a/firmware/application/ui_sd_card_debug.cpp b/firmware/application/ui_sd_card_debug.cpp index eac201ea..dd92f5c6 100644 --- a/firmware/application/ui_sd_card_debug.cpp +++ b/firmware/application/ui_sd_card_debug.cpp @@ -95,7 +95,7 @@ private: } Result run() { - const std::string filename { "_PPTEST_.DAT" }; + const std::filesystem::path filename { u"_PPTEST_.DAT" }; const auto write_result = write(filename); if( write_result != Result::OK ) { @@ -115,7 +115,7 @@ private: return read_result; } - f_unlink(filename.c_str()); + f_unlink(reinterpret_cast(filename.c_str())); if( _stats.read_bytes < bytes_to_read ) { return Result::FailReadIncomplete; @@ -128,7 +128,7 @@ private: return Result::OK; } - Result write(const std::string& filename) { + Result write(const std::filesystem::path& filename) { const auto buffer = std::make_unique>(); if( !buffer ) { return Result::FailHeap; @@ -175,7 +175,7 @@ private: return Result::OK; } - Result read(const std::string& filename) { + Result read(const std::filesystem::path& filename) { const auto buffer = std::make_unique>(); if( !buffer ) { return Result::FailHeap; diff --git a/firmware/chibios-portapack/os/various/fatfs_bindings/fatfs.cmake b/firmware/chibios-portapack/os/various/fatfs_bindings/fatfs.cmake index 389f5d14..1eff8f31 100644 --- a/firmware/chibios-portapack/os/various/fatfs_bindings/fatfs.cmake +++ b/firmware/chibios-portapack/os/various/fatfs_bindings/fatfs.cmake @@ -3,6 +3,7 @@ set(FATFSSRC ${CHIBIOS_PORTAPACK}/os/various/fatfs_bindings/fatfs_diskio.c ${CHIBIOS_PORTAPACK}/os/various/fatfs_bindings/fatfs_syscall.c ${CHIBIOS_PORTAPACK}/ext/fatfs/src/ff.c + ${CHIBIOS_PORTAPACK}/ext/fatfs/src/option/unicode.c ) set(FATFSINC diff --git a/firmware/common/png_writer.cpp b/firmware/common/png_writer.cpp index e1667f14..b714e322 100644 --- a/firmware/common/png_writer.cpp +++ b/firmware/common/png_writer.cpp @@ -50,7 +50,7 @@ static constexpr std::array png_iend { { } }; Optional PNGWriter::create( - const std::string& filename + const std::filesystem::path& filename ) { const auto create_error = file.create(filename); if( create_error.is_valid() ) { diff --git a/firmware/common/png_writer.hpp b/firmware/common/png_writer.hpp index 37bede47..020a118a 100644 --- a/firmware/common/png_writer.hpp +++ b/firmware/common/png_writer.hpp @@ -35,7 +35,7 @@ class PNGWriter { public: ~PNGWriter(); - Optional create(const std::string& filename); + Optional create(const std::filesystem::path& filename); void write_scanline(const std::array& scanline);