WIZ820io(W5200) network interface、EthernetNetIf compatible.

/media/uploads/va009039/wiz820ionetif.jpg

example

#include "WIZ820ioNetIf.h"
#include "HTTPClient.h"
#include "HTTPServer.h"

#if defined(TARGET_KL25Z)
WIZ820ioNetIf eth(PTD2,PTD3,PTD1,PTD0,PTD5);
#endif
HTTPClient http;
HTTPStream stream;

void callback(HTTPResult r){
    printf("callback %d %s\n", r, HTTPClient::ResultStr(r));
}

int main() {
    int err = eth.setup();
    if (err < 0) {
        printf("setup error %d\n", err);
        exit(-1);
    }    

    HTTPServer svr;
    svr.addHandler<SimpleHandler>("/");
    svr.bind(80);

    const char* uri = "http://va009039-mbed.appspot.com/kl25z/";
    http.get(uri, &stream, callback);
    uint8_t buf[256];
    int total = 0;
    stream.readNext(buf, sizeof(buf));
    while(1) {
        if(stream.readable()) {
            int len = stream.readLen();
            total += len;
            printf("%d %d\n", total, len);
            stream.readNext(buf, sizeof(buf));
        }
        Net::poll();
    }
}

Files at this revision

API Documentation at this revision

Comitter:
va009039
Date:
Fri Mar 22 11:51:24 2013 +0000
Child:
1:22b9052d864d
Commit message:
[mbed] converted /w5200NetIf/w5200NetIf

Changed in this revision

DHCPClient.cpp Show annotated file Show diff for this revision Revisions of this file
DHCPClient.h Show annotated file Show diff for this revision Revisions of this file
MyNetDnsRequest.cpp Show annotated file Show diff for this revision Revisions of this file
MyNetDnsRequest.h Show annotated file Show diff for this revision Revisions of this file
MyNetIf.cpp Show annotated file Show diff for this revision Revisions of this file
MyNetIf.h Show annotated file Show diff for this revision Revisions of this file
MyNetTcpSocket.cpp Show annotated file Show diff for this revision Revisions of this file
MyNetTcpSocket.h Show annotated file Show diff for this revision Revisions of this file
MyNetUdpSocket.cpp Show annotated file Show diff for this revision Revisions of this file
MyNetUdpSocket.h Show annotated file Show diff for this revision Revisions of this file
W5200NetIf.cpp Show annotated file Show diff for this revision Revisions of this file
W5200NetIf.h Show annotated file Show diff for this revision Revisions of this file
WIZ820ioNetIf.cpp Show annotated file Show diff for this revision Revisions of this file
WIZ820ioNetIf.h Show annotated file Show diff for this revision Revisions of this file
dnsname.h Show annotated file Show diff for this revision Revisions of this file
w5100.cpp Show annotated file Show diff for this revision Revisions of this file
w5100.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DHCPClient.cpp	Fri Mar 22 11:51:24 2013 +0000
@@ -0,0 +1,170 @@
+// DHCPClient.cpp 2012/4/21
+// DHCP Client for WIZ820io(W5200)
+#include "mbed.h"
+#include "w5100.h"
+#include "UDPSocket.h"
+#include "DHCPClient.h"
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+#ifdef __DEBUG
+#define DBG2(...) do{ DebugStream::debug("%p %d %s ", this,__LINE__,__PRETTY_FUNCTION__); DebugStream::debug(__VA_ARGS__); } while(0);
+#else
+#define DBG2(...) while(0);
+#endif //__DEBUG
+
+//#define DEBUG
+
+#ifdef DEBUG
+#include "Utils.h"
+#define PRINT_FUNC() printf("%p %d:%s\n", this,__LINE__,__PRETTY_FUNCTION__)
+#else //DEBUG
+#define PRINT_FUNC()
+#endif //DEBUG
+
+int DHCPClient::discover(uint8_t buf[], int size) {
+    memset(buf, 0x00, size);
+    const uint8_t headers[] = {0x01,0x01,0x06,0x00,
+                               0x12,0x34,0x56,0x78}; // xid
+    memcpy(buf, headers, sizeof(headers));
+    int t = clock();
+    xid[0] = t<<24;
+    xid[1] = t<<16;
+    xid[2] = t<<8;
+    xid[3] = t;
+    memcpy(buf+DHCP_OFFSET_XID, xid, 4);
+    W5100.getMACAddress(buf+DHCP_OFFSET_CHADDR);
+    const uint8_t options[] = {0x63,0x82,0x53,0x63, // magic cookie
+                               0x35,0x01,0x01, // DHCP DISCOVER
+                               0xff};
+    memcpy(buf+DHCP_OFFSET_MAGIC_COOKIE, options, sizeof(options));
+    uint8_t ip[4] = {0,0,0,0};
+    W5100.setIPAddress(ip);
+    return DHCP_OFFSET_MAGIC_COOKIE + sizeof(options);
+}
+
+int DHCPClient::request(uint8_t buf[], int size) {
+    memset(buf, 0x00, size);
+    const uint8_t headers[] = {0x01,0x01,0x06,0x00,
+                               0x12,0x34,0x56,0x78}; // xid
+    memcpy(buf, headers, sizeof(headers));
+    memcpy(buf+DHCP_OFFSET_XID, xid, 4);
+    memcpy(buf+DHCP_OFFSET_YIADDR, yiaddr, 4);
+    W5100.getMACAddress(buf+DHCP_OFFSET_CHADDR);
+    const uint8_t options[] = {0x63,0x82,0x53,0x63, // magic cookie
+                               0x35,0x01,0x03, // DHCP REQUEST
+                               0x32,0x04,0x00,0x00,0x00,0x00, // request IP
+                               0xff};
+    memcpy(buf+DHCP_OFFSET_MAGIC_COOKIE, options, sizeof(options));
+    memcpy(buf+DHCP_OFFSET_MAGIC_COOKIE+9, yiaddr, 4);
+    return DHCP_OFFSET_MAGIC_COOKIE + sizeof(options);
+}
+
+int DHCPClient::offer_ack(uint8_t buf[], int size) {
+    memcpy(yiaddr, &buf[DHCP_OFFSET_YIADDR], 4);   
+    uint8_t *p;
+    int msg_type = -1;
+    p = buf + DHCP_OFFSET_OPTIONS;
+    while(*p != 0xff && p < (uint8_t*)&buf[DHCP_MAX_PACKET_SIZE]) {
+        int code = *p++;
+        if (code == 0x00) {
+            continue;
+        }
+        int len = *p++;
+#ifdef DEBUG           
+        char codeStr[24];
+        snprintf(codeStr, sizeof(codeStr), "DHCP option: %d", code);
+        printfBytes(codeStr, p, len);
+#endif //DEBUG
+        if (code == 53) {
+           msg_type = *p;
+        } else if (code == 1) {
+            memcpy(netmask, p, 4); // Subnet mask address
+        } else if (code == 3) {
+            memcpy(gateway, p, 4); // Gateway IP address 
+        } else if (code == 6) {// DNS
+            memcpy(dnsaddr, p, 4);
+        }
+        p += len;
+    }
+    return msg_type;
+}
+
+bool DHCPClient::verify(uint8_t buf[], int len) {
+    if (len < DHCP_OFFSET_OPTIONS) {
+        return false;
+    }
+    if (buf[DHCP_OFFSET_OP] != 0x02) {
+        return false;
+    }
+    if (memcmp(buf+DHCP_OFFSET_XID, xid, 4) != 0) {
+        return false;
+    }
+    return true;
+}
+
+void DHCPClient::callback(UDPSocketEvent e)
+{
+    PRINT_FUNC();
+    uint8_t buf[DHCP_MAX_PACKET_SIZE];
+    Host host;
+    int len = m_udp->recvfrom((char*)buf, sizeof(buf), &host);
+    if (!verify(buf, len)) {
+        return;
+    }
+    int r = offer_ack(buf, len);
+    if (r == 2) { // OFFER
+        request(buf, 300);
+        Host server(IpAddr(255,255,255,255), 67); // DHCP broadcast
+        m_udp->sendto((char*)buf, 300, &server);
+    } else if (r == 5) { // ACK
+        exit_flag = true;
+    }
+}
+
+int DHCPClient::setup(int timeout_ms)
+{
+    PRINT_FUNC();   
+    int interval_ms = 2000; // 2000msec
+    if (timeout_ms < interval_ms) {
+        interval_ms = timeout_ms;
+    }
+    m_retry = 0;
+    m_interval.start();
+    m_udp = new UDPSocket;
+    m_udp->setOnEvent(this, &DHCPClient::callback);
+    Host local(IpAddr(0,0,0,0), 68);
+    Host server(IpAddr(255,255,255,255), 67); // DHCP broadcast
+    m_udp->bind(local);
+    uint8_t buf[300];
+    discover(buf, sizeof(buf));
+    m_udp->sendto((char*)buf, sizeof(buf), &server);
+    m_interval.reset();
+    exit_flag = false;
+    int err = 0;
+    while(1) {
+        Net::poll();
+        if (exit_flag) {
+            DBG2("m_retry: %d, m_interval: %d\n", m_retry, m_interval.read_ms());
+            break;
+        }
+        if (m_interval.read_ms() > interval_ms) {
+            DBG2("m_retry: %d\n", m_retry);
+            if (++m_retry >= (timeout_ms/interval_ms)) {
+                err = -1;
+                break;
+            }
+            m_udp->sendto((char*)buf, sizeof(buf), &server);
+            m_interval.reset();
+        }
+#ifdef DEBUG            
+        wait_ms(500);
+#endif //DEBUG
+    }
+    delete m_udp;
+    return err;
+}
+
+DHCPClient::DHCPClient() {
+    m_udp = NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DHCPClient.h	Fri Mar 22 11:51:24 2013 +0000
@@ -0,0 +1,36 @@
+// DHCPClient.h 2012/4/21
+#ifndef DHCPCLIENT_H
+#define DHCPCLIENT_H
+#include "UDPSocket.h"
+
+
+#define DHCP_OFFSET_OP 0
+#define DHCP_OFFSET_XID 4
+#define DHCP_OFFSET_YIADDR 16
+#define DHCP_OFFSET_CHADDR 28
+#define DHCP_OFFSET_MAGIC_COOKIE 236
+#define DHCP_OFFSET_OPTIONS 240
+#define DHCP_MAX_PACKET_SIZE 600
+
+class DHCPClient {
+    int discover(uint8_t buf[], int size);
+    int request(uint8_t buf[], int size);
+    int offer_ack(uint8_t buf[], int size);
+    bool verify(uint8_t buf[], int len);
+public:
+    void callback(UDPSocketEvent e);
+    int setup(int timeout_ms = 15000);
+    DHCPClient();
+    uint8_t chaddr[6]; // MAC
+    uint8_t yiaddr[4]; // IP
+    uint8_t dnsaddr[4]; // DNS
+    uint8_t gateway[4];
+    uint8_t netmask[4];
+private:
+    UDPSocket* m_udp;
+    uint8_t xid[4];
+    bool exit_flag;
+    Timer m_interval;
+    int m_retry;
+};
+#endif //DHCPCLIENT_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyNetDnsRequest.cpp	Fri Mar 22 11:51:24 2013 +0000
@@ -0,0 +1,199 @@
+// MyNetDnsRequest.cpp 2012/4/22
+#include "mbed.h"
+#include "MyNetDnsRequest.h"
+#include "UDPSocket.h"
+#include <string>
+#include "dnsname.h"
+#include "W5200NetIf.h"
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+#ifdef __DEBUG
+#define DBG2(...) do{ DebugStream::debug("%p %d %s ", this,__LINE__,__PRETTY_FUNCTION__); DebugStream::debug(__VA_ARGS__); } while(0);
+#else
+#define DBG2(...) while(0);
+#endif //__DEBUG
+
+//#define DEBUG
+
+#ifdef DEBUG
+#include "Utils.h"
+#define PRINT_FUNC() printf("%p %d:%s\n", this,__LINE__,__PRETTY_FUNCTION__)
+#else //DEBUG
+#define PRINT_FUNC()
+#endif //DEBUG
+
+
+MyNetDnsRequest::MyNetDnsRequest(const char* hostname) : NetDnsRequest(hostname), 
+    m_state(MYNETDNS_START), m_cbFired(false), m_closing(false), m_udp(NULL) {
+    PRINT_FUNC();
+}
+
+MyNetDnsRequest::MyNetDnsRequest(Host* pHost) : NetDnsRequest(pHost), 
+    m_state(MYNETDNS_START), m_cbFired(false), m_closing(false), m_udp(NULL) {
+    PRINT_FUNC();
+}
+
+MyNetDnsRequest::~MyNetDnsRequest() {
+    PRINT_FUNC();
+    if (m_udp) {
+        delete m_udp;
+    }
+}
+
+void MyNetDnsRequest::callback(UDPSocketEvent e)
+{
+    PRINT_FUNC();
+    DBG2("m_id[]=%02x:%02x\n", m_id[0], m_id[1]);
+    uint8_t buf[512];
+    Host host;
+    int len = m_udp->recvfrom((char*)buf, sizeof(buf), &host);
+    if (memcmp(buf+0, m_id, 2) != 0) { //verify
+        return;
+    }
+    int rcode = response(buf, len);
+    if (rcode == 0) {
+        m_state = MYNETDNS_OK;
+    } else {
+        m_state = MYNETDNS_NOTFOUND;
+    }
+}
+
+int MyNetDnsRequest::response(uint8_t buf[], int size) {
+    PRINT_FUNC();
+#ifdef DEBUG
+    printHex(buf, size);
+#endif //DEBUG
+    int rcode = buf[3] & 0x0f;
+    if (rcode != 0) {
+        return rcode;
+    }
+    int qdcount = buf[4]<<8|buf[5];
+    int ancount = buf[6]<<8|buf[7];
+    int pos = 12;
+    while(qdcount-- > 0) {
+        dnsname qname(buf);
+        pos = qname.decode(pos); // qname
+        pos += 4; // qtype qclass
+    }
+    while(ancount-- > 0) {
+        dnsname name(buf);
+        pos = name.decode(pos); // name
+        int type = buf[pos]<<8|buf[pos+1];
+        pos += 8; // type class TTL  
+        int rdlength = buf[pos]<<8|buf[pos+1]; pos += 2;
+        int rdata_pos = pos;
+        pos += rdlength;
+        if (type == 1) { // A record
+            m_ip = IpAddr(buf[rdata_pos],buf[rdata_pos+1],buf[rdata_pos+2],buf[rdata_pos+3]);
+        }
+#ifdef DEBUG
+        printf("%s", name.str.c_str());
+        if (type == 1) {
+            printf(" A %d.%d.%d.%d\n", 
+                buf[rdata_pos],buf[rdata_pos+1],buf[rdata_pos+2],buf[rdata_pos+3]);
+        } else if (type == 5) {
+            dnsname rdname(buf);
+            rdname.decode(rdata_pos);
+            printf(" CNAME %s\n", rdname.str.c_str());
+        } else {
+            printf(" TYPE:%d", type);
+            printfBytes(" RDATA:", &buf[rdata_pos], rdlength);
+        }
+#endif //DEBUG
+    }
+    return rcode;
+}
+
+int MyNetDnsRequest::query(uint8_t buf[], int size, const char* hostname) {
+    PRINT_FUNC();
+    const uint8_t header[] = {
+        0x00,0x00,0x01,0x00, // id=0x0000 QR=0 rd=1 opcode=0 rcode=0
+        0x00,0x01,0x00,0x00, // qdcount=1 ancount=0
+        0x00,0x00,0x00,0x00};// nscount=0 arcount=0 
+    const uint8_t tail[] = {0x00,0x01,0x00,0x01}; // qtype=A qclass=IN
+    memcpy(buf, header, sizeof(header));
+    int t = clock();
+    m_id[0] = t>>8;
+    m_id[1] = t;
+    memcpy(buf, m_id, 2); 
+    dnsname qname(buf);
+    int pos = qname.encode(sizeof(header), (char*)hostname);
+    memcpy(buf+pos, tail, sizeof(tail));
+    pos += sizeof(tail);
+    return pos;
+}
+
+void MyNetDnsRequest::resolve(const char* hostname) {
+    PRINT_FUNC();
+    if (m_udp == NULL) {
+        m_udp = new UDPSocket;
+    }
+    m_udp->setOnEvent(this, &MyNetDnsRequest::callback);
+    Host local(IpAddr(0,0,0,0), 1024 + rand()&0x7fff);
+    IpAddr dns(8,8,8,8);
+    NetIf* pIf = Net::getDefaultIf();
+    if (pIf) {
+        dns = ((W5200NetIf*)pIf)->m_dns;
+    }
+    Host server(dns, 53); // DNS
+    m_udp->bind(local);
+    uint8_t buf[256];                
+    int size = query(buf, sizeof(buf), hostname);
+#ifdef DEBUG
+    printf("hostname:[%s]\n", hostname);
+    printHex(buf, size);
+#endif
+    m_udp->sendto((char*)buf, size, &server);
+    m_interval.reset();
+    m_interval.start();
+}
+
+void MyNetDnsRequest::poll() {
+    PRINT_FUNC();
+#ifdef DEBUG
+    printf("%p m_state: %d, m_udp: %p\n", this, m_state, m_udp);
+    wait_ms(400);
+#endif //DEBUG
+    switch(m_state) {
+        case MYNETDNS_START:
+            m_retry = 0;
+            resolve(m_hostname);
+            m_state = MYNETDNS_PROCESSING;
+            break;
+        case MYNETDNS_PROCESSING: 
+            break;
+        case MYNETDNS_NOTFOUND: 
+            onReply(NETDNS_FOUND); 
+            break;
+        case MYNETDNS_ERROR: 
+            onReply(NETDNS_ERROR);
+            break;
+        case MYNETDNS_OK:
+            DBG2("m_retry=%d, m_interval=%d\n", m_retry, m_interval.read_ms());
+            onReply(NETDNS_FOUND); 
+            break;
+    }
+    if (m_interval.read_ms() > 1000) {
+        m_interval.stop();
+        DBG2("timeout m_retry=%d\n", m_retry);
+        if (++m_retry >= 2) {
+            m_state = MYNETDNS_ERROR;
+        } else {
+            resolve(m_hostname);
+            m_state = MYNETDNS_PROCESSING;
+        }
+    }
+    if(m_closing && (m_state!=MYNETDNS_PROCESSING)) {
+        NetDnsRequest::close();
+    }
+}
+
+void MyNetDnsRequest::close() {
+    PRINT_FUNC();
+    if(m_state != MYNETDNS_PROCESSING) {
+        NetDnsRequest::close();
+    } else {
+        m_closing = true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyNetDnsRequest.h	Fri Mar 22 11:51:24 2013 +0000
@@ -0,0 +1,36 @@
+// MyNetDnsRequest.h 2012/4/19
+#ifndef MYNETDNSREQUEST_H
+#define MYNETDNSREQUEST_H
+#include "if/net/netdnsrequest.h"
+#include "UDPSocket.h"
+ 
+class MyNetDnsRequest : public NetDnsRequest {
+public:
+    MyNetDnsRequest(const char* hostname);
+    MyNetDnsRequest(Host* pHost);
+    virtual ~MyNetDnsRequest();
+    virtual void poll();
+    virtual void close();
+protected:
+    void callback(UDPSocketEvent e);
+    int response(uint8_t buf[], int size);
+    int query(uint8_t buf[], int size, const char* hostname);
+    void resolve(const char* hostname);
+    uint8_t m_id[2];
+    Timer m_interval;
+    int m_retry;
+private:
+    enum MyNetDnsState
+    {
+        MYNETDNS_START,
+        MYNETDNS_PROCESSING, //Req has not completed
+        MYNETDNS_NOTFOUND,
+        MYNETDNS_ERROR,
+        MYNETDNS_OK
+    };
+    MyNetDnsState m_state;
+    bool m_cbFired;
+    bool m_closing;
+    UDPSocket *m_udp;
+};
+#endif //MYNETDNSREQUEST_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyNetIf.cpp	Fri Mar 22 11:51:24 2013 +0000
@@ -0,0 +1,80 @@
+// MyNetIf.cpp 2012/4/17
+#include "mbed.h"
+#include "MyNetIf.h"
+#include "MyNetTcpSocket.h"
+#include "MyNetUdpSocket.h"
+#include "MyNetDnsRequest.h"
+
+//#define DEBUG
+
+#ifdef DEBUG
+#include "w5100.h"
+#include "Utils.h"
+#define PRINT_FUNC() printf("%p %d:%s\n", this,__LINE__,__PRETTY_FUNCTION__)
+#else //DEBUG
+#define PRINT_FUNC()
+#endif //DEBUG
+
+MyNetIf::MyNetIf() : NetIf(), m_init(false)
+{
+    PRINT_FUNC();
+}
+
+MyNetIf::~MyNetIf() {
+    PRINT_FUNC();
+}
+
+void MyNetIf::init() {
+    PRINT_FUNC();
+}
+
+NetTcpSocket* MyNetIf::tcpSocket() {
+    PRINT_FUNC();
+    return new MyNetTcpSocket();
+}
+
+NetUdpSocket* MyNetIf::udpSocket() {
+    PRINT_FUNC();
+    return new MyNetUdpSocket();
+}
+
+NetDnsRequest* MyNetIf::dnsRequest(const char* hostname) {
+    PRINT_FUNC();
+    return new MyNetDnsRequest(hostname);
+}
+
+NetDnsRequest* MyNetIf::dnsRequest(Host* pHost) {
+    PRINT_FUNC();
+    return new MyNetDnsRequest(pHost);
+}
+
+void MyNetIf::poll() {
+    PRINT_FUNC();
+#ifdef DEBUG
+    printf("SnMR:");
+    for(int s = 0; s < MAX_SOCK_NUM; s++) {
+        printf(" %02x", W5100.readSnMR(s));
+    }
+    printf("\n");
+
+    printf("SnIR:");
+    for(int s = 0; s < MAX_SOCK_NUM; s++) {
+        printf(" %02x", W5100.readSnIR(s));
+    }
+    printf("\n");
+
+    printf("SnSR:");
+    for(int s = 0; s < MAX_SOCK_NUM; s++) {
+        printf(" %02x", W5100.readSnSR(s));
+    }
+    printf("\n");
+
+    printf("SnPORT:");
+    for(int s = 0; s < MAX_SOCK_NUM; s++) {
+        printf(" %d", W5100.readSnPORT(s));
+    }
+    printf("\n");
+    
+    wait_ms(500);
+#endif //DEBUG
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyNetIf.h	Fri Mar 22 11:51:24 2013 +0000
@@ -0,0 +1,24 @@
+// MyNetIf.h 2012/4/15
+#ifndef MYIPNETIF_H
+#define MYIPNETIF_H
+#include "mbed.h"
+#include "core/net.h"
+#include "if/net/netif.h"
+
+class MyNetIf : public NetIf {
+public:
+    MyNetIf();
+    
+    void init();
+
+    virtual ~MyNetIf();
+    virtual NetTcpSocket* tcpSocket();
+    virtual NetUdpSocket* udpSocket();
+    virtual NetDnsRequest* dnsRequest(const char* hostname);
+    virtual NetDnsRequest* dnsRequest(Host* pHost);
+    
+    virtual void poll();
+private:
+    bool m_init;
+};
+#endif //MYIPNETIF_H
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyNetTcpSocket.cpp	Fri Mar 22 11:51:24 2013 +0000
@@ -0,0 +1,259 @@
+// MyNetTcpSocket.cpp 2012/4/22
+#include "mbed.h"
+#include "w5100.h"
+#include "MyNetTcpSocket.h"
+//#define __DEBUG
+#include "dbg/dbg.h"
+
+#ifdef __DEBUG
+#define DBG2(...) do{ DebugStream::debug("%p %s ", this,__PRETTY_FUNCTION__); DebugStream::debug(__VA_ARGS__); } while(0);
+#else
+#define DBG2(...) while(0);
+#endif //__DEBUG
+
+//#define DEBUG
+
+#ifdef DEBUG
+#include "Utils.h"
+#define PRINT_FUNC() printf("%p %d:%s\n", this,__LINE__,__PRETTY_FUNCTION__)
+#else //DEBUG
+#define PRINT_FUNC()
+#endif //DEBUG
+
+#define USE_NO_DELAYED_ACK 1
+
+int w5200_new_socket() 
+{
+    for(int i = 0; i < MAX_SOCK_NUM; i++) {
+        if (W5100.readSnMR(i) == SnMR::CLOSE) { // 0x00
+            if (W5100.readSnSR(i) != SnSR::LISTEN) { // 0x14
+                return i;
+            }
+        }
+    }
+    return -1; // not found
+}
+
+MyNetTcpSocket::MyNetTcpSocket(int socket) : NetTcpSocket(),_socket(socket),wait_accept(false)  {
+    PRINT_FUNC();
+    DBG2("socket: %d\n", socket);
+    if (_socket == (-1)) {
+        _socket = w5200_new_socket();
+    }
+#ifdef DEBUG
+    printf("%p socket: %d\n", this, _socket);
+#endif //DEBUG
+    if (_socket != (-1)) {
+        uint8_t Sn_MR = SnMR::TCP; // set TCP mode
+#if USE_NO_DELAYED_ACK 
+        Sn_MR |= SnMR::ND;
+#endif 
+        W5100.writeSnMR(_socket, Sn_MR);
+    }
+}
+
+MyNetTcpSocket::~MyNetTcpSocket() {
+    PRINT_FUNC();
+    DBG2("socket=%d\n", _socket);
+    close();
+    if (_socket != (-1)) {
+        W5100.writeSnMR(_socket, SnMR::CLOSE);
+    }
+}
+
+NetTcpSocketErr MyNetTcpSocket::bind(const Host& me) {
+    PRINT_FUNC();
+    if (_socket == (-1)) {
+        return NETTCPSOCKET_MEM;
+    }
+    int port = me.getPort();
+    W5100.writeSnPORT(_socket, port);
+    return NETTCPSOCKET_OK;
+}
+
+NetTcpSocketErr MyNetTcpSocket::listen() {
+    PRINT_FUNC();
+    if (_socket == (-1)) {
+        return NETTCPSOCKET_MEM;
+    }
+    W5100.execCmdSn(_socket, Sock_OPEN); // set OPEN command
+    W5100.execCmdSn(_socket, Sock_LISTEN); // listen
+#ifdef DEBUG
+    uint8_t ip[4];
+    printf("socket:%d SnMR:%02x SnIR:%02x SnSR:%02x\n", _socket, 
+        W5100.readSnMR(_socket), W5100.readSnIR(_socket), W5100.readSnSR(_socket));
+    W5100.getIPAddress(ip);
+    printf("SIPR: %d.%d.%d.%d Sn_PORT:%d\n", ip[0], ip[1], ip[2], ip[3], W5100.readSnPORT(_socket));
+#endif //DEBUG
+    wait_accept = true;
+    return NETTCPSOCKET_OK;
+}
+
+NetTcpSocketErr MyNetTcpSocket::connect(const Host& host) {
+    PRINT_FUNC();
+    if (_socket == (-1)) {
+        return NETTCPSOCKET_MEM;
+    }
+    uint8_t ip[4];
+    ip[0] = host.getIp()[0];
+    ip[1] = host.getIp()[1];
+    ip[2] = host.getIp()[2];
+    ip[3] = host.getIp()[3];
+    int port = host.getPort();
+    W5100.writeSnDIPR(_socket, ip);
+    W5100.writeSnDPORT(_socket, port);
+    if (W5100.readSnPORT(_socket) == 0) {
+        W5100.writeSnPORT(_socket, 1024 + _socket);
+    }
+    W5100.execCmdSn(_socket, Sock_OPEN); // set OPEN command
+    W5100.execCmdSn(_socket, Sock_CONNECT);
+#ifdef DEBUG
+    printf("socket:%d SnMR:%02x SnIR:%02x SnSR:%02x\n", _socket, 
+        W5100.readSnMR(_socket), W5100.readSnIR(_socket), W5100.readSnSR(_socket));
+    W5100.getIPAddress(ip);
+    printf("SIPR: %d.%d.%d.%d Sn_PORT:%d\n", ip[0], ip[1], ip[2], ip[3], W5100.readSnPORT(_socket));
+    W5100.readSnDIPR(_socket, ip);
+    printf("Sn_DIPR: %d.%d.%d.%d Sn_DPORT:%d\n", ip[0], ip[1], ip[2], ip[3], W5100.readSnDPORT(_socket));
+#endif //DEBUG
+    return NETTCPSOCKET_OK;
+}
+
+NetTcpSocketErr MyNetTcpSocket::accept(Host* pClient, NetTcpSocket** ppNewNetTcpSocket) {
+    PRINT_FUNC();
+    if (_socket == (-1)) {
+        return NETTCPSOCKET_MEM;
+    }
+    uint8_t ip[4];
+    W5100.readSnDIPR(_socket, ip);
+    pClient->setIp(IpAddr(ip[0],ip[1],ip[2],ip[3]));
+    int port = W5100.readSnDPORT(_socket);
+    pClient->setPort(port);
+    Host me;
+    me.setPort(W5100.readSnPORT(_socket));
+    MyNetTcpSocket* pNewNetTcpSocket = new MyNetTcpSocket(_socket);
+    if (pNewNetTcpSocket == NULL) {
+        return NETTCPSOCKET_EMPTY;
+    }
+    pNewNetTcpSocket->m_refs++;
+    *ppNewNetTcpSocket = pNewNetTcpSocket;
+    _socket = w5200_new_socket();
+    if (_socket != (-1)) {
+        uint8_t Sn_MR = SnMR::TCP; // set TCP mode
+#if USE_NO_DELAYED_ACK 
+        Sn_MR |= SnMR::ND;
+#endif 
+        W5100.writeSnMR(_socket, Sn_MR);
+        bind(me);
+        listen();
+     }
+    return NETTCPSOCKET_OK;
+}
+
+int /*if < 0 : NetTcpSocketErr*/ MyNetTcpSocket::send(const char* buf, int len) {
+    PRINT_FUNC();
+#ifdef DEBUG
+    printf("buf:%p, len=%d\n", buf, len);
+    printHex((u8*)buf, len);
+#endif //DEBUG
+    if (_socket == (-1)) {
+        return NETTCPSOCKET_MEM;
+    }
+    if (len > 0) {
+        W5100.send_data_processing(_socket, (uint8_t*)buf, len);
+        W5100.execCmdSn(_socket, Sock_SEND);
+    }
+    return len;
+}
+
+int /*if < 0 : NetTcpSocketErr*/ MyNetTcpSocket::recv(char* buf, int len){
+    PRINT_FUNC();
+    if (_socket == (-1)) {
+        return NETTCPSOCKET_MEM;
+    }
+    int size = W5100.getRXReceivedSize(_socket);
+    if (size > len) {
+        size = len;
+    }
+    if (size > 0) {
+        W5100.recv_data_processing(_socket, (uint8_t*)buf, size);
+        W5100.execCmdSn(_socket, Sock_RECV);
+    }
+#ifdef DEBUG
+    printHex((uint8_t*)buf, size);
+#endif //DEBUG
+    return size;
+}
+
+NetTcpSocketErr MyNetTcpSocket::close() {
+    PRINT_FUNC();
+    DBG2("m_closed=%d m_refs=%d\n", m_closed, m_refs);
+    if(m_closed) {
+        return NETTCPSOCKET_OK;
+    }
+    m_closed = true;
+    cleanUp();
+    if (_socket != (-1)) {
+        W5100.execCmdSn(_socket, Sock_DISCON);
+        W5100.execCmdSn(_socket, Sock_CLOSE);
+    }
+    return NETTCPSOCKET_OK;
+}
+
+NetTcpSocketErr MyNetTcpSocket::poll(){
+    PRINT_FUNC();
+    NetTcpSocket::flushEvents();
+#ifdef DEBUG
+    printf("%p socket:%d\n", this,_socket);
+    if (_socket != (-1)) {
+        printf("SnMR:%02x SnIR:%02x SnSR:%02x\n", 
+            W5100.readSnMR(_socket), W5100.readSnIR(_socket), W5100.readSnSR(_socket));
+        uint8_t ip[4];
+        W5100.readSnDIPR(_socket, ip);
+        printf("Sn_DIPR: %d.%d.%d.%d Sn_DPORT: %d\n", ip[0], ip[1], ip[2], ip[3], W5100.readSnDPORT(_socket));
+        printf("Sn_RX_RSR:%5d, Sn_RX_RD:%5d, Sn_RX_WR:%5d\n",
+                W5100.readSnRX_RSR(_socket), W5100.readSnRX_RD(_socket), W5100.readSnRX_WR(_socket));
+        printf("Sn_TX_FSR:%5d, Sn_TX_RD:%5d, Sn_TX_WR:%5d\n",
+                W5100.readSnTX_FSR(_socket), W5100.readSnTX_RD(_socket), W5100.readSnTX_WR(_socket));
+    }
+    wait_ms(200);
+#endif //DEBUG
+    if (_socket == (-1)) {
+        return NETTCPSOCKET_OK;
+    }
+    uint8_t Sn_SR = W5100.readSnSR(_socket);
+    if (wait_accept) {
+        if (Sn_SR == 0x17) {
+            queueEvent(NETTCPSOCKET_ACCEPT);
+            wait_accept = false;
+        }
+    }
+    if (Sn_SR == 0x1c) {
+        queueEvent(NETTCPSOCKET_CONRST);
+    }
+    if (W5100.getRXReceivedSize(_socket) > 0) {
+        queueEvent(NETTCPSOCKET_READABLE);
+    }
+    if (Sn_SR == 0x17) {
+        queueEvent(NETTCPSOCKET_CONNECTED);
+        if (W5100.getTXFreeSize(_socket) > 0) {
+            queueEvent(NETTCPSOCKET_WRITEABLE);
+        }
+    }
+    if (Sn_SR == 0x00) {
+        queueEvent(NETTCPSOCKET_DISCONNECTED);
+    }
+    return NETTCPSOCKET_OK;
+}
+
+void MyNetTcpSocket::cleanUp() //Flush input buffer
+{
+    PRINT_FUNC();
+    if (_socket == (-1)) {
+        return;
+    }
+    while(W5100.getRXReceivedSize(_socket) > 0) {
+        uint8_t temp[1];
+        W5100.recv_data_processing(_socket, temp, 1);
+        W5100.execCmdSn(_socket, Sock_RECV);
+    }    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyNetTcpSocket.h	Fri Mar 22 11:51:24 2013 +0000
@@ -0,0 +1,25 @@
+// MyNetTcpSocket.h 2012/4/16
+#ifndef MYNETTCPSOCKET_H
+#define MYNETTCPSOCKET_H
+#include "if/net/nettcpsocket.h"
+
+class MyNetTcpSocket : public NetTcpSocket {
+public:
+    MyNetTcpSocket(int socket = (-1));
+    virtual ~MyNetTcpSocket();
+    virtual NetTcpSocketErr bind(const Host& me);
+    virtual NetTcpSocketErr listen();
+    virtual NetTcpSocketErr connect(const Host& host);
+    virtual NetTcpSocketErr accept(Host* pClient, NetTcpSocket** ppNewNetTcpSocket);
+    virtual int /*if < 0 : NetTcpSocketErr*/ send(const char* buf, int len);
+    virtual int /*if < 0 : NetTcpSocketErr*/ recv(char* buf, int len);
+    virtual NetTcpSocketErr close();
+    virtual NetTcpSocketErr poll();
+protected:
+    int _socket;
+    bool wait_accept;
+private:
+    void cleanUp(); //Flush input buffer
+    queue<MyNetTcpSocket*> m_lpInNetTcpSocket;
+};
+#endif //MYNETTCPSOCKET_H
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyNetUdpSocket.cpp	Fri Mar 22 11:51:24 2013 +0000
@@ -0,0 +1,152 @@
+// MyNetUdpSocket.cpp 2012/4/16
+#include "mbed.h"
+#include "MyNetUdpSocket.h"
+#include "w5100.h"
+
+//#define DEBUG
+
+#ifdef DEBUG
+#include "Utils.h"
+#define PRINT_FUNC() printf("%p %d:%s\n", this,__LINE__,__PRETTY_FUNCTION__)
+#else //DEBUG
+#define PRINT_FUNC()
+#endif //DEBUG
+
+extern int w5200_new_socket(); // MyNetTcpSocket.cpp
+
+MyNetUdpSocket::MyNetUdpSocket(int socket) : NetUdpSocket(),_socket(socket)  {
+    PRINT_FUNC();
+    if (_socket == (-1)) {
+        _socket = w5200_new_socket();
+    }
+    if (_socket != (-1)) {
+        W5100.writeSnMR(_socket, SnMR::UDP); // set UDP mode
+    }
+}
+
+MyNetUdpSocket::~MyNetUdpSocket() {
+    PRINT_FUNC();
+    close();
+    if (_socket != (-1)) {
+        W5100.writeSnMR(_socket, SnMR::CLOSE);
+    }
+}
+
+NetUdpSocketErr MyNetUdpSocket::bind(const Host& me) {
+    PRINT_FUNC();
+    if (_socket == (-1)) {
+        return NETUDPSOCKET_MEM;
+    }
+    int port = me.getPort();
+    W5100.writeSnPORT(_socket, port);
+    W5100.execCmdSn( _socket, Sock_OPEN); // set OPEN command
+    return NETUDPSOCKET_OK;
+}
+
+int /*if < 0 : NetUdpSocketErr*/ MyNetUdpSocket::sendto(const char* buf, int len, Host* pHost) {
+    PRINT_FUNC();
+    if (_socket == (-1)) {
+        return NETUDPSOCKET_MEM;
+    }
+    uint8_t ip[4];
+    ip[0] = pHost->getIp()[0];
+    ip[1] = pHost->getIp()[1];
+    ip[2] = pHost->getIp()[2];
+    ip[3] = pHost->getIp()[3];
+    int port = pHost->getPort();
+    W5100.writeSnDIPR(_socket, ip);
+    W5100.writeSnDPORT(_socket, port);
+    W5100.send_data_processing(_socket, (uint8_t*)buf, len);
+    W5100.execCmdSn(_socket, Sock_SEND);
+#ifdef DEBUG
+    printHex((u8*)buf, len);
+    W5100.getIPAddress(ip);
+    printf("SIPR: %d.%d.%d.%d Sn_PORT:%d\n", ip[0], ip[1], ip[2], ip[3], W5100.readSnPORT(_socket));
+    W5100.readSnDIPR(_socket, ip);
+    printf("Sn_DIPR: %d.%d.%d.%d Sn_DPORT:%d\n", ip[0], ip[1], ip[2], ip[3], W5100.readSnDPORT(_socket));
+#endif //DEBUG
+    return len;
+}
+
+int /*if < 0 : NetUdpSocketErr*/ MyNetUdpSocket::recvfrom(char* buf, int len, Host* pHost) {
+    PRINT_FUNC();
+    if (_socket == (-1)) {
+        return NETUDPSOCKET_MEM;
+    }
+    int size = W5100.getRXReceivedSize(_socket);
+    if (size < 8) {
+        return -1;
+    }
+    uint8_t info[8];
+    W5100.recv_data_processing(_socket, info, 8);
+    W5100.execCmdSn(_socket, Sock_RECV);
+    pHost->setIp(IpAddr(info[0],info[1],info[2],info[3]));
+    pHost->setPort(info[4]<<8|info[5]);
+    size -= 8;
+    if (size > len) {
+        size = len;
+    }    
+    W5100.recv_data_processing(_socket, (uint8_t*)buf, size);
+    W5100.execCmdSn(_socket, Sock_RECV);
+#ifdef DEBUG
+    printfBytes("UDP PACKET-INFO", (u8*)info, 8);
+    printHex((u8*)buf, size);
+#endif //DEBUG
+    return size;
+}
+
+NetUdpSocketErr MyNetUdpSocket::close() {
+    PRINT_FUNC();
+    if(m_closed) {
+        return NETUDPSOCKET_OK;
+    }
+    if (_socket == (-1)) {
+        return NETUDPSOCKET_MEM;
+    }
+    m_closed = true;
+    cleanUp();
+    W5100.writeSnMR(_socket, SnMR::CLOSE);
+    return NETUDPSOCKET_OK;
+}
+
+NetUdpSocketErr MyNetUdpSocket::poll() {
+    PRINT_FUNC();
+    NetUdpSocket::flushEvents();
+#ifdef DEBUG
+    printf("%p socket:%d\n", this,_socket); 
+    if (_socket != (-1)) {
+        printf("SnMR:%02x SnIR:%02x SnSR:%02x\n",  
+            W5100.readSnMR(_socket), W5100.readSnIR(_socket), W5100.readSnSR(_socket));
+        uint8_t ip[4];
+        W5100.readSnDIPR(_socket, ip);
+        printf("Sn_DIPR: %d.%d.%d.%d Sn_DPORT: %d\n", ip[0], ip[1], ip[2], ip[3], W5100.readSnDPORT(_socket));
+        uint8_t mac[6];
+        W5100.readSnDHAR(_socket, mac);
+        printf("Sn_DHAR: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+        printf("Sn_RX_RSR:%5d, Sn_RX_RD:%5d, Sn_RX_WR:%5d\n",
+                W5100.readSnRX_RSR(_socket), W5100.readSnRX_RD(_socket), W5100.readSnRX_WR(_socket));
+        printf("Sn_TX_FSR:%5d, Sn_TX_RD:%5d, Sn_TX_WR:%5d\n",
+                W5100.readSnTX_FSR(_socket), W5100.readSnTX_RD(_socket), W5100.readSnTX_WR(_socket));
+    }
+    wait_ms(200);    
+#endif //DEBUG
+    if (_socket != (-1)) {
+        if (W5100.getRXReceivedSize(_socket) > 0) {
+            queueEvent(NETUDPSOCKET_READABLE);
+        }
+    }
+    return NETUDPSOCKET_OK;
+}
+
+void MyNetUdpSocket::cleanUp() //Flush input buffer
+{
+    PRINT_FUNC();
+    if (_socket == (-1)) {
+        return;
+    }
+    while(W5100.getRXReceivedSize(_socket) > 0) {
+        uint8_t temp[1];
+        W5100.recv_data_processing(_socket, temp, 1);
+        W5100.execCmdSn(_socket, Sock_RECV);
+    }    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyNetUdpSocket.h	Fri Mar 22 11:51:24 2013 +0000
@@ -0,0 +1,20 @@
+// MyNetUdpSocket.h 2012/4/16
+#ifndef MYNETUDPSOCKET_H
+#define MYNETUDPSOCKET_H
+#include "if/net/netudpsocket.h"
+
+class MyNetUdpSocket: public NetUdpSocket {
+public:
+    MyNetUdpSocket(int socket = (-1));
+    virtual ~MyNetUdpSocket();
+    virtual NetUdpSocketErr bind(const Host& me);
+    virtual int /*if < 0 : NetUdpSocketErr*/ sendto(const char* buf, int len, Host* pHost);
+    virtual int /*if < 0 : NetUdpSocketErr*/ recvfrom(char* buf, int len, Host* pHost);
+    virtual NetUdpSocketErr close();
+    virtual NetUdpSocketErr poll();
+protected:
+    int _socket;
+private:
+    void cleanUp(); //Flush input buffer
+};
+#endif //MYNETUDPSOCKET_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/W5200NetIf.cpp	Fri Mar 22 11:51:24 2013 +0000
@@ -0,0 +1,88 @@
+// W5200NetIf.cpp 2012/4/23
+#include "W5200NetIf.h"
+#include "DHCPClient.h"
+#include "w5100.h"
+
+extern SPI* pSPI; // w5100.cpp
+extern DigitalOut* pCS; // w5100.cpp
+
+W5200NetIf:: W5200NetIf():MyNetIf(), m_netmask(255,255,255,255), m_gateway(), m_hostname(NULL) {
+    m_hostname = NULL;
+    m_useDhcp = true;
+}
+
+W5200NetIf::W5200NetIf(IpAddr ip, IpAddr netmask, IpAddr gateway, IpAddr dns) :MyNetIf(), m_hostname(NULL) {
+    m_hostname = NULL;
+    m_ip = ip;
+    m_netmask = netmask;
+    m_gateway = gateway;
+    m_dns = dns;
+    m_useDhcp = false;
+}
+
+W5200Err W5200NetIf::IPrenew(int timeout_ms) {
+    if (pSPI == NULL || pCS == NULL) {
+        return W5200_SETUP_ERR;
+    }
+    printf("DHCP Started, waiting for IP...\n");  
+    DHCPClient dhcp;
+    int err = dhcp.setup(timeout_ms);
+    if (err == (-1)) {
+        printf("Timeout.\n");
+        return W5200_TIMEOUT;
+    }
+    printf("Connected, IP: %d.%d.%d.%d\n", dhcp.yiaddr[0], dhcp.yiaddr[1], dhcp.yiaddr[2], dhcp.yiaddr[3]);
+    m_ip = IpAddr(dhcp.yiaddr[0], dhcp.yiaddr[1], dhcp.yiaddr[2], dhcp.yiaddr[3]);
+    m_netmask = IpAddr(dhcp.netmask[0],dhcp.netmask[1],dhcp.netmask[2],dhcp.netmask[3]);
+    m_gateway = IpAddr(dhcp.gateway[0],dhcp.gateway[1],dhcp.gateway[2],dhcp.gateway[3]);
+    uint8_t t[4];
+    t[0] = m_ip[0];
+    t[1] = m_ip[1];
+    t[2] = m_ip[2];
+    t[3] = m_ip[3];
+    W5100.writeSIPR(t);
+    t[0] = m_netmask[0];
+    t[1] = m_netmask[1];
+    t[2] = m_netmask[2];
+    t[3] = m_netmask[3];
+    W5100.writeSUBR(t);
+    t[0] = m_gateway[0];
+    t[1] = m_gateway[1];
+    t[2] = m_gateway[2];
+    t[3] = m_gateway[3];
+    W5100.writeGAR(t);
+    m_dns = IpAddr(dhcp.dnsaddr[0],dhcp.dnsaddr[1],dhcp.dnsaddr[2],dhcp.dnsaddr[3]);
+    return W5200_OK;
+}
+
+W5200Err W5200NetIf::IPrelease(int timeout_ms) {
+    return W5200_OK;
+}
+
+W5200Err W5200NetIf::setup(int timeout_ms) {
+    if (pSPI == NULL || pCS == NULL) {
+        return W5200_SETUP_ERR;
+    }
+    MyNetIf::init();
+    uint8_t mac[6] = {0x00,0x00,0x5e,0x00,0x01,0x01};
+    W5100.setMACAddress(mac);
+    printf("HW Addr is : %02x:%02x:%02x:%02x:%02x:%02x.\n", mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
+    if(! m_useDhcp) {
+        return W5200_OK;
+    }
+    return IPrenew(timeout_ms);
+}
+
+SPI* W5200NetIf::attachSPI(SPI* spi) {
+    if (spi) {
+        pSPI = spi;
+    }
+    return pSPI;
+}
+
+DigitalOut* W5200NetIf::attachCS(DigitalOut* cs) {
+    if (cs) {
+        pCS = cs;
+    }
+    return pCS;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/W5200NetIf.h	Fri Mar 22 11:51:24 2013 +0000
@@ -0,0 +1,46 @@
+// W5200NetIf.h 2012/4/19
+/** \file
+W5200 network interface header file
+*/
+#ifndef W5200_NETIF_H
+#define W5200_NETIF_H
+#include "MyNetIf.h"
+
+///W5200 network interface return codes
+enum W5200Err
+{
+  __W5200_MIN = -0xFFFF,
+  W5200_TIMEOUT, ///<Timeout during setup
+  W5200_SETUP_ERR,
+  W5200_OK = 0 ///<Success
+};
+
+///W5200 network interface
+class W5200NetIf : public MyNetIf {
+public:
+    ///Instantiates the Interface and register it against the stack, DHCP will be used
+    W5200NetIf(); //W/ DHCP
+    ///Instantiates the Interface and register it against the stack, DHCP will not be used
+    /**
+    IpAddr is a container class that can be constructed with either 4 bytes or no parameters for a null IP address.
+    */
+    W5200NetIf(IpAddr ip, IpAddr netmask, IpAddr gateway, IpAddr dns); //W/o DHCP
+    W5200Err IPrenew(int timeout_ms = 15000);
+    W5200Err IPrelease(int timeout_ms = 15000);
+    ///Brings the interface up
+    /**
+    Uses DHCP if necessary
+    @param timeout_ms : You can set the timeout parameter in milliseconds, if not it defaults to 15s
+    @return : W5200_OK on success or W5200_TIMEOUT on timeout
+    */
+    W5200Err setup(int timeout_ms = 15000);
+    SPI* attachSPI(SPI* spi);
+    DigitalOut* attachCS(DigitalOut* cs);
+    IpAddr m_dns;
+private:
+    bool m_useDhcp;
+    IpAddr m_netmask;
+    IpAddr m_gateway;
+    const char* m_hostname;
+};
+#endif //W5200_NETIF_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WIZ820ioNetIf.cpp	Fri Mar 22 11:51:24 2013 +0000
@@ -0,0 +1,49 @@
+// WIZ820ioNetIf.cpp 2012/4/22
+#include "WIZ820ioNetIf.h"
+#include "w5100.h"
+
+DigitalOut* pRESET = NULL;
+
+void hardware_reset() {
+  if (!pRESET) {
+    pRESET = new DigitalOut(p15);
+  }
+  if (pRESET) {
+    pRESET->write(1);
+    pRESET->write(0);
+    wait_us(2);
+    pRESET->write(1);
+    wait_ms(150);
+  }
+}
+
+bool wait_linkup(int timeout = 5000) {
+    Timer link_t;
+    link_t.start();
+    while(link_t.read_ms() < timeout) {
+        if (0x20 & W5100.readPHYSTATUS()) {
+            return true;
+        }
+         wait_ms(50);
+    }  
+    return false;
+}
+
+void WIZ820ioNetIf::reset(PinName _reset) {
+    pRESET = new DigitalOut(_reset);
+}
+    
+int WIZ820ioNetIf::setup(int timeout_ms) {
+    hardware_reset();
+    if (!attachSPI(NULL)) {
+        SPI* spi = new SPI(p11, p12, p13); // mosi, miso, sclk
+        attachSPI(spi);
+    }
+    if (!attachCS(NULL)) {
+        DigitalOut* cs = new DigitalOut(p14);
+        attachCS(cs);
+    }
+    W5100.init();
+    wait_linkup();
+    return W5200NetIf::setup(timeout_ms);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WIZ820ioNetIf.h	Fri Mar 22 11:51:24 2013 +0000
@@ -0,0 +1,22 @@
+// WIZ820ioNetIf.h 2012/4/23
+
+/** \file
+WIZ820io network interface header file
+*/
+#ifndef WIZ820IO_NETIF_H
+#define WIZ820IO_NETIF_H
+#include "W5200NetIf.h"
+
+///WIZ820io network interface
+class WIZ820ioNetIf : public W5200NetIf {
+public:
+    void reset(PinName _reset);
+    ///Brings the interface up
+    /**
+    Uses DHCP if necessary
+    @param timeout_ms : You can set the timeout parameter in milliseconds, if not it defaults to 15s
+    @return : 0 on success or -1 on timeout
+    */    
+    int setup(int timeout_ms = 15000);
+};
+#endif //WIZ820IO_NETIF_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dnsname.h	Fri Mar 22 11:51:24 2013 +0000
@@ -0,0 +1,51 @@
+// dnsname.h 2012/4/13
+#ifndef DNSNAME_H
+#define DNSNAME_H
+class dnsname {
+public:
+    uint8_t *buf;
+    string str;
+    dnsname(uint8_t *s) {
+        buf = s;
+    }
+    int decode(int pos) {
+        while(1) {
+            int len = buf[pos++];
+            if (len == 0x00) {
+                break;
+            }
+            if ((len&0xc0) == 0xc0) { //compress
+                int offset = (len&0x3f)<<8|buf[pos];
+                decode(offset);
+                return pos+1;
+            }
+            if (!str.empty()) {
+                str.append(".");
+            }
+            str.append((const char*)(buf+pos), len);
+            pos += len;
+        }
+        return pos;
+    }
+
+    int encode(int pos, char* s) {
+        while(*s) {  
+            char *f = strchr(s, '.');
+            if (f == NULL) {
+                int len = strlen(s);
+                buf[pos++] = len;
+                memcpy(buf+pos, s, len);
+                pos += len;
+                break;
+            }
+            int len = f - s;
+            buf[pos++] = len;
+            memcpy(buf+pos, s, len);
+            s = f+1;
+            pos += len;
+        }
+        buf[pos++] = 0x00;
+        return pos;
+    }
+};
+#endif //DNSNAME_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/w5100.cpp	Fri Mar 22 11:51:24 2013 +0000
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "mbed.h"
+#include "w5100.h"
+#ifndef MBED
+#include <avr/interrupt.h>
+#endif //MBED
+
+// W5100 controller instance
+W5100Class W5100;
+
+#define TX_RX_MAX_BUF_SIZE 2048
+#define TX_BUF 0x1100
+#define RX_BUF (TX_BUF + TX_RX_MAX_BUF_SIZE)
+
+#ifdef W5200
+#define TXBUF_BASE 0x8000
+#define RXBUF_BASE 0xC000
+#else
+#define TXBUF_BASE 0x4000
+#define RXBUF_BASE 0x6000
+#endif
+
+#ifdef MBED
+
+SPI* pSPI = NULL;
+DigitalOut* pCS = NULL;
+
+inline void delay(int n) { wait_ms(n); }
+inline static void initSS(){ pCS->write(1); }
+inline static void setSS() { pCS->write(0); }
+inline static void resetSS() { pCS->write(1); }
+
+#endif //MBED
+
+void W5100Class::init(void)
+{
+  if (!pSPI) {
+    pSPI = new SPI(p11, p12, p13); // mosi, miso, sclk
+  }
+  if (!pCS) {
+    pCS = new DigitalOut(p14);
+  }
+  initSS();
+  writeMR(1<<RST);
+  
+#ifdef W5200
+  for (int i=0; i<MAX_SOCK_NUM; i++) {
+    write((0x4000 + i * 0x100 + 0x001F), 2);
+    write((0x4000 + i * 0x100 + 0x001E), 2);
+  }
+#else  
+  writeTMSR(0x55);
+  writeRMSR(0x55);
+#endif
+
+  for (int i=0; i<MAX_SOCK_NUM; i++) {
+    SBASE[i] = TXBUF_BASE + SSIZE * i;
+    RBASE[i] = RXBUF_BASE + RSIZE * i;
+  }
+}
+
+uint16_t W5100Class::getTXFreeSize(SOCKET s)
+{
+  uint16_t val=0, val1=0;
+  do {
+    val1 = readSnTX_FSR(s);
+    if (val1 != 0)
+      val = readSnTX_FSR(s);
+  } 
+  while (val != val1);
+  return val;
+}
+
+uint16_t W5100Class::getRXReceivedSize(SOCKET s)
+{
+  uint16_t val=0,val1=0;
+  do {
+    val1 = readSnRX_RSR(s);
+    if (val1 != 0)
+      val = readSnRX_RSR(s);
+  } 
+  while (val != val1);
+  return val;
+}
+
+
+void W5100Class::send_data_processing(SOCKET s, const uint8_t *data, uint16_t len)
+{
+  // This is same as having no offset in a call to send_data_processing_offset
+  send_data_processing_offset(s, 0, data, len);
+}
+
+void W5100Class::send_data_processing_offset(SOCKET s, uint16_t data_offset, const uint8_t *data, uint16_t len)
+{
+  uint16_t ptr = readSnTX_WR(s);
+  ptr += data_offset;
+  uint16_t offset = ptr & SMASK;
+  uint16_t dstAddr = offset + SBASE[s];
+
+  if (offset + len > SSIZE) 
+  {
+    // Wrap around circular buffer
+    uint16_t size = SSIZE - offset;
+    write(dstAddr, data, size);
+    write(SBASE[s], data + size, len - size);
+  } 
+  else {
+    write(dstAddr, data, len);
+  }
+
+  ptr += len;
+  writeSnTX_WR(s, ptr);
+}
+
+
+void W5100Class::recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek)
+{
+  uint16_t ptr;
+  ptr = readSnRX_RD(s);
+  read_data(s, (uint8_t *)ptr, data, len);
+  if (!peek)
+  {
+    ptr += len;
+    writeSnRX_RD(s, ptr);
+  }
+}
+
+void W5100Class::read_data(SOCKET s, volatile uint8_t *src, volatile uint8_t *dst, uint16_t len)
+{
+  uint16_t size;
+  uint16_t src_mask;
+  uint16_t src_ptr;
+
+#ifdef MBED
+  src_mask = (int)src & RMASK;
+#else 
+  src_mask = (uint16_t)src & RMASK;
+#endif //MBED
+  src_ptr = RBASE[s] + src_mask;
+
+  if( (src_mask + len) > RSIZE ) 
+  {
+    size = RSIZE - src_mask;
+    read(src_ptr, (uint8_t *)dst, size);
+    dst += size;
+    read(RBASE[s], (uint8_t *) dst, len - size);
+  } 
+  else
+    read(src_ptr, (uint8_t *) dst, len);
+}
+
+
+uint8_t W5100Class::write(uint16_t _addr, uint8_t _data)
+{
+  setSS();  
+  
+#ifdef W5200
+  pSPI->write(_addr >> 8);
+  pSPI->write(_addr & 0xFF);
+  pSPI->write(0x80);
+  pSPI->write(0x01);
+#else    
+  pSPI->write(0xF0);
+  pSPI->write(_addr >> 8);
+  pSPI->write(_addr & 0xFF);
+#endif  
+  pSPI->write(_data);
+  resetSS();
+  return 1;
+}
+
+uint16_t W5100Class::write(uint16_t _addr, const uint8_t *_buf, uint16_t _len)
+{
+    
+#ifdef W5200
+    setSS();
+    pSPI->write(_addr >> 8);
+    pSPI->write(_addr & 0xFF);
+    pSPI->write((0x80 | ((_len & 0x7F00) >> 8)));
+    pSPI->write(_len & 0x00FF);
+
+  for (uint16_t i=0; i<_len; i++)
+  {
+    pSPI->write(_buf[i]);
+
+  }
+    resetSS();
+#else    
+    
+  for (uint16_t i=0; i<_len; i++)
+  {
+    setSS();    
+    pSPI->write(0xF0);
+    pSPI->write(_addr >> 8);
+    pSPI->write(_addr & 0xFF);
+    _addr++;
+    pSPI->write(_buf[i]);
+    resetSS();
+  }
+#endif
+  
+  return _len;
+}
+
+uint8_t W5100Class::read(uint16_t _addr)
+{
+  setSS();  
+#ifdef W5200
+  pSPI->write(_addr >> 8);
+  pSPI->write(_addr & 0xFF);
+  pSPI->write(0x00);
+  pSPI->write(0x01);
+#else
+  pSPI->write(0x0F);
+  pSPI->write(_addr >> 8);
+  pSPI->write(_addr & 0xFF);
+#endif
+  
+  uint8_t _data = pSPI->write(0);
+  resetSS();
+  return _data;
+}
+
+uint16_t W5100Class::read(uint16_t _addr, uint8_t *_buf, uint16_t _len)
+{
+#ifdef W5200
+    setSS();
+    pSPI->write(_addr >> 8);
+    pSPI->write(_addr & 0xFF);
+    pSPI->write((0x00 | ((_len & 0x7F00) >> 8)));
+    pSPI->write(_len & 0x00FF);
+
+  for (uint16_t i=0; i<_len; i++)
+  {
+    _buf[i] = pSPI->write(0);
+
+  }
+    resetSS();
+
+#else    
+    
+  for (uint16_t i=0; i<_len; i++)
+  {
+    setSS();
+    pSPI->write(0x0F);
+    pSPI->write(_addr >> 8);
+    pSPI->write(_addr & 0xFF);
+    _addr++;
+    _buf[i] = pSPI->write(0);
+    resetSS();
+  }
+#endif  
+  return _len;
+}
+
+void W5100Class::execCmdSn(SOCKET s, SockCMD _cmd) {
+  // Send command to socket
+  writeSnCR(s, _cmd);
+  // Wait for command to complete
+  while (readSnCR(s))
+    ;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/w5100.h	Fri Mar 22 11:51:24 2013 +0000
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef    W5100_H_INCLUDED
+#define    W5100_H_INCLUDED
+#define MBED
+#ifdef MBED
+#include "mbed.h"
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+#else //MBED
+#include <avr/pgmspace.h>
+#include <SPI.h>
+#endif //MBED
+#define W5200
+
+#ifdef W5200
+#define MAX_SOCK_NUM 8
+#else
+#define MAX_SOCK_NUM 4
+#endif
+
+
+typedef uint8_t SOCKET;
+
+#ifndef W5200
+#define IDM_OR  0x8000
+#define IDM_AR0 0x8001
+#define IDM_AR1 0x8002
+#define IDM_DR  0x8003
+#endif
+
+/*
+class MR {
+public:
+  static const uint8_t RST   = 0x80;
+  static const uint8_t PB    = 0x10;
+  static const uint8_t PPPOE = 0x08;
+  static const uint8_t LB    = 0x04;
+  static const uint8_t AI    = 0x02;
+  static const uint8_t IND   = 0x01;
+};
+*/
+/*
+class IR {
+public:
+  static const uint8_t CONFLICT = 0x80;
+  static const uint8_t UNREACH  = 0x40;
+  static const uint8_t PPPoE    = 0x20;
+  static const uint8_t SOCK0    = 0x01;
+  static const uint8_t SOCK1    = 0x02;
+  static const uint8_t SOCK2    = 0x04;
+  static const uint8_t SOCK3    = 0x08;
+  static inline uint8_t SOCK(SOCKET ch) { return (0x01 << ch); };
+};
+*/
+
+class SnMR {
+public:
+  static const uint8_t CLOSE  = 0x00;
+  static const uint8_t TCP    = 0x01;
+  static const uint8_t UDP    = 0x02;
+  static const uint8_t IPRAW  = 0x03;
+  static const uint8_t MACRAW = 0x04;
+  static const uint8_t PPPOE  = 0x05;
+  static const uint8_t ND     = 0x20;
+  static const uint8_t MULTI  = 0x80;
+};
+
+enum SockCMD {
+  Sock_OPEN      = 0x01,
+  Sock_LISTEN    = 0x02,
+  Sock_CONNECT   = 0x04,
+  Sock_DISCON    = 0x08,
+  Sock_CLOSE     = 0x10,
+  Sock_SEND      = 0x20,
+  Sock_SEND_MAC  = 0x21,
+  Sock_SEND_KEEP = 0x22,
+  Sock_RECV      = 0x40
+};
+
+/*class SnCmd {
+public:
+  static const uint8_t OPEN      = 0x01;
+  static const uint8_t LISTEN    = 0x02;
+  static const uint8_t CONNECT   = 0x04;
+  static const uint8_t DISCON    = 0x08;
+  static const uint8_t CLOSE     = 0x10;
+  static const uint8_t SEND      = 0x20;
+  static const uint8_t SEND_MAC  = 0x21;
+  static const uint8_t SEND_KEEP = 0x22;
+  static const uint8_t RECV      = 0x40;
+};
+*/
+
+class SnIR {
+public:
+  static const uint8_t SEND_OK = 0x10;
+  static const uint8_t TIMEOUT = 0x08;
+  static const uint8_t RECV    = 0x04;
+  static const uint8_t DISCON  = 0x02;
+  static const uint8_t CON     = 0x01;
+};
+
+class SnSR {
+public:
+  static const uint8_t CLOSED      = 0x00;
+  static const uint8_t INIT        = 0x13;
+  static const uint8_t LISTEN      = 0x14;
+  static const uint8_t SYNSENT     = 0x15;
+  static const uint8_t SYNRECV     = 0x16;
+  static const uint8_t ESTABLISHED = 0x17;
+  static const uint8_t FIN_WAIT    = 0x18;
+  static const uint8_t CLOSING     = 0x1A;
+  static const uint8_t TIME_WAIT   = 0x1B;
+  static const uint8_t CLOSE_WAIT  = 0x1C;
+  static const uint8_t LAST_ACK    = 0x1D;
+  static const uint8_t UDP         = 0x22;
+  static const uint8_t IPRAW       = 0x32;
+  static const uint8_t MACRAW      = 0x42;
+  static const uint8_t PPPOE       = 0x5F;
+};
+
+class IPPROTO {
+public:
+  static const uint8_t IP   = 0;
+  static const uint8_t ICMP = 1;
+  static const uint8_t IGMP = 2;
+  static const uint8_t GGP  = 3;
+  static const uint8_t TCP  = 6;
+  static const uint8_t PUP  = 12;
+  static const uint8_t UDP  = 17;
+  static const uint8_t IDP  = 22;
+  static const uint8_t ND   = 77;
+  static const uint8_t RAW  = 255;
+};
+
+class W5100Class {
+public:
+  void init();
+
+  /**
+   * @brief    This function is being used for copy the data form Receive buffer of the chip to application buffer.
+   * 
+   * It calculate the actual physical address where one has to read
+   * the data from Receive buffer. Here also take care of the condition while it exceed
+   * the Rx memory uper-bound of socket.
+   */
+  void read_data(SOCKET s, volatile uint8_t * src, volatile uint8_t * dst, uint16_t len);
+  
+  /**
+   * @brief     This function is being called by send() and sendto() function also. 
+   * 
+   * This function read the Tx write pointer register and after copy the data in buffer update the Tx write pointer
+   * register. User should read upper byte first and lower byte later to get proper value.
+   */
+  void send_data_processing(SOCKET s, const uint8_t *data, uint16_t len);
+  /**
+   * @brief A copy of send_data_processing that uses the provided ptr for the
+   *        write offset.  Only needed for the "streaming" UDP API, where
+   *        a single UDP packet is built up over a number of calls to
+   *        send_data_processing_ptr, because TX_WR doesn't seem to get updated
+   *        correctly in those scenarios
+   * @param ptr value to use in place of TX_WR.  If 0, then the value is read
+   *        in from TX_WR
+   * @return New value for ptr, to be used in the next call
+   */
+// FIXME Update documentation
+  void send_data_processing_offset(SOCKET s, uint16_t data_offset, const uint8_t *data, uint16_t len);
+
+  /**
+   * @brief    This function is being called by recv() also.
+   * 
+   * This function read the Rx read pointer register
+   * and after copy the data from receive buffer update the Rx write pointer register.
+   * User should read upper byte first and lower byte later to get proper value.
+   */
+  void recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek = 0);
+
+  inline void setGatewayIp(uint8_t *_addr);
+  inline void getGatewayIp(uint8_t *_addr);
+
+  inline void setSubnetMask(uint8_t *_addr);
+  inline void getSubnetMask(uint8_t *_addr);
+
+  inline void setMACAddress(uint8_t * addr);
+  inline void getMACAddress(uint8_t * addr);
+
+  inline void setIPAddress(uint8_t * addr);
+  inline void getIPAddress(uint8_t * addr);
+
+  inline void setRetransmissionTime(uint16_t timeout);
+  inline void setRetransmissionCount(uint8_t _retry);
+
+  void execCmdSn(SOCKET s, SockCMD _cmd);
+  
+  uint16_t getTXFreeSize(SOCKET s);
+  uint16_t getRXReceivedSize(SOCKET s);
+  
+
+  // W5100 Registers
+  // ---------------
+private:
+  static uint8_t write(uint16_t _addr, uint8_t _data);
+  static uint16_t write(uint16_t addr, const uint8_t *buf, uint16_t len);
+  static uint8_t read(uint16_t addr);
+  static uint16_t read(uint16_t addr, uint8_t *buf, uint16_t len);
+  
+#define __GP_REGISTER8(name, address)             \
+  static inline void write##name(uint8_t _data) { \
+    write(address, _data);                        \
+  }                                               \
+  static inline uint8_t read##name() {            \
+    return read(address);                         \
+  }
+#define __GP_REGISTER16(name, address)            \
+  static void write##name(uint16_t _data) {       \
+    write(address,   _data >> 8);                 \
+    write(address+1, _data & 0xFF);               \
+  }                                               \
+  static uint16_t read##name() {                  \
+    uint16_t res = read(address);                 \
+    res = (res << 8) + read(address + 1);         \
+    return res;                                   \
+  }
+#define __GP_REGISTER_N(name, address, size)      \
+  static uint16_t write##name(uint8_t *_buff) {   \
+    return write(address, _buff, size);           \
+  }                                               \
+  static uint16_t read##name(uint8_t *_buff) {    \
+    return read(address, _buff, size);            \
+  }
+
+public:
+  __GP_REGISTER8 (MR,     0x0000);    // Mode
+  __GP_REGISTER_N(GAR,    0x0001, 4); // Gateway IP address
+  __GP_REGISTER_N(SUBR,   0x0005, 4); // Subnet mask address
+  __GP_REGISTER_N(SHAR,   0x0009, 6); // Source MAC address
+  __GP_REGISTER_N(SIPR,   0x000F, 4); // Source IP address
+  __GP_REGISTER8 (IR,     0x0015);    // Interrupt
+  __GP_REGISTER8 (IMR,    0x0016);    // Interrupt Mask
+  __GP_REGISTER16(RTR,    0x0017);    // Timeout address
+  __GP_REGISTER8 (RCR,    0x0019);    // Retry count
+  
+  #ifndef W5200
+  __GP_REGISTER8 (RMSR,   0x001A);    // Receive memory size
+  __GP_REGISTER8 (TMSR,   0x001B);    // Transmit memory size
+  #endif
+  __GP_REGISTER8 (PATR,   0x001C);    // Authentication type address in PPPoE mode
+  
+  __GP_REGISTER8 (VERSIONR,0x001f);   // Chip version
+  
+  __GP_REGISTER8 (PTIMER, 0x0028);    // PPP LCP Request Timer
+  __GP_REGISTER8 (PMAGIC, 0x0029);    // PPP LCP Magic Number
+  #ifndef W5200
+  __GP_REGISTER_N(UIPR,   0x002A, 4); // Unreachable IP address in UDP mode
+  __GP_REGISTER16(UPORT,  0x002E);    // Unreachable Port address in UDP mode
+#endif
+  __GP_REGISTER8 (PHYSTATUS,0x0035);  // PHY Status
+  
+#undef __GP_REGISTER8
+#undef __GP_REGISTER16
+#undef __GP_REGISTER_N
+
+  // W5100 Socket registers
+  // ----------------------
+private:
+  static inline uint8_t readSn(SOCKET _s, uint16_t _addr);
+  static inline uint8_t writeSn(SOCKET _s, uint16_t _addr, uint8_t _data);
+  static inline uint16_t readSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len);
+  static inline uint16_t writeSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len);
+
+#ifdef W5200
+  static const uint16_t CH_BASE = 0x4000;
+#else
+  static const uint16_t CH_BASE = 0x0400;
+#endif  
+
+  static const uint16_t CH_SIZE = 0x0100;
+
+#define __SOCKET_REGISTER8(name, address)                    \
+  static inline void write##name(SOCKET _s, uint8_t _data) { \
+    writeSn(_s, address, _data);                             \
+  }                                                          \
+  static inline uint8_t read##name(SOCKET _s) {              \
+    return readSn(_s, address);                              \
+  }
+#define __SOCKET_REGISTER16(name, address)                   \
+  static void write##name(SOCKET _s, uint16_t _data) {       \
+    writeSn(_s, address,   _data >> 8);                      \
+    writeSn(_s, address+1, _data & 0xFF);                    \
+  }                                                          \
+  static uint16_t read##name(SOCKET _s) {                    \
+    uint16_t res = readSn(_s, address);                      \
+    res = (res << 8) + readSn(_s, address + 1);              \
+    return res;                                              \
+  }
+#define __SOCKET_REGISTER_N(name, address, size)             \
+  static uint16_t write##name(SOCKET _s, uint8_t *_buff) {   \
+    return writeSn(_s, address, _buff, size);                \
+  }                                                          \
+  static uint16_t read##name(SOCKET _s, uint8_t *_buff) {    \
+    return readSn(_s, address, _buff, size);                 \
+  }
+  
+public:
+  __SOCKET_REGISTER8(SnMR,        0x0000)        // Mode
+  __SOCKET_REGISTER8(SnCR,        0x0001)        // Command
+  __SOCKET_REGISTER8(SnIR,        0x0002)        // Interrupt
+  __SOCKET_REGISTER8(SnSR,        0x0003)        // Status
+  __SOCKET_REGISTER16(SnPORT,     0x0004)        // Source Port
+  __SOCKET_REGISTER_N(SnDHAR,     0x0006, 6)     // Destination Hardw Addr
+  __SOCKET_REGISTER_N(SnDIPR,     0x000C, 4)     // Destination IP Addr
+  __SOCKET_REGISTER16(SnDPORT,    0x0010)        // Destination Port
+  __SOCKET_REGISTER16(SnMSSR,     0x0012)        // Max Segment Size
+  __SOCKET_REGISTER8(SnPROTO,     0x0014)        // Protocol in IP RAW Mode
+  __SOCKET_REGISTER8(SnTOS,       0x0015)        // IP TOS
+  __SOCKET_REGISTER8(SnTTL,       0x0016)        // IP TTL
+  __SOCKET_REGISTER16(SnTX_FSR,   0x0020)        // TX Free Size
+  __SOCKET_REGISTER16(SnTX_RD,    0x0022)        // TX Read Pointer
+  __SOCKET_REGISTER16(SnTX_WR,    0x0024)        // TX Write Pointer
+  __SOCKET_REGISTER16(SnRX_RSR,   0x0026)        // RX Free Size
+  __SOCKET_REGISTER16(SnRX_RD,    0x0028)        // RX Read Pointer
+  __SOCKET_REGISTER16(SnRX_WR,    0x002A)        // RX Write Pointer (supported?)
+  
+#undef __SOCKET_REGISTER8
+#undef __SOCKET_REGISTER16
+#undef __SOCKET_REGISTER_N
+
+
+private:
+  static const uint8_t  RST = 7; // Reset BIT
+
+#ifdef W5200
+  static const int SOCKETS = 8;
+#else
+  static const int SOCKETS = 4;
+#endif
+
+  static const uint16_t SMASK = 0x07FF; // Tx buffer MASK
+  static const uint16_t RMASK = 0x07FF; // Rx buffer MASK
+public:
+  static const uint16_t SSIZE = 2048; // Max Tx buffer size
+private:
+  static const uint16_t RSIZE = 2048; // Max Rx buffer size
+  uint16_t SBASE[SOCKETS]; // Tx buffer base address
+  uint16_t RBASE[SOCKETS]; // Rx buffer base address
+
+private:
+#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
+  inline static void initSS()    { DDRB  |=  _BV(4); };
+  inline static void setSS()     { PORTB &= ~_BV(4); };
+  inline static void resetSS()   { PORTB |=  _BV(4); };
+#elif defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB162__)
+  inline static void initSS()    { DDRB  |=  _BV(0); };
+  inline static void setSS()     { PORTB &= ~_BV(0); };
+  inline static void resetSS()   { PORTB |=  _BV(0); }; 
+#else
+#ifndef MBED
+  inline static void initSS()    { DDRB  |=  _BV(2); };
+  inline static void setSS()     { PORTB &= ~_BV(2); };
+  inline static void resetSS()   { PORTB |=  _BV(2); };
+#endif //MBED
+#endif
+
+};
+
+extern W5100Class W5100;
+
+uint8_t W5100Class::readSn(SOCKET _s, uint16_t _addr) {
+  return read(CH_BASE + _s * CH_SIZE + _addr);
+}
+
+uint8_t W5100Class::writeSn(SOCKET _s, uint16_t _addr, uint8_t _data) {
+  return write(CH_BASE + _s * CH_SIZE + _addr, _data);
+}
+
+uint16_t W5100Class::readSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t _len) {
+  return read(CH_BASE + _s * CH_SIZE + _addr, _buf, _len);
+}
+
+uint16_t W5100Class::writeSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t _len) {
+  return write(CH_BASE + _s * CH_SIZE + _addr, _buf, _len);
+}
+
+void W5100Class::getGatewayIp(uint8_t *_addr) {
+  readGAR(_addr);
+}
+
+void W5100Class::setGatewayIp(uint8_t *_addr) {
+  writeGAR(_addr);
+}
+
+void W5100Class::getSubnetMask(uint8_t *_addr) {
+  readSUBR(_addr);
+}
+
+void W5100Class::setSubnetMask(uint8_t *_addr) {
+  writeSUBR(_addr);
+}
+
+void W5100Class::getMACAddress(uint8_t *_addr) {
+  readSHAR(_addr);
+}
+
+void W5100Class::setMACAddress(uint8_t *_addr) {
+  writeSHAR(_addr);
+}
+
+void W5100Class::getIPAddress(uint8_t *_addr) {
+  readSIPR(_addr);
+}
+
+void W5100Class::setIPAddress(uint8_t *_addr) {
+  writeSIPR(_addr);
+}
+
+void W5100Class::setRetransmissionTime(uint16_t _timeout) {
+  writeRTR(_timeout);
+}
+
+void W5100Class::setRetransmissionCount(uint8_t _retry) {
+  writeRCR(_retry);
+}
+
+#endif