Mbed library for ENC28J60 Ethernet modules. Full support for TCP/IP and UDP Server, Client and HTTP server (webserver). DHCP and DNS is included.

Dependents:   mBuino_ENC28_MQTT Nucleo_Web_ENC28J60 Nucleo_Web_ENC28J60_ADC Serial_over_Ethernet ... more

Library for ENC28J60 Ethernet modules.

/media/uploads/hudakz/enc28j60_module01.jpg

Ported to mbed from Norbert Truchsess's UIPEthernet library for Arduino. Thank you Norbert!

  • Full support for persistent (streaming) TCP/IP and UDP connections Client and Server each, ARP, ICMP, DHCP and DNS.
  • Works with both Mbed OS 2 and Mbed OS 5.

Usage:

  • Import the library into your project.
  • Add #include "UipEthernet.h" to main.cpp
  • Create one instance of the UipEthernet class initialized with the MAC address you'd like to use and SPI pins of the connected Mbed board.

Example programs:

Import programWebSwitch_ENC28J60

HTTP Server serving a simple webpage which enables to remotely turn a digital output on/off. Compile, download, run and type 'IP_address/secret/' (don't forget the last '/') into your web browser and hit ENTER.

Import programHTTPServer_Echo_ENC28J60

A simple HTTP server echoing received requests. Ethernet connection is over an ENC28J60 board. Usage: Type the server's IP address into you web browser and hit <ENTER>.

Import programTcpServer_ENC28J60

Simple TCP/IP Server using the UIPEthernet library for ENC28J60 Ethernet boards.

Import programTcpClient_ENC28J60

Simple TCP/IP Client using the UIPEthernet library for ENC28J60 Ethernet boards.

Import programUdpServer_ENC28J60

Simple UDP Server using the UIPEthernet library for ENC28J60 Ethernet boards.

Import programUdpClient_ENC28J60

Simple UDP Client using the UIPEthernet library for ENC28J60 Ethernet boards.

Import programMQTT_Hello_ENC28J60

MQTT Client example program. Ethernet connection is via an ENC28J60 module.

Files at this revision

API Documentation at this revision

Comitter:
hudakz
Date:
Tue Aug 27 15:01:10 2019 +0000
Parent:
8:4acb22344932
Child:
10:e4ddab81e6a8
Commit message:
Mbed OS 5 support added and API modified.

Changed in this revision

Dhcp.cpp Show diff for this revision Revisions of this file
Dhcp.h Show diff for this revision Revisions of this file
DhcpClient.cpp Show annotated file Show diff for this revision Revisions of this file
DhcpClient.h Show annotated file Show diff for this revision Revisions of this file
Dns.cpp Show diff for this revision Revisions of this file
Dns.h Show diff for this revision Revisions of this file
DnsClient.cpp Show annotated file Show diff for this revision Revisions of this file
DnsClient.h Show annotated file Show diff for this revision Revisions of this file
IpAddress.cpp Show annotated file Show diff for this revision Revisions of this file
IpAddress.h Show annotated file Show diff for this revision Revisions of this file
TcpClient.cpp Show annotated file Show diff for this revision Revisions of this file
TcpClient.h Show annotated file Show diff for this revision Revisions of this file
TcpServer.cpp Show annotated file Show diff for this revision Revisions of this file
TcpServer.h Show annotated file Show diff for this revision Revisions of this file
UIPClient.cpp Show diff for this revision Revisions of this file
UIPClient.h Show diff for this revision Revisions of this file
UIPEthernet.cpp Show diff for this revision Revisions of this file
UIPEthernet.h Show diff for this revision Revisions of this file
UIPServer.cpp Show diff for this revision Revisions of this file
UIPServer.h Show diff for this revision Revisions of this file
UIPUdp.cpp Show diff for this revision Revisions of this file
UIPUdp.h Show diff for this revision Revisions of this file
Udp.h Show diff for this revision Revisions of this file
UdpSocket.cpp Show annotated file Show diff for this revision Revisions of this file
UdpSocket.h Show annotated file Show diff for this revision Revisions of this file
UipEthernet.cpp Show annotated file Show diff for this revision Revisions of this file
UipEthernet.h Show annotated file Show diff for this revision Revisions of this file
ethernet_comp.h Show diff for this revision Revisions of this file
utility/Client.h Show annotated file Show diff for this revision Revisions of this file
utility/Enc28J60Network.cpp Show diff for this revision Revisions of this file
utility/Enc28J60Network.h Show diff for this revision Revisions of this file
utility/Enc28j60Py.cpp Show annotated file Show diff for this revision Revisions of this file
utility/Enc28j60Py.h Show annotated file Show diff for this revision Revisions of this file
utility/IPAddress.cpp Show diff for this revision Revisions of this file
utility/IPAddress.h Show diff for this revision Revisions of this file
utility/MemPool.cpp Show annotated file Show diff for this revision Revisions of this file
utility/MemPool.h Show annotated file Show diff for this revision Revisions of this file
utility/Server.h Show annotated file Show diff for this revision Revisions of this file
utility/Udp.h Show annotated file Show diff for this revision Revisions of this file
utility/enc28j60.h Show annotated file Show diff for this revision Revisions of this file
utility/mempool.cpp Show diff for this revision Revisions of this file
utility/mempool.h Show diff for this revision Revisions of this file
utility/mempool_conf.h Show annotated file Show diff for this revision Revisions of this file
utility/millis.cpp Show diff for this revision Revisions of this file
utility/millis.h Show diff for this revision Revisions of this file
utility/uip-conf.h Show annotated file Show diff for this revision Revisions of this file
utility/uip.h Show annotated file Show diff for this revision Revisions of this file
utility/uip_debug.cpp Show annotated file Show diff for this revision Revisions of this file
utility/uipethernet-conf.h Show annotated file Show diff for this revision Revisions of this file
utility/uipopt.h Show annotated file Show diff for this revision Revisions of this file
--- a/Dhcp.cpp	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,539 +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 "utility/util.h"
-#include "utility/millis.h"
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-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();
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void DhcpClass::reset_DHCP_lease(void) {
-
-    // 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(void) {
-    uint8_t messageType = 0;
-
-    // Pick an initial transaction ID
-
-    _dhcpTransactionId = (rand() % 2000UL) + 1;
-    _dhcpInitialTransactionId = _dhcpTransactionId;
-
-    _dhcpUdpSocket.stop();
-    if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0) {
-
-        // Couldn't get a socket
-        return 0;
-    }
-
-    presend_DHCP();
-
-    volatile 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;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void DhcpClass::presend_DHCP(void)
-{ }
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-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[8] = _dhcpLocalIp[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();
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId) {
-    volatile uint8_t    type = 0;
-    uint8_t             opt_len = 0;
-
-    unsigned long       startTime = millis();
-
-    while (_dhcpUdpSocket.parsePacket() <= 0) {
-        if ((millis() - startTime) > responseTimeout) {
-            return 255;
-        }
-
-        wait_ms(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(void) {
-
-    //this uses a signed / unsigned trick to deal with millis overflow
-    unsigned long   now = millis();
-    signed long     snow = (long)now;
-    volatile 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;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-IPAddress DhcpClass::getLocalIp(void) {
-    return IPAddress(_dhcpLocalIp);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-IPAddress DhcpClass::getSubnetMask(void) {
-    return IPAddress(_dhcpSubnetMask);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-IPAddress DhcpClass::getGatewayIp(void) {
-    return IPAddress(_dhcpGatewayIp);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-IPAddress DhcpClass::getDhcpServerIp(void) {
-    return IPAddress(_dhcpDhcpServerIp);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-IPAddress DhcpClass::getDnsServerIp(void) {
-    return IPAddress(_dhcpDnsServerIp);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-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);
-}
--- a/Dhcp.h	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,189 +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);
-    void            reset_DHCP_lease(void);
-    void            presend_DHCP(void);
-    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(void);
-    IPAddress   getSubnetMask(void);
-    IPAddress   getGatewayIp(void);
-    IPAddress   getDhcpServerIp(void);
-    IPAddress   getDnsServerIp(void);
-
-    int         beginWithDHCP(uint8_t* , unsigned long timeout = 60000, unsigned long responseTimeout = 4000);
-    int         checkLease(void);
-};
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DhcpClient.cpp	Tue Aug 27 15:01:10 2019 +0000
@@ -0,0 +1,526 @@
+// DHCP Library v0.3 - April 25, 2009
+// Author: Jordan Terrell - blog.jordanterrell.com
+#include <string.h>
+#include <stdlib.h>
+#include "DhcpClient.h"
+#include "utility/util.h"
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int DhcpClient::begin(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);
+    resetDhcpLease();
+
+    memcpy((void*)_dhcpMacAddr, (void*)mac, 6);
+    _dhcp_state = STATE_DHCP_START;
+    return requestDhcpLease();
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void DhcpClient::resetDhcpLease()
+{
+    // zero out _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp
+    memset(_dhcpLocalIp, 0, 5 * 4);
+}
+
+//return:0 on error, 1 if request is sent and response is received
+int DhcpClient::requestDhcpLease()
+{
+    uint8_t messageType = 0;
+
+    // Pick an initial transaction ID
+    srand(time(NULL));
+    _dhcpTransactionId = (rand() % 2000UL) + 1;
+    _dhcpInitialTransactionId = _dhcpTransactionId;
+
+    _dhcpUdpSocket.stop();
+    if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0) {
+        // Couldn't get a socket
+        return 0;
+    }
+
+    presendDhcp();
+
+    volatile int    result = 0;
+    time_t          startTime = time(NULL);
+
+    while (_dhcp_state != STATE_DHCP_LEASED) {
+        if (_dhcp_state == STATE_DHCP_START) {
+            _dhcpTransactionId++;
+
+            sendDhcpMessage(DHCP_DISCOVER, (time(NULL) - startTime));
+            _dhcp_state = STATE_DHCP_DISCOVER;
+        }
+        else
+        if (_dhcp_state == STATE_DHCP_REREQUEST) {
+            _dhcpTransactionId++;
+            sendDhcpMessage(DHCP_REQUEST, (time(NULL) - startTime));
+            _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;
+                sendDhcpMessage(DHCP_REQUEST, (time(NULL) - startTime));
+                _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) && ((time(NULL) - startTime) > _timeout))
+            break;
+    }
+
+    // We're done with the socket now
+    _dhcpUdpSocket.stop();
+    _dhcpTransactionId++;
+
+    return result;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void DhcpClient::presendDhcp()
+{ }
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void DhcpClient::sendDhcpMessage(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[8] = _dhcpLocalIp[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();
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint8_t DhcpClient::parseDhcpResponse(unsigned long responseTimeout, uint32_t& transactionId)
+{
+    volatile uint8_t    type = 0;
+    uint8_t             opt_len = 0;
+
+    unsigned long       startTime = time(NULL);
+
+    while (_dhcpUdpSocket.parsePacket() <= 0) {
+        if ((time(NULL) - startTime) > responseTimeout) {
+            return 255;
+        }
+
+        wait_ms(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 DhcpClient::checkLease()
+{
+    time_t          now = time(NULL);
+    volatile int    rc = DHCP_CHECK_NONE;
+    if (_lastCheck != 0) {
+        //calc how many ms past the timeout we are
+        time_t  factor = now - _secTimeout;
+
+        //if on or passed the timeout, reduce the counters
+        if (factor >= 0) {
+            //next timeout should be now plus 1s
+            _secTimeout = now + 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 + requestDhcpLease();
+        }
+
+        //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;
+            resetDhcpLease();
+            rc = 3 + requestDhcpLease();
+        }
+    }
+    else {
+        _secTimeout = now + 1;
+    }
+
+    _lastCheck = now;
+    return rc;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+IpAddress DhcpClient::getLocalIp()
+{
+    return IpAddress(_dhcpLocalIp);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+IpAddress DhcpClient::getSubnetMask()
+{
+    return IpAddress(_dhcpSubnetMask);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+IpAddress DhcpClient::getGatewayIp()
+{
+    return IpAddress(_dhcpGatewayIp);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+IpAddress DhcpClient::getDhcpServerIp()
+{
+    return IpAddress(_dhcpDhcpServerIp);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+IpAddress DhcpClient::getDnsServerIp()
+{
+    return IpAddress(_dhcpDnsServerIp);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void DhcpClient::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);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DhcpClient.h	Tue Aug 27 15:01:10 2019 +0000
@@ -0,0 +1,184 @@
+// DHCP Library v0.3 - April 25, 2009
+// Author: Jordan Terrell - blog.jordanterrell.com
+#ifndef Dhcp_h
+#define Dhcp_h
+
+#include "UdpSocket.h"
+#include "IpAddress.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   DhcpClient
+{
+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;
+    time_t      _renewInSec;
+    time_t      _rebindInSec;
+    time_t      _lastCheck;
+    time_t      _timeout;
+    time_t      _responseTimeout;
+    time_t      _secTimeout;
+    uint8_t     _dhcp_state;
+    UdpSocket   _dhcpUdpSocket;
+
+    int         requestDhcpLease();
+    void        resetDhcpLease();
+    void        presendDhcp();
+    void        sendDhcpMessage(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         begin(uint8_t* mac, unsigned long timeout = 60, unsigned long responseTimeout = 4);
+    int         checkLease();
+};
+#endif
--- a/Dns.cpp	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,451 +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 "utility/millis.h"
-
-#include "Dns.h"
-#include <string.h>
-//#include <stdlib.h>
-
-#include "mbed.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
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void DNSClient::begin(const IPAddress& aDNSServer) {
-    iDNSServer = aDNSServer;
-    iRequestId = 0;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-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] = (uint8_t) 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] = (uint8_t) segmentValue;
-            return 1;
-        }
-    }
-    else {
-        return 0;
-    }
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-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;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-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;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-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;
-        wait(0.050);
-    }
-
-    // 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;
-}
--- a/Dns.h	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DnsClient.cpp	Tue Aug 27 15:01:10 2019 +0000
@@ -0,0 +1,423 @@
+// Arduino DNS client for Enc28J60-based Ethernet shield
+// (c) Copyright 2009-2010 MCQN Ltd.
+// Released under Apache License, version 2.0
+#include "UdpSocket.h"
+#include "utility/util.h"
+
+#include "DnsClient.h"
+#include <string.h>
+#include "mbed.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
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void DnsClient::begin(const IpAddress& aDNSServer)
+{
+    iDNSServer = aDNSServer;
+    iRequestId = 0;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+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] = (uint8_t) 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] = (uint8_t) segmentValue;
+            return 1;
+        }
+    }
+    else {
+        return 0;
+    }
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+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 + (time(NULL) & 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;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+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
+    srand(time(NULL));
+    iRequestId = rand() % 0xFFFF + 1;   // 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;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int16_t DnsClient::processResponse(uint16_t aTimeout, IpAddress& aAddress)
+{
+    time_t  startTime = time(NULL);
+
+    // Wait for a response packet
+    while (iUdp.parsePacket() <= 0) {
+        if ((time(NULL) - startTime) > aTimeout)
+            return TIMED_OUT;
+        wait(0.050);
+    }
+
+    // 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.rawAddress(), 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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DnsClient.h	Tue Aug 27 15:01:10 2019 +0000
@@ -0,0 +1,39 @@
+// 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 "UdpSocket.h"
+#include "IpAddress.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);
+    int16_t     processResponse(uint16_t aTimeout, IpAddress& aAddress);
+
+    IpAddress   iDNSServer;
+    uint16_t    iRequestId;
+    UdpSocket   iUdp;
+};
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IpAddress.cpp	Tue Aug 27 15:01:10 2019 +0000
@@ -0,0 +1,121 @@
+/*
+  IPAddress.cpp - Base class that provides IPAddress
+  Copyright (c) 2011 Adrian McEwen.  All right reserved.
+
+  Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.com>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#include <stdio.h>
+#include "mbed.h"
+#include "IpAddress.h"
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+IpAddress::IpAddress(void) {
+    memset(_address, 0, sizeof(_address));
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+IpAddress::IpAddress(uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4) {
+    _address[0] = octet1;
+    _address[1] = octet2;
+    _address[2] = octet3;
+    _address[3] = octet4;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+IpAddress::IpAddress(uint32_t address) {
+    memcpy(_address, &address, sizeof(_address));
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+IpAddress::IpAddress(const uint8_t address[4]) {
+    memcpy(_address, address, sizeof(_address));
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+//IPAddress &IPAddress::operator=(const uint8_t* address) {
+//    memcpy(_address, address, sizeof(_address));
+//    return *this;
+//}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+IpAddress &IpAddress::operator=(uint32_t address) {
+    memcpy(_address, (const uint8_t*) &address, sizeof(_address));
+    return *this;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+bool IpAddress::operator==(const uint8_t* addr) const
+{
+    return memcmp(addr, _address, sizeof(_address)) == 0;
+}
+
+/**
+ * @brief   Returns IP Address as string of char
+ * @note
+ * @param
+ * @retval
+ */
+const char* IpAddress::toString(char* buf) {
+    uint8_t     i = 0;
+    uint8_t     j = 0;
+
+    for (i = 0; i < 3; i++) {
+        j += sprintf(&buf[j], "%d", _address[i]);
+        buf[j++] = '.';
+    }
+
+    j += sprintf(&buf[j], "%d", _address[i]);
+    buf[j] = '\0';
+    return buf;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IpAddress.h	Tue Aug 27 15:01:10 2019 +0000
@@ -0,0 +1,72 @@
+/*
+  IpAddress.h - Base class that provides IPAddress
+  Copyright (c) 2011 Adrian McEwen.  All right reserved.
+
+  Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.com>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+#ifndef IPADDRESS_H
+#define IPADDRESS_H
+
+#include <stdio.h>
+
+// A class to make it easier to handle and pass around IP addresses
+
+class   IpAddress
+{
+private:
+    uint8_t _address[4];    // IPv4 address
+
+public:
+    // Constructors
+    IpAddress(void);
+    IpAddress(uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4);
+    IpAddress(uint32_t address);
+    IpAddress(const uint8_t address[4]);
+
+    // Overloaded cast operator to allow IPAddress objects to be used where a pointer
+    // to a four-byte uint8_t array is expected
+    operator uint32_t(void) const    { return *((uint32_t*)_address); }
+    bool operator==(const IpAddress& addr) const { return(*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); }
+    bool operator==(const uint8_t* addr) const;
+
+    // Overloaded index operator to allow getting and setting individual octets of the address
+    uint8_t operator[](int index) const { return _address[index]; }
+    uint8_t &operator[](int index)      { return _address[index]; }
+
+    // Overloaded copy operators to allow initialisation of IPAddress objects from other types
+    IpAddress &operator =(uint32_t address);
+
+    // Returns IP Address as string of char
+    const char* toString(char* buf);
+
+    // Access the raw byte array containing the address.  Because this returns a pointer
+    // to the internal structure rather than a copy of the address this function should only
+    // be used when you know that the usage of the returned uint8_t* will be transient and not
+    // stored.
+    uint8_t*    rawAddress(void)   { return _address; }
+
+    //    virtual size_t printTo(Print& p) const;
+    friend class UIPEthernet;
+    friend class UdpSocket;
+    friend class TcpClient;
+    friend class TcpServer;
+    friend class DhcpClient;
+    friend class DnsClient;
+};
+
+const IpAddress INADDR_NONE(0, 0, 0, 0);
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TcpClient.cpp	Tue Aug 27 15:01:10 2019 +0000
@@ -0,0 +1,702 @@
+/*
+ UIPClient.cpp - Arduino implementation of a UIP wrapper class.
+ Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
+ All rights reserved.
+
+ Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.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/>.
+ */
+extern "C"
+{
+#include "utility/uip-conf.h"
+#include "utility/uip.h"
+#include "utility/uip_arp.h"
+#include "string.h"
+}
+#include "UipEthernet.h"
+#include "TcpClient.h"
+#include "DnsClient.h"
+
+#define UIP_TCP_PHYH_LEN    UIP_LLH_LEN + UIP_IPTCPH_LEN
+
+uip_userdata_t TcpClient::all_data[UIP_CONNS];
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+TcpClient::TcpClient() :
+    data(NULL)
+{ }
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+TcpClient::TcpClient(uip_userdata_t* conn_data) :
+    data(conn_data)
+{ }
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int TcpClient::connect(IpAddress ip, uint16_t port)
+{
+    stop();
+
+    uip_ipaddr_t    ipaddr;
+    uip_ip_addr(ipaddr, ip);
+
+    struct uip_conn*    conn = uip_connect(&ipaddr, htons(port));
+    if (conn)
+    {
+#if UIP_CONNECT_TIMEOUT > 0
+        int32_t timeout = time(NULL) + UIP_CONNECT_TIMEOUT;
+#endif
+        while ((conn->tcpstateflags & UIP_TS_MASK) != UIP_CLOSED) {
+            UipEthernet::ethernet->tick();
+            if ((conn->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) {
+                data = (uip_userdata_t*)conn->appstate;
+#ifdef UIPETHERNET_DEBUG_CLIENT
+                printf("connected, state: %d, first packet in: %d\r\n", data->state, data->packets_in[0]);
+#endif
+                return 1;
+            }
+
+#if UIP_CONNECT_TIMEOUT > 0
+            if (((int32_t) (time(NULL) - timeout)) > 0) {
+                conn->tcpstateflags = UIP_CLOSED;
+                break;
+            }
+#endif
+        }
+    }
+
+    return 0;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int TcpClient::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::dnsServerAddress);
+    ret = dns.getHostByName(host, remote_addr);
+    if (ret == 1) {
+        return connect(remote_addr, port);
+    }
+#endif
+    return ret;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void TcpClient::stop()
+{
+    if (data && data->state)
+    {
+#ifdef UIPETHERNET_DEBUG_CLIENT
+        printf("before stop(), with data\r\n");
+        _dumpAllData();
+#endif
+        _flushBlocks(&data->packets_in[0]);
+        if (data->state & UIP_CLIENT_REMOTECLOSED) {
+            data->state = 0;
+        }
+        else {
+            data->state |= UIP_CLIENT_CLOSE;
+        }
+
+#ifdef UIPETHERNET_DEBUG_CLIENT
+        printf("after stop()\r\n");
+        _dumpAllData();
+#endif
+    }
+
+#ifdef UIPETHERNET_DEBUG_CLIENT
+    else {
+        printf("stop(), data: NULL\r\n");
+    }
+#endif
+    data = NULL;
+    UipEthernet::ethernet->tick();
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint8_t TcpClient::connected()
+{
+    return(data && (data->packets_in[0] != NOBLOCK || (data->state & UIP_CLIENT_CONNECTED))) ? 1 : 0;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+bool TcpClient::operator==(const TcpClient& rhs)
+{
+    return data && rhs.data && (data == rhs.data);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+TcpClient::operator bool()
+{
+    UipEthernet::ethernet->tick();
+    return data && (!(data->state & UIP_CLIENT_REMOTECLOSED) || data->packets_in[0] != NOBLOCK);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+size_t TcpClient::write(uint8_t c)
+{
+    return _write(data, &c, 1);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+size_t TcpClient::write(const uint8_t* buf, size_t size)
+{
+    return _write(data, buf, size);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+size_t TcpClient::_write(uip_userdata_t* data, 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::ethernet->tick();
+    if (data && !(data->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED))) {
+        uint8_t p = _currentBlock(&data->packets_out[0]);
+        if (data->packets_out[p] == NOBLOCK)
+        {
+newpacket:
+            data->packets_out[p] = UipEthernet::ethernet->phy.allocBlock(UIP_SOCKET_DATALEN);
+            if (data->packets_out[p] == NOBLOCK)
+            {
+#if UIP_ATTEMPTS_ON_WRITE > 0
+                if (--attempts > 0)
+#endif
+#if UIP_ATTEMPTS_ON_WRITE != 0
+                    goto repeat;
+#endif
+                goto ready;
+            }
+
+            data->out_pos = 0;
+        }
+
+#ifdef UIPETHERNET_DEBUG_CLIENT
+        printf
+        (
+            "UIPClient.write: writePacket(%d) pos: %d, buf[%d-%d]\r\n",
+            u->packets_out[p],
+            u->out_pos,
+            size - remain,
+            remain
+        );
+#endif
+        written = UipEthernet::ethernet->phy.writePacket
+            (
+                data->packets_out[p],
+                data->out_pos,
+                (uint8_t*)buf + size - remain,
+                remain
+            );
+        remain -= written;
+        data->out_pos += written;
+        if (remain > 0) {
+            if (p == 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:
+        data->pollTimer.start();
+        return size - remain;
+    }
+
+    return -1;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int TcpClient::available()
+{
+    if (*this)
+        return _available(data);
+    return 0;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int TcpClient::_available(uip_userdata_t* u)
+{
+    int len = 0;
+    for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) {
+        len += UipEthernet::ethernet->phy.blockSize(u->packets_in[i]);
+    }
+
+    return len;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int TcpClient::read(uint8_t* buf, size_t size)
+{
+    if (*this) {
+        uint16_t    remain = size;
+        if (data->packets_in[0] == NOBLOCK)
+            return 0;
+
+        uint16_t    read;
+        do {
+            read = UipEthernet::ethernet->phy.readPacket(data->packets_in[0], 0, buf + size - remain, remain);
+            if (read == UipEthernet::ethernet->phy.blockSize(data->packets_in[0])) {
+                remain -= read;
+                _eatBlock(&data->packets_in[0]);
+                if
+                (
+                    uip_stopped(&uip_conns[data->state & UIP_CLIENT_SOCKETS]) &&
+                    !(data->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED))
+                ) data->state |= UIP_CLIENT_RESTART;
+                if (data->packets_in[0] == NOBLOCK) {
+                    if (data->state & UIP_CLIENT_REMOTECLOSED) {
+                        data->state = 0;
+                        data = NULL;
+                    }
+
+                    return size - remain;
+                }
+            }
+            else {
+                UipEthernet::ethernet->phy.resizeBlock(data->packets_in[0], read);
+                break;
+            }
+        } while (remain > 0);
+        return size;
+    }
+
+    return -1;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int TcpClient::read()
+{
+    static uint8_t  c;
+    if (read(&c, 1) < 0)
+        return -1;
+    return c;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int TcpClient::peek()
+{
+    static uint8_t  c;
+    if (*this) {
+        if (data->packets_in[0] != NOBLOCK) {
+            UipEthernet::ethernet->phy.readPacket(data->packets_in[0], 0, &c, 1);
+            return c;
+        }
+    }
+
+    return -1;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void TcpClient::flush()
+{
+    if (*this) {
+        _flushBlocks(&data->packets_in[0]);
+    }
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void TcpClient::close()
+{
+    delete this;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void uipclient_appcall()
+{
+    uint16_t            send_len = 0;
+    uip_userdata_t*     u = (uip_userdata_t*)uip_conn->appstate;
+    if (!u && uip_connected())
+    {
+#ifdef UIPETHERNET_DEBUG_CLIENT
+        printf("UIPClient uip_connected\r\n");
+        UIPClient::_dumpAllData();
+#endif
+        u = (uip_userdata_t*)TcpClient::_allocateData();
+        if (u) {
+            uip_conn->appstate = u;
+#ifdef UIPETHERNET_DEBUG_CLIENT
+            printf("UIPClient allocated state: %d", u->state);
+#endif
+        }
+
+#ifdef UIPETHERNET_DEBUG_CLIENT
+        else
+            printf("UIPClient allocation failed\r\n");
+#endif
+    }
+
+    if (u) {
+        if (uip_newdata())
+        {
+#ifdef UIPETHERNET_DEBUG_CLIENT
+            printf("UIPClient uip_newdata, uip_len: %d\r\n", uip_len);
+#endif
+            if (uip_len && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED))) {
+                for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) {
+                    if (u->packets_in[i] == NOBLOCK) {
+                        u->packets_in[i] = UipEthernet::ethernet->phy.allocBlock(uip_len);
+                        if (u->packets_in[i] != NOBLOCK) {
+                            UipEthernet::ethernet->phy.copyPacket
+                                (
+                                    u->packets_in[i],
+                                    0,
+                                    UipEthernet::inPacket,
+                                    ((uint8_t*)uip_appdata) - uip_buf,
+                                    uip_len
+                                );
+                            if (i == UIP_SOCKET_NUMPACKETS - 1)
+                                uip_stop();
+                            goto finish_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
+            printf("UIPClient uip_closed\r\n");
+            UIPClient::_dumpAllData();
+#endif
+            // drop outgoing packets not sent yet:
+
+            TcpClient::_flushBlocks(&u->packets_out[0]);
+            if (u->packets_in[0] != NOBLOCK) {
+                ((uip_userdata_closed_t*)u)->lport = uip_conn->lport;
+                u->state |= UIP_CLIENT_REMOTECLOSED;
+            }
+            else
+                u->state = 0;
+
+            // disassociate appdata.
+#ifdef UIPETHERNET_DEBUG_CLIENT
+            printf("after UIPClient uip_closed\r\n");
+            UIPClient::_dumpAllData();
+#endif
+            uip_conn->appstate = NULL;
+            goto finish;
+        }
+
+        if (uip_acked())
+        {
+#ifdef UIPETHERNET_DEBUG_CLIENT
+            printf("UIPClient uip_acked\r\n");
+#endif
+            TcpClient::_eatBlock(&u->packets_out[0]);
+        }
+
+        if (uip_poll() || uip_rexmit())
+        {
+#ifdef UIPETHERNET_DEBUG_CLIENT
+            //printf("UIPClient uip_poll\r\n");
+#endif
+            if (u->packets_out[0] != NOBLOCK) {
+                if (u->packets_out[1] == NOBLOCK) {
+                    send_len = u->out_pos;
+                    if (send_len > 0) {
+                        UipEthernet::ethernet->phy.resizeBlock(u->packets_out[0], 0, send_len);
+                    }
+                }
+                else
+                    send_len = UipEthernet::ethernet->phy.blockSize(u->packets_out[0]);
+                if (send_len > 0) {
+                    UipEthernet::uipHeaderLen = ((uint8_t*)uip_appdata) - uip_buf;
+                    UipEthernet::uipPacket = UipEthernet::ethernet->phy.allocBlock(UipEthernet::uipHeaderLen + send_len);
+                    if (UipEthernet::uipPacket != NOBLOCK) {
+                        UipEthernet::ethernet->phy.copyPacket
+                            (
+                                UipEthernet::uipPacket,
+                                UipEthernet::uipHeaderLen,
+                                u->packets_out[0],
+                                0,
+                                send_len
+                            );
+                        UipEthernet::packetState |= UIPETHERNET_SENDPACKET;
+                    }
+                }
+
+                goto finish;
+            }
+        }
+
+        // don't close connection unless all outgoing packets are sent
+        if (u->state & UIP_CLIENT_CLOSE)
+        {
+#ifdef UIPETHERNET_DEBUG_CLIENT
+            printf("UIPClient state UIP_CLIENT_CLOSE\r\n");
+            UIPClient::_dumpAllData();
+#endif
+            if (u->packets_out[0] == NOBLOCK) {
+                u->state = 0;
+                uip_conn->appstate = NULL;
+                uip_close();
+#ifdef UIPETHERNET_DEBUG_CLIENT
+                printf("no blocks out -> free userdata\r\n");
+                UIPClient::_dumpAllData();
+#endif
+            }
+            else {
+                uip_stop();
+#ifdef UIPETHERNET_DEBUG_CLIENT
+                printf("blocks outstanding transfer -> uip_stop()\r\n");
+#endif
+            }
+        }
+    }
+
+finish:
+    uip_send(uip_appdata, send_len);
+    uip_len = send_len;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uip_userdata_t* TcpClient::_allocateData()
+{
+    for (uint8_t sock = 0; sock < UIP_CONNS; sock++) {
+        uip_userdata_t*     data = &TcpClient::all_data[sock];
+        if (!data->state) {
+            data->pollTimer.reset();
+            data->state = sock | UIP_CLIENT_CONNECTED;
+            memset(data->packets_in, 0, sizeof(data->packets_in) / sizeof(data->packets_in[0]));
+            memset(&data->packets_out, 0, sizeof(data->packets_out) / sizeof(data->packets_out[0]));
+            data->out_pos = 0;
+            return data;
+        }
+    }
+
+    return NULL;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint8_t TcpClient::_currentBlock(memhandle* block)
+{
+    for (uint8_t i = 1; i < UIP_SOCKET_NUMPACKETS; i++) {
+        if (block[i] == NOBLOCK)
+            return i - 1;
+    }
+
+    return UIP_SOCKET_NUMPACKETS - 1;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void TcpClient::_eatBlock(memhandle* block)
+{
+#ifdef UIPETHERNET_DEBUG_CLIENT
+    memhandle*  start = block;
+    printf("eatblock(%d): ", *block);
+    for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) {
+        printf("%d ", start[i]);
+    }
+
+    printf("-> ");
+#endif
+    UipEthernet::ethernet->phy.freeBlock(block[0]);
+    for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS - 1; i++) {
+        block[i] = block[i + 1];
+    }
+
+    block[UIP_SOCKET_NUMPACKETS - 1] = NOBLOCK;
+#ifdef UIPETHERNET_DEBUG_CLIENT
+    for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) {
+        printf("%d ", start[i]);
+    }
+
+    printf("\r\n");
+#endif
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void TcpClient::_flushBlocks(memhandle* block)
+{
+    for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) {
+        UipEthernet::ethernet->phy.freeBlock(block[i]);
+        block[i] = NOBLOCK;
+    }
+}
+
+#ifdef UIPETHERNET_DEBUG_CLIENT
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UIPClient::_dumpAllData()
+{
+    for (uint8_t i = 0; i < UIP_CONNS; i++) {
+        printf("UIPClient::all_data[%d], state:%d packets_in: ", i, all_data[i].state);
+        for (uint8_t j = 0; j < UIP_SOCKET_NUMPACKETS; j++) {
+            printf("%d ", all_data[i].packets_in[j]);
+        }
+
+        printf("\r\n");
+        if (all_data[i].state & UIP_CLIENT_REMOTECLOSED) {
+            printf("state remote closed, local port: %d", htons(((uip_userdata_closed_t *) (&all_data[i]))->lport));
+            printf("\r\n");
+        }
+        else {
+            printf("packets_out: ");
+            for (uint8_t j = 0; j < UIP_SOCKET_NUMPACKETS; j++) {
+                printf("%d ", all_data[i].packets_out[j]);
+            }
+
+            printf("\r\n");
+            printf("out_pos: %d\r\n", all_data[i].out_pos);
+        }
+    }
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TcpClient.h	Tue Aug 27 15:01:10 2019 +0000
@@ -0,0 +1,105 @@
+/*
+ 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 "mbed.h"
+#include "Client.h"
+#include "utility/MemPool.h"
+
+extern "C"
+{
+#include "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_REMOTECLOSED 0x40
+#define UIP_CLIENT_RESTART      0x80
+#define UIP_CLIENT_STATEFLAGS   (UIP_CLIENT_CONNECTED | UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED | 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
+{
+    Timer       pollTimer;
+    uint8_t     state;
+    memhandle   packets_in[UIP_SOCKET_NUMPACKETS];
+    memhandle   packets_out[UIP_SOCKET_NUMPACKETS];
+    memaddress  out_pos;
+} uip_userdata_t;
+
+class TcpClient : public Client
+{
+public:
+    TcpClient();
+    //TcpClient(UIPEthernet* ethernet);
+    //TcpClient(struct uip_conn* _conn);
+    //TcpClient(struct uip_conn* _conn, UIPEthernet* ethernet);
+    TcpClient(uip_userdata_t* conn_data);
+    //TcpClient(uip_userdata_t* conn_data, UIPEthernet* ethernet);
+    virtual ~TcpClient() {}
+    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 TcpClient& );
+    virtual bool operator   !=(const TcpClient& 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();
+    void                    close();
+
+    static uip_userdata_t   all_data[UIP_CONNS];
+    static size_t           _write(uip_userdata_t* , const uint8_t* buf, size_t size);
+
+private:
+    uip_userdata_t*         data;
+    static uip_userdata_t*  _allocateData();
+    static int              _available(uip_userdata_t* );
+    static uint8_t          _currentBlock(memhandle* blocks);
+    static void             _eatBlock(memhandle* blocks);
+    static void             _flushBlocks(memhandle* blocks);
+
+#ifdef UIPETHERNET_DEBUG_CLIENT
+    static void             _dumpAllData();
+#endif
+    friend class            UipEthernet;
+    friend class            TcpServer;
+    friend void             uipclient_appcall();
+};
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TcpServer.cpp	Tue Aug 27 15:01:10 2019 +0000
@@ -0,0 +1,131 @@
+/*
+ TcpServer.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 "TcpServer.h"
+extern "C"
+{
+#include "utility/uip-conf.h"
+}
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+TcpServer::TcpServer()
+{ }
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+TcpClient* TcpServer::accept()
+{
+    UipEthernet::ethernet->tick();
+    for (uip_userdata_t * data = &TcpClient::all_data[0]; data < &TcpClient::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_REMOTECLOSED) && ((uip_userdata_closed_t*)data)->lport == _port)
+            )
+        ) {
+            return(new TcpClient(data));
+        }
+    }
+
+    return(new TcpClient());
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void TcpServer::open(UipEthernet* ethernet)
+{
+    //UIPEthernet::ethernet = ethernet;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void TcpServer::bind(uint8_t port)
+{
+    _port = htons(port);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void TcpServer::bind(const char* ip, uint8_t port)
+{
+    _port = htons(port);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void TcpServer::listen(uint8_t conns)
+{
+    _conns = _conns < UIP_CONNS ? conns : UIP_CONNS;
+    uip_listen(_port);
+    UipEthernet::ethernet->tick();
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+size_t TcpServer::send(uint8_t c)
+{
+    return send(&c, 1);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+size_t TcpServer::send(const uint8_t* buf, size_t size)
+{
+    size_t  ret = 0;
+    for (uip_userdata_t * data = &TcpClient::all_data[0]; data < &TcpClient::all_data[UIP_CONNS]; data++) {
+        if ((data->state & UIP_CLIENT_CONNECTED) && uip_conns[data->state & UIP_CLIENT_SOCKETS].lport == _port)
+            ret += TcpClient::_write(data, buf, size);
+    }
+
+    return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TcpServer.h	Tue Aug 27 15:01:10 2019 +0000
@@ -0,0 +1,42 @@
+/*
+ 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 "Server.h"
+#include "TcpClient.h"
+
+class UipEthernet;
+
+class TcpServer
+{
+public:
+    TcpServer();
+    void        open(UipEthernet* ethernet);
+    void        bind(uint8_t port);
+    void        bind(const char* ip, uint8_t port);
+    void        listen(uint8_t conns);
+    TcpClient*  accept();
+    size_t      send(uint8_t);
+    size_t      send(const uint8_t* buf, size_t size);
+private:
+    uint16_t    _port;
+    uint8_t     _conns;
+};
+#endif
--- a/UIPClient.cpp	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,666 +0,0 @@
-/*
- UIPClient.cpp - Arduino implementation of a UIP wrapper class.
- Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
- All rights reserved.
-
- Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.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/>.
- */
-extern "C"
-{
-#include "utility/uip-conf.h"
-#include "utility/uip.h"
-#include "utility/uip_arp.h"
-#include "utility/millis.h"
-#include "string.h"
-}
-#include "UIPEthernet.h"
-#include "UIPClient.h"
-#include "Dns.h"
-
-#define UIP_TCP_PHYH_LEN    UIP_LLH_LEN + UIP_IPTCPH_LEN
-
-uip_userdata_t UIPClient::all_data[UIP_CONNS];
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-UIPClient::UIPClient(void) :
-    data(NULL)
-{ }
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-UIPClient::UIPClient(uip_userdata_t* conn_data) :
-    data(conn_data)
-{ }
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-int UIPClient::connect(IPAddress ip, uint16_t port) {
-    stop();
-
-    uip_ipaddr_t    ipaddr;
-    uip_ip_addr(ipaddr, ip);
-
-    struct uip_conn*    conn = uip_connect(&ipaddr, htons(port));
-    if (conn)
-    {
-#if UIP_CONNECT_TIMEOUT > 0
-        int32_t timeout = millis() + 1000 * UIP_CONNECT_TIMEOUT;
-#endif
-        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
-                printf("connected, state: %d, first packet in: %d\r\n", data->state, data->packets_in[0]);
-#endif
-                return 1;
-            }
-
-#if UIP_CONNECT_TIMEOUT > 0
-            if (((int32_t) (millis() - timeout)) > 0) {
-                conn->tcpstateflags = UIP_CLOSED;
-                break;
-            }
-#endif
-        }
-    }
-
-    return 0;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-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::_dnsServerAddress);
-    ret = dns.getHostByName(host, remote_addr);
-    if (ret == 1) {
-        return connect(remote_addr, port);
-    }
-#endif
-    return ret;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void UIPClient::stop(void) {
-    if (data && data->state)
-    {
-#ifdef UIPETHERNET_DEBUG_CLIENT
-        printf("before stop(), with data\r\n");
-        _dumpAllData();
-#endif
-        _flushBlocks(&data->packets_in[0]);
-        if (data->state & UIP_CLIENT_REMOTECLOSED) {
-            data->state = 0;
-        }
-        else {
-            data->state |= UIP_CLIENT_CLOSE;
-        }
-
-#ifdef UIPETHERNET_DEBUG_CLIENT
-        printf("after stop()\r\n");
-        _dumpAllData();
-#endif
-    }
-
-#ifdef UIPETHERNET_DEBUG_CLIENT
-    else {
-        printf("stop(), data: NULL\r\n");
-    }
-#endif
-    data = NULL;
-    uIPEthernet.tick();
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-uint8_t UIPClient::connected(void) {
-    return(data && (data->packets_in[0] != NOBLOCK || (data->state & UIP_CLIENT_CONNECTED))) ? 1 : 0;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-bool UIPClient::operator==(const UIPClient& rhs) {
-    return data && rhs.data && (data == rhs.data);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-UIPClient::operator bool(void) {
-    uIPEthernet.tick();
-    return data && (!(data->state & UIP_CLIENT_REMOTECLOSED) || data->packets_in[0] != NOBLOCK);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-size_t UIPClient::write(uint8_t c) {
-    return _write(data, &c, 1);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-size_t UIPClient::write(const uint8_t* buf, size_t size) {
-    return _write(data, buf, size);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-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_REMOTECLOSED))) {
-        uint8_t p = _currentBlock(&u->packets_out[0]);
-        if (u->packets_out[p] == NOBLOCK)
-        {
-newpacket:
-            u->packets_out[p] = uIPEthernet.network.allocBlock(UIP_SOCKET_DATALEN);
-            if (u->packets_out[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
-        printf("UIPClient.write: writePacket(%d) pos: %d, buf[%d-%d]\r\n", u->packets_out[p], u->out_pos, size - remain, remain);
-#endif
-        written = uIPEthernet.network.writePacket
-            (
-                u->packets_out[p],
-                u->out_pos,
-                (uint8_t*)buf + size - remain,
-                remain
-            );
-        remain -= written;
-        u->out_pos += written;
-        if (remain > 0) {
-            if (p == 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:
-#if UIP_CLIENT_TIMER >= 0
-        u->timer = millis() + UIP_CLIENT_TIMER;
-#endif
-        return size - remain;
-    }
-
-    return -1;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-int UIPClient::available(void) {
-    if (*this)
-        return _available(data);
-    return 0;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-int UIPClient::_available(uip_userdata_t* u) {
-    int len = 0;
-    for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) {
-        len += uIPEthernet.network.blockSize(u->packets_in[i]);
-    }
-
-    return len;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-int UIPClient::read(uint8_t* buf, size_t size) {
-    if (*this) {
-        uint16_t    remain = size;
-        if (data->packets_in[0] == NOBLOCK)
-            return 0;
-
-        uint16_t    read;
-        do {
-            read = uIPEthernet.network.readPacket(data->packets_in[0], 0, buf + size - remain, remain);
-            if (read == uIPEthernet.network.blockSize(data->packets_in[0])) {
-                remain -= read;
-                _eatBlock(&data->packets_in[0]);
-                if
-                (
-                    uip_stopped(&uip_conns[data->state & UIP_CLIENT_SOCKETS])
-                &&  !(data->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED))
-                ) data->state |= UIP_CLIENT_RESTART;
-                if (data->packets_in[0] == NOBLOCK) {
-                    if (data->state & UIP_CLIENT_REMOTECLOSED) {
-                        data->state = 0;
-                        data = NULL;
-                    }
-
-                    return size - remain;
-                }
-            }
-            else {
-                uIPEthernet.network.resizeBlock(data->packets_in[0], read);
-                break;
-            }
-        } while (remain > 0);
-        return size;
-    }
-
-    return -1;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-int UIPClient::read(void) {
-    static uint8_t  c;
-    if (read(&c, 1) < 0)
-        return -1;
-    return c;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-int UIPClient::peek(void) {
-    static uint8_t  c;
-    if (*this) {
-        if (data->packets_in[0] != NOBLOCK) {
-            uIPEthernet.network.readPacket(data->packets_in[0], 0, &c, 1);
-            return c;
-        }
-    }
-
-    return -1;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void UIPClient::flush(void) {
-    if (*this) {
-        _flushBlocks(&data->packets_in[0]);
-    }
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void uipclient_appcall(void) {
-    uint16_t            send_len = 0;
-    uip_userdata_t*     u = (uip_userdata_t*)uip_conn->appstate;
-    if (!u && uip_connected())
-    {
-#ifdef UIPETHERNET_DEBUG_CLIENT
-        printf("UIPClient uip_connected\r\n");
-        UIPClient::_dumpAllData();
-#endif
-        u = (uip_userdata_t*)UIPClient::_allocateData();
-        if (u) {
-            uip_conn->appstate = u;
-#ifdef UIPETHERNET_DEBUG_CLIENT
-            printf("UIPClient allocated state: %d", u->state);
-#endif
-        }
-
-#ifdef UIPETHERNET_DEBUG_CLIENT
-        else
-            printf("UIPClient allocation failed\r\n");
-#endif
-    }
-
-    if (u) {
-        if (uip_newdata())
-        {
-#ifdef UIPETHERNET_DEBUG_CLIENT
-            printf("UIPClient uip_newdata, uip_len: %d\r\n", uip_len);
-#endif
-            if (uip_len && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED))) {
-                for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) {
-                    if (u->packets_in[i] == NOBLOCK) {
-                        u->packets_in[i] = uIPEthernet.network.allocBlock(uip_len);
-                        if (u->packets_in[i] != NOBLOCK) {
-                            uIPEthernet.network.copyPacket
-                                (
-                                    u->packets_in[i],
-                                    0,
-                                    UIPEthernet::in_packet,
-                                    ((uint8_t*)uip_appdata) - uip_buf,
-                                    uip_len
-                                );
-                            if (i == UIP_SOCKET_NUMPACKETS - 1)
-                                uip_stop();
-                            goto finish_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
-            printf("UIPClient uip_closed\r\n");
-            UIPClient::_dumpAllData();
-#endif
-            // drop outgoing packets not sent yet:
-
-            UIPClient::_flushBlocks(&u->packets_out[0]);
-            if (u->packets_in[0] != NOBLOCK) {
-                ((uip_userdata_closed_t*)u)->lport = uip_conn->lport;
-                u->state |= UIP_CLIENT_REMOTECLOSED;
-            }
-            else
-                u->state = 0;
-
-            // disassociate appdata.
-#ifdef UIPETHERNET_DEBUG_CLIENT
-            printf("after UIPClient uip_closed\r\n");
-            UIPClient::_dumpAllData();
-#endif
-            uip_conn->appstate = NULL;
-            goto finish;
-        }
-
-        if (uip_acked())
-        {
-#ifdef UIPETHERNET_DEBUG_CLIENT
-            printf("UIPClient uip_acked\r\n");
-#endif
-            UIPClient::_eatBlock(&u->packets_out[0]);
-        }
-
-        if (uip_poll() || uip_rexmit())
-        {
-#ifdef UIPETHERNET_DEBUG_CLIENT
-            //printf("UIPClient uip_poll\r\n");
-#endif
-            if (u->packets_out[0] != NOBLOCK) {
-                if (u->packets_out[1] == NOBLOCK) {
-                    send_len = u->out_pos;
-                    if (send_len > 0) {
-                        uIPEthernet.network.resizeBlock(u->packets_out[0], 0, send_len);
-                    }
-                }
-                else
-                    send_len = uIPEthernet.network.blockSize(u->packets_out[0]);
-                if (send_len > 0) {
-                    UIPEthernet::uip_hdrlen = ((uint8_t*)uip_appdata) - uip_buf;
-                    UIPEthernet::uip_packet = uIPEthernet.network.allocBlock(UIPEthernet::uip_hdrlen + send_len);
-                    if (UIPEthernet::uip_packet != NOBLOCK) {
-                        uIPEthernet.network.copyPacket
-                            (
-                                UIPEthernet::uip_packet,
-                                UIPEthernet::uip_hdrlen,
-                                u->packets_out[0],
-                                0,
-                                send_len
-                            );
-                        UIPEthernet::packetstate |= UIPETHERNET_SENDPACKET;
-                    }
-                }
-
-                goto finish;
-            }
-        }
-
-        // don't close connection unless all outgoing packets are sent
-        if (u->state & UIP_CLIENT_CLOSE)
-        {
-#ifdef UIPETHERNET_DEBUG_CLIENT
-            printf("UIPClient state UIP_CLIENT_CLOSE\r\n");
-            UIPClient::_dumpAllData();
-#endif
-            if (u->packets_out[0] == NOBLOCK) {
-                u->state = 0;
-                uip_conn->appstate = NULL;
-                uip_close();
-#ifdef UIPETHERNET_DEBUG_CLIENT
-                printf("no blocks out -> free userdata\r\n");
-                UIPClient::_dumpAllData();
-#endif
-            }
-            else {
-                uip_stop();
-#ifdef UIPETHERNET_DEBUG_CLIENT
-                printf("blocks outstanding transfer -> uip_stop()\r\n");
-#endif
-            }
-        }
-    }
-
-finish:
-    uip_send(uip_appdata, send_len);
-    uip_len = send_len;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-uip_userdata_t* UIPClient::_allocateData(void) {
-    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;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-uint8_t UIPClient::_currentBlock(memhandle* block) {
-    for (uint8_t i = 1; i < UIP_SOCKET_NUMPACKETS; i++) {
-        if (block[i] == NOBLOCK)
-            return i - 1;
-    }
-
-    return UIP_SOCKET_NUMPACKETS - 1;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void UIPClient::_eatBlock(memhandle* block)
-{
-#ifdef UIPETHERNET_DEBUG_CLIENT
-    memhandle*  start = block;
-    printf("eatblock(%d): ", *block);
-    for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) {
-        printf("%d ", start[i]);
-    }
-
-    printf("-> ");
-#endif
-    uIPEthernet.network.freeBlock(block[0]);
-    for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS - 1; i++) {
-        block[i] = block[i + 1];
-    }
-
-    block[UIP_SOCKET_NUMPACKETS - 1] = NOBLOCK;
-#ifdef UIPETHERNET_DEBUG_CLIENT
-    for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) {
-        printf("%d ", start[i]);
-    }
-
-    printf("\r\n");
-#endif
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void UIPClient::_flushBlocks(memhandle* block) {
-    for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) {
-        uIPEthernet.network.freeBlock(block[i]);
-        block[i] = NOBLOCK;
-    }
-}
-
-#ifdef UIPETHERNET_DEBUG_CLIENT
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void UIPClient::_dumpAllData(void) {
-    for (uint8_t i = 0; i < UIP_CONNS; i++) {
-        printf("UIPClient::all_data[%d], state:%d packets_in: ", i, all_data[i].state);
-        for (uint8_t j = 0; j < UIP_SOCKET_NUMPACKETS; j++) {
-            printf("%d ", all_data[i].packets_in[j]);
-        }
-
-        printf("\r\n");
-        if (all_data[i].state & UIP_CLIENT_REMOTECLOSED) {
-            printf("state remote closed, local port: %d", htons(((uip_userdata_closed_t *) (&all_data[i]))->lport));
-            printf("\r\n");
-        }
-        else {
-            printf("packets_out: ");
-            for (uint8_t j = 0; j < UIP_SOCKET_NUMPACKETS; j++) {
-                printf("%d ", all_data[i].packets_out[j]);
-            }
-
-            printf("\r\n");
-            printf("out_pos: %d\r\n", all_data[i].out_pos);
-        }
-    }
-}
-#endif
-
--- a/UIPClient.h	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +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"
-//#include "Print.h"
-
-#include "Client.h"
-#include "utility/mempool.h"
-
-extern "C"
-{
-#include "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_REMOTECLOSED 0x40
-#define UIP_CLIENT_RESTART      0x80
-#define UIP_CLIENT_STATEFLAGS   (UIP_CLIENT_CONNECTED | UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED | 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;
-#if UIP_CLIENT_TIMER >= 0
-    unsigned long   timer;
-#endif
-} uip_userdata_t;
-
-class UIPClient :
-    public Client
-{
-public:
-    UIPClient(void);
-    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(void);
-    uint8_t                 connected(void);
-    operator                bool(void);
-    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(void);
-    int                     read(void);
-    int                     peek(void);
-    void                    flush(void);
-
-//  using Print::write;
-
-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(void);
-
-    static size_t           _write(uip_userdata_t* , const uint8_t* buf, size_t size);
-    static int              _available(uip_userdata_t* );
-
-    static uint8_t          _currentBlock(memhandle* blocks);
-    static void             _eatBlock(memhandle* blocks);
-    static void             _flushBlocks(memhandle* blocks);
-
-#ifdef UIPETHERNET_DEBUG_CLIENT
-    static void             _dumpAllData(void);
-#endif
-    friend class            UIPEthernet;
-    friend class            UIPServer;
-
-    friend void             uipclient_appcall(void);
-};
-#endif
-
--- a/UIPEthernet.cpp	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,596 +0,0 @@
-/*
- UIPEthernet.cpp - Arduino implementation of a UIP wrapper class.
- Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
- All rights reserved.
-
- Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.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/>.
-  */
-#include "mbed.h"
-#include "UIPEthernet.h"
-#include "utility/Enc28J60Network.h"
-#include "UIPUdp.h"
-
-extern "C"
-{
-#include "utility/uip-conf.h"
-#include "utility/uip.h"
-#include "utility/uip_arp.h"
-#include "utility/uip_timer.h"
-#include "utility/millis.h"
-}
-#define ETH_HDR ((struct uip_eth_hdr*) &uip_buf[0])
-
-memhandle       UIPEthernet::in_packet(NOBLOCK);
-memhandle       UIPEthernet::uip_packet(NOBLOCK);
-uint8_t         UIPEthernet::uip_hdrlen(0);
-uint8_t         UIPEthernet::packetstate(0);
-
-IPAddress       UIPEthernet::_dnsServerAddress;
-DhcpClass*      UIPEthernet::_dhcp(NULL);
-
-unsigned long   UIPEthernet::periodic_timer;
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void enc28J60_mempool_block_move_callback(memaddress dest, memaddress src, memaddress len) {
-
-    //as ENC28J60 DMA is unable to copy single bytes:
-
-    if (len == 1) {
-        uIPEthernet.network.writeByte(dest, uIPEthernet.network.readByte(src));
-    }
-    else {
-
-        // calculate address of last byte
-        len += src - 1;
-
-        /* 1. Appropriately program the EDMAST, EDMAND
-              and EDMADST register pairs. The EDMAST
-              registers should point to the first byte to copy
-              from, the EDMAND registers should point to the
-              last byte to copy and the EDMADST registers
-              should point to the first byte in the destination
-              range. The destination range will always be
-              linear, never wrapping at any values except from
-              8191 to 0 (the 8-Kbyte memory boundary).
-              Extreme care should be taken when
-              programming the start and end pointers to
-              prevent a never ending DMA operation which
-              would overwrite the entire 8-Kbyte buffer.
-       */
-        uIPEthernet.network.writeRegPair(EDMASTL, src);
-        uIPEthernet.network.writeRegPair(EDMADSTL, dest);
-
-        if ((src <= RXSTOP_INIT) && (len > RXSTOP_INIT))
-            len -= (RXSTOP_INIT - RXSTART_INIT);
-        uIPEthernet.network.writeRegPair(EDMANDL, len);
-
-        /* 2. If an interrupt at the end of the copy process is
-              desired, set EIE.DMAIE and EIE.INTIE and
-              clear EIR.DMAIF.
-
-           3. Verify that ECON1.CSUMEN is clear. */
-        uIPEthernet.network.writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_CSUMEN);
-
-        /* 4. Start the DMA copy by setting ECON1.DMAST. */
-        uIPEthernet.network.writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST);
-
-        //    wait until runnig DMA is completed
-        while (uIPEthernet.network.readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST);
-    }
-}
-
-/*
- * 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.
- */
-UIPEthernet::UIPEthernet(PinName mosi, PinName miso, PinName sck, PinName cs) :
-    network(mosi, miso, sck, cs) {
-    millis_start();
-}
-
-#if UIP_UDP
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-int UIPEthernet::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;
-}
-#endif
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void UIPEthernet::begin(const uint8_t* mac, IPAddress ip) {
-    IPAddress   dns = ip;
-
-    dns[3] = 1;
-    begin(mac, ip, dns);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void UIPEthernet::begin(const uint8_t* mac, IPAddress ip, IPAddress dns) {
-    IPAddress   gateway = ip;
-
-    gateway[3] = 1;
-    begin(mac, ip, dns, gateway);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void UIPEthernet::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway) {
-    IPAddress   subnet(255, 255, 255, 0);
-
-    begin(mac, ip, dns, gateway, subnet);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void UIPEthernet::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) {
-    init(mac);
-    configure(ip, dns, gateway, subnet);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-int UIPEthernet::maintain(void) {
-    tick();
-
-    int rc = DHCP_CHECK_NONE;
-
-#if UIP_UDP
-    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 an error, it will retry though
-                break;
-        }
-    }
-
-    return rc;
-#endif
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-IPAddress UIPEthernet::localIP(void) {
-    uip_ipaddr_t    a;
-
-    uip_gethostaddr(a);
-    return ip_addr_uip(a);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-IPAddress UIPEthernet::subnetMask(void) {
-    uip_ipaddr_t    a;
-
-    uip_getnetmask(a);
-    return ip_addr_uip(a);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-IPAddress UIPEthernet::gatewayIP(void) {
-    uip_ipaddr_t    a;
-
-    uip_getdraddr(a);
-    return ip_addr_uip(a);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-IPAddress UIPEthernet::dnsServerIP(void) {
-    return _dnsServerAddress;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void UIPEthernet::tick(void) {
-    if (in_packet == NOBLOCK) {
-        in_packet = network.receivePacket();
-#ifdef UIPETHERNET_DEBUG
-        if (in_packet != NOBLOCK) {
-            printf("--------------\r\nreceivePacket: %d\r\n", 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; //required for upper_layer_checksum of in_packet!
-#ifdef UIPETHERNET_DEBUG
-                printf("readPacket type IP, uip_len: %d\r\n", 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
-                printf("readPacket type ARP, uip_len: %d\r\n", uip_len);
-#endif
-                uip_arp_arpin();
-                if (uip_len > 0) {
-                    network_send();
-                }
-            }
-        }
-
-        if (in_packet != NOBLOCK && (packetstate & UIPETHERNET_FREEPACKET))
-        {
-#ifdef UIPETHERNET_DEBUG
-            printf("freeing packet: %d\r\n", in_packet);
-#endif
-            network.freePacket();
-            in_packet = NOBLOCK;
-        }
-    }
-
-    unsigned long   now = millis();
-    bool            periodic = (long)(now - periodic_timer) >= 0;
-
-    for (int i = 0; i < UIP_CONNS; i++) {
-        uip_conn = &uip_conns[i];
-        if (periodic) {
-            uip_process(UIP_TIMER);
-        }
-        else {
-            if ((long)(now - ((uip_userdata_t*)uip_conn->appstate)->timer) >= 0)
-                uip_process(UIP_POLL_REQUEST);
-            else
-                continue;
-        }
-
-        // If the above function invocation resulted in data that
-        // should be sent out on the Enc28J60Network, the global variable
-        // uip_len is set to a value > 0.
-        if (uip_len > 0) {
-            uip_arp_out();
-            network_send();
-        }
-    }
-
-    if (periodic) {
-        periodic_timer = now + UIP_PERIODIC_TIMER;
-#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 Enc28J60Network, the global variable
-            // uip_len is set to a value > 0.
-            if (uip_len > 0) {
-                UIPUDP::_send((uip_udp_userdata_t *) (uip_udp_conns[i].appstate));
-            }
-        }
-#endif // UIP_UDP
-    }
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-bool UIPEthernet::network_send(void) {
-    if (packetstate & UIPETHERNET_SENDPACKET)
-    {
-#ifdef UIPETHERNET_DEBUG
-        printf("Enc28J60Network_send uip_packet: %d, hdrlen: %d\r\n", uip_packet, uip_hdrlen);
-#endif
-        uIPEthernet.network.writePacket(uip_packet, 0, uip_buf, uip_hdrlen);
-        packetstate &= ~UIPETHERNET_SENDPACKET;
-        goto sendandfree;
-    }
-
-    uip_packet = Enc28J60Network::allocBlock(uip_len);
-    if (uip_packet != NOBLOCK)
-    {
-#ifdef UIPETHERNET_DEBUG
-        printf("Enc28J60Network_send uip_buf (uip_len): %d, packet: %d\r\n", uip_len, uip_packet);
-#endif
-        uIPEthernet.network.writePacket(uip_packet, 0, uip_buf, uip_len);
-        goto sendandfree;
-    }
-
-    return false;
-sendandfree:
-    network.sendPacket(uip_packet);
-    Enc28J60Network::freeBlock(uip_packet);
-    uip_packet = NOBLOCK;
-    return true;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void UIPEthernet::init(const uint8_t* mac) {
-    periodic_timer = millis() + UIP_PERIODIC_TIMER;
-
-    network.init((uint8_t*)mac);
-    uip_seteth_addr(mac);
-
-    uip_init();
-    uip_arp_init();
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void UIPEthernet::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;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-uint16_t UIPEthernet::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;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-uint16_t UIPEthernet::ipchksum(void) {
-    uint16_t    sum;
-
-    sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN);
-    return(sum == 0) ? 0xffff : htons(sum);
-}
-
-uint16_t
-#if UIP_UDP
-UIPEthernet::upper_layer_chksum(uint8_t proto)
-#else
-uip_tcpchksum (void)
-#endif
-{
-    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. */
-#if UIP_UDP
-    sum = upper_layer_len + proto;
-#else
-    sum = upper_layer_len + UIP_PROTO_TCP;
-#endif
-    /* Sum IP source and destination addresses. */
-
-    sum = UIPEthernet::chksum(sum, (u8_t*) &BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t));
-
-    uint8_t upper_layer_memlen;
-#if UIP_UDP
-    switch (proto) {
-        //    case UIP_PROTO_ICMP:
-        //    case UIP_PROTO_ICMP6:
-        //      upper_layer_memlen = upper_layer_len;
-        //      break;
-        case UIP_PROTO_UDP:
-            upper_layer_memlen = UIP_UDPH_LEN;
-            break;
-
-        default:
-            //  case UIP_PROTO_TCP:
-    #endif
-            upper_layer_memlen = (BUF->tcpoffset >> 4) << 2;
-    #if UIP_UDP
-            break;
-    }
-#endif
-    sum = UIPEthernet::chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_memlen);
-#ifdef UIPETHERNET_DEBUG_CHKSUM
-    printf("chksum uip_buf[%d-%d]: %d\r\n", UIP_IPH_LEN + UIP_LLH_LEN, UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen, htons(sum));
-#endif
-    if (upper_layer_memlen < upper_layer_len) {
-        sum = network.chksum
-            (
-                sum, UIPEthernet::uip_packet, UIP_IPH_LEN +
-                UIP_LLH_LEN +
-                upper_layer_memlen, upper_layer_len -
-                upper_layer_memlen
-            );
-#ifdef UIPETHERNET_DEBUG_CHKSUM
-        printf("chksum uip_packet(%d)[%d-%d]: %d\r\n", uip_packet, UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen, UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_len, htons(sum));
-#endif
-    }
-    return(sum == 0) ? 0xffff : htons(sum);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-uint16_t uip_ipchksum(void) {
-    return uIPEthernet.ipchksum();
-}
-
-#if UIP_UDP
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-uint16_t uip_tcpchksum(void) {
-    uint16_t    sum = uIPEthernet.upper_layer_chksum(UIP_PROTO_TCP);
-
-    return sum;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-uint16_t uip_udpchksum(void) {
-    uint16_t    sum = uIPEthernet.upper_layer_chksum(UIP_PROTO_UDP);
-
-    return sum;
-}
-#endif
-
--- a/UIPEthernet.h	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,127 +0,0 @@
-/*
- UIPEthernet.h - Arduino implementation of a UIP wrapper class.
- Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
- All rights reserved.
-
- Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.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 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 "mbed.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_FREEPACKET  1
-#define UIPETHERNET_SENDPACKET  2
-
-#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   UIPEthernet
-    {
-    public:
-        Enc28J60Network network;
-
-        UIPEthernet(PinName mosi, PinName miso, PinName sck, PinName cs);
-
-        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(void);
-
-        IPAddress   localIP(void);
-        IPAddress   subnetMask(void);
-        IPAddress   gatewayIP(void);
-        IPAddress   dnsServerIP(void);
-    private:
-        static memhandle        in_packet;
-        static memhandle        uip_packet;
-        static uint8_t          uip_hdrlen;
-        static uint8_t          packetstate;
-
-        static IPAddress        _dnsServerAddress;
-        static DhcpClass*       _dhcp;
-
-        static unsigned long    periodic_timer;
-
-        void                    init(const uint8_t* mac);
-        static void             configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet);
-
-        void                    tick(void);
-
-        bool                    network_send(void);
-
-        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);
-#if UIP_UDP
-        uint16_t                upper_layer_chksum(uint8_t proto);
-#endif
-        friend uint16_t         uip_ipchksum(void);
-        friend uint16_t         uip_tcpchksum(void);
-        friend uint16_t         uip_udpchksum(void);
-
-        friend void             uipclient_appcall(void);
-        friend void             uipudp_appcall(void);
-
-#if UIP_CONF_IPV6
-        uint16_t                uip_icmp6chksum(void);
-#endif /* UIP_CONF_IPV6 */
-    };
-
-extern UIPEthernet  uIPEthernet;
-#endif
--- a/UIPServer.cpp	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +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"
-}
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-UIPServer::UIPServer(uint16_t port) :
-    _port(htons(port))
-{ }
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-UIPClient UIPServer::available(void) {
-    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_REMOTECLOSED) && ((uip_userdata_closed_t*)data)->lport == _port)
-            )
-        ) return UIPClient(data);
-    }
-
-    return UIPClient();
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void UIPServer::begin(void) {
-    uip_listen(_port);
-    uIPEthernet.tick();
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-size_t UIPServer::write(uint8_t c) {
-    return write(&c, 1);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-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;
-}
--- a/UIPServer.h	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +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"
-#include "Server.h"
-#include "UIPClient.h"
-
-class UIPServer :
-    public Server
-{
-public:
-    UIPServer(uint16_t);
-    UIPClient   available(void);
-    void        begin(void);
-    size_t      write(uint8_t);
-    size_t      write(const uint8_t* buf, size_t size);
-
-//  using Print::write;
-
-private:
-    uint16_t    _port;
-};
-#endif
--- a/UIPUdp.cpp	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,354 +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"
-
-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(void) :
-    _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(void) {
-    if (_uip_udp_conn) {
-        uip_udp_remove(_uip_udp_conn);
-        _uip_udp_conn->appstate = NULL;
-        _uip_udp_conn = NULL;
-        uIPEthernet.network.freeBlock(appdata.packet_in);
-        uIPEthernet.network.freeBlock(appdata.packet_next);
-        uIPEthernet.network.freeBlock(appdata.packet_out);
-        memset(&appdata, 0, sizeof(appdata));
-    }
-}
-
-// 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
-        printf("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
-                printf("new connection, ");
-#endif
-                _uip_udp_conn->appstate = &appdata;
-            }
-            else
-            {
-#ifdef UIPETHERNET_DEBUG_UDP
-                printf("failed to allocate new connection\r\n");
-#endif
-                return 0;
-            }
-        }
-
-#ifdef UIPETHERNET_DEBUG_UDP
-        printf("rip: %s, port: %d\r\n", ip.asString(), 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
-                printf("failed to allocate memory for packet\r\n");
-#endif
-        }
-
-#ifdef UIPETHERNET_DEBUG_UDP
-        else
-            printf("previous packet on that connection not sent yet\r\n");
-#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(void) {
-    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) {
-            _send(&appdata);
-            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(void) {
-    uIPEthernet.tick();
-#ifdef UIPETHERNET_DEBUG_UDP
-    if (appdata.packet_in != NOBLOCK) {
-        printf("udp parsePacket freeing previous packet: %d\r\n", appdata.packet_in);
-    }
-#endif
-    uIPEthernet.network.freeBlock(appdata.packet_in);
-
-    appdata.packet_in = appdata.packet_next;
-    appdata.packet_next = NOBLOCK;
-
-#ifdef UIPETHERNET_DEBUG_UDP
-    if (appdata.packet_in != NOBLOCK) {
-        printf("udp parsePacket received packet: %d", appdata.packet_in);
-    }
-#endif
-
-    int size = uIPEthernet.network.blockSize(appdata.packet_in);
-#ifdef UIPETHERNET_DEBUG_UDP
-    if (appdata.packet_in != NOBLOCK) {
-        printf(", size: %d\r\n", size);
-    }
-#endif
-    return size;
-}
-
-// Number of bytes remaining in the current packet
-int UIPUDP::available(void) {
-    uIPEthernet.tick();
-    return uIPEthernet.network.blockSize(appdata.packet_in);
-}
-
-// Read a single byte from the current packet
-int UIPUDP::read(void) {
-    static 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) {
-        memaddress  read = uIPEthernet.network.readPacket(appdata.packet_in, 0, buffer, len);
-        if (read == uIPEthernet.network.blockSize(appdata.packet_in)) {
-            uIPEthernet.network.freeBlock(appdata.packet_in);
-            appdata.packet_in = NOBLOCK;
-        }
-        else
-            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(void) {
-    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(void) {
-    uIPEthernet.tick();
-    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(void) {
-    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(void) {
-    return _uip_udp_conn ? ntohs(_uip_udp_conn->rport) : 0;
-}
-
-// UIP callback function
-void uipudp_appcall(void) {
-    if (uip_udp_userdata_t * data = (uip_udp_userdata_t *) (uip_udp_conn->appstate)) {
-        if (uip_newdata()) {
-            if (data->packet_next == NOBLOCK) {
-                uip_udp_conn->rport = UDPBUF->srcport;
-                uip_ipaddr_copy(uip_udp_conn->ripaddr, UDPBUF->srcipaddr);
-                data->packet_next = 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 (data->packet_next != NOBLOCK) {
-
-                    //discard Linklevel and IP and udp-header and any trailing bytes:
-                    uIPEthernet.network.copyPacket
-                        (
-                            data->packet_next,
-                            0,
-                            UIPEthernet::in_packet,
-                            UIP_UDP_PHYH_LEN,
-                            uIPEthernet.network.blockSize(data->packet_next)
-                        );
-#ifdef UIPETHERNET_DEBUG_UDP
-                    printf
-                    (
-                        "udp, uip_newdata received packet: %d, size: %d\r\n",
-                        data->packet_next,
-                        UIPEthernet.network.blockSize(data->packet_next)
-                    );
-#endif
-                }
-            }
-        }
-
-        if (uip_poll() && data->send)
-        {
-            //set uip_slen (uip private) by calling uip_udp_send
-#ifdef UIPETHERNET_DEBUG_UDP
-            printf
-            (
-                "udp, uip_poll preparing packet to send: %d, size: %d\r\n",
-                data->packet_out,
-                UIPEthernet.network.blockSize(data->packet_out)
-            );
-#endif
-            UIPEthernet::uip_packet = data->packet_out;
-            UIPEthernet::uip_hdrlen = UIP_UDP_PHYH_LEN;
-            uip_udp_send(data->out_pos - (UIP_UDP_PHYH_LEN));
-        }
-    }
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void UIPUDP::_send(uip_udp_userdata_t* data) {
-    uip_arp_out();  //add arp
-    if (uip_len == UIP_ARPHDRSIZE) {
-        UIPEthernet::uip_packet = NOBLOCK;
-        UIPEthernet::packetstate &= ~UIPETHERNET_SENDPACKET;
-#ifdef UIPETHERNET_DEBUG_UDP
-        printf("udp, uip_poll results in ARP-packet\r\n");
-#endif
-    }
-    else {
-
-        //arp found ethaddr for ip (otherwise packet is replaced by arp-request)
-        data->send = false;
-        data->packet_out = NOBLOCK;
-        UIPEthernet::packetstate |= UIPETHERNET_SENDPACKET;
-#ifdef UIPETHERNET_DEBUG_UDP
-        printf("udp, uip_packet to send: %d\r\n", UIPEthernet::uip_packet);
-#endif
-    }
-
-    uIPEthernet.network_send();
-}
-#endif
-
--- a/UIPUdp.h	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-/*
- UIPUdp.h - Arduino implementation of a UIP wrapper class.
- Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
- All rights reserved.
-
- Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.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 UIPUDP_H
-#define UIPUDP_H
-
-#include "ethernet_comp.h"
-#include "mbed.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
-
-typedef struct
-{
-    memaddress  out_pos;
-    memhandle   packet_next;
-    memhandle   packet_in;
-    memhandle   packet_out;
-    bool        send;
-} uip_udp_userdata_t;
-
-class UIPUDP :
-    public UDP
-{
-private:
-    struct uip_udp_conn*    _uip_udp_conn;
-
-    uip_udp_userdata_t      appdata;
-public:
-    UIPUDP(void);   // 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(void);         // 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(void);
-
-    // 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(void);
-
-    // Number of bytes remaining in the current packet
-    int         available(void);
-
-    // Read a single byte from the current packet
-    int         read(void);
-
-    // 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);
-    void        flush(void);    // Finish reading the current packet
-
-    // Return the IP address of the host who sent the current incoming packet
-    IPAddress   remoteIP(void);
-
-    // Return the port of the host who sent the current incoming packet
-    uint16_t    remotePort(void);
-private:
-    friend void     uipudp_appcall(void);
-
-    friend class    UIPEthernet;
-    static void     _send(uip_udp_userdata_t* data);
-};
-#endif
--- a/Udp.h	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-/*
- *  Udp.cpp: Library to send/receive UDP packets.
- *
- * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these)
- * 1) UDP does not guarantee the order in which assembled UDP packets are received. This
- * might not happen often in practice, but in larger network topologies, a UDP
- * packet can be received out of sequence. 
- * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being
- * aware of it. Again, this may not be a concern in practice on small local networks.
- * For more information, see http://www.cafeaulait.org/course/week12/35.html
- *
- * MIT License:
- * Copyright (c) 2008 Bjoern Hartmann
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- * 
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * bjoern@cs.stanford.edu 12/30/2008
- */
-#ifndef udp_h
-#define udp_h
-
-#include "mbed.h"
-#include "IPAddress.h"
-
-//class UDP : public Stream {
-class   UDP
-{
-public:
-    virtual uint8_t     begin(uint16_t) = 0;    // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
-    virtual void        stop(void) = 0;         // Finish with the UDP socket
-
-    // Sending UDP packets
-    // Start building up a packet to send to the remote host specific in ip and port
-    // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
-    virtual int         beginPacket(IPAddress ip, uint16_t port) = 0;
-
-    // Start building up a packet to send to the remote host specific in host and port
-    // Returns 1 if successful, 0 if there was a problem resolving the hostname or port
-    virtual int         beginPacket(const char* host, uint16_t port) = 0;
-
-    // Finish off this packet and send it
-    // Returns 1 if the packet was sent successfully, 0 if there was an error
-    virtual int         endPacket(void) = 0;
-
-    // Write a single byte into the packet
-    virtual size_t      write(uint8_t) = 0;
-
-    // Write size bytes from buffer into the packet
-    virtual size_t      write(const uint8_t* buffer, size_t size) = 0;
-
-    // Start processing the next available incoming packet
-    // Returns the size of the packet in bytes, or 0 if no packets are available
-    virtual int         parsePacket(void) = 0;
-
-    // Number of bytes remaining in the current packet
-    virtual int         available(void) = 0;
-
-    // Read a single byte from the current packet
-    virtual int         read(void) = 0;
-
-    // Read up to len bytes from the current packet and place them into buffer
-    // Returns the number of bytes read, or 0 if none are available
-    virtual int         read(unsigned char* buffer, size_t len) = 0;
-
-    // Read up to len characters from the current packet and place them into buffer
-    // Returns the number of characters read, or 0 if none are available
-    virtual int         read(char* buffer, size_t len) = 0;
-
-    // Return the next byte from the current packet without moving on to the next byte
-    virtual int         peek(void) = 0;
-    virtual void        flush(void) = 0;        // Finish reading the current packet
-
-    // Return the IP address of the host who sent the current incoming packet
-    virtual IPAddress   remoteIP(void) = 0;
-
-    // Return the port of the host who sent the current incoming packet
-    virtual uint16_t    remotePort(void) = 0;
-protected:
-    uint8_t*    rawIPAddress(IPAddress& addr)   { return addr.raw_address(); };
-};
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UdpSocket.cpp	Tue Aug 27 15:01:10 2019 +0000
@@ -0,0 +1,374 @@
+/*
+ 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 "UdpSocket.h"
+#include "DnsClient.h"
+
+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
+UdpSocket::UdpSocket() :
+    _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 UdpSocket::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 UdpSocket::stop()
+{
+    if (_uip_udp_conn) {
+        uip_udp_remove(_uip_udp_conn);
+        _uip_udp_conn->appstate = NULL;
+        _uip_udp_conn = NULL;
+        UipEthernet::ethernet->phy.freeBlock(appdata.packet_in);
+        UipEthernet::ethernet->phy.freeBlock(appdata.packet_next);
+        UipEthernet::ethernet->phy.freeBlock(appdata.packet_out);
+        memset(&appdata, 0, sizeof(appdata));
+    }
+}
+
+// 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 UdpSocket::beginPacket(IpAddress ip, uint16_t port)
+{
+    UipEthernet::ethernet->tick();
+    if (ip && port) {
+        uip_ipaddr_t    ripaddr;
+        uip_ip_addr(&ripaddr, ip);
+#ifdef UIPETHERNET_DEBUG_UDP
+        printf("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
+                printf("new connection, ");
+#endif
+                _uip_udp_conn->appstate = &appdata;
+            }
+            else
+            {
+#ifdef UIPETHERNET_DEBUG_UDP
+                printf("failed to allocate new connection\r\n");
+#endif
+                return 0;
+            }
+        }
+
+#ifdef UIPETHERNET_DEBUG_UDP
+        printf("rip: %s, port: %d\r\n", ip.asString(), port);
+#endif
+    }
+
+    if (_uip_udp_conn) {
+        if (appdata.packet_out == NOBLOCK) {
+            appdata.packet_out = UipEthernet::ethernet->phy.allocBlock(UIP_UDP_MAXPACKETSIZE);
+            appdata.out_pos = UIP_UDP_PHYH_LEN;
+            if (appdata.packet_out != NOBLOCK)
+                return 1;
+#ifdef UIPETHERNET_DEBUG_UDP
+            else
+                printf("failed to allocate memory for packet\r\n");
+#endif
+        }
+
+#ifdef UIPETHERNET_DEBUG_UDP
+        else
+            printf("previous packet on that connection not sent yet\r\n");
+#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 UdpSocket::beginPacket(const char* host, uint16_t port)
+{
+    // Look up the host first
+    int         ret = 0;
+    DnsClient   dns;
+    IpAddress   remote_addr;
+
+    dns.begin(UipEthernet::ethernet->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 UdpSocket::endPacket()
+{
+    if (_uip_udp_conn && appdata.packet_out != NOBLOCK) {
+        appdata.send = true;
+        UipEthernet::ethernet->phy.resizeBlock(appdata.packet_out, 0, appdata.out_pos);
+        uip_udp_periodic_conn(_uip_udp_conn);
+        if (uip_len > 0) {
+            _send(&appdata);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+// Write a single byte into the packet
+size_t UdpSocket::write(uint8_t c)
+{
+    return write(&c, 1);
+}
+
+// Write size bytes from buffer into the packet
+size_t UdpSocket::write(const uint8_t* buffer, size_t size)
+{
+    if (appdata.packet_out != NOBLOCK) {
+        size_t  ret = UipEthernet::ethernet->phy.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 UdpSocket::parsePacket()
+{
+    UipEthernet::ethernet->tick();
+#ifdef UIPETHERNET_DEBUG_UDP
+    if (appdata.packet_in != NOBLOCK) {
+        printf("udp parsePacket freeing previous packet: %d\r\n", appdata.packet_in);
+    }
+#endif
+    UipEthernet::ethernet->phy.freeBlock(appdata.packet_in);
+
+    appdata.packet_in = appdata.packet_next;
+    appdata.packet_next = NOBLOCK;
+
+#ifdef UIPETHERNET_DEBUG_UDP
+    if (appdata.packet_in != NOBLOCK) {
+        printf("udp parsePacket received packet: %d", appdata.packet_in);
+    }
+#endif
+
+    int size = UipEthernet::ethernet->phy.blockSize(appdata.packet_in);
+#ifdef UIPETHERNET_DEBUG_UDP
+    if (appdata.packet_in != NOBLOCK) {
+        printf(", size: %d\r\n", size);
+    }
+#endif
+    return size;
+}
+
+// Number of bytes remaining in the current packet
+int UdpSocket::available()
+{
+    UipEthernet::ethernet->tick();
+    return UipEthernet::ethernet->phy.blockSize(appdata.packet_in);
+}
+
+// Read a single byte from the current packet
+int UdpSocket::read()
+{
+    static 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 UdpSocket::read(unsigned char* buffer, size_t len)
+{
+    UipEthernet::ethernet->tick();
+    if (appdata.packet_in != NOBLOCK) {
+        memaddress  read = UipEthernet::ethernet->phy.readPacket(appdata.packet_in, 0, buffer, len);
+        if (read == UipEthernet::ethernet->phy.blockSize(appdata.packet_in)) {
+            UipEthernet::ethernet->phy.freeBlock(appdata.packet_in);
+            appdata.packet_in = NOBLOCK;
+        }
+        else
+            UipEthernet::ethernet->phy.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 UdpSocket::peek()
+{
+    UipEthernet::ethernet->tick();
+    if (appdata.packet_in != NOBLOCK) {
+        unsigned char   c;
+        if (UipEthernet::ethernet->phy.readPacket(appdata.packet_in, 0, &c, 1) == 1)
+            return c;
+    }
+
+    return -1;
+}
+
+// Finish reading the current packet
+void UdpSocket::flush()
+{
+    UipEthernet::ethernet->tick();
+    UipEthernet::ethernet->phy.freeBlock(appdata.packet_in);
+    appdata.packet_in = NOBLOCK;
+}
+
+// Return the IP address of the host who sent the current incoming packet
+IpAddress UdpSocket::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 UdpSocket::remotePort()
+{
+    return _uip_udp_conn ? ntohs(_uip_udp_conn->rport) : 0;
+}
+
+// UIP callback function
+void uipudp_appcall()
+{
+    if (uip_udp_userdata_t * data = (uip_udp_userdata_t *) (uip_udp_conn->appstate)) {
+        if (uip_newdata()) {
+            if (data->packet_next == NOBLOCK) {
+                uip_udp_conn->rport = UDPBUF->srcport;
+                uip_ipaddr_copy(uip_udp_conn->ripaddr, UDPBUF->srcipaddr);
+                data->packet_next = UipEthernet::ethernet->phy.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 (data->packet_next != NOBLOCK) {
+                    //discard Linklevel and IP and udp-header and any trailing bytes:
+                    UipEthernet::ethernet->phy.copyPacket
+                        (
+                            data->packet_next,
+                            0,
+                            UipEthernet::inPacket,
+                            UIP_UDP_PHYH_LEN,
+                            UipEthernet::ethernet->phy.blockSize(data->packet_next)
+                        );
+#ifdef UIPETHERNET_DEBUG_UDP
+                    printf
+                    (
+                        "udp, uip_newdata received packet: %d, size: %d\r\n",
+                        data->packet_next,
+                        UIPEthernet.network.blockSize(data->packet_next)
+                    );
+#endif
+                }
+            }
+        }
+
+        if (uip_poll() && data->send)
+        {
+            //set uip_slen (uip private) by calling uip_udp_send
+#ifdef UIPETHERNET_DEBUG_UDP
+            printf
+            (
+                "udp, uip_poll preparing packet to send: %d, size: %d\r\n",
+                data->packet_out,
+                UIPEthernet.network.blockSize(data->packet_out)
+            );
+#endif
+            UipEthernet::uipPacket = data->packet_out;
+            UipEthernet::uipHeaderLen = UIP_UDP_PHYH_LEN;
+            uip_udp_send(data->out_pos - (UIP_UDP_PHYH_LEN));
+        }
+    }
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UdpSocket::_send(uip_udp_userdata_t* data)
+{
+    uip_arp_out();  //add arp
+    if (uip_len == UIP_ARPHDRSIZE) {
+        UipEthernet::uipPacket = NOBLOCK;
+        UipEthernet::packetState &= ~UIPETHERNET_SENDPACKET;
+#ifdef UIPETHERNET_DEBUG_UDP
+        printf("udp, uip_poll results in ARP-packet\r\n");
+#endif
+    }
+    else {
+        //arp found ethaddr for ip (otherwise packet is replaced by arp-request)
+        data->send = false;
+        data->packet_out = NOBLOCK;
+        UipEthernet::packetState |= UIPETHERNET_SENDPACKET;
+#ifdef UIPETHERNET_DEBUG_UDP
+        printf("udp, uip_packet to send: %d\r\n", UIPEthernet::uip_packet);
+#endif
+    }
+
+    UipEthernet::ethernet->network_send();
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UdpSocket.h	Tue Aug 27 15:01:10 2019 +0000
@@ -0,0 +1,108 @@
+/*
+ UIPUdp.h - Arduino implementation of a UIP wrapper class.
+ Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
+ All rights reserved.
+
+ Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.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 UIPUDP_H
+#define UIPUDP_H
+
+#include "mbed.h"
+#include "utility/Udp.h"
+#include "IpAddress.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
+
+typedef struct
+{
+    memaddress  out_pos;
+    memhandle   packet_next;
+    memhandle   packet_in;
+    memhandle   packet_out;
+    bool        send;
+} uip_udp_userdata_t;
+
+class UdpSocket :  public Udp
+{
+private:
+    struct uip_udp_conn*    _uip_udp_conn;
+    uip_udp_userdata_t      appdata;
+public:
+    UdpSocket();                    // Constructor
+    virtual     ~UdpSocket()    { } // Virtual destructor
+    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();
+
+    friend class    UipEthernet;
+    static void     _send(uip_udp_userdata_t* data);
+};
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UipEthernet.cpp	Tue Aug 27 15:01:10 2019 +0000
@@ -0,0 +1,661 @@
+/*
+ UIPEthernet.cpp - Arduino implementation of a UIP wrapper class.
+ Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
+ All rights reserved.
+
+ Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.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/>.
+  */
+#include "mbed.h"
+#include "UipEthernet.h"
+#include "utility/Enc28j60Py.h"
+#include "UdpSocket.h"
+
+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])
+
+UipEthernet* UipEthernet::  ethernet = NULL;
+memhandle UipEthernet::     inPacket(NOBLOCK);
+memhandle UipEthernet::     uipPacket(NOBLOCK);
+uint8_t UipEthernet::       uipHeaderLen(0);
+uint8_t UipEthernet::       packetState(0);
+IpAddress UipEthernet::     dnsServerAddress;
+//DhcpClient UIPEthernet::    dhcpClient;
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void enc28j60_mempool_block_move_callback(memaddress dest, memaddress src, memaddress len)
+{
+    //as ENC28J60 DMA is unable to copy single bytes:
+    if (len == 1) {
+        UipEthernet::ethernet->phy.writeByte(dest, UipEthernet::ethernet->phy.readByte(src));
+    }
+    else {
+        // calculate address of last byte
+        len += src - 1;
+
+        /* 1. Appropriately program the EDMAST, EDMAND
+              and EDMADST register pairs. The EDMAST
+              registers should point to the first byte to copy
+              from, the EDMAND registers should point to the
+              last byte to copy and the EDMADST registers
+              should point to the first byte in the destination
+              range. The destination range will always be
+              linear, never wrapping at any values except from
+              8191 to 0 (the 8-Kbyte memory boundary).
+              Extreme care should be taken when
+              programming the start and end pointers to
+              prevent a never ending DMA operation which
+              would overwrite the entire 8-Kbyte buffer.
+       */
+        UipEthernet::ethernet->phy.writeRegPair(EDMASTL, src);
+        UipEthernet::ethernet->phy.writeRegPair(EDMADSTL, dest);
+
+        if ((src <= RXSTOP_INIT) && (len > RXSTOP_INIT))
+            len -= (RXSTOP_INIT - RXSTART_INIT);
+        UipEthernet::ethernet->phy.writeRegPair(EDMANDL, len);
+
+        /* 2. If an interrupt at the end of the copy process is
+              desired, set EIE.DMAIE and EIE.INTIE and
+              clear EIR.DMAIF.
+
+           3. Verify that ECON1.CSUMEN is clear. */
+        UipEthernet::ethernet->phy.writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_CSUMEN);
+
+        /* 4. Start the DMA copy by setting ECON1.DMAST. */
+        UipEthernet::ethernet->phy.writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST);
+
+        //    wait until runnig DMA is completed
+        while (UipEthernet::ethernet->phy.readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST);
+    }
+}
+
+/*
+ * 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.
+ */
+UipEthernet::UipEthernet(const uint8_t mac[6], PinName mosi, PinName miso, PinName sck, PinName cs) :
+    phy(mosi, miso, sck, cs),
+    _mac(new uint8_t[6]),
+    _ip(),
+    _dns(),
+    _gateway(),
+    _subnet()
+{
+    for (uint8_t i = 0; i < 6; i++)
+        _mac[i] = mac[i];
+}
+
+#if UIP_UDP
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int UipEthernet::connect()
+{
+    // Inicialize static pointer to the UIPEthernet instance
+    ethernet = this;
+
+    // Initialise the basic info
+    init(_mac);
+
+    // If no local IP address has been set ask DHCP server to provide one
+    if (_ip == IpAddress()) {
+        // Now try to get our config info from a DHCP server
+        int ret = dhcpClient.begin((uint8_t*)_mac);
+
+        if (ret == 1) {
+            // We've successfully found a DHCP server and got our configuration info, so set things
+            // accordingly
+            set_network
+            (
+                dhcpClient.getLocalIp(),
+                dhcpClient.getDnsServerIp(),
+                dhcpClient.getGatewayIp(),
+                dhcpClient.getSubnetMask()
+            );
+        }
+
+        return ret;
+    }
+    else {
+        return 1;
+    }
+}
+#endif
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UipEthernet::set_network(uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4)
+{
+    _ip = IpAddress(octet1, octet2, octet3, octet4);
+    set_network(_ip);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UipEthernet::set_network(IpAddress ip)
+{
+    _ip = ip;
+    _dns = ip;
+    _dns[3] = 1;
+    set_network(ip, dns);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UipEthernet::set_network(IpAddress ip, IpAddress dns)
+{
+    _ip = ip;
+    _dns = dns;
+    _gateway = ip;
+    _gateway[3] = 1;
+    set_network(ip, dns, _gateway);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UipEthernet::set_network(IpAddress ip, IpAddress dns, IpAddress gateway)
+{
+    _ip = ip;
+    _dns = dns;
+    _gateway = gateway;
+    _subnet = IpAddress(255, 255, 255, 0);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UipEthernet::set_network(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;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+IpAddress UipEthernet::localIP()
+{
+    uip_ipaddr_t    a;
+
+    uip_gethostaddr(a);
+    return ip_addr_uip(a);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+IpAddress UipEthernet::subnetMask()
+{
+    uip_ipaddr_t    a;
+
+    uip_getnetmask(a);
+    return ip_addr_uip(a);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+IpAddress UipEthernet::gatewayIP()
+{
+    uip_ipaddr_t    a;
+
+    uip_getdraddr(a);
+    return ip_addr_uip(a);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+IpAddress UipEthernet::dnsServerIP()
+{
+    return dnsServerAddress;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+const char* UipEthernet::get_ip_address()
+{
+    static char buf[16];
+    return localIP().toString(buf);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+const char* UipEthernet::get_netmask()
+{
+    static char buf[16];
+    return subnetMask().toString(buf);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+const char* UipEthernet::get_gateway()
+{
+    static char buf[16];
+    return gatewayIP().toString(buf);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UipEthernet::tick()
+{
+    if (inPacket == NOBLOCK) {
+        inPacket = phy.receivePacket();
+#ifdef UIPETHERNET_DEBUG
+        if (in_packet != NOBLOCK) {
+            printf("--------------\r\nreceivePacket: %d\r\n", in_packet);
+        }
+#endif
+    }
+
+    if (inPacket != NOBLOCK) {
+        packetState = UIPETHERNET_FREEPACKET;
+        uip_len = phy.blockSize(inPacket);
+        if (uip_len > 0) {
+            phy.readPacket(inPacket, 0, (uint8_t*)uip_buf, UIP_BUFSIZE);
+            if (ETH_HDR->type == HTONS(UIP_ETHTYPE_IP)) {
+                uipPacket = inPacket;   //required for upper_layer_checksum of in_packet!
+#ifdef UIPETHERNET_DEBUG
+                printf("readPacket type IP, uip_len: %d\r\n", 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
+                printf("readPacket type ARP, uip_len: %d\r\n", uip_len);
+#endif
+                uip_arp_arpin();
+                if (uip_len > 0) {
+                    network_send();
+                }
+            }
+        }
+
+        if (inPacket != NOBLOCK && (packetState & UIPETHERNET_FREEPACKET))
+        {
+#ifdef UIPETHERNET_DEBUG
+            printf("freeing packet: %d\r\n", in_packet);
+#endif
+            phy.freePacket();
+            inPacket = NOBLOCK;
+        }
+    }
+
+    bool    periodic = periodicTimer.read_ms() > UIP_PERIODIC_TIMEOUT;
+
+    for (int i = 0; i < UIP_CONNS; i++) {
+        uip_conn = &uip_conns[i];
+        if (periodic) {
+            uip_process(UIP_TIMER);
+        }
+        else {
+            uip_userdata_t*     data = (uip_userdata_t*)uip_conn->appstate;
+            if (data != NULL) {
+                if (data->pollTimer.read_ms() >= UIP_CLIENT_TIMEOUT) {
+                    uip_process(UIP_POLL_REQUEST);
+                    data->pollTimer.stop();
+                    data->pollTimer.reset();
+                }
+            }
+            else
+                continue;
+        }
+
+        // If the above function invocation resulted in data that
+        // should be sent out on the Enc28J60Network, the global variable
+        // uip_len is set to a value > 0.
+        if (uip_len > 0) {
+            uip_arp_out();
+            network_send();
+        }
+    }
+
+    if (periodic) {
+        periodicTimer.reset();
+#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 Enc28J60Network, the global variable
+            // uip_len is set to a value > 0.
+            if (uip_len > 0) {
+                UdpSocket::_send((uip_udp_userdata_t *) (uip_udp_conns[i].appstate));
+            }
+        }
+#endif // UIP_UDP
+    }
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+bool UipEthernet::network_send()
+{
+    if (packetState & UIPETHERNET_SENDPACKET)
+    {
+#ifdef UIPETHERNET_DEBUG
+        printf("Enc28J60Network_send uip_packet: %d, hdrlen: %d\r\n", uip_packet, uip_hdrlen);
+#endif
+        phy.writePacket(uipPacket, 0, uip_buf, uipHeaderLen);
+        packetState &= ~UIPETHERNET_SENDPACKET;
+        goto sendandfree;
+    }
+
+    uipPacket = Enc28j60Phy::allocBlock(uip_len);
+    if (uipPacket != NOBLOCK)
+    {
+#ifdef UIPETHERNET_DEBUG
+        printf("Enc28J60Network_send uip_buf (uip_len): %d, packet: %d\r\n", uip_len, uip_packet);
+#endif
+        phy.writePacket(uipPacket, 0, uip_buf, uip_len);
+        goto sendandfree;
+    }
+
+    return false;
+sendandfree:
+    phy.sendPacket(uipPacket);
+    Enc28j60Phy::freeBlock(uipPacket);
+    uipPacket = NOBLOCK;
+    return true;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UipEthernet::init(const uint8_t* mac)
+{
+    periodicTimer.start();
+
+    phy.init((uint8_t*)mac);
+    uip_seteth_addr(mac);
+
+    uip_init();
+    uip_arp_init();
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+//void UIPEthernet::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;
+//}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint16_t UipEthernet::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;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint16_t UipEthernet::ipchksum()
+{
+    uint16_t    sum;
+
+    sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN);
+    return(sum == 0) ? 0xffff : htons(sum);
+}
+
+uint16_t
+#if UIP_UDP
+UipEthernet::upper_layer_chksum(uint8_t proto)
+#else
+uip_tcpchksum()
+#endif
+{
+    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. */
+#if UIP_UDP
+    sum = upper_layer_len + proto;
+#else
+    sum = upper_layer_len + UIP_PROTO_TCP;
+#endif
+    /* Sum IP source and destination addresses. */
+
+    sum = UipEthernet::chksum(sum, (u8_t*) &BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t));
+
+    uint8_t upper_layer_memlen;
+#if UIP_UDP
+    switch (proto) {
+        //    case UIP_PROTO_ICMP:
+        //    case UIP_PROTO_ICMP6:
+        //      upper_layer_memlen = upper_layer_len;
+        //      break;
+        case UIP_PROTO_UDP:
+            upper_layer_memlen = UIP_UDPH_LEN;
+            break;
+
+        default:
+            //  case UIP_PROTO_TCP:
+    #endif
+            upper_layer_memlen = (BUF->tcpoffset >> 4) << 2;
+    #if UIP_UDP
+            break;
+    }
+#endif
+    sum = UipEthernet::chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_memlen);
+#ifdef UIPETHERNET_DEBUG_CHKSUM
+    printf
+        (
+            "chksum uip_buf[%d-%d]: %d\r\n", UIP_IPH_LEN +
+            UIP_LLH_LEN, UIP_IPH_LEN +
+            UIP_LLH_LEN +
+            upper_layer_memlen, htons(sum)
+        );
+#endif
+    if (upper_layer_memlen < upper_layer_len) {
+        sum = phy.chksum
+            (
+                sum, UipEthernet::uipPacket, UIP_IPH_LEN +
+                UIP_LLH_LEN +
+                upper_layer_memlen, upper_layer_len -
+                upper_layer_memlen
+            );
+#ifdef UIPETHERNET_DEBUG_CHKSUM
+        printf
+            (
+                "chksum uip_packet(%d)[%d-%d]: %d\r\n", uip_packet, UIP_IPH_LEN +
+                UIP_LLH_LEN +
+                upper_layer_memlen, UIP_IPH_LEN +
+                UIP_LLH_LEN +
+                upper_layer_len, htons(sum)
+            );
+#endif
+    }
+    return(sum == 0) ? 0xffff : htons(sum);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint16_t uip_ipchksum()
+{
+    return UipEthernet::ethernet->ipchksum();
+}
+
+#if UIP_UDP
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint16_t uip_tcpchksum()
+{
+    uint16_t    sum = UipEthernet::ethernet->upper_layer_chksum(UIP_PROTO_TCP);
+
+    return sum;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint16_t uip_udpchksum()
+{
+    uint16_t    sum = UipEthernet::ethernet->upper_layer_chksum(UIP_PROTO_UDP);
+
+    return sum;
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UipEthernet.h	Tue Aug 27 15:01:10 2019 +0000
@@ -0,0 +1,117 @@
+/*
+ UipEthernet.h - Arduino implementation of a UIP wrapper class.
+ Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
+ All rights reserved.
+
+ Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.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 UIPETHERNET_H
+#define UIPETHERNET_H
+
+//#define UIPETHERNET_DEBUG
+//#define UIPETHERNET_DEBUG_CHKSUM
+//#define UIPETHERNET_DEBUG_UDP
+//#define UIPETHERNET_DEBUG_CLIENT
+#include "mbed.h"
+#include "DhcpClient.h"
+#include "IpAddress.h"
+#include "utility/Enc28j60Py.h"
+#include "TcpClient.h"
+#include "TcpServer.h"
+#include "UdpSocket.h"
+
+extern "C"
+{
+#include "utility/uip_timer.h"
+#include "utility/uip.h"
+}
+#define UIPETHERNET_FREEPACKET  1
+#define UIPETHERNET_SENDPACKET  2
+
+#define uip_ip_addr(addr, ip) \
+    do { \
+        ((u16_t *) (addr))[0] = (((ip[1]) << 8) | (ip[0])); \
+        ((u16_t *) (addr))[1] = (((ip[3]) << 8) | (ip[2])); \
+    } 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 UipEthernet
+{
+public:
+    static UipEthernet* ethernet;
+    static IpAddress    dnsServerAddress;
+    Enc28j60Phy         phy;
+
+    UipEthernet (const uint8_t mac[6], PinName mosi, PinName miso, PinName sck, PinName cs);
+
+    int               connect();
+    void              set_network(uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4);
+    void              set_network(IpAddress ip);
+    void              set_network(IpAddress ip, IpAddress dns);
+    void              set_network(IpAddress ip, IpAddress dns, IpAddress gateway);
+    void              set_network(IpAddress ip, IpAddress dns, IpAddress gateway, IpAddress subnet);
+    void              tick();
+    IpAddress         localIP();
+    IpAddress         subnetMask();
+    IpAddress         gatewayIP();
+    IpAddress         dnsServerIP();
+    const char*       get_ip_address();
+    const char*       get_netmask();
+    const char*       get_gateway();
+    static uint16_t   chksum(uint16_t sum, const uint8_t* data, uint16_t len);
+    static uint16_t   ipchksum();
+private:
+    uint8_t *const    _mac;
+    IpAddress         _ip;
+    IpAddress         _dns;
+    IpAddress         _gateway;
+    IpAddress         _subnet;
+    static memhandle  inPacket;
+    static memhandle  uipPacket;
+    static uint8_t    uipHeaderLen;
+    static uint8_t    packetState;
+    DhcpClient        dhcpClient;
+    Timer             periodicTimer;
+    void              init(const uint8_t* mac);
+    bool              network_send();
+    friend class      TcpServer;
+    friend class      TcpClient;
+    friend class      UdpSocket;
+#if UIP_UDP
+    uint16_t          upper_layer_chksum(uint8_t proto);
+#endif
+    friend uint16_t   uip_ipchksum();
+    friend uint16_t   uip_tcpchksum();
+    friend uint16_t   uip_udpchksum();
+    friend void       uipclient_appcall();
+    friend void       uipudp_appcall();
+
+#if UIP_CONF_IPV6
+    uint16_t          uip_icmp6chksum();
+#endif
+};
+#endif
--- a/ethernet_comp.h	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-#ifndef ETHERNET_COMP_H
-#define ETHERNET_COMP_H
-
-//#define Ethernet UIPEthernet
-#define EthernetClient  UIPClient
-#define EthernetServer  UIPServer
-#define EthernetUDP     UIPUDP
-#endif
--- a/utility/Client.h	Fri Jun 30 19:51:28 2017 +0000
+++ b/utility/Client.h	Tue Aug 27 15:01:10 2019 +0000
@@ -20,12 +20,13 @@
 */
 #ifndef client_h
 #define client_h
-#include "IPAddress.h"
+#include "IpAddress.h"
+#include <stddef.h>
 
 class   Client
 {
 public:
-    virtual int         connect(IPAddress ip, uint16_t port) = 0;
+    virtual int         connect(IpAddress ip, uint16_t port) = 0;
     virtual int         connect(const char* host, uint16_t port) = 0;
     virtual size_t      write(uint8_t) = 0;
     virtual size_t      write(const uint8_t* buf, size_t size) = 0;
@@ -38,6 +39,6 @@
     virtual uint8_t     connected(void) = 0;
     virtual operator    bool(void) = 0;
 protected:
-    uint8_t*    rawIPAddress(IPAddress& addr)   { return addr.raw_address(); };
+    uint8_t*    rawIPAddress(IpAddress& addr)   { return addr.rawAddress(); };
 };
 #endif
--- a/utility/Enc28J60Network.cpp	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,722 +0,0 @@
-/*
- Enc28J60Network.cpp
- UIPEthernet network driver for Microchip ENC28J60 Ethernet Interface.
-
- Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
- All rights reserved.
-
- based on enc28j60.c file from the AVRlib library by Pascal Stang.
- For AVRlib See http://www.procyonengineering.com/
-
- Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.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/>.
- */
-#include "Enc28J60Network.h"
-#include "mbed.h"
-
-extern "C"
-{
-#include "enc28j60.h"
-#include "uip.h"
-} 
-
-uint16_t        Enc28J60Network::nextPacketPtr;
-uint8_t         Enc28J60Network::bank = 0xff;
-struct memblock Enc28J60Network::receivePkt;
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-Enc28J60Network::Enc28J60Network(PinName mosi, PinName miso, PinName sclk, PinName cs) :
-    MemoryPool(),
-    _spi(mosi, miso, sclk),
-    _cs(cs)
-{ }
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void Enc28J60Network::init(uint8_t* macaddr) {
-    MemoryPool::init();         // 1 byte in between RX_STOP_INIT and pool to allow prepending of controlbyte
-
-    // initialize SPI interface
-    _spi.format(8, 0);          // 8bit, mode 0
-    _spi.frequency(7000000);    // 7MHz
-    wait_ms(1000);  // 1 second for stable state
-
-    // initialize I/O
-    _cs = 1;        // ss=0
-
-    // perform system reset
-    writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
-    wait_ms(50);
-
-    // check CLKRDY bit to see if reset is complete
-    // The CLKRDY does not work. See Rev. B4 Silicon Errata point. Just wait.
-    //while(!(readReg(ESTAT) & ESTAT_CLKRDY));
-    // do bank 0 stuff
-    // initialize receive buffer
-    // 16-bit transfers, must write low byte first
-    // set receive buffer start address
-    nextPacketPtr = RXSTART_INIT;
-
-    // Rx start
-    writeRegPair(ERXSTL, RXSTART_INIT);
-
-    // set receive pointer address
-    writeRegPair(ERXRDPTL, RXSTART_INIT);
-
-    // RX end
-    writeRegPair(ERXNDL, RXSTOP_INIT);
-
-    // TX start
-    //writeRegPair(ETXSTL, TXSTART_INIT);
-    // TX end
-    //writeRegPair(ETXNDL, TXSTOP_INIT);
-    // do bank 1 stuff, packet filter:
-    // For broadcast packets we allow only ARP packtets
-    // All other packets should be unicast only for our mac (MAADR)
-    //
-    // The pattern to match on is therefore
-    // Type     ETH.DST
-    // ARP      BROADCAST
-    // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9
-    // in binary these poitions are:11 0000 0011 1111
-    // This is hex 303F->EPMM0=0x3f,EPMM1=0x30
-    //TODO define specific pattern to receive dhcp-broadcast packages instead of setting ERFCON_BCEN!
-    writeReg(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_PMEN | ERXFCON_BCEN);
-    writeRegPair(EPMM0, 0x303f);
-    writeRegPair(EPMCSL, 0xf7f9);
-
-    //
-    //
-    // do bank 2 stuff
-    // enable MAC receive
-    // and bring MAC out of reset (writes 0x00 to MACON2)
-    writeRegPair(MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS);
-
-    // enable automatic padding to 60bytes and CRC operations
-    writeOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN);
-
-    // set inter-frame gap (non-back-to-back)
-    writeRegPair(MAIPGL, 0x0C12);
-
-    // set inter-frame gap (back-to-back)
-    writeReg(MABBIPG, 0x12);
-
-    // Set the maximum packet size which the controller will accept
-    // Do not send packets longer than MAX_FRAMELEN:
-    writeRegPair(MAMXFLL, MAX_FRAMELEN);
-
-    // do bank 3 stuff
-    // write MAC address
-    // NOTE: MAC address in ENC28J60 is byte-backward
-    writeReg(MAADR5, macaddr[0]);
-    writeReg(MAADR4, macaddr[1]);
-    writeReg(MAADR3, macaddr[2]);
-    writeReg(MAADR2, macaddr[3]);
-    writeReg(MAADR1, macaddr[4]);
-    writeReg(MAADR0, macaddr[5]);
-
-    // no loopback of transmitted frames
-    phyWrite(PHCON2, PHCON2_HDLDIS);
-
-    // switch to bank 0
-    setBank(ECON1);
-
-    // enable interrutps
-    writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE | EIE_PKTIE);
-
-    // enable packet reception
-    writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
-
-    clkout(2);      // change clkout from 6.25MHz to 12.5MHz
-    wait_us(60);    // 60us
-
-    //Configure leds
-    phyWrite(PHLCON, 0x476);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-memhandle Enc28J60Network::receivePacket(void) {
-    uint8_t     rxstat;
-    uint16_t    len;
-    // check if a packet has been received and buffered
-
-    //if( !(readReg(EIR) & EIR_PKTIF) ){
-    // The above does not work. See Rev. B4 Silicon Errata point 6.
-    if (readReg(EPKTCNT) != 0) {
-        uint16_t    readPtr = nextPacketPtr +
-            6 > RXSTOP_INIT ? nextPacketPtr +
-            6 -
-            RXSTOP_INIT +
-            RXSTART_INIT : nextPacketPtr +
-            6;
-        // Set the read pointer to the start of the received packet
-
-        writeRegPair(ERDPTL, nextPacketPtr);
-
-        // read the next packet pointer
-        nextPacketPtr = readOp(ENC28J60_READ_BUF_MEM, 0);
-        nextPacketPtr |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8;
-
-        // read the packet length (see datasheet page 43)
-        len = readOp(ENC28J60_READ_BUF_MEM, 0);
-        len |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8;
-        len -= 4;   //remove the CRC count
-
-        // read the receive status (see datasheet page 43)
-        rxstat = readOp(ENC28J60_READ_BUF_MEM, 0);
-
-        //rxstat |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8;
-#ifdef ENC28J60DEBUG
-        printf
-        (
-            "receivePacket [%d-%d], next: %d, stat: %d, count: %d -> ",
-            readPtr,
-            (readPtr + len) % (RXSTOP_INIT + 1),
-            nextPacketPtr,
-            rxstat,
-            readReg(EPKTCNT)
-        );
-        (rxstat & 0x80) != 0 ? printf("OK") : printf("failed");
-        printf("\r\n");
-#endif
-        // decrement the packet counter indicate we are done with this packet
-
-        writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
-
-        // check CRC and symbol errors (see datasheet page 44, table 7-3):
-        // The ERXFCON.CRCEN is set by default. Normally we should not
-        // need to check this.
-        if ((rxstat & 0x80) != 0) {
-            receivePkt.begin = readPtr;
-            receivePkt.size = len;
-            return UIP_RECEIVEBUFFERHANDLE;
-        }
-
-        // Move the RX read pointer to the start of the next received packet
-        // This frees the memory we just read out
-        setERXRDPT();
-    }
-
-    return(NOBLOCK);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void Enc28J60Network::setERXRDPT(void) {
-    writeRegPair(ERXRDPTL, nextPacketPtr == RXSTART_INIT ? RXSTOP_INIT : nextPacketPtr - 1);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-memaddress Enc28J60Network::blockSize(memhandle handle) {
-    return handle == NOBLOCK ? 0 : handle == UIP_RECEIVEBUFFERHANDLE ? receivePkt.size : blocks[handle].size;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void Enc28J60Network::sendPacket(memhandle handle) {
-    memblock*   packet = &blocks[handle];
-    uint16_t    start = packet->begin - 1;
-    uint16_t    end = start + packet->size;
-
-    // backup data at control-byte position
-    uint8_t     data = readByte(start);
-    // write control-byte (if not 0 anyway)
-
-    if (data)
-        writeByte(start, 0);
-
-#ifdef ENC28J60DEBUG
-    printf("sendPacket(%d) [%d-%d]: ", handle, start, end);
-    for (uint16_t i = start; i <= end; i++) {
-        printf("%d ", readByte(i));
-    }
-
-    printf("\r\n");
-#endif
-    // TX start
-
-    writeRegPair(ETXSTL, start);
-
-    // Set the TXND pointer to correspond to the packet size given
-    writeRegPair(ETXNDL, end);
-
-    // send the contents of the transmit buffer onto the network
-    writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
-
-    // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12.
-    if ((readReg(EIR) & EIR_TXERIF)) {
-        writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS);
-    }
-
-    //restore data on control-byte position
-    if (data)
-        writeByte(start, data);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-uint16_t Enc28J60Network::setReadPtr(memhandle handle, memaddress position, uint16_t len) {
-    memblock*   packet = handle == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[handle];
-    memaddress  start = handle == UIP_RECEIVEBUFFERHANDLE
-    &&  packet->begin +
-        position > RXSTOP_INIT ? packet->begin +
-        position -
-        RXSTOP_INIT +
-        RXSTART_INIT : packet->begin +
-        position;
-
-    writeRegPair(ERDPTL, start);
-
-    if (len > packet->size - position)
-        len = packet->size - position;
-    return len;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-uint16_t Enc28J60Network::readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) {
-    len = setReadPtr(handle, position, len);
-    readBuffer(len, buffer);
-    return len;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-uint16_t Enc28J60Network::writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) {
-    memblock*   packet = &blocks[handle];
-    uint16_t    start = packet->begin + position;
-
-    writeRegPair(EWRPTL, start);
-
-    if (len > packet->size - position)
-        len = packet->size - position;
-    writeBuffer(len, buffer);
-    return len;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-uint8_t Enc28J60Network::readByte(uint16_t addr) {
-    uint8_t result;
-
-    writeRegPair(ERDPTL, addr);
-
-    _cs = 0;
-
-    // issue read command
-    _spi.write(ENC28J60_READ_BUF_MEM);
-
-    // read data
-    result = _spi.write(0x00);
-    _cs = 1;
-    return(result);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void Enc28J60Network::writeByte(uint16_t addr, uint8_t data) {
-    writeRegPair(EWRPTL, addr);
-
-    _cs = 0;
-
-    // issue write command
-    _spi.write(ENC28J60_WRITE_BUF_MEM);
-
-    // write data
-    _spi.write(data);
-    _cs = 1;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void Enc28J60Network::copyPacket
-(
-    memhandle   dest_pkt,
-    memaddress  dest_pos,
-    memhandle   src_pkt,
-    memaddress  src_pos,
-    uint16_t    len
-) {
-    memblock*   dest = &blocks[dest_pkt];
-    memblock*   src = src_pkt == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[src_pkt];
-    memaddress  start = src_pkt == UIP_RECEIVEBUFFERHANDLE
-    &&  src->begin +
-        src_pos > RXSTOP_INIT ? src->begin +
-        src_pos -
-        RXSTOP_INIT +
-        RXSTART_INIT : src->begin +
-        src_pos;
-    enc28J60_mempool_block_move_callback(dest->begin + dest_pos, start, len);
-
-    // Move the RX read pointer to the start of the next received packet
-    // This frees the memory we just read out
-    setERXRDPT();
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void Enc28J60Network::freePacket(void) {
-    setERXRDPT();
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-uint8_t Enc28J60Network::readOp(uint8_t op, uint8_t address) {
-    uint8_t result;
-
-    _cs = 0;
-
-    // issue read command
-    _spi.write(op | (address & ADDR_MASK));
-
-    // read data
-    result = _spi.write(0x00);
-
-    // do dummy read if needed (for mac and mii, see datasheet page 29)
-    if (address & 0x80)
-        result = _spi.write(0x00);
-
-    // release CS
-    _cs = 1;
-    return(result);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void Enc28J60Network::writeOp(uint8_t op, uint8_t address, uint8_t data) {
-    _cs = 0;
-
-    // issue write command
-    _spi.write(op | (address & ADDR_MASK));
-
-    // write data
-    _spi.write(data);
-    _cs = 1;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void Enc28J60Network::readBuffer(uint16_t len, uint8_t* data) {
-    _cs = 0;
-
-    // issue read command
-    _spi.write(ENC28J60_READ_BUF_MEM);
-    while (len) {
-        len--;
-
-        // read data
-        *data = _spi.write(0x00);
-        data++;
-    }
-
-    *data = '\0';
-    _cs = 1;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void Enc28J60Network::writeBuffer(uint16_t len, uint8_t* data) {
-    _cs = 0;
-
-    // issue write command
-    _spi.write(ENC28J60_WRITE_BUF_MEM);
-    while (len) {
-        len--;
-
-        // write data
-        _spi.write(*data);
-        data++;
-    }
-
-    _cs = 1;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void Enc28J60Network::setBank(uint8_t address) {
-
-    // set the bank (if needed)
-
-    if ((address & BANK_MASK) != bank) {
-
-        // set the bank
-        writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1 | ECON1_BSEL0));
-        writeOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK) >> 5);
-        bank = (address & BANK_MASK);
-    }
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-uint8_t Enc28J60Network::readReg(uint8_t address) {
-
-    // set the bank
-
-    setBank(address);
-
-    // do the read
-    return readOp(ENC28J60_READ_CTRL_REG, address);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void Enc28J60Network::writeReg(uint8_t address, uint8_t data) {
-
-    // set the bank
-
-    setBank(address);
-
-    // do the write
-    writeOp(ENC28J60_WRITE_CTRL_REG, address, data);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void Enc28J60Network::writeRegPair(uint8_t address, uint16_t data) {
-
-    // set the bank
-
-    setBank(address);
-
-    // do the write
-    writeOp(ENC28J60_WRITE_CTRL_REG, address, (data & 0xFF));
-    writeOp(ENC28J60_WRITE_CTRL_REG, address + 1, (data) >> 8);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void Enc28J60Network::phyWrite(uint8_t address, uint16_t data) {
-
-    // set the PHY register address
-
-    writeReg(MIREGADR, address);
-
-    // write the PHY data
-    writeRegPair(MIWRL, data);
-
-    // wait until the PHY write completes
-    while (readReg(MISTAT) & MISTAT_BUSY) {
-        wait_us(15);
-    }
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-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) {
-        wait_us(15);
-    }   //and MIRDH
-
-    writeReg(MICMD, 0);
-    return(readReg(MIRDL) | readReg(MIRDH) << 8);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void Enc28J60Network::clkout(uint8_t clk) {
-
-    //setup clkout: 2 is 12.5MHz:
-
-    writeReg(ECOCON, clk & 0x7);
-}
-
-// read the revision of the chip:
-uint8_t Enc28J60Network::getrev(void) {
-    return(readReg(EREVID));
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-uint16_t Enc28J60Network::chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t len) {
-    uint8_t     spdr;
-    uint16_t    t;
-    uint16_t    i;
-
-    len = setReadPtr(handle, pos, len) - 1;
-    _cs = 0;
-
-    // issue read command
-    spdr = _spi.write(ENC28J60_READ_BUF_MEM);
-    for (i = 0; i < len; i += 2) {
-
-        // read data
-        spdr = _spi.write(0x00);
-        t = spdr << 8;
-        spdr = _spi.write(0x00);
-        t += spdr;
-        sum += t;
-        if (sum < t) {
-            sum++;  /* carry */
-        }
-    }
-
-    if (i == len) {
-        spdr = _spi.write(0x00);
-        t = (spdr << 8) + 0;
-        sum += t;
-        if (sum < t) {
-            sum++;  /* carry */
-        }
-    }
-
-    _cs = 1;
-
-    /* Return sum in host byte order. */
-    return sum;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void Enc28J60Network::powerOff(void) {
-    writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN);
-    wait_ms(50);
-    writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_VRPS);
-    wait_ms(50);
-    writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void Enc28J60Network::powerOn(void) {
-    writeOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV);
-    wait_ms(50);
-    writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
-    wait_ms(50);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-bool Enc28J60Network::linkStatus(void) {
-    return(phyRead(PHSTAT2) & 0x0400) > 0;
-}
--- a/utility/Enc28J60Network.h	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +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.
-
- based on enc28j60.c file from the AVRlib library by Pascal Stang.
- For AVRlib See http://www.procyonengineering.com/
-
- Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.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 "mbed.h"
-#include "mempool.h"
-
-#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:
-    SPI                     _spi;
-    DigitalOut              _cs;
-    static uint16_t         nextPacketPtr;
-    static uint8_t          bank;
-
-    static 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);
-    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);
-    uint16_t                phyRead(uint8_t address);
-    void                    clkout(uint8_t clk);
-
-    friend void             enc28J60_mempool_block_move_callback(memaddress, memaddress, memaddress);
-public:
-    Enc28J60Network(PinName mosi, PinName miso, PinName sclk, PinName cs);
-    uint8_t     getrev(void);
-    void        powerOn(void);
-    void        powerOff(void);
-    bool        linkStatus(void);
-
-    void        init(uint8_t* macaddr);
-    memhandle   receivePacket(void);
-    void        freePacket(void);
-    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 /* Enc28J60NetworkClass_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utility/Enc28j60Py.cpp	Tue Aug 27 15:01:10 2019 +0000
@@ -0,0 +1,729 @@
+/*
+ Enc28J60Network.cpp
+ UIPEthernet network driver for Microchip ENC28J60 Ethernet Interface.
+
+ Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
+ All rights reserved.
+
+ based on enc28j60.c file from the AVRlib library by Pascal Stang.
+ For AVRlib See http://www.procyonengineering.com/
+
+ Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.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/>.
+ */
+#include "Enc28j60Py.h"
+#include "mbed.h"
+
+extern "C"
+{
+#include "enc28j60.h"
+#include "uip.h"
+}
+
+// Static member initialization
+uint16_t    Enc28j60Phy::nextPacketPtr;
+uint8_t     Enc28j60Phy::bank = 0xff;
+struct      memblock Enc28j60Phy::receivePkt;
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+Enc28j60Phy::Enc28j60Phy(PinName mosi, PinName miso, PinName sclk, PinName cs) :
+    MemPool(),
+    _spi(mosi, miso, sclk),
+    _cs(cs)
+{ }
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void Enc28j60Phy::init(uint8_t* macaddr)
+{
+    MemPool::init();           // 1 byte in between RX_STOP_INIT and pool to allow prepending of controlbyte
+    // initialize SPI interface
+    _spi.format(8, 0);          // 8-bit, mode 0
+    _spi.frequency(10000000);   // 10 Mbit/s
+    wait_ms(1000);              // 1 second for stable state
+    // Release SPI
+    _cs = 1;
+
+    // perform system reset
+    writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
+
+    // check CLKRDY bit to see if reset is complete
+    //while(!(readReg(ESTAT) & ESTAT_CLKRDY));
+    // The CLKRDY does not work. See Rev. B4 Silicon Errata point. Just wait.
+    wait_ms(50);
+
+    // do bank 0 stuff
+    // initialize receive buffer
+    // 16-bit transfers, must write low byte first
+    // set receive buffer start address
+    nextPacketPtr = RXSTART_INIT;
+
+    // Rx start
+    writeRegPair(ERXSTL, RXSTART_INIT);
+
+    // set receive pointer address
+    writeRegPair(ERXRDPTL, RXSTART_INIT);
+
+    // RX end
+    writeRegPair(ERXNDL, RXSTOP_INIT);
+
+    // TX start
+    //writeRegPair(ETXSTL, TXSTART_INIT);
+    // TX end
+    //writeRegPair(ETXNDL, TXSTOP_INIT);
+    // do bank 1 stuff, packet filter:
+    // For broadcast packets we allow only ARP packtets
+    // All other packets should be unicast only for our mac (MAADR)
+    //
+    // The pattern to match on is therefore
+    // Type     ETH.DST
+    // ARP      BROADCAST
+    // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9
+    // in binary these poitions are:11 0000 0011 1111
+    // This is hex 303F->EPMM0=0x3f,EPMM1=0x30
+    //TODO define specific pattern to receive dhcp-broadcast packages instead of setting ERFCON_BCEN!
+    writeReg(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_PMEN | ERXFCON_BCEN);
+    writeRegPair(EPMM0, 0x303f);
+    writeRegPair(EPMCSL, 0xf7f9);
+
+    //
+    //
+    // do bank 2 stuff
+    // enable MAC receive
+    // and bring MAC out of reset (writes 0x00 to MACON2)
+    writeRegPair(MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS);
+
+    // enable automatic padding to 60bytes and CRC operations
+    writeOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN);
+
+    // set inter-frame gap (non-back-to-back)
+    writeRegPair(MAIPGL, 0x0C12);
+
+    // set inter-frame gap (back-to-back)
+    writeReg(MABBIPG, 0x12);
+
+    // Set the maximum packet size which the controller will accept
+    // Do not send packets longer than MAX_FRAMELEN:
+    writeRegPair(MAMXFLL, MAX_FRAMELEN);
+
+    // do bank 3 stuff
+    // write MAC address
+    // NOTE: MAC address in ENC28J60 is byte-backward
+    writeReg(MAADR5, macaddr[0]);
+    writeReg(MAADR4, macaddr[1]);
+    writeReg(MAADR3, macaddr[2]);
+    writeReg(MAADR2, macaddr[3]);
+    writeReg(MAADR1, macaddr[4]);
+    writeReg(MAADR0, macaddr[5]);
+
+    // no loopback of transmitted frames
+    phyWrite(PHCON2, PHCON2_HDLDIS);
+
+    // switch to bank 0
+    setBank(ECON1);
+
+    // enable interrutps
+    writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE | EIE_PKTIE);
+
+    // enable packet reception
+    writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
+
+    //Configure leds
+    phyWrite(PHLCON, 0x476);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+memhandle Enc28j60Phy::receivePacket()
+{
+    uint8_t     rxstat;
+    uint16_t    len;
+    // check if a packet has been received and buffered
+    //if( !(readReg(EIR) & EIR_PKTIF) ){
+    // The above does not work. See Rev. B4 Silicon Errata point 6.
+    if (readReg(EPKTCNT) != 0) {
+        uint16_t    readPtr = nextPacketPtr +
+            6 > RXSTOP_INIT ? nextPacketPtr +
+            6 -
+            RXSTOP_INIT +
+            RXSTART_INIT : nextPacketPtr +
+            6;
+        // Set the read pointer to the start of the received packet
+        writeRegPair(ERDPTL, nextPacketPtr);
+
+        // read the next packet pointer
+        nextPacketPtr = readOp(ENC28J60_READ_BUF_MEM, 0);
+        nextPacketPtr |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8;
+
+        // read the packet length (see datasheet page 43)
+        len = readOp(ENC28J60_READ_BUF_MEM, 0);
+        len |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8;
+        len -= 4;   //remove the CRC count
+        // read the receive status (see datasheet page 43)
+        rxstat = readOp(ENC28J60_READ_BUF_MEM, 0);
+
+        //rxstat |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8;
+#ifdef ENC28J60DEBUG
+        printf
+        (
+            "receivePacket [%d-%d], next: %d, stat: %d, count: %d -> ",
+            readPtr,
+            (readPtr + len) % (RXSTOP_INIT + 1),
+            nextPacketPtr,
+            rxstat,
+            readReg(EPKTCNT)
+        );
+        (rxstat & 0x80) != 0 ? printf("OK") : printf("failed");
+        printf("\r\n");
+#endif
+        // decrement the packet counter indicate we are done with this packet
+
+        writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
+
+        // check CRC and symbol errors (see datasheet page 44, table 7-3):
+        // The ERXFCON.CRCEN is set by default. Normally we should not
+        // need to check this.
+        if ((rxstat & 0x80) != 0) {
+            receivePkt.begin = readPtr;
+            receivePkt.size = len;
+            return UIP_RECEIVEBUFFERHANDLE;
+        }
+
+        // Move the RX read pointer to the start of the next received packet
+        // This frees the memory we just read out
+        setERXRDPT();
+    }
+
+    return(NOBLOCK);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void Enc28j60Phy::setERXRDPT()
+{
+    writeRegPair(ERXRDPTL, nextPacketPtr == RXSTART_INIT ? RXSTOP_INIT : nextPacketPtr - 1);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+memaddress Enc28j60Phy::blockSize(memhandle handle)
+{
+    return handle == NOBLOCK ? 0 : handle == UIP_RECEIVEBUFFERHANDLE ? receivePkt.size : blocks[handle].size;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void Enc28j60Phy::sendPacket(memhandle handle)
+{
+    memblock*   packet = &blocks[handle];
+    uint16_t    start = packet->begin - 1;
+    uint16_t    end = start + packet->size;
+
+    // backup data at control-byte position
+    uint8_t     data = readByte(start);
+    // write control-byte (if not 0 anyway)
+    if (data)
+        writeByte(start, 0);
+
+#ifdef ENC28J60DEBUG
+    printf("sendPacket(%d) [%d-%d]: ", handle, start, end);
+    for (uint16_t i = start; i <= end; i++) {
+        printf("%d ", readByte(i));
+    }
+
+    printf("\r\n");
+#endif
+    // TX start
+
+    writeRegPair(ETXSTL, start);
+
+    // Set the TXND pointer to correspond to the packet size given
+    writeRegPair(ETXNDL, end);
+
+    // send the contents of the transmit buffer onto the network
+    writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
+
+    // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12.
+    if ((readReg(EIR) & EIR_TXERIF)) {
+        writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS);
+    }
+
+    //restore data on control-byte position
+    if (data)
+        writeByte(start, data);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint16_t Enc28j60Phy::setReadPtr(memhandle handle, memaddress position, uint16_t len)
+{
+    memblock*   packet = handle == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[handle];
+    memaddress  start = handle == UIP_RECEIVEBUFFERHANDLE &&
+        packet->begin +
+        position > RXSTOP_INIT ? packet->begin +
+        position -
+        RXSTOP_INIT +
+        RXSTART_INIT : packet->begin +
+        position;
+
+    writeRegPair(ERDPTL, start);
+
+    if (len > packet->size - position)
+        len = packet->size - position;
+    return len;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint16_t Enc28j60Phy::readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len)
+{
+    len = setReadPtr(handle, position, len);
+    readBuffer(len, buffer);
+    return len;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint16_t Enc28j60Phy::writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len)
+{
+    memblock*   packet = &blocks[handle];
+    uint16_t    start = packet->begin + position;
+
+    writeRegPair(EWRPTL, start);
+
+    if (len > packet->size - position)
+        len = packet->size - position;
+    writeBuffer(len, buffer);
+    return len;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint8_t Enc28j60Phy::readByte(uint16_t addr)
+{
+    uint8_t result;
+
+    writeRegPair(ERDPTL, addr);
+
+    _cs = 0;
+
+    // issue read command
+    _spi.write(ENC28J60_READ_BUF_MEM);
+
+    // read data
+    result = _spi.write(0x00);
+    _cs = 1;
+    return(result);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void Enc28j60Phy::writeByte(uint16_t addr, uint8_t data)
+{
+    writeRegPair(EWRPTL, addr);
+
+    _cs = 0;
+
+    // issue write command
+    _spi.write(ENC28J60_WRITE_BUF_MEM);
+
+    // write data
+    _spi.write(data);
+    _cs = 1;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void Enc28j60Phy::copyPacket
+(
+    memhandle   dest_pkt,
+    memaddress  dest_pos,
+    memhandle   src_pkt,
+    memaddress  src_pos,
+    uint16_t    len
+)
+{
+    memblock*   dest = &blocks[dest_pkt];
+    memblock*   src = src_pkt == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[src_pkt];
+    memaddress  start = src_pkt == UIP_RECEIVEBUFFERHANDLE &&
+        src->begin +
+        src_pos > RXSTOP_INIT ? src->begin +
+        src_pos -
+        RXSTOP_INIT +
+        RXSTART_INIT : src->begin +
+        src_pos;
+    enc28j60_mempool_block_move_callback(dest->begin + dest_pos, start, len);
+
+    // Move the RX read pointer to the start of the next received packet
+    // This frees the memory we just read out
+    setERXRDPT();
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void Enc28j60Phy::freePacket()
+{
+    setERXRDPT();
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint8_t Enc28j60Phy::readOp(uint8_t op, uint8_t address)
+{
+    uint8_t result;
+
+    _cs = 0;
+
+    // issue read command
+    _spi.write(op | (address & ADDR_MASK));
+
+    // read data
+    result = _spi.write(0x00);
+
+    // do dummy read if needed (for mac and mii, see datasheet page 29)
+    if (address & 0x80)
+        result = _spi.write(0x00);
+
+    // release CS
+    _cs = 1;
+    return(result);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void Enc28j60Phy::writeOp(uint8_t op, uint8_t address, uint8_t data)
+{
+    _cs = 0;
+
+    // issue write command
+    _spi.write(op | (address & ADDR_MASK));
+
+    // write data
+    _spi.write(data);
+    _cs = 1;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void Enc28j60Phy::readBuffer(uint16_t len, uint8_t* data)
+{
+    _cs = 0;
+
+    // issue read command
+    _spi.write(ENC28J60_READ_BUF_MEM);
+    while (len) {
+        len--;
+
+        // read data
+        *data = _spi.write(0x00);
+        data++;
+    }
+
+    *data = '\0';
+    _cs = 1;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void Enc28j60Phy::writeBuffer(uint16_t len, uint8_t* data)
+{
+    _cs = 0;
+
+    // issue write command
+    _spi.write(ENC28J60_WRITE_BUF_MEM);
+    while (len) {
+        len--;
+
+        // write data
+        _spi.write(*data);
+        data++;
+    }
+
+    _cs = 1;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void Enc28j60Phy::setBank(uint8_t address)
+{
+    // set the bank (if needed)
+    if ((address & BANK_MASK) != bank) {
+        // set the bank
+        writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1 | ECON1_BSEL0));
+        writeOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK) >> 5);
+        bank = (address & BANK_MASK);
+    }
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint8_t Enc28j60Phy::readReg(uint8_t address)
+{
+    // set the bank
+    setBank(address);
+
+    // do the read
+    return readOp(ENC28J60_READ_CTRL_REG, address);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void Enc28j60Phy::writeReg(uint8_t address, uint8_t data)
+{
+    // set the bank
+    setBank(address);
+
+    // do the write
+    writeOp(ENC28J60_WRITE_CTRL_REG, address, data);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void Enc28j60Phy::writeRegPair(uint8_t address, uint16_t data)
+{
+    // set the bank
+    setBank(address);
+
+    // do the write
+    writeOp(ENC28J60_WRITE_CTRL_REG, address, (data & 0xFF));
+    writeOp(ENC28J60_WRITE_CTRL_REG, address + 1, (data) >> 8);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void Enc28j60Phy::phyWrite(uint8_t address, uint16_t data)
+{
+    // set the PHY register address
+    writeReg(MIREGADR, address);
+
+    // write the PHY data
+    writeRegPair(MIWRL, data);
+
+    // wait until the PHY write completes
+    while (readReg(MISTAT) & MISTAT_BUSY) {
+        wait_us(15);
+    }
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint16_t Enc28j60Phy::phyRead(uint8_t address)
+{
+    writeReg(MIREGADR, address);
+    writeReg(MICMD, MICMD_MIIRD);
+
+    // wait until the PHY read completes
+    while (readReg(MISTAT) & MISTAT_BUSY) {
+        wait_us(15);
+    }   //and MIRDH
+
+    writeReg(MICMD, 0);
+    return(readReg(MIRDL) | readReg(MIRDH) << 8);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void Enc28j60Phy::clkout(uint8_t clk)
+{
+    //setup clkout: 2 is 12.5MHz:
+    writeReg(ECOCON, clk & 0x7);
+}
+
+// read the revision of the chip:
+uint8_t Enc28j60Phy::getrev()
+{
+    return(readReg(EREVID));
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint16_t Enc28j60Phy::chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t len)
+{
+    uint8_t     spdr;
+    uint16_t    t;
+    uint16_t    i;
+
+    len = setReadPtr(handle, pos, len) - 1;
+    _cs = 0;
+
+    // issue read command
+    spdr = _spi.write(ENC28J60_READ_BUF_MEM);
+    for (i = 0; i < len; i += 2) {
+        // read data
+        spdr = _spi.write(0x00);
+        t = spdr << 8;
+        spdr = _spi.write(0x00);
+        t += spdr;
+        sum += t;
+        if (sum < t) {
+            sum++;  /* carry */
+        }
+    }
+
+    if (i == len) {
+        spdr = _spi.write(0x00);
+        t = (spdr << 8) + 0;
+        sum += t;
+        if (sum < t) {
+            sum++;  /* carry */
+        }
+    }
+
+    _cs = 1;
+
+    /* Return sum in host byte order. */
+    return sum;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void Enc28j60Phy::powerOff()
+{
+    writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN);
+    wait_ms(50);
+    writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_VRPS);
+    wait_ms(50);
+    writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void Enc28j60Phy::powerOn()
+{
+    writeOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV);
+    wait_ms(50);
+    writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
+    wait_ms(50);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+bool Enc28j60Phy::linkStatus()
+{
+    return(phyRead(PHSTAT2) & 0x0400) > 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utility/Enc28j60Py.h	Tue Aug 27 15:01:10 2019 +0000
@@ -0,0 +1,82 @@
+/*
+ Enc28J60Network.h
+ UIPEthernet network driver for Microchip ENC28J60 Ethernet Interface.
+
+ Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
+ All rights reserved.
+
+ based on enc28j60.c file from the AVRlib library by Pascal Stang.
+ For AVRlib See http://www.procyonengineering.com/
+
+ Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.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 ENC28J60PHY_H
+#define ENC28J60PHY_H
+
+#include "mbed.h"
+#include "MemPool.h"
+
+#define UIP_RECEIVEBUFFERHANDLE 0xff
+
+//#define ENC28J60DEBUG
+
+class Enc28j60Phy : public MemPool
+{
+private:
+    SPI             _spi;
+    DigitalOut      _cs;
+    static uint16_t nextPacketPtr;
+    static uint8_t  bank;
+
+    static struct memblock  receivePkt;
+
+    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);
+    void        setBank(uint8_t address);
+    uint8_t     readReg(uint8_t address);
+    void        writeReg(uint8_t address, uint8_t data);
+    void        phyWrite(uint8_t address, uint16_t data);
+    uint16_t    phyRead(uint8_t address);
+    void        clkout(uint8_t clk);
+
+    friend void enc28j60_mempool_block_move_callback(memaddress, memaddress, memaddress);
+public:
+    Enc28j60Phy(PinName mosi, PinName miso, PinName sclk, PinName cs);
+    uint8_t     getrev();
+    void        powerOn();
+    void        powerOff();
+    bool        linkStatus();
+
+    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);
+
+    uint8_t     readOp(uint8_t op, uint8_t address);
+    uint8_t     readByte(uint16_t addr);
+    void        writeOp(uint8_t op, uint8_t address, uint8_t data);
+    void        writeRegPair(uint8_t address, uint16_t data);
+    void        writeByte(uint16_t addr, uint8_t data);
+};
+
+#endif
--- a/utility/IPAddress.cpp	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,98 +0,0 @@
-/*
-  IPAddress.cpp - Base class that provides IPAddress
-  Copyright (c) 2011 Adrian McEwen.  All right reserved.
-
-  Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.com>
-
-  This library is free software; you can redistribute it and/or
-  modify it under the terms of the GNU Lesser General Public
-  License as published by the Free Software Foundation; either
-  version 2.1 of the License, or (at your option) any later version.
-
-  This library is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public
-  License along with this library; if not, write to the Free Software
-  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-*/
-#include "mbed.h"
-#include "IPAddress.h"
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-IPAddress::IPAddress(void) {
-    memset(_address, 0, sizeof(_address));
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) {
-    _address[0] = first_octet;
-    _address[1] = second_octet;
-    _address[2] = third_octet;
-    _address[3] = fourth_octet;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-IPAddress::IPAddress(uint32_t address) {
-    memcpy(_address, &address, sizeof(_address));
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-IPAddress::IPAddress(const uint8_t* address) {
-    memcpy(_address, address, sizeof(_address));
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-IPAddress &IPAddress::operator=(const uint8_t* address) {
-    memcpy(_address, address, sizeof(_address));
-    return *this;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-IPAddress &IPAddress::operator=(uint32_t address) {
-    memcpy(_address, (const uint8_t*) &address, sizeof(_address));
-    return *this;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-bool IPAddress::operator==(const uint8_t* addr) const
-{
-    return memcmp(addr, _address, sizeof(_address)) == 0;
-}
--- a/utility/IPAddress.h	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-/*
-  IPAddress.h - Base class that provides IPAddress
-  Copyright (c) 2011 Adrian McEwen.  All right reserved.
-
-  Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.com>
-
-  This library is free software; you can redistribute it and/or
-  modify it under the terms of the GNU Lesser General Public
-  License as published by the Free Software Foundation; either
-  version 2.1 of the License, or (at your option) any later version.
-
-  This library is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public
-  License along with this library; if not, write to the Free Software
-  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-*/
-#ifndef IPADDRESS_H
-#define IPADDRESS_H
-
-#include <stdint.h>
-
-// A class to make it easier to handle and pass around IP addresses
-
-class   IPAddress
-{
-private:
-    uint8_t     _address[4];    // IPv4 address
-
-    // Access the raw byte array containing the address.  Because this returns a pointer
-    // to the internal structure rather than a copy of the address this function should only
-    // be used when you know that the usage of the returned uint8_t* will be transient and not
-
-    // stored.
-    uint8_t*    raw_address(void)   { return _address; };
-public:
-    // Constructors
-    IPAddress(void);
-    IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
-    IPAddress(uint32_t address);
-    IPAddress(const uint8_t* address);
-
-    // Overloaded cast operator to allow IPAddress objects to be used where a pointer
-    // to a four-byte uint8_t array is expected
-    operator uint32_t(void) const    { return *((uint32_t*)_address); };
-    bool operator==(const IPAddress& addr) const { return(*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); };
-    bool operator==(const uint8_t* addr) const;
-
-    // Overloaded index operator to allow getting and setting individual octets of the address
-    uint8_t operator[](int index) const { return _address[index]; };
-    uint8_t &operator[](int index)      { return _address[index]; };
-
-    // Overloaded copy operators to allow initialisation of IPAddress objects from other types
-    IPAddress &operator =(const uint8_t* address);
-    IPAddress &operator =(uint32_t address);
-
-    // Returns IP Address as string of char
-    char* toString(void) {
-        static char buff[16];
-        uint8_t     i = 0;
-        uint8_t     j = 0;
-
-        for (i = 0; i < 3; i++) {
-            j += sprintf(&buff[j], "%d", _address[i]);
-            buff[j++] = '.';
-        }
-
-        j += sprintf(&buff[j], "%d", _address[i]);
-        buff[j] = '\0';
-        return buff;
-    }
-
-    //    virtual size_t printTo(Print& p) const;
-    friend class        EthernetClass;
-    friend class        UDP;
-    friend class        Client;
-    friend class        Server;
-    friend class        DhcpClass;
-    friend class        DNSClient;
-};
-
-const IPAddress INADDR_NONE(0, 0, 0, 0);
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utility/MemPool.cpp	Tue Aug 27 15:01:10 2019 +0000
@@ -0,0 +1,192 @@
+/*
+ mempool.cpp - sleek implementation of a memory pool
+ 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 "MemPool.h"
+#include <string.h>
+
+#define POOLOFFSET  1
+
+struct memblock MemPool::    blocks[MEMPOOL_NUM_MEMBLOCKS + 1];
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void MemPool::init() {
+    memset(&blocks[0], 0, sizeof(blocks));
+    blocks[POOLSTART].begin = MEMPOOL_STARTADDRESS;
+    blocks[POOLSTART].size = 0;
+    blocks[POOLSTART].nextblock = NOBLOCK;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+memhandle MemPool::allocBlock(memaddress size) {
+    memblock*   best = NULL;
+    memhandle   cur = POOLSTART;
+    memblock*   block = &blocks[POOLSTART];
+    memaddress  bestsize = MEMPOOL_SIZE + 1;
+
+    do {
+        memhandle   next = block->nextblock;
+        memaddress  freesize = (next == NOBLOCK ? blocks[POOLSTART].begin + MEMPOOL_SIZE : blocks[next].begin) -
+            block->begin -
+            block->size;
+        if (freesize == size) {
+            best = &blocks[cur];
+            goto found;
+        }
+
+        if (freesize > size && freesize < bestsize) {
+            bestsize = freesize;
+            best = &blocks[cur];
+        }
+
+        if (next == NOBLOCK) {
+            if (best)
+                goto found;
+            else
+                goto collect;
+        }
+
+        block = &blocks[next];
+        cur = next;
+    } while (true);
+
+collect:
+    {
+        cur = POOLSTART;
+        block = &blocks[POOLSTART];
+
+        memhandle   next;
+        while ((next = block->nextblock) != NOBLOCK) {
+            memaddress      dest = block->begin + block->size;
+            memblock*       nextblock = &blocks[next];
+            memaddress*     src = &nextblock->begin;
+            if (dest != *src)
+            {
+#ifdef MEMPOOL_MEMBLOCK_MV
+                MEMPOOL_MEMBLOCK_MV(dest, *src, nextblock->size);
+#endif
+                *src = dest;
+            }
+
+            block = nextblock;
+        }
+
+        if (blocks[POOLSTART].begin + MEMPOOL_SIZE - block->begin - block->size >= size)
+            best = block;
+        else
+            goto notfound;
+    }
+
+found:
+    {
+        block = &blocks[POOLOFFSET];
+        for (cur = POOLOFFSET; cur < MEMPOOL_NUM_MEMBLOCKS + POOLOFFSET; cur++) {
+            if (block->size) {
+                block++;
+                continue;
+            }
+
+            memaddress  address = best->begin + best->size;
+#ifdef MEMBLOCK_ALLOC
+            MEMBLOCK_ALLOC(address, size);
+#endif
+            block->begin = address;
+            block->size = size;
+            block->nextblock = best->nextblock;
+            best->nextblock = cur;
+            return cur;
+        }
+    }
+
+notfound:
+    return NOBLOCK;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void MemPool::freeBlock(memhandle handle) {
+    if (handle == NOBLOCK)
+        return;
+
+    memblock*   b = &blocks[POOLSTART];
+
+    do {
+        memhandle   next = b->nextblock;
+        if (next == handle) {
+            memblock*   f = &blocks[next];
+#ifdef MEMBLOCK_FREE
+            MEMBLOCK_FREE(f->begin, f->size);
+#endif
+            b->nextblock = f->nextblock;
+            f->size = 0;
+            f->nextblock = NOBLOCK;
+            return;
+        }
+
+        if (next == NOBLOCK)
+            return;
+        b = &blocks[next];
+    } while (true);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void MemPool::resizeBlock(memhandle handle, memaddress position) {
+    memblock*   block = &blocks[handle];
+    block->begin += position;
+    block->size -= position;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void MemPool::resizeBlock(memhandle handle, memaddress position, memaddress size) {
+    memblock*   block = &blocks[handle];
+    block->begin += position;
+    block->size = size;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+memaddress MemPool::blockSize(memhandle handle) {
+    return blocks[handle].size;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utility/MemPool.h	Tue Aug 27 15:01:10 2019 +0000
@@ -0,0 +1,52 @@
+/*
+ mempool.h - sleek implementation of a memory pool
+ 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 MEMPOOL_H
+#define MEMPOOL_H
+
+#include <inttypes.h>
+
+#define POOLSTART   0
+#define NOBLOCK     0
+
+#include "mempool_conf.h"
+
+struct memblock
+{
+    memaddress  begin;
+    memaddress  size;
+    memhandle   nextblock;
+};
+
+class   MemPool
+{
+#ifdef MEMPOOLTEST_H
+    friend class    MemoryPoolTest;
+#endif
+protected:
+    static struct memblock  blocks[MEMPOOL_NUM_MEMBLOCKS + 1];
+public:
+
+    void                init();
+    static memhandle    allocBlock(memaddress);
+    static void         freeBlock(memhandle);
+    static void         resizeBlock(memhandle handle, memaddress position);
+    static void         resizeBlock(memhandle handle, memaddress position, memaddress size);
+    static memaddress   blockSize(memhandle);
+};
+#endif
--- a/utility/Server.h	Fri Jun 30 19:51:28 2017 +0000
+++ b/utility/Server.h	Tue Aug 27 15:01:10 2019 +0000
@@ -24,6 +24,6 @@
 class   Server
 {
 public:
-    virtual void    begin(void) = 0;
+    virtual void    open(void) = 0;
 };
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utility/Udp.h	Tue Aug 27 15:01:10 2019 +0000
@@ -0,0 +1,95 @@
+/*
+ *  Udp.cpp: Library to send/receive UDP packets.
+ *
+ * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these)
+ * 1) UDP does not guarantee the order in which assembled UDP packets are received. This
+ * might not happen often in practice, but in larger network topologies, a UDP
+ * packet can be received out of sequence. 
+ * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being
+ * aware of it. Again, this may not be a concern in practice on small local networks.
+ * For more information, see http://www.cafeaulait.org/course/week12/35.html
+ *
+ * MIT License:
+ * Copyright (c) 2008 Bjoern Hartmann
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * bjoern@cs.stanford.edu 12/30/2008
+ */
+#ifndef udp_h
+#define udp_h
+
+#include "mbed.h"
+#include "IpAddress.h"
+
+class   Udp
+{
+public:
+    virtual uint8_t     begin(uint16_t) = 0;    // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
+    virtual void        stop(void) = 0;         // Finish with the UDP socket
+
+    // Sending UDP packets
+    // Start building up a packet to send to the remote host specific in ip and port
+    // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
+    virtual int         beginPacket(IpAddress ip, uint16_t port) = 0;
+
+    // Start building up a packet to send to the remote host specific in host and port
+    // Returns 1 if successful, 0 if there was a problem resolving the hostname or port
+    virtual int         beginPacket(const char* host, uint16_t port) = 0;
+
+    // Finish off this packet and send it
+    // Returns 1 if the packet was sent successfully, 0 if there was an error
+    virtual int         endPacket(void) = 0;
+
+    // Write a single byte into the packet
+    virtual size_t      write(uint8_t) = 0;
+
+    // Write size bytes from buffer into the packet
+    virtual size_t      write(const uint8_t* buffer, size_t size) = 0;
+
+    // Start processing the next available incoming packet
+    // Returns the size of the packet in bytes, or 0 if no packets are available
+    virtual int         parsePacket(void) = 0;
+
+    // Number of bytes remaining in the current packet
+    virtual int         available(void) = 0;
+
+    // Read a single byte from the current packet
+    virtual int         read(void) = 0;
+
+    // Read up to len bytes from the current packet and place them into buffer
+    // Returns the number of bytes read, or 0 if none are available
+    virtual int         read(unsigned char* buffer, size_t len) = 0;
+
+    // Read up to len characters from the current packet and place them into buffer
+    // Returns the number of characters read, or 0 if none are available
+    virtual int         read(char* buffer, size_t len) = 0;
+
+    // Return the next byte from the current packet without moving on to the next byte
+    virtual int         peek(void) = 0;
+    virtual void        flush(void) = 0;        // Finish reading the current packet
+
+    // Return the IP address of the host who sent the current incoming packet
+    virtual IpAddress   remoteIP(void) = 0;
+
+    // Return the port of the host who sent the current incoming packet
+    virtual uint16_t    remotePort(void) = 0;
+protected:
+    uint8_t*    rawIPAddress(IpAddress& addr)   { return addr.rawAddress(); };
+};
+#endif
--- a/utility/enc28j60.h	Fri Jun 30 19:51:28 2017 +0000
+++ b/utility/enc28j60.h	Tue Aug 27 15:01:10 2019 +0000
@@ -243,15 +243,14 @@
 //
 // start with recbuf at 0/
 #define RXSTART_INIT     0x0
-// receive buffer end. make sure this is an odd value ( See Rev. B1,B4,B5,B7 Silicon Errata 'Memory (Ethernet Buffer)')
+// receive buffer end. make sure this is an odd value (See Rev. B1,B4,B5,B7 Silicon Errata 'Memory (Ethernet Buffer)')
 #define RXSTOP_INIT      (0x1FFF-0x1800)
 // start TX buffer RXSTOP_INIT+1
-#define TXSTART_INIT     (RXSTOP_INIT+1)
+#define TXSTART_INIT     (0x1FFF-0x1800+1)
 // stp TX buffer at end of mem
 #define TXSTOP_INIT      0x1FFF
 //
 // max frame length which the conroller will accept:
 #define        MAX_FRAMELEN        1500        // (note: maximum ethernet frame length would be 1518)
-//#define MAX_FRAMELEN     600
 
 #endif
--- a/utility/mempool.cpp	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,192 +0,0 @@
-/*
- mempool.cpp - sleek implementation of a memory pool
- 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 "mempool.h"
-#include <string.h>
-
-#define POOLOFFSET  1
-
-struct memblock MemoryPool::    blocks[MEMPOOL_NUM_MEMBLOCKS + 1];
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void MemoryPool::init(void) {
-    memset(&blocks[0], 0, sizeof(blocks));
-    blocks[POOLSTART].begin = MEMPOOL_STARTADDRESS;
-    blocks[POOLSTART].size = 0;
-    blocks[POOLSTART].nextblock = NOBLOCK;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-memhandle MemoryPool::allocBlock(memaddress size) {
-    memblock*   best = NULL;
-    memhandle   cur = POOLSTART;
-    memblock*   block = &blocks[POOLSTART];
-    memaddress  bestsize = MEMPOOL_SIZE + 1;
-
-    do {
-        memhandle   next = block->nextblock;
-        memaddress  freesize = (next == NOBLOCK ? blocks[POOLSTART].begin + MEMPOOL_SIZE : blocks[next].begin) -
-            block->begin -
-            block->size;
-        if (freesize == size) {
-            best = &blocks[cur];
-            goto found;
-        }
-
-        if (freesize > size && freesize < bestsize) {
-            bestsize = freesize;
-            best = &blocks[cur];
-        }
-
-        if (next == NOBLOCK) {
-            if (best)
-                goto found;
-            else
-                goto collect;
-        }
-
-        block = &blocks[next];
-        cur = next;
-    } while (true);
-
-collect:
-    {
-        cur = POOLSTART;
-        block = &blocks[POOLSTART];
-
-        memhandle   next;
-        while ((next = block->nextblock) != NOBLOCK) {
-            memaddress      dest = block->begin + block->size;
-            memblock*       nextblock = &blocks[next];
-            memaddress*     src = &nextblock->begin;
-            if (dest != *src)
-            {
-#ifdef MEMPOOL_MEMBLOCK_MV
-                MEMPOOL_MEMBLOCK_MV(dest, *src, nextblock->size);
-#endif
-                *src = dest;
-            }
-
-            block = nextblock;
-        }
-
-        if (blocks[POOLSTART].begin + MEMPOOL_SIZE - block->begin - block->size >= size)
-            best = block;
-        else
-            goto notfound;
-    }
-
-found:
-    {
-        block = &blocks[POOLOFFSET];
-        for (cur = POOLOFFSET; cur < MEMPOOL_NUM_MEMBLOCKS + POOLOFFSET; cur++) {
-            if (block->size) {
-                block++;
-                continue;
-            }
-
-            memaddress  address = best->begin + best->size;
-#ifdef MEMBLOCK_ALLOC
-            MEMBLOCK_ALLOC(address, size);
-#endif
-            block->begin = address;
-            block->size = size;
-            block->nextblock = best->nextblock;
-            best->nextblock = cur;
-            return cur;
-        }
-    }
-
-notfound:
-    return NOBLOCK;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void MemoryPool::freeBlock(memhandle handle) {
-    if (handle == NOBLOCK)
-        return;
-
-    memblock*   b = &blocks[POOLSTART];
-
-    do {
-        memhandle   next = b->nextblock;
-        if (next == handle) {
-            memblock*   f = &blocks[next];
-#ifdef MEMBLOCK_FREE
-            MEMBLOCK_FREE(f->begin, f->size);
-#endif
-            b->nextblock = f->nextblock;
-            f->size = 0;
-            f->nextblock = NOBLOCK;
-            return;
-        }
-
-        if (next == NOBLOCK)
-            return;
-        b = &blocks[next];
-    } while (true);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void MemoryPool::resizeBlock(memhandle handle, memaddress position) {
-    memblock*   block = &blocks[handle];
-    block->begin += position;
-    block->size -= position;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void MemoryPool::resizeBlock(memhandle handle, memaddress position, memaddress size) {
-    memblock*   block = &blocks[handle];
-    block->begin += position;
-    block->size = size;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-memaddress MemoryPool::blockSize(memhandle handle) {
-    return blocks[handle].size;
-}
--- a/utility/mempool.h	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- mempool.h - sleek implementation of a memory pool
- 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 MEMPOOL_H
-#define MEMPOOL_H
-
-#include <inttypes.h>
-
-#define POOLSTART   0
-#define NOBLOCK     0
-
-#include "mempool_conf.h"
-
-struct memblock
-{
-    memaddress  begin;
-    memaddress  size;
-    memhandle   nextblock;
-};
-
-class   MemoryPool
-{
-#ifdef MEMPOOLTEST_H
-    friend class    MemoryPoolTest;
-#endif
-protected:
-    static struct memblock  blocks[MEMPOOL_NUM_MEMBLOCKS + 1];
-public:
-    static void         init(void);
-    static memhandle    allocBlock(memaddress);
-    static void         freeBlock(memhandle);
-    static void         resizeBlock(memhandle handle, memaddress position);
-    static void         resizeBlock(memhandle handle, memaddress position, memaddress size);
-    static memaddress   blockSize(memhandle);
-};
-#endif
--- a/utility/mempool_conf.h	Fri Jun 30 19:51:28 2017 +0000
+++ b/utility/mempool_conf.h	Tue Aug 27 15:01:10 2019 +0000
@@ -25,7 +25,7 @@
 #define MEMPOOL_STARTADDRESS    TXSTART_INIT + 1
 #define MEMPOOL_SIZE            TXSTOP_INIT - TXSTART_INIT
 
-void  enc28J60_mempool_block_move_callback(memaddress, memaddress, memaddress);
+void  enc28j60_mempool_block_move_callback(memaddress, memaddress, memaddress);
 
-#define MEMPOOL_MEMBLOCK_MV(dest, src, size)    enc28J60_mempool_block_move_callback(dest, src, size)
+#define MEMPOOL_MEMBLOCK_MV(dest, src, size)    enc28j60_mempool_block_move_callback(dest, src, size)
 #endif
--- a/utility/millis.cpp	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*
- uip_millis.cpp
- Copyright (c) 2015 Zoltan Hudak <hudakz@inbox.com>
- 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 "millis.h"
-#include "mbed.h"
-
-volatile unsigned long  _millis;
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-void millis_start(void) {
-    SysTick_Config(SystemCoreClock / 1000);
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-extern "C" void SysTick_Handler(void) {
-    _millis++;
-}
-
-/**
- * @brief
- * @note
- * @param
- * @retval
- */
-extern "C" unsigned long millis(void) {
-    return _millis;
-}
--- a/utility/millis.h	Fri Jun 30 19:51:28 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-/*
- uip_millis.h
- Copyright (c) 2015 Zoltan Hudak <hudakz@inbox.com>
- 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 MILLIS_H
-#define MILLIS_H
-
-extern "C" void          millis_start(void);
-extern "C" unsigned long millis(void);
-
-#endif
--- a/utility/uip-conf.h	Fri Jun 30 19:51:28 2017 +0000
+++ b/utility/uip-conf.h	Tue Aug 27 15:01:10 2019 +0000
@@ -162,23 +162,13 @@
  * \hideinitializer
  */
 #define UIP_CONF_STATISTICS 0
-
-// SLIP
-
 //#define UIP_CONF_LLH_LEN 0
 typedef void*   uip_tcp_appstate_t;
-
 void            uipclient_appcall(void);
-
 #define UIP_APPCALL uipclient_appcall
-
 typedef void*   uip_udp_appstate_t;
-
 void            uipudp_appcall(void);
-
 #define UIP_UDP_APPCALL uipudp_appcall
-
 #define CC_REGISTER_ARG register
-
 #define UIP_ARCH_CHKSUM 1
 #endif /* __UIP_CONF_H__ */
--- a/utility/uip.h	Fri Jun 30 19:51:28 2017 +0000
+++ b/utility/uip.h	Tue Aug 27 15:01:10 2019 +0000
@@ -1416,20 +1416,14 @@
    timer has fired. These values are never used directly, but only in
    the macrose defined in this file. */
 
-#define UIP_DATA            1   /* Tells UIP that there is incoming
-				   data in the uip_buf buffer. The
-				   length of the data is stored in the
-				   global variable uip_len. */
-
-#define UIP_TIMER           2   /* Tells UIP that the periodic timer
-				   has fired. */
-
-#define UIP_POLL_REQUEST    3   /* Tells UIP that a connection should
-				   be polled. */
-
-#define UIP_UDP_SEND_CONN   4   /* Tells UIP that a UDP datagram
-				   should be constructed in the
-				   uip_buf buffer. */
+#define UIP_DATA            1   /*  Tells UIP that there is incoming
+                                    data in the uip_buf buffer. The
+                                    length of the data is stored in the
+                                    global variable uip_len.
+                                */
+#define UIP_TIMER           2   /* Tells UIP that the periodic timer has fired. */
+#define UIP_POLL_REQUEST    3   /* Tells UIP that a connection should be polled. */
+#define UIP_UDP_SEND_CONN   4   /* Tells UIP that a UDP datagram should be constructed in the uip_buf buffer. */
 
 #if UIP_UDP
 #define UIP_UDP_TIMER   5
--- a/utility/uip_debug.cpp	Fri Jun 30 19:51:28 2017 +0000
+++ b/utility/uip_debug.cpp	Tue Aug 27 15:01:10 2019 +0000
@@ -7,7 +7,7 @@
 extern "C"
 {
 #include "uip.h"
-} extern Serial     pc;
+}
 struct uip_conn con[UIP_CONNS];
 
 /**
@@ -19,9 +19,9 @@
 void UIPDebug::uip_debug_printconns(void) {
     for (uint8_t i = 0; i < UIP_CONNS; i++) {
         if (uip_debug_printcon(&con[i], &uip_conns[i])) {
-            pc.printf("connection[");
-            pc.printf("%d", i);
-            pc.printf("] changed.\r\n");
+            printf("connection[");
+            printf("%d", i);
+            printf("] changed.\r\n");
         }
     }
 }
@@ -35,130 +35,130 @@
 bool UIPDebug::uip_debug_printcon(struct uip_conn* lhs, struct uip_conn* rhs) {
     bool    changed = false;
     if (!uip_ipaddr_cmp(lhs->ripaddr, rhs->ripaddr)) {
-        pc.printf(" ripaddr: ");
+        printf(" ripaddr: ");
         uip_debug_printbytes((const uint8_t*)lhs->ripaddr, 4);
-        pc.printf(" -> ");
+        printf(" -> ");
         uip_debug_printbytes((const uint8_t*)rhs->ripaddr, 4);
-        pc.printf("\r\n");
+        printf("\r\n");
         uip_ipaddr_copy(lhs->ripaddr, rhs->ripaddr);
         changed = true;
     }
 
     if (lhs->lport != rhs->lport) {
-        pc.printf(" lport: ");
-        pc.printf("%d", htons(lhs->lport));
-        pc.printf(" -> ");
-        pc.printf("%d\r\n", htons(rhs->lport));
+        printf(" lport: ");
+        printf("%d", htons(lhs->lport));
+        printf(" -> ");
+        printf("%d\r\n", htons(rhs->lport));
         lhs->lport = rhs->lport;
         changed = true;
     }
 
     if (lhs->rport != rhs->rport) {
-        pc.printf(" rport: ");
-        pc.printf("%d", htons(lhs->rport));
-        pc.printf(" -> ");
-        pc.printf("%d\r\n", htons(rhs->rport));
+        printf(" rport: ");
+        printf("%d", htons(lhs->rport));
+        printf(" -> ");
+        printf("%d\r\n", htons(rhs->rport));
         lhs->rport = rhs->rport;
         changed = true;
     }
 
     if ((uint32_t) lhs->rcv_nxt[0] != (uint32_t) rhs->rcv_nxt[0]) {
-        pc.printf(" rcv_nxt: ");
+        printf(" rcv_nxt: ");
         uip_debug_printbytes(lhs->rcv_nxt, 4);
-        pc.printf(" -> ");
+        printf(" -> ");
         uip_debug_printbytes(rhs->rcv_nxt, 4);
         *((uint32_t*) &lhs->rcv_nxt[0]) = (uint32_t) rhs->rcv_nxt[0];
-        pc.printf("\r\n");
+        printf("\r\n");
         changed = true;
     }
 
     if ((uint32_t) lhs->snd_nxt[0] != (uint32_t) rhs->snd_nxt[0]) {
-        pc.printf(" snd_nxt: ");
+        printf(" snd_nxt: ");
         uip_debug_printbytes(lhs->snd_nxt, 4);
-        pc.printf(" -> ");
+        printf(" -> ");
         uip_debug_printbytes(rhs->snd_nxt, 4);
         *((uint32_t*) &lhs->snd_nxt[0]) = (uint32_t) rhs->snd_nxt[0];
-        pc.printf("\r\n");
+        printf("\r\n");
         changed = true;
     }
 
     if (lhs->len != rhs->len) {
-        pc.printf(" len: ");
-        pc.printf("%d", lhs->len);
-        pc.printf(" -> ");
-        pc.printf("%d\r\n", rhs->len);
+        printf(" len: ");
+        printf("%d", lhs->len);
+        printf(" -> ");
+        printf("%d\r\n", rhs->len);
         lhs->len = rhs->len;
         changed = true;
     }
 
     if (lhs->mss != rhs->mss) {
-        pc.printf(" mss: ");
-        pc.printf("%d", lhs->mss);
-        pc.printf(" -> ");
-        pc.printf("%d\r\n", rhs->mss);
+        printf(" mss: ");
+        printf("%d", lhs->mss);
+        printf(" -> ");
+        printf("%d\r\n", rhs->mss);
         lhs->mss = rhs->mss;
         changed = true;
     }
 
     if (lhs->initialmss != rhs->initialmss) {
-        pc.printf(" initialmss: ");
-        pc.printf("%d", lhs->initialmss);
-        pc.printf(" -> ");
-        pc.printf("%d\r\n", rhs->initialmss);
+        printf(" initialmss: ");
+        printf("%d", lhs->initialmss);
+        printf(" -> ");
+        printf("%d\r\n", rhs->initialmss);
         lhs->initialmss = rhs->initialmss;
         changed = true;
     }
 
     if (lhs->sa != rhs->sa) {
-        pc.printf(" sa: ");
-        pc.printf("%d", lhs->sa);
-        pc.printf(" -> ");
-        pc.printf("%d", rhs->sa);
+        printf(" sa: ");
+        printf("%d", lhs->sa);
+        printf(" -> ");
+        printf("%d", rhs->sa);
         lhs->sa = rhs->sa;
         changed = true;
     }
 
     if (lhs->sv != rhs->sv) {
-        pc.printf(" sv: ");
-        pc.printf("%d", lhs->sv);
-        pc.printf(" -> ");
-        pc.printf("%d\r\n", rhs->sv);
+        printf(" sv: ");
+        printf("%d", lhs->sv);
+        printf(" -> ");
+        printf("%d\r\n", rhs->sv);
         lhs->sv = rhs->sv;
         changed = true;
     }
 
     if (lhs->rto != rhs->rto) {
-        pc.printf(" rto: ");
-        pc.printf("%d", lhs->rto);
-        pc.printf(" -> ");
-        pc.printf("%d\r\n", rhs->rto);
+        printf(" rto: ");
+        printf("%d", lhs->rto);
+        printf(" -> ");
+        printf("%d\r\n", rhs->rto);
         lhs->rto = rhs->rto;
         changed = true;
     }
 
     if (lhs->tcpstateflags != rhs->tcpstateflags) {
-        pc.printf(" tcpstateflags: ");
-        pc.printf("%d", lhs->tcpstateflags);
-        pc.printf(" -> ");
-        pc.printf("%d\r\n", rhs->tcpstateflags);
+        printf(" tcpstateflags: ");
+        printf("%d", lhs->tcpstateflags);
+        printf(" -> ");
+        printf("%d\r\n", rhs->tcpstateflags);
         lhs->tcpstateflags = rhs->tcpstateflags;
         changed = true;
     }
 
     if (lhs->timer != rhs->timer) {
-        pc.printf(" timer: ");
-        pc.printf("%d", lhs->timer);
-        pc.printf(" -> ");
-        pc.printf("%d\r\n", rhs->timer);
+        printf(" timer: ");
+        printf("%d", lhs->timer);
+        printf(" -> ");
+        printf("%d\r\n", rhs->timer);
         lhs->timer = rhs->timer;
         changed = true;
     }
 
     if (lhs->nrtx != rhs->nrtx) {
-        pc.printf(" nrtx: ");
-        pc.printf("%d", lhs->nrtx);
-        pc.printf(" -> ");
-        pc.printf("%d\r\n", rhs->nrtx);
+        printf(" nrtx: ");
+        printf("%d", lhs->nrtx);
+        printf(" -> ");
+        printf("%d\r\n", rhs->nrtx);
         lhs->nrtx = rhs->nrtx;
         changed = true;
     }
@@ -174,9 +174,9 @@
  */
 void UIPDebug::uip_debug_printbytes(const uint8_t* data, uint8_t len) {
     for (uint8_t i = 0; i < len; i++) {
-        pc.printf("%d", data[i]);
+        printf("%d", data[i]);
         if (i < len - 1)
-            pc.printf(",");
+            printf(",");
     }
 }
 #endif
--- a/utility/uipethernet-conf.h	Fri Jun 30 19:51:28 2017 +0000
+++ b/utility/uipethernet-conf.h	Tue Aug 27 15:01:10 2019 +0000
@@ -3,32 +3,31 @@
 
 /* for TCP */
 
-#define UIP_SOCKET_NUMPACKETS       5
-#define UIP_CONF_MAX_CONNECTIONS    4
+#define UIP_SOCKET_NUMPACKETS   5
+#define UIP_MAX_CONNECTIONS     4
 
 /* for UDP
  * set UIP_CONF_UDP to 0 to disable UDP (saves aprox. 5kb flash) */
 
-#define UIP_CONF_UDP        1
-#define UIP_CONF_BROADCAST  1
-#define UIP_CONF_UDP_CONNS  4
+#define UIP_CONF_UDP            1
+#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
+#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
+#define UIP_CONNECT_TIMEOUT     -1
 
 /* periodic timer for uip (in ms) */
 
-#define UIP_PERIODIC_TIMER  250
+#define UIP_PERIODIC_TIMEOUT    250
 
-/* timer to poll client for data after last write (in ms)
- * set to -1 to disable fast polling and rely on periodic only (saves 100 bytes flash) */
+/* timer to poll client for data after last write (in ms) */
 
-#define UIP_CLIENT_TIMER    20
+#define UIP_CLIENT_TIMEOUT      10
 #endif
--- a/utility/uipopt.h	Fri Jun 30 19:51:28 2017 +0000
+++ b/utility/uipopt.h	Tue Aug 27 15:01:10 2019 +0000
@@ -244,11 +244,11 @@
  * \hideinitializer
  */
 
-#ifndef UIP_CONF_MAX_CONNECTIONS
+#ifndef UIP_MAX_CONNECTIONS
 #define UIP_CONNS   10
 #else /* UIP_CONF_MAX_CONNECTIONS */
 
-#define UIP_CONNS   UIP_CONF_MAX_CONNECTIONS
+#define UIP_CONNS   UIP_MAX_CONNECTIONS
 #endif /* UIP_CONF_MAX_CONNECTIONS */
 
 /**