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