blob: bd58dea341cd71c58dbfed593380d240840e6a65 [file] [log] [blame]
/* btp_ccp.c - Bluetooth CCP Tester */
/*
* Copyright (c) 2023 Oticon
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "btp/btp.h"
#include "zephyr/sys/byteorder.h"
#include <stdint.h>
#include <../../subsys/bluetooth/audio/tbs_internal.h>
#include <zephyr/logging/log.h>
#define LOG_MODULE_NAME bttester_ccp
LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL);
struct btp_ccp_chrc_handles_ev tbs_handles;
struct bt_tbs_instance *tbs_inst;
static uint8_t call_index;
static uint8_t inst_ccid;
static bool send_ev;
static uint8_t ccp_supported_commands(const void *cmd, uint16_t cmd_len,
void *rsp, uint16_t *rsp_len)
{
struct btp_ccp_read_supported_commands_rp *rp = rsp;
/* octet 0 */
tester_set_bit(rp->data, BTP_CCP_READ_SUPPORTED_COMMANDS);
tester_set_bit(rp->data, BTP_CCP_DISCOVER_TBS);
tester_set_bit(rp->data, BTP_CCP_ACCEPT_CALL);
tester_set_bit(rp->data, BTP_CCP_TERMINATE_CALL);
tester_set_bit(rp->data, BTP_CCP_ORIGINATE_CALL);
tester_set_bit(rp->data, BTP_CCP_READ_CALL_STATE);
tester_set_bit(rp->data, BTP_CCP_READ_BEARER_NAME);
/* octet 1 */
tester_set_bit(rp->data, BTP_CCP_READ_BEARER_UCI);
tester_set_bit(rp->data, BTP_CCP_READ_BEARER_TECH);
tester_set_bit(rp->data, BTP_CCP_READ_URI_LIST);
tester_set_bit(rp->data, BTP_CCP_READ_SIGNAL_STRENGTH);
tester_set_bit(rp->data, BTP_CCP_READ_SIGNAL_INTERVAL);
tester_set_bit(rp->data, BTP_CCP_READ_CURRENT_CALLS);
tester_set_bit(rp->data, BTP_CCP_READ_CCID);
/* octet 2 */
tester_set_bit(rp->data, BTP_CCP_READ_CALL_URI);
tester_set_bit(rp->data, BTP_CCP_READ_STATUS_FLAGS);
tester_set_bit(rp->data, BTP_CCP_READ_OPTIONAL_OPCODES);
tester_set_bit(rp->data, BTP_CCP_READ_FRIENDLY_NAME);
tester_set_bit(rp->data, BTP_CCP_READ_REMOTE_URI);
tester_set_bit(rp->data, BTP_CCP_SET_SIGNAL_INTERVAL);
tester_set_bit(rp->data, BTP_CCP_HOLD_CALL);
/* octet 3 */
tester_set_bit(rp->data, BTP_CCP_RETRIEVE_CALL);
tester_set_bit(rp->data, BTP_CCP_JOIN_CALLS);
*rsp_len = sizeof(*rp) + 1;
return BTP_STATUS_SUCCESS;
}
static void tbs_client_discovered_ev(int err, uint8_t tbs_count, bool gtbs_found)
{
struct btp_ccp_discovered_ev ev;
ev.status = sys_cpu_to_le32(err);
ev.tbs_count = tbs_count;
ev.gtbs_found = gtbs_found;
tester_event(BTP_SERVICE_ID_CCP, BTP_CCP_EV_DISCOVERED, &ev, sizeof(ev));
}
static void tbs_chrc_handles_ev(struct btp_ccp_chrc_handles_ev *tbs_handles)
{
struct btp_ccp_chrc_handles_ev ev;
ev.provider_name = sys_cpu_to_le16(tbs_handles->provider_name);
ev.bearer_uci = sys_cpu_to_le16(tbs_handles->bearer_uci);
ev.bearer_technology = sys_cpu_to_le16(tbs_handles->bearer_technology);
ev.uri_list = sys_cpu_to_le16(tbs_handles->uri_list);
ev.signal_strength = sys_cpu_to_le16(tbs_handles->signal_strength);
ev.signal_interval = sys_cpu_to_le16(tbs_handles->signal_interval);
ev.current_calls = sys_cpu_to_le16(tbs_handles->current_calls);
ev.ccid = sys_cpu_to_le16(tbs_handles->ccid);
ev.status_flags = sys_cpu_to_le16(tbs_handles->status_flags);
ev.bearer_uri = sys_cpu_to_le16(tbs_handles->bearer_uri);
ev.call_state = sys_cpu_to_le16(tbs_handles->call_state);
ev.control_point = sys_cpu_to_le16(tbs_handles->control_point);
ev.optional_opcodes = sys_cpu_to_le16(tbs_handles->optional_opcodes);
ev.termination_reason = sys_cpu_to_le16(tbs_handles->termination_reason);
ev.incoming_call = sys_cpu_to_le16(tbs_handles->incoming_call);
ev.friendly_name = sys_cpu_to_le16(tbs_handles->friendly_name);
tester_event(BTP_SERVICE_ID_CCP, BTP_CCP_EV_CHRC_HANDLES, &ev, sizeof(ev));
}
static void tbs_client_chrc_val_ev(struct bt_conn *conn, uint8_t status, uint8_t inst_index,
uint32_t value)
{
struct btp_ccp_chrc_val_ev ev;
bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
ev.status = status;
ev.inst_index = inst_index;
ev.value = value;
tester_event(BTP_SERVICE_ID_CCP, BTP_CCP_EV_CHRC_VAL, &ev, sizeof(ev));
}
static void tbs_client_chrc_str_ev(struct bt_conn *conn, uint8_t status, uint8_t inst_index,
uint8_t data_len, const char *data)
{
struct btp_ccp_chrc_str_ev *ev;
tester_rsp_buffer_lock();
tester_rsp_buffer_allocate(sizeof(*ev) + data_len, (uint8_t **)&ev);
bt_addr_le_copy(&ev->address, bt_conn_get_dst(conn));
ev->status = status;
ev->inst_index = inst_index;
ev->data_len = data_len;
memcpy(ev->data, data, data_len);
tester_event(BTP_SERVICE_ID_CCP, BTP_CCP_EV_CHRC_STR, ev, sizeof(*ev) + data_len);
tester_rsp_buffer_free();
tester_rsp_buffer_unlock();
}
static void tbs_client_cp_ev(struct bt_conn *conn, uint8_t status)
{
struct btp_ccp_cp_ev ev;
bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
ev.status = status;
tester_event(BTP_SERVICE_ID_CCP, BTP_CCP_EV_CP, &ev, sizeof(ev));
}
static void tbs_client_current_calls_ev(struct bt_conn *conn, uint8_t status)
{
struct btp_ccp_current_calls_ev ev;
bt_addr_le_copy(&ev.address, bt_conn_get_dst(conn));
ev.status = status;
tester_event(BTP_SERVICE_ID_CCP, BTP_CCP_EV_CURRENT_CALLS, &ev, sizeof(ev));
}
static void tbs_client_discover_cb(struct bt_conn *conn, int err, uint8_t tbs_count,
bool gtbs_found)
{
if (err) {
LOG_DBG("Discovery Failed (%d)", err);
return;
}
LOG_DBG("Discovered TBS - err (%u) GTBS (%u)", err, gtbs_found);
bt_tbs_client_read_ccid(conn, 0xFF);
tbs_client_discovered_ev(err, tbs_count, gtbs_found);
send_ev = true;
}
typedef struct bt_tbs_client_call_state bt_tbs_client_call_state_t;
#define CALL_STATES_EV_SIZE sizeof(struct btp_ccp_call_states_ev) + \
sizeof(bt_tbs_client_call_state_t) * \
CONFIG_BT_TBS_CLIENT_MAX_CALLS
static void tbs_client_call_states_ev(int err,
uint8_t inst_index,
uint8_t call_count,
const bt_tbs_client_call_state_t *call_states)
{
struct net_buf_simple *buf = NET_BUF_SIMPLE(CALL_STATES_EV_SIZE);
struct btp_ccp_call_states_ev ev = {
sys_cpu_to_le32(err), inst_index, call_count
};
net_buf_simple_init(buf, 0);
net_buf_simple_add_mem(buf, &ev, sizeof(ev));
for (uint8_t n = 0; n < call_count; n++, call_states++) {
net_buf_simple_add_mem(buf, call_states, sizeof(bt_tbs_client_call_state_t));
}
tester_event(BTP_SERVICE_ID_CCP, BTP_CCP_EV_CALL_STATES, buf->data, buf->len);
}
static void tbs_client_call_states_cb(struct bt_conn *conn,
int err,
uint8_t inst_index,
uint8_t call_count,
const bt_tbs_client_call_state_t *call_states)
{
LOG_DBG("Call states - err (%u) Call Count (%u)", err, call_count);
tbs_client_call_states_ev(err, inst_index, call_count, call_states);
}
static void tbs_client_termination_reason_cb(struct bt_conn *conn,
int err,
uint8_t inst_index,
uint8_t call_index,
uint8_t reason)
{
LOG_DBG("Termination reason - err (%u) Call Index (%u) Reason (%u)",
err, call_index, reason);
}
static void tbs_client_read_string_cb(struct bt_conn *conn, int err, uint8_t inst_index,
const char *value)
{
LOG_DBG("TBS Client read string characteristic value cb");
uint8_t data_len = strlen(value);
tbs_client_chrc_str_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, inst_index,
data_len, value);
}
static void tbs_client_read_val_cb(struct bt_conn *conn, int err, uint8_t inst_index,
uint32_t value)
{
LOG_DBG("TBS Client read characteristic value cb");
tbs_client_chrc_val_ev(conn, err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS, inst_index,
value);
if (send_ev == true) {
inst_ccid = value;
tbs_inst = bt_tbs_client_get_by_ccid(conn, inst_ccid);
tbs_handles.provider_name = tbs_inst->name_sub_params.value_handle;
tbs_handles.bearer_uci = tbs_inst->bearer_uci_handle;
tbs_handles.bearer_technology = tbs_inst->technology_sub_params.value_handle;
tbs_handles.uri_list = tbs_inst->uri_list_handle;
tbs_handles.signal_strength = tbs_inst->signal_strength_sub_params.value_handle;
tbs_handles.signal_interval = tbs_inst->signal_interval_handle;
tbs_handles.current_calls = tbs_inst->current_calls_sub_params.value_handle;
tbs_handles.ccid = tbs_inst->ccid_handle;
tbs_handles.status_flags = tbs_inst->status_flags_sub_params.value_handle;
tbs_handles.bearer_uri = tbs_inst->in_target_uri_sub_params.value_handle;
tbs_handles.call_state = tbs_inst->call_state_sub_params.value_handle;
tbs_handles.control_point = tbs_inst->call_cp_sub_params.value_handle;
tbs_handles.optional_opcodes = tbs_inst->optional_opcodes_handle;
tbs_handles.termination_reason = tbs_inst->termination_reason_handle;
tbs_handles.incoming_call = tbs_inst->incoming_call_sub_params.value_handle;
tbs_handles.friendly_name = tbs_inst->friendly_name_sub_params.value_handle;
tbs_chrc_handles_ev(&tbs_handles);
send_ev = false;
}
}
static void tbs_client_current_calls_cb(struct bt_conn *conn, int err, uint8_t inst_index,
uint8_t call_count, const struct bt_tbs_client_call *calls)
{
LOG_DBG("");
tbs_client_current_calls_ev(conn, err);
}
static void tbs_client_cp_cb(struct bt_conn *conn, int err, uint8_t inst_index, uint8_t call_index)
{
LOG_DBG("");
tbs_client_cp_ev(conn, err);
}
static const struct bt_tbs_client_cb tbs_client_callbacks = {
.discover = tbs_client_discover_cb,
.originate_call = tbs_client_cp_cb,
.terminate_call = tbs_client_cp_cb,
.call_state = tbs_client_call_states_cb,
.termination_reason = tbs_client_termination_reason_cb,
.bearer_provider_name = tbs_client_read_string_cb,
.bearer_uci = tbs_client_read_string_cb,
.technology = tbs_client_read_val_cb,
.uri_list = tbs_client_read_string_cb,
.signal_strength = tbs_client_read_val_cb,
.signal_interval = tbs_client_read_val_cb,
.current_calls = tbs_client_current_calls_cb,
.ccid = tbs_client_read_val_cb,
.call_uri = tbs_client_read_string_cb,
.status_flags = tbs_client_read_val_cb,
.optional_opcodes = tbs_client_read_val_cb,
.friendly_name = tbs_client_read_string_cb,
.remote_uri = tbs_client_read_string_cb,
.accept_call = tbs_client_cp_cb,
.hold_call = tbs_client_cp_cb,
.retrieve_call = tbs_client_cp_cb,
.join_calls = tbs_client_cp_cb,
};
static uint8_t ccp_discover_tbs(const void *cmd, uint16_t cmd_len,
void *rsp, uint16_t *rsp_len)
{
const struct btp_ccp_discover_tbs_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
err = (conn) ? bt_tbs_client_discover(conn) : -ENOTCONN;
if (conn) {
bt_conn_unref(conn);
}
return BTP_STATUS_VAL(err);
}
static uint8_t ccp_accept_call(const void *cmd, uint16_t cmd_len,
void *rsp, uint16_t *rsp_len)
{
const struct btp_ccp_accept_call_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
err = (conn) ? bt_tbs_client_accept_call(conn, cp->inst_index, cp->call_id) : -ENOTCONN;
if (conn) {
bt_conn_unref(conn);
}
return BTP_STATUS_VAL(err);
}
static uint8_t ccp_terminate_call(const void *cmd, uint16_t cmd_len,
void *rsp, uint16_t *rsp_len)
{
const struct btp_ccp_terminate_call_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
err = (conn) ? bt_tbs_client_terminate_call(conn, cp->inst_index, cp->call_id) :
-ENOTCONN;
if (conn) {
bt_conn_unref(conn);
}
return BTP_STATUS_VAL(err);
}
static uint8_t ccp_originate_call(const void *cmd, uint16_t cmd_len,
void *rsp, uint16_t *rsp_len)
{
const struct btp_ccp_originate_call_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
err = (conn) ? bt_tbs_client_originate_call(conn, cp->inst_index, cp->uri) : -ENOTCONN;
if (conn) {
bt_conn_unref(conn);
}
return BTP_STATUS_VAL(err);
}
static uint8_t ccp_read_call_state(const void *cmd, uint16_t cmd_len,
void *rsp, uint16_t *rsp_len)
{
const struct btp_ccp_read_call_state_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
err = (conn) ? bt_tbs_client_read_call_state(conn, cp->inst_index) : -ENOTCONN;
if (conn) {
bt_conn_unref(conn);
}
return BTP_STATUS_VAL(err);
}
static uint8_t ccp_read_bearer_name(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
const struct btp_ccp_read_bearer_name_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
if (!conn) {
LOG_ERR("Unknown connection");
return BTP_STATUS_FAILED;
}
err = bt_tbs_client_read_bearer_provider_name(conn, cp->inst_index);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t ccp_read_bearer_uci(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
const struct btp_ccp_read_bearer_uci_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
if (!conn) {
LOG_ERR("Unknown connection");
return BTP_STATUS_FAILED;
}
err = bt_tbs_client_read_bearer_uci(conn, cp->inst_index);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t ccp_read_bearer_tech(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
const struct btp_ccp_read_bearer_technology_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
if (!conn) {
LOG_ERR("Unknown connection");
return BTP_STATUS_FAILED;
}
err = bt_tbs_client_read_technology(conn, cp->inst_index);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t ccp_read_uri_list(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
const struct btp_ccp_read_uri_list_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
if (!conn) {
LOG_ERR("Unknown connection");
return BTP_STATUS_FAILED;
}
err = bt_tbs_client_read_uri_list(conn, cp->inst_index);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t ccp_read_signal_strength(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
const struct btp_ccp_read_signal_strength_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
if (!conn) {
LOG_ERR("Unknown connection");
return BTP_STATUS_FAILED;
}
err = bt_tbs_client_read_signal_strength(conn, cp->inst_index);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t ccp_read_signal_interval(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
const struct btp_ccp_read_signal_interval_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
if (!conn) {
LOG_ERR("Unknown connection");
return BTP_STATUS_FAILED;
}
err = bt_tbs_client_read_signal_interval(conn, cp->inst_index);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t ccp_read_current_calls(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
const struct btp_ccp_read_current_calls_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
if (!conn) {
LOG_ERR("Unknown connection");
return BTP_STATUS_FAILED;
}
err = bt_tbs_client_read_current_calls(conn, cp->inst_index);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t ccp_read_ccid(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
const struct btp_ccp_read_ccid_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
if (!conn) {
LOG_ERR("Unknown connection");
return BTP_STATUS_FAILED;
}
err = bt_tbs_client_read_ccid(conn, cp->inst_index);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t ccp_read_call_uri(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
const struct btp_ccp_read_call_uri_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
if (!conn) {
LOG_ERR("Unknown connection");
return BTP_STATUS_FAILED;
}
err = bt_tbs_client_read_call_uri(conn, cp->inst_index);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t ccp_read_status_flags(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
const struct btp_ccp_read_status_flags_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
if (!conn) {
LOG_ERR("Unknown connection");
return BTP_STATUS_FAILED;
}
err = bt_tbs_client_read_status_flags(conn, cp->inst_index);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t ccp_read_optional_opcodes(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
const struct btp_ccp_read_optional_opcodes_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
if (!conn) {
LOG_ERR("Unknown connection");
return BTP_STATUS_FAILED;
}
err = bt_tbs_client_read_optional_opcodes(conn, cp->inst_index);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t ccp_read_friendly_name(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
const struct btp_ccp_read_friendly_name_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
if (!conn) {
LOG_ERR("Unknown connection");
return BTP_STATUS_FAILED;
}
err = bt_tbs_client_read_friendly_name(conn, cp->inst_index);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t ccp_read_remote_uri(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
const struct btp_ccp_read_remote_uri_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
if (!conn) {
LOG_ERR("Unknown connection");
return BTP_STATUS_FAILED;
}
err = bt_tbs_client_read_remote_uri(conn, cp->inst_index);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t ccp_set_signal_interval(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
const struct btp_ccp_set_signal_interval_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
if (!conn) {
LOG_ERR("Unknown connection");
return BTP_STATUS_FAILED;
}
err = bt_tbs_client_set_signal_strength_interval(conn, cp->inst_index, cp->interval);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t ccp_hold_call(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
const struct btp_ccp_hold_call_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
if (!conn) {
LOG_ERR("Unknown connection");
return BTP_STATUS_FAILED;
}
err = bt_tbs_client_hold_call(conn, cp->inst_index, cp->call_id);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t ccp_retrieve_call(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
const struct btp_ccp_retrieve_call_cmd *cp = cmd;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
if (!conn) {
LOG_ERR("Unknown connection");
return BTP_STATUS_FAILED;
}
err = bt_tbs_client_retrieve_call(conn, cp->inst_index, cp->call_id);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t ccp_join_calls(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
const struct btp_ccp_join_calls_cmd *cp = cmd;
const uint8_t *call_index;
struct bt_conn *conn;
int err;
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address);
if (!conn) {
LOG_ERR("Unknown connection");
return BTP_STATUS_FAILED;
}
call_index = cp->call_index;
err = bt_tbs_client_join_calls(conn, cp->inst_index, call_index, cp->count);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static const struct btp_handler ccp_handlers[] = {
{
.opcode = BTP_CCP_READ_SUPPORTED_COMMANDS,
.index = BTP_INDEX_NONE,
.expect_len = 0,
.func = ccp_supported_commands
},
{
.opcode = BTP_CCP_DISCOVER_TBS,
.expect_len = sizeof(struct btp_ccp_discover_tbs_cmd),
.func = ccp_discover_tbs
},
{
.opcode = BTP_CCP_ACCEPT_CALL,
.expect_len = sizeof(struct btp_ccp_accept_call_cmd),
.func = ccp_accept_call
},
{
.opcode = BTP_CCP_TERMINATE_CALL,
.expect_len = sizeof(struct btp_ccp_terminate_call_cmd),
.func = ccp_terminate_call
},
{
.opcode = BTP_CCP_ORIGINATE_CALL,
.expect_len = BTP_HANDLER_LENGTH_VARIABLE,
.func = ccp_originate_call
},
{
.opcode = BTP_CCP_READ_CALL_STATE,
.expect_len = sizeof(struct btp_ccp_read_call_state_cmd),
.func = ccp_read_call_state
},
{
.opcode = BTP_CCP_READ_BEARER_NAME,
.expect_len = sizeof(struct btp_ccp_read_bearer_name_cmd),
.func = ccp_read_bearer_name
},
{
.opcode = BTP_CCP_READ_BEARER_UCI,
.expect_len = sizeof(struct btp_ccp_read_bearer_uci_cmd),
.func = ccp_read_bearer_uci
},
{
.opcode = BTP_CCP_READ_BEARER_TECH,
.expect_len = sizeof(struct btp_ccp_read_bearer_technology_cmd),
.func = ccp_read_bearer_tech
},
{
.opcode = BTP_CCP_READ_URI_LIST,
.expect_len = sizeof(struct btp_ccp_read_uri_list_cmd),
.func = ccp_read_uri_list
},
{
.opcode = BTP_CCP_READ_SIGNAL_STRENGTH,
.expect_len = sizeof(struct btp_ccp_read_signal_strength_cmd),
.func = ccp_read_signal_strength
},
{
.opcode = BTP_CCP_READ_SIGNAL_INTERVAL,
.expect_len = sizeof(struct btp_ccp_read_signal_interval_cmd),
.func = ccp_read_signal_interval
},
{
.opcode = BTP_CCP_READ_CURRENT_CALLS,
.expect_len = sizeof(struct btp_ccp_read_current_calls_cmd),
.func = ccp_read_current_calls
},
{
.opcode = BTP_CCP_READ_CCID,
.expect_len = sizeof(struct btp_ccp_read_ccid_cmd),
.func = ccp_read_ccid
},
{
.opcode = BTP_CCP_READ_CALL_URI,
.expect_len = sizeof(struct btp_ccp_read_call_uri_cmd),
.func = ccp_read_call_uri
},
{
.opcode = BTP_CCP_READ_STATUS_FLAGS,
.expect_len = sizeof(struct btp_ccp_read_status_flags_cmd),
.func = ccp_read_status_flags
},
{
.opcode = BTP_CCP_READ_OPTIONAL_OPCODES,
.expect_len = sizeof(struct btp_ccp_read_optional_opcodes_cmd),
.func = ccp_read_optional_opcodes
},
{
.opcode = BTP_CCP_READ_FRIENDLY_NAME,
.expect_len = sizeof(struct btp_ccp_read_friendly_name_cmd),
.func = ccp_read_friendly_name
},
{
.opcode = BTP_CCP_READ_REMOTE_URI,
.expect_len = sizeof(struct btp_ccp_read_remote_uri_cmd),
.func = ccp_read_remote_uri
},
{
.opcode = BTP_CCP_SET_SIGNAL_INTERVAL,
.expect_len = sizeof(struct btp_ccp_set_signal_interval_cmd),
.func = ccp_set_signal_interval
},
{
.opcode = BTP_CCP_HOLD_CALL,
.expect_len = sizeof(struct btp_ccp_hold_call_cmd),
.func = ccp_hold_call
},
{
.opcode = BTP_CCP_RETRIEVE_CALL,
.expect_len = sizeof(struct btp_ccp_retrieve_call_cmd),
.func = ccp_retrieve_call
},
{
.opcode = BTP_CCP_JOIN_CALLS,
.expect_len = BTP_HANDLER_LENGTH_VARIABLE,
.func = ccp_join_calls
},
};
uint8_t tester_init_ccp(void)
{
tester_register_command_handlers(BTP_SERVICE_ID_CCP, ccp_handlers,
ARRAY_SIZE(ccp_handlers));
bt_tbs_client_register_cb(&tbs_client_callbacks);
return BTP_STATUS_SUCCESS;
}
uint8_t tester_unregister_ccp(void)
{
return BTP_STATUS_SUCCESS;
}
/* Telephone Bearer Service */
static uint8_t tbs_supported_commands(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
struct btp_tbs_read_supported_commands_rp *rp = rsp;
/* octet 0 */
tester_set_bit(rp->data, BTP_TBS_READ_SUPPORTED_COMMANDS);
tester_set_bit(rp->data, BTP_TBS_REMOTE_INCOMING);
tester_set_bit(rp->data, BTP_TBS_HOLD);
tester_set_bit(rp->data, BTP_TBS_SET_BEARER_NAME);
tester_set_bit(rp->data, BTP_TBS_SET_TECHNOLOGY);
tester_set_bit(rp->data, BTP_TBS_SET_URI_SCHEME);
tester_set_bit(rp->data, BTP_TBS_SET_STATUS_FLAGS);
/* octet 1 */
tester_set_bit(rp->data, BTP_TBS_REMOTE_HOLD);
tester_set_bit(rp->data, BTP_TBS_ORIGINATE);
tester_set_bit(rp->data, BTP_TBS_SET_SIGNAL_STRENGTH);
*rsp_len = sizeof(*rp) + 2;
return BTP_STATUS_SUCCESS;
}
static uint8_t tbs_remote_incoming(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
const struct btp_tbs_remote_incoming_cmd *cp = cmd;
char friendly_name[CONFIG_BT_TBS_MAX_URI_LENGTH];
char caller_uri[CONFIG_BT_TBS_MAX_URI_LENGTH];
char recv_uri[CONFIG_BT_TBS_MAX_URI_LENGTH];
int err;
LOG_DBG("");
if ((cp->recv_len >= sizeof(recv_uri) || cp->caller_len >= sizeof(caller_uri)) ||
cp->fn_len >= sizeof(friendly_name)) {
return BTP_STATUS_FAILED;
}
memcpy(recv_uri, cp->data, cp->recv_len);
memcpy(caller_uri, cp->data + cp->recv_len, cp->caller_len);
memcpy(friendly_name, cp->data + cp->recv_len + cp->caller_len, cp->fn_len);
recv_uri[cp->recv_len] = '\0';
caller_uri[cp->caller_len] = '\0';
friendly_name[cp->fn_len] = '\0';
err = bt_tbs_remote_incoming(cp->index, recv_uri, caller_uri, friendly_name);
if (err < 0) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t tbs_originate(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
const struct btp_tbs_originate_cmd *cp = cmd;
char uri[CONFIG_BT_TBS_MAX_URI_LENGTH];
int err;
LOG_DBG("TBS Originate Call");
if (cp->uri_len >= sizeof(uri)) {
return BTP_STATUS_FAILED;
}
memcpy(uri, cp->uri, cp->uri_len);
uri[cp->uri_len] = '\0';
err = bt_tbs_originate(cp->index, uri, &call_index);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t tbs_hold(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
const struct btp_tbs_hold_cmd *cp = cmd;
int err;
LOG_DBG("TBS Hold Call");
err = bt_tbs_hold(cp->index);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t tbs_remote_hold(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
const struct btp_tbs_remote_hold_cmd *cp = cmd;
int err;
LOG_DBG("TBS Remote Hold Call");
err = bt_tbs_remote_hold(cp->index);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t tbs_set_bearer_name(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len)
{
const struct btp_tbs_set_bearer_name_cmd *cp = cmd;
char bearer_name[CONFIG_BT_TBS_MAX_PROVIDER_NAME_LENGTH];
int err;
LOG_DBG("TBS Set Bearer Provider Name");
if (cp->name_len >= sizeof(bearer_name)) {
return BTP_STATUS_FAILED;
}
memcpy(bearer_name, cp->name, cp->name_len);
bearer_name[cp->name_len] = '\0';
err = bt_tbs_set_bearer_provider_name(cp->index, bearer_name);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t tbs_set_bearer_technology(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
const struct btp_tbs_set_technology_cmd *cp = cmd;
int err;
LOG_DBG("TBS Set bearer technology");
err = bt_tbs_set_bearer_technology(cp->index, cp->tech);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t tbs_set_uri_scheme_list(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
const struct btp_tbs_set_uri_schemes_list_cmd *cp = cmd;
char uri_list[CONFIG_BT_TBS_MAX_SCHEME_LIST_LENGTH];
char *uri_ptr = (char *)&uri_list;
int err;
LOG_DBG("TBS Set Uri Scheme list");
if (cp->uri_len >= sizeof(uri_list)) {
return BTP_STATUS_FAILED;
}
memcpy(uri_list, cp->uri_list, cp->uri_len);
uri_list[cp->uri_len] = '\0';
if (cp->uri_count > 1) {
/* TODO: currently supporting only one uri*/
return BTP_STATUS_FAILED;
}
err = bt_tbs_set_uri_scheme_list(cp->index, (const char **)&uri_ptr, cp->uri_count);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t tbs_set_status_flags(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
const struct btp_tbs_set_status_flags_cmd *cp = cmd;
uint16_t flags = sys_le16_to_cpu(cp->flags);
int err;
LOG_DBG("TBS Set Status Flags");
err = bt_tbs_set_status_flags(cp->index, flags);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static uint8_t tbs_set_signal_strength(const void *cmd, uint16_t cmd_len, void *rsp,
uint16_t *rsp_len)
{
const struct btp_tbs_set_signal_strength_cmd *cp = cmd;
int err;
LOG_DBG("TBS Set Signal Strength");
err = bt_tbs_set_signal_strength(cp->index, cp->strength);
if (err) {
return BTP_STATUS_FAILED;
}
return BTP_STATUS_SUCCESS;
}
static bool btp_tbs_originate_call_cb(struct bt_conn *conn, uint8_t call_index, const char *uri)
{
LOG_DBG("TBS Originate Call cb");
return true;
}
static void btp_tbs_call_change_cb(struct bt_conn *conn, uint8_t call_index)
{
LOG_DBG("TBS Call Status Changed cb");
}
static struct bt_tbs_cb tbs_cbs = {
.originate_call = btp_tbs_originate_call_cb,
.hold_call = btp_tbs_call_change_cb,
};
static const struct btp_handler tbs_handlers[] = {
{
.opcode = BTP_TBS_READ_SUPPORTED_COMMANDS,
.index = BTP_INDEX_NONE,
.expect_len = 0,
.func = tbs_supported_commands,
},
{
.opcode = BTP_TBS_REMOTE_INCOMING,
.expect_len = BTP_HANDLER_LENGTH_VARIABLE,
.func = tbs_remote_incoming,
},
{
.opcode = BTP_TBS_HOLD,
.expect_len = sizeof(struct btp_tbs_hold_cmd),
.func = tbs_hold,
},
{
.opcode = BTP_TBS_SET_BEARER_NAME,
.expect_len = BTP_HANDLER_LENGTH_VARIABLE,
.func = tbs_set_bearer_name,
},
{
.opcode = BTP_TBS_SET_TECHNOLOGY,
.expect_len = sizeof(struct btp_tbs_set_technology_cmd),
.func = tbs_set_bearer_technology,
},
{
.opcode = BTP_TBS_SET_URI_SCHEME,
.expect_len = BTP_HANDLER_LENGTH_VARIABLE,
.func = tbs_set_uri_scheme_list,
},
{
.opcode = BTP_TBS_SET_STATUS_FLAGS,
.expect_len = sizeof(struct btp_tbs_set_status_flags_cmd),
.func = tbs_set_status_flags,
},
{
.opcode = BTP_TBS_REMOTE_HOLD,
.expect_len = sizeof(struct btp_tbs_remote_hold_cmd),
.func = tbs_remote_hold,
},
{
.opcode = BTP_TBS_ORIGINATE,
.expect_len = BTP_HANDLER_LENGTH_VARIABLE,
.func = tbs_originate,
},
{
.opcode = BTP_TBS_SET_SIGNAL_STRENGTH,
.expect_len = sizeof(struct btp_tbs_set_signal_strength_cmd),
.func = tbs_set_signal_strength,
},
};
uint8_t tester_init_tbs(void)
{
bt_tbs_register_cb(&tbs_cbs);
tester_register_command_handlers(BTP_SERVICE_ID_TBS, tbs_handlers,
ARRAY_SIZE(tbs_handlers));
return BTP_STATUS_SUCCESS;
}
uint8_t tester_unregister_tbs(void)
{
return BTP_STATUS_SUCCESS;
}