// These functions should reside below the API and be called only for calls to filesystem 'FLASH0' // This will only work with AMD AM29LV800BB or AM29LV160BB flash devices! // // terminology // superblock - one block of FLASH // subblock - subdevision of a superblock, smallest space that the filesystem can allocate // block - not used to avoid confusion :-) #include "eCosIvory/FLASHFileSystem.h" // this file system #include "eCosIvory/flash.h" // flash lib #include // malloc #include /* sprintf */ #include /* LED Control */ #include /* diag_printf */ #include "eCosIvory/console.h" // display #include "eCosIvory/system.h" // file system pointer // Constructor FLASHfileSystem::FLASHfileSystem() { // declare block information // to be populated by hand! subBlockSize = SUBBLOCKSIZE; // MUST NOT EXCEED superBlocksize / noSubBlocksPerSuperBlock noSubBlocksPerSuperBlock = SUBBLOCKSPERSUPERBLOCK; CYG_ADDRESS sbt[NUMSUPERBLOCKS] = SUPERBLOCKS; memcpy(superBlockTable, sbt, sizeof(sbt)); // build FAT structure in RAM noSuperBlocks = NUMSUPERBLOCKS; noSubBlocks = NUMSUBBLOCKS; // Attempt to read device information infoFlashCmd flashData; flashData.flashCommand = flashCmd_Info; ((RAMfn_type)(FLASHCodeInRAM))((cyg_uint32 *)&flashData); // valid devices devices... if (flashData.make == AMD && flashData.deviceID == AMD29LV800BB) { valid = true; } else { valid = false; } next = NULL; // invalid file pointer (no open files) //## insert code to restore FAT contents from FLASH //## insert code to create mutex for file system } // destructor FLASHfileSystem::~FLASHfileSystem() { //## insert code to back RAM tables to FLASH //## insert code to destry mutex } // erase block; bool FLASHfileSystem::eraseBlock(CYG_ADDRESS superblock) { eraseFlashCmd flashErase; flashErase.flashCommand = flashCmd_Erase; flashErase.sectorNo = superblock; ((RAMfn_type)(FLASHCodeInRAM))((cyg_uint32 *)&flashErase); while (flashErase.onHold) { cyg_thread_yield(); flashErase.flashCommand = flashCmd_ResumeErase; ((RAMfn_type)(FLASHCodeInRAM))((cyg_uint32 *)&flashErase); } return flashErase.success; } // FLASH Format bool FLASHfileSystem::format(void) { // Confirm that this is flash we know about... if (!valid) return false; // confirm that there are no files open... // i.e. we can not format if there are still files open if(next != NULL) { #ifdef dbg_FLASH diag_printf("format: files are still open - can't format!\r"); #endif return false; } //## lock FLASH mutex // erase superblocks used in our file system for (int SB = 0; SB < noSuperBlocks; SB++) if (!eraseBlock(superBlockTable[SB])) return false; // Initialise structure for (cyg_uint32 count = 0; count < noSubBlocks; count++) { subBlockTable[count].state = unused; subBlockTable[count].next = FLASHNull; subBlockTable[count].prev = FLASHNull; } freeCount = noSubBlocks - noSubBlocksPerSuperBlock; // leave 1 superblock as working space usedCount = 0; dirtyCount = 0; subBlockFreePtr = 0; subBlockUsedPtr = 0; for (int FR = 0; FR < MAXFILES; FR++) { // technicly we need only initialise the name strcpy(FAT[FR].name,"\0"); FAT[FR].start = FLASHNull; FAT[FR].length = 0; } fileCount = 0; //## unlock FLASH mutex return true; } // write to FLASH bool FLASHfileSystem::writeToFlash(cyg_uint16 writeData, cyg_uint32 writeAddress) { writeFlashCmd flashWrite; flashWrite.flashCommand = flashCmd_Write; flashWrite.writeData = writeData; flashWrite.writeAddress = writeAddress; ((RAMfn_type)(FLASHCodeInRAM))((cyg_uint32 *)&flashWrite); return flashWrite.result; } // examine the FAT for a matching name int FLASHfileSystem::lookUp(char *name) { for (int count = 0; count < MAXFILES; count++) if (strcmp(name, FAT[count].name) == 0) return count; return FLASHFileNotFound; } // Calculate the start Address of the SubBlock cyg_uint32 FLASHfileSystem::getSubBlockAddress(int subBlockNumber) { int superBlockNo = subBlockNumber / noSubBlocksPerSuperBlock; int subBlockOfSuperBlock = subBlockNumber % noSubBlocksPerSuperBlock; return (subBlockOfSuperBlock * subBlockSize) + superBlockTable[superBlockNo]; } // FLASH create file bool FLASHfileSystem::create(int length, char *data, char *name) { #ifdef dbg_FLASH diag_printf("checking for valid file system..."); #endif // Confirm that this is flash we know about... if (!valid) return false; //## lock FLASH mutex // check if we have space for the file #ifdef dbg_FLASH diag_printf("FS VALID\rCheck for space in FAT..."); #endif if (fileCount == MAXFILES) return false; #ifdef dbg_FLASH diag_printf("Enough space\r"); #endif //Limit size of file name #ifdef dbg_FLASH diag_printf("Limit file name size..."); #endif int nameLen = strlen(name); if (nameLen > MAXNAMELEN) { nameLen = MAXNAMELEN; } name[nameLen] = '\0'; #ifdef dbg_FLASH diag_printf("File name limited to %s\r", name); #endif // confirm that the file doesn't already exist #ifdef dbg_FLASH diag_printf("checking name is unique..."); #endif if (int FileNumber = lookUp(name) != FLASHFileNotFound) return false; // name exists #ifdef dbg_FLASH diag_printf("DONE\r"); #endif // grab the number of required subBlocks or return false if insufficiant space #ifdef dbg_FLASH diag_printf("Allocating required number of subBlocks..."); #endif int subBlocksRequired = length / subBlockSize; if ((length % subBlockSize) > 0) subBlocksRequired += 1; if (subBlocksRequired > freeCount) return false; freeCount-= subBlocksRequired; #ifdef dbg_FLASH diag_printf("%d subBlocks allocated\r", subBlocksRequired); #endif // build a table of the sub block numbers diag_printf("Building table of subBlocks\r"); int subBlock[subBlocksRequired]; for (int selected = 0; selected < subBlocksRequired; selected++) { #ifdef dbg_FLASH diag_printf("Outer Loop Start (selected = 0x%x\r", selected); #endif do { subBlock[selected] = subBlockFreePtr; subBlockFreePtr++; subBlockFreePtr = subBlockFreePtr % noSubBlocks; } while (subBlockTable[subBlock[selected]].state != unused); subBlockTable[subBlock[selected]].state = inuse; #ifdef dbg_FLASH diag_printf("Using subBlock 0x%x\r", selected); #endif } // Find an unused entry in the FAT and populate it int count = 0; #ifdef dbg_FLASH diag_printf("Looking for space in FAT..."); #endif while (strcmp(FAT[count].name,"") != 0) count++; #ifdef dbg_FLASH diag_printf("added entry to FAT record 0x%x\r", count); #endif strcpy(FAT[count].name,name); FAT[count].length = length; FAT[count].start = subBlock[0]; fileCount++; //## unlock FLASH mutex // populate the data to flash and update each record #ifdef dbg_FLASH diag_printf("writing data to FLASH..."); #endif cyg_uint32 written = 0; // how much data we have already written cyg_uint32 writeEnd; // last data element to write in this subBlock char *pMem = data; for (count = 0; count < subBlocksRequired; count++) { // update subBlockTable //## lock FLASH mutex subBlockTable[subBlock[count]].next = (count != subBlocksRequired-1) ? subBlock[count+1] : FLASHNull; subBlockTable[subBlock[count]].prev = (count != 0) ? subBlock[count-1] : FLASHNull; //## unlock FLASH mutex // Calculate the start Address of the SubBlock cyg_uint32 writeAddress = getSubBlockAddress(subBlock[count]); #ifdef dbg_FLASH diag_printf("Writing subblock from address 0x%08x to ", writeAddress); #endif // calculate the amount of data to write cyg_uint32 writeLength = length - written; if (writeLength > subBlockSize) { writeEnd = writeAddress + subBlockSize; writeLength = subBlockSize; } else { writeEnd = writeAddress + writeLength; } #ifdef dbg_FLASH diag_printf("0x%08x \r\n", writeEnd); #endif //write to FLASH while (writeAddress < writeEnd) { cyg_uint16 tmp = *pMem++; // 1st byte cyg_uint16 wdata = (*pMem++ << 8) | tmp; // 2nd byte // diag_printf("FLASHfileSystem::create Writing 0x%x from 0x%x to 0x%x\r\n", flashWrite.writeData, pMem - 2, flashWrite.writeAddress); writeToFlash(wdata, writeAddress); writeAddress += 2; } written += writeLength; // amount of date written diag_printf("written = 0x%08x \r\n", written); //## lock FLASH mutex subBlockTable[subBlock[count]].state = used; usedCount++; //## unlock FLASH mutex } #ifdef dbg_FLASH diag_printf("DONE\r\r FILE CREATED\r\r"); #endif return true; } // FLASH read file bool FLASHfileSystem::readAll(char *name, int *length, char *data) { // Confirm that this is flash we know about... if (!valid) return false; //## lock FLASH mutex // check that the filename exists int fileNumber = lookUp(name); if (fileNumber == FLASHFileNotFound) return false; // get file attributes *length = FAT[fileNumber].length; int subBlock = FAT[fileNumber].start; // allocate buffer to read data into if ((data = (char *) malloc(*length)) == NULL) return false; // unable to allocate space in which to open the file // read the data from FLASH into RAM int bytesRead = 0; char *storeAt = data; CYG_ADDRESS readAddress = getSubBlockAddress(subBlock); { int readLength = (*length - bytesRead <= subBlockSize) ? *length - bytesRead : subBlockSize; // read from FLASH into the buffer memcpy(storeAt, (char *)readAddress, readLength); // update pointers and counters storeAt += readLength; bytesRead += readLength; subBlock = subBlockTable[subBlock].next; readAddress = getSubBlockAddress(subBlock); } while (readAddress != FLASHNull); //## unlock FLASH mutex } // recover 'dirty' areas of FLASH void FLASHfileSystem::reclaimDirtyFLASH(void) { while (dirtyCount >= noSubBlocksPerSuperBlock) { // find oldest dirtySubBlock int dirtySubBlock; do { dirtySubBlock = subBlockUsedPtr++; subBlockUsedPtr = subBlockUsedPtr % noSubBlocks; } while (subBlockTable[dirtySubBlock].state != dirty); // calculate the SuperBlock within which this subBlock resides int superBlockNo = dirtySubBlock / noSubBlocksPerSuperBlock; int baseSubBlockNo = dirtySubBlock - (dirtySubBlock % noSubBlocksPerSuperBlock); // re-loacate all used subblocks and update tables for (int count = baseSubBlockNo; count < (baseSubBlockNo + noSubBlocksPerSuperBlock); count++) { switch (subBlockTable[count].state) { case used: { // relocate to another subBlock // find a new location to write to int newLocation; do { newLocation = subBlockFreePtr++; subBlockFreePtr = subBlockFreePtr % noSubBlocks; } while (subBlockTable[newLocation].state != unused); subBlockTable[newLocation].state = used; // Calculate the start Address of the SubBlock cyg_uint32 writeAddress = getSubBlockAddress(newLocation); cyg_uint32 writeEnd = writeAddress + subBlockSize ; char *pMem = (char *)getSubBlockAddress(count); //write to FLASH while (writeAddress < writeEnd) { cyg_uint16 tmp = *pMem++; // 1st byte cyg_uint16 data = (*pMem++ << 8) | tmp; // 2nd byte #ifdef dbg_FLASH diag_printf("reclaimDirtyFLASH: Writing 0x%x from 0x%x to 0x%x\r\n", flashWrite.writeData, pMem - 2, flashWrite.writeAddress); #endif writeToFlash(data, writeAddress); writeAddress += 2; } // update FAT if required if (subBlockTable[count].prev == FLASHNull) { // Find Entry in FAT int FR = 0; while (FAT[FR].start != count) FR++; // Update start field FAT[FR].start = newLocation ; } // update linked list subBlockTable[newLocation].state = subBlockTable[count].state; subBlockTable[newLocation].next = subBlockTable[count].next; subBlockTable[newLocation].prev = subBlockTable[count].prev; subBlockTable[count].state = unused; subBlockTable[count].next = FLASHNull; subBlockTable[count].prev = FLASHNull; break; } case dirty: { // change the state to free and update counters subBlockTable[count].state = unused; subBlockTable[count].next = FLASHNull; subBlockTable[count].prev = FLASHNull; --dirtyCount; freeCount++; break; } default: // do not change the subBlockTable entry for this subBlock // i.e. if the subBlock is marked as bad it will remain so // note however that the DATA in flash related to this // subBlock WILL still be ERASED break; } } // erase the superBlock eraseBlock(superBlockTable[superBlockNo]); } } // FLASH erase file bool FLASHfileSystem::erase(char *name) { // Confirm that this is flash we know about... if (!valid) return false; //## lock FLASH mutex // check that the filename exists int fileNumber = lookUp(name); if (fileNumber == FLASHFileNotFound) return false; // delete file number and recover the 1st subBlock of the file strcpy(FAT[fileNumber].name,""); // remove entry int count = FAT[fileNumber].start; fileCount--; do { subBlockTable[count].state = dirty; count = subBlockTable[count].next; dirtyCount++; --usedCount; } while (count != FLASHNull); // reclaim SuperBlocks if possible reclaimDirtyFLASH(); //## unlock FLASH mutex } // diagnostic routine to dump the current file structure to the serial port void FLASHfileSystem::show(void) { //## Lock FLASH mutex char buffer[128]; sprintf(buffer, "File System information:"); display (buffer); sprintf(buffer, " noSuperBlocks = 0x%x", noSuperBlocks); display (buffer); sprintf(buffer, " subBlocksize = 0x%x", subBlockSize); display (buffer); sprintf(buffer, " noSubBlocksPerSuperBlock = 0x%x", noSubBlocksPerSuperBlock); display (buffer); sprintf(buffer, " noSubBlocks = 0x%x", noSubBlocks); display (buffer); sprintf(buffer, " freeCount = 0x%x", freeCount); display (buffer); sprintf(buffer, " usedCount = 0x%x", usedCount); display (buffer); sprintf(buffer, " dirtyCount = 0x%x", dirtyCount); display (buffer); sprintf(buffer, " subBlockFreePtr = 0x%x", subBlockFreePtr); display (buffer); sprintf(buffer, " subBlockUsedPtr = 0x%x", subBlockUsedPtr); display (buffer); sprintf(buffer, " fileCount = 0x%x", fileCount); display (buffer); sprintf(buffer, " FAT name start length"); display (buffer); for (int count0 = 0; count0 < MAXFILES; count0++) { sprintf(buffer, " FAT[0x%x] = %s, 0x%x, 0x%x", count0, FAT[count0].name, FAT[count0].start, FAT[count0].length); display (buffer); } sprintf(buffer, " subBlock state next prev start address"); display (buffer); for (int count1 = 0; count1 < noSubBlocks; count1++) { sprintf(buffer, " subBlockTable[0x%04x] = %02d, 0x%04x, 0x%04x, 0x%08x", count1, subBlockTable[count1].state, subBlockTable[count1].next, subBlockTable[count1].prev, getSubBlockAddress(count1)); display (buffer); } //## unlock FLASH mutex } // show files in file system void FLASHfileSystem::cat(void) { //## Lock FLASH mutex char buffer[128]; int files = 0; int used = 0; for (int count = 0; count < MAXFILES; count++) { if (strcmp(FAT[count].name,"") != 0) { sprintf(buffer, "%s 0x%x", FAT[count].name, FAT[count].length); display (buffer); files++; used += FAT[count].length; } } sprintf(buffer, "%d File(s) 0x%x Bytes\r 0x%x Bytes free\r\n", files, used, (freeCount+dirtyCount)*subBlockSize); display (buffer); //## unlock FLASH mutex } // open a file for read/write returning a handle if valid int FLASHfileSystem::open(char *name, openFile *&handle) { #ifdef dbg_FLASH diag_printf("open\r"); #endif // Confirm that this is flash we know about... if (!valid) return FLASH_UnsupportedDevice; #ifdef dbg_FLASH diag_printf(" fileSystem is valid\r"); #endif //Limit size of file name int nameLen = strlen(name); if (nameLen > MAXNAMELEN) { nameLen = MAXNAMELEN; } name[nameLen] = '\0'; #ifdef dbg_FLASH diag_printf(" name = %s\r", name); #endif //## lock FLASH mutex // check if the filename exists int fileNumber = lookUp(name); if (fileNumber == FLASHFileNotFound) { // file does not exist #ifdef dbg_FLASH diag_printf(" File does not exist - creating new file\r"); #endif // check if there is space to create a new file if (fileCount == MAXFILES) return FLASH_TooManyFiles; // allocate 1st subBlock to the file (there has to be somewhere for the data!) if (freeCount < 1) return FLASH_OutOfSpace; freeCount--; usedCount++; int subBlockSelected; do { subBlockSelected = subBlockFreePtr; subBlockFreePtr++; subBlockFreePtr = subBlockFreePtr % noSubBlocks; } while (subBlockTable[subBlockSelected].state != unused); subBlockTable[subBlockSelected].state = inuse; // find a free entry in the FAT and populate it int count = 0; while (strcmp(FAT[count].name,"") != 0) count++; strcpy(FAT[count].name,name); FAT[count].length = 0; FAT[count].start = subBlockSelected; fileCount++; fileNumber = count; } else { // file does exist #ifdef dbg_FLASH diag_printf(" Found file\r"); #endif // check to see if the file is already open openFile *fwd = next; while (fwd != NULL) { if (fwd->fileNumber == fileNumber) return FLASH_FileAlreadyOpen; fwd = fwd->next; } } #ifdef dbg_FLASH diag_printf(" handle originly 0x%x\r", handle); #endif handle = new openFile(next, fileNumber); #ifdef dbg_FLASH diag_printf(" handle 0x%x\r\n", handle); #endif //## unlock FLASH mutex return FLASH_OperationSuccessful; } // confirm that the handle given is valid bool FLASHfileSystem::validateHandle(openFile *handle) { // travers the linked list of open files to confirm that the handle does exist #ifdef dbg_FLASH diag_printf("validateHandle\r"); diag_printf(" handle = 0x%x\r", handle); #endif openFile *fwd = next; while (fwd != NULL) { if (fwd == handle) { #ifdef dbg_FLASH diag_printf(" handle is valid\r"); #endif return true; } fwd = fwd->next; } #ifdef dbg_FLASH diag_printf(" handle is invalid\r"); #endif return false; } int FLASHfileSystem::read(openFile *handle, size_t position, size_t *length, void *ptr) { #ifdef dbg_FLASH diag_printf("FLASHfileSystem::read\r"); #endif //## lock FLASH mutex // confirm that the handle is valid if (!validateHandle(handle)) return FLASH_InvalidHandle; size_t readPosition = position; size_t toRead = *length; *length = 0; char *buffer = (char *)ptr; char inChar; #ifdef dbg_FLASH diag_printf(" reading...\r"); #endif while (toRead > 0) { #ifdef dbg_FLASH diag_printf(" readPosition = 0x%x\r FAT[handle->fileNumber].length = 0x%x\r", readPosition, FAT[handle->fileNumber].length); #endif // check that the start position is inside the file if (readPosition > FAT[handle->fileNumber].length) { #ifdef dbg_FLASH diag_printf("\rFLASHfileSystem::read EOF DONE\r"); #endif return FLASH_EOF; } // determine the subBlock that we are going to start from int subBlock = readPosition / subBlockSize; // get the address of this subBlock int record = FAT[handle->fileNumber].start; for (int count = 1; count < subBlock; count++) { record = subBlockTable[record].next; } int subBlockAddress = getSubBlockAddress(subBlock); int readAddress = subBlockAddress + (readPosition % subBlockSize); inChar = (*((char *)(readAddress))); #ifdef dbg_FLASH diag_printf("%c", inChar); #endif buffer[readPosition] = inChar; toRead-=1; *length = (size_t)readPosition++; #ifdef dbg_FLASH diag_printf(" bytes left to read = 0x%x\r we have read 0x%x bytes so far\r", toRead, length); #endif } //## unlock FLASHmutex #ifdef dbg_FLASH diag_printf("\rFLASHfileSystem::read DONE\r"); #endif return FLASH_OperationSuccessful; } int FLASHfileSystem::write(openFile *handle, size_t position, size_t *length, void *ptr) { //## lock FLASH mutex #ifdef dbg_FLASH diag_printf("write\r\n"); diag_printf(" handle = 0x%x\r", handle); diag_printf(" position = 0x%x\r",position); diag_printf(" length = 0x%x\r", *length); diag_printf(" ptr = 0x%x\r", ptr); #endif // confirm that the handle is valid if (!validateHandle(handle)) return FLASH_InvalidHandle; // only support append type write #ifdef dbg_FLASH diag_printf(" FAT[handle->fileNumber].length = 0x%x\r", FAT[handle->fileNumber].length); diag_printf(" handle->fileNumber = 0x%x\r", handle->fileNumber); #endif if (position != FAT[handle->fileNumber].length) return FLASH_OporationNotSupported; size_t writePosition = position; size_t toWrite = *length; *length = 0; char *buffer = (char *)ptr; #ifdef dbg_FLASH diag_printf(" We are going to write 0x%x bytes to file 0x%x starting at position 0x%x\r", toWrite, handle->fileNumber, writePosition); #endif while (toWrite > 0) { // determine the subBlock that we are going to start from int subBlock = writePosition / subBlockSize; int record; #ifdef dbg_FLASH diag_printf("\r ---- \r"); #endif if ((writePosition % subBlockSize != 0) || writePosition == 0) { // We are still inside the last subBlock #ifdef dbg_FLASH diag_printf(" This falls inside the last subBlock of the file\r"); #endif // get the address of this subBlock record = FAT[handle->fileNumber].start; while (subBlockTable[record].next != FLASHNull) { record = subBlockTable[record].next; } } else { // We have run out of space to write data. Attempt to get another subBlock #ifdef dbg_FLASH diag_printf(" We have run out of space to write data. Attempt to get another subBlock\r"); #endif // Confirm that there is another free subBlock if (freeCount == 0) return FLASH_OutOfSpace; freeCount--; // get the last subBlock used by our file int lastSubBlock = FAT[handle->fileNumber].start; while (subBlockTable[lastSubBlock].next != FLASHNull) { lastSubBlock = subBlockTable[lastSubBlock].next; } // obtain the subBlock do { record = subBlockFreePtr++; subBlockFreePtr = subBlockFreePtr % noSubBlocks; } while (subBlockTable[record].state != unused); subBlockTable[record].state = used; usedCount++; // add the new subBlock to the end of the linked list for our file subBlockTable[lastSubBlock].next = record; subBlockTable[record].prev = lastSubBlock; subBlockTable[record].next = FLASHNull; } // get the address to write to int subBlockAddress = getSubBlockAddress(record); int writeAddress = subBlockAddress + (writePosition % subBlockSize); #ifdef dbg_FLASH diag_printf(" subBlock Record number = 0x%x\r at address 0x%x\r we will write from address 0x%x\r", record, subBlockAddress, writeAddress); #endif // perform actual write operation // note that this is a 16 bit oporation but we want to work in bytes! if (writeAddress % 2 == 0) { // even address cyg_uint16 data = 0xff00 | *buffer++; // LSB will be the byte to write MSB will be blank (0xff) #ifdef dbg_FLASH diag_printf(" even write data = 0x%04x\r", data); #endif writeToFlash(data, writeAddress); } else { // odd address cyg_uint16 *tmp = (cyg_uint16 *)(writeAddress-1); // LSB is read from device cyg_uint16 rval = *tmp; #ifdef dbg_FLASH diag_printf(" odd write\r read 0x%04x\r rval = 0x%04x\r", *tmp, rval); #endif rval &= 0x00ff; // just interested in the lower byte #ifdef dbg_FLASH diag_printf(" after mask 0x%04x\r", rval); diag_printf(" *buffer = 0x%x\r", *buffer); #endif cyg_uint16 wchar = (cyg_uint16)*buffer++; #ifdef dbg_FLASH diag_printf(" wchr before rotate = 0x%04x\r", wchar); #endif wchar = wchar << 8; #ifdef dbg_FLASH diag_printf(" wchr after rotate = 0x%04x\r", wchar); #endif cyg_uint16 data = wchar | rval; // MSB is the byte to program #ifdef dbg_FLASH diag_printf(" value to write 0x%04x\r", data); #endif writeToFlash(data, writeAddress-1); } // update counts FAT[handle->fileNumber].length++; // file length toWrite--; // number of bytes left to write *length++; // number of bytes written writePosition++; // where to write data to next... } return FLASH_OperationSuccessful; } // closes an open file. free's up any available resources. int FLASHfileSystem::close(openFile *handle) { //## lock FLASH mutex // confirm that the handle is valid if (!validateHandle(handle)) return FLASH_InvalidHandle; // free up resources if possible if (FAT[handle->fileNumber].length == 0) { subBlockTable[FAT[handle->fileNumber].start].state = unused; // mark block as free freeCount++; // number of free blocks +1 usedCount--; // return used block to free state fileCount--; // count of files -1 strcpy(FAT[handle->fileNumber].name,""); // remove entry from FAT } delete handle; //## unlock FLASH mutex return FLASH_OperationSuccessful; } openFile::openFile(openFile *&fwd, int fileNum) { // add the handle to the linked list of all open files #ifdef dbg_FLASH diag_printf("openFile::openFile\r"); #endif if (fwd == NULL) { #ifdef dbg_FLASH diag_printf(" No files open\r"); #endif fwd = this; prev = NULL; next = NULL; } else { #ifdef dbg_FLASH diag_printf(" files are open\r"); #endif while (fwd->next != NULL) { #ifdef dbg_FLASH diag_printf(" advaning down the list\r"); #endif fwd = fwd->next; } #ifdef dbg_FLASH diag_printf(" adding record to the list\r"); #endif fwd->next = this; prev = fwd; next = NULL; } #ifdef dbg_FLASH if (prev == NULL) { diag_printf(" prev = NULL\r"); } else { diag_printf(" prev = 0x%x\r", prev); } if (next == NULL) { diag_printf(" next = NULL\r"); } else { diag_printf(" next = 0x%x\r", next); } if (sys->fs->next == NULL) { diag_printf(" sys->fs->next = NULL\r"); } else { diag_printf(" sys->fs->next = 0x%x\r", sys->fs->next); } diag_printf("openFile::openFile DONE\r"); #endif fileNumber = fileNum; } openFile::~openFile() { #ifdef dbg_FLASH diag_printf("openFile::~openFile\r"); #endif // remove entry from the linked list of open files if (prev != NULL) { prev->next = next; } else { sys->fs->next = next; } if (next != NULL) next->prev = prev; #ifdef dbg_FLASH if (prev == NULL) { diag_printf(" prev = NULL\r"); } else { diag_printf(" prev = 0x%x\r", prev); } if (next == NULL) { diag_printf(" next = NULL\r"); } else { diag_printf(" next = 0x%x\r", next); } if (sys->fs->next == NULL) { diag_printf(" sys->fs->next = NULL\r"); } else { diag_printf(" sys->fs->next = 0x%x\r", sys->fs->next); } diag_printf("openFile::~openFile DONE\r"); #endif }