A library with drivers for different peripherals on the LPC4088 QuickStart Board or related add-on boards.

Dependencies:   FATFileSystem

Fork of EALib by EmbeddedArtists AB

Committer:
embeddedartists
Date:
Wed Dec 11 12:16:40 2013 +0000
Revision:
8:fe3cb3fbb64e
Parent:
0:0fdadbc3d852
Child:
12:15597e45eea0
Extracted SPIFI initialization code from QSPIFileSystem into new SPIFI class to allow spifi to be used without having to use the file system.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
embeddedartists 0:0fdadbc3d852 1 #include "QSPIFileSystem.h"
embeddedartists 0:0fdadbc3d852 2 #include "mbed_debug.h"
embeddedartists 0:0fdadbc3d852 3
embeddedartists 8:fe3cb3fbb64e 4 #include "SPIFI.h"
embeddedartists 0:0fdadbc3d852 5
embeddedartists 0:0fdadbc3d852 6 /******************************************************************************
embeddedartists 0:0fdadbc3d852 7 * Defines and typedefs
embeddedartists 0:0fdadbc3d852 8 *****************************************************************************/
embeddedartists 0:0fdadbc3d852 9
embeddedartists 0:0fdadbc3d852 10 #define QSPI_DBG 0
embeddedartists 0:0fdadbc3d852 11
embeddedartists 0:0fdadbc3d852 12 #define IS_ADDR_IN_SPIFI(__addr) ( (((uint32_t)(__addr)) & 0xff000000) == SPIFI_MEM_BASE )
embeddedartists 0:0fdadbc3d852 13
embeddedartists 8:fe3cb3fbb64e 14 #define MEM_SIZE (memInfo.memSize)
embeddedartists 8:fe3cb3fbb64e 15 #define ERASE_SIZE (memInfo.eraseBlockSize)
embeddedartists 8:fe3cb3fbb64e 16 #define NUM_BLOCKS (memInfo.numEraseBlocks)
embeddedartists 0:0fdadbc3d852 17
embeddedartists 0:0fdadbc3d852 18 typedef uint32_t toc_entry_t;
embeddedartists 0:0fdadbc3d852 19
embeddedartists 0:0fdadbc3d852 20 #define TOC_BLOCK_ADDR (memInfo.tocBlockAddr) //(SPIFI_MEM_BASE + (NUM_BLOCKS - 1)*ERASE_SIZE)
embeddedartists 0:0fdadbc3d852 21 #define TOC_SIZE (memInfo.tocSizeInBytes) //(sizeof(toc_entry_t) * NUM_BLOCKS)
embeddedartists 0:0fdadbc3d852 22 #define NUM_TOCS (memInfo.numTocs) //((int)(ERASE_SIZE/TOC_SIZE))
embeddedartists 0:0fdadbc3d852 23 #define NUM_TOC_BLOCKS ((NUM_TOCS * TOC_SIZE) / ERASE_SIZE)
embeddedartists 0:0fdadbc3d852 24 #define NUM_TOC_ENTRIES ((int)(TOC_SIZE/sizeof(toc_entry_t)))
embeddedartists 0:0fdadbc3d852 25
embeddedartists 0:0fdadbc3d852 26 #define TOC_UNUSED (0xffffffff)
embeddedartists 0:0fdadbc3d852 27 #define TOC_MAX (NUM_BLOCKS - 1)
embeddedartists 0:0fdadbc3d852 28 #define TOC_VALID_MASK (1UL<<31)
embeddedartists 0:0fdadbc3d852 29 #define TOC_RESERVED_MASK (1UL<<30)
embeddedartists 0:0fdadbc3d852 30 #define TOC_USED_MASK (1UL<<29)
embeddedartists 0:0fdadbc3d852 31 #define TOC_FILE_MASK (1UL<<28)
embeddedartists 0:0fdadbc3d852 32 #define TOC_FSIZE_MASK (0x3ffff)
embeddedartists 0:0fdadbc3d852 33 #define TOC_MANDAT_SET_MASK (0x0ffc0000)
embeddedartists 0:0fdadbc3d852 34
embeddedartists 0:0fdadbc3d852 35 #define MANDATORY_BITS_SET(__v) (((__v)&TOC_MANDAT_SET_MASK) == TOC_MANDAT_SET_MASK)
embeddedartists 0:0fdadbc3d852 36
embeddedartists 0:0fdadbc3d852 37 #define VALID_TOC_ENTRY(__v) (((__v)&TOC_VALID_MASK) == 0)
embeddedartists 0:0fdadbc3d852 38 #define USED_TOC_ENTRY(__v) (VALID_TOC_ENTRY(__v) && (((__v)&TOC_USED_MASK) == 0))
embeddedartists 0:0fdadbc3d852 39 #define TOC_IS_FILE(__v) (USED_TOC_ENTRY(__v) && (((__v)&TOC_FILE_MASK) == 0))
embeddedartists 0:0fdadbc3d852 40 #define TOC_IS_RESERVED(__v) (VALID_TOC_ENTRY(__v) && (((__v)&TOC_RESERVED_MASK) == 0))
embeddedartists 0:0fdadbc3d852 41 #define FILESIZE(__v) ((__v) & 0x3ffff)
embeddedartists 0:0fdadbc3d852 42
embeddedartists 0:0fdadbc3d852 43 #define FS_MIN(__a, __b) (((__a) < (__b)) ? (__a) : (__b))
embeddedartists 0:0fdadbc3d852 44
embeddedartists 0:0fdadbc3d852 45 // Mask to compare the different access modes. In LPCXpresso this was defined
embeddedartists 0:0fdadbc3d852 46 // but not in uVision
embeddedartists 0:0fdadbc3d852 47 #ifndef O_ACCMODE
embeddedartists 0:0fdadbc3d852 48 #define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
embeddedartists 0:0fdadbc3d852 49 #endif
embeddedartists 0:0fdadbc3d852 50
embeddedartists 0:0fdadbc3d852 51
embeddedartists 0:0fdadbc3d852 52 /*
embeddedartists 0:0fdadbc3d852 53 * The file header currently only consists of the filename (including path)
embeddedartists 0:0fdadbc3d852 54 * and the string terminating character, but by separating the file name
embeddedartists 0:0fdadbc3d852 55 * length from the size of the header in the code it allows future additions
embeddedartists 0:0fdadbc3d852 56 * to the header without too much code modification.
embeddedartists 0:0fdadbc3d852 57 */
embeddedartists 0:0fdadbc3d852 58 #define HEADER_DNAME_MAXLEN (250)
embeddedartists 0:0fdadbc3d852 59 #define HEADER_FNAME_STRLEN (HEADER_DNAME_MAXLEN + 5)
embeddedartists 0:0fdadbc3d852 60 #define HEADER_FNAME_LEN (HEADER_FNAME_STRLEN + 1)
embeddedartists 0:0fdadbc3d852 61 #define HEADER_LEN (HEADER_FNAME_LEN) // only filename in header for now
embeddedartists 0:0fdadbc3d852 62
embeddedartists 0:0fdadbc3d852 63 typedef enum
embeddedartists 0:0fdadbc3d852 64 {
embeddedartists 0:0fdadbc3d852 65 FS_OK,
embeddedartists 0:0fdadbc3d852 66 FS_ERR_NOT_FORMATTED,
embeddedartists 0:0fdadbc3d852 67 FS_ERR_NO_FILE,
embeddedartists 0:0fdadbc3d852 68 FS_ERR_FILE_EXIST,
embeddedartists 0:0fdadbc3d852 69 FS_ERR_INVALID_PARAM,
embeddedartists 0:0fdadbc3d852 70 FS_ERR_DISK_FULL,
embeddedartists 0:0fdadbc3d852 71 FS_ERR_SPIFI,
embeddedartists 0:0fdadbc3d852 72 FS_ERR_MALLOC,
embeddedartists 0:0fdadbc3d852 73
embeddedartists 0:0fdadbc3d852 74 // FS_ERR_SPIFI_* return codes are listed in the User's Manual
embeddedartists 0:0fdadbc3d852 75 // as possible return values from spifi_init(), spifi_program()
embeddedartists 0:0fdadbc3d852 76 // and spifi_erase() calls.
embeddedartists 0:0fdadbc3d852 77 FS_ERR_SPIFI_INTERNAL_ERROR = 0x20002, // 0x20002, Internal error in API code
embeddedartists 0:0fdadbc3d852 78 FS_ERR_SPIFI_TIMEOUT = 0x20003, // 0x20003, Time-out waiting for program or erase to begin: protection could not be removed.
embeddedartists 0:0fdadbc3d852 79 FS_ERR_SPIFI_OPERAND = 0x20004, // 0x20004, Operand error (i.e. invalid params)
embeddedartists 0:0fdadbc3d852 80 FS_ERR_SPIFI_STATUS = 0x20005, // 0x20005, Device status error
embeddedartists 0:0fdadbc3d852 81 FS_ERR_SPIFI_EXT_DEVICE_ID = 0x20006, // 0x20006, Unknown extended device ID value
embeddedartists 0:0fdadbc3d852 82 FS_ERR_SPIFI_DEVICE_ID = 0x20007, // 0x20007, Unknown device ID code
embeddedartists 0:0fdadbc3d852 83 FS_ERR_SPIFI_DEVICE_TYPE = 0x20008, // 0x20008, Unknown device type code
embeddedartists 0:0fdadbc3d852 84 FS_ERR_SPIFI_MANUFACTURER = 0x20009, // 0x20009, Unknown manufacturer code
embeddedartists 0:0fdadbc3d852 85 FS_ERR_SPIFI_INVALID_JDEC_ID = 0x2000A, // 0x2000A, No operative serial flash (JEDEC ID all zeroes or all ones)
embeddedartists 0:0fdadbc3d852 86 FS_ERR_SPIFI_ERASE_CONFLICT = 0x2000B, // 0x2000B, S_CALLER_ERASE is included in options, and erasure is required.
embeddedartists 0:0fdadbc3d852 87 FS_ERR_SPIFI_VERIFICATION, // other, Other non-zero values can occur if options selects verification.
embeddedartists 0:0fdadbc3d852 88 // They will be the address in the SPIFI memory area at which the first discrepancy was found.
embeddedartists 0:0fdadbc3d852 89 } fresult;
embeddedartists 0:0fdadbc3d852 90
embeddedartists 0:0fdadbc3d852 91 // The number of times to re-attempt a spifi_program() or spifi_erase()
embeddedartists 0:0fdadbc3d852 92 // if the last one reported a verification error.
embeddedartists 0:0fdadbc3d852 93 #define NUM_VERIFICATION_ATTEMPTS (1)
embeddedartists 0:0fdadbc3d852 94
embeddedartists 0:0fdadbc3d852 95 typedef struct
embeddedartists 0:0fdadbc3d852 96 {
embeddedartists 0:0fdadbc3d852 97 uint32_t memSize;
embeddedartists 0:0fdadbc3d852 98 uint32_t eraseBlockSize;
embeddedartists 0:0fdadbc3d852 99 uint32_t numEraseBlocks;
embeddedartists 0:0fdadbc3d852 100 uint32_t tocBlockAddr;
embeddedartists 0:0fdadbc3d852 101 uint32_t numTocs;
embeddedartists 0:0fdadbc3d852 102 uint32_t tocSizeInBytes;
embeddedartists 0:0fdadbc3d852 103 char memName[30];
embeddedartists 0:0fdadbc3d852 104 } meminfo_t;
embeddedartists 0:0fdadbc3d852 105
embeddedartists 0:0fdadbc3d852 106 typedef struct
embeddedartists 0:0fdadbc3d852 107 {
embeddedartists 0:0fdadbc3d852 108 int tocIdx;
embeddedartists 0:0fdadbc3d852 109 uint32_t size;
embeddedartists 0:0fdadbc3d852 110 uint16_t lastBlock;
embeddedartists 0:0fdadbc3d852 111 } fileHandle_t;
embeddedartists 0:0fdadbc3d852 112
embeddedartists 0:0fdadbc3d852 113 /******************************************************************************
embeddedartists 0:0fdadbc3d852 114 * Local variables
embeddedartists 0:0fdadbc3d852 115 *****************************************************************************/
embeddedartists 0:0fdadbc3d852 116
embeddedartists 8:fe3cb3fbb64e 117 static toc_entry_t* TOC = NULL;
embeddedartists 0:0fdadbc3d852 118 static int activeTOC = -1;
embeddedartists 0:0fdadbc3d852 119
embeddedartists 0:0fdadbc3d852 120 static const SPIFI_RTNS *spifi = NULL;
embeddedartists 8:fe3cb3fbb64e 121 static SPIFIobj* obj;
embeddedartists 0:0fdadbc3d852 122 static SPIFIopers opers;
embeddedartists 0:0fdadbc3d852 123
embeddedartists 0:0fdadbc3d852 124 static char addr_conflict_buff[PROG_SIZE];
embeddedartists 0:0fdadbc3d852 125
embeddedartists 0:0fdadbc3d852 126 static meminfo_t memInfo = {0,0,0,0,0,0,{0}};
embeddedartists 0:0fdadbc3d852 127
embeddedartists 0:0fdadbc3d852 128 /******************************************************************************
embeddedartists 0:0fdadbc3d852 129 * Forward Declarations of Local Functions
embeddedartists 0:0fdadbc3d852 130 *****************************************************************************/
embeddedartists 0:0fdadbc3d852 131 static fresult qspifs_init();
embeddedartists 0:0fdadbc3d852 132 static fresult qspifs_translateSpifiError(int rc);
embeddedartists 0:0fdadbc3d852 133 static fresult qspifs_readTOC(void);
embeddedartists 0:0fdadbc3d852 134 static fresult qspifs_saveTOC(void);
embeddedartists 0:0fdadbc3d852 135 static fresult qspifs_findFile(const char* filename, fileHandle_t* fh);
embeddedartists 0:0fdadbc3d852 136 static fresult qspifs_fileSize(int tocIdx, uint32_t* pSize);
embeddedartists 0:0fdadbc3d852 137 static fresult qspifs_eraseBlock(int block);
embeddedartists 0:0fdadbc3d852 138 static fresult qspifs_allocateFile(const char* filename, int neededBlocks, int* pTocIdx);
embeddedartists 0:0fdadbc3d852 139 static void qspifs_deleteFile(fileHandle_t* fh);
embeddedartists 0:0fdadbc3d852 140 static fresult qspifs_allocateSpace(fileHandle_t* fh, uint32_t size);
embeddedartists 0:0fdadbc3d852 141 static fresult qspifs_format(unsigned int minReservedBytes);
embeddedartists 0:0fdadbc3d852 142 static fresult qspifs_write(fileHandle_t* fh, const uint8_t * const pData, uint32_t size);
embeddedartists 0:0fdadbc3d852 143 static bool qspifs_startsWith(const char* prefix, const char* str);
embeddedartists 0:0fdadbc3d852 144
embeddedartists 0:0fdadbc3d852 145 /******************************************************************************
embeddedartists 0:0fdadbc3d852 146 * Local Functions
embeddedartists 0:0fdadbc3d852 147 *****************************************************************************/
embeddedartists 0:0fdadbc3d852 148
embeddedartists 0:0fdadbc3d852 149 /******************************************************************************
embeddedartists 0:0fdadbc3d852 150 *
embeddedartists 0:0fdadbc3d852 151 * Description:
embeddedartists 0:0fdadbc3d852 152 * Initializes spifi, identifies the chip and reads the file system's
embeddedartists 0:0fdadbc3d852 153 * table of content.
embeddedartists 0:0fdadbc3d852 154 *
embeddedartists 0:0fdadbc3d852 155 * Params:
embeddedartists 0:0fdadbc3d852 156 * None
embeddedartists 0:0fdadbc3d852 157 *
embeddedartists 0:0fdadbc3d852 158 * Returns:
embeddedartists 0:0fdadbc3d852 159 * FS_OK or one of the FS_ERR_* error codes
embeddedartists 0:0fdadbc3d852 160 *
embeddedartists 0:0fdadbc3d852 161 *****************************************************************************/
embeddedartists 0:0fdadbc3d852 162 static fresult qspifs_init()
embeddedartists 0:0fdadbc3d852 163 {
embeddedartists 0:0fdadbc3d852 164 if (spifi == NULL) {
embeddedartists 8:fe3cb3fbb64e 165 SPIFI::SpifiError err;
embeddedartists 8:fe3cb3fbb64e 166 err = SPIFI::instance().init();
embeddedartists 8:fe3cb3fbb64e 167 if (err != SPIFI::Ok) {
embeddedartists 8:fe3cb3fbb64e 168 spifi = NULL;
embeddedartists 8:fe3cb3fbb64e 169 return FS_ERR_SPIFI;
embeddedartists 8:fe3cb3fbb64e 170 }
embeddedartists 0:0fdadbc3d852 171
embeddedartists 8:fe3cb3fbb64e 172 SPIFI::instance().internalData(&obj, &spifi);
embeddedartists 0:0fdadbc3d852 173
embeddedartists 0:0fdadbc3d852 174 /* Make sure it is a tested flash module */
embeddedartists 8:fe3cb3fbb64e 175 switch (SPIFI::instance().device()) {
embeddedartists 8:fe3cb3fbb64e 176 case SPIFI::Spansion_S25FL032:
embeddedartists 8:fe3cb3fbb64e 177 /* For the Spansion memory the TOC occupies 256bytes and the TOC block will
embeddedartists 8:fe3cb3fbb64e 178 hold 256 TOCs. */
embeddedartists 8:fe3cb3fbb64e 179 strcpy(memInfo.memName, "Spansion S25FL032");
embeddedartists 8:fe3cb3fbb64e 180 memInfo.memSize = obj->memSize;
embeddedartists 8:fe3cb3fbb64e 181 memInfo.eraseBlockSize = 64*1024;
embeddedartists 8:fe3cb3fbb64e 182 memInfo.numEraseBlocks = memInfo.memSize / memInfo.eraseBlockSize;
embeddedartists 8:fe3cb3fbb64e 183 memInfo.tocSizeInBytes = sizeof(toc_entry_t) * memInfo.numEraseBlocks;
embeddedartists 8:fe3cb3fbb64e 184 memInfo.numTocs = memInfo.eraseBlockSize / memInfo.tocSizeInBytes;
embeddedartists 8:fe3cb3fbb64e 185 memInfo.tocBlockAddr = SPIFI_MEM_BASE + (NUM_BLOCKS * ERASE_SIZE) - (memInfo.numTocs * memInfo.tocSizeInBytes);
embeddedartists 8:fe3cb3fbb64e 186 break;
embeddedartists 0:0fdadbc3d852 187
embeddedartists 8:fe3cb3fbb64e 188 case SPIFI::Winbond_W25Q64FV:
embeddedartists 8:fe3cb3fbb64e 189 /* For the Winbond memory the TOC occupies 8192 bytes and that is bigger than
embeddedartists 8:fe3cb3fbb64e 190 one erase block (which is 4096 bytes). It is possible to either keep only
embeddedartists 8:fe3cb3fbb64e 191 one TOC or to create a couple to reduce wear on the memory. In this case
embeddedartists 8:fe3cb3fbb64e 192 the multiple TOCs option is used. */
embeddedartists 8:fe3cb3fbb64e 193 strcpy(memInfo.memName, "Winbond W25Q64FV");
embeddedartists 8:fe3cb3fbb64e 194 memInfo.memSize = obj->memSize;
embeddedartists 8:fe3cb3fbb64e 195 memInfo.eraseBlockSize = 4*1024;
embeddedartists 8:fe3cb3fbb64e 196 memInfo.numEraseBlocks = memInfo.memSize / memInfo.eraseBlockSize;
embeddedartists 8:fe3cb3fbb64e 197 memInfo.tocSizeInBytes = sizeof(toc_entry_t) * memInfo.numEraseBlocks;
embeddedartists 8:fe3cb3fbb64e 198 memInfo.numTocs = 8;
embeddedartists 8:fe3cb3fbb64e 199 memInfo.tocBlockAddr = SPIFI_MEM_BASE + (NUM_BLOCKS * ERASE_SIZE) - (memInfo.numTocs * memInfo.tocSizeInBytes);
embeddedartists 8:fe3cb3fbb64e 200 break;
embeddedartists 8:fe3cb3fbb64e 201
embeddedartists 8:fe3cb3fbb64e 202 case SPIFI::UnknownDevice:
embeddedartists 8:fe3cb3fbb64e 203 default:
embeddedartists 8:fe3cb3fbb64e 204 debug("INIT: Memory is unknown and may not work as expected\n");
embeddedartists 8:fe3cb3fbb64e 205
embeddedartists 8:fe3cb3fbb64e 206 // Asuming it has 64Kb erase blocks (i.e. same setup as the Spansion S25FL032
embeddedartists 8:fe3cb3fbb64e 207 strcpy(memInfo.memName, "Unknown - check ID");
embeddedartists 8:fe3cb3fbb64e 208 memInfo.memSize = obj->memSize;
embeddedartists 8:fe3cb3fbb64e 209 memInfo.eraseBlockSize = 64*1024;
embeddedartists 8:fe3cb3fbb64e 210 memInfo.numEraseBlocks = memInfo.memSize / memInfo.eraseBlockSize;
embeddedartists 8:fe3cb3fbb64e 211 memInfo.tocSizeInBytes = sizeof(toc_entry_t) * memInfo.numEraseBlocks;
embeddedartists 8:fe3cb3fbb64e 212 memInfo.numTocs = memInfo.eraseBlockSize / memInfo.tocSizeInBytes;
embeddedartists 8:fe3cb3fbb64e 213 memInfo.tocBlockAddr = SPIFI_MEM_BASE + (NUM_BLOCKS * ERASE_SIZE) - (memInfo.numTocs * memInfo.tocSizeInBytes);
embeddedartists 0:0fdadbc3d852 214
embeddedartists 8:fe3cb3fbb64e 215 /*
embeddedartists 8:fe3cb3fbb64e 216 * If this happens, check the manufacturer and device information
embeddedartists 8:fe3cb3fbb64e 217 * and compare with the data sheet for your chip. Also make sure
embeddedartists 8:fe3cb3fbb64e 218 * that the sector sizes are the same (i.e. 64KB) for your chip.
embeddedartists 8:fe3cb3fbb64e 219 * If everything is the same then add an exception for your chip.
embeddedartists 8:fe3cb3fbb64e 220 */
embeddedartists 8:fe3cb3fbb64e 221 break;
embeddedartists 0:0fdadbc3d852 222 }
embeddedartists 8:fe3cb3fbb64e 223
embeddedartists 0:0fdadbc3d852 224 debug_if(QSPI_DBG, "INIT: Found %dMB %s\n", memInfo.memSize/0x100000, memInfo.memName);
embeddedartists 0:0fdadbc3d852 225
embeddedartists 0:0fdadbc3d852 226 if (TOC != NULL) {
embeddedartists 0:0fdadbc3d852 227 delete TOC;
embeddedartists 0:0fdadbc3d852 228 }
embeddedartists 0:0fdadbc3d852 229 TOC = (toc_entry_t*)malloc(TOC_SIZE);
embeddedartists 0:0fdadbc3d852 230 if (TOC == NULL) {
embeddedartists 0:0fdadbc3d852 231 debug_if(QSPI_DBG, "INIT: Failed to allocate memory for TOC\n");
embeddedartists 0:0fdadbc3d852 232 spifi = NULL;
embeddedartists 0:0fdadbc3d852 233 return FS_ERR_MALLOC;
embeddedartists 0:0fdadbc3d852 234 }
embeddedartists 0:0fdadbc3d852 235 }
embeddedartists 0:0fdadbc3d852 236 if (activeTOC == -1)
embeddedartists 0:0fdadbc3d852 237 {
embeddedartists 0:0fdadbc3d852 238 return qspifs_readTOC();
embeddedartists 0:0fdadbc3d852 239 }
embeddedartists 0:0fdadbc3d852 240 return FS_OK;
embeddedartists 0:0fdadbc3d852 241 }
embeddedartists 0:0fdadbc3d852 242
embeddedartists 0:0fdadbc3d852 243 /******************************************************************************
embeddedartists 0:0fdadbc3d852 244 *
embeddedartists 0:0fdadbc3d852 245 * Description:
embeddedartists 0:0fdadbc3d852 246 * Converts the return value from one of the spifi_init(), spifi_program()
embeddedartists 0:0fdadbc3d852 247 * or spifi_erase() calls into a FS_* error code to simplify it for the
embeddedartists 0:0fdadbc3d852 248 * fs_qspi API user.
embeddedartists 0:0fdadbc3d852 249 * This function also attempts to detect the verification failure error.
embeddedartists 0:0fdadbc3d852 250 * When a verification error occurs the spifi_* functions returns the
embeddedartists 0:0fdadbc3d852 251 * conflicting address and not an error code. As this can be any address
embeddedartists 0:0fdadbc3d852 252 * it is difficult to test but this function converts it into the
embeddedartists 0:0fdadbc3d852 253 * FS_ERR_SPIFI_VERIFICATION error code which can be tested against.
embeddedartists 0:0fdadbc3d852 254 *
embeddedartists 0:0fdadbc3d852 255 * Params:
embeddedartists 0:0fdadbc3d852 256 * [in] rc - The return code from any of the spifi_* functions
embeddedartists 0:0fdadbc3d852 257 *
embeddedartists 0:0fdadbc3d852 258 * Returns:
embeddedartists 0:0fdadbc3d852 259 * FS_OK or one of the FS_ERR_* error codes
embeddedartists 0:0fdadbc3d852 260 *
embeddedartists 0:0fdadbc3d852 261 *****************************************************************************/
embeddedartists 0:0fdadbc3d852 262 static fresult qspifs_translateSpifiError(int rc)
embeddedartists 0:0fdadbc3d852 263 {
embeddedartists 0:0fdadbc3d852 264 fresult res;
embeddedartists 0:0fdadbc3d852 265 if (rc == 0)
embeddedartists 0:0fdadbc3d852 266 {
embeddedartists 0:0fdadbc3d852 267 res = FS_OK;
embeddedartists 0:0fdadbc3d852 268 }
embeddedartists 0:0fdadbc3d852 269 else if ((rc >= FS_ERR_SPIFI_INTERNAL_ERROR) && (rc <= FS_ERR_SPIFI_ERASE_CONFLICT))
embeddedartists 0:0fdadbc3d852 270 {
embeddedartists 0:0fdadbc3d852 271 // This is a known error code
embeddedartists 0:0fdadbc3d852 272 res = (fresult)rc;
embeddedartists 0:0fdadbc3d852 273 }
embeddedartists 0:0fdadbc3d852 274 else if (opers.options & (S_VERIFY_PROG | S_VERIFY_ERASE))
embeddedartists 0:0fdadbc3d852 275 {
embeddedartists 0:0fdadbc3d852 276 // As verification was selected and rc is not in the list of known
embeddedartists 0:0fdadbc3d852 277 // codes this falls into this category in the User's Manual:
embeddedartists 0:0fdadbc3d852 278 //
embeddedartists 0:0fdadbc3d852 279 // "Other non-zero values can occur if options selects verification.
embeddedartists 0:0fdadbc3d852 280 // They will be the address in the SPIFI memory area at which the
embeddedartists 0:0fdadbc3d852 281 // first discrepancy was found."
embeddedartists 0:0fdadbc3d852 282 res = FS_ERR_SPIFI_VERIFICATION;
embeddedartists 0:0fdadbc3d852 283 }
embeddedartists 0:0fdadbc3d852 284 else
embeddedartists 0:0fdadbc3d852 285 {
embeddedartists 0:0fdadbc3d852 286 // Should never happen :-) as all listed error codes are covered but
embeddedartists 0:0fdadbc3d852 287 // to be on the safe side and not interpret this as a success, a generic
embeddedartists 0:0fdadbc3d852 288 // error is set.
embeddedartists 0:0fdadbc3d852 289 res = FS_ERR_SPIFI;
embeddedartists 0:0fdadbc3d852 290 }
embeddedartists 0:0fdadbc3d852 291 return res;
embeddedartists 0:0fdadbc3d852 292 }
embeddedartists 0:0fdadbc3d852 293
embeddedartists 0:0fdadbc3d852 294 /******************************************************************************
embeddedartists 0:0fdadbc3d852 295 *
embeddedartists 0:0fdadbc3d852 296 * Description:
embeddedartists 0:0fdadbc3d852 297 * Reads the table of contents (TOC). The TOC is stored in the last erase
embeddedartists 0:0fdadbc3d852 298 * block on the QSPI flash. As the QSPI flash is not exactly RW (might
embeddedartists 0:0fdadbc3d852 299 * require erasing before writing) the TOC is relocated inside the erase
embeddedartists 0:0fdadbc3d852 300 * block everytime it is saved (see saveTOC()). The currently valid TOC
embeddedartists 0:0fdadbc3d852 301 * is allways the last one stored.
embeddedartists 0:0fdadbc3d852 302 *
embeddedartists 0:0fdadbc3d852 303 * Params:
embeddedartists 0:0fdadbc3d852 304 * None
embeddedartists 0:0fdadbc3d852 305 *
embeddedartists 0:0fdadbc3d852 306 * Returns:
embeddedartists 0:0fdadbc3d852 307 * FS_OK or one of the FS_ERR_* error codes
embeddedartists 0:0fdadbc3d852 308 *
embeddedartists 0:0fdadbc3d852 309 *****************************************************************************/
embeddedartists 0:0fdadbc3d852 310 static fresult qspifs_readTOC(void)
embeddedartists 0:0fdadbc3d852 311 {
embeddedartists 0:0fdadbc3d852 312 int i, j;
embeddedartists 0:0fdadbc3d852 313 toc_entry_t* p;
embeddedartists 0:0fdadbc3d852 314 uint8_t invalid = 0;
embeddedartists 0:0fdadbc3d852 315 int lastValid = -1;
embeddedartists 0:0fdadbc3d852 316
embeddedartists 0:0fdadbc3d852 317 // Search for the first unused TOC, keeping track of the valid
embeddedartists 0:0fdadbc3d852 318 // ones as we go.
embeddedartists 0:0fdadbc3d852 319 for (i = 0; (i < NUM_TOCS) && !invalid; i++)
embeddedartists 0:0fdadbc3d852 320 {
embeddedartists 0:0fdadbc3d852 321 p = (toc_entry_t*)(TOC_BLOCK_ADDR + i*TOC_SIZE);
embeddedartists 0:0fdadbc3d852 322 for (j = 0; j < NUM_BLOCKS; j++)
embeddedartists 0:0fdadbc3d852 323 {
embeddedartists 0:0fdadbc3d852 324 if (!VALID_TOC_ENTRY(*p) || !MANDATORY_BITS_SET(*p))
embeddedartists 0:0fdadbc3d852 325 {
embeddedartists 0:0fdadbc3d852 326 // invalid TOC entry, stop looking
embeddedartists 0:0fdadbc3d852 327 invalid = 1;
embeddedartists 0:0fdadbc3d852 328 break;
embeddedartists 0:0fdadbc3d852 329 }
embeddedartists 0:0fdadbc3d852 330 p++;
embeddedartists 0:0fdadbc3d852 331 }
embeddedartists 0:0fdadbc3d852 332
embeddedartists 0:0fdadbc3d852 333 if (!invalid)
embeddedartists 0:0fdadbc3d852 334 {
embeddedartists 0:0fdadbc3d852 335 // this TOC was ok, but perhaps there is a newer one?
embeddedartists 0:0fdadbc3d852 336 lastValid = i;
embeddedartists 0:0fdadbc3d852 337 }
embeddedartists 0:0fdadbc3d852 338 }
embeddedartists 0:0fdadbc3d852 339
embeddedartists 0:0fdadbc3d852 340 if (lastValid == -1)
embeddedartists 0:0fdadbc3d852 341 {
embeddedartists 0:0fdadbc3d852 342 // no valid TOCs on the flash
embeddedartists 0:0fdadbc3d852 343 return FS_ERR_NOT_FORMATTED;
embeddedartists 0:0fdadbc3d852 344 }
embeddedartists 0:0fdadbc3d852 345 else
embeddedartists 0:0fdadbc3d852 346 {
embeddedartists 0:0fdadbc3d852 347 // previous entry was ok so use that
embeddedartists 0:0fdadbc3d852 348 activeTOC = lastValid;
embeddedartists 0:0fdadbc3d852 349 p = (toc_entry_t*)(TOC_BLOCK_ADDR + activeTOC*TOC_SIZE);
embeddedartists 0:0fdadbc3d852 350 memcpy(TOC, p, TOC_SIZE);
embeddedartists 0:0fdadbc3d852 351 return FS_OK;
embeddedartists 0:0fdadbc3d852 352 }
embeddedartists 0:0fdadbc3d852 353 }
embeddedartists 0:0fdadbc3d852 354
embeddedartists 0:0fdadbc3d852 355 /******************************************************************************
embeddedartists 0:0fdadbc3d852 356 *
embeddedartists 0:0fdadbc3d852 357 * Description:
embeddedartists 0:0fdadbc3d852 358 * Saves the table of contents (TOC). The TOC is stored in the last erase
embeddedartists 0:0fdadbc3d852 359 * block on the QSPI flash. As the QSPI flash is not exactly RW (might
embeddedartists 0:0fdadbc3d852 360 * require erasing before writing) the TOC is first compared with what is
embeddedartists 0:0fdadbc3d852 361 * stored in the QSPI flash and if there are no changes or all changes
embeddedartists 0:0fdadbc3d852 362 * only require bit changes 1->0 then the current TOC can be overwritten.
embeddedartists 0:0fdadbc3d852 363 * If bit value changes 0->1 are required then the current stored TOC
embeddedartists 0:0fdadbc3d852 364 * cannot be overwritten and the new TOC is instead stored in the next
embeddedartists 0:0fdadbc3d852 365 * available space. If the entire last block is filled then it is erased
embeddedartists 0:0fdadbc3d852 366 * and the new TOC is placed at the start of it.
embeddedartists 0:0fdadbc3d852 367 *
embeddedartists 0:0fdadbc3d852 368 * Params:
embeddedartists 0:0fdadbc3d852 369 * None
embeddedartists 0:0fdadbc3d852 370 *
embeddedartists 0:0fdadbc3d852 371 * Returns:
embeddedartists 0:0fdadbc3d852 372 * FS_OK or one of the FS_ERR_* error codes
embeddedartists 0:0fdadbc3d852 373 *
embeddedartists 0:0fdadbc3d852 374 *****************************************************************************/
embeddedartists 0:0fdadbc3d852 375 static fresult qspifs_saveTOC(void)
embeddedartists 0:0fdadbc3d852 376 {
embeddedartists 0:0fdadbc3d852 377 int i, rc = 0;
embeddedartists 0:0fdadbc3d852 378 uint32_t* pSrc;
embeddedartists 0:0fdadbc3d852 379 uint32_t* pDest;
embeddedartists 0:0fdadbc3d852 380 uint32_t tmp;
embeddedartists 0:0fdadbc3d852 381 uint8_t identical = 1;
embeddedartists 0:0fdadbc3d852 382
embeddedartists 0:0fdadbc3d852 383 // active TOC same as the one we want to save?
embeddedartists 0:0fdadbc3d852 384 pSrc = (uint32_t*)TOC;
embeddedartists 0:0fdadbc3d852 385 pDest = (uint32_t*)(TOC_BLOCK_ADDR + activeTOC*TOC_SIZE);
embeddedartists 0:0fdadbc3d852 386 for (i = 0; i < NUM_TOC_ENTRIES; i++)
embeddedartists 0:0fdadbc3d852 387 {
embeddedartists 0:0fdadbc3d852 388 if (*pSrc != *pDest)
embeddedartists 0:0fdadbc3d852 389 {
embeddedartists 0:0fdadbc3d852 390 identical = 0;
embeddedartists 0:0fdadbc3d852 391 tmp = ((*pDest) ^ (*pSrc)) & (*pSrc);
embeddedartists 0:0fdadbc3d852 392 if (tmp > 0)
embeddedartists 0:0fdadbc3d852 393 {
embeddedartists 0:0fdadbc3d852 394 // found a change that contains 0->1 bit modification which
embeddedartists 0:0fdadbc3d852 395 // requires erasing or a new location
embeddedartists 0:0fdadbc3d852 396 activeTOC = (activeTOC + 1)%NUM_TOCS;
embeddedartists 0:0fdadbc3d852 397 if (activeTOC == 0)
embeddedartists 0:0fdadbc3d852 398 {
embeddedartists 0:0fdadbc3d852 399 // no more free TOCs so an erase is needed
embeddedartists 0:0fdadbc3d852 400 #if 0
embeddedartists 0:0fdadbc3d852 401 opers.options &= ~S_CALLER_ERASE;
embeddedartists 0:0fdadbc3d852 402 opers.options |= S_FORCE_ERASE;
embeddedartists 0:0fdadbc3d852 403 #else
embeddedartists 0:0fdadbc3d852 404 opers.dest = (char *) TOC_BLOCK_ADDR;
embeddedartists 0:0fdadbc3d852 405 opers.length = TOC_SIZE * NUM_TOCS;
embeddedartists 0:0fdadbc3d852 406 opers.scratch = NULL;
embeddedartists 0:0fdadbc3d852 407 opers.protect = 0;
embeddedartists 0:0fdadbc3d852 408 opers.options = S_NO_VERIFY;
embeddedartists 8:fe3cb3fbb64e 409 rc = spifi->spifi_erase(obj, &opers);
embeddedartists 0:0fdadbc3d852 410 if (rc) {
embeddedartists 0:0fdadbc3d852 411 return qspifs_translateSpifiError(rc);
embeddedartists 0:0fdadbc3d852 412 }
embeddedartists 0:0fdadbc3d852 413 #endif
embeddedartists 0:0fdadbc3d852 414 }
embeddedartists 0:0fdadbc3d852 415 break;
embeddedartists 0:0fdadbc3d852 416 }
embeddedartists 0:0fdadbc3d852 417 }
embeddedartists 0:0fdadbc3d852 418 pSrc++;
embeddedartists 0:0fdadbc3d852 419 pDest++;
embeddedartists 0:0fdadbc3d852 420 }
embeddedartists 0:0fdadbc3d852 421
embeddedartists 0:0fdadbc3d852 422 if (!identical)
embeddedartists 0:0fdadbc3d852 423 {
embeddedartists 0:0fdadbc3d852 424 opers.length = FS_MIN(TOC_SIZE, PROG_SIZE);
embeddedartists 0:0fdadbc3d852 425 opers.scratch = NULL;
embeddedartists 0:0fdadbc3d852 426 opers.protect = 0;
embeddedartists 0:0fdadbc3d852 427 opers.options = S_VERIFY_PROG | S_CALLER_ERASE;
embeddedartists 0:0fdadbc3d852 428 for (int i = 0; i < (TOC_SIZE / PROG_SIZE); i++)
embeddedartists 0:0fdadbc3d852 429 {
embeddedartists 0:0fdadbc3d852 430 opers.dest = (char *)(TOC_BLOCK_ADDR + activeTOC*TOC_SIZE + i*PROG_SIZE);
embeddedartists 8:fe3cb3fbb64e 431 rc = spifi->spifi_program(obj, ((char*)TOC)+i*PROG_SIZE, &opers);
embeddedartists 0:0fdadbc3d852 432 if (rc)
embeddedartists 0:0fdadbc3d852 433 {
embeddedartists 0:0fdadbc3d852 434 break;
embeddedartists 0:0fdadbc3d852 435 }
embeddedartists 0:0fdadbc3d852 436 }
embeddedartists 0:0fdadbc3d852 437 return qspifs_translateSpifiError(rc);
embeddedartists 0:0fdadbc3d852 438 }
embeddedartists 0:0fdadbc3d852 439 return FS_OK;
embeddedartists 0:0fdadbc3d852 440 }
embeddedartists 0:0fdadbc3d852 441
embeddedartists 0:0fdadbc3d852 442 /******************************************************************************
embeddedartists 0:0fdadbc3d852 443 *
embeddedartists 0:0fdadbc3d852 444 * Description:
embeddedartists 0:0fdadbc3d852 445 * Searches the file system for a file with the specified name and
embeddedartists 0:0fdadbc3d852 446 * (if found) returns the file's position in the TOC.
embeddedartists 0:0fdadbc3d852 447 *
embeddedartists 0:0fdadbc3d852 448 * Note that the content of fh is only valid if FS_OK is returned.
embeddedartists 0:0fdadbc3d852 449 *
embeddedartists 0:0fdadbc3d852 450 * Params:
embeddedartists 0:0fdadbc3d852 451 * [in] filename - The name of the file to find
embeddedartists 0:0fdadbc3d852 452 * [out] fh - The handle with the file information
embeddedartists 0:0fdadbc3d852 453 *
embeddedartists 0:0fdadbc3d852 454 * Returns:
embeddedartists 0:0fdadbc3d852 455 * FS_OK or one of the FS_ERR_* error codes
embeddedartists 0:0fdadbc3d852 456 *
embeddedartists 0:0fdadbc3d852 457 *****************************************************************************/
embeddedartists 0:0fdadbc3d852 458 static fresult qspifs_findFile(const char* filename, fileHandle_t* fh)
embeddedartists 0:0fdadbc3d852 459 {
embeddedartists 0:0fdadbc3d852 460 int i;
embeddedartists 0:0fdadbc3d852 461
embeddedartists 0:0fdadbc3d852 462 if (activeTOC == -1)
embeddedartists 0:0fdadbc3d852 463 {
embeddedartists 0:0fdadbc3d852 464 return FS_ERR_NOT_FORMATTED;
embeddedartists 0:0fdadbc3d852 465 }
embeddedartists 0:0fdadbc3d852 466
embeddedartists 0:0fdadbc3d852 467 // Look at all blocks except for the reserved ones
embeddedartists 0:0fdadbc3d852 468 for (i = 0; i < NUM_BLOCKS; i++)
embeddedartists 0:0fdadbc3d852 469 {
embeddedartists 0:0fdadbc3d852 470 if (TOC_IS_FILE(TOC[i]) && !TOC_IS_RESERVED(TOC[i]))
embeddedartists 0:0fdadbc3d852 471 {
embeddedartists 0:0fdadbc3d852 472 // found a file, see if name matches
embeddedartists 0:0fdadbc3d852 473 char* p = (char*)(SPIFI_MEM_BASE + i*ERASE_SIZE);
embeddedartists 0:0fdadbc3d852 474 if (strncmp(filename, p, HEADER_FNAME_LEN) == 0)
embeddedartists 0:0fdadbc3d852 475 {
embeddedartists 0:0fdadbc3d852 476 // found a matching name
embeddedartists 0:0fdadbc3d852 477 fh->tocIdx = i;
embeddedartists 0:0fdadbc3d852 478 fresult res = qspifs_fileSize(fh->tocIdx, &fh->size);
embeddedartists 0:0fdadbc3d852 479 if (res == FS_OK) {
embeddedartists 0:0fdadbc3d852 480 fh->lastBlock = fh->tocIdx + ((fh->size + HEADER_LEN)/ ERASE_SIZE);
embeddedartists 0:0fdadbc3d852 481 }
embeddedartists 0:0fdadbc3d852 482 return FS_OK;
embeddedartists 0:0fdadbc3d852 483 }
embeddedartists 0:0fdadbc3d852 484 }
embeddedartists 0:0fdadbc3d852 485 }
embeddedartists 0:0fdadbc3d852 486 return FS_ERR_NO_FILE;
embeddedartists 0:0fdadbc3d852 487 }
embeddedartists 0:0fdadbc3d852 488
embeddedartists 0:0fdadbc3d852 489 /******************************************************************************
embeddedartists 0:0fdadbc3d852 490 *
embeddedartists 0:0fdadbc3d852 491 * Description:
embeddedartists 0:0fdadbc3d852 492 * Calculates and returns the file's size.
embeddedartists 0:0fdadbc3d852 493 *
embeddedartists 0:0fdadbc3d852 494 * Note that the content of pSize is only valid if FS_OK is returned.
embeddedartists 0:0fdadbc3d852 495 *
embeddedartists 0:0fdadbc3d852 496 * Params:
embeddedartists 0:0fdadbc3d852 497 * [in] tocIdx - The file's position in the TOC
embeddedartists 0:0fdadbc3d852 498 * [out] pSize - The file's size
embeddedartists 0:0fdadbc3d852 499 *
embeddedartists 0:0fdadbc3d852 500 * Returns:
embeddedartists 0:0fdadbc3d852 501 * FS_OK or one of the FS_ERR_* error codes
embeddedartists 0:0fdadbc3d852 502 *
embeddedartists 0:0fdadbc3d852 503 *****************************************************************************/
embeddedartists 0:0fdadbc3d852 504 static fresult qspifs_fileSize(int tocIdx, uint32_t* pSize)
embeddedartists 0:0fdadbc3d852 505 {
embeddedartists 0:0fdadbc3d852 506 int i;
embeddedartists 0:0fdadbc3d852 507
embeddedartists 0:0fdadbc3d852 508 if (tocIdx < 0 || tocIdx > NUM_BLOCKS || !TOC_IS_FILE(TOC[tocIdx]))
embeddedartists 0:0fdadbc3d852 509 {
embeddedartists 0:0fdadbc3d852 510 return FS_ERR_NO_FILE;
embeddedartists 0:0fdadbc3d852 511 }
embeddedartists 0:0fdadbc3d852 512
embeddedartists 0:0fdadbc3d852 513 *pSize = 0;
embeddedartists 0:0fdadbc3d852 514
embeddedartists 0:0fdadbc3d852 515 // A file is always stored in sequential blocks so start with the files
embeddedartists 0:0fdadbc3d852 516 // first block and as long as it is full continue sum up the occupied
embeddedartists 0:0fdadbc3d852 517 // block sizes. As soon as a non-full block is found that must be the
embeddedartists 0:0fdadbc3d852 518 // file's last block.
embeddedartists 0:0fdadbc3d852 519 for (i = tocIdx; i < NUM_BLOCKS; i++)
embeddedartists 0:0fdadbc3d852 520 {
embeddedartists 0:0fdadbc3d852 521 *pSize += FILESIZE(TOC[i]);
embeddedartists 0:0fdadbc3d852 522 if (FILESIZE(TOC[i]) < ERASE_SIZE)
embeddedartists 0:0fdadbc3d852 523 {
embeddedartists 0:0fdadbc3d852 524 // last block in chain
embeddedartists 0:0fdadbc3d852 525 break;
embeddedartists 0:0fdadbc3d852 526 }
embeddedartists 0:0fdadbc3d852 527 }
embeddedartists 0:0fdadbc3d852 528
embeddedartists 0:0fdadbc3d852 529 // Remove the filename header from the file's size
embeddedartists 0:0fdadbc3d852 530 *pSize -= HEADER_LEN;
embeddedartists 0:0fdadbc3d852 531
embeddedartists 0:0fdadbc3d852 532 return FS_OK;
embeddedartists 0:0fdadbc3d852 533 }
embeddedartists 0:0fdadbc3d852 534
embeddedartists 0:0fdadbc3d852 535 /******************************************************************************
embeddedartists 0:0fdadbc3d852 536 *
embeddedartists 0:0fdadbc3d852 537 * Description:
embeddedartists 0:0fdadbc3d852 538 * Erases everything in one block on the QSPI flash.
embeddedartists 0:0fdadbc3d852 539 *
embeddedartists 0:0fdadbc3d852 540 * Params:
embeddedartists 0:0fdadbc3d852 541 * [in] block - The block's number
embeddedartists 0:0fdadbc3d852 542 *
embeddedartists 0:0fdadbc3d852 543 * Returns:
embeddedartists 0:0fdadbc3d852 544 * FS_OK or one of the FS_ERR_* error codes
embeddedartists 0:0fdadbc3d852 545 *
embeddedartists 0:0fdadbc3d852 546 *****************************************************************************/
embeddedartists 0:0fdadbc3d852 547 static fresult qspifs_eraseBlock(int block)
embeddedartists 0:0fdadbc3d852 548 {
embeddedartists 0:0fdadbc3d852 549 opers.dest = (char *)(block * ERASE_SIZE);
embeddedartists 0:0fdadbc3d852 550 opers.length = ERASE_SIZE;
embeddedartists 0:0fdadbc3d852 551 opers.scratch = NULL;
embeddedartists 0:0fdadbc3d852 552 opers.protect = 0;
embeddedartists 0:0fdadbc3d852 553 opers.options = S_NO_VERIFY;
embeddedartists 8:fe3cb3fbb64e 554 return qspifs_translateSpifiError(spifi->spifi_erase (obj, &opers));
embeddedartists 0:0fdadbc3d852 555 }
embeddedartists 0:0fdadbc3d852 556
embeddedartists 0:0fdadbc3d852 557 /******************************************************************************
embeddedartists 0:0fdadbc3d852 558 *
embeddedartists 0:0fdadbc3d852 559 * Description:
embeddedartists 0:0fdadbc3d852 560 * Creates a new file if there is enough space for it on the file system.
embeddedartists 0:0fdadbc3d852 561 * The TOC is searched for a unused sequence of blocks of at least the
embeddedartists 0:0fdadbc3d852 562 * needed size. That block is marked as used and the file's name is stored
embeddedartists 0:0fdadbc3d852 563 * in the first bytes of the file's first block.
embeddedartists 0:0fdadbc3d852 564 *
embeddedartists 0:0fdadbc3d852 565 * Note: The filename will not be tested for uniqueness.
embeddedartists 0:0fdadbc3d852 566 * Note: The value of pTocIdx will only be valid if FS_OK is returned.
embeddedartists 0:0fdadbc3d852 567 *
embeddedartists 0:0fdadbc3d852 568 * Params:
embeddedartists 0:0fdadbc3d852 569 * [in] filename - The name of the new file
embeddedartists 0:0fdadbc3d852 570 * [in] neededBlocks - The number of blocks (in sequence) to allocate
embeddedartists 0:0fdadbc3d852 571 * [out] pTocIdx - The new file's position in the TOC
embeddedartists 0:0fdadbc3d852 572 *
embeddedartists 0:0fdadbc3d852 573 * Returns:
embeddedartists 0:0fdadbc3d852 574 * FS_OK or one of the FS_ERR_* error codes
embeddedartists 0:0fdadbc3d852 575 *
embeddedartists 0:0fdadbc3d852 576 *****************************************************************************/
embeddedartists 0:0fdadbc3d852 577 static fresult qspifs_allocateFile(const char* filename, int neededBlocks, int* pTocIdx)
embeddedartists 0:0fdadbc3d852 578 {
embeddedartists 0:0fdadbc3d852 579 int i, rc;
embeddedartists 0:0fdadbc3d852 580
embeddedartists 0:0fdadbc3d852 581 if (activeTOC == -1)
embeddedartists 0:0fdadbc3d852 582 {
embeddedartists 0:0fdadbc3d852 583 return FS_ERR_NOT_FORMATTED;
embeddedartists 0:0fdadbc3d852 584 }
embeddedartists 0:0fdadbc3d852 585
embeddedartists 0:0fdadbc3d852 586 // Look at all blocks except for the reserved ones
embeddedartists 0:0fdadbc3d852 587 for (i = 0; i < NUM_BLOCKS; i++)
embeddedartists 0:0fdadbc3d852 588 {
embeddedartists 0:0fdadbc3d852 589 //TODO: Improve search to use gaps to avoid having to move files
embeddedartists 0:0fdadbc3d852 590 // that are written to
embeddedartists 0:0fdadbc3d852 591 if (!USED_TOC_ENTRY(TOC[i]) && !TOC_IS_RESERVED(TOC[i]))
embeddedartists 0:0fdadbc3d852 592 {
embeddedartists 0:0fdadbc3d852 593 int j;
embeddedartists 0:0fdadbc3d852 594 for (j = 1; j < neededBlocks; j++)
embeddedartists 0:0fdadbc3d852 595 {
embeddedartists 0:0fdadbc3d852 596 if (USED_TOC_ENTRY(TOC[i+j]) || TOC_IS_RESERVED(TOC[i+j]))
embeddedartists 0:0fdadbc3d852 597 {
embeddedartists 0:0fdadbc3d852 598 // not enough free blocks in sequence, skip past these
embeddedartists 0:0fdadbc3d852 599 // tested entries and continue searching
embeddedartists 0:0fdadbc3d852 600 i += j;
embeddedartists 0:0fdadbc3d852 601 break;
embeddedartists 0:0fdadbc3d852 602 }
embeddedartists 0:0fdadbc3d852 603 }
embeddedartists 0:0fdadbc3d852 604
embeddedartists 0:0fdadbc3d852 605 if (j == neededBlocks)
embeddedartists 0:0fdadbc3d852 606 {
embeddedartists 0:0fdadbc3d852 607 const char* pSrc = filename;
embeddedartists 0:0fdadbc3d852 608 if (IS_ADDR_IN_SPIFI(filename))
embeddedartists 0:0fdadbc3d852 609 {
embeddedartists 0:0fdadbc3d852 610 // The SPIFI ROM driver cannot write data from SPIFI into
embeddedartists 0:0fdadbc3d852 611 // SPIFI (i.e. cannot read and write at the same time).
embeddedartists 0:0fdadbc3d852 612 // The workaround is to copy the source data into a buffer
embeddedartists 0:0fdadbc3d852 613 // in local memory and use that as source for the write
embeddedartists 0:0fdadbc3d852 614 // instead.
embeddedartists 0:0fdadbc3d852 615 memcpy(addr_conflict_buff, filename, strlen(filename)+1);
embeddedartists 0:0fdadbc3d852 616 pSrc = addr_conflict_buff;
embeddedartists 0:0fdadbc3d852 617 }
embeddedartists 0:0fdadbc3d852 618
embeddedartists 0:0fdadbc3d852 619 // Erase the new file's first block and store the filename at the
embeddedartists 0:0fdadbc3d852 620 // start of it
embeddedartists 0:0fdadbc3d852 621 opers.length = strlen(pSrc)+1;
embeddedartists 0:0fdadbc3d852 622 opers.scratch = NULL;
embeddedartists 0:0fdadbc3d852 623 opers.protect = 0;
embeddedartists 0:0fdadbc3d852 624 opers.options = S_VERIFY_PROG | S_FORCE_ERASE;// S_CALLER_ERASE;
embeddedartists 0:0fdadbc3d852 625 opers.dest = (char *)(i*ERASE_SIZE);
embeddedartists 8:fe3cb3fbb64e 626 rc = spifi->spifi_program(obj, (char*)pSrc, &opers);
embeddedartists 0:0fdadbc3d852 627 if (rc) {
embeddedartists 0:0fdadbc3d852 628 return qspifs_translateSpifiError(rc);
embeddedartists 0:0fdadbc3d852 629 }
embeddedartists 0:0fdadbc3d852 630
embeddedartists 0:0fdadbc3d852 631 TOC[i] &= ~(TOC_VALID_MASK | TOC_USED_MASK | TOC_FILE_MASK | TOC_FSIZE_MASK);
embeddedartists 0:0fdadbc3d852 632 TOC[i] |= HEADER_LEN;
embeddedartists 0:0fdadbc3d852 633
embeddedartists 0:0fdadbc3d852 634 *pTocIdx = i;
embeddedartists 0:0fdadbc3d852 635 return FS_OK;
embeddedartists 0:0fdadbc3d852 636 }
embeddedartists 0:0fdadbc3d852 637 }
embeddedartists 0:0fdadbc3d852 638 }
embeddedartists 0:0fdadbc3d852 639 return FS_ERR_DISK_FULL;
embeddedartists 0:0fdadbc3d852 640 }
embeddedartists 0:0fdadbc3d852 641
embeddedartists 0:0fdadbc3d852 642 /******************************************************************************
embeddedartists 0:0fdadbc3d852 643 *
embeddedartists 0:0fdadbc3d852 644 * Description:
embeddedartists 0:0fdadbc3d852 645 * Deletes the specified file by marking all its blocks as unused in
embeddedartists 0:0fdadbc3d852 646 * the TOC.
embeddedartists 0:0fdadbc3d852 647 *
embeddedartists 0:0fdadbc3d852 648 * Note: The deleted blocks are not erased here - that is done when they
embeddedartists 0:0fdadbc3d852 649 * are allocated the next time.
embeddedartists 0:0fdadbc3d852 650 *
embeddedartists 0:0fdadbc3d852 651 * Params:
embeddedartists 0:0fdadbc3d852 652 * [in] fh - The file handle with information about what to delete
embeddedartists 0:0fdadbc3d852 653 *
embeddedartists 0:0fdadbc3d852 654 * Returns:
embeddedartists 0:0fdadbc3d852 655 * None
embeddedartists 0:0fdadbc3d852 656 *
embeddedartists 0:0fdadbc3d852 657 *****************************************************************************/
embeddedartists 0:0fdadbc3d852 658 static void qspifs_deleteFile(fileHandle_t* fh)
embeddedartists 0:0fdadbc3d852 659 {
embeddedartists 0:0fdadbc3d852 660 int i;
embeddedartists 0:0fdadbc3d852 661
embeddedartists 0:0fdadbc3d852 662 for (i = fh->lastBlock; i >= fh->tocIdx; i--)
embeddedartists 0:0fdadbc3d852 663 {
embeddedartists 0:0fdadbc3d852 664 TOC[i] = ~TOC_VALID_MASK;
embeddedartists 0:0fdadbc3d852 665 }
embeddedartists 0:0fdadbc3d852 666 }
embeddedartists 0:0fdadbc3d852 667
embeddedartists 0:0fdadbc3d852 668 /******************************************************************************
embeddedartists 0:0fdadbc3d852 669 *
embeddedartists 0:0fdadbc3d852 670 * Description:
embeddedartists 0:0fdadbc3d852 671 * Ensures that the specified file can grow to the wanted size.
embeddedartists 0:0fdadbc3d852 672 * If the file size will increase enough to need one or more new blocks
embeddedartists 0:0fdadbc3d852 673 * and there isn't enough space then an attempt is made to move the
embeddedartists 0:0fdadbc3d852 674 * current file to a large enough space somewhere else.
embeddedartists 0:0fdadbc3d852 675 *
embeddedartists 0:0fdadbc3d852 676 * If there are more free block(s) at the end of the file then it is not
embeddedartists 0:0fdadbc3d852 677 * moved and instead those blocks are marked as used.
embeddedartists 0:0fdadbc3d852 678 *
embeddedartists 0:0fdadbc3d852 679 * Note: The filename will not be tested for uniqueness.
embeddedartists 0:0fdadbc3d852 680 * Note: The value of pTocIdx will only be valid if FS_OK is returned.
embeddedartists 0:0fdadbc3d852 681 *
embeddedartists 0:0fdadbc3d852 682 * Params:
embeddedartists 0:0fdadbc3d852 683 * [in/out] fh - The current file handle, might be updated after a move
embeddedartists 0:0fdadbc3d852 684 * [in] size - The wanted new size
embeddedartists 0:0fdadbc3d852 685 *
embeddedartists 0:0fdadbc3d852 686 * Returns:
embeddedartists 0:0fdadbc3d852 687 * FS_OK or one of the FS_ERR_* error codes
embeddedartists 0:0fdadbc3d852 688 *
embeddedartists 0:0fdadbc3d852 689 *****************************************************************************/
embeddedartists 0:0fdadbc3d852 690 static fresult qspifs_allocateSpace(fileHandle_t* fh, uint32_t size)
embeddedartists 0:0fdadbc3d852 691 {
embeddedartists 0:0fdadbc3d852 692 uint16_t oldNumBlocks = (fh->size + HEADER_LEN) / ERASE_SIZE;
embeddedartists 0:0fdadbc3d852 693 uint16_t newNumBlocks = (fh->size + HEADER_LEN + size) / ERASE_SIZE;
embeddedartists 0:0fdadbc3d852 694 uint16_t numNeeded = newNumBlocks - oldNumBlocks;
embeddedartists 0:0fdadbc3d852 695 fresult res = FS_OK;
embeddedartists 0:0fdadbc3d852 696
embeddedartists 0:0fdadbc3d852 697 if (numNeeded > 0)
embeddedartists 0:0fdadbc3d852 698 {
embeddedartists 0:0fdadbc3d852 699 uint16_t i;
embeddedartists 0:0fdadbc3d852 700 for (i = 0; i < numNeeded; i++)
embeddedartists 0:0fdadbc3d852 701 {
embeddedartists 0:0fdadbc3d852 702 if (USED_TOC_ENTRY(TOC[fh->tocIdx + oldNumBlocks + 1 + i]) ||
embeddedartists 0:0fdadbc3d852 703 TOC_IS_RESERVED(TOC[fh->tocIdx + oldNumBlocks + 1 + i]))
embeddedartists 0:0fdadbc3d852 704 {
embeddedartists 0:0fdadbc3d852 705 fileHandle_t fhNew;
embeddedartists 0:0fdadbc3d852 706
embeddedartists 0:0fdadbc3d852 707 // have to move the chain
embeddedartists 0:0fdadbc3d852 708 char* filename = (char*)(SPIFI_MEM_BASE + fh->tocIdx * ERASE_SIZE);
embeddedartists 0:0fdadbc3d852 709 res = qspifs_allocateFile(filename, newNumBlocks, &(fhNew.tocIdx));
embeddedartists 0:0fdadbc3d852 710 if (res == FS_OK)
embeddedartists 0:0fdadbc3d852 711 {
embeddedartists 0:0fdadbc3d852 712 // copy data
embeddedartists 0:0fdadbc3d852 713 fhNew.lastBlock = fhNew.tocIdx;
embeddedartists 0:0fdadbc3d852 714 fhNew.size = 0;
embeddedartists 0:0fdadbc3d852 715 res = qspifs_write(&fhNew, (uint8_t*)(SPIFI_MEM_BASE + fh->tocIdx * ERASE_SIZE + HEADER_LEN), fh->size);
embeddedartists 0:0fdadbc3d852 716 }
embeddedartists 0:0fdadbc3d852 717 if (res == FS_OK)
embeddedartists 0:0fdadbc3d852 718 {
embeddedartists 0:0fdadbc3d852 719 // remove old entries
embeddedartists 0:0fdadbc3d852 720 qspifs_deleteFile(fh);
embeddedartists 0:0fdadbc3d852 721
embeddedartists 0:0fdadbc3d852 722 // modify old handle to point to new information
embeddedartists 0:0fdadbc3d852 723 fh->lastBlock = fhNew.lastBlock;
embeddedartists 0:0fdadbc3d852 724 fh->size = fhNew.size;
embeddedartists 0:0fdadbc3d852 725 fh->tocIdx = fhNew.tocIdx;
embeddedartists 0:0fdadbc3d852 726 }
embeddedartists 0:0fdadbc3d852 727 if (res != FS_OK)
embeddedartists 0:0fdadbc3d852 728 {
embeddedartists 0:0fdadbc3d852 729 // not possible to relocate the file => abort
embeddedartists 0:0fdadbc3d852 730 return res;
embeddedartists 0:0fdadbc3d852 731 }
embeddedartists 0:0fdadbc3d852 732 break;
embeddedartists 0:0fdadbc3d852 733 }
embeddedartists 0:0fdadbc3d852 734 }
embeddedartists 0:0fdadbc3d852 735
embeddedartists 0:0fdadbc3d852 736 // have space that is unused, so mark as used
embeddedartists 0:0fdadbc3d852 737 for (i = 0; i < numNeeded; i++)
embeddedartists 0:0fdadbc3d852 738 {
embeddedartists 0:0fdadbc3d852 739 int tocIdx = fh->tocIdx + oldNumBlocks + 1 + i;
embeddedartists 0:0fdadbc3d852 740 TOC[tocIdx] &= ~TOC_USED_MASK;
embeddedartists 0:0fdadbc3d852 741 qspifs_eraseBlock(tocIdx);
embeddedartists 0:0fdadbc3d852 742 }
embeddedartists 0:0fdadbc3d852 743 }
embeddedartists 0:0fdadbc3d852 744
embeddedartists 0:0fdadbc3d852 745 return res;
embeddedartists 0:0fdadbc3d852 746 }
embeddedartists 0:0fdadbc3d852 747
embeddedartists 0:0fdadbc3d852 748 /******************************************************************************
embeddedartists 0:0fdadbc3d852 749 *
embeddedartists 0:0fdadbc3d852 750 * Description:
embeddedartists 0:0fdadbc3d852 751 * Adds a file system to the QSPI flash. The entire flash will be erase
embeddedartists 0:0fdadbc3d852 752 * except for the minReservedBytes first bytes. That reserved area (rounded
embeddedartists 0:0fdadbc3d852 753 * up to the closest even multiple of the erase block size) can be used
embeddedartists 0:0fdadbc3d852 754 * for anything and will never be touched by the file system. That area is
embeddedartists 0:0fdadbc3d852 755 * typically used for executing programs from when the internal flash is
embeddedartists 0:0fdadbc3d852 756 * full.
embeddedartists 0:0fdadbc3d852 757 *
embeddedartists 0:0fdadbc3d852 758 * The file system will have a table of content (TOC) placed at the start
embeddedartists 0:0fdadbc3d852 759 * of the last erase block on the flash.
embeddedartists 0:0fdadbc3d852 760 *
embeddedartists 0:0fdadbc3d852 761 * Params:
embeddedartists 0:0fdadbc3d852 762 * [in] minReservedBytes - The number of bytes to ignore at the start of
embeddedartists 0:0fdadbc3d852 763 * the flash.
embeddedartists 0:0fdadbc3d852 764 *
embeddedartists 0:0fdadbc3d852 765 * Returns:
embeddedartists 0:0fdadbc3d852 766 * FS_OK on success or one of the FS_ERR_* on failure
embeddedartists 0:0fdadbc3d852 767 *
embeddedartists 0:0fdadbc3d852 768 *****************************************************************************/
embeddedartists 0:0fdadbc3d852 769 static fresult qspifs_format(unsigned int minReservedBytes)
embeddedartists 0:0fdadbc3d852 770 {
embeddedartists 0:0fdadbc3d852 771 int i, rc;
embeddedartists 0:0fdadbc3d852 772 int numReserved = 0;
embeddedartists 0:0fdadbc3d852 773
embeddedartists 0:0fdadbc3d852 774 if (minReservedBytes > 0) {
embeddedartists 0:0fdadbc3d852 775 numReserved = (minReservedBytes + ERASE_SIZE - 1) / ERASE_SIZE;
embeddedartists 0:0fdadbc3d852 776 if (numReserved >= (NUM_BLOCKS - 2)) {
embeddedartists 0:0fdadbc3d852 777 // Too many of the erase blocks are reserved - not even room for one file
embeddedartists 0:0fdadbc3d852 778 return FS_ERR_INVALID_PARAM;
embeddedartists 0:0fdadbc3d852 779 }
embeddedartists 0:0fdadbc3d852 780 }
embeddedartists 0:0fdadbc3d852 781
embeddedartists 0:0fdadbc3d852 782 #if 0 // works but is really slow
embeddedartists 0:0fdadbc3d852 783 // Erase all non-reserved blocks
embeddedartists 0:0fdadbc3d852 784 for (i = numReserved; i < NUM_BLOCKS; i++) {
embeddedartists 0:0fdadbc3d852 785 opers.dest = (char *) (i * ERASE_SIZE);
embeddedartists 0:0fdadbc3d852 786 opers.length = ERASE_SIZE;
embeddedartists 0:0fdadbc3d852 787 opers.scratch = NULL;
embeddedartists 0:0fdadbc3d852 788 opers.protect = 0;
embeddedartists 0:0fdadbc3d852 789 opers.options = S_NO_VERIFY;
embeddedartists 0:0fdadbc3d852 790 rc = spifi->spifi_erase(&obj, &opers);
embeddedartists 0:0fdadbc3d852 791 if (rc) {
embeddedartists 0:0fdadbc3d852 792 return qspifs_translateSpifiError(rc);
embeddedartists 0:0fdadbc3d852 793 }
embeddedartists 0:0fdadbc3d852 794 }
embeddedartists 0:0fdadbc3d852 795 #else
embeddedartists 0:0fdadbc3d852 796 // Erase all non-reserved blocks
embeddedartists 0:0fdadbc3d852 797 opers.dest = (char *) (numReserved * ERASE_SIZE);
embeddedartists 0:0fdadbc3d852 798 opers.length = MEM_SIZE - (numReserved * ERASE_SIZE);
embeddedartists 0:0fdadbc3d852 799 opers.scratch = NULL;
embeddedartists 0:0fdadbc3d852 800 opers.protect = 0;
embeddedartists 0:0fdadbc3d852 801 opers.options = S_NO_VERIFY;
embeddedartists 8:fe3cb3fbb64e 802 rc = spifi->spifi_erase(obj, &opers);
embeddedartists 0:0fdadbc3d852 803 if (rc) {
embeddedartists 0:0fdadbc3d852 804 return qspifs_translateSpifiError(rc);
embeddedartists 0:0fdadbc3d852 805 }
embeddedartists 0:0fdadbc3d852 806 #endif
embeddedartists 0:0fdadbc3d852 807
embeddedartists 0:0fdadbc3d852 808 // Create the TOC, mark requested blocks as reserved and mark the TOC's
embeddedartists 0:0fdadbc3d852 809 // block(s) as reserved as well.
embeddedartists 0:0fdadbc3d852 810 for (i = 0; i < numReserved; i++) {
embeddedartists 0:0fdadbc3d852 811 TOC[i] = ~(TOC_VALID_MASK | TOC_RESERVED_MASK);
embeddedartists 0:0fdadbc3d852 812 }
embeddedartists 0:0fdadbc3d852 813 for (; i < (NUM_BLOCKS - NUM_TOC_BLOCKS); i++) {
embeddedartists 0:0fdadbc3d852 814 TOC[i] = ~TOC_VALID_MASK;
embeddedartists 0:0fdadbc3d852 815 }
embeddedartists 0:0fdadbc3d852 816 for (; i < NUM_BLOCKS; i++) {
embeddedartists 0:0fdadbc3d852 817 TOC[i] = ~(TOC_VALID_MASK | TOC_RESERVED_MASK);
embeddedartists 0:0fdadbc3d852 818 }
embeddedartists 0:0fdadbc3d852 819
embeddedartists 0:0fdadbc3d852 820 // Save the TOC in the last block
embeddedartists 0:0fdadbc3d852 821 activeTOC = 0;
embeddedartists 0:0fdadbc3d852 822 fresult res = qspifs_saveTOC();
embeddedartists 0:0fdadbc3d852 823 if (res != FS_OK) {
embeddedartists 0:0fdadbc3d852 824 activeTOC = -1;
embeddedartists 0:0fdadbc3d852 825 return res;
embeddedartists 0:0fdadbc3d852 826 }
embeddedartists 0:0fdadbc3d852 827 // opers.dest = (char *) TOC_BLOCK_ADDR;
embeddedartists 0:0fdadbc3d852 828 // opers.length = TOC_SIZE;
embeddedartists 0:0fdadbc3d852 829 // opers.scratch = NULL;
embeddedartists 0:0fdadbc3d852 830 // opers.protect = 0;
embeddedartists 0:0fdadbc3d852 831 // opers.options = S_VERIFY_PROG | S_CALLER_ERASE;
embeddedartists 0:0fdadbc3d852 832 // rc = spifi->spifi_program(&obj, (char*) TOC, &opers);
embeddedartists 0:0fdadbc3d852 833 // if (rc) {
embeddedartists 0:0fdadbc3d852 834 // return qspifs_translateSpifiError(rc);
embeddedartists 0:0fdadbc3d852 835 // }
embeddedartists 0:0fdadbc3d852 836
embeddedartists 0:0fdadbc3d852 837 // Read back TOC to be sure it worked
embeddedartists 0:0fdadbc3d852 838 return qspifs_readTOC();
embeddedartists 0:0fdadbc3d852 839 }
embeddedartists 0:0fdadbc3d852 840
embeddedartists 0:0fdadbc3d852 841 /******************************************************************************
embeddedartists 0:0fdadbc3d852 842 *
embeddedartists 0:0fdadbc3d852 843 * Description:
embeddedartists 0:0fdadbc3d852 844 * Deletes all files on the file system. This is a "quick format" that
embeddedartists 0:0fdadbc3d852 845 * leaves all blocks untouched and only modifies the TOC. Any reserved
embeddedartists 0:0fdadbc3d852 846 * blocks are kept reserved.
embeddedartists 0:0fdadbc3d852 847 *
embeddedartists 0:0fdadbc3d852 848 * The purpose of this function is to make it easy to clear the file system
embeddedartists 0:0fdadbc3d852 849 * without going through a time consuming complete erase every time.
embeddedartists 0:0fdadbc3d852 850 *
embeddedartists 0:0fdadbc3d852 851 * Params:
embeddedartists 0:0fdadbc3d852 852 * None
embeddedartists 0:0fdadbc3d852 853 *
embeddedartists 0:0fdadbc3d852 854 * Returns:
embeddedartists 0:0fdadbc3d852 855 * FS_OK on success or one of the FS_ERR_* on failure
embeddedartists 0:0fdadbc3d852 856 *
embeddedartists 0:0fdadbc3d852 857 *****************************************************************************/
embeddedartists 0:0fdadbc3d852 858 // static fresult qspifs_deleteAllFiles(void)
embeddedartists 0:0fdadbc3d852 859 // {
embeddedartists 0:0fdadbc3d852 860 // for (int i = 0; i < NUM_BLOCKS; i++)
embeddedartists 0:0fdadbc3d852 861 // {
embeddedartists 0:0fdadbc3d852 862 // if (!TOC_IS_RESERVED(TOC[i])) {
embeddedartists 0:0fdadbc3d852 863 // TOC[i] = ~TOC_VALID_MASK;
embeddedartists 0:0fdadbc3d852 864 // }
embeddedartists 0:0fdadbc3d852 865 // }
embeddedartists 0:0fdadbc3d852 866 //
embeddedartists 0:0fdadbc3d852 867 // return qspifs_saveTOC();
embeddedartists 0:0fdadbc3d852 868 // }
embeddedartists 0:0fdadbc3d852 869
embeddedartists 0:0fdadbc3d852 870 /******************************************************************************
embeddedartists 0:0fdadbc3d852 871 *
embeddedartists 0:0fdadbc3d852 872 * Description:
embeddedartists 0:0fdadbc3d852 873 * Appends the data to the end of the file.
embeddedartists 0:0fdadbc3d852 874 *
embeddedartists 0:0fdadbc3d852 875 * Params:
embeddedartists 0:0fdadbc3d852 876 * [in] fh - The handle to the file as returned from fs_open_append()
embeddedartists 0:0fdadbc3d852 877 * [in] pData - The data to save
embeddedartists 0:0fdadbc3d852 878 * [in] size - Number of bytes to save
embeddedartists 0:0fdadbc3d852 879 *
embeddedartists 0:0fdadbc3d852 880 * Returns:
embeddedartists 0:0fdadbc3d852 881 * FS_OK on success or one of the FS_ERR_* on failure
embeddedartists 0:0fdadbc3d852 882 *
embeddedartists 0:0fdadbc3d852 883 *****************************************************************************/
embeddedartists 0:0fdadbc3d852 884 static fresult qspifs_write(fileHandle_t* fh, const uint8_t * const pData, uint32_t size)
embeddedartists 0:0fdadbc3d852 885 {
embeddedartists 0:0fdadbc3d852 886 uint32_t left = size;
embeddedartists 0:0fdadbc3d852 887 const uint8_t* pSrc = pData;
embeddedartists 0:0fdadbc3d852 888 int rc, i;
embeddedartists 0:0fdadbc3d852 889 fresult res;
embeddedartists 0:0fdadbc3d852 890 int failed_attempts = 0;
embeddedartists 0:0fdadbc3d852 891
embeddedartists 0:0fdadbc3d852 892 do {
embeddedartists 0:0fdadbc3d852 893 res = qspifs_allocateSpace(fh, size);
embeddedartists 0:0fdadbc3d852 894 if (res != FS_OK) {
embeddedartists 0:0fdadbc3d852 895 break;
embeddedartists 0:0fdadbc3d852 896 }
embeddedartists 0:0fdadbc3d852 897
embeddedartists 0:0fdadbc3d852 898 opers.dest = (char *) (SPIFI_MEM_BASE + fh->tocIdx * ERASE_SIZE
embeddedartists 0:0fdadbc3d852 899 + HEADER_LEN + fh->size);
embeddedartists 0:0fdadbc3d852 900 opers.scratch = NULL;
embeddedartists 0:0fdadbc3d852 901 opers.protect = 0;
embeddedartists 0:0fdadbc3d852 902 opers.options = S_VERIFY_PROG; // | S_FORCE_ERASE;
embeddedartists 0:0fdadbc3d852 903
embeddedartists 0:0fdadbc3d852 904 while ((res == FS_OK) && (left > 0)) {
embeddedartists 0:0fdadbc3d852 905 if (left >= PROG_SIZE) {
embeddedartists 0:0fdadbc3d852 906 opers.length = PROG_SIZE;
embeddedartists 0:0fdadbc3d852 907 } else {
embeddedartists 0:0fdadbc3d852 908 opers.length = left;
embeddedartists 0:0fdadbc3d852 909 }
embeddedartists 0:0fdadbc3d852 910 if (IS_ADDR_IN_SPIFI(pData)) {
embeddedartists 0:0fdadbc3d852 911 memcpy(addr_conflict_buff, pSrc, opers.length);
embeddedartists 8:fe3cb3fbb64e 912 rc = spifi->spifi_program(obj, addr_conflict_buff, &opers);
embeddedartists 0:0fdadbc3d852 913 } else {
embeddedartists 8:fe3cb3fbb64e 914 rc = spifi->spifi_program(obj, (char*) pSrc, &opers);
embeddedartists 0:0fdadbc3d852 915 }
embeddedartists 0:0fdadbc3d852 916 res = qspifs_translateSpifiError(rc);
embeddedartists 0:0fdadbc3d852 917 if ((res == FS_ERR_SPIFI_VERIFICATION)
embeddedartists 0:0fdadbc3d852 918 && (++failed_attempts <= NUM_VERIFICATION_ATTEMPTS)) {
embeddedartists 0:0fdadbc3d852 919 // The verification process failed.
embeddedartists 0:0fdadbc3d852 920 // In all the observed occasions re-running the exact same
embeddedartists 0:0fdadbc3d852 921 // spifi_program command again yielded a 0 as a return value
embeddedartists 0:0fdadbc3d852 922 // the second time.
embeddedartists 0:0fdadbc3d852 923 // The quick'N'dirty fix is to re-run that program instruction
embeddedartists 0:0fdadbc3d852 924 // NUM_VERIFICATION_ATTEMPTS more time(s) when this happens.
embeddedartists 0:0fdadbc3d852 925 res = FS_OK;
embeddedartists 0:0fdadbc3d852 926 continue;
embeddedartists 0:0fdadbc3d852 927 }
embeddedartists 0:0fdadbc3d852 928 if (res != FS_OK) {
embeddedartists 0:0fdadbc3d852 929 // Got an error but cannot exit this function here as parts of the data
embeddedartists 0:0fdadbc3d852 930 // (previous loops?) may have been written so the TOC must be updated.
embeddedartists 0:0fdadbc3d852 931 break;
embeddedartists 0:0fdadbc3d852 932 }
embeddedartists 0:0fdadbc3d852 933 pSrc += opers.length;
embeddedartists 0:0fdadbc3d852 934 opers.dest += opers.length;
embeddedartists 0:0fdadbc3d852 935 left -= opers.length;
embeddedartists 0:0fdadbc3d852 936 failed_attempts = 0;
embeddedartists 0:0fdadbc3d852 937 }
embeddedartists 0:0fdadbc3d852 938
embeddedartists 0:0fdadbc3d852 939 // update file information
embeddedartists 0:0fdadbc3d852 940 fh->size = fh->size + size - left;
embeddedartists 0:0fdadbc3d852 941 fh->lastBlock = fh->tocIdx + ((fh->size + HEADER_LEN)/ ERASE_SIZE);
embeddedartists 0:0fdadbc3d852 942 left = fh->size + HEADER_LEN;
embeddedartists 0:0fdadbc3d852 943 for (i = 0; i <= (fh->lastBlock - fh->tocIdx); i++) {
embeddedartists 0:0fdadbc3d852 944 TOC[fh->tocIdx + i] &= ~TOC_FSIZE_MASK;
embeddedartists 0:0fdadbc3d852 945 TOC[fh->tocIdx + i] |= FS_MIN(ERASE_SIZE, left);
embeddedartists 0:0fdadbc3d852 946 left -= FILESIZE(TOC[fh->tocIdx + i]);
embeddedartists 0:0fdadbc3d852 947 }
embeddedartists 0:0fdadbc3d852 948
embeddedartists 0:0fdadbc3d852 949 if (res == FS_OK) {
embeddedartists 0:0fdadbc3d852 950 res = qspifs_saveTOC();
embeddedartists 0:0fdadbc3d852 951 } else {
embeddedartists 0:0fdadbc3d852 952 // Want to save the TOC but not overwrite the previous error with
embeddedartists 0:0fdadbc3d852 953 // a possibly successful TOC saving thus making it seem like there
embeddedartists 0:0fdadbc3d852 954 // was no error
embeddedartists 0:0fdadbc3d852 955 qspifs_saveTOC();
embeddedartists 0:0fdadbc3d852 956 }
embeddedartists 0:0fdadbc3d852 957 } while (0);
embeddedartists 0:0fdadbc3d852 958
embeddedartists 0:0fdadbc3d852 959 return res;
embeddedartists 0:0fdadbc3d852 960 }
embeddedartists 0:0fdadbc3d852 961
embeddedartists 0:0fdadbc3d852 962 /******************************************************************************
embeddedartists 0:0fdadbc3d852 963 *
embeddedartists 0:0fdadbc3d852 964 * Description:
embeddedartists 0:0fdadbc3d852 965 * Tests if str starts with prefix. A prefix of NULL or an empty string
embeddedartists 0:0fdadbc3d852 966 * results in a positive result regardless of the content of str.
embeddedartists 0:0fdadbc3d852 967 *
embeddedartists 0:0fdadbc3d852 968 * Params:
embeddedartists 0:0fdadbc3d852 969 * [in] prefix - The prefix to look for
embeddedartists 0:0fdadbc3d852 970 * [in] str - The string to search for prefix
embeddedartists 0:0fdadbc3d852 971 *
embeddedartists 0:0fdadbc3d852 972 * Returns:
embeddedartists 0:0fdadbc3d852 973 * True if the specified string starts with prefix
embeddedartists 0:0fdadbc3d852 974 *
embeddedartists 0:0fdadbc3d852 975 *****************************************************************************/
embeddedartists 0:0fdadbc3d852 976 static bool qspifs_startsWith(const char* prefix, const char* str)
embeddedartists 0:0fdadbc3d852 977 {
embeddedartists 0:0fdadbc3d852 978 const char* pA = prefix;
embeddedartists 0:0fdadbc3d852 979 const char* pB = str;
embeddedartists 0:0fdadbc3d852 980
embeddedartists 0:0fdadbc3d852 981 if (pA == NULL)
embeddedartists 0:0fdadbc3d852 982 {
embeddedartists 0:0fdadbc3d852 983 return true;
embeddedartists 0:0fdadbc3d852 984 }
embeddedartists 0:0fdadbc3d852 985 for (; *pA != '\0'; pA++, pB++)
embeddedartists 0:0fdadbc3d852 986 {
embeddedartists 0:0fdadbc3d852 987 if (*pB != *pA)
embeddedartists 0:0fdadbc3d852 988 {
embeddedartists 0:0fdadbc3d852 989 return false;
embeddedartists 0:0fdadbc3d852 990 }
embeddedartists 0:0fdadbc3d852 991 }
embeddedartists 0:0fdadbc3d852 992
embeddedartists 0:0fdadbc3d852 993 return true;
embeddedartists 0:0fdadbc3d852 994 }
embeddedartists 0:0fdadbc3d852 995
embeddedartists 0:0fdadbc3d852 996 /******************************************************************************
embeddedartists 0:0fdadbc3d852 997 * Class Declarations
embeddedartists 0:0fdadbc3d852 998 *****************************************************************************/
embeddedartists 0:0fdadbc3d852 999
embeddedartists 0:0fdadbc3d852 1000 class QSPIFileHandle : public FileHandle {
embeddedartists 0:0fdadbc3d852 1001
embeddedartists 0:0fdadbc3d852 1002 public:
embeddedartists 0:0fdadbc3d852 1003 QSPIFileHandle(fileHandle_t* handle, int flags);
embeddedartists 0:0fdadbc3d852 1004
embeddedartists 0:0fdadbc3d852 1005 virtual int close();
embeddedartists 0:0fdadbc3d852 1006
embeddedartists 0:0fdadbc3d852 1007 virtual ssize_t write(const void *buffer, size_t length);
embeddedartists 0:0fdadbc3d852 1008
embeddedartists 0:0fdadbc3d852 1009 virtual ssize_t read(void *buffer, size_t length);
embeddedartists 0:0fdadbc3d852 1010
embeddedartists 0:0fdadbc3d852 1011 virtual int isatty();
embeddedartists 0:0fdadbc3d852 1012
embeddedartists 0:0fdadbc3d852 1013 virtual off_t lseek(off_t position, int whence);
embeddedartists 0:0fdadbc3d852 1014
embeddedartists 0:0fdadbc3d852 1015 virtual int fsync();
embeddedartists 0:0fdadbc3d852 1016
embeddedartists 0:0fdadbc3d852 1017 virtual off_t flen();
embeddedartists 0:0fdadbc3d852 1018
embeddedartists 0:0fdadbc3d852 1019 protected:
embeddedartists 0:0fdadbc3d852 1020
embeddedartists 0:0fdadbc3d852 1021 fileHandle_t fh;
embeddedartists 0:0fdadbc3d852 1022 bool allowReading;
embeddedartists 0:0fdadbc3d852 1023 bool allowWriting;
embeddedartists 0:0fdadbc3d852 1024 uint32_t pos;
embeddedartists 0:0fdadbc3d852 1025 };
embeddedartists 0:0fdadbc3d852 1026
embeddedartists 0:0fdadbc3d852 1027 class QSPIDirHandle : public DirHandle {
embeddedartists 0:0fdadbc3d852 1028
embeddedartists 0:0fdadbc3d852 1029 public:
embeddedartists 0:0fdadbc3d852 1030 static QSPIDirHandle* openDir(const char* dirname);
embeddedartists 0:0fdadbc3d852 1031
embeddedartists 0:0fdadbc3d852 1032 virtual ~QSPIDirHandle();
embeddedartists 0:0fdadbc3d852 1033
embeddedartists 0:0fdadbc3d852 1034 virtual int closedir();
embeddedartists 0:0fdadbc3d852 1035 virtual struct dirent *readdir();
embeddedartists 0:0fdadbc3d852 1036 virtual void rewinddir();
embeddedartists 0:0fdadbc3d852 1037
embeddedartists 0:0fdadbc3d852 1038 private:
embeddedartists 0:0fdadbc3d852 1039 QSPIDirHandle(const char* dirname);
embeddedartists 0:0fdadbc3d852 1040
embeddedartists 0:0fdadbc3d852 1041 int findFileWithPrefix(const char* prefix, int startTOCIdx, int maxTOCIdx) const;
embeddedartists 0:0fdadbc3d852 1042
embeddedartists 0:0fdadbc3d852 1043 protected:
embeddedartists 0:0fdadbc3d852 1044
embeddedartists 0:0fdadbc3d852 1045 char* dirname;
embeddedartists 0:0fdadbc3d852 1046 int nextTocIdx;
embeddedartists 0:0fdadbc3d852 1047
embeddedartists 0:0fdadbc3d852 1048 bool isRoot;
embeddedartists 0:0fdadbc3d852 1049
embeddedartists 0:0fdadbc3d852 1050 struct dirent cur_entry;
embeddedartists 0:0fdadbc3d852 1051 };
embeddedartists 0:0fdadbc3d852 1052
embeddedartists 0:0fdadbc3d852 1053 /******************************************************************************
embeddedartists 0:0fdadbc3d852 1054 * Class Implementations
embeddedartists 0:0fdadbc3d852 1055 *****************************************************************************/
embeddedartists 0:0fdadbc3d852 1056
embeddedartists 0:0fdadbc3d852 1057 QSPIFileHandle::QSPIFileHandle(fileHandle_t* handle, int flags)
embeddedartists 0:0fdadbc3d852 1058 {
embeddedartists 0:0fdadbc3d852 1059 fh = *handle;
embeddedartists 0:0fdadbc3d852 1060 int accmode = (flags & O_ACCMODE);
embeddedartists 0:0fdadbc3d852 1061 allowReading = (accmode == O_RDONLY) || (accmode == O_RDWR);
embeddedartists 0:0fdadbc3d852 1062 allowWriting = (accmode == O_WRONLY) || (accmode == O_RDWR) || (flags & O_APPEND);
embeddedartists 0:0fdadbc3d852 1063 pos = 0;
embeddedartists 0:0fdadbc3d852 1064 }
embeddedartists 0:0fdadbc3d852 1065
embeddedartists 0:0fdadbc3d852 1066 int QSPIFileHandle::close()
embeddedartists 0:0fdadbc3d852 1067 {
embeddedartists 0:0fdadbc3d852 1068 delete this;
embeddedartists 0:0fdadbc3d852 1069 return 0;
embeddedartists 0:0fdadbc3d852 1070 }
embeddedartists 0:0fdadbc3d852 1071
embeddedartists 0:0fdadbc3d852 1072 ssize_t QSPIFileHandle::write(const void *buffer, size_t length)
embeddedartists 0:0fdadbc3d852 1073 {
embeddedartists 0:0fdadbc3d852 1074 if (!allowWriting) {
embeddedartists 0:0fdadbc3d852 1075 return -1;
embeddedartists 0:0fdadbc3d852 1076 }
embeddedartists 0:0fdadbc3d852 1077 fresult res = qspifs_write(&fh, (const uint8_t*)buffer, length);
embeddedartists 0:0fdadbc3d852 1078 if (res == FS_OK) {
embeddedartists 0:0fdadbc3d852 1079 // A write is always 'append' in this file system so the file
embeddedartists 0:0fdadbc3d852 1080 // position is always end of file after a write
embeddedartists 0:0fdadbc3d852 1081 pos = fh.size;
embeddedartists 0:0fdadbc3d852 1082 return length;
embeddedartists 0:0fdadbc3d852 1083 }
embeddedartists 0:0fdadbc3d852 1084 return -1;
embeddedartists 0:0fdadbc3d852 1085 }
embeddedartists 0:0fdadbc3d852 1086
embeddedartists 0:0fdadbc3d852 1087 ssize_t QSPIFileHandle::read(void *buffer, size_t length)
embeddedartists 0:0fdadbc3d852 1088 {
embeddedartists 0:0fdadbc3d852 1089 if (!allowReading) {
embeddedartists 0:0fdadbc3d852 1090 return -1;
embeddedartists 0:0fdadbc3d852 1091 }
embeddedartists 0:0fdadbc3d852 1092 if (pos >= fh.size) {
embeddedartists 0:0fdadbc3d852 1093 return 0;
embeddedartists 0:0fdadbc3d852 1094 }
embeddedartists 0:0fdadbc3d852 1095 uint32_t len = FS_MIN(length, fh.size - pos);
embeddedartists 0:0fdadbc3d852 1096 const char* pData = (const char*)(SPIFI_MEM_BASE + fh.tocIdx*ERASE_SIZE + HEADER_LEN + pos);
embeddedartists 0:0fdadbc3d852 1097 memcpy(buffer, pData, len);
embeddedartists 0:0fdadbc3d852 1098 pos += len;
embeddedartists 0:0fdadbc3d852 1099 return len;
embeddedartists 0:0fdadbc3d852 1100 }
embeddedartists 0:0fdadbc3d852 1101
embeddedartists 0:0fdadbc3d852 1102 int QSPIFileHandle::isatty()
embeddedartists 0:0fdadbc3d852 1103 {
embeddedartists 0:0fdadbc3d852 1104 return 0;
embeddedartists 0:0fdadbc3d852 1105 }
embeddedartists 0:0fdadbc3d852 1106
embeddedartists 0:0fdadbc3d852 1107 off_t QSPIFileHandle::lseek(off_t position, int whence)
embeddedartists 0:0fdadbc3d852 1108 {
embeddedartists 0:0fdadbc3d852 1109 switch (whence) {
embeddedartists 0:0fdadbc3d852 1110 case SEEK_SET:
embeddedartists 0:0fdadbc3d852 1111 pos = position;
embeddedartists 0:0fdadbc3d852 1112 break;
embeddedartists 0:0fdadbc3d852 1113
embeddedartists 0:0fdadbc3d852 1114 case SEEK_CUR:
embeddedartists 0:0fdadbc3d852 1115 pos += position;
embeddedartists 0:0fdadbc3d852 1116 break;
embeddedartists 0:0fdadbc3d852 1117
embeddedartists 0:0fdadbc3d852 1118 case SEEK_END:
embeddedartists 0:0fdadbc3d852 1119 pos = fh.size + position;
embeddedartists 0:0fdadbc3d852 1120 break;
embeddedartists 0:0fdadbc3d852 1121
embeddedartists 0:0fdadbc3d852 1122 default:
embeddedartists 0:0fdadbc3d852 1123 return -1;
embeddedartists 0:0fdadbc3d852 1124 }
embeddedartists 0:0fdadbc3d852 1125 return pos;
embeddedartists 0:0fdadbc3d852 1126 }
embeddedartists 0:0fdadbc3d852 1127
embeddedartists 0:0fdadbc3d852 1128 int QSPIFileHandle::fsync()
embeddedartists 0:0fdadbc3d852 1129 {
embeddedartists 0:0fdadbc3d852 1130 return 0; // always synced
embeddedartists 0:0fdadbc3d852 1131 }
embeddedartists 0:0fdadbc3d852 1132
embeddedartists 0:0fdadbc3d852 1133 off_t QSPIFileHandle::flen()
embeddedartists 0:0fdadbc3d852 1134 {
embeddedartists 0:0fdadbc3d852 1135 return fh.size;
embeddedartists 0:0fdadbc3d852 1136 }
embeddedartists 0:0fdadbc3d852 1137
embeddedartists 0:0fdadbc3d852 1138 QSPIDirHandle::QSPIDirHandle(const char* dirname) {
embeddedartists 0:0fdadbc3d852 1139 size_t len = strlen(dirname);
embeddedartists 0:0fdadbc3d852 1140 this->dirname = (char*)malloc(len + 2); // null termination and possible ending '/'
embeddedartists 0:0fdadbc3d852 1141 if (this->dirname != NULL) {
embeddedartists 0:0fdadbc3d852 1142 if (len == 0 || ((len == 1) && (dirname[0] == '/'))) {
embeddedartists 0:0fdadbc3d852 1143 isRoot = true;
embeddedartists 0:0fdadbc3d852 1144 this->dirname[0] = '\0';
embeddedartists 0:0fdadbc3d852 1145 } else {
embeddedartists 0:0fdadbc3d852 1146 isRoot = false;
embeddedartists 0:0fdadbc3d852 1147 memcpy(this->dirname, dirname, len+1);
embeddedartists 0:0fdadbc3d852 1148 if (dirname[len - 1] != '/') {
embeddedartists 0:0fdadbc3d852 1149 this->dirname[len] = '/';
embeddedartists 0:0fdadbc3d852 1150 this->dirname[len+1] = '\0';
embeddedartists 0:0fdadbc3d852 1151 }
embeddedartists 0:0fdadbc3d852 1152 }
embeddedartists 0:0fdadbc3d852 1153 cur_entry.d_name[HEADER_FNAME_STRLEN] = '\0';
embeddedartists 0:0fdadbc3d852 1154 rewinddir();
embeddedartists 0:0fdadbc3d852 1155 }
embeddedartists 0:0fdadbc3d852 1156 }
embeddedartists 0:0fdadbc3d852 1157
embeddedartists 0:0fdadbc3d852 1158 QSPIDirHandle::~QSPIDirHandle()
embeddedartists 0:0fdadbc3d852 1159 {
embeddedartists 0:0fdadbc3d852 1160 if (dirname != NULL) {
embeddedartists 0:0fdadbc3d852 1161 delete dirname;
embeddedartists 0:0fdadbc3d852 1162 dirname = NULL;
embeddedartists 0:0fdadbc3d852 1163 }
embeddedartists 0:0fdadbc3d852 1164 }
embeddedartists 0:0fdadbc3d852 1165
embeddedartists 0:0fdadbc3d852 1166 QSPIDirHandle* QSPIDirHandle::openDir(const char* dirname)
embeddedartists 0:0fdadbc3d852 1167 {
embeddedartists 0:0fdadbc3d852 1168 QSPIDirHandle* d = new QSPIDirHandle(dirname);
embeddedartists 0:0fdadbc3d852 1169 if (d->dirname == NULL) {
embeddedartists 0:0fdadbc3d852 1170 // failed to allocate memory for the folder name
embeddedartists 0:0fdadbc3d852 1171 delete d;
embeddedartists 0:0fdadbc3d852 1172 d = NULL;
embeddedartists 0:0fdadbc3d852 1173 } else if (!d->isRoot) {
embeddedartists 0:0fdadbc3d852 1174 if (d->findFileWithPrefix(d->dirname, 0, NUM_BLOCKS) == NUM_BLOCKS) {
embeddedartists 0:0fdadbc3d852 1175 // There are no files in this directory, i.e. it does not exist
embeddedartists 0:0fdadbc3d852 1176 delete d;
embeddedartists 0:0fdadbc3d852 1177 d = NULL;
embeddedartists 0:0fdadbc3d852 1178 }
embeddedartists 0:0fdadbc3d852 1179 }
embeddedartists 0:0fdadbc3d852 1180 return d;
embeddedartists 0:0fdadbc3d852 1181 }
embeddedartists 0:0fdadbc3d852 1182
embeddedartists 0:0fdadbc3d852 1183 int QSPIDirHandle::closedir() {
embeddedartists 0:0fdadbc3d852 1184 delete this;
embeddedartists 0:0fdadbc3d852 1185 return 0;
embeddedartists 0:0fdadbc3d852 1186 }
embeddedartists 0:0fdadbc3d852 1187
embeddedartists 0:0fdadbc3d852 1188 int QSPIDirHandle::findFileWithPrefix(const char* prefix, int startTOCIdx, int maxTOCIdx) const
embeddedartists 0:0fdadbc3d852 1189 {
embeddedartists 0:0fdadbc3d852 1190 for (int i = startTOCIdx; i < maxTOCIdx; i++) {
embeddedartists 0:0fdadbc3d852 1191 if (TOC_IS_FILE(TOC[i])) {
embeddedartists 0:0fdadbc3d852 1192 const char* filename = (const char*) (SPIFI_MEM_BASE + i * ERASE_SIZE);
embeddedartists 0:0fdadbc3d852 1193 if (qspifs_startsWith(prefix, filename)) {
embeddedartists 0:0fdadbc3d852 1194 return i;
embeddedartists 0:0fdadbc3d852 1195 }
embeddedartists 0:0fdadbc3d852 1196 }
embeddedartists 0:0fdadbc3d852 1197 }
embeddedartists 0:0fdadbc3d852 1198 return NUM_BLOCKS; // no match
embeddedartists 0:0fdadbc3d852 1199 }
embeddedartists 0:0fdadbc3d852 1200
embeddedartists 0:0fdadbc3d852 1201
embeddedartists 0:0fdadbc3d852 1202 struct dirent *QSPIDirHandle::readdir() {
embeddedartists 0:0fdadbc3d852 1203 if (nextTocIdx < NUM_BLOCKS) {
embeddedartists 0:0fdadbc3d852 1204 for (int i = nextTocIdx; i < NUM_BLOCKS; i++) {
embeddedartists 0:0fdadbc3d852 1205 int possible = findFileWithPrefix(dirname, i, NUM_BLOCKS);
embeddedartists 0:0fdadbc3d852 1206 if (possible < NUM_BLOCKS) {
embeddedartists 0:0fdadbc3d852 1207 const char* fullfilename = (const char*) (SPIFI_MEM_BASE + possible * ERASE_SIZE);
embeddedartists 0:0fdadbc3d852 1208 const char* filename = fullfilename + strlen(dirname);
embeddedartists 0:0fdadbc3d852 1209
embeddedartists 0:0fdadbc3d852 1210 if (strchr(filename, '/') == NULL) {
embeddedartists 0:0fdadbc3d852 1211 // file is not in any sub folder so it is truly in the wanted dir
embeddedartists 0:0fdadbc3d852 1212 nextTocIdx = possible + 1;
embeddedartists 0:0fdadbc3d852 1213 strcpy(cur_entry.d_name, filename);
embeddedartists 0:0fdadbc3d852 1214 return &cur_entry;
embeddedartists 0:0fdadbc3d852 1215 }
embeddedartists 0:0fdadbc3d852 1216
embeddedartists 0:0fdadbc3d852 1217 // this is a file in a subfolder and should not be reported,
embeddedartists 0:0fdadbc3d852 1218 // but the folder name itself should
embeddedartists 0:0fdadbc3d852 1219 strcpy(cur_entry.d_name, fullfilename);
embeddedartists 0:0fdadbc3d852 1220 char* pSlash = strchr(cur_entry.d_name + strlen(dirname), '/');
embeddedartists 0:0fdadbc3d852 1221 pSlash++;
embeddedartists 0:0fdadbc3d852 1222 *pSlash = '\0';
embeddedartists 0:0fdadbc3d852 1223
embeddedartists 0:0fdadbc3d852 1224 // now that cur_entry.d_name contains the folder's complete
embeddedartists 0:0fdadbc3d852 1225 // path with a trailing '/', see if it has occurred earlier
embeddedartists 0:0fdadbc3d852 1226 int older = findFileWithPrefix(cur_entry.d_name, 0, i);
embeddedartists 0:0fdadbc3d852 1227 if (older < possible) {
embeddedartists 0:0fdadbc3d852 1228 // already reported, move past this entry
embeddedartists 0:0fdadbc3d852 1229 i = possible;
embeddedartists 0:0fdadbc3d852 1230 } else {
embeddedartists 0:0fdadbc3d852 1231 // found a new subfolder
embeddedartists 0:0fdadbc3d852 1232 nextTocIdx = possible + 1;
embeddedartists 0:0fdadbc3d852 1233 strcpy(cur_entry.d_name, filename);
embeddedartists 0:0fdadbc3d852 1234 char* pSlash = strchr(cur_entry.d_name, '/');
embeddedartists 0:0fdadbc3d852 1235 // pSlash++; //with ++ the returned dir name is "mydir/" without ++ "mydir" is returned
embeddedartists 0:0fdadbc3d852 1236 *pSlash = '\0';
embeddedartists 0:0fdadbc3d852 1237 return &cur_entry;
embeddedartists 0:0fdadbc3d852 1238 }
embeddedartists 0:0fdadbc3d852 1239 }
embeddedartists 0:0fdadbc3d852 1240 }
embeddedartists 0:0fdadbc3d852 1241 }
embeddedartists 0:0fdadbc3d852 1242 return NULL;
embeddedartists 0:0fdadbc3d852 1243 }
embeddedartists 0:0fdadbc3d852 1244
embeddedartists 0:0fdadbc3d852 1245 void QSPIDirHandle::rewinddir() {
embeddedartists 0:0fdadbc3d852 1246 nextTocIdx = 0;
embeddedartists 0:0fdadbc3d852 1247 }
embeddedartists 0:0fdadbc3d852 1248
embeddedartists 0:0fdadbc3d852 1249
embeddedartists 0:0fdadbc3d852 1250 QSPIFileSystem::QSPIFileSystem(const char* name) :
embeddedartists 0:0fdadbc3d852 1251 FileSystemLike(name) {
embeddedartists 0:0fdadbc3d852 1252
embeddedartists 0:0fdadbc3d852 1253 activeTOC = -1;
embeddedartists 0:0fdadbc3d852 1254 spifi = NULL;
embeddedartists 0:0fdadbc3d852 1255 }
embeddedartists 0:0fdadbc3d852 1256
embeddedartists 0:0fdadbc3d852 1257 // All modes are supported but:
embeddedartists 0:0fdadbc3d852 1258 //
embeddedartists 0:0fdadbc3d852 1259 // 1) All writes are treated as appends
embeddedartists 0:0fdadbc3d852 1260 // 2) Truncation is only to size 0, i.e. effectively a delete
embeddedartists 0:0fdadbc3d852 1261 // 3) File position operations work like this:
embeddedartists 0:0fdadbc3d852 1262 // ReadOnly - dictates where to read from
embeddedartists 0:0fdadbc3d852 1263 // WriteOnly - ignored, writes are always at the end
embeddedartists 0:0fdadbc3d852 1264 // ReadWrite - dictates where to read from, writes ignore it but
embeddedartists 0:0fdadbc3d852 1265 // sets the position to the end afterwards
embeddedartists 0:0fdadbc3d852 1266 //
embeddedartists 0:0fdadbc3d852 1267 FileHandle *QSPIFileSystem::open(const char *filename, int flags)
embeddedartists 0:0fdadbc3d852 1268 {
embeddedartists 0:0fdadbc3d852 1269 fresult res = qspifs_init();
embeddedartists 0:0fdadbc3d852 1270 // if (res == FS_OK) {
embeddedartists 0:0fdadbc3d852 1271 // if ((flags & O_ACCMODE) == O_RDONLY) {
embeddedartists 0:0fdadbc3d852 1272 // // ok
embeddedartists 0:0fdadbc3d852 1273 // } else if (flags & O_APPEND) {
embeddedartists 0:0fdadbc3d852 1274 // // ok
embeddedartists 0:0fdadbc3d852 1275 // } else {
embeddedartists 0:0fdadbc3d852 1276 // // not supported yet, this includes all combination of flags
embeddedartists 0:0fdadbc3d852 1277 // // allowing writing at specific positions in the file. This file system
embeddedartists 0:0fdadbc3d852 1278 // // only allows appending
embeddedartists 0:0fdadbc3d852 1279 // res = FS_ERR_INVALID_PARAM;
embeddedartists 0:0fdadbc3d852 1280 // }
embeddedartists 0:0fdadbc3d852 1281 // }
embeddedartists 0:0fdadbc3d852 1282 if (res == FS_OK) {
embeddedartists 0:0fdadbc3d852 1283 if (strlen(filename) > HEADER_FNAME_STRLEN) {
embeddedartists 0:0fdadbc3d852 1284 // Filename is too long
embeddedartists 0:0fdadbc3d852 1285 res = FS_ERR_INVALID_PARAM;
embeddedartists 0:0fdadbc3d852 1286 }
embeddedartists 0:0fdadbc3d852 1287 }
embeddedartists 0:0fdadbc3d852 1288 if (res == FS_OK) {
embeddedartists 0:0fdadbc3d852 1289 // Handle truncation by silently deleting the file before
embeddedartists 0:0fdadbc3d852 1290 // attempting to open it
embeddedartists 0:0fdadbc3d852 1291 if (flags & O_TRUNC) {
embeddedartists 0:0fdadbc3d852 1292 remove(filename);
embeddedartists 0:0fdadbc3d852 1293 }
embeddedartists 0:0fdadbc3d852 1294 }
embeddedartists 0:0fdadbc3d852 1295 if (res == FS_OK) {
embeddedartists 0:0fdadbc3d852 1296 fileHandle_t fh = {0,0,0};
embeddedartists 0:0fdadbc3d852 1297 res = qspifs_findFile(filename, &fh);
embeddedartists 0:0fdadbc3d852 1298 if ((res == FS_ERR_NO_FILE) && (flags & O_CREAT)) {
embeddedartists 0:0fdadbc3d852 1299 res = qspifs_allocateFile(filename, 1, &fh.tocIdx);
embeddedartists 0:0fdadbc3d852 1300 }
embeddedartists 0:0fdadbc3d852 1301 if (res == FS_OK) {
embeddedartists 0:0fdadbc3d852 1302 res = qspifs_saveTOC();
embeddedartists 0:0fdadbc3d852 1303 }
embeddedartists 0:0fdadbc3d852 1304 if (res == FS_OK) {
embeddedartists 0:0fdadbc3d852 1305 return new QSPIFileHandle(&fh, flags);
embeddedartists 0:0fdadbc3d852 1306 }
embeddedartists 0:0fdadbc3d852 1307 }
embeddedartists 0:0fdadbc3d852 1308 debug_if(QSPI_DBG, "QSPIFS: Failed to open: %d\n", res);
embeddedartists 0:0fdadbc3d852 1309 return NULL;
embeddedartists 0:0fdadbc3d852 1310 }
embeddedartists 0:0fdadbc3d852 1311
embeddedartists 0:0fdadbc3d852 1312 int QSPIFileSystem::remove(const char *filename)
embeddedartists 0:0fdadbc3d852 1313 {
embeddedartists 0:0fdadbc3d852 1314 fileHandle_t fh = {0,0,0};
embeddedartists 0:0fdadbc3d852 1315 fresult res = qspifs_init();
embeddedartists 0:0fdadbc3d852 1316 if (res == FS_OK) {
embeddedartists 0:0fdadbc3d852 1317 res = qspifs_findFile(filename, &fh);
embeddedartists 0:0fdadbc3d852 1318 }
embeddedartists 0:0fdadbc3d852 1319 if (res == FS_OK) {
embeddedartists 0:0fdadbc3d852 1320 qspifs_deleteFile(&fh);
embeddedartists 0:0fdadbc3d852 1321 res = qspifs_saveTOC();
embeddedartists 0:0fdadbc3d852 1322 }
embeddedartists 0:0fdadbc3d852 1323 else if (res == FS_ERR_NO_FILE) {
embeddedartists 0:0fdadbc3d852 1324 // file does not exist so treat it as a successful deletion
embeddedartists 0:0fdadbc3d852 1325 res = FS_OK;
embeddedartists 0:0fdadbc3d852 1326 }
embeddedartists 0:0fdadbc3d852 1327 if (res != FS_OK) {
embeddedartists 0:0fdadbc3d852 1328 debug_if(QSPI_DBG, "QSPIFS: Failed to delete %s: %d\n", filename, res);
embeddedartists 0:0fdadbc3d852 1329 return -1;
embeddedartists 0:0fdadbc3d852 1330 }
embeddedartists 0:0fdadbc3d852 1331 return 0;
embeddedartists 0:0fdadbc3d852 1332 }
embeddedartists 0:0fdadbc3d852 1333
embeddedartists 0:0fdadbc3d852 1334 int QSPIFileSystem::rename(const char *oldname, const char *newname)
embeddedartists 0:0fdadbc3d852 1335 {
embeddedartists 0:0fdadbc3d852 1336 fileHandle_t fhOld = {0,0,0};
embeddedartists 0:0fdadbc3d852 1337 fileHandle_t fhNew = {0,0,0};
embeddedartists 0:0fdadbc3d852 1338
embeddedartists 0:0fdadbc3d852 1339 fresult res = qspifs_init();
embeddedartists 0:0fdadbc3d852 1340 if (res == FS_OK) {
embeddedartists 0:0fdadbc3d852 1341 res = qspifs_findFile(oldname, &fhOld);
embeddedartists 0:0fdadbc3d852 1342 }
embeddedartists 0:0fdadbc3d852 1343 if (res == FS_OK) {
embeddedartists 0:0fdadbc3d852 1344 // Make sure the destination file doesn't exist
embeddedartists 0:0fdadbc3d852 1345 res = qspifs_findFile(newname, &fhNew);
embeddedartists 0:0fdadbc3d852 1346 if (res == FS_OK) {
embeddedartists 0:0fdadbc3d852 1347 res = FS_ERR_FILE_EXIST;
embeddedartists 0:0fdadbc3d852 1348 } else if (res == FS_ERR_NO_FILE) {
embeddedartists 0:0fdadbc3d852 1349 res = FS_OK;
embeddedartists 0:0fdadbc3d852 1350 }
embeddedartists 0:0fdadbc3d852 1351 }
embeddedartists 0:0fdadbc3d852 1352 if (res == FS_OK) {
embeddedartists 0:0fdadbc3d852 1353 int numNeededBlocks = 1 + ((fhOld.size + HEADER_LEN) / ERASE_SIZE);
embeddedartists 0:0fdadbc3d852 1354 res = qspifs_allocateFile(newname, numNeededBlocks, &fhNew.tocIdx);
embeddedartists 0:0fdadbc3d852 1355 if (res == FS_OK) {
embeddedartists 0:0fdadbc3d852 1356 const uint8_t* pData = (const uint8_t*)(SPIFI_MEM_BASE + fhOld.tocIdx*ERASE_SIZE + HEADER_LEN);
embeddedartists 0:0fdadbc3d852 1357 res = qspifs_write(&fhNew, pData, fhOld.size);
embeddedartists 0:0fdadbc3d852 1358 if (res == FS_OK) {
embeddedartists 0:0fdadbc3d852 1359 qspifs_deleteFile(&fhOld);
embeddedartists 0:0fdadbc3d852 1360 } else {
embeddedartists 0:0fdadbc3d852 1361 qspifs_deleteFile(&fhNew);
embeddedartists 0:0fdadbc3d852 1362 }
embeddedartists 0:0fdadbc3d852 1363 }
embeddedartists 0:0fdadbc3d852 1364 qspifs_saveTOC();
embeddedartists 0:0fdadbc3d852 1365 }
embeddedartists 0:0fdadbc3d852 1366 if (res != FS_OK) {
embeddedartists 0:0fdadbc3d852 1367 debug_if(QSPI_DBG, "QSPIFS: Failed to rename '%s' to '%s': %d\n", oldname, newname, res);
embeddedartists 0:0fdadbc3d852 1368 return -1;
embeddedartists 0:0fdadbc3d852 1369 }
embeddedartists 0:0fdadbc3d852 1370 return 0;
embeddedartists 0:0fdadbc3d852 1371 }
embeddedartists 0:0fdadbc3d852 1372
embeddedartists 0:0fdadbc3d852 1373 DirHandle *QSPIFileSystem::opendir(const char *name)
embeddedartists 0:0fdadbc3d852 1374 {
embeddedartists 0:0fdadbc3d852 1375 FileHandle* fh = open(name, O_RDONLY);
embeddedartists 0:0fdadbc3d852 1376 if (fh != NULL) {
embeddedartists 0:0fdadbc3d852 1377 // Attempting to open a file as a dir
embeddedartists 0:0fdadbc3d852 1378 delete fh;
embeddedartists 0:0fdadbc3d852 1379 return NULL;
embeddedartists 0:0fdadbc3d852 1380 }
embeddedartists 0:0fdadbc3d852 1381
embeddedartists 0:0fdadbc3d852 1382 // printf("opendir: name '%s'\n", name);
embeddedartists 0:0fdadbc3d852 1383 if (strlen(name) <= HEADER_DNAME_MAXLEN) {
embeddedartists 0:0fdadbc3d852 1384 return QSPIDirHandle::openDir(name);
embeddedartists 0:0fdadbc3d852 1385 }
embeddedartists 0:0fdadbc3d852 1386 return NULL;
embeddedartists 0:0fdadbc3d852 1387 }
embeddedartists 0:0fdadbc3d852 1388
embeddedartists 0:0fdadbc3d852 1389 int QSPIFileSystem::mkdir(const char *name, mode_t mode)
embeddedartists 0:0fdadbc3d852 1390 {
embeddedartists 0:0fdadbc3d852 1391 // Creating folders is always successful as there are no folders in this filesystem
embeddedartists 0:0fdadbc3d852 1392 return 0;
embeddedartists 0:0fdadbc3d852 1393 }
embeddedartists 0:0fdadbc3d852 1394
embeddedartists 0:0fdadbc3d852 1395 int QSPIFileSystem::format(unsigned int fsSizeInMB)
embeddedartists 0:0fdadbc3d852 1396 {
embeddedartists 0:0fdadbc3d852 1397 fresult res = qspifs_init();
embeddedartists 0:0fdadbc3d852 1398 if (res == FS_OK || res == FS_ERR_NOT_FORMATTED) {
embeddedartists 0:0fdadbc3d852 1399 if (((fsSizeInMB<<20) > memInfo.memSize) || (fsSizeInMB < 1)) {
embeddedartists 0:0fdadbc3d852 1400 debug_if(QSPI_DBG, "QSPIFS: Failed to format to size %d MByte: error %d\n", fsSizeInMB, res);
embeddedartists 0:0fdadbc3d852 1401 return -1;
embeddedartists 0:0fdadbc3d852 1402 }
embeddedartists 0:0fdadbc3d852 1403 activeTOC = -1;
embeddedartists 0:0fdadbc3d852 1404 res = qspifs_format(memInfo.memSize - (fsSizeInMB<<20));
embeddedartists 0:0fdadbc3d852 1405 }
embeddedartists 0:0fdadbc3d852 1406
embeddedartists 0:0fdadbc3d852 1407 if (res != FS_OK) {
embeddedartists 0:0fdadbc3d852 1408 debug_if(QSPI_DBG, "QSPIFS: Failed to format: %d\n", res);
embeddedartists 0:0fdadbc3d852 1409 return -1;
embeddedartists 0:0fdadbc3d852 1410 }
embeddedartists 0:0fdadbc3d852 1411 return 0;
embeddedartists 0:0fdadbc3d852 1412 }
embeddedartists 0:0fdadbc3d852 1413
embeddedartists 0:0fdadbc3d852 1414 bool QSPIFileSystem::isformatted()
embeddedartists 0:0fdadbc3d852 1415 {
embeddedartists 0:0fdadbc3d852 1416 fresult res = qspifs_init();
embeddedartists 0:0fdadbc3d852 1417 if (res == FS_OK) {
embeddedartists 0:0fdadbc3d852 1418 return true;
embeddedartists 0:0fdadbc3d852 1419 } else if (res == FS_ERR_NOT_FORMATTED) {
embeddedartists 0:0fdadbc3d852 1420 return false;
embeddedartists 0:0fdadbc3d852 1421 }
embeddedartists 0:0fdadbc3d852 1422 debug_if(QSPI_DBG, "QSPIFS: Failed to detect status: %d\n", res);
embeddedartists 0:0fdadbc3d852 1423 return false;
embeddedartists 0:0fdadbc3d852 1424 }
embeddedartists 0:0fdadbc3d852 1425
embeddedartists 0:0fdadbc3d852 1426 bool QSPIFileSystem::getMemoryBoundaries(uint32_t* pStartAddr, uint32_t* pEndAddr)
embeddedartists 0:0fdadbc3d852 1427 {
embeddedartists 0:0fdadbc3d852 1428 if (isformatted())
embeddedartists 0:0fdadbc3d852 1429 {
embeddedartists 0:0fdadbc3d852 1430 *pEndAddr = 0x28000000 + memInfo.memSize;
embeddedartists 0:0fdadbc3d852 1431
embeddedartists 0:0fdadbc3d852 1432 // Look at all blocks except for the reserved ones
embeddedartists 0:0fdadbc3d852 1433 for (int i = 0; i < NUM_BLOCKS; i++)
embeddedartists 0:0fdadbc3d852 1434 {
embeddedartists 0:0fdadbc3d852 1435 if (!TOC_IS_RESERVED(TOC[i]))
embeddedartists 0:0fdadbc3d852 1436 {
embeddedartists 0:0fdadbc3d852 1437 // Found first non-reserved erase block, indicating the start of
embeddedartists 0:0fdadbc3d852 1438 // the file system.
embeddedartists 0:0fdadbc3d852 1439 *pStartAddr = SPIFI_MEM_BASE + i*ERASE_SIZE;
embeddedartists 0:0fdadbc3d852 1440 return true;
embeddedartists 0:0fdadbc3d852 1441 }
embeddedartists 0:0fdadbc3d852 1442 }
embeddedartists 0:0fdadbc3d852 1443
embeddedartists 0:0fdadbc3d852 1444 // The entire file system seems to be reserved which should never happen
embeddedartists 0:0fdadbc3d852 1445 // but just in case, report it as beeing 1MB in size.
embeddedartists 0:0fdadbc3d852 1446 *pStartAddr = *pEndAddr - 1024*1024;
embeddedartists 0:0fdadbc3d852 1447 return true;
embeddedartists 0:0fdadbc3d852 1448 }
embeddedartists 0:0fdadbc3d852 1449 return false;
embeddedartists 0:0fdadbc3d852 1450 }