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.
UIPClient.cpp
- Committer:
- hudakz
- Date:
- 2014-12-20
- Revision:
- 2:049ce85163c5
- Parent:
- 0:5350a66d5279
- Child:
- 4:d774541a34da
File content as of revision 2:049ce85163c5:
/*
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 "utility/uip-conf.h"
#include "utility/uip.h"
#include "utility/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;
}
}
