pinebuds/services/nv_section/userdata_section/nvrecord_gsound.c

427 lines
15 KiB
C

/***************************************************************************
*
*Copyright 2015-2019 BES.
*All rights reserved. All unpublished rights reserved.
*
*No part of this work may be used or reproduced in any form or by any
*means, or stored in a database or retrieval system, without prior written
*permission of BES.
*
*Use of this work is governed by a license granted by BES.
*This work contains confidential and proprietary information of
*BES. which is protected by copyright, trade secret,
*trademark and other intellectual property rights.
*
****************************************************************************/
/*****************************header include********************************/
#include "cmsis.h"
#include "nv_section_dbg.h"
#include "nvrecord_gsound.h"
#include "factory_section.h"
#ifdef BISTO_ENABLED
#include "gsound_target_ota.h"
#ifdef GSOUND_HOTWORD_ENABLED
#include "gsound_custom_hotword_common.h"
#endif
#endif
/************************private macro defination***************************/
#define HOTWORD_MODEL_MAX_SIZE (80 * 1024) //!< should adjust this value if
//!< hotword model size changed and should adjust the flash section size at
//!< the sametime., @see HOTWORD_SECTION_SIZE in common.mk
#ifndef OTA_FLASH_LOGIC_ADDR
#define OTA_FLASH_LOGIC_ADDR (FLASH_NC_BASE)
#endif
/************************private type defination****************************/
/************************extern function declearation***********************/
#ifdef GSOUND_HOTWORD_ENABLED
extern uint32_t __hotword_model_start[];
extern uint32_t __hotword_model_end[];
#endif
/**********************private function declearation************************/
/************************private variable defination************************/
#ifdef GSOUND_HOTWORD_ENABLED
#ifdef MODEL_FILE_EMBEDED
const uint8_t EMBEDED_MODEL_FILE [] = {
#include "res/gs_hw/en_all.txt" //!< must correspond to specific model ID, @see DEFAULT_HOTWORD_MODEL_ID
};
/// NOTE: Add more embeded model file info here
#define DEFAULT_MODEL_START_ADDR EMBEDED_MODEL_FILE //!< map to specific flash address within the bin file
#else /// #ifndef MODEL_FILE_EMBEDED
#define DEFAULT_MODEL_START_ADDR __hotword_model_start //!< map to specific flash address out of the bin file
#endif /// #ifdef MODEL_FILE_EMBEDED
HOTWORD_MODEL_INFO_T defaultModel[DEFAULT_MODEL_NUM] = {
{DEFAULT_HOTWORD_MODEL_ID, (uint32_t)DEFAULT_MODEL_START_ADDR, HOTWORD_MODEL_MAX_SIZE},
/// NOTE: Add other embeded model info here
};
char supportedModels[GSOUND_MAX_SUPPORTED_HOTWORD_MODELS_BYTES] = {};
#endif /// #ifdef GSOUND_HOTWORD_ENABLED
static NV_GSOUND_INFO_T *nvrecord_gsound_p = NULL;
/****************************function defination****************************/
void nv_record_gsound_rec_init(void)
{
if (NULL == nvrecord_gsound_p)
{
nvrecord_gsound_p = &(nvrecord_extension_p->gsound_info);
}
#ifdef GSOUND_HOTWORD_ENABLED
/// init default supported model file(s)
/// add to supported model file set(if it is not in this set)
LOG_I("supportedModelCnt:%d", nvrecord_gsound_p->supportedModelCnt);
if (0 == nvrecord_gsound_p->supportedModelCnt) //!< load default info at first time bootup
{
for (uint8_t i = 0; i < DEFAULT_MODEL_NUM; i++)
{
LOG_I("hotword_model_start:0x%x",
defaultModel[i].startAddr);
nv_record_gsound_rec_add_new_model((void *)&defaultModel[i]);
}
}
#endif
}
void nv_record_gsound_rec_get_ptr(void **ptr)
{
*ptr = nvrecord_gsound_p;
}
void nv_record_gsound_rec_updata_enable_state(bool enable)
{
LOG_I("gsound enable state update:%d->%d", nvrecord_gsound_p->isGsoundEnabled, enable);
if (nvrecord_gsound_p->isGsoundEnabled != enable)
{
/// disable the MPU protection for write operation
uint32_t lock = nv_record_pre_write_operation();
/// update the enable state
nvrecord_gsound_p->isGsoundEnabled = enable;
nv_record_extension_update();
/// enable the MPU protection after the write operation
nv_record_post_write_operation(lock);
}
}
#ifdef GSOUND_HOTWORD_ENABLED
bool nv_record_gsound_rec_is_model_insert_allowed(const char *model)
{
bool ret = true;
uint8_t i;
if ((nvrecord_gsound_p->supportedModelCnt >= HOTWORD_MODLE_MAX_NUM) &&
(0xFF != nvrecord_gsound_p->supportedModelCnt))
{
for (i = 0; i < HOTWORD_MODLE_MAX_NUM; i++)
{
/// hotword model exist already
if (!memcmp(&nvrecord_gsound_p->modelInfo[i].modelId, model, strlen(model)))
{
break;
}
}
if (HOTWORD_MODLE_MAX_NUM == i)
{
ret = false;
}
}
return ret;
}
bool nv_record_gsound_rec_add_new_model(void *pInfo)
{
bool ret = true;
bool found = false;
uint32_t lock = 0;
HOTWORD_MODEL_INFO_T *info = (HOTWORD_MODEL_INFO_T *)pInfo;
if (INVALID_MODEL_NUM == nvrecord_gsound_p->supportedModelCnt)
{
lock = nv_record_pre_write_operation();
nvrecord_gsound_p->supportedModelCnt = 0;
nv_record_post_write_operation(lock);
}
if (info)
{
lock = nv_record_pre_write_operation();
info->startAddr |= OTA_FLASH_LOGIC_ADDR;
for (uint8_t i = 0; i < nvrecord_gsound_p->supportedModelCnt; i++)
{
/// hotword model exist already
if (!memcmp(&nvrecord_gsound_p->modelInfo[i].modelId, info->modelId, GSOUND_HOTWORD_MODEL_ID_BYTES))
{
LOG_I("info->startAddr:%x", info->startAddr);
///.update the start address
if (info->startAddr)
{
nvrecord_gsound_p->modelInfo[i].startAddr = info->startAddr;
nvrecord_gsound_p->modelInfo[i].len = info->len;
}
LOG_I("model already exist in user section, model_id:%s, model_addr:%x",
nvrecord_gsound_p->modelInfo[i].modelId,
nvrecord_gsound_p->modelInfo[i].startAddr);
found = true;
break;
}
}
LOG_I("current supportedModelCnt:%d", nvrecord_gsound_p->supportedModelCnt);
/// brand new model insert
if (!found)
{
memcpy(&nvrecord_gsound_p->modelInfo[nvrecord_gsound_p->supportedModelCnt],
info,
sizeof(HOTWORD_MODEL_INFO_T));
LOG_I("new added modelId:%s, startAddr:%x, modelFileLen:%x", info->modelId, info->startAddr, info->len);
nvrecord_gsound_p->supportedModelCnt++;
}
nv_record_post_write_operation(lock);
/// new model file incoming, update flash info
if (!found)
{
/// flush the hotword info to flash
nv_record_update_runtime_userdata();
nv_record_flash_flush();
}
LOG_I("current supportedModelCnt:%d", nvrecord_gsound_p->supportedModelCnt);
}
else
{
LOG_W("NULL pointer received in %s", __func__);
ret = false;
}
return ret;
}
uint32_t nv_record_gsound_rec_get_hotword_model_addr(const char *model_id, bool add_new, int32_t newModelLen)
{
uint32_t addr = 0;
bool found = false;
LOG_I("%s revceived model ID: %s", __func__, model_id);
if (nvrecord_gsound_p)
{
for (uint8_t i = 0; i < ARRAY_SIZE(nvrecord_gsound_p->modelInfo); i++)
{
if (!memcmp(nvrecord_gsound_p->modelInfo[i].modelId, model_id, 4))
{
addr = nvrecord_gsound_p->modelInfo[i].startAddr;
found = true;
LOG_I("found saved model info, index:%d", i);
break;
}
}
}
do
{
if (add_new && !found)
{
addr = (uint32_t)__hotword_model_start;
uint32_t tempAddr;
uint8_t startIdx = 0;
#ifdef MODEL_FILE_EMBEDED
startIdx = DEFAULT_MODEL_NUM; //!< set offset to skip the embeded model file info
#endif
if (INVALID_MODEL_NUM == nvrecord_gsound_p->supportedModelCnt)
{
break;
}
/// get the largest flash address
for (uint8_t i = startIdx; i < nvrecord_gsound_p->supportedModelCnt; i++)
{
tempAddr = nvrecord_gsound_p->modelInfo[i].startAddr + nvrecord_gsound_p->modelInfo[i].len;
if ((tempAddr & 0xFFFFFF) > (addr & 0xFFFFFF))
{
addr = tempAddr;
}
}
/// force 4K align the address
addr = F_4K_ALIGN(addr);
LOG_I("supportedModelCnt:%d, Largest address:0x%x", nvrecord_gsound_p->supportedModelCnt, addr);
/// check is overwrite needed
if ((newModelLen + addr) > (uint32_t)__hotword_model_end ||
(nvrecord_gsound_p->supportedModelCnt >= HOTWORD_MODLE_MAX_NUM))
{
uint8_t cleanIdx = 0; //!< model file index to clean
addr = nvrecord_gsound_p->modelInfo[startIdx].startAddr; //!< init anchor point
uint32_t cleanSize = F_4K_ALIGN(addr + nvrecord_gsound_p->modelInfo[startIdx].len) - addr; //!< flash size to clean
uint32_t lock = nv_record_pre_write_operation(); //!< disable the MPU for info update
uint32_t intLock = int_lock(); //!< lock the global interrupt
/// remove the first record
for (uint8_t i = startIdx; i < (nvrecord_gsound_p->supportedModelCnt - 1); i++)
{
nvrecord_gsound_p->modelInfo[i] = nvrecord_gsound_p->modelInfo[i + 1];
}
/// decrease the number of supported model
nvrecord_gsound_p->supportedModelCnt--;
while (cleanSize < newModelLen)
{
uint8_t headAdjacentIdx = 0xFF, tailAdjacentIdx = 0xFF;
uint32_t headAdjacentOffset = 0xFFFFFFFF, tailAdjacentOffset = 0xFFFFFFFF;
/// find the adjacent chunck
for (uint8_t i = startIdx; i < nvrecord_gsound_p->supportedModelCnt; i++)
{
if (nvrecord_gsound_p->modelInfo[i].startAddr > addr)
{
if (nvrecord_gsound_p->modelInfo[i].startAddr - addr < tailAdjacentOffset)
{
tailAdjacentOffset = nvrecord_gsound_p->modelInfo[i].startAddr - addr;
tailAdjacentIdx = i;
}
}
else if (nvrecord_gsound_p->modelInfo[i].startAddr < addr)
{
if (addr - nvrecord_gsound_p->modelInfo[i].startAddr < headAdjacentOffset)
{
headAdjacentOffset = nvrecord_gsound_p->modelInfo[i].startAddr - addr;
headAdjacentIdx = i;
}
}
}
LOG_I("headAdjacentIdx:%d, tailAdjacentIdx:%d", headAdjacentIdx, tailAdjacentIdx);
/// find the smaller index, smaller index means older record
if (headAdjacentIdx > tailAdjacentIdx)
{
cleanSize += F_4K_ALIGN(nvrecord_gsound_p->modelInfo[tailAdjacentIdx].startAddr +
nvrecord_gsound_p->modelInfo[tailAdjacentIdx].len) -
nvrecord_gsound_p->modelInfo[tailAdjacentIdx].startAddr;
cleanIdx = tailAdjacentIdx;
}
else
{
addr = nvrecord_gsound_p->modelInfo[headAdjacentIdx].startAddr;
cleanSize += F_4K_ALIGN(addr + nvrecord_gsound_p->modelInfo[headAdjacentIdx].len) - addr;
cleanIdx = headAdjacentIdx;
}
/// remove the first record
for (uint8_t i = cleanIdx; i < (nvrecord_gsound_p->supportedModelCnt - 1); i++)
{
nvrecord_gsound_p->modelInfo[i] = nvrecord_gsound_p->modelInfo[i + 1];
}
/// decrease the number of supported model
nvrecord_gsound_p->supportedModelCnt--;
}
if ((addr < (uint32_t)__hotword_model_start) ||
(addr > (uint32_t)__hotword_model_end))
{
LOG_I("invalid addr found:0x%x, clean all model files", addr);
nvrecord_gsound_p->supportedModelCnt = startIdx;
addr = (uint32_t)__hotword_model_start;
}
if (0 == nvrecord_gsound_p->supportedModelCnt)
{
/// invalid number used to identify with fist time bootup
nvrecord_gsound_p->supportedModelCnt = INVALID_MODEL_NUM;
}
int_unlock(intLock); //!< unlock the global interrupt
nv_record_post_write_operation(lock); //!< enable the MPU
/// flush the hotword info to flash
nv_record_update_runtime_userdata();
nv_record_flash_flush();
}
}
} while (0);
return addr;
}
int nv_record_gsound_rec_get_supported_model_id(char *models_out,
uint8_t *length_out)
{
int ret= 0;
const char* terminator = NULL;
if (INVALID_MODEL_NUM == nvrecord_gsound_p->supportedModelCnt)
{
memcpy(models_out, STRING_TERMINATOR_NULL, STRING_TERMINATOR_SIZE);
*length_out = STRING_TERMINATOR_SIZE;
}
else
{
for (uint8_t i = 0; i < nvrecord_gsound_p->supportedModelCnt; i++)
{
LOG_I("supported model_id:%s, model_addr:%x",
nvrecord_gsound_p->modelInfo[i].modelId,
nvrecord_gsound_p->modelInfo[i].startAddr);
memcpy((supportedModels + i * GSOUND_HOTWORD_SUPPORTED_MODEL_ID_BYTES),
nvrecord_gsound_p->modelInfo[i].modelId,
GSOUND_HOTWORD_MODEL_ID_BYTES);
if ((i + 1) == nvrecord_gsound_p->supportedModelCnt)
{
terminator = STRING_TERMINATOR_NULL;
}
else
{
terminator = SUPPORTED_HOTWORD_MODEL_DELIM;
}
memcpy(&supportedModels[(i * GSOUND_HOTWORD_SUPPORTED_MODEL_ID_BYTES) + GSOUND_HOTWORD_MODEL_ID_BYTES],
terminator,
STRING_TERMINATOR_SIZE);
}
if (nvrecord_gsound_p->supportedModelCnt * GSOUND_HOTWORD_SUPPORTED_MODEL_ID_BYTES <= *length_out)
{
strcpy(models_out, supportedModels);
*length_out = strlen(supportedModels) + STRING_TERMINATOR_SIZE;
LOG_I("total supported model_id(length is %d):", *length_out);
DUMP8("0x%02x ", models_out, *length_out);
}
else
{
ret = -1;
LOG_W("supported model id length exceeded max length");
}
}
return ret;
}
#endif