| @@ -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(); | |||
| } | |||