Modify the file main.cpp for M487

Dependencies:   BufferedSerial

Files at this revision

API Documentation at this revision

Comitter:
shliu1
Date:
Fri Sep 29 05:45:43 2017 +0000
Commit message:
main.cpp adds the setting of TARGET_NUMAKER_PFM_M487 for M487

Changed in this revision

BufferedSerial.lib Show annotated file Show diff for this revision Revisions of this file
NuMaker-mbed-SD-driver.lib Show annotated file Show diff for this revision Revisions of this file
NuMaker-mbed-SD-driver/NuSDBlockDevice.cpp Show annotated file Show diff for this revision Revisions of this file
NuMaker-mbed-SD-driver/NuSDBlockDevice.h Show annotated file Show diff for this revision Revisions of this file
NuMaker-mbed-SD-driver/README.md Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-os.lib Show annotated file Show diff for this revision Revisions of this file
mbed_app.json Show annotated file Show diff for this revision Revisions of this file
ste_config.h Show annotated file Show diff for this revision Revisions of this file
uweb_server.cpp Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r c89ccc69a48b BufferedSerial.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BufferedSerial.lib	Fri Sep 29 05:45:43 2017 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/sam_grove/code/BufferedSerial/#a0d37088b405
diff -r 000000000000 -r c89ccc69a48b NuMaker-mbed-SD-driver.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NuMaker-mbed-SD-driver.lib	Fri Sep 29 05:45:43 2017 +0000
@@ -0,0 +1,1 @@
+https://github.com/OpenNuvoton/NuMaker-mbed-SD-driver/#253f370c308331fc9a82b5387ed108750ac70ac8
diff -r 000000000000 -r c89ccc69a48b NuMaker-mbed-SD-driver/NuSDBlockDevice.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NuMaker-mbed-SD-driver/NuSDBlockDevice.cpp	Fri Sep 29 05:45:43 2017 +0000
@@ -0,0 +1,443 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2015-2016 Nuvoton
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Nuvoton mbed enabled targets which support SD card of SD bus mode */
+#if defined(TARGET_NUMAKER_PFM_NUC472) || defined(TARGET_NUMAKER_PFM_M487)
+
+#include "NuSDBlockDevice.h"
+#include "PeripheralPins.h"
+#include "mbed_debug.h"
+#include "nu_modutil.h"
+
+#if defined(TARGET_NUMAKER_PFM_NUC472)
+#define NU_SDH_DAT0         PF_5
+#define NU_SDH_DAT1         PF_4
+#define NU_SDH_DAT2         PF_3
+#define NU_SDH_DAT3         PF_2
+#define NU_SDH_CMD          PF_7
+#define NU_SDH_CLK          PF_8
+#define NU_SDH_CDn          PF_6
+
+#elif defined(TARGET_NUMAKER_PFM_M487)
+#define NU_SDH_DAT0         PE_2
+#define NU_SDH_DAT1         PE_3
+#define NU_SDH_DAT2         PE_4
+#define NU_SDH_DAT3         PE_5
+#define NU_SDH_CMD          PE_7
+#define NU_SDH_CLK          PE_6
+#define NU_SDH_CDn          PD_13
+
+#endif
+
+#if defined(TARGET_NUMAKER_PFM_NUC472)
+extern DISK_DATA_T SD_DiskInfo0;
+extern DISK_DATA_T SD_DiskInfo1;
+extern SD_INFO_T SD0,SD1;
+extern int sd0_ok,sd1_ok;
+
+#elif defined(TARGET_NUMAKER_PFM_M487)
+extern int SDH_ok;
+extern SDH_INFO_T SD0, SD1;
+
+#endif
+
+
+static const struct nu_modinit_s sdh_modinit_tab[] = {
+#if defined(TARGET_NUMAKER_PFM_NUC472)
+    {SD_0_0, SDH_MODULE, CLK_CLKSEL0_SDHSEL_PLL, CLK_CLKDIV0_SDH(2), SDH_RST, SD_IRQn, NULL},
+    {SD_0_1, SDH_MODULE, CLK_CLKSEL0_SDHSEL_PLL, CLK_CLKDIV0_SDH(2), SDH_RST, SD_IRQn, NULL},
+#elif defined(TARGET_NUMAKER_PFM_M487)
+    {SD_0, SDH0_MODULE, CLK_CLKSEL0_SDH0SEL_HCLK, CLK_CLKDIV0_SDH0(2), SDH0_RST, SDH0_IRQn, NULL},
+    {SD_1, SDH1_MODULE, CLK_CLKSEL0_SDH1SEL_HCLK, CLK_CLKDIV3_SDH1(2), SDH1_RST, SDH1_IRQn, NULL},
+#endif
+
+    {NC, 0, 0, 0, 0, (IRQn_Type) 0, NULL}
+};
+
+
+
+#define SD_BLOCK_DEVICE_ERROR_WOULD_BLOCK        -5001	/*!< operation would block */
+#define SD_BLOCK_DEVICE_ERROR_UNSUPPORTED        -5002	/*!< unsupported operation */
+#define SD_BLOCK_DEVICE_ERROR_PARAMETER          -5003	/*!< invalid parameter */
+#define SD_BLOCK_DEVICE_ERROR_NO_INIT            -5004	/*!< uninitialized */
+#define SD_BLOCK_DEVICE_ERROR_NO_DEVICE          -5005	/*!< device is missing or not connected */
+#define SD_BLOCK_DEVICE_ERROR_WRITE_PROTECTED    -5006	/*!< write protected */
+
+
+NuSDBlockDevice::NuSDBlockDevice() :
+    _sectors(0),
+    _is_initialized(false),
+    _dbg(false),
+    _sdh_modinit(NULL),
+    _sdh((SDName) NC),
+    _sdh_base(NULL),
+#if defined(TARGET_NUMAKER_PFM_NUC472)
+    _sdh_port((uint32_t) -1),
+#endif
+    _sdh_irq_thunk(this, &NuSDBlockDevice::_sdh_irq),
+    _sd_dat0(NU_SDH_DAT0),
+    _sd_dat1(NU_SDH_DAT1),
+    _sd_dat2(NU_SDH_DAT2),
+    _sd_dat3(NU_SDH_DAT3),
+    _sd_cmd(NU_SDH_CMD),
+    _sd_clk(NU_SDH_CLK),
+    _sd_cdn(NU_SDH_CDn)
+{
+}
+
+NuSDBlockDevice::NuSDBlockDevice(PinName sd_dat0, PinName sd_dat1, PinName sd_dat2, PinName sd_dat3,
+    PinName sd_cmd, PinName sd_clk, PinName sd_cdn) :
+    _sectors(0),
+    _is_initialized(false),
+    _dbg(false),
+    _sdh_modinit(NULL),
+    _sdh((SDName) NC),
+    _sdh_base(NULL),
+#if defined(TARGET_NUMAKER_PFM_NUC472)
+    _sdh_port((uint32_t) -1),
+#endif
+    _sdh_irq_thunk(this, &NuSDBlockDevice::_sdh_irq)
+{
+    _sd_dat0 = sd_dat0;
+    _sd_dat1 = sd_dat1;
+    _sd_dat2 = sd_dat2;
+    _sd_dat3 = sd_dat3;
+    _sd_cmd = sd_cmd;
+    _sd_clk = sd_clk;
+    _sd_cdn = sd_cdn;
+}
+
+NuSDBlockDevice::~NuSDBlockDevice()
+{
+    if (_is_initialized) {
+        deinit();
+    }
+}
+
+int NuSDBlockDevice::init()
+{
+    _lock.lock();
+    int err = BD_ERROR_OK;
+    
+    do {
+        err = _init_sdh();
+        if (err != BD_ERROR_OK) {
+            break;
+        }
+        
+#if defined(TARGET_NUMAKER_PFM_NUC472)
+        SD_Open(_sdh_port | CardDetect_From_GPIO);
+        SD_Probe(_sdh_port);
+
+        switch (_sdh_port) {
+        case SD_PORT0:
+            _is_initialized = sd0_ok && (SD0.CardType != SD_TYPE_UNKNOWN);
+            break;
+    
+        case SD_PORT1:
+            _is_initialized = sd1_ok && (SD1.CardType != SD_TYPE_UNKNOWN);
+            break;
+        }
+    
+#elif defined(TARGET_NUMAKER_PFM_M487)
+        MBED_ASSERT(_sdh_modinit != NULL);
+        
+        NVIC_SetVector(_sdh_modinit->irq_n, _sdh_irq_thunk.entry());
+        NVIC_EnableIRQ(_sdh_modinit->irq_n);
+
+        SDH_Open(_sdh_base, CardDetect_From_GPIO);
+        SDH_Probe(_sdh_base);
+    
+        switch (NU_MODINDEX(_sdh)) {
+        case 0:
+            _is_initialized = SDH_ok && (SD0.CardType != SDH_TYPE_UNKNOWN);
+            break;
+    
+        case 1:
+            _is_initialized = SDH_ok && (SD1.CardType != SDH_TYPE_UNKNOWN);
+            break;
+        }
+#endif
+
+        if (!_is_initialized) {
+            debug_if(_dbg, "Fail to initialize card\n");
+            err = BD_ERROR_DEVICE_ERROR;
+        }
+        debug_if(_dbg, "init card = %d\n", _is_initialized);
+        _sectors = _sd_sectors();
+    
+    } while (0);
+
+    _lock.unlock();
+    
+    return err;
+}
+
+int NuSDBlockDevice::deinit()
+{
+    _lock.lock();
+   
+    if (_sdh_modinit) {
+        CLK_DisableModuleClock(_sdh_modinit->clkidx);
+    }
+    
+#if defined(TARGET_NUMAKER_PFM_NUC472)
+    // TODO
+#elif defined(TARGET_NUMAKER_PFM_M487)
+    // TODO
+#endif
+
+    _is_initialized = false;
+    
+    _lock.unlock();
+    
+    return BD_ERROR_OK;
+}
+
+int NuSDBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size)
+{
+    if (! is_valid_program(addr, size)) {
+        return SD_BLOCK_DEVICE_ERROR_PARAMETER;
+    }
+
+    _lock.lock();
+    int err = BD_ERROR_OK;
+    
+    do {
+        if (! _is_initialized) {
+            err = SD_BLOCK_DEVICE_ERROR_NO_INIT;
+        }
+
+#if defined(TARGET_NUMAKER_PFM_NUC472)
+        if (SD_Write(_sdh_port, (uint8_t*)b, addr / 512, size / 512) != 0) {
+#elif defined(TARGET_NUMAKER_PFM_M487)
+        if (SDH_Write(_sdh_base, (uint8_t*)b, addr / 512, size / 512) != 0) {
+#endif
+            err = BD_ERROR_DEVICE_ERROR;
+        }
+        
+    } while (0);
+    
+    _lock.unlock();
+    
+    return err;
+}
+
+int NuSDBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size)
+{
+    if (! is_valid_read(addr, size)) {
+        return SD_BLOCK_DEVICE_ERROR_PARAMETER;
+    }
+
+    _lock.lock();
+    int err = BD_ERROR_OK;
+    
+    do {
+        if (! _is_initialized) {
+            err = SD_BLOCK_DEVICE_ERROR_NO_INIT;
+        }
+        
+#if defined(TARGET_NUMAKER_PFM_NUC472)
+        if (SD_Read(_sdh_port, (uint8_t*)b, addr / 512, size / 512) != 0) {
+#elif defined(TARGET_NUMAKER_PFM_M487)
+        if (SDH_Read(_sdh_base, (uint8_t*)b, addr / 512, size / 512) != 0) {
+#endif
+            err = BD_ERROR_DEVICE_ERROR;
+        }
+        
+    } while (0);
+    
+    _lock.unlock();
+    
+    return err;
+}
+
+int NuSDBlockDevice::erase(bd_addr_t addr, bd_size_t size)
+{
+    return BD_ERROR_OK;
+}
+
+bd_size_t NuSDBlockDevice::get_read_size() const
+{
+    return 512;
+}
+
+bd_size_t NuSDBlockDevice::get_program_size() const
+{
+    return 512;
+}
+
+bd_size_t NuSDBlockDevice::get_erase_size() const
+{
+    return 512;
+}
+
+bd_size_t NuSDBlockDevice::size() const
+{
+    return 512 * _sectors;
+}
+
+void NuSDBlockDevice::debug(bool dbg)
+{
+    _dbg = dbg;
+}
+
+int NuSDBlockDevice::_init_sdh()
+{
+    debug_if(_dbg, "SD MPF Setting & Enable SD IP Clock\n");
+        
+    // Check if all pins belong to the same SD module
+    // Merge SD DAT0/1/2/3
+    uint32_t sd_dat0_mod = pinmap_peripheral(_sd_dat0, PinMap_SD_DAT0);
+    uint32_t sd_dat1_mod = pinmap_peripheral(_sd_dat1, PinMap_SD_DAT1);
+    uint32_t sd_dat2_mod = pinmap_peripheral(_sd_dat2, PinMap_SD_DAT2);
+    uint32_t sd_dat3_mod = pinmap_peripheral(_sd_dat3, PinMap_SD_DAT3);
+    uint32_t sd_dat01_mod = (SDName) pinmap_merge(sd_dat0_mod, sd_dat1_mod);
+    uint32_t sd_dat23_mod = (SDName) pinmap_merge(sd_dat2_mod, sd_dat3_mod);
+    uint32_t sd_dat0123_mod = (SDName) pinmap_merge(sd_dat01_mod, sd_dat23_mod);
+    // Merge SD CMD/CLK/CDn
+    uint32_t sd_cmd_mod = pinmap_peripheral(_sd_cmd, PinMap_SD_CMD);
+    uint32_t sd_clk_mod = pinmap_peripheral(_sd_clk, PinMap_SD_CLK);
+    uint32_t sd_cdn_mod = pinmap_peripheral(_sd_cdn, PinMap_SD_CD);
+    uint32_t sd_cmdclk_mod = (SDName) pinmap_merge(sd_cmd_mod, sd_clk_mod);
+    uint32_t sd_cmdclkcdn_mod = (SDName) pinmap_merge(sd_cmdclk_mod, sd_cdn_mod);
+    // Merge SD DAT0/1/2/3 and SD CMD/CLK/CDn
+    uint32_t sd_mod = (SDName) pinmap_merge(sd_dat0123_mod, sd_cmdclkcdn_mod);
+    
+    if (sd_mod == (uint32_t) NC) {
+        debug("SD pinmap error\n");
+        return BD_ERROR_DEVICE_ERROR;
+    }
+    
+    _sdh_modinit = get_modinit(sd_mod, sdh_modinit_tab);
+    MBED_ASSERT(_sdh_modinit != NULL);
+    MBED_ASSERT(_sdh_modinit->modname == sd_mod);
+    
+    
+    // Configure SD multi-function pins
+    pinmap_pinout(_sd_dat0, PinMap_SD_DAT0);
+    pinmap_pinout(_sd_dat1, PinMap_SD_DAT1);
+    pinmap_pinout(_sd_dat2, PinMap_SD_DAT2);
+    pinmap_pinout(_sd_dat3, PinMap_SD_DAT3);
+    pinmap_pinout(_sd_cmd, PinMap_SD_CMD);
+    pinmap_pinout(_sd_clk, PinMap_SD_CLK);
+    pinmap_pinout(_sd_cdn, PinMap_SD_CD);
+    
+    // Configure SD IP clock 
+    SYS_UnlockReg();
+    
+    // Determine SDH port dependent on passed-in pins
+    _sdh = (SDName) sd_mod;
+    _sdh_base = (SDH_T *) NU_MODBASE(_sdh);
+#if defined(TARGET_NUMAKER_PFM_NUC472)
+    switch (NU_MODSUBINDEX(_sdh)) {
+    case 0:
+        _sdh_port = SD_PORT0;
+        break;
+        
+    case 1:
+        _sdh_port = SD_PORT1;
+        break;
+    }
+#endif
+
+    SYS_ResetModule(_sdh_modinit->rsetidx);
+    CLK_SetModuleClock(_sdh_modinit->clkidx, _sdh_modinit->clksrc, _sdh_modinit->clkdiv);
+    CLK_EnableModuleClock(_sdh_modinit->clkidx);
+    
+    SYS_LockReg();
+
+    return BD_ERROR_OK;
+}
+
+uint32_t NuSDBlockDevice::_sd_sectors()
+{
+    _lock.lock();
+   
+#if defined(TARGET_NUMAKER_PFM_NUC472)
+    switch (_sdh_port) {
+    case SD_PORT0:
+        _sectors = SD_DiskInfo0.totalSectorN;
+        break;
+    case SD_PORT1:
+        _sectors = SD_DiskInfo1.totalSectorN;
+        break;
+    }
+    
+#elif defined(TARGET_NUMAKER_PFM_M487)
+    switch (NU_MODINDEX(_sdh)) {
+    case 0:
+        _sectors = SD0.totalSectorN;
+        break;
+    case 1:
+        _sectors = SD1.totalSectorN;
+        break;
+    }
+    
+#endif
+
+    _lock.unlock();
+    
+    return _sectors;
+}
+
+void NuSDBlockDevice::_sdh_irq()
+{
+#if defined(TARGET_NUMAKER_PFM_NUC472)
+    // TODO: Support IRQ
+    
+#elif defined(TARGET_NUMAKER_PFM_M487)
+    // FMI data abort interrupt
+    if (_sdh_base->GINTSTS & SDH_GINTSTS_DTAIF_Msk) {
+        _sdh_base->GINTSTS = SDH_GINTSTS_DTAIF_Msk;
+        /* ResetAllEngine() */
+        _sdh_base->GCTL |= SDH_GCTL_GCTLRST_Msk;
+    }
+
+    //----- SD interrupt status
+    if (_sdh_base->INTSTS & SDH_INTSTS_BLKDIF_Msk) {
+        // block down
+        extern uint8_t volatile _SDH_SDDataReady;
+        _SDH_SDDataReady = TRUE;
+        _sdh_base->INTSTS = SDH_INTSTS_BLKDIF_Msk;
+    }
+    
+    // NOTE: On M487, there are two SDH instances which each support port 0 and don't support port 1.
+    //       Port 0 (support): INTEN.CDIEN0, INTEN.CDSRC0, INTSTS.CDIF0, INTSTS.CDSTS0
+    //       Port 1 (no support): INTEN.CDIEN1, INTEN.CDSRC1, INTSTS.CDIF1, INTSTS.CDSTS1
+    if (_sdh_base->INTSTS & SDH_INTSTS_CDIF_Msk) { // port 0 card detect
+        _sdh_base->INTSTS = SDH_INTSTS_CDIF_Msk;
+        // TBD: Support PnP
+    }
+
+    // CRC error interrupt
+    if (_sdh_base->INTSTS & SDH_INTSTS_CRCIF_Msk) {
+        _sdh_base->INTSTS = SDH_INTSTS_CRCIF_Msk;      // clear interrupt flag
+    }
+
+    if (_sdh_base->INTSTS & SDH_INTSTS_DITOIF_Msk) {
+        _sdh_base->INTSTS = SDH_INTSTS_DITOIF_Msk;
+    }
+
+    // Response in timeout interrupt
+    if (_sdh_base->INTSTS & SDH_INTSTS_RTOIF_Msk) {
+        _sdh_base->INTSTS |= SDH_INTSTS_RTOIF_Msk;
+    }
+#endif
+}
+
+
+#endif  //#if defined(TARGET_NUMAKER_PFM_NUC472) || defined(TARGET_NUMAKER_PFM_M487)
diff -r 000000000000 -r c89ccc69a48b NuMaker-mbed-SD-driver/NuSDBlockDevice.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NuMaker-mbed-SD-driver/NuSDBlockDevice.h	Fri Sep 29 05:45:43 2017 +0000
@@ -0,0 +1,135 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2015-2016 Nuvoton
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __NU_SD_BLOCK_DEVICE_H__
+#define __NU_SD_BLOCK_DEVICE_H__
+
+#include "BlockDevice.h"
+#include "mbed.h"
+
+struct nu_modinit_s;
+
+class NuSDBlockDevice : public BlockDevice {
+public:
+    /** Lifetime of an SD card
+     */
+    NuSDBlockDevice();
+    NuSDBlockDevice(PinName sd_dat0, PinName sd_dat1, PinName sd_dat2, PinName sd_dat3,
+        PinName sd_cmd, PinName sd_clk, PinName sd_cdn);
+    virtual ~NuSDBlockDevice();
+
+    /** Initialize a block device
+     *
+     *  @return         0 on success or a negative error code on failure
+     */
+    virtual int init();
+
+    /** Deinitialize a block device
+     *
+     *  @return         0 on success or a negative error code on failure
+     */
+    virtual int deinit();
+
+    /** Read blocks from a block device
+     *
+     *  @param buffer   Buffer to write blocks to
+     *  @param addr     Address of block to begin reading from
+     *  @param size     Size to read in bytes, must be a multiple of read block size
+     *  @return         0 on success, negative error code on failure
+     */
+    virtual int read(void *buffer, bd_addr_t addr, bd_size_t size);
+
+    /** Program blocks to a block device
+     *
+     *  The blocks must have been erased prior to being programmed
+     *
+     *  @param buffer   Buffer of data to write to blocks
+     *  @param addr     Address of block to begin writing to
+     *  @param size     Size to write in bytes, must be a multiple of program block size
+     *  @return         0 on success, negative error code on failure
+     */
+    virtual int program(const void *buffer, bd_addr_t addr, bd_size_t size);
+
+    /** Erase blocks on a block device
+     *
+     *  The state of an erased block is undefined until it has been programmed
+     *
+     *  @param addr     Address of block to begin erasing
+     *  @param size     Size to erase in bytes, must be a multiple of erase block size
+     *  @return         0 on success, negative error code on failure
+     */
+    virtual int erase(bd_addr_t addr, bd_size_t size);
+
+    /** Get the size of a readable block
+     *
+     *  @return         Size of a readable block in bytes
+     */
+    virtual bd_size_t get_read_size() const;
+
+    /** Get the size of a programable block
+     *
+     *  @return         Size of a programable block in bytes
+     *  @note Must be a multiple of the read size
+     */
+    virtual bd_size_t get_program_size() const;
+
+    /** Get the size of a eraseable block
+     *
+     *  @return         Size of a eraseable block in bytes
+     *  @note Must be a multiple of the program size
+     */
+    virtual bd_size_t get_erase_size() const;
+
+    /** Get the total size of the underlying device
+     *
+     *  @return         Size of the underlying device in bytes
+     */
+    virtual bd_size_t size() const;
+
+    /** Enable or disable debugging
+     *
+     *  @param          State of debugging
+     */
+    virtual void debug(bool dbg);
+
+private:
+    int _init_sdh();
+    uint32_t _sd_sectors();
+    void _sdh_irq();
+
+    uint32_t _sectors;
+    bool _is_initialized;
+    bool _dbg;
+    Mutex _lock;
+    
+    const struct nu_modinit_s * _sdh_modinit;
+    SDName      _sdh;
+    SDH_T *     _sdh_base;
+#if defined(TARGET_NUMAKER_PFM_NUC472)
+    uint32_t    _sdh_port;
+#endif
+
+    CThunk<NuSDBlockDevice>     _sdh_irq_thunk;
+
+    PinName _sd_dat0;
+    PinName _sd_dat1;
+    PinName _sd_dat2;
+    PinName _sd_dat3;
+    PinName _sd_cmd;
+    PinName _sd_clk;
+    PinName _sd_cdn;
+};
+
+#endif  /* __NU_SD_BLOCK_DEVICE_H__ */
diff -r 000000000000 -r c89ccc69a48b NuMaker-mbed-SD-driver/README.md
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NuMaker-mbed-SD-driver/README.md	Fri Sep 29 05:45:43 2017 +0000
@@ -0,0 +1,17 @@
+# Block device driver for SD card supported by Nuvoton platforms
+
+This driver implements [BlockDevice class](https://github.com/ARMmbed/mbed-os/blob/master/features/filesystem/bd/BlockDevice.h)
+introduced with mbed OS 5.4 for SD card running in SD bus mode on Nuvoton platforms which support it.
+
+ARM mbed team also releases an official [SD driver](https://github.com/armmbed/sd-driver), but it supports SPI bus mode 
+rather than SD bus mode.
+
+## Use with FAT file system
+The [SD file system example](https://developer.mbed.org/teams/Nuvoton/code/NuMaker-mbed-SD-FileSystem-example/) is cloned from
+the [FAT file system example](https://github.com/armmbed/mbed-os-example-fat-filesystem) released by ARM mbed team and
+is modified to use this SD block device to back the FAT file system.
+
+## Support Nuvoton platforms
+- [NuMaker-PFM-NUC472](https://developer.mbed.org/platforms/Nuvoton-NUC472/)
+- NuMaker-PFM-M487
+
diff -r 000000000000 -r c89ccc69a48b main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Fri Sep 29 05:45:43 2017 +0000
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2017 Nuvoton Tecnology Corp. All rights reserved.
+ *
+ * The code is forward data from UART port to Ethernet, and vice versa.
+ * 
+ *
+ */
+ 
+#include "ste_config.h"
+
+/* If define USE_STATIC_IP, specify the default IP address. */
+#if 0
+    // private IP address for general purpose
+#define IP_ADDRESS      "192.168.1.2"
+#define NETWORK_MASK    "255.255.255.0"
+#define GATEWAY_ADDRESS "192.168.1.1"
+#else
+    // private IP address only for test with Windows when DHCP server doesn't exist.
+#define IP_ADDRESS      "169.254.108.2"
+#define NETWORK_MASK    "255.255.0.0"
+#define GATEWAY_ADDRESS "169.254.108.1"
+#endif
+
+/* Default configuration for network */
+S_NET_CONFIG net_config = {IP_STATIC_MODE, IP_ADDRESS, NETWORK_MASK, GATEWAY_ADDRESS};
+
+#if defined (TARGET_NUMAKER_PFM_M487)
+BufferedSerial serial_0(PH_8, PH_9, 256, 4);    // UART1
+BufferedSerial serial_1(PC_12, PC_11, 256, 4);  // UART0
+BufferedSerial serial_2(PA_3, PA_2, 256, 4);  // UART4
+
+#elif defined (TARGET_NUMAKER_PFM_NUC472)
+BufferedSerial serial_0(PH_1, PH_0, 256, 4);    // UART4
+BufferedSerial serial_1(PG_2, PG_1, 256, 4);    // UART0
+BufferedSerial serial_2(PC_11, PC_10, 256, 4);  // UART2
+
+#elif defined (TARGET_NUMAKER_PFM_M453)
+#error The board has no Ethernet.
+
+#else
+#error define UART ports for your board.
+#endif
+
+/* Default configuration for network ports and UART ports, etc. */
+S_PORT_CONFIG port_config[MAX_UART_PORTS] = {
+
+#if MAX_UART_PORTS == 1
+    {NET_SERVER_MODE, NET_PORT_BASE, &serial_0, DEFAULT_UART_BAUD, 8, 1, SerialBase::None}
+
+#elif MAX_UART_PORTS == 2
+    {NET_SERVER_MODE, NET_PORT_BASE + 0, &serial_0, DEFAULT_UART_BAUD, 8, 1, SerialBase::None},
+    {NET_SERVER_MODE, NET_PORT_BASE + 1, &serial_1, DEFAULT_UART_BAUD, 8, 1, SerialBase::None}
+
+#elif MAX_UART_PORTS == 3
+    {NET_SERVER_MODE, NET_PORT_BASE + 0, &serial_0, DEFAULT_UART_BAUD, 8, 1, SerialBase::None},
+    {NET_SERVER_MODE, NET_PORT_BASE + 1, &serial_1, DEFAULT_UART_BAUD, 8, 1, SerialBase::None},
+    {NET_SERVER_MODE, NET_PORT_BASE + 2, &serial_2, DEFAULT_UART_BAUD, 8, 1, SerialBase::None}
+
+#else
+#error You have to define ports mapping table.
+#endif
+};
+
+/* UART port to output debug message */
+RawSerial output(USBTX, USBRX);             // UART3 on NuMaker-PFM-NUC472
+EthernetInterface eth;
+
+#ifdef ENABLE_WEB_CONFIG
+
+/* Declare the SD card as storage */
+NuSDBlockDevice bd;
+FATFileSystem fs("fs");
+bool SD_Card_Mounted = FALSE;
+
+#endif
+
+/* ---                  --- */
+
+/*
+ * Forward serial port data to ethernet, and vice versa.
+ *
+ */
+void exchange_data(S_PORT_CONFIG *pmap, TCPSocket *psocket)
+{
+    unsigned char n_buf[256];
+    unsigned char s_buf[256];
+    int n_len = 0, n_index = 0;
+    int s_len = 0, s_index = 0;
+    
+    while(1)
+    {   
+        /*** Network to Serial ***/
+        
+        if (n_len < 0 || n_len == n_index)
+        {
+            // net buffer is empty, try to get new data from network.
+            n_len = psocket->recv(n_buf, sizeof(n_buf));
+            if (n_len == NSAPI_ERROR_WOULD_BLOCK)
+            {
+            }
+            else if (n_len < 0)
+            {
+                printf("Socket Recv Err (%d)\r\n", n_len);
+                psocket->close();
+                break;
+            }
+            else
+            {
+                n_index = 0;
+            }
+        }
+        else
+        {
+            // send data to serial port.
+            for(;n_index < n_len && pmap->pserial->writeable(); n_index++)
+            {
+                pmap->pserial->putc(n_buf[n_index]);
+            }
+        }
+
+        /*** Serial to Network ***/
+        
+        if (pmap->pserial->readable())
+        {
+            // try to get more data from serial port
+            for(s_index = 0; s_index < sizeof(s_buf) && pmap->pserial->readable(); s_index++)
+                s_buf[s_index] = pmap->pserial->getc();
+            
+            // send all data to network.
+            if (s_index > 0)
+            {
+                s_len = psocket->send(s_buf, s_index); 
+                if (s_len == NSAPI_ERROR_WOULD_BLOCK)
+                {
+                    printf("Socket Send no block.\r\n");
+                }               
+                else if (s_len < 0)
+                {
+                    printf("Socket Send Err (%d)\r\n", s_len);
+                    psocket->close();
+                    break;
+                }
+                else if (s_len != s_index)
+                {
+                    printf("Socket Send not complete.\r\n");
+                    psocket->close();
+                    break;
+                }
+            }
+        }
+    }
+}   
+
+void bridge_net_client(S_PORT_CONFIG *pmap)
+{
+    TCPSocket socket;
+    SocketAddress server_address;
+    nsapi_error_t err;
+
+    printf("Thread %x in TCP client mode.\r\n", (unsigned int)pmap);
+
+    if ((err=socket.open(&eth)) < 0)
+    {
+        printf("TCP socket can't open (%d)(%x).\r\n", err, (unsigned int)pmap);
+        return;
+    }
+    
+    printf("Connecting server %s:%d ...\r\n", pmap->server_addr, pmap->server_port);
+    while(1)
+    {
+        if ((err=socket.connect(pmap->server_addr, pmap->server_port)) >= 0)
+            break;
+    }
+    
+    printf("\r\nConnected.");
+
+    socket.set_timeout(1);
+    exchange_data(pmap, &socket);
+}
+
+void bridge_net_server(S_PORT_CONFIG *pmap)
+{
+    TCPServer tcp_server;
+    TCPSocket client_socket;
+    SocketAddress client_address;
+    nsapi_error_t err;
+    
+    printf("Thread %x in TCP server mode.\r\n", (unsigned int)pmap);
+    
+    if ((err=tcp_server.open(&eth)) < 0)
+    {
+        printf("TCP server can't open (%d)(%x).\r\n", err, (unsigned int)pmap);
+        return;
+    }
+    if ((err=tcp_server.bind(eth.get_ip_address(), pmap->port)) < 0)
+    {
+        printf("TCP server can't bind address and port (%d)(%x).\r\n", err, (unsigned int)pmap);
+        return;
+    }
+    if ((err=tcp_server.listen(1)) < 0)
+    {
+        printf("TCP server can't listen (%d)(%x).\r\n", err, (unsigned int)pmap);
+        return;
+    }
+
+    client_socket.set_timeout(1);
+
+    while(1)
+    {   
+        if ((err=tcp_server.accept(&client_socket, &client_address)) < 0)
+        {
+            printf("TCP server fail to accept connection (%d)(%x).\r\n", err, (unsigned int)pmap);
+            return;
+        }
+
+        printf("Connect (%d) from %s:%d ...\r\n", pmap->port, client_address.get_ip_address(), client_address.get_port());
+
+        exchange_data(pmap, &client_socket);        
+    }
+}   
+
+int main()
+{
+    /* Set the console baud-rate */
+    output.baud(115200);
+    printf("\r\nmbed OS version is %d.\r\n", MBED_VERSION);
+    printf("Start Serial-to-Ethernet...\r\n");
+
+#ifdef ENABLE_WEB_CONFIG
+
+    /* Restore configuration from SD card */
+    
+    SD_Card_Mounted = (fs.mount(&bd) >= 0);
+    if (SD_Card_Mounted)
+    {
+        FILE *fd = fopen(SER_CONFIG_FILE, "r");
+        if (fd != NULL)
+        {
+            char pBuf[sizeof(port_config)+2];
+            int len = fread(pBuf, 1, sizeof(port_config)+2, fd);
+            if (len == (sizeof(port_config)+2) && pBuf[0] == 'N' && pBuf[1] == 'T') 
+            {
+                printf("Set Serial ports from config file in SD card.\r\n");
+                memcpy(port_config, pBuf+2, sizeof(port_config));
+            }
+            else
+                printf("Incorrect serial config file.\r\n");
+            
+            fclose(fd);
+        }
+        else
+            printf("Can't open serial config file.\r\n");
+        
+        fd = fopen(NET_CONFIG_FILE, "r");
+        if (fd != NULL)
+        {
+            char pBuf[sizeof(net_config)+2];
+            int len = fread(pBuf, 1, sizeof(net_config)+2, fd);
+            if (len == (sizeof(net_config)+2) && pBuf[0] == 'N' && pBuf[1] == 'T') 
+            {
+                printf("Set network from config file in SD card.\r\n");
+                memcpy(&net_config, pBuf+2, sizeof(net_config));
+            }
+            else
+                printf("Incorrect network config file.\r\n");
+            
+            fclose(fd);
+        }
+        else
+            printf("Can't open network config file.\r\n");
+    }
+    else
+    {
+        printf("Can't find SD card.\r\n");
+    }
+
+#endif
+    
+    printf("Configure UART ports...\r\n");
+    for(int i=0; i<MAX_UART_PORTS; i++)
+    {
+        port_config[i].pserial->baud(port_config[i].baud);
+        port_config[i].pserial->format(port_config[i].data, port_config[i].parity, port_config[i].stop);
+    }
+    
+    if (net_config.mode == IP_STATIC_MODE)
+    {
+        printf("Start Ethernet in Static mode.\r\n");
+        eth.disconnect();
+        ((NetworkInterface *)&eth)->set_network(net_config.ip, net_config.mask, net_config.gateway);
+    }
+    else
+        printf("Start Ethernet in DHCP mode.\r\n");
+    
+    eth.connect();
+    printf("IP Address is %s\r\n", eth.get_ip_address());
+    
+    Thread thread[MAX_UART_PORTS];
+    
+    // Folk thread for each port
+    for(int i=0; i<MAX_UART_PORTS; i++)
+    {
+        if (port_config[i].mode == NET_SERVER_MODE)
+        {
+            thread[i].start(callback(bridge_net_server, &(port_config[i])));
+        }
+        else // if (port_config[i].mode == TCP_CLIENT_MODE)
+        {
+            thread[i].start(callback(bridge_net_client, &(port_config[i])));
+        }
+    }
+
+#ifdef ENABLE_WEB_CONFIG
+    
+    /*** main thread to be a web server for configuration ***/
+    start_httpd();
+
+#endif
+    
+    while(1);
+
+    /* end of main task */    
+    //eth.disconnect();
+}
diff -r 000000000000 -r c89ccc69a48b mbed-os.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-os.lib	Fri Sep 29 05:45:43 2017 +0000
@@ -0,0 +1,1 @@
+https://github.com/ARMmbed/mbed-os/#ca661f9d28526ca8f874b05432493a489c9671ea
diff -r 000000000000 -r c89ccc69a48b mbed_app.json
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed_app.json	Fri Sep 29 05:45:43 2017 +0000
@@ -0,0 +1,22 @@
+{
+    "config": {
+        "SD_DAT0": "NC",
+        "SD_DAT1": "NC",
+        "SD_DAT2": "NC",
+        "SD_DAT3": "NC",
+        "SD_CMD":  "NC",
+        "SD_CLK":  "NC",
+        "SD_CD":   "NC"
+    },
+    "target_overrides": {
+        "NUMAKER_PFM_NUC472": {
+            "SD_DAT0": "PF_5",
+            "SD_DAT1": "PF_4",
+            "SD_DAT2": "PF_3",
+            "SD_DAT3": "PF_2",
+            "SD_CMD":  "PF_7",
+            "SD_CLK":  "PF_8",
+            "SD_CD":   "PF_6"
+        }
+    }
+}
diff -r 000000000000 -r c89ccc69a48b ste_config.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ste_config.h	Fri Sep 29 05:45:43 2017 +0000
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017 Nuvoton Tecnology Corp. All rights reserved.
+ *
+ * Header for Serial-To-Ethernet configuration.
+ *
+ */
+
+#ifndef _STE_CONFIG_H
+#define _STE_CONFIG_H
+
+#include "mbed.h"
+#include "EthernetInterface.h"
+#include "TCPSocket.h"
+#include "TCPServer.h"
+#include "BufferedSerial.h"
+#include "FATFileSystem.h"
+#include "NuSDBlockDevice.h"
+
+
+//#define ENABLE_WEB_CONFIG             // Define this to active a simple web sever for
+                                        // UART ports and Ethernet port parameters configuration.
+
+/* Maximum UART ports supported */
+#define MAX_UART_PORTS      2
+
+/* Default UART baud */
+#define DEFAULT_UART_BAUD   115200
+
+/* Network base port number to listen.
+   So the base port maps to the 1st UART port,
+   the (base port + 1) maps to the 2nd UART port, etc. */
+#define NET_PORT_BASE   10001
+
+/* Path and Filename of configuration files */
+#define SER_CONFIG_FILE "/fs/STE_SER.TXT"   // for serial ports
+#define NET_CONFIG_FILE "/fs/STE_NET.TXT"   // for network
+
+/* Maximum size of server address */
+#define MAX_SERVER_ADDRESS_SIZE     63
+
+/* Maximum size of IP address */
+#define MAX_IPV4_ADDRESS_SIZE       15
+
+/* Functions and global variables declaration. */
+
+typedef enum {
+    NET_SERVER_MODE = 0,
+    NET_CLIENT_MODE
+} E_NetMode;
+
+typedef enum {
+    IP_STATIC_MODE = 0,
+    IP_DHCP_MODE
+} E_IPMode;
+
+typedef struct {
+    E_IPMode        mode;
+    char            ip[MAX_IPV4_ADDRESS_SIZE+1];
+    char            mask[MAX_IPV4_ADDRESS_SIZE+1];
+    char            gateway[MAX_IPV4_ADDRESS_SIZE+1];
+} S_NET_CONFIG;
+
+typedef struct {
+    E_NetMode       mode;       // Network server or client mode
+    int             port;       // Network port number
+    BufferedSerial  *pserial;   // UART number
+    int             baud;       // UART baud
+    int             data;       // UART data bits
+    int             stop;       // UART stop bits
+    mbed::SerialBase::Parity parity; // UART parity bit
+    char            server_addr[MAX_SERVER_ADDRESS_SIZE+1]; // Server address for TCP client mode
+    unsigned short  server_port;    // Server port for TCP client mode
+} S_PORT_CONFIG;
+
+extern RawSerial output;        // for debug output
+extern EthernetInterface eth;
+extern S_PORT_CONFIG port_config[MAX_UART_PORTS];
+extern S_NET_CONFIG net_config;
+
+extern bool SD_Card_Mounted;
+void start_httpd(void);
+
+#endif
diff -r 000000000000 -r c89ccc69a48b uweb_server.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uweb_server.cpp	Fri Sep 29 05:45:43 2017 +0000
@@ -0,0 +1,536 @@
+/*
+ * Copyright (c) 2017 Nuvoton Tecnology Corp. All rights reserved.
+ *
+ * micro web server for serial to Ethernet configuration.
+ * 
+ *
+ */
+ 
+#include <string.h>
+#include "ste_config.h"
+
+#ifdef ENABLE_WEB_CONFIG
+
+#define PAGE_HEADER \
+"<html><head>\r\n" \
+"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\r\n" \
+"<title>Serial to Ethernet Configuration</title>\r\n" \
+"</head>\r\n"
+
+#define PAGE_HEADER_FOR_REFRESH \
+"<html><head>\r\n" \
+"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\r\n" \
+"<meta http-equiv=\"refresh\" content=\"10; url=index.html\" />\r\n" \
+"<title>Serial to Ethernet Configuration</title>\r\n" \
+"</head>\r\n"
+
+#define PAGE_RESTART_FORM \
+"<form action=\"/config.html\" method=\"GET\">\r\n" \
+"<input type=\"hidden\" name=\"restart\" value=\"1\">\r\n" \
+"<input type=\"submit\" value=\"Restart\"> </form>\r\n"
+
+#define PAGE_RESETCONF_FORM \
+"<form action=\"/config.html\" method=\"GET\">\r\n" \
+"<input type=\"hidden\" name=\"resetconf\" value=\"1\">\r\n" \
+"<input type=\"submit\" value=\"Reset Config\"> </form>\r\n"
+
+#define PAGE_CONFIG_FORM_HEAD \
+"<form action=\"/config.html\" method=\"GET\">\r\n"
+
+#define PAGE_CONFIG_SERIAL_FORM \
+"<input type=\"hidden\" name=\"uart_port\" value=\"%d\">\r\n" \
+" Baud <select type=\"text\" name=\"baud\">\r\n \
+    <option value=\"115200\"%s>115200</option>\r\n \
+    <option value=\"9600\"%s>9600</option>\r\n \
+    <option value=\"4800\"%s>4800</option>\r\n \
+    <option value=\"2400\"%s>2400</option>\r\n \
+    </select> &nbsp&nbsp;\r\n \
+  Data bits <select type=\"text\" name=\"databits\">\r\n \
+    <option value=\"8\"%s>8</option>\r\n \
+    <option value=\"7\"%s>7</option>\r\n \
+    <option value=\"6\"%s>6</option>\r\n \
+    <option value=\"5\"%s>5</option>\r\n \
+    </select> &nbsp;&nbsp;\r\n \
+  Parity <select type=\"text\" name=\"parity\">\r\n \
+    <option value=\"0\"%s>None</option>\r\n \
+    <option value=\"1\"%s>Odd</option>\r\n \
+    <option value=\"2\"%s>Even</option>\r\n \
+    </select> &nbsp;&nbsp;\r\n \
+  Stop bits <select type=\"text\" name=\"stopbits\">\r\n \
+    <option value=\"1\"%s>1</option>\r\n \
+    <option value=\"2\"%s>2</option>\r\n \
+    </select> <br>\r\n \
+Network mode <select type=\"text\" name=\"netmode\">\r\n \
+    <option value=\"0\"%s>Server</option>\r\n \
+    <option value=\"1\"%s>Client</option>\r\n \
+    </select> <br> Set following fields for Client only. <br>\r\n \
+Server address <input type=\"text\" name=\"sipaddr\" size=\"16\" value=\"%s\"> &nbsp&nbsp;\r\n \
+Server port <input type=\"text\" name=\"sport\" size=\"5\" value=\"%d\">\r\n"
+
+#define PAGE_CONFIG_NET_FORM \
+"<input type=\"hidden\" name=\"net_config\" value=\"1\">\r\n \
+IP Address Mode <select type=\"text\" name=\"ipmode\">\r\n \
+    <option value=\"0\"%s>Static</option>\r\n \
+    <option value=\"1\"%s>DHCP</option>\r\n \
+    </select> <br> Set following fields for Static IP only. <br>\r\n \
+IP Address <input type=\"text\" name=\"ipaddr\" size=\"16\" value=\"%s\">\r\n \
+Netmask <input type=\"text\" name=\"mask\" size=\"16\" value=\"%s\">\r\n \
+Gateway Address <input type=\"text\" name=\"gwaddr\" size=\"16\" value=\"%s\">\r\n"
+
+typedef void (*PROC_PAGE_PFN)(TCPSocket *, char *);
+
+typedef struct {
+    const char      *vhtmlpage; // virtual page name, eg. index.html ...
+    PROC_PAGE_PFN   pfn;
+} S_WEB_PAGE_SETTING;
+
+extern void process_http_index_html(TCPSocket *, char *);
+extern void process_http_restart_html(TCPSocket *, char *);
+extern void process_http_resetconf_html(TCPSocket *, char *);
+extern void process_http_config_html(TCPSocket *, char *);
+extern void process_http_err_html(TCPSocket *, char *);
+
+#define MAX_WEB_GET_PAGE_SETTINGS   5
+S_WEB_PAGE_SETTING web_get_pages_setings[MAX_WEB_GET_PAGE_SETTINGS] = {
+    {"/ ",                          process_http_index_html},
+    {"/index.html ",                process_http_index_html},
+    {"/config.html?restart=1 ",     process_http_restart_html},
+    {"/config.html?resetconf=1 ",   process_http_resetconf_html},
+    {"/config.html?",               process_http_config_html}   
+};
+
+#define MAX_WEB_POST_PAGE_SETTINGS  1
+S_WEB_PAGE_SETTING web_post_pages_setings[MAX_WEB_POST_PAGE_SETTINGS] = {
+    {"/config.html ", process_http_config_html},
+};
+
+typedef struct {
+    int         type;       // 0: integer, 1:string
+    int         value;      // integer value for integer type
+    char       *str;        // point to string for string type
+    int         min;
+    int         max;        // max value of integer or max length of string
+    const char *cmd;
+    int         cmd_len;
+} S_WEB_CMD_PARAMS;
+
+#define MAX_WEB_CMD_PARAMS  13
+S_WEB_CMD_PARAMS web_cmd_params[MAX_WEB_CMD_PARAMS] = {
+    {0, 0, NULL, 1, MAX_UART_PORTS, "uart_port=", 10},
+    {0, 0, NULL, 2400, 115200,      "baud=", 5},
+    {0, 0, NULL, 5, 8,              "databits=", 9},
+    {0, 0, NULL, 0, 2,              "parity=", 7},
+    {0, 0, NULL, 1, 2,              "stopbits=", 9},
+    {0, 0, NULL, 0, 1,              "netmode=", 8},
+    {1, 0, NULL, 0, 16,             "sipaddr=", 8},
+    {0, 0, NULL, 0, 65535,          "sport=", 6},   
+    {0, 0, NULL, 1, 1,              "net_config=", 11},
+    {0, 0, NULL, 0, 1,              "ipmode=", 7},
+    {1, 0, NULL, 0, 1,              "ipaddr=", 7},
+    {1, 0, NULL, 0, 1,              "mask=", 5},
+    {1, 0, NULL, 0, 1,              "gwaddr=", 7}
+};
+
+const char *parity_string[] = {"None", "Odd", "Even"};
+const char *netmode_string[] = {"Server", "Client"};
+const char *ipmode_string[] = {"Static", "DHCP"};
+
+
+int inspect_each_setting(char *pbuf)
+{
+    int i;
+    int v;
+
+    for(i=0; i<MAX_WEB_CMD_PARAMS; i++)
+    {
+        web_cmd_params[i].value = 0;
+        web_cmd_params[i].str = NULL;
+    }
+    
+    while(*pbuf != '\0')
+    {
+        for(i=0; i<MAX_WEB_CMD_PARAMS; i++)
+        {
+            if (strncmp(pbuf, web_cmd_params[i].cmd, web_cmd_params[i].cmd_len) == 0)
+            {
+                pbuf += web_cmd_params[i].cmd_len;
+                
+                if (web_cmd_params[i].type == 0)
+                {
+                    v = atoi(pbuf);
+                    if (v >= web_cmd_params[i].min && v <= web_cmd_params[i].max)
+                        web_cmd_params[i].value = v;                    
+                }
+                else
+                {
+                    web_cmd_params[i].str = pbuf;
+                }
+
+                for(; *pbuf != '\0'; pbuf++)
+                {
+                    if (*pbuf == '&')
+                    {
+                        *pbuf++ = '\0';
+                        break;
+                    }
+                    else if (*pbuf == ' ')
+                    {
+                        *pbuf = '\0';
+                        break;
+                    }       
+//                  else if (*pbuf == '\r')
+//                  {
+//                      *pbuf++ = '\0';
+//                      if (*pbuf == '\n')
+//                          *pbuf++ = '\0';
+//                      break;
+//                  }
+//                  else if (*pbuf == '\n' || *pbuf == ' ')
+//                  {
+//                      *pbuf++ = '\0';
+//                      break;
+//                  }
+                }
+                
+                break;
+            }   
+        }
+        
+        if (i >= MAX_WEB_CMD_PARAMS)
+            return -1;
+    }
+    
+    return 0;
+}
+    
+int process_settings(char *pbuf)
+{
+    FILE *fp;
+    
+    printf("Verify Configure setting...\r\n");
+    printf("---Dump Settings---\r\n%s\r\n---End of dump---\r\n", pbuf);
+
+    if (SD_Card_Mounted == FALSE)
+    {
+        printf("SD card doesn't exist. Ignore settings.\r\n");
+        return -1;
+    }
+    
+    if (inspect_each_setting(pbuf) < 0)
+    {
+        printf("Unsupported parameters.\r\n");
+        return -1;
+    }
+    
+    if (web_cmd_params[0].value > 0)
+    {
+        int port = web_cmd_params[0].value - 1;
+        port_config[port].baud = web_cmd_params[1].value;
+        port_config[port].data = web_cmd_params[2].value;
+        port_config[port].stop = web_cmd_params[4].value;
+        port_config[port].parity = (mbed::SerialBase::Parity) web_cmd_params[3].value;
+        port_config[port].mode = (E_NetMode) web_cmd_params[5].value;
+        
+        if (web_cmd_params[6].str != NULL)
+        {
+            strncpy(port_config[port].server_addr, web_cmd_params[6].str, MAX_SERVER_ADDRESS_SIZE);
+            port_config[port].server_addr[MAX_SERVER_ADDRESS_SIZE] = '\0';
+        }
+            
+        port_config[port].server_port = web_cmd_params[7].value;
+        
+        printf("Save Serial Config setting...\r\n");    
+        fp = fopen(SER_CONFIG_FILE, "w");
+        if (fp != NULL)
+        {
+            char pBuf[2] = {'N', 'T'};
+            printf("Write config file to SD card.\r\n");
+            fwrite(pBuf, 2, 1, fp);
+            fwrite(port_config, sizeof(port_config), 1, fp);
+            fclose(fp);
+        }
+        else
+        {
+            printf("Can't write to SD card.\r\n");
+        }
+    }
+    else if (web_cmd_params[8].value > 0)
+    {
+        net_config.mode = (E_IPMode)web_cmd_params[9].value;
+        if (web_cmd_params[10].str != NULL)
+        {
+            strncpy(net_config.ip, web_cmd_params[10].str, MAX_IPV4_ADDRESS_SIZE);
+            net_config.ip[MAX_IPV4_ADDRESS_SIZE] = '\0';
+        }
+        if (web_cmd_params[11].str != NULL)
+        {
+            strncpy(net_config.mask, web_cmd_params[11].str, MAX_IPV4_ADDRESS_SIZE);
+            net_config.mask[MAX_IPV4_ADDRESS_SIZE] = '\0';
+        }
+        if (web_cmd_params[12].str != NULL)
+        {
+            strncpy(net_config.gateway, web_cmd_params[12].str, MAX_IPV4_ADDRESS_SIZE);
+            net_config.gateway[MAX_IPV4_ADDRESS_SIZE] = '\0';
+        }
+        printf("Save Network Config setting...\r\n");   
+        fp = fopen(NET_CONFIG_FILE, "w");
+        if (fp != NULL)
+        {
+            char pBuf[2] = {'N', 'T'};
+            printf("Write config file to SD card.\r\n");
+            fwrite(pBuf, 2, 1, fp);
+            fwrite(&net_config, sizeof(net_config), 1, fp);
+            fclose(fp);
+        }
+        else
+        {
+            printf("Can't write to SD card.\r\n");
+        }
+    }
+    
+    return 0;
+}
+
+
+void send_web_data(TCPSocket *socket, char *pbuf)
+{
+    char *p = pbuf;
+    int size = strlen(pbuf);
+    
+    while(size > 0)
+    {
+        int ret = socket->send(p, size);
+        if (ret < 0)
+            break;
+
+        p += ret;
+        size -= ret;
+    }
+}
+
+void send_web_header(TCPSocket *socket, int num)
+{
+    static const char *webpage_header[] = {
+        PAGE_HEADER,
+        PAGE_HEADER_FOR_REFRESH
+    };
+
+    send_web_data(socket, (char *)webpage_header[num]);
+}
+
+const char *status_messages[] = {
+    "\r\n",
+    "Configuration update successfully. </p>\r\n",
+    "Configuration setting error.</p>\r\n",
+    "Reset Configuration successfully. </p>\r\n",
+    "Web page will reload automatically after 10 seconds. </p>\r\n",
+    "Unknown settings. </p>\r\n"
+};
+
+void send_web_body(TCPSocket *socket, int num)
+{
+    int i;
+    static char pbuf[3072];
+
+    /* send page body */
+    send_web_data(socket, (char *)"<body>Serial to Ethernet Configuration </p>\r\n");
+    
+    /* send status message */
+    send_web_data(socket, (char *)status_messages[num]); 
+
+    send_web_data(socket, (char *)PAGE_RESTART_FORM); 
+    send_web_data(socket, (char *)PAGE_RESETCONF_FORM); 
+    
+    /* send network configuration form */
+    send_web_data(socket, (char *)PAGE_CONFIG_FORM_HEAD);
+    
+    sprintf(pbuf, PAGE_CONFIG_NET_FORM,
+        (net_config.mode == IP_STATIC_MODE)?" selected":"",
+        (net_config.mode == IP_DHCP_MODE)?" selected":"",
+        net_config.ip,
+        net_config.mask,
+        net_config.gateway);
+    
+    send_web_data(socket, pbuf);
+    send_web_data(socket, (char *)"<br><input type=\"submit\" value=\"Config Net\"> </form><br>\r\n");
+    
+    /* send serial ports configuration form */
+    send_web_data(socket, (char *)PAGE_CONFIG_FORM_HEAD);
+    for(i=0; i<MAX_UART_PORTS; i++)
+    {
+        S_PORT_CONFIG *s = &port_config[i];
+        
+        sprintf(pbuf, "Serial port #%d<br>\r\n", i+1); 
+        send_web_data(socket, pbuf);
+        sprintf(pbuf, PAGE_CONFIG_SERIAL_FORM,
+            i+1,
+            (s->baud == 115200)?" selected":"",
+            (s->baud == 9600)?" selected":"",
+            (s->baud == 4800)?" selected":"",
+            (s->baud == 2400)?" selected":"",
+            (s->data == 8)?" selected":"",
+            (s->data == 7)?" selected":"",
+            (s->data == 6)?" selected":"",
+            (s->data == 5)?" selected":"",
+            (s->parity == 0)?" selected":"",
+            (s->parity == 1)?" selected":"",
+            (s->parity == 2)?" selected":"",
+            (s->stop == 1)?" selected":"",
+            (s->stop == 2)?" selected":"",
+            (s->mode == 0)?" selected":"",
+            (s->mode == 1)?" selected":"",
+            s->server_addr,
+            s->server_port);
+        
+        send_web_data(socket, pbuf);
+        
+#if MAX_UART_PORTS == 1
+        sprintf(pbuf, "<br><input type=\"submit\" value=\"Config Port\"> </form><br>\r\n");
+#else       
+        sprintf(pbuf, "<br><input type=\"submit\" value=\"Config Port #%d\"> </form><br>\r\n", i);
+#endif
+        send_web_data(socket, pbuf);
+    }
+    
+    /* send end of page body */
+    send_web_data(socket, (char *)"</body></html>\r\n");
+}
+
+void process_http_index_html(TCPSocket *socket, char *pbuf)
+{
+    send_web_header(socket, 0);
+    send_web_body(socket, 0);
+}
+
+void process_http_restart_html(TCPSocket *socket, char *pbuf)
+{
+    send_web_header(socket, 1);
+    send_web_body(socket, 4);
+
+    printf("Restart system...\r\n");
+    wait(1);    // wait 1 second
+//  SYS_ResetCPU();
+    SYS_ResetChip();
+    wait(100);
+}
+
+void process_http_resetconf_html(TCPSocket *socket, char *pbuf)
+{
+    if (SD_Card_Mounted)
+    {                   
+        remove(SER_CONFIG_FILE);
+        remove(NET_CONFIG_FILE);
+        printf("Deleted config files.\r\n");
+    }
+    else
+    {
+        printf("SD card doesn't exist.\r\n");
+    }
+    
+    send_web_header(socket, 0);
+    send_web_body(socket, 3);
+}
+
+void process_http_config_html(TCPSocket *socket, char *pbuf)
+{
+    send_web_header(socket, 0);
+
+    if (process_settings(pbuf) >= 0)
+        send_web_body(socket, 1);
+    else
+        send_web_body(socket, 2);
+}
+
+void process_http_err_html(TCPSocket *socket, char *pbuf)
+{
+    send_web_header(socket, 0);
+    send_web_body(socket, 5);
+}
+
+void process_http_get_request(TCPSocket *socket, char *pbuf)
+{
+    int i;
+    
+    for(i=0; i<MAX_WEB_GET_PAGE_SETTINGS; i++)
+    {
+        int len = strlen(web_get_pages_setings[i].vhtmlpage);
+        if (strncmp(pbuf, web_get_pages_setings[i].vhtmlpage, len) == 0)
+        {
+            if (web_get_pages_setings[i].pfn != NULL)
+            {
+                web_get_pages_setings[i].pfn(socket, pbuf+len);
+                break;
+            }
+        }
+    }
+}
+
+void process_http_post_request(TCPSocket *socket, char *pbuf)
+{
+}
+
+void process_http_request(TCPSocket *socket)
+{
+    char w_buf[2048];
+    int w_len;
+    
+    w_len = socket->recv(w_buf, 2047);
+    if (w_len <= 0)
+        return;
+    
+    w_buf[w_len] = '\0';
+    printf("\n\r---DUMP HTTP DATA (%d)---\r\n%s\r\n---END OF DUMP---\r\n", w_len, w_buf);
+    
+    if (strncmp(w_buf, "GET ", 4) == 0)
+    {
+        process_http_get_request(socket, w_buf+4);
+    }
+    else if (strncmp(w_buf, "POST ", 5) == 0)
+    {
+        process_http_post_request(socket, w_buf+5);
+    }
+    else
+    {
+        process_http_get_request(socket, (char *)"/ ");
+    }
+}
+
+void start_httpd(void)
+{
+    TCPServer http_server;
+    TCPSocket http_socket;
+    SocketAddress http_address;
+
+    if (http_server.open(&eth) < 0)
+    {
+        printf("http server can't open.\r\n");
+        return;
+    }
+    if (http_server.bind(eth.get_ip_address(), 80) < 0)
+    {
+        printf("http server can't bind address and port.\r\n");
+        return;
+    }
+    if (http_server.listen(1) < 0)
+    {
+        printf("http server can't listen.\r\n");
+        return;
+    }
+    
+    printf("Start http server...\r\n");
+
+    while(1)
+    {
+        if (http_server.accept(&http_socket, &http_address) < 0)
+        {
+            printf("http server fail to accept connection.\r\n");
+            return;
+        }
+        
+        printf("http from %s:%d ...\r\n", http_address.get_ip_address(), http_address.get_port());
+        process_http_request(&http_socket);
+        http_socket.close();
+    }
+}
+
+#endif