arduino-emulator
Loading...
Searching...
No Matches
SD.h
1/*
2 SD.h
3 Copyright (c) 2025 Phil Schatzmann. All right reserved.
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19#pragma once
20
21#include <sys/stat.h>
22#include <sys/types.h>
23#include <unistd.h>
24#if defined(_WIN32)
25#include <direct.h>
26#endif
27
28#include <cstdint>
29#include <filesystem>
30#include <fstream>
31#include <iostream>
32#include <string>
33
34#include "Stream.h"
35#ifdef USE_FILESYSTEM
36#include <filesystem>
37#endif
38
39#define SD_SCK_MHZ(maxMhz) (1000000UL * (maxMhz))
40#define SPI_FULL_SPEED SD_SCK_MHZ(50)
41#define SPI_DIV3_SPEED SD_SCK_MHZ(16)
42#define SPI_HALF_SPEED SD_SCK_MHZ(4)
43#define SPI_DIV6_SPEED SD_SCK_MHZ(8)
44#define SPI_QUARTER_SPEED SD_SCK_MHZ(2)
45#define SPI_EIGHTH_SPEED SD_SCK_MHZ(1)
46#define SPI_SIXTEENTH_SPEED SD_SCK_HZ(500000)
47
48// These reuse POSIX's O_* names for unrelated std::ios::openmode values, so
49// they must win over <fcntl.h>'s real O_* macros (already pulled in
50// transitively by this point on some platforms, e.g. via std::fstream/
51// networking headers included before this file) - #undef first rather
52// than #ifndef-guarding, since guarding would leave the real POSIX values
53// in effect and silently break File::open().
54#undef O_RDONLY
55#define O_RDONLY ios::in
56#undef O_WRONLY
57#define O_WRONLY ios::out
58#undef O_RDWR
59#define O_RDWR ios::in | ios::out
60#undef O_AT_END
61#define O_AT_END ios::ate
62#undef O_APPEND
63#define O_APPEND ios::ate
64#undef O_CREAT
65#define O_CREAT ios::trunc
66#undef O_TRUNC
67#define O_TRUNC ios::trunc
68#undef O_EXCL
69#define O_EXCL 0
70#undef O_SYNC
71#define O_SYNC 0
72#define O_READ O_RDONLY
73#define O_WRITE O_WRONLY
74#define FILE_READ ios::in
75#define FILE_WRITE ios::out
76
77#ifndef SS
78#define SS -1
79#endif
80
81#ifndef BUILTIN_SDCARD
82#define BUILTIN_SDCARD -1
83#endif
84
85using std::ios;
86
93 SdSpiConfig(int a = 0, int b = 0, int c = 0) {}
94};
95
100class File : public Stream {
101 public:
102 bool isOpen() {
103 if (filename == "") return false;
104 if (is_dir) return true;
105 bool result = file.is_open();
106 return result;
107 }
108
109 bool open(const char *name, int flags) {
110 this->filename = name;
111 int rc = stat(name, &info);
112 if ((flags == O_RDONLY) && rc == -1) {
113 // if we want to read but the file does not exist we fail
114 return false;
115 } else if (rc == 0 && info.st_mode & S_IFDIR) {
116 // file exists and it is a directory
117 is_dir = true;
118 size_bytes = 0;
119#ifdef USE_FILESYSTEM
120 // prevent authorization exceptions
121 try {
122 dir_path = std::filesystem::path(filename);
123 iterator = std::filesystem::directory_iterator({dir_path});
124 } catch (...) {
125 }
126#endif
127 return true;
128 } else {
129 is_dir = false;
130 size_bytes = rc != -1 ? info.st_size : 0;
131 file.open(filename.c_str(), toMode(flags));
132 return isOpen();
133 }
134 }
135
136 bool close() {
137 file.close();
138 return !isOpen();
139 }
140
141 size_t read(uint8_t *buffer, size_t length) {
142 return readBytes((char *)buffer, length);
143 }
144
145 size_t readBytes(char *buffer, size_t length) {
146 file.read(buffer, length);
147 return static_cast<size_t>(file.gcount());
148 }
149
150 size_t write(const uint8_t *buffer, size_t size) override {
151 file.write((const char *)buffer, size);
152 return file.good() ? size : 0;
153 }
154 size_t write(uint8_t ch) override {
155 file.put(ch);
156 return file.good() ? 1 : 0;
157 }
158 int available() override { return size_bytes - file.tellg(); };
159 int availableForWrite() override { return 1024; }
160 int read() override { return file.get(); }
161 int peek() override { return file.peek(); }
162 void flush() override {}
163 void getName(char *str, size_t len) { strncpy(str, filename.c_str(), len); }
164 bool isDir() { return is_dir; }
165 bool isHidden() { return false; }
166 bool rewind() {
167 pos = 0;
168 return is_dir;
169 }
170 bool openNext(File &dir, int flags = O_RDONLY) {
171 if (!*this) return false;
172
173 // if (pos == 0) {
174 // dir_path = std::filesystem::path(filename);
175 // iterator = std::filesystem::directory_iterator({dir_path});
176 // }
177 // pos++;
178#ifdef USE_FILESYSTEM
179 if (iterator != end(iterator)) {
180 std::filesystem::directory_entry entry = *iterator++;
181 return dir.open(entry.path().c_str(), flags);
182 }
183#endif
184 return false;
185 }
186 int dirIndex() { return pos; }
187
188 File openNextFile() {
189 File next_file;
190 openNext(next_file, O_RDONLY);
191 return next_file;
192 }
193
194 size_t size() {
195 int rc = stat(filename.c_str(), &info);
196 size_bytes = rc != -1 ? info.st_size : 0;
197 return size_bytes;
198 }
199
200 size_t position() { return file.tellg(); }
201
202 bool seek(size_t pos) {
203 file.seekg(pos);
204 return file ? true : false;
205 }
206
207 operator bool() { return isOpen(); }
208
209 bool isDirectory() { return is_dir; }
210
211 const char *name() { return filename.c_str(); }
212
213 void rewindDirectory() {
214 if (!is_dir) return;
215#ifdef USE_FILESYSTEM
216 try {
217 iterator = std::filesystem::directory_iterator(dir_path);
218 } catch (...) {
219 // Handle errors silently
220 }
221#endif
222 }
223
224 protected:
225 std::fstream file;
226 size_t size_bytes = 0;
227 bool is_dir = false;
228 int pos = 0;
229 std::string filename = "";
230 struct stat info;
231
232#ifdef USE_FILESYSTEM
233 std::filesystem::directory_iterator iterator;
234 std::filesystem::path dir_path;
235#endif
236
237 std::ios_base::openmode toMode(int flags) {
238 return (std::ios_base::openmode)flags;
239 }
240};
241
246class SdFat {
247 public:
248 bool begin(int cs = SS, int speed = 0) { return true; }
249
250 bool begin(SdSpiConfig &cfg) { return true; }
251
252 void end() {}
253
254 void errorHalt(const char *msg) {
255 puts(msg);
256 exit(0);
257 }
258 void initErrorHalt() { exit(0); }
259
260 bool exists(const char *name) {
261 struct stat info;
262 return stat(name, &info) == 0;
263 }
264
265 File open(const char *name, int flags = O_READ) {
266 File file;
267 file.open(name, flags);
268 return file;
269 }
270
271 bool remove(const char *name) { return std::remove(name) == 0; }
272 bool mkdir(const char *name) {
273#if defined(_WIN32)
274 return ::_mkdir(name) == 0;
275#else
276 return ::mkdir(name, 0777) == 0;
277#endif
278 }
279 bool rmdir(const char *path) {
280 int rc = ::rmdir(path);
281 return rc == 0;
282 }
283
291 std::error_code ec;
292 const std::filesystem::path root = std::filesystem::current_path(ec);
293 if (ec || !std::filesystem::exists(root, ec) || ec) {
294 return false;
295 }
296
297 const auto status = std::filesystem::status(root, ec);
298 if (ec) {
299 return false;
300 }
301
302 return (status.permissions() & std::filesystem::perms::owner_write) !=
303 std::filesystem::perms::none;
304 }
305
307 uint64_t totalSize() { return totalBytes(); }
308
310 uint64_t usedSize() { return usedBytes(); }
311
312 uint64_t totalBytes() {
313 std::error_code ec;
314 const std::filesystem::space_info si =
315 std::filesystem::space(std::filesystem::current_path(ec), ec);
316 return ec ? 0 : si.capacity;
317 }
318 uint64_t usedBytes() {
319 std::error_code ec;
320 const std::filesystem::space_info si =
321 std::filesystem::space(std::filesystem::current_path(ec), ec);
322 return ec ? 0 : si.capacity - si.available;
323 }
324};
325
326static SdFat SD;
327using SDClass = SdFat;
C++ std based emulatoion ofr File.
Definition SD.h:100
C++ std based emulatoion ofr SdFat.
Definition SD.h:246
uint64_t usedSize()
Used bytes of the host filesystem backing SD.
Definition SD.h:310
bool mediaPresent()
Return whether the host filesystem backing the emulator is usable.
Definition SD.h:290
uint64_t totalSize()
Total capacity in bytes of the host filesystem backing SD.
Definition SD.h:307
C++ std based emulatoion of SdSpiConfig.
Definition SD.h:92