From 88e858f6e39525cfea264f53e14de9a85010f902 Mon Sep 17 00:00:00 2001 From: amcewen Date: Mon, 10 Jan 2011 14:54:29 +0000 Subject: [PATCH 01/17] Fix for issue 439. UDP API changed to derive from Stream. The old sendPacket and readPacket calls have been removed, and replaced with Stream-derived alternatives which provide more commonality with other communications classes and to allow both buffered and full-packet-at-a-time uses. Also includes the introduction of an IPAddress class to make passing them around easier (and require fewer pointers to be exposed) --- libraries/Ethernet/IPAddress.cpp | 39 ++++ libraries/Ethernet/IPAddress.h | 55 ++++++ libraries/Ethernet/Udp.cpp | 175 +++++++++--------- libraries/Ethernet/Udp.h | 53 ++++-- .../UDPSendReceiveString.pde | 31 ++-- .../examples/UdpNtpClient/UdpNtpClient.pde | 15 +- libraries/Ethernet/keywords.txt | 7 + libraries/Ethernet/utility/socket.cpp | 55 ++++++ libraries/Ethernet/utility/socket.h | 21 +++ libraries/Ethernet/utility/w5100.cpp | 12 +- libraries/Ethernet/utility/w5100.h | 16 +- 11 files changed, 359 insertions(+), 120 deletions(-) create mode 100644 libraries/Ethernet/IPAddress.cpp create mode 100644 libraries/Ethernet/IPAddress.h diff --git a/libraries/Ethernet/IPAddress.cpp b/libraries/Ethernet/IPAddress.cpp new file mode 100644 index 000000000..389329de0 --- /dev/null +++ b/libraries/Ethernet/IPAddress.cpp @@ -0,0 +1,39 @@ + +#include +#include + +IPAddress::IPAddress() +{ + memset(_address, 0, sizeof(_address)); +} + +IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) +{ + _address[0] = first_octet; + _address[1] = second_octet; + _address[2] = third_octet; + _address[3] = fourth_octet; +} + +IPAddress::IPAddress(uint32_t address) +{ + memcpy(_address, &address, sizeof(_address)); +} + +IPAddress::IPAddress(const uint8_t *address) +{ + memcpy(_address, address, sizeof(_address)); +} + +IPAddress& IPAddress::operator=(const uint8_t *address) +{ + memcpy(_address, address, sizeof(_address)); + return *this; +} + +IPAddress& IPAddress::operator=(uint32_t address) +{ + memcpy(_address, (const uint8_t *)&address, sizeof(_address)); + return *this; +} + diff --git a/libraries/Ethernet/IPAddress.h b/libraries/Ethernet/IPAddress.h new file mode 100644 index 000000000..586385320 --- /dev/null +++ b/libraries/Ethernet/IPAddress.h @@ -0,0 +1,55 @@ +/* + * + * MIT License: + * Copyright (c) 2011 Adrian McEwen + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * adrianm@mcqn.com 1/1/2011 + */ + +#ifndef IPAddress_h +#define IPAddress_h + +// A class to make it easier to handle and pass around IP addresses + +class IPAddress { +private: + uint8_t _address[4]; // IPv4 address + +public: + // Constructors + IPAddress(); + IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); + IPAddress(uint32_t address); + IPAddress(const uint8_t *address); + + // Overloaded cast operator to allow IPAddress objects to be used where a pointer + // to a four-byte uint8_t array is expected + operator uint8_t*() { return _address; }; + + // Overloaded index operator to allow getting and setting individual octets of the address + uint8_t operator[](int index) const { return _address[index]; }; + uint8_t& operator[](int index) { return _address[index]; }; + + // Overloaded copy operators to allow initialisation of IPAddress objects from other types + IPAddress& operator=(const uint8_t *address); + IPAddress& operator=(uint32_t address); +}; + +#endif diff --git a/libraries/Ethernet/Udp.cpp b/libraries/Ethernet/Udp.cpp index 07c454df2..6ad8aca7e 100644 --- a/libraries/Ethernet/Udp.cpp +++ b/libraries/Ethernet/Udp.cpp @@ -56,97 +56,12 @@ uint8_t UDP::begin(uint16_t port) { return 1; } -/* Send packet contained in buf of length len to peer at specified ip, and port */ -/* Use this function to transmit binary data that might contain 0x00 bytes*/ -/* This function returns sent data size for success else -1. */ -uint16_t UDP::sendPacket(uint8_t * buf, uint16_t len, uint8_t * ip, uint16_t port){ - return sendto(_sock,(const uint8_t *)buf,len,ip,port); -} - -/* Send zero-terminated string str as packet to peer at specified ip, and port */ -/* This function returns sent data size for success else -1. */ -uint16_t UDP::sendPacket(const char str[], uint8_t * ip, uint16_t port){ - // compute strlen - const char *s; - for(s = str; *s; ++s); - uint16_t len = (s-str); - // send packet - return sendto(_sock,(const uint8_t *)str,len,ip,port); -} /* Is data available in rx buffer? Returns 0 if no, number of available bytes if yes. * returned value includes 8 byte UDP header!*/ int UDP::available() { return W5100.getRXReceivedSize(_sock); } - -/* Read a received packet into buffer buf (which is of maximum length len); */ -/* store calling ip and port as well. Call available() to make sure data is ready first. */ -/* NOTE: I don't believe len is ever checked in implementation of recvfrom(),*/ -/* so it's easy to overflow buffer. so we check and truncate. */ -/* returns number of bytes read, or negative number of bytes we would have needed if we truncated */ -int UDP::readPacket(uint8_t * buf, uint16_t bufLen, uint8_t *ip, uint16_t *port) { - int packetLen = available()-8; //skip UDP header; - if(packetLen < 0 ) return 0; // no real data here - if(packetLen > (int)bufLen) { - //packet is too large - truncate - //HACK - hand-parse the UDP packet using TCP recv method - uint8_t tmpBuf[8]; - int i; - //read 8 header bytes and get IP and port from it - recv(_sock,tmpBuf,8); - ip[0] = tmpBuf[0]; - ip[1] = tmpBuf[1]; - ip[2] = tmpBuf[2]; - ip[3] = tmpBuf[3]; - *port = tmpBuf[4]; - *port = (*port << 8) + tmpBuf[5]; - - //now copy first (bufLen) bytes into buf - for(i=0;i<(int)bufLen;i++) { - recv(_sock,tmpBuf,1); - buf[i]=tmpBuf[0]; - } - - //and just read the rest byte by byte and throw it away - while(available()) { - recv(_sock,tmpBuf,1); - } - - return (-1*packetLen); - - //ALTERNATIVE: requires stdlib - takes a bunch of space - /*//create new buffer and read everything into it - uint8_t * tmpBuf = (uint8_t *)malloc(packetLen); - recvfrom(_sock,tmpBuf,packetLen,ip,port); - if(!tmpBuf) return 0; //couldn't allocate - // copy first bufLen bytes - for(unsigned int i=0; i 0) + { + _remoteIP = tmpBuf; + _remotePort = tmpBuf[4]; + _remotePort = (_remotePort << 8) + tmpBuf[5]; + // When we get here, any remaining bytes are the data + ret = available(); + } + return ret; +} + +int UDP::read() +{ + uint8_t byte; + if (recv(_sock, &byte, 1) > 0) + { + // We read things without any problems + return byte; + } + // If we get here, there's no data available + return -1; +} + +int UDP::read(unsigned char* buffer, size_t len) +{ + /* In the readPacket that copes with truncating packets, the buffer was + filled with this code. Not sure why it loops round reading out a byte + at a time. + int i; + for(i=0;i<(int)bufLen;i++) { + recv(_sock,tmpBuf,1); + buf[i]=tmpBuf[0]; + } + */ + return recv(_sock, buffer, len); +} + +int UDP::peek() +{ + uint8_t b; + // Unlike recv, peek doesn't check to see if there's any data available, so we must + if (!available()) + return -1; + ::peek(_sock, &b); + return b; +} + +void UDP::flush() +{ + while (available()) + { + read(); + } +} + diff --git a/libraries/Ethernet/Udp.h b/libraries/Ethernet/Udp.h index c801ee277..3970a9662 100644 --- a/libraries/Ethernet/Udp.h +++ b/libraries/Ethernet/Udp.h @@ -37,28 +37,57 @@ #ifndef udp_h #define udp_h +#include +#include + #define UDP_TX_PACKET_MAX_SIZE 24 -class UDP { +class UDP : public Stream { private: uint8_t _sock; // socket ID for Wiz5100 uint16_t _port; // local port to listen on + IPAddress _remoteIP; // remote IP address for the incoming packet whilst it's being processed + uint16_t _remotePort; // remote port for the incoming packet whilst it's being processed + uint16_t _offset; // offset into the packet being sent public: - UDP(); + UDP(); // Constructor uint8_t begin(uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use - int available(); // has data been received? + void stop(); // Finish with the UDP socket - // C-style buffer-oriented functions - uint16_t sendPacket(uint8_t *, uint16_t, uint8_t *, uint16_t); //send a packet to specified peer - uint16_t sendPacket(const char[], uint8_t *, uint16_t); //send a string as a packet to specified peer - int readPacket(uint8_t *, uint16_t); // read a received packet - int readPacket(uint8_t *, uint16_t, uint8_t *, uint16_t *); // read a received packet, also return sender's ip and port - // readPacket that fills a character string buffer - int readPacket(char *, uint16_t, uint8_t *, uint16_t &); + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + int beginPacket(IPAddress ip, uint16_t port); + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + int endPacket(); + // Write a single byte into the packet + virtual void write(uint8_t); + // Write a string of characters into the packet + virtual void write(const char *str); + // Write size bytes from buffer into the packet + virtual void write(const uint8_t *buffer, size_t size); - // Finish with the UDP socket - void stop(); + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + int parsePacket(); + // Number of bytes remaining in the current packet + virtual int available(); + // Read a single byte from the current packet + virtual int read(); + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len); + // Return the next byte from the current packet without moving on to the next byte + virtual int peek(); + virtual void flush(); // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + IPAddress remoteIP() { return _remoteIP; }; + // Return the port of the host who sent the current incoming packet + uint16_t remotePort() { return _remotePort; }; }; #endif diff --git a/libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.pde b/libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.pde index f27290f54..e23410139 100644 --- a/libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.pde +++ b/libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.pde @@ -22,15 +22,10 @@ // The IP address will be dependent on your local network: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; -byte ip[] = { - 192,168,1,177 }; +IPAddress ip(192, 168, 1, 177); unsigned int localPort = 8888; // local port to listen on -// the next two variables are set when a packet is received -byte remoteIp[4]; // holds received packet's originating IP -unsigned int remotePort; // holds received packet's originating port - // buffers for receiving and sending data char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet, char ReplyBuffer[] = "acknowledged"; // a string to send back @@ -48,19 +43,33 @@ void setup() { void loop() { // if there's data available, read a packet - int packetSize = Udp.available(); // note that this includes the UDP header + int packetSize = Udp.parsePacket(); if(packetSize) { - packetSize = packetSize - 8; // subtract the 8 byte header Serial.print("Received packet of size "); Serial.println(packetSize); + Serial.print("From "); + IPAddress remote = Udp.remoteIP(); + for (int i =0; i < 4; i++) + { + Serial.print(remote[i], DEC); + if (i < 3) + { + Serial.print("."); + } + } + Serial.print(", port "); + Serial.println(Udp.remotePort()); - // read the packet into packetBufffer and get the senders IP addr and port number - Udp.readPacket(packetBuffer,UDP_TX_PACKET_MAX_SIZE, remoteIp, remotePort); + // read the packet into packetBufffer + Udp.read((byte*)packetBuffer,UDP_TX_PACKET_MAX_SIZE); Serial.println("Contents:"); Serial.println(packetBuffer); - Udp.sendPacket( ReplyBuffer, remoteIp, remotePort); + // send a reply, to the IP address and port that sent us the packet we received + Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); + Udp.write(ReplyBuffer); + Udp.endPacket(); } delay(10); } diff --git a/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.pde b/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.pde index 22bc754c5..cfb5a2bc1 100644 --- a/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.pde +++ b/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.pde @@ -24,14 +24,12 @@ // The IP address will be dependent on your local network: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; -byte ip[] = { - 192,168,1,177 }; +IPAddress ip(192, 168, 1, 177); unsigned int localPort = 8888; // local port to listen for UDP packets -byte timeServer[] = { - 192, 43, 244, 18}; // time.nist.gov NTP server +IPAddress timeServer(192, 43, 244, 18); // time.nist.gov NTP server const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message @@ -55,8 +53,9 @@ void loop() // wait to see if a reply is available delay(1000); - if ( Udp.available() ) { - Udp.readPacket(packetBuffer,NTP_PACKET_SIZE); // read the packet into the buffer + if ( Udp.parsePacket() ) { + // We've received a packet, read the data from it + Udp.read(packetBuffer,NTP_PACKET_SIZE); // read the packet into the buffer //the timestamp starts at byte 40 of the received packet and is four bytes, // or two words, long. First, esxtract the two words: @@ -118,7 +117,9 @@ unsigned long sendNTPpacket(byte *address) // all NTP fields have been given values, now // you can send a packet requesting a timestamp: - Udp.sendPacket( packetBuffer,NTP_PACKET_SIZE, address, 123); //NTP requests are to port 123 + Udp.beginPacket(address, 123); //NTP requests are to port 123 + Udp.write(packetBuffer,NTP_PACKET_SIZE); + Udp.endPacket(); } diff --git a/libraries/Ethernet/keywords.txt b/libraries/Ethernet/keywords.txt index ebc579363..7fdcedf09 100644 --- a/libraries/Ethernet/keywords.txt +++ b/libraries/Ethernet/keywords.txt @@ -9,6 +9,7 @@ Ethernet KEYWORD1 Client KEYWORD1 Server KEYWORD1 +IPAddress KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) @@ -19,10 +20,16 @@ connect KEYWORD2 write KEYWORD2 available KEYWORD2 read KEYWORD2 +peek KEYWORD2 flush KEYWORD2 stop KEYWORD2 connected KEYWORD2 begin KEYWORD2 +beginPacket KEYWORD2 +endPacket KEYWORD2 +parsePacket KEYWORD2 +remoteIP KEYWORD2 +remotePort KEYWORD2 ####################################### # Constants (LITERAL1) diff --git a/libraries/Ethernet/utility/socket.cpp b/libraries/Ethernet/utility/socket.cpp index cad54a5e3..487584511 100644 --- a/libraries/Ethernet/utility/socket.cpp +++ b/libraries/Ethernet/utility/socket.cpp @@ -344,3 +344,58 @@ uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len) return ret; } +uint16_t bufferData(SOCKET s, uint16_t offset, const uint8_t* buf, uint16_t len) +{ + uint16_t ret =0; + if (len > W5100.getTXFreeSize(s)) + { + ret = W5100.getTXFreeSize(s); // check size not to exceed MAX size. + } + else + { + ret = len; + } + W5100.send_data_processing_offset(s, offset, buf, ret); + return ret; +} + +int startUDP(SOCKET s, uint8_t* addr, uint16_t port) +{ + if + ( + ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) || + ((port == 0x00)) + ) + { + return 0; + } + else + { + W5100.writeSnDIPR(s, addr); + W5100.writeSnDPORT(s, port); + return 1; + } +} + +int sendUDP(SOCKET s) +{ + W5100.execCmdSn(s, Sock_SEND); + + /* +2008.01 bj */ + while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK ) + { + if (W5100.readSnIR(s) & SnIR::TIMEOUT) + { + /* +2008.01 [bj]: clear interrupt */ + W5100.writeSnIR(s, (SnIR::SEND_OK|SnIR::TIMEOUT)); + return 0; + } + } + + /* +2008.01 bj */ + W5100.writeSnIR(s, SnIR::SEND_OK); + + /* Sent ok */ + return 1; +} + diff --git a/libraries/Ethernet/utility/socket.h b/libraries/Ethernet/utility/socket.h index 48e2d877b..37ea93f3d 100755 --- a/libraries/Ethernet/utility/socket.h +++ b/libraries/Ethernet/utility/socket.h @@ -16,5 +16,26 @@ extern uint16_t recvfrom(SOCKET s, uint8_t * buf, uint16_t len, uint8_t * addr, extern uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len); +// Functions to allow buffered UDP send (i.e. where the UDP datagram is built up over a +// number of calls before being sent +/* + @brief This function sets up a UDP datagram, the data for which will be provided by one + or more calls to bufferData and then finally sent with sendUDP. + @return 1 if the datagram was successfully set up, or 0 if there was an error +*/ +extern int startUDP(SOCKET s, uint8_t* addr, uint16_t port); +/* + @brief This function copies up to len bytes of data from buf into a UDP datagram to be + sent later by sendUDP. Allows datagrams to be built up from a series of bufferData calls. + @return Number of bytes successfully buffered +*/ +uint16_t bufferData(SOCKET s, uint16_t offset, const uint8_t* buf, uint16_t len); +/* + @brief Send a UDP datagram built up from a sequence of startUDP followed by one or more + calls to bufferData. + @return 1 if the datagram was successfully sent, or 0 if there was an error +*/ +int sendUDP(SOCKET s); + #endif /* _SOCKET_H_ */ diff --git a/libraries/Ethernet/utility/w5100.cpp b/libraries/Ethernet/utility/w5100.cpp index aaf3071f7..aafabaeec 100644 --- a/libraries/Ethernet/utility/w5100.cpp +++ b/libraries/Ethernet/utility/w5100.cpp @@ -65,10 +65,16 @@ uint16_t W5100Class::getRXReceivedSize(SOCKET s) } -void W5100Class::send_data_processing(SOCKET s, uint8_t *data, uint16_t len) +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]; @@ -132,7 +138,7 @@ uint8_t W5100Class::write(uint16_t _addr, uint8_t _data) return 1; } -uint16_t W5100Class::write(uint16_t _addr, uint8_t *_buf, uint16_t _len) +uint16_t W5100Class::write(uint16_t _addr, const uint8_t *_buf, uint16_t _len) { for (int i=0; i<_len; i++) { diff --git a/libraries/Ethernet/utility/w5100.h b/libraries/Ethernet/utility/w5100.h index 118e5d80d..9872c7ccb 100755 --- a/libraries/Ethernet/utility/w5100.h +++ b/libraries/Ethernet/utility/w5100.h @@ -146,7 +146,19 @@ public: * 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, uint8_t *data, uint16_t len); + 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. @@ -182,7 +194,7 @@ public: // --------------- private: static uint8_t write(uint16_t _addr, uint8_t _data); - static uint16_t write(uint16_t addr, uint8_t *buf, uint16_t len); + 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); From 5caad5bdb4492c23f553ec94bd100ff78e87604f Mon Sep 17 00:00:00 2001 From: amcewen Date: Thu, 13 Jan 2011 17:55:08 +0000 Subject: [PATCH 02/17] Added a method to read data into a char buffer so that character-based (rather than byte-based) operations don't require a cast. As requested by Tom Igoe. Part of the fix to issue 439. --- libraries/Ethernet/Udp.h | 3 +++ .../examples/UDPSendReceiveString/UDPSendReceiveString.pde | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/Ethernet/Udp.h b/libraries/Ethernet/Udp.h index 3970a9662..8cd3b065a 100644 --- a/libraries/Ethernet/Udp.h +++ b/libraries/Ethernet/Udp.h @@ -80,6 +80,9 @@ public: // Read up to len bytes from the current packet and place them into buffer // Returns the number of bytes read, or 0 if none are available virtual int read(unsigned char* buffer, size_t len); + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); }; // Return the next byte from the current packet without moving on to the next byte virtual int peek(); virtual void flush(); // Finish reading the current packet diff --git a/libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.pde b/libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.pde index e23410139..081d69114 100644 --- a/libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.pde +++ b/libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.pde @@ -62,7 +62,7 @@ void loop() { Serial.println(Udp.remotePort()); // read the packet into packetBufffer - Udp.read((byte*)packetBuffer,UDP_TX_PACKET_MAX_SIZE); + Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE); Serial.println("Contents:"); Serial.println(packetBuffer); From a42dc0b455513b9cf3127b9720cc66d0db274b03 Mon Sep 17 00:00:00 2001 From: amcewen Date: Sun, 16 Jan 2011 20:11:50 +0000 Subject: [PATCH 03/17] Fix for issue 62, adding DHCP support. New begin() method added to EthernetClass which takes just a MAC address and gets the rest of its configuration information via DHCP. Examples updated to use the IPAddress class and some have been changed to get their config via DHCP. --- libraries/Ethernet/Client.cpp | 4 +- libraries/Ethernet/Client.h | 6 +- libraries/Ethernet/Dhcp.cpp | 341 ++++++++++++++++++ libraries/Ethernet/Dhcp.h | 158 ++++++++ libraries/Ethernet/Ethernet.cpp | 77 +++- libraries/Ethernet/Ethernet.h | 18 +- libraries/Ethernet/IPAddress.cpp | 5 + libraries/Ethernet/IPAddress.h | 15 +- libraries/Ethernet/Udp.cpp | 2 +- .../BarometricPressureWebServer.pde | 9 +- .../examples/ChatServer/ChatServer.pde | 8 +- .../examples/PachubeClient/PachubeClient.pde | 21 +- .../PachubeClientString.pde | 12 +- .../examples/TelnetClient/TelnetClient.pde | 6 +- .../examples/UdpNtpClient/UdpNtpClient.pde | 21 +- .../Ethernet/examples/WebClient/WebClient.pde | 16 +- .../Ethernet/examples/WebServer/WebServer.pde | 4 +- libraries/Ethernet/util.h | 13 + 18 files changed, 662 insertions(+), 74 deletions(-) create mode 100755 libraries/Ethernet/Dhcp.cpp create mode 100755 libraries/Ethernet/Dhcp.h create mode 100644 libraries/Ethernet/util.h diff --git a/libraries/Ethernet/Client.cpp b/libraries/Ethernet/Client.cpp index 96d5c7eed..7ae55d08d 100644 --- a/libraries/Ethernet/Client.cpp +++ b/libraries/Ethernet/Client.cpp @@ -16,7 +16,7 @@ uint16_t Client::_srcport = 1024; Client::Client(uint8_t sock) : _sock(sock) { } -Client::Client(uint8_t *ip, uint16_t port) : _ip(ip), _port(port), _sock(MAX_SOCK_NUM) { +Client::Client(IPAddress& ip, uint16_t port) : _ip(ip), _port(port), _sock(MAX_SOCK_NUM) { } uint8_t Client::connect() { @@ -38,7 +38,7 @@ uint8_t Client::connect() { if (_srcport == 0) _srcport = 1024; socket(_sock, SnMR::TCP, _srcport, 0); - if (!::connect(_sock, _ip, _port)) { + if (!::connect(_sock, _ip.raw_address(), _port)) { _sock = MAX_SOCK_NUM; return 0; } diff --git a/libraries/Ethernet/Client.h b/libraries/Ethernet/Client.h index 8725f158a..e92e90e33 100644 --- a/libraries/Ethernet/Client.h +++ b/libraries/Ethernet/Client.h @@ -7,8 +7,8 @@ class Client : public Stream { public: Client(); - Client(uint8_t); - Client(uint8_t *, uint16_t); + Client(uint8_t sock); + Client(IPAddress& ip, uint16_t port); uint8_t status(); uint8_t connect(); @@ -31,7 +31,7 @@ public: private: static uint16_t _srcport; uint8_t _sock; - uint8_t *_ip; + IPAddress _ip; uint16_t _port; }; diff --git a/libraries/Ethernet/Dhcp.cpp b/libraries/Ethernet/Dhcp.cpp new file mode 100755 index 000000000..8264b435b --- /dev/null +++ b/libraries/Ethernet/Dhcp.cpp @@ -0,0 +1,341 @@ +// DHCP Library v0.3 - April 25, 2009 +// Author: Jordan Terrell - blog.jordanterrell.com + +#include "w5100.h" + +#include +#include +#include "Dhcp.h" +#include "wiring.h" +#include "util.h" + +int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout) +{ + uint8_t dhcp_state = STATE_DHCP_START; + uint8_t messageType = 0; + + // zero out _dhcpMacAddr, _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp + memset(_dhcpMacAddr, 0, 26); + + memcpy((void*)_dhcpMacAddr, (void*)mac, 6); + + // Pick an initial transaction ID + _dhcpTransactionId = random(1UL, 2000UL); + _dhcpInitialTransactionId = _dhcpTransactionId; + + if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0) + { + // Couldn't get a socket + return 0; + } + + presend_DHCP(); + + int result = 0; + + unsigned long startTime = millis(); + + while(dhcp_state != STATE_DHCP_LEASED) + { + if(dhcp_state == STATE_DHCP_START) + { + _dhcpTransactionId++; + + send_DHCP_MESSAGE(DHCP_DISCOVER, ((millis() - startTime) / 1000)); + dhcp_state = STATE_DHCP_DISCOVER; + } + else if(dhcp_state == STATE_DHCP_DISCOVER) + { + uint32_t respId; + messageType = parseDHCPResponse(responseTimeout, respId); + if(messageType == DHCP_OFFER) + { + // We'll use the transaction ID that the offer came with, + // rather than the one we were up to + _dhcpTransactionId = respId; + send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime) / 1000)); + dhcp_state = STATE_DHCP_REQUEST; + } + } + else if(dhcp_state == STATE_DHCP_REQUEST) + { + uint32_t respId; + messageType = parseDHCPResponse(responseTimeout, respId); + if(messageType == DHCP_ACK) + { + dhcp_state = STATE_DHCP_LEASED; + result = 1; + } + else if(messageType == DHCP_NAK) + dhcp_state = STATE_DHCP_START; + } + + if(messageType == 255) + { + messageType = 0; + dhcp_state = STATE_DHCP_START; + } + + if(result != 1 && ((millis() - startTime) > timeout)) + break; + } + + // We're done with the socket now + _dhcpUdpSocket.stop(); + _dhcpTransactionId++; + + return result; +} + +void DhcpClass::presend_DHCP() +{ +} + +void DhcpClass::send_DHCP_MESSAGE(uint8_t messageType, uint16_t secondsElapsed) +{ + uint8_t buffer[32]; + memset(buffer, 0, 32); + IPAddress dest_addr( 255, 255, 255, 255 ); // Broadcast address + + if (-1 == _dhcpUdpSocket.beginPacket(dest_addr, DHCP_SERVER_PORT)) + { + // FIXME Need to return errors + return; + } + + buffer[0] = DHCP_BOOTREQUEST; // op + buffer[1] = DHCP_HTYPE10MB; // htype + buffer[2] = DHCP_HLENETHERNET; // hlen + buffer[3] = DHCP_HOPS; // hops + + // xid + unsigned long xid = htonl(_dhcpTransactionId); + memcpy(buffer + 4, &(xid), 4); + + // 8, 9 - seconds elapsed + buffer[8] = ((secondsElapsed & 0xff00) >> 8); + buffer[9] = (secondsElapsed & 0x00ff); + + // flags + unsigned short flags = htons(DHCP_FLAGSBROADCAST); + memcpy(buffer + 10, &(flags), 2); + + // ciaddr: already zeroed + // yiaddr: already zeroed + // siaddr: already zeroed + // giaddr: already zeroed + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 28); + + memset(buffer, 0, 32); // clear local buffer + + memcpy(buffer, _dhcpMacAddr, 6); // chaddr + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 16); + + memset(buffer, 0, 32); // clear local buffer + + // leave zeroed out for sname && file + // put in W5100 transmit buffer x 6 (192 bytes) + + for(int i = 0; i < 6; i++) { + _dhcpUdpSocket.write(buffer, 32); + } + + // OPT - Magic Cookie + buffer[0] = (uint8_t)((MAGIC_COOKIE >> 24)& 0xFF); + buffer[1] = (uint8_t)((MAGIC_COOKIE >> 16)& 0xFF); + buffer[2] = (uint8_t)((MAGIC_COOKIE >> 8)& 0xFF); + buffer[3] = (uint8_t)(MAGIC_COOKIE& 0xFF); + + // OPT - message type + buffer[4] = dhcpMessageType; + buffer[5] = 0x01; + buffer[6] = messageType; //DHCP_REQUEST; + + // OPT - client identifier + buffer[7] = dhcpClientIdentifier; + buffer[8] = 0x07; + buffer[9] = 0x01; + memcpy(buffer + 10, _dhcpMacAddr, 6); + + // OPT - host name + buffer[16] = hostName; + buffer[17] = strlen(HOST_NAME) + 3; // length of hostname + last 3 bytes of mac address + strcpy((char*)&(buffer[18]), HOST_NAME); + + buffer[24] = _dhcpMacAddr[3]; + buffer[25] = _dhcpMacAddr[4]; + buffer[26] = _dhcpMacAddr[5]; + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 27); + + if(messageType == DHCP_REQUEST) + { + buffer[0] = dhcpRequestedIPaddr; + buffer[1] = 0x04; + buffer[2] = _dhcpLocalIp[0]; + buffer[3] = _dhcpLocalIp[1]; + buffer[4] = _dhcpLocalIp[2]; + buffer[5] = _dhcpLocalIp[3]; + + buffer[6] = dhcpServerIdentifier; + buffer[7] = 0x04; + buffer[8] = _dhcpDhcpServerIp[0]; + buffer[9] = _dhcpDhcpServerIp[1]; + buffer[10] = _dhcpDhcpServerIp[2]; + buffer[11] = _dhcpDhcpServerIp[3]; + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 12); + } + + buffer[0] = dhcpParamRequest; + buffer[1] = 0x06; + buffer[2] = subnetMask; + buffer[3] = routersOnSubnet; + buffer[4] = dns; + buffer[5] = domainName; + buffer[6] = dhcpT1value; + buffer[7] = dhcpT2value; + buffer[8] = endOption; + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 9); + + _dhcpUdpSocket.endPacket(); +} + +uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId) +{ + uint8_t type = 0; + uint8_t opt_len = 0; + + unsigned long startTime = millis(); + + while(_dhcpUdpSocket.parsePacket() <= 0) + { + if((millis() - startTime) > responseTimeout) + { + return 255; + } + delay(50); + } + // start reading in the packet + RIP_MSG_FIXED fixedMsg; + _dhcpUdpSocket.read((uint8_t*)&fixedMsg, sizeof(RIP_MSG_FIXED)); + + if(fixedMsg.op == DHCP_BOOTREPLY && _dhcpUdpSocket.remotePort() == DHCP_SERVER_PORT) + { + transactionId = ntohl(fixedMsg.xid); + if(memcmp(fixedMsg.chaddr, _dhcpMacAddr, 6) != 0 || (transactionId < _dhcpInitialTransactionId) || (transactionId > _dhcpTransactionId)) + { + // Need to read the rest of the packet here regardless + _dhcpUdpSocket.flush(); + return 0; + } + + memcpy(_dhcpLocalIp, fixedMsg.yiaddr, 4); + + // Skip to the option part + // Doing this a byte at a time so we don't have to put a big buffer + // on the stack (as we don't have lots of memory lying around) + for (int i =0; i < (240 - sizeof(RIP_MSG_FIXED)); i++) + { + _dhcpUdpSocket.read(); // we don't care about the returned byte + } + + while (_dhcpUdpSocket.available() > 0) + { + switch (_dhcpUdpSocket.read()) + { + case endOption : + break; + + case padOption : + break; + + case dhcpMessageType : + opt_len = _dhcpUdpSocket.read(); + type = _dhcpUdpSocket.read(); + break; + + case subnetMask : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read(_dhcpSubnetMask, 4); + break; + + case routersOnSubnet : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read(_dhcpGatewayIp, 4); + break; + + case dns : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read(_dhcpDnsServerIp, 4); + break; + + case dhcpServerIdentifier : + opt_len = _dhcpUdpSocket.read(); + if( *((uint32_t*)_dhcpDhcpServerIp) == 0 || + IPAddress(_dhcpDhcpServerIp) == _dhcpUdpSocket.remoteIP() ) + { + _dhcpUdpSocket.read(_dhcpDhcpServerIp, sizeof(_dhcpDhcpServerIp)); + } + else + { + // Skip over the rest of this option + while (opt_len--) + { + _dhcpUdpSocket.read(); + } + } + break; + + case dhcpIPaddrLeaseTime : + default : + opt_len = _dhcpUdpSocket.read(); + // Skip over the rest of this option + while (opt_len--) + { + _dhcpUdpSocket.read(); + } + break; + } + } + } + + // Need to skip to end of the packet regardless here + _dhcpUdpSocket.flush(); + + return type; +} + +IPAddress DhcpClass::getLocalIp() +{ + return IPAddress(_dhcpLocalIp); +} + +IPAddress DhcpClass::getSubnetMask() +{ + return IPAddress(_dhcpSubnetMask); +} + +IPAddress DhcpClass::getGatewayIp() +{ + return IPAddress(_dhcpGatewayIp); +} + +IPAddress DhcpClass::getDhcpServerIp() +{ + return IPAddress(_dhcpDhcpServerIp); +} + +IPAddress DhcpClass::getDnsServerIp() +{ + return IPAddress(_dhcpDnsServerIp); +} + diff --git a/libraries/Ethernet/Dhcp.h b/libraries/Ethernet/Dhcp.h new file mode 100755 index 000000000..c0034940c --- /dev/null +++ b/libraries/Ethernet/Dhcp.h @@ -0,0 +1,158 @@ +// DHCP Library v0.3 - April 25, 2009 +// Author: Jordan Terrell - blog.jordanterrell.com + +#ifndef Dhcp_h +#define Dhcp_h + +#include "Udp.h" + +/* DHCP state machine. */ +#define STATE_DHCP_START 0 +#define STATE_DHCP_DISCOVER 1 +#define STATE_DHCP_REQUEST 2 +#define STATE_DHCP_LEASED 3 +#define STATE_DHCP_REREQUEST 4 +#define STATE_DHCP_RELEASE 5 + +#define DHCP_FLAGSBROADCAST 0x8000 + +/* UDP port numbers for DHCP */ +#define DHCP_SERVER_PORT 67 /* from server to client */ +#define DHCP_CLIENT_PORT 68 /* from client to server */ + +/* DHCP message OP code */ +#define DHCP_BOOTREQUEST 1 +#define DHCP_BOOTREPLY 2 + +/* DHCP message type */ +#define DHCP_DISCOVER 1 +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 +#define DHCP_ACK 5 +#define DHCP_NAK 6 +#define DHCP_RELEASE 7 +#define DHCP_INFORM 8 + +#define DHCP_HTYPE10MB 1 +#define DHCP_HTYPE100MB 2 + +#define DHCP_HLENETHERNET 6 +#define DHCP_HOPS 0 +#define DHCP_SECS 0 + +#define MAGIC_COOKIE 0x63825363 +#define MAX_DHCP_OPT 16 + +#define HOST_NAME "WIZnet" + +enum +{ + padOption = 0, + subnetMask = 1, + timerOffset = 2, + routersOnSubnet = 3, + /* timeServer = 4, + nameServer = 5,*/ + dns = 6, + /*logServer = 7, + cookieServer = 8, + lprServer = 9, + impressServer = 10, + resourceLocationServer = 11,*/ + hostName = 12, + /*bootFileSize = 13, + meritDumpFile = 14,*/ + domainName = 15, + /*swapServer = 16, + rootPath = 17, + extentionsPath = 18, + IPforwarding = 19, + nonLocalSourceRouting = 20, + policyFilter = 21, + maxDgramReasmSize = 22, + defaultIPTTL = 23, + pathMTUagingTimeout = 24, + pathMTUplateauTable = 25, + ifMTU = 26, + allSubnetsLocal = 27, + broadcastAddr = 28, + performMaskDiscovery = 29, + maskSupplier = 30, + performRouterDiscovery = 31, + routerSolicitationAddr = 32, + staticRoute = 33, + trailerEncapsulation = 34, + arpCacheTimeout = 35, + ethernetEncapsulation = 36, + tcpDefaultTTL = 37, + tcpKeepaliveInterval = 38, + tcpKeepaliveGarbage = 39, + nisDomainName = 40, + nisServers = 41, + ntpServers = 42, + vendorSpecificInfo = 43, + netBIOSnameServer = 44, + netBIOSdgramDistServer = 45, + netBIOSnodeType = 46, + netBIOSscope = 47, + xFontServer = 48, + xDisplayManager = 49,*/ + dhcpRequestedIPaddr = 50, + dhcpIPaddrLeaseTime = 51, + /*dhcpOptionOverload = 52,*/ + dhcpMessageType = 53, + dhcpServerIdentifier = 54, + dhcpParamRequest = 55, + /*dhcpMsg = 56, + dhcpMaxMsgSize = 57,*/ + dhcpT1value = 58, + dhcpT2value = 59, + /*dhcpClassIdentifier = 60,*/ + dhcpClientIdentifier = 61, + endOption = 255 +}; + +typedef struct _RIP_MSG_FIXED +{ + uint8_t op; + uint8_t htype; + uint8_t hlen; + uint8_t hops; + uint32_t xid; + uint16_t secs; + uint16_t flags; + uint8_t ciaddr[4]; + uint8_t yiaddr[4]; + uint8_t siaddr[4]; + uint8_t giaddr[4]; + uint8_t chaddr[6]; +}RIP_MSG_FIXED; + +class DhcpClass { +private: + uint32_t _dhcpInitialTransactionId; + uint32_t _dhcpTransactionId; + uint8_t _dhcpMacAddr[6]; + uint8_t _dhcpLocalIp[4]; + uint8_t _dhcpSubnetMask[4]; + uint8_t _dhcpGatewayIp[4]; + uint8_t _dhcpDhcpServerIp[4]; + uint8_t _dhcpDnsServerIp[4]; + UDP _dhcpUdpSocket; + + void presend_DHCP(); + void send_DHCP_MESSAGE(uint8_t, uint16_t); + + uint8_t parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId); +public: + IPAddress getLocalIp(); + IPAddress getSubnetMask(); + IPAddress getGatewayIp(); + IPAddress getDhcpServerIp(); + IPAddress getDnsServerIp(); + + int beginWithDHCP(uint8_t *, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); +}; + +#endif diff --git a/libraries/Ethernet/Ethernet.cpp b/libraries/Ethernet/Ethernet.cpp index 91cbacd39..937f5b4f9 100644 --- a/libraries/Ethernet/Ethernet.cpp +++ b/libraries/Ethernet/Ethernet.cpp @@ -1,5 +1,6 @@ #include "w5100.h" #include "Ethernet.h" +#include "Dhcp.h" // XXX: don't make assumptions about the value of MAX_SOCK_NUM. uint8_t EthernetClass::_state[MAX_SOCK_NUM] = { @@ -7,30 +8,78 @@ uint8_t EthernetClass::_state[MAX_SOCK_NUM] = { uint16_t EthernetClass::_server_port[MAX_SOCK_NUM] = { 0, 0, 0, 0 }; -void EthernetClass::begin(uint8_t *mac, uint8_t *ip) +int EthernetClass::begin(uint8_t *mac_address) { - uint8_t gateway[4]; - gateway[0] = ip[0]; - gateway[1] = ip[1]; - gateway[2] = ip[2]; + DhcpClass dhcp; + + // Initialise the basic info + W5100.init(); + W5100.setMACAddress(mac_address); + W5100.setIPAddress(IPAddress(0,0,0,0).raw_address()); + + // Now try to get our config info from a DHCP server + int ret = dhcp.beginWithDHCP(mac_address); + if(ret == 1) + { + // We've successfully found a DHCP server and got our configuration info, so set things + // accordingly + W5100.setIPAddress(dhcp.getLocalIp().raw_address()); + W5100.setGatewayIp(dhcp.getGatewayIp().raw_address()); + W5100.setSubnetMask(dhcp.getSubnetMask().raw_address()); + _dnsServerAddress = dhcp.getDnsServerIp(); + } + + return ret; +} + +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip) +{ + // Assume the gateway will be the machine on the same network as the local IP + // but with last octet being '1' + IPAddress gateway = local_ip; gateway[3] = 1; - begin(mac, ip, gateway); + begin(mac_address, local_ip, gateway); } -void EthernetClass::begin(uint8_t *mac, uint8_t *ip, uint8_t *gateway) +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress gateway) { - uint8_t subnet[] = { - 255, 255, 255, 0 }; - begin(mac, ip, gateway, subnet); + IPAddress subnet(255, 255, 255, 0); + begin(mac_address, local_ip, gateway, subnet); } -void EthernetClass::begin(uint8_t *mac, uint8_t *ip, uint8_t *gateway, uint8_t *subnet) +void EthernetClass::begin(uint8_t *mac, IPAddress local_ip, IPAddress gateway, IPAddress subnet) { W5100.init(); W5100.setMACAddress(mac); - W5100.setIPAddress(ip); - W5100.setGatewayIp(gateway); - W5100.setSubnetMask(subnet); + W5100.setIPAddress(local_ip._address); + W5100.setGatewayIp(gateway._address); + W5100.setSubnetMask(subnet._address); +} + +IPAddress EthernetClass::localIP() +{ + IPAddress ret; + W5100.getIPAddress(ret.raw_address()); + return ret; +} + +IPAddress EthernetClass::subnetMask() +{ + IPAddress ret; + W5100.getSubnetMask(ret.raw_address()); + return ret; +} + +IPAddress EthernetClass::gatewayIP() +{ + IPAddress ret; + W5100.getGatewayIp(ret.raw_address()); + return ret; +} + +IPAddress EthernetClass::dnsServerIP() +{ + return _dnsServerAddress; } EthernetClass Ethernet; diff --git a/libraries/Ethernet/Ethernet.h b/libraries/Ethernet/Ethernet.h index a91f1aa17..fdf0b7f39 100644 --- a/libraries/Ethernet/Ethernet.h +++ b/libraries/Ethernet/Ethernet.h @@ -3,6 +3,7 @@ #include //#include "w5100.h" +#include "IPAddress.h" #include "Client.h" #include "Server.h" @@ -10,12 +11,23 @@ class EthernetClass { private: + IPAddress _dnsServerAddress; public: static uint8_t _state[MAX_SOCK_NUM]; static uint16_t _server_port[MAX_SOCK_NUM]; - void begin(uint8_t *, uint8_t *); - void begin(uint8_t *, uint8_t *, uint8_t *); - void begin(uint8_t *, uint8_t *, uint8_t *, uint8_t *); + // Initialise the Ethernet shield to use the provided MAC address and gain the rest of the + // configuration through DHCP. + // Returns 0 if the DHCP configuration failed, and 1 if it succeeded + int begin(uint8_t *mac_address); + void begin(uint8_t *mac_address, IPAddress local_ip); + void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress gateway); + void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress gateway, IPAddress subnet); + + IPAddress localIP(); + IPAddress subnetMask(); + IPAddress gatewayIP(); + IPAddress dnsServerIP(); + friend class Client; friend class Server; }; diff --git a/libraries/Ethernet/IPAddress.cpp b/libraries/Ethernet/IPAddress.cpp index 389329de0..408d518a0 100644 --- a/libraries/Ethernet/IPAddress.cpp +++ b/libraries/Ethernet/IPAddress.cpp @@ -37,3 +37,8 @@ IPAddress& IPAddress::operator=(uint32_t address) return *this; } +bool IPAddress::operator==(const uint8_t* addr) +{ + return memcmp(addr, _address, sizeof(_address)) == 0; +} + diff --git a/libraries/Ethernet/IPAddress.h b/libraries/Ethernet/IPAddress.h index 586385320..1d19bbd22 100644 --- a/libraries/Ethernet/IPAddress.h +++ b/libraries/Ethernet/IPAddress.h @@ -31,6 +31,11 @@ class IPAddress { private: uint8_t _address[4]; // IPv4 address + // Access the raw byte array containing the address. Because this returns a pointer + // to the internal structure rather than a copy of the address this function should only + // be used when you know that the usage of the returned uint8_t* will be transient and not + // stored. + uint8_t* raw_address() { return _address; }; public: // Constructors @@ -41,7 +46,9 @@ public: // Overloaded cast operator to allow IPAddress objects to be used where a pointer // to a four-byte uint8_t array is expected - operator uint8_t*() { return _address; }; + operator uint32_t() { return *((uint32_t*)_address); }; + bool operator==(const IPAddress& addr) { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); }; + bool operator==(const uint8_t* addr); // Overloaded index operator to allow getting and setting individual octets of the address uint8_t operator[](int index) const { return _address[index]; }; @@ -50,6 +57,12 @@ public: // Overloaded copy operators to allow initialisation of IPAddress objects from other types IPAddress& operator=(const uint8_t *address); IPAddress& operator=(uint32_t address); + + friend class EthernetClass; + friend class UDP; + friend class Client; + friend class Server; + friend class DhcpClass; }; #endif diff --git a/libraries/Ethernet/Udp.cpp b/libraries/Ethernet/Udp.cpp index 6ad8aca7e..a8c98c3f4 100644 --- a/libraries/Ethernet/Udp.cpp +++ b/libraries/Ethernet/Udp.cpp @@ -77,7 +77,7 @@ void UDP::stop() int UDP::beginPacket(IPAddress ip, uint16_t port) { _offset = 0; - return startUDP(_sock, ip, port); + return startUDP(_sock, ip.raw_address(), port); } int UDP::endPacket() diff --git a/libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.pde b/libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.pde index a58433fed..3f43d96db 100644 --- a/libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.pde +++ b/libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.pde @@ -31,12 +31,9 @@ byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // assign an IP address for the controller: -byte ip[] = { - 192,168,1,20 }; -byte gateway[] = { - 192,168,1,1}; -byte subnet[] = { - 255, 255, 255, 0 }; +IPAddress ip(192,168,1,20); +IPAddress gateway(192,168,1,1); +IPAddress subnet(255, 255, 255, 0); // Initialize the Ethernet server library diff --git a/libraries/Ethernet/examples/ChatServer/ChatServer.pde b/libraries/Ethernet/examples/ChatServer/ChatServer.pde index 50ae01408..8267a5dd4 100644 --- a/libraries/Ethernet/examples/ChatServer/ChatServer.pde +++ b/libraries/Ethernet/examples/ChatServer/ChatServer.pde @@ -24,9 +24,9 @@ // The IP address will be dependent on your local network. // gateway and subnet are optional: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; -byte ip[] = { 192,168,1, 177 }; -byte gateway[] = { 192,168,1, 1 }; -byte subnet[] = { 255, 255, 0, 0 }; +IPAddress ip(192,168,1, 177); +IPAddress gateway(192,168,1, 1); +IPAddress subnet(255, 255, 0, 0); // telnet defaults to port 23 Server server(23); @@ -60,4 +60,4 @@ void loop() { // echo the bytes to the server as well: Serial.print(thisChar); } -} \ No newline at end of file +} diff --git a/libraries/Ethernet/examples/PachubeClient/PachubeClient.pde b/libraries/Ethernet/examples/PachubeClient/PachubeClient.pde index fe94541e1..687fa437e 100644 --- a/libraries/Ethernet/examples/PachubeClient/PachubeClient.pde +++ b/libraries/Ethernet/examples/PachubeClient/PachubeClient.pde @@ -23,20 +23,13 @@ #include // assign a MAC address for the ethernet controller. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield // fill in your address here: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; -// assign an IP address for the controller: -byte ip[] = { - 192,169,1,20 }; -byte gateway[] = { - 192,168,1,1}; -byte subnet[] = { - 255, 255, 255, 0 }; // The address of the server you want to connect to (pachube.com): -byte server[] = { - 209,40,205,190 }; +IPAddress server(209,40,205,190); // initialize the library instance: Client client(server, 80); @@ -46,9 +39,15 @@ boolean lastConnected = false; // state of the connection last time through const int postingInterval = 10000; //delay between updates to Pachube.com void setup() { - // start the ethernet connection and serial port: - Ethernet.begin(mac, ip); + // start serial port: Serial.begin(9600); + // start the Ethernet connection: + if (Ethernet.begin(mac) == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // no point in carrying on, so do nothing forevermore: + for(;;) + ; + } // give the ethernet module time to boot up: delay(1000); } diff --git a/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.pde b/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.pde index 225823ac1..0db6e219a 100644 --- a/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.pde +++ b/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.pde @@ -29,16 +29,12 @@ byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // assign an IP address for the controller: -byte ip[] = { - 192,169,1,20 }; -byte gateway[] = { - 192,168,1,1}; -byte subnet[] = { - 255, 255, 255, 0 }; +IPAddress ip(192,169,1,20); +IPAddress gateway(192,168,1,1); +IPAddress subnet(255, 255, 255, 0); // The address of the server you want to connect to (pachube.com): -byte server[] = { - 209,40,205,190 }; +IPAddress server(209,40,205,190); // initialize the library instance: Client client(server, 80); diff --git a/libraries/Ethernet/examples/TelnetClient/TelnetClient.pde b/libraries/Ethernet/examples/TelnetClient/TelnetClient.pde index aca1fa9ad..95756d076 100644 --- a/libraries/Ethernet/examples/TelnetClient/TelnetClient.pde +++ b/libraries/Ethernet/examples/TelnetClient/TelnetClient.pde @@ -24,12 +24,10 @@ // The IP address will be dependent on your local network: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; -byte ip[] = { - 192,168,1,177 }; +IPAddress ip(192,168,1,177); // Enter the IP address of the server you're connecting to: -byte server[] = { - 1,1,1,1 }; +IPAddress server(1,1,1,1); // Initialize the Ethernet client library // with the IP address and port of the server diff --git a/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.pde b/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.pde index cfb5a2bc1..7c2d3ea9e 100644 --- a/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.pde +++ b/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.pde @@ -20,13 +20,11 @@ #include #include -// Enter a MAC address and IP address for your controller below. -// The IP address will be dependent on your local network: +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; -IPAddress ip(192, 168, 1, 177); - unsigned int localPort = 8888; // local port to listen for UDP packets IPAddress timeServer(192, 43, 244, 18); // time.nist.gov NTP server @@ -40,11 +38,16 @@ UDP Udp; void setup() { - // start Ethernet and UDP - Ethernet.begin(mac,ip); - Udp.begin(localPort); - Serial.begin(9600); + + // start Ethernet and UDP + if (Ethernet.begin(mac) == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // no point in carrying on, so do nothing forevermore: + for(;;) + ; + } + Udp.begin(localPort); } void loop() @@ -99,7 +102,7 @@ void loop() } // send an NTP request to the time server at the given address -unsigned long sendNTPpacket(byte *address) +unsigned long sendNTPpacket(IPAddress& address) { // set all bytes in the buffer to 0 memset(packetBuffer, 0, NTP_PACKET_SIZE); diff --git a/libraries/Ethernet/examples/WebClient/WebClient.pde b/libraries/Ethernet/examples/WebClient/WebClient.pde index a2d350311..74d34e0ce 100644 --- a/libraries/Ethernet/examples/WebClient/WebClient.pde +++ b/libraries/Ethernet/examples/WebClient/WebClient.pde @@ -15,11 +15,10 @@ #include #include -// Enter a MAC address and IP address for your controller below. -// The IP address will be dependent on your local network: +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; -byte ip[] = { 192,168,1,177 }; -byte server[] = { 173,194,33,104 }; // Google +IPAddress server(173,194,33,104); // Google // Initialize the Ethernet client library // with the IP address and port of the server @@ -27,10 +26,15 @@ byte server[] = { 173,194,33,104 }; // Google Client client(server, 80); void setup() { - // start the Ethernet connection: - Ethernet.begin(mac, ip); // start the serial library: Serial.begin(9600); + // start the Ethernet connection: + if (Ethernet.begin(mac) == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // no point in carrying on, so do nothing forevermore: + for(;;) + ; + } // give the Ethernet shield a second to initialize: delay(1000); Serial.println("connecting..."); diff --git a/libraries/Ethernet/examples/WebServer/WebServer.pde b/libraries/Ethernet/examples/WebServer/WebServer.pde index 77bcb204e..c69a56a40 100644 --- a/libraries/Ethernet/examples/WebServer/WebServer.pde +++ b/libraries/Ethernet/examples/WebServer/WebServer.pde @@ -21,7 +21,7 @@ // Enter a MAC address and IP address for your controller below. // The IP address will be dependent on your local network: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; -byte ip[] = { 192,168,1, 177 }; +IPAddress ip(192,168,1, 177); // Initialize the Ethernet server library // with the IP address and port you want to use @@ -79,4 +79,4 @@ void loop() // close the connection: client.stop(); } -} \ No newline at end of file +} diff --git a/libraries/Ethernet/util.h b/libraries/Ethernet/util.h new file mode 100644 index 000000000..220011b8f --- /dev/null +++ b/libraries/Ethernet/util.h @@ -0,0 +1,13 @@ +#ifndef UTIL_H +#define UTIL_H + +#define htons(x) ( (x)<<8 | ((x)>>8)&0xFF ) +#define ntohs(x) htons(x) + +#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \ + ((x)<< 8 & 0x00FF0000UL) | \ + ((x)>> 8 & 0x0000FF00UL) | \ + ((x)>>24 & 0x000000FFUL) ) +#define ntohl(x) htonl(x) + +#endif From a310cb8e4dad410af717e3fe9502fc3f98127892 Mon Sep 17 00:00:00 2001 From: amcewen Date: Tue, 25 Jan 2011 16:29:38 +0000 Subject: [PATCH 04/17] Proposed fix for issue 243, adding DNS to the Ethernet library. Uses a slightly modified version of the agreed API as the host/port parameters have been moved from the Client constructor to the Client::connect methods. This means it's possible for errors to be returned if the DNS lookup fails and also reduces the RAM footprint of the Client class as it no longer needs to store the host/port for later use in Client::connect. --- libraries/Ethernet/Client.cpp | 22 +- libraries/Ethernet/Client.h | 6 +- libraries/Ethernet/Dns.cpp | 423 ++++++++++++++++++ libraries/Ethernet/Dns.h | 41 ++ libraries/Ethernet/IPAddress.h | 4 + .../examples/PachubeClient/PachubeClient.pde | 7 +- .../PachubeClientString.pde | 18 +- .../examples/TelnetClient/TelnetClient.pde | 4 +- .../Ethernet/examples/WebClient/WebClient.pde | 4 +- 9 files changed, 503 insertions(+), 26 deletions(-) create mode 100644 libraries/Ethernet/Dns.cpp create mode 100644 libraries/Ethernet/Dns.h diff --git a/libraries/Ethernet/Client.cpp b/libraries/Ethernet/Client.cpp index 7ae55d08d..8a525ca7e 100644 --- a/libraries/Ethernet/Client.cpp +++ b/libraries/Ethernet/Client.cpp @@ -10,16 +10,32 @@ extern "C" { #include "Ethernet.h" #include "Client.h" #include "Server.h" +#include "Dns.h" uint16_t Client::_srcport = 1024; +Client::Client() : _sock(MAX_SOCK_NUM) { +} + Client::Client(uint8_t sock) : _sock(sock) { } -Client::Client(IPAddress& ip, uint16_t port) : _ip(ip), _port(port), _sock(MAX_SOCK_NUM) { +int Client::connect(const char* host, uint16_t port) { + // Look up the host first + int ret = 0; + DNSClient dns; + IPAddress remote_addr; + + dns.begin(Ethernet.dnsServerIP()); + ret = dns.getHostByName(host, remote_addr); + if (ret == 1) { + return connect(remote_addr, port); + } else { + return ret; + } } -uint8_t Client::connect() { +int Client::connect(IPAddress ip, uint16_t port) { if (_sock != MAX_SOCK_NUM) return 0; @@ -38,7 +54,7 @@ uint8_t Client::connect() { if (_srcport == 0) _srcport = 1024; socket(_sock, SnMR::TCP, _srcport, 0); - if (!::connect(_sock, _ip.raw_address(), _port)) { + if (!::connect(_sock, ip.raw_address(), port)) { _sock = MAX_SOCK_NUM; return 0; } diff --git a/libraries/Ethernet/Client.h b/libraries/Ethernet/Client.h index e92e90e33..23a8f1860 100644 --- a/libraries/Ethernet/Client.h +++ b/libraries/Ethernet/Client.h @@ -8,10 +8,10 @@ class Client : public Stream { public: Client(); Client(uint8_t sock); - Client(IPAddress& ip, uint16_t port); uint8_t status(); - uint8_t connect(); + int connect(IPAddress ip, uint16_t port); + int connect(const char *host, uint16_t port); virtual void write(uint8_t); virtual void write(const char *str); virtual void write(const uint8_t *buf, size_t size); @@ -31,8 +31,6 @@ public: private: static uint16_t _srcport; uint8_t _sock; - IPAddress _ip; - uint16_t _port; }; #endif diff --git a/libraries/Ethernet/Dns.cpp b/libraries/Ethernet/Dns.cpp new file mode 100644 index 000000000..3a31e35a4 --- /dev/null +++ b/libraries/Ethernet/Dns.cpp @@ -0,0 +1,423 @@ +// Arduino DNS client for WizNet5100-based Ethernet shield +// (c) Copyright 2009-2010 MCQN Ltd. +// Released under Apache License, version 2.0 + +#include "w5100.h" +#include "Udp.h" +#include "util.h" + +#include "Dns.h" +#include +//#include +#include "wiring.h" + + +#define SOCKET_NONE 255 +// Various flags and header field values for a DNS message +#define UDP_HEADER_SIZE 8 +#define DNS_HEADER_SIZE 12 +#define TTL_SIZE 4 +#define QUERY_FLAG (0) +#define RESPONSE_FLAG (1<<15) +#define QUERY_RESPONSE_MASK (1<<15) +#define OPCODE_STANDARD_QUERY (0) +#define OPCODE_INVERSE_QUERY (1<<11) +#define OPCODE_STATUS_REQUEST (2<<11) +#define OPCODE_MASK (15<<11) +#define AUTHORITATIVE_FLAG (1<<10) +#define TRUNCATION_FLAG (1<<9) +#define RECURSION_DESIRED_FLAG (1<<8) +#define RECURSION_AVAILABLE_FLAG (1<<7) +#define RESP_NO_ERROR (0) +#define RESP_FORMAT_ERROR (1) +#define RESP_SERVER_FAILURE (2) +#define RESP_NAME_ERROR (3) +#define RESP_NOT_IMPLEMENTED (4) +#define RESP_REFUSED (5) +#define RESP_MASK (15) +#define TYPE_A (0x0001) +#define CLASS_IN (0x0001) +#define LABEL_COMPRESSION_MASK (0xC0) +// Port number that DNS servers listen on +#define DNS_PORT 53 + +// Possible return codes from ProcessResponse +#define SUCCESS 1 +#define TIMED_OUT -1 +#define INVALID_SERVER -2 +#define TRUNCATED -3 +#define INVALID_RESPONSE -4 + +void DNSClient::begin(const IPAddress& aDNSServer) +{ + iDNSServer = aDNSServer; + iRequestId = 0; +} + + +int DNSClient::inet_aton(const char* aIPAddrString, IPAddress& aResult) +{ + // See if we've been given a valid IP address + const char* p =aIPAddrString; + while (*p && + ( (*p == '.') || (*p >= '0') || (*p <= '9') )) + { + p++; + } + + if (*p == '\0') + { + // It's looking promising, we haven't found any invalid characters + p = aIPAddrString; + int segment =0; + int segmentValue =0; + while (*p && (segment < 4)) + { + if (*p == '.') + { + // We've reached the end of a segment + if (segmentValue > 255) + { + // You can't have IP address segments that don't fit in a byte + return 0; + } + else + { + aResult[segment] = (byte)segmentValue; + segment++; + segmentValue = 0; + } + } + else + { + // Next digit + segmentValue = (segmentValue*10)+(*p - '0'); + } + p++; + } + // We've reached the end of address, but there'll still be the last + // segment to deal with + if ((segmentValue > 255) || (segment > 3)) + { + // You can't have IP address segments that don't fit in a byte, + // or more than four segments + return 0; + } + else + { + aResult[segment] = (byte)segmentValue; + return 1; + } + } + else + { + return 0; + } +} + +int DNSClient::getHostByName(const char* aHostname, IPAddress& aResult) +{ + int ret =0; + + // See if it's a numeric IP address + if (inet_aton(aHostname, aResult)) + { + // It is, our work here is done + return 1; + } + + // Check we've got a valid DNS server to use + if (iDNSServer == INADDR_NONE) + { + return INVALID_SERVER; + } + + // Find a socket to use + if (iUdp.begin(1024+(millis() & 0xF)) == 1) + { + // Try up to three times + int retries = 0; +// while ((retries < 3) && (ret <= 0)) + { + // Send DNS request + ret = iUdp.beginPacket(iDNSServer, DNS_PORT); + if (ret != 0) + { + // Now output the request data + ret = BuildRequest(aHostname); + if (ret != 0) + { + // And finally send the request + ret = iUdp.endPacket(); + if (ret != 0) + { + // Now wait for a response + int wait_retries = 0; + ret = TIMED_OUT; + while ((wait_retries < 3) && (ret == TIMED_OUT)) + { + ret = ProcessResponse(5000, aResult); + wait_retries++; + } + } + } + } + retries++; + } + + // We're done with the socket now + iUdp.stop(); + } + + return ret; +} + +uint16_t DNSClient::BuildRequest(const char* aName) +{ + // Build header + // 1 1 1 1 1 1 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | ID | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // |QR| Opcode |AA|TC|RD|RA| Z | RCODE | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | QDCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | ANCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | NSCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | ARCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // As we only support one request at a time at present, we can simplify + // some of this header + iRequestId = millis(); // generate a random ID + uint16_t twoByteBuffer; + + // FIXME We should also check that there's enough space available to write to, rather + // FIXME than assume there's enough space (as the code does at present) + iUdp.write((uint8_t*)&iRequestId, sizeof(iRequestId)); + + twoByteBuffer = htons(QUERY_FLAG | OPCODE_STANDARD_QUERY | RECURSION_DESIRED_FLAG); + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + twoByteBuffer = htons(1); // One question record + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + twoByteBuffer = 0; // Zero answer records + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + // and zero additional records + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + // Build question + const char* start =aName; + const char* end =start; + uint8_t len; + // Run through the name being requested + while (*end) + { + // Find out how long this section of the name is + end = start; + while (*end && (*end != '.') ) + { + end++; + } + + if (end-start > 0) + { + // Write out the size of this section + len = end-start; + iUdp.write(&len, sizeof(len)); + // And then write out the section + iUdp.write((uint8_t*)start, end-start); + } + start = end+1; + } + + // We've got to the end of the question name, so + // terminate it with a zero-length section + len = 0; + iUdp.write(&len, sizeof(len)); + // Finally the type and class of question + twoByteBuffer = htons(TYPE_A); + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + twoByteBuffer = htons(CLASS_IN); // Internet class of question + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + // Success! Everything buffered okay + return 1; +} + + +uint16_t DNSClient::ProcessResponse(int aTimeout, IPAddress& aAddress) +{ + uint32_t startTime = millis(); + + // Wait for a response packet + while(iUdp.parsePacket() <= 0) + { + if((millis() - startTime) > aTimeout) + return TIMED_OUT; + delay(50); + } + + // We've had a reply! + // Read the UDP header + uint8_t header[DNS_HEADER_SIZE]; // Enough space to reuse for the DNS header + // Check that it's a response from the right server and the right port + if ( (iDNSServer != iUdp.remoteIP()) || + (iUdp.remotePort() != DNS_PORT) ) + { + // It's not from who we expected + return INVALID_SERVER; + } + + // Read through the rest of the response + if (iUdp.available() < DNS_HEADER_SIZE) + { + return TRUNCATED; + } + iUdp.read(header, DNS_HEADER_SIZE); + + uint16_t header_flags = htons(*((uint16_t*)&header[2])); + // Check that it's a response to this request + if ( ( iRequestId != (*((uint16_t*)&header[0])) ) || + (header_flags & QUERY_RESPONSE_MASK != RESPONSE_FLAG) ) + { + // Mark the entire packet as read + iUdp.flush(); + return INVALID_RESPONSE; + } + // Check for any errors in the response (or in our request) + // although we don't do anything to get round these + if ( (header_flags & TRUNCATION_FLAG) || (header_flags & RESP_MASK) ) + { + // Mark the entire packet as read + iUdp.flush(); + return -5; //INVALID_RESPONSE; + } + + // And make sure we've got (at least) one answer + uint16_t answerCount = htons(*((uint16_t*)&header[6])); + if (answerCount == 0 ) + { + // Mark the entire packet as read + iUdp.flush(); + return -6; //INVALID_RESPONSE; + } + + // Skip over any questions + for (int i =0; i < htons(*((uint16_t*)&header[4])); i++) + { + // Skip over the name + uint8_t len; + do + { + iUdp.read(&len, sizeof(len)); + if (len > 0) + { + // Don't need to actually read the data out for the string, just + // advance ptr to beyond it + while(len--) + { + iUdp.read(); // we don't care about the returned byte + } + } + } while (len != 0); + + // Now jump over the type and class + for (int i =0; i < 4; i++) + { + iUdp.read(); // we don't care about the returned byte + } + } + + // Now we're up to the bit we're interested in, the answer + // There might be more than one answer (although we'll just use the first + // type A answer) and some authority and additional resource records but + // we're going to ignore all of them. + + for (int i =0; i < answerCount; i++) + { + // Skip the name + uint8_t len; + do + { + iUdp.read(&len, sizeof(len)); + if ((len & LABEL_COMPRESSION_MASK) == 0) + { + // It's just a normal label + if (len > 0) + { + // And it's got a length + // Don't need to actually read the data out for the string, + // just advance ptr to beyond it + while(len--) + { + iUdp.read(); // we don't care about the returned byte + } + } + } + else + { + // This is a pointer to a somewhere else in the message for the + // rest of the name. We don't care about the name, and RFC1035 + // says that a name is either a sequence of labels ended with a + // 0 length octet or a pointer or a sequence of labels ending in + // a pointer. Either way, when we get here we're at the end of + // the name + // Skip over the pointer + iUdp.read(); // we don't care about the returned byte + // And set len so that we drop out of the name loop + len = 0; + } + } while (len != 0); + + // Check the type and class + uint16_t answerType; + uint16_t answerClass; + iUdp.read((uint8_t*)&answerType, sizeof(answerType)); + iUdp.read((uint8_t*)&answerClass, sizeof(answerClass)); + + // Ignore the Time-To-Live as we don't do any caching + for (int i =0; i < TTL_SIZE; i++) + { + iUdp.read(); // we don't care about the returned byte + } + + // And read out the length of this answer + // Don't need header_flags anymore, so we can reuse it here + iUdp.read((uint8_t*)&header_flags, sizeof(header_flags)); + + if ( (htons(answerType) == TYPE_A) && (htons(answerClass) == CLASS_IN) ) + { + if (htons(header_flags) != 4) + { + // It's a weird size + // Mark the entire packet as read + iUdp.flush(); + return -9;//INVALID_RESPONSE; + } + iUdp.read(aAddress.raw_address(), 4); + return SUCCESS; + } + else + { + // This isn't an answer type we're after, move onto the next one + for (int i =0; i < htons(header_flags); i++) + { + iUdp.read(); // we don't care about the returned byte + } + } + } + + // Mark the entire packet as read + iUdp.flush(); + + // If we get here then we haven't found an answer + return -10;//INVALID_RESPONSE; +} + diff --git a/libraries/Ethernet/Dns.h b/libraries/Ethernet/Dns.h new file mode 100644 index 000000000..9582351f2 --- /dev/null +++ b/libraries/Ethernet/Dns.h @@ -0,0 +1,41 @@ +// Arduino DNS client for WizNet5100-based Ethernet shield +// (c) Copyright 2009-2010 MCQN Ltd. +// Released under Apache License, version 2.0 + +#ifndef DNSClient_h +#define DNSClient_h + +#include + +class DNSClient +{ +public: + // ctor + void begin(const IPAddress& aDNSServer); + + /** Convert a numeric IP address string into a four-byte IP address. + @param aIPAddrString IP address to convert + @param aResult IPAddress structure to store the returned IP address + @result 1 if aIPAddrString was successfully converted to an IP address, + else error code + */ + int inet_aton(const char *aIPAddrString, IPAddress& aResult); + + /** Resolve the given hostname to an IP address. + @param aHostname Name to be resolved + @param aResult IPAddress structure to store the returned IP address + @result 1 if aIPAddrString was successfully converted to an IP address, + else error code + */ + int getHostByName(const char* aHostname, IPAddress& aResult); + +protected: + uint16_t BuildRequest(const char* aName); + uint16_t ProcessResponse(int aTimeout, IPAddress& aAddress); + + IPAddress iDNSServer; + uint16_t iRequestId; + UDP iUdp; +}; + +#endif diff --git a/libraries/Ethernet/IPAddress.h b/libraries/Ethernet/IPAddress.h index 1d19bbd22..487e420bd 100644 --- a/libraries/Ethernet/IPAddress.h +++ b/libraries/Ethernet/IPAddress.h @@ -63,6 +63,10 @@ public: friend class Client; friend class Server; friend class DhcpClass; + friend class DNSClient; }; +const IPAddress INADDR_NONE(0,0,0,0); + + #endif diff --git a/libraries/Ethernet/examples/PachubeClient/PachubeClient.pde b/libraries/Ethernet/examples/PachubeClient/PachubeClient.pde index 687fa437e..af9bf1f05 100644 --- a/libraries/Ethernet/examples/PachubeClient/PachubeClient.pde +++ b/libraries/Ethernet/examples/PachubeClient/PachubeClient.pde @@ -28,11 +28,8 @@ byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; -// The address of the server you want to connect to (pachube.com): -IPAddress server(209,40,205,190); - // initialize the library instance: -Client client(server, 80); +Client client; long lastConnectionTime = 0; // last time you connected to the server, in milliseconds boolean lastConnected = false; // state of the connection last time through the main loop @@ -85,7 +82,7 @@ void loop() { // this method makes a HTTP connection to the server: void sendData(int thisData) { // if there's a successful connection: - if (client.connect()) { + if (client.connect("www.pachube.com", 80)) { Serial.println("connecting..."); // send the HTTP PUT request. // fill in your feed address here: diff --git a/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.pde b/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.pde index 0db6e219a..e6dbf09ea 100644 --- a/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.pde +++ b/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.pde @@ -28,16 +28,9 @@ // fill in your address here: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; -// assign an IP address for the controller: -IPAddress ip(192,169,1,20); -IPAddress gateway(192,168,1,1); -IPAddress subnet(255, 255, 255, 0); - -// The address of the server you want to connect to (pachube.com): -IPAddress server(209,40,205,190); // initialize the library instance: -Client client(server, 80); +Client client; long lastConnectionTime = 0; // last time you connected to the server, in milliseconds boolean lastConnected = false; // state of the connection last time through the main loop @@ -45,8 +38,13 @@ const int postingInterval = 10000; //delay between updates to Pachube.com void setup() { // start the ethernet connection and serial port: - Ethernet.begin(mac, ip); Serial.begin(9600); + if (Ethernet.begin(mac) == 0) { + Serial.println("Failed to configure Ethernet using DHCP"); + // no point in carrying on, so do nothing forevermore: + for(;;) + ; + } // give the ethernet module time to boot up: delay(1000); } @@ -92,7 +90,7 @@ void loop() { // this method makes a HTTP connection to the server: void sendData(String thisData) { // if there's a successful connection: - if (client.connect()) { + if (client.connect("www.pachube.com", 80)) { Serial.println("connecting..."); // send the HTTP PUT request. // fill in your feed address here: diff --git a/libraries/Ethernet/examples/TelnetClient/TelnetClient.pde b/libraries/Ethernet/examples/TelnetClient/TelnetClient.pde index 95756d076..7502d218d 100644 --- a/libraries/Ethernet/examples/TelnetClient/TelnetClient.pde +++ b/libraries/Ethernet/examples/TelnetClient/TelnetClient.pde @@ -33,7 +33,7 @@ IPAddress server(1,1,1,1); // with the IP address and port of the server // that you want to connect to (port 23 is default for telnet; // if you're using Processing's ChatServer, use port 10002): -Client client(server, 10002); +Client client; void setup() { // start the Ethernet connection: @@ -45,7 +45,7 @@ void setup() { Serial.println("connecting..."); // if you get a connection, report back via serial: - if (client.connect()) { + if (client.connect(server, 10002)) { Serial.println("connected"); } else { diff --git a/libraries/Ethernet/examples/WebClient/WebClient.pde b/libraries/Ethernet/examples/WebClient/WebClient.pde index 74d34e0ce..646c3aadd 100644 --- a/libraries/Ethernet/examples/WebClient/WebClient.pde +++ b/libraries/Ethernet/examples/WebClient/WebClient.pde @@ -23,7 +23,7 @@ IPAddress server(173,194,33,104); // Google // Initialize the Ethernet client library // with the IP address and port of the server // that you want to connect to (port 80 is default for HTTP): -Client client(server, 80); +Client client; void setup() { // start the serial library: @@ -40,7 +40,7 @@ void setup() { Serial.println("connecting..."); // if you get a connection, report back via serial: - if (client.connect()) { + if (client.connect(server, 80)) { Serial.println("connected"); // Make a HTTP request: client.println("GET /search?q=arduino HTTP/1.0"); From 4000c9199b7f91907519a46d692d660012ade090 Mon Sep 17 00:00:00 2001 From: amcewen Date: Fri, 4 Feb 2011 21:15:42 +0000 Subject: [PATCH 05/17] Added new method to UDP to take a hostname rather than an IP address. Part of issue 243 --- libraries/Ethernet/Udp.cpp | 17 +++++++++++++++++ libraries/Ethernet/Udp.h | 3 +++ 2 files changed, 20 insertions(+) diff --git a/libraries/Ethernet/Udp.cpp b/libraries/Ethernet/Udp.cpp index a8c98c3f4..2c8b10332 100644 --- a/libraries/Ethernet/Udp.cpp +++ b/libraries/Ethernet/Udp.cpp @@ -30,6 +30,7 @@ #include "socket.h" #include "Ethernet.h" #include "Udp.h" +#include "Dns.h" /* Constructor */ UDP::UDP() : _sock(MAX_SOCK_NUM) {} @@ -74,6 +75,22 @@ void UDP::stop() _sock = MAX_SOCK_NUM; } +int UDP::beginPacket(const char *host, uint16_t port) +{ + // Look up the host first + int ret = 0; + DNSClient dns; + IPAddress remote_addr; + + dns.begin(Ethernet.dnsServerIP()); + ret = dns.getHostByName(host, remote_addr); + if (ret == 1) { + return beginPacket(remote_addr, port); + } else { + return ret; + } +} + int UDP::beginPacket(IPAddress ip, uint16_t port) { _offset = 0; diff --git a/libraries/Ethernet/Udp.h b/libraries/Ethernet/Udp.h index 8cd3b065a..99df53f15 100644 --- a/libraries/Ethernet/Udp.h +++ b/libraries/Ethernet/Udp.h @@ -60,6 +60,9 @@ public: // Start building up a packet to send to the remote host specific in ip and port // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port int beginPacket(IPAddress ip, uint16_t port); + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + int beginPacket(const char *host, uint16_t port); // Finish off this packet and send it // Returns 1 if the packet was sent successfully, 0 if there was an error int endPacket(); From 7f18110b803609974a3897749d9d1f67ae614fff Mon Sep 17 00:00:00 2001 From: amcewen Date: Fri, 4 Feb 2011 21:44:51 +0000 Subject: [PATCH 06/17] Fixed bug in parsePacket where it could block indefinitely if called when no packets were available to be read. --- libraries/Ethernet/Udp.cpp | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/libraries/Ethernet/Udp.cpp b/libraries/Ethernet/Udp.cpp index 2c8b10332..aed5d983b 100644 --- a/libraries/Ethernet/Udp.cpp +++ b/libraries/Ethernet/Udp.cpp @@ -121,20 +121,25 @@ void UDP::write(const uint8_t *buffer, size_t size) int UDP::parsePacket() { - //HACK - hand-parse the UDP packet using TCP recv method - uint8_t tmpBuf[8]; - int ret =0; - //read 8 header bytes and get IP and port from it - ret = recv(_sock,tmpBuf,8); - if (ret > 0) + if (available() > 0) { - _remoteIP = tmpBuf; - _remotePort = tmpBuf[4]; - _remotePort = (_remotePort << 8) + tmpBuf[5]; - // When we get here, any remaining bytes are the data - ret = available(); + //HACK - hand-parse the UDP packet using TCP recv method + uint8_t tmpBuf[8]; + int ret =0; + //read 8 header bytes and get IP and port from it + ret = recv(_sock,tmpBuf,8); + if (ret > 0) + { + _remoteIP = tmpBuf; + _remotePort = tmpBuf[4]; + _remotePort = (_remotePort << 8) + tmpBuf[5]; + // When we get here, any remaining bytes are the data + ret = available(); + } + return ret; } - return ret; + // There aren't any packets available + return 0; } int UDP::read() From a5f6a42dd7128ba3dc13d25a430f4a5a896d7528 Mon Sep 17 00:00:00 2001 From: amcewen Date: Mon, 28 Mar 2011 12:08:53 +0100 Subject: [PATCH 07/17] Pulled out Client API into a base class to allow multiple derived classes to use it, and moved it (plus IPAddress) out of the Ethernet library so that other libraries can find it. First steps in integrating the WiFly code so it's easier to switch between that and Ethernet --- .../arduino/cores/arduino}/IPAddress.cpp | 0 .../arduino/cores/arduino}/IPAddress.h | 0 hardware/arduino/cores/arduino/NetClient.h | 28 +++++++++++++++++++ libraries/Ethernet/Client.h | 18 ++++++------ 4 files changed, 38 insertions(+), 8 deletions(-) rename {libraries/Ethernet => hardware/arduino/cores/arduino}/IPAddress.cpp (100%) rename {libraries/Ethernet => hardware/arduino/cores/arduino}/IPAddress.h (100%) create mode 100644 hardware/arduino/cores/arduino/NetClient.h diff --git a/libraries/Ethernet/IPAddress.cpp b/hardware/arduino/cores/arduino/IPAddress.cpp similarity index 100% rename from libraries/Ethernet/IPAddress.cpp rename to hardware/arduino/cores/arduino/IPAddress.cpp diff --git a/libraries/Ethernet/IPAddress.h b/hardware/arduino/cores/arduino/IPAddress.h similarity index 100% rename from libraries/Ethernet/IPAddress.h rename to hardware/arduino/cores/arduino/IPAddress.h diff --git a/hardware/arduino/cores/arduino/NetClient.h b/hardware/arduino/cores/arduino/NetClient.h new file mode 100644 index 000000000..d8df9149a --- /dev/null +++ b/hardware/arduino/cores/arduino/NetClient.h @@ -0,0 +1,28 @@ +#ifndef netclient_h +#define netclient_h +#include "WProgram.h" +#include "Print.h" +#include "NetClient.h" +#include "IPAddress.h" + +class NetClient : public Stream { + +public: + virtual int connect(IPAddress ip, uint16_t port) =0; + virtual int connect(const char *host, uint16_t port) =0; + virtual void write(uint8_t) =0; + virtual void write(const char *str) =0; + virtual void write(const uint8_t *buf, size_t size) =0; + virtual int available() = 0; + virtual int read() = 0; + virtual int read(uint8_t *buf, size_t size) = 0; + virtual int peek() = 0; + virtual void flush() = 0; + virtual void stop() = 0; + virtual uint8_t connected() = 0; + virtual uint8_t operator==(int) = 0; + virtual uint8_t operator!=(int) = 0; + virtual operator bool() = 0; +}; + +#endif diff --git a/libraries/Ethernet/Client.h b/libraries/Ethernet/Client.h index 23a8f1860..a4d1589ff 100644 --- a/libraries/Ethernet/Client.h +++ b/libraries/Ethernet/Client.h @@ -2,16 +2,18 @@ #define client_h #include "WProgram.h" #include "Print.h" +#include "NetClient.h" +#include "IPAddress.h" -class Client : public Stream { +class Client : public NetClient { public: Client(); Client(uint8_t sock); uint8_t status(); - int connect(IPAddress ip, uint16_t port); - int connect(const char *host, uint16_t port); + virtual int connect(IPAddress ip, uint16_t port); + virtual int connect(const char *host, uint16_t port); virtual void write(uint8_t); virtual void write(const char *str); virtual void write(const uint8_t *buf, size_t size); @@ -20,11 +22,11 @@ public: virtual int read(uint8_t *buf, size_t size); virtual int peek(); virtual void flush(); - void stop(); - uint8_t connected(); - uint8_t operator==(int); - uint8_t operator!=(int); - operator bool(); + virtual void stop(); + virtual uint8_t connected(); + virtual uint8_t operator==(int); + virtual uint8_t operator!=(int); + virtual operator bool(); friend class Server; From 17d8fcb46d49fc284671d2f124a01e69ce86b0c8 Mon Sep 17 00:00:00 2001 From: amcewen Date: Thu, 31 Mar 2011 16:19:17 +0100 Subject: [PATCH 08/17] Pulled out Server API into the NetServer base class, and a few minor changes to get the NetClient API to work well with the WiFly library --- hardware/arduino/cores/arduino/NetClient.h | 2 -- hardware/arduino/cores/arduino/NetServer.h | 11 +++++++++++ libraries/Ethernet/Server.h | 6 +++--- 3 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 hardware/arduino/cores/arduino/NetServer.h diff --git a/hardware/arduino/cores/arduino/NetClient.h b/hardware/arduino/cores/arduino/NetClient.h index d8df9149a..ea64664e7 100644 --- a/hardware/arduino/cores/arduino/NetClient.h +++ b/hardware/arduino/cores/arduino/NetClient.h @@ -20,8 +20,6 @@ public: virtual void flush() = 0; virtual void stop() = 0; virtual uint8_t connected() = 0; - virtual uint8_t operator==(int) = 0; - virtual uint8_t operator!=(int) = 0; virtual operator bool() = 0; }; diff --git a/hardware/arduino/cores/arduino/NetServer.h b/hardware/arduino/cores/arduino/NetServer.h new file mode 100644 index 000000000..91f484895 --- /dev/null +++ b/hardware/arduino/cores/arduino/NetServer.h @@ -0,0 +1,11 @@ +#ifndef netserver_h +#define netserver_h + +class NetClient; + +class NetServer { +public: + virtual void begin() =0; +}; + +#endif diff --git a/libraries/Ethernet/Server.h b/libraries/Ethernet/Server.h index 6aa5d3aaf..4c3bd1b54 100644 --- a/libraries/Ethernet/Server.h +++ b/libraries/Ethernet/Server.h @@ -1,19 +1,19 @@ #ifndef server_h #define server_h -#include "Print.h" +#include "NetServer.h" class Client; class Server : -public Print { +public NetServer { private: uint16_t _port; void accept(); public: Server(uint16_t); Client available(); - void begin(); + virtual void begin(); virtual void write(uint8_t); virtual void write(const char *str); virtual void write(const uint8_t *buf, size_t size); From 3540d92eb2a8066eb4e8553f6eb72bd632335411 Mon Sep 17 00:00:00 2001 From: amcewen Date: Fri, 1 Apr 2011 21:10:38 +0100 Subject: [PATCH 09/17] Added Printable interface class to allow printing of classes such as IPAddress --- hardware/arduino/cores/arduino/Print.cpp | 11 ++++++++ hardware/arduino/cores/arduino/Print.h | 3 ++ hardware/arduino/cores/arduino/Printable.h | 32 ++++++++++++++++++++++ libraries/Ethernet/IPAddress.cpp | 10 +++++++ libraries/Ethernet/IPAddress.h | 6 +++- 5 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 hardware/arduino/cores/arduino/Printable.h diff --git a/hardware/arduino/cores/arduino/Print.cpp b/hardware/arduino/cores/arduino/Print.cpp index 4ee556dd8..f5e77e082 100755 --- a/hardware/arduino/cores/arduino/Print.cpp +++ b/hardware/arduino/cores/arduino/Print.cpp @@ -101,6 +101,11 @@ void Print::print(double n, int digits) printFloat(n, digits); } +void Print::print(const Printable& x) +{ + x.printTo(*this); +} + void Print::println(void) { print('\r'); @@ -161,6 +166,12 @@ void Print::println(double n, int digits) println(); } +void Print::println(const Printable& x) +{ + print(x); + println(); +} + // Private Methods ///////////////////////////////////////////////////////////// void Print::printNumber(unsigned long n, uint8_t base) diff --git a/hardware/arduino/cores/arduino/Print.h b/hardware/arduino/cores/arduino/Print.h index b092ae51d..d2014bf08 100755 --- a/hardware/arduino/cores/arduino/Print.h +++ b/hardware/arduino/cores/arduino/Print.h @@ -24,6 +24,7 @@ #include // for size_t #include "WString.h" +#include "Printable.h" #define DEC 10 #define HEX 16 @@ -50,6 +51,7 @@ class Print void print(long, int = DEC); void print(unsigned long, int = DEC); void print(double, int = 2); + void print(const Printable&); void println(const String &s); void println(const char[]); @@ -60,6 +62,7 @@ class Print void println(long, int = DEC); void println(unsigned long, int = DEC); void println(double, int = 2); + void println(const Printable&); void println(void); }; diff --git a/hardware/arduino/cores/arduino/Printable.h b/hardware/arduino/cores/arduino/Printable.h new file mode 100644 index 000000000..fc6485826 --- /dev/null +++ b/hardware/arduino/cores/arduino/Printable.h @@ -0,0 +1,32 @@ +/* + Printable.h - Interface class that allows printing of complex types + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef Printable_h +#define Printable_h + +class Print; + +class Printable +{ + public: + virtual void printTo(Print& p) const =0; +}; + +#endif + diff --git a/libraries/Ethernet/IPAddress.cpp b/libraries/Ethernet/IPAddress.cpp index 408d518a0..c4fb75096 100644 --- a/libraries/Ethernet/IPAddress.cpp +++ b/libraries/Ethernet/IPAddress.cpp @@ -42,3 +42,13 @@ bool IPAddress::operator==(const uint8_t* addr) return memcmp(addr, _address, sizeof(_address)) == 0; } +void IPAddress::printTo(Print& p) const +{ + for (int i =0; i < 3; i++) + { + p.print(_address[i], DEC); + p.print('.'); + } + p.print(_address[3], DEC); +} + diff --git a/libraries/Ethernet/IPAddress.h b/libraries/Ethernet/IPAddress.h index 487e420bd..7dd520351 100644 --- a/libraries/Ethernet/IPAddress.h +++ b/libraries/Ethernet/IPAddress.h @@ -26,9 +26,11 @@ #ifndef IPAddress_h #define IPAddress_h +#include + // A class to make it easier to handle and pass around IP addresses -class IPAddress { +class IPAddress : public Printable { private: uint8_t _address[4]; // IPv4 address // Access the raw byte array containing the address. Because this returns a pointer @@ -58,6 +60,8 @@ public: IPAddress& operator=(const uint8_t *address); IPAddress& operator=(uint32_t address); + virtual void printTo(Print& p) const; + friend class EthernetClass; friend class UDP; friend class Client; From facbd279b67923bbabbc4540721280f652ae5726 Mon Sep 17 00:00:00 2001 From: amcewen Date: Sat, 2 Apr 2011 11:33:27 +0100 Subject: [PATCH 10/17] Added a brief explanation of how you'd use Printable --- hardware/arduino/cores/arduino/Printable.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hardware/arduino/cores/arduino/Printable.h b/hardware/arduino/cores/arduino/Printable.h index fc6485826..e5d773261 100644 --- a/hardware/arduino/cores/arduino/Printable.h +++ b/hardware/arduino/cores/arduino/Printable.h @@ -22,6 +22,12 @@ class Print; +/** The Printable class provides a way for new classes to allow themselves to be printed. + By deriving from Printable and implementing the printTo method, it will then be possible + for users to print out instances of this class by passing them into the usual + Print::print and Print::println methods. +*/ + class Printable { public: From 35a78b15ea94014a475967b8414ad00d1a145f9c Mon Sep 17 00:00:00 2001 From: amcewen Date: Sun, 10 Apr 2011 11:34:40 +0100 Subject: [PATCH 11/17] Added virtual destructor to Printable, which also requires new and delete operators to be added --- hardware/arduino/cores/arduino/Printable.h | 3 +++ hardware/arduino/cores/arduino/new.cpp | 18 ++++++++++++++++++ hardware/arduino/cores/arduino/new.h | 22 ++++++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 hardware/arduino/cores/arduino/new.cpp create mode 100644 hardware/arduino/cores/arduino/new.h diff --git a/hardware/arduino/cores/arduino/Printable.h b/hardware/arduino/cores/arduino/Printable.h index e5d773261..5ff607767 100644 --- a/hardware/arduino/cores/arduino/Printable.h +++ b/hardware/arduino/cores/arduino/Printable.h @@ -20,6 +20,8 @@ #ifndef Printable_h #define Printable_h +#include + class Print; /** The Printable class provides a way for new classes to allow themselves to be printed. @@ -31,6 +33,7 @@ class Print; class Printable { public: + virtual ~Printable() {}; virtual void printTo(Print& p) const =0; }; diff --git a/hardware/arduino/cores/arduino/new.cpp b/hardware/arduino/cores/arduino/new.cpp new file mode 100644 index 000000000..0f6d4220e --- /dev/null +++ b/hardware/arduino/cores/arduino/new.cpp @@ -0,0 +1,18 @@ +#include + +void * operator new(size_t size) +{ + return malloc(size); +} + +void operator delete(void * ptr) +{ + free(ptr); +} + +int __cxa_guard_acquire(__guard *g) {return !*(char *)(g);}; +void __cxa_guard_release (__guard *g) {*(char *)g = 1;}; +void __cxa_guard_abort (__guard *) {}; + +void __cxa_pure_virtual(void) {}; + diff --git a/hardware/arduino/cores/arduino/new.h b/hardware/arduino/cores/arduino/new.h new file mode 100644 index 000000000..cd940ce8b --- /dev/null +++ b/hardware/arduino/cores/arduino/new.h @@ -0,0 +1,22 @@ +/* Header to define new/delete operators as they aren't provided by avr-gcc by default + Taken from http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=59453 + */ + +#ifndef NEW_H +#define NEW_H + +#include + +void * operator new(size_t size); +void operator delete(void * ptr); + +__extension__ typedef int __guard __attribute__((mode (__DI__))); + +extern "C" int __cxa_guard_acquire(__guard *); +extern "C" void __cxa_guard_release (__guard *); +extern "C" void __cxa_guard_abort (__guard *); + +extern "C" void __cxa_pure_virtual(void); + +#endif + From 789e22add2f233d2ef8cbbc8ff747f1737972fe9 Mon Sep 17 00:00:00 2001 From: amcewen Date: Sun, 12 Jun 2011 22:02:25 +0100 Subject: [PATCH 12/17] Added a way to specify the DNS server to use with static IP --- libraries/Ethernet/Ethernet.cpp | 18 ++++++++++++++---- libraries/Ethernet/Ethernet.h | 5 +++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/libraries/Ethernet/Ethernet.cpp b/libraries/Ethernet/Ethernet.cpp index 937f5b4f9..c298f3d17 100644 --- a/libraries/Ethernet/Ethernet.cpp +++ b/libraries/Ethernet/Ethernet.cpp @@ -33,27 +33,37 @@ int EthernetClass::begin(uint8_t *mac_address) } void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip) +{ + // Assume the DNS server will be the machine on the same network as the local IP + // but with last octet being '1' + IPAddress dns_server = local_ip; + dns_server[3] = 1; + begin(mac_address, local_ip, dns_server); +} + +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server) { // Assume the gateway will be the machine on the same network as the local IP // but with last octet being '1' IPAddress gateway = local_ip; gateway[3] = 1; - begin(mac_address, local_ip, gateway); + begin(mac_address, local_ip, dns_server, gateway); } -void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress gateway) +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway) { IPAddress subnet(255, 255, 255, 0); - begin(mac_address, local_ip, gateway, subnet); + begin(mac_address, local_ip, dns_server, gateway, subnet); } -void EthernetClass::begin(uint8_t *mac, IPAddress local_ip, IPAddress gateway, IPAddress subnet) +void EthernetClass::begin(uint8_t *mac, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet) { W5100.init(); W5100.setMACAddress(mac); W5100.setIPAddress(local_ip._address); W5100.setGatewayIp(gateway._address); W5100.setSubnetMask(subnet._address); + _dnsServerAddress = dns_server; } IPAddress EthernetClass::localIP() diff --git a/libraries/Ethernet/Ethernet.h b/libraries/Ethernet/Ethernet.h index fdf0b7f39..b4d223fba 100644 --- a/libraries/Ethernet/Ethernet.h +++ b/libraries/Ethernet/Ethernet.h @@ -20,8 +20,9 @@ public: // Returns 0 if the DHCP configuration failed, and 1 if it succeeded int begin(uint8_t *mac_address); void begin(uint8_t *mac_address, IPAddress local_ip); - void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress gateway); - void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress gateway, IPAddress subnet); + void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server); + void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway); + void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet); IPAddress localIP(); IPAddress subnetMask(); From ffd2cec8a0d4e6755d7a0182ab3a32a411f8f240 Mon Sep 17 00:00:00 2001 From: amcewen Date: Thu, 16 Jun 2011 20:16:26 +0100 Subject: [PATCH 13/17] Tweak to defines to support a couple more AVRs - the ATmega32U4 and AT90USB1286, so it doesn't need to be patched for the Teensy boards. --- libraries/Ethernet/utility/w5100.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/Ethernet/utility/w5100.h b/libraries/Ethernet/utility/w5100.h index 9872c7ccb..35d23ed41 100755 --- a/libraries/Ethernet/utility/w5100.h +++ b/libraries/Ethernet/utility/w5100.h @@ -324,6 +324,10 @@ private: 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 inline static void initSS() { DDRB |= _BV(2); }; inline static void setSS() { PORTB &= ~_BV(2); }; From 6b2dec0d01217675daf124a9dea2d0650d88225b Mon Sep 17 00:00:00 2001 From: amcewen Date: Thu, 7 Jul 2011 21:59:35 +0100 Subject: [PATCH 14/17] Fixed bug where the DHCP client didn't correctly handle a response containing more than one DNS server address. Fixes issue 569. --- libraries/Ethernet/Dhcp.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libraries/Ethernet/Dhcp.cpp b/libraries/Ethernet/Dhcp.cpp index c20d2e61d..29db89098 100755 --- a/libraries/Ethernet/Dhcp.cpp +++ b/libraries/Ethernet/Dhcp.cpp @@ -271,11 +271,19 @@ uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& tr case routersOnSubnet : opt_len = _dhcpUdpSocket.read(); _dhcpUdpSocket.read(_dhcpGatewayIp, 4); + for (int i = 0; i < opt_len-4; i++) + { + _dhcpUdpSocket.read(); + } break; case dns : opt_len = _dhcpUdpSocket.read(); _dhcpUdpSocket.read(_dhcpDnsServerIp, 4); + for (int i = 0; i < opt_len-4; i++) + { + _dhcpUdpSocket.read(); + } break; case dhcpServerIdentifier : From b7533c18393c2b6d0e1e4dba620d87215611ce6c Mon Sep 17 00:00:00 2001 From: amcewen Date: Sun, 28 Aug 2011 22:26:07 +0100 Subject: [PATCH 15/17] Final changes to integrate latest core updates to WiFly branch --- hardware/arduino/cores/arduino/NetClient.h | 7 +++---- libraries/Ethernet/Client.h | 2 -- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/hardware/arduino/cores/arduino/NetClient.h b/hardware/arduino/cores/arduino/NetClient.h index ea64664e7..35bfa0a7b 100644 --- a/hardware/arduino/cores/arduino/NetClient.h +++ b/hardware/arduino/cores/arduino/NetClient.h @@ -1,6 +1,5 @@ #ifndef netclient_h #define netclient_h -#include "WProgram.h" #include "Print.h" #include "NetClient.h" #include "IPAddress.h" @@ -10,9 +9,9 @@ class NetClient : public Stream { public: virtual int connect(IPAddress ip, uint16_t port) =0; virtual int connect(const char *host, uint16_t port) =0; - virtual void write(uint8_t) =0; - virtual void write(const char *str) =0; - virtual void write(const uint8_t *buf, size_t size) =0; + virtual size_t write(uint8_t) =0; + virtual size_t write(const char *str) =0; + virtual size_t write(const uint8_t *buf, size_t size) =0; virtual int available() = 0; virtual int read() = 0; virtual int read(uint8_t *buf, size_t size) = 0; diff --git a/libraries/Ethernet/Client.h b/libraries/Ethernet/Client.h index 1d360063a..6717cf128 100644 --- a/libraries/Ethernet/Client.h +++ b/libraries/Ethernet/Client.h @@ -24,8 +24,6 @@ public: virtual void flush(); virtual void stop(); virtual uint8_t connected(); - virtual uint8_t operator==(int); - virtual uint8_t operator!=(int); virtual operator bool(); friend class Server; From ad5dead85a2a32a1be79fec73a39dec67cf0a372 Mon Sep 17 00:00:00 2001 From: amcewen Date: Mon, 29 Aug 2011 22:36:28 +0100 Subject: [PATCH 16/17] Changed names of the Ethernet classes: Client -> EthernetClient, NetClient -> Client, and basic testing performed --- .../cores/arduino/{NetClient.h => Client.h} | 10 +++-- hardware/arduino/cores/arduino/NetServer.h | 11 ----- hardware/arduino/cores/arduino/Server.h | 9 ++++ libraries/Ethernet/Ethernet.h | 8 ++-- .../{Client.cpp => EthernetClient.cpp} | 42 +++++++++---------- .../Ethernet/{Client.h => EthernetClient.h} | 14 +++---- .../{Server.cpp => EthernetServer.cpp} | 28 ++++++------- .../Ethernet/{Server.h => EthernetServer.h} | 16 +++---- .../BarometricPressureWebServer.pde | 8 ++-- .../examples/ChatServer/ChatServer.pde | 4 +- .../DhcpAddressPrinter/DhcpAddressPrinter.ino | 2 +- .../DhcpChatServer/DhcpChatServer.ino | 4 +- .../examples/DnsWebClient/DnsWebClient.pde | 2 +- .../examples/PachubeClient/PachubeClient.pde | 2 +- .../PachubeClientString.pde | 2 +- .../examples/TelnetClient/TelnetClient.pde | 2 +- .../examples/TwitterClient/TwitterClient.ino | 2 +- .../Ethernet/examples/WebClient/WebClient.pde | 2 +- .../Ethernet/examples/WebServer/WebServer.pde | 6 +-- libraries/Ethernet/keywords.txt | 4 +- 20 files changed, 89 insertions(+), 89 deletions(-) rename hardware/arduino/cores/arduino/{NetClient.h => Client.h} (77%) delete mode 100644 hardware/arduino/cores/arduino/NetServer.h create mode 100644 hardware/arduino/cores/arduino/Server.h rename libraries/Ethernet/{Client.cpp => EthernetClient.cpp} (73%) rename libraries/Ethernet/{Client.h => EthernetClient.h} (76%) rename libraries/Ethernet/{Server.cpp => EthernetServer.cpp} (72%) rename libraries/Ethernet/{Server.h => EthernetServer.h} (53%) diff --git a/hardware/arduino/cores/arduino/NetClient.h b/hardware/arduino/cores/arduino/Client.h similarity index 77% rename from hardware/arduino/cores/arduino/NetClient.h rename to hardware/arduino/cores/arduino/Client.h index 35bfa0a7b..ed9e9b48c 100644 --- a/hardware/arduino/cores/arduino/NetClient.h +++ b/hardware/arduino/cores/arduino/Client.h @@ -1,10 +1,10 @@ -#ifndef netclient_h -#define netclient_h +#ifndef client_h +#define client_h #include "Print.h" -#include "NetClient.h" +#include "Stream.h" #include "IPAddress.h" -class NetClient : public Stream { +class Client : public Stream { public: virtual int connect(IPAddress ip, uint16_t port) =0; @@ -20,6 +20,8 @@ public: virtual void stop() = 0; virtual uint8_t connected() = 0; virtual operator bool() = 0; +protected: + uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; }; #endif diff --git a/hardware/arduino/cores/arduino/NetServer.h b/hardware/arduino/cores/arduino/NetServer.h deleted file mode 100644 index 91f484895..000000000 --- a/hardware/arduino/cores/arduino/NetServer.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef netserver_h -#define netserver_h - -class NetClient; - -class NetServer { -public: - virtual void begin() =0; -}; - -#endif diff --git a/hardware/arduino/cores/arduino/Server.h b/hardware/arduino/cores/arduino/Server.h new file mode 100644 index 000000000..edab726be --- /dev/null +++ b/hardware/arduino/cores/arduino/Server.h @@ -0,0 +1,9 @@ +#ifndef server_h +#define server_h + +class Server { +public: + virtual void begin() =0; +}; + +#endif diff --git a/libraries/Ethernet/Ethernet.h b/libraries/Ethernet/Ethernet.h index b4d223fba..c916ddae5 100644 --- a/libraries/Ethernet/Ethernet.h +++ b/libraries/Ethernet/Ethernet.h @@ -4,8 +4,8 @@ #include //#include "w5100.h" #include "IPAddress.h" -#include "Client.h" -#include "Server.h" +#include "EthernetClient.h" +#include "EthernetServer.h" #define MAX_SOCK_NUM 4 @@ -29,8 +29,8 @@ public: IPAddress gatewayIP(); IPAddress dnsServerIP(); - friend class Client; - friend class Server; + friend class EthernetClient; + friend class EthernetServer; }; extern EthernetClass Ethernet; diff --git a/libraries/Ethernet/Client.cpp b/libraries/Ethernet/EthernetClient.cpp similarity index 73% rename from libraries/Ethernet/Client.cpp rename to libraries/Ethernet/EthernetClient.cpp index 3c1c2503b..42c2c6cc1 100644 --- a/libraries/Ethernet/Client.cpp +++ b/libraries/Ethernet/EthernetClient.cpp @@ -8,19 +8,19 @@ extern "C" { #include "Arduino.h" #include "Ethernet.h" -#include "Client.h" -#include "Server.h" +#include "EthernetClient.h" +#include "EthernetServer.h" #include "Dns.h" -uint16_t Client::_srcport = 1024; +uint16_t EthernetClient::_srcport = 1024; -Client::Client() : _sock(MAX_SOCK_NUM) { +EthernetClient::EthernetClient() : _sock(MAX_SOCK_NUM) { } -Client::Client(uint8_t sock) : _sock(sock) { +EthernetClient::EthernetClient(uint8_t sock) : _sock(sock) { } -int Client::connect(const char* host, uint16_t port) { +int EthernetClient::connect(const char* host, uint16_t port) { // Look up the host first int ret = 0; DNSClient dns; @@ -35,7 +35,7 @@ int Client::connect(const char* host, uint16_t port) { } } -int Client::connect(IPAddress ip, uint16_t port) { +int EthernetClient::connect(IPAddress ip, uint16_t port) { if (_sock != MAX_SOCK_NUM) return 0; @@ -54,7 +54,7 @@ int Client::connect(IPAddress ip, uint16_t port) { if (_srcport == 0) _srcport = 1024; socket(_sock, SnMR::TCP, _srcport, 0); - if (!::connect(_sock, ip.raw_address(), port)) { + if (!::connect(_sock, rawIPAddress(ip), port)) { _sock = MAX_SOCK_NUM; return 0; } @@ -70,15 +70,15 @@ int Client::connect(IPAddress ip, uint16_t port) { return 1; } -size_t Client::write(uint8_t b) { +size_t EthernetClient::write(uint8_t b) { return write(&b, 1); } -size_t Client::write(const char *str) { +size_t EthernetClient::write(const char *str) { return write((const uint8_t *) str, strlen(str)); } -size_t Client::write(const uint8_t *buf, size_t size) { +size_t EthernetClient::write(const uint8_t *buf, size_t size) { if (_sock == MAX_SOCK_NUM) { setWriteError(); return 0; @@ -90,13 +90,13 @@ size_t Client::write(const uint8_t *buf, size_t size) { return size; } -int Client::available() { +int EthernetClient::available() { if (_sock != MAX_SOCK_NUM) return W5100.getRXReceivedSize(_sock); return 0; } -int Client::read() { +int EthernetClient::read() { uint8_t b; if ( recv(_sock, &b, 1) > 0 ) { @@ -110,11 +110,11 @@ int Client::read() { } } -int Client::read(uint8_t *buf, size_t size) { +int EthernetClient::read(uint8_t *buf, size_t size) { return recv(_sock, buf, size); } -int Client::peek() { +int EthernetClient::peek() { uint8_t b; // Unlike recv, peek doesn't check to see if there's any data available, so we must if (!available()) @@ -123,12 +123,12 @@ int Client::peek() { return b; } -void Client::flush() { +void EthernetClient::flush() { while (available()) read(); } -void Client::stop() { +void EthernetClient::stop() { if (_sock == MAX_SOCK_NUM) return; @@ -148,7 +148,7 @@ void Client::stop() { _sock = MAX_SOCK_NUM; } -uint8_t Client::connected() { +uint8_t EthernetClient::connected() { if (_sock == MAX_SOCK_NUM) return 0; uint8_t s = status(); @@ -156,14 +156,14 @@ uint8_t Client::connected() { (s == SnSR::CLOSE_WAIT && !available())); } -uint8_t Client::status() { +uint8_t EthernetClient::status() { if (_sock == MAX_SOCK_NUM) return SnSR::CLOSED; return W5100.readSnSR(_sock); } // the next function allows us to use the client returned by -// Server::available() as the condition in an if-statement. +// EthernetServer::available() as the condition in an if-statement. -Client::operator bool() { +EthernetClient::operator bool() { return _sock != MAX_SOCK_NUM; } diff --git a/libraries/Ethernet/Client.h b/libraries/Ethernet/EthernetClient.h similarity index 76% rename from libraries/Ethernet/Client.h rename to libraries/Ethernet/EthernetClient.h index 6717cf128..f68a3b4d9 100644 --- a/libraries/Ethernet/Client.h +++ b/libraries/Ethernet/EthernetClient.h @@ -1,15 +1,15 @@ -#ifndef client_h -#define client_h +#ifndef ethernetclient_h +#define ethernetclient_h #include "Arduino.h" #include "Print.h" -#include "NetClient.h" +#include "Client.h" #include "IPAddress.h" -class Client : public NetClient { +class EthernetClient : public Client { public: - Client(); - Client(uint8_t sock); + EthernetClient(); + EthernetClient(uint8_t sock); uint8_t status(); virtual int connect(IPAddress ip, uint16_t port); @@ -26,7 +26,7 @@ public: virtual uint8_t connected(); virtual operator bool(); - friend class Server; + friend class EthernetServer; private: static uint16_t _srcport; diff --git a/libraries/Ethernet/Server.cpp b/libraries/Ethernet/EthernetServer.cpp similarity index 72% rename from libraries/Ethernet/Server.cpp rename to libraries/Ethernet/EthernetServer.cpp index 1ac75d507..9ae86f39e 100644 --- a/libraries/Ethernet/Server.cpp +++ b/libraries/Ethernet/EthernetServer.cpp @@ -5,18 +5,18 @@ extern "C" { } #include "Ethernet.h" -#include "Client.h" -#include "Server.h" +#include "EthernetClient.h" +#include "EthernetServer.h" -Server::Server(uint16_t port) +EthernetServer::EthernetServer(uint16_t port) { _port = port; } -void Server::begin() +void EthernetServer::begin() { for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { - Client client(sock); + EthernetClient client(sock); if (client.status() == SnSR::CLOSED) { socket(sock, SnMR::TCP, _port, 0); listen(sock); @@ -26,12 +26,12 @@ void Server::begin() } } -void Server::accept() +void EthernetServer::accept() { int listening = 0; for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { - Client client(sock); + EthernetClient client(sock); if (EthernetClass::_server_port[sock] == _port) { if (client.status() == SnSR::LISTEN) { @@ -48,12 +48,12 @@ void Server::accept() } } -Client Server::available() +EthernetClient EthernetServer::available() { accept(); for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { - Client client(sock); + EthernetClient client(sock); if (EthernetClass::_server_port[sock] == _port && (client.status() == SnSR::ESTABLISHED || client.status() == SnSR::CLOSE_WAIT)) { @@ -64,27 +64,27 @@ Client Server::available() } } - return Client(MAX_SOCK_NUM); + return EthernetClient(MAX_SOCK_NUM); } -size_t Server::write(uint8_t b) +size_t EthernetServer::write(uint8_t b) { write(&b, 1); } -size_t Server::write(const char *str) +size_t EthernetServer::write(const char *str) { write((const uint8_t *)str, strlen(str)); } -size_t Server::write(const uint8_t *buffer, size_t size) +size_t EthernetServer::write(const uint8_t *buffer, size_t size) { size_t n = 0; accept(); for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { - Client client(sock); + EthernetClient client(sock); if (EthernetClass::_server_port[sock] == _port && client.status() == SnSR::ESTABLISHED) { diff --git a/libraries/Ethernet/Server.h b/libraries/Ethernet/EthernetServer.h similarity index 53% rename from libraries/Ethernet/Server.h rename to libraries/Ethernet/EthernetServer.h index 0febe4fee..ced5ed649 100644 --- a/libraries/Ethernet/Server.h +++ b/libraries/Ethernet/EthernetServer.h @@ -1,18 +1,18 @@ -#ifndef server_h -#define server_h +#ifndef ethernetserver_h +#define ethernetserver_h -#include "NetServer.h" +#include "Server.h" -class Client; +class EthernetClient; -class Server : -public NetServer { +class EthernetServer : +public Server { private: uint16_t _port; void accept(); public: - Server(uint16_t); - Client available(); + EthernetServer(uint16_t); + EthernetClient available(); virtual void begin(); virtual size_t write(uint8_t); virtual size_t write(const char *str); diff --git a/libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.pde b/libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.pde index 3f43d96db..bfbcb6d4a 100644 --- a/libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.pde +++ b/libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.pde @@ -39,7 +39,7 @@ IPAddress subnet(255, 255, 255, 0); // Initialize the Ethernet server library // with the IP address and port you want to use // (port 80 is default for HTTP): -Server server(80); +EthernetServer server(80); //Sensor's memory register addresses: @@ -96,7 +96,7 @@ void loop() { } // listen for incoming Ethernet connections: - listenForClients(); + listenForEthernetClients(); } @@ -124,9 +124,9 @@ void getData() { Serial.println(" Pa"); } -void listenForClients() { +void listenForEthernetClients() { // listen for incoming clients - Client client = server.available(); + EthernetClient client = server.available(); if (client) { Serial.println("Got a client"); // an http request ends with a blank line diff --git a/libraries/Ethernet/examples/ChatServer/ChatServer.pde b/libraries/Ethernet/examples/ChatServer/ChatServer.pde index 8267a5dd4..9f819fd5a 100644 --- a/libraries/Ethernet/examples/ChatServer/ChatServer.pde +++ b/libraries/Ethernet/examples/ChatServer/ChatServer.pde @@ -29,7 +29,7 @@ IPAddress gateway(192,168,1, 1); IPAddress subnet(255, 255, 0, 0); // telnet defaults to port 23 -Server server(23); +EthernetServer server(23); boolean gotAMessage = false; // whether or not you got a message from the client yet void setup() { @@ -43,7 +43,7 @@ void setup() { void loop() { // wait for a new client: - Client client = server.available(); + EthernetClient client = server.available(); // when the client sends the first byte, say hello: if (client) { diff --git a/libraries/Ethernet/examples/DhcpAddressPrinter/DhcpAddressPrinter.ino b/libraries/Ethernet/examples/DhcpAddressPrinter/DhcpAddressPrinter.ino index 8701568c0..a5787b91d 100644 --- a/libraries/Ethernet/examples/DhcpAddressPrinter/DhcpAddressPrinter.ino +++ b/libraries/Ethernet/examples/DhcpAddressPrinter/DhcpAddressPrinter.ino @@ -24,7 +24,7 @@ byte mac[] = { // Initialize the Ethernet client library // with the IP address and port of the server // that you want to connect to (port 80 is default for HTTP): -Client client; +EthernetClient client; void setup() { // start the serial library: diff --git a/libraries/Ethernet/examples/DhcpChatServer/DhcpChatServer.ino b/libraries/Ethernet/examples/DhcpChatServer/DhcpChatServer.ino index c3e581387..50820542c 100644 --- a/libraries/Ethernet/examples/DhcpChatServer/DhcpChatServer.ino +++ b/libraries/Ethernet/examples/DhcpChatServer/DhcpChatServer.ino @@ -30,7 +30,7 @@ IPAddress gateway(192,168,1, 1); IPAddress subnet(255, 255, 0, 0); // telnet defaults to port 23 -Server server(23); +EthernetServer server(23); boolean gotAMessage = false; // whether or not you got a message from the client yet void setup() { @@ -59,7 +59,7 @@ void setup() { void loop() { // wait for a new client: - Client client = server.available(); + EthernetClient client = server.available(); // when the client sends the first byte, say hello: if (client) { diff --git a/libraries/Ethernet/examples/DnsWebClient/DnsWebClient.pde b/libraries/Ethernet/examples/DnsWebClient/DnsWebClient.pde index 7bec73a83..5c7a53a65 100644 --- a/libraries/Ethernet/examples/DnsWebClient/DnsWebClient.pde +++ b/libraries/Ethernet/examples/DnsWebClient/DnsWebClient.pde @@ -25,7 +25,7 @@ char serverName[] = "www.google.com"; // Initialize the Ethernet client library // with the IP address and port of the server // that you want to connect to (port 80 is default for HTTP): -Client client; +EthernetClient client; void setup() { // start the serial library: diff --git a/libraries/Ethernet/examples/PachubeClient/PachubeClient.pde b/libraries/Ethernet/examples/PachubeClient/PachubeClient.pde index af9bf1f05..e626113b0 100644 --- a/libraries/Ethernet/examples/PachubeClient/PachubeClient.pde +++ b/libraries/Ethernet/examples/PachubeClient/PachubeClient.pde @@ -29,7 +29,7 @@ byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // initialize the library instance: -Client client; +EthernetClient client; long lastConnectionTime = 0; // last time you connected to the server, in milliseconds boolean lastConnected = false; // state of the connection last time through the main loop diff --git a/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.pde b/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.pde index e6dbf09ea..4b97c4175 100644 --- a/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.pde +++ b/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.pde @@ -30,7 +30,7 @@ byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // initialize the library instance: -Client client; +EthernetClient client; long lastConnectionTime = 0; // last time you connected to the server, in milliseconds boolean lastConnected = false; // state of the connection last time through the main loop diff --git a/libraries/Ethernet/examples/TelnetClient/TelnetClient.pde b/libraries/Ethernet/examples/TelnetClient/TelnetClient.pde index 7502d218d..5cf1ad875 100644 --- a/libraries/Ethernet/examples/TelnetClient/TelnetClient.pde +++ b/libraries/Ethernet/examples/TelnetClient/TelnetClient.pde @@ -33,7 +33,7 @@ IPAddress server(1,1,1,1); // with the IP address and port of the server // that you want to connect to (port 23 is default for telnet; // if you're using Processing's ChatServer, use port 10002): -Client client; +EthernetClient client; void setup() { // start the Ethernet connection: diff --git a/libraries/Ethernet/examples/TwitterClient/TwitterClient.ino b/libraries/Ethernet/examples/TwitterClient/TwitterClient.ino index 399e76bc3..f113e17b9 100644 --- a/libraries/Ethernet/examples/TwitterClient/TwitterClient.ino +++ b/libraries/Ethernet/examples/TwitterClient/TwitterClient.ino @@ -33,7 +33,7 @@ byte mac[] = { IPAddress ip(192,168,1,20); // initialize the library instance: -Client client; +EthernetClient client; const int requestInterval = 60000; // delay between requests diff --git a/libraries/Ethernet/examples/WebClient/WebClient.pde b/libraries/Ethernet/examples/WebClient/WebClient.pde index 646c3aadd..18068541f 100644 --- a/libraries/Ethernet/examples/WebClient/WebClient.pde +++ b/libraries/Ethernet/examples/WebClient/WebClient.pde @@ -23,7 +23,7 @@ IPAddress server(173,194,33,104); // Google // Initialize the Ethernet client library // with the IP address and port of the server // that you want to connect to (port 80 is default for HTTP): -Client client; +EthernetClient client; void setup() { // start the serial library: diff --git a/libraries/Ethernet/examples/WebServer/WebServer.pde b/libraries/Ethernet/examples/WebServer/WebServer.pde index c69a56a40..6837f8320 100644 --- a/libraries/Ethernet/examples/WebServer/WebServer.pde +++ b/libraries/Ethernet/examples/WebServer/WebServer.pde @@ -1,5 +1,5 @@ /* - Web Server + Web Server A simple web server that shows the value of the analog input pins. using an Arduino Wiznet Ethernet shield. @@ -26,7 +26,7 @@ IPAddress ip(192,168,1, 177); // Initialize the Ethernet server library // with the IP address and port you want to use // (port 80 is default for HTTP): -Server server(80); +EthernetServer server(80); void setup() { @@ -38,7 +38,7 @@ void setup() void loop() { // listen for incoming clients - Client client = server.available(); + EthernetClient client = server.available(); if (client) { // an http request ends with a blank line boolean currentLineIsBlank = true; diff --git a/libraries/Ethernet/keywords.txt b/libraries/Ethernet/keywords.txt index 7fdcedf09..6b37cbe05 100644 --- a/libraries/Ethernet/keywords.txt +++ b/libraries/Ethernet/keywords.txt @@ -7,8 +7,8 @@ ####################################### Ethernet KEYWORD1 -Client KEYWORD1 -Server KEYWORD1 +EthernetClient KEYWORD1 +EthernetServer KEYWORD1 IPAddress KEYWORD1 ####################################### From a6093a8d91a2f94569394999e9f6a0b2d99637c9 Mon Sep 17 00:00:00 2001 From: amcewen Date: Tue, 30 Aug 2011 21:27:31 +0100 Subject: [PATCH 17/17] Created an abstract base class UDP to match the Client and Server classes, and reworked the Ethernet library to use it and derive EthernetUDP. --- hardware/arduino/cores/arduino/Udp.h | 90 +++++++++++++++++++ libraries/Ethernet/Dhcp.h | 4 +- libraries/Ethernet/Dns.cpp | 2 +- libraries/Ethernet/Dns.h | 4 +- .../Ethernet/{Udp.cpp => EthernetUdp.cpp} | 36 ++++---- libraries/Ethernet/{Udp.h => EthernetUdp.h} | 27 +++--- .../UDPSendReceiveString.pde | 6 +- .../examples/UdpNtpClient/UdpNtpClient.pde | 4 +- 8 files changed, 131 insertions(+), 42 deletions(-) create mode 100644 hardware/arduino/cores/arduino/Udp.h rename libraries/Ethernet/{Udp.cpp => EthernetUdp.cpp} (83%) rename libraries/Ethernet/{Udp.h => EthernetUdp.h} (87%) diff --git a/hardware/arduino/cores/arduino/Udp.h b/hardware/arduino/cores/arduino/Udp.h new file mode 100644 index 000000000..1fb9cd3cf --- /dev/null +++ b/hardware/arduino/cores/arduino/Udp.h @@ -0,0 +1,90 @@ +/* + * Udp.cpp: Library to send/receive UDP packets. + * + * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these) + * 1) UDP does not guarantee the order in which assembled UDP packets are received. This + * might not happen often in practice, but in larger network topologies, a UDP + * packet can be received out of sequence. + * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being + * aware of it. Again, this may not be a concern in practice on small local networks. + * For more information, see http://www.cafeaulait.org/course/week12/35.html + * + * MIT License: + * Copyright (c) 2008 Bjoern Hartmann + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * bjoern@cs.stanford.edu 12/30/2008 + */ + +#ifndef udp_h +#define udp_h + +#include +#include + +class UDP : public Stream { + +public: + virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + virtual void stop() =0; // Finish with the UDP socket + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IPAddress ip, uint16_t port) =0; + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char *host, uint16_t port) =0; + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket() =0; + // Write a single byte into the packet + virtual size_t write(uint8_t) =0; + // Write a string of characters into the packet + virtual size_t write(const char *str) =0; + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t *buffer, size_t size) =0; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket() =0; + // Number of bytes remaining in the current packet + virtual int available() =0; + // Read a single byte from the current packet + virtual int read() =0; + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len) =0; + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) =0; + // Return the next byte from the current packet without moving on to the next byte + virtual int peek() =0; + virtual void flush() =0; // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IPAddress remoteIP() =0; + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort() =0; +protected: + uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; +}; + +#endif diff --git a/libraries/Ethernet/Dhcp.h b/libraries/Ethernet/Dhcp.h index c0034940c..f87719959 100755 --- a/libraries/Ethernet/Dhcp.h +++ b/libraries/Ethernet/Dhcp.h @@ -4,7 +4,7 @@ #ifndef Dhcp_h #define Dhcp_h -#include "Udp.h" +#include "EthernetUdp.h" /* DHCP state machine. */ #define STATE_DHCP_START 0 @@ -139,7 +139,7 @@ private: uint8_t _dhcpGatewayIp[4]; uint8_t _dhcpDhcpServerIp[4]; uint8_t _dhcpDnsServerIp[4]; - UDP _dhcpUdpSocket; + EthernetUDP _dhcpUdpSocket; void presend_DHCP(); void send_DHCP_MESSAGE(uint8_t, uint16_t); diff --git a/libraries/Ethernet/Dns.cpp b/libraries/Ethernet/Dns.cpp index a049c7633..86fd0177a 100644 --- a/libraries/Ethernet/Dns.cpp +++ b/libraries/Ethernet/Dns.cpp @@ -3,7 +3,7 @@ // Released under Apache License, version 2.0 #include "w5100.h" -#include "Udp.h" +#include "EthernetUdp.h" #include "util.h" #include "Dns.h" diff --git a/libraries/Ethernet/Dns.h b/libraries/Ethernet/Dns.h index 9582351f2..d4f49769b 100644 --- a/libraries/Ethernet/Dns.h +++ b/libraries/Ethernet/Dns.h @@ -5,7 +5,7 @@ #ifndef DNSClient_h #define DNSClient_h -#include +#include class DNSClient { @@ -35,7 +35,7 @@ protected: IPAddress iDNSServer; uint16_t iRequestId; - UDP iUdp; + EthernetUDP iUdp; }; #endif diff --git a/libraries/Ethernet/Udp.cpp b/libraries/Ethernet/EthernetUdp.cpp similarity index 83% rename from libraries/Ethernet/Udp.cpp rename to libraries/Ethernet/EthernetUdp.cpp index a1244ffb9..9ca650986 100644 --- a/libraries/Ethernet/Udp.cpp +++ b/libraries/Ethernet/EthernetUdp.cpp @@ -33,10 +33,10 @@ #include "Dns.h" /* Constructor */ -UDP::UDP() : _sock(MAX_SOCK_NUM) {} +EthernetUDP::EthernetUDP() : _sock(MAX_SOCK_NUM) {} -/* Start UDP socket, listening at local port PORT */ -uint8_t UDP::begin(uint16_t port) { +/* Start EthernetUDP socket, listening at local port PORT */ +uint8_t EthernetUDP::begin(uint16_t port) { if (_sock != MAX_SOCK_NUM) return 0; @@ -59,12 +59,12 @@ uint8_t UDP::begin(uint16_t port) { /* Is data available in rx buffer? Returns 0 if no, number of available bytes if yes. * returned value includes 8 byte UDP header!*/ -int UDP::available() { +int EthernetUDP::available() { return W5100.getRXReceivedSize(_sock); } -/* Release any resources being used by this UDP instance */ -void UDP::stop() +/* Release any resources being used by this EthernetUDP instance */ +void EthernetUDP::stop() { if (_sock == MAX_SOCK_NUM) return; @@ -75,7 +75,7 @@ void UDP::stop() _sock = MAX_SOCK_NUM; } -int UDP::beginPacket(const char *host, uint16_t port) +int EthernetUDP::beginPacket(const char *host, uint16_t port) { // Look up the host first int ret = 0; @@ -91,36 +91,36 @@ int UDP::beginPacket(const char *host, uint16_t port) } } -int UDP::beginPacket(IPAddress ip, uint16_t port) +int EthernetUDP::beginPacket(IPAddress ip, uint16_t port) { _offset = 0; - return startUDP(_sock, ip.raw_address(), port); + return startUDP(_sock, rawIPAddress(ip), port); } -int UDP::endPacket() +int EthernetUDP::endPacket() { return sendUDP(_sock); } -size_t UDP::write(uint8_t byte) +size_t EthernetUDP::write(uint8_t byte) { return write(&byte, 1); } -size_t UDP::write(const char *str) +size_t EthernetUDP::write(const char *str) { size_t len = strlen(str); return write((const uint8_t *)str, len); } -size_t UDP::write(const uint8_t *buffer, size_t size) +size_t EthernetUDP::write(const uint8_t *buffer, size_t size) { uint16_t bytes_written = bufferData(_sock, _offset, buffer, size); _offset += bytes_written; return bytes_written; } -int UDP::parsePacket() +int EthernetUDP::parsePacket() { if (available() > 0) { @@ -143,7 +143,7 @@ int UDP::parsePacket() return 0; } -int UDP::read() +int EthernetUDP::read() { uint8_t byte; if (recv(_sock, &byte, 1) > 0) @@ -155,7 +155,7 @@ int UDP::read() return -1; } -int UDP::read(unsigned char* buffer, size_t len) +int EthernetUDP::read(unsigned char* buffer, size_t len) { /* In the readPacket that copes with truncating packets, the buffer was filled with this code. Not sure why it loops round reading out a byte @@ -169,7 +169,7 @@ int UDP::read(unsigned char* buffer, size_t len) return recv(_sock, buffer, len); } -int UDP::peek() +int EthernetUDP::peek() { uint8_t b; // Unlike recv, peek doesn't check to see if there's any data available, so we must @@ -179,7 +179,7 @@ int UDP::peek() return b; } -void UDP::flush() +void EthernetUDP::flush() { while (available()) { diff --git a/libraries/Ethernet/Udp.h b/libraries/Ethernet/EthernetUdp.h similarity index 87% rename from libraries/Ethernet/Udp.h rename to libraries/Ethernet/EthernetUdp.h index 59238c1ae..64e30275f 100644 --- a/libraries/Ethernet/Udp.h +++ b/libraries/Ethernet/EthernetUdp.h @@ -34,15 +34,14 @@ * bjoern@cs.stanford.edu 12/30/2008 */ -#ifndef udp_h -#define udp_h +#ifndef ethernetudp_h +#define ethernetudp_h -#include -#include +#include #define UDP_TX_PACKET_MAX_SIZE 24 -class UDP : public Stream { +class EthernetUDP : public UDP { private: uint8_t _sock; // socket ID for Wiz5100 uint16_t _port; // local port to listen on @@ -51,21 +50,21 @@ private: uint16_t _offset; // offset into the packet being sent public: - UDP(); // Constructor - uint8_t begin(uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use - void stop(); // Finish with the UDP socket + EthernetUDP(); // Constructor + virtual uint8_t begin(uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + virtual void stop(); // Finish with the UDP socket // Sending UDP packets // Start building up a packet to send to the remote host specific in ip and port // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port - int beginPacket(IPAddress ip, uint16_t port); + virtual int beginPacket(IPAddress ip, uint16_t port); // Start building up a packet to send to the remote host specific in host and port // Returns 1 if successful, 0 if there was a problem resolving the hostname or port - int beginPacket(const char *host, uint16_t port); + virtual int beginPacket(const char *host, uint16_t port); // Finish off this packet and send it // Returns 1 if the packet was sent successfully, 0 if there was an error - int endPacket(); + virtual int endPacket(); // Write a single byte into the packet virtual size_t write(uint8_t); // Write a string of characters into the packet @@ -75,7 +74,7 @@ public: // Start processing the next available incoming packet // Returns the size of the packet in bytes, or 0 if no packets are available - int parsePacket(); + virtual int parsePacket(); // Number of bytes remaining in the current packet virtual int available(); // Read a single byte from the current packet @@ -91,9 +90,9 @@ public: virtual void flush(); // Finish reading the current packet // Return the IP address of the host who sent the current incoming packet - IPAddress remoteIP() { return _remoteIP; }; + virtual IPAddress remoteIP() { return _remoteIP; }; // Return the port of the host who sent the current incoming packet - uint16_t remotePort() { return _remotePort; }; + virtual uint16_t remotePort() { return _remotePort; }; }; #endif diff --git a/libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.pde b/libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.pde index 081d69114..4d4045cac 100644 --- a/libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.pde +++ b/libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.pde @@ -15,7 +15,7 @@ #include // needed for Arduino versions later than 0018 #include -#include // UDP library from: bjoern@cs.stanford.edu 12/30/2008 +#include // UDP library from: bjoern@cs.stanford.edu 12/30/2008 // Enter a MAC address and IP address for your controller below. @@ -30,8 +30,8 @@ unsigned int localPort = 8888; // local port to listen on char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet, char ReplyBuffer[] = "acknowledged"; // a string to send back -// A UDP instance to let us send and receive packets over UDP -UDP Udp; +// An EthernetUDP instance to let us send and receive packets over UDP +EthernetUDP Udp; void setup() { // start the Ethernet and UDP: diff --git a/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.pde b/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.pde index 7c2d3ea9e..b4e24b8ce 100644 --- a/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.pde +++ b/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.pde @@ -18,7 +18,7 @@ #include #include -#include +#include // Enter a MAC address for your controller below. // Newer Ethernet shields have a MAC address printed on a sticker on the shield @@ -34,7 +34,7 @@ const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets // A UDP instance to let us send and receive packets over UDP -UDP Udp; +EthernetUDP Udp; void setup() {