Fork for fixes

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UipEthernet.cpp Source File

UipEthernet.cpp

00001 /*
00002  UIPEthernet.cpp - Arduino implementation of a UIP wrapper class.
00003  Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
00004  All rights reserved.
00005 
00006  Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.com>
00007 
00008  This program is free software: you can redistribute it and/or modify
00009  it under the terms of the GNU General Public License as published by
00010  the Free Software Foundation, either version 3 of the License, or
00011  (at your option) any later version.
00012 
00013  This program is distributed in the hope that it will be useful,
00014  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  GNU General Public License for more details.
00017 
00018  You should have received a copy of the GNU General Public License
00019  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00020   */
00021 #include "mbed.h"
00022 #include "UipEthernet.h"
00023 #include "utility/Enc28j60Eth.h"
00024 #include "UdpSocket.h"
00025 
00026 extern "C"
00027 {
00028 #include "utility/uip-conf.h"
00029 #include "utility/uip.h"
00030 #include "utility/uip_arp.h"
00031 #include "utility/uip_timer.h"
00032 }
00033 #define ETH_HDR ((struct uip_eth_hdr*) &uip_buf[0])
00034 
00035 UipEthernet* UipEthernet::  ethernet = NULL;
00036 memhandle UipEthernet::     inPacket(NOBLOCK);
00037 memhandle UipEthernet::     uipPacket(NOBLOCK);
00038 uint8_t UipEthernet::       uipHeaderLen(0);
00039 uint8_t UipEthernet::       packetState(0);
00040 IpAddress UipEthernet::     dnsServerAddress;
00041 
00042 /**
00043  * @brief
00044  * @note
00045  * @param
00046  * @retval
00047  */
00048 void enc28j60_mempool_block_move_callback(memaddress dest, memaddress src, memaddress len)
00049 {
00050     //as ENC28J60 DMA is unable to copy single byte:
00051     if (len == 1) {
00052         UipEthernet::ethernet->enc28j60Eth.writeByte(dest, UipEthernet::ethernet->enc28j60Eth.readByte(src));
00053     }
00054     else {
00055         // calculate address of last byte
00056         len += src - 1;
00057 
00058         /* 1. Appropriately program the EDMAST, EDMAND
00059               and EDMADST register pairs. The EDMAST
00060               registers should point to the first byte to copy
00061               from, the EDMAND registers should point to the
00062               last byte to copy and the EDMADST registers
00063               should point to the first byte in the destination
00064               range. The destination range will always be
00065               linear, never wrapping at any values except from
00066               8191 to 0 (the 8-Kbyte memory boundary).
00067               Extreme care should be taken when
00068               programming the start and end pointers to
00069               prevent a never ending DMA operation which
00070               would overwrite the entire 8-Kbyte buffer.
00071        */
00072         UipEthernet::ethernet->enc28j60Eth.writeRegPair(EDMASTL, src);
00073         UipEthernet::ethernet->enc28j60Eth.writeRegPair(EDMADSTL, dest);
00074 
00075         if ((src <= RXEND_INIT) && (len > RXEND_INIT))
00076             len -= ((RXEND_INIT + 1) - RXSTART_INIT);
00077         UipEthernet::ethernet->enc28j60Eth.writeRegPair(EDMANDL, len);
00078 
00079         /* 2. If an interrupt at the end of the copy process is
00080               desired, set EIE.DMAIE and EIE.INTIE and
00081               clear EIR.DMAIF.
00082 
00083            3. Verify that ECON1.CSUMEN is clear. */
00084         UipEthernet::ethernet->enc28j60Eth.writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_CSUMEN);
00085 
00086         /* 4. Start the DMA copy by setting ECON1.DMAST. */
00087         UipEthernet::ethernet->enc28j60Eth.writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST);
00088 
00089         //    wait until runnig DMA is completed
00090         while (UipEthernet::ethernet->enc28j60Eth.readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST);
00091     }
00092 }
00093 
00094 /*
00095  * Because UIP isn't encapsulated within a class we have to use global
00096  * variables, so we can only have one TCP/IP stack per program.
00097  */
00098 UipEthernet::UipEthernet(const uint8_t mac[6], PinName mosi, PinName miso, PinName sck, PinName cs) :
00099     enc28j60Eth(mosi, miso, sck, cs),
00100     _mac(new uint8_t[6]),
00101     _ip(),
00102     _dns(),
00103     _gateway(),
00104     _subnet()
00105 {
00106     for (uint8_t i = 0; i < 6; i++)
00107         _mac[i] = mac[i];
00108 }
00109 
00110 /**
00111  * @brief
00112  * @note
00113  * @param
00114  * @retval
00115  */
00116 int UipEthernet::connect(unsigned long timeout /*=60*/)
00117 {
00118     // Inicialize static pointer to the UIPEthernet instance
00119     ethernet = this;
00120 
00121     // Initialise the basic info
00122     init(_mac);
00123 
00124     // If no local IP address has been set ask DHCP server to provide one
00125     if (_ip == IpAddress()) {
00126         // Now try to get our config info from a DHCP server
00127         int ret = dhcpClient.begin((uint8_t*)_mac, timeout);
00128 
00129         if (ret == 1) {
00130             // We've successfully found a DHCP server and got our configuration info, so set things
00131             // accordingly
00132             set_network
00133             (
00134                 dhcpClient.getLocalIp(),
00135                 dhcpClient.getDnsServerIp(),
00136                 dhcpClient.getGatewayIp(),
00137                 dhcpClient.getSubnetMask()
00138             );
00139 
00140             return 0;
00141         }
00142 
00143         return -1;
00144     }
00145     else {
00146         return 0;
00147     }
00148 }
00149 
00150 /**
00151  * @brief
00152  * @note
00153  * @param
00154  * @retval
00155  */
00156 void UipEthernet::disconnect()
00157 {
00158      ethernet = NULL;
00159 }
00160 
00161 /**
00162  * @brief
00163  * @note
00164  * @param
00165  * @retval
00166  */
00167 void UipEthernet::set_network(const char *ip_address, const char *netmask, const char *gateway)
00168 {
00169     _ip = IpAddress(ip_address, strlen(ip_address));
00170     _dns = _ip;
00171     _dns[3] = 1;
00172     _gateway = IpAddress(gateway, strlen(gateway));
00173     _subnet = IpAddress(netmask, strlen(netmask));
00174     set_network(_ip, _dns, _gateway, _subnet);
00175 }
00176 
00177 /**
00178  * @brief
00179  * @note
00180  * @param
00181  * @retval
00182  */
00183 void UipEthernet::set_network(uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4)
00184 {
00185     _ip = IpAddress(octet1, octet2, octet3, octet4);
00186     set_network(_ip);
00187 }
00188 
00189 /**
00190  * @brief
00191  * @note
00192  * @param
00193  * @retval
00194  */
00195 void UipEthernet::set_network(IpAddress ip)
00196 {
00197     _ip = ip;
00198     _dns = ip;
00199     _dns[3] = 1;
00200     set_network(ip, dns);
00201 }
00202 
00203 /**
00204  * @brief
00205  * @note
00206  * @param
00207  * @retval
00208  */
00209 void UipEthernet::set_network(IpAddress ip, IpAddress dns)
00210 {
00211     _ip = ip;
00212     _dns = dns;
00213     _gateway = ip;
00214     _gateway[3] = 1;
00215     set_network(ip, dns, _gateway);
00216 }
00217 
00218 /**
00219  * @brief
00220  * @note
00221  * @param
00222  * @retval
00223  */
00224 void UipEthernet::set_network(IpAddress ip, IpAddress dns, IpAddress gateway)
00225 {
00226     _ip = ip;
00227     _dns = dns;
00228     _gateway = gateway;
00229     _subnet = IpAddress(255, 255, 255, 0);
00230     set_network(_ip, _dns, _gateway, _subnet);
00231 }
00232 
00233 /**
00234  * @brief
00235  * @note
00236  * @param
00237  * @retval
00238  */
00239 void UipEthernet::set_network(IpAddress ip, IpAddress dns, IpAddress gateway, IpAddress subnet)
00240 {
00241     uip_ipaddr_t    ipaddr;
00242 
00243     uip_ip_addr(ipaddr, ip);
00244     uip_sethostaddr(ipaddr);
00245 
00246     uip_ip_addr(ipaddr, gateway);
00247     uip_setdraddr(ipaddr);
00248 
00249     uip_ip_addr(ipaddr, subnet);
00250     uip_setnetmask(ipaddr);
00251 
00252     dnsServerAddress = dns;
00253 }
00254 
00255 /**
00256  * @brief
00257  * @note
00258  * @param
00259  * @retval
00260  */
00261 IpAddress UipEthernet::localIP()
00262 {
00263     uip_ipaddr_t    a;
00264 
00265     uip_gethostaddr(a);
00266     return ip_addr_uip(a);
00267 }
00268 
00269 /**
00270  * @brief
00271  * @note
00272  * @param
00273  * @retval
00274  */
00275 IpAddress UipEthernet::subnetMask()
00276 {
00277     uip_ipaddr_t    a;
00278 
00279     uip_getnetmask(a);
00280     return ip_addr_uip(a);
00281 }
00282 
00283 /**
00284  * @brief
00285  * @note
00286  * @param
00287  * @retval
00288  */
00289 IpAddress UipEthernet::gatewayIP()
00290 {
00291     uip_ipaddr_t    a;
00292 
00293     uip_getdraddr(a);
00294     return ip_addr_uip(a);
00295 }
00296 
00297 /**
00298  * @brief
00299  * @note
00300  * @param
00301  * @retval
00302  */
00303 IpAddress UipEthernet::dnsServerIP()
00304 {
00305     return dnsServerAddress;
00306 }
00307 
00308 /**
00309  * @brief
00310  * @note
00311  * @param
00312  * @retval
00313  */
00314 const char* UipEthernet::get_ip_address()
00315 {
00316     static char buf[16];
00317     return localIP().toString(buf);
00318 }
00319 
00320 /**
00321  * @brief
00322  * @note
00323  * @param
00324  * @retval
00325  */
00326 void UipEthernet::get_ip_address(SocketAddress* addr)
00327 {
00328     localIP().toSocketAddress(addr);
00329 }
00330 
00331 /**
00332  * @brief
00333  * @note
00334  * @param
00335  * @retval
00336  */
00337 const char* UipEthernet::get_netmask()
00338 {
00339     static char buf[16];
00340     return subnetMask().toString(buf);
00341 }
00342 
00343 /**
00344  * @brief
00345  * @note
00346  * @param
00347  * @retval
00348  */
00349 void UipEthernet::get_netmask(SocketAddress* addr)
00350 {
00351     return subnetMask().toSocketAddress(addr);
00352 }
00353 
00354 /**
00355  * @brief
00356  * @note
00357  * @param
00358  * @retval
00359  */
00360 const char* UipEthernet::get_gateway()
00361 {
00362     static char buf[16];
00363     return gatewayIP().toString(buf);
00364 }
00365 
00366 /**
00367  * @brief
00368  * @note
00369  * @param
00370  * @retval
00371  */
00372 void UipEthernet::get_gateway(SocketAddress* addr)
00373 {
00374     return gatewayIP().toSocketAddress(addr);
00375 }
00376 
00377 /**
00378  * @brief
00379  * @note
00380  * @param
00381  * @retval
00382  */
00383 const char* UipEthernet::get_mqttFromDhcp()
00384 {
00385   static char buf[16];
00386   return dhcpClient.getMqttServerIp().toString(buf);
00387 }
00388 
00389 /**
00390  * @brief
00391  * @note
00392  * @param
00393  * @retval
00394  */
00395 void UipEthernet::tick()
00396 {
00397     if (inPacket == NOBLOCK) {
00398         inPacket = enc28j60Eth.receivePacket();
00399 #ifdef UIPETHERNET_DEBUG
00400         if (inPacket != NOBLOCK) {
00401             printf("--------------\r\nreceivePacket: %d\r\n", inPacket);
00402         }
00403 #endif
00404     }
00405 
00406     if (inPacket != NOBLOCK) {
00407         packetState = UIPETHERNET_FREEPACKET;
00408         uip_len = enc28j60Eth.blockSize(inPacket);
00409         if (uip_len > 0) {
00410             enc28j60Eth.readPacket(inPacket, 0, (uint8_t*)uip_buf, UIP_BUFSIZE);
00411             if (ETH_HDR->type == HTONS(UIP_ETHTYPE_IP)) {
00412                 uipPacket = inPacket;   //required for upper_layer_checksum of in_packet!
00413 #ifdef UIPETHERNET_DEBUG
00414                 printf("readPacket type IP, uip_len: %d\r\n", uip_len);
00415 #endif
00416                 uip_arp_ipin();
00417                 uip_input();
00418                 if (uip_len > 0) {
00419                     uip_arp_out();
00420                     network_send();
00421 #ifdef UIPETHERNET_DEBUG
00422                     printf("after network_send() type IP, uip_len: %d, inPacket %d \r\n", uip_len, inPacket);
00423 #endif                    
00424                 }
00425             }
00426             else
00427             if (ETH_HDR->type == HTONS(UIP_ETHTYPE_ARP))
00428             {
00429 #ifdef UIPETHERNET_DEBUG
00430                 printf("readPacket type ARP, uip_len: %d\r\n", uip_len);
00431 #endif
00432                 uip_arp_arpin();
00433                 if (uip_len > 0) {
00434                     network_send();
00435 #ifdef UIPETHERNET_DEBUG
00436                     printf("after network_send() type ARP, uip_len: %d, inPacket %d \r\n", uip_len, inPacket);
00437 #endif                    
00438                 }
00439             }
00440         }
00441 
00442         if (inPacket != NOBLOCK && (packetState & UIPETHERNET_FREEPACKET))
00443         {
00444 #ifdef UIPETHERNET_DEBUG
00445             printf("freeing packet: %d\r\n", inPacket);
00446 #endif
00447             enc28j60Eth.freePacket();
00448             inPacket = NOBLOCK;
00449             uip_len = 0;
00450         }
00451     }
00452 
00453     bool    periodic = periodicTimer.read_ms() > UIP_PERIODIC_TIMEOUT;
00454 
00455     for (int i = 0; i < UIP_CONNS; i++) {
00456         uip_conn = &uip_conns[i];
00457         if (periodic) {
00458             uip_process(UIP_TIMER);
00459         }
00460         else {
00461             uip_userdata_t*     data = (uip_userdata_t*)uip_conn->appstate;
00462             if (data != NULL) {
00463                 if (data->pollTimer.read_ms() >= UIP_CLIENT_TIMEOUT) {
00464                     uip_process(UIP_POLL_REQUEST);
00465                     data->pollTimer.stop();
00466                     data->pollTimer.reset();
00467                 }
00468             }
00469             else
00470                 continue;
00471         }
00472 
00473         // If the above function invocation resulted in data that
00474         // should be sent out on the Enc28J60Network, the global variable
00475         // uip_len is set to a value > 0.
00476         if (uip_len > 0) {
00477             uip_arp_out();
00478             network_send();
00479         }
00480     }
00481 
00482     if (periodic) {
00483         periodicTimer.reset();
00484 #if UIP_UDP
00485         for (int i = 0; i < UIP_UDP_CONNS; i++) {
00486             uip_udp_periodic(i);
00487 
00488             // If the above function invocation resulted in data that
00489             // should be sent out on the Enc28J60Network, the global variable
00490             // uip_len is set to a value > 0.
00491             if (uip_len > 0) {
00492                 UdpSocket::_send((uip_udp_userdata_t *) (uip_udp_conns[i].appstate));
00493             }
00494         }
00495 #endif // UIP_UDP
00496     }
00497 }
00498 
00499 /**
00500  * @brief
00501  * @note
00502  * @param
00503  * @retval
00504  */
00505 bool UipEthernet::network_send()
00506 {
00507     if (packetState & UIPETHERNET_SENDPACKET)
00508     {
00509 #ifdef UIPETHERNET_DEBUG
00510         printf("Enc28J60Network_send uipPacket: %d, hdrlen: %d\r\n", inPacket, uipHeaderLen);
00511 #endif
00512         enc28j60Eth.writePacket(uipPacket, 0, uip_buf, uipHeaderLen);
00513         packetState &= ~UIPETHERNET_SENDPACKET;
00514         goto sendandfree;
00515     }
00516 
00517     uipPacket = Enc28j60Eth::allocBlock(uip_len);
00518     if (uipPacket != NOBLOCK)
00519     {
00520 #ifdef UIPETHERNET_DEBUG
00521         printf("Enc28J60Network_send uip_buf (uip_len): %d, packet: %d\r\n", uip_len, uipPacket);
00522 #endif
00523         enc28j60Eth.writePacket(uipPacket, 0, uip_buf, uip_len);
00524         goto sendandfree;
00525     }
00526 
00527 #ifdef UIPETHERNET_DEBUG
00528         printf("Enc28J60Network_send return false\r\n");
00529 #endif
00530     return false;
00531 sendandfree:
00532     enc28j60Eth.sendPacket(uipPacket);
00533     Enc28j60Eth::freeBlock(uipPacket);
00534     uipPacket = NOBLOCK;
00535     return true;
00536 }
00537 
00538 /**
00539  * @brief
00540  * @note
00541  * @param
00542  * @retval
00543  */
00544 void UipEthernet::init(const uint8_t* mac)
00545 {
00546     periodicTimer.start();
00547 
00548     enc28j60Eth.init((uint8_t*)mac);
00549     uip_seteth_addr(mac);
00550 
00551     uip_init();
00552     uip_arp_init();
00553 }
00554 
00555 /**
00556  * @brief
00557  * @note
00558  * @param
00559  * @retval
00560  */
00561 //void UIPEthernet::configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet)
00562 //{
00563 //    uip_ipaddr_t    ipaddr;
00564 //    uip_ip_addr(ipaddr, ip);
00565 //    uip_sethostaddr(ipaddr);
00566 //    uip_ip_addr(ipaddr, gateway);
00567 //    uip_setdraddr(ipaddr);
00568 //    uip_ip_addr(ipaddr, subnet);
00569 //    uip_setnetmask(ipaddr);
00570 //    dnsServerAddress = dns;
00571 //}
00572 
00573 /**
00574  * @brief
00575  * @note
00576  * @param
00577  * @retval
00578  */
00579 uint16_t UipEthernet::chksum(uint16_t sum, const uint8_t* data, uint16_t len)
00580 {
00581     uint16_t        t;
00582     const uint8_t*  dataptr;
00583     const uint8_t*  last_byte;
00584 
00585     dataptr = data;
00586     last_byte = data + len - 1;
00587 
00588     while (dataptr < last_byte) {
00589         /* At least two more bytes */
00590         t = (dataptr[0] << 8) + dataptr[1];
00591         sum += t;
00592         if (sum < t) {
00593             sum++;  /* carry */
00594         }
00595 
00596         dataptr += 2;
00597     }
00598 
00599     if (dataptr == last_byte) {
00600         t = (dataptr[0] << 8) + 0;
00601         sum += t;
00602         if (sum < t) {
00603             sum++;  /* carry */
00604         }
00605     }
00606 
00607     /* Return sum in host byte order. */
00608     return sum;
00609 }
00610 
00611 /**
00612  * @brief
00613  * @note
00614  * @param
00615  * @retval
00616  */
00617 uint16_t UipEthernet::ipchksum()
00618 {
00619     uint16_t    sum;
00620 
00621     sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN);
00622     return(sum == 0) ? 0xffff : htons(sum);
00623 }
00624 
00625 uint16_t
00626 #if UIP_UDP
00627 UipEthernet::upper_layer_chksum(uint8_t proto)
00628 #else
00629 uip_tcpchksum()
00630 #endif
00631 {
00632     uint16_t    upper_layer_len;
00633     uint16_t    sum;
00634 
00635 #if UIP_CONF_IPV6
00636     upper_layer_len = (((u16_t) (BUF->len[0]) << 8) + BUF->len[1]);
00637 #else /* UIP_CONF_IPV6 */
00638     upper_layer_len = (((u16_t) (BUF->len[0]) << 8) + BUF->len[1]) - UIP_IPH_LEN;
00639 #endif /* UIP_CONF_IPV6 */
00640 
00641     /* First sum pseudoheader. */
00642 
00643     /* IP protocol and length fields. This addition cannot carry. */
00644 #if UIP_UDP
00645     sum = upper_layer_len + proto;
00646 #else
00647     sum = upper_layer_len + UIP_PROTO_TCP;
00648 #endif
00649     /* Sum IP source and destination addresses. */
00650 
00651     sum = UipEthernet::chksum(sum, (u8_t*) &BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t));
00652 
00653     uint8_t upper_layer_memlen;
00654 #if UIP_UDP
00655     switch (proto) {
00656         //    case UIP_PROTO_ICMP:
00657         //    case UIP_PROTO_ICMP6:
00658         //      upper_layer_memlen = upper_layer_len;
00659         //      break;
00660         case UIP_PROTO_UDP:
00661             upper_layer_memlen = UIP_UDPH_LEN;
00662             break;
00663 
00664         default:
00665             //  case UIP_PROTO_TCP:
00666     #endif
00667             upper_layer_memlen = (BUF->tcpoffset >> 4) << 2;
00668     #if UIP_UDP
00669             break;
00670     }
00671 #endif
00672     sum = UipEthernet::chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_memlen);
00673 #ifdef UIPETHERNET_DEBUG_CHKSUM
00674     printf
00675         (
00676             "chksum uip_buf[%d-%d]: %d\r\n", UIP_IPH_LEN +
00677             UIP_LLH_LEN, UIP_IPH_LEN +
00678             UIP_LLH_LEN +
00679             upper_layer_memlen, htons(sum)
00680         );
00681 #endif
00682     if (upper_layer_memlen < upper_layer_len) {
00683         sum = enc28j60Eth.chksum
00684             (
00685                 sum, UipEthernet::uipPacket, UIP_IPH_LEN +
00686                 UIP_LLH_LEN +
00687                 upper_layer_memlen, upper_layer_len -
00688                 upper_layer_memlen
00689             );
00690 #ifdef UIPETHERNET_DEBUG_CHKSUM
00691         printf
00692             (
00693                 "chksum uipPacket(%d)[%d-%d]: %d\r\n", uipPacket, UIP_IPH_LEN +
00694                 UIP_LLH_LEN +
00695                 upper_layer_memlen, UIP_IPH_LEN +
00696                 UIP_LLH_LEN +
00697                 upper_layer_len, htons(sum)
00698             );
00699 #endif
00700     }
00701     return(sum == 0) ? 0xffff : htons(sum);
00702 }
00703 
00704 /**
00705  * @brief
00706  * @note
00707  * @param
00708  * @retval
00709  */
00710 uint16_t uip_ipchksum()
00711 {
00712     return UipEthernet::ethernet->ipchksum();
00713 }
00714 
00715 #if UIP_UDP
00716 
00717 /**
00718  * @brief
00719  * @note
00720  * @param
00721  * @retval
00722  */
00723 uint16_t uip_tcpchksum()
00724 {
00725     uint16_t    sum = UipEthernet::ethernet->upper_layer_chksum(UIP_PROTO_TCP);
00726 
00727     return sum;
00728 }
00729 
00730 /**
00731  * @brief
00732  * @note
00733  * @param
00734  * @retval
00735  */
00736 uint16_t uip_udpchksum()
00737 {
00738     uint16_t    sum = UipEthernet::ethernet->upper_layer_chksum(UIP_PROTO_UDP);
00739 
00740     return sum;
00741 }
00742 
00743 #endif