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