![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
The purpose of this application is to allow easy manipulation of the QSPI file system from a PC
Dependencies: EALib USBDevice mbed
The purpose of this application is to allow easy manipulation of the QSPI file system from a PC.
The application makes the LPC4088 QuickStart Board appear as a USB Memory Stick when connected to a PC. The PC will see the current content of the QSPI file system plus an image file of the file system that can be downloaded and (at a later time) be used to restore the file system to it's current state.
To use this application:
- Make sure that the QSPI file system has been formatted (using either the app_qspi_format application or one of the erase.* images).
- Download the app_qspifs_memstick application using drag-n-drop and then reset the board
- Optionally start a terminal program to read the status messages from the application
- Connect a USB cable to the micro USB slot on the back of the LPC4088 QuickStart Board, underneath the ethernet connector, and then to the PC
- The PC will install drivers if needed and then the USB Memory Stick will be available as a new drive
- Modify the file system to suit your needs
- With the USB cable still connected, press the button on the LPC4088 QuickStart Board
- The application will now:
- disconnect the USB Memory Stick
- write all changes to the QSPI flash memory
- create a new image file of the updated QSPI file system and store it in the .current/ folder
- connect the USB Memory Stick again
- Continue from step 6. until satisfied
Note 1: The file system that is exposed is a copy (in SDRAM) of the QSPI file system. The reason for this is that the USBMSD class requires a FAT file system.
Note 2: The image files created in step 8.3 above will be a *.fsX file (where the 'X' is the size of the file system in MB so *.fs1 for a 1MByte file system). The *.fsX file extensions are recognized by the HDK and can be used to drag-n-drop to the MBED drive in the same way as the *.bin files are. A *.fsX file will not overwrite the program stored in internal flash.
main.cpp@0:bd0d999bb6fb, 2013-09-26 (annotated)
- Committer:
- embeddedartists
- Date:
- Thu Sep 26 09:21:11 2013 +0000
- Revision:
- 0:bd0d999bb6fb
First version
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
embeddedartists | 0:bd0d999bb6fb | 1 | /****************************************************************************** |
embeddedartists | 0:bd0d999bb6fb | 2 | * Includes |
embeddedartists | 0:bd0d999bb6fb | 3 | *****************************************************************************/ |
embeddedartists | 0:bd0d999bb6fb | 4 | |
embeddedartists | 0:bd0d999bb6fb | 5 | #include "mbed.h" |
embeddedartists | 0:bd0d999bb6fb | 6 | |
embeddedartists | 0:bd0d999bb6fb | 7 | #include "QSPIFileSystem.h" |
embeddedartists | 0:bd0d999bb6fb | 8 | |
embeddedartists | 0:bd0d999bb6fb | 9 | #include "USBMSD_RAMFS.h" |
embeddedartists | 0:bd0d999bb6fb | 10 | #include "RAMFileSystem.h" |
embeddedartists | 0:bd0d999bb6fb | 11 | #include "sdram.h" |
embeddedartists | 0:bd0d999bb6fb | 12 | #include "crc.h" |
embeddedartists | 0:bd0d999bb6fb | 13 | |
embeddedartists | 0:bd0d999bb6fb | 14 | /****************************************************************************** |
embeddedartists | 0:bd0d999bb6fb | 15 | * Typedefs and defines |
embeddedartists | 0:bd0d999bb6fb | 16 | *****************************************************************************/ |
embeddedartists | 0:bd0d999bb6fb | 17 | |
embeddedartists | 0:bd0d999bb6fb | 18 | typedef bool (*syncFunc)(const char* name, bool isDir); |
embeddedartists | 0:bd0d999bb6fb | 19 | |
embeddedartists | 0:bd0d999bb6fb | 20 | #define RAM_FS_SIZE (20*1024*1024) //20MB |
embeddedartists | 0:bd0d999bb6fb | 21 | |
embeddedartists | 0:bd0d999bb6fb | 22 | /****************************************************************************** |
embeddedartists | 0:bd0d999bb6fb | 23 | * Local variables |
embeddedartists | 0:bd0d999bb6fb | 24 | *****************************************************************************/ |
embeddedartists | 0:bd0d999bb6fb | 25 | |
embeddedartists | 0:bd0d999bb6fb | 26 | QSPIFileSystem qspi("qspi"); |
embeddedartists | 0:bd0d999bb6fb | 27 | //RAMFileSystem ramfs(0xA0000000, 20*1024*1024, "ram"); |
embeddedartists | 0:bd0d999bb6fb | 28 | //USBMSD_RAMFS usbmsd(&ramfs); |
embeddedartists | 0:bd0d999bb6fb | 29 | |
embeddedartists | 0:bd0d999bb6fb | 30 | DigitalOut myled1(LED1); |
embeddedartists | 0:bd0d999bb6fb | 31 | DigitalOut myled2(LED2); |
embeddedartists | 0:bd0d999bb6fb | 32 | DigitalIn button(p23); |
embeddedartists | 0:bd0d999bb6fb | 33 | |
embeddedartists | 0:bd0d999bb6fb | 34 | DigitalOut myled(LED1); |
embeddedartists | 0:bd0d999bb6fb | 35 | static char lsbuff[NAME_MAX+1]; |
embeddedartists | 0:bd0d999bb6fb | 36 | |
embeddedartists | 0:bd0d999bb6fb | 37 | static char image_file_name[128] = { '\0' }; |
embeddedartists | 0:bd0d999bb6fb | 38 | |
embeddedartists | 0:bd0d999bb6fb | 39 | /****************************************************************************** |
embeddedartists | 0:bd0d999bb6fb | 40 | * Local functions |
embeddedartists | 0:bd0d999bb6fb | 41 | *****************************************************************************/ |
embeddedartists | 0:bd0d999bb6fb | 42 | |
embeddedartists | 0:bd0d999bb6fb | 43 | static void ledShowProgress() |
embeddedartists | 0:bd0d999bb6fb | 44 | { |
embeddedartists | 0:bd0d999bb6fb | 45 | static int state = 0; |
embeddedartists | 0:bd0d999bb6fb | 46 | state = (state + 1) % 2; |
embeddedartists | 0:bd0d999bb6fb | 47 | switch (state) |
embeddedartists | 0:bd0d999bb6fb | 48 | { |
embeddedartists | 0:bd0d999bb6fb | 49 | case 0: |
embeddedartists | 0:bd0d999bb6fb | 50 | myled1 = 1; |
embeddedartists | 0:bd0d999bb6fb | 51 | myled2 = 0; |
embeddedartists | 0:bd0d999bb6fb | 52 | break; |
embeddedartists | 0:bd0d999bb6fb | 53 | |
embeddedartists | 0:bd0d999bb6fb | 54 | case 1: |
embeddedartists | 0:bd0d999bb6fb | 55 | default: |
embeddedartists | 0:bd0d999bb6fb | 56 | myled1 = 0; |
embeddedartists | 0:bd0d999bb6fb | 57 | myled2 = 1; |
embeddedartists | 0:bd0d999bb6fb | 58 | } |
embeddedartists | 0:bd0d999bb6fb | 59 | } |
embeddedartists | 0:bd0d999bb6fb | 60 | |
embeddedartists | 0:bd0d999bb6fb | 61 | static void handleError(const char* msg) |
embeddedartists | 0:bd0d999bb6fb | 62 | { |
embeddedartists | 0:bd0d999bb6fb | 63 | printf(msg); |
embeddedartists | 0:bd0d999bb6fb | 64 | while(true) { |
embeddedartists | 0:bd0d999bb6fb | 65 | myled1 = 1; |
embeddedartists | 0:bd0d999bb6fb | 66 | myled2 = 1; |
embeddedartists | 0:bd0d999bb6fb | 67 | wait(0.3); |
embeddedartists | 0:bd0d999bb6fb | 68 | myled1 = 0; |
embeddedartists | 0:bd0d999bb6fb | 69 | myled2 = 0; |
embeddedartists | 0:bd0d999bb6fb | 70 | wait(0.3); |
embeddedartists | 0:bd0d999bb6fb | 71 | } |
embeddedartists | 0:bd0d999bb6fb | 72 | } |
embeddedartists | 0:bd0d999bb6fb | 73 | |
embeddedartists | 0:bd0d999bb6fb | 74 | static void waitForButtonPress() |
embeddedartists | 0:bd0d999bb6fb | 75 | { |
embeddedartists | 0:bd0d999bb6fb | 76 | printf("Press button to sync file systems\n"); |
embeddedartists | 0:bd0d999bb6fb | 77 | |
embeddedartists | 0:bd0d999bb6fb | 78 | myled1 = 1; |
embeddedartists | 0:bd0d999bb6fb | 79 | myled2 = 1; |
embeddedartists | 0:bd0d999bb6fb | 80 | while(button.read() == 1) { |
embeddedartists | 0:bd0d999bb6fb | 81 | wait(0.1); |
embeddedartists | 0:bd0d999bb6fb | 82 | } |
embeddedartists | 0:bd0d999bb6fb | 83 | myled1 = 0; |
embeddedartists | 0:bd0d999bb6fb | 84 | printf("Button pressed, now release it\n"); |
embeddedartists | 0:bd0d999bb6fb | 85 | while(button.read() == 0) { |
embeddedartists | 0:bd0d999bb6fb | 86 | wait(0.1); |
embeddedartists | 0:bd0d999bb6fb | 87 | } |
embeddedartists | 0:bd0d999bb6fb | 88 | } |
embeddedartists | 0:bd0d999bb6fb | 89 | |
embeddedartists | 0:bd0d999bb6fb | 90 | static void addNotFormattedFile() |
embeddedartists | 0:bd0d999bb6fb | 91 | { |
embeddedartists | 0:bd0d999bb6fb | 92 | FILE *fp = fopen("/ram/qspi_not_formatted.txt", "w"); |
embeddedartists | 0:bd0d999bb6fb | 93 | if (fp != NULL) { |
embeddedartists | 0:bd0d999bb6fb | 94 | fprintf(fp, "The QSPI file system has not be formatted and this program can't do it.\n"); |
embeddedartists | 0:bd0d999bb6fb | 95 | fprintf(fp, "Format the QSPI file system and then run this program again!\n"); |
embeddedartists | 0:bd0d999bb6fb | 96 | fclose(fp); |
embeddedartists | 0:bd0d999bb6fb | 97 | } |
embeddedartists | 0:bd0d999bb6fb | 98 | } |
embeddedartists | 0:bd0d999bb6fb | 99 | |
embeddedartists | 0:bd0d999bb6fb | 100 | static bool recursiveProcessFS(char* buff, const char* name, syncFunc func, bool adding) |
embeddedartists | 0:bd0d999bb6fb | 101 | { |
embeddedartists | 0:bd0d999bb6fb | 102 | uint32_t len = strlen(buff); |
embeddedartists | 0:bd0d999bb6fb | 103 | if (len > 0) { |
embeddedartists | 0:bd0d999bb6fb | 104 | if (buff[len - 1] != '/') { |
embeddedartists | 0:bd0d999bb6fb | 105 | buff[len++] = '/'; |
embeddedartists | 0:bd0d999bb6fb | 106 | buff[len] = '\0'; |
embeddedartists | 0:bd0d999bb6fb | 107 | } |
embeddedartists | 0:bd0d999bb6fb | 108 | } |
embeddedartists | 0:bd0d999bb6fb | 109 | strcat(buff, name); |
embeddedartists | 0:bd0d999bb6fb | 110 | len += strlen(name); |
embeddedartists | 0:bd0d999bb6fb | 111 | |
embeddedartists | 0:bd0d999bb6fb | 112 | DIR *d = opendir(buff); |
embeddedartists | 0:bd0d999bb6fb | 113 | bool result = true; // success |
embeddedartists | 0:bd0d999bb6fb | 114 | if (d != NULL) { |
embeddedartists | 0:bd0d999bb6fb | 115 | if (adding) { |
embeddedartists | 0:bd0d999bb6fb | 116 | // when processing in adding mode folders must be created before it's content |
embeddedartists | 0:bd0d999bb6fb | 117 | result = func(buff, true); |
embeddedartists | 0:bd0d999bb6fb | 118 | } |
embeddedartists | 0:bd0d999bb6fb | 119 | struct dirent *p; |
embeddedartists | 0:bd0d999bb6fb | 120 | while (result && ((p = readdir(d)) != NULL)) { |
embeddedartists | 0:bd0d999bb6fb | 121 | result = recursiveProcessFS(buff, p->d_name, func, adding); |
embeddedartists | 0:bd0d999bb6fb | 122 | buff[len] = '\0'; |
embeddedartists | 0:bd0d999bb6fb | 123 | } |
embeddedartists | 0:bd0d999bb6fb | 124 | closedir(d); |
embeddedartists | 0:bd0d999bb6fb | 125 | if (result && !adding) { |
embeddedartists | 0:bd0d999bb6fb | 126 | // when processing in removing mode folders must be deleted after it's content |
embeddedartists | 0:bd0d999bb6fb | 127 | result = func(buff, true); |
embeddedartists | 0:bd0d999bb6fb | 128 | } |
embeddedartists | 0:bd0d999bb6fb | 129 | } else { |
embeddedartists | 0:bd0d999bb6fb | 130 | // a file |
embeddedartists | 0:bd0d999bb6fb | 131 | result = func(buff, false); |
embeddedartists | 0:bd0d999bb6fb | 132 | } |
embeddedartists | 0:bd0d999bb6fb | 133 | return result; |
embeddedartists | 0:bd0d999bb6fb | 134 | } |
embeddedartists | 0:bd0d999bb6fb | 135 | |
embeddedartists | 0:bd0d999bb6fb | 136 | static uint32_t fileLen(FILE* f) |
embeddedartists | 0:bd0d999bb6fb | 137 | { |
embeddedartists | 0:bd0d999bb6fb | 138 | uint32_t pos = ftell(f); |
embeddedartists | 0:bd0d999bb6fb | 139 | fseek(f, 0, SEEK_END); |
embeddedartists | 0:bd0d999bb6fb | 140 | uint32_t size = ftell(f); |
embeddedartists | 0:bd0d999bb6fb | 141 | fseek(f, pos, SEEK_SET); |
embeddedartists | 0:bd0d999bb6fb | 142 | return size; |
embeddedartists | 0:bd0d999bb6fb | 143 | } |
embeddedartists | 0:bd0d999bb6fb | 144 | |
embeddedartists | 0:bd0d999bb6fb | 145 | static bool copy(FILE* fSrc, FILE* fDst) |
embeddedartists | 0:bd0d999bb6fb | 146 | { |
embeddedartists | 0:bd0d999bb6fb | 147 | char buff[512]; |
embeddedartists | 0:bd0d999bb6fb | 148 | uint32_t left = fileLen(fSrc); |
embeddedartists | 0:bd0d999bb6fb | 149 | uint32_t num; |
embeddedartists | 0:bd0d999bb6fb | 150 | uint32_t chunk; |
embeddedartists | 0:bd0d999bb6fb | 151 | |
embeddedartists | 0:bd0d999bb6fb | 152 | fseek(fSrc, 0, SEEK_SET); |
embeddedartists | 0:bd0d999bb6fb | 153 | do { |
embeddedartists | 0:bd0d999bb6fb | 154 | chunk = (left < 512) ? left : 512; |
embeddedartists | 0:bd0d999bb6fb | 155 | num = fread(buff, 1, chunk, fSrc); |
embeddedartists | 0:bd0d999bb6fb | 156 | if (num > 0) { |
embeddedartists | 0:bd0d999bb6fb | 157 | uint32_t tmp = fwrite(buff, 1, num, fDst); |
embeddedartists | 0:bd0d999bb6fb | 158 | if (tmp != num) { |
embeddedartists | 0:bd0d999bb6fb | 159 | // failed to write |
embeddedartists | 0:bd0d999bb6fb | 160 | return false; |
embeddedartists | 0:bd0d999bb6fb | 161 | } |
embeddedartists | 0:bd0d999bb6fb | 162 | left -= num; |
embeddedartists | 0:bd0d999bb6fb | 163 | ledShowProgress(); |
embeddedartists | 0:bd0d999bb6fb | 164 | } |
embeddedartists | 0:bd0d999bb6fb | 165 | } while(num > 0 && left > 0); |
embeddedartists | 0:bd0d999bb6fb | 166 | |
embeddedartists | 0:bd0d999bb6fb | 167 | // copied entire file |
embeddedartists | 0:bd0d999bb6fb | 168 | return true; |
embeddedartists | 0:bd0d999bb6fb | 169 | } |
embeddedartists | 0:bd0d999bb6fb | 170 | |
embeddedartists | 0:bd0d999bb6fb | 171 | static bool identicalFiles(const char* srcName, const char* dstName) |
embeddedartists | 0:bd0d999bb6fb | 172 | { |
embeddedartists | 0:bd0d999bb6fb | 173 | FILE* fSrc = NULL; |
embeddedartists | 0:bd0d999bb6fb | 174 | FILE* fDst = NULL; |
embeddedartists | 0:bd0d999bb6fb | 175 | bool identical = false; |
embeddedartists | 0:bd0d999bb6fb | 176 | do |
embeddedartists | 0:bd0d999bb6fb | 177 | { |
embeddedartists | 0:bd0d999bb6fb | 178 | fSrc = fopen(srcName, "r"); |
embeddedartists | 0:bd0d999bb6fb | 179 | if (fSrc == NULL) { |
embeddedartists | 0:bd0d999bb6fb | 180 | break; |
embeddedartists | 0:bd0d999bb6fb | 181 | } |
embeddedartists | 0:bd0d999bb6fb | 182 | fDst = fopen(dstName, "r"); |
embeddedartists | 0:bd0d999bb6fb | 183 | if (fDst == NULL) { |
embeddedartists | 0:bd0d999bb6fb | 184 | break; |
embeddedartists | 0:bd0d999bb6fb | 185 | } |
embeddedartists | 0:bd0d999bb6fb | 186 | if (fileLen(fSrc) != fileLen(fDst)) { |
embeddedartists | 0:bd0d999bb6fb | 187 | break; |
embeddedartists | 0:bd0d999bb6fb | 188 | } |
embeddedartists | 0:bd0d999bb6fb | 189 | if (crc_Read(fSrc) != crc_Read(fDst)) { |
embeddedartists | 0:bd0d999bb6fb | 190 | break; |
embeddedartists | 0:bd0d999bb6fb | 191 | } |
embeddedartists | 0:bd0d999bb6fb | 192 | |
embeddedartists | 0:bd0d999bb6fb | 193 | // All tests passed so the files are identical |
embeddedartists | 0:bd0d999bb6fb | 194 | identical = true; |
embeddedartists | 0:bd0d999bb6fb | 195 | |
embeddedartists | 0:bd0d999bb6fb | 196 | } while(false); |
embeddedartists | 0:bd0d999bb6fb | 197 | |
embeddedartists | 0:bd0d999bb6fb | 198 | if (fSrc != NULL) { |
embeddedartists | 0:bd0d999bb6fb | 199 | fclose(fSrc); |
embeddedartists | 0:bd0d999bb6fb | 200 | } |
embeddedartists | 0:bd0d999bb6fb | 201 | if (fDst != NULL) { |
embeddedartists | 0:bd0d999bb6fb | 202 | fclose(fDst); |
embeddedartists | 0:bd0d999bb6fb | 203 | } |
embeddedartists | 0:bd0d999bb6fb | 204 | |
embeddedartists | 0:bd0d999bb6fb | 205 | return identical; |
embeddedartists | 0:bd0d999bb6fb | 206 | } |
embeddedartists | 0:bd0d999bb6fb | 207 | |
embeddedartists | 0:bd0d999bb6fb | 208 | static bool addExisting(const char* srcName, bool isDir, const char* dstName) |
embeddedartists | 0:bd0d999bb6fb | 209 | { |
embeddedartists | 0:bd0d999bb6fb | 210 | bool result = true; // success |
embeddedartists | 0:bd0d999bb6fb | 211 | if (isDir) { |
embeddedartists | 0:bd0d999bb6fb | 212 | DIR *d = opendir(dstName); |
embeddedartists | 0:bd0d999bb6fb | 213 | if (d == NULL) { |
embeddedartists | 0:bd0d999bb6fb | 214 | if (dstName[1] != 'r') { printf("%s, new dir, adding\n", dstName); } |
embeddedartists | 0:bd0d999bb6fb | 215 | if (mkdir(dstName, 0) != 0) { |
embeddedartists | 0:bd0d999bb6fb | 216 | printf("Failed to create folder %s\n", dstName); |
embeddedartists | 0:bd0d999bb6fb | 217 | result = false; // dir did not exist and could not be created |
embeddedartists | 0:bd0d999bb6fb | 218 | } |
embeddedartists | 0:bd0d999bb6fb | 219 | } else { |
embeddedartists | 0:bd0d999bb6fb | 220 | closedir(d); |
embeddedartists | 0:bd0d999bb6fb | 221 | } |
embeddedartists | 0:bd0d999bb6fb | 222 | } else if (!identicalFiles(srcName, dstName)) { |
embeddedartists | 0:bd0d999bb6fb | 223 | // Compare the files to avoid replacing with same |
embeddedartists | 0:bd0d999bb6fb | 224 | FILE* fSrc = fopen(srcName, "r"); |
embeddedartists | 0:bd0d999bb6fb | 225 | if (fSrc != NULL) { |
embeddedartists | 0:bd0d999bb6fb | 226 | FILE* fDst = fopen(dstName, "w"); // open and truncate |
embeddedartists | 0:bd0d999bb6fb | 227 | if (fDst != NULL) { |
embeddedartists | 0:bd0d999bb6fb | 228 | if (dstName[1] != 'r') { printf("%s, changed, updating\n", dstName); } |
embeddedartists | 0:bd0d999bb6fb | 229 | result = copy(fSrc, fDst); |
embeddedartists | 0:bd0d999bb6fb | 230 | if (!result) { |
embeddedartists | 0:bd0d999bb6fb | 231 | printf("Failed to copy %s to %s\n", srcName, dstName); |
embeddedartists | 0:bd0d999bb6fb | 232 | } |
embeddedartists | 0:bd0d999bb6fb | 233 | fclose(fDst); |
embeddedartists | 0:bd0d999bb6fb | 234 | } else { |
embeddedartists | 0:bd0d999bb6fb | 235 | printf("Failed to create file %s\n", dstName); |
embeddedartists | 0:bd0d999bb6fb | 236 | result = false; // unable to create file |
embeddedartists | 0:bd0d999bb6fb | 237 | } |
embeddedartists | 0:bd0d999bb6fb | 238 | fclose(fSrc); |
embeddedartists | 0:bd0d999bb6fb | 239 | } else { |
embeddedartists | 0:bd0d999bb6fb | 240 | printf("Failed to copen source file file %s\n", srcName); |
embeddedartists | 0:bd0d999bb6fb | 241 | result = false; // unable to open source |
embeddedartists | 0:bd0d999bb6fb | 242 | } |
embeddedartists | 0:bd0d999bb6fb | 243 | } else { |
embeddedartists | 0:bd0d999bb6fb | 244 | if (dstName[1] != 'r') { printf("%s identical, skipping\n", dstName); } |
embeddedartists | 0:bd0d999bb6fb | 245 | } |
embeddedartists | 0:bd0d999bb6fb | 246 | return result; |
embeddedartists | 0:bd0d999bb6fb | 247 | } |
embeddedartists | 0:bd0d999bb6fb | 248 | |
embeddedartists | 0:bd0d999bb6fb | 249 | static bool addExistingToQspi(const char* name, bool isDir) |
embeddedartists | 0:bd0d999bb6fb | 250 | { |
embeddedartists | 0:bd0d999bb6fb | 251 | // create the target file name by replacing /ram/ with /qspi/ |
embeddedartists | 0:bd0d999bb6fb | 252 | char buff[256]; |
embeddedartists | 0:bd0d999bb6fb | 253 | buff[0] = '\0'; |
embeddedartists | 0:bd0d999bb6fb | 254 | strcat(buff, "/qspi/"); |
embeddedartists | 0:bd0d999bb6fb | 255 | strcat(buff, name+5); |
embeddedartists | 0:bd0d999bb6fb | 256 | |
embeddedartists | 0:bd0d999bb6fb | 257 | // Don't add the file created by createImageFile() |
embeddedartists | 0:bd0d999bb6fb | 258 | if (strcmp(name, image_file_name) == 0) { |
embeddedartists | 0:bd0d999bb6fb | 259 | return true; |
embeddedartists | 0:bd0d999bb6fb | 260 | } |
embeddedartists | 0:bd0d999bb6fb | 261 | |
embeddedartists | 0:bd0d999bb6fb | 262 | return addExisting(name, isDir, buff); |
embeddedartists | 0:bd0d999bb6fb | 263 | } |
embeddedartists | 0:bd0d999bb6fb | 264 | |
embeddedartists | 0:bd0d999bb6fb | 265 | static bool addExistingToRAM(const char* name, bool isDir) |
embeddedartists | 0:bd0d999bb6fb | 266 | { |
embeddedartists | 0:bd0d999bb6fb | 267 | // create the target file name by replacing /qspi/ with /ram/ |
embeddedartists | 0:bd0d999bb6fb | 268 | char buff[256]; |
embeddedartists | 0:bd0d999bb6fb | 269 | buff[0] = '\0'; |
embeddedartists | 0:bd0d999bb6fb | 270 | strcat(buff, "/ram/"); |
embeddedartists | 0:bd0d999bb6fb | 271 | strcat(buff, name+6); |
embeddedartists | 0:bd0d999bb6fb | 272 | return addExisting(name, isDir, buff); |
embeddedartists | 0:bd0d999bb6fb | 273 | } |
embeddedartists | 0:bd0d999bb6fb | 274 | |
embeddedartists | 0:bd0d999bb6fb | 275 | static bool removeIfMissing(const char* toLookFor, const char* toRemove, bool isDir) |
embeddedartists | 0:bd0d999bb6fb | 276 | { |
embeddedartists | 0:bd0d999bb6fb | 277 | int result = 0; //success |
embeddedartists | 0:bd0d999bb6fb | 278 | if (isDir) { |
embeddedartists | 0:bd0d999bb6fb | 279 | DIR *d = opendir(toLookFor); |
embeddedartists | 0:bd0d999bb6fb | 280 | if (d == NULL) { |
embeddedartists | 0:bd0d999bb6fb | 281 | // dir doesn't exist => delete it |
embeddedartists | 0:bd0d999bb6fb | 282 | if (toRemove[1] != 'r') { printf("%s, missing, deleting dir\n", toRemove); } |
embeddedartists | 0:bd0d999bb6fb | 283 | result = remove(toRemove); |
embeddedartists | 0:bd0d999bb6fb | 284 | ledShowProgress(); |
embeddedartists | 0:bd0d999bb6fb | 285 | } else { |
embeddedartists | 0:bd0d999bb6fb | 286 | // dir exist => don't delete |
embeddedartists | 0:bd0d999bb6fb | 287 | closedir(d); |
embeddedartists | 0:bd0d999bb6fb | 288 | } |
embeddedartists | 0:bd0d999bb6fb | 289 | } else { |
embeddedartists | 0:bd0d999bb6fb | 290 | FILE* f = fopen(toLookFor, "r"); |
embeddedartists | 0:bd0d999bb6fb | 291 | if (f == NULL) { |
embeddedartists | 0:bd0d999bb6fb | 292 | // file doesn't exist => delete it |
embeddedartists | 0:bd0d999bb6fb | 293 | if (toRemove[1] != 'r') { printf("%s, missing, deleting file\n", toRemove); } |
embeddedartists | 0:bd0d999bb6fb | 294 | result = remove(toRemove); |
embeddedartists | 0:bd0d999bb6fb | 295 | ledShowProgress(); |
embeddedartists | 0:bd0d999bb6fb | 296 | } else { |
embeddedartists | 0:bd0d999bb6fb | 297 | // file exist => don't delete |
embeddedartists | 0:bd0d999bb6fb | 298 | fclose(f); |
embeddedartists | 0:bd0d999bb6fb | 299 | } |
embeddedartists | 0:bd0d999bb6fb | 300 | } |
embeddedartists | 0:bd0d999bb6fb | 301 | return (result == 0); |
embeddedartists | 0:bd0d999bb6fb | 302 | } |
embeddedartists | 0:bd0d999bb6fb | 303 | |
embeddedartists | 0:bd0d999bb6fb | 304 | static bool removeMissingFromQspi(const char* name, bool isDir) |
embeddedartists | 0:bd0d999bb6fb | 305 | { |
embeddedartists | 0:bd0d999bb6fb | 306 | // create the target file name by replacing /qspi/ with /ram/ |
embeddedartists | 0:bd0d999bb6fb | 307 | char buff[256]; |
embeddedartists | 0:bd0d999bb6fb | 308 | buff[0] = '\0'; |
embeddedartists | 0:bd0d999bb6fb | 309 | strcat(buff, "/ram/"); |
embeddedartists | 0:bd0d999bb6fb | 310 | strcat(buff, name+6); |
embeddedartists | 0:bd0d999bb6fb | 311 | removeIfMissing(buff, name, isDir); |
embeddedartists | 0:bd0d999bb6fb | 312 | return true; |
embeddedartists | 0:bd0d999bb6fb | 313 | } |
embeddedartists | 0:bd0d999bb6fb | 314 | |
embeddedartists | 0:bd0d999bb6fb | 315 | static bool removeMissingFromRAM(const char* name, bool isDir) |
embeddedartists | 0:bd0d999bb6fb | 316 | { |
embeddedartists | 0:bd0d999bb6fb | 317 | // create the target file name by replacing /ram/ with /qspi/ |
embeddedartists | 0:bd0d999bb6fb | 318 | char buff[256]; |
embeddedartists | 0:bd0d999bb6fb | 319 | buff[0] = '\0'; |
embeddedartists | 0:bd0d999bb6fb | 320 | strcat(buff, "/qspi/"); |
embeddedartists | 0:bd0d999bb6fb | 321 | strcat(buff, name+5); |
embeddedartists | 0:bd0d999bb6fb | 322 | |
embeddedartists | 0:bd0d999bb6fb | 323 | // Don't remove the file created by createImageFile() |
embeddedartists | 0:bd0d999bb6fb | 324 | if (strcmp(name, image_file_name) == 0) { |
embeddedartists | 0:bd0d999bb6fb | 325 | return true; |
embeddedartists | 0:bd0d999bb6fb | 326 | } |
embeddedartists | 0:bd0d999bb6fb | 327 | |
embeddedartists | 0:bd0d999bb6fb | 328 | removeIfMissing(buff, name, isDir); |
embeddedartists | 0:bd0d999bb6fb | 329 | return true; |
embeddedartists | 0:bd0d999bb6fb | 330 | } |
embeddedartists | 0:bd0d999bb6fb | 331 | |
embeddedartists | 0:bd0d999bb6fb | 332 | static void syncDir(const char* to, const char* from) |
embeddedartists | 0:bd0d999bb6fb | 333 | { |
embeddedartists | 0:bd0d999bb6fb | 334 | printf("Starting to sync %s on top of %s (This may take time. LED1 & 2 blink for each file)\n", from, to); |
embeddedartists | 0:bd0d999bb6fb | 335 | |
embeddedartists | 0:bd0d999bb6fb | 336 | char* buff = (char*)malloc(512); |
embeddedartists | 0:bd0d999bb6fb | 337 | if (buff != NULL) |
embeddedartists | 0:bd0d999bb6fb | 338 | { |
embeddedartists | 0:bd0d999bb6fb | 339 | buff[0] = '\0'; |
embeddedartists | 0:bd0d999bb6fb | 340 | if (strcmp(to, "/qspi/") == 0) { |
embeddedartists | 0:bd0d999bb6fb | 341 | if (!recursiveProcessFS(buff, to, removeMissingFromQspi, false)) { |
embeddedartists | 0:bd0d999bb6fb | 342 | printf("Failed to remove files from %s that were missing on %s\n", to, from); |
embeddedartists | 0:bd0d999bb6fb | 343 | } else { |
embeddedartists | 0:bd0d999bb6fb | 344 | buff[0] = '\0'; |
embeddedartists | 0:bd0d999bb6fb | 345 | if (!recursiveProcessFS(buff, from, addExistingToQspi, true)) { |
embeddedartists | 0:bd0d999bb6fb | 346 | printf("Failed to add files to %s that existed on %s\n", to, from); |
embeddedartists | 0:bd0d999bb6fb | 347 | } |
embeddedartists | 0:bd0d999bb6fb | 348 | } |
embeddedartists | 0:bd0d999bb6fb | 349 | } else { |
embeddedartists | 0:bd0d999bb6fb | 350 | if (!recursiveProcessFS(buff, to, removeMissingFromRAM, false)) { |
embeddedartists | 0:bd0d999bb6fb | 351 | printf("Failed to remove files from %s that were missing on %s\n", to, from); |
embeddedartists | 0:bd0d999bb6fb | 352 | } else { |
embeddedartists | 0:bd0d999bb6fb | 353 | buff[0] = '\0'; |
embeddedartists | 0:bd0d999bb6fb | 354 | if (!recursiveProcessFS(buff, from, addExistingToRAM, true)) { |
embeddedartists | 0:bd0d999bb6fb | 355 | printf("Failed to add files to %s that existed on %s\n", to, from); |
embeddedartists | 0:bd0d999bb6fb | 356 | } |
embeddedartists | 0:bd0d999bb6fb | 357 | } |
embeddedartists | 0:bd0d999bb6fb | 358 | } |
embeddedartists | 0:bd0d999bb6fb | 359 | free(buff); |
embeddedartists | 0:bd0d999bb6fb | 360 | } |
embeddedartists | 0:bd0d999bb6fb | 361 | printf("Sync completed\n"); |
embeddedartists | 0:bd0d999bb6fb | 362 | } |
embeddedartists | 0:bd0d999bb6fb | 363 | |
embeddedartists | 0:bd0d999bb6fb | 364 | |
embeddedartists | 0:bd0d999bb6fb | 365 | static void createImageFile() |
embeddedartists | 0:bd0d999bb6fb | 366 | { |
embeddedartists | 0:bd0d999bb6fb | 367 | uint32_t startAddr; |
embeddedartists | 0:bd0d999bb6fb | 368 | uint32_t endAddr; |
embeddedartists | 0:bd0d999bb6fb | 369 | uint32_t size; |
embeddedartists | 0:bd0d999bb6fb | 370 | |
embeddedartists | 0:bd0d999bb6fb | 371 | printf("Creating image of existing (if any) QSPI file system\n"); |
embeddedartists | 0:bd0d999bb6fb | 372 | |
embeddedartists | 0:bd0d999bb6fb | 373 | if (!qspi.getMemoryBoundaries(&startAddr, &endAddr)) |
embeddedartists | 0:bd0d999bb6fb | 374 | { |
embeddedartists | 0:bd0d999bb6fb | 375 | handleError("QSPI FS not formatted or impossible to determine it's size\n"); |
embeddedartists | 0:bd0d999bb6fb | 376 | } |
embeddedartists | 0:bd0d999bb6fb | 377 | |
embeddedartists | 0:bd0d999bb6fb | 378 | // Align the start address to an even multiple of 1MB |
embeddedartists | 0:bd0d999bb6fb | 379 | startAddr = startAddr & 0xfff00000; |
embeddedartists | 0:bd0d999bb6fb | 380 | |
embeddedartists | 0:bd0d999bb6fb | 381 | // Update the file to match the size of the file system |
embeddedartists | 0:bd0d999bb6fb | 382 | size = endAddr - startAddr; |
embeddedartists | 0:bd0d999bb6fb | 383 | if ((size < 0x00100000) || (size > 0x00800000) || ((size & 0xfffff) > 0)) |
embeddedartists | 0:bd0d999bb6fb | 384 | { |
embeddedartists | 0:bd0d999bb6fb | 385 | sprintf(lsbuff, "QSPI FS size is not supported (%u bytes)\n", size); |
embeddedartists | 0:bd0d999bb6fb | 386 | handleError(lsbuff); |
embeddedartists | 0:bd0d999bb6fb | 387 | } |
embeddedartists | 0:bd0d999bb6fb | 388 | sprintf(image_file_name, "/ram/.current/fs_image.fs%d", (size >> 20)); |
embeddedartists | 0:bd0d999bb6fb | 389 | |
embeddedartists | 0:bd0d999bb6fb | 390 | // NOTE: The line below is very very !!!! important. For some weird reason the |
embeddedartists | 0:bd0d999bb6fb | 391 | // RAM file system must have at least one folder on it before USB is connected. |
embeddedartists | 0:bd0d999bb6fb | 392 | // If the RAM file system doesn't have any folders on it the result is that |
embeddedartists | 0:bd0d999bb6fb | 393 | // the content of the RAM file system will be the same after USB is disconnected |
embeddedartists | 0:bd0d999bb6fb | 394 | // as it was before connecting - regardless of what is added. Very strange indeed. |
embeddedartists | 0:bd0d999bb6fb | 395 | mkdir("/ram/.current", 0); |
embeddedartists | 0:bd0d999bb6fb | 396 | |
embeddedartists | 0:bd0d999bb6fb | 397 | printf("QSPI FS max size is %d MB\n", (size >> 20)); |
embeddedartists | 0:bd0d999bb6fb | 398 | |
embeddedartists | 0:bd0d999bb6fb | 399 | FILE *fp = fopen(image_file_name, "w"); |
embeddedartists | 0:bd0d999bb6fb | 400 | if (fp != NULL) |
embeddedartists | 0:bd0d999bb6fb | 401 | { |
embeddedartists | 0:bd0d999bb6fb | 402 | while (size > 0) |
embeddedartists | 0:bd0d999bb6fb | 403 | { |
embeddedartists | 0:bd0d999bb6fb | 404 | uint32_t written = fwrite((char*)(endAddr - size), 1, size, fp); |
embeddedartists | 0:bd0d999bb6fb | 405 | size -= written; |
embeddedartists | 0:bd0d999bb6fb | 406 | if (written == 0) |
embeddedartists | 0:bd0d999bb6fb | 407 | { |
embeddedartists | 0:bd0d999bb6fb | 408 | handleError("Failed to create QSPI image file\n"); |
embeddedartists | 0:bd0d999bb6fb | 409 | } |
embeddedartists | 0:bd0d999bb6fb | 410 | } |
embeddedartists | 0:bd0d999bb6fb | 411 | fclose(fp); |
embeddedartists | 0:bd0d999bb6fb | 412 | } |
embeddedartists | 0:bd0d999bb6fb | 413 | } |
embeddedartists | 0:bd0d999bb6fb | 414 | |
embeddedartists | 0:bd0d999bb6fb | 415 | static bool list(const char* name, bool isDir) |
embeddedartists | 0:bd0d999bb6fb | 416 | { |
embeddedartists | 0:bd0d999bb6fb | 417 | if (isDir) { |
embeddedartists | 0:bd0d999bb6fb | 418 | printf("d: %s\n", name); |
embeddedartists | 0:bd0d999bb6fb | 419 | } else { |
embeddedartists | 0:bd0d999bb6fb | 420 | FILE* f = fopen(name, "r"); |
embeddedartists | 0:bd0d999bb6fb | 421 | if (f != NULL) { |
embeddedartists | 0:bd0d999bb6fb | 422 | uint32_t len = fileLen(f); |
embeddedartists | 0:bd0d999bb6fb | 423 | printf("f: %7u %s\n", len, name); |
embeddedartists | 0:bd0d999bb6fb | 424 | fclose(f); |
embeddedartists | 0:bd0d999bb6fb | 425 | } else { |
embeddedartists | 0:bd0d999bb6fb | 426 | printf("f: ??? %s\n", name); |
embeddedartists | 0:bd0d999bb6fb | 427 | } |
embeddedartists | 0:bd0d999bb6fb | 428 | } |
embeddedartists | 0:bd0d999bb6fb | 429 | return true; |
embeddedartists | 0:bd0d999bb6fb | 430 | } |
embeddedartists | 0:bd0d999bb6fb | 431 | |
embeddedartists | 0:bd0d999bb6fb | 432 | static void recursiveList(const char* dirname) |
embeddedartists | 0:bd0d999bb6fb | 433 | { |
embeddedartists | 0:bd0d999bb6fb | 434 | printf("\nRecursive list of file and folders in %s\n", dirname); |
embeddedartists | 0:bd0d999bb6fb | 435 | char* buff = (char*)malloc(512); |
embeddedartists | 0:bd0d999bb6fb | 436 | if (buff != NULL) |
embeddedartists | 0:bd0d999bb6fb | 437 | { |
embeddedartists | 0:bd0d999bb6fb | 438 | buff[0] = '\0'; |
embeddedartists | 0:bd0d999bb6fb | 439 | recursiveProcessFS(buff, dirname, list, true); |
embeddedartists | 0:bd0d999bb6fb | 440 | free(buff); |
embeddedartists | 0:bd0d999bb6fb | 441 | } |
embeddedartists | 0:bd0d999bb6fb | 442 | } |
embeddedartists | 0:bd0d999bb6fb | 443 | |
embeddedartists | 0:bd0d999bb6fb | 444 | /****************************************************************************** |
embeddedartists | 0:bd0d999bb6fb | 445 | * Main function |
embeddedartists | 0:bd0d999bb6fb | 446 | *****************************************************************************/ |
embeddedartists | 0:bd0d999bb6fb | 447 | int main() |
embeddedartists | 0:bd0d999bb6fb | 448 | { |
embeddedartists | 0:bd0d999bb6fb | 449 | printf("\n-----------------\n\nWelcome to the QSPI file system tool...\n"); |
embeddedartists | 0:bd0d999bb6fb | 450 | |
embeddedartists | 0:bd0d999bb6fb | 451 | // 1) Make sure that the button works |
embeddedartists | 0:bd0d999bb6fb | 452 | // 2) Init SDRAM and allocate space for the RAM file system |
embeddedartists | 0:bd0d999bb6fb | 453 | // 3) Setup RAM FS |
embeddedartists | 0:bd0d999bb6fb | 454 | // 4a) If QSPI FS is not formatted: |
embeddedartists | 0:bd0d999bb6fb | 455 | // i) Create a "qspi_not_formatted.txt" file in the root of the file system |
embeddedartists | 0:bd0d999bb6fb | 456 | // 4b) QSPI FS formatted |
embeddedartists | 0:bd0d999bb6fb | 457 | // i) Create an image file of the QSPI FS |
embeddedartists | 0:bd0d999bb6fb | 458 | // ii) Sync QSPI FS on top of RAM FS |
embeddedartists | 0:bd0d999bb6fb | 459 | // 5) Connect USB |
embeddedartists | 0:bd0d999bb6fb | 460 | // 6a) If QSPI FS is not formatted: Loop forever doing nothing |
embeddedartists | 0:bd0d999bb6fb | 461 | // 6b) QSPI FS formatted: Wait for button press |
embeddedartists | 0:bd0d999bb6fb | 462 | // 7) Button pressed, Disconnect USB |
embeddedartists | 0:bd0d999bb6fb | 463 | // 8) QSPI formatted |
embeddedartists | 0:bd0d999bb6fb | 464 | // i) Sync RAM FS on top of QSPI FS |
embeddedartists | 0:bd0d999bb6fb | 465 | // ii) Goto 3) |
embeddedartists | 0:bd0d999bb6fb | 466 | // |
embeddedartists | 0:bd0d999bb6fb | 467 | |
embeddedartists | 0:bd0d999bb6fb | 468 | // 1) |
embeddedartists | 0:bd0d999bb6fb | 469 | button.mode(PullUp); |
embeddedartists | 0:bd0d999bb6fb | 470 | |
embeddedartists | 0:bd0d999bb6fb | 471 | // 2) |
embeddedartists | 0:bd0d999bb6fb | 472 | if (sdram_init()) { |
embeddedartists | 0:bd0d999bb6fb | 473 | handleError("Failed to initialize SDRAM\n"); |
embeddedartists | 0:bd0d999bb6fb | 474 | } |
embeddedartists | 0:bd0d999bb6fb | 475 | |
embeddedartists | 0:bd0d999bb6fb | 476 | void* fsmem = malloc(RAM_FS_SIZE); |
embeddedartists | 0:bd0d999bb6fb | 477 | if (fsmem == NULL) { |
embeddedartists | 0:bd0d999bb6fb | 478 | handleError("Failed to allocate memory for RAM file system\n"); |
embeddedartists | 0:bd0d999bb6fb | 479 | } |
embeddedartists | 0:bd0d999bb6fb | 480 | RAMFileSystem ramfs((uint32_t)fsmem, RAM_FS_SIZE, "ram"); |
embeddedartists | 0:bd0d999bb6fb | 481 | USBMSD_RAMFS usbmsd(&ramfs); |
embeddedartists | 0:bd0d999bb6fb | 482 | |
embeddedartists | 0:bd0d999bb6fb | 483 | while(true) |
embeddedartists | 0:bd0d999bb6fb | 484 | { |
embeddedartists | 0:bd0d999bb6fb | 485 | // 3) |
embeddedartists | 0:bd0d999bb6fb | 486 | ramfs.format(); |
embeddedartists | 0:bd0d999bb6fb | 487 | |
embeddedartists | 0:bd0d999bb6fb | 488 | // 4a) |
embeddedartists | 0:bd0d999bb6fb | 489 | bool qspiFormatted = qspi.isformatted(); |
embeddedartists | 0:bd0d999bb6fb | 490 | if (!qspiFormatted) |
embeddedartists | 0:bd0d999bb6fb | 491 | { |
embeddedartists | 0:bd0d999bb6fb | 492 | addNotFormattedFile(); |
embeddedartists | 0:bd0d999bb6fb | 493 | } |
embeddedartists | 0:bd0d999bb6fb | 494 | |
embeddedartists | 0:bd0d999bb6fb | 495 | // 4b) |
embeddedartists | 0:bd0d999bb6fb | 496 | else |
embeddedartists | 0:bd0d999bb6fb | 497 | { |
embeddedartists | 0:bd0d999bb6fb | 498 | //addTestFile(); |
embeddedartists | 0:bd0d999bb6fb | 499 | createImageFile(); |
embeddedartists | 0:bd0d999bb6fb | 500 | |
embeddedartists | 0:bd0d999bb6fb | 501 | // Copy QSPI FS to RAM FS |
embeddedartists | 0:bd0d999bb6fb | 502 | syncDir("/ram/", "/qspi/"); |
embeddedartists | 0:bd0d999bb6fb | 503 | } |
embeddedartists | 0:bd0d999bb6fb | 504 | |
embeddedartists | 0:bd0d999bb6fb | 505 | // 5) |
embeddedartists | 0:bd0d999bb6fb | 506 | printf("Insert the USB cable!\n"); |
embeddedartists | 0:bd0d999bb6fb | 507 | printf("Starting USB...\n"); |
embeddedartists | 0:bd0d999bb6fb | 508 | for (int i = 0; i < 10; i++) |
embeddedartists | 0:bd0d999bb6fb | 509 | { |
embeddedartists | 0:bd0d999bb6fb | 510 | if (usbmsd.connect()) |
embeddedartists | 0:bd0d999bb6fb | 511 | { |
embeddedartists | 0:bd0d999bb6fb | 512 | printf("Connected!\n"); |
embeddedartists | 0:bd0d999bb6fb | 513 | break; |
embeddedartists | 0:bd0d999bb6fb | 514 | } |
embeddedartists | 0:bd0d999bb6fb | 515 | printf("Failed to connect USB, testing again...\n"); |
embeddedartists | 0:bd0d999bb6fb | 516 | printf("Insert (or remove and then insert) the USB cable!\n"); |
embeddedartists | 0:bd0d999bb6fb | 517 | wait(1); |
embeddedartists | 0:bd0d999bb6fb | 518 | } |
embeddedartists | 0:bd0d999bb6fb | 519 | |
embeddedartists | 0:bd0d999bb6fb | 520 | // 6b) |
embeddedartists | 0:bd0d999bb6fb | 521 | if (qspiFormatted) |
embeddedartists | 0:bd0d999bb6fb | 522 | { |
embeddedartists | 0:bd0d999bb6fb | 523 | waitForButtonPress(); |
embeddedartists | 0:bd0d999bb6fb | 524 | } |
embeddedartists | 0:bd0d999bb6fb | 525 | else |
embeddedartists | 0:bd0d999bb6fb | 526 | { |
embeddedartists | 0:bd0d999bb6fb | 527 | // 6a) no point in waiting for buttons if no file system |
embeddedartists | 0:bd0d999bb6fb | 528 | while (1) {}; |
embeddedartists | 0:bd0d999bb6fb | 529 | } |
embeddedartists | 0:bd0d999bb6fb | 530 | |
embeddedartists | 0:bd0d999bb6fb | 531 | // 7) |
embeddedartists | 0:bd0d999bb6fb | 532 | usbmsd.disconnect(); |
embeddedartists | 0:bd0d999bb6fb | 533 | printf("Disconnected!\n"); |
embeddedartists | 0:bd0d999bb6fb | 534 | |
embeddedartists | 0:bd0d999bb6fb | 535 | // 8) Copy RAM FS to QSPI FS |
embeddedartists | 0:bd0d999bb6fb | 536 | recursiveList("/ram/"); |
embeddedartists | 0:bd0d999bb6fb | 537 | syncDir("/qspi/", "/ram/"); |
embeddedartists | 0:bd0d999bb6fb | 538 | } |
embeddedartists | 0:bd0d999bb6fb | 539 | } |