Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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

This includes DCHP support and new UDP API for the Ethernet library.
  • Loading branch information...
commit f43c0918ff9c1d76b1163652e9db664a5b42ccd3 1 parent efae89e
@damellis damellis authored
Showing with 1,016 additions and 186 deletions.
  1. +2 −2 libraries/Ethernet/Client.cpp
  2. +3 −3 libraries/Ethernet/Client.h
  3. +341 −0 libraries/Ethernet/Dhcp.cpp
  4. +158 −0 libraries/Ethernet/Dhcp.h
  5. +63 −14 libraries/Ethernet/Ethernet.cpp
  6. +15 −3 libraries/Ethernet/Ethernet.h
  7. +44 −0 libraries/Ethernet/IPAddress.cpp
  8. +68 −0 libraries/Ethernet/IPAddress.h
  9. +85 −80 libraries/Ethernet/Udp.cpp
  10. +44 −12 libraries/Ethernet/Udp.h
  11. +3 −6 libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.pde
  12. +4 −4 libraries/Ethernet/examples/ChatServer/ChatServer.pde
  13. +10 −11 libraries/Ethernet/examples/PachubeClient/PachubeClient.pde
  14. +4 −8 libraries/Ethernet/examples/PachubeClientString/PachubeClientString.pde
  15. +2 −4 libraries/Ethernet/examples/TelnetClient/TelnetClient.pde
  16. +21 −12 libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.pde
  17. +18 −14 libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.pde
  18. +10 −6 libraries/Ethernet/examples/WebClient/WebClient.pde
  19. +2 −2 libraries/Ethernet/examples/WebServer/WebServer.pde
  20. +7 −0 libraries/Ethernet/keywords.txt
  21. +13 −0 libraries/Ethernet/util.h
  22. +55 −0 libraries/Ethernet/utility/socket.cpp
  23. +21 −0 libraries/Ethernet/utility/socket.h
  24. +9 −3 libraries/Ethernet/utility/w5100.cpp
  25. +14 −2 libraries/Ethernet/utility/w5100.h
View
4 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;
}
View
6 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();
@@ -29,7 +29,7 @@ class Client : public Stream {
private:
static uint16_t _srcport;
uint8_t _sock;
- uint8_t *_ip;
+ IPAddress _ip;
uint16_t _port;
};
View
341 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 <string.h>
+#include <stdlib.h>
+#include "Dhcp.h"
+#include "Arduino.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);
+}
+
View
158 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
View
77 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;
View
18 libraries/Ethernet/Ethernet.h
@@ -3,6 +3,7 @@
#include <inttypes.h>
//#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;
};
View
44 libraries/Ethernet/IPAddress.cpp
@@ -0,0 +1,44 @@
+
+#include <Arduino.h>
+#include <IPAddress.h>
+
+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;
+}
+
+bool IPAddress::operator==(const uint8_t* addr)
+{
+ return memcmp(addr, _address, sizeof(_address)) == 0;
+}
+
View
68 libraries/Ethernet/IPAddress.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * 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
+ // 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
+ 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 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]; };
+ 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);
+
+ friend class EthernetClass;
+ friend class UDP;
+ friend class Client;
+ friend class Server;
+ friend class DhcpClass;
+};
+
+#endif
View
165 libraries/Ethernet/Udp.cpp
@@ -56,106 +56,111 @@ 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);
}
+/* Release any resources being used by this UDP instance */
+void UDP::stop()
+{
+ if (_sock == MAX_SOCK_NUM)
+ return;
-/* 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];
- }
+ close(_sock);
- //and just read the rest byte by byte and throw it away
- while(available()) {
- recv(_sock,tmpBuf,1);
- }
+ EthernetClass::_server_port[_sock] = 0;
+ _sock = MAX_SOCK_NUM;
+}
- return (-1*packetLen);
+int UDP::beginPacket(IPAddress ip, uint16_t port)
+{
+ _offset = 0;
+ return startUDP(_sock, ip.raw_address(), port);
+}
- //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<bufLen; i++) {
- buf[i]=tmpBuf[i];
- }
- //free temp buffer
- free(tmpBuf);
- */
+int UDP::endPacket()
+{
+ return sendUDP(_sock);
+}
+void UDP::write(uint8_t byte)
+{
+ write(&byte, 1);
+}
- }
- return recvfrom(_sock,buf,bufLen,ip,port);
+void UDP::write(const char *str)
+{
+ size_t len = strlen(str);
+ write((const uint8_t *)str, len);
}
-/* Read a received packet, throw away peer's ip and port. See note above. */
-int UDP::readPacket(uint8_t * buf, uint16_t len) {
- uint8_t ip[4];
- uint16_t port[1];
- return recvfrom(_sock,buf,len,ip,port);
+void UDP::write(const uint8_t *buffer, size_t size)
+{
+ uint16_t bytes_written = bufferData(_sock, _offset, buffer, size);
+ _offset += bytes_written;
}
-int UDP::readPacket(char * buf, uint16_t bufLen, uint8_t *ip, uint16_t &port) {
-uint16_t myPort;
-uint16_t ret = readPacket( (byte*)buf, bufLen, ip, &myPort);
-port = myPort;
-return ret;
+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)
+ {
+ _remoteIP = tmpBuf;
+ _remotePort = tmpBuf[4];
+ _remotePort = (_remotePort << 8) + tmpBuf[5];
+ // When we get here, any remaining bytes are the data
+ ret = available();
+ }
+ return ret;
}
-/* Release any resources being used by this UDP instance */
-void UDP::stop()
+int UDP::read()
{
- if (_sock == MAX_SOCK_NUM)
- return;
+ 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;
+}
- close(_sock);
+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);
+}
- EthernetClass::_server_port[_sock] = 0;
- _sock = MAX_SOCK_NUM;
+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();
+ }
}
View
56 libraries/Ethernet/Udp.h
@@ -37,28 +37,60 @@
#ifndef udp_h
#define udp_h
+#include <Stream.h>
+#include <IPAddress.h>
+
#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
+
+ // 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);
- // 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 &);
+ // 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);
+ // 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
- // Finish with the UDP socket
- void stop();
+ // 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
View
9 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
View
8 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);
}
-}
+}
View
21 libraries/Ethernet/examples/PachubeClient/PachubeClient.pde
@@ -23,20 +23,13 @@
#include <Ethernet.h>
// 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);
}
View
12 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);
View
6 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
View
33 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);
-
- // read the packet into packetBufffer and get the senders IP addr and port number
- Udp.readPacket(packetBuffer,UDP_TX_PACKET_MAX_SIZE, remoteIp, remotePort);
+ 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
+ Udp.read(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);
}
View
32 libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.pde
@@ -20,18 +20,14 @@
#include <Ethernet.h>
#include <Udp.h>
-// 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 };
-
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
@@ -42,11 +38,16 @@ UDP Udp;
void setup()
{
+ Serial.begin(9600);
+
// start Ethernet and UDP
- Ethernet.begin(mac,ip);
+ 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);
-
- Serial.begin(9600);
}
void loop()
@@ -55,8 +56,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:
@@ -100,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);
@@ -118,7 +120,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();
}
View
16 libraries/Ethernet/examples/WebClient/WebClient.pde
@@ -15,11 +15,10 @@
#include <SPI.h>
#include <Ethernet.h>
-// 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...");
View
4 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();
}
-}
+}
View
7 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)
View
13 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
View
55 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;
+}
+
View
21 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_ */
View
12 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)
{
- uint16_t ptr = readSnTX_WR(s);
+ // 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++)
{
View
16 libraries/Ethernet/utility/w5100.h
@@ -146,7 +146,19 @@ class W5100Class {
* 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 @@ class W5100Class {
// ---------------
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);
Please sign in to comment.
Something went wrong with that request. Please try again.