1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-06-16 11:21:18 +03:00

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

This includes DCHP support and new UDP API for the Ethernet library.
This commit is contained in:
David A. Mellis
2011-03-23 23:28:33 -04:00
parent efae89ea0e
commit f43c0918ff
25 changed files with 1021 additions and 191 deletions

View File

@ -16,7 +16,7 @@ uint16_t Client::_srcport = 1024;
Client::Client(uint8_t sock) : _sock(sock) { 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() { uint8_t Client::connect() {
@ -38,7 +38,7 @@ uint8_t Client::connect() {
if (_srcport == 0) _srcport = 1024; if (_srcport == 0) _srcport = 1024;
socket(_sock, SnMR::TCP, _srcport, 0); socket(_sock, SnMR::TCP, _srcport, 0);
if (!::connect(_sock, _ip, _port)) { if (!::connect(_sock, _ip.raw_address(), _port)) {
_sock = MAX_SOCK_NUM; _sock = MAX_SOCK_NUM;
return 0; return 0;
} }

View File

@ -7,8 +7,8 @@ class Client : public Stream {
public: public:
Client(); Client();
Client(uint8_t); Client(uint8_t sock);
Client(uint8_t *, uint16_t); Client(IPAddress& ip, uint16_t port);
uint8_t status(); uint8_t status();
uint8_t connect(); uint8_t connect();
@ -29,7 +29,7 @@ public:
private: private:
static uint16_t _srcport; static uint16_t _srcport;
uint8_t _sock; uint8_t _sock;
uint8_t *_ip; IPAddress _ip;
uint16_t _port; uint16_t _port;
}; };

341
libraries/Ethernet/Dhcp.cpp Executable file
View File

@ -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);
}

158
libraries/Ethernet/Dhcp.h Executable file
View File

@ -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 File

@ -1,5 +1,6 @@
#include "w5100.h" #include "w5100.h"
#include "Ethernet.h" #include "Ethernet.h"
#include "Dhcp.h"
// XXX: don't make assumptions about the value of MAX_SOCK_NUM. // XXX: don't make assumptions about the value of MAX_SOCK_NUM.
uint8_t EthernetClass::_state[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] = { uint16_t EthernetClass::_server_port[MAX_SOCK_NUM] = {
0, 0, 0, 0 }; 0, 0, 0, 0 };
void EthernetClass::begin(uint8_t *mac, uint8_t *ip) int EthernetClass::begin(uint8_t *mac_address)
{ {
uint8_t gateway[4]; DhcpClass dhcp;
gateway[0] = ip[0];
gateway[1] = ip[1]; // Initialise the basic info
gateway[2] = ip[2]; 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; 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[] = { IPAddress subnet(255, 255, 255, 0);
255, 255, 255, 0 }; begin(mac_address, local_ip, gateway, subnet);
begin(mac, 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.init();
W5100.setMACAddress(mac); W5100.setMACAddress(mac);
W5100.setIPAddress(ip); W5100.setIPAddress(local_ip._address);
W5100.setGatewayIp(gateway); W5100.setGatewayIp(gateway._address);
W5100.setSubnetMask(subnet); 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; EthernetClass Ethernet;

View File

@ -3,6 +3,7 @@
#include <inttypes.h> #include <inttypes.h>
//#include "w5100.h" //#include "w5100.h"
#include "IPAddress.h"
#include "Client.h" #include "Client.h"
#include "Server.h" #include "Server.h"
@ -10,12 +11,23 @@
class EthernetClass { class EthernetClass {
private: private:
IPAddress _dnsServerAddress;
public: public:
static uint8_t _state[MAX_SOCK_NUM]; static uint8_t _state[MAX_SOCK_NUM];
static uint16_t _server_port[MAX_SOCK_NUM]; static uint16_t _server_port[MAX_SOCK_NUM];
void begin(uint8_t *, uint8_t *); // Initialise the Ethernet shield to use the provided MAC address and gain the rest of the
void begin(uint8_t *, uint8_t *, uint8_t *); // configuration through DHCP.
void begin(uint8_t *, uint8_t *, uint8_t *, uint8_t *); // 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 Client;
friend class Server; friend class Server;
}; };

View File

@ -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 File

@ -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 File

@ -56,97 +56,12 @@ uint8_t UDP::begin(uint16_t port) {
return 1; 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. /* Is data available in rx buffer? Returns 0 if no, number of available bytes if yes.
* returned value includes 8 byte UDP header!*/ * returned value includes 8 byte UDP header!*/
int UDP::available() { int UDP::available() {
return W5100.getRXReceivedSize(_sock); 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<bufLen; i++) {
buf[i]=tmpBuf[i];
}
//free temp buffer
free(tmpBuf);
*/
}
return recvfrom(_sock,buf,bufLen,ip,port);
}
/* 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);
}
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;
}
/* Release any resources being used by this UDP instance */ /* Release any resources being used by this UDP instance */
void UDP::stop() void UDP::stop()
{ {
@ -159,3 +74,93 @@ void UDP::stop()
_sock = MAX_SOCK_NUM; _sock = MAX_SOCK_NUM;
} }
int UDP::beginPacket(IPAddress ip, uint16_t port)
{
_offset = 0;
return startUDP(_sock, ip.raw_address(), port);
}
int UDP::endPacket()
{
return sendUDP(_sock);
}
void UDP::write(uint8_t byte)
{
write(&byte, 1);
}
void UDP::write(const char *str)
{
size_t len = strlen(str);
write((const uint8_t *)str, len);
}
void UDP::write(const uint8_t *buffer, size_t size)
{
uint16_t bytes_written = bufferData(_sock, _offset, buffer, size);
_offset += bytes_written;
}
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;
}
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();
}
}

View File

@ -37,28 +37,60 @@
#ifndef udp_h #ifndef udp_h
#define udp_h #define udp_h
#include <Stream.h>
#include <IPAddress.h>
#define UDP_TX_PACKET_MAX_SIZE 24 #define UDP_TX_PACKET_MAX_SIZE 24
class UDP { class UDP : public Stream {
private: private:
uint8_t _sock; // socket ID for Wiz5100 uint8_t _sock; // socket ID for Wiz5100
uint16_t _port; // local port to listen on 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: 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 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 // Sending UDP packets
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 // Start building up a packet to send to the remote host specific in ip and port
int readPacket(uint8_t *, uint16_t); // read a received packet // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
int readPacket(uint8_t *, uint16_t, uint8_t *, uint16_t *); // read a received packet, also return sender's ip and port int beginPacket(IPAddress ip, uint16_t port);
// readPacket that fills a character string buffer // Finish off this packet and send it
int readPacket(char *, uint16_t, uint8_t *, uint16_t &); // 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 // Start processing the next available incoming packet
void stop(); // 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
// 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 #endif

View File

@ -31,12 +31,9 @@
byte mac[] = { byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
// assign an IP address for the controller: // assign an IP address for the controller:
byte ip[] = { IPAddress ip(192,168,1,20);
192,168,1,20 }; IPAddress gateway(192,168,1,1);
byte gateway[] = { IPAddress subnet(255, 255, 255, 0);
192,168,1,1};
byte subnet[] = {
255, 255, 255, 0 };
// Initialize the Ethernet server library // Initialize the Ethernet server library

View File

@ -24,9 +24,9 @@
// The IP address will be dependent on your local network. // The IP address will be dependent on your local network.
// gateway and subnet are optional: // gateway and subnet are optional:
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192,168,1, 177 }; IPAddress ip(192,168,1, 177);
byte gateway[] = { 192,168,1, 1 }; IPAddress gateway(192,168,1, 1);
byte subnet[] = { 255, 255, 0, 0 }; IPAddress subnet(255, 255, 0, 0);
// telnet defaults to port 23 // telnet defaults to port 23
Server server(23); Server server(23);
@ -60,4 +60,4 @@ void loop() {
// echo the bytes to the server as well: // echo the bytes to the server as well:
Serial.print(thisChar); Serial.print(thisChar);
} }
} }

View File

@ -23,20 +23,13 @@
#include <Ethernet.h> #include <Ethernet.h>
// assign a MAC address for the ethernet controller. // 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: // fill in your address here:
byte mac[] = { byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; 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): // The address of the server you want to connect to (pachube.com):
byte server[] = { IPAddress server(209,40,205,190);
209,40,205,190 };
// initialize the library instance: // initialize the library instance:
Client client(server, 80); 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 const int postingInterval = 10000; //delay between updates to Pachube.com
void setup() { void setup() {
// start the ethernet connection and serial port: // start serial port:
Ethernet.begin(mac, ip);
Serial.begin(9600); 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: // give the ethernet module time to boot up:
delay(1000); delay(1000);
} }

View File

@ -29,16 +29,12 @@
byte mac[] = { byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
// assign an IP address for the controller: // assign an IP address for the controller:
byte ip[] = { IPAddress ip(192,169,1,20);
192,169,1,20 }; IPAddress gateway(192,168,1,1);
byte gateway[] = { IPAddress subnet(255, 255, 255, 0);
192,168,1,1};
byte subnet[] = {
255, 255, 255, 0 };
// The address of the server you want to connect to (pachube.com): // The address of the server you want to connect to (pachube.com):
byte server[] = { IPAddress server(209,40,205,190);
209,40,205,190 };
// initialize the library instance: // initialize the library instance:
Client client(server, 80); Client client(server, 80);

View File

@ -24,12 +24,10 @@
// The IP address will be dependent on your local network: // The IP address will be dependent on your local network:
byte mac[] = { byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { IPAddress ip(192,168,1,177);
192,168,1,177 };
// Enter the IP address of the server you're connecting to: // Enter the IP address of the server you're connecting to:
byte server[] = { IPAddress server(1,1,1,1);
1,1,1,1 };
// Initialize the Ethernet client library // Initialize the Ethernet client library
// with the IP address and port of the server // with the IP address and port of the server

View File

@ -22,15 +22,10 @@
// The IP address will be dependent on your local network: // The IP address will be dependent on your local network:
byte mac[] = { byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { IPAddress ip(192, 168, 1, 177);
192,168,1,177 };
unsigned int localPort = 8888; // local port to listen on 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 // buffers for receiving and sending data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet, char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet,
char ReplyBuffer[] = "acknowledged"; // a string to send back char ReplyBuffer[] = "acknowledged"; // a string to send back
@ -48,19 +43,33 @@ void setup() {
void loop() { void loop() {
// if there's data available, read a packet // 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) if(packetSize)
{ {
packetSize = packetSize - 8; // subtract the 8 byte header
Serial.print("Received packet of size "); Serial.print("Received packet of size ");
Serial.println(packetSize); 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 // read the packet into packetBufffer
Udp.readPacket(packetBuffer,UDP_TX_PACKET_MAX_SIZE, remoteIp, remotePort); Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE);
Serial.println("Contents:"); Serial.println("Contents:");
Serial.println(packetBuffer); 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); delay(10);
} }

View File

@ -20,18 +20,14 @@
#include <Ethernet.h> #include <Ethernet.h>
#include <Udp.h> #include <Udp.h>
// Enter a MAC address and IP address for your controller below. // Enter a MAC address for your controller below.
// The IP address will be dependent on your local network: // Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = {
192,168,1,177 };
unsigned int localPort = 8888; // local port to listen for UDP packets unsigned int localPort = 8888; // local port to listen for UDP packets
byte timeServer[] = { IPAddress timeServer(192, 43, 244, 18); // time.nist.gov NTP server
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 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() void setup()
{ {
// start Ethernet and UDP
Ethernet.begin(mac,ip);
Udp.begin(localPort);
Serial.begin(9600); 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() void loop()
@ -55,8 +56,9 @@ void loop()
// wait to see if a reply is available // wait to see if a reply is available
delay(1000); delay(1000);
if ( Udp.available() ) { if ( Udp.parsePacket() ) {
Udp.readPacket(packetBuffer,NTP_PACKET_SIZE); // read the packet into the buffer // 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, //the timestamp starts at byte 40 of the received packet and is four bytes,
// or two words, long. First, esxtract the two words: // 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 // 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 // set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE); memset(packetBuffer, 0, NTP_PACKET_SIZE);
@ -118,7 +120,9 @@ unsigned long sendNTPpacket(byte *address)
// all NTP fields have been given values, now // all NTP fields have been given values, now
// you can send a packet requesting a timestamp: // 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 File

@ -15,11 +15,10 @@
#include <SPI.h> #include <SPI.h>
#include <Ethernet.h> #include <Ethernet.h>
// Enter a MAC address and IP address for your controller below. // Enter a MAC address for your controller below.
// The IP address will be dependent on your local network: // Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192,168,1,177 }; IPAddress server(173,194,33,104); // Google
byte server[] = { 173,194,33,104 }; // Google
// Initialize the Ethernet client library // Initialize the Ethernet client library
// with the IP address and port of the server // with the IP address and port of the server
@ -27,10 +26,15 @@ byte server[] = { 173,194,33,104 }; // Google
Client client(server, 80); Client client(server, 80);
void setup() { void setup() {
// start the Ethernet connection:
Ethernet.begin(mac, ip);
// start the serial library: // start the serial library:
Serial.begin(9600); 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: // give the Ethernet shield a second to initialize:
delay(1000); delay(1000);
Serial.println("connecting..."); Serial.println("connecting...");

View File

@ -21,7 +21,7 @@
// Enter a MAC address and IP address for your controller below. // Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network: // The IP address will be dependent on your local network:
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 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 // Initialize the Ethernet server library
// with the IP address and port you want to use // with the IP address and port you want to use
@ -79,4 +79,4 @@ void loop()
// close the connection: // close the connection:
client.stop(); client.stop();
} }
} }

View File

@ -9,6 +9,7 @@
Ethernet KEYWORD1 Ethernet KEYWORD1
Client KEYWORD1 Client KEYWORD1
Server KEYWORD1 Server KEYWORD1
IPAddress KEYWORD1
####################################### #######################################
# Methods and Functions (KEYWORD2) # Methods and Functions (KEYWORD2)
@ -19,10 +20,16 @@ connect KEYWORD2
write KEYWORD2 write KEYWORD2
available KEYWORD2 available KEYWORD2
read KEYWORD2 read KEYWORD2
peek KEYWORD2
flush KEYWORD2 flush KEYWORD2
stop KEYWORD2 stop KEYWORD2
connected KEYWORD2 connected KEYWORD2
begin KEYWORD2 begin KEYWORD2
beginPacket KEYWORD2
endPacket KEYWORD2
parsePacket KEYWORD2
remoteIP KEYWORD2
remotePort KEYWORD2
####################################### #######################################
# Constants (LITERAL1) # Constants (LITERAL1)

13
libraries/Ethernet/util.h Normal file
View File

@ -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 File

@ -344,3 +344,58 @@ uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len)
return ret; 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 File

@ -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); 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 #endif
/* _SOCKET_H_ */ /* _SOCKET_H_ */

View File

@ -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); uint16_t ptr = readSnTX_WR(s);
ptr += data_offset;
uint16_t offset = ptr & SMASK; uint16_t offset = ptr & SMASK;
uint16_t dstAddr = offset + SBASE[s]; uint16_t dstAddr = offset + SBASE[s];
@ -132,7 +138,7 @@ uint8_t W5100Class::write(uint16_t _addr, uint8_t _data)
return 1; 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++) for (int i=0; i<_len; i++)
{ {

View File

@ -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 * 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. * 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. * @brief This function is being called by recv() also.
@ -182,7 +194,7 @@ public:
// --------------- // ---------------
private: private:
static uint8_t write(uint16_t _addr, uint8_t _data); 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 uint8_t read(uint16_t addr);
static uint16_t read(uint16_t addr, uint8_t *buf, uint16_t len); static uint16_t read(uint16_t addr, uint8_t *buf, uint16_t len);