2026-02-08 21:29:14 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
2026-02-28 11:15:27 +01:00
|
|
|
#include <Print.h>
|
|
|
|
|
#include <common/FsApiConstants.h> // for oflag_t
|
|
|
|
|
#include <freertos/semphr.h>
|
2026-02-08 21:29:14 +01:00
|
|
|
|
2026-02-28 11:15:27 +01:00
|
|
|
#include <memory>
|
|
|
|
|
#include <string>
|
2026-02-08 21:29:14 +01:00
|
|
|
#include <vector>
|
|
|
|
|
|
2026-02-28 11:15:27 +01:00
|
|
|
class HalFile;
|
|
|
|
|
|
2026-02-08 21:29:14 +01:00
|
|
|
class HalStorage {
|
|
|
|
|
public:
|
|
|
|
|
HalStorage();
|
|
|
|
|
bool begin();
|
|
|
|
|
bool ready() const;
|
|
|
|
|
std::vector<String> listFiles(const char* path = "/", int maxFiles = 200);
|
|
|
|
|
// Read the entire file at `path` into a String. Returns empty string on failure.
|
|
|
|
|
String readFile(const char* path);
|
|
|
|
|
// Low-memory helpers:
|
|
|
|
|
// Stream the file contents to a `Print` (e.g. `Serial`, or any `Print`-derived object).
|
|
|
|
|
// Returns true on success, false on failure.
|
|
|
|
|
bool readFileToStream(const char* path, Print& out, size_t chunkSize = 256);
|
|
|
|
|
// Read up to `bufferSize-1` bytes into `buffer`, null-terminating it. Returns bytes read.
|
|
|
|
|
size_t readFileToBuffer(const char* path, char* buffer, size_t bufferSize, size_t maxBytes = 0);
|
|
|
|
|
// Write a string to `path` on the SD card. Overwrites existing file.
|
|
|
|
|
// Returns true on success.
|
|
|
|
|
bool writeFile(const char* path, const String& content);
|
|
|
|
|
// Ensure a directory exists, creating it if necessary. Returns true on success.
|
|
|
|
|
bool ensureDirectoryExists(const char* path);
|
|
|
|
|
|
2026-02-28 11:15:27 +01:00
|
|
|
HalFile open(const char* path, const oflag_t oflag = O_RDONLY);
|
2026-02-08 21:29:14 +01:00
|
|
|
bool mkdir(const char* path, const bool pFlag = true);
|
|
|
|
|
bool exists(const char* path);
|
|
|
|
|
bool remove(const char* path);
|
2026-02-22 07:18:25 +01:00
|
|
|
bool rename(const char* oldPath, const char* newPath);
|
2026-02-08 21:29:14 +01:00
|
|
|
bool rmdir(const char* path);
|
|
|
|
|
|
2026-02-28 11:15:27 +01:00
|
|
|
bool openFileForRead(const char* moduleName, const char* path, HalFile& file);
|
|
|
|
|
bool openFileForRead(const char* moduleName, const std::string& path, HalFile& file);
|
|
|
|
|
bool openFileForRead(const char* moduleName, const String& path, HalFile& file);
|
|
|
|
|
bool openFileForWrite(const char* moduleName, const char* path, HalFile& file);
|
|
|
|
|
bool openFileForWrite(const char* moduleName, const std::string& path, HalFile& file);
|
|
|
|
|
bool openFileForWrite(const char* moduleName, const String& path, HalFile& file);
|
2026-02-08 21:29:14 +01:00
|
|
|
bool removeDir(const char* path);
|
|
|
|
|
|
|
|
|
|
static HalStorage& getInstance() { return instance; }
|
|
|
|
|
|
2026-02-28 11:15:27 +01:00
|
|
|
class StorageLock; // private class, used internally
|
|
|
|
|
|
2026-02-08 21:29:14 +01:00
|
|
|
private:
|
|
|
|
|
static HalStorage instance;
|
|
|
|
|
|
|
|
|
|
bool initialized = false;
|
2026-02-28 11:15:27 +01:00
|
|
|
SemaphoreHandle_t storageMutex = nullptr;
|
2026-02-08 21:29:14 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define Storage HalStorage::getInstance()
|
|
|
|
|
|
2026-02-28 11:15:27 +01:00
|
|
|
class HalFile : public Print {
|
|
|
|
|
friend class HalStorage;
|
|
|
|
|
class Impl;
|
|
|
|
|
std::unique_ptr<Impl> impl;
|
|
|
|
|
explicit HalFile(std::unique_ptr<Impl> impl);
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
HalFile();
|
|
|
|
|
~HalFile();
|
|
|
|
|
HalFile(HalFile&&);
|
|
|
|
|
HalFile& operator=(HalFile&&);
|
|
|
|
|
HalFile(const HalFile&) = delete;
|
|
|
|
|
HalFile& operator=(const HalFile&) = delete;
|
|
|
|
|
|
|
|
|
|
void flush();
|
|
|
|
|
size_t getName(char* name, size_t len);
|
|
|
|
|
size_t size();
|
|
|
|
|
size_t fileSize();
|
|
|
|
|
bool seek(size_t pos);
|
|
|
|
|
bool seekCur(int64_t offset);
|
|
|
|
|
bool seekSet(size_t offset);
|
|
|
|
|
int available() const;
|
|
|
|
|
size_t position() const;
|
|
|
|
|
int read(void* buf, size_t count);
|
|
|
|
|
int read(); // read a single byte
|
|
|
|
|
size_t write(const void* buf, size_t count);
|
|
|
|
|
size_t write(uint8_t b) override;
|
|
|
|
|
bool rename(const char* newPath);
|
|
|
|
|
bool isDirectory() const;
|
|
|
|
|
void rewindDirectory();
|
|
|
|
|
bool close();
|
|
|
|
|
HalFile openNextFile();
|
|
|
|
|
bool isOpen() const;
|
|
|
|
|
operator bool() const;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Only do renaming FsFile to HalFile if this header is included by downstream code
|
|
|
|
|
// The renaming is to allow using the thread-safe HalFile instead of the raw FsFile, without needing to change the
|
|
|
|
|
// downstream code
|
|
|
|
|
#ifndef HAL_STORAGE_IMPL
|
|
|
|
|
using FsFile = HalFile;
|
|
|
|
|
#endif
|
|
|
|
|
|
2026-02-08 21:29:14 +01:00
|
|
|
// Downstream code must use Storage instead of SdMan
|
|
|
|
|
#ifdef SdMan
|
|
|
|
|
#undef SdMan
|
|
|
|
|
#endif
|