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

Dependencies:   EALib USBDevice mbed

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 
00007 #include "QSPIFileSystem.h"
00008 
00009 #include "USBMSD_RAMFS.h"
00010 #include "RAMFileSystem.h"
00011 #include "sdram.h"
00012 #include "crc.h"
00013 
00014 /******************************************************************************
00015  * Typedefs and defines
00016  *****************************************************************************/
00017 
00018 typedef bool (*syncFunc)(const char* name, bool isDir);
00019 
00020 #define RAM_FS_SIZE  (20*1024*1024)  //20MB
00021 
00022 /******************************************************************************
00023  * Local variables
00024  *****************************************************************************/
00025 
00026 QSPIFileSystem qspi("qspi");
00027 //RAMFileSystem ramfs(0xA0000000, 20*1024*1024, "ram");
00028 //USBMSD_RAMFS usbmsd(&ramfs);
00029 
00030 DigitalOut myled1(LED1);
00031 DigitalOut myled2(LED2);
00032 DigitalIn  button(p23);
00033 
00034 DigitalOut myled(LED1);
00035 static char lsbuff[NAME_MAX+1];
00036 
00037 static char image_file_name[128] = { '\0' };
00038 
00039 /******************************************************************************
00040  * Local functions
00041  *****************************************************************************/
00042 
00043 static void ledShowProgress()
00044 {
00045   static int state = 0;
00046   state = (state + 1) % 2;
00047   switch (state)
00048   {
00049     case 0:
00050       myled1 = 1;
00051       myled2 = 0;
00052       break;
00053 
00054     case 1:
00055     default:
00056       myled1 = 0;
00057       myled2 = 1;
00058   }
00059 }
00060 
00061 static void handleError(const char* msg)
00062 {
00063   printf(msg);
00064   while(true) {
00065     myled1 = 1;
00066     myled2 = 1;
00067     wait(0.3);
00068     myled1 = 0;
00069     myled2 = 0;
00070     wait(0.3);
00071   }
00072 }
00073 
00074 static void waitForButtonPress()
00075 {
00076   printf("Press button to sync file systems\n");
00077 
00078   myled1 = 1;
00079   myled2 = 1;
00080   while(button.read() == 1) {
00081     wait(0.1);
00082   }
00083   myled1 = 0;
00084   printf("Button pressed, now release it\n");
00085   while(button.read() == 0) {
00086     wait(0.1);
00087   }
00088 }
00089 
00090 static void addNotFormattedFile()
00091 {
00092     FILE *fp = fopen("/ram/qspi_not_formatted.txt", "w");
00093     if (fp != NULL) {
00094         fprintf(fp, "The QSPI file system has not be formatted and this program can't do it.\n");
00095         fprintf(fp, "Format the QSPI file system and then run this program again!\n");
00096         fclose(fp);
00097     }
00098 }
00099 
00100 static bool recursiveProcessFS(char* buff, const char* name, syncFunc func, bool adding)
00101 {
00102   uint32_t len = strlen(buff);
00103   if (len > 0) {
00104     if (buff[len - 1] != '/') {
00105       buff[len++] = '/';
00106       buff[len] = '\0';
00107     }
00108   }
00109   strcat(buff, name);
00110   len += strlen(name);
00111 
00112   DIR *d = opendir(buff);
00113   bool result = true; // success
00114   if (d != NULL) {
00115     if (adding) {
00116       // when processing in adding mode folders must be created before it's content
00117       result = func(buff, true);
00118     }
00119     struct dirent *p;
00120     while (result && ((p = readdir(d)) != NULL)) {
00121       result = recursiveProcessFS(buff, p->d_name, func, adding);
00122       buff[len] = '\0';
00123     }
00124     closedir(d);
00125     if (result && !adding) {
00126       // when processing in removing mode folders must be deleted after it's content
00127       result = func(buff, true);
00128     }
00129   } else {
00130     // a file
00131     result = func(buff, false);
00132   }
00133   return result;
00134 }
00135 
00136 static uint32_t fileLen(FILE* f)
00137 {
00138   uint32_t pos = ftell(f);
00139   fseek(f, 0, SEEK_END);
00140   uint32_t size = ftell(f);
00141   fseek(f, pos, SEEK_SET);
00142   return size;
00143 }
00144 
00145 static bool copy(FILE* fSrc, FILE* fDst)
00146 {
00147   char buff[512];
00148   uint32_t left = fileLen(fSrc);
00149   uint32_t num;
00150   uint32_t chunk;
00151 
00152   fseek(fSrc, 0, SEEK_SET);
00153   do {
00154     chunk = (left < 512) ? left : 512;
00155     num = fread(buff, 1, chunk, fSrc);
00156     if (num > 0) {
00157       uint32_t tmp = fwrite(buff, 1, num, fDst);
00158       if (tmp != num) {
00159         // failed to write
00160         return false;
00161       }
00162       left -= num;
00163       ledShowProgress();
00164     }
00165   } while(num > 0 && left > 0);
00166 
00167   // copied entire file
00168   return true;
00169 }
00170 
00171 static bool identicalFiles(const char* srcName, const char* dstName)
00172 {
00173   FILE* fSrc = NULL;
00174   FILE* fDst = NULL;
00175   bool identical = false;
00176   do
00177   {
00178     fSrc = fopen(srcName, "r");
00179     if (fSrc == NULL) {
00180       break;
00181     }
00182     fDst = fopen(dstName, "r");
00183     if (fDst == NULL) {
00184       break;
00185     }
00186     if (fileLen(fSrc) != fileLen(fDst)) {
00187       break;
00188     }
00189     if (crc_Read(fSrc) != crc_Read(fDst)) {
00190       break;
00191     }
00192 
00193     // All tests passed so the files are identical
00194     identical = true;
00195 
00196   } while(false);
00197 
00198   if (fSrc != NULL) {
00199     fclose(fSrc);
00200   }
00201   if (fDst != NULL) {
00202     fclose(fDst);
00203   }
00204 
00205   return identical;
00206 }
00207 
00208 static bool addExisting(const char* srcName, bool isDir, const char* dstName)
00209 {
00210   bool result = true; // success
00211   if (isDir) {
00212     DIR *d = opendir(dstName);
00213     if (d == NULL) {
00214       if (dstName[1] != 'r') { printf("%s, new dir, adding\n", dstName); }
00215       if (mkdir(dstName, 0) != 0) {
00216         printf("Failed to create folder %s\n", dstName);
00217         result = false; // dir did not exist and could not be created
00218       }
00219     } else {
00220       closedir(d);
00221     }
00222   } else if (!identicalFiles(srcName, dstName)) {
00223     // Compare the files to avoid replacing with same
00224     FILE* fSrc = fopen(srcName, "r");
00225     if (fSrc != NULL) {
00226       FILE* fDst = fopen(dstName, "w"); // open and truncate
00227       if (fDst != NULL) {
00228         if (dstName[1] != 'r') { printf("%s, changed, updating\n", dstName); }
00229         result = copy(fSrc, fDst);
00230         if (!result) {
00231           printf("Failed to copy %s to %s\n", srcName, dstName);
00232         }
00233         fclose(fDst);
00234       } else {
00235         printf("Failed to create file %s\n", dstName);
00236         result = false; // unable to create file
00237       }
00238       fclose(fSrc);
00239     } else {
00240       printf("Failed to copen source file file %s\n", srcName);
00241       result = false; // unable to open source
00242     }
00243   } else {
00244     if (dstName[1] != 'r') { printf("%s identical, skipping\n", dstName); }
00245   }
00246   return result;
00247 }
00248 
00249 static bool addExistingToQspi(const char* name, bool isDir)
00250 {
00251   // create the target file name by replacing /ram/ with /qspi/
00252   char buff[256];
00253   buff[0] = '\0';
00254   strcat(buff, "/qspi/");
00255   strcat(buff, name+5);
00256 
00257   // Don't add the file created by createImageFile()
00258   if (strcmp(name, image_file_name) == 0) {
00259     return true;
00260   }
00261 
00262   return addExisting(name, isDir, buff);
00263 }
00264 
00265 static bool addExistingToRAM(const char* name, bool isDir)
00266 {
00267   // create the target file name by replacing /qspi/ with /ram/
00268   char buff[256];
00269   buff[0] = '\0';
00270   strcat(buff, "/ram/");
00271   strcat(buff, name+6);
00272   return addExisting(name, isDir, buff);
00273 }
00274 
00275 static bool removeIfMissing(const char* toLookFor, const char* toRemove, bool isDir)
00276 {
00277   int result = 0; //success
00278   if (isDir) {
00279     DIR *d = opendir(toLookFor);
00280     if (d == NULL) {
00281       // dir doesn't exist => delete it
00282       if (toRemove[1] != 'r') { printf("%s, missing, deleting dir\n", toRemove); }
00283       result = remove(toRemove);
00284       ledShowProgress();
00285     } else {
00286       // dir exist => don't delete
00287       closedir(d);
00288     }
00289   } else {
00290     FILE* f = fopen(toLookFor, "r");
00291     if (f == NULL) {
00292       // file doesn't exist => delete it
00293       if (toRemove[1] != 'r') { printf("%s, missing, deleting file\n", toRemove); }
00294       result = remove(toRemove);
00295       ledShowProgress();
00296     } else {
00297       // file exist => don't delete
00298       fclose(f);
00299     }
00300   }
00301   return (result == 0);
00302 }
00303 
00304 static bool removeMissingFromQspi(const char* name, bool isDir)
00305 {
00306   // create the target file name by replacing /qspi/ with /ram/
00307   char buff[256];
00308   buff[0] = '\0';
00309   strcat(buff, "/ram/");
00310   strcat(buff, name+6);
00311   removeIfMissing(buff, name, isDir);
00312   return true;
00313 }
00314 
00315 static bool removeMissingFromRAM(const char* name, bool isDir)
00316 {
00317   // create the target file name by replacing /ram/ with /qspi/
00318   char buff[256];
00319   buff[0] = '\0';
00320   strcat(buff, "/qspi/");
00321   strcat(buff, name+5);
00322 
00323   // Don't remove the file created by createImageFile()
00324   if (strcmp(name, image_file_name) == 0) {
00325     return true;
00326   }
00327 
00328   removeIfMissing(buff, name, isDir);
00329   return true;
00330 }
00331 
00332 static void syncDir(const char* to, const char* from)
00333 {
00334   printf("Starting to sync %s on top of %s (This may take time. LED1 & 2 blink for each file)\n", from, to);
00335 
00336   char* buff = (char*)malloc(512);
00337   if (buff != NULL)
00338   {
00339     buff[0] = '\0';
00340     if (strcmp(to, "/qspi/") == 0) {
00341       if (!recursiveProcessFS(buff, to, removeMissingFromQspi, false)) {
00342         printf("Failed to remove files from %s that were missing on %s\n", to, from);
00343       } else {
00344         buff[0] = '\0';
00345         if (!recursiveProcessFS(buff, from, addExistingToQspi, true)) {
00346           printf("Failed to add files to %s that existed on %s\n", to, from);
00347         }
00348       }
00349     } else {
00350       if (!recursiveProcessFS(buff, to, removeMissingFromRAM, false)) {
00351         printf("Failed to remove files from %s that were missing on %s\n", to, from);
00352       } else {
00353         buff[0] = '\0';
00354         if (!recursiveProcessFS(buff, from, addExistingToRAM, true)) {
00355           printf("Failed to add files to %s that existed on %s\n", to, from);
00356         }
00357       }
00358     }
00359     free(buff);
00360   }
00361   printf("Sync completed\n");
00362 }
00363 
00364 
00365 static void createImageFile()
00366 {
00367   uint32_t startAddr;
00368   uint32_t endAddr;
00369   uint32_t size;
00370 
00371   printf("Creating image of existing (if any) QSPI file system\n");
00372 
00373   if (!qspi.getMemoryBoundaries(&startAddr, &endAddr))
00374   {
00375     handleError("QSPI FS not formatted or impossible to determine it's size\n");
00376   }
00377 
00378   // Align the start address to an even multiple of 1MB
00379   startAddr = startAddr & 0xfff00000;
00380 
00381   // Update the file to match the size of the file system
00382   size = endAddr - startAddr;
00383   if ((size < 0x00100000) || (size > 0x00800000) || ((size & 0xfffff) > 0))
00384   {
00385     sprintf(lsbuff, "QSPI FS size is not supported (%u bytes)\n", size);
00386     handleError(lsbuff);
00387   }
00388   sprintf(image_file_name, "/ram/.current/fs_image.fs%d", (size >> 20));
00389   
00390   // NOTE: The line below is very very !!!! important. For some weird reason the
00391   //       RAM file system must have at least one folder on it before USB is connected.
00392   //       If the RAM file system doesn't have any folders on it the result is that
00393   //       the content of the RAM file system will be the same after USB is disconnected
00394   //       as it was before connecting - regardless of what is added. Very strange indeed.
00395   mkdir("/ram/.current", 0);
00396 
00397   printf("QSPI FS max size is %d MB\n", (size >> 20));
00398 
00399   FILE *fp = fopen(image_file_name, "w");
00400   if (fp != NULL)
00401   {
00402     while (size > 0)
00403     {
00404       uint32_t written = fwrite((char*)(endAddr - size), 1, size, fp);
00405       size -= written;
00406       if (written == 0)
00407       {
00408         handleError("Failed to create QSPI image file\n");
00409       }
00410     }
00411     fclose(fp);
00412   }
00413 }
00414 
00415 static bool list(const char* name, bool isDir)
00416 {
00417   if (isDir) {
00418     printf("d:         %s\n", name);
00419   } else {
00420     FILE* f = fopen(name, "r");
00421     if (f != NULL) {
00422       uint32_t len = fileLen(f);
00423       printf("f: %7u %s\n", len, name);
00424       fclose(f);
00425     } else {
00426       printf("f:     ??? %s\n", name);
00427     }
00428   }
00429   return true;
00430 }
00431 
00432 static void recursiveList(const char* dirname)
00433 {
00434   printf("\nRecursive list of file and folders in %s\n", dirname);
00435   char* buff = (char*)malloc(512);
00436   if (buff != NULL)
00437   {
00438     buff[0] = '\0';
00439     recursiveProcessFS(buff, dirname, list, true);
00440     free(buff);
00441   }
00442 }
00443 
00444 /******************************************************************************
00445  * Main function
00446  *****************************************************************************/
00447 int main()
00448 {
00449   printf("\n-----------------\n\nWelcome to the QSPI file system tool...\n");
00450 
00451   // 1) Make sure that the button works
00452   // 2) Init SDRAM and allocate space for the RAM file system
00453   // 3) Setup RAM FS
00454   // 4a) If QSPI FS is not formatted:
00455   //    i) Create a "qspi_not_formatted.txt" file in the root of the file system
00456   // 4b) QSPI FS formatted
00457   //    i) Create an image file of the QSPI FS
00458   //    ii) Sync QSPI FS on top of RAM FS
00459   // 5) Connect USB
00460   // 6a) If QSPI FS is not formatted: Loop forever doing nothing
00461   // 6b) QSPI FS formatted: Wait for button press
00462   // 7) Button pressed, Disconnect USB
00463   // 8) QSPI formatted
00464   //    i) Sync RAM FS on top of QSPI FS
00465   //    ii) Goto 3)
00466   //
00467   
00468   // 1)
00469   button.mode(PullUp);
00470 
00471   // 2)
00472   if (sdram_init()) {
00473     handleError("Failed to initialize SDRAM\n");
00474   }
00475   
00476   void* fsmem = malloc(RAM_FS_SIZE);
00477   if (fsmem == NULL) {
00478     handleError("Failed to allocate memory for RAM file system\n");
00479   }
00480   RAMFileSystem ramfs((uint32_t)fsmem, RAM_FS_SIZE, "ram");
00481   USBMSD_RAMFS usbmsd(&ramfs);
00482   
00483   while(true)
00484   {
00485     // 3)
00486     ramfs.format();    
00487 
00488     // 4a)
00489     bool qspiFormatted = qspi.isformatted();
00490     if (!qspiFormatted)
00491     {
00492       addNotFormattedFile();
00493     }
00494 
00495     // 4b)
00496     else
00497     {
00498       //addTestFile();
00499       createImageFile();
00500 
00501       // Copy QSPI FS to RAM FS
00502       syncDir("/ram/", "/qspi/");
00503     }
00504         
00505     // 5)
00506     printf("Insert the USB cable!\n");
00507     printf("Starting USB...\n");
00508     for (int i = 0; i < 10; i++)
00509     {
00510       if (usbmsd.connect())
00511       {
00512         printf("Connected!\n");
00513         break;
00514       }
00515       printf("Failed to connect USB, testing again...\n");
00516       printf("Insert (or remove and then insert) the USB cable!\n");
00517       wait(1);
00518     }
00519 
00520     // 6b)
00521     if (qspiFormatted) 
00522     {
00523       waitForButtonPress();
00524     }
00525     else
00526     {
00527       // 6a) no point in waiting for buttons if no file system
00528       while (1) {};
00529     }
00530 
00531     // 7)
00532     usbmsd.disconnect();
00533     printf("Disconnected!\n");
00534 
00535     // 8) Copy RAM FS to QSPI FS
00536     recursiveList("/ram/");
00537     syncDir("/qspi/", "/ram/");
00538   }
00539 }