UIPEthernet library for Arduino IDE, Eclipse with arduino plugin and MBED/SMeshStudio (AVR,STM32F,ESP8266,Intel ARC32,Nordic nRF51,Teensy boards,Realtek Ameba(RTL8195A,RTL8710)), ENC28j60 network chip. Compatible with Wiznet W5100 Ethernet library API. Compiled and tested on Nucleo-F302R8. Master repository is: https://github.com/UIPEthernet/UIPEthernet/
UIPEthernet.cpp
- Committer:
- cassyarduino
- Date:
- 2016-12-27
- Revision:
- 5:f9a2b1916a8d
- Parent:
- 0:e3fb1267e3c3
- Child:
- 21:c4439c50a5af
File content as of revision 5:f9a2b1916a8d:
/* UIPEthernet.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/>. */ #if defined(ARDUINO) #include <Arduino.h> #endif #if defined(__MBED__) #include <mbed.h> #include "mbed/millis.h" #endif #include "UIPEthernet.h" #include "utility/logging.h" #include "utility/Enc28J60Network.h" #include "UIPUdp.h" 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]) memhandle UIPEthernetClass::in_packet(NOBLOCK); memhandle UIPEthernetClass::uip_packet(NOBLOCK); uint8_t UIPEthernetClass::uip_hdrlen(0); uint8_t UIPEthernetClass::packetstate(0); IPAddress UIPEthernetClass::_dnsServerAddress; DhcpClass* UIPEthernetClass::_dhcp(NULL); unsigned long UIPEthernetClass::periodic_timer; static DhcpClass s_dhcp; // Placing this instance here is saving 40K to final *.bin (see bug below) // 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() { } #if UIP_UDP int UIPEthernetClass::begin(const uint8_t* mac) { #if ACTLOGLEVEL>=LOG_DEBUG_V3 LogObject.uart_send_strln(F("UIPEthernetClass::begin(const uint8_t* mac) DEBUG_V3:Function started")); #endif //static DhcpClass s_dhcp; // <-- this is a bug ! // I leave it there commented for history. It is bring all GCC "new" memory allocation code, making the *.bin almost 40K bigger. I've move it globally. _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; } #endif void UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip) { #if ACTLOGLEVEL>=LOG_DEBUG_V3 LogObject.uart_send_strln(F("UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip) DEBUG_V3:Function started")); #endif IPAddress dns = ip; dns[3] = 1; begin(mac, ip, dns); } void UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns) { #if ACTLOGLEVEL>=LOG_DEBUG_V3 LogObject.uart_send_strln(F("UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns) DEBUG_V3:Function started")); #endif IPAddress gateway = ip; gateway[3] = 1; begin(mac, ip, dns, gateway); } void UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway) { #if ACTLOGLEVEL>=LOG_DEBUG_V3 LogObject.uart_send_strln(F("UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway) DEBUG_V3:Function started")); #endif IPAddress subnet(255, 255, 255, 0); begin(mac, ip, dns, gateway, subnet); } void UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) { #if ACTLOGLEVEL>=LOG_DEBUG_V3 LogObject.uart_send_strln(F("UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) DEBUG_V3:Function started")); #endif init(mac); configure(ip,dns,gateway,subnet); } int UIPEthernetClass::maintain(){ #if ACTLOGLEVEL>=LOG_DEBUG_V3 LogObject.uart_send_strln(F("UIPEthernetClass::maintain() DEBUG_V3:Function started")); #endif tick(); int rc = DHCP_CHECK_NONE; #if UIP_UDP 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; #endif } IPAddress UIPEthernetClass::localIP() { #if ACTLOGLEVEL>=LOG_DEBUG_V3 LogObject.uart_send_strln(F("UIPEthernetClass::localIP() DEBUG_V3:Function started")); #endif IPAddress ret; uip_ipaddr_t a; uip_gethostaddr(a); return ip_addr_uip(a); } IPAddress UIPEthernetClass::subnetMask() { #if ACTLOGLEVEL>=LOG_DEBUG_V3 LogObject.uart_send_strln(F("UIPEthernetClass::subnetMask() DEBUG_V3:Function started")); #endif IPAddress ret; uip_ipaddr_t a; uip_getnetmask(a); return ip_addr_uip(a); } IPAddress UIPEthernetClass::gatewayIP() { #if ACTLOGLEVEL>=LOG_DEBUG_V3 LogObject.uart_send_strln(F("UIPEthernetClass::gatewayIP() DEBUG_V3:Function started")); #endif IPAddress ret; uip_ipaddr_t a; uip_getdraddr(a); return ip_addr_uip(a); } IPAddress UIPEthernetClass::dnsServerIP() { #if ACTLOGLEVEL>=LOG_DEBUG_V3 LogObject.uart_send_strln(F("UIPEthernetClass::dnsServerIP() DEBUG_V3:Function started")); #endif return _dnsServerAddress; } void UIPEthernetClass::tick() { #if ACTLOGLEVEL>=LOG_DEBUG_V3 LogObject.uart_send_strln(F("UIPEthernetClass::tick() DEBUG_V3:Function started")); #endif if (Enc28J60Network::geterevid()==0) { #if ACTLOGLEVEL>=LOG_ERR LogObject.uart_send_strln(F("UIPEthernetClass::tick() ERROR:EREVID=0 -> Not found ENC28j60 device !!! Function ended !!!")); #endif return; } #if defined(ESP8266) wdt_reset(); #endif if (in_packet == NOBLOCK) { in_packet = Enc28J60Network::receivePacket(); #if ACTLOGLEVEL>=LOG_DEBUG if (in_packet != NOBLOCK) { LogObject.uart_send_str(F("UIPEthernetClass::tick() DEBUG:receivePacket: ")); LogObject.uart_send_decln(in_packet); } #endif } if (in_packet != NOBLOCK) { packetstate = UIPETHERNET_FREEPACKET; uip_len = Enc28J60Network::blockSize(in_packet); if (uip_len > 0) { Enc28J60Network::readPacket(in_packet,0,(uint8_t*)uip_buf,UIP_BUFSIZE); if (ETH_HDR ->type == HTONS(UIP_ETHTYPE_IP)) { uip_packet = in_packet; //required for upper_layer_checksum of in_packet! #if ACTLOGLEVEL>=LOG_DEBUG LogObject.uart_send_str(F("UIPEthernetClass::tick() DEBUG:readPacket type IP, uip_len: ")); LogObject.uart_send_decln(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)) { #if ACTLOGLEVEL>=LOG_DEBUG LogObject.uart_send_str(F("UIPEthernetClass::tick() DEBUG:readPacket type ARP, uip_len: ")); LogObject.uart_send_decln(uip_len); #endif uip_arp_arpin(); if (uip_len > 0) { network_send(); } } } if (in_packet != NOBLOCK && (packetstate & UIPETHERNET_FREEPACKET)) { #if ACTLOGLEVEL>=LOG_DEBUG LogObject.uart_send_str(F("UIPEthernetClass::tick() DEBUG:freeing packet: ")); LogObject.uart_send_decln(in_packet); #endif Enc28J60Network::freePacket(); in_packet = NOBLOCK; } } unsigned long now = millis(); #if UIP_CLIENT_TIMER >= 0 bool periodic = (long)( now - periodic_timer ) >= 0; for (int i = 0; i < UIP_CONNS; i++) { #else if ((long)( now - periodic_timer ) >= 0) { periodic_timer = now + UIP_PERIODIC_TIMER; for (int i = 0; i < UIP_CONNS; i++) { #endif uip_conn = &uip_conns[i]; #if UIP_CLIENT_TIMER >= 0 if (periodic) { #endif uip_process(UIP_TIMER); #if UIP_CLIENT_TIMER >= 0 } else { if (uip_conn!=NULL) { if (((uip_userdata_t*)uip_conn->appstate)!=NULL) { if ((long)( now - ((uip_userdata_t*)uip_conn->appstate)->timer) >= 0) { uip_process(UIP_POLL_REQUEST); } else { continue; } } else { #if ACTLOGLEVEL>=LOG_DEBUG_V1 LogObject.uart_send_strln(F("UIPEthernetClass::tick() DEBUG_V1:((uip_userdata_t*)uip_conn->appstate) is NULL")); #endif if ((long)( now - ((uip_userdata_t*)uip_conn)->timer) >= 0) { uip_process(UIP_POLL_REQUEST); } else { continue; } } } else { #if ACTLOGLEVEL>=LOG_ERR LogObject.uart_send_strln(F("UIPEthernetClass::tick() ERROR:uip_conn is NULL")); #endif continue; } } #endif // If the above function invocation resulted in data that // should be sent out on the Enc28J60Network, the global variable // uip_len is set to a value > 0. if (uip_len > 0) { uip_arp_out(); network_send(); } } #if UIP_CLIENT_TIMER >= 0 if (periodic) { periodic_timer = now + UIP_PERIODIC_TIMER; #endif #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 Enc28J60Network, the global variable // uip_len is set to a value > 0. */ if (uip_len > 0) { UIPUDP::_send((uip_udp_userdata_t *)(uip_udp_conns[i].appstate)); } } #endif /* UIP_UDP */ } } bool UIPEthernetClass::network_send() { #if ACTLOGLEVEL>=LOG_DEBUG_V3 LogObject.uart_send_strln(F("UIPEthernetClass::network_send() DEBUG_V3:Function started")); #endif if (packetstate & UIPETHERNET_SENDPACKET) { #if ACTLOGLEVEL>=LOG_DEBUG LogObject.uart_send_str(F("UIPEthernetClass::network_send() DEBUG:uip_packet: ")); LogObject.uart_send_dec(uip_packet); LogObject.uart_send_str(F(", hdrlen: ")); LogObject.uart_send_decln(uip_hdrlen); #endif Enc28J60Network::writePacket(uip_packet,0,uip_buf,uip_hdrlen); packetstate &= ~ UIPETHERNET_SENDPACKET; goto sendandfree; } uip_packet = Enc28J60Network::allocBlock(uip_len); if (uip_packet != NOBLOCK) { #if ACTLOGLEVEL>=LOG_DEBUG LogObject.uart_send_str(F("UIPEthernetClass::network_send() DEBUG:uip_buf (uip_len): ")); LogObject.uart_send_dec(uip_len); LogObject.uart_send_str(F(", packet: ")); LogObject.uart_send_decln(uip_packet); #endif Enc28J60Network::writePacket(uip_packet,0,uip_buf,uip_len); goto sendandfree; } return false; sendandfree: Enc28J60Network::sendPacket(uip_packet); Enc28J60Network::freeBlock(uip_packet); uip_packet = NOBLOCK; return true; } void UIPEthernetClass::init(const uint8_t* mac) { #if ACTLOGLEVEL>=LOG_DEBUG_V3 LogObject.uart_send_strln(F("UIPEthernetClass::init(const uint8_t* mac) DEBUG_V3:Function started")); #endif periodic_timer = millis() + UIP_PERIODIC_TIMER; Enc28J60Network::init((uint8_t*)mac); uip_seteth_addr(mac); uip_init(); uip_arp_init(); } void UIPEthernetClass::configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) { #if ACTLOGLEVEL>=LOG_DEBUG_V3 LogObject.uart_send_strln(F("UIPEthernetClass::configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) DEBUG_V3:Function started")); #endif 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; } UIPEthernetClass UIPEthernet; /*---------------------------------------------------------------------------*/ uint16_t UIPEthernetClass::chksum(uint16_t sum, const uint8_t *data, uint16_t len) { #if ACTLOGLEVEL>=LOG_DEBUG_V3 LogObject.uart_send_strln(F("UIPEthernetClass::chksum(uint16_t sum, const uint8_t *data, uint16_t len) DEBUG_V3:Function started")); #endif 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) { #if ACTLOGLEVEL>=LOG_DEBUG_V3 LogObject.uart_send_strln(F("UIPEthernetClass::ipchksum(void) DEBUG_V3:Function started")); #endif uint16_t sum; sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN); return (sum == 0) ? 0xffff : htons(sum); } /*---------------------------------------------------------------------------*/ uint16_t #if UIP_UDP UIPEthernetClass::upper_layer_chksum(uint8_t proto) #else uip_tcpchksum(void) #endif { #if ACTLOGLEVEL>=LOG_DEBUG_V3 #if UIP_UDP LogObject.uart_send_strln(F("UIPEthernetClass::upper_layer_chksum(uint8_t proto) DEBUG_V3:Function started")); #else LogObject.uart_send_strln(F("uip_tcpchksum(void) INFO:Function started")); #endif #endif 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. */ #if UIP_UDP sum = upper_layer_len + proto; #else sum = upper_layer_len + UIP_PROTO_TCP; #endif /* Sum IP source and destination addresses. */ sum = UIPEthernetClass::chksum(sum, (u8_t *)&BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t)); uint8_t upper_layer_memlen; #if UIP_UDP switch(proto) { // case UIP_PROTO_ICMP: // case UIP_PROTO_ICMP6: // upper_layer_memlen = upper_layer_len; // break; case UIP_PROTO_UDP: upper_layer_memlen = UIP_UDPH_LEN; break; default: // case UIP_PROTO_TCP: #endif upper_layer_memlen = (BUF->tcpoffset >> 4) << 2; #if UIP_UDP break; } #endif sum = UIPEthernetClass::chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_memlen); #if ACTLOGLEVEL>=LOG_DEBUG #if UIP_UDP LogObject.uart_send_str(F("UIPEthernetClass::upper_layer_chksum(uint8_t proto) DEBUG:uip_buf[")); #else LogObject.uart_send_str(F("uip_tcpchksum(void) DEBUG:uip_buf[")); #endif LogObject.uart_send_dec(UIP_IPH_LEN + UIP_LLH_LEN); LogObject.uart_send_str(F("-")); LogObject.uart_send_dec(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen); LogObject.uart_send_str(F("]: ")); LogObject.uart_send_hexln(htons(sum)); #endif if (upper_layer_memlen < upper_layer_len) { sum = Enc28J60Network::chksum( sum, UIPEthernetClass::uip_packet, UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen, upper_layer_len - upper_layer_memlen ); #if ACTLOGLEVEL>=LOG_DEBUG #if UIP_UDP LogObject.uart_send_str(F("UIPEthernetClass::upper_layer_chksum(uint8_t proto) DEBUG:uip_packet(")); #else LogObject.uart_send_str(F("uip_tcpchksum(void) DEBUG:uip_packet(")); #endif LogObject.uart_send_dec(uip_packet); LogObject.uart_send_str(F(")[")); LogObject.uart_send_dec(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen); LogObject.uart_send_str(F("-")); LogObject.uart_send_dec(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_len); LogObject.uart_send_str(F("]: ")); LogObject.uart_send_hexln(htons(sum)); #endif } return (sum == 0) ? 0xffff : htons(sum); } uint16_t uip_ipchksum(void) { return UIPEthernet.ipchksum(); } #if UIP_UDP uint16_t uip_tcpchksum(void) { uint16_t sum = UIPEthernet.upper_layer_chksum(UIP_PROTO_TCP); return sum; } uint16_t uip_udpchksum(void) { uint16_t sum = UIPEthernet.upper_layer_chksum(UIP_PROTO_UDP); return sum; } #endif