/*************************************************************************** * * 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 "nvrecord.h" #include "besbt.h" #include "crc32.h" #include "hal_norflash.h" #include "hal_sleep.h" #include "hal_timer.h" #include "norflash_api.h" #include "nvrecord_dev.h" #include "nvrecord_env.h" #include "pmu.h" #include "tgt_hardware.h" #include //#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_i < entries_len; tmp_i++) { btif_device_record_t record; bt_status_t ret_status; ret_status = nv_record_enum_dev_records(tmp_i, &record); if (BT_STS_SUCCESS == ret_status) nv_record_print_dev_record(&record); } } int nv_record_get_paired_dev_count(void) { nvrec_section_t *sec = NULL; list_t *entry = NULL; sec = nvrec_section_find(nv_record_config.config, section_name_ddbrec); if (NULL == sec) return 0; entry = sec->entries; 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 < BTIF_BD_ADDR_SIZE; i++) { unsigned int randval; srand(seed); randval = rand(); bdaddr[i] = (randval & 0xff); seed += rand(); } OS_DUMP8("%x ", bdaddr, 6); } void nvrec_dev_set_xtal_fcap(unsigned int xtal_fcap) { uint8_t *mempool = NULL; uint32_t lock; #ifdef nv_record_debug uint32_t devdata[dev_data_len] = { 0, }; uint32_t recrc; #endif syspool_init(); syspool_get_buff(&mempool, 0x1000); nvrec_dev_data_fill_xtal_fcap((uint32_t *)mempool, (uint32_t)xtal_fcap); lock = int_lock_global(); norflash_api_flush_all(); // Ensure that the flash is in an operational state 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)); nvrec_trace(2, "%s: xtal fcap = %d", __func__, devdata[dev_xtal_fcap]); recrc = crc32(0, (uint8_t *)(&devdata[dev_reserv1]), (dev_data_len - dev_reserv1) * sizeof(uint32_t)); nvrec_trace(2, "devdata[dev_crc]=%x.recrc=%x\n", devdata[dev_crc], recrc); if (devdata[dev_crc] != recrc) assert(0); } #endif } int nvrec_dev_get_xtal_fcap(unsigned int *xtal_fcap) { unsigned int xtal_fcap_addr; if (NVREC_DEV_VERSION_1 == nv_record_dev_rev) { xtal_fcap_addr = (unsigned int)(__factory_start + dev_xtal_fcap); } else { xtal_fcap_addr = (unsigned int)(__factory_start + rev2_dev_xtal_fcap); } unsigned int tmpval[1] = { 0, }; if (false == dev_sector_valid) return -1; if (NULL == xtal_fcap) return -1; memcpy((void *)tmpval, (void *)xtal_fcap_addr, sizeof(unsigned int)); *xtal_fcap = tmpval[0]; return 0; } int nvrec_dev_get_dongleaddr(bt_bdaddr_t *dongleaddr) { unsigned int dongle_addr_pos; if (NVREC_DEV_VERSION_1 == nv_record_dev_rev) { dongle_addr_pos = (unsigned int)(__factory_start + dev_dongle_addr); } else { dongle_addr_pos = (unsigned int)(__factory_start + rev2_dev_dongle_addr); } if (false == dev_sector_valid) return -1; if (NULL == dongleaddr) return -1; memcpy((void *)dongleaddr, (void *)dongle_addr_pos, BTIF_BD_ADDR_SIZE); return 0; } int nvrec_dev_get_btaddr(char *btaddr) { unsigned int bt_addr_pos; if (NVREC_DEV_VERSION_1 == nv_record_dev_rev) { bt_addr_pos = (unsigned int)(__factory_start + dev_bt_addr); } else { bt_addr_pos = (unsigned int)(__factory_start + rev2_dev_bt_addr); } if (false == dev_sector_valid) return 0; if (NULL == btaddr) return 0; memcpy((void *)btaddr, (void *)bt_addr_pos, BTIF_BD_ADDR_SIZE); return 1; } char *nvrec_dev_get_bt_name(void) { return classics_bt_name; } const char *nvrec_dev_get_ble_name(void) { if ((NVREC_DEV_VERSION_1 == nv_record_dev_rev) || (!dev_sector_valid)) { return BLE_DEFAULT_NAME; } else { return (const char *)(&__factory_start[rev2_dev_ble_name]); } }