NVProperty generic key value store using the MCU flash area.

Dependents:   Turtle_RadioShuttle

Files at this revision

API Documentation at this revision

Comitter:
Helmut Tschemernjak
Date:
Thu Jan 31 21:31:29 2019 +0100
Parent:
3:968b84113ef3
Child:
5:2560e615ccd5
Commit message:
Updated Properties for MBED

Changed in this revision

NVProperty.cpp Show annotated file Show diff for this revision Revisions of this file
NVProperty_L4Flash.cpp Show diff for this revision Revisions of this file
NVProperty_L4Flash.h Show diff for this revision Revisions of this file
NVProperty_MBEDFlash.cpp Show annotated file Show diff for this revision Revisions of this file
NVProperty_MBEDFlash.h Show annotated file Show diff for this revision Revisions of this file
NVProperty_SRAM.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/NVProperty.cpp	Thu Jan 24 15:38:20 2019 +0100
+++ b/NVProperty.cpp	Thu Jan 31 21:31:29 2019 +0100
@@ -25,10 +25,12 @@
   #include <NVProperty_ESP32efuse.h>
 #elif defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_ARCH_SAMD)
   #include <NVProperty_D21Flash.h>
-#elif defined(__MBED__) && defined(TARGET_STM32L4)
+#elif __MBED__
   #include <mbed.h>
-  #include <NVProperty_L4OTP.h>
-  #include <NVProperty_L4Flash.h>
+  #include <NVProperty_MBEDFlash.h>
+  #ifdef TARGET_STM32L4
+    #include <NVProperty_L4OTP.h>
+  #endif
 #else
 #error "Unkown implementation"
 #endif
@@ -45,8 +47,8 @@
     _flash = new NVProperty_ESP32NVS();
 #elif defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_ARCH_SAMD)
     _flash = new NVProperty_D21Flash(propSizekB, erase);
-#elif TARGET_STM32L4
-	// TODO _flash = new NVProperty_L4Flash(propSizekB, erase);
+#elif __MBED__
+	_flash = new NVProperty_MBEDFlash(propSizekB, erase);
 #else
  #error "unkown platform"
 #endif
--- a/NVProperty_L4Flash.cpp	Thu Jan 24 15:38:20 2019 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,523 +0,0 @@
-/*
- * This is an unpublished work copyright
- * (c) 2019 Helmut Tschemernjak
- * 30826 Garbsen (Hannover) Germany
- *
- *
- * Use is granted to registered RadioShuttle licensees only.
- * Licensees must own a valid serial number and product code.
- * Details see: www.radioshuttle.de
- */
-
-#ifdef TARGET_STM32L4
-
-#include <mbed.h>
-#include "main.h"
-#include <NVPropertyProviderInterface.h>
-#include <NVProperty_L4Flash.h>
-#include <NVProperty.h>
-
-#if 0
-#define OTP_TEST_IN_RAM // test OTP in RAM
-
-
-NVProperty_L4OTP::NVProperty_L4OTP()
-{
-	_debug = false;
-	_propSize = 1 * 1024; 					// no define in HAL laye
-	_startAddress = (uint8_t *) 0x1FFF7000; // no define in HAL layer
-
-#ifdef OTP_TEST_IN_RAM
-	static uint8_t *savedStart;
-	if (!savedStart) {
- 		_startAddress = (uint8_t *) malloc(512);
-		memset(_startAddress, 0xff, 512);
-		savedStart = _startAddress;
-	} else {
-		_startAddress = savedStart;
-	}
-#endif
-	
-	_endAddress = _startAddress + (_propSize);
-	_lastEntry = NULL;
-	
-	_FlashInititalize();
-}
-
-
-NVProperty_L4OTP::~NVProperty_L4OTP()
-{
-	_debug = true;
-	_DumpAllEntires();
-}
-
-
-void
-NVProperty_L4OTP::_FlashInititalize(void)
-{
-	_flash_header *fh = (_flash_header *)_startAddress;
-	if (fh->magic == FLASH_PROP_MAGIC && fh->version == FLASH_PROP_VERSION && fh->size == _propSize) {
-		return;
-	}
-	
-	uint8_t *p = _startAddress;
-	for (int i = 0; i < (int)sizeof(_flash_header); i++) {
-		if (*p++ != 0xff)
-			return; // invalid data
-	}
-	
-	_flash_header f;
-	memset(&f, 0, sizeof(f));
-	f.magic = FLASH_PROP_MAGIC;
-	f.version = FLASH_PROP_VERSION;
-	f.size = _propSize;
-	
-	_OTPWrite(_startAddress, &f, sizeof(f));
-}
-
-
-int
-NVProperty_L4OTP::GetProperty(int key)
-{
-    return GetProperty64(key);
-}
-
-
-int64_t
-NVProperty_L4OTP::GetProperty64(int key)
-{
-	_flashEntry *p = _GetFlashEntry(key);
-	if (!p)
-		return NVProperty::NVP_ENOENT;
-
-    int64_t value = 0;
-	
-    switch(p->t.type) {
-		case NVProperty::T_BIT:
-			if (p->t.t_bit)
-				value = 1;
-			else
-				value = 0;
-			break;
-		case NVProperty::T_8BIT:
-			value = p->u.v_8bit;
-			break;
-		case NVProperty::T_16BIT:
-			{
-				int16_t v;
-				memcpy(&v, &p->u.v_16bit, sizeof(p->u.v_16bit));
-				value = v;
-			}
-			break;
-		case NVProperty::T_32BIT:
-			{
-				int32_t v;
-				memcpy(&v, &p->data.v_32bit, sizeof(p->data.v_32bit));
-				value =v;
-			}
-			break;
-		case NVProperty::T_64BIT:
-			memcpy(&value, p->data.v_64bit, sizeof(p->data.v_64bit));
-			break;
-		case NVProperty::T_STR:
-		case NVProperty::T_BLOB:
-			value = p->u.option.d_len;
-			break;
-	}
-    return value;
-}
-
-const char *
-NVProperty_L4OTP::GetPropertyStr(int key)
-{
-	_flashEntry *p = _GetFlashEntry(key);
-	if (!p || p->t.type != NVProperty::T_STR)
-		return NULL;
-    return strdup(p->data.v_str);
-}
-
-int
-NVProperty_L4OTP::GetPropertyBlob(int key, const void *blob, int *size)
-{
-	_flashEntry *p = _GetFlashEntry(key);
-	if (!p || p->t.type != NVProperty::T_BLOB)
-		return NVProperty::NVP_ENOENT;
-	
-	int cplen = std::min(*size, (int)p->u.option.d_len);
-	if (blob)
-		memcpy((void *)blob, p->data.v_blob, cplen);
-	*size = cplen;
-	
-    return NVProperty::NVP_OK;
-}
-
-
-int
-NVProperty_L4OTP::SetProperty(int key, int64_t value, int type)
-{
-	UNUSED(type);
-	uint8_t valbuf[FLASH_ENTRY_MIN_SIZE + sizeof(int64_t)];
-	_flashEntry *p = (_flashEntry *) valbuf;
-	int storeType;
-	
-	if (GetProperty64(key) == value) // no need to save it again.
-	    return NVProperty::NVP_OK;
-	
-	
-	memset(valbuf, 0, sizeof(valbuf));
-	
-	if (value == 0 ||  value == 1)
-		storeType = NVProperty::T_BIT;
-	else if (value >= -128 && value < 128)
-		storeType = NVProperty::T_8BIT;
-	else if (value >= -32768 && value < 32768)
-		storeType = NVProperty::T_16BIT;
-	else if (value > -2147483647 && value < 2147483648)
-		storeType = NVProperty::T_32BIT;
-	else
-		storeType = NVProperty::T_64BIT;
-	
-	p->key = key;
-	p->t.type = storeType;
-
-
-	switch(storeType) {
-		case NVProperty::T_BIT:
-			p->t.t_bit = value;
-			break;
-		case NVProperty::T_8BIT:
-			p->u.v_8bit = value;
-			break;
-		case NVProperty::T_16BIT:
-			p->u.v_16bit = value;
-			break;
-		case NVProperty::T_32BIT:
-			p->u.option.d_len = sizeof(p->data.v_32bit);
-			{
-				int32_t v = value;
-				memcpy(&p->data.v_32bit, &v, sizeof(p->data.v_32bit));
-			}
-			break;
-		case NVProperty::T_64BIT:
-			p->u.option.d_len = sizeof(p->data.v_64bit);
-			memcpy(p->data.v_64bit, &value, sizeof(p->data.v_64bit));
-			break;
-	}
-	int len;
-	if (storeType == NVProperty::T_BIT || storeType == NVProperty::T_8BIT || storeType == NVProperty::T_16BIT || storeType == NVProperty::T_32BIT) {
-		len = FLASH_ENTRY_MIN_SIZE;
-	} else { // 64/STR/BLOB
-		len = (FLASH_ENTRY_MIN_SIZE - 4) + p->u.option.d_len;
-		len += _GetFlashPaddingSize(len);
-	}
-	if ((uint8_t *)_lastEntry + len >= _endAddress) {
-		if (!_FlashReorgEntries(len))
-			return NVProperty::NVP_ERR_NOSPACE;
-	}
-
-	_OTPWrite((uint8_t *)_lastEntry, p, len);
-	_lastEntry = (_flashEntry *)((uint8_t *)_lastEntry + len);
-
-	// _DumpAllEntires();
-    return NVProperty::NVP_OK;
-}
-
-
-int
-NVProperty_L4OTP::SetPropertyStr(int key, const char *value, int type)
-{
-	if (type != NVProperty::T_STR)
-		return NVProperty::NVP_INVALD_PARM;
-	
-	_flashEntry *p = _GetFlashEntry(key);
-	if (p && p->t.type == NVProperty::T_STR && strcmp(p->data.v_str, value) == 0) {
-		return NVProperty::NVP_OK;
-	}
-
-	int err = NVProperty::NVP_OK;
-	
-	p = new _flashEntry();
-	if (!p)
-		return NVProperty::NVP_ERR_NOSPACE;
-	
-	p->key = key;
-	p->t.type = NVProperty::T_STR;
-	int cplen = std::min(strlen(value), sizeof(p->data.v_str)-1);
-	memcpy(p->data.v_str, value, cplen);
-	p->u.option.d_len = cplen + 1; // zero term
-	
-	int len = (FLASH_ENTRY_MIN_SIZE - 4) + p->u.option.d_len;
-	len += _GetFlashPaddingSize(len);
-
-	if ((uint8_t *)_lastEntry + len >= _endAddress) {
-		if (!_FlashReorgEntries(len)) {
-			err = NVProperty::NVP_ERR_NOSPACE;
-			goto done;
-		}
-	}
-
-	_OTPWrite((uint8_t *)_lastEntry, p, len);
-	_lastEntry = (_flashEntry *)((uint8_t *)_lastEntry + len);
-
-done:
-	delete[] p;
-	// _DumpAllEntires();
-    return err;
-}
-
-int
-NVProperty_L4OTP::SetPropertyBlob(int key, const void *blob, int size, int type)
-{
-	if (type != NVProperty::T_BLOB)
-		return NVProperty::NVP_INVALD_PARM;
-	
-	_flashEntry *p = _GetFlashEntry(key);
-	if (p && p->t.type == NVProperty::T_BLOB && size == p->u.option.d_len) { // check for duplicate
-		if (memcmp(blob, p->data.v_blob, size) == 0)
-			return NVProperty::NVP_OK;
-	}
-	int err = NVProperty::NVP_OK;
-	
-	p = new _flashEntry();
-	if (!p)
-		return NVProperty::NVP_ERR_NOSPACE;
-	
-	p->key = key;
-	p->t.type = NVProperty::T_BLOB;
-	int cplen = std::min(size, (int)sizeof(p->data.v_blob));
-	p->u.option.d_len = cplen;
-	memcpy(p->data.v_blob, blob, cplen);
-	
-	int len = (FLASH_ENTRY_MIN_SIZE - 4) + p->u.option.d_len;
-	len += _GetFlashPaddingSize(len);
-
-	if ((uint8_t *)_lastEntry + len >= _endAddress) {
-		if (!_FlashReorgEntries(len)) {
-			err = NVProperty::NVP_ERR_NOSPACE;
-			goto done;
-		}
-	}
-
-	_OTPWrite((uint8_t *)_lastEntry, p, len);
-	_lastEntry = (_flashEntry *)((uint8_t *)_lastEntry + len);
-
-done:
-	delete[] p;
-	// _DumpAllEntires();
-    return err;
-}
-
-int
-NVProperty_L4OTP::EraseProperty(int key)
-{
-	uint8_t valbuf[FLASH_ENTRY_MIN_SIZE];
-	_flashEntry *p = (_flashEntry *) valbuf;
-
-	_flashEntry *op = _GetFlashEntry(key);
-	if (!op)
-		return NVProperty::NVP_ENOENT;
-	if (op->t.deleted)
-		return NVProperty::NVP_OK;
-	
-	memset(valbuf, 0, sizeof(valbuf));
-	p->key = key;
-	p->t.type = op->t.type;
-	p->t.deleted = true;
-	
-	if ((uint8_t *)_lastEntry + FLASH_ENTRY_MIN_SIZE > _endAddress) {
-		if (!_FlashReorgEntries(FLASH_ENTRY_MIN_SIZE))
-			return NVProperty::NVP_ERR_NOSPACE;
-	}
-
-	_OTPWrite((uint8_t *)_lastEntry, p, FLASH_ENTRY_MIN_SIZE);
-	_lastEntry = (_flashEntry *)((uint8_t *)_lastEntry + FLASH_ENTRY_MIN_SIZE);
-
-	// _DumpAllEntires();
-	return NVProperty::NVP_OK;
-}
-
-int
-NVProperty_L4OTP::ReorgProperties(void)
-{
-    return NVProperty::NVP_OK;
-}
-
-
-int
-NVProperty_L4OTP::OpenPropertyStore(bool forWrite)
-{
-	UNUSED(forWrite);
-    return NVProperty::NVP_OK;
-}
-
-int
-NVProperty_L4OTP::ClosePropertyStore(bool flush)
-{
-    return NVProperty::NVP_OK;
-}
-
-#if 1
-void
-NVProperty_L4OTP::_DumpAllEntires(void)
-{
-	if (!_debug)
-		return;
-	
-	dprintf("------------- DumpAllEntires -------- ");
-
-	int index = 0;
-	_flashEntry *p = (_flashEntry *)(_startAddress + sizeof(_flash_header));
-	while((uint8_t *)p < _endAddress && p->key != NVProperty::PROPERTIES_EOF) {
-
-		int64_t value = 0;
-    	switch(p->t.type) {
-		case NVProperty::T_BIT:
-			if (p->t.t_bit)
-				value = 1;
-			else
-				value = 0;
-			break;
-		case NVProperty::T_8BIT:
-			value = p->u.v_8bit;
-			break;
-		case NVProperty::T_16BIT:
-			{
-				int16_t v;
-				memcpy(&v, &p->u.v_16bit, sizeof(p->u.v_16bit));
-				value = v;
-			}
-			break;
-		case NVProperty::T_32BIT:
-			{
-				int32_t v;
-				memcpy(&v, &p->data.v_32bit, sizeof(p->data.v_32bit));
-				value = v;
-			}
-			break;
-		case NVProperty::T_64BIT:
-			memcpy(&value, p->data.v_64bit, sizeof(p->data.v_64bit));
-			break;
-		case NVProperty::T_STR:
-		case NVProperty::T_BLOB:
-			value = p->u.option.d_len;
-			break;
-		}
-		index++;
-		if (p->t.deleted) {
-			dprintf("Dump[%.2d] Key: %d Type: %d deleted(%d)", index, p->key, p->t.type, p->t.deleted);
-
-		} else if (p->t.type == NVProperty::T_STR) {
-			dprintf("Dump[%.2d] Key: %d Type: %d value: %s", index, p->key, p->t.type, p->data.v_str);
-		} else if (p->t.type == NVProperty::T_BLOB) {
-			dprintf("Dump[%.2d] Key: %d Type: %d len: %d", index, p->key, p->t.type, p->u.option.d_len);
-			dump("Blob",  p->data.v_str, p->u.option.d_len);
-		} else {
-			if (p->t.type == NVProperty::T_64BIT) {
-				dprintf("Dump[%.2d] Key: %d Type: %d value: %lld (0x%llx)", index, p->key, p->t.type, value, value);
-			} else {
-				dprintf("Dump[%.2d] Key: %d Type: %d value: %ld (0x%x)", index, p->key, p->t.type, (int32_t)value, (unsigned int)value);
-			}
-		}
-		
-		p = (_flashEntry *)((uint8_t *)p + _GetFlashEntryLen(p));
-	}
-	int freebytes = _endAddress -(uint8_t *)_lastEntry;
-	if (_lastEntry)
-		dprintf("------ %d bytes free -------", freebytes);
-}
-#endif
-
-NVProperty_L4OTP::_flashEntry *
-NVProperty_L4OTP::_GetFlashEntry(int key, uint8_t *start)
-{
-	_flashEntry *p;
-
-	if (start)
-		p = (_flashEntry *)start;
-	else
-		p = (_flashEntry *)(_startAddress + sizeof(_flash_header));
-	_flashEntry *lastP = NULL;
-	while(true) {
-		if ((uint8_t*)p >= _endAddress || p->key == NVProperty::PROPERTIES_EOF) {
-			if ((uint8_t*)p <= _endAddress)
-				_lastEntry = p;
-			if (!lastP || lastP->t.deleted)
-				return NULL;
-			break;
-		}
-		if (p->key == key)
-			lastP = p;
-
-		p = (_flashEntry *)((uint8_t *)p + _GetFlashEntryLen(p));
-	}
-	return lastP;
-}
-
-
-int
-NVProperty_L4OTP::_GetFlashEntryLen(_flashEntry *p)
-{
-	int len = 0;
-	
-	switch(p->t.type) {
-		case NVProperty::T_64BIT:
-		case NVProperty::T_STR:
-		case NVProperty::T_BLOB:
-			len = (FLASH_ENTRY_MIN_SIZE - 4) + p->u.option.d_len;
-			len += _GetFlashPaddingSize(len);
-			break;
-		default:
-			len = FLASH_ENTRY_MIN_SIZE;
-	}
-	return len;
-}
-
-int
-NVProperty_L4OTP::_GetFlashPaddingSize(int len)
-{
-	int remain = len % FLASH_PADDING_SIZE;
-	
-	if (remain == 0)
-		return 0;
-	
-	return (len + FLASH_PADDING_SIZE - remain) - len;
-}
-
-
-int
-NVProperty_L4OTP::_FlashReorgEntries(int minRequiredSpace)
-{
-	return 0; // no reorg on OTP
-}
-
-
-void
-NVProperty_L4OTP::_OTPWrite(uint8_t *address, const void *d, size_t length)
-{
-	//FlashIAP f;
-	//f.init();
-#ifdef OTP_TEST_IN_RAM
-	memcpy(address, d, length);
-#else
-	uint8_t *data = (uint8_t *)d;
-	uint32_t addr = (uint32_t)address;
-	volatile uint64_t data64;
-
-	HAL_FLASH_Unlock();
-	while (length > 0) {
-		for (uint8_t i = 0; i < 8; i++) {
-			*(((uint8_t *) &data64) + i) = *(data + i);
-        }
-	    int err = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr, data64);
-		addr += 8;
-		data += 8;
-		length -= 8;
-	}
-    HAL_FLASH_Lock();
-#endif
-}
-
-#endif
-
-
-#endif // TARGET_STM32L4
--- a/NVProperty_L4Flash.h	Thu Jan 24 15:38:20 2019 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-/*
- * This is an unpublished work copyright
- * (c) 2019 Helmut Tschemernjak
- * 30826 Garbsen (Hannover) Germany
- *
- *
- * Use is granted to registered RadioShuttle licensees only.
- * Licensees must own a valid serial number and product code.
- * Details see: www.radioshuttle.de
- */
-
-#ifndef __NVPROPERTY_L4FLASH__
-#define __NVPROPERTY_L4FLASH__
-
-class NVProperty_L4Flash : public NVPropertyProviderInterface {
-public:
-	NVProperty_L4Flash(int propSizekB, bool erase);
-	~NVProperty_L4Flash();
-	
-    virtual int GetProperty(int key);
-    virtual int64_t GetProperty64(int key);
-    virtual int GetPropertyBlob(int key, const void *blob, int *size);
-    virtual const char *GetPropertyStr(int key);
-    virtual int SetProperty(int key, int64_t value, int type);
-    virtual int SetPropertyStr(int key, const char *value, int type);
-    virtual int SetPropertyBlob(int key, const void *blob, int size, int type);
-    virtual int EraseProperty(int key);
-    virtual int ReorgProperties(void);
-    virtual int OpenPropertyStore(bool forWrite = false);
-    virtual int ClosePropertyStore(bool flush = false);
-	
-private:
-	void _FlashInititalize(bool force = false);
-	void _FlashEraseRow(int startRow, int count = 1);
-	void _FlashWrite(uint8_t *address, const void *data, size_t length);
-	bool _FlashIsCleared(uint8_t *address, int len);
-	void _FlashWritePage(int page, int offset, uint8_t *data, int length);
-
-	struct _flash_header {
-		uint32_t magic;
-		uint16_t version;
-		uint16_t sizeKB;
-	};
-	
-	static const int FLASH_ENTRY_HEADER			= 4;
-	static const int FLASH_ENTRY_HEADER_SHORT	= 2;
-	static const int MAX_DATA_ENTRY				= 256;
-	
-	struct _flashEntry {
-		uint8_t key;	// Property key
-		struct {
-			uint8_t deleted	: 1; // this key has been deleted
-			uint8_t t_bit  	: 1; // contains the bool value
-			uint8_t reserv1	: 1; //
-			uint8_t reserv2	: 1; //
-			uint8_t type   	: 4; // NVPType
-		} t;
-		union {
-			int16_t v_16bit;
-			int8_t	v_8bit;
-			struct {
-				uint8_t d_len;				 // data length
-				uint8_t f_reserv1  		: 8;
-			} option;
-		} u;
-		union {
-			int32_t v_32bit;
-			int32_t v_64bit[2];	// use use 2 x 32-bit to avoid 64-bit struct padding
-			char v_str[MAX_DATA_ENTRY];
-			uint8_t v_blob[MAX_DATA_ENTRY];
-		} data;
-	};
-	
-	_flashEntry * _GetFlashEntry(int key, uint8_t *start = NULL);
-	int _GetFlashEntryLen(_flashEntry *k);
-	int _GetFlashPaddingSize(int len);
-	_flashEntry *_lastEntry;
-	void _DumpAllEntires(void);
-	int _FlashReorgEntries(int minRequiredSpace);
-	bool _debug;
-	int _propSizekB;
-	int _pageSize;
-	int _numPages;
-	int _rowSize;
-	uint8_t *_startAddress;
-	uint8_t *_endAddress;
-
-	static const int FLASH_PROP_MAGIC = 0x4c6f5261; // "LORA"
-	static const int FLASH_PROP_VERSION = 3;
-	static const int _bootlLoaderSize = 8192;
-	static const int _lockRegions = 16;	// d21 lock regions are always 16 for the entire ram
-
-
-};
-
-#endif // __NVPROPERTY_L4FLASH__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NVProperty_MBEDFlash.cpp	Thu Jan 31 21:31:29 2019 +0100
@@ -0,0 +1,722 @@
+/*
+ * This is an unpublished work copyright
+ * (c) 2019 Helmut Tschemernjak
+ * 30826 Garbsen (Hannover) Germany
+ *
+ *
+ * Use is granted to registered RadioShuttle licensees only.
+ * Licensees must own a valid serial number and product code.
+ * Details see: www.radioshuttle.de
+ */
+
+#ifdef __MBED__
+
+#include <mbed.h>
+#include "main.h"
+#include "arch.h"
+#include <algorithm>
+#include <NVPropertyProviderInterface.h>
+#include <NVProperty_MBEDFlash.h>
+#include <NVProperty.h>
+
+
+#if 0	// sample test code for a man app.
+	{
+	NVProperty p;
+	
+	p.OpenPropertyStore(true);
+	dprintf("OTP--1: %d", p.GetProperty(p.CPUID, -1));
+	p.SetProperty(p.CPUID, p.T_32BIT, 123, p.S_OTP);
+	dprintf("OTP123: %d", p.GetProperty(p.CPUID, 0));
+	p.SetProperty(p.CPUID, p.T_32BIT, 0x12345678, p.S_OTP);
+	dprintf("OTP0x12345678: %x", p.GetProperty(p.CPUID, 0));
+	p.EraseProperty(p.CPUID, p.S_OTP);
+	dprintf("OTP:-2 %d", p.GetProperty(p.CPUID, -2));
+	dprintf("OTP: Host %s", p.GetProperty(p.HOSTNAME, "MyHost"));
+	p.SetProperty(p.HOSTNAME, p.T_STR, "Wunstorf", p.S_OTP);
+	dprintf("OTP: Host %s", p.GetProperty(p.HOSTNAME, "MyHost"));
+	p.SetProperty(p.CPUID, p.T_32BIT, 9876, p.S_OTP);
+	dprintf("OTP9876: %d", p.GetProperty(p.CPUID, 0));
+	dprintf("OTP: Host %s", p.GetProperty(p.HOSTNAME, "MyHost"));
+	
+	}
+#endif
+
+
+
+NVProperty_MBEDFlash::NVProperty_MBEDFlash(int propSizekB, bool erase)
+{
+	_flashIAP = new FlashIAP();
+	_flashIAP->init();
+	
+	_debug = false;
+	_propSizekB = propSizekB;
+	_pageSize = _flashIAP->get_page_size();
+	_numPages = _flashIAP->get_flash_size() / _pageSize;
+	_rowSize = _flashIAP->get_sector_size(_flashIAP->get_flash_start()); //  pageSize * 4;
+	_startAddress = (uint8_t*)_flashIAP->get_flash_start() + ((_numPages-(_propSizekB * 1024)/_pageSize) * _pageSize);
+	_endAddress = _startAddress + (_propSizekB * 1024);
+	_lastEntry = NULL;
+
+	if (_debug) {
+		dprintf("_propSizekB: %d kB", _propSizekB);
+		dprintf("_pageSize: %d", _pageSize);
+		dprintf("_numPages: %d", _numPages);
+		dprintf("_rowSize: %d", _rowSize);
+		dprintf("PageOffset: %d", _numPages-((_propSizekB * 1024)/_pageSize));
+		dprintf("total: %d", _pageSize * _numPages);
+		dprintf("_startAddress: %d", (int)_startAddress);
+	}
+	
+	_FlashInititalize(erase);
+}
+
+
+NVProperty_MBEDFlash::~NVProperty_MBEDFlash()
+{
+	_flashIAP->deinit();
+	delete _flashIAP;
+	_debug = true;
+	wait_ms(100);
+	_DumpAllEntires();
+	wait_ms(100);
+}
+
+
+void
+NVProperty_MBEDFlash::_FlashInititalize(bool force)
+{
+	_flash_header *fh = (_flash_header *)_startAddress;
+	if (fh->magic == FLASH_PROP_MAGIC && fh->version == FLASH_PROP_VERSION && fh->sizeKB == _propSizekB) {
+		if (_debug)
+			dprintf("Flash OK");
+		if (!force)
+			return;
+	}
+	
+	if (_debug)
+		dprintf("Formatting Flash");
+	
+	_flash_header f;
+	memset(&f, 0, sizeof(f));
+	f.magic = FLASH_PROP_MAGIC;
+	f.version = FLASH_PROP_VERSION;
+	f.sizeKB = _propSizekB;
+	
+	int count = (_propSizekB * 1024) / _rowSize;
+	int startRow = (int)_startAddress / _rowSize;
+	_FlashEraseRow(startRow, count);
+	_FlashWrite(_startAddress, &f, sizeof(f));
+}
+
+
+void
+NVProperty_MBEDFlash::_FlashEraseRow(int startRow, int count)
+{
+	// dprintf("_FlashEraseRow: startRow=%d, count=%d", startRow, count);
+	
+	for(int i = 0; i < count; i++) {
+		uint32_t *startAddr = (uint32_t *)((startRow + i) * _rowSize);
+		uint32_t *addr = startAddr;
+		bool foundData = false;
+		for (int offset = 0; offset < _rowSize; offset += sizeof(uint32_t)) {
+			if (*addr++ != 0xffffffff) {
+				foundData = true;
+				break;
+			}
+		}
+		if (_debug)
+			dprintf("_FlashEraseRow: addr=0x%x, count=%d (%s)", (unsigned int)startAddr, i,
+					foundData ? "erased" : "skipped");
+		if (!foundData)
+			continue;
+
+		_flashIAP->erase((startRow + i) * _rowSize, _rowSize);
+	}
+}
+
+
+/*
+ * Find out start page, number of pages
+ * Check if the page contins FF's than write, otherwise erase first
+ */
+void
+NVProperty_MBEDFlash::_FlashWrite(uint8_t *address, const void *d, size_t length)
+{
+	uint8_t *data = (uint8_t *)d;
+	
+	if (address < _startAddress || address > _startAddress + (_pageSize * _numPages))
+		return;
+	
+	int done = 0;
+	
+	do {
+		uint32_t startPage = (uint32_t)(address + done) / _pageSize;
+		int pageOffset = (uint32_t)(address + done) % _pageSize;
+		int pageWriteSize = _pageSize - pageOffset;
+		
+		if (_FlashIsCleared((uint8_t *)(startPage * _pageSize) + pageOffset, pageWriteSize)) {
+			// single page write
+			int writeLength = std::min(pageWriteSize, (int)length);
+			_FlashWritePage(startPage, pageOffset, data, writeLength);
+			length -= writeLength;
+			done += writeLength;
+			data += writeLength;
+		} else {
+			// row write
+			// load row copy
+			// erase row
+			// merge in new data
+			// write row in page copies
+			uint32_t startRow = (uint32_t)(address + done) / _rowSize;
+			int rowOffset = (uint32_t)(address + done) - (startRow * _rowSize);
+			int cplen = std::min((int)length, _rowSize - rowOffset);
+			uint8_t *saveddata = new uint8_t[_rowSize];
+			if (!saveddata)
+				return;
+
+			memcpy(saveddata, (uint8_t *)(startRow * _rowSize), _rowSize);
+			// dprintf("startRow=%d rowOffset=%d, cplen=%d", startRow, rowOffset, cplen);
+			
+			memcpy(saveddata + rowOffset, data, cplen);
+			
+			_FlashEraseRow(startRow);
+			for (int i = 0; i < _rowSize/_pageSize; i++) {
+				_FlashWritePage(((startRow * _rowSize) / _pageSize) + i, 0, saveddata + (i * _pageSize), _pageSize);
+			}
+			length -= cplen;
+			done += cplen;
+			data += cplen;
+
+			delete[] saveddata;
+		}
+	} while(length > 0);
+}
+
+
+bool
+NVProperty_MBEDFlash::_FlashIsCleared(uint8_t *address, int len)
+{
+	while (len > 0) {
+		if (*address++ != NVProperty::PROPERTIES_EOF) {
+			return false;
+		}
+		len--;
+	}
+	return true;
+}
+
+
+void
+NVProperty_MBEDFlash::_FlashWritePage(int page, int offset, uint8_t *data, int length)
+{
+	uint8_t *addr = (uint8_t *)(page * _pageSize) + offset;
+	if (length < 1)
+		return;
+	
+	_flashIAP->program(data, (uint32_t)addr, length);
+}
+
+
+
+int
+NVProperty_MBEDFlash::GetProperty(int key)
+{
+    return GetProperty64(key);
+}
+
+
+int64_t
+NVProperty_MBEDFlash::GetProperty64(int key)
+{
+	_flashEntry *p = _GetFlashEntry(key);
+	if (!p)
+		return NVProperty::NVP_ENOENT;
+
+    int64_t value = 0;
+	
+    switch(p->t.type) {
+		case NVProperty::T_BIT:
+			if (p->t.t_bit)
+				value = 1;
+			else
+				value = 0;
+			break;
+		case NVProperty::T_8BIT:
+			value = p->u.v_8bit;
+			break;
+		case NVProperty::T_16BIT:
+			{
+				int16_t v;
+				memcpy(&v, &p->u.v_16bit, sizeof(p->u.v_16bit));
+				value = v;
+			}
+			break;
+		case NVProperty::T_32BIT:
+			{
+				int32_t v;
+				memcpy(&v, &p->data.v_32bit, sizeof(p->data.v_32bit));
+				value = v;
+			}
+			break;
+		case NVProperty::T_64BIT:
+			memcpy(&value, p->data.v_64bit, sizeof(p->data.v_64bit));
+			break;
+		case NVProperty::T_STR:
+		case NVProperty::T_BLOB:
+			value = p->u.option.d_len;
+			break;
+	}
+    return value;
+}
+
+const char *
+NVProperty_MBEDFlash::GetPropertyStr(int key)
+{
+	_flashEntry *p = _GetFlashEntry(key);
+	if (!p || p->t.type != NVProperty::T_STR)
+		return NULL;
+    return strdup(p->data.v_str);
+}
+
+int
+NVProperty_MBEDFlash::GetPropertyBlob(int key, const void *blob, int *size)
+{
+	_flashEntry *p = _GetFlashEntry(key);
+	if (!p || p->t.type != NVProperty::T_BLOB)
+		return NVProperty::NVP_ENOENT;
+	
+	int cplen = std::min(*size, (int)p->u.option.d_len);
+	if (blob)
+		memcpy((void *)blob, p->data.v_blob, cplen);
+	*size = cplen;
+	
+    return NVProperty::NVP_OK;
+}
+
+
+int
+NVProperty_MBEDFlash::SetProperty(int key, int64_t value, int type)
+{
+	UNUSED(type);
+	uint8_t valbuf[FLASH_ENTRY_MIN_SIZE + sizeof(int64_t)];
+	_flashEntry *p = (_flashEntry *) valbuf;
+	int storeType;
+	
+	if (GetProperty64(key) == value) // no need to save it again.
+	    return NVProperty::NVP_OK;
+	
+	memset(valbuf, 0, sizeof(valbuf));
+	
+	if (value == 0 ||  value == 1)
+		storeType = NVProperty::T_BIT;
+	else if (value >= -128 && value < 128)
+		storeType = NVProperty::T_8BIT;
+	else if (value >= -32768 && value < 32768)
+		storeType = NVProperty::T_16BIT;
+	else if (value > -2147483647LL && value < 2147483648LL)
+		storeType = NVProperty::T_32BIT;
+	else
+		storeType = NVProperty::T_64BIT;
+	
+	p->key = key;
+	p->t.type = storeType;
+
+
+	switch(storeType) {
+		case NVProperty::T_BIT:
+			p->t.t_bit = value;
+			break;
+		case NVProperty::T_8BIT:
+			p->u.v_8bit = value;
+			break;
+		case NVProperty::T_16BIT:
+			p->u.v_16bit = value;
+			break;
+		case NVProperty::T_32BIT:
+			p->u.option.d_len = sizeof(p->data.v_32bit);
+			{
+				int32_t v = value;
+				memcpy(&p->data.v_32bit, &v, sizeof(p->data.v_32bit));
+			}
+			break;
+		case NVProperty::T_64BIT:
+			p->u.option.d_len = sizeof(p->data.v_64bit);
+			memcpy(p->data.v_64bit, &value, sizeof(p->data.v_64bit));
+			break;
+	}
+	int len;
+	if (storeType == NVProperty::T_BIT || storeType == NVProperty::T_8BIT || storeType == NVProperty::T_16BIT || storeType == NVProperty::T_32BIT) {
+		len = FLASH_ENTRY_MIN_SIZE;
+	} else { // 64/STR/BLOB
+		len = (FLASH_ENTRY_MIN_SIZE - 4) + p->u.option.d_len;
+		len += _GetFlashPaddingSize(len);
+	}
+	if ((uint8_t *)_lastEntry + len >= _endAddress) {
+		if (!_FlashReorgEntries(len))
+			return NVProperty::NVP_ERR_NOSPACE;
+	}
+
+	_FlashWrite((uint8_t *)_lastEntry, p, len);
+	_lastEntry = (_flashEntry *)((uint8_t *)_lastEntry + len);
+
+	// _DumpAllEntires();
+    return NVProperty::NVP_OK;
+}
+
+
+int
+NVProperty_MBEDFlash::SetPropertyStr(int key, const char *value, int type)
+{
+	if (type != NVProperty::T_STR)
+		return NVProperty::NVP_INVALD_PARM;
+	
+	_flashEntry *p = _GetFlashEntry(key);
+	if (p && p->t.type == NVProperty::T_STR && strcmp(p->data.v_str, value) == 0) {
+		return NVProperty::NVP_OK;
+	}
+
+	int err = NVProperty::NVP_OK;
+	
+	p = new _flashEntry();
+	if (!p)
+		return NVProperty::NVP_ERR_NOSPACE;
+	
+	p->key = key;
+	p->t.type = NVProperty::T_STR;
+	int cplen = std::min(strlen(value), sizeof(p->data.v_str)-1);
+	memcpy(p->data.v_str, value, cplen);
+	p->u.option.d_len = cplen + 1; // zero term
+	
+	int len = (FLASH_ENTRY_MIN_SIZE - 4) + p->u.option.d_len;
+	len += _GetFlashPaddingSize(len);
+
+	if ((uint8_t *)_lastEntry + len >= _endAddress) {
+		if (!_FlashReorgEntries(len)) {
+			err = NVProperty::NVP_ERR_NOSPACE;
+			goto done;
+		}
+	}
+
+	_FlashWrite((uint8_t *)_lastEntry, p, len);
+	_lastEntry = (_flashEntry *)((uint8_t *)_lastEntry + len);
+
+done:
+	delete[] p;
+	// _DumpAllEntires();
+    return err;
+}
+
+int
+NVProperty_MBEDFlash::SetPropertyBlob(int key, const void *blob, int size, int type)
+{
+	if (type != NVProperty::T_BLOB)
+		return NVProperty::NVP_INVALD_PARM;
+	
+	_flashEntry *p = _GetFlashEntry(key);
+	if (p && p->t.type == NVProperty::T_BLOB && size == p->u.option.d_len) { // check for duplicate
+		if (memcmp(blob, p->data.v_blob, size) == 0)
+			return NVProperty::NVP_OK;
+	}
+	int err = NVProperty::NVP_OK;
+	
+	p = new _flashEntry();
+	if (!p)
+		return NVProperty::NVP_ERR_NOSPACE;
+	
+	p->key = key;
+	p->t.type = NVProperty::T_BLOB;
+	int cplen = std::min(size, (int)sizeof(p->data.v_blob));
+	p->u.option.d_len = cplen;
+	memcpy(p->data.v_blob, blob, cplen);
+	
+	int len = (FLASH_ENTRY_MIN_SIZE - 4) + p->u.option.d_len;
+	len += _GetFlashPaddingSize(len);
+
+	if ((uint8_t *)_lastEntry + len >= _endAddress) {
+		if (!_FlashReorgEntries(len)) {
+			err = NVProperty::NVP_ERR_NOSPACE;
+			goto done;
+		}
+	}
+
+	_FlashWrite((uint8_t *)_lastEntry, p, len);
+	_lastEntry = (_flashEntry *)((uint8_t *)_lastEntry + len);
+
+done:
+	delete[] p;
+	// _DumpAllEntires();
+    return err;
+}
+
+int
+NVProperty_MBEDFlash::EraseProperty(int key)
+{
+	uint8_t valbuf[FLASH_ENTRY_MIN_SIZE];
+	_flashEntry *p = (_flashEntry *) valbuf;
+
+	_flashEntry *op = _GetFlashEntry(key);
+	if (!op)
+		return NVProperty::NVP_ENOENT;
+	if (op->t.deleted)
+		return NVProperty::NVP_OK;
+	
+	memset(valbuf, 0, sizeof(valbuf));
+	p->key = key;
+	p->t.type = op->t.type;
+	p->t.deleted = true;
+	
+	if ((uint8_t *)_lastEntry + FLASH_ENTRY_MIN_SIZE > _endAddress) {
+		if (!_FlashReorgEntries(FLASH_ENTRY_MIN_SIZE))
+			return NVProperty::NVP_ERR_NOSPACE;
+	}
+
+	_FlashWrite((uint8_t *)_lastEntry, p, FLASH_ENTRY_MIN_SIZE);
+	_lastEntry = (_flashEntry *)((uint8_t *)_lastEntry + FLASH_ENTRY_MIN_SIZE);
+
+	// _DumpAllEntires();
+	return NVProperty::NVP_OK;
+}
+
+int
+NVProperty_MBEDFlash::ReorgProperties(void)
+{
+	if (_FlashReorgEntries(FLASH_ENTRY_MIN_SIZE))
+    	return NVProperty::NVP_OK;
+	return NVProperty::NVP_ERR_NOSPACE;
+}
+
+
+int
+NVProperty_MBEDFlash::OpenPropertyStore(bool forWrite)
+{
+	UNUSED(forWrite);
+    return NVProperty::NVP_OK;
+}
+
+int
+NVProperty_MBEDFlash::ClosePropertyStore(bool flush)
+{
+    return NVProperty::NVP_OK;
+}
+
+#if 1
+void
+NVProperty_MBEDFlash::_DumpAllEntires(void)
+{
+	if (!_debug)
+		return;
+	
+	dprintf("------------- DumpAllEntires -------- ");
+
+	int index = 0;
+	_flashEntry *p = (_flashEntry *)(_startAddress + sizeof(_flash_header));
+	while((uint8_t *)p < _endAddress && p->key != NVProperty::PROPERTIES_EOF) {
+
+		int64_t value = 0;
+    	switch(p->t.type) {
+		case NVProperty::T_BIT:
+			if (p->t.t_bit)
+				value = 1;
+			else
+				value = 0;
+			break;
+		case NVProperty::T_8BIT:
+			value = p->u.v_8bit;
+			break;
+		case NVProperty::T_16BIT:
+			{
+				int16_t v;
+				memcpy(&v, &p->u.v_16bit, sizeof(p->u.v_16bit));
+				value = v;
+			}
+			break;
+		case NVProperty::T_32BIT:
+			{
+				int32_t v;
+				memcpy(&v, &p->data.v_32bit, sizeof(p->data.v_32bit));
+				value = v;
+			}
+			break;
+		case NVProperty::T_64BIT:
+			memcpy(&value, p->data.v_64bit, sizeof(p->data.v_64bit));
+			break;
+		case NVProperty::T_STR:
+		case NVProperty::T_BLOB:
+			value = p->u.option.d_len;
+			break;
+		}
+		index++;
+		if (p->t.deleted) {
+			dprintf("Dump[%.2d] Key: %d Type: %d deleted(%d)", index, p->key, p->t.type, p->t.deleted);
+
+		} else if (p->t.type == NVProperty::T_STR) {
+			dprintf("Dump[%.2d] Key: %d Type: %d value: %s", index, p->key, p->t.type, p->data.v_str);
+		} else if (p->t.type == NVProperty::T_BLOB) {
+			dprintf("Dump[%.2d] Key: %d Type: %d len: %d", index, p->key, p->t.type, p->u.option.d_len);
+			dump("Blob",  p->data.v_str, p->u.option.d_len);
+		} else {
+			if (p->t.type == NVProperty::T_64BIT) {
+				dprintf("Dump[%.2d] Key: %d Type: %d value: %lld (0x%llx)", index, p->key, p->t.type, value, value);
+			} else {
+				dprintf("Dump[%.2d] Key: %d Type: %d value: %ld (0x%x)", index, p->key, p->t.type, (int32_t)value, (unsigned int)value);
+			}
+		}
+		
+		p = (_flashEntry *)((uint8_t *)p + _GetFlashEntryLen(p));
+	}
+	int freebytes = _endAddress -(uint8_t *)_lastEntry;
+	if (_lastEntry)
+		dprintf("------ %d bytes free -------", freebytes);
+}
+#endif
+
+NVProperty_MBEDFlash::_flashEntry *
+NVProperty_MBEDFlash::_GetFlashEntry(int key, uint8_t *start)
+{
+	_flashEntry *p;
+
+	if (start)
+		p = (_flashEntry *)start;
+	else
+		p = (_flashEntry *)(_startAddress + sizeof(_flash_header));
+	_flashEntry *lastP = NULL;
+	while(true) {
+		if ((uint8_t*)p >= _endAddress || p->key == NVProperty::PROPERTIES_EOF) {
+			if ((uint8_t*)p <= _endAddress)
+				_lastEntry = p;
+			if (!lastP || lastP->t.deleted)
+				return NULL;
+			break;
+		}
+		if (p->key == key)
+			lastP = p;
+
+		p = (_flashEntry *)((uint8_t *)p + _GetFlashEntryLen(p));
+	}
+	return lastP;
+}
+
+
+int
+NVProperty_MBEDFlash::_GetFlashEntryLen(_flashEntry *p)
+{
+	int len = 0;
+	
+	switch(p->t.type) {
+		case NVProperty::T_64BIT:
+		case NVProperty::T_STR:
+		case NVProperty::T_BLOB:
+			len = (FLASH_ENTRY_MIN_SIZE - 4) + p->u.option.d_len;
+			len += _GetFlashPaddingSize(len);
+			break;
+		default:
+			len = FLASH_ENTRY_MIN_SIZE;
+	}
+	return len;
+}
+
+int
+NVProperty_MBEDFlash::_GetFlashPaddingSize(int len)
+{
+	int remain = len % FLASH_PADDING_SIZE;
+	
+	if (remain == 0)
+		return 0;
+	
+	return (len + FLASH_PADDING_SIZE - remain) - len;
+}
+
+
+int
+NVProperty_MBEDFlash::_FlashReorgEntries(int minRequiredSpace)
+{
+	if (_debug) {
+		dprintf("_FlashReorgEntries: start");
+		// _DumpAllEntires();
+	}
+
+	int totalLen = 0;
+	int freeSpace = 0;
+	
+	_flashEntry *p = (_flashEntry *)(_startAddress + sizeof(_flash_header));
+	while((uint8_t *)p < _endAddress && p->key != NVProperty::PROPERTIES_EOF) {
+		_flashEntry *k = _GetFlashEntry(p->key);
+		if (k == p) { // current entry is the lastest one.
+			totalLen += _GetFlashEntryLen(k);
+		}
+		p = (_flashEntry *)((uint8_t *)p + _GetFlashEntryLen(p));
+	}
+
+	if (_startAddress + sizeof(_flash_header) + totalLen + minRequiredSpace >= _endAddress)
+			return 0;
+	
+	freeSpace = _endAddress - (_startAddress + sizeof(_flash_header) + totalLen);
+	if (_debug)
+		dprintf("freeSpace: %d, totalLen: %d", freeSpace, totalLen);
+	
+	/*
+	 * Copy header
+	 * while (content {
+	 *	- scan until tmp page is full
+	 *	- write page
+	 * }
+	 * Erase remaining pages.
+	 *
+	 */
+	
+	p = (_flashEntry *)(_startAddress + sizeof(_flash_header));
+	uint8_t *saveddata = new uint8_t[_rowSize+sizeof(struct _flashEntry)];
+	if (!saveddata)
+		return 0;
+	uint8_t *t = saveddata;
+	int currentRow = (uint32_t)_startAddress / _rowSize;
+	int totalCopied = 0;
+	
+	t = saveddata;
+	memcpy(t, _startAddress, sizeof(_flash_header));
+	t += sizeof(_flash_header);
+	
+	while((uint8_t *)p < _endAddress && p->key != NVProperty::PROPERTIES_EOF) {
+		_flashEntry *k = _GetFlashEntry(p->key, (uint8_t *)p);
+		if (k == p) {	// current entry is the lastest one.
+			if (!p->t.deleted) {
+				int plen = _GetFlashEntryLen(p);
+				memcpy(t, p, plen);
+				t += plen;
+				totalCopied += plen;
+				if (t - saveddata >= _rowSize) { // copy page
+					_FlashEraseRow(currentRow);
+					_FlashWrite((uint8_t *)(currentRow++ * _rowSize), saveddata, _rowSize);
+					int remainLen = (t - saveddata) - _rowSize;
+					if (remainLen) {
+						memcpy(saveddata, t - remainLen, remainLen);
+					}
+					t = saveddata + remainLen;
+				}
+			}
+		}
+		p = (_flashEntry *)((uint8_t *)p + _GetFlashEntryLen(p));
+	}
+
+	if (t > saveddata) { // copy remaining
+		_FlashEraseRow(currentRow);
+		_FlashWrite((uint8_t *)(currentRow++ * _rowSize), saveddata, t - saveddata);
+	}
+
+	while((uint32_t)0 + currentRow * _rowSize < (uint32_t)_endAddress) {
+		_FlashEraseRow(currentRow++);
+	}
+	delete[] saveddata;
+	_GetFlashEntry(0); // inits the _lastEntry record
+
+	if (_debug) {
+		dprintf("_FlashReorgEntries: end");
+		_DumpAllEntires();
+	}
+	
+	return _endAddress - _startAddress -  (sizeof(_flash_header) + totalCopied);
+}
+
+
+#endif // __MBED__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NVProperty_MBEDFlash.h	Thu Jan 31 21:31:29 2019 +0100
@@ -0,0 +1,97 @@
+/*
+ * This is an unpublished work copyright
+ * (c) 2019 Helmut Tschemernjak
+ * 30826 Garbsen (Hannover) Germany
+ *
+ *
+ * Use is granted to registered RadioShuttle licensees only.
+ * Licensees must own a valid serial number and product code.
+ * Details see: www.radioshuttle.de
+ */
+
+#ifndef __NVPROPERTY_MBEDFLASH__
+#define __NVPROPERTY_MBEDFLASH__
+
+class NVProperty_MBEDFlash : public NVPropertyProviderInterface {
+public:
+	NVProperty_MBEDFlash(int propSizekB, bool erase);
+	~NVProperty_MBEDFlash();
+	
+    virtual int GetProperty(int key);
+    virtual int64_t GetProperty64(int key);
+    virtual int GetPropertyBlob(int key, const void *blob, int *size);
+    virtual const char *GetPropertyStr(int key);
+    virtual int SetProperty(int key, int64_t value, int type);
+    virtual int SetPropertyStr(int key, const char *value, int type);
+    virtual int SetPropertyBlob(int key, const void *blob, int size, int type);
+    virtual int EraseProperty(int key);
+    virtual int ReorgProperties(void);
+    virtual int OpenPropertyStore(bool forWrite = false);
+    virtual int ClosePropertyStore(bool flush = false);
+	
+private:
+	void _FlashInititalize(bool force = false);
+	void _FlashEraseRow(int startRow, int count = 1);
+	void _FlashWrite(uint8_t *address, const void *data, size_t length);
+	bool _FlashIsCleared(uint8_t *address, int len);
+	void _FlashWritePage(int page, int offset, uint8_t *data, int length);
+
+	struct _flash_header {
+		uint32_t magic;
+		uint16_t version;
+		uint16_t sizeKB;
+	};
+	
+	static const int FLASH_ENTRY_MIN_SIZE		= 8;
+	static const int MAX_DATA_ENTRY				= 256-FLASH_ENTRY_MIN_SIZE;
+	static const int FLASH_PADDING_SIZE			= 8; // writes sizes and alignment must be multiple of 64-bit,
+	
+	struct _flashEntry {
+		uint8_t key;	// Property key
+		struct {
+			uint8_t deleted	: 1; // this key has been deleted
+			uint8_t t_bit  	: 1; // contains the bool value
+			uint8_t reserv1	: 1; //
+			uint8_t reserv2	: 1; //
+			uint8_t type   	: 4; // NVPType
+		} t;
+		union {
+			int16_t v_16bit;
+			int8_t	v_8bit;
+			struct {
+				uint8_t d_len;				 // data length
+				uint8_t f_reserv1  		: 8;
+			} option;
+		} u;
+		union {
+			int32_t v_32bit;
+			int32_t v_64bit[2];	// use use 2 x 32-bit to avoid 64-bit struct padding
+			char v_str[MAX_DATA_ENTRY];
+			uint8_t v_blob[MAX_DATA_ENTRY];
+		} data;
+	};
+	
+	_flashEntry * _GetFlashEntry(int key, uint8_t *start = NULL);
+	int _GetFlashEntryLen(_flashEntry *k);
+	int _GetFlashPaddingSize(int len);
+	_flashEntry *_lastEntry;
+	void _DumpAllEntires(void);
+	int _FlashReorgEntries(int minRequiredSpace);
+	bool _debug;
+	int _propSizekB;
+	int _pageSize;
+	int _numPages;
+	int _rowSize;
+	FlashIAP *_flashIAP;
+	uint8_t *_startAddress;
+	uint8_t *_endAddress;
+
+	static const int FLASH_PROP_MAGIC = 0x4c6f5261; // "LORA"
+	static const int FLASH_PROP_VERSION = 3;
+	static const int _bootlLoaderSize = 8192;
+	static const int _lockRegions = 16;	// d21 lock regions are always 16 for the entire ram
+
+
+};
+
+#endif // __NVPROPERTY_MBEDLASH__
--- a/NVProperty_SRAM.cpp	Thu Jan 24 15:38:20 2019 +0100
+++ b/NVProperty_SRAM.cpp	Thu Jan 31 21:31:29 2019 +0100
@@ -43,10 +43,8 @@
         switch (it->second.type) {
             case NVProperty::T_STR:
                 return NVProperty::NVP_ENOENT;
-    	        break;
             case NVProperty::T_BLOB:
                 return NVProperty::NVP_ENOENT;
-                break;
             default:
                 return it->second.val32;
         }
@@ -63,10 +61,8 @@
         switch (it->second.type) {
             case NVProperty::T_STR:
                 return NVProperty::NVP_ENOENT;
-                break;
             case NVProperty::T_BLOB:
                 return NVProperty::NVP_ENOENT;
-                break;
             default:
                 return it->second.val64;
         }
@@ -101,7 +97,6 @@
 				if (blob)
                 	memcpy((void *)blob, it->second.data, *size);
                 return *size;
-                break;
             default:
                 break;
         }