|
- #include "SerialFlash.h"
- #include "util/crc16.h"
-
- /* On-chip SerialFlash file allocation data structures:
-
- uint32_t signature = 0xFA96554C;
- uint16_t maxfiles
- uint16_t stringssize // div by 4
- uint16_t hashes[maxfiles]
- struct {
- uint32_t file_begin
- uint32_t file_length
- uint16_t string_index // div4
- } fileinfo[maxfiles]
- char strings[stringssize]
-
- A 32 bit signature is stored at the beginning of the flash memory.
- If 0xFFFFFFFF is seen, the entire chip should be assumed blank.
- If any value other than 0xFA96554C is found, a different data format
- is stored. This could should refuse to access the flash.
-
- The next 4 bytes store number of files and size of the strings
- section, which allow the position of every other item to be found.
- The string section size is the 16 bit integer times 4, which allows
- up to 262140 bytes for string data.
-
- An array of 16 bit filename hashes allows for quick linear search
- for potentially matching filenames. A hash value of 0xFFFF indicates
- no file is allocated for the remainder of the array.
-
- Following the hashes, and array of 10 byte structs give the location
- and length of the file's actual data, and the offset of its filename
- in the strings section.
-
- Strings are null terminated. The remainder of the chip is file data.
- */
-
- #define DEFAULT_MAXFILES 600
- #define DEFAULT_STRINGS_SIZE 25560
-
-
- static uint32_t check_signature(void)
- {
- uint32_t sig[2];
-
- SerialFlash.read(sig, 0, 8);
- if (sig[0] == 0xFA96554C) return sig[1];
- if (sig[0] == 0xFFFFFFFF) {
- sig[0] = 0xFA96554C;
- sig[1] = ((DEFAULT_STRINGS_SIZE/4) << 16) | DEFAULT_MAXFILES;
- SerialFlash.write(sig, 0, 8);
- while (!SerialFlash.ready()) ; // TODO: timeout
- SerialFlash.read(sig, 0, 8);
- if (sig[0] == 0xFA96554C) return sig[1];
- }
- return 0;
- }
-
- static uint16_t filename_hash(const char *filename)
- {
- uint16_t crc;
- const char *p;
-
- crc = 0xFFFF;
- for (p=filename; *p; p++) {
- // TODO: replace with fast CRC hardware?
- crc = _crc16_update(crc, *p);
- }
- crc ^= 0xFFFF;
- if (crc == 0xFFFF) crc = 0;
- return crc;
- }
-
- static bool filename_compare(const char *filename, uint32_t straddr)
- {
- unsigned int i;
- const char *p;
- char buf[16];
-
- p = filename;
- while (1) {
- SerialFlash.read(buf, straddr, sizeof(buf));
- straddr += sizeof(buf);
- for (i=0; i < sizeof(buf); i++) {
- if (*p++ != buf[i]) return false;
- if (buf[i] == 0) return true;
- }
- }
- }
-
- SerialFlashFile SerialFlashChip::open(const char *filename)
- {
- uint32_t maxfiles, straddr;
- uint16_t hash, hashtable[8];
- uint32_t i, n, index=0;
- uint32_t buf[3];
- SerialFlashFile file;
-
- maxfiles = check_signature();
- if (!maxfiles) return file;
- maxfiles &= 0xFFFF;
- hash = filename_hash(filename);
- while (index < maxfiles) {
- n = 8;
- if (n > maxfiles - index) n = maxfiles - index;
- SerialFlash.read(hashtable, 8 + index * 2, n * 2);
- for (i=0; i < n; i++) {
- if (hashtable[i] == hash) {
- buf[2] = 0;
- SerialFlash.read(buf, 8 + maxfiles * 2 + (index+i) * 10, 10);
- straddr = 8 + maxfiles * 12 + buf[2] * 4;
- if (filename_compare(filename, straddr)) {
- file.address = buf[0];
- file.length = buf[1];
- file.offset = 0;
- return file;
- }
- } else if (hashtable[i] == 0xFFFF) {
- return file;
- }
- }
- index += n;
- }
- return file;
- }
-
- static uint32_t find_first_unallocated_file_index(uint32_t maxfiles)
- {
- uint16_t hashtable[8];
- uint32_t i, n, index=0;
-
- do {
- n = 8;
- if (index + n > maxfiles) n = maxfiles - index;
- SerialFlash.read(hashtable, 8 + index * 2, n * 2);
- for (i=0; i < n; i++) {
- if (hashtable[i] == 0xFFFF) return index + i;
- }
- index += n;
- } while (index < maxfiles);
- return 0xFFFFFFFF;
- }
-
- static uint32_t string_length(uint32_t addr)
- {
- char buf[16];
- const char *p;
- uint32_t len=0;
-
- while (1) {
- SerialFlash.read(buf, addr, sizeof(buf));
- for (p=buf; p < buf + sizeof(buf); p++) {
- if (*p == 0) return len;
- len++;
- }
- addr += len;
- }
- }
-
- // uint32_t signature = 0xFA96554C;
- // uint16_t maxfiles
- // uint16_t stringssize // div by 4
- // uint16_t hashes[maxfiles]
- // struct {
- // uint32_t file_begin
- // uint32_t file_length
- // uint16_t string_index // div 4
- // } fileinfo[maxfiles]
- // char strings[stringssize]
-
- bool SerialFlashChip::create(const char *filename, uint32_t length, uint32_t align)
- {
- uint32_t maxfiles, stringsize;
- uint32_t index, buf[3];
- uint32_t address, straddr, len;
- SerialFlashFile file;
-
- // first, get the filesystem parameters
- maxfiles = check_signature();
- if (!maxfiles) return false;
- stringsize = (maxfiles & 0xFFFF0000) >> 14;
- maxfiles &= 0xFFFF;
- // find the first unused slot for this file
- index = find_first_unallocated_file_index(maxfiles);
- if (index >= maxfiles) return false;
- // compute where to store the filename and actual data
- straddr = 8 + maxfiles * 12;
- if (index == 0) {
- address = straddr + stringsize;
- } else {
- buf[2] = 0;
- SerialFlash.read(buf, 8 + maxfiles * 2 + (index-1) * 10, 10);
- address = buf[0] + buf[1];
- straddr += buf[2] * 4;
- straddr += string_length(straddr);
- straddr = (straddr + 3) & 0x0003FFFC;
- }
- // for files aligned to pages or sectors, adjust addr & len
- if (align > 0) {
- address += align - 1;
- address /= align;
- address *= align;
- length += align - 1;
- length /= align;
- length *= align;
- }
- // last check, if enough space exists...
- len = strlen(filename);
- // TODO: check for enough string space for filename
- if (address + length > SerialFlash.capacity()) return false;
-
- SerialFlash.write(filename, straddr, len+1);
- buf[0] = address;
- buf[1] = length;
- buf[2] = (straddr - (8 + maxfiles * 12)) / 4;
- SerialFlash.write(buf, 8 + maxfiles * 2 + index * 10, 10);
- buf[0] = filename_hash(filename);
- SerialFlash.write(buf, 8 + index * 2, 2);
- while (!SerialFlash.ready()) ; // TODO: timeout
- return false;
- }
-
- bool SerialFlashChip::readdir(char *filename, uint32_t strsize, uint32_t &filesize)
- {
- uint32_t maxfiles, index, straddr;
- uint32_t i, n;
- uint32_t buf[2];
- char str[16], *p=filename;
-
- filename[0] = 0;
- maxfiles = check_signature();
- if (!maxfiles) return false;
- maxfiles &= 0xFFFF;
- index = dirindex;
- if (index >= maxfiles) return false;
- dirindex = index + 1;
-
- buf[1] = 0;
- SerialFlash.read(buf, 8 + 4 + maxfiles * 2 + index * 10, 6);
- if (buf[0] == 0xFFFFFFFF) return false;
- filesize = buf[0];
- straddr = 8 + maxfiles * 12 + buf[1] * 4;
-
- while (strsize) {
- n = strsize;
- if (n > sizeof(str)) n = sizeof(str);
- SerialFlash.read(str, straddr, n);
- for (i=0; i < n; i++) {
- *p++ = str[i];
- if (str[i] == 0) {
- return true;
- }
- }
- strsize -= n;
- }
- *(p - 1) = 0;
- return true;
- }
-
-
- void SerialFlashFile::erase()
- {
- // TODO: erase all the blocks of a file
- // if it's been block aligned, of course
- }
|