Upgrade UIP-library to latest. Recommend Arduino IDE 1.5.7 when compiling EtherentGateway sketch.

This commit is contained in:
Henrik Ekblad
2014-09-16 22:17:07 +02:00
parent 27885fad9b
commit 26129b06a9
51 changed files with 594 additions and 3805 deletions
@@ -14,11 +14,15 @@
* *
* The GW code is designed for Arduino 328p / 16MHz. ATmega168 does not have enough memory to run this program. * The GW code is designed for Arduino 328p / 16MHz. ATmega168 does not have enough memory to run this program.
* *
* COMPILING * COMPILING ENC28J60
* You must make sure to disable DEBUG in Sensor.h before compiling this sketch. Othervise the sketch won't fit in program space when downloading. * > Use Arduino IDE 1.5.7 (or later)
* For UIPEthernet(ENC28J60) usage: Note that I had to disable UDP and DHCP support in uipethernet-conf.h to reduce space. (which meas you ave to choose a static IP) * > Disable DEBUG in Sensor.h before compiling this sketch. Othervise the sketch will probably not fit in program space when downloading.
* For WizNET usage: Do *not* install the provided UIPEthernet-library. Remove UIPEthernet-include below and uncomment the Ethernet.h. * > Remove Ethernet.h include below and inlcude UIPEthernet.h
* COMPILING WizNET (W5100)
* > Remove UIPEthernet include below and include Ethernet.h.
* *
* Note that I had to disable UDP and DHCP support in uipethernet-conf.h to reduce space. (which meas you ave to choose a static IP for that module)
* VERA CONFIGURATION: * VERA CONFIGURATION:
* Enter "ip-number:port" in the ip-field of the Arduino GW device. This will temporarily override any serial configuration for the Vera plugin. * Enter "ip-number:port" in the ip-field of the Arduino GW device. This will temporarily override any serial configuration for the Vera plugin.
* E.g. If you want to use the defualt values in this sketch enter: 192.168.178.66:5003 * E.g. If you want to use the defualt values in this sketch enter: 192.168.178.66:5003
@@ -50,10 +54,10 @@
#include <stdarg.h> #include <stdarg.h>
// Use this if you have attached a Ethernet ENC28J60 shields // Use this if you have attached a Ethernet ENC28J60 shields
//#include <UIPEthernet.h> #include <UIPEthernet.h>
// Use this fo WizNET module and Arduino Ethernet Shield // Use this fo WizNET module and Arduino Ethernet Shield
#include <Ethernet.h> //#include <Ethernet.h>
#define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled #define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled
@@ -66,7 +70,7 @@
#define RADIO_TX_LED_PIN 9 // the PCB, on board LED #define RADIO_TX_LED_PIN 9 // the PCB, on board LED
#define IP_PORT 5003 // The port you want to open #define IP_PORT 5003 // The port you want to open
IPAddress myIp (192, 168, 178, 66); // Configure your static ip-address here IPAddress myIp (192, 168, 178, 66); // Configure your static ip-address here COMPILE ERROR HERE? Use Arduino IDE 1.5.7 or later!
// The MAC address can be anything you want but should be unique on your network. // The MAC address can be anything you want but should be unique on your network.
// Newer boards have a MAC address printed on the underside of the PCB, which you can (optionally) use. // Newer boards have a MAC address printed on the underside of the PCB, which you can (optionally) use.
+4 -2
View File
@@ -1,4 +1,4 @@
This is UIPEthernet version 1.01 This is UIPEthernet version 1.07
An plugin-replacement of the stock Arduino Ethernet library for ENC28J60 shields and breakout boards. Full support for persistent (streaming) TCP-connections and UDP (Client and Server each), ARP, ICMP, DHCP and DNS. An plugin-replacement of the stock Arduino Ethernet library for ENC28J60 shields and breakout boards. Full support for persistent (streaming) TCP-connections and UDP (Client and Server each), ARP, ICMP, DHCP and DNS.
Just include 'UIPEthernet.h' instead of 'Ethernet.h' and use all your code written for the stock Arduino Ethernet lib! Just include 'UIPEthernet.h' instead of 'Ethernet.h' and use all your code written for the stock Arduino Ethernet lib!
@@ -26,7 +26,9 @@ On a Mac, you will want to create a folder named "libraries" in in the "Document
$ cd ~/Documents/Arduino/libraries $ cd ~/Documents/Arduino/libraries
$ git clone https://github.com/ntruchsess/arduino_uip UIPEthernet $ git clone https://github.com/ntruchsess/arduino_uip UIPEthernet
Or you download the zipped version of the library from https://github.com/ntruchsess/arduino_uip/archive/master.zip, create a directory [path to Arduino distribution]\libraries\UIPEthernet and put the contents of the zip-file there. Or you download the zipped version of the library from https://github.com/ntruchsess/arduino_uip/releases, and copy the contained directory UIPEthernet to [path to Arduino distribution]\libraries\UIPEthernet.
If you are running Arduino-IDE 1.5.x use release-version 1.57 or checkout branch 'Arduino_1.5.5'
Additional information can be found on the Arduino website: http://www.arduino.cc/en/Hacking/Libraries Additional information can be found on the Arduino website: http://www.arduino.cc/en/Hacking/Libraries
+152 -104
View File
@@ -49,19 +49,22 @@ UIPClient::UIPClient(uip_userdata_t* conn_data) :
int int
UIPClient::connect(IPAddress ip, uint16_t port) UIPClient::connect(IPAddress ip, uint16_t port)
{ {
stop();
uip_ipaddr_t ipaddr; uip_ipaddr_t ipaddr;
uip_ip_addr(ipaddr, ip); uip_ip_addr(ipaddr, ip);
struct uip_conn* conn = uip_connect(&ipaddr, htons(port)); struct uip_conn* conn = uip_connect(&ipaddr, htons(port));
if (conn) if (conn)
{ {
#if UIP_CONNECT_TIMEOUT > 0
int32_t timeout = millis() + 1000 * UIP_CONNECT_TIMEOUT;
#endif
while((conn->tcpstateflags & UIP_TS_MASK) != UIP_CLOSED) while((conn->tcpstateflags & UIP_TS_MASK) != UIP_CLOSED)
{ {
UIPEthernet.tick(); UIPEthernetClass::tick();
if ((conn->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) if ((conn->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED)
{ {
data = (uip_userdata_t*) conn->appstate; data = (uip_userdata_t*) conn->appstate;
#ifdef UIPETHERNET_DEBUG_CLIENT #ifdef UIPETHERNET_DEBUG_CLIENT
Serial.print(F("connected, state: ")); Serial.print(F("connected, state: "));
Serial.print(data->state); Serial.print(data->state);
Serial.print(F(", first packet in: ")); Serial.print(F(", first packet in: "));
@@ -69,6 +72,13 @@ UIPClient::connect(IPAddress ip, uint16_t port)
#endif #endif
return 1; return 1;
} }
#if UIP_CONNECT_TIMEOUT > 0
if (((int32_t)(millis() - timeout)) > 0)
{
conn->tcpstateflags = UIP_CLOSED;
break;
}
#endif
} }
} }
return 0; return 0;
@@ -83,7 +93,7 @@ UIPClient::connect(const char *host, uint16_t port)
DNSClient dns; DNSClient dns;
IPAddress remote_addr; IPAddress remote_addr;
dns.begin(UIPEthernet.dnsServerIP()); dns.begin(UIPEthernetClass::_dnsServerAddress);
ret = dns.getHostByName(host, remote_addr); ret = dns.getHostByName(host, remote_addr);
if (ret == 1) { if (ret == 1) {
return connect(remote_addr, port); return connect(remote_addr, port);
@@ -95,10 +105,14 @@ UIPClient::connect(const char *host, uint16_t port)
void void
UIPClient::stop() UIPClient::stop()
{ {
if (data) if (data && data->state)
{ {
#ifdef UIPETHERNET_DEBUG_CLIENT
Serial.println(F("before stop(), with data"));
_dumpAllData();
#endif
_flushBlocks(&data->packets_in[0]); _flushBlocks(&data->packets_in[0]);
if (data->state & UIP_CLIENT_CLOSED) if (data->state & UIP_CLIENT_REMOTECLOSED)
{ {
data->state = 0; data->state = 0;
} }
@@ -106,9 +120,19 @@ UIPClient::stop()
{ {
data->state |= UIP_CLIENT_CLOSE; data->state |= UIP_CLIENT_CLOSE;
} }
#ifdef UIPETHERNET_DEBUG_CLIENT
Serial.println(F("after stop()"));
_dumpAllData();
#endif
} }
#ifdef UIPETHERNET_DEBUG_CLIENT
else
{
Serial.println(F("stop(), data: NULL"));
}
#endif
data = NULL; data = NULL;
UIPEthernet.tick(); UIPEthernetClass::tick();
} }
uint8_t uint8_t
@@ -125,8 +149,8 @@ UIPClient::operator==(const UIPClient& rhs)
UIPClient::operator bool() UIPClient::operator bool()
{ {
UIPEthernet.tick(); UIPEthernetClass::tick();
return data && (!(data->state & UIP_CLIENT_CLOSED) || data->packets_in[0] != NOBLOCK); return data && (!(data->state & UIP_CLIENT_REMOTECLOSED) || data->packets_in[0] != NOBLOCK);
} }
size_t size_t
@@ -150,15 +174,15 @@ UIPClient::_write(uip_userdata_t* u, const uint8_t *buf, size_t size)
uint16_t attempts = UIP_ATTEMPTS_ON_WRITE; uint16_t attempts = UIP_ATTEMPTS_ON_WRITE;
#endif #endif
repeat: repeat:
UIPEthernet.tick(); UIPEthernetClass::tick();
if (u && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_CLOSED))) if (u && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
{ {
memhandle* p = _currentBlock(&u->packets_out[0]); uint8_t p = _currentBlock(&u->packets_out[0]);
if (*p == NOBLOCK) if (u->packets_out[p] == NOBLOCK)
{ {
newpacket: newpacket:
*p = UIPEthernet.network.allocBlock(UIP_SOCKET_DATALEN); u->packets_out[p] = Enc28J60Network::allocBlock(UIP_SOCKET_DATALEN);
if (*p == NOBLOCK) if (u->packets_out[p] == NOBLOCK)
{ {
#if UIP_ATTEMPTS_ON_WRITE > 0 #if UIP_ATTEMPTS_ON_WRITE > 0
if ((--attempts)>0) if ((--attempts)>0)
@@ -172,7 +196,7 @@ newpacket:
} }
#ifdef UIPETHERNET_DEBUG_CLIENT #ifdef UIPETHERNET_DEBUG_CLIENT
Serial.print(F("UIPClient.write: writePacket(")); Serial.print(F("UIPClient.write: writePacket("));
Serial.print(*p); Serial.print(u->packets_out[p]);
Serial.print(F(") pos: ")); Serial.print(F(") pos: "));
Serial.print(u->out_pos); Serial.print(u->out_pos);
Serial.print(F(", buf[")); Serial.print(F(", buf["));
@@ -183,12 +207,12 @@ newpacket:
Serial.write((uint8_t*)buf+size-remain,remain); Serial.write((uint8_t*)buf+size-remain,remain);
Serial.println(F("'")); Serial.println(F("'"));
#endif #endif
written = UIPEthernet.network.writePacket(*p,u->out_pos,(uint8_t*)buf+size-remain,remain); written = Enc28J60Network::writePacket(u->packets_out[p],u->out_pos,(uint8_t*)buf+size-remain,remain);
remain -= written; remain -= written;
u->out_pos+=written; u->out_pos+=written;
if (remain > 0) if (remain > 0)
{ {
if (p==&u->packets_out[UIP_SOCKET_NUMPACKETS-1]) if (p == UIP_SOCKET_NUMPACKETS-1)
{ {
#if UIP_ATTEMPTS_ON_WRITE > 0 #if UIP_ATTEMPTS_ON_WRITE > 0
if ((--attempts)>0) if ((--attempts)>0)
@@ -218,15 +242,10 @@ UIPClient::available()
int int
UIPClient::_available(uip_userdata_t *u) UIPClient::_available(uip_userdata_t *u)
{ {
memhandle* p = &u->packets_in[0];
if (*p == NOBLOCK)
return 0;
int len = 0; int len = 0;
for(memhandle* end = p+UIP_SOCKET_NUMPACKETS; p < end; p++) for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++)
{ {
if(*p == NOBLOCK) len += Enc28J60Network::blockSize(u->packets_in[i]);
break;
len += UIPEthernet.network.blockSize(*p);
} }
return len; return len;
} }
@@ -236,23 +255,22 @@ UIPClient::read(uint8_t *buf, size_t size)
{ {
if (*this) if (*this)
{ {
int remain = size; uint16_t remain = size;
memhandle* p = &data->packets_in[0]; if (data->packets_in[0] == NOBLOCK)
if (*p == NOBLOCK)
return 0; return 0;
int read; uint16_t read;
do do
{ {
read = UIPEthernet.network.readPacket(*p,0,buf+size-remain,remain); read = Enc28J60Network::readPacket(data->packets_in[0],0,buf+size-remain,remain);
if (read == UIPEthernet.network.blockSize(*p)) if (read == Enc28J60Network::blockSize(data->packets_in[0]))
{ {
remain -= read; remain -= read;
_eatBlock(p); _eatBlock(&data->packets_in[0]);
if (uip_stopped(&uip_conns[data->state & UIP_CLIENT_SOCKETS]) && !(data->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_CLOSED))) if (uip_stopped(&uip_conns[data->state & UIP_CLIENT_SOCKETS]) && !(data->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
data->state |= UIP_CLIENT_RESTART; data->state |= UIP_CLIENT_RESTART;
if (*p == NOBLOCK) if (data->packets_in[0] == NOBLOCK)
{ {
if (data->state & UIP_CLIENT_CLOSED) if (data->state & UIP_CLIENT_REMOTECLOSED)
{ {
data->state = 0; data->state = 0;
data = NULL; data = NULL;
@@ -262,7 +280,7 @@ UIPClient::read(uint8_t *buf, size_t size)
} }
else else
{ {
UIPEthernet.network.resizeBlock(*p,read); Enc28J60Network::resizeBlock(data->packets_in[0],read);
break; break;
} }
} }
@@ -286,11 +304,10 @@ UIPClient::peek()
{ {
if (*this) if (*this)
{ {
memhandle p = data->packets_in[0]; if (data->packets_in[0] != NOBLOCK)
if (p != NOBLOCK)
{ {
uint8_t c; uint8_t c;
UIPEthernet.network.readPacket(p,0,&c,1); Enc28J60Network::readPacket(data->packets_in[0],0,&c,1);
return c; return c;
} }
} }
@@ -308,26 +325,21 @@ UIPClient::flush()
void void
uipclient_appcall(void) uipclient_appcall(void)
{
UIPClient::uip_callback();
}
void
UIPClient::uip_callback()
{ {
uip_userdata_t *u = (uip_userdata_t*)uip_conn->appstate; uip_userdata_t *u = (uip_userdata_t*)uip_conn->appstate;
if (!u && uip_connected()) if (!u && uip_connected())
{ {
#ifdef UIPETHERNET_DEBUG_CLIENT #ifdef UIPETHERNET_DEBUG_CLIENT
Serial.println(F("UIPClient uip_connected")); Serial.println(F("UIPClient uip_connected"));
UIPClient::_dumpAllData();
#endif #endif
u = (uip_userdata_t*) _allocateData(); u = (uip_userdata_t*) UIPClient::_allocateData();
if (u) if (u)
{ {
uip_conn->appstate = u; uip_conn->appstate = u;
#ifdef UIPETHERNET_DEBUG_CLIENT #ifdef UIPETHERNET_DEBUG_CLIENT
Serial.print(F("UIPClient allocated state: ")); Serial.print(F("UIPClient allocated state: "));
Serial.println(u->state); Serial.println(u->state,BIN);
#endif #endif
} }
#ifdef UIPETHERNET_DEBUG_CLIENT #ifdef UIPETHERNET_DEBUG_CLIENT
@@ -343,33 +355,24 @@ UIPClient::uip_callback()
Serial.print(F("UIPClient uip_newdata, uip_len:")); Serial.print(F("UIPClient uip_newdata, uip_len:"));
Serial.println(uip_len); Serial.println(uip_len);
#endif #endif
if (uip_len && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_CLOSED))) if (uip_len && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
{ {
memhandle newPacket = UIPEthernet.network.allocBlock(uip_len); memhandle newPacket = Enc28J60Network::allocBlock(uip_len);
if (newPacket != NOBLOCK) if (newPacket != NOBLOCK)
{ {
memhandle* p = _currentBlock(&u->packets_in[0]); for (uint8_t i=0; i < UIP_SOCKET_NUMPACKETS; i++)
//if it's not the first packet
if (*p != NOBLOCK)
{ {
uint8_t slot = p - &u->packets_in[0]; if (u->packets_in[i] == NOBLOCK)
if (slot < UIP_SOCKET_NUMPACKETS-1)
p++;
//if this is the last slot stop this connection
if (slot >= UIP_SOCKET_NUMPACKETS-2)
{ {
uip_stop(); if (i == UIP_SOCKET_NUMPACKETS-1)
//if there's no free slot left omit loosing this packet and (again) stop this connection uip_stop();
if (slot == UIP_SOCKET_NUMPACKETS-1) Enc28J60Network::copyPacket(newPacket,0,UIPEthernetClass::in_packet,((uint8_t*)uip_appdata)-uip_buf,uip_len);
goto reject_newdata; u->packets_in[i] = newPacket;
goto finish_newdata;
} }
} }
UIPEthernet.network.copyPacket(newPacket,0,UIPEthernet.in_packet,((uint8_t*)uip_appdata)-uip_buf,uip_len);
*p = newPacket;
goto finish_newdata;
} }
reject_newdata: UIPEthernetClass::packetstate &= ~UIPETHERNET_FREEPACKET;
UIPEthernet.packetstate &= ~UIPETHERNET_FREEPACKET;
uip_stop(); uip_stop();
} }
} }
@@ -384,17 +387,22 @@ finish_newdata:
{ {
#ifdef UIPETHERNET_DEBUG_CLIENT #ifdef UIPETHERNET_DEBUG_CLIENT
Serial.println(F("UIPClient uip_closed")); Serial.println(F("UIPClient uip_closed"));
UIPClient::_dumpAllData();
#endif #endif
// drop outgoing packets not sent yet: // drop outgoing packets not sent yet:
_flushBlocks(&u->packets_out[0]); UIPClient::_flushBlocks(&u->packets_out[0]);
if (u->packets_in[0] != NOBLOCK) if (u->packets_in[0] != NOBLOCK)
{ {
((uip_userdata_closed_t *)u)->lport = uip_conn->lport; ((uip_userdata_closed_t *)u)->lport = uip_conn->lport;
u->state |= UIP_CLIENT_CLOSED; u->state |= UIP_CLIENT_REMOTECLOSED;
} }
else else
u->state = 0; u->state = 0;
// disassociate appdata. // disassociate appdata.
#ifdef UIPETHERNET_DEBUG_CLIENT
Serial.println(F("after UIPClient uip_closed"));
UIPClient::_dumpAllData();
#endif
uip_conn->appstate = NULL; uip_conn->appstate = NULL;
goto nodata; goto nodata;
} }
@@ -403,34 +411,33 @@ finish_newdata:
#ifdef UIPETHERNET_DEBUG_CLIENT #ifdef UIPETHERNET_DEBUG_CLIENT
Serial.println(F("UIPClient uip_acked")); Serial.println(F("UIPClient uip_acked"));
#endif #endif
_eatBlock(&u->packets_out[0]); UIPClient::_eatBlock(&u->packets_out[0]);
} }
if (uip_poll() || uip_rexmit()) if (uip_poll() || uip_rexmit())
{ {
#ifdef UIPETHERNET_DEBUG_CLIENT #ifdef UIPETHERNET_DEBUG_CLIENT
//Serial.println(F("UIPClient uip_poll")); //Serial.println(F("UIPClient uip_poll"));
#endif #endif
memhandle p = u->packets_out[0]; if (u->packets_out[0] != NOBLOCK)
if (p != NOBLOCK)
{ {
if (u->packets_out[1] == NOBLOCK) if (u->packets_out[1] == NOBLOCK)
{ {
uip_len = u->out_pos; uip_len = u->out_pos;
if (uip_len > 0) if (uip_len > 0)
{ {
UIPEthernet.network.resizeBlock(p,0,uip_len); Enc28J60Network::resizeBlock(u->packets_out[0],0,uip_len);
} }
} }
else else
uip_len = UIPEthernet.network.blockSize(p); uip_len = Enc28J60Network::blockSize(u->packets_out[0]);
if (uip_len > 0) if (uip_len > 0)
{ {
UIPEthernet.uip_hdrlen = ((uint8_t*)uip_appdata)-uip_buf; UIPEthernetClass::uip_hdrlen = ((uint8_t*)uip_appdata)-uip_buf;
UIPEthernet.uip_packet = UIPEthernet.network.allocBlock(UIPEthernet.uip_hdrlen+uip_len); UIPEthernetClass::uip_packet = Enc28J60Network::allocBlock(UIPEthernetClass::uip_hdrlen+uip_len);
if (UIPEthernet.uip_packet != NOBLOCK) if (UIPEthernetClass::uip_packet != NOBLOCK)
{ {
UIPEthernet.network.copyPacket(UIPEthernet.uip_packet,UIPEthernet.uip_hdrlen,p,0,uip_len); Enc28J60Network::copyPacket(UIPEthernetClass::uip_packet,UIPEthernetClass::uip_hdrlen,u->packets_out[0],0,uip_len);
UIPEthernet.packetstate |= UIPETHERNET_SENDPACKET; UIPEthernetClass::packetstate |= UIPETHERNET_SENDPACKET;
uip_send(uip_appdata,uip_len); uip_send(uip_appdata,uip_len);
} }
return; return;
@@ -441,23 +448,30 @@ finish_newdata:
if (u->state & UIP_CLIENT_CLOSE) if (u->state & UIP_CLIENT_CLOSE)
{ {
#ifdef UIPETHERNET_DEBUG_CLIENT #ifdef UIPETHERNET_DEBUG_CLIENT
Serial.print(F("UIPClient state UIP_CLIENT_CLOSE")); Serial.println(F("UIPClient state UIP_CLIENT_CLOSE"));
UIPClient::_dumpAllData();
#endif #endif
if (u->packets_out[0] == NOBLOCK) if (u->packets_out[0] == NOBLOCK)
{ {
#ifdef UIPETHERNET_DEBUG_CLIENT
Serial.print(F("UIPClient state UIP_CLIENT_CLOSE -> free userdata"));
#endif
u->state = 0; u->state = 0;
uip_conn->appstate = NULL; uip_conn->appstate = NULL;
uip_close(); uip_close();
#ifdef UIPETHERNET_DEBUG_CLIENT
Serial.println(F("no blocks out -> free userdata"));
UIPClient::_dumpAllData();
#endif
} }
else else
uip_stop(); {
uip_stop();
#ifdef UIPETHERNET_DEBUG_CLIENT
Serial.println(F("blocks outstanding transfer -> uip_stop()"));
#endif
}
} }
} }
nodata: nodata:
UIPEthernet.uip_packet = NOBLOCK; UIPEthernetClass::uip_packet = NOBLOCK;
uip_len=0; uip_len=0;
} }
@@ -477,13 +491,15 @@ UIPClient::_allocateData()
return NULL; return NULL;
} }
memhandle* uint8_t
UIPClient::_currentBlock(memhandle* block) UIPClient::_currentBlock(memhandle* block)
{ {
for(memhandle* end = block+UIP_SOCKET_NUMPACKETS-1; block < end; block++) for (uint8_t i = 1; i < UIP_SOCKET_NUMPACKETS; i++)
if(*(block+1) == NOBLOCK) {
break; if (block[i] == NOBLOCK)
return block; return i-1;
}
return UIP_SOCKET_NUMPACKETS-1;
} }
void void
@@ -493,19 +509,20 @@ UIPClient::_eatBlock(memhandle* block)
memhandle* start = block; memhandle* start = block;
Serial.print(F("eatblock(")); Serial.print(F("eatblock("));
Serial.print(*block); Serial.print(*block);
Serial.print("): "); Serial.print(F("): "));
for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++)
{ {
Serial.print(start[i]); Serial.print(start[i]);
Serial.print(" "); Serial.print(F(" "));
} }
Serial.print("-> "); Serial.print(F("-> "));
#endif #endif
memhandle* end = block+(UIP_SOCKET_NUMPACKETS-1); Enc28J60Network::freeBlock(block[0]);
UIPEthernet.network.freeBlock(*block); for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS-1; i++)
while(block < end) {
*block = *((block++)+1); block[i] = block[i+1];
*end = NOBLOCK; }
block[UIP_SOCKET_NUMPACKETS-1] = NOBLOCK;
#ifdef UIPETHERNET_DEBUG_CLIENT #ifdef UIPETHERNET_DEBUG_CLIENT
for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++)
{ {
@@ -519,15 +536,46 @@ UIPClient::_eatBlock(memhandle* block)
void void
UIPClient::_flushBlocks(memhandle* block) UIPClient::_flushBlocks(memhandle* block)
{ {
for(memhandle* end = block+UIP_SOCKET_NUMPACKETS; block < end; block++) for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++)
{ {
if(*block != NOBLOCK) Enc28J60Network::freeBlock(block[i]);
{ block[i] = NOBLOCK;
UIPEthernet.network.freeBlock(*block);
*block = NOBLOCK;
}
else
break;
} }
} }
#ifdef UIPETHERNET_DEBUG_CLIENT
void
UIPClient::_dumpAllData() {
for (uint8_t i=0; i < UIP_CONNS; i++)
{
Serial.print(F("UIPClient::all_data["));
Serial.print(i);
Serial.print(F("], state:"));
Serial.println(all_data[i].state, BIN);
Serial.print(F("packets_in: "));
for (uint8_t j=0; j < UIP_SOCKET_NUMPACKETS; j++)
{
Serial.print(all_data[i].packets_in[j]);
Serial.print(F(" "));
}
Serial.println();
if (all_data[i].state & UIP_CLIENT_REMOTECLOSED)
{
Serial.print(F("state remote closed, local port: "));
Serial.println(htons(((uip_userdata_closed_t *)(&all_data[i]))->lport));
}
else
{
Serial.print(F("packets_out: "));
for (uint8_t j=0; j < UIP_SOCKET_NUMPACKETS; j++)
{
Serial.print(all_data[i].packets_out[j]);
Serial.print(F(" "));
}
Serial.println();
Serial.print(F("out_pos: "));
Serial.println(all_data[i].out_pos);
}
}
}
#endif
+11 -6
View File
@@ -21,6 +21,7 @@
#define UIPCLIENT_H #define UIPCLIENT_H
#include "ethernet_comp.h" #include "ethernet_comp.h"
#include "Print.h"
#import "Client.h" #import "Client.h"
#import "utility/mempool.h" #import "utility/mempool.h"
@@ -36,9 +37,9 @@ extern "C" {
#define UIP_CLIENT_CONNECTED 0x10 #define UIP_CLIENT_CONNECTED 0x10
#define UIP_CLIENT_CLOSE 0x20 #define UIP_CLIENT_CLOSE 0x20
#define UIP_CLIENT_CLOSED 0x40 #define UIP_CLIENT_REMOTECLOSED 0x40
#define UIP_CLIENT_RESTART 0x80 #define UIP_CLIENT_RESTART 0x80
#define UIP_CLIENT_STATEFLAGS (UIP_CLIENT_CONNECTED | UIP_CLIENT_CLOSE | UIP_CLIENT_CLOSED | UIP_CLIENT_RESTART) #define UIP_CLIENT_STATEFLAGS (UIP_CLIENT_CONNECTED | UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED | UIP_CLIENT_RESTART)
#define UIP_CLIENT_SOCKETS ~UIP_CLIENT_STATEFLAGS #define UIP_CLIENT_SOCKETS ~UIP_CLIENT_STATEFLAGS
typedef uint8_t uip_socket_ptr; typedef uint8_t uip_socket_ptr;
@@ -76,6 +77,8 @@ public:
int peek(); int peek();
void flush(); void flush();
using Print::write;
private: private:
UIPClient(struct uip_conn *_conn); UIPClient(struct uip_conn *_conn);
UIPClient(uip_userdata_t* conn_data); UIPClient(uip_userdata_t* conn_data);
@@ -84,21 +87,23 @@ private:
static uip_userdata_t all_data[UIP_CONNS]; static uip_userdata_t all_data[UIP_CONNS];
static uip_userdata_t* _allocateData(); static uip_userdata_t* _allocateData();
static uip_userdata_t* _getData(struct uip_conn * conn);
static size_t _write(uip_userdata_t *,const uint8_t *buf, size_t size); static size_t _write(uip_userdata_t *,const uint8_t *buf, size_t size);
static int _available(uip_userdata_t *); static int _available(uip_userdata_t *);
static memhandle * _currentBlock(memhandle* blocks); static uint8_t _currentBlock(memhandle* blocks);
static void _eatBlock(memhandle* blocks); static void _eatBlock(memhandle* blocks);
static void _flushBlocks(memhandle* blocks); static void _flushBlocks(memhandle* blocks);
#ifdef UIPETHERNET_DEBUG_CLIENT
static void _dumpAllData();
#endif
friend class UIPEthernetClass; friend class UIPEthernetClass;
friend class UIPServer; friend class UIPServer;
friend void uipclient_appcall(void); friend void uipclient_appcall(void);
static void uip_callback();
}; };
#endif #endif
+60 -37
View File
@@ -25,6 +25,8 @@
#include "HardwareSerial.h" #include "HardwareSerial.h"
#endif #endif
#include "UIPUdp.h"
extern "C" extern "C"
{ {
#include "utility/uip-conf.h" #include "utility/uip-conf.h"
@@ -35,18 +37,24 @@ extern "C"
#define ETH_HDR ((struct uip_eth_hdr *)&uip_buf[0]) #define ETH_HDR ((struct uip_eth_hdr *)&uip_buf[0])
memhandle UIPEthernetClass::in_packet(NOBLOCK);
memhandle UIPEthernetClass::uip_packet(NOBLOCK);
uint8_t UIPEthernetClass::uip_hdrlen(0);
uint8_t UIPEthernetClass::packetstate(0);
IPAddress UIPEthernetClass::_dnsServerAddress;
DhcpClass* UIPEthernetClass::_dhcp(NULL);
struct uip_timer UIPEthernetClass::periodic_timer;
// Because uIP isn't encapsulated within a class we have to use global // Because uIP isn't encapsulated within a class we have to use global
// variables, so we can only have one TCP/IP stack per program. // variables, so we can only have one TCP/IP stack per program.
UIPEthernetClass::UIPEthernetClass() : UIPEthernetClass::UIPEthernetClass()
in_packet(NOBLOCK),
uip_packet(NOBLOCK),
uip_hdrlen(0),
packetstate(0),
_dhcp(NULL)
{ {
} }
#if UIP_UDP
int int
UIPEthernetClass::begin(const uint8_t* mac) UIPEthernetClass::begin(const uint8_t* mac)
{ {
@@ -66,6 +74,7 @@ UIPEthernetClass::begin(const uint8_t* mac)
} }
return ret; return ret;
} }
#endif
void void
UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip) UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip)
@@ -100,6 +109,7 @@ UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddre
int UIPEthernetClass::maintain(){ int UIPEthernetClass::maintain(){
tick(); tick();
int rc = DHCP_CHECK_NONE; int rc = DHCP_CHECK_NONE;
#if UIP_UDP
if(_dhcp != NULL){ if(_dhcp != NULL){
//we have a pointer to dhcp, use it //we have a pointer to dhcp, use it
rc = _dhcp->checkLease(); rc = _dhcp->checkLease();
@@ -118,6 +128,7 @@ int UIPEthernetClass::maintain(){
} }
} }
return rc; return rc;
#endif
} }
IPAddress UIPEthernetClass::localIP() IPAddress UIPEthernetClass::localIP()
@@ -154,7 +165,7 @@ UIPEthernetClass::tick()
{ {
if (in_packet == NOBLOCK) if (in_packet == NOBLOCK)
{ {
in_packet = network.receivePacket(); in_packet = Enc28J60Network::receivePacket();
#ifdef UIPETHERNET_DEBUG #ifdef UIPETHERNET_DEBUG
if (in_packet != NOBLOCK) if (in_packet != NOBLOCK)
{ {
@@ -166,10 +177,10 @@ UIPEthernetClass::tick()
if (in_packet != NOBLOCK) if (in_packet != NOBLOCK)
{ {
packetstate = UIPETHERNET_FREEPACKET; packetstate = UIPETHERNET_FREEPACKET;
uip_len = network.blockSize(in_packet); uip_len = Enc28J60Network::blockSize(in_packet);
if (uip_len > 0) if (uip_len > 0)
{ {
network.readPacket(in_packet,0,(uint8_t*)uip_buf,UIP_BUFSIZE); Enc28J60Network::readPacket(in_packet,0,(uint8_t*)uip_buf,UIP_BUFSIZE);
if (ETH_HDR ->type == HTONS(UIP_ETHTYPE_IP)) if (ETH_HDR ->type == HTONS(UIP_ETHTYPE_IP))
{ {
uip_packet = in_packet; uip_packet = in_packet;
@@ -204,7 +215,7 @@ UIPEthernetClass::tick()
Serial.print(F("freeing packet: ")); Serial.print(F("freeing packet: "));
Serial.println(in_packet); Serial.println(in_packet);
#endif #endif
network.freePacket(); Enc28J60Network::freePacket();
in_packet = NOBLOCK; in_packet = NOBLOCK;
} }
} }
@@ -216,7 +227,7 @@ UIPEthernetClass::tick()
{ {
uip_periodic(i); uip_periodic(i);
// If the above function invocation resulted in data that // If the above function invocation resulted in data that
// should be sent out on the network, the global variable // should be sent out on the Enc28J60Network, the global variable
// uip_len is set to a value > 0. // uip_len is set to a value > 0.
if (uip_len > 0) if (uip_len > 0)
{ {
@@ -230,11 +241,11 @@ UIPEthernetClass::tick()
{ {
uip_udp_periodic(i); uip_udp_periodic(i);
// If the above function invocation resulted in data that // If the above function invocation resulted in data that
// should be sent out on the network, the global variable // should be sent out on the Enc28J60Network, the global variable
// uip_len is set to a value > 0. */ // uip_len is set to a value > 0. */
if (uip_len > 0) if (uip_len > 0)
{ {
network_send(); UIPUDP::_send((uip_udp_userdata_t *)(uip_udp_conns[i].appstate));
} }
} }
#endif /* UIP_UDP */ #endif /* UIP_UDP */
@@ -246,41 +257,42 @@ boolean UIPEthernetClass::network_send()
if (packetstate & UIPETHERNET_SENDPACKET) if (packetstate & UIPETHERNET_SENDPACKET)
{ {
#ifdef UIPETHERNET_DEBUG #ifdef UIPETHERNET_DEBUG
Serial.print(F("network_send uip_packet: ")); Serial.print(F("Enc28J60Network_send uip_packet: "));
Serial.print(uip_packet); Serial.print(uip_packet);
Serial.print(F(", hdrlen: ")); Serial.print(F(", hdrlen: "));
Serial.println(uip_hdrlen); Serial.println(uip_hdrlen);
#endif #endif
network.writePacket(uip_packet,0,uip_buf,uip_hdrlen); Enc28J60Network::writePacket(uip_packet,0,uip_buf,uip_hdrlen);
goto sendandfree; goto sendandfree;
} }
uip_packet = network.allocBlock(uip_len); uip_packet = Enc28J60Network::allocBlock(uip_len);
if (uip_packet != NOBLOCK) if (uip_packet != NOBLOCK)
{ {
#ifdef UIPETHERNET_DEBUG #ifdef UIPETHERNET_DEBUG
Serial.print(F("network_send uip_buf (uip_len): ")); Serial.print(F("Enc28J60Network_send uip_buf (uip_len): "));
Serial.print(uip_len); Serial.print(uip_len);
Serial.print(F(", packet: ")); Serial.print(F(", packet: "));
Serial.println(uip_packet); Serial.println(uip_packet);
#endif #endif
network.writePacket(uip_packet,0,uip_buf,uip_len); Enc28J60Network::writePacket(uip_packet,0,uip_buf,uip_len);
goto sendandfree; goto sendandfree;
} }
return false; return false;
sendandfree: sendandfree:
network.sendPacket(uip_packet); Enc28J60Network::sendPacket(uip_packet);
network.freeBlock(uip_packet); Enc28J60Network::freeBlock(uip_packet);
uip_packet = NOBLOCK; uip_packet = NOBLOCK;
return true; return true;
} }
void UIPEthernetClass::init(const uint8_t* mac) { void UIPEthernetClass::init(const uint8_t* mac) {
uip_timer_set(&this->periodic_timer, CLOCK_SECOND / 4); uip_timer_set(&periodic_timer, CLOCK_SECOND / 4);
network.init((uint8_t*)mac); Enc28J60Network::init((uint8_t*)mac);
uip_seteth_addr(mac); uip_seteth_addr(mac);
uip_init(); uip_init();
uip_arp_init();
} }
void UIPEthernetClass::configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) { void UIPEthernetClass::configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) {
@@ -345,7 +357,11 @@ UIPEthernetClass::ipchksum(void)
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
uint16_t uint16_t
#if UIP_UDP
UIPEthernetClass::upper_layer_chksum(uint8_t proto) UIPEthernetClass::upper_layer_chksum(uint8_t proto)
#else
uip_tcpchksum(void)
#endif
{ {
uint16_t upper_layer_len; uint16_t upper_layer_len;
uint16_t sum; uint16_t sum;
@@ -359,27 +375,34 @@ UIPEthernetClass::upper_layer_chksum(uint8_t proto)
/* First sum pseudoheader. */ /* First sum pseudoheader. */
/* IP protocol and length fields. This addition cannot carry. */ /* IP protocol and length fields. This addition cannot carry. */
#if UIP_UDP
sum = upper_layer_len + proto; sum = upper_layer_len + proto;
#else
sum = upper_layer_len + UIP_PROTO_TCP;
#endif
/* Sum IP source and destination addresses. */ /* Sum IP source and destination addresses. */
sum = chksum(sum, (u8_t *)&BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t)); sum = UIPEthernetClass::chksum(sum, (u8_t *)&BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t));
uint8_t upper_layer_memlen; uint8_t upper_layer_memlen;
#if UIP_UDP
switch(proto) switch(proto)
{ {
case UIP_PROTO_ICMP: // case UIP_PROTO_ICMP:
case UIP_PROTO_ICMP6: // case UIP_PROTO_ICMP6:
upper_layer_memlen = upper_layer_len; // upper_layer_memlen = upper_layer_len;
break; // break;
case UIP_PROTO_TCP: case UIP_PROTO_UDP:
upper_layer_memlen = (BUF->tcpoffset >> 4) << 2;
break;
#if UIP_UDP
case UIP_PROTO_UDP:
upper_layer_memlen = UIP_UDPH_LEN; upper_layer_memlen = UIP_UDPH_LEN;
break; break;
default:
// case UIP_PROTO_TCP:
#endif #endif
upper_layer_memlen = (BUF->tcpoffset >> 4) << 2;
#if UIP_UDP
break;
} }
sum = chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_memlen); #endif
sum = UIPEthernetClass::chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_memlen);
#ifdef UIPETHERNET_DEBUG_CHKSUM #ifdef UIPETHERNET_DEBUG_CHKSUM
Serial.print(F("chksum uip_buf[")); Serial.print(F("chksum uip_buf["));
Serial.print(UIP_IPH_LEN + UIP_LLH_LEN); Serial.print(UIP_IPH_LEN + UIP_LLH_LEN);
@@ -390,9 +413,9 @@ UIPEthernetClass::upper_layer_chksum(uint8_t proto)
#endif #endif
if (upper_layer_memlen < upper_layer_len) if (upper_layer_memlen < upper_layer_len)
{ {
sum = network.chksum( sum = Enc28J60Network::chksum(
sum, sum,
uip_packet, UIPEthernetClass::uip_packet,
UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen, UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen,
upper_layer_len - upper_layer_memlen upper_layer_len - upper_layer_memlen
); );
@@ -403,7 +426,7 @@ UIPEthernetClass::upper_layer_chksum(uint8_t proto)
Serial.print(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen); Serial.print(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen);
Serial.print(F("-")); Serial.print(F("-"));
Serial.print(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_len); Serial.print(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_len);
Serial.print(F"]: ")); Serial.print(F("]: "));
Serial.println(htons(sum),HEX); Serial.println(htons(sum),HEX);
#endif #endif
} }
@@ -416,6 +439,7 @@ uip_ipchksum(void)
return UIPEthernet.ipchksum(); return UIPEthernet.ipchksum();
} }
#if UIP_UDP
uint16_t uint16_t
uip_tcpchksum(void) uip_tcpchksum(void)
{ {
@@ -423,7 +447,6 @@ uip_tcpchksum(void)
return sum; return sum;
} }
#if UIP_UDP
uint16_t uint16_t
uip_udpchksum(void) uip_udpchksum(void)
{ {
+23 -21
View File
@@ -20,6 +20,11 @@
#ifndef UIPETHERNET_H #ifndef UIPETHERNET_H
#define UIPETHERNET_H #define UIPETHERNET_H
//#define UIPETHERNET_DEBUG
//#define UIPETHERNET_DEBUG_CHKSUM
//#define UIPETHERNET_DEBUG_UDP
//#define UIPETHERNET_DEBUG_CLIENT
#include "ethernet_comp.h" #include "ethernet_comp.h"
#include <Arduino.h> #include <Arduino.h>
#include "Dhcp.h" #include "Dhcp.h"
@@ -35,11 +40,6 @@ extern "C"
#include "utility/uip.h" #include "utility/uip.h"
} }
//#define UIPETHERNET_DEBUG
//#define UIPETHERNET_DEBUG_CHKSUM
//#define UIPETHERNET_DEBUG_UDP
//#define UIPETHERNET_DEBUG_CLIENT
#define UIPETHERNET_FREEPACKET 1 #define UIPETHERNET_FREEPACKET 1
#define UIPETHERNET_SENDPACKET 2 #define UIPETHERNET_SENDPACKET 2
#define UIPETHERNET_BUFFERREAD 4 #define UIPETHERNET_BUFFERREAD 4
@@ -82,24 +82,22 @@ public:
IPAddress dnsServerIP(); IPAddress dnsServerIP();
private: private:
IPAddress _dnsServerAddress; static memhandle in_packet;
DhcpClass* _dhcp; static memhandle uip_packet;
static uint8_t uip_hdrlen;
static uint8_t packetstate;
static IPAddress _dnsServerAddress;
static DhcpClass* _dhcp;
struct uip_timer periodic_timer; static struct uip_timer periodic_timer;
memhandle in_packet; static void init(const uint8_t* mac);
memhandle uip_packet; static void configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet);
uint8_t uip_hdrlen;
uint8_t packetstate;
Enc28J60Network network; static void tick();
void init(const uint8_t* mac); static boolean network_send();
void configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet);
void tick();
boolean network_send();
friend class UIPServer; friend class UIPServer;
@@ -109,12 +107,16 @@ private:
static uint16_t chksum(uint16_t sum, const uint8_t* data, uint16_t len); static uint16_t chksum(uint16_t sum, const uint8_t* data, uint16_t len);
static uint16_t ipchksum(void); static uint16_t ipchksum(void);
uint16_t upper_layer_chksum(uint8_t proto); #if UIP_UDP
static uint16_t upper_layer_chksum(uint8_t proto);
#endif
friend uint16_t uip_ipchksum(void); friend uint16_t uip_ipchksum(void);
friend uint16_t uip_tcpchksum(void); friend uint16_t uip_tcpchksum(void);
friend uint16_t uip_udpchksum(void); friend uint16_t uip_udpchksum(void);
friend void uipclient_appcall(void);
friend void uipudp_appcall(void);
#if UIP_CONF_IPV6 #if UIP_CONF_IPV6
uint16_t uip_icmp6chksum(void); uint16_t uip_icmp6chksum(void);
#endif /* UIP_CONF_IPV6 */ #endif /* UIP_CONF_IPV6 */
+3 -3
View File
@@ -28,12 +28,12 @@ UIPServer::UIPServer(uint16_t port) : _port(htons(port))
UIPClient UIPServer::available() UIPClient UIPServer::available()
{ {
UIPEthernet.tick(); UIPEthernetClass::tick();
for ( uip_userdata_t* data = &UIPClient::all_data[0]; data < &UIPClient::all_data[UIP_CONNS]; data++ ) for ( uip_userdata_t* data = &UIPClient::all_data[0]; data < &UIPClient::all_data[UIP_CONNS]; data++ )
{ {
if (data->packets_in[0] != NOBLOCK if (data->packets_in[0] != NOBLOCK
&& (((data->state & UIP_CLIENT_CONNECTED) && uip_conns[data->state & UIP_CLIENT_SOCKETS].lport ==_port) && (((data->state & UIP_CLIENT_CONNECTED) && uip_conns[data->state & UIP_CLIENT_SOCKETS].lport ==_port)
|| ((data->state & UIP_CLIENT_CLOSED) && ((uip_userdata_closed_t *)data)->lport == _port))) || ((data->state & UIP_CLIENT_REMOTECLOSED) && ((uip_userdata_closed_t *)data)->lport == _port)))
return UIPClient(data); return UIPClient(data);
} }
return UIPClient(); return UIPClient();
@@ -42,7 +42,7 @@ UIPClient UIPServer::available()
void UIPServer::begin() void UIPServer::begin()
{ {
uip_listen(_port); uip_listen(_port);
UIPEthernet.tick(); UIPEthernetClass::tick();
} }
size_t UIPServer::write(uint8_t c) size_t UIPServer::write(uint8_t c)
+1 -1
View File
@@ -23,7 +23,7 @@
#import "Server.h" #import "Server.h"
#import "UIPClient.h" #import "UIPClient.h"
class UIPServer : Server { class UIPServer : public Server {
public: public:
UIPServer(uint16_t); UIPServer(uint16_t);
+81 -122
View File
@@ -65,28 +65,13 @@ UIPUDP::stop()
{ {
if (_uip_udp_conn) if (_uip_udp_conn)
{ {
flush();
uip_udp_remove(_uip_udp_conn); uip_udp_remove(_uip_udp_conn);
_uip_udp_conn->appstate = NULL; _uip_udp_conn->appstate = NULL;
_uip_udp_conn=NULL; _uip_udp_conn=NULL;
if (appdata.packet_in != NOBLOCK) Enc28J60Network::freeBlock(appdata.packet_in);
{ Enc28J60Network::freeBlock(appdata.packet_next);
UIPEthernet.network.freeBlock(appdata.packet_in); Enc28J60Network::freeBlock(appdata.packet_out);
appdata.packet_in = NOBLOCK; memset(&appdata,0,sizeof(appdata));
}
uint8_t i = 0;
memhandle* packet = &appdata.packets_in[0];
while (*packet != NOBLOCK && i < UIP_UDP_NUMPACKETS)
{
UIPEthernet.network.freeBlock(*packet);
*packet++ = NOBLOCK;
i++;
}
if (appdata.packet_out != NOBLOCK)
{
UIPEthernet.network.freeBlock(appdata.packet_out);
appdata.packet_out = NOBLOCK;
}
} }
} }
@@ -97,7 +82,7 @@ UIPUDP::stop()
int int
UIPUDP::beginPacket(IPAddress ip, uint16_t port) UIPUDP::beginPacket(IPAddress ip, uint16_t port)
{ {
UIPEthernet.tick(); UIPEthernetClass::tick();
if (ip && port) if (ip && port)
{ {
uip_ipaddr_t ripaddr; uip_ipaddr_t ripaddr;
@@ -139,7 +124,7 @@ UIPUDP::beginPacket(IPAddress ip, uint16_t port)
{ {
if (appdata.packet_out == NOBLOCK) if (appdata.packet_out == NOBLOCK)
{ {
appdata.packet_out = UIPEthernet.network.allocBlock(UIP_UDP_MAXPACKETSIZE); appdata.packet_out = Enc28J60Network::allocBlock(UIP_UDP_MAXPACKETSIZE);
appdata.out_pos = UIP_UDP_PHYH_LEN; appdata.out_pos = UIP_UDP_PHYH_LEN;
if (appdata.packet_out != NOBLOCK) if (appdata.packet_out != NOBLOCK)
return 1; return 1;
@@ -183,11 +168,11 @@ UIPUDP::endPacket()
if (_uip_udp_conn && appdata.packet_out != NOBLOCK) if (_uip_udp_conn && appdata.packet_out != NOBLOCK)
{ {
appdata.send = true; appdata.send = true;
UIPEthernet.network.resizeBlock(appdata.packet_out,0,appdata.out_pos); Enc28J60Network::resizeBlock(appdata.packet_out,0,appdata.out_pos);
uip_udp_periodic_conn(_uip_udp_conn); uip_udp_periodic_conn(_uip_udp_conn);
if (uip_len > 0) if (uip_len > 0)
{ {
UIPEthernet.network_send(); _send(&appdata);
return 1; return 1;
} }
} }
@@ -207,7 +192,7 @@ UIPUDP::write(const uint8_t *buffer, size_t size)
{ {
if (appdata.packet_out != NOBLOCK) if (appdata.packet_out != NOBLOCK)
{ {
size_t ret = UIPEthernet.network.writePacket(appdata.packet_out,appdata.out_pos,(uint8_t*)buffer,size); size_t ret = Enc28J60Network::writePacket(appdata.packet_out,appdata.out_pos,(uint8_t*)buffer,size);
appdata.out_pos += ret; appdata.out_pos += ret;
return ret; return ret;
} }
@@ -219,61 +204,43 @@ UIPUDP::write(const uint8_t *buffer, size_t size)
int int
UIPUDP::parsePacket() UIPUDP::parsePacket()
{ {
UIPEthernet.tick(); UIPEthernetClass::tick();
#ifdef UIPETHERNET_DEBUG_UDP
if (appdata.packet_in != NOBLOCK) if (appdata.packet_in != NOBLOCK)
{ {
#ifdef UIPETHERNET_DEBUG_UDP
Serial.print(F("udp parsePacket freeing previous packet: ")); Serial.print(F("udp parsePacket freeing previous packet: "));
Serial.println(appdata.packet_in); Serial.println(appdata.packet_in);
#endif;
UIPEthernet.network.freeBlock(appdata.packet_in);
} }
memhandle *packet = &appdata.packets_in[0]; #endif
appdata.packet_in = *packet; Enc28J60Network::freeBlock(appdata.packet_in);
appdata.packet_in = appdata.packet_next;
appdata.packet_next = NOBLOCK;
#ifdef UIPETHERNET_DEBUG_UDP
if (appdata.packet_in != NOBLOCK) if (appdata.packet_in != NOBLOCK)
{ {
#ifdef UIPETHERNET_DEBUG_UDP
Serial.print(F("udp parsePacket received packet: ")); Serial.print(F("udp parsePacket received packet: "));
Serial.print(appdata.packet_in); Serial.print(appdata.packet_in);
}
#endif #endif
if (UIP_UDP_NUMPACKETS > 1) int size = Enc28J60Network::blockSize(appdata.packet_in);
{
uint8_t i = 1;
memhandle* p = packet+1;
freeloop:
*packet = *p;
if (*packet == NOBLOCK)
goto freeready;
packet++;
if (i < UIP_UDP_NUMPACKETS-1)
{
i++;
p++;
goto freeloop;
}
}
*packet = NOBLOCK;
freeready:
int size = UIPEthernet.network.blockSize(appdata.packet_in);
#ifdef UIPETHERNET_DEBUG_UDP #ifdef UIPETHERNET_DEBUG_UDP
if (appdata.packet_in != NOBLOCK)
{
Serial.print(F(", size: ")); Serial.print(F(", size: "));
Serial.println(size); Serial.println(size);
#endif
return size;
} }
return 0; #endif
return size;
} }
// Number of bytes remaining in the current packet // Number of bytes remaining in the current packet
int int
UIPUDP::available() UIPUDP::available()
{ {
UIPEthernet.tick(); UIPEthernetClass::tick();
if (appdata.packet_in != NOBLOCK) return Enc28J60Network::blockSize(appdata.packet_in);
{
return UIPEthernet.network.blockSize(appdata.packet_in);
}
return 0;
} }
// Read a single byte from the current packet // Read a single byte from the current packet
@@ -293,11 +260,17 @@ UIPUDP::read()
int int
UIPUDP::read(unsigned char* buffer, size_t len) UIPUDP::read(unsigned char* buffer, size_t len)
{ {
UIPEthernet.tick(); UIPEthernetClass::tick();
if (appdata.packet_in != NOBLOCK) if (appdata.packet_in != NOBLOCK)
{ {
int read = UIPEthernet.network.readPacket(appdata.packet_in,0,buffer,len); memaddress read = Enc28J60Network::readPacket(appdata.packet_in,0,buffer,len);
UIPEthernet.network.resizeBlock(appdata.packet_in,read); if (read == Enc28J60Network::blockSize(appdata.packet_in))
{
Enc28J60Network::freeBlock(appdata.packet_in);
appdata.packet_in = NOBLOCK;
}
else
Enc28J60Network::resizeBlock(appdata.packet_in,read);
return read; return read;
} }
return 0; return 0;
@@ -307,11 +280,11 @@ UIPUDP::read(unsigned char* buffer, size_t len)
int int
UIPUDP::peek() UIPUDP::peek()
{ {
UIPEthernet.tick(); UIPEthernetClass::tick();
if (appdata.packet_in != NOBLOCK) if (appdata.packet_in != NOBLOCK)
{ {
unsigned char c; unsigned char c;
if (UIPEthernet.network.readPacket(appdata.packet_in,0,&c,1) == 1) if (Enc28J60Network::readPacket(appdata.packet_in,0,&c,1) == 1)
return c; return c;
} }
return -1; return -1;
@@ -321,12 +294,9 @@ UIPUDP::peek()
void void
UIPUDP::flush() UIPUDP::flush()
{ {
UIPEthernet.tick(); UIPEthernetClass::tick();
if (appdata.packet_in != NOBLOCK) Enc28J60Network::freeBlock(appdata.packet_in);
{ appdata.packet_in = NOBLOCK;
UIPEthernet.network.freeBlock(appdata.packet_in);
appdata.packet_in = NOBLOCK;
}
} }
// Return the IP address of the host who sent the current incoming packet // Return the IP address of the host who sent the current incoming packet
@@ -347,44 +317,28 @@ UIPUDP::remotePort()
void void
uipudp_appcall(void) { uipudp_appcall(void) {
UIPUDP::uip_callback(); if (uip_udp_userdata_t *data = (uip_udp_userdata_t *)(uip_udp_conn->appstate))
}
void
UIPUDP::uip_callback() {
if (appdata_t *data = (appdata_t *)(uip_udp_conn->appstate))
{ {
if (uip_newdata()) if (uip_newdata())
{ {
uip_udp_conn->rport = UDPBUF->srcport; if (data->packet_next == NOBLOCK)
uip_ipaddr_copy(uip_udp_conn->ripaddr,UDPBUF->srcipaddr);
memhandle *packet = &data->packets_in[0];
uint8_t i = 0;
do
{ {
if (*packet == NOBLOCK) uip_udp_conn->rport = UDPBUF->srcport;
{ uip_ipaddr_copy(uip_udp_conn->ripaddr,UDPBUF->srcipaddr);
*packet = UIPEthernet.network.allocBlock(ntohs(UDPBUF->udplen)-UIP_UDPH_LEN); data->packet_next = Enc28J60Network::allocBlock(ntohs(UDPBUF->udplen)-UIP_UDPH_LEN);
//if we are unable to allocate memory the packet is dropped. udp doesn't guarantee packet delivery //if we are unable to allocate memory the packet is dropped. udp doesn't guarantee packet delivery
if (*packet != NOBLOCK) if (data->packet_next != NOBLOCK)
{ {
//discard Linklevel and IP and udp-header and any trailing bytes: //discard Linklevel and IP and udp-header and any trailing bytes:
UIPEthernet.network.copyPacket(*packet,0,UIPEthernet.in_packet,UIP_UDP_PHYH_LEN,UIPEthernet.network.blockSize(*packet)); Enc28J60Network::copyPacket(data->packet_next,0,UIPEthernetClass::in_packet,UIP_UDP_PHYH_LEN,Enc28J60Network::blockSize(data->packet_next));
#ifdef UIPETHERNET_DEBUG_UDP #ifdef UIPETHERNET_DEBUG_UDP
Serial.print(F("udp, uip_newdata received packet: ")); Serial.print(F("udp, uip_newdata received packet: "));
Serial.print(*packet); Serial.print(data->packet_next);
Serial.print(F(", slot: ")); Serial.print(F(", size: "));
Serial.print(i); Serial.println(Enc28J60Network::blockSize(data->packet_next));
Serial.print(F(", size: "));
Serial.println(UIPEthernet.network.blockSize(*packet));
#endif #endif
break;
}
} }
packet++;
i++;
} }
while (i < UIP_UDP_NUMPACKETS);
} }
if (uip_poll() && data->send) if (uip_poll() && data->send)
{ {
@@ -393,32 +347,37 @@ UIPUDP::uip_callback() {
Serial.print(F("udp, uip_poll preparing packet to send: ")); Serial.print(F("udp, uip_poll preparing packet to send: "));
Serial.print(data->packet_out); Serial.print(data->packet_out);
Serial.print(F(", size: ")); Serial.print(F(", size: "));
Serial.println(UIPEthernet.network.blockSize(data->packet_out)); Serial.println(Enc28J60Network::blockSize(data->packet_out));
#endif #endif
UIPEthernet.uip_packet = data->packet_out; UIPEthernetClass::uip_packet = data->packet_out;
data->packet_out = NOBLOCK; UIPEthernetClass::uip_hdrlen = UIP_UDP_PHYH_LEN;
UIPEthernet.uip_hdrlen = UIP_UDP_PHYH_LEN;
UIPEthernet.packetstate |= UIPETHERNET_SENDPACKET;
uip_udp_send(data->out_pos - (UIP_UDP_PHYH_LEN)); uip_udp_send(data->out_pos - (UIP_UDP_PHYH_LEN));
uip_process(UIP_UDP_SEND_CONN); //generate udp + ip headers
uip_arp_out(); //add arp
if (uip_len == UIP_ARPHDRSIZE)
{
UIPEthernet.packetstate &= ~UIPETHERNET_SENDPACKET;
#ifdef UIPETHERNET_DEBUG_UDP
Serial.println(F("udp, uip_poll results in ARP-packet"));
#endif
}
else
//arp found ethaddr for ip (otherwise packet is replaced by arp-request)
{
data->send = false;
#ifdef UIPETHERNET_DEBUG_UDP
Serial.print(F("udp, uip_packet to send: "));
Serial.println(UIPEthernet.uip_packet);
#endif
}
} }
} }
} }
void
UIPUDP::_send(uip_udp_userdata_t *data) {
uip_arp_out(); //add arp
if (uip_len == UIP_ARPHDRSIZE)
{
UIPEthernetClass::uip_packet = NOBLOCK;
UIPEthernetClass::packetstate &= ~UIPETHERNET_SENDPACKET;
#ifdef UIPETHERNET_DEBUG_UDP
Serial.println(F("udp, uip_poll results in ARP-packet"));
#endif
}
else
//arp found ethaddr for ip (otherwise packet is replaced by arp-request)
{
data->send = false;
data->packet_out = NOBLOCK;
UIPEthernetClass::packetstate |= UIPETHERNET_SENDPACKET;
#ifdef UIPETHERNET_DEBUG_UDP
Serial.print(F("udp, uip_packet to send: "));
Serial.println(UIPEthernetClass::uip_packet);
#endif
}
UIPEthernetClass::network_send();
}
#endif #endif
+13 -13
View File
@@ -25,15 +25,20 @@
#include <Udp.h> #include <Udp.h>
#include "utility/mempool.h" #include "utility/mempool.h"
extern "C" { extern "C" {
#include "utility/uip.h"; #include "utility/uip.h"
} }
#define UIP_UDP_MAXDATALEN 1500 #define UIP_UDP_MAXDATALEN 1500
#define UIP_UDP_PHYH_LEN UIP_LLH_LEN+UIP_IPUDPH_LEN #define UIP_UDP_PHYH_LEN UIP_LLH_LEN+UIP_IPUDPH_LEN
#define UIP_UDP_MAXPACKETSIZE UIP_UDP_MAXDATALEN+UIP_UDP_PHYH_LEN #define UIP_UDP_MAXPACKETSIZE UIP_UDP_MAXDATALEN+UIP_UDP_PHYH_LEN
#ifndef UIP_UDP_NUMPACKETS
#define UIP_UDP_NUMPACKETS 5 typedef struct {
#endif memaddress out_pos;
memhandle packet_next;
memhandle packet_in;
memhandle packet_out;
boolean send;
} uip_udp_userdata_t;
class UIPUDP : public UDP class UIPUDP : public UDP
{ {
@@ -41,14 +46,7 @@ class UIPUDP : public UDP
private: private:
struct uip_udp_conn *_uip_udp_conn; struct uip_udp_conn *_uip_udp_conn;
struct appdata_t uip_udp_userdata_t appdata;
{
memaddress out_pos;
memhandle packets_in[UIP_UDP_NUMPACKETS];
memhandle packet_in;
memhandle packet_out;
boolean send;
} appdata;
public: public:
UIPUDP(); // Constructor UIPUDP(); // Constructor
@@ -120,7 +118,9 @@ private:
friend void uipudp_appcall(void); friend void uipudp_appcall(void);
static void uip_callback(); friend class UIPEthernetClass;
static void _send(uip_udp_userdata_t *data);
}; };
#endif #endif
+1 -1
View File
@@ -4,6 +4,6 @@
#define Ethernet UIPEthernet #define Ethernet UIPEthernet
#define EthernetClient UIPClient #define EthernetClient UIPClient
#define EthernetServer UIPServer #define EthernetServer UIPServer
//#define EthernetUDP UIPUDP #define EthernetUDP UIPUDP
#endif #endif
-478
View File
@@ -1,478 +0,0 @@
// DHCP Library v0.3 - April 25, 2009
// Author: Jordan Terrell - blog.jordanterrell.com
#include <string.h>
#include <stdlib.h>
#include "Dhcp.h"
#include "Arduino.h"
#include "utility/util.h"
int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout)
{
_dhcpLeaseTime=0;
_dhcpT1=0;
_dhcpT2=0;
_lastCheck=0;
_timeout = timeout;
_responseTimeout = responseTimeout;
// zero out _dhcpMacAddr
memset(_dhcpMacAddr, 0, 6);
reset_DHCP_lease();
memcpy((void*)_dhcpMacAddr, (void*)mac, 6);
_dhcp_state = STATE_DHCP_START;
return request_DHCP_lease();
}
void DhcpClass::reset_DHCP_lease(){
// zero out _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp
memset(_dhcpLocalIp, 0, 20);
}
//return:0 on error, 1 if request is sent and response is received
int DhcpClass::request_DHCP_lease(){
uint8_t messageType = 0;
// Pick an initial transaction ID
_dhcpTransactionId = random(1UL, 2000UL);
_dhcpInitialTransactionId = _dhcpTransactionId;
_dhcpUdpSocket.stop();
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_REREQUEST){
_dhcpTransactionId++;
send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime)/1000));
_dhcp_state = STATE_DHCP_REQUEST;
}
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;
//use default lease time if we didn't get it
if(_dhcpLeaseTime == 0){
_dhcpLeaseTime = DEFAULT_LEASE;
}
//calculate T1 & T2 if we didn't get it
if(_dhcpT1 == 0){
//T1 should be 50% of _dhcpLeaseTime
_dhcpT1 = _dhcpLeaseTime >> 1;
}
if(_dhcpT2 == 0){
//T2 should be 87.5% (7/8ths) of _dhcpLeaseTime
_dhcpT2 = _dhcpT1 << 1;
}
_renewInSec = _dhcpT1;
_rebindInSec = _dhcpT2;
}
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) + 6; // length of hostname + last 3 bytes of mac address
strcpy((char*)&(buffer[18]), HOST_NAME);
printByte((char*)&(buffer[24]), _dhcpMacAddr[3]);
printByte((char*)&(buffer[26]), _dhcpMacAddr[4]);
printByte((char*)&(buffer[28]), _dhcpMacAddr[5]);
//put data in W5100 transmit buffer
_dhcpUdpSocket.write(buffer, 30);
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 - (int)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);
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 :
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 dhcpT1value :
opt_len = _dhcpUdpSocket.read();
_dhcpUdpSocket.read((uint8_t*)&_dhcpT1, sizeof(_dhcpT1));
_dhcpT1 = ntohl(_dhcpT1);
break;
case dhcpT2value :
opt_len = _dhcpUdpSocket.read();
_dhcpUdpSocket.read((uint8_t*)&_dhcpT2, sizeof(_dhcpT2));
_dhcpT2 = ntohl(_dhcpT2);
break;
case dhcpIPaddrLeaseTime :
opt_len = _dhcpUdpSocket.read();
_dhcpUdpSocket.read((uint8_t*)&_dhcpLeaseTime, sizeof(_dhcpLeaseTime));
_dhcpLeaseTime = ntohl(_dhcpLeaseTime);
_renewInSec = _dhcpLeaseTime;
break;
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;
}
/*
returns:
0/DHCP_CHECK_NONE: nothing happened
1/DHCP_CHECK_RENEW_FAIL: renew failed
2/DHCP_CHECK_RENEW_OK: renew success
3/DHCP_CHECK_REBIND_FAIL: rebind fail
4/DHCP_CHECK_REBIND_OK: rebind success
*/
int DhcpClass::checkLease(){
//this uses a signed / unsigned trick to deal with millis overflow
unsigned long now = millis();
signed long snow = (long)now;
int rc=DHCP_CHECK_NONE;
if (_lastCheck != 0){
signed long factor;
//calc how many ms past the timeout we are
factor = snow - (long)_secTimeout;
//if on or passed the timeout, reduce the counters
if ( factor >= 0 ){
//next timeout should be now plus 1000 ms minus parts of second in factor
_secTimeout = snow + 1000 - factor % 1000;
//how many seconds late are we, minimum 1
factor = factor / 1000 +1;
//reduce the counters by that mouch
//if we can assume that the cycle time (factor) is fairly constant
//and if the remainder is less than cycle time * 2
//do it early instead of late
if(_renewInSec < factor*2 )
_renewInSec = 0;
else
_renewInSec -= factor;
if(_rebindInSec < factor*2 )
_rebindInSec = 0;
else
_rebindInSec -= factor;
}
//if we have a lease but should renew, do it
if (_dhcp_state == STATE_DHCP_LEASED && _renewInSec <=0){
_dhcp_state = STATE_DHCP_REREQUEST;
rc = 1 + request_DHCP_lease();
}
//if we have a lease or is renewing but should bind, do it
if( (_dhcp_state == STATE_DHCP_LEASED || _dhcp_state == STATE_DHCP_START) && _rebindInSec <=0){
//this should basically restart completely
_dhcp_state = STATE_DHCP_START;
reset_DHCP_lease();
rc = 3 + request_DHCP_lease();
}
}
else{
_secTimeout = snow + 1000;
}
_lastCheck = now;
return rc;
}
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);
}
void DhcpClass::printByte(char * buf, uint8_t n ) {
char *str = &buf[1];
buf[0]='0';
do {
unsigned long m = n;
n /= 16;
char c = m - 16 * n;
*str-- = c < 10 ? c + '0' : c + 'A' - 10;
} while(n);
}
-178
View File
@@ -1,178 +0,0 @@
// DHCP Library v0.3 - April 25, 2009
// Author: Jordan Terrell - blog.jordanterrell.com
#ifndef Dhcp_h
#define Dhcp_h
#include "UIPUdp.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 "ENC28J"
#define DEFAULT_LEASE (900) //default lease time in seconds
#define DHCP_CHECK_NONE (0)
#define DHCP_CHECK_RENEW_FAIL (1)
#define DHCP_CHECK_RENEW_OK (2)
#define DHCP_CHECK_REBIND_FAIL (3)
#define DHCP_CHECK_REBIND_OK (4)
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];
uint32_t _dhcpLeaseTime;
uint32_t _dhcpT1, _dhcpT2;
signed long _renewInSec;
signed long _rebindInSec;
signed long _lastCheck;
unsigned long _timeout;
unsigned long _responseTimeout;
unsigned long _secTimeout;
uint8_t _dhcp_state;
UIPUDP _dhcpUdpSocket;
int request_DHCP_lease();
void reset_DHCP_lease();
void presend_DHCP();
void send_DHCP_MESSAGE(uint8_t, uint16_t);
void printByte(char *, uint8_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);
int checkLease();
};
#endif
-422
View File
@@ -1,422 +0,0 @@
// Arduino DNS client for Enc28J60-based Ethernet shield
// (c) Copyright 2009-2010 MCQN Ltd.
// Released under Apache License, version 2.0
#include "Udp.h"
#include "utility/util.h"
#include "Dns.h"
#include <string.h>
//#include <stdlib.h>
#include "Arduino.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(uint16_t 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) != (uint16_t)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 (uint16_t 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 (uint16_t 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 (uint16_t 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;
}
-41
View File
@@ -1,41 +0,0 @@
// Arduino DNS client for Enc28J60-based Ethernet shield
// (c) Copyright 2009-2010 MCQN Ltd.
// Released under Apache License, version 2.0
#ifndef DNSClient_h
#define DNSClient_h
#include <UIPUdp.h>
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(uint16_t aTimeout, IPAddress& aAddress);
IPAddress iDNSServer;
uint16_t iRequestId;
UIPUDP iUdp;
};
#endif
-533
View File
@@ -1,533 +0,0 @@
/*
UIPClient.cpp - Arduino implementation of a uIP wrapper class.
Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
extern "C"
{
#import "utility/uip-conf.h"
#import "utility/uip.h"
#import "utility/uip_arp.h"
#import "string.h"
}
#include "UIPEthernet.h"
#include "UIPClient.h"
#include "Dns.h"
#ifdef UIPETHERNET_DEBUG_CLIENT
#include "HardwareSerial.h"
#endif
#define UIP_TCP_PHYH_LEN UIP_LLH_LEN+UIP_IPTCPH_LEN
uip_userdata_t UIPClient::all_data[UIP_CONNS];
UIPClient::UIPClient() :
data(NULL)
{
}
UIPClient::UIPClient(uip_userdata_t* conn_data) :
data(conn_data)
{
}
int
UIPClient::connect(IPAddress ip, uint16_t port)
{
uip_ipaddr_t ipaddr;
uip_ip_addr(ipaddr, ip);
struct uip_conn* conn = uip_connect(&ipaddr, htons(port));
if (conn)
{
while((conn->tcpstateflags & UIP_TS_MASK) != UIP_CLOSED)
{
UIPEthernet.tick();
if ((conn->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED)
{
data = (uip_userdata_t*) conn->appstate;
#ifdef UIPETHERNET_DEBUG_CLIENT
Serial.print(F("connected, state: "));
Serial.print(data->state);
Serial.print(F(", first packet in: "));
Serial.println(data->packets_in[0]);
#endif
return 1;
}
}
}
return 0;
}
int
UIPClient::connect(const char *host, uint16_t port)
{
// Look up the host first
int ret = 0;
#if UIP_UDP
DNSClient dns;
IPAddress remote_addr;
dns.begin(UIPEthernet.dnsServerIP());
ret = dns.getHostByName(host, remote_addr);
if (ret == 1) {
return connect(remote_addr, port);
}
#endif
return ret;
}
void
UIPClient::stop()
{
if (data)
{
_flushBlocks(&data->packets_in[0]);
if (data->state & UIP_CLIENT_CLOSED)
{
data->state = 0;
}
else
{
data->state |= UIP_CLIENT_CLOSE;
}
}
data = NULL;
UIPEthernet.tick();
}
uint8_t
UIPClient::connected()
{
return (data && (data->packets_in[0] != NOBLOCK || (data->state & UIP_CLIENT_CONNECTED))) ? 1 : 0;
}
bool
UIPClient::operator==(const UIPClient& rhs)
{
return data && rhs.data && (data == rhs.data);
}
UIPClient::operator bool()
{
UIPEthernet.tick();
return data && (!(data->state & UIP_CLIENT_CLOSED) || data->packets_in[0] != NOBLOCK);
}
size_t
UIPClient::write(uint8_t c)
{
return _write(data, &c, 1);
}
size_t
UIPClient::write(const uint8_t *buf, size_t size)
{
return _write(data, buf, size);
}
size_t
UIPClient::_write(uip_userdata_t* u, const uint8_t *buf, size_t size)
{
int remain = size;
uint16_t written;
#if UIP_ATTEMPTS_ON_WRITE > 0
uint16_t attempts = UIP_ATTEMPTS_ON_WRITE;
#endif
repeat:
UIPEthernet.tick();
if (u && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_CLOSED)))
{
memhandle* p = _currentBlock(&u->packets_out[0]);
if (*p == NOBLOCK)
{
newpacket:
*p = UIPEthernet.network.allocBlock(UIP_SOCKET_DATALEN);
if (*p == NOBLOCK)
{
#if UIP_ATTEMPTS_ON_WRITE > 0
if ((--attempts)>0)
#endif
#if UIP_ATTEMPTS_ON_WRITE != 0
goto repeat;
#endif
goto ready;
}
u->out_pos = 0;
}
#ifdef UIPETHERNET_DEBUG_CLIENT
Serial.print(F("UIPClient.write: writePacket("));
Serial.print(*p);
Serial.print(F(") pos: "));
Serial.print(u->out_pos);
Serial.print(F(", buf["));
Serial.print(size-remain);
Serial.print(F("-"));
Serial.print(remain);
Serial.print(F("]: '"));
Serial.write((uint8_t*)buf+size-remain,remain);
Serial.println(F("'"));
#endif
written = UIPEthernet.network.writePacket(*p,u->out_pos,(uint8_t*)buf+size-remain,remain);
remain -= written;
u->out_pos+=written;
if (remain > 0)
{
if (p==&u->packets_out[UIP_SOCKET_NUMPACKETS-1])
{
#if UIP_ATTEMPTS_ON_WRITE > 0
if ((--attempts)>0)
#endif
#if UIP_ATTEMPTS_ON_WRITE != 0
goto repeat;
#endif
goto ready;
}
p++;
goto newpacket;
}
ready:
return size-remain;
}
return -1;
}
int
UIPClient::available()
{
if (*this)
return _available(data);
return 0;
}
int
UIPClient::_available(uip_userdata_t *u)
{
memhandle* p = &u->packets_in[0];
if (*p == NOBLOCK)
return 0;
int len = 0;
for(memhandle* end = p+UIP_SOCKET_NUMPACKETS; p < end; p++)
{
if(*p == NOBLOCK)
break;
len += UIPEthernet.network.blockSize(*p);
}
return len;
}
int
UIPClient::read(uint8_t *buf, size_t size)
{
if (*this)
{
int remain = size;
memhandle* p = &data->packets_in[0];
if (*p == NOBLOCK)
return 0;
int read;
do
{
read = UIPEthernet.network.readPacket(*p,0,buf+size-remain,remain);
if (read == UIPEthernet.network.blockSize(*p))
{
remain -= read;
_eatBlock(p);
if (uip_stopped(&uip_conns[data->state & UIP_CLIENT_SOCKETS]) && !(data->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_CLOSED)))
data->state |= UIP_CLIENT_RESTART;
if (*p == NOBLOCK)
{
if (data->state & UIP_CLIENT_CLOSED)
{
data->state = 0;
data = NULL;
}
return size-remain;
}
}
else
{
UIPEthernet.network.resizeBlock(*p,read);
break;
}
}
while(remain > 0);
return size;
}
return -1;
}
int
UIPClient::read()
{
uint8_t c;
if (read(&c,1) < 0)
return -1;
return c;
}
int
UIPClient::peek()
{
if (*this)
{
memhandle p = data->packets_in[0];
if (p != NOBLOCK)
{
uint8_t c;
UIPEthernet.network.readPacket(p,0,&c,1);
return c;
}
}
return -1;
}
void
UIPClient::flush()
{
if (*this)
{
_flushBlocks(&data->packets_in[0]);
}
}
void
uipclient_appcall(void)
{
UIPClient::uip_callback();
}
void
UIPClient::uip_callback()
{
uip_userdata_t *u = (uip_userdata_t*)uip_conn->appstate;
if (!u && uip_connected())
{
#ifdef UIPETHERNET_DEBUG_CLIENT
Serial.println(F("UIPClient uip_connected"));
#endif
u = (uip_userdata_t*) _allocateData();
if (u)
{
uip_conn->appstate = u;
#ifdef UIPETHERNET_DEBUG_CLIENT
Serial.print(F("UIPClient allocated state: "));
Serial.println(u->state);
#endif
}
#ifdef UIPETHERNET_DEBUG_CLIENT
else
Serial.println(F("UIPClient allocation failed"));
#endif
}
if (u)
{
if (uip_newdata())
{
#ifdef UIPETHERNET_DEBUG_CLIENT
Serial.print(F("UIPClient uip_newdata, uip_len:"));
Serial.println(uip_len);
#endif
if (uip_len && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_CLOSED)))
{
memhandle newPacket = UIPEthernet.network.allocBlock(uip_len);
if (newPacket != NOBLOCK)
{
memhandle* p = _currentBlock(&u->packets_in[0]);
//if it's not the first packet
if (*p != NOBLOCK)
{
uint8_t slot = p - &u->packets_in[0];
if (slot < UIP_SOCKET_NUMPACKETS-1)
p++;
//if this is the last slot stop this connection
if (slot >= UIP_SOCKET_NUMPACKETS-2)
{
uip_stop();
//if there's no free slot left omit loosing this packet and (again) stop this connection
if (slot == UIP_SOCKET_NUMPACKETS-1)
goto reject_newdata;
}
}
UIPEthernet.network.copyPacket(newPacket,0,UIPEthernet.in_packet,((uint8_t*)uip_appdata)-uip_buf,uip_len);
*p = newPacket;
goto finish_newdata;
}
reject_newdata:
UIPEthernet.packetstate &= ~UIPETHERNET_FREEPACKET;
uip_stop();
}
}
finish_newdata:
if (u->state & UIP_CLIENT_RESTART)
{
u->state &= ~UIP_CLIENT_RESTART;
uip_restart();
}
// If the connection has been closed, save received but unread data.
if (uip_closed() || uip_timedout())
{
#ifdef UIPETHERNET_DEBUG_CLIENT
Serial.println(F("UIPClient uip_closed"));
#endif
// drop outgoing packets not sent yet:
_flushBlocks(&u->packets_out[0]);
if (u->packets_in[0] != NOBLOCK)
{
((uip_userdata_closed_t *)u)->lport = uip_conn->lport;
u->state |= UIP_CLIENT_CLOSED;
}
else
u->state = 0;
// disassociate appdata.
uip_conn->appstate = NULL;
goto nodata;
}
if (uip_acked())
{
#ifdef UIPETHERNET_DEBUG_CLIENT
Serial.println(F("UIPClient uip_acked"));
#endif
_eatBlock(&u->packets_out[0]);
}
if (uip_poll() || uip_rexmit())
{
#ifdef UIPETHERNET_DEBUG_CLIENT
//Serial.println(F("UIPClient uip_poll"));
#endif
memhandle p = u->packets_out[0];
if (p != NOBLOCK)
{
if (u->packets_out[1] == NOBLOCK)
{
uip_len = u->out_pos;
if (uip_len > 0)
{
UIPEthernet.network.resizeBlock(p,0,uip_len);
}
}
else
uip_len = UIPEthernet.network.blockSize(p);
if (uip_len > 0)
{
UIPEthernet.uip_hdrlen = ((uint8_t*)uip_appdata)-uip_buf;
UIPEthernet.uip_packet = UIPEthernet.network.allocBlock(UIPEthernet.uip_hdrlen+uip_len);
if (UIPEthernet.uip_packet != NOBLOCK)
{
UIPEthernet.network.copyPacket(UIPEthernet.uip_packet,UIPEthernet.uip_hdrlen,p,0,uip_len);
UIPEthernet.packetstate |= UIPETHERNET_SENDPACKET;
uip_send(uip_appdata,uip_len);
}
return;
}
}
}
// don't close connection unless all outgoing packets are sent
if (u->state & UIP_CLIENT_CLOSE)
{
#ifdef UIPETHERNET_DEBUG_CLIENT
Serial.print(F("UIPClient state UIP_CLIENT_CLOSE"));
#endif
if (u->packets_out[0] == NOBLOCK)
{
#ifdef UIPETHERNET_DEBUG_CLIENT
Serial.print(F("UIPClient state UIP_CLIENT_CLOSE -> free userdata"));
#endif
u->state = 0;
uip_conn->appstate = NULL;
uip_close();
}
else
uip_stop();
}
}
nodata:
UIPEthernet.uip_packet = NOBLOCK;
uip_len=0;
}
uip_userdata_t *
UIPClient::_allocateData()
{
for ( uint8_t sock = 0; sock < UIP_CONNS; sock++ )
{
uip_userdata_t* data = &UIPClient::all_data[sock];
if (!data->state)
{
data->state = sock | UIP_CLIENT_CONNECTED;
memset(&data->packets_in[0],0,sizeof(uip_userdata_t)-sizeof(data->state));
return data;
}
}
return NULL;
}
memhandle*
UIPClient::_currentBlock(memhandle* block)
{
for(memhandle* end = block+UIP_SOCKET_NUMPACKETS-1; block < end; block++)
if(*(block+1) == NOBLOCK)
break;
return block;
}
void
UIPClient::_eatBlock(memhandle* block)
{
#ifdef UIPETHERNET_DEBUG_CLIENT
memhandle* start = block;
Serial.print(F("eatblock("));
Serial.print(*block);
Serial.print("): ");
for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++)
{
Serial.print(start[i]);
Serial.print(" ");
}
Serial.print("-> ");
#endif
memhandle* end = block+(UIP_SOCKET_NUMPACKETS-1);
UIPEthernet.network.freeBlock(*block);
while(block < end)
*block = *((block++)+1);
*end = NOBLOCK;
#ifdef UIPETHERNET_DEBUG_CLIENT
for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++)
{
Serial.print(start[i]);
Serial.print(F(" "));
}
Serial.println();
#endif
}
void
UIPClient::_flushBlocks(memhandle* block)
{
for(memhandle* end = block+UIP_SOCKET_NUMPACKETS; block < end; block++)
{
if(*block != NOBLOCK)
{
UIPEthernet.network.freeBlock(*block);
*block = NOBLOCK;
}
else
break;
}
}
-104
View File
@@ -1,104 +0,0 @@
/*
UIPClient.h - Arduino implementation of a uIP wrapper class.
Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UIPCLIENT_H
#define UIPCLIENT_H
#include "ethernet_comp.h"
#import "Client.h"
#import "utility/mempool.h"
extern "C" {
#import "utility/uip.h"
}
#define UIP_SOCKET_DATALEN UIP_TCP_MSS
//#define UIP_SOCKET_NUMPACKETS UIP_RECEIVE_WINDOW/UIP_TCP_MSS+1
#ifndef UIP_SOCKET_NUMPACKETS
#define UIP_SOCKET_NUMPACKETS 5
#endif
#define UIP_CLIENT_CONNECTED 0x10
#define UIP_CLIENT_CLOSE 0x20
#define UIP_CLIENT_CLOSED 0x40
#define UIP_CLIENT_RESTART 0x80
#define UIP_CLIENT_STATEFLAGS (UIP_CLIENT_CONNECTED | UIP_CLIENT_CLOSE | UIP_CLIENT_CLOSED | UIP_CLIENT_RESTART)
#define UIP_CLIENT_SOCKETS ~UIP_CLIENT_STATEFLAGS
typedef uint8_t uip_socket_ptr;
typedef struct {
uint8_t state;
memhandle packets_in[UIP_SOCKET_NUMPACKETS];
uint16_t lport; /**< The local TCP port, in network byte order. */
} uip_userdata_closed_t;
typedef struct {
uint8_t state;
memhandle packets_in[UIP_SOCKET_NUMPACKETS];
memhandle packets_out[UIP_SOCKET_NUMPACKETS];
memaddress out_pos;
} uip_userdata_t;
class UIPClient : public Client {
public:
UIPClient();
int connect(IPAddress ip, uint16_t port);
int connect(const char *host, uint16_t port);
int read(uint8_t *buf, size_t size);
void stop();
uint8_t connected();
operator bool();
virtual bool operator==(const EthernetClient&);
virtual bool operator!=(const EthernetClient& rhs) { return !this->operator==(rhs); };
size_t write(uint8_t);
size_t write(const uint8_t *buf, size_t size);
int available();
int read();
int peek();
void flush();
private:
UIPClient(struct uip_conn *_conn);
UIPClient(uip_userdata_t* conn_data);
uip_userdata_t* data;
static uip_userdata_t all_data[UIP_CONNS];
static uip_userdata_t* _allocateData();
static uip_userdata_t* _getData(struct uip_conn * conn);
static size_t _write(uip_userdata_t *,const uint8_t *buf, size_t size);
static int _available(uip_userdata_t *);
static memhandle * _currentBlock(memhandle* blocks);
static void _eatBlock(memhandle* blocks);
static void _flushBlocks(memhandle* blocks);
friend class UIPEthernetClass;
friend class UIPServer;
friend void uipclient_appcall(void);
static void uip_callback();
};
#endif
-433
View File
@@ -1,433 +0,0 @@
/*
UIPEthernet.cpp - Arduino implementation of a uIP wrapper class.
Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Arduino.h>
#include "UIPEthernet.h"
#include "utility/Enc28J60Network.h"
#if(defined UIPETHERNET_DEBUG || defined UIPETHERNET_DEBUG_CHKSUM)
#include "HardwareSerial.h"
#endif
extern "C"
{
#include "utility/uip-conf.h"
#include "utility/uip.h"
#include "utility/uip_arp.h"
#include "utility/uip_timer.h"
}
#define ETH_HDR ((struct uip_eth_hdr *)&uip_buf[0])
// Because uIP isn't encapsulated within a class we have to use global
// variables, so we can only have one TCP/IP stack per program.
UIPEthernetClass::UIPEthernetClass() :
in_packet(NOBLOCK),
uip_packet(NOBLOCK),
uip_hdrlen(0),
packetstate(0),
_dhcp(NULL)
{
}
int
UIPEthernetClass::begin(const uint8_t* mac)
{
static DhcpClass s_dhcp;
_dhcp = &s_dhcp;
// Initialise the basic info
init(mac);
// Now try to get our config info from a DHCP server
int ret = _dhcp->beginWithDHCP((uint8_t*)mac);
if(ret == 1)
{
// We've successfully found a DHCP server and got our configuration info, so set things
// accordingly
configure(_dhcp->getLocalIp(),_dhcp->getDnsServerIp(),_dhcp->getGatewayIp(),_dhcp->getSubnetMask());
}
return ret;
}
void
UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip)
{
IPAddress dns = ip;
dns[3] = 1;
begin(mac, ip, dns);
}
void
UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns)
{
IPAddress gateway = ip;
gateway[3] = 1;
begin(mac, ip, dns, gateway);
}
void
UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway)
{
IPAddress subnet(255, 255, 255, 0);
begin(mac, ip, dns, gateway, subnet);
}
void
UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet)
{
init(mac);
configure(ip,dns,gateway,subnet);
}
int UIPEthernetClass::maintain(){
tick();
int rc = DHCP_CHECK_NONE;
if(_dhcp != NULL){
//we have a pointer to dhcp, use it
rc = _dhcp->checkLease();
switch ( rc ){
case DHCP_CHECK_NONE:
//nothing done
break;
case DHCP_CHECK_RENEW_OK:
case DHCP_CHECK_REBIND_OK:
//we might have got a new IP.
configure(_dhcp->getLocalIp(),_dhcp->getDnsServerIp(),_dhcp->getGatewayIp(),_dhcp->getSubnetMask());
break;
default:
//this is actually a error, it will retry though
break;
}
}
return rc;
}
IPAddress UIPEthernetClass::localIP()
{
IPAddress ret;
uip_ipaddr_t a;
uip_gethostaddr(a);
return ip_addr_uip(a);
}
IPAddress UIPEthernetClass::subnetMask()
{
IPAddress ret;
uip_ipaddr_t a;
uip_getnetmask(a);
return ip_addr_uip(a);
}
IPAddress UIPEthernetClass::gatewayIP()
{
IPAddress ret;
uip_ipaddr_t a;
uip_getdraddr(a);
return ip_addr_uip(a);
}
IPAddress UIPEthernetClass::dnsServerIP()
{
return _dnsServerAddress;
}
void
UIPEthernetClass::tick()
{
if (in_packet == NOBLOCK)
{
in_packet = network.receivePacket();
#ifdef UIPETHERNET_DEBUG
if (in_packet != NOBLOCK)
{
Serial.print(F("--------------\nreceivePacket: "));
Serial.println(in_packet);
}
#endif
}
if (in_packet != NOBLOCK)
{
packetstate = UIPETHERNET_FREEPACKET;
uip_len = network.blockSize(in_packet);
if (uip_len > 0)
{
network.readPacket(in_packet,0,(uint8_t*)uip_buf,UIP_BUFSIZE);
if (ETH_HDR ->type == HTONS(UIP_ETHTYPE_IP))
{
uip_packet = in_packet;
#ifdef UIPETHERNET_DEBUG
Serial.print(F("readPacket type IP, uip_len: "));
Serial.println(uip_len);
#endif
uip_arp_ipin();
uip_input();
if (uip_len > 0)
{
uip_arp_out();
network_send();
}
}
else if (ETH_HDR ->type == HTONS(UIP_ETHTYPE_ARP))
{
#ifdef UIPETHERNET_DEBUG
Serial.print(F("readPacket type ARP, uip_len: "));
Serial.println(uip_len);
#endif
uip_arp_arpin();
if (uip_len > 0)
{
network_send();
}
}
}
if (in_packet != NOBLOCK && (packetstate & UIPETHERNET_FREEPACKET))
{
#ifdef UIPETHERNET_DEBUG
Serial.print(F("freeing packet: "));
Serial.println(in_packet);
#endif
network.freePacket();
in_packet = NOBLOCK;
}
}
if (uip_timer_expired(&periodic_timer))
{
uip_timer_restart(&periodic_timer);
for (int i = 0; i < UIP_CONNS; i++)
{
uip_periodic(i);
// If the above function invocation resulted in data that
// should be sent out on the network, the global variable
// uip_len is set to a value > 0.
if (uip_len > 0)
{
uip_arp_out();
network_send();
}
}
#if UIP_UDP
for (int i = 0; i < UIP_UDP_CONNS; i++)
{
uip_udp_periodic(i);
// If the above function invocation resulted in data that
// should be sent out on the network, the global variable
// uip_len is set to a value > 0. */
if (uip_len > 0)
{
network_send();
}
}
#endif /* UIP_UDP */
}
}
boolean UIPEthernetClass::network_send()
{
if (packetstate & UIPETHERNET_SENDPACKET)
{
#ifdef UIPETHERNET_DEBUG
Serial.print(F("network_send uip_packet: "));
Serial.print(uip_packet);
Serial.print(F(", hdrlen: "));
Serial.println(uip_hdrlen);
#endif
network.writePacket(uip_packet,0,uip_buf,uip_hdrlen);
goto sendandfree;
}
uip_packet = network.allocBlock(uip_len);
if (uip_packet != NOBLOCK)
{
#ifdef UIPETHERNET_DEBUG
Serial.print(F("network_send uip_buf (uip_len): "));
Serial.print(uip_len);
Serial.print(F(", packet: "));
Serial.println(uip_packet);
#endif
network.writePacket(uip_packet,0,uip_buf,uip_len);
goto sendandfree;
}
return false;
sendandfree:
network.sendPacket(uip_packet);
network.freeBlock(uip_packet);
uip_packet = NOBLOCK;
return true;
}
void UIPEthernetClass::init(const uint8_t* mac) {
uip_timer_set(&this->periodic_timer, CLOCK_SECOND / 4);
network.init((uint8_t*)mac);
uip_seteth_addr(mac);
uip_init();
}
void UIPEthernetClass::configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) {
uip_ipaddr_t ipaddr;
uip_ip_addr(ipaddr, ip);
uip_sethostaddr(ipaddr);
uip_ip_addr(ipaddr, gateway);
uip_setdraddr(ipaddr);
uip_ip_addr(ipaddr, subnet);
uip_setnetmask(ipaddr);
_dnsServerAddress = dns;
}
UIPEthernetClass UIPEthernet;
/*---------------------------------------------------------------------------*/
uint16_t
UIPEthernetClass::chksum(uint16_t sum, const uint8_t *data, uint16_t len)
{
uint16_t t;
const uint8_t *dataptr;
const uint8_t *last_byte;
dataptr = data;
last_byte = data + len - 1;
while(dataptr < last_byte) { /* At least two more bytes */
t = (dataptr[0] << 8) + dataptr[1];
sum += t;
if(sum < t) {
sum++; /* carry */
}
dataptr += 2;
}
if(dataptr == last_byte) {
t = (dataptr[0] << 8) + 0;
sum += t;
if(sum < t) {
sum++; /* carry */
}
}
/* Return sum in host byte order. */
return sum;
}
/*---------------------------------------------------------------------------*/
uint16_t
UIPEthernetClass::ipchksum(void)
{
uint16_t sum;
sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN);
return (sum == 0) ? 0xffff : htons(sum);
}
/*---------------------------------------------------------------------------*/
uint16_t
UIPEthernetClass::upper_layer_chksum(uint8_t proto)
{
uint16_t upper_layer_len;
uint16_t sum;
#if UIP_CONF_IPV6
upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]);
#else /* UIP_CONF_IPV6 */
upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]) - UIP_IPH_LEN;
#endif /* UIP_CONF_IPV6 */
/* First sum pseudoheader. */
/* IP protocol and length fields. This addition cannot carry. */
sum = upper_layer_len + proto;
/* Sum IP source and destination addresses. */
sum = chksum(sum, (u8_t *)&BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t));
uint8_t upper_layer_memlen;
switch(proto)
{
case UIP_PROTO_ICMP:
case UIP_PROTO_ICMP6:
upper_layer_memlen = upper_layer_len;
break;
case UIP_PROTO_TCP:
upper_layer_memlen = (BUF->tcpoffset >> 4) << 2;
break;
#if UIP_UDP
case UIP_PROTO_UDP:
upper_layer_memlen = UIP_UDPH_LEN;
break;
#endif
}
sum = chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_memlen);
#ifdef UIPETHERNET_DEBUG_CHKSUM
Serial.print(F("chksum uip_buf["));
Serial.print(UIP_IPH_LEN + UIP_LLH_LEN);
Serial.print(F("-"));
Serial.print(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen);
Serial.print(F("]: "));
Serial.println(htons(sum),HEX);
#endif
if (upper_layer_memlen < upper_layer_len)
{
sum = network.chksum(
sum,
uip_packet,
UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen,
upper_layer_len - upper_layer_memlen
);
#ifdef UIPETHERNET_DEBUG_CHKSUM
Serial.print(F("chksum uip_packet("));
Serial.print(uip_packet);
Serial.print(F(")["));
Serial.print(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen);
Serial.print(F("-"));
Serial.print(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_len);
Serial.print(F"]: "));
Serial.println(htons(sum),HEX);
#endif
}
return (sum == 0) ? 0xffff : htons(sum);
}
uint16_t
uip_ipchksum(void)
{
return UIPEthernet.ipchksum();
}
uint16_t
uip_tcpchksum(void)
{
uint16_t sum = UIPEthernet.upper_layer_chksum(UIP_PROTO_TCP);
return sum;
}
#if UIP_UDP
uint16_t
uip_udpchksum(void)
{
uint16_t sum = UIPEthernet.upper_layer_chksum(UIP_PROTO_UDP);
return sum;
}
#endif
-125
View File
@@ -1,125 +0,0 @@
/*
UIPEthernet.h - Arduino implementation of a uIP wrapper class.
Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UIPETHERNET_H
#define UIPETHERNET_H
#include "ethernet_comp.h"
#include <Arduino.h>
#include "Dhcp.h"
#include "IPAddress.h"
#include "utility/Enc28J60Network.h"
#include "UIPClient.h"
#include "UIPServer.h"
#include "UIPUdp.h"
extern "C"
{
#include "utility/uip_timer.h"
#include "utility/uip.h"
}
//#define UIPETHERNET_DEBUG
//#define UIPETHERNET_DEBUG_CHKSUM
//#define UIPETHERNET_DEBUG_UDP
//#define UIPETHERNET_DEBUG_CLIENT
#define UIPETHERNET_FREEPACKET 1
#define UIPETHERNET_SENDPACKET 2
#define UIPETHERNET_BUFFERREAD 4
#define uip_ip_addr(addr, ip) do { \
((u16_t *)(addr))[0] = HTONS(((ip[0]) << 8) | (ip[1])); \
((u16_t *)(addr))[1] = HTONS(((ip[2]) << 8) | (ip[3])); \
} while(0)
#define ip_addr_uip(a) IPAddress(a[0] & 0xFF, a[0] >> 8 , a[1] & 0xFF, a[1] >> 8) //TODO this is not IPV6 capable
#define uip_seteth_addr(eaddr) do {uip_ethaddr.addr[0] = eaddr[0]; \
uip_ethaddr.addr[1] = eaddr[1];\
uip_ethaddr.addr[2] = eaddr[2];\
uip_ethaddr.addr[3] = eaddr[3];\
uip_ethaddr.addr[4] = eaddr[4];\
uip_ethaddr.addr[5] = eaddr[5];} while(0)
#define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
class UIPEthernetClass
{
public:
UIPEthernetClass();
int begin(const uint8_t* mac);
void begin(const uint8_t* mac, IPAddress ip);
void begin(const uint8_t* mac, IPAddress ip, IPAddress dns);
void begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway);
void begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet);
// maintain() must be called at regular intervals to process the incoming serial
// data and issue IP events to the sketch. It does not return until all IP
// events have been processed. Renews dhcp-lease if required.
int maintain();
IPAddress localIP();
IPAddress subnetMask();
IPAddress gatewayIP();
IPAddress dnsServerIP();
private:
IPAddress _dnsServerAddress;
DhcpClass* _dhcp;
struct uip_timer periodic_timer;
memhandle in_packet;
memhandle uip_packet;
uint8_t uip_hdrlen;
uint8_t packetstate;
Enc28J60Network network;
void init(const uint8_t* mac);
void configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet);
void tick();
boolean network_send();
friend class UIPServer;
friend class UIPClient;
friend class UIPUDP;
static uint16_t chksum(uint16_t sum, const uint8_t* data, uint16_t len);
static uint16_t ipchksum(void);
uint16_t upper_layer_chksum(uint8_t proto);
friend uint16_t uip_ipchksum(void);
friend uint16_t uip_tcpchksum(void);
friend uint16_t uip_udpchksum(void);
#if UIP_CONF_IPV6
uint16_t uip_icmp6chksum(void);
#endif /* UIP_CONF_IPV6 */
};
extern UIPEthernetClass UIPEthernet;
#endif
-63
View File
@@ -1,63 +0,0 @@
/*
UIPServer.cpp - Arduino implementation of a uIP wrapper class.
Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "UIPEthernet.h"
#include "UIPServer.h"
extern "C" {
#include "utility/uip-conf.h"
}
UIPServer::UIPServer(uint16_t port) : _port(htons(port))
{
}
UIPClient UIPServer::available()
{
UIPEthernet.tick();
for ( uip_userdata_t* data = &UIPClient::all_data[0]; data < &UIPClient::all_data[UIP_CONNS]; data++ )
{
if (data->packets_in[0] != NOBLOCK
&& (((data->state & UIP_CLIENT_CONNECTED) && uip_conns[data->state & UIP_CLIENT_SOCKETS].lport ==_port)
|| ((data->state & UIP_CLIENT_CLOSED) && ((uip_userdata_closed_t *)data)->lport == _port)))
return UIPClient(data);
}
return UIPClient();
}
void UIPServer::begin()
{
uip_listen(_port);
UIPEthernet.tick();
}
size_t UIPServer::write(uint8_t c)
{
return write(&c,1);
}
size_t UIPServer::write(const uint8_t *buf, size_t size)
{
size_t ret = 0;
for ( uip_userdata_t* data = &UIPClient::all_data[0]; data < &UIPClient::all_data[UIP_CONNS]; data++ )
{
if ((data->state & UIP_CLIENT_CONNECTED) && uip_conns[data->state & UIP_CLIENT_SOCKETS].lport ==_port)
ret += UIPClient::_write(data,buf,size);
}
return ret;
}
-40
View File
@@ -1,40 +0,0 @@
/*
UIPServer.h - Arduino implementation of a uIP wrapper class.
Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UIPSERVER_H
#define UIPSERVER_H
#include "ethernet_comp.h"
#import "Server.h"
#import "UIPClient.h"
class UIPServer : Server {
public:
UIPServer(uint16_t);
UIPClient available();
void begin();
size_t write(uint8_t);
size_t write(const uint8_t *buf, size_t size);
using Print::write;
private:
uint16_t _port;
};
#endif
-424
View File
@@ -1,424 +0,0 @@
/*
UIPUdp.cpp - Arduino implementation of a uIP wrapper class.
Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "UIPEthernet.h"
#include "UIPUdp.h"
#include "Dns.h"
#ifdef UIPETHERNET_DEBUG_UDP
#include "HardwareSerial.h"
#endif
extern "C" {
#include "utility/uip-conf.h"
#include "utility/uip.h"
#include "utility/uip_arp.h"
}
#if UIP_UDP
#define UIP_ARPHDRSIZE 42
#define UDPBUF ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])
// Constructor
UIPUDP::UIPUDP() :
_uip_udp_conn(NULL)
{
memset(&appdata,0,sizeof(appdata));
}
// initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
uint8_t
UIPUDP::begin(uint16_t port)
{
if (!_uip_udp_conn)
{
_uip_udp_conn = uip_udp_new(NULL, 0);
}
if (_uip_udp_conn)
{
uip_udp_bind(_uip_udp_conn,htons(port));
_uip_udp_conn->appstate = &appdata;
return 1;
}
return 0;
}
// Finish with the UDP socket
void
UIPUDP::stop()
{
if (_uip_udp_conn)
{
flush();
uip_udp_remove(_uip_udp_conn);
_uip_udp_conn->appstate = NULL;
_uip_udp_conn=NULL;
if (appdata.packet_in != NOBLOCK)
{
UIPEthernet.network.freeBlock(appdata.packet_in);
appdata.packet_in = NOBLOCK;
}
uint8_t i = 0;
memhandle* packet = &appdata.packets_in[0];
while (*packet != NOBLOCK && i < UIP_UDP_NUMPACKETS)
{
UIPEthernet.network.freeBlock(*packet);
*packet++ = NOBLOCK;
i++;
}
if (appdata.packet_out != NOBLOCK)
{
UIPEthernet.network.freeBlock(appdata.packet_out);
appdata.packet_out = NOBLOCK;
}
}
}
// 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
UIPUDP::beginPacket(IPAddress ip, uint16_t port)
{
UIPEthernet.tick();
if (ip && port)
{
uip_ipaddr_t ripaddr;
uip_ip_addr(&ripaddr, ip);
#ifdef UIPETHERNET_DEBUG_UDP
Serial.print(F("udp beginPacket, "));
#endif
if (_uip_udp_conn)
{
_uip_udp_conn->rport = htons(port);
uip_ipaddr_copy(_uip_udp_conn->ripaddr, &ripaddr);
}
else
{
_uip_udp_conn = uip_udp_new(&ripaddr,htons(port));
if (_uip_udp_conn)
{
#ifdef UIPETHERNET_DEBUG_UDP
Serial.print(F("new connection, "));
#endif
_uip_udp_conn->appstate = &appdata;
}
else
{
#ifdef UIPETHERNET_DEBUG_UDP
Serial.println(F("failed to allocate new connection"));
#endif
return 0;
}
}
#ifdef UIPETHERNET_DEBUG_UDP
Serial.print(F("rip: "));
Serial.print(ip);
Serial.print(F(", port: "));
Serial.println(port);
#endif
}
if (_uip_udp_conn)
{
if (appdata.packet_out == NOBLOCK)
{
appdata.packet_out = UIPEthernet.network.allocBlock(UIP_UDP_MAXPACKETSIZE);
appdata.out_pos = UIP_UDP_PHYH_LEN;
if (appdata.packet_out != NOBLOCK)
return 1;
#ifdef UIPETHERNET_DEBUG_UDP
else
Serial.println(F("failed to allocate memory for packet"));
#endif
}
#ifdef UIPETHERNET_DEBUG_UDP
else
Serial.println(F("previous packet on that connection not sent yet"));
#endif
}
return 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
int
UIPUDP::beginPacket(const char *host, uint16_t port)
{
// Look up the host first
int ret = 0;
DNSClient dns;
IPAddress remote_addr;
dns.begin(UIPEthernet.dnsServerIP());
ret = dns.getHostByName(host, remote_addr);
if (ret == 1) {
return beginPacket(remote_addr, port);
} else {
return ret;
}
}
// Finish off this packet and send it
// Returns 1 if the packet was sent successfully, 0 if there was an error
int
UIPUDP::endPacket()
{
if (_uip_udp_conn && appdata.packet_out != NOBLOCK)
{
appdata.send = true;
UIPEthernet.network.resizeBlock(appdata.packet_out,0,appdata.out_pos);
uip_udp_periodic_conn(_uip_udp_conn);
if (uip_len > 0)
{
UIPEthernet.network_send();
return 1;
}
}
return 0;
}
// Write a single byte into the packet
size_t
UIPUDP::write(uint8_t c)
{
return write(&c,1);
}
// Write size bytes from buffer into the packet
size_t
UIPUDP::write(const uint8_t *buffer, size_t size)
{
if (appdata.packet_out != NOBLOCK)
{
size_t ret = UIPEthernet.network.writePacket(appdata.packet_out,appdata.out_pos,(uint8_t*)buffer,size);
appdata.out_pos += ret;
return ret;
}
return 0;
}
// Start processing the next available incoming packet
// Returns the size of the packet in bytes, or 0 if no packets are available
int
UIPUDP::parsePacket()
{
UIPEthernet.tick();
if (appdata.packet_in != NOBLOCK)
{
#ifdef UIPETHERNET_DEBUG_UDP
Serial.print(F("udp parsePacket freeing previous packet: "));
Serial.println(appdata.packet_in);
#endif;
UIPEthernet.network.freeBlock(appdata.packet_in);
}
memhandle *packet = &appdata.packets_in[0];
appdata.packet_in = *packet;
if (appdata.packet_in != NOBLOCK)
{
#ifdef UIPETHERNET_DEBUG_UDP
Serial.print(F("udp parsePacket received packet: "));
Serial.print(appdata.packet_in);
#endif
if (UIP_UDP_NUMPACKETS > 1)
{
uint8_t i = 1;
memhandle* p = packet+1;
freeloop:
*packet = *p;
if (*packet == NOBLOCK)
goto freeready;
packet++;
if (i < UIP_UDP_NUMPACKETS-1)
{
i++;
p++;
goto freeloop;
}
}
*packet = NOBLOCK;
freeready:
int size = UIPEthernet.network.blockSize(appdata.packet_in);
#ifdef UIPETHERNET_DEBUG_UDP
Serial.print(F(", size: "));
Serial.println(size);
#endif
return size;
}
return 0;
}
// Number of bytes remaining in the current packet
int
UIPUDP::available()
{
UIPEthernet.tick();
if (appdata.packet_in != NOBLOCK)
{
return UIPEthernet.network.blockSize(appdata.packet_in);
}
return 0;
}
// Read a single byte from the current packet
int
UIPUDP::read()
{
unsigned char c;
if (read(&c,1) > 0)
{
return c;
}
return -1;
}
// 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
int
UIPUDP::read(unsigned char* buffer, size_t len)
{
UIPEthernet.tick();
if (appdata.packet_in != NOBLOCK)
{
int read = UIPEthernet.network.readPacket(appdata.packet_in,0,buffer,len);
UIPEthernet.network.resizeBlock(appdata.packet_in,read);
return read;
}
return 0;
}
// Return the next byte from the current packet without moving on to the next byte
int
UIPUDP::peek()
{
UIPEthernet.tick();
if (appdata.packet_in != NOBLOCK)
{
unsigned char c;
if (UIPEthernet.network.readPacket(appdata.packet_in,0,&c,1) == 1)
return c;
}
return -1;
}
// Finish reading the current packet
void
UIPUDP::flush()
{
UIPEthernet.tick();
if (appdata.packet_in != NOBLOCK)
{
UIPEthernet.network.freeBlock(appdata.packet_in);
appdata.packet_in = NOBLOCK;
}
}
// Return the IP address of the host who sent the current incoming packet
IPAddress
UIPUDP::remoteIP()
{
return _uip_udp_conn ? ip_addr_uip(_uip_udp_conn->ripaddr) : IPAddress();
}
// Return the port of the host who sent the current incoming packet
uint16_t
UIPUDP::remotePort()
{
return _uip_udp_conn ? ntohs(_uip_udp_conn->rport) : 0;
}
// uIP callback function
void
uipudp_appcall(void) {
UIPUDP::uip_callback();
}
void
UIPUDP::uip_callback() {
if (appdata_t *data = (appdata_t *)(uip_udp_conn->appstate))
{
if (uip_newdata())
{
uip_udp_conn->rport = UDPBUF->srcport;
uip_ipaddr_copy(uip_udp_conn->ripaddr,UDPBUF->srcipaddr);
memhandle *packet = &data->packets_in[0];
uint8_t i = 0;
do
{
if (*packet == NOBLOCK)
{
*packet = UIPEthernet.network.allocBlock(ntohs(UDPBUF->udplen)-UIP_UDPH_LEN);
//if we are unable to allocate memory the packet is dropped. udp doesn't guarantee packet delivery
if (*packet != NOBLOCK)
{
//discard Linklevel and IP and udp-header and any trailing bytes:
UIPEthernet.network.copyPacket(*packet,0,UIPEthernet.in_packet,UIP_UDP_PHYH_LEN,UIPEthernet.network.blockSize(*packet));
#ifdef UIPETHERNET_DEBUG_UDP
Serial.print(F("udp, uip_newdata received packet: "));
Serial.print(*packet);
Serial.print(F(", slot: "));
Serial.print(i);
Serial.print(F(", size: "));
Serial.println(UIPEthernet.network.blockSize(*packet));
#endif
break;
}
}
packet++;
i++;
}
while (i < UIP_UDP_NUMPACKETS);
}
if (uip_poll() && data->send)
{
//set uip_slen (uip private) by calling uip_udp_send
#ifdef UIPETHERNET_DEBUG_UDP
Serial.print(F("udp, uip_poll preparing packet to send: "));
Serial.print(data->packet_out);
Serial.print(F(", size: "));
Serial.println(UIPEthernet.network.blockSize(data->packet_out));
#endif
UIPEthernet.uip_packet = data->packet_out;
data->packet_out = NOBLOCK;
UIPEthernet.uip_hdrlen = UIP_UDP_PHYH_LEN;
UIPEthernet.packetstate |= UIPETHERNET_SENDPACKET;
uip_udp_send(data->out_pos - (UIP_UDP_PHYH_LEN));
uip_process(UIP_UDP_SEND_CONN); //generate udp + ip headers
uip_arp_out(); //add arp
if (uip_len == UIP_ARPHDRSIZE)
{
UIPEthernet.packetstate &= ~UIPETHERNET_SENDPACKET;
#ifdef UIPETHERNET_DEBUG_UDP
Serial.println(F("udp, uip_poll results in ARP-packet"));
#endif
}
else
//arp found ethaddr for ip (otherwise packet is replaced by arp-request)
{
data->send = false;
#ifdef UIPETHERNET_DEBUG_UDP
Serial.print(F("udp, uip_packet to send: "));
Serial.println(UIPEthernet.uip_packet);
#endif
}
}
}
}
#endif
-126
View File
@@ -1,126 +0,0 @@
/*
UIPUdp.h - Arduino implementation of a uIP wrapper class.
Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UIPUDP_H
#define UIPUDP_H
#include "ethernet_comp.h"
#include "Arduino.h"
#include <Udp.h>
#include "utility/mempool.h"
extern "C" {
#include "utility/uip.h";
}
#define UIP_UDP_MAXDATALEN 1500
#define UIP_UDP_PHYH_LEN UIP_LLH_LEN+UIP_IPUDPH_LEN
#define UIP_UDP_MAXPACKETSIZE UIP_UDP_MAXDATALEN+UIP_UDP_PHYH_LEN
#ifndef UIP_UDP_NUMPACKETS
#define UIP_UDP_NUMPACKETS 5
#endif
class UIPUDP : public UDP
{
private:
struct uip_udp_conn *_uip_udp_conn;
struct appdata_t
{
memaddress out_pos;
memhandle packets_in[UIP_UDP_NUMPACKETS];
memhandle packet_in;
memhandle packet_out;
boolean send;
} appdata;
public:
UIPUDP(); // 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
// 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);
// 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();
// Write a single byte into the packet
size_t
write(uint8_t);
// Write size bytes from buffer into the packet
size_t
write(const uint8_t *buffer, size_t size);
using Print::write;
// 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
int
available();
// Read a single byte from the current packet
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
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
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
int
peek();
void
flush(); // Finish reading the current packet
// Return the IP address of the host who sent the current incoming packet
IPAddress
remoteIP();
// Return the port of the host who sent the current incoming packet
uint16_t
remotePort();
private:
friend void uipudp_appcall(void);
static void uip_callback();
};
#endif
@@ -1,9 +0,0 @@
#ifndef ETHERNET_COMP_H
#define ETHERNET_COMP_H
#define Ethernet UIPEthernet
#define EthernetClient UIPClient
#define EthernetServer UIPServer
#define EthernetUDP UIPUDP
#endif
@@ -1,93 +0,0 @@
/*
Enc28J60Network.h
UIPEthernet network driver for Microchip ENC28J60 Ethernet Interface.
Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
All rights reserved.
inspired by enc28j60.c file from the AVRlib library by Pascal Stang.
For AVRlib See http://www.procyonengineering.com/
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ENC28J60NETWORK_H_
#define ENC28J60NETWORK_H_
#include "mempool.h"
#define ENC28J60_CONTROL_CS SS // this is pin 10 on Uno and pin 53 on Mega256
#if defined(ARDUINO_ARCH_AVR)
// AVR-specific code
#define SPI_MOSI MOSI
#define SPI_MISO MISO
#define SPI_SCK SCK
#define SPI_SS SS
#define ENC28J60_USE_SPILIB 0
#elif defined(ARDUINO_ARCH_SAM)
#define ENC28J60_USE_SPILIB 1
#endif
#define UIP_RECEIVEBUFFERHANDLE 0xff
//#define ENC28J60DEBUG
/*
* Empfangen von ip-header, arp etc...
* wenn tcp/udp -> tcp/udp-callback -> assign new packet to connection
*/
class Enc28J60Network : public MemoryPool
{
private:
uint16_t nextPacketPtr;
uint8_t bank;
struct memblock receivePkt;
uint8_t readOp(uint8_t op, uint8_t address);
void writeOp(uint8_t op, uint8_t address, uint8_t data);
uint16_t setReadPtr(memhandle handle, memaddress position, uint16_t len);
void setERXRDPT();
void readBuffer(uint16_t len, uint8_t* data);
void writeBuffer(uint16_t len, uint8_t* data);
uint8_t readByte(uint16_t addr);
void writeByte(uint16_t addr, uint8_t data);
void setBank(uint8_t address);
uint8_t readReg(uint8_t address);
void writeReg(uint8_t address, uint8_t data);
void writeRegPair(uint8_t address, uint16_t data);
void phyWrite(uint8_t address, uint16_t data);
void clkout(uint8_t clk);
uint8_t getrev(void);
protected:
void memblock_mv_cb(memaddress dest, memaddress src, memaddress size);
public:
Enc28J60Network();
void init(uint8_t* macaddr);
memhandle receivePacket();
void freePacket();
memaddress blockSize(memhandle handle);
void sendPacket(memhandle handle);
uint16_t readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len);
uint16_t writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len);
void copyPacket(memhandle dest, memaddress dest_pos, memhandle src, memaddress src_pos, uint16_t len);
uint16_t chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t len);
};
#endif /* ENC28J60NETWORK_H_ */
@@ -1,28 +0,0 @@
#ifndef MEMPOOLCONF_H
#define MEMPOOLCONF_H
#include "uipethernet-conf.h"
extern "C" {
#include "uipopt.h"
}
#include <inttypes.h>
typedef uint16_t memaddress;
typedef uint8_t memhandle;
#if UIP_SOCKET_NUMPACKETS and UIP_CONNS
#define NUM_TCP_MEMBLOCKS (UIP_SOCKET_NUMPACKETS*2)*UIP_CONNS
#else
#define NUM_TCP_MEMBLOCKS 0
#endif
#if UIP_UDP and UIP_UDP_NUMPACKETS and UIP_UDP_CONNS
#define NUM_UDP_MEMBLOCKS (UIP_UDP_NUMPACKETS+1)*UIP_UDP_CONNS
#else
#define NUM_UDP_MEMBLOCKS 0
#endif
#define NUM_MEMBLOCKS (NUM_TCP_MEMBLOCKS+NUM_UDP_MEMBLOCKS)
#define MEMBLOCK_MV
#endif
@@ -1,158 +0,0 @@
/*
* Copyright (c) 2006, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the uIP TCP/IP stack
*
* $Id: uip-neighbor.c,v 1.2 2006/06/12 08:00:30 adam Exp $
*/
/**
* \file
* Database of link-local neighbors, used by IPv6 code and
* to be used by a future ARP code rewrite.
* \author
* Adam Dunkels <adam@sics.se>
*/
#include "uip-neighbor.h"
#include <string.h>
#define MAX_TIME 128
#ifdef UIP_NEIGHBOR_CONF_ENTRIES
#define ENTRIES UIP_NEIGHBOR_CONF_ENTRIES
#else /* UIP_NEIGHBOR_CONF_ENTRIES */
#define ENTRIES 8
#endif /* UIP_NEIGHBOR_CONF_ENTRIES */
struct neighbor_entry {
uip_ipaddr_t ipaddr;
struct uip_neighbor_addr addr;
u8_t time;
};
static struct neighbor_entry entries[ENTRIES];
/*---------------------------------------------------------------------------*/
void
uip_neighbor_init(void)
{
int i;
for(i = 0; i < ENTRIES; ++i) {
entries[i].time = MAX_TIME;
}
}
/*---------------------------------------------------------------------------*/
void
uip_neighbor_periodic(void)
{
int i;
for(i = 0; i < ENTRIES; ++i) {
if(entries[i].time < MAX_TIME) {
entries[i].time++;
}
}
}
/*---------------------------------------------------------------------------*/
void
uip_neighbor_add(uip_ipaddr_t ipaddr, struct uip_neighbor_addr *addr)
{
int i, oldest;
u8_t oldest_time;
printf("Adding neighbor with link address %02x:%02x:%02x:%02x:%02x:%02x\n",
addr->addr.addr[0], addr->addr.addr[1], addr->addr.addr[2], addr->addr.addr[3],
addr->addr.addr[4], addr->addr.addr[5]);
/* Find the first unused entry or the oldest used entry. */
oldest_time = 0;
oldest = 0;
for(i = 0; i < ENTRIES; ++i) {
if(entries[i].time == MAX_TIME) {
oldest = i;
break;
}
if(uip_ipaddr_cmp(entries[i].ipaddr, addr)) {
oldest = i;
break;
}
if(entries[i].time > oldest_time) {
oldest = i;
oldest_time = entries[i].time;
}
}
/* Use the oldest or first free entry (either pointed to by the
"oldest" variable). */
entries[oldest].time = 0;
uip_ipaddr_copy(entries[oldest].ipaddr, ipaddr);
memcpy(&entries[oldest].addr, addr, sizeof(struct uip_neighbor_addr));
}
/*---------------------------------------------------------------------------*/
static struct neighbor_entry *
find_entry(uip_ipaddr_t ipaddr)
{
int i;
for(i = 0; i < ENTRIES; ++i) {
if(uip_ipaddr_cmp(entries[i].ipaddr, ipaddr)) {
return &entries[i];
}
}
return NULL;
}
/*---------------------------------------------------------------------------*/
void
uip_neighbor_update(uip_ipaddr_t ipaddr)
{
struct neighbor_entry *e;
e = find_entry(ipaddr);
if(e != NULL) {
e->time = 0;
}
}
/*---------------------------------------------------------------------------*/
struct uip_neighbor_addr *
uip_neighbor_lookup(uip_ipaddr_t ipaddr)
{
struct neighbor_entry *e;
e = find_entry(ipaddr);
if(e != NULL) {
/* printf("Lookup neighbor with link address %02x:%02x:%02x:%02x:%02x:%02x\n",
e->addr.addr.addr[0], e->addr.addr.addr[1], e->addr.addr.addr[2], e->addr.addr.addr[3],
e->addr.addr.addr[4], e->addr.addr.addr[5]);*/
return &e->addr;
}
return NULL;
}
/*---------------------------------------------------------------------------*/
@@ -1,61 +0,0 @@
/*
* Copyright (c) 2006, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the uIP TCP/IP stack
*
* $Id: uip-neighbor.h,v 1.2 2006/06/12 08:00:30 adam Exp $
*/
/**
* \file
* Header file for database of link-local neighbors, used by
* IPv6 code and to be used by future ARP code.
* \author
* Adam Dunkels <adam@sics.se>
*/
#ifndef __UIP_NEIGHBOR_H__
#define __UIP_NEIGHBOR_H__
#include "uip.h"
struct uip_neighbor_addr {
#if UIP_NEIGHBOR_CONF_ADDRTYPE
UIP_NEIGHBOR_CONF_ADDRTYPE addr;
#else
struct uip_eth_addr addr;
#endif
};
void uip_neighbor_init(void);
void uip_neighbor_add(uip_ipaddr_t ipaddr, struct uip_neighbor_addr *addr);
void uip_neighbor_update(uip_ipaddr_t ipaddr);
struct uip_neighbor_addr *uip_neighbor_lookup(uip_ipaddr_t ipaddr);
void uip_neighbor_periodic(void);
#endif /* __UIP-NEIGHBOR_H__ */
@@ -1,18 +0,0 @@
#ifndef UIPETHERNET_CONF_H
#define UIPETHERNET_CONF_H
/* for TCP */
#define UIP_SOCKET_NUMPACKETS 5
#define UIP_CONF_MAX_CONNECTIONS 4
/* for UDP */
#define UIP_CONF_UDP 0//1
#define UIP_CONF_BROADCAST 0//1
#define UIP_CONF_UDP_CONNS 0//4
#define UIP_UDP_NUMPACKETS 0//5
/* number of attempts on write before returning number of bytes sent so far
* set to -1 to block until connection is closed by timeout */
#define UIP_ATTEMPTS_ON_WRITE -1
#endif
@@ -1,5 +1,5 @@
/* /*
Enc28J60Network.h Enc28J60NetworkClass.h
UIPEthernet network driver for Microchip ENC28J60 Ethernet Interface. UIPEthernet network driver for Microchip ENC28J60 Ethernet Interface.
Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de> Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
@@ -25,19 +25,8 @@
#include "Enc28J60Network.h" #include "Enc28J60Network.h"
#include "Arduino.h" #include "Arduino.h"
#if ENC28J60_USE_SPILIB
#include <SPI.h>
#endif
extern "C" { extern "C" {
#if defined(ARDUINO_ARCH_AVR) #include <avr/io.h>
// AVR-specific code
#include <avr/io.h>
#elif defined(ARDUINO_ARCH_SAM)
// SAM-specific code
#else
// generic, non-platform specific code
#endif
#include "enc28j60.h" #include "enc28j60.h"
#include "uip.h" #include "uip.h"
} }
@@ -51,57 +40,40 @@ extern "C" {
// set CS to 1 = passive // set CS to 1 = passive
#define CSPASSIVE digitalWrite(ENC28J60_CONTROL_CS, HIGH) #define CSPASSIVE digitalWrite(ENC28J60_CONTROL_CS, HIGH)
// //
#if defined(ARDUINO_ARCH_AVR)
#define waitspi() while(!(SPSR&(1<<SPIF))) #define waitspi() while(!(SPSR&(1<<SPIF)))
#elif defined(ARDUINO_ARCH_SAM)
#if ENC28J60_CONTROL_CS==BOARD_SPI_SS0 or ENC28J60_CONTROL_CS==BOARD_SPI_SS1 or ENC28J60_CONTROL_CS==BOARD_SPI_SS2 or ENC28J60_CONTROL_CS==BOARD_SPI_SS3
#define ENC28J60_USE_SPILIB_EXT 1
#endif
#endif
uint16_t Enc28J60Network::nextPacketPtr;
uint8_t Enc28J60Network::bank=0xff;
struct memblock Enc28J60Network::receivePkt;
Enc28J60Network::Enc28J60Network() :
MemoryPool(TXSTART_INIT+1, TXSTOP_INIT-TXSTART_INIT), // 1 byte in between RX_STOP_INIT and pool to allow prepending of controlbyte
bank(0xff)
{
}
void Enc28J60Network::init(uint8_t* macaddr) void Enc28J60Network::init(uint8_t* macaddr)
{ {
MemoryPool::init(); // 1 byte in between RX_STOP_INIT and pool to allow prepending of controlbyte
// initialize I/O // initialize I/O
// ss as output: // ss as output:
pinMode(ENC28J60_CONTROL_CS, OUTPUT); pinMode(ENC28J60_CONTROL_CS, OUTPUT);
CSPASSIVE; // ss=0 CSPASSIVE; // ss=0
// //
#if ENC28J60_USE_SPILIB
SPI.begin();
#if defined(ARDUINO_ARCH_AVR)
// AVR-specific code
SPI.setClockDivider(SPI_CLOCK_DIV2); //results in 8MHZ at 16MHZ system clock.
#elif defined(ARDUINO_ARCH_SAM)
// SAM-specific code
SPI.setClockDivider(10); //defaults to 21 which results in aprox. 4MHZ. A 10 should result in a little more than 8MHZ.
#else
// generic, non-platform specific code
#endif
#else
pinMode(SPI_MOSI, OUTPUT); pinMode(SPI_MOSI, OUTPUT);
pinMode(SPI_SCK, OUTPUT); pinMode(SPI_SCK, OUTPUT);
pinMode(SPI_MISO, INPUT); pinMode(SPI_MISO, INPUT);
//Hardware SS must be configured as OUTPUT to enable SPI-master (regardless of which pin is configured as ENC28J60_CONTROL_CS)
pinMode(SPI_SS, OUTPUT); pinMode(SPI_SS, OUTPUT);
digitalWrite(SPI_MOSI, LOW); digitalWrite(SPI_MOSI, LOW);
digitalWrite(SPI_SCK, LOW); digitalWrite(SPI_SCK, LOW);
/*DDRB |= 1<<PB3 | 1<<PB5; // mosi, sck output
cbi(DDRB,PINB4); // MISO is input
//
cbi(PORTB,PB3); // MOSI low
cbi(PORTB,PB5); // SCK low
*/
//
// initialize SPI interface // initialize SPI interface
// master mode and Fosc/2 clock: // master mode and Fosc/2 clock:
SPCR = (1<<SPE)|(1<<MSTR); SPCR = (1<<SPE)|(1<<MSTR);
SPSR |= (1<<SPI2X); SPSR |= (1<<SPI2X);
#endif
// perform system reset // perform system reset
writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
delay(50); delay(50);
@@ -176,7 +148,7 @@ void Enc28J60Network::init(uint8_t* macaddr)
memhandle memhandle
Enc28J60Network::receivePacket() Enc28J60Network::receivePacket()
{ {
uint16_t rxstat; uint8_t rxstat;
uint16_t len; uint16_t len;
// check if a packet has been received and buffered // check if a packet has been received and buffered
//if( !(readReg(EIR) & EIR_PKTIF) ){ //if( !(readReg(EIR) & EIR_PKTIF) ){
@@ -195,7 +167,7 @@ Enc28J60Network::receivePacket()
len -= 4; //remove the CRC count len -= 4; //remove the CRC count
// read the receive status (see datasheet page 43) // read the receive status (see datasheet page 43)
rxstat = readOp(ENC28J60_READ_BUF_MEM, 0); rxstat = readOp(ENC28J60_READ_BUF_MEM, 0);
rxstat |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; //rxstat |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8;
// decrement the packet counter indicate we are done with this packet // decrement the packet counter indicate we are done with this packet
writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC); writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
// check CRC and symbol errors (see datasheet page 44, table 7-3): // check CRC and symbol errors (see datasheet page 44, table 7-3):
@@ -223,7 +195,7 @@ Enc28J60Network::setERXRDPT()
memaddress memaddress
Enc28J60Network::blockSize(memhandle handle) Enc28J60Network::blockSize(memhandle handle)
{ {
return handle == UIP_RECEIVEBUFFERHANDLE ? receivePkt.size : blocks[handle].size; return handle == NOBLOCK ? 0 : handle == UIP_RECEIVEBUFFERHANDLE ? receivePkt.size : blocks[handle].size;
} }
void void
@@ -312,14 +284,6 @@ uint8_t Enc28J60Network::readByte(uint16_t addr)
writeRegPair(ERDPTL, addr); writeRegPair(ERDPTL, addr);
CSACTIVE; CSACTIVE;
#if ENC28J60_USE_SPILIB
// issue read command
SPI.transfer(ENC28J60_READ_BUF_MEM);
// read data
uint8_t c = SPI.transfer(0x00);
CSPASSIVE;
return (c);
#else
// issue read command // issue read command
SPDR = ENC28J60_READ_BUF_MEM; SPDR = ENC28J60_READ_BUF_MEM;
waitspi(); waitspi();
@@ -328,7 +292,6 @@ uint8_t Enc28J60Network::readByte(uint16_t addr)
waitspi(); waitspi();
CSPASSIVE; CSPASSIVE;
return (SPDR); return (SPDR);
#endif
} }
void Enc28J60Network::writeByte(uint16_t addr, uint8_t data) void Enc28J60Network::writeByte(uint16_t addr, uint8_t data)
@@ -336,19 +299,12 @@ void Enc28J60Network::writeByte(uint16_t addr, uint8_t data)
writeRegPair(EWRPTL, addr); writeRegPair(EWRPTL, addr);
CSACTIVE; CSACTIVE;
#if ENC28J60_USE_SPILIB
// issue write command
SPI.transfer(ENC28J60_WRITE_BUF_MEM);
// write data
SPI.transfer(data);
#else
// issue write command // issue write command
SPDR = ENC28J60_WRITE_BUF_MEM; SPDR = ENC28J60_WRITE_BUF_MEM;
waitspi(); waitspi();
// write data // write data
SPDR = data; SPDR = data;
waitspi(); waitspi();
#endif
CSPASSIVE; CSPASSIVE;
} }
@@ -357,19 +313,22 @@ Enc28J60Network::copyPacket(memhandle dest_pkt, memaddress dest_pos, memhandle s
{ {
memblock *dest = &blocks[dest_pkt]; memblock *dest = &blocks[dest_pkt];
memblock *src = src_pkt == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[src_pkt]; memblock *src = src_pkt == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[src_pkt];
memblock_mv_cb(dest->begin+dest_pos,src->begin+src_pos,len); enc28J60_mempool_block_move_callback(dest->begin+dest_pos,src->begin+src_pos,len);
// Move the RX read pointer to the start of the next received packet // Move the RX read pointer to the start of the next received packet
// This frees the memory we just read out // This frees the memory we just read out
setERXRDPT(); setERXRDPT();
} }
void void
Enc28J60Network::memblock_mv_cb(uint16_t dest, uint16_t src, uint16_t len) enc28J60_mempool_block_move_callback(memaddress dest, memaddress src, memaddress len)
{ {
//void
//Enc28J60Network::memblock_mv_cb(uint16_t dest, uint16_t src, uint16_t len)
//{
//as ENC28J60 DMA is unable to copy single bytes: //as ENC28J60 DMA is unable to copy single bytes:
if (len == 1) if (len == 1)
{ {
writeByte(dest,readByte(src)); Enc28J60Network::writeByte(dest,Enc28J60Network::readByte(src));
} }
else else
{ {
@@ -390,11 +349,11 @@ Enc28J60Network::memblock_mv_cb(uint16_t dest, uint16_t src, uint16_t len)
prevent a never ending DMA operation which prevent a never ending DMA operation which
would overwrite the entire 8-Kbyte buffer. would overwrite the entire 8-Kbyte buffer.
*/ */
writeRegPair(EDMASTL, src); Enc28J60Network::writeRegPair(EDMASTL, src);
writeRegPair(EDMADSTL, dest); Enc28J60Network::writeRegPair(EDMADSTL, dest);
if ((src <= RXSTOP_INIT)&& (len > RXSTOP_INIT))len -= (RXSTOP_INIT-RXSTART_INIT); if ((src <= RXSTOP_INIT)&& (len > RXSTOP_INIT))len -= (RXSTOP_INIT-RXSTART_INIT);
writeRegPair(EDMANDL, len); Enc28J60Network::writeRegPair(EDMANDL, len);
/* /*
2. If an interrupt at the end of the copy process is 2. If an interrupt at the end of the copy process is
@@ -402,13 +361,13 @@ Enc28J60Network::memblock_mv_cb(uint16_t dest, uint16_t src, uint16_t len)
clear EIR.DMAIF. clear EIR.DMAIF.
3. Verify that ECON1.CSUMEN is clear. */ 3. Verify that ECON1.CSUMEN is clear. */
writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_CSUMEN); Enc28J60Network::writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_CSUMEN);
/* 4. Start the DMA copy by setting ECON1.DMAST. */ /* 4. Start the DMA copy by setting ECON1.DMAST. */
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST); Enc28J60Network::writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST);
// wait until runnig DMA is completed // wait until runnig DMA is completed
while (readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST); while (Enc28J60Network::readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST);
} }
} }
@@ -423,20 +382,6 @@ Enc28J60Network::readOp(uint8_t op, uint8_t address)
{ {
CSACTIVE; CSACTIVE;
// issue read command // issue read command
#if ENC28J60_USE_SPILIB
SPI.transfer(op | (address & ADDR_MASK));
// read data
if(address & 0x80)
{
// do dummy read if needed (for mac and mii, see datasheet page 29)
SPI.transfer(0x00);
}
uint8_t c = SPI.transfer(0x00);
// release CS
CSPASSIVE;
return(c);
#else
// issue read command
SPDR = op | (address & ADDR_MASK); SPDR = op | (address & ADDR_MASK);
waitspi(); waitspi();
// read data // read data
@@ -451,7 +396,6 @@ Enc28J60Network::readOp(uint8_t op, uint8_t address)
// release CS // release CS
CSPASSIVE; CSPASSIVE;
return(SPDR); return(SPDR);
#endif
} }
void void
@@ -459,18 +403,11 @@ Enc28J60Network::writeOp(uint8_t op, uint8_t address, uint8_t data)
{ {
CSACTIVE; CSACTIVE;
// issue write command // issue write command
#if ENC28J60_USE_SPILIB
SPI.transfer(op | (address & ADDR_MASK));
// write data
SPI.transfer(data);
#else
// issue write command
SPDR = op | (address & ADDR_MASK); SPDR = op | (address & ADDR_MASK);
waitspi(); waitspi();
// write data // write data
SPDR = data; SPDR = data;
waitspi(); waitspi();
#endif
CSPASSIVE; CSPASSIVE;
} }
@@ -479,23 +416,15 @@ Enc28J60Network::readBuffer(uint16_t len, uint8_t* data)
{ {
CSACTIVE; CSACTIVE;
// issue read command // issue read command
#if ENC28J60_USE_SPILIB
SPI.transfer(ENC28J60_READ_BUF_MEM);
#else
SPDR = ENC28J60_READ_BUF_MEM; SPDR = ENC28J60_READ_BUF_MEM;
waitspi(); waitspi();
#endif
while(len) while(len)
{ {
len--; len--;
// read data // read data
#if ENC28J60_USE_SPILIB
*data = SPI.transfer(0x00);
#else
SPDR = 0x00; SPDR = 0x00;
waitspi(); waitspi();
*data = SPDR; *data = SPDR;
#endif
data++; data++;
} }
//*data='\0'; //*data='\0';
@@ -507,24 +436,15 @@ Enc28J60Network::writeBuffer(uint16_t len, uint8_t* data)
{ {
CSACTIVE; CSACTIVE;
// issue write command // issue write command
#if ENC28J60_USE_SPILIB
SPI.transfer(ENC28J60_WRITE_BUF_MEM);
#else
SPDR = ENC28J60_WRITE_BUF_MEM; SPDR = ENC28J60_WRITE_BUF_MEM;
waitspi(); waitspi();
#endif
while(len) while(len)
{ {
len--; len--;
// write data // write data
#if ENC28J60_USE_SPILIB
SPI.transfer(*data);
data++;
#else
SPDR = *data; SPDR = *data;
data++; data++;
waitspi(); waitspi();
#endif
} }
CSPASSIVE; CSPASSIVE;
} }
@@ -583,6 +503,19 @@ Enc28J60Network::phyWrite(uint8_t address, uint16_t data)
} }
} }
uint16_t
Enc28J60Network::phyRead(uint8_t address)
{
writeReg(MIREGADR,address);
writeReg(MICMD, MICMD_MIIRD);
// wait until the PHY read completes
while(readReg(MISTAT) & MISTAT_BUSY){
delayMicroseconds(15);
} //and MIRDH
writeReg(MICMD, 0);
return (readReg(MIRDL) | readReg(MIRDH) << 8);
}
void void
Enc28J60Network::clkout(uint8_t clk) Enc28J60Network::clkout(uint8_t clk)
{ {
@@ -604,40 +537,27 @@ Enc28J60Network::chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t
len = setReadPtr(handle, pos, len)-1; len = setReadPtr(handle, pos, len)-1;
CSACTIVE; CSACTIVE;
// issue read command // issue read command
#if ENC28J60_USE_SPILIB
SPI.transfer(ENC28J60_READ_BUF_MEM);
#else
SPDR = ENC28J60_READ_BUF_MEM; SPDR = ENC28J60_READ_BUF_MEM;
waitspi(); waitspi();
#endif
uint16_t i; uint16_t i;
for (i = 0; i < len; i+=2) for (i = 0; i < len; i+=2)
{ {
// read data // read data
#if ENC28J60_USE_SPILIB
t = SPI.transfer(0x00) << 8;
t += SPI.transfer(0x00);
#else
SPDR = 0x00; SPDR = 0x00;
waitspi(); waitspi();
t = SPDR << 8; t = SPDR << 8;
SPDR = 0x00; SPDR = 0x00;
waitspi(); waitspi();
t += SPDR; t += SPDR;
#endif
sum += t; sum += t;
if(sum < t) { if(sum < t) {
sum++; /* carry */ sum++; /* carry */
} }
} }
if(i == len) { if(i == len) {
#if ENC28J60_USE_SPILIB
t = (SPI.transfer(0x00) << 8) + 0;
#else
SPDR = 0x00; SPDR = 0x00;
waitspi(); waitspi();
t = (SPDR << 8) + 0; t = (SPDR << 8) + 0;
#endif
sum += t; sum += t;
if(sum < t) { if(sum < t) {
sum++; /* carry */ sum++; /* carry */
@@ -648,3 +568,30 @@ Enc28J60Network::chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t
/* Return sum in host byte order. */ /* Return sum in host byte order. */
return sum; return sum;
} }
void
Enc28J60Network::powerOff()
{
writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN);
delay(50);
writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_VRPS);
delay(50);
writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV);
}
void
Enc28J60Network::powerOn()
{
writeOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV);
delay(50);
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
delay(50);
}
bool
Enc28J60Network::linkStatus()
{
return (phyRead(PHSTAT2) & 0x0400) > 0;
}
Enc28J60Network Enc28J60;
@@ -0,0 +1,91 @@
/*
Enc28J60NetworkClass.h
UIPEthernet network driver for Microchip ENC28J60 Ethernet Interface.
Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
All rights reserved.
inspired by enc28j60.c file from the AVRlib library by Pascal Stang.
For AVRlib See http://www.procyonengineering.com/
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef Enc28J60Network_H_
#define Enc28J60Network_H_
#include "mempool.h"
#define ENC28J60_CONTROL_CS SS
#define SPI_MOSI MOSI
#define SPI_MISO MISO
#define SPI_SCK SCK
#define SPI_SS SS
#define UIP_RECEIVEBUFFERHANDLE 0xff
//#define ENC28J60DEBUG
/*
* Empfangen von ip-header, arp etc...
* wenn tcp/udp -> tcp/udp-callback -> assign new packet to connection
*/
class Enc28J60Network : public MemoryPool
{
private:
static uint16_t nextPacketPtr;
static uint8_t bank;
static struct memblock receivePkt;
static uint8_t readOp(uint8_t op, uint8_t address);
static void writeOp(uint8_t op, uint8_t address, uint8_t data);
static uint16_t setReadPtr(memhandle handle, memaddress position, uint16_t len);
static void setERXRDPT();
static void readBuffer(uint16_t len, uint8_t* data);
static void writeBuffer(uint16_t len, uint8_t* data);
static uint8_t readByte(uint16_t addr);
static void writeByte(uint16_t addr, uint8_t data);
static void setBank(uint8_t address);
static uint8_t readReg(uint8_t address);
static void writeReg(uint8_t address, uint8_t data);
static void writeRegPair(uint8_t address, uint16_t data);
static void phyWrite(uint8_t address, uint16_t data);
static uint16_t phyRead(uint8_t address);
static void clkout(uint8_t clk);
friend void enc28J60_mempool_block_move_callback(memaddress,memaddress,memaddress);
public:
uint8_t getrev(void);
void powerOn();
void powerOff();
bool linkStatus();
static void init(uint8_t* macaddr);
static memhandle receivePacket();
static void freePacket();
static memaddress blockSize(memhandle handle);
static void sendPacket(memhandle handle);
static uint16_t readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len);
static uint16_t writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len);
static void copyPacket(memhandle dest, memaddress dest_pos, memhandle src, memaddress src_pos, uint16_t len);
static uint16_t chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t len);
};
extern Enc28J60Network Enc28J60;
#endif /* Enc28J60NetworkClass_H_ */
@@ -22,13 +22,15 @@
#define POOLOFFSET 1 #define POOLOFFSET 1
MemoryPool::MemoryPool(memaddress start, memaddress size) struct memblock MemoryPool::blocks[MEMPOOL_NUM_MEMBLOCKS+1];
void
MemoryPool::init()
{ {
memset(&blocks[0], 0, sizeof(blocks)); memset(&blocks[0], 0, sizeof(blocks));
blocks[POOLSTART].begin = start; blocks[POOLSTART].begin = MEMPOOL_STARTADDRESS;
blocks[POOLSTART].size = 0; blocks[POOLSTART].size = 0;
blocks[POOLSTART].nextblock = NOBLOCK; blocks[POOLSTART].nextblock = NOBLOCK;
poolsize = size;
} }
memhandle memhandle
@@ -37,12 +39,12 @@ MemoryPool::allocBlock(memaddress size)
memblock* best = NULL; memblock* best = NULL;
memhandle cur = POOLSTART; memhandle cur = POOLSTART;
memblock* block = &blocks[POOLSTART]; memblock* block = &blocks[POOLSTART];
memaddress bestsize = poolsize + 1; memaddress bestsize = MEMPOOL_SIZE + 1;
do do
{ {
memhandle next = block->nextblock; memhandle next = block->nextblock;
memaddress freesize = ( next == NOBLOCK ? blocks[POOLSTART].begin + poolsize : blocks[next].begin) - block->begin - block->size; memaddress freesize = ( next == NOBLOCK ? blocks[POOLSTART].begin + MEMPOOL_SIZE : blocks[next].begin) - block->begin - block->size;
if (freesize == size) if (freesize == size)
{ {
best = &blocks[cur]; best = &blocks[cur];
@@ -77,14 +79,14 @@ MemoryPool::allocBlock(memaddress size)
memaddress* src = &nextblock->begin; memaddress* src = &nextblock->begin;
if (dest != *src) if (dest != *src)
{ {
#ifdef MEMBLOCK_MV #ifdef MEMPOOL_MEMBLOCK_MV
memblock_mv_cb(dest,*src,nextblock->size); MEMPOOL_MEMBLOCK_MV(dest,*src,nextblock->size);
#endif #endif
*src = dest; *src = dest;
} }
block = nextblock; block = nextblock;
} }
if (blocks[POOLSTART].begin + poolsize - block->begin - block->size >= size) if (blocks[POOLSTART].begin + MEMPOOL_SIZE - block->begin - block->size >= size)
best = block; best = block;
else else
goto notfound; goto notfound;
@@ -93,7 +95,7 @@ MemoryPool::allocBlock(memaddress size)
found: found:
{ {
block = &blocks[POOLOFFSET]; block = &blocks[POOLOFFSET];
for (cur = POOLOFFSET; cur < NUM_MEMBLOCKS + POOLOFFSET; cur++) for (cur = POOLOFFSET; cur < MEMPOOL_NUM_MEMBLOCKS + POOLOFFSET; cur++)
{ {
if (block->size) if (block->size)
{ {
@@ -118,6 +120,8 @@ MemoryPool::allocBlock(memaddress size)
void void
MemoryPool::freeBlock(memhandle handle) MemoryPool::freeBlock(memhandle handle)
{ {
if (handle == NOBLOCK)
return;
memblock *b = &blocks[POOLSTART]; memblock *b = &blocks[POOLSTART];
do do
@@ -27,18 +27,6 @@
#include "mempool_conf.h" #include "mempool_conf.h"
//#ifdef MEMBLOCK_MV
//#define memblock_mv_cb(dest,src,size) MEMBLOCK_MV(dest,src,size)
//#endif
#ifdef MEMBLOCK_ALLOC
#define memblock_alloc_cb(address,size) MEMBLOCK_ALLOC(address,size)
#endif
#ifdef MEMBLOCK_FREE
#define memblock_free_cb(address,size) MEMBLOCK_FREE(address,size)
#endif
struct memblock struct memblock
{ {
memaddress begin; memaddress begin;
@@ -53,19 +41,14 @@ class MemoryPool
#endif #endif
protected: protected:
memaddress poolsize; static struct memblock blocks[MEMPOOL_NUM_MEMBLOCKS+1];
struct memblock blocks[NUM_MEMBLOCKS+1];
#ifdef MEMBLOCK_MV
virtual void memblock_mv_cb(memaddress dest, memaddress src, memaddress size) = 0;
#endif
public: public:
MemoryPool(memaddress start, memaddress size); static void init();
memhandle static memhandle allocBlock(memaddress);
allocBlock(memaddress); static void freeBlock(memhandle);
void freeBlock(memhandle); static void resizeBlock(memhandle handle, memaddress position);
void resizeBlock(memhandle handle, memaddress position); static void resizeBlock(memhandle handle, memaddress position, memaddress size);
void resizeBlock(memhandle handle, memaddress position, memaddress size); static memaddress blockSize(memhandle);
memaddress blockSize(memhandle);
}; };
#endif #endif
@@ -0,0 +1,34 @@
#ifndef MEMPOOLCONF_H
#define MEMPOOLCONF_H
#include "uipethernet-conf.h"
extern "C" {
#include "uipopt.h"
#include "enc28j60.h"
}
#include <inttypes.h>
typedef uint16_t memaddress;
typedef uint8_t memhandle;
#if UIP_SOCKET_NUMPACKETS and UIP_CONNS
#define NUM_TCP_MEMBLOCKS (UIP_SOCKET_NUMPACKETS*2)*UIP_CONNS
#else
#define NUM_TCP_MEMBLOCKS 0
#endif
#if UIP_UDP and UIP_UDP_CONNS
#define NUM_UDP_MEMBLOCKS 3*UIP_UDP_CONNS
#else
#define NUM_UDP_MEMBLOCKS 0
#endif
#define MEMPOOL_NUM_MEMBLOCKS (NUM_TCP_MEMBLOCKS+NUM_UDP_MEMBLOCKS)
#define MEMPOOL_STARTADDRESS TXSTART_INIT+1
#define MEMPOOL_SIZE TXSTOP_INIT-TXSTART_INIT
void enc28J60_mempool_block_move_callback(memaddress,memaddress,memaddress);
#define MEMPOOL_MEMBLOCK_MV(dest,src,size) enc28J60_mempool_block_move_callback(dest,src,size)
#endif
@@ -0,0 +1,21 @@
#ifndef UIPETHERNET_CONF_H
#define UIPETHERNET_CONF_H
/* for TCP */
#define UIP_SOCKET_NUMPACKETS 5
#define UIP_CONF_MAX_CONNECTIONS 4
/* for UDP */
#define UIP_CONF_UDP 0
#define UIP_CONF_BROADCAST 1
#define UIP_CONF_UDP_CONNS 4
/* number of attempts on write before returning number of bytes sent so far
* set to -1 to block until connection is closed by timeout */
#define UIP_ATTEMPTS_ON_WRITE -1
/* timeout after which UIPClient::connect gives up. The timeout is specified in seconds.
* if set to a number <= 0 connect will timeout when uIP does (which might be longer than you expect...) */
#define UIP_CONNECT_TIMEOUT -1
#endif