Test program for FlashAir with iSDIO

Dependencies:   FlashAir_iSDIO SDFileSystem

FlashAir_monitor/mon.cpp

Committer:
kenjiArai
Date:
2019-08-28
Revision:
3:fc1908567f3b

File content as of revision 3:fc1908567f3b:

/*
 * mbed Application program for the mbed
 *  FlashAir Check program
 *
 * Copyright (c) 2015,'19 Kenji Arai / JH1PJL
 *  http://www.page.sannet.ne.jp/kenjia/index.html
 *  https://os.mbed.com/users/kenjiArai/
 *      Created:    May        5th, 2015
 *      Revised:    August    27th, 2019
 */

//  Include --------------------------------------------------------------------
#include "mbed.h"
#include "FlashAir_iSDIO.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

// from ffconf.h
#define _VOLUMES    1

//  RAM ------------------------------------------------------------------------
BYTE Buff[4096];
char linebuf[64];           // Console input buffer
FATFS Fatfs[_VOLUMES];      // File system object for each logical drive
FIL File1, File2;           // File objects
FATFS_DIR* Dirx;
FILINFO Finfo;
char Lfname[512];
DWORD AccSize;              // Work register for fs command
WORD AccFiles, AccDirs;

uint8_t buffer[512];
uint32_t nextSequenceId = 0;

//  ROM / Constant data --------------------------------------------------------
const char *const monmsg0 =
    "Start monitor program for FlashAir & FatFs/SD File System\r\n";
const char *const monmsg1 =
    " <Please press any key to start the monitor>";
const char *const hisdmsg0 =
    "Entered FlashAir/TOSHIBA iSDIO control commands\r\n";
const char *const hisdmsg1 =
    " retrun=q Help=?\r\n";
const char *const rtnmsg =
    "Return to Root Mode\r\n";
const char *const msg_ok =
    "\r\nSuccess\r\n";
const char *const msg_ng =
    "\r\nFailed\r\n";

static const char HelpMsg0[] =
    "i     FlashAir, iSDIO\r\n"
    "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"
    "q     Return to main\r\n"
    "t     Show current time or Adjust time\r\n"
    "      e.g. t 19 8 24 14 15 16 -> August 24,'19, 14:15:16\r\n"
    "?     Help/You know the command\r\n"
    "\r\n";

static const char HelpMsg1[] =
    "a  Set as AP(Access Point) mode / Act as Host\r\n"
    "s  Set as STA(Station) mode / Connect to Host\r\n"
    "q  Return to File control monitor\r\n"
    "\r\n";

static const char HelpMsg2[] =
    "Connect to Host: step d->s->c->g\r\n"
    "s  Scan sounded host\r\n"
    "c  Connect specific host\r\n"
    "d  Disconnect line\r\n"
    "g  Get status\r\n"
    "t  Current time(JST)\r\n"
    "q  Return to previous monitor\r\n"
    "\r\n";

static const char HelpMsg3[] =
    "Estblish as Host: step d->e->g\r\n"
    "e  Establish connection\r\n"
    "d  Disconnect line\r\n"
    "g  Get status\r\n"
    "q  Return to previous monitor\r\n"
    "\r\n";

// Host information @ STA mode
const char *const ssid       = "pr500m-c86a71-1";
const char *const networkKey = "7daaa01146644";

// FlashAir Host name & password @ AP mode
const char *const name_as_host = "flashair";
const char *const password_ap  = "12345678";

//  Function prototypes --------------------------------------------------------

//  Object ---------------------------------------------------------------------
extern Serial pc;
extern FlashAir_iSDIO sd;
Timer   t;

//------------------------------------------------------------------------------
//  Control Program
//------------------------------------------------------------------------------
// Monitor program for File control
void mon ()
{
    char *ptr;

    Dirx = new FATFS_DIR;
    /* Open Uart to communicate with Host PC */
    pc.puts(monmsg0);
    pc.puts(monmsg1);
    crlf();
    /* monitor is running all time when systen is running */
    char c = pc.getc();
    Finfo.lfname = Lfname;
    Finfo.lfsize = sizeof Lfname;
    //pc.printf("0x%x, 0x%x\r\n", mon, HelpMsg0);
    for (;;) {
        DEBUG_LINE
        pc.putc('>');
        ptr = linebuf;
        get_line( ptr, sizeof(linebuf) );
        switch ( *ptr++ ) {
            // iSDIO, goto sub functions
            case 'i' :
                isdio_mon(ptr);
                break;
            // 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;
            // type, set time
            case 't' :
                t_next(ptr);
                break;
            // Help
            case '?' :
                pc.puts(HelpMsg0);
                break;
            // Exit monitor (return to main())
            case 'q' :
                pc.puts("Return to main\r\n");
                return;
            // Not a command
            default:
                DEBUG_LINE
                pc.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);
    uint32_t size = p1 * fs->csize * 512;
    if (res == FR_OK) {
        return size;
    } else {
        return 0;
    }
}

static void isdio_mon(char *ptr)
{
    pc.puts(hisdmsg0);
    pc.puts(hisdmsg1);
    for (uint32_t i=0; i==0; ) {
        pc.puts("iSDIO>");
        ptr = linebuf;
        get_line(ptr, sizeof(linebuf));
        switch(*ptr++) {
            case 'a' :
                ap_mon(ptr);
                break;
            case 's' :
                sta_mon(ptr);
                break;
            case 'q' :
                i = 1;  // return
                break;
            case '?' :
                pc.puts(HelpMsg1);
                break;
            default:
                pc.putc('?');
                crlf();
        }
    }
    pc.puts(rtnmsg);
}

// Station Mode (connect to Host)
static void sta_mon(char *ptr)
{
    static char str[512];
    time_t seconds_jst;

    pc.puts("Enterd FlashAir STA(Station) Mode -> connect to Host Device\r\n");
    pc.puts(hisdmsg1);
    //Initialise card
    FILE *fp = fopen("/sd/mbed.txt", "a");
    sprintf((char *)buffer, "..");
    fprintf(fp,(char *)buffer);
    fclose(fp);
    DEBUG_LINE
    // Read the previous sequence ID.
    if (sd.readExtMemory(1, 1, 0x420, 0x34, buffer)) {
        DEBUG_LINE
        if (buffer[0x20] == 0x01) {
            DEBUG_LINE
            nextSequenceId = get_u32(buffer + 0x24);
            sd.waitResponse(nextSequenceId);
            nextSequenceId++;
        } else {
            DEBUG_LINE
            nextSequenceId = 0;
        }
    } else {
        DEBUG_LINE
        pc.puts("Failed to read status\r\n");
        nextSequenceId = 0;
    }
    for (uint32_t i=0; i==0; ) {
        DEBUG_LINE
        pc.puts("STA>");
        ptr = linebuf;
        get_line(ptr, sizeof(linebuf));
        switch(*ptr++) {
            case 's' :
                DEBUG_LINE
                if (iSDIO_scan(nextSequenceId) &&
                        iSDIO_waitResponse(nextSequenceId) &&
                        iSDIO_showScanResult()) {
                    pc.puts(msg_ok);
                } else {
                    pc.puts(msg_ng);
                }
                nextSequenceId++;
                break;
            case 'c' :
                DEBUG_LINE
                if (iSDIO_connect(nextSequenceId, ssid, networkKey) &&
                        iSDIO_waitResponse(nextSequenceId)) {
                    pc.puts(msg_ok);
                } else {
                    pc.puts(msg_ng);
                }
                nextSequenceId++;
                break;
            case 'e' :
                DEBUG_LINE
                if (iSDIO_establish(nextSequenceId)) {
                    pc.puts(msg_ok);
                } else {
                    pc.puts(msg_ng);
                }
                break;
            case 'd' :
                DEBUG_LINE
                if (iSDIO_disconnect(nextSequenceId)) {
                    pc.puts(msg_ok);
                } else {
                    pc.puts(msg_ng);
                }
                break;
            case 't' :
                DEBUG_LINE
                seconds_jst = time(NULL);   // Read Int. RTC time
                strftime(
                    str, 40,
                    "%B %d,'%y, %H:%M:%S",
                    localtime(&seconds_jst));
                pc.printf("Time(JST): %s\r\n", str);
                break;
            case 'g' :
                DEBUG_LINE
                if (iSDIO_status() == false) {
                    pc.puts(msg_ng);
                }
                break;
            case 'q' :
                i = 1;  // return
                break;
            case '?' :
                pc.puts(HelpMsg2);
                break;
            default:
                DEBUG_LINE
                pc.putc('?');
                crlf();
        }
    }
    pc.puts(rtnmsg);
}

// Access Point Mode (Act as Host)
static void ap_mon(char *ptr)
{
    pc.puts("Enterd FlashAir AP(Access Point) Mode -> Act as Host\r\n");
    pc.puts(hisdmsg1);
    for (uint32_t i=0; i==0; ) {
        pc.puts("AP>");
        ptr = linebuf;
        get_line(ptr, sizeof(linebuf));
        switch(*ptr++) {
            case 'e' :
                if (iSDIO_establish(nextSequenceId)) {
                    pc.puts(msg_ok);
                } else {
                    pc.puts(msg_ng);
                }
                break;
            case 'd' :
                if (iSDIO_disconnect(nextSequenceId)) {
                    pc.puts(msg_ok);
                } else {
                    pc.puts(msg_ng);
                }
                break;
            case 'g' :
                if (iSDIO_status() == false) {
                    pc.puts(msg_ng);
                }
                break;
            case 'q' :
                i = 1;  // return
                break;
            case '?' :
                pc.puts(HelpMsg3);
                break;
            default:
                pc.putc('?');
                crlf();
        }
    }
    pc.puts(rtnmsg);
}

//------------------------------------------------------------------------------
// iSDIO
void printByte(uint8_t value)
{
    pc.printf("%x", value >> 4);
    pc.printf("%x", value & 0xF);
}

void printBytes(uint8_t* p, uint32_t len)
{
    for (uint32_t i = 0; i < len; ++i) {
        printByte(p[i]);
    }
}
void printIPAddress(uint8_t* p)
{
    pc.printf("%d", p[0]);
    pc.putc('.');
    pc.printf("%d", p[1]);
    pc.putc('.');
    pc.printf("%d", p[2]);
    pc.putc('.');
    pc.printf("%d", p[3]);
}

void printHex(uint8_t* p, uint32_t len)
{
    uint32_t i = 0;
    while (i < len) {
        if ((i & 0xf) == 0) {
            pc.puts("\r\n");
            printByte(i >> 4);
            pc.puts(": ");
        }
        printByte(*p++);
        i++;
    }
    pc.puts("\r\n");
}

uint8_t iSDIO_establish(uint32_t sequenceId)
{
    pc.puts("Establish command: \r\n");
    memset(buffer, 0, 512);
    uint8_t* p = buffer;
    p = put_command_header(p, 1, 0);
    p = put_command_info_header(p, 0x03, sequenceId, 3);
    p = put_str_arg(p, (const uint8_t*)name_as_host);
    p = put_str_arg(p, (const uint8_t*)password_ap);
    p = put_u8_arg(p, 0x06);
    put_command_header(buffer, 1, (p - buffer));
    printHex(buffer, (p - buffer));
    return sd.writeExtDataPort(1, 1, 0x000, buffer) ? true : false;
}

uint8_t iSDIO_connect(
    uint32_t sequenceId,
    const char* ssid,
    const char* networkKey
)
{
    pc.puts("Connect command: \r\n");
    memset(buffer, 0, 512);
    uint8_t* p = buffer;
    p = put_command_header(p, 1, 0);
    p = put_command_info_header(p, 0x02, sequenceId, 2);
    p = put_str_arg(p, (const uint8_t*)ssid);
    p = put_str_arg(p, (const uint8_t*)networkKey);
    put_command_header(buffer, 1, (p - buffer));
    printHex(buffer, (p - buffer));
    return sd.writeExtDataPort(1, 1, 0x000, buffer) ? true : false;
}

uint8_t iSDIO_disconnect(uint32_t sequenceId)
{
    pc.puts("Disconnect command: \r\n");
    memset(buffer, 0, 512);
    uint8_t* p = buffer;
    p = put_command_header(p, 1, 0);
    p = put_command_info_header(p, 0x07, sequenceId, 0);
    put_command_header(buffer, 1, (p - buffer));
    printHex(buffer, (p - buffer));
    return sd.writeExtDataPort(1, 1, 0x000, buffer) ? true : false;
}

uint8_t iSDIO_waitResponse(uint32_t sequenceId)
{
    pc.puts("Waiting response ");
    uint8_t prev = 0xFF;
    for (int i = 0; i < 20; ++i) {
        memset(buffer, 0, 0x14);

        // Read command response status.
        if (!sd.readExtMemory(1, 1, 0x440, 0x14, buffer)) {
            return false;
        }
        uint8_t resp = get_u8(buffer + 8);
        if (sequenceId == get_u32(buffer + 4)) {
            if (prev != resp) {
                switch (resp) {
                    case 0x00:
                        pc.puts("  Initial");
                        break;
                    case 0x01:
                        pc.puts("  Command Processing");
                        break;
                    case 0x02:
                        pc.puts("  Command Rejected");
                        return false;
                    case 0x03:
                        pc.puts("  Process Succeeded");
                        return true;
                    case 0x04:
                        pc.puts("  Process Terminated");
                        return false;
                    default:
                        pc.puts("  Process Failed ");
                        return false;
                }
                prev = resp;
            }
        }
        pc.putc('.');
        wait(1.0);
    }
    return false;
}

uint8_t iSDIO_scan(uint32_t sequenceId)
{
    pc.puts("Scan: \r\n");
    memset(buffer, 0, 512);
    uint8_t* p = buffer;
    p = put_command_header(p, 1, 0);
    p = put_command_info_header(p, 0x01, sequenceId, 0);
    put_command_header(buffer, 1, (p - buffer));
    printHex(buffer, (p - buffer));
    return sd.writeExtDataPort(1, 1, 0x000, buffer) ? true : false;
}

uint8_t iSDIO_showScanResult(void)
{
    // Try to output some wifi info.
    if (!sd.readExtDataPort(1, 1, 0x200, buffer)) {
        pc.puts("Scan result: False\r\n");
        return false;
    }
    uint8_t num = get_u8(buffer + 24);
    pc.puts("\r\nScan result:Number of APs: ");
    pc.printf("%u\r\n",num);
    uint8_t* p = buffer + 28;
    for (int i = 0; i < num; i++) {
        pc.putc(' ');
        pc.printf("%s",(const char*)p);
        pc.puts(", ");
        printBytes(p + 32, 6);
        pc.puts(", ");
        pc.printf("%u",get_u8(p + 38));
        pc.puts(", ");
        switch (get_u8(p + 39)) {
            case 0 :
                pc.puts("NoSec");
                break;
            case 1 :
                pc.puts("WEP");
                break;
            case 2 :
                pc.puts("WPA");
                break;
            case 3 :
                pc.puts("WPA2");
                break;
            default :
                pc.puts("error");
                break;
        }
        pc.puts("\r\n");
        p += 44;
    }
    return true;
}

uint8_t iSDIO_status(void)
{
    pc.puts("Read iSDIO Status Register\r\n");
    // Read iSDIO Status Register (E7 1.10 2.2.2.1)
    memset(buffer, 0, 0x200);
    if (!sd.readExtMemory(1, 1, 0x400, 0x200, buffer)) {
        pc.puts("Cannot read Ext Memory\r\n");
        return false;
    }
#if 1
    uint16_t j = 0;
    pc.puts("HEX 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\r\n 0 ");
    for (int i = 0; i < 0x200; i++) {
        pc.printf("%2x ", buffer[i]);
        if ((i & 0xf) == 0xf) {
            if (i == 0x1ff) {
                pc.puts("\r\n");
            } else {
                pc.printf("\r\n%2x ", ++j);
            }
        }
    }
#endif
    // Show values in the common status area.
    pc.puts("\r\n == iSDIO Status Registers == ");
    pc.puts("\r\n [0400h] Command Write Status: ");
    if (buffer[0x000] & 0x01) pc.puts("CWU ");
    if (buffer[0x000] & 0x02) pc.puts("CWA ");
    pc.puts("\r\n [0420h] iSDIO Status: ");
    if (buffer[0x020] & 0x01) pc.puts("CRU ");
    if (buffer[0x020] & 0x02) pc.puts("ESU ");
    if (buffer[0x020] & 0x04) pc.puts("MCU ");
    if (buffer[0x020] & 0x08) pc.puts("ASU ");
    pc.puts("\r\n [0422h] iSDIO Int Enable: ");
    if (buffer[0x022] & 0x01) pc.puts("CRU_ENA ");
    if (buffer[0x022] & 0x02) pc.puts("ESU_ENA ");
    if (buffer[0x022] & 0x04) pc.puts("MCU_ENA ");
    if (buffer[0x022] & 0x08) pc.puts("ASU_ENA ");
    pc.puts("\r\n [0424h] Error Status: ");
    if (buffer[0x024] & 0x01) pc.puts("CRE ");
    if (buffer[0x024] & 0x02) pc.puts("CWE ");
    if (buffer[0x024] & 0x04) pc.puts("RRE ");
    if (buffer[0x024] & 0x08) pc.puts("APE ");
    pc.puts("\r\n [0426h] Memory Status: ");
    if (buffer[0x026] & 0x01) pc.puts("MEX ");
    if (buffer[0x026] & 0x02) pc.puts("FAT ");
    for (int i = 0; i < 8; ++i) {
        uint8_t addr = 0x40 + i * 0x14;
        pc.puts("\r\n [04");
        printByte(addr);
        pc.puts("h] Command Response Status #");
        pc.printf("%d", i + 1);
        pc.puts(": ");
        if (buffer[addr] & 0x01) {
            pc.puts("id = ");
            pc.printf("%d", get_u16(buffer + addr + 2));
            pc.puts(", sequence id = ");
            pc.printf("%d", get_u32(buffer + addr + 4));
            pc.puts(", status = ");
            switch (buffer[addr + 8]) {
                case 0x00:
                    pc.puts("Initial");
                    break;
                case 0x01:
                    pc.puts("Command Processing");
                    break;
                case 0x02:
                    pc.puts("Command Rejected");
                    break;
                case 0x03:
                    pc.puts("Process Succeeded");
                    break;
                case 0x04:
                    pc.puts("Process Terminated");
                    break;
                default:
                    pc.puts("Process Failed ");
                    pc.printf("0x%x", buffer[addr + 8]);
                    break;
            }
        } else {
            pc.puts("Not registered");
        }
    }
    // Show values in the application status area.
    pc.puts("\r\n == Wireless LAN Status Registers ==");
    pc.puts("\r\n [0500h] DLNA Status: ");
    if (buffer[0x100] & 0x01) pc.puts("ULR ");
    if (buffer[0x100] & 0x02) pc.puts("DLU ");
    if (buffer[0x100] & 0x04) pc.puts("CBR ");
    if (buffer[0x100] & 0x08) pc.puts("CDR ");
    pc.puts("\r\n [0501h] P2P Status: ");
    if (buffer[0x101] & 0x01) pc.puts("ILU ");
    if (buffer[0x101] & 0x02) pc.puts("FLU ");
    pc.puts("\r\n [0502h] PTP Status: ");
    if (buffer[0x102] & 0x01) pc.puts("RPO ");
    if (buffer[0x102] & 0x02) pc.puts("RPD ");
    if (buffer[0x102] & 0x04) pc.puts("RPC ");
    if (buffer[0x102] & 0x08) pc.puts("CPI ");
    if (buffer[0x102] & 0x10) pc.puts("DPI ");
    if (buffer[0x102] & 0x20) pc.puts("CIL ");
    pc.puts("\r\n [0504h] Application: ");
    pc.printf("0x%x", buffer[0x104]);
    pc.puts("\r\n [0506h] WLAN: ");
    if ((buffer[0x106] & 0x01) == 0x00) pc.puts("No Scan, ");
    if ((buffer[0x106] & 0x01) == 0x01) pc.puts("Scanning, ");
    if ((buffer[0x106] & 0x06) == 0x00) pc.puts("No WPS, ");
    if ((buffer[0x106] & 0x06) == 0x02) pc.puts("WPS with PIN, ");
    if ((buffer[0x106] & 0x06) == 0x04) pc.puts("WPS with PBC, ");
    if ((buffer[0x106] & 0x08) == 0x00) pc.puts("Group Client, ");
    if ((buffer[0x106] & 0x08) == 0x08) pc.puts("Group Owner ");
    if ((buffer[0x106] & 0x10) == 0x00) pc.puts("STA, ");
    if ((buffer[0x106] & 0x10) == 0x10) pc.puts("AP, ");
    if ((buffer[0x106] & 0x60) == 0x00) pc.puts("Initial, ");
    if ((buffer[0x106] & 0x60) == 0x20) pc.puts("Infrastructure, ");
    if ((buffer[0x106] & 0x60) == 0x40) pc.puts("Wi-Fi Direct, ");
    if ((buffer[0x106] & 0x80) == 0x00) pc.puts("No Connection, ");
    if ((buffer[0x106] & 0x80) == 0x80) pc.puts("Connected, ");
    pc.puts("\r\n [0508h] SSID: ");
    for (int i = 0; i < 32 && buffer[0x108 + i] != 0; ++i) {
        pc.printf("%c", (char)buffer[0x108 + i]);
    }
    pc.puts("\r\n [0528h] Encryption Mode: ");
    switch (buffer[0x128]) {
        case 0 :
            pc.puts("Open System and no encryption");
            break;
        case 1 :
            pc.puts("Open System and WEP");
            break;
        case 2 :
            pc.puts("Shared Key and WEP");
            break;
        case 3 :
            pc.puts("WPA-PSK and TKIP");
            break;
        case 4 :
            pc.puts("WPA-PSK and AES");
            break;
        case 5 :
            pc.puts("WPA2-PSK and TKIP");
            break;
        case 6 :
            pc.puts("WPA2-PSK and AES");
            break;
        default:
            pc.puts("Unknown");
    }
    pc.puts("\r\n [0529h] Signal Strength: ");
    pc.printf("%d", buffer[0x129]);
    pc.puts("\r\n [052Ah] Channel: ");
    if (buffer[0x12A] == 0) pc.puts("No connection");
    else pc.printf("%d", buffer[0x12A]);
    pc.puts("\r\n [0530h] MAC Address: ");
    printBytes(buffer + 0x130, 6);
    pc.puts("\r\n [0540h] ID: ");
    for (int i = 0; i < 16 && buffer[0x140 + i] != 0; ++i) {
        pc.printf("%c", (char)buffer[0x140 + i]);
    }
    pc.puts("\r\n [0550h] IP Address: ");
    printIPAddress(buffer + 0x150);
    pc.puts("\r\n [0554h] Subnet Mask: ");
    printIPAddress(buffer + 0x154);
    pc.puts("\r\n [0558h] Default Gateway: ");
    printIPAddress(buffer + 0x158);
    pc.puts("\r\n [055Ch] Preferred DNS Server: ");
    printIPAddress(buffer + 0x15C);
    pc.puts("\r\n [0560h] Alternate DNS Server: ");
    printIPAddress(buffer + 0x160);
    pc.puts("\r\n [0564h] Proxy Server: ");
    if ((buffer[0x164] & 0x01) == 0x00) pc.puts("Disabled");
    if ((buffer[0x164] & 0x01) == 0x01) pc.puts("Enabled");
    pc.puts("\r\n [0570h] Date: ");
    pc.printf("%d", buffer[0x171] + 1980);
    pc.putc('-');
    pc.printf("%d", buffer[0x170] >> 4);
    pc.putc('-');
    pc.printf("%d", buffer[0x170] & 0xF);
    pc.puts("\r\n [0572h] Time: ");
    pc.printf("%d", buffer[0x173] >> 3);
    pc.putc(':');
    pc.printf("%d", buffer[0x172] << 3 | buffer[0x170] >> 3);
    pc.putc(':');
    pc.printf("%d", (buffer[0x172] & 0x1F) * 2);
    pc.puts("\r\n [0574h] HTTP Status: ");
    pc.printf("%d", buffer[0x174] & 0xEF);
    if ((buffer[0x174] & 0x80) == 0x00) pc.puts(" (No Processing)");
    if ((buffer[0x174] & 0x80) == 0x80) pc.puts(" (Processing)");
    pc.puts("\r\n [0575h] Power Save Management: ");
    if ((buffer[0x175] & 0x01) == 0x00) pc.puts("Power Save Mode Off");
    if ((buffer[0x175] & 0x01) == 0x01) pc.puts("Power Save Mode On");
    pc.puts("\r\n [0576h] File System Management: ");
    if ((buffer[0x176] & 0x01) == 0x00) {
        pc.puts("FS Information may be modified");
    }
    if ((buffer[0x176] & 0x01) == 0x01) {
        pc.puts("FS Information shall not be modified");
    }
    pc.puts("\r\n");
    return true;
}

//------------------------------------------------------------------------------
// 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:
            pc.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:
            pc.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);  // fg Change directory
            break;
        default:
            pc.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:
            pc.puts("?\r\n");
    }
}

static void r_next(char *ptr)
{
    switch (*ptr++) {
        case 'e' :
            // fn <old_name> <new_name> - Change file/dir name
            if (*ptr == 'n') {
                file_inf(ptr);
            }
            break;
        default:
            pc.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:
            pc.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);
        pc.printf("path: %s, n=%u\r\n", path, i);
        while (((res = f_readdir(&dirs, &Finfo)) == FR_OK) && Finfo.fname[0]) {
            if (_FS_RPATH && Finfo.fname[0] == '.') {
                continue;
            }
            fn = *Finfo.lfname ? Finfo.lfname : Finfo.fname;
            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 {
                pc.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";
    for (uint32_t i = 0; i != rc && *str; i++ ) {
        while ( *str++ ) { ;}
    }
    pc.printf( "rc=%u FR_%s\r\n", (UINT)rc, str );
}

static void file_inf(char *ptr)
{
    DDWORD pf;
    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++) {
                    pc.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;
            }
            pc.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++;
            }
            f_res = f_opendir( Dirx, ptr );
            if ( f_res ) {
                put_rc( (FRESULT)f_res );
                break;
            }
            pf = 0;
            p1 = s1 = s2 = 0;
            for(;;) {
                f_res = f_readdir( Dirx, &Finfo );
                if ( (f_res != FR_OK) || !Finfo.fname[0] ) {
                    break;
                }
                if ( Finfo.fattrib & AM_DIR ) {
                    s2++;
                } else {
                    s1++;
                    pf += Finfo.fsize;
                }
                pc.printf(
                    "%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu  %-12s  %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,
                    Lfname );
            }
            p1 = pf%100;
            pc.printf(
                "%4u file(s),%10lu%02lu bytes total\r\n%4u Dir(s)",
                s1, (DWORD)(pf/100), p1, s2
            );
            if ( f_getfree(ptr, (DWORD *)&p1, &fs) == FR_OK ) {
                pc.printf( ",   %10lu bytes free\r\n", p1 * fs->csize * 512 );
            } else {
                put_rc( (FRESULT)f_res );
            }
            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));
            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)
                pc.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();
            pc.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();
            pc.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 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 );
            pc.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 );
            pc.printf(" Creating %s \r\n", ptr2);
            if ( f_res ) {
                put_rc( (FRESULT)f_res );
                f_close( &File1 );
                break;
            }
            pc.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 _FS_RPATH
        case 'g' :  /* fg <path> - Change current directory */
            while (*ptr == ' ') ptr++;
            put_rc(f_chdir(ptr));
            break;
#endif
    }
}

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;

    pc.printf( "%08lx ", addr );      /* address */
    switch ( width )  {
        case DW_CHAR:
            bp = (unsigned char *)buff;
            for ( i = 0; i < len; i++ ) {       /* Hexdecimal dump */
                pc.printf( " %02x", bp[i] );
            }
            pc.putc(' ');
            for ( i = 0; i < len; i++ ) {       /* ASCII dump */
                pc.putc( (bp[i] >= ' ' && bp[i] <= '~') ? bp[i] : '.' );
            }
            break;
        case DW_SHORT:
            sp = (unsigned short *)buff;
            do {                            /* Hexdecimal dump */
                pc.printf( " %04x", *sp++ );
            } while ( --len );
            break;
        case DW_LONG:
            lp = (unsigned long *)buff;
            do {                            /* Hexdecimal dump */
                pc.printf( " %08lx", *lp++ );
            } while ( --len );
            break;
    }
    pc.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:%ld ",p1);
        xatoi( &ptr, &p1 );
        t.tm_mon        = (uint8_t)p1 - 1;
        pc.printf("Month:%ld ",p1);
        xatoi( &ptr, &p1 );
        t.tm_mday       = (uint8_t)p1;
        pc.printf("Day:%ld ",p1);
        xatoi( &ptr, &p1 );
        t.tm_hour       = (uint8_t)p1;
        pc.printf("Hour:%ld ",p1);
        xatoi( &ptr, &p1 );
        t.tm_min        = (uint8_t)p1;
        pc.printf("Min:%ld ",p1);
        xatoi( &ptr, &p1 );
        t.tm_sec        = (uint8_t)p1;
        pc.printf("Sec: %ld \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 = pc.getc();
        //    Added by Kenji Arai / JH1PJL   May 9th, 2010
        if (c == '\r') {
            buff[idx++] = c;
            break;
        }
        if ((c == '\b') && idx) {
            idx--;
            pc.putc(c);
            pc.putc(' ');
            pc.putc(c);
        }
        if (((uint8_t)c >= ' ') && (idx < len - 1)) {
            buff[idx++] = c;
            pc.putc(c);
        }
    }
    buff[idx] = 0;
    pc.puts("\r\n");
}

/*  Outpur LF & CR */
void crlf( void )
{
    pc.printf( "\r\n" );
}

/*  Check key input */
unsigned int check_hit_key (void)
{
    return ( pc.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;
}