Skip to content

Commit

Permalink
Bluetooth: CCP: Add support for set/get provider name
Browse files Browse the repository at this point in the history
Add support for setting and getting the bearer provider
name. For now the name will be duplicated by the TBS
implementation, but will be optimizied in the future
so only one copy of the name exists.

Signed-off-by: Emil Gydesen <[email protected]>
  • Loading branch information
Thalley committed Oct 3, 2024
1 parent 15e59b5 commit a568ef4
Show file tree
Hide file tree
Showing 6 changed files with 237 additions and 2 deletions.
25 changes: 25 additions & 0 deletions include/zephyr/bluetooth/audio/ccp.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,31 @@ int bt_ccp_server_register_bearer(const struct bt_tbs_register_param *param,
*/
int bt_ccp_server_unregister_bearer(struct bt_ccp_server_bearer *bearer);

/**
* @brief Set a new bearer provider name.
*
* @param bearer The bearer to set the name for.
* @param name The new bearer provider name.
*
* @retval 0 Success
* @retval -EINVAL @p bearer or @p name is NULL, or @p name is the empty string or @p name is larger
* than @kconfig{CONFIG_BT_TBS_MAX_PROVIDER_NAME_LENGTH}
* @retval -EFAULT @p bearer is not registered
*/
int bt_ccp_server_set_bearer_provider_name(struct bt_ccp_server_bearer *bearer, const char *name);

/**
* @brief Get the bearer provider name.
*
* @param[in] bearer The bearer to get the name for.
* @param[out] name Pointer that will be updated to be the bearer provider name.
*
* @retval 0 Success
* @retval -EINVAL @p bearer or @p name is NULL
* @retval -EFAULT @p bearer is not registered
*/
int bt_ccp_server_get_bearer_provider_name(struct bt_ccp_server_bearer *bearer, const char **name);

/** @} */ /* End of group bt_ccp_server */

/**
Expand Down
7 changes: 7 additions & 0 deletions subsys/bluetooth/audio/Kconfig.ccp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ config BT_CCP_SERVER_BEARER_COUNT
help
The number of supported telephone bearers on the CCP Server

config BT_CCP_SERVER_PROVIDER_NAME_MAX_LENGTH
int "The maximum length of the bearer provider name excluding null terminator"
default BT_TBS_MAX_PROVIDER_NAME_LENGTH
range 1 BT_TBS_MAX_PROVIDER_NAME_LENGTH
help
Sets the maximum length of the bearer provider name.

module = BT_CCP_SERVER
module-str = "Call Control Profile Server"
source "subsys/logging/Kconfig.template.log_config"
Expand Down
2 changes: 1 addition & 1 deletion subsys/bluetooth/audio/Kconfig.tbs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ config BT_TBS_MAX_URI_LENGTH
config BT_TBS_MAX_PROVIDER_NAME_LENGTH
int "The maximum length of the bearer provider name"
default 30
range 0 512
range 1 512
help
Sets the maximum length of the bearer provider name.

Expand Down
67 changes: 67 additions & 0 deletions subsys/bluetooth/audio/ccp_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <errno.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>

#include <zephyr/autoconf.h>
#include <zephyr/bluetooth/audio/tbs.h>
Expand All @@ -19,6 +20,7 @@ LOG_MODULE_REGISTER(bt_ccp_server, CONFIG_BT_CCP_SERVER_LOG_LEVEL);

/* A service instance can either be a GTBS or a TBS instance */
struct bt_ccp_server_bearer {
char provider_name[CONFIG_BT_CCP_SERVER_PROVIDER_NAME_MAX_LENGTH + 1];
uint8_t tbs_index;
bool registered;
};
Expand Down Expand Up @@ -68,6 +70,8 @@ int bt_ccp_server_register_bearer(const struct bt_tbs_register_param *param,

free_bearer->registered = true;
free_bearer->tbs_index = (uint8_t)ret;
(void)utf8_lcpy(free_bearer->provider_name, param->provider_name,
sizeof(free_bearer->provider_name));
*bearer = free_bearer;

return 0;
Expand Down Expand Up @@ -103,3 +107,66 @@ int bt_ccp_server_unregister_bearer(struct bt_ccp_server_bearer *bearer)

return 0;
}

int bt_ccp_server_set_bearer_provider_name(struct bt_ccp_server_bearer *bearer, const char *name)
{
size_t len;

CHECKIF(bearer == NULL) {
LOG_DBG("bearer is NULL");

return -EINVAL;
}

CHECKIF(name == NULL) {
LOG_DBG("name is NULL");

return -EINVAL;
}

if (!bearer->registered) {
LOG_DBG("Bearer %p not registered", bearer);

return -EFAULT;
}

len = strlen(name);
if (len > CONFIG_BT_CCP_SERVER_PROVIDER_NAME_MAX_LENGTH || len == 0) {
LOG_DBG("Invalid name length: %zu", len);

return -EINVAL;
}

if (strcmp(bearer->provider_name, name) == 0) {
return 0;
}

(void)utf8_lcpy(bearer->provider_name, name, sizeof(bearer->provider_name));

return bt_tbs_set_bearer_provider_name(bearer->tbs_index, name);
}

int bt_ccp_server_get_bearer_provider_name(struct bt_ccp_server_bearer *bearer, const char **name)
{
CHECKIF(bearer == NULL) {
LOG_DBG("bearer is NULL");

return -EINVAL;
}

CHECKIF(name == NULL) {
LOG_DBG("name is NULL");

return -EINVAL;
}

if (!bearer->registered) {
LOG_DBG("Bearer %p not registered", bearer);

return -EFAULT;
}

*name = bearer->provider_name;

return 0;
}
4 changes: 4 additions & 0 deletions subsys/bluetooth/audio/tbs.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ LOG_MODULE_REGISTER(bt_tbs, CONFIG_BT_TBS_LOG_LEVEL);
/* A service instance can either be a GTBS or a TBS instance */
struct tbs_inst {
/* Attribute values */
/* TODO: The provider name should be removed from the tbs_inst and instead by stored by the
* user of TBS. This will be done once the CCP API is complete as the CCP Server will own
* all the data instead of the TBS
*/
char provider_name[CONFIG_BT_TBS_MAX_PROVIDER_NAME_LENGTH];
char uci[BT_TBS_MAX_UCI_SIZE];
uint8_t technology;
Expand Down
134 changes: 133 additions & 1 deletion tests/bluetooth/audio/ccp_server/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@

DEFINE_FFF_GLOBALS;

#define DEFAULT_BEARER_NAME "test"

struct ccp_server_test_suite_fixture {
/** Need 1 additional bearer than the max to trigger some corner cases */
struct bt_ccp_server_bearer *bearers[CONFIG_BT_CCP_SERVER_BEARER_COUNT + 1];
Expand Down Expand Up @@ -78,7 +80,7 @@ ZTEST_SUITE(ccp_server_test_suite, NULL, ccp_server_test_suite_setup, ccp_server
static void register_default_bearer(struct ccp_server_test_suite_fixture *fixture)
{
const struct bt_tbs_register_param register_param = {
.provider_name = "test",
.provider_name = DEFAULT_BEARER_NAME,
.uci = "un999",
.uri_schemes_supported = "tel",
.gtbs = true,
Expand Down Expand Up @@ -249,3 +251,133 @@ static ZTEST_F(ccp_server_test_suite, test_ccp_server_unregister_bearer_inval_nu
err = bt_ccp_server_unregister_bearer(NULL);
zassert_equal(err, -EINVAL, "Unexpected return value %d", err);
}

static ZTEST_F(ccp_server_test_suite, test_bt_ccp_server_set_bearer_provider_name)
{
const char *new_bearer_name = "New bearer name";
const char *res_bearer_name;
int err;

register_default_bearer(fixture);

err = bt_ccp_server_set_bearer_provider_name(fixture->bearers[0], new_bearer_name);
zassert_equal(err, 0, "Unexpected return value %d", err);

err = bt_ccp_server_get_bearer_provider_name(fixture->bearers[0], &res_bearer_name);
zassert_equal(err, 0, "Unexpected return value %d", err);

zassert_str_equal(new_bearer_name, res_bearer_name, "%s != %s", new_bearer_name,
res_bearer_name);
}

static ZTEST_F(ccp_server_test_suite,
test_bt_ccp_server_set_bearer_provider_name_inval_not_registered)
{
const char *new_bearer_name = "New bearer name";
int err;

/* Register and unregister bearer to get a valid pointer but where it is unregistered*/
register_default_bearer(fixture);
err = bt_ccp_server_unregister_bearer(fixture->bearers[0]);
zassert_equal(err, 0, "Unexpected return value %d", err);

err = bt_ccp_server_set_bearer_provider_name(fixture->bearers[0], new_bearer_name);
zassert_equal(err, -EFAULT, "Unexpected return value %d", err);
}

static ZTEST_F(ccp_server_test_suite, test_bt_ccp_server_set_bearer_provider_name_inval_null_bearer)
{
const char *new_bearer_name = "New bearer name";
int err;

register_default_bearer(fixture);

err = bt_ccp_server_set_bearer_provider_name(NULL, new_bearer_name);
zassert_equal(err, -EINVAL, "Unexpected return value %d", err);
}

static ZTEST_F(ccp_server_test_suite, test_bt_ccp_server_set_bearer_provider_name_inval_null_name)
{
int err;

register_default_bearer(fixture);

err = bt_ccp_server_set_bearer_provider_name(fixture->bearers[0], NULL);
zassert_equal(err, -EINVAL, "Unexpected return value %d", err);
}

static ZTEST_F(ccp_server_test_suite, test_bt_ccp_server_set_bearer_provider_name_inval_empty_name)
{
const char *inval_bearer_name = "";
int err;

register_default_bearer(fixture);

err = bt_ccp_server_set_bearer_provider_name(fixture->bearers[0], inval_bearer_name);
zassert_equal(err, -EINVAL, "Unexpected return value %d", err);
}

static ZTEST_F(ccp_server_test_suite, test_bt_ccp_server_set_bearer_provider_name_inval_long_name)
{
char inval_bearer_name[CONFIG_BT_CCP_SERVER_PROVIDER_NAME_MAX_LENGTH + 1];
int err;

for (size_t i = 0; i < ARRAY_SIZE(inval_bearer_name); i++) {
inval_bearer_name[i] = 'a';
}

register_default_bearer(fixture);

err = bt_ccp_server_set_bearer_provider_name(fixture->bearers[0], inval_bearer_name);
zassert_equal(err, -EINVAL, "Unexpected return value %d", err);
}

static ZTEST_F(ccp_server_test_suite, test_bt_ccp_server_get_bearer_provider_name)
{
const char *res_bearer_name;
int err;

register_default_bearer(fixture);

err = bt_ccp_server_get_bearer_provider_name(fixture->bearers[0], &res_bearer_name);
zassert_equal(err, 0, "Unexpected return value %d", err);

zassert_str_equal(DEFAULT_BEARER_NAME, res_bearer_name, "%s != %s", DEFAULT_BEARER_NAME,
res_bearer_name);
}

static ZTEST_F(ccp_server_test_suite,
test_bt_ccp_server_get_bearer_provider_name_inval_not_registered)
{
const char *res_bearer_name;
int err;

/* Register and unregister bearer to get a valid pointer but where it is unregistered*/
register_default_bearer(fixture);
err = bt_ccp_server_unregister_bearer(fixture->bearers[0]);
zassert_equal(err, 0, "Unexpected return value %d", err);

err = bt_ccp_server_get_bearer_provider_name(fixture->bearers[0], &res_bearer_name);
zassert_equal(err, -EFAULT, "Unexpected return value %d", err);
}

static ZTEST_F(ccp_server_test_suite, test_bt_ccp_server_get_bearer_provider_name_inval_null_bearer)
{
const char *res_bearer_name;
int err;

register_default_bearer(fixture);

err = bt_ccp_server_get_bearer_provider_name(NULL, &res_bearer_name);
zassert_equal(err, -EINVAL, "Unexpected return value %d", err);
}

static ZTEST_F(ccp_server_test_suite, test_bt_ccp_server_get_bearer_provider_name_inval_null_name)
{
int err;

register_default_bearer(fixture);

err = bt_ccp_server_get_bearer_provider_name(fixture->bearers[0], NULL);
zassert_equal(err, -EINVAL, "Unexpected return value %d", err);
}

0 comments on commit a568ef4

Please sign in to comment.