/* * Copyright (c) 2019 Actions Semi Co., Inc. * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief bt manager discover. */ #define SYS_LOG_NO_NEWLINE #define SYS_LOG_DOMAIN "bt discover" #include #include #include #include #include #include #include #include #include "bt_manager_inner.h" #include #include #include #include #include "bt_porting_inner.h" #define BT_DISCOVER_LIST_MAX 4 struct bt_discover_list { bd_address_t addr; int8_t rssi; uint8_t valid:1; uint8_t wait_req_name:1; }; struct bt_discover_info { uint8_t discovering:1; btsrv_discover_result_cb cb; struct bt_discover_list dev_list[BT_DISCOVER_LIST_MAX]; } discover_info; static void bt_discover_check_finish(void); static OS_MUTEX_DEFINE(bt_discover_mutex); static struct bt_discover_info *p_discover = &discover_info; /* Minor Device Class field - Audio/Video Major Class 7 6 5 4 3 2 Minor Device Class bit no. of CoD 0 0 0 0 0 0 Uncategorized, code not assigned 0 0 0 0 0 1 Wearable Headset Device 0 0 0 0 1 0 Hands-free Device 0 0 0 0 1 1 (Reserved) 0 0 0 1 0 0 Microphone 0 0 0 1 0 1 Loudspeaker 0 0 0 1 1 0 Headphones 0 0 0 1 1 1 Portable Audio 0 0 1 0 0 0 Car audio 0 0 1 0 0 1 Set-top box 0 0 1 0 1 0 HiFi Audio Device 0 0 1 0 1 1 VCR 0 0 1 1 0 0 Video Camera 0 0 1 1 0 1 Camcorder 0 0 1 1 1 0 Video Monitor 0 0 1 1 1 1 Video Display and Loudspeaker 0 1 0 0 0 0 Video Conferencing 0 1 0 0 0 1 (Reserved) 0 1 0 0 1 0 Gaming/Toy */ #define BT_COD_RENDERING_SERVICE_BTI (0x1 << 18) #define BT_COD_AUDIO_SERVICE_BTI (0x1 << 21) #define BT_COD_MAJOR_DC_MASK (0x1F00) #define BT_COD_MAJOR_DC_AUDIO (0x400) #define BT_COD_MAJOR_DC_WEARABLE (0x700) #define BT_COD_MINOR_DC_MASK (0xFC) static const uint8_t bt_support_mdc[] = {0x04, 0x14, 0x18, 0x1C, 0x20, 0x28}; static bool bt_discover_transmit_check_device(int cod) { uint8_t mdc, i; #ifdef CONFIG_OTA_PRODUCT_SUPPORT if ((cod & BT_COD_MAJOR_DC_WEARABLE) != BT_COD_MAJOR_DC_WEARABLE) { return false; } #else if (!(cod & (BT_COD_AUDIO_SERVICE_BTI | BT_COD_RENDERING_SERVICE_BTI))) { return false; } if ((cod & BT_COD_MAJOR_DC_MASK) != BT_COD_MAJOR_DC_AUDIO) { return false; } #endif mdc = (uint8_t)(cod & BT_COD_MINOR_DC_MASK); for (i=0; idev_list[i].valid) { if (!memcmp(&p_discover->dev_list[i].addr, &result->addr, sizeof(result->addr))) { if (p_discover->dev_list[i].wait_req_name && result->len) { p_discover->dev_list[i].wait_req_name = 0; } if (result->rssi > p_discover->dev_list[i].rssi) { p_discover->dev_list[i].rssi = result->rssi; } return; } if (weakest_rssi > p_discover->dev_list[i].rssi) { weakest_rssi = p_discover->dev_list[i].rssi; weakest_pos = i; } } else { if (idle_pos == 0xFF) { idle_pos = i; } } } if (idle_pos != 0xFF) { save_pos = idle_pos; } else { if (result->rssi > weakest_rssi) { save_pos = weakest_pos; } } if (save_pos != 0xFF) { memcpy(&p_discover->dev_list[save_pos].addr, &result->addr, sizeof(result->addr)); p_discover->dev_list[save_pos].valid = 1; p_discover->dev_list[save_pos].rssi = result->rssi; if (result->len) { p_discover->dev_list[save_pos].wait_req_name = 0; } else { p_discover->dev_list[save_pos].wait_req_name = 1; } } } static void bt_discover_remote_name_cb(bt_addr_t *addr, uint8_t *name) { int i; struct btsrv_discover_result result; os_mutex_lock(&bt_discover_mutex, OS_FOREVER); if (addr && name) { for (i=0; idev_list[i].valid && (!memcmp(&p_discover->dev_list[i].addr, addr, sizeof(bt_addr_t)))) { memset(&result, 0, sizeof(result)); memcpy(&result.addr, addr, sizeof(bt_addr_t)); result.len = strlen(name); result.name = name; result.rssi = p_discover->dev_list[i].rssi; if (p_discover->cb) { p_discover->cb(&result); } } } } bt_discover_check_finish(); os_mutex_unlock(&bt_discover_mutex); } static void bt_discover_check_finish(void) { int i, ret; struct btsrv_discover_result result; for (i=0; idev_list[i].valid) { if (p_discover->dev_list[i].wait_req_name) { SYS_LOG_INF("Req name %2x%2x%2x%2x%2x%2x", p_discover->dev_list[i].addr.val[5], p_discover->dev_list[i].addr.val[4], p_discover->dev_list[i].addr.val[3], p_discover->dev_list[i].addr.val[2], p_discover->dev_list[i].addr.val[1], p_discover->dev_list[i].addr.val[0]); p_discover->dev_list[i].wait_req_name = 0; ret = btif_br_remote_name_req(&p_discover->dev_list[i].addr, bt_discover_remote_name_cb); if (ret) { continue; } else { return; } } } } /* Discover all finish */ memset(&result, 0, sizeof(result)); p_discover->discovering = 0; result.discover_finish = 1; if (p_discover->cb) { p_discover->cb(&result); } p_discover->cb = NULL; } static void bt_discover_result_cb(void *result) { int cod; struct btsrv_discover_result *cb_result = result; os_mutex_lock(&bt_discover_mutex, OS_FOREVER); if (!p_discover->discovering) { goto cb_exit; } if (cb_result->discover_finish) { bt_discover_check_finish(); } else { cod = (cb_result->cod[2]<<16) + (cb_result->cod[1]<<8) + cb_result->cod[0]; if (!bt_discover_transmit_check_device(cod)) { goto cb_exit; } bt_discover_add_list(cb_result); if (p_discover->cb) { p_discover->cb(result); } } cb_exit: os_mutex_unlock(&bt_discover_mutex); } int bt_manager_br_start_discover(struct btsrv_discover_param *param) { int ret; struct btsrv_discover_param dis_param; os_mutex_lock(&bt_discover_mutex, OS_FOREVER); if (p_discover->discovering) { ret = -EBUSY; goto start_exit; } dis_param.length = param->length; dis_param.num_responses = param->num_responses; dis_param.cb = &bt_discover_result_cb; ret = btif_br_start_discover(&dis_param); if (ret == 0) { p_discover->cb = param->cb; p_discover->discovering = 1; memset(p_discover->dev_list, 0, sizeof(p_discover->dev_list)); } start_exit: os_mutex_unlock(&bt_discover_mutex); return ret; } int bt_manager_br_stop_discover(void) { int ret = 0; os_mutex_lock(&bt_discover_mutex, OS_FOREVER); if (!p_discover->discovering) { goto stop_exit; } p_discover->discovering = 0; p_discover->cb = NULL; ret = btif_br_stop_discover(); stop_exit: os_mutex_unlock(&bt_discover_mutex); return ret; }