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:
Sat Sep 07 17:42:42 2019 +0000
Parent:
14:7648334eb41b
Child:
16:269f652b4d0b
Commit message:
Timeout parameter added for the 'connect' function, SPI speed reduced from 20 to 10 Mb/s, debug messages fixed ...

Changed in this revision

DhcpClient.cpp Show annotated file Show diff for this revision Revisions of this file
DnsClient.cpp 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
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/enc28j60.h Show annotated file 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/uipethernet-conf.h Show annotated file Show diff for this revision Revisions of this file
utility/util.h Show annotated file Show diff for this revision Revisions of this file
--- a/DhcpClient.cpp	Tue Sep 03 09:16:55 2019 +0000
+++ b/DhcpClient.cpp	Sat Sep 07 17:42:42 2019 +0000
@@ -2,6 +2,7 @@
 // Author: Jordan Terrell - blog.jordanterrell.com
 #include <string.h>
 #include <stdlib.h>
+#include "UipEthernet.h"
 #include "DhcpClient.h"
 #include "utility/util.h"
 
@@ -44,54 +45,78 @@
 //return:0 on error, 1 if request is sent and response is received
 int DhcpClient::requestDhcpLease()
 {
+#ifdef UIPETHERNET_DEBUG_UDP
+    printf("requestDhcpLease(): begin\r\n");
+#endif
     uint8_t messageType = 0;
+    Timer           timer;
+
+    timer.reset();
+    timer.start();
 
     // Pick an initial transaction ID
-    srand(time(NULL));
+    srand(time(NULL)+ 1);
     _dhcpTransactionId = (rand() % 2000UL) + 1;
     _dhcpInitialTransactionId = _dhcpTransactionId;
 
     _dhcpUdpSocket.stop();
     if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0) {
         // Couldn't get a socket
+#ifdef UIPETHERNET_DEBUG_UDP
+        printf("requestDhcpLease(): Couldn't get a socket\r\n");
+#endif
         return 0;
     }
 
     presendDhcp();
 
     volatile int    result = 0;
-    time_t          startTime = time(NULL);
 
     while (_dhcp_state != STATE_DHCP_LEASED) {
         if (_dhcp_state == STATE_DHCP_START) {
+#ifdef UIPETHERNET_DEBUG_UDP
+            printf("_dhcp_state: STATE_DHCP_START\r\n");
+#endif
             _dhcpTransactionId++;
 
-            sendDhcpMessage(DHCP_DISCOVER, (time(NULL) - startTime));
+            sendDhcpMessage(DHCP_DISCOVER, (timer.read_ms() / 1000 + 1));
             _dhcp_state = STATE_DHCP_DISCOVER;
         }
         else
         if (_dhcp_state == STATE_DHCP_REREQUEST) {
+#ifdef UIPETHERNET_DEBUG_UDP
+            printf("_dhcp_state: STATE_DHCP_REREQUEST\r\n");
+#endif
             _dhcpTransactionId++;
-            sendDhcpMessage(DHCP_REQUEST, (time(NULL) - startTime));
+            sendDhcpMessage(DHCP_REQUEST, (timer.read_ms() / 1000 + 1));
             _dhcp_state = STATE_DHCP_REQUEST;
         }
         else
         if (_dhcp_state == STATE_DHCP_DISCOVER) {
+#ifdef UIPETHERNET_DEBUG_UDP
+            printf("_dhcp_state: STATE_DHCP_DISCOVER\r\n");
+#endif
             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));
+                sendDhcpMessage(DHCP_REQUEST, (timer.read_ms() / 1000 + 1));
                 _dhcp_state = STATE_DHCP_REQUEST;
             }
         }
         else
         if (_dhcp_state == STATE_DHCP_REQUEST) {
+#ifdef UIPETHERNET_DEBUG_UDP
+            printf("_dhcp_state: STATE_DHCP_REQUEST\r\n");
+#endif
             uint32_t    respId;
             messageType = parseDhcpResponse(_responseTimeout, respId);
             if (messageType == DHCP_ACK) {
+#ifdef UIPETHERNET_DEBUG_UDP
+                printf("messageType: DHCP_ACK\r\n");
+#endif
                 _dhcp_state = STATE_DHCP_LEASED;
                 result = 1;
 
@@ -115,23 +140,37 @@
                 _rebindInSec = _dhcpT2;
             }
             else
-            if (messageType == DHCP_NAK)
+            if (messageType == DHCP_NAK) {
+ #ifdef UIPETHERNET_DEBUG_UDP
+                printf("messageType: DHCP_NAK\r\n");
+#endif
                 _dhcp_state = STATE_DHCP_START;
+            }
         }
 
         if (messageType == 255) {
+#ifdef UIPETHERNET_DEBUG_UDP
+            printf("DHCP_NAK: 255\r\n");
+#endif
             messageType = 0;
             _dhcp_state = STATE_DHCP_START;
         }
 
-        if ((result != 1) && ((time(NULL) - startTime) > _timeout))
+        if ((result != 1) && ((timer.read_ms() / 1000) > _timeout)) {
+#ifdef UIPETHERNET_DEBUG_UDP
+            printf("requestDhcpLease(): timeout\r\n");
+#endif
             break;
+        }
     }
 
     // We're done with the socket now
     _dhcpUdpSocket.stop();
     _dhcpTransactionId++;
 
+#ifdef UIPETHERNET_DEBUG_UDP
+    printf("requestDhcpLease(): %d\r\n", result);
+#endif
     return result;
 }
 
@@ -182,17 +221,17 @@
     // yiaddr: already zeroed
     // siaddr: already zeroed
     // giaddr: already zeroed
-    //put data in W5100 transmit buffer
+    //put data in ENC28J60 transmit buffer
     _dhcpUdpSocket.write(buffer, 28);
 
     memset(buffer, 0, 32);                      // clear local buffer
     memcpy(buffer, _dhcpMacAddr, 6);            // chaddr
-    //put data in W5100 transmit buffer
+    //put data in ENC28J60 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)
+    // put in ENC28J60 transmit buffer x 6 (192 bytes)
     for (int i = 0; i < 6; i++) {
         _dhcpUdpSocket.write(buffer, 32);
     }
@@ -222,7 +261,7 @@
     printByte((char*) &(buffer[26]), _dhcpMacAddr[4]);
     printByte((char*) &(buffer[28]), _dhcpMacAddr[5]);
 
-    //put data in W5100 transmit buffer
+    //put data in ENC28J60 transmit buffer
     _dhcpUdpSocket.write(buffer, 30);
 
     if (messageType == DHCP_REQUEST) {
@@ -242,7 +281,7 @@
         buffer[10] = _dhcpDhcpServerIp[2];
         buffer[11] = _dhcpDhcpServerIp[3];
 
-        //put data in W5100 transmit buffer
+        //put data in ENC28J60 transmit buffer
         _dhcpUdpSocket.write(buffer, 12);
     }
 
@@ -256,7 +295,7 @@
     buffer[7] = dhcpT2value;
     buffer[8] = endOption;
 
-    //put data in W5100 transmit buffer
+    //put data in ENC28J60 transmit buffer
     _dhcpUdpSocket.write(buffer, 9);
 
     _dhcpUdpSocket.endPacket();
@@ -272,11 +311,12 @@
 {
     volatile uint8_t    type = 0;
     uint8_t             opt_len = 0;
+    Timer               timer;
 
-    unsigned long       startTime = time(NULL);
+    timer.start();
 
     while (_dhcpUdpSocket.parsePacket() <= 0) {
-        if ((time(NULL) - startTime) > responseTimeout) {
+        if (timer.read() > responseTimeout) {
             return 255;
         }
 
--- a/DnsClient.cpp	Tue Sep 03 09:16:55 2019 +0000
+++ b/DnsClient.cpp	Sat Sep 07 17:42:42 2019 +0000
@@ -128,6 +128,9 @@
 int DnsClient::getHostByName(const char* aHostname, IpAddress& aResult)
 {
     int ret = 0;
+    Timer   timer;
+
+    timer.start();
 
     // See if it's a numeric IP address
     if (inet_aton(aHostname, aResult)) {
@@ -141,7 +144,7 @@
     }
 
     // Find a socket to use
-    if (iUdp.begin(1024 + (time(NULL) & 0xF)) == 1) {
+    if (iUdp.begin(1024 + ((timer.read_ms() / 1000) & 0xF)) == 1) {
         // Try up to three times
         int retries = 0;
         //        while ((retries < 3) && (ret <= 0))
@@ -202,7 +205,7 @@
     //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     // As we only support one request at a time at present, we can simplify
     // some of this header
-    srand(time(NULL));
+    srand(time(NULL) + 2);
     iRequestId = rand() % 0xFFFF + 1;   // generate a random ID
     uint16_t    twoByteBuffer;
 
@@ -273,12 +276,15 @@
 int16_t DnsClient::processResponse(uint16_t aTimeout, IpAddress& aAddress)
 {
     time_t  startTime = time(NULL);
+    Timer   timer;
+
+    timer.start();
 
     // Wait for a response packet
     while (iUdp.parsePacket() <= 0) {
-        if ((time(NULL) - startTime) > aTimeout)
+        if (timer.read() > aTimeout)
             return TIMED_OUT;
-        wait(0.050);
+        wait_ms(50);
     }
 
     // We've had a reply!
--- a/UdpSocket.cpp	Tue Sep 03 09:16:55 2019 +0000
+++ b/UdpSocket.cpp	Sat Sep 07 17:42:42 2019 +0000
@@ -148,7 +148,8 @@
         }
 
 #ifdef UIPETHERNET_DEBUG_UDP
-        printf("rip: %s, port: %d\r\n", ip.asString(), port);
+        char buf[16];
+        printf("rip: %s, port: %d\r\n", ip.toString(buf), port);
 #endif
     }
 
@@ -156,17 +157,20 @@
         if (appdata.packet_out == NOBLOCK) {
             appdata.packet_out = UipEthernet::ethernet->enc28j60Eth.allocBlock(UIP_UDP_MAXPACKETSIZE);
             appdata.out_pos = UIP_UDP_PHYH_LEN;
-            if (appdata.packet_out != NOBLOCK)
+            if (appdata.packet_out != NOBLOCK) {
                 return 1;
+            }
 #ifdef UIPETHERNET_DEBUG_UDP
-            else
+            else {
                 printf("failed to allocate memory for packet\r\n");
+            }
 #endif
         }
 
 #ifdef UIPETHERNET_DEBUG_UDP
-        else
+        else {
             printf("previous packet on that connection not sent yet\r\n");
+        }
 #endif
     }
 
@@ -363,7 +367,7 @@
                     (
                         "udp, uip_newdata received packet: %d, size: %d\r\n",
                         data->packet_next,
-                        UIPEthernet.network.blockSize(data->packet_next)
+                        UipEthernet::ethernet->enc28j60Eth.blockSize(data->packet_next)
                     );
 #endif
                 }
@@ -378,7 +382,7 @@
             (
                 "udp, uip_poll preparing packet to send: %d, size: %d\r\n",
                 data->packet_out,
-                UIPEthernet.network.blockSize(data->packet_out)
+                UipEthernet::ethernet->enc28j60Eth.blockSize(data->packet_out)
             );
 #endif
             UipEthernet::uipPacket = data->packet_out;
@@ -410,7 +414,7 @@
         data->packet_out = NOBLOCK;
         UipEthernet::packetState |= UIPETHERNET_SENDPACKET;
 #ifdef UIPETHERNET_DEBUG_UDP
-        printf("udp, uip_packet to send: %d\r\n", UIPEthernet::uip_packet);
+        printf("udp, uip_packet to send: %d\r\n", UipEthernet::uipPacket);
 #endif
     }
 
--- a/UipEthernet.cpp	Tue Sep 03 09:16:55 2019 +0000
+++ b/UipEthernet.cpp	Sat Sep 07 17:42:42 2019 +0000
@@ -113,7 +113,7 @@
  * @param
  * @retval
  */
-int UipEthernet::connect()
+int UipEthernet::connect(unsigned long timeout)
 {
     // Inicialize static pointer to the UIPEthernet instance
     ethernet = this;
@@ -124,7 +124,7 @@
     // 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);
+        int ret = dhcpClient.begin((uint8_t*)_mac, timeout);
 
         if (ret == 1) {
             // We've successfully found a DHCP server and got our configuration info, so set things
@@ -352,8 +352,8 @@
     if (inPacket == NOBLOCK) {
         inPacket = enc28j60Eth.receivePacket();
 #ifdef UIPETHERNET_DEBUG
-        if (in_packet != NOBLOCK) {
-            printf("--------------\r\nreceivePacket: %d\r\n", in_packet);
+        if (inPacket != NOBLOCK) {
+            printf("--------------\r\nreceivePacket: %d\r\n", inPacket);
         }
 #endif
     }
@@ -391,7 +391,7 @@
         if (inPacket != NOBLOCK && (packetState & UIPETHERNET_FREEPACKET))
         {
 #ifdef UIPETHERNET_DEBUG
-            printf("freeing packet: %d\r\n", in_packet);
+            printf("freeing packet: %d\r\n", inPacket);
 #endif
             enc28j60Eth.freePacket();
             inPacket = NOBLOCK;
@@ -455,7 +455,7 @@
     if (packetState & UIPETHERNET_SENDPACKET)
     {
 #ifdef UIPETHERNET_DEBUG
-        printf("Enc28J60Network_send uip_packet: %d, hdrlen: %d\r\n", uip_packet, uip_hdrlen);
+        printf("Enc28J60Network_send uipPacket: %d, hdrlen: %d\r\n", inPacket, uipHeaderLen);
 #endif
         enc28j60Eth.writePacket(uipPacket, 0, uip_buf, uipHeaderLen);
         packetState &= ~UIPETHERNET_SENDPACKET;
@@ -466,12 +466,15 @@
     if (uipPacket != NOBLOCK)
     {
 #ifdef UIPETHERNET_DEBUG
-        printf("Enc28J60Network_send uip_buf (uip_len): %d, packet: %d\r\n", uip_len, uip_packet);
+        printf("Enc28J60Network_send uip_buf (uip_len): %d, packet: %d\r\n", uip_len, uipPacket);
 #endif
         enc28j60Eth.writePacket(uipPacket, 0, uip_buf, uip_len);
         goto sendandfree;
     }
 
+#ifdef UIPETHERNET_DEBUG
+        printf("Enc28J60Network_send return false\r\n");
+#endif
     return false;
 sendandfree:
     enc28j60Eth.sendPacket(uipPacket);
@@ -635,7 +638,7 @@
 #ifdef UIPETHERNET_DEBUG_CHKSUM
         printf
             (
-                "chksum uip_packet(%d)[%d-%d]: %d\r\n", uip_packet, UIP_IPH_LEN +
+                "chksum uipPacket(%d)[%d-%d]: %d\r\n", uipPacket, UIP_IPH_LEN +
                 UIP_LLH_LEN +
                 upper_layer_memlen, UIP_IPH_LEN +
                 UIP_LLH_LEN +
--- a/UipEthernet.h	Tue Sep 03 09:16:55 2019 +0000
+++ b/UipEthernet.h	Sat Sep 07 17:42:42 2019 +0000
@@ -39,26 +39,6 @@
 #include "utility/uip.h"
 #include "utility/util.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
 {
@@ -69,7 +49,7 @@
 
     UipEthernet (const uint8_t mac[6], PinName mosi, PinName miso, PinName sck, PinName cs);
 
-    int               connect();
+    int               connect(unsigned long timeout = 60);
     void              disconnect();
     void              set_network(uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4);
     void              set_network(IpAddress ip);
--- a/utility/Enc28j60Eth.cpp	Tue Sep 03 09:16:55 2019 +0000
+++ b/utility/Enc28j60Eth.cpp	Sat Sep 07 17:42:42 2019 +0000
@@ -57,20 +57,21 @@
  */
 void Enc28j60Eth::init(uint8_t* macaddr)
 {
-    MemPool::init();           // 1 byte in between RX_STOP_INIT and pool to allow prepending of controlbyte
+    MemPool::init();            // 1 byte in between RX_STOP_INIT and pool to allow prepending of controlbyte
+    
     // initialize SPI interface
+    _cs = 1;
     _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;
+    _spi.frequency(10000000);   // 10 Mbit/s
+    wait_ms(100);               // for stable state
 
     // 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.
+    // 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
@@ -90,18 +91,18 @@
 
     //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);
+    // However, he host controller should leave at least seven bytes between each
+    // packet and the beginning of the receive buffer.
 
     // 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
+    // The pattern to match is therefore
     // Type     ETH.DST
     // ARP      BROADCAST
     // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9
@@ -370,7 +371,9 @@
 
     // read data
     result = _spi.write(0x00);
+    
     _cs = 1;
+    
     return(result);
 }
 
@@ -391,6 +394,7 @@
 
     // write data
     _spi.write(data);
+    
     _cs = 1;
 }
 
@@ -458,7 +462,6 @@
     if (address & 0x80)
         result = _spi.write(0x00);
 
-    // release CS
     _cs = 1;
     return(result);
 }
@@ -478,6 +481,7 @@
 
     // write data
     _spi.write(data);
+    
     _cs = 1;
 }
 
@@ -493,15 +497,16 @@
 
     // issue read command
     _spi.write(ENC28J60_READ_BUF_MEM);
+ 
+    // read data
     while (len) {
         len--;
-
-        // read data
         *data = _spi.write(0x00);
         data++;
     }
 
     *data = '\0';
+    
     _cs = 1;
 }
 
@@ -517,10 +522,10 @@
 
     // issue write command
     _spi.write(ENC28J60_WRITE_BUF_MEM);
+
+    // write data
     while (len) {
         len--;
-
-        // write data
         _spi.write(*data);
         data++;
     }
--- a/utility/enc28j60.h	Tue Sep 03 09:16:55 2019 +0000
+++ b/utility/enc28j60.h	Sat Sep 07 17:42:42 2019 +0000
@@ -240,12 +240,12 @@
 // 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
+// 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
+#define RXEND_INIT    (0x1FFF - 0x1800) // 0x1800 = 512 * 12
 // Start TX buffer RXEND_INIT + 1
 #define TXSTART_INIT    RXEND_INIT + 1
 // end TX buffer at end of mem
--- a/utility/uip-conf.h	Tue Sep 03 09:16:55 2019 +0000
+++ b/utility/uip-conf.h	Sat Sep 07 17:42:42 2019 +0000
@@ -85,7 +85,7 @@
  *
  * \hideinitializer
  */
-#define UIP_CONF_MAX_LISTENPORTS    5
+#define UIP_CONF_MAX_LISTENPORTS    4
 
 /**
  * UIP buffer size.
--- a/utility/uipethernet-conf.h	Tue Sep 03 09:16:55 2019 +0000
+++ b/utility/uipethernet-conf.h	Sat Sep 07 17:42:42 2019 +0000
@@ -4,14 +4,14 @@
 /* for TCP */
 
 #define UIP_SOCKET_NUMPACKETS   5
-#define UIP_MAX_CONNECTIONS     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      5
+#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 */
--- a/utility/util.h	Tue Sep 03 09:16:55 2019 +0000
+++ b/utility/util.h	Sat Sep 07 17:42:42 2019 +0000
@@ -5,4 +5,25 @@
 //#define ntohs(x)    htons(x)
 #define htonl(x)    (((x) << 24 & 0xFF000000UL) | ((x) << 8 & 0x00FF0000UL) | ((x) >> 8 & 0x0000FF00UL) | ((x) >> 24 & 0x000000FFUL))
 #define ntohl(x)    htonl(x)
+#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])
+
 #endif