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

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 void UipEthernet::tick()
00384 {
00385     if (inPacket == NOBLOCK) {
00386         inPacket = enc28j60Eth.receivePacket();
00387 #ifdef UIPETHERNET_DEBUG
00388         if (inPacket != NOBLOCK) {
00389             printf("--------------\r\nreceivePacket: %d\r\n", inPacket);
00390         }
00391 #endif
00392     }
00393 
00394     if (inPacket != NOBLOCK) {
00395         packetState = UIPETHERNET_FREEPACKET;
00396         uip_len = enc28j60Eth.blockSize(inPacket);
00397         if (uip_len > 0) {
00398             enc28j60Eth.readPacket(inPacket, 0, (uint8_t*)uip_buf, UIP_BUFSIZE);
00399             if (ETH_HDR->type == HTONS(UIP_ETHTYPE_IP)) {
00400                 uipPacket = inPacket;   //required for upper_layer_checksum of in_packet!
00401 #ifdef UIPETHERNET_DEBUG
00402                 printf("readPacket type IP, uip_len: %d\r\n", uip_len);
00403 #endif
00404                 uip_arp_ipin();
00405                 uip_input();
00406                 if (uip_len > 0) {
00407                     uip_arp_out();
00408                     network_send();
00409                 }
00410             }
00411             else
00412             if (ETH_HDR->type == HTONS(UIP_ETHTYPE_ARP))
00413             {
00414 #ifdef UIPETHERNET_DEBUG
00415                 printf("readPacket type ARP, uip_len: %d\r\n", uip_len);
00416 #endif
00417                 uip_arp_arpin();
00418                 if (uip_len > 0) {
00419                     network_send();
00420                 }
00421             }
00422         }
00423 
00424         if (inPacket != NOBLOCK && (packetState & UIPETHERNET_FREEPACKET))
00425         {
00426 #ifdef UIPETHERNET_DEBUG
00427             printf("freeing packet: %d\r\n", inPacket);
00428 #endif
00429             enc28j60Eth.freePacket();
00430             inPacket = NOBLOCK;
00431         }
00432     }
00433 
00434     bool    periodic = periodicTimer.read_ms() > UIP_PERIODIC_TIMEOUT;
00435 
00436     for (int i = 0; i < UIP_CONNS; i++) {
00437         uip_conn = &uip_conns[i];
00438         if (periodic) {
00439             uip_process(UIP_TIMER);
00440         }
00441         else {
00442             uip_userdata_t*     data = (uip_userdata_t*)uip_conn->appstate;
00443             if (data != NULL) {
00444                 if (data->pollTimer.read_ms() >= UIP_CLIENT_TIMEOUT) {
00445                     uip_process(UIP_POLL_REQUEST);
00446                     data->pollTimer.stop();
00447                     data->pollTimer.reset();
00448                 }
00449             }
00450             else
00451                 continue;
00452         }
00453 
00454         // If the above function invocation resulted in data that
00455         // should be sent out on the Enc28J60Network, the global variable
00456         // uip_len is set to a value > 0.
00457         if (uip_len > 0) {
00458             uip_arp_out();
00459             network_send();
00460         }
00461     }
00462 
00463     if (periodic) {
00464         periodicTimer.reset();
00465 #if UIP_UDP
00466         for (int i = 0; i < UIP_UDP_CONNS; i++) {
00467             uip_udp_periodic(i);
00468 
00469             // If the above function invocation resulted in data that
00470             // should be sent out on the Enc28J60Network, the global variable
00471             // uip_len is set to a value > 0.
00472             if (uip_len > 0) {
00473                 UdpSocket::_send((uip_udp_userdata_t *) (uip_udp_conns[i].appstate));
00474             }
00475         }
00476 #endif // UIP_UDP
00477     }
00478 }
00479 
00480 /**
00481  * @brief
00482  * @note
00483  * @param
00484  * @retval
00485  */
00486 bool UipEthernet::network_send()
00487 {
00488     if (packetState & UIPETHERNET_SENDPACKET)
00489     {
00490 #ifdef UIPETHERNET_DEBUG
00491         printf("Enc28J60Network_send uipPacket: %d, hdrlen: %d\r\n", inPacket, uipHeaderLen);
00492 #endif
00493         enc28j60Eth.writePacket(uipPacket, 0, uip_buf, uipHeaderLen);
00494         packetState &= ~UIPETHERNET_SENDPACKET;
00495         goto sendandfree;
00496     }
00497 
00498     uipPacket = Enc28j60Eth::allocBlock(uip_len);
00499     if (uipPacket != NOBLOCK)
00500     {
00501 #ifdef UIPETHERNET_DEBUG
00502         printf("Enc28J60Network_send uip_buf (uip_len): %d, packet: %d\r\n", uip_len, uipPacket);
00503 #endif
00504         enc28j60Eth.writePacket(uipPacket, 0, uip_buf, uip_len);
00505         goto sendandfree;
00506     }
00507 
00508 #ifdef UIPETHERNET_DEBUG
00509         printf("Enc28J60Network_send return false\r\n");
00510 #endif
00511     return false;
00512 sendandfree:
00513     enc28j60Eth.sendPacket(uipPacket);
00514     Enc28j60Eth::freeBlock(uipPacket);
00515     uipPacket = NOBLOCK;
00516     return true;
00517 }
00518 
00519 /**
00520  * @brief
00521  * @note
00522  * @param
00523  * @retval
00524  */
00525 void UipEthernet::init(const uint8_t* mac)
00526 {
00527     periodicTimer.start();
00528 
00529     enc28j60Eth.init((uint8_t*)mac);
00530     uip_seteth_addr(mac);
00531 
00532     uip_init();
00533     uip_arp_init();
00534 }
00535 
00536 /**
00537  * @brief
00538  * @note
00539  * @param
00540  * @retval
00541  */
00542 //void UIPEthernet::configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet)
00543 //{
00544 //    uip_ipaddr_t    ipaddr;
00545 //    uip_ip_addr(ipaddr, ip);
00546 //    uip_sethostaddr(ipaddr);
00547 //    uip_ip_addr(ipaddr, gateway);
00548 //    uip_setdraddr(ipaddr);
00549 //    uip_ip_addr(ipaddr, subnet);
00550 //    uip_setnetmask(ipaddr);
00551 //    dnsServerAddress = dns;
00552 //}
00553 
00554 /**
00555  * @brief
00556  * @note
00557  * @param
00558  * @retval
00559  */
00560 uint16_t UipEthernet::chksum(uint16_t sum, const uint8_t* data, uint16_t len)
00561 {
00562     uint16_t        t;
00563     const uint8_t*  dataptr;
00564     const uint8_t*  last_byte;
00565 
00566     dataptr = data;
00567     last_byte = data + len - 1;
00568 
00569     while (dataptr < last_byte) {
00570         /* At least two more bytes */
00571         t = (dataptr[0] << 8) + dataptr[1];
00572         sum += t;
00573         if (sum < t) {
00574             sum++;  /* carry */
00575         }
00576 
00577         dataptr += 2;
00578     }
00579 
00580     if (dataptr == last_byte) {
00581         t = (dataptr[0] << 8) + 0;
00582         sum += t;
00583         if (sum < t) {
00584             sum++;  /* carry */
00585         }
00586     }
00587 
00588     /* Return sum in host byte order. */
00589     return sum;
00590 }
00591 
00592 /**
00593  * @brief
00594  * @note
00595  * @param
00596  * @retval
00597  */
00598 uint16_t UipEthernet::ipchksum()
00599 {
00600     uint16_t    sum;
00601 
00602     sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN);
00603     return(sum == 0) ? 0xffff : htons(sum);
00604 }
00605 
00606 uint16_t
00607 #if UIP_UDP
00608 UipEthernet::upper_layer_chksum(uint8_t proto)
00609 #else
00610 uip_tcpchksum()
00611 #endif
00612 {
00613     uint16_t    upper_layer_len;
00614     uint16_t    sum;
00615 
00616 #if UIP_CONF_IPV6
00617     upper_layer_len = (((u16_t) (BUF->len[0]) << 8) + BUF->len[1]);
00618 #else /* UIP_CONF_IPV6 */
00619     upper_layer_len = (((u16_t) (BUF->len[0]) << 8) + BUF->len[1]) - UIP_IPH_LEN;
00620 #endif /* UIP_CONF_IPV6 */
00621 
00622     /* First sum pseudoheader. */
00623 
00624     /* IP protocol and length fields. This addition cannot carry. */
00625 #if UIP_UDP
00626     sum = upper_layer_len + proto;
00627 #else
00628     sum = upper_layer_len + UIP_PROTO_TCP;
00629 #endif
00630     /* Sum IP source and destination addresses. */
00631 
00632     sum = UipEthernet::chksum(sum, (u8_t*) &BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t));
00633 
00634     uint8_t upper_layer_memlen;
00635 #if UIP_UDP
00636     switch (proto) {
00637         //    case UIP_PROTO_ICMP:
00638         //    case UIP_PROTO_ICMP6:
00639         //      upper_layer_memlen = upper_layer_len;
00640         //      break;
00641         case UIP_PROTO_UDP:
00642             upper_layer_memlen = UIP_UDPH_LEN;
00643             break;
00644 
00645         default:
00646             //  case UIP_PROTO_TCP:
00647     #endif
00648             upper_layer_memlen = (BUF->tcpoffset >> 4) << 2;
00649     #if UIP_UDP
00650             break;
00651     }
00652 #endif
00653     sum = UipEthernet::chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_memlen);
00654 #ifdef UIPETHERNET_DEBUG_CHKSUM
00655     printf
00656         (
00657             "chksum uip_buf[%d-%d]: %d\r\n", UIP_IPH_LEN +
00658             UIP_LLH_LEN, UIP_IPH_LEN +
00659             UIP_LLH_LEN +
00660             upper_layer_memlen, htons(sum)
00661         );
00662 #endif
00663     if (upper_layer_memlen < upper_layer_len) {
00664         sum = enc28j60Eth.chksum
00665             (
00666                 sum, UipEthernet::uipPacket, UIP_IPH_LEN +
00667                 UIP_LLH_LEN +
00668                 upper_layer_memlen, upper_layer_len -
00669                 upper_layer_memlen
00670             );
00671 #ifdef UIPETHERNET_DEBUG_CHKSUM
00672         printf
00673             (
00674                 "chksum uipPacket(%d)[%d-%d]: %d\r\n", uipPacket, UIP_IPH_LEN +
00675                 UIP_LLH_LEN +
00676                 upper_layer_memlen, UIP_IPH_LEN +
00677                 UIP_LLH_LEN +
00678                 upper_layer_len, htons(sum)
00679             );
00680 #endif
00681     }
00682     return(sum == 0) ? 0xffff : htons(sum);
00683 }
00684 
00685 /**
00686  * @brief
00687  * @note
00688  * @param
00689  * @retval
00690  */
00691 uint16_t uip_ipchksum()
00692 {
00693     return UipEthernet::ethernet->ipchksum();
00694 }
00695 
00696 #if UIP_UDP
00697 
00698 /**
00699  * @brief
00700  * @note
00701  * @param
00702  * @retval
00703  */
00704 uint16_t uip_tcpchksum()
00705 {
00706     uint16_t    sum = UipEthernet::ethernet->upper_layer_chksum(UIP_PROTO_TCP);
00707 
00708     return sum;
00709 }
00710 
00711 /**
00712  * @brief
00713  * @note
00714  * @param
00715  * @retval
00716  */
00717 uint16_t uip_udpchksum()
00718 {
00719     uint16_t    sum = UipEthernet::ethernet->upper_layer_chksum(UIP_PROTO_UDP);
00720 
00721     return sum;
00722 }
00723 
00724 #endif