经典蓝牙和TWS产测常见功能
📎 原始文档:https://www.kdocs.cn/l/csQkHIpOSLZd 经典蓝牙和TWS产测常见功能
产测的其他文档产测相关应用.otl
- 进入蓝牙模式
//一般在idle模式下用
//普通SDK
void enter_bt_mode(void)
{
struct application *app = get_current_app();
if (app) {
if (strcmp(app->name, APP_NAME_BT)) {
if (!app_var.goto_poweroff_flag) {
app_var.play_poweron_tone = 0;
task_switch_to_bt();
}
}
}
}
//可视化SDK
void enter_bt_mode(void)
{
if (!app_in_mode(APP_MODE_BT)) {
if(!app_var.goto_poweroff_flag) {
app_var.play_poweron_tone = 0;
app_send_message(APP_MSG_GOTO_MODE, APP_MODE_BT);
}
}
}
- 进入dut模式 基础接口
extern void bredr_set_dut_enble(u8 en, u8 phone);
进dut常用操作:耳机先取消回连流程(包括回连TWS和回连手机),取消蓝牙BLE广播,再进入dut模式,进入dut后不能再发起任何回连。
普通SDK
可视化SDK
//普通SDK
void bt_bredr_enter_dut_mode(u8 mode, u8 inquiry_scan_en)
{
u8 local_addr[6];
puts("<<<<<<<<<<<<<bt_bredr_enter_dut_mode>>>>>>>>>>>>>>\n");
clk_set("sys", SYS_48M);
u8 chargestore_set_ex_enter_dut_flag(u8 en);
chargestore_set_ex_enter_dut_flag(1);//把测试盒进dut标志位置1,避免走回连
extern void bt_ble_adv_enable(u8 enable);
bt_ble_adv_enable(0);//关BLE广播,如果有其他地方还会打开,那些地方要加标志位屏蔽掉,总之就是不能开ble广播
bredr_set_dut_enble(1, 1);
if (mode) {
bt_user_priv_var.auto_connection_counter = 0;
//下面是断开tws和手机,取消回连,开可发现可连接
#if TCFG_USER_TWS_ENABLE
tws_cancel_state();
user_send_cmd_prepare(USER_CTRL_PAGE_CANCEL, 0, NULL);
user_send_cmd_prepare(USER_CTRL_POWER_OFF, 0, NULL);
if (0 == get_total_connect_dev()) {
log_info("<<<<<no phone connect,instant page_scan,inquiry_scan:%x>>>>>\n", inquiry_scan_en);
bt_get_vm_mac_addr(local_addr);
//log_info("local_adr\n");
//put_buf(local_addr,6);
lmp_hci_write_local_address(local_addr);
if (inquiry_scan_en) {
user_send_cmd_prepare(USER_CTRL_WRITE_SCAN_ENABLE, 0, NULL);
}
user_send_cmd_prepare(USER_CTRL_WRITE_CONN_ENABLE, 0, NULL);
}
#else
if (bt_user_priv_var.auto_connection_timer) {
sys_timeout_del(bt_user_priv_var.auto_connection_timer);
bt_user_priv_var.auto_connection_timer = 0;
}
user_send_cmd_prepare(USER_CTRL_PAGE_CANCEL, 0, NULL);
user_send_cmd_prepare(USER_CTRL_POWER_OFF, 0, NULL);
if (inquiry_scan_en) {
user_send_cmd_prepare(USER_CTRL_WRITE_SCAN_ENABLE, 0, NULL);
}
user_send_cmd_prepare(USER_CTRL_WRITE_CONN_ENABLE, 0, NULL);
#endif
link_task_idle_disable();
}
}
//可视化SDK
void bt_bredr_enter_dut_mode(u8 mode, u8 inquiry_scan_en)
{
puts("<<<<<<<<<<<<<bt_bredr_enter_dut_mode>>>>>>>>>>>>>>\n");
clock_alloc("DUT", SYS_48M);
u8 testbox_set_ex_enter_dut_flag(u8 en);
testbox_set_ex_enter_dut_flag(1);//把测试盒进dut标志位置1,避免走回连
extern void bt_ble_adv_enable(u8 enable);
bt_ble_adv_enable(0);//关BLE广播,如果有其他地方还会打开,那些地方要加标志位屏蔽掉,总之就是不能开ble广播
bredr_set_dut_enble(1, 1);
if (mode) {
clr_device_in_page_list();
dut_idle_run_slot(2);
g_bt_hdl.auto_connection_counter = 0;
#if TCFG_USER_TWS_ENABLE
tws_dual_conn_close();
bt_page_scan_for_test(inquiry_scan_en);
#else
dual_conn_close();
bt_cmd_prepare(USER_CTRL_POWER_OFF, 0, NULL);
u8 local_addr[6];
if (0 == bt_get_total_connect_dev()) {
bt_get_vm_mac_addr(local_addr);
lmp_hci_write_local_address(local_addr);
if (inquiry_scan_en) {
bt_cmd_prepare(USER_CTRL_WRITE_SCAN_ENABLE, 0, NULL);
}
bt_cmd_prepare(USER_CTRL_WRITE_CONN_ENABLE, 0, NULL);
}
#endif
}
}
//调用
bt_bredr_enter_dut_mode(1, 1);
- 进入定频测试
void bt_fix_fre_api(u8 fre);//fre: 0 ~ 78,对应2402——2480
如果开了BLE,需要先关闭BLE广播
普通SDK:
bt_ble_exit();
bt_fix_fre_api(39);//2441
可视化SDK:
void bt_fix_fre_api(u8 fre);
void tws_dual_conn_close();
tws_dual_conn_close();//非tws用dual_conn_close();
bt_ble_adv_enable(0);
bt_ble_exit();
multi_protocol_bt_exit();
bt_fix_fre_api(39);//2441
- 进入配对模式 最终实现就是取消所有回连流程,断开手机,开可发现可连接
//普通SDK
void bt_enter_pairing(void)
{
bt_user_priv_var.auto_connection_counter = 0;
#if TCFG_USER_TWS_ENABLE
gtws.state &= ~BT_TWS_POWER_ON;
if(tws_api_get_tws_state() & TWS_STA_PHONE_CONNECTED){
if(tws_api_get_role() == TWS_ROLE_MASTER){
printf("------------------------------------------------------------\n");
user_send_cmd_prepare(USER_CTRL_ALL_SNIFF_EXIT, 0, NULL);
user_send_cmd_prepare(USER_CTRL_POWER_OFF, 0, NULL);
}
}
else{
if(get_curr_channel_state() || hci_standard_connect_check()){
if(tws_api_get_role() == TWS_ROLE_MASTER){
printf("tttttttttttttttttttttttttttttttttttttttttttttttttttttttt\n");
user_send_cmd_prepare(USER_CTRL_ALL_SNIFF_EXIT, 0, NULL);
user_send_cmd_prepare(USER_CTRL_PAGE_CANCEL, 0, NULL);
user_send_cmd_prepare(USER_CTRL_POWER_OFF, 0, NULL);
}
}
void bt_tws_connect_and_connectable_switch();
bt_tws_connect_and_connectable_switch();
}
#else
if (bt_user_priv_var.auto_connection_timer) {
sys_timeout_del(bt_user_priv_var.auto_connection_timer);
bt_user_priv_var.auto_connection_timer = 0;
}
user_send_cmd_prepare(USER_CTRL_PAGE_CANCEL, 0, NULL);
if(get_total_connect_dev() || hci_standard_connect_check()){
user_send_cmd_prepare(USER_CTRL_POWER_OFF, 0, NULL);
}
else{
user_send_cmd_prepare(USER_CTRL_WRITE_SCAN_ENABLE, 0, NULL);
user_send_cmd_prepare(USER_CTRL_WRITE_CONN_ENABLE, 0, NULL);
}
#endif
}
//可视化SDK
void bt_enter_pairing(void)
{
clr_device_in_page_list();
g_bt_hdl.auto_connection_counter = 0;
#if TCFG_USER_TWS_ENABLE
if(tws_api_get_tws_state() & TWS_STA_PHONE_CONNECTED){
if(tws_api_get_role() == TWS_ROLE_MASTER){
printf("------------------------------------------------------------\n");
bt_cmd_prepare(USER_CTRL_ALL_SNIFF_EXIT, 0, NULL);
bt_cmd_prepare(USER_CTRL_POWER_OFF, 0, NULL);
}
}
else{
if(bt_get_curr_channel_state() || bt_get_total_connect_dev()){
if(tws_api_get_role() == TWS_ROLE_MASTER){
printf("tttttttttttttttttttttttttttttttttttttttttttttttttttttttt\n");
bt_cmd_prepare(USER_CTRL_ALL_SNIFF_EXIT, 0, NULL);
bt_cmd_prepare(USER_CTRL_PAGE_CANCEL, 0, NULL);
bt_cmd_prepare(USER_CTRL_POWER_OFF, 0, NULL);
}
}
bt_cmd_prepare(USER_CTRL_WRITE_SCAN_ENABLE, 0, NULL);
bt_cmd_prepare(USER_CTRL_WRITE_CONN_ENABLE, 0, NULL);
}
#else
bt_cmd_prepare(USER_CTRL_PAGE_CANCEL, 0, NULL);
if(bt_get_curr_channel_state() || bt_get_total_connect_dev()){
bt_cmd_prepare(USER_CTRL_POWER_OFF, 0, NULL);
}
else{
bt_cmd_prepare(USER_CTRL_WRITE_SCAN_ENABLE, 0, NULL);
bt_cmd_prepare(USER_CTRL_WRITE_CONN_ENABLE, 0, NULL);
}
#endif
}
- tws进入单耳配对模式 最终实现断开tws和手机,取消回连,开可发现可连接
//普通SDK
void tws_enter_single_pairing(void)
{
bt_user_priv_var.auto_connection_counter = 0;
u8 chargestore_set_ex_enter_dut_flag(u8 en);
chargestore_set_ex_enter_dut_flag(1);//把测试盒进dut标志位置1,避免走回连
//下面是断开tws和手机,取消回连,开可发现可连接
tws_cancel_state();
user_send_cmd_prepare(USER_CTRL_PAGE_CANCEL, 0, NULL);
user_send_cmd_prepare(USER_CTRL_POWER_OFF, 0, NULL);
if (0 == get_total_connect_dev()) {
bt_get_vm_mac_addr(local_addr);
//log_info("local_adr\n");
//put_buf(local_addr,6);
lmp_hci_write_local_address(local_addr);
user_send_cmd_prepare(USER_CTRL_WRITE_SCAN_ENABLE, 0, NULL);
user_send_cmd_prepare(USER_CTRL_WRITE_CONN_ENABLE, 0, NULL);
}
}
//可视化SDK
void tws_enter_single_pairing(void)
{
clr_device_in_page_list();
g_bt_hdl.auto_connection_counter = 0;
u8 testbox_set_ex_enter_dut_flag(u8 en);
testbox_set_ex_enter_dut_flag(1);//把测试盒进dut标志位置1,避免走回连
//下面是断开tws和手机,取消回连,开可发现可连接
tws_dual_conn_close();
bt_cmd_prepare(USER_CTRL_PAGE_CANCEL, 0, NULL);
tws_api_detach(TWS_DETACH_BY_POWEROFF, 5000);
bt_cmd_prepare(USER_CTRL_POWER_OFF, 0, NULL);
if (0 == get_total_connect_dev()) {
bt_get_vm_mac_addr(local_addr);
//log_info("local_adr\n");
//put_buf(local_addr,6);
lmp_hci_write_local_address(local_addr);
bt_cmd_prepare(USER_CTRL_WRITE_SCAN_ENABLE, 0, NULL);
bt_cmd_prepare(USER_CTRL_WRITE_CONN_ENABLE, 0, NULL);
}
}
- 清除手机配对记录 此操作需要在蓝牙模式下进行,清除设备记录之前先要进入配对模式
//先进蓝牙模式
enter_bt_mode();
//然后进配对模式
bt_enter_pairing();
//然后清除记录
user_send_cmd_prepare(USER_CTRL_DEL_ALL_REMOTE_INFO, 0, NULL);//可视化用bt_cmd_prepare
//如果原来在idle,通过enter_bt_mode()切到蓝牙模式,可以在BT_STATUS_INIT_OK处添加处理
//普通SDK
static int bt_connction_status_event_handler(struct bt_event *bt)
{
STATUS *p_tone = get_tone_config();
u8 *phone_number = NULL;
#if CONFIG_BT_BACKGROUND_ENABLE
int ret = bt_background_event_probe_handler(bt);
if (ret == -EINVAL) {
return 0;
}
#endif
//log_info("bt_conn_event:%d", bt->event);
switch (bt->event) {
case BT_STATUS_INIT_OK:
//......前面维持公版,省略
if(clean_all_info){//enter_bt_mode()时添加标志位处理
clean_all_info = 0;
user_send_cmd_prepare(USER_CTRL_DEL_ALL_REMOTE_INFO, 0, NULL);
clear_current_poweron_memory_search_index(1);
}
else{
bt_init_ok_search_index();//不是清除配对才执行
}
//......后面维持公版,省略
}
//可视化SDK
static int bt_connction_status_event_handler(struct bt_event *bt)
{
switch (bt->event) {
case BT_STATUS_INIT_OK:
//......前面维持公版,省略
if(clean_all_info){//enter_bt_mode()时添加标志位处理
clean_all_info = 0;
bt_cmd_prepare(USER_CTRL_DEL_ALL_REMOTE_INFO, 0, NULL);
clear_current_poweron_memory_search_index(0);
}
else{
bt_init_ok_search_index();//不是清除配对才执行
}
//......后面维持公版,省略
}
static int dual_conn_btstack_event_handler(int *_event)
{
struct bt_event *event = (struct bt_event *)_event;
int state = tws_api_get_tws_state();
printf("dual_conn_btstack_event_handler:%d\n", event->event);
switch (event->event) {
case BT_STATUS_INIT_OK:
if(clean_all_info == 0){
dual_conn_page_devices_init();
}
return 0;
//......后面维持公版,省略
}
- 清除TWS连接记录
//对耳连接状态下使用
tws_api_remove_pairs();
//普通SDK
//蓝牙模式其他状态下使用
/*
* 解除配对,清掉对方地址信息和本地声道信息
*/
void bt_tws_remove_pairs()
{
puts("<<<<<<<<<<<<<<<<<<bt_tws_remove_pairs err>>>>>>>>>>>>>>>>>>\n");
/*正常情况下不必要清除tws相关配对信息,防止用户误操作。只删除手机配对信息即可*/
/* u8 del_phone_remote_info=1; */
/* user_send_cmd_prepare(USER_CTRL_DEL_ALL_REMOTE_INFO, 0, &del_phone_remote_info); */
#if 1
u8 mac_addr[6];
char channel = 'U';
char tws_channel = 0;
gtws.state &= ~BT_TWS_REMOVE_PAIRS;
memset(mac_addr, 0xFF, 6);
syscfg_write(CFG_TWS_COMMON_ADDR, mac_addr, 6);
syscfg_write(CFG_TWS_REMOTE_ADDR, mac_addr, 6);
syscfg_read(CFG_BT_MAC_ADDR, mac_addr, 6);
lmp_hci_write_local_address(mac_addr);
#if (CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_LEFT_START_PAIR) ||\
(CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_RIGHT_START_PAIR) ||\
(CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_MASTER_AS_LEFT)
#if CONFIG_TWS_SECECT_CHARGESTORE_PRIO
syscfg_read(CFG_CHARGESTORE_TWS_CHANNEL, &tws_channel, 1);
#endif
if ((tws_channel != 'L') && (tws_channel != 'R')) {
syscfg_write(CFG_TWS_CHANNEL, &channel, 1);
tws_api_set_local_channel(channel);
}
#endif
tws_api_clear_connect_aa();
bt_tws_wait_pair_and_phone_connect();
#endif
}
//非蓝牙模式下使用
void idle_tws_remove_pairs()
{
puts("<<<<<<<<<<<<<<<<<<idle_tws_remove_pairs err>>>>>>>>>>>>>>>>>>\n");
/*正常情况下不必要清除tws相关配对信息,防止用户误操作。只删除手机配对信息即可*/
/* u8 del_phone_remote_info=1; */
/* user_send_cmd_prepare(USER_CTRL_DEL_ALL_REMOTE_INFO, 0, &del_phone_remote_info); */
#if 1
u8 mac_addr[6];
char channel = 'U';
char tws_channel = 0;
memset(mac_addr, 0xFF, 6);
syscfg_write(CFG_TWS_COMMON_ADDR, mac_addr, 6);
syscfg_write(CFG_TWS_REMOTE_ADDR, mac_addr, 6);
#if (CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_LEFT_START_PAIR) ||\
(CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_RIGHT_START_PAIR) ||\
(CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_MASTER_AS_LEFT)
#if CONFIG_TWS_SECECT_CHARGESTORE_PRIO
syscfg_read(CFG_CHARGESTORE_TWS_CHANNEL, &tws_channel, 1);
#endif
if ((tws_channel != 'L') && (tws_channel != 'R')) {
syscfg_write(CFG_TWS_CHANNEL, &channel, 1);
}
#endif
#endif
}
//可视化SDK
//蓝牙模式其他状态下使用
void bt_tws_remove_pairs()
{
u8 mac_addr[6];
gtws.state &= ~BT_TWS_REMOVE_PAIRS;
gtws.state &= ~BT_TWS_PAIRED;
gtws.state |= BT_TWS_UNPAIRED;
memset(mac_addr, 0xFF, 6);
syscfg_write(CFG_TWS_COMMON_ADDR, mac_addr, 6);
syscfg_write(CFG_TWS_REMOTE_ADDR, mac_addr, 6);
syscfg_read(CFG_BT_MAC_ADDR, mac_addr, 6);
lmp_hci_write_local_address(mac_addr);
#if (CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_START_PAIR_AS_LEFT) ||\
(CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_START_PAIR_AS_RIGHT) ||\
(CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_MASTER_AS_LEFT) || \
(CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_MASTER_AS_RIGHT) && \
CONFIG_TWS_SECECT_CHARGESTORE_PRIO
char channel = 'U';
char tws_channel = 0;
syscfg_read(CFG_CHARGESTORE_TWS_CHANNEL, &tws_channel, 1);
if ((tws_channel != 'L') && (tws_channel != 'R')) {
syscfg_write(CFG_TWS_CHANNEL, &channel, 1);
tws_api_set_local_channel(channel);
}
#endif
}
//非蓝牙模式下使用
void idle_tws_remove_pairs()
{
u8 mac_addr[6];
memset(mac_addr, 0xFF, 6);
syscfg_write(CFG_TWS_COMMON_ADDR, mac_addr, 6);
syscfg_write(CFG_TWS_REMOTE_ADDR, mac_addr, 6);
#if (CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_START_PAIR_AS_LEFT) ||\
(CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_START_PAIR_AS_RIGHT) ||\
(CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_MASTER_AS_LEFT) || \
(CONFIG_TWS_CHANNEL_SELECT == CONFIG_TWS_MASTER_AS_RIGHT) && \
CONFIG_TWS_SECECT_CHARGESTORE_PRIO
char channel = 'U';
char tws_channel = 0;
syscfg_read(CFG_CHARGESTORE_TWS_CHANNEL, &tws_channel, 1);
if ((tws_channel != 'L') && (tws_channel != 'R')) {
syscfg_write(CFG_TWS_CHANNEL, &channel, 1);
}
#endif
}
- tws组队 拿到左右耳的local地址,然后想办法互相交换,写到remote vm
//获取左右耳的local地址
syscfg_read(CFG_TWS_LOCAL_ADDR, local_addr, 6);
//通过串口或者spp等方式左右互换local地址,比如左边local给右边,右边local给左边
//给过来就得到remote,然后写VM
//比如左边local发给右边,这个local就变成了右边的remote
syscfg_write(CFG_TWS_REMOTE_ADDR, mac_remote, 6);
//设置耳机声道
syscfg_write(CFG_TWS_CHANNEL, &channel, 1);
- 烧写mac地址 注意:此烧写方式跟一拖八或者一拖二烧录mac地址是一样的,mac写在flash最后4K,每次写mac地址都会把最后4K擦除,所以要注意在写mac地址之前备份最后4K里面的其他数据(如果有的话,比如认证码三元组之类的)
#define MAC_PAGE_OFFSET 64
typedef enum _FLASH_ERASER {
CHIP_ERASER = 0,
BLOCK_ERASER,
SECTOR_ERASER,
PAGE_ERASER,
} FLASH_ERASER;
extern bool sfc_erase(int cmd, u32 addr);
extern u32 sfc_write(const u8 *buf, u32 addr, u32 len);
/**
* @brief 将蓝牙地址写入保留区最后256字节
*
* @param mac 蓝牙地址
* @param len
* @return int
*/
int set_mac_addr_to_flash(const u8 *mac, u16 len)
{
#if (CONFIG_DEVELOPER_MODE)
return 256;//开发板不支持烧写
#endif
u8 buffer[256];
u32 flash_capacity = sdfile_get_disk_capacity();
u32 sector = flash_capacity - 4 * 1024;
u32 page_addr = flash_capacity - 256;
u8 *auif_ptr = (u8 *)sdfile_flash_addr2cpu_addr(page_addr);
u8 write_mac[6];
u16 crc;
u32 wlen;
///save last 256 byte
/* memset(buffer, 0xff, sizeof(buffer)); */
memcpy(buffer, auif_ptr, sizeof(buffer));
// auif_ptr += MAC_PAGE_OFFSET;
void swapX(const uint8_t *src, uint8_t *dst, int len);
swapX(mac, write_mac, 6);
memcpy(&buffer[MAC_PAGE_OFFSET], write_mac, sizeof(write_mac));
crc = CRC16(&buffer[MAC_PAGE_OFFSET], sizeof(write_mac));
printf("crc:0x%x", crc);
buffer[MAC_PAGE_OFFSET+sizeof(write_mac)] = crc>>8;
buffer[MAC_PAGE_OFFSET+sizeof(write_mac)+1] = crc & 0xff;
put_buf(&buffer[MAC_PAGE_OFFSET], 8);
if(!memcmp(buffer, auif_ptr, sizeof(buffer))) {
printf("same , return");
return 256;
}
printf("erase license sector \n");
sfc_erase(SECTOR_ERASER, sector);
printf("write license to flash \n");
wlen = sfc_write(buffer, page_addr, 256);
printf("wlen:%d \n", wlen);
return wlen;
// return 0;
}
//读取烧录的MAC地址
u8 mac_addr[6];
syscfg_read(CFG_BT_MAC_ADDR, mac_addr, 6);
- 获取tws配对记录
u8 local_addr[6];
u8 remote_addr[6];
u8 common_addr[6];
u8 channel = 0;
bt_get_tws_local_addr(local_addr);
syscfg_read(CFG_TWS_REMOTE_ADDR, remote_addr, 6);
syscfg_read(CFG_TWS_COMMON_ADDR, common_addr, 6);
syscfg_read(CFG_TWS_CHANNEL, &channel, 1);
- 获取耳机检测的电池电压和百分比
u16 get_vbat_value(void);//电压:注意返回值是u16
u8 get_vbat_percent(void);//百分比,返回80表示80%
- 获取蓝牙名
const char *bt_get_local_name();
- 获取SDK版本信息
const char *sdk_version_info_get(void);
- 获取烧录校验码
extern u8 *sdfile_get_burn_code(u8 *len);//len为返回值指向内存的长度
- 获取是否与当前手机配对过
extern int get_link_key(u8 *bd_addr, u8 *link_key, u8 id);
bool get_linkkey_exist_state(const uint8_t *bt_address)
{
u8 link_key[16] = {0};
printf("%s\n", __func__);
put_buf((u8 *)bt_address, 6);
if (get_link_key((u8 *)bt_address, (u8 *)&link_key[0], 0)) {
printf("have link key\n");
return true;
} else {
printf("no link key\n");
return false;
}
}
- 写入自定义数据 用于例如固定BLE地址、或者做SN数据等
此方式受“擦除VM和BT配置区“的影响。想要不受影响请使用模拟烧录器写认证码
1、先定义一个VM索引(注意不要和SDK已有的冲突,SDK已有索引见syscfg_id.h和user_cfg_id.h)
2、将该索引放到蓝牙配置区(蓝牙配置区只允许写一次,要重复写的话请忽略本步骤,但重复写时会受到VM地址的影响,需要固定VM地址,固定VM地址的方式见关于VM、蓝牙配置区和4K预留区.otl)
3、代码上使用syscfg_write写入,使用syscfg_read读取
禁止在中断中写入数据,判断是否在中断中见CPU&OS相关应用.otl
syscfg_write(CFG_FACTORY_INFO, factory_info, 6);
syscfg_read(CFG_FACTORY_INFO, factory_info, 6);
- 模拟烧录器写认证码 注意:如果需要烧写mac地址,则此步骤必须放在烧写mac地址之后,保险起见,生产前要模拟产线流程,看看写完认证码之后耳机的MAC地址有没有问题。
此方式是将数据写入flash最后4K的倒数256字节偏移80字节处,认证码最长支持
256-80-4=172字节
此方式不受”擦除VM和BT配置区”的影响。
烧录器烧认证码参考:蓝牙音频APP相关应用.otl
#define LIC_PAGE_OFFSET 80
typedef enum _FLASH_ERASER {
CHIP_ERASER = 0,
BLOCK_ERASER,
SECTOR_ERASER,
PAGE_ERASER,
} FLASH_ERASER;
typedef struct __flash_of_lic_para_head {
s16 crc;
u16 string_len;
const u8 para_string[];
} __attribute__((packed)) _flash_of_lic_para_head;
extern bool sfc_erase(int cmd, u32 addr);
extern u32 sfc_write(const u8 *buf, u32 addr, u32 len);
//将认证码信息保存到flash里面
int license2flash(const u8 *data, u16 len)
{
_flash_of_lic_para_head header;
u8 buffer[256];
u32 flash_capacity = sdfile_get_disk_capacity();
u32 sector = flash_capacity - 4 * 1024;
u32 page_addr = flash_capacity - 256;
u8 *auif_ptr = (u8 *)sdfile_flash_addr2cpu_addr(page_addr);
///save last 256 byte
/* memset(buffer, 0xff, sizeof(buffer)); */
memcpy(buffer, auif_ptr, sizeof(buffer));
auif_ptr += LIC_PAGE_OFFSET;
header.string_len = len;
///length
memcpy(&buffer[LIC_PAGE_OFFSET + sizeof(header.crc)], &(header.string_len), sizeof(header.string_len));
///context
memcpy(&buffer[LIC_PAGE_OFFSET + sizeof(header)], data, len);
///crc
header.crc = CRC16(&buffer[LIC_PAGE_OFFSET + sizeof(header.crc)], sizeof(header.string_len) + header.string_len);
memcpy(&buffer[LIC_PAGE_OFFSET], &(header.crc), sizeof(header.crc));
///check if need update data to flash,erease license erea if there are some informations in license erea
if (!memcmp(auif_ptr, buffer + LIC_PAGE_OFFSET, len + sizeof(_flash_of_lic_para_head))) {
printf("flash information the same with license\n");
return 0;
}
printf("erase license sector \n");
sfc_erase(SECTOR_ERASER, sector);
printf("write license to flash \n");
sfc_write(buffer, page_addr, 256);
return 0;
}
static bool license_para_head_check(u8 *para)
{
_flash_of_lic_para_head *head;
//fill head
head = (_flash_of_lic_para_head *)para;
///crc check
u8 *crc_data = (u8 *)(para + sizeof(((_flash_of_lic_para_head *)0)->crc));
u32 crc_len = sizeof(_flash_of_lic_para_head) - sizeof(((_flash_of_lic_para_head *)0)->crc)/*head crc*/ + (head->string_len)/*content crc,include end character '\0'*/;
s16 crc_sum = 0;
crc_sum = CRC16(crc_data, crc_len);
if (crc_sum != head->crc) {
printf("license crc error !!! %x %x \n", (u32)crc_sum, (u32)head->crc);
return false;
}
return true;
}
//读取写入的认证码信息,返回值是认证码信息内存地址
const u8 *get_license_ptr(void)
{
u32 flash_capacity = sdfile_get_disk_capacity();
u32 flash_addr = flash_capacity - 256 + LIC_PAGE_OFFSET;
u8 *lic_ptr = NULL;
_flash_of_lic_para_head *head;
printf("flash capacity:%x \n", flash_capacity);
lic_ptr = (u8 *)sdfile_flash_addr2cpu_addr(flash_addr);
//head length check
head = (_flash_of_lic_para_head *)lic_ptr;
if (head->string_len >= 0xff) {
printf("license length error !!! \n");
return NULL;
}
////crc check
if (license_para_head_check(lic_ptr) == (false)) {
printf("license head check fail\n");
return NULL;
}
//put_buf(lic_ptr, 128);
lic_ptr += sizeof(_flash_of_lic_para_head);
return lic_ptr;
}