Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of UIPEthernet by
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/Enc28J60Network.h" 00024 #include "UIPUdp.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 #include "utility/millis.h" 00033 } 00034 #define ETH_HDR ((struct uip_eth_hdr*) &uip_buf[0]) 00035 00036 memhandle UIPEthernet::in_packet(NOBLOCK); 00037 memhandle UIPEthernet::uip_packet(NOBLOCK); 00038 uint8_t UIPEthernet::uip_hdrlen(0); 00039 uint8_t UIPEthernet::packetstate(0); 00040 00041 IPAddress UIPEthernet::_dnsServerAddress; 00042 DhcpClass* UIPEthernet::_dhcp(NULL); 00043 00044 unsigned long UIPEthernet::periodic_timer; 00045 00046 /** 00047 * @brief 00048 * @note 00049 * @param 00050 * @retval 00051 */ 00052 void enc28J60_mempool_block_move_callback(memaddress dest, memaddress src, memaddress len) { 00053 00054 //as ENC28J60 DMA is unable to copy single bytes: 00055 00056 if (len == 1) { 00057 uIPEthernet.network.writeByte(dest, uIPEthernet.network.readByte(src)); 00058 } 00059 else { 00060 00061 // calculate address of last byte 00062 len += src - 1; 00063 00064 /* 1. Appropriately program the EDMAST, EDMAND 00065 and EDMADST register pairs. The EDMAST 00066 registers should point to the first byte to copy 00067 from, the EDMAND registers should point to the 00068 last byte to copy and the EDMADST registers 00069 should point to the first byte in the destination 00070 range. The destination range will always be 00071 linear, never wrapping at any values except from 00072 8191 to 0 (the 8-Kbyte memory boundary). 00073 Extreme care should be taken when 00074 programming the start and end pointers to 00075 prevent a never ending DMA operation which 00076 would overwrite the entire 8-Kbyte buffer. 00077 */ 00078 uIPEthernet.network.writeRegPair(EDMASTL, src); 00079 uIPEthernet.network.writeRegPair(EDMADSTL, dest); 00080 00081 if ((src <= RXSTOP_INIT) && (len > RXSTOP_INIT)) 00082 len -= (RXSTOP_INIT - RXSTART_INIT); 00083 uIPEthernet.network.writeRegPair(EDMANDL, len); 00084 00085 /* 2. If an interrupt at the end of the copy process is 00086 desired, set EIE.DMAIE and EIE.INTIE and 00087 clear EIR.DMAIF. 00088 00089 3. Verify that ECON1.CSUMEN is clear. */ 00090 uIPEthernet.network.writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_CSUMEN); 00091 00092 /* 4. Start the DMA copy by setting ECON1.DMAST. */ 00093 uIPEthernet.network.writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST); 00094 00095 // wait until runnig DMA is completed 00096 while (uIPEthernet.network.readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST); 00097 } 00098 } 00099 00100 /* 00101 * Because UIP isn't encapsulated within a class we have to use global 00102 * variables, so we can only have one TCP/IP stack per program. 00103 */ 00104 UIPEthernet::UIPEthernet(PinName mosi, PinName miso, PinName sck, PinName cs) : 00105 network(mosi, miso, sck, cs) { 00106 millis_start(); 00107 } 00108 00109 #if UIP_UDP 00110 00111 /** 00112 * @brief 00113 * @note 00114 * @param 00115 * @retval 00116 */ 00117 int UIPEthernet::begin(const uint8_t* mac) { 00118 static DhcpClass s_dhcp; 00119 00120 _dhcp = &s_dhcp; 00121 00122 // Initialise the basic info 00123 init(mac); 00124 00125 // Now try to get our config info from a DHCP server 00126 int ret = _dhcp->beginWithDHCP((uint8_t*)mac); 00127 00128 if (ret == 1) { 00129 00130 // We've successfully found a DHCP server and got our configuration info, so set things 00131 // accordingly 00132 configure(_dhcp->getLocalIp(), _dhcp->getDnsServerIp(), _dhcp->getGatewayIp(), _dhcp->getSubnetMask()); 00133 } 00134 00135 return ret; 00136 } 00137 #endif 00138 00139 /** 00140 * @brief 00141 * @note 00142 * @param 00143 * @retval 00144 */ 00145 void UIPEthernet::begin(const uint8_t* mac, IPAddress ip) { 00146 IPAddress dns = ip; 00147 00148 dns[3] = 1; 00149 begin(mac, ip, dns); 00150 } 00151 00152 /** 00153 * @brief 00154 * @note 00155 * @param 00156 * @retval 00157 */ 00158 void UIPEthernet::begin(const uint8_t* mac, IPAddress ip, IPAddress dns) { 00159 IPAddress gateway = ip; 00160 00161 gateway[3] = 1; 00162 begin(mac, ip, dns, gateway); 00163 } 00164 00165 /** 00166 * @brief 00167 * @note 00168 * @param 00169 * @retval 00170 */ 00171 void UIPEthernet::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway) { 00172 IPAddress subnet(255, 255, 255, 0); 00173 00174 begin(mac, ip, dns, gateway, subnet); 00175 } 00176 00177 /** 00178 * @brief 00179 * @note 00180 * @param 00181 * @retval 00182 */ 00183 void UIPEthernet::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) { 00184 init(mac); 00185 configure(ip, dns, gateway, subnet); 00186 } 00187 00188 /** 00189 * @brief 00190 * @note 00191 * @param 00192 * @retval 00193 */ 00194 int UIPEthernet::maintain(void) { 00195 tick(); 00196 00197 int rc = DHCP_CHECK_NONE; 00198 00199 #if UIP_UDP 00200 if (_dhcp != NULL) { 00201 00202 //we have a pointer to dhcp, use it 00203 rc = _dhcp->checkLease(); 00204 switch (rc) { 00205 case DHCP_CHECK_NONE: 00206 //nothing done 00207 break; 00208 00209 case DHCP_CHECK_RENEW_OK: 00210 case DHCP_CHECK_REBIND_OK: 00211 //we might have got a new IP. 00212 configure(_dhcp->getLocalIp(), _dhcp->getDnsServerIp(), _dhcp->getGatewayIp(), _dhcp->getSubnetMask()); 00213 break; 00214 00215 default: 00216 //this is actually an error, it will retry though 00217 break; 00218 } 00219 } 00220 00221 return rc; 00222 #endif 00223 } 00224 00225 /** 00226 * @brief 00227 * @note 00228 * @param 00229 * @retval 00230 */ 00231 IPAddress UIPEthernet::localIP(void) { 00232 uip_ipaddr_t a; 00233 00234 uip_gethostaddr(a); 00235 return ip_addr_uip(a); 00236 } 00237 00238 /** 00239 * @brief 00240 * @note 00241 * @param 00242 * @retval 00243 */ 00244 IPAddress UIPEthernet::subnetMask(void) { 00245 uip_ipaddr_t a; 00246 00247 uip_getnetmask(a); 00248 return ip_addr_uip(a); 00249 } 00250 00251 /** 00252 * @brief 00253 * @note 00254 * @param 00255 * @retval 00256 */ 00257 IPAddress UIPEthernet::gatewayIP(void) { 00258 uip_ipaddr_t a; 00259 00260 uip_getdraddr(a); 00261 return ip_addr_uip(a); 00262 } 00263 00264 /** 00265 * @brief 00266 * @note 00267 * @param 00268 * @retval 00269 */ 00270 IPAddress UIPEthernet::dnsServerIP(void) { 00271 return _dnsServerAddress; 00272 } 00273 00274 /** 00275 * @brief 00276 * @note 00277 * @param 00278 * @retval 00279 */ 00280 void UIPEthernet::tick(void) { 00281 if (in_packet == NOBLOCK) { 00282 in_packet = network.receivePacket(); 00283 #ifdef UIPETHERNET_DEBUG 00284 if (in_packet != NOBLOCK) { 00285 printf("--------------\r\nreceivePacket: %d\r\n", in_packet); 00286 } 00287 #endif 00288 } 00289 00290 if (in_packet != NOBLOCK) { 00291 packetstate = UIPETHERNET_FREEPACKET; 00292 uip_len = network.blockSize(in_packet); 00293 if (uip_len > 0) { 00294 network.readPacket(in_packet, 0, (uint8_t*)uip_buf, UIP_BUFSIZE); 00295 if (ETH_HDR->type == HTONS(UIP_ETHTYPE_IP)) { 00296 uip_packet = in_packet; //required for upper_layer_checksum of in_packet! 00297 #ifdef UIPETHERNET_DEBUG 00298 printf("readPacket type IP, uip_len: %d\r\n", uip_len); 00299 #endif 00300 uip_arp_ipin(); 00301 uip_input(); 00302 if (uip_len > 0) { 00303 uip_arp_out(); 00304 network_send(); 00305 } 00306 } 00307 else 00308 if (ETH_HDR->type == HTONS(UIP_ETHTYPE_ARP)) 00309 { 00310 #ifdef UIPETHERNET_DEBUG 00311 printf("readPacket type ARP, uip_len: %d\r\n", uip_len); 00312 #endif 00313 uip_arp_arpin(); 00314 if (uip_len > 0) { 00315 network_send(); 00316 } 00317 } 00318 } 00319 00320 if (in_packet != NOBLOCK && (packetstate & UIPETHERNET_FREEPACKET)) 00321 { 00322 #ifdef UIPETHERNET_DEBUG 00323 printf("freeing packet: %d\r\n", in_packet); 00324 #endif 00325 network.freePacket(); 00326 in_packet = NOBLOCK; 00327 } 00328 } 00329 00330 unsigned long now = millis(); 00331 bool periodic = (long)(now - periodic_timer) >= 0; 00332 00333 for (int i = 0; i < UIP_CONNS; i++) { 00334 uip_conn = &uip_conns[i]; 00335 if (periodic) { 00336 uip_process(UIP_TIMER); 00337 } 00338 else { 00339 if ((long)(now - ((uip_userdata_t*)uip_conn->appstate)->timer) >= 0) 00340 uip_process(UIP_POLL_REQUEST); 00341 else 00342 continue; 00343 } 00344 00345 // If the above function invocation resulted in data that 00346 // should be sent out on the Enc28J60Network, the global variable 00347 // uip_len is set to a value > 0. 00348 if (uip_len > 0) { 00349 uip_arp_out(); 00350 network_send(); 00351 } 00352 } 00353 00354 if (periodic) { 00355 periodic_timer = now + UIP_PERIODIC_TIMER; 00356 #if UIP_UDP 00357 for (int i = 0; i < UIP_UDP_CONNS; i++) { 00358 uip_udp_periodic(i); 00359 00360 // If the above function invocation resulted in data that 00361 // should be sent out on the Enc28J60Network, the global variable 00362 // uip_len is set to a value > 0. 00363 if (uip_len > 0) { 00364 UIPUDP::_send((uip_udp_userdata_t *) (uip_udp_conns[i].appstate)); 00365 } 00366 } 00367 #endif // UIP_UDP 00368 } 00369 } 00370 00371 /** 00372 * @brief 00373 * @note 00374 * @param 00375 * @retval 00376 */ 00377 bool UIPEthernet::network_send(void) { 00378 if (packetstate & UIPETHERNET_SENDPACKET) 00379 { 00380 #ifdef UIPETHERNET_DEBUG 00381 printf("Enc28J60Network_send uip_packet: %d, hdrlen: %d\r\n", uip_packet, uip_hdrlen); 00382 #endif 00383 uIPEthernet.network.writePacket(uip_packet, 0, uip_buf, uip_hdrlen); 00384 packetstate &= ~UIPETHERNET_SENDPACKET; 00385 goto sendandfree; 00386 } 00387 00388 uip_packet = Enc28J60Network::allocBlock(uip_len); 00389 if (uip_packet != NOBLOCK) 00390 { 00391 #ifdef UIPETHERNET_DEBUG 00392 printf("Enc28J60Network_send uip_buf (uip_len): %d, packet: %d\r\n", uip_len, uip_packet); 00393 #endif 00394 uIPEthernet.network.writePacket(uip_packet, 0, uip_buf, uip_len); 00395 goto sendandfree; 00396 } 00397 00398 return false; 00399 sendandfree: 00400 network.sendPacket(uip_packet); 00401 Enc28J60Network::freeBlock(uip_packet); 00402 uip_packet = NOBLOCK; 00403 return true; 00404 } 00405 00406 /** 00407 * @brief 00408 * @note 00409 * @param 00410 * @retval 00411 */ 00412 void UIPEthernet::init(const uint8_t* mac) { 00413 periodic_timer = millis() + UIP_PERIODIC_TIMER; 00414 00415 network.init((uint8_t*)mac); 00416 uip_seteth_addr(mac); 00417 00418 uip_init(); 00419 uip_arp_init(); 00420 } 00421 00422 /** 00423 * @brief 00424 * @note 00425 * @param 00426 * @retval 00427 */ 00428 void UIPEthernet::configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) { 00429 uip_ipaddr_t ipaddr; 00430 00431 uip_ip_addr(ipaddr, ip); 00432 uip_sethostaddr(ipaddr); 00433 00434 uip_ip_addr(ipaddr, gateway); 00435 uip_setdraddr(ipaddr); 00436 00437 uip_ip_addr(ipaddr, subnet); 00438 uip_setnetmask(ipaddr); 00439 00440 _dnsServerAddress = dns; 00441 } 00442 00443 /** 00444 * @brief 00445 * @note 00446 * @param 00447 * @retval 00448 */ 00449 uint16_t UIPEthernet::chksum(uint16_t sum, const uint8_t* data, uint16_t len) { 00450 uint16_t t; 00451 const uint8_t* dataptr; 00452 const uint8_t* last_byte; 00453 00454 dataptr = data; 00455 last_byte = data + len - 1; 00456 00457 while (dataptr < last_byte) { 00458 00459 /* At least two more bytes */ 00460 t = (dataptr[0] << 8) + dataptr[1]; 00461 sum += t; 00462 if (sum < t) { 00463 sum++; /* carry */ 00464 } 00465 00466 dataptr += 2; 00467 } 00468 00469 if (dataptr == last_byte) { 00470 t = (dataptr[0] << 8) + 0; 00471 sum += t; 00472 if (sum < t) { 00473 sum++; /* carry */ 00474 } 00475 } 00476 00477 /* Return sum in host byte order. */ 00478 return sum; 00479 } 00480 00481 /** 00482 * @brief 00483 * @note 00484 * @param 00485 * @retval 00486 */ 00487 uint16_t UIPEthernet::ipchksum(void) { 00488 uint16_t sum; 00489 00490 sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN); 00491 return(sum == 0) ? 0xffff : htons(sum); 00492 } 00493 00494 uint16_t 00495 #if UIP_UDP 00496 UIPEthernet::upper_layer_chksum(uint8_t proto) 00497 #else 00498 uip_tcpchksum (void) 00499 #endif 00500 { 00501 uint16_t upper_layer_len; 00502 uint16_t sum; 00503 00504 #if UIP_CONF_IPV6 00505 upper_layer_len = (((u16_t) (BUF->len[0]) << 8) + BUF->len[1]); 00506 #else /* UIP_CONF_IPV6 */ 00507 upper_layer_len = (((u16_t) (BUF->len[0]) << 8) + BUF->len[1]) - UIP_IPH_LEN; 00508 #endif /* UIP_CONF_IPV6 */ 00509 00510 /* First sum pseudoheader. */ 00511 00512 /* IP protocol and length fields. This addition cannot carry. */ 00513 #if UIP_UDP 00514 sum = upper_layer_len + proto; 00515 #else 00516 sum = upper_layer_len + UIP_PROTO_TCP; 00517 #endif 00518 /* Sum IP source and destination addresses. */ 00519 00520 sum = UIPEthernet::chksum(sum, (u8_t*) &BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t)); 00521 00522 uint8_t upper_layer_memlen; 00523 #if UIP_UDP 00524 switch (proto) { 00525 // case UIP_PROTO_ICMP: 00526 // case UIP_PROTO_ICMP6: 00527 // upper_layer_memlen = upper_layer_len; 00528 // break; 00529 case UIP_PROTO_UDP: 00530 upper_layer_memlen = UIP_UDPH_LEN; 00531 break; 00532 00533 default: 00534 // case UIP_PROTO_TCP: 00535 #endif 00536 upper_layer_memlen = (BUF->tcpoffset >> 4) << 2; 00537 #if UIP_UDP 00538 break; 00539 } 00540 #endif 00541 sum = UIPEthernet::chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_memlen); 00542 #ifdef UIPETHERNET_DEBUG_CHKSUM 00543 printf("chksum uip_buf[%d-%d]: %d\r\n", UIP_IPH_LEN + UIP_LLH_LEN, UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen, htons(sum)); 00544 #endif 00545 if (upper_layer_memlen < upper_layer_len) { 00546 sum = network.chksum 00547 ( 00548 sum, UIPEthernet::uip_packet, UIP_IPH_LEN + 00549 UIP_LLH_LEN + 00550 upper_layer_memlen, upper_layer_len - 00551 upper_layer_memlen 00552 ); 00553 #ifdef UIPETHERNET_DEBUG_CHKSUM 00554 printf("chksum uip_packet(%d)[%d-%d]: %d\r\n", uip_packet, UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen, UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_len, htons(sum)); 00555 #endif 00556 } 00557 return(sum == 0) ? 0xffff : htons(sum); 00558 } 00559 00560 /** 00561 * @brief 00562 * @note 00563 * @param 00564 * @retval 00565 */ 00566 uint16_t uip_ipchksum(void) { 00567 return uIPEthernet.ipchksum(); 00568 } 00569 00570 #if UIP_UDP 00571 00572 /** 00573 * @brief 00574 * @note 00575 * @param 00576 * @retval 00577 */ 00578 uint16_t uip_tcpchksum(void) { 00579 uint16_t sum = uIPEthernet.upper_layer_chksum(UIP_PROTO_TCP); 00580 00581 return sum; 00582 } 00583 00584 /** 00585 * @brief 00586 * @note 00587 * @param 00588 * @retval 00589 */ 00590 uint16_t uip_udpchksum(void) { 00591 uint16_t sum = uIPEthernet.upper_layer_chksum(UIP_PROTO_UDP); 00592 00593 return sum; 00594 } 00595 #endif 00596
Generated on Tue Jul 12 2022 18:10:58 by
