@@ -52,6 +52,9 @@ public: | |||
static bool createErasable(const char *filename, uint32_t length) { | |||
return create(filename, length, blockSize()); | |||
} | |||
static bool exists(const char *filename); | |||
static bool remove(const char *filename); | |||
static bool remove(SerialFlashFile &file); | |||
static void opendir() { dirindex = 0; } | |||
static bool readdir(char *filename, uint32_t strsize, uint32_t &filesize); | |||
private: | |||
@@ -75,7 +78,7 @@ public: | |||
if (address > 0) return true; | |||
return false; | |||
} | |||
uint32_t read(uint8_t *buf, uint32_t rdlen) { | |||
uint32_t read(void *buf, uint32_t rdlen) { | |||
if (offset + rdlen > length) { | |||
if (offset >= length) return 0; | |||
rdlen = length - offset; | |||
@@ -119,6 +122,7 @@ protected: | |||
uint32_t address; // where this file's data begins in the Flash, or zero | |||
uint32_t length; // total length of the data in the Flash chip | |||
uint32_t offset; // current read/write offset in the file | |||
uint16_t dirindex; | |||
}; | |||
@@ -94,7 +94,7 @@ static uint16_t filename_hash(const char *filename) | |||
hash ^= *p; | |||
hash *= 16777619; | |||
} | |||
hash %= (uint32_t)0xFFFF; | |||
hash = (hash % (uint32_t)0xFFFE) + 1; // all values except 0000 & FFFF | |||
return hash; | |||
} | |||
@@ -115,14 +115,16 @@ static bool filename_compare(const char *filename, uint32_t straddr) | |||
} | |||
} | |||
#if 0 | |||
void pbuf(const void *buf, uint32_t len) | |||
{ | |||
const uint8_t *p = (const uint8_t *)buf; | |||
do { | |||
//Serial.printf("%02X ", *p++); | |||
Serial.printf("%02X ", *p++); | |||
} while (--len > 0); | |||
//Serial.println(); | |||
Serial.println(); | |||
} | |||
#endif | |||
SerialFlashFile SerialFlashChip::open(const char *filename) | |||
{ | |||
@@ -137,6 +139,7 @@ SerialFlashFile SerialFlashChip::open(const char *filename) | |||
if (!maxfiles) return file; | |||
maxfiles &= 0xFFFF; | |||
hash = filename_hash(filename); | |||
//Serial.printf("hash %04X for \"%s\"\n", hash, filename); | |||
while (index < maxfiles) { | |||
n = 8; | |||
if (n > maxfiles - index) n = maxfiles - index; | |||
@@ -161,6 +164,7 @@ SerialFlashFile SerialFlashChip::open(const char *filename) | |||
file.address = buf[0]; | |||
file.length = buf[1]; | |||
file.offset = 0; | |||
file.dirindex = index + i; | |||
return file; | |||
} | |||
} else if (hashtable[i] == 0xFFFF) { | |||
@@ -172,6 +176,40 @@ SerialFlashFile SerialFlashChip::open(const char *filename) | |||
return file; | |||
} | |||
bool SerialFlashChip::exists(const char *filename) | |||
{ | |||
SerialFlashFile file = open(filename); | |||
return (bool)file; | |||
} | |||
bool SerialFlashChip::remove(const char *filename) | |||
{ | |||
SerialFlashFile file = open(filename); | |||
return remove(file); | |||
} | |||
bool SerialFlashChip::remove(SerialFlashFile &file) | |||
{ | |||
// To "remove" a file, we simply zero its hash in the lookup | |||
// table, so it can't be found by open(). The space on the | |||
// flash memory is not freed. | |||
if (!file) return false; | |||
uint16_t hash; | |||
SerialFlash.read(8 + file.dirindex * 2, &hash, 2); | |||
//Serial.printf("remove hash %04X at %d index\n", hash, file.dirindex); | |||
hash ^= 0xFFFF; // write zeros to all ones | |||
SerialFlash.write(8 + file.dirindex * 2, &hash, 2); | |||
while (!SerialFlash.ready()) ; // wait... TODO: timeout | |||
SerialFlash.read(8 + file.dirindex * 2, &hash, 2); | |||
if (hash != 0) { | |||
//Serial.printf("remove failed, hash %04X\n", hash); | |||
return false; | |||
} | |||
file.address = 0; | |||
file.length = 0; | |||
return true; | |||
} | |||
static uint32_t find_first_unallocated_file_index(uint32_t maxfiles) | |||
{ | |||
uint16_t hashtable[8]; | |||
@@ -223,13 +261,14 @@ bool SerialFlashChip::create(const char *filename, uint32_t length, uint32_t ali | |||
uint32_t address, straddr, len; | |||
SerialFlashFile file; | |||
// check if the file already exists | |||
if (exists(filename)) return false; | |||
// first, get the filesystem parameters | |||
maxfiles = check_signature(); | |||
if (!maxfiles) return false; | |||
stringsize = (maxfiles & 0xFFFF0000) >> 14; | |||
maxfiles &= 0xFFFF; | |||
// TODO: should we check if the file already exists? Then what? | |||
// find the first unused slot for this file | |||
index = find_first_unallocated_file_index(maxfiles); |
@@ -26,6 +26,7 @@ void setup() { | |||
int count = 0; | |||
File rootdir = SD.open("/"); | |||
while (1) { | |||
// open a file from the SD card | |||
Serial.println(); | |||
File f = rootdir.openNextFile(); | |||
if (!f) break; | |||
@@ -34,11 +35,37 @@ void setup() { | |||
Serial.print(" "); | |||
unsigned long length = f.size(); | |||
Serial.println(length); | |||
// check if this file is already on the Flash chip | |||
if (SerialFlash.exists(filename)) { | |||
Serial.println(" already exists on the Flash chip"); | |||
SerialFlashFile ff = SerialFlash.open(filename); | |||
if (ff && ff.size() == f.size()) { | |||
Serial.println(" size is the same, comparing data..."); | |||
if (compareFiles(f, ff) == true) { | |||
Serial.println(" files are identical :)"); | |||
f.close(); | |||
ff.close(); | |||
continue; // advance to next file | |||
} else { | |||
Serial.println(" files are different"); | |||
} | |||
} else { | |||
Serial.print(" size is different, "); | |||
Serial.print(ff.size()); | |||
Serial.println(" bytes"); | |||
} | |||
// delete the copy on the Flash chip, if different | |||
Serial.println(" delete file from Flash chip"); | |||
SerialFlash.remove(filename); | |||
} | |||
// create the file on the Flash chip and copy data | |||
if (SerialFlash.create(filename, length)) { | |||
SerialFlashFile ff = SerialFlash.open(filename); | |||
if (ff) { | |||
Serial.print(" copying"); | |||
// copy data. | |||
// copy data loop | |||
unsigned long count = 0; | |||
while (count < length) { | |||
char buf[256]; | |||
@@ -56,14 +83,30 @@ void setup() { | |||
} else { | |||
Serial.println(" unable to create file"); | |||
} | |||
if (++count > 12) break; // testing, only do first 12 files | |||
f.close(); | |||
} | |||
rootdir.close(); | |||
} | |||
bool compareFiles(File &file, SerialFlashFile &ffile) { | |||
file.seek(0); | |||
ffile.seek(0); | |||
unsigned long count = file.size(); | |||
while (count > 0) { | |||
char buf1[128], buf2[128]; | |||
unsigned long n = count; | |||
if (n > 128) n = 128; | |||
file.read(buf1, n); | |||
ffile.read(buf2, n); | |||
if (memcmp(buf1, buf2, n) != 0) return false; // differ | |||
count = count - n; | |||
} | |||
return true; // all data identical | |||
} | |||
void loop() { | |||
} | |||
@@ -0,0 +1,54 @@ | |||
#include <SerialFlash.h> | |||
#include <SPI.h> | |||
const int FlashChipSelect = 6; | |||
void setup() { | |||
//uncomment these if using Teensy audio shield | |||
SPI.setSCK(14); // Audio shield has SCK on pin 14 | |||
SPI.setMOSI(7); // Audio shield has MOSI on pin 7 | |||
// wait for Arduino Serial Monitor | |||
while (!Serial) ; | |||
delay(100); | |||
Serial.println("All Files on SPI Flash chip:"); | |||
if (!SerialFlash.begin()) { | |||
error("Unable to access SPI Flash chip"); | |||
} | |||
SerialFlash.opendir(); | |||
unsigned int count = 0; | |||
while (1) { | |||
char filename[64]; | |||
unsigned long filesize; | |||
if (SerialFlash.readdir(filename, sizeof(filename), filesize)) { | |||
Serial.print(" "); | |||
Serial.print(filename); | |||
spaces(20 - strlen(filename)); | |||
Serial.print(" "); | |||
Serial.print(filesize); | |||
Serial.print(" bytes"); | |||
Serial.println(); | |||
} else { | |||
break; // no more files | |||
} | |||
} | |||
} | |||
void spaces(int num) { | |||
for (int i=0; i < num; i++) { | |||
Serial.print(" "); | |||
} | |||
} | |||
void loop() { | |||
} | |||
void error(const char *message) { | |||
while (1) { | |||
Serial.println(message); | |||
delay(2500); | |||
} | |||
} |
@@ -1,97 +0,0 @@ | |||
#include <SerialFlash.h> | |||
#include <SPI.h> | |||
SerialFlashFile file; | |||
void setup() { | |||
char filename[40]; | |||
uint32_t len; | |||
while (!Serial) ; | |||
delay(10); | |||
//uncomment these if using Teensy audio shield | |||
//SPI.setSCK(14); // Audio shield has SCK on pin 14 | |||
//SPI.setMOSI(7); // Audio shield has MOSI on pin 7 | |||
Serial.println("Test Hardware"); | |||
SerialFlash.begin(); | |||
#if 0 | |||
Serial.println("erase"); | |||
SerialFlash.eraseAll(); | |||
while (!SerialFlash.ready()) { | |||
} | |||
Serial.println("erase done"); | |||
#endif | |||
Serial.println("Directory:"); | |||
while (SerialFlash.readdir(filename, sizeof(filename), len)) { | |||
Serial.print(" file: "); | |||
Serial.print(filename); | |||
Serial.print(" bytes: "); | |||
Serial.print(len); | |||
Serial.println(); | |||
} | |||
Serial.println(); | |||
Serial.println("simple.txt test"); | |||
file = SerialFlash.open("simple.txt"); | |||
if (file) { | |||
Serial.println(" file opened"); | |||
Serial.print(" length = "); | |||
Serial.println(file.size()); | |||
Serial.print(" addr on chip = "); | |||
Serial.println(file.getFlashAddress()); | |||
file.close(); | |||
} else { | |||
Serial.println(" create file"); | |||
SerialFlash.create("simple.txt", 516); | |||
} | |||
Serial.println("soundfile.wav test"); | |||
file = SerialFlash.open("soundfile.wav"); | |||
if (file) { | |||
Serial.println(" file opened"); | |||
Serial.print(" length = "); | |||
Serial.println(file.size()); | |||
Serial.print(" addr on chip = "); | |||
Serial.println(file.getFlashAddress()); | |||
file.close(); | |||
} else { | |||
Serial.println(" create file"); | |||
SerialFlash.createErasable("soundfile.wav", 3081000); | |||
} | |||
Serial.println("wavetable1 test"); | |||
file = SerialFlash.open("wavetable1"); | |||
if (file) { | |||
Serial.println(" file opened"); | |||
Serial.print(" length = "); | |||
Serial.println(file.size()); | |||
Serial.print(" addr on chip = "); | |||
Serial.println(file.getFlashAddress()); | |||
file.close(); | |||
} else { | |||
Serial.println(" create file"); | |||
SerialFlash.create("wavetable1", 181003); | |||
} | |||
Serial.println("end"); | |||
} | |||
void loop() { | |||
} | |||
void printbuf(const void *buf, uint32_t len) | |||
{ | |||
const uint8_t *p = (const uint8_t *)buf; | |||
do { | |||
Serial.print(*p++); | |||
Serial.print(" "); | |||
} while (--len > 0); | |||
Serial.println(); | |||
} | |||