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.
mfs.cpp
00001 /** @file mfs.cpp */ 00002 /*CPP************************************************************************** 00003 * FILENAME : mfs.cpp * 00004 * * 00005 * DESCRIPTION : * 00006 * mFS file system implementation for mBED with external I2C EEEPROM. * 00007 * * 00008 * AUTHOR : Olli Vanhoja START DATE : 2011-02-21 * 00009 *****************************************************************************/ 00010 00011 #include "mbed.h" 00012 #include "mfs.h " 00013 #include "i2c_eeprom.h" 00014 00015 #define BLOCK_LLEN 2 /**< Block number link length in bytes */ 00016 #define RB 1+2*BLOCK_LLEN /**< Reseved bytes per block (1 attrb B, 2 B for next/prev pointers */ 00017 #define I2C_SPEED 200000 /**< I2C bus speed in Hz */ 00018 #define DEBUG /**< Adds extra safety in reading and writing */ 00019 00020 DigitalOut FlushLed(LED2); /**< Flush led */ 00021 00022 mfs::mfs(int i2c_address) 00023 { 00024 mem = new i2c_eeprom(i2c_address, I2C_SPEED); 00025 } 00026 00027 char mfs::read(char *data, uint32_t block, uint32_t byte, uint32_t n) 00028 { 00029 // Faster reading without DEBUG mode 00030 #ifdef DEBUG 00031 if ((byte+n-1 >= BS)) 00032 return 1; 00033 #endif 00034 mem->read(BS*block+byte, n, data); 00035 00036 return 0; 00037 } 00038 00039 char mfs::write(char *data, uint32_t block, uint32_t byte, uint32_t n) 00040 { 00041 // Faster writing without DEBUG mode 00042 #ifdef DEBUG 00043 if (byte+n >= BS) 00044 return 1; 00045 #endif 00046 mem->write(data, BS*block+byte, n); 00047 00048 return 0; 00049 } 00050 00051 char mfs::getNextFreeBlock(uint32_t *blockOut) 00052 { 00053 // Locate free block by seeking EERPOM 00054 char cFlags[1]; 00055 00056 for (*blockOut=0; *blockOut < BC; (*blockOut)++) 00057 { 00058 read(cFlags, *blockOut, 0, 1); 00059 if (cFlags[0] == 0x04) 00060 break; 00061 if (*blockOut >= BC-1) 00062 return 1; 00063 } 00064 00065 return 0; 00066 } 00067 00068 char mfs::findNextFile(uint32_t block, char *filenameOut, uint32_t *blockOut) 00069 { 00070 uint32_t i=block; 00071 char cFlags[1]; 00072 00073 while (i < BC) 00074 { 00075 read(cFlags, i, 0, 1); 00076 00077 if ((cFlags[0] & 0x8C) == 0x8C) 00078 break; // File found 00079 else 00080 i++; 00081 } 00082 00083 if(i == BC) 00084 { 00085 strcpy(filenameOut, ""); 00086 return 1; // Empty fs 00087 } 00088 00089 // Read filename 00090 read(filenameOut, i, RB, 20); 00091 *blockOut = i; // Return block number 00092 return 0; 00093 } 00094 00095 char mfs::getFirstBlockOfFile(char filename[20], uint32_t *blockOut) 00096 { 00097 *blockOut=0; 00098 char tmpFilename[20]=""; 00099 00100 while (1) 00101 { 00102 if (findNextFile(*blockOut, tmpFilename, blockOut) == 0) 00103 { 00104 if(strcmp(tmpFilename, filename) == 0) 00105 return 0; // File exists 00106 } 00107 else return 1; // File doesn't exist 00108 (*blockOut)++; 00109 } 00110 } 00111 00112 char mfs::createFile(char filename[20]) 00113 { 00114 char tmpFilename[20]; 00115 uint32_t n; 00116 uint32_t fb; 00117 00118 for (n=0; n < BC; n++) 00119 { 00120 if(findNextFile(n, tmpFilename, &n) == 0) 00121 { 00122 if(strcmp(tmpFilename, filename) == 0) 00123 return 1; // File exist 00124 } 00125 else break; // We already reached the edge of the universe 00126 n++; 00127 } 00128 00129 if(getNextFreeBlock(&fb) != 0) 00130 return 2; // Out of space 00131 00132 char cData[RB+20+1]; 00133 cData[0] = '\xCC'; // Necessary flags for a file 00134 cData[1] = '\0'; // No more blocks yet 00135 cData[2] = '\0'; 00136 cData[3] = '\0'; // First block so there is no prev blocks 00137 cData[4] = '\0'; 00138 cData[RB+20] = mEOF; // Set EOF at the begining 00139 00140 for (char i=0; i < 20; i++) 00141 cData[RB+i] = filename[i]; 00142 00143 // Create file 00144 write(cData, fb, 0, RB+20+1); 00145 00146 return 0; 00147 } 00148 00149 char mfs::removeFile(char filename[20]) 00150 { 00151 uint32_t block; 00152 char cData[RB-BLOCK_LLEN]; 00153 char cDataNew[RB] = {'\x04', '\0', '\0', '\0', '\0'}; 00154 uint32_t i=0; 00155 00156 // Check if file exists 00157 if (getFirstBlockOfFile(filename, &block) != 0) 00158 return 1; // File not found 00159 00160 read(cData, block, 0, RB-BLOCK_LLEN); 00161 00162 // Check credentials 00163 if (((cData[0] & 0x01)|((cData[0] & 0x10) >> 3)|((cData[0] & 0x20) >> 3) & 0x04) != 0) 00164 return 2; // RO file 00165 00166 // Clear blocks reserved by the file 00167 while(1) 00168 { 00169 write(cDataNew, block, 0, RB); 00170 if ((cData[0] & 0x4C) == 0x4C) 00171 break; // End of file found 00172 else block = (uint32_t)(cData[1])<<8|cData[2]; // Set next block number 00173 i++; 00174 if (i > BC) 00175 return 1; // fs is corrupted 00176 read(cData, block, 0, RB-BLOCK_LLEN); 00177 } 00178 00179 return 0; // Everything went better than expected 00180 } 00181 00182 char mfs::renameFile(char oldFilename[20], char newFilename[20]) 00183 { 00184 uint32_t block; 00185 char cData[1]; 00186 00187 // Check if file exists 00188 if (getFirstBlockOfFile(oldFilename, &block) != 0) 00189 return 1; // File not found 00190 00191 // Check credentials 00192 read(cData, block, 0, 1); 00193 char flags = (cData[0] & 0x01)|((cData[0] & 0x10) >> 3)|((cData[0] & 0x20) >> 3); 00194 if ((flags & 0x04) != 0) 00195 return 2; // RO file 00196 00197 write(newFilename, block, RB, 20); 00198 00199 return 0; // Everything went better than expected 00200 } 00201 00202 char mfs::setFileFlags(char *flags, char filename[20]) 00203 { 00204 /* RO|HIDDEN|LOCK * 00205 * H L */ 00206 00207 uint32_t n; 00208 char cData[1] = {'\0'}; 00209 char cFlags; 00210 00211 // Check if file exists 00212 if (getFirstBlockOfFile(filename, &n) != 0) 00213 return 1; // File not found 00214 00215 read(cData, n, 0, 1); 00216 cFlags = ((flags[0] & 0x01)|((flags[0] & 0x02) << 3)|((flags[0] & 0x04) << 3)); 00217 cData[0] = cData[0] & (~0x31) | cFlags; 00218 write(cData, n, 0, 1); 00219 00220 return 0; 00221 } 00222 00223 char mfs::getFileFlags(char *flags, char filename[20]) 00224 { 00225 /* RO|HIDDEN|LOCK * 00226 * H L */ 00227 00228 uint32_t n; 00229 char cData[1] = {'\0'}; 00230 00231 // Check if file exists 00232 if (getFirstBlockOfFile(filename, &n) != 0) 00233 return 1; // File not found 00234 00235 read(cData, n, 0, 1); 00236 flags[0] = (cData[0] & 0x01)|((cData[0] & 0x10) >> 3)|((cData[0] & 0x20) >> 3); 00237 00238 return 0; 00239 } 00240 00241 // Return number of free blocks 00242 uint32_t mfs::free() 00243 { 00244 uint32_t blocks=0; 00245 uint32_t r; 00246 char cFlags[1]; 00247 00248 for (r=0; r < BC; r++) 00249 { 00250 read(cFlags, r, 0, 1); 00251 if (cFlags[0] == 0x04) 00252 blocks++; 00253 if (r >= BC-1) 00254 return blocks; 00255 } 00256 00257 return 0; 00258 } 00259 00260 uint32_t mfs::mkfs(bool createLabel) 00261 { 00262 uint32_t iAddr = 0; 00263 uint32_t i = 0; 00264 uint32_t bad = 0; // For counting bad block headers 00265 char cFlags[RB] = {'\0', '\0', '\0', '\0', '\0'}, o[1]; 00266 00267 if (createLabel == true) 00268 { 00269 // Write Volume label 00270 cFlags[0] = '\x0E'; 00271 mem->write(cFlags, iAddr, RB); 00272 iAddr = BS; 00273 i = 1; 00274 } 00275 00276 cFlags[0] = '\x04'; 00277 for (; i < BC; i++) 00278 { 00279 mem->write(cFlags, iAddr, RB); 00280 mem->read(iAddr, 1, o); 00281 if (o[0] != cFlags[0]) 00282 bad++; 00283 iAddr += BS; 00284 } 00285 00286 return bad; 00287 } 00288 00289 file::file(mfs *fs_ref, char filename[20], FileOpenMode operation) 00290 { 00291 fMode = operation; 00292 00293 fs = fs_ref; // Don't forget this :) 00294 00295 uint32_t n; 00296 char cData[1] = {'\0'}; 00297 00298 // Check if file exists 00299 if (fs->getFirstBlockOfFile(filename, &n) != 0) 00300 error("Oops, file \"%s\" not found! n=0x%X", filename, n); // File not found 00301 00302 fs->read(cData, n, 0, 1); 00303 char flags = (cData[0] & 0x01)|((cData[0] & 0x10) >> 3)|((cData[0] & 0x20) >> 3); 00304 00305 if ((fMode != RO) && ((flags & 0x04) != 0)) 00306 error("Oops, cant open in RW mode!"); 00307 00308 // Store FBOF number 00309 firstBlock = n; 00310 currBlock = n; 00311 blockPos = RB+20; // skip flags + pointers + filename 00312 byteCount = 0; // First byte of the file 00313 00314 // Initialize buffer 00315 for (unsigned int i=0; i < BUF; i++) 00316 buffer[i] = '\0'; 00317 bufPos = 0; 00318 } 00319 00320 file::~file() 00321 { 00322 flush(); 00323 } 00324 00325 char file::getBlockLink(BlockLinkType linkSelection, uint32_t *blockOut) 00326 { 00327 char cData[1+BLOCK_LLEN]; 00328 00329 if (linkSelection == NEXT) 00330 { 00331 // Fetch link to next block 00332 fs->read(cData, currBlock, 0, 1+BLOCK_LLEN); 00333 if ((cData[0] & 0x40) == 0) 00334 { 00335 *blockOut = ((uint32_t)(cData[1])) << 8; // Hbyte of next block link 00336 *blockOut |= (uint32_t)cData[2]; // Lbyte of next block link 00337 return 0; 00338 } else return 1; // Already at last block 00339 } else if (linkSelection == PREV) 00340 { 00341 if (currBlock != firstBlock) 00342 { 00343 fs->read(cData, currBlock, 1+BLOCK_LLEN, BLOCK_LLEN); 00344 *blockOut = ((uint32_t)(cData[0])) << 8; // Hbyte of next block link 00345 *blockOut |= (uint32_t)cData[1]; // Lbyte of next block link 00346 return 0; 00347 } else return 1; // Already at first block 00348 } 00349 00350 return 0; 00351 } 00352 00353 char file::removeFollowingBlocks(uint32_t block) 00354 { 00355 char cData[RB-BLOCK_LLEN]; 00356 char cDataNew[RB] = {'\x04', '\0', '\0', '\0', '\0'}; 00357 uint32_t i=0; 00358 00359 while(1) 00360 { 00361 fs->read(cData, block, 0, RB-BLOCK_LLEN); 00362 fs->write(cDataNew, block, 0, RB); 00363 if ((cData[0] & 0x4C) == 0x4C) 00364 break; // End of file found 00365 else block = (uint32_t)(cData[0])<<8|cData[1]; // Set next block number 00366 i++; 00367 if (i > BC) 00368 return 1; // fs is corrupted 00369 } 00370 00371 return 0; 00372 } 00373 00374 void file::rewind() 00375 { 00376 flush(); 00377 currBlock = firstBlock; 00378 blockPos = RB+20; // skip flags & pointers + filename 00379 byteCount = 0; 00380 } 00381 00382 char file::rewind(uint32_t n) 00383 { 00384 uint32_t i; 00385 uint32_t block; 00386 uint32_t varBlockOffset; 00387 00388 flush(); // Check if flush is needed 00389 00390 for (i=0; i < n; i++) 00391 { 00392 blockPos--; 00393 byteCount--; 00394 00395 // Change Block? 00396 if (blockPos == firstBlock) 00397 varBlockOffset = RB+20; 00398 else 00399 varBlockOffset = RB; 00400 if ((blockPos < varBlockOffset) && (currBlock > firstBlock)) 00401 { 00402 // Fetch link to previous block 00403 if(getBlockLink(PREV, &block) == 0) 00404 { 00405 currBlock = block; 00406 blockPos = BS-1; // blockPos should be set at the end of block 00407 } else { 00408 blockPos++; 00409 byteCount++; 00410 return 1; // This is the first block and byte 00411 } 00412 } 00413 } 00414 00415 return 0; // OK 00416 } 00417 00418 char file::forward() 00419 { 00420 return forward(1); 00421 } 00422 00423 char file::forward(uint32_t n) 00424 { 00425 uint32_t i; 00426 uint32_t block; // Next block number 00427 char cData[1]; 00428 00429 flush(); // Check if flush is needed 00430 00431 for (i=0; i < n; i++) 00432 { 00433 // If this is empty file EOF will be at first byte 00434 fs->read(cData, currBlock, blockPos, 1); 00435 if (cData[0] == mEOF) 00436 { 00437 return 1; 00438 } 00439 00440 blockPos++; 00441 byteCount++; 00442 00443 // Change Block? 00444 if (blockPos >= BS) 00445 { 00446 // Fetch link to next block 00447 if (getBlockLink(NEXT, &block) == 0) 00448 { 00449 currBlock = block; 00450 blockPos = RB; // Reset block position offset 00451 } else { 00452 blockPos--; 00453 byteCount--; 00454 return 1; // This is the last block & byte 00455 } 00456 } 00457 fs->read(cData, currBlock, blockPos, 1); 00458 if (cData[0] == mEOF) 00459 { 00460 rewind(1); // Get back to the byte before EOF 00461 return 1; 00462 } 00463 } 00464 00465 return 0; // OK 00466 } 00467 00468 char file::seek(uint32_t byte) 00469 { 00470 if (byte > byteCount) 00471 return forward(byte-byteCount); 00472 else if (byte < byteCount) 00473 return rewind(byteCount-byte); 00474 else return 0; 00475 } 00476 00477 // Respects mEOF and automatically sets '\0' at the end of string 00478 void file::read(char *data, uint32_t n) 00479 { 00480 uint32_t i; 00481 uint32_t block; 00482 char cData[1]; 00483 00484 flush(); 00485 00486 for (i=0; i < n; i++) 00487 { 00488 // Change block? 00489 if (blockPos >= BS-1) 00490 { 00491 // Fetch link to next block 00492 if (getBlockLink(NEXT, &block) == 0) 00493 { 00494 currBlock = block; 00495 blockPos = RB; // Reset block position offset 00496 } else goto stop; 00497 } 00498 00499 // Read data 00500 fs->read(cData, currBlock, blockPos, 1); 00501 if (cData[0] == mEOF) 00502 { 00503 stop: 00504 data[i]='\0'; 00505 return; 00506 } else { 00507 data[i] = cData[0]; 00508 blockPos++; 00509 byteCount++; 00510 } 00511 } 00512 if (data[n-1] != '\0') 00513 data[n-1] = '\0'; 00514 } 00515 00516 // Ignores mEOF and doesn't set '\0' markings 00517 void file::readBin(char *data, uint32_t n) 00518 { 00519 uint32_t i; 00520 uint32_t block; 00521 char cData[1]; 00522 00523 for (i=0; i < n; i++) 00524 { 00525 // Change block? 00526 if (blockPos == BS-1) 00527 { 00528 // Fetch link to next block 00529 if (getBlockLink(NEXT, &block) == 0) 00530 { 00531 currBlock = block; 00532 blockPos = RB; // Reset block position offset 00533 } else return; 00534 } 00535 00536 // Read data 00537 fs->read(cData, currBlock, blockPos, 1); 00538 data[i] = cData[0]; 00539 00540 blockPos++; 00541 byteCount++; 00542 } 00543 } 00544 00545 // Always binary 00546 char file::write(char *data, uint32_t n) 00547 { 00548 if (fMode == RO) return 1; 00549 00550 for (uint32_t i=0; i < n; i++) 00551 { 00552 // write to the buffer 00553 buffer[bufPos] = data[i]; 00554 bufPos++; 00555 00556 // If the buffer is full then flush 00557 if(bufPos == BUF) 00558 { 00559 if(flush() != 0); 00560 return 1; // Flush failed 00561 } 00562 } 00563 00564 return 0; 00565 } 00566 00567 char file::flush() 00568 { 00569 char cData[RB], cDataOB[RB-BLOCK_LLEN], c[1]; 00570 uint32_t nextFree; 00571 uint32_t i; 00572 uint32_t leftSpaceEOF; 00573 00574 bool destructiveFlag = false; // Set this true if there is any data to be removed 00575 uint32_t destructiveBlock=0; // First block to be removed by DWRITE 00576 00577 static bool fEOFow = false; /* END of file found while appending (and overwritten). 00578 Must be static because we don't want to found many EOF's. */ 00579 00580 00581 if (bufPos == 0) return 0; // File up-to date 00582 if (fMode == RO) return 1; 00583 00584 for (i=0; i <= bufPos; i++) 00585 { 00586 if(i%2) 00587 FlushLed = 1; 00588 else 00589 FlushLed = 0; 00590 00591 // Change Block? 00592 if ((bufPos - i) == 1) 00593 leftSpaceEOF = 1; 00594 else 00595 leftSpaceEOF = 0; 00596 if (blockPos >= BS-leftSpaceEOF) 00597 { 00598 // Fetch new unused block number 00599 if(fs->getNextFreeBlock(&nextFree) != 0) 00600 return 2; // No free space left 00601 00602 // Read flags from current block 00603 fs->read(cDataOB, currBlock, 0, RB-BLOCK_LLEN); 00604 00605 /* If destructive write is set then check if there is something 00606 to be marked for removal */ 00607 if (((cDataOB[0] & 0x40) != 0x40) && (fMode == DWRITE)) 00608 { 00609 destructiveFlag = true; 00610 destructiveBlock = (uint32_t)cDataOB[1]<<8|cDataOB[2]; 00611 goto allocate_new_block; 00612 } else if ((cDataOB[0] & 0x40) != 0x40) // fMode == AWRITE 00613 { 00614 // Update current block info 00615 currBlock = (uint32_t)cDataOB[1]<<8|cDataOB[2]; 00616 blockPos = RB; // Reset block position offset 00617 } else // There is no block to append so we allocate a new one 00618 { 00619 allocate_new_block: 00620 // Allocate new block for use 00621 cData[0] = 0x4C; // New flags 00622 cData[1] = '\0'; // Hbyte of Next Block link 00623 cData[2] = '\0'; // Lbyte of Next Block link 00624 cData[3] = (char)((currBlock & 0xff00) >> 8); // Hbyte of Prev Block link 00625 cData[4] = (char)(currBlock & 0x00ff); // Lbyte of Prev Block link 00626 fs->write(cData, nextFree, 0, RB); // Update Block Data 00627 00628 // Link old block with new block 00629 cDataOB[0] &= ~0x40; // Clear LBOF flag if set 00630 cDataOB[1] = (char)((nextFree & 0xff00) >> 8); // Hbyte of Next Block link 00631 cDataOB[2] = (char)(nextFree & 0x00ff); // Lbyte of Next Block link 00632 fs->write(cDataOB, currBlock, 0, RB-BLOCK_LLEN); // Update Block Data 00633 00634 // Update current block info 00635 currBlock = nextFree; 00636 blockPos = RB; // Reset block position offset 00637 } 00638 } 00639 00640 if (fMode == AWRITE) // Check if EOF is here 00641 { 00642 fs->read(c, currBlock, blockPos, 1); 00643 if ((c[0] == mEOF) && (fEOFow == false)) 00644 fEOFow = true; 00645 } 00646 00647 // Write file 00648 c[0]=buffer[i]; 00649 fs->write(c, currBlock, blockPos, 1); 00650 blockPos++; 00651 byteCount++; 00652 00653 // For fail safe, write EOF now 00654 if ((fMode == DWRITE)||(fEOFow == true)) 00655 fs->write((char[]){mEOF}, currBlock, blockPos, 1); // Write mEOF 00656 } 00657 00658 bufPos = 0; // Reset buffer position counter 00659 00660 /* If destructive write flag is set 00661 and there is data to be removed then remove data now */ 00662 if (destructiveFlag == true) 00663 if(removeFollowingBlocks(destructiveBlock) != 0) 00664 return 3; 00665 00666 FlushLed = 0; 00667 return 0; 00668 }
Generated on Tue Jul 19 2022 05:47:57 by
1.7.2