RTC auf true

Files at this revision

API Documentation at this revision

Comitter:
kevman
Date:
Wed Mar 13 11:03:24 2019 +0000
Parent:
1:7bcfbc328423
Commit message:
2019-03-13

Changed in this revision

components/802_15_4_RF/atmel-rf-driver/LICENSE Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/atmel-rf-driver/README.md Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/atmel-rf-driver/apache-2.0.txt Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/atmel-rf-driver/atmel-rf-driver/NanostackRfPhyAtmel.h Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/atmel-rf-driver/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/atmel-rf-driver/source/AT86RFReg.h Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/atmel-rf-driver/source/NanostackRfPhyAtmel.cpp Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/atmel-rf-driver/source/at24mac.cpp Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/atmel-rf-driver/source/at24mac.h Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/mcr20a-rf-driver/LICENSE Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/mcr20a-rf-driver/README.md Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/mcr20a-rf-driver/apache-2.0.txt Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/mcr20a-rf-driver/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/mcr20a-rf-driver/mcr20a-rf-driver/NanostackRfPhyMcr20a.h Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/mcr20a-rf-driver/source/MCR20Drv.c Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/mcr20a-rf-driver/source/MCR20Drv.h Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/mcr20a-rf-driver/source/MCR20Overwrites.h Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/mcr20a-rf-driver/source/MCR20Reg.h Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/mcr20a-rf-driver/source/NanostackRfPhyMcr20a.cpp Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/mcr20a-rf-driver/source/XcvrSpi.h Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/stm-s2lp-rf-driver/README.md Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/stm-s2lp-rf-driver/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/stm-s2lp-rf-driver/source/NanostackRfPhys2lp.cpp Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/stm-s2lp-rf-driver/source/rf_configuration.c Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/stm-s2lp-rf-driver/source/rf_configuration.h Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/stm-s2lp-rf-driver/source/s2lpReg.h Show annotated file Show diff for this revision Revisions of this file
components/802_15_4_RF/stm-s2lp-rf-driver/stm-s2lp-rf-driver/NanostackRfPhys2lp.h Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_DATAFLASH/DataFlashBlockDevice.cpp Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_DATAFLASH/DataFlashBlockDevice.h Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_DATAFLASH/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_FLASHIAP/FlashIAPBlockDevice.cpp Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_FLASHIAP/FlashIAPBlockDevice.h Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_FLASHIAP/TESTS/filesystem/fopen/fopen.cpp Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_FLASHIAP/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_FLASHIAP/util/fslittle_debug.h Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_FLASHIAP/util/fslittle_test.c Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_FLASHIAP/util/fslittle_test.h Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_RSPIF/SPIFReducedBlockDevice.cpp Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_RSPIF/SPIFReducedBlockDevice.h Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_RSPIF/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_SD/SDBlockDevice.cpp Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_SD/SDBlockDevice.h Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_SD/TESTS/filesystem/dirs/main.cpp Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_SD/TESTS/filesystem/files/main.cpp Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_SD/TESTS/filesystem/fopen/fopen.cpp Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_SD/TESTS/filesystem/parallel/main.cpp Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_SD/TESTS/filesystem/seek/main.cpp Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_SD/config/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_SD/util/fsfat_debug.h Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_SD/util/fsfat_test.c Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_SD/util/fsfat_test.h Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_SPIF/SPIFBlockDevice.cpp Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_SPIF/SPIFBlockDevice.h Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_SPIF/TESTS/block_device/spif/main.cpp Show annotated file Show diff for this revision Revisions of this file
components/storage/blockdevice/COMPONENT_SPIF/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
components/wifi/esp8266-driver/ESP8266/ESP8266.cpp Show annotated file Show diff for this revision Revisions of this file
components/wifi/esp8266-driver/ESP8266/ESP8266.h Show annotated file Show diff for this revision Revisions of this file
components/wifi/esp8266-driver/ESP8266Interface.cpp Show annotated file Show diff for this revision Revisions of this file
components/wifi/esp8266-driver/ESP8266Interface.h Show annotated file Show diff for this revision Revisions of this file
components/wifi/esp8266-driver/README.md Show annotated file Show diff for this revision Revisions of this file
components/wifi/esp8266-driver/mbed_lib.json Show annotated file Show diff for this revision Revisions of this file
features/frameworks/mbed-coap/_settings/language.settings.xml Show annotated file Show diff for this revision Revisions of this file
features/frameworks/mbed-coap/_settings/org.eclipse.cdt.core.prefs Show annotated file Show diff for this revision Revisions of this file
platform/mbed_rtc_time.cpp Show annotated file Show diff for this revision Revisions of this file
targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/rtc_api.c Show annotated file Show diff for this revision Revisions of this file
targets/targets.json Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/atmel-rf-driver/LICENSE	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,2 @@
+Unless specifically indicated otherwise in a file, files are licensed
+under the Apache 2.0 license, as can be found in: apache-2.0.txt
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/atmel-rf-driver/README.md	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,7 @@
+# Example RF driver for Atmel 802.15.4 transceivers #
+
+Support for:
+ * AT86RF233
+ * AT86RF212B
+
+This driver is used with 6LoWPAN stack.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/atmel-rf-driver/apache-2.0.txt	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,56 @@
+
+
+Apache License
+
+Version 2.0, January 2004
+
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+
+    You must give any other recipients of the Work or Derivative Works a copy of this License; and
+    You must cause any modified files to carry prominent notices stating that You changed the files; and
+    You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+    If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+    You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/atmel-rf-driver/atmel-rf-driver/NanostackRfPhyAtmel.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+#ifndef NANOSTACK_RF_PHY_ATMEL_H_
+#define NANOSTACK_RF_PHY_ATMEL_H_
+
+#include "at24mac.h"
+#include "PinNames.h"
+
+#if defined(MBED_CONF_NANOSTACK_CONFIGURATION) && DEVICE_SPI && DEVICE_I2C
+
+#include "NanostackRfPhy.h"
+
+// Arduino pin defaults for convenience
+#if !defined(ATMEL_SPI_MOSI)
+#define ATMEL_SPI_MOSI   D11
+#endif
+#if !defined(ATMEL_SPI_MISO)
+#define ATMEL_SPI_MISO   D12
+#endif
+#if !defined(ATMEL_SPI_SCLK)
+#define ATMEL_SPI_SCLK   D13
+#endif
+#if !defined(ATMEL_SPI_CS)
+#define ATMEL_SPI_CS     D10
+#endif
+#if !defined(ATMEL_SPI_RST)
+#define ATMEL_SPI_RST    D5
+#endif
+#if !defined(ATMEL_SPI_SLP)
+#define ATMEL_SPI_SLP    D7
+#endif
+#if !defined(ATMEL_SPI_IRQ)
+#define ATMEL_SPI_IRQ    D9
+#endif
+#if !defined(ATMEL_I2C_SDA)
+#define ATMEL_I2C_SDA    D14
+#endif
+#if !defined(ATMEL_I2C_SCL)
+#define ATMEL_I2C_SCL    D15
+#endif
+
+class RFBits;
+
+class NanostackRfPhyAtmel : public NanostackRfPhy {
+public:
+    NanostackRfPhyAtmel(PinName spi_mosi, PinName spi_miso,
+            PinName spi_sclk, PinName spi_cs,  PinName spi_rst, PinName spi_slp, PinName spi_irq,
+            PinName i2c_sda, PinName i2c_scl);
+    virtual ~NanostackRfPhyAtmel();
+    virtual int8_t rf_register();
+    virtual void rf_unregister();
+    virtual void get_mac_address(uint8_t *mac);
+    virtual void set_mac_address(uint8_t *mac);
+
+private:
+    AT24Mac _mac;
+    uint8_t _mac_addr[8];
+    RFBits *_rf;
+    bool _mac_set;
+
+    const PinName _spi_mosi;
+    const PinName _spi_miso;
+    const PinName _spi_sclk;
+    const PinName _spi_cs;
+    const PinName _spi_rst;
+    const PinName _spi_slp;
+    const PinName _spi_irq;
+};
+
+#endif /* MBED_CONF_NANOSTACK_CONFIGURATION */
+#endif /* NANOSTACK_RF_PHY_ATMEL_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/atmel-rf-driver/mbed_lib.json	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,34 @@
+{
+    "name": "atmel-rf",
+    "config": {
+        "full-spi-speed": {
+            "help": "Maximum SPI clock speed (Hz), as long as sufficient inter-byte spacing",
+            "value": 7500000
+        },
+        "full-spi-speed-byte-spacing": {
+            "help": "Required byte spacing in nanoseconds if full SPI speed is in use",
+            "value": 250
+        },
+        "low-spi-speed": {
+            "help": "Maximum SPI clock speed (Hz) if no inter-byte spacing",
+            "value": 3750000
+        },
+        "use-spi-spacing-api": {
+            "help": "Use SPI spacing API proposed in https://github.com/ARMmbed/mbed-os/pull/5353 to ensure spacing between bytes - either run at full speed with spacing, or low with no spacing",
+            "value": false
+        },
+        "assume-spaced-spi":  {
+            "help": "If not using SPI spacing API, assume platform has widely-spaced bytes in bursts, so use full clock speed rather than low.",
+            "value": false
+        },
+        "provide-default": {
+            "help": "Provide default NanostackRfpy. [true/false]",
+            "value": false
+        }
+    },
+    "target_overrides": {
+        "STM": {
+            "assume-spaced-spi": true
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/atmel-rf-driver/source/AT86RFReg.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,172 @@
+/*
+ * 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.
+ */
+
+#ifndef AT86RFREG_H_
+#define AT86RFREG_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*AT86RF212 PHY Modes*/
+#define BPSK_20                     0x00
+#define BPSK_40                     0x04
+#define BPSK_40_ALT                 0x14
+#define OQPSK_SIN_RC_100            0x08
+#define OQPSK_SIN_RC_200            0x09
+#define OQPSK_RC_100                0x18
+#define OQPSK_RC_200                0x19
+#define OQPSK_SIN_250               0x0c
+#define OQPSK_SIN_500               0x0d
+#define OQPSK_SIN_500_ALT           0x0f
+#define OQPSK_RC_250                0x1c
+#define OQPSK_RC_500                0x1d
+#define OQPSK_RC_500_ALT            0x1f
+#define OQPSK_SIN_RC_400_SCR_ON     0x2A
+#define OQPSK_SIN_RC_400_SCR_OFF    0x0A
+#define OQPSK_RC_400_SCR_ON         0x3A
+#define OQPSK_RC_400_SCR_OFF        0x1A
+#define OQPSK_SIN_1000_SCR_ON       0x2E
+#define OQPSK_SIN_1000_SCR_OFF      0x0E
+#define OQPSK_RC_1000_SCR_ON        0x3E
+#define OQPSK_RC_1000_SCR_OFF       0x1E
+
+/*Supported transceivers*/
+#define PART_AT86RF231              0x03
+#define PART_AT86RF212              0x07
+#define PART_AT86RF233              0x0B
+#define VERSION_AT86RF212           0x01
+#define VERSION_AT86RF212B          0x03
+
+/*RF Configuration Registers*/
+#define TRX_STATUS                  0x01
+#define TRX_STATE                   0x02
+#define TRX_CTRL_0                  0x03
+#define TRX_CTRL_1                  0x04
+#define PHY_TX_PWR                  0x05
+#define PHY_RSSI                    0x06
+#define PHY_ED_LEVEL                0x07
+#define PHY_CC_CCA                  0x08
+#define RX_CTRL                     0x0A
+#define SFD_VALUE                   0x0B
+#define TRX_CTRL_2                  0x0C
+#define ANT_DIV                     0x0D
+#define IRQ_MASK                    0x0E
+#define IRQ_STATUS                  0x0F
+#define VREG_CTRL                   0x10
+#define BATMON                      0x11
+#define XOSC_CTRL                   0x12
+#define CC_CTRL_0                   0x13
+#define CC_CTRL_1                   0x14
+#define RX_SYN                      0x15
+#define TRX_RPC                     0x16
+#define RF_CTRL_0                   0x16
+#define XAH_CTRL_1                  0x17
+#define FTN_CTRL                    0x18
+#define PLL_CF                      0x1A
+#define PLL_DCU                     0x1B
+#define PART_NUM                    0x1C
+#define VERSION_NUM                 0x1D
+#define MAN_ID_0                    0x1E
+#define MAN_ID_1                    0x1F
+#define SHORT_ADDR_0                0x20
+#define SHORT_ADDR_1                0x21
+#define PAN_ID_0                    0x22
+#define PAN_ID_1                    0x23
+#define IEEE_ADDR_0                 0x24
+#define IEEE_ADDR_1                 0x25
+#define IEEE_ADDR_2                 0x26
+#define IEEE_ADDR_3                 0x27
+#define IEEE_ADDR_4                 0x28
+#define IEEE_ADDR_5                 0x29
+#define IEEE_ADDR_6                 0x2A
+#define IEEE_ADDR_7                 0x2B
+#define XAH_CTRL_0                  0x2C
+#define CSMA_SEED_0                 0x2D
+#define CSMA_SEED_1                 0x2E
+#define CSMA_BE                     0x2F
+
+/* CSMA_SEED_1*/
+#define AACK_FVN_MODE1              7
+#define AACK_FVN_MODE0              6
+#define AACK_SET_PD                 5
+#define AACK_DIS_ACK                4
+#define AACK_I_AM_COORD             3
+#define CSMA_SEED_12                2
+#define CSMA_SEED_11                1
+#define CSMA_SEED_10                0
+
+/*TRX_STATUS bits*/
+#define CCA_STATUS                  0x40
+#define CCA_DONE                    0x80
+
+/*PHY_CC_CCA bits*/
+#define CCA_REQUEST                 0x80
+#define CCA_MODE_3A                 0x00
+#define CCA_MODE_1                  0x20
+#define CCA_MODE_2                  0x40
+#define CCA_MODE_3B                 0x60
+#define CCA_MODE_MASK               0x60
+#define CCA_CHANNEL_MASK            0x1F
+
+/*IRQ_MASK bits*/
+#define RX_START                    0x04
+#define TRX_END                     0x08
+#define CCA_ED_DONE                 0x10
+#define AMI                         0x20
+#define TRX_UR                      0x40
+
+/*ANT_DIV bits*/
+#define ANT_DIV_EN                  0x08
+#define ANT_EXT_SW_EN               0x04
+#define ANT_CTRL_DEFAULT            0x03
+
+/*TRX_CTRL_1 bits*/
+#define PA_EXT_EN                   0x80
+#define TX_AUTO_CRC_ON              0x20
+#define SPI_CMD_MODE_TRX_STATUS     0x04
+#define SPI_CMD_MODE_PHY_RSSI       0x08
+#define SPI_CMD_MODE_IRQ_STATUS     0x0C
+
+/*TRX_CTRL_2 bits*/
+#define RX_SAFE_MODE                0x80
+
+/*FTN_CTRL bits*/
+#define FTN_START                   0x80
+
+/*PHY_RSSI bits*/
+#define CRC_VALID                   0x80
+
+/*RX_SYN bits*/
+#define RX_PDT_DIS                  0x80
+
+/*TRX_RPC bits */
+#define RX_RPC_CTRL                 0xC0
+#define RX_RPC_EN                   0x20
+#define PDT_RPC_EN                  0x10
+#define PLL_RPC_EN                  0x08
+#define XAH_TX_RPC_EN               0x04
+#define IPAN_RPC_EN                 0x02
+#define TRX_RPC_RSVD_1              0x01
+
+/*XAH_CTRL_1 bits*/
+#define AACK_PROM_MODE              0x02
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AT86RFREG_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/atmel-rf-driver/source/NanostackRfPhyAtmel.cpp	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,2412 @@
+/*
+ * 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 <string.h>
+
+#if defined(MBED_CONF_NANOSTACK_CONFIGURATION) && DEVICE_SPI && DEVICE_I2C
+
+#include "platform/arm_hal_interrupt.h"
+#include "nanostack/platform/arm_hal_phy.h"
+#include "ns_types.h"
+#include "NanostackRfPhyAtmel.h"
+#include "randLIB.h"
+#include "AT86RFReg.h"
+#include "nanostack/platform/arm_hal_phy.h"
+#include "mbed_trace.h"
+#include "mbed_toolchain.h"
+
+#define TRACE_GROUP "AtRF"
+
+/*Worst case sensitivity*/
+#define RF_DEFAULT_SENSITIVITY -88
+/*Run calibration every 5 minutes*/
+#define RF_CALIBRATION_INTERVAL 6000000
+/*Wait ACK for 2.5ms*/
+#define RF_ACK_WAIT_DEFAULT_TIMEOUT 50
+/*Base CCA backoff (50us units) - substitutes for Inter-Frame Spacing*/
+#define RF_CCA_BASE_BACKOFF 13 /* 650us */
+/*CCA random backoff (50us units)*/
+#define RF_CCA_RANDOM_BACKOFF 51 /* 2550us */
+
+#define RF_MTU 127
+
+#define RF_PHY_MODE OQPSK_SIN_250
+
+/*Radio RX and TX state definitions*/
+#define RFF_ON 0x01
+#define RFF_RX 0x02
+#define RFF_TX 0x04
+#define RFF_CCA 0x08
+
+typedef enum
+{
+    RF_MODE_NORMAL = 0,
+    RF_MODE_SNIFFER = 1,
+    RF_MODE_ED = 2
+}rf_mode_t;
+
+/*Atmel RF Part Type*/
+typedef enum
+{
+    ATMEL_UNKNOW_DEV = 0,
+    ATMEL_AT86RF212,
+    ATMEL_AT86RF231, // No longer supported (doesn't give ED+status on frame read)
+    ATMEL_AT86RF233
+}rf_trx_part_e;
+
+/*Atmel RF states*/
+typedef enum
+{
+    NOP = 0x00,
+    BUSY_RX = 0x01,
+    BUSY_TX = 0x02,
+    RF_TX_START = 0x02,
+    FORCE_TRX_OFF = 0x03,
+    FORCE_PLL_ON = 0x04,
+    RX_ON = 0x06,
+    TRX_OFF = 0x08,
+    PLL_ON = 0x09,
+    BUSY_RX_AACK = 0x11,
+    SLEEP = 0x0F,
+    RX_AACK_ON = 0x16,
+    TX_ARET_ON = 0x19,
+    STATE_TRANSITION_IN_PROGRESS = 0x1F
+}rf_trx_states_t;
+
+static const uint8_t *rf_tx_data; // Points to Nanostack's buffer
+static uint8_t rf_tx_length;
+/*ACK wait duration changes depending on data rate*/
+static uint16_t rf_ack_wait_duration = RF_ACK_WAIT_DEFAULT_TIMEOUT;
+
+static int8_t rf_sensitivity = RF_DEFAULT_SENSITIVITY;
+static rf_mode_t rf_mode = RF_MODE_NORMAL;
+static uint8_t radio_tx_power = 0x00;   // Default to +4dBm
+static uint8_t rf_phy_channel = 12;
+static uint8_t rf_tuned = 1;
+static uint8_t rf_use_antenna_diversity = 0;
+static int16_t expected_ack_sequence = -1;
+static uint8_t rf_rx_mode = 0;
+static uint8_t rf_flags = 0;
+static int8_t rf_radio_driver_id = -1;
+static phy_device_driver_s device_driver;
+static uint8_t mac_tx_handle = 0;
+static uint8_t xah_ctrl_1;
+
+/* Channel configurations for 2.4 and sub-GHz */
+static const phy_rf_channel_configuration_s phy_24ghz = {2405000000U, 5000000U, 250000U, 16U, M_OQPSK};
+static const phy_rf_channel_configuration_s phy_subghz = {868300000U, 2000000U, 250000U, 11U, M_OQPSK};
+
+static const phy_device_channel_page_s phy_channel_pages[] = {
+        { CHANNEL_PAGE_0, &phy_24ghz},
+        { CHANNEL_PAGE_2, &phy_subghz},
+        { CHANNEL_PAGE_0, NULL}
+};
+
+/**
+ *  RF output power write
+ *
+ * \brief TX power has to be set before network start.
+ *
+ * \param power
+ *              AT86RF233
+ *              0 = 4 dBm
+ *              1 = 3.7 dBm
+ *              2 = 3.4 dBm
+ *              3 = 3 dBm
+ *              4 = 2.5 dBm
+ *              5 = 2 dBm
+ *              6 = 1 dBm
+ *              7 = 0 dBm
+ *              8 = -1 dBm
+ *              9 = -2 dBm
+ *              10 = -3 dBm
+ *              11 = -4 dBm
+ *              12 = -6 dBm
+ *              13 = -8 dBm
+ *              14 = -12 dBm
+ *              15 = -17 dBm
+ *
+ *              AT86RF212B
+ *              See datasheet for TX power settings
+ *
+ * \return 0, Supported Value
+ * \return -1, Not Supported Value
+ */
+static rf_trx_part_e rf_radio_type_read(void);
+static void rf_ack_wait_timer_start(uint16_t slots);
+static void rf_handle_cca_ed_done(uint8_t full_trx_status);
+static void rf_handle_tx_end(rf_trx_states_t trx_status);
+static void rf_handle_rx_end(rf_trx_states_t trx_status);
+static void rf_on(void);
+static void rf_give_up_on_ack(void);
+static void rf_receive(rf_trx_states_t trx_status = STATE_TRANSITION_IN_PROGRESS);
+static rf_trx_states_t rf_poll_trx_state_change(rf_trx_states_t trx_state);
+static void rf_init(void);
+static int8_t rf_device_register(const uint8_t *mac_addr);
+static void rf_device_unregister(void);
+static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol );
+static void rf_cca_abort(void);
+static void rf_calibration_cb(void);
+static void rf_init_phy_mode(void);
+static void rf_ack_wait_timer_interrupt(void);
+static void rf_calibration_timer_interrupt(void);
+static void rf_calibration_timer_start(uint32_t slots);
+static void rf_cca_timer_interrupt(void);
+static void rf_cca_timer_start(uint32_t slots);
+static uint8_t rf_scale_lqi(int8_t rssi);
+
+static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel);
+static int8_t rf_extension(phy_extension_type_e extension_type,uint8_t *data_ptr);
+static int8_t rf_address_write(phy_address_type_e address_type,uint8_t *address_ptr);
+
+static void rf_if_cca_timer_start(uint32_t slots);
+static void rf_if_enable_promiscuous_mode(void);
+static void rf_if_lock(void);
+static void rf_if_unlock(void);
+static uint8_t rf_if_read_rnd(void);
+static void rf_if_calibration_timer_start(uint32_t slots);
+static void rf_if_interrupt_handler(void);
+static void rf_if_ack_wait_timer_start(uint16_t slots);
+static void rf_if_ack_wait_timer_stop(void);
+static void rf_if_ack_pending_ctrl(uint8_t state);
+static void rf_if_calibration(void);
+static uint8_t rf_if_read_register(uint8_t addr);
+static void rf_if_set_bit(uint8_t addr, uint8_t bit, uint8_t bit_mask);
+static void rf_if_clear_bit(uint8_t addr, uint8_t bit);
+static void rf_if_write_register(uint8_t addr, uint8_t data);
+static void rf_if_reset_radio(void);
+static void rf_if_enable_ant_div(void);
+static void rf_if_disable_ant_div(void);
+static void rf_if_enable_slptr(void);
+static void rf_if_disable_slptr(void);
+static void rf_if_write_antenna_diversity_settings(void);
+static void rf_if_write_set_tx_power_register(uint8_t value);
+static void rf_if_write_rf_settings(void);
+static rf_trx_states_t rf_if_read_trx_state(void);
+static uint16_t rf_if_read_packet(uint8_t data[RF_MTU], uint8_t *lqi_out, uint8_t *ed_out, bool *crc_good);
+static void rf_if_write_short_addr_registers(uint8_t *short_address);
+static uint8_t rf_if_last_acked_pending(void);
+static void rf_if_write_pan_id_registers(uint8_t *pan_id);
+static void rf_if_write_ieee_addr_registers(uint8_t *address);
+static void rf_if_write_frame_buffer(const uint8_t *ptr, uint8_t length);
+static rf_trx_states_t rf_if_change_trx_state(rf_trx_states_t trx_state);
+static void rf_if_start_cca_process(void);
+static int8_t rf_if_scale_rssi(uint8_t ed_level);
+static void rf_if_set_channel_register(uint8_t channel);
+static void rf_if_enable_promiscuous_mode(void);
+static void rf_if_disable_promiscuous_mode(void);
+static uint8_t rf_if_read_part_num(void);
+static void rf_if_enable_irq(void);
+static void rf_if_disable_irq(void);
+static void rf_if_spi_exchange_n(const void *tx, size_t tx_len, void *rx, size_t rx_len);
+
+static inline rf_trx_states_t rf_if_trx_status_from_full(uint8_t full_trx_status)
+{
+    return (rf_trx_states_t) (full_trx_status & 0x1F);
+}
+
+#ifdef MBED_CONF_RTOS_PRESENT
+#include "mbed.h"
+#include "rtos.h"
+
+static void rf_if_irq_task_process_irq();
+
+#define SIG_RADIO       1
+#define SIG_TIMER_ACK   2
+#define SIG_TIMER_CAL   4
+#define SIG_TIMER_CCA   8
+
+#define SIG_TIMERS (SIG_TIMER_ACK|SIG_TIMER_CAL|SIG_TIMER_CCA)
+#define SIG_ALL (SIG_RADIO|SIG_TIMERS)
+#endif
+
+// HW pins to RF chip
+
+class UnlockedSPI : public SPI {
+public:
+    UnlockedSPI(PinName mosi, PinName miso, PinName sclk) :
+        SPI(mosi, miso, sclk) { }
+    virtual void lock() { }
+    virtual void unlock() { }
+};
+
+class RFBits {
+public:
+    RFBits(PinName spi_mosi, PinName spi_miso,
+           PinName spi_sclk, PinName spi_cs,
+           PinName spi_rst, PinName spi_slp, PinName spi_irq);
+    UnlockedSPI spi;
+    DigitalOut CS;
+    DigitalOut RST;
+    DigitalOut SLP_TR;
+    InterruptIn IRQ;
+    Timeout ack_timer;
+    Timeout cal_timer;
+    Timeout cca_timer;
+#ifdef MBED_CONF_RTOS_PRESENT
+    Thread irq_thread;
+    Mutex mutex;
+    void rf_if_irq_task();
+#endif
+};
+
+RFBits::RFBits(PinName spi_mosi, PinName spi_miso,
+               PinName spi_sclk, PinName spi_cs,
+               PinName spi_rst, PinName spi_slp, PinName spi_irq)
+    :   spi(spi_mosi, spi_miso, spi_sclk),
+        CS(spi_cs),
+        RST(spi_rst),
+        SLP_TR(spi_slp),
+        IRQ(spi_irq)
+#ifdef MBED_CONF_RTOS_PRESENT
+,irq_thread(osPriorityRealtime, 1024)
+#endif
+{
+#ifdef MBED_CONF_RTOS_PRESENT
+    irq_thread.start(mbed::callback(this, &RFBits::rf_if_irq_task));
+#endif
+}
+
+static RFBits *rf;
+static uint8_t rf_part_num = 0;
+/*TODO: RSSI Base value setting*/
+static int8_t rf_rssi_base_val = -91;
+
+static void rf_if_lock(void)
+{
+    platform_enter_critical();
+}
+
+static void rf_if_unlock(void)
+{
+    platform_exit_critical();
+}
+
+#ifdef MBED_CONF_RTOS_PRESENT
+static void rf_if_cca_timer_signal(void)
+{
+    rf->irq_thread.signal_set(SIG_TIMER_CCA);
+}
+
+static void rf_if_cal_timer_signal(void)
+{
+    rf->irq_thread.signal_set(SIG_TIMER_CAL);
+}
+
+static void rf_if_ack_timer_signal(void)
+{
+    rf->irq_thread.signal_set(SIG_TIMER_ACK);
+}
+#endif
+
+
+/* Delay functions for RF Chip SPI access */
+#ifdef __CC_ARM
+__asm static void delay_loop(uint32_t count)
+{
+1
+  SUBS a1, a1, #1
+  BCS  %BT1
+  BX   lr
+}
+#elif defined (__ARMCC_VERSION) /* ARMC6 */
+void delay_loop(uint32_t count)
+{
+    // TODO: This needs implementation
+    while(count--)
+        ;;
+}
+#elif defined (__ICCARM__)
+static void delay_loop(uint32_t count)
+{
+  __asm volatile(
+    "loop: \n"
+    " SUBS %0, %0, #1 \n"
+    " BCS.n  loop\n"
+    : "+r" (count)
+    :
+    : "cc"
+  );
+}
+#else // GCC
+static void delay_loop(uint32_t count)
+{
+  __asm__ volatile (
+    "%=:\n\t"
+#if defined(__thumb__) && !defined(__thumb2__)
+    "SUB  %0, #1\n\t"
+#else
+    "SUBS %0, %0, #1\n\t"
+#endif
+    "BCS  %=b\n\t"
+    : "+l" (count)
+    :
+    : "cc"
+  );
+}
+#endif
+
+static void delay_ns(uint32_t ns)
+{
+  uint32_t cycles_per_us = SystemCoreClock / 1000000;
+  // Cortex-M0 takes 4 cycles per loop (SUB=1, BCS=3)
+  // Cortex-M3 and M4 takes 3 cycles per loop (SUB=1, BCS=2)
+  // Cortex-M7 - who knows?
+  // Cortex M3-M7 have "CYCCNT" - would be better than a software loop, but M0 doesn't
+  // Assume 3 cycles per loop for now - will be 33% slow on M0. No biggie,
+  // as original version of code was 300% slow on M4.
+  // [Note that this very calculation, plus call overhead, will take multiple
+  // cycles. Could well be 100ns on its own... So round down here, startup is
+  // worth at least one loop iteration.]
+  uint32_t count = (cycles_per_us * ns) / 3000;
+
+  delay_loop(count);
+}
+
+// t1 = 180ns, SEL falling edge to MISO active [SPI setup assumed slow enough to not need manual delay]
+#define CS_SELECT()  {rf->CS = 0; /* delay_ns(180); */}
+ // t9 = 250ns, last clock to SEL rising edge, t8 = 250ns, SPI idle time between consecutive access
+#define CS_RELEASE() {delay_ns(250); rf->CS = 1; delay_ns(250);}
+
+/*
+ * \brief Read connected radio part.
+ *
+ * This function only return valid information when rf_init() is called
+ *
+ * \return
+ */
+static rf_trx_part_e rf_radio_type_read(void)
+{
+  rf_trx_part_e ret_val = ATMEL_UNKNOW_DEV;
+
+  switch (rf_part_num)
+  {
+    case PART_AT86RF212:
+      ret_val = ATMEL_AT86RF212;
+      break;
+    case PART_AT86RF233:
+      ret_val = ATMEL_AT86RF233;
+      break;
+    default:
+      break;
+  }
+
+  return ret_val;
+}
+
+
+/*
+ * \brief Function starts the ACK wait timeout.
+ *
+ * \param slots Given slots, resolution 50us
+ *
+ * \return none
+ */
+static void rf_if_ack_wait_timer_start(uint16_t slots)
+{
+#ifdef MBED_CONF_RTOS_PRESENT
+  rf->ack_timer.attach_us(rf_if_ack_timer_signal, slots*50);
+#else
+  rf->ack_timer.attach_us(rf_ack_wait_timer_interrupt, slots*50);
+#endif
+}
+
+/*
+ * \brief Function starts the calibration interval.
+ *
+ * \param slots Given slots, resolution 50us
+ *
+ * \return none
+ */
+static void rf_if_calibration_timer_start(uint32_t slots)
+{
+#ifdef MBED_CONF_RTOS_PRESENT
+  rf->cal_timer.attach_us(rf_if_cal_timer_signal, slots*50);
+#else
+  rf->cal_timer.attach_us(rf_calibration_timer_interrupt, slots*50);
+#endif
+}
+
+/*
+ * \brief Function starts the CCA interval.
+ *
+ * \param slots Given slots, resolution 50us
+ *
+ * \return none
+ */
+static void rf_if_cca_timer_start(uint32_t slots)
+{
+#ifdef MBED_CONF_RTOS_PRESENT
+  rf->cca_timer.attach_us(rf_if_cca_timer_signal, slots*50);
+#else
+  rf->cca_timer.attach_us(rf_cca_timer_interrupt, slots*50);
+#endif
+}
+
+/*
+ * \brief Function stops the CCA interval.
+ *
+ * \return none
+ */
+static void rf_if_cca_timer_stop(void)
+{
+  rf->cca_timer.detach();
+}
+
+/*
+ * \brief Function stops the ACK wait timeout.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_if_ack_wait_timer_stop(void)
+{
+  rf->ack_timer.detach();
+}
+
+/*
+ * \brief Function sets bit(s) in given RF register.
+ *
+ * \param addr Address of the register to set
+ * \param bit Bit(s) to set
+ * \param bit_mask Masks the field inside the register
+ *
+ * \return none
+ */
+static void rf_if_set_bit(uint8_t addr, uint8_t bit, uint8_t bit_mask)
+{
+  uint8_t reg = rf_if_read_register(addr);
+  reg &= ~bit_mask;
+  reg |= bit;
+  rf_if_write_register(addr, reg);
+}
+
+/*
+ * \brief Function clears bit(s) in given RF register.
+ *
+ * \param addr Address of the register to clear
+ * \param bit Bit(s) to clear
+ *
+ * \return none
+ */
+static void rf_if_clear_bit(uint8_t addr, uint8_t bit)
+{
+  rf_if_set_bit(addr, 0, bit);
+}
+
+/*
+ * \brief Function writes register in RF.
+ *
+ * \param addr Address on the RF
+ * \param data Written data
+ *
+ * \return none
+ */
+static void rf_if_write_register(uint8_t addr, uint8_t data)
+{
+  const uint8_t tx[2] = { static_cast<uint8_t>(0xC0 | addr), data };
+  uint8_t rx[2];
+  CS_SELECT();
+  rf_if_spi_exchange_n(tx, 2, rx, 2);
+  CS_RELEASE();
+}
+
+/*
+ * \brief Function reads RF register, and also outputs PHY_STATUS
+ *
+ * \param addr Address on the RF
+ * \param[out] status_out Pointer to store PHY_STATUS
+ *
+ * \return Read register data
+ */
+static uint8_t rf_if_read_register_with_status(uint8_t addr, uint8_t *status_out)
+{
+  const uint8_t tx[1] = { static_cast<uint8_t>(0x80 | addr) };
+  uint8_t rx[2];
+  CS_SELECT();
+  rf_if_spi_exchange_n(tx, 1, rx, 2);
+  CS_RELEASE();
+  if (status_out) {
+      *status_out = rx[0];
+  }
+  return rx[1];
+}
+
+/*
+ * \brief Function reads RF register.
+ *
+ * \param addr Address on the RF
+ *
+ * \return Read register data
+ */
+static uint8_t rf_if_read_register(uint8_t addr)
+{
+  return rf_if_read_register_with_status(addr, NULL);
+}
+
+/*
+ * \brief Function resets the RF.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_if_reset_radio(void)
+{
+#if MBED_CONF_ATMEL_RF_USE_SPI_SPACING_API
+  rf->spi.frequency(MBED_CONF_ATMEL_RF_FULL_SPI_SPEED);
+  int spacing = rf->spi.write_spacing(MBED_CONF_ATMEL_RF_FULL_SPI_SPEED_BYTE_SPACING);
+  if (spacing < MBED_CONF_ATMEL_RF_FULL_SPI_SPEED_BYTE_SPACING) {
+      rf->spi.frequency(MBED_CONF_ATMEL_RF_LOW_SPI_SPEED);
+      rf->spi.write_spacing(0);
+  }
+#elif MBED_CONF_ATMEL_RF_ASSUME_SPACED_SPI
+  rf->spi.frequency(MBED_CONF_ATMEL_RF_FULL_SPI_SPEED);
+#else
+  rf->spi.frequency(MBED_CONF_ATMEL_RF_LOW_SPI_SPEED);
+#endif
+  rf->IRQ.rise(0);
+  rf->RST = 1;
+  wait_ms(1);
+  rf->RST = 0;
+  wait_ms(10);
+  CS_RELEASE();
+  rf->SLP_TR = 0;
+  wait_ms(10);
+  rf->RST = 1;
+  wait_ms(10);
+
+  rf->IRQ.rise(&rf_if_interrupt_handler);
+}
+
+/*
+ * \brief Function enables the promiscuous mode.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_if_enable_promiscuous_mode(void)
+{
+  if (!(xah_ctrl_1 & AACK_PROM_MODE)) {
+    /*Set AACK_PROM_MODE to enable the promiscuous mode*/
+    rf_if_write_register(XAH_CTRL_1, xah_ctrl_1 |= AACK_PROM_MODE);
+  }
+}
+
+/*
+ * \brief Function disable the promiscuous mode.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_if_disable_promiscuous_mode(void)
+{
+  if (xah_ctrl_1 & AACK_PROM_MODE) {
+    /*Clear AACK_PROM_MODE to disable the promiscuous mode*/
+    rf_if_write_register(XAH_CTRL_1, xah_ctrl_1 &= ~AACK_PROM_MODE);
+  }
+}
+
+/*
+ * \brief Function enables the Antenna diversity usage.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_if_enable_ant_div(void)
+{
+  /*Set ANT_EXT_SW_EN to enable controlling of antenna diversity*/
+  rf_if_set_bit(ANT_DIV, ANT_EXT_SW_EN, ANT_EXT_SW_EN);
+}
+
+/*
+ * \brief Function disables the Antenna diversity usage.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_if_disable_ant_div(void)
+{
+  rf_if_clear_bit(ANT_DIV, ANT_EXT_SW_EN);
+}
+
+/*
+ * \brief Function sets the SLP TR pin.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_if_enable_slptr(void)
+{
+  rf->SLP_TR = 1;
+}
+
+/*
+ * \brief Function clears the SLP TR pin.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_if_disable_slptr(void)
+{
+  rf->SLP_TR = 0;
+}
+
+/*
+ * \brief Function writes the antenna diversity settings.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_if_write_antenna_diversity_settings(void)
+{
+  /*Recommended setting of PDT_THRES is 3 when antenna diversity is used*/
+  rf_if_set_bit(RX_CTRL, 0x03, 0x0f);
+  rf_if_write_register(ANT_DIV, ANT_DIV_EN | ANT_EXT_SW_EN | ANT_CTRL_DEFAULT);
+}
+
+/*
+ * \brief Function writes the TX output power register.
+ *
+ * \param value Given register value
+ *
+ * \return none
+ */
+static void rf_if_write_set_tx_power_register(uint8_t value)
+{
+  rf_if_write_register(PHY_TX_PWR, value);
+}
+
+/*
+ * \brief Function returns the RF part number.
+ *
+ * \param none
+ *
+ * \return part number
+ */
+static uint8_t rf_if_read_part_num(void)
+{
+  return rf_if_read_register(PART_NUM);
+}
+
+/*
+ * \brief Function writes the RF settings and initialises SPI interface.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_if_write_rf_settings(void)
+{
+  /*Reset RF module*/
+  rf_if_reset_radio();
+
+  rf_part_num = rf_if_read_part_num();
+
+  rf_if_write_register(XAH_CTRL_0,0);
+
+  /* Auto CRC on, IRQ status shows unmasked only, TRX_STATUS output on all accesses */
+  rf_if_write_register(TRX_CTRL_1, TX_AUTO_CRC_ON | SPI_CMD_MODE_TRX_STATUS);
+
+  rf_if_write_register(IRQ_MASK, CCA_ED_DONE | TRX_END | TRX_UR);
+
+  xah_ctrl_1 = rf_if_read_register(XAH_CTRL_1);
+
+  /*Read transceiver PART_NUM*/
+  rf_part_num = rf_if_read_register(PART_NUM);
+
+  /*Sub-GHz RF settings*/
+  if(rf_part_num == PART_AT86RF212)
+  {
+    /*GC_TX_OFFS mode-dependent setting - OQPSK*/
+    rf_if_write_register(RF_CTRL_0, 0x32);
+
+    if(rf_if_read_register(VERSION_NUM) == VERSION_AT86RF212B)
+    {
+      /*TX Output Power setting - 0 dBm North American Band*/
+      rf_if_write_register(PHY_TX_PWR, 0x03);
+    }
+    else
+    {
+      /*TX Output Power setting - 0 dBm North American Band*/
+      rf_if_write_register(PHY_TX_PWR, 0x24);
+    }
+
+    /*PHY Mode: IEEE 802.15.4-2006/2011 - OQPSK-SIN-250*/
+    rf_if_write_register(TRX_CTRL_2, RX_SAFE_MODE | RF_PHY_MODE);
+    /*Based on receiver Characteristics. See AT86RF212B Datasheet where RSSI BASE VALUE in range -97 - -100 dBm*/
+    rf_rssi_base_val = -98;
+  }
+  /*2.4GHz RF settings*/
+  else
+  {
+#if 0
+    /* Disable power saving functions for now - can only impact reliability,
+     * and don't have any users demanding it. */
+    /*Set RPC register*/
+    rf_if_write_register(TRX_RPC, RX_RPC_CTRL|RX_RPC_EN|PLL_RPC_EN|XAH_TX_RPC_EN|IPAN_RPC_EN|TRX_RPC_RSVD_1);
+#endif
+    /*PHY Mode: IEEE 802.15.4 - Data Rate 250 kb/s*/
+    rf_if_write_register(TRX_CTRL_2, RX_SAFE_MODE);
+    rf_rssi_base_val = -91;
+  }
+}
+
+/*
+ * \brief Function returns the RF state
+ *
+ * \param none
+ *
+ * \return RF state
+ */
+static rf_trx_states_t rf_if_read_trx_state(void)
+{
+  return rf_if_trx_status_from_full(rf_if_read_register(TRX_STATUS));
+}
+
+/*
+ * \brief Function reads packet buffer.
+ *
+ * \param data_out Output buffer
+ * \param lqi_out LQI output
+ * \param ed_out ED output
+ * \param crc_good CRC good indication
+ *
+ * \return PSDU length [0..RF_MTU]
+ */
+static uint16_t rf_if_read_packet(uint8_t data_out[RF_MTU], uint8_t *lqi_out, uint8_t *ed_out, bool *crc_good)
+{
+  CS_SELECT();
+  const uint8_t tx[1] = { 0x20 };
+  uint8_t rx[3];
+  rf_if_spi_exchange_n(tx, 1, rx, 2);
+  uint8_t len = rx[1] & 0x7F;
+  rf_if_spi_exchange_n(NULL, 0, data_out, len);
+  rf_if_spi_exchange_n(NULL, 0, rx, 3);
+  *lqi_out = rx[0];
+  *ed_out = rx[1];
+  *crc_good = rx[2] & 0x80;
+  CS_RELEASE();
+
+  return len;
+}
+
+/*
+ * \brief Function writes RF short address registers
+ *
+ * \param short_address Given short address
+ *
+ * \return none
+ */
+static void rf_if_write_short_addr_registers(uint8_t *short_address)
+{
+  rf_if_write_register(SHORT_ADDR_1, *short_address++);
+  rf_if_write_register(SHORT_ADDR_0, *short_address);
+}
+
+/*
+ * \brief Function sets the frame pending in ACK message
+ *
+ * \param state Given frame pending state
+ *
+ * \return none
+ */
+static void rf_if_ack_pending_ctrl(uint8_t state)
+{
+  rf_if_lock();
+  if(state)
+  {
+    rf_if_set_bit(CSMA_SEED_1, (1 << AACK_SET_PD), (1 << AACK_SET_PD));
+  }
+  else
+  {
+    rf_if_clear_bit(CSMA_SEED_1, (1 << AACK_SET_PD));
+  }
+  rf_if_unlock();
+}
+
+/*
+ * \brief Function returns the state of frame pending control
+ *
+ * \param none
+ *
+ * \return Frame pending state
+ */
+static uint8_t rf_if_last_acked_pending(void)
+{
+  uint8_t last_acked_data_pending;
+
+  rf_if_lock();
+  if(rf_if_read_register(CSMA_SEED_1) & (1 << AACK_SET_PD))
+    last_acked_data_pending = 1;
+  else
+    last_acked_data_pending = 0;
+  rf_if_unlock();
+
+  return last_acked_data_pending;
+}
+
+/*
+ * \brief Function calibrates the RF part.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_if_calibration(void)
+{
+  rf_if_set_bit(FTN_CTRL, FTN_START, FTN_START);
+  /*Wait while calibration is running*/
+  while(rf_if_read_register(FTN_CTRL) & FTN_START);
+}
+
+/*
+ * \brief Function writes RF PAN Id registers
+ *
+ * \param pan_id Given PAN Id
+ *
+ * \return none
+ */
+static void rf_if_write_pan_id_registers(uint8_t *pan_id)
+{
+  rf_if_write_register(PAN_ID_1, *pan_id++);
+  rf_if_write_register(PAN_ID_0, *pan_id);
+}
+
+/*
+ * \brief Function writes RF IEEE Address registers
+ *
+ * \param address Given IEEE Address
+ *
+ * \return none
+ */
+static void rf_if_write_ieee_addr_registers(uint8_t *address)
+{
+  uint8_t i;
+  uint8_t temp = IEEE_ADDR_0;
+
+  for(i=0; i<8; i++)
+    rf_if_write_register(temp++, address[7-i]);
+}
+
+/*
+ * \brief Function writes data in RF frame buffer.
+ *
+ * \param ptr Pointer to data (PSDU, except FCS)
+ * \param length Pointer to length (PSDU length, minus 2 for FCS)
+ *
+ * \return none
+ */
+static void rf_if_write_frame_buffer(const uint8_t *ptr, uint8_t length)
+{
+  const uint8_t cmd[2] = { 0x60, static_cast<uint8_t>(length + 2) };
+
+  CS_SELECT();
+  rf_if_spi_exchange_n(cmd, 2, NULL, 0);
+  rf_if_spi_exchange_n(ptr, length, NULL, 0);
+  CS_RELEASE();
+}
+
+/*
+ * \brief Function returns 8-bit random value.
+ *
+ * \param none
+ *
+ * \return random value
+ */
+static uint8_t rf_if_read_rnd(void)
+{
+  uint8_t temp;
+  uint8_t tmp_rpc_val = 0;
+  /*RPC must be disabled while reading the random number*/
+  if(rf_part_num == PART_AT86RF233)
+  {
+    tmp_rpc_val = rf_if_read_register(TRX_RPC);
+    rf_if_write_register(TRX_RPC, RX_RPC_CTRL|TRX_RPC_RSVD_1);
+  }
+
+  wait_ms(1);
+  temp = ((rf_if_read_register(PHY_RSSI)>>5) << 6);
+  wait_ms(1);
+  temp |= ((rf_if_read_register(PHY_RSSI)>>5) << 4);
+  wait_ms(1);
+  temp |= ((rf_if_read_register(PHY_RSSI)>>5) << 2);
+  wait_ms(1);
+  temp |= ((rf_if_read_register(PHY_RSSI)>>5));
+  wait_ms(1);
+  if(rf_part_num == PART_AT86RF233)
+    rf_if_write_register(TRX_RPC, tmp_rpc_val);
+  return temp;
+}
+
+/*
+ * \brief Function changes the state of the RF.
+ *
+ * \param trx_state Given RF state
+ *
+ * \return none
+ */
+static rf_trx_states_t rf_if_change_trx_state(rf_trx_states_t trx_state)
+{
+  rf_if_write_register(TRX_STATE, trx_state);
+  /*Wait while not in desired state*/
+  return rf_poll_trx_state_change(trx_state);
+}
+
+/*
+ * \brief Function starts the CCA process
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_if_start_cca_process(void)
+{
+  rf_if_write_register(PHY_CC_CCA, CCA_REQUEST | CCA_MODE_3A | rf_phy_channel);
+}
+
+/*
+ * \brief Function scales RSSI
+ *
+ * \param ed_level ED level read from chip
+ *
+ * \return appropriately scaled RSSI dBm
+ */
+static int8_t rf_if_scale_rssi(uint8_t ed_level)
+{
+  if (rf_part_num == PART_AT86RF212) {
+    /* Data sheet says to multiply by 1.03 - this is 1.03125, rounding down */
+    ed_level += ed_level >> 5;
+  }
+  return rf_rssi_base_val + ed_level;
+}
+
+/*
+ * \brief Function sets the RF channel field
+ *
+ * \param Given channel
+ *
+ * \return none
+ */
+static void rf_if_set_channel_register(uint8_t channel)
+{
+  rf_if_set_bit(PHY_CC_CCA, channel, CCA_CHANNEL_MASK);
+}
+
+/*
+ * \brief Function enables RF irq pin interrupts in RF interface.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_if_enable_irq(void)
+{
+  rf->IRQ.enable_irq();
+}
+
+/*
+ * \brief Function disables RF irq pin interrupts in RF interface.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_if_disable_irq(void)
+{
+  rf->IRQ.disable_irq();
+}
+
+#ifdef MBED_CONF_RTOS_PRESENT
+static void rf_if_interrupt_handler(void)
+{
+    rf->irq_thread.signal_set(SIG_RADIO);
+}
+
+// Started during construction of rf, so variable
+// rf isn't set at the start. Uses 'this' instead.
+void RFBits::rf_if_irq_task(void)
+{
+    for (;;) {
+        osEvent event = irq_thread.signal_wait(0);
+        if (event.status != osEventSignal) {
+            continue;
+        }
+        rf_if_lock();
+        if (event.value.signals & SIG_RADIO) {
+            rf_if_irq_task_process_irq();
+        }
+        if (event.value.signals & SIG_TIMER_ACK) {
+            rf_ack_wait_timer_interrupt();
+        }
+        if (event.value.signals & SIG_TIMER_CCA) {
+            rf_cca_timer_interrupt();
+        }
+        if (event.value.signals & SIG_TIMER_CAL) {
+            rf_calibration_timer_interrupt();
+        }
+        rf_if_unlock();
+    }
+}
+
+static void rf_if_irq_task_process_irq(void)
+#else
+/*
+ * \brief Function is a RF interrupt vector. End of frame in RX and TX are handled here as well as CCA process interrupt.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_if_interrupt_handler(void)
+#endif
+{
+  static uint8_t last_is, last_ts;
+  uint8_t irq_status, full_trx_status;
+  uint8_t orig_xah_ctrl_1 = xah_ctrl_1;
+
+  /*Read and clear interrupt flag, and pick up trx_status*/
+  irq_status = rf_if_read_register_with_status(IRQ_STATUS, &full_trx_status);
+  uint8_t orig_flags = rf_flags;
+
+  /*Frame end interrupt (RX and TX)*/
+  if(irq_status & TRX_END)
+  {
+    /*TX done interrupt*/
+    rf_trx_states_t trx_status = rf_if_trx_status_from_full(full_trx_status);
+    if(trx_status == PLL_ON || trx_status == TX_ARET_ON)
+    {
+      rf_handle_tx_end(trx_status);
+    }
+    /*Frame received interrupt*/
+    else
+    {
+      rf_handle_rx_end(trx_status);
+    }
+  }
+  if(irq_status & CCA_ED_DONE)
+  {
+    rf_handle_cca_ed_done(full_trx_status);
+  }
+  if (irq_status & TRX_UR)
+  {
+    tr_error("Radio underrun is %x->%x ts %x->%x fl %x->%x x1 %x", last_is, irq_status, last_ts, full_trx_status, orig_flags, rf_flags, orig_xah_ctrl_1);
+  }
+  last_is = irq_status;
+  last_ts = full_trx_status;
+}
+
+/*
+ * \brief Function writes/read data in SPI interface
+ */
+static void rf_if_spi_exchange_n(const void *tx, size_t tx_len, void *rx, size_t rx_len)
+{
+#if 1
+  rf->spi.write(static_cast<const char *>(tx), tx_len,
+                static_cast<char *>(rx), rx_len);
+#else
+  const uint8_t *txb = static_cast<const uint8_t *>(tx);
+  uint8_t *rxb = static_cast<uint8_t *>(rx);
+  while (tx_len > 0 || rx_len > 0) {
+      uint8_t b;
+      if (tx_len) {
+          tx_len--;
+          b = *txb++;
+      } else {
+          b = 0xFF;
+      }
+      b = rf->spi.write(b);
+      if (rx_len) {
+          rx_len--;
+          *rxb++ = b;
+      }
+  }
+#endif
+}
+
+/*
+ * \brief Function sets given RF flag on.
+ *
+ * \param x Given RF flag
+ *
+ * \return none
+ */
+static void rf_flags_set(uint8_t x)
+{
+    rf_flags |= x;
+}
+
+/*
+ * \brief Function clears given RF flag on.
+ *
+ * \param x Given RF flag
+ *
+ * \return none
+ */
+static void rf_flags_clear(uint8_t x)
+{
+    rf_flags &= ~x;
+}
+
+/*
+ * \brief Function checks if given RF flag is on.
+ *
+ * \param x Given RF flag
+ *
+ * \return states of the given flags
+ */
+static uint8_t rf_flags_check(uint8_t x)
+{
+    return (rf_flags & x);
+}
+
+/*
+ * \brief Function clears all RF flags.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_flags_reset(void)
+{
+    rf_flags = 0;
+}
+
+/*
+ * \brief Function initialises and registers the RF driver.
+ *
+ * \param none
+ *
+ * \return rf_radio_driver_id Driver ID given by NET library
+ */
+static int8_t rf_device_register(const uint8_t *mac_addr)
+{
+    rf_trx_part_e radio_type;
+
+    rf_init();
+
+    radio_type = rf_radio_type_read();
+    if(radio_type != ATMEL_UNKNOW_DEV)
+    {
+        /*Set pointer to MAC address*/
+        device_driver.PHY_MAC = (uint8_t *)mac_addr;
+        device_driver.driver_description = (char*)"ATMEL_MAC";
+        //Create setup Used Radio chips
+        if(radio_type == ATMEL_AT86RF212)
+        {
+            device_driver.link_type = PHY_LINK_15_4_SUBGHZ_TYPE;
+        }
+        else
+        {
+            device_driver.link_type = PHY_LINK_15_4_2_4GHZ_TYPE;
+        }
+        device_driver.phy_channel_pages = phy_channel_pages;
+        /*Maximum size of payload is 127*/
+        device_driver.phy_MTU = 127;
+        /*No header in PHY*/
+        device_driver.phy_header_length = 0;
+        /*No tail in PHY*/
+        device_driver.phy_tail_length = 0;
+        /*Set address write function*/
+        device_driver.address_write = &rf_address_write;
+        /*Set RF extension function*/
+        device_driver.extension = &rf_extension;
+        /*Set RF state control function*/
+        device_driver.state_control = &rf_interface_state_control;
+        /*Set transmit function*/
+        device_driver.tx = &rf_start_cca;
+        /*NULLIFY rx and tx_done callbacks*/
+        device_driver.phy_rx_cb = NULL;
+        device_driver.phy_tx_done_cb = NULL;
+        /*Register device driver*/
+        rf_radio_driver_id = arm_net_phy_register(&device_driver);
+    } else {
+        rf_if_disable_irq();
+    }
+    return rf_radio_driver_id;
+}
+
+/*
+ * \brief Function unregisters the RF driver.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_device_unregister()
+{
+    if (rf_radio_driver_id >= 0) {
+        arm_net_phy_unregister(rf_radio_driver_id);
+        rf_radio_driver_id = -1;
+    }
+}
+
+
+/*
+ * \brief Function is a call back for ACK wait timeout.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_ack_wait_timer_interrupt(void)
+{
+    rf_if_lock();
+    rf_give_up_on_ack();
+    rf_if_unlock();
+}
+
+/*
+ * \brief Function is a call back for calibration interval timer.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_calibration_timer_interrupt(void)
+{
+    /*Calibrate RF*/
+    rf_calibration_cb();
+    /*Start new calibration timeout*/
+    rf_calibration_timer_start(RF_CALIBRATION_INTERVAL);
+}
+
+/*
+ * \brief Function is a call back for cca interval timer.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_cca_timer_interrupt(void)
+{
+    rf_flags_set(RFF_CCA);
+    /*Start CCA process*/
+    rf_if_start_cca_process();
+}
+
+/*
+ * \brief Function starts the ACK wait timeout.
+ *
+ * \param slots Given slots, resolution 50us
+ *
+ * \return none
+ */
+static void rf_ack_wait_timer_start(uint16_t slots)
+{
+    rf_if_ack_wait_timer_start(slots);
+}
+
+/*
+ * \brief Function starts the calibration interval.
+ *
+ * \param slots Given slots, resolution 50us
+ *
+ * \return none
+ */
+static void rf_calibration_timer_start(uint32_t slots)
+{
+    rf_if_calibration_timer_start(slots);
+}
+
+/*
+ * \brief Function starts the CCA backoff.
+ *
+ * \param slots Given slots, resolution 50us
+ *
+ * \return none
+ */
+static void rf_cca_timer_start(uint32_t slots)
+{
+    rf_if_cca_timer_start(slots);
+}
+
+/*
+ * \brief Function stops the CCA backoff.
+ *
+ * \return none
+ */
+static void rf_cca_timer_stop(void)
+{
+    rf_if_cca_timer_stop();
+}
+
+/*
+ * \brief Function writes various RF settings in startup.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_write_settings(void)
+{
+    rf_if_lock();
+    rf_if_write_rf_settings();
+    /*Set output power*/
+    rf_if_write_set_tx_power_register(radio_tx_power);
+    /*Initialise Antenna Diversity*/
+    if(rf_use_antenna_diversity)
+        rf_if_write_antenna_diversity_settings();
+    rf_if_unlock();
+}
+
+/*
+ * \brief Function writes 16-bit address in RF address filter.
+ *
+ * \param short_address Given short address
+ *
+ * \return none
+ */
+static void rf_set_short_adr(uint8_t * short_address)
+{
+    rf_if_lock();
+    /*Wake up RF if sleeping*/
+    if(rf_flags_check(RFF_ON) == 0)
+    {
+        rf_if_disable_slptr();
+        rf_poll_trx_state_change(TRX_OFF);
+    }
+    /*Write address filter registers*/
+    rf_if_write_short_addr_registers(short_address);
+    /*RF back to sleep*/
+    if(rf_flags_check(RFF_ON) == 0)
+    {
+        rf_if_enable_slptr();
+    }
+    rf_if_unlock();
+}
+
+/*
+ * \brief Function writes PAN Id in RF PAN Id filter.
+ *
+ * \param pan_id Given PAN Id
+ *
+ * \return none
+ */
+static void rf_set_pan_id(uint8_t *pan_id)
+{
+    rf_if_lock();
+    /*Wake up RF if sleeping*/
+    if(rf_flags_check(RFF_ON) == 0)
+    {
+        rf_if_disable_slptr();
+        rf_poll_trx_state_change(TRX_OFF);
+    }
+    /*Write address filter registers*/
+    rf_if_write_pan_id_registers(pan_id);
+    /*RF back to sleep*/
+    if(rf_flags_check(RFF_ON) == 0)
+    {
+        rf_if_enable_slptr();
+    }
+    rf_if_unlock();
+}
+
+/*
+ * \brief Function writes 64-bit address in RF address filter.
+ *
+ * \param address Given 64-bit address
+ *
+ * \return none
+ */
+static void rf_set_address(uint8_t *address)
+{
+    rf_if_lock();
+    /*Wake up RF if sleeping*/
+    if(rf_flags_check(RFF_ON) == 0)
+    {
+        rf_if_disable_slptr();
+        rf_poll_trx_state_change(TRX_OFF);
+    }
+    /*Write address filter registers*/
+    rf_if_write_ieee_addr_registers(address);
+    /*RF back to sleep*/
+    if(rf_flags_check(RFF_ON) == 0)
+    {
+        rf_if_enable_slptr();
+    }
+    rf_if_unlock();
+}
+
+/*
+ * \brief Function sets the RF channel.
+ *
+ * \param ch New channel
+ *
+ * \return none
+ */
+static void rf_channel_set(uint8_t ch)
+{
+    rf_if_lock();
+    rf_phy_channel = ch;
+    if(ch < 0x1f)
+        rf_if_set_channel_register(ch);
+    rf_if_unlock();
+}
+
+
+/*
+ * \brief Function initialises the radio driver and resets the radio.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_init(void)
+{
+    rf_if_lock();
+
+    /*Write RF settings*/
+    rf_write_settings();
+    /*Initialise PHY mode*/
+    rf_init_phy_mode();
+    /*Clear RF flags*/
+    rf_flags_reset();
+    /*Set RF in TRX OFF state*/
+    rf_if_change_trx_state(TRX_OFF);
+    /*Set RF in PLL_ON state*/
+    rf_trx_states_t trx_status = rf_if_change_trx_state(PLL_ON);
+    /*Start receiver*/
+    rf_receive(trx_status);
+    /*Read randomness, and add to seed*/
+    randLIB_add_seed(rf_if_read_rnd());
+    /*Start RF calibration timer*/
+    rf_calibration_timer_start(RF_CALIBRATION_INTERVAL);
+
+    rf_if_unlock();
+}
+
+/**
+ * \brief Function gets called when MAC is setting radio off.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_off(void)
+{
+    if(rf_flags_check(RFF_ON))
+    {
+        rf_if_lock();
+        rf_cca_abort();
+        uint16_t while_counter = 0;
+        /*Wait while receiving*/
+        while(rf_if_read_trx_state() == BUSY_RX_AACK)
+        {
+            while_counter++;
+            if(while_counter == 0xffff)
+                break;
+        }
+        /*RF state change: RX_AACK_ON->PLL_ON->TRX_OFF->SLEEP*/
+        if(rf_if_read_trx_state() == RX_AACK_ON)
+        {
+            rf_if_change_trx_state(PLL_ON);
+        }
+        rf_if_change_trx_state(TRX_OFF);
+        rf_if_enable_slptr();
+
+        /*Disable Antenna Diversity*/
+        if(rf_use_antenna_diversity)
+            rf_if_disable_ant_div();
+        rf_if_unlock();
+    }
+
+    /*Clears all flags*/
+    rf_flags_reset();
+}
+
+/*
+ * \brief Function polls the RF state until it has changed to desired state.
+ *
+ * \param trx_state RF state
+ *
+ * \return none
+ */
+static rf_trx_states_t rf_poll_trx_state_change(rf_trx_states_t trx_state)
+{
+    uint16_t while_counter = 0;
+
+    if(trx_state == FORCE_PLL_ON)
+        trx_state = PLL_ON;
+    else if(trx_state == FORCE_TRX_OFF)
+        trx_state = TRX_OFF;
+
+    rf_trx_states_t state_out;
+    while((state_out = rf_if_read_trx_state()) != trx_state)
+    {
+        while_counter++;
+        if(while_counter == 0x1ff)
+            break;
+    }
+
+    return state_out;
+}
+
+/*
+ * \brief Function polls the RF state until it is no longer transitioning.
+ *
+ * \param trx_state RF state
+ *
+ * \return none
+ */
+static rf_trx_states_t rf_poll_for_state(void)
+{
+    rf_trx_states_t state_out;
+    while((state_out = rf_if_read_trx_state()) == STATE_TRANSITION_IN_PROGRESS)
+    {
+    }
+
+    return state_out;
+}
+
+/*
+ * \brief Function starts the CCA process before starting data transmission and copies the data to RF TX FIFO.
+ *
+ * \param data_ptr Pointer to TX data (excluding FCS)
+ * \param data_length Length of the TX data (excluding FCS)
+ * \param tx_handle Handle to transmission
+ * \return 0 Success
+ * \return -1 Busy
+ */
+static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol )
+{
+    (void)data_protocol;
+    rf_if_lock();
+    /*Check if transmitter is busy*/
+    rf_trx_states_t trx_state = rf_if_read_trx_state();
+    if(trx_state == BUSY_RX || trx_state == BUSY_RX_AACK || data_length > RF_MTU - 2)
+    {
+        rf_if_unlock();
+        /*Return busy*/
+        return -1;
+    }
+    else
+    {
+        rf_give_up_on_ack();
+
+        /*Nanostack has a static TX buffer, which will remain valid until we*/
+        /*generate a callback, so we just note the pointer for reading later.*/
+        rf_tx_data = data_ptr;
+        rf_tx_length = data_length;
+        /*Start CCA timeout*/
+        rf_cca_timer_start(RF_CCA_BASE_BACKOFF + randLIB_get_random_in_range(0, RF_CCA_RANDOM_BACKOFF));
+        /*Store TX handle*/
+        mac_tx_handle = tx_handle;
+        rf_if_unlock();
+    }
+
+    /*Return success*/
+    return 0;
+}
+
+/*
+ * \brief Function aborts CCA process.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_cca_abort(void)
+{
+    rf_cca_timer_stop();
+    rf_flags_clear(RFF_CCA);
+}
+
+/*
+ * \brief Function starts the transmission of the frame.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static bool rf_start_tx()
+{
+    /* Attempt change to PLL_ON */
+    rf_if_write_register(TRX_STATE, PLL_ON);
+
+    // It appears that if radio is busy, rather than ignoring the state change,
+    // the state change happens when it stops being busy - eg
+    // after address match fail or finishing reception. If this happens, we do
+    // not want to transmit - our channel clear check is stale (either someone is
+    // still transmitting, or it's a long time since we checked). So wait for the
+    // PLL_ON change and then go to receive mode without trying to transmit.
+    rf_trx_states_t state = rf_poll_for_state();
+    int poll_count = 0;
+    while (state != PLL_ON) {
+        /* Change didn't work (yet) - must be busy - assume it will eventually change */
+        state = rf_poll_for_state();
+        poll_count++;
+    }
+
+    rf_flags_clear(RFF_RX);
+    // Check whether we saw any delay in the PLL_ON transition.
+    if (poll_count > 0) {
+        tr_warning("PLL_ON delayed, retry count: %d", poll_count);
+        // let's get back to the receiving state.
+        rf_receive(state);
+        return false;
+    }
+
+    rf_flags_set(RFF_TX);
+    /*RF state change: SLP_TR pulse triggers PLL_ON->BUSY_TX*/
+    rf_if_enable_slptr();
+    /*Chip permits us to write frame buffer while it is transmitting*/
+    /*As long as first byte of data is in within 176us of TX start, we're good */
+    rf_if_write_frame_buffer(rf_tx_data, rf_tx_length);
+    rf_if_disable_slptr();
+    return true;
+}
+
+/*
+ * \brief Function sets the RF in RX state.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_receive(rf_trx_states_t trx_status)
+{
+    uint16_t while_counter = 0;
+    if(rf_flags_check(RFF_ON) == 0)
+    {
+        rf_on();
+        rf_channel_set(rf_phy_channel);
+        trx_status = TRX_OFF;
+    }
+    /*If not yet in RX state set it*/
+    if(rf_flags_check(RFF_RX) == 0)
+    {
+        /*Wait while receiving data. Just making sure, usually this shouldn't happen. */
+        while(trx_status == BUSY_RX || trx_status == BUSY_RX_AACK || trx_status == STATE_TRANSITION_IN_PROGRESS)
+        {
+            while_counter++;
+            if(while_counter == 0xffff)
+            {
+                break;
+            }
+            trx_status = rf_if_read_trx_state();
+        }
+
+        if((rf_mode == RF_MODE_SNIFFER) || (rf_mode == RF_MODE_ED))
+        {
+            if (trx_status != RX_ON) {
+                trx_status = rf_if_change_trx_state(RX_ON);
+            }
+        }
+        else
+        {
+            /*ACK is always received in promiscuous mode to bypass address filters*/
+            if(rf_rx_mode)
+            {
+                rf_rx_mode = 0;
+                rf_if_enable_promiscuous_mode();
+            }
+            else
+            {
+                rf_if_disable_promiscuous_mode();
+            }
+            if (trx_status != RX_AACK_ON) {
+                trx_status = rf_if_change_trx_state(RX_AACK_ON);
+            }
+        }
+        /*If calibration timer was unable to calibrate the RF, run calibration now*/
+        if(!rf_tuned)
+        {
+            /*Start calibration. This can be done in states TRX_OFF, PLL_ON or in any receive state*/
+            rf_if_calibration();
+            /*RF is tuned now*/
+            rf_tuned = 1;
+        }
+
+        rf_flags_set(RFF_RX);
+    }
+}
+
+/*
+ * \brief Function calibrates the radio.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_calibration_cb(void)
+{
+    /*clear tuned flag to start tuning in rf_receive*/
+    rf_tuned = 0;
+    /*If RF is in default receive state, start calibration*/
+    if(rf_if_read_trx_state() == RX_AACK_ON)
+    {
+        rf_if_lock();
+        /*Set RF in PLL_ON state*/
+        rf_if_change_trx_state(PLL_ON);
+        /*Set RF in TRX_OFF state to start PLL tuning*/
+        rf_if_change_trx_state(TRX_OFF);
+        /*Set RF in RX_ON state to calibrate*/
+        rf_trx_states_t trx_status = rf_if_change_trx_state(RX_ON);
+        /*Calibrate FTN*/
+        rf_if_calibration();
+        /*RF is tuned now*/
+        rf_tuned = 1;
+        /*Back to default receive state*/
+        rf_flags_clear(RFF_RX);
+        rf_receive(trx_status);
+        rf_if_unlock();
+    }
+}
+
+/*
+ * \brief Function sets RF_ON flag when radio is powered.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_on(void)
+{
+    /*Set RFF_ON flag*/
+    if(rf_flags_check(RFF_ON) == 0)
+    {
+        rf_if_lock();
+        rf_flags_set(RFF_ON);
+        /*Enable Antenna diversity*/
+        if(rf_use_antenna_diversity)
+            /*Set ANT_EXT_SW_EN to enable controlling of antenna diversity*/
+            rf_if_enable_ant_div();
+
+        /*Wake up from sleep state*/
+        rf_if_disable_slptr();
+        rf_poll_trx_state_change(TRX_OFF);
+        rf_if_unlock();
+    }
+}
+
+/*
+ * \brief Abandon waiting for an ack frame
+
+ * \return none
+ */
+static void rf_give_up_on_ack(void)
+{
+    if (expected_ack_sequence == -1) {
+        return;
+    }
+
+    rf_if_disable_promiscuous_mode();
+    rf_if_ack_wait_timer_stop();
+    expected_ack_sequence = -1;
+
+    if(device_driver.phy_tx_done_cb){
+        device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_FAIL, 0, 0);
+    }
+}
+
+/*
+ * \brief Function handles the received ACK frame.
+ *
+ * \param seq_number Sequence number of received ACK
+ * \param data_pending Pending bit state in received ACK
+ *
+ * \return none
+ */
+static void rf_handle_ack(uint8_t seq_number, uint8_t data_pending)
+{
+    phy_link_tx_status_e phy_status;
+    /*Received ACK sequence must be equal with transmitted packet sequence*/
+    if(expected_ack_sequence == seq_number)
+    {
+        rf_if_disable_promiscuous_mode();
+        rf_if_ack_wait_timer_stop();
+        expected_ack_sequence = -1;
+
+        /*When data pending bit in ACK frame is set, inform NET library*/
+        if(data_pending)
+            phy_status = PHY_LINK_TX_DONE_PENDING;
+        else
+            phy_status = PHY_LINK_TX_DONE;
+        /*Call PHY TX Done API*/
+        if(device_driver.phy_tx_done_cb){
+            device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle,phy_status, 0, 0);
+        }
+    } else {
+        rf_give_up_on_ack();
+    }
+}
+
+/*
+ * \brief Function is a call back for RX end interrupt.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_handle_rx_end(rf_trx_states_t trx_status)
+{
+    /*Frame received interrupt*/
+    if(!rf_flags_check(RFF_RX)) {
+        return;
+    }
+
+    static uint8_t rf_buffer[RF_MTU];
+    uint8_t rf_lqi, rf_ed;
+    int8_t rf_rssi;
+    bool crc_good;
+
+    /*Read received packet*/
+    uint8_t len = rf_if_read_packet(rf_buffer, &rf_lqi, &rf_ed, &crc_good);
+
+    if (len < 5 || !crc_good) {
+        rf_give_up_on_ack();
+        return;
+    }
+
+    /* Convert raw ED to dBm value (chip-dependent) */
+    rf_rssi = rf_if_scale_rssi(rf_ed);
+
+    /* Create a virtual LQI using received RSSI, forgetting actual HW LQI */
+    /* (should be done through PHY_EXTENSION_CONVERT_SIGNAL_INFO) */
+    rf_lqi = rf_scale_lqi(rf_rssi);
+
+    /*Handle received ACK*/
+    if((rf_buffer[0] & 0x07) == 0x02 && rf_mode != RF_MODE_SNIFFER)
+    {
+        /*Check if data is pending*/
+        bool pending = (rf_buffer[0] & 0x10);
+
+        /*Send sequence number in ACK handler*/
+        rf_handle_ack(rf_buffer[2], pending);
+    } else {
+        rf_give_up_on_ack();
+        if( device_driver.phy_rx_cb ){
+            device_driver.phy_rx_cb(rf_buffer, len - 2, rf_lqi, rf_rssi, rf_radio_driver_id);
+        }
+    }
+}
+
+/*
+ * \brief Function is called when MAC is shutting down the radio.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_shutdown(void)
+{
+    /*Call RF OFF*/
+    rf_off();
+}
+
+/*
+ * \brief Function is a call back for TX end interrupt.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_handle_tx_end(rf_trx_states_t trx_status)
+{
+    rf_rx_mode = 0;
+    /*If ACK is needed for this transmission*/
+    if((rf_tx_data[0] & 0x20) && rf_flags_check(RFF_TX))
+    {
+        expected_ack_sequence = rf_tx_data[2];
+        rf_ack_wait_timer_start(rf_ack_wait_duration);
+        rf_rx_mode = 1;
+    }
+    rf_flags_clear(RFF_TX);
+    /*Start receiver*/
+    rf_receive(trx_status);
+
+    /*Call PHY TX Done API*/
+    if(device_driver.phy_tx_done_cb){
+        device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 0, 0);
+    }
+}
+
+/*
+ * \brief Function is a call back for CCA ED done interrupt.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_handle_cca_ed_done(uint8_t full_trx_status)
+{
+    if (!rf_flags_check(RFF_CCA)) {
+        return;
+    }
+    rf_flags_clear(RFF_CCA);
+
+    bool success = false;
+
+    /*Check the result of CCA process*/
+    if((full_trx_status & CCA_STATUS) && rf_if_trx_status_from_full(full_trx_status) == RX_AACK_ON)
+    {
+        success = rf_start_tx();
+    }
+
+    if (!success)
+    {
+        /*Send CCA fail notification*/
+        if(device_driver.phy_tx_done_cb){
+            device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 0, 0);
+        }
+    }
+}
+
+/*
+ * \brief Function gives the control of RF states to MAC.
+ *
+ * \param new_state RF state
+ * \param rf_channel RF channel
+ *
+ * \return 0 Success
+ */
+static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel)
+{
+    int8_t ret_val = 0;
+    switch (new_state)
+    {
+        /*Reset PHY driver and set to idle*/
+        case PHY_INTERFACE_RESET:
+            break;
+        /*Disable PHY Interface driver*/
+        case PHY_INTERFACE_DOWN:
+            rf_shutdown();
+            break;
+        /*Enable PHY Interface driver*/
+        case PHY_INTERFACE_UP:
+            rf_if_lock();
+            rf_mode = RF_MODE_NORMAL;
+            rf_channel_set(rf_channel);
+            rf_receive();
+            rf_if_enable_irq();
+            rf_if_unlock();
+            break;
+        /*Enable wireless interface ED scan mode*/
+        case PHY_INTERFACE_RX_ENERGY_STATE:
+            rf_mode = RF_MODE_ED;
+            rf_channel_set(rf_channel);
+            rf_receive();
+            rf_if_disable_irq();
+            // Read status to clear pending flags.
+            rf_if_read_register(IRQ_STATUS);
+            // ED can be initiated by writing arbitrary value to PHY_ED_LEVEL
+            rf_if_write_register(PHY_ED_LEVEL, 0xff);
+            break;
+        case PHY_INTERFACE_SNIFFER_STATE:             /**< Enable Sniffer state */
+            rf_mode = RF_MODE_SNIFFER;
+            rf_channel_set(rf_channel);
+            rf_flags_clear(RFF_RX);
+            rf_receive();
+            rf_if_enable_irq();
+            break;
+    }
+    return ret_val;
+}
+
+/*
+ * \brief Function controls the ACK pending, channel setting and energy detection.
+ *
+ * \param extension_type Type of control
+ * \param data_ptr Data from NET library
+ *
+ * \return 0 Success
+ */
+static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr)
+{
+    switch (extension_type)
+    {
+        /*Control MAC pending bit for Indirect data transmission*/
+        case PHY_EXTENSION_CTRL_PENDING_BIT:
+            if(*data_ptr)
+            {
+                rf_if_ack_pending_ctrl(1);
+            }
+            else
+            {
+                rf_if_ack_pending_ctrl(0);
+            }
+            break;
+        /*Return frame pending status*/
+        case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS:
+            *data_ptr = rf_if_last_acked_pending();
+            break;
+        /*Set channel*/
+        case PHY_EXTENSION_SET_CHANNEL:
+            break;
+        /*Read energy on the channel*/
+        case PHY_EXTENSION_READ_CHANNEL_ENERGY:
+            // End of the ED measurement is indicated by CCA_ED_DONE
+            while (!(rf_if_read_register(IRQ_STATUS) & CCA_ED_DONE));
+            // RF input power: RSSI base level + 1[db] * PHY_ED_LEVEL
+            *data_ptr = rf_sensitivity + rf_if_read_register(PHY_ED_LEVEL);
+            // Read status to clear pending flags.
+            rf_if_read_register(IRQ_STATUS);
+            // Next ED measurement is started, next PHY_EXTENSION_READ_CHANNEL_ENERGY call will return the result.
+            rf_if_write_register(PHY_ED_LEVEL, 0xff);
+            break;
+        /*Read status of the link*/
+        case PHY_EXTENSION_READ_LINK_STATUS:
+            break;
+        default:
+            break;
+    }
+    return 0;
+}
+
+/*
+ * \brief Function sets the addresses to RF address filters.
+ *
+ * \param address_type Type of address
+ * \param address_ptr Pointer to given address
+ *
+ * \return 0 Success
+ */
+static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr)
+{
+    int8_t ret_val = 0;
+    switch (address_type)
+    {
+        /*Set 48-bit address*/
+        case PHY_MAC_48BIT:
+            break;
+            /*Set 64-bit address*/
+        case PHY_MAC_64BIT:
+            rf_set_address(address_ptr);
+            break;
+        /*Set 16-bit address*/
+        case PHY_MAC_16BIT:
+            rf_set_short_adr(address_ptr);
+            break;
+        /*Set PAN Id*/
+        case PHY_MAC_PANID:
+            rf_set_pan_id(address_ptr);
+            break;
+    }
+    return ret_val;
+}
+
+/*
+ * \brief Function initialises the ACK wait time and returns the used PHY mode.
+ *
+ * \param none
+ *
+ * \return tmp Used PHY mode
+ */
+static void rf_init_phy_mode(void)
+{
+    uint8_t tmp = 0;
+    uint8_t part = rf_if_read_part_num();
+    /*Read used PHY Mode*/
+    tmp = rf_if_read_register(TRX_CTRL_2);
+    /*Set ACK wait time for used data rate*/
+    if(part == PART_AT86RF212)
+    {
+        if((tmp & 0x1f) == 0x00)
+        {
+            rf_sensitivity = -110;
+            rf_ack_wait_duration = 938;
+            tmp = BPSK_20;
+        }
+        else if((tmp & 0x1f) == 0x04)
+        {
+            rf_sensitivity = -108;
+            rf_ack_wait_duration = 469;
+            tmp = BPSK_40;
+        }
+        else if((tmp & 0x1f) == 0x14)
+        {
+            rf_sensitivity = -108;
+            rf_ack_wait_duration = 469;
+            tmp = BPSK_40_ALT;
+        }
+        else if((tmp & 0x1f) == 0x08)
+        {
+            rf_sensitivity = -101;
+            rf_ack_wait_duration = 50;
+            tmp = OQPSK_SIN_RC_100;
+        }
+        else if((tmp & 0x1f) == 0x09)
+        {
+            rf_sensitivity = -99;
+            rf_ack_wait_duration = 30;
+            tmp = OQPSK_SIN_RC_200;
+        }
+        else if((tmp & 0x1f) == 0x18)
+        {
+            rf_sensitivity = -102;
+            rf_ack_wait_duration = 50;
+            tmp = OQPSK_RC_100;
+        }
+        else if((tmp & 0x1f) == 0x19)
+        {
+            rf_sensitivity = -100;
+            rf_ack_wait_duration = 30;
+            tmp = OQPSK_RC_200;
+        }
+        else if((tmp & 0x1f) == 0x0c)
+        {
+            rf_sensitivity = -100;
+            rf_ack_wait_duration = 20;
+            tmp = OQPSK_SIN_250;
+        }
+        else if((tmp & 0x1f) == 0x0d)
+        {
+            rf_sensitivity = -98;
+            rf_ack_wait_duration = 25;
+            tmp = OQPSK_SIN_500;
+        }
+        else if((tmp & 0x1f) == 0x0f)
+        {
+            rf_sensitivity = -98;
+            rf_ack_wait_duration = 25;
+            tmp = OQPSK_SIN_500_ALT;
+        }
+        else if((tmp & 0x1f) == 0x1c)
+        {
+            rf_sensitivity = -101;
+            rf_ack_wait_duration = 20;
+            tmp = OQPSK_RC_250;
+        }
+        else if((tmp & 0x1f) == 0x1d)
+        {
+            rf_sensitivity = -99;
+            rf_ack_wait_duration = 25;
+            tmp = OQPSK_RC_500;
+        }
+        else if((tmp & 0x1f) == 0x1f)
+        {
+            rf_sensitivity = -99;
+            rf_ack_wait_duration = 25;
+            tmp = OQPSK_RC_500_ALT;
+        }
+        else if((tmp & 0x3f) == 0x2A)
+        {
+            rf_sensitivity = -91;
+            rf_ack_wait_duration = 25;
+            tmp = OQPSK_SIN_RC_400_SCR_ON;
+        }
+        else if((tmp & 0x3f) == 0x0A)
+        {
+            rf_sensitivity = -91;
+            rf_ack_wait_duration = 25;
+            tmp = OQPSK_SIN_RC_400_SCR_OFF;
+        }
+        else if((tmp & 0x3f) == 0x3A)
+        {
+            rf_sensitivity = -97;
+            rf_ack_wait_duration = 25;
+            tmp = OQPSK_RC_400_SCR_ON;
+        }
+        else if((tmp & 0x3f) == 0x1A)
+        {
+            rf_sensitivity = -97;
+            rf_ack_wait_duration = 25;
+            tmp = OQPSK_RC_400_SCR_OFF;
+        }
+        else if((tmp & 0x3f) == 0x2E)
+        {
+            rf_sensitivity = -93;
+            rf_ack_wait_duration = 13;
+            tmp = OQPSK_SIN_1000_SCR_ON;
+        }
+        else if((tmp & 0x3f) == 0x0E)
+        {
+            rf_sensitivity = -93;
+            rf_ack_wait_duration = 13;
+            tmp = OQPSK_SIN_1000_SCR_OFF;
+        }
+        else if((tmp & 0x3f) == 0x3E)
+        {
+            rf_sensitivity = -95;
+            rf_ack_wait_duration = 13;
+            tmp = OQPSK_RC_1000_SCR_ON;
+        }
+        else if((tmp & 0x3f) == 0x1E)
+        {
+            rf_sensitivity = -95;
+            rf_ack_wait_duration = 13;
+            tmp = OQPSK_RC_1000_SCR_OFF;
+        }
+    }
+    else
+    {
+        rf_sensitivity = -101;
+        rf_ack_wait_duration = 20;
+    }
+    /*Board design might reduces the sensitivity*/
+    //rf_sensitivity += RF_SENSITIVITY_CALIBRATION;
+}
+
+
+static uint8_t rf_scale_lqi(int8_t rssi)
+{
+    uint8_t scaled_lqi;
+
+    /*rssi < RF sensitivity*/
+    if(rssi < rf_sensitivity)
+        scaled_lqi=0;
+    /*-91 dBm < rssi < -81 dBm (AT86RF233 XPro)*/
+    /*-90 dBm < rssi < -80 dBm (AT86RF212B XPro)*/
+    else if(rssi < (rf_sensitivity + 10))
+        scaled_lqi=31;
+    /*-81 dBm < rssi < -71 dBm (AT86RF233 XPro)*/
+    /*-80 dBm < rssi < -70 dBm (AT86RF212B XPro)*/
+    else if(rssi < (rf_sensitivity + 20))
+        scaled_lqi=207;
+    /*-71 dBm < rssi < -61 dBm (AT86RF233 XPro)*/
+    /*-70 dBm < rssi < -60 dBm (AT86RF212B XPro)*/
+    else if(rssi < (rf_sensitivity + 30))
+        scaled_lqi=255;
+    /*-61 dBm < rssi < -51 dBm (AT86RF233 XPro)*/
+    /*-60 dBm < rssi < -50 dBm (AT86RF212B XPro)*/
+    else if(rssi < (rf_sensitivity + 40))
+        scaled_lqi=255;
+    /*-51 dBm < rssi < -41 dBm (AT86RF233 XPro)*/
+    /*-50 dBm < rssi < -40 dBm (AT86RF212B XPro)*/
+    else if(rssi < (rf_sensitivity + 50))
+        scaled_lqi=255;
+    /*-41 dBm < rssi < -31 dBm (AT86RF233 XPro)*/
+    /*-40 dBm < rssi < -30 dBm (AT86RF212B XPro)*/
+    else if(rssi < (rf_sensitivity + 60))
+        scaled_lqi=255;
+    /*-31 dBm < rssi < -21 dBm (AT86RF233 XPro)*/
+    /*-30 dBm < rssi < -20 dBm (AT86RF212B XPro)*/
+    else if(rssi < (rf_sensitivity + 70))
+        scaled_lqi=255;
+    /*rssi > RF saturation*/
+    else if(rssi > (rf_sensitivity + 80))
+        scaled_lqi=111;
+    /*-21 dBm < rssi < -11 dBm (AT86RF233 XPro)*/
+    /*-20 dBm < rssi < -10 dBm (AT86RF212B XPro)*/
+    else
+        scaled_lqi=255;
+
+    return scaled_lqi;
+}
+
+NanostackRfPhyAtmel::NanostackRfPhyAtmel(PinName spi_mosi, PinName spi_miso,
+        PinName spi_sclk, PinName spi_cs,  PinName spi_rst, PinName spi_slp, PinName spi_irq,
+        PinName i2c_sda, PinName i2c_scl)
+    : _mac(i2c_sda, i2c_scl), _mac_addr(), _rf(NULL), _mac_set(false),
+      _spi_mosi(spi_mosi), _spi_miso(spi_miso), _spi_sclk(spi_sclk),
+      _spi_cs(spi_cs), _spi_rst(spi_rst), _spi_slp(spi_slp), _spi_irq(spi_irq)
+{
+    _rf = new RFBits(_spi_mosi, _spi_miso, _spi_sclk, _spi_cs, _spi_rst, _spi_slp, _spi_irq);
+}
+
+NanostackRfPhyAtmel::~NanostackRfPhyAtmel()
+{
+    delete _rf;
+}
+
+int8_t NanostackRfPhyAtmel::rf_register()
+{
+    if (NULL == _rf) {
+        return -1;
+    }
+
+    rf_if_lock();
+
+    if (rf != NULL) {
+        rf_if_unlock();
+        error("Multiple registrations of NanostackRfPhyAtmel not supported");
+        return -1;
+    }
+
+    // Read the mac address if it hasn't been set by a user
+    rf = _rf;
+    if (!_mac_set) {
+        int ret = _mac.read_eui64((void*)_mac_addr);
+        if (ret < 0) {
+            rf = NULL;
+            rf_if_unlock();
+            return -1;
+        }
+    }
+
+    int8_t radio_id = rf_device_register(_mac_addr);
+    if (radio_id < 0) {
+        rf = NULL;
+    }
+
+    rf_if_unlock();
+    return radio_id;
+}
+
+void NanostackRfPhyAtmel::rf_unregister()
+{
+    rf_if_lock();
+
+    if (NULL == rf) {
+        rf_if_unlock();
+        return;
+    }
+
+    rf_device_unregister();
+    rf = NULL;
+
+    rf_if_unlock();
+}
+
+void NanostackRfPhyAtmel::get_mac_address(uint8_t *mac)
+{
+    rf_if_lock();
+
+    if (NULL == rf) {
+        error("NanostackRfPhyAtmel Must be registered to read mac address");
+        rf_if_unlock();
+        return;
+    }
+    memcpy((void*)mac, (void*)_mac_addr, sizeof(_mac_addr));
+
+    rf_if_unlock();
+}
+
+void NanostackRfPhyAtmel::set_mac_address(uint8_t *mac)
+{
+    rf_if_lock();
+
+    if (NULL != rf) {
+        error("NanostackRfPhyAtmel cannot change mac address when running");
+        rf_if_unlock();
+        return;
+    }
+    memcpy((void*)_mac_addr, (void*)mac, sizeof(_mac_addr));
+    _mac_set = true;
+
+    rf_if_unlock();
+}
+
+#if MBED_CONF_ATMEL_RF_PROVIDE_DEFAULT
+
+NanostackRfPhy &NanostackRfPhy::get_default_instance()
+{
+  static NanostackRfPhyAtmel rf_phy(ATMEL_SPI_MOSI, ATMEL_SPI_MISO, ATMEL_SPI_SCLK, ATMEL_SPI_CS,
+                           ATMEL_SPI_RST, ATMEL_SPI_SLP, ATMEL_SPI_IRQ, ATMEL_I2C_SDA, ATMEL_I2C_SCL);
+  return rf_phy;
+}
+
+#endif // MBED_CONF_ATMEL_RF_PROVIDE_DEFAULT
+
+#endif // MBED_CONF_NANOSTACK_CONFIGURATION
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/atmel-rf-driver/source/at24mac.cpp	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2016-2016 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 "at24mac.h"
+
+#if DEVICE_I2C
+
+/* Device addressing */
+#define AT24MAC_EEPROM_ADDRESS		(0x0A<<4)
+#define AT24MAC_RW_PROTECT_ADDRESS	(0x06<<4)
+#define AT24MAC_SERIAL_ADDRESS		(0x0B<<4)
+
+/* Known memory blocks */
+#define AT24MAC_SERIAL_OFFSET	(0x80)
+#define AT24MAC_EUI64_OFFSET	(0x98)
+#define AT24MAC_EUI48_OFFSET	(0x9A)
+
+#define SERIAL_LEN 16
+#define EUI64_LEN 8
+#define EUI48_LEN 6
+
+AT24Mac::I2CReset::I2CReset(PinName sda, PinName scl)
+{
+    mbed::DigitalInOut pin_sda(sda, PIN_OUTPUT, PullUp, 1);
+    mbed::DigitalInOut pin_scl(scl, PIN_OUTPUT, PullUp, 0);
+    //generate 9 clocks for worst-case scenario
+    for (int i = 0; i < 10; ++i) {
+        pin_scl = 1;
+        wait_us(5);
+        pin_scl = 0;
+        wait_us(5);
+    }
+    //generate a STOP condition
+    pin_sda = 0;
+    wait_us(5);
+    pin_scl = 1;
+    wait_us(5);
+    pin_sda = 1;
+    wait_us(5);
+}
+
+/*I2C needs to be reset before constructing the I2C object (in case I2C is stuck)
+  because they use the same pins, therefore i2c_reset has to be before _i2c
+  in the initializer list*/
+AT24Mac::AT24Mac(PinName sda, PinName scl) : i2c_reset(sda, scl), _i2c(sda, scl)
+{
+    // Do nothing
+}
+
+int AT24Mac::read_serial(void *buf)
+{
+    char offset = AT24MAC_SERIAL_OFFSET;
+    if (_i2c.write(AT24MAC_SERIAL_ADDRESS, &offset, 1, true))
+        return -1; //No ACK
+    return _i2c.read(AT24MAC_SERIAL_ADDRESS, (char*)buf, SERIAL_LEN);
+}
+
+int AT24Mac::read_eui64(void *buf)
+{
+    char offset = AT24MAC_EUI64_OFFSET;
+    if (_i2c.write(AT24MAC_SERIAL_ADDRESS, &offset, 1, true))
+        return -1; //No ACK
+    return _i2c.read(AT24MAC_SERIAL_ADDRESS, (char*)buf, EUI64_LEN);
+}
+
+int AT24Mac::read_eui48(void *buf)
+{
+    char offset = AT24MAC_EUI48_OFFSET;
+    if (_i2c.write(AT24MAC_SERIAL_ADDRESS, &offset, 1, true))
+        return -1; //No ACK
+    return _i2c.read(AT24MAC_SERIAL_ADDRESS, (char*)buf, EUI48_LEN);
+}
+
+#endif /* DEVICE_I2C */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/atmel-rf-driver/source/at24mac.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+#ifndef AT24MAC_H
+#define AT24MAC_H
+
+#include "PinNames.h"
+
+#if DEVICE_I2C
+
+#include "I2C.h"
+#include "drivers/DigitalInOut.h"
+#include "platform/mbed_wait_api.h"
+
+/*
+ * AT24MAC drivers.
+ *
+ * This is a EEPROM chip designed to contain factory programmed read-only EUI-64 or EUI-48,
+ * a 128bit serial number and some user programmable EEPROM.
+ *
+ * AT24MAC602 contains EUI-64, use read_eui64()
+ * AT24MAC402 contains EUI-64, use read_eui48()
+ *
+ * NOTE: You cannot use both EUI-64 and EUI-48. Chip contains only one of those.
+ */
+
+class AT24Mac {
+public:
+    AT24Mac(PinName sda, PinName scl);
+
+    /**
+     * Read unique serial number from chip.
+     * \param buf pointer to write serial number to. Must have space for 16 bytes.
+     * \return zero on success, negative number on failure
+     */
+    int read_serial(void *buf);
+
+    /**
+     * Read EUI-64 from chip.
+     * \param buf pointer to write EUI-64 to. Must have space for 8 bytes.
+     * \return zero on success, negative number on failure
+     */
+    int read_eui64(void *buf);
+
+    /**
+     * Read EUI-48 from chip.
+     * \param buf pointer to write EUI-48 to. Must have space for 6 bytes.
+     * \return zero on success, negative number on failure
+     */
+    int read_eui48(void *buf);
+
+private:
+    /*
+     * Dummy class to allow us to reset I2C before the I2C constructor is called in
+     * the initializer list of AT24Mac's constructor
+     */
+    class I2CReset {
+    public:
+        I2CReset(PinName sda, PinName scl);
+    };
+    I2CReset i2c_reset;
+    mbed::I2C _i2c;
+};
+
+#endif /* DEVICE_I2C */
+#endif /* AT24MAC_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/mcr20a-rf-driver/LICENSE	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,2 @@
+Unless specifically indicated otherwise in a file, files are licensed
+under the Apache 2.0 license, as can be found in: apache-2.0.txt
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/mcr20a-rf-driver/README.md	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,6 @@
+# Example RF driver for Freescale 802.15.4 transceivers #
+
+Support for:
+ * MCR20A
+
+This driver is used with 6LoWPAN stack.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/mcr20a-rf-driver/apache-2.0.txt	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,56 @@
+
+
+Apache License
+
+Version 2.0, January 2004
+
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+
+    You must give any other recipients of the Work or Derivative Works a copy of this License; and
+    You must cause any modified files to carry prominent notices stating that You changed the files; and
+    You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+    If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+    You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/mcr20a-rf-driver/mbed_lib.json	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,9 @@
+{
+    "name": "mcr20a",
+    "config": {
+        "provide-default": {
+            "help": "Provide default NanostackRfpy. [true/false]",
+            "value": false
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/mcr20a-rf-driver/mcr20a-rf-driver/NanostackRfPhyMcr20a.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#ifndef NANOSTACK_PHY_MCR20A_H_
+#define NANOSTACK_PHY_MCR20A_H_
+
+#include "mbed.h"
+
+#if defined(MBED_CONF_NANOSTACK_CONFIGURATION) && DEVICE_SPI
+
+#include "NanostackRfPhy.h"
+
+// Arduino pin defaults for convenience
+#if !defined(MCR20A_SPI_MOSI)
+#define MCR20A_SPI_MOSI   D11
+#endif
+#if !defined(MCR20A_SPI_MISO)
+#define MCR20A_SPI_MISO   D12
+#endif
+#if !defined(MCR20A_SPI_SCLK)
+#define MCR20A_SPI_SCLK   D13
+#endif
+#if !defined(MCR20A_SPI_CS)
+#define MCR20A_SPI_CS     D10
+#endif
+#if !defined(MCR20A_SPI_RST)
+#define MCR20A_SPI_RST    D5
+#endif
+#if !defined(MCR20A_SPI_IRQ)
+#define MCR20A_SPI_IRQ    D2
+#endif
+
+class NanostackRfPhyMcr20a : public NanostackRfPhy {
+public:
+    NanostackRfPhyMcr20a(PinName spi_mosi, PinName spi_miso,
+                         PinName spi_sclk, PinName spi_cs,  PinName spi_rst,
+                         PinName spi_irq);
+    virtual ~NanostackRfPhyMcr20a();
+    virtual int8_t rf_register();
+    virtual void rf_unregister();
+    virtual void get_mac_address(uint8_t *mac);
+    virtual void set_mac_address(uint8_t *mac);
+
+private:
+    SPI _spi;
+    DigitalOut _rf_cs;
+    DigitalOut _rf_rst;
+    InterruptIn _rf_irq;
+    DigitalIn _rf_irq_pin;
+    Thread _irq_thread;
+
+    void _pins_set();
+    void _pins_clear();
+};
+
+#endif /* MBED_CONF_NANOSTACK_CONFIGURATION */
+#endif /* NANOSTACK_PHY_MCR20A_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/mcr20a-rf-driver/source/MCR20Drv.c	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,683 @@
+/*!
+* Copyright (c) 2015, Freescale Semiconductor, Inc.
+* All rights reserved.
+*
+* \file MCR20Drv.c
+*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+*
+* o Redistributions of source code must retain the above copyright notice, this list
+*   of conditions and the following disclaimer.
+*
+* o Redistributions in binary form must reproduce the above copyright notice, this
+*   list of conditions and the following disclaimer in the documentation and/or
+*   other materials provided with the distribution.
+*
+* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
+*   contributors may be used to endorse or promote products derived from this
+*   software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+/*****************************************************************************
+*                               INCLUDED HEADERS                            *
+*---------------------------------------------------------------------------*
+* Add to this section all the headers that this module needs to include.    *
+*---------------------------------------------------------------------------*
+*****************************************************************************/
+
+#include "MCR20Drv.h"
+#include "MCR20Reg.h"
+#include "XcvrSpi.h"
+
+#if defined(MBED_CONF_NANOSTACK_CONFIGURATION) && DEVICE_SPI
+
+#include "platform/mbed_critical.h"
+
+/*****************************************************************************
+*                               PRIVATE VARIABLES                           *
+*---------------------------------------------------------------------------*
+* Add to this section all the variables and constants that have local       *
+* (file) scope.                                                             *
+* Each of this declarations shall be preceded by the 'static' keyword.      *
+* These variables / constants cannot be accessed outside this module.       *
+*---------------------------------------------------------------------------*
+*****************************************************************************/
+uint32_t mPhyIrqDisableCnt = 1;
+
+/*****************************************************************************
+*                               PUBLIC VARIABLES                            *
+*---------------------------------------------------------------------------*
+* Add to this section all the variables and constants that have global      *
+* (project) scope.                                                          *
+* These variables / constants can be accessed outside this module.          *
+* These variables / constants shall be preceded by the 'extern' keyword in  *
+* the interface header.                                                     *
+*---------------------------------------------------------------------------*
+*****************************************************************************/
+
+/*****************************************************************************
+*                           PRIVATE FUNCTIONS PROTOTYPES                    *
+*---------------------------------------------------------------------------*
+* Add to this section all the functions prototypes that have local (file)   *
+* scope.                                                                    *
+* These functions cannot be accessed outside this module.                   *
+* These declarations shall be preceded by the 'static' keyword.             *
+*---------------------------------------------------------------------------*
+*****************************************************************************/
+
+/*****************************************************************************
+*                                PRIVATE FUNCTIONS                          *
+*---------------------------------------------------------------------------*
+* Add to this section all the functions that have local (file) scope.       *
+* These functions cannot be accessed outside this module.                   *
+* These definitions shall be preceded by the 'static' keyword.              *
+*---------------------------------------------------------------------------*
+*****************************************************************************/
+
+
+/*****************************************************************************
+*                             PUBLIC FUNCTIONS                              *
+*---------------------------------------------------------------------------*
+* Add to this section all the functions that have global (project) scope.   *
+* These functions can be accessed outside this module.                      *
+* These functions shall have their declarations (prototypes) within the     *
+* interface header file and shall be preceded by the 'extern' keyword.      *
+*---------------------------------------------------------------------------*
+*****************************************************************************/
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_Init
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+void MCR20Drv_Init
+(
+void
+)
+{
+    xcvr_spi_init(gXcvrSpiInstance_c);
+    xcvr_spi_configure_speed(gXcvrSpiInstance_c, 8000000);
+
+    gXcvrDeassertCS_d();
+    #if !defined(TARGET_KW24D)
+      MCR20Drv_RST_B_Deassert();
+    #endif
+    RF_IRQ_Init();
+    RF_IRQ_Disable();
+    mPhyIrqDisableCnt = 1;
+}
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_DirectAccessSPIWrite
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+void MCR20Drv_DirectAccessSPIWrite
+(
+uint8_t address,
+uint8_t value
+)
+{
+    uint16_t txData;
+
+    ProtectFromMCR20Interrupt();
+
+    xcvr_spi_configure_speed(gXcvrSpiInstance_c, 16000000);
+
+    gXcvrAssertCS_d();
+
+    txData = (address & TransceiverSPI_DirectRegisterAddressMask);
+    txData |= value << 8;
+
+    xcvr_spi_transfer(gXcvrSpiInstance_c, (uint8_t *)&txData, 0, sizeof(txData));
+
+    gXcvrDeassertCS_d();
+    UnprotectFromMCR20Interrupt();
+}
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_DirectAccessSPIMultiByteWrite
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+void MCR20Drv_DirectAccessSPIMultiByteWrite
+(
+uint8_t startAddress,
+uint8_t * byteArray,
+uint8_t numOfBytes
+)
+{
+    uint8_t txData;
+
+    if( (numOfBytes == 0) || (byteArray == 0) )
+    {
+        return;
+    }
+
+    ProtectFromMCR20Interrupt();
+
+    xcvr_spi_configure_speed(gXcvrSpiInstance_c, 16000000);
+
+    gXcvrAssertCS_d();
+
+    txData = (startAddress & TransceiverSPI_DirectRegisterAddressMask);
+
+    xcvr_spi_transfer(gXcvrSpiInstance_c, &txData, 0, sizeof(txData));
+    xcvr_spi_transfer(gXcvrSpiInstance_c, byteArray, 0, numOfBytes);
+
+    gXcvrDeassertCS_d();
+    UnprotectFromMCR20Interrupt();
+}
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_PB_SPIByteWrite
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+void MCR20Drv_PB_SPIByteWrite
+(
+uint8_t address,
+uint8_t value
+)
+{
+    uint32_t txData;
+
+    ProtectFromMCR20Interrupt();
+
+    xcvr_spi_configure_speed(gXcvrSpiInstance_c, 16000000);
+
+    gXcvrAssertCS_d();
+
+    txData  = TransceiverSPI_WriteSelect            |
+        TransceiverSPI_PacketBuffAccessSelect |
+            TransceiverSPI_PacketBuffByteModeSelect;
+    txData |= (address) << 8;
+    txData |= (value)   << 16;
+
+    xcvr_spi_transfer(gXcvrSpiInstance_c, (uint8_t*)&txData, 0, 3);
+
+    gXcvrDeassertCS_d();
+    UnprotectFromMCR20Interrupt();
+}
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_PB_SPIBurstWrite
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+void MCR20Drv_PB_SPIBurstWrite
+(
+uint8_t * byteArray,
+uint8_t numOfBytes
+)
+{
+    uint8_t txData;
+
+    if( (numOfBytes == 0) || (byteArray == 0) )
+    {
+        return;
+    }
+
+    ProtectFromMCR20Interrupt();
+
+    xcvr_spi_configure_speed(gXcvrSpiInstance_c, 16000000);
+
+    gXcvrAssertCS_d();
+
+    txData = TransceiverSPI_WriteSelect            |
+        TransceiverSPI_PacketBuffAccessSelect |
+            TransceiverSPI_PacketBuffBurstModeSelect;
+
+    xcvr_spi_transfer(gXcvrSpiInstance_c, &txData, 0, 1);
+    xcvr_spi_transfer(gXcvrSpiInstance_c, byteArray, 0, numOfBytes);
+
+    gXcvrDeassertCS_d();
+    UnprotectFromMCR20Interrupt();
+}
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_DirectAccessSPIRead
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+
+uint8_t MCR20Drv_DirectAccessSPIRead
+(
+uint8_t address
+)
+{
+    uint8_t txData;
+    uint8_t rxData;
+
+    ProtectFromMCR20Interrupt();
+
+    xcvr_spi_configure_speed(gXcvrSpiInstance_c, 8000000);
+
+    gXcvrAssertCS_d();
+
+    txData = (address & TransceiverSPI_DirectRegisterAddressMask) |
+        TransceiverSPI_ReadSelect;
+
+    xcvr_spi_transfer(gXcvrSpiInstance_c, &txData, 0, sizeof(txData));
+    xcvr_spi_transfer(gXcvrSpiInstance_c, 0, &rxData, sizeof(rxData));
+
+    gXcvrDeassertCS_d();
+    UnprotectFromMCR20Interrupt();
+
+    return rxData;
+
+}
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_DirectAccessSPIMultyByteRead
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+uint8_t MCR20Drv_DirectAccessSPIMultiByteRead
+(
+uint8_t startAddress,
+uint8_t * byteArray,
+uint8_t numOfBytes
+)
+{
+    uint8_t  txData;
+    uint8_t  phyIRQSTS1;
+
+    if( (numOfBytes == 0) || (byteArray == 0) )
+    {
+        return 0;
+    }
+
+    ProtectFromMCR20Interrupt();
+
+    xcvr_spi_configure_speed(gXcvrSpiInstance_c, 8000000);
+
+    gXcvrAssertCS_d();
+
+    txData = (startAddress & TransceiverSPI_DirectRegisterAddressMask) |
+        TransceiverSPI_ReadSelect;
+
+    xcvr_spi_transfer(gXcvrSpiInstance_c, &txData, &phyIRQSTS1, sizeof(txData));
+    xcvr_spi_transfer(gXcvrSpiInstance_c, 0, byteArray, numOfBytes);
+
+    gXcvrDeassertCS_d();
+    UnprotectFromMCR20Interrupt();
+
+    return phyIRQSTS1;
+}
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_PB_SPIBurstRead
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+uint8_t MCR20Drv_PB_SPIBurstRead
+(
+uint8_t * byteArray,
+uint8_t numOfBytes
+)
+{
+    uint8_t  txData;
+    uint8_t  phyIRQSTS1;
+
+    if( (numOfBytes == 0) || (byteArray == 0) )
+    {
+        return 0;
+    }
+
+    ProtectFromMCR20Interrupt();
+
+    xcvr_spi_configure_speed(gXcvrSpiInstance_c, 8000000);
+
+    gXcvrAssertCS_d();
+
+    txData = TransceiverSPI_ReadSelect |
+        TransceiverSPI_PacketBuffAccessSelect |
+            TransceiverSPI_PacketBuffBurstModeSelect;
+
+    xcvr_spi_transfer(gXcvrSpiInstance_c, &txData, &phyIRQSTS1, sizeof(txData));
+    xcvr_spi_transfer(gXcvrSpiInstance_c, 0, byteArray, numOfBytes);
+
+    gXcvrDeassertCS_d();
+    UnprotectFromMCR20Interrupt();
+
+    return phyIRQSTS1;
+}
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_IndirectAccessSPIWrite
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+void MCR20Drv_IndirectAccessSPIWrite
+(
+uint8_t address,
+uint8_t value
+)
+{
+    uint32_t  txData;
+
+    ProtectFromMCR20Interrupt();
+
+    xcvr_spi_configure_speed(gXcvrSpiInstance_c, 16000000);
+
+    gXcvrAssertCS_d();
+
+    txData = TransceiverSPI_IARIndexReg;
+    txData |= (address) << 8;
+    txData |= (value)   << 16;
+
+    xcvr_spi_transfer(gXcvrSpiInstance_c, (uint8_t*)&txData, 0, 3);
+
+    gXcvrDeassertCS_d();
+    UnprotectFromMCR20Interrupt();
+}
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_IndirectAccessSPIMultiByteWrite
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+void MCR20Drv_IndirectAccessSPIMultiByteWrite
+(
+uint8_t startAddress,
+uint8_t * byteArray,
+uint8_t numOfBytes
+)
+{
+    uint16_t  txData;
+
+    if( (numOfBytes == 0) || (byteArray == 0) )
+    {
+        return;
+    }
+
+    ProtectFromMCR20Interrupt();
+
+    xcvr_spi_configure_speed(gXcvrSpiInstance_c, 16000000);
+
+    gXcvrAssertCS_d();
+
+    txData = TransceiverSPI_IARIndexReg;
+    txData |= (startAddress)  << 8;
+
+    xcvr_spi_transfer(gXcvrSpiInstance_c, (uint8_t*)&txData, 0, sizeof(txData));
+    xcvr_spi_transfer(gXcvrSpiInstance_c, (uint8_t*)byteArray, 0, numOfBytes);
+
+    gXcvrDeassertCS_d();
+    UnprotectFromMCR20Interrupt();
+}
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_IndirectAccessSPIRead
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+uint8_t MCR20Drv_IndirectAccessSPIRead
+(
+uint8_t address
+)
+{
+    uint16_t  txData;
+    uint8_t   rxData;
+
+    ProtectFromMCR20Interrupt();
+
+    xcvr_spi_configure_speed(gXcvrSpiInstance_c, 8000000);
+
+    gXcvrAssertCS_d();
+
+    txData = TransceiverSPI_IARIndexReg | TransceiverSPI_ReadSelect;
+    txData |= (address) << 8;
+
+    xcvr_spi_transfer(gXcvrSpiInstance_c, (uint8_t*)&txData, 0, sizeof(txData));
+    xcvr_spi_transfer(gXcvrSpiInstance_c, 0, &rxData, sizeof(rxData));
+
+    gXcvrDeassertCS_d();
+    UnprotectFromMCR20Interrupt();
+
+    return rxData;
+}
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_IndirectAccessSPIMultiByteRead
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+void MCR20Drv_IndirectAccessSPIMultiByteRead
+(
+uint8_t startAddress,
+uint8_t * byteArray,
+uint8_t numOfBytes
+)
+{
+    uint16_t  txData;
+
+    if( (numOfBytes == 0) || (byteArray == 0) )
+    {
+        return;
+    }
+
+    ProtectFromMCR20Interrupt();
+
+    xcvr_spi_configure_speed(gXcvrSpiInstance_c, 8000000);
+
+    gXcvrAssertCS_d();
+
+    txData = (TransceiverSPI_IARIndexReg | TransceiverSPI_ReadSelect);
+    txData |= (startAddress) << 8;
+
+    xcvr_spi_transfer(gXcvrSpiInstance_c, (uint8_t*)&txData, 0, sizeof(txData));
+    xcvr_spi_transfer(gXcvrSpiInstance_c, 0, byteArray, numOfBytes);
+
+    gXcvrDeassertCS_d();
+    UnprotectFromMCR20Interrupt();
+}
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_IsIrqPending
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+uint32_t  MCR20Drv_IsIrqPending
+(
+void
+)
+{
+    return RF_isIRQ_Pending();
+}
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_IRQ_Disable
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+void MCR20Drv_IRQ_Disable
+(
+void
+)
+{
+    core_util_critical_section_enter();
+
+    if( mPhyIrqDisableCnt == 0 )
+    {
+        RF_IRQ_Disable();
+    }
+
+    mPhyIrqDisableCnt++;
+
+    core_util_critical_section_exit();
+}
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_IRQ_Enable
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+void MCR20Drv_IRQ_Enable
+(
+void
+)
+{
+    core_util_critical_section_enter();
+
+    if( mPhyIrqDisableCnt )
+    {
+        mPhyIrqDisableCnt--;
+
+        if( mPhyIrqDisableCnt == 0 )
+        {
+            RF_IRQ_Enable();
+        }
+    }
+
+    core_util_critical_section_exit();
+}
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_RST_Assert
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+void MCR20Drv_RST_B_Assert
+(
+void
+)
+{
+    RF_RST_Set(0);
+}
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_RST_Deassert
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+void MCR20Drv_RST_B_Deassert
+(
+void
+)
+{
+    RF_RST_Set(1);
+}
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_SoftRST_Assert
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+void MCR20Drv_SoftRST_Assert
+(
+void
+)
+{
+    MCR20Drv_IndirectAccessSPIWrite(SOFT_RESET, (0x80));
+}
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_SoftRST_Deassert
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+void MCR20Drv_SoftRST_Deassert
+(
+void
+)
+{
+    MCR20Drv_IndirectAccessSPIWrite(SOFT_RESET, (0x00));
+}
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_Soft_RESET
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+void MCR20Drv_Soft_RESET
+(
+void
+)
+{
+    //assert SOG_RST
+    MCR20Drv_IndirectAccessSPIWrite(SOFT_RESET, (0x80));
+
+    //deassert SOG_RST
+    MCR20Drv_IndirectAccessSPIWrite(SOFT_RESET, (0x00));
+}
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_RESET
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+void MCR20Drv_RESET
+(
+void
+)
+{
+  #if !defined(TARGET_KW24D)
+    volatile uint32_t delay = 1000;
+    //assert RST_B
+    MCR20Drv_RST_B_Assert();
+
+    while(delay--);
+
+    //deassert RST_B
+    MCR20Drv_RST_B_Deassert();
+  #endif
+}
+
+/*---------------------------------------------------------------------------
+* Name: MCR20Drv_Set_CLK_OUT_Freq
+* Description: -
+* Parameters: -
+* Return: -
+*---------------------------------------------------------------------------*/
+void MCR20Drv_Set_CLK_OUT_Freq
+(
+uint8_t freqDiv
+)
+{
+    uint8_t clkOutCtrlReg = (freqDiv & cCLK_OUT_DIV_Mask) | cCLK_OUT_EN | cCLK_OUT_EXTEND;
+
+    if(freqDiv == gCLK_OUT_FREQ_DISABLE)
+    {
+        clkOutCtrlReg = (cCLK_OUT_EXTEND | gCLK_OUT_FREQ_4_MHz); //reset value with clock out disabled
+    }
+
+    MCR20Drv_DirectAccessSPIWrite((uint8_t) CLK_OUT_CTRL, clkOutCtrlReg);
+}
+
+#endif /* MBED_CONF_NANOSTACK_CONFIGURATION */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/mcr20a-rf-driver/source/MCR20Drv.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,373 @@
+/*!
+* Copyright (c) 2015, Freescale Semiconductor, Inc.
+* All rights reserved.
+*
+* \file MCR20Drv.h
+*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+*
+* o Redistributions of source code must retain the above copyright notice, this list
+*   of conditions and the following disclaimer.
+*
+* o Redistributions in binary form must reproduce the above copyright notice, this
+*   list of conditions and the following disclaimer in the documentation and/or
+*   other materials provided with the distribution.
+*
+* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
+*   contributors may be used to endorse or promote products derived from this
+*   software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __MCR20_DRV_H__
+#define __MCR20_DRV_H__
+
+#include <stdint.h>
+
+/*****************************************************************************
+ *                               INCLUDED HEADERS                            *
+ *---------------------------------------------------------------------------*
+ * Add to this section all the headers that this module needs to include.    *
+ * Note that it is not a good practice to include header files into header   *
+ * files, so use this section only if there is no other better solution.     *
+ *---------------------------------------------------------------------------*
+ *****************************************************************************/
+
+/*****************************************************************************
+ *                             PRIVATE MACROS                                *
+ *---------------------------------------------------------------------------*
+ * Add to this section all the access macros, registers mappings, bit access *
+ * macros, masks, flags etc ...
+ *---------------------------------------------------------------------------*
+ *****************************************************************************/
+
+/* Disable XCVR clock output by default, to reduce power consumption */
+#ifndef gMCR20_ClkOutFreq_d 
+#define gMCR20_ClkOutFreq_d gCLK_OUT_FREQ_DISABLE
+#endif
+
+/*****************************************************************************
+ *                            PUBLIC FUNCTIONS                               *
+ *---------------------------------------------------------------------------*
+ * Add to this section all the global functions prototype preceded (as a     *
+ * good practice) by the keyword 'extern'                                    *
+ *---------------------------------------------------------------------------*
+ *****************************************************************************/
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_Init
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+extern void MCR20Drv_Init
+(
+  void
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_SPI_DMA_Init
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+void MCR20Drv_SPI_DMA_Init
+(
+  void
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_Start_PB_DMA_SPI_Write
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+void MCR20Drv_Start_PB_DMA_SPI_Write
+(
+  uint8_t * srcAddress,
+  uint8_t numOfBytes
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_Start_PB_DMA_SPI_Read
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+void MCR20Drv_Start_PB_DMA_SPI_Read
+(
+  uint8_t * dstAddress,
+  uint8_t numOfBytes
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_DirectAccessSPIWrite
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+void MCR20Drv_DirectAccessSPIWrite
+(
+ uint8_t address,
+ uint8_t value
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_DirectAccessSPIMultiByteWrite
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+void MCR20Drv_DirectAccessSPIMultiByteWrite
+(
+ uint8_t startAddress,
+ uint8_t * byteArray,
+ uint8_t numOfBytes
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_PB_SPIBurstWrite
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+void MCR20Drv_PB_SPIBurstWrite
+(
+ uint8_t * byteArray,
+ uint8_t numOfBytes
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_DirectAccessSPIRead
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+uint8_t MCR20Drv_DirectAccessSPIRead
+(
+ uint8_t address
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_DirectAccessSPIMultyByteRead
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+
+uint8_t MCR20Drv_DirectAccessSPIMultiByteRead
+(
+ uint8_t startAddress,
+ uint8_t * byteArray,
+ uint8_t numOfBytes
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_PB_SPIByteWrite
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+void MCR20Drv_PB_SPIByteWrite
+(
+ uint8_t address,
+ uint8_t value
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_PB_SPIBurstRead
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+uint8_t MCR20Drv_PB_SPIBurstRead
+(
+ uint8_t * byteArray,
+ uint8_t numOfBytes
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_IndirectAccessSPIWrite
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+void MCR20Drv_IndirectAccessSPIWrite
+(
+ uint8_t address,
+ uint8_t value
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_IndirectAccessSPIMultiByteWrite
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+void MCR20Drv_IndirectAccessSPIMultiByteWrite
+(
+ uint8_t startAddress,
+ uint8_t * byteArray,
+ uint8_t numOfBytes
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_IndirectAccessSPIRead
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+uint8_t MCR20Drv_IndirectAccessSPIRead
+(
+ uint8_t address
+);
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_IndirectAccessSPIMultiByteRead
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+void MCR20Drv_IndirectAccessSPIMultiByteRead
+(
+ uint8_t startAddress,
+ uint8_t * byteArray,
+ uint8_t numOfBytes
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_IsIrqPending
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+uint32_t MCR20Drv_IsIrqPending
+(
+  void
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_IRQ_Disable
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+void MCR20Drv_IRQ_Disable
+(
+  void
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_IRQ_Enable
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+void MCR20Drv_IRQ_Enable
+(
+  void
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_RST_PortConfig
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+void MCR20Drv_RST_B_PortConfig
+(
+  void
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_RST_Assert
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+void MCR20Drv_RST_B_Assert
+(
+  void
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_RST_Deassert
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+void MCR20Drv_RST_B_Deassert
+(
+  void
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_SoftRST_Assert
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+void MCR20Drv_SoftRST_Assert
+(
+  void
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_SoftRST_Deassert
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+void MCR20Drv_SoftRST_Deassert
+(
+  void
+);
+
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_RESET
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+void MCR20Drv_RESET
+(
+  void
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_Soft_RESET
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+void MCR20Drv_Soft_RESET
+(
+  void
+);
+
+/*---------------------------------------------------------------------------
+ * Name: MCR20Drv_Set_CLK_OUT_Freq
+ * Description: -
+ * Parameters: -
+ * Return: -
+ *---------------------------------------------------------------------------*/
+void MCR20Drv_Set_CLK_OUT_Freq
+(
+  uint8_t freqDiv
+);
+
+#define ProtectFromMCR20Interrupt()   MCR20Drv_IRQ_Disable()
+#define UnprotectFromMCR20Interrupt() MCR20Drv_IRQ_Enable()
+
+#endif /* __MCR20_DRV_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/mcr20a-rf-driver/source/MCR20Overwrites.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,309 @@
+/*!
+* Copyright (c) 2015, Freescale Semiconductor, Inc.
+* All rights reserved.
+*
+* \file MCR20Overwrites.h
+* Description: Overwrites header file for MCR20 Register values
+*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+*
+* o Redistributions of source code must retain the above copyright notice, this list
+*   of conditions and the following disclaimer.
+*
+* o Redistributions in binary form must reproduce the above copyright notice, this
+*   list of conditions and the following disclaimer in the documentation and/or
+*   other materials provided with the distribution.
+*
+* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
+*   contributors may be used to endorse or promote products derived from this
+*   software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef OVERWRITES_H_
+#define OVERWRITES_H_
+
+typedef struct overwrites_tag {
+ char address;
+ char data;
+}overwrites_t;
+
+
+/*****************************************************************************************************************/
+//         This file is created exclusively for use with the transceiver 2.0 silicon
+//         and is provided for the world to use. It contains a list of all
+//         known overwrite values. Overwrite values are non-default register
+//         values that configure the transceiver device to a more optimally performing
+//         posture. It is expected that low level software (i.e. PHY) will
+//         consume this file as a #include, and transfer the contents to the
+//         the indicated addresses in the transceiver's memory space. This file has
+//         at least one required entry, that being its own version current version
+//         number, to be stored at transceiver's location 0x3B the
+//         OVERWRITES_VERSION_NUMBER register. The RAM register is provided in
+//         the transceiver address space to assist in future debug efforts. The
+//         analyst may read this location (once device has been booted with
+//         mysterious software) and have a good indication of what register
+//         overwrites were performed (with all versions of the overwrites.h file
+//         being archived forever at the Compass location shown above.
+//
+//     The transceiver has an indirect register (IAR) space. Write access to this space
+//         requires 3 or more writes:
+//         1st) the first write is an index value to the indirect (write Bit7=0, register access Bit 6=0) + 0x3E
+//         2nd) IAR Register #0x00 - 0xFF.
+//     3rd) The data to write
+//         nth) Burst mode additional data if required.
+//
+//     Write access to direct space requires only a single address, data pair.
+
+overwrites_t const overwrites_direct[] ={
+{0x3B, 0x0C}, //version 0C: new value for ACKDELAY targeting 198us (23 May, 2013, Larry Roshak)
+{0x23, 0x17}  //PA_PWR new default Power Step is "23"  
+};
+
+overwrites_t const overwrites_indirect[] ={
+{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) 
+{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3                         
+{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 
+{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid)
+{0x79, 0x2F}, //CHF_IBUF  Adjust the gm-C filter gain (+/- 6dB)         (21 Dec, 2012, on behalf of S. Soca)
+{0x7A, 0x2F}, //CHF_QBUF  Adjust the gm-C filter gain (+/- 6dB)         (21 Dec, 2012, on behalf of S. Soca)
+{0x7B, 0x24}, //CHF_IRIN  Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7C, 0x24}, //CHF_QRIN  Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7D, 0x24}, //CHF_IL    Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7E, 0x24}, //CHF_QL    Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7F, 0x32}, //CHF_CC1   Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
+{0x80, 0x1D}, //CHF_CCL   Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
+{0x81, 0x2D}, //CHF_CC2   Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
+{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x64, 0x28}, //PA_CAL_DIS=1  Disabled PA calibration 
+{0x52, 0x55}, //AGC_THR1 RSSI tune up 
+{0x53, 0x2D}, //AGC_THR2 RSSI tune up 
+{0x66, 0x5F}, //ATT_RSSI1 tune up     
+{0x67, 0x8F}, //ATT_RSSI2 tune up     
+{0x68, 0x61}, //RSSI_OFFSET 
+{0x78, 0x03}, //CHF_PMAGAIN 
+{0x22, 0x50}, //CCA1_THRESH 
+{0x4D, 0x13}, //CORR_NVAL moved from 0x14 to 0x13 for 0.5 dB improved Rx Sensitivity 
+{0x39, 0x3D}  //ACKDELAY new value targeting a delay of 198us (23 May, 2013, Larry Roshak)
+};
+
+
+/* begin of deprecated versions
+
+==VERSION 1==
+(version 1 is empty)
+
+==VERSION 2==
+overwrites_t const overwrites_indirect[] ={
+{0x31, 0x02}  //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) 
+};
+
+==VERSION 3==
+overwrites_t const overwrites_indirect[] ={
+{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) 
+{0x91, 0xB3}, //VCO_CTRL1: override VCOALC_REF_TX to 3 
+{0x92, 0x07}  //VCO_CTRL2: override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 
+};
+
+==VERSION 4==
+overwrites_t const overwrites_direct[] ={
+{0x3B, 0x04}  //version 04 is the current version: update PA_COILTUNING default 
+};
+
+overwrites_t const overwrites_indirect[] ={
+{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) 
+{0x91, 0xB3}, //VCO_CTRL1: override VCOALC_REF_TX to 3 
+{0x92, 0x07}  //VCO_CTRL2: override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 
+{0x8A, 0x71}  //PA_TUNING: override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid)
+};
+
+==VERSION 5==
+overwrites_t const overwrites_direct[] ={
+{0x3B, 0x05}  //version 05: updates Channel Filter Register set (21 Dec 2012, on behalf of S. Soca)
+};
+
+overwrites_t const overwrites_indirect[] ={
+{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) 
+{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3                         
+{0x92, 0x07}  //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 
+{0x8A, 0x71}  //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid)
+{0x79, 0x2F}  //CHF_IBUF  Adjust the gm-C filter gain (+/- 6dB)         (21 Dec, 2012, on behalf of S. Soca)
+{0x7A, 0x2F}  //CHF_QBUF  Adjust the gm-C filter gain (+/- 6dB)         (21 Dec, 2012, on behalf of S. Soca)
+{0x7B, 0x24}  //CHF_IRIN  Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7C, 0x24}  //CHF_QRIN  Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7D, 0x24}  //CHF_IL    Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7E, 0x24}  //CHF_QL    Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x82, 0x24}  //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x83, 0x24}  //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7F, 0x32}  //CHF_CC1   Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
+{0x80, 0x1D}  //CHF_CCL   Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
+{0x81, 0x2D}  //CHF_CC2   Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
+};
+
+==VERSION 6==
+overwrites_t const overwrites_direct[] ={
+{0x3B, 0x06}  //version 06: disable PA calibration 
+};
+
+overwrites_t const overwrites_indirect[] ={
+{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) 
+{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3                         
+{0x92, 0x07}  //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 
+{0x8A, 0x71}  //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid)
+{0x79, 0x2F}  //CHF_IBUF  Adjust the gm-C filter gain (+/- 6dB)         (21 Dec, 2012, on behalf of S. Soca)
+{0x7A, 0x2F}  //CHF_QBUF  Adjust the gm-C filter gain (+/- 6dB)         (21 Dec, 2012, on behalf of S. Soca)
+{0x7B, 0x24}  //CHF_IRIN  Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7C, 0x24}  //CHF_QRIN  Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7D, 0x24}  //CHF_IL    Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7E, 0x24}  //CHF_QL    Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x82, 0x24}  //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x83, 0x24}  //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7F, 0x32}  //CHF_CC1   Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
+{0x80, 0x1D}  //CHF_CCL   Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
+{0x81, 0x2D}  //CHF_CC2   Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
+{0x64, 0x28}  //PA_CAL_DIS=1  Disabled PA calibration 
+};
+
+==VERSION 7==
+overwrites_t const overwrites_direct[] ={
+{0x3B, 0x07}  //version 07: updated registers for ED/RSSI 
+};
+
+overwrites_t const overwrites_indirect[] ={
+{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) 
+{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3                         
+{0x92, 0x07},  //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 
+{0x8A, 0x71},  //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid)
+{0x79, 0x2F},  //CHF_IBUF  Adjust the gm-C filter gain (+/- 6dB)         (21 Dec, 2012, on behalf of S. Soca)
+{0x7A, 0x2F},  //CHF_QBUF  Adjust the gm-C filter gain (+/- 6dB)         (21 Dec, 2012, on behalf of S. Soca)
+{0x7B, 0x24},  //CHF_IRIN  Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7C, 0x24},  //CHF_QRIN  Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7D, 0x24},  //CHF_IL    Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7E, 0x24},  //CHF_QL    Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x82, 0x24},  //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x83, 0x24},  //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7F, 0x32}, //CHF_CC1   Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
+{0x80, 0x1D},  //CHF_CCL   Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
+{0x81, 0x2D},  //CHF_CC2   Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
+{0x64, 0x28},  //PA_CAL_DIS=1  Disabled PA calibration 
+{0x52, 0x73},  //AGC_THR1 RSSI tune up 
+{0x53, 0x2D}, //AGC_THR2 RSSI tune up 
+{0x66, 0x5F}, //ATT_RSSI1 tune up 
+{0x67, 0x8F}, //ATT_RSSI2 tune up 
+{0x68, 0x60}, //RSSI_OFFSET 
+{0x69, 0x65}  //RSSI_SLOPE 
+};
+
+
+==VERSION 8==
+overwrites_t const overwrites_direct[] ={
+{0x3B, 0x08}  //version 08: updated registers for ED/RSSI 
+};
+
+overwrites_t const overwrites_indirect[] ={
+{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) 
+{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3                         
+{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 
+{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid)
+{0x79, 0x2F}, //CHF_IBUF  Adjust the gm-C filter gain (+/- 6dB)         (21 Dec, 2012, on behalf of S. Soca)
+{0x7A, 0x2F}, //CHF_QBUF  Adjust the gm-C filter gain (+/- 6dB)         (21 Dec, 2012, on behalf of S. Soca)
+{0x7B, 0x24}, //CHF_IRIN  Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7C, 0x24}, //CHF_QRIN  Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7D, 0x24}, //CHF_IL    Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7E, 0x24}, //CHF_QL    Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7F, 0x32}, //CHF_CC1   Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
+{0x80, 0x1D}, //CHF_CCL   Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
+{0x81, 0x2D}, //CHF_CC2   Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
+{0x64, 0x28}, //PA_CAL_DIS=1  Disabled PA calibration 
+{0x52, 0x73}, //AGC_THR1 RSSI tune up 
+{0x53, 0x2D}, //AGC_THR2 RSSI tune up 
+{0x66, 0x5F}, //ATT_RSSI1 tune up     
+{0x67, 0x8F}, //ATT_RSSI2 tune up     
+{0x69, 0x65}  //RSSI_SLOPE            
+{0x68, 0x61}, //RSSI_OFFSET 
+{0x78, 0x03}  //CHF_PMAGAIN 
+};
+
+
+==VERSION 9==
+overwrites_t const overwrites_direct[] ={
+{0x3B, 0x09}  //version 09: updated registers for ED/RSSI and PowerStep 
+{0x23, 0x17}  //PA_PWR new default value                                
+};
+
+overwrites_t const overwrites_indirect[] ={
+{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) 
+{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3                         
+{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 
+{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid)
+{0x79, 0x2F}, //CHF_IBUF  Adjust the gm-C filter gain (+/- 6dB)         (21 Dec, 2012, on behalf of S. Soca)
+{0x7A, 0x2F}, //CHF_QBUF  Adjust the gm-C filter gain (+/- 6dB)         (21 Dec, 2012, on behalf of S. Soca)
+{0x7B, 0x24}, //CHF_IRIN  Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7C, 0x24}, //CHF_QRIN  Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7D, 0x24}, //CHF_IL    Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7E, 0x24}, //CHF_QL    Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7F, 0x32}, //CHF_CC1   Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
+{0x80, 0x1D}, //CHF_CCL   Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
+{0x81, 0x2D}, //CHF_CC2   Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
+{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x64, 0x28}, //PA_CAL_DIS=1  Disabled PA calibration 
+{0x52, 0x55}, //AGC_THR1 RSSI tune up 
+{0x53, 0x2D}, //AGC_THR2 RSSI tune up 
+{0x66, 0x5F}, //ATT_RSSI1 tune up     
+{0x67, 0x8F}, //ATT_RSSI2 tune up     
+{0x68, 0x61}, //RSSI_OFFSET 
+{0x78, 0x03}  //CHF_PMAGAIN 
+};
+
+==VERSION A==
+overwrites_t const overwrites_direct[] ={
+{0x3B, 0x0A}  //version 0A: updated registers for CCA 
+{0x23, 0x17}  //PA_PWR new default Power Step is "23"  
+};
+
+overwrites_t const overwrites_indirect[] ={
+{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) 
+{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3                         
+{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 
+{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid)
+{0x79, 0x2F}, //CHF_IBUF  Adjust the gm-C filter gain (+/- 6dB)         (21 Dec, 2012, on behalf of S. Soca)
+{0x7A, 0x2F}, //CHF_QBUF  Adjust the gm-C filter gain (+/- 6dB)         (21 Dec, 2012, on behalf of S. Soca)
+{0x7B, 0x24}, //CHF_IRIN  Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7C, 0x24}, //CHF_QRIN  Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7D, 0x24}, //CHF_IL    Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7E, 0x24}, //CHF_QL    Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x7F, 0x32}, //CHF_CC1   Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
+{0x80, 0x1D}, //CHF_CCL   Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
+{0x81, 0x2D}, //CHF_CC2   Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
+{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz)      (21 Dec, 2012, on behalf of S. Soca)
+{0x64, 0x28}, //PA_CAL_DIS=1  Disabled PA calibration 
+{0x52, 0x55}, //AGC_THR1 RSSI tune up 
+{0x53, 0x2D}, //AGC_THR2 RSSI tune up 
+{0x66, 0x5F}, //ATT_RSSI1 tune up     
+{0x67, 0x8F}, //ATT_RSSI2 tune up     
+{0x68, 0x61}, //RSSI_OFFSET 
+{0x78, 0x03}  //CHF_PMAGAIN 
+{0x22, 0x50}  //CCA1_THRESH 
+};
+
+end of deprecated versions */
+
+
+#endif  //OVERWRITES_H_
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/mcr20a-rf-driver/source/MCR20Reg.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,730 @@
+/*!
+* Copyright (c) 2015, Freescale Semiconductor, Inc.
+* All rights reserved.
+*
+* \file MCR20reg.h
+* MCR20 Registers
+*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+*
+* o Redistributions of source code must retain the above copyright notice, this list
+*   of conditions and the following disclaimer.
+*
+* o Redistributions in binary form must reproduce the above copyright notice, this
+*   list of conditions and the following disclaimer in the documentation and/or
+*   other materials provided with the distribution.
+*
+* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
+*   contributors may be used to endorse or promote products derived from this
+*   software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __MCR20_REG_H__
+#define __MCR20_REG_H__
+/*****************************************************************************
+ *                               INCLUDED HEADERS                            *
+ *---------------------------------------------------------------------------*
+ * Add to this section all the headers that this module needs to include.    *
+ * Note that it is not a good practice to include header files into header   *
+ * files, so use this section only if there is no other better solution.     *
+ *---------------------------------------------------------------------------*
+ *****************************************************************************/
+
+/****************************************************************************/
+/* Transceiver SPI Registers */
+/****************************************************************************/
+
+#define TransceiverSPI_IARIndexReg                  (0x3E)
+
+#define TransceiverSPI_ReadSelect                   (1<<7)
+#define TransceiverSPI_WriteSelect                  (0<<7)
+#define TransceiverSPI_RegisterAccessSelect         (0<<6)
+#define TransceiverSPI_PacketBuffAccessSelect       (1<<6)
+#define TransceiverSPI_PacketBuffBurstModeSelect    (0<<5)
+#define TransceiverSPI_PacketBuffByteModeSelect     (1<<5)
+
+#define TransceiverSPI_DirectRegisterAddressMask    (0x3F)
+
+#define IRQSTS1             0x00
+#define IRQSTS2             0x01
+#define IRQSTS3             0x02
+#define PHY_CTRL1           0x03
+#define PHY_CTRL2           0x04
+#define PHY_CTRL3           0x05
+#define RX_FRM_LEN          0x06
+#define PHY_CTRL4           0x07
+#define SRC_CTRL            0x08
+#define SRC_ADDRS_SUM_LSB   0x09
+#define SRC_ADDRS_SUM_MSB   0x0A
+#define CCA1_ED_FNL         0x0B
+#define EVENT_TMR_LSB       0x0C
+#define EVENT_TMR_MSB       0x0D
+#define EVENT_TMR_USB       0x0E
+#define TIMESTAMP_LSB       0x0F
+#define TIMESTAMP_MSB       0x10
+#define TIMESTAMP_USB       0x11
+#define T3CMP_LSB           0x12
+#define T3CMP_MSB           0x13
+#define T3CMP_USB           0x14
+#define T2PRIMECMP_LSB      0x15
+#define T2PRIMECMP_MSB      0x16
+#define T1CMP_LSB           0x17
+#define T1CMP_MSB           0x18
+#define T1CMP_USB           0x19
+#define T2CMP_LSB           0x1A
+#define T2CMP_MSB           0x1B
+#define T2CMP_USB           0x1C
+#define T4CMP_LSB           0x1D
+#define T4CMP_MSB           0x1E
+#define T4CMP_USB           0x1F
+#define PLL_INT0            0x20
+#define PLL_FRAC0_LSB       0x21
+#define PLL_FRAC0_MSB       0x22
+#define PA_PWR              0x23
+#define SEQ_STATE           0x24
+#define LQI_VALUE           0x25
+#define RSSI_CCA_CONT       0x26
+//--------------            0x27
+#define ASM_CTRL1           0x28
+#define ASM_CTRL2           0x29
+#define ASM_DATA_0          0x2A
+#define ASM_DATA_1          0x2B
+#define ASM_DATA_2          0x2C
+#define ASM_DATA_3          0x2D
+#define ASM_DATA_4          0x2E
+#define ASM_DATA_5          0x2F
+#define ASM_DATA_6          0x30
+#define ASM_DATA_7          0x31
+#define ASM_DATA_8          0x32
+#define ASM_DATA_9          0x33
+#define ASM_DATA_A          0x34
+#define ASM_DATA_B          0x35
+#define ASM_DATA_C          0x36
+#define ASM_DATA_D          0x37
+#define ASM_DATA_E          0x38
+#define ASM_DATA_F          0x39
+//-------------------       0x3A
+#define OVERWRITE_VER       0x3B
+#define CLK_OUT_CTRL        0x3C
+#define PWR_MODES           0x3D
+#define IAR_INDEX           0x3E
+#define IAR_DATA            0x3F
+
+
+#define PART_ID             0x00
+#define XTAL_TRIM           0x01
+#define PMC_LP_TRIM         0x02
+#define MACPANID0_LSB       0x03
+#define MACPANID0_MSB       0x04
+#define MACSHORTADDRS0_LSB  0x05
+#define MACSHORTADDRS0_MSB  0x06
+#define MACLONGADDRS0_0     0x07
+#define MACLONGADDRS0_8     0x08
+#define MACLONGADDRS0_16    0x09
+#define MACLONGADDRS0_24    0x0A
+#define MACLONGADDRS0_32    0x0B
+#define MACLONGADDRS0_40    0x0C
+#define MACLONGADDRS0_48    0x0D
+#define MACLONGADDRS0_56    0x0E
+#define RX_FRAME_FILTER     0x0F
+#define PLL_INT1            0x10
+#define PLL_FRAC1_LSB       0x11
+#define PLL_FRAC1_MSB       0x12
+#define MACPANID1_LSB       0x13
+#define MACPANID1_MSB       0x14
+#define MACSHORTADDRS1_LSB  0x15
+#define MACSHORTADDRS1_MSB  0x16
+#define MACLONGADDRS1_0     0x17
+#define MACLONGADDRS1_8     0x18
+#define MACLONGADDRS1_16    0x19
+#define MACLONGADDRS1_24    0x1A
+#define MACLONGADDRS1_32    0x1B
+#define MACLONGADDRS1_40    0x1C
+#define MACLONGADDRS1_48    0x1D
+#define MACLONGADDRS1_56    0x1E
+#define DUAL_PAN_CTRL       0x1F
+#define DUAL_PAN_DWELL      0x20
+#define DUAL_PAN_STS        0x21
+#define CCA1_THRESH         0x22
+#define CCA1_ED_OFFSET_COMP 0x23
+#define LQI_OFFSET_COMP     0x24
+#define CCA_CTRL            0x25
+#define CCA2_CORR_PEAKS     0x26
+#define CCA2_CORR_THRESH    0x27
+#define TMR_PRESCALE        0x28
+//----------------          0x29
+#define GPIO_DATA           0x2A
+#define GPIO_DIR            0x2B
+#define GPIO_PUL_EN         0x2C
+#define GPIO_PUL_SEL        0x2D
+#define GPIO_DS             0x2E
+//--------------            0x2F
+#define ANT_PAD_CTRL        0x30
+#define MISC_PAD_CTRL       0x31
+#define BSM_CTRL            0x32
+//---------------           0x33
+#define _RNG                0x34
+#define RX_BYTE_COUNT       0x35
+#define RX_WTR_MARK         0x36
+#define SOFT_RESET          0x37
+#define TXDELAY             0x38
+#define ACKDELAY            0x39
+#define SEQ_MGR_CTRL        0x3A
+#define SEQ_MGR_STS         0x3B
+#define SEQ_T_STS           0x3C
+#define ABORT_STS           0x3D
+#define CCCA_BUSY_CNT       0x3E
+#define SRC_ADDR_CHECKSUM1  0x3F
+#define SRC_ADDR_CHECKSUM2  0x40
+#define SRC_TBL_VALID1      0x41
+#define SRC_TBL_VALID2      0x42
+#define FILTERFAIL_CODE1    0x43
+#define FILTERFAIL_CODE2    0x44
+#define SLOT_PRELOAD        0x45
+//----------------          0x46
+#define CORR_VT             0x47
+#define SYNC_CTRL           0x48
+#define PN_LSB_0            0x49
+#define PN_LSB_1            0x4A
+#define PN_MSB_0            0x4B
+#define PN_MSB_1            0x4C
+#define CORR_NVAL           0x4D
+#define TX_MODE_CTRL        0x4E
+#define SNF_THR             0x4F
+#define FAD_THR             0x50
+#define ANT_AGC_CTRL        0x51
+#define AGC_THR1            0x52
+#define AGC_THR2            0x53
+#define AGC_HYS             0x54
+#define AFC                 0x55
+//---------------           0x56
+//---------------           0x57
+#define PHY_STS             0x58
+#define RX_MAX_CORR         0x59
+#define RX_MAX_PREAMBLE     0x5A
+#define RSSI                0x5B
+//---------------           0x5C
+//---------------           0x5D
+#define PLL_DIG_CTRL        0x5E
+#define VCO_CAL             0x5F
+#define VCO_BEST_DIFF       0x60
+#define VCO_BIAS            0x61
+#define KMOD_CTRL           0x62
+#define KMOD_CAL            0x63
+#define PA_CAL              0x64
+#define PA_PWRCAL           0x65
+#define ATT_RSSI1           0x66
+#define ATT_RSSI2           0x67
+#define RSSI_OFFSET         0x68
+#define RSSI_SLOPE          0x69
+#define RSSI_CAL1           0x6A
+#define RSSI_CAL2           0x6B
+//---------------           0x6C
+//---------------           0x6D
+#define XTAL_CTRL           0x6E
+#define XTAL_COMP_MIN       0x6F
+#define XTAL_COMP_MAX       0x70
+#define XTAL_GM             0x71
+//---------------           0x72
+//---------------           0x73
+#define LNA_TUNE            0x74
+#define LNA_AGCGAIN         0x75
+//---------------           0x76
+//---------------           0x77
+#define CHF_PMA_GAIN        0x78
+#define CHF_IBUF            0x79
+#define CHF_QBUF            0x7A
+#define CHF_IRIN            0x7B
+#define CHF_QRIN            0x7C
+#define CHF_IL              0x7D
+#define CHF_QL              0x7E
+#define CHF_CC1             0x7F
+#define CHF_CCL             0x80
+#define CHF_CC2             0x81
+#define CHF_IROUT           0x82
+#define CHF_QROUT           0x83
+//---------------           0x84
+//---------------           0x85
+#define RSSI_CTRL           0x86
+//---------------           0x87
+//---------------           0x88
+#define PA_BIAS             0x89
+#define PA_TUNING           0x8A
+//---------------           0x8B
+//---------------           0x8C
+#define PMC_HP_TRIM         0x8D
+#define VREGA_TRIM          0x8E
+//---------------           0x8F
+//---------------           0x90
+#define VCO_CTRL1           0x91
+#define VCO_CTRL2           0x92
+//---------------           0x93
+//---------------           0x94
+#define ANA_SPARE_OUT1      0x95
+#define ANA_SPARE_OUT2      0x96
+#define ANA_SPARE_IN        0x97
+#define MISCELLANEOUS       0x98
+//---------------           0x99
+#define SEQ_MGR_OVRD0       0x9A
+#define SEQ_MGR_OVRD1       0x9B
+#define SEQ_MGR_OVRD2       0x9C
+#define SEQ_MGR_OVRD3       0x9D
+#define SEQ_MGR_OVRD4       0x9E
+#define SEQ_MGR_OVRD5       0x9F
+#define SEQ_MGR_OVRD6       0xA0
+#define SEQ_MGR_OVRD7       0xA1
+//---------------           0xA2
+#define TESTMODE_CTRL       0xA3
+#define DTM_CTRL1           0xA4
+#define DTM_CTRL2           0xA5
+#define ATM_CTRL1           0xA6
+#define ATM_CTRL2           0xA7
+#define ATM_CTRL3           0xA8
+//---------------           0xA9
+#define LIM_FE_TEST_CTRL    0xAA
+#define CHF_TEST_CTRL       0xAB
+#define VCO_TEST_CTRL       0xAC
+#define PLL_TEST_CTRL       0xAD
+#define PA_TEST_CTRL        0xAE
+#define PMC_TEST_CTRL       0xAF
+#define SCAN_DTM_PROTECT_1  0xFE
+#define SCAN_DTM_PROTECT_0  0xFF
+
+// IRQSTS1 bits
+#define cIRQSTS1_RX_FRM_PEND         (1<<7)
+#define cIRQSTS1_PLL_UNLOCK_IRQ      (1<<6)
+#define cIRQSTS1_FILTERFAIL_IRQ      (1<<5)
+#define cIRQSTS1_RXWTRMRKIRQ         (1<<4)
+#define cIRQSTS1_CCAIRQ              (1<<3)
+#define cIRQSTS1_RXIRQ               (1<<2)
+#define cIRQSTS1_TXIRQ               (1<<1)
+#define cIRQSTS1_SEQIRQ              (1<<0)
+
+typedef union regIRQSTS1_tag{
+  uint8_t byte;
+  struct{
+    uint8_t SEQIRQ:1;
+    uint8_t TXIRQ:1;
+    uint8_t RXIRQ:1;
+    uint8_t CCAIRQ:1;
+    uint8_t RXWTRMRKIRQ:1;
+    uint8_t FILTERFAIL_IRQ:1;
+    uint8_t PLL_UNLOCK_IRQ:1;
+    uint8_t RX_FRM_PEND:1;
+  }bit;
+} regIRQSTS1_t;
+
+// IRQSTS2 bits
+#define cIRQSTS2_CRCVALID            (1<<7)
+#define cIRQSTS2_CCA                 (1<<6)
+#define cIRQSTS2_SRCADDR             (1<<5)
+#define cIRQSTS2_PI                  (1<<4)
+#define cIRQSTS2_TMRSTATUS           (1<<3)
+#define cIRQSTS2_ASM_IRQ             (1<<2)
+#define cIRQSTS2_PB_ERR_IRQ          (1<<1)
+#define cIRQSTS2_WAKE_IRQ            (1<<0)
+
+typedef union regIRQSTS2_tag{
+  uint8_t byte;
+  struct{
+    uint8_t WAKE_IRQ:1;
+    uint8_t PB_ERR_IRQ:1;
+    uint8_t ASM_IRQ:1;
+    uint8_t TMRSTATUS:1;
+    uint8_t PI_:1;
+    uint8_t SRCADDR:1;
+    uint8_t CCA:1;
+    uint8_t CRCVALID:1;
+  }bit;
+} regIRQSTS2_t;
+
+// IRQSTS3 bits
+#define cIRQSTS3_TMR4MSK             (1<<7)
+#define cIRQSTS3_TMR3MSK             (1<<6)
+#define cIRQSTS3_TMR2MSK             (1<<5)
+#define cIRQSTS3_TMR1MSK             (1<<4)
+#define cIRQSTS3_TMR4IRQ             (1<<3)
+#define cIRQSTS3_TMR3IRQ             (1<<2)
+#define cIRQSTS3_TMR2IRQ             (1<<1)
+#define cIRQSTS3_TMR1IRQ             (1<<0)
+
+typedef union regIRQSTS3_tag{
+  uint8_t byte;
+  struct{
+    uint8_t TMR1IRQ:1;
+    uint8_t TMR2IRQ:1;
+    uint8_t TMR3IRQ:1;
+    uint8_t TMR4IRQ:1;
+    uint8_t TMR1MSK:1;
+    uint8_t TMR2MSK:1;
+    uint8_t TMR3MSK:1;
+    uint8_t TMR4MSK:1;
+  }bit;
+} regIRQSTS3_t;
+
+// PHY_CTRL1 bits
+#define cPHY_CTRL1_TMRTRIGEN           (1<<7)
+#define cPHY_CTRL1_SLOTTED             (1<<6)
+#define cPHY_CTRL1_CCABFRTX            (1<<5)
+#define cPHY_CTRL1_RXACKRQD            (1<<4)
+#define cPHY_CTRL1_AUTOACK             (1<<3)
+#define cPHY_CTRL1_XCVSEQ              (7<<0)
+
+typedef union regPHY_CTRL1_tag{
+  uint8_t byte;
+  struct{
+    uint8_t XCVSEQ:3;
+    uint8_t AUTOACK:1;
+    uint8_t RXACKRQD:1;
+    uint8_t CCABFRTX:1;
+    uint8_t SLOTTED:1;
+    uint8_t TMRTRIGEN:1;
+  }bit;
+} regPHY_CTRL1_t; 
+
+// PHY_CTRL2 bits
+#define cPHY_CTRL2_CRC_MSK             (1<<7)
+#define cPHY_CTRL2_PLL_UNLOCK_MSK      (1<<6)
+#define cPHY_CTRL2_FILTERFAIL_MSK      (1<<5)
+#define cPHY_CTRL2_RX_WMRK_MSK         (1<<4)
+#define cPHY_CTRL2_CCAMSK              (1<<3)
+#define cPHY_CTRL2_RXMSK               (1<<2)
+#define cPHY_CTRL2_TXMSK               (1<<1)
+#define cPHY_CTRL2_SEQMSK              (1<<0)
+
+typedef union regPHY_CTRL2_tag{
+  uint8_t byte;
+  struct{
+    uint8_t SEQMSK:1;
+    uint8_t TXMSK:1;
+    uint8_t RXMSK:1;
+    uint8_t CCAMSK:1;
+    uint8_t RX_WMRK_MSK:1;
+    uint8_t FILTERFAIL_MSK:1;
+    uint8_t PLL_UNLOCK_MSK:1;
+    uint8_t CRC_MSK:1;
+  }bit;
+} regPHY_CTRL2_t; 
+
+// PHY_CTRL3 bits
+#define cPHY_CTRL3_TMR4CMP_EN          (1<<7)
+#define cPHY_CTRL3_TMR3CMP_EN          (1<<6)
+#define cPHY_CTRL3_TMR2CMP_EN          (1<<5)
+#define cPHY_CTRL3_TMR1CMP_EN          (1<<4)
+#define cPHY_CTRL3_ASM_MSK             (1<<2)
+#define cPHY_CTRL3_PB_ERR_MSK          (1<<1)
+#define cPHY_CTRL3_WAKE_MSK            (1<<0)
+
+typedef union regPHY_CTRL3_tag{
+  uint8_t byte;
+  struct{
+    uint8_t WAKE_MSK:1;
+    uint8_t PB_ERR_MSK:1;
+    uint8_t ASM_MSK:1;
+    uint8_t RESERVED:1;
+    uint8_t TMR1CMP_EN:1;
+    uint8_t TMR2CMP_EN:1;
+    uint8_t TMR3CMP_EN:1;
+    uint8_t TMR4CMP_EN:1;
+  }bit;
+} regPHY_CTRL3_t;
+
+// RX_FRM_LEN bits
+#define cRX_FRAME_LENGTH               (0x7F)
+
+// PHY_CTRL4 bits
+#define cPHY_CTRL4_TRCV_MSK            (1<<7)
+#define cPHY_CTRL4_TC3TMOUT            (1<<6)
+#define cPHY_CTRL4_PANCORDNTR0         (1<<5)
+#define cPHY_CTRL4_CCATYPE             (3<<0)
+#define cPHY_CTRL4_CCATYPE_Shift_c     (3)
+#define cPHY_CTRL4_TMRLOAD             (1<<2)
+#define cPHY_CTRL4_PROMISCUOUS         (1<<1)
+#define cPHY_CTRL4_TC2PRIME_EN         (1<<0)
+
+typedef union regPHY_CTRL4_tag{
+  uint8_t byte;
+  struct{
+    uint8_t TC2PRIME_EN:1;
+    uint8_t PROMISCUOUS:1;
+    uint8_t TMRLOAD:1;
+    uint8_t CCATYPE:2;
+    uint8_t PANCORDNTR0:1;
+    uint8_t TC3TMOUT:1;
+    uint8_t TRCV_MSK:1;
+  }bit;
+} regPHY_CTRL4_t;
+
+// SRC_CTRL bits
+#define cSRC_CTRL_INDEX               (0x0F)
+#define cSRC_CTRL_INDEX_Shift_c       (4)
+#define cSRC_CTRL_ACK_FRM_PND         (1<<3)
+#define cSRC_CTRL_SRCADDR_EN          (1<<2)
+#define cSRC_CTRL_INDEX_EN            (1<<1)
+#define cSRC_CTRL_INDEX_DISABLE       (1<<0)
+
+typedef union regSRC_CTRL_tag{
+  uint8_t byte;
+  struct{
+    uint8_t INDEX_DISABLE:1;
+    uint8_t INDEX_EN:1;
+    uint8_t SRCADDR_EN:1;
+    uint8_t ACK_FRM_PND:1;
+    uint8_t INDEX:4;
+  }bit;
+} regSRC_CTRL_t;
+
+// ASM_CTRL1 bits
+#define cASM_CTRL1_CLEAR               (1<<7)
+#define cASM_CTRL1_START               (1<<6)
+#define cASM_CTRL1_SELFTST             (1<<5)
+#define cASM_CTRL1_CTR                 (1<<4)
+#define cASM_CTRL1_CBC                 (1<<3)
+#define cASM_CTRL1_AES                 (1<<2)
+#define cASM_CTRL1_LOAD_MAC            (1<<1)
+
+// ASM_CTRL2 bits
+#define cASM_CTRL2_DATA_REG_TYPE_SEL          (7)
+#define cASM_CTRL2_DATA_REG_TYPE_SEL_Shift_c  (5)
+#define cASM_CTRL2_TSTPAS                     (1<<1)
+
+// CLK_OUT_CTRL bits
+#define cCLK_OUT_CTRL_EXTEND           (1<<7)
+#define cCLK_OUT_CTRL_HIZ              (1<<6)
+#define cCLK_OUT_CTRL_SR               (1<<5)
+#define cCLK_OUT_CTRL_DS               (1<<4)
+#define cCLK_OUT_CTRL_EN               (1<<3)
+#define cCLK_OUT_CTRL_DIV              (7)
+
+// PWR_MODES bits
+#define cPWR_MODES_XTAL_READY          (1<<5)
+#define cPWR_MODES_XTALEN              (1<<4)
+#define cPWR_MODES_ASM_CLK_EN          (1<<3)
+#define cPWR_MODES_AUTODOZE            (1<<1)
+#define cPWR_MODES_PMC_MODE            (1<<0)
+
+// RX_FRAME_FILTER bits
+#define cRX_FRAME_FLT_FRM_VER             (0xC0)
+#define cRX_FRAME_FLT_FRM_VER_Shift_c     (6)
+#define cRX_FRAME_FLT_ACTIVE_PROMISCUOUS  (1<<5)
+#define cRX_FRAME_FLT_NS_FT               (1<<4)
+#define cRX_FRAME_FLT_CMD_FT              (1<<3)
+#define cRX_FRAME_FLT_ACK_FT              (1<<2)
+#define cRX_FRAME_FLT_DATA_FT             (1<<1)
+#define cRX_FRAME_FLT_BEACON_FT           (1<<0)
+
+typedef union regRX_FRAME_FILTER_tag{
+  uint8_t byte;
+  struct{
+    uint8_t FRAME_FLT_BEACON_FT:1;
+    uint8_t FRAME_FLT_DATA_FT:1;
+    uint8_t FRAME_FLT_ACK_FT:1;
+    uint8_t FRAME_FLT_CMD_FT:1;
+    uint8_t FRAME_FLT_NS_FT:1;
+    uint8_t FRAME_FLT_ACTIVE_PROMISCUOUS:1;
+    uint8_t FRAME_FLT_FRM_VER:2;
+  }bit;
+} regRX_FRAME_FILTER_t; 
+
+// DUAL_PAN_CTRL bits
+#define cDUAL_PAN_CTRL_DUAL_PAN_SAM_LVL_MSK       (0xF0)
+#define cDUAL_PAN_CTRL_DUAL_PAN_SAM_LVL_Shift_c   (4)
+#define cDUAL_PAN_CTRL_CURRENT_NETWORK            (1<<3)
+#define cDUAL_PAN_CTRL_PANCORDNTR1                (1<<2)
+#define cDUAL_PAN_CTRL_DUAL_PAN_AUTO              (1<<1)
+#define cDUAL_PAN_CTRL_ACTIVE_NETWORK             (1<<0)
+
+// DUAL_PAN_STS bits
+#define cDUAL_PAN_STS_RECD_ON_PAN1        (1<<7)
+#define cDUAL_PAN_STS_RECD_ON_PAN0        (1<<6)
+#define cDUAL_PAN_STS_DUAL_PAN_REMAIN     (0x3F)
+
+// CCA_CTRL bits
+#define cCCA_CTRL_AGC_FRZ_EN          (1<<6)
+#define cCCA_CTRL_CONT_RSSI_EN        (1<<5)
+#define cCCA_CTRL_LQI_RSSI_NOT_CORR   (1<<4)
+#define cCCA_CTRL_CCA3_AND_NOT_OR     (1<<3)
+#define cCCA_CTRL_POWER_COMP_EN_LQI   (1<<2)
+#define cCCA_CTRL_POWER_COMP_EN_ED    (1<<1)
+#define cCCA_CTRL_POWER_COMP_EN_CCA1  (1<<0)
+
+// GPIO_DATA bits
+#define cGPIO_DATA_7        (1<<7)
+#define cGPIO_DATA_6        (1<<6)
+#define cGPIO_DATA_5        (1<<5)
+#define cGPIO_DATA_4        (1<<4)
+#define cGPIO_DATA_3        (1<<3)
+#define cGPIO_DATA_2        (1<<2)
+#define cGPIO_DATA_1        (1<<1)
+#define cGPIO_DATA_0        (1<<0)
+
+// GPIO_DIR bits
+#define cGPIO_DIR_7         (1<<7)
+#define cGPIO_DIR_6         (1<<6)
+#define cGPIO_DIR_5         (1<<5)
+#define cGPIO_DIR_4         (1<<4)
+#define cGPIO_DIR_3         (1<<3)
+#define cGPIO_DIR_2         (1<<2)
+#define cGPIO_DIR_1         (1<<1)
+#define cGPIO_DIR_0         (1<<0)
+
+// GPIO_PUL_EN bits
+#define cGPIO_PUL_EN_7      (1<<7)
+#define cGPIO_PUL_EN_6      (1<<6)
+#define cGPIO_PUL_EN_5      (1<<5)
+#define cGPIO_PUL_EN_4      (1<<4)
+#define cGPIO_PUL_EN_3      (1<<3)
+#define cGPIO_PUL_EN_2      (1<<2)
+#define cGPIO_PUL_EN_1      (1<<1)
+#define cGPIO_PUL_EN_0      (1<<0)
+
+// GPIO_PUL_SEL bits
+#define cGPIO_PUL_SEL_7     (1<<7)
+#define cGPIO_PUL_SEL_6     (1<<6)
+#define cGPIO_PUL_SEL_5     (1<<5)
+#define cGPIO_PUL_SEL_4     (1<<4)
+#define cGPIO_PUL_SEL_3     (1<<3)
+#define cGPIO_PUL_SEL_2     (1<<2)
+#define cGPIO_PUL_SEL_1     (1<<1)
+#define cGPIO_PUL_SEL_0     (1<<0)
+
+// GPIO_DS bits
+#define cGPIO_DS_7          (1<<7)
+#define cGPIO_DS_6          (1<<6)
+#define cGPIO_DS_5          (1<<5)
+#define cGPIO_DS_4          (1<<4)
+#define cGPIO_DS_3          (1<<3)
+#define cGPIO_DS_2          (1<<2)
+#define cGPIO_DS_1          (1<<1)
+#define cGPIO_DS_0          (1<<0)
+
+// SPI_CTRL bits
+//#define cSPI_CTRL_MISO_HIZ_EN        (1<<1)
+//#define cSPI_CTRL_PB_PROTECT         (1<<0)
+
+// ANT_PAD_CTRL bits
+#define cANT_PAD_CTRL_ANTX_POL           (0x0F)
+#define cANT_PAD_CTRL_ANTX_POL_Shift_c   (4)
+#define cANT_PAD_CTRL_ANTX_CTRLMODE      (1<<3)
+#define cANT_PAD_CTRL_ANTX_HZ            (1<<2)
+#define cANT_PAD_CTRL_ANTX_EN            (3)
+
+// MISC_PAD_CTRL bits
+#define cMISC_PAD_CTRL_MISO_HIZ_EN        (1<<3)
+#define cMISC_PAD_CTRL_IRQ_B_OD           (1<<2)
+#define cMISC_PAD_CTRL_NON_GPIO_DS        (1<<1)
+#define cMISC_PAD_CTRL_ANTX_CURR          (1<<0)
+
+// ANT_AGC_CTRL bits
+#define cANT_AGC_CTRL_FAD_EN_Shift_c    (0)
+#define cANT_AGC_CTRL_FAD_EN_Mask_c     (1<<cANT_AGC_CTRL_FAD_EN_Shift_c)
+#define cANT_AGC_CTRL_ANTX_Shift_c      (1)
+#define cANT_AGC_CTRL_ANTX_Mask_c       (1<<cANT_AGC_CTRL_ANTX_Shift_c)
+
+// BSM_CTRL bits
+#define cBSM_CTRL_BSM_EN                  (1<<0)
+
+// SOFT_RESET bits
+#define cSOFT_RESET_SOG_RST            (1<<7)
+#define cSOFT_RESET_REGS_RST           (1<<4)
+#define cSOFT_RESET_PLL_RST            (1<<3)
+#define cSOFT_RESET_TX_RST             (1<<2)
+#define cSOFT_RESET_RX_RST             (1<<1)
+#define cSOFT_RESET_SEQ_MGR_RST        (1<<0)
+
+// SEQ_MGR_CTRL bits
+#define cSEQ_MGR_CTRL_SEQ_STATE_CTRL          (3)
+#define cSEQ_MGR_CTRL_SEQ_STATE_CTRL_Shift_c  (6)
+#define cSEQ_MGR_CTRL_NO_RX_RECYCLE           (1<<5)
+#define cSEQ_MGR_CTRL_LATCH_PREAMBLE          (1<<4)
+#define cSEQ_MGR_CTRL_EVENT_TMR_DO_NOT_LATCH  (1<<3)
+#define cSEQ_MGR_CTRL_CLR_NEW_SEQ_INHIBIT     (1<<2)
+#define cSEQ_MGR_CTRL_PSM_LOCK_DIS            (1<<1)
+#define cSEQ_MGR_CTRL_PLL_ABORT_OVRD          (1<<0)
+
+// SEQ_MGR_STS bits
+#define cSEQ_MGR_STS_TMR2_SEQ_TRIG_ARMED (1<<7)
+#define cSEQ_MGR_STS_RX_MODE             (1<<6)
+#define cSEQ_MGR_STS_RX_TIMEOUT_PENDING  (1<<5)
+#define cSEQ_MGR_STS_NEW_SEQ_INHIBIT     (1<<4)
+#define cSEQ_MGR_STS_SEQ_IDLE            (1<<3)
+#define cSEQ_MGR_STS_XCVSEQ_ACTUAL       (7)
+
+// ABORT_STS bits
+#define cABORT_STS_PLL_ABORTED        (1<<2)
+#define cABORT_STS_TC3_ABORTED        (1<<1)
+#define cABORT_STS_SW_ABORTED         (1<<0)
+
+// FILTERFAIL_CODE2 bits
+#define cFILTERFAIL_CODE2_PAN_SEL  (1<<7)
+#define cFILTERFAIL_CODE2_9_8      (3)
+
+// PHY_STS bits
+#define cPHY_STS_PLL_UNLOCK  (1<<7)
+#define cPHY_STS_PLL_LOCK_ERR        (1<<6)
+#define cPHY_STS_PLL_LOCK            (1<<5)
+#define cPHY_STS_CRCVALID            (1<<3)
+#define cPHY_STS_FILTERFAIL_FLAG_SEL (1<<2)
+#define cPHY_STS_SFD_DET             (1<<1)
+#define cPHY_STS_PREAMBLE_DET        (1<<0)
+
+// TESTMODE_CTRL bits
+#define cTEST_MODE_CTRL_HOT_ANT            (1<<4)
+#define cTEST_MODE_CTRL_IDEAL_RSSI_EN      (1<<3)
+#define cTEST_MODE_CTRL_IDEAL_PFC_EN       (1<<2)
+#define cTEST_MODE_CTRL_CONTINUOUS_EN      (1<<1)
+#define cTEST_MODE_CTRL_FPGA_EN            (1<<0)
+
+// DTM_CTRL1 bits
+#define cDTM_CTRL1_ATM_LOCKED  (1<<7)
+#define cDTM_CTRL1_DTM_EN      (1<<6)
+#define cDTM_CTRL1_PAGE5       (1<<5)
+#define cDTM_CTRL1_PAGE4       (1<<4)
+#define cDTM_CTRL1_PAGE3       (1<<3)
+#define cDTM_CTRL1_PAGE2       (1<<2)
+#define cDTM_CTRL1_PAGE1       (1<<1)
+#define cDTM_CTRL1_PAGE0       (1<<0)
+
+// TX_MODE_CTRL
+#define cTX_MODE_CTRL_TX_INV   (1<<4)
+#define cTX_MODE_CTRL_BT_EN    (1<<3)
+#define cTX_MODE_CTRL_DTS2     (1<<2)
+#define cTX_MODE_CTRL_DTS1     (1<<1)
+#define cTX_MODE_CTRL_DTS0     (1<<0)
+
+#define cTX_MODE_CTRL_DTS_MASK (7)
+
+// CLK_OUT_CTRL bits
+#define cCLK_OUT_EXTEND        (1<<7)
+#define cCLK_OUT_HIZ           (1<<6)
+#define cCLK_OUT_SR            (1<<5)
+#define cCLK_OUT_DS            (1<<4)
+#define cCLK_OUT_EN            (1<<3)
+#define cCLK_OUT_DIV_Mask      (7<<0)
+
+#define gCLK_OUT_FREQ_32_MHz      (0)
+#define gCLK_OUT_FREQ_16_MHz      (1)
+#define gCLK_OUT_FREQ_8_MHz       (2)
+#define gCLK_OUT_FREQ_4_MHz       (3)
+#define gCLK_OUT_FREQ_1_MHz       (4)
+#define gCLK_OUT_FREQ_250_KHz     (5)
+#define gCLK_OUT_FREQ_62_5_KHz    (6)
+#define gCLK_OUT_FREQ_32_78_KHz   (7)
+#define gCLK_OUT_FREQ_DISABLE     (8)
+
+
+
+
+#endif /* __MCR20_REG_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/mcr20a-rf-driver/source/NanostackRfPhyMcr20a.cpp	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,1820 @@
+/*
+ * 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 "NanostackRfPhyMcr20a.h"
+
+#if defined(MBED_CONF_NANOSTACK_CONFIGURATION) && DEVICE_SPI
+
+#include "ns_types.h"
+#include "platform/arm_hal_interrupt.h"
+#include "nanostack/platform/arm_hal_phy.h"
+#include <string.h>
+#include "rtos.h"
+
+/* Freescale headers which are for C files */
+extern "C" {
+#include "MCR20Drv.h"
+#include "MCR20Reg.h"
+#include "MCR20Overwrites.h"
+}
+
+
+#define RF_BUFFER_SIZE 128
+
+/*Radio RX and TX state definitions*/
+#define RFF_ON 0x01
+#define RFF_RX 0x02
+#define RFF_TX 0x04
+#define RFF_CCA 0x08
+
+#define RF_MODE_NORMAL  0
+#define RF_MODE_SNIFFER 1
+
+#define RF_CCA_THRESHOLD 75 /* -75 dBm */
+
+#define RF_TX_POWER_MAX 0
+
+/* PHY constants in symbols */
+#define gPhyWarmUpTime_c       9
+#define gPhySHRDuration_c     10
+#define gPhySymbolsPerOctet_c  2
+#define gPhyAckWaitDuration_c 54
+
+#define gCcaED_c               0
+#define gCcaCCA_MODE1_c        1
+
+#define gXcvrRunState_d       gXcvrPwrAutodoze_c
+#if !defined(TARGET_KW24D)
+  #define gXcvrLowPowerState_d  gXcvrPwrHibernate_c
+#else
+  #define gXcvrLowPowerState_d  gXcvrPwrAutodoze_c
+#endif
+
+/* MCR20A XCVR states */
+typedef enum xcvrState_tag{
+  gIdle_c,
+  gRX_c,
+  gTX_c,
+  gCCA_c,
+  gTR_c,
+  gCCCA_c,
+}xcvrState_t;
+
+/* MCR20A XCVR low power states */
+typedef enum xcvrPwrMode_tag{
+    gXcvrPwrIdle_c,
+    gXcvrPwrAutodoze_c,
+    gXcvrPwrDoze_c,
+    gXcvrPwrHibernate_c
+}xcvrPwrMode_t;
+
+
+/*RF Part Type*/
+typedef enum
+{
+    FREESCALE_UNKNOW_DEV = 0,
+    FREESCALE_MCR20A
+}rf_trx_part_e;
+
+/*Atmel RF states*/
+typedef enum
+{
+    NOP = 0x00,
+    BUSY_RX = 0x01,
+    RF_TX_START = 0x02,
+    FORCE_TRX_OFF = 0x03,
+    FORCE_PLL_ON = 0x04,
+    RX_ON = 0x06,
+    TRX_OFF = 0x08,
+    PLL_ON = 0x09,
+    BUSY_RX_AACK = 0x11,
+    SLEEP = 0x0F,
+    RX_AACK_ON = 0x16,
+    TX_ARET_ON = 0x19
+}rf_trx_states_t;
+
+/*RF receive buffer*/
+static uint8_t rf_buffer[RF_BUFFER_SIZE];
+
+/* TX info */
+static uint8_t  radio_tx_power = 0x17; /* 0 dBm */
+static uint8_t  mac_tx_handle = 0;
+static uint8_t  need_ack = 0;
+static uint16_t tx_len = 0;
+
+/* RF driver data */
+static xcvrState_t mPhySeqState;
+static xcvrPwrMode_t mPwrState;
+static phy_device_driver_s device_driver;
+static uint8_t mStatusAndControlRegs[8];
+static uint8_t rf_rnd = 0;
+static int8_t  rf_radio_driver_id = -1;
+static uint8_t MAC_address[8];
+
+/* Driver instance handle and hardware */
+static NanostackRfPhyMcr20a *rf = NULL;
+static SPI *spi = NULL;
+static DigitalOut *cs = NULL;
+static DigitalOut *rst = NULL;
+static InterruptIn *irq = NULL;
+static DigitalIn *irq_pin = NULL;
+static Thread *irq_thread = NULL;
+
+/* Channel info */                 /* 2405    2410    2415    2420    2425    2430    2435    2440    2445    2450    2455    2460    2465    2470    2475    2480 */
+static const uint8_t  pll_int[16] =  {0x0B,   0x0B,   0x0B,   0x0B,   0x0B,   0x0B,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0D,   0x0D,   0x0D,   0x0D};
+static const uint16_t pll_frac[16] = {0x2800, 0x5000, 0x7800, 0xA000, 0xC800, 0xF000, 0x1800, 0x4000, 0x6800, 0x9000, 0xB800, 0xE000, 0x0800, 0x3000, 0x5800, 0x8000};
+
+/* Channel configurations for 2.4 */
+static const phy_rf_channel_configuration_s phy_24ghz = {2405000000U, 5000000U, 250000U, 16U, M_OQPSK};
+
+static const phy_device_channel_page_s phy_channel_pages[] = {
+        { CHANNEL_PAGE_0, &phy_24ghz},
+        { CHANNEL_PAGE_0, NULL}
+};
+
+
+static rf_trx_part_e rf_radio_type_read(void);
+
+MBED_UNUSED static void rf_ack_wait_timer_start(uint16_t slots);
+MBED_UNUSED static void rf_ack_wait_timer_stop(void);
+MBED_UNUSED static void rf_handle_cca_ed_done(void);
+MBED_UNUSED static void rf_handle_tx_end(void);
+MBED_UNUSED static void rf_handle_rx_end(void);
+MBED_UNUSED static void rf_on(void);
+MBED_UNUSED static void rf_receive(void);
+MBED_UNUSED static void rf_poll_trx_state_change(rf_trx_states_t trx_state);
+MBED_UNUSED static void rf_init(void);
+MBED_UNUSED static void rf_set_mac_address(const uint8_t *ptr);
+MBED_UNUSED static int8_t rf_device_register(void);
+MBED_UNUSED static void rf_device_unregister(void);
+MBED_UNUSED static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol );
+MBED_UNUSED static void rf_cca_abort(void);
+MBED_UNUSED static void rf_read_mac_address(uint8_t *ptr);
+MBED_UNUSED static int8_t rf_read_random(void);
+MBED_UNUSED static void rf_calibration_cb(void);
+MBED_UNUSED static void rf_init_phy_mode(void);
+MBED_UNUSED static void rf_ack_wait_timer_interrupt(void);
+MBED_UNUSED static void rf_calibration_timer_interrupt(void);
+MBED_UNUSED static void rf_calibration_timer_start(uint32_t slots);
+MBED_UNUSED static void rf_cca_timer_interrupt(void);
+MBED_UNUSED static void rf_cca_timer_start(uint32_t slots);
+MBED_UNUSED static uint16_t rf_get_phy_mtu_size(void);
+MBED_UNUSED static uint8_t rf_scale_lqi(int8_t rssi);
+
+/**
+ *  RF output power write
+ *
+ * \brief TX power has to be set before network start.
+ *
+ * \param power
+ *              See datasheet for TX power settings
+ *
+ * \return 0, Supported Value
+ * \return -1, Not Supported Value
+ */
+MBED_UNUSED static int8_t rf_tx_power_set(uint8_t power);
+MBED_UNUSED static uint8_t rf_tx_power_get(void);
+MBED_UNUSED static int8_t rf_enable_antenna_diversity(void);
+
+/* Private functions */
+MBED_UNUSED static void    rf_abort(void);
+MBED_UNUSED static void    rf_promiscuous(uint8_t mode);
+MBED_UNUSED static void    rf_get_timestamp(uint32_t *pRetClk);
+MBED_UNUSED static void    rf_set_timeout(uint32_t *pEndTime);
+MBED_UNUSED static void    rf_set_power_state(xcvrPwrMode_t newState);
+MBED_UNUSED static uint8_t rf_if_read_rnd(void);
+MBED_UNUSED static uint8_t rf_convert_LQI(uint8_t hwLqi);
+MBED_UNUSED static uint8_t rf_get_channel_energy(void);
+MBED_UNUSED static uint8_t rf_convert_energy_level(uint8_t energyLevel);
+MBED_UNUSED static int8_t  rf_convert_LQI_to_RSSI(uint8_t lqi);
+MBED_UNUSED static int8_t  rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel);
+MBED_UNUSED static int8_t  rf_extension(phy_extension_type_e extension_type,uint8_t *data_ptr);
+MBED_UNUSED static int8_t  rf_address_write(phy_address_type_e address_type,uint8_t *address_ptr);
+static void PHY_InterruptThread(void);
+static void handle_interrupt(void);
+
+
+/*
+ * \brief Read connected radio part.
+ *
+ * This function only return valid information when rf_init() is called
+ *
+ * \return
+ */
+static rf_trx_part_e rf_radio_type_read(void)
+{
+    return FREESCALE_MCR20A;
+}
+
+/*
+ * \brief Function initialises and registers the RF driver.
+ *
+ * \param none
+ *
+ * \return rf_radio_driver_id Driver ID given by NET library
+ */
+static int8_t rf_device_register(void)
+{
+    rf_trx_part_e radio_type;
+
+    rf_init();
+
+
+
+    radio_type = rf_radio_type_read();
+    if(radio_type == FREESCALE_MCR20A)
+    {
+        /*Set pointer to MAC address*/
+        device_driver.PHY_MAC = MAC_address;
+        device_driver.driver_description = (char*)"FREESCALE_MAC";
+
+        //Create setup Used Radio chips
+        /*Type of RF PHY is SubGHz*/
+        device_driver.link_type = PHY_LINK_15_4_2_4GHZ_TYPE;
+
+        device_driver.phy_channel_pages = phy_channel_pages;
+        /*Maximum size of payload is 127*/
+        device_driver.phy_MTU = 127;
+        /*No header in PHY*/
+        device_driver.phy_header_length = 0;
+        /*No tail in PHY*/
+        device_driver.phy_tail_length = 0;
+        /*Set address write function*/
+        device_driver.address_write = &rf_address_write;
+        /*Set RF extension function*/
+        device_driver.extension = &rf_extension;
+        /*Set RF state control function*/
+        device_driver.state_control = &rf_interface_state_control;
+        /*Set transmit function*/
+        device_driver.tx = &rf_start_cca;
+        /*Upper layer callbacks init to NULL*/
+        device_driver.phy_rx_cb = NULL;
+        device_driver.phy_tx_done_cb = NULL;
+        /*Virtual upper data callback init to NULL*/
+        device_driver.arm_net_virtual_rx_cb = NULL;
+        device_driver.arm_net_virtual_tx_cb = NULL;
+
+        /*Register device driver*/
+        rf_radio_driver_id = arm_net_phy_register(&device_driver);
+    }
+
+    return rf_radio_driver_id;
+}
+
+/*
+ * \brief Function unregisters the RF driver.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_device_unregister(void)
+{
+    arm_net_phy_unregister(rf_radio_driver_id);
+}
+
+/*
+ * \brief Function returns the generated 8-bit random value for seeding Pseudo-random generator.
+ *
+ * \param none
+ *
+ * \return random value
+ */
+static int8_t rf_read_random(void)
+{
+    return rf_rnd;
+}
+
+/*
+ * \brief Function is a call back for ACK wait timeout.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_ack_wait_timer_interrupt(void)
+{
+    /* The packet was transmitted successfully, but no ACK was received */
+    if (device_driver.phy_tx_done_cb) {
+        device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 1, 1);
+    }
+    rf_receive();
+}
+
+/*
+ * \brief Function is a call back for calibration interval timer.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_calibration_timer_interrupt(void)
+{
+}
+
+/*
+ * \brief Function is a call back for cca interval timer.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_cca_timer_interrupt(void)
+{
+    /* CCA time-out handled by Hardware */
+}
+
+
+/*
+ * \brief Function starts the ACK wait time-out.
+ *
+ * \param slots The ACK wait time-out in [symbols]
+ *
+ * \return none
+ */
+static void rf_ack_wait_timer_start(uint16_t time)
+{
+    uint32_t timeout;
+
+    rf_get_timestamp(&timeout);
+    timeout += time;
+    rf_set_timeout(&timeout);
+}
+
+/*
+ * \brief Function starts the calibration interval.
+ *
+ * \param slots Given slots, resolution 50us
+ *
+ * \return none
+ */
+static void rf_calibration_timer_start(uint32_t slots)
+{
+    (void)slots;
+}
+
+/*
+ * \brief Function starts the CCA timout.
+ *
+ * \param slots Given slots, resolution 50us
+ *
+ * \return none
+ */
+static void rf_cca_timer_start(uint32_t slots)
+{
+    (void)slots;
+}
+
+/*
+ * \brief Function stops the ACK wait timeout.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_ack_wait_timer_stop(void)
+{
+}
+
+/*
+ * \brief Function reads the MAC address array.
+ *
+ * \param ptr Pointer to read array
+ *
+ * \return none
+ */
+static void rf_read_mac_address(uint8_t *ptr)
+{
+    memcpy(ptr, MAC_address, 8);
+}
+
+/*
+ * \brief Function sets the MAC address array.
+ *
+ * \param ptr Pointer to given MAC address array
+ *
+ * \return none
+ */
+static void rf_set_mac_address(const uint8_t *ptr)
+{
+    memcpy(MAC_address, ptr, 8);
+}
+
+static uint16_t rf_get_phy_mtu_size(void)
+{
+    return device_driver.phy_MTU;
+}
+
+/*
+ * \brief Function writes 16-bit address in RF address filter.
+ *
+ * \param short_address Given short address
+ *
+ * \return none
+ */
+static void rf_set_short_adr(uint8_t * short_address)
+{
+    /* Write one register at a time to be accessible from hibernate mode */
+    MCR20Drv_IndirectAccessSPIWrite(MACSHORTADDRS0_MSB, short_address[0]);
+    MCR20Drv_IndirectAccessSPIWrite(MACSHORTADDRS0_LSB, short_address[1]);
+}
+
+/*
+ * \brief Function writes PAN Id in RF PAN Id filter.
+ *
+ * \param pan_id Given PAN Id
+ *
+ * \return none
+ */
+static void rf_set_pan_id(uint8_t *pan_id)
+{
+    /* Write one register at a time to be accessible from hibernate mode */
+    MCR20Drv_IndirectAccessSPIWrite(MACPANID0_MSB, pan_id[0]);
+    MCR20Drv_IndirectAccessSPIWrite(MACPANID0_LSB, pan_id[1]);
+}
+
+/*
+ * \brief Function writes 64-bit address in RF address filter.
+ *
+ * \param address Given 64-bit address
+ *
+ * \return none
+ */
+static void rf_set_address(uint8_t *address)
+{
+    /* Write one register at a time to be accessible from hibernate mode */
+    MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_0,  address[7]);
+    MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_8,  address[6]);
+    MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_16, address[5]);
+    MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_24, address[4]);
+    MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_32, address[3]);
+    MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_40, address[2]);
+    MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_48, address[1]);
+    MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_56, address[0]);
+}
+
+/*
+ * \brief Function sets the RF channel.
+ *
+ * \param ch New channel
+ *
+ * \return none
+ */
+static void rf_channel_set(uint8_t channel)
+{
+    MCR20Drv_DirectAccessSPIWrite(PLL_INT0, pll_int[channel - 11]);
+    MCR20Drv_DirectAccessSPIMultiByteWrite(PLL_FRAC0_LSB, (uint8_t *) &pll_frac[channel - 11], 2);
+}
+
+
+/*
+ * \brief Function initialises the radio driver and resets the radio.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_init(void)
+{
+    uint32_t index;
+    mPhySeqState = gIdle_c;
+    mPwrState = gXcvrPwrIdle_c;
+    /*Reset RF module*/
+    MCR20Drv_RESET();
+    /* Initialize the transceiver SPI driver */
+    MCR20Drv_Init();
+    /* Disable Tristate on MISO for SPI reads */
+    MCR20Drv_IndirectAccessSPIWrite(MISC_PAD_CTRL, 0x02);
+    /* Set XCVR clock output settings */
+    #if !defined(TARGET_KW24D)
+      MCR20Drv_Set_CLK_OUT_Freq(gMCR20_ClkOutFreq_d);
+    #endif
+    /* Set default XCVR power state */
+    rf_set_power_state(gXcvrRunState_d);
+
+    /* PHY_CTRL1 default HW settings  + AUTOACK enabled */
+    mStatusAndControlRegs[PHY_CTRL1] = cPHY_CTRL1_AUTOACK;
+    /* PHY_CTRL2 : mask all PP interrupts */
+    mStatusAndControlRegs[PHY_CTRL2] = cPHY_CTRL2_CRC_MSK | \
+                                       cPHY_CTRL2_PLL_UNLOCK_MSK | \
+                                       /*cPHY_CTRL2_FILTERFAIL_MSK | */ \
+                                       cPHY_CTRL2_RX_WMRK_MSK | \
+                                       cPHY_CTRL2_CCAMSK | \
+                                       cPHY_CTRL2_RXMSK | \
+                                       cPHY_CTRL2_TXMSK | \
+                                       cPHY_CTRL2_SEQMSK;
+    /* PHY_CTRL3 : enable timer 3 and disable remaining interrupts */
+    mStatusAndControlRegs[PHY_CTRL3] = cPHY_CTRL3_ASM_MSK    | \
+                                       cPHY_CTRL3_PB_ERR_MSK | \
+                                       cPHY_CTRL3_WAKE_MSK   | \
+                                       cPHY_CTRL3_TMR3CMP_EN;
+    /* PHY_CTRL4 unmask global TRX interrupts, enable 16 bit mode for TC2 - TC2 prime EN */
+    mStatusAndControlRegs[PHY_CTRL4] = cPHY_CTRL4_TC2PRIME_EN | (gCcaCCA_MODE1_c << cPHY_CTRL4_CCATYPE_Shift_c);
+    /* Clear all PP IRQ bits to avoid unexpected interrupts immediately after initialization */
+    mStatusAndControlRegs[IRQSTS1] = cIRQSTS1_PLL_UNLOCK_IRQ | \
+                                     cIRQSTS1_FILTERFAIL_IRQ | \
+                                     cIRQSTS1_RXWTRMRKIRQ | \
+                                     cIRQSTS1_CCAIRQ | \
+                                     cIRQSTS1_RXIRQ | \
+                                     cIRQSTS1_TXIRQ | \
+                                     cIRQSTS1_SEQIRQ;
+
+    mStatusAndControlRegs[IRQSTS2] = cIRQSTS2_ASM_IRQ | cIRQSTS2_PB_ERR_IRQ | cIRQSTS2_WAKE_IRQ;
+    /* Mask and clear all TMR IRQs */
+    mStatusAndControlRegs[IRQSTS3] = cIRQSTS3_TMR4MSK | cIRQSTS3_TMR3MSK | cIRQSTS3_TMR2MSK | cIRQSTS3_TMR1MSK | \
+                                     cIRQSTS3_TMR4IRQ | cIRQSTS3_TMR3IRQ | cIRQSTS3_TMR2IRQ | cIRQSTS3_TMR1IRQ;
+    /* Write settings to XCVR */
+    MCR20Drv_DirectAccessSPIMultiByteWrite(PHY_CTRL1, &mStatusAndControlRegs[PHY_CTRL1], 5);
+    /* Clear all interrupts */
+    MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, &mStatusAndControlRegs[IRQSTS1], 3);
+
+    /*  RX_FRAME_FILTER. Accept FrameVersion 0 and 1 packets, reject all others */
+    MCR20Drv_IndirectAccessSPIWrite(RX_FRAME_FILTER, (cRX_FRAME_FLT_FRM_VER | \
+                                                      cRX_FRAME_FLT_BEACON_FT | \
+                                                      cRX_FRAME_FLT_DATA_FT | \
+                                                      cRX_FRAME_FLT_CMD_FT ));
+    /* Direct register overwrites */
+    for (index = 0; index < sizeof(overwrites_direct)/sizeof(overwrites_t); index++)
+        MCR20Drv_DirectAccessSPIWrite(overwrites_direct[index].address, overwrites_direct[index].data);
+    /* Indirect register overwrites */
+    for (index = 0; index < sizeof(overwrites_indirect)/sizeof(overwrites_t); index++)
+        MCR20Drv_IndirectAccessSPIWrite(overwrites_indirect[index].address, overwrites_indirect[index].data);
+
+    /* Set the CCA energy threshold value */
+    MCR20Drv_IndirectAccessSPIWrite(CCA1_THRESH, RF_CCA_THRESHOLD);
+    /* Set prescaller to obtain 1 symbol (16us) timebase */
+    MCR20Drv_IndirectAccessSPIWrite(TMR_PRESCALE, 0x05);
+
+    MCR20Drv_IRQ_Enable();
+
+    /*Read random variable. This will be used when seeding pseudo-random generator*/
+    rf_rnd = rf_if_read_rnd();
+    /*Write initial eui64*/
+    rf_set_address(MAC_address);
+    /*set default channel to 11*/
+    rf_channel_set(11);
+    /*Start receiver*/
+    rf_receive();
+}
+
+/**
+ * \brief Function gets called when MAC is setting radio off.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_off(void)
+{
+    /* Abort any ongoing sequences */
+    rf_abort();
+    /* Set XCVR in a low power state */
+    rf_set_power_state(gXcvrLowPowerState_d);
+}
+
+/*
+ * \brief Function polls the RF state until it has changed to desired state.
+ *
+ * \param trx_state RF state
+ *
+ * \return none
+ */
+static void rf_poll_trx_state_change(rf_trx_states_t trx_state)
+{
+    (void)trx_state;
+}
+
+/*
+ * \brief Function starts the CCA process before starting data transmission and copies the data to RF TX FIFO.
+ *
+ * \param data_ptr Pointer to TX data
+ * \param data_length Length of the TX data
+ * \param tx_handle Handle to transmission
+ * \return 0 Success
+ * \return -1 Busy
+ */
+static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol )
+{
+    uint8_t ccaMode;
+
+    /* Parameter validation */
+    if( !data_ptr || (data_length > 125) || (PHY_LAYER_PAYLOAD != data_protocol) )
+    {
+        return -1;
+    }
+
+    if( mPhySeqState == gRX_c )
+    {
+        uint8_t phyReg = MCR20Drv_DirectAccessSPIRead(SEQ_STATE) & 0x1F;
+        /* Check for an Rx in progress. */
+        if((phyReg <= 0x06) || (phyReg == 0x15) || (phyReg == 0x16))
+        {
+            if (device_driver.phy_tx_done_cb) {
+                device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 1, 1);
+            }
+            return -1;
+        }
+        rf_abort();
+    }
+
+    /*Check if transmitter is busy*/
+    if( mPhySeqState != gIdle_c )
+    {
+        /*Return busy*/
+        return -1;
+    }
+
+    /*Store TX handle*/
+    mac_tx_handle = tx_handle;
+    /*Check if transmitted data needs to be acked*/
+    need_ack = (*data_ptr & 0x20) == 0x20;
+
+    /* Set XCVR power state in run mode */
+    rf_set_power_state(gXcvrRunState_d);
+    /* Load data into XCVR */
+    tx_len = data_length + 2;
+    MCR20Drv_PB_SPIBurstWrite(data_ptr - 1, data_length + 1);
+    MCR20Drv_PB_SPIByteWrite(0,tx_len);
+
+    /* Set CCA mode 1 */
+    ccaMode = (mStatusAndControlRegs[PHY_CTRL4] >> cPHY_CTRL4_CCATYPE_Shift_c) & cPHY_CTRL4_CCATYPE;
+    if( ccaMode != gCcaCCA_MODE1_c )
+    {
+        mStatusAndControlRegs[PHY_CTRL4] &= ~(cPHY_CTRL4_CCATYPE << cPHY_CTRL4_CCATYPE_Shift_c);
+        mStatusAndControlRegs[PHY_CTRL4] |= gCcaCCA_MODE1_c << cPHY_CTRL4_CCATYPE_Shift_c;
+        MCR20Drv_DirectAccessSPIWrite(PHY_CTRL4, mStatusAndControlRegs[PHY_CTRL4]);
+    }
+
+    /* Read XCVR registers */
+    mStatusAndControlRegs[0] = MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &mStatusAndControlRegs[1], 4);
+    mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ);
+    mStatusAndControlRegs[PHY_CTRL1] |= gCCA_c;
+    mPhySeqState = gCCA_c;
+
+    /* Ensure that no spurious interrupts are raised */
+    mStatusAndControlRegs[IRQSTS3] &= 0xF0; /* do not change other IRQ status */
+    mStatusAndControlRegs[IRQSTS3] |= (cIRQSTS3_TMR3MSK | cIRQSTS3_TMR3IRQ);
+    MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 3);
+
+    /* Write XCVR settings */
+    MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]);
+
+    /* Unmask SEQ interrupt */
+    mStatusAndControlRegs[PHY_CTRL2] &= ~(cPHY_CTRL2_SEQMSK);
+    MCR20Drv_DirectAccessSPIWrite(PHY_CTRL2, mStatusAndControlRegs[PHY_CTRL2]);
+
+    /*Return success*/
+    return 0;
+}
+
+/*
+ * \brief Function aborts CCA process.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_cca_abort(void)
+{
+    rf_abort();
+}
+
+/*
+ * \brief Function starts the transmission of the frame. Called from ISR context!
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_start_tx(void)
+{
+    /* Perform TxRxAck sequence if required by phyTxMode */
+    if( need_ack )
+    {
+        mStatusAndControlRegs[PHY_CTRL1] |= cPHY_CTRL1_RXACKRQD;
+        mPhySeqState = gTR_c;
+    }
+    else
+    {
+        mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_RXACKRQD);
+        mPhySeqState = gTX_c;
+    }
+
+    mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ);
+    mStatusAndControlRegs[PHY_CTRL1] |= mPhySeqState;
+
+    /* Unmask SEQ interrupt */
+    mStatusAndControlRegs[PHY_CTRL2] &= ~(cPHY_CTRL2_SEQMSK);
+
+    /* Start the sequence immediately */
+    MCR20Drv_DirectAccessSPIMultiByteWrite(PHY_CTRL1, &mStatusAndControlRegs[PHY_CTRL1], 2);
+
+    if( need_ack )
+    {
+        rf_ack_wait_timer_start(gPhyWarmUpTime_c + gPhySHRDuration_c + tx_len * gPhySymbolsPerOctet_c + gPhyAckWaitDuration_c);
+    }
+}
+
+/*
+ * \brief Function sets the RF in RX state. Called from ISR context!
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_receive(void)
+{
+    uint8_t phyRegs[5];
+
+    /* RX can start only from Idle state */
+    if( mPhySeqState != gIdle_c )
+    {
+        return;
+    }
+
+    /* Set XCVR power state in run mode */
+    rf_set_power_state(gXcvrRunState_d);
+    /* read XVCR settings */
+    phyRegs[IRQSTS1] = MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &phyRegs[IRQSTS2], 4);
+    /* unmask SEQ interrupt */
+    phyRegs[PHY_CTRL2] &= ~(cPHY_CTRL2_SEQMSK);
+    /* set XcvrSeq to RX */
+    phyRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ);
+    phyRegs[PHY_CTRL1] |=  gRX_c;
+    mPhySeqState = gRX_c;
+    /* Ensure that no spurious interrupts are raised */
+    phyRegs[IRQSTS3] &= 0xF0; /* do not change other IRQ status */
+    phyRegs[IRQSTS3] |= cIRQSTS3_TMR3MSK | cIRQSTS3_TMR3IRQ;
+    /* sync settings with XCVR */
+    MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, phyRegs, 5);
+}
+
+/*
+ * \brief Function calibrates the radio.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_calibration_cb(void)
+{
+}
+
+/*
+ * \brief Function sets RF_ON flag when radio is powered.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_on(void)
+{
+}
+
+/*
+ * \brief Function is a call back for RX end interrupt.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_handle_rx_end(void)
+{
+    uint8_t rf_lqi = MCR20Drv_DirectAccessSPIRead(LQI_VALUE);
+    int8_t rf_rssi = 0;
+    uint8_t len = mStatusAndControlRegs[RX_FRM_LEN] - 2;
+
+
+    /*Start receiver*/
+    rf_receive();
+
+    /*Check the length is valid*/
+    if(len > 1 && len < RF_BUFFER_SIZE)
+    {
+        rf_lqi  = rf_convert_LQI(rf_lqi);
+        rf_rssi = rf_convert_LQI_to_RSSI(rf_lqi);
+        /*gcararu: Scale LQI using received RSSI, to match the LQI reported by the ATMEL radio */
+        rf_lqi  = rf_scale_lqi(rf_rssi);
+
+        /*Read received packet*/
+        MCR20Drv_PB_SPIBurstRead(rf_buffer, len);
+        if (device_driver.phy_rx_cb) {
+            device_driver.phy_rx_cb(rf_buffer, len, rf_lqi, rf_rssi, rf_radio_driver_id);
+        }
+    }
+}
+
+/*
+ * \brief Function is called when MAC is shutting down the radio.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_shutdown(void)
+{
+    /*Call RF OFF*/
+    rf_off();
+}
+
+/*
+ * \brief Function is a call back for TX end interrupt.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_handle_tx_end(void)
+{
+    uint8_t rx_frame_pending = mStatusAndControlRegs[IRQSTS1] & cIRQSTS1_RX_FRM_PEND;
+
+    /*Start receiver*/
+    rf_receive();
+
+    if (!device_driver.phy_tx_done_cb) {
+        return;
+    }
+
+    /*Call PHY TX Done API*/
+    if( need_ack )
+    {
+        if( rx_frame_pending )
+        {
+            device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_DONE_PENDING, 1, 1);
+        }
+        else
+        {
+            // arm_net_phy_tx_done(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 1, 1);
+            device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_DONE, 1, 1);
+        }
+    }
+    else
+    {
+        device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 1, 1);
+    }
+}
+
+/*
+ * \brief Function is a call back for CCA ED done interrupt.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_handle_cca_ed_done(void)
+{
+    /*Check the result of CCA process*/
+    if( !(mStatusAndControlRegs[IRQSTS2] & cIRQSTS2_CCA) )
+    {
+        rf_start_tx();
+    }
+    else if (device_driver.phy_tx_done_cb)
+    {
+        /*Send CCA fail notification*/
+        device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 1, 1);
+    }
+}
+
+/*
+ * \brief Function sets the TX power variable.
+ *
+ * \param power TX power setting
+ *
+ * \return 0 Success
+ * \return -1 Fail
+ */
+static int8_t rf_tx_power_set(uint8_t power)
+{
+    /* gcapraru: Map MCR20A Tx power levels over ATMEL values */
+    static uint8_t pwrLevelMapping[16] = {25,25,25,24,24,24,23,23,22,22,21,20,19,18,17,14};
+
+    if( power > 15 )
+    {
+        return -1;
+    }
+
+    radio_tx_power = power;
+    MCR20Drv_DirectAccessSPIWrite(PA_PWR, pwrLevelMapping[power]);
+    return 0;
+}
+
+/*
+ * \brief Function returns the TX power variable.
+ *
+ * \param none
+ *
+ * \return radio_tx_power TX power variable
+ */
+static uint8_t rf_tx_power_get(void)
+{
+    return radio_tx_power;
+}
+
+/*
+ * \brief Function enables the usage of Antenna diversity.
+ *
+ * \param none
+ *
+ * \return 0 Success
+ */
+static int8_t rf_enable_antenna_diversity(void)
+{
+    uint8_t phyReg;
+
+    phyReg = MCR20Drv_IndirectAccessSPIRead(ANT_AGC_CTRL);
+    phyReg |= cANT_AGC_CTRL_FAD_EN_Mask_c;
+    MCR20Drv_IndirectAccessSPIWrite(ANT_AGC_CTRL, phyReg);
+
+    phyReg = MCR20Drv_IndirectAccessSPIRead(ANT_PAD_CTRL);
+    phyReg |= 0x02;
+    MCR20Drv_IndirectAccessSPIWrite(ANT_PAD_CTRL, phyReg);
+
+    return 0;
+}
+
+/*
+ * \brief Function gives the control of RF states to MAC.
+ *
+ * \param new_state RF state
+ * \param rf_channel RF channel
+ *
+ * \return 0 Success
+ */
+static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel)
+{
+    int8_t ret_val = 0;
+    switch (new_state)
+    {
+        /*Reset PHY driver and set to idle*/
+        case PHY_INTERFACE_RESET:
+            break;
+        /*Disable PHY Interface driver*/
+        case PHY_INTERFACE_DOWN:
+            rf_shutdown();
+            break;
+        /*Enable PHY Interface driver*/
+        case PHY_INTERFACE_UP:
+            rf_channel_set(rf_channel);
+            rf_receive();
+            break;
+        /*Enable wireless interface ED scan mode*/
+        case PHY_INTERFACE_RX_ENERGY_STATE:
+            rf_abort();
+            rf_channel_set(rf_channel);
+            break;
+        case PHY_INTERFACE_SNIFFER_STATE:             /**< Enable Sniffer state */
+            rf_promiscuous(1);
+            rf_channel_set(rf_channel);
+            rf_receive();
+            break;
+    }
+    return ret_val;
+}
+
+/*
+ * \brief Function controls the ACK pending, channel setting and energy detection.
+ *
+ * \param extension_type Type of control
+ * \param data_ptr Data from NET library
+ *
+ * \return 0 Success
+ */
+static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr)
+{
+    switch (extension_type)
+    {
+        /*Control MAC pending bit for Indirect data transmission*/
+        case PHY_EXTENSION_CTRL_PENDING_BIT:
+        {
+            uint8_t reg = MCR20Drv_DirectAccessSPIRead(SRC_CTRL);
+
+            if(*data_ptr)
+            {
+                reg |= cSRC_CTRL_ACK_FRM_PND;
+            }
+            else
+            {
+                reg &= ~cSRC_CTRL_ACK_FRM_PND;
+            }
+
+            MCR20Drv_DirectAccessSPIWrite(SRC_CTRL, reg);
+            break;
+
+        }
+        /*Return frame Auto Ack frame pending status*/
+        case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS: {
+            uint8_t reg = MCR20Drv_DirectAccessSPIRead(SRC_CTRL);
+            if (reg & cSRC_CTRL_ACK_FRM_PND) {
+                *data_ptr = 1;
+            } else {
+                *data_ptr  = 0;
+            }
+            break;
+        }
+        /*Set channel*/
+        case PHY_EXTENSION_SET_CHANNEL:
+            break;
+        /*Read energy on the channel*/
+        case PHY_EXTENSION_READ_CHANNEL_ENERGY:
+            *data_ptr = rf_get_channel_energy();
+            break;
+        /*Read status of the link*/
+        case PHY_EXTENSION_READ_LINK_STATUS:
+            break;
+        case PHY_EXTENSION_CONVERT_SIGNAL_INFO:
+            break;
+        case PHY_EXTENSION_ACCEPT_ANY_BEACON:
+            break;
+    }
+    return 0;
+}
+
+/*
+ * \brief Function sets the addresses to RF address filters.
+ *
+ * \param address_type Type of address
+ * \param address_ptr Pointer to given address
+ *
+ * \return 0 Success
+ */
+static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr)
+{
+    int8_t ret_val = 0;
+    switch (address_type)
+    {
+        /*Set 48-bit address*/
+        case PHY_MAC_48BIT:
+            break;
+            /*Set 64-bit address*/
+        case PHY_MAC_64BIT:
+            rf_set_address(address_ptr);
+            break;
+        /*Set 16-bit address*/
+        case PHY_MAC_16BIT:
+            rf_set_short_adr(address_ptr);
+            break;
+        /*Set PAN Id*/
+        case PHY_MAC_PANID:
+            rf_set_pan_id(address_ptr);
+            break;
+    }
+    return ret_val;
+}
+
+/*
+ * \brief Function initialises the ACK wait time and returns the used PHY mode.
+ *
+ * \param none
+ *
+ * \return tmp Used PHY mode
+ */
+static void rf_init_phy_mode(void)
+{
+}
+
+/*
+ * \brief Function is a RF interrupt vector. End of frame in RX and TX are handled here as well as CCA process interrupt.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void PHY_InterruptHandler(void)
+{
+    MCR20Drv_IRQ_Disable();
+    irq_thread->signal_set(1);
+}
+
+static void PHY_InterruptThread(void)
+{
+    for (;;) {
+        osEvent event = irq_thread->signal_wait(0);
+        if (event.status != osEventSignal) {
+            continue;
+        }
+        handle_interrupt();
+        MCR20Drv_IRQ_Enable();
+    }
+}
+
+static void handle_interrupt(void)
+{
+    uint8_t xcvseqCopy;
+
+    /* Read transceiver interrupt status and control registers */
+    mStatusAndControlRegs[IRQSTS1] =
+        MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &mStatusAndControlRegs[IRQSTS2], 7);
+
+    xcvseqCopy = mStatusAndControlRegs[PHY_CTRL1] & cPHY_CTRL1_XCVSEQ;
+
+    /* Flter Fail IRQ */
+    if( (mStatusAndControlRegs[IRQSTS1] & cIRQSTS1_FILTERFAIL_IRQ) &&
+       !(mStatusAndControlRegs[PHY_CTRL2] & cPHY_CTRL2_FILTERFAIL_MSK) )
+    {
+        if( xcvseqCopy == gRX_c )
+        {
+            /* Abort current SEQ */
+            mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ);
+            MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]);
+            /* Wait for Sequence Idle */
+            while ((MCR20Drv_DirectAccessSPIRead(SEQ_STATE) & 0x1F) != 0);
+            /* Clear IRQ flags: */
+            MCR20Drv_DirectAccessSPIWrite(IRQSTS1, cIRQSTS1_SEQIRQ);
+            /* Restart Rx asap */
+            mStatusAndControlRegs[PHY_CTRL1] |= gRX_c;
+            MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]);
+        }
+    }
+
+    /* TMR3 IRQ: ACK wait time-out */
+    if( (mStatusAndControlRegs[IRQSTS3] & cIRQSTS3_TMR3IRQ) &&
+       !(mStatusAndControlRegs[IRQSTS3] & cIRQSTS3_TMR3MSK) )
+    {
+        /* Disable TMR3 IRQ */
+        mStatusAndControlRegs[IRQSTS3] |= cIRQSTS3_TMR3MSK;
+
+        if( xcvseqCopy == gTR_c )
+        {
+            /* Set XCVR to Idle */
+            mPhySeqState = gIdle_c;
+            mStatusAndControlRegs[PHY_CTRL1] &=  ~( cPHY_CTRL1_XCVSEQ );
+            /* Mask interrupts */
+            mStatusAndControlRegs[PHY_CTRL2] |= cPHY_CTRL2_CCAMSK | cPHY_CTRL2_RXMSK | cPHY_CTRL2_TXMSK | cPHY_CTRL2_SEQMSK;
+            /* Sync settings with XCVR */
+            MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 5);
+
+            rf_ack_wait_timer_interrupt();
+            return;
+        }
+    }
+
+    /* Sequencer interrupt, the autosequence has completed */
+    if( (mStatusAndControlRegs[IRQSTS1] & cIRQSTS1_SEQIRQ) &&
+       !(mStatusAndControlRegs[PHY_CTRL2] & cPHY_CTRL2_SEQMSK) )
+    {
+        /* Set XCVR to Idle */
+        mPhySeqState = gIdle_c;
+        mStatusAndControlRegs[PHY_CTRL1] &=  ~( cPHY_CTRL1_XCVSEQ );
+        /* Mask interrupts */
+        mStatusAndControlRegs[PHY_CTRL2] |= cPHY_CTRL2_CCAMSK | cPHY_CTRL2_RXMSK | cPHY_CTRL2_TXMSK | cPHY_CTRL2_SEQMSK;
+        /* Sync settings with XCVR */
+        MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 5);
+
+        /* PLL unlock, the autosequence has been aborted due to PLL unlock */
+        if( mStatusAndControlRegs[IRQSTS1] & cIRQSTS1_PLL_UNLOCK_IRQ )
+        {
+            if(xcvseqCopy == gRX_c)
+            {
+                rf_receive();
+            }
+            return;
+        }
+
+        switch(xcvseqCopy)
+        {
+        case gTX_c:
+        case gTR_c:
+            rf_handle_tx_end();
+            break;
+
+        case gRX_c:
+            rf_handle_rx_end();
+            break;
+
+        case gCCA_c:
+            rf_handle_cca_ed_done();
+            break;
+
+        default:
+            break;
+        }
+
+        return;
+    }
+    /* Other IRQ. Clear XCVR interrupt flags */
+    MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 3);
+}
+
+/*
+ * \brief Function forces the XCVR to Idle state.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_abort(void)
+{
+    /* Mask XCVR irq */
+    MCR20Drv_IRQ_Disable();
+
+    mPhySeqState = gIdle_c;
+
+    mStatusAndControlRegs[IRQSTS1] = MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &mStatusAndControlRegs[IRQSTS2], 5);
+
+    /* Mask SEQ interrupt */
+    mStatusAndControlRegs[PHY_CTRL2] |= cPHY_CTRL2_SEQMSK;
+    MCR20Drv_DirectAccessSPIWrite(PHY_CTRL2, mStatusAndControlRegs[PHY_CTRL2]);
+
+    if( (mStatusAndControlRegs[PHY_CTRL1] & cPHY_CTRL1_XCVSEQ) != gIdle_c )
+    {
+        /* Abort current SEQ */
+        mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ);
+        MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]);
+
+        /* Wait for Sequence Idle (if not already) */
+        while ((MCR20Drv_DirectAccessSPIRead(SEQ_STATE) & 0x1F) != 0);
+        //while ( !(MCR20Drv_DirectAccessSPIRead(IRQSTS1) & cIRQSTS1_SEQIRQ));
+        mStatusAndControlRegs[IRQSTS1] |= cIRQSTS1_SEQIRQ;
+    }
+
+    /* Clear all PP IRQ bits to avoid unexpected interrupts and mask TMR3 interrupt.
+       Do not change TMR IRQ status. */
+    mStatusAndControlRegs[IRQSTS3] &= 0xF0;
+    mStatusAndControlRegs[IRQSTS3] |= (cIRQSTS3_TMR3MSK | cIRQSTS3_TMR3IRQ);
+    MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 3);
+
+    /* Unmask XCVR irq */
+    MCR20Drv_IRQ_Enable();
+}
+
+/*
+ * \brief Function reads a time-stamp value from XCVR [symbols]
+ *
+ * \param pEndTime pointer to location where time-stamp will be stored
+ *
+ * \return none
+ */
+static void rf_get_timestamp(uint32_t *pRetClk)
+{
+    if(NULL == pRetClk)
+    {
+        return;
+    }
+
+    platform_enter_critical();
+
+    *pRetClk = 0;
+    MCR20Drv_DirectAccessSPIMultiByteRead(EVENT_TMR_LSB, (uint8_t *) pRetClk, 3);
+
+    platform_exit_critical();
+}
+
+/*
+ * \brief Function set a time-out to an XCVR sequence.
+ *
+ * \param pEndTime pointer to the sequence time-out value [symbols]
+ *
+ * \return none
+ */
+static void rf_set_timeout(uint32_t *pEndTime)
+{
+    uint8_t phyReg;
+
+    if(NULL == pEndTime)
+    {
+        return;
+    }
+
+    platform_enter_critical();
+
+    phyReg = MCR20Drv_DirectAccessSPIRead(IRQSTS3);
+    phyReg &= 0xF0;                    /* do not change IRQ status */
+    phyReg |= (cIRQSTS3_TMR3MSK);      /* mask TMR3 interrupt */
+    MCR20Drv_DirectAccessSPIWrite(IRQSTS3, phyReg);
+
+    MCR20Drv_DirectAccessSPIMultiByteWrite(T3CMP_LSB, (uint8_t *) pEndTime, 3);
+
+    phyReg &= ~(cIRQSTS3_TMR3MSK);      /* unmask TMR3 interrupt */
+    phyReg |= (cIRQSTS3_TMR3IRQ);       /* aknowledge TMR3 IRQ */
+    MCR20Drv_DirectAccessSPIWrite(IRQSTS3, phyReg);
+
+    platform_exit_critical();
+}
+
+/*
+ * \brief Function reads a random number from RF.
+ *
+ * \param none
+ *
+ * \return 8-bit random number
+ */
+static uint8_t rf_if_read_rnd(void)
+{
+    uint8_t phyReg;
+
+    MCR20Drv_IRQ_Disable();
+    /* Check if XCVR is idle */
+    phyReg = MCR20Drv_DirectAccessSPIRead(PHY_CTRL1);
+
+    if( (phyReg & cPHY_CTRL1_XCVSEQ) == gIdle_c )
+    {
+        /* Program a new sequence */
+        MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, phyReg | gCCA_c);
+        /* Wait for sequence to finish */
+        while( !(MCR20Drv_DirectAccessSPIRead(IRQSTS1) & cIRQSTS1_SEQIRQ) );
+        /* Clear interrupt flag */
+        MCR20Drv_DirectAccessSPIWrite(IRQSTS1, cIRQSTS1_SEQIRQ);
+    }
+
+    MCR20Drv_IRQ_Enable();
+
+    return MCR20Drv_IndirectAccessSPIRead(_RNG);
+}
+
+/*
+ * \brief Function converts LQI into RSSI.
+ *
+ * \param LQI
+ *
+ * \return RSSI
+ */
+static int8_t rf_convert_LQI_to_RSSI(uint8_t lqi)
+{
+    int32_t rssi = (50*lqi - 16820) / 163;
+    return (int8_t)rssi;
+}
+
+/*
+ * \brief Function scale the LQI value reported by RF into a 0-255 value.
+ *
+ * \param hwLqi - the LQI value reported by RF
+ *
+ * \return scaled LQI
+ */
+static uint8_t rf_convert_LQI(uint8_t hwLqi)
+{
+    uint32_t tmpLQI;
+
+    /* LQI Saturation Level */
+    if (hwLqi >= 230)
+    {
+        return 0xFF;
+    }
+    else if (hwLqi <= 9)
+    {
+        return 0;
+    }
+    else
+    {
+        /* Rescale the LQI values from min to saturation to the 0x00 - 0xFF range */
+        /* The LQI value mst be multiplied by ~1.1087 */
+        /* tmpLQI =  hwLqi * 7123 ~= hwLqi * 65536 * 0.1087 = hwLqi * 2^16 * 0.1087*/
+        tmpLQI = ((uint32_t)hwLqi * (uint32_t)7123 );
+        /* tmpLQI =  (tmpLQI / 2^16) + hwLqi */
+        tmpLQI = (uint32_t)(tmpLQI >> 16) + (uint32_t)hwLqi;
+
+        return (uint8_t)tmpLQI;
+    }
+}
+
+/*
+ * \brief Function enables/disables Rx promiscuous mode.
+ *
+ * \param state of XCVR promiscuous mode
+ *
+ * \return none
+ */
+static void rf_promiscuous(uint8_t state)
+{
+    uint8_t rxFrameFltReg, phyCtrl4Reg;
+
+    rxFrameFltReg = MCR20Drv_IndirectAccessSPIRead(RX_FRAME_FILTER);
+    phyCtrl4Reg = MCR20Drv_DirectAccessSPIRead(PHY_CTRL4);
+
+    if( state )
+    {
+        /* FRM_VER[1:0] = b00. 00: Any FrameVersion accepted (0,1,2 & 3) */
+        /* All frame types accepted*/
+        phyCtrl4Reg   |= cPHY_CTRL4_PROMISCUOUS;
+        rxFrameFltReg &= ~(cRX_FRAME_FLT_FRM_VER);
+        rxFrameFltReg |=  (cRX_FRAME_FLT_ACK_FT | cRX_FRAME_FLT_NS_FT);
+    }
+    else
+    {
+        phyCtrl4Reg   &= ~cPHY_CTRL4_PROMISCUOUS;
+        /* FRM_VER[1:0] = b11. Accept FrameVersion 0 and 1 packets, reject all others */
+        /* Beacon, Data and MAC command frame types accepted */
+        rxFrameFltReg &= ~(cRX_FRAME_FLT_FRM_VER);
+        rxFrameFltReg |= (0x03 << cRX_FRAME_FLT_FRM_VER_Shift_c);
+        rxFrameFltReg &= ~(cRX_FRAME_FLT_ACK_FT | cRX_FRAME_FLT_NS_FT);
+    }
+
+    MCR20Drv_IndirectAccessSPIWrite(RX_FRAME_FILTER, rxFrameFltReg);
+    MCR20Drv_DirectAccessSPIWrite(PHY_CTRL4, phyCtrl4Reg);
+}
+
+/*
+ * \brief Function used to switch XCVR power state.
+ *
+ * \param state The XCVR power mode
+ *
+ * \return none
+ */
+static void rf_set_power_state(xcvrPwrMode_t newState)
+{
+    uint8_t pwrMode;
+    uint8_t xtalState;
+
+    if( mPwrState == newState )
+    {
+        return;
+    }
+
+    /* Read power settings from RF */
+    pwrMode = MCR20Drv_DirectAccessSPIRead(PWR_MODES);
+    xtalState = pwrMode & cPWR_MODES_XTALEN;
+
+    switch( newState )
+    {
+    case gXcvrPwrIdle_c:
+        pwrMode &= ~(cPWR_MODES_AUTODOZE);
+        pwrMode |= (cPWR_MODES_XTALEN | cPWR_MODES_PMC_MODE);
+        break;
+    case gXcvrPwrAutodoze_c:
+        pwrMode |= (cPWR_MODES_XTALEN | cPWR_MODES_AUTODOZE | cPWR_MODES_PMC_MODE);
+        break;
+    case gXcvrPwrDoze_c:
+        pwrMode &= ~(cPWR_MODES_AUTODOZE | cPWR_MODES_PMC_MODE);
+        pwrMode |= cPWR_MODES_XTALEN;
+        break;
+    case gXcvrPwrHibernate_c:
+        pwrMode &= ~(cPWR_MODES_XTALEN | cPWR_MODES_AUTODOZE | cPWR_MODES_PMC_MODE);
+        break;
+    default:
+        return;
+    }
+
+    mPwrState = newState;
+    MCR20Drv_DirectAccessSPIWrite(PWR_MODES, pwrMode);
+
+    if( !xtalState && (pwrMode & cPWR_MODES_XTALEN))
+    {
+        /* wait for crystal oscillator to complet its warmup */
+        while( ( MCR20Drv_DirectAccessSPIRead(PWR_MODES) & cPWR_MODES_XTAL_READY ) != cPWR_MODES_XTAL_READY);
+        /* wait for radio wakeup from hibernate interrupt */
+        while( ( MCR20Drv_DirectAccessSPIRead(IRQSTS2) & (cIRQSTS2_WAKE_IRQ | cIRQSTS2_TMRSTATUS) ) != (cIRQSTS2_WAKE_IRQ | cIRQSTS2_TMRSTATUS) );
+
+        MCR20Drv_DirectAccessSPIWrite(IRQSTS2, cIRQSTS2_WAKE_IRQ);
+    }
+}
+
+/*
+ * \brief Function reads the energy level on the preselected channel.
+ *
+ * \return energy level
+ */
+static uint8_t rf_get_channel_energy(void)
+{
+    uint8_t ccaMode;
+
+    MCR20Drv_IRQ_Disable();
+    /* RX can start only from Idle state */
+    if( mPhySeqState != gIdle_c )
+    {
+        MCR20Drv_IRQ_Enable();
+        return 0;
+    }
+
+    /* Set XCVR power state in run mode */
+    rf_set_power_state(gXcvrRunState_d);
+
+    /* Switch to ED mode */
+    ccaMode = (mStatusAndControlRegs[PHY_CTRL4] >> cPHY_CTRL4_CCATYPE_Shift_c) & cPHY_CTRL4_CCATYPE;
+    if( ccaMode != gCcaED_c )
+    {
+        mStatusAndControlRegs[PHY_CTRL4] &= ~(cPHY_CTRL4_CCATYPE << cPHY_CTRL4_CCATYPE_Shift_c);
+        mStatusAndControlRegs[PHY_CTRL4] |= gCcaED_c << cPHY_CTRL4_CCATYPE_Shift_c;
+        MCR20Drv_DirectAccessSPIWrite(PHY_CTRL4, mStatusAndControlRegs[PHY_CTRL4]);
+    }
+
+    /* Start ED sequence */
+    mStatusAndControlRegs[PHY_CTRL1] |= gCCA_c;
+    MCR20Drv_DirectAccessSPIWrite(IRQSTS1, cIRQSTS1_CCAIRQ | cIRQSTS1_SEQIRQ);
+    MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]);
+    /* Wait for sequence to finish */
+    while ( !(MCR20Drv_DirectAccessSPIRead(IRQSTS1) & cIRQSTS1_SEQIRQ));
+    /* Set XCVR to Idle */
+    mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ);
+    MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]);
+    MCR20Drv_DirectAccessSPIWrite(IRQSTS1, cIRQSTS1_CCAIRQ | cIRQSTS1_SEQIRQ);
+
+    MCR20Drv_IRQ_Enable();
+
+    return rf_convert_energy_level(MCR20Drv_DirectAccessSPIRead(CCA1_ED_FNL));
+}
+
+/*
+ * \brief Function converts the energy level from dBm to a 0-255 value.
+ *
+ * \param energyLevel in dBm
+ *
+ * \return energy level (0-255)
+ */
+static uint8_t rf_convert_energy_level(uint8_t energyLevel)
+{
+    if(energyLevel >= 90)
+    {
+        /* ED value is below minimum. Return 0x00. */
+        energyLevel = 0x00;
+    }
+    else if(energyLevel <= 26)
+    {
+        /* ED value is above maximum. Return 0xFF. */
+        energyLevel = 0xFF;
+    }
+    else
+    {
+        /* Energy level (-90 dBm to -26 dBm ) --> varies form 0 to 64 */
+        energyLevel = (90 - energyLevel);
+        /* Rescale the energy level values to the 0x00-0xff range (0 to 64 translates in 0 to 255) */
+        /* energyLevel * 3.9844 ~= 4 */
+        /* Multiply with 4=2^2 by shifting left.
+        The multiplication will not overflow beacause energyLevel has values between 0 and 63 */
+        energyLevel <<= 2;
+    }
+
+    return energyLevel;
+}
+
+static uint8_t rf_scale_lqi(int8_t rssi)
+{
+    uint8_t scaled_lqi;
+    /*Worst case sensitivity*/
+    const int8_t rf_sensitivity = -98;
+
+    /*rssi < RF sensitivity*/
+    if(rssi < rf_sensitivity)
+        scaled_lqi=0;
+    /*-91 dBm < rssi < -81 dBm (AT86RF233 XPro)*/
+    /*-90 dBm < rssi < -80 dBm (AT86RF212B XPro)*/
+    else if(rssi < (rf_sensitivity + 10))
+        scaled_lqi=31;
+    /*-81 dBm < rssi < -71 dBm (AT86RF233 XPro)*/
+    /*-80 dBm < rssi < -70 dBm (AT86RF212B XPro)*/
+    else if(rssi < (rf_sensitivity + 20))
+        scaled_lqi=207;
+    /*-71 dBm < rssi < -61 dBm (AT86RF233 XPro)*/
+    /*-70 dBm < rssi < -60 dBm (AT86RF212B XPro)*/
+    else if(rssi < (rf_sensitivity + 30))
+        scaled_lqi=255;
+    /*-61 dBm < rssi < -51 dBm (AT86RF233 XPro)*/
+    /*-60 dBm < rssi < -50 dBm (AT86RF212B XPro)*/
+    else if(rssi < (rf_sensitivity + 40))
+        scaled_lqi=255;
+    /*-51 dBm < rssi < -41 dBm (AT86RF233 XPro)*/
+    /*-50 dBm < rssi < -40 dBm (AT86RF212B XPro)*/
+    else if(rssi < (rf_sensitivity + 50))
+        scaled_lqi=255;
+    /*-41 dBm < rssi < -31 dBm (AT86RF233 XPro)*/
+    /*-40 dBm < rssi < -30 dBm (AT86RF212B XPro)*/
+    else if(rssi < (rf_sensitivity + 60))
+        scaled_lqi=255;
+    /*-31 dBm < rssi < -21 dBm (AT86RF233 XPro)*/
+    /*-30 dBm < rssi < -20 dBm (AT86RF212B XPro)*/
+    else if(rssi < (rf_sensitivity + 70))
+        scaled_lqi=255;
+    /*rssi > RF saturation*/
+    else if(rssi > (rf_sensitivity + 80))
+        scaled_lqi=111;
+    /*-21 dBm < rssi < -11 dBm (AT86RF233 XPro)*/
+    /*-20 dBm < rssi < -10 dBm (AT86RF212B XPro)*/
+    else
+        scaled_lqi=255;
+
+    return scaled_lqi;
+}
+
+
+/*****************************************************************************/
+/*              Layer porting to the Freescale driver                        */
+/*****************************************************************************/
+extern "C" void xcvr_spi_init(uint32_t instance)
+{
+    (void)instance;
+}
+
+extern "C" void RF_IRQ_Init(void) {
+    MBED_ASSERT(irq != NULL);
+    irq->mode(PullUp);
+    irq->fall(&PHY_InterruptHandler);
+}
+
+extern "C" void RF_IRQ_Enable(void) {
+    MBED_ASSERT(irq != NULL);
+    irq->enable_irq();
+}
+
+extern "C" void RF_IRQ_Disable(void) {
+    MBED_ASSERT(irq != NULL);
+    irq->disable_irq();
+}
+
+extern "C" uint8_t RF_isIRQ_Pending(void) {
+    MBED_ASSERT(rf != NULL);
+    return !irq_pin->read();
+}
+
+extern "C" void RF_RST_Set(int state) {
+    MBED_ASSERT(rst != NULL);
+    *rst = state;
+}
+
+extern "C" void gXcvrAssertCS_d(void)
+{
+    MBED_ASSERT(cs != NULL);
+    *cs = 0;
+}
+
+extern "C" void gXcvrDeassertCS_d(void)
+{
+    MBED_ASSERT(cs != NULL);
+    *cs = 1;
+}
+
+extern "C" void xcvr_spi_configure_speed(uint32_t instance, uint32_t freq)
+{
+    MBED_ASSERT(spi != NULL);
+    (void)instance;
+    spi->frequency(freq);
+}
+
+extern "C" void xcvr_spi_transfer(uint32_t instance,
+                         uint8_t * sendBuffer,
+                         uint8_t * receiveBuffer,
+                         size_t transferByteCount)
+{
+    MBED_ASSERT(spi != NULL);
+    (void)instance;
+    volatile uint8_t dummy;
+
+    if( !transferByteCount )
+        return;
+
+    if( !sendBuffer && !receiveBuffer )
+        return;
+
+    while( transferByteCount-- )
+    {
+        if( sendBuffer )
+        {
+            dummy = *sendBuffer;
+            sendBuffer++;
+        }
+        else
+        {
+            dummy = 0xFF;
+        }
+
+        dummy = spi->write(dummy);
+
+        if( receiveBuffer )
+        {
+            *receiveBuffer = dummy;
+            receiveBuffer++;
+        }
+    }
+}
+
+/*****************************************************************************/
+/*****************************************************************************/
+
+static void rf_if_lock(void)
+{
+    platform_enter_critical();
+}
+
+static void rf_if_unlock(void)
+{
+    platform_exit_critical();
+}
+
+NanostackRfPhyMcr20a::NanostackRfPhyMcr20a(PinName spi_mosi, PinName spi_miso,
+        PinName spi_sclk, PinName spi_cs,  PinName spi_rst, PinName spi_irq)
+    : _spi(spi_mosi, spi_miso, spi_sclk), _rf_cs(spi_cs), _rf_rst(spi_rst, 1),
+      _rf_irq(spi_irq), _rf_irq_pin(spi_irq),
+      _irq_thread(osPriorityRealtime, 1024)
+{
+    char mac48[6];
+    mbed_mac_address(mac48);
+
+    MAC_address[0] = mac48[0];
+    MAC_address[1] = mac48[1];
+    MAC_address[2] = mac48[2];
+    MAC_address[3] = 0xFF;
+    MAC_address[4] = 0xFF;
+    MAC_address[5] = mac48[3];
+    MAC_address[6] = mac48[4];
+    MAC_address[7] = mac48[5];
+}
+
+NanostackRfPhyMcr20a::~NanostackRfPhyMcr20a()
+{
+    // Do nothing
+}
+
+int8_t NanostackRfPhyMcr20a::rf_register()
+{
+
+    rf_if_lock();
+
+    if (rf != NULL) {
+        rf_if_unlock();
+        error("Multiple registrations of NanostackRfPhyMcr20a not supported");
+        return -1;
+    }
+
+    _irq_thread.start(mbed::callback(PHY_InterruptThread));
+
+    _pins_set();
+    int8_t radio_id = rf_device_register();
+    if (radio_id < 0) {
+        _pins_clear();
+        rf = NULL;
+    }
+
+    rf_if_unlock();
+    return radio_id;
+}
+
+void NanostackRfPhyMcr20a::rf_unregister()
+{
+    rf_if_lock();
+
+    if (rf != this) {
+        rf_if_unlock();
+        return;
+    }
+
+    rf_device_unregister();
+    rf = NULL;
+    _pins_clear();
+
+    rf_if_unlock();
+}
+
+void NanostackRfPhyMcr20a::get_mac_address(uint8_t *mac)
+{
+    rf_if_lock();
+
+    memcpy((void*)mac, (void*)MAC_address, sizeof(MAC_address));
+
+    rf_if_unlock();
+}
+
+void NanostackRfPhyMcr20a::set_mac_address(uint8_t *mac)
+{
+    rf_if_lock();
+
+    if (NULL != rf) {
+        error("NanostackRfPhyAtmel cannot change mac address when running");
+        rf_if_unlock();
+        return;
+    }
+    memcpy((void*)MAC_address, (void*)mac, sizeof(MAC_address));
+
+    rf_if_unlock();
+}
+
+void NanostackRfPhyMcr20a::_pins_set()
+{
+    spi = &_spi;
+    cs = &_rf_cs;
+    rst = &_rf_rst;
+    irq = &_rf_irq;
+    irq_pin = &_rf_irq_pin;
+    irq_thread = &_irq_thread;
+}
+
+void NanostackRfPhyMcr20a::_pins_clear()
+{
+    spi = NULL;
+    cs = NULL;
+    rst = NULL;
+    irq = NULL;
+    irq_pin = NULL;
+    irq_thread = NULL;
+}
+
+#if MBED_CONF_MCR20A_PROVIDE_DEFAULT || TARGET_KW24D
+
+NanostackRfPhy &NanostackRfPhy::get_default_instance()
+{
+    static NanostackRfPhyMcr20a rf_phy(MCR20A_SPI_MOSI, MCR20A_SPI_MISO, MCR20A_SPI_SCLK, MCR20A_SPI_CS, MCR20A_SPI_RST, MCR20A_SPI_IRQ);
+    return rf_phy;
+}
+
+#endif // MBED_CONF_MCR20A_PROVIDE_DEFAULT
+
+#endif // MBED_CONF_NANOSTACK_CONFIGURATION
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/mcr20a-rf-driver/source/XcvrSpi.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,89 @@
+/*!
+* Copyright (c) 2015, Freescale Semiconductor, Inc.
+* All rights reserved.
+*
+* \file XcvrSpi.h
+*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+*
+* o Redistributions of source code must retain the above copyright notice, this list
+*   of conditions and the following disclaimer.
+*
+* o Redistributions in binary form must reproduce the above copyright notice, this
+*   list of conditions and the following disclaimer in the documentation and/or
+*   other materials provided with the distribution.
+*
+* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
+*   contributors may be used to endorse or promote products derived from this
+*   software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __XCVR_SPI_H__
+#define __XCVR_SPI_H__
+
+
+/*****************************************************************************
+ *                               INCLUDED HEADERS                            *
+ *---------------------------------------------------------------------------*
+ * Add to this section all the headers that this module needs to include.    *
+ * Note that it is not a good practice to include header files into header   *
+ * files, so use this section only if there is no other better solution.     *
+ *---------------------------------------------------------------------------*
+ *****************************************************************************/
+ 
+
+/*****************************************************************************
+ *                             PUBLIC MACROS                                 *
+ *---------------------------------------------------------------------------*
+ * Add to this section all the access macros, registers mappings, bit access *
+ * macros, masks, flags etc ...
+ *---------------------------------------------------------------------------*
+ *****************************************************************************/
+#define gXcvrSpiInstance_c              0
+
+/*****************************************************************************
+ *                            PUBLIC FUNCTIONS                               *
+ *---------------------------------------------------------------------------*
+ * Add to this section all the global functions prototype preceded (as a     *
+ * good practice) by the keyword 'extern'                                    *
+ *---------------------------------------------------------------------------*
+ *****************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus */
+
+void RF_RST_Set(int state);
+void RF_CS_Set(int state);
+void RF_IRQ_Init(void);
+void RF_IRQ_Disable(void);
+void RF_IRQ_Enable(void);
+uint8_t RF_isIRQ_Pending(void);
+
+void gXcvrAssertCS_d(void);
+void gXcvrDeassertCS_d(void);
+
+void xcvr_spi_init(uint32_t instance);
+void xcvr_spi_configure_speed(uint32_t instance, uint32_t freq);
+void xcvr_spi_transfer(uint32_t instance,
+                         uint8_t * sendBuffer,
+                         uint8_t * receiveBuffer,
+                         uint32_t transferByteCount);
+                         
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus */
+
+#endif /* __XCVR_SPI_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/stm-s2lp-rf-driver/README.md	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,6 @@
+# Example RF driver for STM 802.15.4 transceivers #
+
+Support for:
+ * S2-LP
+
+This driver is used with 6LoWPAN and Wi-SUN stacks.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/stm-s2lp-rf-driver/mbed_lib.json	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,9 @@
+{
+    "name": "s2lp",
+    "config": {
+        "provide-default": {
+            "help": "Provide default NanostackRfpy. [true/false]",
+            "value": false
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/stm-s2lp-rf-driver/source/NanostackRfPhys2lp.cpp	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,1376 @@
+/*
+ * 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 <string.h>
+#if defined(MBED_CONF_NANOSTACK_CONFIGURATION) && DEVICE_SPI
+#include "platform/arm_hal_interrupt.h"
+#include "nanostack/platform/arm_hal_phy.h"
+#include "ns_types.h"
+#include "NanostackRfPhys2lp.h"
+#include "s2lpReg.h"
+#include "rf_configuration.h"
+#include "randLIB.h"
+#include "mbed_trace.h"
+#include "mbed_toolchain.h"
+#include "common_functions.h"
+#include <Timer.h>
+
+#define TRACE_GROUP "s2lp"
+
+#define INTERRUPT_GPIO  S2LP_GPIO3
+
+#if INTERRUPT_GPIO == S2LP_GPIO0
+#define INT_IN_GPIO     rf->RF_S2LP_GPIO0
+#elif INTERRUPT_GPIO == S2LP_GPIO1
+#define INT_IN_GPIO     rf->RF_S2LP_GPIO1
+#elif INTERRUPT_GPIO == S2LP_GPIO2
+#define INT_IN_GPIO     rf->RF_S2LP_GPIO2
+#else
+#define INT_IN_GPIO     rf->RF_S2LP_GPIO3
+#endif
+
+#ifdef TEST_GPIOS_ENABLED
+#define TEST_TX_STARTED     rf->TEST1 = 1;
+#define TEST_TX_DONE        rf->TEST1 = 0;
+#define TEST_RX_STARTED     rf->TEST2 = 1;
+#define TEST_RX_DONE        rf->TEST2 = 0;
+#define TEST_ACK_TX_STARTED rf->TEST3 = 1;
+#define TEST_ACK_TX_DONE    rf->TEST3 = 0;
+#define TEST1_ON            rf->TEST4 = 1;
+#define TEST1_OFF           rf->TEST4 = 0;
+#define TEST2_ON            rf->TEST5 = 1;
+#define TEST2_OFF           rf->TEST5 = 0;
+extern void (*fhss_uc_switch)(void);
+extern void (*fhss_bc_switch)(void);
+#else //TEST_GPIOS_ENABLED
+#define TEST_TX_STARTED
+#define TEST_TX_DONE
+#define TEST_RX_STARTED
+#define TEST_RX_DONE
+#define TEST_ACK_TX_STARTED
+#define TEST_ACK_TX_DONE
+#define TEST1_ON
+#define TEST1_OFF
+#define TEST2_ON
+#define TEST2_OFF
+#endif //TEST_GPIOS_ENABLED
+
+#define MAC_FRAME_TYPE_MASK     0x07
+#define MAC_FRAME_BEACON        (0)
+#define MAC_TYPE_DATA           (1)
+#define MAC_TYPE_ACK            (2)
+#define MAC_TYPE_COMMAND        (3)
+#define MAC_DATA_PENDING        0x10
+#define MAC_FRAME_VERSION_2     (2)
+#define FC_DST_MODE             0x0C
+#define FC_SRC_MODE             0xC0
+#define FC_DST_ADDR_NONE        0x00
+#define FC_DST_16_BITS          0x08
+#define FC_DST_64_BITS          0x0C
+#define FC_SRC_64_BITS          0xC0
+#define FC_SEQUENCE_COMPRESSION 0x01
+#define FC_AR                   0x20
+#define FC_PAN_ID_COMPRESSION   0x40
+#define VERSION_FIELD_MASK      0x30
+#define SHIFT_SEQ_COMP_FIELD    (0)
+#define SHIFT_VERSION_FIELD     (4)
+#define SHIFT_PANID_COMP_FIELD  (6)
+#define OFFSET_DST_PAN_ID       (3)
+#define OFFSET_DST_ADDR         (5)
+
+#define CS_SELECT()  {rf->CS = 0;}
+#define CS_RELEASE() {rf->CS = 1;}
+
+class UnlockedSPI : public SPI {
+public:
+    UnlockedSPI(PinName sdi, PinName sdo, PinName sclk) :
+        SPI(sdi, sdo, sclk) { }
+    virtual void lock() { }
+    virtual void unlock() { }
+};
+
+class RFPins {
+public:
+    RFPins(PinName spi_sdi, PinName spi_sdo,
+           PinName spi_sclk, PinName spi_cs, PinName spi_sdn,
+#ifdef TEST_GPIOS_ENABLED
+           PinName spi_test1, PinName spi_test2, PinName spi_test3, PinName spi_test4, PinName spi_test5,
+#endif //TEST_GPIOS_ENABLED
+           PinName spi_gpio0, PinName spi_gpio1, PinName spi_gpio2,
+           PinName spi_gpio3);
+    UnlockedSPI spi;
+    DigitalOut CS;
+    DigitalOut SDN;
+#ifdef TEST_GPIOS_ENABLED
+    DigitalOut TEST1;
+    DigitalOut TEST2;
+    DigitalOut TEST3;
+    DigitalOut TEST4;
+    DigitalOut TEST5;
+#endif //TEST_GPIOS_ENABLED
+    InterruptIn RF_S2LP_GPIO0;
+    InterruptIn RF_S2LP_GPIO1;
+    InterruptIn RF_S2LP_GPIO2;
+    InterruptIn RF_S2LP_GPIO3;
+    Timeout cca_timer;
+    Timeout backup_timer;
+    Timer tx_timer;
+#ifdef MBED_CONF_RTOS_PRESENT
+    Thread irq_thread;
+    Mutex mutex;
+    void rf_irq_task();
+#endif //MBED_CONF_RTOS_PRESENT
+};
+
+RFPins::RFPins(PinName spi_sdi, PinName spi_sdo,
+               PinName spi_sclk, PinName spi_cs, PinName spi_sdn,
+#ifdef TEST_GPIOS_ENABLED
+               PinName spi_test1, PinName spi_test2, PinName spi_test3, PinName spi_test4, PinName spi_test5,
+#endif //TEST_GPIOS_ENABLED
+               PinName spi_gpio0, PinName spi_gpio1, PinName spi_gpio2,
+               PinName spi_gpio3)
+    :   spi(spi_sdi, spi_sdo, spi_sclk),
+        CS(spi_cs),
+        SDN(spi_sdn),
+#ifdef TEST_GPIOS_ENABLED
+        TEST1(spi_test1),
+        TEST2(spi_test2),
+        TEST3(spi_test3),
+        TEST4(spi_test4),
+        TEST5(spi_test5),
+#endif //TEST_GPIOS_ENABLED
+        RF_S2LP_GPIO0(spi_gpio0),
+        RF_S2LP_GPIO1(spi_gpio1),
+        RF_S2LP_GPIO2(spi_gpio2),
+        RF_S2LP_GPIO3(spi_gpio3)
+#ifdef MBED_CONF_RTOS_PRESENT
+    , irq_thread(osPriorityRealtime, 1024)
+#endif //MBED_CONF_RTOS_PRESENT
+{
+#ifdef MBED_CONF_RTOS_PRESENT
+    irq_thread.start(mbed::callback(this, &RFPins::rf_irq_task));
+#endif //MBED_CONF_RTOS_PRESENT
+}
+
+static uint8_t rf_read_register_with_status(uint8_t addr, uint16_t *status_out);
+static s2lp_states_e rf_read_state(void);
+static void rf_write_register(uint8_t addr, uint8_t data);
+static void rf_print_registers(void);
+static void rf_interrupt_handler(void);
+static void rf_receive(uint8_t rx_channel);
+static void rf_cca_timer_stop(void);
+static void rf_backup_timer_start(uint32_t slots);
+static void rf_backup_timer_stop(void);
+static void rf_rx_ready_handler(void);
+static uint32_t read_irq_status(void);
+static bool rf_rx_filter(uint8_t *mac_header, uint8_t *mac_64bit_addr, uint8_t *mac_16bit_addr, uint8_t *pan_id);
+
+static RFPins *rf;
+static phy_device_driver_s device_driver;
+static int8_t rf_radio_driver_id = -1;
+static uint8_t *tx_data_ptr;
+static uint16_t tx_data_length;
+static uint16_t rx_data_length;
+static uint32_t enabled_interrupts;
+static uint8_t mac_tx_handle;
+static uint8_t rf_rx_channel;
+static uint8_t rf_new_channel;
+static uint8_t rx_buffer[RF_MTU];
+static rf_states_e rf_state = RF_IDLE;
+// This will be used when given channel spacing cannot be supported by transceiver
+static uint8_t rf_channel_multiplier = 1;
+static uint16_t tx_sequence = 0xffff;
+static uint32_t tx_time = 0;
+static uint32_t rx_time = 0;
+static uint32_t tx_finnish_time = 0;
+static uint32_t symbols_in_seconds;
+static bool cca_enabled = true;
+static uint8_t s2lp_PAN_ID[2] = {0xff, 0xff};
+static uint8_t s2lp_short_address[2];
+static uint8_t s2lp_MAC[8];
+
+/* Channel configurations for sub-GHz */
+static const phy_rf_channel_configuration_s phy_subghz = {868300000U, 500000U, 250000U, 11U, M_UNDEFINED};
+
+static const phy_device_channel_page_s phy_channel_pages[] = {
+    { CHANNEL_PAGE_2, &phy_subghz},
+    { CHANNEL_PAGE_0, NULL}
+};
+
+#ifdef MBED_CONF_RTOS_PRESENT
+#include "mbed.h"
+#include "rtos.h"
+
+static void rf_irq_task_process_irq();
+
+#define SIG_RADIO           1
+#define SIG_TIMER_CCA       2
+#define SIG_TIMER_BACKUP    4
+
+#endif //MBED_CONF_RTOS_PRESENT
+
+#define ACK_FRAME_LENGTH    3
+// Give some additional time for processing, PHY headers, CRC etc.
+#define PACKET_SENDING_EXTRA_TIME   10000
+#define MAX_PACKET_SENDING_TIME (uint32_t)(8000000/phy_subghz.datarate)*RF_MTU + PACKET_SENDING_EXTRA_TIME
+#define ACK_SENDING_TIME (uint32_t)(8000000/phy_subghz.datarate)*ACK_FRAME_LENGTH + PACKET_SENDING_EXTRA_TIME
+
+#ifdef TEST_GPIOS_ENABLED
+void test1_toggle(void)
+{
+    if (rf->TEST4) {
+        rf->TEST4 = 0;
+    } else {
+        rf->TEST4 = 1;
+    }
+}
+void test2_toggle(void)
+{
+    if (rf->TEST5) {
+        rf->TEST5 = 0;
+    } else {
+        rf->TEST5 = 1;
+    }
+}
+#endif //TEST_GPIOS_ENABLED
+
+static void rf_calculate_symbols_in_seconds(uint32_t baudrate, phy_modulation_e modulation)
+{
+    (void) modulation;
+    uint8_t bits_in_symbols = 1;
+    symbols_in_seconds = baudrate / bits_in_symbols;
+}
+
+static uint32_t rf_get_timestamp(void)
+{
+    return (uint32_t)rf->tx_timer.read_us();
+}
+
+static void rf_lock(void)
+{
+    platform_enter_critical();
+}
+
+static void rf_unlock(void)
+{
+    platform_exit_critical();
+}
+
+#ifdef MBED_CONF_RTOS_PRESENT
+static void rf_cca_timer_signal(void)
+{
+    rf->irq_thread.signal_set(SIG_TIMER_CCA);
+}
+
+static void rf_backup_timer_signal(void)
+{
+    rf->irq_thread.signal_set(SIG_TIMER_BACKUP);
+}
+#endif //MBED_CONF_RTOS_PRESENT
+
+/*
+ * \brief Function writes/read data in SPI interface
+ */
+static void rf_spi_exchange(const void *tx, size_t tx_len, void *rx, size_t rx_len)
+{
+    rf->spi.write(static_cast<const char *>(tx), tx_len, static_cast<char *>(rx), rx_len);
+}
+
+static uint8_t rf_read_register_with_status(uint8_t addr, uint16_t *status_out)
+{
+    const uint8_t tx[2] = {SPI_RD_REG, addr};
+    uint8_t rx[3];
+    rf_lock();
+    CS_SELECT();
+    rf_spi_exchange(tx, sizeof(tx), rx, sizeof(rx));
+    CS_RELEASE();
+    if (status_out) {
+        *status_out = (rx[0] << 8) | rx[1];
+    }
+    rf_unlock();
+    return rx[2];
+}
+
+static void rf_write_register(uint8_t addr, uint8_t data)
+{
+    const uint8_t tx[3] = {SPI_WR_REG, addr, data};
+    rf_lock();
+    CS_SELECT();
+    rf_spi_exchange(tx, sizeof(tx), NULL, 0);
+    CS_RELEASE();
+    rf_unlock();
+}
+
+static void rf_write_register_field(uint8_t addr, uint8_t field, uint8_t value)
+{
+    uint8_t reg_tmp = rf_read_register_with_status(addr, NULL);
+    reg_tmp &= ~field;
+    reg_tmp |= value;
+    rf_write_register(addr, reg_tmp);
+}
+
+static s2lp_states_e rf_read_state(void)
+{
+    return (s2lp_states_e)(rf_read_register_with_status(MC_STATE0, NULL) >> 1);
+}
+
+static void rf_poll_state_change(s2lp_states_e state)
+{
+    uint16_t break_counter = 0;
+    while (state != rf_read_state()) {
+        if (break_counter++ == 0xffff) {
+            tr_err("Failed to change state from %x to: %x", rf_read_state(), state);
+            break;
+        }
+    }
+}
+
+static void rf_enable_gpio_signal(uint8_t gpio_pin, uint8_t interrupt_signal, uint8_t gpio_mode)
+{
+    rf_write_register(GPIO0_CONF + gpio_pin, (interrupt_signal << 3) | gpio_mode);
+}
+
+static void rf_enable_interrupt(uint8_t event)
+{
+    rf_write_register_field(IRQ_MASK0 - (event / 8), 1 << (event % 8), 1 << (event % 8));
+    enabled_interrupts |= (1 << event);
+}
+
+static void rf_disable_interrupt(uint8_t event)
+{
+    rf_write_register_field(IRQ_MASK0 - (event / 8), 1 << (event % 8), 0 << (event % 8));
+    enabled_interrupts &= ~(1 << event);
+}
+
+static void rf_disable_all_interrupts(void)
+{
+    rf_write_register(IRQ_MASK0, 0);
+    rf_write_register(IRQ_MASK1, 0);
+    rf_write_register(IRQ_MASK2, 0);
+    rf_write_register(IRQ_MASK3, 0);
+    enabled_interrupts = 0;
+    read_irq_status();
+}
+
+static void rf_enable_gpio_interrupt(void)
+{
+    rf_enable_gpio_signal(INTERRUPT_GPIO, NIRQ, DIG_OUT_HIGH);
+    INT_IN_GPIO.mode(PullUp);
+    INT_IN_GPIO.fall(&rf_interrupt_handler);
+    INT_IN_GPIO.enable_irq();
+}
+
+static void rf_send_command(s2lp_commands_e command)
+{
+    const uint8_t tx[2] = {SPI_CMD, command};
+    rf_lock();
+    CS_SELECT();
+    rf_spi_exchange(tx, sizeof(tx), NULL, 0);
+    CS_RELEASE();
+    rf_unlock();
+}
+
+static void rf_state_change(s2lp_states_e state, bool lock_mode_tx)
+{
+    s2lp_commands_e command;
+
+    if (S2LP_STATE_READY == state) {
+        s2lp_states_e cur_state = rf_read_state();
+        if (S2LP_STATE_TX == cur_state || S2LP_STATE_RX == cur_state) {
+            command = S2LP_CMD_SABORT;
+        } else {
+            command = S2LP_CMD_READY;
+        }
+    } else if (S2LP_STATE_LOCK == state && lock_mode_tx) {
+        command = S2LP_CMD_LOCKTX;
+    } else if (S2LP_STATE_LOCK == state && !lock_mode_tx) {
+        command = S2LP_CMD_LOCKRX;
+    } else if (S2LP_STATE_RX == state) {
+        command = S2LP_CMD_RX;
+    } else if (S2LP_STATE_TX == state) {
+        command = S2LP_CMD_TX;
+    } else {
+        tr_err("Invalid state %x", state);
+        return;
+    }
+    rf_send_command(command);
+    rf_poll_state_change(state);
+}
+
+static uint8_t rf_write_tx_fifo(uint8_t *ptr, uint16_t length, uint8_t max_write)
+{
+    const uint8_t spi_header[SPI_HEADER_LENGTH] = {SPI_WR_REG, TX_FIFO};
+    uint8_t written_length = length;
+    if (length > max_write) {
+        written_length = max_write;
+    }
+    CS_SELECT();
+    rf_spi_exchange(spi_header, SPI_HEADER_LENGTH, NULL, 0);
+    rf_spi_exchange(ptr, written_length, NULL, 0);
+    CS_RELEASE();
+    return written_length;
+}
+
+static uint8_t rf_read_rx_fifo(uint8_t *ptr, uint16_t length)
+{
+    const uint8_t spi_header[SPI_HEADER_LENGTH] = {SPI_RD_REG, RX_FIFO};
+    CS_SELECT();
+    rf_spi_exchange(spi_header, SPI_HEADER_LENGTH, NULL, 0);
+    rf_spi_exchange(NULL, 0, ptr, length);
+    CS_RELEASE();
+    return length;
+}
+
+static void rf_write_packet_length(uint16_t packet_length)
+{
+    rf_write_register(PCKTLEN1, packet_length / 256);
+    rf_write_register(PCKTLEN0, packet_length % 256);
+}
+
+static uint32_t read_irq_status(void)
+{
+    const uint8_t tx[2] = {SPI_RD_REG, IRQ_STATUS3};
+    uint8_t rx[6];
+    CS_SELECT();
+    rf_spi_exchange(tx, sizeof(tx), rx, sizeof(rx));
+    CS_RELEASE();
+    return (((uint32_t)rx[2] << 24) | ((uint32_t)rx[3] << 16) | ((uint32_t)rx[4] << 8) | rx[5]);
+}
+
+static void rf_init_registers(void)
+{
+    rf_write_register_field(PCKTCTRL3, PCKT_FORMAT_FIELD, PCKT_FORMAT_802_15_4);
+    // Set deviation
+    uint8_t fdev_m, fdev_e;
+    rf_conf_calculate_deviation_registers(DEVIATION, &fdev_m, &fdev_e);
+    rf_write_register(MOD0, fdev_m);
+    rf_write_register_field(MOD1, FDEV_E_FIELD, fdev_e);
+    rf_write_register_field(MOD2, MOD_TYPE_FIELD, MOD_2FSK);
+    // Set datarate
+    uint16_t datarate_m;
+    uint8_t datarate_e;
+    rf_conf_calculate_datarate_registers(phy_subghz.datarate, &datarate_m, &datarate_e);
+    rf_write_register_field(MOD2, DATARATE_E_FIELD, datarate_e);
+    rf_write_register(MOD3, (uint8_t)datarate_m);
+    rf_write_register(MOD4, datarate_m >> 8);
+    // Set RX filter bandwidth
+    uint8_t chflt_m, chflt_e;
+    rf_conf_calculate_rx_filter_bandwidth_registers(RX_FILTER_BANDWIDTH, &chflt_m, &chflt_e);
+    rf_write_register_field(CHFLT, CHFLT_M_FIELD, chflt_m << 4);
+    rf_write_register_field(CHFLT, CHFLT_E_FIELD, chflt_e);
+    rf_write_register(PCKT_FLT_OPTIONS, 0);
+    // Set base frequency (Channel 0 center frequency)
+    uint8_t synt3, synt2, synt1, synt0;
+    rf_conf_calculate_base_frequency_registers(phy_subghz.channel_0_center_frequency, &synt3, &synt2, &synt1, &synt0);
+    rf_write_register_field(SYNT3, SYNT_FIELD, synt3);
+    rf_write_register(SYNT2, synt2);
+    rf_write_register(SYNT1, synt1);
+    rf_write_register(SYNT0, synt0);
+    // Set channel spacing
+    uint8_t ch_space;
+    uint8_t ch_space_divider = 1;
+    while (rf_conf_calculate_channel_spacing_registers(phy_subghz.channel_spacing / ch_space_divider, &ch_space)) {
+        ch_space_divider++;
+        rf_channel_multiplier++;
+    }
+    rf_write_register(CHSPACE, ch_space);
+    rf_write_register_field(PCKTCTRL1, PCKT_CRCMODE_FIELD, PCKT_CRCMODE_0X1021);
+    rf_write_register_field(PCKTCTRL1, PCKT_TXSOURCE_FIELD, PCKT_TXSOURCE_NORMAL);
+    rf_write_register_field(PCKTCTRL1, PCKT_WHITENING_FIELD, PCKT_WHITENING_ENABLED);
+    rf_write_register_field(PCKTCTRL2, PCKT_FIXVARLEN_FIELD, PCKT_VARIABLE_LEN);
+    rf_write_register_field(PCKTCTRL3, PCKT_RXMODE_FIELD, PCKT_RXMODE_NORMAL);
+    rf_write_register(PCKTCTRL5, PCKT_PREAMBLE_LEN);
+    rf_write_register_field(PCKTCTRL6, PCKT_SYNCLEN_FIELD, PCKT_SYNCLEN);
+    rf_write_register_field(QI, PQI_TH_FIELD, PQI_TH);
+    rf_write_register_field(QI, SQI_EN_FIELD, SQI_EN);
+    rf_write_register(SYNC0, SFD0);
+    rf_write_register(SYNC1, SFD1);
+    // Set RSSI threshold
+    uint8_t rssi_th;
+    rf_conf_calculate_rssi_threshold_registers(RSSI_THRESHOLD, &rssi_th);
+    rf_write_register(RSSI_TH, rssi_th);
+}
+
+static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr)
+{
+    int8_t ret_val = 0;
+    switch (address_type) {
+        /*Set 48-bit address*/
+        case PHY_MAC_48BIT:
+            break;
+        /*Set 64-bit address*/
+        case PHY_MAC_64BIT:
+            memcpy(s2lp_MAC, address_ptr, 8);
+            break;
+        /*Set 16-bit address*/
+        case PHY_MAC_16BIT:
+            memcpy(s2lp_short_address, address_ptr, 2);
+            break;
+        /*Set PAN Id*/
+        case PHY_MAC_PANID:
+            memcpy(s2lp_PAN_ID, address_ptr, 2);
+            break;
+    }
+    return ret_val;
+}
+
+static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr)
+{
+    int8_t retval = 0;
+    phy_csma_params_t *csma_params;
+    uint32_t *timer_value;
+    switch (extension_type) {
+        case PHY_EXTENSION_SET_CHANNEL:
+            if (rf_state == RF_IDLE || rf_state == RF_CSMA_STARTED) {
+                rf_receive(*data_ptr);
+            } else {
+                // Store the new channel if couldn't change it yet.
+                rf_new_channel = *data_ptr;
+                retval = -1;
+            }
+            break;
+        case PHY_EXTENSION_CTRL_PENDING_BIT:
+            break;
+        /*Return frame pending status*/
+        case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS:
+            break;
+        case PHY_EXTENSION_ACCEPT_ANY_BEACON:
+            break;
+        case PHY_EXTENSION_SET_TX_TIME:
+            tx_time = common_read_32_bit(data_ptr);
+            break;
+        case PHY_EXTENSION_READ_RX_TIME:
+            common_write_32_bit(rx_time, data_ptr);
+            break;
+        case PHY_EXTENSION_DYNAMIC_RF_SUPPORTED:
+            *data_ptr = true;
+            break;
+        case PHY_EXTENSION_GET_TIMESTAMP:
+            timer_value = (uint32_t *)data_ptr;
+            *timer_value = rf_get_timestamp();
+            break;
+        case PHY_EXTENSION_SET_CSMA_PARAMETERS:
+            csma_params = (phy_csma_params_t *)data_ptr;
+            if (csma_params->backoff_time == 0) {
+                rf_cca_timer_stop();
+                if (rf_read_register_with_status(TX_FIFO_STATUS, NULL)) {
+                    rf_send_command(S2LP_CMD_SABORT);
+                    rf_poll_state_change(S2LP_STATE_READY);
+                    rf_send_command(S2LP_CMD_FLUSHTXFIFO);
+                    rf_poll_state_change(S2LP_STATE_READY);
+                }
+                if (rf_state == RF_TX_STARTED) {
+                    rf_state = RF_IDLE;
+                    rf_receive(rf_rx_channel);
+                }
+                tx_time = 0;
+            } else {
+                tx_time = csma_params->backoff_time;
+                cca_enabled = csma_params->cca_enabled;
+            }
+            break;
+        case PHY_EXTENSION_READ_TX_FINNISH_TIME:
+            timer_value = (uint32_t *)data_ptr;
+            *timer_value = tx_finnish_time;
+            break;
+
+        case PHY_EXTENSION_GET_SYMBOLS_PER_SECOND:
+            timer_value = (uint32_t *)data_ptr;
+            *timer_value = symbols_in_seconds;
+            break;
+
+        default:
+            break;
+    }
+
+    return retval;
+}
+
+
+static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel)
+{
+    int8_t ret_val = 0;
+    switch (new_state) {
+        /*Reset PHY driver and set to idle*/
+        case PHY_INTERFACE_RESET:
+            break;
+        /*Disable PHY Interface driver*/
+        case PHY_INTERFACE_DOWN:
+            break;
+        /*Enable PHY Interface driver*/
+        case PHY_INTERFACE_UP:
+            rf_receive(rf_channel);
+            break;
+        /*Enable wireless interface ED scan mode*/
+        case PHY_INTERFACE_RX_ENERGY_STATE:
+            break;
+        /*Enable Sniffer state*/
+        case PHY_INTERFACE_SNIFFER_STATE:
+            break;
+    }
+    return ret_val;
+}
+
+static void rf_tx_sent_handler(void)
+{
+    rf_backup_timer_stop();
+    rf_disable_interrupt(TX_DATA_SENT);
+    if (rf_state != RF_TX_ACK) {
+        tx_finnish_time = rf_get_timestamp();
+        TEST_TX_DONE
+        rf_state = RF_IDLE;
+        rf_receive(rf_rx_channel);
+        if (device_driver.phy_tx_done_cb) {
+            device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 0, 0);
+        }
+    } else {
+        TEST_ACK_TX_DONE
+        rf_receive(rf_rx_channel);
+    }
+}
+
+static void rf_tx_threshold_handler(void)
+{
+    rf_disable_interrupt(TX_FIFO_ALMOST_EMPTY);
+    // TODO check the FIFO threshold. By default, threshold is half of the FIFO size
+    uint8_t written_length = rf_write_tx_fifo(tx_data_ptr, tx_data_length, FIFO_SIZE / 2);
+    if (written_length < tx_data_length) {
+        tx_data_ptr += written_length;
+        tx_data_length -= written_length;
+        rf_enable_interrupt(TX_FIFO_ALMOST_EMPTY);
+    }
+}
+
+static void rf_start_tx(void)
+{
+    rf_disable_all_interrupts();
+    // More TX data to be written in FIFO when TX threshold interrupt occurs
+    if (tx_data_ptr) {
+        rf_enable_interrupt(TX_FIFO_ALMOST_EMPTY);
+    }
+    rf_enable_interrupt(TX_DATA_SENT);
+    rf_enable_interrupt(TX_FIFO_UNF_OVF);
+    rf_state_change(S2LP_STATE_READY, false);
+    rf_state_change(S2LP_STATE_LOCK, true);
+    rf_state_change(S2LP_STATE_TX, false);
+    rf_backup_timer_start(MAX_PACKET_SENDING_TIME);
+}
+
+static void rf_cca_timer_interrupt(void)
+{
+    if (device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_PREPARE, 0, 0) != 0) {
+        if (rf_read_register_with_status(TX_FIFO_STATUS, NULL)) {
+            rf_send_command(S2LP_CMD_FLUSHTXFIFO);
+        }
+        rf_state = RF_IDLE;
+        return;
+    }
+    if ((cca_enabled == true) && (rf_read_register_with_status(LINK_QUALIF1, NULL) & CARRIER_SENSE || (rf_state != RF_CSMA_STARTED && rf_state != RF_IDLE))) {
+        if (rf_state == RF_CSMA_STARTED) {
+            rf_state = RF_IDLE;
+        }
+        if (rf_read_register_with_status(TX_FIFO_STATUS, NULL)) {
+            rf_send_command(S2LP_CMD_FLUSHTXFIFO);
+        }
+        tx_finnish_time = rf_get_timestamp();
+        if (device_driver.phy_tx_done_cb) {
+            device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 0, 0);
+        }
+    } else {
+        rf_start_tx();
+        rf_state = RF_TX_STARTED;
+        TEST_TX_STARTED
+    }
+}
+
+static void rf_cca_timer_stop(void)
+{
+    rf->cca_timer.detach();
+}
+
+static void rf_cca_timer_start(uint32_t slots)
+{
+#ifdef MBED_CONF_RTOS_PRESENT
+    rf->cca_timer.attach_us(rf_cca_timer_signal, slots);
+#else //MBED_CONF_RTOS_PRESENT
+    rf->cca_timer.attach_us(rf_cca_timer_interrupt, slots);
+#endif //MBED_CONF_RTOS_PRESENT
+}
+
+static void rf_backup_timer_interrupt(void)
+{
+    tx_finnish_time = rf_get_timestamp();
+    if (rf_state == RF_TX_STARTED) {
+        if (device_driver.phy_tx_done_cb) {
+            device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 0, 0);
+        }
+    }
+    if (rf_read_register_with_status(TX_FIFO_STATUS, NULL)) {
+        rf_send_command(S2LP_CMD_FLUSHTXFIFO);
+    }
+    TEST_TX_DONE
+    TEST_RX_DONE
+    rf_state = RF_IDLE;
+    rf_receive(rf_rx_channel);
+}
+
+static void rf_backup_timer_stop(void)
+{
+    rf->backup_timer.detach();
+}
+
+static void rf_backup_timer_start(uint32_t slots)
+{
+#ifdef MBED_CONF_RTOS_PRESENT
+    rf->backup_timer.attach_us(rf_backup_timer_signal, slots);
+#else //MBED_CONF_RTOS_PRESENT
+    rf->backup_timer.attach_us(rf_backup_timer_interrupt, slots);
+#endif //MBED_CONF_RTOS_PRESENT
+}
+
+static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol)
+{
+    rf_lock();
+    if (rf_state != RF_IDLE) {
+        rf_unlock();
+        return -1;
+    }
+    rf_state = RF_CSMA_STARTED;
+    uint8_t written_length = rf_write_tx_fifo(data_ptr, data_length, FIFO_SIZE);
+    if (written_length < data_length) {
+        tx_data_ptr = data_ptr + written_length;
+        tx_data_length = data_length - written_length;
+    } else {
+        tx_data_ptr = NULL;
+    }
+    // If Ack is requested, store the MAC sequence. This will be compared with received Ack.
+    uint8_t version = ((*(data_ptr + 1) & VERSION_FIELD_MASK) >> SHIFT_VERSION_FIELD);
+    if ((version != MAC_FRAME_VERSION_2) && (*data_ptr & FC_AR)) {
+        tx_sequence = *(data_ptr + 2);
+    }
+    // TODO: Define this better
+    rf_write_packet_length(data_length + 4);
+    mac_tx_handle = tx_handle;
+    if (tx_time) {
+        uint32_t backoff_time = tx_time - rf_get_timestamp();
+        // Max. time to TX can be 65ms, otherwise time has passed already -> send immediately
+        if (backoff_time <= 65000) {
+            rf_cca_timer_start(backoff_time);
+            rf_unlock();
+            return 0;
+        }
+    }
+    rf_cca_timer_interrupt();
+    rf_unlock();
+    return 0;
+}
+
+static void rf_send_ack(uint8_t seq)
+{
+    // If the reception started during CCA process, the TX FIFO may already contain a data packet
+    if (rf_read_register_with_status(TX_FIFO_STATUS, NULL)) {
+        rf_send_command(S2LP_CMD_SABORT);
+        rf_poll_state_change(S2LP_STATE_READY);
+        rf_send_command(S2LP_CMD_FLUSHTXFIFO);
+        rf_poll_state_change(S2LP_STATE_READY);
+    }
+    rf_state = RF_TX_ACK;
+    uint8_t ack_frame[3] = {MAC_TYPE_ACK, 0, seq};
+    rf_write_tx_fifo(ack_frame, sizeof(ack_frame), FIFO_SIZE);
+    rf_write_packet_length(sizeof(ack_frame) + 4);
+    tx_data_ptr = NULL;
+    rf_start_tx();
+    TEST_ACK_TX_STARTED
+    rf_backup_timer_start(ACK_SENDING_TIME);
+}
+
+static void rf_handle_ack(uint8_t seq_number, uint8_t pending)
+{
+    phy_link_tx_status_e phy_status;
+    if (tx_sequence == (uint16_t)seq_number) {
+        tx_finnish_time = rf_get_timestamp();
+        if (pending) {
+            phy_status = PHY_LINK_TX_DONE_PENDING;
+        } else {
+            phy_status = PHY_LINK_TX_DONE;
+        }
+        // No CCA attempts done, just waited Ack
+        device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, phy_status, 0, 0);
+        // Clear TX sequence when Ack is received to avoid duplicate Acks
+        tx_sequence = 0xffff;
+    }
+}
+
+static void rf_rx_ready_handler(void)
+{
+    rf_backup_timer_stop();
+    TEST_RX_DONE
+    rx_data_length += rf_read_rx_fifo(&rx_buffer[rx_data_length], rf_read_register_with_status(RX_FIFO_STATUS, NULL));
+    uint8_t version = ((rx_buffer[1] & VERSION_FIELD_MASK) >> SHIFT_VERSION_FIELD);
+    if (((rx_buffer[0] & MAC_FRAME_TYPE_MASK) == MAC_TYPE_ACK) && (version < MAC_FRAME_VERSION_2)) {
+        rf_handle_ack(rx_buffer[2], rx_buffer[0] & MAC_DATA_PENDING);
+    } else if (rf_rx_filter(rx_buffer, s2lp_MAC, s2lp_short_address, s2lp_PAN_ID)) {
+        rf_state = RF_IDLE;
+        int8_t rssi = (rf_read_register_with_status(RSSI_LEVEL, NULL) - RSSI_OFFSET);
+        if (device_driver.phy_rx_cb) {
+            device_driver.phy_rx_cb(rx_buffer, rx_data_length, 0xf0, rssi, rf_radio_driver_id);
+        }
+        // Check Ack request
+        if ((version != MAC_FRAME_VERSION_2) && (rx_buffer[0] & FC_AR)) {
+            rf_send_ack(rx_buffer[2]);
+        }
+    }
+    if ((rf_state != RF_TX_ACK) && (rf_state != RF_CSMA_STARTED)) {
+        rf_receive(rf_rx_channel);
+    }
+}
+
+static void rf_rx_threshold_handler(void)
+{
+    rx_data_length += rf_read_rx_fifo(&rx_buffer[rx_data_length], rf_read_register_with_status(RX_FIFO_STATUS, NULL));
+}
+
+static void rf_sync_detected_handler(void)
+{
+    rx_time = rf_get_timestamp();
+    rf_state = RF_RX_STARTED;
+    TEST_RX_STARTED
+    rf_disable_interrupt(SYNC_WORD);
+    rf_backup_timer_start(MAX_PACKET_SENDING_TIME);
+}
+
+static void rf_receive(uint8_t rx_channel)
+{
+    if (rf_state == RF_TX_STARTED) {
+        return;
+    }
+    rf_lock();
+    rf_disable_all_interrupts();
+    rf_state_change(S2LP_STATE_READY, false);
+    rf_send_command(S2LP_CMD_FLUSHRXFIFO);
+    rf_poll_state_change(S2LP_STATE_READY);
+    if (rx_channel != rf_rx_channel) {
+        rf_write_register(CHNUM, rx_channel * rf_channel_multiplier);
+        rf_rx_channel = rf_new_channel = rx_channel;
+    }
+    rf_state_change(S2LP_STATE_LOCK, false);
+    rf_state_change(S2LP_STATE_RX, false);
+    rf_enable_interrupt(SYNC_WORD);
+    rf_enable_interrupt(RX_FIFO_ALMOST_FULL);
+    rf_enable_interrupt(RX_DATA_READY);
+    rf_enable_interrupt(RX_FIFO_UNF_OVF);
+    rx_data_length = 0;
+    rf_state = RF_IDLE;
+    rf_unlock();
+}
+
+#ifdef MBED_CONF_RTOS_PRESENT
+static void rf_interrupt_handler(void)
+{
+    rf->irq_thread.signal_set(SIG_RADIO);
+}
+
+void RFPins::rf_irq_task(void)
+{
+    for (;;) {
+        osEvent event = irq_thread.signal_wait(0);
+        if (event.status != osEventSignal) {
+            continue;
+        }
+        rf_lock();
+        if (event.value.signals & SIG_RADIO) {
+            rf_irq_task_process_irq();
+        }
+        if (event.value.signals & SIG_TIMER_CCA) {
+            rf_cca_timer_interrupt();
+        }
+        if (event.value.signals & SIG_TIMER_BACKUP) {
+            rf_backup_timer_interrupt();
+        }
+        rf_unlock();
+    }
+}
+
+static void rf_irq_task_process_irq(void)
+#else //MBED_CONF_RTOS_PRESENT
+static void rf_interrupt_handler(void)
+#endif //MBED_CONF_RTOS_PRESENT
+{
+    rf_lock();
+    uint32_t irq_status = read_irq_status();
+    if (rf_state == RF_TX_STARTED || rf_state == RF_TX_ACK) {
+        if ((irq_status & (1 << TX_DATA_SENT)) && (enabled_interrupts & (1 << TX_DATA_SENT))) {
+            rf_tx_sent_handler();
+        }
+    }
+    if (rf_state == RF_TX_STARTED) {
+        if ((irq_status & (1 << TX_FIFO_ALMOST_EMPTY)) && (enabled_interrupts & (1 << TX_FIFO_ALMOST_EMPTY))) {
+            rf_tx_threshold_handler();
+        }
+    }
+    if ((irq_status & (1 << TX_FIFO_UNF_OVF)) && (enabled_interrupts & (1 << TX_FIFO_UNF_OVF))) {
+        tx_finnish_time = rf_get_timestamp();
+        TEST_TX_DONE
+        device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_FAIL, 1, 0);
+        rf_send_command(S2LP_CMD_SABORT);
+        rf_poll_state_change(S2LP_STATE_READY);
+        rf_send_command(S2LP_CMD_FLUSHTXFIFO);
+        rf_poll_state_change(S2LP_STATE_READY);
+        rf_state = RF_IDLE;
+        rf_receive(rf_rx_channel);
+    }
+    if (rf_state == RF_IDLE || rf_state == RF_TX_STARTED) {
+        if ((irq_status & (1 << SYNC_WORD)) && (enabled_interrupts & (1 << SYNC_WORD))) {
+            rf_sync_detected_handler();
+        }
+    } else if (rf_state == RF_RX_STARTED) {
+        if ((irq_status & (1 << RX_DATA_READY)) && (enabled_interrupts & (1 << RX_DATA_READY))) {
+            if (!(irq_status & (1 << CRC_ERROR))) {
+                rf_rx_ready_handler();
+            } else {
+                rf_state = RF_IDLE;
+                // In case the channel change was called during reception, driver is responsible to change the channel if CRC failed.
+                rf_receive(rf_new_channel);
+            }
+        }
+        if ((irq_status & (1 << RX_FIFO_ALMOST_FULL)) && (enabled_interrupts & (1 << RX_FIFO_ALMOST_FULL))) {
+            rf_rx_threshold_handler();
+        }
+        if ((irq_status & (1 << RX_DATA_DISCARDED)) && (enabled_interrupts & (1 << RX_DATA_DISCARDED))) {
+
+        }
+        if ((irq_status & (1 << CRC_ERROR)) && (enabled_interrupts & (1 << CRC_ERROR))) {
+
+        }
+    }
+    if ((irq_status & (1 << RX_FIFO_UNF_OVF)) && (enabled_interrupts & (1 << RX_FIFO_UNF_OVF))) {
+        TEST_RX_DONE
+        rf_send_command(S2LP_CMD_SABORT);
+        rf_poll_state_change(S2LP_STATE_READY);
+        rf_send_command(S2LP_CMD_FLUSHRXFIFO);
+        rf_poll_state_change(S2LP_STATE_READY);
+        rf_state = RF_IDLE;
+        rf_receive(rf_rx_channel);
+    }
+    rf_unlock();
+}
+
+static void rf_reset(void)
+{
+    // Shutdown
+    rf->SDN = 1;
+    wait_ms(10);
+    // Wake up
+    rf->SDN = 0;
+    // Wait until GPIO0 (RESETN) goes high
+    while (rf->RF_S2LP_GPIO0 == 0);
+}
+
+static void rf_init(void)
+{
+#ifdef TEST_GPIOS_ENABLED
+    fhss_bc_switch = test1_toggle;
+    fhss_uc_switch = test2_toggle;
+#endif //TEST_GPIOS_ENABLED
+    rf_reset();
+    rf->spi.frequency(10000000);
+    CS_RELEASE();
+    if (PARTNUM != rf_read_register_with_status(DEVICE_INFO1, NULL)) {
+        tr_err("Invalid part number: %x", rf_read_register_with_status(DEVICE_INFO1, NULL));
+    }
+    if (VERSION != rf_read_register_with_status(DEVICE_INFO0, NULL)) {
+        tr_err("Invalid version: %x", rf_read_register_with_status(DEVICE_INFO0, NULL));
+    }
+    rf_init_registers();
+    rf_enable_gpio_interrupt();
+    rf_calculate_symbols_in_seconds(phy_subghz.datarate, phy_subghz.modulation);
+    rf->tx_timer.start();
+    rf_print_registers();
+}
+
+static int8_t rf_device_register(const uint8_t *mac_addr)
+{
+    rf_init();
+    /*Set pointer to MAC address*/
+    device_driver.PHY_MAC = (uint8_t *)mac_addr;
+    device_driver.driver_description = (char *)"S2LP_MAC";
+    device_driver.link_type = PHY_LINK_15_4_SUBGHZ_TYPE;
+    device_driver.phy_channel_pages = phy_channel_pages;
+    device_driver.phy_MTU = RF_MTU;
+    /*No header in PHY*/
+    device_driver.phy_header_length = 0;
+    /*No tail in PHY*/
+    device_driver.phy_tail_length = 0;
+    /*Set address write function*/
+    device_driver.address_write = &rf_address_write;
+    /*Set RF extension function*/
+    device_driver.extension = &rf_extension;
+    /*Set RF state control function*/
+    device_driver.state_control = &rf_interface_state_control;
+    /*Set transmit function*/
+    device_driver.tx = &rf_start_cca;
+    /*NULLIFY rx and tx_done callbacks*/
+    device_driver.phy_rx_cb = NULL;
+    device_driver.phy_tx_done_cb = NULL;
+    /*Register device driver*/
+    rf_radio_driver_id = arm_net_phy_register(&device_driver);
+    return rf_radio_driver_id;
+}
+
+static void rf_device_unregister()
+{
+    if (rf_radio_driver_id >= 0) {
+        arm_net_phy_unregister(rf_radio_driver_id);
+        rf_radio_driver_id = -1;
+    }
+}
+
+void NanostackRfPhys2lp::get_mac_address(uint8_t *mac)
+{
+
+}
+
+void NanostackRfPhys2lp::set_mac_address(uint8_t *mac)
+{
+
+}
+
+int8_t NanostackRfPhys2lp::rf_register()
+{
+    if (NULL == _rf) {
+        return -1;
+    }
+    rf_lock();
+    if (rf != NULL) {
+        rf_unlock();
+        error("Multiple registrations of NanostackRfPhyAtmel not supported");
+        return -1;
+    }
+    rf = _rf;
+    int8_t radio_id = rf_device_register(_mac_addr);
+    if (radio_id < 0) {
+        rf = NULL;
+    }
+    rf_unlock();
+    return radio_id;
+}
+
+void NanostackRfPhys2lp::rf_unregister()
+{
+    rf_lock();
+    if (NULL == rf) {
+        rf_unlock();
+        return;
+    }
+    rf_device_unregister();
+    rf = NULL;
+    rf_unlock();
+}
+
+NanostackRfPhys2lp::NanostackRfPhys2lp(PinName spi_sdi, PinName spi_sdo, PinName spi_sclk, PinName spi_cs, PinName spi_sdn,
+#ifdef TEST_GPIOS_ENABLED
+                                       PinName spi_test1, PinName spi_test2, PinName spi_test3, PinName spi_test4, PinName spi_test5,
+#endif //TEST_GPIOS_ENABLED
+                                       PinName spi_gpio0, PinName spi_gpio1, PinName spi_gpio2, PinName spi_gpio3)
+    : _mac_addr(), _rf(NULL), _mac_set(false),
+      _spi_sdi(spi_sdi), _spi_sdo(spi_sdo), _spi_sclk(spi_sclk), _spi_cs(spi_cs), _spi_sdn(spi_sdn),
+#ifdef TEST_GPIOS_ENABLED
+      _spi_test1(spi_test1), _spi_test2(spi_test2), _spi_test3(spi_test3), _spi_test4(spi_test4), _spi_test5(spi_test5),
+#endif //TEST_GPIOS_ENABLED
+      _spi_gpio0(spi_gpio0), _spi_gpio1(spi_gpio1), _spi_gpio2(spi_gpio2), _spi_gpio3(spi_gpio3)
+{
+    _rf = new RFPins(_spi_sdi, _spi_sdo, _spi_sclk, _spi_cs, _spi_sdn,
+#ifdef TEST_GPIOS_ENABLED
+                     _spi_test1, _spi_test2, _spi_test3, _spi_test4, _spi_test5,
+#endif //TEST_GPIOS_ENABLED
+                     _spi_gpio0, _spi_gpio1, _spi_gpio2, _spi_gpio3);
+}
+
+NanostackRfPhys2lp::~NanostackRfPhys2lp()
+{
+    delete _rf;
+}
+
+static bool rf_panid_filter_common(uint8_t *panid_start, uint8_t *pan_id, uint8_t frame_type)
+{
+    // PHY driver shouldn't drop received Beacon frames as they might be used by load balancing
+    if (frame_type == MAC_FRAME_BEACON) {
+        return true;
+    }
+    bool retval = true;
+    uint8_t cmp_table[2] = {0xff, 0xff};
+    if (!(pan_id[0] == 0xff && pan_id[1] == 0xff)) {
+        if (memcmp((uint8_t *)panid_start, (uint8_t *) cmp_table, 2)) {
+            retval = false;
+        }
+        if (!retval) {
+            for (uint8_t i = 0; i < 2; i++) {
+                cmp_table[1 - i] = panid_start[i];
+            }
+            if (!memcmp(pan_id, cmp_table, 2)) {
+                retval = true;
+            }
+        }
+    }
+    return retval;
+}
+
+static bool rf_panid_v2_filter(uint8_t *ptr, uint8_t *pan_id, uint8_t dst_mode, uint8_t src_mode, uint8_t seq_compressed, uint8_t panid_compressed, uint8_t frame_type)
+{
+    if ((dst_mode == FC_DST_ADDR_NONE) && (frame_type == MAC_TYPE_DATA || frame_type == MAC_TYPE_COMMAND)) {
+        return true;
+    }
+    if ((dst_mode == FC_DST_64_BITS) && (src_mode == FC_SRC_64_BITS) && panid_compressed) {
+        return true;
+    }
+    if (seq_compressed) {
+        ptr--;
+    }
+    return rf_panid_filter_common(ptr, pan_id, frame_type);
+}
+
+static bool rf_panid_v1_v0_filter(uint8_t *ptr, uint8_t *pan_id, uint8_t frame_type)
+{
+    return rf_panid_filter_common(ptr, pan_id, frame_type);
+}
+
+static bool rf_addr_filter_common(uint8_t *ptr, uint8_t addr_mode, uint8_t *mac_64bit_addr, uint8_t *mac_16bit_addr)
+{
+    uint8_t cmp_table[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+    bool retval = true;
+    switch (addr_mode) {
+        case FC_DST_16_BITS:
+            if (memcmp((uint8_t *)ptr, (uint8_t *) cmp_table, 2)) {
+                retval = false;
+            }
+            if (!retval) {
+                for (uint8_t i = 0; i < 2; i++) {
+                    cmp_table[1 - i] = ptr[i];
+                }
+
+                if (!memcmp((uint8_t *)mac_16bit_addr, (uint8_t *) cmp_table, 2)) {
+                    retval = true;
+                }
+            }
+            break;
+        case FC_DST_64_BITS:
+            if (memcmp((uint8_t *)ptr, (uint8_t *) cmp_table, 8)) {
+                retval = false;
+            }
+            if (!retval) {
+                for (uint8_t i = 0; i < 8; i++) {
+                    cmp_table[7 - i] = ptr[i];
+                }
+
+                if (!memcmp((uint8_t *)mac_64bit_addr, (uint8_t *) cmp_table, 8)) {
+                    retval = true;
+                }
+            }
+            break;
+        case FC_DST_ADDR_NONE:
+            retval = true;
+            break;
+        default:
+            retval = false;
+            break;
+    }
+    return retval;
+}
+
+static bool rf_addr_v2_filter(uint8_t *ptr, uint8_t *mac_64bit_addr, uint8_t *mac_16bit_addr, uint8_t dst_mode, uint8_t seq_compressed, uint8_t panid_compressed)
+{
+    if (seq_compressed) {
+        ptr--;
+    }
+    if (panid_compressed) {
+        ptr -= 2;
+    }
+    return rf_addr_filter_common(ptr, dst_mode, mac_64bit_addr, mac_16bit_addr);
+}
+
+static bool rf_addr_v1_v0_filter(uint8_t *ptr, uint8_t *mac_64bit_addr, uint8_t *mac_16bit_addr, uint8_t dst_mode)
+{
+    return rf_addr_filter_common(ptr, dst_mode, mac_64bit_addr, mac_16bit_addr);
+}
+
+static bool rf_rx_filter(uint8_t *mac_header, uint8_t *mac_64bit_addr, uint8_t *mac_16bit_addr, uint8_t *pan_id)
+{
+    uint8_t dst_mode = (mac_header[1] & FC_DST_MODE);
+    uint8_t src_mode = (mac_header[1] & FC_SRC_MODE);
+    uint8_t seq_compressed = ((mac_header[1] & FC_SEQUENCE_COMPRESSION) >> SHIFT_SEQ_COMP_FIELD);
+    uint8_t panid_compressed = ((mac_header[0] & FC_PAN_ID_COMPRESSION) >> SHIFT_PANID_COMP_FIELD);
+    uint8_t frame_type = mac_header[0] & MAC_FRAME_TYPE_MASK;
+    uint8_t version = ((mac_header[1] & VERSION_FIELD_MASK) >> SHIFT_VERSION_FIELD);
+    if (version == MAC_FRAME_VERSION_2) {
+        if (!rf_panid_v2_filter(mac_header + OFFSET_DST_PAN_ID, pan_id, dst_mode, src_mode, seq_compressed, panid_compressed, frame_type)) {
+            return false;
+        }
+        if (!rf_addr_v2_filter(mac_header + OFFSET_DST_ADDR, mac_64bit_addr, mac_16bit_addr, dst_mode, seq_compressed, panid_compressed)) {
+            return false;
+        }
+    } else {
+        if (!rf_panid_v1_v0_filter(mac_header + OFFSET_DST_PAN_ID, pan_id, frame_type)) {
+            return false;
+        }
+        if (!rf_addr_v1_v0_filter(mac_header + OFFSET_DST_ADDR, mac_64bit_addr, mac_16bit_addr, dst_mode)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+static void rf_print_registers(void)
+{
+    tr_debug("GPIO0_CONF: %x", rf_read_register_with_status(GPIO0_CONF, NULL));
+    tr_debug("GPIO1_CONF: %x", rf_read_register_with_status(GPIO1_CONF, NULL));
+    tr_debug("GPIO2_CONF: %x", rf_read_register_with_status(GPIO2_CONF, NULL));
+    tr_debug("GPIO3_CONF: %x", rf_read_register_with_status(GPIO3_CONF, NULL));
+    tr_debug("SYNT3: %x", rf_read_register_with_status(SYNT3, NULL));
+    tr_debug("SYNT2: %x", rf_read_register_with_status(SYNT2, NULL));
+    tr_debug("SYNT1: %x", rf_read_register_with_status(SYNT1, NULL));
+    tr_debug("SYNT0: %x", rf_read_register_with_status(SYNT0, NULL));
+    tr_debug("IF_OFFSET_ANA: %x", rf_read_register_with_status(IF_OFFSET_ANA, NULL));
+    tr_debug("IF_OFFSET_DIG: %x", rf_read_register_with_status(IF_OFFSET_DIG, NULL));
+    tr_debug("CHSPACE: %x", rf_read_register_with_status(CHSPACE, NULL));
+    tr_debug("CHNUM: %x", rf_read_register_with_status(CHNUM, NULL));
+    tr_debug("MOD4: %x", rf_read_register_with_status(MOD4, NULL));
+    tr_debug("MOD3: %x", rf_read_register_with_status(MOD3, NULL));
+    tr_debug("MOD2: %x", rf_read_register_with_status(MOD2, NULL));
+    tr_debug("MOD1: %x", rf_read_register_with_status(MOD1, NULL));
+    tr_debug("MOD0: %x", rf_read_register_with_status(MOD0, NULL));
+    tr_debug("CHFLT: %x", rf_read_register_with_status(CHFLT, NULL));
+    tr_debug("AFC2: %x", rf_read_register_with_status(AFC2, NULL));
+    tr_debug("AFC1: %x", rf_read_register_with_status(AFC1, NULL));
+    tr_debug("AFC0: %x", rf_read_register_with_status(AFC0, NULL));
+    tr_debug("RSSI_FLT: %x", rf_read_register_with_status(RSSI_FLT, NULL));
+    tr_debug("RSSI_TH: %x", rf_read_register_with_status(RSSI_TH, NULL));
+    tr_debug("AGCCTRL4: %x", rf_read_register_with_status(AGCCTRL4, NULL));
+    tr_debug("AGCCTRL3: %x", rf_read_register_with_status(AGCCTRL3, NULL));
+    tr_debug("AGCCTRL2: %x", rf_read_register_with_status(AGCCTRL2, NULL));
+    tr_debug("AGCCTRL1: %x", rf_read_register_with_status(AGCCTRL1, NULL));
+    tr_debug("AGCCTRL0: %x", rf_read_register_with_status(AGCCTRL0, NULL));
+    tr_debug("ANT_SELECT_CONF: %x", rf_read_register_with_status(ANT_SELECT_CONF, NULL));
+    tr_debug("CLOCKREC2: %x", rf_read_register_with_status(CLOCKREC2, NULL));
+    tr_debug("CLOCKREC1: %x", rf_read_register_with_status(CLOCKREC1, NULL));
+    tr_debug("PCKTCTRL6: %x", rf_read_register_with_status(PCKTCTRL6, NULL));
+    tr_debug("PCKTCTRL5: %x", rf_read_register_with_status(PCKTCTRL5, NULL));
+    tr_debug("PCKTCTRL4: %x", rf_read_register_with_status(PCKTCTRL4, NULL));
+    tr_debug("PCKTCTRL3: %x", rf_read_register_with_status(PCKTCTRL3, NULL));
+    tr_debug("PCKTCTRL2: %x", rf_read_register_with_status(PCKTCTRL2, NULL));
+    tr_debug("PCKTCTRL1: %x", rf_read_register_with_status(PCKTCTRL1, NULL));
+    tr_debug("PCKTLEN1: %x", rf_read_register_with_status(PCKTLEN1, NULL));
+    tr_debug("PCKTLEN0: %x", rf_read_register_with_status(PCKTLEN0, NULL));
+    tr_debug("SYNC3: %x", rf_read_register_with_status(SYNC3, NULL));
+    tr_debug("SYNC2: %x", rf_read_register_with_status(SYNC2, NULL));
+    tr_debug("SYNC1: %x", rf_read_register_with_status(SYNC1, NULL));
+    tr_debug("SYNC0: %x", rf_read_register_with_status(SYNC0, NULL));
+    tr_debug("QI: %x", rf_read_register_with_status(QI, NULL));
+    tr_debug("PCKT_PSTMBL: %x", rf_read_register_with_status(PCKT_PSTMBL, NULL));
+    tr_debug("PROTOCOL2: %x", rf_read_register_with_status(PROTOCOL2, NULL));
+    tr_debug("PROTOCOL1: %x", rf_read_register_with_status(PROTOCOL1, NULL));
+    tr_debug("PROTOCOL0: %x", rf_read_register_with_status(PROTOCOL0, NULL));
+    tr_debug("FIFO_CONFIG3: %x", rf_read_register_with_status(FIFO_CONFIG3, NULL));
+    tr_debug("FIFO_CONFIG2: %x", rf_read_register_with_status(FIFO_CONFIG2, NULL));
+    tr_debug("FIFO_CONFIG1: %x", rf_read_register_with_status(FIFO_CONFIG1, NULL));
+    tr_debug("FIFO_CONFIG0: %x", rf_read_register_with_status(FIFO_CONFIG0, NULL));
+    tr_debug("PCKT_FLT_OPTIONS: %x", rf_read_register_with_status(PCKT_FLT_OPTIONS, NULL));
+    tr_debug("PCKT_FLT_GOALS4: %x", rf_read_register_with_status(PCKT_FLT_GOALS4, NULL));
+    tr_debug("PCKT_FLT_GOALS3: %x", rf_read_register_with_status(PCKT_FLT_GOALS3, NULL));
+    tr_debug("PCKT_FLT_GOALS2: %x", rf_read_register_with_status(PCKT_FLT_GOALS2, NULL));
+    tr_debug("PCKT_FLT_GOALS1: %x", rf_read_register_with_status(PCKT_FLT_GOALS1, NULL));
+    tr_debug("PCKT_FLT_GOALS0: %x", rf_read_register_with_status(PCKT_FLT_GOALS0, NULL));
+    tr_debug("TIMERS5: %x", rf_read_register_with_status(TIMERS5, NULL));
+    tr_debug("TIMERS4: %x", rf_read_register_with_status(TIMERS4, NULL));
+    tr_debug("TIMERS3: %x", rf_read_register_with_status(TIMERS3, NULL));
+    tr_debug("TIMERS2: %x", rf_read_register_with_status(TIMERS2, NULL));
+    tr_debug("TIMERS1: %x", rf_read_register_with_status(TIMERS1, NULL));
+    tr_debug("TIMERS0: %x", rf_read_register_with_status(TIMERS0, NULL));
+    tr_debug("CSMA_CONF3: %x", rf_read_register_with_status(CSMA_CONF3, NULL));
+    tr_debug("CSMA_CONF2: %x", rf_read_register_with_status(CSMA_CONF2, NULL));
+    tr_debug("CSMA_CONF1: %x", rf_read_register_with_status(CSMA_CONF1, NULL));
+    tr_debug("CSMA_CONF0: %x", rf_read_register_with_status(CSMA_CONF0, NULL));
+    tr_debug("IRQ_MASK3: %x", rf_read_register_with_status(IRQ_MASK3, NULL));
+    tr_debug("IRQ_MASK2: %x", rf_read_register_with_status(IRQ_MASK2, NULL));
+    tr_debug("IRQ_MASK1: %x", rf_read_register_with_status(IRQ_MASK1, NULL));
+    tr_debug("IRQ_MASK0: %x", rf_read_register_with_status(IRQ_MASK0, NULL));
+    tr_debug("FAST_RX_TIMER: %x", rf_read_register_with_status(FAST_RX_TIMER, NULL));
+    tr_debug("PA_POWER8: %x", rf_read_register_with_status(PA_POWER8, NULL));
+    tr_debug("PA_POWER7: %x", rf_read_register_with_status(PA_POWER7, NULL));
+    tr_debug("PA_POWER6: %x", rf_read_register_with_status(PA_POWER6, NULL));
+    tr_debug("PA_POWER5: %x", rf_read_register_with_status(PA_POWER5, NULL));
+    tr_debug("PA_POWER4: %x", rf_read_register_with_status(PA_POWER4, NULL));
+    tr_debug("PA_POWER3: %x", rf_read_register_with_status(PA_POWER3, NULL));
+    tr_debug("PA_POWER2: %x", rf_read_register_with_status(PA_POWER2, NULL));
+    tr_debug("PA_POWER1: %x", rf_read_register_with_status(PA_POWER1, NULL));
+    tr_debug("PA_POWER0: %x", rf_read_register_with_status(PA_POWER0, NULL));
+    tr_debug("PA_CONFIG1: %x", rf_read_register_with_status(PA_CONFIG1, NULL));
+    tr_debug("PA_CONFIG0: %x", rf_read_register_with_status(PA_CONFIG0, NULL));
+    tr_debug("SYNTH_CONFIG2: %x", rf_read_register_with_status(SYNTH_CONFIG2, NULL));
+    tr_debug("VCO_CONFIG: %x", rf_read_register_with_status(VCO_CONFIG, NULL));
+    tr_debug("VCO_CALIBR_IN2: %x", rf_read_register_with_status(VCO_CALIBR_IN2, NULL));
+    tr_debug("VCO_CALIBR_IN1: %x", rf_read_register_with_status(VCO_CALIBR_IN1, NULL));
+    tr_debug("VCO_CALIBR_IN0: %x", rf_read_register_with_status(VCO_CALIBR_IN0, NULL));
+    tr_debug("XO_RCO_CONF1: %x", rf_read_register_with_status(XO_RCO_CONF1, NULL));
+    tr_debug("XO_RCO_CONF0: %x", rf_read_register_with_status(XO_RCO_CONF0, NULL));
+    tr_debug("RCO_CALIBR_CONF3: %x", rf_read_register_with_status(RCO_CALIBR_CONF3, NULL));
+    tr_debug("RCO_CALIBR_CONF2: %x", rf_read_register_with_status(RCO_CALIBR_CONF2, NULL));
+    tr_debug("PM_CONF4: %x", rf_read_register_with_status(PM_CONF4, NULL));
+    tr_debug("PM_CONF3: %x", rf_read_register_with_status(PM_CONF3, NULL));
+    tr_debug("PM_CONF2: %x", rf_read_register_with_status(PM_CONF2, NULL));
+    tr_debug("PM_CONF1: %x", rf_read_register_with_status(PM_CONF1, NULL));
+    tr_debug("PM_CONF0: %x", rf_read_register_with_status(PM_CONF0, NULL));
+    tr_debug("MC_STATE1: %x", rf_read_register_with_status(MC_STATE1, NULL));
+    tr_debug("MC_STATE0: %x", rf_read_register_with_status(MC_STATE0, NULL));
+    tr_debug("TX_FIFO_STATUS: %x", rf_read_register_with_status(TX_FIFO_STATUS, NULL));
+    tr_debug("RX_FIFO_STATUS: %x", rf_read_register_with_status(RX_FIFO_STATUS, NULL));
+    tr_debug("RCO_CALIBR_OUT4: %x", rf_read_register_with_status(RCO_CALIBR_OUT4, NULL));
+    tr_debug("RCO_CALIBR_OUT3: %x", rf_read_register_with_status(RCO_CALIBR_OUT3, NULL));
+    tr_debug("VCO_CALIBR_OUT1: %x", rf_read_register_with_status(VCO_CALIBR_OUT1, NULL));
+    tr_debug("VCO_CALIBR_OUT0: %x", rf_read_register_with_status(VCO_CALIBR_OUT0, NULL));
+    tr_debug("TX_PCKT_INFO: %x", rf_read_register_with_status(TX_PCKT_INFO, NULL));
+    tr_debug("RX_PCKT_INFO: %x", rf_read_register_with_status(RX_PCKT_INFO, NULL));
+    tr_debug("AFC_CORR: %x", rf_read_register_with_status(AFC_CORR, NULL));
+    tr_debug("LINK_QUALIF2: %x", rf_read_register_with_status(LINK_QUALIF2, NULL));
+    tr_debug("LINK_QUALIF1: %x", rf_read_register_with_status(LINK_QUALIF1, NULL));
+    tr_debug("RSSI_LEVEL: %x", rf_read_register_with_status(RSSI_LEVEL, NULL));
+    tr_debug("RX_PCKT_LEN1: %x", rf_read_register_with_status(RX_PCKT_LEN1, NULL));
+    tr_debug("RX_PCKT_LEN0: %x", rf_read_register_with_status(RX_PCKT_LEN0, NULL));
+    tr_debug("CRC_FIELD3: %x", rf_read_register_with_status(CRC_FIELD3, NULL));
+    tr_debug("CRC_FIELD2: %x", rf_read_register_with_status(CRC_FIELD2, NULL));
+    tr_debug("CRC_FIELD1: %x", rf_read_register_with_status(CRC_FIELD1, NULL));
+    tr_debug("CRC_FIELD0: %x", rf_read_register_with_status(CRC_FIELD0, NULL));
+    tr_debug("RX_ADDRE_FIELD1: %x", rf_read_register_with_status(RX_ADDRE_FIELD1, NULL));
+    tr_debug("RX_ADDRE_FIELD0: %x", rf_read_register_with_status(RX_ADDRE_FIELD0, NULL));
+    tr_debug("RSSI_LEVEL_RUN: %x", rf_read_register_with_status(RSSI_LEVEL_RUN, NULL));
+    tr_debug("DEVICE_INFO1: %x", rf_read_register_with_status(DEVICE_INFO1, NULL));
+    tr_debug("DEVICE_INFO0: %x", rf_read_register_with_status(DEVICE_INFO0, NULL));
+    tr_debug("IRQ_STATUS3: %x", rf_read_register_with_status(IRQ_STATUS3, NULL));
+    tr_debug("IRQ_STATUS2: %x", rf_read_register_with_status(IRQ_STATUS2, NULL));
+    tr_debug("IRQ_STATUS1: %x", rf_read_register_with_status(IRQ_STATUS1, NULL));
+    tr_debug("IRQ_STATUS0: %x", rf_read_register_with_status(IRQ_STATUS0, NULL));
+}
+
+#if MBED_CONF_S2LP_PROVIDE_DEFAULT
+NanostackRfPhy &NanostackRfPhy::get_default_instance()
+{
+    static NanostackRfPhys2lp rf_phy(S2LP_SPI_SDI, S2LP_SPI_SDO, S2LP_SPI_SCLK, S2LP_SPI_CS, S2LP_SPI_SDN,
+#ifdef TEST_GPIOS_ENABLED
+                                     S2LP_SPI_TEST1, S2LP_SPI_TEST2, S2LP_SPI_TEST3, S2LP_SPI_TEST4, S2LP_SPI_TEST5,
+#endif //TEST_GPIOS_ENABLED
+                                     S2LP_SPI_GPIO0, S2LP_SPI_GPIO1, S2LP_SPI_GPIO2, S2LP_SPI_GPIO3);
+    return rf_phy;
+}
+#endif // MBED_CONF_S2LP_PROVIDE_DEFAULT
+#endif // MBED_CONF_NANOSTACK_CONFIGURATION && DEVICE_SPI
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/stm-s2lp-rf-driver/source/rf_configuration.c	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,145 @@
+/*
+ * 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 "ns_types.h"
+#include "rf_configuration.h"
+#include "mbed_trace.h"
+
+#define TRACE_GROUP "rfcf"
+
+// Note that F_XO and F_DIG depends on the used clock frequency
+#define F_XO    50000000
+#define F_DIG   25000000
+// Note that reference divider depends on REFDIV field in XO_RCO_CONF0 register
+#define REF_DIVIDER     1
+// Note that band selector depends on BS field in SYNT3 register
+#define BAND_SELECTOR   4
+#define DEF_2EXP33  8589934592
+#define DEF_2EXP20  1048576
+#define DEF_2EXP19  524288
+#define DEF_2EXP16  65536
+#define DEF_2EXP15  32768
+// Use multiplier for better resolution
+#define RESOLUTION_MULTIPLIER   1000000
+
+void rf_conf_calculate_datarate_registers(uint32_t datarate, uint16_t *datarate_mantissa, uint8_t *datarate_exponent)
+{
+    uint64_t datarate_m = (uint64_t)datarate * DEF_2EXP33;
+    uint8_t datarate_e = 1;
+    while (datarate_m >= DEF_2EXP16) {
+        datarate_e++;
+        uint16_t var_2exp_datarate_e = (uint32_t)2 << (datarate_e - 1);
+        datarate_m = (uint64_t)datarate * DEF_2EXP33;
+        datarate_m = datarate_m / ((uint64_t)var_2exp_datarate_e * F_DIG);
+        datarate_m -= DEF_2EXP16;
+    }
+    *datarate_mantissa = datarate_m;
+    *datarate_exponent = datarate_e;
+}
+
+void rf_conf_calculate_base_frequency_registers(uint32_t frequency, uint8_t *synt3, uint8_t *synt2, uint8_t *synt1, uint8_t *synt0)
+{
+    uint64_t freq_tmp = (uint64_t)frequency * RESOLUTION_MULTIPLIER;
+    freq_tmp = (freq_tmp / (F_XO / ((BAND_SELECTOR / 2) * REF_DIVIDER)));
+    freq_tmp *= DEF_2EXP20;
+    freq_tmp /= RESOLUTION_MULTIPLIER;
+    *synt3 = (uint8_t)(freq_tmp >> 24);
+    *synt2 = (uint8_t)(freq_tmp >> 16);
+    *synt1 = (uint8_t)(freq_tmp >> 8);
+    *synt0 = (uint8_t)freq_tmp;
+}
+
+void rf_conf_calculate_deviation_registers(uint32_t deviation, uint8_t *fdev_m, uint8_t *fdev_e)
+{
+    uint64_t fdev_m_tmp = 0xffff;
+    uint8_t fdev_e_tmp = 1;
+
+    while (fdev_m_tmp > 255) {
+        fdev_e_tmp++;
+        uint16_t var_2exp_datarate_e_minus_1 = (uint16_t)2 << ((fdev_e_tmp - 1) - 1);
+        fdev_m_tmp = (uint64_t)deviation * RESOLUTION_MULTIPLIER;
+        fdev_m_tmp = (((fdev_m_tmp / F_XO) * DEF_2EXP19 * BAND_SELECTOR * REF_DIVIDER * (8 / BAND_SELECTOR)) / var_2exp_datarate_e_minus_1);
+        fdev_m_tmp += RESOLUTION_MULTIPLIER / 2;
+        fdev_m_tmp /= RESOLUTION_MULTIPLIER;
+        fdev_m_tmp -= 256;
+    }
+    *fdev_m = (uint8_t)fdev_m_tmp;
+    *fdev_e = fdev_e_tmp;
+}
+
+int rf_conf_calculate_channel_spacing_registers(uint32_t channel_spacing, uint8_t *ch_space)
+{
+    uint64_t ch_space_tmp = (uint64_t)channel_spacing * RESOLUTION_MULTIPLIER;
+    ch_space_tmp /= F_XO;
+    ch_space_tmp *= DEF_2EXP15;
+    ch_space_tmp += RESOLUTION_MULTIPLIER / 2;
+    ch_space_tmp /= RESOLUTION_MULTIPLIER;
+    // Check if channel spacing is too high
+    if (ch_space_tmp > 255) {
+        return -1;
+    }
+    *ch_space = (uint8_t)ch_space_tmp;
+    return 0;
+}
+
+/* Note: This function doesn't necessarily give the optimal RX filter settings.
+ * When accurate chflt_m and chflt_e settings are needed they must be computed manually.
+ * Function uses undefined values (900000, 852000, ...)
+ * to find the chflt_m and chflt_e settings from the RX filter table (see. S2-LP datasheet).
+ */
+void rf_conf_calculate_rx_filter_bandwidth_registers(uint32_t rx_bandwidth, uint8_t *chflt_m, uint8_t *chflt_e)
+{
+    uint8_t chflt_e_tmp = 0;
+    uint8_t chflt_m_tmp = 0;
+
+    while (rx_bandwidth < 900000 / (2 << chflt_e_tmp)) {
+        chflt_e_tmp++;
+    }
+    uint32_t rx_bandwidth_tmp = rx_bandwidth;
+    if (chflt_e_tmp > 0) {
+        rx_bandwidth_tmp = rx_bandwidth * (2 << (chflt_e_tmp - 1));
+    }
+    if (852000 > rx_bandwidth_tmp) {
+        chflt_m_tmp++;
+    }
+    if (806000 > rx_bandwidth_tmp) {
+        chflt_m_tmp++;
+    }
+    if (760000 > rx_bandwidth_tmp) {
+        chflt_m_tmp++;
+    }
+    if (724000 > rx_bandwidth_tmp) {
+        chflt_m_tmp++;
+    }
+    if (682000 > rx_bandwidth_tmp) {
+        chflt_m_tmp++;
+    }
+    if (650000 > rx_bandwidth_tmp) {
+        chflt_m_tmp++;
+    }
+    if (588000 > rx_bandwidth_tmp) {
+        chflt_m_tmp++;
+    }
+    if (542000 > rx_bandwidth_tmp) {
+        chflt_m_tmp++;
+    }
+    *chflt_m = chflt_m_tmp;
+    *chflt_e = chflt_e_tmp;
+}
+
+void rf_conf_calculate_rssi_threshold_registers(int16_t rssi_threshold, uint8_t *rssi_th)
+{
+    *rssi_th = rssi_threshold + RSSI_OFFSET;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/stm-s2lp-rf-driver/source/rf_configuration.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#ifndef RF_CONF_H_
+#define RF_CONF_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RSSI_OFFSET     146
+
+void rf_conf_calculate_datarate_registers(uint32_t datarate, uint16_t *datarate_mantissa, uint8_t *datarate_exponent);
+void rf_conf_calculate_base_frequency_registers(uint32_t frequency, uint8_t *synt3, uint8_t *synt2, uint8_t *synt1, uint8_t *synt0);
+void rf_conf_calculate_deviation_registers(uint32_t deviation, uint8_t *fdev_m, uint8_t *fdev_e);
+int rf_conf_calculate_channel_spacing_registers(uint32_t channel_spacing, uint8_t *ch_space);
+void rf_conf_calculate_rx_filter_bandwidth_registers(uint32_t rx_bandwidth, uint8_t *chflt_m, uint8_t *chflt_e);
+void rf_conf_calculate_rssi_threshold_registers(int16_t rssi_threshold, uint8_t *rssi_th);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RF_CONF_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/stm-s2lp-rf-driver/source/s2lpReg.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,332 @@
+/*
+ * 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.
+ */
+
+#ifndef S2LPREG_H_
+#define S2LPREG_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RF_MTU              2047
+#define PARTNUM             0x03
+#define VERSION             0xC1
+#define FIFO_SIZE           128
+#define SPI_HEADER_LENGTH   2
+
+#define S2LP_GPIO0   0
+#define S2LP_GPIO1   1
+#define S2LP_GPIO2   2
+#define S2LP_GPIO3   3
+
+// GPIO modes
+#define DIG_IN          1
+#define DIG_OUT_LOW     2
+#define DIG_OUT_HIGH    3
+
+// Interrupt events
+#define RX_DATA_READY           0
+#define RX_DATA_DISCARDED       1
+#define TX_DATA_SENT            2
+#define MAX_RE_TX               3
+#define CRC_ERROR               4
+#define TX_FIFO_UNF_OVF         5
+#define RX_FIFO_UNF_OVF         6
+#define TX_FIFO_ALMOST_FULL     7
+#define TX_FIFO_ALMOST_EMPTY    8
+#define RX_FIFO_ALMOST_FULL     9
+#define RX_FIFO_ALMOST_EMPTY    10
+#define MAX_CCA_BACKOFFS        11
+#define VALID_PREAMBLE          12
+#define SYNC_WORD               13
+#define RSSI_ABOVE_THR          14
+#define WAKE_UP_TIMEOUT         15
+#define READY                   16
+#define STANDBY_SWITCHING       17
+#define LOW_BATTERY_LVL         18
+#define POWER_ON_RESET          19
+#define RX_TIMER_TIMEOUT        28
+#define SNIFF_TIMER_TIMEOUT     29
+
+// GPIO signals
+#define NIRQ                                0
+#define POR                                 1
+#define WUT_EXPIRE                          2
+#define LOW_BATTERY                         3
+#define TX_DATA_OUTPUT                      4
+#define TX_STATE                            5
+#define TXRX_FIFO_ALMOST_EMPTY              6
+#define TXRX_FIFO_ALMOST_FULL               7
+#define RX_DATA_OUTPUT                      8
+#define RX_CLOCK_OUTPUT                     9
+#define RX_STATE                            10
+#define STATE_OTHER_THAN_SLEEP_OR_STANDBY   11
+#define STANDBY_STATE                       12
+#define ANTENNA_SWITCH                      13
+#define VALID_PREAMBLE_DETECTED             14
+#define SYNC_WORD_DETECTED                  15
+#define RSSI_ABOVE_THRESHOLD                16
+#define TXRX_MODE_INDICATOR                 18
+#define VDD                                 19
+#define GND                                 20
+#define SMPS_ENABLE                         21
+#define SLEEP_STATE                         22
+#define READY_STATE                         23
+#define LOCK_STATE                          24
+#define WAIT_LOCK_DETECTOR                  25
+#define TX_DATA_OOK                         26
+#define WAIT_READY                          27
+#define WAIT_TIMER_EXPIRATION               28
+#define END_OF_CALIBRATION                  29
+#define ENABLE_SYNTH_BLOCK                  30
+
+// RF registers
+#define GPIO0_CONF          0x00
+#define GPIO1_CONF          0x01
+#define GPIO2_CONF          0x02
+#define GPIO3_CONF          0x03
+#define SYNT3               0x05
+#define SYNT2               0x06
+#define SYNT1               0x07
+#define SYNT0               0x08
+#define IF_OFFSET_ANA       0x09
+#define IF_OFFSET_DIG       0x0A
+#define CHSPACE             0x0C
+#define CHNUM               0x0D
+#define MOD4                0x0E
+#define MOD3                0x0F
+#define MOD2                0x10
+#define MOD1                0x11
+#define MOD0                0x12
+#define CHFLT               0x13
+#define AFC2                0x14
+#define AFC1                0x15
+#define AFC0                0x16
+#define RSSI_FLT            0x17
+#define RSSI_TH             0x18
+#define AGCCTRL4            0x1A
+#define AGCCTRL3            0x1B
+#define AGCCTRL2            0x1C
+#define AGCCTRL1            0x1D
+#define AGCCTRL0            0x1E
+#define ANT_SELECT_CONF     0x1F
+#define CLOCKREC2           0x20
+#define CLOCKREC1           0x21
+#define PCKTCTRL6           0x2B
+#define PCKTCTRL5           0x2C
+#define PCKTCTRL4           0x2D
+#define PCKTCTRL3           0x2E
+#define PCKTCTRL2           0x2F
+#define PCKTCTRL1           0x30
+#define PCKTLEN1            0x31
+#define PCKTLEN0            0x32
+#define SYNC3               0x33
+#define SYNC2               0x34
+#define SYNC1               0x35
+#define SYNC0               0x36
+#define QI                  0x37
+#define PCKT_PSTMBL         0x38
+#define PROTOCOL2           0x39
+#define PROTOCOL1           0x3A
+#define PROTOCOL0           0x3B
+#define FIFO_CONFIG3        0x3C
+#define FIFO_CONFIG2        0x3D
+#define FIFO_CONFIG1        0x3E
+#define FIFO_CONFIG0        0x3F
+#define PCKT_FLT_OPTIONS    0x40
+#define PCKT_FLT_GOALS4     0x41
+#define PCKT_FLT_GOALS3     0x42
+#define PCKT_FLT_GOALS2     0x43
+#define PCKT_FLT_GOALS1     0x44
+#define PCKT_FLT_GOALS0     0x45
+#define TIMERS5             0x46
+#define TIMERS4             0x47
+#define TIMERS3             0x48
+#define TIMERS2             0x49
+#define TIMERS1             0x4A
+#define TIMERS0             0x4B
+#define CSMA_CONF3          0x4C
+#define CSMA_CONF2          0x4D
+#define CSMA_CONF1          0x4E
+#define CSMA_CONF0          0x4F
+#define IRQ_MASK3           0x50
+#define IRQ_MASK2           0x51
+#define IRQ_MASK1           0x52
+#define IRQ_MASK0           0x53
+#define FAST_RX_TIMER       0x54
+#define PA_POWER8           0x5A
+#define PA_POWER7           0x5B
+#define PA_POWER6           0x5C
+#define PA_POWER5           0x5D
+#define PA_POWER4           0x5E
+#define PA_POWER3           0x5F
+#define PA_POWER2           0x60
+#define PA_POWER1           0x61
+#define PA_POWER0           0x62
+#define PA_CONFIG1          0x63
+#define PA_CONFIG0          0x64
+#define SYNTH_CONFIG2       0x65
+#define VCO_CONFIG          0x68
+#define VCO_CALIBR_IN2      0x69
+#define VCO_CALIBR_IN1      0x6A
+#define VCO_CALIBR_IN0      0x6B
+#define XO_RCO_CONF1        0x6C
+#define XO_RCO_CONF0        0x6D
+#define RCO_CALIBR_CONF3    0x6E
+#define RCO_CALIBR_CONF2    0x6F
+#define PM_CONF4            0x75
+#define PM_CONF3            0x76
+#define PM_CONF2            0x77
+#define PM_CONF1            0x78
+#define PM_CONF0            0x79
+#define MC_STATE1           0x8D
+#define MC_STATE0           0x8E
+#define TX_FIFO_STATUS      0x8F
+#define RX_FIFO_STATUS      0x90
+#define RCO_CALIBR_OUT4     0x94
+#define RCO_CALIBR_OUT3     0x95
+#define VCO_CALIBR_OUT1     0x99
+#define VCO_CALIBR_OUT0     0x9A
+#define TX_PCKT_INFO        0x9C
+#define RX_PCKT_INFO        0x9D
+#define AFC_CORR            0x9E
+#define LINK_QUALIF2        0x9F
+#define LINK_QUALIF1        0xA0
+#define RSSI_LEVEL          0xA2
+#define RX_PCKT_LEN1        0xA4
+#define RX_PCKT_LEN0        0xA5
+#define CRC_FIELD3          0xA6
+#define CRC_FIELD2          0xA7
+#define CRC_FIELD1          0xA8
+#define CRC_FIELD0          0xA9
+#define RX_ADDRE_FIELD1     0xAA
+#define RX_ADDRE_FIELD0     0xAB
+#define RSSI_LEVEL_RUN      0xEF
+#define DEVICE_INFO1        0xF0
+#define DEVICE_INFO0        0xF1
+#define IRQ_STATUS3         0xFA
+#define IRQ_STATUS2         0xFB
+#define IRQ_STATUS1         0xFC
+#define IRQ_STATUS0         0xFD
+#define TX_FIFO             0xFF
+#define RX_FIFO             0xFF
+
+#define SFD0 0x90
+#define SFD1 0x4e
+
+#define DEVIATION               125000
+#define RX_FILTER_BANDWIDTH     540000
+#define RSSI_THRESHOLD          -60
+
+// PCKTCTRL6
+#define PCKT_SYNCLEN_FIELD      0xFC
+#define PCKT_SYNCLEN            (16 << 2)
+
+// PCKTCTRL5
+#define PCKT_PREAMBLE_LEN       32
+
+// PCKTCTRL3
+#define PCKT_FORMAT_FIELD       0xC0
+#define PCKT_FORMAT_802_15_4    (1 << 6)
+#define PCKT_RXMODE_FIELD       0x30
+#define PCKT_RXMODE_NORMAL      (0 << 4)
+
+// PCKTCTRL2
+#define PCKT_FIXVARLEN_FIELD    0x01
+#define PCKT_VARIABLE_LEN       (1 << 0)
+
+// PCKTCTRL1
+#define PCKT_CRCMODE_FIELD      0xE0
+#define PCKT_CRCMODE_0X1021     (3 << 5)
+#define PCKT_TXSOURCE_FIELD     0x0C
+#define PCKT_TXSOURCE_NORMAL    (0 << 2)
+#define PCKT_WHITENING_FIELD    0x10
+#define PCKT_WHITENING_ENABLED  (1 << 4)
+
+// MOD4
+#define DATARATE_M_MSB          0x47
+// MOD3
+#define DATARATE_M_LSB          0xAE
+
+// MOD2
+#define MOD_TYPE_FIELD          0xF0
+#define MOD_2FSK                (0 << 4)
+#define MOD_2GFSK               (10 << 4)
+#define DATARATE_E_FIELD        0x0F
+#define DATARATE_E              (10 << 0)
+
+// MOD1
+#define FDEV_E_FIELD            0x0F
+
+// QI
+#define PQI_TH_FIELD            0x1E
+#define PQI_TH                  (8 << 1)
+#define SQI_EN_FIELD            0x01
+#define SQI_EN                  (1 << 0)
+
+// SYNT3
+#define SYNT_FIELD              0x0F
+
+// CHFLT
+#define CHFLT_M_FIELD           0xF0
+#define CHFLT_E_FIELD           0x0F
+
+// LINK_QUALIF1
+#define CARRIER_SENSE           (1 << 7)
+
+#define SPI_WR_REG  0x00
+#define SPI_RD_REG  0x01
+#define SPI_CMD     0x80
+
+typedef enum {
+    S2LP_STATE_STANDBY      = 0x02,
+    S2LP_STATE_SLEEPA       = 0x01,
+    S2LP_STATE_SLEEPB       = 0x03,
+    S2LP_STATE_READY        = 0x00,
+    S2LP_STATE_LOCK         = 0x0C,
+    S2LP_STATE_RX           = 0x30,
+    S2LP_STATE_TX           = 0x5C,
+    S2LP_STATE_SYNTH_SETUP  = 0x50
+} s2lp_states_e;
+
+typedef enum {
+    S2LP_CMD_TX = 0x60,
+    S2LP_CMD_RX,
+    S2LP_CMD_READY,
+    S2LP_CMD_STANDBY,
+    S2LP_CMD_SLEEP,
+    S2LP_CMD_LOCKRX,
+    S2LP_CMD_LOCKTX,
+    S2LP_CMD_SABORT,
+    S2LP_CMD_LDC_RELOAD,
+    S2LP_CMD_SRES = 0x70,
+    S2LP_CMD_FLUSHRXFIFO,
+    S2LP_CMD_FLUSHTXFIFO,
+    S2LP_CMD_SEQUPDATE
+} s2lp_commands_e;
+
+typedef enum {
+    RF_IDLE,
+    RF_CSMA_STARTED,
+    RF_TX_STARTED,
+    RF_RX_STARTED,
+    RF_TX_ACK
+} rf_states_e;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* S2LPREG_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/802_15_4_RF/stm-s2lp-rf-driver/stm-s2lp-rf-driver/NanostackRfPhys2lp.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+#ifndef NANOSTACK_PHY_S2LP_H_
+#define NANOSTACK_PHY_S2LP_H_
+
+#include "mbed.h"
+#if defined(MBED_CONF_NANOSTACK_CONFIGURATION) && DEVICE_SPI
+#include "NanostackRfPhy.h"
+
+// Uncomment to use testing gpios attached to TX/RX processes
+//#define TEST_GPIOS_ENABLED
+
+#if !defined(S2LP_SPI_SDI)
+#define S2LP_SPI_SDI   D11
+#endif
+#if !defined(S2LP_SPI_SDO)
+#define S2LP_SPI_SDO   D12
+#endif
+#if !defined(S2LP_SPI_SCLK)
+#define S2LP_SPI_SCLK   D13
+#endif
+#if !defined(S2LP_SPI_CS)
+#define S2LP_SPI_CS     A1
+#endif
+#if !defined(S2LP_SPI_SDN)
+#define S2LP_SPI_SDN    D7
+#endif
+#if !defined(S2LP_SPI_TEST1)
+#define S2LP_SPI_TEST1    D6
+#endif
+#if !defined(S2LP_SPI_TEST2)
+#define S2LP_SPI_TEST2    D5
+#endif
+#if !defined(S2LP_SPI_TEST3)
+#define S2LP_SPI_TEST3    D4
+#endif
+#if !defined(S2LP_SPI_TEST4)
+#define S2LP_SPI_TEST4    D2
+#endif
+#if !defined(S2LP_SPI_TEST5)
+#define S2LP_SPI_TEST5    D8
+#endif
+#if !defined(S2LP_SPI_GPIO0)
+#define S2LP_SPI_GPIO0    A0
+#endif
+#if !defined(S2LP_SPI_GPIO1)
+#define S2LP_SPI_GPIO1    A2
+#endif
+#if !defined(S2LP_SPI_GPIO2)
+#define S2LP_SPI_GPIO2    A3
+#endif
+#if !defined(S2LP_SPI_GPIO3)
+#define S2LP_SPI_GPIO3    A5
+#endif
+
+class RFPins;
+
+class NanostackRfPhys2lp : public NanostackRfPhy {
+public:
+    NanostackRfPhys2lp(PinName spi_sdi, PinName spi_sdo,
+                       PinName spi_sclk, PinName spi_cs,  PinName spi_sdn,
+#ifdef TEST_GPIOS_ENABLED
+                       PinName spi_test1, PinName spi_test2, PinName spi_test3, PinName spi_test4, PinName spi_test5,
+#endif //TEST_GPIOS_ENABLED
+                       PinName spi_gpio0, PinName spi_gpio1, PinName spi_gpio2, PinName spi_gpio3);
+    virtual ~NanostackRfPhys2lp();
+    virtual int8_t rf_register();
+    virtual void rf_unregister();
+    virtual void get_mac_address(uint8_t *mac);
+    virtual void set_mac_address(uint8_t *mac);
+
+private:
+    uint8_t _mac_addr[8];
+    RFPins *_rf;
+    bool _mac_set;
+
+    const PinName _spi_sdi;
+    const PinName _spi_sdo;
+    const PinName _spi_sclk;
+    const PinName _spi_cs;
+    const PinName _spi_sdn;
+#ifdef TEST_GPIOS_ENABLED
+    const PinName _spi_test1;
+    const PinName _spi_test2;
+    const PinName _spi_test3;
+    const PinName _spi_test4;
+    const PinName _spi_test5;
+#endif //TEST_GPIOS_ENABLED
+    const PinName _spi_gpio0;
+    const PinName _spi_gpio1;
+    const PinName _spi_gpio2;
+    const PinName _spi_gpio3;
+};
+#endif /* MBED_CONF_NANOSTACK_CONFIGURATION && DEVICE_SPI */
+#endif /* NANOSTACK_PHY_S2LP_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_DATAFLASH/DataFlashBlockDevice.cpp	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,821 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2016 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 "DataFlashBlockDevice.h"
+#include "mbed_critical.h"
+
+#include <inttypes.h>
+
+/* constants */
+#define DATAFLASH_READ_SIZE        1
+#define DATAFLASH_PROG_SIZE        1
+#define DATAFLASH_TIMEOUT          10000
+#define DATAFLASH_ID_MATCH         0x1F20
+#define DATAFLASH_ID_DENSITY_MASK  0x001F
+#define DATAFLASH_PAGE_SIZE_256    0x0100
+#define DATAFLASH_PAGE_SIZE_264    0x0108
+#define DATAFLASH_PAGE_SIZE_512    0x0200
+#define DATAFLASH_PAGE_SIZE_528    0x0210
+#define DATAFLASH_BLOCK_SIZE_2K    0x0800
+#define DATAFLASH_BLOCK_SIZE_2K1   0x0840
+#define DATAFLASH_BLOCK_SIZE_4K    0x1000
+#define DATAFLASH_BLOCK_SIZE_4K1   0x1080
+#define DATAFLASH_PAGE_BIT_264     9
+#define DATAFLASH_PAGE_BIT_528     10
+
+/* enable debug */
+#ifndef DATAFLASH_DEBUG
+#define DATAFLASH_DEBUG 0
+#endif /* DATAFLASH_DEBUG */
+
+#if DATAFLASH_DEBUG
+#define DEBUG_PRINTF(...) printf(__VA_ARGS__)
+#else
+#define DEBUG_PRINTF(...)
+#endif
+
+void _print_status(uint16_t status);
+
+/* non-exhaustive opcode list */
+enum opcode {
+    DATAFLASH_OP_NOP                       = 0x00,
+    DATAFLASH_OP_STATUS                    = 0xD7,
+    DATAFLASH_OP_ID                        = 0x9F,
+    DATAFLASH_OP_READ_LOW_POWER            = 0x01,
+    DATAFLASH_OP_READ_LOW_FREQUENCY        = 0x03,
+    DATAFLASH_OP_PROGRAM_DIRECT            = 0x02, // Program through Buffer 1 without Built-In Erase
+    DATAFLASH_OP_PROGRAM_DIRECT_WITH_ERASE = 0x82,
+    DATAFLASH_OP_ERASE_BLOCK               = 0x50,
+};
+
+/* non-exhaustive command list */
+enum command {
+    DATAFLASH_COMMAND_WRITE_DISABLE        = 0x3D2A7FA9,
+    DATAFLASH_COMMAND_WRITE_ENABLE         = 0x3D2A7F9A,
+    DATAFLASH_COMMAND_BINARY_PAGE_SIZE     = 0x3D2A80A6,
+    DATAFLASH_COMMAND_DATAFLASH_PAGE_SIZE  = 0x3D2A80A7,
+};
+
+/* bit masks for interpreting the status register */
+enum status_bit {
+    DATAFLASH_BIT_READY                = (0x01 << 15),
+    DATAFLASH_BIT_COMPARE              = (0x01 << 14),
+    DATAFLASH_BIT_DENSITY              = (0x0F << 10),
+    DATAFLASH_BIT_PROTECT              = (0x01 <<  9),
+    DATAFLASH_BIT_PAGE_SIZE            = (0x01 <<  8),
+
+    DATAFLASH_BIT_ERASE_PROGRAM_ERROR  = (0x01 <<  5),
+    DATAFLASH_BIT_SECTOR_LOCKDOWN      = (0x01 <<  3),
+    DATAFLASH_BIT_PROGRAM_SUSPEND_2    = (0x01 <<  2),
+    DATAFLASH_BIT_PROGRAM_SUSPEND_1    = (0x01 <<  1),
+    DATAFLASH_BIT_ERASE_SUSPEND        = (0x01 <<  0),
+};
+
+/* bit masks for detecting density from status register */
+enum status_density {
+    DATAFLASH_STATUS_DENSITY_2_MBIT    = (0x05 << 10),
+    DATAFLASH_STATUS_DENSITY_4_MBIT    = (0x07 << 10),
+    DATAFLASH_STATUS_DENSITY_8_MBIT    = (0x09 << 10),
+    DATAFLASH_STATUS_DENSITY_16_MBIT   = (0x0B << 10),
+    DATAFLASH_STATUS_DENSITY_32_MBIT   = (0x0D << 10),
+    DATAFLASH_STATUS_DENSITY_64_MBIT   = (0x0F << 10),
+};
+
+/* code for calculating density */
+enum id_density {
+    DATAFLASH_ID_DENSITY_2_MBIT    = 0x03,
+    DATAFLASH_ID_DENSITY_4_MBIT    = 0x04,
+    DATAFLASH_ID_DENSITY_8_MBIT    = 0x05,
+    DATAFLASH_ID_DENSITY_16_MBIT   = 0x06,
+    DATAFLASH_ID_DENSITY_32_MBIT   = 0x07,
+    DATAFLASH_ID_DENSITY_64_MBIT   = 0x08,
+};
+
+/* typical duration in milliseconds for each operation */
+enum timing {
+    DATAFLASH_TIMING_ERASE_PROGRAM_PAGE   =    17,
+    DATAFLASH_TIMING_PROGRAM_PAGE         =     3,
+    DATAFLASH_TIMING_ERASE_PAGE           =    12,
+    DATAFLASH_TIMING_ERASE_BLOCK          =    45,
+    DATAFLASH_TIMING_ERASE_SECTOR         =   700,
+    DATAFLASH_TIMING_ERASE_CHIP           = 45000
+};
+
+/* frequency domains */
+enum frequency {
+    DATAFLASH_LOW_POWER_FREQUENCY =  15000000,
+    DATAFLASH_LOW_FREQUENCY       =  50000000,
+    DATAFLASH_HIGH_FREQUENCY      =  85000000,
+    DATAFLASH_HIGHEST_FREQUENCY   = 104000000
+};
+
+/* number of dummy bytes required in each frequency domain */
+enum dummy {
+    DATAFLASH_LOW_POWER_BYTES         = 0,
+    DATAFLASH_LOW_FREQUENCY_BYTES     = 0,
+    DATAFLASH_HIGH_FREQUENCY_BYTES    = 1,
+    DATAFLASH_HIGHEST_FREQUENCY_BYTES = 2
+};
+
+DataFlashBlockDevice::DataFlashBlockDevice(PinName mosi,
+                                           PinName miso,
+                                           PinName sclk,
+                                           PinName cs,
+                                           int freq,
+                                           PinName nwp)
+    :   _spi(mosi, miso, sclk),
+        _cs(cs, 1),
+        _nwp(nwp),
+        _device_size(0),
+        _page_size(0),
+        _block_size(0),
+        _is_initialized(0),
+        _init_ref_count(0)
+{
+    /* check that frequency is within range */
+    if (freq > DATAFLASH_LOW_FREQUENCY) {
+
+        /* cap frequency at the highest supported one */
+        _spi.frequency(DATAFLASH_LOW_FREQUENCY);
+
+    } else {
+        /* freqency is valid, use as-is */
+        _spi.frequency(freq);
+    }
+
+    /* write protect chip if pin is connected */
+    if (nwp != NC) {
+        _nwp = 0;
+    }
+}
+
+int DataFlashBlockDevice::init()
+{
+    _mutex.lock();
+    DEBUG_PRINTF("init\r\n");
+
+    if (!_is_initialized) {
+        _init_ref_count = 0;
+    }
+
+    uint32_t val = core_util_atomic_incr_u32(&_init_ref_count, 1);
+
+    if (val != 1) {
+        _mutex.unlock();
+        return BD_ERROR_OK;
+    }
+
+    int result = BD_ERROR_DEVICE_ERROR;
+
+    /* read ID register to validate model and set dimensions */
+    uint16_t id = _get_register(DATAFLASH_OP_ID);
+
+    DEBUG_PRINTF("id: %04X\r\n", id & DATAFLASH_ID_MATCH);
+
+    /* get status register to verify the page size mode */
+    uint16_t status = _get_register(DATAFLASH_OP_STATUS);
+
+    /* manufacture ID match */
+    if ((id & DATAFLASH_ID_MATCH) == DATAFLASH_ID_MATCH) {
+
+        /* calculate density */
+        _device_size = 0x8000 << (id & DATAFLASH_ID_DENSITY_MASK);
+
+        bool binary_page_size = true;
+
+        /* check if device is configured for binary page sizes */
+        if ((status & DATAFLASH_BIT_PAGE_SIZE) == DATAFLASH_BIT_PAGE_SIZE) {
+            DEBUG_PRINTF("Page size is binary\r\n");
+
+#if MBED_CONF_DATAFLASH_DATAFLASH_SIZE
+            /* send reconfiguration command */
+            _write_command(DATAFLASH_COMMAND_DATAFLASH_PAGE_SIZE, NULL, 0);
+
+            /* wait for device to be ready and update return code */
+            result = _sync();
+
+            /* set binary flag */
+            binary_page_size = false;
+#else
+            /* set binary flag */
+            binary_page_size = true;
+#endif
+        } else {
+            DEBUG_PRINTF("Page size is not binary\r\n");
+
+#if MBED_CONF_DATAFLASH_BINARY_SIZE
+            /* send reconfiguration command */
+            _write_command(DATAFLASH_COMMAND_BINARY_PAGE_SIZE, NULL, 0);
+
+            /* wait for device to be ready and update return code */
+            result = _sync();
+
+            /* set binary flag */
+            binary_page_size = true;
+#else
+            /* set binary flag */
+            binary_page_size = false;
+#endif
+        }
+
+        /* set page program size and block erase size */
+        switch (id & DATAFLASH_ID_DENSITY_MASK) {
+            case DATAFLASH_ID_DENSITY_2_MBIT:
+            case DATAFLASH_ID_DENSITY_4_MBIT:
+            case DATAFLASH_ID_DENSITY_8_MBIT:
+            case DATAFLASH_ID_DENSITY_64_MBIT:
+                if (binary_page_size) {
+                    _page_size = DATAFLASH_PAGE_SIZE_256;
+                    _block_size = DATAFLASH_BLOCK_SIZE_2K;
+                } else {
+                    _page_size = DATAFLASH_PAGE_SIZE_264;
+                    _block_size = DATAFLASH_BLOCK_SIZE_2K1;
+
+                    /* adjust device size */
+                    _device_size = (_device_size / DATAFLASH_PAGE_SIZE_256) *
+                                   DATAFLASH_PAGE_SIZE_264;
+                }
+                break;
+            case DATAFLASH_ID_DENSITY_16_MBIT:
+            case DATAFLASH_ID_DENSITY_32_MBIT:
+                if (binary_page_size) {
+                    _page_size = DATAFLASH_PAGE_SIZE_512;
+                    _block_size = DATAFLASH_BLOCK_SIZE_4K;
+                } else {
+                    _page_size = DATAFLASH_PAGE_SIZE_528;
+                    _block_size = DATAFLASH_BLOCK_SIZE_4K1;
+
+                    /* adjust device size */
+                    _device_size = (_device_size / DATAFLASH_PAGE_SIZE_512) *
+                                   DATAFLASH_PAGE_SIZE_528;
+                }
+                break;
+            default:
+                break;
+        }
+
+        DEBUG_PRINTF("density: %" PRIu16 "\r\n", id & DATAFLASH_ID_DENSITY_MASK);
+        DEBUG_PRINTF("size: %" PRIu32 "\r\n", _device_size);
+        DEBUG_PRINTF("page: %" PRIu16 "\r\n", _page_size);
+        DEBUG_PRINTF("block: %" PRIu16 "\r\n", _block_size);
+
+        /* device successfully detected, set OK error code */
+        result = BD_ERROR_OK;
+    }
+
+    /* write protect device when idle */
+    _write_enable(false);
+
+    if (result == BD_ERROR_OK) {
+        _is_initialized = true;
+    }
+
+    _mutex.unlock();
+    return result;
+}
+
+int DataFlashBlockDevice::deinit()
+{
+    _mutex.lock();
+    DEBUG_PRINTF("deinit\r\n");
+
+    if (!_is_initialized) {
+        _init_ref_count = 0;
+        _mutex.unlock();
+        return BD_ERROR_OK;
+    }
+
+    uint32_t val = core_util_atomic_decr_u32(&_init_ref_count, 1);
+
+    if (val) {
+        _mutex.unlock();
+        return BD_ERROR_OK;
+    }
+
+    _is_initialized = false;
+    _mutex.unlock();
+    return BD_ERROR_OK;
+}
+
+int DataFlashBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
+{
+    _mutex.lock();
+    DEBUG_PRINTF("read: %p %" PRIX64 " %" PRIX64 "\r\n", buffer, addr, size);
+
+    if (!_is_initialized) {
+        _mutex.unlock();
+        return BD_ERROR_DEVICE_ERROR;
+    }
+
+    int result = BD_ERROR_DEVICE_ERROR;
+
+    /* check parameters are valid and the read is within bounds */
+    if (is_valid_read(addr, size) && buffer) {
+
+        uint8_t *external_buffer = static_cast<uint8_t *>(buffer);
+
+        /* activate device */
+        _cs = 0;
+
+        /* send read opcode */
+        _spi.write(DATAFLASH_OP_READ_LOW_FREQUENCY);
+
+        /* translate address */
+        uint32_t address = _translate_address(addr);
+
+        DEBUG_PRINTF("address: %" PRIX32 "\r\n", address);
+
+        /* send read address */
+        _spi.write((address >> 16) & 0xFF);
+        _spi.write((address >>  8) & 0xFF);
+        _spi.write(address & 0xFF);
+
+        /* clock out one byte at a time and store in external buffer */
+        for (uint32_t index = 0; index < size; index++) {
+            external_buffer[index] = _spi.write(DATAFLASH_OP_NOP);
+        }
+
+        /* deactivate device */
+        _cs = 1;
+
+        result = BD_ERROR_OK;
+    }
+
+    _mutex.unlock();
+    return result;
+}
+
+int DataFlashBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size)
+{
+    _mutex.lock();
+    DEBUG_PRINTF("program: %p %" PRIX64 " %" PRIX64 "\r\n", buffer, addr, size);
+
+    if (!_is_initialized) {
+        _mutex.unlock();
+        return BD_ERROR_DEVICE_ERROR;
+    }
+
+    int result = BD_ERROR_DEVICE_ERROR;
+
+    /* check parameters are valid and the write is within bounds */
+    if (is_valid_program(addr, size) && buffer) {
+
+        const uint8_t *external_buffer = static_cast<const uint8_t *>(buffer);
+
+        /* Each write command can only cover one page at a time.
+           Find page and current page offset for handling unaligned writes.
+         */
+        uint32_t page_number = addr / _page_size;
+        uint32_t page_offset = addr % _page_size;
+
+        /* disable write protection */
+        _write_enable(true);
+
+        /* continue until all bytes have been written */
+        uint32_t bytes_written = 0;
+        while (bytes_written < size) {
+
+            /* find remaining bytes to be written */
+            uint32_t bytes_remaining = size - bytes_written;
+
+            /* cap the value at the page size and offset */
+            if (bytes_remaining > (_page_size - page_offset)) {
+                bytes_remaining = _page_size - page_offset;
+            }
+
+            /* Write one page, bytes_written keeps track of the progress,
+               page_number is the page address, and page_offset is non-zero for
+               unaligned writes.
+             */
+            result = _write_page(&external_buffer[bytes_written],
+                                 page_number,
+                                 page_offset,
+                                 bytes_remaining);
+
+            /* update loop variables upon success otherwise break loop */
+            if (result == BD_ERROR_OK) {
+                bytes_written += bytes_remaining;
+                page_number++;
+
+                /* After the first successful write,
+                   all subsequent writes will be aligned.
+                 */
+                page_offset = 0;
+            } else {
+                break;
+            }
+        }
+
+        /* enable write protection */
+        _write_enable(false);
+    }
+
+    _mutex.unlock();
+    return result;
+}
+
+int DataFlashBlockDevice::erase(bd_addr_t addr, bd_size_t size)
+{
+    _mutex.lock();
+    DEBUG_PRINTF("erase: %" PRIX64 " %" PRIX64 "\r\n", addr, size);
+
+    if (!_is_initialized) {
+        _mutex.unlock();
+        return BD_ERROR_DEVICE_ERROR;
+    }
+
+    int result = BD_ERROR_DEVICE_ERROR;
+
+    /* check parameters are valid and the erase is within bounds */
+    if (is_valid_erase(addr, size)) {
+
+        /* disable write protection */
+        _write_enable(true);
+
+        /* erase one block at a time until the full size has been erased */
+        uint32_t erased = 0;
+        while (erased < size) {
+
+            /* set block erase opcode */
+            uint32_t command = DATAFLASH_OP_ERASE_BLOCK;
+
+            /* translate address */
+            uint32_t address = _translate_address(addr);
+
+            /* set block address */
+            command = (command << 8) | ((address >> 16) & 0xFF);
+            command = (command << 8) | ((address >>  8) & 0xFF);
+            command = (command << 8) | (address & 0xFF);
+
+            /* send command to device */
+            _write_command(command, NULL, 0);
+
+            /* wait until device is ready and update return value */
+            result = _sync();
+
+            /* if erase failed, break loop */
+            if (result != BD_ERROR_OK) {
+                break;
+            }
+
+            /* update loop variables */
+            addr += _block_size;
+            erased += _block_size;
+        }
+
+        /* enable write protection */
+        _write_enable(false);
+    }
+
+    _mutex.unlock();
+    return result;
+}
+
+bd_size_t DataFlashBlockDevice::get_read_size() const
+{
+    DEBUG_PRINTF("read size: %d\r\n", DATAFLASH_READ_SIZE);
+
+    return DATAFLASH_READ_SIZE;
+}
+
+bd_size_t DataFlashBlockDevice::get_program_size() const
+{
+    DEBUG_PRINTF("program size: %d\r\n", DATAFLASH_PROG_SIZE);
+
+    return DATAFLASH_PROG_SIZE;
+}
+
+bd_size_t DataFlashBlockDevice::get_erase_size() const
+{
+    _mutex.lock();
+    DEBUG_PRINTF("erase size: %" PRIX16 "\r\n", _block_size);
+    bd_size_t block_size = _block_size;
+    _mutex.unlock();
+    return block_size;
+}
+
+bd_size_t DataFlashBlockDevice::get_erase_size(bd_addr_t addr) const
+{
+    _mutex.lock();
+    DEBUG_PRINTF("erase size: %" PRIX16 "\r\n", _block_size);
+    bd_size_t block_size = _block_size;
+    _mutex.unlock();
+    return block_size;
+}
+
+bd_size_t DataFlashBlockDevice::size() const
+{
+    _mutex.lock();
+    DEBUG_PRINTF("device size: %" PRIX32 "\r\n", _device_size);
+    bd_size_t device_size = _device_size;
+    _mutex.unlock();
+    return device_size;
+}
+
+/**
+ * @brief Function for reading a specific register.
+ * @details Used for reading either the Status Register or Manufacture and ID Register.
+ *
+ * @param opcode Register to be read.
+ * @return value.
+ */
+uint16_t DataFlashBlockDevice::_get_register(uint8_t opcode)
+{
+    _mutex.lock();
+    DEBUG_PRINTF("_get_register: %" PRIX8 "\r\n", opcode);
+
+    /* activate device */
+    _cs = 0;
+
+    /* write opcode */
+    _spi.write(opcode);
+
+    /* read and store result */
+    int status = (_spi.write(DATAFLASH_OP_NOP));
+    status = (status << 8) | (_spi.write(DATAFLASH_OP_NOP));
+
+    /* deactivate device */
+    _cs = 1;
+
+    _mutex.unlock();
+    return status;
+}
+
+/**
+ * @brief Function for sending command and data to device.
+ * @details The command can be an opcode with address and data or
+ *          a 4 byte command without data.
+ *
+ *          The supported frequencies and the opcode used do not
+ *          require dummy bytes to be sent after command.
+ *
+ * @param command Opcode with address or 4 byte command.
+ * @param buffer Data to be sent after command.
+ * @param size Size of buffer.
+ */
+void DataFlashBlockDevice::_write_command(uint32_t command, const uint8_t *buffer, uint32_t size)
+{
+    DEBUG_PRINTF("_write_command: %" PRIX32 " %p %" PRIX32 "\r\n", command, buffer, size);
+
+    /* activate device */
+    _cs = 0;
+
+    /* send command (opcode with data or 4 byte command) */
+    _spi.write((command >> 24) & 0xFF);
+    _spi.write((command >> 16) & 0xFF);
+    _spi.write((command >>  8) & 0xFF);
+    _spi.write(command & 0xFF);
+
+    /* send optional data */
+    if (buffer && size) {
+        for (uint32_t index = 0; index < size; index++) {
+            _spi.write(buffer[index]);
+        }
+    }
+
+    /* deactivate device */
+    _cs = 1;
+}
+
+/**
+ * @brief Enable and disable write protection.
+ *
+ * @param enable Boolean for enabling or disabling write protection.
+ */
+void DataFlashBlockDevice::_write_enable(bool enable)
+{
+    DEBUG_PRINTF("_write_enable: %d\r\n", enable);
+
+    /* enable writing, disable write protection */
+    if (enable) {
+        /* if not-write-protected pin is connected, select it */
+        if (_nwp.is_connected()) {
+            _nwp = 1;
+        }
+
+        /* send 4 byte command enabling writes */
+        _write_command(DATAFLASH_COMMAND_WRITE_ENABLE, NULL, 0);
+    } else {
+
+        /* if not-write-protected pin is connected, deselect it */
+        if (_nwp.is_connected()) {
+            _nwp = 0;
+        }
+
+        /* send 4 byte command disabling writes */
+        _write_command(DATAFLASH_COMMAND_WRITE_DISABLE, NULL, 0);
+    }
+}
+
+/**
+ * @brief Sleep and poll status register until device is ready for next command.
+ *
+ * @return BlockDevice compatible error code.
+ */
+int DataFlashBlockDevice::_sync(void)
+{
+    DEBUG_PRINTF("_sync\r\n");
+
+    /* default return value if operation times out */
+    int result = BD_ERROR_DEVICE_ERROR;
+
+    /* Poll device until a hard coded timeout is reached.
+       The polling interval is based on the typical page program time.
+     */
+    for (uint32_t timeout = 0;
+            timeout < DATAFLASH_TIMEOUT;
+            timeout += DATAFLASH_TIMING_ERASE_PROGRAM_PAGE) {
+
+        /* get status register */
+        uint16_t status = _get_register(DATAFLASH_OP_STATUS);
+
+        /* erase/program bit set, exit with error code set */
+        if (status & DATAFLASH_BIT_ERASE_PROGRAM_ERROR) {
+            DEBUG_PRINTF("DATAFLASH_BIT_ERASE_PROGRAM_ERROR\r\n");
+            break;
+            /* device ready, set OK code set */
+        } else if (status & DATAFLASH_BIT_READY) {
+            DEBUG_PRINTF("DATAFLASH_BIT_READY\r\n");
+            result = BD_ERROR_OK;
+            break;
+            /* wait the typical write period before trying again */
+        } else {
+            DEBUG_PRINTF("wait_ms: %d\r\n", DATAFLASH_TIMING_ERASE_PROGRAM_PAGE);
+            wait_ms(DATAFLASH_TIMING_ERASE_PROGRAM_PAGE);
+        }
+    }
+
+    return result;
+}
+
+/**
+ * @brief Write single page.
+ * @details Address can be unaligned.
+ *
+ * @param buffer Data to write.
+ * @param addr Address to write from.
+ * @param size Bytes to write. Can at most be the full page.
+ * @return BlockDevice error code.
+ */
+int DataFlashBlockDevice::_write_page(const uint8_t *buffer,
+                                      uint32_t page,
+                                      uint32_t offset,
+                                      uint32_t size)
+{
+    DEBUG_PRINTF("_write_page: %p %" PRIX32 " %" PRIX32 "\r\n", buffer, page, size);
+
+    uint32_t command = DATAFLASH_OP_NOP;
+
+    /* opcode for writing directly to device, in a single command,
+       assuming the page has been erased before hand.
+     */
+    command = DATAFLASH_OP_PROGRAM_DIRECT;
+
+    uint32_t address = 0;
+
+    /* convert page number and offset into device address based on address format */
+    if (_page_size == DATAFLASH_PAGE_SIZE_264) {
+        address = (page << DATAFLASH_PAGE_BIT_264) | offset;
+    } else if (_page_size == DATAFLASH_PAGE_SIZE_528) {
+        address = (page << DATAFLASH_PAGE_BIT_528) | offset;
+    } else {
+        address = (page * _page_size) | offset;
+    }
+
+    /* set write address */
+    command = (command << 8) | ((address >> 16) & 0xFF);
+    command = (command << 8) | ((address >>  8) & 0xFF);
+    command = (command << 8) | (address & 0xFF);
+
+    /* send write command with data */
+    _write_command(command, buffer, size);
+
+    /* wait until device is ready before continuing */
+    int result = _sync();
+
+    return result;
+}
+
+/**
+ * @brief Translate address.
+ * @details If the device is configured for non-binary page sizes,
+ *          the address is translated from binary to non-binary form.
+ *
+ * @param addr Binary address.
+ * @return Address in format expected by device.
+ */
+uint32_t DataFlashBlockDevice::_translate_address(bd_addr_t addr)
+{
+    uint32_t address = addr;
+
+    /* translate address if page size is non-binary */
+    if (_page_size == DATAFLASH_PAGE_SIZE_264) {
+        address = ((addr / DATAFLASH_PAGE_SIZE_264) << DATAFLASH_PAGE_BIT_264) |
+                  (addr % DATAFLASH_PAGE_SIZE_264);
+    } else if (_page_size == DATAFLASH_PAGE_SIZE_528) {
+        address = ((addr / DATAFLASH_PAGE_SIZE_528) << DATAFLASH_PAGE_BIT_528) |
+                  (addr % DATAFLASH_PAGE_SIZE_528);
+    }
+
+    return address;
+}
+
+/**
+ * @brief Internal function for printing out each bit set in status register.
+ *
+ * @param status Status register.
+ */
+void _print_status(uint16_t status)
+{
+#if DATAFLASH_DEBUG
+    DEBUG_PRINTF("%04X\r\n", status);
+
+    /* device is ready (after write/erase) */
+    if (status & DATAFLASH_BIT_READY) {
+        DEBUG_PRINTF("DATAFLASH_BIT_READY\r\n");
+    }
+
+    /* Buffer comparison failed */
+    if (status & DATAFLASH_BIT_COMPARE) {
+        DEBUG_PRINTF("DATAFLASH_BIT_COMPARE\r\n");
+    }
+
+    /* device size is 2 MB */
+    if (status & DATAFLASH_STATUS_DENSITY_2_MBIT) {
+        DEBUG_PRINTF("DATAFLASH_STATUS_DENSITY_2_MBIT\r\n");
+    }
+
+    /* device size is 4 MB */
+    if (status & DATAFLASH_STATUS_DENSITY_4_MBIT) {
+        DEBUG_PRINTF("DATAFLASH_STATUS_DENSITY_4_MBIT\r\n");
+    }
+
+    /* device size is 8 MB */
+    if (status & DATAFLASH_STATUS_DENSITY_8_MBIT) {
+        DEBUG_PRINTF("DATAFLASH_STATUS_DENSITY_8_MBIT\r\n");
+    }
+
+    /* device size is 16 MB */
+    if (status & DATAFLASH_STATUS_DENSITY_16_MBIT) {
+        DEBUG_PRINTF("DATAFLASH_STATUS_DENSITY_16_MBIT\r\n");
+    }
+
+    /* device size is 32 MB */
+    if (status & DATAFLASH_STATUS_DENSITY_32_MBIT) {
+        DEBUG_PRINTF("DATAFLASH_STATUS_DENSITY_32_MBIT\r\n");
+    }
+
+    /* device size is 64 MB */
+    if (status & DATAFLASH_STATUS_DENSITY_64_MBIT) {
+        DEBUG_PRINTF("DATAFLASH_STATUS_DENSITY_64_MBIT\r\n");
+    }
+
+    /* sector protectino enabled */
+    if (status & DATAFLASH_BIT_PROTECT) {
+        DEBUG_PRINTF("DATAFLASH_BIT_PROTECT\r\n");
+    }
+
+    /* page size is a power of 2 */
+    if (status & DATAFLASH_BIT_PAGE_SIZE) {
+        DEBUG_PRINTF("DATAFLASH_BIT_PAGE_SIZE\r\n");
+    }
+
+    /* erase/program error */
+    if (status & DATAFLASH_BIT_ERASE_PROGRAM_ERROR) {
+        DEBUG_PRINTF("DATAFLASH_BIT_ERASE_PROGRAM_ERROR\r\n");
+    }
+
+    /* sector lockdown still possible */
+    if (status & DATAFLASH_BIT_SECTOR_LOCKDOWN) {
+        DEBUG_PRINTF("DATAFLASH_BIT_SECTOR_LOCKDOWN\r\n");
+    }
+
+    /* program operation suspended while using buffer 2 */
+    if (status & DATAFLASH_BIT_PROGRAM_SUSPEND_2) {
+        DEBUG_PRINTF("DATAFLASH_BIT_PROGRAM_SUSPEND_2\r\n");
+    }
+
+    /* program operation suspended while using buffer 1 */
+    if (status & DATAFLASH_BIT_PROGRAM_SUSPEND_1) {
+        DEBUG_PRINTF("DATAFLASH_BIT_PROGRAM_SUSPEND_1\r\n");
+    }
+
+    /* erase has been suspended */
+    if (status & DATAFLASH_BIT_ERASE_SUSPEND) {
+        DEBUG_PRINTF("DATAFLASH_BIT_ERASE_SUSPEND\r\n");
+    }
+#endif
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_DATAFLASH/DataFlashBlockDevice.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,182 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2016 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_DATAFLASH_BLOCK_DEVICE_H
+#define MBED_DATAFLASH_BLOCK_DEVICE_H
+
+#include <mbed.h>
+#include "BlockDevice.h"
+
+
+/** BlockDevice for DataFlash flash devices
+ *
+ *  @code
+ *  // Here's an example using the AT45DB on the K64F
+ *  #include "mbed.h"
+ *  #include "DataFlashBlockDevice.h"
+ *
+ *  // Create DataFlash on SPI bus with PTE5 as chip select
+ *  DataFlashBlockDevice dataflash(PTE2, PTE4, PTE1, PTE5);
+ *
+ *  // Create DataFlash on SPI bus with PTE6 as write-protect
+ *  DataFlashBlockDevice dataflash2(PTE2, PTE4, PTE1, PTE5, PTE6);
+ *
+ *  int main() {
+ *      printf("dataflash test\n");
+ *
+ *      // Initialize the SPI flash device and print the memory layout
+ *      dataflash.init();
+ *      printf("dataflash size: %llu\n", dataflash.size());
+ *      printf("dataflash read size: %llu\n", dataflash.get_read_size());
+ *      printf("dataflash program size: %llu\n", dataflash.get_program_size());
+ *      printf("dataflash erase size: %llu\n", dataflash.get_erase_size());
+ *
+ *      // Write "Hello World!" to the first block
+ *      char *buffer = (char*)malloc(dataflash.get_erase_size());
+ *      sprintf(buffer, "Hello World!\n");
+ *      dataflash.erase(0, dataflash.get_erase_size());
+ *      dataflash.program(buffer, 0, dataflash.get_erase_size());
+ *
+ *      // Read back what was stored
+ *      dataflash.read(buffer, 0, dataflash.get_erase_size());
+ *      printf("%s", buffer);
+ *
+ *      // Deinitialize the device
+ *      dataflash.deinit();
+ *  }
+ *  @endcode
+ */
+class DataFlashBlockDevice : public BlockDevice {
+public:
+    /** Creates a DataFlashBlockDevice on a SPI bus specified by pins
+     *
+     *  @param mosi     SPI master out, slave in pin
+     *  @param miso     SPI master in, slave out pin
+     *  @param sclk     SPI clock pin
+     *  @param csel     SPI chip select pin
+     *  @param nowp     GPIO not-write-protect
+     *  @param freq     Clock speed of the SPI bus (defaults to 40MHz)
+     */
+    DataFlashBlockDevice(PinName mosi,
+                         PinName miso,
+                         PinName sclk,
+                         PinName csel,
+                         int freq = 40000000,
+                         PinName nowp = NC);
+
+    /** Initialize a block device
+     *
+     *  @return         0 on success or a negative error code on failure
+     */
+    virtual int init();
+
+    /** Deinitialize a block device
+     *
+     *  @return         0 on success or a negative error code on failure
+     */
+    virtual int 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         0 on success, negative error code on failure
+     */
+    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         0 on success, negative error code on failure
+     */
+    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         0 on success, negative error code on failure
+     */
+    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 programable block 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 eraseable block in bytes
+     *  @note Must be a multiple of the program size
+     */
+    virtual bd_size_t get_erase_size() const;
+
+    /** Get the size of an erasable block given address
+     *
+     *  @param addr     Address within the erasable block
+     *  @return         Size of an erasable block in bytes
+     *  @note Must be a multiple of the program size
+     */
+    virtual bd_size_t get_erase_size(bd_addr_t addr) const;
+
+    /** Get the total size of the underlying device
+     *
+     *  @return         Size of the underlying device in bytes
+     */
+    virtual bd_size_t size() const;
+
+private:
+    // Master side hardware
+    SPI _spi;
+    DigitalOut _cs;
+    DigitalOut _nwp;
+
+    // Device configuration
+    uint32_t _device_size;
+    uint16_t _page_size;
+    uint16_t _block_size;
+    bool _is_initialized;
+    uint32_t _init_ref_count;
+
+    // Internal functions
+    uint16_t _get_register(uint8_t opcode);
+    void _write_command(uint32_t command, const uint8_t *buffer, uint32_t size);
+    void _write_enable(bool enable);
+    int _sync(void);
+    int _write_page(const uint8_t *buffer, uint32_t addr, uint32_t offset, uint32_t size);
+    uint32_t _translate_address(bd_addr_t addr);
+
+    // Mutex for thread safety
+    mutable PlatformMutex _mutex;
+};
+
+
+#endif  /* MBED_DATAFLASH_BLOCK_DEVICE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_DATAFLASH/mbed_lib.json	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,17 @@
+{
+    "name": "dataflash",
+    "config": {
+        "SPI_MOSI": "NC",
+        "SPI_MISO": "NC",
+        "SPI_CLK":  "NC",
+        "SPI_CS":   "NC",
+        "binary-size": {
+            "help": "Configure device to use binary address space.",
+            "value": "0"
+        },
+        "dataflash-size": {
+            "help": "Configure device to use DataFlash address space.",
+            "value": "0"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_FLASHIAP/FlashIAPBlockDevice.cpp	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,237 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2016 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.
+ */
+
+#ifdef DEVICE_FLASH
+
+#include "FlashIAPBlockDevice.h"
+#include "mbed_critical.h"
+
+#include "mbed.h"
+
+#include <inttypes.h>
+
+#define FLASHIAP_READ_SIZE 1
+
+// Debug available
+#ifndef FLASHIAP_DEBUG
+#define FLASHIAP_DEBUG      0
+#endif
+
+#if FLASHIAP_DEBUG
+#define DEBUG_PRINTF(...) printf(__VA_ARGS__)
+#else
+#define DEBUG_PRINTF(...)
+#endif
+
+FlashIAPBlockDevice::FlashIAPBlockDevice(uint32_t address, uint32_t size)
+    : _flash(), _base(address), _size(size), _is_initialized(false), _init_ref_count(0)
+{
+
+}
+
+FlashIAPBlockDevice::~FlashIAPBlockDevice()
+{
+    deinit();
+}
+
+int FlashIAPBlockDevice::init()
+{
+    DEBUG_PRINTF("init\r\n");
+
+    if (!_is_initialized) {
+        _init_ref_count = 0;
+    }
+
+    uint32_t val = core_util_atomic_incr_u32(&_init_ref_count, 1);
+
+    if (val != 1) {
+        return BD_ERROR_OK;
+    }
+
+    int ret = _flash.init();
+
+    if (ret) {
+        core_util_atomic_decr_u32(&_init_ref_count, 1);
+        return ret;
+    }
+
+    if (_size + _base > _flash.get_flash_size() + _flash.get_flash_start()) {
+        core_util_atomic_decr_u32(&_init_ref_count, 1);
+        return BD_ERROR_DEVICE_ERROR;
+    }
+
+    if (_base < _flash.get_flash_start()) {
+        core_util_atomic_decr_u32(&_init_ref_count, 1);
+        return BD_ERROR_DEVICE_ERROR;
+    }
+
+    if (!_base) {
+        _base = _flash.get_flash_start();
+    }
+
+    if (!_size) {
+        _size = _flash.get_flash_size() - (_base - _flash.get_flash_start());
+    }
+
+    _is_initialized = true;
+    return ret;
+}
+
+int FlashIAPBlockDevice::deinit()
+{
+    DEBUG_PRINTF("deinit\r\n");
+
+    if (!_is_initialized) {
+        _init_ref_count = 0;
+        return 0;
+    }
+
+    uint32_t val = core_util_atomic_decr_u32(&_init_ref_count, 1);
+
+    if (val) {
+        return 0;
+    }
+
+    _is_initialized = false;
+
+    return _flash.deinit();
+}
+
+int FlashIAPBlockDevice::read(void *buffer,
+                              bd_addr_t virtual_address,
+                              bd_size_t size)
+{
+    DEBUG_PRINTF("read: %" PRIX64 " %" PRIX64 "\r\n", virtual_address, size);
+
+    /* Default to error return code; success must be set explicitly. */
+    int result = BD_ERROR_DEVICE_ERROR;
+
+    /* Check that the address and size are properly aligned and fit. */
+    if (_is_initialized && is_valid_read(virtual_address, size)) {
+
+        /* Convert virtual address to the physical address for the device. */
+        bd_addr_t physical_address = _base + virtual_address;
+
+        /* Read data using the internal flash driver. */
+        result = _flash.read(buffer, physical_address, size);
+
+        DEBUG_PRINTF("physical: %" PRIX64 "\r\n", physical_address);
+    }
+
+    return result;
+}
+
+int FlashIAPBlockDevice::program(const void *buffer,
+                                 bd_addr_t virtual_address,
+                                 bd_size_t size)
+{
+    DEBUG_PRINTF("program: %" PRIX64 " %" PRIX64 "\r\n", virtual_address, size);
+
+    /* Default to error return code; success must be set explicitly. */
+    int result = BD_ERROR_DEVICE_ERROR;
+
+    /* Check that the address and size are properly aligned and fit. */
+    if (_is_initialized && is_valid_program(virtual_address, size)) {
+
+        /* Convert virtual address to the physical address for the device. */
+        bd_addr_t physical_address = _base + virtual_address;
+
+        /* Write data using the internal flash driver. */
+        result = _flash.program(buffer, physical_address, size);
+
+        DEBUG_PRINTF("physical: %" PRIX64 " %" PRIX64 "\r\n",
+                     physical_address,
+                     size);
+    }
+
+    return result;
+}
+
+int FlashIAPBlockDevice::erase(bd_addr_t virtual_address,
+                               bd_size_t size)
+{
+    DEBUG_PRINTF("erase: %" PRIX64 " %" PRIX64 "\r\n", virtual_address, size);
+
+    /* Default to error return code; success must be set explicitly. */
+    int result = BD_ERROR_DEVICE_ERROR;
+
+    /* Check that the address and size are properly aligned and fit. */
+    if (_is_initialized && is_valid_erase(virtual_address, size)) {
+
+        /* Convert virtual address to the physical address for the device. */
+        bd_addr_t physical_address = _base + virtual_address;
+
+        /* Erase sector */
+        result = _flash.erase(physical_address, size);
+    }
+
+    return result;
+}
+
+bd_size_t FlashIAPBlockDevice::get_read_size() const
+{
+    DEBUG_PRINTF("get_read_size: %d\r\n", FLASHIAP_READ_SIZE);
+
+    return FLASHIAP_READ_SIZE;
+}
+
+bd_size_t FlashIAPBlockDevice::get_program_size() const
+{
+    if (!_is_initialized) {
+        return 0;
+    }
+
+    uint32_t page_size = _flash.get_page_size();
+
+    DEBUG_PRINTF("get_program_size: %" PRIX32 "\r\n", page_size);
+
+    return page_size;
+}
+
+bd_size_t FlashIAPBlockDevice::get_erase_size() const
+{
+    if (!_is_initialized) {
+        return 0;
+    }
+
+    uint32_t erase_size = _flash.get_sector_size(_base);
+
+    DEBUG_PRINTF("get_erase_size: %" PRIX32 "\r\n", erase_size);
+
+    return erase_size;
+}
+
+bd_size_t FlashIAPBlockDevice::get_erase_size(bd_addr_t addr) const
+{
+    if (!_is_initialized) {
+        return 0;
+    }
+
+    uint32_t erase_size = _flash.get_sector_size(_base + addr);
+
+    DEBUG_PRINTF("get_erase_size: %" PRIX32 "\r\n", erase_size);
+
+    return erase_size;
+}
+
+bd_size_t FlashIAPBlockDevice::size() const
+{
+    DEBUG_PRINTF("size: %" PRIX64 "\r\n", _size);
+
+    return _size;
+}
+
+#endif /* DEVICE_FLASH */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_FLASHIAP/FlashIAPBlockDevice.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,128 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2016 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_FLASHIAP_BLOCK_DEVICE_H
+#define MBED_FLASHIAP_BLOCK_DEVICE_H
+
+#ifdef DEVICE_FLASH
+
+#include "FlashIAP.h"
+#include "BlockDevice.h"
+#include "platform/mbed_toolchain.h"
+
+/** BlockDevice using the FlashIAP API
+ *
+ */
+class FlashIAPBlockDevice : public BlockDevice {
+public:
+
+    /** Creates a FlashIAPBlockDevice
+     *
+     *  @param address  Physical address where the block device start
+     *  @param size     The block device size
+     */
+    FlashIAPBlockDevice(uint32_t address = MBED_CONF_FLASHIAP_BLOCK_DEVICE_BASE_ADDRESS,
+                        uint32_t size = MBED_CONF_FLASHIAP_BLOCK_DEVICE_SIZE);
+                        
+    virtual ~FlashIAPBlockDevice();
+
+    /** Initialize a block device
+     *
+     *  @return         0 on success or a negative error code on failure
+     */
+    virtual int init();
+
+    /** Deinitialize a block device
+     *
+     *  @return         0 on success or a negative error code on failure
+     */
+    virtual int 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         0 on success, negative error code on failure
+     */
+    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         0 on success, negative error code on failure
+     */
+    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         0 on success, negative error code on failure
+     */
+    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 programable block 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 eraseable block in bytes
+     *  @note Must be a multiple of the program size
+     */
+    virtual bd_size_t get_erase_size() const;
+
+    /** Get the size of an erasable block given address
+     *
+     *  @param addr     Address within the erasable block
+     *  @return         Size of an erasable block in bytes
+     *  @note Must be a multiple of the program size
+     */
+    virtual bd_size_t get_erase_size(bd_addr_t addr) const;
+
+    /** Get the total size of the underlying device
+     *
+     *  @return         Size of the underlying device in bytes
+     */
+    virtual bd_size_t size() const;
+
+private:
+    // Device configuration
+    mbed::FlashIAP _flash;
+    bd_addr_t _base;
+    bd_size_t _size;
+    bool _is_initialized;
+    uint32_t _init_ref_count;
+};
+
+#endif /* DEVICE_FLASH */
+#endif /* MBED_FLASHIAP_BLOCK_DEVICE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_FLASHIAP/TESTS/filesystem/fopen/fopen.cpp	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,1482 @@
+/*
+ * mbed Microcontroller Library
+ * Copyright (c) 2006-2016 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.
+ */
+
+/** @file fopen.cpp Test cases to POSIX file fopen() interface.
+ *
+ * Please consult the documentation under the test-case functions for
+ * a description of the individual test case.
+ */
+
+//#include "mbed.h"
+#include "LittleFileSystem.h"
+#include "fslittle_debug.h"
+#include "fslittle_test.h"
+#include "utest/utest.h"
+#include "unity/unity.h"
+#include "greentea-client/test_env.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>     /*rand()*/
+#include <inttypes.h>
+#include <errno.h>
+/* mbed_retarget.h is included after errno.h so symbols are mapped to
+ * consistent values for all toolchains */
+//#include "platform/mbed_retarget.h"
+
+using namespace utest::v1;
+
+/// @cond FSLITTLE_DOXYGEN_DISABLE
+#ifdef FSLITTLE_DEBUG
+#define FSLITTLE_FOPEN_GREENTEA_TIMEOUT_S     3000
+#else
+#define FSLITTLE_FOPEN_GREENTEA_TIMEOUT_S     1000
+#endif
+/// @endcond
+
+
+/* DEVICE_SPI
+ *  This symbol is defined in targets.json if the target has a SPI interface, which is required for SDCard support.
+ *
+ * MBED_CONF_APP_FSLITTLE_SDCARD_INSTALLED
+ *  For testing purposes, an SDCard must be installed on the target for the test cases in this file to succeed.
+ *  If the target has an SD card installed then the MBED_CONF_APP_FSLITTLE_SDCARD_INSTALLED will be generated
+ *  from the mbed_app.json, which includes the line
+ *    {
+ *    "config": {
+ *        "UART_RX": "D0",
+ *        <<< lines removed >>>
+ *        "DEVICE_SPI": 1,
+ *        "FSLITTLE_SDCARD_INSTALLED": 1
+ *      },
+ *      <<< lines removed >>>
+ */
+
+#include "FlashIAPBlockDevice.h"
+#include "SlicingBlockDevice.h"
+
+FlashIAPBlockDevice *flash;
+SlicingBlockDevice *slice;
+LittleFileSystem fs("sd");
+
+static char fslittle_fopen_utest_msg_g[FSLITTLE_UTEST_MSG_BUF_SIZE];
+#define FSLITTLE_FOPEN_TEST_MOUNT_PT_NAME      "sd"
+#define FSLITTLE_FOPEN_TEST_MOUNT_PT_PATH      "/"FSLITTLE_FOPEN_TEST_MOUNT_PT_NAME
+#define FSLITTLE_FOPEN_TEST_WORK_BUF_SIZE_1    64
+#define FSLITTLE_FOPEN_TEST_FILEPATH_MAX_DEPTH 20
+static const int MAX_TEST_SIZE = 256 * 1024 * 2;
+static const char *sd_badfile_path = "/sd/badfile.txt";
+static const char *sd_testfile_path = "/sd/test.txt";
+
+#define FSLITTLE_FOPEN_TEST_00      fslittle_fopen_test_00
+#define FSLITTLE_FOPEN_TEST_01      fslittle_fopen_test_01
+#define FSLITTLE_FOPEN_TEST_02      fslittle_fopen_test_02
+#define FSLITTLE_FOPEN_TEST_03      fslittle_fopen_test_03
+#define FSLITTLE_FOPEN_TEST_04      fslittle_fopen_test_04
+#define FSLITTLE_FOPEN_TEST_05      fslittle_fopen_test_05
+#define FSLITTLE_FOPEN_TEST_06      fslittle_fopen_test_06
+#define FSLITTLE_FOPEN_TEST_07      fslittle_fopen_test_07
+#define FSLITTLE_FOPEN_TEST_08      fslittle_fopen_test_08
+#define FSLITTLE_FOPEN_TEST_09      fslittle_fopen_test_09
+#define FSLITTLE_FOPEN_TEST_10      fslittle_fopen_test_10
+#define FSLITTLE_FOPEN_TEST_11      fslittle_fopen_test_11
+#define FSLITTLE_FOPEN_TEST_12      fslittle_fopen_test_12
+#define FSLITTLE_FOPEN_TEST_13      fslittle_fopen_test_13
+#define FSLITTLE_FOPEN_TEST_14      fslittle_fopen_test_14
+#define FSLITTLE_FOPEN_TEST_15      fslittle_fopen_test_15
+#define FSLITTLE_FOPEN_TEST_17      fslittle_fopen_test_17
+#define FSLITTLE_FOPEN_TEST_18      fslittle_fopen_test_18
+#define FSLITTLE_FOPEN_TEST_19      fslittle_fopen_test_19
+#define FSLITTLE_FOPEN_TEST_20      fslittle_fopen_test_20
+#define FSLITTLE_FOPEN_TEST_21      fslittle_fopen_test_21
+#define FSLITTLE_FOPEN_TEST_22      fslittle_fopen_test_22
+#define FSLITTLE_FOPEN_TEST_23      fslittle_fopen_test_23
+#define FSLITTLE_FOPEN_TEST_24      fslittle_fopen_test_24
+#define FSLITTLE_FOPEN_TEST_25      fslittle_fopen_test_25
+#define FSLITTLE_FOPEN_TEST_26      fslittle_fopen_test_26
+#define FSLITTLE_FOPEN_TEST_27      fslittle_fopen_test_27
+#define FSLITTLE_FOPEN_TEST_28      fslittle_fopen_test_28
+#define FSLITTLE_FOPEN_TEST_29      fslittle_fopen_test_29
+#define FSLITTLE_FOPEN_TEST_30      fslittle_fopen_test_30
+
+
+/* support functions */
+
+/*
+ * open tests that focus on testing fopen()
+ * fslittle_handle_t fopen(const char* filename, char* data, size_t* len, fslittle_key_desc_t* kdesc)
+ */
+
+/* file data for test_01 */
+static fslittle_kv_data_t fslittle_fopen_test_01_kv_data[] = {
+    { "/sd/fopentst/hello/world/animal/wobbly/dog/foot/frontlft.txt", "missing"},
+    { NULL, NULL},
+};
+
+
+/** @brief
+ * Split a file path into its component parts, setting '/' characters to '\0', and returning
+ * pointers to the file path components in the parts array. For example, if
+ * filepath = "/sd/fopentst/hello/world/animal/wobbly/dog/foot/frontlft.txt" then
+ *  *parts[0] = "sd"
+ *  *parts[1] = "fopentst"
+ *  *parts[2] = "hello"
+ *  *parts[3] = "world"
+ *  *parts[4] = "animal"
+ *  *parts[5] = "wobbly"
+ *  *parts[6] = "dog"
+ *  *parts[7] = "foot"
+ *  *parts[8] = "frontlft.txt"
+ *   parts[9] = NULL
+ *
+ * ARGUMENTS
+ *  @param  filepath     IN file path string to split into component parts. Expected to start with '/'
+ *  @param  parts        IN OUT array to hold pointers to parts
+ *  @param  num          IN number of components available in parts
+ *
+ * @return  On success, this returns the number of components in the filepath Returns number of compoee
+ */
+static int32_t fslittle_filepath_split(char *filepath, char *parts[], uint32_t num)
+{
+    uint32_t i = 0;
+    int32_t ret = -1;
+    char *z = filepath;
+
+    while (i < num && *z != '\0') {
+        if (*z == '/') {
+            *z = '\0';
+            parts[i] = ++z;
+            i++;
+        } else {
+            z++;
+        }
+    }
+    if (*z == '\0' && i > 0) {
+        ret = (int32_t) i;
+    }
+    return ret;
+}
+
+
+/** @brief
+ * remove all directories and file in the given filepath
+ *
+ * ARGUMENTS
+ *  @param  filepath     IN file path string to split into component parts. Expected to start with '/'
+ *
+ * @return  On success, this returns 0, otherwise < 0 is returned;
+ */
+int32_t fslittle_filepath_remove_all(char *filepath)
+{
+    int32_t ret = -1;
+    int32_t len = 0;
+    char *fpathbuf = NULL;
+    char *pos = NULL;
+
+    FSLITTLE_FENTRYLOG("%s:entered\n", __func__);
+    len = strlen(filepath);
+    fpathbuf = (char *) malloc(len + 1);
+    if (fpathbuf == NULL) {
+        FSLITTLE_DBGLOG("%s: failed to duplicate string (out of memory)\n", __func__);
+        return ret;
+    }
+    memset(fpathbuf, 0, len + 1);
+    memcpy(fpathbuf, filepath, len);
+
+    /* delete the leaf node first, and then successively parent directories. */
+    pos = fpathbuf + strlen(fpathbuf);
+    while (pos != fpathbuf) {
+        /* If the remaining file path is the mount point path then finish as the mount point cannot be removed */
+        if (strlen(fpathbuf) == strlen(FSLITTLE_FOPEN_TEST_MOUNT_PT_PATH) && strncmp(fpathbuf, FSLITTLE_FOPEN_TEST_MOUNT_PT_PATH, strlen(fpathbuf)) == 0) {
+            break;
+        }
+        ret = remove(fpathbuf);
+        pos = strrchr(fpathbuf, '/');
+        *pos = '\0';
+    }
+    if (fpathbuf) {
+        free(fpathbuf);
+    }
+    return ret;
+}
+
+
+/** @brief
+ * make all directories in the given filepath. Do not create the file if present at end of filepath
+ *
+ * ARGUMENTS
+ *  @param  filepath     IN file path containing directories and file
+ *  @param  do_asserts   IN set to true if function should assert on errors
+ *
+ * @return  On success, this returns 0, otherwise < 0 is returned;
+ */
+static int32_t fslittle_filepath_make_dirs(char *filepath, bool do_asserts)
+{
+    int32_t i = 0;
+    int32_t num_parts = 0;
+    int32_t len = 0;
+    int32_t ret = -1;
+    char *fpathbuf = NULL;
+    char *buf = NULL;
+    int pos = 0;
+    char *parts[FSLITTLE_FOPEN_TEST_FILEPATH_MAX_DEPTH];
+
+    FSLITTLE_DBGLOG("%s:entered\n", __func__);
+    /* find the dirs to create*/
+    memset(parts, 0, sizeof(parts));
+    len = strlen(filepath);
+    fpathbuf = (char *) malloc(len + 1);
+    if (fpathbuf == NULL) {
+        FSLITTLE_DBGLOG("%s: failed to duplicate string (out of memory)\n", __func__);
+        return ret;
+    }
+    memset(fpathbuf, 0, len + 1);
+    memcpy(fpathbuf, filepath, len);
+    num_parts = fslittle_filepath_split(fpathbuf, parts, FSLITTLE_FOPEN_TEST_FILEPATH_MAX_DEPTH);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to split filepath (filename=\"%s\", num_parts=%d)\n", __func__, filepath, (int) num_parts);
+    TEST_ASSERT_MESSAGE(num_parts > 0, fslittle_fopen_utest_msg_g);
+
+    /* Now create the directories on the directory path.
+     * Skip creating dir for "/sd" which must be present */
+    buf = (char *) malloc(strlen(filepath) + 1);
+    memset(buf, 0, strlen(filepath) + 1);
+    pos = sprintf(buf, "/%s", parts[0]);
+    for (i = 1; i < num_parts - 1; i++) {
+        pos += sprintf(buf + pos, "/%s", parts[i]);
+        FSLITTLE_DBGLOG("mkdir(%s)\n", buf);
+        ret = mkdir(buf, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+        if (do_asserts == true) {
+            FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create directory (filepath2=\"%s\", ret=%d, errno=%d)\n", __func__, buf, (int) ret, errno);
+            TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+        }
+    }
+
+    if (buf) {
+        free(buf);
+    }
+    if (fpathbuf) {
+        free(fpathbuf);
+    }
+    return ret;
+}
+
+
+/* FIX ME: errno not set correctly when error occurs. This indicates a problem with the implementation. */
+
+/** @brief
+ * Basic fopen test which does the following:
+ * - creates file and writes some data to the value blob.
+ * - closes the newly created file.
+ * - opens the file (r-only)
+ * - reads the file data and checks its the same as the previously created data.
+ * - closes the opened file
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+static control_t fslittle_fopen_test_01(const size_t call_count)
+{
+    char *read_buf;
+    int32_t ret = 0;
+    size_t len = 0;
+    fslittle_kv_data_t *node;
+    FILE *fp = NULL;
+
+    FSLITTLE_DBGLOG("%s:entered\n", __func__);
+    (void) call_count;
+    node = fslittle_fopen_test_01_kv_data;
+
+    /* remove file and directory from a previous failed test run, if present */
+    fslittle_filepath_remove_all((char *) node->filename);
+
+    /* create dirs */
+    ret = fslittle_filepath_make_dirs((char *) node->filename, true);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create dirs for filename (filename=\"%s\")(ret=%d)\n", __func__, node->filename, (int) ret);
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+
+    FSLITTLE_DBGLOG("%s:About to create new file (filename=\"%s\", data=\"%s\")\n", __func__, node->filename, node->value);
+    fp = fopen(node->filename, "w+");
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create file (filename=\"%s\", data=\"%s\")(ret=%d, errno=%d)\n", __func__, node->filename, node->value, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(fp != NULL, fslittle_fopen_utest_msg_g);
+
+    FSLITTLE_DBGLOG("%s:length of file=%d (filename=\"%s\", data=\"%s\")\n", __func__, (int) len, node->filename, node->value);
+    len = strlen(node->value);
+    ret = fwrite((const void *) node->value, len, 1, fp);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write file (filename=\"%s\", data=\"%s\")(ret=%d)\n", __func__, node->filename, node->value, (int) ret);
+    TEST_ASSERT_MESSAGE(ret == 1, fslittle_fopen_utest_msg_g);
+
+    FSLITTLE_DBGLOG("Created file successfully (filename=\"%s\", data=\"%s\")\n", node->filename, node->value);
+    ret = fclose(fp);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to close file (ret=%d, errno=%d)\n", __func__, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+
+    /* now open the newly created key */
+    fp = NULL;
+    fp = fopen(node->filename, "r");
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open file for reading (filename=\"%s\", data=\"%s\")(ret=%d)\n", __func__, node->filename, node->value, (int) ret);
+    TEST_ASSERT_MESSAGE(fp != NULL, fslittle_fopen_utest_msg_g);
+
+    len = strlen(node->value) + 1;
+    read_buf = (char *) malloc(len);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to allocated read buffer \n", __func__);
+    TEST_ASSERT_MESSAGE(read_buf != NULL, fslittle_fopen_utest_msg_g);
+
+    FSLITTLE_DBGLOG("Opened file successfully (filename=\"%s\", data=\"%s\")\n", node->filename, node->value);
+    memset(read_buf, 0, len);
+    ret = fread((void *) read_buf, len, 1, fp);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to read file (filename=\"%s\", data=\"%s\", read_buf=\"%s\", ret=%d)\n", __func__, node->filename, node->value, read_buf, (int) ret);
+    /* FIX ME: fread should return the number of items read, not 0 when an item is read successfully.
+     * This indicates a problem with the implementation, as the correct data is read. The correct assert should be:
+     *   TEST_ASSERT_MESSAGE(ret == 1, fslittle_fopen_utest_msg_g);
+     * The following assert is curerntly used until the implementation is fixed
+     */
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+
+    /* check read data is as expected */
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: read value data (%s) != expected value data (filename=\"%s\", data=\"%s\", read_buf=\"%s\", ret=%d)\n", __func__, read_buf, node->filename, node->value, read_buf, (int) ret);
+    TEST_ASSERT_MESSAGE(strncmp(read_buf, node->value, strlen(node->value)) == 0, fslittle_fopen_utest_msg_g);
+
+    if (read_buf) {
+        free(read_buf);
+    }
+    ret = fclose(fp);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: fclose() call failed (ret=%d, errno=%d).\n", __func__, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+    return CaseNext;
+}
+
+static fslittle_kv_data_t fslittle_fopen_test_02_data[] = {
+    FSLITTLE_INIT_1_TABLE_MID_NODE,
+    { NULL, NULL},
+};
+
+/**
+ * @brief   test to fopen() a pre-existing key and try to write it, which should fail
+ *          as by default pre-existing keys are opened read-only
+ *
+ * Basic open test which does the following:
+ * - creates file with default rw perms and writes some data to the value blob.
+ * - closes the newly created file.
+ * - opens the file with the default permissions (read-only)
+ * - tries to write the file data which should fail because file was not opened with write flag set.
+ * - closes the opened key
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fslittle_fopen_test_02(const size_t call_count)
+{
+    int32_t ret = -1;
+    size_t len = 0;
+    FILE *fp = NULL;
+
+    FSLITTLE_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+    len = strlen(fslittle_fopen_test_02_data[0].value);
+    ret = fslittle_test_create(fslittle_fopen_test_02_data[0].filename, (char *) fslittle_fopen_test_02_data[0].value, len);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret);
+    TEST_ASSERT_MESSAGE(ret >= 0, fslittle_fopen_utest_msg_g);
+
+    /* by default, owner of key opens with read-only permissions*/
+    fp = fopen(fslittle_fopen_test_02_data[0].filename, "r");
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open file (filename=\"%s\", ret=%d)\n", __func__, fslittle_fopen_test_02_data[0].filename, (int) ret);
+    TEST_ASSERT_MESSAGE(fp != NULL, fslittle_fopen_utest_msg_g);
+
+    len = strlen(fslittle_fopen_test_02_data[0].value);
+    ret = fwrite((const void *) fslittle_fopen_test_02_data[0].value, len, 1, fp);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: call to fwrite() succeeded when should have failed for read-only file (filename=\"%s\")(ret=%d).\n", __func__, fslittle_fopen_test_02_data[0].filename, (int) ret);
+    TEST_ASSERT_MESSAGE(ret <= 0, fslittle_fopen_utest_msg_g);
+
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: fclose() call failed.\n", __func__);
+    TEST_ASSERT_MESSAGE(fclose(fp) == 0, fslittle_fopen_utest_msg_g);
+
+    return CaseNext;
+}
+
+
+/**
+ * @brief   test to fopen() a pre-existing file and try to write it, which should succeed
+ *          because the key was opened read-write permissions explicitly
+ *
+ * Basic open test which does the following:
+ * - creates file with default rw perms and writes some data to the value blob.
+ * - closes the newly created file.
+ * - opens the file with the rw permissions (non default)
+ * - tries to write the file data which should succeeds because file was opened with write flag set.
+ * - closes the opened key
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fslittle_fopen_test_03(const size_t call_count)
+{
+    int32_t ret = -1;
+    size_t len = 0;
+    FILE *fp = NULL;
+
+    FSLITTLE_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+    len = strlen(fslittle_fopen_test_02_data[0].value);
+    ret = fslittle_test_create(fslittle_fopen_test_02_data[0].filename, (char *) fslittle_fopen_test_02_data[0].value, len);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create file in store (ret=%d).\n", __func__, (int) ret);
+    TEST_ASSERT_MESSAGE(ret >= 0, fslittle_fopen_utest_msg_g);
+
+    /* opens with read-write permissions*/
+    fp = fopen(fslittle_fopen_test_02_data[0].filename, "w+");
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open file (filename=\"%s\")(ret=%d)\n", __func__, fslittle_fopen_test_02_data[0].filename, (int) ret);
+    TEST_ASSERT_MESSAGE(ret >= 0, fslittle_fopen_utest_msg_g);
+
+    len = strlen(fslittle_fopen_test_02_data[0].value);
+    ret = fwrite((const void *) fslittle_fopen_test_02_data[0].value, len, 1, fp);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: call to fwrite() failed when should have succeeded (filename=\"%s\", ret=%d).\n", __func__, fslittle_fopen_test_02_data[0].filename, (int) ret);
+    TEST_ASSERT_MESSAGE(ret >= 0, fslittle_fopen_utest_msg_g);
+
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: fclose() call failed.\n", __func__);
+    TEST_ASSERT_MESSAGE(fclose(fp) >= 0, fslittle_fopen_utest_msg_g);
+
+    /* clean-up */
+    ret = remove(fslittle_fopen_test_02_data[0].filename);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to delete file (filename=%s, ret=%d) .\n", __func__, fslittle_fopen_test_02_data[0].filename, (int) ret);
+    TEST_ASSERT_MESSAGE(ret >= 0, fslittle_fopen_utest_msg_g);
+
+    return CaseNext;
+}
+
+
+/** @brief  test to call fopen() with a filename string that exceeds the maximum length
+ * - check that filenames of this length can be created
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fslittle_fopen_test_04(const size_t call_count)
+{
+    char filename_good[FSLITTLE_FILENAME_MAX_LENGTH + 1];
+    char filename_bad[FSLITTLE_FILENAME_MAX_LENGTH + 2];
+    int32_t ret = -1;
+    size_t len = 0;
+
+    FSLITTLE_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+    memset(filename_good, 0, FSLITTLE_FILENAME_MAX_LENGTH + 1);
+    memset(filename_bad, 0, FSLITTLE_FILENAME_MAX_LENGTH + 2);
+    ret = fslittle_test_filename_gen(filename_good, FSLITTLE_FILENAME_MAX_LENGTH);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to generate filename_good.\n", __func__);
+    TEST_ASSERT_MESSAGE(ret >= 0, fslittle_fopen_utest_msg_g);
+
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: filename_good is not the correct length (filename_good=%s, len=%d, expected=%d).\n", __func__, filename_good, (int) strlen(filename_good), (int) FSLITTLE_FILENAME_MAX_LENGTH);
+    TEST_ASSERT_MESSAGE(strlen(filename_good) == FSLITTLE_FILENAME_MAX_LENGTH, fslittle_fopen_utest_msg_g);
+
+    ret = fslittle_test_filename_gen(filename_bad, FSLITTLE_FILENAME_MAX_LENGTH + 1);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to generate filename_bad.\n", __func__);
+    TEST_ASSERT_MESSAGE(ret >= 0, fslittle_fopen_utest_msg_g);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: filename_bad is not the correct length (len=%d, expected=%d).\n", __func__, (int) strlen(filename_bad), (int) FSLITTLE_FILENAME_MAX_LENGTH + 1);
+    TEST_ASSERT_MESSAGE(strlen(filename_bad) == FSLITTLE_FILENAME_MAX_LENGTH + 1, fslittle_fopen_utest_msg_g);
+
+    len = strlen(filename_good);
+    ret = fslittle_test_create(filename_good, filename_good, len);
+
+    len = strlen(filename_bad);
+    ret = fslittle_test_create(filename_bad, filename_bad, len);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: created file in store for filename_bad when should have failed (filename=%s, ret=%d).\n", __func__, filename_bad, (int) ret);
+    TEST_ASSERT_MESSAGE(ret < 0, fslittle_fopen_utest_msg_g);
+    return CaseNext;
+}
+
+
+/// @cond FSLITTLE_DOXYGEN_DISABLE
+typedef struct fslittle_fopen_kv_name_ascii_node {
+    uint32_t code;
+    uint32_t f_allowed : 1;
+} fslittle_fopen_kv_name_ascii_node;
+/// @endcond
+
+static const uint32_t fslittle_fopen_kv_name_ascii_table_code_sentinel_g = 256;
+
+/*@brief    table recording ascii character codes permitted in kv names */
+static fslittle_fopen_kv_name_ascii_node fslittle_fopen_kv_name_ascii_table[] = {
+    {0, true},          /* code 0-33 allowed*/
+    {34, false},        /* '"' not allowed */
+    {35, true},         /* allowed */
+    {42, false},        /* '*' not allowed */
+    {43, true},         /* allowed */
+    {47, false},        /* '/' not allowed */
+    {48, true},         /* allowed */
+    {58, false},        /* ':' not allowed */
+    {59, true},         /* allowed */
+    {60, false},        /* '<' not allowed */
+    {61, true},         /* allowed */
+    {62, false},        /* '?', '>' not allowed */
+    {64, true},         /* allowed */
+    {92, false},        /* '\' not allowed */
+    {93, true},         /* allowed */
+    {124, false},        /* '!' not allowed */
+    {125, true},         /* allowed */
+    {127, false},        /* DEL not allowed */
+    {128, true},         /* allowed */
+    {fslittle_fopen_kv_name_ascii_table_code_sentinel_g, false},       /* sentinel */
+};
+
+
+/// @cond FSLITTLE_DOXYGEN_DISABLE
+enum fslittle_fopen_kv_name_pos {
+    fslittle_fopen_kv_name_pos_start = 0x0,
+    fslittle_fopen_kv_name_pos_mid,
+    fslittle_fopen_kv_name_pos_end,
+    fslittle_fopen_kv_name_pos_max
+};
+/// @endcond
+
+/** @brief  test to call fopen() with filename that in includes illegal characters
+ *          - the character(s) can be at the beginning of the filename
+ *          - the character(s) can be at the end of the filename
+ *          - the character(s) can be somewhere within the filename string
+ *          - a max-length string of random characters (legal and illegal)
+ *          - a max-length string of random illegal characters only
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fslittle_fopen_test_05(const size_t call_count)
+{
+    bool f_allowed = false;
+    const char *mnt_pt = FSLITTLE_FOPEN_TEST_MOUNT_PT_PATH;
+    const char *basename = "goodfile";
+    const char *extname = "txt";
+    const size_t basename_len = strlen(basename);
+    const size_t filename_len = strlen(mnt_pt) + strlen(basename) + strlen(extname) + 2; /* extra 2 chars for '/' and '.' in "/sd/goodfile.txt" */
+    char filename[FSLITTLE_BUF_MAX_LENGTH];
+    size_t len = 0;
+    uint32_t j = 0;
+    int32_t ret = 0;
+    fslittle_fopen_kv_name_ascii_node *node = NULL;
+    uint32_t pos;
+
+    FSLITTLE_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+#ifdef FSLITTLE_DEBUG
+    /* symbol only used why debug is enabled */
+    const char *pos_str = NULL;
+#endif
+
+    /* create bad keyname strings with invalid character code at start of keyname */
+    node = fslittle_fopen_kv_name_ascii_table;
+    memset(filename, 0, FSLITTLE_BUF_MAX_LENGTH);
+    while (node->code !=  fslittle_fopen_kv_name_ascii_table_code_sentinel_g) {
+        /* loop over range */
+        for (j = node->code; j < (node + 1)->code; j++) {
+            if ((j >= 48 && j <= 57) || (j >= 65 && j <= 90) || (j >= 97 && j <= 122)) {
+                FSLITTLE_DBGLOG("%s: skipping alpha-numeric ascii character code %d (%c).\n", __func__, (int) j, (char) j);
+                continue;
+            }
+
+            /* set the start, mid, last character of the name to the test char code */
+            for (pos = (uint32_t) fslittle_fopen_kv_name_pos_start; pos < (uint32_t) fslittle_fopen_kv_name_pos_max; pos++) {
+                len = snprintf(filename, filename_len + 1, "%s/%s.%s", mnt_pt, basename, extname);
+                /* overwrite a char at the pos start, mid, end of the filename with an ascii char code (both illegal and legal)*/
+                switch (pos) {
+                    case fslittle_fopen_kv_name_pos_start:
+                        filename[5] = (char) j; /* 5 so at to write the second basename char (bad chars as first char not accepted)*/
+                        break;
+                    case fslittle_fopen_kv_name_pos_mid:
+                        /* create bad keyname strings with invalid character code in the middle of keyname */
+                        filename[5 + basename_len / 2] = (char) j;
+                        break;
+                    case fslittle_fopen_kv_name_pos_end:
+                        /* create bad keyname strings with invalid character code at end of keyname */
+                        filename[5 + basename_len - 1] = (char) j;
+                        break;
+                    default:
+                        FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: unexpected value of pos (pos=%d).\n", __func__, (int) pos);
+                        TEST_ASSERT_MESSAGE(ret >= 0, fslittle_fopen_utest_msg_g);
+                        break;
+                }
+
+#ifdef FSLITTLE_DEBUG
+                /* processing only required when debug trace enabled */
+                switch (pos) {
+                    case fslittle_fopen_kv_name_pos_start:
+                        pos_str = "start";
+                        break;
+                    case fslittle_fopen_kv_name_pos_mid:
+                        pos_str = "middle";
+                        break;
+                    case fslittle_fopen_kv_name_pos_end:
+                        pos_str = "end";
+                        break;
+                    default:
+                        break;
+                }
+#endif
+                ret = fslittle_test_create(filename, (const char *) filename, len);
+
+                /* special cases */
+                switch (j) {
+                    //case 0 :
+                    //case 46 :
+                    //    switch(pos)
+                    //    {
+                    //    /* for code = 0 (null terminator). permitted at mid and end of string */
+                    //    /* for code = 46 ('.'). permitted at mid and end of string but not at start */
+                    //    case fslittle_fopen_kv_name_pos_start:
+                    //        f_allowed = false;
+                    //        break;
+                    //    case fslittle_fopen_kv_name_pos_mid:
+                    //    case fslittle_fopen_kv_name_pos_end:
+                    //    default:
+                    //        f_allowed = true;
+                    //        break;
+                    //    }
+                    //    break;
+                    default:
+                        f_allowed = node->f_allowed;
+                        break;
+                }
+                if (f_allowed == true) {
+                    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create file in store when filename contains valid characters (code=%d, ret=%d).\n", __func__, (int) j, (int) ret);
+                    TEST_ASSERT_MESSAGE(ret >= 0, fslittle_fopen_utest_msg_g);
+                    /* revert FSLITTLE_LOG for more trace */
+                    FSLITTLE_DBGLOG("Successfully created a file with valid keyname containing ascii character code %d (%c) at the %s of the keyname.\n", (int) j, (int) j, pos_str);
+                    FSLITTLE_LOG("%c", '.');
+
+                    ret = fslittle_test_delete(filename);
+                    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to delete file previously created (code=%d, ret=%d).\n", __func__, (int) j, (int) ret);
+                    TEST_ASSERT_MESSAGE(ret >= 0, fslittle_fopen_utest_msg_g);
+                } else {
+                    /*node->f_allowed == false => not allowed to create kv name with ascii code */
+                    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: created file in store when filename contains an invalid character (code=%d, ret=%d).\n", __func__, (int) j, (int) ret);
+                    TEST_ASSERT_MESSAGE(ret < 0, fslittle_fopen_utest_msg_g);
+                    /* revert FSLITTLE_LOG for more trace */
+                    FSLITTLE_DBGLOG("Successfully failed to create a file with an invalid keyname containing ascii character code %d at the %s of the keyname.\n", (int) j, pos_str);
+                    FSLITTLE_LOG("%c", '.');
+                }
+            }
+        }
+        node++;
+    }
+
+    FSLITTLE_LOG("%c", '\n');
+    return CaseNext;
+}
+
+
+static const char fslittle_fopen_ascii_illegal_buf_g[] = "\"?'*+,./:;<=>?[\\]|";
+
+/** @brief  test to call fopen() with filename that in includes
+ *          illegal characters
+ *          - a max-length string of random illegal characters only
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fslittle_fopen_test_06(const size_t call_count)
+{
+// legal in LittleFS
+#if 0
+    const char *mnt_pt = FSLITTLE_FOPEN_TEST_MOUNT_PT_PATH;
+    const char *extname = "txt";
+    const size_t filename_len = strlen(mnt_pt) + FSLITTLE_MAX_FILE_BASENAME + strlen(extname) + 2; /* extra 2 chars for '/' and '.' in "/sd/goodfile.txt" */
+    char filename[FSLITTLE_BUF_MAX_LENGTH];
+    int32_t i = 0;
+    int32_t j = 0;
+    uint32_t pos = 0;
+    uint32_t len = 0;
+    int32_t ret = -1;
+    size_t buf_data_max = 0;
+
+    FSLITTLE_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+    memset(filename, 0, FSLITTLE_BUF_MAX_LENGTH);
+    /* create bad keyname strings with invalid character code at start of keyname */
+    buf_data_max = strlen(fslittle_fopen_ascii_illegal_buf_g);
+
+    /* generate a number of illegal filenames */
+    for (j = 0; i < FSLITTLE_MAX_FILE_BASENAME; j++) {
+        /* generate a kv name of illegal chars*/
+        len = snprintf(filename, filename_len + 1, "%s/", mnt_pt);
+        for (i = 0; i < FSLITTLE_MAX_FILE_BASENAME; i++) {
+            pos = rand() % (buf_data_max + 1);
+            len += snprintf(filename + len, filename_len + 1, "%c", fslittle_fopen_ascii_illegal_buf_g[pos]);
+
+        }
+        len += snprintf(filename + len, filename_len + 1, ".%s", extname);
+        ret = fslittle_test_create(filename, filename, len);
+        FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: created file when filename contains invalid characters (filename=%s, ret=%d).\n", __func__, filename, (int) ret);
+        TEST_ASSERT_MESSAGE(ret < 0, fslittle_fopen_utest_msg_g);
+    }
+#endif
+    return CaseNext;
+}
+
+
+/** @brief  test for errno reporting on a failed fopen()call
+ *
+ *  This test does the following:
+ *  - tries to open a file that does not exist for reading, and checks that a NULL pointer is returned.
+ *  - checks that errno is not 0 as there is an error.
+ *  - checks that ferror() returns 1 indicating an error exists.
+ *
+ * Note: see NOTE_1 below.
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fslittle_fopen_test_07(const size_t call_count)
+{
+    FILE *f = NULL;
+    int ret = -1;
+    int errno_val = 0;
+    const char *filename = sd_badfile_path;
+
+    FSLITTLE_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+    errno = 0;
+    /* this is expect to fail as the file doesnt exist */
+    f = fopen(filename, "r");
+
+    /* Store errno so the current value set  is not changed by new function call */
+    errno_val = errno;
+
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: opened non-existent file for reading (filename=%s, f=%p).\n", __func__, filename, f);
+    TEST_ASSERT_MESSAGE(f == NULL, fslittle_fopen_utest_msg_g);
+
+    /* check errno is set correctly */
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: errno has unexpected value (errno != 0 expected) (filename=%s, errno=%d).\n", __func__, filename, errno);
+    TEST_ASSERT_MESSAGE(errno_val != 0, fslittle_fopen_utest_msg_g);
+
+    return CaseNext;
+}
+
+
+/** @brief  test for operation of clearerr() and ferror()
+ *
+ *  The test does the following:
+ *  - opens and then closes a file, but keeps a copy of the FILE pointer fp.
+ *  - set errno to 0.
+ *  - write to the close file with fwrite(fp) which should return 0 (no writes) and set the errno.
+ *  - check the error condition is set with ferror().
+ *  - clear the error with clearerr().
+ *  - check the error condition is reset with ferror().
+ *
+ * NOTE_1: GCC/ARMCC support for setting errno
+ *  - Documentation (e.g. fwrite() man page) does not explicity say fwrite() sets errno
+ *    (e.g. for an fwrite() on a read-only file).
+ *  - GCC libc fwrite() appears to set errno as expected.
+ *  - ARMCC & IAR libc fwrite() appears not to set errno.
+ *
+ * The following ARMCC documents are silent on whether fwrite() sets errno:
+ * - "ARM C and C++ Libraries and Floating-Point Support".
+ * - "RL-ARM User Guide fwrite() section".
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fslittle_fopen_test_08(const size_t call_count)
+{
+    FILE *fp = NULL;
+    int ret = -1;
+    int ret_ferror = -1;
+    const char *filename = sd_testfile_path;
+
+    FSLITTLE_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+    errno = 0;
+    fp = fopen(filename, "w+");
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open file (filename=%s, f=%p).\n", __func__, filename, fp);
+    TEST_ASSERT_MESSAGE(fp != NULL, fslittle_fopen_utest_msg_g);
+
+    /* close the fp but then try to read or write it */
+    ret = fclose(fp);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to close file (ret=%d, errno=%d)\n", __func__, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+
+    /* open file  */
+    errno = 0;
+    fp = fopen(filename, "r");
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open file for reading (filename=\"%s\", ret=%d)\n", __func__, filename, (int) ret);
+    TEST_ASSERT_MESSAGE(fp != NULL, fslittle_fopen_utest_msg_g);
+
+    /* Perform fwrite() operation that will fail. */
+    errno = 0;
+    ret = fwrite("42!", 4, 1, fp);
+
+    ret_ferror = ferror(fp);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: ferror() failed to report error (filename=%s, ret_ferror=%d).\n", __func__, filename, (int) ret_ferror);
+    TEST_ASSERT_MESSAGE(ret_ferror != 0, fslittle_fopen_utest_msg_g);
+
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: fwrite successfully wrote to read-only file (filename=%s, ret=%d).\n", __func__, filename, (int) ret);
+    /* the fwrite() should fail and return 0. */
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+
+#if ! defined(__ARMCC_VERSION) && defined(__GNUC__)
+    /* check that errno is set. ARMCC appears not to set errno for fwrite() failure. */
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: unexpected zero value for errno (filename=%s, ret=%d, errno=%d).\n", __func__, filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(errno != 0, fslittle_fopen_utest_msg_g);
+
+    /* check that errno is set to the expected value (this may change differ for different libc's) */
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: errno != EBADF (filename=%s, ret=%d, errno=%d).\n", __func__, filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(errno == EBADF, fslittle_fopen_utest_msg_g);
+#endif  /* ! defined(__ARMCC_VERSION) && defined(__GNUC__) */
+
+    /* check clearerr() return clears the error */
+    clearerr(fp);
+    ret = ferror(fp);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: ferror() did not return zero value when error has been cleared (filename=%s, ret=%d).\n", __func__, filename, (int) ret);
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+
+    fclose(fp);
+    return CaseNext;
+}
+
+
+/** @brief  test for operation of ftell()
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fslittle_fopen_test_09(const size_t call_count)
+{
+    FILE *fp = NULL;
+    int ret = -1;
+    int32_t len = 0;
+
+    FSLITTLE_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+    /* create a file of a certain length */
+    len = strlen(fslittle_fopen_test_02_data[0].value);
+    ret = fslittle_test_create(fslittle_fopen_test_02_data[0].filename, (char *) fslittle_fopen_test_02_data[0].value, len);
+
+    errno = 0;
+    /* Open the file for reading so the file is not truncated to 0 length. */
+    fp = fopen(fslittle_fopen_test_02_data[0].filename, "r");
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open file (filename=%s, fp=%p, errno=%d).\n", __func__, fslittle_fopen_test_02_data[0].filename, fp, errno);
+    TEST_ASSERT_MESSAGE(fp != NULL, fslittle_fopen_utest_msg_g);
+
+    errno = 0;
+    ret = fseek(fp, 0, SEEK_END);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: fseek() failed to SEEK_END (filename=%s, ret=%d, errno=%d).\n", __func__, fslittle_fopen_test_02_data[0].filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+
+    errno = 0;
+    ret = ftell(fp);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: ftell() failed to report correct offset value (filename=%s, ret=%d, errno=%d).\n", __func__, fslittle_fopen_test_02_data[0].filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == len, fslittle_fopen_utest_msg_g);
+
+    errno = 0;
+    ret = fclose(fp);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to close file (ret=%d, errno=%d)\n", __func__, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+
+    return CaseNext;
+}
+
+
+/* file data for test_10 */
+static fslittle_kv_data_t fslittle_fopen_test_10_kv_data[] = {
+    { "/sd/test_10/testfile.txt", "test_data"},
+    { NULL, NULL},
+};
+
+/** @brief  test for operation of remove()
+ *
+ * Performs the following tests:
+ *  1. test remove() on a file that exists. This should succeed.
+ *  2. test remove() on a dir that exists. This should succeed.
+ *  3. test remove() on a file that doesnt exist. This should fail. check errno set.
+ *  4. test remove() on a dir that doesnt exist. This should fail. check errno set.
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fslittle_fopen_test_10(const size_t call_count)
+{
+    char buf[FSLITTLE_FOPEN_TEST_WORK_BUF_SIZE_1];
+    char *pos = NULL;
+    int32_t ret = -1;
+    size_t len = 0;
+    fslittle_kv_data_t *node = fslittle_fopen_test_10_kv_data;
+
+    FSLITTLE_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+    TEST_ASSERT(strlen(node->filename) < FSLITTLE_FOPEN_TEST_WORK_BUF_SIZE_1);
+
+    /* start from a known state i.e. directory to be created in not present */
+    fslittle_filepath_remove_all((char *) node->filename);
+
+    /* (1) */
+    errno = 0;
+    ret = fslittle_filepath_make_dirs((char *) node->filename, false);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+
+    len = strlen(node->value);
+    ret = fslittle_test_create(node->filename, (char *) node->value, len);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret);
+    TEST_ASSERT_MESSAGE(ret >= 0, fslittle_fopen_utest_msg_g);
+
+    ret = remove(node->filename);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: delete file operation failed (filename=%s, ret=%d) .\n", __func__, node->filename, (int) ret);
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+
+    /* (3) */
+    ret = remove(node->filename);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: deleted a file that doesn't exist (filename=%s, ret=%d, errno=%d) .\n", __func__, node->filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret != 0, fslittle_fopen_utest_msg_g);
+
+    /* (2) */
+    memset(buf, 0, FSLITTLE_FOPEN_TEST_WORK_BUF_SIZE_1);
+    memcpy(buf, node->filename, strlen(node->filename));
+    pos = strrchr(buf, '/');
+    *pos = '\0';
+    ret = remove(buf);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: delete directory operation failed (directory name=%s, ret=%d, errno=%d).\n", __func__, buf, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+
+    /* (4) */
+    ret = remove(buf);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: deleted a directory that doesn't exist (directory name=%s, ret=%d, errno=%d).\n", __func__, buf, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret != 0, fslittle_fopen_utest_msg_g);
+
+    return CaseNext;
+}
+
+
+/* file data for test_11 */
+static fslittle_kv_data_t fslittle_fopen_test_11_kv_data[] = {
+    { "/sd/test_11/step0.txt", "test_data"},
+    { "/sd/test_11/step1.txt", "test_data"},
+    { "/sd/test_11/subdir/step3.txt", "test_data"},
+    { NULL, NULL},
+};
+
+/** @brief  test for operation of rename()
+ *
+ * This test does the following:
+ *  1) test rename() on a file that exists to a new filename within the same directory.
+ *  2) test rename() on a file that exists to a new filename within a different directory.
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fslittle_fopen_test_11(const size_t call_count)
+{
+    int32_t ret = -1;
+    size_t len = 0;
+    fslittle_kv_data_t *node = fslittle_fopen_test_11_kv_data;
+
+    FSLITTLE_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+    TEST_ASSERT(strlen(node->filename) < FSLITTLE_FOPEN_TEST_WORK_BUF_SIZE_1);
+
+    /* start from a known state i.e. directory to be created in not present, files not present */
+    while (node->filename != NULL) {
+        fslittle_filepath_remove_all((char *) node->filename);
+        node++;
+    }
+
+    /* create file and directories ready for rename() tests */
+    errno = 0;
+    node = fslittle_fopen_test_11_kv_data;
+    ret = fslittle_filepath_make_dirs((char *) node->filename, false);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+
+    len = strlen(node->value);
+    ret = fslittle_test_create(node->filename, (char *) node->value, len);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret);
+    TEST_ASSERT_MESSAGE(ret >= 0, fslittle_fopen_utest_msg_g);
+
+    errno = 0;
+    node = &fslittle_fopen_test_11_kv_data[2];
+    ret = fslittle_filepath_make_dirs((char *) node->filename, false);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+
+    /* (1) */
+    ret = rename(fslittle_fopen_test_11_kv_data[0].filename, fslittle_fopen_test_11_kv_data[1].filename);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to rename file from (%s) to (%s) (ret=%d, errno=%d).\n", __func__, fslittle_fopen_test_11_kv_data[0].filename, fslittle_fopen_test_11_kv_data[1].filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+
+    /* (2) */
+    ret = rename(fslittle_fopen_test_11_kv_data[1].filename, fslittle_fopen_test_11_kv_data[2].filename);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to rename file from (%s) to (%s) (ret=%d, errno=%d).\n", __func__, fslittle_fopen_test_11_kv_data[1].filename, fslittle_fopen_test_11_kv_data[2].filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+
+    return CaseNext;
+}
+
+
+/* file data for test_12 */
+static fslittle_kv_data_t fslittle_fopen_test_12_kv_data[] = {
+    { "/sd/test_12/subdir/testfil1.txt", "testfil1.txt"},
+    { "/sd/test_12/testfil2.txt", "testfil2.txt"},
+    { "/sd/test_12/testfil3.txt", "testfil3.txt"},
+    { "/sd/test_12/testfil4.txt", "testfil4.txt"},
+    { "/sd/test_12/testfil5.txt", "testfil5.txt"},
+    { NULL, NULL},
+};
+
+/** @brief  test for operation of readdir().
+ *
+ * Note, rewinddir(), telldir() and seekdir() dont appear to work reliably.
+ * opendir() not available on ARM/IAR toolchains.
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fslittle_fopen_test_12(const size_t call_count)
+{
+    char buf[FSLITTLE_FOPEN_TEST_WORK_BUF_SIZE_1];
+    char *pos = NULL;
+    int32_t count = 0;
+    int32_t ret = -1;
+    size_t len = 0;
+    DIR *dir;
+    struct dirent *dp;
+    fslittle_kv_data_t *node = fslittle_fopen_test_12_kv_data;
+
+    FSLITTLE_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+#if ! defined(__ARMCC_VERSION) && defined(__GNUC__)
+
+    /* start from a known state i.e. directory to be created in not present */
+    while (node->filename != NULL) {
+        fslittle_filepath_remove_all((char *) node->filename);
+        node++;
+    }
+
+    /* create a file */
+    node = fslittle_fopen_test_12_kv_data;
+    errno = 0;
+    ret = fslittle_filepath_make_dirs((char *) node->filename, false);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+
+    node = fslittle_fopen_test_12_kv_data;
+    while (node->filename != NULL) {
+        len = strlen(node->value);
+        ret = fslittle_test_create(node->filename, (char *) node->value, len);
+        FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret);
+        TEST_ASSERT_MESSAGE(ret >= 0, fslittle_fopen_utest_msg_g);
+        node++;
+    }
+
+    node = fslittle_fopen_test_12_kv_data;
+    memset(buf, 0, FSLITTLE_FOPEN_TEST_WORK_BUF_SIZE_1);
+    memcpy(buf, node->filename, strlen(node->filename));
+    pos = strrchr(buf, '/');
+    *pos = '\0';
+    dir = opendir(buf);
+
+    dp = readdir(dir);
+    TEST_ASSERT_MESSAGE(dp != 0, "Error: readdir() failed\n");
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: unexpected object name (name=%s, expected=%s).\n", __func__, dp->d_name, ".");
+    TEST_ASSERT_MESSAGE(strncmp(dp->d_name, ".", strlen(".")) == 0, fslittle_fopen_utest_msg_g);
+    dp = readdir(dir);
+    TEST_ASSERT_MESSAGE(dp != 0, "Error: readdir() failed\n");
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: unexpected object name (name=%s, expected=%s).\n", __func__, dp->d_name, "..");
+    TEST_ASSERT_MESSAGE(strncmp(dp->d_name, "..", strlen("..")) == 0, fslittle_fopen_utest_msg_g);
+
+    while ((dp = readdir(dir)) != NULL) {
+        FSLITTLE_DBGLOG("%s: filename: \"%s\"\n", __func__, dp->d_name);
+        TEST_ASSERT_MESSAGE(dp != 0, "Error: readdir() failed\n");
+        FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: unexpected object name (name=%s, expected=%s).\n", __func__, dp->d_name, fslittle_fopen_test_12_kv_data[count].value);
+        TEST_ASSERT_MESSAGE(strncmp(dp->d_name, fslittle_fopen_test_12_kv_data[count].value, strlen(fslittle_fopen_test_12_kv_data[count].value)) == 0, fslittle_fopen_utest_msg_g);
+        count++;
+    }
+    closedir(dir);
+
+    /* cleanup */
+    node = fslittle_fopen_test_12_kv_data;
+    while (node->filename != NULL) {
+        fslittle_filepath_remove_all((char *) node->filename);
+        node++;
+    }
+#endif  /* ! defined(__ARMCC_VERSION) && defined(__GNUC__) */
+    return CaseNext;
+}
+
+
+/* file data for test_13 */
+static fslittle_kv_data_t fslittle_fopen_test_13_kv_data[] = {
+    /* a file is included in the filepath even though its not created by the test,
+     * as the fslittle_filepath_make_dirs() works with it present. */
+    { "/sd/test_13/dummy.txt", "testdir"},
+    { NULL, NULL},
+};
+/** @brief  test for operation of mkdir()/remove()
+ *
+ * This test checks that:
+ * - The mkdir() function successfully creates a directory that is not already present.
+ * - The mkdir() function returns EEXIST when trying to create a directory thats already present.
+ * - The remove() function successfully removes a directory that is present.
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fslittle_fopen_test_13(const size_t call_count)
+{
+    int32_t ret = 0;
+
+    FSLITTLE_DBGLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+    /* start from a known state i.e. directory to be created in not present */
+    fslittle_filepath_remove_all((char *) fslittle_fopen_test_13_kv_data[0].filename);
+
+    errno = 0;
+    ret = fslittle_filepath_make_dirs((char *) fslittle_fopen_test_13_kv_data[0].filename, false);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, fslittle_fopen_test_13_kv_data[0].filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+
+    /* check that get a suitable error when try to create it again.*/
+    errno = 0;
+    ret = fslittle_filepath_make_dirs((char *) fslittle_fopen_test_13_kv_data[0].filename, false);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: permitted to create directory when already exists (dirname=%s, ret=%d, errno=%d)\n", __func__, fslittle_fopen_test_13_kv_data[0].filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret != 0, fslittle_fopen_utest_msg_g);
+
+    /* check errno is as expected */
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: errno != EEXIST (dirname=%s, ret=%d, errno=%d)\n", __func__, fslittle_fopen_test_13_kv_data[0].filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(errno == EEXIST, fslittle_fopen_utest_msg_g);
+
+    ret = fslittle_filepath_remove_all((char *) fslittle_fopen_test_13_kv_data[0].filename);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to remove directory (dirname=%s, ret=%d, errno=%d)\n", __func__, fslittle_fopen_test_13_kv_data[0].filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+
+    return CaseNext;
+}
+
+/* file data for test_14 */
+static fslittle_kv_data_t fslittle_fopen_test_14_kv_data[] = {
+    /* a file is included in the filepath even though its not created by the test,
+     * as the fslittle_filepath_make_dirs() works with it present. */
+    { "/sd/test_14/testfile.txt", "testdata"},
+    { NULL, NULL},
+};
+
+/** @brief  test for operation of stat()
+ *
+ * stat() is currently no supported by ARMCC and IAR toolchains libc.
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fslittle_fopen_test_14(const size_t call_count)
+{
+#if ! defined(__ARMCC_VERSION) && defined(__GNUC__)
+
+    char buf[FSLITTLE_FOPEN_TEST_WORK_BUF_SIZE_1];
+    char *pos = NULL;
+    int32_t ret = -1;
+    size_t len = 0;
+    struct stat file_stat;
+    fslittle_kv_data_t *node = fslittle_fopen_test_14_kv_data;
+
+    FSLITTLE_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+    TEST_ASSERT(strlen(node->filename) < FSLITTLE_FOPEN_TEST_WORK_BUF_SIZE_1);
+
+    /* start from a known state i.e. directory to be created in not present */
+    fslittle_filepath_remove_all((char *) node->filename);
+
+    /* Create file in a directory. */
+    errno = 0;
+    ret = fslittle_filepath_make_dirs((char *) node->filename, false);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+
+    len = strlen(node->value);
+    ret = fslittle_test_create(node->filename, (char *) node->value, len);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret);
+    TEST_ASSERT_MESSAGE(ret >= 0, fslittle_fopen_utest_msg_g);
+
+    /* Test stat() on the file returns the correct attribute set */
+    memset(&file_stat, 0, sizeof(file_stat));
+    ret = stat(node->filename, &file_stat);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: stat() operation on file failed (filename=%s, ret=%d, errno=%d).\n", __func__, node->filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: expected st_mode S_IFREG flag not set (filename=%s).\n", __func__, node->filename);
+    TEST_ASSERT_MESSAGE((file_stat.st_mode & S_IFREG) == S_IFREG, fslittle_fopen_utest_msg_g);
+
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: unexpected st_mode S_IFDIR flag set (filename=%s).\n", __func__, node->filename);
+    TEST_ASSERT_MESSAGE((file_stat.st_mode & S_IFDIR) != S_IFDIR, fslittle_fopen_utest_msg_g);
+
+    /* Test stat() on the directory returns the correct attribute set */
+    memset(&file_stat, 0, sizeof(file_stat));
+    memset(buf, 0, FSLITTLE_FOPEN_TEST_WORK_BUF_SIZE_1);
+    memcpy(buf, node->filename, strlen(node->filename));
+    pos = strrchr(buf, '/');
+    *pos = '\0';
+    ret = stat(buf, &file_stat);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: stat() operation on directory failed (directory name=%s, ret=%d, errno=%d).\n", __func__, buf, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: unexpected st_mode S_IFREG flag set (directory name=%s).\n", __func__, buf);
+    TEST_ASSERT_MESSAGE((file_stat.st_mode & S_IFREG) != S_IFREG, fslittle_fopen_utest_msg_g);
+
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: expected st_mode S_IFDIR flag not set (directory name=%s).\n", __func__, buf);
+    TEST_ASSERT_MESSAGE((file_stat.st_mode & S_IFDIR) == S_IFDIR, fslittle_fopen_utest_msg_g);
+
+    /* clean up after successful test */
+    fslittle_filepath_remove_all((char *) node->filename);
+
+#endif /* ! defined(__ARMCC_VERSION) && defined(__GNUC__) */
+    return CaseNext;
+}
+
+/** @brief  test for operation of SDFileSystem::format()
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fslittle_fopen_test_00(const size_t call_count)
+{
+
+    FSLITTLE_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+    int32_t ret = -1;
+
+    flash = new FlashIAPBlockDevice();
+    ret = flash->init();
+    TEST_ASSERT_EQUAL(0, ret);
+
+    // Use slice of last sectors
+    bd_addr_t slice_addr = flash->size();
+    bd_size_t slice_size = 0;
+    while (slice_size < MAX_TEST_SIZE) {
+        bd_size_t unit_size = flash->get_erase_size(slice_addr - 1);
+        slice_addr -= unit_size;
+        slice_size += unit_size;
+    }
+    slice = new SlicingBlockDevice(flash, slice_addr);
+    slice->init();
+
+    ret = fs.reformat(slice);
+    FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to format sdcard (ret=%d)\n", __func__, (int) ret);
+    TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+    fs.mount(slice);
+
+    return CaseNext;
+}
+
+
+/* @brief   test utility function to create a file of a given size.
+ *
+ * A reference data table is used of so that the data file can be later be
+ * checked with fslittle_test_check_data_file().
+ *
+ * @param   filename    name of the file including path
+ * @param   data        data to store in file
+ * @param   len         number of bytes of data present in the data buffer.
+ */
+int32_t fslittle_test_create_data_file(const char *filename, size_t len)
+{
+    int32_t ret = -1;
+    FILE *fp = NULL;
+    size_t write_len = 0;
+    size_t written_len = 0;
+    int32_t exp = 0;
+    const int32_t exp_max = 8;      /* so as not to exceed FSLITTLE_TEST_BYTE_DATA_TABLE_SIZE/2 */
+
+    FSLITTLE_FENTRYLOG("%s:entered (filename=%s, len=%d).\n", __func__, filename, (int) len);
+    TEST_ASSERT(len % FSLITTLE_TEST_BYTE_DATA_TABLE_SIZE == 0);
+    fp = fopen(filename, "a");
+    if (fp == NULL) {
+        return ret;
+    }
+
+    while (written_len < len) {
+        /* write fslittle_test_byte_data_table or part thereof, in 9 writes of sizes
+         * 1, 2, 4, 8, 16, 32, 64, 128, 1, totalling 256 bytes len permitting. */
+        for (exp = 0; (exp <= exp_max) && (written_len < len); exp++) {
+            write_len = 0x1 << (exp % exp_max);
+            write_len = len - written_len  > write_len ? write_len : len - written_len;
+            ret = fwrite((const void *) &fslittle_test_byte_data_table[written_len % FSLITTLE_TEST_BYTE_DATA_TABLE_SIZE], write_len, 1, fp);
+            written_len += write_len;
+            if (ret != 1) {
+                FSLITTLE_DBGLOG("%s:Error: fwrite() failed (ret=%d)\n", __func__, (int) ret);
+                ret = -1;
+                goto out0;
+            }
+        }
+    }
+    if (written_len == len) {
+        ret = 0;
+    } else {
+        ret = -1;
+    }
+out0:
+    fclose(fp);
+    return ret;
+}
+
+
+/* @brief   test utility function to check the data in the specified file is correct.
+ *
+ * The data read from the file is check that it agrees with the data written by
+ * fslittle_test_create_data_file().
+ *
+ * @param   filename    name of the file including path
+ * @param   data        data to store in file
+ * @param   len         number of bytes of data present in the data buffer.
+ */
+int32_t fslittle_test_check_data_file(const char *filename, size_t len)
+{
+    int32_t ret = -1;
+    FILE *fp = NULL;
+    size_t read_len = 0;
+    uint8_t buf[FSLITTLE_TEST_BYTE_DATA_TABLE_SIZE];
+
+    FSLITTLE_FENTRYLOG("%s:entered (filename=%s, len=%d).\n", __func__, filename, (int) len);
+    TEST_ASSERT(len % FSLITTLE_TEST_BYTE_DATA_TABLE_SIZE == 0);
+    fp = fopen(filename, "r");
+    if (fp == NULL) {
+        return ret;
+    }
+
+    while (read_len < len) {
+        ret = fread((void *) buf, FSLITTLE_TEST_BYTE_DATA_TABLE_SIZE, 1, fp);
+        read_len += FSLITTLE_TEST_BYTE_DATA_TABLE_SIZE;
+        if (ret == 0) {
+            /* end of read*/
+            FSLITTLE_DBGLOG("%s:unable to read data\n", __func__);
+            break;
+        }
+        if (memcmp(buf, fslittle_test_byte_data_table, FSLITTLE_TEST_BYTE_DATA_TABLE_SIZE) != 0) {
+            FSLITTLE_DBGLOG("%s:Error: read data not as expected (0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x\n", __func__,
+                            buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
+            ret = -1;
+            goto out0;
+        }
+    }
+    if (read_len == len) {
+        ret = 0;
+    }
+out0:
+    fclose(fp);
+    return ret;
+}
+
+/* file data for test_16 */
+static fslittle_kv_data_t fslittle_fopen_test_15_kv_data[] = {
+    { "/sd/tst16_0/testfil0.txt", "dummy_data"},
+    { "/sd/tst16_1/subdir0/testfil0.txt", "dummy_data"},
+    { "/sd/tst16_2/subdir0/subdir1/testfil0.txt", "dummy_data"},
+    { "/sd/tst16_3/subdir0/subdir1/subdir2/subdir3/testfil0.txt", "dummy_data"},
+
+#if 0
+    { "/sd/tst16_4/subdir0/subdir1/subdir2/subdir3/subdir4/testfil0.txt", "dummy_data"},
+    { "/sd/tst16_5/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/testfil0.txt", "dummy_data"},
+    { "/sd/tst16_6/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/subdir6/testfil0.txt", "dummy_data"},
+    { "/sd/tst16_7/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/subdir6/subdir7/testfil0.txt", "dummy_data"},
+    { "/sd/tst16_8/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/subdir6/subdir7/subdir8/testfil0.txt", "dummy_data"},
+    { "/sd/tst16_9/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/subdir6/subdir7/subdir8/subdir9/testfil0.txt", "dummy_data"},
+#endif
+    { NULL, NULL},
+};
+
+
+/** @brief  stress test to write data to fs
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fslittle_fopen_test_15(const size_t call_count)
+{
+    int32_t ret = 0;
+    fslittle_kv_data_t *node = fslittle_fopen_test_15_kv_data;
+    const int32_t num_blocks = 100; /* each file ~25kB */
+
+    FSLITTLE_DBGLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+    /* remove file and directory from a previous failed test run, if present */
+    while (node->filename != NULL) {
+        fslittle_filepath_remove_all((char *) node->filename);
+        node++;
+    }
+
+    /* create dirs */
+    node = fslittle_fopen_test_15_kv_data;
+    while (node->filename != NULL) {
+        ret = fslittle_filepath_make_dirs((char *) node->filename, true);
+        FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create dirs for filename (filename=\"%s\")(ret=%d)\n", __func__, node->filename, (int) ret);
+        TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+        node++;
+    }
+
+    /* create the data files */
+    node = fslittle_fopen_test_15_kv_data;
+    while (node->filename != NULL) {
+        ret = fslittle_test_create_data_file(node->filename, num_blocks * FSLITTLE_TEST_BYTE_DATA_TABLE_SIZE);
+        FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create data file (filename=\"%s\")(ret=%d)\n", __func__, node->filename, (int) ret);
+        TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+        node++;
+    }
+
+    /* read the data back and check its as expected */
+    node = fslittle_fopen_test_15_kv_data;
+    while (node->filename != NULL) {
+        ret = fslittle_test_check_data_file(node->filename, num_blocks * FSLITTLE_TEST_BYTE_DATA_TABLE_SIZE);
+        FSLITTLE_TEST_UTEST_MESSAGE(fslittle_fopen_utest_msg_g, FSLITTLE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to check data file (filename=\"%s\")(ret=%d)\n", __func__, node->filename, (int) ret);
+        TEST_ASSERT_MESSAGE(ret == 0, fslittle_fopen_utest_msg_g);
+        node++;
+    }
+
+    /* clean up */
+    node = fslittle_fopen_test_15_kv_data;
+    while (node->filename != NULL) {
+        fslittle_filepath_remove_all((char *) node->filename);
+        node++;
+    }
+    return CaseNext;
+}
+
+/// @cond FSLITTLE_DOXYGEN_DISABLE
+utest::v1::status_t greentea_setup(const size_t number_of_cases)
+{
+    GREENTEA_SETUP(FSLITTLE_FOPEN_GREENTEA_TIMEOUT_S, "default_auto");
+    return greentea_test_setup_handler(number_of_cases);
+}
+
+Case cases[] = {
+    /*          1         2         3         4         5         6        7  */
+    /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
+    Case("FSLITTLE_FOPEN_TEST_00: format() test.", FSLITTLE_FOPEN_TEST_00),
+    Case("FSLITTLE_FOPEN_TEST_01: fopen()/fwrite()/fclose() directories/file in multi-dir filepath.", FSLITTLE_FOPEN_TEST_01),
+    Case("FSLITTLE_FOPEN_TEST_02: fopen(r) pre-existing file try to write it.", FSLITTLE_FOPEN_TEST_02),
+    Case("FSLITTLE_FOPEN_TEST_03: fopen(w+) pre-existing file try to write it.", FSLITTLE_FOPEN_TEST_03),
+    Case("FSLITTLE_FOPEN_TEST_04: fopen() with a filename exceeding the maximum length.", FSLITTLE_FOPEN_TEST_04),
+#ifdef FOPEN_EXTENDED_TESTING
+    Case("FSLITTLE_FOPEN_TEST_05: fopen() with bad filenames (extended).", FSLITTLE_FOPEN_TEST_05),
+#endif
+    Case("FSLITTLE_FOPEN_TEST_06: fopen() with bad filenames (minimal).", FSLITTLE_FOPEN_TEST_06),
+    Case("FSLITTLE_FOPEN_TEST_07: fopen()/errno handling.", FSLITTLE_FOPEN_TEST_07),
+    Case("FSLITTLE_FOPEN_TEST_08: ferror()/clearerr()/errno handling.", FSLITTLE_FOPEN_TEST_08),
+    Case("FSLITTLE_FOPEN_TEST_09: ftell() handling.", FSLITTLE_FOPEN_TEST_09),
+    Case("FSLITTLE_FOPEN_TEST_10: remove() test.", FSLITTLE_FOPEN_TEST_10),
+    Case("FSLITTLE_FOPEN_TEST_11: rename().", FSLITTLE_FOPEN_TEST_11),
+    Case("FSLITTLE_FOPEN_TEST_12: opendir(), readdir(), closedir() test.", FSLITTLE_FOPEN_TEST_12),
+    Case("FSLITTLE_FOPEN_TEST_13: mkdir() test.", FSLITTLE_FOPEN_TEST_13),
+    Case("FSLITTLE_FOPEN_TEST_14: stat() test.", FSLITTLE_FOPEN_TEST_14),
+    Case("FSLITTLE_FOPEN_TEST_15: write/check n x 25kB data files.", FSLITTLE_FOPEN_TEST_15),
+};
+
+
+/* Declare your test specification with a custom setup handler */
+Specification specification(greentea_setup, cases);
+
+int main()
+{
+    return !Harness::run(specification);
+}
+/// @endcond
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_FLASHIAP/mbed_lib.json	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,19 @@
+{
+    "name": "flashiap-block-device",
+    "config": {
+        "base-address": {
+            "help": "Base address for the block device on the external flash.",
+            "value": "0xFFFFFFFF"
+        },
+        "size": {
+            "help": "Memory allocated for block device.",
+            "value": "0"
+        }
+    },
+    "target_overrides": {
+        "REALTEK_RTL8195AM": {
+            "base-address": "0x1C0000",
+            "size": "0x40000"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_FLASHIAP/util/fslittle_debug.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,104 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2016 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.
+ */
+
+/** @file fslittle_debug.h
+ *
+ * component debug header file.
+ */
+
+
+#ifndef __FSLITTLE_DEBUG
+#define __FSLITTLE_DEBUG
+
+#include <stdint.h>
+#include <assert.h>
+#include <stdio.h>
+
+
+/* Debug Support */
+
+#define FSLITTLE_LOG_NONE        0
+#define FSLITTLE_LOG_ERR         1
+#define FSLITTLE_LOG_WARN        2
+#define FSLITTLE_LOG_NOTICE      3
+#define FSLITTLE_LOG_INFO        4
+#define FSLITTLE_LOG_DEBUG       5
+#define FSLITTLE_LOG_FENTRY      6
+
+#define FSLITTLE_LOG(_fmt, ...)                          \
+  do                                                    \
+  {                                                     \
+        printf(_fmt, __VA_ARGS__);                      \
+  }while(0);
+
+#define noFSLITTLE_DEBUG
+#ifdef FSLITTLE_DEBUG
+
+extern uint32_t fslittle_optDebug_g;
+extern uint32_t fslittle_optLogLevel_g;
+
+
+/* uncomment for asserts to work */
+/* #undef NDEBUG */
+// todo: port to mbedOSV3++ #include <core-util/assert.h>
+
+#define FSLITTLE_INLINE
+// todo: port to mbedOSV3++ #define FSLITTLE_ASSERT  CORE_UTIL_ASSERT
+#define FSLITTLE_ASSERT(...)
+
+#define FSLITTLE_DBGLOG(_fmt, ...)                       \
+  do                                                    \
+  {                                                     \
+    if(fslittle_optDebug_g && (fslittle_optLogLevel_g >= FSLITTLE_LOG_DEBUG))  \
+    {                                                   \
+        printf(_fmt, __VA_ARGS__);                      \
+    }                                                   \
+  }while(0);
+
+
+#define FSLITTLE_ERRLOG(_fmt, ...)                       \
+  do                                                    \
+  {                                                     \
+    if(fslittle_optDebug_g && (fslittle_optLogLevel_g >= FSLITTLE_LOG_ERR))  \
+    {                                                   \
+        printf(_fmt, __VA_ARGS__);                      \
+    }                                                   \
+  }while(0);
+
+
+#define FSLITTLE_FENTRYLOG(_fmt, ...)                       \
+  do                                                    \
+  {                                                     \
+    if(fslittle_optDebug_g && (fslittle_optLogLevel_g >= FSLITTLE_LOG_FENTRY))  \
+    {                                                   \
+        printf(_fmt, __VA_ARGS__);                      \
+    }                                                   \
+  }while(0);
+
+
+
+
+
+#else
+#define FSLITTLE_ASSERT(_x)                   do { } while(0)
+#define FSLITTLE_INLINE                       inline
+#define FSLITTLE_DBGLOG(_fmt, ...)            do { } while(0)
+#define FSLITTLE_ERRLOG(_fmt, ...)            do { } while(0)
+#define FSLITTLE_FENTRYLOG(_fmt, ...)         do { } while(0)
+#endif /* FSLITTLE_DEBUG */
+
+
+#endif /*__FSLITTLE_DEBUG*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_FLASHIAP/util/fslittle_test.c	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,116 @@
+/* @file fslittle_test.c
+ *
+ * mbed Microcontroller Library
+ * Copyright (c) 2006-2016 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.
+ *
+ * test support code implementation file.
+ */
+
+#include "fslittle_debug.h"
+#include "fslittle_test.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <ctype.h>
+
+
+#ifdef FSLITTLE_DEBUG
+uint32_t fslittle_optDebug_g = 1;
+uint32_t fslittle_optLogLevel_g = FSLITTLE_LOG_NONE; /*FSLITTLE_LOG_NONE|FSLITTLE_LOG_ERR|FSLITTLE_LOG_DEBUG|FSLITTLE_LOG_FENTRY; */
+#endif
+
+/* ruler for measuring text strings */
+/*                                                                                                    1         1         1         1         1         1         1         1         1         1         2         2         2 */
+/* 0        1         2         3         4         5         6         7         8         9         0         1         2         3         4         5         6         7         8         9         0         1         2 */
+/* 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 */
+
+const uint8_t fslittle_test_byte_data_table[FSLITTLE_TEST_BYTE_DATA_TABLE_SIZE] = {
+    0x2d, 0xf3, 0x31, 0x4c, 0x11, 0x4f, 0xde, 0x0d, 0xbd, 0xbc, 0xa6, 0x78, 0x36, 0x5c, 0x1d, 0x28,
+    0x5f, 0xa9, 0x10, 0x65, 0x54, 0x45, 0x21, 0x1a, 0x88, 0xfe, 0x76, 0x45, 0xb9, 0xac, 0x65, 0x9a,
+    0x34, 0x9d, 0x73, 0x10, 0xb4, 0xa9, 0x2e, 0x90, 0x95, 0x68, 0xac, 0xfe, 0xc5, 0x2d, 0x15, 0x03,
+    0x34, 0x70, 0xf1, 0x1d, 0x48, 0xa1, 0xa0, 0xed, 0x5c, 0x2f, 0xf5, 0x2b, 0xb9, 0x84, 0xbb, 0x45,
+    0x32, 0xdd, 0xb1, 0x33, 0x95, 0x2a, 0xbc, 0x26, 0xf0, 0x89, 0xba, 0xf4, 0xbd, 0xf9, 0x5d, 0x2e,
+    0x6e, 0x11, 0xc6, 0xa7, 0x78, 0xfc, 0xc9, 0x0e, 0x6b, 0x38, 0xba, 0x14, 0x1b, 0xab, 0x4c, 0x20,
+    0x91, 0xe4, 0xb0, 0xf1, 0x2b, 0x14, 0x07, 0x6b, 0xb5, 0xcd, 0xe3, 0x49, 0x75, 0xac, 0xe8, 0x98,
+    0xf1, 0x58, 0x8f, 0xd9, 0xc4, 0x8f, 0x00, 0x17, 0xb5, 0x06, 0x6a, 0x33, 0xbd, 0xa7, 0x40, 0x5a,
+    0xbf, 0x49, 0xf7, 0x27, 0x1b, 0x4c, 0x3e, 0x6f, 0xe3, 0x08, 0x1f, 0xfd, 0xa6, 0xd4, 0xc7, 0x5f,
+    0xa4, 0xa6, 0x82, 0xad, 0x19, 0xd5, 0x5c, 0xd8, 0x3a, 0x49, 0x85, 0xc9, 0x21, 0x83, 0xf6, 0xc6,
+    0x84, 0xf9, 0x76, 0x89, 0xf3, 0x2d, 0x17, 0x50, 0x97, 0x38, 0x48, 0x9a, 0xe1, 0x82, 0xcd, 0xac,
+    0xa8, 0x1d, 0xd7, 0x96, 0x5e, 0xb3, 0x08, 0xa8, 0x3a, 0xc7, 0x2b, 0x05, 0xaf, 0xdc, 0x16, 0xdf,
+    0x48, 0x0f, 0x2a, 0x7e, 0x3a, 0x82, 0xd7, 0x80, 0xd6, 0x49, 0x27, 0x5d, 0xe3, 0x07, 0x62, 0xb3,
+    0xc3, 0x6c, 0xba, 0xb2, 0xaa, 0x9f, 0xd9, 0x03, 0x0d, 0x27, 0xa8, 0xe0, 0xd6, 0xee, 0x79, 0x4b,
+    0xd6, 0x97, 0x99, 0xb7, 0x11, 0xd6, 0x0d, 0x34, 0xae, 0x99, 0x4a, 0x93, 0x95, 0xd0, 0x5a, 0x34,
+    0x19, 0xa2, 0x69, 0x57, 0xcf, 0x7c, 0x3d, 0x98, 0x88, 0x5d, 0x04, 0xf2, 0xd7, 0xac, 0xa5, 0x63
+};
+
+
+/* @brief  test utility function to delete the file identified by filename
+ */
+int32_t fslittle_test_delete(const char *filename)
+{
+    FSLITTLE_FENTRYLOG("%s:entered.\r\n", __func__);
+    return remove(filename);
+}
+
+
+/* @brief   test utility function to create a file
+ *
+ * @param   filename    name of the file including path
+ * @param   data        data to store in file
+ * @param   len         number of bytes of data present in the data buffer.
+ */
+int32_t fslittle_test_create(const char *filename, const char *data, size_t len)
+{
+    int32_t ret = -1;
+    FILE *fp = NULL;
+
+    FSLITTLE_FENTRYLOG("%s:entered (filename=%s, len=%d).\n", __func__, filename, (int) len);
+    fp = fopen(filename, "w+");
+    if (fp == NULL) {
+        return ret;
+    }
+    ret = fwrite((const void *) data, len, 1, fp);
+    if (ret < 0) {
+        fclose(fp);
+        return ret;
+    }
+    fclose(fp);
+    return ret;
+}
+
+
+/* @brief   support function for generating a kv_name
+ * @param   name    buffer to hold kv name
+ * @param   len     length of kv name to generate
+ *
+ */
+int32_t fslittle_test_filename_gen(char *name, const size_t len)
+{
+    size_t i;
+    uint32_t pos = 0;
+
+    const char *buf = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!$-_@";
+    const int buf_len = strlen(buf);
+    FSLITTLE_FENTRYLOG("%s:entered\n", __func__);
+    for (i = 0; i < len; i++) {
+        pos = rand() % (buf_len);
+        name[i] = buf[pos];
+    }
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_FLASHIAP/util/fslittle_test.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,74 @@
+/** @file fslittle_test.h
+ *
+ * mbed Microcontroller Library
+ * Copyright (c) 2006-2016 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.
+ *
+ * Header file for test support data structures and function API.
+ */
+#ifndef __FSLITTLE_TEST_H
+#define __FSLITTLE_TEST_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Defines */
+//#define FSLITTLE_INIT_1_TABLE_HEAD                 { "a", ""}
+#define FSLITTLE_INIT_1_TABLE_MID_NODE             { "/sd/01234567.txt", "abcdefghijklmnopqrstuvwxyz"}
+//#define FSLITTLE_INIT_1_TABLE_TAIL                 { "/sd/fopentst/hello/world/animal/wobbly/dog/foot/backrght.txt", "present"}
+#define FSLITTLE_TEST_RW_TABLE_SENTINEL            0xffffffff
+#define FSLITTLE_TEST_BYTE_DATA_TABLE_SIZE         256
+#define FSLITTLE_UTEST_MSG_BUF_SIZE                256
+#define FSLITTLE_UTEST_DEFAULT_TIMEOUT_MS          10000
+#define FSLITTLE_MBED_HOSTTEST_TIMEOUT             60
+#define FSLITTLE_MAX_FILE_BASENAME                 8
+#define FSLITTLE_MAX_FILE_EXTNAME                  3
+#define FSLITTLE_BUF_MAX_LENGTH                    64
+#define FSLITTLE_FILENAME_MAX_LENGTH               255
+
+
+/* support macro for make string for utest _MESSAGE macros, which dont support formatted output */
+#define FSLITTLE_TEST_UTEST_MESSAGE(_buf, _max_len, _fmt, ...)   \
+  do                                                            \
+  {                                                             \
+      snprintf((_buf), (_max_len), (_fmt), __VA_ARGS__);        \
+  }while(0);
+
+
+/*
+ * Structures
+ */
+
+/* kv data for test */
+typedef struct fslittle_kv_data_t {
+    const char *filename;
+    const char *value;
+} fslittle_kv_data_t;
+
+
+extern const uint8_t fslittle_test_byte_data_table[FSLITTLE_TEST_BYTE_DATA_TABLE_SIZE];
+
+int32_t fslittle_test_create(const char *filename, const char *data, size_t len);
+int32_t fslittle_test_delete(const char *key_name);
+int32_t fslittle_test_filename_gen(char *name, const size_t len);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __FSLITTLE_TEST_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_RSPIF/SPIFReducedBlockDevice.cpp	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,344 @@
+
+/* 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 "SPIFReducedBlockDevice.h"
+#include "mbed_wait_api.h"
+
+// Read/write/erase sizes
+#define SPIF_READ_SIZE  1
+#define SPIF_PROG_SIZE  1
+#define SPIF_SE_SIZE    4096
+#define SPIF_TIMEOUT    10000
+
+// Debug available
+#define SPIF_DEBUG      0
+
+// Legacy SFDP Instruction Table.
+enum ops {
+    SPIF_NOP  = 0x00, // No operation
+    SPIF_READ = 0x03, // Read data
+    SPIF_PROG = 0x02, // Program data
+    SPIF_SE   = 0x20, // 4KB Sector Erase
+    SPIF_CE   = 0xc7, // Chip Erase
+    SPIF_SFDP = 0x5a, // Read SFDP
+    SPIF_WREN = 0x06, // Write Enable
+    SPIF_WRDI = 0x04, // Write Disable
+    SPIF_RDSR = 0x05, // Read Status Register
+    SPIF_RDID = 0x9f, // Read Manufacturer and JDEC Device ID
+};
+
+// Status register from RDSR
+// [---------| wel | wip ]
+// [-   6   -|  1  |  1  ]
+#define SPIF_WEL 0x2
+#define SPIF_WIP 0x1
+
+
+SPIFReducedBlockDevice::SPIFReducedBlockDevice(
+    PinName mosi, PinName miso, PinName sclk, PinName cs, int freq)
+    : _spi(mosi, miso, sclk), _cs(cs), _size(0)
+{
+    _cs = 1;
+    _spi.frequency(freq);
+}
+
+int SPIFReducedBlockDevice::init()
+{
+    // Check for vendor specific hacks, these should move into more general
+    // handling when possible. RDID is not used to verify a device is attached.
+    uint8_t id[3];
+    _cmdread(SPIF_RDID, 0, 3, 0x0, id);
+
+    switch (id[0]) {
+        case 0xbf:
+            // SST devices come preset with block protection
+            // enabled for some regions, issue gbpu instruction to clear
+            _wren();
+            _cmdwrite(0x98, 0, 0, 0x0, NULL);
+            break;
+    }
+
+    // Check that device is doing ok
+    int err = _sync();
+    if (err) {
+        return BD_ERROR_DEVICE_ERROR;
+    }
+
+    // Check JEDEC serial flash discoverable parameters for device
+    // specific info
+    uint8_t header[16];
+    _cmdread(SPIF_SFDP, 4, 16, 0x0, header);
+
+    // Verify SFDP signature for sanity
+    // Also check that major/minor version is acceptable
+    if (!(memcmp(&header[0], "SFDP", 4) == 0 && header[5] == 1)) {
+        return BD_ERROR_DEVICE_ERROR;
+    }
+
+    // The SFDP spec indicates the standard table is always at offset 0
+    // in the parameter headers, we check just to be safe
+    if (!(header[8] == 0 && header[10] == 1)) {
+        return BD_ERROR_DEVICE_ERROR;
+    }
+
+    // Parameter table pointer, spi commands are BE, SFDP is LE,
+    // also sfdp command expects extra read wait byte
+    // header 12-14 3 bytes building the parameter table address
+    uint32_t table_addr = (
+                              (header[14] << 24) |
+                              (header[13] << 16) |
+                              (header[12] << 8 ));
+
+    uint8_t table[8];
+    _cmdread(SPIF_SFDP, 4, 8, table_addr, table);
+
+    // Check erase size, currently only supports 4kbytes
+    if ((table[0] & 0x3) != 0x1 || table[1] != SPIF_SE) {
+        // First byte of table, bits 0 and 1 = 0x1 indicating 4 KB Erase is supported
+        // Second Byte of table = Sector Erase Command (0x20)
+        return BD_ERROR_DEVICE_ERROR;
+    }
+
+    // Check address size, currently only supports 3byte addresses
+    if ((table[2] & 0x4) != 0 || (table[7] & 0x80) != 0) {
+        return BD_ERROR_DEVICE_ERROR;
+    }
+
+    // Get device density, stored as size in bits - 1
+    uint32_t density = (
+                           (table[7] << 24) |
+                           (table[6] << 16) |
+                           (table[5] << 8 ) |
+                           (table[4] << 0 ));
+    // Table bytes 5-8 : Bits 0|30 indicate Flash Density (size) in bits (divide by 8 for Bytes)
+    _size = (density / 8) + 1;
+
+    return 0;
+}
+
+int SPIFReducedBlockDevice::deinit()
+{
+    // Latch write disable just to keep noise
+    // from changing the device
+    _cmdwrite(SPIF_WRDI, 0, 0, 0x0, NULL);
+
+    return 0;
+}
+
+void SPIFReducedBlockDevice::_cmdread(
+    uint8_t op, uint32_t addrc, uint32_t retc,
+    uint32_t addr, uint8_t *rets)
+{
+    _cs = 0;
+    _spi.write(op);
+
+    for (uint32_t i = 0; i < addrc; i++) {
+        _spi.write(0xff & (addr >> 8 * (addrc - 1 - i)));
+    }
+
+    for (uint32_t i = 0; i < retc; i++) {
+        rets[i] = _spi.write(0);
+    }
+    _cs = 1;
+
+    if (SPIF_DEBUG) {
+        printf("spif <- %02x", op);
+        for (uint32_t i = 0; i < addrc; i++) {
+            if (i < addrc) {
+                printf("%02lx", 0xff & (addr >> 8 * (addrc - 1 - i)));
+            } else {
+                printf("  ");
+            }
+        }
+        printf(" ");
+        for (uint32_t i = 0; i < 16 && i < retc; i++) {
+            printf("%02x", rets[i]);
+        }
+        if (retc > 16) {
+            printf("...");
+        }
+        printf("\n");
+    }
+}
+
+void SPIFReducedBlockDevice::_cmdwrite(
+    uint8_t op, uint32_t addrc, uint32_t argc,
+    uint32_t addr, const uint8_t *args)
+{
+    _cs = 0;
+    _spi.write(op);
+
+    for (uint32_t i = 0; i < addrc; i++) {
+        _spi.write(0xff & (addr >> 8 * (addrc - 1 - i)));
+    }
+
+    for (uint32_t i = 0; i < argc; i++) {
+        _spi.write(args[i]);
+    }
+    _cs = 1;
+
+    if (SPIF_DEBUG) {
+        printf("spif -> %02x", op);
+        for (uint32_t i = 0; i < addrc; i++) {
+            if (i < addrc) {
+                printf("%02lx", 0xff & (addr >> 8 * (addrc - 1 - i)));
+            } else {
+                printf("  ");
+            }
+        }
+        printf(" ");
+        for (uint32_t i = 0; i < 16 && i < argc; i++) {
+            printf("%02x", args[i]);
+        }
+        if (argc > 16) {
+            printf("...");
+        }
+        printf("\n");
+    }
+}
+
+int SPIFReducedBlockDevice::_sync()
+{
+    for (int i = 0; i < SPIF_TIMEOUT; i++) {
+        // Read status register until write not-in-progress
+        uint8_t status;
+        _cmdread(SPIF_RDSR, 0, 1, 0x0, &status);
+
+        // Check WIP bit
+        if (!(status & SPIF_WIP)) {
+            return 0;
+        }
+
+        wait_ms(1);
+    }
+
+    return BD_ERROR_DEVICE_ERROR;
+}
+
+int SPIFReducedBlockDevice::_wren()
+{
+    _cmdwrite(SPIF_WREN, 0, 0, 0x0, NULL);
+
+    for (int i = 0; i < SPIF_TIMEOUT; i++) {
+        // Read status register until write latch is enabled
+        uint8_t status;
+        _cmdread(SPIF_RDSR, 0, 1, 0x0, &status);
+
+        // Check WEL bit
+        if (status & SPIF_WEL) {
+            return 0;
+        }
+
+        wait_ms(1);
+    }
+
+    return BD_ERROR_DEVICE_ERROR;
+}
+
+int SPIFReducedBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
+{
+    // Check the address and size fit onto the chip.
+    MBED_ASSERT(is_valid_read(addr, size));
+
+    _cmdread(SPIF_READ, 3, size, addr, static_cast<uint8_t *>(buffer));
+    return 0;
+}
+
+int SPIFReducedBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size)
+{
+    // Check the address and size fit onto the chip.
+    MBED_ASSERT(is_valid_program(addr, size));
+
+    while (size > 0) {
+        int err = _wren();
+        if (err) {
+            return err;
+        }
+
+        // Write up to 256 bytes a page
+        uint32_t off = addr % 256;
+        uint32_t chunk = (off + size < 256) ? size : (256 - off);
+        _cmdwrite(SPIF_PROG, 3, chunk, addr, static_cast<const uint8_t *>(buffer));
+        buffer = static_cast<const uint8_t *>(buffer) + chunk;
+        addr += chunk;
+        size -= chunk;
+
+        wait_ms(1);
+
+        err = _sync();
+        if (err) {
+            return err;
+        }
+    }
+
+    return 0;
+}
+
+int SPIFReducedBlockDevice::erase(bd_addr_t addr, bd_size_t size)
+{
+    // Check the address and size fit onto the chip.
+    MBED_ASSERT(is_valid_erase(addr, size));
+
+    while (size > 0) {
+        int err = _wren();
+        if (err) {
+            return err;
+        }
+
+        // Erase 4kbyte sectors
+        uint32_t chunk = 4096;
+        _cmdwrite(SPIF_SE, 3, 0, addr, NULL);
+        addr += chunk;
+        size -= chunk;
+
+        err = _sync();
+        if (err) {
+            return err;
+        }
+    }
+
+    return 0;
+}
+
+bd_size_t SPIFReducedBlockDevice::get_read_size() const
+{
+    return SPIF_READ_SIZE;
+}
+
+bd_size_t SPIFReducedBlockDevice::get_program_size() const
+{
+    return SPIF_PROG_SIZE;
+}
+
+bd_size_t SPIFReducedBlockDevice::get_erase_size() const
+{
+    return SPIF_SE_SIZE;
+}
+
+bd_size_t SPIFReducedBlockDevice::get_erase_size(bd_addr_t addr) const
+{
+    return SPIF_SE_SIZE;
+}
+
+int SPIFReducedBlockDevice::get_erase_value() const
+{
+    return 0xFF;
+}
+
+bd_size_t SPIFReducedBlockDevice::size() const
+{
+    return _size;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_RSPIF/SPIFReducedBlockDevice.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,174 @@
+/* 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_RSPIF_BLOCK_DEVICE_H
+#define MBED_RSPIF_BLOCK_DEVICE_H
+
+#include "SPI.h"
+#include "DigitalOut.h"
+#include "BlockDevice.h"
+
+/** Reduced BlockDevice for SPI based flash devices
+ *  *Should only be used by Boot Loader*
+ *
+ *  @code
+ *  // Here's an example using the SPI flash device on K82F
+ *  #include "mbed.h"
+ *  #include "SPIFReducedBlockDevice.h"
+ *
+ *  // Create flash device on SPI bus with PTE5 as chip select
+ *  SPIFReducedBlockDevice rspif(PTE2, PTE4, PTE1, PTE5);
+ *
+ *  int main() {
+ *      printf("reduced spif test\n");
+ *
+ *      // Initialize the Reduced SPI flash device and print the memory layout
+ *      rspif.init();
+ *      printf("rspif size: %llu\n",         rspif.size());
+ *      printf("rspif read size: %llu\n",    rspif.get_read_size());
+ *      printf("rspif program size: %llu\n", rspif.get_program_size());
+ *      printf("rspif erase size: %llu\n",   rspif.get_erase_size());
+ *
+ *      // Write "Hello World!" to the first block
+ *      char *buffer = (char*)malloc(rspif.get_erase_size());
+ *      sprintf(buffer, "Hello World!\n");
+ *      rspif.erase(0, rspif.get_erase_size());
+ *      rspif.program(buffer, 0, rspif.get_erase_size());
+ *
+ *      // Read back what was stored
+ *      rspif.read(buffer, 0, rspif.get_erase_size());
+ *      printf("%s", buffer);
+ *
+ *      // Deinitialize the device
+ *      rspif.deinit();
+ *  }
+ *  @endcode
+ */
+class SPIFReducedBlockDevice : public BlockDevice {
+public:
+    /** Creates a SPIFReducedBlockDevice on a SPI bus specified by pins
+     *
+     *  @param mosi     SPI master out, slave in pin
+     *  @param miso     SPI master in, slave out pin
+     *  @param sclk     SPI clock pin
+     *  @param csel     SPI chip select pin
+     *  @param freq     Clock speed of the SPI bus (defaults to 40MHz)
+     */
+    SPIFReducedBlockDevice(PinName mosi, PinName miso, PinName sclk, PinName csel, int freq = 40000000);
+
+    /** Initialize a block device
+     *
+     *  @return         0 on success or a negative error code on failure
+     */
+    virtual int init();
+
+    /** Deinitialize a block device
+     *
+     *  @return         0 on success or a negative error code on failure
+     */
+    virtual int 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         0 on success, negative error code on failure
+     */
+    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         0 on success, negative error code on failure
+     */
+    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         0 on success, negative error code on failure
+     */
+    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 programable block 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 eraseable block in bytes
+     *  @note Must be a multiple of the program size
+     */
+    virtual bd_size_t get_erase_size() const;
+
+    /** Get the size of a eraseable block
+     *
+     *  @param addr     Address of block to query erase size
+     *  @return         Size of a eraseable block in bytes
+     *  @note Must be a multiple of the program size
+     */
+    virtual bd_size_t get_erase_size(bd_addr_t addr) const;
+
+    /** 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:
+    // Master side hardware
+    mbed::SPI _spi;
+    mbed::DigitalOut _cs;
+
+    // Device configuration discovered through sfdp
+    bd_size_t _size;
+
+    // Internal functions
+    int _wren();
+    int _sync();
+    void _cmdread(uint8_t op, uint32_t addrc, uint32_t retc,
+                  uint32_t addr, uint8_t *rets);
+    void _cmdwrite(uint8_t op, uint32_t addrc, uint32_t argc,
+                   uint32_t addr, const uint8_t *args);
+};
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_RSPIF/mbed_lib.json	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,66 @@
+{
+  "name": "rspif-driver",
+  "config": {
+    "SPI_MOSI": "NC",
+    "SPI_MISO": "NC",
+    "SPI_CLK":  "NC",
+    "SPI_CS":   "NC",
+    "SPI_FREQ": "40000000"
+  },
+  "target_overrides": {
+    "K82F": {
+      "SPI_MOSI": "PTE2",
+      "SPI_MISO": "PTE4",
+      "SPI_CLK":  "PTE1",
+      "SPI_CS":   "PTE5"
+    },
+    "LPC54114": {
+      "SPI_MOSI": "P0_20",
+      "SPI_MISO": "P0_18",
+      "SPI_CLK":  "P0_19",
+      "SPI_CS":   "P1_2"
+    },
+    "NRF52840_DK": {
+      "SPI_MOSI": "p20",
+      "SPI_MISO": "p21",
+      "SPI_CLK":  "p19",
+      "SPI_CS":   "p17"
+    },
+    "HEXIWEAR": {
+      "SPI_MOSI": "PTD6",
+      "SPI_MISO": "PTD7",
+      "SPI_CLK":  "PTD5",
+      "SPI_CS":   "PTD4"
+    },
+    "MTB_UBLOX_ODIN_W2": {
+      "SPI_MOSI": "PE_14",
+      "SPI_MISO": "PE_13",
+      "SPI_CLK":  "PE_12",
+      "SPI_CS":   "PE_11"
+    },
+    "MTB_ADV_WISE_1530": {
+      "SPI_MOSI": "PC_3",
+      "SPI_MISO": "PC_2",
+      "SPI_CLK":  "PB_13",
+      "SPI_CS":   "PC_12"
+    },
+    "MTB_MXCHIP_EMW3166": {
+      "SPI_MOSI": "PB_15",
+      "SPI_MISO": "PB_14",
+      "SPI_CLK":  "PB_13",
+      "SPI_CS":   "PA_10"
+    },
+    "MTB_USI_WM_BN_BM_22": {
+      "SPI_MOSI": "PC_3",
+      "SPI_MISO": "PC_2",
+      "SPI_CLK":  "PB_13",
+      "SPI_CS":   "PA_6"
+    },
+    "MTB_ADV_WISE_1570": {
+      "SPI_MOSI": "PA_7",
+      "SPI_MISO": "PA_6",
+      "SPI_CLK":  "PA_5",
+      "SPI_CS":   "PB_12"
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_SD/SDBlockDevice.cpp	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,1096 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2013 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.
+ */
+
+/* Introduction
+ * ------------
+ * SD and MMC cards support a number of interfaces, but common to them all
+ * is one based on SPI. Since we already have the mbed SPI Interface, it will
+ * be used for SD cards.
+ *
+ * The main reference I'm using is Chapter 7, "SPI Mode" of:
+ *  http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
+ *
+ * SPI Startup
+ * -----------
+ * The SD card powers up in SD mode. The start-up procedure is complicated
+ * by the requirement to support older SDCards in a backwards compatible
+ * way with the new higher capacity variants SDHC and SDHC.
+ *
+ * The following figures from the specification with associated text describe
+ * the SPI mode initialisation process:
+ *  - Figure 7-1: SD Memory Card State Diagram (SPI mode)
+ *  - Figure 7-2: SPI Mode Initialization Flow
+ *
+ * Firstly, a low initial clock should be selected (in the range of 100-
+ * 400kHZ). After initialisation has been completed, the switch to a
+ * higher clock speed can be made (e.g. 1MHz). Newer cards will support
+ * higher speeds than the default _transfer_sck defined here.
+ *
+ * Next, note the following from the SDCard specification (note to
+ * Figure 7-1):
+ *
+ *  In any of the cases CMD1 is not recommended because it may be difficult for the host
+ *  to distinguish between MultiMediaCard and SD Memory Card
+ *
+ * Hence CMD1 is not used for the initialisation sequence.
+ *
+ * The SPI interface mode is selected by asserting CS low and sending the
+ * reset command (CMD0). The card will respond with a (R1) response.
+ * In practice many cards initially respond with 0xff or invalid data
+ * which is ignored. Data is read until a valid response is received
+ * or the number of re-reads has exceeded a maximim count. If a valid
+ * response is not received then the CMD0 can be retried. This
+ * has been found to successfully initialise cards where the SPI master
+ * (on MCU) has been reset but the SDCard has not, so the first
+ * CMD0 may be lost.
+ *
+ * CMD8 is optionally sent to determine the voltage range supported, and
+ * indirectly determine whether it is a version 1.x SD/non-SD card or
+ * version 2.x. I'll just ignore this for now.
+ *
+ * ACMD41 is repeatedly issued to initialise the card, until "in idle"
+ * (bit 0) of the R1 response goes to '0', indicating it is initialised.
+ *
+ * You should also indicate whether the host supports High Capicity cards,
+ * and check whether the card is high capacity - i'll also ignore this
+ *
+ * SPI Protocol
+ * ------------
+ * The SD SPI protocol is based on transactions made up of 8-bit words, with
+ * the host starting every bus transaction by asserting the CS signal low. The
+ * card always responds to commands, data blocks and errors.
+ *
+ * The protocol supports a CRC, but by default it is off (except for the
+ * first reset CMD0, where the CRC can just be pre-calculated, and CMD8)
+ * I'll leave the CRC off I think!
+ *
+ * Standard capacity cards have variable data block sizes, whereas High
+ * Capacity cards fix the size of data block to 512 bytes. I'll therefore
+ * just always use the Standard Capacity cards with a block size of 512 bytes.
+ * This is set with CMD16.
+ *
+ * You can read and write single blocks (CMD17, CMD25) or multiple blocks
+ * (CMD18, CMD25). For simplicity, I'll just use single block accesses. When
+ * the card gets a read command, it responds with a response token, and then
+ * a data token or an error.
+ *
+ * SPI Command Format
+ * ------------------
+ * Commands are 6-bytes long, containing the command, 32-bit argument, and CRC.
+ *
+ * +---------------+------------+------------+-----------+----------+--------------+
+ * | 01 | cmd[5:0] | arg[31:24] | arg[23:16] | arg[15:8] | arg[7:0] | crc[6:0] | 1 |
+ * +---------------+------------+------------+-----------+----------+--------------+
+ *
+ * As I'm not using CRC, I can fix that byte to what is needed for CMD0 (0x95)
+ *
+ * All Application Specific commands shall be preceded with APP_CMD (CMD55).
+ *
+ * SPI Response Format
+ * -------------------
+ * The main response format (R1) is a status byte (normally zero). Key flags:
+ *  idle - 1 if the card is in an idle state/initialising
+ *  cmd  - 1 if an illegal command code was detected
+ *
+ *    +-------------------------------------------------+
+ * R1 | 0 | arg | addr | seq | crc | cmd | erase | idle |
+ *    +-------------------------------------------------+
+ *
+ * R1b is the same, except it is followed by a busy signal (zeros) until
+ * the first non-zero byte when it is ready again.
+ *
+ * Data Response Token
+ * -------------------
+ * Every data block written to the card is acknowledged by a byte
+ * response token
+ *
+ * +----------------------+
+ * | xxx | 0 | status | 1 |
+ * +----------------------+
+ *              010 - OK!
+ *              101 - CRC Error
+ *              110 - Write Error
+ *
+ * Single Block Read and Write
+ * ---------------------------
+ *
+ * Block transfers have a byte header, followed by the data, followed
+ * by a 16-bit CRC. In our case, the data will always be 512 bytes.
+ *
+ * +------+---------+---------+- -  - -+---------+-----------+----------+
+ * | 0xFE | data[0] | data[1] |        | data[n] | crc[15:8] | crc[7:0] |
+ * +------+---------+---------+- -  - -+---------+-----------+----------+
+ */
+
+/* If the target has no SPI support then SDCard is not supported */
+#ifdef DEVICE_SPI
+
+#include "SDBlockDevice.h"
+#include "platform/mbed_debug.h"
+#include "platform/mbed_wait_api.h"
+#include <errno.h>
+
+#ifndef MBED_CONF_SD_CMD_TIMEOUT
+#define MBED_CONF_SD_CMD_TIMEOUT                 5000   /*!< Timeout in ms for response */
+#endif
+
+#ifndef MBED_CONF_SD_CMD0_IDLE_STATE_RETRIES
+#define MBED_CONF_SD_CMD0_IDLE_STATE_RETRIES     5      /*!< Number of retries for sending CMDO */
+#endif
+
+#ifndef MBED_CONF_SD_INIT_FREQUENCY
+#define MBED_CONF_SD_INIT_FREQUENCY              100000 /*!< Initialization frequency Range (100KHz-400KHz) */
+#endif
+
+
+#define SD_COMMAND_TIMEOUT                       MBED_CONF_SD_CMD_TIMEOUT
+#define SD_CMD0_GO_IDLE_STATE_RETRIES            MBED_CONF_SD_CMD0_IDLE_STATE_RETRIES
+#define SD_DBG                                   0      /*!< 1 - Enable debugging */
+#define SD_CMD_TRACE                             0      /*!< 1 - Enable SD command tracing */
+
+#define SD_BLOCK_DEVICE_ERROR_WOULD_BLOCK        -5001  /*!< operation would block */
+#define SD_BLOCK_DEVICE_ERROR_UNSUPPORTED        -5002  /*!< unsupported operation */
+#define SD_BLOCK_DEVICE_ERROR_PARAMETER          -5003  /*!< invalid parameter */
+#define SD_BLOCK_DEVICE_ERROR_NO_INIT            -5004  /*!< uninitialized */
+#define SD_BLOCK_DEVICE_ERROR_NO_DEVICE          -5005  /*!< device is missing or not connected */
+#define SD_BLOCK_DEVICE_ERROR_WRITE_PROTECTED    -5006  /*!< write protected */
+#define SD_BLOCK_DEVICE_ERROR_UNUSABLE           -5007  /*!< unusable card */
+#define SD_BLOCK_DEVICE_ERROR_NO_RESPONSE        -5008  /*!< No response from device */
+#define SD_BLOCK_DEVICE_ERROR_CRC                -5009  /*!< CRC error */
+#define SD_BLOCK_DEVICE_ERROR_ERASE              -5010  /*!< Erase error: reset/sequence */
+#define SD_BLOCK_DEVICE_ERROR_WRITE              -5011  /*!< SPI Write error: !SPI_DATA_ACCEPTED */
+
+#define BLOCK_SIZE_HC                            512    /*!< Block size supported for SD card is 512 bytes  */
+#define WRITE_BL_PARTIAL                         0      /*!< Partial block write - Not supported */
+#define SPI_CMD(x) (0x40 | (x & 0x3f))
+
+/* R1 Response Format */
+#define R1_NO_RESPONSE          (0xFF)
+#define R1_RESPONSE_RECV        (0x80)
+#define R1_IDLE_STATE           (1 << 0)
+#define R1_ERASE_RESET          (1 << 1)
+#define R1_ILLEGAL_COMMAND      (1 << 2)
+#define R1_COM_CRC_ERROR        (1 << 3)
+#define R1_ERASE_SEQUENCE_ERROR (1 << 4)
+#define R1_ADDRESS_ERROR        (1 << 5)
+#define R1_PARAMETER_ERROR      (1 << 6)
+
+// Types
+#define SDCARD_NONE              0           /**< No card is present */
+#define SDCARD_V1                1           /**< v1.x Standard Capacity */
+#define SDCARD_V2                2           /**< v2.x Standard capacity SD card */
+#define SDCARD_V2HC              3           /**< v2.x High capacity SD card */
+#define CARD_UNKNOWN             4           /**< Unknown or unsupported card */
+
+/* SIZE in Bytes */
+#define PACKET_SIZE              6           /*!< SD Packet size CMD+ARG+CRC */
+#define R1_RESPONSE_SIZE         1           /*!< Size of R1 response */
+#define R2_RESPONSE_SIZE         2           /*!< Size of R2 response */
+#define R3_R7_RESPONSE_SIZE      5           /*!< Size of R3/R7 response */
+
+/* R1b Response */
+#define DEVICE_BUSY             (0x00)
+
+/* R2 Response Format */
+#define R2_CARD_LOCKED          (1 << 0)
+#define R2_CMD_FAILED           (1 << 1)
+#define R2_ERROR                (1 << 2)
+#define R2_CC_ERROR             (1 << 3)
+#define R2_CC_FAILED            (1 << 4)
+#define R2_WP_VIOLATION         (1 << 5)
+#define R2_ERASE_PARAM          (1 << 6)
+#define R2_OUT_OF_RANGE         (1 << 7)
+
+/* R3 Response : OCR Register */
+#define OCR_HCS_CCS             (0x1 << 30)
+#define OCR_LOW_VOLTAGE         (0x01 << 24)
+#define OCR_3_3V                (0x1 << 20)
+
+/* R7 response pattern for CMD8 */
+#define CMD8_PATTERN             (0xAA)
+
+/*  CRC Enable  */
+#define CRC_ENABLE               (0)         /*!< CRC 1 - Enable 0 - Disable */
+
+/* Control Tokens   */
+#define SPI_DATA_RESPONSE_MASK   (0x1F)
+#define SPI_DATA_ACCEPTED        (0x05)
+#define SPI_DATA_CRC_ERROR       (0x0B)
+#define SPI_DATA_WRITE_ERROR     (0x0D)
+#define SPI_START_BLOCK          (0xFE)      /*!< For Single Block Read/Write and Multiple Block Read */
+#define SPI_START_BLK_MUL_WRITE  (0xFC)      /*!< Start Multi-block write */
+#define SPI_STOP_TRAN            (0xFD)      /*!< Stop Multi-block write */
+
+#define SPI_DATA_READ_ERROR_MASK (0xF)       /*!< Data Error Token: 4 LSB bits */
+#define SPI_READ_ERROR           (0x1 << 0)  /*!< Error */
+#define SPI_READ_ERROR_CC        (0x1 << 1)  /*!< CC Error*/
+#define SPI_READ_ERROR_ECC_C     (0x1 << 2)  /*!< Card ECC failed */
+#define SPI_READ_ERROR_OFR       (0x1 << 3)  /*!< Out of Range */
+
+SDBlockDevice::SDBlockDevice(PinName mosi, PinName miso, PinName sclk, PinName cs, uint64_t hz, bool crc_on)
+    : _sectors(0), _spi(mosi, miso, sclk), _cs(cs), _is_initialized(0),
+      _crc_on(crc_on), _init_ref_count(0), _crc16(0, 0, false, false)
+{
+    _cs = 1;
+    _card_type = SDCARD_NONE;
+
+    // Set default to 100kHz for initialisation and 1MHz for data transfer
+    MBED_STATIC_ASSERT(((MBED_CONF_SD_INIT_FREQUENCY >= 100000) && (MBED_CONF_SD_INIT_FREQUENCY <= 400000)),
+                       "Initialization frequency should be between 100KHz to 400KHz");
+    _init_sck = MBED_CONF_SD_INIT_FREQUENCY;
+    _transfer_sck = hz;
+
+    // Only HC block size is supported.
+    _block_size = BLOCK_SIZE_HC;
+    _erase_size = BLOCK_SIZE_HC;
+}
+
+SDBlockDevice::~SDBlockDevice()
+{
+    if (_is_initialized) {
+        deinit();
+    }
+}
+
+int SDBlockDevice::_initialise_card()
+{
+    // Detail debugging is for commands
+    _dbg = SD_DBG ? SD_CMD_TRACE : 0;
+    int32_t status = BD_ERROR_OK;
+    uint32_t response, arg;
+
+    // Initialize the SPI interface: Card by default is in SD mode
+    _spi_init();
+
+    // The card is transitioned from SDCard mode to SPI mode by sending the CMD0 + CS Asserted("0")
+    if (_go_idle_state() != R1_IDLE_STATE) {
+        debug_if(SD_DBG, "No disk, or could not put SD card in to SPI idle state\n");
+        return SD_BLOCK_DEVICE_ERROR_NO_DEVICE;
+    }
+
+    // Send CMD8, if the card rejects the command then it's probably using the
+    // legacy protocol, or is a MMC, or just flat-out broken
+    status = _cmd8();
+    if (BD_ERROR_OK != status && SD_BLOCK_DEVICE_ERROR_UNSUPPORTED != status) {
+        return status;
+    }
+
+    if (_crc_on) {
+        // Enable CRC
+        status = _cmd(CMD59_CRC_ON_OFF, _crc_on);
+    }
+
+    // Read OCR - CMD58 Response contains OCR register
+    if (BD_ERROR_OK != (status = _cmd(CMD58_READ_OCR, 0x0, 0x0, &response))) {
+        return status;
+    }
+
+    // Check if card supports voltage range: 3.3V
+    if (!(response & OCR_3_3V)) {
+        _card_type = CARD_UNKNOWN;
+        status = SD_BLOCK_DEVICE_ERROR_UNUSABLE;
+        return status;
+    }
+
+    // HCS is set 1 for HC/XC capacity cards for ACMD41, if supported
+    arg = 0x0;
+    if (SDCARD_V2 == _card_type) {
+        arg |= OCR_HCS_CCS;
+    }
+
+    /* Idle state bit in the R1 response of ACMD41 is used by the card to inform the host
+     * if initialization of ACMD41 is completed. "1" indicates that the card is still initializing.
+     * "0" indicates completion of initialization. The host repeatedly issues ACMD41 until
+     * this bit is set to "0".
+     */
+    _spi_timer.start();
+    do {
+        status = _cmd(ACMD41_SD_SEND_OP_COND, arg, 1, &response);
+    } while ((response & R1_IDLE_STATE) && (_spi_timer.read_ms() < SD_COMMAND_TIMEOUT));
+    _spi_timer.stop();
+
+    // Initialization complete: ACMD41 successful
+    if ((BD_ERROR_OK != status) || (0x00 != response)) {
+        _card_type = CARD_UNKNOWN;
+        debug_if(SD_DBG, "Timeout waiting for card\n");
+        return status;
+    }
+
+    if (SDCARD_V2 == _card_type) {
+        // Get the card capacity CCS: CMD58
+        if (BD_ERROR_OK == (status = _cmd(CMD58_READ_OCR, 0x0, 0x0, &response))) {
+            // High Capacity card
+            if (response & OCR_HCS_CCS) {
+                _card_type = SDCARD_V2HC;
+                debug_if(SD_DBG, "Card Initialized: High Capacity Card \n");
+            } else {
+                debug_if(SD_DBG, "Card Initialized: Standard Capacity Card: Version 2.x \n");
+            }
+        }
+    } else {
+        _card_type = SDCARD_V1;
+        debug_if(SD_DBG, "Card Initialized: Version 1.x Card\n");
+    }
+
+    if (!_crc_on) {
+        // Disable CRC
+        status = _cmd(CMD59_CRC_ON_OFF, _crc_on);
+    }
+    return status;
+}
+
+
+int SDBlockDevice::init()
+{
+    int err;
+
+    lock();
+
+    if (!_is_initialized) {
+        _init_ref_count = 0;
+    }
+
+    _init_ref_count++;
+
+    if (_init_ref_count != 1) {
+        goto end;
+    }
+
+    err = _initialise_card();
+    _is_initialized = (err == BD_ERROR_OK);
+    if (!_is_initialized) {
+        debug_if(SD_DBG, "Fail to initialize card\n");
+        unlock();
+        return err;
+    }
+    debug_if(SD_DBG, "init card = %d\n", _is_initialized);
+    _sectors = _sd_sectors();
+    // CMD9 failed
+    if (0 == _sectors) {
+        unlock();
+        return BD_ERROR_DEVICE_ERROR;
+    }
+
+    // Set block length to 512 (CMD16)
+    if (_cmd(CMD16_SET_BLOCKLEN, _block_size) != 0) {
+        debug_if(SD_DBG, "Set %d-byte block timed out\n", _block_size);
+        unlock();
+        return BD_ERROR_DEVICE_ERROR;
+    }
+
+    // Set SCK for data transfer
+    err = _freq();
+    if (err) {
+        unlock();
+        return err;
+    }
+
+end:
+    unlock();
+    return BD_ERROR_OK;
+}
+
+int SDBlockDevice::deinit()
+{
+    lock();
+
+    if (!_is_initialized) {
+        _init_ref_count = 0;
+        goto end;
+    }
+
+    _init_ref_count--;
+
+    if (_init_ref_count) {
+        goto end;
+    }
+
+    _is_initialized = false;
+    _sectors = 0;
+
+end:
+    unlock();
+    return BD_ERROR_OK;
+}
+
+
+int SDBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size)
+{
+    if (!is_valid_program(addr, size)) {
+        return SD_BLOCK_DEVICE_ERROR_PARAMETER;
+    }
+
+    lock();
+    if (!_is_initialized) {
+        unlock();
+        return SD_BLOCK_DEVICE_ERROR_NO_INIT;
+    }
+
+    const uint8_t *buffer = static_cast<const uint8_t *>(b);
+    int status = BD_ERROR_OK;
+    uint8_t response;
+
+    // Get block count
+    bd_addr_t blockCnt = size / _block_size;
+
+    // SDSC Card (CCS=0) uses byte unit address
+    // SDHC and SDXC Cards (CCS=1) use block unit address (512 Bytes unit)
+    if (SDCARD_V2HC == _card_type) {
+        addr = addr / _block_size;
+    }
+
+    // Send command to perform write operation
+    if (blockCnt == 1) {
+        // Single block write command
+        if (BD_ERROR_OK != (status = _cmd(CMD24_WRITE_BLOCK, addr))) {
+            unlock();
+            return status;
+        }
+
+        // Write data
+        response = _write(buffer, SPI_START_BLOCK, _block_size);
+
+        // Only CRC and general write error are communicated via response token
+        if (response != SPI_DATA_ACCEPTED) {
+            debug_if(SD_DBG, "Single Block Write failed: 0x%x \n", response);
+            status = SD_BLOCK_DEVICE_ERROR_WRITE;
+        }
+    } else {
+        // Pre-erase setting prior to multiple block write operation
+        _cmd(ACMD23_SET_WR_BLK_ERASE_COUNT, blockCnt, 1);
+
+        // Multiple block write command
+        if (BD_ERROR_OK != (status = _cmd(CMD25_WRITE_MULTIPLE_BLOCK, addr))) {
+            unlock();
+            return status;
+        }
+
+        // Write the data: one block at a time
+        do {
+            response = _write(buffer, SPI_START_BLK_MUL_WRITE, _block_size);
+            if (response != SPI_DATA_ACCEPTED) {
+                debug_if(SD_DBG, "Multiple Block Write failed: 0x%x \n", response);
+                break;
+            }
+            buffer += _block_size;
+        } while (--blockCnt);     // Receive all blocks of data
+
+        /* In a Multiple Block write operation, the stop transmission will be done by
+         * sending 'Stop Tran' token instead of 'Start Block' token at the beginning
+         * of the next block
+         */
+        _spi.write(SPI_STOP_TRAN);
+    }
+
+    _deselect();
+    unlock();
+    return status;
+}
+
+int SDBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size)
+{
+    if (!is_valid_read(addr, size)) {
+        return SD_BLOCK_DEVICE_ERROR_PARAMETER;
+    }
+
+    lock();
+    if (!_is_initialized) {
+        unlock();
+        return SD_BLOCK_DEVICE_ERROR_PARAMETER;
+    }
+
+    uint8_t *buffer = static_cast<uint8_t *>(b);
+    int status = BD_ERROR_OK;
+    bd_addr_t blockCnt =  size / _block_size;
+
+    // SDSC Card (CCS=0) uses byte unit address
+    // SDHC and SDXC Cards (CCS=1) use block unit address (512 Bytes unit)
+    if (SDCARD_V2HC == _card_type) {
+        addr = addr / _block_size;
+    }
+
+    // Write command ro receive data
+    if (blockCnt > 1) {
+        status = _cmd(CMD18_READ_MULTIPLE_BLOCK, addr);
+    } else {
+        status = _cmd(CMD17_READ_SINGLE_BLOCK, addr);
+    }
+    if (BD_ERROR_OK != status) {
+        unlock();
+        return status;
+    }
+
+    // receive the data : one block at a time
+    while (blockCnt) {
+        if (0 != _read(buffer, _block_size)) {
+            status = SD_BLOCK_DEVICE_ERROR_NO_RESPONSE;
+            break;
+        }
+        buffer += _block_size;
+        --blockCnt;
+    }
+    _deselect();
+
+    // Send CMD12(0x00000000) to stop the transmission for multi-block transfer
+    if (size > _block_size) {
+        status = _cmd(CMD12_STOP_TRANSMISSION, 0x0);
+    }
+    unlock();
+    return status;
+}
+
+bool SDBlockDevice::_is_valid_trim(bd_addr_t addr, bd_size_t size)
+{
+    return (
+               addr % _erase_size == 0 &&
+               size % _erase_size == 0 &&
+               addr + size <= this->size());
+}
+
+int SDBlockDevice::trim(bd_addr_t addr, bd_size_t size)
+{
+    if (!_is_valid_trim(addr, size)) {
+        return SD_BLOCK_DEVICE_ERROR_PARAMETER;
+    }
+
+    lock();
+    if (!_is_initialized) {
+        unlock();
+        return SD_BLOCK_DEVICE_ERROR_NO_INIT;
+    }
+    int status = BD_ERROR_OK;
+
+    size -= _block_size;
+    // SDSC Card (CCS=0) uses byte unit address
+    // SDHC and SDXC Cards (CCS=1) use block unit address (512 Bytes unit)
+    if (SDCARD_V2HC == _card_type) {
+        size = size / _block_size;
+        addr = addr / _block_size;
+    }
+
+    // Start lba sent in start command
+    if (BD_ERROR_OK != (status = _cmd(CMD32_ERASE_WR_BLK_START_ADDR, addr))) {
+        unlock();
+        return status;
+    }
+
+    // End lba = addr+size sent in end addr command
+    if (BD_ERROR_OK != (status = _cmd(CMD33_ERASE_WR_BLK_END_ADDR, addr + size))) {
+        unlock();
+        return status;
+    }
+    status = _cmd(CMD38_ERASE, 0x0);
+    unlock();
+    return status;
+}
+
+bd_size_t SDBlockDevice::get_read_size() const
+{
+    return _block_size;
+}
+
+bd_size_t SDBlockDevice::get_program_size() const
+{
+    return _block_size;
+}
+
+bd_size_t SDBlockDevice::size() const
+{
+    return _block_size * _sectors;
+}
+
+void SDBlockDevice::debug(bool dbg)
+{
+    _dbg = dbg;
+}
+
+int SDBlockDevice::frequency(uint64_t freq)
+{
+    lock();
+    _transfer_sck = freq;
+    int err = _freq();
+    unlock();
+    return err;
+}
+
+// PRIVATE FUNCTIONS
+int SDBlockDevice::_freq(void)
+{
+    // Max frequency supported is 25MHZ
+    if (_transfer_sck <= 25000000) {
+        _spi.frequency(_transfer_sck);
+        return 0;
+    } else {  // TODO: Switch function to be implemented for higher frequency
+        _transfer_sck = 25000000;
+        _spi.frequency(_transfer_sck);
+        return -EINVAL;
+    }
+}
+
+uint8_t SDBlockDevice::_cmd_spi(SDBlockDevice::cmdSupported cmd, uint32_t arg)
+{
+    uint8_t response;
+    char cmdPacket[PACKET_SIZE];
+    uint32_t crc;
+
+    // Prepare the command packet
+    cmdPacket[0] = SPI_CMD(cmd);
+    cmdPacket[1] = (arg >> 24);
+    cmdPacket[2] = (arg >> 16);
+    cmdPacket[3] = (arg >> 8);
+    cmdPacket[4] = (arg >> 0);
+
+    if (_crc_on) {
+        _crc7.compute((void *)cmdPacket, 5, &crc);
+        cmdPacket[5] = (char)(crc | 0x01);
+    } else {
+        // CMD0 is executed in SD mode, hence should have correct CRC
+        // CMD8 CRC verification is always enabled
+        switch (cmd) {
+            case CMD0_GO_IDLE_STATE:
+                cmdPacket[5] = 0x95;
+                break;
+            case CMD8_SEND_IF_COND:
+                cmdPacket[5] = 0x87;
+                break;
+            default:
+                cmdPacket[5] = 0xFF;    // Make sure bit 0-End bit is high
+                break;
+        }
+    }
+
+    // send a command
+    for (int i = 0; i < PACKET_SIZE; i++) {
+        _spi.write(cmdPacket[i]);
+    }
+
+    // The received byte immediataly following CMD12 is a stuff byte,
+    // it should be discarded before receive the response of the CMD12.
+    if (CMD12_STOP_TRANSMISSION == cmd) {
+        _spi.write(SPI_FILL_CHAR);
+    }
+
+    // Loop for response: Response is sent back within command response time (NCR), 0 to 8 bytes for SDC
+    for (int i = 0; i < 0x10; i++) {
+        response = _spi.write(SPI_FILL_CHAR);
+        // Got the response
+        if (!(response & R1_RESPONSE_RECV)) {
+            break;
+        }
+    }
+    return response;
+}
+
+int SDBlockDevice::_cmd(SDBlockDevice::cmdSupported cmd, uint32_t arg, bool isAcmd, uint32_t *resp)
+{
+    int32_t status = BD_ERROR_OK;
+    uint32_t response;
+
+    // Select card and wait for card to be ready before sending next command
+    // Note: next command will fail if card is not ready
+    _select();
+
+    // No need to wait for card to be ready when sending the stop command
+    if (CMD12_STOP_TRANSMISSION != cmd) {
+        if (false == _wait_ready(SD_COMMAND_TIMEOUT)) {
+            debug_if(SD_DBG, "Card not ready yet \n");
+        }
+    }
+
+    // Re-try command
+    for (int i = 0; i < 3; i++) {
+        // Send CMD55 for APP command first
+        if (isAcmd) {
+            response = _cmd_spi(CMD55_APP_CMD, 0x0);
+            // Wait for card to be ready after CMD55
+            if (false == _wait_ready(SD_COMMAND_TIMEOUT)) {
+                debug_if(SD_DBG, "Card not ready yet \n");
+            }
+        }
+
+        // Send command over SPI interface
+        response = _cmd_spi(cmd, arg);
+        if (R1_NO_RESPONSE == response) {
+            debug_if(SD_DBG, "No response CMD:%d \n", cmd);
+            continue;
+        }
+        break;
+    }
+
+    // Pass the response to the command call if required
+    if (NULL != resp) {
+        *resp = response;
+    }
+
+    // Process the response R1  : Exit on CRC/Illegal command error/No response
+    if (R1_NO_RESPONSE == response) {
+        _deselect();
+        debug_if(SD_DBG, "No response CMD:%d response: 0x%x\n", cmd, response);
+        return SD_BLOCK_DEVICE_ERROR_NO_DEVICE;         // No device
+    }
+    if (response & R1_COM_CRC_ERROR) {
+        _deselect();
+        debug_if(SD_DBG, "CRC error CMD:%d response 0x%x \n", cmd, response);
+        return SD_BLOCK_DEVICE_ERROR_CRC;                // CRC error
+    }
+    if (response & R1_ILLEGAL_COMMAND) {
+        _deselect();
+        debug_if(SD_DBG, "Illegal command CMD:%d response 0x%x\n", cmd, response);
+        if (CMD8_SEND_IF_COND == cmd) {                  // Illegal command is for Ver1 or not SD Card
+            _card_type = CARD_UNKNOWN;
+        }
+        return SD_BLOCK_DEVICE_ERROR_UNSUPPORTED;      // Command not supported
+    }
+
+    debug_if(_dbg, "CMD:%d \t arg:0x%x \t Response:0x%x \n", cmd, arg, response);
+    // Set status for other errors
+    if ((response & R1_ERASE_RESET) || (response & R1_ERASE_SEQUENCE_ERROR)) {
+        status = SD_BLOCK_DEVICE_ERROR_ERASE;            // Erase error
+    } else if ((response & R1_ADDRESS_ERROR) || (response & R1_PARAMETER_ERROR)) {
+        // Misaligned address / invalid address block length
+        status = SD_BLOCK_DEVICE_ERROR_PARAMETER;
+    }
+
+    // Get rest of the response part for other commands
+    switch (cmd) {
+        case CMD8_SEND_IF_COND:             // Response R7
+            debug_if(_dbg, "V2-Version Card\n");
+            _card_type = SDCARD_V2;
+        // Note: No break here, need to read rest of the response
+        case CMD58_READ_OCR:                // Response R3
+            response  = (_spi.write(SPI_FILL_CHAR) << 24);
+            response |= (_spi.write(SPI_FILL_CHAR) << 16);
+            response |= (_spi.write(SPI_FILL_CHAR) << 8);
+            response |= _spi.write(SPI_FILL_CHAR);
+            debug_if(_dbg, "R3/R7: 0x%x \n", response);
+            break;
+
+        case CMD12_STOP_TRANSMISSION:       // Response R1b
+        case CMD38_ERASE:
+            _wait_ready(SD_COMMAND_TIMEOUT);
+            break;
+
+        case ACMD13_SD_STATUS:             // Response R2
+            response = _spi.write(SPI_FILL_CHAR);
+            debug_if(_dbg, "R2: 0x%x \n", response);
+            break;
+
+        default:                            // Response R1
+            break;
+    }
+
+    // Pass the updated response to the command
+    if (NULL != resp) {
+        *resp = response;
+    }
+
+    // Do not deselect card if read is in progress.
+    if (((CMD9_SEND_CSD == cmd) || (ACMD22_SEND_NUM_WR_BLOCKS == cmd) ||
+            (CMD24_WRITE_BLOCK == cmd) || (CMD25_WRITE_MULTIPLE_BLOCK == cmd) ||
+            (CMD17_READ_SINGLE_BLOCK == cmd) || (CMD18_READ_MULTIPLE_BLOCK == cmd))
+            && (BD_ERROR_OK == status)) {
+        return BD_ERROR_OK;
+    }
+    // Deselect card
+    _deselect();
+    return status;
+}
+
+int SDBlockDevice::_cmd8()
+{
+    uint32_t arg = (CMD8_PATTERN << 0);         // [7:0]check pattern
+    uint32_t response = 0;
+    int32_t status = BD_ERROR_OK;
+
+    arg |= (0x1 << 8);  // 2.7-3.6V             // [11:8]supply voltage(VHS)
+
+    status = _cmd(CMD8_SEND_IF_COND, arg, 0x0, &response);
+    // Verify voltage and pattern for V2 version of card
+    if ((BD_ERROR_OK == status) && (SDCARD_V2 == _card_type)) {
+        // If check pattern is not matched, CMD8 communication is not valid
+        if ((response & 0xFFF) != arg) {
+            debug_if(SD_DBG, "CMD8 Pattern mismatch 0x%x : 0x%x\n", arg, response);
+            _card_type = CARD_UNKNOWN;
+            status = SD_BLOCK_DEVICE_ERROR_UNUSABLE;
+        }
+    }
+    return status;
+}
+
+uint32_t SDBlockDevice::_go_idle_state()
+{
+    uint32_t response;
+
+    /* Reseting the MCU SPI master may not reset the on-board SDCard, in which
+     * case when MCU power-on occurs the SDCard will resume operations as
+     * though there was no reset. In this scenario the first CMD0 will
+     * not be interpreted as a command and get lost. For some cards retrying
+     * the command overcomes this situation. */
+    for (int i = 0; i < SD_CMD0_GO_IDLE_STATE_RETRIES; i++) {
+        _cmd(CMD0_GO_IDLE_STATE, 0x0, 0x0, &response);
+        if (R1_IDLE_STATE == response) {
+            break;
+        }
+        wait_ms(1);
+    }
+    return response;
+}
+
+int SDBlockDevice::_read_bytes(uint8_t *buffer, uint32_t length)
+{
+    uint16_t crc;
+
+    // read until start byte (0xFE)
+    if (false == _wait_token(SPI_START_BLOCK)) {
+        debug_if(SD_DBG, "Read timeout\n");
+        _deselect();
+        return SD_BLOCK_DEVICE_ERROR_NO_RESPONSE;
+    }
+
+    // read data
+    for (uint32_t i = 0; i < length; i++) {
+        buffer[i] = _spi.write(SPI_FILL_CHAR);
+    }
+
+    // Read the CRC16 checksum for the data block
+    crc = (_spi.write(SPI_FILL_CHAR) << 8);
+    crc |= _spi.write(SPI_FILL_CHAR);
+
+    if (_crc_on) {
+        uint32_t crc_result;
+        // Compute and verify checksum
+        _crc16.compute((void *)buffer, length, &crc_result);
+        if ((uint16_t)crc_result != crc) {
+            debug_if(SD_DBG, "_read_bytes: Invalid CRC received 0x%x result of computation 0x%x\n",
+                     crc, crc_result);
+            _deselect();
+            return SD_BLOCK_DEVICE_ERROR_CRC;
+        }
+    }
+
+    _deselect();
+    return 0;
+}
+
+int SDBlockDevice::_read(uint8_t *buffer, uint32_t length)
+{
+    uint16_t crc;
+
+    // read until start byte (0xFE)
+    if (false == _wait_token(SPI_START_BLOCK)) {
+        debug_if(SD_DBG, "Read timeout\n");
+        return SD_BLOCK_DEVICE_ERROR_NO_RESPONSE;
+    }
+
+    // read data
+    _spi.write(NULL, 0, (char *)buffer, length);
+
+    // Read the CRC16 checksum for the data block
+    crc = (_spi.write(SPI_FILL_CHAR) << 8);
+    crc |= _spi.write(SPI_FILL_CHAR);
+
+    if (_crc_on) {
+        uint32_t crc_result;
+        // Compute and verify checksum
+        _crc16.compute((void *)buffer, length, &crc_result);
+        if ((uint16_t)crc_result != crc) {
+            debug_if(SD_DBG, "_read_bytes: Invalid CRC received 0x%x result of computation 0x%x\n",
+                     crc, crc_result);
+            return SD_BLOCK_DEVICE_ERROR_CRC;
+        }
+    }
+
+    return 0;
+}
+
+uint8_t SDBlockDevice::_write(const uint8_t *buffer, uint8_t token, uint32_t length)
+{
+
+    uint32_t crc = (~0);
+    uint8_t response = 0xFF;
+
+    // indicate start of block
+    _spi.write(token);
+
+    // write the data
+    _spi.write((char *)buffer, length, NULL, 0);
+
+    if (_crc_on) {
+        // Compute CRC
+        _crc16.compute((void *)buffer, length, &crc);
+    }
+
+    // write the checksum CRC16
+    _spi.write(crc >> 8);
+    _spi.write(crc);
+
+
+    // check the response token
+    response = _spi.write(SPI_FILL_CHAR);
+
+    // Wait for last block to be written
+    if (false == _wait_ready(SD_COMMAND_TIMEOUT)) {
+        debug_if(SD_DBG, "Card not ready yet \n");
+    }
+
+    return (response & SPI_DATA_RESPONSE_MASK);
+}
+
+static uint32_t ext_bits(unsigned char *data, int msb, int lsb)
+{
+    uint32_t bits = 0;
+    uint32_t size = 1 + msb - lsb;
+    for (uint32_t i = 0; i < size; i++) {
+        uint32_t position = lsb + i;
+        uint32_t byte = 15 - (position >> 3);
+        uint32_t bit = position & 0x7;
+        uint32_t value = (data[byte] >> bit) & 1;
+        bits |= value << i;
+    }
+    return bits;
+}
+
+bd_size_t SDBlockDevice::_sd_sectors()
+{
+    uint32_t c_size, c_size_mult, read_bl_len;
+    uint32_t block_len, mult, blocknr;
+    uint32_t hc_c_size;
+    bd_size_t blocks = 0, capacity = 0;
+
+    // CMD9, Response R2 (R1 byte + 16-byte block read)
+    if (_cmd(CMD9_SEND_CSD, 0x0) != 0x0) {
+        debug_if(SD_DBG, "Didn't get a response from the disk\n");
+        return 0;
+    }
+    uint8_t csd[16];
+    if (_read_bytes(csd, 16) != 0) {
+        debug_if(SD_DBG, "Couldn't read csd response from disk\n");
+        return 0;
+    }
+
+    // csd_structure : csd[127:126]
+    int csd_structure = ext_bits(csd, 127, 126);
+    switch (csd_structure) {
+        case 0:
+            c_size = ext_bits(csd, 73, 62);              // c_size        : csd[73:62]
+            c_size_mult = ext_bits(csd, 49, 47);         // c_size_mult   : csd[49:47]
+            read_bl_len = ext_bits(csd, 83, 80);         // read_bl_len   : csd[83:80] - the *maximum* read block length
+            block_len = 1 << read_bl_len;                // BLOCK_LEN = 2^READ_BL_LEN
+            mult = 1 << (c_size_mult + 2);               // MULT = 2^C_SIZE_MULT+2 (C_SIZE_MULT < 8)
+            blocknr = (c_size + 1) * mult;               // BLOCKNR = (C_SIZE+1) * MULT
+            capacity = blocknr * block_len;              // memory capacity = BLOCKNR * BLOCK_LEN
+            blocks = capacity / _block_size;
+            debug_if(SD_DBG, "Standard Capacity: c_size: %d \n", c_size);
+            debug_if(SD_DBG, "Sectors: 0x%x : %llu\n", blocks, blocks);
+            debug_if(SD_DBG, "Capacity: 0x%x : %llu MB\n", capacity, (capacity / (1024U * 1024U)));
+
+            // ERASE_BLK_EN = 1: Erase in multiple of 512 bytes supported
+            if (ext_bits(csd, 46, 46)) {
+                _erase_size = BLOCK_SIZE_HC;
+            } else {
+                // ERASE_BLK_EN = 1: Erase in multiple of SECTOR_SIZE supported
+                _erase_size = BLOCK_SIZE_HC * (ext_bits(csd, 45, 39) + 1);
+            }
+            break;
+
+        case 1:
+            hc_c_size = ext_bits(csd, 69, 48);            // device size : C_SIZE : [69:48]
+            blocks = (hc_c_size + 1) << 10;               // block count = C_SIZE+1) * 1K byte (512B is block size)
+            debug_if(SD_DBG, "SDHC/SDXC Card: hc_c_size: %d \n", hc_c_size);
+            debug_if(SD_DBG, "Sectors: 0x%x : %llu\n", blocks, blocks);
+            debug_if(SD_DBG, "Capacity: %llu MB\n", (blocks / (2048U)));
+            // ERASE_BLK_EN is fixed to 1, which means host can erase one or multiple of 512 bytes.
+            _erase_size = BLOCK_SIZE_HC;
+            break;
+
+        default:
+            debug_if(SD_DBG, "CSD struct unsupported\r\n");
+            return 0;
+    };
+    return blocks;
+}
+
+// SPI function to wait till chip is ready and sends start token
+bool SDBlockDevice::_wait_token(uint8_t token)
+{
+    _spi_timer.reset();
+    _spi_timer.start();
+
+    do {
+        if (token == _spi.write(SPI_FILL_CHAR)) {
+            _spi_timer.stop();
+            return true;
+        }
+    } while (_spi_timer.read_ms() < 300);       // Wait for 300 msec for start token
+    _spi_timer.stop();
+    debug_if(SD_DBG, "_wait_token: timeout\n");
+    return false;
+}
+
+// SPI function to wait till chip is ready
+// The host controller should wait for end of the process until DO goes high (a 0xFF is received).
+bool SDBlockDevice::_wait_ready(uint16_t ms)
+{
+    uint8_t response;
+    _spi_timer.reset();
+    _spi_timer.start();
+    do {
+        response = _spi.write(SPI_FILL_CHAR);
+        if (response == 0xFF) {
+            _spi_timer.stop();
+            return true;
+        }
+    } while (_spi_timer.read_ms() < ms);
+    _spi_timer.stop();
+    return false;
+}
+
+// SPI function to wait for count
+void SDBlockDevice::_spi_wait(uint8_t count)
+{
+    for (uint8_t i = 0; i < count; ++i) {
+        _spi.write(SPI_FILL_CHAR);
+    }
+}
+
+void SDBlockDevice::_spi_init()
+{
+    _spi.lock();
+    // Set to SCK for initialization, and clock card with cs = 1
+    _spi.frequency(_init_sck);
+    _spi.format(8, 0);
+    _spi.set_default_write_value(SPI_FILL_CHAR);
+    // Initial 74 cycles required for few cards, before selecting SPI mode
+    _cs = 1;
+    _spi_wait(10);
+    _spi.unlock();
+}
+
+void SDBlockDevice::_select()
+{
+    _spi.lock();
+    _spi.write(SPI_FILL_CHAR);
+    _cs = 0;
+}
+
+void SDBlockDevice::_deselect()
+{
+    _cs = 1;
+    _spi.write(SPI_FILL_CHAR);
+    _spi.unlock();
+}
+
+#endif  /* DEVICE_SPI */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_SD/SDBlockDevice.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,230 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2013 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_SD_BLOCK_DEVICE_H
+#define MBED_SD_BLOCK_DEVICE_H
+
+/* If the target has no SPI support then SDCard is not supported */
+#ifdef DEVICE_SPI
+
+#include "BlockDevice.h"
+#include "drivers/SPI.h"
+#include "drivers/Timer.h"
+#include "drivers/MbedCRC.h"
+#include "drivers/DigitalOut.h"
+#include "platform/platform.h"
+#include "platform/PlatformMutex.h"
+
+/** SDBlockDevice class
+ *
+ * Access an SD Card using SPI
+ */
+class SDBlockDevice : public BlockDevice {
+public:
+    /** Lifetime of an SD card
+     */
+    SDBlockDevice(PinName mosi, PinName miso, PinName sclk, PinName cs, uint64_t hz = 1000000, bool crc_on = 0);
+    virtual ~SDBlockDevice();
+
+    /** Initialize a block device
+     *
+     *  @return         0 on success or a negative error code on failure
+     */
+    virtual int init();
+
+    /** Deinitialize a block device
+     *
+     *  @return         0 on success or a negative error code on failure
+     */
+    virtual int 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         0 on success, negative error code on failure
+     */
+    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         0 on success, negative error code on failure
+     */
+    virtual int program(const void *buffer, bd_addr_t addr, bd_size_t size);
+
+    /** Mark blocks as no longer in use
+     *
+     *  This function provides a hint to the underlying block device that a region of blocks
+     *  is no longer in use and may be erased without side effects. Erase must still be called
+     *  before programming, but trimming allows flash-translation-layers to schedule erases when
+     *  the device is not busy.
+     *
+     *  @param addr     Address of block to mark as unused
+     *  @param size     Size to mark as unused in bytes, must be a multiple of erase block size
+     *  @return         0 on success, negative error code on failure
+     */
+    virtual int trim(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 programable block in bytes
+     *  @note Must be a multiple of the read size
+     */
+    virtual bd_size_t get_program_size() const;
+
+    /** Get the total size of the underlying device
+     *
+     *  @return         Size of the underlying device in bytes
+     */
+    virtual bd_size_t size() const;
+
+    /** Enable or disable debugging
+     *
+     *  @param dbg        State of debugging
+     */
+    virtual void debug(bool dbg);
+
+    /** Set the transfer frequency
+     *
+     *  @param freq     Transfer frequency
+     *  @note Max frequency supported is 25MHZ
+     */
+    virtual int frequency(uint64_t freq);
+
+
+private:
+    /* Commands : Listed below are commands supported
+     * in SPI mode for SD card : Only Mandatory ones
+     */
+    enum cmdSupported {
+        CMD_NOT_SUPPORTED = -1,             /**< Command not supported error */
+        CMD0_GO_IDLE_STATE = 0,             /**< Resets the SD Memory Card */
+        CMD1_SEND_OP_COND = 1,              /**< Sends host capacity support */
+        CMD6_SWITCH_FUNC = 6,               /**< Check and Switches card function */
+        CMD8_SEND_IF_COND = 8,              /**< Supply voltage info */
+        CMD9_SEND_CSD = 9,                  /**< Provides Card Specific data */
+        CMD10_SEND_CID = 10,                /**< Provides Card Identification */
+        CMD12_STOP_TRANSMISSION = 12,       /**< Forces the card to stop transmission */
+        CMD13_SEND_STATUS = 13,             /**< Card responds with status */
+        CMD16_SET_BLOCKLEN = 16,            /**< Length for SC card is set */
+        CMD17_READ_SINGLE_BLOCK = 17,       /**< Read single block of data */
+        CMD18_READ_MULTIPLE_BLOCK = 18,     /**< Card transfers data blocks to host until interrupted
+                                                 by a STOP_TRANSMISSION command */
+        CMD24_WRITE_BLOCK = 24,             /**< Write single block of data */
+        CMD25_WRITE_MULTIPLE_BLOCK = 25,    /**< Continuously writes blocks of data until
+                                                 'Stop Tran' token is sent */
+        CMD27_PROGRAM_CSD = 27,             /**< Programming bits of CSD */
+        CMD32_ERASE_WR_BLK_START_ADDR = 32, /**< Sets the address of the first write
+                                                 block to be erased. */
+        CMD33_ERASE_WR_BLK_END_ADDR = 33,   /**< Sets the address of the last write
+                                                 block of the continuous range to be erased.*/
+        CMD38_ERASE = 38,                   /**< Erases all previously selected write blocks */
+        CMD55_APP_CMD = 55,                 /**< Extend to Applications specific commands */
+        CMD56_GEN_CMD = 56,                 /**< General Purpose Command */
+        CMD58_READ_OCR = 58,                /**< Read OCR register of card */
+        CMD59_CRC_ON_OFF = 59,              /**< Turns the CRC option on or off*/
+        // App Commands
+        ACMD6_SET_BUS_WIDTH = 6,
+        ACMD13_SD_STATUS = 13,
+        ACMD22_SEND_NUM_WR_BLOCKS = 22,
+        ACMD23_SET_WR_BLK_ERASE_COUNT = 23,
+        ACMD41_SD_SEND_OP_COND = 41,
+        ACMD42_SET_CLR_CARD_DETECT = 42,
+        ACMD51_SEND_SCR = 51,
+    };
+
+    uint8_t _card_type;
+    int _cmd(SDBlockDevice::cmdSupported cmd, uint32_t arg, bool isAcmd = 0, uint32_t *resp = NULL);
+    int _cmd8();
+
+    /*  Move the SDCard into the SPI Mode idle state
+     *
+     *  The card is transitioned from SDCard mode to SPI mode by sending the
+     *  CMD0 (GO_IDLE_STATE) command with CS asserted. See the notes in the
+     *  "SPI Startup" section of the comments at the head of the
+     *  implementation file for further details and specification references.
+     *
+     *  @return         Response form the card. R1_IDLE_STATE (0x1), the successful
+     *                  response from CMD0. R1_XXX_XXX for more response
+     */
+    uint32_t _go_idle_state();
+    int _initialise_card();
+
+    bd_size_t _sectors;
+    bd_size_t _sd_sectors();
+
+    bool _is_valid_trim(bd_addr_t addr, bd_size_t size);
+
+    /* SPI functions */
+    mbed::Timer _spi_timer;               /**< Timer Class object used for busy wait */
+    uint32_t _init_sck;             /**< Intial SPI frequency */
+    uint32_t _transfer_sck;         /**< SPI frequency during data transfer/after initialization */
+    mbed::SPI _spi;                       /**< SPI Class object */
+
+    /* SPI initialization function */
+    void _spi_init();
+    uint8_t _cmd_spi(SDBlockDevice::cmdSupported cmd, uint32_t arg);
+    void _spi_wait(uint8_t count);
+
+    bool _wait_token(uint8_t token);        /**< Wait for token */
+    bool _wait_ready(uint16_t ms = 300);    /**< 300ms default wait for card to be ready */
+    int _read(uint8_t *buffer, uint32_t length);
+    int _read_bytes(uint8_t *buffer, uint32_t length);
+    uint8_t _write(const uint8_t *buffer, uint8_t token, uint32_t length);
+    int _freq(void);
+
+    /* Chip Select and SPI mode select */
+    mbed::DigitalOut _cs;
+    void _select();
+    void _deselect();
+
+    virtual void lock()
+    {
+        _mutex.lock();
+    }
+
+    virtual void unlock()
+    {
+        _mutex.unlock();
+    }
+
+    PlatformMutex _mutex;
+    bd_size_t _block_size;
+    bd_size_t _erase_size;
+    bool _is_initialized;
+    bool _dbg;
+    bool _crc_on;
+    uint32_t _init_ref_count;
+
+    mbed::MbedCRC<POLY_7BIT_SD, 7> _crc7;
+    mbed::MbedCRC<POLY_16BIT_CCITT, 16> _crc16;
+};
+
+#endif  /* DEVICE_SPI */
+
+#endif  /* MBED_SD_BLOCK_DEVICE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_SD/TESTS/filesystem/dirs/main.cpp	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,500 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2016 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 "mbed.h"
+#include "greentea-client/test_env.h"
+#include "unity.h"
+#include "utest.h"
+#include <stdlib.h>
+#include <errno.h>
+
+using namespace utest::v1;
+
+// test configuration
+#ifndef MBED_TEST_FILESYSTEM
+#define MBED_TEST_FILESYSTEM FATFileSystem
+#endif
+
+#ifndef MBED_TEST_FILESYSTEM_DECL
+#define MBED_TEST_FILESYSTEM_DECL MBED_TEST_FILESYSTEM fs("fs")
+#endif
+
+#ifndef MBED_TEST_BLOCKDEVICE
+#define MBED_TEST_BLOCKDEVICE SDBlockDevice
+#define MBED_TEST_BLOCKDEVICE_DECL SDBlockDevice bd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS);
+#endif
+
+#ifndef MBED_TEST_BLOCKDEVICE_DECL
+#define MBED_TEST_BLOCKDEVICE_DECL MBED_TEST_BLOCKDEVICE bd
+#endif
+
+#ifndef MBED_TEST_FILES
+#define MBED_TEST_FILES 4
+#endif
+
+#ifndef MBED_TEST_DIRS
+#define MBED_TEST_DIRS 4
+#endif
+
+#ifndef MBED_TEST_BUFFER
+#define MBED_TEST_BUFFER 8192
+#endif
+
+#ifndef MBED_TEST_TIMEOUT
+#define MBED_TEST_TIMEOUT 120
+#endif
+
+
+// declarations
+#define STRINGIZE(x) STRINGIZE2(x)
+#define STRINGIZE2(x) #x
+#define INCLUDE(x) STRINGIZE(x.h)
+
+#include INCLUDE(MBED_TEST_FILESYSTEM)
+#include INCLUDE(MBED_TEST_BLOCKDEVICE)
+
+MBED_TEST_FILESYSTEM_DECL;
+MBED_TEST_BLOCKDEVICE_DECL;
+
+Dir dir[MBED_TEST_DIRS];
+File file[MBED_TEST_FILES];
+DIR *dd[MBED_TEST_DIRS];
+FILE *fd[MBED_TEST_FILES];
+struct dirent ent;
+struct dirent *ed;
+size_t size;
+uint8_t buffer[MBED_TEST_BUFFER];
+uint8_t rbuffer[MBED_TEST_BUFFER];
+uint8_t wbuffer[MBED_TEST_BUFFER];
+
+
+// tests
+
+void test_directory_tests()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = MBED_TEST_FILESYSTEM::format(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void test_root_directory()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = dir[0].open(&fs, "/");
+        TEST_ASSERT_EQUAL(0, res);
+        res = dir[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void test_directory_creation()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.mkdir("potato", 0777);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void test_file_creation()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].open(&fs, "burito", O_CREAT | O_WRONLY);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void dir_file_check(char *list[], uint32_t elements)
+{
+    int res;
+    while (1) {
+        res = dir[0].read(&ent);
+        if (0 == res) {
+            break;
+        }
+        for (int i = 0; i < elements ; i++) {
+            res = strcmp(ent.d_name, list[i]);
+            if (0 == res) {
+                res = ent.d_type;
+                if ((DT_DIR != res) && (DT_REG != res)) {
+                    TEST_ASSERT(1);
+                }
+                break;
+            } else if (i == elements) {
+                TEST_ASSERT_EQUAL(0, res);
+            }
+        }
+    }
+}
+
+void test_directory_iteration()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    res = fs.mount(&bd);
+    TEST_ASSERT_EQUAL(0, res);
+    res = dir[0].open(&fs, "/");
+    TEST_ASSERT_EQUAL(0, res);
+    char *dir_list[] = {"potato", "burito", ".", ".."};
+
+    dir_file_check(dir_list, (sizeof(dir_list) / sizeof(dir_list[0])));
+
+    res = dir[0].close();
+    TEST_ASSERT_EQUAL(0, res);
+    res = fs.unmount();
+    TEST_ASSERT_EQUAL(0, res);
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void test_directory_failures()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.mkdir("potato", 0777);
+        TEST_ASSERT_EQUAL(-EEXIST, res);
+        res = dir[0].open(&fs, "tomato");
+        TEST_ASSERT_EQUAL(-ENOTDIR, res);
+        res = dir[0].open(&fs, "burito");
+        TEST_ASSERT_NOT_EQUAL(0, res);
+        res = file[0].open(&fs, "tomato", O_RDONLY);
+        TEST_ASSERT_EQUAL(-ENOENT, res);
+        res = file[0].open(&fs, "potato", O_RDONLY);
+        TEST_ASSERT_NOT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void test_nested_directories()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.mkdir("potato/baked", 0777);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.mkdir("potato/sweet", 0777);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.mkdir("potato/fried", 0777);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = dir[0].open(&fs, "/");
+        TEST_ASSERT_EQUAL(0, res);
+        char *dir_list[] = {"potato", "baked", "sweet", "fried", ".", ".."};
+        dir_file_check(dir_list, (sizeof(dir_list) / sizeof(dir_list[0])));
+        res = dir[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void test_multi_block_directory()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.mkdir("cactus", 0777);
+        TEST_ASSERT_EQUAL(0, res);
+        for (int i = 0; i < 128; i++) {
+            sprintf((char *)buffer, "cactus/test%d", i);
+            res = fs.mkdir((char *)buffer, 0777);
+            TEST_ASSERT_EQUAL(0, res);
+        }
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = dir[0].open(&fs, "cactus");
+        TEST_ASSERT_EQUAL(0, res);
+
+#if (MBED_TEST_FILESYSTEM != FATFileSystem)
+        char *dir_list[] = {".", ".."};
+        dir_file_check(dir_list, (sizeof(dir_list) / sizeof(dir_list[0])));
+#endif
+
+        for (int i = 0; i < 128; i++) {
+            sprintf((char *)buffer, "test%d", i);
+            res = dir[0].read(&ent);
+            TEST_ASSERT_EQUAL(1, res);
+            res = strcmp(ent.d_name, (char *)buffer);
+            TEST_ASSERT_EQUAL(0, res);
+        }
+        res = dir[0].read(&ent);
+        TEST_ASSERT_EQUAL(0, res);
+        res = dir[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void test_directory_remove()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.remove("potato");
+        TEST_ASSERT_NOT_EQUAL(0, res);
+        res = fs.remove("potato/sweet");
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.remove("potato/baked");
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.remove("potato/fried");
+        TEST_ASSERT_EQUAL(0, res);
+        res = dir[0].open(&fs, "potato");
+        TEST_ASSERT_EQUAL(0, res);
+
+#if (MBED_TEST_FILESYSTEM != FATFileSystem)
+        char *dir_list[] = {".", ".."};
+        dir_file_check(dir_list, (sizeof(dir_list) / sizeof(dir_list[0])));
+#endif
+
+        res = dir[0].read(&ent);
+        TEST_ASSERT_EQUAL(0, res);
+        res = dir[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.remove("potato");
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = dir[0].open(&fs, "/");
+        TEST_ASSERT_EQUAL(0, res);
+        char *dir_list[] = {"burito", "cactus", ".", ".."};
+        dir_file_check(dir_list, (sizeof(dir_list) / sizeof(dir_list[0])));
+        res = dir[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void test_directory_rename()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.mkdir("coldpotato", 0777);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.mkdir("coldpotato/baked", 0777);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.mkdir("coldpotato/sweet", 0777);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.mkdir("coldpotato/fried", 0777);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.rename("coldpotato", "hotpotato");
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = dir[0].open(&fs, "hotpotato");
+        TEST_ASSERT_EQUAL(0, res);
+        char *dir_list[] = {"baked", "sweet", "fried", ".", ".."};
+        dir_file_check(dir_list, (sizeof(dir_list) / sizeof(dir_list[0])));
+        res = dir[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.mkdir("warmpotato", 0777);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.mkdir("warmpotato/mushy", 0777);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.rename("hotpotato", "warmpotato");
+        TEST_ASSERT_NOT_EQUAL(0, res);
+        res = fs.remove("warmpotato/mushy");
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.remove("warmpotato");
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.rename("hotpotato", "warmpotato");
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = dir[0].open(&fs, "warmpotato");
+        TEST_ASSERT_EQUAL(0, res);
+        char *dir_list[] = {"baked", "sweet", "fried", ".", ".."};
+        dir_file_check(dir_list, (sizeof(dir_list) / sizeof(dir_list[0])));
+        res = dir[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.mkdir("coldpotato", 0777);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.rename("warmpotato/baked", "coldpotato/baked");
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.rename("warmpotato/sweet", "coldpotato/sweet");
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.rename("warmpotato/fried", "coldpotato/fried");
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.remove("coldpotato");
+        TEST_ASSERT_NOT_EQUAL(0, res);
+        res = fs.remove("warmpotato");
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = dir[0].open(&fs, "coldpotato");
+        TEST_ASSERT_EQUAL(0, res);
+        char *dir_list[] = {"baked", "sweet", "fried", ".", ".."};
+        dir_file_check(dir_list, (sizeof(dir_list) / sizeof(dir_list[0])));
+        res = dir[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+
+
+// test setup
+utest::v1::status_t test_setup(const size_t number_of_cases)
+{
+    GREENTEA_SETUP(MBED_TEST_TIMEOUT, "default_auto");
+    return verbose_test_setup_handler(number_of_cases);
+}
+
+Case cases[] = {
+    Case("Directory tests", test_directory_tests),
+    Case("Root directory", test_root_directory),
+    Case("Directory creation", test_directory_creation),
+    Case("File creation", test_file_creation),
+    Case("Directory iteration", test_directory_iteration),
+    Case("Directory failures", test_directory_failures),
+    Case("Nested directories", test_nested_directories),
+    Case("Multi-block directory", test_multi_block_directory),
+    Case("Directory remove", test_directory_remove),
+    Case("Directory rename", test_directory_rename),
+};
+
+Specification specification(test_setup, cases);
+
+int main()
+{
+    return !Harness::run(specification);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_SD/TESTS/filesystem/files/main.cpp	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,337 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2016 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 "mbed.h"
+#include "greentea-client/test_env.h"
+#include "unity.h"
+#include "utest.h"
+#include <stdlib.h>
+#include <errno.h>
+
+using namespace utest::v1;
+
+// test configuration
+#ifndef MBED_TEST_FILESYSTEM
+#define MBED_TEST_FILESYSTEM FATFileSystem
+#endif
+
+#ifndef MBED_TEST_FILESYSTEM_DECL
+#define MBED_TEST_FILESYSTEM_DECL MBED_TEST_FILESYSTEM fs("fs")
+#endif
+
+#ifndef MBED_TEST_BLOCKDEVICE
+#define MBED_TEST_BLOCKDEVICE SDBlockDevice
+#define MBED_TEST_BLOCKDEVICE_DECL SDBlockDevice bd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS);
+#endif
+
+#ifndef MBED_TEST_BLOCKDEVICE_DECL
+#define MBED_TEST_BLOCKDEVICE_DECL MBED_TEST_BLOCKDEVICE bd
+#endif
+
+#ifndef MBED_TEST_FILES
+#define MBED_TEST_FILES 4
+#endif
+
+#ifndef MBED_TEST_DIRS
+#define MBED_TEST_DIRS 4
+#endif
+
+#ifndef MBED_TEST_BUFFER
+#define MBED_TEST_BUFFER 8192
+#endif
+
+#ifndef MBED_TEST_TIMEOUT
+#define MBED_TEST_TIMEOUT 120
+#endif
+
+
+// declarations
+#define STRINGIZE(x) STRINGIZE2(x)
+#define STRINGIZE2(x) #x
+#define INCLUDE(x) STRINGIZE(x.h)
+
+#include INCLUDE(MBED_TEST_FILESYSTEM)
+#include INCLUDE(MBED_TEST_BLOCKDEVICE)
+
+MBED_TEST_FILESYSTEM_DECL;
+MBED_TEST_BLOCKDEVICE_DECL;
+
+Dir dir[MBED_TEST_DIRS];
+File file[MBED_TEST_FILES];
+DIR *dd[MBED_TEST_DIRS];
+FILE *fd[MBED_TEST_FILES];
+struct dirent ent;
+struct dirent *ed;
+size_t size;
+uint8_t buffer[MBED_TEST_BUFFER];
+uint8_t rbuffer[MBED_TEST_BUFFER];
+uint8_t wbuffer[MBED_TEST_BUFFER];
+
+static char file_counter = 0;
+const char *filenames[] = {"smallavacado", "mediumavacado", "largeavacado",
+                           "blockfile", "bigblockfile", "hello", ".", ".."
+                          };
+
+// tests
+
+void test_file_tests()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = MBED_TEST_FILESYSTEM::format(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void test_simple_file_test()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].open(&fs, "hello", O_WRONLY | O_CREAT);
+        TEST_ASSERT_EQUAL(0, res);
+        size = strlen("Hello World!\n");
+        memcpy(wbuffer, "Hello World!\n", size);
+        res = file[0].write(wbuffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = file[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].open(&fs, "hello", O_RDONLY);
+        TEST_ASSERT_EQUAL(0, res);
+        size = strlen("Hello World!\n");
+        res = file[0].read(rbuffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = memcmp(rbuffer, wbuffer, size);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+template <int file_size, int write_size, int read_size>
+void test_write_file_test()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        size_t size = file_size;
+        size_t chunk = write_size;
+        srand(0);
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].open(&fs, filenames[file_counter], O_WRONLY | O_CREAT);
+        TEST_ASSERT_EQUAL(0, res);
+        for (size_t i = 0; i < size; i += chunk) {
+            chunk = (chunk < size - i) ? chunk : size - i;
+            for (size_t b = 0; b < chunk; b++) {
+                buffer[b] = rand() & 0xff;
+            }
+            res = file[0].write(buffer, chunk);
+            TEST_ASSERT_EQUAL(chunk, res);
+        }
+        res = file[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    {
+        size_t size = file_size;
+        size_t chunk = read_size;
+        srand(0);
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].open(&fs, filenames[file_counter], O_RDONLY);
+        TEST_ASSERT_EQUAL(0, res);
+        for (size_t i = 0; i < size; i += chunk) {
+            chunk = (chunk < size - i) ? chunk : size - i;
+            res = file[0].read(buffer, chunk);
+            TEST_ASSERT_EQUAL(chunk, res);
+            for (size_t b = 0; b < chunk && i + b < size; b++) {
+                res = buffer[b];
+                TEST_ASSERT_EQUAL(rand() & 0xff, res);
+            }
+        }
+        res = file[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    file_counter++;
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void test_non_overlap_check()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        size_t size = 32;
+        size_t chunk = 29;
+        srand(0);
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].open(&fs, "smallavacado", O_RDONLY);
+        TEST_ASSERT_EQUAL(0, res);
+        for (size_t i = 0; i < size; i += chunk) {
+            chunk = (chunk < size - i) ? chunk : size - i;
+            res = file[0].read(buffer, chunk);
+            TEST_ASSERT_EQUAL(chunk, res);
+            for (size_t b = 0; b < chunk && i + b < size; b++) {
+                res = buffer[b];
+                TEST_ASSERT_EQUAL(rand() & 0xff, res);
+            }
+        }
+        res = file[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    {
+        size_t size = 8192;
+        size_t chunk = 29;
+        srand(0);
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].open(&fs, "mediumavacado", O_RDONLY);
+        TEST_ASSERT_EQUAL(0, res);
+        for (size_t i = 0; i < size; i += chunk) {
+            chunk = (chunk < size - i) ? chunk : size - i;
+            res = file[0].read(buffer, chunk);
+            TEST_ASSERT_EQUAL(chunk, res);
+            for (size_t b = 0; b < chunk && i + b < size; b++) {
+                res = buffer[b];
+                TEST_ASSERT_EQUAL(rand() & 0xff, res);
+            }
+        }
+        res = file[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    {
+        size_t size = 262144;
+        size_t chunk = 29;
+        srand(0);
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].open(&fs, "largeavacado", O_RDONLY);
+        TEST_ASSERT_EQUAL(0, res);
+        for (size_t i = 0; i < size; i += chunk) {
+            chunk = (chunk < size - i) ? chunk : size - i;
+            res = file[0].read(buffer, chunk);
+            TEST_ASSERT_EQUAL(chunk, res);
+            for (size_t b = 0; b < chunk && i + b < size; b++) {
+                res = buffer[b];
+                TEST_ASSERT_EQUAL(rand() & 0xff, res);
+            }
+        }
+        res = file[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void test_dir_check()
+{
+
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = dir[0].open(&fs, "/");
+        TEST_ASSERT_EQUAL(0, res);
+        int numFiles = sizeof(filenames) / sizeof(filenames[0]);
+        // Check the filenames in directory
+        while (1) {
+            res = dir[0].read(&ent);
+            if (0 == res) {
+                break;
+            }
+            for (int i = 0; i < numFiles ; i++) {
+                res = strcmp(ent.d_name, filenames[i]);
+                if (0 == res) {
+                    res = ent.d_type;
+                    if ((DT_REG != res) && (DT_DIR != res)) {
+                        TEST_ASSERT(1);
+                    }
+                    break;
+                } else if (i == numFiles) {
+                    TEST_ASSERT_EQUAL(0, res);
+                }
+            }
+        }
+        res = dir[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+
+// test setup
+utest::v1::status_t test_setup(const size_t number_of_cases)
+{
+    GREENTEA_SETUP(MBED_TEST_TIMEOUT, "default_auto");
+    return verbose_test_setup_handler(number_of_cases);
+}
+
+Case cases[] = {
+    Case("File tests", test_file_tests),
+    Case("Simple file test", test_simple_file_test),
+    Case("Small file test", test_write_file_test<32, 31, 29>),
+    Case("Medium file test", test_write_file_test<8192, 31, 29>),
+    Case("Large file test", test_write_file_test<262144, 31, 29>),
+    Case("Block Size file test", test_write_file_test<9000, 512, 512>),
+    Case("Multiple block size file test", test_write_file_test<26215, MBED_TEST_BUFFER, MBED_TEST_BUFFER>),
+    Case("Non-overlap check", test_non_overlap_check),
+    Case("Dir check", test_dir_check),
+};
+
+Specification specification(test_setup, cases);
+
+int main()
+{
+    return !Harness::run(specification);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_SD/TESTS/filesystem/fopen/fopen.cpp	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,1621 @@
+/*
+ * mbed Microcontroller Library
+ * Copyright (c) 2006-2016 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.
+ */
+
+/** @file fopen.cpp Test cases to POSIX file fopen() interface.
+ *
+ * Please consult the documentation under the test-case functions for
+ * a description of the individual test case.
+ */
+
+#include "mbed.h"
+#include "mbed_config.h"
+#include "SDBlockDevice.h"
+#include "FATFileSystem.h"
+#include "fsfat_debug.h"
+#include "fsfat_test.h"
+#include "utest/utest.h"
+#include "unity/unity.h"
+#include "greentea-client/test_env.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>     /*rand()*/
+#include <inttypes.h>
+#include <errno.h>
+/* mbed_retarget.h is included after errno.h so symbols are mapped to
+ * consistent values for all toolchains */
+#include "platform/mbed_retarget.h"
+
+using namespace utest::v1;
+
+/// @cond FSFAT_DOXYGEN_DISABLE
+#ifdef FSFAT_DEBUG
+#define FSFAT_FOPEN_GREENTEA_TIMEOUT_S     3000
+#else
+#define FSFAT_FOPEN_GREENTEA_TIMEOUT_S     1000
+#endif
+/// @endcond
+
+
+/* DEVICE_SPI
+ *  This symbol is defined in targets.json if the target has a SPI interface, which is required for SDCard support.
+ *
+ * MBED_CONF_APP_FSFAT_SDCARD_INSTALLED
+ *  For testing purposes, an SDCard must be installed on the target for the test cases in this file to succeed.
+ *  If the target has an SD card installed then the MBED_CONF_APP_FSFAT_SDCARD_INSTALLED will be generated
+ *  from the mbed_app.json, which includes the line
+ *    {
+ *    "config": {
+ *        "UART_RX": "D0",
+ *        <<< lines removed >>>
+ *        "DEVICE_SPI": 1,
+ *        "FSFAT_SDCARD_INSTALLED": 1
+ *      },
+ *      <<< lines removed >>>
+ */
+
+#if defined(DEVICE_SPI) && ( defined(MBED_CONF_APP_FSFAT_SDCARD_INSTALLED) || (MBED_CONF_SD_FSFAT_SDCARD_INSTALLED))
+static char fsfat_fopen_utest_msg_g[FSFAT_UTEST_MSG_BUF_SIZE];
+#define FSFAT_FOPEN_TEST_MOUNT_PT_NAME      "sd"
+#define FSFAT_FOPEN_TEST_MOUNT_PT_PATH      "/" FSFAT_FOPEN_TEST_MOUNT_PT_NAME
+#define FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1    64
+#define FSFAT_FOPEN_TEST_FILEPATH_MAX_DEPTH 20
+static const char *sd_badfile_path = "/sd/badfile.txt";
+static const char *sd_testfile_path = "/sd/test.txt";
+
+SDBlockDevice sd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS);
+FATFileSystem fs("sd", &sd);
+
+#define FSFAT_FOPEN_TEST_01      fsfat_fopen_test_01
+#define FSFAT_FOPEN_TEST_02      fsfat_fopen_test_02
+#define FSFAT_FOPEN_TEST_03      fsfat_fopen_test_03
+#define FSFAT_FOPEN_TEST_04      fsfat_fopen_test_04
+#define FSFAT_FOPEN_TEST_05      fsfat_fopen_test_05
+#define FSFAT_FOPEN_TEST_06      fsfat_fopen_test_06
+#define FSFAT_FOPEN_TEST_07      fsfat_fopen_test_07
+#define FSFAT_FOPEN_TEST_08      fsfat_fopen_test_08
+#define FSFAT_FOPEN_TEST_09      fsfat_fopen_test_09
+#define FSFAT_FOPEN_TEST_10      fsfat_fopen_test_10
+#define FSFAT_FOPEN_TEST_11      fsfat_fopen_test_11
+#define FSFAT_FOPEN_TEST_12      fsfat_fopen_test_12
+#define FSFAT_FOPEN_TEST_13      fsfat_fopen_test_13
+#define FSFAT_FOPEN_TEST_14      fsfat_fopen_test_14
+#define FSFAT_FOPEN_TEST_15      fsfat_fopen_test_15
+#define FSFAT_FOPEN_TEST_16      fsfat_fopen_test_16
+#define FSFAT_FOPEN_TEST_17      fsfat_fopen_test_17
+#define FSFAT_FOPEN_TEST_18      fsfat_fopen_test_18
+#define FSFAT_FOPEN_TEST_19      fsfat_fopen_test_19
+#define FSFAT_FOPEN_TEST_20      fsfat_fopen_test_20
+#define FSFAT_FOPEN_TEST_21      fsfat_fopen_test_21
+#define FSFAT_FOPEN_TEST_22      fsfat_fopen_test_22
+#define FSFAT_FOPEN_TEST_23      fsfat_fopen_test_23
+#define FSFAT_FOPEN_TEST_24      fsfat_fopen_test_24
+#define FSFAT_FOPEN_TEST_25      fsfat_fopen_test_25
+#define FSFAT_FOPEN_TEST_26      fsfat_fopen_test_26
+#define FSFAT_FOPEN_TEST_27      fsfat_fopen_test_27
+#define FSFAT_FOPEN_TEST_28      fsfat_fopen_test_28
+#define FSFAT_FOPEN_TEST_29      fsfat_fopen_test_29
+#define FSFAT_FOPEN_TEST_30      fsfat_fopen_test_30
+
+
+/* support functions */
+
+/*
+ * open tests that focus on testing fopen()
+ * fsfat_handle_t fopen(const char* filename, char* data, size_t* len, fsfat_key_desc_t* kdesc)
+ */
+
+/* file data for test_01 */
+static fsfat_kv_data_t fsfat_fopen_test_01_kv_data[] = {
+    { "/sd/fopentst/hello/world/animal/wobbly/dog/foot/frontlft.txt", "missing"},
+    { NULL, NULL},
+};
+
+
+/** @brief
+ * Split a file path into its component parts, setting '/' characters to '\0', and returning
+ * pointers to the file path components in the parts array. For example, if
+ * filepath = "/sd/fopentst/hello/world/animal/wobbly/dog/foot/frontlft.txt" then
+ *  *parts[0] = "sd"
+ *  *parts[1] = "fopentst"
+ *  *parts[2] = "hello"
+ *  *parts[3] = "world"
+ *  *parts[4] = "animal"
+ *  *parts[5] = "wobbly"
+ *  *parts[6] = "dog"
+ *  *parts[7] = "foot"
+ *  *parts[8] = "frontlft.txt"
+ *   parts[9] = NULL
+ *
+ * ARGUMENTS
+ *  @param  filepath     IN file path string to split into component parts. Expected to start with '/'
+ *  @param  parts        IN OUT array to hold pointers to parts
+ *  @param  num          IN number of components available in parts
+ *
+ * @return  On success, this returns the number of components in the filepath Returns number of compoee
+ */
+static int32_t fsfat_filepath_split(char *filepath, char *parts[], uint32_t num)
+{
+    uint32_t i = 0;
+    int32_t ret = -1;
+    char *z = filepath;
+
+    while (i < num && *z != '\0') {
+        if (*z == '/') {
+            *z = '\0';
+            parts[i] = ++z;
+            i++;
+        } else {
+            z++;
+        }
+    }
+    if (*z == '\0' && i > 0) {
+        ret = (int32_t) i;
+    }
+    return ret;
+}
+
+
+/** @brief
+ * remove all directories and file in the given filepath
+ *
+ * ARGUMENTS
+ *  @param  filepath     IN file path string to split into component parts. Expected to start with '/'
+ *
+ * @return  On success, this returns 0, otherwise < 0 is returned;
+ */
+int32_t fsfat_filepath_remove_all(char *filepath)
+{
+    int32_t ret = -1;
+    int32_t len = 0;
+    char *fpathbuf = NULL;
+    char *pos = NULL;
+
+    FSFAT_FENTRYLOG("%s:entered\n", __func__);
+    len = strlen(filepath);
+    fpathbuf = (char *) malloc(len + 1);
+    if (fpathbuf == NULL) {
+        FSFAT_DBGLOG("%s: failed to duplicate string (out of memory)\n", __func__);
+        return ret;
+    }
+    memset(fpathbuf, 0, len + 1);
+    memcpy(fpathbuf, filepath, len);
+
+    /* delete the leaf node first, and then successively parent directories. */
+    pos = fpathbuf + strlen(fpathbuf);
+    while (pos != fpathbuf) {
+        /* If the remaining file path is the mount point path then finish as the mount point cannot be removed */
+        if (strlen(fpathbuf) == strlen(FSFAT_FOPEN_TEST_MOUNT_PT_PATH)) {
+            if (strncmp(fpathbuf, FSFAT_FOPEN_TEST_MOUNT_PT_PATH, strlen(fpathbuf)) == 0) {
+                break;
+            }
+        }
+        ret = remove(fpathbuf);
+        pos = strrchr(fpathbuf, '/');
+        *pos = '\0';
+    }
+    if (fpathbuf) {
+        free(fpathbuf);
+    }
+    return ret;
+}
+
+
+/** @brief
+ * make all directories in the given filepath. Do not create the file if present at end of filepath
+ *
+ * ARGUMENTS
+ *  @param  filepath     IN file path containing directories and file
+ *  @param  do_asserts   IN set to true if function should assert on errors
+ *
+ * @return  On success, this returns 0, otherwise < 0 is returned;
+ */
+static int32_t fsfat_filepath_make_dirs(char *filepath, bool do_asserts)
+{
+    int32_t i = 0;
+    int32_t num_parts = 0;
+    int32_t len = 0;
+    int32_t ret = -1;
+    char *fpathbuf = NULL;
+    char *buf = NULL;
+    int pos = 0;
+    char *parts[FSFAT_FOPEN_TEST_FILEPATH_MAX_DEPTH];
+
+    FSFAT_DBGLOG("%s:entered\n", __func__);
+    /* find the dirs to create*/
+    memset(parts, 0, sizeof(parts));
+    len = strlen(filepath);
+    fpathbuf = (char *) malloc(len + 1);
+    if (fpathbuf == NULL) {
+        FSFAT_DBGLOG("%s: failed to duplicate string (out of memory)\n", __func__);
+        return ret;
+    }
+    memset(fpathbuf, 0, len + 1);
+    memcpy(fpathbuf, filepath, len);
+    num_parts = fsfat_filepath_split(fpathbuf, parts, FSFAT_FOPEN_TEST_FILEPATH_MAX_DEPTH);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to split filepath (filename=\"%s\", num_parts=%d)\n", __func__, filepath, (int) num_parts);
+    TEST_ASSERT_MESSAGE(num_parts > 0, fsfat_fopen_utest_msg_g);
+
+    /* Now create the directories on the directory path.
+     * Skip creating dir for "/sd" which must be present */
+    buf = (char *) malloc(strlen(filepath) + 1);
+    memset(buf, 0, strlen(filepath) + 1);
+    pos = sprintf(buf, "/%s", parts[0]);
+    for (i = 1; i < num_parts - 1; i++) {
+        pos += sprintf(buf + pos, "/%s", parts[i]);
+        FSFAT_DBGLOG("mkdir(%s)\n", buf);
+        ret = mkdir(buf, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+        if (do_asserts == true) {
+            FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                                     "%s:Error: failed to create directory (filepath2=\"%s\", ret=%d, errno=%d)\n", __func__, buf, (int) ret, errno);
+            TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+        }
+    }
+
+    if (buf) {
+        free(buf);
+    }
+    if (fpathbuf) {
+        free(fpathbuf);
+    }
+    return ret;
+}
+
+
+/* FIX ME: errno not set correctly when error occurs. This indicates a problem with the implementation. */
+
+/** @brief
+ * Basic fopen test which does the following:
+ * - creates file and writes some data to the value blob.
+ * - closes the newly created file.
+ * - opens the file (r-only)
+ * - reads the file data and checks its the same as the previously created data.
+ * - closes the opened file
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+static control_t fsfat_fopen_test_01(const size_t call_count)
+{
+    char *read_buf;
+    int32_t ret = 0;
+    size_t len = 0;
+    fsfat_kv_data_t *node;
+    FILE *fp = NULL;
+
+    FSFAT_DBGLOG("%s:entered\n", __func__);
+    (void) call_count;
+    node = fsfat_fopen_test_01_kv_data;
+
+    /* remove file and directory from a previous failed test run, if present */
+    fsfat_filepath_remove_all((char *) node->filename);
+
+    /* create dirs */
+    ret = fsfat_filepath_make_dirs((char *) node->filename, true);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to create dirs for filename (filename=\"%s\")(ret=%d)\n", __func__, node->filename, (int) ret);
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+
+    FSFAT_DBGLOG("%s:About to create new file (filename=\"%s\", data=\"%s\")\n", __func__, node->filename, node->value);
+    fp = fopen(node->filename, "w+");
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to create file (filename=\"%s\", data=\"%s\")(ret=%d, errno=%d)\n", __func__, node->filename,
+                             node->value, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g);
+
+    FSFAT_DBGLOG("%s:length of file=%d (filename=\"%s\", data=\"%s\")\n", __func__, (int) len, node->filename, node->value);
+    len = strlen(node->value);
+    ret = fwrite((const void *) node->value, len, 1, fp);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to write file (filename=\"%s\", data=\"%s\")(ret=%d)\n", __func__, node->filename, node->value,
+                             (int) ret);
+    TEST_ASSERT_MESSAGE(ret == 1, fsfat_fopen_utest_msg_g);
+
+    FSFAT_DBGLOG("Created file successfully (filename=\"%s\", data=\"%s\")\n", node->filename, node->value);
+    ret = fclose(fp);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to close file (ret=%d, errno=%d)\n", __func__, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+
+    /* now open the newly created key */
+    fp = NULL;
+    fp = fopen(node->filename, "r");
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to open file for reading (filename=\"%s\", data=\"%s\")(ret=%d)\n", __func__, node->filename,
+                             node->value, (int) ret);
+    TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g);
+
+    len = strlen(node->value) + 1;
+    read_buf = (char *) malloc(len);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to allocated read buffer \n", __func__);
+    TEST_ASSERT_MESSAGE(read_buf != NULL, fsfat_fopen_utest_msg_g);
+
+    FSFAT_DBGLOG("Opened file successfully (filename=\"%s\", data=\"%s\")\n", node->filename, node->value);
+    memset(read_buf, 0, len);
+    ret = fread((void *) read_buf, len, 1, fp);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to read file (filename=\"%s\", data=\"%s\", read_buf=\"%s\", ret=%d)\n", __func__, node->filename,
+                             node->value, read_buf, (int) ret);
+    /* FIX ME: fread should return the number of items read, not 0 when an item is read successfully.
+     * This indicates a problem with the implementation, as the correct data is read. The correct assert should be:
+     *   TEST_ASSERT_MESSAGE(ret == 1, fsfat_fopen_utest_msg_g);
+     * The following assert is curerntly used until the implementation is fixed
+     */
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+
+    /* check read data is as expected */
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: read value data (%s) != expected value data (filename=\"%s\", data=\"%s\", read_buf=\"%s\", ret=%d)\n",
+                             __func__, read_buf, node->filename, node->value, read_buf, (int) ret);
+    TEST_ASSERT_MESSAGE(strncmp(read_buf, node->value, strlen(node->value)) == 0, fsfat_fopen_utest_msg_g);
+
+    if (read_buf) {
+        free(read_buf);
+    }
+    ret = fclose(fp);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: fclose() call failed (ret=%d, errno=%d).\n", __func__, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+    return CaseNext;
+}
+
+static fsfat_kv_data_t fsfat_fopen_test_02_data[] = {
+    FSFAT_INIT_1_TABLE_MID_NODE,
+    { NULL, NULL},
+};
+
+/**
+ * @brief   test to fopen() a pre-existing key and try to write it, which should fail
+ *          as by default pre-existing keys are opened read-only
+ *
+ * Basic open test which does the following:
+ * - creates file with default rw perms and writes some data to the value blob.
+ * - closes the newly created file.
+ * - opens the file with the default permissions (read-only)
+ * - tries to write the file data which should fail because file was not opened with write flag set.
+ * - closes the opened key
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fsfat_fopen_test_02(const size_t call_count)
+{
+    int32_t ret = -1;
+    size_t len = 0;
+    FILE *fp = NULL;
+
+    FSFAT_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+    len = strlen(fsfat_fopen_test_02_data[0].value);
+    ret = fsfat_test_create(fsfat_fopen_test_02_data[0].filename, (char *) fsfat_fopen_test_02_data[0].value, len);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret);
+    TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
+
+    /* by default, owner of key opens with read-only permissions*/
+    fp = fopen(fsfat_fopen_test_02_data[0].filename, "r");
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to open file (filename=\"%s\", ret=%d)\n", __func__, fsfat_fopen_test_02_data[0].filename, (int) ret);
+    TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g);
+
+    len = strlen(fsfat_fopen_test_02_data[0].value);
+    ret = fwrite((const void *) fsfat_fopen_test_02_data[0].value, len, 1, fp);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: call to fwrite() succeeded when should have failed for read-only file (filename=\"%s\")(ret=%d).\n",
+                             __func__, fsfat_fopen_test_02_data[0].filename, (int) ret);
+    TEST_ASSERT_MESSAGE(ret <= 0, fsfat_fopen_utest_msg_g);
+
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: fclose() call failed.\n",
+                             __func__);
+    TEST_ASSERT_MESSAGE(fclose(fp) == 0, fsfat_fopen_utest_msg_g);
+
+    return CaseNext;
+}
+
+
+/**
+ * @brief   test to fopen() a pre-existing file and try to write it, which should succeed
+ *          because the key was opened read-write permissions explicitly
+ *
+ * Basic open test which does the following:
+ * - creates file with default rw perms and writes some data to the value blob.
+ * - closes the newly created file.
+ * - opens the file with the rw permissions (non default)
+ * - tries to write the file data which should succeeds because file was opened with write flag set.
+ * - closes the opened key
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fsfat_fopen_test_03(const size_t call_count)
+{
+    int32_t ret = -1;
+    size_t len = 0;
+    FILE *fp = NULL;
+
+    FSFAT_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+    len = strlen(fsfat_fopen_test_02_data[0].value);
+    ret = fsfat_test_create(fsfat_fopen_test_02_data[0].filename, (char *) fsfat_fopen_test_02_data[0].value, len);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to create file in store (ret=%d).\n", __func__, (int) ret);
+    TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
+
+    /* opens with read-write permissions*/
+    fp = fopen(fsfat_fopen_test_02_data[0].filename, "w+");
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to open file (filename=\"%s\")(ret=%d)\n", __func__, fsfat_fopen_test_02_data[0].filename, (int) ret);
+    TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
+
+    len = strlen(fsfat_fopen_test_02_data[0].value);
+    ret = fwrite((const void *) fsfat_fopen_test_02_data[0].value, len, 1, fp);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: call to fwrite() failed when should have succeeded (filename=\"%s\", ret=%d).\n", __func__,
+                             fsfat_fopen_test_02_data[0].filename, (int) ret);
+    TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
+
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: fclose() call failed.\n",
+                             __func__);
+    TEST_ASSERT_MESSAGE(fclose(fp) >= 0, fsfat_fopen_utest_msg_g);
+
+    /* clean-up */
+    ret = remove(fsfat_fopen_test_02_data[0].filename);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: unable to delete file (filename=%s, ret=%d) .\n", __func__, fsfat_fopen_test_02_data[0].filename, (int) ret);
+    TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
+
+    return CaseNext;
+}
+
+
+/** @brief  test to call fopen() with a filename string that exceeds the maximum length
+ * - chanFS supports the exFAT format which should support 255 char filenames
+ * - check that filenames of this length can be created
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fsfat_fopen_test_04(const size_t call_count)
+{
+    char filename_good[FSFAT_FILENAME_MAX_LENGTH + 1];
+    char filename_bad[FSFAT_FILENAME_MAX_LENGTH + 2];
+    int32_t ret = -1;
+    size_t len = 0;
+
+    FSFAT_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+    memset(filename_good, 0, FSFAT_FILENAME_MAX_LENGTH + 1);
+    memset(filename_bad, 0, FSFAT_FILENAME_MAX_LENGTH + 2);
+    ret = fsfat_test_filename_gen(filename_good, FSFAT_FILENAME_MAX_LENGTH);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: unable to generate filename_good.\n", __func__);
+    TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
+
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: filename_good is not the correct length (filename_good=%s, len=%d, expected=%d).\n", __func__, filename_good,
+                             (int) strlen(filename_good), (int) FSFAT_FILENAME_MAX_LENGTH);
+    TEST_ASSERT_MESSAGE(strlen(filename_good) == FSFAT_FILENAME_MAX_LENGTH, fsfat_fopen_utest_msg_g);
+
+    ret = fsfat_test_filename_gen(filename_bad, FSFAT_FILENAME_MAX_LENGTH + 1);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: unable to generate filename_bad.\n", __func__);
+    TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: filename_bad is not the correct length (len=%d, expected=%d).\n", __func__, (int) strlen(filename_bad),
+                             (int) FSFAT_FILENAME_MAX_LENGTH + 1);
+    TEST_ASSERT_MESSAGE(strlen(filename_bad) == FSFAT_FILENAME_MAX_LENGTH + 1, fsfat_fopen_utest_msg_g);
+
+    len = strlen(filename_good);
+    ret = fsfat_test_create(filename_good, filename_good, len);
+    /* FIXME:
+     * The current implementation can create file with a filename with 9 chars (more than the 8 restriction of FAT32 Short File Names).
+     * However, the exFAT 255 char filesnames is not supported and hence the following is commented out. Find out what is
+     * the supported max filename length and change this testcase according.
+     *
+     *  FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create file (filename=%s, ret=%d).\n", __func__, filename_good, (int) ret);
+     *  TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
+     */
+
+    len = strlen(filename_bad);
+    ret = fsfat_test_create(filename_bad, filename_bad, len);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: created file in store for filename_bad when should have failed (filename=%s, ret=%d).\n", __func__,
+                             filename_bad, (int) ret);
+    TEST_ASSERT_MESSAGE(ret < 0, fsfat_fopen_utest_msg_g);
+    return CaseNext;
+}
+
+
+/// @cond FSFAT_DOXYGEN_DISABLE
+typedef struct fsfat_fopen_kv_name_ascii_node {
+    uint32_t code;
+    uint32_t f_allowed : 1;
+} fsfat_fopen_kv_name_ascii_node;
+/// @endcond
+
+static const uint32_t fsfat_fopen_kv_name_ascii_table_code_sentinel_g = 256;
+
+/*@brief    table recording ascii character codes permitted in kv names */
+static fsfat_fopen_kv_name_ascii_node fsfat_fopen_kv_name_ascii_table[] = {
+    {0, true},          /* code 0-33 allowed*/
+    {34, false},        /* '"' not allowed */
+    {35, true},         /* allowed */
+    {42, false},        /* '*' not allowed */
+    {43, true},         /* allowed */
+    {47, false},        /* '/' not allowed */
+    {48, true},         /* allowed */
+    {58, false},        /* ':' not allowed */
+    {59, true},         /* allowed */
+    {60, false},        /* '<' not allowed */
+    {61, true},         /* allowed */
+    {62, false},        /* '?', '>' not allowed */
+    {64, true},         /* allowed */
+    {92, false},        /* '\' not allowed */
+    {93, true},         /* allowed */
+    {124, false},        /* '!' not allowed */
+    {125, true},         /* allowed */
+    {127, false},        /* DEL not allowed */
+    {128, true},         /* allowed */
+    {fsfat_fopen_kv_name_ascii_table_code_sentinel_g, false},       /* sentinel */
+};
+
+
+/// @cond FSFAT_DOXYGEN_DISABLE
+enum fsfat_fopen_kv_name_pos {
+    fsfat_fopen_kv_name_pos_start = 0x0,
+    fsfat_fopen_kv_name_pos_mid,
+    fsfat_fopen_kv_name_pos_end,
+    fsfat_fopen_kv_name_pos_max
+};
+/// @endcond
+
+/** @brief  test to call fopen() with filename that in includes illegal characters
+ *          - the character(s) can be at the beginning of the filename
+ *          - the character(s) can be at the end of the filename
+ *          - the character(s) can be somewhere within the filename string
+ *          - a max-length string of random characters (legal and illegal)
+ *          - a max-length string of random illegal characters only
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fsfat_fopen_test_05(const size_t call_count)
+{
+    bool f_allowed = false;
+    const char *mnt_pt = FSFAT_FOPEN_TEST_MOUNT_PT_PATH;
+    const char *basename = "goodfile";
+    const char *extname = "txt";
+    const size_t basename_len = strlen(basename);
+    const size_t filename_len = strlen(mnt_pt) + strlen(basename) + strlen(extname) +
+                                2; /* extra 2 chars for '/' and '.' in "/sd/goodfile.txt" */
+    char filename[FSFAT_BUF_MAX_LENGTH];
+    size_t len = 0;
+    uint32_t j = 0;
+    int32_t ret = 0;
+    fsfat_fopen_kv_name_ascii_node *node = NULL;
+    uint32_t pos;
+
+    FSFAT_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+#ifdef FSFAT_DEBUG
+    /* symbol only used why debug is enabled */
+    const char *pos_str = NULL;
+#endif
+
+    /* create bad keyname strings with invalid character code at start of keyname */
+    node = fsfat_fopen_kv_name_ascii_table;
+    memset(filename, 0, FSFAT_BUF_MAX_LENGTH);
+    while (node->code !=  fsfat_fopen_kv_name_ascii_table_code_sentinel_g) {
+        /* loop over range */
+        for (j = node->code; j < (node + 1)->code; j++) {
+            if ((j >= 48 && j <= 57) || (j >= 65 && j <= 90) || (j >= 97 && j <= 122)) {
+                FSFAT_DBGLOG("%s: skipping alpha-numeric ascii character code %d (%c).\n", __func__, (int) j, (char) j);
+                continue;
+            }
+
+            /* set the start, mid, last character of the name to the test char code */
+            for (pos = (uint32_t) fsfat_fopen_kv_name_pos_start; pos < (uint32_t) fsfat_fopen_kv_name_pos_max; pos++) {
+                len = snprintf(filename, filename_len + 1, "%s/%s.%s", mnt_pt, basename, extname);
+                /* overwrite a char at the pos start, mid, end of the filename with an ascii char code (both illegal and legal)*/
+                switch (pos) {
+                    case fsfat_fopen_kv_name_pos_start:
+                        filename[5] = (char) j; /* 5 so at to write the second basename char (bad chars as first char not accepted)*/
+                        break;
+                    case fsfat_fopen_kv_name_pos_mid:
+                        /* create bad keyname strings with invalid character code in the middle of keyname */
+                        filename[5 + basename_len / 2] = (char) j;
+                        break;
+                    case fsfat_fopen_kv_name_pos_end:
+                        /* create bad keyname strings with invalid character code at end of keyname */
+                        filename[5 + basename_len - 1] = (char) j;
+                        break;
+                    default:
+                        FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                                                 "%s:Error: unexpected value of pos (pos=%d).\n", __func__, (int) pos);
+                        TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
+                        break;
+                }
+
+#ifdef FSFAT_DEBUG
+                /* processing only required when debug trace enabled */
+                switch (pos) {
+                    case fsfat_fopen_kv_name_pos_start:
+                        pos_str = "start";
+                        break;
+                    case fsfat_fopen_kv_name_pos_mid:
+                        pos_str = "middle";
+                        break;
+                    case fsfat_fopen_kv_name_pos_end:
+                        pos_str = "end";
+                        break;
+                    default:
+                        break;
+                }
+#endif
+                ret = fsfat_test_create(filename, (const char *) filename, len);
+
+                /* special cases */
+                switch (j) {
+                    //case 0 :
+                    //case 46 :
+                    //    switch(pos)
+                    //    {
+                    //    /* for code = 0 (null terminator). permitted at mid and end of string */
+                    //    /* for code = 46 ('.'). permitted at mid and end of string but not at start */
+                    //    case fsfat_fopen_kv_name_pos_start:
+                    //        f_allowed = false;
+                    //        break;
+                    //    case fsfat_fopen_kv_name_pos_mid:
+                    //    case fsfat_fopen_kv_name_pos_end:
+                    //    default:
+                    //        f_allowed = true;
+                    //        break;
+                    //    }
+                    //    break;
+                    default:
+                        f_allowed = node->f_allowed;
+                        break;
+                }
+                if (f_allowed == true) {
+                    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                                             "%s:Error: failed to create file in store when filename contains valid characters (code=%d, ret=%d).\n", __func__,
+                                             (int) j, (int) ret);
+                    TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
+                    /* revert FSFAT_LOG for more trace */
+                    FSFAT_DBGLOG("Successfully created a file with valid keyname containing ascii character code %d (%c) at the %s of the keyname.\n",
+                                 (int) j, (int) j, pos_str);
+                    FSFAT_LOG("%c", '.');
+
+                    ret = fsfat_test_delete(filename);
+                    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                                             "%s:Error: failed to delete file previously created (code=%d, ret=%d).\n", __func__, (int) j, (int) ret);
+                    TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
+                } else {
+                    /*node->f_allowed == false => not allowed to create kv name with ascii code */
+                    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                                             "%s:Error: created file in store when filename contains an invalid character (code=%d, ret=%d).\n", __func__, (int) j,
+                                             (int) ret);
+                    TEST_ASSERT_MESSAGE(ret < 0, fsfat_fopen_utest_msg_g);
+                    /* revert FSFAT_LOG for more trace */
+                    FSFAT_DBGLOG("Successfully failed to create a file with an invalid keyname containing ascii character code %d at the %s of the keyname.\n",
+                                 (int) j, pos_str);
+                    FSFAT_LOG("%c", '.');
+                }
+            }
+        }
+        node++;
+    }
+
+    FSFAT_LOG("%c", '\n');
+    return CaseNext;
+}
+
+
+static const char fsfat_fopen_ascii_illegal_buf_g[] = "\"�'*+,./:;<=>?[\\]|";
+
+/** @brief  test to call fopen() with filename that in includes
+ *          illegal characters
+ *          - a max-length string of random illegal characters only
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fsfat_fopen_test_06(const size_t call_count)
+{
+    const char *mnt_pt = FSFAT_FOPEN_TEST_MOUNT_PT_PATH;
+    const char *extname = "txt";
+    const size_t filename_len = strlen(mnt_pt) + FSFAT_MAX_FILE_BASENAME + strlen(extname) +
+                                2; /* extra 2 chars for '/' and '.' in "/sd/goodfile.txt" */
+    char filename[FSFAT_BUF_MAX_LENGTH];
+    int32_t i = 0;
+    int32_t j = 0;
+    uint32_t pos = 0;
+    uint32_t len = 0;
+    int32_t ret = -1;
+    size_t buf_data_max = 0;
+
+    FSFAT_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+    memset(filename, 0, FSFAT_BUF_MAX_LENGTH);
+    /* create bad keyname strings with invalid character code at start of keyname */
+    buf_data_max = strlen(fsfat_fopen_ascii_illegal_buf_g);
+
+    /* generate a number of illegal filenames */
+    for (j = 0; i < FSFAT_MAX_FILE_BASENAME; j++) {
+        /* generate a kv name of illegal chars*/
+        len = snprintf(filename, filename_len + 1, "%s/", mnt_pt);
+        for (i = 0; i < FSFAT_MAX_FILE_BASENAME; i++) {
+            pos = rand() % (buf_data_max + 1);
+            len += snprintf(filename + len, filename_len + 1, "%c", fsfat_fopen_ascii_illegal_buf_g[pos]);
+
+        }
+        len += snprintf(filename + len, filename_len + 1, ".%s", extname);
+        ret = fsfat_test_create(filename, filename, len);
+        FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                                 "%s:Error: created file when filename contains invalid characters (filename=%s, ret=%d).\n", __func__, filename,
+                                 (int) ret);
+        TEST_ASSERT_MESSAGE(ret < 0, fsfat_fopen_utest_msg_g);
+    }
+    return CaseNext;
+}
+
+
+/** @brief  test for errno reporting on a failed fopen()call
+ *
+ *  This test does the following:
+ *  - tries to open a file that does not exist for reading, and checks that a NULL pointer is returned.
+ *  - checks that errno is not 0 as there is an error.
+ *  - checks that ferror() returns 1 indicating an error exists.
+ *
+ * Note: see NOTE_1 below.
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fsfat_fopen_test_07(const size_t call_count)
+{
+    FILE *f = NULL;
+    int ret = -1;
+    int errno_val = 0;
+    const char *filename = sd_badfile_path;
+
+    FSFAT_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+    errno = 0;
+    /* this is expect to fail as the file doesnt exist */
+    f = fopen(filename, "r");
+
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: opened non-existent file for reading (filename=%s, f=%p).\n", __func__, filename, f);
+    TEST_ASSERT_MESSAGE(f == NULL, fsfat_fopen_utest_msg_g);
+
+    /* check errno is set correctly */
+#if ! defined(__ARMCC_VERSION) && defined(__GNUC__)
+    /* Store errno so the current value set  is not changed by new function call */
+    errno_val = errno;
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: errno has unexpected value (errno != 0 expected) (filename=%s, errno=%d).\n", __func__, filename, errno);
+    TEST_ASSERT_MESSAGE(errno_val != 0, fsfat_fopen_utest_msg_g);
+#endif  /* ! defined(__ARMCC_VERSION) && defined(__GNUC__) */
+    return CaseNext;
+}
+
+
+/** @brief  test for operation of clearerr() and ferror()
+ *
+ *  The test does the following:
+ *  - opens and then closes a file, but keeps a copy of the FILE pointer fp.
+ *  - set errno to 0.
+ *  - write to the close file with fwrite(fp) which should return 0 (no writes) and set the errno.
+ *  - check the error condition is set with ferror().
+ *  - clear the error with clearerr().
+ *  - check the error condition is reset with ferror().
+ *
+ * NOTE_1: GCC/ARMCC support for setting errno
+ *  - Documentation (e.g. fwrite() man page) does not explicity say fwrite() sets errno
+ *    (e.g. for an fwrite() on a read-only file).
+ *  - GCC libc fwrite() appears to set errno as expected.
+ *  - ARMCC & IAR libc fwrite() appears not to set errno.
+ *
+ * The following ARMCC documents are silent on whether fwrite() sets errno:
+ * - "ARM C and C++ Libraries and Floating-Point Support".
+ * - "RL-ARM User Guide fwrite() section".
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fsfat_fopen_test_08(const size_t call_count)
+{
+    FILE *fp = NULL;
+    int ret = -1;
+    int ret_ferror = -1;
+    const char *filename = sd_testfile_path;
+
+    FSFAT_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+    errno = 0;
+    fp = fopen(filename, "w+");
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to open file (filename=%s, f=%p).\n", __func__, filename, fp);
+    TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g);
+
+    /* close the fp but then try to read or write it */
+    ret = fclose(fp);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to close file (ret=%d, errno=%d)\n", __func__, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+
+    /* open file  */
+    errno = 0;
+    fp = fopen(filename, "r");
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to open file for reading (filename=\"%s\", ret=%d)\n", __func__, filename, (int) ret);
+    TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g);
+
+    /* Perform fwrite() operation that will fail. */
+    errno = 0;
+    ret = fwrite("42!", 4, 1, fp);
+
+    ret_ferror = ferror(fp);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: ferror() failed to report error (filename=%s, ret_ferror=%d).\n", __func__, filename, (int) ret_ferror);
+    TEST_ASSERT_MESSAGE(ret_ferror != 0, fsfat_fopen_utest_msg_g);
+
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: fwrite successfully wrote to read-only file (filename=%s, ret=%d).\n", __func__, filename, (int) ret);
+    /* the fwrite() should fail and return 0. */
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+
+#if ! defined(__ARMCC_VERSION) && defined(__GNUC__)
+    /* check that errno is set. ARMCC appears not to set errno for fwrite() failure. */
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: unexpected zero value for errno (filename=%s, ret=%d, errno=%d).\n", __func__, filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(errno != 0, fsfat_fopen_utest_msg_g);
+
+    /* check that errno is set to the expected value (this may change differ for different libc's) */
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: errno != EBADF (filename=%s, ret=%d, errno=%d).\n", __func__, filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(errno == EBADF, fsfat_fopen_utest_msg_g);
+#endif  /* ! defined(__ARMCC_VERSION) && defined(__GNUC__) */
+
+    /* check clearerr() return clears the error */
+    clearerr(fp);
+    ret = ferror(fp);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: ferror() did not return zero value when error has been cleared (filename=%s, ret=%d).\n", __func__, filename,
+                             (int) ret);
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+
+    fclose(fp);
+    return CaseNext;
+}
+
+
+/** @brief  test for operation of ftell()
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fsfat_fopen_test_09(const size_t call_count)
+{
+    FILE *fp = NULL;
+    int ret = -1;
+    int32_t len = 0;
+
+    FSFAT_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+    /* create a file of a certain length */
+    len = strlen(fsfat_fopen_test_02_data[0].value);
+    ret = fsfat_test_create(fsfat_fopen_test_02_data[0].filename, (char *) fsfat_fopen_test_02_data[0].value, len);
+
+    errno = 0;
+    /* Open the file for reading so the file is not truncated to 0 length. */
+    fp = fopen(fsfat_fopen_test_02_data[0].filename, "r");
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to open file (filename=%s, fp=%p, errno=%d).\n", __func__, fsfat_fopen_test_02_data[0].filename, fp,
+                             errno);
+    TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g);
+
+    errno = 0;
+    ret = fseek(fp, 0, SEEK_END);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: fseek() failed to SEEK_END (filename=%s, ret=%d, errno=%d).\n", __func__,
+                             fsfat_fopen_test_02_data[0].filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+
+    errno = 0;
+    ret = ftell(fp);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: ftell() failed to report correct offset value (filename=%s, ret=%d, errno=%d).\n", __func__,
+                             fsfat_fopen_test_02_data[0].filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == len, fsfat_fopen_utest_msg_g);
+
+    errno = 0;
+    ret = fclose(fp);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to close file (ret=%d, errno=%d)\n", __func__, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+
+    return CaseNext;
+}
+
+
+/* file data for test_10 */
+static fsfat_kv_data_t fsfat_fopen_test_10_kv_data[] = {
+    { "/sd/test_10/testfile.txt", "test_data"},
+    { NULL, NULL},
+};
+
+/** @brief  test for operation of remove()
+ *
+ * Performs the following tests:
+ *  1. test remove() on a file that exists. This should succeed.
+ *  2. test remove() on a dir that exists. This should succeed.
+ *  3. test remove() on a file that doesnt exist. This should fail. check errno set.
+ *  4. test remove() on a dir that doesnt exist. This should fail. check errno set.
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fsfat_fopen_test_10(const size_t call_count)
+{
+    char buf[FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1];
+    char *pos = NULL;
+    int32_t ret = -1;
+    size_t len = 0;
+    fsfat_kv_data_t *node = fsfat_fopen_test_10_kv_data;
+
+    FSFAT_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+    TEST_ASSERT(strlen(node->filename) < FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1);
+
+    /* start from a known state i.e. directory to be created in not present */
+    fsfat_filepath_remove_all((char *) node->filename);
+
+    /* (1) */
+    errno = 0;
+    ret = fsfat_filepath_make_dirs((char *) node->filename, false);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+
+    len = strlen(node->value);
+    ret = fsfat_test_create(node->filename, (char *) node->value, len);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret);
+    TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
+
+    ret = remove(node->filename);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: delete file operation failed (filename=%s, ret=%d) .\n", __func__, node->filename, (int) ret);
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+
+    /* (3) */
+    ret = remove(node->filename);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: deleted a file that doesn't exist (filename=%s, ret=%d, errno=%d) .\n", __func__, node->filename, (int) ret,
+                             errno);
+    TEST_ASSERT_MESSAGE(ret != 0, fsfat_fopen_utest_msg_g);
+
+    /* (2) */
+    memset(buf, 0, FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1);
+    memcpy(buf, node->filename, strlen(node->filename));
+    pos = strrchr(buf, '/');
+    *pos = '\0';
+    ret = remove(buf);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: delete directory operation failed (directory name=%s, ret=%d, errno=%d).\n", __func__, buf, (int) ret,
+                             errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+
+    /* (4) */
+    ret = remove(buf);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: deleted a directory that doesn't exist (directory name=%s, ret=%d, errno=%d).\n", __func__, buf, (int) ret,
+                             errno);
+    TEST_ASSERT_MESSAGE(ret != 0, fsfat_fopen_utest_msg_g);
+
+    return CaseNext;
+}
+
+
+/* file data for test_11 */
+static fsfat_kv_data_t fsfat_fopen_test_11_kv_data[] = {
+    { "/sd/test_11/step0.txt", "test_data"},
+    { "/sd/test_11/step1.txt", "test_data"},
+    { "/sd/test_11/subdir/step3.txt", "test_data"},
+    { NULL, NULL},
+};
+
+/** @brief  test for operation of rename()
+ *
+ * This test does the following:
+ *  1) test rename() on a file that exists to a new filename within the same directory.
+ *  2) test rename() on a file that exists to a new filename within a different directory.
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fsfat_fopen_test_11(const size_t call_count)
+{
+    int32_t ret = -1;
+    size_t len = 0;
+    fsfat_kv_data_t *node = fsfat_fopen_test_11_kv_data;
+
+    FSFAT_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+    TEST_ASSERT(strlen(node->filename) < FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1);
+
+    /* start from a known state i.e. directory to be created in not present, files not present */
+    while (node->filename != NULL) {
+        fsfat_filepath_remove_all((char *) node->filename);
+        node++;
+    }
+
+    /* create file and directories ready for rename() tests */
+    errno = 0;
+    node = fsfat_fopen_test_11_kv_data;
+    ret = fsfat_filepath_make_dirs((char *) node->filename, false);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+
+    len = strlen(node->value);
+    ret = fsfat_test_create(node->filename, (char *) node->value, len);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret);
+    TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
+
+    errno = 0;
+    node = &fsfat_fopen_test_11_kv_data[2];
+    ret = fsfat_filepath_make_dirs((char *) node->filename, false);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+
+    /* (1) */
+    ret = rename(fsfat_fopen_test_11_kv_data[0].filename, fsfat_fopen_test_11_kv_data[1].filename);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: unable to rename file from (%s) to (%s) (ret=%d, errno=%d).\n", __func__,
+                             fsfat_fopen_test_11_kv_data[0].filename, fsfat_fopen_test_11_kv_data[1].filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+
+    /* (2) */
+    ret = rename(fsfat_fopen_test_11_kv_data[1].filename, fsfat_fopen_test_11_kv_data[2].filename);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: unable to rename file from (%s) to (%s) (ret=%d, errno=%d).\n", __func__,
+                             fsfat_fopen_test_11_kv_data[1].filename, fsfat_fopen_test_11_kv_data[2].filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+
+    return CaseNext;
+}
+
+
+/* file data for test_12 */
+static fsfat_kv_data_t fsfat_fopen_test_12_kv_data[] = {
+    { "/sd/test_12/subdir/testfil1.txt", "testfil1.txt"},
+    { "/sd/test_12/testfil2.txt", "testfil2.txt"},
+    { "/sd/test_12/testfil3.txt", "testfil3.txt"},
+    { "/sd/test_12/testfil4.txt", "testfil4.txt"},
+    { "/sd/test_12/testfil5.txt", "testfil5.txt"},
+    { NULL, NULL},
+};
+
+/** @brief  test for operation of readdir().
+ *
+ * Note, rewinddir(), telldir() and seekdir() dont appear to work reliably.
+ * opendir() not available on ARM/IAR toolchains.
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fsfat_fopen_test_12(const size_t call_count)
+{
+    char buf[FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1];
+    char *pos = NULL;
+    int32_t count = 0;
+    int32_t ret = -1;
+    size_t len = 0;
+    DIR *dir;
+    struct dirent *dp;
+    fsfat_kv_data_t *node = fsfat_fopen_test_12_kv_data;
+
+    FSFAT_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+#if ! defined(__ARMCC_VERSION) && defined(__GNUC__)
+
+    /* start from a known state i.e. directory to be created in not present */
+    while (node->filename != NULL) {
+        fsfat_filepath_remove_all((char *) node->filename);
+        node++;
+    }
+
+    /* create a file */
+    node = fsfat_fopen_test_12_kv_data;
+    errno = 0;
+    ret = fsfat_filepath_make_dirs((char *) node->filename, false);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+
+    node = fsfat_fopen_test_12_kv_data;
+    while (node->filename != NULL) {
+        len = strlen(node->value);
+        ret = fsfat_test_create(node->filename, (char *) node->value, len);
+        FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                                 "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret);
+        TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
+        node++;
+    }
+
+    node = fsfat_fopen_test_12_kv_data;
+    memset(buf, 0, FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1);
+    memcpy(buf, node->filename, strlen(node->filename));
+    pos = strrchr(buf, '/');
+    *pos = '\0';
+    dir = opendir(buf);
+
+    while ((dp = readdir(dir)) != NULL) {
+        FSFAT_DBGLOG("%s: filename: \"%s\"\n", __func__, dp->d_name);
+        TEST_ASSERT_MESSAGE(dp != 0, "Error: readdir() failed\n");
+        FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                                 "%s:Error: unexpected object name (name=%s, expected=%s).\n", __func__, dp->d_name,
+                                 fsfat_fopen_test_12_kv_data[count].value);
+        TEST_ASSERT_MESSAGE(strncmp(dp->d_name, fsfat_fopen_test_12_kv_data[count].value,
+                                    strlen(fsfat_fopen_test_12_kv_data[count].value)) == 0, fsfat_fopen_utest_msg_g);
+        count++;
+    }
+    closedir(dir);
+
+    /* cleanup */
+    node = fsfat_fopen_test_12_kv_data;
+    while (node->filename != NULL) {
+        fsfat_filepath_remove_all((char *) node->filename);
+        node++;
+    }
+#endif  /* ! defined(__ARMCC_VERSION) && defined(__GNUC__) */
+    return CaseNext;
+}
+
+
+/* file data for test_13 */
+static fsfat_kv_data_t fsfat_fopen_test_13_kv_data[] = {
+    /* a file is included in the filepath even though its not created by the test,
+     * as the fsfat_filepath_make_dirs() works with it present. */
+    { "/sd/test_13/dummy.txt", "testdir"},
+    { NULL, NULL},
+};
+/** @brief  test for operation of mkdir()/remove()
+ *
+ * This test checks that:
+ * - The mkdir() function successfully creates a directory that is not already present.
+ * - The mkdir() function returns EEXIST when trying to create a directory thats already present.
+ * - The remove() function successfully removes a directory that is present.
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fsfat_fopen_test_13(const size_t call_count)
+{
+    int32_t ret = 0;
+
+    FSFAT_DBGLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+    /* start from a known state i.e. directory to be created in not present */
+    fsfat_filepath_remove_all((char *) fsfat_fopen_test_13_kv_data[0].filename);
+
+    errno = 0;
+    ret = fsfat_filepath_make_dirs((char *) fsfat_fopen_test_13_kv_data[0].filename, false);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, fsfat_fopen_test_13_kv_data[0].filename,
+                             (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+
+    /* check that get a suitable error when try to create it again.*/
+    errno = 0;
+    ret = fsfat_filepath_make_dirs((char *) fsfat_fopen_test_13_kv_data[0].filename, false);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: permitted to create directory when already exists (dirname=%s, ret=%d, errno=%d)\n", __func__,
+                             fsfat_fopen_test_13_kv_data[0].filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret != 0, fsfat_fopen_utest_msg_g);
+
+    /* check errno is as expected */
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: errno != EEXIST (dirname=%s, ret=%d, errno=%d)\n", __func__, fsfat_fopen_test_13_kv_data[0].filename,
+                             (int) ret, errno);
+    TEST_ASSERT_MESSAGE(errno == EEXIST, fsfat_fopen_utest_msg_g);
+
+    ret = fsfat_filepath_remove_all((char *) fsfat_fopen_test_13_kv_data[0].filename);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to remove directory (dirname=%s, ret=%d, errno=%d)\n", __func__,
+                             fsfat_fopen_test_13_kv_data[0].filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+
+    return CaseNext;
+}
+
+/* file data for test_14 */
+static fsfat_kv_data_t fsfat_fopen_test_14_kv_data[] = {
+    /* a file is included in the filepath even though its not created by the test,
+     * as the fsfat_filepath_make_dirs() works with it present. */
+    { "/sd/test_14/testfile.txt", "testdata"},
+    { NULL, NULL},
+};
+
+/** @brief  test for operation of stat()
+ *
+ * stat() is currently no supported by ARMCC and IAR toolchains libc.
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fsfat_fopen_test_14(const size_t call_count)
+{
+#if ! defined(__ARMCC_VERSION) && defined(__GNUC__)
+
+    char buf[FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1];
+    char *pos = NULL;
+    int32_t ret = -1;
+    size_t len = 0;
+    struct stat file_stat;
+    fsfat_kv_data_t *node = fsfat_fopen_test_14_kv_data;
+
+    FSFAT_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+    TEST_ASSERT(strlen(node->filename) < FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1);
+
+    /* start from a known state i.e. directory to be created in not present */
+    fsfat_filepath_remove_all((char *) node->filename);
+
+    /* Create file in a directory. */
+    errno = 0;
+    ret = fsfat_filepath_make_dirs((char *) node->filename, false);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+
+    len = strlen(node->value);
+    ret = fsfat_test_create(node->filename, (char *) node->value, len);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret);
+    TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
+
+    /* Test stat() on the file returns the correct attribute set */
+    memset(&file_stat, 0, sizeof(file_stat));
+    ret = stat(node->filename, &file_stat);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: stat() operation on file failed (filename=%s, ret=%d, errno=%d).\n", __func__, node->filename, (int) ret,
+                             errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: expected st_mode S_IFREG flag not set (filename=%s).\n", __func__, node->filename);
+    TEST_ASSERT_MESSAGE((file_stat.st_mode & S_IFREG) == S_IFREG, fsfat_fopen_utest_msg_g);
+
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: unexpected st_mode S_IFDIR flag set (filename=%s).\n", __func__, node->filename);
+    TEST_ASSERT_MESSAGE((file_stat.st_mode & S_IFDIR) != S_IFDIR, fsfat_fopen_utest_msg_g);
+
+    /* Test stat() on the directory returns the correct attribute set */
+    memset(&file_stat, 0, sizeof(file_stat));
+    memset(buf, 0, FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1);
+    memcpy(buf, node->filename, strlen(node->filename));
+    pos = strrchr(buf, '/');
+    *pos = '\0';
+    ret = stat(buf, &file_stat);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: stat() operation on directory failed (directory name=%s, ret=%d, errno=%d).\n", __func__, buf, (int) ret,
+                             errno);
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: unexpected st_mode S_IFREG flag set (directory name=%s).\n", __func__, buf);
+    TEST_ASSERT_MESSAGE((file_stat.st_mode & S_IFREG) != S_IFREG, fsfat_fopen_utest_msg_g);
+
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: expected st_mode S_IFDIR flag not set (directory name=%s).\n", __func__, buf);
+    TEST_ASSERT_MESSAGE((file_stat.st_mode & S_IFDIR) == S_IFDIR, fsfat_fopen_utest_msg_g);
+
+    /* clean up after successful test */
+    fsfat_filepath_remove_all((char *) node->filename);
+
+#endif /* ! defined(__ARMCC_VERSION) && defined(__GNUC__) */
+    return CaseNext;
+}
+
+/** @brief  test for operation of SDFileSystem::format()
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fsfat_fopen_test_15(const size_t call_count)
+{
+
+    FSFAT_FENTRYLOG("%s:entered\n", __func__);
+    (void) call_count;
+    int32_t ret = -1;
+
+    /* the allocation_unit of 0 means chanFS will use the default for the card (varies according to capacity). */
+    fs.unmount();
+    ret = fs.format(&sd);
+    FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                             "%s:Error: failed to format sdcard (ret=%d)\n", __func__, (int) ret);
+    TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+    fs.mount(&sd);
+    return CaseNext;
+}
+
+
+/* @brief   test utility function to create a file of a given size.
+ *
+ * A reference data table is used of so that the data file can be later be
+ * checked with fsfat_test_check_data_file().
+ *
+ * @param   filename    name of the file including path
+ * @param   data        data to store in file
+ * @param   len         number of bytes of data present in the data buffer.
+ */
+int32_t fsfat_test_create_data_file(const char *filename, size_t len)
+{
+    int32_t ret = -1;
+    FILE *fp = NULL;
+    size_t write_len = 0;
+    size_t written_len = 0;
+    int32_t exp = 0;
+    const int32_t exp_max = 8;      /* so as not to exceed FSFAT_TEST_BYTE_DATA_TABLE_SIZE/2 */
+
+    FSFAT_FENTRYLOG("%s:entered (filename=%s, len=%d).\n", __func__, filename, (int) len);
+    TEST_ASSERT(len % FSFAT_TEST_BYTE_DATA_TABLE_SIZE == 0);
+    fp = fopen(filename, "a");
+    if (fp == NULL) {
+        return ret;
+    }
+
+    while (written_len < len) {
+        /* write fsfat_test_byte_data_table or part thereof, in 9 writes of sizes
+         * 1, 2, 4, 8, 16, 32, 64, 128, 1, totalling 256 bytes len permitting. */
+        for (exp = 0; (exp <= exp_max) && (written_len < len); exp++) {
+            write_len = 0x1 << (exp % exp_max);
+            write_len = len - written_len  > write_len ? write_len : len - written_len;
+            ret = fwrite((const void *) &fsfat_test_byte_data_table[written_len % FSFAT_TEST_BYTE_DATA_TABLE_SIZE], write_len, 1,
+                         fp);
+            written_len += write_len;
+            if (ret != 1) {
+                FSFAT_DBGLOG("%s:Error: fwrite() failed (ret=%d)\n", __func__, (int) ret);
+                ret = -1;
+                goto out0;
+            }
+        }
+    }
+    if (written_len == len) {
+        ret = 0;
+    } else {
+        ret = -1;
+    }
+out0:
+    fclose(fp);
+    return ret;
+}
+
+
+/* @brief   test utility function to check the data in the specified file is correct.
+ *
+ * The data read from the file is check that it agrees with the data written by
+ * fsfat_test_create_data_file().
+ *
+ * @param   filename    name of the file including path
+ * @param   data        data to store in file
+ * @param   len         number of bytes of data present in the data buffer.
+ */
+int32_t fsfat_test_check_data_file(const char *filename, size_t len)
+{
+    int32_t ret = -1;
+    FILE *fp = NULL;
+    size_t read_len = 0;
+    uint8_t buf[FSFAT_TEST_BYTE_DATA_TABLE_SIZE];
+
+    FSFAT_FENTRYLOG("%s:entered (filename=%s, len=%d).\n", __func__, filename, (int) len);
+    TEST_ASSERT(len % FSFAT_TEST_BYTE_DATA_TABLE_SIZE == 0);
+    fp = fopen(filename, "r");
+    if (fp == NULL) {
+        return ret;
+    }
+
+    while (read_len < len) {
+        ret = fread((void *) buf, FSFAT_TEST_BYTE_DATA_TABLE_SIZE, 1, fp);
+        read_len += FSFAT_TEST_BYTE_DATA_TABLE_SIZE;
+        if (ret == 0) {
+            /* end of read*/
+            FSFAT_DBGLOG("%s:unable to read data\n", __func__);
+            break;
+        }
+        if (memcmp(buf, fsfat_test_byte_data_table, FSFAT_TEST_BYTE_DATA_TABLE_SIZE) != 0) {
+            FSFAT_DBGLOG("%s:Error: read data not as expected (0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x\n",
+                         __func__,
+                         buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13],
+                         buf[14], buf[15]);
+            ret = -1;
+            goto out0;
+        }
+    }
+    if (read_len == len) {
+        ret = 0;
+    }
+out0:
+    fclose(fp);
+    return ret;
+}
+
+/* file data for test_16 */
+static fsfat_kv_data_t fsfat_fopen_test_16_kv_data[] = {
+    { "/sd/tst16_0/testfil0.txt", "dummy_data"},
+    { "/sd/tst16_1/subdir0/testfil0.txt", "dummy_data"},
+    { "/sd/tst16_2/subdir0/subdir1/testfil0.txt", "dummy_data"},
+    { "/sd/tst16_3/subdir0/subdir1/subdir2/subdir3/testfil0.txt", "dummy_data"},
+    { "/sd/tst16_4/subdir0/subdir1/subdir2/subdir3/subdir4/testfil0.txt", "dummy_data"},
+    { "/sd/tst16_5/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/testfil0.txt", "dummy_data"},
+    { "/sd/tst16_6/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/subdir6/testfil0.txt", "dummy_data"},
+    { "/sd/tst16_7/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/subdir6/subdir7/testfil0.txt", "dummy_data"},
+    { "/sd/tst16_8/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/subdir6/subdir7/subdir8/testfil0.txt", "dummy_data"},
+    { "/sd/tst16_9/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/subdir6/subdir7/subdir8/subdir9/testfil0.txt", "dummy_data"},
+    { NULL, NULL},
+};
+
+
+/** @brief  stress test to write data to fs
+ *
+ * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
+ */
+control_t fsfat_fopen_test_16(const size_t call_count)
+{
+    int32_t ret = 0;
+    fsfat_kv_data_t *node = fsfat_fopen_test_16_kv_data;
+    const int32_t num_blocks = 100; /* each file ~25kB */
+
+    FSFAT_DBGLOG("%s:entered\n", __func__);
+    (void) call_count;
+
+    /* remove file and directory from a previous failed test run, if present */
+    while (node->filename != NULL) {
+        fsfat_filepath_remove_all((char *) node->filename);
+        node++;
+    }
+
+    /* create dirs */
+    node = fsfat_fopen_test_16_kv_data;
+    while (node->filename != NULL) {
+        ret = fsfat_filepath_make_dirs((char *) node->filename, true);
+        FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                                 "%s:Error: failed to create dirs for filename (filename=\"%s\")(ret=%d)\n", __func__, node->filename, (int) ret);
+        TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+        node++;
+    }
+
+    /* create the data files */
+    node = fsfat_fopen_test_16_kv_data;
+    while (node->filename != NULL) {
+        ret = fsfat_test_create_data_file(node->filename, num_blocks * FSFAT_TEST_BYTE_DATA_TABLE_SIZE);
+        FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                                 "%s:Error: failed to create data file (filename=\"%s\")(ret=%d)\n", __func__, node->filename, (int) ret);
+        TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+        node++;
+    }
+
+    /* read the data back and check its as expected */
+    node = fsfat_fopen_test_16_kv_data;
+    while (node->filename != NULL) {
+        ret = fsfat_test_check_data_file(node->filename, num_blocks * FSFAT_TEST_BYTE_DATA_TABLE_SIZE);
+        FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
+                                 "%s:Error: failed to check data file (filename=\"%s\")(ret=%d)\n", __func__, node->filename, (int) ret);
+        TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
+        node++;
+    }
+
+    /* clean up */
+    node = fsfat_fopen_test_16_kv_data;
+    while (node->filename != NULL) {
+        fsfat_filepath_remove_all((char *) node->filename);
+        node++;
+    }
+    return CaseNext;
+}
+
+
+#else
+
+
+#define FSFAT_FOPEN_TEST_01      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_02      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_03      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_04      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_05      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_06      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_07      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_08      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_09      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_10      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_11      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_12      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_13      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_14      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_15      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_16      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_17      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_18      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_19      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_20      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_21      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_22      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_23      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_24      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_25      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_26      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_27      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_28      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_29      fsfat_fopen_test_dummy
+#define FSFAT_FOPEN_TEST_30      fsfat_fopen_test_dummy
+
+/** @brief  fsfat_fopen_test_dummy    Dummy test case for testing when platform doesnt have an SDCard installed.
+ *
+ * @return success always
+ */
+static control_t fsfat_fopen_test_dummy()
+{
+    printf("Null test\n");
+    return CaseNext;
+}
+
+#endif
+
+
+/// @cond FSFAT_DOXYGEN_DISABLE
+utest::v1::status_t greentea_setup(const size_t number_of_cases)
+{
+    GREENTEA_SETUP(FSFAT_FOPEN_GREENTEA_TIMEOUT_S, "default_auto");
+    return greentea_test_setup_handler(number_of_cases);
+}
+
+Case cases[] = {
+    /*          1         2         3         4         5         6        7  */
+    /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
+    Case("FSFAT_FOPEN_TEST_01: fopen()/fwrite()/fclose() directories/file in multi-dir filepath.", FSFAT_FOPEN_TEST_01),
+    Case("FSFAT_FOPEN_TEST_02: fopen(r) pre-existing file try to write it.", FSFAT_FOPEN_TEST_02),
+    Case("FSFAT_FOPEN_TEST_03: fopen(w+) pre-existing file try to write it.", FSFAT_FOPEN_TEST_03),
+    Case("FSFAT_FOPEN_TEST_04: fopen() with a filename exceeding the maximum length.", FSFAT_FOPEN_TEST_04),
+#ifdef FOPEN_EXTENDED_TESTING
+    Case("FSFAT_FOPEN_TEST_05: fopen() with bad filenames (extended).", FSFAT_FOPEN_TEST_05),
+#endif
+    Case("FSFAT_FOPEN_TEST_06: fopen() with bad filenames (minimal).", FSFAT_FOPEN_TEST_06),
+    Case("FSFAT_FOPEN_TEST_07: fopen()/errno handling.", FSFAT_FOPEN_TEST_07),
+    Case("FSFAT_FOPEN_TEST_08: ferror()/clearerr()/errno handling.", FSFAT_FOPEN_TEST_08),
+    Case("FSFAT_FOPEN_TEST_09: ftell() handling.", FSFAT_FOPEN_TEST_09),
+    Case("FSFAT_FOPEN_TEST_10: remove() test.", FSFAT_FOPEN_TEST_10),
+    Case("FSFAT_FOPEN_TEST_11: rename().", FSFAT_FOPEN_TEST_11),
+    Case("FSFAT_FOPEN_TEST_12: opendir(), readdir(), closedir() test.", FSFAT_FOPEN_TEST_12),
+    Case("FSFAT_FOPEN_TEST_13: mkdir() test.", FSFAT_FOPEN_TEST_13),
+    Case("FSFAT_FOPEN_TEST_14: stat() test.", FSFAT_FOPEN_TEST_14),
+    Case("FSFAT_FOPEN_TEST_15: format() test.", FSFAT_FOPEN_TEST_15),
+    Case("FSFAT_FOPEN_TEST_16: write/check n x 25kB data files.", FSFAT_FOPEN_TEST_16),
+};
+
+
+/* Declare your test specification with a custom setup handler */
+Specification specification(greentea_setup, cases);
+
+int main()
+{
+    return !Harness::run(specification);
+}
+/// @endcond
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_SD/TESTS/filesystem/parallel/main.cpp	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,209 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2016 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 "mbed.h"
+#include "greentea-client/test_env.h"
+#include "unity.h"
+#include "utest.h"
+#include <stdlib.h>
+#include <errno.h>
+
+using namespace utest::v1;
+
+// test configuration
+#ifndef MBED_TEST_FILESYSTEM
+#define MBED_TEST_FILESYSTEM FATFileSystem
+#endif
+
+#ifndef MBED_TEST_FILESYSTEM_DECL
+#define MBED_TEST_FILESYSTEM_DECL MBED_TEST_FILESYSTEM fs("fs")
+#endif
+
+#ifndef MBED_TEST_BLOCKDEVICE
+#define MBED_TEST_BLOCKDEVICE SDBlockDevice
+#define MBED_TEST_BLOCKDEVICE_DECL SDBlockDevice bd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS);
+#endif
+
+#ifndef MBED_TEST_BLOCKDEVICE_DECL
+#define MBED_TEST_BLOCKDEVICE_DECL MBED_TEST_BLOCKDEVICE bd
+#endif
+
+#ifndef MBED_TEST_FILES
+#define MBED_TEST_FILES 4
+#endif
+
+#ifndef MBED_TEST_DIRS
+#define MBED_TEST_DIRS 4
+#endif
+
+#ifndef MBED_TEST_BUFFER
+#define MBED_TEST_BUFFER 512
+#endif
+
+#ifndef MBED_TEST_TIMEOUT
+#define MBED_TEST_TIMEOUT 120
+#endif
+
+#ifndef MBED_THREAD_COUNT
+#define MBED_THREAD_COUNT    MBED_TEST_FILES
+#endif
+
+// declarations
+#define STRINGIZE(x) STRINGIZE2(x)
+#define STRINGIZE2(x) #x
+#define INCLUDE(x) STRINGIZE(x.h)
+
+#include INCLUDE(MBED_TEST_FILESYSTEM)
+#include INCLUDE(MBED_TEST_BLOCKDEVICE)
+
+MBED_TEST_FILESYSTEM_DECL;
+MBED_TEST_BLOCKDEVICE_DECL;
+
+Dir dir[MBED_TEST_DIRS];
+File file[MBED_TEST_FILES];
+DIR *dd[MBED_TEST_DIRS];
+FILE *fd[MBED_TEST_FILES];
+struct dirent ent;
+struct dirent *ed;
+
+volatile bool count_done = 0;
+
+// tests
+
+void test_file_tests()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = MBED_TEST_FILESYSTEM::format(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void write_file_data(char count)
+{
+
+    char filename[10];
+    uint8_t wbuffer[MBED_TEST_BUFFER];
+    int res;
+
+    sprintf(filename, "%s%d", "data", count);
+    res = file[count].open(&fs, filename, O_WRONLY | O_CREAT);
+    TEST_ASSERT_EQUAL(0, res);
+
+    char letter = 'A' + count;
+    for (uint32_t i = 0; i < MBED_TEST_BUFFER; i++) {
+        wbuffer[i] = letter++;
+        if ('z' == letter) {
+            letter = 'A' + count;
+        }
+    }
+
+    for (uint32_t i = 0; i < 5; i++) {
+        res = file[count].write(wbuffer, MBED_TEST_BUFFER);
+        TEST_ASSERT_EQUAL(MBED_TEST_BUFFER, res);
+    }
+
+    res = file[count].close();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void read_file_data(char count)
+{
+    char filename[10];
+    uint8_t rbuffer[MBED_TEST_BUFFER];
+    int res;
+
+    sprintf(filename, "%s%d", "data", count);
+    res = file[count].open(&fs, filename, O_RDONLY);
+    TEST_ASSERT_EQUAL(0, res);
+
+    for (uint32_t i = 0; i < 5; i++) {
+        res = file[count].read(rbuffer, MBED_TEST_BUFFER);
+        TEST_ASSERT_EQUAL(MBED_TEST_BUFFER, res);
+        char letter = 'A' + count;
+        for (uint32_t i = 0; i < MBED_TEST_BUFFER; i++) {
+            res = rbuffer[i];
+            TEST_ASSERT_EQUAL(letter++, res);
+            if ('z' == letter) {
+                letter = 'A' + count;
+            }
+        }
+    }
+
+    res = file[count].close();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void test_thread_access_test()
+{
+    char *dummy = new (std::nothrow) char[OS_STACK_SIZE * MBED_THREAD_COUNT];
+    delete[] dummy;
+    TEST_SKIP_UNLESS_MESSAGE(dummy, "Not enough memory to run test");
+
+    Thread *data[MBED_THREAD_COUNT];
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+    res = fs.mount(&bd);
+    TEST_ASSERT_EQUAL(0, res);
+
+    // Write threads in parallel
+    for (char thread_count = 0; thread_count < MBED_THREAD_COUNT; thread_count++) {
+        data[thread_count] = new Thread(osPriorityNormal);
+        data[thread_count]->start(callback((void(*)(void *))write_file_data, (void *)thread_count));
+    }
+
+    // Wait for write thread to join before creating read thread
+    for (char thread_count = 0; thread_count < MBED_THREAD_COUNT; thread_count++) {
+        data[thread_count]->join();
+        delete data[thread_count];
+        data[thread_count] = new Thread(osPriorityNormal);
+        data[thread_count]->start(callback((void(*)(void *))read_file_data, (void *)thread_count));
+    }
+
+    // Wait for read threads to join
+    for (char thread_count = 0; thread_count < MBED_THREAD_COUNT; thread_count++) {
+        data[thread_count]->join();
+        delete data[thread_count];
+    }
+    res = fs.unmount();
+    TEST_ASSERT_EQUAL(0, res);
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+// test setup
+utest::v1::status_t test_setup(const size_t number_of_cases)
+{
+    GREENTEA_SETUP(MBED_TEST_TIMEOUT, "default_auto");
+    return verbose_test_setup_handler(number_of_cases);
+}
+
+Case cases[] = {
+    Case("File tests", test_file_tests),
+    Case("Filesystem access from multiple threads", test_thread_access_test),
+};
+
+Specification specification(test_setup, cases);
+
+int main()
+{
+    return !Harness::run(specification);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_SD/TESTS/filesystem/seek/main.cpp	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,656 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2016 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 "mbed.h"
+#include "greentea-client/test_env.h"
+#include "unity.h"
+#include "utest.h"
+#include <stdlib.h>
+#include <errno.h>
+
+using namespace utest::v1;
+
+// test configuration
+#ifndef MBED_TEST_FILESYSTEM
+#define MBED_TEST_FILESYSTEM FATFileSystem
+#endif
+
+#ifndef MBED_TEST_FILESYSTEM_DECL
+#define MBED_TEST_FILESYSTEM_DECL MBED_TEST_FILESYSTEM fs("fs")
+#endif
+
+#ifndef MBED_TEST_BLOCKDEVICE
+#define MBED_TEST_BLOCKDEVICE SDBlockDevice
+#define MBED_TEST_BLOCKDEVICE_DECL SDBlockDevice bd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS);
+#endif
+
+#ifndef MBED_TEST_BLOCKDEVICE_DECL
+#define MBED_TEST_BLOCKDEVICE_DECL MBED_TEST_BLOCKDEVICE bd
+#endif
+
+#ifndef MBED_TEST_FILES
+#define MBED_TEST_FILES 4
+#endif
+
+#ifndef MBED_TEST_DIRS
+#define MBED_TEST_DIRS 4
+#endif
+
+#ifndef MBED_TEST_BUFFER
+#define MBED_TEST_BUFFER 8192
+#endif
+
+#ifndef MBED_TEST_TIMEOUT
+#define MBED_TEST_TIMEOUT 120
+#endif
+
+
+// declarations
+#define STRINGIZE(x) STRINGIZE2(x)
+#define STRINGIZE2(x) #x
+#define INCLUDE(x) STRINGIZE(x.h)
+
+#include INCLUDE(MBED_TEST_FILESYSTEM)
+#include INCLUDE(MBED_TEST_BLOCKDEVICE)
+
+MBED_TEST_FILESYSTEM_DECL;
+MBED_TEST_BLOCKDEVICE_DECL;
+
+Dir dir[MBED_TEST_DIRS];
+File file[MBED_TEST_FILES];
+DIR *dd[MBED_TEST_DIRS];
+FILE *fd[MBED_TEST_FILES];
+struct dirent ent;
+struct dirent *ed;
+size_t size;
+uint8_t buffer[MBED_TEST_BUFFER];
+uint8_t rbuffer[MBED_TEST_BUFFER];
+uint8_t wbuffer[MBED_TEST_BUFFER];
+
+
+// tests
+
+void test_seek_tests()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = MBED_TEST_FILESYSTEM::format(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.mkdir("hello", 0777);
+        TEST_ASSERT_EQUAL(0, res);
+        for (int i = 0; i < 132; i++) {
+            sprintf((char *)buffer, "hello/kitty%d", i);
+            res = file[0].open(&fs, (char *)buffer,
+                               O_WRONLY | O_CREAT | O_APPEND);
+            TEST_ASSERT_EQUAL(0, res);
+
+            size = strlen("kittycatcat");
+            memcpy(buffer, "kittycatcat", size);
+            for (int j = 0; j < 132; j++) {
+                file[0].write(buffer, size);
+            }
+            res = file[0].close();
+            TEST_ASSERT_EQUAL(0, res);
+        }
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void test_simple_dir_seek()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = dir[0].open(&fs, "hello");
+        TEST_ASSERT_EQUAL(0, res);
+#if (MBED_TEST_FILESYSTEM != FATFileSystem)
+        res = dir[0].read(&ent);
+        TEST_ASSERT_EQUAL(1, res);
+        res = strcmp(ent.d_name, ".");
+        TEST_ASSERT_EQUAL(0, res);
+        res = dir[0].read(&ent);
+        TEST_ASSERT_EQUAL(1, res);
+        res = strcmp(ent.d_name, "..");
+        TEST_ASSERT_EQUAL(0, res);
+#endif
+
+        off_t pos;
+        int i;
+        for (i = 0; i < 4; i++) {
+            sprintf((char *)buffer, "kitty%d", i);
+            res = dir[0].read(&ent);
+            TEST_ASSERT_EQUAL(1, res);
+            res = strcmp(ent.d_name, (char *)buffer);
+            TEST_ASSERT_EQUAL(0, res);
+            pos = dir[0].tell();
+        }
+        res = pos >= 0;
+        TEST_ASSERT_EQUAL(1, res);
+
+        dir[0].seek(pos);
+        sprintf((char *)buffer, "kitty%d", i);
+        res = dir[0].read(&ent);
+        TEST_ASSERT_EQUAL(1, res);
+        res = strcmp(ent.d_name, (char *)buffer);
+        TEST_ASSERT_EQUAL(0, res);
+
+        dir[0].rewind();
+        sprintf((char *)buffer, "kitty%d", 0);
+#if (MBED_TEST_FILESYSTEM != FATFileSystem)
+        res = dir[0].read(&ent);
+        TEST_ASSERT_EQUAL(1, res);
+        res = strcmp(ent.d_name, ".");
+        TEST_ASSERT_EQUAL(0, res);
+        res = dir[0].read(&ent);
+        TEST_ASSERT_EQUAL(1, res);
+        res = strcmp(ent.d_name, "..");
+        TEST_ASSERT_EQUAL(0, res);
+#endif
+        res = dir[0].read(&ent);
+        TEST_ASSERT_EQUAL(1, res);
+        res = strcmp(ent.d_name, (char *)buffer);
+        TEST_ASSERT_EQUAL(0, res);
+
+        dir[0].seek(pos);
+        sprintf((char *)buffer, "kitty%d", i);
+        res = dir[0].read(&ent);
+        TEST_ASSERT_EQUAL(1, res);
+        res = strcmp(ent.d_name, (char *)buffer);
+        TEST_ASSERT_EQUAL(0, res);
+        res = dir[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void test_large_dir_seek()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = dir[0].open(&fs, "hello");
+        TEST_ASSERT_EQUAL(0, res);
+#if (MBED_TEST_FILESYSTEM != FATFileSystem)
+        res = dir[0].read(&ent);
+        TEST_ASSERT_EQUAL(1, res);
+        res = strcmp(ent.d_name, ".");
+        TEST_ASSERT_EQUAL(0, res);
+        res = dir[0].read(&ent);
+        TEST_ASSERT_EQUAL(1, res);
+        res = strcmp(ent.d_name, "..");
+        TEST_ASSERT_EQUAL(0, res);
+#endif
+
+        off_t pos;
+        int i;
+        for (i = 0; i < 128; i++) {
+            sprintf((char *)buffer, "kitty%d", i);
+            res = dir[0].read(&ent);
+            TEST_ASSERT_EQUAL(1, res);
+            res = strcmp(ent.d_name, (char *)buffer);
+            TEST_ASSERT_EQUAL(0, res);
+            pos = dir[0].tell();
+        }
+        res = pos >= 0;
+        TEST_ASSERT_EQUAL(1, res);
+
+        dir[0].seek(pos);
+        sprintf((char *)buffer, "kitty%d", i);
+        res = dir[0].read(&ent);
+        TEST_ASSERT_EQUAL(1, res);
+        res = strcmp(ent.d_name, (char *)buffer);
+        TEST_ASSERT_EQUAL(0, res);
+
+        dir[0].rewind();
+        sprintf((char *)buffer, "kitty%d", 0);
+#if (MBED_TEST_FILESYSTEM != FATFileSystem)
+        res = dir[0].read(&ent);
+        TEST_ASSERT_EQUAL(1, res);
+        res = strcmp(ent.d_name, ".");
+        TEST_ASSERT_EQUAL(0, res);
+        res = dir[0].read(&ent);
+        TEST_ASSERT_EQUAL(1, res);
+        res = strcmp(ent.d_name, "..");
+        TEST_ASSERT_EQUAL(0, res);
+#endif
+        res = dir[0].read(&ent);
+        TEST_ASSERT_EQUAL(1, res);
+        res = strcmp(ent.d_name, (char *)buffer);
+        TEST_ASSERT_EQUAL(0, res);
+
+        dir[0].seek(pos);
+        sprintf((char *)buffer, "kitty%d", i);
+        res = dir[0].read(&ent);
+        TEST_ASSERT_EQUAL(1, res);
+        res = strcmp(ent.d_name, (char *)buffer);
+        TEST_ASSERT_EQUAL(0, res);
+        res = dir[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void test_simple_file_seek()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].open(&fs, "hello/kitty42", O_RDONLY);
+        TEST_ASSERT_EQUAL(0, res);
+
+        off_t pos;
+        size = strlen("kittycatcat");
+        for (int i = 0; i < 4; i++) {
+            res = file[0].read(buffer, size);
+            TEST_ASSERT_EQUAL(size, res);
+            res = memcmp(buffer, "kittycatcat", size);
+            TEST_ASSERT_EQUAL(0, res);
+            pos = file[0].tell();
+        }
+        res = pos >= 0;
+        TEST_ASSERT_EQUAL(1, res);
+        res = file[0].seek(pos, SEEK_SET);
+        TEST_ASSERT_EQUAL(pos, res);
+        res = file[0].read(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = memcmp(buffer, "kittycatcat", size);
+        TEST_ASSERT_EQUAL(0, res);
+
+        file[0].rewind();
+        res = file[0].read(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = memcmp(buffer, "kittycatcat", size);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].seek(pos, SEEK_SET);
+        TEST_ASSERT_EQUAL(pos, res);
+        res = file[0].read(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = memcmp(buffer, "kittycatcat", size);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].seek(-size, SEEK_CUR);
+        TEST_ASSERT_EQUAL(pos, res);
+        res = file[0].read(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = memcmp(buffer, "kittycatcat", size);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].seek(-size, SEEK_END) >= 0;
+        TEST_ASSERT_EQUAL(1, res);
+        res = file[0].read(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = memcmp(buffer, "kittycatcat", size);
+        TEST_ASSERT_EQUAL(0, res);
+
+        size_t size = file[0].size();
+        res = file[0].seek(0, SEEK_CUR);
+        TEST_ASSERT_EQUAL(size, res);
+        res = file[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void test_large_file_seek()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].open(&fs, "hello/kitty42", O_RDONLY);
+        TEST_ASSERT_EQUAL(0, res);
+
+        off_t pos;
+        size = strlen("kittycatcat");
+        for (int i = 0; i < 128; i++) {
+            res = file[0].read(buffer, size);
+            TEST_ASSERT_EQUAL(size, res);
+            res = memcmp(buffer, "kittycatcat", size);
+            TEST_ASSERT_EQUAL(0, res);
+            pos = file[0].tell();
+        }
+        res = pos >= 0;
+        TEST_ASSERT_EQUAL(1, res);
+        res = file[0].seek(pos, SEEK_SET);
+        TEST_ASSERT_EQUAL(pos, res);
+        res = file[0].read(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = memcmp(buffer, "kittycatcat", size);
+        TEST_ASSERT_EQUAL(0, res);
+
+        file[0].rewind();
+        res = file[0].read(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = memcmp(buffer, "kittycatcat", size);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].seek(pos, SEEK_SET);
+        TEST_ASSERT_EQUAL(pos, res);
+        res = file[0].read(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = memcmp(buffer, "kittycatcat", size);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].seek(-size, SEEK_CUR);
+        TEST_ASSERT_EQUAL(pos, res);
+        res = file[0].read(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = memcmp(buffer, "kittycatcat", size);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].seek(-size, SEEK_END) >= 0;
+        TEST_ASSERT_EQUAL(1, res);
+        res = file[0].read(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = memcmp(buffer, "kittycatcat", size);
+        TEST_ASSERT_EQUAL(0, res);
+
+        size_t size = file[0].size();
+        res = file[0].seek(0, SEEK_CUR);
+        TEST_ASSERT_EQUAL(size, res);
+        res = file[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void test_simple_file_seek_and_write()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].open(&fs, "hello/kitty42", O_RDWR);
+        TEST_ASSERT_EQUAL(0, res);
+
+        off_t pos;
+        size = strlen("kittycatcat");
+        for (int i = 0; i < 4; i++) {
+            res = file[0].read(buffer, size);
+            TEST_ASSERT_EQUAL(size, res);
+            res = memcmp(buffer, "kittycatcat", size);
+            TEST_ASSERT_EQUAL(0, res);
+            pos = file[0].tell();
+        }
+        res = pos >= 0;
+        TEST_ASSERT_EQUAL(1, res);
+
+        memcpy(buffer, "doggodogdog", size);
+        res = file[0].seek(pos, SEEK_SET);
+        TEST_ASSERT_EQUAL(pos, res);
+        res = file[0].write(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = file[0].seek(pos, SEEK_SET);
+        TEST_ASSERT_EQUAL(pos, res);
+        res = file[0].read(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = memcmp(buffer, "doggodogdog", size);
+        TEST_ASSERT_EQUAL(0, res);
+
+        file[0].rewind();
+        res = file[0].read(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = memcmp(buffer, "kittycatcat", size);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].seek(pos, SEEK_SET);
+        TEST_ASSERT_EQUAL(pos, res);
+        res = file[0].read(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = memcmp(buffer, "doggodogdog", size);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].seek(-size, SEEK_END) >= 0;
+        TEST_ASSERT_EQUAL(1, res);
+        res = file[0].read(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = memcmp(buffer, "kittycatcat", size);
+        TEST_ASSERT_EQUAL(0, res);
+
+        size_t size = file[0].size();
+        res = file[0].seek(0, SEEK_CUR);
+        TEST_ASSERT_EQUAL(size, res);
+        res = file[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void test_large_file_seek_and_write()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].open(&fs, "hello/kitty42", O_RDWR);
+        TEST_ASSERT_EQUAL(0, res);
+
+        off_t pos;
+        size = strlen("kittycatcat");
+        for (int i = 0; i < 128; i++) {
+            res = file[0].read(buffer, size);
+            TEST_ASSERT_EQUAL(size, res);
+            if (i != 4) {
+                res = memcmp(buffer, "kittycatcat", size);
+                TEST_ASSERT_EQUAL(0, res);
+            }
+            pos = file[0].tell();
+        }
+        res = pos >= 0;
+        TEST_ASSERT_EQUAL(1, res);
+
+        memcpy(buffer, "doggodogdog", size);
+        res = file[0].seek(pos, SEEK_SET);
+        TEST_ASSERT_EQUAL(pos, res);
+        res = file[0].write(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = file[0].seek(pos, SEEK_SET);
+        TEST_ASSERT_EQUAL(pos, res);
+        res = file[0].read(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = memcmp(buffer, "doggodogdog", size);
+        TEST_ASSERT_EQUAL(0, res);
+
+        file[0].rewind();
+        res = file[0].read(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = memcmp(buffer, "kittycatcat", size);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].seek(pos, SEEK_SET);
+        TEST_ASSERT_EQUAL(pos, res);
+        res = file[0].read(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = memcmp(buffer, "doggodogdog", size);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].seek(-size, SEEK_END) >= 0;
+        TEST_ASSERT_EQUAL(1, res);
+        res = file[0].read(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = memcmp(buffer, "kittycatcat", size);
+        TEST_ASSERT_EQUAL(0, res);
+
+        size_t size = file[0].size();
+        res = file[0].seek(0, SEEK_CUR);
+        TEST_ASSERT_EQUAL(size, res);
+        res = file[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void test_boundary_seek_and_write()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].open(&fs, "hello/kitty42", O_RDWR);
+        TEST_ASSERT_EQUAL(0, res);
+
+        size = strlen("hedgehoghog");
+        const off_t offsets[] = {512, 1020, 513, 1021, 511, 1019};
+
+        for (int i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) {
+            off_t off = offsets[i];
+            memcpy(buffer, "hedgehoghog", size);
+            res = file[0].seek(off, SEEK_SET);
+            TEST_ASSERT_EQUAL(off, res);
+            res = file[0].write(buffer, size);
+            TEST_ASSERT_EQUAL(size, res);
+            res = file[0].seek(off, SEEK_SET);
+            TEST_ASSERT_EQUAL(off, res);
+            res = file[0].read(buffer, size);
+            TEST_ASSERT_EQUAL(size, res);
+            res = memcmp(buffer, "hedgehoghog", size);
+            TEST_ASSERT_EQUAL(0, res);
+            res = file[0].seek(0, SEEK_SET);
+            TEST_ASSERT_EQUAL(0, res);
+            res = file[0].read(buffer, size);
+            TEST_ASSERT_EQUAL(size, res);
+            res = memcmp(buffer, "kittycatcat", size);
+            TEST_ASSERT_EQUAL(0, res);
+            res = file[0].sync();
+            TEST_ASSERT_EQUAL(0, res);
+        }
+        res = file[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+void test_out_of_bounds_seek()
+{
+    int res = bd.init();
+    TEST_ASSERT_EQUAL(0, res);
+
+    {
+        res = fs.mount(&bd);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].open(&fs, "hello/kitty42", O_RDWR);
+        TEST_ASSERT_EQUAL(0, res);
+
+        size = strlen("kittycatcat");
+        res = file[0].size();
+        TEST_ASSERT_EQUAL(132 * size, res);
+        res = file[0].seek((132 + 4) * size,
+                           SEEK_SET);
+        TEST_ASSERT_EQUAL((132 + 4)*size, res);
+        res = file[0].read(buffer, size);
+        TEST_ASSERT_EQUAL(0, res);
+
+        memcpy(buffer, "porcupineee", size);
+        res = file[0].write(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = file[0].seek((132 + 4) * size,
+                           SEEK_SET);
+        TEST_ASSERT_EQUAL((132 + 4)*size, res);
+        res = file[0].read(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+        res = memcmp(buffer, "porcupineee", size);
+        TEST_ASSERT_EQUAL(0, res);
+        res = file[0].seek(132 * size,
+                           SEEK_SET);
+        TEST_ASSERT_EQUAL(132 * size, res);
+        res = file[0].read(buffer, size);
+        TEST_ASSERT_EQUAL(size, res);
+#if (MBED_TEST_FILESYSTEM != FATFileSystem)
+        // FatFs does not guarantee empty expanded buffer
+        res = memcmp(buffer, "\0\0\0\0\0\0\0\0\0\0\0", size);
+        TEST_ASSERT_EQUAL(0, res);
+#endif
+        res = file[0].close();
+        TEST_ASSERT_EQUAL(0, res);
+        res = fs.unmount();
+        TEST_ASSERT_EQUAL(0, res);
+    }
+
+    res = bd.deinit();
+    TEST_ASSERT_EQUAL(0, res);
+}
+
+
+
+// test setup
+utest::v1::status_t test_setup(const size_t number_of_cases)
+{
+    GREENTEA_SETUP(MBED_TEST_TIMEOUT, "default_auto");
+    return verbose_test_setup_handler(number_of_cases);
+}
+
+Case cases[] = {
+    Case("Seek tests", test_seek_tests),
+    Case("Simple dir seek", test_simple_dir_seek),
+    Case("Large dir seek", test_large_dir_seek),
+    Case("Simple file seek", test_simple_file_seek),
+    Case("Large file seek", test_large_file_seek),
+    Case("Simple file seek and write", test_simple_file_seek_and_write),
+    Case("Large file seek and write", test_large_file_seek_and_write),
+    Case("Boundary seek and write", test_boundary_seek_and_write),
+    Case("Out-of-bounds seek", test_out_of_bounds_seek),
+};
+
+Specification specification(test_setup, cases);
+
+int main()
+{
+    return !Harness::run(specification);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_SD/config/mbed_lib.json	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,220 @@
+{
+    "name": "sd",
+    "config": {
+        "SPI_CS": "NC",
+        "SPI_MOSI": "NC",
+        "SPI_MISO": "NC",
+        "SPI_CLK": "NC",
+        "DEVICE_SPI": 1,
+        "FSFAT_SDCARD_INSTALLED": 1,
+        "CMD_TIMEOUT": 10000,
+        "CMD0_IDLE_STATE_RETRIES": 5,
+        "SD_INIT_FREQUENCY": 100000
+    },
+    "target_overrides": {
+        "DISCO_F051R8": {
+             "SPI_MOSI": "SPI_MOSI",
+             "SPI_MISO": "SPI_MISO",
+             "SPI_CLK":  "SPI_SCK",
+             "SPI_CS":   "SPI_CS"
+        },
+        "DISCO_L475VG_IOT01A": {
+             "SPI_MOSI": "SPI_MOSI",
+             "SPI_MISO": "SPI_MISO",
+             "SPI_CLK":  "SPI_SCK",
+             "SPI_CS":   "SPI_CS"
+        },
+        "DISCO_L476VG": {
+          "SPI_MOSI": "PE_15",
+          "SPI_MISO": "PE_14",
+          "SPI_CLK":  "PE_13",
+          "SPI_CS":   "PE_12"
+        },
+        "K20D50M": {
+             "SPI_MOSI": "PTD2",
+             "SPI_MISO": "PTD3",
+             "SPI_CLK":  "PTD1",
+             "SPI_CS":   "PTC2"
+        },
+        "KL22F": {
+             "SPI_MOSI": "PTD6",
+             "SPI_MISO": "PTD7",
+             "SPI_CLK":  "PTD5",
+             "SPI_CS":   "PTD4"
+        },
+        "KL25Z": {
+             "SPI_MOSI": "PTD2",
+             "SPI_MISO": "PTD3",
+             "SPI_CLK":  "PTD1",
+             "SPI_CS":   "PTD0"
+        },
+        "KL43Z": {
+             "SPI_MOSI": "PTD6",
+             "SPI_MISO": "PTD7",
+             "SPI_CLK":  "PTD5",
+             "SPI_CS":   "PTD4"
+        },
+        "KL46Z": {
+             "SPI_MOSI": "PTD6",
+             "SPI_MISO": "PTD7",
+             "SPI_CLK":  "PTD5",
+             "SPI_CS":   "PTD4"
+        },
+        "K64F": {
+             "SPI_MOSI": "PTE3",
+             "SPI_MISO": "PTE1",
+             "SPI_CLK":  "PTE2",
+             "SPI_CS":   "PTE4"
+        },
+        "K66F": {
+             "SPI_MOSI": "PTE3",
+             "SPI_MISO": "PTE1",
+             "SPI_CLK":  "PTE2",
+             "SPI_CS":   "PTE4"
+        },
+        "LPC11U37H_401": {
+             "SPI_MOSI": "SDMOSI",
+             "SPI_MISO": "SDMISO",
+             "SPI_CLK":  "SDSCLK",
+             "SPI_CS":   "SDSSEL"
+        },
+        "LPC2368": {
+             "SPI_MOSI": "p11",
+             "SPI_MISO": "p12",
+             "SPI_CLK":  "p13",
+             "SPI_CS":   "p14"
+        },
+         "NUCLEO_F411RE": {
+             "SPI_MOSI": "PC_3",
+             "SPI_MISO": "PC_2",
+             "SPI_CLK":  "PC_7",
+             "SPI_CS":   "PB_9"
+         },
+         "NUCLEO_F429ZI": {
+             "SPI_MOSI": "PC_12",
+             "SPI_MISO": "PC_11",
+             "SPI_CLK":  "PC_10",
+             "SPI_CS":   "PA_15"
+         },
+         "DISCO_F429ZI": {
+            "SPI_MOSI": "PC_12",
+            "SPI_MISO": "PC_11",
+            "SPI_CLK":  "PC_10",
+            "SPI_CS":   "PA_15"
+        },
+         "NUCLEO_F746ZG": {
+            "SPI_MOSI": "PC_12",
+            "SPI_MISO": "PC_11",
+            "SPI_CLK":  "PC_10",
+            "SPI_CS":   "PA_15"
+        },
+         "NUCLEO_F767ZI": {
+            "SPI_MOSI": "PC_12",
+            "SPI_MISO": "PC_11",
+            "SPI_CLK":  "PC_10",
+            "SPI_CS":   "PA_15"
+        },
+        "NUCLEO_L031K6": {
+             "SPI_MOSI": "SPI_MOSI",
+             "SPI_MISO": "SPI_MISO",
+             "SPI_CLK":  "SPI_SCK",
+             "SPI_CS":   "SPI_CS"
+        },
+        "NUCLEO_L476RG": {
+             "SPI_MOSI": "SPI_MOSI",
+             "SPI_MISO": "SPI_MISO",
+             "SPI_CLK":  "SPI_SCK",
+             "SPI_CS":   "SPI_CS"
+        },
+        "NUMAKER_PFM_M453": {
+             "SPI_MOSI": "PD_13",
+             "SPI_MISO": "PD_14",
+             "SPI_CLK":  "PD_15",
+             "SPI_CS":   "PD_12"
+        },
+        "NUMAKER_PFM_M487": {
+             "SPI_MOSI": "D11",
+             "SPI_MISO": "D12",
+             "SPI_CLK":  "D13",
+             "SPI_CS":   "D10"
+        },
+        "NUMAKER_PFM_NUC472": {
+             "SPI_MOSI": "PF_0",
+             "SPI_MISO": "PD_15",
+             "SPI_CLK":  "PD_14",
+             "SPI_CS":   "PD_13"
+        },
+        "nRF51822": {
+             "SPI_MOSI": "p12",
+             "SPI_MISO": "p13",
+             "SPI_CLK":  "p15",
+             "SPI_CS":   "p14"
+        },
+        "UBLOX_C030": {
+             "SPI_MOSI": "D11",
+             "SPI_MISO": "D12",
+             "SPI_CLK":  "D13",
+             "SPI_CS":   "D10"
+        },
+        "UBLOX_EVK_ODIN_W2": {
+            "SPI_CS": "D9",
+            "SPI_MOSI": "D11",
+            "SPI_MISO": "D12",
+            "SPI_CLK": "D13"
+        },
+        "MTB_UBLOX_ODIN_W2": {
+            "SPI_CS": "PG_4",
+            "SPI_MOSI": "PE_14",
+            "SPI_MISO": "PE_13",
+            "SPI_CLK": "PE_12"
+       },
+        "RZ_A1H": {
+             "SPI_MOSI": "P8_5",
+             "SPI_MISO": "P8_6",
+             "SPI_CLK":  "P8_3",
+             "SPI_CS":   "P8_4"
+        },
+        "GR_LYCHEE": {
+             "SPI_MOSI": "P5_6",
+             "SPI_MISO": "P5_7",
+             "SPI_CLK":  "P5_4",
+             "SPI_CS":   "P5_5"
+        },
+        "HEXIWEAR": {
+             "SPI_MOSI": "PTE3",
+             "SPI_MISO": "PTE1",
+             "SPI_CLK":  "PTE2",
+             "SPI_CS":   "PTE4"
+        },
+        "MTB_MTS_DRAGONFLY": {
+             "SPI_MOSI": "SPI2_MOSI",
+             "SPI_MISO": "SPI2_MISO",
+             "SPI_CLK":  "SPI2_SCK",
+             "SPI_CS":   "SPI_CS2"
+        },
+        "TB_SENSE_12": {
+             "SPI_MOSI": "PC6",
+             "SPI_MISO": "PC7",
+             "SPI_CLK": "PC8",
+             "SPI_CS": "PC9"
+        },
+        "LPC1768": {
+            "SPI_MOSI": "p5",
+            "SPI_MISO": "p6",
+            "SPI_CLK": "p7",
+            "SPI_CS": "p8"
+        },
+        "REALTEK_RTL8195AM": {
+            "SPI_MOSI": "D11",
+            "SPI_MISO": "D12",
+            "SPI_CLK": "D13",
+            "SPI_CS": "D9"
+        },
+        "NUCLEO_F207ZG": {
+             "SPI_MOSI": "PC_12",
+             "SPI_MISO": "PC_11",
+             "SPI_CLK":  "PC_10",
+             "SPI_CS":   "PA_15"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_SD/util/fsfat_debug.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,104 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2016 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.
+ */
+
+/** @file fsfat_debug.h
+ *
+ * component debug header file.
+ */
+
+
+#ifndef __FSFAT_DEBUG
+#define __FSFAT_DEBUG
+
+#include <stdint.h>
+#include <assert.h>
+#include <stdio.h>
+
+
+/* Debug Support */
+
+#define FSFAT_LOG_NONE        0
+#define FSFAT_LOG_ERR         1
+#define FSFAT_LOG_WARN        2
+#define FSFAT_LOG_NOTICE      3
+#define FSFAT_LOG_INFO        4
+#define FSFAT_LOG_DEBUG       5
+#define FSFAT_LOG_FENTRY      6
+
+#define FSFAT_LOG(_fmt, ...)                          \
+  do                                                    \
+  {                                                     \
+        printf(_fmt, __VA_ARGS__);                      \
+  }while(0);
+
+#define noFSFAT_DEBUG
+#ifdef FSFAT_DEBUG
+
+extern uint32_t fsfat_optDebug_g;
+extern uint32_t fsfat_optLogLevel_g;
+
+
+/* uncomment for asserts to work */
+/* #undef NDEBUG */
+// todo: port to mbedOSV3++ #include <core-util/assert.h>
+
+#define FSFAT_INLINE
+// todo: port to mbedOSV3++ #define FSFAT_ASSERT  CORE_UTIL_ASSERT
+#define FSFAT_ASSERT(...)
+
+#define FSFAT_DBGLOG(_fmt, ...)                       \
+  do                                                    \
+  {                                                     \
+    if(fsfat_optDebug_g && (fsfat_optLogLevel_g >= FSFAT_LOG_DEBUG))  \
+    {                                                   \
+        printf(_fmt, __VA_ARGS__);                      \
+    }                                                   \
+  }while(0);
+
+
+#define FSFAT_ERRLOG(_fmt, ...)                       \
+  do                                                    \
+  {                                                     \
+    if(fsfat_optDebug_g && (fsfat_optLogLevel_g >= FSFAT_LOG_ERR))  \
+    {                                                   \
+        printf(_fmt, __VA_ARGS__);                      \
+    }                                                   \
+  }while(0);
+
+
+#define FSFAT_FENTRYLOG(_fmt, ...)                       \
+  do                                                    \
+  {                                                     \
+    if(fsfat_optDebug_g && (fsfat_optLogLevel_g >= FSFAT_LOG_FENTRY))  \
+    {                                                   \
+        printf(_fmt, __VA_ARGS__);                      \
+    }                                                   \
+  }while(0);
+
+
+
+
+
+#else
+#define FSFAT_ASSERT(_x)                   do { } while(0)
+#define FSFAT_INLINE                       inline
+#define FSFAT_DBGLOG(_fmt, ...)            do { } while(0)
+#define FSFAT_ERRLOG(_fmt, ...)            do { } while(0)
+#define FSFAT_FENTRYLOG(_fmt, ...)         do { } while(0)
+#endif /* FSFAT_DEBUG */
+
+
+#endif /*__FSFAT_DEBUG*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_SD/util/fsfat_test.c	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,116 @@
+/* @file fsfat_test.c
+ *
+ * mbed Microcontroller Library
+ * Copyright (c) 2006-2016 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.
+ *
+ * test support code implementation file.
+ */
+
+#include "fsfat_debug.h"
+#include "fsfat_test.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <ctype.h>
+
+
+#ifdef FSFAT_DEBUG
+uint32_t fsfat_optDebug_g = 1;
+uint32_t fsfat_optLogLevel_g = FSFAT_LOG_NONE; /*FSFAT_LOG_NONE|FSFAT_LOG_ERR|FSFAT_LOG_DEBUG|FSFAT_LOG_FENTRY; */
+#endif
+
+/* ruler for measuring text strings */
+/*                                                                                                    1         1         1         1         1         1         1         1         1         1         2         2         2 */
+/* 0        1         2         3         4         5         6         7         8         9         0         1         2         3         4         5         6         7         8         9         0         1         2 */
+/* 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 */
+
+const uint8_t fsfat_test_byte_data_table[FSFAT_TEST_BYTE_DATA_TABLE_SIZE] = {
+    0x2d, 0xf3, 0x31, 0x4c, 0x11, 0x4f, 0xde, 0x0d, 0xbd, 0xbc, 0xa6, 0x78, 0x36, 0x5c, 0x1d, 0x28,
+    0x5f, 0xa9, 0x10, 0x65, 0x54, 0x45, 0x21, 0x1a, 0x88, 0xfe, 0x76, 0x45, 0xb9, 0xac, 0x65, 0x9a,
+    0x34, 0x9d, 0x73, 0x10, 0xb4, 0xa9, 0x2e, 0x90, 0x95, 0x68, 0xac, 0xfe, 0xc5, 0x2d, 0x15, 0x03,
+    0x34, 0x70, 0xf1, 0x1d, 0x48, 0xa1, 0xa0, 0xed, 0x5c, 0x2f, 0xf5, 0x2b, 0xb9, 0x84, 0xbb, 0x45,
+    0x32, 0xdd, 0xb1, 0x33, 0x95, 0x2a, 0xbc, 0x26, 0xf0, 0x89, 0xba, 0xf4, 0xbd, 0xf9, 0x5d, 0x2e,
+    0x6e, 0x11, 0xc6, 0xa7, 0x78, 0xfc, 0xc9, 0x0e, 0x6b, 0x38, 0xba, 0x14, 0x1b, 0xab, 0x4c, 0x20,
+    0x91, 0xe4, 0xb0, 0xf1, 0x2b, 0x14, 0x07, 0x6b, 0xb5, 0xcd, 0xe3, 0x49, 0x75, 0xac, 0xe8, 0x98,
+    0xf1, 0x58, 0x8f, 0xd9, 0xc4, 0x8f, 0x00, 0x17, 0xb5, 0x06, 0x6a, 0x33, 0xbd, 0xa7, 0x40, 0x5a,
+    0xbf, 0x49, 0xf7, 0x27, 0x1b, 0x4c, 0x3e, 0x6f, 0xe3, 0x08, 0x1f, 0xfd, 0xa6, 0xd4, 0xc7, 0x5f,
+    0xa4, 0xa6, 0x82, 0xad, 0x19, 0xd5, 0x5c, 0xd8, 0x3a, 0x49, 0x85, 0xc9, 0x21, 0x83, 0xf6, 0xc6,
+    0x84, 0xf9, 0x76, 0x89, 0xf3, 0x2d, 0x17, 0x50, 0x97, 0x38, 0x48, 0x9a, 0xe1, 0x82, 0xcd, 0xac,
+    0xa8, 0x1d, 0xd7, 0x96, 0x5e, 0xb3, 0x08, 0xa8, 0x3a, 0xc7, 0x2b, 0x05, 0xaf, 0xdc, 0x16, 0xdf,
+    0x48, 0x0f, 0x2a, 0x7e, 0x3a, 0x82, 0xd7, 0x80, 0xd6, 0x49, 0x27, 0x5d, 0xe3, 0x07, 0x62, 0xb3,
+    0xc3, 0x6c, 0xba, 0xb2, 0xaa, 0x9f, 0xd9, 0x03, 0x0d, 0x27, 0xa8, 0xe0, 0xd6, 0xee, 0x79, 0x4b,
+    0xd6, 0x97, 0x99, 0xb7, 0x11, 0xd6, 0x0d, 0x34, 0xae, 0x99, 0x4a, 0x93, 0x95, 0xd0, 0x5a, 0x34,
+    0x19, 0xa2, 0x69, 0x57, 0xcf, 0x7c, 0x3d, 0x98, 0x88, 0x5d, 0x04, 0xf2, 0xd7, 0xac, 0xa5, 0x63
+};
+
+
+/* @brief  test utility function to delete the file identified by filename
+ */
+int32_t fsfat_test_delete(const char *filename)
+{
+    FSFAT_FENTRYLOG("%s:entered.\r\n", __func__);
+    return remove(filename);
+}
+
+
+/* @brief   test utility function to create a file
+ *
+ * @param   filename    name of the file including path
+ * @param   data        data to store in file
+ * @param   len         number of bytes of data present in the data buffer.
+ */
+int32_t fsfat_test_create(const char *filename, const char *data, size_t len)
+{
+    int32_t ret = -1;
+    FILE *fp = NULL;
+
+    FSFAT_FENTRYLOG("%s:entered (filename=%s, len=%d).\n", __func__, filename, (int) len);
+    fp = fopen(filename, "w+");
+    if (fp == NULL) {
+        return ret;
+    }
+    ret = fwrite((const void *) data, len, 1, fp);
+    if (ret < 0) {
+        fclose(fp);
+        return ret;
+    }
+    fclose(fp);
+    return ret;
+}
+
+
+/* @brief   support function for generating a kv_name
+ * @param   name    buffer to hold kv name
+ * @param   len     length of kv name to generate
+ *
+ */
+int32_t fsfat_test_filename_gen(char *name, const size_t len)
+{
+    size_t i;
+    uint32_t pos = 0;
+
+    const char *buf = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!$-_@";
+    const int buf_len = strlen(buf);
+    FSFAT_FENTRYLOG("%s:entered\n", __func__);
+    for (i = 0; i < len; i++) {
+        pos = rand() % (buf_len);
+        name[i] = buf[pos];
+    }
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_SD/util/fsfat_test.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,74 @@
+/** @file fsfat_test.h
+ *
+ * mbed Microcontroller Library
+ * Copyright (c) 2006-2016 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.
+ *
+ * Header file for test support data structures and function API.
+ */
+#ifndef __FSFAT_TEST_H
+#define __FSFAT_TEST_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Defines */
+//#define FSFAT_INIT_1_TABLE_HEAD                 { "a", ""}
+#define FSFAT_INIT_1_TABLE_MID_NODE             { "/sd/01234567.txt", "abcdefghijklmnopqrstuvwxyz"}
+//#define FSFAT_INIT_1_TABLE_TAIL                 { "/sd/fopentst/hello/world/animal/wobbly/dog/foot/backrght.txt", "present"}
+#define FSFAT_TEST_RW_TABLE_SENTINEL            0xffffffff
+#define FSFAT_TEST_BYTE_DATA_TABLE_SIZE         256
+#define FSFAT_UTEST_MSG_BUF_SIZE                256
+#define FSFAT_UTEST_DEFAULT_TIMEOUT_MS          10000
+#define FSFAT_MBED_HOSTTEST_TIMEOUT             60
+#define FSFAT_MAX_FILE_BASENAME                 8
+#define FSFAT_MAX_FILE_EXTNAME                  3
+#define FSFAT_BUF_MAX_LENGTH                    64
+#define FSFAT_FILENAME_MAX_LENGTH               255
+
+
+/* support macro for make string for utest _MESSAGE macros, which dont support formatted output */
+#define FSFAT_TEST_UTEST_MESSAGE(_buf, _max_len, _fmt, ...)   \
+  do                                                            \
+  {                                                             \
+      snprintf((_buf), (_max_len), (_fmt), __VA_ARGS__);        \
+  }while(0);
+
+
+/*
+ * Structures
+ */
+
+/* kv data for test */
+typedef struct fsfat_kv_data_t {
+    const char *filename;
+    const char *value;
+} fsfat_kv_data_t;
+
+
+extern const uint8_t fsfat_test_byte_data_table[FSFAT_TEST_BYTE_DATA_TABLE_SIZE];
+
+int32_t fsfat_test_create(const char *filename, const char *data, size_t len);
+int32_t fsfat_test_delete(const char *key_name);
+int32_t fsfat_test_filename_gen(char *name, const size_t len);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __FSFAT_TEST_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_SPIF/SPIFBlockDevice.cpp	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,1048 @@
+/* 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 "SPIFBlockDevice.h"
+#include "mbed_critical.h"
+
+#include <string.h>
+#include "mbed_wait_api.h"
+
+#include "mbed_trace.h"
+#define TRACE_GROUP "SPIF"
+using namespace mbed;
+
+/* Default SPIF Parameters */
+/****************************/
+#define SPIF_DEFAULT_READ_SIZE  1
+#define SPIF_DEFAULT_PROG_SIZE  1
+#define SPIF_DEFAULT_PAGE_SIZE  256
+#define SPIF_DEFAULT_SE_SIZE    4096
+#define SPI_MAX_STATUS_REGISTER_SIZE 2
+#ifndef UINT64_MAX
+#define UINT64_MAX -1
+#endif
+#define SPI_NO_ADDRESS_COMMAND UINT64_MAX
+// Status Register Bits
+#define SPIF_STATUS_BIT_WIP 0x1 //Write In Progress
+#define SPIF_STATUS_BIT_WEL 0x2 // Write Enable Latch
+
+/* SFDP Header Parsing */
+/***********************/
+#define SPIF_SFDP_HEADER_SIZE 8
+#define SPIF_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 SPIF_BASIC_PARAM_TABLE_FAST_READ_SUPPORT_BYTE 2
+#define SPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPORT_BYTE 16
+#define SPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE 23
+#define SPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE 15
+#define SPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE 13
+#define SPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE 40
+// Address Length
+#define SPIF_ADDR_SIZE_3_BYTES 3
+// Erase Types Params
+#define SPIF_BASIC_PARAM_ERASE_TYPE_1_BYTE 29
+#define SPIF_BASIC_PARAM_ERASE_TYPE_2_BYTE 31
+#define SPIF_BASIC_PARAM_ERASE_TYPE_3_BYTE 33
+#define SPIF_BASIC_PARAM_ERASE_TYPE_4_BYTE 35
+#define SPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE 28
+#define SPIF_BASIC_PARAM_ERASE_TYPE_2_SIZE_BYTE 30
+#define SPIF_BASIC_PARAM_ERASE_TYPE_3_SIZE_BYTE 32
+#define SPIF_BASIC_PARAM_ERASE_TYPE_4_SIZE_BYTE 34
+#define SPIF_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 spif_default_instructions {
+    SPIF_NOP = 0x00, // No operation
+    SPIF_PP = 0x02, // Page Program data
+    SPIF_READ = 0x03, // Read data
+    SPIF_SE   = 0x20, // 4KB Sector Erase
+    SPIF_SFDP = 0x5a, // Read SFDP
+    SPIF_WRSR = 0x01, // Write Status/Configuration Register
+    SPIF_WRDI = 0x04, // Write Disable
+    SPIF_RDSR = 0x05, // Read Status Register
+    SPIF_WREN = 0x06, // Write Enable
+    SPIF_RSTEN = 0x66, // Reset Enable
+    SPIF_RST = 0x99, // Reset
+    SPIF_RDID = 0x9f, // Read Manufacturer and JDEC Device ID
+};
+
+// Mutex is used for some SPI 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
+SingletonPtr<PlatformMutex> SPIFBlockDevice::_mutex;
+
+// Local Function
+static unsigned int local_math_power(int base, int exp);
+
+//***********************
+// SPIF Block Device APIs
+//***********************
+SPIFBlockDevice::SPIFBlockDevice(
+    PinName mosi, PinName miso, PinName sclk, PinName csel, int freq)
+    : _spi(mosi, miso, sclk), _cs(csel), _device_size_bytes(0), _is_initialized(false), _init_ref_count(0)
+{
+    _address_size = SPIF_ADDR_SIZE_3_BYTES;
+    // Initial SFDP read tables are read with 8 dummy cycles
+    // Default Bus Setup 1_1_1 with 0 dummy and mode cycles
+    _read_dummy_and_mode_cycles = 8;
+    _write_dummy_and_mode_cycles = 0;
+    _dummy_and_mode_cycles = _read_dummy_and_mode_cycles;
+
+    _min_common_erase_size = 0;
+    _regions_count = 1;
+    _region_erase_types_bitfield[0] = ERASE_BITMASK_NONE;
+
+    if (SPIF_BD_ERROR_OK != _spi_set_frequency(freq)) {
+        tr_error("ERROR: SPI Set Frequency Failed");
+    }
+
+    _cs = 1;
+}
+
+int SPIFBlockDevice::init()
+{
+    uint8_t vendor_device_ids[4];
+    size_t data_length = 3;
+    int status = SPIF_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;
+    spif_bd_error spi_status = SPIF_BD_ERROR_OK;
+
+    _mutex->lock();
+
+    if (!_is_initialized) {
+        _init_ref_count = 0;
+    }
+
+    _init_ref_count++;
+
+    if (_init_ref_count != 1) {
+        goto exit_point;
+    }
+
+    // Soft Reset
+    if (-1 == _reset_flash_mem()) {
+        tr_error("ERROR: init - Unable to initialize flash memory, tests failed\n");
+        status = SPIF_BD_ERROR_DEVICE_ERROR;
+        goto exit_point;
+    } else {
+        tr_info("INFO: Initialize flash memory OK\n");
+    }
+
+
+    /* Read Manufacturer ID (1byte), and Device ID (2bytes)*/
+    spi_status = _spi_send_general_command(SPIF_RDID, SPI_NO_ADDRESS_COMMAND, NULL, 0, (char *)vendor_device_ids,
+                                           data_length);
+    if (spi_status != SPIF_BD_ERROR_OK) {
+        tr_error("ERROR: init - Read Vendor ID Failed");
+        status = SPIF_BD_ERROR_DEVICE_ERROR;
+        goto exit_point;
+    }
+
+    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();
+            _spi_send_general_command(SPIF_WRDI, SPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0);
+            break;
+    }
+
+    //Synchronize Device
+    if (false == _is_mem_ready()) {
+        tr_error("ERROR: init - _is_mem_ready Failed");
+        status = SPIF_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("ERROR: init - Parse SFDP Headers Failed");
+        status = SPIF_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("ERROR: init - Parse Basic Param Table Failed");
+        status = SPIF_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("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("ERROR: init - Parse Sector Map Table Failed");
+            status = SPIF_BD_ERROR_PARSING_FAILED;
+            goto exit_point;
+        }
+    }
+
+    // Configure  BUS Mode to 1_1_1 for all commands other than Read
+    // Dummy And Mode Cycles Back default 0
+    _dummy_and_mode_cycles = _write_dummy_and_mode_cycles;
+    _is_initialized = true;
+
+exit_point:
+    _mutex->unlock();
+
+    return status;
+}
+
+
+int SPIFBlockDevice::deinit()
+{
+    spif_bd_error status = SPIF_BD_ERROR_OK;
+
+    _mutex->lock();
+
+    if (!_is_initialized) {
+        _init_ref_count = 0;
+        goto exit_point;
+    }
+
+    _init_ref_count--;
+
+    if (_init_ref_count) {
+        goto exit_point;
+    }
+
+    // Disable Device for Writing
+    status = _spi_send_general_command(SPIF_WRDI, SPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0);
+    if (status != SPIF_BD_ERROR_OK)  {
+        tr_error("ERROR: Write Disable failed");
+    }
+    _is_initialized = false;
+
+exit_point:
+    _mutex->unlock();
+
+    return status;
+}
+
+int SPIFBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
+{
+    if (!_is_initialized) {
+        return BD_ERROR_DEVICE_ERROR;
+    }
+
+    int status = SPIF_BD_ERROR_OK;
+    tr_info("INFO Read - Inst: 0x%xh", _read_instruction);
+    _mutex->lock();
+
+    // Set Dummy Cycles for Specific Read Command Mode
+    _dummy_and_mode_cycles = _read_dummy_and_mode_cycles;
+
+    status = _spi_send_read_command(_read_instruction, static_cast<uint8_t *>(buffer), addr, size);
+
+    // Set Dummy Cycles for all other command modes
+    _dummy_and_mode_cycles = _write_dummy_and_mode_cycles;
+
+    _mutex->unlock();
+    return status;
+}
+
+int SPIFBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size)
+{
+    if (!_is_initialized) {
+        return BD_ERROR_DEVICE_ERROR;
+    }
+
+    bool program_failed = false;
+    int status = SPIF_BD_ERROR_OK;
+    uint32_t offset = 0;
+    uint32_t chunk = 0;
+
+    tr_debug("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);
+
+        _mutex->lock();
+
+        //Send WREN
+        if (_set_write_enable() != 0) {
+            tr_error("ERROR: Write Enabe failed\n");
+            program_failed = true;
+            status = SPIF_BD_ERROR_WREN_FAILED;
+            goto exit_point;
+        }
+
+        _spi_send_program_command(_prog_instruction, buffer, addr, chunk);
+
+        buffer = static_cast<const uint8_t *>(buffer) + chunk;
+        addr += chunk;
+        size -= chunk;
+
+        if (false == _is_mem_ready()) {
+            tr_error("ERROR: Device not ready after write, failed\n");
+            program_failed = true;
+            status = SPIF_BD_ERROR_READY_FAILED;
+            goto exit_point;
+        }
+        _mutex->unlock();
+    }
+
+exit_point:
+    if (program_failed) {
+        _mutex->unlock();
+    }
+
+    return status;
+}
+
+int SPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size)
+{
+    if (!_is_initialized) {
+        return BD_ERROR_DEVICE_ERROR;
+    }
+
+    int type = 0;
+    uint32_t offset = 0;
+    uint32_t chunk = 4096;
+    int cur_erase_inst = _erase_instruction;
+    int size = (int)in_size;
+    bool erase_failed = false;
+    int status = SPIF_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_info("DEBUG: erase - addr: %llu, in_size: %llu", addr, in_size);
+
+    if ((addr + in_size) > _device_size_bytes) {
+        tr_error("ERROR: erase exceeds flash device size");
+        return SPIF_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("ERROR: invalid erase - unaligned address and size");
+        return SPIF_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, (unsigned 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("DEBUG: erase - addr: %llu, size:%d, Inst: 0x%xh, chunk: %lu , ",
+                 addr, size, cur_erase_inst, chunk);
+        tr_debug("DEBUG: erase - Region: %d, Type:%d",
+                 region, type);
+
+        _mutex->lock();
+
+        if (_set_write_enable() != 0) {
+            tr_error("ERROR: SPI Erase Device not ready - failed");
+            erase_failed = true;
+            status = SPIF_BD_ERROR_READY_FAILED;
+            goto exit_point;
+        }
+
+        _spi_send_erase_command(cur_erase_inst, addr, size);
+
+        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("ERROR: SPI After Erase Device not ready - failed\n");
+            erase_failed = true;
+            status = SPIF_BD_ERROR_READY_FAILED;
+            goto exit_point;
+        }
+
+        _mutex->unlock();
+    }
+
+exit_point:
+    if (erase_failed) {
+        _mutex->unlock();
+    }
+
+    return status;
+}
+
+bd_size_t SPIFBlockDevice::get_read_size() const
+{
+    // Assuming all devices support 1byte read granularity
+    return SPIF_DEFAULT_READ_SIZE;
+}
+
+bd_size_t SPIFBlockDevice::get_program_size() const
+{
+    // Assuming all devices support 1byte program granularity
+    return SPIF_DEFAULT_PROG_SIZE;
+}
+
+bd_size_t SPIFBlockDevice::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 SPIFBlockDevice::get_erase_size(bd_addr_t addr)
+{
+    // Find region of current address
+    int region = _utils_find_addr_region(addr);
+
+    unsigned 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("ERROR: no erase type was found for region addr");
+        }
+    }
+
+    return (bd_size_t)min_region_erase_size;
+}
+
+bd_size_t SPIFBlockDevice::size() const
+{
+    if (!_is_initialized) {
+        return 0;
+    }
+
+    return _device_size_bytes;
+}
+
+int SPIFBlockDevice::get_erase_value() const
+{
+    return 0xFF;
+}
+
+/***************************************************/
+/*********** SPI Driver API Functions **************/
+/***************************************************/
+spif_bd_error SPIFBlockDevice::_spi_set_frequency(int freq)
+{
+    _spi.frequency(freq);
+    return SPIF_BD_ERROR_OK;
+}
+
+spif_bd_error SPIFBlockDevice::_spi_send_read_command(int read_inst, uint8_t *buffer, bd_addr_t addr, bd_size_t size)
+{
+    uint32_t dummy_bytes = _dummy_and_mode_cycles / 8;
+    int dummy_byte = 0;
+
+    // csel must go low for the entire command (Inst, Address and Data)
+    _cs = 0;
+
+    // Write 1 byte Instruction
+    _spi.write(read_inst);
+
+    // Write Address (can be either 3 or 4 bytes long)
+    for (int address_shift = ((_address_size - 1) * 8); address_shift >= 0; address_shift -= 8) {
+        _spi.write((addr >> address_shift) & 0xFF);
+    }
+
+    // Write Dummy Cycles Bytes
+    for (uint32_t i = 0; i < dummy_bytes; i++) {
+        _spi.write(dummy_byte);
+    }
+
+    // Read Data
+    for (bd_size_t i = 0; i < size; i++) {
+        buffer[i] = _spi.write(0);
+    }
+
+    // csel back to high
+    _cs = 1;
+    return SPIF_BD_ERROR_OK;
+}
+
+spif_bd_error SPIFBlockDevice::_spi_send_program_command(int prog_inst, const void *buffer, bd_addr_t addr,
+                                                         bd_size_t size)
+{
+    // Send Program (write) command to device driver
+    uint32_t dummy_bytes = _dummy_and_mode_cycles / 8;
+    int dummy_byte = 0;
+    uint8_t *data = (uint8_t *)buffer;
+
+    // csel must go low for the entire command (Inst, Address and Data)
+    _cs = 0;
+
+    // Write 1 byte Instruction
+    _spi.write(prog_inst);
+
+    // Write Address (can be either 3 or 4 bytes long)
+    for (int address_shift = ((_address_size - 1) * 8); address_shift >= 0; address_shift -= 8) {
+        _spi.write((addr >> address_shift) & 0xFF);
+    }
+
+    // Write Dummy Cycles Bytes
+    for (uint32_t i = 0; i < dummy_bytes; i++) {
+        _spi.write(dummy_byte);
+    }
+
+    // Write Data
+    for (bd_size_t i = 0; i < size; i++) {
+        _spi.write(data[i]);
+    }
+
+    // csel back to high
+    _cs = 1;
+
+    return SPIF_BD_ERROR_OK;
+}
+
+spif_bd_error SPIFBlockDevice::_spi_send_erase_command(int erase_inst, bd_addr_t addr, bd_size_t size)
+{
+    tr_info("INFO: Erase Inst: 0x%xh, addr: %llu, size: %llu", erase_inst, addr, size);
+    addr = (((int)addr) & 0x00FFF000);
+    _spi_send_general_command(erase_inst, addr, NULL, 0, NULL, 0);
+    return SPIF_BD_ERROR_OK;
+}
+
+spif_bd_error SPIFBlockDevice::_spi_send_general_command(int instruction, bd_addr_t addr, char *tx_buffer,
+                                                         size_t tx_length, char *rx_buffer, size_t rx_length)
+{
+    // Send a general command Instruction to driver
+    uint32_t dummy_bytes = _dummy_and_mode_cycles / 8;
+    uint8_t dummy_byte = 0x00;
+
+    // csel must go low for the entire command (Inst, Address and Data)
+    _cs = 0;
+
+    // Write 1 byte Instruction
+    _spi.write(instruction);
+
+    // Reading SPI Bus registers does not require Flash Address
+    if (addr != SPI_NO_ADDRESS_COMMAND) {
+        // Write Address (can be either 3 or 4 bytes long)
+        for (int address_shift = ((_address_size - 1) * 8); address_shift >= 0; address_shift -= 8) {
+            _spi.write((addr >> address_shift) & 0xFF);
+        }
+
+        // Write Dummy Cycles Bytes
+        for (uint32_t i = 0; i < dummy_bytes; i++) {
+            _spi.write(dummy_byte);
+        }
+    }
+
+    // Read/Write Data
+    _spi.write(tx_buffer, (int)tx_length, rx_buffer, (int)rx_length);
+
+    // csel back to high
+    _cs = 1;
+
+    return SPIF_BD_ERROR_OK;
+}
+
+/*********************************************************/
+/********** SFDP Parsing and Detection Functions *********/
+/*********************************************************/
+int SPIFBlockDevice::_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;
+
+
+    spif_bd_error status = _spi_send_read_command(SPIF_SFDP, sector_map_table, sector_map_table_addr /*address*/,
+                                                  sector_map_table_size);
+    if (status != SPIF_BD_ERROR_OK) {
+        tr_error("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("ERROR: Sector Map - Supporting Only Single! Map Descriptor (not map commands)");
+        return -1;
+    }
+
+    _regions_count = sector_map_table[2] + 1;
+    if (_regions_count > SPIF_MAX_REGIONS) {
+        tr_error("ERROR: Supporting up to %d regions, current setup to %d regions - fail",
+                 SPIF_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 SPIFBlockDevice::_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 */
+    //memset(param_table, 0, SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES);
+
+    spif_bd_error status = _spi_send_read_command(SPIF_SFDP, param_table, basic_table_addr /*address*/,
+                                                  basic_table_size);
+    if (status != SPIF_BD_ERROR_OK) {
+        tr_error("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("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 = SPIF_READ;
+    _prog_instruction = SPIF_PP;
+    _erase_instruction = SPIF_SE;
+
+    // Set Page Size (SPI write must be done on Page limits)
+    _page_size_bytes = _sfdp_detect_page_size(param_table, basic_table_size);
+
+    // Detect and Set Erase Types
+    _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, _read_instruction);
+
+    return 0;
+}
+
+int SPIFBlockDevice::_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[16];
+    uint8_t param_header[SPIF_SFDP_HEADER_SIZE];
+    size_t data_length = SPIF_SFDP_HEADER_SIZE;
+    bd_addr_t addr = 0x0;
+
+    // Set 1-1-1 bus mode for SFDP header parsing
+    // Initial SFDP read tables are read with 8 dummy cycles
+    _read_dummy_and_mode_cycles = 8;
+    _dummy_and_mode_cycles = 8;
+
+    spif_bd_error status = _spi_send_read_command(SPIF_SFDP, sfdp_header, addr /*address*/, data_length);
+    if (status != SPIF_BD_ERROR_OK) {
+        tr_error("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("ERROR: init - _verify SFDP signature and version Failed");
+        return -1;
+    } else {
+        tr_info("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("DEBUG: number of Param Headers: %d", number_of_param_headers);
+
+
+    addr += SPIF_SFDP_HEADER_SIZE;
+    data_length = SPIF_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 = _spi_send_read_command(SPIF_SFDP, param_header, addr, data_length);
+        if (status != SPIF_BD_ERROR_OK) {
+            tr_error("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("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("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("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 += SPIF_PARAM_HEADER_SIZE;
+
+    }
+    return 0;
+}
+
+unsigned int SPIFBlockDevice::_sfdp_detect_page_size(uint8_t *basic_param_table_ptr, int basic_param_table_size)
+{
+    unsigned int page_size = SPIF_DEFAULT_PAGE_SIZE;
+
+    if (basic_param_table_size > SPIF_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[SPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE]) >> 4;
+        page_size = local_math_power(2, page_to_power_size);
+        tr_debug("DEBUG: Detected Page Size: %d", page_size);
+    } else {
+        tr_debug("DEBUG: Using Default Page Size: %d", page_size);
+    }
+    return page_size;
+}
+
+int SPIFBlockDevice::_sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param_table_ptr, int basic_param_table_size,
+                                                            int &erase4k_inst,
+                                                            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[SPIF_BASIC_PARAM_4K_ERASE_TYPE_BYTE];
+
+    if (basic_param_table_size > SPIF_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[SPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE + 2 * i_ind]); // Size given as 2^N
+            tr_info("DEBUG: 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[SPIF_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("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("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("WARNING: Couldn't find Erase Type for 4KB size");
+    }
+    return 0;
+}
+
+int SPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table_ptr, int basic_param_table_size,
+                                                     int &read_inst)
+{
+    do {
+
+        // TBD - SPIF Dual Read Modes Require SPI driver support
+        /*
+        uint8_t examined_byte;
+
+        if (basic_param_table_size > SPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPORT_BYTE) {
+            examined_byte = basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_QPI_READ_SUPPORT_BYTE];
+            if (examined_byte & 0x01) {
+                //  Fast Read 2-2-2 Supported
+                read_inst = basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE];
+                _read_dummy_and_mode_cycles = (basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE - 1] >> 5)
+                                         + (basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE - 1] & 0x1F);
+                tr_info("\nDEBUG: Read Bus Mode set to 2-2-2, Instruction: 0x%xh", read_inst);
+                break;
+            }
+        }
+        examined_byte = basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_FAST_READ_SUPPORT_BYTE];
+        if (examined_byte & 0x20) {
+            //  Fast Read 1-2-2 Supported
+            read_inst = basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE];
+            _read_dummy_and_mode_cycles = (basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE - 1] >> 5)
+                                     + (basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE - 1] & 0x1F);
+            tr_debug("\nDEBUG: Read Bus Mode set to 1-2-2, Instruction: 0x%xh", read_inst);
+            break;
+        }
+        if (examined_byte & 0x01) {
+            // Fast Read 1-1-2 Supported
+            read_inst = basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE];
+            _read_dummy_and_mode_cycles = (basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE - 1] >> 5)
+                                     + (basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE - 1] & 0x1F);
+             tr_debug("\nDEBUG: Read Bus Mode set to 1-1-2, Instruction: 0x%xh", _read_instruction);
+            break;
+        }
+         */
+        _read_dummy_and_mode_cycles = 0;
+        tr_debug("\nDEBUG: Read Bus Mode set to 1-1-1, Instruction: 0x%xh", read_inst);
+    } while (false);
+
+    return 0;
+}
+
+int SPIFBlockDevice::_reset_flash_mem()
+{
+    // Perform Soft Reset of the Device prior to initialization
+    int status = 0;
+    char status_value[2] = {0};
+    tr_info("INFO: _reset_flash_mem:\n");
+    //Read the Status Register from device
+    if (SPIF_BD_ERROR_OK == _spi_send_general_command(SPIF_RDSR, SPI_NO_ADDRESS_COMMAND, NULL, 0, status_value, 1)) {
+        // store received values in status_value
+        tr_debug("DEBUG: Reading Status Register Success: value = 0x%x\n", (int)status_value[0]);
+    } else {
+        tr_debug("ERROR: Reading Status Register failed\n");
+        status = -1;
+    }
+
+    if (0 == status) {
+        //Send Reset Enable
+        if (SPIF_BD_ERROR_OK == _spi_send_general_command(SPIF_RSTEN, SPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0)) {
+            // store received values in status_value
+            tr_debug("DEBUG: Sending RSTEN Success\n");
+        } else {
+            tr_error("ERROR: Sending RSTEN failed\n");
+            status = -1;
+        }
+
+        if (0 == status) {
+            //Send Reset
+            if (SPIF_BD_ERROR_OK == _spi_send_general_command(SPIF_RST, SPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0)) {
+                // store received values in status_value
+                tr_debug("DEBUG: Sending RST Success\n");
+            } else {
+                tr_error("ERROR: Sending RST failed\n");
+                status = -1;
+            }
+            _is_mem_ready();
+        }
+    }
+
+    return status;
+}
+
+bool SPIFBlockDevice::_is_mem_ready()
+{
+    // Check Status Register Busy Bit to Verify the Device isn't Busy
+    char status_value[2];
+    int retries = 0;
+    bool mem_ready = true;
+
+    do {
+        wait_ms(1);
+        retries++;
+        //Read the Status Register from device
+        if (SPIF_BD_ERROR_OK != _spi_send_general_command(SPIF_RDSR, SPI_NO_ADDRESS_COMMAND, NULL, 0, status_value,
+                                                          1)) {   // store received values in status_value
+            tr_error("ERROR: Reading Status Register failed\n");
+        }
+    } while ((status_value[0] & SPIF_STATUS_BIT_WIP) != 0 && retries < IS_MEM_READY_MAX_RETRIES);
+
+    if ((status_value[0] & SPIF_STATUS_BIT_WIP) != 0) {
+        tr_error("ERROR: _is_mem_ready FALSE\n");
+        mem_ready = false;
+    }
+    return mem_ready;
+}
+
+int SPIFBlockDevice::_set_write_enable()
+{
+    // Check Status Register Busy Bit to Verify the Device isn't Busy
+    char status_value[2];
+    int status = -1;
+
+    do {
+        if (SPIF_BD_ERROR_OK !=  _spi_send_general_command(SPIF_WREN, SPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0)) {
+            tr_error("ERROR:Sending WREN command FAILED\n");
+            break;
+        }
+
+        if (false == _is_mem_ready()) {
+            tr_error("ERROR: Device not ready, write failed");
+            break;
+        }
+
+        memset(status_value, 0, 2);
+        if (SPIF_BD_ERROR_OK != _spi_send_general_command(SPIF_RDSR, SPI_NO_ADDRESS_COMMAND, NULL, 0, status_value,
+                                                          1)) {   // store received values in status_value
+            tr_error("ERROR: Reading Status Register failed\n");
+            break;
+        }
+
+        if ((status_value[0] & SPIF_STATUS_BIT_WEL) == 0) {
+            tr_error("ERROR: _set_write_enable failed\n");
+            break;
+        }
+        status = 0;
+    } while (false);
+    return status;
+}
+
+/*********************************************/
+/************* Utility Functions *************/
+/*********************************************/
+int SPIFBlockDevice::_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 SPIFBlockDevice::_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("ERROR: no erase type was found for current region addr");
+    }
+    return largest_erase_type;
+
+}
+
+/*********************************************/
+/************** Local Functions **************/
+/*********************************************/
+static unsigned 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/components/storage/blockdevice/COMPONENT_SPIF/SPIFBlockDevice.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,300 @@
+/* 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_SPIF_BLOCK_DEVICE_H
+#define MBED_SPIF_BLOCK_DEVICE_H
+
+#include "SPI.h"
+#include "DigitalOut.h"
+#include "BlockDevice.h"
+
+/** Enum spif standard error codes
+ *
+ *  @enum spif_bd_error
+ */
+enum spif_bd_error {
+    SPIF_BD_ERROR_OK                    = 0,     /*!< no error */
+    SPIF_BD_ERROR_DEVICE_ERROR          = BD_ERROR_DEVICE_ERROR, /*!< device specific error -4001 */
+    SPIF_BD_ERROR_PARSING_FAILED        = -4002, /* SFDP Parsing failed */
+    SPIF_BD_ERROR_READY_FAILED          = -4003, /* Wait for  Mem Ready failed */
+    SPIF_BD_ERROR_WREN_FAILED           = -4004, /* Write Enable Failed */
+    SPIF_BD_ERROR_INVALID_ERASE_PARAMS  = -4005, /* Erase command not on sector aligned addresses or exceeds device size */
+};
+
+
+#define SPIF_MAX_REGIONS    10
+#define MAX_NUM_OF_ERASE_TYPES 4
+
+/** BlockDevice for SFDP based flash devices over SPI bus
+ *
+ *  @code
+ *  // Here's an example using SPI flash device on K82F target
+ *  #include "mbed.h"
+ *  #include "SPIFBlockDevice.h"
+ *
+ *  // Create flash device on SPI bus with PTE5 as chip select
+ *  SPIFBlockDevice spif(PTE2, PTE4, PTE1, PTE5);
+ *
+ *  int main() {
+ *      printf("spif test\n");
+ *
+ *      // Initialize the SPI flash device and print the memory layout
+ *      spif.init();
+ *      printf("spif size: %llu\n",         spif.size());
+ *      printf("spif read size: %llu\n",    spif.get_read_size());
+ *      printf("spif program size: %llu\n", spif.get_program_size());
+ *      printf("spif erase size: %llu\n",   spif.get_erase_size());
+ *
+ *      // Write "Hello World!" to the first block
+ *      char *buffer = (char*)malloc(spif.get_erase_size());
+ *      sprintf(buffer, "Hello World!\n");
+ *      spif.erase(0, spif.get_erase_size());
+ *      spif.program(buffer, 0, spif.get_erase_size());
+ *
+ *      // Read back what was stored
+ *      spif.read(buffer, 0, spif.get_erase_size());
+ *      printf("%s", buffer);
+ *
+ *      // Deinitialize the device
+ *      spif.deinit();
+ *  }
+ *  @endcode
+ */
+class SPIFBlockDevice : public BlockDevice {
+public:
+    /** Creates a SPIFBlockDevice on a SPI bus specified by pins
+     *
+     *  @param mosi     SPI master out, slave in pin
+     *  @param miso     SPI master in, slave out pin
+     *  @param sclk     SPI clock pin
+     *  @param csel     SPI chip select pin
+     *  @param freq     Clock speed of the SPI bus (defaults to 40MHz)
+     */
+    SPIFBlockDevice(PinName mosi, PinName miso, PinName sclk, PinName csel, int freq = 40000000);
+
+    /** Initialize a block device
+     *
+     *  @return         SPIF_BD_ERROR_OK(0) - success
+     *                  SPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
+     *                  SPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timedout
+     *                  SPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
+     */
+    virtual int init();
+
+    /** Deinitialize a block device
+     *
+     *  @return         SPIF_BD_ERROR_OK(0) - success
+     */
+    virtual int deinit();
+
+    /** Desctruct SPIFBlockDevie
+      */
+    ~SPIFBlockDevice()
+    {
+        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         SPIF_BD_ERROR_OK(0) - success
+     *                  SPIF_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         SPIF_BD_ERROR_OK(0) - success
+     *                  SPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
+     *                  SPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
+     *                  SPIF_BD_ERROR_WREN_FAILED - Write Enable failed
+     */
+    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         SPIF_BD_ERROR_OK(0) - success
+     *                  SPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed
+     *                  SPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out
+     *                  SPIF_BD_ERROR_WREN_FAILED - Write Enable failed
+     *                  SPIF_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 programable block 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 eraseable block 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
+
+    /****************************************/
+    /* 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, int &read_inst);
+
+    // Set Page size for program
+    unsigned 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,
+                                               int &erase4k_inst,
+                                               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);
+
+    /********************************/
+    /*   Calls to SPI Driver APIs   */
+    /********************************/
+    // Send Program => Write command to Driver
+    spif_bd_error _spi_send_program_command(int prog_inst, const void *buffer, bd_addr_t addr, bd_size_t size);
+
+    // Send Read command to Driver
+    //spif_bd_error _spi_send_read_command(uint8_t read_inst, void *buffer, bd_addr_t addr, bd_size_t size);
+    spif_bd_error _spi_send_read_command(int read_inst, uint8_t *buffer, bd_addr_t addr, bd_size_t size);
+
+    // Send Erase Instruction using command_transfer command to Driver
+    spif_bd_error _spi_send_erase_command(int erase_inst, bd_addr_t addr, bd_size_t size);
+
+    // Send Generic command_transfer command to Driver
+    spif_bd_error _spi_send_general_command(int instruction, bd_addr_t addr, char *tx_buffer,
+                                            size_t tx_length, char *rx_buffer, size_t rx_length);
+
+    // Send set_frequency command to Driver
+    spif_bd_error _spi_set_frequency(int freq);
+    /********************************/
+
+    // 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();
+
+private:
+    // Master side hardware
+    mbed::SPI _spi;
+    // Enable CS control (low/high) for SPI driver operatios
+    mbed::DigitalOut _cs;
+
+    // Mutex is used to protect Flash device for some SPI 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
+    static SingletonPtr<PlatformMutex> _mutex;
+
+    // Command Instructions
+    int _read_instruction;
+    int _prog_instruction;
+    int _erase_instruction;
+    int _erase4k_inst;  // Legacy 4K erase instruction (default 0x20h)
+
+    // Up To 4 Erase Types are supported by SFDP (each with its own command Instruction and Size)
+    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[SPIF_MAX_REGIONS]; //regions size in bytes
+    bd_size_t _region_high_boundary[SPIF_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[SPIF_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
+    bd_size_t _device_size_bytes;
+
+    // Bus configuration
+    unsigned int _address_size; // number of bytes for address
+    unsigned int _read_dummy_and_mode_cycles; // Number of Dummy and Mode Bits required by Read Bus Mode
+    unsigned int _write_dummy_and_mode_cycles; // Number of Dummy and Mode Bits required by Write Bus Mode
+    unsigned 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  /* MBED_SPIF_BLOCK_DEVICE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/storage/blockdevice/COMPONENT_SPIF/TESTS/block_device/spif/main.cpp	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,286 @@
+/* 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 "SPIFBlockDevice.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 SPIF_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(SPIFBlockDevice &block_device, 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) % block_device.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 = block_device.erase(block, block_size);
+    TEST_ASSERT_EQUAL(0, err);
+
+    err = block_device.program(write_block, block, block_size);
+    TEST_ASSERT_EQUAL(0, err);
+
+    err = block_device.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_spif_random_program_read_erase()
+{
+    utest_printf("\nTest Random Program Read Erase Starts..\n");
+
+    SPIFBlockDevice block_device(MBED_CONF_SPIF_DRIVER_SPI_MOSI, MBED_CONF_SPIF_DRIVER_SPI_MISO,
+                                 MBED_CONF_SPIF_DRIVER_SPI_CLK,
+                                 MBED_CONF_SPIF_DRIVER_SPI_CS);
+
+    int err = block_device.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 = (block_device.*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 = block_device.get_erase_size();
+    unsigned addrwidth = ceil(log(float(block_device.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(block_device, block_size, write_block, read_block, addrwidth);
+    }
+
+    err = block_device.deinit();
+    TEST_ASSERT_EQUAL(0, err);
+
+end:
+    delete[] write_block;
+    delete[] read_block;
+}
+
+void test_spif_unaligned_erase()
+{
+    utest_printf("\nTest Unaligned Erase Starts..\n");
+
+    SPIFBlockDevice block_device(MBED_CONF_SPIF_DRIVER_SPI_MOSI, MBED_CONF_SPIF_DRIVER_SPI_MISO,
+                                 MBED_CONF_SPIF_DRIVER_SPI_CLK,
+                                 MBED_CONF_SPIF_DRIVER_SPI_CS);
+
+    int err = block_device.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 = (block_device.*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 = block_device.get_erase_size(addr);
+    unsigned addrwidth = ceil(log(float(block_device.size() - 1)) / log(float(16))) + 1;
+
+    utest_printf("\ntest  %0*llx:%llu...", addrwidth, addr, sector_erase_size);
+
+    //unaligned start address
+    addr += 1;
+    err = block_device.erase(addr, sector_erase_size - 1);
+    TEST_ASSERT_EQUAL(SPIF_BD_ERROR_INVALID_ERASE_PARAMS, err);
+
+    err = block_device.erase(addr, sector_erase_size);
+    TEST_ASSERT_EQUAL(SPIF_BD_ERROR_INVALID_ERASE_PARAMS, err);
+
+    err = block_device.erase(addr, 1);
+    TEST_ASSERT_EQUAL(SPIF_BD_ERROR_INVALID_ERASE_PARAMS, err);
+
+    //unaligned end address
+    addr = 0;
+
+    err = block_device.erase(addr, 1);
+    TEST_ASSERT_EQUAL(SPIF_BD_ERROR_INVALID_ERASE_PARAMS, err);
+
+    err = block_device.erase(addr, sector_erase_size + 1);
+    TEST_ASSERT_EQUAL(SPIF_BD_ERROR_INVALID_ERASE_PARAMS, err);
+
+    //erase size exceeds flash device size
+    err = block_device.erase(addr, block_device.size() + 1);
+    TEST_ASSERT_EQUAL(SPIF_BD_ERROR_INVALID_ERASE_PARAMS, err);
+
+    // Valid erase
+    err = block_device.erase(addr, sector_erase_size);
+    TEST_ASSERT_EQUAL(SPIF_BD_ERROR_OK, err);
+
+    err = block_device.deinit();
+    TEST_ASSERT_EQUAL(0, err);
+}
+
+static void test_spif_thread_job(void *block_device_ptr/*, int thread_num*/)
+{
+    static int thread_num = 0;
+    thread_num++;
+    SPIFBlockDevice *block_device = (SPIFBlockDevice *)block_device_ptr;
+    utest_printf("\n Thread %d Started \n", thread_num);
+
+    bd_size_t block_size = block_device->get_erase_size();
+    unsigned addrwidth = ceil(log(float(block_device->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((*block_device), block_size, write_block, read_block, addrwidth);
+    }
+
+end:
+    delete[] write_block;
+    delete[] read_block;
+}
+
+void test_spif_multi_threads()
+{
+    utest_printf("\nTest Multi Threaded Erase/Program/Read Starts..\n");
+
+    SPIFBlockDevice block_device(MBED_CONF_SPIF_DRIVER_SPI_MOSI, MBED_CONF_SPIF_DRIVER_SPI_MISO,
+                                 MBED_CONF_SPIF_DRIVER_SPI_CLK,
+                                 MBED_CONF_SPIF_DRIVER_SPI_CS);
+
+    int err = block_device.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 = (block_device.*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 spif_bd_thread[SPIF_TEST_NUM_OF_THREADS];
+
+    osStatus threadStatus;
+    int i_ind;
+
+    for (i_ind = 0; i_ind < SPIF_TEST_NUM_OF_THREADS; i_ind++) {
+        threadStatus = spif_bd_thread[i_ind].start(test_spif_thread_job, (void *)&block_device);
+        if (threadStatus != 0) {
+            utest_printf("\n Thread %d Start Failed!", i_ind + 1);
+        }
+    }
+
+    for (i_ind = 0; i_ind < SPIF_TEST_NUM_OF_THREADS; i_ind++) {
+        spif_bd_thread[i_ind].join();
+    }
+
+    err = block_device.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_spif_unaligned_erase),
+    Case("Testing read write random blocks", test_spif_random_program_read_erase),
+    Case("Testing Multi Threads Erase Program Read", test_spif_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/components/storage/blockdevice/COMPONENT_SPIF/mbed_lib.json	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,66 @@
+{
+    "name": "spif-driver",
+    "config": {
+        "SPI_MOSI": "NC",
+        "SPI_MISO": "NC",
+        "SPI_CLK":  "NC",
+        "SPI_CS":   "NC",
+        "SPI_FREQ": "40000000"
+    },
+    "target_overrides": {
+        "K82F": {
+            "SPI_MOSI": "PTE2",
+            "SPI_MISO": "PTE4",
+            "SPI_CLK":  "PTE1",
+            "SPI_CS":   "PTE5"
+        },
+        "LPC54114": {
+            "SPI_MOSI": "P0_20",
+            "SPI_MISO": "P0_18",
+            "SPI_CLK":  "P0_19",
+            "SPI_CS":   "P1_2"
+        },
+        "NRF52840_DK": {
+            "SPI_MOSI": "p20",
+            "SPI_MISO": "p21",
+            "SPI_CLK":  "p19",
+            "SPI_CS":   "p17"
+        },
+        "HEXIWEAR": {
+             "SPI_MOSI": "PTD6",
+             "SPI_MISO": "PTD7",
+             "SPI_CLK":  "PTD5",
+             "SPI_CS":   "PTD4"
+        },
+        "MTB_UBLOX_ODIN_W2": {
+             "SPI_MOSI": "PE_14",
+             "SPI_MISO": "PE_13",
+             "SPI_CLK":  "PE_12",
+             "SPI_CS":   "PE_11"
+        },
+         "MTB_ADV_WISE_1530": {
+             "SPI_MOSI": "PC_3",
+             "SPI_MISO": "PC_2",
+             "SPI_CLK":  "PB_13",
+             "SPI_CS":   "PC_12"            
+       },
+         "MTB_MXCHIP_EMW3166": {
+             "SPI_MOSI": "PB_15",
+             "SPI_MISO": "PB_14",
+             "SPI_CLK":  "PB_13",
+             "SPI_CS":   "PA_10"            
+       },
+         "MTB_USI_WM_BN_BM_22": {
+             "SPI_MOSI": "PC_3",
+             "SPI_MISO": "PC_2",
+             "SPI_CLK":  "PB_13",
+             "SPI_CS":   "PA_6"            
+       },
+         "MTB_ADV_WISE_1570": {
+             "SPI_MOSI": "PA_7",
+             "SPI_MISO": "PA_6",
+             "SPI_CLK":  "PA_5",
+             "SPI_CS":   "PB_12"
+       }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/wifi/esp8266-driver/ESP8266/ESP8266.cpp	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,670 @@
+/* ESP8266 Example
+ * 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.
+ */
+
+#include "ESP8266.h"
+#include "mbed_debug.h"
+#include "nsapi_types.h"
+
+#include <cstring>
+
+#define ESP8266_DEFAULT_BAUD_RATE   115200
+#define ESP8266_ALL_SOCKET_IDS      -1
+
+ESP8266::ESP8266(PinName tx, PinName rx, bool debug)
+    : _serial(tx, rx, ESP8266_DEFAULT_BAUD_RATE), 
+      _parser(&_serial), 
+      _packets(0), 
+      _packets_end(&_packets),
+      _connect_error(0),
+      _fail(false),
+      _closed(false),
+      _socket_open(),
+      _connection_status(NSAPI_STATUS_DISCONNECTED)
+{
+    _serial.set_baud( ESP8266_DEFAULT_BAUD_RATE );
+    _parser.debug_on(debug);
+    _parser.set_delimiter("\r\n");
+    _parser.oob("+IPD", callback(this, &ESP8266::_packet_handler));
+    //Note: espressif at command document says that this should be +CWJAP_CUR:<error code>
+    //but seems that at least current version is not sending it
+    //https://www.espressif.com/sites/default/files/documentation/4a-esp8266_at_instruction_set_en.pdf
+    //Also seems that ERROR is not sent, but FAIL instead
+    _parser.oob("+CWJAP:", callback(this, &ESP8266::_connect_error_handler));
+    _parser.oob("0,CLOSED", callback(this, &ESP8266::_oob_socket0_closed_handler));
+    _parser.oob("1,CLOSED", callback(this, &ESP8266::_oob_socket1_closed_handler));
+    _parser.oob("2,CLOSED", callback(this, &ESP8266::_oob_socket2_closed_handler));
+    _parser.oob("3,CLOSED", callback(this, &ESP8266::_oob_socket3_closed_handler));
+    _parser.oob("4,CLOSED", callback(this, &ESP8266::_oob_socket4_closed_handler));
+    _parser.oob("WIFI ", callback(this, &ESP8266::_connection_status_handler));
+    _parser.oob("UNLINK", callback(this, &ESP8266::_oob_socket_close_error));
+}
+
+int ESP8266::get_firmware_version()
+{
+    int version;
+
+    _smutex.lock();
+    bool done = _parser.send("AT+GMR")
+           && _parser.recv("SDK version:%d", &version)
+           && _parser.recv("OK\n");
+    _smutex.unlock();
+
+    if(done) {
+        return version;
+    } else { 
+        // Older firmware versions do not prefix the version with "SDK version: "
+        return -1;
+    }
+}
+
+bool ESP8266::startup(int mode)
+{
+    if (!(mode == WIFIMODE_STATION || mode == WIFIMODE_SOFTAP
+        || mode == WIFIMODE_STATION_SOFTAP)) {
+        return false;
+    }
+
+    _smutex.lock();
+    setTimeout(ESP8266_CONNECT_TIMEOUT);
+    bool done = _parser.send("AT+CWMODE_CUR=%d", mode)
+            && _parser.recv("OK\n")
+            &&_parser.send("AT+CIPMUX=1")
+            && _parser.recv("OK\n");
+    setTimeout(); //Restore default
+    _smutex.unlock();
+
+    return done;
+}
+
+bool ESP8266::reset(void)
+{
+    _smutex.lock();
+    setTimeout(ESP8266_CONNECT_TIMEOUT);
+
+    for (int i = 0; i < 2; i++) {
+        if (_parser.send("AT+RST")
+            && _parser.recv("OK\n")
+            && _parser.recv("ready")) {
+            _clear_socket_packets(ESP8266_ALL_SOCKET_IDS);
+            _smutex.unlock();
+            return true;
+        }
+    }
+    setTimeout();
+    _smutex.unlock();
+
+    return false;
+}
+
+bool ESP8266::dhcp(bool enabled, int mode)
+{
+    //only 3 valid modes
+    if (mode < 0 || mode > 2) {
+        return false;
+    }
+
+    _smutex.lock();
+    bool done = _parser.send("AT+CWDHCP_CUR=%d,%d", mode, enabled?1:0)
+                && _parser.recv("OK\n");
+    _smutex.unlock();
+
+    return done;
+}
+
+nsapi_error_t ESP8266::connect(const char *ap, const char *passPhrase)
+{
+    _smutex.lock();
+    setTimeout(ESP8266_CONNECT_TIMEOUT);
+    _connection_status = NSAPI_STATUS_CONNECTING;
+    if(_connection_status_cb)
+        _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connection_status);
+
+    _parser.send("AT+CWJAP_CUR=\"%s\",\"%s\"", ap, passPhrase);
+    if (!_parser.recv("OK\n")) {
+        if (_fail) {
+            _smutex.unlock();
+            nsapi_error_t ret;
+            if (_connect_error == 1)
+                ret = NSAPI_ERROR_CONNECTION_TIMEOUT;
+            else if (_connect_error == 2)
+                ret = NSAPI_ERROR_AUTH_FAILURE;
+            else if (_connect_error == 3)
+                ret = NSAPI_ERROR_NO_SSID;
+            else
+                ret = NSAPI_ERROR_NO_CONNECTION;
+
+            _fail = false;
+            _connect_error = 0;
+            return ret;
+        }
+    }
+    setTimeout();
+    _smutex.unlock();
+
+    return NSAPI_ERROR_OK;
+}
+
+bool ESP8266::disconnect(void)
+{
+    _smutex.lock();
+    bool done = _parser.send("AT+CWQAP") && _parser.recv("OK\n");
+    _smutex.unlock();
+
+    return done;
+}
+
+const char *ESP8266::getIPAddress(void)
+{
+    _smutex.lock();
+    setTimeout(ESP8266_CONNECT_TIMEOUT);
+    if (!(_parser.send("AT+CIFSR")
+        && _parser.recv("+CIFSR:STAIP,\"%15[^\"]\"", _ip_buffer)
+        && _parser.recv("OK\n"))) {
+        _smutex.unlock();
+        return 0;
+    }
+    setTimeout();
+    _smutex.unlock();
+
+    return _ip_buffer;
+}
+
+const char *ESP8266::getMACAddress(void)
+{
+    _smutex.lock();
+    if (!(_parser.send("AT+CIFSR")
+        && _parser.recv("+CIFSR:STAMAC,\"%17[^\"]\"", _mac_buffer)
+        && _parser.recv("OK\n"))) {
+        _smutex.unlock();
+        return 0;
+    }
+    _smutex.unlock();
+
+    return _mac_buffer;
+}
+
+const char *ESP8266::getGateway()
+{
+    _smutex.lock();
+    if (!(_parser.send("AT+CIPSTA_CUR?")
+        && _parser.recv("+CIPSTA_CUR:gateway:\"%15[^\"]\"", _gateway_buffer)
+        && _parser.recv("OK\n"))) {
+        _smutex.unlock();
+        return 0;
+    }
+    _smutex.unlock();
+
+    return _gateway_buffer;
+}
+
+const char *ESP8266::getNetmask()
+{
+    _smutex.lock();
+    if (!(_parser.send("AT+CIPSTA_CUR?")
+        && _parser.recv("+CIPSTA_CUR:netmask:\"%15[^\"]\"", _netmask_buffer)
+        && _parser.recv("OK\n"))) {
+        _smutex.unlock();
+        return 0;
+    }
+    _smutex.unlock();
+
+    return _netmask_buffer;
+}
+
+int8_t ESP8266::getRSSI()
+{
+    int8_t rssi;
+    char bssid[18];
+
+    _smutex.lock();
+    setTimeout(ESP8266_CONNECT_TIMEOUT);
+    if (!(_parser.send("AT+CWJAP_CUR?")
+        && _parser.recv("+CWJAP_CUR:\"%*[^\"]\",\"%17[^\"]\"", bssid)
+        && _parser.recv("OK\n"))) {
+       _smutex.unlock();
+        return 0;
+    }
+    setTimeout();
+   _smutex.unlock();
+
+   _smutex.lock();
+   setTimeout(ESP8266_CONNECT_TIMEOUT);
+    if (!(_parser.send("AT+CWLAP=\"\",\"%s\",", bssid)
+        && _parser.recv("+CWLAP:(%*d,\"%*[^\"]\",%hhd,", &rssi)
+        && _parser.recv("OK\n"))) {
+        _smutex.unlock();
+        return 0;
+    }
+    setTimeout();
+    _smutex.unlock();
+
+    return rssi;
+}
+
+int ESP8266::scan(WiFiAccessPoint *res, unsigned limit)
+{
+    unsigned cnt = 0;
+    nsapi_wifi_ap_t ap;
+
+    _smutex.lock();
+    setTimeout(ESP8266_CONNECT_TIMEOUT);
+
+    if (!_parser.send("AT+CWLAP")) {
+        _smutex.unlock();
+        return NSAPI_ERROR_DEVICE_ERROR;
+    }
+
+    while (recv_ap(&ap)) {
+        if (cnt < limit) {
+            res[cnt] = WiFiAccessPoint(ap);
+        }
+
+        cnt++;
+        if (limit != 0 && cnt >= limit) {
+            break;
+        }
+    }
+    setTimeout();
+    _smutex.unlock();
+
+    return cnt;
+}
+
+nsapi_error_t ESP8266::open_udp(int id, const char* addr, int port, int local_port)
+{
+    static const char *type = "UDP";
+    bool done = false;
+
+    if (id >= SOCKET_COUNT) {
+        return NSAPI_ERROR_PARAMETER;
+    } else if (_socket_open[id]) {
+        return NSAPI_ERROR_IS_CONNECTED;
+    }
+
+    _smutex.lock();
+    if(local_port) {
+        done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d,%d", id, type, addr, port, local_port)
+                && _parser.recv("OK\n");
+    } else {
+        done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d", id, type, addr, port)
+               && _parser.recv("OK\n");
+    }
+
+    if (done) {
+        _socket_open[id] = 1;
+    }
+
+    _clear_socket_packets(id);
+
+    _smutex.unlock();
+
+    return done ? NSAPI_ERROR_OK : NSAPI_ERROR_DEVICE_ERROR;
+}
+
+bool ESP8266::open_tcp(int id, const char* addr, int port, int keepalive)
+{
+    static const char *type = "TCP";
+    bool done = false;
+
+    if (id >= SOCKET_COUNT || _socket_open[id]) {
+        return false;
+    }
+
+    _smutex.lock();
+    if(keepalive) {
+        done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d,%d", id, type, addr, port, keepalive)
+                && _parser.recv("OK\n");
+    } else {
+        done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d", id, type, addr, port)
+               && _parser.recv("OK\n");
+    }
+
+    if (done) {
+        _socket_open[id] = 1;
+    }
+
+    _clear_socket_packets(id);
+
+    _smutex.unlock();
+
+    return done;
+}
+
+bool ESP8266::dns_lookup(const char* name, char* ip)
+{
+    _smutex.lock();
+    bool done = _parser.send("AT+CIPDOMAIN=\"%s\"", name) && _parser.recv("+CIPDOMAIN:%s%*[\r]%*[\n]", ip);
+    _smutex.unlock();
+
+    return done;
+}
+
+nsapi_error_t ESP8266::send(int id, const void *data, uint32_t amount)
+{
+    //May take a second try if device is busy
+    for (unsigned i = 0; i < 2; i++) {
+        _smutex.lock();
+        setTimeout(ESP8266_SEND_TIMEOUT);
+        if (_parser.send("AT+CIPSEND=%d,%lu", id, amount)
+            && _parser.recv(">")
+            && _parser.write((char*)data, (int)amount) >= 0) {
+            while (_parser.process_oob()); // multiple sends in a row require this
+            _smutex.unlock();
+            return NSAPI_ERROR_OK;
+        }
+        setTimeout();
+        _smutex.unlock();
+    }
+
+    return NSAPI_ERROR_DEVICE_ERROR;
+}
+
+void ESP8266::_packet_handler()
+{
+    int id;
+    int amount;
+
+    // parse out the packet
+    if (!_parser.recv(",%d,%d:", &id, &amount)) {
+        return;
+    }
+
+    struct packet *packet = (struct packet*)malloc(
+            sizeof(struct packet) + amount);
+    if (!packet) {
+        debug("ESP8266: could not allocate memory for RX data\n");
+        return;
+    }
+
+    packet->id = id;
+    packet->len = amount;
+    packet->next = 0;
+
+    if (_parser.read((char*)(packet + 1), amount) < amount) {
+        free(packet);
+        return;
+    }
+
+    // append to packet list
+    *_packets_end = packet;
+    _packets_end = &packet->next;
+}
+
+int32_t ESP8266::recv_tcp(int id, void *data, uint32_t amount, uint32_t timeout)
+{
+    _smutex.lock();
+    setTimeout(timeout);
+
+    // Poll for inbound packets
+    while (_parser.process_oob()) {
+    }
+
+    setTimeout();
+
+    // check if any packets are ready for us
+    for (struct packet **p = &_packets; *p; p = &(*p)->next) {
+        if ((*p)->id == id) {
+            struct packet *q = *p;
+
+            if (q->len <= amount) { // Return and remove full packet
+                memcpy(data, q+1, q->len);
+
+                if (_packets_end == &(*p)->next) {
+                    _packets_end = p;
+                }
+                *p = (*p)->next;
+                _smutex.unlock();
+
+                uint32_t len = q->len;
+                free(q);
+                return len;
+            } else { // return only partial packet
+                memcpy(data, q+1, amount);
+
+                q->len -= amount;
+                memmove(q+1, (uint8_t*)(q+1) + amount, q->len);
+
+                _smutex.unlock();
+                return amount;
+            }
+        }
+    }
+    if(!_socket_open[id]) {
+        _smutex.unlock();
+        return 0;
+    }
+    _smutex.unlock();
+
+    return NSAPI_ERROR_WOULD_BLOCK;
+}
+
+int32_t ESP8266::recv_udp(int id, void *data, uint32_t amount, uint32_t timeout)
+{
+    _smutex.lock();
+    setTimeout(timeout);
+
+    // Poll for inbound packets
+    while (_parser.process_oob()) {
+    }
+
+    setTimeout();
+
+    // check if any packets are ready for us
+    for (struct packet **p = &_packets; *p; p = &(*p)->next) {
+        if ((*p)->id == id) {
+            struct packet *q = *p;
+
+            // Return and remove packet (truncated if necessary)
+            uint32_t len = q->len < amount ? q->len : amount;
+            memcpy(data, q+1, len);
+
+            if (_packets_end == &(*p)->next) {
+                _packets_end = p;
+            }
+            *p = (*p)->next;
+            _smutex.unlock();
+
+            free(q);
+            return len;
+        }
+    }
+    _smutex.unlock();
+
+    return NSAPI_ERROR_WOULD_BLOCK;
+}
+
+void ESP8266::_clear_socket_packets(int id)
+{
+    struct packet **p = &_packets;
+
+    while (*p) {
+        if ((*p)->id == id || id == ESP8266_ALL_SOCKET_IDS) {
+            struct packet *q = *p;
+
+            if (_packets_end == &(*p)->next) {
+                _packets_end = p; // Set last packet next field/_packets
+            }
+            *p = (*p)->next;
+
+            free(q);
+        } else {
+            // Point to last packet next field
+            p = &(*p)->next;
+        }
+    }
+}
+
+bool ESP8266::close(int id)
+{
+    //May take a second try if device is busy
+    for (unsigned i = 0; i < 2; i++) {
+        _smutex.lock();
+        if (_parser.send("AT+CIPCLOSE=%d", id)) {
+            if (!_parser.recv("OK\n")) {
+                if (_closed) { // UNLINK ERROR
+                    _closed = false;
+                    _socket_open[id] = 0;
+                    _clear_socket_packets(id);
+                    _smutex.unlock();
+                    // ESP8266 has a habit that it might close a socket on its own.
+                    //debug("ESP8266: socket %d already closed when calling close\n", id);
+                    return true;
+                }
+            } else {
+                _clear_socket_packets(id);
+                _smutex.unlock();
+                return true;
+            }
+        }
+        _smutex.unlock();
+    }
+
+    return false;
+}
+
+void ESP8266::setTimeout(uint32_t timeout_ms)
+{
+    _parser.set_timeout(timeout_ms);
+}
+
+bool ESP8266::readable()
+{
+    return _serial.FileHandle::readable();
+}
+
+bool ESP8266::writeable()
+{
+    return _serial.FileHandle::writable();
+}
+
+void ESP8266::sigio(Callback<void()> func)
+{
+    _serial.sigio(func);
+}
+
+void ESP8266::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
+{
+    _connection_status_cb = status_cb;
+}
+
+bool ESP8266::recv_ap(nsapi_wifi_ap_t *ap)
+{
+    int sec;
+    int dummy;
+    bool ret = _parser.recv("+CWLAP:(%d,\"%32[^\"]\",%hhd,\"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\",%hhu,%d,%d)\n",
+            &sec,
+            ap->ssid,
+            &ap->rssi,
+            &ap->bssid[0], &ap->bssid[1], &ap->bssid[2], &ap->bssid[3], &ap->bssid[4], &ap->bssid[5],
+            &ap->channel,
+            &dummy,
+            &dummy);
+
+    ap->security = sec < 5 ? (nsapi_security_t)sec : NSAPI_SECURITY_UNKNOWN;
+
+    return ret;
+}
+
+void ESP8266::_connect_error_handler()
+{
+    _fail = false;
+    _connect_error = 0;
+
+    if (_parser.recv("%d", &_connect_error) && _parser.recv("FAIL")) {
+        _fail = true;
+        _parser.abort();
+    }
+}
+
+void ESP8266::_oob_socket_close_error()
+{
+    if (_parser.recv("ERROR\n")) {
+        _closed = true; // Not possible to pinpoint to a certain socket
+        _parser.abort();
+    }
+}
+
+void ESP8266::_oob_socket0_closed_handler()
+{
+    _socket_open[0] = 0;
+}
+
+void ESP8266::_oob_socket1_closed_handler()
+{
+    _socket_open[1] = 0;
+}
+
+void ESP8266::_oob_socket2_closed_handler()
+{
+    _socket_open[2] = 0;
+}
+
+void ESP8266::_oob_socket3_closed_handler()
+{
+    _socket_open[3] = 0;
+}
+
+void ESP8266::_oob_socket4_closed_handler()
+{
+    _socket_open[4] = 0;
+}
+
+void ESP8266::_connection_status_handler()
+{
+    char status[13];
+    if (_parser.recv("%12[^\"]\n", status)) {
+        if (strcmp(status, "GOT IP\n") == 0)
+            _connection_status = NSAPI_STATUS_GLOBAL_UP;
+        else if (strcmp(status, "DISCONNECT\n") == 0)
+            _connection_status = NSAPI_STATUS_DISCONNECTED;
+        else
+            return;
+
+        if(_connection_status_cb)
+            _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connection_status);
+    }
+}
+
+int8_t ESP8266::get_default_wifi_mode()
+{
+    int8_t mode;
+
+    _smutex.lock();
+    if (_parser.send("AT+CWMODE_DEF?")
+        && _parser.recv("+CWMODE_DEF:%hhd", &mode)
+        && _parser.recv("OK\n")) {
+        _smutex.unlock();
+        return mode;
+    }
+    _smutex.unlock();
+
+    return 0;
+}
+
+bool ESP8266::set_default_wifi_mode(const int8_t mode)
+{
+    _smutex.lock();
+    bool done = _parser.send("AT+CWMODE_DEF=%hhd", mode)
+                && _parser.recv("OK\n");
+    _smutex.unlock();
+
+    return done;
+}
+
+nsapi_connection_status_t ESP8266::get_connection_status() const
+{
+    return _connection_status;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/wifi/esp8266-driver/ESP8266/ESP8266.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,309 @@
+/* ESP8266Interface Example
+ * 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.
+ */
+
+#ifndef ESP8266_H
+#define ESP8266_H
+
+#include "ATCmdParser.h"
+#include "nsapi_types.h"
+#include "rtos.h"
+
+// Various timeouts for different ESP8266 operations
+#ifndef ESP8266_CONNECT_TIMEOUT
+#define ESP8266_CONNECT_TIMEOUT 15000
+#endif
+#ifndef ESP8266_SEND_TIMEOUT
+#define ESP8266_SEND_TIMEOUT    2000
+#endif
+#ifndef ESP8266_RECV_TIMEOUT
+#define ESP8266_RECV_TIMEOUT    2000
+#endif
+#ifndef ESP8266_MISC_TIMEOUT
+#define ESP8266_MISC_TIMEOUT    2000
+#endif
+
+/** ESP8266Interface class.
+    This is an interface to a ESP8266 radio.
+ */
+class ESP8266
+{
+public:
+    ESP8266(PinName tx, PinName rx, bool debug=false);
+
+    /**
+    * Check firmware version of ESP8266
+    *
+    * @return integer firmware version or -1 if firmware query command gives outdated response
+    */
+    int get_firmware_version(void);
+    
+    /**
+    * Startup the ESP8266
+    *
+    * @param mode mode of WIFI 1-client, 2-host, 3-both
+    * @return true only if ESP8266 was setup correctly
+    */
+    bool startup(int mode);
+
+    /**
+    * Reset ESP8266
+    *
+    * @return true only if ESP8266 resets successfully
+    */
+    bool reset(void);
+
+    /**
+    * Enable/Disable DHCP
+    *
+    * @param enabled DHCP enabled when true
+    * @param mode mode of DHCP 0-softAP, 1-station, 2-both
+    * @return true only if ESP8266 enables/disables DHCP successfully
+    */
+    bool dhcp(bool enabled, int mode);
+
+    /**
+    * Connect ESP8266 to AP
+    *
+    * @param ap the name of the AP
+    * @param passPhrase the password of AP
+    * @return NSAPI_ERROR_OK only if ESP8266 is connected successfully
+    */
+    nsapi_error_t connect(const char *ap, const char *passPhrase);
+
+    /**
+    * Disconnect ESP8266 from AP
+    *
+    * @return true only if ESP8266 is disconnected successfully
+    */
+    bool disconnect(void);
+
+    /**
+    * Get the IP address of ESP8266
+    *
+    * @return null-teriminated IP address or null if no IP address is assigned
+    */
+    const char *getIPAddress(void);
+
+    /**
+    * Get the MAC address of ESP8266
+    *
+    * @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();
+
+    /** 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
+    * @param port the port on the destination
+    * @param local_port UDP socket's local port, zero means any
+    * @return true only if socket opened successfully
+    */
+    nsapi_error_t open_udp(int id, const char* addr, int port, int local_port = 0);
+
+    /**
+    * 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
+    * @param port the port on the destination
+    * @param tcp_keepalive TCP connection's keep alive time, zero means disabled
+    * @return true only if socket opened successfully
+    */
+    bool open_tcp(int id, const char* addr, int port, int keepalive = 0);
+
+    /**
+    * 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 NSAPI_ERROR_OK in success, negative error code in failure
+    */
+    nsapi_error_t send(int id, const void *data, uint32_t amount);
+
+    /**
+    * Receives datagram from an open UDP 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_udp(int id, void *data, uint32_t amount, uint32_t timeout=ESP8266_RECV_TIMEOUT);
+
+    /**
+    * Receives stream data from an open TCP 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_tcp(int id, void *data, uint32_t amount, uint32_t timeout=ESP8266_RECV_TIMEOUT);
+
+    /**
+    * 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);
+
+    /**
+    * Allows timeout to be changed between commands
+    *
+    * @param timeout_ms timeout of the connection
+    */
+    void setTimeout(uint32_t timeout_ms=ESP8266_MISC_TIMEOUT);
+
+    /**
+    * Checks if data is available
+    */
+    bool readable();
+
+    /**
+    * Checks if data can be written
+    */
+    bool writeable();
+
+    /**
+    * Attach a function to call whenever sigio happens in the serial
+    *
+    * @param func A pointer to a void function, or 0 to set as none
+    */
+    void sigio(Callback<void()> func);
+
+    /**
+    * Attach a function to call whenever sigio happens in the serial
+    *
+    * @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 sigio(T *obj, M method) {
+        sigio(Callback<void()>(obj, method));
+    }
+
+    /**
+    * 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(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb);
+
+    /**
+     * Read default Wifi mode from flash
+     *
+     * return Station, SoftAP or SoftAP+Station - 0 on failure
+     */
+    int8_t get_default_wifi_mode();
+
+    /**
+     * Write default Wifi mode to flash
+     */
+    bool set_default_wifi_mode(const int8_t mode);
+
+    /** Get the connection status
+     *
+     *  @return         The connection status according to ConnectionStatusType
+     */
+    nsapi_connection_status_t get_connection_status() const;
+
+    static const int8_t WIFIMODE_STATION = 1;
+    static const int8_t WIFIMODE_SOFTAP = 2;
+    static const int8_t WIFIMODE_STATION_SOFTAP = 3;
+    static const int8_t SOCKET_COUNT = 5;
+
+private:
+    UARTSerial _serial;
+    ATCmdParser _parser;
+    Mutex _smutex; // Protect serial port access
+
+    struct packet {
+        struct packet *next;
+        int id;
+        uint32_t len;
+        // data follows
+    } *_packets, **_packets_end;
+    void _packet_handler();
+    void _connect_error_handler();
+    bool recv_ap(nsapi_wifi_ap_t *ap);
+    void _oob_socket0_closed_handler();
+    void _oob_socket1_closed_handler();
+    void _oob_socket2_closed_handler();
+    void _oob_socket3_closed_handler();
+    void _oob_socket4_closed_handler();
+    void _connection_status_handler();
+    void _oob_socket_close_error();
+    void _clear_socket_packets(int id);
+
+    char _ip_buffer[16];
+    char _gateway_buffer[16];
+    char _netmask_buffer[16];
+    char _mac_buffer[18];
+
+    int _connect_error;
+    bool _fail;
+    bool _closed;
+    int _socket_open[SOCKET_COUNT];
+    nsapi_connection_status_t _connection_status;
+    Callback<void(nsapi_event_t, intptr_t)> _connection_status_cb;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/wifi/esp8266-driver/ESP8266Interface.cpp	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,586 @@
+/* ESP8266 implementation of NetworkInterfaceAPI
+ * 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.
+ */
+
+#include <cstring>
+#include "ESP8266.h"
+#include "ESP8266Interface.h"
+#include "mbed_debug.h"
+#include "nsapi_types.h"
+
+
+#ifndef MBED_CONF_ESP8266_TX
+#ifdef TARGET_FF_ARDUINO
+#define MBED_CONF_ESP8266_TX D1
+#else
+#define MBED_CONF_ESP8266_TX NC
+#endif
+#endif
+
+#ifndef MBED_CONF_ESP8266_RX
+#ifdef TARGET_FF_ARDUINO
+#define MBED_CONF_ESP8266_RX D0
+#else
+#define MBED_CONF_ESP8266_RX NC
+#endif
+#endif
+
+// Firmware version
+#define ESP8266_VERSION 2
+
+ESP8266Interface::ESP8266Interface()
+    : _esp(MBED_CONF_ESP8266_TX, MBED_CONF_ESP8266_RX, MBED_CONF_ESP8266_DEBUG),
+      _initialized(false),
+      _started(false)
+{
+    memset(_ids, 0, sizeof(_ids));
+    memset(_cbs, 0, sizeof(_cbs));
+    memset(ap_ssid, 0, sizeof(ap_ssid));
+    memset(ap_pass, 0, sizeof(ap_pass));
+    memset(_local_ports, 0, sizeof(_local_ports));
+    ap_sec = NSAPI_SECURITY_UNKNOWN;
+
+    _esp.sigio(this, &ESP8266Interface::event);
+    _esp.setTimeout();
+}
+
+// ESP8266Interface implementation
+ESP8266Interface::ESP8266Interface(PinName tx, PinName rx, bool debug)
+    : _esp(tx, rx, debug),
+      _initialized(false),
+      _started(false)
+{
+    memset(_ids, 0, sizeof(_ids));
+    memset(_cbs, 0, sizeof(_cbs));
+    memset(ap_ssid, 0, sizeof(ap_ssid));
+    memset(ap_pass, 0, sizeof(ap_pass));
+    memset(_local_ports, 0, sizeof(_local_ports));
+    ap_sec = NSAPI_SECURITY_UNKNOWN;
+
+    _esp.sigio(this, &ESP8266Interface::event);
+    _esp.setTimeout();
+}
+
+int ESP8266Interface::connect(const char *ssid, const char *pass, nsapi_security_t security,
+                                        uint8_t channel)
+{
+    if (channel != 0) {
+        return NSAPI_ERROR_UNSUPPORTED;
+    }
+
+    int err = set_credentials(ssid, pass, security);
+    if(err) {
+        return err;
+    }
+
+    return connect();
+}
+
+int ESP8266Interface::connect()
+{
+    nsapi_error_t status;
+
+    if (strlen(ap_ssid) == 0) {
+        return NSAPI_ERROR_NO_SSID;
+    }
+
+    if (ap_sec != NSAPI_SECURITY_NONE) {
+        if (strlen(ap_pass) < ESP8266_PASSPHRASE_MIN_LENGTH) {
+            return NSAPI_ERROR_PARAMETER;
+        }
+    }
+
+    status = _init();
+    if(status != NSAPI_ERROR_OK) {
+        return status;
+    }
+
+    if(get_ip_address()) {
+        return NSAPI_ERROR_IS_CONNECTED;
+    }
+
+    status = _startup(ESP8266::WIFIMODE_STATION);
+    if(status != NSAPI_ERROR_OK) {
+        return status;
+    }
+    _started = true;
+
+    if (!_esp.dhcp(true, 1)) {
+        return NSAPI_ERROR_DHCP_FAILURE;
+    }
+
+    int connect_error = _esp.connect(ap_ssid, ap_pass);
+    if (connect_error) {
+        return connect_error;
+    }
+
+    if (!get_ip_address()) {
+        return NSAPI_ERROR_DHCP_FAILURE;
+    }
+
+    return NSAPI_ERROR_OK;
+}
+
+int ESP8266Interface::set_credentials(const char *ssid, const char *pass, nsapi_security_t security)
+{
+    ap_sec = security;
+
+    if (!ssid) {
+        return NSAPI_ERROR_PARAMETER;
+    }
+
+    int ssid_length = strlen(ssid);
+
+    if (ssid_length > 0
+        && ssid_length <= ESP8266_SSID_MAX_LENGTH) {
+        memset(ap_ssid, 0, sizeof(ap_ssid));
+        strncpy(ap_ssid, ssid, sizeof(ap_ssid));
+    } else {
+        return NSAPI_ERROR_PARAMETER;
+    }
+
+    if (ap_sec != NSAPI_SECURITY_NONE) {
+
+        if (!pass) {
+            return NSAPI_ERROR_PARAMETER;
+        }
+
+        int pass_length = strlen(pass);
+        if (pass_length >= ESP8266_PASSPHRASE_MIN_LENGTH
+            && pass_length <= ESP8266_PASSPHRASE_MAX_LENGTH ) {
+            memset(ap_pass, 0, sizeof(ap_pass));
+            strncpy(ap_pass, pass, sizeof(ap_pass));
+        } else {
+            return NSAPI_ERROR_PARAMETER;
+        }
+    } else {
+        memset(ap_pass, 0, sizeof(ap_pass));
+    }
+
+    return NSAPI_ERROR_OK;
+}
+
+int ESP8266Interface::set_channel(uint8_t channel)
+{
+    return NSAPI_ERROR_UNSUPPORTED;
+}
+
+
+int ESP8266Interface::disconnect()
+{
+    _started = false;
+    _initialized = false;
+
+    return _esp.disconnect() ? NSAPI_ERROR_OK : NSAPI_ERROR_DEVICE_ERROR;
+}
+
+const char *ESP8266Interface::get_ip_address()
+{
+    if(!_started) {
+        return NULL;
+    }
+
+    const char *ip_buff = _esp.getIPAddress();
+    if(!ip_buff || std::strcmp(ip_buff, "0.0.0.0") == 0) {
+        return NULL;
+    }
+
+    return ip_buff;
+}
+
+const char *ESP8266Interface::get_mac_address()
+{
+    return _esp.getMACAddress();
+}
+
+const char *ESP8266Interface::get_gateway()
+{
+    return _started ? _esp.getGateway() : NULL;
+}
+
+const char *ESP8266Interface::get_netmask()
+{
+    return _started ? _esp.getNetmask() : NULL;
+}
+
+int8_t ESP8266Interface::get_rssi()
+{
+    return _started ? _esp.getRSSI() : 0;
+}
+
+int ESP8266Interface::scan(WiFiAccessPoint *res, unsigned count)
+{
+    nsapi_error_t status;
+
+    status = _init();
+    if(status != NSAPI_ERROR_OK) {
+        return status;
+    }
+
+    status = _startup(ESP8266::WIFIMODE_STATION);
+    if(status != NSAPI_ERROR_OK) {
+        return status;
+    }
+
+    return _esp.scan(res, count);
+}
+
+bool ESP8266Interface::_get_firmware_ok()
+{
+    if (_esp.get_firmware_version() != ESP8266_VERSION) {
+        debug("ESP8266: ERROR: Firmware incompatible with this driver.\
+               \r\nUpdate to v%d - https://developer.mbed.org/teams/ESP8266/wiki/Firmware-Update\r\n",ESP8266_VERSION);
+        return false;
+    }
+
+    return true;
+}
+
+bool ESP8266Interface::_disable_default_softap()
+{
+    static int disabled = false;
+
+    if (disabled || _esp.get_default_wifi_mode() == ESP8266::WIFIMODE_STATION) {
+        disabled = true;
+        return true;
+    }
+    if (_esp.set_default_wifi_mode(ESP8266::WIFIMODE_STATION)) {
+        disabled = true;
+        return true;
+    }
+
+    return false;
+}
+
+nsapi_error_t ESP8266Interface::_init(void)
+{
+    if (!_initialized) {
+        if (!_esp.reset()) {
+            return NSAPI_ERROR_DEVICE_ERROR;
+        }
+        if (!_get_firmware_ok()) {
+            return NSAPI_ERROR_DEVICE_ERROR;
+        }
+        if (_disable_default_softap() == false) {
+            return NSAPI_ERROR_DEVICE_ERROR;
+        }
+        _initialized = true;
+    }
+    return NSAPI_ERROR_OK;
+}
+
+nsapi_error_t ESP8266Interface::_startup(const int8_t wifi_mode)
+{
+    if (!_started) {
+        if (!_esp.startup(wifi_mode)) {
+            return NSAPI_ERROR_DEVICE_ERROR;
+        }
+    }
+    return NSAPI_ERROR_OK;
+}
+
+struct esp8266_socket {
+    int id;
+    nsapi_protocol_t proto;
+    bool connected;
+    SocketAddress addr;
+    int keepalive; // TCP
+};
+
+int ESP8266Interface::socket_open(void **handle, nsapi_protocol_t proto)
+{
+    // Look for an unused socket
+    int id = -1;
+
+    for (int i = 0; i < ESP8266_SOCKET_COUNT; i++) {
+        if (!_ids[i]) {
+            id = i;
+            _ids[i] = true;
+            break;
+        }
+    }
+
+    if (id == -1) {
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+
+    struct esp8266_socket *socket = new struct esp8266_socket;
+    if (!socket) {
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+
+    socket->id = id;
+    socket->proto = proto;
+    socket->connected = false;
+    socket->keepalive = 0;
+    *handle = socket;
+    return 0;
+}
+
+int ESP8266Interface::socket_close(void *handle)
+{
+    struct esp8266_socket *socket = (struct esp8266_socket *)handle;
+    int err = 0;
+
+    if (!socket) {
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+
+    if (socket->connected && !_esp.close(socket->id)) {
+        err = NSAPI_ERROR_DEVICE_ERROR;
+    }
+
+    socket->connected = false;
+    _ids[socket->id] = false;
+    _local_ports[socket->id] = 0;
+    delete socket;
+    return err;
+}
+
+int ESP8266Interface::socket_bind(void *handle, const SocketAddress &address)
+{
+    struct esp8266_socket *socket = (struct esp8266_socket *)handle;
+
+    if (!socket) {
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+
+    if (socket->proto == NSAPI_UDP) {
+        if(address.get_addr().version != NSAPI_UNSPEC) {
+            return NSAPI_ERROR_UNSUPPORTED;
+        }
+
+        for(int id = 0; id < ESP8266_SOCKET_COUNT; id++) {
+            if(_local_ports[id] == address.get_port() && id != socket->id) { // Port already reserved by another socket
+                return NSAPI_ERROR_PARAMETER;
+            } else if (id == socket->id && socket->connected) {
+                return NSAPI_ERROR_PARAMETER;
+            }
+        }
+        _local_ports[socket->id] = address.get_port();
+        return 0;
+    }
+
+    return NSAPI_ERROR_UNSUPPORTED;
+}
+
+int ESP8266Interface::socket_listen(void *handle, int backlog)
+{
+    return NSAPI_ERROR_UNSUPPORTED;
+}
+
+int ESP8266Interface::socket_connect(void *handle, const SocketAddress &addr)
+{
+    struct esp8266_socket *socket = (struct esp8266_socket *)handle;
+    nsapi_error_t ret;
+
+    if (!socket) {
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+
+    if (socket->proto == NSAPI_UDP) {
+        ret = _esp.open_udp(socket->id, addr.get_ip_address(), addr.get_port(), _local_ports[socket->id]);
+        if (ret != NSAPI_ERROR_OK) {
+            return ret;
+        }
+    } else {
+        if (!_esp.open_tcp(socket->id, addr.get_ip_address(), addr.get_port(), socket->keepalive)) {
+            return NSAPI_ERROR_DEVICE_ERROR;
+        }
+    }
+
+    socket->connected = true;
+    return 0;
+}
+
+int ESP8266Interface::socket_accept(void *server, void **socket, SocketAddress *addr)
+{
+    return NSAPI_ERROR_UNSUPPORTED;
+}
+
+int ESP8266Interface::socket_send(void *handle, const void *data, unsigned size)
+{
+    nsapi_error_t status;
+    struct esp8266_socket *socket = (struct esp8266_socket *)handle;
+
+    if (!socket) {
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+
+    status = _esp.send(socket->id, data, size);
+
+    return status != NSAPI_ERROR_OK ? status : size;
+}
+
+int ESP8266Interface::socket_recv(void *handle, void *data, unsigned size)
+{
+    struct esp8266_socket *socket = (struct esp8266_socket *)handle;
+
+    if (!socket) {
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+
+    int32_t recv;
+    if (socket->proto == NSAPI_TCP) {
+        recv = _esp.recv_tcp(socket->id, data, size);
+        if (recv <= 0 && recv != NSAPI_ERROR_WOULD_BLOCK) {
+            socket->connected = false;
+        }
+    } else {
+        recv = _esp.recv_udp(socket->id, data, size);
+    }
+
+    return recv;
+}
+
+int ESP8266Interface::socket_sendto(void *handle, const SocketAddress &addr, const void *data, unsigned size)
+{
+    struct esp8266_socket *socket = (struct esp8266_socket *)handle;
+
+    if (!socket) {
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+
+    if((strcmp(addr.get_ip_address(), "0.0.0.0") == 0) || !addr.get_port())  {
+        return NSAPI_ERROR_DNS_FAILURE;
+    }
+
+    if (socket->connected && socket->addr != addr) {
+        if (!_esp.close(socket->id)) {
+            return NSAPI_ERROR_DEVICE_ERROR;
+        }
+        socket->connected = false;
+    }
+
+    if (!socket->connected) {
+        int err = socket_connect(socket, addr);
+        if (err < 0) {
+            return err;
+        }
+        socket->addr = addr;
+    }
+
+    return socket_send(socket, data, size);
+}
+
+int ESP8266Interface::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size)
+{
+    struct esp8266_socket *socket = (struct esp8266_socket *)handle;
+
+    if (!socket) {
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+
+    int ret = socket_recv(socket, data, size);
+    if (ret >= 0 && addr) {
+        *addr = socket->addr;
+    }
+
+    return ret;
+}
+
+void ESP8266Interface::socket_attach(void *handle, void (*callback)(void *), void *data)
+{
+    struct esp8266_socket *socket = (struct esp8266_socket *)handle;
+    _cbs[socket->id].callback = callback;
+    _cbs[socket->id].data = data;
+}
+
+nsapi_error_t ESP8266Interface::setsockopt(nsapi_socket_t handle, int level,
+        int optname, const void *optval, unsigned optlen)
+{
+    struct esp8266_socket *socket = (struct esp8266_socket *)handle;
+
+    if (!optlen) {
+        return NSAPI_ERROR_PARAMETER;
+    } else if (!socket) {
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+
+    if (level == NSAPI_SOCKET && socket->proto == NSAPI_TCP) {
+        switch (optname) {
+            case NSAPI_KEEPALIVE: {
+                if(socket->connected) {// ESP8266 limitation, keepalive needs to be given before connecting
+                    return NSAPI_ERROR_UNSUPPORTED;
+                }
+
+                if (optlen == sizeof(int)) {
+                    int secs = *(int *)optval;
+                    if (secs  >= 0 && secs <= 7200) {
+                        socket->keepalive = secs;
+                        return NSAPI_ERROR_OK;
+                    }
+                }
+                return NSAPI_ERROR_PARAMETER;
+            }
+        }
+    }
+
+    return NSAPI_ERROR_UNSUPPORTED;
+}
+
+nsapi_error_t ESP8266Interface::getsockopt(nsapi_socket_t handle, int level, int optname, void *optval, unsigned *optlen)
+{
+    struct esp8266_socket *socket = (struct esp8266_socket *)handle;
+
+    if (!optval || !optlen) {
+        return NSAPI_ERROR_PARAMETER;
+    } else if (!socket) {
+        return NSAPI_ERROR_NO_SOCKET;
+    }
+
+    if (level == NSAPI_SOCKET && socket->proto == NSAPI_TCP) {
+        switch (optname) {
+            case NSAPI_KEEPALIVE: {
+                if(*optlen > sizeof(int)) {
+                    *optlen = sizeof(int);
+                }
+                memcpy(optval, &(socket->keepalive), *optlen);
+                return NSAPI_ERROR_OK;
+            }
+        }
+    }
+
+    return NSAPI_ERROR_UNSUPPORTED;
+}
+
+
+void ESP8266Interface::event()
+{
+    for (int i = 0; i < ESP8266_SOCKET_COUNT; i++) {
+        if (_cbs[i].callback) {
+            _cbs[i].callback(_cbs[i].data);
+        }
+    }
+}
+
+void ESP8266Interface::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
+{
+    _esp.attach(status_cb);
+}
+
+nsapi_connection_status_t ESP8266Interface::get_connection_status() const
+{
+    return _esp.get_connection_status();
+}
+
+#if MBED_CONF_ESP8266_PROVIDE_DEFAULT
+
+WiFiInterface *WiFiInterface::get_default_instance() {
+    static ESP8266Interface esp;
+    return &esp;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/wifi/esp8266-driver/ESP8266Interface.h	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,322 @@
+/* ESP8266 implementation of NetworkInterfaceAPI
+ * 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.
+ */
+
+#ifndef ESP8266_INTERFACE_H
+#define ESP8266_INTERFACE_H
+
+#include "mbed.h"
+#include "ESP8266.h"
+
+
+#define ESP8266_SOCKET_COUNT 5
+
+/** ESP8266Interface class
+ *  Implementation of the NetworkStack for the ESP8266
+ */
+class ESP8266Interface : public NetworkStack, public WiFiInterface
+{
+public:
+    /**
+     * @brief ESP8266Interface default constructor
+     *        Will use values defined in mbed_lib.json
+     */
+    ESP8266Interface();
+
+    /** ESP8266Interface lifetime
+     * @param tx        TX pin
+     * @param rx        RX pin
+     * @param debug     Enable debugging
+     */
+    ESP8266Interface(PinName tx, PinName rx, bool debug = false);
+
+    /** 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);
+
+    /** 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
+     * @param  timeout  Timeout in milliseconds; 0 for no timeout (Default: 0)
+     * @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;
+
+    /** @copydoc NetworkStack::setsockopt
+     */
+    virtual nsapi_error_t setsockopt(nsapi_socket_t handle, int level,
+            int optname, const void *optval, unsigned optlen);
+
+    /** @copydoc NetworkStack::getsockopt
+     */
+    virtual nsapi_error_t getsockopt(nsapi_socket_t handle, int level, int optname,
+            void *optval, unsigned *optlen);
+
+    /** Register callback for status reporting
+     *
+     *  The specified status callback function will be called on status changes
+     *  on the network. The parameters on the callback are the event type and
+     *  event-type dependent reason parameter.
+     *
+     *  In ESP8266 the callback will be called when processing OOB-messages via
+     *  AT-parser. Do NOT call any ESP8266Interface -functions or do extensive
+     *  processing in the callback.
+     *
+     *  @param status_cb The callback for status changes
+     */
+    virtual void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb);
+
+    /** Get the connection status
+     *
+     *  @return         The connection status according to ConnectionStatusType
+     */
+    virtual nsapi_connection_status_t get_connection_status() const;
+
+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:
+    static const int ESP8266_SSID_MAX_LENGTH = 32; /* 32 is what 802.11 defines as longest possible name */
+    static const int ESP8266_PASSPHRASE_MAX_LENGTH = 63; /* The longest allowed passphrase */
+    static const int ESP8266_PASSPHRASE_MIN_LENGTH = 8; /* The shortest allowed passphrase */
+
+    ESP8266 _esp;
+    bool _ids[ESP8266_SOCKET_COUNT];
+    int _initialized;
+    int _started;
+
+    char ap_ssid[ESP8266_SSID_MAX_LENGTH + 1]; /* 32 is what 802.11 defines as longest possible name; +1 for the \0 */
+    nsapi_security_t ap_sec;
+    uint8_t ap_ch;
+    char ap_pass[ESP8266_PASSPHRASE_MAX_LENGTH + 1];
+    uint16_t _local_ports[ESP8266_SOCKET_COUNT];
+
+    bool _disable_default_softap();
+    void event();
+    bool _get_firmware_ok();
+    nsapi_error_t _init(void);
+    nsapi_error_t _startup(const int8_t wifi_mode);
+
+    struct {
+        void (*callback)(void *);
+        void *data;
+    } _cbs[ESP8266_SOCKET_COUNT];
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/wifi/esp8266-driver/README.md	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,13 @@
+# ESP8266 WiFi driver for Mbed OS
+
+The Mbed OS driver for the ESP8266 WiFi module.
+
+## Firmware version
+
+ESP8266 modules come in different shapes and formats, but the most important factor is the firmware version in it. To make sure that the firmware in your module is compatible with Mbed OS, follow the [Update guide](https://developer.mbed.org/teams/ESP8266/wiki/Firmware-Update).
+
+## Restrictions
+
+- The ESP8266 WiFi module does not allow the TCP client to bind on a specific port.
+- Setting up a UDP server is not possible.
+- The serial port does not have hardware flow control enabled. The AT command set does not either have a way to limit the download rate. Therefore, downloading anything larger than the serial port input buffer is unreliable. An application should be able to read fast enough to stay ahead of the network. This affects mostly the TCP protocol where data would be lost with no notification. On UDP, this would lead to only packet losses which the higher layer protocol should recover from.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/wifi/esp8266-driver/mbed_lib.json	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,35 @@
+{
+    "name": "esp8266",
+    "config": {
+        "tx": {
+            "help": "TX pin for serial connection",
+            "value": null
+        },
+        "rx": {
+            "help": "RX pin for serial connection",
+            "value": null
+        },
+        "debug": {
+            "help": "Enable debug logs",
+            "value": false
+        },
+        "provide-default": {
+            "help": "Provide default WifiInterface. [true/false]",
+            "value": false
+        }
+    },
+    "target_overrides": {
+         "HEXIWEAR": {
+            "tx": "PTD3",
+            "rx": "PTD2"
+        },
+        "NUCLEO_F401RE": {
+            "tx": "D8",
+            "rx": "D2"
+        },
+        "NUCLEO_F411RE": {
+            "tx": "D8",
+            "rx": "D2"
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/features/frameworks/mbed-coap/_settings/language.settings.xml	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<project>
+	<configuration id="0.2056004298.1497082229" name="ArmCC Cortex-M3">
+		<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
+			<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
+			<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
+			<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
+			<provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuildCommandParser" id="org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser" keep-relative-paths="false" name="CDT GCC Build Output Parser" parameter="(.*gcc)|([gc]\+\+)|(clang)|(ArmCC)" prefer-non-shared="true" resource-scope="per-project" store-entries-with-project="true">
+				<language id="org.eclipse.cdt.core.gcc">
+					<resource project-relative-path="">
+						<entry kind="includePath" name="/${ProjName}/libNsdl/src/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+                        <entry kind="includePath" name="/${ProjName}/mbed-coap/src/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+						<entry kind="includePath" name="/libService/include">
+							<flag value="VALUE_WORKSPACE_PATH|RESOLVED"/>
+						</entry>
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+						<entry kind="macro" name="VERSION" value="&quot;2.0-release-77-g0f5d7bf-dirty&quot;"/>
+					</resource>
+					<resource project-relative-path="libList">
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+					<resource project-relative-path="randLIB">
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+					<resource project-relative-path="libX509_V3">
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+					<resource project-relative-path="libaes">
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+					<resource project-relative-path="nsdynmemLIB">
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+					<resource project-relative-path="CCM_lib">
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+					<resource project-relative-path="SHA256_Lib">
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+					<resource project-relative-path="IPv6_fcf_lib">
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+					<resource project-relative-path="libip6string">
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+					<resource project-relative-path="ECC_library/src">
+						<entry kind="includePath" name="/${ProjName}/ECC_library">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+					<resource project-relative-path="libNSTun">
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+				</language>
+			</provider>
+		</extension>
+	</configuration>
+	<configuration id="0.2056004298.1497082229.1854995973" name="ArmCC Cortex-M0">
+		<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
+			<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
+			<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
+			<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
+			<provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuildCommandParser" id="org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser" keep-relative-paths="false" name="CDT GCC Build Output Parser" parameter="(.*gcc)|([gc]\+\+)|(clang)|(ArmCC)" prefer-non-shared="true" resource-scope="per-project" store-entries-with-project="true">
+				<language id="org.eclipse.cdt.core.gcc">
+					<resource project-relative-path="libList">
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+					<resource project-relative-path="">
+						<entry kind="includePath" name="/${ProjName}/libNsdl/src/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+                        <entry kind="includePath" name="/${ProjName}/mbed-coap/src/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+						<entry kind="includePath" name="/libService/include">
+							<flag value="VALUE_WORKSPACE_PATH|RESOLVED"/>
+						</entry>
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+						<entry kind="macro" name="VERSION" value="&quot;2.0-release-77-g0f5d7bf-dirty&quot;"/>
+					</resource>
+					<resource project-relative-path="randLIB">
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+					<resource project-relative-path="libX509_V3">
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+					<resource project-relative-path="libaes">
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+					<resource project-relative-path="nsdynmemLIB">
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+					<resource project-relative-path="SHA256_Lib">
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+					<resource project-relative-path="CCM_lib">
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+					<resource project-relative-path="libip6string">
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+					<resource project-relative-path="IPv6_fcf_lib">
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+					<resource project-relative-path="ECC_library/src">
+						<entry kind="includePath" name="/${ProjName}/ECC_library">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+					<resource project-relative-path="libNSTun">
+						<entry kind="includePath" name="/${ProjName}/include">
+							<flag value="VALUE_WORKSPACE_PATH"/>
+						</entry>
+					</resource>
+				</language>
+			</provider>
+		</extension>
+	</configuration>
+	<configuration id="0.2056004298.141662914.2121498000.642060230.2118977701" name="GCC Cortex-M0">
+		<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
+			<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
+			<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
+			<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
+			<provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuildCommandParser" id="org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser" keep-relative-paths="false" name="CDT GCC Build Output Parser" parameter="(.*gcc)|([gc]\+\+)|(clang)" prefer-non-shared="true" resource-scope="per-project" store-entries-with-project="true"/>
+		</extension>
+	</configuration>
+	<configuration id="0.2056004298.141662914.2121498000.642060230.2118977701.1678729521" name="GCC Cortex-M3">
+		<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
+			<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
+			<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
+			<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
+			<provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuildCommandParser" id="org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser" keep-relative-paths="false" name="CDT GCC Build Output Parser" parameter="(.*gcc)|([gc]\+\+)|(clang)" prefer-non-shared="true" resource-scope="per-project" store-entries-with-project="true"/>
+		</extension>
+	</configuration>
+	<configuration id="0.2056004298.141662914.1517984773.801758434.1788862897.788959847" name="GCC Native">
+		<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
+			<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
+			<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
+			<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
+			<provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuildCommandParser" id="org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser" keep-relative-paths="false" name="CDT GCC Build Output Parser" parameter="(gcc)|([gc]\+\+)|(clang)" prefer-non-shared="true" resource-scope="per-project"/>
+		</extension>
+	</configuration>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/features/frameworks/mbed-coap/_settings/org.eclipse.cdt.core.prefs	Wed Mar 13 11:03:24 2019 +0000
@@ -0,0 +1,62 @@
+eclipse.preferences.version=1
+environment/project/0.2056004298.141662914.1517984773.801758434.1788862897.788959847/CC/delimiter=;
+environment/project/0.2056004298.141662914.1517984773.801758434.1788862897.788959847/CC/operation=append
+environment/project/0.2056004298.141662914.1517984773.801758434.1788862897.788959847/CC/value=gcc
+environment/project/0.2056004298.141662914.1517984773.801758434.1788862897.788959847/V/delimiter=;
+environment/project/0.2056004298.141662914.1517984773.801758434.1788862897.788959847/V/operation=append
+environment/project/0.2056004298.141662914.1517984773.801758434.1788862897.788959847/V/value=1
+environment/project/0.2056004298.141662914.1517984773.801758434.1788862897.788959847/append=true
+environment/project/0.2056004298.141662914.1517984773.801758434.1788862897.788959847/appendContributed=true
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701.1678729521/CPU/delimiter=;
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701.1678729521/CPU/operation=replace
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701.1678729521/CPU/value=Cortex-M0
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701.1678729521/DEBUG/delimiter=;
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701.1678729521/DEBUG/operation=replace
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701.1678729521/DEBUG/value=1
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701.1678729521/PLATFORM/delimiter=;
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701.1678729521/PLATFORM/operation=append
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701.1678729521/PLATFORM/value=arm-unknown-linux-uclibcgnueabi-
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701.1678729521/V/delimiter=;
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701.1678729521/V/operation=append
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701.1678729521/V/value=1
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701.1678729521/append=true
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701.1678729521/appendContributed=true
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701/CPU/delimiter=;
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701/CPU/operation=replace
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701/CPU/value=Cortex-M0
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701/DEBUG/delimiter=;
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701/DEBUG/operation=replace
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701/DEBUG/value=1
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701/PLATFORM/delimiter=;
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701/PLATFORM/operation=append
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701/PLATFORM/value=arm-unknown-linux-uclibcgnueabi-
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701/V/delimiter=;
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701/V/operation=append
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701/V/value=1
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701/append=true
+environment/project/0.2056004298.141662914.2121498000.642060230.2118977701/appendContributed=true
+environment/project/0.2056004298.1497082229.1854995973/CC/delimiter=;
+environment/project/0.2056004298.1497082229.1854995973/CC/operation=append
+environment/project/0.2056004298.1497082229.1854995973/CC/value=ArmCC
+environment/project/0.2056004298.1497082229.1854995973/CPU/delimiter=;
+environment/project/0.2056004298.1497082229.1854995973/CPU/operation=replace
+environment/project/0.2056004298.1497082229.1854995973/CPU/value=Cortex-M0
+environment/project/0.2056004298.1497082229.1854995973/DEBUG/delimiter=;
+environment/project/0.2056004298.1497082229.1854995973/DEBUG/operation=replace
+environment/project/0.2056004298.1497082229.1854995973/DEBUG/value=1
+environment/project/0.2056004298.1497082229.1854995973/V/delimiter=;
+environment/project/0.2056004298.1497082229.1854995973/V/operation=append
+environment/project/0.2056004298.1497082229.1854995973/V/value=1
+environment/project/0.2056004298.1497082229.1854995973/append=true
+environment/project/0.2056004298.1497082229.1854995973/appendContributed=true
+environment/project/0.2056004298.1497082229/CC/delimiter=;
+environment/project/0.2056004298.1497082229/CC/operation=append
+environment/project/0.2056004298.1497082229/CC/value=ArmCC
+environment/project/0.2056004298.1497082229/CPU/delimiter=;
+environment/project/0.2056004298.1497082229/CPU/operation=append
+environment/project/0.2056004298.1497082229/CPU/value=Cortex-M3
+environment/project/0.2056004298.1497082229/V/delimiter=;
+environment/project/0.2056004298.1497082229/V/operation=append
+environment/project/0.2056004298.1497082229/V/value=1
+environment/project/0.2056004298.1497082229/append=true
+environment/project/0.2056004298.1497082229/appendContributed=true
--- a/platform/mbed_rtc_time.cpp	Thu Nov 29 19:05:57 2018 +0000
+++ b/platform/mbed_rtc_time.cpp	Wed Mar 13 11:03:24 2019 +0000
@@ -105,14 +105,14 @@
 
 void set_time(time_t t)
 {
-//    _mutex->lock();
+    _mutex->lock();
     if (_rtc_init != NULL) {
         _rtc_init();
     }
     if (_rtc_write != NULL) {
         _rtc_write(t);
     }
-//    _mutex->unlock();
+    _mutex->unlock();
 }
 
 void attach_rtc(time_t (*read_rtc)(void), void (*write_rtc)(time_t), void (*init_rtc)(void), int (*isenabled_rtc)(void))
--- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/rtc_api.c	Thu Nov 29 19:05:57 2018 +0000
+++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/rtc_api.c	Wed Mar 13 11:03:24 2019 +0000
@@ -21,7 +21,6 @@
 #include "fsl_rtc.h"
 #include "PeripheralPins.h"
 
-// changed PeterS 
 static bool rtc_time_set = true;
 
 void rtc_init(void)
--- a/targets/targets.json	Thu Nov 29 19:05:57 2018 +0000
+++ b/targets/targets.json	Wed Mar 13 11:03:24 2019 +0000
@@ -638,7 +638,7 @@
         "inherits": ["Target"],
         "detect_code": ["0240"],
         "device_has": ["USTICKER", "LPTICKER", "RTC", "CRC", "ANALOGIN", "ANALOGOUT", "EMAC", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_FC", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPI_ASYNCH", "SPISLAVE", "STDIO_MESSAGES", "STORAGE", "TRNG", "FLASH"],
-        "features": ["STORAGE"],
+        "features": ["STORAGE", "RTC"],
         "release_versions": ["2", "5"],
         "device_name": "MK64FN1M0xxx12",
         "bootloader_supported": true,
@@ -4626,4 +4626,3 @@
         "detect_code": ["8001"]
     }
 }
-