iSDIO Library for TOSHIBA FlashAir. include HTTP or HTTPS Client.

Dependencies:   SDFileSystem

Dependents:   FlashAir_Twitter Neon_F303K8_04

Fork of HTTPClient by Donatien Garnier

Files at this revision

API Documentation at this revision

Comitter:
ban4jp
Date:
Mon Dec 15 12:23:22 2014 +0000
Parent:
19:3b1625dbd7e9
Commit message:
Initial commit.

Changed in this revision

HTTPClient.cpp Show annotated file Show diff for this revision Revisions of this file
HTTPClient.h Show annotated file Show diff for this revision Revisions of this file
SDFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
iSDIO.cpp Show annotated file Show diff for this revision Revisions of this file
iSDIO.h Show annotated file Show diff for this revision Revisions of this file
iSDIO_helper.cpp Show annotated file Show diff for this revision Revisions of this file
iSDIO_helper.h Show annotated file Show diff for this revision Revisions of this file
diff -r 3b1625dbd7e9 -r 51abf34bcc06 HTTPClient.cpp
--- a/HTTPClient.cpp	Sun Dec 14 19:05:31 2014 +0000
+++ b/HTTPClient.cpp	Mon Dec 15 12:23:22 2014 +0000
@@ -18,7 +18,7 @@
  */
 
 //Debug is disabled by default
-#if 0
+#if 1
 //Enable debug
 #include <cstdio>
 #define DBG(x, ...) std::printf("[HTTPClient : DBG]"x"\r\n", ##__VA_ARGS__);
@@ -41,15 +41,18 @@
 #define MAX(x,y) (((x)>(y))?(x):(y))
 
 #define CHUNK_SIZE 256
+#define HEADER_KEY_MAXLENGTH   64
+#define HEADER_VALUE_MAXLENGTH 128
 
 #include <cstring>
 
 #include "HTTPClient.h"
 
 HTTPClient::HTTPClient() :
-    m_sock(), m_basicAuthUser(NULL), m_basicAuthPassword(NULL), m_httpResponseCode(0)
+    m_basicAuthUser(NULL), m_basicAuthPassword(NULL), m_httpResponseCode(0)
 {
-
+    bufferPos = buffer;
+    recvCount = 0;
 }
 
 HTTPClient::~HTTPClient()
@@ -100,7 +103,6 @@
 #define CHECK_CONN_ERR(ret) \
   do{ \
     if(ret) { \
-      m_sock.close(); \
       ERR("Connection error (%d)", ret); \
       return HTTP_CONN; \
     } \
@@ -108,7 +110,6 @@
 
 #define PRTCL_ERR() \
   do{ \
-    m_sock.close(); \
     ERR("Protocol error"); \
     return HTTP_PRTCL; \
   } while(0)
@@ -125,6 +126,7 @@
 
     char scheme[8];
     uint16_t port;
+    uint16_t cmd;
     char host[32];
     char path[64];
     //First we need to parse the url (http[s]://host[:port][/[path]]) -- HTTPS not supported (yet?)
@@ -137,20 +139,36 @@
     if(port == 0) { //TODO do handle HTTPS->443
         port = 80;
     }
+    if(strcmp(scheme, "http") == 0) {
+        cmd = 0x21; //SendHTTPMessageByRegister
+    } else if(strcmp(scheme, "https") == 0) {
+        cmd = 0x23; //SendHTTPSSLMessageByRegister
+    } else {
+        ERR("Not support scheme %s", scheme);
+        return HTTP_PARSE;
+    }
 
     DBG("Scheme: %s", scheme);
     DBG("Host: %s", host);
     DBG("Port: %d", port);
+    DBG("Cmd: %x", cmd);
     DBG("Path: %s", path);
 
-    //Connect
-    DBG("Connecting socket to server");
-    int ret = m_sock.connect(host, port);
-    if (ret < 0) {
-        m_sock.close();
-        ERR("Could not connect");
-        return HTTP_CONN;
-    }
+    int ret;
+
+    //Get card instance
+    card = SD_iSDIO::getInstance();
+    sequenceId = card->getSequenceId();
+
+    //Create card command
+    memset(buffer, 0, 1024);
+    bufferPos = buffer;
+    bufferPos = put_command_header(bufferPos, 1, 0);
+    bufferPos = put_command_info_header(bufferPos, cmd, sequenceId, 2);
+    bufferPos = put_str_arg(bufferPos, host);
+
+    uint8_t* bodyLenPos = bufferPos;
+    bufferPos += 4; //skip value of data size
 
     //Send request
     DBG("Sending request");
@@ -159,7 +177,6 @@
     snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s\r\n", meth, path, host); //Write request
     ret = send(buf);
     if(ret) {
-        m_sock.close();
         ERR("Could not write request");
         return HTTP_CONN;
     }
@@ -244,6 +261,38 @@
         }
     }
 
+    put_u32(bodyLenPos, (bufferPos - bodyLenPos - 4));
+    put_command_header(buffer, 1, (bufferPos - buffer));
+
+#if 0
+    for (int i = 0; i < 0x400; i++) {
+        printf("%2x ", buffer[i]);
+        if ((i & 0xf) == 0xf) printf("\n");
+        if (i == 0x200-1) printf("----\n");
+    }
+    printf((char *)bodyLenPos + 4);
+    printf("\n");
+#endif
+
+    DBG("Send data size %d", (bufferPos - buffer));
+
+    if( card->writeExtDataPort(1, 1, 0x000, buffer) != true ) {
+        ERR("writeExtDataPort error (1)\n");
+        return HTTP_PRTCL;
+    }
+    if( (bufferPos - buffer) > 512 ) {
+        if( card->writeExtDataPort(1, 1, 0x000, &buffer[512]) != true ) {
+            ERR("writeExtDataPort error (2)\n");
+            return HTTP_PRTCL;
+        }
+    }
+
+    DBG("waitResponse");
+    card->waitResponse(sequenceId);
+
+    bufferPos = buffer;
+    recvCount = 0;
+
     //Receive response
     DBG("Receiving response");
     ret = recv(buf, 1, CHUNK_SIZE - 1, &trfLen); //Read n bytes
@@ -285,7 +334,8 @@
         PRTCL_ERR();
     }
 
-    if( (m_httpResponseCode < 200) || (m_httpResponseCode >= 300) ) {
+    //if( (m_httpResponseCode < 200) || (m_httpResponseCode >= 300) ) {
+    if( (m_httpResponseCode < 100) || (m_httpResponseCode >= 600) ) {
         //Did not return a 2xx code; TODO fetch headers/(&data?) anyway and implement a mean of writing/reading headers
         WARN("Response code %d", m_httpResponseCode);
         PRTCL_ERR();
@@ -327,14 +377,14 @@
 
         buf[crlfPos] = '\0';
 
-        char key[32];
-        char value[32];
+        char key[HEADER_KEY_MAXLENGTH];
+        char value[HEADER_VALUE_MAXLENGTH];
 
         //key[31] = '\0';
         //value[31] = '\0';
 
-        memset(key, 0, 32);
-        memset(value, 0, 32);
+        memset(key, 0, HEADER_KEY_MAXLENGTH);
+        memset(value, 0, HEADER_VALUE_MAXLENGTH);
 
         //int n = sscanf(buf, "%31[^:]: %31[^\r\n]", key, value);
 
@@ -343,12 +393,12 @@
         char* keyEnd = strchr(buf, ':');
         if(keyEnd != NULL) {
             *keyEnd = '\0';
-            if(strlen(buf) < 32) {
+            if(strlen(buf) < HEADER_KEY_MAXLENGTH) {
                 strcpy(key, buf);
                 n++;
                 char* valueStart = keyEnd + 2;
                 if( (valueStart - buf) < crlfPos ) {
-                    if(strlen(valueStart) < 32) {
+                    if(strlen(valueStart) < HEADER_VALUE_MAXLENGTH) {
                         strcpy(value, valueStart);
                         n++;
                     }
@@ -356,7 +406,7 @@
             }
         }
         if ( n == 2 ) {
-            DBG("Read header : %s: %s\n", key, value);
+            DBG("Read header : %s: %s", key, value);
             if( !strcmp(key, "Content-Length") ) {
                 sscanf(value, "%d", &recvContentLength);
                 recvLengthUnknown = false;
@@ -484,7 +534,6 @@
 
     }
 
-    m_sock.close();
     DBG("Completed HTTP transaction");
 
     return HTTP_OK;
@@ -495,41 +544,93 @@
     DBG("Trying to read between %d and %d bytes", minLen, maxLen);
     size_t readLen = 0;
 
-    if(!m_sock.is_connected()) {
-        WARN("Connection was closed by server");
-        return HTTP_CLOSED; //Connection was closed by server
-    }
+    DBG("  recvCount: %d", recvCount);
+
+    if (recvCount == 0) {
 
-    int ret;
-    while(readLen < maxLen) {
-        if(readLen < minLen) {
-            DBG("Trying to read at most %d bytes [Blocking]", minLen - readLen);
-            m_sock.set_blocking(false, m_timeout);
-            ret = m_sock.receive_all(buf + readLen, minLen - readLen);
-        } else {
-            DBG("Trying to read at most %d bytes [Not blocking]", maxLen - readLen);
-            m_sock.set_blocking(false, 0);
-            ret = m_sock.receive(buf + readLen, maxLen - readLen);
+        // Read header and data.
+        if (!card->readExtDataPort(1, 1, 0x200, buffer)) {
+            return HTTP_PRTCL;
+        }
+#if 0
+        for (int i = 0; i < 0x200; i++) {
+            printf("%2x ", buffer[i]);
+            if ((i & 0xf) == 0xf) printf("\n");
+        }
+#endif
+        if (buffer[0] != 0x02) {
+            return HTTP_CONN;
         }
 
-        if( ret > 0) {
-            readLen += ret;
-        } else if( ret == 0 ) {
-            break;
+        recvTotalSize = get_u32(buffer + 20);
+        uint32_t recvSize = recvTotalSize > 488 ? 488 : recvTotalSize;
+        uint32_t pos = 24;
+
+        if (recvSize < maxLen) {
+            memcpy(buf, &buffer[pos], recvSize);
+            readLen = recvSize;
         } else {
-            if(!m_sock.is_connected()) {
-                ERR("Connection error (recv returned %d)", ret);
-                *pReadLen = readLen;
-                return HTTP_CONN;
+            memcpy(buf, &buffer[pos], maxLen);
+            readLen = maxLen;
+        }
+        bufferPos = &buffer[pos] + readLen;
+        recvAvailableSize = recvTotalSize - readLen;
+
+        DBG("  recvTotalSize: %d", recvTotalSize);
+        DBG("  recvAvailableSize: %d", recvAvailableSize);
+
+        recvCount++;
+
+    } else {
+
+        uint32_t recvSize = 512 - (bufferPos - buffer);
+        if (recvAvailableSize < recvSize) recvSize = recvAvailableSize;
+
+        DBG("  recvAvailableSize: %d", recvAvailableSize);
+        DBG("  recvSize: %d", recvSize);
+
+        if (recvSize > 0) {
+
+            if (recvSize < maxLen) {
+                memcpy(buf, bufferPos, recvSize);
+                readLen = recvSize;
             } else {
-                break;
+                memcpy(buf, bufferPos, maxLen);
+                readLen = maxLen;
+            }
+            bufferPos += readLen;
+            recvAvailableSize -= readLen;
+
+        } else if (recvAvailableSize > 0) {
+
+            // Read next data.
+            if (!card->readExtDataPort(1, 1, 0x200, buffer)) {
+                return HTTP_PRTCL;
             }
+#if 0
+            for (int i = 0; i < 0x200; i++) {
+                printf("%2x ", buffer[i]);
+                if ((i & 0xf) == 0xf) printf("\n");
+            }
+#endif
+            recvSize = recvAvailableSize > 512 ? 512 : recvAvailableSize;
+
+            if (recvSize < maxLen) {
+                memcpy(buf, buffer, recvSize);
+                readLen = recvSize;
+            } else {
+                memcpy(buf, buffer, maxLen);
+                readLen = maxLen;
+            }
+            bufferPos = buffer + readLen;
+            recvAvailableSize -= readLen;
+
+            recvCount++;
+
         }
 
-        if(!m_sock.is_connected()) {
-            break;
-        }
     }
+
     DBG("Read %d bytes", readLen);
     *pReadLen = readLen;
     return HTTP_OK;
@@ -543,22 +644,13 @@
     DBG("Trying to write %d bytes", len);
     size_t writtenLen = 0;
 
-    if(!m_sock.is_connected()) {
-        WARN("Connection was closed by server");
-        return HTTP_CLOSED; //Connection was closed by server
+    if(((buffer + 1024) - bufferPos) >= len) {
+        writtenLen = len;
+    } else {
+        writtenLen = ((buffer + 1024) - bufferPos);
     }
-
-    m_sock.set_blocking(false, m_timeout);
-    int ret = m_sock.send_all(buf, len);
-    if(ret > 0) {
-        writtenLen += ret;
-    } else if( ret == 0 ) {
-        WARN("Connection was closed by server");
-        return HTTP_CLOSED; //Connection was closed by server
-    } else {
-        ERR("Connection error (send returned %d)", ret);
-        return HTTP_CONN;
-    }
+    memcpy(bufferPos, buf, writtenLen);
+    bufferPos += writtenLen;
 
     DBG("Written %d bytes", writtenLen);
     return HTTP_OK;
diff -r 3b1625dbd7e9 -r 51abf34bcc06 HTTPClient.h
--- a/HTTPClient.h	Sun Dec 14 19:05:31 2014 +0000
+++ b/HTTPClient.h	Mon Dec 15 12:23:22 2014 +0000
@@ -24,7 +24,7 @@
 #ifndef HTTP_CLIENT_H
 #define HTTP_CLIENT_H
 
-#include "TCPSocketConnection.h"
+#include "iSDIO.h"
 
 #define HTTP_CLIENT_DEFAULT_TIMEOUT 15000
 
@@ -140,7 +140,14 @@
     HTTPResult parseURL(const char* url, char* scheme, size_t maxSchemeLen, char* host, size_t maxHostLen, uint16_t* port, char* path, size_t maxPathLen); //Parse URL
 
     //Parameters
-    TCPSocketConnection m_sock;
+    SD_iSDIO* card;
+    uint32_t sequenceId;
+
+    uint8_t buffer[512 * 2];
+    uint8_t* bufferPos;
+    uint8_t recvCount;
+    uint32_t recvTotalSize;
+    uint32_t recvAvailableSize;
 
     int m_timeout;
 
diff -r 3b1625dbd7e9 -r 51abf34bcc06 SDFileSystem.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystem.lib	Mon Dec 15 12:23:22 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/teams/mbed/code/SDFileSystem/#7b35d1709458
diff -r 3b1625dbd7e9 -r 51abf34bcc06 iSDIO.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/iSDIO.cpp	Mon Dec 15 12:23:22 2014 +0000
@@ -0,0 +1,207 @@
+#include "mbed.h"
+#include "iSDIO.h"
+
+#define CMD48 0x30
+#define CMD49 0x31
+
+SD_iSDIO::SD_iSDIO(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name) :
+    SDFileSystem(mosi, miso, sclk, cs, name)
+{
+    //disk_initialize();
+    instance = this;
+    sequenceId = 0;
+}
+
+SD_iSDIO* SD_iSDIO::instance = 0;
+
+SD_iSDIO* SD_iSDIO::getInstance()
+{
+    return SD_iSDIO::instance;
+}
+
+uint32_t SD_iSDIO::getSequenceId()
+{
+    return sequenceId++;
+}
+
+uint8_t SD_iSDIO::readExtDataPort(uint8_t mio, uint8_t func, uint16_t addr, uint8_t* dst)
+{
+    uint32_t arg =
+        (((uint32_t)mio & 0x1) << 31) |
+        (mio ? (((uint32_t)func & 0x7) << 28) : (((uint32_t)func & 0xF) << 27)) |
+        (((uint32_t)addr & 0x1FE00) << 9);
+    return readExt(arg, dst, 512);
+}
+
+uint8_t SD_iSDIO::readExtMemory(uint8_t mio, uint8_t func, uint32_t addr, uint16_t count, uint8_t* dst)
+{
+    uint32_t offset = addr & 0x1FF;
+    if (offset + count > 512) count = 512 - offset;
+    if (count == 0) return true;
+    uint32_t arg =
+        (((uint32_t)mio & 0x1) << 31) |
+        (mio ? (((uint32_t)func & 0x7) << 28) : (((uint32_t)func & 0xF) << 27)) |
+        ((addr & 0x1FFFF) << 9) |
+        ((count - 1) & 0x1FF);
+    return readExt(arg, dst, count);
+}
+
+uint8_t SD_iSDIO::writeExtDataPort(uint8_t mio, uint8_t func, uint16_t addr, const uint8_t* src)
+{
+    uint32_t arg =
+        (((uint32_t)mio & 0x1) << 31) |
+        (mio ? (((uint32_t)func & 0x7) << 28) : (((uint32_t)func & 0xF) << 27)) |
+        (((uint32_t)addr & 0x1FE00) << 9);
+    return writeExt(arg, src, 512);
+}
+
+uint8_t SD_iSDIO::writeExtMemory(uint8_t mio, uint8_t func, uint32_t addr, uint16_t count, const uint8_t* src)
+{
+    uint32_t arg =
+        (((uint32_t)mio & 0x1) << 31) |
+        (mio ? (((uint32_t)func & 0x7) << 28) : (((uint32_t)func & 0xF) << 27)) |
+        ((addr & 0x1FFFF) << 9) |
+        ((count - 1) & 0x1FF);
+    return writeExt(arg, src, count);
+}
+
+uint8_t SD_iSDIO::writeExtMask(uint8_t mio, uint8_t func, uint32_t addr, uint8_t mask, const uint8_t* src)
+{
+    uint32_t arg =
+        (((uint32_t)mio & 0x1) << 31) |
+        (mio ? (((uint32_t)func & 0x7) << 28) : (((uint32_t)func & 0xF) << 27)) |
+        (0x1 << 26) |
+        ((addr & 0x1FFFF) << 9) |
+        mask;
+    return writeExt(arg, src, 1);
+}
+
+uint8_t SD_iSDIO::waitResponse(uint32_t sequenceId)
+{
+    uint8_t buffer[0x14];
+    
+    //printf("\nWaiting response ");
+    uint8_t prev = 0xFF;
+    for (int i = 0; i < 20; ++i) {
+        memset(buffer, 0, 0x14);
+        // Read command response status.
+        if (!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:
+                        //printf("\n  Initial");
+                        break;
+                    case 0x01:
+                        //printf("\n  Command Processing");
+                        break;
+                    case 0x02:
+                        //printf("\n  Command Rejected");
+                        return false;
+                    case 0x03:
+                        //printf("\n  Process Succeeded");
+                        return true;
+                    case 0x04:
+                        //printf("\n  Process Terminated");
+                        return false;
+                    default:
+                        //printf("\n  Process Failed ");
+                        //printf("%x", resp);
+                        return false;
+                }
+                prev = resp;
+            }
+        }
+        //printf(".");
+        wait_ms(1000);
+    }
+    return false;
+}
+
+/** Perform Extention Read. */
+uint8_t SD_iSDIO::readExt(uint32_t arg, uint8_t* dst, uint16_t count)
+{
+    uint16_t i;
+    // send command and argument.
+    if (_cmd(CMD48, arg)) {
+        error("SD_CARD_ERROR_CMD48");
+        _cs = 1;
+        return false;
+    }
+
+    _cs = 0;
+
+    /*
+    // wait for start block token.
+    if (!waitStartBlock()) {
+        _cs = 1;
+        return false;
+    }
+    */
+    while (_spi.write(0xFF) == 0xFF);
+
+    // receive data
+    for (i = 0; i < count; ++i) {
+        dst[i] = _spi.write(0xFF);
+    }
+    // skip dummy bytes and 16-bit crc.
+    for (; i < 514; ++i) {
+        _spi.write(0xFF);
+    }
+    _cs = 1;
+    _spi.write(0xFF); // dummy clock to force FlashAir finish the command.
+    return true;
+}
+
+/** Perform Extention Write. */
+uint8_t SD_iSDIO::writeExt(uint32_t arg, const uint8_t* src, uint16_t count)
+{
+    uint16_t i;
+    uint8_t status;
+    // send command and argument.
+    if (_cmd(CMD49, arg)) {
+        error("SD_CARD_ERROR_CMD49");
+        _cs = 1;
+        return false;
+    }
+
+    _cs = 0;
+
+    // send start block token.
+    //_spi.write(DATA_START_BLOCK);
+    _spi.write(0xFE);
+    // send data
+    for (i = 0; i < count; ++i) {
+        _spi.write(src[i]);
+    }
+    // send dummy bytes until 512 bytes.
+    for (; i < 512; ++i) {
+        _spi.write(0xFF);
+    }
+    // dummy 16-bit crc
+    _spi.write(0xFF);
+    _spi.write(0xFF);
+    // wait a data response token
+    status = _spi.write(0xFF);
+    //if ((status & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
+    if ((status & 0x1F) != 0x05) {
+        error("SD_CARD_ERROR_WRITE");
+        _cs = 1;
+        return false;
+    }
+    // wait for flash programming to complete
+    /*
+    if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
+        error("SD_CARD_ERROR_WRITE_TIMEOUT");
+        _cs = 1;
+        return false;
+    }
+    */
+    while (_spi.write(0xFF) == 0);
+
+    _cs = 1;
+    return true;
+}
diff -r 3b1625dbd7e9 -r 51abf34bcc06 iSDIO.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/iSDIO.h	Mon Dec 15 12:23:22 2014 +0000
@@ -0,0 +1,32 @@
+#ifndef SD_iSDIO_h
+#define SD_iSDIO_h
+
+#include "mbed.h"
+#include "SDFileSystem.h"
+#include "iSDIO_helper.h"
+
+class SD_iSDIO : public SDFileSystem
+{
+public:
+    SD_iSDIO(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name);
+
+    static SD_iSDIO* getInstance();
+    uint32_t getSequenceId();
+
+    uint8_t readExtDataPort(uint8_t mio, uint8_t func, uint16_t addr, uint8_t* dst);
+    uint8_t readExtMemory(uint8_t mio, uint8_t func, uint32_t addr, uint16_t count, uint8_t* dst);
+    uint8_t writeExtDataPort(uint8_t mio, uint8_t func, uint16_t addr, const uint8_t* src);
+    uint8_t writeExtMemory(uint8_t mio, uint8_t func, uint32_t addr, uint16_t count, const uint8_t* src);
+    uint8_t writeExtMask(uint8_t mio, uint8_t func, uint32_t addr, uint8_t mask, const uint8_t* src);
+
+    uint8_t waitResponse(uint32_t sequenceId);
+
+protected:
+    uint8_t readExt(uint32_t arg, uint8_t* src, uint16_t count);
+    uint8_t writeExt(uint32_t arg, const uint8_t* src, uint16_t count);
+
+    static SD_iSDIO* instance;
+    uint32_t sequenceId;
+};
+
+#endif  // SD_iSDIO_h
diff -r 3b1625dbd7e9 -r 51abf34bcc06 iSDIO_helper.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/iSDIO_helper.cpp	Mon Dec 15 12:23:22 2014 +0000
@@ -0,0 +1,51 @@
+/* Arduino Sdio Library
+ *  Copyright (C) 2014 by Munehiro Doi, Fixstars Corporation
+ *  All rights reserved.
+ *  Released under the BSD 2-Clause license.
+ *  http://flashair-developers.com/documents/license.html
+ */
+
+#include "iSDIO_helper.h"
+
+//------------------------------------------------------------------------------
+/** specific version for string. it adds padding bytes after text data. */
+template <>
+uint8_t* put_T(uint8_t* p, const char* value) {
+    while (*value != 0) {
+        *p++ = *((uint8_t*)value++);
+    }
+    return p;
+}
+
+template <>
+uint8_t* put_T_arg(uint8_t* p, const char* value) {
+    uint8_t* orig = p;
+    p += sizeof(uint32_t);            // skip length area.
+    p = put_T(p, value);              // data
+    uint32_t len = p - orig - sizeof(uint32_t); 
+    put_T(orig, len);                 // write length.
+    for (int i = 0; i < ((4 - (len & 3)) & 3); ++i) { // padding
+        *p++ = 0;
+    }
+    return p;
+}
+
+uint8_t* put_command_header(uint8_t* p, uint8_t num_commands,
+        uint32_t command_bytes) {
+    p = put_u8(p, 0x01);           // Write Data ID
+    p = put_u8(p, num_commands);   // Number of commands.
+    p = put_u16(p, 0);             // reserved.
+    p = put_u32(p, command_bytes); // size of command write data.
+    p = put_u32(p, 0);             // reserved.
+    return p;  
+}
+
+uint8_t* put_command_info_header(uint8_t* p, uint16_t command_id,
+        uint32_t sequence_id, uint16_t num_args) {
+    p = put_u16(p, 0);             // reserved.
+    p = put_u16(p, command_id);    // iSDIO command id.
+    p = put_u32(p, sequence_id); // iSDIO command sequence id.
+    p = put_u16(p, num_args);      // Number of Arguments.
+    p = put_u16(p, 0);             // Reserved.
+    return p;
+}
diff -r 3b1625dbd7e9 -r 51abf34bcc06 iSDIO_helper.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/iSDIO_helper.h	Mon Dec 15 12:23:22 2014 +0000
@@ -0,0 +1,220 @@
+/* Arduino Sdio Library
+ *  Copyright (C) 2014 by Munehiro Doi, Fixstars Corporation
+ *  All rights reserved.
+ *  Released under the BSD 2-Clause license.
+ *  http://flashair-developers.com/documents/license.html
+ */
+#ifndef iSDIO_helper_h
+#define iSDIO_helper_h
+
+#include <stdint.h>
+
+//------------------------------------------------------------------------------
+// utilities to make a data block.
+template <typename T>
+uint8_t* put_T(uint8_t* p, T value) {
+    *((T*)p) = value;
+    p += sizeof(T);
+    return p;
+}
+/** specific version for string. it set length, data, and paddings. */
+template <>
+uint8_t* put_T(uint8_t* p, const char* value);
+
+// utilities for those who want to see value types by function names.
+static inline
+uint8_t* put_u8(uint8_t* p, uint8_t value) {
+    return put_T(p, value);
+}
+static inline
+uint8_t* put_u16(uint8_t* p, uint16_t value) {
+    return put_T(p, value);
+}
+static inline
+uint8_t* put_u32(uint8_t* p, uint32_t value) {
+    return put_T(p, value);
+}
+static inline
+uint8_t* put_str(uint8_t* p, const char* value) {
+    return put_T(p, value);
+}
+
+static inline
+uint8_t get_u8(uint8_t* p) {
+    return *((uint8_t*)p);
+}
+static inline
+uint16_t get_u16(uint8_t* p) {
+    return *((uint16_t*)p);
+}
+static inline
+uint32_t get_u32(uint8_t* p) {
+    return *((uint32_t*)p);
+}
+
+template <typename T>
+uint8_t* put_T_arg(uint8_t* p, T value) {
+    p = put_T(p, (uint32_t)sizeof(T)); // length
+    p = put_T(p, value);                      // data
+    for (uint8_t i = 0; i < (4 - sizeof(T)) & 0x3; ++i) { // padding
+        *p++ = 0;
+    }
+    return p;
+}
+template <>
+uint8_t* put_T_arg(uint8_t* p, const char* value);
+
+static inline
+uint8_t* put_u8_arg(uint8_t* p, uint8_t value) {
+    return put_T_arg(p, value);
+}
+static inline
+uint8_t* put_u16_arg(uint8_t* p, uint16_t value) {
+    return put_T_arg(p, value);
+}
+static inline
+uint8_t* put_u32_arg(uint8_t* p, uint32_t value) {
+    return put_T_arg(p, value);
+}
+static inline
+uint8_t* put_str_arg(uint8_t* p, const char* value) {
+    return put_T_arg(p, value);
+}
+uint8_t* put_command_header(uint8_t* p, uint8_t num_commands,
+        uint32_t command_bytes);
+uint8_t* put_command_info_header(uint8_t* p, uint16_t command_id,
+        uint32_t sequence_id, uint16_t num_args);
+
+//------------------------------------------------------------------------------
+/**
+ * Header data for CMD48/49 param
+ */
+typedef struct { 
+    uint8_t  id;
+    uint8_t  number;
+    uint16_t _reserved1;
+    uint32_t size;
+    uint32_t _reserved2;
+} isdio_command_header_t;
+
+/**
+ * Information data for CMD48/49 param
+ */
+typedef struct { 
+    uint16_t _reserved0;
+    uint16_t command;
+    uint32_t sequence_id;
+    uint16_t num_args;
+    uint16_t _reserved1;
+} isdio_command_info_header_t;
+
+/**
+ * iSDIO Response Status Register at 0x440
+ */
+typedef struct {
+    uint8_t  registration;
+    uint8_t  _reserved0;
+    uint16_t command_id;
+    uint32_t sequence_id;
+    uint8_t  status;
+    uint8_t  _reserved1[3];
+    uint32_t error_status;
+    uint32_t data_size;
+} isdio_response_status_t;
+
+/**
+ * Status Register at 0x400
+ */
+typedef struct {
+    uint8_t                 CWU       :1; // Command Write Update
+    uint8_t                 CWA       :1; // Command Write Abort
+    uint8_t                 _reserved0:6;
+    uint8_t                 _reserved1[31];
+    uint16_t                CRU       :1; // Command Response Update
+    uint16_t                ESU       :1; // Error Status Update
+    uint16_t                MCU       :1; // Media Change Update
+    uint16_t                ASU       :1; // Application Status Update
+    uint16_t                _reserved2:12;
+    uint16_t                CRU_ENA   :1; // CRU Enabled
+    uint16_t                ESU_ENA   :1; // ESU Enabled
+    uint16_t                MCU_ENA   :1; // MCU Enabled
+    uint16_t                ASU_ENA   :1; // ASU Enabled
+    uint16_t                _reserved3:12;
+    uint16_t                CRE       :1; // Command Response Error
+    uint16_t                CWE       :1; // Command Write Error
+    uint16_t                RRE       :1; // Response Receive Error
+    uint16_t                APE       :1; // Application Specific Error
+    uint16_t                _reserved4:12;
+    uint16_t                MEX       :1; // Memory Existence
+    uint16_t                FAT       :1; // FAT System
+    uint16_t                _reserved5:14;
+    uint8_t                 _reserved6[24];
+    isdio_response_status_t response[8];
+    uint8_t                 _reserved7[32];
+    uint8_t                 application_status[256];
+} isdio_status_t;
+
+
+typedef struct {
+    uint8_t    ULR :1;
+    uint8_t    DLU :1;
+    uint8_t    CBR :1;
+    uint8_t    CDR :1;
+    uint8_t    _reserved0 :4;    
+    uint8_t    ILU :1;
+    uint8_t    FLU :1;
+    uint8_t    _reserved1 :6;
+    uint8_t    RPO :1;
+    uint8_t    RPD :1;
+    uint8_t    RPC :1;
+    uint8_t    CPI :1;
+    uint8_t    DPI :1;
+    uint8_t    CIL :1;
+    uint8_t    _reserved2 :2;
+    uint8_t    _reserved3;
+    uint8_t    application;
+    uint8_t    _reserved4;
+    uint16_t   Scan         :1;
+    uint16_t   WPS          :2;
+    uint16_t   Group        :1;
+    uint16_t   AP_STA       :1;
+    uint16_t   Infra_Direct :2;
+    uint16_t   Connected    :1;
+    uint16_t   _reserved5    :8;
+    char       SSID[32];
+    uint8_t    encryption_mode;
+    uint8_t    signal_strength;
+    uint8_t    channel;
+    uint8_t    _reserved6[5];
+    uint8_t    MACAddress[6];
+    uint8_t    _reserved7[10];
+    uint8_t    ID[16];
+    uint8_t    IPAddress[4];
+    uint8_t    SubnetMask[4];
+    uint8_t    DefaultGateway[4];
+    uint8_t    PreferredDNSServer[4];
+    uint8_t    AlternateDNSServer[4];
+    uint8_t    ProxyServer:1;
+    uint8_t    _reserved8:7;
+} isdio_wlan_status_t;
+
+/**
+ * iSDIO Vendor Status Register at 0x5C0
+ */
+typedef struct {
+    uint32_t vendorId;
+    uint32_t vendorFunction;
+    uint32_t HttpBodyTransferSize;
+    uint32_t HttpBodyTotalSize;
+    uint32_t HttpBuffSize;
+    uint32_t LHFStatus:8;
+    uint32_t PhotoshareStatus:8;
+    uint32_t FileDownloadStatus:8;
+    uint32_t rsv0:8;
+    uint32_t FtpTransferSize;
+    uint32_t rsv1;
+    uint32_t rsv2[4];
+    uint8_t VendorFwVersion[16];
+} isdio_vender_status_t;
+
+#endif  // iSDIO_helper_h