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 07:05:18 2016 +0000
Revision:
0:06e35dd73c95
Child:
1:b04139d88c59
First version

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