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.

/media/uploads/hudakz/enc28j60_module01.jpg

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" to main.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.

Files at this revision

API Documentation at this revision

Comitter:
hudakz
Date:
Fri Jun 05 15:12:21 2020 +0000
Parent:
15:53715cc81c63
Child:
17:1123c3fe86ca
Commit message:
Library for ENC28J60 Ethernet modules.

Changed in this revision

DnsClient.cpp Show annotated file Show diff for this revision Revisions of this file
IpAddress.h Show annotated file Show diff for this revision Revisions of this file
UipEthernet.cpp Show annotated file Show diff for this revision Revisions of this file
UipEthernet.h Show annotated file Show diff for this revision Revisions of this file
utility/Enc28j60Eth.cpp Show annotated file Show diff for this revision Revisions of this file
utility/ip4tos.c Show diff for this revision Revisions of this file
utility/ip6tos.c Show diff for this revision Revisions of this file
utility/os2_ip4tos.c Show annotated file Show diff for this revision Revisions of this file
utility/os2_ip6tos.c Show annotated file Show diff for this revision Revisions of this file
utility/os2_stoip4.c Show annotated file Show diff for this revision Revisions of this file
utility/os2_stoip6.c Show annotated file Show diff for this revision Revisions of this file
utility/stoip4.c Show diff for this revision Revisions of this file
utility/stoip6.c Show diff for this revision Revisions of this file
--- a/DnsClient.cpp	Sat Sep 07 17:42:42 2019 +0000
+++ b/DnsClient.cpp	Fri Jun 05 15:12:21 2020 +0000
@@ -7,6 +7,7 @@
 #include "DnsClient.h"
 #include <string.h>
 #include "mbed.h"
+#include "mbed_version.h"
 
 #define SOCKET_NONE 255
 
@@ -284,7 +285,11 @@
     while (iUdp.parsePacket() <= 0) {
         if (timer.read() > aTimeout)
             return TIMED_OUT;
+#if MBED_MAJOR_VERSION == 2
         wait_ms(50);
+#else
+        thread_sleep_for(50);
+#endif
     }
 
     // We've had a reply!
--- a/IpAddress.h	Sat Sep 07 17:42:42 2019 +0000
+++ b/IpAddress.h	Fri Jun 05 15:12:21 2020 +0000
@@ -22,6 +22,7 @@
 #define IPADDRESS_h
 
 #include <stdio.h>
+#include "SocketAddress.h"
 
 // A class to make it easier to handle and pass around IP addresses
 
@@ -55,6 +56,8 @@
     // Returns IP Address as string of char
     const char* toString(char* buf);
 
+    void toSocketAddress(SocketAddress* sockAddr) { sockAddr->set_ip_bytes((const void*)_address, NSAPI_IPv4); }
+
     // 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
--- a/UipEthernet.cpp	Sat Sep 07 17:42:42 2019 +0000
+++ b/UipEthernet.cpp	Fri Jun 05 15:12:21 2020 +0000
@@ -113,7 +113,7 @@
  * @param
  * @retval
  */
-int UipEthernet::connect(unsigned long timeout)
+int UipEthernet::connect(unsigned long timeout /*=60*/)
 {
     // Inicialize static pointer to the UIPEthernet instance
     ethernet = this;
@@ -323,6 +323,17 @@
  * @param
  * @retval
  */
+void UipEthernet::get_ip_address(SocketAddress* addr)
+{
+    localIP().toSocketAddress(addr);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
 const char* UipEthernet::get_netmask()
 {
     static char buf[16];
@@ -335,6 +346,17 @@
  * @param
  * @retval
  */
+void UipEthernet::get_netmask(SocketAddress* addr)
+{
+    return subnetMask().toSocketAddress(addr);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
 const char* UipEthernet::get_gateway()
 {
     static char buf[16];
@@ -347,6 +369,17 @@
  * @param
  * @retval
  */
+void UipEthernet::get_gateway(SocketAddress* addr)
+{
+    return gatewayIP().toSocketAddress(addr);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
 void UipEthernet::tick()
 {
     if (inPacket == NOBLOCK) {
--- a/UipEthernet.h	Sat Sep 07 17:42:42 2019 +0000
+++ b/UipEthernet.h	Fri Jun 05 15:12:21 2020 +0000
@@ -63,8 +63,11 @@
     IpAddress         gatewayIP();
     IpAddress         dnsServerIP();
     const char*       get_ip_address();
+    void              get_ip_address(SocketAddress* addr);
     const char*       get_netmask();
+    void              get_netmask(SocketAddress* addr);
     const char*       get_gateway();
+    void              get_gateway(SocketAddress* addr);
     static uint16_t   chksum(uint16_t sum, const uint8_t* data, uint16_t len);
     static uint16_t   ipchksum();
     bool              stoip4(const char *ip4addr, size_t len, void *dest);
--- a/utility/Enc28j60Eth.cpp	Sat Sep 07 17:42:42 2019 +0000
+++ b/utility/Enc28j60Eth.cpp	Fri Jun 05 15:12:21 2020 +0000
@@ -25,6 +25,7 @@
  */
 #include "Enc28j60Eth.h"
 #include "mbed.h"
+#include "mbed_version.h"
 
 extern "C"
 {
@@ -63,7 +64,11 @@
     _cs = 1;
     _spi.format(8, 0);          // 8-bit, mode 0
     _spi.frequency(10000000);   // 10 Mbit/s
-    wait_ms(100);               // for stable state
+#if MBED_MAJOR_VERSION == 2
+    wait_ms(100);
+#else
+    thread_sleep_for(100);
+#endif
 
     // perform system reset
     writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
@@ -72,7 +77,11 @@
     // while(!(readReg(ESTAT) & ESTAT_CLKRDY));
     // The CLKRDY does not work. See Rev. B4 Silicon Errata point.
     // Just wait.
+#if MBED_MAJOR_VERSION == 2
     wait_ms(50);
+#else
+    thread_sleep_for(50);
+#endif
 
     // do bank 0 stuff
     // initialize receive buffer
@@ -707,9 +716,17 @@
 void Enc28j60Eth::powerOff()
 {
     writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN);
+#if MBED_MAJOR_VERSION == 2
     wait_ms(50);
+#else
+    thread_sleep_for(50);
+#endif
     writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_VRPS);
+#if MBED_MAJOR_VERSION == 2
     wait_ms(50);
+#else
+    thread_sleep_for(50);
+#endif
     writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV);
 }
 
@@ -722,9 +739,17 @@
 void Enc28j60Eth::powerOn()
 {
     writeOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV);
+#if MBED_MAJOR_VERSION == 2
     wait_ms(50);
+#else
+    thread_sleep_for(50);
+#endif
     writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
+#if MBED_MAJOR_VERSION == 2
     wait_ms(50);
+#else
+    thread_sleep_for(50);
+#endif
 }
 
 /**
--- a/utility/ip4tos.c	Sat Sep 07 17:42:42 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2014-2018 ARM Limited. All rights reserved.
- * SPDX-License-Identifier: Apache-2.0
- * Licensed under the Apache License, Version 2.0 (the License); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an AS IS BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "mbed_version.h"
-
-#if MBED_MAJOR_VERSION == 2
-
-#include <stdio.h>
-#include <string.h>
-#include "common_functions.h"
-#include "ip4string.h"
-
-static void ipv4_itoa(char *string, uint8_t byte);
-
-/**
- * Print binary IPv4 address to a string.
- * String must contain enough room for full address, 16 bytes exact.
- * \param addr IPv4 address.
- * \p buffer to write string to.
- */
-uint_fast8_t ip4tos(const void *ip4addr, char *p)
-{
-    uint_fast8_t outputPos = 0;
-    const uint8_t *byteArray = ip4addr;
-
-    for (uint_fast8_t component = 0; component < 4; ++component) {
-        //Convert the byte to string
-        ipv4_itoa(&p[outputPos], byteArray[component]);
-
-        //Move outputPos to the end of the string
-        while (p[outputPos] != '\0') {
-            outputPos += 1;
-        }
-
-        //Append a dot if this is not the last digit
-        if (component < 3) {
-            p[outputPos++] = '.';
-        }
-    }
-
-    // Return length of generated string, excluding the terminating null character
-    return outputPos;
-}
-
-static void ipv4_itoa(char *string, uint8_t byte)
-{
-    char *baseString = string;
-
-    //Write the digits to the buffer from the least significant to the most
-    //  This is the incorrect order but we will swap later
-    do {
-        *string++ = '0' + byte % 10;
-        byte /= 10;
-    } while (byte);
-
-    //We put the final \0, then go back one step on the last digit for the swap
-    *string-- = '\0';
-
-    //We now swap the digits
-    while (baseString < string) {
-        uint8_t tmp = *string;
-        *string-- = *baseString;
-        *baseString++ = tmp;
-    }
-}
-#endif
--- a/utility/ip6tos.c	Sat Sep 07 17:42:42 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,124 +0,0 @@
-/*
- * Copyright (c) 2014-2015 ARM Limited. All rights reserved.
- * SPDX-License-Identifier: Apache-2.0
- * Licensed under the Apache License, Version 2.0 (the License); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an AS IS BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "mbed_version.h"
-
-#if MBED_MAJOR_VERSION == 2
-
-#include <stdio.h>
-#include <string.h>
-#include "common_functions.h"
-#include "ip6string.h"
-
-/**
- * Print binary IPv6 address to a string.
- * String must contain enough room for full address, 40 bytes exact.
- * IPv4 tunneling addresses are not covered.
- * \param addr IPv6 address.
- * \p buffer to write string to.
- */
-uint_fast8_t ip6tos(const void *ip6addr, char *p)
-{
-    char *p_orig = p;
-    uint_fast8_t zero_start = 255, zero_len = 1;
-    const uint8_t *addr = ip6addr;
-    uint_fast16_t part;
-
-    /* Follow RFC 5952 - pre-scan for longest run of zeros */
-    for (uint_fast8_t n = 0; n < 8; n++) {
-        part = *addr++;
-        part = (part << 8) | *addr++;
-        if (part != 0) {
-            continue;
-        }
-
-        /* We're at the start of a run of zeros - scan to non-zero (or end) */
-        uint_fast8_t n0 = n;
-        for (n = n0 + 1; n < 8; n++) {
-            part = *addr++;
-            part = (part << 8) | *addr++;
-            if (part != 0) {
-                break;
-            }
-        }
-
-        /* Now n0->initial zero of run, n->after final zero in run. Is this the
-         * longest run yet? If equal, we stick with the previous one - RFC 5952
-         * S4.2.3. Note that zero_len being initialised to 1 stops us
-         * shortening a 1-part run (S4.2.2.)
-         */
-        if (n - n0 > zero_len) {
-            zero_start = n0;
-            zero_len = n - n0;
-        }
-
-        /* Continue scan for initial zeros from part n+1 - we've already
-         * consumed part n, and know it's non-zero. */
-    }
-
-    /* Now go back and print, jumping over any zero run */
-    addr = ip6addr;
-    for (uint_fast8_t n = 0; n < 8;) {
-        if (n == zero_start) {
-            if (n == 0) {
-                *p++ = ':';
-            }
-            *p++ = ':';
-            addr += 2 * zero_len;
-            n += zero_len;
-            continue;
-        }
-
-        part = *addr++;
-        part = (part << 8) | *addr++;
-        n++;
-
-        p += sprintf(p, "%"PRIxFAST16, part);
-
-        /* One iteration writes "part:" rather than ":part", and has the
-         * explicit check for n == 8 below, to allow easy extension for
-         * IPv4-in-IPv6-type addresses ("xxxx::xxxx:a.b.c.d"): we'd just
-         * run the same loop for 6 parts, and output would then finish with the
-         * required : or ::, ready for "a.b.c.d" to be tacked on.
-         */
-        if (n != 8) {
-            *p++ = ':';
-        }
-    }
-    *p = '\0';
-
-    // Return length of generated string, excluding the terminating null character
-    return p - p_orig;
-}
-
-uint_fast8_t ip6_prefix_tos(const void *prefix, uint_fast8_t prefix_len, char *p)
-{
-    char *wptr = p;
-    uint8_t addr[16] = {0};
-
-    if (prefix_len > 128) {
-        return 0;
-    }
-
-    // Generate prefix part of the string
-    bitcopy(addr, prefix, prefix_len);
-    wptr += ip6tos(addr, wptr);
-    // Add the prefix length part of the string
-    wptr += sprintf(wptr, "/%"PRIuFAST8, prefix_len);
-
-    // Return total length of generated string
-    return wptr - p;
-}
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utility/os2_ip4tos.c	Fri Jun 05 15:12:21 2020 +0000
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2014-2018 ARM Limited. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "mbed_version.h"
+
+#if MBED_MAJOR_VERSION == 2
+
+#include <stdio.h>
+#include <string.h>
+#include "common_functions.h"
+#include "ip4string.h"
+
+static void ipv4_itoa(char *string, uint8_t byte);
+
+/**
+ * Print binary IPv4 address to a string.
+ * String must contain enough room for full address, 16 bytes exact.
+ * \param addr IPv4 address.
+ * \p buffer to write string to.
+ */
+uint_fast8_t ip4tos(const void *ip4addr, char *p)
+{
+    uint_fast8_t outputPos = 0;
+    const uint8_t *byteArray = ip4addr;
+
+    for (uint_fast8_t component = 0; component < 4; ++component) {
+        //Convert the byte to string
+        ipv4_itoa(&p[outputPos], byteArray[component]);
+
+        //Move outputPos to the end of the string
+        while (p[outputPos] != '\0') {
+            outputPos += 1;
+        }
+
+        //Append a dot if this is not the last digit
+        if (component < 3) {
+            p[outputPos++] = '.';
+        }
+    }
+
+    // Return length of generated string, excluding the terminating null character
+    return outputPos;
+}
+
+static void ipv4_itoa(char *string, uint8_t byte)
+{
+    char *baseString = string;
+
+    //Write the digits to the buffer from the least significant to the most
+    //  This is the incorrect order but we will swap later
+    do {
+        *string++ = '0' + byte % 10;
+        byte /= 10;
+    } while (byte);
+
+    //We put the final \0, then go back one step on the last digit for the swap
+    *string-- = '\0';
+
+    //We now swap the digits
+    while (baseString < string) {
+        uint8_t tmp = *string;
+        *string-- = *baseString;
+        *baseString++ = tmp;
+    }
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utility/os2_ip6tos.c	Fri Jun 05 15:12:21 2020 +0000
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2014-2015 ARM Limited. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "mbed_version.h"
+
+#if MBED_MAJOR_VERSION == 2
+
+#include <stdio.h>
+#include <string.h>
+#include "common_functions.h"
+#include "ip6string.h"
+
+/**
+ * Print binary IPv6 address to a string.
+ * String must contain enough room for full address, 40 bytes exact.
+ * IPv4 tunneling addresses are not covered.
+ * \param addr IPv6 address.
+ * \p buffer to write string to.
+ */
+uint_fast8_t ip6tos(const void *ip6addr, char *p)
+{
+    char *p_orig = p;
+    uint_fast8_t zero_start = 255, zero_len = 1;
+    const uint8_t *addr = ip6addr;
+    uint_fast16_t part;
+
+    /* Follow RFC 5952 - pre-scan for longest run of zeros */
+    for (uint_fast8_t n = 0; n < 8; n++) {
+        part = *addr++;
+        part = (part << 8) | *addr++;
+        if (part != 0) {
+            continue;
+        }
+
+        /* We're at the start of a run of zeros - scan to non-zero (or end) */
+        uint_fast8_t n0 = n;
+        for (n = n0 + 1; n < 8; n++) {
+            part = *addr++;
+            part = (part << 8) | *addr++;
+            if (part != 0) {
+                break;
+            }
+        }
+
+        /* Now n0->initial zero of run, n->after final zero in run. Is this the
+         * longest run yet? If equal, we stick with the previous one - RFC 5952
+         * S4.2.3. Note that zero_len being initialised to 1 stops us
+         * shortening a 1-part run (S4.2.2.)
+         */
+        if (n - n0 > zero_len) {
+            zero_start = n0;
+            zero_len = n - n0;
+        }
+
+        /* Continue scan for initial zeros from part n+1 - we've already
+         * consumed part n, and know it's non-zero. */
+    }
+
+    /* Now go back and print, jumping over any zero run */
+    addr = ip6addr;
+    for (uint_fast8_t n = 0; n < 8;) {
+        if (n == zero_start) {
+            if (n == 0) {
+                *p++ = ':';
+            }
+            *p++ = ':';
+            addr += 2 * zero_len;
+            n += zero_len;
+            continue;
+        }
+
+        part = *addr++;
+        part = (part << 8) | *addr++;
+        n++;
+
+        p += sprintf(p, "%"PRIxFAST16, part);
+
+        /* One iteration writes "part:" rather than ":part", and has the
+         * explicit check for n == 8 below, to allow easy extension for
+         * IPv4-in-IPv6-type addresses ("xxxx::xxxx:a.b.c.d"): we'd just
+         * run the same loop for 6 parts, and output would then finish with the
+         * required : or ::, ready for "a.b.c.d" to be tacked on.
+         */
+        if (n != 8) {
+            *p++ = ':';
+        }
+    }
+    *p = '\0';
+
+    // Return length of generated string, excluding the terminating null character
+    return p - p_orig;
+}
+
+uint_fast8_t ip6_prefix_tos(const void *prefix, uint_fast8_t prefix_len, char *p)
+{
+    char *wptr = p;
+    uint8_t addr[16] = {0};
+
+    if (prefix_len > 128) {
+        return 0;
+    }
+
+    // Generate prefix part of the string
+    bitcopy(addr, prefix, prefix_len);
+    wptr += ip6tos(addr, wptr);
+    // Add the prefix length part of the string
+    wptr += sprintf(wptr, "/%"PRIuFAST8, prefix_len);
+
+    // Return total length of generated string
+    return wptr - p;
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utility/os2_stoip4.c	Fri Jun 05 15:12:21 2020 +0000
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2014-2018 ARM Limited. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "mbed_version.h"
+
+#if MBED_MAJOR_VERSION == 2
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "common_functions.h"
+#include "ip4string.h"
+
+/**
+ * Convert numeric IPv4 address string to a binary.
+ * \param ip4addr IPv4 address in string format.
+ * \param len Length of IPv4 string, maximum of 16..
+ * \param dest buffer for address. MUST be 4 bytes.
+ * \return boolean set to true if conversion succeded, false if it didn't
+ */
+bool stoip4(const char *ip4addr, size_t len, void *dest)
+{
+    uint8_t *addr = dest;
+
+    if (len > 16) { // Too long, not possible
+        return false;
+    }
+
+    uint_fast8_t stringLength = 0, byteCount = 0;
+
+    //Iterate over each component of the IP. The exit condition is in the middle of the loop
+    while (true) {
+
+        //No valid character (IPv4 addresses don't have implicit 0, that is x.y..z being read as x.y.0.z)
+        if (stringLength == len || ip4addr[stringLength] < '0' || ip4addr[stringLength] > '9') {
+            return false;
+        }
+
+        //For each component, we convert it to the raw value
+        uint_fast16_t byte = 0;
+        while (stringLength < len && ip4addr[stringLength] >= '0' && ip4addr[stringLength] <= '9') {
+            byte *= 10;
+            byte += ip4addr[stringLength++] - '0';
+
+            //We go over the maximum value for an IPv4 component
+            if (byte > 0xff) {
+                return false;
+            }
+        }
+
+        //Append the component
+        addr[byteCount++] = (uint8_t) byte;
+
+        //If we're at the end, we leave the loop. It's the only way to reach the `true` output
+        if (byteCount == 4) {
+            break;
+        }
+
+        //If the next character is invalid, we return false
+        if (stringLength == len || ip4addr[stringLength++] != '.') {
+            return false;
+        }
+    }
+
+    return stringLength == len || ip4addr[stringLength] == '\0';
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utility/os2_stoip6.c	Fri Jun 05 15:12:21 2020 +0000
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2014-2015 ARM Limited. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "mbed_version.h"
+
+#if MBED_MAJOR_VERSION == 2
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "common_functions.h"
+#include "ip6string.h"
+
+static uint16_t hex(const char *p);
+static bool is_hex(char c);
+
+/**
+ * Convert numeric IPv6 address string to a binary.
+ * IPv4 tunnelling addresses are not covered.
+ * \param ip6addr IPv6 address in string format.
+ * \param len Length of ipv6 string.
+ * \param dest buffer for address. MUST be 16 bytes.
+ * \return boolean set to true if conversion succeed, false if it didn't
+ */
+bool stoip6(const char *ip6addr, size_t len, void *dest)
+{
+    uint8_t *addr;
+    const char *p, *q;
+    int_fast8_t field_no, coloncolon = -1;
+
+    addr = dest;
+
+    if (len > 39) { // Too long, not possible. We do not support IPv4-mapped IPv6 addresses
+        goto error;
+    }
+
+    // First go forward the string, until end, noting :: position if any
+    // We're decrementing `len` as we go forward, and stop when it reaches 0
+    for (field_no = 0, p = ip6addr; len && *p; p = q + 1) {
+
+        for (q = p; len && *q && (*q != ':'); len -= 1) { // Seek for ':' or end
+            if (!is_hex(*q++)) { // There must only be hex characters besides ':'
+                goto error;
+            }
+        }
+
+        if ((q - p) > 4) { // We can't have more than 4 hex digits per segment
+            goto error;
+        }
+
+        if (field_no == 8) { // If the address goes farther than 8 segments
+            goto error;
+        }
+
+        // Convert and write this part, (high-endian AKA network byte order)
+        addr = common_write_16_bit(hex(p), addr);
+        field_no++;
+
+        // We handle the colons
+        if (len) {
+            // Check if we reached "::"
+            if (q[0] == ':' && q[1] == ':') {
+                if (coloncolon != -1) { // We are not supposed to see "::" more than once per address
+                    goto error;
+                }
+                coloncolon = field_no;
+                q++;
+                len -= 2;
+            } else {
+                len -= 1;
+            }
+        }
+    }
+
+    if (coloncolon != -1) {
+        /* Insert zeros in the appropriate place */
+        uint_fast8_t head_size = 2 * coloncolon;
+        uint_fast8_t inserted_size = 2 * (8 - field_no);
+        uint_fast8_t tail_size = 16 - head_size - inserted_size;
+        addr = dest;
+        memmove(addr + head_size + inserted_size, addr + head_size, tail_size);
+        memset(addr + head_size, 0, inserted_size);
+    } else if (field_no != 8) { // Report an error if we didn't get 8 fields
+        goto error;
+    }
+    return true;
+
+error:
+    // Fill the output buffer with 0 so we stick to the old failure behavior.
+    // We are however more agressive and wipe the entire address, and do so more often.
+    memset(dest, 0, 16);
+    return false;
+}
+
+unsigned char sipv6_prefixlength(const char *ip6addr)
+{
+    char *ptr = strchr(ip6addr, '/');
+    if (ptr) {
+        return (unsigned char)strtoul(ptr + 1, 0, 10);
+    }
+    return 0;
+}
+
+int stoip6_prefix(const char *ip6addr, void *dest, int_fast16_t *prefix_len_out)
+{
+    size_t addr_len, total_len;
+    int_fast16_t prefix_length;
+
+    if (prefix_len_out) {
+        *prefix_len_out = -1;
+    }
+
+    total_len = addr_len = strlen(ip6addr);
+    const char *ptr = strchr(ip6addr, '/');
+    if (ptr) {
+        addr_len = ptr - ip6addr;
+        if (prefix_len_out) {
+            if (total_len - addr_len > 3) {
+                /* too many digits in prefix */
+                return -1;
+            }
+
+            prefix_length = strtoul(ptr + 1, 0, 10);
+            if (prefix_length <  0 || prefix_length > 128) {
+                /* prefix value illegal */
+                return -1;
+            }
+
+            *prefix_len_out = prefix_length;
+        }
+    }
+
+    if (!stoip6(ip6addr, addr_len, dest)) {
+        /* parser failure */
+        return -1;
+    }
+
+    return 0;
+}
+
+static bool is_hex(char c)
+{
+    // 'A' (0x41) and 'a' (0x61) are mapped in the ASCII table in such a way that masking the 0x20 bit turn 'a' in 'A'
+    if ((c & ~0x20) >= 'A' && (c & ~0x20) <= 'F') {
+        return true;
+    }
+
+    if (c >= '0' && c <= '9') {
+        return true;
+    }
+
+    return false;
+}
+
+static uint16_t hex(const char *p)
+{
+    uint16_t val = 0;
+
+    for (;;) {
+        char c = *p++;
+        if ((c >= '0') && (c <= '9')) {
+            val = (val << 4) | (c - '0');
+        } else if ((c >= 'A') && (c <= 'F')) {
+            val = (val << 4) | (10 + (c - 'A'));
+        } else if ((c >= 'a') && (c <= 'f')) {
+            val = (val << 4) | (10 + (c - 'a'));
+        } else {
+            break; // Non hex character
+        }
+    }
+    return val;
+}
+#endif
--- a/utility/stoip4.c	Sat Sep 07 17:42:42 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2014-2018 ARM Limited. All rights reserved.
- * SPDX-License-Identifier: Apache-2.0
- * Licensed under the Apache License, Version 2.0 (the License); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an AS IS BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "mbed_version.h"
-
-#if MBED_MAJOR_VERSION == 2
-
-#include <string.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "common_functions.h"
-#include "ip4string.h"
-
-/**
- * Convert numeric IPv4 address string to a binary.
- * \param ip4addr IPv4 address in string format.
- * \param len Length of IPv4 string, maximum of 16..
- * \param dest buffer for address. MUST be 4 bytes.
- * \return boolean set to true if conversion succeded, false if it didn't
- */
-bool stoip4(const char *ip4addr, size_t len, void *dest)
-{
-    uint8_t *addr = dest;
-
-    if (len > 16) { // Too long, not possible
-        return false;
-    }
-
-    uint_fast8_t stringLength = 0, byteCount = 0;
-
-    //Iterate over each component of the IP. The exit condition is in the middle of the loop
-    while (true) {
-
-        //No valid character (IPv4 addresses don't have implicit 0, that is x.y..z being read as x.y.0.z)
-        if (stringLength == len || ip4addr[stringLength] < '0' || ip4addr[stringLength] > '9') {
-            return false;
-        }
-
-        //For each component, we convert it to the raw value
-        uint_fast16_t byte = 0;
-        while (stringLength < len && ip4addr[stringLength] >= '0' && ip4addr[stringLength] <= '9') {
-            byte *= 10;
-            byte += ip4addr[stringLength++] - '0';
-
-            //We go over the maximum value for an IPv4 component
-            if (byte > 0xff) {
-                return false;
-            }
-        }
-
-        //Append the component
-        addr[byteCount++] = (uint8_t) byte;
-
-        //If we're at the end, we leave the loop. It's the only way to reach the `true` output
-        if (byteCount == 4) {
-            break;
-        }
-
-        //If the next character is invalid, we return false
-        if (stringLength == len || ip4addr[stringLength++] != '.') {
-            return false;
-        }
-    }
-
-    return stringLength == len || ip4addr[stringLength] == '\0';
-}
-#endif
--- a/utility/stoip6.c	Sat Sep 07 17:42:42 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,185 +0,0 @@
-/*
- * Copyright (c) 2014-2015 ARM Limited. All rights reserved.
- * SPDX-License-Identifier: Apache-2.0
- * Licensed under the Apache License, Version 2.0 (the License); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an AS IS BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "mbed_version.h"
-
-#if MBED_MAJOR_VERSION == 2
-
-#include <string.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "common_functions.h"
-#include "ip6string.h"
-
-static uint16_t hex(const char *p);
-static bool is_hex(char c);
-
-/**
- * Convert numeric IPv6 address string to a binary.
- * IPv4 tunnelling addresses are not covered.
- * \param ip6addr IPv6 address in string format.
- * \param len Length of ipv6 string.
- * \param dest buffer for address. MUST be 16 bytes.
- * \return boolean set to true if conversion succeed, false if it didn't
- */
-bool stoip6(const char *ip6addr, size_t len, void *dest)
-{
-    uint8_t *addr;
-    const char *p, *q;
-    int_fast8_t field_no, coloncolon = -1;
-
-    addr = dest;
-
-    if (len > 39) { // Too long, not possible. We do not support IPv4-mapped IPv6 addresses
-        goto error;
-    }
-
-    // First go forward the string, until end, noting :: position if any
-    // We're decrementing `len` as we go forward, and stop when it reaches 0
-    for (field_no = 0, p = ip6addr; len && *p; p = q + 1) {
-
-        for (q = p; len && *q && (*q != ':'); len -= 1) { // Seek for ':' or end
-            if (!is_hex(*q++)) { // There must only be hex characters besides ':'
-                goto error;
-            }
-        }
-
-        if ((q - p) > 4) { // We can't have more than 4 hex digits per segment
-            goto error;
-        }
-
-        if (field_no == 8) { // If the address goes farther than 8 segments
-            goto error;
-        }
-
-        // Convert and write this part, (high-endian AKA network byte order)
-        addr = common_write_16_bit(hex(p), addr);
-        field_no++;
-
-        // We handle the colons
-        if (len) {
-            // Check if we reached "::"
-            if (q[0] == ':' && q[1] == ':') {
-                if (coloncolon != -1) { // We are not supposed to see "::" more than once per address
-                    goto error;
-                }
-                coloncolon = field_no;
-                q++;
-                len -= 2;
-            } else {
-                len -= 1;
-            }
-        }
-    }
-
-    if (coloncolon != -1) {
-        /* Insert zeros in the appropriate place */
-        uint_fast8_t head_size = 2 * coloncolon;
-        uint_fast8_t inserted_size = 2 * (8 - field_no);
-        uint_fast8_t tail_size = 16 - head_size - inserted_size;
-        addr = dest;
-        memmove(addr + head_size + inserted_size, addr + head_size, tail_size);
-        memset(addr + head_size, 0, inserted_size);
-    } else if (field_no != 8) { // Report an error if we didn't get 8 fields
-        goto error;
-    }
-    return true;
-
-error:
-    // Fill the output buffer with 0 so we stick to the old failure behavior.
-    // We are however more agressive and wipe the entire address, and do so more often.
-    memset(dest, 0, 16);
-    return false;
-}
-
-unsigned char sipv6_prefixlength(const char *ip6addr)
-{
-    char *ptr = strchr(ip6addr, '/');
-    if (ptr) {
-        return (unsigned char)strtoul(ptr + 1, 0, 10);
-    }
-    return 0;
-}
-
-int stoip6_prefix(const char *ip6addr, void *dest, int_fast16_t *prefix_len_out)
-{
-    size_t addr_len, total_len;
-    int_fast16_t prefix_length;
-
-    if (prefix_len_out) {
-        *prefix_len_out = -1;
-    }
-
-    total_len = addr_len = strlen(ip6addr);
-    const char *ptr = strchr(ip6addr, '/');
-    if (ptr) {
-        addr_len = ptr - ip6addr;
-        if (prefix_len_out) {
-            if (total_len - addr_len > 3) {
-                /* too many digits in prefix */
-                return -1;
-            }
-
-            prefix_length = strtoul(ptr + 1, 0, 10);
-            if (prefix_length <  0 || prefix_length > 128) {
-                /* prefix value illegal */
-                return -1;
-            }
-
-            *prefix_len_out = prefix_length;
-        }
-    }
-
-    if (!stoip6(ip6addr, addr_len, dest)) {
-        /* parser failure */
-        return -1;
-    }
-
-    return 0;
-}
-
-static bool is_hex(char c)
-{
-    // 'A' (0x41) and 'a' (0x61) are mapped in the ASCII table in such a way that masking the 0x20 bit turn 'a' in 'A'
-    if ((c & ~0x20) >= 'A' && (c & ~0x20) <= 'F') {
-        return true;
-    }
-
-    if (c >= '0' && c <= '9') {
-        return true;
-    }
-
-    return false;
-}
-
-static uint16_t hex(const char *p)
-{
-    uint16_t val = 0;
-
-    for (;;) {
-        char c = *p++;
-        if ((c >= '0') && (c <= '9')) {
-            val = (val << 4) | (c - '0');
-        } else if ((c >= 'A') && (c <= 'F')) {
-            val = (val << 4) | (10 + (c - 'A'));
-        } else if ((c >= 'a') && (c <= 'f')) {
-            val = (val << 4) | (10 + (c - 'a'));
-        } else {
-            break; // Non hex character
-        }
-    }
-    return val;
-}
-#endif