Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: mBuino_ENC28_MQTT Nucleo_Web_ENC28J60 Nucleo_Web_ENC28J60_ADC Serial_over_Ethernet ... more
Library for ENC28J60 Ethernet modules.

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"tomain.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.
Diff: UIPClient.cpp
- Revision:
- 0:5350a66d5279
- Child:
- 2:049ce85163c5
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/UIPClient.cpp Mon Sep 15 11:12:30 2014 +0000
@@ -0,0 +1,627 @@
+/*
+ UIPClient.cpp - Arduino implementation of a uIP wrapper class.
+ Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
+ All rights reserved.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+extern "C"
+{
+#include "uip-conf.h"
+#include "uip.h"
+#include "uip_arp.h"
+#include "string.h"
+}
+#include "UIPEthernet.h"
+#include "UIPClient.h"
+#include "Dns.h"
+
+#ifdef UIPETHERNET_DEBUG_CLIENT
+ #include "HardwareSerial.h"
+#endif
+#define UIP_TCP_PHYH_LEN UIP_LLH_LEN + UIP_IPTCPH_LEN
+
+uip_userdata_closed_t* UIPClient:: closed_conns[UIP_CONNS];
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+UIPClient::UIPClient(void) :
+ _uip_conn(NULL),
+ data(NULL) {
+ UIPEthernet.set_uip_callback(&UIPClient::uip_callback);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+UIPClient::UIPClient(struct uip_conn* conn) :
+ _uip_conn(conn),
+ data(conn ? (uip_userdata_t*)conn->appstate.user : NULL)
+{ }
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+UIPClient::UIPClient(uip_userdata_closed_t* conn_data) :
+ _uip_conn(NULL),
+ data((uip_userdata_t*)conn_data)
+{ }
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int UIPClient::connect(IPAddress ip, uint16_t port) {
+ uip_ipaddr_t ipaddr;
+ uip_ip_addr(ipaddr, ip);
+ _uip_conn = uip_connect(&ipaddr, htons(port));
+ if(_uip_conn) {
+ while((_uip_conn->tcpstateflags & UIP_TS_MASK) != UIP_CLOSED) {
+ UIPEthernet.tick();
+ if((_uip_conn->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED)
+ {
+#ifdef UIPETHERNET_DEBUG_CLIENT
+ Serial.print("connected, state: ");
+ Serial.print(((uip_userdata_t*)_uip_conn->appstate.user)->state);
+ Serial.print(", first packet in: ");
+ Serial.println(((uip_userdata_t*)_uip_conn->appstate.user)->packets_in[0]);
+#endif
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int UIPClient::connect(const char* host, uint16_t port) {
+
+ // Look up the host first
+ int ret = 0;
+#if UIP_UDP
+ DNSClient dns;
+ IPAddress remote_addr;
+
+ dns.begin(UIPEthernet.dnsServerIP());
+ ret = dns.getHostByName(host, remote_addr);
+ if(ret == 1) {
+ return connect(remote_addr, port);
+ }
+#endif
+ return ret;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UIPClient::stop(void) {
+ if(data) {
+ _flushBlocks(&data->packets_in[0]);
+ if(data->state & UIP_CLIENT_CLOSED) {
+ uip_userdata_closed_t ** cc = &UIPClient::closed_conns[0];
+ for(uint8_t i = 0; i < UIP_CONNS; i++) {
+ if(*cc == (void*)data) {
+ *cc = NULL;
+ break;
+ }
+
+ cc++;
+ }
+
+ free(data);
+ }
+ else {
+ data->state |= UIP_CLIENT_CLOSE;
+ }
+
+ data = NULL;
+ }
+
+ _uip_conn = NULL;
+ UIPEthernet.tick();
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+uint8_t UIPClient::connected(void) {
+ return((_uip_conn && (_uip_conn->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) || available() > 0) ? 1 : 0;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+bool UIPClient::operator==(const UIPClient& rhs) {
+ return _uip_conn && rhs._uip_conn && _uip_conn == rhs._uip_conn;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+UIPClient::operator bool(void) {
+ UIPEthernet.tick();
+ return(data || (_uip_conn && (data = (uip_userdata_t*)_uip_conn->appstate.user)))
+&& (!(data->state & UIP_CLIENT_CLOSED) || data->packets_in[0] != NOBLOCK);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+size_t UIPClient::write(uint8_t c) {
+ return _write(_uip_conn, &c, 1);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+size_t UIPClient::write(const uint8_t* buf, size_t size) {
+ return _write(_uip_conn, buf, size);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+size_t UIPClient::_write(struct uip_conn* conn, const uint8_t* buf, size_t size) {
+ uip_userdata_t* u;
+ int remain = size;
+ uint16_t written;
+#if UIP_ATTEMPTS_ON_WRITE > 0
+ uint16_t attempts = UIP_ATTEMPTS_ON_WRITE;
+#endif
+ repeat : UIPEthernet.tick();
+ if(conn && (u = (uip_userdata_t*)conn->appstate.user) && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_CLOSED))) {
+ memhandle* p = _currentBlock(&u->packets_out[0]);
+ if(*p == NOBLOCK)
+ {
+newpacket:
+ *p = UIPEthernet.network.allocBlock(UIP_SOCKET_DATALEN);
+ if(*p == NOBLOCK)
+ {
+#if UIP_ATTEMPTS_ON_WRITE > 0
+ if((--attempts) > 0)
+#endif
+#if UIP_ATTEMPTS_ON_WRITE != 0
+ goto repeat;
+#endif
+ goto ready;
+ }
+
+ u->out_pos = 0;
+ }
+
+#ifdef UIPETHERNET_DEBUG_CLIENT
+ Serial.print("UIPClient.write: writePacket(");
+ Serial.print(*p);
+ Serial.print(") pos: ");
+ Serial.print(u->out_pos);
+ Serial.print(", buf[");
+ Serial.print(size - remain);
+ Serial.print("-");
+ Serial.print(remain);
+ Serial.print("]: '");
+ Serial.write((uint8_t*)buf + size - remain, remain);
+ Serial.println("'");
+#endif
+ written = UIPEthernet.network.writePacket(*p, u->out_pos, (uint8_t*)buf + size - remain, remain);
+ remain -= written;
+ u->out_pos += written;
+ if(remain > 0) {
+ if(p == &u->packets_out[UIP_SOCKET_NUMPACKETS - 1])
+ {
+#if UIP_ATTEMPTS_ON_WRITE > 0
+ if((--attempts) > 0)
+#endif
+#if UIP_ATTEMPTS_ON_WRITE != 0
+ goto repeat;
+#endif
+ goto ready;
+ }
+
+ p++;
+ goto newpacket;
+ }
+
+ready:
+ return size - remain;
+ }
+
+ return -1;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int UIPClient::available(void) {
+ if(*this)
+ return _available(data);
+ return -1;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int UIPClient::_available(uip_userdata_t* u) {
+ memhandle* p = &u->packets_in[0];
+ if(*p == NOBLOCK)
+ return 0;
+
+ int len = 0;
+ for(memhandle * end = p + UIP_SOCKET_NUMPACKETS; p < end; p++) {
+ if(*p == NOBLOCK)
+ break;
+ len += UIPEthernet.network.blockSize(*p);
+ }
+
+ return len;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int UIPClient::read(uint8_t* buf, size_t size) {
+ if(*this) {
+ int remain = size;
+ memhandle* p = &data->packets_in[0];
+ if(*p == NOBLOCK)
+ return 0;
+
+ int read;
+ do
+ {
+ read = UIPEthernet.network.readPacket(*p, 0, buf + size - remain, remain);
+ if(read == UIPEthernet.network.blockSize(*p)) {
+ remain -= read;
+ _eatBlock(p);
+ if(_uip_conn && uip_stopped(_uip_conn) && !(data->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_CLOSED)))
+ data->state |= UIP_CLIENT_RESTART;
+ if(*p == NOBLOCK)
+ return size - remain;
+ }
+ else {
+ UIPEthernet.network.resizeBlock(*p, read);
+ break;
+ }
+ } while(remain > 0);
+ return size;
+ }
+
+ return -1;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int UIPClient::read(void) {
+ uint8_t c;
+ if(read(&c, 1) < 0)
+ return -1;
+ return c;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int UIPClient::peek(void) {
+ if(*this) {
+ memhandle p = data->packets_in[0];
+ if(p != NOBLOCK) {
+ uint8_t c;
+ UIPEthernet.network.readPacket(p, 0, &c, 1);
+ return c;
+ }
+ }
+
+ return -1;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UIPClient::flush(void) {
+ if(*this) {
+ _flushBlocks(&data->packets_in[0]);
+ }
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UIPClient::uip_callback(uip_tcp_appstate_t* s) {
+ uip_userdata_t* u = (uip_userdata_t*)s->user;
+ if(!u && uip_connected())
+ {
+#ifdef UIPETHERNET_DEBUG_CLIENT
+ Serial.println("UIPClient uip_connected");
+#endif
+ // We want to store some data in our connections, so allocate some space
+
+ // for it. The connection_data struct is defined in a separate .h file,
+ // due to the way the Arduino IDE works. (typedefs come after function
+ // definitions.)
+ u = (uip_userdata_t*)malloc(sizeof(uip_userdata_t));
+ if(u) {
+ memset(u, 0, sizeof(uip_userdata_t));
+ s->user = u;
+ }
+ }
+
+ if(u) {
+ if(uip_newdata())
+ {
+#ifdef UIPETHERNET_DEBUG_CLIENT
+ Serial.print("UIPClient uip_newdata, uip_len:");
+ Serial.println(uip_len);
+#endif
+ if(uip_len && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_CLOSED))) {
+ memhandle newPacket = UIPEthernet.network.allocBlock(uip_len);
+ if(newPacket != NOBLOCK) {
+ memhandle* p = _currentBlock(&u->packets_in[0]);
+ //if it's not the first packet
+
+ if(*p != NOBLOCK) {
+ uint8_t slot = p - &u->packets_in[0];
+ if(slot < UIP_SOCKET_NUMPACKETS - 1)
+ p++;
+
+ //if this is the last slot stop this connection
+ if(slot >= UIP_SOCKET_NUMPACKETS - 2) {
+ uip_stop();
+
+ //if there's no free slot left omit loosing this packet and (again) stop this connection
+ if(slot == UIP_SOCKET_NUMPACKETS - 1)
+ goto reject_newdata;
+ }
+ }
+
+ UIPEthernet.network.copyPacket
+ (
+ newPacket,
+ 0,
+ UIPEthernet.in_packet,
+ ((uint8_t*)uip_appdata) - uip_buf,
+ uip_len
+ );
+ *p = newPacket;
+ goto finish_newdata;
+ }
+
+reject_newdata:
+ UIPEthernet.packetstate &= ~UIPETHERNET_FREEPACKET;
+ uip_stop();
+ }
+ }
+
+finish_newdata:
+ if(u->state & UIP_CLIENT_RESTART) {
+ u->state &= ~UIP_CLIENT_RESTART;
+ uip_restart();
+ }
+
+ // If the connection has been closed, save received but unread data.
+ if(uip_closed() || uip_timedout())
+ {
+#ifdef UIPETHERNET_DEBUG_CLIENT
+ Serial.println("UIPClient uip_closed");
+#endif
+ // drop outgoing packets not sent yet:
+
+ _flushBlocks(&u->packets_out[0]);
+ if(u->packets_in[0] != NOBLOCK) {
+ uip_userdata_closed_t ** closed_conn_data = &UIPClient::closed_conns[0];
+ for(uip_socket_ptr i = 0; i < UIP_CONNS; i++) {
+ if(!*closed_conn_data) {
+ *closed_conn_data = (uip_userdata_closed_t*)u;
+ (*closed_conn_data)->lport = uip_conn->lport;
+ break;
+ }
+
+ closed_conn_data++;
+ }
+ }
+
+ u->state |= UIP_CLIENT_CLOSED;
+
+ // disassociate appdata.
+ s->user = NULL;
+ goto nodata;
+ }
+
+ if(uip_acked())
+ {
+#ifdef UIPETHERNET_DEBUG_CLIENT
+ Serial.println("UIPClient uip_acked");
+#endif
+ _eatBlock(&u->packets_out[0]);
+ }
+
+ if(uip_poll() || uip_rexmit())
+ {
+#ifdef UIPETHERNET_DEBUG_CLIENT
+ Serial.println("UIPClient uip_poll");
+#endif
+
+ memhandle p = u->packets_out[0];
+ if(p != NOBLOCK) {
+ if(u->packets_out[1] == NOBLOCK) {
+ uip_len = u->out_pos;
+ if(uip_len > 0) {
+ UIPEthernet.network.resizeBlock(p, 0, uip_len);
+ }
+ }
+ else
+ uip_len = UIPEthernet.network.blockSize(p);
+ if(uip_len > 0) {
+ UIPEthernet.uip_hdrlen = ((uint8_t*)uip_appdata) - uip_buf;
+ UIPEthernet.uip_packet = UIPEthernet.network.allocBlock(UIPEthernet.uip_hdrlen + uip_len);
+ if(UIPEthernet.uip_packet != NOBLOCK) {
+ UIPEthernet.network.copyPacket(UIPEthernet.uip_packet, UIPEthernet.uip_hdrlen, p, 0, uip_len);
+ UIPEthernet.packetstate |= UIPETHERNET_SENDPACKET;
+ uip_send(uip_appdata, uip_len);
+ }
+
+ return;
+ }
+ }
+ }
+
+ // don't close connection unless all outgoing packets are sent
+ if(u->state & UIP_CLIENT_CLOSE)
+ {
+#ifdef UIPETHERNET_DEBUG_CLIENT
+ Serial.print("UIPClient state UIP_CLIENT_CLOSE");
+#endif
+ if(u->packets_out[0] == NOBLOCK)
+ {
+#ifdef UIPETHERNET_DEBUG_CLIENT
+ Serial.print("UIPClient state UIP_CLIENT_CLOSE -> free userdata");
+#endif
+ free(u);
+ s->user = NULL;
+ uip_close();
+ }
+ else
+ uip_stop();
+ }
+ }
+
+nodata:
+ UIPEthernet.uip_packet = NOBLOCK;
+ uip_len = 0;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+memhandle* UIPClient::_currentBlock(memhandle* block) {
+ for(memhandle * end = block + UIP_SOCKET_NUMPACKETS - 1; block < end; block++)
+ if(*(block + 1) == NOBLOCK)
+ break;
+ return block;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UIPClient::_eatBlock(memhandle* block)
+{
+#ifdef UIPETHERNET_DEBUG_CLIENT
+ memhandle* start = block;
+ Serial.print("eatblock(");
+ Serial.print(*block);
+ Serial.print("): ");
+ for(uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) {
+ Serial.print(start[i]);
+ Serial.print(" ");
+ }
+
+ Serial.print("-> ");
+#endif
+
+ memhandle* end = block + (UIP_SOCKET_NUMPACKETS - 1);
+ UIPEthernet.network.freeBlock(*block);
+ while(block < end)
+ *block = *((block++) + 1);
+ *end = NOBLOCK;
+#ifdef UIPETHERNET_DEBUG_CLIENT
+ for(uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) {
+ Serial.print(start[i]);
+ Serial.print(" ");
+ }
+
+ Serial.println();
+#endif
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void UIPClient::_flushBlocks(memhandle* block) {
+ for(memhandle * end = block + UIP_SOCKET_NUMPACKETS; block < end; block++) {
+ if(*block != NOBLOCK) {
+ UIPEthernet.network.freeBlock(*block);
+ *block = NOBLOCK;
+ }
+ else
+ break;
+ }
+}
