DHCP Client for WIZ820io(W5200)

Dependencies:   EthernetNetIf mbed

Files at this revision

API Documentation at this revision

Comitter:
va009039
Date:
Tue Apr 10 03:38:22 2012 +0000
Commit message:

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
EthernetNetIf.lib Show annotated file Show diff for this revision Revisions of this file
MyEthernetNetIf.cpp Show annotated file Show diff for this revision Revisions of this file
MyEthernetNetIf.h Show annotated file Show diff for this revision Revisions of this file
MyUDPSocket.h 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.bld 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	Tue Apr 10 03:38:22 2012 +0000
@@ -0,0 +1,100 @@
+// DHCPClient.cpp 2012/4/10
+// DHCP Client for WIZ820io(W5200)
+#include "mbed.h"
+#include "MyEthernetNetIf.h"
+#include "MyUDPSocket.h"
+#include "DHCPClient.h"
+#ifdef DEBUG
+#include "Utils.h"
+#endif //DEBUG
+
+static DHCPClient* _g_dhcp;
+static void _DHCP_OnEvent(UDPSocketEvent e)
+{
+    _g_dhcp->callback(e);
+}
+
+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 DHCP_VERBOSE           
+        char codeStr[24];
+        snprintf(codeStr, sizeof(codeStr), "DHCP option: %d", code);
+        printfBytes(codeStr, p, len);
+#endif //DHCP_VERBOSE
+        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;
+}
+
+void DHCPClient::callback(UDPSocketEvent e)
+{
+    PRINT_FUNC();
+    uint8_t buf[DHCP_MAX_PACKET_SIZE];
+    Host host;
+    int len = p_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
+        p_udp->sendto((char*)buf, 300, &server);
+    } else if (r == 5) { // ACK
+        exit_flag = true;
+    }
+}
+
+int DHCPClient::setup(int timeout_ms)
+{
+    Timer t;
+    t.start();
+    p_udp = new MyUDPSocket;
+    p_udp->setOnEvent(_DHCP_OnEvent);
+    Host local(IpAddr(0,0,0,0), 68);
+    Host server(IpAddr(255,255,255,255), 67); // DHCP broadcast
+    p_udp->bind(local);
+    uint8_t buf[300];
+    discover(buf, sizeof(buf));
+    p_udp->sendto((char*)buf, sizeof(buf), &server);
+    exit_flag = false;
+    int err = 0;
+    while(1) {
+        p_udp->poll();
+        if (exit_flag) {
+            break;
+        }
+        if (t.read_ms() > timeout_ms) {
+            err = -1;
+            break;
+        }
+#ifdef DEBUG            
+        wait_ms(100);
+#endif //DEBUG
+    }
+    delete p_udp;
+    return err;
+}
+
+DHCPClient::DHCPClient()
+{
+    _g_dhcp = this;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DHCPClient.h	Tue Apr 10 03:38:22 2012 +0000
@@ -0,0 +1,86 @@
+// DHCPClient.h 2012/4/10
+#ifndef DHCPCLIENT_H
+#define DHCPCLIENT_H
+#include "UDPSocket.h"
+
+//#define DHCP_VERBOSE
+
+#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
+
+extern void _DHCP_OnEvent(UDPSocketEvent e); // DHCPClient.cpp
+
+class DHCPClient {
+    int 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));
+        //printHex((u8*)buf, 236);
+        uint8_t ip[4] = {0,0,0,0};
+        W5100.setIPAddress(ip);
+        return DHCP_OFFSET_MAGIC_COOKIE + sizeof(options);
+    }
+    
+    int 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 offer_ack(uint8_t buf[], int size);
+
+    bool 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;
+    }
+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:
+    MyUDPSocket* p_udp;
+    uint8_t xid[4];
+    bool exit_flag;
+};
+#endif //DHCPCLIENT_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EthernetNetIf.lib	Tue Apr 10 03:38:22 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/donatien/code/EthernetNetIf/#bc7df6da7589
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyEthernetNetIf.cpp	Tue Apr 10 03:38:22 2012 +0000
@@ -0,0 +1,84 @@
+// MyEthernetNetIf.h 2012/4/10
+// EthernetNetIf for WIZ820io(W5200)
+#include "mbed.h"
+#include "MyEthernetNetIf.h"
+#include "DHCPClient.h"
+#include "w5100.h"
+
+extern W5100Class W5100; // w5100.cpp
+
+bool wait_linkup(int timeout = 3000) {
+    Timer link_t;
+    link_t.start();
+    while(link_t.read_ms() < timeout) {
+        if (0x20 & W5100.readPHYSTATUS()) {
+            return true;
+        }
+         wait_ms(50);
+    }  
+    return false;
+}
+
+void MyEthernetNetIf::hardware_setup(){
+    W5100.hardware_reset();
+    W5100.init();
+    wait_linkup();
+}
+
+MyEthernetNetIf::MyEthernetNetIf(IpAddr ip, IpAddr netmask, IpAddr gateway, IpAddr dns) {
+    m_ip = ip;
+    m_netmask = netmask;
+    m_gateway = gateway;
+    m_dns = dns;
+    m_useDhcp = false;
+}
+
+MyEthernetNetIf:: MyEthernetNetIf() {
+    m_useDhcp = true;
+}
+
+EthernetErr MyEthernetNetIf::setup(int timeout_ms)
+{
+    hardware_setup();
+    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]);
+    uint8_t u[4];
+    u[0] = m_ip[0];
+    u[1] = m_ip[1];
+    u[2] = m_ip[2];
+    u[3] = m_ip[3];
+    W5100.setIPAddress(u);
+    u[0] = m_netmask[0];
+    u[1] = m_netmask[1];
+    u[2] = m_netmask[2];
+    u[3] = m_netmask[3];
+    W5100.setSubnetMask(u);
+    u[0] = m_gateway[0];
+    u[1] = m_gateway[1];
+    u[2] = m_gateway[2];
+    u[3] = m_gateway[3];
+    W5100.setGatewayIp(u);
+    if (! m_useDhcp) {
+        return ETH_OK;
+    }
+    printf("DHCP Started, waiting for IP...\n");  
+    DHCPClient* dhcp;
+    EthernetErr err;
+    dhcp = new DHCPClient;
+    int r = dhcp->setup(timeout_ms);
+    if (r == (-1)) {
+        printf("Timeout.\n");
+        err = ETH_TIMEOUT;  
+    } else {
+        W5100.writeSIPR(dhcp->yiaddr);
+        W5100.writeSUBR(dhcp->netmask);
+        W5100.writeGAR(dhcp->gateway);
+        m_ip = IpAddr(dhcp->yiaddr[0],dhcp->yiaddr[1],dhcp->yiaddr[2],dhcp->yiaddr[3]);
+        m_dns = IpAddr(dhcp->dnsaddr[0],dhcp->dnsaddr[1],dhcp->dnsaddr[2],dhcp->dnsaddr[3]);
+        printf("Connected, IP: %d.%d.%d.%d\n", dhcp->yiaddr[0], dhcp->yiaddr[1], dhcp->yiaddr[2], dhcp->yiaddr[3]);
+        err = ETH_OK;
+    }
+    delete dhcp;
+    return err;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyEthernetNetIf.h	Tue Apr 10 03:38:22 2012 +0000
@@ -0,0 +1,24 @@
+// MyEthernetNetIf.h 2012/4/10
+#ifndef MYETHERNETNETIF_H
+#define MYETHERNETNETIF_H
+#include "w5100.h"
+#include "EthernetNetIf.h"
+#include "MyUDPSocket.h"
+
+class MyEthernetNetIf {
+    void hardware_setup();
+public:
+    MyEthernetNetIf(IpAddr ip, IpAddr netmask, IpAddr gateway, IpAddr dns);
+    MyEthernetNetIf();
+    IpAddr getDns() { return m_dns; }
+    EthernetErr setup(int timeout_ms = 15000);
+    IpAddr getIp() {return m_ip; } ;
+    IpAddr getDNS() {return m_dns; };
+private:
+    IpAddr m_ip;
+    IpAddr m_netmask;
+    IpAddr m_gateway;
+    IpAddr m_dns;
+    bool m_useDhcp;
+};
+#endif // MYETHERNETNETIF_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MyUDPSocket.h	Tue Apr 10 03:38:22 2012 +0000
@@ -0,0 +1,125 @@
+#ifndef MYUDPSOCKET_H
+#define MYUDPSOCKET_H
+#include "UDPSocket.h"
+
+#ifdef DEBUG
+#define PRINT_FUNC() printf("%d:%s\n", __LINE__,__PRETTY_FUNCTION__)
+#else //DEBUG
+#define PRINT_FUNC()
+#endif //DEBUG
+
+class MyUDPSocket {
+    int _socket;
+    void (*m_pCb)(UDPSocketEvent);
+public:
+    MyUDPSocket() {
+        _socket = 7;
+        W5100.writeSnMR(_socket, SnMR::UDP); // set UDP mode
+    }
+
+    UDPSocketErr bind(const Host& me) {
+        if (! me.getIp().isNull()) {
+            uint8_t ip[4];
+            ip[0] = me.getIp()[0];
+            ip[1] = me.getIp()[1];
+            ip[2] = me.getIp()[2];
+            ip[3] = me.getIp()[3];
+            W5100.setIPAddress(ip);
+        }
+        int port = me.getPort();
+        if (port) {
+            W5100.writeSnPORT(_socket, port);
+        }
+        W5100.execCmdSn( _socket, Sock_OPEN); // set OPEN command
+        return UDPSOCKET_OK;
+    }
+
+    int /*if < 0 : UDPSocketErr*/ sendto(const char* buf, int len, Host* pHost) {
+#ifdef DEBUG
+        PRINT_FUNC();
+        printHex((u8*)buf, len);
+#endif //DEBUG
+        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
+        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 : UDPSocketErr*/ recvfrom(char* buf, int len, Host* pHost) {
+        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;
+    }
+    
+    UDPSocketErr close()
+    {
+        W5100.execCmdSn(_socket, Sock_CLOSE);
+        return UDPSOCKET_OK;
+    }
+    
+    void setOnEvent(void (*pMethod)(UDPSocketEvent))
+    {
+        m_pCb = pMethod;
+    }
+    
+    void resetOnEvent() {
+        m_pCb = NULL;
+    }
+    
+    void poll()
+    {
+        PRINT_FUNC();
+#ifdef DEBUG
+        printf("socket:%d SnMR:%02x SnIR:%02x SnSR:%02x\n", _socket, 
+            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:%d, Sn_RX_RD:%d, Sn_RX_WR:%d\n",
+                    W5100.readSnRX_RSR(_socket), W5100.readSnRX_RD(_socket), W5100.readSnRX_WR(_socket));
+        printf("Sn_TX_FSR:%d, Sn_TX_RD:%d, Sn_TX_WR:%d\n",
+                    W5100.readSnTX_FSR(_socket), W5100.readSnTX_RD(_socket), W5100.readSnTX_WR(_socket));
+#endif //DEBUG
+        if (m_pCb == NULL) {
+            return;
+        }
+        if (W5100.getRXReceivedSize(_socket) > 0) {
+            m_pCb(UDPSOCKET_READABLE);
+            return;
+        }
+     }
+};    
+#endif // MYUDPSOCKET_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Apr 10 03:38:22 2012 +0000
@@ -0,0 +1,16 @@
+#include "mbed.h"
+#include "MyEthernetNetIf.h"
+
+#define WIZ820IO
+
+#ifdef WIZ820IO
+MyEthernetNetIf eth;
+#else
+EthernetNetIf eth;
+#endif
+
+int main() {
+    printf("setup...\n");
+    int r = eth.setup();
+    printf("%d\n", r);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Tue Apr 10 03:38:22 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/737756e0b479
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/w5100.cpp	Tue Apr 10 03:38:22 2012 +0000
@@ -0,0 +1,271 @@
+/*
+ * 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 "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 spi(p11, p12, p13); // mosi, miso, sclk
+DigitalOut _cs(p14);
+DigitalOut _reset(p15);
+inline void delay(int n) { wait_ms(n); }
+inline static void initSS(){ _cs = 1; }
+inline static void setSS() { _cs = 0; }
+inline static void resetSS() { _cs = 1; }
+
+void W5100Class::hardware_reset() {
+  _reset = 1;
+  _reset = 0;
+  wait_us(2);
+  _reset = 1;
+  wait_ms(150);
+}
+#endif //MBED
+
+void W5100Class::init(void)
+{
+  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
+  spi.write(_addr >> 8);
+  spi.write(_addr & 0xFF);
+  spi.write(0x80);
+  spi.write(0x01);
+#else    
+  spi.write(0xF0);
+  spi.write(_addr >> 8);
+  spi.write(_addr & 0xFF);
+#endif  
+  spi.write(_data);
+  resetSS();
+  return 1;
+}
+
+uint16_t W5100Class::write(uint16_t _addr, const uint8_t *_buf, uint16_t _len)
+{
+    
+#ifdef W5200
+    setSS();
+    spi.write(_addr >> 8);
+    spi.write(_addr & 0xFF);
+    spi.write((0x80 | ((_len & 0x7F00) >> 8)));
+    spi.write(_len & 0x00FF);
+
+  for (uint16_t i=0; i<_len; i++)
+  {
+    spi.write(_buf[i]);
+
+  }
+    resetSS();
+#else    
+    
+  for (uint16_t i=0; i<_len; i++)
+  {
+    setSS();    
+    spi.write(0xF0);
+    spi.write(_addr >> 8);
+    spi.write(_addr & 0xFF);
+    _addr++;
+    spi.write(_buf[i]);
+    resetSS();
+  }
+#endif
+  
+  return _len;
+}
+
+uint8_t W5100Class::read(uint16_t _addr)
+{
+  setSS();  
+#ifdef W5200
+  spi.write(_addr >> 8);
+  spi.write(_addr & 0xFF);
+  spi.write(0x00);
+  spi.write(0x01);
+#else
+  spi.write(0x0F);
+  spi.write(_addr >> 8);
+  spi.write(_addr & 0xFF);
+#endif
+  
+  uint8_t _data = spi.write(0);
+  resetSS();
+  return _data;
+}
+
+uint16_t W5100Class::read(uint16_t _addr, uint8_t *_buf, uint16_t _len)
+{
+#ifdef W5200
+    setSS();
+    spi.write(_addr >> 8);
+    spi.write(_addr & 0xFF);
+    spi.write((0x00 | ((_len & 0x7F00) >> 8)));
+    spi.write(_len & 0x00FF);
+
+  for (uint16_t i=0; i<_len; i++)
+  {
+    _buf[i] = spi.write(0);
+
+  }
+    resetSS();
+
+#else    
+    
+  for (uint16_t i=0; i<_len; i++)
+  {
+    setSS();
+    spi.write(0x0F);
+    spi.write(_addr >> 8);
+    spi.write(_addr & 0xFF);
+    _addr++;
+    _buf[i] = spi.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	Tue Apr 10 03:38:22 2012 +0000
@@ -0,0 +1,435 @@
+/*
+ * 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:
+#ifdef MBED
+  void hardware_reset();
+#endif //MBED
+  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