Fork for fixes
Embed:
(wiki syntax)
Show/hide line numbers
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
Generated on Fri Jul 15 2022 22:55:10 by 1.7.2