/* * Copyright (c) 2019 Bose Corporation * Copyright (c) 2021 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include #include #include #include #include "bstests.h" #include "common.h" #ifdef CONFIG_BT_TBS extern enum bst_result_t bst_result; static uint8_t g_call_index; CREATE_FLAG(is_connected); CREATE_FLAG(call_placed); CREATE_FLAG(call_held); CREATE_FLAG(call_terminated); CREATE_FLAG(call_accepted); CREATE_FLAG(call_retrieved); CREATE_FLAG(call_joined); static void tbs_hold_call_cb(struct bt_conn *conn, uint8_t call_index) { if (call_index == g_call_index) { SET_FLAG(call_held); } } static bool tbs_originate_call_cb(struct bt_conn *conn, uint8_t call_index, const char *caller_id) { printk("Placing call to remote with id %u to %s\n", call_index, caller_id); g_call_index = call_index; SET_FLAG(call_placed); return true; } static bool tbs_authorize_cb(struct bt_conn *conn) { return conn == default_conn; } static void tbs_terminate_call_cb(struct bt_conn *conn, uint8_t call_index, uint8_t reason) { printk("Terminating call with id %u reason: %u", call_index, reason); SET_FLAG(call_terminated); UNSET_FLAG(call_placed); } static void tbs_accept_call_cb(struct bt_conn *conn, uint8_t call_index) { printk("Accepting call with index %u\n", call_index); SET_FLAG(call_accepted); } static void tbs_retrieve_call_cb(struct bt_conn *conn, uint8_t call_index) { printk("Retrieve call with index %u\n", call_index); SET_FLAG(call_retrieved); } static void tbs_join_calls_cb(struct bt_conn *conn, uint8_t call_index_count, const uint8_t *call_indexes) { for (size_t i = 0; i < sizeof(call_indexes); i++) { printk("Call index: %u joined\n", call_indexes[i]); } SET_FLAG(call_joined); } static struct bt_tbs_cb tbs_cbs = { .originate_call = tbs_originate_call_cb, .terminate_call = tbs_terminate_call_cb, .hold_call = tbs_hold_call_cb, .accept_call = tbs_accept_call_cb, .retrieve_call = tbs_retrieve_call_cb, .join_calls = tbs_join_calls_cb, .authorize = tbs_authorize_cb, }; static void connected(struct bt_conn *conn, uint8_t err) { char addr[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); if (err != 0) { FAIL("Failed to connect to %s (%u)\n", addr, err); return; } printk("Connected to %s\n", addr); default_conn = bt_conn_ref(conn); SET_FLAG(is_connected); } static struct bt_conn_cb conn_callbacks = { .connected = connected, .disconnected = disconnected, }; static int test_provider_name(void) { int err; printk("%s\n", __func__); err = bt_tbs_set_bearer_provider_name(0, "BabblesimTBS"); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Could not set bearer provider name: %d\n", err); return err; } printk("Set bearer provider name test success\n"); return err; } static int test_set_signal_strength(void) { int err; printk("%s\n", __func__); err = bt_tbs_set_signal_strength(0, 6); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Could not set bearer provider name: %d\n", err); return err; } printk("Set signal strength test success\n"); return err; } static int test_set_bearer_technology(void) { int err; printk("%s\n", __func__); err = bt_tbs_set_bearer_technology(0, BT_TBS_TECHNOLOGY_GSM); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Could not set bearer technology: %d\n", err); return err; } printk("Set bearer technology test success\n"); return err; } static int test_set_status_flags(void) { int err; printk("%s\n", __func__); err = bt_tbs_set_status_flags(0, 3); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Could not set status flags: %d\n", err); return err; } printk("Set status flags test success\n"); return err; } static int test_answer_terminate(void) { int err; printk("%s\n", __func__); printk("Placing call\n"); err = bt_tbs_originate(0, "tel:000000000001", &g_call_index); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Could not originate call: %d\n", err); return err; } printk("Answering call\n"); err = bt_tbs_remote_answer(g_call_index); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Could not accept call: %d\n", err); return err; } printk("Terminating call\n"); err = bt_tbs_terminate(g_call_index); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Could not terminate call: %d\n", err); return err; } printk("Test answer & terminate successful\n"); return err; } static int test_hold_retrieve(void) { int err; printk("%s\n", __func__); err = bt_tbs_originate(0, "tel:000000000001", &g_call_index); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Could not originate call: %d\n", err); return err; } err = bt_tbs_remote_answer(g_call_index); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Could not accept call: %d\n", err); return err; } printk("Holding call\n"); err = bt_tbs_hold(g_call_index); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Could not terminate call: %d\n", err); return err; } printk("Retrieving call\n"); err = bt_tbs_retrieve(g_call_index); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Could not retrieve call: %d\n", err); return err; } printk("Terminating call\n"); err = bt_tbs_terminate(g_call_index); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Could not terminate call: %d\n", err); return err; } printk("Hold & retrieve test successful\n"); return err; } static int test_join(void) { int err; uint8_t call_indexes[2]; printk("%s\n", __func__); printk("Placing first call\n"); err = bt_tbs_originate(0, "tel:000000000001", &g_call_index); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Could not originate first call: %d\n", err); return err; } printk("Answering first call\n"); err = bt_tbs_remote_answer(g_call_index); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Could not answer first call: %d\n", err); return err; } printk("First call answered\n"); call_indexes[0] = (uint8_t)g_call_index; printk("Placing second call\n"); err = bt_tbs_originate(0, "tel:000000000002", &g_call_index); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Could not originate second call: %d\n", err); return err; } printk("Answering second call\n"); err = bt_tbs_remote_answer(g_call_index); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Could not answer second call: %d\n", err); return err; } printk("Second call answered\n"); call_indexes[1] = (uint8_t)g_call_index; printk("Joining calls\n"); err = bt_tbs_join(2, call_indexes); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Could not join calls: %d\n", err); return err; } err = bt_tbs_terminate(call_indexes[0]); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Could not terminate first call: %d\n", err); return err; } err = bt_tbs_terminate(call_indexes[1]); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Could not terminate second call: %d\n", err); return err; } printk("Join calls test successful\n"); return err; } static void test_tbs_server_only(void) { test_answer_terminate(); test_hold_retrieve(); test_join(); test_provider_name(); test_set_signal_strength(); test_set_bearer_technology(); test_set_status_flags(); } static void init(void) { const struct bt_tbs_register_param gtbs_param = { .provider_name = "Generic TBS", .uci = "un000", .uri_schemes_supported = "tel,skype", .gtbs = true, .authorization_required = false, .technology = BT_TBS_TECHNOLOGY_3G, .supported_features = CONFIG_BT_TBS_SUPPORTED_FEATURES, }; int err; err = bt_enable(NULL); if (err != 0) { FAIL("Bluetooth enable failed (err %d)\n", err); return; } printk("Bluetooth initialized\n"); err = bt_conn_cb_register(&conn_callbacks); if (err != 0) { FAIL("Failed to register conn CBs (err %d)\n", err); return; } err = bt_le_scan_cb_register(&common_scan_cb); if (err != 0) { FAIL("Failed to register scan CBs (err %d)\n", err); return; } bt_tbs_register_cb(&tbs_cbs); err = bt_tbs_register_bearer(>bs_param); if (err < 0) { FAIL("Failed to register GTBS (err %d)\n", err); return; } printk("Registered GTBS\n"); for (int i = 0; i < CONFIG_BT_TBS_BEARER_COUNT; i++) { char prov_name[22]; /* Enough to store "Telephone Bearer #255" */ const struct bt_tbs_register_param tbs_param = { .provider_name = prov_name, .uci = "un000", .uri_schemes_supported = "tel,skype", .gtbs = false, .authorization_required = false, /* Set different technologies per bearer */ .technology = (i % BT_TBS_TECHNOLOGY_WCDMA) + 1, .supported_features = CONFIG_BT_TBS_SUPPORTED_FEATURES, }; snprintf(prov_name, sizeof(prov_name), "Telephone Bearer #%d", i); err = bt_tbs_register_bearer(&tbs_param); if (err < 0) { FAIL("Failed to register TBS[%d]: %d", i, err); return; } printk("Registered TBS[%d] with index %u\n", i, (uint8_t)err); } } static void test_main(void) { int err; init(); err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL); if (err != 0) { FAIL("Scanning failed to start (err %d)\n", err); return; } printk("Scanning successfully started\n"); WAIT_FOR_COND(is_connected); WAIT_FOR_COND(call_placed); err = bt_tbs_remote_answer(g_call_index); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Remote could not answer call: %d\n", err); return; } printk("Remote answered %u\n", g_call_index); err = bt_tbs_remote_hold(g_call_index); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Remote could not hold call: %d\n", err); } printk("Remote held %u\n", g_call_index); WAIT_FOR_COND(call_held); err = bt_tbs_remote_retrieve(g_call_index); if (err != BT_TBS_RESULT_CODE_SUCCESS) { FAIL("Remote could not answer call: %d\n", err); return; } printk("Remote retrieved %u\n", g_call_index); PASS("TBS Passed\n"); } static void tbs_test_server_only(void) { init(); test_tbs_server_only(); PASS("TBS server tests passed\n"); } static const struct bst_test_instance test_tbs[] = { { .test_id = "tbs_test_server_only", .test_pre_init_f = test_init, .test_tick_f = test_tick, .test_main_f = tbs_test_server_only }, { .test_id = "tbs", .test_pre_init_f = test_init, .test_tick_f = test_tick, .test_main_f = test_main }, BSTEST_END_MARKER }; struct bst_test_list *test_tbs_install(struct bst_test_list *tests) { return bst_add_tests(tests, test_tbs); } #else struct bst_test_list *test_tbs_install(struct bst_test_list *tests) { return tests; } #endif /* CONFIG_BT_TBS */