#include "app_protocol_api.h" #include "app_protocol_common.h" #include "system/includes.h" #include "app_config.h" #include "audio_config.h" #include "app_chargestore.h" #include "app_power_manage.h" #include "asm/charge.h" #include "bt_tws.h" #include "btstack/avctp_user.h" #include "3th_profile_api.h" #include "bt_common.h" #include "tone_player.h" #include "app_main.h" #include "key_event_deal.h" #if AI_APP_PROTOCOL #if 1 #define APP_PROTOCOL_LOG printf #define APP_PROTOCOL_DUMP put_buf #else #define APP_PROTOCOL_LOG(...) #define APP_PROTOCOL_DUMP(...) #endif __attribute__((weak)) void app_protocol_tone_play(int index, int tws_sync) { } static const char **app_tone_table = NULL; static struct app_protocol_private_handle_t *private_handle; extern u8 get_remote_dev_company(void); #define REMOTE_DEV_ANDROID 1 #define REMOTE_DEV_IOS 2 bool is_ios_system(void) { APP_PROTOCOL_LOG("remote_dev_company :%d \n", get_remote_dev_company()); return (get_remote_dev_company() == REMOTE_DEV_IOS); } void app_protocol_tone_register(const char **tone_table) { app_tone_table = tone_table; } const char *app_protocol_get_tone(int index) { if (app_tone_table) { return app_tone_table[index]; } return NULL; } void app_protocol_handle_register(struct app_protocol_private_handle_t *hd) { private_handle = hd; } struct app_protocol_private_handle_t *app_protocol_get_handle() { return private_handle; } //协议私有同步消息处理函数 void app_protocol_tws_sync_private_deal(int cmd, int value) { if (private_handle && private_handle->tws_sync_func) { private_handle->tws_sync_func(cmd, value); } } //协议私有收到对耳数据处理函数 void app_protocol_tws_rx_data_private_deal(u16 opcode, u8 *data, u16 len) { if (private_handle && private_handle->tws_rx_from_siblling) { private_handle->tws_rx_from_siblling(opcode, data, len); } } int app_protocol_sys_event_private_deal(struct sys_event *event) { if (private_handle && private_handle->sys_event_handler) { return private_handle->sys_event_handler(event); } return 0; } #if APP_PROTOCOL_SPEECH_EN #define APP_PROTOCOL_MIC_TIMEOUT 8000 //mic使用超时时间,0不限时 static u16 mic_timer = 0; static u16 tone_after_exit_sniff_timer = 0; static u8 exit_sniff_cnt = 0; void __app_protocol_speech_stop(void) { if (ai_mic_is_busy()) { if (mic_timer) { sys_timeout_del(mic_timer); mic_timer = 0; } APP_PROTOCOL_LOG("app_protocol_speech_stop\n"); ai_mic_rec_close(); app_protocol_stop_speech_cmd(); } } static void app_protocol_speech_timeout(void *priv) { APP_PROTOCOL_LOG(" speech timeout !!! \n"); __app_protocol_speech_stop(); } static int app_protocol_speech_start_check() { if (BT_STATUS_TAKEING_PHONE == get_bt_connect_status()) { APP_PROTOCOL_LOG("phone ing...\n"); return -1; } if (ai_mic_is_busy()) { APP_PROTOCOL_LOG("mic activing...\n"); return -1; } return 0; } int __app_protocol_speech_start(void) { if (!app_protocol_speech_start_check() && ai_mic_rec_start() == 0) { #if APP_PROTOCOL_MIC_TIMEOUT mic_timer = sys_timeout_add(NULL, app_protocol_speech_timeout, APP_PROTOCOL_MIC_TIMEOUT); #endif return 0; } APP_PROTOCOL_LOG("speech start fail\n"); return -1; } int app_protocol_start_speech_by_app(u8 tone_en) { if (app_protocol_speech_start_check()) { return -1; } if (app_var.siri_stu) { APP_PROTOCOL_LOG("siri activing...\n"); return -1; } if (tone_en) { app_protocol_tone_play(APP_RROTOCOL_TONE_SPEECH_APP_START, 1); } else { app_protocol_post_bt_event(AI_EVENT_SPEECH_START, NULL); } return 0; } int app_protocol_stop_speech_by_app() { app_protocol_post_bt_event(AI_EVENT_SPEECH_STOP, NULL); return 0; } static void speech_tone_play_after_exit_sniff() { tone_after_exit_sniff_timer = 0; if (bt_is_sniff_close() && exit_sniff_cnt < 13) { exit_sniff_cnt++; tone_after_exit_sniff_timer = sys_timeout_add(NULL, speech_tone_play_after_exit_sniff, 100); return; } exit_sniff_cnt = 0; if (!app_protocol_speech_start_check()) { app_protocol_tone_play(APP_RROTOCOL_TONE_SPEECH_KEY_START, 1); } } int app_protocol_start_speech_by_key(struct sys_event *event) { #if TCFG_USER_TWS_ENABLE if (get_bt_tws_connect_status() && !is_tws_master_role()) { APP_PROTOCOL_LOG("tws slave, return\n"); return 0; } #endif user_send_cmd_prepare(USER_CTRL_HFP_GET_SIRI_STATUS, 0, NULL); if (app_protocol_speech_start_check()) { return -1; } if (app_protocol_check_connect_success() && (get_curr_channel_state()&A2DP_CH)) { printf("no connect\n"); } else { if (get_curr_channel_state()&A2DP_CH) { //<协议未连接, 但是A2DP已连接, 点击唤醒键, 提示TTS【请打开小度APP】 if (is_ios_system()) { APP_PROTOCOL_LOG("ble adv ibeaconn"); app_protocol_ibeacon_switch(1); } else { user_send_cmd_prepare(USER_CTRL_HFP_GET_SIRI_OPEN, 0, NULL); } app_protocol_tone_play(APP_PROTOCOL_TONE_DISCONNECTED_ALL, 1); } else { //<蓝牙完全关闭状态, 用户按唤醒键, 提示TTS【蓝牙未连接, 请用手机蓝牙和我连接吧】 app_protocol_tone_play(APP_RROTOCOL_TONE_OPEN_APP, 1); } APP_PROTOCOL_LOG("A2dp or protocol no connect err!!!\n"); return -1; } #if 1//等退出sniff后再播提示音 if (bt_is_sniff_close()) { user_send_cmd_prepare(USER_CTRL_ALL_SNIFF_EXIT, 0, NULL); if (tone_after_exit_sniff_timer == 0) { tone_after_exit_sniff_timer = sys_timeout_add(NULL, speech_tone_play_after_exit_sniff, 100); } return 0; } exit_sniff_cnt = 0; #endif app_protocol_tone_play(APP_RROTOCOL_TONE_SPEECH_KEY_START, 1); return 0; } int app_protocol_stop_speech_by_key(void) { return 0; } #else void __app_protocol_speech_stop(void) { } #endif void app_speech_tone_play_end_callback(void *priv, int flag) { u32 index = (u32)priv; switch (index) { #if APP_PROTOCOL_SPEECH_EN case APP_RROTOCOL_TONE_SPEECH_KEY_START: APP_PROTOCOL_LOG("APP_RROTOCOL_TONE_SPEECH_KEY_START\n"); if (app_protocol_speech_start_check()) { break; } if (app_var.siri_stu) { APP_PROTOCOL_LOG("siri activing...\n"); break; } ///按键启动需要report, app启动, 直接启动语音即可 if (is_tws_master_role() && !app_protocol_start_speech_cmd()) {//从转发mic数据给主机或主机上报完成开启mic APP_PROTOCOL_LOG("app_protocol_mic_status_report success\n"); app_protocol_post_bt_event(AI_EVENT_SPEECH_START, NULL); } break; case APP_RROTOCOL_TONE_SPEECH_APP_START: APP_PROTOCOL_LOG("APP_RROTOCOL_TONE_SPEECH_APP_START\n"); if (app_protocol_speech_start_check()) { break; } if (app_var.siri_stu) { APP_PROTOCOL_LOG("siri activing...\n"); break; } if (is_tws_master_role()) { app_protocol_post_bt_event(AI_EVENT_SPEECH_START, NULL); } break; #endif default: break; } } int app_protocol_set_volume(u8 vol) { u8 vol_l = (vol * get_max_sys_vol()) / 0x64; u8 vol_r = (vol * get_max_sys_vol()) / 0x64; app_audio_set_volume(APP_AUDIO_STATE_MUSIC, APP_AUDIO_STATE_MUSIC, vol_r); return 0; } __attribute__((weak)) bool vbat_is_low_power(void) { return 0; } u8 app_protocal_get_bat_by_type(u8 type) { u8 value = 0; extern u8 get_tws_sibling_bat_persent(void); u8 sibling_val = get_tws_sibling_bat_persent(); #if TCFG_CHARGESTORE_ENABLE if (sibling_val == 0xff) { sibling_val = chargestore_get_sibling_power_level(); } #endif switch (type) { case APP_PROTOCOL_BAT_T_CHARGE_FLAG: value = get_charge_online_flag(); break; case APP_PROTOCOL_BAT_T_MAIN: value = get_vbat_percent(); break; #if TCFG_CHARGESTORE_ENABLE case APP_PROTOCOL_BAT_T_BOX: value = chargestore_get_power_level(); break; #endif case APP_PROTOCOL_BAT_T_TWS_LEFT: value = (tws_api_get_local_channel() == 'L') ? get_vbat_percent() : sibling_val; break; case APP_PROTOCOL_BAT_T_TWS_RIGHT: value = (tws_api_get_local_channel() == 'R') ? get_vbat_percent() : sibling_val; break; case APP_PROTOCOL_BAT_T_TWS_SIBLING: value = sibling_val; break; case APP_PROTOCOL_BAT_T_LOW_POWER: value = vbat_is_low_power(); break; default: break; } if (value == 0xff) { //获取不到电量返回0 value = 0; } return value; } u32 read_cfg_file(void *buf, u16 len, char *path) { FILE *fp = fopen(path, "r"); int rlen; if (!fp) { //printf("read_cfg_file:fopen err!\n"); return FALSE; } rlen = fread(fp, buf, len); if (rlen <= 0) { //printf("read_cfg_file:fread err!\n"); return FALSE; } fclose(fp); return TRUE; } #define LIC_PAGE_OFFSET 80 #define FORCE_TO_ERASE 1 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; 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 *app_protocal_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; } extern bool sfc_erase(int cmd, u32 addr); extern u32 sfc_write(const u8 *buf, u32 addr, u32 len); //将三元组信息保存到flash里面 int app_protocol_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); #if (!FORCE_TO_ERASE) APP_PROTOCOL_LOG("not supported flash erase !!! \n"); return (-1); #endif ///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))) { APP_PROTOCOL_LOG("flash information the same with license\n"); return 0; } APP_PROTOCOL_LOG("erase license sector \n"); sfc_erase(SECTOR_ERASER, sector); APP_PROTOCOL_LOG("write license to flash \n"); sfc_write(buffer, page_addr, 256); return 0; } int app_protocol_tws_send_to_sibling(u16 opcode, u8 *data, u16 len) { u8 send_data[len + 4]; printf("app protocol send data to sibling \n"); send_data[0] = opcode & 0xff; send_data[1] = opcode >> 8; send_data[2] = len & 0xff; send_data[3] = len >> 8; memcpy(send_data + 4, data, len); return tws_api_send_data_to_sibling(send_data, sizeof(send_data), APP_PROTOCOL_TWS_SEND_ID); } static void __tws_rx_from_sibling(u8 *data) { u16 opcode = (data[1] << 8) | data[0]; u16 len = (data[3] << 8) | data[2]; u8 *rx_data = data + 4; switch (opcode) { case APP_PROTOCOL_TWS_FOR_LIB: APP_PROTOCOL_LOG("APP_PROTOCOL_TWS_FOR_LIB"); app_protocol_get_tws_data_for_lib(rx_data, len); break; } app_protocol_tws_rx_data_private_deal(opcode, rx_data, len); free(data); } static void app_protocol_rx_from_sibling(void *_data, u16 len, bool rx) { int err = 0; if (rx) { printf(">>>%s \n", __func__); printf("len :%d\n", len); put_buf(_data, len); u8 *rx_data = malloc(len); memcpy(rx_data, _data, len); int msg[4]; msg[0] = (int)__tws_rx_from_sibling; msg[1] = 1; msg[2] = (int)rx_data; err = os_taskq_post_type("app_core", Q_CALLBACK, 3, msg); if (err) { printf("tws rx post fail\n"); } } } //发送给对耳 REGISTER_TWS_FUNC_STUB(app_vol_sync_stub) = { .func_id = APP_PROTOCOL_TWS_SEND_ID, .func = app_protocol_rx_from_sibling, }; //对耳同步执行 int app_protocol_tws_sync_send(int cmd, int value) { int data[2]; data[0] = cmd; data[1] = value; return tws_api_send_data_to_slave(data, sizeof(data), APP_PROTOCOL_TWS_SYNC_ID); } void app_protocol_tws_sync_deal(int cmd, int value) { switch (cmd) { case APP_PROTOCOL_SYNC_TONE: printf("APP_PROTOCOL_SYNC_TONE:%d\n", value); app_protocol_tone_play(value, 0); break; } app_protocol_tws_sync_private_deal(cmd, value); } static void app_protocol_tws_sync_rx(void *data, u16 len, bool rx) { int err = 0; int *arg = (int *)data; int msg[8]; msg[0] = (int)app_protocol_tws_sync_deal; msg[1] = len / sizeof(int); msg[2] = arg[0]; //cmd msg[3] = arg[1]; //value err = os_taskq_post_type("app_core", Q_CALLBACK, 2 + len / sizeof(int), msg); if (err) { printf("tws sync post fail\n"); } } REGISTER_TWS_FUNC_STUB(app_protocol_sync) = { .func_id = APP_PROTOCOL_TWS_SYNC_ID, .func = app_protocol_tws_sync_rx, }; //在app_core任务里面进行处理 int app_protocol_post_app_core_callback(int callback, void *priv) { int msg[8]; msg[0] = callback; msg[1] = 1; msg[2] = (int)priv; return os_taskq_post_type("app_core", Q_CALLBACK, 3, msg); } void app_protocol_post_bt_event(u8 event, void *priv) { struct sys_event e; memset(&e, 0, sizeof(e)); e.type = SYS_BT_EVENT; e.arg = (void *)SYS_BT_AI_EVENT_TYPE_STATUS; e.u.bt.event = event; e.u.bt.value = (int)priv; sys_event_notify(&e); } static int app_protocol_bt_status_event_handler(struct bt_event *bt) { switch (bt->event) { case BT_STATUS_INIT_OK: app_protocol_all_init(); break; case BT_STATUS_SECOND_CONNECTED: case BT_STATUS_FIRST_CONNECTED: if (app_protocol_check_connect_success()) { app_protocol_tone_play(APP_PROTOCOL_TONE_CONNECTED_ALL_FINISH, 1); } else { app_protocol_tone_play(APP_PROTOCOL_TONE_CONNECTED_NEED_OPEN_APP, 1); } break; case BT_STATUS_FIRST_DISCONNECT: case BT_STATUS_SECOND_DISCONNECT: app_protocol_tone_play(APP_PROTOCOL_TONE_DISCONNECTED, 1); app_protocal_update_tws_state_to_lib(USER_NOTIFY_STATE_MOBILE_DISCONNECTED); break; case BT_STATUS_PHONE_INCOME: case BT_STATUS_PHONE_OUT: case BT_STATUS_PHONE_ACTIVE: __app_protocol_speech_stop(); app_protocol_ble_adv_switch(0); break; case BT_STATUS_PHONE_HANGUP: app_protocol_ble_adv_switch(1); break; case BT_STATUS_PHONE_MANUFACTURER: if (!app_protocol_check_connect_success()) { if (is_ios_system()) { app_protocol_ibeacon_switch(1); } if (get_call_status() != BT_CALL_HANGUP) { app_protocol_ble_adv_switch(0); } } break; case BT_STATUS_VOICE_RECOGNITION: if ((app_var.siri_stu == 1) || (app_var.siri_stu == 2)) { __app_protocol_speech_stop(); app_protocol_ble_adv_switch(0); } else if (app_var.siri_stu == 0) { app_protocol_ble_adv_switch(1); } break; case BT_STATUS_CONN_A2DP_CH: app_protocal_update_tws_state_to_lib(USER_NOTIFY_STATE_MOBILE_CONNECTED); break; } return 0; } static void app_protocol_bt_tws_event_handler(struct bt_event *bt) { int role = bt->args[0]; int phone_link_connection = bt->args[1]; int reason = bt->args[2]; switch (bt->event) { case TWS_EVENT_CONNECTED: if (!is_tws_master_role()) { app_protocol_disconnect(NULL); app_protocol_ble_adv_switch(0); } else { #if APP_PROTOCOL_SPEECH_EN if (ai_mic_is_busy()) { //mic在解码过程中,从机连接成功,挂起音频 //ai_mic_tws_sync_suspend(); } #endif } app_protocal_update_tws_state_to_lib(USER_NOTIFY_STATE_TWS_CONNECT); break; case TWS_EVENT_CONNECTION_DETACH: if (!app_protocol_check_connect_success()) { //APP未连接,开启广播 if (0 == get_esco_coder_busy_flag()) { //esco在用的时候开广播会影响质量 app_protocol_ble_adv_switch(1); } } #if APP_PROTOCOL_SPEECH_EN if (!ai_mic_is_busy()) { __app_protocol_speech_stop(); //对耳断开时没启动mic,停止语音 } #endif app_protocal_update_tws_state_to_lib(USER_NOTIFY_STATE_BATTERY_LEVEL_UPDATE); //主动上报电量 app_protocal_update_tws_state_to_lib(USER_NOTIFY_STATE_TWS_DISCONNECT); break; case TWS_EVENT_ROLE_SWITCH: app_protocal_update_tws_state_to_lib(USER_NOTIFY_STATE_ROLE_SWITCH_FINISH); app_protocol_disconnect(NULL); if (role == TWS_ROLE_MASTER && (0 == get_esco_coder_busy_flag())) { app_protocol_ble_adv_switch(1); } else { app_protocol_ble_adv_switch(0); } break; } } static int app_protocol_bt_ai_event_handler(struct bt_event *bt) { switch (bt->event) { #if APP_PROTOCOL_SPEECH_EN case AI_EVENT_SPEECH_START: APP_PROTOCOL_LOG("AI_EVENT_SPEECH_START"); __app_protocol_speech_start(); break; case AI_EVENT_SPEECH_STOP: APP_PROTOCOL_LOG("AI_EVENT_SPEECH_STOP"); __app_protocol_speech_stop(); break; #endif case AI_EVENT_APP_CONNECT: APP_PROTOCOL_LOG("AI_EVENT_APP_CONNECT"); if (get_curr_channel_state()&A2DP_CH) { app_protocol_tone_play(APP_PROTOCOL_TONE_CONNECTED_ALL_FINISH, 1); } else { app_protocol_tone_play(APP_PROTOCOL_TONE_PROTOCOL_CONNECTED, 1); } break; case AI_EVENT_APP_DISCONNECT: APP_PROTOCOL_LOG("AI_EVENT_APP_DISCONNECT"); __app_protocol_speech_stop(); break; } return 0; } int app_protocol_sys_event_handler(struct sys_event *event) { switch (event->type) { case SYS_BT_EVENT: if ((u32)event->arg == SYS_BT_EVENT_TYPE_CON_STATUS) { app_protocol_bt_status_event_handler(&event->u.bt); } #if TCFG_USER_TWS_ENABLE else if (((u32)event->arg == SYS_BT_EVENT_FROM_TWS)) { app_protocol_bt_tws_event_handler(&event->u.bt); } #endif else if (((u32)event->arg == SYS_BT_AI_EVENT_TYPE_STATUS)) { app_protocol_bt_ai_event_handler(&event->u.bt); } break; case SYS_KEY_EVENT: app_protocol_key_event_handler(event); break; } app_protocol_sys_event_private_deal(event); return 0; } void tell_lib_start_role_switch() { app_protocol_ble_adv_switch(0); if (is_tws_master_role()) { printf("master dev will role switch\n"); app_protocal_update_tws_state_to_lib(USER_NOTIFY_STATE_ROLE_SWITCH_START); /* os_time_dly(10); */ } } #else int app_protocol_sys_event_handler(struct sys_event *event) { return 0; } void tell_lib_start_role_switch() { } #endif