bluetooth: ots: Add Create and Delete procedures
Add the ability to perform an OTS Create or Delete Procedure. Signed-off-by: Abe Kohandel <abe.kohandel@gmail.com>
This commit is contained in:
parent
c02197ece7
commit
a6f932a194
9 changed files with 572 additions and 163 deletions
|
@ -215,21 +215,6 @@ struct bt_ots_obj_size {
|
||||||
uint32_t alloc;
|
uint32_t alloc;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
/** @brief Descriptor for OTS object initialization. */
|
|
||||||
struct bt_ots_obj_metadata {
|
|
||||||
/* Object Name */
|
|
||||||
char *name;
|
|
||||||
|
|
||||||
/* Object Type */
|
|
||||||
struct bt_ots_obj_type type;
|
|
||||||
|
|
||||||
/* Object Size */
|
|
||||||
struct bt_ots_obj_size size;
|
|
||||||
|
|
||||||
/* Object Properties */
|
|
||||||
uint32_t props;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @brief Object Action Control Point Feature bits. */
|
/** @brief Object Action Control Point Feature bits. */
|
||||||
enum {
|
enum {
|
||||||
/** Bit 0 OACP Create Op Code Supported */
|
/** Bit 0 OACP Create Op Code Supported */
|
||||||
|
@ -486,6 +471,48 @@ struct bt_ots_feat {
|
||||||
/** @brief Opaque OTS instance. */
|
/** @brief Opaque OTS instance. */
|
||||||
struct bt_ots;
|
struct bt_ots;
|
||||||
|
|
||||||
|
/** @brief Descriptor for OTS object addition */
|
||||||
|
struct bt_ots_obj_add_param {
|
||||||
|
/** @brief Object size to allocate */
|
||||||
|
uint32_t size;
|
||||||
|
|
||||||
|
/** @brief Object type */
|
||||||
|
struct bt_ots_obj_type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Descriptor for OTS created object.
|
||||||
|
*
|
||||||
|
* Descriptor for OTS object created by the application. This descriptor is
|
||||||
|
* returned by @ref bt_ots_cb.obj_created callback which contains further
|
||||||
|
* documentation on distinguishing between server and client object creation.
|
||||||
|
*/
|
||||||
|
struct bt_ots_obj_created_desc {
|
||||||
|
/** @brief Object name
|
||||||
|
*
|
||||||
|
* The object name as a NULL terminated string.
|
||||||
|
*
|
||||||
|
* When the server creates a new object the name
|
||||||
|
* shall be > 0 and <= BT_OTS_OBJ_MAX_NAME_LEN
|
||||||
|
* When the client creates a new object the name
|
||||||
|
* shall be an empty string
|
||||||
|
*/
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
/** @brief Object size
|
||||||
|
*
|
||||||
|
* @ref bt_ots_obj_size.alloc shall be >= @ref bt_ots_obj_add_param.size
|
||||||
|
*
|
||||||
|
* When the server creates a new object @ref bt_ots_obj_size.cur
|
||||||
|
* shall be <= @ref bt_ots_obj_add_param.size
|
||||||
|
* When the client creates a new object @ref bt_ots_obj_size.cur
|
||||||
|
* shall be 0
|
||||||
|
*/
|
||||||
|
struct bt_ots_obj_size size;
|
||||||
|
|
||||||
|
/** @brief Object properties */
|
||||||
|
uint32_t props;
|
||||||
|
};
|
||||||
|
|
||||||
/** @brief OTS callback structure. */
|
/** @brief OTS callback structure. */
|
||||||
struct bt_ots_cb {
|
struct bt_ots_cb {
|
||||||
/** @brief Object created callback
|
/** @brief Object created callback
|
||||||
|
@ -498,18 +525,21 @@ struct bt_ots_cb {
|
||||||
*
|
*
|
||||||
* @param ots OTS instance.
|
* @param ots OTS instance.
|
||||||
* @param conn The connection that is requesting object creation or
|
* @param conn The connection that is requesting object creation or
|
||||||
* NULL if object is created by the following function:
|
* NULL if object is created by bt_ots_obj_add().
|
||||||
* bt_ots_obj_add().
|
|
||||||
* @param id Object ID.
|
* @param id Object ID.
|
||||||
* @param init Object initialization metadata.
|
* @param add_param Object creation requested parameters.
|
||||||
|
* @param created_desc Created object descriptor that shall be filled by the
|
||||||
|
* receiver of this callback.
|
||||||
*
|
*
|
||||||
* @return 0 in case of success or negative value in case of error.
|
* @return 0 in case of success or negative value in case of error.
|
||||||
* Possible return values:
|
* @return -ENOTSUP if object type is not supported
|
||||||
* -ENOMEM if no available space for new object.
|
* @return -ENOMEM if no available space for new object.
|
||||||
|
* @return -EINVAL if an invalid parameter is provided
|
||||||
|
* @return other negative values are treated as a generic operation failure
|
||||||
*/
|
*/
|
||||||
int (*obj_created)(struct bt_ots *ots, struct bt_conn *conn,
|
int (*obj_created)(struct bt_ots *ots, struct bt_conn *conn, uint64_t id,
|
||||||
uint64_t id,
|
const struct bt_ots_obj_add_param *add_param,
|
||||||
const struct bt_ots_obj_metadata *init);
|
struct bt_ots_obj_created_desc *created_desc);
|
||||||
|
|
||||||
/** @brief Object deleted callback
|
/** @brief Object deleted callback
|
||||||
*
|
*
|
||||||
|
@ -521,8 +551,18 @@ struct bt_ots_cb {
|
||||||
* @param conn The connection that deleted the object or NULL if
|
* @param conn The connection that deleted the object or NULL if
|
||||||
* this request came from the server.
|
* this request came from the server.
|
||||||
* @param id Object ID.
|
* @param id Object ID.
|
||||||
|
*
|
||||||
|
* @retval When an error is indicated by using a negative value, the
|
||||||
|
* object delete procedure is aborted and a corresponding failed
|
||||||
|
* status is returned to the client.
|
||||||
|
* @return 0 in case of success.
|
||||||
|
* @return -EBUSY if the object is locked. This is generally not expected
|
||||||
|
* to be returned by the application as the OTS layer tracks object
|
||||||
|
* accesses. An object locked status is returned to the client.
|
||||||
|
* @return Other negative values in case of error. A generic operation
|
||||||
|
* failed status is returned to the client.
|
||||||
*/
|
*/
|
||||||
void (*obj_deleted)(struct bt_ots *ots, struct bt_conn *conn,
|
int (*obj_deleted)(struct bt_ots *ots, struct bt_conn *conn,
|
||||||
uint64_t id);
|
uint64_t id);
|
||||||
|
|
||||||
/** @brief Object selected callback
|
/** @brief Object selected callback
|
||||||
|
@ -621,11 +661,12 @@ struct bt_ots_init {
|
||||||
* to notify the user about a new object ID.
|
* to notify the user about a new object ID.
|
||||||
*
|
*
|
||||||
* @param ots OTS instance.
|
* @param ots OTS instance.
|
||||||
* @param obj_init Meta data of the object.
|
* @param param Object addition parameters.
|
||||||
*
|
*
|
||||||
* @return 0 in case of success or negative value in case of error.
|
* @return ID of created object in case of success.
|
||||||
|
* @return negative value in case of error.
|
||||||
*/
|
*/
|
||||||
int bt_ots_obj_add(struct bt_ots *ots, struct bt_ots_obj_metadata *obj_init);
|
int bt_ots_obj_add(struct bt_ots *ots, const struct bt_ots_obj_add_param *param);
|
||||||
|
|
||||||
/** @brief Delete an object from the OTS instance.
|
/** @brief Delete an object from the OTS instance.
|
||||||
*
|
*
|
||||||
|
|
|
@ -6,6 +6,8 @@ CONFIG_BT_OTS_DIR_LIST_OBJ=y
|
||||||
CONFIG_BT_OTS_OBJ_NAME_WRITE_SUPPORT=y
|
CONFIG_BT_OTS_OBJ_NAME_WRITE_SUPPORT=y
|
||||||
CONFIG_BT_OTS_OACP_WRITE_SUPPORT=y
|
CONFIG_BT_OTS_OACP_WRITE_SUPPORT=y
|
||||||
CONFIG_BT_OTS_OACP_PATCH_SUPPORT=y
|
CONFIG_BT_OTS_OACP_PATCH_SUPPORT=y
|
||||||
|
CONFIG_BT_OTS_OACP_CREATE_SUPPORT=y
|
||||||
|
CONFIG_BT_OTS_OACP_DELETE_SUPPORT=y
|
||||||
|
|
||||||
CONFIG_LOG=y
|
CONFIG_LOG=y
|
||||||
CONFIG_ASSERT=y
|
CONFIG_ASSERT=y
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
|
#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
|
||||||
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
|
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
|
||||||
|
|
||||||
#define OBJ_POOL_SIZE 2
|
#define OBJ_POOL_SIZE CONFIG_BT_OTS_MAX_OBJ_CNT
|
||||||
#define OBJ_MAX_SIZE 100
|
#define OBJ_MAX_SIZE 100
|
||||||
|
|
||||||
static const struct bt_data ad[] = {
|
static const struct bt_data ad[] = {
|
||||||
|
@ -37,6 +37,14 @@ static struct {
|
||||||
} objects[OBJ_POOL_SIZE];
|
} objects[OBJ_POOL_SIZE];
|
||||||
static uint32_t obj_cnt;
|
static uint32_t obj_cnt;
|
||||||
|
|
||||||
|
struct object_creation_data {
|
||||||
|
struct bt_ots_obj_size size;
|
||||||
|
char *name;
|
||||||
|
uint32_t props;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct object_creation_data *object_being_created;
|
||||||
|
|
||||||
static void connected(struct bt_conn *conn, uint8_t err)
|
static void connected(struct bt_conn *conn, uint8_t err)
|
||||||
{
|
{
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -57,11 +65,12 @@ BT_CONN_CB_DEFINE(conn_callbacks) = {
|
||||||
.disconnected = disconnected,
|
.disconnected = disconnected,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ots_obj_created(struct bt_ots *ots, struct bt_conn *conn,
|
static int ots_obj_created(struct bt_ots *ots, struct bt_conn *conn, uint64_t id,
|
||||||
uint64_t id,
|
const struct bt_ots_obj_add_param *add_param,
|
||||||
const struct bt_ots_obj_metadata *init)
|
struct bt_ots_obj_created_desc *created_desc)
|
||||||
{
|
{
|
||||||
char id_str[BT_OTS_OBJ_ID_STR_LEN];
|
char id_str[BT_OTS_OBJ_ID_STR_LEN];
|
||||||
|
uint64_t index;
|
||||||
|
|
||||||
bt_ots_obj_id_to_str(id, id_str, sizeof(id_str));
|
bt_ots_obj_id_to_str(id, id_str, sizeof(id_str));
|
||||||
|
|
||||||
|
@ -71,19 +80,35 @@ static int ots_obj_created(struct bt_ots *ots, struct bt_conn *conn,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (init->size.alloc > OBJ_MAX_SIZE) {
|
if (add_param->size > OBJ_MAX_SIZE) {
|
||||||
printk("Object pool item is too small for Object with %s ID\n",
|
printk("Object pool item is too small for Object with %s ID\n",
|
||||||
id_str);
|
id_str);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (object_being_created) {
|
||||||
|
created_desc->name = object_being_created->name;
|
||||||
|
created_desc->size = object_being_created->size;
|
||||||
|
created_desc->props = object_being_created->props;
|
||||||
|
} else {
|
||||||
|
index = id - BT_OTS_OBJ_ID_MIN;
|
||||||
|
objects[index].name[0] = '\0';
|
||||||
|
|
||||||
|
created_desc->name = objects[index].name;
|
||||||
|
created_desc->size.alloc = OBJ_MAX_SIZE;
|
||||||
|
BT_OTS_OBJ_SET_PROP_READ(created_desc->props);
|
||||||
|
BT_OTS_OBJ_SET_PROP_WRITE(created_desc->props);
|
||||||
|
BT_OTS_OBJ_SET_PROP_PATCH(created_desc->props);
|
||||||
|
BT_OTS_OBJ_SET_PROP_DELETE(created_desc->props);
|
||||||
|
}
|
||||||
|
|
||||||
printk("Object with %s ID has been created\n", id_str);
|
printk("Object with %s ID has been created\n", id_str);
|
||||||
obj_cnt++;
|
obj_cnt++;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ots_obj_deleted(struct bt_ots *ots, struct bt_conn *conn,
|
static int ots_obj_deleted(struct bt_ots *ots, struct bt_conn *conn,
|
||||||
uint64_t id)
|
uint64_t id)
|
||||||
{
|
{
|
||||||
char id_str[BT_OTS_OBJ_ID_STR_LEN];
|
char id_str[BT_OTS_OBJ_ID_STR_LEN];
|
||||||
|
@ -93,6 +118,8 @@ static void ots_obj_deleted(struct bt_ots *ots, struct bt_conn *conn,
|
||||||
printk("Object with %s ID has been deleted\n", id_str);
|
printk("Object with %s ID has been deleted\n", id_str);
|
||||||
|
|
||||||
obj_cnt--;
|
obj_cnt--;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ots_obj_selected(struct bt_ots *ots, struct bt_conn *conn,
|
static void ots_obj_selected(struct bt_ots *ots, struct bt_conn *conn,
|
||||||
|
@ -150,7 +177,7 @@ static ssize_t ots_obj_write(struct bt_ots *ots, struct bt_conn *conn,
|
||||||
"Offset = %lu, Length = %zu, Remaining= %zu\n",
|
"Offset = %lu, Length = %zu, Remaining= %zu\n",
|
||||||
id_str, (long)offset, len, rem);
|
id_str, (long)offset, len, rem);
|
||||||
|
|
||||||
memcpy(&objects[obj_index].data[offset], data, len);
|
(void)memcpy(&objects[obj_index].data[offset], data, len);
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
@ -177,8 +204,9 @@ static int ots_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct bt_ots *ots;
|
struct bt_ots *ots;
|
||||||
|
struct object_creation_data obj_data;
|
||||||
struct bt_ots_init ots_init;
|
struct bt_ots_init ots_init;
|
||||||
struct bt_ots_obj_metadata obj_init;
|
struct bt_ots_obj_add_param param;
|
||||||
const char * const first_object_name = "first_object.txt";
|
const char * const first_object_name = "first_object.txt";
|
||||||
const char * const second_object_name = "second_object.gif";
|
const char * const second_object_name = "second_object.gif";
|
||||||
uint32_t cur_size;
|
uint32_t cur_size;
|
||||||
|
@ -191,9 +219,11 @@ static int ots_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Configure OTS initialization. */
|
/* Configure OTS initialization. */
|
||||||
memset(&ots_init, 0, sizeof(ots_init));
|
(void)memset(&ots_init, 0, sizeof(ots_init));
|
||||||
BT_OTS_OACP_SET_FEAT_READ(ots_init.features.oacp);
|
BT_OTS_OACP_SET_FEAT_READ(ots_init.features.oacp);
|
||||||
BT_OTS_OACP_SET_FEAT_WRITE(ots_init.features.oacp);
|
BT_OTS_OACP_SET_FEAT_WRITE(ots_init.features.oacp);
|
||||||
|
BT_OTS_OACP_SET_FEAT_CREATE(ots_init.features.oacp);
|
||||||
|
BT_OTS_OACP_SET_FEAT_DELETE(ots_init.features.oacp);
|
||||||
BT_OTS_OACP_SET_FEAT_PATCH(ots_init.features.oacp);
|
BT_OTS_OACP_SET_FEAT_PATCH(ots_init.features.oacp);
|
||||||
BT_OTS_OLCP_SET_FEAT_GO_TO(ots_init.features.olcp);
|
BT_OTS_OLCP_SET_FEAT_GO_TO(ots_init.features.olcp);
|
||||||
ots_init.cb = &ots_callbacks;
|
ots_init.cb = &ots_callbacks;
|
||||||
|
@ -212,22 +242,25 @@ static int ots_init(void)
|
||||||
objects[0].data[i] = i + 1;
|
objects[0].data[i] = i + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&obj_init, 0, sizeof(obj_init));
|
(void)memset(&obj_data, 0, sizeof(obj_data));
|
||||||
__ASSERT(strlen(first_object_name) <= CONFIG_BT_OTS_OBJ_MAX_NAME_LEN,
|
__ASSERT(strlen(first_object_name) <= CONFIG_BT_OTS_OBJ_MAX_NAME_LEN,
|
||||||
"Object name length is larger than the allowed maximum of %u",
|
"Object name length is larger than the allowed maximum of %u",
|
||||||
CONFIG_BT_OTS_OBJ_MAX_NAME_LEN);
|
CONFIG_BT_OTS_OBJ_MAX_NAME_LEN);
|
||||||
strcpy(objects[0].name, first_object_name);
|
(void)strcpy(objects[0].name, first_object_name);
|
||||||
obj_init.name = objects[0].name;
|
obj_data.name = objects[0].name;
|
||||||
obj_init.type.uuid.type = BT_UUID_TYPE_16;
|
obj_data.size.cur = cur_size;
|
||||||
obj_init.type.uuid_16.val = BT_UUID_OTS_TYPE_UNSPECIFIED_VAL;
|
obj_data.size.alloc = alloc_size;
|
||||||
obj_init.size.cur = cur_size;
|
BT_OTS_OBJ_SET_PROP_READ(obj_data.props);
|
||||||
obj_init.size.alloc = alloc_size;
|
BT_OTS_OBJ_SET_PROP_WRITE(obj_data.props);
|
||||||
BT_OTS_OBJ_SET_PROP_READ(obj_init.props);
|
BT_OTS_OBJ_SET_PROP_PATCH(obj_data.props);
|
||||||
BT_OTS_OBJ_SET_PROP_WRITE(obj_init.props);
|
object_being_created = &obj_data;
|
||||||
BT_OTS_OBJ_SET_PROP_PATCH(obj_init.props);
|
|
||||||
|
|
||||||
err = bt_ots_obj_add(ots, &obj_init);
|
param.size = alloc_size;
|
||||||
if (err) {
|
param.type.uuid.type = BT_UUID_TYPE_16;
|
||||||
|
param.type.uuid_16.val = BT_UUID_OTS_TYPE_UNSPECIFIED_VAL;
|
||||||
|
err = bt_ots_obj_add(ots, ¶m);
|
||||||
|
object_being_created = NULL;
|
||||||
|
if (err < 0) {
|
||||||
printk("Failed to add an object to OTS (err: %d)\n", err);
|
printk("Failed to add an object to OTS (err: %d)\n", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -239,20 +272,23 @@ static int ots_init(void)
|
||||||
objects[1].data[i] = i * 2;
|
objects[1].data[i] = i * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&obj_init, 0, sizeof(obj_init));
|
(void)memset(&obj_data, 0, sizeof(obj_data));
|
||||||
__ASSERT(strlen(second_object_name) <= CONFIG_BT_OTS_OBJ_MAX_NAME_LEN,
|
__ASSERT(strlen(second_object_name) <= CONFIG_BT_OTS_OBJ_MAX_NAME_LEN,
|
||||||
"Object name length is larger than the allowed maximum of %u",
|
"Object name length is larger than the allowed maximum of %u",
|
||||||
CONFIG_BT_OTS_OBJ_MAX_NAME_LEN);
|
CONFIG_BT_OTS_OBJ_MAX_NAME_LEN);
|
||||||
strcpy(objects[1].name, second_object_name);
|
(void)strcpy(objects[1].name, second_object_name);
|
||||||
obj_init.name = objects[1].name;
|
obj_data.name = objects[1].name;
|
||||||
obj_init.type.uuid.type = BT_UUID_TYPE_16;
|
obj_data.size.cur = cur_size;
|
||||||
obj_init.type.uuid_16.val = BT_UUID_OTS_TYPE_UNSPECIFIED_VAL;
|
obj_data.size.alloc = alloc_size;
|
||||||
obj_init.size.cur = cur_size;
|
BT_OTS_OBJ_SET_PROP_READ(obj_data.props);
|
||||||
obj_init.size.alloc = alloc_size;
|
object_being_created = &obj_data;
|
||||||
BT_OTS_OBJ_SET_PROP_READ(obj_init.props);
|
|
||||||
|
|
||||||
err = bt_ots_obj_add(ots, &obj_init);
|
param.size = alloc_size;
|
||||||
if (err) {
|
param.type.uuid.type = BT_UUID_TYPE_16;
|
||||||
|
param.type.uuid_16.val = BT_UUID_OTS_TYPE_UNSPECIFIED_VAL;
|
||||||
|
err = bt_ots_obj_add(ots, ¶m);
|
||||||
|
object_being_created = NULL;
|
||||||
|
if (err < 0) {
|
||||||
printk("Failed to add an object to OTS (err: %d)\n", err);
|
printk("Failed to add an object to OTS (err: %d)\n", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -261,12 +261,22 @@ enum mpl_objects {
|
||||||
/* And, except for the icon object, all objects can be created dynamically. */
|
/* And, except for the icon object, all objects can be created dynamically. */
|
||||||
/* So a single buffer to hold object content is sufficient. */
|
/* So a single buffer to hold object content is sufficient. */
|
||||||
struct obj_t {
|
struct obj_t {
|
||||||
uint64_t selected_id; /* ID of the currently selected object*/
|
/* ID of the currently selected object*/
|
||||||
|
uint64_t selected_id;
|
||||||
|
|
||||||
bool busy;
|
bool busy;
|
||||||
uint8_t add_type; /* Type of object being added, e.g. MPL_OBJ_ICON */
|
|
||||||
|
/* Type of object being added, e.g. MPL_OBJ_ICON */
|
||||||
|
uint8_t add_type;
|
||||||
|
|
||||||
|
/* Descriptor of object being added */
|
||||||
|
struct bt_ots_obj_created_desc *desc;
|
||||||
union {
|
union {
|
||||||
struct mpl_track *add_track; /* Pointer to track being added */
|
/* Pointer to track being added */
|
||||||
struct mpl_group *add_group; /* Pointer to group being added */
|
struct mpl_track *add_track;
|
||||||
|
|
||||||
|
/* Pointer to group being added */
|
||||||
|
struct mpl_group *add_group;
|
||||||
};
|
};
|
||||||
struct net_buf_simple *content;
|
struct net_buf_simple *content;
|
||||||
};
|
};
|
||||||
|
@ -440,7 +450,8 @@ static uint32_t setup_group_object(struct mpl_group *group)
|
||||||
static int add_icon_object(struct mpl_mediaplayer *pl)
|
static int add_icon_object(struct mpl_mediaplayer *pl)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct bt_ots_obj_metadata icon = {0};
|
struct bt_ots_obj_add_param add_param = {};
|
||||||
|
struct bt_ots_obj_created_desc created_desc = {};
|
||||||
struct bt_uuid *icon_type = BT_UUID_OTS_TYPE_MPL_ICON;
|
struct bt_uuid *icon_type = BT_UUID_OTS_TYPE_MPL_ICON;
|
||||||
static char *icon_name = "Icon";
|
static char *icon_name = "Icon";
|
||||||
|
|
||||||
|
@ -452,14 +463,17 @@ static int add_icon_object(struct mpl_mediaplayer *pl)
|
||||||
}
|
}
|
||||||
obj.busy = true;
|
obj.busy = true;
|
||||||
obj.add_type = MPL_OBJ_ICON;
|
obj.add_type = MPL_OBJ_ICON;
|
||||||
|
obj.desc = &created_desc;
|
||||||
|
|
||||||
icon.size.alloc = icon.size.cur = setup_icon_object();
|
obj.desc->size.alloc = obj.desc->size.cur = setup_icon_object();
|
||||||
icon.name = icon_name;
|
obj.desc->name = icon_name;
|
||||||
icon.type.uuid.type = BT_UUID_TYPE_16;
|
BT_OTS_OBJ_SET_PROP_READ(obj.desc->props);
|
||||||
icon.type.uuid_16.val = BT_UUID_16(icon_type)->val;
|
|
||||||
BT_OTS_OBJ_SET_PROP_READ(icon.props);
|
|
||||||
|
|
||||||
ret = bt_ots_obj_add(bt_mcs_get_ots(), &icon);
|
add_param.size = obj.desc->size.alloc;
|
||||||
|
add_param.type.uuid.type = BT_UUID_TYPE_16;
|
||||||
|
add_param.type.uuid_16.val = BT_UUID_16(icon_type)->val;
|
||||||
|
|
||||||
|
ret = bt_ots_obj_add(bt_mcs_get_ots(), &add_param);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
BT_WARN("Unable to add icon object, error %d", ret);
|
BT_WARN("Unable to add icon object, error %d", ret);
|
||||||
|
@ -472,7 +486,8 @@ static int add_icon_object(struct mpl_mediaplayer *pl)
|
||||||
static int add_current_track_segments_object(struct mpl_mediaplayer *pl)
|
static int add_current_track_segments_object(struct mpl_mediaplayer *pl)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct bt_ots_obj_metadata segs = {0};
|
struct bt_ots_obj_add_param add_param = {};
|
||||||
|
struct bt_ots_obj_created_desc created_desc = {};
|
||||||
struct bt_uuid *segs_type = BT_UUID_OTS_TYPE_TRACK_SEGMENT;
|
struct bt_uuid *segs_type = BT_UUID_OTS_TYPE_TRACK_SEGMENT;
|
||||||
|
|
||||||
if (obj.busy) {
|
if (obj.busy) {
|
||||||
|
@ -481,14 +496,17 @@ static int add_current_track_segments_object(struct mpl_mediaplayer *pl)
|
||||||
}
|
}
|
||||||
obj.busy = true;
|
obj.busy = true;
|
||||||
obj.add_type = MPL_OBJ_TRACK_SEGMENTS;
|
obj.add_type = MPL_OBJ_TRACK_SEGMENTS;
|
||||||
|
obj.desc = &created_desc;
|
||||||
|
|
||||||
segs.size.alloc = segs.size.cur = setup_segments_object(pl->group->track);
|
obj.desc->size.alloc = obj.desc->size.cur = setup_segments_object(pl->group->track);
|
||||||
segs.name = pl->group->track->title;
|
obj.desc->name = pl->group->track->title;
|
||||||
segs.type.uuid.type = BT_UUID_TYPE_16;
|
BT_OTS_OBJ_SET_PROP_READ(obj.desc->props);
|
||||||
segs.type.uuid_16.val = BT_UUID_16(segs_type)->val;
|
|
||||||
BT_OTS_OBJ_SET_PROP_READ(segs.props);
|
|
||||||
|
|
||||||
ret = bt_ots_obj_add(bt_mcs_get_ots(), &segs);
|
add_param.size = obj.desc->size.alloc;
|
||||||
|
add_param.type.uuid.type = BT_UUID_TYPE_16;
|
||||||
|
add_param.type.uuid_16.val = BT_UUID_16(segs_type)->val;
|
||||||
|
|
||||||
|
ret = bt_ots_obj_add(bt_mcs_get_ots(), &add_param);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
BT_WARN("Unable to add track segments object: %d", ret);
|
BT_WARN("Unable to add track segments object: %d", ret);
|
||||||
obj.busy = false;
|
obj.busy = false;
|
||||||
|
@ -499,7 +517,8 @@ static int add_current_track_segments_object(struct mpl_mediaplayer *pl)
|
||||||
/* Add a single track to the OTS */
|
/* Add a single track to the OTS */
|
||||||
static int add_track_object(struct mpl_track *track)
|
static int add_track_object(struct mpl_track *track)
|
||||||
{
|
{
|
||||||
struct bt_ots_obj_metadata track_meta = {0};
|
struct bt_ots_obj_add_param add_param = {};
|
||||||
|
struct bt_ots_obj_created_desc created_desc = {};
|
||||||
struct bt_uuid *track_type = BT_UUID_OTS_TYPE_TRACK;
|
struct bt_uuid *track_type = BT_UUID_OTS_TYPE_TRACK;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -516,13 +535,17 @@ static int add_track_object(struct mpl_track *track)
|
||||||
|
|
||||||
obj.add_type = MPL_OBJ_TRACK;
|
obj.add_type = MPL_OBJ_TRACK;
|
||||||
obj.add_track = track;
|
obj.add_track = track;
|
||||||
|
obj.desc = &created_desc;
|
||||||
|
|
||||||
track_meta.size.alloc = track_meta.size.cur = setup_track_object(track);
|
obj.desc->size.alloc = obj.desc->size.cur = setup_track_object(track);
|
||||||
track_meta.name = track->title;
|
obj.desc->name = track->title;
|
||||||
track_meta.type.uuid.type = BT_UUID_TYPE_16;
|
BT_OTS_OBJ_SET_PROP_READ(obj.desc->props);
|
||||||
track_meta.type.uuid_16.val = BT_UUID_16(track_type)->val;
|
|
||||||
BT_OTS_OBJ_SET_PROP_READ(track_meta.props);
|
add_param.size = obj.desc->size.alloc;
|
||||||
ret = bt_ots_obj_add(bt_mcs_get_ots(), &track_meta);
|
add_param.type.uuid.type = BT_UUID_TYPE_16;
|
||||||
|
add_param.type.uuid_16.val = BT_UUID_16(track_type)->val;
|
||||||
|
|
||||||
|
ret = bt_ots_obj_add(bt_mcs_get_ots(), &add_param);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
BT_WARN("Unable to add track object: %d", ret);
|
BT_WARN("Unable to add track object: %d", ret);
|
||||||
|
@ -536,7 +559,8 @@ static int add_track_object(struct mpl_track *track)
|
||||||
static int add_parent_group_object(struct mpl_mediaplayer *pl)
|
static int add_parent_group_object(struct mpl_mediaplayer *pl)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct bt_ots_obj_metadata group_meta = {0};
|
struct bt_ots_obj_add_param add_param = {};
|
||||||
|
struct bt_ots_obj_created_desc created_desc = {};
|
||||||
struct bt_uuid *group_type = BT_UUID_OTS_TYPE_GROUP;
|
struct bt_uuid *group_type = BT_UUID_OTS_TYPE_GROUP;
|
||||||
|
|
||||||
if (obj.busy) {
|
if (obj.busy) {
|
||||||
|
@ -545,14 +569,17 @@ static int add_parent_group_object(struct mpl_mediaplayer *pl)
|
||||||
}
|
}
|
||||||
obj.busy = true;
|
obj.busy = true;
|
||||||
obj.add_type = MPL_OBJ_PARENT_GROUP;
|
obj.add_type = MPL_OBJ_PARENT_GROUP;
|
||||||
|
obj.desc = &created_desc;
|
||||||
|
|
||||||
group_meta.size.alloc = group_meta.size.cur = setup_parent_group_object(pl->group);
|
obj.desc->size.alloc = obj.desc->size.cur = setup_parent_group_object(pl->group);
|
||||||
group_meta.name = pl->group->parent->title;
|
obj.desc->name = pl->group->parent->title;
|
||||||
group_meta.type.uuid.type = BT_UUID_TYPE_16;
|
BT_OTS_OBJ_SET_PROP_READ(obj.desc->props);
|
||||||
group_meta.type.uuid_16.val = BT_UUID_16(group_type)->val;
|
|
||||||
BT_OTS_OBJ_SET_PROP_READ(group_meta.props);
|
|
||||||
|
|
||||||
ret = bt_ots_obj_add(bt_mcs_get_ots(), &group_meta);
|
add_param.size = obj.desc->size.alloc;
|
||||||
|
add_param.type.uuid.type = BT_UUID_TYPE_16;
|
||||||
|
add_param.type.uuid_16.val = BT_UUID_16(group_type)->val;
|
||||||
|
|
||||||
|
ret = bt_ots_obj_add(bt_mcs_get_ots(), &add_param);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
BT_WARN("Unable to add parent group object");
|
BT_WARN("Unable to add parent group object");
|
||||||
obj.busy = false;
|
obj.busy = false;
|
||||||
|
@ -563,7 +590,8 @@ static int add_parent_group_object(struct mpl_mediaplayer *pl)
|
||||||
/* Add a single group to the OTS */
|
/* Add a single group to the OTS */
|
||||||
static int add_group_object(struct mpl_group *group)
|
static int add_group_object(struct mpl_group *group)
|
||||||
{
|
{
|
||||||
struct bt_ots_obj_metadata group_meta = {0};
|
struct bt_ots_obj_add_param add_param = {};
|
||||||
|
struct bt_ots_obj_created_desc created_desc = {};
|
||||||
struct bt_uuid *group_type = BT_UUID_OTS_TYPE_GROUP;
|
struct bt_uuid *group_type = BT_UUID_OTS_TYPE_GROUP;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -581,14 +609,17 @@ static int add_group_object(struct mpl_group *group)
|
||||||
|
|
||||||
obj.add_type = MPL_OBJ_GROUP;
|
obj.add_type = MPL_OBJ_GROUP;
|
||||||
obj.add_group = group;
|
obj.add_group = group;
|
||||||
|
obj.desc = &created_desc;
|
||||||
|
|
||||||
group_meta.size.alloc = group_meta.size.cur = setup_group_object(group);
|
obj.desc->size.alloc = obj.desc->size.cur = setup_group_object(group);
|
||||||
group_meta.name = group->title;
|
obj.desc->name = group->title;
|
||||||
group_meta.type.uuid.type = BT_UUID_TYPE_16;
|
BT_OTS_OBJ_SET_PROP_READ(obj.desc->props);
|
||||||
group_meta.type.uuid_16.val = BT_UUID_16(group_type)->val;
|
|
||||||
BT_OTS_OBJ_SET_PROP_READ(group_meta.props);
|
|
||||||
|
|
||||||
ret = bt_ots_obj_add(bt_mcs_get_ots(), &group_meta);
|
add_param.size = obj.desc->size.alloc;
|
||||||
|
add_param.type.uuid.type = BT_UUID_TYPE_16;
|
||||||
|
add_param.type.uuid_16.val = BT_UUID_16(group_type)->val;
|
||||||
|
|
||||||
|
ret = bt_ots_obj_add(bt_mcs_get_ots(), &add_param);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
BT_WARN("Unable to add group object: %d", ret);
|
BT_WARN("Unable to add group object: %d", ret);
|
||||||
|
@ -657,10 +688,12 @@ static int add_group_and_track_objects(struct mpl_mediaplayer *pl)
|
||||||
|
|
||||||
/**** Callbacks from the object transfer service ******************************/
|
/**** Callbacks from the object transfer service ******************************/
|
||||||
|
|
||||||
static void on_obj_deleted(struct bt_ots *ots, struct bt_conn *conn,
|
static int on_obj_deleted(struct bt_ots *ots, struct bt_conn *conn,
|
||||||
uint64_t id)
|
uint64_t id)
|
||||||
{
|
{
|
||||||
BT_DBG_OBJ_ID("Object Id deleted: ", id);
|
BT_DBG_OBJ_ID("Object Id deleted: ", id);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_obj_selected(struct bt_ots *ots, struct bt_conn *conn,
|
static void on_obj_selected(struct bt_ots *ots, struct bt_conn *conn,
|
||||||
|
@ -709,13 +742,15 @@ static void on_obj_selected(struct bt_ots *ots, struct bt_conn *conn,
|
||||||
obj.busy = false;
|
obj.busy = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_obj_created(struct bt_ots *ots, struct bt_conn *conn,
|
static int on_obj_created(struct bt_ots *ots, struct bt_conn *conn, uint64_t id,
|
||||||
uint64_t id,
|
const struct bt_ots_obj_add_param *add_param,
|
||||||
const struct bt_ots_obj_metadata *metadata)
|
struct bt_ots_obj_created_desc *created_desc)
|
||||||
{
|
{
|
||||||
BT_DBG_OBJ_ID("Object Id created: ", id);
|
BT_DBG_OBJ_ID("Object Id created: ", id);
|
||||||
|
|
||||||
if (!bt_uuid_cmp(&metadata->type.uuid, BT_UUID_OTS_TYPE_MPL_ICON)) {
|
*created_desc = *obj.desc;
|
||||||
|
|
||||||
|
if (!bt_uuid_cmp(&add_param->type.uuid, BT_UUID_OTS_TYPE_MPL_ICON)) {
|
||||||
BT_DBG("Icon Obj Type");
|
BT_DBG("Icon Obj Type");
|
||||||
if (obj.add_type == MPL_OBJ_ICON) {
|
if (obj.add_type == MPL_OBJ_ICON) {
|
||||||
obj.add_type = MPL_OBJ_NONE;
|
obj.add_type = MPL_OBJ_NONE;
|
||||||
|
@ -724,7 +759,7 @@ static int on_obj_created(struct bt_ots *ots, struct bt_conn *conn,
|
||||||
BT_DBG("Unexpected object creation");
|
BT_DBG("Unexpected object creation");
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (!bt_uuid_cmp(&metadata->type.uuid,
|
} else if (!bt_uuid_cmp(&add_param->type.uuid,
|
||||||
BT_UUID_OTS_TYPE_TRACK_SEGMENT)) {
|
BT_UUID_OTS_TYPE_TRACK_SEGMENT)) {
|
||||||
BT_DBG("Track Segments Obj Type");
|
BT_DBG("Track Segments Obj Type");
|
||||||
if (obj.add_type == MPL_OBJ_TRACK_SEGMENTS) {
|
if (obj.add_type == MPL_OBJ_TRACK_SEGMENTS) {
|
||||||
|
@ -734,7 +769,7 @@ static int on_obj_created(struct bt_ots *ots, struct bt_conn *conn,
|
||||||
BT_DBG("Unexpected object creation");
|
BT_DBG("Unexpected object creation");
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (!bt_uuid_cmp(&metadata->type.uuid,
|
} else if (!bt_uuid_cmp(&add_param->type.uuid,
|
||||||
BT_UUID_OTS_TYPE_TRACK)) {
|
BT_UUID_OTS_TYPE_TRACK)) {
|
||||||
BT_DBG("Track Obj Type");
|
BT_DBG("Track Obj Type");
|
||||||
if (obj.add_type == MPL_OBJ_TRACK) {
|
if (obj.add_type == MPL_OBJ_TRACK) {
|
||||||
|
@ -745,7 +780,7 @@ static int on_obj_created(struct bt_ots *ots, struct bt_conn *conn,
|
||||||
BT_DBG("Unexpected object creation");
|
BT_DBG("Unexpected object creation");
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (!bt_uuid_cmp(&metadata->type.uuid,
|
} else if (!bt_uuid_cmp(&add_param->type.uuid,
|
||||||
BT_UUID_OTS_TYPE_GROUP)) {
|
BT_UUID_OTS_TYPE_GROUP)) {
|
||||||
BT_DBG("Group Obj Type");
|
BT_DBG("Group Obj Type");
|
||||||
if (obj.add_type == MPL_OBJ_PARENT_GROUP) {
|
if (obj.add_type == MPL_OBJ_PARENT_GROUP) {
|
||||||
|
|
|
@ -46,6 +46,14 @@ config BT_OTS_MAX_OBJ_CNT
|
||||||
config BT_OTS_SECONDARY_SVC
|
config BT_OTS_SECONDARY_SVC
|
||||||
bool "Register OTS as Secondary Service"
|
bool "Register OTS as Secondary Service"
|
||||||
|
|
||||||
|
config BT_OTS_OACP_CREATE_SUPPORT
|
||||||
|
bool "Support OACP Create Operation"
|
||||||
|
depends on BT_OTS_OACP_WRITE_SUPPORT
|
||||||
|
depends on BT_OTS_OBJ_NAME_WRITE_SUPPORT
|
||||||
|
|
||||||
|
config BT_OTS_OACP_DELETE_SUPPORT
|
||||||
|
bool "Support OACP Delete Operation"
|
||||||
|
|
||||||
config BT_OTS_OACP_READ_SUPPORT
|
config BT_OTS_OACP_READ_SUPPORT
|
||||||
bool "Support OACP Read Operation"
|
bool "Support OACP Read Operation"
|
||||||
default y
|
default y
|
||||||
|
|
|
@ -30,6 +30,18 @@
|
||||||
|
|
||||||
LOG_MODULE_REGISTER(bt_ots, CONFIG_BT_OTS_LOG_LEVEL);
|
LOG_MODULE_REGISTER(bt_ots, CONFIG_BT_OTS_LOG_LEVEL);
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_OTS_OACP_CREATE_SUPPORT)
|
||||||
|
#define OACP_FEAT_BIT_CREATE BIT(BT_OTS_OACP_FEAT_CREATE)
|
||||||
|
#else
|
||||||
|
#define OACP_FEAT_BIT_CREATE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_OTS_OACP_DELETE_SUPPORT)
|
||||||
|
#define OACP_FEAT_BIT_DELETE BIT(BT_OTS_OACP_FEAT_DELETE)
|
||||||
|
#else
|
||||||
|
#define OACP_FEAT_BIT_DELETE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_BT_OTS_OACP_READ_SUPPORT)
|
#if defined(CONFIG_BT_OTS_OACP_READ_SUPPORT)
|
||||||
#define OACP_FEAT_BIT_READ BIT(BT_OTS_OACP_FEAT_READ)
|
#define OACP_FEAT_BIT_READ BIT(BT_OTS_OACP_FEAT_READ)
|
||||||
#else
|
#else
|
||||||
|
@ -50,6 +62,8 @@ LOG_MODULE_REGISTER(bt_ots, CONFIG_BT_OTS_LOG_LEVEL);
|
||||||
|
|
||||||
/* OACP features supported by Kconfig */
|
/* OACP features supported by Kconfig */
|
||||||
#define OACP_FEAT ( \
|
#define OACP_FEAT ( \
|
||||||
|
OACP_FEAT_BIT_CREATE | \
|
||||||
|
OACP_FEAT_BIT_DELETE | \
|
||||||
OACP_FEAT_BIT_READ | \
|
OACP_FEAT_BIT_READ | \
|
||||||
OACP_FEAT_BIT_WRITE | \
|
OACP_FEAT_BIT_WRITE | \
|
||||||
OACP_FEAT_BIT_PATCH)
|
OACP_FEAT_BIT_PATCH)
|
||||||
|
@ -200,14 +214,17 @@ static ssize_t ots_obj_type_read(struct bt_conn *conn,
|
||||||
}
|
}
|
||||||
|
|
||||||
obj_meta = &ots->cur_obj->metadata;
|
obj_meta = &ots->cur_obj->metadata;
|
||||||
if (obj_meta->type.uuid.type == BT_UUID_TYPE_128) {
|
switch (obj_meta->type.uuid.type) {
|
||||||
return bt_gatt_attr_read(conn, attr, buf, len, offset,
|
case BT_UUID_TYPE_16:
|
||||||
obj_meta->type.uuid_128.val,
|
|
||||||
sizeof(obj_meta->type.uuid_128.val));
|
|
||||||
} else {
|
|
||||||
return bt_gatt_attr_read(conn, attr, buf, len, offset,
|
return bt_gatt_attr_read(conn, attr, buf, len, offset,
|
||||||
&obj_meta->type.uuid_16.val,
|
&obj_meta->type.uuid_16.val,
|
||||||
sizeof(obj_meta->type.uuid_16.val));
|
sizeof(obj_meta->type.uuid_16.val));
|
||||||
|
case BT_UUID_TYPE_128:
|
||||||
|
return bt_gatt_attr_read(conn, attr, buf, len, offset,
|
||||||
|
obj_meta->type.uuid_128.val,
|
||||||
|
sizeof(obj_meta->type.uuid_128.val));
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,12 +288,13 @@ static ssize_t ots_obj_prop_read(struct bt_conn *conn,
|
||||||
sizeof(ots->cur_obj->metadata.props));
|
sizeof(ots->cur_obj->metadata.props));
|
||||||
}
|
}
|
||||||
|
|
||||||
int bt_ots_obj_add(struct bt_ots *ots,
|
int bt_ots_obj_add_internal(struct bt_ots *ots, struct bt_conn *conn,
|
||||||
struct bt_ots_obj_metadata *obj_init)
|
const struct bt_ots_obj_add_param *param,
|
||||||
|
struct bt_gatt_ots_object **obj)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct bt_gatt_ots_object *obj;
|
struct bt_gatt_ots_object *new_obj;
|
||||||
size_t name_len;
|
struct bt_ots_obj_created_desc created_desc;
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) && ots->dir_list &&
|
if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) && ots->dir_list &&
|
||||||
ots->dir_list->dir_list_obj->state.type != BT_GATT_OTS_OBJECT_IDLE_STATE) {
|
ots->dir_list->dir_list_obj->state.type != BT_GATT_OTS_OBJECT_IDLE_STATE) {
|
||||||
|
@ -284,50 +302,96 @@ int bt_ots_obj_add(struct bt_ots *ots,
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
name_len = strlen(obj_init->name);
|
err = bt_gatt_ots_obj_manager_obj_add(ots->obj_manager, &new_obj);
|
||||||
|
|
||||||
CHECKIF(name_len == 0 || name_len > CONFIG_BT_OTS_OBJ_MAX_NAME_LEN) {
|
|
||||||
LOG_DBG("Invalid name length %zu", name_len);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
CHECKIF(!ots_obj_validate_prop_against_oacp(obj_init->props, ots->features.oacp)) {
|
|
||||||
LOG_DBG("Object properties (0x%04X) are not a subset of OACP (0x%04X)",
|
|
||||||
obj_init->props, ots->features.oacp);
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = bt_gatt_ots_obj_manager_obj_add(ots->obj_manager, &obj);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_ERR("No space available in the object manager");
|
LOG_ERR("No space available in the object manager");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize object. */
|
|
||||||
memcpy(&obj->metadata, obj_init, sizeof(obj->metadata));
|
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)) {
|
if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)) {
|
||||||
bt_ots_dir_list_obj_add(ots->dir_list, ots->obj_manager, ots->cur_obj, obj);
|
bt_ots_dir_list_obj_add(ots->dir_list, ots->obj_manager, ots->cur_obj, new_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Request object data. */
|
(void)memset(&created_desc, 0, sizeof(created_desc));
|
||||||
|
|
||||||
if (ots->cb->obj_created) {
|
if (ots->cb->obj_created) {
|
||||||
err = ots->cb->obj_created(ots, NULL, obj->id, obj_init);
|
err = ots->cb->obj_created(ots, NULL, new_obj->id, param, &created_desc);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
bt_gatt_ots_obj_manager_obj_delete(obj);
|
(void)bt_gatt_ots_obj_manager_obj_delete(new_obj);
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)) {
|
if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)) {
|
||||||
bt_ots_dir_list_obj_remove(ots->dir_list, ots->obj_manager,
|
bt_ots_dir_list_obj_remove(ots->dir_list, ots->obj_manager,
|
||||||
ots->cur_obj, obj);
|
ots->cur_obj, new_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ots_obj_validate_prop_against_oacp(created_desc.props, ots->features.oacp)) {
|
||||||
|
LOG_ERR("Object properties (0x%04X) are not a subset of OACP (0x%04X)",
|
||||||
|
created_desc.props, ots->features.oacp);
|
||||||
|
|
||||||
|
(void)bt_ots_obj_delete(ots, new_obj->id);
|
||||||
|
return -ECANCELED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (created_desc.name == NULL) {
|
||||||
|
LOG_ERR("Object name must be set by application after object creation.");
|
||||||
|
|
||||||
|
(void)bt_ots_obj_delete(ots, new_obj->id);
|
||||||
|
return -ECANCELED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (created_desc.size.alloc < param->size) {
|
||||||
|
LOG_ERR("Object allocated size must >= requested size.");
|
||||||
|
|
||||||
|
(void)bt_ots_obj_delete(ots, new_obj->id);
|
||||||
|
return -ECANCELED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new_obj->metadata.type = param->type;
|
||||||
|
new_obj->metadata.name = created_desc.name;
|
||||||
|
new_obj->metadata.size = created_desc.size;
|
||||||
|
new_obj->metadata.props = created_desc.props;
|
||||||
|
|
||||||
|
if (obj) {
|
||||||
|
*obj = new_obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bt_ots_obj_add(struct bt_ots *ots, const struct bt_ots_obj_add_param *param)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
size_t name_len;
|
||||||
|
struct bt_gatt_ots_object *obj;
|
||||||
|
|
||||||
|
err = bt_ots_obj_add_internal(ots, NULL, param, &obj);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
name_len = strlen(obj->metadata.name);
|
||||||
|
if (name_len == 0 || name_len > CONFIG_BT_OTS_OBJ_MAX_NAME_LEN) {
|
||||||
|
LOG_ERR("Invalid name length %zu", name_len);
|
||||||
|
|
||||||
|
(void)bt_ots_obj_delete(ots, obj->id);
|
||||||
|
return -ECANCELED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj->metadata.size.cur > param->size) {
|
||||||
|
LOG_ERR("Object current size must be less than or equal to requested size.");
|
||||||
|
|
||||||
|
(void)bt_ots_obj_delete(ots, obj->id);
|
||||||
|
return -ECANCELED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj->id;
|
||||||
|
}
|
||||||
|
|
||||||
int bt_ots_obj_delete(struct bt_ots *ots, uint64_t id)
|
int bt_ots_obj_delete(struct bt_ots *ots, uint64_t id)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -338,12 +402,9 @@ int bt_ots_obj_delete(struct bt_ots *ots, uint64_t id)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ots->cur_obj == obj) {
|
|
||||||
if (obj->state.type != BT_GATT_OTS_OBJECT_IDLE_STATE) {
|
if (obj->state.type != BT_GATT_OTS_OBJECT_IDLE_STATE) {
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
ots->cur_obj = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) && ots->dir_list &&
|
if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) && ots->dir_list &&
|
||||||
ots->dir_list->dir_list_obj->state.type != BT_GATT_OTS_OBJECT_IDLE_STATE) {
|
ots->dir_list->dir_list_obj->state.type != BT_GATT_OTS_OBJECT_IDLE_STATE) {
|
||||||
|
@ -351,6 +412,13 @@ int bt_ots_obj_delete(struct bt_ots *ots, uint64_t id)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ots->cb->obj_deleted) {
|
||||||
|
err = ots->cb->obj_deleted(ots, NULL, obj->id);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = bt_gatt_ots_obj_manager_obj_delete(obj);
|
err = bt_gatt_ots_obj_manager_obj_delete(obj);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
|
@ -360,8 +428,8 @@ int bt_ots_obj_delete(struct bt_ots *ots, uint64_t id)
|
||||||
bt_ots_dir_list_obj_remove(ots->dir_list, ots->obj_manager, ots->cur_obj, obj);
|
bt_ots_dir_list_obj_remove(ots->dir_list, ots->obj_manager, ots->cur_obj, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ots->cb->obj_deleted) {
|
if (ots->cur_obj == obj) {
|
||||||
ots->cb->obj_deleted(ots, NULL, obj->id);
|
ots->cur_obj = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -385,6 +453,9 @@ int bt_ots_init(struct bt_ots *ots,
|
||||||
|
|
||||||
__ASSERT(ots_init->cb->obj_created,
|
__ASSERT(ots_init->cb->obj_created,
|
||||||
"Callback for object creation is not set");
|
"Callback for object creation is not set");
|
||||||
|
__ASSERT(ots_init->cb->obj_deleted ||
|
||||||
|
!BT_OTS_OACP_GET_FEAT_CREATE(ots_init->features.oacp),
|
||||||
|
"Callback for object deletion is not set and object creation is enabled");
|
||||||
__ASSERT(ots_init->cb->obj_read ||
|
__ASSERT(ots_init->cb->obj_read ||
|
||||||
!BT_OTS_OACP_GET_FEAT_READ(ots_init->features.oacp),
|
!BT_OTS_OACP_GET_FEAT_READ(ots_init->features.oacp),
|
||||||
"Callback for object reading is not set");
|
"Callback for object reading is not set");
|
||||||
|
@ -400,6 +471,10 @@ int bt_ots_init(struct bt_ots *ots,
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__ASSERT(!BT_OTS_OACP_GET_FEAT_CREATE(ots_init->features.oacp) ||
|
||||||
|
BT_OTS_OACP_GET_FEAT_WRITE(ots_init->features.oacp),
|
||||||
|
"Object creation requires object write to be supported");
|
||||||
|
|
||||||
ots->features.oacp = ots_init->features.oacp;
|
ots->features.oacp = ots_init->features.oacp;
|
||||||
LOG_DBG("OACP features: 0x%04X", ots->features.oacp);
|
LOG_DBG("OACP features: 0x%04X", ots->features.oacp);
|
||||||
|
|
||||||
|
@ -495,6 +570,69 @@ BT_GATT_SERVICE_INSTANCE_DEFINE(ots_service_list, ots_instances,
|
||||||
CONFIG_BT_OTS_MAX_INST_CNT,
|
CONFIG_BT_OTS_MAX_INST_CNT,
|
||||||
BT_GATT_OTS_ATTRS);
|
BT_GATT_OTS_ATTRS);
|
||||||
|
|
||||||
|
static void ots_delete_empty_name_objects(struct bt_ots *ots, struct bt_conn *conn)
|
||||||
|
{
|
||||||
|
char id_str[BT_OTS_OBJ_ID_STR_LEN];
|
||||||
|
struct bt_gatt_ots_object *obj;
|
||||||
|
struct bt_gatt_ots_object *next_obj;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = bt_gatt_ots_obj_manager_first_obj_get(ots->obj_manager, &next_obj);
|
||||||
|
while (!err) {
|
||||||
|
obj = next_obj;
|
||||||
|
|
||||||
|
/* Get the next object before we potentially delete the current object and
|
||||||
|
* no longer can get the next object
|
||||||
|
*/
|
||||||
|
err = bt_gatt_ots_obj_manager_next_obj_get(ots->obj_manager, obj, &next_obj);
|
||||||
|
|
||||||
|
if (strlen(obj->metadata.name) == 0) {
|
||||||
|
bt_ots_obj_id_to_str(obj->id, id_str, sizeof(id_str));
|
||||||
|
LOG_DBG("Deleting object with %s ID due to empty name", log_strdup(id_str));
|
||||||
|
|
||||||
|
if (ots->cb && ots->cb->obj_deleted) {
|
||||||
|
ots->cb->obj_deleted(ots, conn, obj->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)) {
|
||||||
|
bt_ots_dir_list_obj_remove(ots->dir_list, ots->obj_manager,
|
||||||
|
ots->cur_obj, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bt_gatt_ots_obj_manager_obj_delete(obj)) {
|
||||||
|
LOG_ERR("Failed to remove object with %s ID from object manager",
|
||||||
|
log_strdup(id_str));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ots_conn_disconnected(struct bt_conn *conn, uint8_t reason)
|
||||||
|
{
|
||||||
|
uint32_t index;
|
||||||
|
struct bt_ots *instance;
|
||||||
|
|
||||||
|
for (instance = BT_GATT_OTS_INSTANCE_LIST_START, index = 0;
|
||||||
|
index < instance_cnt;
|
||||||
|
instance++, index++) {
|
||||||
|
|
||||||
|
LOG_DBG("Processing disconnect for OTS instance %u", index);
|
||||||
|
|
||||||
|
if (instance->cur_obj != NULL) {
|
||||||
|
__ASSERT(instance->cur_obj->state.type == BT_GATT_OTS_OBJECT_IDLE_STATE,
|
||||||
|
"The current object is expected to be in idle state as part "
|
||||||
|
"of cleanup of the L2CAP channel connection close.");
|
||||||
|
instance->cur_obj = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ots_delete_empty_name_objects(instance, conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BT_CONN_CB_DEFINE(conn_callbacks) = {
|
||||||
|
.disconnected = ots_conn_disconnected,
|
||||||
|
};
|
||||||
|
|
||||||
struct bt_ots *bt_ots_free_instance_get(void)
|
struct bt_ots *bt_ots_free_instance_get(void)
|
||||||
{
|
{
|
||||||
if (instance_cnt >= BT_GATT_OTS_INSTANCE_LIST_SIZE) {
|
if (instance_cnt >= BT_GATT_OTS_INSTANCE_LIST_SIZE) {
|
||||||
|
|
|
@ -64,6 +64,21 @@ struct bt_gatt_ots_object_state {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @brief Descriptor for OTS object initialization. */
|
||||||
|
struct bt_ots_obj_metadata {
|
||||||
|
/* Object Name */
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
/* Object Type */
|
||||||
|
struct bt_ots_obj_type type;
|
||||||
|
|
||||||
|
/* Object Size */
|
||||||
|
struct bt_ots_obj_size size;
|
||||||
|
|
||||||
|
/* Object Properties */
|
||||||
|
uint32_t props;
|
||||||
|
};
|
||||||
|
|
||||||
struct bt_gatt_ots_object {
|
struct bt_gatt_ots_object {
|
||||||
uint64_t id;
|
uint64_t id;
|
||||||
struct bt_ots_obj_metadata metadata;
|
struct bt_ots_obj_metadata metadata;
|
||||||
|
@ -89,6 +104,9 @@ struct bt_ots {
|
||||||
void *obj_manager;
|
void *obj_manager;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int bt_ots_obj_add_internal(struct bt_ots *ots, struct bt_conn *conn,
|
||||||
|
const struct bt_ots_obj_add_param *param,
|
||||||
|
struct bt_gatt_ots_object **obj);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <bluetooth/services/ots.h>
|
#include <bluetooth/services/ots.h>
|
||||||
#include "ots_internal.h"
|
#include "ots_internal.h"
|
||||||
#include "ots_dir_list_internal.h"
|
#include "ots_dir_list_internal.h"
|
||||||
|
#include "ots_obj_manager_internal.h"
|
||||||
|
|
||||||
#include <logging/log.h>
|
#include <logging/log.h>
|
||||||
|
|
||||||
|
@ -45,6 +46,121 @@ static void oacp_l2cap_closed(struct bt_gatt_ots_l2cap *l2cap_ctx,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_OTS_OACP_CREATE_SUPPORT)
|
||||||
|
static enum bt_gatt_ots_oacp_res_code oacp_create_proc_validate(
|
||||||
|
struct bt_conn *conn,
|
||||||
|
struct bt_ots *ots,
|
||||||
|
struct bt_gatt_ots_oacp_proc *proc)
|
||||||
|
{
|
||||||
|
char str[BT_UUID_STR_LEN];
|
||||||
|
int err;
|
||||||
|
struct bt_gatt_ots_object *obj;
|
||||||
|
const struct bt_ots_obj_add_param param = {
|
||||||
|
.size = proc->create_params.size,
|
||||||
|
.type = proc->create_params.type,
|
||||||
|
};
|
||||||
|
|
||||||
|
bt_uuid_to_str(¶m.type.uuid, str, BT_UUID_STR_LEN);
|
||||||
|
LOG_DBG("Validating Create procedure with size: 0x%08X and "
|
||||||
|
"type: %s", param.size, log_strdup(str));
|
||||||
|
|
||||||
|
if (!BT_OTS_OACP_GET_FEAT_CREATE(ots->features.oacp)) {
|
||||||
|
LOG_DBG("Create Procedure is not supported.");
|
||||||
|
return BT_GATT_OTS_OACP_RES_OPCODE_NOT_SUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bt_ots_obj_add_internal(ots, conn, ¶m, &obj);
|
||||||
|
if (err) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify Initialization Metadata */
|
||||||
|
if (strlen(obj->metadata.name) > 0) {
|
||||||
|
LOG_ERR("Object name shall be a zero length string after object creation.");
|
||||||
|
(void)bt_ots_obj_delete(ots, obj->id);
|
||||||
|
err = -ECANCELED;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj->metadata.size.cur > 0) {
|
||||||
|
LOG_ERR("Object current size must be 0.");
|
||||||
|
(void)bt_ots_obj_delete(ots, obj->id);
|
||||||
|
err = -ECANCELED;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!BT_OTS_OBJ_GET_PROP_WRITE(obj->metadata.props)) {
|
||||||
|
LOG_ERR("Created object must have write property.");
|
||||||
|
(void)bt_ots_obj_delete(ots, obj->id);
|
||||||
|
err = -ECANCELED;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ots->cur_obj = obj;
|
||||||
|
ots->cur_obj->state.type = BT_GATT_OTS_OBJECT_IDLE_STATE;
|
||||||
|
|
||||||
|
LOG_DBG("Create procedure is complete");
|
||||||
|
|
||||||
|
exit:
|
||||||
|
switch (err) {
|
||||||
|
case 0:
|
||||||
|
return BT_GATT_OTS_OACP_RES_SUCCESS;
|
||||||
|
case -ENOTSUP:
|
||||||
|
return BT_GATT_OTS_OACP_RES_UNSUP_TYPE;
|
||||||
|
case -ENOMEM:
|
||||||
|
return BT_GATT_OTS_OACP_RES_INSUFF_RES;
|
||||||
|
case -EINVAL:
|
||||||
|
return BT_GATT_OTS_OACP_RES_INV_PARAM;
|
||||||
|
case -ECANCELED:
|
||||||
|
default:
|
||||||
|
return BT_GATT_OTS_OACP_RES_OPER_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_OTS_OACP_DELETE_SUPPORT)
|
||||||
|
static enum bt_gatt_ots_oacp_res_code oacp_delete_proc_validate(
|
||||||
|
struct bt_conn *conn,
|
||||||
|
struct bt_ots *ots,
|
||||||
|
struct bt_gatt_ots_oacp_proc *proc)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!BT_OTS_OACP_GET_FEAT_DELETE(ots->features.oacp)) {
|
||||||
|
LOG_DBG("Delete Procedure is not supported.");
|
||||||
|
return BT_GATT_OTS_OACP_RES_OPCODE_NOT_SUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ots->cur_obj) {
|
||||||
|
LOG_DBG("No object is selected.");
|
||||||
|
return BT_GATT_OTS_OACP_RES_INV_OBJ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!BT_OTS_OBJ_GET_PROP_DELETE(ots->cur_obj->metadata.props)) {
|
||||||
|
LOG_DBG("Object properties do not permit deletion.");
|
||||||
|
return BT_GATT_OTS_OACP_RES_NOT_PERMITTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bt_ots_obj_delete(ots, ots->cur_obj->id);
|
||||||
|
if (err) {
|
||||||
|
LOG_ERR("Deleting object during Delete procedure failed: %d", err);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DBG("Delete procedure is complete");
|
||||||
|
|
||||||
|
exit:
|
||||||
|
switch (err) {
|
||||||
|
case 0:
|
||||||
|
return BT_GATT_OTS_OACP_RES_SUCCESS;
|
||||||
|
case -EBUSY:
|
||||||
|
return BT_GATT_OTS_OACP_RES_OBJ_LOCKED;
|
||||||
|
default:
|
||||||
|
return BT_GATT_OTS_OACP_RES_OPER_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static enum bt_gatt_ots_oacp_res_code oacp_read_proc_validate(
|
static enum bt_gatt_ots_oacp_res_code oacp_read_proc_validate(
|
||||||
struct bt_conn *conn,
|
struct bt_conn *conn,
|
||||||
struct bt_ots *ots,
|
struct bt_ots *ots,
|
||||||
|
@ -162,12 +278,18 @@ static enum bt_gatt_ots_oacp_res_code oacp_proc_validate(
|
||||||
switch (proc->type) {
|
switch (proc->type) {
|
||||||
case BT_GATT_OTS_OACP_PROC_READ:
|
case BT_GATT_OTS_OACP_PROC_READ:
|
||||||
return oacp_read_proc_validate(conn, ots, proc);
|
return oacp_read_proc_validate(conn, ots, proc);
|
||||||
case BT_GATT_OTS_OACP_PROC_WRITE:
|
|
||||||
#if defined(CONFIG_BT_OTS_OACP_WRITE_SUPPORT)
|
#if defined(CONFIG_BT_OTS_OACP_WRITE_SUPPORT)
|
||||||
|
case BT_GATT_OTS_OACP_PROC_WRITE:
|
||||||
return oacp_write_proc_validate(conn, ots, proc);
|
return oacp_write_proc_validate(conn, ots, proc);
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(CONFIG_BT_OTS_OACP_CREATE_SUPPORT)
|
||||||
case BT_GATT_OTS_OACP_PROC_CREATE:
|
case BT_GATT_OTS_OACP_PROC_CREATE:
|
||||||
|
return oacp_create_proc_validate(conn, ots, proc);
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_BT_OTS_OACP_DELETE_SUPPORT)
|
||||||
case BT_GATT_OTS_OACP_PROC_DELETE:
|
case BT_GATT_OTS_OACP_PROC_DELETE:
|
||||||
|
return oacp_delete_proc_validate(conn, ots, proc);
|
||||||
|
#endif
|
||||||
case BT_GATT_OTS_OACP_PROC_CHECKSUM_CALC:
|
case BT_GATT_OTS_OACP_PROC_CHECKSUM_CALC:
|
||||||
case BT_GATT_OTS_OACP_PROC_EXECUTE:
|
case BT_GATT_OTS_OACP_PROC_EXECUTE:
|
||||||
case BT_GATT_OTS_OACP_PROC_ABORT:
|
case BT_GATT_OTS_OACP_PROC_ABORT:
|
||||||
|
@ -186,14 +308,18 @@ static enum bt_gatt_ots_oacp_res_code oacp_command_decode(
|
||||||
|
|
||||||
proc->type = net_buf_simple_pull_u8(&net_buf);
|
proc->type = net_buf_simple_pull_u8(&net_buf);
|
||||||
switch (proc->type) {
|
switch (proc->type) {
|
||||||
|
#if defined(CONFIG_BT_OTS_OACP_CREATE_SUPPORT)
|
||||||
case BT_GATT_OTS_OACP_PROC_CREATE:
|
case BT_GATT_OTS_OACP_PROC_CREATE:
|
||||||
proc->create_params.size = net_buf_simple_pull_le32(&net_buf);
|
proc->create_params.size = net_buf_simple_pull_le32(&net_buf);
|
||||||
bt_uuid_create(&proc->create_params.type.uuid, net_buf.data,
|
bt_uuid_create(&proc->create_params.type.uuid, net_buf.data,
|
||||||
net_buf.len);
|
net_buf.len);
|
||||||
net_buf_simple_pull_mem(&net_buf, net_buf.len);
|
net_buf_simple_pull_mem(&net_buf, net_buf.len);
|
||||||
break;
|
return BT_GATT_OTS_OACP_RES_SUCCESS;
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_BT_OTS_OACP_DELETE_SUPPORT)
|
||||||
case BT_GATT_OTS_OACP_PROC_DELETE:
|
case BT_GATT_OTS_OACP_PROC_DELETE:
|
||||||
break;
|
return BT_GATT_OTS_OACP_RES_SUCCESS;
|
||||||
|
#endif
|
||||||
case BT_GATT_OTS_OACP_PROC_CHECKSUM_CALC:
|
case BT_GATT_OTS_OACP_PROC_CHECKSUM_CALC:
|
||||||
proc->cs_calc_params.offset =
|
proc->cs_calc_params.offset =
|
||||||
net_buf_simple_pull_le32(&net_buf);
|
net_buf_simple_pull_le32(&net_buf);
|
||||||
|
@ -208,8 +334,8 @@ static enum bt_gatt_ots_oacp_res_code oacp_command_decode(
|
||||||
proc->read_params.len =
|
proc->read_params.len =
|
||||||
net_buf_simple_pull_le32(&net_buf);
|
net_buf_simple_pull_le32(&net_buf);
|
||||||
return BT_GATT_OTS_OACP_RES_SUCCESS;
|
return BT_GATT_OTS_OACP_RES_SUCCESS;
|
||||||
case BT_GATT_OTS_OACP_PROC_WRITE:
|
|
||||||
#if defined(CONFIG_BT_OTS_OACP_WRITE_SUPPORT)
|
#if defined(CONFIG_BT_OTS_OACP_WRITE_SUPPORT)
|
||||||
|
case BT_GATT_OTS_OACP_PROC_WRITE:
|
||||||
proc->write_params.offset =
|
proc->write_params.offset =
|
||||||
net_buf_simple_pull_le32(&net_buf);
|
net_buf_simple_pull_le32(&net_buf);
|
||||||
proc->write_params.len =
|
proc->write_params.len =
|
||||||
|
@ -217,8 +343,6 @@ static enum bt_gatt_ots_oacp_res_code oacp_command_decode(
|
||||||
proc->write_params.mode =
|
proc->write_params.mode =
|
||||||
net_buf_simple_pull_u8(&net_buf);
|
net_buf_simple_pull_u8(&net_buf);
|
||||||
return BT_GATT_OTS_OACP_RES_SUCCESS;
|
return BT_GATT_OTS_OACP_RES_SUCCESS;
|
||||||
#else
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
case BT_GATT_OTS_OACP_PROC_ABORT:
|
case BT_GATT_OTS_OACP_PROC_ABORT:
|
||||||
default:
|
default:
|
||||||
|
@ -243,9 +367,6 @@ static bool oacp_command_len_verify(struct bt_gatt_ots_oacp_proc *proc,
|
||||||
case BT_UUID_TYPE_16:
|
case BT_UUID_TYPE_16:
|
||||||
ref_len += BT_GATT_OTS_OACP_CREATE_UUID16_PARAMS_SIZE;
|
ref_len += BT_GATT_OTS_OACP_CREATE_UUID16_PARAMS_SIZE;
|
||||||
break;
|
break;
|
||||||
case BT_UUID_TYPE_32:
|
|
||||||
ref_len += BT_GATT_OTS_OACP_CREATE_UUID32_PARAMS_SIZE;
|
|
||||||
break;
|
|
||||||
case BT_UUID_TYPE_128:
|
case BT_UUID_TYPE_128:
|
||||||
ref_len += BT_GATT_OTS_OACP_CREATE_UUID128_PARAMS_SIZE;
|
ref_len += BT_GATT_OTS_OACP_CREATE_UUID128_PARAMS_SIZE;
|
||||||
break;
|
break;
|
||||||
|
@ -443,6 +564,11 @@ static void oacp_ind_cb(struct bt_conn *conn,
|
||||||
|
|
||||||
LOG_DBG("Received OACP Indication ACK with status: 0x%04X", err);
|
LOG_DBG("Received OACP Indication ACK with status: 0x%04X", err);
|
||||||
|
|
||||||
|
if (!ots->cur_obj) {
|
||||||
|
LOG_DBG("There is no object associated with this ACK");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (ots->cur_obj->state.type) {
|
switch (ots->cur_obj->state.type) {
|
||||||
case BT_GATT_OTS_OBJECT_READ_OP_STATE:
|
case BT_GATT_OTS_OBJECT_READ_OP_STATE:
|
||||||
oacp_read_proc_execute(ots, conn);
|
oacp_read_proc_execute(ots, conn);
|
||||||
|
@ -450,6 +576,9 @@ static void oacp_ind_cb(struct bt_conn *conn,
|
||||||
case BT_GATT_OTS_OBJECT_WRITE_OP_STATE:
|
case BT_GATT_OTS_OBJECT_WRITE_OP_STATE:
|
||||||
/* procedure execution is driven by L2CAP socket receive */
|
/* procedure execution is driven by L2CAP socket receive */
|
||||||
break;
|
break;
|
||||||
|
case BT_GATT_OTS_OBJECT_IDLE_STATE:
|
||||||
|
/* procedure is not in progress and was already completed */
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_ERR("Unsupported OTS state: %d", ots->cur_obj->state.type);
|
LOG_ERR("Unsupported OTS state: %d", ots->cur_obj->state.type);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -92,14 +92,16 @@ struct bt_gatt_ots_oacp_proc {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Size of Object Action Control Point create procedure with 16-bit UUID object type */
|
/* Size of the generic part of the Object Action Control Point create procedure */
|
||||||
#define BT_GATT_OTS_OACP_CREATE_UUID16_PARAMS_SIZE 7
|
#define BT_GATT_OTS_OACP_CREATE_GENERIC_PARAMS_SIZE 4
|
||||||
|
|
||||||
/* Size of Object Action Control Point create procedure with 32-bit UUID object type */
|
/* Size of Object Action Control Point create procedure with 16-bit UUID object type */
|
||||||
#define BT_GATT_OTS_OACP_CREATE_UUID32_PARAMS_SIZE 9
|
#define BT_GATT_OTS_OACP_CREATE_UUID16_PARAMS_SIZE \
|
||||||
|
(BT_GATT_OTS_OACP_CREATE_GENERIC_PARAMS_SIZE + BT_UUID_SIZE_16)
|
||||||
|
|
||||||
/* Size of Object Action Control Point create procedure with 128-bit UUID object type */
|
/* Size of Object Action Control Point create procedure with 128-bit UUID object type */
|
||||||
#define BT_GATT_OTS_OACP_CREATE_UUID128_PARAMS_SIZE 21
|
#define BT_GATT_OTS_OACP_CREATE_UUID128_PARAMS_SIZE \
|
||||||
|
(BT_GATT_OTS_OACP_CREATE_GENERIC_PARAMS_SIZE + BT_UUID_SIZE_128)
|
||||||
|
|
||||||
/* Size of Object Action Control Point checksum calculation procedure */
|
/* Size of Object Action Control Point checksum calculation procedure */
|
||||||
#define BT_GATT_OTS_OACP_CS_CALC_PARAMS_SIZE 8
|
#define BT_GATT_OTS_OACP_CS_CALC_PARAMS_SIZE 8
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue