Skip to content
43 changes: 42 additions & 1 deletion sources/Adapters/adv/filesystem/advFileSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,10 @@ PicoFileType advFileSystem::getFileType(int index) {
}

void advFileSystem::list(etl::ivector<int> *fileIndexes, const char *filter,
bool subDirOnly, bool includeHidden) {
ListFlags flags) {
bool subDirOnly = flags & LF_SUBDIRS_ONLY;
bool includeHidden = flags & LF_INCLUDE_HIDDEN;
bool sorted = flags & LF_SORTED;

fileIndexes->clear();

Expand All @@ -155,6 +158,8 @@ void advFileSystem::list(etl::ivector<int> *fileIndexes, const char *filter,
return;
}

uint32_t sortKeys[MAX_FILE_INDEX_SIZE];

for (size_t i = 0; i < file_cache_.size(); ++i) {
if (fileIndexes->full()) {
Trace::Error("PICOFILESYSTEM: fileIndexes is full, breaking list");
Expand Down Expand Up @@ -187,12 +192,48 @@ void advFileSystem::list(etl::ivector<int> *fileIndexes, const char *filter,
}
} else {
fileIndexes->push_back(i);

if (sorted) {
sortKeys[fileIndexes->size() - 1] =
FileSystem::getFileSortKey(fno.fname);
}
}
Trace::Log("FILESYSTEM", "[%d] got file: %s", index, fno.fname);
} else {
Trace::Log("FILESYSTEM", "skipped hidden: %s", fno.fname);
}
}

for (size_t i = 1; i < fileIndexes->size(); i++) {
uint32_t key = sortKeys[i];
int index = fileIndexes->at(i);
size_t j = i;

while (j > 0) {
bool shouldMove = sortKeys[j - 1] > key;

if (!shouldMove && sortKeys[j - 1] == key) {
// keys are identical, do a tiebreaker by doing a string compare to
// ensure stable sorting of files with same first 4 letters
const FILINFO &fA = file_cache_[index];
const FILINFO &fB = file_cache_[fileIndexes->at(j - 1)];

shouldMove = strcasecmp(fA.fname, fB.fname) > 0;
}

if (shouldMove) {
sortKeys[j] = sortKeys[j - 1];
fileIndexes->at(j) = fileIndexes->at(j - 1);
--j;
} else {
break;
}
}

sortKeys[j] = key;
fileIndexes->at(j) = index;
}

f_closedir(&dir);
Trace::Log("FILESYSTEM", "added file indexes:%d", fileIndexes->size());
}
Expand Down
2 changes: 1 addition & 1 deletion sources/Adapters/adv/filesystem/advFileSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class advFileSystem : public FileSystem {
virtual FileHandle Open(const char *name, const char *mode) override;
virtual bool chdir(const char *path) override;
virtual void list(etl::ivector<int> *fileIndexes, const char *filter,
bool subDirOnly, bool includeHidden = false) override;
ListFlags flags) override;
virtual void getFileName(int index, char *name, int length) override;
virtual PicoFileType getFileType(int index) override;
virtual bool isParentRoot() override;
Expand Down
4 changes: 2 additions & 2 deletions sources/Adapters/adv/gui/SerialDebugUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,8 @@ void SerialDebugUI::listFiles(const char *path) {
if (!fs->chdir(path)) {
Trace::Error("failed to ls files path:%s", path);
}
etl::vector<int, MAX_FILE_INDEX_SIZE> fileIndexes;
fs->list(&fileIndexes, "", false);

fs->list(&fileIndexList_, "", LF_SORTED);

// No need to actually do the printing below for now as the current debug code
// in PicoFileSystem class is already printing all the files fetched when the
Expand Down
93 changes: 73 additions & 20 deletions sources/Adapters/picoTracker/filesystem/picoTrackerFileSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

#include "picoTrackerFileSystem.h"
#include "Application/Persistency/PersistencyService.h"
#include "Externals/etl/include/etl/pool.h"
#include "pico/multicore.h"
#include <cstring>
Expand Down Expand Up @@ -120,20 +121,22 @@ PicoFileType picoTrackerFileSystem::getFileType(int index) {
}

void picoTrackerFileSystem::list(etl::ivector<int> *fileIndexes,
const char *filter, bool subDirOnly,
bool includeHidden) {
const char *filter, ListFlags flags) {
bool subDirOnly = flags & LF_SUBDIRS_ONLY;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@n1LS no the point from my previous feedback was not to consolidate the bool params, my point is that we dont want to change the interface of list. If that requires adding a new listSorted() then please do that.

bool includeHidden = flags & LF_INCLUDE_HIDDEN;
bool sorted = flags & LF_SORTED;
std::lock_guard<Mutex> lock(mutex);

fileIndexes->clear();

File cwd;
char buffer[PFILENAME_SIZE];

if (!cwd.openCwd()) {
char name[PFILENAME_SIZE];
cwd.getName(name, PFILENAME_SIZE);
cwd.getName(buffer, PFILENAME_SIZE);
Trace::Error("Failed to open cwd");
return;
}
char buffer[PFILENAME_SIZE];
cwd.getName(buffer, PFILENAME_SIZE);
Trace::Log("FILESYSTEM", "LIST DIR:%s", buffer);

Expand All @@ -144,6 +147,9 @@ void picoTrackerFileSystem::list(etl::ivector<int> *fileIndexes,

File entry;
uint16_t count = 0;

uint32_t sortKeys[MAX_FILE_INDEX_SIZE];

// ref: https://github.com/greiman/SdFat/issues/353#issuecomment-1003422848
while (entry.openNext(&cwd, O_READ) && (count < fileIndexes->capacity())) {
uint32_t index = entry.dirIndex();
Expand All @@ -157,25 +163,69 @@ void picoTrackerFileSystem::list(etl::ivector<int> *fileIndexes,
// matchesFilter);
}
// filter out "." and files that dont match filter if a filter is given
if ((entry.isDirectory() && entry.dirIndex() != 0) ||
((includeHidden || !entry.isHidden()) && matchesFilter)) {
if (subDirOnly) {
if (entry.isDirectory()) {
fileIndexes->push_back(index);
}
} else {
fileIndexes->push_back(index);
bool validDir = entry.isDirectory() && entry.dirIndex() != 0;
bool matchVisible = (!entry.isHidden() || includeHidden) && matchesFilter;

if ((validDir || matchVisible) && (!subDirOnly || entry.isDirectory())) {
if (sorted) {
entry.getName(buffer, PFILENAME_SIZE);
sortKeys[count] = FileSystem::getFileSortKey(buffer);
}
// Trace::Log("FILESYSTEM", "[%d] got file: %s", index, buffer);
fileIndexes->push_back(index);
count++;
// Trace::Log("FILESYSTEM", "[%d] got file: %s", index, buffer);
} else {
// Trace::Log("FILESYSTEM", "skipped hidden: %s", buffer);
// Trace::Log("FILESYSTEM", "skipped non-matching file: %s", buffer);
}
entry.close();
}
cwd.close();

Trace::Log("FILESYSTEM", "scanned: %d, added file indexes:%d", count,
fileIndexes->size());

if (!sorted) {
return;
}

// sort using insertion sort (with an extra step if our keys are identical)
char currentName[PFILENAME_SIZE];

for (size_t i = 1; i < count; i++) {
uint32_t key = sortKeys[i];
int index = fileIndexes->at(i);
size_t j = i;

while (j > 0) {
bool shouldMove = sortKeys[j - 1] > key;

if (!shouldMove && sortKeys[j - 1] == key) {
// keys are identical, do a tiebreaker by doing a string compare to
// ensure stable sorting of files with same first 4 letters
entry.open(index);
entry.getName(currentName, PFILENAME_SIZE);
entry.close();

entry.open(fileIndexes->at(j - 1));
entry.getName(buffer, PFILENAME_SIZE);
entry.close();

shouldMove = strcasecmp(buffer, currentName) > 0;
}

if (shouldMove) {
sortKeys[j] = sortKeys[j - 1];
fileIndexes->at(j) = fileIndexes->at(j - 1);
--j;
} else {
break;
}
}

sortKeys[j] = key;
fileIndexes->at(j) = index;
}

cwd.close();
}

void picoTrackerFileSystem::getFileName(int index, char *name, int length) {
Expand Down Expand Up @@ -277,18 +327,21 @@ bool picoTrackerFileSystem::CopyFile(const char *srcFilename,
auto fSrc = sd.open(srcFilename, O_READ);
auto fDest = sd.open(destFilename, O_WRITE | O_CREAT);

const int FILE_BUFFER_SIZE = 1024;
char fileBuffer[FILE_BUFFER_SIZE];

int n = 0;
int bufferSize = sizeof(fileBuffer_);

while (true) {
n = fSrc.read(fileBuffer_, bufferSize);
n = fSrc.read(fileBuffer, FILE_BUFFER_SIZE);
// check for read error and only write if no error
if (n >= 0) {
fDest.write(fileBuffer_, n);
fDest.write(fileBuffer, n);
} else {
Trace::Error("Failed to read file: %s", srcFilename);
return false;
}
if (n < bufferSize) {
if ((size_t)n < FILE_BUFFER_SIZE) {
break;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class picoTrackerFileSystem : public FileSystem {
virtual FileHandle Open(const char *name, const char *mode) override;
virtual bool chdir(const char *path) override;
virtual void list(etl::ivector<int> *fileIndexes, const char *filter,
bool subDirOnly, bool includeHidden = false) override;
ListFlags flags) override;
virtual void getFileName(int index, char *name, int length) override;
virtual PicoFileType getFileType(int index) override;
virtual bool isParentRoot() override;
Expand All @@ -50,9 +50,6 @@ class picoTrackerFileSystem : public FileSystem {
private:
SdFs sd;
void tolowercase(char *temp);
// buffer needs to be allocated here as too big for allocation as local
// variable on the stack
uint8_t fileBuffer_[512];
};

// Concrete implementation of PI_File for picoTracker
Expand Down
11 changes: 6 additions & 5 deletions sources/Adapters/picoTracker/gui/SerialDebugUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,14 @@ void SerialDebugUI::listFiles(const char *path) {
if (!fs->chdir(path)) {
Trace::Error("failed to ls files path:%s", path);
}
etl::vector<int, MAX_FILE_INDEX_SIZE> fileIndexes;
fs->list(&fileIndexes, "", false);

etl::vector<int, MAX_FILE_INDEX_SIZE> fileIndexList_;
fs->list(&fileIndexList_, "", LF_SORTED);

char name[PFILENAME_SIZE];
for (size_t i = 0; i < fileIndexes.size(); i++) {
fs->getFileName(fileIndexes[i], name, PFILENAME_SIZE);
if (fs->getFileType(fileIndexes[i]) == PFT_FILE) {
for (size_t i = 0; i < fileIndexList_.size(); i++) {
fs->getFileName(fileIndexList_[i], name, PFILENAME_SIZE);
if (fs->getFileType(fileIndexList_[i]) == PFT_FILE) {
printf("[file] %s\n", name);
} else {
printf("[dir] %s\n", name);
Expand Down
2 changes: 0 additions & 2 deletions sources/Application/AppWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,6 @@ AppWindow::AppWindow(I_GUIWindowImp &imp, const char *projectName)

// Init all members

_statusLine[0] = 0;

_currentView = nullptr;
_closeProject = false;
_lastA = 0;
Expand Down
4 changes: 3 additions & 1 deletion sources/Application/AppWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,16 @@ class AppWindow : public GUIWindow, I_Observer, Status {
using GUIWindow::Clear;
virtual void Clear(bool all = false);
virtual void ClearTextRect(GUIRect &rect);
using GUIWindow::SetColor;
virtual void SetColor(ColorDefinition cd);
void InvalidateTextCache();

void SetDirty();
void UpdateColorsFromConfig();
void SetSdCardPresent(bool present);

View *getCurrentView() const { return _currentView; }

char projectName_[MAX_PROJECT_NAME_LENGTH + 1];

protected: // GUIWindow implementation
Expand Down Expand Up @@ -104,7 +107,6 @@ class AppWindow : public GUIWindow, I_Observer, Status {
unsigned short _mask;
unsigned long _lastA;
unsigned long _lastB;
char _statusLine[80];

bool lowBatteryState_;
bool lowBatteryMessageShown_;
Expand Down
9 changes: 4 additions & 5 deletions sources/Application/Instruments/SamplePool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,9 @@ void SamplePool::Load(const char *projectName) {
PROJECT_SAMPLES_DIR);
}
// First, find all wav files
etl::vector<int, MAX_FILE_INDEX_SIZE> fileIndexes;
fs->list(&fileIndexes, ".wav", false);
fs->list(&fileIndexList_, ".wav", LF_SORTED);
char name[PFILENAME_SIZE];
uint totalSamples = fileIndexes.size();
uint totalSamples = fileIndexList_.size();

// store for ui updates
importCount = totalSamples;
Expand All @@ -69,8 +68,8 @@ void SamplePool::Load(const char *projectName) {
importIndex = i;
importName = name;

fs->getFileName(fileIndexes[i], name, PFILENAME_SIZE);
if (fs->getFileType(fileIndexes[i]) == PFT_FILE) {
fs->getFileName(fileIndexList_[i], name, PFILENAME_SIZE);
if (fs->getFileType(fileIndexList_[i]) == PFT_FILE) {
// Check if the filename exceeds the maximum allowed length
if (strlen(name) > MAX_INSTRUMENT_FILENAME_LENGTH) {
Trace::Error(
Expand Down
1 change: 1 addition & 0 deletions sources/Application/Instruments/SamplePool.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class SamplePool : public T_Factory<SamplePool>, public Observable {

private:
etl::vector<I_Observer *, MAX_SAMPLEINSTRUMENT_COUNT> observers_;
etl::vector<int, MAX_FILE_INDEX_SIZE> fileIndexList_;
};

#endif
18 changes: 9 additions & 9 deletions sources/Application/Persistency/PersistencyService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#include "PersistencyService.h"
#include "../Instruments/SamplePool.h"
#include "Foundation/Services/ServiceRegistry.h"

#include "Foundation/Types/Types.h"
#include "Persistent.h"
#include "System/Console/Trace.h"
Expand Down Expand Up @@ -78,13 +77,13 @@ bool PersistencyService::DeleteDirectoryContents_(uint8_t depth) {
}

while (true) {
fileIndexes_.clear();
fs->list(&fileIndexes_, "", false, true);
fileIndexList_.clear();
fs->list(&fileIndexList_, "", LF_INCLUDE_HIDDEN);

bool foundEntry = false;
bool deletedEntry = false;
for (size_t i = 0; i < fileIndexes_.size(); ++i) {
fs->getFileName(fileIndexes_[i], deleteNameBuffer_,
for (size_t i = 0; i < fileIndexList_.size(); ++i) {
fs->getFileName(fileIndexList_[i], deleteNameBuffer_,
sizeof(deleteNameBuffer_));

if ((strcmp(deleteNameBuffer_, ".") == 0) ||
Expand All @@ -94,7 +93,7 @@ bool PersistencyService::DeleteDirectoryContents_(uint8_t depth) {

foundEntry = true;

const PicoFileType type = fs->getFileType(fileIndexes_[i]);
const PicoFileType type = fs->getFileType(fileIndexList_[i]);
if (type == PFT_FILE) {
if (!fs->DeleteFile(deleteNameBuffer_)) {
Trace::Error("PERSISTENCYSERVICE: Could not delete file: %s",
Expand Down Expand Up @@ -194,10 +193,11 @@ PersistencyResult PersistencyService::Save(const char *projectName,
Trace::Debug("get list of samples to copy from old project: %s",
oldProjectName);

fs->list(&fileIndexes_, ".wav", false);
fs->list(&fileIndexList_, ".wav");
char filenameBuffer[PFILENAME_SIZE];
for (size_t i = 0; i < fileIndexes_.size(); i++) {
fs->getFileName(fileIndexes_[i], filenameBuffer, sizeof(filenameBuffer));
for (size_t i = 0; i < fileIndexList_.size(); i++) {
fs->getFileName(fileIndexList_[i], filenameBuffer,
sizeof(filenameBuffer));

// ignore . and .. entries as using *.wav doesnt filter them out
if (strcmp(filenameBuffer, ".") == 0 || strcmp(filenameBuffer, "..") == 0)
Expand Down
Loading
Loading