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
Library for ENC28J60 Ethernet modules.
Ported to mbed from Norbert Truchsess's UIPEthernet library for Arduino. Thank you Norbert!
- Full support for persistent (streaming) TCP/IP and UDP connections Client and Server each, ARP, ICMP, DHCP and DNS.
- Works with both Mbed OS 2 and Mbed OS 5.
Usage:
- Import the library into your project.
- Add
#include "UipEthernet.h"
tomain.cpp
- Create one instance of the UipEthernet class initialized with the MAC address you'd like to use and SPI pins of the connected Mbed board.
Example programs:
Import programWebSwitch_ENC28J60
HTTP Server serving a simple webpage which enables to remotely turn a digital output on/off. Compile, download, run and type 'IP_address/secret/' (don't forget the last '/') into your web browser and hit ENTER.
Import programHTTPServer_Echo_ENC28J60
A simple HTTP server echoing received requests. Ethernet connection is over an ENC28J60 board. Usage: Type the server's IP address into you web browser and hit <ENTER>.
Import programTcpServer_ENC28J60
Simple TCP/IP Server using the UIPEthernet library for ENC28J60 Ethernet boards.
Import programTcpClient_ENC28J60
Simple TCP/IP Client using the UIPEthernet library for ENC28J60 Ethernet boards.
Import programUdpServer_ENC28J60
Simple UDP Server using the UIPEthernet library for ENC28J60 Ethernet boards.
Import programUdpClient_ENC28J60
Simple UDP Client using the UIPEthernet library for ENC28J60 Ethernet boards.
Import programMQTT_Hello_ENC28J60
MQTT Client example program. Ethernet connection is via an ENC28J60 module.
Revision 9:a156d3de5647, committed 2019-08-27
- Comitter:
- hudakz
- Date:
- Tue Aug 27 15:01:10 2019 +0000
- Parent:
- 8:4acb22344932
- Child:
- 10:e4ddab81e6a8
- Commit message:
- Mbed OS 5 support added and API modified.
Changed in this revision
--- a/Dhcp.cpp Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,539 +0,0 @@ -// DHCP Library v0.3 - April 25, 2009 -// Author: Jordan Terrell - blog.jordanterrell.com -#include <string.h> -#include <stdlib.h> -#include "Dhcp.h" -#include "utility/util.h" -#include "utility/millis.h" - -/** - * @brief - * @note - * @param - * @retval - */ -int DhcpClass::beginWithDHCP(uint8_t* mac, unsigned long timeout, unsigned long responseTimeout) { - _dhcpLeaseTime = 0; - _dhcpT1 = 0; - _dhcpT2 = 0; - _lastCheck = 0; - _timeout = timeout; - _responseTimeout = responseTimeout; - - // zero out _dhcpMacAddr - memset(_dhcpMacAddr, 0, 6); - reset_DHCP_lease(); - - memcpy((void*)_dhcpMacAddr, (void*)mac, 6); - _dhcp_state = STATE_DHCP_START; - return request_DHCP_lease(); -} - -/** - * @brief - * @note - * @param - * @retval - */ -void DhcpClass::reset_DHCP_lease(void) { - - // zero out _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp - - memset(_dhcpLocalIp, 0, 20); -} - -//return:0 on error, 1 if request is sent and response is received -int DhcpClass::request_DHCP_lease(void) { - uint8_t messageType = 0; - - // Pick an initial transaction ID - - _dhcpTransactionId = (rand() % 2000UL) + 1; - _dhcpInitialTransactionId = _dhcpTransactionId; - - _dhcpUdpSocket.stop(); - if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0) { - - // Couldn't get a socket - return 0; - } - - presend_DHCP(); - - volatile int result = 0; - - unsigned long startTime = millis(); - - while (_dhcp_state != STATE_DHCP_LEASED) { - if (_dhcp_state == STATE_DHCP_START) { - _dhcpTransactionId++; - - send_DHCP_MESSAGE(DHCP_DISCOVER, ((millis() - startTime) / 1000)); - _dhcp_state = STATE_DHCP_DISCOVER; - } - else - if (_dhcp_state == STATE_DHCP_REREQUEST) { - _dhcpTransactionId++; - send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime) / 1000)); - _dhcp_state = STATE_DHCP_REQUEST; - } - else - if (_dhcp_state == STATE_DHCP_DISCOVER) { - uint32_t respId; - messageType = parseDHCPResponse(_responseTimeout, respId); - if (messageType == DHCP_OFFER) { - - // We'll use the transaction ID that the offer came with, - // rather than the one we were up to - _dhcpTransactionId = respId; - send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime) / 1000)); - _dhcp_state = STATE_DHCP_REQUEST; - } - } - else - if (_dhcp_state == STATE_DHCP_REQUEST) { - uint32_t respId; - messageType = parseDHCPResponse(_responseTimeout, respId); - if (messageType == DHCP_ACK) { - _dhcp_state = STATE_DHCP_LEASED; - result = 1; - - //use default lease time if we didn't get it - if (_dhcpLeaseTime == 0) { - _dhcpLeaseTime = DEFAULT_LEASE; - } - - //calculate T1 & T2 if we didn't get it - if (_dhcpT1 == 0) { - - //T1 should be 50% of _dhcpLeaseTime - _dhcpT1 = _dhcpLeaseTime >> 1; - } - - if (_dhcpT2 == 0) { - - //T2 should be 87.5% (7/8ths) of _dhcpLeaseTime - _dhcpT2 = _dhcpT1 << 1; - } - - _renewInSec = _dhcpT1; - _rebindInSec = _dhcpT2; - } - else - if (messageType == DHCP_NAK) - _dhcp_state = STATE_DHCP_START; - } - - if (messageType == 255) { - messageType = 0; - _dhcp_state = STATE_DHCP_START; - } - - if ((result != 1) && ((millis() - startTime) > _timeout)) - break; - } - - // We're done with the socket now - _dhcpUdpSocket.stop(); - _dhcpTransactionId++; - - return result; -} - -/** - * @brief - * @note - * @param - * @retval - */ -void DhcpClass::presend_DHCP(void) -{ } - -/** - * @brief - * @note - * @param - * @retval - */ -void DhcpClass::send_DHCP_MESSAGE(uint8_t messageType, uint16_t secondsElapsed) { - uint8_t buffer[32]; - memset(buffer, 0, 32); - - IPAddress dest_addr(255, 255, 255, 255); // Broadcast address - - if (-1 == _dhcpUdpSocket.beginPacket(dest_addr, DHCP_SERVER_PORT)) { - - // FIXME Need to return errors - return; - } - - buffer[0] = DHCP_BOOTREQUEST; // op - buffer[1] = DHCP_HTYPE10MB; // htype - buffer[2] = DHCP_HLENETHERNET; // hlen - buffer[3] = DHCP_HOPS; // hops - - // xid - unsigned long xid = htonl(_dhcpTransactionId); - memcpy(buffer + 4, &(xid), 4); - - // 8, 9 - seconds elapsed - buffer[8] = ((secondsElapsed & 0xff00) >> 8); - buffer[9] = (secondsElapsed & 0x00ff); - - // flags - unsigned short flags = htons(DHCP_FLAGSBROADCAST); - memcpy(buffer + 10, &(flags), 2); - - // ciaddr: already zeroed - // yiaddr: already zeroed - // siaddr: already zeroed - // giaddr: already zeroed - //put data in W5100 transmit buffer - _dhcpUdpSocket.write(buffer, 28); - - memset(buffer, 0, 32); // clear local buffer - memcpy(buffer, _dhcpMacAddr, 6); // chaddr - - //put data in W5100 transmit buffer - _dhcpUdpSocket.write(buffer, 16); - - memset(buffer, 0, 32); // clear local buffer - - // leave zeroed out for sname && file - // put in W5100 transmit buffer x 6 (192 bytes) - for (int i = 0; i < 6; i++) { - _dhcpUdpSocket.write(buffer, 32); - } - - // OPT - Magic Cookie - buffer[0] = (uint8_t) ((MAGIC_COOKIE >> 24) & 0xFF); - buffer[1] = (uint8_t) ((MAGIC_COOKIE >> 16) & 0xFF); - buffer[2] = (uint8_t) ((MAGIC_COOKIE >> 8) & 0xFF); - buffer[3] = (uint8_t) (MAGIC_COOKIE & 0xFF); - - // OPT - message type - buffer[4] = dhcpMessageType; - buffer[5] = 0x01; - buffer[6] = messageType; //DHCP_REQUEST; - - // OPT - client identifier - buffer[7] = dhcpClientIdentifier; - buffer[8] = 0x07; - buffer[9] = 0x01; - memcpy(buffer + 10, _dhcpMacAddr, 6); - - // OPT - host name - buffer[16] = hostName; - buffer[17] = strlen(HOST_NAME) + 6; // length of hostname + last 3 bytes of mac address - strcpy((char*) &(buffer[18]), HOST_NAME); - - printByte((char*) &(buffer[24]), _dhcpMacAddr[3]); - printByte((char*) &(buffer[26]), _dhcpMacAddr[4]); - printByte((char*) &(buffer[28]), _dhcpMacAddr[5]); - - //put data in W5100 transmit buffer - _dhcpUdpSocket.write(buffer, 30); - - if (messageType == DHCP_REQUEST) { - buffer[0] = dhcpRequestedIPaddr; - buffer[1] = 0x04; - buffer[2] = _dhcpLocalIp[0]; - buffer[3] = _dhcpLocalIp[1]; - buffer[4] = _dhcpLocalIp[2]; - buffer[5] = _dhcpLocalIp[3]; - - buffer[6] = dhcpServerIdentifier; - buffer[7] = 0x04; - - //buffer[8] = _dhcpDhcpServerIp[0]; - buffer[8] = _dhcpLocalIp[0]; - buffer[9] = _dhcpDhcpServerIp[1]; - buffer[10] = _dhcpDhcpServerIp[2]; - buffer[11] = _dhcpDhcpServerIp[3]; - - //put data in W5100 transmit buffer - _dhcpUdpSocket.write(buffer, 12); - } - - buffer[0] = dhcpParamRequest; - buffer[1] = 0x06; - buffer[2] = subnetMask; - buffer[3] = routersOnSubnet; - buffer[4] = dns; - buffer[5] = domainName; - buffer[6] = dhcpT1value; - buffer[7] = dhcpT2value; - buffer[8] = endOption; - - //put data in W5100 transmit buffer - _dhcpUdpSocket.write(buffer, 9); - - _dhcpUdpSocket.endPacket(); -} - -/** - * @brief - * @note - * @param - * @retval - */ -uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId) { - volatile uint8_t type = 0; - uint8_t opt_len = 0; - - unsigned long startTime = millis(); - - while (_dhcpUdpSocket.parsePacket() <= 0) { - if ((millis() - startTime) > responseTimeout) { - return 255; - } - - wait_ms(50); - } - - // start reading in the packet - RIP_MSG_FIXED fixedMsg; - _dhcpUdpSocket.read((uint8_t*) &fixedMsg, sizeof(RIP_MSG_FIXED)); - - if (fixedMsg.op == DHCP_BOOTREPLY && _dhcpUdpSocket.remotePort() == DHCP_SERVER_PORT) { - transactionId = ntohl(fixedMsg.xid); - if - ( - memcmp(fixedMsg.chaddr, _dhcpMacAddr, 6) != 0 - || (transactionId < _dhcpInitialTransactionId) - || (transactionId > _dhcpTransactionId) - ) { - - // Need to read the rest of the packet here regardless - _dhcpUdpSocket.flush(); - return 0; - } - - memcpy(_dhcpLocalIp, fixedMsg.yiaddr, 4); - - // Skip to the option part - // Doing this a byte at a time so we don't have to put a big buffer - // on the stack (as we don't have lots of memory lying around) - for (int i = 0; i < (240 - (int)sizeof(RIP_MSG_FIXED)); i++) { - _dhcpUdpSocket.read(); // we don't care about the returned byte - } - - while (_dhcpUdpSocket.available() > 0) { - switch (_dhcpUdpSocket.read()) { - case endOption: - break; - - case padOption: - break; - - case dhcpMessageType: - opt_len = _dhcpUdpSocket.read(); - type = _dhcpUdpSocket.read(); - break; - - case subnetMask: - opt_len = _dhcpUdpSocket.read(); - _dhcpUdpSocket.read(_dhcpSubnetMask, 4); - break; - - case routersOnSubnet: - opt_len = _dhcpUdpSocket.read(); - _dhcpUdpSocket.read(_dhcpGatewayIp, 4); - for (int i = 0; i < opt_len - 4; i++) { - _dhcpUdpSocket.read(); - } - break; - - case dns: - opt_len = _dhcpUdpSocket.read(); - _dhcpUdpSocket.read(_dhcpDnsServerIp, 4); - for (int i = 0; i < opt_len - 4; i++) { - _dhcpUdpSocket.read(); - } - break; - - case dhcpServerIdentifier: - opt_len = _dhcpUdpSocket.read(); - if (*((uint32_t*)_dhcpDhcpServerIp) == 0 || IPAddress(_dhcpDhcpServerIp) == _dhcpUdpSocket.remoteIP()) { - _dhcpUdpSocket.read(_dhcpDhcpServerIp, sizeof(_dhcpDhcpServerIp)); - } - else { - - // Skip over the rest of this option - while (opt_len--) { - _dhcpUdpSocket.read(); - } - } - break; - - case dhcpT1value: - opt_len = _dhcpUdpSocket.read(); - _dhcpUdpSocket.read((uint8_t*) &_dhcpT1, sizeof(_dhcpT1)); - _dhcpT1 = ntohl(_dhcpT1); - break; - - case dhcpT2value: - opt_len = _dhcpUdpSocket.read(); - _dhcpUdpSocket.read((uint8_t*) &_dhcpT2, sizeof(_dhcpT2)); - _dhcpT2 = ntohl(_dhcpT2); - break; - - case dhcpIPaddrLeaseTime: - opt_len = _dhcpUdpSocket.read(); - _dhcpUdpSocket.read((uint8_t*) &_dhcpLeaseTime, sizeof(_dhcpLeaseTime)); - _dhcpLeaseTime = ntohl(_dhcpLeaseTime); - _renewInSec = _dhcpLeaseTime; - break; - - default: - opt_len = _dhcpUdpSocket.read(); - - // Skip over the rest of this option - while (opt_len--) { - _dhcpUdpSocket.read(); - } - break; - } - } - } - - // Need to skip to end of the packet regardless here - _dhcpUdpSocket.flush(); - - return type; -} - -/* - returns: - 0/DHCP_CHECK_NONE: nothing happened - 1/DHCP_CHECK_RENEW_FAIL: renew failed - 2/DHCP_CHECK_RENEW_OK: renew success - 3/DHCP_CHECK_REBIND_FAIL: rebind fail - 4/DHCP_CHECK_REBIND_OK: rebind success -*/ -int DhcpClass::checkLease(void) { - - //this uses a signed / unsigned trick to deal with millis overflow - unsigned long now = millis(); - signed long snow = (long)now; - volatile int rc = DHCP_CHECK_NONE; - if (_lastCheck != 0) { - signed long factor; - //calc how many ms past the timeout we are - - factor = snow - (long)_secTimeout; - - //if on or passed the timeout, reduce the counters - if (factor >= 0) { - - //next timeout should be now plus 1000 ms minus parts of second in factor - _secTimeout = snow + 1000 - factor % 1000; - - //how many seconds late are we, minimum 1 - factor = factor / 1000 + 1; - - //reduce the counters by that mouch - //if we can assume that the cycle time (factor) is fairly constant - //and if the remainder is less than cycle time * 2 - //do it early instead of late - if (_renewInSec < factor * 2) - _renewInSec = 0; - else - _renewInSec -= factor; - - if (_rebindInSec < factor * 2) - _rebindInSec = 0; - else - _rebindInSec -= factor; - } - - //if we have a lease but should renew, do it - if (_dhcp_state == STATE_DHCP_LEASED && _renewInSec <= 0) { - _dhcp_state = STATE_DHCP_REREQUEST; - rc = 1 + request_DHCP_lease(); - } - - //if we have a lease or is renewing but should bind, do it - if ((_dhcp_state == STATE_DHCP_LEASED || _dhcp_state == STATE_DHCP_START) && _rebindInSec <= 0) { - - //this should basically restart completely - _dhcp_state = STATE_DHCP_START; - reset_DHCP_lease(); - rc = 3 + request_DHCP_lease(); - } - } - else { - _secTimeout = snow + 1000; - } - - _lastCheck = now; - return rc; -} - -/** - * @brief - * @note - * @param - * @retval - */ -IPAddress DhcpClass::getLocalIp(void) { - return IPAddress(_dhcpLocalIp); -} - -/** - * @brief - * @note - * @param - * @retval - */ -IPAddress DhcpClass::getSubnetMask(void) { - return IPAddress(_dhcpSubnetMask); -} - -/** - * @brief - * @note - * @param - * @retval - */ -IPAddress DhcpClass::getGatewayIp(void) { - return IPAddress(_dhcpGatewayIp); -} - -/** - * @brief - * @note - * @param - * @retval - */ -IPAddress DhcpClass::getDhcpServerIp(void) { - return IPAddress(_dhcpDhcpServerIp); -} - -/** - * @brief - * @note - * @param - * @retval - */ -IPAddress DhcpClass::getDnsServerIp(void) { - return IPAddress(_dhcpDnsServerIp); -} - -/** - * @brief - * @note - * @param - * @retval - */ -void DhcpClass::printByte(char* buf, uint8_t n) { - char* str = &buf[1]; - buf[0] = '0'; - do { - unsigned long m = n; - n /= 16; - - char c = m - 16 * n; - *str-- = c < 10 ? c + '0' : c + 'A' - 10; - } while (n); -}
--- a/Dhcp.h Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,189 +0,0 @@ -// DHCP Library v0.3 - April 25, 2009 -// Author: Jordan Terrell - blog.jordanterrell.com -#ifndef Dhcp_h -#define Dhcp_h - -#include "UIPUdp.h" - -/* DHCP state machine. */ - -#define STATE_DHCP_START 0 -#define STATE_DHCP_DISCOVER 1 -#define STATE_DHCP_REQUEST 2 -#define STATE_DHCP_LEASED 3 -#define STATE_DHCP_REREQUEST 4 -#define STATE_DHCP_RELEASE 5 - -#define DHCP_FLAGSBROADCAST 0x8000 - -/* UDP port numbers for DHCP */ - -#define DHCP_SERVER_PORT 67 /* from server to client */ - -#define DHCP_CLIENT_PORT 68 /* from client to server */ - -/* DHCP message OP code */ - -#define DHCP_BOOTREQUEST 1 -#define DHCP_BOOTREPLY 2 - -/* DHCP message type */ - -#define DHCP_DISCOVER 1 -#define DHCP_OFFER 2 -#define DHCP_REQUEST 3 -#define DHCP_DECLINE 4 -#define DHCP_ACK 5 -#define DHCP_NAK 6 -#define DHCP_RELEASE 7 -#define DHCP_INFORM 8 - -#define DHCP_HTYPE10MB 1 -#define DHCP_HTYPE100MB 2 - -#define DHCP_HLENETHERNET 6 -#define DHCP_HOPS 0 -#define DHCP_SECS 0 - -#define MAGIC_COOKIE 0x63825363 -#define MAX_DHCP_OPT 16 - -#define HOST_NAME "ENC28J" -#define DEFAULT_LEASE (900) //default lease time in seconds - -#define DHCP_CHECK_NONE (0) -#define DHCP_CHECK_RENEW_FAIL (1) -#define DHCP_CHECK_RENEW_OK (2) -#define DHCP_CHECK_REBIND_FAIL (3) -#define DHCP_CHECK_REBIND_OK (4) - -enum -{ - padOption = 0, - subnetMask = 1, - timerOffset = 2, - routersOnSubnet = 3, - - /* timeServer = 4, - nameServer = 5,*/ - dns = 6, - - /*logServer = 7, - cookieServer = 8, - lprServer = 9, - impressServer = 10, - resourceLocationServer = 11,*/ - hostName = 12, - - /*bootFileSize = 13, - meritDumpFile = 14,*/ - domainName = 15, - - /*swapServer = 16, - rootPath = 17, - extentionsPath = 18, - IPforwarding = 19, - nonLocalSourceRouting = 20, - policyFilter = 21, - maxDgramReasmSize = 22, - defaultIPTTL = 23, - pathMTUagingTimeout = 24, - pathMTUplateauTable = 25, - ifMTU = 26, - allSubnetsLocal = 27, - broadcastAddr = 28, - performMaskDiscovery = 29, - maskSupplier = 30, - performRouterDiscovery = 31, - routerSolicitationAddr = 32, - staticRoute = 33, - trailerEncapsulation = 34, - arpCacheTimeout = 35, - ethernetEncapsulation = 36, - tcpDefaultTTL = 37, - tcpKeepaliveInterval = 38, - tcpKeepaliveGarbage = 39, - nisDomainName = 40, - nisServers = 41, - ntpServers = 42, - vendorSpecificInfo = 43, - netBIOSnameServer = 44, - netBIOSdgramDistServer = 45, - netBIOSnodeType = 46, - netBIOSscope = 47, - xFontServer = 48, - xDisplayManager = 49,*/ - dhcpRequestedIPaddr = 50, - dhcpIPaddrLeaseTime = 51, - - /*dhcpOptionOverload = 52,*/ - dhcpMessageType = 53, - dhcpServerIdentifier= 54, - dhcpParamRequest = 55, - - /*dhcpMsg = 56, - dhcpMaxMsgSize = 57,*/ - dhcpT1value = 58, - dhcpT2value = 59, - - /*dhcpClassIdentifier = 60,*/ - dhcpClientIdentifier= 61, - endOption = 255 -}; - -typedef struct _RIP_MSG_FIXED -{ - uint8_t op; - uint8_t htype; - uint8_t hlen; - uint8_t hops; - uint32_t xid; - uint16_t secs; - uint16_t flags; - uint8_t ciaddr[4]; - uint8_t yiaddr[4]; - uint8_t siaddr[4]; - uint8_t giaddr[4]; - uint8_t chaddr[6]; -} RIP_MSG_FIXED; - -class DhcpClass -{ -private: - uint32_t _dhcpInitialTransactionId; - uint32_t _dhcpTransactionId; - uint8_t _dhcpMacAddr[6]; - uint8_t _dhcpLocalIp[4]; - uint8_t _dhcpSubnetMask[4]; - uint8_t _dhcpGatewayIp[4]; - uint8_t _dhcpDhcpServerIp[4]; - uint8_t _dhcpDnsServerIp[4]; - uint32_t _dhcpLeaseTime; - uint32_t _dhcpT1, _dhcpT2; - signed long _renewInSec; - signed long _rebindInSec; - signed long _lastCheck; - unsigned long _timeout; - unsigned long _responseTimeout; - unsigned long _secTimeout; - uint8_t _dhcp_state; - UIPUDP _dhcpUdpSocket; - - int request_DHCP_lease(void); - void reset_DHCP_lease(void); - void presend_DHCP(void); - void send_DHCP_MESSAGE(uint8_t, uint16_t); - void printByte(char* , uint8_t); - - uint8_t parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId); -public: - IPAddress getLocalIp(void); - IPAddress getSubnetMask(void); - IPAddress getGatewayIp(void); - IPAddress getDhcpServerIp(void); - IPAddress getDnsServerIp(void); - - int beginWithDHCP(uint8_t* , unsigned long timeout = 60000, unsigned long responseTimeout = 4000); - int checkLease(void); -}; -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DhcpClient.cpp Tue Aug 27 15:01:10 2019 +0000 @@ -0,0 +1,526 @@ +// DHCP Library v0.3 - April 25, 2009 +// Author: Jordan Terrell - blog.jordanterrell.com +#include <string.h> +#include <stdlib.h> +#include "DhcpClient.h" +#include "utility/util.h" + +/** + * @brief + * @note + * @param + * @retval + */ +int DhcpClient::begin(uint8_t* mac, unsigned long timeout, unsigned long responseTimeout) +{ + _dhcpLeaseTime = 0; + _dhcpT1 = 0; + _dhcpT2 = 0; + _lastCheck = 0; + _timeout = timeout; + _responseTimeout = responseTimeout; + + // zero out _dhcpMacAddr + memset(_dhcpMacAddr, 0, 6); + resetDhcpLease(); + + memcpy((void*)_dhcpMacAddr, (void*)mac, 6); + _dhcp_state = STATE_DHCP_START; + return requestDhcpLease(); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void DhcpClient::resetDhcpLease() +{ + // zero out _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp + memset(_dhcpLocalIp, 0, 5 * 4); +} + +//return:0 on error, 1 if request is sent and response is received +int DhcpClient::requestDhcpLease() +{ + uint8_t messageType = 0; + + // Pick an initial transaction ID + srand(time(NULL)); + _dhcpTransactionId = (rand() % 2000UL) + 1; + _dhcpInitialTransactionId = _dhcpTransactionId; + + _dhcpUdpSocket.stop(); + if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0) { + // Couldn't get a socket + return 0; + } + + presendDhcp(); + + volatile int result = 0; + time_t startTime = time(NULL); + + while (_dhcp_state != STATE_DHCP_LEASED) { + if (_dhcp_state == STATE_DHCP_START) { + _dhcpTransactionId++; + + sendDhcpMessage(DHCP_DISCOVER, (time(NULL) - startTime)); + _dhcp_state = STATE_DHCP_DISCOVER; + } + else + if (_dhcp_state == STATE_DHCP_REREQUEST) { + _dhcpTransactionId++; + sendDhcpMessage(DHCP_REQUEST, (time(NULL) - startTime)); + _dhcp_state = STATE_DHCP_REQUEST; + } + else + if (_dhcp_state == STATE_DHCP_DISCOVER) { + uint32_t respId; + messageType = parseDhcpResponse(_responseTimeout, respId); + if (messageType == DHCP_OFFER) { + // We'll use the transaction ID that the offer came with, + // rather than the one we were up to + _dhcpTransactionId = respId; + sendDhcpMessage(DHCP_REQUEST, (time(NULL) - startTime)); + _dhcp_state = STATE_DHCP_REQUEST; + } + } + else + if (_dhcp_state == STATE_DHCP_REQUEST) { + uint32_t respId; + messageType = parseDhcpResponse(_responseTimeout, respId); + if (messageType == DHCP_ACK) { + _dhcp_state = STATE_DHCP_LEASED; + result = 1; + + //use default lease time if we didn't get it + if (_dhcpLeaseTime == 0) { + _dhcpLeaseTime = DEFAULT_LEASE; + } + + //calculate T1 & T2 if we didn't get it + if (_dhcpT1 == 0) { + //T1 should be 50% of _dhcpLeaseTime + _dhcpT1 = _dhcpLeaseTime >> 1; + } + + if (_dhcpT2 == 0) { + //T2 should be 87.5% (7/8ths) of _dhcpLeaseTime + _dhcpT2 = _dhcpT1 << 1; + } + + _renewInSec = _dhcpT1; + _rebindInSec = _dhcpT2; + } + else + if (messageType == DHCP_NAK) + _dhcp_state = STATE_DHCP_START; + } + + if (messageType == 255) { + messageType = 0; + _dhcp_state = STATE_DHCP_START; + } + + if ((result != 1) && ((time(NULL) - startTime) > _timeout)) + break; + } + + // We're done with the socket now + _dhcpUdpSocket.stop(); + _dhcpTransactionId++; + + return result; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void DhcpClient::presendDhcp() +{ } + +/** + * @brief + * @note + * @param + * @retval + */ +void DhcpClient::sendDhcpMessage(uint8_t messageType, uint16_t secondsElapsed) +{ + uint8_t buffer[32]; + memset(buffer, 0, 32); + + IpAddress dest_addr(255, 255, 255, 255); // Broadcast address + + if (-1 == _dhcpUdpSocket.beginPacket(dest_addr, DHCP_SERVER_PORT)) { + // FIXME Need to return errors + return; + } + + buffer[0] = DHCP_BOOTREQUEST; // op + buffer[1] = DHCP_HTYPE10MB; // htype + buffer[2] = DHCP_HLENETHERNET; // hlen + buffer[3] = DHCP_HOPS; // hops + // xid + unsigned long xid = htonl(_dhcpTransactionId); + memcpy(buffer + 4, &(xid), 4); + + // 8, 9 - seconds elapsed + buffer[8] = ((secondsElapsed & 0xff00) >> 8); + buffer[9] = (secondsElapsed & 0x00ff); + + // flags + unsigned short flags = htons(DHCP_FLAGSBROADCAST); + memcpy(buffer + 10, &(flags), 2); + + // ciaddr: already zeroed + // yiaddr: already zeroed + // siaddr: already zeroed + // giaddr: already zeroed + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 28); + + memset(buffer, 0, 32); // clear local buffer + memcpy(buffer, _dhcpMacAddr, 6); // chaddr + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 16); + + memset(buffer, 0, 32); // clear local buffer + // leave zeroed out for sname && file + // put in W5100 transmit buffer x 6 (192 bytes) + for (int i = 0; i < 6; i++) { + _dhcpUdpSocket.write(buffer, 32); + } + + // OPT - Magic Cookie + buffer[0] = (uint8_t) ((MAGIC_COOKIE >> 24) & 0xFF); + buffer[1] = (uint8_t) ((MAGIC_COOKIE >> 16) & 0xFF); + buffer[2] = (uint8_t) ((MAGIC_COOKIE >> 8) & 0xFF); + buffer[3] = (uint8_t) (MAGIC_COOKIE & 0xFF); + + // OPT - message type + buffer[4] = dhcpMessageType; + buffer[5] = 0x01; + buffer[6] = messageType; //DHCP_REQUEST; + // OPT - client identifier + buffer[7] = dhcpClientIdentifier; + buffer[8] = 0x07; + buffer[9] = 0x01; + memcpy(buffer + 10, _dhcpMacAddr, 6); + + // OPT - host name + buffer[16] = hostName; + buffer[17] = strlen(HOST_NAME) + 6; // length of hostname + last 3 bytes of mac address + strcpy((char*) &(buffer[18]), HOST_NAME); + + printByte((char*) &(buffer[24]), _dhcpMacAddr[3]); + printByte((char*) &(buffer[26]), _dhcpMacAddr[4]); + printByte((char*) &(buffer[28]), _dhcpMacAddr[5]); + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 30); + + if (messageType == DHCP_REQUEST) { + buffer[0] = dhcpRequestedIPaddr; + buffer[1] = 0x04; + buffer[2] = _dhcpLocalIp[0]; + buffer[3] = _dhcpLocalIp[1]; + buffer[4] = _dhcpLocalIp[2]; + buffer[5] = _dhcpLocalIp[3]; + + buffer[6] = dhcpServerIdentifier; + buffer[7] = 0x04; + + //buffer[8] = _dhcpDhcpServerIp[0]; + buffer[8] = _dhcpLocalIp[0]; + buffer[9] = _dhcpDhcpServerIp[1]; + buffer[10] = _dhcpDhcpServerIp[2]; + buffer[11] = _dhcpDhcpServerIp[3]; + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 12); + } + + buffer[0] = dhcpParamRequest; + buffer[1] = 0x06; + buffer[2] = subnetMask; + buffer[3] = routersOnSubnet; + buffer[4] = dns; + buffer[5] = domainName; + buffer[6] = dhcpT1value; + buffer[7] = dhcpT2value; + buffer[8] = endOption; + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 9); + + _dhcpUdpSocket.endPacket(); +} + +/** + * @brief + * @note + * @param + * @retval + */ +uint8_t DhcpClient::parseDhcpResponse(unsigned long responseTimeout, uint32_t& transactionId) +{ + volatile uint8_t type = 0; + uint8_t opt_len = 0; + + unsigned long startTime = time(NULL); + + while (_dhcpUdpSocket.parsePacket() <= 0) { + if ((time(NULL) - startTime) > responseTimeout) { + return 255; + } + + wait_ms(50); + } + + // start reading in the packet + RIP_MSG_FIXED fixedMsg; + _dhcpUdpSocket.read((uint8_t*) &fixedMsg, sizeof(RIP_MSG_FIXED)); + + if (fixedMsg.op == DHCP_BOOTREPLY && _dhcpUdpSocket.remotePort() == DHCP_SERVER_PORT) { + transactionId = ntohl(fixedMsg.xid); + if + ( + memcmp(fixedMsg.chaddr, _dhcpMacAddr, 6) != 0 || + (transactionId < _dhcpInitialTransactionId) || + (transactionId > _dhcpTransactionId) + ) { + // Need to read the rest of the packet here regardless + _dhcpUdpSocket.flush(); + return 0; + } + + memcpy(_dhcpLocalIp, fixedMsg.yiaddr, 4); + + // Skip to the option part + // Doing this a byte at a time so we don't have to put a big buffer + // on the stack (as we don't have lots of memory lying around) + for (int i = 0; i < (240 - (int)sizeof(RIP_MSG_FIXED)); i++) { + _dhcpUdpSocket.read(); // we don't care about the returned byte + } + + while (_dhcpUdpSocket.available() > 0) { + switch (_dhcpUdpSocket.read()) { + case endOption: + break; + + case padOption: + break; + + case dhcpMessageType: + opt_len = _dhcpUdpSocket.read(); + type = _dhcpUdpSocket.read(); + break; + + case subnetMask: + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read(_dhcpSubnetMask, 4); + break; + + case routersOnSubnet: + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read(_dhcpGatewayIp, 4); + for (int i = 0; i < opt_len - 4; i++) { + _dhcpUdpSocket.read(); + } + break; + + case dns: + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read(_dhcpDnsServerIp, 4); + for (int i = 0; i < opt_len - 4; i++) { + _dhcpUdpSocket.read(); + } + break; + + case dhcpServerIdentifier: + opt_len = _dhcpUdpSocket.read(); + if (*((uint32_t*)_dhcpDhcpServerIp) == 0 || IpAddress(_dhcpDhcpServerIp) == _dhcpUdpSocket.remoteIP()) { + _dhcpUdpSocket.read(_dhcpDhcpServerIp, sizeof(_dhcpDhcpServerIp)); + } + else { + // Skip over the rest of this option + while (opt_len--) { + _dhcpUdpSocket.read(); + } + } + break; + + case dhcpT1value: + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read((uint8_t*) &_dhcpT1, sizeof(_dhcpT1)); + _dhcpT1 = ntohl(_dhcpT1); + break; + + case dhcpT2value: + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read((uint8_t*) &_dhcpT2, sizeof(_dhcpT2)); + _dhcpT2 = ntohl(_dhcpT2); + break; + + case dhcpIPaddrLeaseTime: + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read((uint8_t*) &_dhcpLeaseTime, sizeof(_dhcpLeaseTime)); + _dhcpLeaseTime = ntohl(_dhcpLeaseTime); + _renewInSec = _dhcpLeaseTime; + break; + + default: + opt_len = _dhcpUdpSocket.read(); + + // Skip over the rest of this option + while (opt_len--) { + _dhcpUdpSocket.read(); + } + break; + } + } + } + + // Need to skip to end of the packet regardless here + _dhcpUdpSocket.flush(); + + return type; +} + +/* + returns: + 0/DHCP_CHECK_NONE: nothing happened + 1/DHCP_CHECK_RENEW_FAIL: renew failed + 2/DHCP_CHECK_RENEW_OK: renew success + 3/DHCP_CHECK_REBIND_FAIL: rebind fail + 4/DHCP_CHECK_REBIND_OK: rebind success +*/ +int DhcpClient::checkLease() +{ + time_t now = time(NULL); + volatile int rc = DHCP_CHECK_NONE; + if (_lastCheck != 0) { + //calc how many ms past the timeout we are + time_t factor = now - _secTimeout; + + //if on or passed the timeout, reduce the counters + if (factor >= 0) { + //next timeout should be now plus 1s + _secTimeout = now + 1; + + //reduce the counters by that mouch + //if we can assume that the cycle time (factor) is fairly constant + //and if the remainder is less than cycle time * 2 + //do it early instead of late + if (_renewInSec < factor * 2) + _renewInSec = 0; + else + _renewInSec -= factor; + + if (_rebindInSec < factor * 2) + _rebindInSec = 0; + else + _rebindInSec -= factor; + } + + //if we have a lease but should renew, do it + if (_dhcp_state == STATE_DHCP_LEASED && _renewInSec <= 0) { + _dhcp_state = STATE_DHCP_REREQUEST; + rc = 1 + requestDhcpLease(); + } + + //if we have a lease or is renewing but should bind, do it + if ((_dhcp_state == STATE_DHCP_LEASED || _dhcp_state == STATE_DHCP_START) && _rebindInSec <= 0) { + //this should basically restart completely + _dhcp_state = STATE_DHCP_START; + resetDhcpLease(); + rc = 3 + requestDhcpLease(); + } + } + else { + _secTimeout = now + 1; + } + + _lastCheck = now; + return rc; +} + +/** + * @brief + * @note + * @param + * @retval + */ +IpAddress DhcpClient::getLocalIp() +{ + return IpAddress(_dhcpLocalIp); +} + +/** + * @brief + * @note + * @param + * @retval + */ +IpAddress DhcpClient::getSubnetMask() +{ + return IpAddress(_dhcpSubnetMask); +} + +/** + * @brief + * @note + * @param + * @retval + */ +IpAddress DhcpClient::getGatewayIp() +{ + return IpAddress(_dhcpGatewayIp); +} + +/** + * @brief + * @note + * @param + * @retval + */ +IpAddress DhcpClient::getDhcpServerIp() +{ + return IpAddress(_dhcpDhcpServerIp); +} + +/** + * @brief + * @note + * @param + * @retval + */ +IpAddress DhcpClient::getDnsServerIp() +{ + return IpAddress(_dhcpDnsServerIp); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void DhcpClient::printByte(char* buf, uint8_t n) +{ + char* str = &buf[1]; + buf[0] = '0'; + do { + unsigned long m = n; + n /= 16; + + char c = m - 16 * n; + *str-- = c < 10 ? c + '0' : c + 'A' - 10; + } while (n); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DhcpClient.h Tue Aug 27 15:01:10 2019 +0000 @@ -0,0 +1,184 @@ +// DHCP Library v0.3 - April 25, 2009 +// Author: Jordan Terrell - blog.jordanterrell.com +#ifndef Dhcp_h +#define Dhcp_h + +#include "UdpSocket.h" +#include "IpAddress.h" + +/* DHCP state machine. */ + +#define STATE_DHCP_START 0 +#define STATE_DHCP_DISCOVER 1 +#define STATE_DHCP_REQUEST 2 +#define STATE_DHCP_LEASED 3 +#define STATE_DHCP_REREQUEST 4 +#define STATE_DHCP_RELEASE 5 + +#define DHCP_FLAGSBROADCAST 0x8000 + +/* UDP port numbers for DHCP */ + +#define DHCP_SERVER_PORT 67 /* from server to client */ + +#define DHCP_CLIENT_PORT 68 /* from client to server */ + +/* DHCP message OP code */ + +#define DHCP_BOOTREQUEST 1 +#define DHCP_BOOTREPLY 2 + +/* DHCP message type */ + +#define DHCP_DISCOVER 1 +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 +#define DHCP_ACK 5 +#define DHCP_NAK 6 +#define DHCP_RELEASE 7 +#define DHCP_INFORM 8 + +#define DHCP_HTYPE10MB 1 +#define DHCP_HTYPE100MB 2 + +#define DHCP_HLENETHERNET 6 +#define DHCP_HOPS 0 +#define DHCP_SECS 0 + +#define MAGIC_COOKIE 0x63825363 +#define MAX_DHCP_OPT 16 + +#define HOST_NAME "ENC28J" +#define DEFAULT_LEASE (900) //default lease time in seconds + +#define DHCP_CHECK_NONE (0) +#define DHCP_CHECK_RENEW_FAIL (1) +#define DHCP_CHECK_RENEW_OK (2) +#define DHCP_CHECK_REBIND_FAIL (3) +#define DHCP_CHECK_REBIND_OK (4) + +enum +{ + padOption = 0, + subnetMask = 1, + timerOffset = 2, + routersOnSubnet = 3, + timeServer = 4, + nameServer = 5, + dns = 6, + logServer = 7, + cookieServer = 8, + lprServer = 9, + impressServer = 10, + resourceLocationServer = 11, + hostName = 12, + bootFileSize = 13, + meritDumpFile = 14, + domainName = 15, + swapServer = 16, + rootPath = 17, + extentionsPath = 18, + IPforwarding = 19, + nonLocalSourceRouting = 20, + policyFilter = 21, + maxDgramReasmSize = 22, + defaultIPTTL = 23, + pathMTUagingTimeout = 24, + pathMTUplateauTable = 25, + ifMTU = 26, + allSubnetsLocal = 27, + broadcastAddr = 28, + performMaskDiscovery = 29, + maskSupplier = 30, + performRouterDiscovery = 31, + routerSolicitationAddr = 32, + staticRoute = 33, + trailerEncapsulation = 34, + arpCacheTimeout = 35, + ethernetEncapsulation = 36, + tcpDefaultTTL = 37, + tcpKeepaliveInterval = 38, + tcpKeepaliveGarbage = 39, + nisDomainName = 40, + nisServers = 41, + ntpServers = 42, + vendorSpecificInfo = 43, + netBIOSnameServer = 44, + netBIOSdgramDistServer = 45, + netBIOSnodeType = 46, + netBIOSscope = 47, + xFontServer = 48, + xDisplayManager = 49, + dhcpRequestedIPaddr = 50, + dhcpIPaddrLeaseTime = 51, + dhcpOptionOverload = 52, + dhcpMessageType = 53, + dhcpServerIdentifier = 54, + dhcpParamRequest = 55, + dhcpMsg = 56, + dhcpMaxMsgSize = 57, + dhcpT1value = 58, + dhcpT2value = 59, + dhcpClassIdentifier = 60, + dhcpClientIdentifier = 61, + endOption = 255 +}; + +typedef struct _RIP_MSG_FIXED +{ + uint8_t op; + uint8_t htype; + uint8_t hlen; + uint8_t hops; + uint32_t xid; + uint16_t secs; + uint16_t flags; + uint8_t ciaddr[4]; + uint8_t yiaddr[4]; + uint8_t siaddr[4]; + uint8_t giaddr[4]; + uint8_t chaddr[6]; +} RIP_MSG_FIXED; + +class DhcpClient +{ +private: + uint32_t _dhcpInitialTransactionId; + uint32_t _dhcpTransactionId; + uint8_t _dhcpMacAddr[6]; + uint8_t _dhcpLocalIp[4]; + uint8_t _dhcpSubnetMask[4]; + uint8_t _dhcpGatewayIp[4]; + uint8_t _dhcpDhcpServerIp[4]; + uint8_t _dhcpDnsServerIp[4]; + uint32_t _dhcpLeaseTime; + uint32_t _dhcpT1, _dhcpT2; + time_t _renewInSec; + time_t _rebindInSec; + time_t _lastCheck; + time_t _timeout; + time_t _responseTimeout; + time_t _secTimeout; + uint8_t _dhcp_state; + UdpSocket _dhcpUdpSocket; + + int requestDhcpLease(); + void resetDhcpLease(); + void presendDhcp(); + void sendDhcpMessage(uint8_t, uint16_t); + void printByte(char* , uint8_t); + + uint8_t parseDhcpResponse(unsigned long responseTimeout, uint32_t& transactionId); + +public: + IpAddress getLocalIp(); + IpAddress getSubnetMask(); + IpAddress getGatewayIp(); + IpAddress getDhcpServerIp(); + IpAddress getDnsServerIp(); + + int begin(uint8_t* mac, unsigned long timeout = 60, unsigned long responseTimeout = 4); + int checkLease(); +}; +#endif
--- a/Dns.cpp Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,451 +0,0 @@ -// Arduino DNS client for Enc28J60-based Ethernet shield -// (c) Copyright 2009-2010 MCQN Ltd. -// Released under Apache License, version 2.0 -#include "Udp.h" -#include "utility/util.h" -#include "utility/millis.h" - -#include "Dns.h" -#include <string.h> -//#include <stdlib.h> - -#include "mbed.h" - -#define SOCKET_NONE 255 -// Various flags and header field values for a DNS message - -#define UDP_HEADER_SIZE 8 -#define DNS_HEADER_SIZE 12 -#define TTL_SIZE 4 -#define QUERY_FLAG (0) -#define RESPONSE_FLAG (1 << 15) -#define QUERY_RESPONSE_MASK (1 << 15) -#define OPCODE_STANDARD_QUERY (0) -#define OPCODE_INVERSE_QUERY (1 << 11) -#define OPCODE_STATUS_REQUEST (2 << 11) -#define OPCODE_MASK (15 << 11) -#define AUTHORITATIVE_FLAG (1 << 10) -#define TRUNCATION_FLAG (1 << 9) -#define RECURSION_DESIRED_FLAG (1 << 8) -#define RECURSION_AVAILABLE_FLAG (1 << 7) -#define RESP_NO_ERROR (0) -#define RESP_FORMAT_ERROR (1) -#define RESP_SERVER_FAILURE (2) -#define RESP_NAME_ERROR (3) -#define RESP_NOT_IMPLEMENTED (4) -#define RESP_REFUSED (5) -#define RESP_MASK (15) -#define TYPE_A (0x0001) -#define CLASS_IN (0x0001) -#define LABEL_COMPRESSION_MASK (0xC0) -// Port number that DNS servers listen on - -#define DNS_PORT 53 - -// Possible return codes from ProcessResponse - -#define SUCCESS 1 -#define TIMED_OUT - 1 -#define INVALID_SERVER - 2 -#define TRUNCATED - 3 -#define INVALID_RESPONSE - 4 - -/** - * @brief - * @note - * @param - * @retval - */ -void DNSClient::begin(const IPAddress& aDNSServer) { - iDNSServer = aDNSServer; - iRequestId = 0; -} - -/** - * @brief - * @note - * @param - * @retval - */ -int DNSClient::inet_aton(const char* aIPAddrString, IPAddress& aResult) { - - // See if we've been given a valid IP address - const char* p = aIPAddrString; - while (*p && ((*p == '.') || ((*p >= '0') && (*p <= '9')))) { - p++; - } - - if (*p == '\0') { - - // It's looking promising, we haven't found any invalid characters - p = aIPAddrString; - - int segment = 0; - int segmentValue = 0; - while (*p && (segment < 4)) { - if (*p == '.') { - - // We've reached the end of a segment - if (segmentValue > 255) { - - // You can't have IP address segments that don't fit in a byte - return 0; - } - else { - aResult[segment] = (uint8_t) segmentValue; - segment++; - segmentValue = 0; - } - } - else { - - // Next digit - segmentValue = (segmentValue * 10) + (*p - '0'); - } - - p++; - } - - // We've reached the end of address, but there'll still be the last - // segment to deal with - if ((segmentValue > 255) || (segment > 3)) { - - // You can't have IP address segments that don't fit in a byte, - // or more than four segments - return 0; - } - else { - aResult[segment] = (uint8_t) segmentValue; - return 1; - } - } - else { - return 0; - } -} - -/** - * @brief - * @note - * @param - * @retval - */ -int DNSClient::getHostByName(const char* aHostname, IPAddress& aResult) { - int ret = 0; - - // See if it's a numeric IP address - - if (inet_aton(aHostname, aResult)) { - - // It is, our work here is done - return 1; - } - - // Check we've got a valid DNS server to use - if (iDNSServer == INADDR_NONE) { - return INVALID_SERVER; - } - - // Find a socket to use - if (iUdp.begin(1024 + (millis() & 0xF)) == 1) { - - // Try up to three times - int retries = 0; - // while ((retries < 3) && (ret <= 0)) - { - // Send DNS request - ret = iUdp.beginPacket(iDNSServer, DNS_PORT); - if (ret != 0) { - - // Now output the request data - ret = BuildRequest(aHostname); - if (ret != 0) { - - // And finally send the request - ret = iUdp.endPacket(); - if (ret != 0) { - - // Now wait for a response - int wait_retries = 0; - ret = TIMED_OUT; - while ((wait_retries < 3) && (ret == TIMED_OUT)) { - ret = ProcessResponse(5000, aResult); - wait_retries++; - } - } - } - } - - retries++; - } - - // We're done with the socket now - iUdp.stop(); - } - - return ret; -} - -/** - * @brief - * @note - * @param - * @retval - */ -uint16_t DNSClient::BuildRequest(const char* aName) { - - // Build header - - // 1 1 1 1 1 1 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - // | ID | - // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - // |QR| Opcode |AA|TC|RD|RA| Z | RCODE | - // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - // | QDCOUNT | - // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - // | ANCOUNT | - // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - // | NSCOUNT | - // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - // | ARCOUNT | - // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - // As we only support one request at a time at present, we can simplify - // some of this header - iRequestId = millis(); // generate a random ID - uint16_t twoByteBuffer; - - // FIXME We should also check that there's enough space available to write to, rather - - // FIXME than assume there's enough space (as the code does at present) - iUdp.write((uint8_t*) &iRequestId, sizeof(iRequestId)); - - twoByteBuffer = htons(QUERY_FLAG | OPCODE_STANDARD_QUERY | RECURSION_DESIRED_FLAG); - iUdp.write((uint8_t*) &twoByteBuffer, sizeof(twoByteBuffer)); - - twoByteBuffer = htons(1); // One question record - iUdp.write((uint8_t*) &twoByteBuffer, sizeof(twoByteBuffer)); - - twoByteBuffer = 0; // Zero answer records - iUdp.write((uint8_t*) &twoByteBuffer, sizeof(twoByteBuffer)); - - iUdp.write((uint8_t*) &twoByteBuffer, sizeof(twoByteBuffer)); - - // and zero additional records - iUdp.write((uint8_t*) &twoByteBuffer, sizeof(twoByteBuffer)); - - // Build question - const char* start = aName; - const char* end = start; - uint8_t len; - // Run through the name being requested - - while (*end) { - - // Find out how long this section of the name is - end = start; - while (*end && (*end != '.')) { - end++; - } - - if (end - start > 0) { - - // Write out the size of this section - len = end - start; - iUdp.write(&len, sizeof(len)); - - // And then write out the section - iUdp.write((uint8_t*)start, end - start); - } - - start = end + 1; - } - - // We've got to the end of the question name, so - // terminate it with a zero-length section - len = 0; - iUdp.write(&len, sizeof(len)); - - // Finally the type and class of question - twoByteBuffer = htons(TYPE_A); - iUdp.write((uint8_t*) &twoByteBuffer, sizeof(twoByteBuffer)); - - twoByteBuffer = htons(CLASS_IN); // Internet class of question - iUdp.write((uint8_t*) &twoByteBuffer, sizeof(twoByteBuffer)); - - // Success! Everything buffered okay - return 1; -} - -/** - * @brief - * @note - * @param - * @retval - */ -uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress& aAddress) { - uint32_t startTime = millis(); - - // Wait for a response packet - - while (iUdp.parsePacket() <= 0) { - if ((millis() - startTime) > aTimeout) - return TIMED_OUT; - wait(0.050); - } - - // We've had a reply! - // Read the UDP header - uint8_t header[DNS_HEADER_SIZE]; // Enough space to reuse for the DNS header - - // Check that it's a response from the right server and the right port - if ((iDNSServer != iUdp.remoteIP()) || (iUdp.remotePort() != DNS_PORT)) { - - // It's not from who we expected - return INVALID_SERVER; - } - - // Read through the rest of the response - if (iUdp.available() < DNS_HEADER_SIZE) { - return TRUNCATED; - } - - iUdp.read(header, DNS_HEADER_SIZE); - - uint16_t header_flags = htons(*((uint16_t*) &header[2])); - // Check that it's a response to this request - - if - ( - (iRequestId != (*((uint16_t*) &header[0]))) - || ((header_flags & QUERY_RESPONSE_MASK) != (uint16_t) RESPONSE_FLAG) - ) { - - // Mark the entire packet as read - iUdp.flush(); - return INVALID_RESPONSE; - } - - // Check for any errors in the response (or in our request) - // although we don't do anything to get round these - if ((header_flags & TRUNCATION_FLAG) || (header_flags & RESP_MASK)) { - - // Mark the entire packet as read - iUdp.flush(); - return -5; //INVALID_RESPONSE; - } - - // And make sure we've got (at least) one answer - uint16_t answerCount = htons(*((uint16_t*) &header[6])); - if (answerCount == 0) { - - // Mark the entire packet as read - iUdp.flush(); - return -6; //INVALID_RESPONSE; - } - - // Skip over any questions - for (uint16_t i = 0; i < htons(*((uint16_t*) &header[4])); i++) { - - // Skip over the name - uint8_t len; - do { - iUdp.read(&len, sizeof(len)); - if (len > 0) { - - // Don't need to actually read the data out for the string, just - // advance ptr to beyond it - while (len--) { - iUdp.read(); // we don't care about the returned byte - } - } - } while (len != 0); - - // Now jump over the type and class - for (int i = 0; i < 4; i++) { - iUdp.read(); // we don't care about the returned byte - } - } - - // Now we're up to the bit we're interested in, the answer - // There might be more than one answer (although we'll just use the first - // type A answer) and some authority and additional resource records but - // we're going to ignore all of them. - for (uint16_t i = 0; i < answerCount; i++) { - - // Skip the name - uint8_t len; - do { - iUdp.read(&len, sizeof(len)); - if ((len & LABEL_COMPRESSION_MASK) == 0) { - - // It's just a normal label - if (len > 0) { - - // And it's got a length - // Don't need to actually read the data out for the string, - // just advance ptr to beyond it - while (len--) { - iUdp.read(); // we don't care about the returned byte - } - } - } - else { - - // This is a pointer to a somewhere else in the message for the - // rest of the name. We don't care about the name, and RFC1035 - // says that a name is either a sequence of labels ended with a - // 0 length octet or a pointer or a sequence of labels ending in - // a pointer. Either way, when we get here we're at the end of - // the name - // Skip over the pointer - iUdp.read(); // we don't care about the returned byte - - // And set len so that we drop out of the name loop - len = 0; - } - } while (len != 0); - - // Check the type and class - uint16_t answerType; - uint16_t answerClass; - iUdp.read((uint8_t*) &answerType, sizeof(answerType)); - iUdp.read((uint8_t*) &answerClass, sizeof(answerClass)); - - // Ignore the Time-To-Live as we don't do any caching - for (int i = 0; i < TTL_SIZE; i++) { - iUdp.read(); // we don't care about the returned byte - } - - // And read out the length of this answer - // Don't need header_flags anymore, so we can reuse it here - iUdp.read((uint8_t*) &header_flags, sizeof(header_flags)); - - if ((htons(answerType) == TYPE_A) && (htons(answerClass) == CLASS_IN)) { - if (htons(header_flags) != 4) { - - // It's a weird size - // Mark the entire packet as read - iUdp.flush(); - return -9; //INVALID_RESPONSE; - } - - iUdp.read(aAddress.raw_address(), 4); - return SUCCESS; - } - else { - - // This isn't an answer type we're after, move onto the next one - for (uint16_t i = 0; i < htons(header_flags); i++) { - iUdp.read(); // we don't care about the returned byte - } - } - } - - // Mark the entire packet as read - iUdp.flush(); - - // If we get here then we haven't found an answer - return -10; //INVALID_RESPONSE; -}
--- a/Dns.h Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -// Arduino DNS client for Enc28J60-based Ethernet shield -// (c) Copyright 2009-2010 MCQN Ltd. -// Released under Apache License, version 2.0 -#ifndef DNSClient_h -#define DNSClient_h - -#include "UIPUdp.h" - -class DNSClient -{ -public: - // ctor - void begin(const IPAddress& aDNSServer); - - /** Convert a numeric IP address string into a four-byte IP address. - @param aIPAddrString IP address to convert - @param aResult IPAddress structure to store the returned IP address - @result 1 if aIPAddrString was successfully converted to an IP address, - else error code - */ - int inet_aton(const char* aIPAddrString, IPAddress& aResult); - - /** Resolve the given hostname to an IP address. - @param aHostname Name to be resolved - @param aResult IPAddress structure to store the returned IP address - @result 1 if aIPAddrString was successfully converted to an IP address, - else error code - */ - int getHostByName(const char* aHostname, IPAddress& aResult); -protected: - uint16_t BuildRequest(const char* aName); - uint16_t ProcessResponse(uint16_t aTimeout, IPAddress& aAddress); - - IPAddress iDNSServer; - uint16_t iRequestId; - UIPUDP iUdp; -}; -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DnsClient.cpp Tue Aug 27 15:01:10 2019 +0000 @@ -0,0 +1,423 @@ +// Arduino DNS client for Enc28J60-based Ethernet shield +// (c) Copyright 2009-2010 MCQN Ltd. +// Released under Apache License, version 2.0 +#include "UdpSocket.h" +#include "utility/util.h" + +#include "DnsClient.h" +#include <string.h> +#include "mbed.h" + +#define SOCKET_NONE 255 + +// Various flags and header field values for a DNS message + +#define UDP_HEADER_SIZE 8 +#define DNS_HEADER_SIZE 12 +#define TTL_SIZE 4 +#define QUERY_FLAG (0) +#define RESPONSE_FLAG (1 << 15) +#define QUERY_RESPONSE_MASK (1 << 15) +#define OPCODE_STANDARD_QUERY (0) +#define OPCODE_INVERSE_QUERY (1 << 11) +#define OPCODE_STATUS_REQUEST (2 << 11) +#define OPCODE_MASK (15 << 11) +#define AUTHORITATIVE_FLAG (1 << 10) +#define TRUNCATION_FLAG (1 << 9) +#define RECURSION_DESIRED_FLAG (1 << 8) +#define RECURSION_AVAILABLE_FLAG (1 << 7) +#define RESP_NO_ERROR (0) +#define RESP_FORMAT_ERROR (1) +#define RESP_SERVER_FAILURE (2) +#define RESP_NAME_ERROR (3) +#define RESP_NOT_IMPLEMENTED (4) +#define RESP_REFUSED (5) +#define RESP_MASK (15) +#define TYPE_A (0x0001) +#define CLASS_IN (0x0001) +#define LABEL_COMPRESSION_MASK (0xC0) + +// Port number that DNS servers listen on + +#define DNS_PORT 53 + +// Possible return codes from ProcessResponse + +#define SUCCESS 1 +#define TIMED_OUT - 1 +#define INVALID_SERVER - 2 +#define TRUNCATED - 3 +#define INVALID_RESPONSE - 4 + +/** + * @brief + * @note + * @param + * @retval + */ +void DnsClient::begin(const IpAddress& aDNSServer) +{ + iDNSServer = aDNSServer; + iRequestId = 0; +} + +/** + * @brief + * @note + * @param + * @retval + */ +int DnsClient::inet_aton(const char* aIPAddrString, IpAddress& aResult) +{ + // See if we've been given a valid IP address + const char* p = aIPAddrString; + while (*p && ((*p == '.') || ((*p >= '0') && (*p <= '9')))) { + p++; + } + + if (*p == '\0') { + // It's looking promising, we haven't found any invalid characters + p = aIPAddrString; + + int segment = 0; + int segmentValue = 0; + while (*p && (segment < 4)) { + if (*p == '.') { + // We've reached the end of a segment + if (segmentValue > 255) { + // You can't have IP address segments that don't fit in a byte + return 0; + } + else { + aResult[segment] = (uint8_t) segmentValue; + segment++; + segmentValue = 0; + } + } + else { + // Next digit + segmentValue = (segmentValue * 10) + (*p - '0'); + } + + p++; + } + + // We've reached the end of address, but there'll still be the last + // segment to deal with + if ((segmentValue > 255) || (segment > 3)) { + // You can't have IP address segments that don't fit in a byte, + // or more than four segments + return 0; + } + else { + aResult[segment] = (uint8_t) segmentValue; + return 1; + } + } + else { + return 0; + } +} + +/** + * @brief + * @note + * @param + * @retval + */ +int DnsClient::getHostByName(const char* aHostname, IpAddress& aResult) +{ + int ret = 0; + + // See if it's a numeric IP address + if (inet_aton(aHostname, aResult)) { + // It is, our work here is done + return 1; + } + + // Check we've got a valid DNS server to use + if (iDNSServer == INADDR_NONE) { + return INVALID_SERVER; + } + + // Find a socket to use + if (iUdp.begin(1024 + (time(NULL) & 0xF)) == 1) { + // Try up to three times + int retries = 0; + // while ((retries < 3) && (ret <= 0)) + { + // Send DNS request + ret = iUdp.beginPacket(iDNSServer, DNS_PORT); + if (ret != 0) { + // Now output the request data + ret = buildRequest(aHostname); + if (ret != 0) { + // And finally send the request + ret = iUdp.endPacket(); + if (ret != 0) { + // Now wait for a response + int wait_retries = 0; + ret = TIMED_OUT; + while ((wait_retries < 3) && (ret == TIMED_OUT)) { + ret = processResponse(5000, aResult); + wait_retries++; + } + } + } + } + + retries++; + } + + // We're done with the socket now + iUdp.stop(); + } + + return ret; +} + +/** + * @brief + * @note + * @param + * @retval + */ +uint16_t DnsClient::buildRequest(const char* aName) +{ + // Build header + // 1 1 1 1 1 1 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | ID | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // |QR| Opcode |AA|TC|RD|RA| Z | RCODE | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | QDCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | ANCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | NSCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | ARCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // As we only support one request at a time at present, we can simplify + // some of this header + srand(time(NULL)); + iRequestId = rand() % 0xFFFF + 1; // generate a random ID + uint16_t twoByteBuffer; + + // FIXME We should also check that there's enough space available to write to, rather + // FIXME than assume there's enough space (as the code does at present) + iUdp.write((uint8_t*) &iRequestId, sizeof(iRequestId)); + + twoByteBuffer = htons(QUERY_FLAG | OPCODE_STANDARD_QUERY | RECURSION_DESIRED_FLAG); + iUdp.write((uint8_t*) &twoByteBuffer, sizeof(twoByteBuffer)); + + twoByteBuffer = htons(1); // One question record + iUdp.write((uint8_t*) &twoByteBuffer, sizeof(twoByteBuffer)); + + twoByteBuffer = 0; // Zero answer records + iUdp.write((uint8_t*) &twoByteBuffer, sizeof(twoByteBuffer)); + + iUdp.write((uint8_t*) &twoByteBuffer, sizeof(twoByteBuffer)); + + // and zero additional records + iUdp.write((uint8_t*) &twoByteBuffer, sizeof(twoByteBuffer)); + + // Build question + const char* start = aName; + const char* end = start; + uint8_t len; + // Run through the name being requested + while (*end) { + // Find out how long this section of the name is + end = start; + while (*end && (*end != '.')) { + end++; + } + + if (end - start > 0) { + // Write out the size of this section + len = end - start; + iUdp.write(&len, sizeof(len)); + + // And then write out the section + iUdp.write((uint8_t*)start, end - start); + } + + start = end + 1; + } + + // We've got to the end of the question name, so + // terminate it with a zero-length section + len = 0; + iUdp.write(&len, sizeof(len)); + + // Finally the type and class of question + twoByteBuffer = htons(TYPE_A); + iUdp.write((uint8_t*) &twoByteBuffer, sizeof(twoByteBuffer)); + + twoByteBuffer = htons(CLASS_IN); // Internet class of question + iUdp.write((uint8_t*) &twoByteBuffer, sizeof(twoByteBuffer)); + + // Success! Everything buffered okay + return 1; +} + +/** + * @brief + * @note + * @param + * @retval + */ +int16_t DnsClient::processResponse(uint16_t aTimeout, IpAddress& aAddress) +{ + time_t startTime = time(NULL); + + // Wait for a response packet + while (iUdp.parsePacket() <= 0) { + if ((time(NULL) - startTime) > aTimeout) + return TIMED_OUT; + wait(0.050); + } + + // We've had a reply! + // Read the UDP header + uint8_t header[DNS_HEADER_SIZE]; // Enough space to reuse for the DNS header + + // Check that it's a response from the right server and the right port + if ((iDNSServer != iUdp.remoteIP()) || (iUdp.remotePort() != DNS_PORT)) { + // It's not from who we expected + return INVALID_SERVER; + } + + // Read through the rest of the response + if (iUdp.available() < DNS_HEADER_SIZE) { + return TRUNCATED; + } + + iUdp.read(header, DNS_HEADER_SIZE); + + uint16_t header_flags = htons(*((uint16_t*) &header[2])); + // Check that it's a response to this request + if + ( + (iRequestId != (*((uint16_t*) &header[0]))) || + ((header_flags & QUERY_RESPONSE_MASK) != (uint16_t) RESPONSE_FLAG) + ) { + // Mark the entire packet as read + iUdp.flush(); + return INVALID_RESPONSE; + } + + // Check for any errors in the response (or in our request) + // although we don't do anything to get round these + if ((header_flags & TRUNCATION_FLAG) || (header_flags & RESP_MASK)) { + // Mark the entire packet as read + iUdp.flush(); + return -5; //INVALID_RESPONSE; + } + + // And make sure we've got (at least) one answer + uint16_t answerCount = htons(*((uint16_t*) &header[6])); + if (answerCount == 0) { + // Mark the entire packet as read + iUdp.flush(); + return -6; //INVALID_RESPONSE; + } + + // Skip over any questions + for (uint16_t i = 0; i < htons(*((uint16_t*) &header[4])); i++) { + // Skip over the name + uint8_t len; + do { + iUdp.read(&len, sizeof(len)); + if (len > 0) { + // Don't need to actually read the data out for the string, just + // advance ptr to beyond it + while (len--) { + iUdp.read(); // we don't care about the returned byte + } + } + } while (len != 0); + + // Now jump over the type and class + for (int i = 0; i < 4; i++) { + iUdp.read(); // we don't care about the returned byte + } + } + + // Now we're up to the bit we're interested in, the answer + // There might be more than one answer (although we'll just use the first + // type A answer) and some authority and additional resource records but + // we're going to ignore all of them. + for (uint16_t i = 0; i < answerCount; i++) { + // Skip the name + uint8_t len; + do { + iUdp.read(&len, sizeof(len)); + if ((len & LABEL_COMPRESSION_MASK) == 0) { + // It's just a normal label + if (len > 0) { + // And it's got a length + // Don't need to actually read the data out for the string, + // just advance ptr to beyond it + while (len--) { + iUdp.read(); // we don't care about the returned byte + } + } + } + else { + // This is a pointer to a somewhere else in the message for the + // rest of the name. We don't care about the name, and RFC1035 + // says that a name is either a sequence of labels ended with a + // 0 length octet or a pointer or a sequence of labels ending in + // a pointer. Either way, when we get here we're at the end of + // the name + // Skip over the pointer + iUdp.read(); // we don't care about the returned byte + // And set len so that we drop out of the name loop + len = 0; + } + } while (len != 0); + + // Check the type and class + uint16_t answerType; + uint16_t answerClass; + iUdp.read((uint8_t*) &answerType, sizeof(answerType)); + iUdp.read((uint8_t*) &answerClass, sizeof(answerClass)); + + // Ignore the Time-To-Live as we don't do any caching + for (int i = 0; i < TTL_SIZE; i++) { + iUdp.read(); // we don't care about the returned byte + } + + // And read out the length of this answer + // Don't need header_flags anymore, so we can reuse it here + iUdp.read((uint8_t*) &header_flags, sizeof(header_flags)); + + if ((htons(answerType) == TYPE_A) && (htons(answerClass) == CLASS_IN)) { + if (htons(header_flags) != 4) { + // It's a weird size + // Mark the entire packet as read + iUdp.flush(); + return -9; //INVALID_RESPONSE; + } + + iUdp.read(aAddress.rawAddress(), 4); + return SUCCESS; + } + else { + // This isn't an answer type we're after, move onto the next one + for (uint16_t i = 0; i < htons(header_flags); i++) { + iUdp.read(); // we don't care about the returned byte + } + } + } + + // Mark the entire packet as read + iUdp.flush(); + + // If we get here then we haven't found an answer + return -10; //INVALID_RESPONSE; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DnsClient.h Tue Aug 27 15:01:10 2019 +0000 @@ -0,0 +1,39 @@ +// Arduino DNS client for Enc28J60-based Ethernet shield +// (c) Copyright 2009-2010 MCQN Ltd. +// Released under Apache License, version 2.0 +#ifndef DNSClient_h +#define DNSClient_h + +#include "UdpSocket.h" +#include "IpAddress.h" + +class DnsClient +{ +public: + // ctor + void begin(const IpAddress& aDNSServer); + + /** Convert a numeric IP address string into a four-byte IP address. + @param aIPAddrString IP address to convert + @param aResult IPAddress structure to store the returned IP address + @result 1 if aIPAddrString was successfully converted to an IP address, + else error code + */ + int inet_aton(const char* aIPAddrString, IpAddress& aResult); + + /** Resolve the given hostname to an IP address. + @param aHostname Name to be resolved + @param aResult IPAddress structure to store the returned IP address + @result 1 if aIPAddrString was successfully converted to an IP address, + else error code + */ + int getHostByName(const char* aHostname, IpAddress& aResult); +protected: + uint16_t buildRequest(const char* aName); + int16_t processResponse(uint16_t aTimeout, IpAddress& aAddress); + + IpAddress iDNSServer; + uint16_t iRequestId; + UdpSocket iUdp; +}; +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IpAddress.cpp Tue Aug 27 15:01:10 2019 +0000 @@ -0,0 +1,121 @@ +/* + IPAddress.cpp - Base class that provides IPAddress + Copyright (c) 2011 Adrian McEwen. All right reserved. + + Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.com> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include <stdio.h> +#include "mbed.h" +#include "IpAddress.h" + +/** + * @brief + * @note + * @param + * @retval + */ +IpAddress::IpAddress(void) { + memset(_address, 0, sizeof(_address)); +} + +/** + * @brief + * @note + * @param + * @retval + */ +IpAddress::IpAddress(uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4) { + _address[0] = octet1; + _address[1] = octet2; + _address[2] = octet3; + _address[3] = octet4; +} + +/** + * @brief + * @note + * @param + * @retval + */ +IpAddress::IpAddress(uint32_t address) { + memcpy(_address, &address, sizeof(_address)); +} + +/** + * @brief + * @note + * @param + * @retval + */ +IpAddress::IpAddress(const uint8_t address[4]) { + memcpy(_address, address, sizeof(_address)); +} + +/** + * @brief + * @note + * @param + * @retval + */ +//IPAddress &IPAddress::operator=(const uint8_t* address) { +// memcpy(_address, address, sizeof(_address)); +// return *this; +//} + +/** + * @brief + * @note + * @param + * @retval + */ +IpAddress &IpAddress::operator=(uint32_t address) { + memcpy(_address, (const uint8_t*) &address, sizeof(_address)); + return *this; +} + +/** + * @brief + * @note + * @param + * @retval + */ +bool IpAddress::operator==(const uint8_t* addr) const +{ + return memcmp(addr, _address, sizeof(_address)) == 0; +} + +/** + * @brief Returns IP Address as string of char + * @note + * @param + * @retval + */ +const char* IpAddress::toString(char* buf) { + uint8_t i = 0; + uint8_t j = 0; + + for (i = 0; i < 3; i++) { + j += sprintf(&buf[j], "%d", _address[i]); + buf[j++] = '.'; + } + + j += sprintf(&buf[j], "%d", _address[i]); + buf[j] = '\0'; + return buf; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IpAddress.h Tue Aug 27 15:01:10 2019 +0000 @@ -0,0 +1,72 @@ +/* + IpAddress.h - Base class that provides IPAddress + Copyright (c) 2011 Adrian McEwen. All right reserved. + + Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.com> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef IPADDRESS_H +#define IPADDRESS_H + +#include <stdio.h> + +// A class to make it easier to handle and pass around IP addresses + +class IpAddress +{ +private: + uint8_t _address[4]; // IPv4 address + +public: + // Constructors + IpAddress(void); + IpAddress(uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4); + IpAddress(uint32_t address); + IpAddress(const uint8_t address[4]); + + // Overloaded cast operator to allow IPAddress objects to be used where a pointer + // to a four-byte uint8_t array is expected + operator uint32_t(void) const { return *((uint32_t*)_address); } + bool operator==(const IpAddress& addr) const { return(*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); } + bool operator==(const uint8_t* addr) const; + + // Overloaded index operator to allow getting and setting individual octets of the address + uint8_t operator[](int index) const { return _address[index]; } + uint8_t &operator[](int index) { return _address[index]; } + + // Overloaded copy operators to allow initialisation of IPAddress objects from other types + IpAddress &operator =(uint32_t address); + + // Returns IP Address as string of char + const char* toString(char* buf); + + // Access the raw byte array containing the address. Because this returns a pointer + // to the internal structure rather than a copy of the address this function should only + // be used when you know that the usage of the returned uint8_t* will be transient and not + // stored. + uint8_t* rawAddress(void) { return _address; } + + // virtual size_t printTo(Print& p) const; + friend class UIPEthernet; + friend class UdpSocket; + friend class TcpClient; + friend class TcpServer; + friend class DhcpClient; + friend class DnsClient; +}; + +const IpAddress INADDR_NONE(0, 0, 0, 0); +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TcpClient.cpp Tue Aug 27 15:01:10 2019 +0000 @@ -0,0 +1,702 @@ +/* + UIPClient.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/>. + */ +extern "C" +{ +#include "utility/uip-conf.h" +#include "utility/uip.h" +#include "utility/uip_arp.h" +#include "string.h" +} +#include "UipEthernet.h" +#include "TcpClient.h" +#include "DnsClient.h" + +#define UIP_TCP_PHYH_LEN UIP_LLH_LEN + UIP_IPTCPH_LEN + +uip_userdata_t TcpClient::all_data[UIP_CONNS]; + +/** + * @brief + * @note + * @param + * @retval + */ +TcpClient::TcpClient() : + data(NULL) +{ } + +/** + * @brief + * @note + * @param + * @retval + */ +TcpClient::TcpClient(uip_userdata_t* conn_data) : + data(conn_data) +{ } + +/** + * @brief + * @note + * @param + * @retval + */ +int TcpClient::connect(IpAddress ip, uint16_t port) +{ + stop(); + + uip_ipaddr_t ipaddr; + uip_ip_addr(ipaddr, ip); + + struct uip_conn* conn = uip_connect(&ipaddr, htons(port)); + if (conn) + { +#if UIP_CONNECT_TIMEOUT > 0 + int32_t timeout = time(NULL) + UIP_CONNECT_TIMEOUT; +#endif + while ((conn->tcpstateflags & UIP_TS_MASK) != UIP_CLOSED) { + UipEthernet::ethernet->tick(); + if ((conn->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) { + data = (uip_userdata_t*)conn->appstate; +#ifdef UIPETHERNET_DEBUG_CLIENT + printf("connected, state: %d, first packet in: %d\r\n", data->state, data->packets_in[0]); +#endif + return 1; + } + +#if UIP_CONNECT_TIMEOUT > 0 + if (((int32_t) (time(NULL) - timeout)) > 0) { + conn->tcpstateflags = UIP_CLOSED; + break; + } +#endif + } + } + + return 0; +} + +/** + * @brief + * @note + * @param + * @retval + */ +int TcpClient::connect(const char* host, uint16_t port) +{ + // Look up the host first + int ret = 0; +#if UIP_UDP + DnsClient dns; + IpAddress remote_addr; + + dns.begin(UipEthernet::dnsServerAddress); + ret = dns.getHostByName(host, remote_addr); + if (ret == 1) { + return connect(remote_addr, port); + } +#endif + return ret; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void TcpClient::stop() +{ + if (data && data->state) + { +#ifdef UIPETHERNET_DEBUG_CLIENT + printf("before stop(), with data\r\n"); + _dumpAllData(); +#endif + _flushBlocks(&data->packets_in[0]); + if (data->state & UIP_CLIENT_REMOTECLOSED) { + data->state = 0; + } + else { + data->state |= UIP_CLIENT_CLOSE; + } + +#ifdef UIPETHERNET_DEBUG_CLIENT + printf("after stop()\r\n"); + _dumpAllData(); +#endif + } + +#ifdef UIPETHERNET_DEBUG_CLIENT + else { + printf("stop(), data: NULL\r\n"); + } +#endif + data = NULL; + UipEthernet::ethernet->tick(); +} + +/** + * @brief + * @note + * @param + * @retval + */ +uint8_t TcpClient::connected() +{ + return(data && (data->packets_in[0] != NOBLOCK || (data->state & UIP_CLIENT_CONNECTED))) ? 1 : 0; +} + +/** + * @brief + * @note + * @param + * @retval + */ +bool TcpClient::operator==(const TcpClient& rhs) +{ + return data && rhs.data && (data == rhs.data); +} + +/** + * @brief + * @note + * @param + * @retval + */ +TcpClient::operator bool() +{ + UipEthernet::ethernet->tick(); + return data && (!(data->state & UIP_CLIENT_REMOTECLOSED) || data->packets_in[0] != NOBLOCK); +} + +/** + * @brief + * @note + * @param + * @retval + */ +size_t TcpClient::write(uint8_t c) +{ + return _write(data, &c, 1); +} + +/** + * @brief + * @note + * @param + * @retval + */ +size_t TcpClient::write(const uint8_t* buf, size_t size) +{ + return _write(data, buf, size); +} + +/** + * @brief + * @note + * @param + * @retval + */ +size_t TcpClient::_write(uip_userdata_t* data, const uint8_t* buf, size_t size) +{ + int remain = size; + uint16_t written; +#if UIP_ATTEMPTS_ON_WRITE > 0 + uint16_t attempts = UIP_ATTEMPTS_ON_WRITE; +#endif + repeat : UipEthernet::ethernet->tick(); + if (data && !(data->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED))) { + uint8_t p = _currentBlock(&data->packets_out[0]); + if (data->packets_out[p] == NOBLOCK) + { +newpacket: + data->packets_out[p] = UipEthernet::ethernet->phy.allocBlock(UIP_SOCKET_DATALEN); + if (data->packets_out[p] == NOBLOCK) + { +#if UIP_ATTEMPTS_ON_WRITE > 0 + if (--attempts > 0) +#endif +#if UIP_ATTEMPTS_ON_WRITE != 0 + goto repeat; +#endif + goto ready; + } + + data->out_pos = 0; + } + +#ifdef UIPETHERNET_DEBUG_CLIENT + printf + ( + "UIPClient.write: writePacket(%d) pos: %d, buf[%d-%d]\r\n", + u->packets_out[p], + u->out_pos, + size - remain, + remain + ); +#endif + written = UipEthernet::ethernet->phy.writePacket + ( + data->packets_out[p], + data->out_pos, + (uint8_t*)buf + size - remain, + remain + ); + remain -= written; + data->out_pos += written; + if (remain > 0) { + if (p == UIP_SOCKET_NUMPACKETS - 1) + { +#if UIP_ATTEMPTS_ON_WRITE > 0 + if (--attempts > 0) +#endif +#if UIP_ATTEMPTS_ON_WRITE != 0 + goto repeat; +#endif + goto ready; + } + + p++; + goto newpacket; + } + +ready: + data->pollTimer.start(); + return size - remain; + } + + return -1; +} + +/** + * @brief + * @note + * @param + * @retval + */ +int TcpClient::available() +{ + if (*this) + return _available(data); + return 0; +} + +/** + * @brief + * @note + * @param + * @retval + */ +int TcpClient::_available(uip_userdata_t* u) +{ + int len = 0; + for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { + len += UipEthernet::ethernet->phy.blockSize(u->packets_in[i]); + } + + return len; +} + +/** + * @brief + * @note + * @param + * @retval + */ +int TcpClient::read(uint8_t* buf, size_t size) +{ + if (*this) { + uint16_t remain = size; + if (data->packets_in[0] == NOBLOCK) + return 0; + + uint16_t read; + do { + read = UipEthernet::ethernet->phy.readPacket(data->packets_in[0], 0, buf + size - remain, remain); + if (read == UipEthernet::ethernet->phy.blockSize(data->packets_in[0])) { + remain -= read; + _eatBlock(&data->packets_in[0]); + if + ( + uip_stopped(&uip_conns[data->state & UIP_CLIENT_SOCKETS]) && + !(data->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)) + ) data->state |= UIP_CLIENT_RESTART; + if (data->packets_in[0] == NOBLOCK) { + if (data->state & UIP_CLIENT_REMOTECLOSED) { + data->state = 0; + data = NULL; + } + + return size - remain; + } + } + else { + UipEthernet::ethernet->phy.resizeBlock(data->packets_in[0], read); + break; + } + } while (remain > 0); + return size; + } + + return -1; +} + +/** + * @brief + * @note + * @param + * @retval + */ +int TcpClient::read() +{ + static uint8_t c; + if (read(&c, 1) < 0) + return -1; + return c; +} + +/** + * @brief + * @note + * @param + * @retval + */ +int TcpClient::peek() +{ + static uint8_t c; + if (*this) { + if (data->packets_in[0] != NOBLOCK) { + UipEthernet::ethernet->phy.readPacket(data->packets_in[0], 0, &c, 1); + return c; + } + } + + return -1; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void TcpClient::flush() +{ + if (*this) { + _flushBlocks(&data->packets_in[0]); + } +} + +/** + * @brief + * @note + * @param + * @retval + */ +void TcpClient::close() +{ + delete this; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void uipclient_appcall() +{ + uint16_t send_len = 0; + uip_userdata_t* u = (uip_userdata_t*)uip_conn->appstate; + if (!u && uip_connected()) + { +#ifdef UIPETHERNET_DEBUG_CLIENT + printf("UIPClient uip_connected\r\n"); + UIPClient::_dumpAllData(); +#endif + u = (uip_userdata_t*)TcpClient::_allocateData(); + if (u) { + uip_conn->appstate = u; +#ifdef UIPETHERNET_DEBUG_CLIENT + printf("UIPClient allocated state: %d", u->state); +#endif + } + +#ifdef UIPETHERNET_DEBUG_CLIENT + else + printf("UIPClient allocation failed\r\n"); +#endif + } + + if (u) { + if (uip_newdata()) + { +#ifdef UIPETHERNET_DEBUG_CLIENT + printf("UIPClient uip_newdata, uip_len: %d\r\n", uip_len); +#endif + if (uip_len && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED))) { + for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { + if (u->packets_in[i] == NOBLOCK) { + u->packets_in[i] = UipEthernet::ethernet->phy.allocBlock(uip_len); + if (u->packets_in[i] != NOBLOCK) { + UipEthernet::ethernet->phy.copyPacket + ( + u->packets_in[i], + 0, + UipEthernet::inPacket, + ((uint8_t*)uip_appdata) - uip_buf, + uip_len + ); + if (i == UIP_SOCKET_NUMPACKETS - 1) + uip_stop(); + goto finish_newdata; + } + } + } + + UipEthernet::packetState &= ~UIPETHERNET_FREEPACKET; + uip_stop(); + } + } + +finish_newdata: + if (u->state & UIP_CLIENT_RESTART) { + u->state &= ~UIP_CLIENT_RESTART; + uip_restart(); + } + + // If the connection has been closed, save received but unread data. + if (uip_closed() || uip_timedout()) + { +#ifdef UIPETHERNET_DEBUG_CLIENT + printf("UIPClient uip_closed\r\n"); + UIPClient::_dumpAllData(); +#endif + // drop outgoing packets not sent yet: + + TcpClient::_flushBlocks(&u->packets_out[0]); + if (u->packets_in[0] != NOBLOCK) { + ((uip_userdata_closed_t*)u)->lport = uip_conn->lport; + u->state |= UIP_CLIENT_REMOTECLOSED; + } + else + u->state = 0; + + // disassociate appdata. +#ifdef UIPETHERNET_DEBUG_CLIENT + printf("after UIPClient uip_closed\r\n"); + UIPClient::_dumpAllData(); +#endif + uip_conn->appstate = NULL; + goto finish; + } + + if (uip_acked()) + { +#ifdef UIPETHERNET_DEBUG_CLIENT + printf("UIPClient uip_acked\r\n"); +#endif + TcpClient::_eatBlock(&u->packets_out[0]); + } + + if (uip_poll() || uip_rexmit()) + { +#ifdef UIPETHERNET_DEBUG_CLIENT + //printf("UIPClient uip_poll\r\n"); +#endif + if (u->packets_out[0] != NOBLOCK) { + if (u->packets_out[1] == NOBLOCK) { + send_len = u->out_pos; + if (send_len > 0) { + UipEthernet::ethernet->phy.resizeBlock(u->packets_out[0], 0, send_len); + } + } + else + send_len = UipEthernet::ethernet->phy.blockSize(u->packets_out[0]); + if (send_len > 0) { + UipEthernet::uipHeaderLen = ((uint8_t*)uip_appdata) - uip_buf; + UipEthernet::uipPacket = UipEthernet::ethernet->phy.allocBlock(UipEthernet::uipHeaderLen + send_len); + if (UipEthernet::uipPacket != NOBLOCK) { + UipEthernet::ethernet->phy.copyPacket + ( + UipEthernet::uipPacket, + UipEthernet::uipHeaderLen, + u->packets_out[0], + 0, + send_len + ); + UipEthernet::packetState |= UIPETHERNET_SENDPACKET; + } + } + + goto finish; + } + } + + // don't close connection unless all outgoing packets are sent + if (u->state & UIP_CLIENT_CLOSE) + { +#ifdef UIPETHERNET_DEBUG_CLIENT + printf("UIPClient state UIP_CLIENT_CLOSE\r\n"); + UIPClient::_dumpAllData(); +#endif + if (u->packets_out[0] == NOBLOCK) { + u->state = 0; + uip_conn->appstate = NULL; + uip_close(); +#ifdef UIPETHERNET_DEBUG_CLIENT + printf("no blocks out -> free userdata\r\n"); + UIPClient::_dumpAllData(); +#endif + } + else { + uip_stop(); +#ifdef UIPETHERNET_DEBUG_CLIENT + printf("blocks outstanding transfer -> uip_stop()\r\n"); +#endif + } + } + } + +finish: + uip_send(uip_appdata, send_len); + uip_len = send_len; +} + +/** + * @brief + * @note + * @param + * @retval + */ +uip_userdata_t* TcpClient::_allocateData() +{ + for (uint8_t sock = 0; sock < UIP_CONNS; sock++) { + uip_userdata_t* data = &TcpClient::all_data[sock]; + if (!data->state) { + data->pollTimer.reset(); + data->state = sock | UIP_CLIENT_CONNECTED; + memset(data->packets_in, 0, sizeof(data->packets_in) / sizeof(data->packets_in[0])); + memset(&data->packets_out, 0, sizeof(data->packets_out) / sizeof(data->packets_out[0])); + data->out_pos = 0; + return data; + } + } + + return NULL; +} + +/** + * @brief + * @note + * @param + * @retval + */ +uint8_t TcpClient::_currentBlock(memhandle* block) +{ + for (uint8_t i = 1; i < UIP_SOCKET_NUMPACKETS; i++) { + if (block[i] == NOBLOCK) + return i - 1; + } + + return UIP_SOCKET_NUMPACKETS - 1; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void TcpClient::_eatBlock(memhandle* block) +{ +#ifdef UIPETHERNET_DEBUG_CLIENT + memhandle* start = block; + printf("eatblock(%d): ", *block); + for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { + printf("%d ", start[i]); + } + + printf("-> "); +#endif + UipEthernet::ethernet->phy.freeBlock(block[0]); + for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS - 1; i++) { + block[i] = block[i + 1]; + } + + block[UIP_SOCKET_NUMPACKETS - 1] = NOBLOCK; +#ifdef UIPETHERNET_DEBUG_CLIENT + for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { + printf("%d ", start[i]); + } + + printf("\r\n"); +#endif +} + +/** + * @brief + * @note + * @param + * @retval + */ +void TcpClient::_flushBlocks(memhandle* block) +{ + for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { + UipEthernet::ethernet->phy.freeBlock(block[i]); + block[i] = NOBLOCK; + } +} + +#ifdef UIPETHERNET_DEBUG_CLIENT + +/** + * @brief + * @note + * @param + * @retval + */ +void UIPClient::_dumpAllData() +{ + for (uint8_t i = 0; i < UIP_CONNS; i++) { + printf("UIPClient::all_data[%d], state:%d packets_in: ", i, all_data[i].state); + for (uint8_t j = 0; j < UIP_SOCKET_NUMPACKETS; j++) { + printf("%d ", all_data[i].packets_in[j]); + } + + printf("\r\n"); + if (all_data[i].state & UIP_CLIENT_REMOTECLOSED) { + printf("state remote closed, local port: %d", htons(((uip_userdata_closed_t *) (&all_data[i]))->lport)); + printf("\r\n"); + } + else { + printf("packets_out: "); + for (uint8_t j = 0; j < UIP_SOCKET_NUMPACKETS; j++) { + printf("%d ", all_data[i].packets_out[j]); + } + + printf("\r\n"); + printf("out_pos: %d\r\n", all_data[i].out_pos); + } + } +} +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TcpClient.h Tue Aug 27 15:01:10 2019 +0000 @@ -0,0 +1,105 @@ +/* + UIPClient.h - Arduino implementation of a UIP wrapper class. + Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de> + All rights reserved. + + 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/>. + */ +#ifndef UIPCLIENT_H +#define UIPCLIENT_H + +#include "mbed.h" +#include "Client.h" +#include "utility/MemPool.h" + +extern "C" +{ +#include "utility/uip.h" +} +#define UIP_SOCKET_DATALEN UIP_TCP_MSS +//#define UIP_SOCKET_NUMPACKETS UIP_RECEIVE_WINDOW/UIP_TCP_MSS+1 + +#ifndef UIP_SOCKET_NUMPACKETS +#define UIP_SOCKET_NUMPACKETS 5 +#endif +#define UIP_CLIENT_CONNECTED 0x10 +#define UIP_CLIENT_CLOSE 0x20 +#define UIP_CLIENT_REMOTECLOSED 0x40 +#define UIP_CLIENT_RESTART 0x80 +#define UIP_CLIENT_STATEFLAGS (UIP_CLIENT_CONNECTED | UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED | UIP_CLIENT_RESTART) +#define UIP_CLIENT_SOCKETS ~UIP_CLIENT_STATEFLAGS + +typedef uint8_t uip_socket_ptr; + +typedef struct +{ + uint8_t state; + memhandle packets_in[UIP_SOCKET_NUMPACKETS]; + uint16_t lport; /**< The local TCP port, in network byte order. */ +} uip_userdata_closed_t; + +typedef struct +{ + Timer pollTimer; + uint8_t state; + memhandle packets_in[UIP_SOCKET_NUMPACKETS]; + memhandle packets_out[UIP_SOCKET_NUMPACKETS]; + memaddress out_pos; +} uip_userdata_t; + +class TcpClient : public Client +{ +public: + TcpClient(); + //TcpClient(UIPEthernet* ethernet); + //TcpClient(struct uip_conn* _conn); + //TcpClient(struct uip_conn* _conn, UIPEthernet* ethernet); + TcpClient(uip_userdata_t* conn_data); + //TcpClient(uip_userdata_t* conn_data, UIPEthernet* ethernet); + virtual ~TcpClient() {} + int connect(IpAddress ip, uint16_t port); + int connect(const char* host, uint16_t port); + int read(uint8_t* buf, size_t size); + void stop(); + uint8_t connected(); + operator bool(); + virtual bool operator ==(const TcpClient& ); + virtual bool operator !=(const TcpClient& rhs) { return !this->operator ==(rhs); } + size_t write(uint8_t); + size_t write(const uint8_t* buf, size_t size); + int available(); + int read(); + int peek(); + void flush(); + void close(); + + static uip_userdata_t all_data[UIP_CONNS]; + static size_t _write(uip_userdata_t* , const uint8_t* buf, size_t size); + +private: + uip_userdata_t* data; + static uip_userdata_t* _allocateData(); + static int _available(uip_userdata_t* ); + static uint8_t _currentBlock(memhandle* blocks); + static void _eatBlock(memhandle* blocks); + static void _flushBlocks(memhandle* blocks); + +#ifdef UIPETHERNET_DEBUG_CLIENT + static void _dumpAllData(); +#endif + friend class UipEthernet; + friend class TcpServer; + friend void uipclient_appcall(); +}; +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TcpServer.cpp Tue Aug 27 15:01:10 2019 +0000 @@ -0,0 +1,131 @@ +/* + TcpServer.cpp - Arduino implementation of a UIP wrapper class. + Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de> + All rights reserved. + + 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/>. + */ +#include "UipEthernet.h" +#include "TcpServer.h" +extern "C" +{ +#include "utility/uip-conf.h" +} +/** + * @brief + * @note + * @param + * @retval + */ +TcpServer::TcpServer() +{ } + +/** + * @brief + * @note + * @param + * @retval + */ +TcpClient* TcpServer::accept() +{ + UipEthernet::ethernet->tick(); + for (uip_userdata_t * data = &TcpClient::all_data[0]; data < &TcpClient::all_data[UIP_CONNS]; data++) { + if + ( + data->packets_in[0] != NOBLOCK && + ( + ((data->state & UIP_CLIENT_CONNECTED) && uip_conns[data->state & UIP_CLIENT_SOCKETS].lport == _port) || + ((data->state & UIP_CLIENT_REMOTECLOSED) && ((uip_userdata_closed_t*)data)->lport == _port) + ) + ) { + return(new TcpClient(data)); + } + } + + return(new TcpClient()); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void TcpServer::open(UipEthernet* ethernet) +{ + //UIPEthernet::ethernet = ethernet; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void TcpServer::bind(uint8_t port) +{ + _port = htons(port); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void TcpServer::bind(const char* ip, uint8_t port) +{ + _port = htons(port); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void TcpServer::listen(uint8_t conns) +{ + _conns = _conns < UIP_CONNS ? conns : UIP_CONNS; + uip_listen(_port); + UipEthernet::ethernet->tick(); +} + +/** + * @brief + * @note + * @param + * @retval + */ +size_t TcpServer::send(uint8_t c) +{ + return send(&c, 1); +} + +/** + * @brief + * @note + * @param + * @retval + */ +size_t TcpServer::send(const uint8_t* buf, size_t size) +{ + size_t ret = 0; + for (uip_userdata_t * data = &TcpClient::all_data[0]; data < &TcpClient::all_data[UIP_CONNS]; data++) { + if ((data->state & UIP_CLIENT_CONNECTED) && uip_conns[data->state & UIP_CLIENT_SOCKETS].lport == _port) + ret += TcpClient::_write(data, buf, size); + } + + return ret; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TcpServer.h Tue Aug 27 15:01:10 2019 +0000 @@ -0,0 +1,42 @@ +/* + UIPServer.h - Arduino implementation of a UIP wrapper class. + Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de> + All rights reserved. + + 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/>. + */ +#ifndef UIPSERVER_H +#define UIPSERVER_H + +#include "Server.h" +#include "TcpClient.h" + +class UipEthernet; + +class TcpServer +{ +public: + TcpServer(); + void open(UipEthernet* ethernet); + void bind(uint8_t port); + void bind(const char* ip, uint8_t port); + void listen(uint8_t conns); + TcpClient* accept(); + size_t send(uint8_t); + size_t send(const uint8_t* buf, size_t size); +private: + uint16_t _port; + uint8_t _conns; +}; +#endif
--- a/UIPClient.cpp Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,666 +0,0 @@ -/* - UIPClient.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/>. - */ -extern "C" -{ -#include "utility/uip-conf.h" -#include "utility/uip.h" -#include "utility/uip_arp.h" -#include "utility/millis.h" -#include "string.h" -} -#include "UIPEthernet.h" -#include "UIPClient.h" -#include "Dns.h" - -#define UIP_TCP_PHYH_LEN UIP_LLH_LEN + UIP_IPTCPH_LEN - -uip_userdata_t UIPClient::all_data[UIP_CONNS]; - -/** - * @brief - * @note - * @param - * @retval - */ -UIPClient::UIPClient(void) : - data(NULL) -{ } - -/** - * @brief - * @note - * @param - * @retval - */ -UIPClient::UIPClient(uip_userdata_t* conn_data) : - data(conn_data) -{ } - -/** - * @brief - * @note - * @param - * @retval - */ -int UIPClient::connect(IPAddress ip, uint16_t port) { - stop(); - - uip_ipaddr_t ipaddr; - uip_ip_addr(ipaddr, ip); - - struct uip_conn* conn = uip_connect(&ipaddr, htons(port)); - if (conn) - { -#if UIP_CONNECT_TIMEOUT > 0 - int32_t timeout = millis() + 1000 * UIP_CONNECT_TIMEOUT; -#endif - while ((conn->tcpstateflags & UIP_TS_MASK) != UIP_CLOSED) { - uIPEthernet.tick(); - if ((conn->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) { - data = (uip_userdata_t*)conn->appstate; -#ifdef UIPETHERNET_DEBUG_CLIENT - printf("connected, state: %d, first packet in: %d\r\n", data->state, data->packets_in[0]); -#endif - return 1; - } - -#if UIP_CONNECT_TIMEOUT > 0 - if (((int32_t) (millis() - timeout)) > 0) { - conn->tcpstateflags = UIP_CLOSED; - break; - } -#endif - } - } - - return 0; -} - -/** - * @brief - * @note - * @param - * @retval - */ -int UIPClient::connect(const char* host, uint16_t port) { - - // Look up the host first - int ret = 0; -#if UIP_UDP - DNSClient dns; - IPAddress remote_addr; - - dns.begin(UIPEthernet::_dnsServerAddress); - ret = dns.getHostByName(host, remote_addr); - if (ret == 1) { - return connect(remote_addr, port); - } -#endif - return ret; -} - -/** - * @brief - * @note - * @param - * @retval - */ -void UIPClient::stop(void) { - if (data && data->state) - { -#ifdef UIPETHERNET_DEBUG_CLIENT - printf("before stop(), with data\r\n"); - _dumpAllData(); -#endif - _flushBlocks(&data->packets_in[0]); - if (data->state & UIP_CLIENT_REMOTECLOSED) { - data->state = 0; - } - else { - data->state |= UIP_CLIENT_CLOSE; - } - -#ifdef UIPETHERNET_DEBUG_CLIENT - printf("after stop()\r\n"); - _dumpAllData(); -#endif - } - -#ifdef UIPETHERNET_DEBUG_CLIENT - else { - printf("stop(), data: NULL\r\n"); - } -#endif - data = NULL; - uIPEthernet.tick(); -} - -/** - * @brief - * @note - * @param - * @retval - */ -uint8_t UIPClient::connected(void) { - return(data && (data->packets_in[0] != NOBLOCK || (data->state & UIP_CLIENT_CONNECTED))) ? 1 : 0; -} - -/** - * @brief - * @note - * @param - * @retval - */ -bool UIPClient::operator==(const UIPClient& rhs) { - return data && rhs.data && (data == rhs.data); -} - -/** - * @brief - * @note - * @param - * @retval - */ -UIPClient::operator bool(void) { - uIPEthernet.tick(); - return data && (!(data->state & UIP_CLIENT_REMOTECLOSED) || data->packets_in[0] != NOBLOCK); -} - -/** - * @brief - * @note - * @param - * @retval - */ -size_t UIPClient::write(uint8_t c) { - return _write(data, &c, 1); -} - -/** - * @brief - * @note - * @param - * @retval - */ -size_t UIPClient::write(const uint8_t* buf, size_t size) { - return _write(data, buf, size); -} - -/** - * @brief - * @note - * @param - * @retval - */ -size_t UIPClient::_write(uip_userdata_t* u, const uint8_t* buf, size_t size) { - int remain = size; - uint16_t written; -#if UIP_ATTEMPTS_ON_WRITE > 0 - uint16_t attempts = UIP_ATTEMPTS_ON_WRITE; -#endif - repeat : uIPEthernet.tick(); - if (u && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED))) { - uint8_t p = _currentBlock(&u->packets_out[0]); - if (u->packets_out[p] == NOBLOCK) - { -newpacket: - u->packets_out[p] = uIPEthernet.network.allocBlock(UIP_SOCKET_DATALEN); - if (u->packets_out[p] == NOBLOCK) - { -#if UIP_ATTEMPTS_ON_WRITE > 0 - if ((--attempts) > 0) -#endif -#if UIP_ATTEMPTS_ON_WRITE != 0 - goto repeat; -#endif - goto ready; - } - - u->out_pos = 0; - } - -#ifdef UIPETHERNET_DEBUG_CLIENT - printf("UIPClient.write: writePacket(%d) pos: %d, buf[%d-%d]\r\n", u->packets_out[p], u->out_pos, size - remain, remain); -#endif - written = uIPEthernet.network.writePacket - ( - u->packets_out[p], - u->out_pos, - (uint8_t*)buf + size - remain, - remain - ); - remain -= written; - u->out_pos += written; - if (remain > 0) { - if (p == UIP_SOCKET_NUMPACKETS - 1) - { -#if UIP_ATTEMPTS_ON_WRITE > 0 - if ((--attempts) > 0) -#endif -#if UIP_ATTEMPTS_ON_WRITE != 0 - goto repeat; -#endif - goto ready; - } - - p++; - goto newpacket; - } - -ready: -#if UIP_CLIENT_TIMER >= 0 - u->timer = millis() + UIP_CLIENT_TIMER; -#endif - return size - remain; - } - - return -1; -} - -/** - * @brief - * @note - * @param - * @retval - */ -int UIPClient::available(void) { - if (*this) - return _available(data); - return 0; -} - -/** - * @brief - * @note - * @param - * @retval - */ -int UIPClient::_available(uip_userdata_t* u) { - int len = 0; - for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { - len += uIPEthernet.network.blockSize(u->packets_in[i]); - } - - return len; -} - -/** - * @brief - * @note - * @param - * @retval - */ -int UIPClient::read(uint8_t* buf, size_t size) { - if (*this) { - uint16_t remain = size; - if (data->packets_in[0] == NOBLOCK) - return 0; - - uint16_t read; - do { - read = uIPEthernet.network.readPacket(data->packets_in[0], 0, buf + size - remain, remain); - if (read == uIPEthernet.network.blockSize(data->packets_in[0])) { - remain -= read; - _eatBlock(&data->packets_in[0]); - if - ( - uip_stopped(&uip_conns[data->state & UIP_CLIENT_SOCKETS]) - && !(data->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)) - ) data->state |= UIP_CLIENT_RESTART; - if (data->packets_in[0] == NOBLOCK) { - if (data->state & UIP_CLIENT_REMOTECLOSED) { - data->state = 0; - data = NULL; - } - - return size - remain; - } - } - else { - uIPEthernet.network.resizeBlock(data->packets_in[0], read); - break; - } - } while (remain > 0); - return size; - } - - return -1; -} - -/** - * @brief - * @note - * @param - * @retval - */ -int UIPClient::read(void) { - static uint8_t c; - if (read(&c, 1) < 0) - return -1; - return c; -} - -/** - * @brief - * @note - * @param - * @retval - */ -int UIPClient::peek(void) { - static uint8_t c; - if (*this) { - if (data->packets_in[0] != NOBLOCK) { - uIPEthernet.network.readPacket(data->packets_in[0], 0, &c, 1); - return c; - } - } - - return -1; -} - -/** - * @brief - * @note - * @param - * @retval - */ -void UIPClient::flush(void) { - if (*this) { - _flushBlocks(&data->packets_in[0]); - } -} - -/** - * @brief - * @note - * @param - * @retval - */ -void uipclient_appcall(void) { - uint16_t send_len = 0; - uip_userdata_t* u = (uip_userdata_t*)uip_conn->appstate; - if (!u && uip_connected()) - { -#ifdef UIPETHERNET_DEBUG_CLIENT - printf("UIPClient uip_connected\r\n"); - UIPClient::_dumpAllData(); -#endif - u = (uip_userdata_t*)UIPClient::_allocateData(); - if (u) { - uip_conn->appstate = u; -#ifdef UIPETHERNET_DEBUG_CLIENT - printf("UIPClient allocated state: %d", u->state); -#endif - } - -#ifdef UIPETHERNET_DEBUG_CLIENT - else - printf("UIPClient allocation failed\r\n"); -#endif - } - - if (u) { - if (uip_newdata()) - { -#ifdef UIPETHERNET_DEBUG_CLIENT - printf("UIPClient uip_newdata, uip_len: %d\r\n", uip_len); -#endif - if (uip_len && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED))) { - for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { - if (u->packets_in[i] == NOBLOCK) { - u->packets_in[i] = uIPEthernet.network.allocBlock(uip_len); - if (u->packets_in[i] != NOBLOCK) { - uIPEthernet.network.copyPacket - ( - u->packets_in[i], - 0, - UIPEthernet::in_packet, - ((uint8_t*)uip_appdata) - uip_buf, - uip_len - ); - if (i == UIP_SOCKET_NUMPACKETS - 1) - uip_stop(); - goto finish_newdata; - } - } - } - - UIPEthernet::packetstate &= ~UIPETHERNET_FREEPACKET; - uip_stop(); - } - } - -finish_newdata: - if (u->state & UIP_CLIENT_RESTART) { - u->state &= ~UIP_CLIENT_RESTART; - uip_restart(); - } - - // If the connection has been closed, save received but unread data. - if (uip_closed() || uip_timedout()) - { -#ifdef UIPETHERNET_DEBUG_CLIENT - printf("UIPClient uip_closed\r\n"); - UIPClient::_dumpAllData(); -#endif - // drop outgoing packets not sent yet: - - UIPClient::_flushBlocks(&u->packets_out[0]); - if (u->packets_in[0] != NOBLOCK) { - ((uip_userdata_closed_t*)u)->lport = uip_conn->lport; - u->state |= UIP_CLIENT_REMOTECLOSED; - } - else - u->state = 0; - - // disassociate appdata. -#ifdef UIPETHERNET_DEBUG_CLIENT - printf("after UIPClient uip_closed\r\n"); - UIPClient::_dumpAllData(); -#endif - uip_conn->appstate = NULL; - goto finish; - } - - if (uip_acked()) - { -#ifdef UIPETHERNET_DEBUG_CLIENT - printf("UIPClient uip_acked\r\n"); -#endif - UIPClient::_eatBlock(&u->packets_out[0]); - } - - if (uip_poll() || uip_rexmit()) - { -#ifdef UIPETHERNET_DEBUG_CLIENT - //printf("UIPClient uip_poll\r\n"); -#endif - if (u->packets_out[0] != NOBLOCK) { - if (u->packets_out[1] == NOBLOCK) { - send_len = u->out_pos; - if (send_len > 0) { - uIPEthernet.network.resizeBlock(u->packets_out[0], 0, send_len); - } - } - else - send_len = uIPEthernet.network.blockSize(u->packets_out[0]); - if (send_len > 0) { - UIPEthernet::uip_hdrlen = ((uint8_t*)uip_appdata) - uip_buf; - UIPEthernet::uip_packet = uIPEthernet.network.allocBlock(UIPEthernet::uip_hdrlen + send_len); - if (UIPEthernet::uip_packet != NOBLOCK) { - uIPEthernet.network.copyPacket - ( - UIPEthernet::uip_packet, - UIPEthernet::uip_hdrlen, - u->packets_out[0], - 0, - send_len - ); - UIPEthernet::packetstate |= UIPETHERNET_SENDPACKET; - } - } - - goto finish; - } - } - - // don't close connection unless all outgoing packets are sent - if (u->state & UIP_CLIENT_CLOSE) - { -#ifdef UIPETHERNET_DEBUG_CLIENT - printf("UIPClient state UIP_CLIENT_CLOSE\r\n"); - UIPClient::_dumpAllData(); -#endif - if (u->packets_out[0] == NOBLOCK) { - u->state = 0; - uip_conn->appstate = NULL; - uip_close(); -#ifdef UIPETHERNET_DEBUG_CLIENT - printf("no blocks out -> free userdata\r\n"); - UIPClient::_dumpAllData(); -#endif - } - else { - uip_stop(); -#ifdef UIPETHERNET_DEBUG_CLIENT - printf("blocks outstanding transfer -> uip_stop()\r\n"); -#endif - } - } - } - -finish: - uip_send(uip_appdata, send_len); - uip_len = send_len; -} - -/** - * @brief - * @note - * @param - * @retval - */ -uip_userdata_t* UIPClient::_allocateData(void) { - for (uint8_t sock = 0; sock < UIP_CONNS; sock++) { - uip_userdata_t* data = &UIPClient::all_data[sock]; - if (!data->state) { - data->state = sock | UIP_CLIENT_CONNECTED; - memset(&data->packets_in[0], 0, sizeof(uip_userdata_t) - sizeof(data->state)); - return data; - } - } - - return NULL; -} - -/** - * @brief - * @note - * @param - * @retval - */ -uint8_t UIPClient::_currentBlock(memhandle* block) { - for (uint8_t i = 1; i < UIP_SOCKET_NUMPACKETS; i++) { - if (block[i] == NOBLOCK) - return i - 1; - } - - return UIP_SOCKET_NUMPACKETS - 1; -} - -/** - * @brief - * @note - * @param - * @retval - */ -void UIPClient::_eatBlock(memhandle* block) -{ -#ifdef UIPETHERNET_DEBUG_CLIENT - memhandle* start = block; - printf("eatblock(%d): ", *block); - for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { - printf("%d ", start[i]); - } - - printf("-> "); -#endif - uIPEthernet.network.freeBlock(block[0]); - for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS - 1; i++) { - block[i] = block[i + 1]; - } - - block[UIP_SOCKET_NUMPACKETS - 1] = NOBLOCK; -#ifdef UIPETHERNET_DEBUG_CLIENT - for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { - printf("%d ", start[i]); - } - - printf("\r\n"); -#endif -} - -/** - * @brief - * @note - * @param - * @retval - */ -void UIPClient::_flushBlocks(memhandle* block) { - for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { - uIPEthernet.network.freeBlock(block[i]); - block[i] = NOBLOCK; - } -} - -#ifdef UIPETHERNET_DEBUG_CLIENT - -/** - * @brief - * @note - * @param - * @retval - */ -void UIPClient::_dumpAllData(void) { - for (uint8_t i = 0; i < UIP_CONNS; i++) { - printf("UIPClient::all_data[%d], state:%d packets_in: ", i, all_data[i].state); - for (uint8_t j = 0; j < UIP_SOCKET_NUMPACKETS; j++) { - printf("%d ", all_data[i].packets_in[j]); - } - - printf("\r\n"); - if (all_data[i].state & UIP_CLIENT_REMOTECLOSED) { - printf("state remote closed, local port: %d", htons(((uip_userdata_closed_t *) (&all_data[i]))->lport)); - printf("\r\n"); - } - else { - printf("packets_out: "); - for (uint8_t j = 0; j < UIP_SOCKET_NUMPACKETS; j++) { - printf("%d ", all_data[i].packets_out[j]); - } - - printf("\r\n"); - printf("out_pos: %d\r\n", all_data[i].out_pos); - } - } -} -#endif -
--- a/UIPClient.h Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,113 +0,0 @@ -/* - UIPClient.h - Arduino implementation of a UIP wrapper class. - Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de> - All rights reserved. - - 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/>. - */ -#ifndef UIPCLIENT_H -#define UIPCLIENT_H - -#include "ethernet_comp.h" -//#include "Print.h" - -#include "Client.h" -#include "utility/mempool.h" - -extern "C" -{ -#include "utility/uip.h" -} -#define UIP_SOCKET_DATALEN UIP_TCP_MSS -//#define UIP_SOCKET_NUMPACKETS UIP_RECEIVE_WINDOW/UIP_TCP_MSS+1 - -#ifndef UIP_SOCKET_NUMPACKETS -#define UIP_SOCKET_NUMPACKETS 5 -#endif -#define UIP_CLIENT_CONNECTED 0x10 -#define UIP_CLIENT_CLOSE 0x20 -#define UIP_CLIENT_REMOTECLOSED 0x40 -#define UIP_CLIENT_RESTART 0x80 -#define UIP_CLIENT_STATEFLAGS (UIP_CLIENT_CONNECTED | UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED | UIP_CLIENT_RESTART) -#define UIP_CLIENT_SOCKETS ~UIP_CLIENT_STATEFLAGS - -typedef uint8_t uip_socket_ptr; - -typedef struct -{ - uint8_t state; - memhandle packets_in[UIP_SOCKET_NUMPACKETS]; - uint16_t lport; /**< The local TCP port, in network byte order. */ -} uip_userdata_closed_t; - -typedef struct -{ - uint8_t state; - memhandle packets_in[UIP_SOCKET_NUMPACKETS]; - memhandle packets_out[UIP_SOCKET_NUMPACKETS]; - memaddress out_pos; -#if UIP_CLIENT_TIMER >= 0 - unsigned long timer; -#endif -} uip_userdata_t; - -class UIPClient : - public Client -{ -public: - UIPClient(void); - int connect(IPAddress ip, uint16_t port); - int connect(const char* host, uint16_t port); - int read(uint8_t* buf, size_t size); - void stop(void); - uint8_t connected(void); - operator bool(void); - virtual bool operator ==(const EthernetClient& ); - virtual bool operator !=(const EthernetClient& rhs) { return !this->operator ==(rhs); }; - - size_t write(uint8_t); - size_t write(const uint8_t* buf, size_t size); - int available(void); - int read(void); - int peek(void); - void flush(void); - -// using Print::write; - -private: - UIPClient(struct uip_conn* _conn); - UIPClient(uip_userdata_t* conn_data); - - uip_userdata_t* data; - - static uip_userdata_t all_data[UIP_CONNS]; - static uip_userdata_t* _allocateData(void); - - static size_t _write(uip_userdata_t* , const uint8_t* buf, size_t size); - static int _available(uip_userdata_t* ); - - static uint8_t _currentBlock(memhandle* blocks); - static void _eatBlock(memhandle* blocks); - static void _flushBlocks(memhandle* blocks); - -#ifdef UIPETHERNET_DEBUG_CLIENT - static void _dumpAllData(void); -#endif - friend class UIPEthernet; - friend class UIPServer; - - friend void uipclient_appcall(void); -}; -#endif -
--- a/UIPEthernet.cpp Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,596 +0,0 @@ -/* - 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/>. - */ -#include "mbed.h" -#include "UIPEthernet.h" -#include "utility/Enc28J60Network.h" -#include "UIPUdp.h" - -extern "C" -{ -#include "utility/uip-conf.h" -#include "utility/uip.h" -#include "utility/uip_arp.h" -#include "utility/uip_timer.h" -#include "utility/millis.h" -} -#define ETH_HDR ((struct uip_eth_hdr*) &uip_buf[0]) - -memhandle UIPEthernet::in_packet(NOBLOCK); -memhandle UIPEthernet::uip_packet(NOBLOCK); -uint8_t UIPEthernet::uip_hdrlen(0); -uint8_t UIPEthernet::packetstate(0); - -IPAddress UIPEthernet::_dnsServerAddress; -DhcpClass* UIPEthernet::_dhcp(NULL); - -unsigned long UIPEthernet::periodic_timer; - -/** - * @brief - * @note - * @param - * @retval - */ -void enc28J60_mempool_block_move_callback(memaddress dest, memaddress src, memaddress len) { - - //as ENC28J60 DMA is unable to copy single bytes: - - if (len == 1) { - uIPEthernet.network.writeByte(dest, uIPEthernet.network.readByte(src)); - } - else { - - // calculate address of last byte - len += src - 1; - - /* 1. Appropriately program the EDMAST, EDMAND - and EDMADST register pairs. The EDMAST - registers should point to the first byte to copy - from, the EDMAND registers should point to the - last byte to copy and the EDMADST registers - should point to the first byte in the destination - range. The destination range will always be - linear, never wrapping at any values except from - 8191 to 0 (the 8-Kbyte memory boundary). - Extreme care should be taken when - programming the start and end pointers to - prevent a never ending DMA operation which - would overwrite the entire 8-Kbyte buffer. - */ - uIPEthernet.network.writeRegPair(EDMASTL, src); - uIPEthernet.network.writeRegPair(EDMADSTL, dest); - - if ((src <= RXSTOP_INIT) && (len > RXSTOP_INIT)) - len -= (RXSTOP_INIT - RXSTART_INIT); - uIPEthernet.network.writeRegPair(EDMANDL, len); - - /* 2. If an interrupt at the end of the copy process is - desired, set EIE.DMAIE and EIE.INTIE and - clear EIR.DMAIF. - - 3. Verify that ECON1.CSUMEN is clear. */ - uIPEthernet.network.writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_CSUMEN); - - /* 4. Start the DMA copy by setting ECON1.DMAST. */ - uIPEthernet.network.writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST); - - // wait until runnig DMA is completed - while (uIPEthernet.network.readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST); - } -} - -/* - * 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. - */ -UIPEthernet::UIPEthernet(PinName mosi, PinName miso, PinName sck, PinName cs) : - network(mosi, miso, sck, cs) { - millis_start(); -} - -#if UIP_UDP - -/** - * @brief - * @note - * @param - * @retval - */ -int UIPEthernet::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; -} -#endif - -/** - * @brief - * @note - * @param - * @retval - */ -void UIPEthernet::begin(const uint8_t* mac, IPAddress ip) { - IPAddress dns = ip; - - dns[3] = 1; - begin(mac, ip, dns); -} - -/** - * @brief - * @note - * @param - * @retval - */ -void UIPEthernet::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 UIPEthernet::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 UIPEthernet::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 UIPEthernet::maintain(void) { - tick(); - - int rc = DHCP_CHECK_NONE; - -#if UIP_UDP - 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 an error, it will retry though - break; - } - } - - return rc; -#endif -} - -/** - * @brief - * @note - * @param - * @retval - */ -IPAddress UIPEthernet::localIP(void) { - uip_ipaddr_t a; - - uip_gethostaddr(a); - return ip_addr_uip(a); -} - -/** - * @brief - * @note - * @param - * @retval - */ -IPAddress UIPEthernet::subnetMask(void) { - uip_ipaddr_t a; - - uip_getnetmask(a); - return ip_addr_uip(a); -} - -/** - * @brief - * @note - * @param - * @retval - */ -IPAddress UIPEthernet::gatewayIP(void) { - uip_ipaddr_t a; - - uip_getdraddr(a); - return ip_addr_uip(a); -} - -/** - * @brief - * @note - * @param - * @retval - */ -IPAddress UIPEthernet::dnsServerIP(void) { - return _dnsServerAddress; -} - -/** - * @brief - * @note - * @param - * @retval - */ -void UIPEthernet::tick(void) { - if (in_packet == NOBLOCK) { - in_packet = network.receivePacket(); -#ifdef UIPETHERNET_DEBUG - if (in_packet != NOBLOCK) { - printf("--------------\r\nreceivePacket: %d\r\n", 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; //required for upper_layer_checksum of in_packet! -#ifdef UIPETHERNET_DEBUG - printf("readPacket type IP, uip_len: %d\r\n", 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 - printf("readPacket type ARP, uip_len: %d\r\n", uip_len); -#endif - uip_arp_arpin(); - if (uip_len > 0) { - network_send(); - } - } - } - - if (in_packet != NOBLOCK && (packetstate & UIPETHERNET_FREEPACKET)) - { -#ifdef UIPETHERNET_DEBUG - printf("freeing packet: %d\r\n", in_packet); -#endif - network.freePacket(); - in_packet = NOBLOCK; - } - } - - unsigned long now = millis(); - bool periodic = (long)(now - periodic_timer) >= 0; - - for (int i = 0; i < UIP_CONNS; i++) { - uip_conn = &uip_conns[i]; - if (periodic) { - uip_process(UIP_TIMER); - } - else { - if ((long)(now - ((uip_userdata_t*)uip_conn->appstate)->timer) >= 0) - uip_process(UIP_POLL_REQUEST); - else - continue; - } - - // If the above function invocation resulted in data that - // should be sent out on the Enc28J60Network, the global variable - // uip_len is set to a value > 0. - if (uip_len > 0) { - uip_arp_out(); - network_send(); - } - } - - if (periodic) { - periodic_timer = now + UIP_PERIODIC_TIMER; -#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 Enc28J60Network, the global variable - // uip_len is set to a value > 0. - if (uip_len > 0) { - UIPUDP::_send((uip_udp_userdata_t *) (uip_udp_conns[i].appstate)); - } - } -#endif // UIP_UDP - } -} - -/** - * @brief - * @note - * @param - * @retval - */ -bool UIPEthernet::network_send(void) { - if (packetstate & UIPETHERNET_SENDPACKET) - { -#ifdef UIPETHERNET_DEBUG - printf("Enc28J60Network_send uip_packet: %d, hdrlen: %d\r\n", uip_packet, uip_hdrlen); -#endif - uIPEthernet.network.writePacket(uip_packet, 0, uip_buf, uip_hdrlen); - packetstate &= ~UIPETHERNET_SENDPACKET; - goto sendandfree; - } - - uip_packet = Enc28J60Network::allocBlock(uip_len); - if (uip_packet != NOBLOCK) - { -#ifdef UIPETHERNET_DEBUG - printf("Enc28J60Network_send uip_buf (uip_len): %d, packet: %d\r\n", uip_len, uip_packet); -#endif - uIPEthernet.network.writePacket(uip_packet, 0, uip_buf, uip_len); - goto sendandfree; - } - - return false; -sendandfree: - network.sendPacket(uip_packet); - Enc28J60Network::freeBlock(uip_packet); - uip_packet = NOBLOCK; - return true; -} - -/** - * @brief - * @note - * @param - * @retval - */ -void UIPEthernet::init(const uint8_t* mac) { - periodic_timer = millis() + UIP_PERIODIC_TIMER; - - network.init((uint8_t*)mac); - uip_seteth_addr(mac); - - uip_init(); - uip_arp_init(); -} - -/** - * @brief - * @note - * @param - * @retval - */ -void UIPEthernet::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 - */ -uint16_t UIPEthernet::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; -} - -/** - * @brief - * @note - * @param - * @retval - */ -uint16_t UIPEthernet::ipchksum(void) { - uint16_t sum; - - sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN); - return(sum == 0) ? 0xffff : htons(sum); -} - -uint16_t -#if UIP_UDP -UIPEthernet::upper_layer_chksum(uint8_t proto) -#else -uip_tcpchksum (void) -#endif -{ - 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. */ -#if UIP_UDP - sum = upper_layer_len + proto; -#else - sum = upper_layer_len + UIP_PROTO_TCP; -#endif - /* Sum IP source and destination addresses. */ - - sum = UIPEthernet::chksum(sum, (u8_t*) &BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t)); - - uint8_t upper_layer_memlen; -#if UIP_UDP - switch (proto) { - // case UIP_PROTO_ICMP: - // case UIP_PROTO_ICMP6: - // upper_layer_memlen = upper_layer_len; - // break; - case UIP_PROTO_UDP: - upper_layer_memlen = UIP_UDPH_LEN; - break; - - default: - // case UIP_PROTO_TCP: - #endif - upper_layer_memlen = (BUF->tcpoffset >> 4) << 2; - #if UIP_UDP - break; - } -#endif - sum = UIPEthernet::chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_memlen); -#ifdef UIPETHERNET_DEBUG_CHKSUM - 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)); -#endif - if (upper_layer_memlen < upper_layer_len) { - sum = network.chksum - ( - sum, UIPEthernet::uip_packet, UIP_IPH_LEN + - UIP_LLH_LEN + - upper_layer_memlen, upper_layer_len - - upper_layer_memlen - ); -#ifdef UIPETHERNET_DEBUG_CHKSUM - 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)); -#endif - } - return(sum == 0) ? 0xffff : htons(sum); -} - -/** - * @brief - * @note - * @param - * @retval - */ -uint16_t uip_ipchksum(void) { - return uIPEthernet.ipchksum(); -} - -#if UIP_UDP - -/** - * @brief - * @note - * @param - * @retval - */ -uint16_t uip_tcpchksum(void) { - uint16_t sum = uIPEthernet.upper_layer_chksum(UIP_PROTO_TCP); - - return sum; -} - -/** - * @brief - * @note - * @param - * @retval - */ -uint16_t uip_udpchksum(void) { - uint16_t sum = uIPEthernet.upper_layer_chksum(UIP_PROTO_UDP); - - return sum; -} -#endif -
--- a/UIPEthernet.h Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -/* - UIPEthernet.h - 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/>. - */ -#ifndef UIPETHERNET_H -#define UIPETHERNET_H - -//#define UIPETHERNET_DEBUG - -//#define UIPETHERNET_DEBUG_CHKSUM -//#define UIPETHERNET_DEBUG_UDP -//#define UIPETHERNET_DEBUG_CLIENT -#include "ethernet_comp.h" -#include "mbed.h" -#include "Dhcp.h" -#include "IPAddress.h" -#include "utility/Enc28J60Network.h" -#include "UIPClient.h" -#include "UIPServer.h" -#include "UIPUdp.h" - -extern "C" -{ -#include "utility/uip_timer.h" -#include "utility/uip.h" -} -#define UIPETHERNET_FREEPACKET 1 -#define UIPETHERNET_SENDPACKET 2 - -#define uip_ip_addr(addr, ip) \ - do { \ - ((u16_t *) (addr))[0] = HTONS(((ip[0]) << 8) | (ip[1])); \ - ((u16_t *) (addr))[1] = HTONS(((ip[2]) << 8) | (ip[3])); \ - } while (0) -#define ip_addr_uip(a) IPAddress(a[0] & 0xFF, a[0] >> 8, a[1] & 0xFF, a[1] >> 8) //TODO this is not IPV6 capable - -#define uip_seteth_addr(eaddr) \ - do { \ - uip_ethaddr.addr[0] = eaddr[0]; \ - uip_ethaddr.addr[1] = eaddr[1]; \ - uip_ethaddr.addr[2] = eaddr[2]; \ - uip_ethaddr.addr[3] = eaddr[3]; \ - uip_ethaddr.addr[4] = eaddr[4]; \ - uip_ethaddr.addr[5] = eaddr[5]; \ - } while (0) -#define BUF ((struct uip_tcpip_hdr*) &uip_buf[UIP_LLH_LEN]) - class UIPEthernet - { - public: - Enc28J60Network network; - - UIPEthernet(PinName mosi, PinName miso, PinName sck, PinName cs); - - int begin(const uint8_t* mac); - void begin(const uint8_t* mac, IPAddress ip); - void begin(const uint8_t* mac, IPAddress ip, IPAddress dns); - void begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway); - void begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet); - - // maintain() must be called at regular intervals to process the incoming serial - // data and issue IP events to the sketch. It does not return until all IP - // events have been processed. Renews dhcp-lease if required. - int maintain(void); - - IPAddress localIP(void); - IPAddress subnetMask(void); - IPAddress gatewayIP(void); - IPAddress dnsServerIP(void); - private: - static memhandle in_packet; - static memhandle uip_packet; - static uint8_t uip_hdrlen; - static uint8_t packetstate; - - static IPAddress _dnsServerAddress; - static DhcpClass* _dhcp; - - static unsigned long periodic_timer; - - void init(const uint8_t* mac); - static void configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet); - - void tick(void); - - bool network_send(void); - - friend class UIPServer; - - friend class UIPClient; - - friend class UIPUDP; - - static uint16_t chksum(uint16_t sum, const uint8_t* data, uint16_t len); - static uint16_t ipchksum(void); -#if UIP_UDP - uint16_t upper_layer_chksum(uint8_t proto); -#endif - friend uint16_t uip_ipchksum(void); - friend uint16_t uip_tcpchksum(void); - friend uint16_t uip_udpchksum(void); - - friend void uipclient_appcall(void); - friend void uipudp_appcall(void); - -#if UIP_CONF_IPV6 - uint16_t uip_icmp6chksum(void); -#endif /* UIP_CONF_IPV6 */ - }; - -extern UIPEthernet uIPEthernet; -#endif
--- a/UIPServer.cpp Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/* - UIPServer.cpp - Arduino implementation of a UIP wrapper class. - Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de> - All rights reserved. - - 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/>. - */ -#include "UIPEthernet.h" -#include "UIPServer.h" -extern "C" -{ -#include "utility/uip-conf.h" -} -/** - * @brief - * @note - * @param - * @retval - */ -UIPServer::UIPServer(uint16_t port) : - _port(htons(port)) -{ } - -/** - * @brief - * @note - * @param - * @retval - */ -UIPClient UIPServer::available(void) { - uIPEthernet.tick(); - for (uip_userdata_t * data = &UIPClient::all_data[0]; data < &UIPClient::all_data[UIP_CONNS]; data++) { - if - ( - data->packets_in[0] != NOBLOCK - && ( - ((data->state & UIP_CLIENT_CONNECTED) && uip_conns[data->state & UIP_CLIENT_SOCKETS].lport == _port) - || ((data->state & UIP_CLIENT_REMOTECLOSED) && ((uip_userdata_closed_t*)data)->lport == _port) - ) - ) return UIPClient(data); - } - - return UIPClient(); -} - -/** - * @brief - * @note - * @param - * @retval - */ -void UIPServer::begin(void) { - uip_listen(_port); - uIPEthernet.tick(); -} - -/** - * @brief - * @note - * @param - * @retval - */ -size_t UIPServer::write(uint8_t c) { - return write(&c, 1); -} - -/** - * @brief - * @note - * @param - * @retval - */ -size_t UIPServer::write(const uint8_t* buf, size_t size) { - size_t ret = 0; - for (uip_userdata_t * data = &UIPClient::all_data[0]; data < &UIPClient::all_data[UIP_CONNS]; data++) { - if ((data->state & UIP_CLIENT_CONNECTED) && uip_conns[data->state & UIP_CLIENT_SOCKETS].lport == _port) - ret += UIPClient::_write(data, buf, size); - } - - return ret; -}
--- a/UIPServer.h Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - UIPServer.h - Arduino implementation of a UIP wrapper class. - Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de> - All rights reserved. - - 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/>. - */ -#ifndef UIPSERVER_H -#define UIPSERVER_H - -#include "ethernet_comp.h" -#include "Server.h" -#include "UIPClient.h" - -class UIPServer : - public Server -{ -public: - UIPServer(uint16_t); - UIPClient available(void); - void begin(void); - size_t write(uint8_t); - size_t write(const uint8_t* buf, size_t size); - -// using Print::write; - -private: - uint16_t _port; -}; -#endif
--- a/UIPUdp.cpp Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,354 +0,0 @@ -/* - UIPUdp.cpp - Arduino implementation of a UIP wrapper class. - Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de> - All rights reserved. - - 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/>. - */ -#include "UIPEthernet.h" -#include "UIPUdp.h" -#include "Dns.h" - -extern "C" -{ -#include "utility/uip-conf.h" -#include "utility/uip.h" -#include "utility/uip_arp.h" -} -#if UIP_UDP -#define UIP_ARPHDRSIZE 42 -#define UDPBUF ((struct uip_udpip_hdr*) &uip_buf[UIP_LLH_LEN]) - -// Constructor -UIPUDP::UIPUDP(void) : - _uip_udp_conn(NULL) { - memset(&appdata, 0, sizeof(appdata)); -} - -// initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use -uint8_t UIPUDP::begin(uint16_t port) { - if (!_uip_udp_conn) { - _uip_udp_conn = uip_udp_new(NULL, 0); - } - - if (_uip_udp_conn) { - uip_udp_bind(_uip_udp_conn, htons(port)); - _uip_udp_conn->appstate = &appdata; - return 1; - } - - return 0; -} - -// Finish with the UDP socket -void UIPUDP::stop(void) { - if (_uip_udp_conn) { - uip_udp_remove(_uip_udp_conn); - _uip_udp_conn->appstate = NULL; - _uip_udp_conn = NULL; - uIPEthernet.network.freeBlock(appdata.packet_in); - uIPEthernet.network.freeBlock(appdata.packet_next); - uIPEthernet.network.freeBlock(appdata.packet_out); - memset(&appdata, 0, sizeof(appdata)); - } -} - -// Sending UDP packets -// Start building up a packet to send to the remote host specific in ip and port - -// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port -int UIPUDP::beginPacket(IPAddress ip, uint16_t port) { - uIPEthernet.tick(); - if (ip && port) { - uip_ipaddr_t ripaddr; - uip_ip_addr(&ripaddr, ip); -#ifdef UIPETHERNET_DEBUG_UDP - printf("udp beginPacket, "); -#endif - if (_uip_udp_conn) { - _uip_udp_conn->rport = htons(port); - uip_ipaddr_copy(_uip_udp_conn->ripaddr, &ripaddr); - } - else { - _uip_udp_conn = uip_udp_new(&ripaddr, htons(port)); - if (_uip_udp_conn) - { -#ifdef UIPETHERNET_DEBUG_UDP - printf("new connection, "); -#endif - _uip_udp_conn->appstate = &appdata; - } - else - { -#ifdef UIPETHERNET_DEBUG_UDP - printf("failed to allocate new connection\r\n"); -#endif - return 0; - } - } - -#ifdef UIPETHERNET_DEBUG_UDP - printf("rip: %s, port: %d\r\n", ip.asString(), port); -#endif - } - - if (_uip_udp_conn) { - if (appdata.packet_out == NOBLOCK) { - appdata.packet_out = uIPEthernet.network.allocBlock(UIP_UDP_MAXPACKETSIZE); - appdata.out_pos = UIP_UDP_PHYH_LEN; - if (appdata.packet_out != NOBLOCK) - return 1; -#ifdef UIPETHERNET_DEBUG_UDP - else - printf("failed to allocate memory for packet\r\n"); -#endif - } - -#ifdef UIPETHERNET_DEBUG_UDP - else - printf("previous packet on that connection not sent yet\r\n"); -#endif - } - - return 0; -} - -// Start building up a packet to send to the remote host specific in host and port - -// Returns 1 if successful, 0 if there was a problem resolving the hostname or port -int UIPUDP::beginPacket(const char* host, uint16_t port) { - - // Look up the host first - int ret = 0; - DNSClient dns; - IPAddress remote_addr; - - dns.begin(uIPEthernet.dnsServerIP()); - ret = dns.getHostByName(host, remote_addr); - if (ret == 1) { - return beginPacket(remote_addr, port); - } - else { - return ret; - } -} - -// Finish off this packet and send it - -// Returns 1 if the packet was sent successfully, 0 if there was an error -int UIPUDP::endPacket(void) { - if (_uip_udp_conn && appdata.packet_out != NOBLOCK) { - appdata.send = true; - uIPEthernet.network.resizeBlock(appdata.packet_out, 0, appdata.out_pos); - uip_udp_periodic_conn(_uip_udp_conn); - if (uip_len > 0) { - _send(&appdata); - return 1; - } - } - - return 0; -} - -// Write a single byte into the packet -size_t UIPUDP::write(uint8_t c) { - return write(&c, 1); -} - -// Write size bytes from buffer into the packet -size_t UIPUDP::write(const uint8_t* buffer, size_t size) { - if (appdata.packet_out != NOBLOCK) { - size_t ret = uIPEthernet.network.writePacket(appdata.packet_out, appdata.out_pos, (uint8_t*)buffer, size); - appdata.out_pos += ret; - return ret; - } - - return 0; -} - -// Start processing the next available incoming packet - -// Returns the size of the packet in bytes, or 0 if no packets are available -int UIPUDP::parsePacket(void) { - uIPEthernet.tick(); -#ifdef UIPETHERNET_DEBUG_UDP - if (appdata.packet_in != NOBLOCK) { - printf("udp parsePacket freeing previous packet: %d\r\n", appdata.packet_in); - } -#endif - uIPEthernet.network.freeBlock(appdata.packet_in); - - appdata.packet_in = appdata.packet_next; - appdata.packet_next = NOBLOCK; - -#ifdef UIPETHERNET_DEBUG_UDP - if (appdata.packet_in != NOBLOCK) { - printf("udp parsePacket received packet: %d", appdata.packet_in); - } -#endif - - int size = uIPEthernet.network.blockSize(appdata.packet_in); -#ifdef UIPETHERNET_DEBUG_UDP - if (appdata.packet_in != NOBLOCK) { - printf(", size: %d\r\n", size); - } -#endif - return size; -} - -// Number of bytes remaining in the current packet -int UIPUDP::available(void) { - uIPEthernet.tick(); - return uIPEthernet.network.blockSize(appdata.packet_in); -} - -// Read a single byte from the current packet -int UIPUDP::read(void) { - static unsigned char c; - if (read(&c, 1) > 0) { - return c; - } - - return -1; -} - -// Read up to len bytes from the current packet and place them into buffer - -// Returns the number of bytes read, or 0 if none are available -int UIPUDP::read(unsigned char* buffer, size_t len) { - uIPEthernet.tick(); - if (appdata.packet_in != NOBLOCK) { - memaddress read = uIPEthernet.network.readPacket(appdata.packet_in, 0, buffer, len); - if (read == uIPEthernet.network.blockSize(appdata.packet_in)) { - uIPEthernet.network.freeBlock(appdata.packet_in); - appdata.packet_in = NOBLOCK; - } - else - uIPEthernet.network.resizeBlock(appdata.packet_in, read); - return read; - } - - return 0; -} - -// Return the next byte from the current packet without moving on to the next byte -int UIPUDP::peek(void) { - uIPEthernet.tick(); - if (appdata.packet_in != NOBLOCK) { - unsigned char c; - if (uIPEthernet.network.readPacket(appdata.packet_in, 0, &c, 1) == 1) - return c; - } - - return -1; -} - -// Finish reading the current packet -void UIPUDP::flush(void) { - uIPEthernet.tick(); - uIPEthernet.network.freeBlock(appdata.packet_in); - appdata.packet_in = NOBLOCK; -} - -// Return the IP address of the host who sent the current incoming packet -IPAddress UIPUDP::remoteIP(void) { - return _uip_udp_conn ? ip_addr_uip(_uip_udp_conn->ripaddr) : IPAddress(); -} - -// Return the port of the host who sent the current incoming packet -uint16_t UIPUDP::remotePort(void) { - return _uip_udp_conn ? ntohs(_uip_udp_conn->rport) : 0; -} - -// UIP callback function -void uipudp_appcall(void) { - if (uip_udp_userdata_t * data = (uip_udp_userdata_t *) (uip_udp_conn->appstate)) { - if (uip_newdata()) { - if (data->packet_next == NOBLOCK) { - uip_udp_conn->rport = UDPBUF->srcport; - uip_ipaddr_copy(uip_udp_conn->ripaddr, UDPBUF->srcipaddr); - data->packet_next = uIPEthernet.network.allocBlock(ntohs(UDPBUF->udplen) - UIP_UDPH_LEN); - - //if we are unable to allocate memory the packet is dropped. udp doesn't guarantee packet delivery - if (data->packet_next != NOBLOCK) { - - //discard Linklevel and IP and udp-header and any trailing bytes: - uIPEthernet.network.copyPacket - ( - data->packet_next, - 0, - UIPEthernet::in_packet, - UIP_UDP_PHYH_LEN, - uIPEthernet.network.blockSize(data->packet_next) - ); -#ifdef UIPETHERNET_DEBUG_UDP - printf - ( - "udp, uip_newdata received packet: %d, size: %d\r\n", - data->packet_next, - UIPEthernet.network.blockSize(data->packet_next) - ); -#endif - } - } - } - - if (uip_poll() && data->send) - { - //set uip_slen (uip private) by calling uip_udp_send -#ifdef UIPETHERNET_DEBUG_UDP - printf - ( - "udp, uip_poll preparing packet to send: %d, size: %d\r\n", - data->packet_out, - UIPEthernet.network.blockSize(data->packet_out) - ); -#endif - UIPEthernet::uip_packet = data->packet_out; - UIPEthernet::uip_hdrlen = UIP_UDP_PHYH_LEN; - uip_udp_send(data->out_pos - (UIP_UDP_PHYH_LEN)); - } - } -} - -/** - * @brief - * @note - * @param - * @retval - */ -void UIPUDP::_send(uip_udp_userdata_t* data) { - uip_arp_out(); //add arp - if (uip_len == UIP_ARPHDRSIZE) { - UIPEthernet::uip_packet = NOBLOCK; - UIPEthernet::packetstate &= ~UIPETHERNET_SENDPACKET; -#ifdef UIPETHERNET_DEBUG_UDP - printf("udp, uip_poll results in ARP-packet\r\n"); -#endif - } - else { - - //arp found ethaddr for ip (otherwise packet is replaced by arp-request) - data->send = false; - data->packet_out = NOBLOCK; - UIPEthernet::packetstate |= UIPETHERNET_SENDPACKET; -#ifdef UIPETHERNET_DEBUG_UDP - printf("udp, uip_packet to send: %d\r\n", UIPEthernet::uip_packet); -#endif - } - - uIPEthernet.network_send(); -} -#endif -
--- a/UIPUdp.h Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +0,0 @@ -/* - UIPUdp.h - 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/>. - */ -#ifndef UIPUDP_H -#define UIPUDP_H - -#include "ethernet_comp.h" -#include "mbed.h" -#include "Udp.h" -#include "utility/mempool.h" -extern "C" -{ -#include "utility/uip.h" -} -#define UIP_UDP_MAXDATALEN 1500 -#define UIP_UDP_PHYH_LEN UIP_LLH_LEN + UIP_IPUDPH_LEN -#define UIP_UDP_MAXPACKETSIZE UIP_UDP_MAXDATALEN + UIP_UDP_PHYH_LEN - -typedef struct -{ - memaddress out_pos; - memhandle packet_next; - memhandle packet_in; - memhandle packet_out; - bool send; -} uip_udp_userdata_t; - -class UIPUDP : - public UDP -{ -private: - struct uip_udp_conn* _uip_udp_conn; - - uip_udp_userdata_t appdata; -public: - UIPUDP(void); // Constructor - uint8_t begin(uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use - void stop(void); // Finish with the UDP socket - - // Sending UDP packets - // Start building up a packet to send to the remote host specific in ip and port - // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port - int beginPacket(IPAddress ip, uint16_t port); - - // Start building up a packet to send to the remote host specific in host and port - // Returns 1 if successful, 0 if there was a problem resolving the hostname or port - int beginPacket(const char* host, uint16_t port); - - // Finish off this packet and send it - // Returns 1 if the packet was sent successfully, 0 if there was an error - int endPacket(void); - - // Write a single byte into the packet - size_t write(uint8_t); - - // Write size bytes from buffer into the packet - size_t write(const uint8_t* buffer, size_t size); - - // using Print::write; - // Start processing the next available incoming packet - // Returns the size of the packet in bytes, or 0 if no packets are available - int parsePacket(void); - - // Number of bytes remaining in the current packet - int available(void); - - // Read a single byte from the current packet - int read(void); - - // Read up to len bytes from the current packet and place them into buffer - // Returns the number of bytes read, or 0 if none are available - int read(unsigned char* buffer, size_t len); - // Read up to len characters from the current packet and place them into buffer - - // Returns the number of characters read, or 0 if none are available - int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); } - - // Return the next byte from the current packet without moving on to the next byte - int peek(void); - void flush(void); // Finish reading the current packet - - // Return the IP address of the host who sent the current incoming packet - IPAddress remoteIP(void); - - // Return the port of the host who sent the current incoming packet - uint16_t remotePort(void); -private: - friend void uipudp_appcall(void); - - friend class UIPEthernet; - static void _send(uip_udp_userdata_t* data); -}; -#endif
--- a/Udp.h Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -/* - * Udp.cpp: Library to send/receive UDP packets. - * - * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these) - * 1) UDP does not guarantee the order in which assembled UDP packets are received. This - * might not happen often in practice, but in larger network topologies, a UDP - * packet can be received out of sequence. - * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being - * aware of it. Again, this may not be a concern in practice on small local networks. - * For more information, see http://www.cafeaulait.org/course/week12/35.html - * - * MIT License: - * Copyright (c) 2008 Bjoern Hartmann - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * bjoern@cs.stanford.edu 12/30/2008 - */ -#ifndef udp_h -#define udp_h - -#include "mbed.h" -#include "IPAddress.h" - -//class UDP : public Stream { -class UDP -{ -public: - virtual uint8_t begin(uint16_t) = 0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use - virtual void stop(void) = 0; // Finish with the UDP socket - - // Sending UDP packets - // Start building up a packet to send to the remote host specific in ip and port - // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port - virtual int beginPacket(IPAddress ip, uint16_t port) = 0; - - // Start building up a packet to send to the remote host specific in host and port - // Returns 1 if successful, 0 if there was a problem resolving the hostname or port - virtual int beginPacket(const char* host, uint16_t port) = 0; - - // Finish off this packet and send it - // Returns 1 if the packet was sent successfully, 0 if there was an error - virtual int endPacket(void) = 0; - - // Write a single byte into the packet - virtual size_t write(uint8_t) = 0; - - // Write size bytes from buffer into the packet - virtual size_t write(const uint8_t* buffer, size_t size) = 0; - - // Start processing the next available incoming packet - // Returns the size of the packet in bytes, or 0 if no packets are available - virtual int parsePacket(void) = 0; - - // Number of bytes remaining in the current packet - virtual int available(void) = 0; - - // Read a single byte from the current packet - virtual int read(void) = 0; - - // Read up to len bytes from the current packet and place them into buffer - // Returns the number of bytes read, or 0 if none are available - virtual int read(unsigned char* buffer, size_t len) = 0; - - // Read up to len characters from the current packet and place them into buffer - // Returns the number of characters read, or 0 if none are available - virtual int read(char* buffer, size_t len) = 0; - - // Return the next byte from the current packet without moving on to the next byte - virtual int peek(void) = 0; - virtual void flush(void) = 0; // Finish reading the current packet - - // Return the IP address of the host who sent the current incoming packet - virtual IPAddress remoteIP(void) = 0; - - // Return the port of the host who sent the current incoming packet - virtual uint16_t remotePort(void) = 0; -protected: - uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; -}; -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UdpSocket.cpp Tue Aug 27 15:01:10 2019 +0000 @@ -0,0 +1,374 @@ +/* + UIPUdp.cpp - Arduino implementation of a UIP wrapper class. + Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de> + All rights reserved. + + 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/>. + */ +#include "UipEthernet.h" +#include "UdpSocket.h" +#include "DnsClient.h" + +extern "C" +{ +#include "utility/uip-conf.h" +#include "utility/uip.h" +#include "utility/uip_arp.h" +} +#if UIP_UDP +#define UIP_ARPHDRSIZE 42 +#define UDPBUF ((struct uip_udpip_hdr*) &uip_buf[UIP_LLH_LEN]) + +// Constructor +UdpSocket::UdpSocket() : + _uip_udp_conn(NULL) +{ + memset(&appdata, 0, sizeof(appdata)); +} + +// initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use +uint8_t UdpSocket::begin(uint16_t port) +{ + if (!_uip_udp_conn) { + _uip_udp_conn = uip_udp_new(NULL, 0); + } + + if (_uip_udp_conn) { + uip_udp_bind(_uip_udp_conn, htons(port)); + _uip_udp_conn->appstate = &appdata; + return 1; + } + + return 0; +} + +// Finish with the UDP socket +void UdpSocket::stop() +{ + if (_uip_udp_conn) { + uip_udp_remove(_uip_udp_conn); + _uip_udp_conn->appstate = NULL; + _uip_udp_conn = NULL; + UipEthernet::ethernet->phy.freeBlock(appdata.packet_in); + UipEthernet::ethernet->phy.freeBlock(appdata.packet_next); + UipEthernet::ethernet->phy.freeBlock(appdata.packet_out); + memset(&appdata, 0, sizeof(appdata)); + } +} + +// Sending UDP packets +// Start building up a packet to send to the remote host specific in ip and port + +// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port +int UdpSocket::beginPacket(IpAddress ip, uint16_t port) +{ + UipEthernet::ethernet->tick(); + if (ip && port) { + uip_ipaddr_t ripaddr; + uip_ip_addr(&ripaddr, ip); +#ifdef UIPETHERNET_DEBUG_UDP + printf("udp beginPacket, "); +#endif + if (_uip_udp_conn) { + _uip_udp_conn->rport = htons(port); + uip_ipaddr_copy(_uip_udp_conn->ripaddr, &ripaddr); + } + else { + _uip_udp_conn = uip_udp_new(&ripaddr, htons(port)); + if (_uip_udp_conn) + { +#ifdef UIPETHERNET_DEBUG_UDP + printf("new connection, "); +#endif + _uip_udp_conn->appstate = &appdata; + } + else + { +#ifdef UIPETHERNET_DEBUG_UDP + printf("failed to allocate new connection\r\n"); +#endif + return 0; + } + } + +#ifdef UIPETHERNET_DEBUG_UDP + printf("rip: %s, port: %d\r\n", ip.asString(), port); +#endif + } + + if (_uip_udp_conn) { + if (appdata.packet_out == NOBLOCK) { + appdata.packet_out = UipEthernet::ethernet->phy.allocBlock(UIP_UDP_MAXPACKETSIZE); + appdata.out_pos = UIP_UDP_PHYH_LEN; + if (appdata.packet_out != NOBLOCK) + return 1; +#ifdef UIPETHERNET_DEBUG_UDP + else + printf("failed to allocate memory for packet\r\n"); +#endif + } + +#ifdef UIPETHERNET_DEBUG_UDP + else + printf("previous packet on that connection not sent yet\r\n"); +#endif + } + + return 0; +} + +// Start building up a packet to send to the remote host specific in host and port + +// Returns 1 if successful, 0 if there was a problem resolving the hostname or port +int UdpSocket::beginPacket(const char* host, uint16_t port) +{ + // Look up the host first + int ret = 0; + DnsClient dns; + IpAddress remote_addr; + + dns.begin(UipEthernet::ethernet->dnsServerIP()); + ret = dns.getHostByName(host, remote_addr); + if (ret == 1) { + return beginPacket(remote_addr, port); + } + else { + return ret; + } +} + +// Finish off this packet and send it + +// Returns 1 if the packet was sent successfully, 0 if there was an error +int UdpSocket::endPacket() +{ + if (_uip_udp_conn && appdata.packet_out != NOBLOCK) { + appdata.send = true; + UipEthernet::ethernet->phy.resizeBlock(appdata.packet_out, 0, appdata.out_pos); + uip_udp_periodic_conn(_uip_udp_conn); + if (uip_len > 0) { + _send(&appdata); + return 1; + } + } + + return 0; +} + +// Write a single byte into the packet +size_t UdpSocket::write(uint8_t c) +{ + return write(&c, 1); +} + +// Write size bytes from buffer into the packet +size_t UdpSocket::write(const uint8_t* buffer, size_t size) +{ + if (appdata.packet_out != NOBLOCK) { + size_t ret = UipEthernet::ethernet->phy.writePacket + ( + appdata.packet_out, + appdata.out_pos, + (uint8_t*)buffer, + size + ); + appdata.out_pos += ret; + return ret; + } + + return 0; +} + +// Start processing the next available incoming packet + +// Returns the size of the packet in bytes, or 0 if no packets are available +int UdpSocket::parsePacket() +{ + UipEthernet::ethernet->tick(); +#ifdef UIPETHERNET_DEBUG_UDP + if (appdata.packet_in != NOBLOCK) { + printf("udp parsePacket freeing previous packet: %d\r\n", appdata.packet_in); + } +#endif + UipEthernet::ethernet->phy.freeBlock(appdata.packet_in); + + appdata.packet_in = appdata.packet_next; + appdata.packet_next = NOBLOCK; + +#ifdef UIPETHERNET_DEBUG_UDP + if (appdata.packet_in != NOBLOCK) { + printf("udp parsePacket received packet: %d", appdata.packet_in); + } +#endif + + int size = UipEthernet::ethernet->phy.blockSize(appdata.packet_in); +#ifdef UIPETHERNET_DEBUG_UDP + if (appdata.packet_in != NOBLOCK) { + printf(", size: %d\r\n", size); + } +#endif + return size; +} + +// Number of bytes remaining in the current packet +int UdpSocket::available() +{ + UipEthernet::ethernet->tick(); + return UipEthernet::ethernet->phy.blockSize(appdata.packet_in); +} + +// Read a single byte from the current packet +int UdpSocket::read() +{ + static unsigned char c; + if (read(&c, 1) > 0) { + return c; + } + + return -1; +} + +// Read up to len bytes from the current packet and place them into buffer + +// Returns the number of bytes read, or 0 if none are available +int UdpSocket::read(unsigned char* buffer, size_t len) +{ + UipEthernet::ethernet->tick(); + if (appdata.packet_in != NOBLOCK) { + memaddress read = UipEthernet::ethernet->phy.readPacket(appdata.packet_in, 0, buffer, len); + if (read == UipEthernet::ethernet->phy.blockSize(appdata.packet_in)) { + UipEthernet::ethernet->phy.freeBlock(appdata.packet_in); + appdata.packet_in = NOBLOCK; + } + else + UipEthernet::ethernet->phy.resizeBlock(appdata.packet_in, read); + return read; + } + + return 0; +} + +// Return the next byte from the current packet without moving on to the next byte +int UdpSocket::peek() +{ + UipEthernet::ethernet->tick(); + if (appdata.packet_in != NOBLOCK) { + unsigned char c; + if (UipEthernet::ethernet->phy.readPacket(appdata.packet_in, 0, &c, 1) == 1) + return c; + } + + return -1; +} + +// Finish reading the current packet +void UdpSocket::flush() +{ + UipEthernet::ethernet->tick(); + UipEthernet::ethernet->phy.freeBlock(appdata.packet_in); + appdata.packet_in = NOBLOCK; +} + +// Return the IP address of the host who sent the current incoming packet +IpAddress UdpSocket::remoteIP() +{ + return _uip_udp_conn ? ip_addr_uip(_uip_udp_conn->ripaddr) : IpAddress(); +} + +// Return the port of the host who sent the current incoming packet +uint16_t UdpSocket::remotePort() +{ + return _uip_udp_conn ? ntohs(_uip_udp_conn->rport) : 0; +} + +// UIP callback function +void uipudp_appcall() +{ + if (uip_udp_userdata_t * data = (uip_udp_userdata_t *) (uip_udp_conn->appstate)) { + if (uip_newdata()) { + if (data->packet_next == NOBLOCK) { + uip_udp_conn->rport = UDPBUF->srcport; + uip_ipaddr_copy(uip_udp_conn->ripaddr, UDPBUF->srcipaddr); + data->packet_next = UipEthernet::ethernet->phy.allocBlock(ntohs(UDPBUF->udplen) - UIP_UDPH_LEN); + + //if we are unable to allocate memory the packet is dropped. udp doesn't guarantee packet delivery + if (data->packet_next != NOBLOCK) { + //discard Linklevel and IP and udp-header and any trailing bytes: + UipEthernet::ethernet->phy.copyPacket + ( + data->packet_next, + 0, + UipEthernet::inPacket, + UIP_UDP_PHYH_LEN, + UipEthernet::ethernet->phy.blockSize(data->packet_next) + ); +#ifdef UIPETHERNET_DEBUG_UDP + printf + ( + "udp, uip_newdata received packet: %d, size: %d\r\n", + data->packet_next, + UIPEthernet.network.blockSize(data->packet_next) + ); +#endif + } + } + } + + if (uip_poll() && data->send) + { + //set uip_slen (uip private) by calling uip_udp_send +#ifdef UIPETHERNET_DEBUG_UDP + printf + ( + "udp, uip_poll preparing packet to send: %d, size: %d\r\n", + data->packet_out, + UIPEthernet.network.blockSize(data->packet_out) + ); +#endif + UipEthernet::uipPacket = data->packet_out; + UipEthernet::uipHeaderLen = UIP_UDP_PHYH_LEN; + uip_udp_send(data->out_pos - (UIP_UDP_PHYH_LEN)); + } + } +} + +/** + * @brief + * @note + * @param + * @retval + */ +void UdpSocket::_send(uip_udp_userdata_t* data) +{ + uip_arp_out(); //add arp + if (uip_len == UIP_ARPHDRSIZE) { + UipEthernet::uipPacket = NOBLOCK; + UipEthernet::packetState &= ~UIPETHERNET_SENDPACKET; +#ifdef UIPETHERNET_DEBUG_UDP + printf("udp, uip_poll results in ARP-packet\r\n"); +#endif + } + else { + //arp found ethaddr for ip (otherwise packet is replaced by arp-request) + data->send = false; + data->packet_out = NOBLOCK; + UipEthernet::packetState |= UIPETHERNET_SENDPACKET; +#ifdef UIPETHERNET_DEBUG_UDP + printf("udp, uip_packet to send: %d\r\n", UIPEthernet::uip_packet); +#endif + } + + UipEthernet::ethernet->network_send(); +} +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UdpSocket.h Tue Aug 27 15:01:10 2019 +0000 @@ -0,0 +1,108 @@ +/* + UIPUdp.h - 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/>. + */ +#ifndef UIPUDP_H +#define UIPUDP_H + +#include "mbed.h" +#include "utility/Udp.h" +#include "IpAddress.h" +#include "utility/MemPool.h" +extern "C" +{ +#include "utility/uip.h" +} +#define UIP_UDP_MAXDATALEN 1500 +#define UIP_UDP_PHYH_LEN UIP_LLH_LEN + UIP_IPUDPH_LEN +#define UIP_UDP_MAXPACKETSIZE UIP_UDP_MAXDATALEN + UIP_UDP_PHYH_LEN + +typedef struct +{ + memaddress out_pos; + memhandle packet_next; + memhandle packet_in; + memhandle packet_out; + bool send; +} uip_udp_userdata_t; + +class UdpSocket : public Udp +{ +private: + struct uip_udp_conn* _uip_udp_conn; + uip_udp_userdata_t appdata; +public: + UdpSocket(); // Constructor + virtual ~UdpSocket() { } // Virtual destructor + uint8_t begin(uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + void stop(); // Finish with the UDP socket + // Sending UDP packets + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + int beginPacket(IpAddress ip, uint16_t port); + + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + int beginPacket(const char* host, uint16_t port); + + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + int endPacket(); + + // Write a single byte into the packet + size_t write(uint8_t); + + // Write size bytes from buffer into the packet + size_t write(const uint8_t* buffer, size_t size); + + // using Print::write; + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + int parsePacket(); + + // Number of bytes remaining in the current packet + int available(); + + // Read a single byte from the current packet + int read(); + + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + int read(unsigned char* buffer, size_t len); + // Read up to len characters from the current packet and place them into buffer + + // Returns the number of characters read, or 0 if none are available + int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); } + + // Return the next byte from the current packet without moving on to the next byte + int peek(); + void flush(); // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + IpAddress remoteIP(); + + // Return the port of the host who sent the current incoming packet + uint16_t remotePort(); +private: + friend void uipudp_appcall(); + + friend class UipEthernet; + static void _send(uip_udp_userdata_t* data); +}; +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UipEthernet.cpp Tue Aug 27 15:01:10 2019 +0000 @@ -0,0 +1,661 @@ +/* + 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/>. + */ +#include "mbed.h" +#include "UipEthernet.h" +#include "utility/Enc28j60Py.h" +#include "UdpSocket.h" + +extern "C" +{ +#include "utility/uip-conf.h" +#include "utility/uip.h" +#include "utility/uip_arp.h" +#include "utility/uip_timer.h" +} +#define ETH_HDR ((struct uip_eth_hdr*) &uip_buf[0]) + +UipEthernet* UipEthernet:: ethernet = NULL; +memhandle UipEthernet:: inPacket(NOBLOCK); +memhandle UipEthernet:: uipPacket(NOBLOCK); +uint8_t UipEthernet:: uipHeaderLen(0); +uint8_t UipEthernet:: packetState(0); +IpAddress UipEthernet:: dnsServerAddress; +//DhcpClient UIPEthernet:: dhcpClient; + +/** + * @brief + * @note + * @param + * @retval + */ +void enc28j60_mempool_block_move_callback(memaddress dest, memaddress src, memaddress len) +{ + //as ENC28J60 DMA is unable to copy single bytes: + if (len == 1) { + UipEthernet::ethernet->phy.writeByte(dest, UipEthernet::ethernet->phy.readByte(src)); + } + else { + // calculate address of last byte + len += src - 1; + + /* 1. Appropriately program the EDMAST, EDMAND + and EDMADST register pairs. The EDMAST + registers should point to the first byte to copy + from, the EDMAND registers should point to the + last byte to copy and the EDMADST registers + should point to the first byte in the destination + range. The destination range will always be + linear, never wrapping at any values except from + 8191 to 0 (the 8-Kbyte memory boundary). + Extreme care should be taken when + programming the start and end pointers to + prevent a never ending DMA operation which + would overwrite the entire 8-Kbyte buffer. + */ + UipEthernet::ethernet->phy.writeRegPair(EDMASTL, src); + UipEthernet::ethernet->phy.writeRegPair(EDMADSTL, dest); + + if ((src <= RXSTOP_INIT) && (len > RXSTOP_INIT)) + len -= (RXSTOP_INIT - RXSTART_INIT); + UipEthernet::ethernet->phy.writeRegPair(EDMANDL, len); + + /* 2. If an interrupt at the end of the copy process is + desired, set EIE.DMAIE and EIE.INTIE and + clear EIR.DMAIF. + + 3. Verify that ECON1.CSUMEN is clear. */ + UipEthernet::ethernet->phy.writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_CSUMEN); + + /* 4. Start the DMA copy by setting ECON1.DMAST. */ + UipEthernet::ethernet->phy.writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST); + + // wait until runnig DMA is completed + while (UipEthernet::ethernet->phy.readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST); + } +} + +/* + * 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. + */ +UipEthernet::UipEthernet(const uint8_t mac[6], PinName mosi, PinName miso, PinName sck, PinName cs) : + phy(mosi, miso, sck, cs), + _mac(new uint8_t[6]), + _ip(), + _dns(), + _gateway(), + _subnet() +{ + for (uint8_t i = 0; i < 6; i++) + _mac[i] = mac[i]; +} + +#if UIP_UDP + +/** + * @brief + * @note + * @param + * @retval + */ +int UipEthernet::connect() +{ + // Inicialize static pointer to the UIPEthernet instance + ethernet = this; + + // Initialise the basic info + init(_mac); + + // If no local IP address has been set ask DHCP server to provide one + if (_ip == IpAddress()) { + // Now try to get our config info from a DHCP server + int ret = dhcpClient.begin((uint8_t*)_mac); + + if (ret == 1) { + // We've successfully found a DHCP server and got our configuration info, so set things + // accordingly + set_network + ( + dhcpClient.getLocalIp(), + dhcpClient.getDnsServerIp(), + dhcpClient.getGatewayIp(), + dhcpClient.getSubnetMask() + ); + } + + return ret; + } + else { + return 1; + } +} +#endif + +/** + * @brief + * @note + * @param + * @retval + */ +void UipEthernet::set_network(uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4) +{ + _ip = IpAddress(octet1, octet2, octet3, octet4); + set_network(_ip); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void UipEthernet::set_network(IpAddress ip) +{ + _ip = ip; + _dns = ip; + _dns[3] = 1; + set_network(ip, dns); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void UipEthernet::set_network(IpAddress ip, IpAddress dns) +{ + _ip = ip; + _dns = dns; + _gateway = ip; + _gateway[3] = 1; + set_network(ip, dns, _gateway); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void UipEthernet::set_network(IpAddress ip, IpAddress dns, IpAddress gateway) +{ + _ip = ip; + _dns = dns; + _gateway = gateway; + _subnet = IpAddress(255, 255, 255, 0); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void UipEthernet::set_network(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 + */ +IpAddress UipEthernet::localIP() +{ + uip_ipaddr_t a; + + uip_gethostaddr(a); + return ip_addr_uip(a); +} + +/** + * @brief + * @note + * @param + * @retval + */ +IpAddress UipEthernet::subnetMask() +{ + uip_ipaddr_t a; + + uip_getnetmask(a); + return ip_addr_uip(a); +} + +/** + * @brief + * @note + * @param + * @retval + */ +IpAddress UipEthernet::gatewayIP() +{ + uip_ipaddr_t a; + + uip_getdraddr(a); + return ip_addr_uip(a); +} + +/** + * @brief + * @note + * @param + * @retval + */ +IpAddress UipEthernet::dnsServerIP() +{ + return dnsServerAddress; +} + +/** + * @brief + * @note + * @param + * @retval + */ +const char* UipEthernet::get_ip_address() +{ + static char buf[16]; + return localIP().toString(buf); +} + +/** + * @brief + * @note + * @param + * @retval + */ +const char* UipEthernet::get_netmask() +{ + static char buf[16]; + return subnetMask().toString(buf); +} + +/** + * @brief + * @note + * @param + * @retval + */ +const char* UipEthernet::get_gateway() +{ + static char buf[16]; + return gatewayIP().toString(buf); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void UipEthernet::tick() +{ + if (inPacket == NOBLOCK) { + inPacket = phy.receivePacket(); +#ifdef UIPETHERNET_DEBUG + if (in_packet != NOBLOCK) { + printf("--------------\r\nreceivePacket: %d\r\n", in_packet); + } +#endif + } + + if (inPacket != NOBLOCK) { + packetState = UIPETHERNET_FREEPACKET; + uip_len = phy.blockSize(inPacket); + if (uip_len > 0) { + phy.readPacket(inPacket, 0, (uint8_t*)uip_buf, UIP_BUFSIZE); + if (ETH_HDR->type == HTONS(UIP_ETHTYPE_IP)) { + uipPacket = inPacket; //required for upper_layer_checksum of in_packet! +#ifdef UIPETHERNET_DEBUG + printf("readPacket type IP, uip_len: %d\r\n", 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 + printf("readPacket type ARP, uip_len: %d\r\n", uip_len); +#endif + uip_arp_arpin(); + if (uip_len > 0) { + network_send(); + } + } + } + + if (inPacket != NOBLOCK && (packetState & UIPETHERNET_FREEPACKET)) + { +#ifdef UIPETHERNET_DEBUG + printf("freeing packet: %d\r\n", in_packet); +#endif + phy.freePacket(); + inPacket = NOBLOCK; + } + } + + bool periodic = periodicTimer.read_ms() > UIP_PERIODIC_TIMEOUT; + + for (int i = 0; i < UIP_CONNS; i++) { + uip_conn = &uip_conns[i]; + if (periodic) { + uip_process(UIP_TIMER); + } + else { + uip_userdata_t* data = (uip_userdata_t*)uip_conn->appstate; + if (data != NULL) { + if (data->pollTimer.read_ms() >= UIP_CLIENT_TIMEOUT) { + uip_process(UIP_POLL_REQUEST); + data->pollTimer.stop(); + data->pollTimer.reset(); + } + } + else + continue; + } + + // If the above function invocation resulted in data that + // should be sent out on the Enc28J60Network, the global variable + // uip_len is set to a value > 0. + if (uip_len > 0) { + uip_arp_out(); + network_send(); + } + } + + if (periodic) { + periodicTimer.reset(); +#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 Enc28J60Network, the global variable + // uip_len is set to a value > 0. + if (uip_len > 0) { + UdpSocket::_send((uip_udp_userdata_t *) (uip_udp_conns[i].appstate)); + } + } +#endif // UIP_UDP + } +} + +/** + * @brief + * @note + * @param + * @retval + */ +bool UipEthernet::network_send() +{ + if (packetState & UIPETHERNET_SENDPACKET) + { +#ifdef UIPETHERNET_DEBUG + printf("Enc28J60Network_send uip_packet: %d, hdrlen: %d\r\n", uip_packet, uip_hdrlen); +#endif + phy.writePacket(uipPacket, 0, uip_buf, uipHeaderLen); + packetState &= ~UIPETHERNET_SENDPACKET; + goto sendandfree; + } + + uipPacket = Enc28j60Phy::allocBlock(uip_len); + if (uipPacket != NOBLOCK) + { +#ifdef UIPETHERNET_DEBUG + printf("Enc28J60Network_send uip_buf (uip_len): %d, packet: %d\r\n", uip_len, uip_packet); +#endif + phy.writePacket(uipPacket, 0, uip_buf, uip_len); + goto sendandfree; + } + + return false; +sendandfree: + phy.sendPacket(uipPacket); + Enc28j60Phy::freeBlock(uipPacket); + uipPacket = NOBLOCK; + return true; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void UipEthernet::init(const uint8_t* mac) +{ + periodicTimer.start(); + + phy.init((uint8_t*)mac); + uip_seteth_addr(mac); + + uip_init(); + uip_arp_init(); +} + +/** + * @brief + * @note + * @param + * @retval + */ +//void UIPEthernet::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 + */ +uint16_t UipEthernet::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; +} + +/** + * @brief + * @note + * @param + * @retval + */ +uint16_t UipEthernet::ipchksum() +{ + uint16_t sum; + + sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN); + return(sum == 0) ? 0xffff : htons(sum); +} + +uint16_t +#if UIP_UDP +UipEthernet::upper_layer_chksum(uint8_t proto) +#else +uip_tcpchksum() +#endif +{ + 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. */ +#if UIP_UDP + sum = upper_layer_len + proto; +#else + sum = upper_layer_len + UIP_PROTO_TCP; +#endif + /* Sum IP source and destination addresses. */ + + sum = UipEthernet::chksum(sum, (u8_t*) &BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t)); + + uint8_t upper_layer_memlen; +#if UIP_UDP + switch (proto) { + // case UIP_PROTO_ICMP: + // case UIP_PROTO_ICMP6: + // upper_layer_memlen = upper_layer_len; + // break; + case UIP_PROTO_UDP: + upper_layer_memlen = UIP_UDPH_LEN; + break; + + default: + // case UIP_PROTO_TCP: + #endif + upper_layer_memlen = (BUF->tcpoffset >> 4) << 2; + #if UIP_UDP + break; + } +#endif + sum = UipEthernet::chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_memlen); +#ifdef UIPETHERNET_DEBUG_CHKSUM + 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) + ); +#endif + if (upper_layer_memlen < upper_layer_len) { + sum = phy.chksum + ( + sum, UipEthernet::uipPacket, UIP_IPH_LEN + + UIP_LLH_LEN + + upper_layer_memlen, upper_layer_len - + upper_layer_memlen + ); +#ifdef UIPETHERNET_DEBUG_CHKSUM + 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) + ); +#endif + } + return(sum == 0) ? 0xffff : htons(sum); +} + +/** + * @brief + * @note + * @param + * @retval + */ +uint16_t uip_ipchksum() +{ + return UipEthernet::ethernet->ipchksum(); +} + +#if UIP_UDP + +/** + * @brief + * @note + * @param + * @retval + */ +uint16_t uip_tcpchksum() +{ + uint16_t sum = UipEthernet::ethernet->upper_layer_chksum(UIP_PROTO_TCP); + + return sum; +} + +/** + * @brief + * @note + * @param + * @retval + */ +uint16_t uip_udpchksum() +{ + uint16_t sum = UipEthernet::ethernet->upper_layer_chksum(UIP_PROTO_UDP); + + return sum; +} +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UipEthernet.h Tue Aug 27 15:01:10 2019 +0000 @@ -0,0 +1,117 @@ +/* + UipEthernet.h - 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/>. + */ +#ifndef UIPETHERNET_H +#define UIPETHERNET_H + +//#define UIPETHERNET_DEBUG +//#define UIPETHERNET_DEBUG_CHKSUM +//#define UIPETHERNET_DEBUG_UDP +//#define UIPETHERNET_DEBUG_CLIENT +#include "mbed.h" +#include "DhcpClient.h" +#include "IpAddress.h" +#include "utility/Enc28j60Py.h" +#include "TcpClient.h" +#include "TcpServer.h" +#include "UdpSocket.h" + +extern "C" +{ +#include "utility/uip_timer.h" +#include "utility/uip.h" +} +#define UIPETHERNET_FREEPACKET 1 +#define UIPETHERNET_SENDPACKET 2 + +#define uip_ip_addr(addr, ip) \ + do { \ + ((u16_t *) (addr))[0] = (((ip[1]) << 8) | (ip[0])); \ + ((u16_t *) (addr))[1] = (((ip[3]) << 8) | (ip[2])); \ + } while (0) +#define ip_addr_uip(a) IpAddress(a[0] & 0xFF, a[0] >> 8, a[1] & 0xFF, a[1] >> 8) //TODO this is not IPV6 capable + +#define uip_seteth_addr(eaddr) \ + do { \ + uip_ethaddr.addr[0] = eaddr[0]; \ + uip_ethaddr.addr[1] = eaddr[1]; \ + uip_ethaddr.addr[2] = eaddr[2]; \ + uip_ethaddr.addr[3] = eaddr[3]; \ + uip_ethaddr.addr[4] = eaddr[4]; \ + uip_ethaddr.addr[5] = eaddr[5]; \ + } while (0) +#define BUF ((struct uip_tcpip_hdr*) &uip_buf[UIP_LLH_LEN]) + +class UipEthernet +{ +public: + static UipEthernet* ethernet; + static IpAddress dnsServerAddress; + Enc28j60Phy phy; + + UipEthernet (const uint8_t mac[6], PinName mosi, PinName miso, PinName sck, PinName cs); + + int connect(); + void set_network(uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4); + void set_network(IpAddress ip); + void set_network(IpAddress ip, IpAddress dns); + void set_network(IpAddress ip, IpAddress dns, IpAddress gateway); + void set_network(IpAddress ip, IpAddress dns, IpAddress gateway, IpAddress subnet); + void tick(); + IpAddress localIP(); + IpAddress subnetMask(); + IpAddress gatewayIP(); + IpAddress dnsServerIP(); + const char* get_ip_address(); + const char* get_netmask(); + const char* get_gateway(); + static uint16_t chksum(uint16_t sum, const uint8_t* data, uint16_t len); + static uint16_t ipchksum(); +private: + uint8_t *const _mac; + IpAddress _ip; + IpAddress _dns; + IpAddress _gateway; + IpAddress _subnet; + static memhandle inPacket; + static memhandle uipPacket; + static uint8_t uipHeaderLen; + static uint8_t packetState; + DhcpClient dhcpClient; + Timer periodicTimer; + void init(const uint8_t* mac); + bool network_send(); + friend class TcpServer; + friend class TcpClient; + friend class UdpSocket; +#if UIP_UDP + uint16_t upper_layer_chksum(uint8_t proto); +#endif + friend uint16_t uip_ipchksum(); + friend uint16_t uip_tcpchksum(); + friend uint16_t uip_udpchksum(); + friend void uipclient_appcall(); + friend void uipudp_appcall(); + +#if UIP_CONF_IPV6 + uint16_t uip_icmp6chksum(); +#endif +}; +#endif
--- a/ethernet_comp.h Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -#ifndef ETHERNET_COMP_H -#define ETHERNET_COMP_H - -//#define Ethernet UIPEthernet -#define EthernetClient UIPClient -#define EthernetServer UIPServer -#define EthernetUDP UIPUDP -#endif
--- a/utility/Client.h Fri Jun 30 19:51:28 2017 +0000 +++ b/utility/Client.h Tue Aug 27 15:01:10 2019 +0000 @@ -20,12 +20,13 @@ */ #ifndef client_h #define client_h -#include "IPAddress.h" +#include "IpAddress.h" +#include <stddef.h> class Client { public: - virtual int connect(IPAddress ip, uint16_t port) = 0; + virtual int connect(IpAddress ip, uint16_t port) = 0; virtual int connect(const char* host, uint16_t port) = 0; virtual size_t write(uint8_t) = 0; virtual size_t write(const uint8_t* buf, size_t size) = 0; @@ -38,6 +39,6 @@ virtual uint8_t connected(void) = 0; virtual operator bool(void) = 0; protected: - uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; + uint8_t* rawIPAddress(IpAddress& addr) { return addr.rawAddress(); }; }; #endif
--- a/utility/Enc28J60Network.cpp Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,722 +0,0 @@ -/* - Enc28J60Network.cpp - UIPEthernet network driver for Microchip ENC28J60 Ethernet Interface. - - Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de> - All rights reserved. - - based on enc28j60.c file from the AVRlib library by Pascal Stang. - For AVRlib See http://www.procyonengineering.com/ - - 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/>. - */ -#include "Enc28J60Network.h" -#include "mbed.h" - -extern "C" -{ -#include "enc28j60.h" -#include "uip.h" -} - -uint16_t Enc28J60Network::nextPacketPtr; -uint8_t Enc28J60Network::bank = 0xff; -struct memblock Enc28J60Network::receivePkt; - -/** - * @brief - * @note - * @param - * @retval - */ -Enc28J60Network::Enc28J60Network(PinName mosi, PinName miso, PinName sclk, PinName cs) : - MemoryPool(), - _spi(mosi, miso, sclk), - _cs(cs) -{ } - -/** - * @brief - * @note - * @param - * @retval - */ -void Enc28J60Network::init(uint8_t* macaddr) { - MemoryPool::init(); // 1 byte in between RX_STOP_INIT and pool to allow prepending of controlbyte - - // initialize SPI interface - _spi.format(8, 0); // 8bit, mode 0 - _spi.frequency(7000000); // 7MHz - wait_ms(1000); // 1 second for stable state - - // initialize I/O - _cs = 1; // ss=0 - - // perform system reset - writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); - wait_ms(50); - - // check CLKRDY bit to see if reset is complete - // The CLKRDY does not work. See Rev. B4 Silicon Errata point. Just wait. - //while(!(readReg(ESTAT) & ESTAT_CLKRDY)); - // do bank 0 stuff - // initialize receive buffer - // 16-bit transfers, must write low byte first - // set receive buffer start address - nextPacketPtr = RXSTART_INIT; - - // Rx start - writeRegPair(ERXSTL, RXSTART_INIT); - - // set receive pointer address - writeRegPair(ERXRDPTL, RXSTART_INIT); - - // RX end - writeRegPair(ERXNDL, RXSTOP_INIT); - - // TX start - //writeRegPair(ETXSTL, TXSTART_INIT); - // TX end - //writeRegPair(ETXNDL, TXSTOP_INIT); - // do bank 1 stuff, packet filter: - // For broadcast packets we allow only ARP packtets - // All other packets should be unicast only for our mac (MAADR) - // - // The pattern to match on is therefore - // Type ETH.DST - // ARP BROADCAST - // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9 - // in binary these poitions are:11 0000 0011 1111 - // This is hex 303F->EPMM0=0x3f,EPMM1=0x30 - //TODO define specific pattern to receive dhcp-broadcast packages instead of setting ERFCON_BCEN! - writeReg(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_PMEN | ERXFCON_BCEN); - writeRegPair(EPMM0, 0x303f); - writeRegPair(EPMCSL, 0xf7f9); - - // - // - // do bank 2 stuff - // enable MAC receive - // and bring MAC out of reset (writes 0x00 to MACON2) - writeRegPair(MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS); - - // enable automatic padding to 60bytes and CRC operations - writeOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN); - - // set inter-frame gap (non-back-to-back) - writeRegPair(MAIPGL, 0x0C12); - - // set inter-frame gap (back-to-back) - writeReg(MABBIPG, 0x12); - - // Set the maximum packet size which the controller will accept - // Do not send packets longer than MAX_FRAMELEN: - writeRegPair(MAMXFLL, MAX_FRAMELEN); - - // do bank 3 stuff - // write MAC address - // NOTE: MAC address in ENC28J60 is byte-backward - writeReg(MAADR5, macaddr[0]); - writeReg(MAADR4, macaddr[1]); - writeReg(MAADR3, macaddr[2]); - writeReg(MAADR2, macaddr[3]); - writeReg(MAADR1, macaddr[4]); - writeReg(MAADR0, macaddr[5]); - - // no loopback of transmitted frames - phyWrite(PHCON2, PHCON2_HDLDIS); - - // switch to bank 0 - setBank(ECON1); - - // enable interrutps - writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE | EIE_PKTIE); - - // enable packet reception - writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); - - clkout(2); // change clkout from 6.25MHz to 12.5MHz - wait_us(60); // 60us - - //Configure leds - phyWrite(PHLCON, 0x476); -} - -/** - * @brief - * @note - * @param - * @retval - */ -memhandle Enc28J60Network::receivePacket(void) { - uint8_t rxstat; - uint16_t len; - // check if a packet has been received and buffered - - //if( !(readReg(EIR) & EIR_PKTIF) ){ - // The above does not work. See Rev. B4 Silicon Errata point 6. - if (readReg(EPKTCNT) != 0) { - uint16_t readPtr = nextPacketPtr + - 6 > RXSTOP_INIT ? nextPacketPtr + - 6 - - RXSTOP_INIT + - RXSTART_INIT : nextPacketPtr + - 6; - // Set the read pointer to the start of the received packet - - writeRegPair(ERDPTL, nextPacketPtr); - - // read the next packet pointer - nextPacketPtr = readOp(ENC28J60_READ_BUF_MEM, 0); - nextPacketPtr |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; - - // read the packet length (see datasheet page 43) - len = readOp(ENC28J60_READ_BUF_MEM, 0); - len |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; - len -= 4; //remove the CRC count - - // read the receive status (see datasheet page 43) - rxstat = readOp(ENC28J60_READ_BUF_MEM, 0); - - //rxstat |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; -#ifdef ENC28J60DEBUG - printf - ( - "receivePacket [%d-%d], next: %d, stat: %d, count: %d -> ", - readPtr, - (readPtr + len) % (RXSTOP_INIT + 1), - nextPacketPtr, - rxstat, - readReg(EPKTCNT) - ); - (rxstat & 0x80) != 0 ? printf("OK") : printf("failed"); - printf("\r\n"); -#endif - // decrement the packet counter indicate we are done with this packet - - writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC); - - // check CRC and symbol errors (see datasheet page 44, table 7-3): - // The ERXFCON.CRCEN is set by default. Normally we should not - // need to check this. - if ((rxstat & 0x80) != 0) { - receivePkt.begin = readPtr; - receivePkt.size = len; - return UIP_RECEIVEBUFFERHANDLE; - } - - // Move the RX read pointer to the start of the next received packet - // This frees the memory we just read out - setERXRDPT(); - } - - return(NOBLOCK); -} - -/** - * @brief - * @note - * @param - * @retval - */ -void Enc28J60Network::setERXRDPT(void) { - writeRegPair(ERXRDPTL, nextPacketPtr == RXSTART_INIT ? RXSTOP_INIT : nextPacketPtr - 1); -} - -/** - * @brief - * @note - * @param - * @retval - */ -memaddress Enc28J60Network::blockSize(memhandle handle) { - return handle == NOBLOCK ? 0 : handle == UIP_RECEIVEBUFFERHANDLE ? receivePkt.size : blocks[handle].size; -} - -/** - * @brief - * @note - * @param - * @retval - */ -void Enc28J60Network::sendPacket(memhandle handle) { - memblock* packet = &blocks[handle]; - uint16_t start = packet->begin - 1; - uint16_t end = start + packet->size; - - // backup data at control-byte position - uint8_t data = readByte(start); - // write control-byte (if not 0 anyway) - - if (data) - writeByte(start, 0); - -#ifdef ENC28J60DEBUG - printf("sendPacket(%d) [%d-%d]: ", handle, start, end); - for (uint16_t i = start; i <= end; i++) { - printf("%d ", readByte(i)); - } - - printf("\r\n"); -#endif - // TX start - - writeRegPair(ETXSTL, start); - - // Set the TXND pointer to correspond to the packet size given - writeRegPair(ETXNDL, end); - - // send the contents of the transmit buffer onto the network - writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS); - - // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12. - if ((readReg(EIR) & EIR_TXERIF)) { - writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS); - } - - //restore data on control-byte position - if (data) - writeByte(start, data); -} - -/** - * @brief - * @note - * @param - * @retval - */ -uint16_t Enc28J60Network::setReadPtr(memhandle handle, memaddress position, uint16_t len) { - memblock* packet = handle == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[handle]; - memaddress start = handle == UIP_RECEIVEBUFFERHANDLE - && packet->begin + - position > RXSTOP_INIT ? packet->begin + - position - - RXSTOP_INIT + - RXSTART_INIT : packet->begin + - position; - - writeRegPair(ERDPTL, start); - - if (len > packet->size - position) - len = packet->size - position; - return len; -} - -/** - * @brief - * @note - * @param - * @retval - */ -uint16_t Enc28J60Network::readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) { - len = setReadPtr(handle, position, len); - readBuffer(len, buffer); - return len; -} - -/** - * @brief - * @note - * @param - * @retval - */ -uint16_t Enc28J60Network::writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) { - memblock* packet = &blocks[handle]; - uint16_t start = packet->begin + position; - - writeRegPair(EWRPTL, start); - - if (len > packet->size - position) - len = packet->size - position; - writeBuffer(len, buffer); - return len; -} - -/** - * @brief - * @note - * @param - * @retval - */ -uint8_t Enc28J60Network::readByte(uint16_t addr) { - uint8_t result; - - writeRegPair(ERDPTL, addr); - - _cs = 0; - - // issue read command - _spi.write(ENC28J60_READ_BUF_MEM); - - // read data - result = _spi.write(0x00); - _cs = 1; - return(result); -} - -/** - * @brief - * @note - * @param - * @retval - */ -void Enc28J60Network::writeByte(uint16_t addr, uint8_t data) { - writeRegPair(EWRPTL, addr); - - _cs = 0; - - // issue write command - _spi.write(ENC28J60_WRITE_BUF_MEM); - - // write data - _spi.write(data); - _cs = 1; -} - -/** - * @brief - * @note - * @param - * @retval - */ -void Enc28J60Network::copyPacket -( - memhandle dest_pkt, - memaddress dest_pos, - memhandle src_pkt, - memaddress src_pos, - uint16_t len -) { - memblock* dest = &blocks[dest_pkt]; - memblock* src = src_pkt == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[src_pkt]; - memaddress start = src_pkt == UIP_RECEIVEBUFFERHANDLE - && src->begin + - src_pos > RXSTOP_INIT ? src->begin + - src_pos - - RXSTOP_INIT + - RXSTART_INIT : src->begin + - src_pos; - enc28J60_mempool_block_move_callback(dest->begin + dest_pos, start, len); - - // Move the RX read pointer to the start of the next received packet - // This frees the memory we just read out - setERXRDPT(); -} - -/** - * @brief - * @note - * @param - * @retval - */ -void Enc28J60Network::freePacket(void) { - setERXRDPT(); -} - -/** - * @brief - * @note - * @param - * @retval - */ -uint8_t Enc28J60Network::readOp(uint8_t op, uint8_t address) { - uint8_t result; - - _cs = 0; - - // issue read command - _spi.write(op | (address & ADDR_MASK)); - - // read data - result = _spi.write(0x00); - - // do dummy read if needed (for mac and mii, see datasheet page 29) - if (address & 0x80) - result = _spi.write(0x00); - - // release CS - _cs = 1; - return(result); -} - -/** - * @brief - * @note - * @param - * @retval - */ -void Enc28J60Network::writeOp(uint8_t op, uint8_t address, uint8_t data) { - _cs = 0; - - // issue write command - _spi.write(op | (address & ADDR_MASK)); - - // write data - _spi.write(data); - _cs = 1; -} - -/** - * @brief - * @note - * @param - * @retval - */ -void Enc28J60Network::readBuffer(uint16_t len, uint8_t* data) { - _cs = 0; - - // issue read command - _spi.write(ENC28J60_READ_BUF_MEM); - while (len) { - len--; - - // read data - *data = _spi.write(0x00); - data++; - } - - *data = '\0'; - _cs = 1; -} - -/** - * @brief - * @note - * @param - * @retval - */ -void Enc28J60Network::writeBuffer(uint16_t len, uint8_t* data) { - _cs = 0; - - // issue write command - _spi.write(ENC28J60_WRITE_BUF_MEM); - while (len) { - len--; - - // write data - _spi.write(*data); - data++; - } - - _cs = 1; -} - -/** - * @brief - * @note - * @param - * @retval - */ -void Enc28J60Network::setBank(uint8_t address) { - - // set the bank (if needed) - - if ((address & BANK_MASK) != bank) { - - // set the bank - writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1 | ECON1_BSEL0)); - writeOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK) >> 5); - bank = (address & BANK_MASK); - } -} - -/** - * @brief - * @note - * @param - * @retval - */ -uint8_t Enc28J60Network::readReg(uint8_t address) { - - // set the bank - - setBank(address); - - // do the read - return readOp(ENC28J60_READ_CTRL_REG, address); -} - -/** - * @brief - * @note - * @param - * @retval - */ -void Enc28J60Network::writeReg(uint8_t address, uint8_t data) { - - // set the bank - - setBank(address); - - // do the write - writeOp(ENC28J60_WRITE_CTRL_REG, address, data); -} - -/** - * @brief - * @note - * @param - * @retval - */ -void Enc28J60Network::writeRegPair(uint8_t address, uint16_t data) { - - // set the bank - - setBank(address); - - // do the write - writeOp(ENC28J60_WRITE_CTRL_REG, address, (data & 0xFF)); - writeOp(ENC28J60_WRITE_CTRL_REG, address + 1, (data) >> 8); -} - -/** - * @brief - * @note - * @param - * @retval - */ -void Enc28J60Network::phyWrite(uint8_t address, uint16_t data) { - - // set the PHY register address - - writeReg(MIREGADR, address); - - // write the PHY data - writeRegPair(MIWRL, data); - - // wait until the PHY write completes - while (readReg(MISTAT) & MISTAT_BUSY) { - wait_us(15); - } -} - -/** - * @brief - * @note - * @param - * @retval - */ -uint16_t Enc28J60Network::phyRead(uint8_t address) { - writeReg(MIREGADR, address); - writeReg(MICMD, MICMD_MIIRD); - - // wait until the PHY read completes - while (readReg(MISTAT) & MISTAT_BUSY) { - wait_us(15); - } //and MIRDH - - writeReg(MICMD, 0); - return(readReg(MIRDL) | readReg(MIRDH) << 8); -} - -/** - * @brief - * @note - * @param - * @retval - */ -void Enc28J60Network::clkout(uint8_t clk) { - - //setup clkout: 2 is 12.5MHz: - - writeReg(ECOCON, clk & 0x7); -} - -// read the revision of the chip: -uint8_t Enc28J60Network::getrev(void) { - return(readReg(EREVID)); -} - -/** - * @brief - * @note - * @param - * @retval - */ -uint16_t Enc28J60Network::chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t len) { - uint8_t spdr; - uint16_t t; - uint16_t i; - - len = setReadPtr(handle, pos, len) - 1; - _cs = 0; - - // issue read command - spdr = _spi.write(ENC28J60_READ_BUF_MEM); - for (i = 0; i < len; i += 2) { - - // read data - spdr = _spi.write(0x00); - t = spdr << 8; - spdr = _spi.write(0x00); - t += spdr; - sum += t; - if (sum < t) { - sum++; /* carry */ - } - } - - if (i == len) { - spdr = _spi.write(0x00); - t = (spdr << 8) + 0; - sum += t; - if (sum < t) { - sum++; /* carry */ - } - } - - _cs = 1; - - /* Return sum in host byte order. */ - return sum; -} - -/** - * @brief - * @note - * @param - * @retval - */ -void Enc28J60Network::powerOff(void) { - writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN); - wait_ms(50); - writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_VRPS); - wait_ms(50); - writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV); -} - -/** - * @brief - * @note - * @param - * @retval - */ -void Enc28J60Network::powerOn(void) { - writeOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV); - wait_ms(50); - writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); - wait_ms(50); -} - -/** - * @brief - * @note - * @param - * @retval - */ -bool Enc28J60Network::linkStatus(void) { - return(phyRead(PHSTAT2) & 0x0400) > 0; -}
--- a/utility/Enc28J60Network.h Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* - Enc28J60Network.h - UIPEthernet network driver for Microchip ENC28J60 Ethernet Interface. - - Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de> - All rights reserved. - - based on enc28j60.c file from the AVRlib library by Pascal Stang. - For AVRlib See http://www.procyonengineering.com/ - - 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/>. - */ -#ifndef ENC28J60NETWORK_H -#define ENC28J60NETWORK_H - -#include "mbed.h" -#include "mempool.h" - -#define UIP_RECEIVEBUFFERHANDLE 0xff - -//#define ENC28J60DEBUG - -/* - * Empfangen von ip-header, arp etc... - * wenn tcp/udp -> tcp/udp-callback -> assign new packet to connection - */ -class Enc28J60Network : - public MemoryPool -{ -private: - SPI _spi; - DigitalOut _cs; - static uint16_t nextPacketPtr; - static uint8_t bank; - - static struct memblock receivePkt; - - uint8_t readOp(uint8_t op, uint8_t address); - void writeOp(uint8_t op, uint8_t address, uint8_t data); - uint16_t setReadPtr(memhandle handle, memaddress position, uint16_t len); - void setERXRDPT(void); - void readBuffer(uint16_t len, uint8_t* data); - void writeBuffer(uint16_t len, uint8_t* data); - uint8_t readByte(uint16_t addr); - void writeByte(uint16_t addr, uint8_t data); - void setBank(uint8_t address); - uint8_t readReg(uint8_t address); - void writeReg(uint8_t address, uint8_t data); - void writeRegPair(uint8_t address, uint16_t data); - void phyWrite(uint8_t address, uint16_t data); - uint16_t phyRead(uint8_t address); - void clkout(uint8_t clk); - - friend void enc28J60_mempool_block_move_callback(memaddress, memaddress, memaddress); -public: - Enc28J60Network(PinName mosi, PinName miso, PinName sclk, PinName cs); - uint8_t getrev(void); - void powerOn(void); - void powerOff(void); - bool linkStatus(void); - - void init(uint8_t* macaddr); - memhandle receivePacket(void); - void freePacket(void); - memaddress blockSize(memhandle handle); - void sendPacket(memhandle handle); - uint16_t readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len); - uint16_t writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len); - void copyPacket(memhandle dest, memaddress dest_pos, memhandle src, memaddress src_pos, uint16_t len); - uint16_t chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t len); -}; -#endif /* Enc28J60NetworkClass_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utility/Enc28j60Py.cpp Tue Aug 27 15:01:10 2019 +0000 @@ -0,0 +1,729 @@ +/* + Enc28J60Network.cpp + UIPEthernet network driver for Microchip ENC28J60 Ethernet Interface. + + Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de> + All rights reserved. + + based on enc28j60.c file from the AVRlib library by Pascal Stang. + For AVRlib See http://www.procyonengineering.com/ + + 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/>. + */ +#include "Enc28j60Py.h" +#include "mbed.h" + +extern "C" +{ +#include "enc28j60.h" +#include "uip.h" +} + +// Static member initialization +uint16_t Enc28j60Phy::nextPacketPtr; +uint8_t Enc28j60Phy::bank = 0xff; +struct memblock Enc28j60Phy::receivePkt; + +/** + * @brief + * @note + * @param + * @retval + */ +Enc28j60Phy::Enc28j60Phy(PinName mosi, PinName miso, PinName sclk, PinName cs) : + MemPool(), + _spi(mosi, miso, sclk), + _cs(cs) +{ } + +/** + * @brief + * @note + * @param + * @retval + */ +void Enc28j60Phy::init(uint8_t* macaddr) +{ + MemPool::init(); // 1 byte in between RX_STOP_INIT and pool to allow prepending of controlbyte + // initialize SPI interface + _spi.format(8, 0); // 8-bit, mode 0 + _spi.frequency(10000000); // 10 Mbit/s + wait_ms(1000); // 1 second for stable state + // Release SPI + _cs = 1; + + // perform system reset + writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); + + // check CLKRDY bit to see if reset is complete + //while(!(readReg(ESTAT) & ESTAT_CLKRDY)); + // The CLKRDY does not work. See Rev. B4 Silicon Errata point. Just wait. + wait_ms(50); + + // do bank 0 stuff + // initialize receive buffer + // 16-bit transfers, must write low byte first + // set receive buffer start address + nextPacketPtr = RXSTART_INIT; + + // Rx start + writeRegPair(ERXSTL, RXSTART_INIT); + + // set receive pointer address + writeRegPair(ERXRDPTL, RXSTART_INIT); + + // RX end + writeRegPair(ERXNDL, RXSTOP_INIT); + + // TX start + //writeRegPair(ETXSTL, TXSTART_INIT); + // TX end + //writeRegPair(ETXNDL, TXSTOP_INIT); + // do bank 1 stuff, packet filter: + // For broadcast packets we allow only ARP packtets + // All other packets should be unicast only for our mac (MAADR) + // + // The pattern to match on is therefore + // Type ETH.DST + // ARP BROADCAST + // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9 + // in binary these poitions are:11 0000 0011 1111 + // This is hex 303F->EPMM0=0x3f,EPMM1=0x30 + //TODO define specific pattern to receive dhcp-broadcast packages instead of setting ERFCON_BCEN! + writeReg(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_PMEN | ERXFCON_BCEN); + writeRegPair(EPMM0, 0x303f); + writeRegPair(EPMCSL, 0xf7f9); + + // + // + // do bank 2 stuff + // enable MAC receive + // and bring MAC out of reset (writes 0x00 to MACON2) + writeRegPair(MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS); + + // enable automatic padding to 60bytes and CRC operations + writeOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN); + + // set inter-frame gap (non-back-to-back) + writeRegPair(MAIPGL, 0x0C12); + + // set inter-frame gap (back-to-back) + writeReg(MABBIPG, 0x12); + + // Set the maximum packet size which the controller will accept + // Do not send packets longer than MAX_FRAMELEN: + writeRegPair(MAMXFLL, MAX_FRAMELEN); + + // do bank 3 stuff + // write MAC address + // NOTE: MAC address in ENC28J60 is byte-backward + writeReg(MAADR5, macaddr[0]); + writeReg(MAADR4, macaddr[1]); + writeReg(MAADR3, macaddr[2]); + writeReg(MAADR2, macaddr[3]); + writeReg(MAADR1, macaddr[4]); + writeReg(MAADR0, macaddr[5]); + + // no loopback of transmitted frames + phyWrite(PHCON2, PHCON2_HDLDIS); + + // switch to bank 0 + setBank(ECON1); + + // enable interrutps + writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE | EIE_PKTIE); + + // enable packet reception + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); + + //Configure leds + phyWrite(PHLCON, 0x476); +} + +/** + * @brief + * @note + * @param + * @retval + */ +memhandle Enc28j60Phy::receivePacket() +{ + uint8_t rxstat; + uint16_t len; + // check if a packet has been received and buffered + //if( !(readReg(EIR) & EIR_PKTIF) ){ + // The above does not work. See Rev. B4 Silicon Errata point 6. + if (readReg(EPKTCNT) != 0) { + uint16_t readPtr = nextPacketPtr + + 6 > RXSTOP_INIT ? nextPacketPtr + + 6 - + RXSTOP_INIT + + RXSTART_INIT : nextPacketPtr + + 6; + // Set the read pointer to the start of the received packet + writeRegPair(ERDPTL, nextPacketPtr); + + // read the next packet pointer + nextPacketPtr = readOp(ENC28J60_READ_BUF_MEM, 0); + nextPacketPtr |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; + + // read the packet length (see datasheet page 43) + len = readOp(ENC28J60_READ_BUF_MEM, 0); + len |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; + len -= 4; //remove the CRC count + // read the receive status (see datasheet page 43) + rxstat = readOp(ENC28J60_READ_BUF_MEM, 0); + + //rxstat |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; +#ifdef ENC28J60DEBUG + printf + ( + "receivePacket [%d-%d], next: %d, stat: %d, count: %d -> ", + readPtr, + (readPtr + len) % (RXSTOP_INIT + 1), + nextPacketPtr, + rxstat, + readReg(EPKTCNT) + ); + (rxstat & 0x80) != 0 ? printf("OK") : printf("failed"); + printf("\r\n"); +#endif + // decrement the packet counter indicate we are done with this packet + + writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC); + + // check CRC and symbol errors (see datasheet page 44, table 7-3): + // The ERXFCON.CRCEN is set by default. Normally we should not + // need to check this. + if ((rxstat & 0x80) != 0) { + receivePkt.begin = readPtr; + receivePkt.size = len; + return UIP_RECEIVEBUFFERHANDLE; + } + + // Move the RX read pointer to the start of the next received packet + // This frees the memory we just read out + setERXRDPT(); + } + + return(NOBLOCK); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void Enc28j60Phy::setERXRDPT() +{ + writeRegPair(ERXRDPTL, nextPacketPtr == RXSTART_INIT ? RXSTOP_INIT : nextPacketPtr - 1); +} + +/** + * @brief + * @note + * @param + * @retval + */ +memaddress Enc28j60Phy::blockSize(memhandle handle) +{ + return handle == NOBLOCK ? 0 : handle == UIP_RECEIVEBUFFERHANDLE ? receivePkt.size : blocks[handle].size; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void Enc28j60Phy::sendPacket(memhandle handle) +{ + memblock* packet = &blocks[handle]; + uint16_t start = packet->begin - 1; + uint16_t end = start + packet->size; + + // backup data at control-byte position + uint8_t data = readByte(start); + // write control-byte (if not 0 anyway) + if (data) + writeByte(start, 0); + +#ifdef ENC28J60DEBUG + printf("sendPacket(%d) [%d-%d]: ", handle, start, end); + for (uint16_t i = start; i <= end; i++) { + printf("%d ", readByte(i)); + } + + printf("\r\n"); +#endif + // TX start + + writeRegPair(ETXSTL, start); + + // Set the TXND pointer to correspond to the packet size given + writeRegPair(ETXNDL, end); + + // send the contents of the transmit buffer onto the network + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS); + + // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12. + if ((readReg(EIR) & EIR_TXERIF)) { + writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS); + } + + //restore data on control-byte position + if (data) + writeByte(start, data); +} + +/** + * @brief + * @note + * @param + * @retval + */ +uint16_t Enc28j60Phy::setReadPtr(memhandle handle, memaddress position, uint16_t len) +{ + memblock* packet = handle == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[handle]; + memaddress start = handle == UIP_RECEIVEBUFFERHANDLE && + packet->begin + + position > RXSTOP_INIT ? packet->begin + + position - + RXSTOP_INIT + + RXSTART_INIT : packet->begin + + position; + + writeRegPair(ERDPTL, start); + + if (len > packet->size - position) + len = packet->size - position; + return len; +} + +/** + * @brief + * @note + * @param + * @retval + */ +uint16_t Enc28j60Phy::readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) +{ + len = setReadPtr(handle, position, len); + readBuffer(len, buffer); + return len; +} + +/** + * @brief + * @note + * @param + * @retval + */ +uint16_t Enc28j60Phy::writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) +{ + memblock* packet = &blocks[handle]; + uint16_t start = packet->begin + position; + + writeRegPair(EWRPTL, start); + + if (len > packet->size - position) + len = packet->size - position; + writeBuffer(len, buffer); + return len; +} + +/** + * @brief + * @note + * @param + * @retval + */ +uint8_t Enc28j60Phy::readByte(uint16_t addr) +{ + uint8_t result; + + writeRegPair(ERDPTL, addr); + + _cs = 0; + + // issue read command + _spi.write(ENC28J60_READ_BUF_MEM); + + // read data + result = _spi.write(0x00); + _cs = 1; + return(result); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void Enc28j60Phy::writeByte(uint16_t addr, uint8_t data) +{ + writeRegPair(EWRPTL, addr); + + _cs = 0; + + // issue write command + _spi.write(ENC28J60_WRITE_BUF_MEM); + + // write data + _spi.write(data); + _cs = 1; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void Enc28j60Phy::copyPacket +( + memhandle dest_pkt, + memaddress dest_pos, + memhandle src_pkt, + memaddress src_pos, + uint16_t len +) +{ + memblock* dest = &blocks[dest_pkt]; + memblock* src = src_pkt == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[src_pkt]; + memaddress start = src_pkt == UIP_RECEIVEBUFFERHANDLE && + src->begin + + src_pos > RXSTOP_INIT ? src->begin + + src_pos - + RXSTOP_INIT + + RXSTART_INIT : src->begin + + src_pos; + enc28j60_mempool_block_move_callback(dest->begin + dest_pos, start, len); + + // Move the RX read pointer to the start of the next received packet + // This frees the memory we just read out + setERXRDPT(); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void Enc28j60Phy::freePacket() +{ + setERXRDPT(); +} + +/** + * @brief + * @note + * @param + * @retval + */ +uint8_t Enc28j60Phy::readOp(uint8_t op, uint8_t address) +{ + uint8_t result; + + _cs = 0; + + // issue read command + _spi.write(op | (address & ADDR_MASK)); + + // read data + result = _spi.write(0x00); + + // do dummy read if needed (for mac and mii, see datasheet page 29) + if (address & 0x80) + result = _spi.write(0x00); + + // release CS + _cs = 1; + return(result); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void Enc28j60Phy::writeOp(uint8_t op, uint8_t address, uint8_t data) +{ + _cs = 0; + + // issue write command + _spi.write(op | (address & ADDR_MASK)); + + // write data + _spi.write(data); + _cs = 1; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void Enc28j60Phy::readBuffer(uint16_t len, uint8_t* data) +{ + _cs = 0; + + // issue read command + _spi.write(ENC28J60_READ_BUF_MEM); + while (len) { + len--; + + // read data + *data = _spi.write(0x00); + data++; + } + + *data = '\0'; + _cs = 1; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void Enc28j60Phy::writeBuffer(uint16_t len, uint8_t* data) +{ + _cs = 0; + + // issue write command + _spi.write(ENC28J60_WRITE_BUF_MEM); + while (len) { + len--; + + // write data + _spi.write(*data); + data++; + } + + _cs = 1; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void Enc28j60Phy::setBank(uint8_t address) +{ + // set the bank (if needed) + if ((address & BANK_MASK) != bank) { + // set the bank + writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1 | ECON1_BSEL0)); + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK) >> 5); + bank = (address & BANK_MASK); + } +} + +/** + * @brief + * @note + * @param + * @retval + */ +uint8_t Enc28j60Phy::readReg(uint8_t address) +{ + // set the bank + setBank(address); + + // do the read + return readOp(ENC28J60_READ_CTRL_REG, address); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void Enc28j60Phy::writeReg(uint8_t address, uint8_t data) +{ + // set the bank + setBank(address); + + // do the write + writeOp(ENC28J60_WRITE_CTRL_REG, address, data); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void Enc28j60Phy::writeRegPair(uint8_t address, uint16_t data) +{ + // set the bank + setBank(address); + + // do the write + writeOp(ENC28J60_WRITE_CTRL_REG, address, (data & 0xFF)); + writeOp(ENC28J60_WRITE_CTRL_REG, address + 1, (data) >> 8); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void Enc28j60Phy::phyWrite(uint8_t address, uint16_t data) +{ + // set the PHY register address + writeReg(MIREGADR, address); + + // write the PHY data + writeRegPair(MIWRL, data); + + // wait until the PHY write completes + while (readReg(MISTAT) & MISTAT_BUSY) { + wait_us(15); + } +} + +/** + * @brief + * @note + * @param + * @retval + */ +uint16_t Enc28j60Phy::phyRead(uint8_t address) +{ + writeReg(MIREGADR, address); + writeReg(MICMD, MICMD_MIIRD); + + // wait until the PHY read completes + while (readReg(MISTAT) & MISTAT_BUSY) { + wait_us(15); + } //and MIRDH + + writeReg(MICMD, 0); + return(readReg(MIRDL) | readReg(MIRDH) << 8); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void Enc28j60Phy::clkout(uint8_t clk) +{ + //setup clkout: 2 is 12.5MHz: + writeReg(ECOCON, clk & 0x7); +} + +// read the revision of the chip: +uint8_t Enc28j60Phy::getrev() +{ + return(readReg(EREVID)); +} + +/** + * @brief + * @note + * @param + * @retval + */ +uint16_t Enc28j60Phy::chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t len) +{ + uint8_t spdr; + uint16_t t; + uint16_t i; + + len = setReadPtr(handle, pos, len) - 1; + _cs = 0; + + // issue read command + spdr = _spi.write(ENC28J60_READ_BUF_MEM); + for (i = 0; i < len; i += 2) { + // read data + spdr = _spi.write(0x00); + t = spdr << 8; + spdr = _spi.write(0x00); + t += spdr; + sum += t; + if (sum < t) { + sum++; /* carry */ + } + } + + if (i == len) { + spdr = _spi.write(0x00); + t = (spdr << 8) + 0; + sum += t; + if (sum < t) { + sum++; /* carry */ + } + } + + _cs = 1; + + /* Return sum in host byte order. */ + return sum; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void Enc28j60Phy::powerOff() +{ + writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN); + wait_ms(50); + writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_VRPS); + wait_ms(50); + writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void Enc28j60Phy::powerOn() +{ + writeOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV); + wait_ms(50); + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); + wait_ms(50); +} + +/** + * @brief + * @note + * @param + * @retval + */ +bool Enc28j60Phy::linkStatus() +{ + return(phyRead(PHSTAT2) & 0x0400) > 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utility/Enc28j60Py.h Tue Aug 27 15:01:10 2019 +0000 @@ -0,0 +1,82 @@ +/* + Enc28J60Network.h + UIPEthernet network driver for Microchip ENC28J60 Ethernet Interface. + + Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de> + All rights reserved. + + based on enc28j60.c file from the AVRlib library by Pascal Stang. + For AVRlib See http://www.procyonengineering.com/ + + 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/>. + */ +#ifndef ENC28J60PHY_H +#define ENC28J60PHY_H + +#include "mbed.h" +#include "MemPool.h" + +#define UIP_RECEIVEBUFFERHANDLE 0xff + +//#define ENC28J60DEBUG + +class Enc28j60Phy : public MemPool +{ +private: + SPI _spi; + DigitalOut _cs; + static uint16_t nextPacketPtr; + static uint8_t bank; + + static struct memblock receivePkt; + + uint16_t setReadPtr(memhandle handle, memaddress position, uint16_t len); + void setERXRDPT(); + void readBuffer(uint16_t len, uint8_t* data); + void writeBuffer(uint16_t len, uint8_t* data); + void setBank(uint8_t address); + uint8_t readReg(uint8_t address); + void writeReg(uint8_t address, uint8_t data); + void phyWrite(uint8_t address, uint16_t data); + uint16_t phyRead(uint8_t address); + void clkout(uint8_t clk); + + friend void enc28j60_mempool_block_move_callback(memaddress, memaddress, memaddress); +public: + Enc28j60Phy(PinName mosi, PinName miso, PinName sclk, PinName cs); + uint8_t getrev(); + void powerOn(); + void powerOff(); + bool linkStatus(); + + void init(uint8_t* macaddr); + memhandle receivePacket(); + void freePacket(); + memaddress blockSize(memhandle handle); + void sendPacket(memhandle handle); + uint16_t readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len); + uint16_t writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len); + void copyPacket(memhandle dest, memaddress dest_pos, memhandle src, memaddress src_pos, uint16_t len); + uint16_t chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t len); + + uint8_t readOp(uint8_t op, uint8_t address); + uint8_t readByte(uint16_t addr); + void writeOp(uint8_t op, uint8_t address, uint8_t data); + void writeRegPair(uint8_t address, uint16_t data); + void writeByte(uint16_t addr, uint8_t data); +}; + +#endif
--- a/utility/IPAddress.cpp Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -/* - IPAddress.cpp - Base class that provides IPAddress - Copyright (c) 2011 Adrian McEwen. All right reserved. - - Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.com> - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#include "mbed.h" -#include "IPAddress.h" - -/** - * @brief - * @note - * @param - * @retval - */ -IPAddress::IPAddress(void) { - memset(_address, 0, sizeof(_address)); -} - -/** - * @brief - * @note - * @param - * @retval - */ -IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) { - _address[0] = first_octet; - _address[1] = second_octet; - _address[2] = third_octet; - _address[3] = fourth_octet; -} - -/** - * @brief - * @note - * @param - * @retval - */ -IPAddress::IPAddress(uint32_t address) { - memcpy(_address, &address, sizeof(_address)); -} - -/** - * @brief - * @note - * @param - * @retval - */ -IPAddress::IPAddress(const uint8_t* address) { - memcpy(_address, address, sizeof(_address)); -} - -/** - * @brief - * @note - * @param - * @retval - */ -IPAddress &IPAddress::operator=(const uint8_t* address) { - memcpy(_address, address, sizeof(_address)); - return *this; -} - -/** - * @brief - * @note - * @param - * @retval - */ -IPAddress &IPAddress::operator=(uint32_t address) { - memcpy(_address, (const uint8_t*) &address, sizeof(_address)); - return *this; -} - -/** - * @brief - * @note - * @param - * @retval - */ -bool IPAddress::operator==(const uint8_t* addr) const -{ - return memcmp(addr, _address, sizeof(_address)) == 0; -}
--- a/utility/IPAddress.h Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/* - IPAddress.h - Base class that provides IPAddress - Copyright (c) 2011 Adrian McEwen. All right reserved. - - Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.com> - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#ifndef IPADDRESS_H -#define IPADDRESS_H - -#include <stdint.h> - -// A class to make it easier to handle and pass around IP addresses - -class IPAddress -{ -private: - uint8_t _address[4]; // IPv4 address - - // Access the raw byte array containing the address. Because this returns a pointer - // to the internal structure rather than a copy of the address this function should only - // be used when you know that the usage of the returned uint8_t* will be transient and not - - // stored. - uint8_t* raw_address(void) { return _address; }; -public: - // Constructors - IPAddress(void); - IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); - IPAddress(uint32_t address); - IPAddress(const uint8_t* address); - - // Overloaded cast operator to allow IPAddress objects to be used where a pointer - // to a four-byte uint8_t array is expected - operator uint32_t(void) const { return *((uint32_t*)_address); }; - bool operator==(const IPAddress& addr) const { return(*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); }; - bool operator==(const uint8_t* addr) const; - - // Overloaded index operator to allow getting and setting individual octets of the address - uint8_t operator[](int index) const { return _address[index]; }; - uint8_t &operator[](int index) { return _address[index]; }; - - // Overloaded copy operators to allow initialisation of IPAddress objects from other types - IPAddress &operator =(const uint8_t* address); - IPAddress &operator =(uint32_t address); - - // Returns IP Address as string of char - char* toString(void) { - static char buff[16]; - uint8_t i = 0; - uint8_t j = 0; - - for (i = 0; i < 3; i++) { - j += sprintf(&buff[j], "%d", _address[i]); - buff[j++] = '.'; - } - - j += sprintf(&buff[j], "%d", _address[i]); - buff[j] = '\0'; - return buff; - } - - // virtual size_t printTo(Print& p) const; - friend class EthernetClass; - friend class UDP; - friend class Client; - friend class Server; - friend class DhcpClass; - friend class DNSClient; -}; - -const IPAddress INADDR_NONE(0, 0, 0, 0); -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utility/MemPool.cpp Tue Aug 27 15:01:10 2019 +0000 @@ -0,0 +1,192 @@ +/* + mempool.cpp - sleek implementation of a memory pool + Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de> + All rights reserved. + + 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/>. + */ +#include "MemPool.h" +#include <string.h> + +#define POOLOFFSET 1 + +struct memblock MemPool:: blocks[MEMPOOL_NUM_MEMBLOCKS + 1]; + +/** + * @brief + * @note + * @param + * @retval + */ +void MemPool::init() { + memset(&blocks[0], 0, sizeof(blocks)); + blocks[POOLSTART].begin = MEMPOOL_STARTADDRESS; + blocks[POOLSTART].size = 0; + blocks[POOLSTART].nextblock = NOBLOCK; +} + +/** + * @brief + * @note + * @param + * @retval + */ +memhandle MemPool::allocBlock(memaddress size) { + memblock* best = NULL; + memhandle cur = POOLSTART; + memblock* block = &blocks[POOLSTART]; + memaddress bestsize = MEMPOOL_SIZE + 1; + + do { + memhandle next = block->nextblock; + memaddress freesize = (next == NOBLOCK ? blocks[POOLSTART].begin + MEMPOOL_SIZE : blocks[next].begin) - + block->begin - + block->size; + if (freesize == size) { + best = &blocks[cur]; + goto found; + } + + if (freesize > size && freesize < bestsize) { + bestsize = freesize; + best = &blocks[cur]; + } + + if (next == NOBLOCK) { + if (best) + goto found; + else + goto collect; + } + + block = &blocks[next]; + cur = next; + } while (true); + +collect: + { + cur = POOLSTART; + block = &blocks[POOLSTART]; + + memhandle next; + while ((next = block->nextblock) != NOBLOCK) { + memaddress dest = block->begin + block->size; + memblock* nextblock = &blocks[next]; + memaddress* src = &nextblock->begin; + if (dest != *src) + { +#ifdef MEMPOOL_MEMBLOCK_MV + MEMPOOL_MEMBLOCK_MV(dest, *src, nextblock->size); +#endif + *src = dest; + } + + block = nextblock; + } + + if (blocks[POOLSTART].begin + MEMPOOL_SIZE - block->begin - block->size >= size) + best = block; + else + goto notfound; + } + +found: + { + block = &blocks[POOLOFFSET]; + for (cur = POOLOFFSET; cur < MEMPOOL_NUM_MEMBLOCKS + POOLOFFSET; cur++) { + if (block->size) { + block++; + continue; + } + + memaddress address = best->begin + best->size; +#ifdef MEMBLOCK_ALLOC + MEMBLOCK_ALLOC(address, size); +#endif + block->begin = address; + block->size = size; + block->nextblock = best->nextblock; + best->nextblock = cur; + return cur; + } + } + +notfound: + return NOBLOCK; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void MemPool::freeBlock(memhandle handle) { + if (handle == NOBLOCK) + return; + + memblock* b = &blocks[POOLSTART]; + + do { + memhandle next = b->nextblock; + if (next == handle) { + memblock* f = &blocks[next]; +#ifdef MEMBLOCK_FREE + MEMBLOCK_FREE(f->begin, f->size); +#endif + b->nextblock = f->nextblock; + f->size = 0; + f->nextblock = NOBLOCK; + return; + } + + if (next == NOBLOCK) + return; + b = &blocks[next]; + } while (true); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void MemPool::resizeBlock(memhandle handle, memaddress position) { + memblock* block = &blocks[handle]; + block->begin += position; + block->size -= position; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void MemPool::resizeBlock(memhandle handle, memaddress position, memaddress size) { + memblock* block = &blocks[handle]; + block->begin += position; + block->size = size; +} + +/** + * @brief + * @note + * @param + * @retval + */ +memaddress MemPool::blockSize(memhandle handle) { + return blocks[handle].size; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utility/MemPool.h Tue Aug 27 15:01:10 2019 +0000 @@ -0,0 +1,52 @@ +/* + mempool.h - sleek implementation of a memory pool + Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de> + All rights reserved. + + 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/>. + */ +#ifndef MEMPOOL_H +#define MEMPOOL_H + +#include <inttypes.h> + +#define POOLSTART 0 +#define NOBLOCK 0 + +#include "mempool_conf.h" + +struct memblock +{ + memaddress begin; + memaddress size; + memhandle nextblock; +}; + +class MemPool +{ +#ifdef MEMPOOLTEST_H + friend class MemoryPoolTest; +#endif +protected: + static struct memblock blocks[MEMPOOL_NUM_MEMBLOCKS + 1]; +public: + + void init(); + static memhandle allocBlock(memaddress); + static void freeBlock(memhandle); + static void resizeBlock(memhandle handle, memaddress position); + static void resizeBlock(memhandle handle, memaddress position, memaddress size); + static memaddress blockSize(memhandle); +}; +#endif
--- a/utility/Server.h Fri Jun 30 19:51:28 2017 +0000 +++ b/utility/Server.h Tue Aug 27 15:01:10 2019 +0000 @@ -24,6 +24,6 @@ class Server { public: - virtual void begin(void) = 0; + virtual void open(void) = 0; }; #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utility/Udp.h Tue Aug 27 15:01:10 2019 +0000 @@ -0,0 +1,95 @@ +/* + * Udp.cpp: Library to send/receive UDP packets. + * + * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these) + * 1) UDP does not guarantee the order in which assembled UDP packets are received. This + * might not happen often in practice, but in larger network topologies, a UDP + * packet can be received out of sequence. + * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being + * aware of it. Again, this may not be a concern in practice on small local networks. + * For more information, see http://www.cafeaulait.org/course/week12/35.html + * + * MIT License: + * Copyright (c) 2008 Bjoern Hartmann + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * bjoern@cs.stanford.edu 12/30/2008 + */ +#ifndef udp_h +#define udp_h + +#include "mbed.h" +#include "IpAddress.h" + +class Udp +{ +public: + virtual uint8_t begin(uint16_t) = 0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + virtual void stop(void) = 0; // Finish with the UDP socket + + // Sending UDP packets + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IpAddress ip, uint16_t port) = 0; + + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char* host, uint16_t port) = 0; + + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket(void) = 0; + + // Write a single byte into the packet + virtual size_t write(uint8_t) = 0; + + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t* buffer, size_t size) = 0; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket(void) = 0; + + // Number of bytes remaining in the current packet + virtual int available(void) = 0; + + // Read a single byte from the current packet + virtual int read(void) = 0; + + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len) = 0; + + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) = 0; + + // Return the next byte from the current packet without moving on to the next byte + virtual int peek(void) = 0; + virtual void flush(void) = 0; // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IpAddress remoteIP(void) = 0; + + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort(void) = 0; +protected: + uint8_t* rawIPAddress(IpAddress& addr) { return addr.rawAddress(); }; +}; +#endif
--- a/utility/enc28j60.h Fri Jun 30 19:51:28 2017 +0000 +++ b/utility/enc28j60.h Tue Aug 27 15:01:10 2019 +0000 @@ -243,15 +243,14 @@ // // start with recbuf at 0/ #define RXSTART_INIT 0x0 -// receive buffer end. make sure this is an odd value ( See Rev. B1,B4,B5,B7 Silicon Errata 'Memory (Ethernet Buffer)') +// receive buffer end. make sure this is an odd value (See Rev. B1,B4,B5,B7 Silicon Errata 'Memory (Ethernet Buffer)') #define RXSTOP_INIT (0x1FFF-0x1800) // start TX buffer RXSTOP_INIT+1 -#define TXSTART_INIT (RXSTOP_INIT+1) +#define TXSTART_INIT (0x1FFF-0x1800+1) // stp TX buffer at end of mem #define TXSTOP_INIT 0x1FFF // // max frame length which the conroller will accept: #define MAX_FRAMELEN 1500 // (note: maximum ethernet frame length would be 1518) -//#define MAX_FRAMELEN 600 #endif
--- a/utility/mempool.cpp Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,192 +0,0 @@ -/* - mempool.cpp - sleek implementation of a memory pool - Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de> - All rights reserved. - - 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/>. - */ -#include "mempool.h" -#include <string.h> - -#define POOLOFFSET 1 - -struct memblock MemoryPool:: blocks[MEMPOOL_NUM_MEMBLOCKS + 1]; - -/** - * @brief - * @note - * @param - * @retval - */ -void MemoryPool::init(void) { - memset(&blocks[0], 0, sizeof(blocks)); - blocks[POOLSTART].begin = MEMPOOL_STARTADDRESS; - blocks[POOLSTART].size = 0; - blocks[POOLSTART].nextblock = NOBLOCK; -} - -/** - * @brief - * @note - * @param - * @retval - */ -memhandle MemoryPool::allocBlock(memaddress size) { - memblock* best = NULL; - memhandle cur = POOLSTART; - memblock* block = &blocks[POOLSTART]; - memaddress bestsize = MEMPOOL_SIZE + 1; - - do { - memhandle next = block->nextblock; - memaddress freesize = (next == NOBLOCK ? blocks[POOLSTART].begin + MEMPOOL_SIZE : blocks[next].begin) - - block->begin - - block->size; - if (freesize == size) { - best = &blocks[cur]; - goto found; - } - - if (freesize > size && freesize < bestsize) { - bestsize = freesize; - best = &blocks[cur]; - } - - if (next == NOBLOCK) { - if (best) - goto found; - else - goto collect; - } - - block = &blocks[next]; - cur = next; - } while (true); - -collect: - { - cur = POOLSTART; - block = &blocks[POOLSTART]; - - memhandle next; - while ((next = block->nextblock) != NOBLOCK) { - memaddress dest = block->begin + block->size; - memblock* nextblock = &blocks[next]; - memaddress* src = &nextblock->begin; - if (dest != *src) - { -#ifdef MEMPOOL_MEMBLOCK_MV - MEMPOOL_MEMBLOCK_MV(dest, *src, nextblock->size); -#endif - *src = dest; - } - - block = nextblock; - } - - if (blocks[POOLSTART].begin + MEMPOOL_SIZE - block->begin - block->size >= size) - best = block; - else - goto notfound; - } - -found: - { - block = &blocks[POOLOFFSET]; - for (cur = POOLOFFSET; cur < MEMPOOL_NUM_MEMBLOCKS + POOLOFFSET; cur++) { - if (block->size) { - block++; - continue; - } - - memaddress address = best->begin + best->size; -#ifdef MEMBLOCK_ALLOC - MEMBLOCK_ALLOC(address, size); -#endif - block->begin = address; - block->size = size; - block->nextblock = best->nextblock; - best->nextblock = cur; - return cur; - } - } - -notfound: - return NOBLOCK; -} - -/** - * @brief - * @note - * @param - * @retval - */ -void MemoryPool::freeBlock(memhandle handle) { - if (handle == NOBLOCK) - return; - - memblock* b = &blocks[POOLSTART]; - - do { - memhandle next = b->nextblock; - if (next == handle) { - memblock* f = &blocks[next]; -#ifdef MEMBLOCK_FREE - MEMBLOCK_FREE(f->begin, f->size); -#endif - b->nextblock = f->nextblock; - f->size = 0; - f->nextblock = NOBLOCK; - return; - } - - if (next == NOBLOCK) - return; - b = &blocks[next]; - } while (true); -} - -/** - * @brief - * @note - * @param - * @retval - */ -void MemoryPool::resizeBlock(memhandle handle, memaddress position) { - memblock* block = &blocks[handle]; - block->begin += position; - block->size -= position; -} - -/** - * @brief - * @note - * @param - * @retval - */ -void MemoryPool::resizeBlock(memhandle handle, memaddress position, memaddress size) { - memblock* block = &blocks[handle]; - block->begin += position; - block->size = size; -} - -/** - * @brief - * @note - * @param - * @retval - */ -memaddress MemoryPool::blockSize(memhandle handle) { - return blocks[handle].size; -}
--- a/utility/mempool.h Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - mempool.h - sleek implementation of a memory pool - Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de> - All rights reserved. - - 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/>. - */ -#ifndef MEMPOOL_H -#define MEMPOOL_H - -#include <inttypes.h> - -#define POOLSTART 0 -#define NOBLOCK 0 - -#include "mempool_conf.h" - -struct memblock -{ - memaddress begin; - memaddress size; - memhandle nextblock; -}; - -class MemoryPool -{ -#ifdef MEMPOOLTEST_H - friend class MemoryPoolTest; -#endif -protected: - static struct memblock blocks[MEMPOOL_NUM_MEMBLOCKS + 1]; -public: - static void init(void); - static memhandle allocBlock(memaddress); - static void freeBlock(memhandle); - static void resizeBlock(memhandle handle, memaddress position); - static void resizeBlock(memhandle handle, memaddress position, memaddress size); - static memaddress blockSize(memhandle); -}; -#endif
--- a/utility/mempool_conf.h Fri Jun 30 19:51:28 2017 +0000 +++ b/utility/mempool_conf.h Tue Aug 27 15:01:10 2019 +0000 @@ -25,7 +25,7 @@ #define MEMPOOL_STARTADDRESS TXSTART_INIT + 1 #define MEMPOOL_SIZE TXSTOP_INIT - TXSTART_INIT -void enc28J60_mempool_block_move_callback(memaddress, memaddress, memaddress); +void enc28j60_mempool_block_move_callback(memaddress, memaddress, memaddress); -#define MEMPOOL_MEMBLOCK_MV(dest, src, size) enc28J60_mempool_block_move_callback(dest, src, size) +#define MEMPOOL_MEMBLOCK_MV(dest, src, size) enc28j60_mempool_block_move_callback(dest, src, size) #endif
--- a/utility/millis.cpp Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - uip_millis.cpp - Copyright (c) 2015 Zoltan Hudak <hudakz@inbox.com> - All rights reserved. - - 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/>. - */ -#include "millis.h" -#include "mbed.h" - -volatile unsigned long _millis; - -/** - * @brief - * @note - * @param - * @retval - */ -void millis_start(void) { - SysTick_Config(SystemCoreClock / 1000); -} - -/** - * @brief - * @note - * @param - * @retval - */ -extern "C" void SysTick_Handler(void) { - _millis++; -} - -/** - * @brief - * @note - * @param - * @retval - */ -extern "C" unsigned long millis(void) { - return _millis; -}
--- a/utility/millis.h Fri Jun 30 19:51:28 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -/* - uip_millis.h - Copyright (c) 2015 Zoltan Hudak <hudakz@inbox.com> - All rights reserved. - - 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/>. - */ -#ifndef MILLIS_H -#define MILLIS_H - -extern "C" void millis_start(void); -extern "C" unsigned long millis(void); - -#endif
--- a/utility/uip-conf.h Fri Jun 30 19:51:28 2017 +0000 +++ b/utility/uip-conf.h Tue Aug 27 15:01:10 2019 +0000 @@ -162,23 +162,13 @@ * \hideinitializer */ #define UIP_CONF_STATISTICS 0 - -// SLIP - //#define UIP_CONF_LLH_LEN 0 typedef void* uip_tcp_appstate_t; - void uipclient_appcall(void); - #define UIP_APPCALL uipclient_appcall - typedef void* uip_udp_appstate_t; - void uipudp_appcall(void); - #define UIP_UDP_APPCALL uipudp_appcall - #define CC_REGISTER_ARG register - #define UIP_ARCH_CHKSUM 1 #endif /* __UIP_CONF_H__ */
--- a/utility/uip.h Fri Jun 30 19:51:28 2017 +0000 +++ b/utility/uip.h Tue Aug 27 15:01:10 2019 +0000 @@ -1416,20 +1416,14 @@ timer has fired. These values are never used directly, but only in the macrose defined in this file. */ -#define UIP_DATA 1 /* Tells UIP that there is incoming - data in the uip_buf buffer. The - length of the data is stored in the - global variable uip_len. */ - -#define UIP_TIMER 2 /* Tells UIP that the periodic timer - has fired. */ - -#define UIP_POLL_REQUEST 3 /* Tells UIP that a connection should - be polled. */ - -#define UIP_UDP_SEND_CONN 4 /* Tells UIP that a UDP datagram - should be constructed in the - uip_buf buffer. */ +#define UIP_DATA 1 /* Tells UIP that there is incoming + data in the uip_buf buffer. The + length of the data is stored in the + global variable uip_len. + */ +#define UIP_TIMER 2 /* Tells UIP that the periodic timer has fired. */ +#define UIP_POLL_REQUEST 3 /* Tells UIP that a connection should be polled. */ +#define UIP_UDP_SEND_CONN 4 /* Tells UIP that a UDP datagram should be constructed in the uip_buf buffer. */ #if UIP_UDP #define UIP_UDP_TIMER 5
--- a/utility/uip_debug.cpp Fri Jun 30 19:51:28 2017 +0000 +++ b/utility/uip_debug.cpp Tue Aug 27 15:01:10 2019 +0000 @@ -7,7 +7,7 @@ extern "C" { #include "uip.h" -} extern Serial pc; +} struct uip_conn con[UIP_CONNS]; /** @@ -19,9 +19,9 @@ void UIPDebug::uip_debug_printconns(void) { for (uint8_t i = 0; i < UIP_CONNS; i++) { if (uip_debug_printcon(&con[i], &uip_conns[i])) { - pc.printf("connection["); - pc.printf("%d", i); - pc.printf("] changed.\r\n"); + printf("connection["); + printf("%d", i); + printf("] changed.\r\n"); } } } @@ -35,130 +35,130 @@ bool UIPDebug::uip_debug_printcon(struct uip_conn* lhs, struct uip_conn* rhs) { bool changed = false; if (!uip_ipaddr_cmp(lhs->ripaddr, rhs->ripaddr)) { - pc.printf(" ripaddr: "); + printf(" ripaddr: "); uip_debug_printbytes((const uint8_t*)lhs->ripaddr, 4); - pc.printf(" -> "); + printf(" -> "); uip_debug_printbytes((const uint8_t*)rhs->ripaddr, 4); - pc.printf("\r\n"); + printf("\r\n"); uip_ipaddr_copy(lhs->ripaddr, rhs->ripaddr); changed = true; } if (lhs->lport != rhs->lport) { - pc.printf(" lport: "); - pc.printf("%d", htons(lhs->lport)); - pc.printf(" -> "); - pc.printf("%d\r\n", htons(rhs->lport)); + printf(" lport: "); + printf("%d", htons(lhs->lport)); + printf(" -> "); + printf("%d\r\n", htons(rhs->lport)); lhs->lport = rhs->lport; changed = true; } if (lhs->rport != rhs->rport) { - pc.printf(" rport: "); - pc.printf("%d", htons(lhs->rport)); - pc.printf(" -> "); - pc.printf("%d\r\n", htons(rhs->rport)); + printf(" rport: "); + printf("%d", htons(lhs->rport)); + printf(" -> "); + printf("%d\r\n", htons(rhs->rport)); lhs->rport = rhs->rport; changed = true; } if ((uint32_t) lhs->rcv_nxt[0] != (uint32_t) rhs->rcv_nxt[0]) { - pc.printf(" rcv_nxt: "); + printf(" rcv_nxt: "); uip_debug_printbytes(lhs->rcv_nxt, 4); - pc.printf(" -> "); + printf(" -> "); uip_debug_printbytes(rhs->rcv_nxt, 4); *((uint32_t*) &lhs->rcv_nxt[0]) = (uint32_t) rhs->rcv_nxt[0]; - pc.printf("\r\n"); + printf("\r\n"); changed = true; } if ((uint32_t) lhs->snd_nxt[0] != (uint32_t) rhs->snd_nxt[0]) { - pc.printf(" snd_nxt: "); + printf(" snd_nxt: "); uip_debug_printbytes(lhs->snd_nxt, 4); - pc.printf(" -> "); + printf(" -> "); uip_debug_printbytes(rhs->snd_nxt, 4); *((uint32_t*) &lhs->snd_nxt[0]) = (uint32_t) rhs->snd_nxt[0]; - pc.printf("\r\n"); + printf("\r\n"); changed = true; } if (lhs->len != rhs->len) { - pc.printf(" len: "); - pc.printf("%d", lhs->len); - pc.printf(" -> "); - pc.printf("%d\r\n", rhs->len); + printf(" len: "); + printf("%d", lhs->len); + printf(" -> "); + printf("%d\r\n", rhs->len); lhs->len = rhs->len; changed = true; } if (lhs->mss != rhs->mss) { - pc.printf(" mss: "); - pc.printf("%d", lhs->mss); - pc.printf(" -> "); - pc.printf("%d\r\n", rhs->mss); + printf(" mss: "); + printf("%d", lhs->mss); + printf(" -> "); + printf("%d\r\n", rhs->mss); lhs->mss = rhs->mss; changed = true; } if (lhs->initialmss != rhs->initialmss) { - pc.printf(" initialmss: "); - pc.printf("%d", lhs->initialmss); - pc.printf(" -> "); - pc.printf("%d\r\n", rhs->initialmss); + printf(" initialmss: "); + printf("%d", lhs->initialmss); + printf(" -> "); + printf("%d\r\n", rhs->initialmss); lhs->initialmss = rhs->initialmss; changed = true; } if (lhs->sa != rhs->sa) { - pc.printf(" sa: "); - pc.printf("%d", lhs->sa); - pc.printf(" -> "); - pc.printf("%d", rhs->sa); + printf(" sa: "); + printf("%d", lhs->sa); + printf(" -> "); + printf("%d", rhs->sa); lhs->sa = rhs->sa; changed = true; } if (lhs->sv != rhs->sv) { - pc.printf(" sv: "); - pc.printf("%d", lhs->sv); - pc.printf(" -> "); - pc.printf("%d\r\n", rhs->sv); + printf(" sv: "); + printf("%d", lhs->sv); + printf(" -> "); + printf("%d\r\n", rhs->sv); lhs->sv = rhs->sv; changed = true; } if (lhs->rto != rhs->rto) { - pc.printf(" rto: "); - pc.printf("%d", lhs->rto); - pc.printf(" -> "); - pc.printf("%d\r\n", rhs->rto); + printf(" rto: "); + printf("%d", lhs->rto); + printf(" -> "); + printf("%d\r\n", rhs->rto); lhs->rto = rhs->rto; changed = true; } if (lhs->tcpstateflags != rhs->tcpstateflags) { - pc.printf(" tcpstateflags: "); - pc.printf("%d", lhs->tcpstateflags); - pc.printf(" -> "); - pc.printf("%d\r\n", rhs->tcpstateflags); + printf(" tcpstateflags: "); + printf("%d", lhs->tcpstateflags); + printf(" -> "); + printf("%d\r\n", rhs->tcpstateflags); lhs->tcpstateflags = rhs->tcpstateflags; changed = true; } if (lhs->timer != rhs->timer) { - pc.printf(" timer: "); - pc.printf("%d", lhs->timer); - pc.printf(" -> "); - pc.printf("%d\r\n", rhs->timer); + printf(" timer: "); + printf("%d", lhs->timer); + printf(" -> "); + printf("%d\r\n", rhs->timer); lhs->timer = rhs->timer; changed = true; } if (lhs->nrtx != rhs->nrtx) { - pc.printf(" nrtx: "); - pc.printf("%d", lhs->nrtx); - pc.printf(" -> "); - pc.printf("%d\r\n", rhs->nrtx); + printf(" nrtx: "); + printf("%d", lhs->nrtx); + printf(" -> "); + printf("%d\r\n", rhs->nrtx); lhs->nrtx = rhs->nrtx; changed = true; } @@ -174,9 +174,9 @@ */ void UIPDebug::uip_debug_printbytes(const uint8_t* data, uint8_t len) { for (uint8_t i = 0; i < len; i++) { - pc.printf("%d", data[i]); + printf("%d", data[i]); if (i < len - 1) - pc.printf(","); + printf(","); } } #endif
--- a/utility/uipethernet-conf.h Fri Jun 30 19:51:28 2017 +0000 +++ b/utility/uipethernet-conf.h Tue Aug 27 15:01:10 2019 +0000 @@ -3,32 +3,31 @@ /* for TCP */ -#define UIP_SOCKET_NUMPACKETS 5 -#define UIP_CONF_MAX_CONNECTIONS 4 +#define UIP_SOCKET_NUMPACKETS 5 +#define UIP_MAX_CONNECTIONS 4 /* for UDP * set UIP_CONF_UDP to 0 to disable UDP (saves aprox. 5kb flash) */ -#define UIP_CONF_UDP 1 -#define UIP_CONF_BROADCAST 1 -#define UIP_CONF_UDP_CONNS 4 +#define UIP_CONF_UDP 1 +#define UIP_CONF_BROADCAST 1 +#define UIP_CONF_UDP_CONNS 4 /* number of attempts on write before returning number of bytes sent so far * set to -1 to block until connection is closed by timeout */ -#define UIP_ATTEMPTS_ON_WRITE - 1 +#define UIP_ATTEMPTS_ON_WRITE -1 /* timeout after which UIPClient::connect gives up. The timeout is specified in seconds. * if set to a number <= 0 connect will timeout when UIP does (which might be longer than you expect...) */ -#define UIP_CONNECT_TIMEOUT - 1 +#define UIP_CONNECT_TIMEOUT -1 /* periodic timer for uip (in ms) */ -#define UIP_PERIODIC_TIMER 250 +#define UIP_PERIODIC_TIMEOUT 250 -/* timer to poll client for data after last write (in ms) - * set to -1 to disable fast polling and rely on periodic only (saves 100 bytes flash) */ +/* timer to poll client for data after last write (in ms) */ -#define UIP_CLIENT_TIMER 20 +#define UIP_CLIENT_TIMEOUT 10 #endif
--- a/utility/uipopt.h Fri Jun 30 19:51:28 2017 +0000 +++ b/utility/uipopt.h Tue Aug 27 15:01:10 2019 +0000 @@ -244,11 +244,11 @@ * \hideinitializer */ -#ifndef UIP_CONF_MAX_CONNECTIONS +#ifndef UIP_MAX_CONNECTIONS #define UIP_CONNS 10 #else /* UIP_CONF_MAX_CONNECTIONS */ -#define UIP_CONNS UIP_CONF_MAX_CONNECTIONS +#define UIP_CONNS UIP_MAX_CONNECTIONS #endif /* UIP_CONF_MAX_CONNECTIONS */ /**