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
main.cpp
00001 /****************************************************************************** 00002 * Includes 00003 *****************************************************************************/ 00004 00005 #include "mbed.h" 00006 #include "mbed_interface.h" 00007 #include "rtos.h" 00008 00009 #include "DMBoard.h" 00010 #include "RAMFileSystem.h" 00011 #include "USBMSD_RAMFS.h" 00012 00013 #include "crc.h" 00014 00015 #include "lpc_swim.h" 00016 #include "lpc_swim_font.h" 00017 #include "lpc_winfreesystem14x16.h" 00018 00019 /****************************************************************************** 00020 * Typedefs and defines 00021 *****************************************************************************/ 00022 00023 typedef bool (*syncFunc)(const char* name, bool isDir); 00024 00025 /* Size of RAM file system */ 00026 #define RAM_FS_SIZE (20*1024*1024) 00027 00028 00029 /****************************************************************************** 00030 * Local variables 00031 *****************************************************************************/ 00032 00033 //DigitalOut myled1(LED1); 00034 //DigitalOut myled2(LED2); 00035 //DigitalIn button(p23); 00036 00037 //DigitalOut myled(LED1); 00038 static char lsbuff[NAME_MAX+1]; 00039 00040 static char image_file_name[128] = { '\0' }; 00041 00042 /****************************************************************************** 00043 * Local functions 00044 *****************************************************************************/ 00045 00046 00047 static void ledShowProgress() 00048 { 00049 static int state = 0; 00050 state = (state + 1) % 2; 00051 00052 DMBoard* board = &DMBoard::instance(); 00053 board->setLED(DMBoard::Led1, state==0); 00054 board->setLED(DMBoard::Led2, state!=0); 00055 } 00056 00057 static void handleError(const char* msg) 00058 { 00059 DMBoard* board = &DMBoard::instance(); 00060 board->logger()->printf(msg); 00061 while(true) { 00062 board->setLED(DMBoard::Led1, false); 00063 board->setLED(DMBoard::Led2, false); 00064 wait(0.3); 00065 board->setLED(DMBoard::Led1, true); 00066 board->setLED(DMBoard::Led2, true); 00067 wait(0.3); 00068 } 00069 } 00070 00071 static void waitForButtonPress() 00072 { 00073 DMBoard* board = &DMBoard::instance(); 00074 printf("Press button to sync file systems\n"); 00075 00076 board->setLED(DMBoard::Led1, false); 00077 board->setLED(DMBoard::Led2, false); 00078 while(!board->buttonPressed()) { 00079 wait(0.1); 00080 } 00081 board->setLED(DMBoard::Led1, true); 00082 printf("Button pressed, now release it\n"); 00083 while(board->buttonPressed()) { 00084 wait(0.1); 00085 } 00086 } 00087 00088 static void addNotFormattedFile() 00089 { 00090 FILE *fp = fopen("/ram/qspi_not_formatted.txt", "w"); 00091 if (fp != NULL) { 00092 fprintf(fp, "The QSPI file system has not be formatted. To format create a\n"); 00093 fprintf(fp, "file with the name \"format_qspi_X_mb\" on the drive and then\n"); 00094 fprintf(fp, "press the USER/ISP/SW1 button to format\n"); 00095 fprintf(fp, "The X in the file name should be replaced with the desired\n"); 00096 fprintf(fp, "file system size in Mb (1 to 16). For a 10 Mb file sytem the file\n"); 00097 fprintf(fp, "name would be format_qspi_10_mb.\n"); 00098 fclose(fp); 00099 } 00100 } 00101 00102 static bool recursiveProcessFS(char* buff, const char* name, syncFunc func, bool adding) 00103 { 00104 uint32_t len = strlen(buff); 00105 if (len > 0) { 00106 if (buff[len - 1] != '/') { 00107 buff[len++] = '/'; 00108 buff[len] = '\0'; 00109 } 00110 } 00111 strcat(buff, name); 00112 len += strlen(name); 00113 00114 DIR *d = opendir(buff); 00115 bool result = true; // success 00116 if (d != NULL) { 00117 if (adding) { 00118 // when processing in adding mode folders must be created before it's content 00119 result = func(buff, true); 00120 } 00121 struct dirent *p; 00122 while (result && ((p = readdir(d)) != NULL)) { 00123 result = recursiveProcessFS(buff, p->d_name, func, adding); 00124 buff[len] = '\0'; 00125 } 00126 closedir(d); 00127 if (result && !adding) { 00128 // when processing in removing mode folders must be deleted after it's content 00129 result = func(buff, true); 00130 } 00131 } else { 00132 // a file 00133 result = func(buff, false); 00134 } 00135 return result; 00136 } 00137 00138 static uint32_t fileLen(FILE* f) 00139 { 00140 uint32_t pos = ftell(f); 00141 fseek(f, 0, SEEK_END); 00142 uint32_t size = ftell(f); 00143 fseek(f, pos, SEEK_SET); 00144 return size; 00145 } 00146 00147 static bool copy(FILE* fSrc, FILE* fDst) 00148 { 00149 char buff[512]; 00150 uint32_t left = fileLen(fSrc); 00151 uint32_t num; 00152 uint32_t chunk; 00153 00154 fseek(fSrc, 0, SEEK_SET); 00155 do { 00156 chunk = (left < 512) ? left : 512; 00157 num = fread(buff, 1, chunk, fSrc); 00158 if (num > 0) { 00159 uint32_t tmp = fwrite(buff, 1, num, fDst); 00160 if (tmp != num) { 00161 // failed to write 00162 return false; 00163 } 00164 left -= num; 00165 ledShowProgress(); 00166 } 00167 } while(num > 0 && left > 0); 00168 00169 // copied entire file 00170 return true; 00171 } 00172 00173 static bool identicalFiles(const char* srcName, const char* dstName) 00174 { 00175 FILE* fSrc = NULL; 00176 FILE* fDst = NULL; 00177 bool identical = false; 00178 do 00179 { 00180 fSrc = fopen(srcName, "r"); 00181 if (fSrc == NULL) { 00182 break; 00183 } 00184 fDst = fopen(dstName, "r"); 00185 if (fDst == NULL) { 00186 break; 00187 } 00188 if (fileLen(fSrc) != fileLen(fDst)) { 00189 break; 00190 } 00191 if (crc_File(fSrc) != crc_File(fDst)) { 00192 break; 00193 } 00194 00195 // All tests passed so the files are identical 00196 identical = true; 00197 00198 } while(false); 00199 00200 if (fSrc != NULL) { 00201 fclose(fSrc); 00202 } 00203 if (fDst != NULL) { 00204 fclose(fDst); 00205 } 00206 00207 return identical; 00208 } 00209 00210 static bool addExisting(const char* srcName, bool isDir, const char* dstName) 00211 { 00212 bool result = true; // success 00213 if (isDir) { 00214 DIR *d = opendir(dstName); 00215 if (d == NULL) { 00216 if (dstName[1] != 'r') { printf("%s, new dir, adding\n", dstName); } 00217 if (mkdir(dstName, 0) != 0) { 00218 printf("Failed to create folder %s\n", dstName); 00219 result = false; // dir did not exist and could not be created 00220 } 00221 } else { 00222 closedir(d); 00223 } 00224 } else if (!identicalFiles(srcName, dstName)) { 00225 // Compare the files to avoid replacing with same 00226 FILE* fSrc = fopen(srcName, "r"); 00227 if (fSrc != NULL) { 00228 FILE* fDst = fopen(dstName, "w"); // open and truncate 00229 if (fDst != NULL) { 00230 if (dstName[1] != 'r') { printf("%s, changed, updating\n", dstName); } 00231 result = copy(fSrc, fDst); 00232 if (!result) { 00233 printf("Failed to copy %s to %s\n", srcName, dstName); 00234 } 00235 fclose(fDst); 00236 } else { 00237 printf("Failed to create file %s\n", dstName); 00238 result = false; // unable to create file 00239 } 00240 fclose(fSrc); 00241 } else { 00242 printf("Failed to copen source file file %s\n", srcName); 00243 result = false; // unable to open source 00244 } 00245 } else { 00246 if (dstName[1] != 'r') { printf("%s identical, skipping\n", dstName); } 00247 } 00248 return result; 00249 } 00250 00251 static bool addExistingToQspi(const char* name, bool isDir) 00252 { 00253 // create the target file name by replacing /ram/ with /qspi/ 00254 char buff[256]; 00255 buff[0] = '\0'; 00256 strcat(buff, "/qspi/"); 00257 strcat(buff, name+5); 00258 00259 // Don't add the file created by createImageFile() 00260 if (strcmp(name, image_file_name) == 0) { 00261 return true; 00262 } 00263 00264 return addExisting(name, isDir, buff); 00265 } 00266 00267 static bool addExistingToRAM(const char* name, bool isDir) 00268 { 00269 // create the target file name by replacing /qspi/ with /ram/ 00270 char buff[256]; 00271 buff[0] = '\0'; 00272 strcat(buff, "/ram/"); 00273 strcat(buff, name+6); 00274 return addExisting(name, isDir, buff); 00275 } 00276 00277 static bool removeIfMissing(const char* toLookFor, const char* toRemove, bool isDir) 00278 { 00279 int result = 0; //success 00280 if (isDir) { 00281 DIR *d = opendir(toLookFor); 00282 if (d == NULL) { 00283 // dir doesn't exist => delete it 00284 if (toRemove[1] != 'r') { printf("%s, missing, deleting dir\n", toRemove); } 00285 result = remove(toRemove); 00286 ledShowProgress(); 00287 } else { 00288 // dir exist => don't delete 00289 closedir(d); 00290 } 00291 } else { 00292 FILE* f = fopen(toLookFor, "r"); 00293 if (f == NULL) { 00294 // file doesn't exist => delete it 00295 if (toRemove[1] != 'r') { printf("%s, missing, deleting file\n", toRemove); } 00296 result = remove(toRemove); 00297 ledShowProgress(); 00298 } else { 00299 // file exist => don't delete 00300 fclose(f); 00301 } 00302 } 00303 return (result == 0); 00304 } 00305 00306 static bool removeMissingFromQspi(const char* name, bool isDir) 00307 { 00308 // create the target file name by replacing /qspi/ with /ram/ 00309 char buff[256]; 00310 buff[0] = '\0'; 00311 strcat(buff, "/ram/"); 00312 strcat(buff, name+6); 00313 removeIfMissing(buff, name, isDir); 00314 return true; 00315 } 00316 00317 static bool removeMissingFromRAM(const char* name, bool isDir) 00318 { 00319 // create the target file name by replacing /ram/ with /qspi/ 00320 char buff[256]; 00321 buff[0] = '\0'; 00322 strcat(buff, "/qspi/"); 00323 strcat(buff, name+5); 00324 00325 // Don't remove the file created by createImageFile() 00326 if (strcmp(name, image_file_name) == 0) { 00327 return true; 00328 } 00329 00330 removeIfMissing(buff, name, isDir); 00331 return true; 00332 } 00333 00334 static void syncDir(const char* to, const char* from) 00335 { 00336 printf("Starting to sync %s on top of %s (This may take time. LED1 & 2 blink for each file)\n", from, to); 00337 00338 char* buff = (char*)malloc(512); 00339 if (buff != NULL) 00340 { 00341 buff[0] = '\0'; 00342 if (strcmp(to, "/qspi/") == 0) { 00343 if (!recursiveProcessFS(buff, to, removeMissingFromQspi, false)) { 00344 printf("Failed to remove files from %s that were missing on %s\n", to, from); 00345 } else { 00346 buff[0] = '\0'; 00347 if (!recursiveProcessFS(buff, from, addExistingToQspi, true)) { 00348 printf("Failed to add files to %s that existed on %s\n", to, from); 00349 } 00350 } 00351 } else { 00352 if (!recursiveProcessFS(buff, to, removeMissingFromRAM, false)) { 00353 printf("Failed to remove files from %s that were missing on %s\n", to, from); 00354 } else { 00355 buff[0] = '\0'; 00356 if (!recursiveProcessFS(buff, from, addExistingToRAM, true)) { 00357 printf("Failed to add files to %s that existed on %s\n", to, from); 00358 } 00359 } 00360 } 00361 free(buff); 00362 } 00363 printf("Sync completed\n"); 00364 } 00365 00366 00367 static void createImageFile(QSPIFileSystem* qspi) 00368 { 00369 uint32_t startAddr; 00370 uint32_t endAddr; 00371 uint32_t size; 00372 00373 printf("Creating image of existing (if any) QSPI file system\n"); 00374 00375 if (!qspi->getMemoryBoundaries(&startAddr, &endAddr)) 00376 { 00377 handleError("QSPI FS not formatted or impossible to determine it's size\n"); 00378 } 00379 00380 // Align the start address to an even multiple of 1MB 00381 startAddr = startAddr & 0xfff00000; 00382 00383 // Update the file to match the size of the file system 00384 size = endAddr - startAddr; 00385 if ((size < 0x00100000) || (size > 0x01000000) || ((size & 0xfffff) > 0)) 00386 { 00387 sprintf(lsbuff, "QSPI FS size is not supported (%u bytes)\n", size); 00388 handleError(lsbuff); 00389 } 00390 sprintf(image_file_name, "/ram/.current/fs_image.fs%d", (size >> 20)); 00391 00392 // NOTE: The line below is very very !!!! important. For some weird reason the 00393 // RAM file system must have at least one folder on it before USB is connected. 00394 // If the RAM file system doesn't have any folders on it the result is that 00395 // the content of the RAM file system will be the same after USB is disconnected 00396 // as it was before connecting - regardless of what is added. Very strange indeed. 00397 mkdir("/ram/.current", 0); 00398 00399 printf("QSPI FS max size is %d MB\n", (size >> 20)); 00400 00401 FILE *fp = fopen(image_file_name, "w"); 00402 if (fp != NULL) 00403 { 00404 while (size > 0) 00405 { 00406 uint32_t written = fwrite((char*)(endAddr - size), 1, size, fp); 00407 size -= written; 00408 if (written == 0) 00409 { 00410 handleError("Failed to create QSPI image file\n"); 00411 } 00412 } 00413 fclose(fp); 00414 } 00415 } 00416 00417 static bool list(const char* name, bool isDir) 00418 { 00419 if (isDir) { 00420 printf("d: %s\n", name); 00421 } else { 00422 FILE* f = fopen(name, "r"); 00423 if (f != NULL) { 00424 uint32_t len = fileLen(f); 00425 printf("f: %7u %s\n", len, name); 00426 fclose(f); 00427 } else { 00428 printf("f: ??? %s\n", name); 00429 } 00430 } 00431 return true; 00432 } 00433 00434 static void recursiveList(const char* dirname) 00435 { 00436 printf("\nRecursive list of file and folders in %s\n", dirname); 00437 char* buff = (char*)malloc(512); 00438 if (buff != NULL) 00439 { 00440 buff[0] = '\0'; 00441 recursiveProcessFS(buff, dirname, list, true); 00442 free(buff); 00443 } 00444 } 00445 00446 static bool formatIfRequested() 00447 { 00448 DMBoard* board = &DMBoard::instance(); 00449 RtosLog* logger = board->logger(); 00450 char marker[50]; 00451 int size; 00452 uint32_t maxSize = SPIFI::instance().memorySize()>>20; 00453 00454 for (size = 1; size <= maxSize; size++) { 00455 sprintf(marker, "/ram/format_qspi_%d_mb", size); 00456 FILE *fp = fopen(marker, "r"); 00457 if (fp != NULL) { 00458 logger->printf("Found a marker file requesting to place a %d Mb file system on QSPI\n", size); 00459 logger->printf("This operation may take up to a couple of minutes!\n"); 00460 QSPIFileSystem* qspi = board->getQspiFS(); 00461 00462 int err = qspi->format(size); 00463 if (err == 0) { 00464 logger->printf("Successfully added a %d Mb file system to QSPI!\n", size); 00465 } else { 00466 logger->printf("Failed to format QSPI!\n"); 00467 } 00468 // formatting was requested 00469 return true; 00470 } 00471 } 00472 // no formatting requested 00473 return false; 00474 } 00475 00476 static void showInfoScreen() 00477 { 00478 static SWIM_WINDOW_T* win = NULL; 00479 static void* fb = NULL; 00480 00481 Display* disp = DMBoard::instance().display(); 00482 win = (SWIM_WINDOW_T*)malloc(sizeof(SWIM_WINDOW_T)); 00483 fb = disp->allocateFramebuffer(); 00484 00485 swim_window_open(win, 00486 disp->width(), disp->height(), // full size 00487 (COLOR_T*)fb, 00488 0,0,disp->width()-1, disp->height()-1, // window position and size 00489 0, // border 00490 BLUE, WHITE, BLACK); // colors: pen, backgr, forgr 00491 00492 swim_set_font(win, (FONT_T*)&font_winfreesys14x16); 00493 00494 // Show a message 00495 swim_put_text_centered_win(win, "In this version all instructions are printed on the console!", disp->height()/2 - 20); 00496 swim_put_text_centered_win(win, "Connect a terminal application using 115200, 8N1.", disp->height()/2 + 20); 00497 00498 // Start display in default mode (16-bit) 00499 Display::DisplayError disperr = disp->powerUp(fb); 00500 if (disperr != Display::DisplayError_Ok) { 00501 DMBoard::instance().logger()->printf("Failed to initialize the display, got error %d\r\n", disperr); 00502 wait_ms(2000); // allow RtosLog to flush messages 00503 mbed_die(); 00504 } 00505 } 00506 00507 /****************************************************************************** 00508 * Main function 00509 *****************************************************************************/ 00510 int main() 00511 { 00512 DMBoard::BoardError err; 00513 DMBoard* board = &DMBoard::instance(); 00514 RtosLog* log = board->logger(); 00515 err = board->init(); 00516 if (err != DMBoard::Ok) { 00517 log->printf("Failed to initialize the board, got error %d\r\n", err); 00518 wait_ms(2000); // allow RtosLog to flush messages 00519 mbed_die(); 00520 } 00521 00522 log->printf("\n\n---\nQSPI file syncer app\nBuilt: " __DATE__ " at " __TIME__ "\n\n"); 00523 00524 showInfoScreen(); 00525 00526 // allocate a chunk of memory in the external SDRAM to use as a RAM file system 00527 void* fsmem = malloc(RAM_FS_SIZE); 00528 if (fsmem == NULL) { 00529 log->printf("Failed to allocate memory for RAM file system\n"); 00530 mbed_die(); 00531 } 00532 00533 // create a file system based on the allocated memory 00534 RAMFileSystem ramfs((uint32_t)fsmem, RAM_FS_SIZE, "ram"); 00535 USBMSD_RAMFS usbmsd(&ramfs); 00536 00537 while(true) 00538 { 00539 // add an empty file system on it 00540 ramfs.format(); 00541 00542 QSPIFileSystem* qspi = board->getQspiFS(); 00543 bool qspiFormatted = qspi->isformatted(); 00544 if (!qspiFormatted) 00545 { 00546 addNotFormattedFile(); 00547 } 00548 else 00549 { 00550 createImageFile(qspi); 00551 00552 // Copy QSPI FS to RAM FS 00553 syncDir("/ram/", "/qspi/"); 00554 } 00555 00556 printf("Insert the USB cable!\n"); 00557 printf("Starting USB...\n"); 00558 for (int i = 0; i < 10; i++) 00559 { 00560 if (usbmsd.connect()) 00561 { 00562 printf("Connected!\n"); 00563 break; 00564 } 00565 printf("Failed to connect USB, testing again...\n"); 00566 printf("Insert (or remove and then insert) the USB cable!\n"); 00567 wait(1); 00568 } 00569 00570 waitForButtonPress(); 00571 00572 usbmsd.disconnect(); 00573 printf("Disconnected!\n"); 00574 00575 // Look for (re)format instruction file 00576 if (formatIfRequested()) { 00577 continue; 00578 } 00579 00580 // Copy RAM FS to QSPI FS 00581 recursiveList("/ram/"); 00582 syncDir("/qspi/", "/ram/"); 00583 } 00584 } 00585
Generated on Tue Jul 19 2022 07:34:38 by 1.7.2