/*************************************************************************** * * 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. * ****************************************************************************/ #include #include "hal_sleep.h" #include "besbt.h" #include "nvrecord.h" #include "nvrecord_dev.h" #include "nvrecord_env.h" #include "crc32.h" #include "hal_timer.h" #include "hal_norflash.h" #include "pmu.h" #include "tgt_hardware.h" #include "norflash_api.h" //#define NVREC_BURN_TEST #define OS_DUMP8(x...) // factory section region #define NVRECORD_CACHE_2_UNCACHE(addr) \ ((unsigned char *)((unsigned int)addr & ~(0x04000000))) static bool dev_sector_valid = false; uint8_t nv_record_dev_rev = NVREC_DEV_NEWEST_REV; #define CLASSIC_BTNAME_LEN (BLE_NAME_LEN_IN_NV-5) char classics_bt_name[CLASSIC_BTNAME_LEN]= "BES"; extern uint32_t __factory_start[]; /* dev_version_and_magic, //0 dev_crc, // 1 dev_reserv1, // 2 dev_reserv2, //3// 3 dev_name, //[4~66] dev_bt_addr = 67, //[67~68] dev_ble_addr = 69, //[69~70] dev_dongle_addr = 71, dev_xtal_fcap = 73, //73 dev_data_len = 74, dev_ble_name = 75, //[75~82] */ #if !defined(NEW_NV_RECORD_ENABLED) #ifdef __ARMCC_VERSION #define USERDATA_POOL_LOC __attribute__((section(".bss.userdata_pool"))) #else #define USERDATA_POOL_LOC __attribute__((section(".userdata_pool"))) #endif //#define LINK_KEY_ENCRYPT #ifdef LINK_KEY_ENCRYPT #include "aes.h" #define LINK_KEY_ENCRYPT_KEY "\x11\x07\x9e\x34\x9B\x5F\x80\x00\x00\x80\x00\x10\x00\x00\x00\x01" #endif extern uint32_t __userdata_start[]; extern uint32_t __userdata_end[]; extern int nv_record_flash_flush_in_sleep(void); static int nv_record_flash_flush_int(bool is_async); void nv_callback(void* param); nv_record_struct nv_record_config; static bool nvrec_init = false; static bool nvrec_mempool_init = false; static uint32_t _user_data_main_start; static uint32_t _user_data_bak_start; static uint32_t USERDATA_POOL_LOC usrdata_ddblist_pool[1024]; static void nv_record_print_dev_record(const btif_device_record_t* record) { #ifdef nv_record_debug nvrec_trace(0,"nv record bdAddr = "); DUMP8("%02x ",record->bdAddr.address,sizeof(record->bdAddr.address)); nvrec_trace(0,"record_trusted = "); DUMP8("%d ",&record->trusted,sizeof((uint8_t)record->trusted)); nvrec_trace(0,"record_linkKey = "); DUMP8("%02x ",record->linkKey,sizeof(record->linkKey)); nvrec_trace(0,"record_keyType = "); DUMP8("%x ",&record->keyType,sizeof(record->keyType)); nvrec_trace(0,"record_pinLen = "); DUMP8("%x ",&record->pinLen,sizeof(record->pinLen)); #endif } heap_handle_t g_nv_mempool = NULL; static void nv_record_mempool_init(void) { unsigned char *poolstart = 0; poolstart = (unsigned char *)(usrdata_ddblist_pool+mempool_pre_offset); if(!nvrec_mempool_init) { g_nv_mempool = heap_register((unsigned char*)poolstart, (size_t)(sizeof(usrdata_ddblist_pool)-(mempool_pre_offset*sizeof(uint32_t)))); nvrec_mempool_init = TRUE; } /*add other memory pool */ } static bool nv_record_data_is_valid(void) { uint32_t crc; uint32_t flsh_crc; uint32_t verandmagic; verandmagic = usrdata_ddblist_pool[0]; if(((nvrecord_struct_version<<16)|nvrecord_magic) != verandmagic) { nvrec_trace(2,"%s: verandmagic error! verandmagic = 0x%x.",__func__,((nvrecord_struct_version<<16)|nvrecord_magic)); return false; } crc = crc32(0,(uint8_t *)(&usrdata_ddblist_pool[pos_heap_contents]),(sizeof(usrdata_ddblist_pool)-(pos_heap_contents*sizeof(uint32_t)))); flsh_crc = usrdata_ddblist_pool[pos_crc]; if (flsh_crc == crc) { return true; } else { nvrec_trace(3,"%s: crc checking fail! flsh_crc = 0x%x,crc = 0x%x.",__func__,flsh_crc,crc); return false; } } static bool nv_record_list_is_valid(void) { nvrec_config_t *config = NULL; nvrec_section_t *sec = NULL; list_node_t *node = NULL; list_node_t *sub_node = NULL; nvrec_entry_t *entry = NULL; bool ret = true; uint32_t mem_start; uint32_t mem_end; config = (nvrec_config_t *)usrdata_ddblist_pool[pos_config_addr]; if(usrdata_ddblist_pool[pos_start_ram_addr] != (uint32_t)usrdata_ddblist_pool) { return false; } mem_start = (uint32_t)config; mem_end = mem_start + (sizeof(usrdata_ddblist_pool)-(pos_heap_contents*sizeof(uint32_t))); for (node = list_begin_ext(config->sections); node != list_end_ext(config->sections); node = list_next_ext(node)) { sec = list_node_ext(node); for (sub_node = list_begin_ext(sec->entries); sub_node != list_end_ext(sec->entries); sub_node = list_next_ext(sub_node)) { entry = list_node_ext(sub_node); if(entry->key == NULL || entry->value == NULL) { ret = false; break; } if(((uint32_t)entry->key >= mem_start && (uint32_t)entry->key + strlen(entry->key) < mem_end) && ((uint32_t)entry->value >= mem_start && (uint32_t)entry->value + strlen(entry->value) < mem_end)) { // nvrec_trace(4,"%s: entry = 0x%x,key = 0x%x, value = 0x%x.", // __func__,(uint32_t)entry,(uint32_t)entry->key,(uint32_t)entry->value); } else { nvrec_trace(4,"%s: sec = 0x%x,name = %s, entries = 0x%x.", __func__,(uint32_t)sec,sec->name,(uint32_t)sec->entries); nvrec_trace(4,"%s: entry pointer error! entry = 0x%x,key = 0x%x, value = 0x%x.", __func__,(uint32_t)entry,(uint32_t)entry->key,(uint32_t)entry->value); ret = false; break; } } if(!ret) { break; } } return ret; } void nv_record_init(void) { enum NORFLASH_API_RET_T result; uint32_t sector_size = 0; uint32_t block_size = 0; uint32_t page_size = 0; hal_norflash_get_size(HAL_NORFLASH_ID_0, NULL, &block_size, §or_size, &page_size); result = norflash_api_register(NORFLASH_API_MODULE_ID_USERDATA, HAL_NORFLASH_ID_0, ((uint32_t)__userdata_start), (uint32_t)__userdata_end - (uint32_t)__userdata_start, block_size, sector_size, page_size, sizeof(usrdata_ddblist_pool)*2, nv_callback ); ASSERT(result == NORFLASH_API_OK,"nv_record_init: module register failed! result = %d.",result); } bt_status_t nv_record_open(SECTIONS_ADP_ENUM section_id) { bt_status_t ret_status = BT_STS_FAILED; uint32_t lock; bool main_is_valid = false; bool bak_is_valid = false; bool data_is_valid = false; if(nvrec_init) { return BT_STS_SUCCESS; } _user_data_main_start = (uint32_t)__userdata_start; _user_data_bak_start = (uint32_t)__userdata_start + nvrecord_mem_pool_size; lock = int_lock_global(); nv_record_config.is_update = false; nv_record_config.written_size = 0; nv_record_config.state = NV_STATE_IDLE; switch(section_id) { case section_usrdata_ddbrecord: // userdata main sector checking. memcpy((void *)usrdata_ddblist_pool,(void *)_user_data_main_start, sizeof(usrdata_ddblist_pool)); if( nv_record_data_is_valid() && usrdata_ddblist_pool[pos_start_ram_addr]==(uint32_t)usrdata_ddblist_pool) { if(nv_record_list_is_valid()) { // nvrec_trace(1,"%s,main sector list valid.",__func__); main_is_valid = true; } else { nvrec_trace(1,"%s,main sector list invalid.",__func__); main_is_valid = false; } } else { nvrec_trace(1,"%s,main sector data invalid.",__func__); main_is_valid = false; } // userdata bak sector checking. memcpy((void *)usrdata_ddblist_pool,(void *)_user_data_bak_start, sizeof(usrdata_ddblist_pool)); if( nv_record_data_is_valid() && usrdata_ddblist_pool[pos_start_ram_addr]==(uint32_t)usrdata_ddblist_pool) { if(nv_record_list_is_valid()) { // TRACE(1,"%s,bak sector list valid.",__func__); bak_is_valid = true; } else { nvrec_trace(1,"%s,bak sector list invalid.",__func__); bak_is_valid = false; } } else { nvrec_trace(1,"%s,bak sector data invalid.",__func__); bak_is_valid = false; } if(main_is_valid) { memcpy((void *)usrdata_ddblist_pool,(void *)_user_data_main_start, sizeof(usrdata_ddblist_pool)); data_is_valid = true; if(!bak_is_valid) { nv_record_config.is_update = true; nv_record_config.state = NV_STATE_MAIN_DONE; nv_record_config.config = (nvrec_config_t *)usrdata_ddblist_pool[pos_config_addr]; nv_record_flash_flush_int(false); } } else { if(bak_is_valid) { memcpy((void *)usrdata_ddblist_pool,(void *)_user_data_bak_start, sizeof(usrdata_ddblist_pool)); nv_record_config.config = (nvrec_config_t *)usrdata_ddblist_pool[pos_config_addr]; data_is_valid = true; nv_record_config.is_update = true; nv_record_config.state = NV_STATE_IDLE; nv_record_flash_flush_int(false); } else { data_is_valid = false; } } if(data_is_valid) { nv_record_config.config = (nvrec_config_t *)usrdata_ddblist_pool[pos_config_addr]; // nvrec_trace(4,"%s,config=0x%x,g_nv_mempool=0x%x,ln=%d\n", // nvrecord_tag,usrdata_ddblist_pool[pos_config_addr],g_nv_mempool,__LINE__); g_nv_mempool = (heap_handle_t)(&usrdata_ddblist_pool[mempool_pre_offset]); ret_status = BT_STS_SUCCESS; } else { nvrec_trace(1,"%s,userdata invalid. ",__func__); ret_status = nv_record_config_rebuild(); if(ret_status != BT_STS_SUCCESS) { break; } ret_status = BT_STS_SUCCESS; } break; default: break; } nvrec_init = true; if (ret_status == BT_STS_SUCCESS) { #ifdef FLASH_SUSPEND hal_sleep_set_sleep_hook(HAL_SLEEP_HOOK_USER_NVRECORD, nv_record_flash_flush_in_sleep); #else hal_sleep_set_deep_sleep_hook(HAL_DEEP_SLEEP_HOOK_USER_NVRECORD, nv_record_flash_flush_in_sleep); #endif } int_unlock_global(lock); nvrec_trace(2,"%s,open,ret_status=%d\n",nvrecord_tag,ret_status); return ret_status; } bt_status_t nv_record_config_rebuild(void) { nvrec_mempool_init = false; memset(usrdata_ddblist_pool,0,sizeof(usrdata_ddblist_pool)); usrdata_ddblist_pool[pos_version_and_magic] = ((nvrecord_struct_version<<16)|nvrecord_magic); nv_record_mempool_init(); nv_record_config.config = nvrec_config_new("PRECIOUS 4K."); if(nv_record_config.config == NULL) return BT_STS_FAILED; nvrec_init = true; nv_record_config.is_update = true; return BT_STS_SUCCESS; } static size_t config_entries_get_ddbrec_length(const char *secname) { size_t entries_len = 0; if(NULL != nv_record_config.config) { nvrec_section_t *sec = NULL; sec = nvrec_section_find(nv_record_config.config,secname); if (NULL != sec) entries_len = sec->entries->length; } return entries_len; } #if 0 static bool config_entries_has_ddbrec(const btif_device_record_t* param_rec) { char key[BD_ADDR_SIZE+1] = {0,}; assert(param_rec != NULL); memcpy(key,param_rec->bdAddr.address,BTIF_BD_ADDR_SIZE); if(nvrec_config_has_key(nv_record_config.config,section_name_ddbrec,(const char *)key)) return true; return false; } #endif static void config_entries_ddbdev_delete_head(void)//delete the oldest record. { list_node_t *head_node = NULL; list_t *entry = NULL; nvrec_section_t *sec = NULL; sec = nvrec_section_find(nv_record_config.config,section_name_ddbrec); entry = sec->entries; head_node = list_begin_ext(entry); if(NULL != head_node) { btif_device_record_t *rec = NULL; unsigned int recaddr = 0; nvrec_entry_t *entry_temp = list_node_ext(head_node); recaddr = nvrec_config_get_int(nv_record_config.config,section_name_ddbrec,entry_temp->key,0); rec = (btif_device_record_t *)recaddr; pool_free(rec); nvrec_entry_free(entry_temp); if(1 == config_entries_get_ddbrec_length(section_name_ddbrec)) entry->head = entry->tail = NULL; else entry->head = list_next_ext(head_node); pool_free(head_node); entry->length -= 1; } } static void config_entries_ddbdev_delete_tail(void) { list_node_t *node = NULL; list_node_t *temp_ptr = NULL; list_node_t *tailnode = NULL; size_t entrieslen = 0; nvrec_entry_t *entry_temp = NULL; nvrec_section_t *sec = nvrec_section_find(nv_record_config.config,section_name_ddbrec); btif_device_record_t *recaddr = NULL; unsigned int addr = 0; if (!sec) assert(0); sec->entries->length -= 1; entrieslen = sec->entries->length; node = list_begin_ext(sec->entries); while(entrieslen > 1) { node = list_next_ext(node); entrieslen--; } tailnode = list_next_ext(node); entry_temp = list_node_ext(tailnode); addr = nvrec_config_get_int(nv_record_config.config,section_name_ddbrec,entry_temp->key,0); recaddr = (btif_device_record_t *)addr; pool_free(recaddr); nvrec_entry_free(entry_temp); //pool_free(entry_temp); temp_ptr = node->next; node->next = NULL; pool_free(temp_ptr); sec->entries->tail = node; } static void config_entries_ddbdev_delete(const btif_device_record_t* param_rec) { nvrec_section_t *sec = NULL; list_node_t *entry_del = NULL; list_node_t *entry_pre = NULL; list_node_t *entry_next = NULL; list_node_t *node = NULL; btif_device_record_t *recaddr = NULL; unsigned int addr = 0; int pos = 0,pos_pre=0; nvrec_entry_t *entry_temp = NULL; sec = nvrec_section_find(nv_record_config.config,section_name_ddbrec); for(node=list_begin_ext(sec->entries);node!=NULL;node=list_next_ext(node)) { nvrec_entry_t *entries = list_node_ext(node); pos++; if(0 == memcmp(entries->key,param_rec->bdAddr.address,BTIF_BD_ADDR_SIZE)) { entry_del = node; entry_next = entry_del->next; break; } } if (entry_del){ /*get entry_del pre node*/ pos_pre = (pos-1); pos=0; node=list_begin_ext(sec->entries); pos++; while(pos < pos_pre) { node=list_next_ext(node); pos += 1; } entry_pre = node; /*delete entry_del following...*/ entry_temp = list_node_ext(entry_del); addr = nvrec_config_get_int(nv_record_config.config,section_name_ddbrec,(char *)entry_temp->key,0); assert(0!=addr); recaddr = (btif_device_record_t *)addr; pool_free(recaddr); nvrec_entry_free(entry_temp); //pool_free(entry_temp); pool_free(entry_pre->next); entry_pre->next = entry_next; sec->entries->length -= 1; } } static bool config_entries_ddbdev_is_head(const btif_device_record_t* param_rec) { list_node_t *head_node = NULL; nvrec_section_t *sec = NULL; list_t *entry = NULL; nvrec_entry_t *entry_temp = NULL; sec = nvrec_section_find(nv_record_config.config,section_name_ddbrec); entry = sec->entries; head_node = list_begin_ext(entry); entry_temp = list_node_ext(head_node); if(0 == memcmp(entry_temp->key,param_rec->bdAddr.address,BTIF_BD_ADDR_SIZE)) return true; return false; } static bool config_entries_ddbdev_is_tail(const btif_device_record_t* param_rec) { list_node_t *node = NULL; nvrec_entry_t *entry_temp = NULL; nvrec_section_t *sec = nvrec_section_find(nv_record_config.config,section_name_ddbrec); if (!sec) assert(0); for (node = list_begin_ext(sec->entries); node != list_end_ext(sec->entries); node = list_next_ext(node)) { entry_temp = list_node_ext(node); } if(0 == memcmp(entry_temp->key,param_rec->bdAddr.address,BTIF_BD_ADDR_SIZE)) return true; return false; } /* this function should be surrounded by OS_LockStack and OS_UnlockStack when call. */ static void config_specific_entry_value_delete(const btif_device_record_t* param_rec) { if(config_entries_ddbdev_is_head(param_rec)) config_entries_ddbdev_delete_head(); else if(config_entries_ddbdev_is_tail(param_rec)) config_entries_ddbdev_delete_tail(); else config_entries_ddbdev_delete(param_rec); nv_record_update_runtime_userdata(); } /********************************************** gyt add:list head is the odest,list tail is the latest. this function should be surrounded by OS_LockStack and OS_UnlockStack when call. **********************************************/ static bt_status_t POSSIBLY_UNUSED nv_record_ddbrec_add(const btif_device_record_t* param_rec) { btdevice_volume device_vol; btdevice_profile device_plf; char key[BTIF_BD_ADDR_SIZE+1] = {0,}; nvrec_btdevicerecord *nvrec_pool_record = NULL; bool ddbrec_exist = false; bool is_flush = true; int getint; #ifdef BTIF_DIP_DEVICE uint16_t vend_id = 0; uint16_t vend_id_source = 0; #endif device_vol.a2dp_vol = NVRAM_ENV_STREAM_VOLUME_A2DP_VOL_DEFAULT; device_vol.hfp_vol = NVRAM_ENV_STREAM_VOLUME_HFP_VOL_DEFAULT; device_plf.hfp_act = false; device_plf.hsp_act = false; device_plf.a2dp_act = false; device_plf.a2dp_codectype = 0; if(NULL == param_rec) return BT_STS_FAILED; memcpy(key,param_rec->bdAddr.address,BTIF_BD_ADDR_SIZE); getint = nvrec_config_get_int(nv_record_config.config,section_name_ddbrec,(char *)key,0); if(getint){ ddbrec_exist = true; nvrec_pool_record = (nvrec_btdevicerecord *)getint; device_vol.a2dp_vol = nvrec_pool_record->device_vol.a2dp_vol; device_vol.hfp_vol = nvrec_pool_record->device_vol.hfp_vol; device_plf.hfp_act = nvrec_pool_record->device_plf.hfp_act; device_plf.hsp_act = nvrec_pool_record->device_plf.hsp_act; device_plf.a2dp_act = nvrec_pool_record->device_plf.a2dp_act; device_plf.a2dp_codectype = nvrec_pool_record->device_plf.a2dp_codectype; #ifdef BTIF_DIP_DEVICE vend_id = nvrec_pool_record->vend_id; vend_id_source = nvrec_pool_record->vend_id_source; #endif if( memcmp(&nvrec_pool_record->record.bdAddr, ¶m_rec->bdAddr,sizeof(nvrec_pool_record->record.bdAddr)) == 0 && memcmp(nvrec_pool_record->record.linkKey, param_rec->linkKey,sizeof(nvrec_pool_record->record.linkKey)) == 0 && nvrec_pool_record->record.trusted == param_rec->trusted && nvrec_pool_record->record.pinLen == param_rec->pinLen && nvrec_pool_record->record.keyType == param_rec->keyType && config_entries_ddbdev_is_tail(param_rec) ){ is_flush = false; } } if(is_flush){ if (pool_free_space() < sizeof(nvrec_btdevicerecord)) { nvrec_trace(1,"%s,free space of nvrec is not enough!",nvrecord_tag); config_entries_ddbdev_delete_head(); } nvrec_pool_record = (nvrec_btdevicerecord *)pool_malloc(sizeof(nvrec_btdevicerecord)); if(NULL == nvrec_pool_record){ nvrec_trace(1,"%s,pool_malloc failure.",nvrecord_tag); return BT_STS_FAILED; } nvrec_trace(2,"%s,pool_malloc addr = 0x%x\n",nvrecord_tag,(unsigned int)nvrec_pool_record); memcpy(nvrec_pool_record,param_rec,sizeof(btif_device_record_t)); #ifdef LINK_KEY_ENCRYPT U8 linkKey[16]; AES128_ECB_encrypt(param_rec->linkKey, LINK_KEY_ENCRYPT_KEY, linkKey); memcpy(nvrec_pool_record->record.linkKey, linkKey, 16); #endif memcpy(key,param_rec->bdAddr.address,BTIF_BD_ADDR_SIZE); nvrec_pool_record->device_vol.a2dp_vol = device_vol.a2dp_vol; nvrec_pool_record->device_vol.hfp_vol = device_vol.hfp_vol; nvrec_pool_record->device_plf.hfp_act = device_plf.hfp_act; nvrec_pool_record->device_plf.hsp_act = device_plf.hsp_act; nvrec_pool_record->device_plf.a2dp_act = device_plf.a2dp_act; nvrec_pool_record->device_plf.a2dp_codectype = device_plf.a2dp_codectype; #ifdef BTIF_DIP_DEVICE nvrec_pool_record->vend_id = vend_id; nvrec_pool_record->vend_id_source = vend_id_source; #endif if (ddbrec_exist){ config_specific_entry_value_delete(param_rec); } if(DDB_RECORD_NUM == config_entries_get_ddbrec_length(section_name_ddbrec)) { nvrec_trace(1,"%s,ddbrec list is full,delete the oldest and add param_rec to list.",nvrecord_tag); config_entries_ddbdev_delete_head(); } nvrec_config_set_int(nv_record_config.config,section_name_ddbrec,(char *)key,(int)nvrec_pool_record); #ifdef nv_record_debug getint = nvrec_config_get_int(nv_record_config.config,section_name_ddbrec,(char *)key,0); nvrec_trace(2,"%s,get pool_malloc addr = 0x%x\n",nvrecord_tag,(unsigned int)getint); #endif nv_record_update_runtime_userdata(); } return BT_STS_SUCCESS; } /* this function should be surrounded by OS_LockStack and OS_UnlockStack when call. */ bt_status_t nv_record_add(SECTIONS_ADP_ENUM type,void *record) { bt_status_t retstatus = BT_STS_FAILED; if ((NULL == record) || (section_none == type)) return BT_STS_FAILED; switch(type) { case section_usrdata_ddbrecord: retstatus = nv_record_ddbrec_add(record); break; default: break; } return retstatus; } /* this function should be surrounded by OS_LockStack and OS_UnlockStack when call. */ bt_status_t nv_record_ddbrec_find(const bt_bdaddr_t* bd_ddr,btif_device_record_t *record) { unsigned int getint = 0; char key[BTIF_BD_ADDR_SIZE+1] = {0,}; btif_device_record_t *getrecaddr = NULL; if((NULL == nv_record_config.config) || (NULL == bd_ddr) || (NULL == record)) return BT_STS_FAILED; memcpy(key,bd_ddr->address,BTIF_BD_ADDR_SIZE); getint = nvrec_config_get_int(nv_record_config.config,section_name_ddbrec,(char *)key,0); if(0 == getint) return BT_STS_FAILED; getrecaddr = (btif_device_record_t *)getint; memcpy(record,(void *)getrecaddr,sizeof(btif_device_record_t)); #ifdef LINK_KEY_ENCRYPT U8 linkKey[16]; AES128_ECB_decrypt(getrecaddr->linkKey, LINK_KEY_ENCRYPT_KEY, linkKey); memcpy(record->linkKey, linkKey, 16); #endif return BT_STS_SUCCESS; } int nv_record_btdevicerecord_find(const bt_bdaddr_t *bd_ddr, nvrec_btdevicerecord **record) { unsigned int getint = 0; char key[BTIF_BD_ADDR_SIZE+1] = {0,}; if((NULL == nv_record_config.config) || (NULL == bd_ddr) || (NULL == record)) return -1; memcpy(key,bd_ddr->address, BTIF_BD_ADDR_SIZE); getint = nvrec_config_get_int(nv_record_config.config,section_name_ddbrec,(char *)key,0); if(0 == getint) return -1; *record = (nvrec_btdevicerecord *)getint; return 0; } void nv_record_btdevicerecord_set_a2dp_vol(nvrec_btdevicerecord* pRecord, int8_t vol) { pRecord->device_vol.a2dp_vol = vol; } void nv_record_btdevicerecord_set_hfp_vol(nvrec_btdevicerecord* pRecord, int8_t vol) { pRecord->device_vol.hfp_vol = vol; } void nv_record_btdevicevolume_set_a2dp_vol(btdevice_volume* device_vol, int8_t vol) { device_vol->a2dp_vol = vol; } void nv_record_btdevicevolume_set_hfp_vol(btdevice_volume* device_vol, int8_t vol) { device_vol->hfp_vol = vol; } void nv_record_btdevicerecord_set_vend_id_and_source(nvrec_btdevicerecord* pRecord, int16_t vend_id, int16_t vend_id_source) { #ifdef BTIF_DIP_DEVICE if (vend_id != pRecord->vend_id) { pRecord->vend_id = vend_id; pRecord->vend_id_source = vend_id_source; } #endif } void nv_record_btdevicerecord_set_a2dp_profile_active_state(btdevice_profile* device_plf, bool isActive) { device_plf->a2dp_act = isActive; } void nv_record_btdevicerecord_set_hfp_profile_active_state(btdevice_profile* device_plf, bool isActive) { device_plf->hfp_act = isActive; } void nv_record_btdevicerecord_set_hsp_profile_active_state(btdevice_profile* device_plf, bool isActive) { device_plf->hsp_act = isActive; } void nv_record_btdevicerecord_set_a2dp_profile_codec(btdevice_profile* device_plf, uint8_t a2dpCodec) { device_plf->a2dp_codectype = a2dpCodec; } uint32_t nv_record_pre_write_operation(void) { return 0; } void nv_record_post_write_operation(uint32_t lock) { } /* this function should be surrounded by OS_LockStack and OS_UnlockStack when call. */ bt_status_t nv_record_ddbrec_delete(const bt_bdaddr_t *bdaddr) { unsigned int getint = 0; btif_device_record_t *getrecaddr = NULL; char key[BTIF_BD_ADDR_SIZE+1] = {0,}; memcpy(key,bdaddr->address,BTIF_BD_ADDR_SIZE); getint = nvrec_config_get_int(nv_record_config.config,section_name_ddbrec,(char *)key,0); if(0 == getint) return BT_STS_FAILED; //found ddb record,del it and return succeed. getrecaddr = (btif_device_record_t *)getint; config_specific_entry_value_delete((const btif_device_record_t *)getrecaddr); return BT_STS_SUCCESS; } /* this function should be surrounded by OS_LockStack and OS_UnlockStack when call. */ bt_status_t nv_record_enum_dev_records(unsigned short index,btif_device_record_t* record) { nvrec_section_t *sec = NULL; list_node_t *node = NULL; unsigned short pos = 0; nvrec_entry_t *entry_temp = NULL; btif_device_record_t *recaddr = NULL; unsigned int addr = 0; if((index >= DDB_RECORD_NUM) || (NULL == record) || (NULL == nv_record_config.config)) return BT_STS_FAILED; sec = nvrec_section_find(nv_record_config.config,section_name_ddbrec); if(NULL == sec) return BT_STS_INVALID_PARM; if(NULL == sec->entries) return BT_STS_INVALID_PARM; if(0 == sec->entries->length) return BT_STS_FAILED; if(index >= sec->entries->length) return BT_STS_FAILED; node = list_begin_ext(sec->entries); while(pos < index) { node = list_next_ext(node); pos++; } entry_temp = list_node_ext(node); addr = nvrec_config_get_int(nv_record_config.config,section_name_ddbrec,(char *)entry_temp->key,0); if(0 == addr) return BT_STS_FAILED; recaddr = (btif_device_record_t *)addr; memcpy(record,recaddr,sizeof(btif_device_record_t)); #ifdef LINK_KEY_ENCRYPT U8 linkKey[16]; AES128_ECB_decrypt(recaddr->linkKey, LINK_KEY_ENCRYPT_KEY, linkKey); memcpy(record->linkKey, linkKey, 16); #endif nv_record_print_dev_record(record); return BT_STS_SUCCESS; } /* return: -1: enum dev failure. 0: without paired dev. 1: only 1 paired dev,store@record1. 2: get 2 paired dev.notice:record1 is the latest record. */ int nv_record_enum_latest_two_paired_dev(btif_device_record_t* record1,btif_device_record_t* record2) { bt_status_t getret1 = BT_STS_FAILED; bt_status_t getret2 = BT_STS_FAILED; nvrec_section_t *sec = NULL; size_t entries_len = 0; list_t *entry = NULL; if((NULL == record1) || (NULL == record2)) return -1; sec = nvrec_section_find(nv_record_config.config,section_name_ddbrec); if(NULL == sec) return 0; entry = sec->entries; if(NULL == entry) return 0; entries_len = entry->length; if(0 == entries_len) return 0; else if(entries_len < 0) return -1; if(1 == entries_len) { getret1 = nv_record_enum_dev_records(0,record1); if(BT_STS_SUCCESS == getret1) return 1; return -1; } getret1 = nv_record_enum_dev_records(entries_len-1,record1); getret2 = nv_record_enum_dev_records(entries_len-2,record2); if((BT_STS_SUCCESS != getret1) || (BT_STS_SUCCESS != getret2)) { memset(record1,0x0,sizeof(btif_device_record_t)); memset(record2,0x0,sizeof(btif_device_record_t)); return -1; } return 2; } int nv_record_touch_cause_flush(void) { nv_record_update_runtime_userdata(); return 0; } void nv_record_all_ddbrec_print(void) { list_t *entry = NULL; int tmp_i = 0; nvrec_section_t *sec = NULL; size_t entries_len = 0; sec = nvrec_section_find(nv_record_config.config,section_name_ddbrec); if(NULL == sec) return; entry = sec->entries; if(NULL == entry) return; entries_len = entry->length; if(0 == entries_len) { nvrec_trace(1,"%s: without btdevicerec.",__func__); return; } for(tmp_i=0;tmp_ientries; if(NULL == entry) return 0; return entry->length; } void nv_record_sector_clear(void) { uint32_t lock; enum NORFLASH_API_RET_T ret,ret1; lock = int_lock_global(); ret = norflash_api_erase(NORFLASH_API_MODULE_ID_USERDATA, (uint32_t)__userdata_start, sizeof(usrdata_ddblist_pool), false); ret1 = norflash_api_erase(NORFLASH_API_MODULE_ID_USERDATA, (uint32_t)__userdata_start + nvrecord_mem_pool_size, sizeof(usrdata_ddblist_pool), false); nvrec_init = false; nvrec_mempool_init = false; int_unlock_global(lock); ASSERT(ret == NORFLASH_API_OK,"nv_record_sector_clear: erase main sector failed! ret = %d.",ret); ASSERT(ret1 == NORFLASH_API_OK,"nv_record_sector_clear: erase bak sector failed! ret1 = %d.",ret1); } #define DISABLE_NV_RECORD_CRC_CHECK_BEFORE_FLUSH 1 void nv_record_update_runtime_userdata(void) { uint32_t lock; if (NULL == nv_record_config.config) { return; } lock = int_lock(); nv_record_config.is_update = true; #if !DISABLE_NV_RECORD_CRC_CHECK_BEFORE_FLUSH buffer_alloc_ctx* heapctx = memory_buffer_heap_getaddr(); memcpy((void *)(&usrdata_ddblist_pool[pos_heap_contents]),heapctx,sizeof(buffer_alloc_ctx)); uint32_t crc = crc32(0,(uint8_t *)(&usrdata_ddblist_pool[pos_heap_contents]),(sizeof(usrdata_ddblist_pool)-(pos_heap_contents*sizeof(uint32_t)))); usrdata_ddblist_pool[pos_crc] = crc; #endif int_unlock(lock); } static int nv_record_flash_flush_main(bool is_async) { uint32_t crc; uint32_t lock; enum NORFLASH_API_RET_T ret = NORFLASH_API_OK; uint8_t *burn_buf = NULL; uint32_t verandmagic; if(NULL == nv_record_config.config) { nvrec_trace(1,"%s,nv_record_config.config is null.\n", __func__); goto _func_end; } burn_buf = (uint8_t *)&usrdata_ddblist_pool[0]; verandmagic = usrdata_ddblist_pool[0]; ASSERT((((nvrecord_struct_version<<16)|nvrecord_magic) == verandmagic), "%s: verandmagic = 0x%08x.", __func__, verandmagic); if(is_async) { hal_trace_pause(); lock = int_lock_global(); if(nv_record_config.state == NV_STATE_IDLE || nv_record_config.state == NV_STATE_MAIN_ERASING) { if(nv_record_config.state == NV_STATE_IDLE) { nv_record_config.state = NV_STATE_MAIN_ERASING; // nvrec_trace(1,"%s: NV_STATE_MAIN_ERASING", __func__); } ret = norflash_api_erase(NORFLASH_API_MODULE_ID_USERDATA, _user_data_main_start, sizeof(usrdata_ddblist_pool), true); if(ret == NORFLASH_API_OK) { nv_record_config.state = NV_STATE_MAIN_ERASED; // nvrec_trace(1,"%s: NV_STATE_MAIN_ERASED", __func__); nvrec_trace(2,"%s: norflash_api_erase ok,addr = 0x%x.",__func__,_user_data_main_start); } else if(ret == NORFLASH_API_BUFFER_FULL) { norflash_api_flush(); } else { ASSERT(0,"%s: norflash_api_erase err,ret = %d,addr = 0x%x.",__func__,ret,_user_data_main_start); } } else if(nv_record_config.state == NV_STATE_MAIN_ERASED || nv_record_config.state == NV_STATE_MAIN_WRITTING) { if(nv_record_config.state == NV_STATE_MAIN_ERASED) { nv_record_config.state = NV_STATE_MAIN_WRITTING; // nvrec_trace(1,"%s: NV_STATE_MAIN_WRITTING", __func__); } crc = crc32(0,(uint8_t *)(&usrdata_ddblist_pool[pos_heap_contents]),(sizeof(usrdata_ddblist_pool)-(pos_heap_contents*sizeof(uint32_t)))); //nvrec_trace(2,"%s,crc=%x.\n",nvrecord_tag,crc); usrdata_ddblist_pool[pos_version_and_magic] = ((nvrecord_struct_version<<16)|nvrecord_magic); usrdata_ddblist_pool[pos_crc] = crc; usrdata_ddblist_pool[pos_start_ram_addr] = (uint32_t)&usrdata_ddblist_pool; usrdata_ddblist_pool[pos_reserv2] = 0; usrdata_ddblist_pool[pos_config_addr] = (uint32_t)nv_record_config.config; ASSERT(nv_record_list_is_valid(),"%s nv_record_list is invalid!",__func__); ret = norflash_api_write(NORFLASH_API_MODULE_ID_USERDATA, _user_data_main_start, burn_buf, sizeof(usrdata_ddblist_pool), true ); if(ret == NORFLASH_API_OK) { nv_record_config.is_update = false; nv_record_config.state = NV_STATE_MAIN_WRITTEN; // nvrec_trace(1,"%s: NV_STATE_MAIN_WRITTEN", __func__); nvrec_trace(2,"%s: norflash_api_write ok,addr = 0x%x.",__func__,_user_data_main_start); } else if(ret == NORFLASH_API_BUFFER_FULL) { norflash_api_flush(); } else { ASSERT(0,"%s: norflash_api_write err,ret = %d,addr = 0x%x.",__func__,ret,_user_data_main_start); } } else { if(norflash_api_get_used_buffer_count(NORFLASH_API_MODULE_ID_USERDATA,NORFLASH_API_ALL) == 0) { nv_record_config.state = NV_STATE_MAIN_DONE; // nvrec_trace(1,"%s: NV_STATE_MAIN_DONE", __func__); } else { norflash_api_flush(); } } int_unlock_global(lock); hal_trace_continue(); } else { // nvrec_trace(1,"%s: sync flush begin!", __func__); if(nv_record_config.state == NV_STATE_IDLE || nv_record_config.state == NV_STATE_MAIN_ERASING) { do { hal_trace_pause(); lock = int_lock_global(); ret = norflash_api_erase(NORFLASH_API_MODULE_ID_USERDATA, _user_data_main_start, sizeof(usrdata_ddblist_pool), true); int_unlock_global(lock); hal_trace_continue(); if(ret == NORFLASH_API_OK) { nv_record_config.state = NV_STATE_MAIN_ERASED; nvrec_trace(2,"%s: norflash_api_erase ok,addr = 0x%x.",__func__, _user_data_main_start); } else if(ret == NORFLASH_API_BUFFER_FULL) { do { norflash_api_flush(); }while(norflash_api_get_free_buffer_count(NORFLASH_API_ERASING) == 0); } else { ASSERT(0,"%s: norflash_api_erase err,ret = %d,addr = 0x%x.",__func__,ret,_user_data_main_start); } }while(ret == NORFLASH_API_BUFFER_FULL); } if(nv_record_config.state == NV_STATE_MAIN_ERASED) { do { hal_trace_pause(); lock = int_lock_global(); crc = crc32(0,(uint8_t *)(&usrdata_ddblist_pool[pos_heap_contents]),(sizeof(usrdata_ddblist_pool)-(pos_heap_contents*sizeof(uint32_t)))); //nvrec_trace(2,"%s,crc=%x.\n",nvrecord_tag,crc); usrdata_ddblist_pool[pos_version_and_magic] = ((nvrecord_struct_version<<16)|nvrecord_magic); usrdata_ddblist_pool[pos_crc] = crc; usrdata_ddblist_pool[pos_start_ram_addr] = (uint32_t)&usrdata_ddblist_pool; usrdata_ddblist_pool[pos_reserv2] = 0; usrdata_ddblist_pool[pos_config_addr] = (uint32_t)nv_record_config.config; ASSERT(nv_record_list_is_valid(),"%s nv_record_list is invalid!",__func__); ret = norflash_api_write(NORFLASH_API_MODULE_ID_USERDATA, _user_data_main_start, burn_buf, sizeof(usrdata_ddblist_pool), true ); int_unlock_global(lock); hal_trace_continue(); if(ret == NORFLASH_API_OK) { nv_record_config.is_update = false; nv_record_config.state = NV_STATE_MAIN_WRITTEN; nvrec_trace(2,"%s: norflash_api_write ok,addr = 0x%x.",__func__,_user_data_main_start); } else if(ret == NORFLASH_API_BUFFER_FULL) { do { norflash_api_flush(); }while(norflash_api_get_free_buffer_count(NORFLASH_API_WRITTING) == 0); } else { ASSERT(0,"%s: norflash_api_write err,ret = %d,addr = 0x%x.",__func__,ret,_user_data_main_start); } }while(ret == NORFLASH_API_BUFFER_FULL); do { norflash_api_flush(); }while(norflash_api_get_used_buffer_count(NORFLASH_API_MODULE_ID_USERDATA,NORFLASH_API_ALL) > 0); nv_record_config.state = NV_STATE_MAIN_DONE; nvrec_trace(1,"%s: sync flush done.", __func__); } #if 0 //#ifdef nv_record_debug if (ret == NORFLASH_API_OK) { uint32_t recrc; uint32_t crc; uint8_t* burn_buf; uint8_t* read_buffer = (uint8_t*)__userdata_start; burn_buf = (uint8_t *)&usrdata_ddblist_pool[0]; crc = ((uint32_t *)burn_buf)[pos_crc]; recrc = crc32(0,((uint8_t *)read_buffer + sizeof(uint32_t)*pos_heap_contents),(sizeof(usrdata_ddblist_pool)-(pos_heap_contents*sizeof(uint32_t)))); ASSERT(crc == recrc,"%s, 0x%x,recrc=%08x crc=%08x\n", __func__,_user_data_main_start,recrc,crc); TRACE(1,"%s crc ok.",__func__); } #endif } _func_end: return (ret == NORFLASH_API_OK) ? 0:1; } static int nv_record_flash_flush_bak(bool is_async) { uint32_t lock; enum NORFLASH_API_RET_T ret = NORFLASH_API_OK; uint8_t burn_buf[128]; if(is_async) { hal_trace_pause(); lock = int_lock_global(); if(nv_record_config.state == NV_STATE_MAIN_DONE || nv_record_config.state == NV_STATE_BAK_ERASING) { if(nv_record_config.state == NV_STATE_MAIN_DONE) { nv_record_config.state = NV_STATE_BAK_ERASING; // nvrec_trace(1,"%s: NV_STATE_BAK_ERASING", __func__); } ret = norflash_api_erase(NORFLASH_API_MODULE_ID_USERDATA, _user_data_bak_start, sizeof(usrdata_ddblist_pool), true); if(ret == NORFLASH_API_OK) { nv_record_config.state = NV_STATE_BAK_ERASED; nvrec_trace(2,"%s: norflash_api_erase ok,addr = 0x%x.", __func__,_user_data_bak_start); // nvrec_trace(1,"%s: NV_STATE_BAK_ERASED", __func__); } else if(ret == NORFLASH_API_BUFFER_FULL) { norflash_api_flush(); } else { ASSERT(0,"%s: norflash_api_erase err,ret = %d,addr = 0x%x.", __func__,ret,_user_data_bak_start); } } else if(nv_record_config.state == NV_STATE_BAK_ERASED || nv_record_config.state == NV_STATE_BAK_WRITTING) { if(nv_record_config.state == NV_STATE_BAK_ERASED) { nv_record_config.state = NV_STATE_BAK_WRITTING; nv_record_config.written_size = 0; // nvrec_trace(1,"%s: NV_STATE_BAK_WRITTING", __func__); } do { ret = norflash_api_read(NORFLASH_API_MODULE_ID_USERDATA, _user_data_main_start + nv_record_config.written_size, burn_buf, sizeof(burn_buf) ); ASSERT(ret == NORFLASH_API_OK,"norflash_api_read failed! ret = %d, addr = 0x%x.", (int32_t)ret,_user_data_main_start + nv_record_config.written_size); ret = norflash_api_write(NORFLASH_API_MODULE_ID_USERDATA, _user_data_bak_start + nv_record_config.written_size, burn_buf, sizeof(burn_buf), true ); if(ret == NORFLASH_API_OK) { nv_record_config.written_size += sizeof(burn_buf); if(nv_record_config.written_size == nvrecord_mem_pool_size) { nv_record_config.state = NV_STATE_BAK_WRITTEN; // nvrec_trace(1,"%s: NV_STATE_BAK_WRITTEN", __func__); break; } } else if(ret == NORFLASH_API_BUFFER_FULL) { norflash_api_flush(); break; } else { ASSERT(0,"%s: norflash_api_write err,ret = %d,addr = 0x%x.", __func__,ret,_user_data_bak_start + nv_record_config.written_size); } }while(1); } else { if(norflash_api_get_used_buffer_count(NORFLASH_API_MODULE_ID_USERDATA,NORFLASH_API_ALL) == 0) { // nvrec_trace(1,"%s: NV_STATE_BAK_DONE", __func__); nv_record_config.state = NV_STATE_BAK_DONE; } else { norflash_api_flush(); } } int_unlock_global(lock); hal_trace_continue(); } else { // nvrec_trace(1,"%s: sync flush begin.", __func__); if(nv_record_config.state == NV_STATE_MAIN_DONE || nv_record_config.state == NV_STATE_BAK_ERASING) { do { hal_trace_pause(); lock = int_lock_global(); ret = norflash_api_erase(NORFLASH_API_MODULE_ID_USERDATA, _user_data_bak_start, sizeof(usrdata_ddblist_pool), true); int_unlock_global(lock); hal_trace_continue(); if(ret == NORFLASH_API_OK) { nv_record_config.state = NV_STATE_BAK_ERASED; nvrec_trace(2,"%s: norflash_api_erase ok,addr = 0x%x.", __func__, _user_data_bak_start); } else if(ret == NORFLASH_API_BUFFER_FULL) { do { norflash_api_flush(); }while(norflash_api_get_free_buffer_count(NORFLASH_API_ERASING) == 0); } else { ASSERT(0,"%s: norflash_api_erase err,ret = %d,addr = 0x%x.",__func__,ret,_user_data_bak_start); } }while(ret == NORFLASH_API_BUFFER_FULL); } if(nv_record_config.state == NV_STATE_BAK_ERASED) { nv_record_config.state = NV_STATE_BAK_WRITTING; nv_record_config.written_size = 0; do { hal_trace_pause(); do { lock = int_lock_global(); ret = norflash_api_read(NORFLASH_API_MODULE_ID_USERDATA, _user_data_main_start + nv_record_config.written_size, burn_buf, sizeof(burn_buf) ); ASSERT(ret == NORFLASH_API_OK,"norflash_api_read failed! ret = %d, addr = 0x%x.", (int32_t)ret, _user_data_main_start + nv_record_config.written_size); ret = norflash_api_write(NORFLASH_API_MODULE_ID_USERDATA, _user_data_bak_start + nv_record_config.written_size, burn_buf, sizeof(burn_buf), true ); int_unlock_global(lock); if(ret == NORFLASH_API_OK) { nv_record_config.written_size += sizeof(burn_buf); if(nv_record_config.written_size == nvrecord_mem_pool_size) { nv_record_config.state = NV_STATE_BAK_WRITTEN; break; } } else if(ret == NORFLASH_API_BUFFER_FULL) { nv_record_config.state = NV_STATE_BAK_WRITTING; do { norflash_api_flush(); }while(norflash_api_get_free_buffer_count(NORFLASH_API_WRITTING) == 0); } else { ASSERT(0,"%s: norflash_api_write err,ret = %d,addr = 0x%x.", __func__,ret,_user_data_bak_start + nv_record_config.written_size); } }while(1); hal_trace_continue(); if(ret == NORFLASH_API_OK) { nv_record_config.state = NV_STATE_BAK_WRITTEN; nvrec_trace(3,"%s: norflash_api_write ok,addr = 0x%x,len = 0x%x.", __func__,_user_data_bak_start,nv_record_config.written_size); } else if(ret == NORFLASH_API_BUFFER_FULL) { do { norflash_api_flush(); }while(norflash_api_get_free_buffer_count(NORFLASH_API_WRITTING) == 0); } else { ASSERT(0,"%s: norflash_api_write err,ret = %d,addr = 0x%x.",__func__,ret,_user_data_bak_start); } }while(ret == NORFLASH_API_BUFFER_FULL); do { norflash_api_flush(); }while(norflash_api_get_used_buffer_count(NORFLASH_API_MODULE_ID_USERDATA,NORFLASH_API_ALL) > 0); nv_record_config.state = NV_STATE_BAK_DONE; nvrec_trace(1,"%s: sync flush done.", __func__); } } if(nv_record_config.state == NV_STATE_BAK_DONE) { nv_record_config.state = NV_STATE_IDLE; // nvrec_trace(1,"%s: NV_STATE_IDLE", __func__); } return (ret == NORFLASH_API_OK) ? 0:1; } static int nv_record_flash_flush_int(bool is_async) { int ret = 0; do{ if((nv_record_config.state == NV_STATE_IDLE && nv_record_config.is_update == TRUE) || nv_record_config.state == NV_STATE_MAIN_ERASING || nv_record_config.state == NV_STATE_MAIN_ERASED || nv_record_config.state == NV_STATE_MAIN_WRITTING || nv_record_config.state == NV_STATE_MAIN_WRITTEN ) { ret = nv_record_flash_flush_main(is_async); if(is_async) { break; } } if(nv_record_config.state == NV_STATE_MAIN_DONE || nv_record_config.state == NV_STATE_BAK_ERASING || nv_record_config.state == NV_STATE_BAK_ERASED || nv_record_config.state == NV_STATE_BAK_WRITTING || nv_record_config.state == NV_STATE_BAK_WRITTEN || nv_record_config.state == NV_STATE_BAK_DONE ) { ret = nv_record_flash_flush_bak(is_async); } }while(0); return ret; } void nv_record_flash_flush(void) { nv_record_flash_flush_int(false); } int nv_record_flash_flush_in_sleep(void) { nv_record_flash_flush_int(true); return 0; } void nv_callback(void* param) { NORFLASH_API_OPERA_RESULT *opera_result; //uint8_t *burn_buf; opera_result = (NORFLASH_API_OPERA_RESULT*)param; nvrec_trace(6,"%s:type = %d, addr = 0x%x,len = 0x%x,remain = %d,result = %d.", __func__, opera_result->type, opera_result->addr, opera_result->len, opera_result->remain_num, opera_result->result); #ifdef nv_record_debug if (opera_result->result == NORFLASH_API_OK){ if(opera_result->remain_num == 0 && opera_result->type == NORFLASH_API_WRITTING) { uint32_t recrc; uint32_t crc; uint8_t* read_buffer = (uint8_t*)opera_result->addr; crc = ((uint32_t *)read_buffer)[pos_crc]; recrc = crc32(0, ((uint8_t *)read_buffer + sizeof(uint32_t)*pos_heap_contents), (sizeof(usrdata_ddblist_pool)-(pos_heap_contents*sizeof(uint32_t)))); ASSERT(crc == recrc,"%s:addr=0x%x,recrc=0x%x crc=0x%x.", __func__,opera_result->addr,recrc,crc); } } else{ ASSERT(0,"%s:flash write fail!addr=0x%x,result = %d.", __func__,opera_result->addr,opera_result->result); } #endif } #ifdef NVREC_BAIDU_DATA_SECTION #define BAIDU_DATA_FM_SPEC_VALUE (0xffee) int nvrec_baidu_data_init(void) { int _fmfreq = 0; if (!nvrec_config_has_section(nv_record_config.config, BAIDU_DATA_SECTIN)) { nvrec_trace(0,"no baidu section default, new one!"); nvrec_config_set_int(nv_record_config.config, BAIDU_DATA_SECTIN, BAIDU_DATA_FM_KEY, BAIDU_DATA_DEF_FM_FREQ); } else { nvrec_trace(1,"has baidu section, fmfreq is %d", nvrec_config_get_int(nv_record_config.config, BAIDU_DATA_SECTIN, BAIDU_DATA_FM_KEY, BAIDU_DATA_FM_SPEC_VALUE)); _fmfreq = nvrec_config_get_int(nv_record_config.config, BAIDU_DATA_SECTIN, BAIDU_DATA_FM_KEY, BAIDU_DATA_FM_SPEC_VALUE); if (_fmfreq == BAIDU_DATA_FM_SPEC_VALUE) { nvrec_trace(1,"fm bas bad value, set to %d", BAIDU_DATA_DEF_FM_FREQ); nvrec_config_set_int(nv_record_config.config, BAIDU_DATA_SECTIN, BAIDU_DATA_FM_KEY, BAIDU_DATA_DEF_FM_FREQ); _fmfreq = nvrec_config_get_int(nv_record_config.config, BAIDU_DATA_SECTIN, BAIDU_DATA_FM_KEY, BAIDU_DATA_FM_SPEC_VALUE); if (_fmfreq == BAIDU_DATA_FM_SPEC_VALUE) { nvrec_trace(0,"get fm freq still fail!!!"); ASSERT(0, "nvrecord fail, system down!"); } } } return 0; } int nvrec_get_fm_freq(void) { int _fmfreq = 0; _fmfreq = nvrec_config_get_int(nv_record_config.config, BAIDU_DATA_SECTIN, BAIDU_DATA_FM_KEY, BAIDU_DATA_FM_SPEC_VALUE); if (_fmfreq == BAIDU_DATA_FM_SPEC_VALUE) { nvrec_trace(1,"%s : get fm freq fail, reinit fmfreq data", __func__); nvrec_baidu_data_init(); } _fmfreq = nvrec_config_get_int(nv_record_config.config, BAIDU_DATA_SECTIN, BAIDU_DATA_FM_KEY, BAIDU_DATA_FM_SPEC_VALUE); if (_fmfreq == BAIDU_DATA_FM_SPEC_VALUE) { nvrec_trace(1,"%s : get fm freq still fail", __func__); ASSERT(0, "%s : nvrecord fail, system down!", __func__); } nvrec_trace(2,"%s:get fm freq %d", __func__, _fmfreq); return _fmfreq; } int nvrec_set_fm_freq(int fmfreq) { int t = hal_sys_timer_get(); nvrec_trace(2,"%s:fmfreq %d", __func__, fmfreq); nvrec_config_set_int(nv_record_config.config, BAIDU_DATA_SECTIN, BAIDU_DATA_FM_KEY, fmfreq); nvrec_trace(2,"%s: use %d ms", __func__, TICKS_TO_MS(hal_sys_timer_get()-t)); nv_record_config.is_update = true; #if defined(NVREC_BAIDU_DATA_FLUSH_DIRECT) nv_record_flash_flush_int(false); #endif nvrec_trace(2,"%s: use %d ms", __func__, TICKS_TO_MS(hal_sys_timer_get()-t)); return 0; } int nvrec_get_rand(char *rand) { char * _rand = 0; if (rand == NULL) return 1; #if 0 _rand = nvrec_config_get_string(nv_record_config.config, BAIDU_DATA_SECTIN, BAIDU_DATA_RAND_KEY, BAIDU_DATA_DEF_RAND); if (strcmp(_rand, BAIDU_DATA_DEF_RAND)==0 || _rand == NULL) { TRACE(1,"%s : get rand fail!", __func__); return 1; } #else _rand = BAIDU_DATA_DEF_RAND; #endif memcpy(rand, _rand, BAIDU_DATA_RAND_LEN); nvrec_trace(2,"%s:rand %s", __func__, rand); return 0; } int nvrec_set_rand(char *rand) { int t = hal_sys_timer_get(); if (rand != NULL) nvrec_trace(2,"%s:rand %s", __func__, rand); else nvrec_trace(1,"%s:rand nul", __func__); nvrec_config_set_string(nv_record_config.config, BAIDU_DATA_SECTIN, BAIDU_DATA_RAND_KEY, rand); nvrec_trace(2,"%s: use %d ms", __func__, TICKS_TO_MS(hal_sys_timer_get()-t)); nv_record_config.is_update = true; #if defined(NVREC_BAIDU_DATA_FLUSH_DIRECT) nv_record_flash_flush_int(false); #endif nvrec_trace(2,"%s: use %d ms", __func__, TICKS_TO_MS(hal_sys_timer_get()-t)); return 0; } int nvrec_clear_rand(void) { nvrec_set_rand(NULL); return 0; } int nvrec_dev_get_sn(char *sn) { unsigned int sn_addr; if (NVREC_DEV_VERSION_1 == nv_record_dev_rev) { return -1; } else { sn_addr = (unsigned int)(__factory_start + rev2_dev_prod_sn); } if(false == dev_sector_valid) return -1; if (NULL == sn) return -1; memcpy((void *)sn, (void *)sn_addr, BAIDU_DATA_SN_LEN); return 0; } #endif #endif // !defined(NEW_NV_RECORD_ENABLED) bool nvrec_dev_data_open(void) { uint32_t dev_zone_crc,dev_zone_flsh_crc; uint32_t vermagic; vermagic = __factory_start[dev_version_and_magic]; nvrec_trace(2,"%s,vermagic=0x%x",__func__,vermagic); if ((nvrec_dev_magic != (vermagic&0xFFFF)) || ((vermagic >> 16) > NVREC_DEV_NEWEST_REV)) { dev_sector_valid = false; nvrec_trace(1,"%s,dev sector invalid.",__func__); return dev_sector_valid; } // following the nv rec version number programmed by the downloader tool, // to be backward compatible nv_record_dev_rev = vermagic >> 16; nvrec_trace(1,"Nv record dev version %d", nv_record_dev_rev); if (NVREC_DEV_VERSION_1 == nv_record_dev_rev) { dev_zone_flsh_crc = __factory_start[dev_crc]; dev_zone_crc = crc32(0,(uint8_t *)(&__factory_start[dev_reserv1]),(dev_data_len-dev_reserv1)*sizeof(uint32_t)); } else { // check the data length if ((rev2_dev_section_start_reserved*sizeof(uint32_t)) + __factory_start[rev2_dev_data_len] > 4096) { nvrec_trace(1,"nv rec dev data len %d has exceeds the facory sector size!.", __factory_start[rev2_dev_data_len]); dev_sector_valid = false; return false; } // assure that in future, if the nv dev data structure is extended, the former tool // and former bin can still be workable dev_zone_flsh_crc = __factory_start[rev2_dev_crc]; dev_zone_crc = crc32(0,(uint8_t *)(&__factory_start[rev2_dev_section_start_reserved]), __factory_start[rev2_dev_data_len]); } nvrec_trace(4,"%s: data len 0x%x,dev_zone_flsh_crc=0x%x,dev_zone_crc=0x%x",__func__, __factory_start[rev2_dev_data_len],dev_zone_flsh_crc,dev_zone_crc); if (dev_zone_flsh_crc == dev_zone_crc) { dev_sector_valid = true; } if (dev_sector_valid) { nvrec_trace(1,"%s: nv rec dev is valid.", __func__); } else { nvrec_trace(1,"%s: nv rec dev is invalid.", __func__); } return dev_sector_valid; } bool nvrec_dev_localname_addr_init(dev_addr_name *dev) { uint32_t *p_devdata_cache = __factory_start; size_t name_len = 0; if(true == dev_sector_valid) { nvrec_trace(1,"%s: nv dev data valid", __func__); if (NVREC_DEV_VERSION_1 == nv_record_dev_rev) { memcpy((void *) dev->btd_addr,(void *)&p_devdata_cache[dev_bt_addr],BTIF_BD_ADDR_SIZE); memcpy((void *) dev->ble_addr,(void *)&p_devdata_cache[dev_ble_addr],BTIF_BD_ADDR_SIZE); dev->localname = (char *)&p_devdata_cache[dev_name]; } else { memcpy((void *) dev->btd_addr,(void *)&p_devdata_cache[rev2_dev_bt_addr],BTIF_BD_ADDR_SIZE); memcpy((void *) dev->ble_addr,(void *)&p_devdata_cache[rev2_dev_ble_addr],BTIF_BD_ADDR_SIZE); dev->localname = (char *)&p_devdata_cache[rev2_dev_name]; dev->ble_name = (char *)&p_devdata_cache[rev2_dev_ble_name]; } if (strlen(dev->localname) < CLASSIC_BTNAME_LEN) { name_len = strlen(dev->localname); } else { name_len = CLASSIC_BTNAME_LEN - 1; } memcpy(classics_bt_name,dev->localname,name_len); classics_bt_name[name_len] = '\0'; bt_set_local_name(classics_bt_name); bt_set_local_address(dev->btd_addr); } else { nvrec_trace(1,"%s: nv dev data invalid", __func__); } nvrec_trace(0,"BT addr is:"); DUMP8("%02x ", dev->btd_addr, BTIF_BD_ADDR_SIZE); nvrec_trace(0,"BLE addr is:"); DUMP8("%02x ", dev->ble_addr, BTIF_BD_ADDR_SIZE); nvrec_trace(2,"localname=%s, namelen=%d", dev->localname, strlen(dev->localname)); if (dev->ble_name) nvrec_trace(2,"blename=%s, namelen=%d", dev->ble_name, strlen(dev->ble_name)); return dev_sector_valid; } int nvrec_dev_force_get_btaddress(unsigned char *btd_addr) { uint32_t *p_devdata_cache = __factory_start; memcpy((void *) btd_addr,(void *)&p_devdata_cache[dev_bt_addr],BTIF_BD_ADDR_SIZE); return 0; } static void nvrec_dev_data_fill_xtal_fcap(uint32_t *mem_pool,uint32_t val) { uint8_t *btaddr = NULL; uint8_t *bleaddr = NULL; assert(0 != mem_pool); if (!dev_sector_valid) { mem_pool[dev_version_and_magic] = ((nv_record_dev_rev<<16)|nvrec_dev_magic); } if (NVREC_DEV_VERSION_1 == nv_record_dev_rev) { if(dev_sector_valid) { memcpy((void *)mem_pool,(void *)__factory_start,0x1000); mem_pool[dev_xtal_fcap] = val; mem_pool[dev_crc] = crc32(0,(uint8_t *)(&mem_pool[dev_reserv1]),(dev_data_len-dev_reserv1)*sizeof(uint32_t)); } else { const char *localname = bt_get_local_name(); unsigned int namelen = strlen(localname); btaddr = bt_get_local_address(); bleaddr = bt_get_ble_local_address(); mem_pool[dev_reserv1] = 0; mem_pool[dev_reserv2] = 0; memcpy((void *)&mem_pool[dev_name],(void *)localname,(size_t)namelen); nvrec_dev_rand_btaddr_gen(btaddr); nvrec_dev_rand_btaddr_gen(bleaddr); memcpy((void *)&mem_pool[dev_bt_addr],(void *)btaddr,BTIF_BD_ADDR_SIZE); memcpy((void *)&mem_pool[dev_ble_addr],(void *)bleaddr,BTIF_BD_ADDR_SIZE); memset((void *)&mem_pool[dev_dongle_addr],0x0,BTIF_BD_ADDR_SIZE); mem_pool[dev_xtal_fcap] = val; mem_pool[dev_crc] = crc32(0,(uint8_t *)(&mem_pool[dev_reserv1]),(dev_data_len-dev_reserv1)*sizeof(uint32_t)); nvrec_trace(2,"%s: mem_pool[dev_crc]=%x.\n",__func__,mem_pool[dev_crc]); } } else { if(dev_sector_valid) { memcpy((void *)mem_pool,(void *)__factory_start,0x1000); mem_pool[rev2_dev_xtal_fcap] = val; mem_pool[rev2_dev_crc] = crc32(0, (uint8_t *)(&mem_pool[rev2_dev_section_start_reserved]),mem_pool[rev2_dev_data_len]); } else { const char *localname = bt_get_local_name(); unsigned int namelen = strlen(localname); btaddr = bt_get_local_address(); bleaddr = bt_get_ble_local_address(); mem_pool[rev2_dev_section_start_reserved] = 0; mem_pool[rev2_dev_reserv2] = 0; memcpy((void *)&mem_pool[rev2_dev_name],(void *)localname,(size_t)namelen); memcpy((void *)&mem_pool[rev2_dev_ble_name], (void *)bt_get_ble_local_name(), BLE_NAME_LEN_IN_NV); nvrec_dev_rand_btaddr_gen(btaddr); nvrec_dev_rand_btaddr_gen(bleaddr); memcpy((void *)&mem_pool[rev2_dev_bt_addr],(void *)btaddr,BTIF_BD_ADDR_SIZE); memcpy((void *)&mem_pool[rev2_dev_ble_addr],(void *)bleaddr,BTIF_BD_ADDR_SIZE); memset((void *)&mem_pool[rev2_dev_dongle_addr],0x0,BTIF_BD_ADDR_SIZE); mem_pool[rev2_dev_xtal_fcap] = val; mem_pool[rev2_dev_data_len] = (rev2_dev_section_end-rev2_dev_section_start_reserved)*sizeof(uint32_t); mem_pool[rev2_dev_crc] = crc32(0, (uint8_t *)(&mem_pool[rev2_dev_section_start_reserved]), mem_pool[rev2_dev_data_len]); nvrec_trace(2,"%s: mem_pool[rev2_dev_crc] = 0x%x.\n", __func__,mem_pool[rev2_dev_crc]); } } } void nvrec_dev_flash_flush(unsigned char *mempool) { uint32_t lock; #ifdef nv_record_debug uint32_t devdata[dev_data_len] = {0,}; uint32_t recrc; #endif if(NULL == mempool) return; lock = int_lock_global(); pmu_flash_write_config(); hal_norflash_erase(HAL_NORFLASH_ID_0,(uint32_t)NVRECORD_CACHE_2_UNCACHE(__factory_start),0x1000); hal_norflash_write(HAL_NORFLASH_ID_0,(uint32_t)NVRECORD_CACHE_2_UNCACHE(__factory_start),(uint8_t *)mempool,0x1000);//dev_data_len*sizeof(uint32_t)); pmu_flash_read_config(); int_unlock_global(lock); #ifdef nv_record_debug if (NVREC_DEV_VERSION_1 == nv_record_dev_rev) { memset(devdata,0x0,dev_data_len*sizeof(uint32_t)); memcpy(devdata,__factory_start,dev_data_len*sizeof(uint32_t)); recrc = crc32(0,(uint8_t *)(&devdata[dev_reserv1]),(dev_data_len-dev_reserv1)*sizeof(uint32_t)); nvrec_trace(3,"%s: devdata[dev_crc]=%x.recrc=%x\n", __func__,devdata[dev_crc],recrc); if(devdata[dev_crc] != recrc) assert(0); } #endif } void nvrec_dev_rand_btaddr_gen(uint8_t* bdaddr) { unsigned int seed; int i; OS_DUMP8("%x ",bdaddr,6); seed = hal_sys_timer_get(); for(i=0;i