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 15:53715cc81c63, committed 2019-09-07
- Comitter:
- hudakz
- Date:
- Sat Sep 07 17:42:42 2019 +0000
- Parent:
- 14:7648334eb41b
- Child:
- 16:269f652b4d0b
- Commit message:
- Timeout parameter added for the 'connect' function, SPI speed reduced from 20 to 10 Mb/s, debug messages fixed ...
Changed in this revision
--- a/DhcpClient.cpp Tue Sep 03 09:16:55 2019 +0000 +++ b/DhcpClient.cpp Sat Sep 07 17:42:42 2019 +0000 @@ -2,6 +2,7 @@ // Author: Jordan Terrell - blog.jordanterrell.com #include <string.h> #include <stdlib.h> +#include "UipEthernet.h" #include "DhcpClient.h" #include "utility/util.h" @@ -44,54 +45,78 @@ //return:0 on error, 1 if request is sent and response is received int DhcpClient::requestDhcpLease() { +#ifdef UIPETHERNET_DEBUG_UDP + printf("requestDhcpLease(): begin\r\n"); +#endif uint8_t messageType = 0; + Timer timer; + + timer.reset(); + timer.start(); // Pick an initial transaction ID - srand(time(NULL)); + srand(time(NULL)+ 1); _dhcpTransactionId = (rand() % 2000UL) + 1; _dhcpInitialTransactionId = _dhcpTransactionId; _dhcpUdpSocket.stop(); if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0) { // Couldn't get a socket +#ifdef UIPETHERNET_DEBUG_UDP + printf("requestDhcpLease(): Couldn't get a socket\r\n"); +#endif return 0; } presendDhcp(); volatile int result = 0; - time_t startTime = time(NULL); while (_dhcp_state != STATE_DHCP_LEASED) { if (_dhcp_state == STATE_DHCP_START) { +#ifdef UIPETHERNET_DEBUG_UDP + printf("_dhcp_state: STATE_DHCP_START\r\n"); +#endif _dhcpTransactionId++; - sendDhcpMessage(DHCP_DISCOVER, (time(NULL) - startTime)); + sendDhcpMessage(DHCP_DISCOVER, (timer.read_ms() / 1000 + 1)); _dhcp_state = STATE_DHCP_DISCOVER; } else if (_dhcp_state == STATE_DHCP_REREQUEST) { +#ifdef UIPETHERNET_DEBUG_UDP + printf("_dhcp_state: STATE_DHCP_REREQUEST\r\n"); +#endif _dhcpTransactionId++; - sendDhcpMessage(DHCP_REQUEST, (time(NULL) - startTime)); + sendDhcpMessage(DHCP_REQUEST, (timer.read_ms() / 1000 + 1)); _dhcp_state = STATE_DHCP_REQUEST; } else if (_dhcp_state == STATE_DHCP_DISCOVER) { +#ifdef UIPETHERNET_DEBUG_UDP + printf("_dhcp_state: STATE_DHCP_DISCOVER\r\n"); +#endif 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)); + sendDhcpMessage(DHCP_REQUEST, (timer.read_ms() / 1000 + 1)); _dhcp_state = STATE_DHCP_REQUEST; } } else if (_dhcp_state == STATE_DHCP_REQUEST) { +#ifdef UIPETHERNET_DEBUG_UDP + printf("_dhcp_state: STATE_DHCP_REQUEST\r\n"); +#endif uint32_t respId; messageType = parseDhcpResponse(_responseTimeout, respId); if (messageType == DHCP_ACK) { +#ifdef UIPETHERNET_DEBUG_UDP + printf("messageType: DHCP_ACK\r\n"); +#endif _dhcp_state = STATE_DHCP_LEASED; result = 1; @@ -115,23 +140,37 @@ _rebindInSec = _dhcpT2; } else - if (messageType == DHCP_NAK) + if (messageType == DHCP_NAK) { + #ifdef UIPETHERNET_DEBUG_UDP + printf("messageType: DHCP_NAK\r\n"); +#endif _dhcp_state = STATE_DHCP_START; + } } if (messageType == 255) { +#ifdef UIPETHERNET_DEBUG_UDP + printf("DHCP_NAK: 255\r\n"); +#endif messageType = 0; _dhcp_state = STATE_DHCP_START; } - if ((result != 1) && ((time(NULL) - startTime) > _timeout)) + if ((result != 1) && ((timer.read_ms() / 1000) > _timeout)) { +#ifdef UIPETHERNET_DEBUG_UDP + printf("requestDhcpLease(): timeout\r\n"); +#endif break; + } } // We're done with the socket now _dhcpUdpSocket.stop(); _dhcpTransactionId++; +#ifdef UIPETHERNET_DEBUG_UDP + printf("requestDhcpLease(): %d\r\n", result); +#endif return result; } @@ -182,17 +221,17 @@ // yiaddr: already zeroed // siaddr: already zeroed // giaddr: already zeroed - //put data in W5100 transmit buffer + //put data in ENC28J60 transmit buffer _dhcpUdpSocket.write(buffer, 28); memset(buffer, 0, 32); // clear local buffer memcpy(buffer, _dhcpMacAddr, 6); // chaddr - //put data in W5100 transmit buffer + //put data in ENC28J60 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) + // put in ENC28J60 transmit buffer x 6 (192 bytes) for (int i = 0; i < 6; i++) { _dhcpUdpSocket.write(buffer, 32); } @@ -222,7 +261,7 @@ printByte((char*) &(buffer[26]), _dhcpMacAddr[4]); printByte((char*) &(buffer[28]), _dhcpMacAddr[5]); - //put data in W5100 transmit buffer + //put data in ENC28J60 transmit buffer _dhcpUdpSocket.write(buffer, 30); if (messageType == DHCP_REQUEST) { @@ -242,7 +281,7 @@ buffer[10] = _dhcpDhcpServerIp[2]; buffer[11] = _dhcpDhcpServerIp[3]; - //put data in W5100 transmit buffer + //put data in ENC28J60 transmit buffer _dhcpUdpSocket.write(buffer, 12); } @@ -256,7 +295,7 @@ buffer[7] = dhcpT2value; buffer[8] = endOption; - //put data in W5100 transmit buffer + //put data in ENC28J60 transmit buffer _dhcpUdpSocket.write(buffer, 9); _dhcpUdpSocket.endPacket(); @@ -272,11 +311,12 @@ { volatile uint8_t type = 0; uint8_t opt_len = 0; + Timer timer; - unsigned long startTime = time(NULL); + timer.start(); while (_dhcpUdpSocket.parsePacket() <= 0) { - if ((time(NULL) - startTime) > responseTimeout) { + if (timer.read() > responseTimeout) { return 255; }
--- a/DnsClient.cpp Tue Sep 03 09:16:55 2019 +0000 +++ b/DnsClient.cpp Sat Sep 07 17:42:42 2019 +0000 @@ -128,6 +128,9 @@ int DnsClient::getHostByName(const char* aHostname, IpAddress& aResult) { int ret = 0; + Timer timer; + + timer.start(); // See if it's a numeric IP address if (inet_aton(aHostname, aResult)) { @@ -141,7 +144,7 @@ } // Find a socket to use - if (iUdp.begin(1024 + (time(NULL) & 0xF)) == 1) { + if (iUdp.begin(1024 + ((timer.read_ms() / 1000) & 0xF)) == 1) { // Try up to three times int retries = 0; // while ((retries < 3) && (ret <= 0)) @@ -202,7 +205,7 @@ // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // As we only support one request at a time at present, we can simplify // some of this header - srand(time(NULL)); + srand(time(NULL) + 2); iRequestId = rand() % 0xFFFF + 1; // generate a random ID uint16_t twoByteBuffer; @@ -273,12 +276,15 @@ int16_t DnsClient::processResponse(uint16_t aTimeout, IpAddress& aAddress) { time_t startTime = time(NULL); + Timer timer; + + timer.start(); // Wait for a response packet while (iUdp.parsePacket() <= 0) { - if ((time(NULL) - startTime) > aTimeout) + if (timer.read() > aTimeout) return TIMED_OUT; - wait(0.050); + wait_ms(50); } // We've had a reply!
--- a/UdpSocket.cpp Tue Sep 03 09:16:55 2019 +0000 +++ b/UdpSocket.cpp Sat Sep 07 17:42:42 2019 +0000 @@ -148,7 +148,8 @@ } #ifdef UIPETHERNET_DEBUG_UDP - printf("rip: %s, port: %d\r\n", ip.asString(), port); + char buf[16]; + printf("rip: %s, port: %d\r\n", ip.toString(buf), port); #endif } @@ -156,17 +157,20 @@ if (appdata.packet_out == NOBLOCK) { appdata.packet_out = UipEthernet::ethernet->enc28j60Eth.allocBlock(UIP_UDP_MAXPACKETSIZE); appdata.out_pos = UIP_UDP_PHYH_LEN; - if (appdata.packet_out != NOBLOCK) + if (appdata.packet_out != NOBLOCK) { return 1; + } #ifdef UIPETHERNET_DEBUG_UDP - else + else { printf("failed to allocate memory for packet\r\n"); + } #endif } #ifdef UIPETHERNET_DEBUG_UDP - else + else { printf("previous packet on that connection not sent yet\r\n"); + } #endif } @@ -363,7 +367,7 @@ ( "udp, uip_newdata received packet: %d, size: %d\r\n", data->packet_next, - UIPEthernet.network.blockSize(data->packet_next) + UipEthernet::ethernet->enc28j60Eth.blockSize(data->packet_next) ); #endif } @@ -378,7 +382,7 @@ ( "udp, uip_poll preparing packet to send: %d, size: %d\r\n", data->packet_out, - UIPEthernet.network.blockSize(data->packet_out) + UipEthernet::ethernet->enc28j60Eth.blockSize(data->packet_out) ); #endif UipEthernet::uipPacket = data->packet_out; @@ -410,7 +414,7 @@ data->packet_out = NOBLOCK; UipEthernet::packetState |= UIPETHERNET_SENDPACKET; #ifdef UIPETHERNET_DEBUG_UDP - printf("udp, uip_packet to send: %d\r\n", UIPEthernet::uip_packet); + printf("udp, uip_packet to send: %d\r\n", UipEthernet::uipPacket); #endif }
--- a/UipEthernet.cpp Tue Sep 03 09:16:55 2019 +0000 +++ b/UipEthernet.cpp Sat Sep 07 17:42:42 2019 +0000 @@ -113,7 +113,7 @@ * @param * @retval */ -int UipEthernet::connect() +int UipEthernet::connect(unsigned long timeout) { // Inicialize static pointer to the UIPEthernet instance ethernet = this; @@ -124,7 +124,7 @@ // 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); + int ret = dhcpClient.begin((uint8_t*)_mac, timeout); if (ret == 1) { // We've successfully found a DHCP server and got our configuration info, so set things @@ -352,8 +352,8 @@ if (inPacket == NOBLOCK) { inPacket = enc28j60Eth.receivePacket(); #ifdef UIPETHERNET_DEBUG - if (in_packet != NOBLOCK) { - printf("--------------\r\nreceivePacket: %d\r\n", in_packet); + if (inPacket != NOBLOCK) { + printf("--------------\r\nreceivePacket: %d\r\n", inPacket); } #endif } @@ -391,7 +391,7 @@ if (inPacket != NOBLOCK && (packetState & UIPETHERNET_FREEPACKET)) { #ifdef UIPETHERNET_DEBUG - printf("freeing packet: %d\r\n", in_packet); + printf("freeing packet: %d\r\n", inPacket); #endif enc28j60Eth.freePacket(); inPacket = NOBLOCK; @@ -455,7 +455,7 @@ if (packetState & UIPETHERNET_SENDPACKET) { #ifdef UIPETHERNET_DEBUG - printf("Enc28J60Network_send uip_packet: %d, hdrlen: %d\r\n", uip_packet, uip_hdrlen); + printf("Enc28J60Network_send uipPacket: %d, hdrlen: %d\r\n", inPacket, uipHeaderLen); #endif enc28j60Eth.writePacket(uipPacket, 0, uip_buf, uipHeaderLen); packetState &= ~UIPETHERNET_SENDPACKET; @@ -466,12 +466,15 @@ if (uipPacket != NOBLOCK) { #ifdef UIPETHERNET_DEBUG - printf("Enc28J60Network_send uip_buf (uip_len): %d, packet: %d\r\n", uip_len, uip_packet); + printf("Enc28J60Network_send uip_buf (uip_len): %d, packet: %d\r\n", uip_len, uipPacket); #endif enc28j60Eth.writePacket(uipPacket, 0, uip_buf, uip_len); goto sendandfree; } +#ifdef UIPETHERNET_DEBUG + printf("Enc28J60Network_send return false\r\n"); +#endif return false; sendandfree: enc28j60Eth.sendPacket(uipPacket); @@ -635,7 +638,7 @@ #ifdef UIPETHERNET_DEBUG_CHKSUM printf ( - "chksum uip_packet(%d)[%d-%d]: %d\r\n", uip_packet, UIP_IPH_LEN + + "chksum uipPacket(%d)[%d-%d]: %d\r\n", uipPacket, UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen, UIP_IPH_LEN + UIP_LLH_LEN +
--- a/UipEthernet.h Tue Sep 03 09:16:55 2019 +0000 +++ b/UipEthernet.h Sat Sep 07 17:42:42 2019 +0000 @@ -39,26 +39,6 @@ #include "utility/uip.h" #include "utility/util.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 { @@ -69,7 +49,7 @@ UipEthernet (const uint8_t mac[6], PinName mosi, PinName miso, PinName sck, PinName cs); - int connect(); + int connect(unsigned long timeout = 60); void disconnect(); void set_network(uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4); void set_network(IpAddress ip);
--- a/utility/Enc28j60Eth.cpp Tue Sep 03 09:16:55 2019 +0000 +++ b/utility/Enc28j60Eth.cpp Sat Sep 07 17:42:42 2019 +0000 @@ -57,20 +57,21 @@ */ void Enc28j60Eth::init(uint8_t* macaddr) { - MemPool::init(); // 1 byte in between RX_STOP_INIT and pool to allow prepending of controlbyte + MemPool::init(); // 1 byte in between RX_STOP_INIT and pool to allow prepending of controlbyte + // initialize SPI interface + _cs = 1; _spi.format(8, 0); // 8-bit, mode 0 - _spi.frequency(20000000); // 20 Mbit/s - wait_ms(1000); // 1 second for stable state - // Release SPI - _cs = 1; + _spi.frequency(10000000); // 10 Mbit/s + wait_ms(100); // for stable state // 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. + // 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 @@ -90,18 +91,18 @@ //All memory which is not used by the receive buffer is considered the transmission buffer. // No explicit action is required to initialize the transmission buffer. - // However, he host controller should leave at least seven bytes between each - // packet and the beginning of the receive buffer. // TX start //writeRegPair(ETXSTL, TXSTART_INIT); // TX end //writeRegPair(ETXNDL, TXEND_INIT); + // However, he host controller should leave at least seven bytes between each + // packet and the beginning of the receive buffer. // 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 + // The pattern to match is therefore // Type ETH.DST // ARP BROADCAST // 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9 @@ -370,7 +371,9 @@ // read data result = _spi.write(0x00); + _cs = 1; + return(result); } @@ -391,6 +394,7 @@ // write data _spi.write(data); + _cs = 1; } @@ -458,7 +462,6 @@ if (address & 0x80) result = _spi.write(0x00); - // release CS _cs = 1; return(result); } @@ -478,6 +481,7 @@ // write data _spi.write(data); + _cs = 1; } @@ -493,15 +497,16 @@ // issue read command _spi.write(ENC28J60_READ_BUF_MEM); + + // read data while (len) { len--; - - // read data *data = _spi.write(0x00); data++; } *data = '\0'; + _cs = 1; } @@ -517,10 +522,10 @@ // issue write command _spi.write(ENC28J60_WRITE_BUF_MEM); + + // write data while (len) { len--; - - // write data _spi.write(*data); data++; }
--- a/utility/enc28j60.h Tue Sep 03 09:16:55 2019 +0000 +++ b/utility/enc28j60.h Sat Sep 07 17:42:42 2019 +0000 @@ -240,12 +240,12 @@ // The RXSTART_INIT should be zero. See Silicon Errata: // Sometimes, when ERXST or ERXND is written to, the exact value, 0000h, is stored in the Internal // Receive Write Pointer instead of the ERXST address. -// Work around +// Work around: // Use the lower segment of the buffer memory for the receive buffer, starting at address 0000h. // For example, use the range (0000h to n) for the receive buffer, and ((n + 1) to 8191) for the transmit buffer. #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)') -#define RXEND_INIT 0x11CB // = (3 * 1518) + 1 +#define RXEND_INIT (0x1FFF - 0x1800) // 0x1800 = 512 * 12 // Start TX buffer RXEND_INIT + 1 #define TXSTART_INIT RXEND_INIT + 1 // end TX buffer at end of mem
--- a/utility/uip-conf.h Tue Sep 03 09:16:55 2019 +0000 +++ b/utility/uip-conf.h Sat Sep 07 17:42:42 2019 +0000 @@ -85,7 +85,7 @@ * * \hideinitializer */ -#define UIP_CONF_MAX_LISTENPORTS 5 +#define UIP_CONF_MAX_LISTENPORTS 4 /** * UIP buffer size.
--- a/utility/uipethernet-conf.h Tue Sep 03 09:16:55 2019 +0000 +++ b/utility/uipethernet-conf.h Sat Sep 07 17:42:42 2019 +0000 @@ -4,14 +4,14 @@ /* for TCP */ #define UIP_SOCKET_NUMPACKETS 5 -#define UIP_MAX_CONNECTIONS 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 5 +#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 */
--- a/utility/util.h Tue Sep 03 09:16:55 2019 +0000 +++ b/utility/util.h Sat Sep 07 17:42:42 2019 +0000 @@ -5,4 +5,25 @@ //#define ntohs(x) htons(x) #define htonl(x) (((x) << 24 & 0xFF000000UL) | ((x) << 8 & 0x00FF0000UL) | ((x) >> 8 & 0x0000FF00UL) | ((x) >> 24 & 0x000000FFUL)) #define ntohl(x) htonl(x) +#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]) + #endif