static bool createErasable(const char *filename, uint32_t length) { | static bool createErasable(const char *filename, uint32_t length) { | ||||
return create(filename, length, blockSize()); | 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 void opendir() { dirindex = 0; } | ||||
static bool readdir(char *filename, uint32_t strsize, uint32_t &filesize); | static bool readdir(char *filename, uint32_t strsize, uint32_t &filesize); | ||||
private: | private: | ||||
if (address > 0) return true; | if (address > 0) return true; | ||||
return false; | 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 + rdlen > length) { | ||||
if (offset >= length) return 0; | if (offset >= length) return 0; | ||||
rdlen = length - offset; | rdlen = length - offset; | ||||
uint32_t address; // where this file's data begins in the Flash, or zero | 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 length; // total length of the data in the Flash chip | ||||
uint32_t offset; // current read/write offset in the file | uint32_t offset; // current read/write offset in the file | ||||
uint16_t dirindex; | |||||
}; | }; | ||||
hash ^= *p; | hash ^= *p; | ||||
hash *= 16777619; | hash *= 16777619; | ||||
} | } | ||||
hash %= (uint32_t)0xFFFF; | |||||
hash = (hash % (uint32_t)0xFFFE) + 1; // all values except 0000 & FFFF | |||||
return hash; | return hash; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
#if 0 | |||||
void pbuf(const void *buf, uint32_t len) | void pbuf(const void *buf, uint32_t len) | ||||
{ | { | ||||
const uint8_t *p = (const uint8_t *)buf; | const uint8_t *p = (const uint8_t *)buf; | ||||
do { | do { | ||||
//Serial.printf("%02X ", *p++); | |||||
Serial.printf("%02X ", *p++); | |||||
} while (--len > 0); | } while (--len > 0); | ||||
//Serial.println(); | |||||
Serial.println(); | |||||
} | } | ||||
#endif | |||||
SerialFlashFile SerialFlashChip::open(const char *filename) | SerialFlashFile SerialFlashChip::open(const char *filename) | ||||
{ | { | ||||
if (!maxfiles) return file; | if (!maxfiles) return file; | ||||
maxfiles &= 0xFFFF; | maxfiles &= 0xFFFF; | ||||
hash = filename_hash(filename); | hash = filename_hash(filename); | ||||
//Serial.printf("hash %04X for \"%s\"\n", hash, filename); | |||||
while (index < maxfiles) { | while (index < maxfiles) { | ||||
n = 8; | n = 8; | ||||
if (n > maxfiles - index) n = maxfiles - index; | if (n > maxfiles - index) n = maxfiles - index; | ||||
file.address = buf[0]; | file.address = buf[0]; | ||||
file.length = buf[1]; | file.length = buf[1]; | ||||
file.offset = 0; | file.offset = 0; | ||||
file.dirindex = index + i; | |||||
return file; | return file; | ||||
} | } | ||||
} else if (hashtable[i] == 0xFFFF) { | } else if (hashtable[i] == 0xFFFF) { | ||||
return file; | 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) | static uint32_t find_first_unallocated_file_index(uint32_t maxfiles) | ||||
{ | { | ||||
uint16_t hashtable[8]; | uint16_t hashtable[8]; | ||||
uint32_t address, straddr, len; | uint32_t address, straddr, len; | ||||
SerialFlashFile file; | SerialFlashFile file; | ||||
// check if the file already exists | |||||
if (exists(filename)) return false; | |||||
// first, get the filesystem parameters | // first, get the filesystem parameters | ||||
maxfiles = check_signature(); | maxfiles = check_signature(); | ||||
if (!maxfiles) return false; | if (!maxfiles) return false; | ||||
stringsize = (maxfiles & 0xFFFF0000) >> 14; | stringsize = (maxfiles & 0xFFFF0000) >> 14; | ||||
maxfiles &= 0xFFFF; | maxfiles &= 0xFFFF; | ||||
// TODO: should we check if the file already exists? Then what? | |||||
// find the first unused slot for this file | // find the first unused slot for this file | ||||
index = find_first_unallocated_file_index(maxfiles); | index = find_first_unallocated_file_index(maxfiles); |
int count = 0; | int count = 0; | ||||
File rootdir = SD.open("/"); | File rootdir = SD.open("/"); | ||||
while (1) { | while (1) { | ||||
// open a file from the SD card | |||||
Serial.println(); | Serial.println(); | ||||
File f = rootdir.openNextFile(); | File f = rootdir.openNextFile(); | ||||
if (!f) break; | if (!f) break; | ||||
Serial.print(" "); | Serial.print(" "); | ||||
unsigned long length = f.size(); | unsigned long length = f.size(); | ||||
Serial.println(length); | 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)) { | if (SerialFlash.create(filename, length)) { | ||||
SerialFlashFile ff = SerialFlash.open(filename); | SerialFlashFile ff = SerialFlash.open(filename); | ||||
if (ff) { | if (ff) { | ||||
Serial.print(" copying"); | Serial.print(" copying"); | ||||
// copy data. | |||||
// copy data loop | |||||
unsigned long count = 0; | unsigned long count = 0; | ||||
while (count < length) { | while (count < length) { | ||||
char buf[256]; | char buf[256]; | ||||
} else { | } else { | ||||
Serial.println(" unable to create file"); | Serial.println(" unable to create file"); | ||||
} | } | ||||
if (++count > 12) break; // testing, only do first 12 files | |||||
f.close(); | f.close(); | ||||
} | } | ||||
rootdir.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() { | void loop() { | ||||
} | } | ||||
#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); | |||||
} | |||||
} |
#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(); | |||||
} | |||||