#include "filesystem.h"
#include <EEPROM.h>
#include "eewl.h"
#define EEPROM_SIZE 4096
#define MAX_FILES 16
#define MAX_PATH_LEN 32
#define MAGIC 0x50465331
#define BUFFER_LEN 10
#define BUFFER_START 0x10
// 1. Define the child struct FIRST
struct FileEntry {
char path[MAX_PATH_LEN];
uint16_t offset;
uint16_t size;
uint8_t used;
};
// 2. Now the parent struct knows what a 'FileEntry' is
struct FSMetadata {
uint32_t magic;
FileEntry files[MAX_FILES];
};
static FSMetadata metadata;
EEWL wl(metadata, BUFFER_LEN, BUFFER_START);
// Calculate the safe start for raw data (skipping the wear-leveling zone)
static int dataStart() {
return BUFFER_START + (BUFFER_LEN * (sizeof(FSMetadata) + 1));
}
static void loadFS() {
if (!wl.get(metadata)) {
formatFilesystem();
}
}
static void saveFS() {
wl.put(metadata);
}
bool initFilesystem() {
wl.begin();
loadFS();
if (metadata.magic != MAGIC) {
formatFilesystem();
}
return true;
}
void formatFilesystem() {
metadata.magic = MAGIC;
memset(metadata.files, 0, sizeof(metadata.files));
saveFS();
}
static int findFile(const char* path) {
for (int i = 0; i < MAX_FILES; i++) {
if (metadata.files[i].used && strcmp(metadata.files[i].path, path) == 0)
return i;
}
return -1;
}
bool fileExists(const char* path) {
return findFile(path) >= 0;
}
bool createFile(const char* path) {
if (fileExists(path)) return false;
for (int i = 0; i < MAX_FILES; i++) {
if (!metadata.files[i].used) {
strncpy(metadata.files[i].path, path, MAX_PATH_LEN);
metadata.files[i].offset = dataStart();
metadata.files[i].size = 0;
metadata.files[i].used = 1;
saveFS();
return true;
}
}
return false;
}
bool deleteFile(const char* path) {
int idx = findFile(path);
if (idx < 0) return false;
metadata.files[idx].used = 0;
saveFS();
return true;
}
bool writeFile(const char* path, const String& content) {
int idx = findFile(path);
if (idx < 0 && !createFile(path)) return false;
idx = findFile(path);
int offset = dataStart();
for (int i = 0; i < MAX_FILES; i++) {
if (i != idx && metadata.files[i].used)
offset += metadata.files[i].size;
}
metadata.files[idx].offset = offset;
metadata.files[idx].size = content.length();
for (int i = 0; i < content.length(); i++) {
EEPROM.write(offset + i, content[i]);
}
saveFS();
return true;
}
bool appendFile(const char* path, const String& content) {
String existing;
readFile(path, existing);
existing += content;
return writeFile(path, existing);
}
bool readFile(const char* path, String& content) {
int idx = findFile(path);
if (idx < 0) return false;
content = "";
for (int i = 0; i < metadata.files[idx].size; i++) {
content += char(EEPROM.read(metadata.files[idx].offset + i));
}
return true;
}
long getFileSize(const char* path) {
int idx = findFile(path);
if (idx < 0) return -1;
return metadata.files[idx].size;
}
bool isFile(const char* path) {
return fileExists(path);
}
bool isDirectory(const char* path) {
int len = strlen(path);
for (int i = 0; i < MAX_FILES; i++) {
if (metadata.files[i].used && strncmp(metadata.files[i].path, path, len) == 0)
return true;
}
return false;
}
bool dirExists(const char* path) {
return isDirectory(path);
}
bool createDir(const char*) {
return true;
}
bool deleteDir(const char* path) {
for (int i = 0; i < MAX_FILES; i++) {
if (metadata.files[i].used && strncmp(metadata.files[i].path, path, strlen(path)) == 0)
return false;
}
return true;
}
bool listDir(const char* path, String* out, int maxFiles, int& count) {
count = 0;
int len = strlen(path);
for (int i = 0; i < MAX_FILES && count < maxFiles; i++) {
if (metadata.files[i].used && strncmp(metadata.files[i].path, path, len) == 0) {
out[count++] = metadata.files[i].path;
}
}
return true;
}
bool getFilesystemInfo(long& total, long& used) {
total = EEPROM_SIZE;
used = dataStart();
for (int i = 0; i < MAX_FILES; i++) {
if (metadata.files[i].used) used += metadata.files[i].size;
}
return true;
}