From a6f932a194c3e0b17b1d5508938207e95920a427 Mon Sep 17 00:00:00 2001 From: Abe Kohandel Date: Mon, 22 Nov 2021 06:32:47 -0800 Subject: [PATCH] bluetooth: ots: Add Create and Delete procedures Add the ability to perform an OTS Create or Delete Procedure. Signed-off-by: Abe Kohandel --- include/bluetooth/services/ots.h | 103 ++++++--- samples/bluetooth/peripheral_ots/prj.conf | 2 + samples/bluetooth/peripheral_ots/src/main.c | 98 +++++--- subsys/bluetooth/audio/mpl.c | 133 +++++++---- subsys/bluetooth/services/ots/Kconfig | 8 + subsys/bluetooth/services/ots/ots.c | 214 ++++++++++++++---- subsys/bluetooth/services/ots/ots_internal.h | 18 ++ subsys/bluetooth/services/ots/ots_oacp.c | 147 +++++++++++- .../services/ots/ots_oacp_internal.h | 12 +- 9 files changed, 572 insertions(+), 163 deletions(-) diff --git a/include/bluetooth/services/ots.h b/include/bluetooth/services/ots.h index e4f924069c3..632985d2a27 100644 --- a/include/bluetooth/services/ots.h +++ b/include/bluetooth/services/ots.h @@ -215,21 +215,6 @@ struct bt_ots_obj_size { uint32_t alloc; } __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. */ enum { /** Bit 0 OACP Create Op Code Supported */ @@ -486,6 +471,48 @@ struct bt_ots_feat { /** @brief Opaque OTS instance. */ 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. */ struct bt_ots_cb { /** @brief Object created callback @@ -496,20 +523,23 @@ struct bt_ots_cb { * object. This callback is also triggered when the server * creates a new object with bt_ots_obj_add() API. * - * @param ots OTS instance. - * @param conn The connection that is requesting object creation or - * NULL if object is created by the following function: - * bt_ots_obj_add(). - * @param id Object ID. - * @param init Object initialization metadata. + * @param ots OTS instance. + * @param conn The connection that is requesting object creation or + * NULL if object is created by bt_ots_obj_add(). + * @param id Object ID. + * @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. - * Possible return values: - * -ENOMEM if no available space for new object. + * @return -ENOTSUP if object type is not supported + * @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, - uint64_t id, - const struct bt_ots_obj_metadata *init); + int (*obj_created)(struct bt_ots *ots, struct bt_conn *conn, uint64_t id, + const struct bt_ots_obj_add_param *add_param, + struct bt_ots_obj_created_desc *created_desc); /** @brief Object deleted callback * @@ -521,9 +551,19 @@ struct bt_ots_cb { * @param conn The connection that deleted the object or NULL if * this request came from the server. * @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, - uint64_t id); + int (*obj_deleted)(struct bt_ots *ots, struct bt_conn *conn, + uint64_t id); /** @brief Object selected callback * @@ -621,11 +661,12 @@ struct bt_ots_init { * to notify the user about a new object ID. * * @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. * diff --git a/samples/bluetooth/peripheral_ots/prj.conf b/samples/bluetooth/peripheral_ots/prj.conf index 83785cb0a37..4269e395cfd 100644 --- a/samples/bluetooth/peripheral_ots/prj.conf +++ b/samples/bluetooth/peripheral_ots/prj.conf @@ -6,6 +6,8 @@ CONFIG_BT_OTS_DIR_LIST_OBJ=y CONFIG_BT_OTS_OBJ_NAME_WRITE_SUPPORT=y CONFIG_BT_OTS_OACP_WRITE_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_ASSERT=y diff --git a/samples/bluetooth/peripheral_ots/src/main.c b/samples/bluetooth/peripheral_ots/src/main.c index 2216bdf02e8..9f3446787b3 100644 --- a/samples/bluetooth/peripheral_ots/src/main.c +++ b/samples/bluetooth/peripheral_ots/src/main.c @@ -19,7 +19,7 @@ #define DEVICE_NAME CONFIG_BT_DEVICE_NAME #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 static const struct bt_data ad[] = { @@ -37,6 +37,14 @@ static struct { } objects[OBJ_POOL_SIZE]; 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) { if (err) { @@ -57,11 +65,12 @@ BT_CONN_CB_DEFINE(conn_callbacks) = { .disconnected = disconnected, }; -static int ots_obj_created(struct bt_ots *ots, struct bt_conn *conn, - uint64_t id, - const struct bt_ots_obj_metadata *init) +static int ots_obj_created(struct bt_ots *ots, struct bt_conn *conn, uint64_t id, + const struct bt_ots_obj_add_param *add_param, + struct bt_ots_obj_created_desc *created_desc) { char id_str[BT_OTS_OBJ_ID_STR_LEN]; + uint64_t index; 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; } - 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", id_str); 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); obj_cnt++; 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) { 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); obj_cnt--; + + return 0; } 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", 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; } @@ -177,8 +204,9 @@ static int ots_init(void) { int err; struct bt_ots *ots; + struct object_creation_data obj_data; 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 second_object_name = "second_object.gif"; uint32_t cur_size; @@ -191,9 +219,11 @@ static int ots_init(void) } /* 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_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_OLCP_SET_FEAT_GO_TO(ots_init.features.olcp); ots_init.cb = &ots_callbacks; @@ -212,22 +242,25 @@ static int ots_init(void) 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, "Object name length is larger than the allowed maximum of %u", CONFIG_BT_OTS_OBJ_MAX_NAME_LEN); - strcpy(objects[0].name, first_object_name); - obj_init.name = objects[0].name; - obj_init.type.uuid.type = BT_UUID_TYPE_16; - obj_init.type.uuid_16.val = BT_UUID_OTS_TYPE_UNSPECIFIED_VAL; - obj_init.size.cur = cur_size; - obj_init.size.alloc = alloc_size; - BT_OTS_OBJ_SET_PROP_READ(obj_init.props); - BT_OTS_OBJ_SET_PROP_WRITE(obj_init.props); - BT_OTS_OBJ_SET_PROP_PATCH(obj_init.props); + (void)strcpy(objects[0].name, first_object_name); + obj_data.name = objects[0].name; + obj_data.size.cur = cur_size; + obj_data.size.alloc = alloc_size; + BT_OTS_OBJ_SET_PROP_READ(obj_data.props); + BT_OTS_OBJ_SET_PROP_WRITE(obj_data.props); + BT_OTS_OBJ_SET_PROP_PATCH(obj_data.props); + object_being_created = &obj_data; - err = bt_ots_obj_add(ots, &obj_init); - if (err) { + param.size = alloc_size; + 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); return err; } @@ -239,20 +272,23 @@ static int ots_init(void) 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, "Object name length is larger than the allowed maximum of %u", CONFIG_BT_OTS_OBJ_MAX_NAME_LEN); - strcpy(objects[1].name, second_object_name); - obj_init.name = objects[1].name; - obj_init.type.uuid.type = BT_UUID_TYPE_16; - obj_init.type.uuid_16.val = BT_UUID_OTS_TYPE_UNSPECIFIED_VAL; - obj_init.size.cur = cur_size; - obj_init.size.alloc = alloc_size; - BT_OTS_OBJ_SET_PROP_READ(obj_init.props); + (void)strcpy(objects[1].name, second_object_name); + obj_data.name = objects[1].name; + obj_data.size.cur = cur_size; + obj_data.size.alloc = alloc_size; + BT_OTS_OBJ_SET_PROP_READ(obj_data.props); + object_being_created = &obj_data; - err = bt_ots_obj_add(ots, &obj_init); - if (err) { + param.size = alloc_size; + 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); return err; } diff --git a/subsys/bluetooth/audio/mpl.c b/subsys/bluetooth/audio/mpl.c index d37be0d9a8b..e282ccaeb2e 100644 --- a/subsys/bluetooth/audio/mpl.c +++ b/subsys/bluetooth/audio/mpl.c @@ -261,14 +261,24 @@ enum mpl_objects { /* And, except for the icon object, all objects can be created dynamically. */ /* So a single buffer to hold object content is sufficient. */ struct obj_t { - uint64_t selected_id; /* ID of the currently selected object*/ - bool busy; - uint8_t add_type; /* Type of object being added, e.g. MPL_OBJ_ICON */ + /* ID of the currently selected object*/ + uint64_t selected_id; + + bool busy; + + /* 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 { - struct mpl_track *add_track; /* Pointer to track being added */ - struct mpl_group *add_group; /* Pointer to group being added */ + /* Pointer to track 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; }; static struct obj_t obj = { @@ -440,7 +450,8 @@ static uint32_t setup_group_object(struct mpl_group *group) static int add_icon_object(struct mpl_mediaplayer *pl) { 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; static char *icon_name = "Icon"; @@ -452,14 +463,17 @@ static int add_icon_object(struct mpl_mediaplayer *pl) } obj.busy = true; obj.add_type = MPL_OBJ_ICON; + obj.desc = &created_desc; - icon.size.alloc = icon.size.cur = setup_icon_object(); - icon.name = icon_name; - icon.type.uuid.type = BT_UUID_TYPE_16; - icon.type.uuid_16.val = BT_UUID_16(icon_type)->val; - BT_OTS_OBJ_SET_PROP_READ(icon.props); + obj.desc->size.alloc = obj.desc->size.cur = setup_icon_object(); + obj.desc->name = icon_name; + BT_OTS_OBJ_SET_PROP_READ(obj.desc->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) { 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) { 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; if (obj.busy) { @@ -481,14 +496,17 @@ static int add_current_track_segments_object(struct mpl_mediaplayer *pl) } obj.busy = true; obj.add_type = MPL_OBJ_TRACK_SEGMENTS; + obj.desc = &created_desc; - segs.size.alloc = segs.size.cur = setup_segments_object(pl->group->track); - segs.name = pl->group->track->title; - segs.type.uuid.type = BT_UUID_TYPE_16; - segs.type.uuid_16.val = BT_UUID_16(segs_type)->val; - BT_OTS_OBJ_SET_PROP_READ(segs.props); + obj.desc->size.alloc = obj.desc->size.cur = setup_segments_object(pl->group->track); + obj.desc->name = pl->group->track->title; + BT_OTS_OBJ_SET_PROP_READ(obj.desc->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) { BT_WARN("Unable to add track segments object: %d", ret); 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 */ 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; int ret; @@ -516,13 +535,17 @@ static int add_track_object(struct mpl_track *track) obj.add_type = MPL_OBJ_TRACK; obj.add_track = track; + obj.desc = &created_desc; - track_meta.size.alloc = track_meta.size.cur = setup_track_object(track); - track_meta.name = track->title; - track_meta.type.uuid.type = BT_UUID_TYPE_16; - track_meta.type.uuid_16.val = BT_UUID_16(track_type)->val; - BT_OTS_OBJ_SET_PROP_READ(track_meta.props); - ret = bt_ots_obj_add(bt_mcs_get_ots(), &track_meta); + obj.desc->size.alloc = obj.desc->size.cur = setup_track_object(track); + obj.desc->name = track->title; + BT_OTS_OBJ_SET_PROP_READ(obj.desc->props); + + 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(track_type)->val; + + ret = bt_ots_obj_add(bt_mcs_get_ots(), &add_param); if (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) { 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; if (obj.busy) { @@ -545,14 +569,17 @@ static int add_parent_group_object(struct mpl_mediaplayer *pl) } obj.busy = true; 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); - group_meta.name = pl->group->parent->title; - group_meta.type.uuid.type = BT_UUID_TYPE_16; - group_meta.type.uuid_16.val = BT_UUID_16(group_type)->val; - BT_OTS_OBJ_SET_PROP_READ(group_meta.props); + obj.desc->size.alloc = obj.desc->size.cur = setup_parent_group_object(pl->group); + obj.desc->name = pl->group->parent->title; + BT_OTS_OBJ_SET_PROP_READ(obj.desc->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) { BT_WARN("Unable to add parent group object"); obj.busy = false; @@ -563,7 +590,8 @@ static int add_parent_group_object(struct mpl_mediaplayer *pl) /* Add a single group to the OTS */ 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; int ret; @@ -581,14 +609,17 @@ static int add_group_object(struct mpl_group *group) obj.add_type = MPL_OBJ_GROUP; obj.add_group = group; + obj.desc = &created_desc; - group_meta.size.alloc = group_meta.size.cur = setup_group_object(group); - group_meta.name = group->title; - group_meta.type.uuid.type = BT_UUID_TYPE_16; - group_meta.type.uuid_16.val = BT_UUID_16(group_type)->val; - BT_OTS_OBJ_SET_PROP_READ(group_meta.props); + obj.desc->size.alloc = obj.desc->size.cur = setup_group_object(group); + obj.desc->name = group->title; + BT_OTS_OBJ_SET_PROP_READ(obj.desc->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) { 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 ******************************/ -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) { BT_DBG_OBJ_ID("Object Id deleted: ", id); + + return 0; } 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; } -static int on_obj_created(struct bt_ots *ots, struct bt_conn *conn, - uint64_t id, - const struct bt_ots_obj_metadata *metadata) +static int on_obj_created(struct bt_ots *ots, struct bt_conn *conn, uint64_t id, + const struct bt_ots_obj_add_param *add_param, + struct bt_ots_obj_created_desc *created_desc) { 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"); if (obj.add_type == MPL_OBJ_ICON) { 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"); } - } else if (!bt_uuid_cmp(&metadata->type.uuid, + } else if (!bt_uuid_cmp(&add_param->type.uuid, BT_UUID_OTS_TYPE_TRACK_SEGMENT)) { BT_DBG("Track Segments Obj Type"); 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"); } - } else if (!bt_uuid_cmp(&metadata->type.uuid, + } else if (!bt_uuid_cmp(&add_param->type.uuid, BT_UUID_OTS_TYPE_TRACK)) { BT_DBG("Track Obj Type"); 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"); } - } else if (!bt_uuid_cmp(&metadata->type.uuid, + } else if (!bt_uuid_cmp(&add_param->type.uuid, BT_UUID_OTS_TYPE_GROUP)) { BT_DBG("Group Obj Type"); if (obj.add_type == MPL_OBJ_PARENT_GROUP) { diff --git a/subsys/bluetooth/services/ots/Kconfig b/subsys/bluetooth/services/ots/Kconfig index c211bee2627..22b1ab8aa1a 100644 --- a/subsys/bluetooth/services/ots/Kconfig +++ b/subsys/bluetooth/services/ots/Kconfig @@ -46,6 +46,14 @@ config BT_OTS_MAX_OBJ_CNT config BT_OTS_SECONDARY_SVC 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 bool "Support OACP Read Operation" default y diff --git a/subsys/bluetooth/services/ots/ots.c b/subsys/bluetooth/services/ots/ots.c index 1b6b3023d76..366f964b139 100644 --- a/subsys/bluetooth/services/ots/ots.c +++ b/subsys/bluetooth/services/ots/ots.c @@ -30,6 +30,18 @@ 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) #define OACP_FEAT_BIT_READ BIT(BT_OTS_OACP_FEAT_READ) #else @@ -50,6 +62,8 @@ LOG_MODULE_REGISTER(bt_ots, CONFIG_BT_OTS_LOG_LEVEL); /* OACP features supported by Kconfig */ #define OACP_FEAT ( \ + OACP_FEAT_BIT_CREATE | \ + OACP_FEAT_BIT_DELETE | \ OACP_FEAT_BIT_READ | \ OACP_FEAT_BIT_WRITE | \ 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; - if (obj_meta->type.uuid.type == 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)); - } else { + switch (obj_meta->type.uuid.type) { + case BT_UUID_TYPE_16: return bt_gatt_attr_read(conn, attr, buf, len, offset, &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)); } -int bt_ots_obj_add(struct bt_ots *ots, - struct bt_ots_obj_metadata *obj_init) +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) { int err; - struct bt_gatt_ots_object *obj; - size_t name_len; + struct bt_gatt_ots_object *new_obj; + struct bt_ots_obj_created_desc created_desc; 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) { @@ -284,50 +302,96 @@ int bt_ots_obj_add(struct bt_ots *ots, return -EBUSY; } - name_len = strlen(obj_init->name); - - 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); + err = bt_gatt_ots_obj_manager_obj_add(ots->obj_manager, &new_obj); if (err) { LOG_ERR("No space available in the object manager"); return err; } - /* Initialize object. */ - memcpy(&obj->metadata, obj_init, sizeof(obj->metadata)); - 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) { - 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) { - 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)) { bt_ots_dir_list_obj_remove(ots->dir_list, ots->obj_manager, - ots->cur_obj, obj); + ots->cur_obj, new_obj); } 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; } +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 err; @@ -338,11 +402,8 @@ int bt_ots_obj_delete(struct bt_ots *ots, uint64_t id) return err; } - if (ots->cur_obj == obj) { - if (obj->state.type != BT_GATT_OTS_OBJECT_IDLE_STATE) { - return -EBUSY; - } - ots->cur_obj = NULL; + if (obj->state.type != BT_GATT_OTS_OBJECT_IDLE_STATE) { + return -EBUSY; } if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) && ots->dir_list && @@ -351,6 +412,13 @@ int bt_ots_obj_delete(struct bt_ots *ots, uint64_t id) 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); if (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); } - if (ots->cb->obj_deleted) { - ots->cb->obj_deleted(ots, NULL, obj->id); + if (ots->cur_obj == obj) { + ots->cur_obj = NULL; } return 0; @@ -385,6 +453,9 @@ int bt_ots_init(struct bt_ots *ots, __ASSERT(ots_init->cb->obj_created, "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 || !BT_OTS_OACP_GET_FEAT_READ(ots_init->features.oacp), "Callback for object reading is not set"); @@ -400,6 +471,10 @@ int bt_ots_init(struct bt_ots *ots, 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; 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, 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) { if (instance_cnt >= BT_GATT_OTS_INSTANCE_LIST_SIZE) { diff --git a/subsys/bluetooth/services/ots/ots_internal.h b/subsys/bluetooth/services/ots/ots_internal.h index aecdcd3f8b4..4164a6d80f3 100644 --- a/subsys/bluetooth/services/ots/ots_internal.h +++ b/subsys/bluetooth/services/ots/ots_internal.h @@ -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 { uint64_t id; struct bt_ots_obj_metadata metadata; @@ -89,6 +104,9 @@ struct bt_ots { 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 } #endif diff --git a/subsys/bluetooth/services/ots/ots_oacp.c b/subsys/bluetooth/services/ots/ots_oacp.c index ac25743029a..2389fa63959 100644 --- a/subsys/bluetooth/services/ots/ots_oacp.c +++ b/subsys/bluetooth/services/ots/ots_oacp.c @@ -16,6 +16,7 @@ #include #include "ots_internal.h" #include "ots_dir_list_internal.h" +#include "ots_obj_manager_internal.h" #include @@ -45,6 +46,121 @@ static void oacp_l2cap_closed(struct bt_gatt_ots_l2cap *l2cap_ctx, } #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( struct bt_conn *conn, struct bt_ots *ots, @@ -162,12 +278,18 @@ static enum bt_gatt_ots_oacp_res_code oacp_proc_validate( switch (proc->type) { case BT_GATT_OTS_OACP_PROC_READ: return oacp_read_proc_validate(conn, ots, proc); - case BT_GATT_OTS_OACP_PROC_WRITE: #if defined(CONFIG_BT_OTS_OACP_WRITE_SUPPORT) + case BT_GATT_OTS_OACP_PROC_WRITE: return oacp_write_proc_validate(conn, ots, proc); #endif +#if defined(CONFIG_BT_OTS_OACP_CREATE_SUPPORT) 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: + return oacp_delete_proc_validate(conn, ots, proc); +#endif case BT_GATT_OTS_OACP_PROC_CHECKSUM_CALC: case BT_GATT_OTS_OACP_PROC_EXECUTE: 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); switch (proc->type) { +#if defined(CONFIG_BT_OTS_OACP_CREATE_SUPPORT) case BT_GATT_OTS_OACP_PROC_CREATE: proc->create_params.size = net_buf_simple_pull_le32(&net_buf); bt_uuid_create(&proc->create_params.type.uuid, net_buf.data, 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: - break; + return BT_GATT_OTS_OACP_RES_SUCCESS; +#endif case BT_GATT_OTS_OACP_PROC_CHECKSUM_CALC: proc->cs_calc_params.offset = 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 = net_buf_simple_pull_le32(&net_buf); return BT_GATT_OTS_OACP_RES_SUCCESS; - case BT_GATT_OTS_OACP_PROC_WRITE: #if defined(CONFIG_BT_OTS_OACP_WRITE_SUPPORT) + case BT_GATT_OTS_OACP_PROC_WRITE: proc->write_params.offset = net_buf_simple_pull_le32(&net_buf); proc->write_params.len = @@ -217,8 +343,6 @@ static enum bt_gatt_ots_oacp_res_code oacp_command_decode( proc->write_params.mode = net_buf_simple_pull_u8(&net_buf); return BT_GATT_OTS_OACP_RES_SUCCESS; -#else - break; #endif case BT_GATT_OTS_OACP_PROC_ABORT: default: @@ -243,9 +367,6 @@ static bool oacp_command_len_verify(struct bt_gatt_ots_oacp_proc *proc, case BT_UUID_TYPE_16: ref_len += BT_GATT_OTS_OACP_CREATE_UUID16_PARAMS_SIZE; break; - case BT_UUID_TYPE_32: - ref_len += BT_GATT_OTS_OACP_CREATE_UUID32_PARAMS_SIZE; - break; case BT_UUID_TYPE_128: ref_len += BT_GATT_OTS_OACP_CREATE_UUID128_PARAMS_SIZE; 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); + if (!ots->cur_obj) { + LOG_DBG("There is no object associated with this ACK"); + return; + } + switch (ots->cur_obj->state.type) { case BT_GATT_OTS_OBJECT_READ_OP_STATE: 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: /* procedure execution is driven by L2CAP socket receive */ break; + case BT_GATT_OTS_OBJECT_IDLE_STATE: + /* procedure is not in progress and was already completed */ + break; default: LOG_ERR("Unsupported OTS state: %d", ots->cur_obj->state.type); break; diff --git a/subsys/bluetooth/services/ots/ots_oacp_internal.h b/subsys/bluetooth/services/ots/ots_oacp_internal.h index 5af0d96455d..a481e746f11 100644 --- a/subsys/bluetooth/services/ots/ots_oacp_internal.h +++ b/subsys/bluetooth/services/ots/ots_oacp_internal.h @@ -92,14 +92,16 @@ struct bt_gatt_ots_oacp_proc { }; }; -/* Size of Object Action Control Point create procedure with 16-bit UUID object type */ -#define BT_GATT_OTS_OACP_CREATE_UUID16_PARAMS_SIZE 7 +/* Size of the generic part of the Object Action Control Point create procedure */ +#define BT_GATT_OTS_OACP_CREATE_GENERIC_PARAMS_SIZE 4 -/* Size of Object Action Control Point create procedure with 32-bit UUID object type */ -#define BT_GATT_OTS_OACP_CREATE_UUID32_PARAMS_SIZE 9 +/* Size of Object Action Control Point create procedure with 16-bit UUID object type */ +#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 */ -#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 */ #define BT_GATT_OTS_OACP_CS_CALC_PARAMS_SIZE 8