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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

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