cassyarduino cassyarduino / UIPEthernet
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