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.
Diff: UIPEthernet.cpp
- Revision:
- 0:e3fb1267e3c3
- Child:
- 5:f9a2b1916a8d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/UIPEthernet.cpp Wed Dec 21 16:58:10 2016 +0100
@@ -0,0 +1,600 @@
+/*
+ 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
+ {
+ u8_t conntimer;
+ 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