mbed OS5
Fork of UIPEthernet by
Diff: UIPEthernet.cpp
- Revision:
- 0:5350a66d5279
- Child:
- 2:049ce85163c5
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UIPEthernet.cpp Mon Sep 15 11:12:30 2014 +0000 @@ -0,0 +1,591 @@ +/* + UIPEthernet.cpp - Arduino implementation of a uIP wrapper class. + Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de> + All rights reserved. + + Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#pragma once +#include <mbed.h> +#include "UIPEthernet.h" +#include "Enc28J60Network.h" + +#if (defined UIPETHERNET_DEBUG || defined UIPETHERNET_DEBUG_CHKSUM) + #include "HardwareSerial.h" +#endif +extern "C" +{ +#include "uip-conf.h" +#include "uip.h" +#include "uip_arp.h" +#include "uip_timer.h" +} +#define ETH_HDR ((struct uip_eth_hdr*) &uip_buf[0]) + +// Because uIP isn't encapsulated within a class we have to use global + +// variables, so we can only have one TCP/IP stack per program. +UIPEthernetClass::UIPEthernetClass(PinName mosi, PinName miso, PinName sck, PinName cs) : + network(mosi, miso, sck, cs), + fn_uip_cb(NULL), + fn_uip_udp_cb(NULL), + in_packet(NOBLOCK), + uip_packet(NOBLOCK), + uip_hdrlen(0), + packetstate(0), + _dhcp(NULL) +{ } + +/** + * @brief + * @note + * @param + * @retval + */ +int UIPEthernetClass::begin(const uint8_t* mac) { + static DhcpClass s_dhcp; + _dhcp = &s_dhcp; + + // Initialise the basic info + init(mac); + + // Now try to get our config info from a DHCP server + int ret = _dhcp->beginWithDHCP((uint8_t*)mac); + if(ret == 1) { + + // We've successfully found a DHCP server and got our configuration info, so set things + // accordingly + configure(_dhcp->getLocalIp(), _dhcp->getDnsServerIp(), _dhcp->getGatewayIp(), _dhcp->getSubnetMask()); + } + + return ret; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip) { + IPAddress dns = ip; + dns[3] = 1; + begin(mac, ip, dns); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns) { + IPAddress gateway = ip; + gateway[3] = 1; + begin(mac, ip, dns, gateway); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway) { + IPAddress subnet(255, 255, 255, 0); + begin(mac, ip, dns, gateway, subnet); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) { + init(mac); + configure(ip, dns, gateway, subnet); +} + +/** + * @brief + * @note + * @param + * @retval + */ +int UIPEthernetClass::maintain(void) { + tick(); + + int rc = DHCP_CHECK_NONE; + if(_dhcp != NULL) { + + //we have a pointer to dhcp, use it + rc = _dhcp->checkLease(); + switch(rc) { + case DHCP_CHECK_NONE: + //nothing done + break; + + case DHCP_CHECK_RENEW_OK: + case DHCP_CHECK_REBIND_OK: + //we might have got a new IP. + configure(_dhcp->getLocalIp(), _dhcp->getDnsServerIp(), _dhcp->getGatewayIp(), _dhcp->getSubnetMask()); + break; + + default: + //this is actually a error, it will retry though + break; + } + } + + return rc; +} + +/** + * @brief + * @note + * @param + * @retval + */ +IPAddress UIPEthernetClass::localIP(void) { + IPAddress ret; + uip_ipaddr_t a; + uip_gethostaddr(a); + return ip_addr_uip(a); +} + +/** + * @brief + * @note + * @param + * @retval + */ +IPAddress UIPEthernetClass::subnetMask(void) { + IPAddress ret; + uip_ipaddr_t a; + uip_getnetmask(a); + return ip_addr_uip(a); +} + +/** + * @brief + * @note + * @param + * @retval + */ +IPAddress UIPEthernetClass::gatewayIP(void) { + IPAddress ret; + uip_ipaddr_t a; + uip_getdraddr(a); + return ip_addr_uip(a); +} + +/** + * @brief + * @note + * @param + * @retval + */ +IPAddress UIPEthernetClass::dnsServerIP(void) { + return _dnsServerAddress; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void UIPEthernetClass::tick(void) { + if(in_packet == NOBLOCK) { + in_packet = network.receivePacket(); +#ifdef UIPETHERNET_DEBUG + if(in_packet != NOBLOCK) { + Serial.print("--------------\nreceivePacket: "); + Serial.println(in_packet); + } +#endif + } + + if(in_packet != NOBLOCK) { + packetstate = UIPETHERNET_FREEPACKET; + uip_len = network.blockSize(in_packet); + if(uip_len > 0) { + network.readPacket(in_packet, 0, (uint8_t*)uip_buf, UIP_BUFSIZE); + if(ETH_HDR->type == HTONS(UIP_ETHTYPE_IP)) { + uip_packet = in_packet; +#ifdef UIPETHERNET_DEBUG + Serial.print("readPacket type IP, uip_len: "); + Serial.println(uip_len); +#endif + uip_arp_ipin(); + uip_input(); + if(uip_len > 0) { + uip_arp_out(); + network_send(); + } + } + else + if(ETH_HDR->type == HTONS(UIP_ETHTYPE_ARP)) + { +#ifdef UIPETHERNET_DEBUG + Serial.print("readPacket type ARP, uip_len: "); + Serial.println(uip_len); +#endif + uip_arp_arpin(); + if(uip_len > 0) { + network_send(); + } + } + } + + if(in_packet != NOBLOCK && (packetstate & UIPETHERNET_FREEPACKET)) + { +#ifdef UIPETHERNET_DEBUG + Serial.print("freeing packet: "); + Serial.println(in_packet); +#endif + network.freePacket(); + in_packet = NOBLOCK; + } + } + + if(uip_timer_expired(&periodic_timer)) { + uip_timer_restart(&periodic_timer); + for(int i = 0; i < UIP_CONNS; i++) { + uip_periodic(i); + + // If the above function invocation resulted in data that + // should be sent out on the network, the global variable + // uip_len is set to a value > 0. + if(uip_len > 0) { + uip_arp_out(); + network_send(); + } + } + +#if UIP_UDP + for(int i = 0; i < UIP_UDP_CONNS; i++) { + uip_udp_periodic(i); + + // If the above function invocation resulted in data that + // should be sent out on the network, the global variable + // uip_len is set to a value > 0. */ + if(uip_len > 0) { + network_send(); + } + } +#endif /* UIP_UDP */ + } +} + +/** + * @brief + * @note + * @param + * @retval + */ +bool UIPEthernetClass::network_send(void) { + if(packetstate & UIPETHERNET_SENDPACKET) + { +#ifdef UIPETHERNET_DEBUG + Serial.print("network_send uip_packet: "); + Serial.print(uip_packet); + Serial.print(", hdrlen: "); + Serial.println(uip_hdrlen); +#endif + network.writePacket(uip_packet, 0, uip_buf, uip_hdrlen); + goto sendandfree; + } + + uip_packet = network.allocBlock(uip_len); + if(uip_packet != NOBLOCK) + { +#ifdef UIPETHERNET_DEBUG + Serial.print("network_send uip_buf (uip_len): "); + Serial.print(uip_len); + Serial.print(", packet: "); + Serial.println(uip_packet); +#endif + network.writePacket(uip_packet, 0, uip_buf, uip_len); + goto sendandfree; + } + + return false; +sendandfree: + network.sendPacket(uip_packet); + network.freeBlock(uip_packet); + uip_packet = NOBLOCK; + return true; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void UIPEthernetClass::init(const uint8_t* mac) { + uip_timer_set(&this->periodic_timer, CLOCK_SECOND / 4); + + network.init((uint8_t*)mac); + uip_seteth_addr(mac); + + uip_init(); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void UIPEthernetClass::configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) { + uip_ipaddr_t ipaddr; + + uip_ip_addr(ipaddr, ip); + uip_sethostaddr(ipaddr); + + uip_ip_addr(ipaddr, gateway); + uip_setdraddr(ipaddr); + + uip_ip_addr(ipaddr, subnet); + uip_setnetmask(ipaddr); + + _dnsServerAddress = dns; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void UIPEthernetClass::set_uip_callback(fn_uip_cb_t fn) { + this->fn_uip_cb = fn; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void UIPEthernetClass::uip_callback(void) { + struct uipethernet_state* s = &(uip_conn->appstate); + + if(this->fn_uip_cb) { + + // The sketch wants to handle all uIP events itself, using uIP functions. + this->fn_uip_cb(s); //->p, &s->user); + } +} + +/** + * @brief + * @note + * @param + * @retval + */ +void UIPEthernetClass::set_uip_udp_callback(fn_uip_udp_cb_t fn) { + this->fn_uip_udp_cb = fn; +} + +#if UIP_UDP + +/** + * @brief + * @note + * @param + * @retval + */ +void UIPEthernetClass::uip_udp_callback(void) { + struct uipudp_state* s = &(uip_udp_conn->appstate); + + if(this->fn_uip_udp_cb) { + + // The sketch wants to handle all uIP events itself, using uIP functions. + this->fn_uip_udp_cb(s); //->p, &s->user); + } +} +#endif +//UIPEthernetClass UIPEthernet; + +// uIP callback function +void uipethernet_appcall(void) { + UIPEthernet.uip_callback(); +} + +#if UIP_UDP + +/** + * @brief + * @note + * @param + * @retval + */ +void uipudp_appcall(void) { + UIPEthernet.uip_udp_callback(); +} +#endif + +/*---------------------------------------------------------------------------*/ +uint16_t UIPEthernetClass::chksum(uint16_t sum, const uint8_t* data, uint16_t len) { + uint16_t t; + const uint8_t* dataptr; + const uint8_t* last_byte; + + dataptr = data; + last_byte = data + len - 1; + + while(dataptr < last_byte) { + + /* At least two more bytes */ + t = (dataptr[0] << 8) + dataptr[1]; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + + dataptr += 2; + } + + if(dataptr == last_byte) { + t = (dataptr[0] << 8) + 0; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + } + + /* Return sum in host byte order. */ + return sum; +} + +/*---------------------------------------------------------------------------*/ +uint16_t UIPEthernetClass::ipchksum(void) { + uint16_t sum; + + sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN); + return(sum == 0) ? 0xffff : htons(sum); +} + +/*---------------------------------------------------------------------------*/ +uint16_t UIPEthernetClass::upper_layer_chksum(uint8_t proto) { + uint16_t upper_layer_len; + uint16_t sum; + +#if UIP_CONF_IPV6 + upper_layer_len = (((u16_t) (BUF->len[0]) << 8) + BUF->len[1]); +#else /* UIP_CONF_IPV6 */ + upper_layer_len = (((u16_t) (BUF->len[0]) << 8) + BUF->len[1]) - UIP_IPH_LEN; +#endif /* UIP_CONF_IPV6 */ + + /* First sum pseudoheader. */ + + /* IP protocol and length fields. This addition cannot carry. */ + sum = upper_layer_len + proto; + + /* Sum IP source and destination addresses. */ + sum = chksum(sum, (u8_t*) &BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t)); + + uint8_t upper_layer_memlen; + switch(proto) { + case UIP_PROTO_ICMP: + case UIP_PROTO_ICMP6: + upper_layer_memlen = upper_layer_len; + break; + + case UIP_PROTO_TCP: + upper_layer_memlen = (BUF->tcpoffset >> 4) << 2; + break; +#if UIP_UDP + + case UIP_PROTO_UDP: + upper_layer_memlen = UIP_UDPH_LEN; + break; +#endif + } + + sum = chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_memlen); +#ifdef UIPETHERNET_DEBUG_CHKSUM + Serial.print("chksum uip_buf["); + Serial.print(UIP_IPH_LEN + UIP_LLH_LEN); + Serial.print("-"); + Serial.print(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen); + Serial.print("]: "); + Serial.println(htons(sum), HEX); +#endif + if(upper_layer_memlen < upper_layer_len) { + sum = network.chksum + ( + sum, + uip_packet, + UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen, + upper_layer_len - upper_layer_memlen + ); +#ifdef UIPETHERNET_DEBUG_CHKSUM + Serial.print("chksum uip_packet("); + Serial.print(uip_packet); + Serial.print(")["); + Serial.print(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen); + Serial.print("-"); + Serial.print(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_len); + Serial.print("]: "); + Serial.println(htons(sum), HEX); +#endif + } + + return(sum == 0) ? 0xffff : htons(sum); +} + +/** + * @brief + * @note + * @param + * @retval + */ +uint16_t uip_ipchksum(void) { + return UIPEthernet.ipchksum(); +} + +/** + * @brief + * @note + * @param + * @retval + */ +uint16_t uip_tcpchksum(void) { + uint16_t sum = UIPEthernet.upper_layer_chksum(UIP_PROTO_TCP); + return sum; +} + +#if UIP_UDP + +/** + * @brief + * @note + * @param + * @retval + */ +uint16_t uip_udpchksum(void) { + uint16_t sum = UIPEthernet.upper_layer_chksum(UIP_PROTO_UDP); + return sum; +} +#endif + + +