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