Mbed OS and Pelion Device Management example over WIFI for DISCO_L475VG_IOT01 board

Dependencies:   X_NUCLEO_COMMON ST_INTERFACES

DEPRECATED

This example application is not maintained and not recommended. It uses an old version of Mbed OS, Pelion DM and Arm toolchain. It doesn't work with Mbed Studio.

Please use: https://os.mbed.com/teams/mbed-os-examples/code/mbed-os-example-pelion/

This example is known to work on the following platforms:

DISCO_L475E_IOT01A

Follow the Quick-Start instructions: https://cloud.mbed.com/quick-start

Example functionality

This example showcases the following device functionality:

  • Read onboard temperature and humidity sensors, and report them as Pelion LWM2M resources (see image below).
  • On user button click, increment Pelion LWM2M button resource.
  • Allow the user to change the state of the board LED from Pelion LWM2M led_state resource and PUT request.
  • Uses all onboard sensors and reports them as Pelion LWM2M resources.

/media/uploads/screamer/pelion_st_humidity_reading.png?v=2

Use this example with Mbed CLI

1. Import the application into your desktop:

mbed import https://os.mbed.com/teams/ST/code/pelion-example-disco-iot01

cd pelion-example-disco-iot01

2. Install the CLOUD_SDK_API_KEY

mbed config -G CLOUD_SDK_API_KEY <PELION_DM_API_KEY>

For instructions on how to generate your API key, please see the documentation.

3. Initialize firmware credentials (done once per repository). You can use the following command:

mbed dm init -d "<your company name in Pelion DM>" --model-name "<product model identifier>" -q --force

If above command do not work for your Mbed CLI, please consider upgrading Mbed CLI to version 1.8.x or above.

4. Compile and program:

mbed compile -t <toolchain> -m DISCO_L475VG_IOT01A

(supported toolchains : GCC_ARM / ARM / IAR)

5. You can connect on a virtual terminal/COM port to the platform using:

mbed sterm -b 115200

This should give you an output similar to:

[BOOT] Mbed Bootloader
[BOOT] ARM: 00000000000000000000
[BOOT] OEM: 00000000000000000000
[BOOT] Layout: 0 80096F4
[BOOT] Active firmware integrity check:
[BOOT] SHA256: 0660E360D432225D5251461998FD8617B017098C5F1F90D5FB607BF8C27ED530
[BOOT] Version: 1553615309
[BOOT] Slot 0 is empty
[BOOT] Active firmware up-to-date
[BOOT] Application's start address: 0x8010400
[BOOT] Application's jump address: 0x8011041
[BOOT] Application's stack address: 0x20018000
[BOOT] Forwarding to application...

Starting Simple Pelion Device Management Client example
You can hold the user button during boot to format the storage and change the device identity.

Sensors configuration:
Invalid new address!
HTS221  humidity & temperature    = 0xBC
LPS22HB pressure & temperature    = 0xB1
LIS3MDL magnetometer              = 0x3D
LSM6DSL accelerometer & gyroscope = 0x6A

Connecting to the network using Wifi...
Connected to the network successfully. IP address: 192.168.1.3
Initializing Pelion Device Management Client...
Initialized Pelion Client. Registering...
Registered to Pelion Device Management. Endpoint Name: 0169********************001002d5

ADC temp:     23.0037 C,  vref:      0.3661 V
HTS221 temp:   28.700 C,  humidity:   31.90 %
LPS22HB temp:  29.600 C,  pressure: 1032.01 mbar
LIS3MDL mag:    0.217 x,  -0.284 y,  -0.053 z [gauss]
LSM6DSL acc:    0.005 x,  -0.014 y,   1.029 z [g]
LSM6DSL gyro:   0.910 x,  -0.910 y,   1.120 z [dps]
VL53L0X dist:    1855 mm

Files at this revision

API Documentation at this revision

Comitter:
screamer
Date:
Sat Dec 08 01:46:22 2018 +0000
Parent:
9:265744785d33
Child:
11:8df4529f060d
Commit message:
Update example to Pelion Client 2.0.1.1 and Mbed OS 5.10.4. Also prepare repo to expose sensors in the cloud

Changed in this revision

bootloader/bootloader_app.json Show annotated file Show diff for this revision Revisions of this file
bootloader/mbed-bootloader-DISCO_L475VG_IOT01A.bin Show annotated file Show diff for this revision Revisions of this file
bootloader/mbed-bootloader-L475VG.bin Show diff for this revision Revisions of this file
bootloader/mbed_app.json Show diff for this revision Revisions of this file
drivers/network/WIFI_ISM43362.lib Show annotated file Show diff for this revision Revisions of this file
drivers/network/WIFI_ISM43362/ISM43362/ATParser/ATParser.cpp Show annotated file Show diff for this revision Revisions of this file
drivers/network/WIFI_ISM43362/ISM43362/ATParser/ATParser.h Show annotated file Show diff for this revision Revisions of this file
drivers/network/WIFI_ISM43362/ISM43362/ATParser/BufferedSpi/Buffer/MyBuffer.cpp Show annotated file Show diff for this revision Revisions of this file
drivers/network/WIFI_ISM43362/ISM43362/ATParser/BufferedSpi/Buffer/MyBuffer.h Show annotated file Show diff for this revision Revisions of this file
drivers/network/WIFI_ISM43362/ISM43362/ATParser/BufferedSpi/BufferedPrint.c Show annotated file Show diff for this revision Revisions of this file
drivers/network/WIFI_ISM43362/ISM43362/ATParser/BufferedSpi/BufferedSpi.cpp Show annotated file Show diff for this revision Revisions of this file
drivers/network/WIFI_ISM43362/ISM43362/ATParser/BufferedSpi/BufferedSpi.h Show annotated file Show diff for this revision Revisions of this file
drivers/network/WIFI_ISM43362/ISM43362/ISM43362.cpp Show annotated file Show diff for this revision Revisions of this file
drivers/network/WIFI_ISM43362/ISM43362/ISM43362.h Show annotated file Show diff for this revision Revisions of this file
drivers/network/WIFI_ISM43362/ISM43362Interface.cpp Show annotated file Show diff for this revision Revisions of this file
drivers/network/WIFI_ISM43362/ISM43362Interface.h Show annotated file Show diff for this revision Revisions of this file
drivers/network/WIFI_ISM43362/README.md Show annotated file Show diff for this revision Revisions of this file
drivers/network/WIFI_ISM43362/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
drivers/storage/COMPONENT_QSPIF/QSPIFBlockDevice.cpp Show annotated file Show diff for this revision Revisions of this file
drivers/storage/COMPONENT_QSPIF/QSPIFBlockDevice.h Show annotated file Show diff for this revision Revisions of this file
drivers/storage/COMPONENT_QSPIF/TESTS/block_device/qspif/main.cpp Show annotated file Show diff for this revision Revisions of this file
drivers/storage/COMPONENT_QSPIF/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
drivers/storage/MySystemStorage.cpp Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-os.lib Show annotated file Show diff for this revision Revisions of this file
mbed_app.json Show annotated file Show diff for this revision Revisions of this file
mbed_cloud_dev_credentials.c Show annotated file Show diff for this revision Revisions of this file
sensors/HTS221.lib Show annotated file Show diff for this revision Revisions of this file
sensors/LIS3MDL.lib Show annotated file Show diff for this revision Revisions of this file
sensors/LPS22HB.lib Show annotated file Show diff for this revision Revisions of this file
sensors/LSM303AGR.lib Show annotated file Show diff for this revision Revisions of this file
sensors/LSM6DSL.lib Show annotated file Show diff for this revision Revisions of this file
sensors/VL53L0X.lib Show annotated file Show diff for this revision Revisions of this file
simple-mbed-cloud-client.lib Show annotated file Show diff for this revision Revisions of this file
update_default_resources.c Show annotated file Show diff for this revision Revisions of this file
wifi-ism43362.lib Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bootloader/bootloader_app.json	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,69 @@
+{
+    "macros": [
+        "MBEDTLS_USER_CONFIG_FILE=\"bootloader_mbedtls_user_config.h\"",
+        "SHOW_PROGRESS_BAR=0",
+        "MAX_COPY_RETRIES=1",
+        "MAX_BOOT_RETRIES=3",
+        "ARM_BOOTLOADER_USE_NVSTORE_ROT=1",
+        "ARM_UC_USE_PAL_CRYPTO=0",
+        "ARM_UC_USE_PAL_BLOCKDEVICE=1",
+        "ARM_UC_PAAL_TRACE_ENABLE=0",
+        "ARM_UC_PROFILE_MBED_CLOUD_CLIENT=1",
+        "ARM_UC_FEATURE_CRYPTO_PAL=0",
+        "ARM_UC_FEATURE_CRYPTO_MBEDTLS=1",
+        "MBED_CLOUD_CLIENT_UPDATE_STORAGE=ARM_UCP_FLASHIAP_BLOCKDEVICE",
+        "DEFAULT_MAX_APPLICATION_SIZE=(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - MBED_CONF_APP_APPLICATION_START_ADDRESS)",
+        "DISABLE_ERROR_DESCRIPTION=1",
+        "Mutex=PlatformMutex"
+    ],
+    "config": {
+        "application-start-address": {
+            "help": "Address to the beginning of the active application firmware in flash",
+            "value": null
+        },
+        "application-jump-address": {
+            "help": "Jump address for running the active application firmware",
+            "value": null
+        },
+        "max-application-size": {
+            "help": "Maximum size of the active application",
+            "value": null
+        },
+        "flash-start-address": {
+            "help": "Start address of internal flash. Only used in this config to help the definition of other macros.",
+            "value": null
+        },
+        "flash-size": {
+            "help": "Total size of internal flash. Only used in this config to help the definition of other macros.",
+            "value": null
+        }
+    },
+    "target_overrides": {
+        "*": {
+            "target.features_remove"           : ["LWIP"],
+            "target.features_add"              : ["COMMON_PAL"],
+            "platform.stdio-baud-rate"         : 115200,
+            "platform.stdio-flush-at-exit"     : false,
+            "update-client.storage-address"    : "(1024*1024*64)",
+            "update-client.storage-size"       : "(1024*1024*2)",
+            "update-client.storage-locations"  : 1,
+            "update-client.firmware-header-version": "2"
+        },
+        "DISCO_L475VG_IOT01A": {
+            "target.components_add"            : ["QSPIF"],
+            "target.components_remove"         : ["FLASHIAP"],
+            "flash-start-address"              : "0x08000000",
+            "flash-size"                       : "(1024*1024)",
+            "nvstore.area_1_address"           : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(2*1024))",
+            "nvstore.area_1_size"              : "(2*1024)",
+            "nvstore.area_2_address"           : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(2*1024))",
+            "nvstore.area_2_size"              : "(2*1024)",
+            "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)",
+            "update-client.storage-address"    : "(1024*1024*2)",
+            "update-client.storage-size"       : "(1024*1024*2)",
+            "update-client.storage-locations"  : 1,
+            "application-start-address"        : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)",
+            "max-application-size"             : "DEFAULT_MAX_APPLICATION_SIZE"
+        }
+    }
+}
Binary file bootloader/mbed-bootloader-DISCO_L475VG_IOT01A.bin has changed
Binary file bootloader/mbed-bootloader-L475VG.bin has changed
--- a/bootloader/mbed_app.json	Sun Oct 14 19:01:53 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-{
-    "macros": [
-        "MBEDTLS_USER_CONFIG_FILE=\"bootloader_mbedtls_user_config.h\"",
-        "MAX_COPY_RETRIES=1",
-        "SHOW_PROGRESS_BAR=1",
-        "MAX_BOOT_RETRIES=3",
-        "ARM_UC_USE_PAL_CRYPTO=0",
-        "ARM_BOOTLOADER_USE_NVSTORE_ROT=1",
-        "ARM_UC_USE_PAL_BLOCKDEVICE=1",
-        "ARM_UC_PAAL_TRACE_ENABLE=0",
-        "MBED_CLOUD_CLIENT_UPDATE_STORAGE=ARM_UCP_FLASHIAP_BLOCKDEVICE",
-        "DEFAULT_MAX_APPLICATION_SIZE=(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - MBED_CONF_APP_APPLICATION_START_ADDRESS)",
-        "DISABLE_ERROR_DESCRIPTION=1",
-        "Mutex=PlatformMutex"
-    ],
-    "config": {
-        "application-start-address": {
-            "help": "Address to the beginning of the active application firmware in flash",
-            "value": null
-        },
-        "application-jump-address": {
-            "help": "Jump address for running the active application firmware",
-            "value": null
-        },
-        "max-application-size": {
-            "help": "Maximum size of the active application",
-            "value": null
-        },
-        "flash-start-address": {
-            "help": "Start address of internal flash. Only used in this config to help the definition of other macros.",
-            "value": null
-        },
-        "flash-size": {
-            "help": "Total size of internal flash. Only used in this config to help the definition of other macros.",
-            "value": null
-        }
-    },
-    "target_overrides": {
-        "*": {
-            "target.features_remove": ["LWIP"],
-            "target.features_add"   : ["COMMON_PAL"],
-            "platform.stdio-baud-rate"    : 115200,
-            "platform.stdio-flush-at-exit": false,
-            "update-client.storage-address"  : "(1024*1024*64)",
-            "update-client.storage-size"     : "(1024*1024*2)",
-            "update-client.storage-locations": 1,
-            "update-client.firmware-header-version": "2"
-        },
-         "DISCO_L475VG_IOT01A": {
-            "flash-start-address"              : "0x08000000",
-            "flash-size"                       : "(1024*1024)",
-            "nvstore.area_1_address"           : "(0x08000000+((1024-4)*1024))",
-            "nvstore.area_1_size"              : "(2*1024)",
-            "nvstore.area_2_address"           : "(0x08000000+((1024-2)*1024))",
-            "nvstore.area_2_size"              : "(2*1024)",
-            "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS+64*1024)",
-            "application-start-address"        : "(MBED_CONF_APP_FLASH_START_ADDRESS+65*1024)",
-            "max-application-size"             : "DEFAULT_MAX_APPLICATION_SIZE",
-            "sd.SPI_MOSI"  : "D11",
-            "sd.SPI_MISO"  : "D12",
-            "sd.SPI_CLK"   : "D13",
-            "sd.SPI_CS"    : "D10"
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/network/WIFI_ISM43362.lib	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,1 @@
+https://github.com/ARMmbed/wifi-ism43362/#49d0f834dc420c98631fc33777aace9a31d8d584
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/network/WIFI_ISM43362/ISM43362/ATParser/ATParser.cpp	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,454 @@
+/* Copyright (c) 2015 ARM Limited
+ *
+ * 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.
+ *
+ * @section DESCRIPTION
+ *
+ * Parser for the AT command syntax
+ *
+ */
+
+#include "ATParser.h"
+#include "mbed_debug.h"
+
+#ifdef LF
+#undef LF
+#define LF  10
+#else
+#define LF  10
+#endif
+
+#ifdef CR
+#undef CR
+#define CR  13
+#else
+#define CR  13
+#endif
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+// activate / de-activate debug
+#define dbg_on           0
+#define AT_DATA_PRINT    0
+#define AT_COMMAND_PRINT 0
+#define AT_HEXA_DATA     0
+
+ATParser::ATParser(BufferedSpi &serial_spi, const char *delimiter, int buffer_size, int timeout) :
+    _serial_spi(&serial_spi),
+    _buffer_size(buffer_size), _in_prev(0), _oobs(NULL)
+{
+    _buffer = new char[buffer_size];
+    setTimeout(timeout);
+    setDelimiter(delimiter);
+}
+
+
+// getc/putc handling with timeouts
+int ATParser::putc(char c)
+{
+    return _serial_spi->putc(c);
+}
+
+int ATParser::getc()
+{
+    return _serial_spi->getc();
+}
+
+void ATParser::flush()
+{
+    _bufferMutex.lock();
+    while (_serial_spi->readable()) {
+        _serial_spi->getc();
+    }
+    _bufferMutex.unlock();
+}
+
+// read/write handling with timeouts
+int ATParser::write(const char *data, int size_of_data, int size_in_buff)
+{
+    int i = 0;
+    _bufferMutex.lock();
+    debug_if(dbg_on, "ATParser write: %d BYTES\r\n", size_of_data);
+    debug_if(AT_DATA_PRINT, "ATParser write: (ASCII) ", size_of_data);
+    for (; i < size_of_data; i++) {
+        debug_if(AT_DATA_PRINT, "%c", data[i]);
+        if (putc(data[i]) < 0) {
+            debug_if(AT_DATA_PRINT, "\r\n");
+            _bufferMutex.unlock();
+            return -1;
+        }
+    }
+    debug_if(AT_DATA_PRINT, "\r\n");
+
+    _serial_spi->buffsend(size_of_data + size_in_buff);
+    _bufferMutex.unlock();
+
+    return (size_of_data + size_in_buff);
+}
+
+int ATParser::read(char *data)
+{
+    int readsize;
+    int i = 0;
+
+    _bufferMutex.lock();
+
+    //this->flush();
+    if (!_serial_spi->readable()) {
+        readsize = _serial_spi->read();
+    } else {
+        debug_if(dbg_on, "Pending data when reading from WIFI\r\n");
+        return -1;
+    }
+
+    debug_if(dbg_on, "ATParser read: %d data avail in SPI\r\n", readsize);
+
+    if (readsize < 0) {
+        _bufferMutex.unlock();
+        return -1;
+    }
+
+    for (i = 0 ; i < readsize; i++) {
+        int c = getc();
+        if (c < 0) {
+            _bufferMutex.unlock();
+            return -1;
+        }
+        data[i] = c;
+    }
+
+#if AT_HEXA_DATA
+    debug_if(AT_DATA_PRINT, "ATParser read: (HEXA) ");
+    for (i = 0; i < readsize; i++) {
+        debug_if(AT_DATA_PRINT, "%2X ", data[i]);
+        if ((i + 1) % 20 == 0) {
+            debug_if(AT_DATA_PRINT, "\r\n");
+        }
+    }
+    debug_if(AT_DATA_PRINT, "\r\n");
+#endif
+    debug_if(AT_DATA_PRINT, "ATParser read: (ASCII) ");
+    for (i = 0; i < readsize; i++) {
+        debug_if(AT_DATA_PRINT, "%c", data[i]);
+    }
+    debug_if(AT_DATA_PRINT, "\r\n");
+
+    _bufferMutex.unlock();
+
+    return (readsize);
+}
+
+// printf/scanf handling
+int ATParser::vprintf(const char *format, va_list args)
+{
+    _bufferMutex.lock();
+    if (vsprintf(_buffer, format, args) < 0) {
+        _bufferMutex.unlock();
+        return false;
+    }
+
+    int i = 0;
+    for (; _buffer[i]; i++) {
+        if (putc(_buffer[i]) < 0) {
+            _bufferMutex.unlock();
+            return -1;
+        }
+    }
+    _bufferMutex.unlock();
+
+    return i;
+}
+
+int ATParser::vscanf(const char *format, va_list args)
+{
+    // Since format is const, we need to copy it into our buffer to
+    // add the line's null terminator and clobber value-matches with asterisks.
+    //
+    // We just use the beginning of the buffer to avoid unnecessary allocations.
+    int i = 0;
+    int offset = 0;
+
+    _bufferMutex.lock();
+
+    while (format[i]) {
+        if (format[i] == '%' && format[i + 1] != '%' && format[i + 1] != '*') {
+            _buffer[offset++] = '%';
+            _buffer[offset++] = '*';
+            i++;
+        } else {
+            _buffer[offset++] = format[i++];
+        }
+    }
+
+    // Scanf has very poor support for catching errors
+    // fortunately, we can abuse the %n specifier to determine
+    // if the entire string was matched.
+    _buffer[offset++] = '%';
+    _buffer[offset++] = 'n';
+    _buffer[offset++] = 0;
+
+    // To workaround scanf's lack of error reporting, we actually
+    // make two passes. One checks the validity with the modified
+    // format string that only stores the matched characters (%n).
+    // The other reads in the actual matched values.
+    //
+    // We keep trying the match until we succeed or some other error
+    // derails us.
+    int j = 0;
+
+    while (true) {
+        // Ran out of space
+        if (j + 1 >= _buffer_size - offset) {
+            _bufferMutex.unlock();
+            return false;
+        }
+        // Recieve next character
+        int c = getc();
+        if (c < 0) {
+            _bufferMutex.unlock();
+            return -1;
+        }
+        _buffer[offset + j++] = c;
+        _buffer[offset + j] = 0;
+
+        // Check for match
+        int count = -1;
+        sscanf(_buffer + offset, _buffer, &count);
+
+        // We only succeed if all characters in the response are matched
+        if (count == j) {
+            // Store the found results
+            vsscanf(_buffer + offset, format, args);
+            _bufferMutex.unlock();
+            return j;
+        }
+    }
+}
+
+
+// Command parsing with line handling
+bool ATParser::vsend(const char *command, va_list args)
+{
+    int i = 0, j = 0;
+    _bufferMutex.lock();
+    // Create and send command
+    if (vsprintf(_buffer, command, args) < 0) {
+        _bufferMutex.unlock();
+        return false;
+    }
+    /* get buffer length */
+    for (i = 0; _buffer[i]; i++) {
+    }
+
+    for (j = 0; _delimiter[j]; j++) {
+        _buffer[i + j] = _delimiter[j];
+    }
+    _buffer[i + j] = 0; // only to get a clean debug log
+
+    bool ret = !(_serial_spi->buffwrite(_buffer, i + j) < 0);
+
+    debug_if(AT_COMMAND_PRINT, "AT> %s\n", _buffer);
+    _bufferMutex.unlock();
+    return ret;
+}
+
+bool ATParser::vrecv(const char *response, va_list args)
+{
+    _bufferMutex.lock();
+
+    if (!_serial_spi->readable()) {
+        // debug_if(dbg_on, "NO DATA, read again\r\n");
+        if (_serial_spi->read() < 0) {
+            return false;
+        }
+    }
+    // else {
+    //      debug_if(dbg_on, "Pending data\r\n");
+    // }
+
+restart:
+    _aborted = false;
+    // Iterate through each line in the expected response
+    while (response[0]) {
+        // Since response is const, we need to copy it into our buffer to
+        // add the line's null terminator and clobber value-matches with asterisks.
+        //
+        // We just use the beginning of the buffer to avoid unnecessary allocations.
+        int i = 0;
+        int offset = 0;
+        bool whole_line_wanted = false;
+
+        while (response[i]) {
+            if (response[i] == '%' && response[i + 1] != '%' && response[i + 1] != '*') {
+                _buffer[offset++] = '%';
+                _buffer[offset++] = '*';
+                i++;
+            } else {
+                _buffer[offset++] = response[i++];
+                // Find linebreaks, taking care not to be fooled if they're in a %[^\n] conversion specification
+                if (response[i - 1] == '\n' && !(i >= 3 && response[i - 3] == '[' && response[i - 2] == '^')) {
+                    whole_line_wanted = true;
+                    break;
+                }
+            }
+        }
+
+        // Scanf has very poor support for catching errors
+        // fortunately, we can abuse the %n specifier to determine
+        // if the entire string was matched.
+        _buffer[offset++] = '%';
+        _buffer[offset++] = 'n';
+        _buffer[offset++] = 0;
+
+        // debug_if(dbg_on, "ATParser vrecv: AT? ====%s====\n", _buffer);
+        // To workaround scanf's lack of error reporting, we actually
+        // make two passes. One checks the validity with the modified
+        // format string that only stores the matched characters (%n).
+        // The other reads in the actual matched values.
+        //
+        // We keep trying the match until we succeed or some other error
+        // derails us.
+        int j = 0;
+
+        while (true) {
+            // Recieve next character
+            int c = getc();
+            if (c < 0) {
+                debug_if(dbg_on, "AT(Timeout)\n");
+                _bufferMutex.unlock();
+                return false;
+            }
+
+            // debug_if(AT_DATA_PRINT, "%2X ", c);
+
+            _buffer[offset + j++] = c;
+            _buffer[offset + j] = 0;
+
+            // Check for oob data
+            for (struct oob *oob = _oobs; oob; oob = oob->next) {
+                if ((unsigned)j == oob->len && memcmp(
+                            oob->prefix, _buffer + offset, oob->len) == 0) {
+                    debug_if(dbg_on, "AT! %s\n", oob->prefix);
+                    oob->cb();
+
+                    if (_aborted) {
+                        debug_if(dbg_on, "AT(Aborted)\n");
+                        _bufferMutex.unlock();
+                        return false;
+                    }
+                    // oob may have corrupted non-reentrant buffer,
+                    // so we need to set it up again
+                    goto restart;
+                }
+            }
+
+            // Check for match
+            int count = -1;
+            if (whole_line_wanted && c != '\n') {
+                // Don't attempt scanning until we get delimiter if they included it in format
+                // This allows recv("Foo: %s\n") to work, and not match with just the first character of a string
+                // (scanf does not itself match whitespace in its format string, so \n is not significant to it)
+            } else {
+                sscanf(_buffer + offset, _buffer, &count);
+            }
+
+            // We only succeed if all characters in the response are matched
+            if (count == j) {
+                debug_if(AT_COMMAND_PRINT, "AT= ====%s====\n", _buffer + offset);
+                // Reuse the front end of the buffer
+                memcpy(_buffer, response, i);
+                _buffer[i] = 0;
+
+                // Store the found results
+                vsscanf(_buffer + offset, _buffer, args);
+
+                // Jump to next line and continue parsing
+                response += i;
+                break;
+            }
+
+            // Clear the buffer when we hit a newline or ran out of space
+            // running out of space usually means we ran into binary data
+            if ((c == '\n')) {
+                // debug_if(dbg_on, "New line AT<<< %s", _buffer+offset);
+                j = 0;
+            }
+            if ((j + 1 >= (_buffer_size - offset))) {
+
+                debug_if(dbg_on, "Out of space AT<<< %s, j=%d", _buffer + offset, j);
+                j = 0;
+            }
+        }
+    }
+
+    _bufferMutex.unlock();
+
+    return true;
+}
+
+
+// Mapping to vararg functions
+int ATParser::printf(const char *format, ...)
+{
+    va_list args;
+    va_start(args, format);
+    int res = vprintf(format, args);
+    va_end(args);
+    return res;
+}
+
+int ATParser::scanf(const char *format, ...)
+{
+    va_list args;
+    va_start(args, format);
+    int res = vscanf(format, args);
+    va_end(args);
+    return res;
+}
+
+bool ATParser::send(const char *command, ...)
+{
+    va_list args;
+    va_start(args, command);
+    bool res = vsend(command, args);
+    va_end(args);
+    return res;
+}
+
+bool ATParser::recv(const char *response, ...)
+{
+    va_list args;
+    va_start(args, response);
+    bool res = vrecv(response, args);
+    va_end(args);
+    return res;
+}
+
+
+// oob registration
+void ATParser::oob(const char *prefix, Callback<void()> cb)
+{
+    struct oob *oob = new struct oob;
+    oob->len = strlen(prefix);
+    oob->prefix = prefix;
+    oob->cb = cb;
+    oob->next = _oobs;
+    _oobs = oob;
+}
+
+void ATParser::abort()
+{
+    _aborted = true;
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/network/WIFI_ISM43362/ISM43362/ATParser/ATParser.h	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,246 @@
+/* Copyright (c) 2015 ARM Limited
+ *
+ * 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.
+ *
+ * @section DESCRIPTION
+ *
+ * Parser for the AT command syntax
+ *
+ */
+#ifndef AT_PARSER_H
+#define AT_PARSER_H
+
+#include "mbed.h"
+#include <cstdarg>
+#include <vector>
+#include "BufferedSpi.h"
+#include "Callback.h"
+
+#define DEFAULT_SPI_TIMEOUT 60000 /* 1 minute */
+
+/**
+* Parser class for parsing AT commands
+*
+* Here are some examples:
+* @code
+* ATParser at = ATParser(serial, "\r\n");
+* int value;
+* char buffer[100];
+*
+* at.send("AT") && at.recv("OK");
+* at.send("AT+CWMODE=%d", 3) && at.recv("OK");
+* at.send("AT+CWMODE?") && at.recv("+CWMODE:%d\r\nOK", &value);
+* at.recv("+IPD,%d:", &value);
+* at.read(buffer, value);
+* at.recv("OK");
+* @endcode
+*/
+class ATParser {
+private:
+    // Serial information
+    BufferedSpi *_serial_spi;
+    int _buffer_size;
+    char *_buffer;
+    Mutex _bufferMutex;
+
+    // Parsing information
+    const char *_delimiter;
+    int _delim_size;
+    char _in_prev;
+    volatile bool _aborted;
+
+    struct oob {
+        unsigned len;
+        const char *prefix;
+        mbed::Callback<void()> cb;
+        oob *next;
+    };
+    oob *_oobs;
+
+public:
+    /**
+    * Constructor
+    *
+    * @param serial spi interface to use for AT commands
+    * @param buffer_size size of internal buffer for transaction
+    * @param timeout timeout of the connection
+    * @param delimiter string of characters to use as line delimiters
+    */
+    ATParser(BufferedSpi &serial_spi, const char *delimiter = "\r\n", int buffer_size = 1440, int timeout = DEFAULT_SPI_TIMEOUT);
+
+    /**
+    * Destructor
+    */
+    ~ATParser()
+    {
+        while (_oobs) {
+            struct oob *oob = _oobs;
+            _oobs = oob->next;
+            delete oob;
+        }
+        delete[] _buffer;
+    }
+
+    /**
+    * Allows timeout to be changed between commands
+    *
+    * @param timeout timeout of the connection
+    */
+    void setTimeout(int timeout)
+    {
+        _serial_spi->setTimeout(timeout);
+    }
+
+    /**
+    * Sets string of characters to use as line delimiters
+    *
+    * @param delimiter string of characters to use as line delimiters
+    */
+    void setDelimiter(const char *delimiter)
+    {
+        _delimiter = delimiter;
+        _delim_size = strlen(delimiter);
+    }
+
+    /**
+     * Sends an AT command
+     *
+     * Sends a formatted command using printf style formatting
+     * @see printf
+     *
+     * @param command printf-like format string of command to send which
+     *                is appended with a newline
+     * @param ... all printf-like arguments to insert into command
+     * @return true only if command is successfully sent
+     */
+    bool send(const char *command, ...);
+
+    bool vsend(const char *command, va_list args);
+
+    /**
+     * Receive an AT response
+     *
+     * Receives a formatted response using scanf style formatting
+     * @see scanf
+     *
+     * Responses are parsed line at a time.
+     * Any received data that does not match the response is ignored until
+     * a timeout occurs.
+     *
+     * @param response scanf-like format string of response to expect
+     * @param ... all scanf-like arguments to extract from response
+     * @return true only if response is successfully matched
+     */
+    bool recv(const char *response, ...);
+    bool vrecv(const char *response, va_list args);
+
+
+    /**
+     * Write a single byte to the underlying stream
+     *
+     * @param c The byte to write
+     * @return The byte that was written or -1 during a timeout
+     */
+    int putc(char c);
+
+    /**
+     * Get a single byte from the underlying stream
+     *
+     * @return The byte that was read or -1 during a timeout
+     */
+    int getc();
+
+    /**
+     * Write an array of bytes to the underlying stream
+     * assuming the header of the command is already in _txbuffer
+     *
+     * @param data the array of bytes to write
+     * @param size_of_data number of bytes in data array
+     * @param size_in_buff number of bytes already in the internal buff
+     * @return number of bytes written or -1 on failure
+     */
+    int write(const char *data, int size_of_data, int size_in_buff);
+
+    /**
+     * Read an array of bytes from the underlying stream
+     *
+     * @param data the destination for the read bytes
+     * @param size number of bytes to read
+     * @return number of bytes read or -1 on failure
+     */
+    int read(char *data);
+
+    /**
+     * Direct printf to underlying stream
+     * @see printf
+     *
+     * @param format format string to pass to printf
+     * @param ... arguments to printf
+     * @return number of bytes written or -1 on failure
+     */
+    int printf(const char *format, ...);
+    int vprintf(const char *format, va_list args);
+
+    /**
+    * Direct scanf on underlying stream
+    * @see ::scanf
+    *
+    * @param format format string to pass to scanf
+    * @param ... arguments to scanf
+    * @return number of bytes read or -1 on failure
+    */
+    int scanf(const char *format, ...);
+
+    int vscanf(const char *format, va_list args);
+
+    /**
+     * Attach a callback for out-of-band data
+     *
+     * @param prefix string on when to initiate callback
+     * @param func callback to call when string is read
+     * @note out-of-band data is only processed during a scanf call
+     */
+    void oob(const char *prefix, mbed::Callback<void()> func);
+
+    /**
+     * Flushes the underlying stream
+     */
+    void flush();
+
+    /**
+     * Abort current recv
+     *
+     * Can be called from oob handler to interrupt the current
+     * recv operation.
+     */
+    void abort();
+
+    /**
+    * Process out-of-band data
+    *
+    * Process out-of-band data in the receive buffer. This function
+    * returns immediately if there is no data to process.
+    *
+    * @return true if oob data processed, false otherwise
+    */
+    bool process_oob(void);
+    /**
+    * Get buffer_size
+    */
+    int get_size(void)
+    {
+        return _buffer_size;
+    }
+
+};
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/network/WIFI_ISM43362/ISM43362/ATParser/BufferedSpi/Buffer/MyBuffer.cpp	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,86 @@
+
+/**
+ * @file    Buffer.cpp
+ * @brief   Software Buffer - Templated Ring Buffer for most data types
+ * @author  sam grove
+ * @version 1.0
+ * @see
+ *
+ * Copyright (c) 2013
+ *
+ * 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 "MyBuffer.h"
+
+template <class T>
+MyBuffer<T>::MyBuffer(uint32_t size)
+{
+    _buf = new T [size];
+    _size = size;
+    clear();
+
+    return;
+}
+
+template <class T>
+MyBuffer<T>::~MyBuffer()
+{
+    delete [] _buf;
+
+    return;
+}
+
+template <class T>
+uint32_t MyBuffer<T>::getSize()
+{
+    return this->_size;
+}
+
+template <class T>
+uint32_t MyBuffer<T>::getNbAvailable()
+{
+    if (_wloc >= _rloc) {
+        return (_wloc - _rloc);
+    } else {
+        return (_size - _rloc + _wloc);
+    }
+}
+
+template <class T>
+void MyBuffer<T>::clear(void)
+{
+    _wloc = 0;
+    _rloc = 0;
+    memset(_buf, 0, _size);
+
+    return;
+}
+
+template <class T>
+uint32_t MyBuffer<T>::peek(char c)
+{
+    return 1;
+}
+
+// make the linker aware of some possible types
+template class MyBuffer<uint8_t>;
+template class MyBuffer<int8_t>;
+template class MyBuffer<uint16_t>;
+template class MyBuffer<int16_t>;
+template class MyBuffer<uint32_t>;
+template class MyBuffer<int32_t>;
+template class MyBuffer<uint64_t>;
+template class MyBuffer<int64_t>;
+template class MyBuffer<char>;
+template class MyBuffer<wchar_t>;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/network/WIFI_ISM43362/ISM43362/ATParser/BufferedSpi/Buffer/MyBuffer.h	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,164 @@
+
+/**
+ * @file    Buffer.h
+ * @brief   Software Buffer - Templated Ring Buffer for most data types
+ * @author  sam grove
+ * @version 1.0
+ * @see
+ *
+ * Copyright (c) 2013
+ *
+ * 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.
+ */
+
+#ifndef MYBUFFER_H
+#define MYBUFFER_H
+
+#include <stdint.h>
+#include <string.h>
+
+/** A templated software ring buffer
+ *
+ * Example:
+ * @code
+ *  #include "mbed.h"
+ *  #include "MyBuffer.h"
+ *
+ *  MyBuffer <char> buf;
+ *
+ *  int main()
+ *  {
+ *      buf = 'a';
+ *      buf.put('b');
+ *      char *head = buf.head();
+ *      puts(head);
+ *
+ *      char whats_in_there[2] = {0};
+ *      int pos = 0;
+ *
+ *      while(buf.available())
+ *      {
+ *          whats_in_there[pos++] = buf;
+ *      }
+ *      printf("%c %c\n", whats_in_there[0], whats_in_there[1]);
+ *      buf.clear();
+ *      error("done\n\n\n");
+ *  }
+ * @endcode
+ */
+
+template <typename T>
+class MyBuffer {
+private:
+    T   *_buf;
+    volatile uint32_t   _wloc;
+    volatile uint32_t   _rloc;
+    uint32_t            _size;
+
+public:
+    /** Create a Buffer and allocate memory for it
+     *  @param size The size of the buffer
+     */
+    MyBuffer(uint32_t size = 0x100);
+
+    /** Get the size of the ring buffer
+     * @return the size of the ring buffer
+     */
+    uint32_t getSize();
+    uint32_t getNbAvailable();
+
+    /** Destry a Buffer and release it's allocated memory
+     */
+    ~MyBuffer();
+
+    /** Add a data element into the buffer
+     *  @param data Something to add to the buffer
+     */
+    void put(T data);
+
+    /** Remove a data element from the buffer
+     *  @return Pull the oldest element from the buffer
+     */
+    T get(void);
+
+    /** Get the address to the head of the buffer
+     *  @return The address of element 0 in the buffer
+     */
+    T *head(void);
+
+    /** Reset the buffer to 0. Useful if using head() to parse packeted data
+     */
+    void clear(void);
+
+    /** Determine if anything is readable in the buffer
+     *  @return 1 if something can be read, 0 otherwise
+     */
+    uint32_t available(void);
+
+    /** Overloaded operator for writing to the buffer
+     *  @param data Something to put in the buffer
+     *  @return
+     */
+    MyBuffer &operator= (T data)
+    {
+        put(data);
+        return *this;
+    }
+
+    /** Overloaded operator for reading from the buffer
+     *  @return Pull the oldest element from the buffer
+     */
+    operator int(void)
+    {
+        return get();
+    }
+
+    uint32_t peek(char c);
+
+};
+
+template <class T>
+inline void MyBuffer<T>::put(T data)
+{
+    _buf[_wloc++] = data;
+    _wloc %= (_size - 1);
+
+    return;
+}
+
+template <class T>
+inline T MyBuffer<T>::get(void)
+{
+    T data_pos = _buf[_rloc++];
+    _rloc %= (_size - 1);
+
+    return data_pos;
+}
+
+template <class T>
+inline T *MyBuffer<T>::head(void)
+{
+    T *data_pos = &_buf[0];
+
+    return data_pos;
+}
+
+template <class T>
+inline uint32_t MyBuffer<T>::available(void)
+{
+    return (_wloc == _rloc) ? 0 : 1;
+    //return 1;
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/network/WIFI_ISM43362/ISM43362/ATParser/BufferedSpi/BufferedPrint.c	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,44 @@
+/*
+ * 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 <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "mbed_error.h"
+
+size_t BufferedSpiThunk(void *buf_serial, const void *s, size_t length);
+
+int BufferedPrintfC(void *stream, int size, const char* format, va_list arg)
+{
+    int r;
+    char buffer[512];
+    if (size >= 512) {
+        return -1;
+    }
+    memset(buffer, 0, size);
+    r = vsprintf(buffer, format, arg);
+    // this may not hit the heap but should alert the user anyways
+    if(r > (int32_t) size) {
+        error("%s %d buffer overwrite (max_buf_size: %d exceeded: %d)!\r\n", __FILE__, __LINE__, size, r);
+        return 0;
+    }
+    if ( r > 0 ) {
+        BufferedSpiThunk(stream, buffer, r);
+    }
+    return r;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/network/WIFI_ISM43362/ISM43362/ATParser/BufferedSpi/BufferedSpi.cpp	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,333 @@
+/**
+ * @file    BufferedSpi.cpp
+ * @brief   Software Buffer - Extends mbed SPI functionallity
+ * @author  Armelle Duboc
+ * @version 1.0
+ * @see
+ *
+ * Copyright (c) STMicroelectronics 2017
+ *
+ * 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 "BufferedSpi.h"
+#include <stdarg.h>
+#include "mbed_debug.h"
+#include "mbed_error.h"
+
+// change to true to add few SPI debug lines
+#define local_debug false
+
+extern "C" int BufferedPrintfC(void *stream, int size, const char *format, va_list arg);
+
+void BufferedSpi::DatareadyRising(void)
+{
+    if (_cmddata_rdy_rising_event == 1) {
+        _cmddata_rdy_rising_event = 0;
+    }
+}
+
+int BufferedSpi::wait_cmddata_rdy_high(void)
+{
+    Timer timer;
+    timer.start();
+
+    /* wait for dataready = 1 */
+    while (dataready.read() == 0) {
+        if (timer.read_ms() > _timeout) {
+            debug_if(local_debug, "ERROR: SPI write timeout\r\n");
+            return -1;
+        }
+    }
+
+    _cmddata_rdy_rising_event = 1;
+
+    return 0;
+}
+
+int BufferedSpi::wait_cmddata_rdy_rising_event(void)
+{
+    Timer timer;
+    timer.start();
+
+    while (_cmddata_rdy_rising_event == 1) {
+        if (timer.read_ms() > _timeout) {
+            _cmddata_rdy_rising_event = 0;
+            if (dataready.read() == 1) {
+                debug_if(local_debug, "ERROR: We missed rising event !! (timemout=%d)\r\n", _timeout);
+            }
+            debug_if(local_debug, "ERROR: SPI read timeout\r\n");
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+BufferedSpi::BufferedSpi(PinName mosi, PinName miso, PinName sclk, PinName _nss, PinName _datareadypin,
+                         uint32_t buf_size, uint32_t tx_multiple, const char *name)
+    : SPI(mosi, miso, sclk, NC), nss(_nss),  _txbuf((uint32_t)(tx_multiple * buf_size)), _rxbuf(buf_size), dataready(_datareadypin)
+{
+    this->_buf_size = buf_size;
+    this->_tx_multiple = tx_multiple;
+    this->_sigio_event = 0;
+
+    _datareadyInt = new InterruptIn(_datareadypin);
+    _datareadyInt->rise(callback(this, &BufferedSpi::DatareadyRising));
+
+    _cmddata_rdy_rising_event = 1;
+
+    return;
+}
+
+BufferedSpi::~BufferedSpi(void)
+{
+
+    return;
+}
+
+void BufferedSpi::frequency(int hz)
+{
+    SPI::frequency(hz);
+}
+
+void BufferedSpi::format(int bits, int mode)
+{
+    SPI::format(bits, mode);
+}
+
+void BufferedSpi::disable_nss()
+{
+    nss = 1;
+    wait_us(15);
+}
+
+void BufferedSpi::enable_nss()
+{
+    nss = 0;
+    wait_us(15);
+}
+
+int BufferedSpi::readable(void)
+{
+    return _rxbuf.available();  // note: look if things are in the buffer
+}
+
+int BufferedSpi::writeable(void)
+{
+    return 1;   // buffer allows overwriting by design, always true
+}
+
+int BufferedSpi::getc(void)
+{
+    if (_rxbuf.available()) {
+        return _rxbuf;
+    } else {
+        return -1;
+    }
+}
+
+int BufferedSpi::putc(int c)
+{
+    _txbuf = (char)c;
+
+    return c;
+}
+
+void BufferedSpi::flush_txbuf(void)
+{
+    _txbuf.clear();
+}
+
+int BufferedSpi::puts(const char *s)
+{
+    if (s != NULL) {
+        const char *ptr = s;
+
+        while (*(ptr) != 0) {
+            _txbuf = *(ptr++);
+        }
+        _txbuf = '\n';  // done per puts definition
+        BufferedSpi::txIrq();                // only write to hardware in one place
+        return (ptr - s) + 1;
+    }
+    return 0;
+}
+
+extern "C" size_t BufferedSpiThunk(void *buf_spi, const void *s, size_t length)
+{
+    BufferedSpi *buffered_spi = (BufferedSpi *)buf_spi;
+    return buffered_spi->buffwrite(s, length);
+}
+
+int BufferedSpi::printf(const char *format, ...)
+{
+    va_list arg;
+    va_start(arg, format);
+    int r = BufferedPrintfC((void *)this, this->_buf_size, format, arg);
+    va_end(arg);
+    return r;
+}
+
+ssize_t BufferedSpi::buffwrite(const void *s, size_t length)
+{
+    /* flush buffer from previous message */
+    this->flush_txbuf();
+
+    if (wait_cmddata_rdy_high() < 0) {
+        debug_if(local_debug, "BufferedSpi::buffwrite timeout (%d)\r\n", _timeout);
+        return -1;
+    }
+
+    this->enable_nss();
+
+    if (s != NULL && length > 0) {
+        /* 1st fill _txbuf */
+        const char *ptr = (const char *)s;
+        const char *end = ptr + length;
+
+        while (ptr != end) {
+            _txbuf = *(ptr++);
+        }
+        if (length & 1) { /* padding to send the last char */
+            _txbuf = '\n';
+            length++;
+        }
+
+        /* 2nd write in SPI */
+        BufferedSpi::txIrq();                // only write to hardware in one place
+
+        this->disable_nss();
+        return ptr - (const char *)s;
+    }
+    this->disable_nss();
+
+    return 0;
+}
+
+ssize_t BufferedSpi::buffsend(size_t length)
+{
+    /* wait for dataready = 1 */
+    if (wait_cmddata_rdy_high() < 0) {
+        debug_if(local_debug, "BufferedSpi::buffsend timeout (%d)\r\n", _timeout);
+        return -1;
+    }
+
+    this->enable_nss();
+
+    /* _txbuffer is already filled with data to send */
+    /* check if _txbuffer needs padding to send the last char */
+    if (length & 1) {
+        _txbuf = '\n';
+        length++;
+    }
+    BufferedSpi::txIrq();                // only write to hardware in one place
+
+    this->disable_nss();
+
+    return length;
+}
+
+ssize_t BufferedSpi::read()
+{
+    return this->read(0);
+}
+
+ssize_t BufferedSpi::read(uint32_t max)
+{
+    uint32_t len = 0;
+    uint8_t FirstRemoved = 1;
+    int tmp;
+
+    disable_nss();
+
+    /* wait for data ready is up */
+    if (wait_cmddata_rdy_rising_event() != 0) {
+        debug_if(local_debug, "BufferedSpi::read timeout (%d)\r\n", _timeout);
+        return -1;
+    }
+
+    enable_nss();
+    while (dataready.read() == 1 && (len < (_buf_size - 2))) {
+        tmp = SPI::write(0xAA);  // dummy write to receive 2 bytes
+
+        if (!((len == 0) && (tmp == 0x0A0D) && (FirstRemoved))) {
+            /* do not take into account the 2 firts \r \n char in the buffer */
+            if ((max == 0) || (len < max)) {
+                _rxbuf = (char)(tmp & 0x00FF);
+                _rxbuf = (char)((tmp >> 8) & 0xFF);
+                len += 2;
+            }
+        } else {
+            FirstRemoved = 0;
+        }
+    }
+    disable_nss();
+
+    if (len >= _buf_size) {
+        debug_if(local_debug, "firmware ERROR ES_WIFI_ERROR_STUFFING_FOREVER\r\n");
+        return -1;
+    }
+
+    debug_if(local_debug, "SPI READ %d BYTES\r\n", len);
+
+    return len;
+}
+
+void BufferedSpi::txIrq(void)
+{
+    /* write everything available in the _txbuffer */
+    int value = 0;
+    int dbg_cnt = 0;
+    while (_txbuf.available() && (_txbuf.getNbAvailable() > 0)) {
+        value = _txbuf.get();
+        if (_txbuf.available() && ((_txbuf.getNbAvailable() % 2) != 0)) {
+            value |= ((_txbuf.get() << 8) & 0XFF00);
+            SPI::write(value);
+            dbg_cnt++;
+        }
+    }
+    debug_if(local_debug, "SPI Sent %d BYTES\r\n", 2 * dbg_cnt);
+    // disable the TX interrupt when there is nothing left to send
+    BufferedSpi::attach(NULL, BufferedSpi::TxIrq);
+    // trigger callback if necessary
+    if (_cbs[TxIrq]) {
+        _cbs[TxIrq]();
+    }
+    return;
+}
+
+void BufferedSpi::prime(void)
+{
+    BufferedSpi::txIrq();                // only write to hardware in one place
+    return;
+}
+
+void BufferedSpi::attach(Callback<void()> func, IrqType type)
+{
+    _cbs[type] = func;
+}
+
+void BufferedSpi::sigio(Callback<void()> func)
+{
+    core_util_critical_section_enter();
+    _sigio_cb = func;
+    if (_sigio_cb) {
+        if (_sigio_event == 1) {
+            _sigio_cb();
+            _sigio_event = 0;
+        }
+    }
+    core_util_critical_section_exit();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/network/WIFI_ISM43362/ISM43362/ATParser/BufferedSpi/BufferedSpi.h	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,234 @@
+
+/**
+ * @file    BufferedSpi.h
+ * @brief   Software Buffer - Extends mbed SPI functionallity
+ * @author  Armelle Duboc
+ * @version 1.0
+ * @see
+ *
+ * Copyright (c) STMicroelectronics 2017
+ *
+ * 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.
+ */
+
+#ifndef BUFFEREDSPI_H
+#define BUFFEREDSPI_H
+
+#include "mbed.h"
+#include "MyBuffer.h"
+
+/** A spi port (SPI) for communication with wifi device
+ *
+ * Can be used for Full Duplex communication, or Simplex by specifying
+ * one pin as NC (Not Connected)
+ *
+ * Example:
+ * @code
+ *  #include "mbed.h"
+ *  #include "BufferedSerial.h"
+ *
+ *  BufferedSerial pc(USBTX, USBRX);
+ *
+ *  int main()
+ *  {
+ *      while(1)
+ *      {
+ *          Timer s;
+ *
+ *          s.start();
+ *          pc.printf("Hello World - buffered\n");
+ *          int buffered_time = s.read_us();
+ *          wait(0.1f); // give time for the buffer to empty
+ *
+ *          s.reset();
+ *          printf("Hello World - blocking\n");
+ *          int polled_time = s.read_us();
+ *          s.stop();
+ *          wait(0.1f); // give time for the buffer to empty
+ *
+ *          pc.printf("printf buffered took %d us\n", buffered_time);
+ *          pc.printf("printf blocking took %d us\n", polled_time);
+ *          wait(0.5f);
+ *      }
+ *  }
+ * @endcode
+ */
+
+/**
+ *  @class BufferedSpi
+ *  @brief Software buffers and interrupt driven tx and rx for Serial
+ */
+class BufferedSpi : public SPI {
+private:
+    DigitalOut    nss;
+    MyBuffer <char> _txbuf;
+    uint32_t      _buf_size;
+    uint32_t      _tx_multiple;
+    volatile int _timeout;
+    void txIrq(void);
+    void prime(void);
+
+    InterruptIn *_datareadyInt;
+    volatile int _cmddata_rdy_rising_event;
+    void DatareadyRising(void);
+    int wait_cmddata_rdy_rising_event(void);
+    int wait_cmddata_rdy_high(void);
+
+
+    Callback<void()> _cbs[2];
+
+    Callback<void()> _sigio_cb;
+    uint8_t          _sigio_event;
+
+public:
+    MyBuffer <char> _rxbuf;
+    DigitalIn dataready;
+    enum IrqType {
+        RxIrq = 0,
+        TxIrq,
+
+        IrqCnt
+    };
+
+    /** Create a BufferedSpi Port, connected to the specified transmit and receive pins
+     *  @param SPI mosi pin
+     *  @param SPI miso pin
+     *  @param SPI sclk pin
+     *  @param SPI nss pin
+     *  @param Dataready pin
+     *  @param buf_size printf() buffer size
+     *  @param tx_multiple amount of max printf() present in the internal ring buffer at one time
+     *  @param name optional name
+    */
+    BufferedSpi(PinName mosi, PinName miso, PinName sclk, PinName nss, PinName datareadypin, uint32_t buf_size = 2500, uint32_t tx_multiple = 1, const char *name = NULL);
+
+    /** Destroy a BufferedSpi Port
+     */
+    virtual ~BufferedSpi(void);
+
+    /** call to SPI frequency Function
+     */
+    virtual void frequency(int hz);
+
+    /** clear the transmit buffer
+     */
+    virtual void flush_txbuf(void);
+
+    /** call to SPI format function
+     */
+    virtual void format(int bits, int mode);
+
+    virtual void enable_nss(void);
+
+    virtual void disable_nss(void);
+
+    /** Check on how many bytes are in the rx buffer
+     *  @return 1 if something exists, 0 otherwise
+     */
+    virtual int readable(void);
+
+    /** Check to see if the tx buffer has room
+     *  @return 1 always has room and can overwrite previous content if too small / slow
+     */
+    virtual int writeable(void);
+
+    /** Get a single byte from the BufferedSpi Port.
+     *  Should check readable() before calling this.
+     *  @return A byte that came in on the SPI Port
+     */
+    virtual int getc(void);
+
+    /** Write a single byte to the BufferedSpi Port.
+     *  @param c The byte to write to the SPI Port
+     *  @return The byte that was written to the SPI Port Buffer
+     */
+    virtual int putc(int c);
+
+    /** Write a string to the BufferedSpi Port. Must be NULL terminated
+     *  @param s The string to write to the Spi Port
+     *  @return The number of bytes written to the Spi Port Buffer
+     */
+    virtual int puts(const char *s);
+
+    /** Write a formatted string to the BufferedSpi Port.
+     *  @param format The string + format specifiers to write to the Spi Port
+     *  @return The number of bytes written to the Spi Port Buffer
+     */
+    virtual int printf(const char *format, ...);
+
+    /** Write data to the Buffered Spi Port
+     *  @param s A pointer to data to send
+     *  @param length The amount of data being pointed to
+     *  @return The number of bytes written to the Spi Port Buffer
+     */
+    virtual ssize_t buffwrite(const void *s, std::size_t length);
+
+    /** Send datas to the Spi port that are already present
+     *  in the internal _txbuffer
+     *  @param length
+     *  @return the number of bytes written on the SPI port
+     */
+    virtual ssize_t buffsend(size_t length);
+
+    /** Read data from the Spi Port to the _rxbuf
+     *  @param max: optional. = max sieze of the input read
+     *  @return The number of bytes read from the SPI port and written to the _rxbuf
+     */
+    virtual ssize_t read();
+    virtual ssize_t read(uint32_t max);
+
+    /**
+    * Allows timeout to be changed between commands
+    *
+    * @param timeout timeout of the connection in ms
+    */
+    void setTimeout(int timeout)
+    {
+        /*  this is a safe guard timeout at SPI level in case module is stuck */
+        _timeout = timeout;
+    }
+
+    /** Register a callback once any data is ready for sockets
+     *  @param func     Function to call on state change
+     */
+    virtual void sigio(Callback<void()> func);
+
+    /** Attach a function to call whenever a serial interrupt is generated
+     *  @param func A pointer to a void function, or 0 to set as none
+     *  @param type Which serial interrupt to attach the member function to (Serial::RxIrq for receive, TxIrq for transmit buffer empty)
+     */
+    virtual void attach(Callback<void()> func, IrqType type = RxIrq);
+
+    /** Attach a member function to call whenever a serial interrupt is generated
+     *  @param obj pointer to the object to call the member function on
+     *  @param method pointer to the member function to call
+     *  @param type Which serial interrupt to attach the member function to (Serial::RxIrq for receive, TxIrq for transmit buffer empty)
+     */
+    template <typename T>
+    void attach(T *obj, void (T::*method)(), IrqType type = RxIrq)
+    {
+        attach(Callback<void()>(obj, method), type);
+    }
+
+    /** Attach a member function to call whenever a serial interrupt is generated
+     *  @param obj pointer to the object to call the member function on
+     *  @param method pointer to the member function to call
+     *  @param type Which serial interrupt to attach the member function to (Serial::RxIrq for receive, TxIrq for transmit buffer empty)
+     */
+    template <typename T>
+    void attach(T *obj, void (*method)(T *), IrqType type = RxIrq)
+    {
+        attach(Callback<void()>(obj, method), type);
+    }
+};
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/network/WIFI_ISM43362/ISM43362/ISM43362.cpp	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,699 @@
+/* ISM43362 Example
+*
+* Copyright (c) STMicroelectronics 2018
+ *
+ * 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 <string.h>
+#include "ISM43362.h"
+#include "mbed_debug.h"
+
+// activate / de-activate debug
+#define ism_debug 0
+
+ISM43362::ISM43362(PinName mosi, PinName miso, PinName sclk, PinName nss, PinName resetpin, PinName datareadypin, PinName wakeup, bool debug)
+    : _bufferspi(mosi, miso, sclk, nss, datareadypin),
+      _parser(_bufferspi),
+      _resetpin(resetpin),
+      _packets(0), _packets_end(&_packets)
+{
+    DigitalOut wakeup_pin(wakeup);
+    _bufferspi.format(16, 0); /* 16bits, ploarity low, phase 1Edge, master mode */
+    _bufferspi.frequency(20000000); /* up to 20 MHz */
+    _active_id = 0xFF;
+    _FwVersionId = 0;
+
+    _ism_debug = debug || ism_debug;
+    reset();
+}
+
+/**
+  * @brief  Parses and returns number from string.
+  * @param  ptr: pointer to string
+  * @param  cnt: pointer to the number of parsed digit
+  * @retval integer value.
+  */
+#define CHARISHEXNUM(x)                 (((x) >= '0' && (x) <= '9') || \
+                                         ((x) >= 'a' && (x) <= 'f') || \
+                                         ((x) >= 'A' && (x) <= 'F'))
+#define CHARISNUM(x)                    ((x) >= '0' && (x) <= '9')
+#define CHAR2NUM(x)                     ((x) - '0')
+
+
+extern "C" int32_t ParseNumber(char *ptr, uint8_t *cnt)
+{
+    uint8_t minus = 0, i = 0;
+    int32_t sum = 0;
+
+    if (*ptr == '-') {                                      /* Check for minus character */
+        minus = 1;
+        ptr++;
+        i++;
+    }
+    if (*ptr == 'C') {  /* input string from get_firmware_version is Cx.x.x.x */
+        ptr++;
+    }
+
+    while (CHARISNUM(*ptr) || (*ptr == '.')) { /* Parse number */
+        if (*ptr == '.') {
+            ptr++; // next char
+        } else {
+            sum = 10 * sum + CHAR2NUM(*ptr);
+            ptr++;
+            i++;
+        }
+    }
+
+    if (cnt != NULL) {                   /* Save number of characters used for number */
+        *cnt = i;
+    }
+    if (minus) {                         /* Minus detected */
+        return 0 - sum;
+    }
+    return sum;                          /* Return number */
+}
+
+uint32_t ISM43362::get_firmware_version(void)
+{
+    char tmp_buffer[250];
+    char *ptr, *ptr2;
+    char _fw_version[16];
+
+    /* Use %[^\n] instead of %s to allow having spaces in the string */
+    if (!(_parser.send("I?") && _parser.recv("%[^\n^\r]\r\n", tmp_buffer) && check_response())) {
+        debug_if(_ism_debug, "ISM43362: get_firmware_version is FAIL\r\n");
+        return 0;
+    }
+    debug_if(_ism_debug, "ISM43362: get_firmware_version = %s\r\n", tmp_buffer);
+
+    // Get the first version in the string
+    ptr = strtok((char *)tmp_buffer, ",");
+    ptr = strtok(NULL, ",");
+    ptr2 = strtok(NULL, ",");
+    if (ptr == NULL) {
+        debug_if(_ism_debug, "ISM43362: get_firmware_version decoding is FAIL\r\n");
+        return 0;
+    }
+    strncpy(_fw_version, ptr, ptr2 - ptr);
+    _FwVersionId = ParseNumber(_fw_version, NULL);
+
+    return _FwVersionId;
+}
+
+bool ISM43362::reset(void)
+{
+    char tmp_buffer[100];
+    debug_if(_ism_debug, "ISM43362: Reset Module\r\n");
+    _resetpin = 0;
+    wait_ms(10);
+    _resetpin = 1;
+    wait_ms(500);
+
+    /* Wait for prompt line : the string is "> ". */
+    /* As the space char is not detected by sscanf function in parser.recv, */
+    /* we need to use %[\n] */
+    if (!_parser.recv(">%[^\n]", tmp_buffer)) {
+        debug_if(_ism_debug, "ISM43362: Reset Module failed\r\n");
+        return false;
+    }
+    return true;
+}
+
+void ISM43362::print_rx_buff(void)
+{
+    char tmp[150] = {0};
+    uint16_t i = 0;
+    debug_if(_ism_debug, "ISM43362: ");
+    while (i  < 150) {
+        int c = _parser.getc();
+        if (c < 0) {
+            break;
+        }
+        tmp[i] = c;
+        debug_if(_ism_debug, "0x%2X ", c);
+        i++;
+    }
+    debug_if(_ism_debug, "\n");
+    debug_if(_ism_debug, "ISM43362: Buffer content =====%s=====\r\n", tmp);
+}
+
+/*  checks the standard OK response of the WIFI module, shouldbe:
+ *  \r\nDATA\r\nOK\r\n>sp
+ *  or
+ *  \r\nERROR\r\nUSAGE\r\n>sp
+ *  function returns true if OK, false otherwise. In case of error,
+ *  print error content then flush buffer */
+bool ISM43362::check_response(void)
+{
+    char tmp_buffer[100];
+    if (!_parser.recv("OK\r\n")) {
+        print_rx_buff();
+        _parser.flush();
+        return false;
+    }
+
+    /*  Then we should get the prompt: "> " */
+    /* As the space char is not detected by sscanf function in parser.recv, */
+    /* we need to use %[\n] */
+    if (!_parser.recv(">%[^\n]", tmp_buffer)) {
+        debug_if(_ism_debug, "ISM43362: Missing prompt in WIFI resp\r\n");
+        print_rx_buff();
+        _parser.flush();
+        return false;
+    }
+
+    /*  Inventek module do stuffing / padding of data with 0x15,
+     *  in case buffer contains such */
+    while (1) {
+        int c = _parser.getc();
+        if (c == 0x15) {
+            // debug_if(_ism_debug, "ISM43362: Flush char 0x%x\n", c);
+            continue;
+        } else {
+            /*  How to put it back if needed ? */
+            break;
+        }
+    }
+    return true;
+}
+
+bool ISM43362::dhcp(bool enabled)
+{
+    return (_parser.send("C4=%d", enabled ? 1 : 0) && check_response());
+}
+
+int ISM43362::connect(const char *ap, const char *passPhrase, ism_security_t ap_sec)
+{
+    char tmp[256];
+
+    if (!(_parser.send("C1=%s", ap) && check_response())) {
+        return NSAPI_ERROR_PARAMETER;
+    }
+
+    if (!(_parser.send("C2=%s", passPhrase) && check_response())) {
+        return NSAPI_ERROR_PARAMETER;
+    }
+
+    /* Check security level is acceptable */
+    if (ap_sec > ISM_SECURITY_WPA_WPA2) {
+        debug_if(_ism_debug, "ISM43362: Unsupported security level %d\n", ap_sec);
+        return NSAPI_ERROR_UNSUPPORTED;
+    }
+
+    if (!(_parser.send("C3=%d", ap_sec) && check_response())) {
+        return NSAPI_ERROR_PARAMETER;
+    }
+
+    if (_parser.send("C0")) {
+        while (_parser.recv("%[^\n]\n", tmp)) {
+            if (strstr(tmp, "OK")) {
+                _parser.flush();
+                return NSAPI_ERROR_OK;
+            }
+            if (strstr(tmp, "JOIN")) {
+                if (strstr(tmp, "Failed")) {
+                    _parser.flush();
+                    return NSAPI_ERROR_AUTH_FAILURE;
+                }
+            }
+        }
+    }
+
+    return NSAPI_ERROR_NO_CONNECTION;
+}
+
+bool ISM43362::disconnect(void)
+{
+    return (_parser.send("CD") && check_response());
+}
+
+const char *ISM43362::getIPAddress(void)
+{
+    char tmp_ip_buffer[250];
+    char *ptr, *ptr2;
+
+    /* Use %[^\n] instead of %s to allow having spaces in the string */
+    if (!(_parser.send("C?")
+            && _parser.recv("%[^\n^\r]\r\n", tmp_ip_buffer)
+            && check_response())) {
+        debug_if(_ism_debug, "ISM43362: getIPAddress LINE KO: %s\n", tmp_ip_buffer);
+        return 0;
+    }
+
+    /* Get the IP address in the result */
+    /* TODO : check if the begining of the string is always = "eS-WiFi_AP_C47F51011231," */
+    ptr = strtok((char *)tmp_ip_buffer, ",");
+    ptr = strtok(NULL, ",");
+    ptr = strtok(NULL, ",");
+    ptr = strtok(NULL, ",");
+    ptr = strtok(NULL, ",");
+    ptr = strtok(NULL, ",");
+    ptr2 = strtok(NULL, ",");
+    if (ptr == NULL) {
+        return 0;
+    }
+    strncpy(_ip_buffer, ptr, ptr2 - ptr);
+
+    tmp_ip_buffer[59] = 0;
+    debug_if(_ism_debug, "ISM43362: receivedIPAddress: %s\n", _ip_buffer);
+
+    return _ip_buffer;
+}
+
+const char *ISM43362::getMACAddress(void)
+{
+    if (!(_parser.send("Z5") && _parser.recv("%s\r\n", _mac_buffer) && check_response())) {
+        debug_if(_ism_debug, "ISM43362: receivedMacAddress LINE KO: %s\n", _mac_buffer);
+        return 0;
+    }
+
+    debug_if(_ism_debug, "ISM43362: receivedMacAddress:%s, size=%d\r\n", _mac_buffer, sizeof(_mac_buffer));
+
+    return _mac_buffer;
+}
+
+const char *ISM43362::getGateway()
+{
+    char tmp[250];
+    /* Use %[^\n] instead of %s to allow having spaces in the string */
+    if (!(_parser.send("C?") && _parser.recv("%[^\n^\r]\r\n", tmp) && check_response())) {
+        debug_if(_ism_debug, "ISM43362: getGateway LINE KO: %s\r\n", tmp);
+        return 0;
+    }
+
+    /* Extract the Gateway in the received buffer */
+    char *ptr;
+    ptr = strtok(tmp, ",");
+    for (int i = 0; i < 7; i++) {
+        if (ptr == NULL) {
+            break;
+        }
+        ptr = strtok(NULL, ",");
+    }
+
+    strncpy(_gateway_buffer, ptr, sizeof(_gateway_buffer));
+
+    debug_if(_ism_debug, "ISM43362: getGateway: %s\r\n", _gateway_buffer);
+
+    return _gateway_buffer;
+}
+
+const char *ISM43362::getNetmask()
+{
+    char tmp[250];
+    /* Use %[^\n] instead of %s to allow having spaces in the string */
+    if (!(_parser.send("C?") && _parser.recv("%[^\n^\r]\r\n", tmp) && check_response())) {
+        debug_if(_ism_debug, "ISM43362: getNetmask LINE KO: %s\n", tmp);
+        return 0;
+    }
+
+    /* Extract Netmask in the received buffer */
+    char *ptr;
+    ptr = strtok(tmp, ",");
+    for (int i = 0; i < 6; i++) {
+        if (ptr == NULL) {
+            break;
+        }
+        ptr = strtok(NULL, ",");
+    }
+
+    strncpy(_netmask_buffer, ptr, sizeof(_netmask_buffer));
+
+    debug_if(_ism_debug, "ISM43362: getNetmask: %s\r\n", _netmask_buffer);
+
+    return _netmask_buffer;
+}
+
+int8_t ISM43362::getRSSI()
+{
+    int8_t rssi;
+    char tmp[25];
+
+    if (!(_parser.send("CR") && _parser.recv("%s\r\n", tmp) && check_response())) {
+        debug_if(_ism_debug, "ISM43362: getRSSI LINE KO: %s\r\n", tmp);
+        return 0;
+    }
+
+    rssi = ParseNumber(tmp, NULL);
+
+    debug_if(_ism_debug, "ISM43362: getRSSI: %d\r\n", rssi);
+
+    return rssi;
+}
+/**
+  * @brief  Parses Security type.
+  * @param  ptr: pointer to string
+  * @retval Encryption type.
+  */
+extern "C" nsapi_security_t ParseSecurity(char *ptr)
+{
+    if (strstr(ptr, "Open")) {
+        return NSAPI_SECURITY_NONE;
+    } else if (strstr(ptr, "WEP")) {
+        return NSAPI_SECURITY_WEP;
+    } else if (strstr(ptr, "WPA2 AES")) {
+        return NSAPI_SECURITY_WPA2;
+    } else if (strstr(ptr, "WPA WPA2")) {
+        return NSAPI_SECURITY_WPA_WPA2;
+    } else if (strstr(ptr, "WPA2 TKIP")) {
+        return NSAPI_SECURITY_UNKNOWN;    // no match in mbed
+    } else if (strstr(ptr, "WPA2")) {
+        return NSAPI_SECURITY_WPA2;    // catch any other WPA2 formula
+    } else if (strstr(ptr, "WPA")) {
+        return NSAPI_SECURITY_WPA;
+    } else {
+        return NSAPI_SECURITY_UNKNOWN;
+    }
+}
+
+/**
+  * @brief  Convert char in Hex format to integer.
+  * @param  a: character to convert
+  * @retval integer value.
+  */
+extern "C"  uint8_t Hex2Num(char a)
+{
+    if (a >= '0' && a <= '9') {                             /* Char is num */
+        return a - '0';
+    } else if (a >= 'a' && a <= 'f') {                      /* Char is lowercase character A - Z (hex) */
+        return (a - 'a') + 10;
+    } else if (a >= 'A' && a <= 'F') {                      /* Char is uppercase character A - Z (hex) */
+        return (a - 'A') + 10;
+    }
+
+    return 0;
+}
+
+/**
+  * @brief  Extract a hex number from a string.
+  * @param  ptr: pointer to string
+  * @param  cnt: pointer to the number of parsed digit
+  * @retval Hex value.
+  */
+extern "C" uint32_t ParseHexNumber(char *ptr, uint8_t *cnt)
+{
+    uint32_t sum = 0;
+    uint8_t i = 0;
+
+    while (CHARISHEXNUM(*ptr)) {         /* Parse number */
+        sum <<= 4;
+        sum += Hex2Num(*ptr);
+        ptr++;
+        i++;
+    }
+
+    if (cnt != NULL) {                  /* Save number of characters used for number */
+        *cnt = i;
+    }
+    return sum;                         /* Return number */
+}
+
+bool ISM43362::isConnected(void)
+{
+    return getIPAddress() != 0;
+}
+
+int ISM43362::scan(WiFiAccessPoint *res, unsigned limit)
+{
+    unsigned cnt = 0, num = 0;
+    char *ptr;
+    char tmp[256];
+
+    if (!(_parser.send("F0"))) {
+        debug_if(_ism_debug, "ISM43362: scan error\r\n");
+        return 0;
+    }
+
+    /* Parse the received buffer and fill AP buffer */
+    /* Use %[^\n] instead of %s to allow having spaces in the string */
+    while (_parser.recv("#%[^\n]\n", tmp)) {
+        if (limit != 0 && cnt >= limit) {
+            /* reached end */
+            break;
+        }
+        nsapi_wifi_ap_t ap = {0};
+        debug_if(_ism_debug, "ISM43362: received:%s\n", tmp);
+        ptr = strtok(tmp, ",");
+        num = 0;
+        while (ptr != NULL) {
+            switch (num++) {
+                case 0: /* Ignore index */
+                case 4: /* Ignore Max Rate */
+                case 5: /* Ignore Network Type */
+                case 7: /* Ignore Radio Band */
+                    break;
+                case 1:
+                    ptr[strlen(ptr) - 1] = 0;
+                    strncpy((char *)ap.ssid,  ptr + 1, 32);
+                    break;
+                case 2:
+                    for (int i = 0; i < 6; i++) {
+                        ap.bssid[i] = ParseHexNumber(ptr + (i * 3), NULL);
+                    }
+                    break;
+                case 3:
+                    ap.rssi = ParseNumber(ptr, NULL);
+                    break;
+                case 6:
+                    ap.security = ParseSecurity(ptr);
+                    break;
+                case 8:
+                    ap.channel = ParseNumber(ptr, NULL);
+                    num = 1;
+                    break;
+                default:
+                    break;
+            }
+            ptr = strtok(NULL, ",");
+        }
+        if (res != NULL) {
+            res[cnt] = WiFiAccessPoint(ap);
+        }
+        cnt++;
+    }
+
+    /* We may stop before having read all the APs list, so flush the rest of
+     * it as well as OK commands */
+    _parser.flush();
+
+    debug_if(_ism_debug, "ISM43362: End of Scan: cnt=%d\n", cnt);
+
+    return cnt;
+
+}
+
+bool ISM43362::open(const char *type, int id, const char *addr, int port)
+{
+    /* TODO : This is the implementation for the client socket, need to check if need to create openserver too */
+    //IDs only 0-3
+    if ((id < 0) || (id > 3)) {
+        debug_if(_ism_debug, "ISM43362: open: wrong id\n");
+        return false;
+    }
+    /* Set communication socket */
+    _active_id = id;
+    if (!(_parser.send("P0=%d", id) && check_response())) {
+        debug_if(_ism_debug, "ISM43362: open: P0 issue\n");
+        return false;
+    }
+    /* Set protocol */
+    if (!(_parser.send("P1=%s", type) && check_response())) {
+        debug_if(_ism_debug, "ISM43362: open: P1 issue\n");
+        return false;
+    }
+    /* Set address */
+    if (!(_parser.send("P3=%s", addr) && check_response())) {
+        debug_if(_ism_debug, "ISM43362: open: P3 issue\n");
+        return false;
+    }
+    if (!(_parser.send("P4=%d", port) && check_response())) {
+        debug_if(_ism_debug, "ISM43362: open: P4 issue\n");
+        return false;
+    }
+    /* Start client */
+    if (!(_parser.send("P6=1") && check_response())) {
+        debug_if(_ism_debug, "ISM43362: open: P6 issue\n");
+        return false;
+    }
+
+    /* request as much data as possible - i.e. module max size */
+    if (!(_parser.send("R1=%d", ES_WIFI_MAX_RX_PACKET_SIZE) && check_response())) {
+        debug_if(_ism_debug, "ISM43362: open: R1 issue\n");
+        return -1;
+    }
+
+    /* Non blocking mode : set Read Transport Timeout to 1ms */
+    if (!(_parser.send("R2=1") && check_response())) {
+        debug_if(_ism_debug, "ISM43362: open: R2 issue\n");
+        return -1;
+    }
+
+    debug_if(_ism_debug, "ISM43362: open ok with id %d type %s addr %s port %d\n", id, type, addr, port);
+
+    return true;
+}
+
+bool ISM43362::dns_lookup(const char *name, char *ip)
+{
+    char tmp[30];
+
+    if (!(_parser.send("D0=%s", name) && _parser.recv("%s\r\n", tmp)
+            && check_response())) {
+        debug_if(_ism_debug, "ISM43362 dns_lookup: D0 issue: %s\n", tmp);
+        return 0;
+    }
+
+    strncpy(ip, tmp, sizeof(tmp));
+
+    debug_if(_ism_debug, "ISM43362 dns_lookup: %s ok\n", ip);
+    return 1;
+}
+
+bool ISM43362::send(int id, const void *data, uint32_t amount)
+{
+    // The Size limit has to be checked on caller side.
+    if (amount > ES_WIFI_MAX_TX_PACKET_SIZE) {
+        debug_if(_ism_debug, "ISM43362 send: max issue\n");
+        return false;
+    }
+
+    /* Activate the socket id in the wifi module */
+    if ((id < 0) || (id > 3)) {
+        return false;
+    }
+    if (_active_id != id) {
+        _active_id = id;
+        if (!(_parser.send("P0=%d", id) && check_response())) {
+            debug_if(_ism_debug, "ISM43362 send: P0 issue\n");
+            return false;
+        }
+    }
+
+    /* set Write Transport Packet Size */
+    int i = _parser.printf("S3=%d\r", (int)amount);
+    if (i < 0) {
+        debug_if(_ism_debug, "ISM43362 send: S3 issue\n");
+        return false;
+    }
+    i = _parser.write((const char *)data, amount, i);
+    if (i < 0) {
+        return false;
+    }
+
+    if (!check_response()) {
+        return false;
+    }
+
+    debug_if(_ism_debug, "ISM43362 send: id %d amount %d\n", id, amount);
+    return true;
+}
+
+int ISM43362::check_recv_status(int id, void *data)
+{
+    int read_amount;
+
+    debug_if(_ism_debug, "ISM43362 check_recv_status: id %d\r\n", id);
+
+    /* Activate the socket id in the wifi module */
+    if ((id < 0) || (id > 3)) {
+        debug_if(_ism_debug, "ISM43362 check_recv_status: ERROR with id %d\r\n", id);
+        return -1;
+    }
+
+    if (_active_id != id) {
+        _active_id = id;
+        if (!(_parser.send("P0=%d", id) && check_response())) {
+            return -1;
+        }
+    }
+
+
+    if (!_parser.send("R0")) {
+        return -1;
+    }
+    read_amount = _parser.read((char *)data);
+
+    if (read_amount < 0) {
+        debug_if(_ism_debug, "ISM43362 check_recv_status: ERROR in data RECV, timeout?\r\n");
+        return -1; /* nothing to read */
+    }
+
+    /*  If there are spurious 0x15 at the end of the data, this is an error
+     *  we hall can get rid off of them :-(
+     *  This should not happen, but let's try to clean-up anyway
+     */
+    char *cleanup = (char *) data;
+    while ((read_amount > 0) && (cleanup[read_amount - 1] == 0x15)) {
+        // debug_if(_ism_debug, "ISM43362 check_recv_status: spurious 0X15 trashed\r\n");
+        /* Remove the trailling char then search again */
+        read_amount--;
+    }
+
+    if ((read_amount >= 6) && (strncmp("OK\r\n> ", (char *)data, 6) == 0)) {
+        // debug_if(_ism_debug, "ISM43362 check_recv_status: recv 2 nothing to read=%d\r\n", read_amount);
+        // read_amount -= 6;
+        return 0; /* nothing to read */
+    } else if ((read_amount >= 8) && (strncmp((char *)((uint32_t) data + read_amount - 8), "\r\nOK\r\n> ", 8)) == 0) {
+        /* bypass ""\r\nOK\r\n> " if present at the end of the chain */
+        read_amount -= 8;
+    } else {
+        debug_if(_ism_debug, "ISM43362 check_recv_status: ERROR, flushing %d bytes: ", read_amount);
+        // for (int i = 0; i < read_amount; i++) {
+        //      debug_if(_ism_debug, "%2X ", cleanup[i]);
+        // }
+        // debug_if(_ism_debug, "\r\n (ASCII)", cleanup);
+        cleanup[read_amount] = 0;
+        debug_if(_ism_debug, "%s\r\n", cleanup);
+        return -1; /* nothing to read */
+    }
+
+    debug_if(_ism_debug, "ISM43362 check_recv_status: id %d read_amount=%d\r\n", id, read_amount);
+    return read_amount;
+}
+
+bool ISM43362::close(int id)
+{
+    if ((id < 0) || (id > 3)) {
+        debug_if(_ism_debug, "ISM43362: Wrong socket number\n");
+        return false;
+    }
+    /* Set connection on this socket */
+    debug_if(_ism_debug, "ISM43362: CLOSE socket id=%d\n", id);
+    _active_id = id;
+    if (!(_parser.send("P0=%d", id) && check_response())) {
+        return false;
+    }
+    /* close this socket */
+    if (!(_parser.send("P6=0") && check_response())) {
+        return false;
+    }
+    return true;
+}
+
+bool ISM43362::readable()
+{
+    /* not applicable with SPI api */
+    return true;
+}
+
+bool ISM43362::writeable()
+{
+    /* not applicable with SPI api */
+    return true;
+}
+
+void ISM43362::attach(Callback<void()> func)
+{
+    /* not applicable with SPI api */
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/network/WIFI_ISM43362/ISM43362/ISM43362.h	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,250 @@
+/* ISM43362Interface Example
+ * Copyright (c) STMicroelectronics 2017
+ *
+ * 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.
+ */
+
+#ifndef ISM43362_H
+#define ISM43362_H
+#include "ATParser.h"
+
+#define ES_WIFI_MAX_SSID_NAME_SIZE                  32
+#define ES_WIFI_MAX_PSWD_NAME_SIZE                  32
+#define ES_WIFI_PRODUCT_ID_SIZE                     32
+#define ES_WIFI_PRODUCT_NAME_SIZE                   32
+#define ES_WIFI_FW_REV_SIZE                         16
+#define ES_WIFI_API_REV_SIZE                        16
+#define ES_WIFI_STACK_REV_SIZE                      16
+#define ES_WIFI_RTOS_REV_SIZE                       16
+
+// The input range for AT Command 'R1' is 0 to 1200 bytes
+// 'R1' Set Read Transport Packet Size (bytes)
+#define ES_WIFI_MAX_RX_PACKET_SIZE                     1200
+// Module maxume DATA payload for Tx packet is 1460
+#define ES_WIFI_MAX_TX_PACKET_SIZE                     1460
+typedef enum ism_security {
+    ISM_SECURITY_NONE         = 0x0,      /*!< open access point */
+    ISM_SECURITY_WEP          = 0x1,      /*!< phrase conforms to WEP */
+    ISM_SECURITY_WPA          = 0x2,      /*!< phrase conforms to WPA */
+    ISM_SECURITY_WPA2         = 0x3,      /*!< phrase conforms to WPA2 */
+    ISM_SECURITY_WPA_WPA2     = 0x4,      /*!< phrase conforms to WPA/WPA2 */
+    ISM_SECURITY_UNKNOWN      = 0xFF,     /*!< unknown/unsupported security in scan results */
+} ism_security_t;
+
+extern "C" int32_t ParseNumber(char *ptr, uint8_t *cnt);
+
+/** ISM43362Interface class.
+    This is an interface to a ISM43362 radio.
+ */
+class ISM43362 {
+public:
+    ISM43362(PinName mosi, PinName miso, PinName clk, PinName nss, PinName resetpin, PinName datareadypin, PinName wakeup, bool debug = false);
+
+    /**
+    * Check firmware version of ISM43362
+    *
+    * @return fw version or null if no version is read
+    */
+    uint32_t get_firmware_version(void);
+
+    /**
+    * Reset ISM43362
+    *
+    * @return true only if ISM43362 resets successfully
+    */
+    bool reset(void);
+
+    /**
+    * Enable/Disable DHCP
+    *
+    * @param enabled DHCP enabled when true
+    * @return true only if ISM43362 enables/disables DHCP successfully
+    */
+    bool dhcp(bool enabled);
+
+    /**
+    * Connect ISM43362 to AP
+    *
+    * @param ap the name of the AP
+    * @param passPhrase the password of AP
+    * @param ap_sec the security level of network AP
+    * @return nsapi_error enum
+    */
+    int connect(const char *ap, const char *passPhrase, ism_security_t ap_sec);
+
+    /**
+    * Disconnect ISM43362 from AP
+    *
+    * @return true only if ISM43362 is disconnected successfully
+    */
+    bool disconnect(void);
+
+    /**
+    * Get the IP address of ISM43362
+    *
+    * @return null-teriminated IP address or null if no IP address is assigned
+    */
+    const char *getIPAddress(void);
+
+    /**
+    * Get the MAC address of ISM43362
+    *
+    * @return null-terminated MAC address or null if no MAC address is assigned
+    */
+    const char *getMACAddress(void);
+
+    /** Get the local gateway
+    *
+    *  @return         Null-terminated representation of the local gateway
+    *                  or null if no network mask has been recieved
+    */
+    const char *getGateway();
+
+    /** Get the local network mask
+     *
+     *  @return         Null-terminated representation of the local network mask
+     *                  or null if no network mask has been recieved
+     */
+    const char *getNetmask();
+
+    /* Return RSSI for active connection
+     *
+     * @return      Measured RSSI
+     */
+    int8_t getRSSI();
+
+    /**
+    * Check if ISM43362 is conenected
+    *
+    * @return true only if the chip has an IP address
+    */
+    bool isConnected(void);
+
+    /** Scan for available networks
+     *
+     * @param  ap    Pointer to allocated array to store discovered AP
+     * @param  limit Size of allocated @a res array, or 0 to only count available AP
+     * @return       Number of entries in @a res, or if @a count was 0 number of available networks, negative on error
+     *               see @a nsapi_error
+     */
+    int scan(WiFiAccessPoint *res, unsigned limit);
+
+    /**Perform a dns query
+    *
+    * @param name Hostname to resolve
+    * @param ip   Buffer to store IP address
+    * @return 0 true on success, false on failure
+    */
+    bool dns_lookup(const char *name, char *ip);
+
+    /**
+    * Open a socketed connection
+    *
+    * @param type the type of socket to open "UDP" or "TCP"
+    * @param id id to give the new socket, valid 0-4
+    * @param port port to open connection with
+    * @param addr the IP address of the destination
+    * @return true only if socket opened successfully
+    */
+    bool open(const char *type, int id, const char *addr, int port);
+
+    /**
+    * Sends data to an open socket
+    *
+    * @param id id of socket to send to
+    * @param data data to be sent
+    * @param amount amount of data to be sent - max 1024
+    * @return true only if data sent successfully
+    */
+    bool send(int id, const void *data, uint32_t amount);
+
+    /**
+    * Receives data from an open socket
+    *
+    * @param id id to receive from
+    * @param data placeholder for returned information
+    * @param amount number of bytes to be received
+    * @return the number of bytes received
+    */
+    int32_t recv(int id, void *data, uint32_t amount);
+
+    /**
+    * Closes a socket
+    *
+    * @param id id of socket to close, valid only 0-4
+    * @return true only if socket is closed successfully
+    */
+    bool close(int id);
+
+    /**
+    * Checks if data is available
+    */
+    bool readable();
+
+    /**
+    * Checks if data can be written
+    */
+    bool writeable();
+
+    /**
+    * Attach a function to call whenever network state has changed
+    *
+    * @param func A pointer to a void function, or 0 to set as none
+    */
+    void attach(Callback<void()> func);
+
+    /**
+    * Check is datas are available to read for a socket
+    * @param id socket id
+    * @param data placeholder for returned information
+    * @param amount size to read for the check
+    * @return amount of read value, or -1 for errors
+    */
+    int check_recv_status(int id, void *data);
+
+    /**
+    * Attach a function to call whenever network state has changed
+    *
+    * @param obj pointer to the object to call the member function on
+    * @param method pointer to the member function to call
+    */
+    template <typename T, typename M>
+    void attach(T *obj, M method)
+    {
+        attach(Callback<void()>(obj, method));
+    }
+
+private:
+    BufferedSpi _bufferspi;
+    ATParser _parser;
+    DigitalOut _resetpin;
+    volatile int _active_id;
+    void print_rx_buff(void);
+    bool check_response(void);
+    struct packet {
+        struct packet *next;
+        int id;
+        uint32_t len;
+        // data follows
+    } *_packets, * *_packets_end;
+    void _packet_handler();
+    bool _ism_debug;
+
+    char _ip_buffer[16];
+    char _gateway_buffer[16];
+    char _netmask_buffer[16];
+    char _mac_buffer[18];
+    uint32_t _FwVersionId;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/network/WIFI_ISM43362/ISM43362Interface.cpp	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,555 @@
+/* ISM43362 implementation of NetworkInterfaceAPI
+ * Copyright (c) STMicroelectronics 2018
+ *
+ * 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 <string.h>
+#include "ISM43362Interface.h"
+#include "mbed_debug.h"
+
+                                            // Product ID,FW Revision,API Revision,Stack Revision,RTOS Revision,CPU Clock,Product Name
+#define LATEST_FW_VERSION_NUMBER "C3.5.2.5" // ISM43362-M3G-L44-SPI,C3.5.2.5.STM,v3.5.2,v1.4.0.rc1,v8.2.1,120000000,Inventek eS-WiFi
+
+// activate / de-activate debug
+#define ism_interface_debug 0
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+// ISM43362Interface implementation
+ISM43362Interface::ISM43362Interface(bool debug)
+    : _ism(MBED_CONF_ISM43362_WIFI_MOSI, MBED_CONF_ISM43362_WIFI_MISO, MBED_CONF_ISM43362_WIFI_SCLK, MBED_CONF_ISM43362_WIFI_NSS, MBED_CONF_ISM43362_WIFI_RESET, MBED_CONF_ISM43362_WIFI_DATAREADY, MBED_CONF_ISM43362_WIFI_WAKEUP, debug)
+{
+    _ism_debug = ism_interface_debug || debug;
+    memset(_ids, 0, sizeof(_ids));
+    memset(_socket_obj, 0, sizeof(_socket_obj));
+    memset(_cbs, 0, sizeof(_cbs));
+    memset(ap_ssid, 0, sizeof(ap_ssid));
+    memset(ap_pass, 0, sizeof(ap_pass));
+    ap_sec = ISM_SECURITY_UNKNOWN;
+
+    thread_read_socket.start(callback(this, &ISM43362Interface::socket_check_read));
+
+    _mutex.lock();
+
+    // Check all supported firmware versions
+    _FwVersion = _ism.get_firmware_version();
+
+    if (!_FwVersion) {
+        error("ISM43362Interface: ERROR cannot read firmware version\r\n");
+    }
+
+    debug_if(_ism_debug, "ISM43362Interface: read_version = %lu\r\n", _FwVersion);
+    /* FW Revision should be with format "CX.X.X.X" with X as a single digit */
+    if ( (_FwVersion < 1000) || (_FwVersion > 9999) ) {
+        debug_if(_ism_debug, "ISM43362Interface: read_version issue\r\n");
+    }
+
+#if TARGET_DISCO_L475VG_IOT01A
+    if (_FwVersion < ParseNumber(LATEST_FW_VERSION_NUMBER, NULL)) {
+        debug_if(_ism_debug, "ISM43362Interface: please update FW\r\n");
+    }
+#endif
+
+    _mutex.unlock();
+}
+
+int ISM43362Interface::connect(const char *ssid, const char *pass, nsapi_security_t security,
+                               uint8_t channel)
+{
+    if (channel != 0) {
+        return NSAPI_ERROR_UNSUPPORTED;
+    }
+
+    nsapi_error_t credentials_status = set_credentials(ssid, pass, security);
+    if (credentials_status) {
+        return credentials_status;
+    }
+
+    return connect();
+}
+
+int ISM43362Interface::connect()
+{
+    if (strlen(ap_ssid) == 0) {
+        return NSAPI_ERROR_NO_SSID;
+    }
+
+    _mutex.lock();
+
+    if (!_ism.dhcp(true)) {
+        _mutex.unlock();
+        return NSAPI_ERROR_DHCP_FAILURE;
+    }
+
+    int connect_status = _ism.connect(ap_ssid, ap_pass, ap_sec);
+    debug_if(_ism_debug, "ISM43362Interface: connect_status %d\n", connect_status);
+
+    if (connect_status != NSAPI_ERROR_OK) {
+        _mutex.unlock();
+        return connect_status;
+    }
+
+    if (!_ism.getIPAddress()) {
+        _mutex.unlock();
+        return NSAPI_ERROR_DHCP_FAILURE;
+    }
+
+    _mutex.unlock();
+
+    return NSAPI_ERROR_OK;
+}
+
+nsapi_error_t ISM43362Interface::gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version)
+{
+    if (strlen(name) == 0) {
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+
+    _mutex.lock();
+    if (address->set_ip_address(name)) {
+        if (version != NSAPI_UNSPEC && address->get_ip_version() != version) {
+            _mutex.unlock();
+            return NSAPI_ERROR_DNS_FAILURE;
+        }
+
+        _mutex.unlock();
+        return NSAPI_ERROR_OK;
+    }
+
+    char *ipbuff = new char[NSAPI_IP_SIZE];
+    int ret = 0;
+    if (!_ism.dns_lookup(name, ipbuff)) {
+        ret = NSAPI_ERROR_DEVICE_ERROR;
+    } else {
+        address->set_ip_address(ipbuff);
+    }
+    _mutex.unlock();
+
+    delete[] ipbuff;
+
+    return ret;
+}
+
+int ISM43362Interface::set_credentials(const char *ssid, const char *pass, nsapi_security_t security)
+{
+    if ((strlen(ssid) == 0) || (strlen(ssid) > 32)) {
+        return NSAPI_ERROR_PARAMETER;
+    }
+
+    if ((security != NSAPI_SECURITY_NONE) && (strcmp(pass, "") == 0)) {
+        return NSAPI_ERROR_PARAMETER;
+    }
+
+    if (strlen(pass) > 63) {
+        return NSAPI_ERROR_PARAMETER;
+    }
+
+    _mutex.lock();
+    memset(ap_ssid, 0, sizeof(ap_ssid));
+    strncpy(ap_ssid, ssid, sizeof(ap_ssid));
+
+    memset(ap_pass, 0, sizeof(ap_pass));
+    strncpy(ap_pass, pass, sizeof(ap_pass));
+
+    switch (security) {
+        case NSAPI_SECURITY_NONE:
+            ap_sec = ISM_SECURITY_NONE;
+            break;
+        case NSAPI_SECURITY_WEP:
+            ap_sec = ISM_SECURITY_WEP;
+            break;
+        case NSAPI_SECURITY_WPA:
+            ap_sec = ISM_SECURITY_WPA;
+            break;
+        case NSAPI_SECURITY_WPA2:
+            ap_sec = ISM_SECURITY_WPA2;
+            break;
+        case NSAPI_SECURITY_WPA_WPA2:
+            ap_sec = ISM_SECURITY_WPA_WPA2;
+            break;
+        default:
+            ap_sec = ISM_SECURITY_UNKNOWN;
+            break;
+    }
+    _mutex.unlock();
+
+    return NSAPI_ERROR_OK;
+}
+
+int ISM43362Interface::set_channel(uint8_t channel)
+{
+    return NSAPI_ERROR_UNSUPPORTED;
+}
+
+int ISM43362Interface::disconnect()
+{
+    _mutex.lock();
+
+    if (!_ism.disconnect()) {
+        _mutex.unlock();
+        return NSAPI_ERROR_DEVICE_ERROR;
+    }
+
+    _mutex.unlock();
+
+    return NSAPI_ERROR_OK;
+}
+
+const char *ISM43362Interface::get_ip_address()
+{
+    _mutex.lock();
+    const char *ret = _ism.getIPAddress();
+    _mutex.unlock();
+    return ret;
+}
+
+const char *ISM43362Interface::get_mac_address()
+{
+    _mutex.lock();
+    const char *ret = _ism.getMACAddress();
+    _mutex.unlock();
+    return ret;
+}
+
+const char *ISM43362Interface::get_gateway()
+{
+    _mutex.lock();
+    const char *ret = _ism.getGateway();
+    _mutex.unlock();
+    return ret;
+}
+
+const char *ISM43362Interface::get_netmask()
+{
+    _mutex.lock();
+    const char *ret = _ism.getNetmask();
+    _mutex.unlock();
+    return ret;
+}
+
+int8_t ISM43362Interface::get_rssi()
+{
+    _mutex.lock();
+    int8_t ret = _ism.getRSSI();
+    _mutex.unlock();
+    return ret;
+}
+
+int ISM43362Interface::scan(WiFiAccessPoint *res, unsigned count)
+{
+    _mutex.lock();
+    int ret = _ism.scan(res, count);
+    _mutex.unlock();
+    return ret;
+}
+
+struct ISM43362_socket {
+    int id;
+    nsapi_protocol_t proto;
+    volatile bool connected;
+    SocketAddress addr;
+    char read_data[1400];
+    volatile uint32_t read_data_size;
+};
+
+int ISM43362Interface::socket_open(void **handle, nsapi_protocol_t proto)
+{
+    // Look for an unused socket
+    int id = -1;
+    for (int i = 0; i < ISM43362_SOCKET_COUNT; i++) {
+        if (!_ids[i]) {
+            id = i;
+            _ids[i] = true;
+            break;
+        }
+    }
+
+    if (id == -1) {
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+    _mutex.lock();
+    struct ISM43362_socket *socket = new struct ISM43362_socket;
+    if (!socket) {
+        _mutex.unlock();
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+    socket->id = id;
+    debug_if(_ism_debug, "ISM43362Interface: socket_open, id=%d\n", socket->id);
+    memset(socket->read_data, 0, sizeof(socket->read_data));
+    socket->addr = 0;
+    socket->read_data_size = 0;
+    socket->proto = proto;
+    socket->connected = false;
+    *handle = socket;
+    _mutex.unlock();
+
+    return 0;
+}
+
+int ISM43362Interface::socket_close(void *handle)
+{
+    _mutex.lock();
+    struct ISM43362_socket *socket = (struct ISM43362_socket *)handle;
+    debug_if(_ism_debug, "ISM43362Interface: socket_close, id=%d\n", socket->id);
+    int err = 0;
+
+    if (!_ism.close(socket->id)) {
+        err = NSAPI_ERROR_DEVICE_ERROR;
+    }
+
+    socket->connected = false;
+    _ids[socket->id] = false;
+    _socket_obj[socket->id] = 0;
+    _mutex.unlock();
+    delete socket;
+    return err;
+}
+
+int ISM43362Interface::socket_bind(void *handle, const SocketAddress &address)
+{
+    return NSAPI_ERROR_UNSUPPORTED;
+}
+
+int ISM43362Interface::socket_listen(void *handle, int backlog)
+{
+    return NSAPI_ERROR_UNSUPPORTED;
+}
+
+int ISM43362Interface::socket_connect(void *handle, const SocketAddress &addr)
+{
+    _mutex.lock();
+    int ret = socket_connect_nolock(handle, addr);
+    _mutex.unlock();
+    return ret;
+}
+
+int ISM43362Interface::socket_connect_nolock(void *handle, const SocketAddress &addr)
+{
+    struct ISM43362_socket *socket = (struct ISM43362_socket *)handle;
+    const char *proto = (socket->proto == NSAPI_UDP) ? "1" : "0";
+    if (!_ism.open(proto, socket->id, addr.get_ip_address(), addr.get_port())) {
+        return NSAPI_ERROR_DEVICE_ERROR;
+    }
+    _ids[socket->id]  = true;
+    _socket_obj[socket->id] = (uint32_t)socket;
+    socket->connected = true;
+    return 0;
+
+}
+
+
+
+void ISM43362Interface::socket_check_read()
+{
+    while (1) {
+        for (int i = 0; i < ISM43362_SOCKET_COUNT; i++) {
+            _mutex.lock();
+            if (_socket_obj[i] != 0) {
+                struct ISM43362_socket *socket = (struct ISM43362_socket *)_socket_obj[i];
+                /* Check if there is something to read for this socket. But if it */
+                /* has already been read : don't read again */
+                if ((socket->connected) && (socket->read_data_size == 0) && _cbs[socket->id].callback) {
+                    /* if no callback is set, no need to read ?*/
+                    int read_amount = _ism.check_recv_status(socket->id, socket->read_data);
+                    // debug_if(_ism_debug, "ISM43362Interface socket_check_read: i %d read_amount %d \r\n", i, read_amount);
+                    if (read_amount > 0) {
+                        socket->read_data_size = read_amount;
+                    } else if (read_amount < 0) {
+                        /* Mark donw connection has been lost or closed */
+                        debug_if(_ism_debug, "ISM43362Interface socket_check_read: i %d closed\r\n", i, read_amount);
+                        socket->connected = false;
+                    }
+                    if (read_amount != 0) {
+                        /* There is something to read in this socket*/
+                        if (_cbs[socket->id].callback) {
+                            _cbs[socket->id].callback(_cbs[socket->id].data);
+                        }
+                    }
+                }
+            }
+            _mutex.unlock();
+        }
+        wait_ms(50);
+    }
+}
+
+int ISM43362Interface::socket_accept(void *server, void **socket, SocketAddress *addr)
+{
+    return NSAPI_ERROR_UNSUPPORTED;
+}
+
+int ISM43362Interface::socket_send(void *handle, const void *data, unsigned size)
+{
+    _mutex.lock();
+    int ret = socket_send_nolock(handle, data, size);
+    _mutex.unlock();
+    return ret;
+}
+
+/*  CAREFULL LOCK must be taken before callling this function */
+int ISM43362Interface::socket_send_nolock(void *handle, const void *data, unsigned size)
+{
+    struct ISM43362_socket *socket = (struct ISM43362_socket *)handle;
+
+    if (size > ES_WIFI_MAX_TX_PACKET_SIZE) {
+        size = ES_WIFI_MAX_TX_PACKET_SIZE;
+    }
+
+    if (!_ism.send(socket->id, data, size)) {
+        debug_if(_ism_debug, "ISM43362Interface: socket_send ERROR\r\n");
+        return NSAPI_ERROR_DEVICE_ERROR; // or WOULD_BLOCK ?
+    }
+
+    return size;
+}
+
+int ISM43362Interface::socket_recv(void *handle, void *data, unsigned size)
+{
+    _mutex.lock();
+    unsigned recv = 0;
+    struct ISM43362_socket *socket = (struct ISM43362_socket *)handle;
+    char *ptr = (char *)data;
+
+    // debug_if(_ism_debug, "ISM43362Interface socket_recv: req=%d read_data_size=%d connected %d\r\n", size, socket->read_data_size, socket->connected);
+
+    if (!socket->connected) {
+        _mutex.unlock();
+        return NSAPI_ERROR_CONNECTION_LOST;
+    }
+
+    if (socket->read_data_size == 0) {
+        /* if no callback is set, no need to read ?*/
+        int read_amount = _ism.check_recv_status(socket->id, socket->read_data);
+        if (read_amount > 0) {
+            socket->read_data_size = read_amount;
+        } else if (read_amount < 0) {
+            socket->connected = false;
+            debug_if(_ism_debug, "ISM43362Interface socket_recv: socket closed\r\n");
+            _mutex.unlock();
+            return NSAPI_ERROR_CONNECTION_LOST;
+        }
+    }
+
+    if (socket->read_data_size != 0) {
+        // debug_if(_ism_debug, "ISM43362Interface socket_recv: read_data_size=%d\r\n", socket->read_data_size);
+        uint32_t i = 0;
+        while ((i < socket->read_data_size) && (i < size)) {
+            *ptr++ = socket->read_data[i];
+            i++;
+        }
+
+        recv += i;
+
+        if (i >= socket->read_data_size) {
+            /* All the storeed data has been read, reset buffer */
+            memset(socket->read_data, 0, sizeof(socket->read_data));
+            socket->read_data_size = 0;
+            // debug_if(_ism_debug, "ISM43362Interface: Socket_recv buffer reset\r\n");
+        } else {
+            /*  In case there is remaining data in buffer, update socket content
+             *  For now by shift copy of all data (not very efficient to be
+             *  revised */
+            while (i < socket->read_data_size) {
+                socket->read_data[i - size] = socket->read_data[i];
+                i++;
+            }
+
+            socket->read_data_size -= size;
+        }
+    }
+    // else {
+    //     debug_if(_ism_debug, "ISM43362Interface socket_recv: Nothing in buffer\r\n");
+    // }
+
+    _mutex.unlock();
+
+    if (recv > 0) {
+        debug_if(_ism_debug, "ISM43362Interface socket_recv: recv=%d\r\n", recv);
+        return recv;
+    } else {
+        debug_if(_ism_debug, "ISM43362Interface socket_recv: returns WOULD BLOCK\r\n");
+        return NSAPI_ERROR_WOULD_BLOCK;
+    }
+}
+
+int ISM43362Interface::socket_sendto(void *handle, const SocketAddress &addr, const void *data, unsigned size)
+{
+    _mutex.lock();
+    struct ISM43362_socket *socket = (struct ISM43362_socket *)handle;
+
+    if (socket->connected && socket->addr != addr) {
+        if (!_ism.close(socket->id)) {
+            debug_if(_ism_debug, "ISM43362Interface: socket_sendto ERROR\r\n");
+            _mutex.unlock();
+            return NSAPI_ERROR_DEVICE_ERROR;
+        }
+        socket->connected = false;
+        _ids[socket->id] = false;
+        _socket_obj[socket->id] = 0;
+    }
+
+    if (!socket->connected) {
+        int err = socket_connect_nolock(socket, addr);
+        if (err < 0) {
+            _mutex.unlock();
+            return err;
+        }
+        socket->addr = addr;
+    }
+
+    int ret = socket_send_nolock(socket, data, size);
+
+    _mutex.unlock();
+
+    return ret;
+}
+
+int ISM43362Interface::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size)
+{
+    int ret = socket_recv(handle, data, size);
+    _mutex.lock();
+    if ((ret >= 0) && addr) {
+        struct ISM43362_socket *socket = (struct ISM43362_socket *)handle;
+        *addr = socket->addr;
+    }
+    _mutex.unlock();
+    return ret;
+}
+
+void ISM43362Interface::socket_attach(void *handle, void (*cb)(void *), void *data)
+{
+    _mutex.lock();
+    struct ISM43362_socket *socket = (struct ISM43362_socket *)handle;
+    _cbs[socket->id].callback = cb;
+    _cbs[socket->id].data = data;
+    _mutex.unlock();
+}
+
+void ISM43362Interface::event()
+{
+    for (int i = 0; i < ISM43362_SOCKET_COUNT; i++) {
+        if (_cbs[i].callback) {
+            _cbs[i].callback(_cbs[i].data);
+        }
+    }
+}
+
+#if MBED_CONF_ISM43362_PROVIDE_DEFAULT
+
+WiFiInterface *WiFiInterface::get_default_instance() {
+    static ISM43362Interface ism;
+    return &ism;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/network/WIFI_ISM43362/ISM43362Interface.h	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,298 @@
+/* ISM43362 implementation of NetworkInterfaceAPI
+ * Copyright (c) STMicroelectronics 2017
+ *
+ * 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.
+ */
+
+#ifndef ISM43362_INTERFACE_H
+#define ISM43362_INTERFACE_H
+
+#include "mbed.h"
+#include "ISM43362.h"
+
+
+#define ISM43362_SOCKET_COUNT 4
+
+/** ISM43362Interface class
+ *  Implementation of the NetworkStack for the ISM43362
+ */
+class ISM43362Interface : public NetworkStack, public WiFiInterface
+{
+public:
+    /** ISM43362Interface lifetime
+     * @param debug     Enable debugging
+     */
+    ISM43362Interface(bool debug = MBED_CONF_ISM43362_WIFI_DEBUG);
+
+    /** Start the interface
+     *
+     *  Attempts to connect to a WiFi network. Requires ssid and passphrase to be set.
+     *  If passphrase is invalid, NSAPI_ERROR_AUTH_ERROR is returned.
+     *
+     *  @return         0 on success, negative error code on failure
+     */
+    virtual int connect();
+
+    /** Start the interface
+     *
+     *  Attempts to connect to a WiFi network.
+     *
+     *  @param ssid      Name of the network to connect to
+     *  @param pass      Security passphrase to connect to the network
+     *  @param security  Type of encryption for connection (Default: NSAPI_SECURITY_NONE)
+     *  @param channel   This parameter is not supported, setting it to anything else than 0 will result in NSAPI_ERROR_UNSUPPORTED
+     *  @return          0 on success, or error code on failure
+     */
+    virtual int connect(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE,
+                        uint8_t channel = 0);
+
+    /** Translates a hostname to an IP address with specific version
+     *
+     *  The hostname may be either a domain name or an IP address. If the
+     *  hostname is an IP address, no network transactions will be performed.
+     *
+     *
+     *  @param host     Hostname to resolve
+     *  @param address  Destination for the host SocketAddress
+     *  @param version  IP version of address to resolve, NSAPI_UNSPEC indicates
+     *                  version is chosen by the stack (defaults to NSAPI_UNSPEC)
+     *  @return         0 on success, negative error code on failure
+     */
+    virtual nsapi_error_t gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version = NSAPI_UNSPEC);
+
+    /** Set the WiFi network credentials
+     *
+     *  @param ssid      Name of the network to connect to
+     *  @param pass      Security passphrase to connect to the network
+     *  @param security  Type of encryption for connection
+     *                   (defaults to NSAPI_SECURITY_NONE)
+     *  @return          0 on success, or error code on failure
+     */
+    virtual int set_credentials(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE);
+
+    /** Set the WiFi network channel - NOT SUPPORTED
+     *
+     * This function is not supported and will return NSAPI_ERROR_UNSUPPORTED
+     *
+     *  @param channel   Channel on which the connection is to be made, or 0 for any (Default: 0)
+     *  @return          Not supported, returns NSAPI_ERROR_UNSUPPORTED
+     */
+    virtual int set_channel(uint8_t channel);
+
+    /** Stop the interface
+     *  @return             0 on success, negative on failure
+     */
+    virtual int disconnect();
+
+    /** Get the internally stored IP address
+     *  @return             IP address of the interface or null if not yet connected
+     */
+    virtual const char *get_ip_address();
+
+    /** Get the internally stored MAC address
+     *  @return             MAC address of the interface
+     */
+    virtual const char *get_mac_address();
+
+    /** Get the local gateway
+    *
+    *  @return         Null-terminated representation of the local gateway
+    *                  or null if no network mask has been recieved
+    */
+    virtual const char *get_gateway();
+
+    /** Get the local network mask
+     *
+     *  @return         Null-terminated representation of the local network mask
+     *                  or null if no network mask has been recieved
+     */
+    virtual const char *get_netmask();
+
+    /** Gets the current radio signal strength for active connection
+     *
+     * @return          Connection strength in dBm (negative value)
+     */
+    virtual int8_t get_rssi();
+
+    /** Scan for available networks
+     *
+     * This function will block.
+     *
+     * @param  ap       Pointer to allocated array to store discovered AP
+     * @param  count    Size of allocated @a res array, or 0 to only count available AP
+     * @return          Number of entries in @a, or if @a count was 0 number of available networks, negative on error
+     *                  see @a nsapi_error
+     */
+    virtual int scan(WiFiAccessPoint *res, unsigned count);
+
+    /** Translates a hostname to an IP address with specific version
+     *
+     *  The hostname may be either a domain name or an IP address. If the
+     *  hostname is an IP address, no network transactions will be performed.
+     *
+     *  If no stack-specific DNS resolution is provided, the hostname
+     *  will be resolve using a UDP socket on the stack.
+     *
+     *  @param address  Destination for the host SocketAddress
+     *  @param host     Hostname to resolve
+     *  @param version  IP version of address to resolve, NSAPI_UNSPEC indicates
+     *                  version is chosen by the stack (defaults to NSAPI_UNSPEC)
+     *  @return         0 on success, negative error code on failure
+     */
+    using NetworkInterface::gethostbyname;
+
+    /** Add a domain name server to list of servers to query
+     *
+     *  @param addr     Destination for the host address
+     *  @return         0 on success, negative error code on failure
+     */
+    using NetworkInterface::add_dns_server;
+
+protected:
+    /** Open a socket
+     *  @param handle       Handle in which to store new socket
+     *  @param proto        Type of socket to open, NSAPI_TCP or NSAPI_UDP
+     *  @return             0 on success, negative on failure
+     */
+    virtual int socket_open(void **handle, nsapi_protocol_t proto);
+
+    /** Close the socket
+     *  @param handle       Socket handle
+     *  @return             0 on success, negative on failure
+     *  @note On failure, any memory associated with the socket must still
+     *        be cleaned up
+     */
+    virtual int socket_close(void *handle);
+
+    /** Bind a server socket to a specific port
+     *  @param handle       Socket handle
+     *  @param address      Local address to listen for incoming connections on
+     *  @return             0 on success, negative on failure.
+     */
+    virtual int socket_bind(void *handle, const SocketAddress &address);
+
+    /** Start listening for incoming connections
+     *  @param handle       Socket handle
+     *  @param backlog      Number of pending connections that can be queued up at any
+     *                      one time [Default: 1]
+     *  @return             0 on success, negative on failure
+     */
+    virtual int socket_listen(void *handle, int backlog);
+
+    /** Connects this TCP socket to the server
+     *  @param handle       Socket handle
+     *  @param address      SocketAddress to connect to
+     *  @return             0 on success, negative on failure
+     */
+    virtual int socket_connect(void *handle, const SocketAddress &address);
+
+    /** Accept a new connection.
+     *  @param handle       Handle in which to store new socket
+     *  @param server       Socket handle to server to accept from
+     *  @return             0 on success, negative on failure
+     *  @note This call is not-blocking, if this call would block, must
+     *        immediately return NSAPI_ERROR_WOULD_WAIT
+     */
+    virtual int socket_accept(void *handle, void **socket, SocketAddress *address);
+
+    /** Send data to the remote host
+     *  @param handle       Socket handle
+     *  @param data         The buffer to send to the host
+     *  @param size         The length of the buffer to send
+     *  @return             Number of written bytes on success, negative on failure
+     *  @note This call is not-blocking, if this call would block, must
+     *        immediately return NSAPI_ERROR_WOULD_WAIT
+     */
+    virtual int socket_send(void *handle, const void *data, unsigned size);
+
+    /** Receive data from the remote host
+     *  @param handle       Socket handle
+     *  @param data         The buffer in which to store the data received from the host
+     *  @param size         The maximum length of the buffer
+     *  @return             Number of received bytes on success, negative on failure
+     *  @note This call is not-blocking, if this call would block, must
+     *        immediately return NSAPI_ERROR_WOULD_WAIT
+     */
+    virtual int socket_recv(void *handle, void *data, unsigned size);
+
+    /** Send a packet to a remote endpoint
+     *  @param handle       Socket handle
+     *  @param address      The remote SocketAddress
+     *  @param data         The packet to be sent
+     *  @param size         The length of the packet to be sent
+     *  @return             The number of written bytes on success, negative on failure
+     *  @note This call is not-blocking, if this call would block, must
+     *        immediately return NSAPI_ERROR_WOULD_WAIT
+     */
+    virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size);
+
+    /** Receive a packet from a remote endpoint
+     *  @param handle       Socket handle
+     *  @param address      Destination for the remote SocketAddress or null
+     *  @param buffer       The buffer for storing the incoming packet data
+     *                      If a packet is too long to fit in the supplied buffer,
+     *                      excess bytes are discarded
+     *  @param size         The length of the buffer
+     *  @return             The number of received bytes on success, negative on failure
+     *  @note This call is not-blocking, if this call would block, must
+     *        immediately return NSAPI_ERROR_WOULD_WAIT
+     */
+    virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size);
+
+    /** Register a callback on state change of the socket
+     *  @param handle       Socket handle
+     *  @param callback     Function to call on state change
+     *  @param data         Argument to pass to callback
+     *  @note Callback may be called in an interrupt context.
+     */
+    virtual void socket_attach(void *handle, void (*callback)(void *), void *data);
+
+    /** Provide access to the NetworkStack object
+     *
+     *  @return The underlying NetworkStack object
+     */
+    virtual NetworkStack *get_stack()
+    {
+        return this;
+    }
+
+private:
+    ISM43362 _ism;
+    bool _ids[ISM43362_SOCKET_COUNT];
+    uint32_t _socket_obj[ISM43362_SOCKET_COUNT]; // store addresses of socket handles
+    Mutex _mutex;
+    Thread thread_read_socket;
+    char ap_ssid[33]; /* 32 is what 802.11 defines as longest possible name; +1 for the \0 */
+    ism_security_t ap_sec;
+    uint8_t ap_ch;
+    char ap_pass[64]; /* The longest allowed passphrase */
+
+    bool _ism_debug;
+    uint32_t _FwVersion;
+
+    void event();
+    struct {
+        void (*callback)(void *);
+        void *data;
+    } _cbs[ISM43362_SOCKET_COUNT];
+
+    /** Function called by the socket read thread to check if data is available on the wifi module
+     *
+     */
+    virtual void socket_check_read();
+    int socket_send_nolock(void *handle, const void *data, unsigned size);
+    int socket_connect_nolock(void *handle, const SocketAddress &addr);
+
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/network/WIFI_ISM43362/README.md	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,50 @@
+# ISM43362 WiFi driver for mbed-os
+
+The mbed OS driver for the ISM43362 WiFi module
+
+https://www.inventeksys.com/products-page/wifi-modules/ism4336-m3g-l44-e-embedded-serial-to-wifi-module/
+
+
+## Currently supported platforms
+
+ISM43362 module is soldered on the following platforms from STMicroelectronics
+
+ * [DISCO_L475VG_IOT01A](https://os.mbed.com/platforms/ST-Discovery-L475E-IOT01A/)
+ * [DISCO_F413ZH](https://os.mbed.com/platforms/ST-Discovery-F413H/)
+
+## Configuration
+
+Correct pins have already been configured for both supported platforms.
+
+Here is configured pins:
+
+- MBED_CONF_ISM43362_WIFI_MISO      : spi-miso pin for the ism43362 connection
+- MBED_CONF_ISM43362_WIFI_MOSI     : spi-mosi pin for the ism43362 connection
+- MBED_CONF_ISM43362_WIFI_SPI_SCLK  : spi-clock pin for the ism43362 connection
+- MBED_CONF_ISM43362_WIFI_SPI_NSS   : spi-nss pin for the ism43362 connection
+- MBED_CONF_ISM43362_WIFI_RESET     : Reset pin for the ism43362 wifi module
+- MBED_CONF_ISM43362_WIFI_DATAREADY : Data Ready pin for the ism43362 wifi module
+- MBED_CONF_ISM43362_WIFI_WAKEUP    : Wakeup pin for the ism43362 wifi module
+
+## Debug
+
+Some debug print on console can help to debug if necessary.
+
+- in ISM43362Interface.cpp file, set ism_interface_debug to 1
+- in ISM43362/ISM43362.cpp file, set ism_debug to 1
+- in ISM43362/ATParser/ATParser.cpp file, there are 3 different level : dbg_on / AT_DATA_PRINT / AT_COMMAND_PRINT
+
+Another way to enable these prints is overwrite MBED_CONF_ISM43362_WIFI_DEBUG in your json file:
+            "ism43362.wifi-debug": true
+
+
+## Firmware version
+
+This driver has been tested with C3.5.2.2 and C3.5.2.3.BETA9 firmware version
+
+## wifi module FW update
+
+Only Wifi module from DISCO_L475VG_IOT01A can be updated (HW limitation for DISCO_F413ZH).
+
+For more information about the wifi FW version, refer to the detailed procedure in
+http://www.st.com/content/st_com/en/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32cube-embedded-software-expansion/x-cube-azure.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/network/WIFI_ISM43362/mbed_lib.json	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,63 @@
+{
+    "name": "ism43362",
+    "config": {
+        "wifi-miso": {
+            "help": "SPI-MISO connection to external device",
+            "value": "NC"
+        },
+        "wifi-mosi": {
+            "help": "SPI-MOSI connection to external device",
+            "value": "NC"
+        },
+        "wifi-sclk": {
+            "help": "SPI-CLOCK connection to external device",
+            "value": "NC"
+        },
+        "wifi-nss": {
+            "help": "SPI chip select of external device",
+            "value": "NC"
+        },
+        "wifi-reset": {
+            "help": "ISM43362 reset",
+            "value": "NC"
+        },
+        "wifi-dataready": {
+            "help": "ISM43362 dataready",
+            "value": "NC"
+        },
+        "wifi-wakeup": {
+            "help": "ISM43362 wakeup",
+            "value": "NC"
+        },
+        "wifi-debug": {
+            "help": "Defines whether logging is on or off",
+            "value": false
+        },
+        "provide-default": {
+            "help": "Provide default WifiInterface. [true/false]",
+            "value": false
+        }
+    },
+    "target_overrides": {
+        "DISCO_F413ZH": {
+            "ism43362.wifi-miso": "PB_4",
+            "ism43362.wifi-mosi": "PB_5",
+            "ism43362.wifi-sclk": "PB_12",
+            "ism43362.wifi-nss": "PG_11",
+            "ism43362.wifi-reset": "PH_1",
+            "ism43362.wifi-dataready": "PG_12",
+            "ism43362.wifi-wakeup": "PB_15",
+            "ism43362.provide-default": true
+        },
+        "DISCO_L475VG_IOT01A": {
+            "ism43362.wifi-miso": "PC_11",
+            "ism43362.wifi-mosi": "PC_12",
+            "ism43362.wifi-sclk": "PC_10",
+            "ism43362.wifi-nss": "PE_0",
+            "ism43362.wifi-reset": "PE_8",
+            "ism43362.wifi-dataready": "PE_1",
+            "ism43362.wifi-wakeup": "PB_13",
+            "ism43362.provide-default": true
+        }
+     }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/storage/COMPONENT_QSPIF/QSPIFBlockDevice.cpp	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,1405 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2018 ARM Limited
+ *
+ * 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 "QSPIFBlockDevice.h"
+#include <string.h>
+#include "mbed_wait_api.h"
+
+#ifndef MBED_CONF_MBED_TRACE_ENABLE
+#define MBED_CONF_MBED_TRACE_ENABLE        0
+#endif
+
+#include "mbed_trace.h"
+#define TRACE_GROUP "QSPIF"
+
+using namespace mbed;
+
+/* Default QSPIF Parameters */
+/****************************/
+#define QSPIF_DEFAULT_READ_SIZE  1
+#define QSPIF_DEFAULT_PROG_SIZE  1
+#define QSPIF_DEFAULT_PAGE_SIZE  256
+#define QSPIF_DEFAULT_SE_SIZE    4096
+#define QSPI_MAX_STATUS_REGISTER_SIZE 3
+#ifndef UINT64_MAX
+#define UINT64_MAX -1
+#endif
+#define QSPI_NO_ADDRESS_COMMAND UINT64_MAX
+// Status Register Bits
+#define QSPIF_STATUS_BIT_WIP        0x1 //Write In Progress
+#define QSPIF_STATUS_BIT_WEL        0x2 // Write Enable Latch
+
+/* SFDP Header Parsing */
+/***********************/
+#define QSPIF_SFDP_HEADER_SIZE 8
+#define QSPIF_PARAM_HEADER_SIZE 8
+
+/* Basic Parameters Table Parsing */
+/**********************************/
+#define SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES 64 /* 16 DWORDS */
+//READ Instruction support according to BUS Configuration
+#define QSPIF_BASIC_PARAM_TABLE_FAST_READ_SUPPORT_BYTE 2
+#define QSPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPORT_BYTE 16
+#define QSPIF_BASIC_PARAM_TABLE_444_READ_INST_BYTE 27
+#define QSPIF_BASIC_PARAM_TABLE_144_READ_INST_BYTE 9
+#define QSPIF_BASIC_PARAM_TABLE_114_READ_INST_BYTE 11
+#define QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE 23
+#define QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE 15
+#define QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE 13
+#define QSPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE 40
+// Quad Enable Params
+#define QSPIF_BASIC_PARAM_TABLE_QER_BYTE 58
+#define QSPIF_BASIC_PARAM_TABLE_444_MODE_EN_SEQ_BYTE 56
+// Erase Types Params
+#define QSPIF_BASIC_PARAM_ERASE_TYPE_1_BYTE 29
+#define QSPIF_BASIC_PARAM_ERASE_TYPE_2_BYTE 31
+#define QSPIF_BASIC_PARAM_ERASE_TYPE_3_BYTE 33
+#define QSPIF_BASIC_PARAM_ERASE_TYPE_4_BYTE 35
+#define QSPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE 28
+#define QSPIF_BASIC_PARAM_ERASE_TYPE_2_SIZE_BYTE 30
+#define QSPIF_BASIC_PARAM_ERASE_TYPE_3_SIZE_BYTE 32
+#define QSPIF_BASIC_PARAM_ERASE_TYPE_4_SIZE_BYTE 34
+#define QSPIF_BASIC_PARAM_4K_ERASE_TYPE_BYTE 1
+
+// Erase Types Per Region BitMask
+#define ERASE_BITMASK_TYPE4 0x08
+#define ERASE_BITMASK_TYPE1 0x01
+#define ERASE_BITMASK_NONE  0x00
+#define ERASE_BITMASK_ALL   0x0F
+
+#define IS_MEM_READY_MAX_RETRIES 10000
+
+enum qspif_default_instructions {
+    QSPIF_NOP  = 0x00, // No operation
+    QSPIF_PP = 0x02, // Page Program data
+    QSPIF_READ = 0x03, // Read data
+    QSPIF_SE   = 0x20, // 4KB Sector Erase
+    QSPIF_SFDP = 0x5a, // Read SFDP
+    QSPIF_WRSR = 0x01, // Write Status/Configuration Register
+    QSPIF_WRDI = 0x04, // Write Disable
+    QSPIF_RDSR = 0x05, // Read Status Register
+    QSPIF_WREN = 0x06, // Write Enable
+    QSPIF_RSTEN = 0x66, // Reset Enable
+    QSPIF_RST = 0x99, // Reset
+    QSPIF_RDID = 0x9f, // Read Manufacturer and JDEC Device ID
+};
+
+// Local Function
+static int local_math_power(int base, int exp);
+
+/* Init function to initialize Different Devices CS static list */
+static PinName *generate_initialized_active_qspif_csel_arr();
+// Static Members for different devices csel
+// _devices_mutex is used to lock csel list - only one QSPIFBlockDevice instance per csel is allowed
+SingletonPtr<PlatformMutex> QSPIFBlockDevice::_devices_mutex;
+int QSPIFBlockDevice::_number_of_active_qspif_flash_csel = 0;
+PinName *QSPIFBlockDevice::_active_qspif_flash_csel_arr = generate_initialized_active_qspif_csel_arr();
+
+/********* Public API Functions *********/
+/****************************************/
+QSPIFBlockDevice::QSPIFBlockDevice(PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName csel,
+                                   int clock_mode, int freq)
+    : _qspi(io0, io1, io2, io3, sclk, csel, clock_mode), _csel(csel), _freq(freq), _device_size_bytes(0),
+      _init_ref_count(0),
+      _is_initialized(false)
+{
+    _unique_device_status = add_new_csel_instance(csel);
+
+    if (_unique_device_status == 0) {
+        tr_info("Adding a new QSPIFBlockDevice csel: %d\n", (int)csel);
+    } else if (_unique_device_status == -1) {
+        tr_error("QSPIFBlockDevice with the same csel(%d) already exists\n", (int)csel);
+    } else {
+        tr_error("Too many different QSPIFBlockDevice devices - max allowed: %d\n", QSPIF_MAX_ACTIVE_FLASH_DEVICES);
+    }
+}
+
+int QSPIFBlockDevice::init()
+{
+    if (_unique_device_status == 0) {
+        tr_debug("QSPIFBlockDevice csel: %d", (int)_csel);
+    } else if (_unique_device_status == -1) {
+        tr_error("QSPIFBlockDevice with the same csel(%d) already exists", (int)_csel);
+        return QSPIF_BD_ERROR_DEVICE_NOT_UNIQE;
+    } else {
+        tr_error("Too many different QSPIFBlockDevice devices - max allowed: %d", QSPIF_MAX_ACTIVE_FLASH_DEVICES);
+        return QSPIF_BD_ERROR_DEVICE_MAX_EXCEED;
+    }
+
+    uint8_t vendor_device_ids[4];
+    size_t data_length = 3;
+    int status = QSPIF_BD_ERROR_OK;
+    uint32_t basic_table_addr = 0;
+    size_t basic_table_size = 0;
+    uint32_t sector_map_table_addr = 0;
+    size_t sector_map_table_size = 0;
+    int qspi_status = QSPI_STATUS_OK;
+
+    _mutex.lock();
+
+    if (!_is_initialized) {
+        _init_ref_count = 0;
+    }
+
+    _init_ref_count++;
+
+    if (_init_ref_count != 1) {
+        goto exit_point;
+    }
+
+    //Initialize parameters
+    _min_common_erase_size = 0;
+    _regions_count = 1;
+    _region_erase_types_bitfield[0] = ERASE_BITMASK_NONE;
+
+    //Default Bus Setup 1_1_1 with 0 dummy and mode cycles
+    _inst_width = QSPI_CFG_BUS_SINGLE;
+    _address_width = QSPI_CFG_BUS_SINGLE;
+    _address_size = QSPI_CFG_ADDR_SIZE_24;
+    _data_width = QSPI_CFG_BUS_SINGLE;
+    _dummy_and_mode_cycles = 0;
+    _write_register_inst = QSPIF_WRSR;
+    _read_register_inst = QSPIF_RDSR;
+
+
+    if (QSPI_STATUS_OK != _qspi_set_frequency(_freq)) {
+        tr_error("QSPI Set Frequency Failed");
+        status = QSPIF_BD_ERROR_DEVICE_ERROR;
+        goto exit_point;
+    }
+
+    // Soft Reset
+    if (-1 == _reset_flash_mem()) {
+        tr_error("Init - Unable to initialize flash memory, tests failed");
+        status = QSPIF_BD_ERROR_DEVICE_ERROR;
+        goto exit_point;
+    } else {
+        tr_info("Initialize flash memory OK");
+    }
+
+    /* Read Manufacturer ID (1byte), and Device ID (2bytes)*/
+    qspi_status = _qspi_send_general_command(QSPIF_RDID, QSPI_NO_ADDRESS_COMMAND, NULL, 0, (char *)vendor_device_ids,
+                                             data_length);
+    if (qspi_status != QSPI_STATUS_OK) {
+        tr_error("Init - Read Vendor ID Failed");
+        status = QSPIF_BD_ERROR_DEVICE_ERROR;
+        goto exit_point;
+    }
+
+    tr_debug("Vendor device ID = 0x%x 0x%x 0x%x 0x%x \n", vendor_device_ids[0],
+             vendor_device_ids[1], vendor_device_ids[2], vendor_device_ids[3]);
+    switch (vendor_device_ids[0]) {
+        case 0xbf:
+            // SST devices come preset with block protection
+            // enabled for some regions, issue write disable instruction to clear
+            _set_write_enable();
+            _qspi_send_general_command(QSPIF_WRDI, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0);
+            break;
+    }
+
+    //Synchronize Device
+    if (false == _is_mem_ready()) {
+        tr_error("Init - _is_mem_ready Failed");
+        status = QSPIF_BD_ERROR_READY_FAILED;
+        goto exit_point;
+    }
+
+    /**************************** Parse SFDP Header ***********************************/
+    if (0 != _sfdp_parse_sfdp_headers(basic_table_addr, basic_table_size, sector_map_table_addr, sector_map_table_size)) {
+        tr_error("Init - Parse SFDP Headers Failed");
+        status = QSPIF_BD_ERROR_PARSING_FAILED;
+        goto exit_point;
+    }
+
+    /**************************** Parse Basic Parameters Table ***********************************/
+    if (0 != _sfdp_parse_basic_param_table(basic_table_addr, basic_table_size)) {
+        tr_error("Init - Parse Basic Param Table Failed");
+        status = QSPIF_BD_ERROR_PARSING_FAILED;
+        goto exit_point;
+    }
+
+    /**************************** Parse Sector Map Table ***********************************/
+    _region_size_bytes[0] =
+        _device_size_bytes; // If there's no region map, we have a single region sized the entire device size
+    _region_high_boundary[0] = _device_size_bytes - 1;
+
+    if ((sector_map_table_addr != 0) && (0 != sector_map_table_size)) {
+        tr_info("Init - Parsing Sector Map Table - addr: 0x%lxh, Size: %d", sector_map_table_addr,
+                sector_map_table_size);
+        if (0 != _sfdp_parse_sector_map_table(sector_map_table_addr, sector_map_table_size)) {
+            tr_error("Init - Parse Sector Map Table Failed");
+            status = QSPIF_BD_ERROR_PARSING_FAILED;
+            goto exit_point;
+        }
+    }
+
+    // Configure  BUS Mode to 1_1_1 for all commands other than Read
+    _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE,
+                           QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 0);
+
+    _is_initialized = true;
+
+exit_point:
+    _mutex.unlock();
+
+    return status;
+}
+
+int QSPIFBlockDevice::deinit()
+{
+    int result = QSPIF_BD_ERROR_OK;
+
+    _mutex.lock();
+
+    if (!_is_initialized) {
+        _init_ref_count = 0;
+        _mutex.unlock();
+        return result;
+    }
+
+    _init_ref_count--;
+
+    if (_init_ref_count) {
+        _mutex.unlock();
+        return result;
+    }
+
+    // Disable Device for Writing
+    qspi_status_t status = _qspi_send_general_command(QSPIF_WRDI, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0);
+    if (status != QSPI_STATUS_OK)  {
+        tr_error("Write Disable failed");
+        result = QSPIF_BD_ERROR_DEVICE_ERROR;
+    }
+
+    _is_initialized = false;
+
+    _mutex.unlock();
+
+    if (_unique_device_status == 0) {
+        remove_csel_instance(_csel);
+    }
+
+    return result;
+}
+
+int QSPIFBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
+{
+    int status = QSPIF_BD_ERROR_OK;
+    tr_info("Read Inst: 0x%xh", _read_instruction);
+
+    _mutex.lock();
+
+    // Configure Bus for Reading
+    _qspi_configure_format(_inst_width, _address_width, _address_size, QSPI_CFG_BUS_SINGLE,
+                           QSPI_CFG_ALT_SIZE_8, _data_width, _dummy_and_mode_cycles);
+
+    if (QSPI_STATUS_OK != _qspi_send_read_command(_read_instruction, buffer, addr, size)) {
+        status = QSPIF_BD_ERROR_DEVICE_ERROR;
+        tr_error("Read Command failed");
+    }
+
+    // All commands other than Read use default 1-1-1 Bus mode (Program/Erase are constrained by flash memory performance less than that of the bus)
+    _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE,
+                           QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 0);
+
+    _mutex.unlock();
+    return status;
+
+}
+
+int QSPIFBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size)
+{
+    qspi_status_t result = QSPI_STATUS_OK;
+    bool program_failed = false;
+    int status = QSPIF_BD_ERROR_OK;
+    uint32_t offset = 0;
+    uint32_t chunk = 0;
+    bd_size_t written_bytes = 0;
+
+    tr_debug("Program - Buff: 0x%lxh, addr: %llu, size: %llu", (uint32_t)buffer, addr, size);
+
+    while (size > 0) {
+        // Write on _page_size_bytes boundaries (Default 256 bytes a page)
+        offset = addr % _page_size_bytes;
+        chunk = (offset + size < _page_size_bytes) ? size : (_page_size_bytes - offset);
+        written_bytes = chunk;
+
+        _mutex.lock();
+
+        //Send WREN
+        if (_set_write_enable() != 0) {
+            tr_error("Write Enabe failed");
+            program_failed = true;
+            status = QSPIF_BD_ERROR_WREN_FAILED;
+            goto exit_point;
+        }
+
+        result = _qspi_send_program_command(_prog_instruction, buffer, addr, &written_bytes);
+        if ((result != QSPI_STATUS_OK) || (chunk != written_bytes)) {
+            tr_error("Write failed");
+            program_failed = true;
+            status = QSPIF_BD_ERROR_DEVICE_ERROR;
+            goto exit_point;
+        }
+
+        buffer = static_cast<const uint8_t *>(buffer) + chunk;
+        addr += chunk;
+        size -= chunk;
+
+        if (false == _is_mem_ready()) {
+            tr_error("Device not ready after write, failed");
+            program_failed = true;
+            status = QSPIF_BD_ERROR_READY_FAILED;
+            goto exit_point;
+        }
+        _mutex.unlock();
+    }
+
+exit_point:
+    if (program_failed) {
+        _mutex.unlock();
+    }
+
+    return status;
+}
+
+int QSPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size)
+{
+    int type = 0;
+    uint32_t offset = 0;
+    uint32_t chunk = 4096;
+    unsigned int cur_erase_inst = _erase_instruction;
+    int size = (int)in_size;
+    bool erase_failed = false;
+    int status = QSPIF_BD_ERROR_OK;
+    // Find region of erased address
+    int region = _utils_find_addr_region(addr);
+    // Erase Types of selected region
+    uint8_t bitfield = _region_erase_types_bitfield[region];
+
+    tr_debug("Erase - addr: %llu, in_size: %llu", addr, in_size);
+
+    if ((addr + in_size) > _device_size_bytes) {
+        tr_error("Erase exceeds flash device size");
+        return QSPIF_BD_ERROR_INVALID_ERASE_PARAMS;
+    }
+
+    if (((addr % get_erase_size(addr)) != 0) || (((addr + in_size) % get_erase_size(addr + in_size - 1)) != 0)) {
+        tr_error("Invalid erase - unaligned address and size");
+        return QSPIF_BD_ERROR_INVALID_ERASE_PARAMS;
+    }
+
+    // For each iteration erase the largest section supported by current region
+    while (size > 0) {
+        // iterate to find next Largest erase type ( a. supported by region, b. smaller than size)
+        // find the matching instruction and erase size chunk for that type.
+        type = _utils_iterate_next_largest_erase_type(bitfield, size, (int)addr, _region_high_boundary[region]);
+        cur_erase_inst = _erase_type_inst_arr[type];
+        offset = addr % _erase_type_size_arr[type];
+        chunk = ((offset + size) < _erase_type_size_arr[type]) ? size : (_erase_type_size_arr[type] - offset);
+
+        tr_debug("Erase - addr: %llu, size:%d, Inst: 0x%xh, chunk: %lu ",
+                 addr, size, cur_erase_inst, chunk);
+        tr_debug("Erase - Region: %d, Type:%d ",
+                 region, type);
+
+        _mutex.lock();
+
+        if (_set_write_enable() != 0) {
+            tr_error("QSPI Erase Device not ready - failed");
+            erase_failed = true;
+            status = QSPIF_BD_ERROR_READY_FAILED;
+            goto exit_point;
+        }
+
+        if (QSPI_STATUS_OK != _qspi_send_erase_command(cur_erase_inst, addr, size)) {
+            tr_error("QSPI Erase command failed!");
+            erase_failed = true;
+            status = QSPIF_BD_ERROR_DEVICE_ERROR;
+            goto exit_point;
+        }
+
+        addr += chunk;
+        size -= chunk;
+
+        if ((size > 0) && (addr > _region_high_boundary[region])) {
+            // erase crossed to next region
+            region++;
+            bitfield = _region_erase_types_bitfield[region];
+        }
+
+        if (false == _is_mem_ready()) {
+            tr_error("QSPI After Erase Device not ready - failed");
+            erase_failed = true;
+            status = QSPIF_BD_ERROR_READY_FAILED;
+            goto exit_point;
+        }
+
+        _mutex.unlock();
+    }
+
+exit_point:
+    if (erase_failed) {
+        _mutex.unlock();
+    }
+
+    return status;
+}
+
+bd_size_t QSPIFBlockDevice::get_read_size() const
+{
+    // Assuming all devices support 1byte read granularity
+    return QSPIF_DEFAULT_READ_SIZE;
+}
+
+bd_size_t QSPIFBlockDevice::get_program_size() const
+{
+    // Assuming all devices support 1byte program granularity
+    return QSPIF_DEFAULT_PROG_SIZE;
+}
+
+bd_size_t QSPIFBlockDevice::get_erase_size() const
+{
+    // return minimal erase size supported by all regions (0 if none exists)
+    return _min_common_erase_size;
+}
+
+// Find minimal erase size supported by the region to which the address belongs to
+bd_size_t QSPIFBlockDevice::get_erase_size(bd_addr_t addr)
+{
+    // Find region of current address
+    int region = _utils_find_addr_region(addr);
+
+    int min_region_erase_size = _min_common_erase_size;
+    int8_t type_mask = ERASE_BITMASK_TYPE1;
+    int i_ind = 0;
+
+
+    if (region != -1) {
+        type_mask = 0x01;
+
+        for (i_ind = 0; i_ind < 4; i_ind++) {
+            // loop through erase types bitfield supported by region
+            if (_region_erase_types_bitfield[region] & type_mask) {
+
+                min_region_erase_size = _erase_type_size_arr[i_ind];
+                break;
+            }
+            type_mask = type_mask << 1;
+        }
+
+        if (i_ind == 4) {
+            tr_error("No erase type was found for region addr");
+        }
+    }
+
+    return (bd_size_t)min_region_erase_size;
+}
+
+bd_size_t QSPIFBlockDevice::size() const
+{
+    return _device_size_bytes;
+}
+
+int QSPIFBlockDevice::get_erase_value() const
+{
+    return 0xFF;
+}
+
+/********************************/
+/*   Different Device Csel Mgmt */
+/********************************/
+static PinName *generate_initialized_active_qspif_csel_arr()
+{
+    PinName *init_arr = new PinName[QSPIF_MAX_ACTIVE_FLASH_DEVICES];
+    for (int i_ind = 0; i_ind < QSPIF_MAX_ACTIVE_FLASH_DEVICES; i_ind++) {
+        init_arr[i_ind] = NC;
+    }
+    return init_arr;
+}
+
+int QSPIFBlockDevice::add_new_csel_instance(PinName csel)
+{
+    int status = 0;
+    _devices_mutex->lock();
+    if (_number_of_active_qspif_flash_csel >= QSPIF_MAX_ACTIVE_FLASH_DEVICES) {
+        status = -2;
+        goto exit_point;
+    }
+
+    // verify the device is unique(no identical csel already exists)
+    for (int i_ind = 0; i_ind < QSPIF_MAX_ACTIVE_FLASH_DEVICES; i_ind++) {
+        if (_active_qspif_flash_csel_arr[i_ind] == csel) {
+            status = -1;
+            goto exit_point;
+        }
+    }
+
+    // Insert new csel into existing device list
+    for (int i_ind = 0; i_ind < QSPIF_MAX_ACTIVE_FLASH_DEVICES; i_ind++) {
+        if (_active_qspif_flash_csel_arr[i_ind] == NC) {
+            _active_qspif_flash_csel_arr[i_ind] = csel;
+            break;
+        }
+    }
+    _number_of_active_qspif_flash_csel++;
+
+exit_point:
+    _devices_mutex->unlock();
+    return status;
+}
+
+int QSPIFBlockDevice::remove_csel_instance(PinName csel)
+{
+    int status = -1;
+    _devices_mutex->lock();
+    // remove the csel from existing device list
+    for (int i_ind = 0; i_ind < QSPIF_MAX_ACTIVE_FLASH_DEVICES; i_ind++) {
+        if (_active_qspif_flash_csel_arr[i_ind] == csel) {
+            _active_qspif_flash_csel_arr[i_ind] = NC;
+            if (_number_of_active_qspif_flash_csel > 0) {
+                _number_of_active_qspif_flash_csel--;
+            }
+            status = 0;
+            break;
+        }
+    }
+    _devices_mutex->unlock();
+    return status;
+}
+
+/*********************************************************/
+/********** SFDP Parsing and Detection Functions *********/
+/*********************************************************/
+int QSPIFBlockDevice::_sfdp_parse_sector_map_table(uint32_t sector_map_table_addr, size_t sector_map_table_size)
+{
+    uint8_t sector_map_table[SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES]; /* Up To 16 DWORDS = 64 Bytes */
+    uint32_t tmp_region_size = 0;
+    int i_ind = 0;
+    int prev_boundary = 0;
+    // Default set to all type bits 1-4 are common
+    int min_common_erase_type_bits = ERASE_BITMASK_ALL;
+
+
+    qspi_status_t status = _qspi_send_read_command(QSPIF_SFDP, (char *)sector_map_table, sector_map_table_addr /*address*/,
+                                                   sector_map_table_size);
+    if (status != QSPI_STATUS_OK) {
+        tr_error("Init - Read SFDP First Table Failed");
+        return -1;
+    }
+
+    // Currently we support only Single Map Descriptor
+    if (!((sector_map_table[0] & 0x3) == 0x03) && (sector_map_table[1]  == 0x0)) {
+        tr_error("Sector Map - Supporting Only Single! Map Descriptor (not map commands)");
+        return -1;
+    }
+
+    _regions_count = sector_map_table[2] + 1;
+    if (_regions_count > QSPIF_MAX_REGIONS) {
+        tr_error("Supporting up to %d regions, current setup to %d regions - fail",
+                 QSPIF_MAX_REGIONS, _regions_count);
+        return -1;
+    }
+
+    // Loop through Regions and set for each one: size, supported erase types, high boundary offset
+    // Calculate minimum Common Erase Type for all Regions
+    for (i_ind = 0; i_ind < _regions_count; i_ind++) {
+        tmp_region_size = ((*((uint32_t *)&sector_map_table[(i_ind + 1) * 4])) >> 8) & 0x00FFFFFF; // bits 9-32
+        _region_size_bytes[i_ind] = (tmp_region_size + 1) * 256; // Region size is 0 based multiple of 256 bytes;
+        _region_erase_types_bitfield[i_ind] = sector_map_table[(i_ind + 1) * 4] & 0x0F; // bits 1-4
+        min_common_erase_type_bits &= _region_erase_types_bitfield[i_ind];
+        _region_high_boundary[i_ind] = (_region_size_bytes[i_ind] - 1) + prev_boundary;
+        prev_boundary = _region_high_boundary[i_ind] + 1;
+    }
+
+    // Calc minimum Common Erase Size from min_common_erase_type_bits
+    uint8_t type_mask = ERASE_BITMASK_TYPE1;
+    for (i_ind = 0; i_ind < 4; i_ind++) {
+        if (min_common_erase_type_bits & type_mask) {
+            _min_common_erase_size = _erase_type_size_arr[i_ind];
+            break;
+        }
+        type_mask = type_mask << 1;
+    }
+
+    if (i_ind == 4) {
+        // No common erase type was found between regions
+        _min_common_erase_size = 0;
+    }
+
+    return 0;
+}
+
+int QSPIFBlockDevice::_sfdp_parse_basic_param_table(uint32_t basic_table_addr, size_t basic_table_size)
+{
+    uint8_t param_table[SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES]; /* Up To 16 DWORDS = 64 Bytes */
+
+    qspi_status_t status = _qspi_send_read_command(QSPIF_SFDP, (char *)param_table, basic_table_addr /*address*/,
+                                                   basic_table_size);
+    if (status != QSPI_STATUS_OK) {
+        tr_error("Init - Read SFDP First Table Failed");
+        return -1;
+    }
+
+    // Check address size, currently only supports 3byte addresses
+    if ((param_table[2] & 0x4) != 0 || (param_table[7] & 0x80) != 0) {
+        tr_error("Init - verify 3byte addressing Failed");
+        return -1;
+    }
+
+    // Get device density (stored in bits - 1)
+    uint32_t density_bits = (
+                                (param_table[7] << 24) |
+                                (param_table[6] << 16) |
+                                (param_table[5] << 8) |
+                                param_table[4]);
+    _device_size_bytes = (density_bits + 1) / 8;
+
+    // Set Default read/program/erase Instructions
+    _read_instruction = QSPIF_READ;
+    _prog_instruction = QSPIF_PP;
+    _erase_instruction = QSPIF_SE;
+
+    _erase_instruction = _erase4k_inst;
+
+    // Set Page Size (QSPI write must be done on Page limits)
+    _page_size_bytes = _sfdp_detect_page_size(param_table, basic_table_size);
+
+    // Detect and Set Erase Types
+    bool shouldSetQuadEnable = false;
+    bool is_qpi_mode = false;
+
+    _sfdp_detect_erase_types_inst_and_size(param_table, basic_table_size, _erase4k_inst, _erase_type_inst_arr,
+                                           _erase_type_size_arr);
+    _erase_instruction = _erase4k_inst;
+
+    // Detect and Set fastest Bus mode (default 1-1-1)
+    _sfdp_detect_best_bus_read_mode(param_table, basic_table_size, shouldSetQuadEnable, is_qpi_mode, _read_instruction);
+    if (true == shouldSetQuadEnable) {
+        _enable_fast_mdoe();
+        // Set Quad Enable and QPI Bus modes if Supported
+        tr_info("Init - Setting Quad Enable");
+        if (0 != _sfdp_set_quad_enabled(param_table)) {
+            tr_error("Device supports Quad bus, but Quad Enable Failed");
+            return -1;
+        }
+        if (true == is_qpi_mode) {
+            tr_info("Init - Setting QPI mode");
+            _sfdp_set_qpi_enabled(param_table);
+        }
+    }
+    return 0;
+}
+
+int QSPIFBlockDevice::_sfdp_parse_sfdp_headers(uint32_t &basic_table_addr, size_t &basic_table_size,
+                                               uint32_t &sector_map_table_addr, size_t &sector_map_table_size)
+{
+    uint8_t sfdp_header[QSPIF_SFDP_HEADER_SIZE];
+    uint8_t param_header[QSPIF_PARAM_HEADER_SIZE];
+    size_t data_length = QSPIF_SFDP_HEADER_SIZE;
+    bd_addr_t addr = 0x0;
+
+    // Set 1-1-1 bus mode for SFDP header parsing
+    _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE,
+                           QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 8);
+
+    qspi_status_t status = _qspi_send_read_command(QSPIF_SFDP, (char *)sfdp_header, addr /*address*/, data_length);
+    if (status != QSPI_STATUS_OK) {
+        tr_error("Init - Read SFDP Failed");
+        return -1;
+    }
+
+    // Verify SFDP signature for sanity
+    // Also check that major/minor version is acceptable
+    if (!(memcmp(&sfdp_header[0], "SFDP", 4) == 0 && sfdp_header[5] == 1)) {
+        tr_error("Init - _verify SFDP signature and version Failed");
+        return -1;
+    } else {
+        tr_info("Init - verified SFDP Signature and version Successfully");
+    }
+
+    // Discover Number of Parameter Headers
+    int number_of_param_headers = (int)(sfdp_header[6]) + 1;
+    tr_debug("Number of Param Headers: %d", number_of_param_headers);
+
+
+    addr += QSPIF_SFDP_HEADER_SIZE;
+    data_length = QSPIF_PARAM_HEADER_SIZE;
+
+    // Loop over Param Headers and parse them (currently supported Basic Param Table and Sector Region Map Table)
+    for (int i_ind = 0; i_ind < number_of_param_headers; i_ind++) {
+
+        status = _qspi_send_read_command(QSPIF_SFDP, (char *)param_header, addr, data_length);
+        if (status != QSPI_STATUS_OK) {
+            tr_error("Init - Read Param Table %d Failed", i_ind + 1);
+            return -1;
+        }
+
+        // The SFDP spec indicates the standard table is always at offset 0
+        // in the parameter headers, we check just to be safe
+        if (param_header[2] != 1) {
+            tr_error("Param Table %d - Major Version should be 1!", i_ind + 1);
+            return -1;
+        }
+
+        if ((param_header[0] == 0) && (param_header[7] == 0xFF)) {
+            // Found Basic Params Table: LSB=0x00, MSB=0xFF
+            tr_debug("Found Basic Param Table at Table: %d", i_ind + 1);
+            basic_table_addr = ((param_header[6] << 16) | (param_header[5] << 8) | (param_header[4]));
+            // Supporting up to 64 Bytes Table (16 DWORDS)
+            basic_table_size = ((param_header[3] * 4) < SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES) ? (param_header[3] * 4) : 64;
+
+        } else if ((param_header[0] == 81) && (param_header[7] == 0xFF)) {
+            // Found Sector Map Table: LSB=0x81, MSB=0xFF
+            tr_debug("Found Sector Map Table at Table: %d", i_ind + 1);
+            sector_map_table_addr = ((param_header[6] << 16) | (param_header[5] << 8) | (param_header[4]));
+            sector_map_table_size = param_header[3] * 4;
+
+        }
+        addr += QSPIF_PARAM_HEADER_SIZE;
+
+    }
+    return 0;
+}
+
+int QSPIFBlockDevice::_sfdp_set_qpi_enabled(uint8_t *basic_param_table_ptr)
+{
+    uint8_t config_reg[1];
+
+    // QPI 4-4-4 Enable Procedure is specified in 5 Bits
+    uint8_t en_seq_444_value = (((basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_444_MODE_EN_SEQ_BYTE] & 0xF0) >> 4) | ((
+                                                                                                                           basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_444_MODE_EN_SEQ_BYTE + 1] & 0x01) << 4));
+
+    switch (en_seq_444_value) {
+        case 1:
+        case 2:
+            tr_debug("_sfdp_set_qpi_enabled - send command 38h");
+            if (QSPI_STATUS_OK != _qspi_send_general_command(0x38, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0)) {
+                tr_error("_sfdp_set_qpi_enabled - send command 38h Failed");
+            }
+            break;
+
+        case 4:
+            tr_debug("_sfdp_set_qpi_enabled - send command 35h");
+            if (QSPI_STATUS_OK != _qspi_send_general_command(0x35, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0)) {
+                tr_error("_sfdp_set_qpi_enabled - send command 35h Failed");
+            }
+            break;
+
+        case 8:
+            tr_debug("_sfdp_set_qpi_enabled - set config bit 6 and send command 71h");
+            if (QSPI_STATUS_OK != _qspi_send_general_command(0x65, 0x800003, NULL, 0, (char *)config_reg, 1)) {
+                tr_error("_sfdp_set_qpi_enabled - set config bit 6 command 65h Failed");
+            }
+            config_reg[0] |= 0x40; //Set Bit 6
+            if (QSPI_STATUS_OK != _qspi_send_general_command(0x71, 0x800003, NULL, 0, (char *)config_reg, 1)) {
+                tr_error("_sfdp_set_qpi_enabled - send command 71h Failed");
+            }
+            break;
+
+        case 16:
+            tr_debug("_sfdp_set_qpi_enabled - reset config bits 0-7 and send command 61h");
+            if (QSPI_STATUS_OK != _qspi_send_general_command(0x65, QSPI_NO_ADDRESS_COMMAND, NULL, 0, (char *)config_reg, 1)) {
+                tr_error("_sfdp_set_qpi_enabled - send command 65h Failed");
+            }
+            config_reg[0] &= 0x7F; //Reset Bit 7 of CR
+            if (QSPI_STATUS_OK != _qspi_send_general_command(0x61, QSPI_NO_ADDRESS_COMMAND, NULL, 0, (char *)config_reg, 1)) {
+                tr_error("_sfdp_set_qpi_enabled - send command 61 Failed");
+            }
+            break;
+
+        default:
+            tr_warning("_sfdp_set_qpi_enabled - Unsuported En Seq 444 configuration");
+            break;
+    }
+    return 0;
+}
+
+
+
+int QSPIFBlockDevice::_sfdp_set_quad_enabled(uint8_t *basic_param_table_ptr)
+{
+    int sr_read_size = QSPI_MAX_STATUS_REGISTER_SIZE;
+    int sr_write_size = QSPI_MAX_STATUS_REGISTER_SIZE;
+
+    char status_reg_setup[QSPI_MAX_STATUS_REGISTER_SIZE] = {0};
+    char status_reg[QSPI_MAX_STATUS_REGISTER_SIZE] = {0};
+
+    // QUAD Enable procedure is specified by 3 bits
+    uint8_t qer_value = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_QER_BYTE] & 0x70) >> 4;
+
+
+    switch (qer_value) {
+        case 0:
+            tr_debug("Device Does not Have a QE Bit, continue based on Read Inst");
+            return 0;
+
+        case 1:
+        case 4:
+            status_reg_setup[1] = 0x02;  //Bit 1 of Status Reg 2
+            tr_debug("Setting QE Bit, Bit 1 of Status Reg 2");
+            break;
+
+        case 2:
+            status_reg_setup[0] = 0x40; // Bit 6 of Status Reg 1
+            sr_write_size = 1;
+            tr_debug("Setting QE Bit, Bit 6 of Status Reg 1");
+            break;
+
+        case 3:
+            status_reg_setup[0] = 0x80; // Bit 7 of Status Reg 1
+            sr_write_size = 1;
+            _write_register_inst = 0x3E;
+            _read_register_inst = 0x3F;
+            tr_debug("Setting QE Bit, Bit 7 of Status Reg 1");
+            break;
+        case 5:
+            status_reg_setup[1] = 0x2; // Bit 1 of status Reg 2
+            _read_register_inst = 0x35;
+            sr_read_size = 1;
+            tr_debug("Setting QE Bit, Bit 1 of Status Reg 2 -special read command");
+            break;
+        default:
+            tr_warning("_setQuadEnable - Unsuported QER configuration");
+            break;
+    }
+
+    // Configure  BUS Mode to 1_1_1 for all commands other than Read
+    _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE,
+                           QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 0);
+
+    // Read Status Register
+    if (QSPI_STATUS_OK == _qspi_send_general_command(_read_register_inst, QSPI_NO_ADDRESS_COMMAND, NULL, 0,
+                                                     status_reg,
+                                                     sr_read_size)) {   // store received values in status_value
+        tr_debug("Reading Status Register Success: value = 0x%x", (int)status_reg[0]);
+    } else {
+        tr_error("Reading Status Register failed");
+        return -1;
+    }
+
+    // Set Bits for Quad Enable
+    for (int i = 0; i < QSPI_MAX_STATUS_REGISTER_SIZE; i++) {
+        status_reg[i] |= status_reg_setup[i];
+    }
+
+    // Write new Status Register Setup
+    if (_set_write_enable() != 0) {
+        tr_error("Write Enabe failed");
+        return -1;
+    }
+
+    if (QSPI_STATUS_OK == _qspi_send_general_command(_write_register_inst, QSPI_NO_ADDRESS_COMMAND, (char *)status_reg,
+                                                     sr_write_size, NULL,
+                                                     0)) {   // Write QE to status_register
+        tr_debug("_setQuadEnable - Writing Status Register Success: value = 0x%x",
+                 (int)status_reg[0]);
+    } else {
+        tr_error("_setQuadEnable - Writing Status Register failed");
+        return -1;
+    }
+
+    if (false == _is_mem_ready()) {
+        tr_error("Device not ready after write, failed");
+        return -1;
+    }
+
+
+    // For Debug
+    memset(status_reg, 0, QSPI_MAX_STATUS_REGISTER_SIZE);
+    if (QSPI_STATUS_OK == _qspi_send_general_command(_read_register_inst, QSPI_NO_ADDRESS_COMMAND, NULL, 0,
+                                                     (char *)status_reg,
+                                                     sr_read_size)) {   // store received values in status_value
+        tr_debug("Reading Status Register Success: value = 0x%x", (int)status_reg[0]);
+    } else {
+        tr_error("Reading Status Register failed");
+        return -1;
+    }
+
+    return 0;
+}
+
+int QSPIFBlockDevice::_sfdp_detect_page_size(uint8_t *basic_param_table_ptr, int basic_param_table_size)
+{
+    unsigned int page_size = QSPIF_DEFAULT_PAGE_SIZE;
+
+    if (basic_param_table_size > QSPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE) {
+        // Page Size is specified by 4 Bits (N), calculated by 2^N
+        int page_to_power_size = ((int)basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE]) >> 4;
+        page_size = local_math_power(2, page_to_power_size);
+        tr_debug("Detected Page Size: %d", page_size);
+    } else {
+        tr_debug("Using Default Page Size: %d", page_size);
+    }
+    return page_size;
+}
+
+int QSPIFBlockDevice::_sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, int basic_param_table_size,
+                                                             unsigned int &erase4k_inst,
+                                                             unsigned int *erase_type_inst_arr, unsigned int *erase_type_size_arr)
+{
+    erase4k_inst = 0xff;
+    bool found_4Kerase_type = false;
+    uint8_t bitfield = 0x01;
+
+    // Erase 4K Inst is taken either from param table legacy 4K erase or superseded by erase Instruction for type of size 4K
+    erase4k_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_4K_ERASE_TYPE_BYTE];
+
+    if (basic_param_table_size > QSPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE) {
+        // Loop Erase Types 1-4
+        for (int i_ind = 0; i_ind < 4; i_ind++) {
+            erase_type_inst_arr[i_ind] = 0xff; //0xFF default for unsupported type
+            erase_type_size_arr[i_ind] = local_math_power(2,
+                                                          basic_param_table_ptr[QSPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE + 2 * i_ind]); // Size given as 2^N
+            tr_info("Erase Type(A) %d - Inst: 0x%xh, Size: %d", (i_ind + 1), erase_type_inst_arr[i_ind],
+                    erase_type_size_arr[i_ind]);
+            if (erase_type_size_arr[i_ind] > 1) {
+                // if size==1 type is not supported
+                erase_type_inst_arr[i_ind] = basic_param_table_ptr[QSPIF_BASIC_PARAM_ERASE_TYPE_1_BYTE + 2 * i_ind];
+
+                if ((erase_type_size_arr[i_ind] < _min_common_erase_size) || (_min_common_erase_size == 0)) {
+                    //Set default minimal common erase for singal region
+                    _min_common_erase_size = erase_type_size_arr[i_ind];
+                }
+
+                // SFDP standard requires 4K Erase type to exist and its instruction to be identical to legacy field erase instruction
+                if (erase_type_size_arr[i_ind] == 4096) {
+                    found_4Kerase_type = true;
+                    if (erase4k_inst != erase_type_inst_arr[i_ind]) {
+                        //Verify 4KErase Type is identical to Legacy 4K erase type specified in Byte 1 of Param Table
+                        erase4k_inst = erase_type_inst_arr[i_ind];
+                        tr_warning("_detectEraseTypesInstAndSize - Default 4K erase Inst is different than erase type Inst for 4K");
+
+                    }
+                }
+                _region_erase_types_bitfield[0] |= bitfield; // If there's no region map, set region "0" types bitfield as defualt;
+            }
+
+            tr_info("Erase Type %d - Inst: 0x%xh, Size: %d", (i_ind + 1), erase_type_inst_arr[i_ind],
+                    erase_type_size_arr[i_ind]);
+            bitfield = bitfield << 1;
+        }
+    }
+
+    if (false == found_4Kerase_type) {
+        tr_warning("Couldn't find Erase Type for 4KB size");
+    }
+    return 0;
+}
+
+int QSPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table_ptr, int basic_param_table_size,
+                                                      bool &set_quad_enable,
+                                                      bool &is_qpi_mode, unsigned int &read_inst)
+{
+    set_quad_enable = false;
+    is_qpi_mode = false;
+    uint8_t examined_byte;
+
+    do { // compound statement is the loop body
+
+        if (basic_param_table_size > QSPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPORT_BYTE) {
+            examined_byte = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPORT_BYTE];
+
+            if (examined_byte & 0x10) {
+                // QPI 4-4-4 Supported
+                read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_444_READ_INST_BYTE];
+                set_quad_enable = true;
+                is_qpi_mode = true;
+                _dummy_and_mode_cycles = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_444_READ_INST_BYTE - 1] >> 5)
+                                         + (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_444_READ_INST_BYTE - 1] & 0x1F);
+                tr_debug("Read Bus Mode set to 4-4-4, Instruction: 0x%xh", _read_instruction);
+                //_inst_width = QSPI_CFG_BUS_QUAD;
+                _address_width = QSPI_CFG_BUS_QUAD;
+                _data_width = QSPI_CFG_BUS_QUAD;
+
+                break;
+            }
+        }
+
+
+        examined_byte = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_FAST_READ_SUPPORT_BYTE];
+        if (examined_byte & 0x40) {
+            //  Fast Read 1-4-4 Supported
+            read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_144_READ_INST_BYTE];
+            set_quad_enable = true;
+            // dummy cycles + mode cycles = Dummy Cycles
+            _dummy_and_mode_cycles = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_144_READ_INST_BYTE - 1] >> 5)
+                                     + (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_144_READ_INST_BYTE - 1] & 0x1F);
+            _address_width = QSPI_CFG_BUS_QUAD;
+            _data_width = QSPI_CFG_BUS_QUAD;
+            tr_debug("Read Bus Mode set to 1-4-4, Instruction: 0x%xh", _read_instruction);
+            break;
+        }
+
+        if (examined_byte & 0x80) {
+            //  Fast Read 1-1-4 Supported
+            read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_114_READ_INST_BYTE];
+            set_quad_enable = true;
+            _dummy_and_mode_cycles = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_114_READ_INST_BYTE - 1] >> 5)
+                                     + (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_114_READ_INST_BYTE - 1] & 0x1F);
+            _data_width = QSPI_CFG_BUS_QUAD;
+            tr_debug("Read Bus Mode set to 1-1-4, Instruction: 0x%xh", _read_instruction);
+            break;
+        }
+        examined_byte = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPORT_BYTE];
+        if (examined_byte & 0x01) {
+            //  Fast Read 2-2-2 Supported
+            read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE];
+            _dummy_and_mode_cycles = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE - 1] >> 5)
+                                     + (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE - 1] & 0x1F);
+            _address_width = QSPI_CFG_BUS_DUAL;
+            _data_width = QSPI_CFG_BUS_DUAL;
+            tr_info("Read Bus Mode set to 2-2-2, Instruction: 0x%xh", _read_instruction);
+            break;
+        }
+
+        examined_byte = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_FAST_READ_SUPPORT_BYTE];
+        if (examined_byte & 0x20) {
+            //  Fast Read 1-2-2 Supported
+            read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE];
+            _dummy_and_mode_cycles = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE - 1] >> 5)
+                                     + (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE - 1] & 0x1F);
+            _address_width = QSPI_CFG_BUS_DUAL;
+            _data_width = QSPI_CFG_BUS_DUAL;
+            tr_debug("Read Bus Mode set to 1-2-2, Instruction: 0x%xh", _read_instruction);
+            break;
+        }
+        if (examined_byte & 0x01) {
+            // Fast Read 1-1-2 Supported
+            read_inst = basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE];
+            _dummy_and_mode_cycles = (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE - 1] >> 5)
+                                     + (basic_param_table_ptr[QSPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE - 1] & 0x1F);
+            _data_width = QSPI_CFG_BUS_DUAL;
+            tr_debug("Read Bus Mode set to 1-1-2, Instruction: 0x%xh", _read_instruction);
+            break;
+        }
+        tr_debug("Read Bus Mode set to 1-1-1, Instruction: 0x%xh", _read_instruction);
+    } while (false);
+
+    return 0;
+}
+
+int QSPIFBlockDevice::_reset_flash_mem()
+{
+    // Perform Soft Reset of the Device prior to initialization
+    int status = 0;
+    char status_value[QSPI_MAX_STATUS_REGISTER_SIZE] = {0};
+    tr_info("_reset_flash_mem:");
+    //Read the Status Register from device
+    if (QSPI_STATUS_OK == _qspi_send_general_command(QSPIF_RDSR, QSPI_NO_ADDRESS_COMMAND, NULL, 0, status_value,
+                                                     QSPI_MAX_STATUS_REGISTER_SIZE)) {   // store received values in status_value
+        tr_debug("Reading Status Register Success: value = 0x%x", (int)status_value[0]);
+    } else {
+        tr_error("Reading Status Register failed: value = 0x%x", (int)status_value[0]);
+        status = -1;
+    }
+
+    if (0 == status) {
+        //Send Reset Enable
+        if (QSPI_STATUS_OK == _qspi_send_general_command(QSPIF_RSTEN, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL,
+                                                         0)) {    // store received values in status_value
+            tr_debug("Sending RSTEN Success");
+        } else {
+            tr_error("Sending RSTEN failed");
+            status = -1;
+        }
+
+
+        if (0 == status) {
+            //Send Reset
+            if (QSPI_STATUS_OK == _qspi_send_general_command(QSPIF_RST, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL,
+                                                             0)) {   // store received values in status_value
+                tr_debug("Sending RST Success");
+            } else {
+                tr_error("Sending RST failed");
+                status = -1;
+            }
+
+            _is_mem_ready();
+        }
+    }
+
+    return status;
+}
+
+bool QSPIFBlockDevice::_is_mem_ready()
+{
+    // Check Status Register Busy Bit to Verify the Device isn't Busy
+    char status_value[QSPI_MAX_STATUS_REGISTER_SIZE];
+    int retries = 0;
+    bool mem_ready = true;
+
+    do {
+        wait_ms(1);
+        retries++;
+        //Read the Status Register from device
+        memset(status_value, 0xFF, QSPI_MAX_STATUS_REGISTER_SIZE);
+        if (QSPI_STATUS_OK != _qspi_send_general_command(QSPIF_RDSR, QSPI_NO_ADDRESS_COMMAND, NULL, 0, status_value,
+                                                         QSPI_MAX_STATUS_REGISTER_SIZE)) {   // store received values in status_value
+            tr_error("Reading Status Register failed");
+        }
+    } while ((status_value[0] & QSPIF_STATUS_BIT_WIP) != 0 && retries < IS_MEM_READY_MAX_RETRIES);
+
+    if ((status_value[0] & QSPIF_STATUS_BIT_WIP) != 0) {
+        tr_error("_is_mem_ready FALSE: status value = 0x%x ", (int)status_value[0]);
+        mem_ready = false;
+    }
+    return mem_ready;
+}
+
+int QSPIFBlockDevice::_set_write_enable()
+{
+    // Check Status Register Busy Bit to Verify the Device isn't Busy
+    char status_value[QSPI_MAX_STATUS_REGISTER_SIZE];
+    int status = -1;
+
+    do {
+        if (QSPI_STATUS_OK !=  _qspi_send_general_command(QSPIF_WREN, QSPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0)) {
+            tr_error("Sending WREN command FAILED");
+            break;
+        }
+
+        if (false == _is_mem_ready()) {
+            tr_error("Device not ready, write failed");
+            break;
+        }
+
+        memset(status_value, 0, QSPI_MAX_STATUS_REGISTER_SIZE);
+        if (QSPI_STATUS_OK != _qspi_send_general_command(QSPIF_RDSR, QSPI_NO_ADDRESS_COMMAND, NULL, 0, status_value,
+                                                         QSPI_MAX_STATUS_REGISTER_SIZE)) {   // store received values in status_value
+            tr_error("Reading Status Register failed");
+            break;
+        }
+
+        if ((status_value[0] & QSPIF_STATUS_BIT_WEL) == 0) {
+            tr_error("_set_write_enable failed");
+            break;
+        }
+        status = 0;
+    } while (false);
+    return status;
+}
+
+int QSPIFBlockDevice::_enable_fast_mdoe()
+{
+    char status_reg[QSPI_MAX_STATUS_REGISTER_SIZE] = {0};
+    unsigned int read_conf_register_inst = 0x15;
+    char status_reg_qer_setup[QSPI_MAX_STATUS_REGISTER_SIZE] = {0};
+
+    status_reg_qer_setup[2] = 0x2; // Bit 1 of config Reg 2
+
+    // Configure  BUS Mode to 1_1_1 for all commands other than Read
+    _qspi_configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE,
+                           QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 0);
+
+    // Read Status Register
+    if (QSPI_STATUS_OK == _qspi_send_general_command(read_conf_register_inst, QSPI_NO_ADDRESS_COMMAND, NULL, 0,
+                                                     &status_reg[1],
+                                                     QSPI_MAX_STATUS_REGISTER_SIZE - 1)) {  // store received values in status_value
+        tr_debug("Reading Config Register Success: value = 0x%x", (int)status_reg[2]);
+    } else {
+        tr_error("Reading Config Register failed");
+        return -1;
+    }
+
+    // Set Bits for Quad Enable
+    for (int i = 0; i < QSPI_MAX_STATUS_REGISTER_SIZE; i++) {
+        status_reg[i] |= status_reg_qer_setup[i];
+    }
+
+    // Write new Status Register Setup
+    if (_set_write_enable() != 0) {
+        tr_error("Write Enabe failed");
+        return -1;
+    }
+
+    if (QSPI_STATUS_OK == _qspi_send_general_command(_write_register_inst, QSPI_NO_ADDRESS_COMMAND, status_reg,
+                                                     QSPI_MAX_STATUS_REGISTER_SIZE, NULL,
+                                                     0)) {   // Write Fast mode bit to status_register
+        tr_debug("fast mode enable - Writing Config Register Success: value = 0x%x",
+                 (int)status_reg[2]);
+    } else {
+        tr_error("fast mode enable - Writing Config Register failed");
+        return -1;
+    }
+
+    if (false == _is_mem_ready()) {
+        tr_error("Device not ready after write, failed");
+        return -1;
+    }
+
+    // For Debug
+    memset(status_reg, 0, QSPI_MAX_STATUS_REGISTER_SIZE);
+    if (QSPI_STATUS_OK == _qspi_send_general_command(read_conf_register_inst, QSPI_NO_ADDRESS_COMMAND, NULL, 0,
+                                                     &status_reg[1],
+                                                     QSPI_MAX_STATUS_REGISTER_SIZE - 1)) {  // store received values in status_value
+        tr_debug("Verifying Config Register Success: value = 0x%x", (int)status_reg[2]);
+    } else {
+        tr_error("Verifying Config Register failed");
+        return -1;
+    }
+
+    return 0;
+}
+
+/*********************************************/
+/************* Utility Functions *************/
+/*********************************************/
+int QSPIFBlockDevice::_utils_find_addr_region(bd_size_t offset)
+{
+    //Find the region to which the given offset belong to
+    if ((offset > _device_size_bytes) || (_regions_count == 0)) {
+        return -1;
+    }
+
+    if (_regions_count == 1) {
+        return 0;
+    }
+
+    for (int i_ind = _regions_count - 2; i_ind >= 0; i_ind--) {
+
+        if (offset > _region_high_boundary[i_ind]) {
+            return (i_ind + 1);
+        }
+    }
+    return -1;
+
+}
+
+int QSPIFBlockDevice::_utils_iterate_next_largest_erase_type(uint8_t &bitfield, int size, int offset, int boundry)
+{
+    // Iterate on all supported Erase Types of the Region to which the offset belong to.
+    // Iterates from highest type to lowest
+    uint8_t type_mask = ERASE_BITMASK_TYPE4;
+    int i_ind  = 0;
+    int largest_erase_type = 0;
+    for (i_ind = 3; i_ind >= 0; i_ind--) {
+        if (bitfield & type_mask) {
+            largest_erase_type = i_ind;
+            if ((size > (int)(_erase_type_size_arr[largest_erase_type])) &&
+                    ((boundry - offset) > (int)(_erase_type_size_arr[largest_erase_type]))) {
+                break;
+            } else {
+                bitfield &= ~type_mask;
+            }
+        }
+        type_mask = type_mask >> 1;
+    }
+
+    if (i_ind == 4) {
+        tr_error("No erase type was found for current region addr");
+    }
+    return largest_erase_type;
+
+}
+
+/***************************************************/
+/*********** QSPI Driver API Functions *************/
+/***************************************************/
+qspi_status_t QSPIFBlockDevice::_qspi_set_frequency(int freq)
+{
+    return _qspi.set_frequency(freq);
+}
+
+qspi_status_t QSPIFBlockDevice::_qspi_send_read_command(unsigned int read_inst, void *buffer, bd_addr_t addr,
+                                                        bd_size_t size)
+{
+    // Send Read command to device driver
+    size_t buf_len = size;
+
+    if (_qspi.read(read_inst, -1, (unsigned int)addr, (char *)buffer, &buf_len) != QSPI_STATUS_OK) {
+        tr_error("Read failed");
+        return QSPI_STATUS_ERROR;
+    }
+
+    return QSPI_STATUS_OK;
+
+}
+
+qspi_status_t QSPIFBlockDevice::_qspi_send_program_command(unsigned int progInst, const void *buffer, bd_addr_t addr,
+                                                           bd_size_t *size)
+{
+    // Send Program (write) command to device driver
+    qspi_status_t result = QSPI_STATUS_OK;
+
+    result = _qspi.write(progInst, -1, addr, (char *)buffer, (size_t *)size);
+    if (result != QSPI_STATUS_OK) {
+        tr_error("QSPI Write failed");
+    }
+
+    return result;
+}
+
+qspi_status_t QSPIFBlockDevice::_qspi_send_erase_command(unsigned int erase_inst, bd_addr_t addr, bd_size_t size)
+{
+    // Send Erase Instruction command to driver
+    qspi_status_t result = QSPI_STATUS_OK;
+
+    tr_info("Inst: 0x%xh, addr: %llu, size: %llu", erase_inst, addr, size);
+
+    result = _qspi.command_transfer(erase_inst, // command to send
+                                    (((int)addr) & 0x00FFF000), // Align addr to 4096
+                                    NULL,                 // do not transmit
+                                    0,              // do not transmit
+                                    NULL,                 // just receive two bytes of data
+                                    0); // store received values in status_value
+
+    if (QSPI_STATUS_OK != result) {
+        tr_error("QSPI Erase failed");
+    }
+
+    return result;
+
+}
+
+qspi_status_t QSPIFBlockDevice::_qspi_send_general_command(unsigned int instruction, bd_addr_t addr,
+                                                           const char *tx_buffer,
+                                                           size_t tx_length, const char *rx_buffer, size_t rx_length)
+{
+    // Send a general command Instruction to driver
+    qspi_status_t status = _qspi.command_transfer(instruction, (int)addr, tx_buffer, tx_length, rx_buffer, rx_length);
+
+    if (QSPI_STATUS_OK != status) {
+        tr_error("Sending Generic command: %x", instruction);
+    }
+
+    return status;
+}
+
+qspi_status_t QSPIFBlockDevice::_qspi_configure_format(qspi_bus_width_t inst_width, qspi_bus_width_t address_width,
+                                                       qspi_address_size_t address_size, qspi_bus_width_t alt_width, qspi_alt_size_t alt_size, qspi_bus_width_t data_width,
+                                                       int dummy_cycles)
+{
+    // Configure QSPI driver Bus format
+    qspi_status_t status = _qspi.configure_format(inst_width, address_width, address_size, alt_width, alt_size, data_width,
+                                                  dummy_cycles);
+
+    return status;
+}
+
+/*********************************************/
+/************** Local Functions **************/
+/*********************************************/
+static int local_math_power(int base, int exp)
+{
+    // Integer X^Y function, used to calculate size fields given in 2^N format
+    int result = 1;
+    while (exp) {
+        result *= base;
+        exp--;
+    }
+    return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/storage/COMPONENT_QSPIF/QSPIFBlockDevice.h	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,364 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2018 ARM Limited
+ *
+ * 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.
+ */
+#ifndef MBED_QSPIF_BLOCK_DEVICE_H
+#define MBED_QSPIF_BLOCK_DEVICE_H
+
+#include "QSPI.h"
+#include "BlockDevice.h"
+
+/** Enum qspif standard error codes
+ *
+ *  @enum qspif_bd_error
+ */
+enum qspif_bd_error {
+    QSPIF_BD_ERROR_OK                    = 0,     /*!< no error */
+    QSPIF_BD_ERROR_DEVICE_ERROR          = BD_ERROR_DEVICE_ERROR, /*!< device specific error -4001 */
+    QSPIF_BD_ERROR_PARSING_FAILED        = -4002, /* SFDP Parsing failed */
+    QSPIF_BD_ERROR_READY_FAILED          = -4003, /* Wait for  Mem Ready failed */
+    QSPIF_BD_ERROR_WREN_FAILED           = -4004, /* Write Enable Failed */
+    QSPIF_BD_ERROR_INVALID_ERASE_PARAMS  = -4005, /* Erase command not on sector aligned addresses or exceeds device size */
+    QSPIF_BD_ERROR_DEVICE_NOT_UNIQE      = -4006, /* Only one instance per csel is allowed */
+    QSPIF_BD_ERROR_DEVICE_MAX_EXCEED     = -4007 /* Max active QSPIF devices exceeded */
+};
+
+/** Enum qspif polarity mode
+ *
+ *  @enum qspif_polarity_mode
+ */
+enum qspif_polarity_mode {
+    QSPIF_POLARITY_MODE_0 = 0, /* CPOL=0, CPHA=0 */
+    QSPIF_POLARITY_MODE_1      /* CPOL=1, CPHA=1 */
+};
+
+#define QSPIF_MAX_REGIONS   10
+#define MAX_NUM_OF_ERASE_TYPES 4
+#define QSPIF_MAX_ACTIVE_FLASH_DEVICES 10
+
+/** BlockDevice for SFDP based flash devices over QSPI bus
+ *
+ *  @code
+ *  // Here's an example using QSPI flash device on DISCO_L476VG target
+ *  #include "mbed.h"
+ *  #include "QSPIFBlockDevice.h"
+ *
+ *  QSPIFBlockDevice block_device(QSPI_FLASH1_IO0, QSPI_FLASH1_IO1, QSPI_FLASH1_IO2, QSPI_FLASH1_IO3,
+ *                                QSPI_FLASH1_SCK, QSPI_FLASH1_CSN, QSPIF_POLARITY_MODE_0, MBED_CONF_QSPIF_QSPI_FREQ);
+ *
+ *  int main()
+ *  {
+ *      printf("QSPI SFDP Flash Block Device example\n");
+ *
+ *      // Initialize the SPI flash device and print the memory layout
+ *      block_device.init();
+ *      bd_size_t sector_size_at_address_0 = block_device.get_erase_size(0);
+ *
+ *      printf("QSPIF BD size: %llu\n",         block_device.size());
+ *      printf("QSPIF BD read size: %llu\n",    block_device.get_read_size());
+ *      printf("QSPIF BD program size: %llu\n", block_device.get_program_size());
+ *      printf("QSPIF BD erase size (at address 0): %llu\n", sector_size_at_address_0);
+ *
+ *      // Write "Hello World!" to the first block
+ *      char *buffer = (char *) malloc(sector_size_at_address_0);
+ *      sprintf(buffer, "Hello World!\n");
+ *      block_device.erase(0, sector_size_at_address_0);
+ *      block_device.program(buffer, 0, sector_size_at_address_0);
+ *
+ *      // Read back what was stored
+ *      block_device.read(buffer, 0, sector_size_at_address_0);
+ *      printf("%s", buffer);
+ *
+ *      // Deinitialize the device
+ *      block_device.deinit();
+ *  }
+ *  @endcode
+ */
+class QSPIFBlockDevice : public BlockDevice {
+public:
+    /** Create QSPIFBlockDevice - An SFDP based Flash Block Device over QSPI bus
+     *
+     *  @param io0 1st IO pin used for sending/receiving data during data phase of a transaction
+     *  @param io1 2nd IO pin used for sending/receiving data during data phase of a transaction
+     *  @param io2 3rd IO pin used for sending/receiving data during data phase of a transaction
+     *  @param io3 4th IO pin used for sending/receiving data during data phase of a transaction
+     *  @param sclk QSPI Clock pin
+     *  @param csel QSPI chip select pin
+     *  @param clock_mode specifies the QSPI Clock Polarity mode (QSPIF_POLARITY_MODE_0/QSPIF_POLARITY_MODE_1)
+     *         default value = 0
+     *  @param freq Clock frequency of the QSPI bus (defaults to 40MHz)
+     *
+     */
+    QSPIFBlockDevice(PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName csel,
+                     int clock_mode, int freq = MBED_CONF_QSPIF_QSPI_FREQ);
+
+    /** Initialize a block device
+     *
+     *  @return         QSPIF_BD_ERROR_OK(0) - success
+     *                  QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
+     *                  QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timedout
+     *                  QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
+     */
+    virtual int init();
+
+    /** Deinitialize a block device
+     *
+     *  @return         QSPIF_BD_ERROR_OK(0) - success
+     *                  QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
+     */
+    virtual int deinit();
+
+    /** Desctruct QSPIFBlockDevie
+      */
+    ~QSPIFBlockDevice()
+    {
+        deinit();
+    }
+
+    /** Read blocks from a block device
+     *
+     *  @param buffer   Buffer to write blocks to
+     *  @param addr     Address of block to begin reading from
+     *  @param size     Size to read in bytes, must be a multiple of read block size
+     *  @return         QSPIF_BD_ERROR_OK(0) - success
+     *                  QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
+     */
+    virtual int read(void *buffer, bd_addr_t addr, bd_size_t size);
+
+    /** Program blocks to a block device
+     *
+     *  The blocks must have been erased prior to being programmed
+     *
+     *  @param buffer   Buffer of data to write to blocks
+     *  @param addr     Address of block to begin writing to
+     *  @param size     Size to write in bytes, must be a multiple of program block size
+     *  @return         QSPIF_BD_ERROR_OK(0) - success
+     *                  QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
+     *                  QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
+     *                  QSPIF_BD_ERROR_WREN_FAILED - Write Enable failed
+     *                  QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
+     */
+    virtual int program(const void *buffer, bd_addr_t addr, bd_size_t size);
+
+    /** Erase blocks on a block device
+     *
+     *  The state of an erased block is undefined until it has been programmed
+     *
+     *  @param addr     Address of block to begin erasing
+     *  @param size     Size to erase in bytes, must be a multiple of erase block size
+     *  @return         QSPIF_BD_ERROR_OK(0) - success
+     *                  QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
+     *                  QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
+     *                  QSPIF_BD_ERROR_WREN_FAILED - Write Enable failed
+     *                  QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
+     *                  QSPIF_BD_ERROR_INVALID_ERASE_PARAMS - Trying to erase unaligned address or size
+     */
+    virtual int erase(bd_addr_t addr, bd_size_t size);
+
+    /** Get the size of a readable block
+     *
+     *  @return         Size of a readable block in bytes
+     */
+    virtual bd_size_t get_read_size() const;
+
+    /** Get the size of a programable block
+     *
+     *  @return         Size of a program block size in bytes
+     *  @note Must be a multiple of the read size
+     */
+    virtual bd_size_t get_program_size() const;
+
+    /** Get the size of a eraseable block
+     *
+     *  @return         Size of a minimal erase block, common to all regions, in bytes
+     *  @note Must be a multiple of the program size
+     */
+    virtual bd_size_t get_erase_size() const;
+
+    /** Get the size of minimal eraseable sector size of given address
+     *
+     *  @param addr     Any address within block queried for erase sector size (can be any address within flash size offset)
+     *  @return         Size of minimal erase sector size, in given address region, in bytes
+     *  @note Must be a multiple of the program size
+     */
+    virtual bd_size_t get_erase_size(bd_addr_t addr);
+
+    /** Get the value of storage byte after it was erased
+     *
+     *  If get_erase_value returns a non-negative byte value, the underlying
+     *  storage is set to that value when erased, and storage containing
+     *  that value can be programmed without another erase.
+     *
+     *  @return         The value of storage when erased, or -1 if you can't
+     *                  rely on the value of erased storage
+     */
+    virtual int get_erase_value() const;
+
+    /** Get the total size of the underlying device
+     *
+     *  @return         Size of the underlying device in bytes
+     */
+    virtual bd_size_t size() const;
+
+private:
+    // Internal functions
+
+
+    /********************************/
+    /*   Different Device Csel Mgmt */
+    /********************************/
+    // Add a new QSPI device CS to existing devices list.
+    // Only one QSPIFBlockDevice instance per CS is allowed
+    int add_new_csel_instance(PinName csel);
+
+    // Remove device CS from existing device list upon destroying object (last deinit is called)
+    int remove_csel_instance(PinName csel);
+
+    /********************************/
+    /*   Calls to QSPI Driver APIs  */
+    /********************************/
+    // Send Program => Write command to Driver
+    qspi_status_t _qspi_send_program_command(unsigned int prog_instruction, const void *buffer, bd_addr_t addr,
+                                             bd_size_t *size);
+
+    // Send Read command to Driver
+    qspi_status_t _qspi_send_read_command(unsigned int read_instruction, void *buffer, bd_addr_t addr, bd_size_t size);
+
+    // Send Erase Instruction using command_transfer command to Driver
+    qspi_status_t _qspi_send_erase_command(unsigned int erase_instruction, bd_addr_t addr, bd_size_t size);
+
+    // Send Generic command_transfer command to Driver
+    qspi_status_t _qspi_send_general_command(unsigned int instruction_int, bd_addr_t addr, const char *tx_buffer,
+                                             size_t tx_length, const char *rx_buffer, size_t rx_length);
+
+    // Send Bus configure_format command to Driver
+    qspi_status_t _qspi_configure_format(qspi_bus_width_t inst_width, qspi_bus_width_t address_width,
+                                         qspi_address_size_t address_size, qspi_bus_width_t alt_width, qspi_alt_size_t alt_size, qspi_bus_width_t data_width,
+                                         int dummy_cycles);
+
+    // Send set_frequency command to Driver
+    qspi_status_t _qspi_set_frequency(int freq);
+
+    /*********************************/
+    /* Flash Configuration Functions */
+    /*********************************/
+    // Soft Reset Flash Memory
+    int _reset_flash_mem();
+
+    // Configure Write Enable in Status Register
+    int _set_write_enable();
+
+    // Wait on status register until write not-in-progress
+    bool _is_mem_ready();
+
+    // Enable Fast Mode - for flash chips with low power default
+    int _enable_fast_mdoe();
+
+    /****************************************/
+    /* SFDP Detection and Parsing Functions */
+    /****************************************/
+    // Parse SFDP Headers and retrieve Basic Param and Sector Map Tables (if exist)
+    int _sfdp_parse_sfdp_headers(uint32_t &basic_table_addr, size_t &basic_table_size,
+                                 uint32_t &sector_map_table_addr, size_t &sector_map_table_size);
+
+    // Parse and Detect required Basic Parameters from Table
+    int _sfdp_parse_basic_param_table(uint32_t basic_table_addr, size_t basic_table_size);
+
+    // Parse and read information required by Regions Secotr Map
+    int _sfdp_parse_sector_map_table(uint32_t sector_map_table_addr, size_t sector_map_table_size);
+
+    // Detect fastest read Bus mode supported by device
+    int _sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table_ptr, int basic_param_table_size, bool &set_quad_enable,
+                                        bool &is_qpi_mode, unsigned int &read_inst);
+
+    // Enable Quad mode if supported (1-1-4, 1-4-4, 4-4-4 bus modes)
+    int _sfdp_set_quad_enabled(uint8_t *basic_param_table_ptr);
+
+    // Enable QPI mode (4-4-4) is supported
+    int _sfdp_set_qpi_enabled(uint8_t *basic_param_table_ptr);
+
+    // Set Page size for program
+    int _sfdp_detect_page_size(uint8_t *basic_param_table_ptr, int basic_param_table_size);
+
+    // Detect all supported erase types
+    int _sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, int basic_param_table_size,
+                                               unsigned int &erase4k_inst,
+                                               unsigned int *erase_type_inst_arr, unsigned int *erase_type_size_arr);
+
+    /***********************/
+    /* Utilities Functions */
+    /***********************/
+    // Find the region to which the given offset belong to
+    int _utils_find_addr_region(bd_size_t offset);
+
+    // Iterate on all supported Erase Types of the Region to which the offset belong to.
+    // Iterates from highest type to lowest
+    int _utils_iterate_next_largest_erase_type(uint8_t &bitfield, int size, int offset, int boundry);
+
+private:
+    // Internal Members
+
+    // QSPI Driver Object
+    mbed::QSPI _qspi;
+
+    // Static List of different QSPI based Flash devices csel that already exist
+    // Each QSPI Flash device csel can have only 1 QSPIFBlockDevice instance
+    // _devices_mutex is used to lock csel list - only one QSPIFBlockDevice instance per csel is allowed
+    static SingletonPtr<PlatformMutex> _devices_mutex;
+    static int _number_of_active_qspif_flash_csel;
+    static PinName *_active_qspif_flash_csel_arr;
+
+    int _unique_device_status;
+    PinName _csel;
+
+    // Mutex is used to protect Flash device for some QSPI Driver commands that must be done sequentially with no other commands in between
+    // e.g. (1)Set Write Enable, (2)Program, (3)Wait Memory Ready
+    PlatformMutex _mutex;
+
+    // Command Instructions
+    unsigned int _read_instruction;
+    unsigned int _prog_instruction;
+    unsigned int _erase_instruction;
+    unsigned int _erase4k_inst;  // Legacy 4K erase instruction (default 0x20h)
+    unsigned int _write_register_inst; // Write status/config register instruction may vary between chips
+    unsigned int _read_register_inst; // Read status/config register instruction may vary between chips
+
+    // Up To 4 Erase Types are supported by SFDP (each with its own command Instruction and Size)
+    unsigned int _erase_type_inst_arr[MAX_NUM_OF_ERASE_TYPES];
+    unsigned int _erase_type_size_arr[MAX_NUM_OF_ERASE_TYPES];
+
+    // Sector Regions Map
+    int _regions_count; //number of regions
+    int _region_size_bytes[QSPIF_MAX_REGIONS]; //regions size in bytes
+    bd_size_t _region_high_boundary[QSPIF_MAX_REGIONS]; //region high address offset boundary
+    //Each Region can support a bit combination of any of the 4 Erase Types
+    uint8_t _region_erase_types_bitfield[QSPIF_MAX_REGIONS];
+    unsigned int _min_common_erase_size; // minimal common erase size for all regions (0 if none exists)
+
+    unsigned int _page_size_bytes; // Page size - 256 Bytes default
+    int _freq;
+    bd_size_t _device_size_bytes;
+
+    // Bus speed configuration
+    qspi_bus_width_t _inst_width; //Bus width for Instruction phase
+    qspi_bus_width_t _address_width; //Bus width for Address phase
+    qspi_address_size_t _address_size; // number of bytes for address
+    qspi_bus_width_t _data_width; //Bus width for Data phase
+    int _dummy_and_mode_cycles; // Number of Dummy and Mode Bits required by Current Bus Mode
+
+    uint32_t _init_ref_count;
+    bool _is_initialized;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/storage/COMPONENT_QSPIF/TESTS/block_device/qspif/main.cpp	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,292 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2018 ARM Limited
+ *
+ * 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 "greentea-client/test_env.h"
+#include "unity.h"
+#include "utest.h"
+#include "QSPIFBlockDevice.h"
+#include "mbed_trace.h"
+#include "rtos/Thread.h"
+#include <stdlib.h>
+
+using namespace utest::v1;
+
+#define TEST_BLOCK_COUNT 10
+#define TEST_ERROR_MASK 16
+#define QSPIF_TEST_NUM_OF_THREADS 5
+
+const struct {
+    const char *name;
+    bd_size_t (BlockDevice::*method)() const;
+} ATTRS[] = {
+    {"read size",    &BlockDevice::get_read_size},
+    {"program size", &BlockDevice::get_program_size},
+    {"erase size",   &BlockDevice::get_erase_size},
+    {"total size",   &BlockDevice::size},
+};
+
+static SingletonPtr<PlatformMutex> _mutex;
+
+
+// Mutex is protecting rand() per srand for buffer writing and verification.
+// Mutex is also protecting printouts for clear logs.
+// Mutex is NOT protecting Block Device actions: erase/program/read - which is the purpose of the multithreaded test!
+void basic_erase_program_read_test(QSPIFBlockDevice &blockD, bd_size_t block_size, uint8_t *write_block,
+                                   uint8_t *read_block, unsigned addrwidth)
+{
+    int err = 0;
+    _mutex->lock();
+    // Find a random block
+    bd_addr_t block = (rand() * block_size) % blockD.size();
+
+    // Use next random number as temporary seed to keep
+    // the address progressing in the pseudorandom sequence
+    unsigned seed = rand();
+
+    // Fill with random sequence
+    srand(seed);
+    for (bd_size_t i_ind = 0; i_ind < block_size; i_ind++) {
+        write_block[i_ind] = 0xff & rand();
+    }
+    // Write, sync, and read the block
+    utest_printf("\ntest  %0*llx:%llu...", addrwidth, block, block_size);
+    _mutex->unlock();
+
+    err = blockD.erase(block, block_size);
+    TEST_ASSERT_EQUAL(0, err);
+
+    err = blockD.program(write_block, block, block_size);
+    TEST_ASSERT_EQUAL(0, err);
+
+    err = blockD.read(read_block, block, block_size);
+    TEST_ASSERT_EQUAL(0, err);
+
+    _mutex->lock();
+    // Check that the data was unmodified
+    srand(seed);
+    int val_rand;
+    for (bd_size_t i_ind = 0; i_ind < block_size; i_ind++) {
+        val_rand = rand();
+        if ((0xff & val_rand) != read_block[i_ind]) {
+            utest_printf("\n Assert Failed Buf Read - block:size: %llx:%llu \n", block, block_size);
+            utest_printf("\n pos: %llu, exp: %02x, act: %02x, wrt: %02x \n", i_ind, (0xff & val_rand), read_block[i_ind],
+                         write_block[i_ind]);
+        }
+        TEST_ASSERT_EQUAL(0xff & val_rand, read_block[i_ind]);
+    }
+    _mutex->unlock();
+}
+
+void test_qspif_random_program_read_erase()
+{
+    utest_printf("\nTest Random Program Read Erase Starts..\n");
+
+    QSPIFBlockDevice blockD(QSPI_FLASH1_IO0, QSPI_FLASH1_IO1, QSPI_FLASH1_IO2, QSPI_FLASH1_IO3,
+                            QSPI_FLASH1_SCK, QSPI_FLASH1_CSN, QSPIF_POLARITY_MODE_0, MBED_CONF_QSPIF_QSPI_FREQ);
+
+    int err = blockD.init();
+    TEST_ASSERT_EQUAL(0, err);
+
+    for (unsigned atr = 0; atr < sizeof(ATTRS) / sizeof(ATTRS[0]); atr++) {
+        static const char *prefixes[] = {"", "k", "M", "G"};
+        for (int i_ind = 3; i_ind >= 0; i_ind--) {
+            bd_size_t size = (blockD.*ATTRS[atr].method)();
+            if (size >= (1ULL << 10 * i_ind)) {
+                utest_printf("%s: %llu%sbytes (%llubytes)\n",
+                             ATTRS[atr].name, size >> 10 * i_ind, prefixes[i_ind], size);
+                break;
+            }
+        }
+    }
+
+    bd_size_t block_size = blockD.get_erase_size();
+    unsigned addrwidth = ceil(log(float(blockD.size() - 1)) / log(float(16))) + 1;
+
+    uint8_t *write_block = new (std::nothrow) uint8_t[block_size];
+    uint8_t *read_block = new (std::nothrow) uint8_t[block_size];
+    if (!write_block || !read_block) {
+        utest_printf("\n Not enough memory for test");
+        goto end;
+    }
+
+    for (int b = 0; b < TEST_BLOCK_COUNT; b++) {
+        basic_erase_program_read_test(blockD, block_size, write_block, read_block, addrwidth);
+    }
+
+    err = blockD.deinit();
+    TEST_ASSERT_EQUAL(0, err);
+
+end:
+    delete[] write_block;
+    delete[] read_block;
+}
+
+void test_qspif_unaligned_erase()
+{
+
+    utest_printf("\nTest Unaligned Erase Starts..\n");
+
+    QSPIFBlockDevice blockD(QSPI_FLASH1_IO0, QSPI_FLASH1_IO1, QSPI_FLASH1_IO2, QSPI_FLASH1_IO3,
+                            QSPI_FLASH1_SCK, QSPI_FLASH1_CSN, QSPIF_POLARITY_MODE_0, MBED_CONF_QSPIF_QSPI_FREQ);
+
+    int err = blockD.init();
+    TEST_ASSERT_EQUAL(0, err);
+
+    for (unsigned atr = 0; atr < sizeof(ATTRS) / sizeof(ATTRS[0]); atr++) {
+        static const char *prefixes[] = {"", "k", "M", "G"};
+        for (int i_ind = 3; i_ind >= 0; i_ind--) {
+            bd_size_t size = (blockD.*ATTRS[atr].method)();
+            if (size >= (1ULL << 10 * i_ind)) {
+                utest_printf("%s: %llu%sbytes (%llubytes)\n",
+                             ATTRS[atr].name, size >> 10 * i_ind, prefixes[i_ind], size);
+                break;
+            }
+        }
+    }
+
+    bd_addr_t addr = 0;
+    bd_size_t sector_erase_size = blockD.get_erase_size(addr);
+    unsigned addrwidth = ceil(log(float(blockD.size() - 1)) / log(float(16))) + 1;
+
+    utest_printf("\ntest  %0*llx:%llu...", addrwidth, addr, sector_erase_size);
+
+    //unaligned start address
+    addr += 1;
+    err = blockD.erase(addr, sector_erase_size - 1);
+    TEST_ASSERT_EQUAL(QSPIF_BD_ERROR_INVALID_ERASE_PARAMS, err);
+
+    err = blockD.erase(addr, sector_erase_size);
+    TEST_ASSERT_EQUAL(QSPIF_BD_ERROR_INVALID_ERASE_PARAMS, err);
+
+    err = blockD.erase(addr, 1);
+    TEST_ASSERT_EQUAL(QSPIF_BD_ERROR_INVALID_ERASE_PARAMS, err);
+
+    //unaligned end address
+    addr = 0;
+
+    err = blockD.erase(addr, 1);
+    TEST_ASSERT_EQUAL(QSPIF_BD_ERROR_INVALID_ERASE_PARAMS, err);
+
+    err = blockD.erase(addr, sector_erase_size + 1);
+    TEST_ASSERT_EQUAL(QSPIF_BD_ERROR_INVALID_ERASE_PARAMS, err);
+
+    //erase size exceeds flash device size
+    err = blockD.erase(addr, blockD.size() + 1);
+    TEST_ASSERT_EQUAL(QSPIF_BD_ERROR_INVALID_ERASE_PARAMS, err);
+
+    // Valid erase
+    err = blockD.erase(addr, sector_erase_size);
+    TEST_ASSERT_EQUAL(QSPIF_BD_ERROR_OK, err);
+
+    err = blockD.deinit();
+    TEST_ASSERT_EQUAL(0, err);
+}
+
+
+
+static void test_qspif_thread_job(void *vBlockD/*, int thread_num*/)
+{
+    static int thread_num = 0;
+    thread_num++;
+    QSPIFBlockDevice *blockD = (QSPIFBlockDevice *)vBlockD;
+    utest_printf("\n Thread %d Started \n", thread_num);
+
+    bd_size_t block_size = blockD->get_erase_size();
+    unsigned addrwidth = ceil(log(float(blockD->size() - 1)) / log(float(16))) + 1;
+
+    uint8_t *write_block = new (std::nothrow) uint8_t[block_size];
+    uint8_t *read_block = new (std::nothrow) uint8_t[block_size];
+    if (!write_block || !read_block) {
+        utest_printf("\n Not enough memory for test");
+        goto end;
+    }
+
+    for (int b = 0; b < TEST_BLOCK_COUNT; b++) {
+        basic_erase_program_read_test((*blockD), block_size, write_block, read_block, addrwidth);
+    }
+
+end:
+    delete[] write_block;
+    delete[] read_block;
+}
+
+void test_qspif_multi_threads()
+{
+
+    utest_printf("\nTest Multi Threaded Erase/Program/Read Starts..\n");
+
+    QSPIFBlockDevice blockD(QSPI_FLASH1_IO0, QSPI_FLASH1_IO1, QSPI_FLASH1_IO2, QSPI_FLASH1_IO3,
+                            QSPI_FLASH1_SCK, QSPI_FLASH1_CSN, QSPIF_POLARITY_MODE_0, MBED_CONF_QSPIF_QSPI_FREQ);
+
+    int err = blockD.init();
+    TEST_ASSERT_EQUAL(0, err);
+
+    for (unsigned atr = 0; atr < sizeof(ATTRS) / sizeof(ATTRS[0]); atr++) {
+        static const char *prefixes[] = {"", "k", "M", "G"};
+        for (int i_ind = 3; i_ind >= 0; i_ind--) {
+            bd_size_t size = (blockD.*ATTRS[atr].method)();
+            if (size >= (1ULL << 10 * i_ind)) {
+                utest_printf("%s: %llu%sbytes (%llubytes)\n",
+                             ATTRS[atr].name, size >> 10 * i_ind, prefixes[i_ind], size);
+                break;
+            }
+        }
+    }
+
+    rtos::Thread qspif_bd_thread[QSPIF_TEST_NUM_OF_THREADS];
+
+    osStatus threadStatus;
+    int i_ind;
+
+    for (i_ind = 0; i_ind < QSPIF_TEST_NUM_OF_THREADS; i_ind++) {
+        threadStatus = qspif_bd_thread[i_ind].start(test_qspif_thread_job, (void *)&blockD);
+        if (threadStatus != 0) {
+            utest_printf("\n Thread %d Start Failed!", i_ind + 1);
+        }
+    }
+
+    for (i_ind = 0; i_ind < QSPIF_TEST_NUM_OF_THREADS; i_ind++) {
+        qspif_bd_thread[i_ind].join();
+    }
+
+    err = blockD.deinit();
+    TEST_ASSERT_EQUAL(0, err);
+}
+
+
+
+
+// Test setup
+utest::v1::status_t test_setup(const size_t number_of_cases)
+{
+    GREENTEA_SETUP(60, "default_auto");
+    return verbose_test_setup_handler(number_of_cases);
+}
+
+Case cases[] = {
+    Case("Testing unaligned erase blocks", test_qspif_unaligned_erase),
+    Case("Testing read write random blocks", test_qspif_random_program_read_erase),
+    Case("Testing Multi Threads Erase Program Read", test_qspif_multi_threads)
+};
+
+Specification specification(test_setup, cases);
+
+
+int main()
+{
+    mbed_trace_init();
+    utest_printf("MAIN STARTS\n");
+    return !Harness::run(specification);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/storage/COMPONENT_QSPIF/mbed_lib.json	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,30 @@
+{
+"name": "qspif",
+    "config": {
+        "QSPI_IO0": "QSPI_FLASH1_IO0",
+        "QSPI_IO1": "QSPI_FLASH1_IO1",
+        "QSPI_IO2": "QSPI_FLASH1_IO2",
+        "QSPI_IO3": "QSPI_FLASH1_IO3",
+        "QSPI_SCK": "QSPI_FLASH1_SCK",
+        "QSPI_CSN": "QSPI_FLASH1_CSN",
+        "QSPI_POLARITY_MODE": 0,
+        "QSPI_FREQ": "40000000"
+    },
+    "target_overrides": {
+        "DISCO_F413ZH": {
+            "QSPI_FREQ": "80000000"
+        },
+        "DISCO_L475VG_IOT01A": {
+            "QSPI_FREQ": "8000000"
+        },
+        "DISCO_L476VG": {
+            "QSPI_FREQ": "80000000"
+        },
+        "DISCO_F469NI": {
+            "QSPI_FREQ": "80000000"
+        },
+        "NRF52840_DK": {
+            "QSPI_FREQ": "32000000"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/storage/MySystemStorage.cpp	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 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 "BlockDevice.h"
+#include "FileSystem.h"
+#include "FATFileSystem.h"
+#include "LittleFileSystem.h"
+
+#if COMPONENT_SPIF
+#include "SPIFBlockDevice.h"
+#endif
+
+#if COMPONENT_QSPIF
+#include "QSPIFBlockDevice.h"
+#endif
+
+#if COMPONENT_DATAFLASH
+#include "DataFlashBlockDevice.h"
+#endif
+
+#if COMPONENT_SD
+#include "SDBlockDevice.h"
+#endif
+
+#if COMPONENT_FLASHIAP
+#include "FlashIAPBlockDevice.h"
+#endif
+
+#if COMPONENT_NUSD
+#include "NuSDBlockDevice.h"
+#endif
+
+using namespace mbed;
+
+// Align a value to a specified size.
+// Parameters :
+// val           - [IN]   Value.
+// size          - [IN]   Size.
+// Return        : Aligned value.
+static inline uint32_t align_up(uint32_t val, uint32_t size)
+{
+    return (((val - 1) / size) + 1) * size;
+}
+
+BlockDevice *BlockDevice::get_default_instance()
+{
+#if COMPONENT_SPIF
+
+    static SPIFBlockDevice default_bd(
+        MBED_CONF_SPIF_DRIVER_SPI_MOSI,
+        MBED_CONF_SPIF_DRIVER_SPI_MISO,
+        MBED_CONF_SPIF_DRIVER_SPI_CLK,
+        MBED_CONF_SPIF_DRIVER_SPI_CS,
+        MBED_CONF_SPIF_DRIVER_SPI_FREQ
+    );
+
+    return &default_bd;
+
+#elif COMPONENT_QSPIF
+
+    static QSPIFBlockDevice default_bd(
+        MBED_CONF_QSPIF_QSPI_IO0,
+        MBED_CONF_QSPIF_QSPI_IO1,
+        MBED_CONF_QSPIF_QSPI_IO2,
+        MBED_CONF_QSPIF_QSPI_IO3,
+        MBED_CONF_QSPIF_QSPI_SCK,
+        MBED_CONF_QSPIF_QSPI_CSN,
+        MBED_CONF_QSPIF_QSPI_POLARITY_MODE,
+        MBED_CONF_QSPIF_QSPI_FREQ
+    );
+
+    return &default_bd;
+
+#elif COMPONENT_DATAFLASH
+
+    static DataFlashBlockDevice default_bd(
+        MBED_CONF_DATAFLASH_SPI_MOSI,
+        MBED_CONF_DATAFLASH_SPI_MISO,
+        MBED_CONF_DATAFLASH_SPI_CLK,
+        MBED_CONF_DATAFLASH_SPI_CS
+    );
+
+    return &default_bd;
+
+#elif COMPONENT_SD
+
+    static SDBlockDevice default_bd(
+        MBED_CONF_SD_SPI_MOSI,
+        MBED_CONF_SD_SPI_MISO,
+        MBED_CONF_SD_SPI_CLK,
+        MBED_CONF_SD_SPI_CS
+    );
+
+    return &default_bd;
+
+#elif COMPONENT_NUSD
+
+    static NuSDBlockDevice default_bd;
+
+    return &default_bd;
+
+#elif COMPONENT_FLASHIAP
+
+#if (MBED_CONF_FLASHIAP_BLOCK_DEVICE_SIZE == 0) && (MBED_CONF_FLASHIAP_BLOCK_DEVICE_BASE_ADDRESS == 0xFFFFFFFF)
+
+    size_t flash_size;
+    uint32_t start_address;
+    uint32_t bottom_address;
+    FlashIAP flash;
+
+    int ret = flash.init();
+    if (ret != 0) {
+        return 0;
+    }
+
+    //Find the start of first sector after text area
+    bottom_address = align_up(FLASHIAP_ROM_END, flash.get_sector_size(FLASHIAP_ROM_END));
+    start_address = flash.get_flash_start();
+    flash_size = flash.get_flash_size();
+
+    ret = flash.deinit();
+
+    static FlashIAPBlockDevice default_bd(bottom_address, start_address + flash_size - bottom_address);
+
+#else
+
+    static FlashIAPBlockDevice default_bd;
+
+#endif
+
+    return &default_bd;
+
+#else
+
+    return NULL;
+
+#endif
+
+}
+
+FileSystem *FileSystem::get_default_instance()
+{
+#if COMPONENT_SPIF || COMPONENT_QSPIF || COMPONENT_DATAFLASH || COMPONENT_NUSD
+
+    static LittleFileSystem flash("flash", BlockDevice::get_default_instance());
+    flash.set_as_default();
+
+    return &flash;
+
+#elif COMPONENT_SD
+
+    static FATFileSystem sdcard("sd", BlockDevice::get_default_instance());
+    sdcard.set_as_default();
+
+    return &sdcard;
+
+#elif COMPONENT_FLASHIAP
+
+    static LittleFileSystem flash("flash", BlockDevice::get_default_instance());
+    flash.set_as_default();
+
+    return &flash;
+
+#else
+
+    return NULL;
+
+#endif
+
+}
--- a/main.cpp	Sun Oct 14 19:01:53 2018 +0100
+++ b/main.cpp	Sat Dec 08 01:46:22 2018 +0000
@@ -18,7 +18,26 @@
 #ifndef MBED_TEST_MODE
 #include "mbed.h"
 #include "simple-mbed-cloud-client.h"
-#include "FATFileSystem.h"
+#include "LittleFileSystem.h"
+
+//#define SENSORS_AND_BUTTONS
+#ifdef SENSORS_AND_BUTTONS
+#include "HTS221Sensor.h"
+#include "LPS22HBSensor.h"
+#include "LSM6DSLSensor.h"
+#include "lis3mdl_class.h"
+#include "VL53L0X.h"
+
+static DevI2C devI2c(PB_11,PB_10);
+static HTS221Sensor hum_temp(&devI2c);
+static LPS22HBSensor press_temp(&devI2c);
+static LSM6DSLSensor acc_gyro(&devI2c,LSM6DSL_ACC_GYRO_I2C_ADDRESS_LOW,PD_11); // low address
+static LIS3MDL magnetometer(&devI2c);
+static DigitalOut shutdown_pin(PC_6);
+static VL53L0X range(&devI2c, &shutdown_pin, PC_7);
+
+InterruptIn button(USER_BUTTON);
+#endif /* SENSORS_AND_BUTTONS */
 
 // An event queue is a very useful structure to debounce information between contexts (e.g. ISR and normal threads)
 // This is great because things such as network operations are illegal in ISR, so updating a resource in a button's fall() function is not allowed
@@ -29,19 +48,30 @@
 
 // Default block device
 BlockDevice* bd = BlockDevice::get_default_instance();
-FATFileSystem fs("sd", bd);
+SlicingBlockDevice sd(bd, 0, 2*1024*1024);
+LittleFileSystem fs("fs", &sd);
 
 // Declaring pointers for access to Pelion Client resources outside of main()
 MbedCloudClientResource *button_res;
 MbedCloudClientResource *pattern_res;
 
-// This function gets triggered by the timer. It's easy to replace it by an InterruptIn and fall() mode on a real button
-void fake_button_press() {
-    int v = button_res->get_value_int() + 1;
+#ifdef SENSORS_AND_BUTTONS
+// Additional resources for sensor readings
+MbedCloudClientResource *humidity_res;
+MbedCloudClientResource *temperature_res;
+MbedCloudClientResource *distance_res;
+#endif /* SENSORS_AND_BUTTONS */
 
-    button_res->set_value(v);
+// When the device is registered, this variable will be used to access various useful information, like device ID etc.
+static const ConnectorClientEndpointInfo* endpointInfo;
 
-    printf("Simulated button clicked %d times\n", v);
+/**
+ * Button function triggered by the physical button press or by timer depending on SENSORS_AND_BUTTONS macro.
+ */
+void button_press() {
+    int v = button_res->get_value_int() + 1;
+    button_res->set_value(v);
+    printf("Button clicked %d times\n", v);
 }
 
 /**
@@ -98,19 +128,134 @@
  */
 void registered(const ConnectorClientEndpointInfo *endpoint) {
     printf("Connected to Pelion Device Management. Endpoint Name: %s\n", endpoint->internal_endpoint_name.c_str());
+    endpointInfo = endpoint;
 }
 
+#ifdef SENSORS_AND_BUTTONS
+/**
+ * Initialize sensors
+ */
+void sensors_init() {
+    uint8_t id;
+
+    // Initialize sensors
+    hum_temp.init(NULL);
+    press_temp.init(NULL);
+    acc_gyro.init(NULL);
+    magnetometer.init(NULL);
+    range.init_sensor(VL53L0X_DEFAULT_ADDRESS);
+
+    /// Call sensors enable routines
+    hum_temp.enable();
+    press_temp.enable();
+    //magnetometer.enable();
+    acc_gyro.enable_x();
+    acc_gyro.enable_g();
+
+    printf("\033[2J\033[20A");
+    printf ("\r\n--- Sensors configuration ---\r\n\r\n");
+
+    hum_temp.read_id(&id);
+    printf("HTS221  humidity & temperature    = 0x%X\r\n", id);
+    press_temp.read_id(&id);
+    printf("LPS22HB pressure & temperature    = 0x%X\r\n", id);
+    magnetometer.read_id(&id);
+    printf("LIS3MDL magnetometer              = 0x%X\r\n", id);
+    acc_gyro.read_id(&id);
+    printf("LSM6DSL accelerometer & gyroscope = 0x%X\r\n", id);
+
+    printf("\n\r--- Reading sensor values ---\n\r"); ;
+}
+
+/**
+ * Update sensors and report their values.
+ * This function is called periodically.
+ */
+void sensors_update() {
+    float value1, value2;
+    int32_t axes[3];
+    uint32_t distance;
+
+    printf("\r\n");
+
+    value1 = value2 = 0.0;
+    hum_temp.get_temperature(&value1);
+    hum_temp.get_humidity(&value2);
+    if (endpointInfo) {
+        temperature_res->set_value(value1);
+        humidity_res->set_value(value2);
+    }
+    printf("HTS221:  [temp] %.2f C, [hum]   %.2f%%\r\n", value1, value2);
+
+    value1 = value2 = 0.0;
+    press_temp.get_temperature(&value1);
+    press_temp.get_pressure(&value2);
+    printf("LPS22HB: [temp] %.2f C, [press] %.2f mbar\r\n", value1, value2);
+    printf("Mag/Acc/Gyro readings:        x,      y,      z\r\n");
+
+    magnetometer.get_m_axes(axes);
+    printf("LIS3MDL [mag/mgauss]:    %6ld, %6ld, %6ld\r\n", axes[0], axes[1], axes[2]);
+    acc_gyro.get_x_axes(axes);
+    printf("LSM6DSL [acc/mg]:        %6ld, %6ld, %6ld\r\n", axes[0], axes[1], axes[2]);
+    acc_gyro.get_g_axes(axes);
+    printf("LSM6DSL [gyro/mdps]:     %6ld, %6ld, %6ld\r\n", axes[0], axes[1], axes[2]);
+
+    if (range.get_distance(&distance) == VL53L0X_ERROR_NONE) {
+        printf("VL53L0X [mm]:            %6ld\r\n", distance);
+        if (endpointInfo) {
+            distance_res->set_value((int)distance);
+        }
+    } else {
+        printf("VL53L0X [mm]:                --\r\n");
+    }
+
+    printf("\033[8A");
+}
+#endif /* SENSORS_AND_BUTTONS */
+
+
 int main(void) {
     printf("Starting Simple Pelion Device Management Client example\n");
     printf("Connecting to the network using Wifi...\n");
 
+    // If the User button is pressed, then format storage.
+    const int PRESSED = 0;
+    DigitalIn *user_button = new DigitalIn(USER_BUTTON);
+    if (user_button->read() == PRESSED) {
+        printf("User button is pushed on start. Formatting the storage...\n");
+        int storage_status = fs.reformat(&sd);
+        if (storage_status != 0) {
+            if (sd.erase(0, sd.size()) == 0) {
+                if (fs.format(&sd) == 0) {
+                    storage_status = 0;
+                    printf("The storage reformatted successfully.\n");
+                }
+            }
+        }
+        if (storage_status != 0) {
+            printf("Failed to reformat the storage.\n");
+        }
+    }
+
+#ifdef SENSORS_AND_BUTTONS
+    sensors_init();
+#endif /* SENSORS_AND_BUTTONS */
+
     // Connect to the internet (DHCP is expected to be on)
     net = NetworkInterface::get_default_instance();
 
-    nsapi_error_t status = net->connect();
+    nsapi_error_t net_status = -1;
+    for (int tries = 0; tries < 3; tries++) {
+        net_status = net->connect();
+        if (net_status == NSAPI_ERROR_OK) {
+            break;
+        } else {
+            printf("[WARN] Unable to connect to network. Retrying...\n");
+        }
+    }
 
-    if (status != NSAPI_ERROR_OK) {
-        printf("Connecting to the network failed %d!\n", status);
+    if (net_status != NSAPI_ERROR_OK) {
+        printf("Connecting to the network failed %d!\n", net_status);
         return -1;
     }
 
@@ -140,6 +285,24 @@
     blink_res->methods(M2MMethod::POST);
     blink_res->attach_post_callback(blink_callback);
 
+#ifdef SENSORS_AND_BUTTONS
+    // Sensor resources
+    temperature_res = client.create_resource("3303/0/5700", "temperature");
+    temperature_res->set_value(0);
+    temperature_res->methods(M2MMethod::GET);
+    temperature_res->observable(true);
+
+    humidity_res = client.create_resource("3304/0/5700", "humidity");
+    humidity_res->set_value(0);
+    humidity_res->methods(M2MMethod::GET);
+    humidity_res->observable(true);
+
+    distance_res = client.create_resource("3330/0/5700", "distance");
+    distance_res->set_value(0);
+    distance_res->methods(M2MMethod::GET);
+    distance_res->observable(true);
+#endif /* SENSORS_AND_BUTTONS */
+
     printf("Initialized Pelion Client. Registering...\n");
 
     // Callback that fires when registering is complete
@@ -150,8 +313,15 @@
 
     // Placeholder for callback to update local resource when GET comes.
     // The timer fires on an interrupt context, but debounces it to the eventqueue, so it's safe to do network operations
+#ifdef SENSORS_AND_BUTTONS
+    button.fall(eventQueue.event(button_press));
+
     Ticker timer;
-    timer.attach(eventQueue.event(&fake_button_press), 5.0);
+    timer.attach(eventQueue.event(sensors_update), 3.0);
+#else /* SENSORS_AND_BUTTONS */
+    Ticker timer;
+    timer.attach(eventQueue.event(&button_press), 5.0);
+#endif /* SENSORS_AND_BUTTONS */
 
     // You can easily run the eventQueue in a separate thread if required
     eventQueue.dispatch_forever();
--- a/mbed-os.lib	Sun Oct 14 19:01:53 2018 +0100
+++ b/mbed-os.lib	Sat Dec 08 01:46:22 2018 +0000
@@ -1,1 +1,1 @@
-https://github.com/ARMmbed/mbed-os/#c53d51fe9220728bf8ed27afe7afc1ecc3f6f5d7
+https://github.com/ARMmbed/mbed-os/#2fd0c5cfbd83fce62da6308f9d64c0ab64e1f0d6
--- a/mbed_app.json	Sun Oct 14 19:01:53 2018 +0100
+++ b/mbed_app.json	Sat Dec 08 01:46:22 2018 +0000
@@ -1,53 +1,47 @@
 {
     "macros": [
-        "MBEDTLS_USER_CONFIG_FILE=\"mbedTLSConfig_mbedOS.h\"",
-        "PAL_USER_DEFINED_CONFIGURATION=\"sotp_fs_config_MbedOS.h\"",
+        "ARM_UC_USE_PAL_BLOCKDEVICE=1",
+        "MBED_CLOUD_CLIENT_UPDATE_STORAGE=ARM_UCP_FLASHIAP_BLOCKDEVICE",
         "MBED_CLIENT_USER_CONFIG_FILE=\"mbed_cloud_client_user_config.h\"",
         "MBED_CLOUD_CLIENT_USER_CONFIG_FILE=\"mbed_cloud_client_user_config.h\"",
-        "PAL_DTLS_PEER_MIN_TIMEOUT=5000",
-        "MBED_CONF_APP_MAIN_STACK_SIZE=7000",
-        "ARM_UC_USE_PAL_BLOCKDEVICE=1",
-        "MBED_CLOUD_CLIENT_UPDATE_STORAGE=ARM_UCP_FLASHIAP_BLOCKDEVICE"
+        "PAL_USER_DEFINED_CONFIGURATION=\"sotp_fs_config_MbedOS.h\"",
+        "PAL_FS_MOUNT_POINT_PRIMARY=\"/fs\"",
+        "MBEDTLS_USER_CONFIG_FILE=\"mbedTLSConfig_mbedOS.h\"",
+        "PAL_DTLS_PEER_MIN_TIMEOUT=5000"
     ],
     "target_overrides": {
         "*": {
-            "platform.stdio-baud-rate": 115200,
+            "platform.stdio-baud-rate"          : 115200,
             "platform.stdio-convert-newlines"   : true,
             "update-client.storage-address"     : "(1024*1024*64)",
             "update-client.storage-size"        : "(1024*1024*2)",
             "update-client.storage-locations"   : "1",
             "mbed-trace.enable"                 : null,
             "nsapi.default-wifi-security"       : "WPA_WPA2",
-            "nsapi.default-wifi-ssid"           : "\"SSID\"",
-            "nsapi.default-wifi-password"       : "\"Password\""
+            "nsapi.default-wifi-ssid"           : "\"RD2\"",
+            "nsapi.default-wifi-password"       : "\"mimieli1\""
         },
         "DISCO_L475VG_IOT01A": {
+            "target.features_add"               : ["BOOTLOADER"],
+            "target.components_add"             : ["QSPIF"],
+            "target.components_remove"          : ["FLASHIAP"],
+            "target.extra_labels_add"           : ["WIFI_ISM43362"],
             "target.network-default-interface-type" : "WIFI",
-            "target.features_add"               : ["STORAGE", "BOOTLOADER"],
-            "target.components_add"             : ["SD"],
-            "sd.SPI_MOSI"                       : "D11",
-            "sd.SPI_MISO"                       : "D12",
-            "sd.SPI_CLK"                        : "D13",
-            "sd.SPI_CS"                         : "D10",
-            "target.app_offset"                 : "0x10400",
-            "target.header_offset"              : "0x10000",
-            "target.bootloader_img"             : "bootloader/mbed-bootloader-L475VG.bin",
-            "sotp-section-1-address"            : "(0x08000000+((1024-4)*1024))",
+            "flash-start-address"               : "0x08000000",
+            "flash-size"                        : "(1024*1024)",
+            "sotp-section-1-address"            : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(2*1024))",
             "sotp-section-1-size"               : "(2*1024)",
-            "sotp-section-2-address"            : "(0x08000000+((1024-2)*1024))",
+            "sotp-section-2-address"            : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(2*1024))",
             "sotp-section-2-size"               : "(2*1024)",
             "sotp-num-sections"                 : 2,
-            "update-client.application-details" : "(0x08000000+64*1024)",
-            "update-client.bootloader-details"  : "0x080082A0"
-        },
-        "DISCO_F413ZH": {
-            "sotp-section-1-address"            : "(0x08000000+((1536-256)*1024))",
-            "sotp-section-1-size"               : "(128*1024)",
-            "sotp-section-2-address"            : "(0x08000000+((1536-128)*1024))",
-            "sotp-section-2-size"               : "(128*1024)",
-            "sotp-num-sections"                 : 2
+            "target.bootloader_img"             : "bootloader/mbed-bootloader-DISCO_L475VG_IOT01A.bin",
+            "target.header_offset"              : "0x10000",
+            "target.app_offset"                 : "0x10400",
+            "update-client.application-details" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)",
+            "update-client.storage-address"     : "(1024*1024*2)",
+            "update-client.storage-size"        : "(1024*1024*2)",
+            "update-client.storage-locations"   : 1
         }
-
     },
     "config": {
         "format-storage-layer-on-error": {
@@ -58,6 +52,17 @@
             "help": "Enable Developer mode to skip Factory enrollment",
             "value": 1
         },
+        "main-stack-size": {
+            "value": 6000
+        },
+        "flash-start-address": {
+            "help": "Start address of internal flash. Only used in this config to help the definition of other macros.",
+            "value": null
+        },
+        "flash-size": {
+            "help": "Total size of internal flash. Only used in this config to help the definition of other macros.",
+            "value": null
+        },
         "sotp-section-1-address": {
             "help": "Flash sector address for SOTP sector 1",
             "macro_name": "PAL_INTERNAL_FLASH_SECTION_1_ADDRESS",
@@ -84,4 +89,4 @@
             "value": null
         }
     }
-}
+}
\ No newline at end of file
--- a/mbed_cloud_dev_credentials.c	Sun Oct 14 19:01:53 2018 +0100
+++ b/mbed_cloud_dev_credentials.c	Sat Dec 08 01:46:22 2018 +0000
@@ -15,39 +15,39 @@
  */
 #ifndef __MBED_CLOUD_DEV_CREDENTIALS_H__
 #define __MBED_CLOUD_DEV_CREDENTIALS_H__
-
+ 
 #if MBED_CONF_APP_DEVELOPER_MODE == 1
 #error "Replace mbed_cloud_dev_credentials.c with your own developer cert."
 #endif
-
+ 
 #include <inttypes.h>
-
+ 
 const char MBED_CLOUD_DEV_BOOTSTRAP_ENDPOINT_NAME[] = "";
 const char MBED_CLOUD_DEV_ACCOUNT_ID[] = "";
 const char MBED_CLOUD_DEV_BOOTSTRAP_SERVER_URI[] = "";
-
+ 
 const uint8_t MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_CERTIFICATE[] =
 { 0x0 };
-
+ 
 const uint8_t MBED_CLOUD_DEV_BOOTSTRAP_SERVER_ROOT_CA_CERTIFICATE[] =
 { 0x0 };
-
+ 
 const uint8_t MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_PRIVATE_KEY[] =
 { 0x0 };
-
+ 
 const char MBED_CLOUD_DEV_MANUFACTURER[] = "dev_manufacturer";
-
+ 
 const char MBED_CLOUD_DEV_MODEL_NUMBER[] = "dev_model_num";
-
+ 
 const char MBED_CLOUD_DEV_SERIAL_NUMBER[] = "0";
-
+ 
 const char MBED_CLOUD_DEV_DEVICE_TYPE[] = "dev_device_type";
-
+ 
 const char MBED_CLOUD_DEV_HARDWARE_VERSION[] = "dev_hardware_version";
-
+ 
 const uint32_t MBED_CLOUD_DEV_MEMORY_TOTAL_KB = 0;
 const uint32_t MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_CERTIFICATE_SIZE = sizeof(MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_CERTIFICATE);
 const uint32_t MBED_CLOUD_DEV_BOOTSTRAP_SERVER_ROOT_CA_CERTIFICATE_SIZE = sizeof(MBED_CLOUD_DEV_BOOTSTRAP_SERVER_ROOT_CA_CERTIFICATE);
 const uint32_t MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_PRIVATE_KEY_SIZE = sizeof(MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_PRIVATE_KEY);
-
-#endif //__MBED_CLOUD_DEV_CREDENTIALS_H__
+ 
+#endif //__MBED_CLOUD_DEV_CREDENTIALS_H__
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sensors/HTS221.lib	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,1 @@
+https://developer.mbed.org/teams/ST/code/HTS221/#312ee2694a77
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sensors/LIS3MDL.lib	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,1 @@
+https://developer.mbed.org/teams/ST/code/LIS3MDL/#308889c4d074
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sensors/LPS22HB.lib	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,1 @@
+https://developer.mbed.org/teams/ST/code/LPS22HB/#f7b403c70f6b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sensors/LSM303AGR.lib	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,1 @@
+https://developer.mbed.org/teams/ST/code/LSM303AGR/#652f8f67d991
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sensors/LSM6DSL.lib	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,1 @@
+https://developer.mbed.org/teams/ST/code/LSM6DSL/#20ccff7dd652
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sensors/VL53L0X.lib	Sat Dec 08 01:46:22 2018 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/teams/ST/code/VL53L0X/#e9269ff624ed
--- a/simple-mbed-cloud-client.lib	Sun Oct 14 19:01:53 2018 +0100
+++ b/simple-mbed-cloud-client.lib	Sat Dec 08 01:46:22 2018 +0000
@@ -1,1 +1,1 @@
-https://github.com/armmbed/simple-mbed-cloud-client/#8b023aa9e04bcd15ac01726c6f5b58b9422fafad
+https://github.com/armmbed/simple-mbed-cloud-client/#3dfbf54fdd67f5c498da495772bed5cac94d091c
--- a/update_default_resources.c	Sun Oct 14 19:01:53 2018 +0100
+++ b/update_default_resources.c	Sat Dec 08 01:46:22 2018 +0000
@@ -15,27 +15,27 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 // ----------------------------------------------------------------------------
-
+ 
 #ifdef MBED_CLOUD_CLIENT_USER_CONFIG_FILE
 #include MBED_CLOUD_CLIENT_USER_CONFIG_FILE
 #endif
-
+ 
 #include <stdint.h>
-
+ 
 #ifdef MBED_CLOUD_DEV_UPDATE_ID
 const uint8_t arm_uc_vendor_id[16] = { "dev_manufacturer" };
 const uint16_t arm_uc_vendor_id_size = sizeof(arm_uc_vendor_id);
-
+ 
 const uint8_t arm_uc_class_id[16]  = { "dev_model_number" };
 const uint16_t arm_uc_class_id_size = sizeof(arm_uc_class_id);
 #endif
-
+ 
 #ifdef MBED_CLOUD_DEV_UPDATE_CERT
 const uint8_t arm_uc_default_fingerprint[32] = { 0 };
 const uint16_t arm_uc_default_fingerprint_size =
     sizeof(arm_uc_default_fingerprint);
-
+ 
 const uint8_t arm_uc_default_certificate[1] = { 0 };
 const uint16_t arm_uc_default_certificate_size =
     sizeof(arm_uc_default_certificate);
-#endif
+#endif
\ No newline at end of file
--- a/wifi-ism43362.lib	Sun Oct 14 19:01:53 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-https://github.com/ARMmbed/wifi-ism43362/#49d0f834dc420c98631fc33777aace9a31d8d584