Skip to content
This repository
Browse code

Merge branch 'dhcp' of github.com:amcewen/Arduino.

This includes DCHP support and new UDP API for the Ethernet library.
  • Loading branch information...
commit f43c0918ff9c1d76b1163652e9db664a5b42ccd3 1 parent efae89e
David A. Mellis authored March 23, 2011

Showing 25 changed files with 1,016 additions and 186 deletions. Show diff stats Hide diff stats

  1. 4  libraries/Ethernet/Client.cpp
  2. 6  libraries/Ethernet/Client.h
  3. 341  libraries/Ethernet/Dhcp.cpp
  4. 158  libraries/Ethernet/Dhcp.h
  5. 77  libraries/Ethernet/Ethernet.cpp
  6. 18  libraries/Ethernet/Ethernet.h
  7. 44  libraries/Ethernet/IPAddress.cpp
  8. 68  libraries/Ethernet/IPAddress.h
  9. 165  libraries/Ethernet/Udp.cpp
  10. 56  libraries/Ethernet/Udp.h
  11. 9  libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.pde
  12. 8  libraries/Ethernet/examples/ChatServer/ChatServer.pde
  13. 21  libraries/Ethernet/examples/PachubeClient/PachubeClient.pde
  14. 12  libraries/Ethernet/examples/PachubeClientString/PachubeClientString.pde
  15. 6  libraries/Ethernet/examples/TelnetClient/TelnetClient.pde
  16. 33  libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.pde
  17. 32  libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.pde
  18. 16  libraries/Ethernet/examples/WebClient/WebClient.pde
  19. 4  libraries/Ethernet/examples/WebServer/WebServer.pde
  20. 7  libraries/Ethernet/keywords.txt
  21. 13  libraries/Ethernet/util.h
  22. 55  libraries/Ethernet/utility/socket.cpp
  23. 21  libraries/Ethernet/utility/socket.h
  24. 12  libraries/Ethernet/utility/w5100.cpp
  25. 16  libraries/Ethernet/utility/w5100.h
4  libraries/Ethernet/Client.cpp
@@ -16,7 +16,7 @@ uint16_t Client::_srcport = 1024;
16 16
 Client::Client(uint8_t sock) : _sock(sock) {
17 17
 }
18 18
 
19  
-Client::Client(uint8_t *ip, uint16_t port) : _ip(ip), _port(port), _sock(MAX_SOCK_NUM) {
  19
+Client::Client(IPAddress& ip, uint16_t port) : _ip(ip), _port(port), _sock(MAX_SOCK_NUM) {
20 20
 }
21 21
 
22 22
 uint8_t Client::connect() {
@@ -38,7 +38,7 @@ uint8_t Client::connect() {
38 38
   if (_srcport == 0) _srcport = 1024;
39 39
   socket(_sock, SnMR::TCP, _srcport, 0);
40 40
 
41  
-  if (!::connect(_sock, _ip, _port)) {
  41
+  if (!::connect(_sock, _ip.raw_address(), _port)) {
42 42
     _sock = MAX_SOCK_NUM;
43 43
     return 0;
44 44
   }
6  libraries/Ethernet/Client.h
@@ -7,8 +7,8 @@ class Client : public Stream {
7 7
 
8 8
 public:
9 9
   Client();
10  
-  Client(uint8_t);
11  
-  Client(uint8_t *, uint16_t);
  10
+  Client(uint8_t sock);
  11
+  Client(IPAddress& ip, uint16_t port);
12 12
 
13 13
   uint8_t status();
14 14
   uint8_t connect();
@@ -29,7 +29,7 @@ class Client : public Stream {
29 29
 private:
30 30
   static uint16_t _srcport;
31 31
   uint8_t _sock;
32  
-  uint8_t *_ip;
  32
+  IPAddress _ip;
33 33
   uint16_t _port;
34 34
 };
35 35
 
341  libraries/Ethernet/Dhcp.cpp
... ...
@@ -0,0 +1,341 @@
  1
+// DHCP Library v0.3 - April 25, 2009
  2
+// Author: Jordan Terrell - blog.jordanterrell.com
  3
+
  4
+#include "w5100.h"
  5
+
  6
+#include <string.h>
  7
+#include <stdlib.h>
  8
+#include "Dhcp.h"
  9
+#include "Arduino.h"
  10
+#include "util.h"
  11
+
  12
+int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout)
  13
+{
  14
+    uint8_t dhcp_state = STATE_DHCP_START;
  15
+    uint8_t messageType = 0;
  16
+  
  17
+    // zero out _dhcpMacAddr, _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp
  18
+    memset(_dhcpMacAddr, 0, 26); 
  19
+
  20
+    memcpy((void*)_dhcpMacAddr, (void*)mac, 6);
  21
+  
  22
+    // Pick an initial transaction ID
  23
+    _dhcpTransactionId = random(1UL, 2000UL);
  24
+    _dhcpInitialTransactionId = _dhcpTransactionId;
  25
+
  26
+    if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0)
  27
+    {
  28
+      // Couldn't get a socket
  29
+      return 0;
  30
+    }
  31
+    
  32
+    presend_DHCP();
  33
+    
  34
+    int result = 0;
  35
+    
  36
+    unsigned long startTime = millis();
  37
+    
  38
+    while(dhcp_state != STATE_DHCP_LEASED)
  39
+    {
  40
+        if(dhcp_state == STATE_DHCP_START)
  41
+        {
  42
+            _dhcpTransactionId++;
  43
+            
  44
+            send_DHCP_MESSAGE(DHCP_DISCOVER, ((millis() - startTime) / 1000));
  45
+            dhcp_state = STATE_DHCP_DISCOVER;
  46
+        }
  47
+        else if(dhcp_state == STATE_DHCP_DISCOVER)
  48
+        {
  49
+            uint32_t respId;
  50
+            messageType = parseDHCPResponse(responseTimeout, respId);
  51
+            if(messageType == DHCP_OFFER)
  52
+            {
  53
+                // We'll use the transaction ID that the offer came with,
  54
+                // rather than the one we were up to
  55
+                _dhcpTransactionId = respId;
  56
+                send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime) / 1000));
  57
+                dhcp_state = STATE_DHCP_REQUEST;
  58
+            }
  59
+        }
  60
+        else if(dhcp_state == STATE_DHCP_REQUEST)
  61
+        {
  62
+            uint32_t respId;
  63
+            messageType = parseDHCPResponse(responseTimeout, respId);
  64
+            if(messageType == DHCP_ACK)
  65
+            {
  66
+                dhcp_state = STATE_DHCP_LEASED;
  67
+                result = 1;
  68
+            }
  69
+            else if(messageType == DHCP_NAK)
  70
+                dhcp_state = STATE_DHCP_START;
  71
+        }
  72
+        
  73
+        if(messageType == 255)
  74
+        {
  75
+            messageType = 0;
  76
+            dhcp_state = STATE_DHCP_START;
  77
+        }
  78
+        
  79
+        if(result != 1 && ((millis() - startTime) > timeout))
  80
+            break;
  81
+    }
  82
+    
  83
+    // We're done with the socket now
  84
+    _dhcpUdpSocket.stop();
  85
+    _dhcpTransactionId++;
  86
+    
  87
+    return result;
  88
+}
  89
+
  90
+void DhcpClass::presend_DHCP()
  91
+{
  92
+}
  93
+
  94
+void DhcpClass::send_DHCP_MESSAGE(uint8_t messageType, uint16_t secondsElapsed)
  95
+{
  96
+    uint8_t buffer[32];
  97
+    memset(buffer, 0, 32);
  98
+    IPAddress dest_addr( 255, 255, 255, 255 ); // Broadcast address
  99
+
  100
+    if (-1 == _dhcpUdpSocket.beginPacket(dest_addr, DHCP_SERVER_PORT))
  101
+    {
  102
+        // FIXME Need to return errors
  103
+        return;
  104
+    }
  105
+
  106
+    buffer[0] = DHCP_BOOTREQUEST;   // op
  107
+    buffer[1] = DHCP_HTYPE10MB;     // htype
  108
+    buffer[2] = DHCP_HLENETHERNET;  // hlen
  109
+    buffer[3] = DHCP_HOPS;          // hops
  110
+
  111
+    // xid
  112
+    unsigned long xid = htonl(_dhcpTransactionId);
  113
+    memcpy(buffer + 4, &(xid), 4);
  114
+
  115
+    // 8, 9 - seconds elapsed
  116
+    buffer[8] = ((secondsElapsed & 0xff00) >> 8);
  117
+    buffer[9] = (secondsElapsed & 0x00ff);
  118
+
  119
+    // flags
  120
+    unsigned short flags = htons(DHCP_FLAGSBROADCAST);
  121
+    memcpy(buffer + 10, &(flags), 2);
  122
+
  123
+    // ciaddr: already zeroed
  124
+    // yiaddr: already zeroed
  125
+    // siaddr: already zeroed
  126
+    // giaddr: already zeroed
  127
+
  128
+    //put data in W5100 transmit buffer
  129
+    _dhcpUdpSocket.write(buffer, 28);
  130
+
  131
+    memset(buffer, 0, 32); // clear local buffer
  132
+
  133
+    memcpy(buffer, _dhcpMacAddr, 6); // chaddr
  134
+
  135
+    //put data in W5100 transmit buffer
  136
+    _dhcpUdpSocket.write(buffer, 16);
  137
+
  138
+    memset(buffer, 0, 32); // clear local buffer
  139
+
  140
+    // leave zeroed out for sname && file
  141
+    // put in W5100 transmit buffer x 6 (192 bytes)
  142
+  
  143
+    for(int i = 0; i < 6; i++) {
  144
+        _dhcpUdpSocket.write(buffer, 32);
  145
+    }
  146
+  
  147
+    // OPT - Magic Cookie
  148
+    buffer[0] = (uint8_t)((MAGIC_COOKIE >> 24)& 0xFF);
  149
+    buffer[1] = (uint8_t)((MAGIC_COOKIE >> 16)& 0xFF);
  150
+    buffer[2] = (uint8_t)((MAGIC_COOKIE >> 8)& 0xFF);
  151
+    buffer[3] = (uint8_t)(MAGIC_COOKIE& 0xFF);
  152
+
  153
+    // OPT - message type
  154
+    buffer[4] = dhcpMessageType;
  155
+    buffer[5] = 0x01;
  156
+    buffer[6] = messageType; //DHCP_REQUEST;
  157
+
  158
+    // OPT - client identifier
  159
+    buffer[7] = dhcpClientIdentifier;
  160
+    buffer[8] = 0x07;
  161
+    buffer[9] = 0x01;
  162
+    memcpy(buffer + 10, _dhcpMacAddr, 6);
  163
+
  164
+    // OPT - host name
  165
+    buffer[16] = hostName;
  166
+    buffer[17] = strlen(HOST_NAME) + 3; // length of hostname + last 3 bytes of mac address
  167
+    strcpy((char*)&(buffer[18]), HOST_NAME);
  168
+
  169
+    buffer[24] = _dhcpMacAddr[3];
  170
+    buffer[25] = _dhcpMacAddr[4];
  171
+    buffer[26] = _dhcpMacAddr[5];
  172
+
  173
+    //put data in W5100 transmit buffer
  174
+    _dhcpUdpSocket.write(buffer, 27);
  175
+
  176
+    if(messageType == DHCP_REQUEST)
  177
+    {
  178
+        buffer[0] = dhcpRequestedIPaddr;
  179
+        buffer[1] = 0x04;
  180
+        buffer[2] = _dhcpLocalIp[0];
  181
+        buffer[3] = _dhcpLocalIp[1];
  182
+        buffer[4] = _dhcpLocalIp[2];
  183
+        buffer[5] = _dhcpLocalIp[3];
  184
+
  185
+        buffer[6] = dhcpServerIdentifier;
  186
+        buffer[7] = 0x04;
  187
+        buffer[8] = _dhcpDhcpServerIp[0];
  188
+        buffer[9] = _dhcpDhcpServerIp[1];
  189
+        buffer[10] = _dhcpDhcpServerIp[2];
  190
+        buffer[11] = _dhcpDhcpServerIp[3];
  191
+
  192
+        //put data in W5100 transmit buffer
  193
+        _dhcpUdpSocket.write(buffer, 12);
  194
+    }
  195
+    
  196
+    buffer[0] = dhcpParamRequest;
  197
+    buffer[1] = 0x06;
  198
+    buffer[2] = subnetMask;
  199
+    buffer[3] = routersOnSubnet;
  200
+    buffer[4] = dns;
  201
+    buffer[5] = domainName;
  202
+    buffer[6] = dhcpT1value;
  203
+    buffer[7] = dhcpT2value;
  204
+    buffer[8] = endOption;
  205
+    
  206
+    //put data in W5100 transmit buffer
  207
+    _dhcpUdpSocket.write(buffer, 9);
  208
+
  209
+    _dhcpUdpSocket.endPacket();
  210
+}
  211
+
  212
+uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId)
  213
+{
  214
+    uint8_t type = 0;
  215
+    uint8_t opt_len = 0;
  216
+     
  217
+    unsigned long startTime = millis();
  218
+
  219
+    while(_dhcpUdpSocket.parsePacket() <= 0)
  220
+    {
  221
+        if((millis() - startTime) > responseTimeout)
  222
+        {
  223
+            return 255;
  224
+        }
  225
+        delay(50);
  226
+    }
  227
+    // start reading in the packet
  228
+    RIP_MSG_FIXED fixedMsg;
  229
+    _dhcpUdpSocket.read((uint8_t*)&fixedMsg, sizeof(RIP_MSG_FIXED));
  230
+  
  231
+    if(fixedMsg.op == DHCP_BOOTREPLY && _dhcpUdpSocket.remotePort() == DHCP_SERVER_PORT)
  232
+    {
  233
+        transactionId = ntohl(fixedMsg.xid);
  234
+        if(memcmp(fixedMsg.chaddr, _dhcpMacAddr, 6) != 0 || (transactionId < _dhcpInitialTransactionId) || (transactionId > _dhcpTransactionId))
  235
+        {
  236
+            // Need to read the rest of the packet here regardless
  237
+            _dhcpUdpSocket.flush();
  238
+            return 0;
  239
+        }
  240
+
  241
+        memcpy(_dhcpLocalIp, fixedMsg.yiaddr, 4);
  242
+
  243
+        // Skip to the option part
  244
+        // Doing this a byte at a time so we don't have to put a big buffer
  245
+        // on the stack (as we don't have lots of memory lying around)
  246
+        for (int i =0; i < (240 - sizeof(RIP_MSG_FIXED)); i++)
  247
+        {
  248
+            _dhcpUdpSocket.read(); // we don't care about the returned byte
  249
+        }
  250
+
  251
+        while (_dhcpUdpSocket.available() > 0) 
  252
+        {
  253
+            switch (_dhcpUdpSocket.read()) 
  254
+            {
  255
+                case endOption :
  256
+                    break;
  257
+                    
  258
+                case padOption :
  259
+                    break;
  260
+                
  261
+                case dhcpMessageType :
  262
+                    opt_len = _dhcpUdpSocket.read();
  263
+                    type = _dhcpUdpSocket.read();
  264
+                    break;
  265
+                
  266
+                case subnetMask :
  267
+                    opt_len = _dhcpUdpSocket.read();
  268
+                    _dhcpUdpSocket.read(_dhcpSubnetMask, 4);
  269
+                    break;
  270
+                
  271
+                case routersOnSubnet :
  272
+                    opt_len = _dhcpUdpSocket.read();
  273
+                    _dhcpUdpSocket.read(_dhcpGatewayIp, 4);
  274
+                    break;
  275
+                
  276
+                case dns :
  277
+                    opt_len = _dhcpUdpSocket.read();
  278
+                    _dhcpUdpSocket.read(_dhcpDnsServerIp, 4);
  279
+                    break;
  280
+                
  281
+                case dhcpServerIdentifier :
  282
+                    opt_len = _dhcpUdpSocket.read();
  283
+                    if( *((uint32_t*)_dhcpDhcpServerIp) == 0 || 
  284
+                        IPAddress(_dhcpDhcpServerIp) == _dhcpUdpSocket.remoteIP() )
  285
+                    {
  286
+                        _dhcpUdpSocket.read(_dhcpDhcpServerIp, sizeof(_dhcpDhcpServerIp));
  287
+                    }
  288
+                    else
  289
+                    {
  290
+                        // Skip over the rest of this option
  291
+                        while (opt_len--)
  292
+                        {
  293
+                            _dhcpUdpSocket.read();
  294
+                        }
  295
+                    }
  296
+                    break;
  297
+                
  298
+                case dhcpIPaddrLeaseTime :
  299
+                default :
  300
+                    opt_len = _dhcpUdpSocket.read();
  301
+                    // Skip over the rest of this option
  302
+                    while (opt_len--)
  303
+                    {
  304
+                        _dhcpUdpSocket.read();
  305
+                    }
  306
+                    break;
  307
+            }
  308
+        }
  309
+    }
  310
+
  311
+    // Need to skip to end of the packet regardless here
  312
+    _dhcpUdpSocket.flush();
  313
+
  314
+    return type;
  315
+}
  316
+
  317
+IPAddress DhcpClass::getLocalIp()
  318
+{
  319
+    return IPAddress(_dhcpLocalIp);
  320
+}
  321
+
  322
+IPAddress DhcpClass::getSubnetMask()
  323
+{
  324
+    return IPAddress(_dhcpSubnetMask);
  325
+}
  326
+
  327
+IPAddress DhcpClass::getGatewayIp()
  328
+{
  329
+    return IPAddress(_dhcpGatewayIp);
  330
+}
  331
+
  332
+IPAddress DhcpClass::getDhcpServerIp()
  333
+{
  334
+    return IPAddress(_dhcpDhcpServerIp);
  335
+}
  336
+
  337
+IPAddress DhcpClass::getDnsServerIp()
  338
+{
  339
+    return IPAddress(_dhcpDnsServerIp);
  340
+}
  341
+
158  libraries/Ethernet/Dhcp.h
... ...
@@ -0,0 +1,158 @@
  1
+// DHCP Library v0.3 - April 25, 2009
  2
+// Author: Jordan Terrell - blog.jordanterrell.com
  3
+
  4
+#ifndef Dhcp_h
  5
+#define Dhcp_h
  6
+
  7
+#include "Udp.h"
  8
+
  9
+/* DHCP state machine. */
  10
+#define STATE_DHCP_START 0
  11
+#define	STATE_DHCP_DISCOVER	1
  12
+#define	STATE_DHCP_REQUEST	2
  13
+#define	STATE_DHCP_LEASED	3
  14
+#define	STATE_DHCP_REREQUEST	4
  15
+#define	STATE_DHCP_RELEASE	5
  16
+
  17
+#define DHCP_FLAGSBROADCAST	0x8000
  18
+
  19
+/* UDP port numbers for DHCP */
  20
+#define	DHCP_SERVER_PORT	67	/* from server to client */
  21
+#define DHCP_CLIENT_PORT	68	/* from client to server */
  22
+
  23
+/* DHCP message OP code */
  24
+#define DHCP_BOOTREQUEST	1
  25
+#define DHCP_BOOTREPLY		2
  26
+
  27
+/* DHCP message type */
  28
+#define	DHCP_DISCOVER		1
  29
+#define DHCP_OFFER		  2
  30
+#define	DHCP_REQUEST		3
  31
+#define	DHCP_DECLINE		4
  32
+#define	DHCP_ACK		    5
  33
+#define DHCP_NAK		    6
  34
+#define	DHCP_RELEASE		7
  35
+#define DHCP_INFORM		  8
  36
+
  37
+#define DHCP_HTYPE10MB		1
  38
+#define DHCP_HTYPE100MB		2
  39
+
  40
+#define DHCP_HLENETHERNET	6
  41
+#define DHCP_HOPS		0
  42
+#define DHCP_SECS		0
  43
+
  44
+#define MAGIC_COOKIE		0x63825363
  45
+#define MAX_DHCP_OPT	16
  46
+
  47
+#define HOST_NAME "WIZnet"
  48
+
  49
+enum
  50
+{
  51
+	padOption		=	0,
  52
+	subnetMask		=	1,
  53
+	timerOffset		=	2,
  54
+	routersOnSubnet		=	3,
  55
+	/* timeServer		=	4,
  56
+	nameServer		=	5,*/
  57
+	dns			=	6,
  58
+	/*logServer		=	7,
  59
+	cookieServer		=	8,
  60
+	lprServer		=	9,
  61
+	impressServer		=	10,
  62
+	resourceLocationServer	=	11,*/
  63
+	hostName		=	12,
  64
+	/*bootFileSize		=	13,
  65
+	meritDumpFile		=	14,*/
  66
+	domainName		=	15,
  67
+	/*swapServer		=	16,
  68
+	rootPath		=	17,
  69
+	extentionsPath		=	18,
  70
+	IPforwarding		=	19,
  71
+	nonLocalSourceRouting	=	20,
  72
+	policyFilter		=	21,
  73
+	maxDgramReasmSize	=	22,
  74
+	defaultIPTTL		=	23,
  75
+	pathMTUagingTimeout	=	24,
  76
+	pathMTUplateauTable	=	25,
  77
+	ifMTU			=	26,
  78
+	allSubnetsLocal		=	27,
  79
+	broadcastAddr		=	28,
  80
+	performMaskDiscovery	=	29,
  81
+	maskSupplier		=	30,
  82
+	performRouterDiscovery	=	31,
  83
+	routerSolicitationAddr	=	32,
  84
+	staticRoute		=	33,
  85
+	trailerEncapsulation	=	34,
  86
+	arpCacheTimeout		=	35,
  87
+	ethernetEncapsulation	=	36,
  88
+	tcpDefaultTTL		=	37,
  89
+	tcpKeepaliveInterval	=	38,
  90
+	tcpKeepaliveGarbage	=	39,
  91
+	nisDomainName		=	40,
  92
+	nisServers		=	41,
  93
+	ntpServers		=	42,
  94
+	vendorSpecificInfo	=	43,
  95
+	netBIOSnameServer	=	44,
  96
+	netBIOSdgramDistServer	=	45,
  97
+	netBIOSnodeType		=	46,
  98
+	netBIOSscope		=	47,
  99
+	xFontServer		=	48,
  100
+	xDisplayManager		=	49,*/
  101
+	dhcpRequestedIPaddr	=	50,
  102
+	dhcpIPaddrLeaseTime	=	51,
  103
+	/*dhcpOptionOverload	=	52,*/
  104
+	dhcpMessageType		=	53,
  105
+	dhcpServerIdentifier	=	54,
  106
+	dhcpParamRequest	=	55,
  107
+	/*dhcpMsg			=	56,
  108
+	dhcpMaxMsgSize		=	57,*/
  109
+	dhcpT1value		=	58,
  110
+	dhcpT2value		=	59,
  111
+	/*dhcpClassIdentifier	=	60,*/
  112
+	dhcpClientIdentifier	=	61,
  113
+	endOption		=	255
  114
+};
  115
+
  116
+typedef struct _RIP_MSG_FIXED
  117
+{
  118
+	uint8_t  op; 
  119
+	uint8_t  htype; 
  120
+	uint8_t  hlen;
  121
+	uint8_t  hops;
  122
+	uint32_t xid;
  123
+	uint16_t secs;
  124
+	uint16_t flags;
  125
+	uint8_t  ciaddr[4];
  126
+	uint8_t  yiaddr[4];
  127
+	uint8_t  siaddr[4];
  128
+	uint8_t  giaddr[4];
  129
+	uint8_t  chaddr[6];
  130
+}RIP_MSG_FIXED;
  131
+
  132
+class DhcpClass {
  133
+private:
  134
+  uint32_t _dhcpInitialTransactionId;
  135
+  uint32_t _dhcpTransactionId;
  136
+  uint8_t  _dhcpMacAddr[6];
  137
+  uint8_t  _dhcpLocalIp[4];
  138
+  uint8_t  _dhcpSubnetMask[4];
  139
+  uint8_t  _dhcpGatewayIp[4];
  140
+  uint8_t  _dhcpDhcpServerIp[4];
  141
+  uint8_t  _dhcpDnsServerIp[4];
  142
+  UDP _dhcpUdpSocket;
  143
+  
  144
+  void presend_DHCP();
  145
+  void send_DHCP_MESSAGE(uint8_t, uint16_t);
  146
+  
  147
+  uint8_t parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId);
  148
+public:
  149
+  IPAddress getLocalIp();
  150
+  IPAddress getSubnetMask();
  151
+  IPAddress getGatewayIp();
  152
+  IPAddress getDhcpServerIp();
  153
+  IPAddress getDnsServerIp();
  154
+  
  155
+  int beginWithDHCP(uint8_t *, unsigned long timeout = 60000, unsigned long responseTimeout = 4000);
  156
+};
  157
+
  158
+#endif
77  libraries/Ethernet/Ethernet.cpp
... ...
@@ -1,5 +1,6 @@
1 1
 #include "w5100.h"
2 2
 #include "Ethernet.h"
  3
+#include "Dhcp.h"
3 4
 
4 5
 // XXX: don't make assumptions about the value of MAX_SOCK_NUM.
5 6
 uint8_t EthernetClass::_state[MAX_SOCK_NUM] = { 
@@ -7,30 +8,78 @@ uint8_t EthernetClass::_state[MAX_SOCK_NUM] = {
7 8
 uint16_t EthernetClass::_server_port[MAX_SOCK_NUM] = { 
8 9
   0, 0, 0, 0 };
9 10
 
10  
-void EthernetClass::begin(uint8_t *mac, uint8_t *ip)
  11
+int EthernetClass::begin(uint8_t *mac_address)
11 12
 {
12  
-  uint8_t gateway[4];
13  
-  gateway[0] = ip[0];
14  
-  gateway[1] = ip[1];
15  
-  gateway[2] = ip[2];
  13
+  DhcpClass dhcp;
  14
+
  15
+  // Initialise the basic info
  16
+  W5100.init();
  17
+  W5100.setMACAddress(mac_address);
  18
+  W5100.setIPAddress(IPAddress(0,0,0,0).raw_address());
  19
+
  20
+  // Now try to get our config info from a DHCP server
  21
+  int ret = dhcp.beginWithDHCP(mac_address);
  22
+  if(ret == 1)
  23
+  {
  24
+    // We've successfully found a DHCP server and got our configuration info, so set things
  25
+    // accordingly
  26
+    W5100.setIPAddress(dhcp.getLocalIp().raw_address());
  27
+    W5100.setGatewayIp(dhcp.getGatewayIp().raw_address());
  28
+    W5100.setSubnetMask(dhcp.getSubnetMask().raw_address());
  29
+    _dnsServerAddress = dhcp.getDnsServerIp();
  30
+  }
  31
+
  32
+  return ret;
  33
+}
  34
+
  35
+void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip)
  36
+{
  37
+  // Assume the gateway will be the machine on the same network as the local IP
  38
+  // but with last octet being '1'
  39
+  IPAddress gateway = local_ip;
16 40
   gateway[3] = 1;
17  
-  begin(mac, ip, gateway);
  41
+  begin(mac_address, local_ip, gateway);
18 42
 }
19 43
 
20  
-void EthernetClass::begin(uint8_t *mac, uint8_t *ip, uint8_t *gateway)
  44
+void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress gateway)
21 45
 {
22  
-  uint8_t subnet[] = { 
23  
-    255, 255, 255, 0   };
24  
-  begin(mac, ip, gateway, subnet);
  46
+  IPAddress subnet(255, 255, 255, 0);
  47
+  begin(mac_address, local_ip, gateway, subnet);
25 48
 }
26 49
 
27  
-void EthernetClass::begin(uint8_t *mac, uint8_t *ip, uint8_t *gateway, uint8_t *subnet)
  50
+void EthernetClass::begin(uint8_t *mac, IPAddress local_ip, IPAddress gateway, IPAddress subnet)
28 51
 {
29 52
   W5100.init();
30 53
   W5100.setMACAddress(mac);
31  
-  W5100.setIPAddress(ip);
32  
-  W5100.setGatewayIp(gateway);
33  
-  W5100.setSubnetMask(subnet);
  54
+  W5100.setIPAddress(local_ip._address);
  55
+  W5100.setGatewayIp(gateway._address);
  56
+  W5100.setSubnetMask(subnet._address);
  57
+}
  58
+
  59
+IPAddress EthernetClass::localIP()
  60
+{
  61
+  IPAddress ret;
  62
+  W5100.getIPAddress(ret.raw_address());
  63
+  return ret;
  64
+}
  65
+
  66
+IPAddress EthernetClass::subnetMask()
  67
+{
  68
+  IPAddress ret;
  69
+  W5100.getSubnetMask(ret.raw_address());
  70
+  return ret;
  71
+}
  72
+
  73
+IPAddress EthernetClass::gatewayIP()
  74
+{
  75
+  IPAddress ret;
  76
+  W5100.getGatewayIp(ret.raw_address());
  77
+  return ret;
  78
+}
  79
+
  80
+IPAddress EthernetClass::dnsServerIP()
  81
+{
  82
+  return _dnsServerAddress;
34 83
 }
35 84
 
36 85
 EthernetClass Ethernet;
18  libraries/Ethernet/Ethernet.h
@@ -3,6 +3,7 @@
3 3
 
4 4
 #include <inttypes.h>
5 5
 //#include "w5100.h"
  6
+#include "IPAddress.h"
6 7
 #include "Client.h"
7 8
 #include "Server.h"
8 9
 
@@ -10,12 +11,23 @@
10 11
 
11 12
 class EthernetClass {
12 13
 private:
  14
+  IPAddress _dnsServerAddress;
13 15
 public:
14 16
   static uint8_t _state[MAX_SOCK_NUM];
15 17
   static uint16_t _server_port[MAX_SOCK_NUM];
16  
-  void begin(uint8_t *, uint8_t *);
17  
-  void begin(uint8_t *, uint8_t *, uint8_t *);
18  
-  void begin(uint8_t *, uint8_t *, uint8_t *, uint8_t *);
  18
+  // Initialise the Ethernet shield to use the provided MAC address and gain the rest of the
  19
+  // configuration through DHCP.
  20
+  // Returns 0 if the DHCP configuration failed, and 1 if it succeeded
  21
+  int begin(uint8_t *mac_address);
  22
+  void begin(uint8_t *mac_address, IPAddress local_ip);
  23
+  void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress gateway);
  24
+  void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress gateway, IPAddress subnet);
  25
+
  26
+  IPAddress localIP();
  27
+  IPAddress subnetMask();
  28
+  IPAddress gatewayIP();
  29
+  IPAddress dnsServerIP();
  30
+
19 31
   friend class Client;
20 32
   friend class Server;
21 33
 };
44  libraries/Ethernet/IPAddress.cpp
... ...
@@ -0,0 +1,44 @@
  1
+
  2
+#include <Arduino.h>
  3
+#include <IPAddress.h>
  4
+
  5
+IPAddress::IPAddress()
  6
+{
  7
+    memset(_address, 0, sizeof(_address));
  8
+}
  9
+
  10
+IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet)
  11
+{
  12
+    _address[0] = first_octet;
  13
+    _address[1] = second_octet;
  14
+    _address[2] = third_octet;
  15
+    _address[3] = fourth_octet;
  16
+}
  17
+
  18
+IPAddress::IPAddress(uint32_t address)
  19
+{
  20
+    memcpy(_address, &address, sizeof(_address));
  21
+}
  22
+
  23
+IPAddress::IPAddress(const uint8_t *address)
  24
+{
  25
+    memcpy(_address, address, sizeof(_address));
  26
+}
  27
+
  28
+IPAddress& IPAddress::operator=(const uint8_t *address)
  29
+{
  30
+    memcpy(_address, address, sizeof(_address));
  31
+    return *this;
  32
+}
  33
+
  34
+IPAddress& IPAddress::operator=(uint32_t address)
  35
+{
  36
+    memcpy(_address, (const uint8_t *)&address, sizeof(_address));
  37
+    return *this;
  38
+}
  39
+
  40
+bool IPAddress::operator==(const uint8_t* addr)
  41
+{
  42
+    return memcmp(addr, _address, sizeof(_address)) == 0;
  43
+}
  44
+
68  libraries/Ethernet/IPAddress.h
... ...
@@ -0,0 +1,68 @@
  1
+/*
  2
+ *
  3
+ * MIT License:
  4
+ * Copyright (c) 2011 Adrian McEwen
  5
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
  6
+ * of this software and associated documentation files (the "Software"), to deal
  7
+ * in the Software without restriction, including without limitation the rights
  8
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9
+ * copies of the Software, and to permit persons to whom the Software is
  10
+ * furnished to do so, subject to the following conditions:
  11
+ * 
  12
+ * The above copyright notice and this permission notice shall be included in
  13
+ * all copies or substantial portions of the Software.
  14
+ * 
  15
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21
+ * THE SOFTWARE.
  22
+ *
  23
+ * adrianm@mcqn.com 1/1/2011
  24
+ */
  25
+
  26
+#ifndef IPAddress_h
  27
+#define IPAddress_h
  28
+
  29
+// A class to make it easier to handle and pass around IP addresses
  30
+
  31
+class IPAddress {
  32
+private:
  33
+    uint8_t _address[4];  // IPv4 address
  34
+    // Access the raw byte array containing the address.  Because this returns a pointer
  35
+    // to the internal structure rather than a copy of the address this function should only
  36
+    // be used when you know that the usage of the returned uint8_t* will be transient and not
  37
+    // stored.
  38
+    uint8_t* raw_address() { return _address; };
  39
+
  40
+public:
  41
+    // Constructors
  42
+    IPAddress();
  43
+    IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
  44
+    IPAddress(uint32_t address);
  45
+    IPAddress(const uint8_t *address);
  46
+
  47
+    // Overloaded cast operator to allow IPAddress objects to be used where a pointer
  48
+    // to a four-byte uint8_t array is expected
  49
+    operator uint32_t() { return *((uint32_t*)_address); };
  50
+    bool operator==(const IPAddress& addr) { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); };
  51
+    bool operator==(const uint8_t* addr);
  52
+
  53
+    // Overloaded index operator to allow getting and setting individual octets of the address
  54
+    uint8_t operator[](int index) const { return _address[index]; };
  55
+    uint8_t& operator[](int index) { return _address[index]; };
  56
+
  57
+    // Overloaded copy operators to allow initialisation of IPAddress objects from other types
  58
+    IPAddress& operator=(const uint8_t *address);
  59
+    IPAddress& operator=(uint32_t address);
  60
+
  61
+    friend class EthernetClass;
  62
+    friend class UDP;
  63
+    friend class Client;
  64
+    friend class Server;
  65
+    friend class DhcpClass;
  66
+};
  67
+
  68
+#endif
165  libraries/Ethernet/Udp.cpp
@@ -56,106 +56,111 @@ uint8_t UDP::begin(uint16_t port) {
56 56
   return 1;
57 57
 }
58 58
 
59  
-/* Send packet contained in buf of length len to peer at specified ip, and port */
60  
-/* Use this function to transmit binary data that might contain 0x00 bytes*/
61  
-/* This function returns sent data size for success else -1. */
62  
-uint16_t UDP::sendPacket(uint8_t * buf, uint16_t len,  uint8_t * ip, uint16_t port){
63  
-  return sendto(_sock,(const uint8_t *)buf,len,ip,port);
64  
-}
65  
-
66  
-/* Send  zero-terminated string str as packet to peer at specified ip, and port */
67  
-/* This function returns sent data size for success else -1. */
68  
-uint16_t UDP::sendPacket(const char str[], uint8_t * ip, uint16_t port){	
69  
-  // compute strlen
70  
-  const char *s;
71  
-  for(s = str; *s; ++s);
72  
-  uint16_t len = (s-str);
73  
-  // send packet
74  
-  return sendto(_sock,(const uint8_t *)str,len,ip,port);
75  
-}
76 59
 /* Is data available in rx buffer? Returns 0 if no, number of available bytes if yes. 
77 60
  * returned value includes 8 byte UDP header!*/
78 61
 int UDP::available() {
79 62
   return W5100.getRXReceivedSize(_sock);
80 63
 }
81 64
 
  65
+/* Release any resources being used by this UDP instance */
  66
+void UDP::stop()
  67
+{
  68
+  if (_sock == MAX_SOCK_NUM)
  69
+    return;
82 70
 
83  
-/* Read a received packet into buffer buf (which is of maximum length len); */
84  
-/* store calling ip and port as well. Call available() to make sure data is ready first. */
85  
-/* NOTE: I don't believe len is ever checked in implementation of recvfrom(),*/
86  
-/*       so it's easy to overflow buffer. so we check and truncate. */
87  
-/* returns number of bytes read, or negative number of bytes we would have needed if we truncated */
88  
-int UDP::readPacket(uint8_t * buf, uint16_t bufLen, uint8_t *ip, uint16_t *port) {
89  
-  int packetLen = available()-8; //skip UDP header;
90  
-  if(packetLen < 0 ) return 0; // no real data here	
91  
-  if(packetLen > (int)bufLen) {
92  
-    //packet is too large - truncate
93  
-    //HACK - hand-parse the UDP packet using TCP recv method
94  
-    uint8_t tmpBuf[8];
95  
-    int i;
96  
-    //read 8 header bytes and get IP and port from it
97  
-    recv(_sock,tmpBuf,8);
98  
-    ip[0] = tmpBuf[0];
99  
-    ip[1] = tmpBuf[1];
100  
-    ip[2] = tmpBuf[2];
101  
-    ip[3] = tmpBuf[3];
102  
-    *port = tmpBuf[4];
103  
-    *port = (*port << 8) + tmpBuf[5];
104  
-
105  
-    //now copy first (bufLen) bytes into buf		
106  
-    for(i=0;i<(int)bufLen;i++) {
107  
-      recv(_sock,tmpBuf,1);
108  
-      buf[i]=tmpBuf[0];
109  
-    }
  71
+  close(_sock);
110 72
 
111  
-    //and just read the rest byte by byte and throw it away
112  
-    while(available()) {
113  
-      recv(_sock,tmpBuf,1);
114  
-    }
  73
+  EthernetClass::_server_port[_sock] = 0;
  74
+  _sock = MAX_SOCK_NUM;
  75
+}
115 76
 
116  
-    return (-1*packetLen);
  77
+int UDP::beginPacket(IPAddress ip, uint16_t port)
  78
+{
  79
+  _offset = 0;
  80
+  return startUDP(_sock, ip.raw_address(), port);
  81
+}
117 82
 
118  
-    //ALTERNATIVE: requires stdlib - takes a bunch of space
119  
-    /*//create new buffer and read everything into it
120  
-     		uint8_t * tmpBuf = (uint8_t *)malloc(packetLen);
121  
-     		recvfrom(_sock,tmpBuf,packetLen,ip,port);
122  
-     		if(!tmpBuf) return 0; //couldn't allocate
123  
-     		// copy first bufLen bytes
124  
-     		for(unsigned int i=0; i<bufLen; i++) {
125  
-     			buf[i]=tmpBuf[i];
126  
-     		}
127  
-     		//free temp buffer
128  
-     		free(tmpBuf);
129  
-     		*/
  83
+int UDP::endPacket()
  84
+{
  85
+  return sendUDP(_sock);
  86
+}
130 87
 
  88
+void UDP::write(uint8_t byte)
  89
+{
  90
+  write(&byte, 1);
  91
+}
131 92
 
132  
-  } 
133  
-  return recvfrom(_sock,buf,bufLen,ip,port);
  93
+void UDP::write(const char *str)
  94
+{
  95
+  size_t len = strlen(str);
  96
+  write((const uint8_t *)str, len);
134 97
 }
135 98
 
136  
-/* Read a received packet, throw away peer's ip and port.  See note above. */
137  
-int UDP::readPacket(uint8_t * buf, uint16_t len) {
138  
-  uint8_t ip[4];
139  
-  uint16_t port[1];
140  
-  return recvfrom(_sock,buf,len,ip,port);
  99
+void UDP::write(const uint8_t *buffer, size_t size)
  100
+{
  101
+  uint16_t bytes_written = bufferData(_sock, _offset, buffer, size);
  102
+  _offset += bytes_written;
141 103
 }
142 104
 
143  
-int UDP::readPacket(char * buf, uint16_t bufLen, uint8_t *ip, uint16_t &port) {
144  
-uint16_t myPort;
145  
-uint16_t ret = readPacket( (byte*)buf, bufLen, ip, &myPort);
146  
-port = myPort;
147  
-return ret;
  105
+int UDP::parsePacket()
  106
+{
  107
+  //HACK - hand-parse the UDP packet using TCP recv method
  108
+  uint8_t tmpBuf[8];
  109
+  int ret =0;	
  110
+  //read 8 header bytes and get IP and port from it
  111
+  ret = recv(_sock,tmpBuf,8);
  112
+  if (ret > 0)
  113
+  {
  114
+    _remoteIP = tmpBuf;
  115
+    _remotePort = tmpBuf[4];
  116
+    _remotePort = (_remotePort << 8) + tmpBuf[5];
  117
+    // When we get here, any remaining bytes are the data
  118
+    ret = available();
  119
+  }
  120
+  return ret;
148 121
 }
149 122
 
150  
-/* Release any resources being used by this UDP instance */
151  
-void UDP::stop()
  123
+int UDP::read()
152 124
 {
153  
-  if (_sock == MAX_SOCK_NUM)
154  
-    return;
  125
+  uint8_t byte;
  126
+  if (recv(_sock, &byte, 1) > 0)
  127
+  {
  128
+    // We read things without any problems
  129
+    return byte;
  130
+  }
  131
+  // If we get here, there's no data available
  132
+  return -1;
  133
+}
155 134
 
156  
-  close(_sock);
  135
+int UDP::read(unsigned char* buffer, size_t len)
  136
+{
  137
+  /* In the readPacket that copes with truncating packets, the buffer was
  138
+     filled with this code.  Not sure why it loops round reading out a byte
  139
+     at a time.
  140
+  int i;
  141
+  for(i=0;i<(int)bufLen;i++) {
  142
+    recv(_sock,tmpBuf,1);
  143
+    buf[i]=tmpBuf[0];
  144
+  }
  145
+  */
  146
+  return recv(_sock, buffer, len);
  147
+}
157 148
 
158  
-  EthernetClass::_server_port[_sock] = 0;
159  
-  _sock = MAX_SOCK_NUM;
  149
+int UDP::peek()
  150
+{
  151
+  uint8_t b;
  152
+  // Unlike recv, peek doesn't check to see if there's any data available, so we must
  153
+  if (!available())
  154
+    return -1;
  155
+  ::peek(_sock, &b);
  156
+  return b;
  157
+}
  158
+
  159
+void UDP::flush()
  160
+{
  161
+  while (available())
  162
+  {
  163
+    read();
  164
+  }
160 165
 }
161 166
 
56  libraries/Ethernet/Udp.h
@@ -37,28 +37,60 @@
37 37
 #ifndef udp_h
38 38
 #define udp_h
39 39
 
  40
+#include <Stream.h>
  41
+#include <IPAddress.h>
  42
+
40 43
 #define UDP_TX_PACKET_MAX_SIZE 24
41 44
 
42  
-class UDP {
  45
+class UDP : public Stream {
43 46
 private:
44 47
   uint8_t _sock;  // socket ID for Wiz5100
45 48
   uint16_t _port; // local port to listen on
  49
+  IPAddress _remoteIP; // remote IP address for the incoming packet whilst it's being processed
  50
+  uint16_t _remotePort; // remote port for the incoming packet whilst it's being processed
  51
+  uint16_t _offset; // offset into the packet being sent
46 52
 
47 53
 public:
48  
-  UDP();
  54
+  UDP();  // Constructor
49 55
   uint8_t begin(uint16_t);	// initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
50  
-  int available();								// has data been received?
  56
+  void stop();  // Finish with the UDP socket
  57
+
  58
+  // Sending UDP packets
  59
+  
  60
+  // Start building up a packet to send to the remote host specific in ip and port
  61
+  // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
  62
+  int beginPacket(IPAddress ip, uint16_t port);
  63
+  // Finish off this packet and send it
  64
+  // Returns 1 if the packet was sent successfully, 0 if there was an error
  65
+  int endPacket();
  66
+  // Write a single byte into the packet
  67
+  virtual void write(uint8_t);
  68
+  // Write a string of characters into the packet
  69
+  virtual void write(const char *str);
  70
+  // Write size bytes from buffer into the packet
  71
+  virtual void write(const uint8_t *buffer, size_t size);
51 72
 
52  
-  // C-style buffer-oriented functions
53  
-  uint16_t sendPacket(uint8_t *, uint16_t, uint8_t *, uint16_t); //send a packet to specified peer 
54  
-  uint16_t sendPacket(const char[], uint8_t *, uint16_t);  //send a string as a packet to specified peer
55  
-  int readPacket(uint8_t *, uint16_t);		// read a received packet 
56  
-  int readPacket(uint8_t *, uint16_t, uint8_t *, uint16_t *);		// read a received packet, also return sender's ip and port 	
57  
-  // readPacket that fills a character string buffer
58  
-  int readPacket(char *, uint16_t, uint8_t *, uint16_t &);
  73
+  // Start processing the next available incoming packet
  74
+  // Returns the size of the packet in bytes, or 0 if no packets are available
  75
+  int parsePacket();
  76
+  // Number of bytes remaining in the current packet
  77
+  virtual int available();
  78
+  // Read a single byte from the current packet
  79
+  virtual int read();
  80
+  // Read up to len bytes from the current packet and place them into buffer
  81
+  // Returns the number of bytes read, or 0 if none are available
  82
+  virtual int read(unsigned char* buffer, size_t len);
  83
+  // Read up to len characters from the current packet and place them into buffer
  84
+  // Returns the number of characters read, or 0 if none are available
  85
+  virtual int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); };
  86
+  // Return the next byte from the current packet without moving on to the next byte
  87
+  virtual int peek();
  88
+  virtual void flush();	// Finish reading the current packet
59 89
 
60  
-  // Finish with the UDP socket
61  
-  void stop();
  90
+  // Return the IP address of the host who sent the current incoming packet
  91
+  IPAddress remoteIP() { return _remoteIP; };
  92
+  // Return the port of the host who sent the current incoming packet
  93
+  uint16_t remotePort() { return _remotePort; };
62 94
 };
63 95
 
64 96
 #endif
9  libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.pde
@@ -31,12 +31,9 @@
31 31
 byte mac[] = { 
32 32
   0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
33 33
 // assign an IP address for the controller:
34  
-byte ip[] = { 
35  
-  192,168,1,20 };
36  
-byte gateway[] = {
37  
-  192,168,1,1};	
38  
-byte subnet[] = { 
39  
-  255, 255, 255, 0 };
  34
+IPAddress ip(192,168,1,20);
  35
+IPAddress gateway(192,168,1,1);	
  36
+IPAddress subnet(255, 255, 255, 0);
40 37
 
41 38
 
42 39
 // Initialize the Ethernet server library
8  libraries/Ethernet/examples/ChatServer/ChatServer.pde
@@ -24,9 +24,9 @@
24 24
 // The IP address will be dependent on your local network.
25 25
 // gateway and subnet are optional:
26 26
 byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
27  
-byte ip[] = { 192,168,1, 177 };
28  
-byte gateway[] = { 192,168,1, 1 };
29  
-byte subnet[] = { 255, 255, 0, 0 };
  27
+IPAddress ip(192,168,1, 177);
  28
+IPAddress gateway(192,168,1, 1);
  29
+IPAddress subnet(255, 255, 0, 0);
30 30
 
31 31
 // telnet defaults to port 23
32 32
 Server server(23);
@@ -60,4 +60,4 @@ void loop() {
60 60
     // echo the bytes to the server as well: