Noodle
Loading...
Searching...
No Matches
noodle_fs.h
Go to the documentation of this file.
1
39
40
41#pragma once
42
43#include <stddef.h>
44#include <stdint.h>
45
46// -----------------------------
47// Path policy
48// -----------------------------
56#if defined(NOODLE_USE_SDFAT)
57 #define NOODLE_FS_NEEDS_LEADING_SLASH 0
58#else
59 #define NOODLE_FS_NEEDS_LEADING_SLASH 1
60#endif
61
69#ifndef NOODLE_MAX_FILENAME
70 #define NOODLE_MAX_FILENAME 20 // plenty for "w28.txt" etc.
71#endif
72
73
74// ------------------------------
75// 1) Enforce "exactly one"
76// ------------------------------
77#if (defined(NOODLE_USE_SDFAT) + defined(NOODLE_USE_SD_MMC) + defined(NOODLE_USE_FFAT) + defined(NOODLE_USE_LITTLEFS) + defined(NOODLE_USE_NONE)) != 1
78# error "Select exactly ONE backend: NOODLE_USE_SDFAT, NOODLE_USE_SD_MMC, NOODLE_USE_FFAT, NOODLE_USE_LITTLEFS, or NOODLE_USE_NONE"
79#endif
80
81// ------------------------------
82// 2) NONE backend
83// ------------------------------
84#if defined(NOODLE_USE_NONE)
85
95 struct NDL_NullFile {
96 bool _open = false;
97
98 // Match common File/FsFile-ish methods used in embedded code.
99 operator bool() const { return _open; }
100 bool available() const { return false; }
101 int read() { return -1; }
102 int peek() { return -1; }
103 size_t readBytes(char*, size_t) { return 0; }
104 size_t write(uint8_t) { return 0; }
105 size_t write(const uint8_t*, size_t) { return 0; }
106 void flush() {}
107 void close() { _open = false; }
108 size_t size() const { return 0; }
109 size_t position() const { return 0; }
110 bool seek(uint32_t) { return false; }
111 size_t println(uint8_t v) { (void)v; return 0; }
112 size_t println(float v) { (void)v; return 0; }
113 size_t println(float v, int base) { (void)v; return 0; }
114 };
115
120 using NDL_File = NDL_NullFile;
121
122 // No NOODLE_FS symbol in NONE mode.
123
124#else
125// ------------------------------
126// 3) Real backends
127// ------------------------------
128 #if defined(NOODLE_USE_SDFAT)
129 #include <SdFat.h>
130
131#if defined(ESP32) || defined(ARDUINO_ARCH_ESP32) || \
132 defined(ESP8266) || defined(ARDUINO_ARCH_ESP8266) || \
133 defined(ARDUINO_ARCH_RP2040)
134 using NDL_File = FsFile; // SdFat on ESP32 typically uses FsFile
135 #else
136 using NDL_File = File; // SdFat on AVR often uses File wrapper
137 #endif
138
145 extern SdFat NOODLE_FS; // defined in noodle_internal.cpp
146
147 #elif defined(NOODLE_USE_FFAT)
148 #include <FFat.h>
150 #define NOODLE_FS FFat
151 using NDL_File = File;
152
153 #elif defined(NOODLE_USE_LITTLEFS)
154 #include <LittleFS.h>
156 #define NOODLE_FS LittleFS
157 using NDL_File = File;
158
159 #elif defined(NOODLE_USE_SD_MMC)
160 #include <SD_MMC.h>
162 #define NOODLE_FS SD_MMC
163 using NDL_File = File;
164
165 #endif
166#endif
167
168// ------------------------------
169// 4) Unified API
170// ------------------------------
183inline void noodle_copy_name(char* dst, size_t cap, const char* src) {
184 if (!dst || cap == 0) return;
185 if (!src) { dst[0] = '\0'; return; }
186
187 size_t i = 0;
188 while (src[i] != '\0' && (i + 1) < cap) {
189 dst[i] = src[i];
190 i++;
191 }
192 dst[i] = '\0';
193}
194
207inline const char* noodle_norm_filename(const char* name) {
208 if (!name) return "";
209
210#if NOODLE_FS_NEEDS_LEADING_SLASH
211 // One static buffer is enough for your simplified rules.
212 // Size = '/' + filename + '\0'
213 static char out[NOODLE_MAX_FILENAME + 2];
214
215 if (name[0] == '/') {
216 noodle_copy_name(out, sizeof(out), name);
217 return out;
218 }
219
220 out[0] = '/';
221 noodle_copy_name(out + 1, NOODLE_MAX_FILENAME + 1, name);
222 return out;
223#else
224 // SdFat: return as-is, no extra RAM used.
225 return name;
226#endif
227}
228
239inline NDL_File noodle_fs_open_read(const char* path) {
240 path = noodle_norm_filename(path);
241#if defined(NOODLE_USE_NONE)
242 (void)path;
243 return NDL_File{}; // invalid handle
244#elif defined(NOODLE_USE_SDFAT)
245 return NOODLE_FS.open(path, O_RDONLY);
246#else
247 return NOODLE_FS.open(path, FILE_READ);
248#endif
249}
250
262inline NDL_File noodle_fs_open_write(const char* path) {
263 path = noodle_norm_filename(path);
264#if defined(NOODLE_USE_NONE)
265 (void)path;
266 return NDL_File{}; // invalid handle
267#elif defined(NOODLE_USE_SDFAT)
268 int flags = O_WRITE | O_CREAT | O_TRUNC;
269 return NOODLE_FS.open(path, flags);
270#else
271 return NOODLE_FS.open(path, FILE_WRITE);
272#endif
273}
274
284inline bool noodle_fs_remove(const char* path) {
285 path = noodle_norm_filename(path);
286#if defined(NOODLE_USE_NONE)
287 (void)path;
288 return false;
289#else
290 return NOODLE_FS.remove(path);
291#endif
292}
293
303inline void noodle_rewind_file(NDL_File &fi) {
304#if defined(NOODLE_USE_SDFAT)
305 fi.seekSet(0);
306#elif defined(NOODLE_USE_FFAT) || defined(NOODLE_USE_LITTLEFS) || defined(NOODLE_USE_SD_MMC) || defined(NOODLE_USE_SD)
307 fi.seek(0);
308#else
309 // NOODLE_USE_NONE (or unknown backend): nothing to seek. Close the handle.
310 fi.close();
311#endif
312}
void noodle_rewind_file(NDL_File &fi)
Rewind a file handle to position 0.
Definition noodle_fs.h:303
void noodle_copy_name(char *dst, size_t cap, const char *src)
Copy a C string into a bounded buffer with NUL-termination.
Definition noodle_fs.h:183
bool noodle_fs_remove(const char *path)
Remove a file using the selected backend.
Definition noodle_fs.h:284
#define NOODLE_MAX_FILENAME
Maximum filename length copied by noodle_norm_filename().
Definition noodle_fs.h:70
NDL_File noodle_fs_open_write(const char *path)
Open a file for writing using the selected backend.
Definition noodle_fs.h:262
NDL_File noodle_fs_open_read(const char *path)
Open a file for reading using the selected backend.
Definition noodle_fs.h:239
const char * noodle_norm_filename(const char *name)
Normalize a filename/path for the selected filesystem backend.
Definition noodle_fs.h:207
NDL_File fi
Shared input file handle used by streaming layer implementations.
Definition noodle_internal.cpp:14
SdFat NOODLE_FS
SdFat filesystem object used by the SdFat backend.
Definition noodle_internal.cpp:10