mFS file system library for EEPROM memory chips.

Committer:
HBP
Date:
Thu Feb 24 09:28:32 2011 +0000
Revision:
13:142b6be3e3c8
Parent:
12:928346513c87
- Better handling of empty files
- doesn\t write EOF on AWRITE if EOF is not reached

Who changed what in which revision?

UserRevisionLine numberNew contents of line
HBP 10:211cb54339a0 1 /** @file mfs.cpp */
HBP 5:a0fe74dce80d 2 /*CPP**************************************************************************
HBP 7:5ac5121bb4e0 3 * FILENAME : mfs.cpp *
HBP 7:5ac5121bb4e0 4 * *
HBP 7:5ac5121bb4e0 5 * DESCRIPTION : *
HBP 7:5ac5121bb4e0 6 * mFS file system implementation for mBED with external I2C EEEPROM. *
HBP 7:5ac5121bb4e0 7 * *
HBP 7:5ac5121bb4e0 8 * AUTHOR : Olli Vanhoja START DATE : 2011-02-21 *
HBP 7:5ac5121bb4e0 9 *****************************************************************************/
HBP 0:cbf45dde2b49 10
HBP 0:cbf45dde2b49 11 #include "mbed.h"
HBP 0:cbf45dde2b49 12 #include "mfs.h"
HBP 0:cbf45dde2b49 13 #include "i2c_eeprom.h"
HBP 0:cbf45dde2b49 14
HBP 12:928346513c87 15 #define BLOCK_LLEN 2 /**< Block number link length in bytes */
HBP 12:928346513c87 16 #define RB 1+2*BLOCK_LLEN /**< Reseved bytes per block (1 attrb B, 2 B for next/prev pointers */
HBP 12:928346513c87 17 #define I2C_SPEED 200000 /**< I2C bus speed in Hz */
HBP 12:928346513c87 18 #define DEBUG /**< Adds extra safety in reading and writing */
HBP 0:cbf45dde2b49 19
HBP 10:211cb54339a0 20 DigitalOut FlushLed(LED2); /**< Flush led */
HBP 0:cbf45dde2b49 21
HBP 0:cbf45dde2b49 22 mfs::mfs(int i2c_address)
HBP 0:cbf45dde2b49 23 {
HBP 10:211cb54339a0 24 mem = new i2c_eeprom(i2c_address, I2C_SPEED);
HBP 0:cbf45dde2b49 25 }
HBP 0:cbf45dde2b49 26
HBP 10:211cb54339a0 27 char mfs::read(char *data, uint32_t block, uint32_t byte, uint32_t n)
HBP 0:cbf45dde2b49 28 {
HBP 0:cbf45dde2b49 29 // Faster reading without DEBUG mode
HBP 0:cbf45dde2b49 30 #ifdef DEBUG
HBP 0:cbf45dde2b49 31 if ((byte+n-1 >= BS))
HBP 0:cbf45dde2b49 32 return 1;
HBP 0:cbf45dde2b49 33 #endif
HBP 0:cbf45dde2b49 34 mem->read(BS*block+byte, n, data);
HBP 12:928346513c87 35
HBP 0:cbf45dde2b49 36 return 0;
HBP 0:cbf45dde2b49 37 }
HBP 0:cbf45dde2b49 38
HBP 10:211cb54339a0 39 char mfs::write(char *data, uint32_t block, uint32_t byte, uint32_t n)
HBP 0:cbf45dde2b49 40 {
HBP 0:cbf45dde2b49 41 // Faster writing without DEBUG mode
HBP 0:cbf45dde2b49 42 #ifdef DEBUG
HBP 0:cbf45dde2b49 43 if (byte+n >= BS)
HBP 0:cbf45dde2b49 44 return 1;
HBP 0:cbf45dde2b49 45 #endif
HBP 0:cbf45dde2b49 46 mem->write(data, BS*block+byte, n);
HBP 12:928346513c87 47
HBP 0:cbf45dde2b49 48 return 0;
HBP 0:cbf45dde2b49 49 }
HBP 0:cbf45dde2b49 50
HBP 10:211cb54339a0 51 char mfs::getNextFreeBlock(uint32_t *blockOut)
HBP 0:cbf45dde2b49 52 {
HBP 0:cbf45dde2b49 53 // Locate free block by seeking EERPOM
HBP 0:cbf45dde2b49 54 char cFlags[1];
HBP 0:cbf45dde2b49 55
HBP 0:cbf45dde2b49 56 for (*blockOut=0; *blockOut < BC; (*blockOut)++)
HBP 0:cbf45dde2b49 57 {
HBP 0:cbf45dde2b49 58 read(cFlags, *blockOut, 0, 1);
HBP 0:cbf45dde2b49 59 if (cFlags[0] == 0x04)
HBP 0:cbf45dde2b49 60 break;
HBP 0:cbf45dde2b49 61 if (*blockOut >= BC-1)
HBP 0:cbf45dde2b49 62 return 1;
HBP 0:cbf45dde2b49 63 }
HBP 0:cbf45dde2b49 64
HBP 0:cbf45dde2b49 65 return 0;
HBP 0:cbf45dde2b49 66 }
HBP 0:cbf45dde2b49 67
HBP 10:211cb54339a0 68 char mfs::findNextFile(uint32_t block, char *filenameOut, uint32_t *blockOut)
HBP 0:cbf45dde2b49 69 {
HBP 9:52c01cb100ac 70 uint32_t i=block;
HBP 0:cbf45dde2b49 71 char cFlags[1];
HBP 0:cbf45dde2b49 72
HBP 0:cbf45dde2b49 73 while (i < BC)
HBP 0:cbf45dde2b49 74 {
HBP 0:cbf45dde2b49 75 read(cFlags, i, 0, 1);
HBP 0:cbf45dde2b49 76
HBP 0:cbf45dde2b49 77 if ((cFlags[0] & 0x8C) == 0x8C)
HBP 0:cbf45dde2b49 78 break; // File found
HBP 0:cbf45dde2b49 79 else
HBP 0:cbf45dde2b49 80 i++;
HBP 0:cbf45dde2b49 81 }
HBP 0:cbf45dde2b49 82
HBP 0:cbf45dde2b49 83 if(i == BC)
HBP 0:cbf45dde2b49 84 {
HBP 0:cbf45dde2b49 85 strcpy(filenameOut, "");
HBP 10:211cb54339a0 86 return 1; // Empty fs
HBP 0:cbf45dde2b49 87 }
HBP 0:cbf45dde2b49 88
HBP 0:cbf45dde2b49 89 // Read filename
HBP 10:211cb54339a0 90 read(filenameOut, i, RB, 20);
HBP 10:211cb54339a0 91 *blockOut = i; // Return block number
HBP 10:211cb54339a0 92 return 0;
HBP 0:cbf45dde2b49 93 }
HBP 0:cbf45dde2b49 94
HBP 10:211cb54339a0 95 char mfs::getFirstBlockOfFile(char filename[20], uint32_t *blockOut)
HBP 0:cbf45dde2b49 96 {
HBP 10:211cb54339a0 97 *blockOut=0;
HBP 0:cbf45dde2b49 98 char tmpFilename[20]="";
HBP 0:cbf45dde2b49 99
HBP 10:211cb54339a0 100 while (1)
HBP 0:cbf45dde2b49 101 {
HBP 10:211cb54339a0 102 if (findNextFile(*blockOut, tmpFilename, blockOut) == 0)
HBP 0:cbf45dde2b49 103 {
HBP 0:cbf45dde2b49 104 if(strcmp(tmpFilename, filename) == 0)
HBP 10:211cb54339a0 105 return 0; // File exists
HBP 0:cbf45dde2b49 106 }
HBP 10:211cb54339a0 107 else return 1; // File doesn't exist
HBP 10:211cb54339a0 108 (*blockOut)++;
HBP 0:cbf45dde2b49 109 }
HBP 0:cbf45dde2b49 110 }
HBP 0:cbf45dde2b49 111
HBP 0:cbf45dde2b49 112 char mfs::createFile(char filename[20])
HBP 0:cbf45dde2b49 113 {
HBP 0:cbf45dde2b49 114 char tmpFilename[20];
HBP 9:52c01cb100ac 115 uint32_t n;
HBP 10:211cb54339a0 116 uint32_t fb;
HBP 0:cbf45dde2b49 117
HBP 0:cbf45dde2b49 118 for (n=0; n < BC; n++)
HBP 0:cbf45dde2b49 119 {
HBP 10:211cb54339a0 120 if(findNextFile(n, tmpFilename, &n) == 0)
HBP 0:cbf45dde2b49 121 {
HBP 0:cbf45dde2b49 122 if(strcmp(tmpFilename, filename) == 0)
HBP 0:cbf45dde2b49 123 return 1; // File exist
HBP 0:cbf45dde2b49 124 }
HBP 0:cbf45dde2b49 125 else break; // We already reached the edge of the universe
HBP 0:cbf45dde2b49 126 n++;
HBP 0:cbf45dde2b49 127 }
HBP 0:cbf45dde2b49 128
HBP 10:211cb54339a0 129 if(getNextFreeBlock(&fb) != 0)
HBP 0:cbf45dde2b49 130 return 2; // Out of space
HBP 0:cbf45dde2b49 131
HBP 13:142b6be3e3c8 132 char cData[RB+20+1];
HBP 13:142b6be3e3c8 133 cData[0] = '\xCC'; // Necessary flags for a file
HBP 13:142b6be3e3c8 134 cData[1] = '\0'; // No more blocks yet
HBP 12:928346513c87 135 cData[2] = '\0';
HBP 13:142b6be3e3c8 136 cData[3] = '\0'; // First block so there is no prev blocks
HBP 12:928346513c87 137 cData[4] = '\0';
HBP 13:142b6be3e3c8 138 cData[RB+20] = mEOF; // Set EOF at the begining
HBP 0:cbf45dde2b49 139
HBP 0:cbf45dde2b49 140 for (char i=0; i < 20; i++)
HBP 10:211cb54339a0 141 cData[RB+i] = filename[i];
HBP 0:cbf45dde2b49 142
HBP 0:cbf45dde2b49 143 // Create file
HBP 13:142b6be3e3c8 144 write(cData, fb, 0, RB+20+1);
HBP 0:cbf45dde2b49 145
HBP 0:cbf45dde2b49 146 return 0;
HBP 0:cbf45dde2b49 147 }
HBP 0:cbf45dde2b49 148
HBP 0:cbf45dde2b49 149 char mfs::removeFile(char filename[20])
HBP 0:cbf45dde2b49 150 {
HBP 9:52c01cb100ac 151 uint32_t block;
HBP 12:928346513c87 152 char cData[RB-BLOCK_LLEN];
HBP 12:928346513c87 153 char cDataNew[RB] = {'\x04', '\0', '\0', '\0', '\0'};
HBP 12:928346513c87 154 uint32_t i=0;
HBP 0:cbf45dde2b49 155
HBP 0:cbf45dde2b49 156 // Check if file exists
HBP 11:6c4fcb9d6193 157 if (getFirstBlockOfFile(filename, &block) != 0)
HBP 0:cbf45dde2b49 158 return 1; // File not found
HBP 0:cbf45dde2b49 159
HBP 12:928346513c87 160 read(cData, block, 0, RB-BLOCK_LLEN);
HBP 12:928346513c87 161
HBP 12:928346513c87 162 // Check credentials
HBP 12:928346513c87 163 if (((cData[0] & 0x01)|((cData[0] & 0x10) >> 3)|((cData[0] & 0x20) >> 3) & 0x04) != 0)
HBP 12:928346513c87 164 return 2; // RO file
HBP 12:928346513c87 165
HBP 12:928346513c87 166 // Clear blocks reserved by the file
HBP 0:cbf45dde2b49 167 while(1)
HBP 0:cbf45dde2b49 168 {
HBP 12:928346513c87 169 write(cDataNew, block, 0, RB);
HBP 12:928346513c87 170 if ((cData[0] & 0x4C) == 0x4C)
HBP 12:928346513c87 171 break; // End of file found
HBP 12:928346513c87 172 else block = (uint32_t)(cData[1])<<8|cData[2]; // Set next block number
HBP 0:cbf45dde2b49 173 i++;
HBP 12:928346513c87 174 if (i > BC)
HBP 12:928346513c87 175 return 1; // fs is corrupted
HBP 12:928346513c87 176 read(cData, block, 0, RB-BLOCK_LLEN);
HBP 0:cbf45dde2b49 177 }
HBP 0:cbf45dde2b49 178
HBP 0:cbf45dde2b49 179 return 0; // Everything went better than expected
HBP 0:cbf45dde2b49 180 }
HBP 0:cbf45dde2b49 181
HBP 7:5ac5121bb4e0 182 char mfs::renameFile(char oldFilename[20], char newFilename[20])
HBP 7:5ac5121bb4e0 183 {
HBP 9:52c01cb100ac 184 uint32_t block;
HBP 12:928346513c87 185 char cData[1];
HBP 7:5ac5121bb4e0 186
HBP 7:5ac5121bb4e0 187 // Check if file exists
HBP 10:211cb54339a0 188 if (getFirstBlockOfFile(oldFilename, &block) != 0)
HBP 7:5ac5121bb4e0 189 return 1; // File not found
HBP 7:5ac5121bb4e0 190
HBP 12:928346513c87 191 // Check credentials
HBP 12:928346513c87 192 read(cData, block, 0, 1);
HBP 12:928346513c87 193 char flags = (cData[0] & 0x01)|((cData[0] & 0x10) >> 3)|((cData[0] & 0x20) >> 3);
HBP 12:928346513c87 194 if ((flags & 0x04) != 0)
HBP 12:928346513c87 195 return 2; // RO file
HBP 12:928346513c87 196
HBP 10:211cb54339a0 197 write(newFilename, block, RB, 20);
HBP 7:5ac5121bb4e0 198
HBP 7:5ac5121bb4e0 199 return 0; // Everything went better than expected
HBP 7:5ac5121bb4e0 200 }
HBP 7:5ac5121bb4e0 201
HBP 0:cbf45dde2b49 202 char mfs::setFileFlags(char *flags, char filename[20])
HBP 0:cbf45dde2b49 203 {
HBP 0:cbf45dde2b49 204 /* RO|HIDDEN|LOCK *
HBP 0:cbf45dde2b49 205 * H L */
HBP 0:cbf45dde2b49 206
HBP 9:52c01cb100ac 207 uint32_t n;
HBP 0:cbf45dde2b49 208 char cData[1] = {'\0'};
HBP 12:928346513c87 209 char cFlags;
HBP 0:cbf45dde2b49 210
HBP 0:cbf45dde2b49 211 // Check if file exists
HBP 10:211cb54339a0 212 if (getFirstBlockOfFile(filename, &n) != 0)
HBP 0:cbf45dde2b49 213 return 1; // File not found
HBP 0:cbf45dde2b49 214
HBP 0:cbf45dde2b49 215 read(cData, n, 0, 1);
HBP 12:928346513c87 216 cFlags = ((flags[0] & 0x01)|((flags[0] & 0x02) << 3)|((flags[0] & 0x04) << 3));
HBP 12:928346513c87 217 cData[0] = cData[0] & (~0x31) | cFlags;
HBP 0:cbf45dde2b49 218 write(cData, n, 0, 1);
HBP 0:cbf45dde2b49 219
HBP 0:cbf45dde2b49 220 return 0;
HBP 0:cbf45dde2b49 221 }
HBP 0:cbf45dde2b49 222
HBP 0:cbf45dde2b49 223 char mfs::getFileFlags(char *flags, char filename[20])
HBP 0:cbf45dde2b49 224 {
HBP 0:cbf45dde2b49 225 /* RO|HIDDEN|LOCK *
HBP 0:cbf45dde2b49 226 * H L */
HBP 0:cbf45dde2b49 227
HBP 9:52c01cb100ac 228 uint32_t n;
HBP 0:cbf45dde2b49 229 char cData[1] = {'\0'};
HBP 0:cbf45dde2b49 230
HBP 0:cbf45dde2b49 231 // Check if file exists
HBP 10:211cb54339a0 232 if (getFirstBlockOfFile(filename, &n) != 0)
HBP 0:cbf45dde2b49 233 return 1; // File not found
HBP 0:cbf45dde2b49 234
HBP 0:cbf45dde2b49 235 read(cData, n, 0, 1);
HBP 0:cbf45dde2b49 236 flags[0] = (cData[0] & 0x01)|((cData[0] & 0x10) >> 3)|((cData[0] & 0x20) >> 3);
HBP 0:cbf45dde2b49 237
HBP 0:cbf45dde2b49 238 return 0;
HBP 0:cbf45dde2b49 239 }
HBP 0:cbf45dde2b49 240
HBP 0:cbf45dde2b49 241 // Return number of free blocks
HBP 10:211cb54339a0 242 uint32_t mfs::free()
HBP 0:cbf45dde2b49 243 {
HBP 10:211cb54339a0 244 uint32_t blocks=0;
HBP 10:211cb54339a0 245 uint32_t r;
HBP 0:cbf45dde2b49 246 char cFlags[1];
HBP 0:cbf45dde2b49 247
HBP 0:cbf45dde2b49 248 for (r=0; r < BC; r++)
HBP 0:cbf45dde2b49 249 {
HBP 0:cbf45dde2b49 250 read(cFlags, r, 0, 1);
HBP 0:cbf45dde2b49 251 if (cFlags[0] == 0x04)
HBP 0:cbf45dde2b49 252 blocks++;
HBP 0:cbf45dde2b49 253 if (r >= BC-1)
HBP 0:cbf45dde2b49 254 return blocks;
HBP 0:cbf45dde2b49 255 }
HBP 0:cbf45dde2b49 256
HBP 0:cbf45dde2b49 257 return 0;
HBP 0:cbf45dde2b49 258 }
HBP 0:cbf45dde2b49 259
HBP 10:211cb54339a0 260 uint32_t mfs::mkfs(bool createLabel)
HBP 0:cbf45dde2b49 261 {
HBP 10:211cb54339a0 262 uint32_t iAddr = 0;
HBP 10:211cb54339a0 263 uint32_t i = 0;
HBP 10:211cb54339a0 264 uint32_t bad = 0; // For counting bad block headers
HBP 12:928346513c87 265 char cFlags[RB] = {'\0', '\0', '\0', '\0', '\0'}, o[1];
HBP 0:cbf45dde2b49 266
HBP 10:211cb54339a0 267 if (createLabel == true)
HBP 0:cbf45dde2b49 268 {
HBP 0:cbf45dde2b49 269 // Write Volume label
HBP 0:cbf45dde2b49 270 cFlags[0] = '\x0E';
HBP 12:928346513c87 271 mem->write(cFlags, iAddr, RB);
HBP 0:cbf45dde2b49 272 iAddr = BS;
HBP 0:cbf45dde2b49 273 i = 1;
HBP 0:cbf45dde2b49 274 }
HBP 0:cbf45dde2b49 275
HBP 0:cbf45dde2b49 276 cFlags[0] = '\x04';
HBP 0:cbf45dde2b49 277 for (; i < BC; i++)
HBP 0:cbf45dde2b49 278 {
HBP 12:928346513c87 279 mem->write(cFlags, iAddr, RB);
HBP 12:928346513c87 280 mem->read(iAddr, 1, o);
HBP 12:928346513c87 281 if (o[0] != cFlags[0])
HBP 0:cbf45dde2b49 282 bad++;
HBP 0:cbf45dde2b49 283 iAddr += BS;
HBP 0:cbf45dde2b49 284 }
HBP 0:cbf45dde2b49 285
HBP 0:cbf45dde2b49 286 return bad;
HBP 0:cbf45dde2b49 287 }
HBP 0:cbf45dde2b49 288
HBP 12:928346513c87 289 file::file(mfs *fs_ref, char filename[20], FileOpenMode operation)
HBP 0:cbf45dde2b49 290 {
HBP 12:928346513c87 291 fMode = operation;
HBP 0:cbf45dde2b49 292
HBP 0:cbf45dde2b49 293 fs = fs_ref; // Don't forget this :)
HBP 0:cbf45dde2b49 294
HBP 9:52c01cb100ac 295 uint32_t n;
HBP 12:928346513c87 296 char cData[1] = {'\0'};
HBP 0:cbf45dde2b49 297
HBP 0:cbf45dde2b49 298 // Check if file exists
HBP 10:211cb54339a0 299 if (fs->getFirstBlockOfFile(filename, &n) != 0)
HBP 0:cbf45dde2b49 300 error("Oops, file \"%s\" not found! n=0x%X", filename, n); // File not found
HBP 0:cbf45dde2b49 301
HBP 0:cbf45dde2b49 302 fs->read(cData, n, 0, 1);
HBP 0:cbf45dde2b49 303 char flags = (cData[0] & 0x01)|((cData[0] & 0x10) >> 3)|((cData[0] & 0x20) >> 3);
HBP 0:cbf45dde2b49 304
HBP 12:928346513c87 305 if ((fMode != RO) && ((flags & 0x04) != 0))
HBP 12:928346513c87 306 error("Oops, cant open in RW mode!");
HBP 0:cbf45dde2b49 307
HBP 0:cbf45dde2b49 308 // Store FBOF number
HBP 0:cbf45dde2b49 309 firstBlock = n;
HBP 0:cbf45dde2b49 310 currBlock = n;
HBP 0:cbf45dde2b49 311 blockPos = RB+20; // skip flags + pointers + filename
HBP 12:928346513c87 312 byteCount = 0; // First byte of the file
HBP 0:cbf45dde2b49 313
HBP 0:cbf45dde2b49 314 // Initialize buffer
HBP 0:cbf45dde2b49 315 for (unsigned int i=0; i < BUF; i++)
HBP 0:cbf45dde2b49 316 buffer[i] = '\0';
HBP 0:cbf45dde2b49 317 bufPos = 0;
HBP 0:cbf45dde2b49 318 }
HBP 0:cbf45dde2b49 319
HBP 0:cbf45dde2b49 320 file::~file()
HBP 0:cbf45dde2b49 321 {
HBP 0:cbf45dde2b49 322 flush();
HBP 0:cbf45dde2b49 323 }
HBP 0:cbf45dde2b49 324
HBP 12:928346513c87 325 char file::getBlockLink(BlockLinkType linkSelection, uint32_t *blockOut)
HBP 12:928346513c87 326 {
HBP 12:928346513c87 327 char cData[1+BLOCK_LLEN];
HBP 12:928346513c87 328
HBP 12:928346513c87 329 if (linkSelection == NEXT)
HBP 12:928346513c87 330 {
HBP 12:928346513c87 331 // Fetch link to next block
HBP 12:928346513c87 332 fs->read(cData, currBlock, 0, 1+BLOCK_LLEN);
HBP 12:928346513c87 333 if ((cData[0] & 0x40) == 0)
HBP 12:928346513c87 334 {
HBP 12:928346513c87 335 *blockOut = ((uint32_t)(cData[1])) << 8; // Hbyte of next block link
HBP 12:928346513c87 336 *blockOut |= (uint32_t)cData[2]; // Lbyte of next block link
HBP 12:928346513c87 337 return 0;
HBP 12:928346513c87 338 } else return 1; // Already at last block
HBP 12:928346513c87 339 } else if (linkSelection == PREV)
HBP 12:928346513c87 340 {
HBP 12:928346513c87 341 if (currBlock != firstBlock)
HBP 12:928346513c87 342 {
HBP 12:928346513c87 343 fs->read(cData, currBlock, 1+BLOCK_LLEN, BLOCK_LLEN);
HBP 12:928346513c87 344 *blockOut = ((uint32_t)(cData[0])) << 8; // Hbyte of next block link
HBP 12:928346513c87 345 *blockOut |= (uint32_t)cData[1]; // Lbyte of next block link
HBP 12:928346513c87 346 return 0;
HBP 12:928346513c87 347 } else return 1; // Already at first block
HBP 12:928346513c87 348 }
HBP 12:928346513c87 349
HBP 12:928346513c87 350 return 0;
HBP 12:928346513c87 351 }
HBP 12:928346513c87 352
HBP 12:928346513c87 353 char file::removeFollowingBlocks(uint32_t block)
HBP 12:928346513c87 354 {
HBP 12:928346513c87 355 char cData[RB-BLOCK_LLEN];
HBP 12:928346513c87 356 char cDataNew[RB] = {'\x04', '\0', '\0', '\0', '\0'};
HBP 12:928346513c87 357 uint32_t i=0;
HBP 12:928346513c87 358
HBP 12:928346513c87 359 while(1)
HBP 12:928346513c87 360 {
HBP 12:928346513c87 361 fs->read(cData, block, 0, RB-BLOCK_LLEN);
HBP 12:928346513c87 362 fs->write(cDataNew, block, 0, RB);
HBP 12:928346513c87 363 if ((cData[0] & 0x4C) == 0x4C)
HBP 12:928346513c87 364 break; // End of file found
HBP 12:928346513c87 365 else block = (uint32_t)(cData[0])<<8|cData[1]; // Set next block number
HBP 12:928346513c87 366 i++;
HBP 12:928346513c87 367 if (i > BC)
HBP 12:928346513c87 368 return 1; // fs is corrupted
HBP 12:928346513c87 369 }
HBP 12:928346513c87 370
HBP 12:928346513c87 371 return 0;
HBP 12:928346513c87 372 }
HBP 12:928346513c87 373
HBP 0:cbf45dde2b49 374 void file::rewind()
HBP 0:cbf45dde2b49 375 {
HBP 0:cbf45dde2b49 376 flush();
HBP 0:cbf45dde2b49 377 currBlock = firstBlock;
HBP 0:cbf45dde2b49 378 blockPos = RB+20; // skip flags & pointers + filename
HBP 12:928346513c87 379 byteCount = 0;
HBP 0:cbf45dde2b49 380 }
HBP 0:cbf45dde2b49 381
HBP 9:52c01cb100ac 382 char file::rewind(uint32_t n)
HBP 5:a0fe74dce80d 383 {
HBP 9:52c01cb100ac 384 uint32_t i;
HBP 12:928346513c87 385 uint32_t block;
HBP 12:928346513c87 386 uint32_t varBlockOffset;
HBP 5:a0fe74dce80d 387
HBP 9:52c01cb100ac 388 flush(); // Check if flush is needed
HBP 5:a0fe74dce80d 389
HBP 5:a0fe74dce80d 390 for (i=0; i < n; i++)
HBP 5:a0fe74dce80d 391 {
HBP 5:a0fe74dce80d 392 blockPos--;
HBP 12:928346513c87 393 byteCount--;
HBP 5:a0fe74dce80d 394
HBP 5:a0fe74dce80d 395 // Change Block?
HBP 12:928346513c87 396 if (blockPos == firstBlock)
HBP 12:928346513c87 397 varBlockOffset = RB+20;
HBP 12:928346513c87 398 else
HBP 12:928346513c87 399 varBlockOffset = RB;
HBP 12:928346513c87 400 if ((blockPos < varBlockOffset) && (currBlock > firstBlock))
HBP 5:a0fe74dce80d 401 {
HBP 12:928346513c87 402 // Fetch link to previous block
HBP 12:928346513c87 403 if(getBlockLink(PREV, &block) == 0)
HBP 5:a0fe74dce80d 404 {
HBP 12:928346513c87 405 currBlock = block;
HBP 12:928346513c87 406 blockPos = BS-1; // blockPos should be set at the end of block
HBP 5:a0fe74dce80d 407 } else {
HBP 5:a0fe74dce80d 408 blockPos++;
HBP 12:928346513c87 409 byteCount++;
HBP 12:928346513c87 410 return 1; // This is the first block and byte
HBP 5:a0fe74dce80d 411 }
HBP 5:a0fe74dce80d 412 }
HBP 5:a0fe74dce80d 413 }
HBP 5:a0fe74dce80d 414
HBP 5:a0fe74dce80d 415 return 0; // OK
HBP 5:a0fe74dce80d 416 }
HBP 5:a0fe74dce80d 417
HBP 0:cbf45dde2b49 418 char file::forward()
HBP 0:cbf45dde2b49 419 {
HBP 5:a0fe74dce80d 420 return forward(1);
HBP 5:a0fe74dce80d 421 }
HBP 5:a0fe74dce80d 422
HBP 9:52c01cb100ac 423 char file::forward(uint32_t n)
HBP 5:a0fe74dce80d 424 {
HBP 9:52c01cb100ac 425 uint32_t i;
HBP 12:928346513c87 426 uint32_t block; // Next block number
HBP 12:928346513c87 427 char cData[1];
HBP 0:cbf45dde2b49 428
HBP 9:52c01cb100ac 429 flush(); // Check if flush is needed
HBP 5:a0fe74dce80d 430
HBP 5:a0fe74dce80d 431 for (i=0; i < n; i++)
HBP 5:a0fe74dce80d 432 {
HBP 13:142b6be3e3c8 433 // If this is empty file EOF will be at first byte
HBP 13:142b6be3e3c8 434 fs->read(cData, currBlock, blockPos, 1);
HBP 13:142b6be3e3c8 435 if (cData[0] == mEOF)
HBP 13:142b6be3e3c8 436 {
HBP 13:142b6be3e3c8 437 return 1;
HBP 13:142b6be3e3c8 438 }
HBP 13:142b6be3e3c8 439
HBP 5:a0fe74dce80d 440 blockPos++;
HBP 12:928346513c87 441 byteCount++;
HBP 0:cbf45dde2b49 442
HBP 5:a0fe74dce80d 443 // Change Block?
HBP 12:928346513c87 444 if (blockPos >= BS)
HBP 5:a0fe74dce80d 445 {
HBP 5:a0fe74dce80d 446 // Fetch link to next block
HBP 12:928346513c87 447 if (getBlockLink(NEXT, &block) == 0)
HBP 5:a0fe74dce80d 448 {
HBP 12:928346513c87 449 currBlock = block;
HBP 5:a0fe74dce80d 450 blockPos = RB; // Reset block position offset
HBP 5:a0fe74dce80d 451 } else {
HBP 5:a0fe74dce80d 452 blockPos--;
HBP 12:928346513c87 453 byteCount--;
HBP 12:928346513c87 454 return 1; // This is the last block & byte
HBP 5:a0fe74dce80d 455 }
HBP 5:a0fe74dce80d 456 }
HBP 5:a0fe74dce80d 457 fs->read(cData, currBlock, blockPos, 1);
HBP 5:a0fe74dce80d 458 if (cData[0] == mEOF)
HBP 10:211cb54339a0 459 {
HBP 12:928346513c87 460 rewind(1); // Get back to the byte before EOF
HBP 5:a0fe74dce80d 461 return 1;
HBP 10:211cb54339a0 462 }
HBP 5:a0fe74dce80d 463 }
HBP 0:cbf45dde2b49 464
HBP 0:cbf45dde2b49 465 return 0; // OK
HBP 0:cbf45dde2b49 466 }
HBP 0:cbf45dde2b49 467
HBP 12:928346513c87 468 char file::seek(uint32_t byte)
HBP 12:928346513c87 469 {
HBP 12:928346513c87 470 if (byte > byteCount)
HBP 12:928346513c87 471 return forward(byte-byteCount);
HBP 12:928346513c87 472 else if (byte < byteCount)
HBP 12:928346513c87 473 return rewind(byteCount-byte);
HBP 12:928346513c87 474 else return 0;
HBP 12:928346513c87 475 }
HBP 12:928346513c87 476
HBP 0:cbf45dde2b49 477 // Respects mEOF and automatically sets '\0' at the end of string
HBP 9:52c01cb100ac 478 void file::read(char *data, uint32_t n)
HBP 0:cbf45dde2b49 479 {
HBP 9:52c01cb100ac 480 uint32_t i;
HBP 12:928346513c87 481 uint32_t block;
HBP 12:928346513c87 482 char cData[1];
HBP 0:cbf45dde2b49 483
HBP 9:52c01cb100ac 484 flush();
HBP 0:cbf45dde2b49 485
HBP 0:cbf45dde2b49 486 for (i=0; i < n; i++)
HBP 0:cbf45dde2b49 487 {
HBP 0:cbf45dde2b49 488 // Change block?
HBP 12:928346513c87 489 if (blockPos >= BS-1)
HBP 0:cbf45dde2b49 490 {
HBP 0:cbf45dde2b49 491 // Fetch link to next block
HBP 12:928346513c87 492 if (getBlockLink(NEXT, &block) == 0)
HBP 0:cbf45dde2b49 493 {
HBP 12:928346513c87 494 currBlock = block;
HBP 12:928346513c87 495 blockPos = RB; // Reset block position offset
HBP 0:cbf45dde2b49 496 } else goto stop;
HBP 0:cbf45dde2b49 497 }
HBP 0:cbf45dde2b49 498
HBP 0:cbf45dde2b49 499 // Read data
HBP 0:cbf45dde2b49 500 fs->read(cData, currBlock, blockPos, 1);
HBP 0:cbf45dde2b49 501 if (cData[0] == mEOF)
HBP 0:cbf45dde2b49 502 {
HBP 0:cbf45dde2b49 503 stop:
HBP 0:cbf45dde2b49 504 data[i]='\0';
HBP 0:cbf45dde2b49 505 return;
HBP 5:a0fe74dce80d 506 } else {
HBP 5:a0fe74dce80d 507 data[i] = cData[0];
HBP 5:a0fe74dce80d 508 blockPos++;
HBP 12:928346513c87 509 byteCount++;
HBP 5:a0fe74dce80d 510 }
HBP 0:cbf45dde2b49 511 }
HBP 12:928346513c87 512 if (data[n-1] != '\0')
HBP 12:928346513c87 513 data[n-1] = '\0';
HBP 0:cbf45dde2b49 514 }
HBP 0:cbf45dde2b49 515
HBP 0:cbf45dde2b49 516 // Ignores mEOF and doesn't set '\0' markings
HBP 9:52c01cb100ac 517 void file::readBin(char *data, uint32_t n)
HBP 0:cbf45dde2b49 518 {
HBP 9:52c01cb100ac 519 uint32_t i;
HBP 12:928346513c87 520 uint32_t block;
HBP 12:928346513c87 521 char cData[1];
HBP 0:cbf45dde2b49 522
HBP 0:cbf45dde2b49 523 for (i=0; i < n; i++)
HBP 0:cbf45dde2b49 524 {
HBP 0:cbf45dde2b49 525 // Change block?
HBP 0:cbf45dde2b49 526 if (blockPos == BS-1)
HBP 0:cbf45dde2b49 527 {
HBP 0:cbf45dde2b49 528 // Fetch link to next block
HBP 12:928346513c87 529 if (getBlockLink(NEXT, &block) == 0)
HBP 0:cbf45dde2b49 530 {
HBP 12:928346513c87 531 currBlock = block;
HBP 0:cbf45dde2b49 532 blockPos = RB; // Reset block position offset
HBP 0:cbf45dde2b49 533 } else return;
HBP 0:cbf45dde2b49 534 }
HBP 0:cbf45dde2b49 535
HBP 0:cbf45dde2b49 536 // Read data
HBP 0:cbf45dde2b49 537 fs->read(cData, currBlock, blockPos, 1);
HBP 0:cbf45dde2b49 538 data[i] = cData[0];
HBP 0:cbf45dde2b49 539
HBP 0:cbf45dde2b49 540 blockPos++;
HBP 12:928346513c87 541 byteCount++;
HBP 0:cbf45dde2b49 542 }
HBP 0:cbf45dde2b49 543 }
HBP 0:cbf45dde2b49 544
HBP 0:cbf45dde2b49 545 // Always binary
HBP 9:52c01cb100ac 546 char file::write(char *data, uint32_t n)
HBP 0:cbf45dde2b49 547 {
HBP 12:928346513c87 548 if (fMode == RO) return 1;
HBP 0:cbf45dde2b49 549
HBP 9:52c01cb100ac 550 for (uint32_t i=0; i < n; i++)
HBP 0:cbf45dde2b49 551 {
HBP 0:cbf45dde2b49 552 // write to the buffer
HBP 0:cbf45dde2b49 553 buffer[bufPos] = data[i];
HBP 0:cbf45dde2b49 554 bufPos++;
HBP 0:cbf45dde2b49 555
HBP 0:cbf45dde2b49 556 // If the buffer is full then flush
HBP 0:cbf45dde2b49 557 if(bufPos == BUF)
HBP 0:cbf45dde2b49 558 {
HBP 0:cbf45dde2b49 559 if(flush() != 0);
HBP 0:cbf45dde2b49 560 return 1; // Flush failed
HBP 0:cbf45dde2b49 561 }
HBP 0:cbf45dde2b49 562 }
HBP 0:cbf45dde2b49 563
HBP 0:cbf45dde2b49 564 return 0;
HBP 0:cbf45dde2b49 565 }
HBP 0:cbf45dde2b49 566
HBP 0:cbf45dde2b49 567 char file::flush()
HBP 0:cbf45dde2b49 568 {
HBP 12:928346513c87 569 char cData[RB], cDataOB[RB-BLOCK_LLEN], c[1];
HBP 10:211cb54339a0 570 uint32_t nextFree;
HBP 9:52c01cb100ac 571 uint32_t i;
HBP 12:928346513c87 572 uint32_t leftSpaceEOF;
HBP 12:928346513c87 573
HBP 12:928346513c87 574 bool destructiveFlag = false; // Set this true if there is any data to be removed
HBP 12:928346513c87 575 uint32_t destructiveBlock=0; // First block to be removed by DWRITE
HBP 0:cbf45dde2b49 576
HBP 13:142b6be3e3c8 577 static bool fEOFow = false; /* END of file found while appending (and overwritten).
HBP 13:142b6be3e3c8 578 Must be static because we don't want to found many EOF's. */
HBP 13:142b6be3e3c8 579
HBP 13:142b6be3e3c8 580
HBP 0:cbf45dde2b49 581 if (bufPos == 0) return 0; // File up-to date
HBP 12:928346513c87 582 if (fMode == RO) return 1;
HBP 0:cbf45dde2b49 583
HBP 12:928346513c87 584 for (i=0; i <= bufPos; i++)
HBP 0:cbf45dde2b49 585 {
HBP 0:cbf45dde2b49 586 if(i%2)
HBP 0:cbf45dde2b49 587 FlushLed = 1;
HBP 0:cbf45dde2b49 588 else
HBP 0:cbf45dde2b49 589 FlushLed = 0;
HBP 0:cbf45dde2b49 590
HBP 0:cbf45dde2b49 591 // Change Block?
HBP 12:928346513c87 592 if ((bufPos - i) == 1)
HBP 12:928346513c87 593 leftSpaceEOF = 1;
HBP 12:928346513c87 594 else
HBP 12:928346513c87 595 leftSpaceEOF = 0;
HBP 12:928346513c87 596 if (blockPos >= BS-leftSpaceEOF)
HBP 0:cbf45dde2b49 597 {
HBP 0:cbf45dde2b49 598 // Fetch new unused block number
HBP 0:cbf45dde2b49 599 if(fs->getNextFreeBlock(&nextFree) != 0)
HBP 12:928346513c87 600 return 2; // No free space left
HBP 0:cbf45dde2b49 601
HBP 12:928346513c87 602 // Read flags from current block
HBP 12:928346513c87 603 fs->read(cDataOB, currBlock, 0, RB-BLOCK_LLEN);
HBP 9:52c01cb100ac 604
HBP 12:928346513c87 605 /* If destructive write is set then check if there is something
HBP 12:928346513c87 606 to be marked for removal */
HBP 12:928346513c87 607 if (((cDataOB[0] & 0x40) != 0x40) && (fMode == DWRITE))
HBP 12:928346513c87 608 {
HBP 12:928346513c87 609 destructiveFlag = true;
HBP 12:928346513c87 610 destructiveBlock = (uint32_t)cDataOB[1]<<8|cDataOB[2];
HBP 12:928346513c87 611 goto allocate_new_block;
HBP 12:928346513c87 612 } else if ((cDataOB[0] & 0x40) != 0x40) // fMode == AWRITE
HBP 12:928346513c87 613 {
HBP 12:928346513c87 614 // Update current block info
HBP 12:928346513c87 615 currBlock = (uint32_t)cDataOB[1]<<8|cDataOB[2];
HBP 12:928346513c87 616 blockPos = RB; // Reset block position offset
HBP 12:928346513c87 617 } else // There is no block to append so we allocate a new one
HBP 12:928346513c87 618 {
HBP 12:928346513c87 619 allocate_new_block:
HBP 12:928346513c87 620 // Allocate new block for use
HBP 12:928346513c87 621 cData[0] = 0x4C; // New flags
HBP 12:928346513c87 622 cData[1] = '\0'; // Hbyte of Next Block link
HBP 12:928346513c87 623 cData[2] = '\0'; // Lbyte of Next Block link
HBP 12:928346513c87 624 cData[3] = (char)((currBlock & 0xff00) >> 8); // Hbyte of Prev Block link
HBP 12:928346513c87 625 cData[4] = (char)(currBlock & 0x00ff); // Lbyte of Prev Block link
HBP 12:928346513c87 626 fs->write(cData, nextFree, 0, RB); // Update Block Data
HBP 0:cbf45dde2b49 627
HBP 12:928346513c87 628 // Link old block with new block
HBP 12:928346513c87 629 cDataOB[0] &= ~0x40; // Clear LBOF flag if set
HBP 12:928346513c87 630 cDataOB[1] = (char)((nextFree & 0xff00) >> 8); // Hbyte of Next Block link
HBP 12:928346513c87 631 cDataOB[2] = (char)(nextFree & 0x00ff); // Lbyte of Next Block link
HBP 12:928346513c87 632 fs->write(cDataOB, currBlock, 0, RB-BLOCK_LLEN); // Update Block Data
HBP 9:52c01cb100ac 633
HBP 12:928346513c87 634 // Update current block info
HBP 12:928346513c87 635 currBlock = nextFree;
HBP 12:928346513c87 636 blockPos = RB; // Reset block position offset
HBP 12:928346513c87 637 }
HBP 0:cbf45dde2b49 638 }
HBP 0:cbf45dde2b49 639
HBP 13:142b6be3e3c8 640 if (fMode == AWRITE) // Check if EOF is here
HBP 13:142b6be3e3c8 641 {
HBP 13:142b6be3e3c8 642 fs->read(c, currBlock, blockPos, 1);
HBP 13:142b6be3e3c8 643 if ((c[0] == mEOF) && (fEOFow == false))
HBP 13:142b6be3e3c8 644 fEOFow = true;
HBP 13:142b6be3e3c8 645 }
HBP 13:142b6be3e3c8 646
HBP 0:cbf45dde2b49 647 // Write file
HBP 0:cbf45dde2b49 648 c[0]=buffer[i];
HBP 0:cbf45dde2b49 649 fs->write(c, currBlock, blockPos, 1);
HBP 0:cbf45dde2b49 650 blockPos++;
HBP 12:928346513c87 651 byteCount++;
HBP 13:142b6be3e3c8 652
HBP 13:142b6be3e3c8 653 // For fail safe, write EOF now
HBP 13:142b6be3e3c8 654 if ((fMode == DWRITE)||(fEOFow == true))
HBP 13:142b6be3e3c8 655 fs->write((char[]){mEOF}, currBlock, blockPos, 1); // Write mEOF
HBP 0:cbf45dde2b49 656 }
HBP 0:cbf45dde2b49 657
HBP 0:cbf45dde2b49 658 bufPos = 0; // Reset buffer position counter
HBP 0:cbf45dde2b49 659
HBP 12:928346513c87 660 /* If destructive write flag is set
HBP 12:928346513c87 661 and there is data to be removed then remove data now */
HBP 12:928346513c87 662 if (destructiveFlag == true)
HBP 12:928346513c87 663 if(removeFollowingBlocks(destructiveBlock) != 0)
HBP 12:928346513c87 664 return 3;
HBP 12:928346513c87 665
HBP 0:cbf45dde2b49 666 FlushLed = 0;
HBP 0:cbf45dde2b49 667 return 0;
HBP 0:cbf45dde2b49 668 }