huge work on FAT32, initial support for writing
This commit is contained in:
179
ext/sd/fat32/File2.h
Normal file
179
ext/sd/fat32/File2.h
Normal file
@@ -0,0 +1,179 @@
|
||||
class File2 {
|
||||
|
||||
static constexpr const char* NAME = "FAT32_File2";
|
||||
static constexpr const uint32_t F_EOF = 0xFFFFFFFF;
|
||||
|
||||
FS& fs;
|
||||
DirEntryAt dea;
|
||||
|
||||
uint32_t curAbsPos = 0; // absolute position withithin the file
|
||||
uint32_t posInCluster = 0; // position within the current cluster
|
||||
uint32_t iCurCluster = 0; // current cluster index (within list of clusters)
|
||||
|
||||
std::vector<ClusterNr> clusters; // all clusters the file uses
|
||||
|
||||
public:
|
||||
|
||||
File2(FS& fs, const DirEntryAt& dea) : fs(fs), dea(dea) {
|
||||
Log::addInfo(NAME, "init @ cluster %d", getFirstCluster());
|
||||
getAllClusters(dea.getFirstCluster());
|
||||
}
|
||||
|
||||
/** the file's USED size */
|
||||
uint32_t getSize() const {return dea.getSize();}
|
||||
|
||||
/** the file's ALLOCATED size */
|
||||
uint32_t getAllocatedSize() const {return clusters.size() * fs.tmp.bytesPerCluster;}
|
||||
|
||||
/** the file's first cluster */
|
||||
ClusterNr getFirstCluster() const {return dea.getFirstCluster();}
|
||||
|
||||
/** get the file's name */
|
||||
const std::string& getName() const {return dea.getName();}
|
||||
|
||||
|
||||
/** read x bytes from the file */
|
||||
uint32_t read(uint32_t size, uint8_t* dst, std::function<void(int)> callback) {
|
||||
|
||||
Log::addInfo(NAME, "read %d bytes", size);
|
||||
|
||||
uint32_t remaining = size;
|
||||
uint32_t totalRead = 0;
|
||||
|
||||
while(remaining) {
|
||||
const uint32_t read = _read(remaining, dst);
|
||||
if (read == F_EOF) {
|
||||
Log::addInfo(NAME, "EOF"); break;
|
||||
}
|
||||
remaining -= read;
|
||||
dst += read;
|
||||
totalRead += read;
|
||||
callback(totalRead*100/size);
|
||||
}
|
||||
|
||||
return totalRead;
|
||||
|
||||
}
|
||||
|
||||
uint32_t write(uint32_t size, const uint8_t* src, std::function<void(int)> callback) {
|
||||
|
||||
Log::addInfo(NAME, "write %d bytes", size);
|
||||
|
||||
uint32_t remaining = size;
|
||||
uint32_t totalWritten = 0;
|
||||
|
||||
while(remaining) {
|
||||
const uint32_t written = _write(remaining, src);
|
||||
remaining -= written;
|
||||
src += written;
|
||||
totalWritten += written;
|
||||
callback(totalWritten*100/size);
|
||||
}
|
||||
|
||||
// update the file header (size might have changed)
|
||||
fs.write(dea);
|
||||
|
||||
return totalWritten;
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void setSize(uint32_t size) {dea.setSize(size);}
|
||||
|
||||
/** fetch the list of all clusters the file is using */
|
||||
void getAllClusters(ClusterNr startCluster) {
|
||||
|
||||
// initial cluster
|
||||
clusters.push_back(startCluster);
|
||||
|
||||
// all following clusters
|
||||
while(true) {
|
||||
startCluster = fs.getNextCluster(startCluster);
|
||||
if (!startCluster.isEndOfClusters()) {
|
||||
clusters.push_back(startCluster);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// debug
|
||||
char buf[1024];
|
||||
char* dst = buf; dst += sprintf(dst, "clusters: ");
|
||||
for (ClusterNr nr : clusters) {dst += sprintf(dst, "%d ", nr);}
|
||||
Log::addInfo(NAME, buf);
|
||||
|
||||
}
|
||||
|
||||
int32_t _read(uint32_t readSize, uint8_t* dst) {
|
||||
|
||||
// EOF reached?
|
||||
if (curAbsPos >= getSize()) {
|
||||
return F_EOF;
|
||||
}
|
||||
|
||||
// end of current cluster reached? -> switch to the next one
|
||||
if (posInCluster == fs.tmp.bytesPerCluster) {
|
||||
++iCurCluster;
|
||||
posInCluster = 0;
|
||||
Log::addInfo(NAME, "next cluster [%d] %d", iCurCluster, clusters[iCurCluster]);
|
||||
}
|
||||
|
||||
// how many bytes are left in the current cluster?
|
||||
const uint32_t remainingInCluster = fs.tmp.bytesPerCluster - posInCluster;
|
||||
|
||||
// determine how many bytes to read
|
||||
const uint32_t toRead = std::min(remainingInCluster, readSize);
|
||||
|
||||
const uint32_t offset = fs.clusterToAbsPos(clusters[iCurCluster]) + posInCluster;
|
||||
const uint32_t read = fs.dev.read(offset, toRead, dst);
|
||||
posInCluster += read;
|
||||
curAbsPos += read;
|
||||
|
||||
return read;
|
||||
|
||||
}
|
||||
|
||||
int32_t _write(uint32_t writeSize, const uint8_t* src) {
|
||||
|
||||
if (curAbsPos >= getAllocatedSize()) {
|
||||
if (clusters.empty()) {
|
||||
const ClusterNr newCluster = fs.allocFreeCluster(0);
|
||||
clusters.push_back(newCluster);
|
||||
Log::addInfo(NAME, "allocFirstCluster: %d", newCluster);
|
||||
} else {
|
||||
const ClusterNr prevCluster = clusters.back();
|
||||
const ClusterNr newCluster = fs.allocFreeCluster(prevCluster);
|
||||
clusters.push_back(newCluster);
|
||||
Log::addInfo(NAME, "allocNextCluster(%d): %d", prevCluster, newCluster);
|
||||
}
|
||||
dea.setSize(dea.getSize() + fs.tmp.bytesPerCluster);
|
||||
fs.write(dea);
|
||||
}
|
||||
|
||||
// end of current cluster reached? -> switch to the next one
|
||||
if (posInCluster == fs.tmp.bytesPerCluster) {
|
||||
++iCurCluster;
|
||||
posInCluster = 0;
|
||||
Log::addInfo(NAME, "next cluster [%d] %d", iCurCluster, clusters[iCurCluster]);
|
||||
}
|
||||
|
||||
// how many bytes are left in the current cluster?
|
||||
const uint32_t remainingInCluster = fs.tmp.bytesPerCluster - posInCluster;
|
||||
|
||||
// determine how many bytes to write
|
||||
const uint32_t toWrite = std::min(remainingInCluster, writeSize);
|
||||
|
||||
const uint32_t offset = fs.clusterToAbsPos(clusters[iCurCluster]) + posInCluster;
|
||||
const uint32_t written = fs.dev.write(offset, toWrite, src);
|
||||
posInCluster += written;
|
||||
curAbsPos += written;
|
||||
|
||||
// adjust the number of bytes used
|
||||
if (this->getSize() < curAbsPos) {this->setSize(curAbsPos);}
|
||||
|
||||
return written;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user