1st version for FatFs monitor

Dependents:   DISCO-F469NI_USB_Disk

Files at this revision

API Documentation at this revision

Comitter:
kenjiArai
Date:
Mon Apr 30 05:20:42 2018 +0000
Commit message:
1st version for FatFs monitor

Changed in this revision

mon.cpp Show annotated file Show diff for this revision Revisions of this file
mon.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 6f52c89729de mon.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mon.cpp	Mon Apr 30 05:20:42 2018 +0000
@@ -0,0 +1,1236 @@
+/*
+ * mbed Application program for the mbed
+ *  FatFs Check program / monitor part
+ *
+ * Copyright (c) 2015,'18 Kenji Arai / JH1PJL
+ *  http://www.page.sannet.ne.jp/kenjia/index.html
+ *  https://os.mbed.com/users/kenjiArai/
+ *      Created:    May        5th, 2015
+ *      Revised:    June      14th, 2015
+ *      Revised:    April     29th, 2018
+ */
+
+/*
+ *---------------- REFERENCE ---------------------------------------------------
+ * Original Source Information
+ * FatFs sample program
+ *      ChaN FatFs  http://elm-chan.org/
+ *      http://elm-chan.org/fsw/ff/00index_e.html
+ */
+/*----------------------------------------------------------------------*/
+/* FAT file system sample project for FatFs            (C)ChaN, 2016    */
+/*----------------------------------------------------------------------*/
+
+//  Include --------------------------------------------------------------------
+#include "mbed.h"
+#if (MBED_MAJOR_VERSION == 2)
+#include "SDFileSystem.h"
+#elif (MBED_MAJOR_VERSION == 5)
+#include "FATFileSystem.h"
+#endif
+#include "ff.h"
+#include "ffconf.h"
+#include "diskio.h"
+#include "mon.h"
+
+//  Definition -----------------------------------------------------------------
+#define DO_DEBUG    0
+
+#if DO_DEBUG
+#define DEBUG_LINE  pc.printf("line:%d\r\n", __LINE__);
+#else
+#define DEBUG_LINE  {;}
+#endif
+
+// Com
+#if  1
+#define BAUD(x)     pc.baud(x)
+#define GETC(x)     pc.getc(x)
+#define PUTC(x)     pc.putc(x)
+#define PUTS(x)     pc.puts(x)
+#define PRINTF(...) pc.printf(__VA_ARGS__)
+#define READABLE(x) pc.readable(x)
+#else
+#define BAUD(x)     {;}
+#define GETC(x)     {;}
+#define PUTC(x)     {;}
+#define PRINTF(...) {;}
+#define READABLE(x) {;}
+#endif
+
+#define UTC_JST_OFFSET  (32400) // +9 hours
+
+// from ffconf.h
+#define _VOLUMES    1
+#define FF_USE_LFN  0
+
+#if !defined(FF_FS_RPATH)
+#define FF_FS_RPATH 0
+#endif
+
+#define DW_CHAR         sizeof(char)
+#define DW_SHORT        sizeof(short)
+#define DW_LONG         sizeof(long)
+
+/* These types must be 16-bit, 32-bit or larger integer */
+typedef int             INT;
+typedef unsigned int    UINT;
+
+/* These types must be 8-bit integer */
+typedef char            CHAR;
+typedef unsigned char   UCHAR;
+typedef unsigned char   BYTE;
+
+/* These types must be 16-bit integer */
+typedef short           SHORT;
+typedef unsigned short  USHORT;
+typedef unsigned short  WORD;
+typedef unsigned short  WCHAR;
+
+/* These types must be 32-bit integer */
+typedef long            LONG;
+typedef unsigned long   ULONG;
+typedef unsigned long   DWORD;
+/*  by Kenji Arai / JH1PJL  September 10th, 2012  */
+typedef unsigned long long  DDWORD;
+
+//  RAM ------------------------------------------------------------------------
+BYTE Buff[4096];
+char Linebuf[128];          // Console input buffer
+FATFS Fatfs[_VOLUMES];      // File system object for each logical drive
+FIL File1, File2;           // File objects
+FATFS_DIR* Dirx;
+FILINFO Finfo;
+#if FF_USE_LFN
+//inside of FILINFO
+char Lfname[512];
+#endif
+DWORD AccSize;              // Work register for fs command
+WORD AccFiles, AccDirs;
+
+//  ROM / Constant data --------------------------------------------------------
+char *const monmsg0 = "Start monitor program for FatFs File System\r\n";
+char *const monmsg1 = " <Please press any key to start the monitor>";
+
+static const char HelpMsg0[] =
+    "dir   <full_pass>\r\n"
+    "type  <file_name>\r\n"
+    "vol\r\n"
+    "ren   <org_file_name> <new_file_name>\r\n"
+    "copy  <file_name> <file_name>\r\n"
+    "mkdir <dir_name>\r\n"
+    "cd    <dir_name>\r\n"
+    "x     extend commands mode\r\n"
+    "q     Return to main\r\n"
+    "t     Show current time or Adjust time\r\n"
+    "      e.g. t 18 3 28 14 48 20 -> 2018-03-28 14:48:20\r\n"
+    "?     Help/You know the command\r\n"
+    "\r\n";
+
+static const char HelpMsg1[] =
+    "[File system controls]\r\n"
+    " fi <ld#> [<mount>]- Force initialized the volume\r\n"
+    " fs [<path>] - Show volume status\r\n"
+    " fl [<path>] - Show a directory\r\n"
+    " fo <mode> <file> - Open a file\r\n"
+    "    <mode>  Read=1, Write=2\r\n"
+    " fc - Close the file\r\n"
+    " fe <ofs> - Move fp in normal seek\r\n"
+    " fd <len> - Read and dump the file\r\n"
+    " fr <len> - Read the file\r\n"
+    " fw <len> <val> - Write to the file\r\n"
+    " fn <org.name> <new.name> - Rename an object\r\n"
+    " fu <name> - Unlink an object\r\n"
+    " fv - Truncate the file at current fp\r\n"
+    " fk <name> - Create a directory\r\n"
+    " fa <atrr> <mask> <object name> - Change attribute of an object\r\n"
+    " ft <year> <month> <day> <hour> <min> <sec> <name>"
+    " - Change timestamp of an object\r\n"
+    " fx <src.file> <dst.file> - Copy a file\r\n"
+    " fg <path> - Change current directory\r\n"
+    " fq - Show current directory\r\n"
+    " fb <name> - Set volume label\r\n"
+    " fm <ld#> <type> <csize> - Create file system\r\n"
+    " fz [<len>] - Change/Show R/W length for fr/fw/fx command\r\n"
+    "[Disk contorls]\r\n"
+    " di <pd#> - Initialize disk\r\n"
+    " dd [<pd#> <lba>] - Dump a secrtor\r\n"
+    " ds <pd#> - Show disk status\r\n"
+    "[Buffer controls]\r\n"
+    " bd <ofs> - Dump working buffer\r\n"
+    " be <ofs> [<data>] ... - Edit working buffer\r\n"
+    " br <pd#> <lba> [<count>] - Read disk into working buffer\r\n"
+    " bw <pd#> <lba> [<count>] - Write working buffer into disk\r\n"
+    " bf <val> - Fill working buffer\r\n"
+    "[Misc commands]\r\n"
+    " q Return\r\n"
+    " ? Help\r\n"
+    "\r\n";
+
+//  Function prototypes --------------------------------------------------------
+#if (MBED_MAJOR_VERSION == 2)
+extern SDFileSystem fs;
+#elif (MBED_MAJOR_VERSION == 5)
+extern HeapBlockDevice bd;
+extern FATFileSystem fs;
+#endif
+
+static void extended_mon( char *ptr );
+static void v_next( char *ptr );
+static void d_next( char *ptr );
+static void c_next( char *ptr );
+static void m_next( char *ptr );
+static void r_next( char *ptr );
+static void t_next( char *ptr );
+static void memory_inf(char *ptr);
+static void disk_inf(char *ptr);
+
+static void crlf( void );
+static FRESULT scan_files( char* path );
+static void put_rc( FRESULT rc );
+static void file_inf( char *ptr );
+static void put_dump( void* buff, unsigned long addr, int len, int width );
+static void chk_and_set_time(char *ptr);
+static int xatoi ( char **str, long *res );
+
+void get_line (char *buff, int len);
+
+//  Object ---------------------------------------------------------------------
+extern  Serial pc;
+static Timer   t;
+
+//------------------------------------------------------------------------------
+//  Control Program
+//------------------------------------------------------------------------------
+// Monitor program for File control
+void mon ()
+{
+    char *ptr;
+
+    Dirx = new FATFS_DIR;
+    /* Open Uart to communicate with Host PC */
+    PUTS(monmsg0);
+    PUTS(monmsg1);
+    crlf();
+#if FF_USE_LFN
+    // no needs because FILINFO structure is changed
+    Finfo.lfname = Lfname;
+    Finfo.lfsize = sizeof Lfname;
+#endif
+    for (;;) {
+        DEBUG_LINE
+        PUTC('>');
+        ptr = Linebuf;
+        get_line( ptr, sizeof(Linebuf) );
+        switch ( *ptr++ ) {
+                // vol
+            case 'v' :
+                v_next(ptr);
+                break;
+                // dir
+            case 'd' :
+                d_next(ptr);
+                break;
+                // cd, copy
+            case 'c' :
+                c_next(ptr);
+                break;
+                // mkdir
+            case 'm' :
+                m_next(ptr);
+                break;
+                // ren
+            case 'r' :
+                r_next(ptr);
+                break;
+            case 't' :
+                t_next(ptr);
+                break;
+            case 'x' :
+                extended_mon(ptr);
+                break;
+                // Help
+            case '?' :
+                PUTS(HelpMsg0);
+                break;
+                // Exit monitor (return to main())
+            case 'q' :
+                PUTS("Return to main\r\n");
+                return;
+                // Not a command
+            default:
+                PUTS("? [HELP]=?");
+                crlf();
+                break;
+        }
+    }
+}
+
+uint32_t get_disk_freespace(void)
+{
+    long  p1;
+    UINT   s1, s2;
+    FATFS  *fs;
+    BYTE res;
+
+    if (Dirx == NULL){
+        Dirx = new FATFS_DIR;
+    }
+    char p = NULL;
+    res = f_opendir(Dirx, &p);
+    if (res) {
+        return 0;
+    }
+    p1 = s1 = s2 = 0;
+    for(;;) {
+        res = f_readdir(Dirx, &Finfo);
+        if ((res != FR_OK) || !Finfo.fname[0]) break;
+        if (Finfo.fattrib & AM_DIR) {
+            s2++;
+        } else {
+            s1++;
+            p1 += Finfo.fsize;
+        }
+    }
+    res = f_getfree(&p, (DWORD*)&p1, &fs);
+    DWORD tot_sect = (fs->n_fatent - 2) * fs->csize;
+    DWORD fre_sect = p1 * fs->csize;
+#if 0
+    PRINTF("%lu KB total drive space.\n"
+           "%lu KB available.\n",
+           tot_sect / 2, fre_sect / 2);
+#endif
+    uint32_t size = fre_sect / 2;
+//    uint64_t size = p1 * fs->csize * 512;
+    if (res == FR_OK) {
+        return size;
+    } else {
+        return 0;
+    }
+}
+
+static void extended_mon( char *ptr )
+{
+    PUTS(HelpMsg1);
+    while(true) {
+        PUTS("e>");
+        ptr = Linebuf;
+        get_line( ptr, sizeof(Linebuf) );
+        switch ( *ptr++ ) {
+            case 'f' :
+                DEBUG_LINE;
+                file_inf(ptr);
+                break;
+            case 'd' :
+                DEBUG_LINE;
+                disk_inf(ptr);
+                break;
+            case 'm' :
+                DEBUG_LINE;
+                memory_inf(ptr);
+                break;
+            case '?' :
+                DEBUG_LINE;
+                PUTS(HelpMsg1);
+                break;
+            case 'q' :
+                DEBUG_LINE;
+                return;
+            default:
+                PUTS( "?\r\n" );
+        }
+    }
+}
+
+//------------------------------------------------------------------------------
+// General monitor functions
+static void v_next( char *ptr )
+{
+    switch ( *ptr++ ) {
+        case 'o' :
+            if (*ptr == 'l') {
+                *ptr = 's';
+                file_inf(ptr);  // fs [<path>] - Show volume status
+            }
+            break;
+        default:
+            PUTS( "?\r\n" );
+    }
+}
+
+static void d_next(char *ptr)
+{
+    switch ( *ptr++ ) {
+        case 'i' :
+            if (*ptr == 'r') {
+                *ptr = 'l';
+                file_inf(ptr);  // fl [<path>] - Directory listing
+            }
+            break;
+        default:
+            PUTS( "?\r\n" );
+    }
+}
+
+static void c_next(char *ptr)
+{
+    switch ( *ptr++ ) {
+        case 'o' :
+            if ((*ptr == 'p') && (*(ptr + 1) == 'y')) {
+                ptr++;
+                *ptr = 'x';
+                file_inf(ptr);  // fx <src_name> <dst_name> - Copy file
+            }
+            break;
+        case 'd' :
+            *ptr = 'g';
+            file_inf(ptr);  // fx <src_name> <dst_name> - Copy file
+            break;
+        default:
+            PUTS( "?\r\n" );
+    }
+}
+
+static void m_next(char *ptr)
+{
+    switch ( *ptr++ ) {
+        case 'k' :
+            if ((*ptr == 'd') && (*(ptr + 1) == 'i') && (*(ptr + 2) == 'r')) {
+                ptr += 2;
+                *ptr = 'k';
+                file_inf(ptr);  // fk <name> - Create a directory
+            }
+            break;
+        default:
+            PUTS("?\r\n");
+    }
+}
+
+static void r_next(char *ptr)
+{
+    switch (*ptr++) {
+        case 'e' :
+            if (*ptr == 'n') {
+                // fn <old_name> <new_name> - Change file/dir name
+                file_inf(ptr);
+            }
+            break;
+        default:
+            PUTS("?\r\n");
+    }
+}
+
+static void t_next(char *ptr)
+{
+    switch (*ptr++) {
+        case ' ' :
+        case 0x0d:
+            chk_and_set_time(ptr);
+        case 'y' :
+            if ((*ptr == 'p') && (*(ptr + 1) == 'e')) {
+                ptr++;
+                *ptr = '&';
+                file_inf(ptr);
+            }
+            break;
+        default:
+            PUTS("?\r\n");
+    }
+}
+
+static FRESULT scan_files (
+    char* path      /* Pointer to the path name working buffer */
+)
+{
+    FATFS_DIR  dirs;
+    FRESULT res;
+    BYTE i;
+    char *fn;
+
+    if ((res = f_opendir(&dirs, path)) == FR_OK) {
+        i = strlen(path);
+        PRINTF("path: %s, n=%u\r\n", path, i);
+        while (((res = f_readdir(&dirs, &Finfo)) == FR_OK) && Finfo.fname[0]) {
+            if (FF_FS_RPATH && Finfo.fname[0] == '.') {
+                continue;
+            }
+#if FF_USE_LFN
+            //fn = *Finfo.lfname ? Finfo.lfname : Finfo.fname;
+            if (Finfo.altname[0] == 0) {
+                fn = Finfo.fname;
+            } else {
+                fn = Finfo.altname;
+            }
+#else
+            fn = Finfo.fname;
+#endif
+            if (Finfo.fattrib & AM_DIR) {
+                AccDirs++;
+                *(path+i) = '/';
+                strcpy(path+i+1, fn);
+                res = scan_files(path);
+                *(path+i) = '\0';
+                if (res != FR_OK) break;
+            } else {
+                PRINTF("%s/%s\r\n", path, fn);
+                AccFiles++;
+                AccSize += Finfo.fsize;
+            }
+        }
+    }
+    return res;
+}
+
+static void put_rc (FRESULT rc)
+{
+    const char *str =
+        "OK\0" "DISK_ERR\0" "INT_ERR\0" "NOT_READY\0" "NO_FILE\0" "NO_PATH\0"
+        "INVALID_NAME\0" "DENIED\0" "EXIST\0" "INVALID_OBJECT\0"
+        "WRITE_PROTECTED\0" "INVALID_DRIVE\0" "NOT_ENABLED\0"
+        "NO_FILE_SYSTEM\0" "MKFS_ABORTED\0" "TIMEOUT\0"
+        "LOCKED\0" "NOT_ENOUGH_CORE\0" "TOO_MANY_OPEN_FILES\0";
+    int i;
+
+    for ( i = 0; i != rc && *str; i++ ) {
+        while ( *str++ ) {
+            ;
+        }
+    }
+    PRINTF( "rc=%u FR_%s\r\n", (UINT)rc, str );
+}
+
+static void file_inf(char *ptr)
+{
+    long  p1, p2, p3;
+    CHAR   *ptr2;
+    BYTE   f_res;
+    UINT   s1, s2, cnt, blen = sizeof Buff;
+    FATFS  *fs;
+    static const BYTE ft[] = {0, 12, 16, 32};
+    BYTE res;
+    DWORD ofs = 0;
+    uint32_t tim;
+
+    switch (*ptr++) {
+        case '&' :
+            DEBUG_LINE;
+            while (*ptr == ' ') ptr++;
+            /* Open a file */
+            f_res = f_open(&File1, ptr, FA_READ);
+            if ( f_res ) {
+                put_rc((FRESULT)f_res);
+                break;
+            }
+            DEBUG_LINE;
+            /* Read all lines and display it */
+            while(true) {
+                f_res = f_read(&File1, (TCHAR*)Buff, blen, &cnt);
+                if ( f_res ) {
+                    put_rc((FRESULT)f_res);
+                    break;
+                }
+                for (s1 = 0; s1 < cnt; s1++) {
+                    PUTC(Buff[s1]);
+                }
+                if (cnt != blen) {
+                    break;
+                }
+            }
+            DEBUG_LINE;
+            /* Close the file */
+            f_close(&File1);
+            break;
+
+        case 'i' :  /* fi [<opt>]- Initialize logical drive */
+            if ( !xatoi(&ptr, &p1) ) {
+                break;
+            }
+            if (!xatoi(&ptr, &p2)) p2 = 0;
+            put_rc(f_mount(&Fatfs[p1], (const TCHAR*)p1, 0));
+            break;
+
+        case 's' :  /* fs [<path>] - Show volume status */
+            f_res = f_getfree( ptr, (DWORD*)&p2, &fs );
+            if ( f_res ) {
+                put_rc((FRESULT)f_res);
+                break;
+            }
+            PRINTF
+            (
+                "\rFAT type = FAT%u\r\nBytes/Cluster"
+                " = %lu\r\nNumber of FATs = %u\r\n"
+                "Root DIR entries = %u\r\n"
+                "Sectors/FAT = %lu\r\n"
+                "Number of clusters = %lu\r\n"
+                "FAT start (lba) = %lu\r\n"
+                "DIR start (lba,clustor) = %lu\r\n"
+                "Data start (lba) = %lu\r\n",
+                ft[fs->fs_type & 3], (DWORD)fs->csize * 512, fs->n_fats,
+                fs->n_rootdir, fs->fsize, (DWORD)fs->n_fatent - 2,
+                fs->fatbase, fs->dirbase, fs->database
+            );
+            AccSize = AccFiles = AccDirs = 0;
+            break;
+        case 'l' :  /* fl [<path>] - Directory listing */
+            while (*ptr == ' ') ptr++;
+            res = f_opendir(Dirx, ptr);
+            if (res) {
+                put_rc((FRESULT)res);
+                break;
+            }
+            p1 = s1 = s2 = 0;
+            for(;;) {
+                res = f_readdir(Dirx, &Finfo);
+                if ((res != FR_OK) || !Finfo.fname[0]) break;
+                if (Finfo.fattrib & AM_DIR) {
+                    s2++;
+                } else {
+                    s1++;
+                    p1 += Finfo.fsize;
+                }
+                PRINTF("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu  %s\r\n",
+                       (Finfo.fattrib & AM_DIR) ? 'D' : '-',
+                       (Finfo.fattrib & AM_RDO) ? 'R' : '-',
+                       (Finfo.fattrib & AM_HID) ? 'H' : '-',
+                       (Finfo.fattrib & AM_SYS) ? 'S' : '-',
+                       (Finfo.fattrib & AM_ARC) ? 'A' : '-',
+                       (Finfo.fdate >> 9) + 1980, (Finfo.fdate >> 5) & 15,
+                       Finfo.fdate & 31,
+                       (Finfo.ftime >> 11), (Finfo.ftime >> 5) & 63,
+                       Finfo.fsize, Finfo.fname);
+            }
+#if 0   // f_getfree cannnot count under Dir, subdirectory area
+            PRINTF("%4u File(s),%10lu bytes total\r\n%4u Dir(s)", s1, p1, s2);
+            res = f_getfree(ptr, (DWORD*)&p1, &fs);
+            if (res == FR_OK)
+                PRINTF(", %10lu bytes free\r\n", p1 * fs->csize * 512);
+            else
+                put_rc((FRESULT)res);
+#else
+            PRINTF("%4u File(s) = %10lu bytes total, %4u Dir(s)\r\n",
+                   s1, p1, s2);
+#endif
+            break;
+
+        case 'o' :  /* fo <mode> <file> - Open a file */
+            if (!xatoi(&ptr, &p1)) break;
+            while (*ptr == ' ') ptr++;
+            put_rc(f_open(&File1, ptr, (BYTE)p1));
+#if 0
+            put_rc(f_open(&File1, "savedata.txt", 1));
+            PRINTF("Open savedata.txt as read mode\r\n");
+#endif
+            break;
+
+        case 'c' :  /* fc - Close a file */
+            put_rc(f_close(&File1));
+            break;
+
+        case 'e' :  /* fe - Seek file pointer */
+            if (!xatoi(&ptr, &p1)) break;
+            res = f_lseek(&File1, p1);
+            put_rc((FRESULT)res);
+            if (res == FR_OK)
+                PRINTF("fptr=%lu(0x%lX)\r\n", File1.fptr, File1.fptr);
+            break;
+
+        case 'd' :  /* fd <len> - read and dump file from current fp */
+            if (!xatoi(&ptr, &p1)) break;
+            ofs = File1.fptr;
+            while (p1) {
+                if ((UINT)p1 >= 16) {
+                    cnt = 16;
+                    p1 -= 16;
+                } else                {
+                    cnt = p1;
+                    p1 = 0;
+                }
+                res = f_read(&File1, Buff, cnt, &cnt);
+                if (res != FR_OK) {
+                    put_rc((FRESULT)res);
+                    break;
+                }
+                if (!cnt) break;
+                put_dump(Buff, ofs, cnt, DW_CHAR);
+                ofs += 16;
+            }
+            break;
+
+        case 'r' :  /* fr <len> - read file */
+            if (!xatoi(&ptr, &p1)) break;
+            p2 = 0;
+            t.reset();
+            t.start();
+            while (p1) {
+                if ((UINT)p1 >= blen) {
+                    cnt = blen;
+                    p1 -= blen;
+                } else {
+                    cnt = p1;
+                    p1 = 0;
+                }
+                res = f_read(&File1, Buff, cnt, &s2);
+                if (res != FR_OK) {
+                    put_rc((FRESULT)res);
+                    break;
+                }
+                p2 += s2;
+                if (cnt != s2) break;
+            }
+            tim = t.read_ms();
+            PRINTF("%lu bytes read with %lu kB/sec.\r\n",
+                   p2, tim ? (p2 / tim) : 0);
+            break;
+
+        case 'w' :  /* fw <len> <val> - write file */
+            if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2)) break;
+            memset(Buff, (BYTE)p2, blen);
+            p2 = 0;
+            t.reset();
+            t.start();
+            while (p1) {
+                if ((UINT)p1 >= blen) {
+                    cnt = blen;
+                    p1 -= blen;
+                } else {
+                    cnt = p1;
+                    p1 = 0;
+                }
+                res = f_write(&File1, Buff, cnt, &s2);
+                if (res != FR_OK) {
+                    put_rc((FRESULT)res);
+                    break;
+                }
+                p2 += s2;
+                if (cnt != s2) break;
+            }
+            tim = t.read_ms();
+            PRINTF("%lu bytes written with %lu kB/sec.\r\n",
+                   p2, tim ? (p2 / tim) : 0);
+            break;
+
+        case 'n' :  /* fn <org.name> <new.name> - Change name of an object */
+            while (*ptr == ' ') ptr++;
+            ptr2 = strchr(ptr, ' ');
+            if (!ptr2) break;
+            *ptr2++ = 0;
+            while (*ptr2 == ' ') ptr2++;
+            put_rc(f_rename(ptr, ptr2));
+            break;
+
+        case 'u' :  /* fu <name> - Unlink an object */
+            while (*ptr == ' ') ptr++;
+            put_rc(f_unlink(ptr));
+            break;
+
+        case 'v' :  /* fv - Truncate file */
+            put_rc(f_truncate(&File1));
+            break;
+
+        case 'k' :  /* fk <name> - Create a directory */
+            while (*ptr == ' ') ptr++;
+            put_rc(f_mkdir(ptr));
+            break;
+#if 0
+        case 'a' :  /* fa <atrr> <mask> <name> - Change attribute of an object */
+            if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2)) break;
+            while (*ptr == ' ') ptr++;
+            put_rc(f_chmod(ptr, p1, p2));
+            break;
+#endif
+#if 0
+            /* ft <year> <month> <day> <hour> <min> <sec> <name>
+                                                 - Change timestamp of an object */
+        case 't' :
+            if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) {
+                break;
+            }
+            Finfo.fdate = ((p1 - 1980) << 9) | ((p2 & 15) << 5) | (p3 & 31);
+            if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) {
+                break;
+            }
+            Finfo.ftime =
+                ((p1 & 31) << 11) | ((p2 & 63) << 5) | ((p3 >> 1) & 31);
+            put_rc(f_utime(ptr, &Finfo));
+            break;
+#endif
+#if FILCPY_NOTUSE == 0
+        case 'x' : /* fx <src_name> <dst_name> - Copy file */
+            while ( *ptr == ' ' ) {
+                ptr++;
+            }
+            ptr2 = strchr( ptr, ' ' );
+            if ( !ptr2 ) {
+                break;
+            }
+            *ptr2++ = 0;
+            while ( *ptr2 == ' ' ) {
+                ptr2++;
+            }
+            f_res = f_open( &File1, ptr, FA_OPEN_EXISTING | FA_READ );
+            PRINTF("Opening %s \r\n", ptr);
+            if ( f_res ) {
+                put_rc( (FRESULT)f_res );
+                break;
+            }
+            f_res = f_open( &File2, ptr2, FA_CREATE_ALWAYS | FA_WRITE );
+            PRINTF(" Creating %s \r\n", ptr2);
+            if ( f_res ) {
+                put_rc( (FRESULT)f_res );
+                f_close( &File1 );
+                break;
+            }
+            PRINTF("Copying file...");
+            p1 = 0;
+            for ( ;; ) {
+                f_res = f_read( &File1, Buff, blen, &s1 );
+                if ( f_res || s1 == 0 ) {
+                    break;   /* error or eof */
+                }
+                f_res = f_write( &File2, Buff, s1, &s2 );
+                p1 += s2;
+                if ( f_res || s2 < s1 ) {
+                    break;   /* error or disk full */
+                }
+            }
+            f_close( &File1 );
+            f_close( &File2 );
+            crlf();
+            break;
+#endif
+#if 0
+        case 'x' : /* fx <src.name> <dst.name> - Copy a file */
+            while (*ptr == ' ') ptr++;
+            ptr2 = strchr(ptr, ' ');
+            if (!ptr2) break;
+            *ptr2++ = 0;
+            while (*ptr2 == ' ') ptr2++;
+            PRINTF("Opening \"%s\"", ptr);
+            res = f_open(&File1, ptr, FA_OPEN_EXISTING | FA_READ);
+            PUTS("\r\n");
+            if (res) {
+                put_rc((FRESULT)res);
+                break;
+            }
+            PRINTF("Creating \"%s\"", ptr2);
+            res = f_open(&File1, ptr2, FA_CREATE_ALWAYS | FA_WRITE);
+            PUTS("\r\n");
+            if (res) {
+                put_rc((FRESULT)res);
+                f_close(&File1);
+                break;
+            }
+            PRINTF("Copying file...");
+            t.reset();
+            t.start();
+            p1 = 0;
+            for (;;) {
+                res = f_read(&File1, Buff, blen, &s1);
+                if (res || s1 == 0) break;   /* error or eof */
+                res = f_write(&File2, Buff, s1, &s2);
+                p1 += s2;
+                if (res || s2 < s1) break;   /* error or disk full */
+            }
+            tim = t.read_ms();
+            PRINTF("\r\n%lu bytes copied with %lu kB/sec.\r\n",
+                   p1, tim ? (p1 / tim) : 0);
+            f_close(&File1);
+            f_close(&File2);
+            break;
+#endif
+#if FF_FS_RPATH
+        case 'g' :  /* fg <path> - Change current directory */
+            while (*ptr == ' ') ptr++;
+            put_rc(f_chdir(ptr));
+            break;
+#if FF_FS_RPATH >= 2
+        case 'q' :  /* fq - Show current dir path */
+            res = f_getcwd(Linebuf, sizeof Linebuf);
+            if (res)
+                put_rc(res);
+            else
+                PRINTF("%s\r\n", Linebuf);
+            break;
+#endif
+#endif
+#if FF_USE_LABEL
+        case 'b' :  /* fb <name> - Set volume label */
+            while (*ptr == ' ') ptr++;
+            put_rc(f_setlabel(ptr));
+            break;
+#endif  /* FF_USE_LABEL */
+#if FF_USE_MKFS
+        case 'm' :  /* fm <type> <csize> - Create file system */
+            if (!xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) break;
+            PRINTF("The volume will be formatted. Are you sure? (Y/n)=");
+            get_line(Linebuf, sizeof Linebuf);
+            if (Linebuf[0] == 'Y')
+                put_rc(f_mkfs("", (BYTE)p2, (DWORD)p3, Buff, sizeof Buff));
+            break;
+#endif  /* FF_USE_MKFS */
+            /* fz [<size>] - Change/Show R/W length for fr/fw/fx command */
+        case 'z' :
+            if (xatoi(&ptr, &p1) && p1 >= 1 && p1 <= (long)sizeof Buff)
+                blen = p1;
+            PRINTF("blen=%u\r\n", blen);
+            break;
+    }
+}
+
+static void memory_inf(char *ptr)
+{
+    long  p1, p2, p3;
+
+    switch (*ptr++) {
+        case 'd' :  /* md[b|h|w] <address> [<count>] - Dump memory */
+            switch (*ptr++) {
+                case 'w':
+                    p3 = DW_LONG;
+                    break;
+                case 'h':
+                    p3 = DW_SHORT;
+                    break;
+                default:
+                    p3 = DW_CHAR;
+            }
+            if (!xatoi(&ptr, &p1)) break;
+            if (!xatoi(&ptr, &p2)) p2 = 128 / p3;
+            for (ptr = (char*)p1; p2 >= 16 / p3; ptr += 16, p2 -= 16 / p3)
+                put_dump(ptr, (DWORD)ptr, 16 / p3, p3);
+            if (p2) put_dump((BYTE*)ptr, (UINT)ptr, p2, p3);
+            break;
+        case 'f' :  /* mf <address> <value> <count> - Fill memory */
+            if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) {
+                break;
+            }
+            while (p3--) {
+                *(BYTE*)p1 = (BYTE)p2;
+                p1++;
+            }
+            break;
+        case 'e' :  /* me[b|h|w] <address> [<value> ...] - Edit memory */
+            switch (*ptr++) {   /* Get data width */
+                case 'w':
+                    p3 = DW_LONG;
+                    break;
+                case 'h':
+                    p3 = DW_SHORT;
+                    break;
+                default:
+                    p3 = DW_CHAR;
+            }
+            if (!xatoi(&ptr, &p1)) break;   /* Get start address */
+            if (xatoi(&ptr, &p2)) { /* 2nd parameter is given (direct mode) */
+                do {
+                    switch (p3) {
+                        case DW_LONG:
+                            *(DWORD*)p1 = (DWORD)p2;
+                            break;
+                        case DW_SHORT:
+                            *(WORD*)p1 = (WORD)p2;
+                            break;
+                        default:
+                            *(BYTE*)p1 = (BYTE)p2;
+                    }
+                    p1 += p3;
+                } while (xatoi(&ptr, &p2)); /* Get next value */
+                break;
+            }
+            for (;;) {  /* 2nd parameter is not given (interactive mode) */
+                switch (p3) {
+                    case DW_LONG:
+                        PRINTF("%08X 0x%08X-", p1, *(DWORD*)p1);
+                        break;
+                    case DW_SHORT:
+                        PRINTF("%08X 0x%04X-", p1, *(WORD*)p1);
+                        break;
+                    default:
+                        PRINTF("%08X 0x%02X-", p1, *(BYTE*)p1);
+                }
+                ptr = Linebuf;
+                get_line(ptr, sizeof Linebuf);
+                if (*ptr == '.') break;
+                if ((BYTE)*ptr >= ' ') {
+                    if (!xatoi(&ptr, &p2)) continue;
+                    switch (p3) {
+                        case DW_LONG:
+                            *(DWORD*)p1 = (DWORD)p2;
+                            break;
+                        case DW_SHORT:
+                            *(WORD*)p1 = (WORD)p2;
+                            break;
+                        default:
+                            *(BYTE*)p1 = (BYTE)p2;
+                    }
+                }
+                p1 += p3;
+            }
+    }
+}
+
+static void disk_inf(char *ptr)
+{
+    long  p1, p2;
+    UINT   s1;
+    BYTE res, b, drv = 0;
+    DWORD ofs = 0, sect = 0, blk[2];
+
+    switch (*ptr++) {
+        case 'd' :  /* dd [<pd#> <sect>] - Dump secrtor */
+            if (!xatoi(&ptr, &p1)) {
+                p1 = drv;
+                p2 = sect;
+            } else {
+                if (!xatoi(&ptr, &p2)) break;
+            }
+            drv = (BYTE)p1;
+            sect = p2;
+            res = disk_read(drv, Buff, sect, 1);
+            if (res) {
+                PRINTF("rc=%d\r\n", (WORD)res);
+                break;
+            }
+            PRINTF("PD#:%u LBA:%lu\r\n", drv, sect++);
+            for (ptr=(char*)Buff, ofs = 0; ofs < 0x200; ptr += 16, ofs += 16)
+                put_dump((BYTE*)ptr, ofs, 16, DW_CHAR);
+            break;
+
+        case 'i' :  /* di <pd#> - Initialize disk */
+            if (!xatoi(&ptr, &p1)) break;
+            PRINTF("rc=%d\r\n", (WORD)disk_initialize((BYTE)p1));
+            break;
+
+        case 's' :  /* ds <pd#> - Show disk status */
+            if (!xatoi(&ptr, &p1)) break;
+            if (disk_ioctl((BYTE)p1, GET_SECTOR_COUNT, &p2) == RES_OK) {
+                PRINTF("Drive size: %lu sectors\r\n", p2);
+            }
+            if (disk_ioctl((BYTE)p1, GET_BLOCK_SIZE, &p2) == RES_OK) {
+                PRINTF("Block size: %lu sectors\r\n", p2);
+            }
+            if (disk_ioctl((BYTE)p1, MMC_GET_TYPE, &b) == RES_OK) {
+                PRINTF("Media type: %u\r\n", b);
+            }
+            if (disk_ioctl((BYTE)p1, MMC_GET_CSD, Buff) == RES_OK) {
+                PUTS("CSD:\r\n");
+                put_dump(Buff, 0, 16, DW_CHAR);
+            }
+            if (disk_ioctl((BYTE)p1, MMC_GET_CID, Buff) == RES_OK) {
+                PUTS("CID:\r\n");
+                put_dump(Buff, 0, 16, DW_CHAR);
+            }
+            if (disk_ioctl((BYTE)p1, MMC_GET_OCR, Buff) == RES_OK) {
+                PUTS("OCR:\r\n");
+                put_dump(Buff, 0, 4, DW_CHAR);
+            }
+            if (disk_ioctl((BYTE)p1, MMC_GET_SDSTAT, Buff) == RES_OK) {
+                PUTS("SD Status:\r\n");
+                for (s1 = 0; s1 < 64; s1 += 16) {
+                    put_dump(Buff+s1, s1, 16, DW_CHAR);
+                }
+            }
+            break;
+
+        case 'c' :  /* Disk ioctl */
+            switch (*ptr++) {
+                case 's' :  /* dcs <pd#> - CTRL_SYNC */
+                    if (!xatoi(&ptr, &p1)) break;
+                    PRINTF("rc=%d\r\n", disk_ioctl((BYTE)p1, CTRL_SYNC, 0));
+                    break;
+                case 'e' :  /* dce <pd#> <s.lba> <e.lba> - CTRL_TRIM */
+                    if (!xatoi(&ptr, &p1) ||
+                            !xatoi(&ptr, (long*)&blk[0]) ||
+                            !xatoi(&ptr, (long*)&blk[1])) {
+                        break;
+                    }
+                    PRINTF("rc=%d\r\n", disk_ioctl((BYTE)p1, CTRL_TRIM, blk));
+                    break;
+            }
+    }
+}
+
+void put_dump (
+    void* buff,             /* Pointer to the array to be dumped */
+    unsigned long addr,     /* Heading address value */
+    int len,                /* Number of items to be dumped */
+    int width               /* Size of the items (DW_CHAR, DW_SHORT, DW_LONG) */
+)
+{
+    int i;
+    unsigned char *bp;
+    unsigned short *sp;
+    unsigned long *lp;
+
+    PRINTF( "%08lx ", addr );      /* address */
+    switch ( width )  {
+        case DW_CHAR:
+            bp = (unsigned char *)buff;
+            for ( i = 0; i < len; i++ ) {       /* Hexdecimal dump */
+                PRINTF( " %02x", bp[i] );
+            }
+            PUTC(' ');
+            for ( i = 0; i < len; i++ ) {       /* ASCII dump */
+                PUTC( (bp[i] >= ' ' && bp[i] <= '~') ? bp[i] : '.' );
+            }
+            break;
+        case DW_SHORT:
+            sp = (unsigned short *)buff;
+            do {                            /* Hexdecimal dump */
+                PRINTF( " %04x", *sp++ );
+            } while ( --len );
+            break;
+        case DW_LONG:
+            lp = (unsigned long *)buff;
+            do {                            /* Hexdecimal dump */
+                PRINTF( " %08lx", *lp++ );
+            } while ( --len );
+            break;
+    }
+    PUTS( "\r\n" );
+}
+
+// RTC related subroutines
+void chk_and_set_time(char *ptr)
+{
+    char buf[64];
+
+    long p1;
+    struct tm t;
+    time_t seconds;
+
+    if (xatoi(&ptr, &p1)) {
+        t.tm_year       = (uint8_t)p1 + 100;
+        pc.printf("Year:%d ",p1);
+        xatoi( &ptr, &p1 );
+        t.tm_mon        = (uint8_t)p1 - 1;
+        pc.printf("Month:%d ",p1);
+        xatoi( &ptr, &p1 );
+        t.tm_mday       = (uint8_t)p1;
+        pc.printf("Day:%d ",p1);
+        xatoi( &ptr, &p1 );
+        t.tm_hour       = (uint8_t)p1;
+        pc.printf("Hour:%d ",p1);
+        xatoi( &ptr, &p1 );
+        t.tm_min        = (uint8_t)p1;
+        pc.printf("Min:%d ",p1);
+        xatoi( &ptr, &p1 );
+        t.tm_sec        = (uint8_t)p1;
+        pc.printf("Sec: %d \r\n",p1);
+        seconds = mktime(&t);
+        set_time(seconds);
+    } else {
+        seconds = time(NULL);
+    }
+    strftime(buf, 50, " %B %d,'%y, %H:%M:%S\r\n", localtime(&seconds));
+    pc.printf("[Time] %s", buf);
+}
+
+//  Get key input data
+void get_line (char *buff, int len)
+{
+    char c;
+    int idx = 0;
+
+    for (;;) {
+        c = GETC();
+        //    Added by Kenji Arai / JH1PJL   May 9th, 2010
+        if (c == '\r') {
+            buff[idx++] = c;
+            break;
+        }
+        if ((c == '\b') && idx) {
+            idx--;
+            PUTC(c);
+            PUTC(' ');
+            PUTC(c);
+        }
+        if (((uint8_t)c >= ' ') && (idx < len - 1)) {
+            buff[idx++] = c;
+            PUTC(c);
+        }
+    }
+    buff[idx] = 0;
+    PUTS("\r\n");
+}
+
+/*  Outpur LF & CR */
+void crlf( void )
+{
+    PRINTF( "\r\n" );
+}
+
+/*  Check key input */
+unsigned int check_hit_key (void)
+{
+    return ( READABLE() );
+}
+
+/*----------------------------------------------*/
+/* Get a value of the string                    */
+/*----------------------------------------------*/
+/*  "123 -5   0x3ff 0b1111 0377  w "
+        ^                           1st call returns 123 and next ptr
+           ^                        2nd call returns -5 and next ptr
+                   ^                3rd call returns 1023 and next ptr
+                          ^         4th call returns 15 and next ptr
+                               ^    5th call returns 255 and next ptr
+                                  ^ 6th call fails and returns 0
+*/
+int xatoi (         /* 0:Failed, 1:Successful */
+    char **str,     /* Pointer to pointer to the string */
+    long *res       /* Pointer to the valiable to store the value */
+)
+{
+    unsigned long val;
+    unsigned char c, r, s = 0;
+
+    *res = 0;
+    while ( (c = **str) == ' ' ) {
+        (*str)++;   /* Skip leading spaces */
+    }
+    if ( c == '-' ) {       /* negative? */
+        s = 1;
+        c = *(++(*str));
+    }
+    if ( c == '0' ) {
+        c = *(++(*str));
+        switch (c) {
+            case 'x':       /* hexdecimal */
+                r = 16;
+                c = *(++(*str));
+                break;
+            case 'b':       /* binary */
+                r = 2;
+                c = *(++(*str));
+                break;
+            default:
+                if ( c <= ' ' ) return 1;   /* single zero */
+                if ( c < '0' || c > '9' ) return 0; /* invalid char */
+                r = 8;      /* octal */
+        }
+    } else {
+        if ( c < '0' || c > '9' ) return 0; /* EOL or invalid char */
+        r = 10;         /* decimal */
+    }
+    val = 0;
+    while ( c > ' ' ) {
+        if ( c >= 'a' ) {
+            c -= 0x20;
+        }
+        c -= '0';
+        if ( c >= 17 ) {
+            c -= 7;
+            if ( c <= 9 ) {
+                return 0;   /* invalid char */
+            }
+        }
+        if ( c >= r ) {
+            return 0;   /* invalid char for current radix */
+        }
+        val = val * r + c;
+        c = *(++(*str));
+    }
+    if (s) val = 0 - val;           /* apply sign if needed */
+    *res = val;
+    return 1;
+}
diff -r 000000000000 -r 6f52c89729de mon.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mon.h	Mon Apr 30 05:20:42 2018 +0000
@@ -0,0 +1,15 @@
+/*
+ * mbed Application program for the mbed
+ *  FatFs Check program /monitor part
+ *
+ * Copyright (c) 2015,'18 Kenji Arai / JH1PJL
+ *  http://www.page.sannet.ne.jp/kenjia/index.html
+ *  https://os.mbed.com/users/kenjiArai/
+ *      Created:    May        5th, 2015
+ *      Revised:    June      14th, 2015
+ *      Revised:    April     29th, 2018
+ */
+
+//  Function prototypes --------------------------------------------------------
+void mon(void);
+uint32_t get_disk_freespace(void);