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.

Revision:
0:5350a66d5279
Child:
2:049ce85163c5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UIPEthernet.cpp	Mon Sep 15 11:12:30 2014 +0000
@@ -0,0 +1,591 @@
+/*
+ UIPEthernet.cpp - Arduino implementation of a uIP wrapper class.
+ Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
+ All rights reserved.
+
+ Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+#pragma once
+#include <mbed.h>
+#include "UIPEthernet.h"
+#include "Enc28J60Network.h"
+
+#if (defined UIPETHERNET_DEBUG || defined UIPETHERNET_DEBUG_CHKSUM)
+    #include "HardwareSerial.h"
+#endif
+extern "C"
+{
+#include "uip-conf.h"
+#include "uip.h"
+#include "uip_arp.h"
+#include "uip_timer.h"
+}
+#define ETH_HDR ((struct uip_eth_hdr*) &uip_buf[0])
+
+// Because uIP isn't encapsulated within a class we have to use global
+
+// variables, so we can only have one TCP/IP stack per program.
+UIPEthernetClass::UIPEthernetClass(PinName mosi, PinName miso, PinName sck, PinName cs) :
+    network(mosi, miso, sck, cs),
+    fn_uip_cb(NULL),
+    fn_uip_udp_cb(NULL),
+    in_packet(NOBLOCK),
+    uip_packet(NOBLOCK),
+    uip_hdrlen(0),
+    packetstate(0),
+    _dhcp(NULL)
+{ }
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int UIPEthernetClass::begin(const uint8_t* mac) {
+    static DhcpClass    s_dhcp;
+    _dhcp = &s_dhcp;
+
+    // Initialise the basic info
+    init(mac);
+
+    // Now try to get our config info from a DHCP server
+    int ret = _dhcp->beginWithDHCP((uint8_t*)mac);
+    if(ret == 1) {
+
+        // We've successfully found a DHCP server and got our configuration info, so set things
+        // accordingly
+        configure(_dhcp->getLocalIp(), _dhcp->getDnsServerIp(), _dhcp->getGatewayIp(), _dhcp->getSubnetMask());
+    }
+
+    return ret;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip) {
+    IPAddress   dns = ip;
+    dns[3] = 1;
+    begin(mac, ip, dns);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns) {
+    IPAddress   gateway = ip;
+    gateway[3] = 1;
+    begin(mac, ip, dns, gateway);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway) {
+    IPAddress   subnet(255, 255, 255, 0);
+    begin(mac, ip, dns, gateway, subnet);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) {
+    init(mac);
+    configure(ip, dns, gateway, subnet);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int UIPEthernetClass::maintain(void) {
+    tick();
+
+    int rc = DHCP_CHECK_NONE;
+    if(_dhcp != NULL) {
+
+        //we have a pointer to dhcp, use it
+        rc = _dhcp->checkLease();
+        switch(rc) {
+        case DHCP_CHECK_NONE:
+            //nothing done
+            break;
+
+        case DHCP_CHECK_RENEW_OK:
+        case DHCP_CHECK_REBIND_OK:
+            //we might have got a new IP.
+            configure(_dhcp->getLocalIp(), _dhcp->getDnsServerIp(), _dhcp->getGatewayIp(), _dhcp->getSubnetMask());
+            break;
+
+        default:
+            //this is actually a error, it will retry though
+            break;
+        }
+    }
+
+    return rc;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+IPAddress UIPEthernetClass::localIP(void) {
+    IPAddress       ret;
+    uip_ipaddr_t    a;
+    uip_gethostaddr(a);
+    return ip_addr_uip(a);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+IPAddress UIPEthernetClass::subnetMask(void) {
+    IPAddress       ret;
+    uip_ipaddr_t    a;
+    uip_getnetmask(a);
+    return ip_addr_uip(a);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+IPAddress UIPEthernetClass::gatewayIP(void) {
+    IPAddress       ret;
+    uip_ipaddr_t    a;
+    uip_getdraddr(a);
+    return ip_addr_uip(a);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+IPAddress UIPEthernetClass::dnsServerIP(void) {
+    return _dnsServerAddress;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UIPEthernetClass::tick(void) {
+    if(in_packet == NOBLOCK) {
+        in_packet = network.receivePacket();
+#ifdef UIPETHERNET_DEBUG
+        if(in_packet != NOBLOCK) {
+            Serial.print("--------------\nreceivePacket: ");
+            Serial.println(in_packet);
+        }
+#endif
+    }
+
+    if(in_packet != NOBLOCK) {
+        packetstate = UIPETHERNET_FREEPACKET;
+        uip_len = network.blockSize(in_packet);
+        if(uip_len > 0) {
+            network.readPacket(in_packet, 0, (uint8_t*)uip_buf, UIP_BUFSIZE);
+            if(ETH_HDR->type == HTONS(UIP_ETHTYPE_IP)) {
+                uip_packet = in_packet;
+#ifdef UIPETHERNET_DEBUG
+                Serial.print("readPacket type IP, uip_len: ");
+                Serial.println(uip_len);
+#endif
+                uip_arp_ipin();
+                uip_input();
+                if(uip_len > 0) {
+                    uip_arp_out();
+                    network_send();
+                }
+            }
+            else
+            if(ETH_HDR->type == HTONS(UIP_ETHTYPE_ARP))
+            {
+#ifdef UIPETHERNET_DEBUG
+                Serial.print("readPacket type ARP, uip_len: ");
+                Serial.println(uip_len);
+#endif
+                uip_arp_arpin();
+                if(uip_len > 0) {
+                    network_send();
+                }
+            }
+        }
+
+        if(in_packet != NOBLOCK && (packetstate & UIPETHERNET_FREEPACKET))
+        {
+#ifdef UIPETHERNET_DEBUG
+            Serial.print("freeing packet: ");
+            Serial.println(in_packet);
+#endif
+            network.freePacket();
+            in_packet = NOBLOCK;
+        }
+    }
+
+    if(uip_timer_expired(&periodic_timer)) {
+        uip_timer_restart(&periodic_timer);
+        for(int i = 0; i < UIP_CONNS; i++) {
+            uip_periodic(i);
+
+            // If the above function invocation resulted in data that
+            // should be sent out on the network, the global variable
+            // uip_len is set to a value > 0.
+            if(uip_len > 0) {
+                uip_arp_out();
+                network_send();
+            }
+        }
+
+#if UIP_UDP
+        for(int i = 0; i < UIP_UDP_CONNS; i++) {
+            uip_udp_periodic(i);
+
+            // If the above function invocation resulted in data that
+            // should be sent out on the network, the global variable
+            // uip_len is set to a value > 0. */
+            if(uip_len > 0) {
+                network_send();
+            }
+        }
+#endif /* UIP_UDP */
+    }
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+bool UIPEthernetClass::network_send(void) {
+    if(packetstate & UIPETHERNET_SENDPACKET)
+    {
+#ifdef UIPETHERNET_DEBUG
+        Serial.print("network_send uip_packet: ");
+        Serial.print(uip_packet);
+        Serial.print(", hdrlen: ");
+        Serial.println(uip_hdrlen);
+#endif
+        network.writePacket(uip_packet, 0, uip_buf, uip_hdrlen);
+        goto sendandfree;
+    }
+
+    uip_packet = network.allocBlock(uip_len);
+    if(uip_packet != NOBLOCK)
+    {
+#ifdef UIPETHERNET_DEBUG
+        Serial.print("network_send uip_buf (uip_len): ");
+        Serial.print(uip_len);
+        Serial.print(", packet: ");
+        Serial.println(uip_packet);
+#endif
+        network.writePacket(uip_packet, 0, uip_buf, uip_len);
+        goto sendandfree;
+    }
+
+    return false;
+sendandfree:
+    network.sendPacket(uip_packet);
+    network.freeBlock(uip_packet);
+    uip_packet = NOBLOCK;
+    return true;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UIPEthernetClass::init(const uint8_t* mac) {
+    uip_timer_set(&this->periodic_timer, CLOCK_SECOND / 4);
+
+    network.init((uint8_t*)mac);
+    uip_seteth_addr(mac);
+
+    uip_init();
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UIPEthernetClass::configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) {
+    uip_ipaddr_t    ipaddr;
+
+    uip_ip_addr(ipaddr, ip);
+    uip_sethostaddr(ipaddr);
+
+    uip_ip_addr(ipaddr, gateway);
+    uip_setdraddr(ipaddr);
+
+    uip_ip_addr(ipaddr, subnet);
+    uip_setnetmask(ipaddr);
+
+    _dnsServerAddress = dns;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UIPEthernetClass::set_uip_callback(fn_uip_cb_t fn) {
+    this->fn_uip_cb = fn;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UIPEthernetClass::uip_callback(void) {
+    struct uipethernet_state*   s = &(uip_conn->appstate);
+
+    if(this->fn_uip_cb) {
+
+        // The sketch wants to handle all uIP events itself, using uIP functions.
+        this->fn_uip_cb(s); //->p, &s->user);
+    }
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UIPEthernetClass::set_uip_udp_callback(fn_uip_udp_cb_t fn) {
+    this->fn_uip_udp_cb = fn;
+}
+
+#if UIP_UDP
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UIPEthernetClass::uip_udp_callback(void) {
+    struct uipudp_state*    s = &(uip_udp_conn->appstate);
+
+    if(this->fn_uip_udp_cb) {
+
+        // The sketch wants to handle all uIP events itself, using uIP functions.
+        this->fn_uip_udp_cb(s); //->p, &s->user);
+    }
+}
+#endif
+//UIPEthernetClass UIPEthernet;
+
+// uIP callback function
+void uipethernet_appcall(void) {
+    UIPEthernet.uip_callback();
+}
+
+#if UIP_UDP
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void uipudp_appcall(void) {
+    UIPEthernet.uip_udp_callback();
+}
+#endif
+
+/*---------------------------------------------------------------------------*/
+uint16_t UIPEthernetClass::chksum(uint16_t sum, const uint8_t* data, uint16_t len) {
+    uint16_t        t;
+    const uint8_t*  dataptr;
+    const uint8_t*  last_byte;
+
+    dataptr = data;
+    last_byte = data + len - 1;
+
+    while(dataptr < last_byte) {
+
+        /* At least two more bytes */
+        t = (dataptr[0] << 8) + dataptr[1];
+        sum += t;
+        if(sum < t) {
+            sum++;  /* carry */
+        }
+
+        dataptr += 2;
+    }
+
+    if(dataptr == last_byte) {
+        t = (dataptr[0] << 8) + 0;
+        sum += t;
+        if(sum < t) {
+            sum++;  /* carry */
+        }
+    }
+
+    /* Return sum in host byte order. */
+    return sum;
+}
+
+/*---------------------------------------------------------------------------*/
+uint16_t UIPEthernetClass::ipchksum(void) {
+    uint16_t    sum;
+
+    sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN);
+    return(sum == 0) ? 0xffff : htons(sum);
+}
+
+/*---------------------------------------------------------------------------*/
+uint16_t UIPEthernetClass::upper_layer_chksum(uint8_t proto) {
+    uint16_t    upper_layer_len;
+    uint16_t    sum;
+
+#if UIP_CONF_IPV6
+    upper_layer_len = (((u16_t) (BUF->len[0]) << 8) + BUF->len[1]);
+#else /* UIP_CONF_IPV6 */
+    upper_layer_len = (((u16_t) (BUF->len[0]) << 8) + BUF->len[1]) - UIP_IPH_LEN;
+#endif /* UIP_CONF_IPV6 */
+
+    /* First sum pseudoheader. */
+
+    /* IP protocol and length fields. This addition cannot carry. */
+    sum = upper_layer_len + proto;
+
+    /* Sum IP source and destination addresses. */
+    sum = chksum(sum, (u8_t*) &BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t));
+
+    uint8_t upper_layer_memlen;
+    switch(proto) {
+    case UIP_PROTO_ICMP:
+    case UIP_PROTO_ICMP6:
+        upper_layer_memlen = upper_layer_len;
+        break;
+
+    case UIP_PROTO_TCP:
+        upper_layer_memlen = (BUF->tcpoffset >> 4) << 2;
+        break;
+#if UIP_UDP
+
+    case UIP_PROTO_UDP:
+        upper_layer_memlen = UIP_UDPH_LEN;
+        break;
+#endif
+    }
+
+    sum = chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_memlen);
+#ifdef UIPETHERNET_DEBUG_CHKSUM
+    Serial.print("chksum uip_buf[");
+    Serial.print(UIP_IPH_LEN + UIP_LLH_LEN);
+    Serial.print("-");
+    Serial.print(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen);
+    Serial.print("]: ");
+    Serial.println(htons(sum), HEX);
+#endif
+    if(upper_layer_memlen < upper_layer_len) {
+        sum = network.chksum
+            (
+                sum,
+                uip_packet,
+                UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen,
+                upper_layer_len - upper_layer_memlen
+            );
+#ifdef UIPETHERNET_DEBUG_CHKSUM
+        Serial.print("chksum uip_packet(");
+        Serial.print(uip_packet);
+        Serial.print(")[");
+        Serial.print(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen);
+        Serial.print("-");
+        Serial.print(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_len);
+        Serial.print("]: ");
+        Serial.println(htons(sum), HEX);
+#endif
+    }
+
+    return(sum == 0) ? 0xffff : htons(sum);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint16_t uip_ipchksum(void) {
+    return UIPEthernet.ipchksum();
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint16_t uip_tcpchksum(void) {
+    uint16_t    sum = UIPEthernet.upper_layer_chksum(UIP_PROTO_TCP);
+    return sum;
+}
+
+#if UIP_UDP
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint16_t uip_udpchksum(void) {
+    uint16_t    sum = UIPEthernet.upper_layer_chksum(UIP_PROTO_UDP);
+    return sum;
+}
+#endif
+
+
+