diff --git a/doc/connectivity/bluetooth/shell/audio/ccp.rst b/doc/connectivity/bluetooth/shell/audio/ccp.rst index e5f81db914ad7..a7e6375550816 100644 --- a/doc/connectivity/bluetooth/shell/audio/ccp.rst +++ b/doc/connectivity/bluetooth/shell/audio/ccp.rst @@ -24,6 +24,7 @@ to :code:`0` which is the GTBS bearer. init : Initialize CCP Call Control Server set_bearer_name : Set bearer name [index] get_bearer_name : Get bearer name [index] + get_bearer_uci : Get bearer UCI [index] Example Usage @@ -58,6 +59,15 @@ Setting and getting the bearer name uart:~$ ccp_call_control_server get_bearer_name 1 Bearer[1] name: New TBS name +Getting the bearer UCI +---------------------- + +.. code-block:: console + + uart:~$ ccp_call_control_server get_bearer_uci + Bearer[0] UCI: un999 + uart:~$ ccp_call_control_server get_bearer_uci 1 + Bearer[1] UCI: skype Call Control Client ******************* diff --git a/include/zephyr/bluetooth/audio/ccp.h b/include/zephyr/bluetooth/audio/ccp.h index 0dd68befe2961..227782bc510a3 100644 --- a/include/zephyr/bluetooth/audio/ccp.h +++ b/include/zephyr/bluetooth/audio/ccp.h @@ -120,6 +120,19 @@ int bt_ccp_call_control_server_set_bearer_provider_name( int bt_ccp_call_control_server_get_bearer_provider_name( struct bt_ccp_call_control_server_bearer *bearer, const char **name); +/** + * @brief Get the bearer UCI. + * + * @param[in] bearer The bearer to get the UCI for. + * @param[out] uci Pointer that will be updated to be the bearer uci. + * + * @retval 0 Success + * @retval -EINVAL @p bearer or @p uci is NULL + * @retval -EFAULT @p bearer is not registered + */ +int bt_ccp_call_control_server_get_bearer_uci(struct bt_ccp_call_control_server_bearer *bearer, + const char **uci); + /** @} */ /* End of group bt_ccp_call_control_server */ /** diff --git a/include/zephyr/bluetooth/audio/tbs.h b/include/zephyr/bluetooth/audio/tbs.h index e1cc6bd36af15..2d8eb8338a829 100644 --- a/include/zephyr/bluetooth/audio/tbs.h +++ b/include/zephyr/bluetooth/audio/tbs.h @@ -199,7 +199,14 @@ extern "C" { * whenever the client should perform on action on the GTBS instance of the * server, rather than any of the specific Telephone Bearer Service instances. */ -#define BT_TBS_GTBS_INDEX 0xFF +#define BT_TBS_GTBS_INDEX 0xFF + +/** Maximum size of bearer uniform caller identifier (UCI) + * + * Includes the NULL terminator. + * Allowed values are defined by Bluetooth Assigned Numbers. + */ +#define BT_TBS_MAX_UCI_SIZE 6 /** @brief Opaque Telephone Bearer Service instance. */ struct bt_tbs_instance; diff --git a/subsys/bluetooth/audio/ccp_call_control_server.c b/subsys/bluetooth/audio/ccp_call_control_server.c index 053a83ed6bfff..37f766bfc1596 100644 --- a/subsys/bluetooth/audio/ccp_call_control_server.c +++ b/subsys/bluetooth/audio/ccp_call_control_server.c @@ -23,6 +23,7 @@ LOG_MODULE_REGISTER(bt_ccp_call_control_server, CONFIG_BT_CCP_CALL_CONTROL_SERVE /* A service instance can either be a GTBS or a TBS instance */ struct bt_ccp_call_control_server_bearer { char provider_name[CONFIG_BT_CCP_CALL_CONTROL_SERVER_PROVIDER_NAME_MAX_LENGTH + 1]; + char uci[BT_TBS_MAX_UCI_SIZE]; uint8_t tbs_index; bool registered; }; @@ -75,6 +76,7 @@ int bt_ccp_call_control_server_register_bearer(const struct bt_tbs_register_para free_bearer->tbs_index = (uint8_t)ret; (void)utf8_lcpy(free_bearer->provider_name, param->provider_name, sizeof(free_bearer->provider_name)); + (void)utf8_lcpy(free_bearer->uci, param->uci, sizeof(free_bearer->uci)); *bearer = free_bearer; return 0; @@ -175,3 +177,29 @@ int bt_ccp_call_control_server_get_bearer_provider_name( return 0; } + +int bt_ccp_call_control_server_get_bearer_uci(struct bt_ccp_call_control_server_bearer *bearer, + const char **uci) +{ + CHECKIF(bearer == NULL) { + LOG_DBG("bearer is NULL"); + + return -EINVAL; + } + + CHECKIF(uci == NULL) { + LOG_DBG("uci is NULL"); + + return -EINVAL; + } + + if (!bearer->registered) { + LOG_DBG("Bearer %p not registered", bearer); + + return -EFAULT; + } + + *uci = bearer->uci; + + return 0; +} diff --git a/subsys/bluetooth/audio/shell/ccp_call_control_server.c b/subsys/bluetooth/audio/shell/ccp_call_control_server.c index 4934fe8b52c3d..a2fc53b365b58 100644 --- a/subsys/bluetooth/audio/shell/ccp_call_control_server.c +++ b/subsys/bluetooth/audio/shell/ccp_call_control_server.c @@ -111,7 +111,7 @@ static int cmd_ccp_call_control_server_set_bearer_name(const struct shell *sh, s if (argc > 2) { index = validate_and_get_index(sh, argv[1]); if (index < 0) { - return index; + return -ENOEXEC; } } @@ -139,7 +139,7 @@ static int cmd_ccp_call_control_server_get_bearer_name(const struct shell *sh, s if (argc > 1) { index = validate_and_get_index(sh, argv[1]); if (index < 0) { - return index; + return -ENOEXEC; } } @@ -155,6 +155,32 @@ static int cmd_ccp_call_control_server_get_bearer_name(const struct shell *sh, s return 0; } +static int cmd_ccp_call_control_server_get_bearer_uci(const struct shell *sh, size_t argc, + char *argv[]) +{ + const char *uci; + int index = 0; + int err = 0; + + if (argc > 1) { + index = validate_and_get_index(sh, argv[1]); + if (index < 0) { + return -ENOEXEC; + } + } + + err = bt_ccp_call_control_server_get_bearer_uci(bearers[index], &uci); + if (err != 0) { + shell_error(sh, "Failed to get bearer[%d] UCI: %d", index, err); + + return -ENOEXEC; + } + + shell_print(sh, "Bearer[%d] UCI: %s", index, uci); + + return 0; +} + static int cmd_ccp_call_control_server(const struct shell *sh, size_t argc, char **argv) { if (argc > 1) { @@ -174,6 +200,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(ccp_call_control_server_cmds, cmd_ccp_call_control_server_set_bearer_name, 2, 1), SHELL_CMD_ARG(get_bearer_name, NULL, "Get bearer name [index]", cmd_ccp_call_control_server_get_bearer_name, 1, 1), + SHELL_CMD_ARG(get_bearer_uci, NULL, "Get bearer UCI [index]", + cmd_ccp_call_control_server_get_bearer_uci, 1, 1), SHELL_SUBCMD_SET_END); SHELL_CMD_ARG_REGISTER(ccp_call_control_server, &ccp_call_control_server_cmds, diff --git a/subsys/bluetooth/audio/tbs_internal.h b/subsys/bluetooth/audio/tbs_internal.h index 08fadf48745fb..11a279efacb5d 100644 --- a/subsys/bluetooth/audio/tbs_internal.h +++ b/subsys/bluetooth/audio/tbs_internal.h @@ -21,7 +21,6 @@ #include #include -#define BT_TBS_MAX_UCI_SIZE 6 #define BT_TBS_MIN_URI_LEN 3 /* a:b */ #define BT_TBS_FREE_CALL_INDEX 0 diff --git a/tests/bluetooth/audio/ccp_call_control_server/src/main.c b/tests/bluetooth/audio/ccp_call_control_server/src/main.c index 212cd185fda11..989502ebedd15 100644 --- a/tests/bluetooth/audio/ccp_call_control_server/src/main.c +++ b/tests/bluetooth/audio/ccp_call_control_server/src/main.c @@ -26,6 +26,7 @@ DEFINE_FFF_GLOBALS; #define DEFAULT_BEARER_NAME "test" +#define DEFAULT_BEARER_UCI "un999" struct ccp_call_control_server_test_suite_fixture { /** Need 1 additional bearer than the max to trigger some corner cases */ @@ -83,7 +84,7 @@ static void register_default_bearer(struct ccp_call_control_server_test_suite_fi { const struct bt_tbs_register_param register_param = { .provider_name = DEFAULT_BEARER_NAME, - .uci = "un999", + .uci = DEFAULT_BEARER_UCI, .uri_schemes_supported = "tel", .gtbs = true, .authorization_required = false, @@ -408,3 +409,55 @@ static ZTEST_F(ccp_call_control_server_test_suite, err = bt_ccp_call_control_server_get_bearer_provider_name(fixture->bearers[0], NULL); zassert_equal(err, -EINVAL, "Unexpected return value %d", err); } + +static ZTEST_F(ccp_call_control_server_test_suite, test_bt_ccp_call_control_server_get_bearer_uci) +{ + const char *res_bearer_uci; + int err; + + register_default_bearer(fixture); + + err = bt_ccp_call_control_server_get_bearer_uci(fixture->bearers[0], &res_bearer_uci); + zassert_equal(err, 0, "Unexpected return value %d", err); + + zassert_str_equal(DEFAULT_BEARER_UCI, res_bearer_uci, "%s != %s", DEFAULT_BEARER_UCI, + res_bearer_uci); +} + +static ZTEST_F(ccp_call_control_server_test_suite, + test_bt_ccp_call_control_server_get_bearer_uci_inval_not_registered) +{ + const char *res_bearer_uci; + int err; + + /* Register and unregister bearer to get a valid pointer but where it is unregistered*/ + register_default_bearer(fixture); + err = bt_ccp_call_control_server_unregister_bearer(fixture->bearers[0]); + zassert_equal(err, 0, "Unexpected return value %d", err); + + err = bt_ccp_call_control_server_get_bearer_uci(fixture->bearers[0], &res_bearer_uci); + zassert_equal(err, -EFAULT, "Unexpected return value %d", err); +} + +static ZTEST_F(ccp_call_control_server_test_suite, + test_bt_ccp_call_control_server_get_bearer_uci_inval_null_bearer) +{ + const char *res_bearer_uci; + int err; + + register_default_bearer(fixture); + + err = bt_ccp_call_control_server_get_bearer_uci(NULL, &res_bearer_uci); + zassert_equal(err, -EINVAL, "Unexpected return value %d", err); +} + +static ZTEST_F(ccp_call_control_server_test_suite, + test_bt_ccp_call_control_server_get_bearer_uci_inval_null_uci) +{ + int err; + + register_default_bearer(fixture); + + err = bt_ccp_call_control_server_get_bearer_uci(fixture->bearers[0], NULL); + zassert_equal(err, -EINVAL, "Unexpected return value %d", err); +}