28#include <zephyr/drivers/disk.h>
29#include <zephyr/fs/fs.h>
30#include <zephyr/fs/littlefs.h>
31#include <zephyr/kernel.h>
32#include <zephyr/storage/disk_access.h>
34#include <etl/basic_string.h>
35#include <etl/format_spec.h>
38#include <etl/string.h>
39#include <etl/string_stream.h>
40#include <etl/to_string.h>
50static struct fs_mount_t storage_mnt = {
52 .mnt_point = CONFIG_STORAGE_MNT_POINT,
53 .fs_data = &lfs_storage,
54 .storage_dev = (
void *)CONFIG_DISK_NAME,
55 .flags = FS_MOUNT_FLAG_USE_DISK_ACCESS | FS_MOUNT_FLAG_NO_FORMAT,
59alignas(16)
static uint8_t aligned_buffer[CONFIG_MAX_MTU];
62static etl::queue<etl::string<CONFIG_STORAGE_MAX_PATH_LEN>,
63 CONFIG_STORAGE_MAX_DEPTH>
85 const etl::string<16> emmc_dirpath(CONFIG_STORAGE_MNT_POINT);
86 const uint64_t used_bytes =
du(emmc_dirpath);
87 const uint64_t total_bytes =
88 (
sectors_num() - CONFIG_DISK_START_SECTOR) * 512ULL;
90 return static_cast<float>(used_bytes) /
static_cast<float>(total_bytes);
99 if (m_enabled && m_mounted) {
100 fs_unmount(&storage_mnt);
106 if (m_enabled && mnt && d == lib::emmc::dir::MCU) {
107 int ret = fs_mount(&storage_mnt);
108 if (ret == 0 || ret == -EBUSY) {
142 int rc = fs_mount(&storage_mnt);
149 storage_mnt.flags = storage_mnt.flags & ~FS_MOUNT_FLAG_NO_FORMAT;
150 rc = fs_mount(&storage_mnt);
155 storage_mnt.flags |= FS_MOUNT_FLAG_NO_FORMAT;
159 m_pname.append(storage_mnt.mnt_point);
160 m_pname.append(CONFIG_STORAGE_LOG_MCU_PATH);
165 int rc = fs_unmount(&storage_mnt);
166 disk_access_ioctl(CONFIG_DISK_NAME, DISK_IOCTL_CTRL_DEINIT, NULL);
170 if (rc < 0 && rc != -EINVAL) {
209 set_dir_priv(d,
true);
222 return emmc.get_dir();
255 if (path.size() >= CONFIG_STORAGE_MAX_PATH_LEN) {
261 int rc = fs_mkdir(path.c_str());
262 if (rc < 0 && rc != -EEXIST) {
268storage::rm_priv(
const etl::istring &path)
270 return fs_unlink(path.c_str());
281storage::ready_raw()
const
283 return enabled() && get_dir() == lib::emmc::dir::MCU;
301 if (path.size() > CONFIG_STORAGE_MAX_PATH_LEN) {
305 struct fs_dirent entry;
306 int rc = fs_stat(path.c_str(), &entry);
307 if (rc < 0 || entry.type != FS_DIR_ENTRY_FILE) {
335 if (path.size() >= CONFIG_STORAGE_MAX_PATH_LEN) {
339 static struct fs_dirent entry;
341 int rc = fs_stat(path.c_str(), &entry);
342 if (rc < 0 || entry.type != FS_DIR_ENTRY_DIR) {
346 etl::string_stream stream(m_pname);
348 struct fs_dir_t dirp;
349 fs_dir_t_init(&dirp);
352 rc = fs_opendir(&dirp, path.c_str());
358 rc = fs_readdir(&dirp, &entry);
360 if (rc || entry.name[0] == 0) {
369 stream << path <<
"/" << entry.name;
374 if (entry.type == FS_DIR_ENTRY_FILE) {
380 rc = fs_unlink(path.c_str());
402 if (path.size() >= CONFIG_STORAGE_MAX_PATH_LEN) {
405 struct fs_file_t
file;
409 fs_file_t_init(&
file);
410 rc = fs_open(&
file, path.c_str(), FS_O_CREATE | FS_O_RDWR);
416 fs_seek(&
file, 0, FS_SEEK_END);
417 len = std::min<size_t>(len, CONFIG_MAX_MTU);
418 std::copy_n(b, len, aligned_buffer);
419 rc = fs_write(&
file, aligned_buffer, len);
452 if (path.size() >= CONFIG_STORAGE_MAX_PATH_LEN) {
457 uint64_t curr_size =
du(path);
458 const off_t new_size =
459 (curr_size > len) ?
static_cast<off_t
>(curr_size - len) : 0;
462 struct fs_file_t
file;
465 fs_file_t_init(&
file);
466 rc = fs_open(&
file, path.c_str(), FS_O_RDWR);
473 rc = fs_truncate(&
file, new_size);
509 if (path.size() >= CONFIG_STORAGE_MAX_PATH_LEN) {
512 struct fs_file_t
file;
516 fs_file_t_init(&
file);
517 rc = fs_open(&
file, path.c_str(), FS_O_CREATE | FS_O_RDWR);
526 fs_seek(&
file, 0, FS_SEEK_END);
529 len = std::min<size_t>(len, CONFIG_MAX_MTU);
530 std::copy_n(b, len, aligned_buffer);
531 rc = fs_write(&
file, aligned_buffer, len);
568 if (path.size() >= CONFIG_STORAGE_MAX_PATH_LEN) {
575 struct fs_dirent entry;
578 int rc = fs_stat(path.c_str(), &entry);
582 if (entry.type == FS_DIR_ENTRY_FILE) {
587 m_dfs_dirs.push(path);
589 while (!m_dfs_dirs.empty()) {
595 auto ¤t = m_dfs_dirs.front();
598 while (
ls(dir, entry)) {
599 if (entry.type == FS_DIR_ENTRY_FILE) {
601 }
else if (entry.type == FS_DIR_ENTRY_DIR && m_dfs_dirs.full() ==
false) {
602 m_dfs_dirs.push(current);
603 auto &new_dir = m_dfs_dirs.back();
605 new_dir += entry.name;
630 struct fs_dirent entry;
632 etl::string_stream stream(m_pname);
637 more =
ls(dir, entry);
640 if (entry.type == FS_DIR_ENTRY_DIR) {
641 stream << path.c_str() <<
"/" << entry.name <<
"/"
644 stream << path.c_str() <<
"/" << entry.name <<
"\n";
675 int rc = fs_readdir(&dir.m_dir, &entry);
676 if (rc || entry.name[0] == 0) {
694 struct fs_dirent entry;
695 int rc = fs_stat(path.c_str(), &entry);
699 return entry.type == FS_DIR_ENTRY_FILE;
750 fs_seek(&f.m_file,
offset, FS_SEEK_SET);
751 len = std::min<size_t>(len, CONFIG_MAX_MTU);
752 ssize_t ret = fs_read(&f.m_file, aligned_buffer, len);
756 std::copy_n(aligned_buffer, ret, b);
773 len = std::min<size_t>(len, CONFIG_MAX_MTU);
774 ssize_t ret = fs_read(&f.m_file, aligned_buffer, len);
778 std::copy_n(aligned_buffer, ret, b);
811 if (start_sector + sectors + (remainder ? 1 : 0) >=
812 CONFIG_DISK_START_SECTOR) {
816 for (
size_t i = 0; i < sectors; i++) {
819 int ret = disk_access_write(CONFIG_STM32_SDMMC_DEFAULT_DISK_NAME,
820 aligned_buffer, start_sector + i, 1);
828 int ret = disk_access_read(CONFIG_STM32_SDMMC_DEFAULT_DISK_NAME,
829 aligned_buffer, start_sector + sectors, 1);
836 std::copy_n(b + sectors *
SECTOR_SIZE, remainder, aligned_buffer);
837 ret = disk_access_write(CONFIG_STM32_SDMMC_DEFAULT_DISK_NAME,
838 aligned_buffer, start_sector + sectors, 1);
862 for (
size_t i = 0; i < sectors; i++) {
863 int ret = disk_access_read(CONFIG_STM32_SDMMC_DEFAULT_DISK_NAME,
864 aligned_buffer, start_sector + i, 1);
893 std::fill_n(aligned_buffer, 512, 0xFF);
894 for (
size_t i = start_sector; i < start_sector + sectors; i++) {
895 disk_access_write(CONFIG_STM32_SDMMC_DEFAULT_DISK_NAME, aligned_buffer, i,
909 int ret = disk_access_ioctl(CONFIG_STM32_SDMMC_DEFAULT_DISK_NAME,
910 DISK_IOCTL_GET_SECTOR_COUNT, &cnt);
static board & get_instance()
Gets a reference to the single instance of the Board interface class.
Implements a scoped lock utilizing the Zephyr mutex.
size_t read(const etl::istring &path, uint8_t *b, size_t len, size_t offset)
Reads from a file starting from specific offset.
void ls(const etl::istring &path, etl::istring &res)
Lists the contents of a directory.
void truncate(const etl::istring &path, size_t len)
Truncate a file by removing bytes from its end.
uint64_t du(const etl::istring &path)
Calculate the disk usage of a file or directory likewise the 'du' command of Linux.
size_t read_raw(uint8_t *b, size_t start_sector, size_t sectors)
Reads directly raw sectors from the eMMC, bypassing any filesystem.
bool enabled() const
Checks if the storage subsystem is enabled.
void rmdir(const etl::istring &path)
Removes a directory and all its contents.
float utilization()
Get eMMC storage utilization of the partition used by the MCU.
void mkdir(const etl::istring &path)
Creates a directory at the specified path.
bool ready() const
Checks if the storage subsystem is ready to accept filesystem operations for the MCU side.
size_t write_raw(const uint8_t *b, size_t start_sector, size_t len)
Writes raw bytes on the eMMC.
lib::emmc::dir get_dir() const
Get the direction of the eMMC.
size_t write(const etl::istring &path, const uint8_t *b, size_t len)
Writes data to a file.
size_t sectors_num() const
Returns the number of total sectors of the eMMC.
void erase_sectors(size_t start_sector, size_t sectors)
Erase a specific number of sectors.
void enable(bool en)
Enable or disable the storage subsystem.
bool is_file(const etl::istring &path)
Check if a path is a file.
bool mounted() const
Checks if the storage subsystem is mounted.
void rm(const etl::istring &path)
Removes a file from the filesystem.
bool is_dir(const etl::istring &path)
Check if a path is a directory.
static constexpr size_t SECTOR_SIZE
void set_dir(lib::emmc::dir d)
Set the direction of the eMMC.
storage(storage const &)=delete
FS_LITTLEFS_DECLARE_CUSTOM_CONFIG(lfs_storage, storage::SECTOR_SIZE, storage::SECTOR_SIZE, storage::SECTOR_SIZE, storage::SECTOR_SIZE, 4 *storage::SECTOR_SIZE)