Skip to content

Commit 5ce0b13

Browse files
committed
ESP32: faster file and directory abstractions
1 parent b69e6d9 commit 5ce0b13

File tree

3 files changed

+169
-71
lines changed

3 files changed

+169
-71
lines changed

common/file_reader.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ class FileReader {
102102
}
103103
#endif
104104
#ifdef ENABLE_SD
105-
new (&sd_file_) File;
105+
new (&sd_file_) LSFS::LSFILE;
106106
type_ = TYPE_SD;
107107
sd_file_ = LSFS::Open(filename);
108108
if (sd_file_) {
@@ -127,7 +127,7 @@ class FileReader {
127127
}
128128
#endif
129129
#ifdef ENABLE_SD
130-
new (&sd_file_) File;
130+
new (&sd_file_) LSFS::LSFILE;
131131
type_ = TYPE_SD;
132132
sd_file_ = LSFS::OpenFast(filename);
133133
if (sd_file_) {
@@ -141,7 +141,7 @@ class FileReader {
141141
bool Create(const char* filename) {
142142
Close();
143143
#ifdef ENABLE_SD
144-
new (&sd_file_) File;
144+
new (&sd_file_) LSFS::LSFILE;
145145
sd_file_ = LSFS::OpenForWrite(filename);
146146
if (sd_file_) {
147147
type_ = TYPE_SD;
@@ -153,7 +153,7 @@ class FileReader {
153153
bool OpenRW(const char* filename) {
154154
Close();
155155
#ifdef ENABLE_SD
156-
new (&sd_file_) File;
156+
new (&sd_file_) LSFS::LSFILE;
157157
sd_file_ = LSFS::OpenRW(filename);
158158
if (sd_file_) {
159159
type_ = TYPE_SD;
@@ -457,7 +457,7 @@ class FileReader {
457457
TYPE_MEM
458458
} type_;
459459
union {
460-
IF_SD(File sd_file_;)
460+
IF_SD(LSFS::LSFILE sd_file_;)
461461
IF_SF(SerialFlashFile sf_file_;)
462462
MemFile mem_file_;
463463
};

common/lsfs.h

Lines changed: 159 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@
55

66
#include "string_piece.h"
77

8+
#ifdef F_MAXPATH
9+
#define PO_MAXPATH F_MAXPATH
10+
#elif ESP32
11+
#define PO_MAXPATH 1024
12+
#else
13+
#define PO_MAXPATH 128
14+
#endif
15+
16+
817
struct PathHelper {
918
void Append(const char* name) {
1019
if (strlen(path_) && path_[strlen(path_)-1] != '/') {
@@ -56,13 +65,16 @@ struct PathHelper {
5665
void UndoDirname() {
5766
path_[strlen(path_)] = '/';
5867
}
68+
69+
void Slashify() {
70+
size_t len = strlen(path_);
71+
if (path_[len-1] == '/') return;
72+
path_[len] = '/';
73+
path_[len+1] = 0;
74+
}
5975
operator const char*() const { return path_; }
6076
operator StringPiece() const { return StringPiece(path_); }
61-
#ifdef F_MAXPATH
62-
char path_[F_MAXPATH];
63-
#else
64-
char path_[128];
65-
#endif
77+
char path_[PO_MAXPATH];
6678
};
6779

6880

@@ -131,7 +143,7 @@ class File {
131143

132144
class LSFS {
133145
public:
134-
typedef File FILE;
146+
typedef File LSFILE;
135147
static bool Begin() { return true; }
136148
static bool End() { return true; }
137149
static bool Exists(const char* path) {
@@ -196,7 +208,7 @@ class LSFS {
196208

197209
class LSFS {
198210
public:
199-
typedef File FILE;
211+
typedef File LSFILE;
200212
static bool Begin() {
201213
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
202214
// Prefer the built-in sd card for Teensy 3.5/3.6 as it is faster.
@@ -283,7 +295,7 @@ class LSFS {
283295

284296
class LSFS {
285297
public:
286-
typedef File FILE;
298+
typedef File LSFILE;
287299
static bool IsMounted() {
288300
return mounted_;
289301
}
@@ -444,27 +456,108 @@ class LSFS {
444456
bool LSFS::mounted_ = false;
445457
#elif defined(ESP32)
446458

459+
#include <sys/stat.h>
460+
#include <unistd.h>
461+
#include <dirent.h>
462+
#include <fcntl.h>
463+
447464
#include "FS.h"
448465
#include "SD_MMC.h"
449466
#include "SD.h"
450467

468+
#include "linked_ptr.h"
469+
// Posix file primitives
470+
471+
class DoCloseFile {
472+
public:
473+
static void Free(FILE* f) { if(f) fclose(f); }
474+
};
475+
476+
class DoCloseDir {
477+
public:
478+
static void Free(DIR* dir) { if(dir) closedir(dir); }
479+
};
480+
451481
class LSFS {
452482
public:
453-
typedef File FILE;
483+
484+
class File : public Stream {
485+
public:
486+
File() : file_() {}
487+
File(FILE* f) : file_(f) {
488+
if (file_.get()) {
489+
setvbuf(file_.get(), NULL, _IOFBF, 512);
490+
}
491+
}
492+
operator bool() const { return !!file_; }
493+
void close() { file_ = NULL; }
494+
int read(uint8_t *dest, size_t bytes) {
495+
return fread(dest, 1, bytes, file_.get());
496+
}
497+
int read() {
498+
uint8_t c;
499+
read(&c, 1);
500+
return c;
501+
}
502+
size_t write(const uint8_t *dest, size_t bytes) override {
503+
return fwrite(dest, 1, bytes, file_.get());
504+
}
505+
size_t write(uint8_t c) override {
506+
return write(&c, 1);
507+
}
508+
void seek(size_t pos) {
509+
fseek(file_.get(), pos, SEEK_SET);
510+
}
511+
uint32_t position() {
512+
return ftell(file_.get());
513+
}
514+
// Warning: slow!
515+
int available() {
516+
long pos = position();
517+
fseek(file_.get(), 0, SEEK_END);
518+
long end = position();
519+
seek(pos);
520+
return end - pos;
521+
}
522+
// Warning: slow!
523+
uint32_t size() {
524+
long pos = position();
525+
fseek(file_.get(), 0, SEEK_END);
526+
long end = position();
527+
seek(pos);
528+
return end;
529+
}
530+
// Warning: slow!
531+
int peek() {
532+
long pos = position();
533+
uint8_t ret;
534+
read(&ret, 1);
535+
seek(pos);
536+
return ret;
537+
}
538+
LinkedPtr<FILE, DoCloseFile> file_;
539+
};
540+
541+
typedef File LSFILE;
542+
454543
static bool Begin() {
455544

456545
#if 1
457546
#define SDCLASS SD_MMC
458547
SD_MMC.setPins(sdClkPin, sdCmdPin, sdD0Pin, sdD1Pin, sdD2Pin, sdD3Pin);
459-
if (!SD_MMC.begin("/sdcard", false, false, SDMMC_FREQ_DEFAULT, /*maxOpenFiles=*/ 32)) return false;
548+
// if (!SD_MMC.begin("/sdcard", false, false, SDMMC_FREQ_DEFAULT, /*maxOpenFiles=*/ 32)) return false;
549+
if (!SD_MMC.begin("/sdcard", false, false, BOARD_MAX_SDMMC_FREQ, /*maxOpenFiles=*/ 32)) return false;
460550

551+
chdir("/sdcard");
461552
#endif
462553

554+
463555
#if 0
464556
#define SDCLASS SD
465557
SPI.begin(sdClkPin, sdD0Pin, sdCmdPin);
466558
if (!SD.begin(sdD3Pin, SPI, /* frequency= */ 20000000, "/sd" , /* max_file=*/ 32)) return false;
467-
#endif
559+
#endif
560+
468561

469562
// if (!SDCLASS.begin()) return false;
470563
uint8_t cardType = SDCLASS.cardType();
@@ -476,88 +569,92 @@ class LSFS {
476569
return true;
477570
}
478571
static bool Exists(const char* path) {
479-
return SDCLASS.exists(path);
572+
PathHelper p("/sdcard", path);
573+
struct stat s;
574+
return stat(p, &s) == 0;
575+
576+
// return SDCLASS.exists(path);
480577
}
481578
static bool Remove(const char* path) {
482-
return SDCLASS.remove(path);
579+
return unlink(path) == 0;
580+
// return SDCLASS.remove(path);
483581
}
484582
static File Open(const char* path) {
485-
if (!SDCLASS.exists(path)) return File();
486-
File f = SDCLASS.open(path);
487-
f.setBufferSize(512);
488-
return f;
583+
PathHelper p("/sdcard", path);
584+
return fopen(p, "r");
489585
}
490586
static File OpenRW(const char* path) {
491-
File f = SDCLASS.open(path, FILE_WRITE);
492-
f.setBufferSize(512);
493-
return f;
494-
587+
PathHelper p("/sdcard", path);
588+
File ret = fopen(p, "r+");
589+
if (ret) return ret;
590+
return OpenForWrite(p);
495591
}
496592
static File OpenFast(const char* path) {
497-
// At some point, I put this check in here to make sure that the file
498-
// exists before we try to open it, as opening directories and other
499-
// weird files can cause open() to hang. However, this check takes
500-
// too long, and causes audio underflows, so we're going to need a
501-
// different approach to not opening directories and weird files. /Hubbe
502-
// if (!SDCLASS.exists(path)) return File();
503-
File f = SDCLASS.open(path);
504-
f.setBufferSize(512);
505-
return f;
593+
PathHelper p("/sdcard", path);
594+
return fopen(p, "r");
506595
}
507596
static File OpenForWrite(const char* path) {
508-
File f = SDCLASS.open(path, FILE_WRITE);
509-
if (!f) {
510-
PathHelper tmp(path);
511-
if (tmp.Dirname()) {
512-
SDCLASS.mkdir(tmp);
513-
f = SDCLASS.open(path, FILE_WRITE);
514-
}
515-
}
516-
f.setBufferSize(512);
517-
return f;
597+
PathHelper p("/sdcard", path);
598+
return fopen(p, "wct");
518599
}
600+
519601
class Iterator {
520602
public:
521-
explicit Iterator(const char* dirname) {
522-
dir_ = SDCLASS.open(dirname);
523-
if (dir_.isDirectory()) {
524-
f_ = dir_.openNextFile();
603+
explicit Iterator(const char* path) : path_("/sdcard", path) {
604+
path_.Slashify();
605+
606+
dir_ = opendir(path_);
607+
if (dir_.get() == nullptr) {
608+
entry_ = nullptr;
609+
return;
525610
}
611+
entry_ = readdir(dir_.get());
526612
}
527-
explicit Iterator(Iterator& other) {
528-
dir_ = other.f_;
529-
other.f_ = File();
530-
f_ = dir_.openNextFile();
613+
614+
explicit Iterator(Iterator& other) : path_(other.path_, other.name()) {
615+
path_.Slashify();
616+
617+
dir_ = opendir(path_);
618+
if (!dir_) {
619+
STDERR << "Expected path does not exist: " << path_ << "\n";
620+
entry_ = nullptr;
621+
return;
622+
}
623+
entry_ = readdir(dir_.get());
531624
}
532-
~Iterator() {
533-
dir_.close();
534-
f_.close();
625+
626+
void operator++() { entry_ = readdir(dir_.get()); }
627+
operator bool() { return !!entry_; }
628+
bool isdir() {
629+
struct stat s;
630+
PathHelper filename(path_, entry_->d_name);
631+
stat(filename, &s);
632+
return S_ISDIR(s.st_mode);
535633
}
536-
void operator++() {
537-
f_.close();
538-
f_ = dir_.openNextFile();
634+
const char* name() { return entry_->d_name; }
635+
size_t size() {
636+
struct stat s;
637+
PathHelper filename(path_, entry_->d_name);
638+
stat(filename, &s);
639+
return s.st_size;
539640
}
540-
operator bool() { return f_; }
541-
bool isdir() { return f_.isDirectory(); }
542-
const char* name() { return f_.name(); }
543-
size_t size() { return f_.size(); }
544641

545642
private:
546-
File dir_;
547-
File f_;
643+
PathHelper path_;
644+
LinkedPtr<DIR, DoCloseDir> dir_;
645+
dirent* entry_;
548646
};
549647
};
550648

551649

552-
553650
#else
554651

555652
// Standard arduino
556653
#include <SD.h>
557654

558655
class LSFS {
559656
public:
560-
typedef File FILE;
657+
typedef File LSFILE;
561658
static bool Begin() {
562659
return SD.begin(sdCardSelectPin);
563660
}

common/sd_test.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,23 +65,24 @@ class SDTestHelper {
6565
void TestFile(const char* filename) {
6666
uint8_t block[512];
6767
uint32_t start_open = micros();
68-
File f = LSFS::Open(filename);
68+
LSFS::LSFILE f = LSFS::Open(filename);
6969
if (!f) {
7070
STDOUT << "Failed to open!";
7171
}
7272
open_histogram.count(micros() - start_open);
7373

7474
int cnt = 0;
7575
uint32_t block_start = micros();
76-
while (f.available()) {
76+
while (true) {
7777
uint32_t start = micros();
78-
f.read(block, 512);
78+
uint32_t bytes_read = f.read(block, 512);
7979
uint32_t end = micros();
80+
if (bytes_read < 512) break;
8081
histogram.count(end - start);
8182
if (++cnt == 128) {
8283
cnt = 0;
8384
uint32_t block_time = micros() - block_start;
84-
int streams = (int)((64.0 / 88.2) / (block_time * 0.000001));
85+
int streams = (int)((512 * 128 / 2 / 44100.0) / (block_time * 0.000001));
8586
if (streams < 10) STDOUT << (char)('0' + streams);
8687
else if (streams < 36) STDOUT << (char)('A' + streams - 10);
8788
else STDOUT << '!';

0 commit comments

Comments
 (0)