From 1d3a88c85145a12649c9027082037410cec714e1 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 10 Oct 2024 11:03:40 +0200 Subject: [PATCH] Bluetooth: CCP: Server: Add support for get UCI Add support for getting the UCI. For now the UCI will be duplicated by the TBS implementation, but will be optimizied in the future so only one copy of the UCI exists. Signed-off-by: Emil Gydesen --- .../bluetooth/shell/audio/ccp.rst | 10 ++++ include/zephyr/bluetooth/audio/ccp.h | 13 +++++ include/zephyr/bluetooth/audio/tbs.h | 9 ++- .../bluetooth/audio/ccp_call_control_server.c | 28 ++++++++++ .../audio/shell/ccp_call_control_server.c | 32 ++++++++++- subsys/bluetooth/audio/tbs_internal.h | 1 - .../audio/ccp_call_control_server/src/main.c | 55 ++++++++++++++++++- 7 files changed, 143 insertions(+), 5 deletions(-) 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); +}