LCD Driver, some teensy code, SDCard code, MBR/FAT32
This commit is contained in:
45
ext/sd/fat32/DirIterator.h
Normal file
45
ext/sd/fat32/DirIterator.h
Normal file
@@ -0,0 +1,45 @@
|
||||
class DirIterator {
|
||||
|
||||
FS& fs;
|
||||
ClusterNr nextCluster;
|
||||
int curEntryInCluster;
|
||||
uint8_t buf[512];
|
||||
|
||||
public:
|
||||
|
||||
DirIterator(FS& fs, ClusterNr clusterNr) : fs(fs), nextCluster(clusterNr), curEntryInCluster(255) {
|
||||
|
||||
}
|
||||
|
||||
bool hasNext() {
|
||||
|
||||
while(true) {
|
||||
|
||||
++curEntryInCluster;
|
||||
|
||||
// reached end of cluster? load the next one
|
||||
if (curEntryInCluster > fs.tmp.dirEntriesPerSector) {
|
||||
fs.dev.read(fs.clusterToAbsPos(nextCluster), 512, buf);
|
||||
nextCluster = fs.getNextCluster(nextCluster);
|
||||
curEntryInCluster = 0;
|
||||
}
|
||||
|
||||
DirEntry* desc = reinterpret_cast<DirEntry*>(buf + (sizeof(DirEntry) * curEntryInCluster));
|
||||
|
||||
if (desc->isLongFileName()) {continue;}
|
||||
if (desc->isUnused()) {continue;}
|
||||
if (desc->isEndOfDirectory()) {return false;}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DirEntry next() {
|
||||
DirEntry* de = reinterpret_cast<DirEntry*>(buf + (sizeof(DirEntry) * curEntryInCluster));
|
||||
return *de;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
100
ext/sd/fat32/FS.h
Normal file
100
ext/sd/fat32/FS.h
Normal file
@@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include "Structs.h"
|
||||
|
||||
// https://www.pjrc.com/tech/8051/ide/fat32.html
|
||||
namespace FAT32 {
|
||||
|
||||
template <typename BlockDev> class FS {
|
||||
|
||||
static constexpr const char* NAME = "FAT32";
|
||||
|
||||
BlockDev& dev;
|
||||
AbsOffset offset;
|
||||
|
||||
|
||||
FSDesc desc;
|
||||
Precomputed tmp;
|
||||
bool valid = false;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
#include "File.h"
|
||||
#include "DirIterator.h"
|
||||
|
||||
/** ctor with the absolute offset addr (in bytes) */
|
||||
FS(BlockDev& dev, AbsOffset offset) : dev(dev), offset(offset) {
|
||||
init();
|
||||
}
|
||||
|
||||
/** is the detected FS valid? */
|
||||
bool isValid() const {
|
||||
return valid;
|
||||
}
|
||||
|
||||
/** get an iterator for the root directory */
|
||||
DirIterator getRoot() {
|
||||
return DirIterator(*this, desc.rootDirFirstCluster);
|
||||
}
|
||||
|
||||
/** open the given file for reading*/
|
||||
File open(const DirEntry& de) {
|
||||
return File(*this, de.getFirstCluster(), de.size);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void init() {
|
||||
|
||||
debugMod3(NAME")
|
||||
uint8_t buf[512];
|
||||
dev.read(offset, 512, buf);
|
||||
|
||||
desc.bytesPerSector = getU16(&buf[0x0B]);
|
||||
desc.sectorsPerCluster = getU8(&buf[0x0D]);
|
||||
desc.numReservedSectors = getU16(&buf[0x0E]);
|
||||
desc.numberOfFATs = getU8(&buf[0x10]);
|
||||
desc.sectorsPerFAT = getU32(&buf[0x24]);
|
||||
desc.rootDirFirstCluster = getU32(&buf[0x2C]);
|
||||
|
||||
// basic sanity check based on constants
|
||||
valid = (desc.bytesPerSector == 512) && (desc.numberOfFATs == 2) && (getU16(&buf[0x1FE]) == 0xAA55);
|
||||
|
||||
tmp.bytesPerCluster = desc.sectorsPerCluster * desc.bytesPerSector;
|
||||
tmp.startOfFAT = offset + (desc.numReservedSectors * desc.bytesPerSector);
|
||||
tmp.startOfFirstDataCluster = offset + (desc.numReservedSectors * desc.bytesPerSector) + (desc.numberOfFATs * desc.sectorsPerFAT * desc.bytesPerSector);
|
||||
tmp.startOfFirstRootDirCluster = clusterToAbsPos(desc.rootDirFirstCluster);
|
||||
tmp.dirEntriesPerSector = desc.bytesPerSector / sizeof(DirEntry);
|
||||
|
||||
/*
|
||||
std::cout << (int)desc.bytesPerSector << std::endl;
|
||||
std::cout << (int)desc.sectorsPerCluster << std::endl;
|
||||
std::cout << (int)desc.numReservedSectors << std::endl;
|
||||
std::cout << (int)desc.numberOfFATs << std::endl;
|
||||
std::cout << (int)desc.sectorsPerFAT << std::endl;
|
||||
std::cout << (int)desc.rootDirFirstCluster << std::endl;
|
||||
|
||||
std::cout << tmp.startOfFAT << std::endl;
|
||||
std::cout << tmp.startOfFirstDataCluster << std::endl;
|
||||
std::cout << tmp.startOfFirstRootDirCluster << std::endl;
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
/** determine the ClusterNr following the given ClusterNr */
|
||||
ClusterNr getNextCluster(ClusterNr clusterNr) {
|
||||
const AbsPos pos = tmp.startOfFAT + ((clusterNr) * sizeof(uint32_t));
|
||||
ClusterNr next;
|
||||
int read = dev.read(pos, 4, reinterpret_cast<uint8_t*>(&next));
|
||||
return next;
|
||||
}
|
||||
|
||||
/** convert ClusterNr into an absolute position on disk */
|
||||
AbsPos clusterToAbsPos(ClusterNr clusterNr) {
|
||||
return tmp.startOfFirstDataCluster + ((clusterNr - 2) * desc.sectorsPerCluster * desc.bytesPerSector);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
100
ext/sd/fat32/FS.h.autosave
Normal file
100
ext/sd/fat32/FS.h.autosave
Normal file
@@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include "Structs.h"
|
||||
|
||||
// https://www.pjrc.com/tech/8051/ide/fat32.html
|
||||
namespace FAT32 {
|
||||
|
||||
template <typename BlockDev> class FS {
|
||||
|
||||
static constexpr const char* NAME = "FAT32";
|
||||
|
||||
BlockDev& dev;
|
||||
AbsOffset offset;
|
||||
|
||||
|
||||
FSDesc desc;
|
||||
Precomputed tmp;
|
||||
bool valid = false;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
#include "File.h"
|
||||
#include "DirIterator.h"
|
||||
|
||||
/** ctor with the absolute offset addr (in bytes) */
|
||||
FS(BlockDev& dev, AbsOffset offset) : dev(dev), offset(offset) {
|
||||
init();
|
||||
}
|
||||
|
||||
/** is the detected FS valid? */
|
||||
bool isValid() const {
|
||||
return valid;
|
||||
}
|
||||
|
||||
/** get an iterator for the root directory */
|
||||
DirIterator getRoot() {
|
||||
return DirIterator(*this, desc.rootDirFirstCluster);
|
||||
}
|
||||
|
||||
/** open the given file for reading*/
|
||||
File open(const DirEntry& de) {
|
||||
return File(*this, de.getFirstCluster(), de.size);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void init() {
|
||||
|
||||
debugMod3(NAME)
|
||||
uint8_t buf[512];
|
||||
dev.read(offset, 512, buf);
|
||||
|
||||
desc.bytesPerSector = getU16(&buf[0x0B]);
|
||||
desc.sectorsPerCluster = getU8(&buf[0x0D]);
|
||||
desc.numReservedSectors = getU16(&buf[0x0E]);
|
||||
desc.numberOfFATs = getU8(&buf[0x10]);
|
||||
desc.sectorsPerFAT = getU32(&buf[0x24]);
|
||||
desc.rootDirFirstCluster = getU32(&buf[0x2C]);
|
||||
|
||||
// basic sanity check based on constants
|
||||
valid = (desc.bytesPerSector == 512) && (desc.numberOfFATs == 2) && (getU16(&buf[0x1FE]) == 0xAA55);
|
||||
|
||||
tmp.bytesPerCluster = desc.sectorsPerCluster * desc.bytesPerSector;
|
||||
tmp.startOfFAT = offset + (desc.numReservedSectors * desc.bytesPerSector);
|
||||
tmp.startOfFirstDataCluster = offset + (desc.numReservedSectors * desc.bytesPerSector) + (desc.numberOfFATs * desc.sectorsPerFAT * desc.bytesPerSector);
|
||||
tmp.startOfFirstRootDirCluster = clusterToAbsPos(desc.rootDirFirstCluster);
|
||||
tmp.dirEntriesPerSector = desc.bytesPerSector / sizeof(DirEntry);
|
||||
|
||||
/*
|
||||
std::cout << (int)desc.bytesPerSector << std::endl;
|
||||
std::cout << (int)desc.sectorsPerCluster << std::endl;
|
||||
std::cout << (int)desc.numReservedSectors << std::endl;
|
||||
std::cout << (int)desc.numberOfFATs << std::endl;
|
||||
std::cout << (int)desc.sectorsPerFAT << std::endl;
|
||||
std::cout << (int)desc.rootDirFirstCluster << std::endl;
|
||||
|
||||
std::cout << tmp.startOfFAT << std::endl;
|
||||
std::cout << tmp.startOfFirstDataCluster << std::endl;
|
||||
std::cout << tmp.startOfFirstRootDirCluster << std::endl;
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
/** determine the ClusterNr following the given ClusterNr */
|
||||
ClusterNr getNextCluster(ClusterNr clusterNr) {
|
||||
const AbsPos pos = tmp.startOfFAT + ((clusterNr) * sizeof(uint32_t));
|
||||
ClusterNr next;
|
||||
int read = dev.read(pos, 4, reinterpret_cast<uint8_t*>(&next));
|
||||
return next;
|
||||
}
|
||||
|
||||
/** convert ClusterNr into an absolute position on disk */
|
||||
AbsPos clusterToAbsPos(ClusterNr clusterNr) {
|
||||
return tmp.startOfFirstDataCluster + ((clusterNr - 2) * desc.sectorsPerCluster * desc.bytesPerSector);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
64
ext/sd/fat32/File.h
Normal file
64
ext/sd/fat32/File.h
Normal file
@@ -0,0 +1,64 @@
|
||||
class File {
|
||||
|
||||
static constexpr const int32_t F_EOF = -1;
|
||||
|
||||
FS& fs;
|
||||
uint32_t totalSize;
|
||||
|
||||
uint32_t curAbsPos = 0; // position withithin the whole file
|
||||
uint32_t curCluster = 0; // cluster we are currently reading
|
||||
uint32_t posInCluster = 0; // position within the current cluster
|
||||
|
||||
|
||||
public:
|
||||
|
||||
File(FS& fs, uint32_t firstCluster, uint32_t size) : fs(fs), totalSize(size), curCluster(firstCluster) {
|
||||
|
||||
}
|
||||
|
||||
/** the file's size */
|
||||
uint32_t getSize() const {return totalSize;}
|
||||
|
||||
uint32_t read(uint32_t size, uint8_t* dst) {
|
||||
uint32_t total = 0;
|
||||
while(true) {
|
||||
const uint32_t read = _read(size, dst);
|
||||
if (read == F_EOF) {break;}
|
||||
size -= read;
|
||||
dst += read;
|
||||
total += read;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
int32_t _read(uint32_t readSize, uint8_t* dst) {
|
||||
|
||||
// EOF reached?
|
||||
if (curAbsPos >= totalSize) {
|
||||
return F_EOF;
|
||||
}
|
||||
|
||||
// end of current cluster reached? -> determine the next one
|
||||
if (posInCluster == fs.tmp.bytesPerCluster) {
|
||||
curCluster = fs.getNextCluster(curCluster);
|
||||
posInCluster = 0;
|
||||
}
|
||||
|
||||
// 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(curCluster) + posInCluster;
|
||||
const uint32_t read = fs.dev.read(offset, toRead, dst);
|
||||
posInCluster += read;
|
||||
curAbsPos += read;
|
||||
|
||||
return read;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
77
ext/sd/fat32/Structs.h
Normal file
77
ext/sd/fat32/Structs.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace FAT32 {
|
||||
|
||||
using ClusterNr = uint32_t;
|
||||
using AbsOffset = uint32_t;
|
||||
using AbsPos = uint32_t;
|
||||
|
||||
struct FSDesc {
|
||||
uint16_t bytesPerSector;
|
||||
uint8_t sectorsPerCluster;
|
||||
uint16_t numReservedSectors;
|
||||
uint8_t numberOfFATs;
|
||||
uint32_t sectorsPerFAT;
|
||||
ClusterNr rootDirFirstCluster;
|
||||
};
|
||||
|
||||
struct Precomputed {
|
||||
uint32_t bytesPerCluster;
|
||||
AbsPos startOfFAT; // absolute byte offset where the FAT begins
|
||||
AbsPos startOfFirstDataCluster; // absolute byte offset where the first cluster is
|
||||
AbsPos startOfFirstRootDirCluster; // absolute byte offset where the first root dir cluster is
|
||||
uint32_t dirEntriesPerSector;
|
||||
};
|
||||
|
||||
union Attributes {
|
||||
uint8_t raw;
|
||||
struct {
|
||||
uint8_t readOnly : 1;
|
||||
uint8_t hidden : 1;
|
||||
uint8_t system : 1;
|
||||
uint8_t volumeID : 1;
|
||||
uint8_t directory : 1;
|
||||
uint8_t archive : 1;
|
||||
uint8_t unused1 : 1;
|
||||
uint8_t unused2 : 1;
|
||||
} bits;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct DirEntry {
|
||||
|
||||
unsigned char name[8];
|
||||
unsigned char ext[3];
|
||||
Attributes attr;
|
||||
uint8_t dummy1[8];
|
||||
uint16_t firstClusterHi;
|
||||
uint8_t dummy2[4];
|
||||
uint16_t firstClusterLo;
|
||||
uint32_t size; // file size in bytes
|
||||
|
||||
bool isUnused() const {return name[0] == 0xE5;}
|
||||
bool isDirectory() const {return attr.bits.directory;}
|
||||
bool isEndOfDirectory() const {return name[0] == 0x00;}
|
||||
bool isLongFileName() const {return (attr.raw & 0b1111) == 0b1111;}
|
||||
|
||||
uint32_t getFirstCluster() const {return firstClusterHi<<16 | firstClusterLo<<0;}
|
||||
|
||||
std::string getName() const {
|
||||
char buf[16];
|
||||
uint8_t pos = 0;
|
||||
for (uint8_t i = 0; i < 8; ++i) {if (name[i] != ' ') {buf[pos++] = name[i];}}
|
||||
buf[pos++] = '.';
|
||||
for (uint8_t i = 0; i < 8; ++i) {if ( ext[i] != ' ') {buf[pos++] = ext[i];}}
|
||||
buf[pos] = 0;
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
static inline uint16_t getU8(const uint8_t* src) {return src[0];}
|
||||
static inline uint16_t getU16(const uint8_t* src) {return src[0]<<0 | src[1]<<8;}
|
||||
static inline uint32_t getU32(const uint8_t* src) {return src[0]<<0 | src[1]<<8 | src[2]<<16 | src[3]<<24;}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user