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:
Fri Aug 30 08:11:40 2019 +0000
Parent:
10:e4ddab81e6a8
Child:
12:1dd995402b99
Commit message:
"set_network" method of Mbed style added.

Changed in this revision

DhcpClient.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
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
utility/Enc28j60Eth.cpp Show annotated file Show diff for this revision Revisions of this file
utility/Enc28j60Eth.h Show annotated file Show diff for this revision Revisions of this file
utility/Enc28j60Py.cpp Show diff for this revision Revisions of this file
utility/Enc28j60Py.h 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_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
--- a/DhcpClient.h	Tue Aug 27 22:08:54 2019 +0000
+++ b/DhcpClient.h	Fri Aug 30 08:11:40 2019 +0000
@@ -1,7 +1,7 @@
 // DHCP Library v0.3 - April 25, 2009
 // Author: Jordan Terrell - blog.jordanterrell.com
-#ifndef Dhcp_h
-#define Dhcp_h
+#ifndef DHCPCLIENT_h
+#define DHCPCLIENT_h
 
 #include "UdpSocket.h"
 #include "IpAddress.h"
--- a/IpAddress.cpp	Tue Aug 27 22:08:54 2019 +0000
+++ b/IpAddress.cpp	Fri Aug 30 08:11:40 2019 +0000
@@ -18,7 +18,6 @@
   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"
@@ -29,7 +28,8 @@
  * @param
  * @retval
  */
-IpAddress::IpAddress(void) {
+IpAddress::IpAddress(void)
+{
     memset(_address, 0, sizeof(_address));
 }
 
@@ -39,7 +39,8 @@
  * @param
  * @retval
  */
-IpAddress::IpAddress(uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4) {
+IpAddress::IpAddress(uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4)
+{
     _address[0] = octet1;
     _address[1] = octet2;
     _address[2] = octet3;
@@ -52,7 +53,8 @@
  * @param
  * @retval
  */
-IpAddress::IpAddress(uint32_t address) {
+IpAddress::IpAddress(uint32_t address)
+{
     memcpy(_address, &address, sizeof(_address));
 }
 
@@ -62,7 +64,8 @@
  * @param
  * @retval
  */
-IpAddress::IpAddress(const uint8_t address[4]) {
+IpAddress::IpAddress(const uint8_t address[4])
+{
     memcpy(_address, address, sizeof(_address));
 }
 
@@ -72,10 +75,37 @@
  * @param
  * @retval
  */
-//IPAddress &IPAddress::operator=(const uint8_t* address) {
-//    memcpy(_address, address, sizeof(_address));
-//    return *this;
-//}
+IpAddress::IpAddress(const char* str, size_t len)
+{
+    uint8_t pos = 0;
+    uint8_t byte;
+    uint8_t i = 0;
+
+    if (len > 16)
+        return;
+
+    while (true) {
+        if (pos == len || str[pos] < '0' || str[pos] > '9') {
+            return;
+        }
+
+        byte = 0;
+        while (pos < len && str[pos] >= '0' && str[pos] <= '9') {
+            byte *= 10;
+            byte += str[pos++] - '0';
+        }
+
+        _address[i++] = byte;
+
+        if (i == 4) {
+            return;
+        }
+
+        if (pos == len || str[pos++] != '.') {
+            return;
+        }
+    }
+}
 
 /**
  * @brief
@@ -83,7 +113,19 @@
  * @param
  * @retval
  */
-IpAddress &IpAddress::operator=(uint32_t address) {
+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;
 }
@@ -105,9 +147,10 @@
  * @param
  * @retval
  */
-const char* IpAddress::toString(char* buf) {
-    uint8_t     i = 0;
-    uint8_t     j = 0;
+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]);
--- a/IpAddress.h	Tue Aug 27 22:08:54 2019 +0000
+++ b/IpAddress.h	Fri Aug 30 08:11:40 2019 +0000
@@ -18,8 +18,8 @@
   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
+#ifndef IPADDRESS_h
+#define IPADDRESS_h
 
 #include <stdio.h>
 
@@ -36,6 +36,7 @@
     IpAddress(uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4);
     IpAddress(uint32_t address);
     IpAddress(const uint8_t address[4]);
+    IpAddress(const char *str, size_t len);
 
     // Overloaded cast operator to allow IPAddress objects to be used where a pointer
     // to a four-byte uint8_t array is expected
@@ -49,6 +50,7 @@
 
     // Overloaded copy operators to allow initialisation of IPAddress objects from other types
     IpAddress &operator =(uint32_t address);
+    IpAddress &operator =(const uint8_t* address);
 
     // Returns IP Address as string of char
     const char* toString(char* buf);
@@ -59,7 +61,6 @@
     // stored.
     uint8_t*    rawAddress(void)   { return _address; }
 
-    //    virtual size_t printTo(Print& p) const;
     friend class UIPEthernet;
     friend class UdpSocket;
     friend class TcpClient;
--- a/TcpClient.cpp	Tue Aug 27 22:08:54 2019 +0000
+++ b/TcpClient.cpp	Fri Aug 30 08:11:40 2019 +0000
@@ -31,7 +31,7 @@
 
 #define UIP_TCP_PHYH_LEN    UIP_LLH_LEN + UIP_IPTCPH_LEN
 
-uip_userdata_t TcpClient::  all_data[UIP_CONNS];
+uip_userdata_t TcpClient::all_data[UIP_CONNS];
 
 /**
  * @brief
@@ -194,7 +194,7 @@
  * @param
  * @retval
  */
-size_t TcpClient::send(uint8_t c)
+int TcpClient::send(uint8_t c)
 {
     return _write(data, &c, 1);
 }
@@ -205,7 +205,7 @@
  * @param
  * @retval
  */
-size_t TcpClient::send(const uint8_t* buf, size_t size)
+int TcpClient::send(const uint8_t* buf, size_t size)
 {
     return _write(data, buf, size);
 }
@@ -216,9 +216,9 @@
  * @param
  * @retval
  */
-size_t TcpClient::_write(uip_userdata_t* data, const uint8_t* buf, size_t size)
+int TcpClient::_write(uip_userdata_t* data, const uint8_t* buf, size_t size)
 {
-    int         remain = size;
+    size_t      remain = size;
     uint16_t    written;
 #if UIP_ATTEMPTS_ON_WRITE > 0
     uint16_t    attempts = UIP_ATTEMPTS_ON_WRITE;
@@ -229,7 +229,7 @@
         if (data->packets_out[p] == NOBLOCK)
         {
 newpacket:
-            data->packets_out[p] = UipEthernet::ethernet->phy.allocBlock(UIP_SOCKET_DATALEN);
+            data->packets_out[p] = UipEthernet::ethernet->enc28j60Eth.allocBlock(UIP_SOCKET_DATALEN);
             if (data->packets_out[p] == NOBLOCK)
             {
 #if UIP_ATTEMPTS_ON_WRITE > 0
@@ -254,7 +254,7 @@
             remain
         );
 #endif
-        written = UipEthernet::ethernet->phy.writePacket
+        written = UipEthernet::ethernet->enc28j60Eth.writePacket
             (
                 data->packets_out[p],
                 data->out_pos,
@@ -310,7 +310,7 @@
 {
     size_t  len = 0;
     for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) {
-        len += UipEthernet::ethernet->phy.blockSize(u->packets_in[i]);
+        len += UipEthernet::ethernet->enc28j60Eth.blockSize(u->packets_in[i]);
     }
 
     return len;
@@ -331,8 +331,8 @@
 
         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])) {
+            read = UipEthernet::ethernet->enc28j60Eth.readPacket(data->packets_in[0], 0, buf + size - remain, remain);
+            if (read == UipEthernet::ethernet->enc28j60Eth.blockSize(data->packets_in[0])) {
                 remain -= read;
                 _eatBlock(&data->packets_in[0]);
                 if
@@ -350,7 +350,7 @@
                 }
             }
             else {
-                UipEthernet::ethernet->phy.resizeBlock(data->packets_in[0], read);
+                UipEthernet::ethernet->enc28j60Eth.resizeBlock(data->packets_in[0], read);
                 break;
             }
         } while (remain > 0);
@@ -366,7 +366,7 @@
  * @param
  * @retval
  */
-size_t TcpClient::recv()
+int TcpClient::recv()
 {
     static uint8_t  c;
     if (recv(&c, 1) < 0)
@@ -385,7 +385,7 @@
     static uint8_t  c;
     if (*this) {
         if (data->packets_in[0] != NOBLOCK) {
-            UipEthernet::ethernet->phy.readPacket(data->packets_in[0], 0, &c, 1);
+            UipEthernet::ethernet->enc28j60Eth.readPacket(data->packets_in[0], 0, &c, 1);
             return c;
         }
     }
@@ -412,12 +412,9 @@
  * @param
  * @retval
  */
-const char* TcpClient::getpeername()
+IpAddress TcpClient::getRemoteIp()
 {
-    static char buf[16];
-    IpAddress   remoteIp = ip_addr_uip(data->ripaddr);
-
-    return remoteIp.toString(buf);
+    return ip_addr_uip(data->ripaddr);
 }
 
 /**
@@ -426,9 +423,11 @@
  * @param
  * @retval
  */
-IpAddress TcpClient::getRemoteIp()
+const char* TcpClient::getpeername()
 {
-    return ip_addr_uip(data->ripaddr);
+    static char buf[16];
+
+    return getRemoteIp().toString(buf);
 }
 
 /**
@@ -481,9 +480,9 @@
             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);
+                        u->packets_in[i] = UipEthernet::ethernet->enc28j60Eth.allocBlock(uip_len);
                         if (u->packets_in[i] != NOBLOCK) {
-                            UipEthernet::ethernet->phy.copyPacket
+                            UipEthernet::ethernet->enc28j60Eth.copyPacket
                                 (
                                     u->packets_in[i],
                                     0,
@@ -552,16 +551,16 @@
                 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);
+                        UipEthernet::ethernet->enc28j60Eth.resizeBlock(u->packets_out[0], 0, send_len);
                     }
                 }
                 else
-                    send_len = UipEthernet::ethernet->phy.blockSize(u->packets_out[0]);
+                    send_len = UipEthernet::ethernet->enc28j60Eth.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);
+                    UipEthernet::uipPacket = UipEthernet::ethernet->enc28j60Eth.allocBlock(UipEthernet::uipHeaderLen + send_len);
                     if (UipEthernet::uipPacket != NOBLOCK) {
-                        UipEthernet::ethernet->phy.copyPacket
+                        UipEthernet::ethernet->enc28j60Eth.copyPacket
                             (
                                 UipEthernet::uipPacket,
                                 UipEthernet::uipHeaderLen,
@@ -620,6 +619,8 @@
         if (!data->state) {
             data->pollTimer.reset();
             data->state = sock | UIP_CLIENT_CONNECTED;
+            data->ripaddr[0] = 0;
+            data->ripaddr[1] = 0;
             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;
@@ -663,7 +664,7 @@
 
     printf("-> ");
 #endif
-    UipEthernet::ethernet->phy.freeBlock(block[0]);
+    UipEthernet::ethernet->enc28j60Eth.freeBlock(block[0]);
     for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS - 1; i++) {
         block[i] = block[i + 1];
     }
@@ -687,7 +688,7 @@
 void TcpClient::_flushBlocks(memhandle* block)
 {
     for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) {
-        UipEthernet::ethernet->phy.freeBlock(block[i]);
+        UipEthernet::ethernet->enc28j60Eth.freeBlock(block[i]);
         block[i] = NOBLOCK;
     }
 }
--- a/TcpClient.h	Tue Aug 27 22:08:54 2019 +0000
+++ b/TcpClient.h	Fri Aug 30 08:11:40 2019 +0000
@@ -16,8 +16,8 @@
  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
+#ifndef TCPCLIENT_h
+#define TCPCLIENT_h
 
 #include "mbed.h"
 #include "IpAddress.h"
@@ -74,10 +74,10 @@
     operator                bool();
     virtual bool operator   ==(const TcpClient& );
     virtual bool operator   !=(const TcpClient& rhs)    { return !this->operator ==(rhs); }
-    size_t                  send(uint8_t);
-    size_t                  send(const uint8_t* buf, size_t size);
+    int                     send(uint8_t);
+    int                     send(const uint8_t* buf, size_t size);
     size_t                  available();
-    size_t                  recv();
+    int                     recv();
     int                     peek();
     void                    flush();
     const char*             getpeername();
@@ -85,7 +85,7 @@
     void                    close();
 
     static uip_userdata_t   all_data[UIP_CONNS];
-    static size_t           _write(uip_userdata_t* , const uint8_t* buf, size_t size);
+    static int             _write(uip_userdata_t* , const uint8_t* buf, size_t size);
 
 protected:
     uint8_t*                rawIPAddress(IpAddress& addr)   { return addr.rawAddress(); }
--- a/TcpServer.cpp	Tue Aug 27 22:08:54 2019 +0000
+++ b/TcpServer.cpp	Fri Aug 30 08:11:40 2019 +0000
@@ -28,8 +28,9 @@
  * @param
  * @retval
  */
-TcpServer::TcpServer()
-{ }
+TcpServer::TcpServer() :
+    _conns(1)
+{}
 
 /**
  * @brief
@@ -40,7 +41,7 @@
 TcpClient* TcpServer::accept()
 {
     UipEthernet::ethernet->tick();
-    for (uip_userdata_t * data = &TcpClient::all_data[0]; data < &TcpClient::all_data[UIP_CONNS]; data++) {
+    for (uip_userdata_t * data = &TcpClient::all_data[0]; data < &TcpClient::all_data[_conns]; data++) {
         if
         (
             data->packets_in[0] != NOBLOCK &&
@@ -65,7 +66,10 @@
  * @retval
  */
 void TcpServer::open(UipEthernet* ethernet)
-{ }
+{
+    if (UipEthernet::ethernet != ethernet)
+        UipEthernet::ethernet = ethernet;
+}
 
 /**
  * @brief
@@ -122,7 +126,7 @@
 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++) {
+    for (uip_userdata_t * data = &TcpClient::all_data[0]; data < &TcpClient::all_data[_conns]; data++) {
         if ((data->state & UIP_CLIENT_CONNECTED) && uip_conns[data->state & UIP_CLIENT_SOCKETS].lport == _port)
             ret += TcpClient::_write(data, buf, size);
     }
--- a/TcpServer.h	Tue Aug 27 22:08:54 2019 +0000
+++ b/TcpServer.h	Fri Aug 30 08:11:40 2019 +0000
@@ -16,8 +16,8 @@
  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
+#ifndef TCPSERVER_h
+#define TCPSERVER_h
 
 #include "TcpClient.h"
 
--- a/UdpSocket.cpp	Tue Aug 27 22:08:54 2019 +0000
+++ b/UdpSocket.cpp	Fri Aug 30 08:11:40 2019 +0000
@@ -60,9 +60,9 @@
         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);
+        UipEthernet::ethernet->enc28j60Eth.freeBlock(appdata.packet_in);
+        UipEthernet::ethernet->enc28j60Eth.freeBlock(appdata.packet_next);
+        UipEthernet::ethernet->enc28j60Eth.freeBlock(appdata.packet_out);
         memset(&appdata, 0, sizeof(appdata));
     }
 }
@@ -109,7 +109,7 @@
 
     if (_uip_udp_conn) {
         if (appdata.packet_out == NOBLOCK) {
-            appdata.packet_out = UipEthernet::ethernet->phy.allocBlock(UIP_UDP_MAXPACKETSIZE);
+            appdata.packet_out = UipEthernet::ethernet->enc28j60Eth.allocBlock(UIP_UDP_MAXPACKETSIZE);
             appdata.out_pos = UIP_UDP_PHYH_LEN;
             if (appdata.packet_out != NOBLOCK)
                 return 1;
@@ -155,7 +155,7 @@
 {
     if (_uip_udp_conn && appdata.packet_out != NOBLOCK) {
         appdata.send = true;
-        UipEthernet::ethernet->phy.resizeBlock(appdata.packet_out, 0, appdata.out_pos);
+        UipEthernet::ethernet->enc28j60Eth.resizeBlock(appdata.packet_out, 0, appdata.out_pos);
         uip_udp_periodic_conn(_uip_udp_conn);
         if (uip_len > 0) {
             _send(&appdata);
@@ -176,7 +176,7 @@
 size_t UdpSocket::write(const uint8_t* buffer, size_t size)
 {
     if (appdata.packet_out != NOBLOCK) {
-        size_t  ret = UipEthernet::ethernet->phy.writePacket
+        size_t  ret = UipEthernet::ethernet->enc28j60Eth.writePacket
             (
                 appdata.packet_out,
                 appdata.out_pos,
@@ -201,7 +201,7 @@
         printf("udp parsePacket freeing previous packet: %d\r\n", appdata.packet_in);
     }
 #endif
-    UipEthernet::ethernet->phy.freeBlock(appdata.packet_in);
+    UipEthernet::ethernet->enc28j60Eth.freeBlock(appdata.packet_in);
 
     appdata.packet_in = appdata.packet_next;
     appdata.packet_next = NOBLOCK;
@@ -212,7 +212,7 @@
     }
 #endif
 
-    int size = UipEthernet::ethernet->phy.blockSize(appdata.packet_in);
+    int size = UipEthernet::ethernet->enc28j60Eth.blockSize(appdata.packet_in);
 #ifdef UIPETHERNET_DEBUG_UDP
     if (appdata.packet_in != NOBLOCK) {
         printf(", size: %d\r\n", size);
@@ -225,7 +225,7 @@
 int UdpSocket::available()
 {
     UipEthernet::ethernet->tick();
-    return UipEthernet::ethernet->phy.blockSize(appdata.packet_in);
+    return UipEthernet::ethernet->enc28j60Eth.blockSize(appdata.packet_in);
 }
 
 // Read a single byte from the current packet
@@ -246,13 +246,13 @@
 {
     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);
+        memaddress  read = UipEthernet::ethernet->enc28j60Eth.readPacket(appdata.packet_in, 0, buffer, len);
+        if (read == UipEthernet::ethernet->enc28j60Eth.blockSize(appdata.packet_in)) {
+            UipEthernet::ethernet->enc28j60Eth.freeBlock(appdata.packet_in);
             appdata.packet_in = NOBLOCK;
         }
         else
-            UipEthernet::ethernet->phy.resizeBlock(appdata.packet_in, read);
+            UipEthernet::ethernet->enc28j60Eth.resizeBlock(appdata.packet_in, read);
         return read;
     }
 
@@ -265,7 +265,7 @@
     UipEthernet::ethernet->tick();
     if (appdata.packet_in != NOBLOCK) {
         unsigned char   c;
-        if (UipEthernet::ethernet->phy.readPacket(appdata.packet_in, 0, &c, 1) == 1)
+        if (UipEthernet::ethernet->enc28j60Eth.readPacket(appdata.packet_in, 0, &c, 1) == 1)
             return c;
     }
 
@@ -276,7 +276,7 @@
 void UdpSocket::flush()
 {
     UipEthernet::ethernet->tick();
-    UipEthernet::ethernet->phy.freeBlock(appdata.packet_in);
+    UipEthernet::ethernet->enc28j60Eth.freeBlock(appdata.packet_in);
     appdata.packet_in = NOBLOCK;
 }
 
@@ -300,18 +300,18 @@
             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);
+                data->packet_next = UipEthernet::ethernet->enc28j60Eth.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
+                    UipEthernet::ethernet->enc28j60Eth.copyPacket
                         (
                             data->packet_next,
                             0,
                             UipEthernet::inPacket,
                             UIP_UDP_PHYH_LEN,
-                            UipEthernet::ethernet->phy.blockSize(data->packet_next)
+                            UipEthernet::ethernet->enc28j60Eth.blockSize(data->packet_next)
                         );
 #ifdef UIPETHERNET_DEBUG_UDP
                     printf
--- a/UdpSocket.h	Tue Aug 27 22:08:54 2019 +0000
+++ b/UdpSocket.h	Fri Aug 30 08:11:40 2019 +0000
@@ -18,8 +18,8 @@
  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
+#ifndef UDPSOCKET_h
+#define UDPSOCKET_h
 
 #include "mbed.h"
 #include "utility/Udp.h"
--- a/UipEthernet.cpp	Tue Aug 27 22:08:54 2019 +0000
+++ b/UipEthernet.cpp	Fri Aug 30 08:11:40 2019 +0000
@@ -20,7 +20,7 @@
   */
 #include "mbed.h"
 #include "UipEthernet.h"
-#include "utility/Enc28j60Py.h"
+#include "utility/Enc28j60Eth.h"
 #include "UdpSocket.h"
 
 extern "C"
@@ -38,7 +38,6 @@
 uint8_t UipEthernet::       uipHeaderLen(0);
 uint8_t UipEthernet::       packetState(0);
 IpAddress UipEthernet::     dnsServerAddress;
-//DhcpClient UIPEthernet::    dhcpClient;
 
 /**
  * @brief
@@ -48,9 +47,9 @@
  */
 void enc28j60_mempool_block_move_callback(memaddress dest, memaddress src, memaddress len)
 {
-    //as ENC28J60 DMA is unable to copy single bytes:
+    //as ENC28J60 DMA is unable to copy single byte:
     if (len == 1) {
-        UipEthernet::ethernet->phy.writeByte(dest, UipEthernet::ethernet->phy.readByte(src));
+        UipEthernet::ethernet->enc28j60Eth.writeByte(dest, UipEthernet::ethernet->enc28j60Eth.readByte(src));
     }
     else {
         // calculate address of last byte
@@ -70,25 +69,25 @@
               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);
+        UipEthernet::ethernet->enc28j60Eth.writeRegPair(EDMASTL, src);
+        UipEthernet::ethernet->enc28j60Eth.writeRegPair(EDMADSTL, dest);
 
-        if ((src <= RXSTOP_INIT) && (len > RXSTOP_INIT))
-            len -= (RXSTOP_INIT - RXSTART_INIT);
-        UipEthernet::ethernet->phy.writeRegPair(EDMANDL, len);
+        if ((src <= RXEND_INIT) && (len > RXEND_INIT))
+            len -= ((RXEND_INIT + 1) - RXSTART_INIT);
+        UipEthernet::ethernet->enc28j60Eth.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);
+        UipEthernet::ethernet->enc28j60Eth.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);
+        UipEthernet::ethernet->enc28j60Eth.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);
+        while (UipEthernet::ethernet->enc28j60Eth.readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST);
     }
 }
 
@@ -97,7 +96,7 @@
  * 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),
+    enc28j60Eth(mosi, miso, sck, cs),
     _mac(new uint8_t[6]),
     _ip(),
     _dns(),
@@ -108,8 +107,6 @@
         _mac[i] = mac[i];
 }
 
-#if UIP_UDP
-
 /**
  * @brief
  * @note
@@ -147,7 +144,22 @@
         return 1;
     }
 }
-#endif
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UipEthernet::set_network(const char *ip_address, const char *netmask, const char *gateway)
+{
+    _ip = IpAddress(ip_address, strlen(ip_address));
+    _dns = _ip;
+    _dns[3] = 1;
+    _gateway = IpAddress(gateway, strlen(gateway));
+    _subnet = IpAddress(netmask, strlen(netmask));
+    set_network(_ip, _dns, _gateway, _subnet);
+}
 
 /**
  * @brief
@@ -202,6 +214,7 @@
     _dns = dns;
     _gateway = gateway;
     _subnet = IpAddress(255, 255, 255, 0);
+    set_network(_ip, _dns, _gateway, _subnet);
 }
 
 /**
@@ -324,7 +337,7 @@
 void UipEthernet::tick()
 {
     if (inPacket == NOBLOCK) {
-        inPacket = phy.receivePacket();
+        inPacket = enc28j60Eth.receivePacket();
 #ifdef UIPETHERNET_DEBUG
         if (in_packet != NOBLOCK) {
             printf("--------------\r\nreceivePacket: %d\r\n", in_packet);
@@ -334,9 +347,9 @@
 
     if (inPacket != NOBLOCK) {
         packetState = UIPETHERNET_FREEPACKET;
-        uip_len = phy.blockSize(inPacket);
+        uip_len = enc28j60Eth.blockSize(inPacket);
         if (uip_len > 0) {
-            phy.readPacket(inPacket, 0, (uint8_t*)uip_buf, UIP_BUFSIZE);
+            enc28j60Eth.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
@@ -367,7 +380,7 @@
 #ifdef UIPETHERNET_DEBUG
             printf("freeing packet: %d\r\n", in_packet);
 #endif
-            phy.freePacket();
+            enc28j60Eth.freePacket();
             inPacket = NOBLOCK;
         }
     }
@@ -431,25 +444,25 @@
 #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);
+        enc28j60Eth.writePacket(uipPacket, 0, uip_buf, uipHeaderLen);
         packetState &= ~UIPETHERNET_SENDPACKET;
         goto sendandfree;
     }
 
-    uipPacket = Enc28j60Phy::allocBlock(uip_len);
+    uipPacket = Enc28j60Eth::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);
+        enc28j60Eth.writePacket(uipPacket, 0, uip_buf, uip_len);
         goto sendandfree;
     }
 
     return false;
 sendandfree:
-    phy.sendPacket(uipPacket);
-    Enc28j60Phy::freeBlock(uipPacket);
+    enc28j60Eth.sendPacket(uipPacket);
+    Enc28j60Eth::freeBlock(uipPacket);
     uipPacket = NOBLOCK;
     return true;
 }
@@ -464,7 +477,7 @@
 {
     periodicTimer.start();
 
-    phy.init((uint8_t*)mac);
+    enc28j60Eth.init((uint8_t*)mac);
     uip_seteth_addr(mac);
 
     uip_init();
@@ -599,7 +612,7 @@
         );
 #endif
     if (upper_layer_memlen < upper_layer_len) {
-        sum = phy.chksum
+        sum = enc28j60Eth.chksum
             (
                 sum, UipEthernet::uipPacket, UIP_IPH_LEN +
                 UIP_LLH_LEN +
@@ -658,4 +671,5 @@
 
     return sum;
 }
+
 #endif
--- a/UipEthernet.h	Tue Aug 27 22:08:54 2019 +0000
+++ b/UipEthernet.h	Fri Aug 30 08:11:40 2019 +0000
@@ -18,8 +18,8 @@
  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
+#ifndef UIPETHERNET_h
+#define UIPETHERNET_h
 
 //#define UIPETHERNET_DEBUG
 //#define UIPETHERNET_DEBUG_CHKSUM
@@ -28,7 +28,7 @@
 #include "mbed.h"
 #include "DhcpClient.h"
 #include "IpAddress.h"
-#include "utility/Enc28j60Py.h"
+#include "utility/Enc28j60Eth.h"
 #include "TcpClient.h"
 #include "TcpServer.h"
 #include "UdpSocket.h"
@@ -64,7 +64,7 @@
 public:
     static UipEthernet* ethernet;
     static IpAddress    dnsServerAddress;
-    Enc28j60Phy         phy;
+    Enc28j60Eth         enc28j60Eth;
 
     UipEthernet (const uint8_t mac[6], PinName mosi, PinName miso, PinName sck, PinName cs);
 
@@ -74,6 +74,7 @@
     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              set_network(const char *ip_address, const char *netmask, const char *gateway);
     void              tick();
     IpAddress         localIP();
     IpAddress         subnetMask();
@@ -84,6 +85,7 @@
     const char*       get_gateway();
     static uint16_t   chksum(uint16_t sum, const uint8_t* data, uint16_t len);
     static uint16_t   ipchksum();
+    bool              stoip4(const char *ip4addr, size_t len, void *dest);
 private:
     uint8_t *const    _mac;
     IpAddress         _ip;
@@ -114,4 +116,5 @@
     uint16_t          uip_icmp6chksum();
 #endif
 };
+
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utility/Enc28j60Eth.cpp	Fri Aug 30 08:11:40 2019 +0000
@@ -0,0 +1,734 @@
+/*
+ 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 "Enc28j60Eth.h"
+#include "mbed.h"
+
+extern "C"
+{
+#include "enc28j60.h"
+#include "uip.h"
+}
+
+// Static member initialization
+uint16_t    Enc28j60Eth::nextPacketPtr;
+uint8_t     Enc28j60Eth::bank = 0xff;
+struct      memblock Enc28j60Eth::receivePkt;
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+Enc28j60Eth::Enc28j60Eth(PinName mosi, PinName miso, PinName sclk, PinName cs) :
+    MemPool(),
+    _spi(mosi, miso, sclk),
+    _cs(cs)
+{ }
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void Enc28j60Eth::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(20000000);   // 20 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, RXEND_INIT);
+
+    //All memory which is not used by the receive buffer is considered the transmission buffer.
+    // No explicit action is required to initialize the transmission buffer.
+    // However, he host controller should leave at least seven bytes between each
+    // packet and the beginning of the receive buffer.
+    // TX start
+    //writeRegPair(ETXSTL, TXSTART_INIT);
+    // TX end
+    //writeRegPair(ETXNDL, TXEND_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 Enc28j60Eth::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 > RXEND_INIT ? nextPacketPtr +
+            6 -
+            RXEND_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) % (RXEND_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 Enc28j60Eth::setERXRDPT()
+{
+    writeRegPair(ERXRDPTL, nextPacketPtr == RXSTART_INIT ? RXEND_INIT : nextPacketPtr - 1);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+memaddress Enc28j60Eth::blockSize(memhandle handle)
+{
+    return handle == NOBLOCK ? 0 : handle == UIP_RECEIVEBUFFERHANDLE ? receivePkt.size : blocks[handle].size;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void Enc28j60Eth::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 Enc28j60Eth::setReadPtr(memhandle handle, memaddress position, uint16_t len)
+{
+    memblock*   packet = handle == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[handle];
+    memaddress  start = handle == UIP_RECEIVEBUFFERHANDLE &&
+        packet->begin +
+        position > RXEND_INIT ? packet->begin +
+        position -
+        RXEND_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 Enc28j60Eth::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 Enc28j60Eth::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 Enc28j60Eth::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 Enc28j60Eth::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 Enc28j60Eth::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 > RXEND_INIT ? src->begin +
+        src_pos -
+        RXEND_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 Enc28j60Eth::freePacket()
+{
+    setERXRDPT();
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint8_t Enc28j60Eth::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 Enc28j60Eth::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 Enc28j60Eth::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 Enc28j60Eth::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 Enc28j60Eth::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 Enc28j60Eth::readReg(uint8_t address)
+{
+    // set the bank
+    setBank(address);
+
+    // do the read
+    return readOp(ENC28J60_READ_CTRL_REG, address);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void Enc28j60Eth::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 Enc28j60Eth::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 Enc28j60Eth::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 Enc28j60Eth::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 Enc28j60Eth::clkout(uint8_t clk)
+{
+    //setup clkout: 2 is 12.5MHz:
+    writeReg(ECOCON, clk & 0x7);
+}
+
+// read the revision of the chip:
+uint8_t Enc28j60Eth::getrev()
+{
+    return(readReg(EREVID));
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint16_t Enc28j60Eth::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 Enc28j60Eth::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 Enc28j60Eth::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 Enc28j60Eth::linkStatus()
+{
+    return(phyRead(PHSTAT2) & 0x0400) > 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utility/Enc28j60Eth.h	Fri Aug 30 08:11:40 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 Enc28j60Eth : 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:
+    Enc28j60Eth(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/Enc28j60Py.cpp	Tue Aug 27 22:08:54 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,729 +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 "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;
-}
--- a/utility/Enc28j60Py.h	Tue Aug 27 22:08:54 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +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 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/enc28j60.h	Tue Aug 27 22:08:54 2019 +0000
+++ b/utility/enc28j60.h	Fri Aug 30 08:11:40 2019 +0000
@@ -222,35 +222,36 @@
 #define PHCON2_HDLDIS    0x0100
 
 // ENC28J60 Packet Control Byte Bit Definitions
-#define PKTCTRL_PHUGEEN  0x08
-#define PKTCTRL_PPADEN   0x04
-#define PKTCTRL_PCRCEN   0x02
-#define PKTCTRL_POVERRIDE 0x01
+#define PKTCTRL_PHUGEEN         0x08
+#define PKTCTRL_PPADEN          0x04
+#define PKTCTRL_PCRCEN          0x02
+#define PKTCTRL_POVERRIDE       0x01
 
 // SPI operation codes
-#define ENC28J60_READ_CTRL_REG       0x00
-#define ENC28J60_READ_BUF_MEM        0x3A
-#define ENC28J60_WRITE_CTRL_REG      0x40
-#define ENC28J60_WRITE_BUF_MEM       0x7A
-#define ENC28J60_BIT_FIELD_SET       0x80
-#define ENC28J60_BIT_FIELD_CLR       0xA0
-#define ENC28J60_SOFT_RESET          0xFF
+#define ENC28J60_READ_CTRL_REG  0x00
+#define ENC28J60_READ_BUF_MEM   0x3A
+#define ENC28J60_WRITE_CTRL_REG 0x40
+#define ENC28J60_WRITE_BUF_MEM  0x7A
+#define ENC28J60_BIT_FIELD_SET  0x80
+#define ENC28J60_BIT_FIELD_CLR  0xA0
+#define ENC28J60_SOFT_RESET     0xFF
 
 
-// The RXSTART_INIT should be zero. See Rev. B4 Silicon Errata
-// buffer boundaries applied to internal 8K ram
-// the entire available packet buffer space is allocated
+// The RXSTART_INIT should be zero. See Silicon Errata:
+// Sometimes, when ERXST or ERXND is written to, the exact value, 0000h, is stored in the Internal
+// Receive Write Pointer instead of the ERXST address.
+// Work around
+// Use the lower segment of the buffer memory for the receive buffer, starting at address 0000h.
+// For example, use the range (0000h to n) for the receive buffer, and ((n + 1) to 8191) for the transmit buffer.
+#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)')
+#define RXEND_INIT      0x11CB      // = (3 * 1518) + 1
+// Start TX buffer RXEND_INIT + 1
+#define TXSTART_INIT    RXEND_INIT + 1
+// end TX buffer at end of mem
+#define TXEND_INIT      0x1FFF
 //
-// 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)')
-#define RXSTOP_INIT      (0x1FFF-0x1800)
-// start TX buffer 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)
+// Max frame length which the conroller will accept:
+#define MAX_FRAMELEN    1518        // (note: maximum ethernet frame length is 1518)
 
 #endif
--- a/utility/mempool_conf.h	Tue Aug 27 22:08:54 2019 +0000
+++ b/utility/mempool_conf.h	Fri Aug 30 08:11:40 2019 +0000
@@ -17,13 +17,13 @@
 #define NUM_TCP_MEMBLOCKS   0
 #endif
 #if UIP_UDP and UIP_UDP_CONNS
-#define NUM_UDP_MEMBLOCKS   3 * UIP_UDP_CONNS
+#define NUM_UDP_MEMBLOCKS   (3 * UIP_UDP_CONNS)
 #else
 #define NUM_UDP_MEMBLOCKS   0
 #endif
 #define MEMPOOL_NUM_MEMBLOCKS   (NUM_TCP_MEMBLOCKS + NUM_UDP_MEMBLOCKS)
-#define MEMPOOL_STARTADDRESS    TXSTART_INIT + 1
-#define MEMPOOL_SIZE            TXSTOP_INIT - TXSTART_INIT
+#define MEMPOOL_STARTADDRESS    (TXSTART_INIT + 1)
+#define MEMPOOL_SIZE            (TXEND_INIT - TXSTART_INIT)
 
 void  enc28j60_mempool_block_move_callback(memaddress, memaddress, memaddress);
 
--- a/utility/uip.h	Tue Aug 27 22:08:54 2019 +0000
+++ b/utility/uip.h	Fri Aug 30 08:11:40 2019 +0000
@@ -58,7 +58,7 @@
  */
 
 typedef u16_t uip_ip4addr_t[2];
-typedef u16_t           uip_ip6addr_t[8];
+typedef u16_t uip_ip6addr_t[8];
 #if UIP_CONF_IPV6
 typedef uip_ip6addr_t   uip_ipaddr_t;
 #else /* UIP_CONF_IPV6 */