The purpose of this application is to allow easy manipulation of the QSPI file system from a PC (**NOTE**: Application doesn't work with update to mbed OS 5 since USB Device support is currently not available for LPC4088)

Dependencies:   DMBasicGUI DMSupport

Note

This application doesn't work with the latest updates to mbed OS 5 since USB Device support is currently not available for LPC4088

The purpose of this application is to allow easy manipulation of the QSPI file system from a PC.

The application makes the LPC4088 Display Module 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:

  1. Download the lpc4088_displaymodule_fs_aid application using drag-n-drop and then reset the board
  2. Optionally start a terminal program to read the status messages from the application
  3. Connect a USB cable to the mini USB slot on the back of the LPC4088 Display Module, and then to the PC
  4. The PC will install drivers if needed and then the USB Memory Stick will be available as a new drive
  5. Modify the file system to suit your needs
  6. With the USB cable still connected, press the USER/ISP/SW1 button on the LPC4088 Display Module
  7. The application will now:
    1. disconnect the USB Memory Stick
    2. write all changes to the QSPI flash memory
    3. create a new image file of the updated QSPI file system and store it in the .current/ folder
    4. connect the USB Memory Stick again
  8. Continue from step 5. until satisfied

Note 1: If the QSPI doesn't have a file system on it or to replace the current one with a new, possibly of a different size, file system just add a file with the name format_qspi_X_mb (where X should be replace with the wanted file system size in Mb). For a 10 Mb file system the file name should be format_qspi_10_mb.

Note 2: 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 3: The image files created in step 7.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.

Committer:
alindvall
Date:
Mon May 16 08:13:27 2016 +0000
Revision:
1:b04139d88c59
Parent:
0:06e35dd73c95
Added support for formatting of QSPI file system via special files.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
alindvall 0:06e35dd73c95 1 /******************************************************************************
alindvall 0:06e35dd73c95 2 * Includes
alindvall 0:06e35dd73c95 3 *****************************************************************************/
alindvall 1:b04139d88c59 4
alindvall 0:06e35dd73c95 5 #include "mbed.h"
alindvall 0:06e35dd73c95 6 #include "mbed_interface.h"
alindvall 0:06e35dd73c95 7 #include "rtos.h"
alindvall 0:06e35dd73c95 8
alindvall 0:06e35dd73c95 9 #include "DMBoard.h"
alindvall 0:06e35dd73c95 10 #include "RAMFileSystem.h"
alindvall 0:06e35dd73c95 11 #include "USBMSD_RAMFS.h"
alindvall 0:06e35dd73c95 12
alindvall 0:06e35dd73c95 13 #include "crc.h"
alindvall 0:06e35dd73c95 14
alindvall 0:06e35dd73c95 15 #include "lpc_swim.h"
alindvall 0:06e35dd73c95 16 #include "lpc_swim_font.h"
alindvall 0:06e35dd73c95 17 #include "lpc_winfreesystem14x16.h"
alindvall 0:06e35dd73c95 18
alindvall 0:06e35dd73c95 19 /******************************************************************************
alindvall 0:06e35dd73c95 20 * Typedefs and defines
alindvall 0:06e35dd73c95 21 *****************************************************************************/
alindvall 0:06e35dd73c95 22
alindvall 0:06e35dd73c95 23 typedef bool (*syncFunc)(const char* name, bool isDir);
alindvall 0:06e35dd73c95 24
alindvall 0:06e35dd73c95 25 /* Size of RAM file system */
alindvall 0:06e35dd73c95 26 #define RAM_FS_SIZE (20*1024*1024)
alindvall 0:06e35dd73c95 27
alindvall 0:06e35dd73c95 28
alindvall 0:06e35dd73c95 29 /******************************************************************************
alindvall 0:06e35dd73c95 30 * Local variables
alindvall 0:06e35dd73c95 31 *****************************************************************************/
alindvall 0:06e35dd73c95 32
alindvall 0:06e35dd73c95 33 //DigitalOut myled1(LED1);
alindvall 0:06e35dd73c95 34 //DigitalOut myled2(LED2);
alindvall 0:06e35dd73c95 35 //DigitalIn button(p23);
alindvall 0:06e35dd73c95 36
alindvall 0:06e35dd73c95 37 //DigitalOut myled(LED1);
alindvall 0:06e35dd73c95 38 static char lsbuff[NAME_MAX+1];
alindvall 0:06e35dd73c95 39
alindvall 0:06e35dd73c95 40 static char image_file_name[128] = { '\0' };
alindvall 0:06e35dd73c95 41
alindvall 0:06e35dd73c95 42 /******************************************************************************
alindvall 0:06e35dd73c95 43 * Local functions
alindvall 0:06e35dd73c95 44 *****************************************************************************/
alindvall 0:06e35dd73c95 45
alindvall 0:06e35dd73c95 46
alindvall 0:06e35dd73c95 47 static void ledShowProgress()
alindvall 0:06e35dd73c95 48 {
alindvall 0:06e35dd73c95 49 static int state = 0;
alindvall 0:06e35dd73c95 50 state = (state + 1) % 2;
alindvall 1:b04139d88c59 51
alindvall 1:b04139d88c59 52 DMBoard* board = &DMBoard::instance();
alindvall 1:b04139d88c59 53 board->setLED(DMBoard::Led1, state==0);
alindvall 1:b04139d88c59 54 board->setLED(DMBoard::Led2, state!=0);
alindvall 0:06e35dd73c95 55 }
alindvall 0:06e35dd73c95 56
alindvall 0:06e35dd73c95 57 static void handleError(const char* msg)
alindvall 0:06e35dd73c95 58 {
alindvall 1:b04139d88c59 59 DMBoard* board = &DMBoard::instance();
alindvall 1:b04139d88c59 60 board->logger()->printf(msg);
alindvall 0:06e35dd73c95 61 while(true) {
alindvall 0:06e35dd73c95 62 board->setLED(DMBoard::Led1, false);
alindvall 0:06e35dd73c95 63 board->setLED(DMBoard::Led2, false);
alindvall 0:06e35dd73c95 64 wait(0.3);
alindvall 0:06e35dd73c95 65 board->setLED(DMBoard::Led1, true);
alindvall 0:06e35dd73c95 66 board->setLED(DMBoard::Led2, true);
alindvall 0:06e35dd73c95 67 wait(0.3);
alindvall 0:06e35dd73c95 68 }
alindvall 0:06e35dd73c95 69 }
alindvall 0:06e35dd73c95 70
alindvall 0:06e35dd73c95 71 static void waitForButtonPress()
alindvall 0:06e35dd73c95 72 {
alindvall 1:b04139d88c59 73 DMBoard* board = &DMBoard::instance();
alindvall 0:06e35dd73c95 74 printf("Press button to sync file systems\n");
alindvall 0:06e35dd73c95 75
alindvall 0:06e35dd73c95 76 board->setLED(DMBoard::Led1, false);
alindvall 0:06e35dd73c95 77 board->setLED(DMBoard::Led2, false);
alindvall 0:06e35dd73c95 78 while(!board->buttonPressed()) {
alindvall 0:06e35dd73c95 79 wait(0.1);
alindvall 0:06e35dd73c95 80 }
alindvall 0:06e35dd73c95 81 board->setLED(DMBoard::Led1, true);
alindvall 0:06e35dd73c95 82 printf("Button pressed, now release it\n");
alindvall 0:06e35dd73c95 83 while(board->buttonPressed()) {
alindvall 0:06e35dd73c95 84 wait(0.1);
alindvall 0:06e35dd73c95 85 }
alindvall 0:06e35dd73c95 86 }
alindvall 0:06e35dd73c95 87
alindvall 0:06e35dd73c95 88 static void addNotFormattedFile()
alindvall 0:06e35dd73c95 89 {
alindvall 0:06e35dd73c95 90 FILE *fp = fopen("/ram/qspi_not_formatted.txt", "w");
alindvall 0:06e35dd73c95 91 if (fp != NULL) {
alindvall 1:b04139d88c59 92 fprintf(fp, "The QSPI file system has not be formatted. To format create a\n");
alindvall 1:b04139d88c59 93 fprintf(fp, "file with the name \"format_qspi_X_mb\" on the drive and then\n");
alindvall 1:b04139d88c59 94 fprintf(fp, "press the USER/ISP/SW1 button to format\n");
alindvall 1:b04139d88c59 95 fprintf(fp, "The X in the file name should be replaced with the desired\n");
alindvall 1:b04139d88c59 96 fprintf(fp, "file system size in Mb (1 to 16). For a 10 Mb file sytem the file\n");
alindvall 1:b04139d88c59 97 fprintf(fp, "name would be format_qspi_10_mb.\n");
alindvall 0:06e35dd73c95 98 fclose(fp);
alindvall 0:06e35dd73c95 99 }
alindvall 0:06e35dd73c95 100 }
alindvall 0:06e35dd73c95 101
alindvall 0:06e35dd73c95 102 static bool recursiveProcessFS(char* buff, const char* name, syncFunc func, bool adding)
alindvall 0:06e35dd73c95 103 {
alindvall 0:06e35dd73c95 104 uint32_t len = strlen(buff);
alindvall 0:06e35dd73c95 105 if (len > 0) {
alindvall 0:06e35dd73c95 106 if (buff[len - 1] != '/') {
alindvall 0:06e35dd73c95 107 buff[len++] = '/';
alindvall 0:06e35dd73c95 108 buff[len] = '\0';
alindvall 0:06e35dd73c95 109 }
alindvall 0:06e35dd73c95 110 }
alindvall 0:06e35dd73c95 111 strcat(buff, name);
alindvall 0:06e35dd73c95 112 len += strlen(name);
alindvall 0:06e35dd73c95 113
alindvall 0:06e35dd73c95 114 DIR *d = opendir(buff);
alindvall 0:06e35dd73c95 115 bool result = true; // success
alindvall 0:06e35dd73c95 116 if (d != NULL) {
alindvall 0:06e35dd73c95 117 if (adding) {
alindvall 0:06e35dd73c95 118 // when processing in adding mode folders must be created before it's content
alindvall 0:06e35dd73c95 119 result = func(buff, true);
alindvall 0:06e35dd73c95 120 }
alindvall 0:06e35dd73c95 121 struct dirent *p;
alindvall 0:06e35dd73c95 122 while (result && ((p = readdir(d)) != NULL)) {
alindvall 0:06e35dd73c95 123 result = recursiveProcessFS(buff, p->d_name, func, adding);
alindvall 0:06e35dd73c95 124 buff[len] = '\0';
alindvall 0:06e35dd73c95 125 }
alindvall 0:06e35dd73c95 126 closedir(d);
alindvall 0:06e35dd73c95 127 if (result && !adding) {
alindvall 0:06e35dd73c95 128 // when processing in removing mode folders must be deleted after it's content
alindvall 0:06e35dd73c95 129 result = func(buff, true);
alindvall 0:06e35dd73c95 130 }
alindvall 0:06e35dd73c95 131 } else {
alindvall 0:06e35dd73c95 132 // a file
alindvall 0:06e35dd73c95 133 result = func(buff, false);
alindvall 0:06e35dd73c95 134 }
alindvall 0:06e35dd73c95 135 return result;
alindvall 0:06e35dd73c95 136 }
alindvall 0:06e35dd73c95 137
alindvall 0:06e35dd73c95 138 static uint32_t fileLen(FILE* f)
alindvall 0:06e35dd73c95 139 {
alindvall 0:06e35dd73c95 140 uint32_t pos = ftell(f);
alindvall 0:06e35dd73c95 141 fseek(f, 0, SEEK_END);
alindvall 0:06e35dd73c95 142 uint32_t size = ftell(f);
alindvall 0:06e35dd73c95 143 fseek(f, pos, SEEK_SET);
alindvall 0:06e35dd73c95 144 return size;
alindvall 0:06e35dd73c95 145 }
alindvall 0:06e35dd73c95 146
alindvall 0:06e35dd73c95 147 static bool copy(FILE* fSrc, FILE* fDst)
alindvall 0:06e35dd73c95 148 {
alindvall 0:06e35dd73c95 149 char buff[512];
alindvall 0:06e35dd73c95 150 uint32_t left = fileLen(fSrc);
alindvall 0:06e35dd73c95 151 uint32_t num;
alindvall 0:06e35dd73c95 152 uint32_t chunk;
alindvall 0:06e35dd73c95 153
alindvall 0:06e35dd73c95 154 fseek(fSrc, 0, SEEK_SET);
alindvall 0:06e35dd73c95 155 do {
alindvall 0:06e35dd73c95 156 chunk = (left < 512) ? left : 512;
alindvall 0:06e35dd73c95 157 num = fread(buff, 1, chunk, fSrc);
alindvall 0:06e35dd73c95 158 if (num > 0) {
alindvall 0:06e35dd73c95 159 uint32_t tmp = fwrite(buff, 1, num, fDst);
alindvall 0:06e35dd73c95 160 if (tmp != num) {
alindvall 0:06e35dd73c95 161 // failed to write
alindvall 0:06e35dd73c95 162 return false;
alindvall 0:06e35dd73c95 163 }
alindvall 0:06e35dd73c95 164 left -= num;
alindvall 0:06e35dd73c95 165 ledShowProgress();
alindvall 0:06e35dd73c95 166 }
alindvall 0:06e35dd73c95 167 } while(num > 0 && left > 0);
alindvall 0:06e35dd73c95 168
alindvall 0:06e35dd73c95 169 // copied entire file
alindvall 0:06e35dd73c95 170 return true;
alindvall 0:06e35dd73c95 171 }
alindvall 0:06e35dd73c95 172
alindvall 0:06e35dd73c95 173 static bool identicalFiles(const char* srcName, const char* dstName)
alindvall 0:06e35dd73c95 174 {
alindvall 0:06e35dd73c95 175 FILE* fSrc = NULL;
alindvall 0:06e35dd73c95 176 FILE* fDst = NULL;
alindvall 0:06e35dd73c95 177 bool identical = false;
alindvall 0:06e35dd73c95 178 do
alindvall 0:06e35dd73c95 179 {
alindvall 0:06e35dd73c95 180 fSrc = fopen(srcName, "r");
alindvall 0:06e35dd73c95 181 if (fSrc == NULL) {
alindvall 0:06e35dd73c95 182 break;
alindvall 0:06e35dd73c95 183 }
alindvall 0:06e35dd73c95 184 fDst = fopen(dstName, "r");
alindvall 0:06e35dd73c95 185 if (fDst == NULL) {
alindvall 0:06e35dd73c95 186 break;
alindvall 0:06e35dd73c95 187 }
alindvall 0:06e35dd73c95 188 if (fileLen(fSrc) != fileLen(fDst)) {
alindvall 0:06e35dd73c95 189 break;
alindvall 0:06e35dd73c95 190 }
alindvall 0:06e35dd73c95 191 if (crc_File(fSrc) != crc_File(fDst)) {
alindvall 0:06e35dd73c95 192 break;
alindvall 0:06e35dd73c95 193 }
alindvall 0:06e35dd73c95 194
alindvall 0:06e35dd73c95 195 // All tests passed so the files are identical
alindvall 0:06e35dd73c95 196 identical = true;
alindvall 0:06e35dd73c95 197
alindvall 0:06e35dd73c95 198 } while(false);
alindvall 0:06e35dd73c95 199
alindvall 0:06e35dd73c95 200 if (fSrc != NULL) {
alindvall 0:06e35dd73c95 201 fclose(fSrc);
alindvall 0:06e35dd73c95 202 }
alindvall 0:06e35dd73c95 203 if (fDst != NULL) {
alindvall 0:06e35dd73c95 204 fclose(fDst);
alindvall 0:06e35dd73c95 205 }
alindvall 0:06e35dd73c95 206
alindvall 0:06e35dd73c95 207 return identical;
alindvall 0:06e35dd73c95 208 }
alindvall 0:06e35dd73c95 209
alindvall 0:06e35dd73c95 210 static bool addExisting(const char* srcName, bool isDir, const char* dstName)
alindvall 0:06e35dd73c95 211 {
alindvall 0:06e35dd73c95 212 bool result = true; // success
alindvall 0:06e35dd73c95 213 if (isDir) {
alindvall 0:06e35dd73c95 214 DIR *d = opendir(dstName);
alindvall 0:06e35dd73c95 215 if (d == NULL) {
alindvall 0:06e35dd73c95 216 if (dstName[1] != 'r') { printf("%s, new dir, adding\n", dstName); }
alindvall 0:06e35dd73c95 217 if (mkdir(dstName, 0) != 0) {
alindvall 0:06e35dd73c95 218 printf("Failed to create folder %s\n", dstName);
alindvall 0:06e35dd73c95 219 result = false; // dir did not exist and could not be created
alindvall 0:06e35dd73c95 220 }
alindvall 0:06e35dd73c95 221 } else {
alindvall 0:06e35dd73c95 222 closedir(d);
alindvall 0:06e35dd73c95 223 }
alindvall 0:06e35dd73c95 224 } else if (!identicalFiles(srcName, dstName)) {
alindvall 0:06e35dd73c95 225 // Compare the files to avoid replacing with same
alindvall 0:06e35dd73c95 226 FILE* fSrc = fopen(srcName, "r");
alindvall 0:06e35dd73c95 227 if (fSrc != NULL) {
alindvall 0:06e35dd73c95 228 FILE* fDst = fopen(dstName, "w"); // open and truncate
alindvall 0:06e35dd73c95 229 if (fDst != NULL) {
alindvall 0:06e35dd73c95 230 if (dstName[1] != 'r') { printf("%s, changed, updating\n", dstName); }
alindvall 0:06e35dd73c95 231 result = copy(fSrc, fDst);
alindvall 0:06e35dd73c95 232 if (!result) {
alindvall 0:06e35dd73c95 233 printf("Failed to copy %s to %s\n", srcName, dstName);
alindvall 0:06e35dd73c95 234 }
alindvall 0:06e35dd73c95 235 fclose(fDst);
alindvall 0:06e35dd73c95 236 } else {
alindvall 0:06e35dd73c95 237 printf("Failed to create file %s\n", dstName);
alindvall 0:06e35dd73c95 238 result = false; // unable to create file
alindvall 0:06e35dd73c95 239 }
alindvall 0:06e35dd73c95 240 fclose(fSrc);
alindvall 0:06e35dd73c95 241 } else {
alindvall 0:06e35dd73c95 242 printf("Failed to copen source file file %s\n", srcName);
alindvall 0:06e35dd73c95 243 result = false; // unable to open source
alindvall 0:06e35dd73c95 244 }
alindvall 0:06e35dd73c95 245 } else {
alindvall 0:06e35dd73c95 246 if (dstName[1] != 'r') { printf("%s identical, skipping\n", dstName); }
alindvall 0:06e35dd73c95 247 }
alindvall 0:06e35dd73c95 248 return result;
alindvall 0:06e35dd73c95 249 }
alindvall 0:06e35dd73c95 250
alindvall 0:06e35dd73c95 251 static bool addExistingToQspi(const char* name, bool isDir)
alindvall 0:06e35dd73c95 252 {
alindvall 0:06e35dd73c95 253 // create the target file name by replacing /ram/ with /qspi/
alindvall 0:06e35dd73c95 254 char buff[256];
alindvall 0:06e35dd73c95 255 buff[0] = '\0';
alindvall 0:06e35dd73c95 256 strcat(buff, "/qspi/");
alindvall 0:06e35dd73c95 257 strcat(buff, name+5);
alindvall 0:06e35dd73c95 258
alindvall 0:06e35dd73c95 259 // Don't add the file created by createImageFile()
alindvall 0:06e35dd73c95 260 if (strcmp(name, image_file_name) == 0) {
alindvall 0:06e35dd73c95 261 return true;
alindvall 0:06e35dd73c95 262 }
alindvall 0:06e35dd73c95 263
alindvall 0:06e35dd73c95 264 return addExisting(name, isDir, buff);
alindvall 0:06e35dd73c95 265 }
alindvall 0:06e35dd73c95 266
alindvall 0:06e35dd73c95 267 static bool addExistingToRAM(const char* name, bool isDir)
alindvall 0:06e35dd73c95 268 {
alindvall 0:06e35dd73c95 269 // create the target file name by replacing /qspi/ with /ram/
alindvall 0:06e35dd73c95 270 char buff[256];
alindvall 0:06e35dd73c95 271 buff[0] = '\0';
alindvall 0:06e35dd73c95 272 strcat(buff, "/ram/");
alindvall 0:06e35dd73c95 273 strcat(buff, name+6);
alindvall 0:06e35dd73c95 274 return addExisting(name, isDir, buff);
alindvall 0:06e35dd73c95 275 }
alindvall 0:06e35dd73c95 276
alindvall 0:06e35dd73c95 277 static bool removeIfMissing(const char* toLookFor, const char* toRemove, bool isDir)
alindvall 0:06e35dd73c95 278 {
alindvall 0:06e35dd73c95 279 int result = 0; //success
alindvall 0:06e35dd73c95 280 if (isDir) {
alindvall 0:06e35dd73c95 281 DIR *d = opendir(toLookFor);
alindvall 0:06e35dd73c95 282 if (d == NULL) {
alindvall 0:06e35dd73c95 283 // dir doesn't exist => delete it
alindvall 0:06e35dd73c95 284 if (toRemove[1] != 'r') { printf("%s, missing, deleting dir\n", toRemove); }
alindvall 0:06e35dd73c95 285 result = remove(toRemove);
alindvall 0:06e35dd73c95 286 ledShowProgress();
alindvall 0:06e35dd73c95 287 } else {
alindvall 0:06e35dd73c95 288 // dir exist => don't delete
alindvall 0:06e35dd73c95 289 closedir(d);
alindvall 0:06e35dd73c95 290 }
alindvall 0:06e35dd73c95 291 } else {
alindvall 0:06e35dd73c95 292 FILE* f = fopen(toLookFor, "r");
alindvall 0:06e35dd73c95 293 if (f == NULL) {
alindvall 0:06e35dd73c95 294 // file doesn't exist => delete it
alindvall 0:06e35dd73c95 295 if (toRemove[1] != 'r') { printf("%s, missing, deleting file\n", toRemove); }
alindvall 0:06e35dd73c95 296 result = remove(toRemove);
alindvall 0:06e35dd73c95 297 ledShowProgress();
alindvall 0:06e35dd73c95 298 } else {
alindvall 0:06e35dd73c95 299 // file exist => don't delete
alindvall 0:06e35dd73c95 300 fclose(f);
alindvall 0:06e35dd73c95 301 }
alindvall 0:06e35dd73c95 302 }
alindvall 0:06e35dd73c95 303 return (result == 0);
alindvall 0:06e35dd73c95 304 }
alindvall 0:06e35dd73c95 305
alindvall 0:06e35dd73c95 306 static bool removeMissingFromQspi(const char* name, bool isDir)
alindvall 0:06e35dd73c95 307 {
alindvall 0:06e35dd73c95 308 // create the target file name by replacing /qspi/ with /ram/
alindvall 0:06e35dd73c95 309 char buff[256];
alindvall 0:06e35dd73c95 310 buff[0] = '\0';
alindvall 0:06e35dd73c95 311 strcat(buff, "/ram/");
alindvall 0:06e35dd73c95 312 strcat(buff, name+6);
alindvall 0:06e35dd73c95 313 removeIfMissing(buff, name, isDir);
alindvall 0:06e35dd73c95 314 return true;
alindvall 0:06e35dd73c95 315 }
alindvall 0:06e35dd73c95 316
alindvall 0:06e35dd73c95 317 static bool removeMissingFromRAM(const char* name, bool isDir)
alindvall 0:06e35dd73c95 318 {
alindvall 0:06e35dd73c95 319 // create the target file name by replacing /ram/ with /qspi/
alindvall 0:06e35dd73c95 320 char buff[256];
alindvall 0:06e35dd73c95 321 buff[0] = '\0';
alindvall 0:06e35dd73c95 322 strcat(buff, "/qspi/");
alindvall 0:06e35dd73c95 323 strcat(buff, name+5);
alindvall 0:06e35dd73c95 324
alindvall 0:06e35dd73c95 325 // Don't remove the file created by createImageFile()
alindvall 0:06e35dd73c95 326 if (strcmp(name, image_file_name) == 0) {
alindvall 0:06e35dd73c95 327 return true;
alindvall 0:06e35dd73c95 328 }
alindvall 0:06e35dd73c95 329
alindvall 0:06e35dd73c95 330 removeIfMissing(buff, name, isDir);
alindvall 0:06e35dd73c95 331 return true;
alindvall 0:06e35dd73c95 332 }
alindvall 0:06e35dd73c95 333
alindvall 0:06e35dd73c95 334 static void syncDir(const char* to, const char* from)
alindvall 0:06e35dd73c95 335 {
alindvall 0:06e35dd73c95 336 printf("Starting to sync %s on top of %s (This may take time. LED1 & 2 blink for each file)\n", from, to);
alindvall 0:06e35dd73c95 337
alindvall 0:06e35dd73c95 338 char* buff = (char*)malloc(512);
alindvall 0:06e35dd73c95 339 if (buff != NULL)
alindvall 0:06e35dd73c95 340 {
alindvall 0:06e35dd73c95 341 buff[0] = '\0';
alindvall 0:06e35dd73c95 342 if (strcmp(to, "/qspi/") == 0) {
alindvall 0:06e35dd73c95 343 if (!recursiveProcessFS(buff, to, removeMissingFromQspi, false)) {
alindvall 0:06e35dd73c95 344 printf("Failed to remove files from %s that were missing on %s\n", to, from);
alindvall 0:06e35dd73c95 345 } else {
alindvall 0:06e35dd73c95 346 buff[0] = '\0';
alindvall 0:06e35dd73c95 347 if (!recursiveProcessFS(buff, from, addExistingToQspi, true)) {
alindvall 0:06e35dd73c95 348 printf("Failed to add files to %s that existed on %s\n", to, from);
alindvall 0:06e35dd73c95 349 }
alindvall 0:06e35dd73c95 350 }
alindvall 0:06e35dd73c95 351 } else {
alindvall 0:06e35dd73c95 352 if (!recursiveProcessFS(buff, to, removeMissingFromRAM, false)) {
alindvall 0:06e35dd73c95 353 printf("Failed to remove files from %s that were missing on %s\n", to, from);
alindvall 0:06e35dd73c95 354 } else {
alindvall 0:06e35dd73c95 355 buff[0] = '\0';
alindvall 0:06e35dd73c95 356 if (!recursiveProcessFS(buff, from, addExistingToRAM, true)) {
alindvall 0:06e35dd73c95 357 printf("Failed to add files to %s that existed on %s\n", to, from);
alindvall 0:06e35dd73c95 358 }
alindvall 0:06e35dd73c95 359 }
alindvall 0:06e35dd73c95 360 }
alindvall 0:06e35dd73c95 361 free(buff);
alindvall 0:06e35dd73c95 362 }
alindvall 0:06e35dd73c95 363 printf("Sync completed\n");
alindvall 0:06e35dd73c95 364 }
alindvall 0:06e35dd73c95 365
alindvall 0:06e35dd73c95 366
alindvall 0:06e35dd73c95 367 static void createImageFile(QSPIFileSystem* qspi)
alindvall 0:06e35dd73c95 368 {
alindvall 0:06e35dd73c95 369 uint32_t startAddr;
alindvall 0:06e35dd73c95 370 uint32_t endAddr;
alindvall 0:06e35dd73c95 371 uint32_t size;
alindvall 0:06e35dd73c95 372
alindvall 0:06e35dd73c95 373 printf("Creating image of existing (if any) QSPI file system\n");
alindvall 0:06e35dd73c95 374
alindvall 0:06e35dd73c95 375 if (!qspi->getMemoryBoundaries(&startAddr, &endAddr))
alindvall 0:06e35dd73c95 376 {
alindvall 0:06e35dd73c95 377 handleError("QSPI FS not formatted or impossible to determine it's size\n");
alindvall 0:06e35dd73c95 378 }
alindvall 0:06e35dd73c95 379
alindvall 0:06e35dd73c95 380 // Align the start address to an even multiple of 1MB
alindvall 0:06e35dd73c95 381 startAddr = startAddr & 0xfff00000;
alindvall 0:06e35dd73c95 382
alindvall 0:06e35dd73c95 383 // Update the file to match the size of the file system
alindvall 0:06e35dd73c95 384 size = endAddr - startAddr;
alindvall 0:06e35dd73c95 385 if ((size < 0x00100000) || (size > 0x01000000) || ((size & 0xfffff) > 0))
alindvall 0:06e35dd73c95 386 {
alindvall 0:06e35dd73c95 387 sprintf(lsbuff, "QSPI FS size is not supported (%u bytes)\n", size);
alindvall 0:06e35dd73c95 388 handleError(lsbuff);
alindvall 0:06e35dd73c95 389 }
alindvall 0:06e35dd73c95 390 sprintf(image_file_name, "/ram/.current/fs_image.fs%d", (size >> 20));
alindvall 1:b04139d88c59 391
alindvall 0:06e35dd73c95 392 // NOTE: The line below is very very !!!! important. For some weird reason the
alindvall 0:06e35dd73c95 393 // RAM file system must have at least one folder on it before USB is connected.
alindvall 0:06e35dd73c95 394 // If the RAM file system doesn't have any folders on it the result is that
alindvall 0:06e35dd73c95 395 // the content of the RAM file system will be the same after USB is disconnected
alindvall 0:06e35dd73c95 396 // as it was before connecting - regardless of what is added. Very strange indeed.
alindvall 0:06e35dd73c95 397 mkdir("/ram/.current", 0);
alindvall 0:06e35dd73c95 398
alindvall 0:06e35dd73c95 399 printf("QSPI FS max size is %d MB\n", (size >> 20));
alindvall 0:06e35dd73c95 400
alindvall 0:06e35dd73c95 401 FILE *fp = fopen(image_file_name, "w");
alindvall 0:06e35dd73c95 402 if (fp != NULL)
alindvall 0:06e35dd73c95 403 {
alindvall 0:06e35dd73c95 404 while (size > 0)
alindvall 0:06e35dd73c95 405 {
alindvall 0:06e35dd73c95 406 uint32_t written = fwrite((char*)(endAddr - size), 1, size, fp);
alindvall 0:06e35dd73c95 407 size -= written;
alindvall 0:06e35dd73c95 408 if (written == 0)
alindvall 0:06e35dd73c95 409 {
alindvall 0:06e35dd73c95 410 handleError("Failed to create QSPI image file\n");
alindvall 0:06e35dd73c95 411 }
alindvall 0:06e35dd73c95 412 }
alindvall 0:06e35dd73c95 413 fclose(fp);
alindvall 0:06e35dd73c95 414 }
alindvall 0:06e35dd73c95 415 }
alindvall 0:06e35dd73c95 416
alindvall 0:06e35dd73c95 417 static bool list(const char* name, bool isDir)
alindvall 0:06e35dd73c95 418 {
alindvall 0:06e35dd73c95 419 if (isDir) {
alindvall 0:06e35dd73c95 420 printf("d: %s\n", name);
alindvall 0:06e35dd73c95 421 } else {
alindvall 0:06e35dd73c95 422 FILE* f = fopen(name, "r");
alindvall 0:06e35dd73c95 423 if (f != NULL) {
alindvall 0:06e35dd73c95 424 uint32_t len = fileLen(f);
alindvall 0:06e35dd73c95 425 printf("f: %7u %s\n", len, name);
alindvall 0:06e35dd73c95 426 fclose(f);
alindvall 0:06e35dd73c95 427 } else {
alindvall 0:06e35dd73c95 428 printf("f: ??? %s\n", name);
alindvall 0:06e35dd73c95 429 }
alindvall 0:06e35dd73c95 430 }
alindvall 0:06e35dd73c95 431 return true;
alindvall 0:06e35dd73c95 432 }
alindvall 0:06e35dd73c95 433
alindvall 0:06e35dd73c95 434 static void recursiveList(const char* dirname)
alindvall 0:06e35dd73c95 435 {
alindvall 0:06e35dd73c95 436 printf("\nRecursive list of file and folders in %s\n", dirname);
alindvall 0:06e35dd73c95 437 char* buff = (char*)malloc(512);
alindvall 0:06e35dd73c95 438 if (buff != NULL)
alindvall 0:06e35dd73c95 439 {
alindvall 0:06e35dd73c95 440 buff[0] = '\0';
alindvall 0:06e35dd73c95 441 recursiveProcessFS(buff, dirname, list, true);
alindvall 0:06e35dd73c95 442 free(buff);
alindvall 0:06e35dd73c95 443 }
alindvall 0:06e35dd73c95 444 }
alindvall 0:06e35dd73c95 445
alindvall 1:b04139d88c59 446 static bool formatIfRequested()
alindvall 1:b04139d88c59 447 {
alindvall 1:b04139d88c59 448 DMBoard* board = &DMBoard::instance();
alindvall 1:b04139d88c59 449 RtosLog* logger = board->logger();
alindvall 1:b04139d88c59 450 char marker[50];
alindvall 1:b04139d88c59 451 int size;
alindvall 1:b04139d88c59 452 uint32_t maxSize = SPIFI::instance().memorySize()>>20;
alindvall 1:b04139d88c59 453
alindvall 1:b04139d88c59 454 for (size = 1; size <= maxSize; size++) {
alindvall 1:b04139d88c59 455 sprintf(marker, "/ram/format_qspi_%d_mb", size);
alindvall 1:b04139d88c59 456 FILE *fp = fopen(marker, "r");
alindvall 1:b04139d88c59 457 if (fp != NULL) {
alindvall 1:b04139d88c59 458 logger->printf("Found a marker file requesting to place a %d Mb file system on QSPI\n", size);
alindvall 1:b04139d88c59 459 logger->printf("This operation may take up to a couple of minutes!\n");
alindvall 1:b04139d88c59 460 QSPIFileSystem* qspi = board->getQspiFS();
alindvall 1:b04139d88c59 461
alindvall 1:b04139d88c59 462 int err = qspi->format(size);
alindvall 1:b04139d88c59 463 if (err == 0) {
alindvall 1:b04139d88c59 464 logger->printf("Successfully added a %d Mb file system to QSPI!\n", size);
alindvall 1:b04139d88c59 465 } else {
alindvall 1:b04139d88c59 466 logger->printf("Failed to format QSPI!\n");
alindvall 1:b04139d88c59 467 }
alindvall 1:b04139d88c59 468 // formatting was requested
alindvall 1:b04139d88c59 469 return true;
alindvall 1:b04139d88c59 470 }
alindvall 1:b04139d88c59 471 }
alindvall 1:b04139d88c59 472 // no formatting requested
alindvall 1:b04139d88c59 473 return false;
alindvall 1:b04139d88c59 474 }
alindvall 1:b04139d88c59 475
alindvall 0:06e35dd73c95 476 static void showInfoScreen()
alindvall 0:06e35dd73c95 477 {
alindvall 1:b04139d88c59 478 static SWIM_WINDOW_T* win = NULL;
alindvall 1:b04139d88c59 479 static void* fb = NULL;
alindvall 1:b04139d88c59 480
alindvall 0:06e35dd73c95 481 Display* disp = DMBoard::instance().display();
alindvall 0:06e35dd73c95 482 win = (SWIM_WINDOW_T*)malloc(sizeof(SWIM_WINDOW_T));
alindvall 0:06e35dd73c95 483 fb = disp->allocateFramebuffer();
alindvall 1:b04139d88c59 484
alindvall 1:b04139d88c59 485 swim_window_open(win,
alindvall 0:06e35dd73c95 486 disp->width(), disp->height(), // full size
alindvall 0:06e35dd73c95 487 (COLOR_T*)fb,
alindvall 0:06e35dd73c95 488 0,0,disp->width()-1, disp->height()-1, // window position and size
alindvall 0:06e35dd73c95 489 0, // border
alindvall 0:06e35dd73c95 490 BLUE, WHITE, BLACK); // colors: pen, backgr, forgr
alindvall 1:b04139d88c59 491
alindvall 1:b04139d88c59 492 swim_set_font(win, (FONT_T*)&font_winfreesys14x16);
alindvall 0:06e35dd73c95 493
alindvall 0:06e35dd73c95 494 // Show a message
alindvall 1:b04139d88c59 495 swim_put_text_centered_win(win, "In this version all instructions are printed on the console!", disp->height()/2 - 20);
alindvall 1:b04139d88c59 496 swim_put_text_centered_win(win, "Connect a terminal application using 115200, 8N1.", disp->height()/2 + 20);
alindvall 1:b04139d88c59 497
alindvall 0:06e35dd73c95 498 // Start display in default mode (16-bit)
alindvall 0:06e35dd73c95 499 Display::DisplayError disperr = disp->powerUp(fb);
alindvall 0:06e35dd73c95 500 if (disperr != Display::DisplayError_Ok) {
alindvall 0:06e35dd73c95 501 DMBoard::instance().logger()->printf("Failed to initialize the display, got error %d\r\n", disperr);
alindvall 0:06e35dd73c95 502 wait_ms(2000); // allow RtosLog to flush messages
alindvall 0:06e35dd73c95 503 mbed_die();
alindvall 0:06e35dd73c95 504 }
alindvall 0:06e35dd73c95 505 }
alindvall 0:06e35dd73c95 506
alindvall 0:06e35dd73c95 507 /******************************************************************************
alindvall 0:06e35dd73c95 508 * Main function
alindvall 0:06e35dd73c95 509 *****************************************************************************/
alindvall 0:06e35dd73c95 510 int main()
alindvall 0:06e35dd73c95 511 {
alindvall 0:06e35dd73c95 512 DMBoard::BoardError err;
alindvall 0:06e35dd73c95 513 DMBoard* board = &DMBoard::instance();
alindvall 0:06e35dd73c95 514 RtosLog* log = board->logger();
alindvall 0:06e35dd73c95 515 err = board->init();
alindvall 0:06e35dd73c95 516 if (err != DMBoard::Ok) {
alindvall 0:06e35dd73c95 517 log->printf("Failed to initialize the board, got error %d\r\n", err);
alindvall 0:06e35dd73c95 518 wait_ms(2000); // allow RtosLog to flush messages
alindvall 0:06e35dd73c95 519 mbed_die();
alindvall 0:06e35dd73c95 520 }
alindvall 1:b04139d88c59 521
alindvall 0:06e35dd73c95 522 log->printf("\n\n---\nQSPI file syncer app\nBuilt: " __DATE__ " at " __TIME__ "\n\n");
alindvall 0:06e35dd73c95 523
alindvall 1:b04139d88c59 524 showInfoScreen();
alindvall 1:b04139d88c59 525
alindvall 0:06e35dd73c95 526 // allocate a chunk of memory in the external SDRAM to use as a RAM file system
alindvall 0:06e35dd73c95 527 void* fsmem = malloc(RAM_FS_SIZE);
alindvall 0:06e35dd73c95 528 if (fsmem == NULL) {
alindvall 0:06e35dd73c95 529 log->printf("Failed to allocate memory for RAM file system\n");
alindvall 0:06e35dd73c95 530 mbed_die();
alindvall 0:06e35dd73c95 531 }
alindvall 1:b04139d88c59 532
alindvall 0:06e35dd73c95 533 // create a file system based on the allocated memory
alindvall 0:06e35dd73c95 534 RAMFileSystem ramfs((uint32_t)fsmem, RAM_FS_SIZE, "ram");
alindvall 1:b04139d88c59 535 USBMSD_RAMFS usbmsd(&ramfs);
alindvall 1:b04139d88c59 536
alindvall 1:b04139d88c59 537 while(true)
alindvall 1:b04139d88c59 538 {
alindvall 0:06e35dd73c95 539 // add an empty file system on it
alindvall 0:06e35dd73c95 540 ramfs.format();
alindvall 1:b04139d88c59 541
alindvall 1:b04139d88c59 542 QSPIFileSystem* qspi = board->getQspiFS();
alindvall 0:06e35dd73c95 543 bool qspiFormatted = qspi->isformatted();
alindvall 0:06e35dd73c95 544 if (!qspiFormatted)
alindvall 0:06e35dd73c95 545 {
alindvall 0:06e35dd73c95 546 addNotFormattedFile();
alindvall 0:06e35dd73c95 547 }
alindvall 1:b04139d88c59 548 else
alindvall 1:b04139d88c59 549 {
alindvall 0:06e35dd73c95 550 createImageFile(qspi);
alindvall 1:b04139d88c59 551
alindvall 0:06e35dd73c95 552 // Copy QSPI FS to RAM FS
alindvall 0:06e35dd73c95 553 syncDir("/ram/", "/qspi/");
alindvall 1:b04139d88c59 554 }
alindvall 1:b04139d88c59 555
alindvall 0:06e35dd73c95 556 printf("Insert the USB cable!\n");
alindvall 0:06e35dd73c95 557 printf("Starting USB...\n");
alindvall 0:06e35dd73c95 558 for (int i = 0; i < 10; i++)
alindvall 0:06e35dd73c95 559 {
alindvall 0:06e35dd73c95 560 if (usbmsd.connect())
alindvall 0:06e35dd73c95 561 {
alindvall 0:06e35dd73c95 562 printf("Connected!\n");
alindvall 0:06e35dd73c95 563 break;
alindvall 0:06e35dd73c95 564 }
alindvall 0:06e35dd73c95 565 printf("Failed to connect USB, testing again...\n");
alindvall 0:06e35dd73c95 566 printf("Insert (or remove and then insert) the USB cable!\n");
alindvall 0:06e35dd73c95 567 wait(1);
alindvall 0:06e35dd73c95 568 }
alindvall 0:06e35dd73c95 569
alindvall 1:b04139d88c59 570 waitForButtonPress();
alindvall 0:06e35dd73c95 571
alindvall 0:06e35dd73c95 572 usbmsd.disconnect();
alindvall 0:06e35dd73c95 573 printf("Disconnected!\n");
alindvall 0:06e35dd73c95 574
alindvall 1:b04139d88c59 575 // Look for (re)format instruction file
alindvall 1:b04139d88c59 576 if (formatIfRequested()) {
alindvall 1:b04139d88c59 577 continue;
alindvall 1:b04139d88c59 578 }
alindvall 1:b04139d88c59 579
alindvall 1:b04139d88c59 580 // Copy RAM FS to QSPI FS
alindvall 0:06e35dd73c95 581 recursiveList("/ram/");
alindvall 0:06e35dd73c95 582 syncDir("/qspi/", "/ram/");
alindvall 1:b04139d88c59 583 }
alindvall 0:06e35dd73c95 584 }
alindvall 0:06e35dd73c95 585