NVProperty generic key value store using the MCU flash area.

Dependents:   Turtle_RadioShuttle

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers NVProperty_MBEDFlash.cpp Source File

NVProperty_MBEDFlash.cpp

00001 /*
00002  * This is an unpublished work copyright
00003  * (c) 2019 Helmut Tschemernjak
00004  * 30826 Garbsen (Hannover) Germany
00005  *
00006  *
00007  * Use is granted to registered RadioShuttle licensees only.
00008  * Licensees must own a valid serial number and product code.
00009  * Details see: www.radioshuttle.de
00010  */
00011 
00012 #ifdef __MBED__
00013 
00014 #include <mbed.h>
00015 #include "main.h"
00016 #include "arch.h"
00017 #include <algorithm>
00018 #include <NVPropertyProviderInterface.h>
00019 #include <NVProperty_MBEDFlash.h>
00020 #include <NVProperty.h>
00021 
00022 
00023 #if 0   // sample test code for a main app.
00024     {
00025         NVProperty p;
00026         p.OpenPropertyStore(true);
00027         
00028         dprintf("LORA_REMOTE_ID: %d", p.GetProperty(p.LORA_REMOTE_ID, 0));
00029         p.SetProperty(p.LORA_REMOTE_ID, p.T_32BIT, 123);
00030         dprintf("LORA_REMOTE_ID: %d", p.GetProperty(p.LORA_REMOTE_ID, 0));
00031         dprintf("Host: %s", p.GetProperty(p.HOSTNAME, "MyHost"));
00032         p.SetProperty(p.HOSTNAME, p.T_STR, "Wunstorf", p.S_FLASH);
00033         dprintf("Host: %s", p.GetProperty(p.HOSTNAME, "MyHost"));
00034         p.SetProperty(p.LORA_REMOTE_ID, p.T_32BIT, 456);
00035         dprintf("LORA_REMOTE_ID: %d", p.GetProperty(p.LORA_REMOTE_ID, 0));
00036         dprintf("Host: %s", p.GetProperty(p.HOSTNAME, "MyHost"));
00037     }
00038 #endif
00039 
00040 
00041 
00042 NVProperty_MBEDFlash::NVProperty_MBEDFlash(int propSizekB, bool erase)
00043 {
00044     _flashIAP = new FlashIAP();
00045     _flashIAP->init();
00046     
00047     // a min page size > 8 looks strange
00048     MBED_ASSERT(_flashIAP->get_page_size() <= sizeof(int64_t));
00049     
00050 
00051     _debug = false;
00052     _propSizekB = propSizekB;
00053     _pageSize = _flashIAP->get_page_size();
00054     _numPages = _flashIAP->get_flash_size() / _pageSize;
00055     _rowSize = _flashIAP->get_sector_size(_flashIAP->get_flash_start());
00056     MBED_ASSERT(((propSizekB *1024) % _rowSize) == 0);
00057     _startAddress = (uint8_t*)_flashIAP->get_flash_start() + ((_numPages-(_propSizekB * 1024)/_pageSize) * _pageSize);
00058     _endAddress = _startAddress + (_propSizekB * 1024);
00059     //  _flashErasedValue = _flashIAP->get_erase_value();
00060     _flashErasedValue = 0xff; // until the new mbed flashIAP->get_erase_value() is available
00061 #ifdef TARGET_STM32L0
00062     _flashErasedValue = 0x00;
00063 #endif
00064     _lastEntry = NULL;
00065 
00066     if (_debug) {
00067         dprintf("_propSizekB: %d kB", _propSizekB);
00068         dprintf("_pageSize: %d", _pageSize);
00069         dprintf("_numPages: %d", _numPages);
00070         dprintf("_rowSize: %d", _rowSize);
00071         dprintf("PageOffset: %d", _numPages-((_propSizekB * 1024)/_pageSize));
00072         dprintf("total: %d", _pageSize * _numPages);
00073         dprintf("_startAddress: %d", (int)_startAddress);
00074     }
00075     
00076     _FlashInititalize(erase);
00077     _GetFlashEntry(0); // inits the _lastEntry record
00078 }
00079 
00080 
00081 NVProperty_MBEDFlash::~NVProperty_MBEDFlash()
00082 {
00083     _flashIAP->deinit();
00084     delete _flashIAP;
00085 #if 0
00086     _debug = true;
00087     wait_ms(100);
00088     _DumpAllEntires();
00089     wait_ms(100);
00090     dump("buffer: ", _startAddress, 100);
00091     wait_ms(100);
00092 #endif
00093 }
00094 
00095 
00096 void
00097 NVProperty_MBEDFlash::_FlashInititalize(bool force)
00098 {
00099     _flash_header *fh = (_flash_header *)_startAddress;
00100     if (fh->magic == FLASH_PROP_MAGIC && fh->version == FLASH_PROP_VERSION && fh->sizeKB == _propSizekB) {
00101         if (_debug)
00102             dprintf("Flash OK");
00103         if (!force)
00104             return;
00105     }
00106     
00107     if (_debug)
00108         dprintf("Formatting Flash");
00109     
00110     _flash_header f;
00111     memset(&f, 0, sizeof(f));
00112     f.magic = FLASH_PROP_MAGIC;
00113     f.version = FLASH_PROP_VERSION;
00114     f.sizeKB = _propSizekB;
00115     
00116     int count = (_propSizekB * 1024) / _rowSize;
00117     int startRow = (int)_startAddress / _rowSize;
00118     _FlashEraseRow(startRow, count);
00119     _FlashWrite(_startAddress, &f, sizeof(f));
00120 }
00121 
00122 
00123 void
00124 NVProperty_MBEDFlash::_FlashEraseRow(int startRow, int count)
00125 {
00126     // dprintf("_FlashEraseRow: startRow=%d, count=%d", startRow, count);
00127     
00128     for(int i = 0; i < count; i++) {
00129         uint32_t *startAddr = (uint32_t *)((startRow + i) * _rowSize);
00130         uint32_t *addr = startAddr;
00131         bool foundData = false;
00132         uint32_t emtpyValue = _flashErasedValue << 24 | _flashErasedValue << 16 | _flashErasedValue << 8 | _flashErasedValue;
00133         for (int offset = 0; offset < _rowSize; offset += sizeof(uint32_t)) {
00134             if (*addr++ != emtpyValue) {
00135                 foundData = true;
00136                 break;
00137             }
00138         }
00139         if (_debug)
00140             dprintf("_FlashEraseRow: addr=0x%x, count=%d (%s)", (unsigned int)startAddr, i,
00141                     foundData ? "erased" : "skipped");
00142         if (!foundData)
00143             continue;
00144 
00145         _flashIAP->erase((startRow + i) * _rowSize, _rowSize);
00146     }
00147 }
00148 
00149 
00150 /*
00151  * Find out start page, number of pages
00152  * Check if the page contins FF's than write, otherwise erase first
00153  */
00154 void
00155 NVProperty_MBEDFlash::_FlashWrite(uint8_t *address, const void *d, size_t length)
00156 {
00157     uint8_t *data = (uint8_t *)d;
00158     
00159     if (address < _startAddress || address > _startAddress + (_pageSize * _numPages))
00160         return;
00161     
00162     int done = 0;
00163     
00164     do {
00165         uint32_t startPage = (uint32_t)(address + done) / _pageSize;
00166         int pageOffset = (uint32_t)(address + done) % _pageSize;
00167         int pageWriteSize = _pageSize - pageOffset;
00168         
00169         if (_FlashIsCleared((uint8_t *)(startPage * _pageSize) + pageOffset, pageWriteSize)) {
00170             // single page write
00171             int writeLength = std::min(pageWriteSize, (int)length);
00172             _FlashWritePage(startPage, pageOffset, data, writeLength);
00173             length -= writeLength;
00174             done += writeLength;
00175             data += writeLength;
00176         } else {
00177             // row write
00178             // load row copy
00179             // erase row
00180             // merge in new data
00181             // write row in page copies
00182             uint32_t startRow = (uint32_t)(address + done) / _rowSize;
00183             int rowOffset = (uint32_t)(address + done) - (startRow * _rowSize);
00184             int cplen = std::min((int)length, _rowSize - rowOffset);
00185             uint8_t *saveddata = new uint8_t[_rowSize];
00186             if (!saveddata)
00187                 return;
00188 
00189             memcpy(saveddata, (uint8_t *)(startRow * _rowSize), _rowSize);
00190             // dprintf("startRow=%d rowOffset=%d, cplen=%d", startRow, rowOffset, cplen);
00191             
00192             memcpy(saveddata + rowOffset, data, cplen);
00193             
00194             _FlashEraseRow(startRow);
00195             for (int i = 0; i < _rowSize/_pageSize; i++) {
00196                 _FlashWritePage(((startRow * _rowSize) / _pageSize) + i, 0, saveddata + (i * _pageSize), _pageSize);
00197             }
00198             length -= cplen;
00199             done += cplen;
00200             data += cplen;
00201 
00202             delete[] saveddata;
00203         }
00204     } while(length > 0);
00205 }
00206 
00207 
00208 bool
00209 NVProperty_MBEDFlash::_FlashIsCleared(uint8_t *address, int len)
00210 {
00211     while (len-- > 0) {
00212         if (*address++ != _flashErasedValue) {
00213             return false;
00214         }
00215     }
00216     return true;
00217 }
00218 
00219 
00220 void
00221 NVProperty_MBEDFlash::_FlashWritePage(int page, int offset, uint8_t *data, int length)
00222 {
00223     uint8_t *addr = (uint8_t *)(page * _pageSize) + offset;
00224     if (length < 1)
00225         return;
00226     
00227     _flashIAP->program(data, (uint32_t)addr, length);
00228 }
00229 
00230 
00231 
00232 int
00233 NVProperty_MBEDFlash::GetProperty(int key)
00234 {
00235     return GetProperty64(key);
00236 }
00237 
00238 
00239 int64_t
00240 NVProperty_MBEDFlash::GetProperty64(int key)
00241 {
00242     _flashEntry *p = _GetFlashEntry(key);
00243     if (!p)
00244         return NVProperty::NVP_ENOENT;
00245 
00246     int64_t value = 0;
00247     
00248     switch(p->t.type) {
00249         case NVProperty::T_BIT:
00250             if (p->t.t_bit)
00251                 value = 1;
00252             else
00253                 value = 0;
00254             break;
00255         case NVProperty::T_8BIT:
00256             value = p->u.v_8bit;
00257             break;
00258         case NVProperty::T_16BIT:
00259             {
00260                 int16_t v;
00261                 memcpy(&v, &p->u.v_16bit, sizeof(p->u.v_16bit));
00262                 value = v;
00263             }
00264             break;
00265         case NVProperty::T_32BIT:
00266             {
00267                 int32_t v;
00268                 memcpy(&v, &p->data.v_32bit, sizeof(p->data.v_32bit));
00269                 value = v;
00270             }
00271             break;
00272         case NVProperty::T_64BIT:
00273             memcpy(&value, p->data.v_64bit, sizeof(p->data.v_64bit));
00274             break;
00275         case NVProperty::T_STR:
00276         case NVProperty::T_BLOB:
00277             value = p->u.option.d_len;
00278             break;
00279     }
00280     return value;
00281 }
00282 
00283 const char *
00284 NVProperty_MBEDFlash::GetPropertyStr(int key)
00285 {
00286     _flashEntry *p = _GetFlashEntry(key);
00287     if (!p || p->t.type != NVProperty::T_STR)
00288         return NULL;
00289     return strdup(p->data.v_str);
00290 }
00291 
00292 int
00293 NVProperty_MBEDFlash::GetPropertyBlob(int key, const void *blob, int *size)
00294 {
00295     _flashEntry *p = _GetFlashEntry(key);
00296     if (!p || p->t.type != NVProperty::T_BLOB)
00297         return NVProperty::NVP_ENOENT;
00298     
00299     int cplen = std::min(*size, (int)p->u.option.d_len);
00300     if (blob)
00301         memcpy((void *)blob, p->data.v_blob, cplen);
00302     *size = cplen;
00303     
00304     return NVProperty::NVP_OK;
00305 }
00306 
00307 
00308 int
00309 NVProperty_MBEDFlash::SetProperty(int key, int64_t value, int type)
00310 {
00311     UNUSED(type);
00312     uint8_t valbuf[16];
00313     _flashEntry *p = (_flashEntry *) valbuf;
00314     int storeType;
00315     
00316     if (GetProperty64(key) == value) // no need to save it again.
00317         return NVProperty::NVP_OK;
00318     
00319     memset(valbuf, 0, sizeof(valbuf));
00320     
00321     if (value == 0 ||  value == 1)
00322         storeType = NVProperty::T_BIT;
00323     else if (value >= -128 && value < 128)
00324         storeType = NVProperty::T_8BIT;
00325     else if (value >= -32768 && value < 32768)
00326         storeType = NVProperty::T_16BIT;
00327     else if (value > -2147483647LL && value < 2147483648LL)
00328         storeType = NVProperty::T_32BIT;
00329     else
00330         storeType = NVProperty::T_64BIT;
00331     
00332     p->key = key;
00333     p->t.type = storeType;
00334 
00335 
00336     switch(storeType) {
00337         case NVProperty::T_BIT:
00338             p->t.t_bit = value;
00339             break;
00340         case NVProperty::T_8BIT:
00341             p->u.v_8bit = value;
00342             break;
00343         case NVProperty::T_16BIT:
00344             p->u.v_16bit = value;
00345             break;
00346         case NVProperty::T_32BIT:
00347             p->u.option.d_len = sizeof(p->data.v_32bit);
00348             {
00349                 int32_t v = value;
00350                 memcpy(&p->data.v_32bit, &v, sizeof(p->data.v_32bit));
00351             }
00352             break;
00353         case NVProperty::T_64BIT:
00354             p->u.option.d_len = sizeof(p->data.v_64bit);
00355             memcpy(p->data.v_64bit, &value, sizeof(p->data.v_64bit));
00356             break;
00357     }
00358     int len;
00359     if (storeType == NVProperty::T_BIT)
00360         len = FLASH_ENTRY_HEADER_SHORT;
00361     else if (storeType == NVProperty::T_8BIT || storeType == NVProperty::T_16BIT)
00362         len = FLASH_ENTRY_HEADER;
00363     else // 32/64/STR/BLOB
00364         len = FLASH_ENTRY_HEADER + p->u.option.d_len;
00365     len += _GetFlashPaddingSize(len);
00366     if ((uint8_t *)_lastEntry + len >= _endAddress) {
00367         if (!_FlashReorgEntries(len))
00368             return NVProperty::NVP_ERR_NOSPACE;
00369     }
00370 
00371     _FlashWrite((uint8_t *)_lastEntry, p, len);
00372     _lastEntry = (_flashEntry *)((uint8_t *)_lastEntry + len);
00373 
00374     // _DumpAllEntires();
00375     return NVProperty::NVP_OK;
00376 }
00377 
00378 
00379 int
00380 NVProperty_MBEDFlash::SetPropertyStr(int key, const char *value, int type)
00381 {
00382     if (type != NVProperty::T_STR)
00383         return NVProperty::NVP_INVALD_PARM;
00384     
00385     _flashEntry *p = _GetFlashEntry(key);
00386     if (p && p->t.type == NVProperty::T_STR && strcmp(p->data.v_str, value) == 0) {
00387         return NVProperty::NVP_OK;
00388     }
00389 
00390     int err = NVProperty::NVP_OK;
00391     
00392     p = new _flashEntry();
00393     if (!p)
00394         return NVProperty::NVP_ERR_NOSPACE;
00395     
00396     p->key = key;
00397     p->t.type = NVProperty::T_STR;
00398     int cplen = std::min(strlen(value), sizeof(p->data.v_str)-1);
00399     memcpy(p->data.v_str, value, cplen);
00400     p->u.option.d_len = cplen + 1; // zero term
00401     
00402     int len = FLASH_ENTRY_HEADER + p->u.option.d_len;
00403     len += _GetFlashPaddingSize(len);
00404 
00405     if ((uint8_t *)_lastEntry + len >= _endAddress) {
00406         if (!_FlashReorgEntries(len)) {
00407             err = NVProperty::NVP_ERR_NOSPACE;
00408             goto done;
00409         }
00410     }
00411 
00412     _FlashWrite((uint8_t *)_lastEntry, p, len);
00413     _lastEntry = (_flashEntry *)((uint8_t *)_lastEntry + len);
00414 
00415 done:
00416     delete[] p;
00417     // _DumpAllEntires();
00418     return err;
00419 }
00420 
00421 int
00422 NVProperty_MBEDFlash::SetPropertyBlob(int key, const void *blob, int size, int type)
00423 {
00424     if (type != NVProperty::T_BLOB)
00425         return NVProperty::NVP_INVALD_PARM;
00426     
00427     _flashEntry *p = _GetFlashEntry(key);
00428     if (p && p->t.type == NVProperty::T_BLOB && size == p->u.option.d_len) { // check for duplicate
00429         if (memcmp(blob, p->data.v_blob, size) == 0)
00430             return NVProperty::NVP_OK;
00431     }
00432     int err = NVProperty::NVP_OK;
00433     
00434     p = new _flashEntry();
00435     if (!p)
00436         return NVProperty::NVP_ERR_NOSPACE;
00437     
00438     p->key = key;
00439     p->t.type = NVProperty::T_BLOB;
00440     int cplen = std::min(size, (int)sizeof(p->data.v_blob));
00441     p->u.option.d_len = cplen;
00442     memcpy(p->data.v_blob, blob, cplen);
00443     
00444     int len = FLASH_ENTRY_HEADER + p->u.option.d_len;
00445     len += _GetFlashPaddingSize(len);
00446 
00447     if ((uint8_t *)_lastEntry + len >= _endAddress) {
00448         if (!_FlashReorgEntries(len)) {
00449             err = NVProperty::NVP_ERR_NOSPACE;
00450             goto done;
00451         }
00452     }
00453 
00454     _FlashWrite((uint8_t *)_lastEntry, p, len);
00455     _lastEntry = (_flashEntry *)((uint8_t *)_lastEntry + len);
00456 
00457 done:
00458     delete[] p;
00459     // _DumpAllEntires();
00460     return err;
00461 }
00462 
00463 int
00464 NVProperty_MBEDFlash::EraseProperty(int key)
00465 {
00466     uint8_t valbuf[16];
00467     _flashEntry *p = (_flashEntry *) valbuf;
00468 
00469     _flashEntry *op = _GetFlashEntry(key);
00470     if (!op)
00471         return NVProperty::NVP_ENOENT;
00472     if (op->t.deleted)
00473         return NVProperty::NVP_OK;
00474     
00475     memset(valbuf, 0, sizeof(valbuf));
00476     p->key = key;
00477     p->t.type = op->t.type;
00478     p->t.deleted = true;
00479     
00480     int len = FLASH_ENTRY_HEADER_SHORT;
00481     len += _GetFlashPaddingSize(len);
00482     
00483     if ((uint8_t *)_lastEntry + len > _endAddress) {
00484             if (!_FlashReorgEntries(len))
00485                 return NVProperty::NVP_ERR_NOSPACE;
00486     }
00487 
00488     _FlashWrite((uint8_t *)_lastEntry, p, len);
00489     _lastEntry = (_flashEntry *)((uint8_t *)_lastEntry + len);
00490 
00491     // _DumpAllEntires();
00492     return NVProperty::NVP_OK;
00493 }
00494 
00495 int
00496 NVProperty_MBEDFlash::ReorgProperties(void)
00497 {
00498     if (_FlashReorgEntries(FLASH_ENTRY_HEADER))
00499         return NVProperty::NVP_OK;
00500     return NVProperty::NVP_ERR_NOSPACE;
00501 }
00502 
00503 
00504 int
00505 NVProperty_MBEDFlash::OpenPropertyStore(bool forWrite)
00506 {
00507     UNUSED(forWrite);
00508     return NVProperty::NVP_OK;
00509 }
00510 
00511 int
00512 NVProperty_MBEDFlash::ClosePropertyStore(bool flush)
00513 {
00514     return NVProperty::NVP_OK;
00515 }
00516 
00517 #if 1
00518 void
00519 NVProperty_MBEDFlash::_DumpAllEntires(void)
00520 {
00521     if (!_debug)
00522         return;
00523     
00524     dprintf("------------- DumpAllEntires -------- ");
00525 
00526     int index = 0;
00527     _flashEntry *p = (_flashEntry *)(_startAddress + sizeof(_flash_header));
00528     while((uint8_t *)p < _endAddress && p->key != _flashErasedValue) {
00529 
00530         int64_t value = 0;
00531         switch(p->t.type) {
00532         case NVProperty::T_BIT:
00533             if (p->t.t_bit)
00534                 value = 1;
00535             else
00536                 value = 0;
00537             break;
00538         case NVProperty::T_8BIT:
00539             value = p->u.v_8bit;
00540             break;
00541         case NVProperty::T_16BIT:
00542             {
00543                 int16_t v;
00544                 memcpy(&v, &p->u.v_16bit, sizeof(p->u.v_16bit));
00545                 value = v;
00546             }
00547             break;
00548         case NVProperty::T_32BIT:
00549             {
00550                 int32_t v;
00551                 memcpy(&v, &p->data.v_32bit, sizeof(p->data.v_32bit));
00552                 value = v;
00553             }
00554             break;
00555         case NVProperty::T_64BIT:
00556             memcpy(&value, p->data.v_64bit, sizeof(p->data.v_64bit));
00557             break;
00558         case NVProperty::T_STR:
00559         case NVProperty::T_BLOB:
00560             value = p->u.option.d_len;
00561             break;
00562         }
00563         index++;
00564         if (p->t.deleted) {
00565             dprintf("Dump[%.2d] Key: %d Type: %d deleted(%d)", index, p->key, p->t.type, p->t.deleted);
00566 
00567         } else if (p->t.type == NVProperty::T_STR) {
00568             dprintf("Dump[%.2d] Key: %d Type: %d value: %s", index, p->key, p->t.type, p->data.v_str);
00569         } else if (p->t.type == NVProperty::T_BLOB) {
00570             dprintf("Dump[%.2d] Key: %d Type: %d len: %d", index, p->key, p->t.type, p->u.option.d_len);
00571             dump("Blob",  p->data.v_str, p->u.option.d_len);
00572         } else {
00573             if (p->t.type == NVProperty::T_64BIT) {
00574                 dprintf("Dump[%.2d] Key: %d Type: %d value: %lld (0x%llx)", index, p->key, p->t.type, value, value);
00575             } else {
00576                 dprintf("Dump[%.2d] Key: %d Type: %d value: %ld (0x%x)", index, p->key, p->t.type, (int32_t)value, (unsigned int)value);
00577             }
00578         }
00579         
00580         p = (_flashEntry *)((uint8_t *)p + _GetFlashEntryLen(p));
00581     }
00582     int freebytes = _endAddress -(uint8_t *)_lastEntry;
00583     if (_lastEntry)
00584         dprintf("------ %d bytes free -------", freebytes);
00585 }
00586 #endif
00587 
00588 NVProperty_MBEDFlash::_flashEntry *
00589 NVProperty_MBEDFlash::_GetFlashEntry(int key, uint8_t *start)
00590 {
00591     _flashEntry *p;
00592 
00593     if (start)
00594         p = (_flashEntry *)start;
00595     else
00596         p = (_flashEntry *)(_startAddress + sizeof(_flash_header));
00597     _flashEntry *lastP = NULL;
00598     while(true) {
00599         if ((uint8_t*)p >= _endAddress || p->key == _flashErasedValue) {
00600             if ((uint8_t*)p <= _endAddress)
00601                 _lastEntry = p;
00602             if (!lastP || lastP->t.deleted)
00603                 return NULL;
00604             break;
00605         }
00606         if (p->key == key)
00607             lastP = p;
00608 
00609         p = (_flashEntry *)((uint8_t *)p + _GetFlashEntryLen(p));
00610     }
00611     return lastP;
00612 }
00613 
00614 
00615 int
00616 NVProperty_MBEDFlash::_GetFlashEntryLen(_flashEntry *p)
00617 {
00618     int len = 0;
00619     
00620     if (p->t.type == NVProperty::T_BIT || p->t.deleted)
00621         len = FLASH_ENTRY_HEADER_SHORT;
00622     else if (p->t.type == NVProperty::T_8BIT || p->t.type == NVProperty::T_16BIT)
00623         len = FLASH_ENTRY_HEADER;
00624     else
00625         len = FLASH_ENTRY_HEADER + p->u.option.d_len;
00626         
00627     len += _GetFlashPaddingSize(len);
00628 
00629     return len;
00630 }
00631 
00632 int
00633 NVProperty_MBEDFlash::_GetFlashPaddingSize(int len)
00634 {
00635     int remain = len % _pageSize;
00636     
00637     if (remain == 0)
00638         return 0;
00639     
00640     return (len + _pageSize - remain) - len;
00641 }
00642 
00643 
00644 int
00645 NVProperty_MBEDFlash::_FlashReorgEntries(int minRequiredSpace)
00646 {
00647     if (_debug) {
00648         dprintf("_FlashReorgEntries: start");
00649         // _DumpAllEntires();
00650     }
00651 
00652     int totalLen = 0;
00653     int freeSpace = 0;
00654     
00655     _flashEntry *p = (_flashEntry *)(_startAddress + sizeof(_flash_header));
00656     while((uint8_t *)p < _endAddress && p->key != _flashErasedValue) {
00657         _flashEntry *k = _GetFlashEntry(p->key);
00658         if (k == p) { // current entry is the lastest one.
00659             totalLen += _GetFlashEntryLen(k);
00660         }
00661         p = (_flashEntry *)((uint8_t *)p + _GetFlashEntryLen(p));
00662     }
00663 
00664     if (_startAddress + sizeof(_flash_header) + totalLen + minRequiredSpace >= _endAddress)
00665             return 0;
00666     
00667     freeSpace = _endAddress - (_startAddress + sizeof(_flash_header) + totalLen);
00668     if (_debug)
00669         dprintf("freeSpace: %d, totalLen: %d", freeSpace, totalLen);
00670     
00671     /*
00672      * Copy header
00673      * while (content {
00674      *  - scan until tmp page is full
00675      *  - write page
00676      * }
00677      * Erase remaining pages.
00678      *
00679      */
00680     
00681     p = (_flashEntry *)(_startAddress + sizeof(_flash_header));
00682     uint8_t *saveddata = new uint8_t[_rowSize+sizeof(struct _flashEntry)];
00683     if (!saveddata)
00684         return 0;
00685     uint8_t *t = saveddata;
00686     int currentRow = (uint32_t)_startAddress / _rowSize;
00687     int totalCopied = 0;
00688     
00689     t = saveddata;
00690     memcpy(t, _startAddress, sizeof(_flash_header));
00691     t += sizeof(_flash_header);
00692     
00693     while((uint8_t *)p < _endAddress && p->key != _flashErasedValue) {
00694         _flashEntry *k = _GetFlashEntry(p->key, (uint8_t *)p);
00695         if (k == p) {   // current entry is the lastest one.
00696             if (!p->t.deleted) {
00697                 int plen = _GetFlashEntryLen(p);
00698                 memcpy(t, p, plen);
00699                 t += plen;
00700                 totalCopied += plen;
00701                 if (t - saveddata >= _rowSize) { // copy page
00702                     _FlashEraseRow(currentRow);
00703                     _FlashWrite((uint8_t *)(currentRow++ * _rowSize), saveddata, _rowSize);
00704                     int remainLen = (t - saveddata) - _rowSize;
00705                     if (remainLen) {
00706                         memcpy(saveddata, t - remainLen, remainLen);
00707                     }
00708                     t = saveddata + remainLen;
00709                 }
00710             }
00711         }
00712         p = (_flashEntry *)((uint8_t *)p + _GetFlashEntryLen(p));
00713     }
00714 
00715     if (t > saveddata) { // copy remaining
00716         _FlashEraseRow(currentRow);
00717         _FlashWrite((uint8_t *)(currentRow++ * _rowSize), saveddata, t - saveddata);
00718     }
00719 
00720     while((uint32_t)0 + currentRow * _rowSize < (uint32_t)_endAddress) {
00721         _FlashEraseRow(currentRow++);
00722     }
00723     delete[] saveddata;
00724     _GetFlashEntry(0); // inits the _lastEntry record
00725 
00726     if (_debug) {
00727         dprintf("_FlashReorgEntries: end");
00728         _DumpAllEntires();
00729     }
00730     
00731     return _endAddress - _startAddress -  (sizeof(_flash_header) + totalCopied);
00732 }
00733 
00734 
00735 #endif // __MBED__