NVProperty generic key value store using the MCU flash area.
Dependents: Turtle_RadioShuttle
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
Generated on Tue Jul 12 2022 20:44:07 by 1.7.2