worked on FAT32 stuff

This commit is contained in:
2021-02-21 09:33:08 +01:00
parent da12992ae8
commit 4ac72c678f
13 changed files with 494 additions and 148 deletions

57
Debug.h
View File

@@ -31,41 +31,54 @@ extern "C" {
class Log {
public:
template<typename... Args> static void addInfo(const char* module, const char* fmt, Args... args) {
template<typename... Args> static inline void addInfo(const char* module, const char* fmt, Args... args) {
add('i', module, fmt, args...);
}
template<typename... Args> static void addError(const char* module, const char* fmt, Args... args) {
template<typename... Args> static inline void addError(const char* module, const char* fmt, Args... args) {
add('e', module, fmt, args...);
while(true) {}
//while(true) {}
}
private:
template<typename... Args> static void add(char level, const char* module, const char* fmt, Args... args) {
char buf[4096];
char* dst = buf;
#if defined(WITH_LOG)
dst = dst + sprintf(dst, "%c[%-10s] ", level, module);
dst = dst + sprintf(dst, fmt, args...);
dst = dst + sprintf(dst, "\n");
template<typename... Args> static void add(char level, const char* module, const char* fmt, Args... args) {
#ifdef IS_DESKTOP
printf(buf);
#elif TEENSY
Serial.print(buf);
#elif ESP8266
os_printf(buf);
#elif ESP32
printf(buf);
#else
#error "unsupported platform"
#endif
// temporal buffer (NOTE! MUST NOT BE TOO LARGE OR IT CAN KILL THE STACK!)
char buf[512];
}
char* dst = buf;
char* end = buf + sizeof(buf);
dst = dst + snprintf(dst, (end-dst), "%c[%-10s] ", level, module);
dst = dst + snprintf(dst, (end-dst)-2, fmt, args...);
dst = dst + snprintf(dst, (end-dst), "\n");
#if IS_DESKTOP
printf(buf);
#elif TEENSY
Serial.print(buf);
#elif ESP8266
os_printf(buf);
#elif ESP32
printf(buf);
#else
#error "unsupported platform"
#endif
}
#else
template<typename... Args> static void add(char , const char* , const char* , Args... ) {}
#endif
};

View File

@@ -38,7 +38,7 @@ public:
if (offset || size < SEC_SIZE) { // non-aligned / non-full-block write
// read the whole sector
if (!readSingleBlock(addrLBA, buf)) {return written;}
if (!readBlock(addrLBA, buf)) {return written;}
// merge in the new data
const uint32_t toModify = min(SEC_SIZE-offset, size);
@@ -46,7 +46,7 @@ public:
offset = 0;
// write back the modified sector
if (!writeSingleBlock(addrLBA, buf)) {return written;}
if (!writeBlock(addrLBA, buf)) {return written;}
++addrLBA;
size -= toModify;
@@ -55,7 +55,7 @@ public:
} else {
// write a full block
if (!writeSingleBlock(addrLBA, &src[written])) {return written;}
if (!writeBlock(addrLBA, &src[written])) {return written;}
++addrLBA;
size -= SEC_SIZE;
@@ -83,7 +83,7 @@ public:
if (offset || size < SEC_SIZE) { // non-aligned read / non-full-block read
const uint32_t toRead = min(SEC_SIZE-offset, size);
if (!readSingleBlock(addrLBA, &dst[read], offset, toRead)) {return read;}
if (!readBlock(addrLBA, &dst[read], offset, toRead)) {return read;}
offset = 0; // all following reads are aligned
++addrLBA;
@@ -92,7 +92,7 @@ public:
} else { // full block read
if (!readSingleBlock(addrLBA, &dst[read])) {return read;}
if (!readBlock(addrLBA, &dst[read])) {return read;}
++addrLBA;
size -= SEC_SIZE;
read += SEC_SIZE;
@@ -106,14 +106,14 @@ public:
}
/** read a single block of SEC_SIZE bytes. addr = byteAddr/512 */
bool readSingleBlock(LBA512 addr, uint8_t* dst) {
return dev.readSingleBlock(addr, dst);
bool readBlock(LBA512 addr, uint8_t* dst) {
return dev.readBlock(addr, dst);
}
/** read a single block of SEC_SIZE bytes. addr = byteAddr/512, write only a fraction of the 512 bytes into dst (skip+len) */
bool readSingleBlock(LBA512 addr, uint8_t* dst, uint16_t skip, uint16_t len) {
bool readBlock(LBA512 addr, uint8_t* dst, uint16_t skip, uint16_t len) {
uint8_t buf[SEC_SIZE];
if (!dev.readSingleBlock(addr, buf)) {return false;}
if (!dev.readBlock(addr, buf)) {return false;}
for (int i = 0; i < len; ++i) {
*dst = buf[i+skip];
++dst;
@@ -122,8 +122,8 @@ public:
}
/** write a single block of 512 bytes. addr = byteAddr/512 */
bool writeSingleBlock(LBA512 addr, const uint8_t* src) {
return dev.writeSingleBlock(addr, src);
bool writeBlock(LBA512 addr, const uint8_t* src) {
return dev.writeBlock(addr, src);
}

View File

@@ -38,6 +38,7 @@ ADD_DEFINITIONS(
-Warray-bounds
-fstack-protector-all
-DWITH_LOG
-g
-O0
@@ -65,6 +66,7 @@ ADD_EXECUTABLE(
TARGET_LINK_LIBRARIES(
${PROJECT_NAME}
gtest
fmt
# pthread
${EXTRA_LIBS}
)

76
ext/sd/CRC16.h Normal file
View File

@@ -0,0 +1,76 @@
#pragma once
static constexpr const uint16_t tblCRC16[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
};
class CRC16 {
public:
static uint16_t get(const uint8_t* pData, size_t length) {
const uint32_t* p = (const uint32_t*)pData;
//assert ( (length & 3) == 0 );
// Calculate the CRC16 checksum for the specified data block.
// Unrolled loop which processes 4-bytes per iteration.
uint16_t crc = 0;
while (length) {
uint32_t data = *p++;
data = ((data >> 8) & 0x00FF00FF) | ((data << 8) & 0xFF00FF00);
crc ^= data;
crc = (crc << 8) ^ tblCRC16[(crc >> 8) & 0x00FF];
crc = (crc << 8) ^ tblCRC16[(crc >> 8) & 0x00FF];
crc ^= data >> 16;
crc = (crc << 8) ^ tblCRC16[(crc >> 8) & 0x00FF];
crc = (crc << 8) ^ tblCRC16[(crc >> 8) & 0x00FF];
length -= 4;
}
// Return the calculated checksum
return crc;
}
};

View File

@@ -2,6 +2,7 @@
#include "../../io/GPIO.h"
#include "../../Debug.h"
#include "CRC16.h"
#define TEENSY_SD_PIN_CS 46
#define TEENSY_SD_PIN_MOSI 45
@@ -17,7 +18,7 @@
template <typename SPI, int PIN_CS> class SDCard {
SPI& spi;
union R1 { // SanDisk Manual Page 5-13
uint8_t raw;
struct {
@@ -60,7 +61,7 @@ template <typename SPI, int PIN_CS> class SDCard {
public:
SDCard(SPI& spi) : spi(spi) {
}
bool init() {
@@ -117,39 +118,111 @@ public:
}
private:
//LBA512 lastReadBlock = 0xFFFFFFFF;
//LBA512 lastWriteBlock = 0xFFFFFFFF;
public:
/** read a single block of 512 bytes, addr = byteAddr/512 */
bool readSingleBlock(LBA512 addr, uint8_t* dst) {
sendCMD(17, addr>>24, addr>>16, addr>>8, addr>>0, 0xFF);
R1 res; readResponse(&res.raw, 1);
bool readBlock(LBA512 addr, uint8_t* dst) {
Log::addInfo(NAME, "readBlock(%d*512): %02x", addr, res.raw);
/*
if (lastReadBlock == 0xFFFFFFFF) {
if (!startMultiRead(addr)) {endCMD(); return false;}
if (!readMultiBlock(dst)) {endCMD(); return false;}
// read command OK?
if (res.raw != 0) {Log::addError(NAME, "failed"); endCMD(); return false;}
// wait for data to become available
for (uint16_t i = 0; ; ++i) {
uint8_t res = spi.readWriteByte(0xFF);
if (res == 0xFE) {break;} // available!
if (res != 0xFF) {Log::addError(NAME, "invalid"); endCMD(); return false;} // invalid response
if (i > 1024) {Log::addError(NAME, "timeout"); endCMD(); return false;} // timeout
} else if ((lastReadBlock + 1) == addr) {
if (!readMultiBlock(dst)) {endCMD(); return false;}
} else {
if (!stopMultiRead()) {endCMD(); return false;}
if (!startMultiRead(addr)) {endCMD(); return false;}
if (!readMultiBlock(dst)) {endCMD(); return false;}
}
// read data
for (uint16_t i = 0; i < 512; ++i) {
dst[i] = spi.readWriteByte(0xFF);
}
// done
endCMD();
lastReadBlock = addr;
return true;
*/
// bulletproof, but slower
return readSingleBlock(addr, dst);
}
/** write a single block of 512 bytes, addr = byteAddr/512 */
bool writeBlock(LBA512 addr, const uint8_t* src) {
// bulletproof, but slow
return writeSingleBlock(addr, src);
}
private:
/*
bool startMultiRead(LBA512 addr) {
sendCMD(18, addr>>24, addr>>16, addr>>8, addr>>0, 0xFF);
R1 res; readResponse(&res.raw, 1);
Log::addInfo(NAME, "startMultiRead(%d*512): %02x", addr, res.raw);
if (res.raw != 0) {Log::addError(NAME, "failed"); endCMD(); return false;}
// wait for data to become available
for (uint16_t i = 0; ; ++i) {
uint8_t res = spi.readWriteByte(0xFF);
if (res == 0xFE) {break;} // available!
if (res != 0xFF) {Log::addError(NAME, "invalid"); endCMD(); return false;} // invalid response
if (i > 1024) {Log::addError(NAME, "timeout"); endCMD(); return false;} // timeout
}
return true;
}
bool readMultiBlock(uint8_t* dst) {
Log::addInfo(NAME, "readMultiBlock()");
for (uint16_t i = 0; i < 512; ++i) {
dst[i] = spi.readWriteByte(0xFF);
}
return true;
}
bool stopMultiRead() {
sendCMD(12, 0,0,0,0, 0xFF);
R1 res; readResponse(&res.raw, 1);
Log::addInfo(NAME, "stopMultiRead(): %02x", res.raw);
endCMD();
lastReadBlock = 0xFFFFFFFF;
return true;//(res.raw == 0);
}
*/
/** select the card (CS = low) */
void select() {
spi.writeByte(0xFF);
MyGPIO::clear(PIN_CS);
spi.writeByte(0xFF);
}
/** deselect the card (CS = high) */
void deselect() {
spi.writeByte(0xFF);
MyGPIO::set(PIN_CS);
spi.writeByte(0xFF);
}
/** send a new command */
void sendCMD(uint8_t cmd, uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t arg3, uint8_t crc) {
@@ -226,11 +299,8 @@ private:
}
/** read the card's response to the last command */
void readResponse(uint8_t* dst, uint8_t len) {
// the SD card takes some time to answer, but must receive clock signals meanwhile!
@@ -253,18 +323,102 @@ private:
/** select the card (CS = low) */
void select() {
spi.writeByte(0xFF);
MyGPIO::clear(PIN_CS);
spi.writeByte(0xFF);
private:
/** most simple read operation: read a single block of 512 bytes, addr = byteAddr/512 */
bool readSingleBlock(LBA512 addr, uint8_t* dst) {
sendCMD(17, addr>>24, addr>>16, addr>>8, addr>>0, 0xFF);
R1 res; readResponse(&res.raw, 1);
Log::addInfo(NAME, "readSingleBlock(%d*512): %02x", addr, res.raw);
// read command OK?
if (res.raw != 0) {Log::addError(NAME, "failed"); endCMD(); return false;}
// wait for data to become available
for (uint16_t i = 0; ; ++i) {
uint8_t res = spi.readWriteByte(0xFF);
if (res == 0xFE) {break;} // available!
if (res != 0xFF) {Log::addError(NAME, "invalid"); endCMD(); return false;} // invalid response
if (i > 1024) {Log::addError(NAME, "timeout"); endCMD(); return false;} // timeout
}
// read data
for (uint16_t i = 0; i < 512; ++i) {
dst[i] = spi.readWriteByte(0xFF);
}
// done
endCMD();
return true;
}
/** deselect the card (CS = high) */
void deselect() {
spi.writeByte(0xFF);
MyGPIO::set(PIN_CS);
spi.writeByte(0xFF);
bool waitWhileBusy() {
Log::addInfo(NAME, "waitWhileBusy()");
uint8_t res = 0;
for (uint16_t i = 0; ; ++i) {
res = spi.readWriteByte(0xFF);
if (res == 0xFF) {return true;}
if (i >= 1024) {return false;} // timeout
}
}
/** most simple write operation: write a single block of 512 bytes, addr = byteAddr/512 */
bool writeSingleBlock(LBA512 addr, const uint8_t* src) {
sendCMD(24, addr>>24, addr>>16, addr>>8, addr>>0, 0xFF);
R1 res; readResponse(&res.raw, 1);
Log::addInfo(NAME, "writeSingleBlock(%d*512): %02x", addr, res.raw);
// write command OK?
if (res.raw != 0) {Log::addError(NAME, "failed"); endCMD(); return false;}
// wait while the card is busy
if (!waitWhileBusy()) {Log::addError(NAME, "busy timeout"); endCMD(); return false;}
// send BLOCK_START
spi.writeByte(0xFE);
// send data
for (uint16_t i = 0; i < 512; ++i) {
spi.writeByte(src[i]);
}
// send CRC16
// NOTE: it seems that it doesnt matter what we send here
// the card is always fine with it?!
//const uint16_t crc = CRC16::get(src, 512);
//spi.writeByte(crc >> 8);
//spi.writeByte(crc);
spi.writeByte(0xFF);
spi.writeByte(0xFF);
//const uint8_t DATA_RESPONSE_MASK = 0x1F;
//const uint8_t DATA_RESPONSE_DATA_ACCEPTED = ((2 << 1) | 1);
//uint8_t crcRes = spi.readWriteByte(0xFF);
const uint8_t crcRes = spi.readWriteByte(0xFF); // response to CRC
//R1 res2; readResponse(&res2.raw, 1);
//Log::addInfo(NAME, "writeSingleBlockCRC(): %02x %02x", tmp, res2.raw);
// wait for card to finish writing
// should be a series of 0x00 followed by something != 0x00 and then a series of 0xFF
// TODO: check the non 0x00 value?
while(true) {
if (spi.readWriteByte(0xFF) == 0xFF) {break;}
}
endCMD();
return true;
//return (crcRes & DATA_RESPONSE_MASK) == DATA_RESPONSE_DATA_ACCEPTED;
}
};

View File

@@ -20,11 +20,7 @@ public:
}
DirEntryAt cur() {
AbsPos pos = fs.clusterToAbsPos(curCluster) + (curSectorInCluster * fs.desc.bytesPerSector) + (curEntryInSector * sizeof(DirEntry));
DirEntry* dirEntry = reinterpret_cast<DirEntry*>(buf + (curEntryInSector * sizeof(DirEntry)));
return DirEntryAt(pos, dirEntry);
}
/** get the next usable entry within the current directory */
DirEntryAt nextUsable() {
@@ -86,6 +82,12 @@ public:
private:
DirEntryAt cur() {
AbsPos pos = fs.clusterToAbsPos(curCluster) + (curSectorInCluster * fs.desc.bytesPerSector) + (curEntryInSector * sizeof(DirEntry));
DirEntry* dirEntry = reinterpret_cast<DirEntry*>(buf + (curEntryInSector * sizeof(DirEntry)));
return DirEntryAt(pos, dirEntry);
}
DirEntryAt next(bool allocIfNeeded) {
while(true) {

View File

@@ -2,6 +2,7 @@
#include <cstdint>
#include <functional>
#include <vector>
#include "Structs.h"
@@ -75,33 +76,24 @@ namespace FAT32 {
return File(*this, dea.getSize(), dea.getFirstCluster());
}
/** open the given file for reading*/
/** open the given file for reading */
File2 open2(const DirEntryAt& dea) {
return File2(*this, dea);
}
/** create a new file for writing, in the given directory */
File2 create2(const char* name) {
/** get or create a file with the given name */
File2 getOrCreateFile(const char* name) {
ClusterNr dirStartCluster = 2; // TODO
DirEntryAt dea = getDirEntry(name, true);
//if (!dea.isValid()) {Log::addError(NAME, "create2(): not a valid DirEntry");}
//if (!dea.isDirectory()) {Log::addError(NAME, "create2(): not a directory");}
DirIterator di(*this, dirStartCluster);
// new file -> allocate the first cluster
if (dea.getFirstCluster() == 0) {
ClusterNr firstCluster = allocFreeCluster(0);
dea.setFirstCluster(firstCluster);
write(dea);
}
// allocate a new directory entry for the file
DirEntryAt dea2 = di.nextFree();
dea2.setName(name);
dea2.setSize(0);
// allocate the file's first cluster
ClusterNr firstCluster = allocFreeCluster(0);
dea2.setFirstCluster(firstCluster);
// write the file description
write(dea2);
return File2(*this, dea2);
return File2(*this, dea);
}
@@ -132,18 +124,36 @@ namespace FAT32 {
Log::addInfo(NAME, "Bytes/Sector: %d, Sector/Cluster: %d, FATs: %d, RootDir: %d", desc.bytesPerSector, desc.sectorsPerCluster, desc.numberOfFATs, desc.rootDirFirstCluster);
/*
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;
*/
/** get (or create, if needed) a DirEntry with the given name */
DirEntryAt getDirEntry(const char* name, bool createIfNeeded) {
// TODO: support for sub folders)
// start at the root folder
ClusterNr dirStartCluster = 2;
{ // search for a matching existing entry
DirIterator di(*this, dirStartCluster);
while(true) {
DirEntryAt dea = di.nextUsable();
if (!dea.isValid()) {break;}
if (dea.getName() == name) {return dea;}
}
}
// no matching entry found
if (!createIfNeeded) {return DirEntryAt::invalid();}
{ // allocate a new DirEntry for the file
DirIterator di(*this, dirStartCluster);
DirEntryAt dea = di.nextFree();
dea.setName(name);
dea.setSize(0);
dea.setFirstCluster(0);
return dea;
}
}

View File

@@ -29,11 +29,11 @@ public:
ClusterNr getFirstCluster() const {return dea.getFirstCluster();}
/** get the file's name */
const std::string& getName() const {return dea.getName();}
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) {
uint32_t read(uint32_t size, uint8_t* dst) {
Log::addInfo(NAME, "read %d bytes", size);
@@ -48,14 +48,14 @@ public:
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) {
/* write the given data into the file */
uint32_t write(uint32_t size, const uint8_t* src) {
Log::addInfo(NAME, "write %d bytes", size);
@@ -67,10 +67,10 @@ public:
remaining -= written;
src += written;
totalWritten += written;
callback(totalWritten*100/size);
//callback(totalWritten*100/size);
}
// update the file header (size might have changed)
// update the file header (filesize might have changed)
fs.write(dea);
return totalWritten;
@@ -98,10 +98,10 @@ private:
}
// debug
char buf[1024];
char* dst = buf; dst += sprintf(dst, "clusters: ");
for (ClusterNr nr : clusters) {dst += sprintf(dst, "%d ", nr);}
Log::addInfo(NAME, buf);
//char buf[1024];
//char* dst = buf; dst += sprintf(dst, "clusters: ");
//for (ClusterNr nr : clusters) {dst += sprintf(dst, "%d ", nr);}
//Log::addInfo(NAME, buf);
}
@@ -136,6 +136,7 @@ private:
int32_t _write(uint32_t writeSize, const uint8_t* src) {
// do we need to append more free sectors to the end of the file?
if (curAbsPos >= getAllocatedSize()) {
if (clusters.empty()) {
const ClusterNr newCluster = fs.allocFreeCluster(0);
@@ -147,8 +148,6 @@ private:
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

View File

@@ -2,7 +2,7 @@
#include <string.h>
#include <string>
#include "Types.h"
#include "../Types.h"
namespace FAT32 {

View File

@@ -17,6 +17,8 @@
#include <fstream>
#include <fmt/format.h>
//class Simu {
// FILE* f;
@@ -60,13 +62,13 @@ public:
fclose(f);
}
uint32_t readSingleBlock(LBA512 addr, uint8_t* dst) {
uint32_t readBlock(LBA512 addr, uint8_t* dst) {
Log::addInfo("SD", "read512(%d*512)", addr);
memcpy(dst, data+addr*512, 512);
return 512;
}
uint32_t writeSingleBlock(LBA512 addr, const uint8_t* src) {
uint32_t writeBlock(LBA512 addr, const uint8_t* src) {
Log::addInfo("SD", "write512(%d*512)", addr);
memcpy(data+addr*512, src, 512);
return 512;
@@ -76,8 +78,16 @@ public:
#include <gtest/gtest.h>
//#define logInfo(fmt, ...) std::string s = fmt::format(FMT_STRING(fmt), __VA_ARGS__);
int main(int argc, char** argv) {
//logInfo("{:s}", "I am not a number")
//std::string s = fmt::format(FMT_STRING("{:s}"), "I am not a number");
//std::string s = fmt::format(FMT_STRING("{:s}"), "I am not a number");
::testing::InitGoogleTest(&argc, argv);
::testing::GTEST_FLAG(filter) = "*TestCreate*";
return RUN_ALL_TESTS();
@@ -99,10 +109,6 @@ int main(int argc, char** argv) {
FAT32FS fat(ah, mbr.getPartition(0).getFirstSector() * 512);
auto callback = [] (const int percent) {
std::cout << percent << std::endl;
};
FAT32FS::DirIterator dir = fat.getRoot();
while(false) {
@@ -114,7 +120,7 @@ int main(int argc, char** argv) {
if (1==0) {
uint8_t* bufff = (uint8_t*) malloc(1024*1024);
uint32_t read = f.read(f.getSize(), bufff, callback);
uint32_t read = f.read(f.getSize(), bufff);
std::string name = f.getName();
std::ofstream out("/tmp/ram/" + name);
@@ -132,10 +138,10 @@ int main(int argc, char** argv) {
//FAT32::DirEntryAt root = fat.getRoot().cur();
FAT32FS::File2 file = fat.create2("tmp1.txt");
FAT32FS::File2 file = fat.getOrCreateFile("tmp1.txt");
uint8_t src[128];
file.write(128, src, [] (int percent) {} );
file.write(128, src);
// diff /tmp/ram/TETRIS.GB /apps/workspace/gbemu/tests/tetris.gb
// diff /tmp/ram/KIRBY1.GB /apps/workspace/gbemu/tests/Kirby\'s\ Dream\ Land\ \(USA\,\ Europe\).gb

View File

@@ -25,18 +25,18 @@ struct TestDevice {
}
/** read a 512 byte block into dst */
bool readSingleBlock(LBA512 addr, uint8_t* dst) {
bool readBlock(LBA512 addr, uint8_t* dst) {
memcpy(dst, buf+addr*512, 512);
return true;
}
bool writeSingleBlock(LBA512 addr, const uint8_t* src) {
bool writeBlock(LBA512 addr, const uint8_t* src) {
memcpy(buf+addr*512, src, 512);
return true;
}
void reset(uint8_t val) {
for (int i = 0; i < sizeof(buf); ++i) {buf[i] = val;}
for (uint32_t i = 0; i < sizeof(buf); ++i) {buf[i] = val;}
}
};

View File

@@ -11,7 +11,7 @@
TEST(TestCreate, structure) {
TEST(TestCreat, structure) {
FAT32::FSHeader header;
@@ -26,25 +26,102 @@ TEST(TestCreate, structure) {
}
TEST (TestCreate, write) {
TEST (TestCreat, writeRead) {
using BlockDev = AccessHelper<TestDevice>;
using FS = FAT32::FS<BlockDev>;
size_t size = 32*1024*1024;
TestDevice dev(size);
BlockDev bDev(dev);
FAT32::FS<BlockDev> fs(bDev, 0);
FS fs(bDev, 0);
fs.setup(size);
const char* test = "This is a test";
FAT32::FS<BlockDev>::File2 f1 = fs.create2("test1.txt");
f1.write(strlen(test), (const uint8_t*)test, [](int percent) {});
for (int i = 0; i < 64; ++i) {
FAT32::FS<BlockDev>::File2 f2 = fs.create2("test2.txt");
f2.write(strlen(test), (const uint8_t*)test, [](int percent) {});
char name[64];
sprintf(name, "test%03d.txt", i);
const size_t size = 128 + i * 512;
const size_t sizeA = (size/4096+1) * 4096;
std::cout << name << " - " << size << std::endl;
FAT32::FS<BlockDev>::File2 f = fs.getOrCreateFile(name);
uint8_t* data = (uint8_t*)malloc(128 + i * 512);
for (uint32_t j = 0; j < size; ++j) {data[j] = j;}
uint32_t written = f.write(size, data);
free(data);
ASSERT_EQ(size, written);
ASSERT_EQ(size, f.getSize());
ASSERT_EQ(sizeA, f.getAllocatedSize());
}
dev.toFile("/tmp/ram/1.fat32");
// mount -t vfat 1.fat32 /mnt/fat/ && ls -l /mnt/fat/ && cat /mnt/fat/test1.txt && umount /mnt/fat
// mount -t vfat 1.fat32 /mnt/fat/ && ls -l /mnt/fat/ && cat /mnt/fat/test001.txt && umount /mnt/fat
// READ AGAIN
FS fs2(bDev, 0);
FS::DirIterator di = fs2.getRoot();
for (int i = 0; i < 64; ++i) {
char name[64];
sprintf(name, "test%03d.txt", i);
const size_t size = 128 + i * 512;
const size_t sizeA = (size/4096+1) * 4096;
FAT32::DirEntryAt dea = di.nextUsable();
FS::File2 f = fs.open2(dea);
ASSERT_EQ(name, dea.getName());
ASSERT_EQ(name, f.getName());
ASSERT_EQ(size, f.getSize());
ASSERT_EQ(sizeA, f.getAllocatedSize());
uint8_t* data = (uint8_t*)malloc(128 + i * 512);
uint32_t read = f.read(size, data);
ASSERT_EQ(size, read);
for (uint32_t j = 0; j < size; ++j) {
ASSERT_EQ((uint8_t)j, data[j]);
}
free(data);
}
}
TEST (TestCreate, getOrCreateFile) {
using BlockDev = AccessHelper<TestDevice>;
using FS = FAT32::FS<BlockDev>;
size_t size = 32*1024*1024;
TestDevice dev(size);
BlockDev bDev(dev);
FS fs(bDev, 0);
fs.setup(size);
FS::File2 f1 = fs.getOrCreateFile("test.txt");
ASSERT_EQ(0, f1.getSize());
ASSERT_EQ(4096, f1.getAllocatedSize());
ASSERT_EQ("test.txt", f1.getName());
uint8_t d1[128];
uint8_t d2[128];
for (int i = 0; i < 128; ++i) {d1[i] = 1;}
ASSERT_EQ(128, f1.write(128, d1));
FS::File2 f2 = fs.getOrCreateFile("test.txt");
ASSERT_EQ(128, f2.getSize());
ASSERT_EQ(128, f2.read(128, d2));
for (uint32_t i = 0; i < 128; ++i) {ASSERT_EQ(d1[i], d2[i]);}
}

View File

@@ -10,9 +10,10 @@
// NOTE: the last template argument has changed from "bool fast" to "int slowdown" where 0 is now fastest!
template <int PIN_MISO, int PIN_MOSI, int PIN_CLK, int SLOWDOWN> class SoftSPI {
template <int PIN_MISO, int PIN_MOSI, int PIN_CLK> class SoftSPI {
static constexpr const char* NAME = "softSPI";
uint8_t SLOWDOWN = 128;
#ifndef BIT
#define BIT(x) (1<<x)
@@ -25,6 +26,11 @@ public:
init();
}
void setSlowdown(uint8_t sd) {
this->SLOWDOWN = sd;
}
private:
void init() {
@@ -34,10 +40,11 @@ private:
MyGPIO::setOutput(PIN_CLK);
}
private:
static inline void wait() {
inline void wait() {
for (int i = 0; i < SLOWDOWN; ++i) {
__asm__ __volatile__("nop");
}
@@ -67,7 +74,7 @@ private:
return (val) ? 1 : 0;
}
static inline uint8_t readWriteBit(const bool out) {
inline uint8_t readWriteBit(const bool out) {
if(out) {MyGPIO::set(PIN_MOSI);} else {MyGPIO::clear(PIN_MOSI);}
wait();
clkHi();