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
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
Generated on Tue Jul 12 2022 18:48:00 by 1.7.2