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

void advFileSystem::list(etl::ivector<int> *fileIndexes, const char *filter,
bool subDirOnly, bool includeHidden) {
bool subDirOnly, bool includeHidden, bool sorted) {

fileIndexes->clear();

Expand All @@ -155,6 +155,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 +189,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
3 changes: 2 additions & 1 deletion sources/Adapters/adv/filesystem/advFileSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ 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;
bool subDirOnly, bool includeHidden = false,
bool sorted = false) 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_, "", false, false, true);

// 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
89 changes: 70 additions & 19 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 @@ -121,19 +122,19 @@ PicoFileType picoTrackerFileSystem::getFileType(int index) {

void picoTrackerFileSystem::list(etl::ivector<int> *fileIndexes,
const char *filter, bool subDirOnly,
bool includeHidden) {
bool includeHidden, bool sorted) {
Comment thread
n1LS marked this conversation as resolved.
Outdated
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 +145,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 +161,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 +325,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,8 @@ 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;
bool subDirOnly, bool includeHidden = false,
bool sorted = false) 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 +51,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_, "", false, false, true);

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", false, false, true);
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_, "", false, true);

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", false);
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