Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Flipper-Zero/STM32CubeWB.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'Projects/STM32WB5MM-DK/Applications/BLE/BLE_Mesh_Model_Sensor/STM32_WPAN/app/appli_nvm.c')
-rw-r--r--Projects/STM32WB5MM-DK/Applications/BLE/BLE_Mesh_Model_Sensor/STM32_WPAN/app/appli_nvm.c749
1 files changed, 749 insertions, 0 deletions
diff --git a/Projects/STM32WB5MM-DK/Applications/BLE/BLE_Mesh_Model_Sensor/STM32_WPAN/app/appli_nvm.c b/Projects/STM32WB5MM-DK/Applications/BLE/BLE_Mesh_Model_Sensor/STM32_WPAN/app/appli_nvm.c
new file mode 100644
index 000000000..ce9af8d33
--- /dev/null
+++ b/Projects/STM32WB5MM-DK/Applications/BLE/BLE_Mesh_Model_Sensor/STM32_WPAN/app/appli_nvm.c
@@ -0,0 +1,749 @@
+/**
+ ******************************************************************************
+ * @file appli_nvm.c
+ * @author BLE Mesh Team
+ * @brief User Application file
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2020-2021 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include <string.h>
+#include "hal_common.h"
+#include "ble_mesh.h"
+#include "mesh_cfg_usr.h"
+#include "appli_nvm.h"
+#include "mesh_cfg.h"
+#include "pal_nvm.h"
+#include "appli_mesh.h"
+#ifdef SAVE_MODEL_STATE_FOR_ALL_MESSAGES
+#include "common.h"
+#endif
+#if (LOW_POWER_FEATURE == 1)
+#include "app_conf.h"
+#include "stm32_seq.h"
+#endif
+#include "config_client.h"
+
+/** @addtogroup ST_BLE_Mesh
+* @{
+*/
+
+/** @addtogroup Application_Mesh_Models
+* @{
+*/
+/* Private define ------------------------------------------------------------*/
+
+extern const MOBLEUINT8* _bdaddr[];
+
+#ifdef SAVE_MODEL_STATE_FOR_ALL_MESSAGES
+extern MOBLEUINT8 PowerOnOff_flag;
+#endif
+
+extern const void* appNvmBase;
+
+
+/*
+* Page of size 4k, STM32WB, reserved for application is divided into 16 subpages of each 256 bytes
+* First subpage is reserved (for e.g. External MAC is present in this area)
+* Rest 15 subpages are used on rolling basis for application states.
+* First byte of each subpage indicates if page is valid or not
+*/
+
+#define APP_NVM_RESERVED_SIZE 256U
+#define APP_NVM_SUBPAGE_SIZE 256U
+#define APP_NVM_MAX_SUBPAGE 15U
+#define APP_NVM_SUBPAGE_OFFSET(i) (unsigned int)(APP_NVM_RESERVED_SIZE + APP_NVM_SUBPAGE_SIZE*(i))
+
+/* offsets defined wrt start of subpage */
+#define APP_NVM_VALID_FLAG_OFFSET 0U
+#define APP_NVM_VALID_FLAG_SIZE 4U
+#define APP_NVM_RESET_COUNT_OFFSET (unsigned int)APP_NVM_VALID_FLAG_SIZE
+#define APP_NVM_RESET_COUNT_SIZE 12U /* 12 bytes reserved for write cycle optimization */
+#define APP_NVM_GENERIC_MODEL_OFFSET (unsigned int)(APP_NVM_VALID_FLAG_SIZE+APP_NVM_RESET_COUNT_SIZE)
+//#define APP_NVM_GENERIC_MODEL_SIZE 16U
+#define APP_NVM_LIGHT_MODEL_OFFSET (unsigned int)(APP_NVM_VALID_FLAG_SIZE+APP_NVM_RESET_COUNT_SIZE+APP_NVM_GENERIC_MODEL_SIZE)
+//#define APP_NVM_LIGHT_MODEL_SIZE 16U
+
+#define FLASH_EMPTY_SIGNATURE 0xFFFFFFFF
+
+#define RADIO_OFF_DELAY 1000
+
+/* Private variables ---------------------------------------------------------*/
+
+typedef struct
+{
+ MOBLEUINT8 modelData[APP_NVM_GENERIC_MODEL_SIZE+APP_NVM_LIGHT_MODEL_SIZE];
+ MOBLEBOOL erasePageReq;
+ MOBLEBOOL writeReq;
+} APPLI_NVM_REQS;
+
+/* ALIGN(4) */
+__attribute__((aligned(4))) APPLI_NVM_REQS AppliNvm_Reqs;
+MOBLEUINT16 StopRadioInProgress;
+
+MOBLE_RESULT AppliNvm_EraseRestoreResvNvm(void);
+MOBLE_RESULT AppliNvm_FindFirstEmptyPage(MOBLEINT16* subPageIndex,
+ MOBLEUINT32 SubPageSize,
+ MOBLEUINT32 totalSubPage,
+ MOBLEUINT32 nvmBaseOffset);
+MOBLE_RESULT AppliNvm_MarkSubpageInvalid(void);
+MOBLE_RESULT AppliNvm_FlashProgram(MOBLEUINT32 offset,
+ void const *buf, MOBLEUINT32 size);
+
+#if 0 //#ifdef ENABLE_NVM_TEST
+/**
+* @brief This function erases a specified flash page
+* @param Page Number
+* @retval MOBLE_RESULT_INVALIDARG if PageNumber overflow
+* MOBLE_RESULT_FALSE if flash operation is very close to next radio event
+* MOBLE_RESULT_FAIL if flash command error is set
+* MOBLE_RESULT_SUCCESS on success
+*/
+MOBLE_RESULT AppliNvm_FlashErase(uint16_t PageNumber)
+{
+ MOBLE_RESULT result;
+
+ if (PageNumber < FLASH_PAGE_NB)
+ {
+ BLEMesh_StopAdvScan();
+ ATOMIC_SECTION_BEGIN();
+ result = PalNvmErase(APP_NVM_BASE, 0);
+ ATOMIC_SECTION_END();
+ }
+ else /* Invalid page no */
+ {
+ result = MOBLE_RESULT_INVALIDARG;
+ }
+
+ return result;
+}
+#endif
+
+/**
+* @brief Program word (32-bit) at a APP_NVM_BASE + APP_NVM_RESERVED_SIZE
+* @param TypeProgram Indicate the way to program at a specified address
+* @param Address: address to write
+* @param Data: word to write
+* @retval MOBLE_RESULT_SUCCESS on success
+*/
+MOBLE_RESULT AppliNvm_FlashProgram(MOBLEUINT32 offset,
+ void const *buf,
+ MOBLEUINT32 size)
+{
+ MOBLE_RESULT result = MOBLE_RESULT_SUCCESS;
+
+ if (offset > PAGE_SIZE)
+ {
+ result = MOBLE_RESULT_INVALIDARG;
+ }
+ else if (size == 0)
+ {
+ result = MOBLE_RESULT_FALSE;
+ }
+ else if (offset + size > (APP_NVM_BASE + PAGE_SIZE))
+ {
+ result = MOBLE_RESULT_INVALIDARG;
+ }
+ else if (offset & 3)
+ {
+ result = MOBLE_RESULT_INVALIDARG;
+ }
+ else if (size & 3)
+ {
+ result = MOBLE_RESULT_INVALIDARG;
+ }
+ else
+ {
+ result = PalNvmWrite(APP_NVM_BASE,
+ offset,
+ buf,
+ size);
+ }
+
+ return result;
+}
+
+
+/**
+* @brief Mark first valid subpage as invalid.
+* @param void
+* @retval MOBLE_RESULT_SUCCESS on success
+*/
+MOBLE_RESULT AppliNvm_MarkSubpageInvalid(void)
+{
+ MOBLE_RESULT result = MOBLE_RESULT_SUCCESS;
+#if 0
+ MOBLEUINT32 valid = 0;
+ MOBLEINT16 currSubPageIdx;
+ MOBLEUINT8 subPageTemp[APP_NVM_SUBPAGE_SIZE];
+
+ /* find valid subpage */
+ result = AppliNvm_FindFirstEmptyPage(&currSubPageIdx,
+ APP_NVM_SUBPAGE_SIZE,
+ APP_NVM_MAX_SUBPAGE,
+ (APP_NVM_BASE+APP_NVM_RESERVED_SIZE));
+
+
+ if (result == MOBLE_RESULT_OUTOFMEMORY)
+ {
+ AppliNvm_Reqs.erasePageReq = MOBLE_TRUE;
+ }
+ else
+ {
+ /* mark valid subpage as invalid */
+ memcpy((void*)subPageTemp,
+ (void*)(PRVN_NVM_BASE_OFFSET + APP_NVM_SUBPAGE_OFFSET(currSubPageIdx)),
+ APP_NVM_SUBPAGE_SIZE);
+ subPageTemp[APP_NVM_VALID_FLAG_OFFSET] = valid;
+ result = AppliNvm_FlashProgram(APP_NVM_SUBPAGE_OFFSET(currSubPageIdx),
+ (uint32_t*)&subPageTemp,
+ APP_NVM_SUBPAGE_SIZE);
+ if (MOBLE_FAILED(result))
+ {
+ result = MOBLE_RESULT_FAIL;
+ }
+ else if (result == MOBLE_RESULT_FALSE)
+ {
+ /* radio busy, try again later */
+ }
+ else
+ {
+ /* do nothing */
+ }
+ }
+#endif
+ return result;
+}
+
+
+/**
+* @brief This function writes Reset count value in flash at APP_NVM_BASE + APP_NVM_RESERVED_SIZE
+* if device has been turned ON 5 times consecutively with each ON duration < 2s, reset to factory settings
+* LED blinks 2 times to indicate device startup without reset
+* LED blinks 5 times to indicate reset at device startup
+* @param void
+* @retval MOBLE_RESULT_SUCCESS on success
+*/
+MOBLE_RESULT AppliNvm_FactorySettingReset(void)
+{
+ MOBLE_RESULT result = MOBLE_RESULT_SUCCESS;
+#if 0
+ MOBLEINT16 currSubPageIdx = 0;
+ MOBLEUINT32 resetCount;
+ MOBLEUINT8 subPageTemp[APP_NVM_SUBPAGE_SIZE];
+
+ result = AppliNvm_FindFirstEmptyPage(&currSubPageIdx,APP_NVM_SUBPAGE_SIZE,APP_NVM_MAX_SUBPAGE,
+ (APP_NVM_BASE+APP_NVM_RESERVED_SIZE));
+
+ if(result == MOBLE_RESULT_OUTOFMEMORY)
+ {
+ AppliNvm_Reqs.erasePageReq = MOBLE_TRUE;
+#if (LOW_POWER_FEATURE == 1)
+ UTIL_SEQ_SetTask( 1<<CFG_TASK_APPLI_REQ_ID, CFG_SCH_PRIO_0);
+#endif
+ result = MOBLE_RESULT_FAIL;
+ }
+ else
+ {
+ if(currSubPageIdx > 0)
+ {
+ /* Not the first reset */
+ /* read the previous subpage */
+ memcpy((void*)&(subPageTemp[0]),
+ (void*)(APP_NVM_BASE + APP_NVM_SUBPAGE_OFFSET(currSubPageIdx-1)),
+ APP_NVM_SUBPAGE_SIZE);
+ }
+ else
+ {
+ /* read the current subpage */
+ memcpy((void*)&(subPageTemp[0]),
+ (void*)(APP_NVM_BASE + APP_NVM_SUBPAGE_OFFSET(currSubPageIdx)),
+ APP_NVM_SUBPAGE_SIZE);
+ }
+
+ /* read reset count from the subpage */
+ memcpy((void*)&resetCount,
+ (void*)&(subPageTemp[APP_NVM_RESET_COUNT_OFFSET]),
+ 4);
+ resetCount = resetCount << 1; /* Shifting for making Bits 0 from LSB */
+ memcpy((void*)&(subPageTemp[APP_NVM_RESET_COUNT_OFFSET]), (void*)&resetCount, 4);
+
+ /* Check for "POWER_ON_OFF_CYCLES_FOR_UNPROVISIONING" times, that many bits shall be zero */
+ if (resetCount > MASK_BITS_FOR_POWER_ON_OFF_CYCLES)
+ {
+ /* MASK_BITS_FOR_POWER_ON_OFF_CYCLES = 0xFFFFFFE0 */
+
+ /* update reset count */
+ result = AppliNvm_FlashProgram(APP_NVM_SUBPAGE_OFFSET(currSubPageIdx),
+ (uint32_t*)&subPageTemp,
+ APP_NVM_SUBPAGE_SIZE);
+
+ if (!memcmp((void*)&subPageTemp[APP_NVM_RESET_COUNT_OFFSET],
+ (void*)(APP_NVM_BASE + APP_NVM_SUBPAGE_OFFSET(currSubPageIdx)+APP_NVM_RESET_COUNT_OFFSET),
+ 4))
+ {
+ /* updated value of reset count in flash */
+ }
+
+ /* Blink twice to indicate device startup
+ 1 second to blink once and 2 seconds to blink twice */
+ for (MOBLEUINT8 i=0; i< ON_TIME_IN_SECONDS_FOR_POWER_CYCLING; i++)
+ {
+ Appli_LedBlink();
+ }
+
+ /* Load model data copy from nvm */
+ memcpy((void*)AppliNvm_Reqs.modelData,
+ (void*)(APP_NVM_SUBPAGE_OFFSET(currSubPageIdx)+APP_NVM_GENERIC_MODEL_OFFSET),
+ APP_NVM_MODELDATA_PER_ELEMENT_SIZE);
+
+ result = AppliNvm_MarkSubpageInvalid();
+
+ if (MOBLE_FAILED(result))
+ {
+ result = MOBLE_RESULT_FAIL;
+ }
+ }
+ else /* Device is forced to factory reset, 5 LSBs are zero */
+ {
+ /* Unprovision node */
+ BLEMesh_Unprovision();
+
+ /* Clear lib data, primary and backup nvm used by BLE-Mesh lib */
+ PalNvmErase(NVM_BASE, 0);
+ PalNvmErase(NVM_BASE, 0x1000);
+
+ AppliNvm_ClearModelState();
+
+ BLEMesh_SetUnprovisionedDevBeaconInterval(100);
+
+ /* Blink 5 times to indicate factory setting reset */
+ for (MOBLEUINT8 i=0; i<BLINK_TIMES_FOR_FACTORY_RESET; i++)
+ {
+ Appli_LedBlink();
+ }
+
+ TRACE_M(TF_MISC, "Reset to factory settings \r\n");
+ }
+
+ result = MOBLE_RESULT_SUCCESS;
+ }
+#endif
+ return result;
+}
+
+
+/**
+* @brief Save model states in nvm
+* @param model state buff
+* @param model state buff size
+* @retval MOBLE_RESULT_SUCCESS on success
+*/
+MOBLE_RESULT AppliNvm_SaveModelState(uint8_t* state,
+ uint16_t size)
+{
+ MOBLE_RESULT result = MOBLE_RESULT_SUCCESS; /* if save model state not defined, return MOBLE_RESULT_FAIL */
+
+#if (SAVE_MODEL_STATE_NVM == 1)
+
+ if (size > APP_NVM_MODEL_SIZE)
+ {
+ /* incorrect size */
+ result = MOBLE_RESULT_FAIL;
+ }
+ else
+ {
+ memcpy(AppliNvm_Reqs.modelData,
+ state,
+ size);
+
+ AppliNvm_Reqs.writeReq = MOBLE_TRUE;
+ AppliNvm_Reqs.erasePageReq = MOBLE_FALSE;
+#if (LOW_POWER_FEATURE == 1)
+ UTIL_SEQ_SetTask( 1<<CFG_TASK_APPLI_REQ_ID, CFG_SCH_PRIO_0);
+#endif
+ }
+#endif /* SAVE_MODEL_STATE_NVM */
+ return result;
+}
+
+
+/**
+* @brief Clear model states in nvm
+* @param none
+* @retval MOBLE_RESULT_SUCCESS on success
+*/
+MOBLE_RESULT AppliNvm_ClearModelState(void)
+{
+ MOBLE_RESULT result = MOBLE_RESULT_FAIL; /* if save model state not defined, return MOBLE_RESULT_FAIL */
+
+#if (SAVE_MODEL_STATE_NVM == 1)
+ MOBLEUINT8 subPageTemp[APP_NVM_SUBPAGE_SIZE];
+ MOBLEINT16 subPageIdx;
+ MOBLEUINT8 clearBuff[APP_NVM_MODELDATA_PER_ELEMENT_SIZE] = {0};
+ MOBLEUINT32 valid = 0;
+
+ result = AppliNvm_FindFirstEmptyPage(&subPageIdx,
+ APP_NVM_SUBPAGE_SIZE,
+ APP_NVM_MAX_SUBPAGE,
+ (APP_NVM_BASE+APP_NVM_RESERVED_SIZE));
+
+ if (MOBLE_FAILED(result))
+ {
+ result = MOBLE_RESULT_FAIL;
+ }
+ else
+ {
+ if(subPageIdx > 0)
+ { /* Not the first subpage */
+ /* clear models states */
+ memcpy((void*)&(subPageTemp[0]),
+ (void*)(APP_NVM_BASE + APP_NVM_SUBPAGE_OFFSET(subPageIdx-1)),
+ APP_NVM_SUBPAGE_SIZE);
+ memcpy((void*)&subPageTemp[APP_NVM_GENERIC_MODEL_OFFSET],
+ (void*)(clearBuff),
+ APP_NVM_GENERIC_MODEL_SIZE+APP_NVM_LIGHT_MODEL_SIZE);
+ subPageTemp[APP_NVM_VALID_FLAG_OFFSET] = valid;
+
+ result = AppliNvm_FlashProgram(APP_NVM_SUBPAGE_OFFSET(subPageIdx),
+ (uint32_t*)&subPageTemp,
+ APP_NVM_SUBPAGE_SIZE);
+ }
+ else
+ { /* First subpage */
+ memcpy((void*)&(subPageTemp[0]),
+ (void*)(APP_NVM_BASE + APP_NVM_SUBPAGE_OFFSET(subPageIdx)),
+ APP_NVM_SUBPAGE_SIZE);
+ memcpy((void*)&subPageTemp[APP_NVM_GENERIC_MODEL_OFFSET],
+ (void*)(clearBuff),
+ APP_NVM_GENERIC_MODEL_SIZE+APP_NVM_LIGHT_MODEL_SIZE);
+ subPageTemp[APP_NVM_VALID_FLAG_OFFSET] = valid;
+
+ result = AppliNvm_FlashProgram(APP_NVM_SUBPAGE_OFFSET(subPageIdx),
+ (uint32_t*)&subPageTemp,
+ APP_NVM_SUBPAGE_SIZE);
+ }
+ }
+#endif /* SAVE_MODEL_STATE_NVM */
+ return result;
+}
+
+
+/**
+* @brief Load Model states from nvm
+* @param model state buff
+* @param model state buff size
+* @retval MOBLE_RESULT_SUCCESS on success
+*/
+MOBLE_RESULT AppliNvm_LoadModelState(uint8_t state[],
+ uint16_t* size)
+{
+#if (SAVE_MODEL_STATE_NVM == 1)
+ MOBLE_RESULT result = MOBLE_RESULT_SUCCESS;
+ MOBLEINT16 currSubPageIdx = 0;
+
+ *size = 0;
+ result = AppliNvm_FindFirstEmptyPage(&currSubPageIdx,
+ APP_NVM_SUBPAGE_SIZE,
+ APP_NVM_MAX_SUBPAGE,
+ APP_NVM_BASE + APP_NVM_RESERVED_SIZE);
+
+ if(result == MOBLE_RESULT_OUTOFMEMORY)
+ {
+ AppliNvm_Reqs.erasePageReq = MOBLE_TRUE;
+#if (LOW_POWER_FEATURE == 1)
+ UTIL_SEQ_SetTask( 1<<CFG_TASK_APPLI_REQ_ID, CFG_SCH_PRIO_0);
+#endif
+ result = MOBLE_RESULT_FAIL;
+ }
+ else
+ {
+ if(currSubPageIdx > 0)
+ {
+ /* Not the first reset */
+ /* Load model data copy from nvm */
+ memcpy((void*)AppliNvm_Reqs.modelData,
+ (void*)(APP_NVM_BASE + APP_NVM_SUBPAGE_OFFSET(currSubPageIdx-1) + APP_NVM_GENERIC_MODEL_OFFSET),
+ APP_NVM_GENERIC_MODEL_SIZE + APP_NVM_LIGHT_MODEL_SIZE);
+ memcpy((void*)state,
+ (void*)(AppliNvm_Reqs.modelData),
+ APP_NVM_MODEL_SIZE);
+ *size = APP_NVM_MODEL_SIZE;
+ }
+ }
+ return result;
+#else /* SAVE_MODEL_STATE_NVM */
+ *size = 0;
+ return MOBLE_RESULT_SUCCESS;
+#endif /* SAVE_MODEL_STATE_NVM */
+}
+
+
+/**
+* @brief Process NVM erase and write requests
+* @param void
+* @retval void
+*/
+void AppliNvm_Process(void)
+{
+ MOBLE_RESULT result;
+ MOBLEINT16 subPageIdx;
+ uint8_t reserveAreaCopy[APP_NVM_RESERVED_SIZE];
+
+ /* Erase if required */
+ if ((AppliNvm_Reqs.erasePageReq == MOBLE_TRUE) &&
+ (!LL_FLASH_IsActiveFlag_OperationSuspended()))
+ {
+ if(StopRadioInProgress == 0)
+ {
+ /* save reserve flash area */
+ memcpy((void*)reserveAreaCopy,
+ (void*)APP_NVM_BASE,
+ APP_NVM_RESERVED_SIZE);
+
+ TRACE_M(TF_PROVISION,"Erase flash page\r\n");
+ result = PalNvmErase(APP_NVM_BASE, 0);
+
+ if(result == MOBLE_RESULT_OUTOFMEMORY)
+ {
+ AppliNvm_Reqs.erasePageReq = MOBLE_TRUE;
+#if (LOW_POWER_FEATURE == 1)
+ UTIL_SEQ_SetTask( 1<<CFG_TASK_APPLI_REQ_ID, CFG_SCH_PRIO_0);
+#endif
+ }
+ else
+ {
+ AppliNvm_Reqs.erasePageReq = MOBLE_FALSE;
+ AppliNvm_Reqs.writeReq = MOBLE_TRUE;
+#if (LOW_POWER_FEATURE == 1)
+ UTIL_SEQ_SetTask( 1<<CFG_TASK_APPLI_REQ_ID, CFG_SCH_PRIO_0);
+#endif
+ /* restore reserve area */
+/* FLASH_ProgramWordBurst(APP_NVM_BASE, (uint32_t*)reserveAreaCopy); */
+ result = AppliNvm_FlashProgram(0,
+ (uint32_t*)&reserveAreaCopy,
+ APP_NVM_RESERVED_SIZE);
+ BLEMesh_ResumeAdvScan();
+ }
+ }
+ else
+ StopRadioInProgress--;
+ }
+
+ if (AppliNvm_Reqs.erasePageReq == MOBLE_FALSE &&
+ AppliNvm_Reqs.writeReq == MOBLE_TRUE)
+ {
+ result = AppliNvm_FindFirstEmptyPage(&subPageIdx,
+ APP_NVM_SUBPAGE_SIZE,
+ APP_NVM_MAX_SUBPAGE,
+ (APP_NVM_BASE+APP_NVM_RESERVED_SIZE));
+
+ if(result == MOBLE_RESULT_OUTOFMEMORY)
+ {
+ BLEMesh_SuspendAdvScan();
+ StopRadioInProgress = RADIO_OFF_DELAY;
+
+ AppliNvm_Reqs.erasePageReq = MOBLE_TRUE;
+#if (LOW_POWER_FEATURE == 1)
+ UTIL_SEQ_SetTask( 1<<CFG_TASK_APPLI_REQ_ID, CFG_SCH_PRIO_0);
+#endif
+ result = MOBLE_RESULT_SUCCESS;
+ }
+ else
+ {
+ MOBLEUINT8 subPageTemp[APP_NVM_SUBPAGE_SIZE];
+ MOBLEUINT32 valid = 0;
+
+ if(subPageIdx > 0)
+ {
+ /* Not the first reset */
+ /* read the previous subpage */
+ memcpy((void*)&(subPageTemp[0]),
+ (void*)(APP_NVM_BASE + APP_NVM_SUBPAGE_OFFSET(subPageIdx-1)),
+ APP_NVM_SUBPAGE_SIZE);
+ }
+ else
+ {
+ /* read the current subpage */
+ memcpy((void*)&(subPageTemp[0]),
+ (void*)(APP_NVM_BASE + APP_NVM_SUBPAGE_OFFSET(subPageIdx)),
+ APP_NVM_SUBPAGE_SIZE);
+ }
+
+ memcpy((void*)&(subPageTemp[APP_NVM_GENERIC_MODEL_OFFSET]),
+ (void*)&(AppliNvm_Reqs.modelData),
+ APP_NVM_GENERIC_MODEL_SIZE+APP_NVM_LIGHT_MODEL_SIZE);
+
+ subPageTemp[APP_NVM_VALID_FLAG_OFFSET] = valid;
+
+ result = AppliNvm_FlashProgram(APP_NVM_SUBPAGE_OFFSET(subPageIdx),
+ (uint8_t*)subPageTemp,
+ APP_NVM_SUBPAGE_SIZE);
+
+ if (result == MOBLE_RESULT_SUCCESS)
+ {
+ AppliNvm_Reqs.writeReq = MOBLE_FALSE;
+ }
+ }
+ }
+}
+
+
+/**
+* @brief Function used to set the flag which is responsible for storing the
+ states in flash.
+* @param void
+* @retval void
+*/
+void AppliNvm_SaveMessageParam (void)
+{
+#ifdef SAVE_MODEL_STATE_FOR_ALL_MESSAGES
+ PowerOnOff_flag = FLAG_SET;
+#endif
+}
+
+
+/**
+* @brief Find first valid subpage available.
+* If no valid subpage found, erase page appli nvm to reset it
+* @param pointer to variable to update first valid subpage index
+* @retval MOBLE_RESULT_SUCCESS on success
+*/
+MOBLE_RESULT AppliNvm_FindFirstEmptyPage(MOBLEINT16* subPageIndex,
+ MOBLEUINT32 SubPageSize,
+ MOBLEUINT32 totalSubPage,
+ MOBLEUINT32 nvmBaseOffset)
+{
+ MOBLEUINT32 valid[2];
+ MOBLEINT8 subPageIdx = -1;
+ MOBLEUINT32 *subPageOffset;
+ MOBLEUINT32 addressValidPage;
+ MOBLE_RESULT result = MOBLE_RESULT_SUCCESS;
+
+ for (MOBLEUINT16 count=0; count<totalSubPage; count++)
+ {
+ addressValidPage = nvmBaseOffset + SubPageSize*count;
+ subPageOffset = &addressValidPage;
+
+ /* Read 8 bytes and check if it's Empty */
+ memcpy((void*)&valid, (void*)(*subPageOffset), 8);
+
+ if ((valid[0] == FLASH_EMPTY_SIGNATURE) /*&& (valid[1] == FLASH_EMPTY_SIGNATURE)*/)
+ {
+ subPageIdx = count;
+ break;
+ }
+ }
+
+ if (subPageIdx < 0)
+ {
+ TRACE_M(TF_PROVISION,"Out of Memory, Flash page is full \r\n");
+ result = MOBLE_RESULT_OUTOFMEMORY;
+ }
+ else
+ {
+ result = MOBLE_RESULT_SUCCESS;
+ }
+
+ *subPageIndex = subPageIdx;
+
+ return result;
+}
+
+#if 0 //#ifdef ENABLE_NVM_TEST
+MOBLE_RESULT AppliNVM_Save_FlashTesting(MOBLEUINT8 *buffer,
+ MOBLEUINT16 buffer_size)
+{
+ MOBLE_RESULT result = MOBLE_RESULT_FAIL;
+ uint8_t reserveAreaCopy[APP_NVM_RESERVED_SIZE];
+ MOBLEINT16 subPageIdx;
+
+ for(MOBLEUINT8 count = 0;count <= buffer_size;count++)
+ {
+ buffer[count] = count;
+ }
+
+ /* save reserve flash area */
+ memcpy((void*)reserveAreaCopy,
+ (void*)APP_NVM_BASE,
+ APP_NVM_RESERVED_SIZE);
+
+ result = AppliNvm_FlashErase((uint16_t)((APP_NVM_BASE - RESET_MANAGER_FLASH_BASE_ADDRESS) / PAGE_SIZE));
+
+ if (result == MOBLE_RESULT_SUCCESS)
+ {
+ /* restore reserve area */
+// FLASH_ProgramWordBurst(APP_NVM_BASE, (uint32_t*)reserveAreaCopy);
+ result = AppliNvm_FlashProgram(0,
+ (uint32_t*)&reserveAreaCopy,
+ APP_NVM_RESERVED_SIZE);
+ }
+
+ result = AppliNvm_FindFirstEmptyPage(&subPageIdx,
+ APP_NVM_SUBPAGE_SIZE,
+ APP_NVM_MAX_SUBPAGE,
+ (APP_NVM_BASE+APP_NVM_RESERVED_SIZE));
+
+ if(result == MOBLE_RESULT_OUTOFMEMORY)
+ {
+ TRACE_M(TF_PROVISION, "Flash sub page is full, preparing new subpage\r\n");
+ }
+ else
+ {
+ result = AppliNvm_FlashProgram(APP_NVM_SUBPAGE_OFFSET(subPageIdx)+APP_NVM_GENERIC_MODEL_OFFSET,
+ buffer,
+ buffer_size);
+ }
+ return result;
+}
+
+MOBLE_RESULT AppliNVM_Retrieve_FlashTesting(MOBLEUINT8 *buffer,
+ MOBLEUINT16 buffer_size)
+{
+ MOBLEINT16 currSubPageIdx;
+ MOBLE_RESULT result = MOBLE_RESULT_FAIL;
+
+ result = AppliNvm_FindFirstEmptyPage(&currSubPageIdx,
+ APP_NVM_SUBPAGE_SIZE,
+ APP_NVM_MAX_SUBPAGE,
+ (APP_NVM_BASE+APP_NVM_RESERVED_SIZE));
+
+ if(result == MOBLE_RESULT_OUTOFMEMORY)
+ {
+ TRACE_M(TF_PROVISION," Can not find the empty page for testing flash \r\n");
+ }
+ else
+ {
+ memcpy((void*)buffer,
+ (void*)(APP_NVM_SUBPAGE_OFFSET(currSubPageIdx)+APP_NVM_GENERIC_MODEL_OFFSET),
+ buffer_size);
+
+ result = AppliNvm_MarkSubpageInvalid();
+
+ if (MOBLE_FAILED(result))
+ {
+ result = MOBLE_RESULT_FAIL;
+ }
+ }
+
+ return result;
+}
+#endif
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/