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_L4OTP.cpp Source File

NVProperty_L4OTP.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 TARGET_STM32L4
00013 
00014 #include <mbed.h>
00015 #include "main.h"
00016 #include "arch.h"
00017 #include <algorithm>
00018 #include <NVPropertyProviderInterface.h>
00019 #include <NVProperty_L4OTP.h>
00020 #include <NVProperty.h>
00021 
00022 
00023 #if 0   // sample test code for a main app.
00024     {
00025     NVProperty p;
00026     
00027     p.OpenPropertyStore(true);
00028     dprintf("OTP--1: %d", p.GetProperty(p.CPUID, -1));
00029     p.SetProperty(p.CPUID, p.T_32BIT, 123, p.S_OTP);
00030     dprintf("OTP123: %d", p.GetProperty(p.CPUID, 0));
00031     p.SetProperty(p.CPUID, p.T_32BIT, 0x12345678, p.S_OTP);
00032     dprintf("OTP0x12345678: %x", p.GetProperty(p.CPUID, 0));
00033     p.EraseProperty(p.CPUID, p.S_OTP);
00034     dprintf("OTP:-2 %d", p.GetProperty(p.CPUID, -2));
00035     dprintf("OTP: Host %s", p.GetProperty(p.HOSTNAME, "MyHost"));
00036     p.SetProperty(p.HOSTNAME, p.T_STR, "Wunstorf", p.S_OTP);
00037     dprintf("OTP: Host %s", p.GetProperty(p.HOSTNAME, "MyHost"));
00038     p.SetProperty(p.CPUID, p.T_32BIT, 9876, p.S_OTP);
00039     dprintf("OTP9876: %d", p.GetProperty(p.CPUID, 0));
00040     dprintf("OTP: Host %s", p.GetProperty(p.HOSTNAME, "MyHost"));
00041     
00042     }
00043 #endif
00044 
00045 // #define OTP_TEST_IN_RAM // test OTP in RAM
00046 
00047 
00048 NVProperty_L4OTP::NVProperty_L4OTP()
00049 {
00050     _debug = false;
00051     _propSize = 1 * 1024;                   // no define in HAL laye
00052     _startAddress = (uint8_t *) 0x1FFF7000; // no define in HAL layer
00053 
00054 #ifdef OTP_TEST_IN_RAM
00055     static uint8_t *savedStart;
00056     if (!savedStart) {
00057         _startAddress = (uint8_t *) malloc(512);
00058         memset(_startAddress, _flashErasedValue, 512);
00059         savedStart = _startAddress;
00060     } else {
00061         _startAddress = savedStart;
00062     }
00063 #endif
00064     
00065     _endAddress = _startAddress + (_propSize);
00066     _lastEntry = NULL;
00067     
00068     _FlashInititalize();
00069     _GetFlashEntry(0); // inits the _lastEntry record
00070 }
00071 
00072 
00073 NVProperty_L4OTP::~NVProperty_L4OTP()
00074 {
00075 #ifdef OTP_TEST_IN_RAM
00076     _debug = true;
00077     _DumpAllEntires();
00078     wait_ms(100);
00079     dump("_startAddress", _startAddress, 100);
00080 #endif
00081 }
00082 
00083 
00084 void
00085 NVProperty_L4OTP::_FlashInititalize(void)
00086 {
00087     _flash_header *fh = (_flash_header *)_startAddress;
00088     if (fh->magic == FLASH_PROP_MAGIC && fh->version == FLASH_PROP_VERSION && fh->size == _propSize) {
00089         return;
00090     }
00091     
00092     uint8_t *p = _startAddress;
00093     for (int i = 0; i < (int)sizeof(_flash_header); i++) {
00094         if (*p++ != _flashErasedValue)
00095             return; // invalid data
00096     }
00097     
00098     _flash_header f;
00099     memset(&f, 0, sizeof(f));
00100     f.magic = FLASH_PROP_MAGIC;
00101     f.version = FLASH_PROP_VERSION;
00102     f.size = _propSize;
00103     
00104     _OTPWrite(_startAddress, &f, sizeof(f));
00105 }
00106 
00107 
00108 int
00109 NVProperty_L4OTP::GetProperty(int key)
00110 {
00111     return GetProperty64(key);
00112 }
00113 
00114 
00115 int64_t
00116 NVProperty_L4OTP::GetProperty64(int key)
00117 {
00118     _flashEntry *p = _GetFlashEntry(key);
00119     if (!p)
00120         return NVProperty::NVP_ENOENT;
00121 
00122     int64_t value = 0;
00123     
00124     switch(p->t.type) {
00125         case NVProperty::T_BIT:
00126             if (p->t.t_bit)
00127                 value = 1;
00128             else
00129                 value = 0;
00130             break;
00131         case NVProperty::T_8BIT:
00132             value = p->u.v_8bit;
00133             break;
00134         case NVProperty::T_16BIT:
00135             {
00136                 int16_t v;
00137                 memcpy(&v, &p->u.v_16bit, sizeof(p->u.v_16bit));
00138                 value = v;
00139             }
00140             break;
00141         case NVProperty::T_32BIT:
00142             {
00143                 int32_t v;
00144                 memcpy(&v, &p->data.v_32bit, sizeof(p->data.v_32bit));
00145                 value = v;
00146             }
00147             break;
00148         case NVProperty::T_64BIT:
00149             memcpy(&value, p->data.v_64bit, sizeof(p->data.v_64bit));
00150             break;
00151         case NVProperty::T_STR:
00152         case NVProperty::T_BLOB:
00153             value = p->u.option.d_len;
00154             break;
00155     }
00156     return value;
00157 }
00158 
00159 const char *
00160 NVProperty_L4OTP::GetPropertyStr(int key)
00161 {
00162     _flashEntry *p = _GetFlashEntry(key);
00163     if (!p || p->t.type != NVProperty::T_STR)
00164         return NULL;
00165     return strdup(p->data.v_str);
00166 }
00167 
00168 int
00169 NVProperty_L4OTP::GetPropertyBlob(int key, const void *blob, int *size)
00170 {
00171     _flashEntry *p = _GetFlashEntry(key);
00172     if (!p || p->t.type != NVProperty::T_BLOB)
00173         return NVProperty::NVP_ENOENT;
00174     
00175     int cplen = std::min(*size, (int)p->u.option.d_len);
00176     if (blob)
00177         memcpy((void *)blob, p->data.v_blob, cplen);
00178     *size = cplen;
00179     
00180     return NVProperty::NVP_OK;
00181 }
00182 
00183 
00184 int
00185 NVProperty_L4OTP::SetProperty(int key, int64_t value, int type)
00186 {
00187     UNUSED(type);
00188     uint8_t valbuf[FLASH_ENTRY_MIN_SIZE + sizeof(int64_t)];
00189     _flashEntry *p = (_flashEntry *) valbuf;
00190     int storeType;
00191     
00192     if (GetProperty64(key) == value) // no need to save it again.
00193         return NVProperty::NVP_OK;
00194     
00195     memset(valbuf, 0, sizeof(valbuf));
00196     
00197     if (value == 0 ||  value == 1)
00198         storeType = NVProperty::T_BIT;
00199     else if (value >= -128 && value < 128)
00200         storeType = NVProperty::T_8BIT;
00201     else if (value >= -32768 && value < 32768)
00202         storeType = NVProperty::T_16BIT;
00203     else if (value > -2147483647LL && value < 2147483648LL)
00204         storeType = NVProperty::T_32BIT;
00205     else
00206         storeType = NVProperty::T_64BIT;
00207     
00208     p->key = key;
00209     p->t.type = storeType;
00210 
00211 
00212     switch(storeType) {
00213         case NVProperty::T_BIT:
00214             p->t.t_bit = value;
00215             break;
00216         case NVProperty::T_8BIT:
00217             p->u.v_8bit = value;
00218             break;
00219         case NVProperty::T_16BIT:
00220             p->u.v_16bit = value;
00221             break;
00222         case NVProperty::T_32BIT:
00223             p->u.option.d_len = sizeof(p->data.v_32bit);
00224             {
00225                 int32_t v = value;
00226                 memcpy(&p->data.v_32bit, &v, sizeof(p->data.v_32bit));
00227             }
00228             break;
00229         case NVProperty::T_64BIT:
00230             p->u.option.d_len = sizeof(p->data.v_64bit);
00231             memcpy(p->data.v_64bit, &value, sizeof(p->data.v_64bit));
00232             break;
00233     }
00234     int len;
00235     if (storeType == NVProperty::T_BIT || storeType == NVProperty::T_8BIT || storeType == NVProperty::T_16BIT || storeType == NVProperty::T_32BIT) {
00236         len = FLASH_ENTRY_MIN_SIZE;
00237     } else { // 64/STR/BLOB
00238         len = (FLASH_ENTRY_MIN_SIZE - 4) + p->u.option.d_len;
00239         len += _GetFlashPaddingSize(len);
00240     }
00241     if ((uint8_t *)_lastEntry + len >= _endAddress) {
00242         if (!_FlashReorgEntries(len))
00243             return NVProperty::NVP_ERR_NOSPACE;
00244     }
00245 
00246     _OTPWrite((uint8_t *)_lastEntry, p, len);
00247     _lastEntry = (_flashEntry *)((uint8_t *)_lastEntry + len);
00248 
00249     // _DumpAllEntires();
00250     return NVProperty::NVP_OK;
00251 }
00252 
00253 
00254 int
00255 NVProperty_L4OTP::SetPropertyStr(int key, const char *value, int type)
00256 {
00257     if (type != NVProperty::T_STR)
00258         return NVProperty::NVP_INVALD_PARM;
00259     
00260     _flashEntry *p = _GetFlashEntry(key);
00261     if (p && p->t.type == NVProperty::T_STR && strcmp(p->data.v_str, value) == 0) {
00262         return NVProperty::NVP_OK;
00263     }
00264 
00265     int err = NVProperty::NVP_OK;
00266     
00267     p = new _flashEntry();
00268     if (!p)
00269         return NVProperty::NVP_ERR_NOSPACE;
00270     
00271     p->key = key;
00272     p->t.type = NVProperty::T_STR;
00273     int cplen = std::min(strlen(value), sizeof(p->data.v_str)-1);
00274     memcpy(p->data.v_str, value, cplen);
00275     p->u.option.d_len = cplen + 1; // zero term
00276     
00277     int len = (FLASH_ENTRY_MIN_SIZE - 4) + p->u.option.d_len;
00278     len += _GetFlashPaddingSize(len);
00279 
00280     if ((uint8_t *)_lastEntry + len >= _endAddress) {
00281         if (!_FlashReorgEntries(len)) {
00282             err = NVProperty::NVP_ERR_NOSPACE;
00283             goto done;
00284         }
00285     }
00286 
00287     _OTPWrite((uint8_t *)_lastEntry, p, len);
00288     _lastEntry = (_flashEntry *)((uint8_t *)_lastEntry + len);
00289 
00290 done:
00291     delete[] p;
00292     // _DumpAllEntires();
00293     return err;
00294 }
00295 
00296 int
00297 NVProperty_L4OTP::SetPropertyBlob(int key, const void *blob, int size, int type)
00298 {
00299     if (type != NVProperty::T_BLOB)
00300         return NVProperty::NVP_INVALD_PARM;
00301     
00302     _flashEntry *p = _GetFlashEntry(key);
00303     if (p && p->t.type == NVProperty::T_BLOB && size == p->u.option.d_len) { // check for duplicate
00304         if (memcmp(blob, p->data.v_blob, size) == 0)
00305             return NVProperty::NVP_OK;
00306     }
00307     int err = NVProperty::NVP_OK;
00308     
00309     p = new _flashEntry();
00310     if (!p)
00311         return NVProperty::NVP_ERR_NOSPACE;
00312     
00313     p->key = key;
00314     p->t.type = NVProperty::T_BLOB;
00315     int cplen = std::min(size, (int)sizeof(p->data.v_blob));
00316     p->u.option.d_len = cplen;
00317     memcpy(p->data.v_blob, blob, cplen);
00318     
00319     int len = (FLASH_ENTRY_MIN_SIZE - 4) + p->u.option.d_len;
00320     len += _GetFlashPaddingSize(len);
00321 
00322     if ((uint8_t *)_lastEntry + len >= _endAddress) {
00323         if (!_FlashReorgEntries(len)) {
00324             err = NVProperty::NVP_ERR_NOSPACE;
00325             goto done;
00326         }
00327     }
00328 
00329     _OTPWrite((uint8_t *)_lastEntry, p, len);
00330     _lastEntry = (_flashEntry *)((uint8_t *)_lastEntry + len);
00331 
00332 done:
00333     delete[] p;
00334     // _DumpAllEntires();
00335     return err;
00336 }
00337 
00338 int
00339 NVProperty_L4OTP::EraseProperty(int key)
00340 {
00341     uint8_t valbuf[FLASH_ENTRY_MIN_SIZE];
00342     _flashEntry *p = (_flashEntry *) valbuf;
00343 
00344     _flashEntry *op = _GetFlashEntry(key);
00345     if (!op)
00346         return NVProperty::NVP_ENOENT;
00347     if (op->t.deleted)
00348         return NVProperty::NVP_OK;
00349     
00350     memset(valbuf, 0, sizeof(valbuf));
00351     p->key = key;
00352     p->t.type = op->t.type;
00353     p->t.deleted = true;
00354     
00355     if ((uint8_t *)_lastEntry + FLASH_ENTRY_MIN_SIZE > _endAddress) {
00356         if (!_FlashReorgEntries(FLASH_ENTRY_MIN_SIZE))
00357             return NVProperty::NVP_ERR_NOSPACE;
00358     }
00359 
00360     _OTPWrite((uint8_t *)_lastEntry, p, FLASH_ENTRY_MIN_SIZE);
00361     _lastEntry = (_flashEntry *)((uint8_t *)_lastEntry + FLASH_ENTRY_MIN_SIZE);
00362 
00363     // _DumpAllEntires();
00364     return NVProperty::NVP_OK;
00365 }
00366 
00367 int
00368 NVProperty_L4OTP::ReorgProperties(void)
00369 {
00370     return NVProperty::NVP_OK;
00371 }
00372 
00373 
00374 int
00375 NVProperty_L4OTP::OpenPropertyStore(bool forWrite)
00376 {
00377     UNUSED(forWrite);
00378     return NVProperty::NVP_OK;
00379 }
00380 
00381 int
00382 NVProperty_L4OTP::ClosePropertyStore(bool flush)
00383 {
00384     return NVProperty::NVP_OK;
00385 }
00386 
00387 #if 1
00388 void
00389 NVProperty_L4OTP::_DumpAllEntires(void)
00390 {
00391     if (!_debug)
00392         return;
00393     
00394     dprintf("------------- DumpAllEntires -------- ");
00395 
00396     int index = 0;
00397     _flashEntry *p = (_flashEntry *)(_startAddress + sizeof(_flash_header));
00398     while((uint8_t *)p < _endAddress && p->key != _flashErasedValue) {
00399 
00400         int64_t value = 0;
00401         switch(p->t.type) {
00402         case NVProperty::T_BIT:
00403             if (p->t.t_bit)
00404                 value = 1;
00405             else
00406                 value = 0;
00407             break;
00408         case NVProperty::T_8BIT:
00409             value = p->u.v_8bit;
00410             break;
00411         case NVProperty::T_16BIT:
00412             {
00413                 int16_t v;
00414                 memcpy(&v, &p->u.v_16bit, sizeof(p->u.v_16bit));
00415                 value = v;
00416             }
00417             break;
00418         case NVProperty::T_32BIT:
00419             {
00420                 int32_t v;
00421                 memcpy(&v, &p->data.v_32bit, sizeof(p->data.v_32bit));
00422                 value = v;
00423             }
00424             break;
00425         case NVProperty::T_64BIT:
00426             memcpy(&value, p->data.v_64bit, sizeof(p->data.v_64bit));
00427             break;
00428         case NVProperty::T_STR:
00429         case NVProperty::T_BLOB:
00430             value = p->u.option.d_len;
00431             break;
00432         }
00433         index++;
00434         if (p->t.deleted) {
00435             dprintf("Dump[%.2d] Key: %d Type: %d deleted(%d)", index, p->key, p->t.type, p->t.deleted);
00436 
00437         } else if (p->t.type == NVProperty::T_STR) {
00438             dprintf("Dump[%.2d] Key: %d Type: %d value: %s", index, p->key, p->t.type, p->data.v_str);
00439         } else if (p->t.type == NVProperty::T_BLOB) {
00440             dprintf("Dump[%.2d] Key: %d Type: %d len: %d", index, p->key, p->t.type, p->u.option.d_len);
00441             dump("Blob",  p->data.v_str, p->u.option.d_len);
00442         } else {
00443             if (p->t.type == NVProperty::T_64BIT) {
00444                 dprintf("Dump[%.2d] Key: %d Type: %d value: %lld (0x%llx)", index, p->key, p->t.type, value, value);
00445             } else {
00446                 dprintf("Dump[%.2d] Key: %d Type: %d value: %ld (0x%x)", index, p->key, p->t.type, (int32_t)value, (unsigned int)value);
00447             }
00448         }
00449         
00450         p = (_flashEntry *)((uint8_t *)p + _GetFlashEntryLen(p));
00451     }
00452     int freebytes = _endAddress -(uint8_t *)_lastEntry;
00453     if (_lastEntry)
00454         dprintf("------ %d bytes free -------", freebytes);
00455 }
00456 #endif
00457 
00458 NVProperty_L4OTP::_flashEntry *
00459 NVProperty_L4OTP::_GetFlashEntry(int key, uint8_t *start)
00460 {
00461     _flashEntry *p;
00462 
00463     if (start)
00464         p = (_flashEntry *)start;
00465     else
00466         p = (_flashEntry *)(_startAddress + sizeof(_flash_header));
00467     _flashEntry *lastP = NULL;
00468     while(true) {
00469         if ((uint8_t*)p >= _endAddress || p->key == _flashErasedValue) {
00470             if ((uint8_t*)p <= _endAddress)
00471                 _lastEntry = p;
00472             if (!lastP || lastP->t.deleted)
00473                 return NULL;
00474             break;
00475         }
00476         if (p->key == key)
00477             lastP = p;
00478 
00479         p = (_flashEntry *)((uint8_t *)p + _GetFlashEntryLen(p));
00480     }
00481     return lastP;
00482 }
00483 
00484 
00485 int
00486 NVProperty_L4OTP::_GetFlashEntryLen(_flashEntry *p)
00487 {
00488     int len = 0;
00489     
00490     switch(p->t.type) {
00491         case NVProperty::T_64BIT:
00492         case NVProperty::T_STR:
00493         case NVProperty::T_BLOB:
00494             len = (FLASH_ENTRY_MIN_SIZE - 4) + p->u.option.d_len;
00495             len += _GetFlashPaddingSize(len);
00496             break;
00497         default:
00498             len = FLASH_ENTRY_MIN_SIZE;
00499     }
00500     return len;
00501 }
00502 
00503 int
00504 NVProperty_L4OTP::_GetFlashPaddingSize(int len)
00505 {
00506     int remain = len % FLASH_PADDING_SIZE;
00507     
00508     if (remain == 0)
00509         return 0;
00510     
00511     return (len + FLASH_PADDING_SIZE - remain) - len;
00512 }
00513 
00514 
00515 int
00516 NVProperty_L4OTP::_FlashReorgEntries(int minRequiredSpace)
00517 {
00518     return 0; // no reorg on OTP
00519 }
00520 
00521 
00522 void
00523 NVProperty_L4OTP::_OTPWrite(uint8_t *address, const void *d, size_t length)
00524 {
00525 #ifdef OTP_TEST_IN_RAM
00526     memcpy(address, d, length);
00527 #else
00528     OTPWrite(address, d, length);
00529 #endif
00530 }
00531 
00532 #endif // TARGET_STM32L4