Kenji Arai / Mbed OS RAM_Disk_Control
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mon.cpp Source File

mon.cpp

00001 /*
00002  * mbed Application program for the mbed
00003  *  FatFs Check program / monitor part
00004  *
00005  * Copyright (c) 2015,'18,'19,'20 Kenji Arai / JH1PJL
00006  *  http://www7b.biglobe.ne.jp/~kenjia/
00007  *  https://os.mbed.com/users/kenjiArai/
00008  *      Created:    May        5th, 2015
00009  *      Revised:    June      14th, 2015
00010  *      Revised:    April      7th, 2018
00011  *      Revised:    May        2nd, 2020
00012  */
00013 
00014 /*
00015  *---------------- REFERENCE ---------------------------------------------------
00016  * Original Source Information
00017  * FatFs sample program
00018  *      ChaN FatFs  http://elm-chan.org/
00019  *      http://elm-chan.org/fsw/ff/00index_e.html
00020  */
00021 /*----------------------------------------------------------------------*/
00022 /* FAT file system sample project for FatFs            (C)ChaN, 2016    */
00023 /*----------------------------------------------------------------------*/
00024 
00025 //  Include --------------------------------------------------------------------
00026 #include "mbed.h"
00027 #if (MBED_MAJOR_VERSION == 2)
00028 #include "SDFileSystem.h"
00029 #elif (MBED_MAJOR_VERSION == 5)
00030 #include "FATFileSystem.h"
00031 #endif
00032 #include "ff.h"
00033 #include "ffconf.h"
00034 #include "diskio.h"
00035 #include "mon.h"
00036 
00037 //  Definition -----------------------------------------------------------------
00038 #define DO_DEBUG    0
00039 
00040 #if DO_DEBUG
00041 #define DEBUG_LINE  pc.printf("line:%d\r\n", __LINE__);
00042 #else
00043 #define DEBUG_LINE  {;}
00044 #endif
00045 
00046 // Com
00047 #if  1
00048 #define BAUD(x)     pc.baud(x)
00049 #define GETC(x)     pc.getc(x)
00050 #define PUTC(x)     pc.putc(x)
00051 #define PUTS(x)     pc.puts(x)
00052 #define PRINTF(...) pc.printf(__VA_ARGS__)
00053 #define READABLE(x) pc.readable(x)
00054 #else
00055 #define BAUD(x)     {;}
00056 #define GETC(x)     {;}
00057 #define PUTC(x)     {;}
00058 #define PRINTF(...) {;}
00059 #define READABLE(x) {;}
00060 #endif
00061 
00062 #define UTC_JST_OFFSET  (32400) // +9 hours
00063 
00064 // from ffconf.h
00065 #define _VOLUMES    1
00066 
00067 #if !defined(FF_FS_RPATH)
00068 #define FF_FS_RPATH 0
00069 #endif
00070 
00071 #define DW_CHAR         sizeof(char)
00072 #define DW_SHORT        sizeof(short)
00073 #define DW_LONG         sizeof(long)
00074 
00075 /* These types must be 16-bit, 32-bit or larger integer */
00076 typedef int             INT;
00077 typedef unsigned int    UINT;
00078 
00079 /* These types must be 8-bit integer */
00080 typedef char            CHAR;
00081 typedef unsigned char   UCHAR;
00082 typedef unsigned char   BYTE;
00083 
00084 /* These types must be 16-bit integer */
00085 typedef short           SHORT;
00086 typedef unsigned short  USHORT;
00087 typedef unsigned short  WORD;
00088 typedef unsigned short  WCHAR;
00089 
00090 /* These types must be 32-bit integer */
00091 typedef long            LONG;
00092 typedef unsigned long   ULONG;
00093 typedef unsigned long   DWORD;
00094 /*  by Kenji Arai / JH1PJL  September 10th, 2012  */
00095 typedef unsigned long long  DDWORD;
00096 
00097 //  RAM ------------------------------------------------------------------------
00098 BYTE Buff[4096];
00099 char Linebuf[128];          // Console input buffer
00100 FATFS Fatfs[_VOLUMES];      // File system object for each logical drive
00101 FIL File1, File2;           // File objects
00102 FATFS_DIR* Dirx;
00103 FILINFO Finfo;
00104 DWORD AccSize;              // Work register for fs command
00105 WORD AccFiles, AccDirs;
00106 
00107 //  ROM / Constant data --------------------------------------------------------
00108 const char *const monmsg0 = "Start monitor program for FatFs File System\r\n";
00109 const char *const monmsg1 = " <Please press any key to start the monitor>";
00110 
00111 static const char HelpMsg0[] =
00112     "dir   <full_pass>\r\n"
00113     "type  <file_name>\r\n"
00114     "vol\r\n"
00115     "ren   <org_file_name> <new_file_name>\r\n"
00116     "copy  <file_name> <file_name>\r\n"
00117     "mkdir <dir_name>\r\n"
00118     "cd    <dir_name>\r\n"
00119     "x     extend commands mode\r\n"
00120     "q     Return to main\r\n"
00121     "t     Show current time or Adjust time\r\n"
00122     "      e.g. t 20 5 2 10 11 12 -> May 02,'20, 10:11:12\r\n"
00123     "?     Help/You know the command\r\n"
00124     "\r\n";
00125 
00126 static const char HelpMsg1[] =
00127     "[File system controls]\r\n"
00128     " fi <ld#> [<mount>]- Force initialized the volume\r\n"
00129     " fs [<path>] - Show volume status\r\n"
00130     " fl [<path>] - Show a directory\r\n"
00131     " fo <mode> <file> - Open a file\r\n"
00132     "    <mode>  Read=1, Write=2\r\n"
00133     " fc - Close the file\r\n"
00134     " fe <ofs> - Move fp in normal seek\r\n"
00135     " fd <len> - Read and dump the file\r\n"
00136     " fr <len> - Read the file\r\n"
00137     " fw <len> <val> - Write to the file\r\n"
00138     " fn <org.name> <new.name> - Rename an object\r\n"
00139     " fu <name> - Unlink an object\r\n"
00140     " fv - Truncate the file at current fp\r\n"
00141     " fk <name> - Create a directory\r\n"
00142     " fa <atrr> <mask> <object name> - Change attribute of an object\r\n"
00143     " ft <year> <month> <day> <hour> <min> <sec> <name>"
00144     " - Change timestamp of an object\r\n"
00145     " fx <src.file> <dst.file> - Copy a file\r\n"
00146     " fg <path> - Change current directory\r\n"
00147     " fq - Show current directory\r\n"
00148     " fb <name> - Set volume label\r\n"
00149     " fm <ld#> <type> <csize> - Create file system\r\n"
00150     " fz [<len>] - Change/Show R/W length for fr/fw/fx command\r\n"
00151     "[Disk contorls]\r\n"
00152     " di <pd#> - Initialize disk\r\n"
00153     " dd [<pd#> <lba>] - Dump a secrtor\r\n"
00154     " ds <pd#> - Show disk status\r\n"
00155     "[Buffer controls]\r\n"
00156     " bd <ofs> - Dump working buffer\r\n"
00157     " be <ofs> [<data>] ... - Edit working buffer\r\n"
00158     " br <pd#> <lba> [<count>] - Read disk into working buffer\r\n"
00159     " bw <pd#> <lba> [<count>] - Write working buffer into disk\r\n"
00160     " bf <val> - Fill working buffer\r\n"
00161     "[Misc commands]\r\n"
00162     " q Return\r\n"
00163     " ? Help\r\n"
00164     "\r\n";
00165 
00166 //  Function prototypes --------------------------------------------------------
00167 #if (MBED_MAJOR_VERSION == 2)
00168 extern SDFileSystem fs;
00169 #elif (MBED_MAJOR_VERSION == 5)
00170 extern HeapBlockDevice bd;
00171 extern FATFileSystem fs;
00172 #endif
00173 
00174 static void extended_mon( char *ptr );
00175 static void v_next( char *ptr );
00176 static void d_next( char *ptr );
00177 static void c_next( char *ptr );
00178 static void m_next( char *ptr );
00179 static void r_next( char *ptr );
00180 static void t_next( char *ptr );
00181 static void memory_inf(char *ptr);
00182 static void disk_inf(char *ptr);
00183 
00184 static void crlf( void );
00185 static FRESULT scan_files( char* path );
00186 static void put_rc( FRESULT rc );
00187 static void file_inf( char *ptr );
00188 static void put_dump( void* buff, unsigned long addr, int len, int width );
00189 static void chk_and_set_time(char *ptr);
00190 static int xatoi ( char **str, long *res );
00191 
00192 void get_line (char *buff, int len);
00193 
00194 //  Object ---------------------------------------------------------------------
00195 extern  Serial pc;
00196 Timer   t;
00197 
00198 //------------------------------------------------------------------------------
00199 //  Control Program
00200 //------------------------------------------------------------------------------
00201 // Monitor program for File control
00202 void mon ()
00203 {
00204     char *ptr;
00205 
00206     Dirx = new FATFS_DIR;
00207     /* Open Uart to communicate with Host PC */
00208     PUTS(monmsg0);
00209     PUTS(monmsg1);
00210     crlf();
00211     for (;;) {
00212         DEBUG_LINE
00213         PUTC('>');
00214         ptr = Linebuf;
00215         get_line( ptr, sizeof(Linebuf) );
00216         switch ( *ptr++ ) {
00217                 // vol
00218             case 'v' :
00219                 v_next(ptr);
00220                 break;
00221                 // dir
00222             case 'd' :
00223                 d_next(ptr);
00224                 break;
00225                 // cd, copy
00226             case 'c' :
00227                 c_next(ptr);
00228                 break;
00229                 // mkdir
00230             case 'm' :
00231                 m_next(ptr);
00232                 break;
00233                 // ren
00234             case 'r' :
00235                 r_next(ptr);
00236                 break;
00237             case 't' :
00238                 t_next(ptr);
00239                 break;
00240             case 'x' :
00241                 extended_mon(ptr);
00242                 break;
00243                 // Help
00244             case '?' :
00245                 PUTS(HelpMsg0);
00246                 break;
00247                 // Exit monitor (return to main())
00248             case 'q' :
00249                 PUTS("Return to main\r\n");
00250                 return;
00251                 // Not a command
00252             default:
00253                 PUTS("? [HELP]=?");
00254                 crlf();
00255                 break;
00256         }
00257     }
00258 }
00259 
00260 uint32_t get_disk_freespace(void)
00261 {
00262     long  p1;
00263     UINT   s1, s2;
00264     FATFS  *fs;
00265     BYTE res;
00266 
00267     if (Dirx == NULL){
00268         Dirx = new FATFS_DIR;
00269     }
00270     char p = NULL;
00271     res = f_opendir(Dirx, &p);
00272     if (res) {
00273         return 0;
00274     }
00275     p1 = s1 = s2 = 0;
00276     for(;;) {
00277         res = f_readdir(Dirx, &Finfo);
00278         if ((res != FR_OK) || !Finfo.fname[0]) break;
00279         if (Finfo.fattrib & AM_DIR) {
00280             s2++;
00281         } else {
00282             s1++;
00283             p1 += Finfo.fsize;
00284         }
00285     }
00286     res = f_getfree(&p, (DWORD*)&p1, &fs);
00287     uint32_t size = p1 * fs->csize * 512;
00288     if (res == FR_OK) {
00289         return size;
00290     } else {
00291         return 0;
00292     }
00293 }
00294 
00295 uint32_t get_data_file_size(const char *const file_name)
00296 {
00297     BYTE res;
00298     //const char *file_name ="acc_data.txt";
00299  
00300     if (Dirx == NULL){
00301         Dirx = new FATFS_DIR;
00302     }
00303     char p = NULL;
00304     res = f_opendir(Dirx, &p);
00305     if (res) {
00306         put_rc((FRESULT)res);
00307         return 0;
00308     }
00309     for(;;) {
00310         res = f_readdir(Dirx, &Finfo);
00311         if ((res != FR_OK) || !Finfo.fname[0]) break;
00312         if (strcmp(Finfo.fname, file_name) == 0){
00313             return Finfo.fsize;
00314         }
00315     }
00316     return 0;
00317 }
00318 
00319 static void extended_mon( char *ptr )
00320 {
00321     PUTS(HelpMsg1);
00322     while(true) {
00323         PUTS("e>");
00324         ptr = Linebuf;
00325         get_line( ptr, sizeof(Linebuf) );
00326         switch ( *ptr++ ) {
00327             case 'f' :
00328                 DEBUG_LINE;
00329                 file_inf(ptr);
00330                 break;
00331             case 'd' :
00332                 DEBUG_LINE;
00333                 disk_inf(ptr);
00334                 break;
00335             case 'm' :
00336                 DEBUG_LINE;
00337                 memory_inf(ptr);
00338                 break;
00339             case '?' :
00340                 DEBUG_LINE;
00341                 PUTS(HelpMsg1);
00342                 break;
00343             case 'q' :
00344                 DEBUG_LINE;
00345                 return;
00346             default:
00347                 PUTS( "?\r\n" );
00348         }
00349     }
00350 }
00351 
00352 //------------------------------------------------------------------------------
00353 // General monitor functions
00354 static void v_next( char *ptr )
00355 {
00356     switch ( *ptr++ ) {
00357         case 'o' :
00358             if (*ptr == 'l') {
00359                 *ptr = 's';
00360                 file_inf(ptr);  // fs [<path>] - Show volume status
00361             }
00362             break;
00363         default:
00364             PUTS( "?\r\n" );
00365     }
00366 }
00367 
00368 static void d_next(char *ptr)
00369 {
00370     switch ( *ptr++ ) {
00371         case 'i' :
00372             if (*ptr == 'r') {
00373                 *ptr = 'l';
00374                 file_inf(ptr);  // fl [<path>] - Directory listing
00375             }
00376             break;
00377         default:
00378             PUTS( "?\r\n" );
00379     }
00380 }
00381 
00382 static void c_next(char *ptr)
00383 {
00384     switch ( *ptr++ ) {
00385         case 'o' :
00386             if ((*ptr == 'p') && (*(ptr + 1) == 'y')) {
00387                 ptr++;
00388                 *ptr = 'x';
00389                 file_inf(ptr);  // fx <src_name> <dst_name> - Copy file
00390             }
00391             break;
00392         case 'd' :
00393             *ptr = 'g';
00394             file_inf(ptr);  // fx <src_name> <dst_name> - Copy file
00395             break;
00396         default:
00397             PUTS( "?\r\n" );
00398     }
00399 }
00400 
00401 static void m_next(char *ptr)
00402 {
00403     switch ( *ptr++ ) {
00404         case 'k' :
00405             if ((*ptr == 'd') && (*(ptr + 1) == 'i') && (*(ptr + 2) == 'r')) {
00406                 ptr += 2;
00407                 *ptr = 'k';
00408                 file_inf(ptr);  // fk <name> - Create a directory
00409             }
00410             break;
00411         default:
00412             PUTS("?\r\n");
00413     }
00414 }
00415 
00416 static void r_next(char *ptr)
00417 {
00418     switch (*ptr++) {
00419         case 'e' :
00420             if (*ptr == 'n') {
00421                 // fn <old_name> <new_name> - Change file/dir name
00422                 file_inf(ptr);
00423             }
00424             break;
00425         default:
00426             PUTS("?\r\n");
00427     }
00428 }
00429 
00430 static void t_next(char *ptr)
00431 {
00432     switch (*ptr++) {
00433         case ' ' :
00434         case 0x0d:
00435             chk_and_set_time(ptr);
00436         case 'y' :
00437             if ((*ptr == 'p') && (*(ptr + 1) == 'e')) {
00438                 ptr++;
00439                 *ptr = '&';
00440                 file_inf(ptr);
00441             }
00442             break;
00443         default:
00444             PUTS("?\r\n");
00445     }
00446 }
00447 
00448 static FRESULT scan_files (
00449     char* path      /* Pointer to the path name working buffer */
00450 )
00451 {
00452     FATFS_DIR  dirs;
00453     FRESULT res;
00454     BYTE i;
00455     char *fn;
00456 
00457     if ((res = f_opendir(&dirs, path)) == FR_OK) {
00458         i = strlen(path);
00459         PRINTF("path: %s, n=%u\r\n", path, i);
00460         while (((res = f_readdir(&dirs, &Finfo)) == FR_OK) && Finfo.fname[0]) {
00461             if (FF_FS_RPATH && Finfo.fname[0] == '.') {
00462                 continue;
00463             }
00464             fn = Finfo.fname;
00465             if (Finfo.fattrib & AM_DIR) {
00466                 AccDirs++;
00467                 *(path+i) = '/';
00468                 strcpy(path+i+1, fn);
00469                 res = scan_files(path);
00470                 *(path+i) = '\0';
00471                 if (res != FR_OK) break;
00472             } else {
00473                 PRINTF("%s/%s\r\n", path, fn);
00474                 AccFiles++;
00475                 AccSize += Finfo.fsize;
00476             }
00477         }
00478     }
00479     return res;
00480 }
00481 
00482 static void put_rc (FRESULT rc)
00483 {
00484     const char *str =
00485         "OK\0" "DISK_ERR\0" "INT_ERR\0" "NOT_READY\0" "NO_FILE\0" "NO_PATH\0"
00486         "INVALID_NAME\0" "DENIED\0" "EXIST\0" "INVALID_OBJECT\0"
00487         "WRITE_PROTECTED\0" "INVALID_DRIVE\0" "NOT_ENABLED\0"
00488         "NO_FILE_SYSTEM\0" "MKFS_ABORTED\0" "TIMEOUT\0"
00489         "LOCKED\0" "NOT_ENOUGH_CORE\0" "TOO_MANY_OPEN_FILES\0";
00490     int i;
00491 
00492     for ( i = 0; i != rc && *str; i++ ) {
00493         while ( *str++ ) {
00494             ;
00495         }
00496     }
00497     PRINTF( "rc=%u FR_%s\r\n", (UINT)rc, str );
00498 }
00499 
00500 static void file_inf(char *ptr)
00501 {
00502     long  p1, p2, p3;
00503     CHAR   *ptr2;
00504     BYTE   f_res;
00505     UINT   s1, s2, cnt, blen = sizeof Buff;
00506     FATFS  *fs;
00507     static const BYTE ft[] = {0, 12, 16, 32};
00508     BYTE res;
00509     DWORD ofs = 0;
00510     uint32_t tim;
00511 
00512     switch (*ptr++) {
00513         case '&' :
00514             DEBUG_LINE;
00515             while (*ptr == ' ') ptr++;
00516             /* Open a file */
00517             f_res = f_open(&File1, ptr, FA_READ);
00518             if ( f_res ) {
00519                 put_rc((FRESULT)f_res);
00520                 break;
00521             }
00522             DEBUG_LINE;
00523             /* Read all lines and display it */
00524             while(true) {
00525                 f_res = f_read(&File1, (TCHAR*)Buff, blen, &cnt);
00526                 if ( f_res ) {
00527                     put_rc((FRESULT)f_res);
00528                     break;
00529                 }
00530                 for (s1 = 0; s1 < cnt; s1++) {
00531                     PUTC(Buff[s1]);
00532                 }
00533                 if (cnt != blen) {
00534                     break;
00535                 }
00536             }
00537             DEBUG_LINE;
00538             /* Close the file */
00539             f_close(&File1);
00540             break;
00541 
00542         case 'i' :  /* fi [<opt>]- Initialize logical drive */
00543             if ( !xatoi(&ptr, &p1) ) {
00544                 break;
00545             }
00546             if (!xatoi(&ptr, &p2)) p2 = 0;
00547             put_rc(f_mount(&Fatfs[p1], (const TCHAR*)p1, 0));
00548             break;
00549 
00550         case 's' :  /* fs [<path>] - Show volume status */
00551             f_res = f_getfree( ptr, (DWORD*)&p2, &fs );
00552             if ( f_res ) {
00553                 put_rc((FRESULT)f_res);
00554                 break;
00555             }
00556             PRINTF
00557             (
00558                 "\rFAT type = FAT%u\r\nBytes/Cluster"
00559                 " = %lu\r\nNumber of FATs = %u\r\n"
00560                 "Root DIR entries = %u\r\n"
00561                 "Sectors/FAT = %lu\r\n"
00562                 "Number of clusters = %lu\r\n"
00563                 "FAT start (lba) = %lu\r\n"
00564                 "DIR start (lba,clustor) = %lu\r\n"
00565                 "Data start (lba) = %lu\r\n",
00566                 ft[fs->fs_type & 3], (DWORD)fs->csize * 512, fs->n_fats,
00567                 fs->n_rootdir, fs->fsize, (DWORD)fs->n_fatent - 2,
00568                 fs->fatbase, fs->dirbase, fs->database
00569             );
00570             AccSize = AccFiles = AccDirs = 0;
00571             break;
00572         case 'l' :  /* fl [<path>] - Directory listing */
00573             while (*ptr == ' ') ptr++;
00574             res = f_opendir(Dirx, ptr);
00575             if (res) {
00576                 put_rc((FRESULT)res);
00577                 break;
00578             }
00579             p1 = s1 = s2 = 0;
00580             for(;;) {
00581                 res = f_readdir(Dirx, &Finfo);
00582                 if ((res != FR_OK) || !Finfo.fname[0]) break;
00583                 if (Finfo.fattrib & AM_DIR) {
00584                     s2++;
00585                 } else {
00586                     s1++;
00587                     p1 += Finfo.fsize;
00588                 }
00589                 PRINTF("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu  %s\r\n",
00590                        (Finfo.fattrib & AM_DIR) ? 'D' : '-',
00591                        (Finfo.fattrib & AM_RDO) ? 'R' : '-',
00592                        (Finfo.fattrib & AM_HID) ? 'H' : '-',
00593                        (Finfo.fattrib & AM_SYS) ? 'S' : '-',
00594                        (Finfo.fattrib & AM_ARC) ? 'A' : '-',
00595                        (Finfo.fdate >> 9) + 1980, (Finfo.fdate >> 5) & 15,
00596                        Finfo.fdate & 31,
00597                        (Finfo.ftime >> 11), (Finfo.ftime >> 5) & 63,
00598                        Finfo.fsize, Finfo.fname);
00599             }
00600 #if 0   // f_getfree cannnot count under Dir, subdirectory area
00601             PRINTF("%4u File(s),%10lu bytes total\r\n%4u Dir(s)", s1, p1, s2);
00602             res = f_getfree(ptr, (DWORD*)&p1, &fs);
00603             if (res == FR_OK)
00604                 PRINTF(", %10lu bytes free\r\n", p1 * fs->csize * 512);
00605             else
00606                 put_rc((FRESULT)res);
00607 #else
00608             PRINTF("%4u File(s) = %10lu bytes total, %4u Dir(s)\r\n",
00609                    s1, p1, s2);
00610 #endif
00611             break;
00612 
00613         case 'o' :  /* fo <mode> <file> - Open a file */
00614             if (!xatoi(&ptr, &p1)) break;
00615             while (*ptr == ' ') ptr++;
00616             put_rc(f_open(&File1, ptr, (BYTE)p1));
00617 #if 0
00618             put_rc(f_open(&File1, "savedata.txt", 1));
00619             PRINTF("Open savedata.txt as read mode\r\n");
00620 #endif
00621             break;
00622 
00623         case 'c' :  /* fc - Close a file */
00624             put_rc(f_close(&File1));
00625             break;
00626 
00627         case 'e' :  /* fe - Seek file pointer */
00628             if (!xatoi(&ptr, &p1)) break;
00629             res = f_lseek(&File1, p1);
00630             put_rc((FRESULT)res);
00631             if (res == FR_OK)
00632                 PRINTF("fptr=%lu(0x%lX)\r\n", File1.fptr, File1.fptr);
00633             break;
00634 
00635         case 'd' :  /* fd <len> - read and dump file from current fp */
00636             if (!xatoi(&ptr, &p1)) break;
00637             ofs = File1.fptr;
00638             while (p1) {
00639                 if ((UINT)p1 >= 16) {
00640                     cnt = 16;
00641                     p1 -= 16;
00642                 } else                {
00643                     cnt = p1;
00644                     p1 = 0;
00645                 }
00646                 res = f_read(&File1, Buff, cnt, &cnt);
00647                 if (res != FR_OK) {
00648                     put_rc((FRESULT)res);
00649                     break;
00650                 }
00651                 if (!cnt) break;
00652                 put_dump(Buff, ofs, cnt, DW_CHAR);
00653                 ofs += 16;
00654             }
00655             break;
00656 
00657         case 'r' :  /* fr <len> - read file */
00658             if (!xatoi(&ptr, &p1)) break;
00659             p2 = 0;
00660             t.reset();
00661             t.start();
00662             while (p1) {
00663                 if ((UINT)p1 >= blen) {
00664                     cnt = blen;
00665                     p1 -= blen;
00666                 } else {
00667                     cnt = p1;
00668                     p1 = 0;
00669                 }
00670                 res = f_read(&File1, Buff, cnt, &s2);
00671                 if (res != FR_OK) {
00672                     put_rc((FRESULT)res);
00673                     break;
00674                 }
00675                 p2 += s2;
00676                 if (cnt != s2) break;
00677             }
00678             tim = t.read_ms();
00679             PRINTF("%lu bytes read with %lu kB/sec.\r\n",
00680                    p2, tim ? (p2 / tim) : 0);
00681             break;
00682 
00683         case 'w' :  /* fw <len> <val> - write file */
00684             if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2)) break;
00685             memset(Buff, (BYTE)p2, blen);
00686             p2 = 0;
00687             t.reset();
00688             t.start();
00689             while (p1) {
00690                 if ((UINT)p1 >= blen) {
00691                     cnt = blen;
00692                     p1 -= blen;
00693                 } else {
00694                     cnt = p1;
00695                     p1 = 0;
00696                 }
00697                 res = f_write(&File1, Buff, cnt, &s2);
00698                 if (res != FR_OK) {
00699                     put_rc((FRESULT)res);
00700                     break;
00701                 }
00702                 p2 += s2;
00703                 if (cnt != s2) break;
00704             }
00705             tim = t.read_ms();
00706             PRINTF("%lu bytes written with %lu kB/sec.\r\n",
00707                    p2, tim ? (p2 / tim) : 0);
00708             break;
00709 
00710         case 'n' :  /* fn <org.name> <new.name> - Change name of an object */
00711             while (*ptr == ' ') ptr++;
00712             ptr2 = strchr(ptr, ' ');
00713             if (!ptr2) break;
00714             *ptr2++ = 0;
00715             while (*ptr2 == ' ') ptr2++;
00716             put_rc(f_rename(ptr, ptr2));
00717             break;
00718 
00719         case 'u' :  /* fu <name> - Unlink an object */
00720             while (*ptr == ' ') ptr++;
00721             put_rc(f_unlink(ptr));
00722             break;
00723 
00724         case 'v' :  /* fv - Truncate file */
00725             put_rc(f_truncate(&File1));
00726             break;
00727 
00728         case 'k' :  /* fk <name> - Create a directory */
00729             while (*ptr == ' ') ptr++;
00730             put_rc(f_mkdir(ptr));
00731             break;
00732 #if 0
00733         case 'a' :  /* fa <atrr> <mask> <name> - Change attribute of an object */
00734             if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2)) break;
00735             while (*ptr == ' ') ptr++;
00736             put_rc(f_chmod(ptr, p1, p2));
00737             break;
00738 #endif
00739 #if 0
00740             /* ft <year> <month> <day> <hour> <min> <sec> <name>
00741                                                  - Change timestamp of an object */
00742         case 't' :
00743             if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) {
00744                 break;
00745             }
00746             Finfo.fdate = ((p1 - 1980) << 9) | ((p2 & 15) << 5) | (p3 & 31);
00747             if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) {
00748                 break;
00749             }
00750             Finfo.ftime =
00751                 ((p1 & 31) << 11) | ((p2 & 63) << 5) | ((p3 >> 1) & 31);
00752             put_rc(f_utime(ptr, &Finfo));
00753             break;
00754 #endif
00755 #if FILCPY_NOTUSE == 0
00756         case 'x' : /* fx <src_name> <dst_name> - Copy file */
00757             while ( *ptr == ' ' ) {
00758                 ptr++;
00759             }
00760             ptr2 = strchr( ptr, ' ' );
00761             if ( !ptr2 ) {
00762                 break;
00763             }
00764             *ptr2++ = 0;
00765             while ( *ptr2 == ' ' ) {
00766                 ptr2++;
00767             }
00768             f_res = f_open( &File1, ptr, FA_OPEN_EXISTING | FA_READ );
00769             PRINTF("Opening %s \r\n", ptr);
00770             if ( f_res ) {
00771                 put_rc( (FRESULT)f_res );
00772                 break;
00773             }
00774             f_res = f_open( &File2, ptr2, FA_CREATE_ALWAYS | FA_WRITE );
00775             PRINTF(" Creating %s \r\n", ptr2);
00776             if ( f_res ) {
00777                 put_rc( (FRESULT)f_res );
00778                 f_close( &File1 );
00779                 break;
00780             }
00781             PRINTF("Copying file...");
00782             p1 = 0;
00783             for ( ;; ) {
00784                 f_res = f_read( &File1, Buff, blen, &s1 );
00785                 if ( f_res || s1 == 0 ) {
00786                     break;   /* error or eof */
00787                 }
00788                 f_res = f_write( &File2, Buff, s1, &s2 );
00789                 p1 += s2;
00790                 if ( f_res || s2 < s1 ) {
00791                     break;   /* error or disk full */
00792                 }
00793             }
00794             f_close( &File1 );
00795             f_close( &File2 );
00796             crlf();
00797             break;
00798 #endif
00799 #if 0
00800         case 'x' : /* fx <src.name> <dst.name> - Copy a file */
00801             while (*ptr == ' ') ptr++;
00802             ptr2 = strchr(ptr, ' ');
00803             if (!ptr2) break;
00804             *ptr2++ = 0;
00805             while (*ptr2 == ' ') ptr2++;
00806             PRINTF("Opening \"%s\"", ptr);
00807             res = f_open(&File1, ptr, FA_OPEN_EXISTING | FA_READ);
00808             PUTS("\r\n");
00809             if (res) {
00810                 put_rc((FRESULT)res);
00811                 break;
00812             }
00813             PRINTF("Creating \"%s\"", ptr2);
00814             res = f_open(&File1, ptr2, FA_CREATE_ALWAYS | FA_WRITE);
00815             PUTS("\r\n");
00816             if (res) {
00817                 put_rc((FRESULT)res);
00818                 f_close(&File1);
00819                 break;
00820             }
00821             PRINTF("Copying file...");
00822             t.reset();
00823             t.start();
00824             p1 = 0;
00825             for (;;) {
00826                 res = f_read(&File1, Buff, blen, &s1);
00827                 if (res || s1 == 0) break;   /* error or eof */
00828                 res = f_write(&File2, Buff, s1, &s2);
00829                 p1 += s2;
00830                 if (res || s2 < s1) break;   /* error or disk full */
00831             }
00832             tim = t.read_ms();
00833             PRINTF("\r\n%lu bytes copied with %lu kB/sec.\r\n",
00834                    p1, tim ? (p1 / tim) : 0);
00835             f_close(&File1);
00836             f_close(&File2);
00837             break;
00838 #endif
00839 #if FF_FS_RPATH
00840         case 'g' :  /* fg <path> - Change current directory */
00841             while (*ptr == ' ') ptr++;
00842             put_rc(f_chdir(ptr));
00843             break;
00844 #if FF_FS_RPATH >= 2
00845         case 'q' :  /* fq - Show current dir path */
00846             res = f_getcwd(Linebuf, sizeof Linebuf);
00847             if (res)
00848                 put_rc(res);
00849             else
00850                 PRINTF("%s\r\n", Linebuf);
00851             break;
00852 #endif
00853 #endif
00854 #if FF_USE_LABEL
00855         case 'b' :  /* fb <name> - Set volume label */
00856             while (*ptr == ' ') ptr++;
00857             put_rc(f_setlabel(ptr));
00858             break;
00859 #endif  /* FF_USE_LABEL */
00860 #if FF_USE_MKFS
00861         case 'm' :  /* fm <type> <csize> - Create file system */
00862             if (!xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) break;
00863             PRINTF("The volume will be formatted. Are you sure? (Y/n)=");
00864             get_line(Linebuf, sizeof Linebuf);
00865             if (Linebuf[0] == 'Y')
00866                 put_rc(f_mkfs("", (BYTE)p2, (DWORD)p3, Buff, sizeof Buff));
00867             break;
00868 #endif  /* FF_USE_MKFS */
00869             /* fz [<size>] - Change/Show R/W length for fr/fw/fx command */
00870         case 'z' :
00871             if (xatoi(&ptr, &p1) && p1 >= 1 && p1 <= (long)sizeof Buff)
00872                 blen = p1;
00873             PRINTF("blen=%u\r\n", blen);
00874             break;
00875     }
00876 }
00877 
00878 static void memory_inf(char *ptr)
00879 {
00880     long  p1, p2, p3;
00881 
00882     switch (*ptr++) {
00883         case 'd' :  /* md[b|h|w] <address> [<count>] - Dump memory */
00884             switch (*ptr++) {
00885                 case 'w':
00886                     p3 = DW_LONG;
00887                     break;
00888                 case 'h':
00889                     p3 = DW_SHORT;
00890                     break;
00891                 default:
00892                     p3 = DW_CHAR;
00893             }
00894             if (!xatoi(&ptr, &p1)) break;
00895             if (!xatoi(&ptr, &p2)) p2 = 128 / p3;
00896             for (ptr = (char*)p1; p2 >= 16 / p3; ptr += 16, p2 -= 16 / p3)
00897                 put_dump(ptr, (DWORD)ptr, 16 / p3, p3);
00898             if (p2) put_dump((BYTE*)ptr, (UINT)ptr, p2, p3);
00899             break;
00900         case 'f' :  /* mf <address> <value> <count> - Fill memory */
00901             if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) {
00902                 break;
00903             }
00904             while (p3--) {
00905                 *(BYTE*)p1 = (BYTE)p2;
00906                 p1++;
00907             }
00908             break;
00909         case 'e' :  /* me[b|h|w] <address> [<value> ...] - Edit memory */
00910             switch (*ptr++) {   /* Get data width */
00911                 case 'w':
00912                     p3 = DW_LONG;
00913                     break;
00914                 case 'h':
00915                     p3 = DW_SHORT;
00916                     break;
00917                 default:
00918                     p3 = DW_CHAR;
00919             }
00920             if (!xatoi(&ptr, &p1)) break;   /* Get start address */
00921             if (xatoi(&ptr, &p2)) { /* 2nd parameter is given (direct mode) */
00922                 do {
00923                     switch (p3) {
00924                         case DW_LONG:
00925                             *(DWORD*)p1 = (DWORD)p2;
00926                             break;
00927                         case DW_SHORT:
00928                             *(WORD*)p1 = (WORD)p2;
00929                             break;
00930                         default:
00931                             *(BYTE*)p1 = (BYTE)p2;
00932                     }
00933                     p1 += p3;
00934                 } while (xatoi(&ptr, &p2)); /* Get next value */
00935                 break;
00936             }
00937             for (;;) {  /* 2nd parameter is not given (interactive mode) */
00938                 switch (p3) {
00939                     case DW_LONG:
00940                         PRINTF("%08X 0x%08X-", (unsigned int)p1, *(unsigned int*)p1);
00941                         break;
00942                     case DW_SHORT:
00943                         PRINTF("%08X 0x%04X-", (unsigned int)p1, *(WORD*)p1);
00944                         break;
00945                     default:
00946                         PRINTF("%08X 0x%02X-", (unsigned int)p1, *(BYTE*)p1);
00947                 }
00948                 ptr = Linebuf;
00949                 get_line(ptr, sizeof Linebuf);
00950                 if (*ptr == '.') break;
00951                 if ((BYTE)*ptr >= ' ') {
00952                     if (!xatoi(&ptr, &p2)) continue;
00953                     switch (p3) {
00954                         case DW_LONG:
00955                             *(DWORD*)p1 = (DWORD)p2;
00956                             break;
00957                         case DW_SHORT:
00958                             *(WORD*)p1 = (WORD)p2;
00959                             break;
00960                         default:
00961                             *(BYTE*)p1 = (BYTE)p2;
00962                     }
00963                 }
00964                 p1 += p3;
00965             }
00966     }
00967 }
00968 
00969 static void disk_inf(char *ptr)
00970 {
00971     long  p1, p2;
00972     UINT   s1;
00973     BYTE res, b, drv = 0;
00974     DWORD ofs = 0, sect = 0, blk[2];
00975 
00976     switch (*ptr++) {
00977         case 'd' :  /* dd [<pd#> <sect>] - Dump secrtor */
00978             if (!xatoi(&ptr, &p1)) {
00979                 p1 = drv;
00980                 p2 = sect;
00981             } else {
00982                 if (!xatoi(&ptr, &p2)) break;
00983             }
00984             drv = (BYTE)p1;
00985             sect = p2;
00986             res = disk_read(drv, Buff, sect, 1);
00987             if (res) {
00988                 PRINTF("rc=%d\r\n", (WORD)res);
00989                 break;
00990             }
00991             PRINTF("PD#:%u LBA:%lu\r\n", drv, sect++);
00992             for (ptr=(char*)Buff, ofs = 0; ofs < 0x200; ptr += 16, ofs += 16)
00993                 put_dump((BYTE*)ptr, ofs, 16, DW_CHAR);
00994             break;
00995 
00996         case 'i' :  /* di <pd#> - Initialize disk */
00997             if (!xatoi(&ptr, &p1)) break;
00998             PRINTF("rc=%d\r\n", (WORD)disk_initialize((BYTE)p1));
00999             break;
01000 
01001         case 's' :  /* ds <pd#> - Show disk status */
01002             if (!xatoi(&ptr, &p1)) break;
01003             if (disk_ioctl((BYTE)p1, GET_SECTOR_COUNT, &p2) == RES_OK) {
01004                 PRINTF("Drive size: %lu sectors\r\n", p2);
01005             }
01006             if (disk_ioctl((BYTE)p1, GET_BLOCK_SIZE, &p2) == RES_OK) {
01007                 PRINTF("Block size: %lu sectors\r\n", p2);
01008             }
01009             if (disk_ioctl((BYTE)p1, MMC_GET_TYPE, &b) == RES_OK) {
01010                 PRINTF("Media type: %u\r\n", b);
01011             }
01012             if (disk_ioctl((BYTE)p1, MMC_GET_CSD, Buff) == RES_OK) {
01013                 PUTS("CSD:\r\n");
01014                 put_dump(Buff, 0, 16, DW_CHAR);
01015             }
01016             if (disk_ioctl((BYTE)p1, MMC_GET_CID, Buff) == RES_OK) {
01017                 PUTS("CID:\r\n");
01018                 put_dump(Buff, 0, 16, DW_CHAR);
01019             }
01020             if (disk_ioctl((BYTE)p1, MMC_GET_OCR, Buff) == RES_OK) {
01021                 PUTS("OCR:\r\n");
01022                 put_dump(Buff, 0, 4, DW_CHAR);
01023             }
01024             if (disk_ioctl((BYTE)p1, MMC_GET_SDSTAT, Buff) == RES_OK) {
01025                 PUTS("SD Status:\r\n");
01026                 for (s1 = 0; s1 < 64; s1 += 16) {
01027                     put_dump(Buff+s1, s1, 16, DW_CHAR);
01028                 }
01029             }
01030             break;
01031 
01032         case 'c' :  /* Disk ioctl */
01033             switch (*ptr++) {
01034                 case 's' :  /* dcs <pd#> - CTRL_SYNC */
01035                     if (!xatoi(&ptr, &p1)) break;
01036                     PRINTF("rc=%d\r\n", disk_ioctl((BYTE)p1, CTRL_SYNC, 0));
01037                     break;
01038                 case 'e' :  /* dce <pd#> <s.lba> <e.lba> - CTRL_TRIM */
01039                     if (!xatoi(&ptr, &p1) ||
01040                             !xatoi(&ptr, (long*)&blk[0]) ||
01041                             !xatoi(&ptr, (long*)&blk[1])) {
01042                         break;
01043                     }
01044                     PRINTF("rc=%d\r\n", disk_ioctl((BYTE)p1, CTRL_TRIM, blk));
01045                     break;
01046             }
01047     }
01048 }
01049 
01050 void put_dump (
01051     void* buff,             /* Pointer to the array to be dumped */
01052     unsigned long addr,     /* Heading address value */
01053     int len,                /* Number of items to be dumped */
01054     int width               /* Size of the items (DW_CHAR, DW_SHORT, DW_LONG) */
01055 )
01056 {
01057     int i;
01058     unsigned char *bp;
01059     unsigned short *sp;
01060     unsigned long *lp;
01061 
01062     PRINTF( "%08lx ", addr );      /* address */
01063     switch ( width )  {
01064         case DW_CHAR:
01065             bp = (unsigned char *)buff;
01066             for ( i = 0; i < len; i++ ) {       /* Hexdecimal dump */
01067                 PRINTF( " %02x", bp[i] );
01068             }
01069             PUTC(' ');
01070             for ( i = 0; i < len; i++ ) {       /* ASCII dump */
01071                 PUTC( (bp[i] >= ' ' && bp[i] <= '~') ? bp[i] : '.' );
01072             }
01073             break;
01074         case DW_SHORT:
01075             sp = (unsigned short *)buff;
01076             do {                            /* Hexdecimal dump */
01077                 PRINTF( " %04x", *sp++ );
01078             } while ( --len );
01079             break;
01080         case DW_LONG:
01081             lp = (unsigned long *)buff;
01082             do {                            /* Hexdecimal dump */
01083                 PRINTF( " %08lx", *lp++ );
01084             } while ( --len );
01085             break;
01086     }
01087     PUTS( "\r\n" );
01088 }
01089 
01090 // RTC related subroutines
01091 void chk_and_set_time(char *ptr)
01092 {
01093     char buf[64];
01094 
01095     long p1;
01096     struct tm t;
01097     time_t seconds;
01098 
01099     if (xatoi(&ptr, &p1)) {
01100         t.tm_year       = (uint8_t)p1 + 100;
01101         pc.printf("Year:%ld ",p1);
01102         xatoi( &ptr, &p1 );
01103         t.tm_mon        = (uint8_t)p1 - 1;
01104         pc.printf("Month:%ld ",p1);
01105         xatoi( &ptr, &p1 );
01106         t.tm_mday       = (uint8_t)p1;
01107         pc.printf("Day:%ld ",p1);
01108         xatoi( &ptr, &p1 );
01109         t.tm_hour       = (uint8_t)p1;
01110         pc.printf("Hour:%ld ",p1);
01111         xatoi( &ptr, &p1 );
01112         t.tm_min        = (uint8_t)p1;
01113         pc.printf("Min:%ld ",p1);
01114         xatoi( &ptr, &p1 );
01115         t.tm_sec        = (uint8_t)p1;
01116         pc.printf("Sec: %ld \r\n",p1);
01117         seconds = mktime(&t);
01118         set_time(seconds);
01119     } else {
01120         seconds = time(NULL);
01121     }
01122     strftime(buf, 50, " %B %d,'%y, %H:%M:%S\r\n", localtime(&seconds));
01123     pc.printf("[Time] %s", buf);
01124 }
01125 
01126 //  Get key input data
01127 void get_line (char *buff, int len)
01128 {
01129     char c;
01130     int idx = 0;
01131 
01132     for (;;) {
01133         c = GETC();
01134         //    Added by Kenji Arai / JH1PJL   May 9th, 2010
01135         if (c == '\r') {
01136             buff[idx++] = c;
01137             break;
01138         }
01139         if ((c == '\b') && idx) {
01140             idx--;
01141             PUTC(c);
01142             PUTC(' ');
01143             PUTC(c);
01144         }
01145         if (((uint8_t)c >= ' ') && (idx < len - 1)) {
01146             buff[idx++] = c;
01147             PUTC(c);
01148         }
01149     }
01150     buff[idx] = 0;
01151     PUTS("\r\n");
01152 }
01153 
01154 /*  Outpur LF & CR */
01155 void crlf( void )
01156 {
01157     PRINTF( "\r\n" );
01158 }
01159 
01160 /*  Check key input */
01161 unsigned int check_hit_key (void)
01162 {
01163     return ( READABLE() );
01164 }
01165 
01166 /*----------------------------------------------*/
01167 /* Get a value of the string                    */
01168 /*----------------------------------------------*/
01169 /*  "123 -5   0x3ff 0b1111 0377  w "
01170         ^                           1st call returns 123 and next ptr
01171            ^                        2nd call returns -5 and next ptr
01172                    ^                3rd call returns 1023 and next ptr
01173                           ^         4th call returns 15 and next ptr
01174                                ^    5th call returns 255 and next ptr
01175                                   ^ 6th call fails and returns 0
01176 */
01177 int xatoi (         /* 0:Failed, 1:Successful */
01178     char **str,     /* Pointer to pointer to the string */
01179     long *res       /* Pointer to the valiable to store the value */
01180 )
01181 {
01182     unsigned long val;
01183     unsigned char c, r, s = 0;
01184 
01185     *res = 0;
01186     while ( (c = **str) == ' ' ) {
01187         (*str)++;   /* Skip leading spaces */
01188     }
01189     if ( c == '-' ) {       /* negative? */
01190         s = 1;
01191         c = *(++(*str));
01192     }
01193     if ( c == '0' ) {
01194         c = *(++(*str));
01195         switch (c) {
01196             case 'x':       /* hexdecimal */
01197                 r = 16;
01198                 c = *(++(*str));
01199                 break;
01200             case 'b':       /* binary */
01201                 r = 2;
01202                 c = *(++(*str));
01203                 break;
01204             default:
01205                 if ( c <= ' ' ) return 1;   /* single zero */
01206                 if ( c < '0' || c > '9' ) return 0; /* invalid char */
01207                 r = 8;      /* octal */
01208         }
01209     } else {
01210         if ( c < '0' || c > '9' ) return 0; /* EOL or invalid char */
01211         r = 10;         /* decimal */
01212     }
01213     val = 0;
01214     while ( c > ' ' ) {
01215         if ( c >= 'a' ) {
01216             c -= 0x20;
01217         }
01218         c -= '0';
01219         if ( c >= 17 ) {
01220             c -= 7;
01221             if ( c <= 9 ) {
01222                 return 0;   /* invalid char */
01223             }
01224         }
01225         if ( c >= r ) {
01226             return 0;   /* invalid char for current radix */
01227         }
01228         val = val * r + c;
01229         c = *(++(*str));
01230     }
01231     if (s) val = 0 - val;           /* apply sign if needed */
01232     *res = val;
01233     return 1;
01234 }