port of teensy SerialFlash library for SPI serial flash like winbond from https://github.com/PaulStoffregen/SerialFlash
SerialFlashDirectory.cpp@0:e5c9fd5789d7, 2016-04-14 (annotated)
- Committer:
- manitou
- Date:
- Thu Apr 14 12:05:15 2016 +0000
- Revision:
- 0:e5c9fd5789d7
initial port of teensy SerialFlash library
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
manitou | 0:e5c9fd5789d7 | 1 | /* SerialFlash Library - for filesystem-like access to SPI Serial Flash memory |
manitou | 0:e5c9fd5789d7 | 2 | * https://github.com/PaulStoffregen/SerialFlash |
manitou | 0:e5c9fd5789d7 | 3 | * Copyright (C) 2015, Paul Stoffregen, paul@pjrc.com |
manitou | 0:e5c9fd5789d7 | 4 | * |
manitou | 0:e5c9fd5789d7 | 5 | * Development of this library was funded by PJRC.COM, LLC by sales of Teensy. |
manitou | 0:e5c9fd5789d7 | 6 | * Please support PJRC's efforts to develop open source software by purchasing |
manitou | 0:e5c9fd5789d7 | 7 | * Teensy or other genuine PJRC products. |
manitou | 0:e5c9fd5789d7 | 8 | * |
manitou | 0:e5c9fd5789d7 | 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
manitou | 0:e5c9fd5789d7 | 10 | * of this software and associated documentation files (the "Software"), to deal |
manitou | 0:e5c9fd5789d7 | 11 | * in the Software without restriction, including without limitation the rights |
manitou | 0:e5c9fd5789d7 | 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
manitou | 0:e5c9fd5789d7 | 13 | * copies of the Software, and to permit persons to whom the Software is |
manitou | 0:e5c9fd5789d7 | 14 | * furnished to do so, subject to the following conditions: |
manitou | 0:e5c9fd5789d7 | 15 | * |
manitou | 0:e5c9fd5789d7 | 16 | * The above copyright notice, development funding notice, and this permission |
manitou | 0:e5c9fd5789d7 | 17 | * notice shall be included in all copies or substantial portions of the Software. |
manitou | 0:e5c9fd5789d7 | 18 | * |
manitou | 0:e5c9fd5789d7 | 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
manitou | 0:e5c9fd5789d7 | 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
manitou | 0:e5c9fd5789d7 | 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
manitou | 0:e5c9fd5789d7 | 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
manitou | 0:e5c9fd5789d7 | 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
manitou | 0:e5c9fd5789d7 | 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
manitou | 0:e5c9fd5789d7 | 25 | * THE SOFTWARE. |
manitou | 0:e5c9fd5789d7 | 26 | */ |
manitou | 0:e5c9fd5789d7 | 27 | #include "mbed.h" |
manitou | 0:e5c9fd5789d7 | 28 | #include "SerialFlash.h" |
manitou | 0:e5c9fd5789d7 | 29 | //#include "util/crc16.h" |
manitou | 0:e5c9fd5789d7 | 30 | |
manitou | 0:e5c9fd5789d7 | 31 | /* On-chip SerialFlash file allocation data structures: |
manitou | 0:e5c9fd5789d7 | 32 | |
manitou | 0:e5c9fd5789d7 | 33 | uint32_t signature = 0xFA96554C; |
manitou | 0:e5c9fd5789d7 | 34 | uint16_t maxfiles |
manitou | 0:e5c9fd5789d7 | 35 | uint16_t stringssize // div by 4 |
manitou | 0:e5c9fd5789d7 | 36 | uint16_t hashes[maxfiles] |
manitou | 0:e5c9fd5789d7 | 37 | struct { |
manitou | 0:e5c9fd5789d7 | 38 | uint32_t file_begin |
manitou | 0:e5c9fd5789d7 | 39 | uint32_t file_length |
manitou | 0:e5c9fd5789d7 | 40 | uint16_t string_index // div4 |
manitou | 0:e5c9fd5789d7 | 41 | } fileinfo[maxfiles] |
manitou | 0:e5c9fd5789d7 | 42 | char strings[stringssize] |
manitou | 0:e5c9fd5789d7 | 43 | |
manitou | 0:e5c9fd5789d7 | 44 | A 32 bit signature is stored at the beginning of the flash memory. |
manitou | 0:e5c9fd5789d7 | 45 | If 0xFFFFFFFF is seen, the entire chip should be assumed blank. |
manitou | 0:e5c9fd5789d7 | 46 | If any value other than 0xFA96554C is found, a different data format |
manitou | 0:e5c9fd5789d7 | 47 | is stored. This could should refuse to access the flash. |
manitou | 0:e5c9fd5789d7 | 48 | |
manitou | 0:e5c9fd5789d7 | 49 | The next 4 bytes store number of files and size of the strings |
manitou | 0:e5c9fd5789d7 | 50 | section, which allow the position of every other item to be found. |
manitou | 0:e5c9fd5789d7 | 51 | The string section size is the 16 bit integer times 4, which allows |
manitou | 0:e5c9fd5789d7 | 52 | up to 262140 bytes for string data. |
manitou | 0:e5c9fd5789d7 | 53 | |
manitou | 0:e5c9fd5789d7 | 54 | An array of 16 bit filename hashes allows for quick linear search |
manitou | 0:e5c9fd5789d7 | 55 | for potentially matching filenames. A hash value of 0xFFFF indicates |
manitou | 0:e5c9fd5789d7 | 56 | no file is allocated for the remainder of the array. |
manitou | 0:e5c9fd5789d7 | 57 | |
manitou | 0:e5c9fd5789d7 | 58 | Following the hashes, and array of 10 byte structs give the location |
manitou | 0:e5c9fd5789d7 | 59 | and length of the file's actual data, and the offset of its filename |
manitou | 0:e5c9fd5789d7 | 60 | in the strings section. |
manitou | 0:e5c9fd5789d7 | 61 | |
manitou | 0:e5c9fd5789d7 | 62 | Strings are null terminated. The remainder of the chip is file data. |
manitou | 0:e5c9fd5789d7 | 63 | */ |
manitou | 0:e5c9fd5789d7 | 64 | |
manitou | 0:e5c9fd5789d7 | 65 | #define DEFAULT_MAXFILES 600 |
manitou | 0:e5c9fd5789d7 | 66 | #define DEFAULT_STRINGS_SIZE 25560 |
manitou | 0:e5c9fd5789d7 | 67 | |
manitou | 0:e5c9fd5789d7 | 68 | |
manitou | 0:e5c9fd5789d7 | 69 | static uint32_t check_signature(void) |
manitou | 0:e5c9fd5789d7 | 70 | { |
manitou | 0:e5c9fd5789d7 | 71 | uint32_t sig[2]; |
manitou | 0:e5c9fd5789d7 | 72 | |
manitou | 0:e5c9fd5789d7 | 73 | SerialFlash.read(0, sig, 8); |
manitou | 0:e5c9fd5789d7 | 74 | //Serial.printf("sig: %08X %08X\n", sig[0], sig[1]); |
manitou | 0:e5c9fd5789d7 | 75 | if (sig[0] == 0xFA96554C) return sig[1]; |
manitou | 0:e5c9fd5789d7 | 76 | if (sig[0] == 0xFFFFFFFF) { |
manitou | 0:e5c9fd5789d7 | 77 | sig[0] = 0xFA96554C; |
manitou | 0:e5c9fd5789d7 | 78 | sig[1] = ((uint32_t)(DEFAULT_STRINGS_SIZE/4) << 16) | DEFAULT_MAXFILES; |
manitou | 0:e5c9fd5789d7 | 79 | SerialFlash.write(0, sig, 8); |
manitou | 0:e5c9fd5789d7 | 80 | while (!SerialFlash.ready()) ; // TODO: timeout |
manitou | 0:e5c9fd5789d7 | 81 | SerialFlash.read(0, sig, 8); |
manitou | 0:e5c9fd5789d7 | 82 | if (sig[0] == 0xFA96554C) return sig[1]; |
manitou | 0:e5c9fd5789d7 | 83 | } |
manitou | 0:e5c9fd5789d7 | 84 | return 0; |
manitou | 0:e5c9fd5789d7 | 85 | } |
manitou | 0:e5c9fd5789d7 | 86 | |
manitou | 0:e5c9fd5789d7 | 87 | static uint16_t filename_hash(const char *filename) |
manitou | 0:e5c9fd5789d7 | 88 | { |
manitou | 0:e5c9fd5789d7 | 89 | // http://isthe.com/chongo/tech/comp/fnv/ |
manitou | 0:e5c9fd5789d7 | 90 | uint32_t hash = 2166136261; |
manitou | 0:e5c9fd5789d7 | 91 | const char *p; |
manitou | 0:e5c9fd5789d7 | 92 | |
manitou | 0:e5c9fd5789d7 | 93 | for (p=filename; *p; p++) { |
manitou | 0:e5c9fd5789d7 | 94 | hash ^= *p; |
manitou | 0:e5c9fd5789d7 | 95 | hash *= 16777619; |
manitou | 0:e5c9fd5789d7 | 96 | } |
manitou | 0:e5c9fd5789d7 | 97 | hash = (hash % (uint32_t)0xFFFE) + 1; // all values except 0000 & FFFF |
manitou | 0:e5c9fd5789d7 | 98 | return hash; |
manitou | 0:e5c9fd5789d7 | 99 | } |
manitou | 0:e5c9fd5789d7 | 100 | |
manitou | 0:e5c9fd5789d7 | 101 | static bool filename_compare(const char *filename, uint32_t straddr) |
manitou | 0:e5c9fd5789d7 | 102 | { |
manitou | 0:e5c9fd5789d7 | 103 | unsigned int i; |
manitou | 0:e5c9fd5789d7 | 104 | const char *p; |
manitou | 0:e5c9fd5789d7 | 105 | char buf[16]; |
manitou | 0:e5c9fd5789d7 | 106 | |
manitou | 0:e5c9fd5789d7 | 107 | p = filename; |
manitou | 0:e5c9fd5789d7 | 108 | while (1) { |
manitou | 0:e5c9fd5789d7 | 109 | SerialFlash.read(straddr, buf, sizeof(buf)); |
manitou | 0:e5c9fd5789d7 | 110 | straddr += sizeof(buf); |
manitou | 0:e5c9fd5789d7 | 111 | for (i=0; i < sizeof(buf); i++) { |
manitou | 0:e5c9fd5789d7 | 112 | if (*p++ != buf[i]) return false; |
manitou | 0:e5c9fd5789d7 | 113 | if (buf[i] == 0) return true; |
manitou | 0:e5c9fd5789d7 | 114 | } |
manitou | 0:e5c9fd5789d7 | 115 | } |
manitou | 0:e5c9fd5789d7 | 116 | } |
manitou | 0:e5c9fd5789d7 | 117 | |
manitou | 0:e5c9fd5789d7 | 118 | #if 0 |
manitou | 0:e5c9fd5789d7 | 119 | void pbuf(const void *buf, uint32_t len) |
manitou | 0:e5c9fd5789d7 | 120 | { |
manitou | 0:e5c9fd5789d7 | 121 | const uint8_t *p = (const uint8_t *)buf; |
manitou | 0:e5c9fd5789d7 | 122 | do { |
manitou | 0:e5c9fd5789d7 | 123 | Serial.printf("%02X ", *p++); |
manitou | 0:e5c9fd5789d7 | 124 | } while (--len > 0); |
manitou | 0:e5c9fd5789d7 | 125 | Serial.println(); |
manitou | 0:e5c9fd5789d7 | 126 | } |
manitou | 0:e5c9fd5789d7 | 127 | #endif |
manitou | 0:e5c9fd5789d7 | 128 | |
manitou | 0:e5c9fd5789d7 | 129 | SerialFlashFile SerialFlashChip::open(const char *filename) |
manitou | 0:e5c9fd5789d7 | 130 | { |
manitou | 0:e5c9fd5789d7 | 131 | uint32_t maxfiles, straddr; |
manitou | 0:e5c9fd5789d7 | 132 | uint16_t hash, hashtable[8]; |
manitou | 0:e5c9fd5789d7 | 133 | uint32_t i, n, index=0; |
manitou | 0:e5c9fd5789d7 | 134 | uint32_t buf[3]; |
manitou | 0:e5c9fd5789d7 | 135 | SerialFlashFile file; |
manitou | 0:e5c9fd5789d7 | 136 | |
manitou | 0:e5c9fd5789d7 | 137 | maxfiles = check_signature(); |
manitou | 0:e5c9fd5789d7 | 138 | //Serial.printf("sig: %08X\n", maxfiles); |
manitou | 0:e5c9fd5789d7 | 139 | if (!maxfiles) return file; |
manitou | 0:e5c9fd5789d7 | 140 | maxfiles &= 0xFFFF; |
manitou | 0:e5c9fd5789d7 | 141 | hash = filename_hash(filename); |
manitou | 0:e5c9fd5789d7 | 142 | //Serial.printf("hash %04X for \"%s\"\n", hash, filename); |
manitou | 0:e5c9fd5789d7 | 143 | while (index < maxfiles) { |
manitou | 0:e5c9fd5789d7 | 144 | n = 8; |
manitou | 0:e5c9fd5789d7 | 145 | if (n > maxfiles - index) n = maxfiles - index; |
manitou | 0:e5c9fd5789d7 | 146 | SerialFlash.read(8 + index * 2, hashtable, n * 2); |
manitou | 0:e5c9fd5789d7 | 147 | //Serial.printf(" read %u: ", 8 + index * 2); |
manitou | 0:e5c9fd5789d7 | 148 | //pbuf(hashtable, n * 2); |
manitou | 0:e5c9fd5789d7 | 149 | for (i=0; i < n; i++) { |
manitou | 0:e5c9fd5789d7 | 150 | if (hashtable[i] == hash) { |
manitou | 0:e5c9fd5789d7 | 151 | //Serial.printf(" hash match at index %u\n", index+i); |
manitou | 0:e5c9fd5789d7 | 152 | buf[2] = 0; |
manitou | 0:e5c9fd5789d7 | 153 | SerialFlash.read(8 + maxfiles * 2 + (index+i) * 10, buf, 10); |
manitou | 0:e5c9fd5789d7 | 154 | |
manitou | 0:e5c9fd5789d7 | 155 | //Serial.printf(" maxf=%d, index=%d, i=%d\n", maxfiles, index, i); |
manitou | 0:e5c9fd5789d7 | 156 | //Serial.printf(" read %u: ", 8 + maxfiles * 2 + (index+i) * 10); |
manitou | 0:e5c9fd5789d7 | 157 | //pbuf(buf, 10); |
manitou | 0:e5c9fd5789d7 | 158 | straddr = 8 + maxfiles * 12 + buf[2] * 4; |
manitou | 0:e5c9fd5789d7 | 159 | //Serial.printf(" straddr = %u\n", straddr); |
manitou | 0:e5c9fd5789d7 | 160 | if (filename_compare(filename, straddr)) { |
manitou | 0:e5c9fd5789d7 | 161 | //Serial.printf(" match!\n"); |
manitou | 0:e5c9fd5789d7 | 162 | //Serial.printf(" addr = %u\n", buf[0]); |
manitou | 0:e5c9fd5789d7 | 163 | //Serial.printf(" len = %u\n", buf[1]); |
manitou | 0:e5c9fd5789d7 | 164 | file.address = buf[0]; |
manitou | 0:e5c9fd5789d7 | 165 | file.length = buf[1]; |
manitou | 0:e5c9fd5789d7 | 166 | file.offset = 0; |
manitou | 0:e5c9fd5789d7 | 167 | file.dirindex = index + i; |
manitou | 0:e5c9fd5789d7 | 168 | return file; |
manitou | 0:e5c9fd5789d7 | 169 | } |
manitou | 0:e5c9fd5789d7 | 170 | } else if (hashtable[i] == 0xFFFF) { |
manitou | 0:e5c9fd5789d7 | 171 | return file; |
manitou | 0:e5c9fd5789d7 | 172 | } |
manitou | 0:e5c9fd5789d7 | 173 | } |
manitou | 0:e5c9fd5789d7 | 174 | index += n; |
manitou | 0:e5c9fd5789d7 | 175 | } |
manitou | 0:e5c9fd5789d7 | 176 | return file; |
manitou | 0:e5c9fd5789d7 | 177 | } |
manitou | 0:e5c9fd5789d7 | 178 | |
manitou | 0:e5c9fd5789d7 | 179 | bool SerialFlashChip::exists(const char *filename) |
manitou | 0:e5c9fd5789d7 | 180 | { |
manitou | 0:e5c9fd5789d7 | 181 | SerialFlashFile file = open(filename); |
manitou | 0:e5c9fd5789d7 | 182 | return (bool)file; |
manitou | 0:e5c9fd5789d7 | 183 | } |
manitou | 0:e5c9fd5789d7 | 184 | |
manitou | 0:e5c9fd5789d7 | 185 | bool SerialFlashChip::remove(const char *filename) |
manitou | 0:e5c9fd5789d7 | 186 | { |
manitou | 0:e5c9fd5789d7 | 187 | SerialFlashFile file = open(filename); |
manitou | 0:e5c9fd5789d7 | 188 | return remove(file); |
manitou | 0:e5c9fd5789d7 | 189 | } |
manitou | 0:e5c9fd5789d7 | 190 | |
manitou | 0:e5c9fd5789d7 | 191 | bool SerialFlashChip::remove(SerialFlashFile &file) |
manitou | 0:e5c9fd5789d7 | 192 | { |
manitou | 0:e5c9fd5789d7 | 193 | // To "remove" a file, we simply zero its hash in the lookup |
manitou | 0:e5c9fd5789d7 | 194 | // table, so it can't be found by open(). The space on the |
manitou | 0:e5c9fd5789d7 | 195 | // flash memory is not freed. |
manitou | 0:e5c9fd5789d7 | 196 | if (!file) return false; |
manitou | 0:e5c9fd5789d7 | 197 | uint16_t hash; |
manitou | 0:e5c9fd5789d7 | 198 | SerialFlash.read(8 + file.dirindex * 2, &hash, 2); |
manitou | 0:e5c9fd5789d7 | 199 | //Serial.printf("remove hash %04X at %d index\n", hash, file.dirindex); |
manitou | 0:e5c9fd5789d7 | 200 | hash ^= 0xFFFF; // write zeros to all ones |
manitou | 0:e5c9fd5789d7 | 201 | SerialFlash.write(8 + file.dirindex * 2, &hash, 2); |
manitou | 0:e5c9fd5789d7 | 202 | while (!SerialFlash.ready()) ; // wait... TODO: timeout |
manitou | 0:e5c9fd5789d7 | 203 | SerialFlash.read(8 + file.dirindex * 2, &hash, 2); |
manitou | 0:e5c9fd5789d7 | 204 | if (hash != 0) { |
manitou | 0:e5c9fd5789d7 | 205 | //Serial.printf("remove failed, hash %04X\n", hash); |
manitou | 0:e5c9fd5789d7 | 206 | return false; |
manitou | 0:e5c9fd5789d7 | 207 | } |
manitou | 0:e5c9fd5789d7 | 208 | file.address = 0; |
manitou | 0:e5c9fd5789d7 | 209 | file.length = 0; |
manitou | 0:e5c9fd5789d7 | 210 | return true; |
manitou | 0:e5c9fd5789d7 | 211 | } |
manitou | 0:e5c9fd5789d7 | 212 | |
manitou | 0:e5c9fd5789d7 | 213 | static uint32_t find_first_unallocated_file_index(uint32_t maxfiles) |
manitou | 0:e5c9fd5789d7 | 214 | { |
manitou | 0:e5c9fd5789d7 | 215 | uint16_t hashtable[8]; |
manitou | 0:e5c9fd5789d7 | 216 | uint32_t i, n, index=0; |
manitou | 0:e5c9fd5789d7 | 217 | |
manitou | 0:e5c9fd5789d7 | 218 | do { |
manitou | 0:e5c9fd5789d7 | 219 | n = 8; |
manitou | 0:e5c9fd5789d7 | 220 | if (index + n > maxfiles) n = maxfiles - index; |
manitou | 0:e5c9fd5789d7 | 221 | SerialFlash.read(8 + index * 2, hashtable, n * 2); |
manitou | 0:e5c9fd5789d7 | 222 | for (i=0; i < n; i++) { |
manitou | 0:e5c9fd5789d7 | 223 | if (hashtable[i] == 0xFFFF) return index + i; |
manitou | 0:e5c9fd5789d7 | 224 | } |
manitou | 0:e5c9fd5789d7 | 225 | index += n; |
manitou | 0:e5c9fd5789d7 | 226 | } while (index < maxfiles); |
manitou | 0:e5c9fd5789d7 | 227 | return 0xFFFFFFFF; |
manitou | 0:e5c9fd5789d7 | 228 | } |
manitou | 0:e5c9fd5789d7 | 229 | |
manitou | 0:e5c9fd5789d7 | 230 | static uint32_t string_length(uint32_t addr) |
manitou | 0:e5c9fd5789d7 | 231 | { |
manitou | 0:e5c9fd5789d7 | 232 | char buf[16]; |
manitou | 0:e5c9fd5789d7 | 233 | const char *p; |
manitou | 0:e5c9fd5789d7 | 234 | uint32_t len=0; |
manitou | 0:e5c9fd5789d7 | 235 | |
manitou | 0:e5c9fd5789d7 | 236 | while (1) { |
manitou | 0:e5c9fd5789d7 | 237 | SerialFlash.read(addr, buf, sizeof(buf)); |
manitou | 0:e5c9fd5789d7 | 238 | for (p=buf; p < buf + sizeof(buf); p++) { |
manitou | 0:e5c9fd5789d7 | 239 | len++; |
manitou | 0:e5c9fd5789d7 | 240 | if (*p == 0) return len; |
manitou | 0:e5c9fd5789d7 | 241 | } |
manitou | 0:e5c9fd5789d7 | 242 | addr += sizeof(buf); |
manitou | 0:e5c9fd5789d7 | 243 | } |
manitou | 0:e5c9fd5789d7 | 244 | } |
manitou | 0:e5c9fd5789d7 | 245 | |
manitou | 0:e5c9fd5789d7 | 246 | // uint32_t signature = 0xFA96554C; |
manitou | 0:e5c9fd5789d7 | 247 | // uint16_t maxfiles |
manitou | 0:e5c9fd5789d7 | 248 | // uint16_t stringssize // div by 4 |
manitou | 0:e5c9fd5789d7 | 249 | // uint16_t hashes[maxfiles] |
manitou | 0:e5c9fd5789d7 | 250 | // struct { |
manitou | 0:e5c9fd5789d7 | 251 | // uint32_t file_begin |
manitou | 0:e5c9fd5789d7 | 252 | // uint32_t file_length |
manitou | 0:e5c9fd5789d7 | 253 | // uint16_t string_index // div 4 |
manitou | 0:e5c9fd5789d7 | 254 | // } fileinfo[maxfiles] |
manitou | 0:e5c9fd5789d7 | 255 | // char strings[stringssize] |
manitou | 0:e5c9fd5789d7 | 256 | |
manitou | 0:e5c9fd5789d7 | 257 | bool SerialFlashChip::create(const char *filename, uint32_t length, uint32_t align) |
manitou | 0:e5c9fd5789d7 | 258 | { |
manitou | 0:e5c9fd5789d7 | 259 | uint32_t maxfiles, stringsize; |
manitou | 0:e5c9fd5789d7 | 260 | uint32_t index, buf[3]; |
manitou | 0:e5c9fd5789d7 | 261 | uint32_t address, straddr, len; |
manitou | 0:e5c9fd5789d7 | 262 | SerialFlashFile file; |
manitou | 0:e5c9fd5789d7 | 263 | |
manitou | 0:e5c9fd5789d7 | 264 | // check if the file already exists |
manitou | 0:e5c9fd5789d7 | 265 | if (exists(filename)) return false; |
manitou | 0:e5c9fd5789d7 | 266 | |
manitou | 0:e5c9fd5789d7 | 267 | // first, get the filesystem parameters |
manitou | 0:e5c9fd5789d7 | 268 | maxfiles = check_signature(); |
manitou | 0:e5c9fd5789d7 | 269 | if (!maxfiles) return false; |
manitou | 0:e5c9fd5789d7 | 270 | stringsize = (maxfiles & 0xFFFF0000) >> 14; |
manitou | 0:e5c9fd5789d7 | 271 | maxfiles &= 0xFFFF; |
manitou | 0:e5c9fd5789d7 | 272 | |
manitou | 0:e5c9fd5789d7 | 273 | // find the first unused slot for this file |
manitou | 0:e5c9fd5789d7 | 274 | index = find_first_unallocated_file_index(maxfiles); |
manitou | 0:e5c9fd5789d7 | 275 | if (index >= maxfiles) return false; |
manitou | 0:e5c9fd5789d7 | 276 | //Serial.printf("index = %u\n", index); |
manitou | 0:e5c9fd5789d7 | 277 | // compute where to store the filename and actual data |
manitou | 0:e5c9fd5789d7 | 278 | straddr = 8 + maxfiles * 12; |
manitou | 0:e5c9fd5789d7 | 279 | if (index == 0) { |
manitou | 0:e5c9fd5789d7 | 280 | address = straddr + stringsize; |
manitou | 0:e5c9fd5789d7 | 281 | } else { |
manitou | 0:e5c9fd5789d7 | 282 | buf[2] = 0; |
manitou | 0:e5c9fd5789d7 | 283 | SerialFlash.read(8 + maxfiles * 2 + (index-1) * 10, buf, 10); |
manitou | 0:e5c9fd5789d7 | 284 | address = buf[0] + buf[1]; |
manitou | 0:e5c9fd5789d7 | 285 | straddr += buf[2] * 4; |
manitou | 0:e5c9fd5789d7 | 286 | straddr += string_length(straddr); |
manitou | 0:e5c9fd5789d7 | 287 | straddr = (straddr + 3) & 0x0003FFFC; |
manitou | 0:e5c9fd5789d7 | 288 | } |
manitou | 0:e5c9fd5789d7 | 289 | //Serial.printf("straddr = %u\n", straddr); |
manitou | 0:e5c9fd5789d7 | 290 | //Serial.printf("address = %u\n", address); |
manitou | 0:e5c9fd5789d7 | 291 | //Serial.printf("length = %u\n", length); |
manitou | 0:e5c9fd5789d7 | 292 | if (align > 0) { |
manitou | 0:e5c9fd5789d7 | 293 | // for files aligned to sectors, adjust addr & len |
manitou | 0:e5c9fd5789d7 | 294 | address += align - 1; |
manitou | 0:e5c9fd5789d7 | 295 | address /= align; |
manitou | 0:e5c9fd5789d7 | 296 | address *= align; |
manitou | 0:e5c9fd5789d7 | 297 | //Serial.printf("align address = %u\n", address); |
manitou | 0:e5c9fd5789d7 | 298 | length += align - 1; |
manitou | 0:e5c9fd5789d7 | 299 | length /= align; |
manitou | 0:e5c9fd5789d7 | 300 | length *= align; |
manitou | 0:e5c9fd5789d7 | 301 | //Serial.printf("align length = %u\n", length); |
manitou | 0:e5c9fd5789d7 | 302 | } else { |
manitou | 0:e5c9fd5789d7 | 303 | // always align every file to a page boundary |
manitou | 0:e5c9fd5789d7 | 304 | // for predictable write latency and to guarantee |
manitou | 0:e5c9fd5789d7 | 305 | // write suspend for reading another file can't |
manitou | 0:e5c9fd5789d7 | 306 | // conflict on the same page (2 files never share |
manitou | 0:e5c9fd5789d7 | 307 | // a write page). |
manitou | 0:e5c9fd5789d7 | 308 | address = (address + 255) & 0xFFFFFF00; |
manitou | 0:e5c9fd5789d7 | 309 | } |
manitou | 0:e5c9fd5789d7 | 310 | //Serial.printf("address = %u\n", address); |
manitou | 0:e5c9fd5789d7 | 311 | // last check, if enough space exists... |
manitou | 0:e5c9fd5789d7 | 312 | len = strlen(filename); |
manitou | 0:e5c9fd5789d7 | 313 | // TODO: check for enough string space for filename |
manitou | 0:e5c9fd5789d7 | 314 | uint8_t id[3]; |
manitou | 0:e5c9fd5789d7 | 315 | SerialFlash.readID(id); |
manitou | 0:e5c9fd5789d7 | 316 | if (address + length > SerialFlash.capacity(id)) return false; |
manitou | 0:e5c9fd5789d7 | 317 | |
manitou | 0:e5c9fd5789d7 | 318 | SerialFlash.write(straddr, filename, len+1); |
manitou | 0:e5c9fd5789d7 | 319 | buf[0] = address; |
manitou | 0:e5c9fd5789d7 | 320 | buf[1] = length; |
manitou | 0:e5c9fd5789d7 | 321 | buf[2] = (straddr - (8 + maxfiles * 12)) / 4; |
manitou | 0:e5c9fd5789d7 | 322 | SerialFlash.write(8 + maxfiles * 2 + index * 10, buf, 10); |
manitou | 0:e5c9fd5789d7 | 323 | //Serial.printf(" write %u: ", 8 + maxfiles * 2 + index * 10); |
manitou | 0:e5c9fd5789d7 | 324 | //pbuf(buf, 10); |
manitou | 0:e5c9fd5789d7 | 325 | while (!SerialFlash.ready()) ; // TODO: timeout |
manitou | 0:e5c9fd5789d7 | 326 | |
manitou | 0:e5c9fd5789d7 | 327 | buf[0] = filename_hash(filename); |
manitou | 0:e5c9fd5789d7 | 328 | //Serial.printf("hash = %04X\n", buf[0]); |
manitou | 0:e5c9fd5789d7 | 329 | SerialFlash.write(8 + index * 2, buf, 2); |
manitou | 0:e5c9fd5789d7 | 330 | while (!SerialFlash.ready()) ; // TODO: timeout |
manitou | 0:e5c9fd5789d7 | 331 | return true; |
manitou | 0:e5c9fd5789d7 | 332 | } |
manitou | 0:e5c9fd5789d7 | 333 | |
manitou | 0:e5c9fd5789d7 | 334 | bool SerialFlashChip::readdir(char *filename, uint32_t strsize, uint32_t &filesize) |
manitou | 0:e5c9fd5789d7 | 335 | { |
manitou | 0:e5c9fd5789d7 | 336 | uint32_t maxfiles, index, straddr; |
manitou | 0:e5c9fd5789d7 | 337 | uint32_t i, n; |
manitou | 0:e5c9fd5789d7 | 338 | uint32_t buf[2]; |
manitou | 0:e5c9fd5789d7 | 339 | uint16_t hash; |
manitou | 0:e5c9fd5789d7 | 340 | char str[16], *p=filename; |
manitou | 0:e5c9fd5789d7 | 341 | |
manitou | 0:e5c9fd5789d7 | 342 | filename[0] = 0; |
manitou | 0:e5c9fd5789d7 | 343 | maxfiles = check_signature(); |
manitou | 0:e5c9fd5789d7 | 344 | if (!maxfiles) return false; |
manitou | 0:e5c9fd5789d7 | 345 | maxfiles &= 0xFFFF; |
manitou | 0:e5c9fd5789d7 | 346 | index = dirindex; |
manitou | 0:e5c9fd5789d7 | 347 | while (1) { |
manitou | 0:e5c9fd5789d7 | 348 | if (index >= maxfiles) return false; |
manitou | 0:e5c9fd5789d7 | 349 | //Serial.printf("readdir, index = %u\n", index); |
manitou | 0:e5c9fd5789d7 | 350 | SerialFlash.read(8 + index * 2, &hash, 2); |
manitou | 0:e5c9fd5789d7 | 351 | if (hash != 0) break; |
manitou | 0:e5c9fd5789d7 | 352 | index++; // skip deleted entries |
manitou | 0:e5c9fd5789d7 | 353 | } |
manitou | 0:e5c9fd5789d7 | 354 | dirindex = index + 1; |
manitou | 0:e5c9fd5789d7 | 355 | buf[1] = 0; |
manitou | 0:e5c9fd5789d7 | 356 | SerialFlash.read(8 + 4 + maxfiles * 2 + index * 10, buf, 6); |
manitou | 0:e5c9fd5789d7 | 357 | if (buf[0] == 0xFFFFFFFF) return false; |
manitou | 0:e5c9fd5789d7 | 358 | filesize = buf[0]; |
manitou | 0:e5c9fd5789d7 | 359 | straddr = 8 + maxfiles * 12 + buf[1] * 4; |
manitou | 0:e5c9fd5789d7 | 360 | //Serial.printf(" length = %u\n", buf[0]); |
manitou | 0:e5c9fd5789d7 | 361 | //Serial.printf(" straddr = %u\n", straddr); |
manitou | 0:e5c9fd5789d7 | 362 | |
manitou | 0:e5c9fd5789d7 | 363 | while (strsize) { |
manitou | 0:e5c9fd5789d7 | 364 | n = strsize; |
manitou | 0:e5c9fd5789d7 | 365 | if (n > sizeof(str)) n = sizeof(str); |
manitou | 0:e5c9fd5789d7 | 366 | SerialFlash.read(straddr, str, n); |
manitou | 0:e5c9fd5789d7 | 367 | for (i=0; i < n; i++) { |
manitou | 0:e5c9fd5789d7 | 368 | *p++ = str[i]; |
manitou | 0:e5c9fd5789d7 | 369 | if (str[i] == 0) { |
manitou | 0:e5c9fd5789d7 | 370 | //Serial.printf(" name = %s\n", filename); |
manitou | 0:e5c9fd5789d7 | 371 | return true; |
manitou | 0:e5c9fd5789d7 | 372 | } |
manitou | 0:e5c9fd5789d7 | 373 | } |
manitou | 0:e5c9fd5789d7 | 374 | strsize -= n; |
manitou | 0:e5c9fd5789d7 | 375 | straddr += n; |
manitou | 0:e5c9fd5789d7 | 376 | } |
manitou | 0:e5c9fd5789d7 | 377 | *(p - 1) = 0; |
manitou | 0:e5c9fd5789d7 | 378 | //Serial.printf(" name(overflow) = %s\n", filename); |
manitou | 0:e5c9fd5789d7 | 379 | return true; |
manitou | 0:e5c9fd5789d7 | 380 | } |
manitou | 0:e5c9fd5789d7 | 381 | |
manitou | 0:e5c9fd5789d7 | 382 | |
manitou | 0:e5c9fd5789d7 | 383 | void SerialFlashFile::erase() |
manitou | 0:e5c9fd5789d7 | 384 | { |
manitou | 0:e5c9fd5789d7 | 385 | uint32_t i, blocksize; |
manitou | 0:e5c9fd5789d7 | 386 | |
manitou | 0:e5c9fd5789d7 | 387 | blocksize = SerialFlash.blockSize(); |
manitou | 0:e5c9fd5789d7 | 388 | if (address & (blocksize - 1)) return; // must begin on a block boundary |
manitou | 0:e5c9fd5789d7 | 389 | if (length & (blocksize - 1)) return; // must be exact number of blocks |
manitou | 0:e5c9fd5789d7 | 390 | for (i=0; i < length; i += blocksize) { |
manitou | 0:e5c9fd5789d7 | 391 | SerialFlash.eraseBlock(address + i); |
manitou | 0:e5c9fd5789d7 | 392 | } |
manitou | 0:e5c9fd5789d7 | 393 | } |
manitou | 0:e5c9fd5789d7 | 394 |