From c7a0bc45634688eccca6c41856fb40ec6c73099c Mon Sep 17 00:00:00 2001 From: Patrick Kappl Date: Sat, 29 Oct 2022 21:11:02 +0200 Subject: [PATCH 01/10] Implement "empty" functions required by littlefs --- CMakeLists.txt | 2 + Sts1CobcSw/CMakeLists.txt | 1 + Sts1CobcSw/FileSystem/CMakeLists.txt | 4 + Sts1CobcSw/FileSystem/FileSystem.cpp | 105 +++++++++++++++++++++++++++ Sts1CobcSw/FileSystem/FileSystem.hpp | 6 ++ Sts1CobcSw/Periphery/Flash.hpp | 12 ++- 6 files changed, 126 insertions(+), 4 deletions(-) create mode 100644 Sts1CobcSw/FileSystem/CMakeLists.txt create mode 100644 Sts1CobcSw/FileSystem/FileSystem.cpp create mode 100644 Sts1CobcSw/FileSystem/FileSystem.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f4bdce5..45fc0f9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,7 @@ include(cmake/custom-commands.cmake) find_package_and_notify(etl) find_package_and_notify(type_safe) +find_package_and_notify(littlefs) find_rodos() # ---- Declare targets ---- @@ -28,6 +29,7 @@ add_library(Sts1CobcSw_Utility OBJECT) add_program(HelloDummy) if(CMAKE_SYSTEM_NAME STREQUAL Generic) + add_library(Sts1CobcSw_FileSystem OBJECT) add_library(Sts1CobcSw_Hal INTERFACE) add_library(Sts1CobcSw_Periphery OBJECT) add_program(CobcSw) diff --git a/Sts1CobcSw/CMakeLists.txt b/Sts1CobcSw/CMakeLists.txt index fde570ba..ea27f025 100644 --- a/Sts1CobcSw/CMakeLists.txt +++ b/Sts1CobcSw/CMakeLists.txt @@ -1,4 +1,5 @@ if(CMAKE_SYSTEM_NAME STREQUAL Generic) + add_subdirectory(FileSystem) add_subdirectory(Hal) add_subdirectory(Periphery) endif() diff --git a/Sts1CobcSw/FileSystem/CMakeLists.txt b/Sts1CobcSw/FileSystem/CMakeLists.txt new file mode 100644 index 00000000..1bfd3d1b --- /dev/null +++ b/Sts1CobcSw/FileSystem/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(Sts1CobcSw_FileSystem PRIVATE FileSystem.cpp) +target_link_libraries( + Sts1CobcSw_FileSystem PRIVATE littlefs::littlefs Sts1CobcSw_Periphery Sts1CobcSw_Serial +) diff --git a/Sts1CobcSw/FileSystem/FileSystem.cpp b/Sts1CobcSw/FileSystem/FileSystem.cpp new file mode 100644 index 00000000..6dd2da1c --- /dev/null +++ b/Sts1CobcSw/FileSystem/FileSystem.cpp @@ -0,0 +1,105 @@ +#include +#include +#include + +#include + +#include + + +namespace sts1cobcsw::fs +{ +using periphery::flash::pageSize; +using RODOS::PRINTF; + + +// --- Private function declarations + +auto Read(lfs_config const * config, + lfs_block_t blockNo, + lfs_off_t offset, + void * buffer, + lfs_size_t size) -> int; +auto Program(lfs_config const * config, + lfs_block_t blockNo, + lfs_off_t offset, + void const * buffer, + lfs_size_t size) -> int; +auto Erase(lfs_config const * config, lfs_block_t blockNo) -> int; +auto Sync(lfs_config const * config) -> int; + + +// --- Globals --- + +auto readBuffer = std::array{}; +auto programBuffer = std::array{}; +auto lookaheadBuffer = std::array{}; + +// TODO: Check if they need to be global +lfs_t lfs{}; +lfs_file_t lfsFile{}; +const lfs_config lfsConfig{.read = &Read, + .prog = &Program, + .erase = &Erase, + .sync = &Sync, + + .read_size = pageSize, + .prog_size = pageSize, + .block_size = periphery::flash::sectorSize, + .block_count = periphery::flash::nSectors, + .block_cycles = 500, + .cache_size = pageSize, + .lookahead_size = pageSize, + + .read_buffer = data(readBuffer), + .prog_buffer = data(programBuffer), + .lookahead_buffer = data(lookaheadBuffer)}; + + +// --- Public function definitions + + +// --- Private function definitions + +auto Read(lfs_config const * config, + lfs_block_t blockNo, + lfs_off_t offset, + void * buffer, + lfs_size_t size) -> int +{ + PRINTF("Read(blockNo=%d, offset=%d, size=%d)\n", + static_cast(blockNo), + static_cast(offset), + static_cast(size)); + + return 0; +} + + +auto Program(lfs_config const * config, + lfs_block_t blockNo, + lfs_off_t offset, + void const * buffer, + lfs_size_t size) -> int +{ + PRINTF("Program(blockNo=%d, offset=%d, size=%d)\n", + static_cast(blockNo), + static_cast(offset), + static_cast(size)); + return 0; +} + + +auto Erase(lfs_config const * config, lfs_block_t blockNo) -> int +{ + PRINTF("Erase(blockNo=%d)\n", static_cast(blockNo)); + return 0; +} + + +auto Sync(lfs_config const * config) -> int +{ + PRINTF("Sync()\n"); + return 0; +} +} \ No newline at end of file diff --git a/Sts1CobcSw/FileSystem/FileSystem.hpp b/Sts1CobcSw/FileSystem/FileSystem.hpp new file mode 100644 index 00000000..5ed5d15a --- /dev/null +++ b/Sts1CobcSw/FileSystem/FileSystem.hpp @@ -0,0 +1,6 @@ +#pragma once + + +namespace sts1cobcsw::fs +{ +} \ No newline at end of file diff --git a/Sts1CobcSw/Periphery/Flash.hpp b/Sts1CobcSw/Periphery/Flash.hpp index a7ffd847..d5207ab0 100644 --- a/Sts1CobcSw/Periphery/Flash.hpp +++ b/Sts1CobcSw/Periphery/Flash.hpp @@ -10,10 +10,14 @@ namespace sts1cobcsw::periphery::flash { -[[maybe_unused]] constexpr std::size_t pageSize = 256; // bytes -[[maybe_unused]] constexpr std::size_t sectorSize = 4 * 1024; // bytes -[[maybe_unused]] constexpr std::size_t smallBlockSize = 32 * 1024; // bytes -[[maybe_unused]] constexpr std::size_t largeBlockSize = 64 * 1024; // bytes +[[maybe_unused]] constexpr std::size_t pageSize = 256; // bytes +[[maybe_unused]] constexpr std::size_t sectorSize = 4 * 1024; // bytes +[[maybe_unused]] constexpr std::size_t smallBlockSize = 32 * 1024; // bytes +[[maybe_unused]] constexpr std::size_t largeBlockSize = 64 * 1024; // bytes +[[maybe_unused]] constexpr std::size_t flashSize = 128 * 1024 * 1024; // bytes +[[maybe_unused]] constexpr std::size_t nSectors = flashSize / sectorSize; +[[maybe_unused]] constexpr std::size_t nSmallBlocks = flashSize / smallBlockSize; +[[maybe_unused]] constexpr std::size_t nLargeBlocks = flashSize / largeBlockSize; using serial::Byte; From 20828c175a7a2efe9f82bf89b86d0a1dfce4e767 Mon Sep 17 00:00:00 2001 From: Patrick Kappl Date: Sat, 29 Oct 2022 21:12:37 +0200 Subject: [PATCH 02/10] Implement and test fs::Mount() and fs::Unmount() --- Sts1CobcSw/FileSystem/FileSystem.cpp | 31 ++++++++++++++++++++++ Sts1CobcSw/FileSystem/FileSystem.hpp | 2 ++ Tests/HardwareTests/CMakeLists.txt | 5 ++++ Tests/HardwareTests/FileSystem.test.cpp | 35 +++++++++++++++++++++++++ 4 files changed, 73 insertions(+) create mode 100644 Tests/HardwareTests/FileSystem.test.cpp diff --git a/Sts1CobcSw/FileSystem/FileSystem.cpp b/Sts1CobcSw/FileSystem/FileSystem.cpp index 6dd2da1c..08b723e8 100644 --- a/Sts1CobcSw/FileSystem/FileSystem.cpp +++ b/Sts1CobcSw/FileSystem/FileSystem.cpp @@ -2,6 +2,8 @@ #include #include +#include + #include #include @@ -58,6 +60,35 @@ const lfs_config lfsConfig{.read = &Read, // --- Public function definitions +auto Mount() -> void +{ + PRINTF("Mounting...\n"); + int errorCode = lfs_mount(&lfs, &lfsConfig); + PRINTF("Returned error code = %d\n\n", errorCode); + + // reformat if we can't mount the filesystem + // this should only happen on the first boot + if(errorCode != 0) + { + PRINTF("Formatting...\n"); + errorCode = lfs_format(&lfs, &lfsConfig); + PRINTF("Returned error code = %d\n\n", errorCode); + + PRINTF("Mounting...\n"); + errorCode = lfs_mount(&lfs, &lfsConfig); + PRINTF("Returned error code = %d\n\n", errorCode); + } +} + + +// TODO: This begs for a destructor +auto Unmount() -> void +{ + PRINTF("Mounting...\n"); + auto errorCode = lfs_unmount(&lfs); + PRINTF("Returned error code = %d\n\n", errorCode); +} + // --- Private function definitions diff --git a/Sts1CobcSw/FileSystem/FileSystem.hpp b/Sts1CobcSw/FileSystem/FileSystem.hpp index 5ed5d15a..803f9b6c 100644 --- a/Sts1CobcSw/FileSystem/FileSystem.hpp +++ b/Sts1CobcSw/FileSystem/FileSystem.hpp @@ -3,4 +3,6 @@ namespace sts1cobcsw::fs { +auto Mount() -> void; +auto Unmount() -> void; } \ No newline at end of file diff --git a/Tests/HardwareTests/CMakeLists.txt b/Tests/HardwareTests/CMakeLists.txt index 1d908936..b972f1e1 100644 --- a/Tests/HardwareTests/CMakeLists.txt +++ b/Tests/HardwareTests/CMakeLists.txt @@ -3,6 +3,11 @@ add_subdirectory(EduCommandTests) add_program(Crc32 Crc32.test.cpp) target_link_libraries(Sts1CobcSwTests_Crc32 PRIVATE rodos::rodos) +add_program(FileSystem FileSystem.test.cpp) +target_link_libraries( + Sts1CobcSwTests_FileSystem PRIVATE rodos::rodos Sts1CobcSw_FileSystem littlefs::littlefs +) + add_program(Flash Flash.test.cpp) target_link_libraries( Sts1CobcSwTests_Flash PRIVATE rodos::rodos Sts1CobcSw_Periphery Sts1CobcSw_Serial diff --git a/Tests/HardwareTests/FileSystem.test.cpp b/Tests/HardwareTests/FileSystem.test.cpp new file mode 100644 index 00000000..f374b05e --- /dev/null +++ b/Tests/HardwareTests/FileSystem.test.cpp @@ -0,0 +1,35 @@ +#include + +#include + +#include + + +namespace sts1cobcsw +{ +using RODOS::PRINTF; + + +constexpr std::size_t stackSize = 5'000; + + +class FileSystemTest : public RODOS::StaticThread +{ +public: + FileSystemTest() : StaticThread("FileSystemTest") + { + } + +private: + void init() override + { + fs::Mount(); + } + + + void run() override + { + fs::Unmount(); + } +} fileSystemTest; +} From 7ac4a2fe8d4f802287076708bd473516219be751 Mon Sep 17 00:00:00 2001 From: Patrick Kappl Date: Sun, 30 Oct 2022 00:07:41 +0200 Subject: [PATCH 03/10] Fully implement littlefs functions and do some tests --- Sts1CobcSw/FileSystem/CMakeLists.txt | 5 ++-- Sts1CobcSw/FileSystem/FileSystem.cpp | 40 +++++++++++++++++++++---- Sts1CobcSw/FileSystem/FileSystem.hpp | 8 +++++ Sts1CobcSw/Periphery/Flash.cpp | 4 ++- Tests/HardwareTests/CMakeLists.txt | 3 +- Tests/HardwareTests/FileSystem.test.cpp | 24 ++++++++++++++- Tests/HardwareTests/Flash.test.cpp | 2 +- 7 files changed, 74 insertions(+), 12 deletions(-) diff --git a/Sts1CobcSw/FileSystem/CMakeLists.txt b/Sts1CobcSw/FileSystem/CMakeLists.txt index 1bfd3d1b..bff97963 100644 --- a/Sts1CobcSw/FileSystem/CMakeLists.txt +++ b/Sts1CobcSw/FileSystem/CMakeLists.txt @@ -1,4 +1,3 @@ target_sources(Sts1CobcSw_FileSystem PRIVATE FileSystem.cpp) -target_link_libraries( - Sts1CobcSw_FileSystem PRIVATE littlefs::littlefs Sts1CobcSw_Periphery Sts1CobcSw_Serial -) +target_link_libraries(Sts1CobcSw_FileSystem PUBLIC littlefs::littlefs) +target_link_libraries(Sts1CobcSw_FileSystem PRIVATE Sts1CobcSw_Periphery Sts1CobcSw_Serial) diff --git a/Sts1CobcSw/FileSystem/FileSystem.cpp b/Sts1CobcSw/FileSystem/FileSystem.cpp index 08b723e8..8295b07b 100644 --- a/Sts1CobcSw/FileSystem/FileSystem.cpp +++ b/Sts1CobcSw/FileSystem/FileSystem.cpp @@ -2,17 +2,18 @@ #include #include -#include - #include +#include #include +#include namespace sts1cobcsw::fs { using periphery::flash::pageSize; using RODOS::PRINTF; +using serial::Byte; // --- Private function declarations @@ -60,6 +61,11 @@ const lfs_config lfsConfig{.read = &Read, // --- Public function definitions +auto Initialize() -> void +{ + [[maybe_unused]] auto errorCode = periphery::flash::Initialize(); +} + auto Mount() -> void { PRINTF("Mounting...\n"); @@ -84,7 +90,7 @@ auto Mount() -> void // TODO: This begs for a destructor auto Unmount() -> void { - PRINTF("Mounting...\n"); + PRINTF("Unmounting...\n"); auto errorCode = lfs_unmount(&lfs); PRINTF("Returned error code = %d\n\n", errorCode); } @@ -102,7 +108,16 @@ auto Read(lfs_config const * config, static_cast(blockNo), static_cast(offset), static_cast(size)); - + + // The following only works if read_size == pageSize + auto startAddress = blockNo * config->block_size + offset; + for(auto i = 0U; i < size; i += config->read_size) + { + auto page = periphery::flash::ReadPage(startAddress + i); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + std::copy(begin(page), end(page), (static_cast(buffer) + i)); + } + return 0; } @@ -117,6 +132,18 @@ auto Program(lfs_config const * config, static_cast(blockNo), static_cast(offset), static_cast(size)); + + // The following only works if prog_size == pageSize + auto startAddress = blockNo * config->block_size + offset; + for(auto i = 0U; i < size; i += config->prog_size) + { + auto page = periphery::flash::Page{}; + std::copy((static_cast(buffer) + i), // NOLINT + (static_cast(buffer) + i + config->prog_size), // NOLINT + begin(page)); + periphery::flash::ProgramPage(startAddress + i, std::span(page)); + periphery::flash::WaitWhileBusy(); + } return 0; } @@ -124,13 +151,16 @@ auto Program(lfs_config const * config, auto Erase(lfs_config const * config, lfs_block_t blockNo) -> int { PRINTF("Erase(blockNo=%d)\n", static_cast(blockNo)); + periphery::flash::EraseSector(blockNo * config->block_size); + periphery::flash::WaitWhileBusy(); return 0; } -auto Sync(lfs_config const * config) -> int +auto Sync([[maybe_unused]] lfs_config const * config) -> int { PRINTF("Sync()\n"); + periphery::flash::WaitWhileBusy(); return 0; } } \ No newline at end of file diff --git a/Sts1CobcSw/FileSystem/FileSystem.hpp b/Sts1CobcSw/FileSystem/FileSystem.hpp index 803f9b6c..b71374e5 100644 --- a/Sts1CobcSw/FileSystem/FileSystem.hpp +++ b/Sts1CobcSw/FileSystem/FileSystem.hpp @@ -1,8 +1,16 @@ #pragma once +#include + + namespace sts1cobcsw::fs { +extern lfs_t lfs; +extern lfs_file_t lfsFile; +extern const lfs_config lfsConfig; + +auto Initialize() -> void; auto Mount() -> void; auto Unmount() -> void; } \ No newline at end of file diff --git a/Sts1CobcSw/Periphery/Flash.cpp b/Sts1CobcSw/Periphery/Flash.cpp index 77c515a0..9eadf8d9 100644 --- a/Sts1CobcSw/Periphery/Flash.cpp +++ b/Sts1CobcSw/Periphery/Flash.cpp @@ -91,9 +91,11 @@ auto DeserializeFrom(Byte * source, JedecId * jedecId) -> Byte *; writeProtectionGpioPin.Set(); constexpr auto baudrate = 1'000'000; - return spi.init(baudrate, /*slave=*/false, /*tiMode=*/false); + auto errorCode = spi.init(baudrate, /*slave=*/false, /*tiMode=*/false); periphery::flash::Enter4ByteAdressMode(); + + return errorCode; } diff --git a/Tests/HardwareTests/CMakeLists.txt b/Tests/HardwareTests/CMakeLists.txt index b972f1e1..6b85d3b9 100644 --- a/Tests/HardwareTests/CMakeLists.txt +++ b/Tests/HardwareTests/CMakeLists.txt @@ -5,7 +5,8 @@ target_link_libraries(Sts1CobcSwTests_Crc32 PRIVATE rodos::rodos) add_program(FileSystem FileSystem.test.cpp) target_link_libraries( - Sts1CobcSwTests_FileSystem PRIVATE rodos::rodos Sts1CobcSw_FileSystem littlefs::littlefs + Sts1CobcSwTests_FileSystem PRIVATE rodos::rodos littlefs::littlefs Sts1CobcSw_FileSystem + Sts1CobcSw_Periphery ) add_program(Flash Flash.test.cpp) diff --git a/Tests/HardwareTests/FileSystem.test.cpp b/Tests/HardwareTests/FileSystem.test.cpp index f374b05e..fa461514 100644 --- a/Tests/HardwareTests/FileSystem.test.cpp +++ b/Tests/HardwareTests/FileSystem.test.cpp @@ -1,7 +1,10 @@ #include +#include + #include +#include #include @@ -23,12 +26,31 @@ class FileSystemTest : public RODOS::StaticThread private: void init() override { - fs::Mount(); + fs::Initialize(); } void run() override { + fs::Mount(); + + lfs_file_open(&fs::lfs, &fs::lfsFile, "MyFile", LFS_O_RDWR | LFS_O_CREAT); + + auto fileSize = lfs_file_size(&fs::lfs, &fs::lfsFile); + PRINTF("\nFile size = %d == 8\n", static_cast(fileSize)); + + int number = 0; + lfs_file_read(&fs::lfs, &fs::lfsFile, &number, sizeof(number)); + PRINTF("\nNumber = %d == 123\n", number); + + lfs_file_read(&fs::lfs, &fs::lfsFile, &number, sizeof(number)); + PRINTF("\nNumber = %d == 12345\n", number); + + // number = 12345; + // lfs_file_write(&fs::lfs, &fs::lfsFile, &number, sizeof(number)); + + lfs_file_close(&fs::lfs, &fs::lfsFile); + fs::Unmount(); } } fileSystemTest; diff --git a/Tests/HardwareTests/Flash.test.cpp b/Tests/HardwareTests/Flash.test.cpp index f79c484f..caa60db7 100644 --- a/Tests/HardwareTests/Flash.test.cpp +++ b/Tests/HardwareTests/Flash.test.cpp @@ -66,7 +66,7 @@ class FlashTest : public RODOS::StaticThread PRINTF("Status Register 3: 0x%02x == 0x41\n", static_cast(statusRegister)); Check(statusRegister == 0x41_b); - std::uint32_t pageAddress = 0x00'00'0C'00; + std::uint32_t pageAddress = 0x00'01'00'00; PRINTF("\n"); PRINTF("Reading page at address 0x%08x:\n", static_cast(pageAddress)); From 3b114252ab1f45e485a2bd5733ad701ac6599e82 Mon Sep 17 00:00:00 2001 From: Patrick Kappl Date: Sun, 30 Oct 2022 00:11:31 +0200 Subject: [PATCH 04/10] Fix spell check --- Tests/HardwareTests/FileSystem.test.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Tests/HardwareTests/FileSystem.test.cpp b/Tests/HardwareTests/FileSystem.test.cpp index fa461514..af4802f8 100644 --- a/Tests/HardwareTests/FileSystem.test.cpp +++ b/Tests/HardwareTests/FileSystem.test.cpp @@ -41,10 +41,12 @@ class FileSystemTest : public RODOS::StaticThread int number = 0; lfs_file_read(&fs::lfs, &fs::lfsFile, &number, sizeof(number)); - PRINTF("\nNumber = %d == 123\n", number); + PRINTF("\n"); + PRINTF("Number = %d == 123\n", number); lfs_file_read(&fs::lfs, &fs::lfsFile, &number, sizeof(number)); - PRINTF("\nNumber = %d == 12345\n", number); + PRINTF("\n"); + PRINTF("Number = %d == 12345\n", number); // number = 12345; // lfs_file_write(&fs::lfs, &fs::lfsFile, &number, sizeof(number)); From 0b20eb6eb922572e19ee6b79be83a2b5940f946e Mon Sep 17 00:00:00 2001 From: Patrick Kappl Date: Sun, 30 Oct 2022 00:18:24 +0200 Subject: [PATCH 05/10] Only find littlefs when building for COBC --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 45fc0f9b..2de4a006 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,8 +18,10 @@ include(cmake/custom-commands.cmake) find_package_and_notify(etl) find_package_and_notify(type_safe) -find_package_and_notify(littlefs) find_rodos() +if(CMAKE_SYSTEM_NAME STREQUAL Generic) + find_package_and_notify(littlefs) +endif() # ---- Declare targets ---- From cdc788c37fcfcd5d3623c00b3d6606dfd0ece893 Mon Sep 17 00:00:00 2001 From: Patrick Kappl Date: Sun, 30 Oct 2022 14:16:58 +0100 Subject: [PATCH 06/10] Write wrappers to open/close, read/write file and get file size --- Sts1CobcSw/FileSystem/FileSystem.cpp | 52 +++++++++++++++++-------- Sts1CobcSw/FileSystem/FileSystem.hpp | 34 +++++++++++++++- Tests/HardwareTests/FileSystem.test.cpp | 19 +++++---- 3 files changed, 80 insertions(+), 25 deletions(-) diff --git a/Sts1CobcSw/FileSystem/FileSystem.cpp b/Sts1CobcSw/FileSystem/FileSystem.cpp index 8295b07b..3e726f61 100644 --- a/Sts1CobcSw/FileSystem/FileSystem.cpp +++ b/Sts1CobcSw/FileSystem/FileSystem.cpp @@ -41,6 +41,8 @@ auto lookaheadBuffer = std::array{}; // TODO: Check if they need to be global lfs_t lfs{}; lfs_file_t lfsFile{}; +// TODO: Maybe add a conifg header to set things like NAME_MAX or whatever. That could safe a bit of +// RAM. const lfs_config lfsConfig{.read = &Read, .prog = &Program, .erase = &Erase, @@ -50,7 +52,7 @@ const lfs_config lfsConfig{.read = &Read, .prog_size = pageSize, .block_size = periphery::flash::sectorSize, .block_count = periphery::flash::nSectors, - .block_cycles = 500, + .block_cycles = 200, .cache_size = pageSize, .lookahead_size = pageSize, @@ -66,33 +68,51 @@ auto Initialize() -> void [[maybe_unused]] auto errorCode = periphery::flash::Initialize(); } -auto Mount() -> void + +auto Format() -> int { - PRINTF("Mounting...\n"); - int errorCode = lfs_mount(&lfs, &lfsConfig); + PRINTF("Formatting...\n"); + auto errorCode = lfs_format(&lfs, &lfsConfig); PRINTF("Returned error code = %d\n\n", errorCode); + return errorCode; +} - // reformat if we can't mount the filesystem - // this should only happen on the first boot - if(errorCode != 0) - { - PRINTF("Formatting...\n"); - errorCode = lfs_format(&lfs, &lfsConfig); - PRINTF("Returned error code = %d\n\n", errorCode); - PRINTF("Mounting...\n"); - errorCode = lfs_mount(&lfs, &lfsConfig); - PRINTF("Returned error code = %d\n\n", errorCode); - } +auto Mount() -> int +{ + PRINTF("Mounting...\n"); + int errorCode = lfs_mount(&lfs, &lfsConfig); + PRINTF("Returned error code = %d\n\n", errorCode); + return errorCode; } // TODO: This begs for a destructor -auto Unmount() -> void +auto Unmount() -> int { PRINTF("Unmounting...\n"); auto errorCode = lfs_unmount(&lfs); PRINTF("Returned error code = %d\n\n", errorCode); + return errorCode; +} + + +auto OpenFile(char const * path, int flags) -> int +{ + return lfs_file_open(&lfs, &lfsFile, path, flags); +} + + +auto CloseFile() -> int +{ + return lfs_file_close(&lfs, &lfsFile); +} + + +// Return the size of the currently open file +auto FileSize() -> int +{ + return lfs_file_size(&lfs, &lfsFile); } diff --git a/Sts1CobcSw/FileSystem/FileSystem.hpp b/Sts1CobcSw/FileSystem/FileSystem.hpp index b71374e5..644a1358 100644 --- a/Sts1CobcSw/FileSystem/FileSystem.hpp +++ b/Sts1CobcSw/FileSystem/FileSystem.hpp @@ -10,7 +10,37 @@ extern lfs_t lfs; extern lfs_file_t lfsFile; extern const lfs_config lfsConfig; +// Must be called once in a thread's init() function auto Initialize() -> void; -auto Mount() -> void; -auto Unmount() -> void; +auto Format() -> int; +auto Mount() -> int; +auto Unmount() -> int; + +auto OpenFile(char const * path, int flags) -> int; +auto CloseFile() -> int; +auto FileSize() -> int; + +template +auto ReadFromFile(T * t) -> int; + +template +auto WriteToFile(T const & t) -> int; + +// TODO: Implement ls + + +// --- Function template definitions --- + +template +inline auto ReadFromFile(T * t) -> int +{ + return lfs_file_read(&lfs, &lfsFile, t, sizeof(T)); +} + + +template +inline auto WriteToFile(T const & t) -> int +{ + return lfs_file_write(&lfs, &lfsFile, &t, sizeof(T)); +} } \ No newline at end of file diff --git a/Tests/HardwareTests/FileSystem.test.cpp b/Tests/HardwareTests/FileSystem.test.cpp index af4802f8..39e97cdc 100644 --- a/Tests/HardwareTests/FileSystem.test.cpp +++ b/Tests/HardwareTests/FileSystem.test.cpp @@ -34,24 +34,29 @@ class FileSystemTest : public RODOS::StaticThread { fs::Mount(); - lfs_file_open(&fs::lfs, &fs::lfsFile, "MyFile", LFS_O_RDWR | LFS_O_CREAT); + fs::OpenFile("MyFile", LFS_O_RDWR | LFS_O_CREAT); - auto fileSize = lfs_file_size(&fs::lfs, &fs::lfsFile); - PRINTF("\nFile size = %d == 8\n", static_cast(fileSize)); + auto fileSize = fs::FileSize(); + PRINTF("\nFile size = %d == 12\n", fileSize); int number = 0; - lfs_file_read(&fs::lfs, &fs::lfsFile, &number, sizeof(number)); + fs::ReadFromFile(&number); PRINTF("\n"); PRINTF("Number = %d == 123\n", number); - lfs_file_read(&fs::lfs, &fs::lfsFile, &number, sizeof(number)); + fs::ReadFromFile(&number); PRINTF("\n"); PRINTF("Number = %d == 12345\n", number); - // number = 12345; + fs::ReadFromFile(&number); + PRINTF("\n"); + PRINTF("Number = %d == 1234567\n", number); + + // number = 1234567; + // fs::WriteToFile(number); // lfs_file_write(&fs::lfs, &fs::lfsFile, &number, sizeof(number)); - lfs_file_close(&fs::lfs, &fs::lfsFile); + fs::CloseFile(); fs::Unmount(); } From 1979660acb4d9aaf3dd1fc29a98070a922091aee Mon Sep 17 00:00:00 2001 From: Patrick Kappl Date: Sun, 30 Oct 2022 16:39:35 +0100 Subject: [PATCH 07/10] Implement and test fs::Ls() Ls as in the shell command to list information about the files in a directory. --- Sts1CobcSw/FileSystem/FileSystem.cpp | 51 +++++++++++++++++++++++++ Sts1CobcSw/FileSystem/FileSystem.hpp | 6 +-- Tests/HardwareTests/FileSystem.test.cpp | 2 + 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/Sts1CobcSw/FileSystem/FileSystem.cpp b/Sts1CobcSw/FileSystem/FileSystem.cpp index 3e726f61..0c094712 100644 --- a/Sts1CobcSw/FileSystem/FileSystem.cpp +++ b/Sts1CobcSw/FileSystem/FileSystem.cpp @@ -116,6 +116,57 @@ auto FileSize() -> int } +//! @brief List information (type, size, name) about the files under the given path. +auto Ls(char const * path) -> int +{ + auto directory = lfs_dir_t{}; + int errorCode = lfs_dir_open(&lfs, &directory, path); + if(errorCode != 0) + { + return errorCode; + } + + auto info = lfs_info{}; + while(true) + { + int result = lfs_dir_read(&lfs, &directory, &info); + if(result < 0) + { + // An error occured + return result; + } + if(result == 0) + { + // We are at the end of the directory + break; + } + + switch(info.type) + { + case LFS_TYPE_REG: + { + PRINTF("reg "); + break; + } + case LFS_TYPE_DIR: + { + PRINTF("dir "); + break; + } + default: + { + PRINTF("? "); + break; + } + } + + PRINTF(" %8d B %s\n", static_cast(info.size), &(info.name[0])); + } + + return lfs_dir_close(&lfs, &directory); +} + + // --- Private function definitions auto Read(lfs_config const * config, diff --git a/Sts1CobcSw/FileSystem/FileSystem.hpp b/Sts1CobcSw/FileSystem/FileSystem.hpp index 644a1358..f646eec9 100644 --- a/Sts1CobcSw/FileSystem/FileSystem.hpp +++ b/Sts1CobcSw/FileSystem/FileSystem.hpp @@ -16,17 +16,17 @@ auto Format() -> int; auto Mount() -> int; auto Unmount() -> int; +// File stuff auto OpenFile(char const * path, int flags) -> int; auto CloseFile() -> int; auto FileSize() -> int; - template auto ReadFromFile(T * t) -> int; - template auto WriteToFile(T const & t) -> int; -// TODO: Implement ls +// Higher level stuff +auto Ls(char const * path) -> int; // --- Function template definitions --- diff --git a/Tests/HardwareTests/FileSystem.test.cpp b/Tests/HardwareTests/FileSystem.test.cpp index 39e97cdc..0c0850a5 100644 --- a/Tests/HardwareTests/FileSystem.test.cpp +++ b/Tests/HardwareTests/FileSystem.test.cpp @@ -58,6 +58,8 @@ class FileSystemTest : public RODOS::StaticThread fs::CloseFile(); + fs::Ls("/"); + fs::Unmount(); } } fileSystemTest; From ec43f9c45676d6aa16ce3af940ed0dfa35041003 Mon Sep 17 00:00:00 2001 From: Patrick Kappl Date: Sun, 30 Oct 2022 17:00:34 +0100 Subject: [PATCH 08/10] Remove debug PRINTF()'s from low-level lfs functions --- Sts1CobcSw/FileSystem/FileSystem.cpp | 40 +++++++------------------ Sts1CobcSw/FileSystem/FileSystem.hpp | 2 ++ Tests/HardwareTests/FileSystem.test.cpp | 14 ++++----- 3 files changed, 19 insertions(+), 37 deletions(-) diff --git a/Sts1CobcSw/FileSystem/FileSystem.cpp b/Sts1CobcSw/FileSystem/FileSystem.cpp index 0c094712..5acd3c74 100644 --- a/Sts1CobcSw/FileSystem/FileSystem.cpp +++ b/Sts1CobcSw/FileSystem/FileSystem.cpp @@ -12,7 +12,6 @@ namespace sts1cobcsw::fs { using periphery::flash::pageSize; -using RODOS::PRINTF; using serial::Byte; @@ -71,29 +70,20 @@ auto Initialize() -> void auto Format() -> int { - PRINTF("Formatting...\n"); - auto errorCode = lfs_format(&lfs, &lfsConfig); - PRINTF("Returned error code = %d\n\n", errorCode); - return errorCode; + return lfs_format(&lfs, &lfsConfig); } auto Mount() -> int { - PRINTF("Mounting...\n"); - int errorCode = lfs_mount(&lfs, &lfsConfig); - PRINTF("Returned error code = %d\n\n", errorCode); - return errorCode; + return lfs_mount(&lfs, &lfsConfig); } // TODO: This begs for a destructor auto Unmount() -> int { - PRINTF("Unmounting...\n"); - auto errorCode = lfs_unmount(&lfs); - PRINTF("Returned error code = %d\n\n", errorCode); - return errorCode; + return lfs_unmount(&lfs); } @@ -119,6 +109,10 @@ auto FileSize() -> int //! @brief List information (type, size, name) about the files under the given path. auto Ls(char const * path) -> int { + using RODOS::PRINTF; + + PRINTF("$ ls %s\n", path); + auto directory = lfs_dir_t{}; int errorCode = lfs_dir_open(&lfs, &directory, path); if(errorCode != 0) @@ -132,7 +126,7 @@ auto Ls(char const * path) -> int int result = lfs_dir_read(&lfs, &directory, &info); if(result < 0) { - // An error occured + // An error occurred return result; } if(result == 0) @@ -145,17 +139,17 @@ auto Ls(char const * path) -> int { case LFS_TYPE_REG: { - PRINTF("reg "); + PRINTF(" reg "); break; } case LFS_TYPE_DIR: { - PRINTF("dir "); + PRINTF(" dir "); break; } default: { - PRINTF("? "); + PRINTF(" ? "); break; } } @@ -175,11 +169,6 @@ auto Read(lfs_config const * config, void * buffer, lfs_size_t size) -> int { - PRINTF("Read(blockNo=%d, offset=%d, size=%d)\n", - static_cast(blockNo), - static_cast(offset), - static_cast(size)); - // The following only works if read_size == pageSize auto startAddress = blockNo * config->block_size + offset; for(auto i = 0U; i < size; i += config->read_size) @@ -199,11 +188,6 @@ auto Program(lfs_config const * config, void const * buffer, lfs_size_t size) -> int { - PRINTF("Program(blockNo=%d, offset=%d, size=%d)\n", - static_cast(blockNo), - static_cast(offset), - static_cast(size)); - // The following only works if prog_size == pageSize auto startAddress = blockNo * config->block_size + offset; for(auto i = 0U; i < size; i += config->prog_size) @@ -221,7 +205,6 @@ auto Program(lfs_config const * config, auto Erase(lfs_config const * config, lfs_block_t blockNo) -> int { - PRINTF("Erase(blockNo=%d)\n", static_cast(blockNo)); periphery::flash::EraseSector(blockNo * config->block_size); periphery::flash::WaitWhileBusy(); return 0; @@ -230,7 +213,6 @@ auto Erase(lfs_config const * config, lfs_block_t blockNo) -> int auto Sync([[maybe_unused]] lfs_config const * config) -> int { - PRINTF("Sync()\n"); periphery::flash::WaitWhileBusy(); return 0; } diff --git a/Sts1CobcSw/FileSystem/FileSystem.hpp b/Sts1CobcSw/FileSystem/FileSystem.hpp index f646eec9..725b7b44 100644 --- a/Sts1CobcSw/FileSystem/FileSystem.hpp +++ b/Sts1CobcSw/FileSystem/FileSystem.hpp @@ -27,6 +27,8 @@ auto WriteToFile(T const & t) -> int; // Higher level stuff auto Ls(char const * path) -> int; +// TODO: Implement cat +// TODO: Implement simple hexdump // --- Function template definitions --- diff --git a/Tests/HardwareTests/FileSystem.test.cpp b/Tests/HardwareTests/FileSystem.test.cpp index 0c0850a5..d944ec5b 100644 --- a/Tests/HardwareTests/FileSystem.test.cpp +++ b/Tests/HardwareTests/FileSystem.test.cpp @@ -34,30 +34,28 @@ class FileSystemTest : public RODOS::StaticThread { fs::Mount(); - fs::OpenFile("MyFile", LFS_O_RDWR | LFS_O_CREAT); + PRINTF("\n"); + auto const * fileName = "MyFile"; + PRINTF("Opening file %s\n", fileName); + fs::OpenFile(fileName, LFS_O_RDWR | LFS_O_CREAT); auto fileSize = fs::FileSize(); - PRINTF("\nFile size = %d == 12\n", fileSize); + PRINTF("File size = %d == 12\n", fileSize); int number = 0; fs::ReadFromFile(&number); - PRINTF("\n"); PRINTF("Number = %d == 123\n", number); - fs::ReadFromFile(&number); - PRINTF("\n"); PRINTF("Number = %d == 12345\n", number); - fs::ReadFromFile(&number); - PRINTF("\n"); PRINTF("Number = %d == 1234567\n", number); // number = 1234567; // fs::WriteToFile(number); - // lfs_file_write(&fs::lfs, &fs::lfsFile, &number, sizeof(number)); fs::CloseFile(); + PRINTF("\n"); fs::Ls("/"); fs::Unmount(); From 715f184d9701956f3b135edc80203bb73f138ff4 Mon Sep 17 00:00:00 2001 From: Patrick Kappl Date: Tue, 8 Nov 2022 21:18:39 +0100 Subject: [PATCH 09/10] Add and test fs::CreateDirectory() and fs::Remove() --- Sts1CobcSw/FileSystem/FileSystem.cpp | 17 ++++++++- Sts1CobcSw/FileSystem/FileSystem.hpp | 6 +++- Sts1CobcSw/Serial/Serial.hpp | 6 ++-- Tests/HardwareTests/FileSystem.test.cpp | 46 ++++++++++++++++++------- 4 files changed, 56 insertions(+), 19 deletions(-) diff --git a/Sts1CobcSw/FileSystem/FileSystem.cpp b/Sts1CobcSw/FileSystem/FileSystem.cpp index 5acd3c74..a5814299 100644 --- a/Sts1CobcSw/FileSystem/FileSystem.cpp +++ b/Sts1CobcSw/FileSystem/FileSystem.cpp @@ -74,6 +74,7 @@ auto Format() -> int } +// Must be called before using the file system auto Mount() -> int { return lfs_mount(&lfs, &lfsConfig); @@ -81,6 +82,7 @@ auto Mount() -> int // TODO: This begs for a destructor +// Must be called to release all the resources of the file system auto Unmount() -> int { return lfs_unmount(&lfs); @@ -99,13 +101,26 @@ auto CloseFile() -> int } -// Return the size of the currently open file +//! @brief Return the size of the currently open file. auto FileSize() -> int { return lfs_file_size(&lfs, &lfsFile); } +auto CreateDirectory(char const * path) -> int +{ + return lfs_mkdir(&lfs, path); +} + + +//! @brief Remove a file or an empty directory. +auto Remove(char const * path) -> int +{ + return lfs_remove(&lfs, path); +} + + //! @brief List information (type, size, name) about the files under the given path. auto Ls(char const * path) -> int { diff --git a/Sts1CobcSw/FileSystem/FileSystem.hpp b/Sts1CobcSw/FileSystem/FileSystem.hpp index 725b7b44..bcf9f6c0 100644 --- a/Sts1CobcSw/FileSystem/FileSystem.hpp +++ b/Sts1CobcSw/FileSystem/FileSystem.hpp @@ -25,7 +25,11 @@ auto ReadFromFile(T * t) -> int; template auto WriteToFile(T const & t) -> int; -// Higher level stuff +// Directory stuff +auto CreateDirectory(char const * path) -> int; + +// Other stuff +auto Remove(char const * path) -> int; auto Ls(char const * path) -> int; // TODO: Implement cat // TODO: Implement simple hexdump diff --git a/Sts1CobcSw/Serial/Serial.hpp b/Sts1CobcSw/Serial/Serial.hpp index 1314046b..16e4c3ab 100644 --- a/Sts1CobcSw/Serial/Serial.hpp +++ b/Sts1CobcSw/Serial/Serial.hpp @@ -54,8 +54,7 @@ template using SerialBuffer = std::array>; -// Function declarations -// --------------------- +// --- Function declarations --- // TODO: Rename data -> t or variable // Must be overloaded for user-defined types to be serializable @@ -81,8 +80,7 @@ template [[nodiscard]] constexpr auto Deserialize(std::span> source) -> T; -// Function template definitions -// ----------------------------- +// --- Function template definitions --- template inline constexpr auto SerializeTo(Byte * destination, T const & data) -> Byte * diff --git a/Tests/HardwareTests/FileSystem.test.cpp b/Tests/HardwareTests/FileSystem.test.cpp index d944ec5b..1ce60e08 100644 --- a/Tests/HardwareTests/FileSystem.test.cpp +++ b/Tests/HardwareTests/FileSystem.test.cpp @@ -32,30 +32,50 @@ class FileSystemTest : public RODOS::StaticThread void run() override { + PRINTF("\n"); + PRINTF("File system test\n"); + fs::Mount(); PRINTF("\n"); - auto const * fileName = "MyFile"; - PRINTF("Opening file %s\n", fileName); - fs::OpenFile(fileName, LFS_O_RDWR | LFS_O_CREAT); + fs::Ls("/"); - auto fileSize = fs::FileSize(); - PRINTF("File size = %d == 12\n", fileSize); + auto const * directoryPath = "MyFolder"; + PRINTF("\n"); + PRINTF("Creating directory '%s' ...\n", directoryPath); + fs::CreateDirectory(directoryPath); + fs::Ls("/"); - int number = 0; - fs::ReadFromFile(&number); - PRINTF("Number = %d == 123\n", number); + auto const * filePath = "MyFolder/MyFile"; + PRINTF("\n"); + PRINTF("Creating file '%s' ...\n", filePath); + fs::OpenFile(filePath, LFS_O_WRONLY | LFS_O_CREAT); + + PRINTF("Writing to file ...\n"); + int number = 123; + fs::WriteToFile(number); + number = 456; + fs::WriteToFile(number); + fs::CloseFile(); + + PRINTF("Reading from file ...\n"); + fs::OpenFile(filePath, LFS_O_RDONLY); fs::ReadFromFile(&number); - PRINTF("Number = %d == 12345\n", number); + PRINTF(" number = %d == 123\n", number); fs::ReadFromFile(&number); - PRINTF("Number = %d == 1234567\n", number); + PRINTF(" number = %d == 456\n", number); + fs::CloseFile(); - // number = 1234567; - // fs::WriteToFile(number); + fs::Ls(directoryPath); - fs::CloseFile(); + PRINTF("\n"); + PRINTF("Deleting file '%s' ...\n", filePath); + fs::Remove(filePath); + fs::Ls(directoryPath); PRINTF("\n"); + PRINTF("Deleting directory '%s' ...\n", directoryPath); + fs::Remove(directoryPath); fs::Ls("/"); fs::Unmount(); From 2ca5161c42553f0cc58eb36df24b985304d47589 Mon Sep 17 00:00:00 2001 From: Patrick Kappl Date: Wed, 9 Nov 2022 22:08:15 +0100 Subject: [PATCH 10/10] Format file system if mounting doesn't work in test --- Tests/HardwareTests/FileSystem.test.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Tests/HardwareTests/FileSystem.test.cpp b/Tests/HardwareTests/FileSystem.test.cpp index 1ce60e08..21907977 100644 --- a/Tests/HardwareTests/FileSystem.test.cpp +++ b/Tests/HardwareTests/FileSystem.test.cpp @@ -35,7 +35,12 @@ class FileSystemTest : public RODOS::StaticThread PRINTF("\n"); PRINTF("File system test\n"); - fs::Mount(); + + auto errorCode = fs::Mount(); + if(errorCode < 0) + { + fs::Format(); + } PRINTF("\n"); fs::Ls("/");