diff --git a/firmware/application/apps/ui_fileman.cpp b/firmware/application/apps/ui_fileman.cpp index 20869fe7e..554895cd5 100644 --- a/firmware/application/apps/ui_fileman.cpp +++ b/firmware/application/apps/ui_fileman.cpp @@ -43,6 +43,7 @@ namespace ui { static const fs::path txt_ext{u".TXT"}; static const fs::path ppl_ext{u".PPL"}; static const fs::path c8_ext{u".C8"}; +static const fs::path cu8_ext{u".CU8"}; static const fs::path c16_ext{u".C16"}; static const fs::path cxx_ext{u".C*"}; static const fs::path png_ext{u".PNG"}; @@ -88,8 +89,11 @@ fs::path get_partner_file(fs::path path) { path.replace_extension(txt_ext); else if (path_iequal(ext, txt_ext)) { path.replace_extension(c8_ext); + if (!fs::file_exists(path)) + path.replace_extension(cu8_ext); if (!fs::file_exists(path)) path.replace_extension(c16_ext); + } else return {}; diff --git a/firmware/application/apps/ui_fileman.hpp b/firmware/application/apps/ui_fileman.hpp index 05a10cce9..511b6276f 100644 --- a/firmware/application/apps/ui_fileman.hpp +++ b/firmware/application/apps/ui_fileman.hpp @@ -80,6 +80,7 @@ class FileManBaseView : public View { {u".PNG", &bitmap_icon_file_image, ui::Color::green()}, {u".BMP", &bitmap_icon_file_image, ui::Color::green()}, {u".C8", &bitmap_icon_file_iq, ui::Color::dark_cyan()}, + {u".CU8", &bitmap_icon_file_iq, ui::Color::dark_cyan()}, {u".C16", &bitmap_icon_file_iq, ui::Color::dark_cyan()}, {u".WAV", &bitmap_icon_file_wav, ui::Color::dark_magenta()}, {u".PPL", &bitmap_icon_file_iq, ui::Color::white()}, // Playlist/Replay diff --git a/firmware/application/file.cpp b/firmware/application/file.cpp index 08bf0f36f..75b707486 100644 --- a/firmware/application/file.cpp +++ b/firmware/application/file.cpp @@ -30,6 +30,7 @@ namespace fs = std::filesystem; static const fs::path c8_ext{u".C8"}; +static const fs::path cu8_ext{u".CU8"}; static const fs::path c16_ext{u".C16"}; Optional File::open_fatfs(const std::filesystem::path& filename, BYTE mode) { @@ -543,12 +544,14 @@ bool path_iequal( bool is_cxx_capture_file(const path& filename) { auto ext = filename.extension(); - return path_iequal(c8_ext, ext) || path_iequal(c16_ext, ext); + return path_iequal(c8_ext, ext) || path_iequal(cu8_ext, ext) || path_iequal(c16_ext, ext); } uint8_t capture_file_sample_size(const path& filename) { if (path_iequal(filename.extension(), c8_ext)) return sizeof(complex8_t); + if (path_iequal(filename.extension(), cu8_ext)) + return sizeof(complexu8_t); if (path_iequal(filename.extension(), c16_ext)) return sizeof(complex16_t); return 0; diff --git a/firmware/application/io_convert.cpp b/firmware/application/io_convert.cpp index 62507d32d..9eea9465d 100644 --- a/firmware/application/io_convert.cpp +++ b/firmware/application/io_convert.cpp @@ -24,6 +24,7 @@ namespace fs = std::filesystem; static const fs::path c8_ext = u".C8"; +static const fs::path cu8_ext = u".CU8"; namespace file_convert { @@ -59,21 +60,42 @@ void c8_to_c16(const void* buffer, File::Size bytes) { } } +// Convert cu8 buffer to c16 buffer. +// Same buffer used for input & output; input size is bytes; output size is 2*bytes. +void cu8_to_c16(const void* buffer, File::Size bytes) { + complexu8_t* src = (complexu8_t*)buffer; + complex16_t* dest = (complex16_t*)buffer; + uint32_t i = bytes / sizeof(complexu8_t); + + if (i != 0) { + do { + i--; + int16_t re_out = ((int16_t)src[i].real() - 128) * 256; + int16_t im_out = ((int16_t)src[i].imag() - 128) * 256; + dest[i] = {(int16_t)re_out, (int16_t)im_out}; + } while (i != 0); + } +} + } /* namespace file_convert */ // Automatically enables C8/C16 conversion based on file extension Optional FileConvertReader::open(const std::filesystem::path& filename) { convert_c8_to_c16 = path_iequal(filename.extension(), c8_ext); + convert_cu8_to_c16 = path_iequal(filename.extension(), cu8_ext); return file_.open(filename); } // If C8 conversion enabled, half the number of bytes are read from the file & expanded to fill the whole buffer. File::Result FileConvertReader::read(void* const buffer, const File::Size bytes) { - auto read_result = file_.read(buffer, convert_c8_to_c16 ? bytes / 2 : bytes); + auto read_result = file_.read(buffer, (convert_c8_to_c16 || convert_cu8_to_c16) ? bytes / 2 : bytes); if (read_result.is_ok()) { if (convert_c8_to_c16) { file_convert::c8_to_c16(buffer, read_result.value()); read_result = read_result.value() * 2; + } else if (convert_cu8_to_c16) { + file_convert::cu8_to_c16(buffer, read_result.value()); + read_result = read_result.value() * 2; } bytes_read_ += read_result.value(); } diff --git a/firmware/application/io_convert.hpp b/firmware/application/io_convert.hpp index 0455444f3..20565880a 100644 --- a/firmware/application/io_convert.hpp +++ b/firmware/application/io_convert.hpp @@ -52,6 +52,7 @@ class FileConvertReader : public stream::Reader { const File& file() const& { return file_; } bool convert_c8_to_c16{}; + bool convert_cu8_to_c16{}; protected: File file_{}; diff --git a/firmware/common/complex.hpp b/firmware/common/complex.hpp index b8f184e3a..df9a1ec59 100644 --- a/firmware/common/complex.hpp +++ b/firmware/common/complex.hpp @@ -106,10 +106,12 @@ struct complex { } /* namespace std */ using complex8_t = std::complex; +using complexu8_t = std::complex; using complex16_t = std::complex; using complex32_t = std::complex; static_assert(sizeof(complex8_t) == 2, "complex8_t size wrong"); +static_assert(sizeof(complexu8_t) == 2, "complexu8_t size wrong"); static_assert(sizeof(complex16_t) == 4, "complex16_t size wrong"); static_assert(sizeof(complex32_t) == 8, "complex32_t size wrong");