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.
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.
UIPEthernet.cpp
- Committer:
- hudakz
- Date:
- 2014-12-20
- Revision:
- 2:049ce85163c5
- Parent:
- 0:5350a66d5279
- Child:
- 4:d774541a34da
File content as of revision 2:049ce85163c5:
/* 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 "utility/Enc28J60Network.h" #if (defined UIPETHERNET_DEBUG || defined UIPETHERNET_DEBUG_CHKSUM) #include "HardwareSerial.h" #endif extern "C" { #include "utility/uip-conf.h" #include "utility/uip.h" #include "utility/uip_arp.h" #include "utility/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