blob: c2508f846a55bfacee3e804dc6925472dce4b58c [file] [log] [blame]
/**
* Copyright (c) 2021-2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_SUBSYS_BLUETOOTH_AUDIO_CSIP_H_
#define ZEPHYR_SUBSYS_BLUETOOTH_AUDIO_CSIP_H_
/**
* @brief Coordinated Set Identification Profile (CSIP)
*
* @defgroup bt_gatt_csip Coordinated Set Identification Profile (CSIP)
*
* @ingroup bluetooth
* @{
* *
* [Experimental] Users should note that the APIs can change as a part of ongoing development.
*/
#include <zephyr/types.h>
#include <stdbool.h>
#include <zephyr/bluetooth/conn.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Recommended timer for member discovery */
#define BT_CSIP_SET_COORDINATOR_DISCOVER_TIMER_VALUE K_SECONDS(10)
#if defined(CONFIG_BT_CSIP_SET_COORDINATOR)
#define BT_CSIP_SET_COORDINATOR_MAX_CSIS_INSTANCES CONFIG_BT_CSIP_SET_COORDINATOR_MAX_CSIS_INSTANCES
#else
#define BT_CSIP_SET_COORDINATOR_MAX_CSIS_INSTANCES 0
#endif /* CONFIG_BT_CSIP_SET_COORDINATOR */
/** Accept the request to read the SIRK as plaintext */
#define BT_CSIP_READ_SIRK_REQ_RSP_ACCEPT 0x00
/** Accept the request to read the SIRK, but return encrypted SIRK */
#define BT_CSIP_READ_SIRK_REQ_RSP_ACCEPT_ENC 0x01
/** Reject the request to read the SIRK */
#define BT_CSIP_READ_SIRK_REQ_RSP_REJECT 0x02
/** SIRK is available only via an OOB procedure */
#define BT_CSIP_READ_SIRK_REQ_RSP_OOB_ONLY 0x03
/** Size of the Set Identification Resolving Key (SIRK) */
#define BT_CSIP_SET_SIRK_SIZE 16
/** Size of the Resolvable Set Identifier (RSI) */
#define BT_CSIP_RSI_SIZE 6
/* Coordinate Set Identification Service Error codes */
/** Service is already locked */
#define BT_CSIP_ERROR_LOCK_DENIED 0x80
/** Service is not locked */
#define BT_CSIP_ERROR_LOCK_RELEASE_DENIED 0x81
/** Invalid lock value */
#define BT_CSIP_ERROR_LOCK_INVAL_VALUE 0x82
/** SIRK only available out-of-band */
#define BT_CSIP_ERROR_SIRK_OOB_ONLY 0x83
/** Client is already owner of the lock */
#define BT_CSIP_ERROR_LOCK_ALREADY_GRANTED 0x84
/**
* @brief Helper to declare bt_data array including RSI
*
* This macro is mainly for creating an array of struct bt_data
* elements which is then passed to e.g. @ref bt_le_ext_adv_start().
*
* @param _rsi Pointer to the RSI value
*/
#define BT_CSIP_DATA_RSI(_rsi) BT_DATA(BT_DATA_CSIS_RSI, _rsi, BT_CSIP_RSI_SIZE)
/** @brief Opaque Coordinated Set Identification Service instance. */
struct bt_csip_set_member_svc_inst;
/** Callback structure for the Coordinated Set Identification Service */
struct bt_csip_set_member_cb {
/**
* @brief Callback whenever the lock changes on the server.
*
* @param conn The connection to the client that changed the lock.
* NULL if server changed it, either by calling
* bt_csip_set_member_lock() or by timeout.
* @param svc_inst Pointer to the Coordinated Set Identification
* Service.
* @param locked Whether the lock was locked or released.
*
*/
void (*lock_changed)(struct bt_conn *conn,
struct bt_csip_set_member_svc_inst *svc_inst,
bool locked);
/**
* @brief Request from a peer device to read the sirk.
*
* If this callback is not set, all clients will be allowed to read
* the SIRK unencrypted.
*
* @param conn The connection to the client that requested to read
* the SIRK.
* @param svc_inst Pointer to the Coordinated Set Identification
* Service.
*
* @return A BT_CSIP_READ_SIRK_REQ_RSP_* response code.
*/
uint8_t (*sirk_read_req)(struct bt_conn *conn,
struct bt_csip_set_member_svc_inst *svc_inst);
};
/** Register structure for Coordinated Set Identification Service */
struct bt_csip_set_member_register_param {
/**
* @brief Size of the set.
*
* If set to 0, the set size characteristic won't be initialized.
*/
uint8_t set_size;
/**
* @brief The unique Set Identity Resolving Key (SIRK)
*
* This shall be unique between different sets, and shall be the same
* for each set member for each set.
*/
uint8_t set_sirk[BT_CSIP_SET_SIRK_SIZE];
/**
* @brief Boolean to set whether the set is lockable by clients
*
* Setting this to false will disable the lock characteristic.
*/
bool lockable;
/**
* @brief Rank of this device in this set.
*
* If the lockable parameter is set to true, this shall be > 0 and
* <= to the set_size. If the lockable parameter is set to false, this
* may be set to 0 to disable the rank characteristic.
*/
uint8_t rank;
/** Pointer to the callback structure. */
struct bt_csip_set_member_cb *cb;
#if CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT > 1
/**
* @brief Parent service pointer
*
* Mandatory parent service pointer if this CSIS instance is included
* by another service. All CSIS instances when
* @kconfig{CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT} is above 1
* shall be included by another service, as per the
* Coordinated Set Identification Profile (CSIP).
*/
const struct bt_gatt_service *parent;
#endif /* CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT > 1 */
};
/**
* @brief Get the service declaration attribute.
*
* The first service attribute can be included in any other GATT service.
*
* @param svc_inst Pointer to the Coordinated Set Identification Service.
*
* @return The first CSIS attribute instance.
*/
void *bt_csip_set_member_svc_decl_get(const struct bt_csip_set_member_svc_inst *svc_inst);
/**
* @brief Register a Coordinated Set Identification Service instance.
*
* This will register and enable the service and make it discoverable by
* clients.
*
* This shall only be done as a server.
*
* @param param Coordinated Set Identification Service register
* parameters.
* @param[out] svc_inst Pointer to the registered Coordinated Set
* Identification Service.
*
* @return 0 if success, errno on failure.
*/
int bt_csip_set_member_register(const struct bt_csip_set_member_register_param *param,
struct bt_csip_set_member_svc_inst **svc_inst);
/**
* @brief Print the SIRK to the debug output
*
* @param svc_inst Pointer to the Coordinated Set Identification Service.
*/
void bt_csip_set_member_print_sirk(const struct bt_csip_set_member_svc_inst *svc_inst);
/**
* @brief Generate the Resolvable Set Identifier (RSI) value.
*
* This will generate RSI for given @p svc_inst instance.
*
* @param svc_inst Pointer to the Coordinated Set Identification Service.
* @param rsi Pointer to the 6-octet newly generated RSI data.
*
* @return int 0 if on success, errno on error.
*/
int bt_csip_set_member_generate_rsi(const struct bt_csip_set_member_svc_inst *svc_inst,
uint8_t rsi[BT_CSIP_RSI_SIZE]);
/**
* @brief Locks a specific Coordinated Set Identification Service instance on the server.
*
* @param svc_inst Pointer to the Coordinated Set Identification Service.
* @param lock If true lock the set, if false release the set.
* @param force This argument only have meaning when @p lock is false
* (release) and will force release the lock, regardless of who
* took the lock.
*
* @return 0 on success, GATT error on error.
*/
int bt_csip_set_member_lock(struct bt_csip_set_member_svc_inst *svc_inst,
bool lock, bool force);
/** Information about a specific set */
struct bt_csip_set_coordinator_set_info {
/**
* @brief The 16 octet set Set Identity Resolving Key (SIRK)
*
* The Set SIRK may not be exposed by the server over Bluetooth, and
* may require an out-of-band solution.
*/
uint8_t set_sirk[BT_CSIP_SET_SIRK_SIZE];
/**
* @brief The size of the set
*
* Will be 0 if not exposed by the server.
*/
uint8_t set_size;
/**
* @brief The rank of the set on on the remote device
*
* Will be 0 if not exposed by the server.
*/
uint8_t rank;
};
/**
* @brief Struct representing a coordinated set instance on a remote device
*
* The values in this struct will be populated during discovery of sets
* (bt_csip_set_coordinator_discover()).
*/
struct bt_csip_set_coordinator_csis_inst {
struct bt_csip_set_coordinator_set_info info;
/** Internally used pointer value */
void *svc_inst;
};
/** Struct representing a remote device as a set member */
struct bt_csip_set_coordinator_set_member {
/** Array of Coordinated Set Identification Service instances for the remote device */
struct bt_csip_set_coordinator_csis_inst insts[BT_CSIP_SET_COORDINATOR_MAX_CSIS_INSTANCES];
};
/**
* @typedef bt_csip_set_coordinator_discover_cb
* @brief Callback for discovering Coordinated Set Identification Services.
*
* @param conn Pointer to the remote device.
* @param member Pointer to the set member.
* @param err 0 on success, or an errno value on error.
* @param set_count Number of sets on the member.
*/
typedef void (*bt_csip_set_coordinator_discover_cb)(
struct bt_conn *conn,
const struct bt_csip_set_coordinator_set_member *member,
int err, size_t set_count);
/**
* @brief Initialise the csip_set_coordinator instance for a connection. This will do a
* discovery on the device and prepare the instance for following commands.
*
* @param conn Pointer to remote device to perform discovery on.
*
* @return int Return 0 on success, or an errno value on error.
*/
int bt_csip_set_coordinator_discover(struct bt_conn *conn);
/**
* @typedef bt_csip_set_coordinator_lock_set_cb
* @brief Callback for locking a set across one or more devices
*
* @param err 0 on success, or an errno value on error.
*/
typedef void (*bt_csip_set_coordinator_lock_set_cb)(int err);
/**
* @typedef bt_csip_set_coordinator_lock_changed_cb
* @brief Callback when the lock value on a set of a connected device changes.
*
* @param inst The Coordinated Set Identification Service instance that was
* changed.
* @param locked Whether the lock is locked or release.
*
* @return int Return 0 on success, or an errno value on error.
*/
typedef void (*bt_csip_set_coordinator_lock_changed_cb)(
struct bt_csip_set_coordinator_csis_inst *inst, bool locked);
/**
* @typedef bt_csip_set_coordinator_ordered_access_cb_t
* @brief Callback for bt_csip_set_coordinator_ordered_access()
*
* If any of the set members supplied to bt_csip_set_coordinator_ordered_access() is
* in the locked state, this will be called with @p locked true and @p member
* will be the locked member, and the ordered access procedure is cancelled.
* Likewise, if any error occurs, the procedure will also be aborted.
*
* @param set_info Pointer to the a specific set_info struct.
* @param err Error value. 0 on success, GATT error or errno on fail.
* @param locked Whether the lock is locked or release.
* @param member The locked member if @p locked is true, otherwise NULL.
*/
typedef void (*bt_csip_set_coordinator_ordered_access_cb_t)(
const struct bt_csip_set_coordinator_set_info *set_info,
int err, bool locked,
struct bt_csip_set_coordinator_set_member *member);
struct bt_csip_set_coordinator_cb {
/* Set callbacks */
bt_csip_set_coordinator_lock_set_cb lock_set;
bt_csip_set_coordinator_lock_set_cb release_set;
bt_csip_set_coordinator_lock_changed_cb lock_changed;
/* Device specific callbacks */
bt_csip_set_coordinator_discover_cb discover;
bt_csip_set_coordinator_ordered_access_cb_t ordered_access;
/** Internally used field for list handling */
sys_snode_t _node;
};
/**
* @brief Check if advertising data indicates a set member
*
* @param set_sirk The SIRK of the set to check against
* @param data The advertising data
*
* @return true if the advertising data indicates a set member, false otherwise
*/
bool bt_csip_set_coordinator_is_set_member(const uint8_t set_sirk[BT_CSIP_SET_SIRK_SIZE],
struct bt_data *data);
/**
* @brief Registers callbacks for csip_set_coordinator.
*
* @param cb Pointer to the callback structure.
*
* @return Return 0 on success, or an errno value on error.
*/
int bt_csip_set_coordinator_register_cb(struct bt_csip_set_coordinator_cb *cb);
/**
* @brief Callback function definition for bt_csip_set_coordinator_ordered_access()
*
* @param set_info Pointer to the a specific set_info struct.
* @param members Array of members ordered by rank. The procedure shall be
* done on the members in ascending order.
* @param count Number of members in @p members.
*
* @return true if the procedures can be successfully done, or false to stop the
* procedure.
*/
typedef bool (*bt_csip_set_coordinator_ordered_access_t)(
const struct bt_csip_set_coordinator_set_info *set_info,
struct bt_csip_set_coordinator_set_member *members[],
size_t count);
/**
* @brief Access Coordinated Set devices in an ordered manner as a client
*
* This function will read the lock state of all devices and if all devices are
* in the unlocked state, then @p cb will be called with the same members as
* provided by @p members, but where the members are ordered by rank
* (if present). Once this procedure is finished or an error occurs,
* @ref bt_csip_set_coordinator_cb.ordered_access will be called.
*
* This procedure only works if all the members have the lock characterstic,
* and all either has rank = 0 or unique ranks.
*
* If any of the members are in the locked state, the procedure will be
* cancelled.
*
* This can only be done on members that are bonded.
*
* @param members Array of set members to access.
* @param count Number of set members in @p members.
* @param set_info Pointer to the a specific set_info struct, as a member may
* be part of multiple sets.
* @param cb The callback function to be called for each member.
*/
int bt_csip_set_coordinator_ordered_access(
const struct bt_csip_set_coordinator_set_member *members[],
uint8_t count,
const struct bt_csip_set_coordinator_set_info *set_info,
bt_csip_set_coordinator_ordered_access_t cb);
/**
* @brief Lock an array of set members
*
* The members will be locked starting from lowest rank going up.
*
* TODO: If locking fails, the already locked members will not be unlocked.
*
* @param members Array of set members to lock.
* @param count Number of set members in @p members.
* @param set_info Pointer to the a specific set_info struct, as a member may
* be part of multiple sets.
*
* @return Return 0 on success, or an errno value on error.
*/
int bt_csip_set_coordinator_lock(const struct bt_csip_set_coordinator_set_member **members,
uint8_t count,
const struct bt_csip_set_coordinator_set_info *set_info);
/**
* @brief Release an array of set members
*
* The members will be released starting from highest rank going down.
*
* @param members Array of set members to lock.
* @param count Number of set members in @p members.
* @param set_info Pointer to the a specific set_info struct, as a member may
* be part of multiple sets.
*
* @return Return 0 on success, or an errno value on error.
*/
int bt_csip_set_coordinator_release(const struct bt_csip_set_coordinator_set_member **members,
uint8_t count,
const struct bt_csip_set_coordinator_set_info *set_info);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* ZEPHYR_SUBSYS_BLUETOOTH_AUDIO_CSIP_H_ */