Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
SerialFlashDirectory.cpp
00001 /* SerialFlash Library - for filesystem-like access to SPI Serial Flash memory 00002 * https://github.com/PaulStoffregen/SerialFlash 00003 * Copyright (C) 2015, Paul Stoffregen, paul@pjrc.com 00004 * 00005 * Development of this library was funded by PJRC.COM, LLC by sales of Teensy. 00006 * Please support PJRC's efforts to develop open source software by purchasing 00007 * Teensy or other genuine PJRC products. 00008 * 00009 * Permission is hereby granted, free of charge, to any person obtaining a copy 00010 * of this software and associated documentation files (the "Software"), to deal 00011 * in the Software without restriction, including without limitation the rights 00012 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00013 * copies of the Software, and to permit persons to whom the Software is 00014 * furnished to do so, subject to the following conditions: 00015 * 00016 * The above copyright notice, development funding notice, and this permission 00017 * notice shall be included in all copies or substantial portions of the Software. 00018 * 00019 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00020 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00021 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00022 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00023 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00024 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00025 * THE SOFTWARE. 00026 */ 00027 #include "mbed.h" 00028 #include "SerialFlash.h" 00029 //#include "util/crc16.h" 00030 00031 /* On-chip SerialFlash file allocation data structures: 00032 00033 uint32_t signature = 0xFA96554C; 00034 uint16_t maxfiles 00035 uint16_t stringssize // div by 4 00036 uint16_t hashes[maxfiles] 00037 struct { 00038 uint32_t file_begin 00039 uint32_t file_length 00040 uint16_t string_index // div4 00041 } fileinfo[maxfiles] 00042 char strings[stringssize] 00043 00044 A 32 bit signature is stored at the beginning of the flash memory. 00045 If 0xFFFFFFFF is seen, the entire chip should be assumed blank. 00046 If any value other than 0xFA96554C is found, a different data format 00047 is stored. This could should refuse to access the flash. 00048 00049 The next 4 bytes store number of files and size of the strings 00050 section, which allow the position of every other item to be found. 00051 The string section size is the 16 bit integer times 4, which allows 00052 up to 262140 bytes for string data. 00053 00054 An array of 16 bit filename hashes allows for quick linear search 00055 for potentially matching filenames. A hash value of 0xFFFF indicates 00056 no file is allocated for the remainder of the array. 00057 00058 Following the hashes, and array of 10 byte structs give the location 00059 and length of the file's actual data, and the offset of its filename 00060 in the strings section. 00061 00062 Strings are null terminated. The remainder of the chip is file data. 00063 */ 00064 00065 #define DEFAULT_MAXFILES 600 00066 #define DEFAULT_STRINGS_SIZE 25560 00067 00068 00069 static uint32_t check_signature(void) 00070 { 00071 uint32_t sig[2]; 00072 00073 SerialFlash.read(0, sig, 8); 00074 //Serial.printf("sig: %08X %08X\n", sig[0], sig[1]); 00075 if (sig[0] == 0xFA96554C) return sig[1]; 00076 if (sig[0] == 0xFFFFFFFF) { 00077 sig[0] = 0xFA96554C; 00078 sig[1] = ((uint32_t)(DEFAULT_STRINGS_SIZE/4) << 16) | DEFAULT_MAXFILES; 00079 SerialFlash.write(0, sig, 8); 00080 while (!SerialFlash.ready()) ; // TODO: timeout 00081 SerialFlash.read(0, sig, 8); 00082 if (sig[0] == 0xFA96554C) return sig[1]; 00083 } 00084 return 0; 00085 } 00086 00087 static uint16_t filename_hash(const char *filename) 00088 { 00089 // http://isthe.com/chongo/tech/comp/fnv/ 00090 uint32_t hash = 2166136261; 00091 const char *p; 00092 00093 for (p=filename; *p; p++) { 00094 hash ^= *p; 00095 hash *= 16777619; 00096 } 00097 hash = (hash % (uint32_t)0xFFFE) + 1; // all values except 0000 & FFFF 00098 return hash; 00099 } 00100 00101 static bool filename_compare(const char *filename, uint32_t straddr) 00102 { 00103 unsigned int i; 00104 const char *p; 00105 char buf[16]; 00106 00107 p = filename; 00108 while (1) { 00109 SerialFlash.read(straddr, buf, sizeof(buf)); 00110 straddr += sizeof(buf); 00111 for (i=0; i < sizeof(buf); i++) { 00112 if (*p++ != buf[i]) return false; 00113 if (buf[i] == 0) return true; 00114 } 00115 } 00116 } 00117 00118 #if 0 00119 void pbuf(const void *buf, uint32_t len) 00120 { 00121 const uint8_t *p = (const uint8_t *)buf; 00122 do { 00123 Serial.printf("%02X ", *p++); 00124 } while (--len > 0); 00125 Serial.println(); 00126 } 00127 #endif 00128 00129 SerialFlashFile SerialFlashChip::open(const char *filename) 00130 { 00131 uint32_t maxfiles, straddr; 00132 uint16_t hash, hashtable[8]; 00133 uint32_t i, n, index=0; 00134 uint32_t buf[3]; 00135 SerialFlashFile file; 00136 00137 maxfiles = check_signature(); 00138 //Serial.printf("sig: %08X\n", maxfiles); 00139 if (!maxfiles) return file; 00140 maxfiles &= 0xFFFF; 00141 hash = filename_hash(filename); 00142 //Serial.printf("hash %04X for \"%s\"\n", hash, filename); 00143 while (index < maxfiles) { 00144 n = 8; 00145 if (n > maxfiles - index) n = maxfiles - index; 00146 SerialFlash.read(8 + index * 2, hashtable, n * 2); 00147 //Serial.printf(" read %u: ", 8 + index * 2); 00148 //pbuf(hashtable, n * 2); 00149 for (i=0; i < n; i++) { 00150 if (hashtable[i] == hash) { 00151 //Serial.printf(" hash match at index %u\n", index+i); 00152 buf[2] = 0; 00153 SerialFlash.read(8 + maxfiles * 2 + (index+i) * 10, buf, 10); 00154 00155 //Serial.printf(" maxf=%d, index=%d, i=%d\n", maxfiles, index, i); 00156 //Serial.printf(" read %u: ", 8 + maxfiles * 2 + (index+i) * 10); 00157 //pbuf(buf, 10); 00158 straddr = 8 + maxfiles * 12 + buf[2] * 4; 00159 //Serial.printf(" straddr = %u\n", straddr); 00160 if (filename_compare(filename, straddr)) { 00161 //Serial.printf(" match!\n"); 00162 //Serial.printf(" addr = %u\n", buf[0]); 00163 //Serial.printf(" len = %u\n", buf[1]); 00164 file.address = buf[0]; 00165 file.length = buf[1]; 00166 file.offset = 0; 00167 file.dirindex = index + i; 00168 return file; 00169 } 00170 } else if (hashtable[i] == 0xFFFF) { 00171 return file; 00172 } 00173 } 00174 index += n; 00175 } 00176 return file; 00177 } 00178 00179 bool SerialFlashChip::exists(const char *filename) 00180 { 00181 SerialFlashFile file = open(filename); 00182 return (bool)file; 00183 } 00184 00185 bool SerialFlashChip::remove(const char *filename) 00186 { 00187 SerialFlashFile file = open(filename); 00188 return remove(file); 00189 } 00190 00191 bool SerialFlashChip::remove(SerialFlashFile &file) 00192 { 00193 // To "remove" a file, we simply zero its hash in the lookup 00194 // table, so it can't be found by open(). The space on the 00195 // flash memory is not freed. 00196 if (!file) return false; 00197 uint16_t hash; 00198 SerialFlash.read(8 + file.dirindex * 2, &hash, 2); 00199 //Serial.printf("remove hash %04X at %d index\n", hash, file.dirindex); 00200 hash ^= 0xFFFF; // write zeros to all ones 00201 SerialFlash.write(8 + file.dirindex * 2, &hash, 2); 00202 while (!SerialFlash.ready()) ; // wait... TODO: timeout 00203 SerialFlash.read(8 + file.dirindex * 2, &hash, 2); 00204 if (hash != 0) { 00205 //Serial.printf("remove failed, hash %04X\n", hash); 00206 return false; 00207 } 00208 file.address = 0; 00209 file.length = 0; 00210 return true; 00211 } 00212 00213 static uint32_t find_first_unallocated_file_index(uint32_t maxfiles) 00214 { 00215 uint16_t hashtable[8]; 00216 uint32_t i, n, index=0; 00217 00218 do { 00219 n = 8; 00220 if (index + n > maxfiles) n = maxfiles - index; 00221 SerialFlash.read(8 + index * 2, hashtable, n * 2); 00222 for (i=0; i < n; i++) { 00223 if (hashtable[i] == 0xFFFF) return index + i; 00224 } 00225 index += n; 00226 } while (index < maxfiles); 00227 return 0xFFFFFFFF; 00228 } 00229 00230 static uint32_t string_length(uint32_t addr) 00231 { 00232 char buf[16]; 00233 const char *p; 00234 uint32_t len=0; 00235 00236 while (1) { 00237 SerialFlash.read(addr, buf, sizeof(buf)); 00238 for (p=buf; p < buf + sizeof(buf); p++) { 00239 len++; 00240 if (*p == 0) return len; 00241 } 00242 addr += sizeof(buf); 00243 } 00244 } 00245 00246 // uint32_t signature = 0xFA96554C; 00247 // uint16_t maxfiles 00248 // uint16_t stringssize // div by 4 00249 // uint16_t hashes[maxfiles] 00250 // struct { 00251 // uint32_t file_begin 00252 // uint32_t file_length 00253 // uint16_t string_index // div 4 00254 // } fileinfo[maxfiles] 00255 // char strings[stringssize] 00256 00257 bool SerialFlashChip::create(const char *filename, uint32_t length, uint32_t align) 00258 { 00259 uint32_t maxfiles, stringsize; 00260 uint32_t index, buf[3]; 00261 uint32_t address, straddr, len; 00262 SerialFlashFile file; 00263 00264 // check if the file already exists 00265 if (exists(filename)) return false; 00266 00267 // first, get the filesystem parameters 00268 maxfiles = check_signature(); 00269 if (!maxfiles) return false; 00270 stringsize = (maxfiles & 0xFFFF0000) >> 14; 00271 maxfiles &= 0xFFFF; 00272 00273 // find the first unused slot for this file 00274 index = find_first_unallocated_file_index(maxfiles); 00275 if (index >= maxfiles) return false; 00276 //Serial.printf("index = %u\n", index); 00277 // compute where to store the filename and actual data 00278 straddr = 8 + maxfiles * 12; 00279 if (index == 0) { 00280 address = straddr + stringsize; 00281 } else { 00282 buf[2] = 0; 00283 SerialFlash.read(8 + maxfiles * 2 + (index-1) * 10, buf, 10); 00284 address = buf[0] + buf[1]; 00285 straddr += buf[2] * 4; 00286 straddr += string_length(straddr); 00287 straddr = (straddr + 3) & 0x0003FFFC; 00288 } 00289 //Serial.printf("straddr = %u\n", straddr); 00290 //Serial.printf("address = %u\n", address); 00291 //Serial.printf("length = %u\n", length); 00292 if (align > 0) { 00293 // for files aligned to sectors, adjust addr & len 00294 address += align - 1; 00295 address /= align; 00296 address *= align; 00297 //Serial.printf("align address = %u\n", address); 00298 length += align - 1; 00299 length /= align; 00300 length *= align; 00301 //Serial.printf("align length = %u\n", length); 00302 } else { 00303 // always align every file to a page boundary 00304 // for predictable write latency and to guarantee 00305 // write suspend for reading another file can't 00306 // conflict on the same page (2 files never share 00307 // a write page). 00308 address = (address + 255) & 0xFFFFFF00; 00309 } 00310 //Serial.printf("address = %u\n", address); 00311 // last check, if enough space exists... 00312 len = strlen(filename); 00313 // TODO: check for enough string space for filename 00314 uint8_t id[3]; 00315 SerialFlash.readID(id); 00316 if (address + length > SerialFlash.capacity(id)) return false; 00317 00318 SerialFlash.write(straddr, filename, len+1); 00319 buf[0] = address; 00320 buf[1] = length; 00321 buf[2] = (straddr - (8 + maxfiles * 12)) / 4; 00322 SerialFlash.write(8 + maxfiles * 2 + index * 10, buf, 10); 00323 //Serial.printf(" write %u: ", 8 + maxfiles * 2 + index * 10); 00324 //pbuf(buf, 10); 00325 while (!SerialFlash.ready()) ; // TODO: timeout 00326 00327 buf[0] = filename_hash(filename); 00328 //Serial.printf("hash = %04X\n", buf[0]); 00329 SerialFlash.write(8 + index * 2, buf, 2); 00330 while (!SerialFlash.ready()) ; // TODO: timeout 00331 return true; 00332 } 00333 00334 bool SerialFlashChip::readdir(char *filename, uint32_t strsize, uint32_t &filesize) 00335 { 00336 uint32_t maxfiles, index, straddr; 00337 uint32_t i, n; 00338 uint32_t buf[2]; 00339 uint16_t hash; 00340 char str[16], *p=filename; 00341 00342 filename[0] = 0; 00343 maxfiles = check_signature(); 00344 if (!maxfiles) return false; 00345 maxfiles &= 0xFFFF; 00346 index = dirindex; 00347 while (1) { 00348 if (index >= maxfiles) return false; 00349 //Serial.printf("readdir, index = %u\n", index); 00350 SerialFlash.read(8 + index * 2, &hash, 2); 00351 if (hash != 0) break; 00352 index++; // skip deleted entries 00353 } 00354 dirindex = index + 1; 00355 buf[1] = 0; 00356 SerialFlash.read(8 + 4 + maxfiles * 2 + index * 10, buf, 6); 00357 if (buf[0] == 0xFFFFFFFF) return false; 00358 filesize = buf[0]; 00359 straddr = 8 + maxfiles * 12 + buf[1] * 4; 00360 //Serial.printf(" length = %u\n", buf[0]); 00361 //Serial.printf(" straddr = %u\n", straddr); 00362 00363 while (strsize) { 00364 n = strsize; 00365 if (n > sizeof(str)) n = sizeof(str); 00366 SerialFlash.read(straddr, str, n); 00367 for (i=0; i < n; i++) { 00368 *p++ = str[i]; 00369 if (str[i] == 0) { 00370 //Serial.printf(" name = %s\n", filename); 00371 return true; 00372 } 00373 } 00374 strsize -= n; 00375 straddr += n; 00376 } 00377 *(p - 1) = 0; 00378 //Serial.printf(" name(overflow) = %s\n", filename); 00379 return true; 00380 } 00381 00382 00383 void SerialFlashFile::erase() 00384 { 00385 uint32_t i, blocksize; 00386 00387 blocksize = SerialFlash.blockSize(); 00388 if (address & (blocksize - 1)) return; // must begin on a block boundary 00389 if (length & (blocksize - 1)) return; // must be exact number of blocks 00390 for (i=0; i < length; i += blocksize) { 00391 SerialFlash.eraseBlock(address + i); 00392 } 00393 } 00394
Generated on Tue Jul 12 2022 20:36:33 by
