vor ble umbau

This commit is contained in:
2026-03-12 07:07:00 +01:00
parent 96aed70fc6
commit 5bb0d345da
45 changed files with 3681 additions and 48 deletions

View File

@@ -0,0 +1,373 @@
#include <zephyr/fs/littlefs.h>
#include <zephyr/fs/fs.h>
#include <zephyr/logging/log.h>
#include <zephyr/pm/device.h>
#include "fs_mgmt.h"
LOG_MODULE_REGISTER(fs_mgmt, CONFIG_FS_MGMT_LOG_LEVEL);
#define FS_PARTITION_ID FLASH_AREA_ID(littlefs_storage)
FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(fs_storage_data);
#define QSPI_FLASH_NODE DT_ALIAS(qspi_flash)
static const struct device *flash_dev = DEVICE_DT_GET(QSPI_FLASH_NODE);
static struct fs_mount_t fs_storage_mnt = {
.type = FS_LITTLEFS,
.fs_data = &fs_storage_data,
.storage_dev = (void *)FS_PARTITION_ID,
.mnt_point = CONFIG_FS_MGMT_MOUNT_POINT,
};
static int open_count = 0;
static struct k_mutex flash_pm_lock;
/**
* @brief Puts the QSPI flash into deep sleep mode to save power
* Decrements the open count and suspends the flash if no more users are active
* @return 0 on success, negative error code on failure
*/
static int fs_mgmt_pm_flash_suspend(void)
{
#if IS_ENABLED(CONFIG_PM_DEVICE)
if (!device_is_ready(flash_dev))
{
return -ENODEV;
}
k_mutex_lock(&flash_pm_lock, K_FOREVER);
if (open_count > 0)
{
open_count--;
if (open_count == 0)
{
int rc = pm_device_action_run(flash_dev, PM_DEVICE_ACTION_SUSPEND);
if (rc < 0)
{
LOG_WRN("Could not suspend flash: %d", rc);
}
else
{
LOG_DBG("Flash entered deep power-down");
}
}
}
k_mutex_unlock(&flash_pm_lock);
#endif /* CONFIG_PM_DEVICE */
return 0;
}
/**
* @brief Resumes the QSPI flash from deep sleep mode
* Increments the open count and resumes the flash if it was previously suspended
* @return 0 on success, negative error code on failure
*/
static int fs_mgmt_pm_flash_resume(void)
{
#if IS_ENABLED(CONFIG_PM_DEVICE)
if (!device_is_ready(flash_dev))
return -ENODEV;
k_mutex_lock(&flash_pm_lock, K_FOREVER);
if (open_count == 0)
{
int rc = pm_device_action_run(flash_dev, PM_DEVICE_ACTION_RESUME);
if (rc == 0)
{
k_busy_wait(50); // t-exit-dpd
LOG_DBG("Flash resumed");
}
}
open_count++;
k_mutex_unlock(&flash_pm_lock);
#endif /* CONFIG_PM_DEVICE */
return 0;
}
int fs_mgmt_pm_open(struct fs_file_t *file, const char *path, fs_mode_t mode)
{
LOG_DBG("PM Opening file '%s' with mode 0x%02x", path, mode);
fs_mgmt_pm_flash_resume();
int rc = fs_open(file, path, mode);
if (rc < 0)
{
fs_mgmt_pm_flash_suspend();
}
return rc;
}
int fs_mgmt_pm_close(struct fs_file_t *file)
{
LOG_DBG("PM Closing file");
int rc = fs_close(file);
fs_mgmt_pm_flash_suspend();
return rc;
}
int fs_mgmt_pm_opendir(struct fs_dir_t *dirp, const char *path)
{
LOG_DBG("PM Opening directory '%s'", path);
fs_mgmt_pm_flash_resume();
int rc = fs_opendir(dirp, path);
if (rc < 0)
{
fs_mgmt_pm_flash_suspend();
}
return rc;
}
int fs_mgmt_pm_closedir(struct fs_dir_t *dirp)
{
LOG_DBG("PM Closing directory");
int rc = fs_closedir(dirp);
fs_mgmt_pm_flash_suspend();
return rc;
}
int fs_mgmt_pm_unlink(const char *path)
{
LOG_DBG("PM Unlinking file '%s'", path);
fs_mgmt_pm_flash_resume();
int rc = fs_unlink(path);
fs_mgmt_pm_flash_suspend();
return rc;
}
int fs_mgmt_pm_statvfs(const char *path, struct fs_statvfs *stat)
{
LOG_DBG("PM Getting filesystem stats for '%s'", path);
fs_mgmt_pm_flash_resume();
int rc = fs_statvfs(path, stat);
fs_mgmt_pm_flash_suspend();
return rc;
}
int fs_mgmt_pm_stat(const char *path, struct fs_dirent *entry)
{
LOG_DBG("PM Getting stat for '%s'", path);
fs_mgmt_pm_flash_resume();
int rc = fs_stat(path, entry);
fs_mgmt_pm_flash_suspend();
return rc;
}
int fs_mgmt_pm_mkdir(const char *path)
{
LOG_DBG("PM Creating directory '%s'", path);
fs_mgmt_pm_flash_resume();
int rc = fs_mkdir(path);
fs_mgmt_pm_flash_suspend();
return rc;
}
int fs_mgmt_pm_rename(const char *old_path, const char *new_path)
{
LOG_DBG("PM Renaming '%s' to '%s'", old_path, new_path);
fs_mgmt_pm_flash_resume();
int rc = fs_rename(old_path, new_path);
fs_mgmt_pm_flash_suspend();
return rc;
}
int fs_mgmt_pm_rm_recursive(char *path_buf, size_t max_len)
{
struct fs_dirent entry;
struct fs_dir_t dir;
int rc;
fs_mgmt_pm_flash_resume();
/* 1. Stat prüfen: Ist es eine Datei? */
rc = fs_stat(path_buf, &entry);
if (rc != 0)
{
fs_mgmt_pm_flash_suspend();
return rc;
}
/* Wenn es eine Datei ist, direkt löschen und beenden */
if (entry.type == FS_DIR_ENTRY_FILE)
{
rc = fs_unlink(path_buf);
fs_mgmt_pm_flash_suspend();
return rc;
}
/* 2. Es ist ein Verzeichnis. Schleife bis es leer ist. */
size_t orig_len = strlen(path_buf);
while (1)
{
fs_dir_t_init(&dir);
rc = fs_opendir(&dir, path_buf);
if (rc != 0)
{
break;
}
bool found_something = false;
/* Genau EINEN löschbaren Eintrag suchen */
while (1)
{
rc = fs_readdir(&dir, &entry);
if (rc != 0 || entry.name[0] == '\0')
{
break; /* Ende oder Fehler */
}
if (strcmp(entry.name, ".") == 0 || strcmp(entry.name, "..") == 0)
{
continue; /* Ignorieren */
}
found_something = true;
break; /* Treffer! Schleife abbrechen. */
}
/* WICHTIG: Das Verzeichnis SOFORT schließen, BEVOR wir rekurieren!
* Damit geben wir das File-Handle (NUM_DIRS) an Zephyr zurück. */
fs_closedir(&dir);
if (!found_something || rc != 0)
{
break; /* Verzeichnis ist nun restlos leer */
}
size_t name_len = strlen(entry.name);
if (orig_len + 1 + name_len >= max_len)
{
rc = -ENAMETOOLONG;
break;
}
/* Pfad für das gefundene Kindelement bauen */
path_buf[orig_len] = '/';
strcpy(&path_buf[orig_len + 1], entry.name);
/* Rekursiver Aufruf für das Kind */
rc = fs_mgmt_pm_rm_recursive(path_buf, max_len);
/* Puffer sofort wieder auf unser Verzeichnis zurückschneiden */
path_buf[orig_len] = '\0';
if (rc != 0)
{
break; /* Abbruch, falls beim Löschen des Kindes ein Fehler auftrat */
}
}
/* 3. Das nun restlos leere Verzeichnis selbst löschen */
if (rc == 0)
{
rc = fs_unlink(path_buf);
}
fs_mgmt_pm_flash_suspend();
return rc;
}
int fs_mgmt_pm_mkdir_recursive(char *path)
{
int rc = 0;
struct fs_dirent entry;
char *p = path;
/* Führenden Slash überspringen, falls vorhanden (z. B. bei "/lfs") */
if (*p == '/')
{
p++;
}
/* Flash für den gesamten Durchlauf aktivieren */
fs_mgmt_pm_flash_resume();
while (*p != '\0')
{
if (*p == '/')
{
*p = '\0'; /* String temporär am aktuellen Slash terminieren */
/* Prüfen, ob dieser Pfadabschnitt bereits existiert */
rc = fs_stat(path, &entry);
if (rc == -ENOENT)
{
/* Existiert nicht -> anlegen */
rc = fs_mkdir(path);
if (rc != 0)
{
*p = '/'; /* Bei Fehler Slash wiederherstellen und abbrechen */
break;
}
}
else if (rc == 0)
{
/* Existiert -> prüfen, ob es ein Verzeichnis ist */
if (entry.type != FS_DIR_ENTRY_DIR)
{
rc = -ENOTDIR;
*p = '/';
break;
}
}
else
{
/* Anderer Dateisystemfehler */
*p = '/';
break;
}
*p = '/'; /* Slash für den nächsten Schleifendurchlauf wiederherstellen */
}
p++;
}
/* Letztes Element verarbeiten, falls der Pfad nicht mit '/' endet */
if (rc == 0 && p > path && *(p - 1) != '/')
{
rc = fs_stat(path, &entry);
if (rc == -ENOENT)
{
rc = fs_mkdir(path);
}
else if (rc == 0)
{
if (entry.type != FS_DIR_ENTRY_DIR)
{
rc = -ENOTDIR;
}
}
}
/* Flash am Ende wieder in den Suspend schicken */
fs_mgmt_pm_flash_suspend();
return rc;
}
int fs_mgmt_init(void)
{
k_mutex_init(&flash_pm_lock);
if (!device_is_ready(flash_dev)) {
LOG_ERR("Flash device not ready!");
return -ENODEV;
}
fs_mgmt_pm_flash_resume();
int rc = fs_mount(&fs_storage_mnt);
if (rc < 0)
{
LOG_ERR("Error mounting filesystem: %d", rc);
return rc;
}
fs_mgmt_pm_flash_suspend();
LOG_DBG("Filesystem mounted successfully");
return 0;
}