Bluetooth: services: Adds directory listing object to OTS

The directory listing object is an internal object which
content is the aggregation of all the metadata of all objects
(including the directory listing object itself). The client
can read this value to get a list of all objects with names,
lengths, and other metadata.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2021-02-22 14:26:31 +01:00 committed by Carles Cufí
commit e90ec2df44
11 changed files with 508 additions and 11 deletions

View file

@ -33,6 +33,9 @@ extern "C" {
/** @brief Length of OTS object ID string (in bytes). */
#define BT_OTS_OBJ_ID_STR_LEN 15
/** @brief ID of the Directory Listing Object */
#define OTS_OBJ_ID_DIR_LIST 0x000000000000
/** @brief Type of an OTS object. */
struct bt_ots_obj_type {
union {
@ -193,6 +196,124 @@ enum {
#define BT_OTS_OBJ_GET_PROP_MARKED(prop) \
((prop) & BIT(BT_OTS_OBJ_PROP_MARKED))
/** @brief Directory Listing record flag field. */
enum {
/** Bit 0 Object Type UUID Size 0: 16bit 1: 128bit*/
BT_OTS_DIR_LIST_FLAG_TYPE_128 = 0,
/** Bit 1 Current Size Present*/
BT_OTS_DIR_LIST_FLAG_CUR_SIZE = 1,
/** Bit 2 Allocated Size Present */
BT_OTS_DIR_LIST_FLAG_ALLOC_SIZE = 2,
/** Bit 3 Object First-Created Present*/
BT_OTS_DIR_LIST_FLAG_FIRST_CREATED = 3,
/** Bit 4 Object Last-Modified Present*/
BT_OTS_DIR_LIST_FLAG_LAST_MODIFIED = 4,
/** Bit 5 Object Properties Present*/
BT_OTS_DIR_LIST_FLAG_PROPERTIES = 5,
/** Bit 6 RFU*/
BT_OTS_DIR_LIST_FLAG_RFU = 6,
/** Bit 7 Extended Flags Present*/
BT_OTS_DIR_LIST_FLAG_EXTENDED = 7,
};
/** @brief Set @ref BT_OTS_DIR_LIST_SET_FLAG_TYPE_128 flag.
*
* @param flags Directory Listing Object flags.
*/
#define BT_OTS_DIR_LIST_SET_FLAG_TYPE_128(flags) \
WRITE_BIT((flags), BT_OTS_DIR_LIST_FLAG_TYPE_128, 1)
/** @brief Set @ref BT_OTS_DIR_LIST_FLAG_CUR_SIZE flag.
*
* @param flags Directory Listing Object flags.
*/
#define BT_OTS_DIR_LIST_SET_FLAG_CUR_SIZE(flags) \
WRITE_BIT((flags), BT_OTS_DIR_LIST_FLAG_CUR_SIZE, 1)
/** @brief Set @ref BT_OTS_DIR_LIST_FLAG_ALLOC_SIZE flag.
*
* @param flags Directory Listing Object flags.
*/
#define BT_OTS_DIR_LIST_SET_FLAG_ALLOC_SIZE(flags) \
WRITE_BIT((flags), BT_OTS_DIR_LIST_FLAG_ALLOC_SIZE, 1)
/** @brief Set @ref BT_OTS_DIR_LIST_FLAG_FIRST_CREATED flag.
*
* @param flags Directory Listing Object flags.
*/
#define BT_OTS_DIR_LIST_SET_FLAG_FIRST_CREATED(flags) \
WRITE_BIT((flags), BT_OTS_DIR_LIST_FLAG_FIRST_CREATED, 1)
/** @brief Set @ref BT_OTS_DIR_LIST_FLAG_LAST_MODIFIED flag.
*
* @param flags Directory Listing Object flags.
*/
#define BT_OTS_DIR_LIST_SET_FLAG_LAST_MODIFIED(flags) \
WRITE_BIT((flags), BT_OTS_DIR_LIST_FLAG_LAST_MODIFIED, 1)
/** @brief Set @ref BT_OTS_DIR_LIST_FLAG_PROPERTIES flag.
*
* @param flags Directory Listing Object flags.
*/
#define BT_OTS_DIR_LIST_SET_FLAG_PROPERTIES(flags) \
WRITE_BIT((flags), BT_OTS_DIR_LIST_FLAG_PROPERTIES, 1)
/** @brief Set @ref BT_OTS_DIR_LIST_FLAG_EXTENDED flag.
*
* @param flags Directory Listing Object flags.
*/
#define BT_OTS_DIR_LIST_SET_FLAG_EXTENDED(flags) \
WRITE_BIT((flags), BT_OTS_DIR_LIST_FLAG_EXTENDED, 1)
/** @brief Get @ref BT_OTS_DIR_LIST_GET_FLAG_TYPE_128 flag.
*
* @param flags Directory Listing Object flags.
*/
#define BT_OTS_DIR_LIST_GET_FLAG_TYPE_128(flags) \
((flags) & BIT(BT_OTS_DIR_LIST_FLAG_TYPE_128))
/** @brief Get @ref BT_OTS_DIR_LIST_GET_FLAG_CUR_SIZE flag.
*
* @param flags Directory Listing Object flags.
*/
#define BT_OTS_DIR_LIST_GET_FLAG_CUR_SIZE(flags) \
((flags) & BIT(BT_OTS_DIR_LIST_FLAG_CUR_SIZE))
/** @brief Get @ref BT_OTS_DIR_LIST_GET_FLAG_ALLOC_SIZE flag.
*
* @param flags Directory Listing Object flags.
*/
#define BT_OTS_DIR_LIST_GET_FLAG_ALLOC_SIZE(flags) \
((flags) & BIT(BT_OTS_DIR_LIST_FLAG_ALLOC_SIZE))
/** @brief Get @ref BT_OTS_DIR_LIST_GET_FLAG_FIRST_CREATED flag.
*
* @param flags Directory Listing Object flags.
*/
#define BT_OTS_DIR_LIST_GET_FLAG_FIRST_CREATED(flags) \
((flags) & BIT(BT_OTS_DIR_LIST_FLAG_FIRST_CREATED))
/** @brief Get @ref BT_OTS_DIR_LIST_GET_FLAG_LAST_MODIFIED flag.
*
* @param flags Directory Listing Object flags.
*/
#define BT_OTS_DIR_LIST_GET_FLAG_LAST_MODIFIED(flags) \
((flags) & BIT(BT_OTS_DIR_LIST_FLAG_LAST_MODIFIED))
/** @brief Get @ref BT_OTS_DIR_LIST_GET_FLAG_PROPERTIES flag.
*
* @param flags Directory Listing Object flags.
*/
#define BT_OTS_DIR_LIST_GET_FLAG_PROPERTIES(flags) \
((flags) & BIT(BT_OTS_DIR_LIST_FLAG_PROPERTIES))
/** @brief Get @ref BT_OTS_DIR_LIST_GET_FLAG_EXTENDED flag.
*
* @param flags Directory Listing Object flags.
*/
#define BT_OTS_DIR_LIST_GET_FLAG_EXTENDED(flags) \
((flags) & BIT(BT_OTS_DIR_LIST_FLAG_EXTENDED))
/** @brief Descriptor for OTS Object Size parameter. */
struct bt_ots_obj_size {
/* Current Size */

View file

@ -2,5 +2,6 @@ CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DEVICE_NAME="Zephyr OTS"
CONFIG_BT_OTS=y
CONFIG_BT_OTS_DIR_LIST_OBJ=y
CONFIG_LOG=y

View file

@ -7,3 +7,5 @@ zephyr_sources_ifdef(
ots_obj_manager.c
ots_oacp.c
ots_olcp.c)
zephyr_library_sources_ifdef(CONFIG_BT_OTS_DIR_LIST_OBJ ots_dir_list.c)

View file

@ -13,14 +13,34 @@ config BT_OTS
if BT_OTS
config BT_OTS_DIR_LIST_OBJ
bool "Enables the Directory Listing Object"
help
Enables the Directory Listing Object, which is an object that contains all the metadata
from all other objects, for easy exposure to a client. Enabling this will use one of the
objects given by BT_OTS_MAX_OBJ_CNT.
config BT_OTS_DIR_LIST_OBJ_NAME
string "The object name of the Directory Listing Object"
default "Directory"
depends on BT_OTS_DIR_LIST_OBJ
help
The name of the Directory Listing Object when it is read by a client.
config BT_OTS_MAX_INST_CNT
int "Maximum number of available OTS instances"
default 1
range 1 1 if !BT_OTS_SECONDARY_SVC
config BT_OTS_MAX_OBJ_CNT
int "Maximum number of objects that each service instance can store"
default 5
hex "Maximum number of objects that each service instance can store"
default 0x05
# Given the maximum size of a directory listing record (172) and the maximum size of an
# object using the net_buf implementation is 2^16-1, the maximum number of objects is given
# by 2^16-1 / 172 = 381 == 0x17D)
range 0x02 0x17D if BT_OTS_DIR_LIST_OBJ
# Max obj count is otherwise the non-RFU IDs available
range 0x01 0xFFFFFFFFFFFFFEFF
config BT_OTS_SECONDARY_SVC
bool "Register OTS as Secondary Service"

View file

@ -22,6 +22,7 @@
#include <bluetooth/services/ots.h>
#include "ots_internal.h"
#include "ots_obj_manager_internal.h"
#include "ots_dir_list_internal.h"
#include <logging/log.h>
@ -167,6 +168,13 @@ int bt_ots_obj_add(struct bt_ots *ots,
int err;
struct bt_gatt_ots_object *obj;
#if IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)
if (ots->dir_list->dir_list_obj->state.type != BT_GATT_OTS_OBJECT_IDLE_STATE) {
LOG_DBG("Directory Listing Object is being read");
return -EBUSY;
}
#endif /* CONFIG_BT_OTS_DIR_LIST_OBJ */
err = bt_gatt_ots_obj_manager_obj_add(ots->obj_manager, &obj);
if (err) {
LOG_ERR("No space available in the object manager");
@ -176,11 +184,20 @@ int bt_ots_obj_add(struct bt_ots *ots,
/* 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, obj);
}
/* Request object data. */
if (ots->cb->obj_created) {
err = ots->cb->obj_created(ots, NULL, obj->id, obj_init);
if (err) {
bt_gatt_ots_obj_manager_obj_delete(obj);
if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)) {
bt_ots_dir_list_obj_remove(ots, obj);
}
return err;
}
}
@ -210,11 +227,22 @@ int bt_ots_obj_delete(struct bt_ots *ots, uint64_t id)
ots->cur_obj = NULL;
}
#if IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)
if (ots->dir_list->dir_list_obj->state.type != BT_GATT_OTS_OBJECT_IDLE_STATE) {
LOG_DBG("Directory Listing Object is being read");
return -EBUSY;
}
#endif /* CONFIG_BT_OTS_DIR_LIST_OBJ */
err = bt_gatt_ots_obj_manager_obj_delete(obj);
if (err) {
return err;
}
if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)) {
bt_ots_dir_list_obj_remove(ots, obj);
}
if (ots->cb->obj_deleted) {
ots->cb->obj_deleted(ots, NULL, obj->id);
}
@ -275,6 +303,10 @@ int bt_ots_init(struct bt_ots *ots,
return err;
}
if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)) {
bt_ots_dir_list_init(ots);
}
LOG_DBG("Initialized OTS");
return 0;
@ -352,6 +384,7 @@ static int bt_gatt_ots_instances_prepare(const struct device *dev)
instance++, index++) {
/* Assign an object pool to the OTS instance. */
instance->obj_manager = bt_gatt_ots_obj_manager_assign();
if (!instance->obj_manager) {
LOG_ERR("OTS Object manager instance not available");
return -ENOMEM;

View file

@ -0,0 +1,226 @@
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/types.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <sys/dlist.h>
#include <sys/byteorder.h>
#include <bluetooth/services/ots.h>
#include "ots_internal.h"
#include "ots_obj_manager_internal.h"
#include <logging/log.h>
LOG_MODULE_DECLARE(bt_ots, CONFIG_BT_OTS_LOG_LEVEL);
static struct bt_ots_dir_list dir_lists[CONFIG_BT_OTS_MAX_INST_CNT];
static void dir_list_object_encode(struct bt_gatt_ots_object *obj,
struct net_buf_simple *net_buf)
{
uint8_t flags = 0;
uint8_t *start;
BT_OTS_DIR_LIST_SET_FLAG_PROPERTIES(flags);
BT_OTS_DIR_LIST_SET_FLAG_CUR_SIZE(flags);
if (obj->metadata.type.uuid.type == BT_UUID_TYPE_128) {
BT_OTS_DIR_LIST_SET_FLAG_TYPE_128(flags);
}
/* skip 16bits at the beginning of the record for the record's length */
start = net_buf_simple_add(net_buf, sizeof(uint16_t));
/* ID */
net_buf_simple_add_le48(net_buf, obj->id);
/* Name length */
net_buf_simple_add_u8(net_buf, strlen(obj->metadata.name));
/* Name */
net_buf_simple_add_mem(net_buf, obj->metadata.name,
strlen(obj->metadata.name));
/* Flags */
net_buf_simple_add_u8(net_buf, flags);
/* encode Object type */
if (obj->metadata.type.uuid.type == BT_UUID_TYPE_16) {
net_buf_simple_add_le16(net_buf, obj->metadata.type.uuid_16.val);
} else {
net_buf_simple_add_mem(net_buf, obj->metadata.type.uuid_128.val,
BT_UUID_SIZE_128);
}
/* encode Object Current size */
net_buf_simple_add_le32(net_buf, obj->metadata.size.cur);
/* Object properties */
net_buf_simple_add_le32(net_buf, obj->metadata.props);
/* Update the record length at the beginning */
sys_put_le16(net_buf_simple_tail(net_buf) - start, start);
}
void bt_ots_dir_list_obj_add(struct bt_ots *ots,
struct bt_gatt_ots_object *obj)
{
__ASSERT(ots->dir_list->dir_list_obj != obj,
"Cannot add Directory Listing Object");
if (ots->dir_list->dir_list_obj != ots->cur_obj) {
/* We only need to update the object directory listing if it is currently selected,
* as we otherwise only create it when it is selected.
*/
return;
}
dir_list_object_encode(obj, &ots->dir_list->net_buf);
/*re-encode the Directory Listing Object size with the is new size*/
sys_put_le16(ots->dir_list->net_buf.len, ots->dir_list->net_buf.data);
/* Update Directory Listing Object metadata size */
ots->dir_list->dir_list_obj->metadata.size.cur = ots->dir_list->net_buf.len;
}
void bt_ots_dir_list_obj_remove(struct bt_ots *ots,
struct bt_gatt_ots_object *obj)
{
uint16_t offset = 0;
__ASSERT(ots->dir_list->dir_list_obj != obj,
"Cannot remove Directory Listing Object");
if (ots->dir_list->dir_list_obj != ots->cur_obj) {
/* We only need to update the object directory listing if it is currently selected,
* as we otherwise only create it when it is selected.
*/
return;
}
while (offset < ots->dir_list->net_buf.len) {
uint16_t len = sys_get_le16(ots->dir_list->net_buf.data + offset);
uint64_t id = sys_get_le64(ots->dir_list->net_buf.data + offset + sizeof(len));
__ASSERT(len, "Invalid object length");
if (id == obj->id) {
/* Delete object by moving memory after the object to
* the objects current location
*/
memmove(ots->dir_list->net_buf.data + offset,
ots->dir_list->net_buf.data + offset + len,
ots->dir_list->net_buf.len - (offset + len));
/* Decrement net_buf len to new length */
ots->dir_list->net_buf.len -= len;
break;
}
offset += len;
}
__ASSERT(offset <= ots->dir_list->net_buf.len, "Object was not removed");
/*re-encode the Directory Listing Object size with the is new size*/
sys_put_le16(ots->dir_list->net_buf.len, ots->dir_list->net_buf.data);
/* Update Directory Listing Object metadata size */
ots->dir_list->dir_list_obj->metadata.size.cur = ots->dir_list->net_buf.len;
}
static void dir_list_encode(struct bt_ots *ots)
{
struct bt_gatt_ots_object *obj;
int err;
err = bt_gatt_ots_obj_manager_first_obj_get(ots->obj_manager, &obj);
__ASSERT(err == 0 && first_obj == ots->dir_list->dir_list_obj,
"Expecting first object to be the Directory Listing Object");
/* Init with len = 0 to reset data */
net_buf_simple_init_with_data(&ots->dir_list->net_buf,
ots->dir_list->_content,
sizeof(ots->dir_list->_content));
ots->dir_list->net_buf.len = 0;
do {
dir_list_object_encode(obj, &ots->dir_list->net_buf);
err = bt_gatt_ots_obj_manager_next_obj_get(ots->obj_manager, obj, &obj);
} while (!err);
/*re-encode the Directory Listing Object size with the is new size*/
sys_put_le16(ots->dir_list->net_buf.len, ots->dir_list->net_buf.data);
/* Update Directory Listing Object metadata size */
ots->dir_list->dir_list_obj->metadata.size.cur = ots->dir_list->net_buf.len;
}
void bt_ots_dir_list_selected(struct bt_ots *ots)
{
if (ots->dir_list->dir_list_obj != ots->cur_obj) {
/* We only need to update the object directory listing if it is currently selected,
* as we otherwise only create it when it is selected.
*/
return;
}
dir_list_encode(ots);
}
void bt_ots_dir_list_init(struct bt_ots *ots)
{
struct bt_gatt_ots_object *dir_list_obj;
int err;
static char *dir_list_obj_name = CONFIG_BT_OTS_DIR_LIST_OBJ_NAME;
if (!ots->dir_list) {
for (int i = 0; i < ARRAY_SIZE(dir_lists); i++) {
if (!dir_lists[i].dir_list_obj) {
ots->dir_list = &dir_lists[i];
}
}
}
__ASSERT(ots->dir_list,
"Could not assign Directory Listing Object to OTS instance %p", ots);
__ASSERT(strlen(dir_list_obj_name) < UINT8_MAX,
"BT_OTS_DIR_LIST_OBJ_NAME shall be less than 255 octets");
err = bt_gatt_ots_obj_manager_obj_add(ots->obj_manager, &dir_list_obj);
__ASSERT(!err, "Could not add Directory Listing Object for object manager %p", obj_man);
memset(&dir_list_obj->metadata, 0, sizeof(dir_list_obj->metadata));
dir_list_obj->metadata.name = dir_list_obj_name;
dir_list_obj->metadata.size.alloc = sizeof(ots->dir_list->_content);
dir_list_obj->metadata.type.uuid.type = BT_UUID_TYPE_16;
dir_list_obj->metadata.type.uuid_16.val = BT_UUID_OTS_DIRECTORY_LISTING_VAL;
BT_OTS_OBJ_SET_PROP_READ(dir_list_obj->metadata.props);
ots->dir_list->dir_list_obj = dir_list_obj;
/* Set size in dir_list_encode */
dir_list_encode(ots);
}
int bt_ots_dir_list_content_get(struct bt_ots *ots, uint8_t **data,
uint32_t len, uint32_t offset)
{
if (offset >= ots->dir_list->net_buf.len) {
*data = NULL;
return 0;
}
*data = ots->dir_list->net_buf.data + offset;
return MIN(len, ots->dir_list->net_buf.len - offset);
}

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef BT_OTS_DIR_LIST_INTERNAL_H_
#define BT_OTS_DIR_LIST_INTERNAL_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/types.h>
#include <zephyr/types.h>
#include <bluetooth/gatt.h>
#include <bluetooth/services/ots.h>
#include "ots_internal.h"
void bt_ots_dir_list_obj_add(struct bt_ots *ots, struct bt_gatt_ots_object *obj);
void bt_ots_dir_list_obj_remove(struct bt_ots *ots, struct bt_gatt_ots_object *obj);
void bt_ots_dir_list_selected(struct bt_ots *ots);
void bt_ots_dir_list_init(struct bt_ots *ots);
int bt_ots_dir_list_content_get(struct bt_ots *ots, uint8_t **data,
uint32_t len, uint32_t offset);
#ifdef __cplusplus
}
#endif
#endif /* BT_OTS_DIR_LIST_INTERNAL_H_ */

View file

@ -16,6 +16,10 @@ extern "C" {
#include "ots_oacp_internal.h"
#include "ots_olcp_internal.h"
/** Maximum size of the Directory Listing Object Record. Table 4.1 in the OTS spec. */
#define DIR_LIST_OBJ_RECORD_MAX_SIZE 172
#define DIR_LIST_MAX_SIZE (DIR_LIST_OBJ_RECORD_MAX_SIZE * CONFIG_BT_OTS_MAX_OBJ_CNT)
/**@brief OTS Attribute Protocol Application Error codes. */
enum bt_gatt_ots_att_err_codes {
/** An attempt was made to write a value that is invalid or
@ -66,6 +70,12 @@ struct bt_gatt_ots_indicate {
bool is_enabled;
};
struct bt_ots_dir_list {
struct net_buf_simple net_buf;
struct bt_gatt_ots_object *dir_list_obj;
uint8_t _content[DIR_LIST_MAX_SIZE];
};
struct bt_ots {
struct bt_ots_feat features;
struct bt_gatt_ots_object *cur_obj;
@ -74,6 +84,9 @@ struct bt_ots {
struct bt_gatt_ots_indicate olcp_ind;
struct bt_gatt_ots_l2cap l2cap;
struct bt_ots_cb *cb;
#if defined(CONFIG_BT_OTS_DIR_LIST_OBJ)
struct bt_ots_dir_list *dir_list;
#endif /* CONFIG_BT_OTS_DIR_LIST_OBJ */
void *obj_manager;
};

View file

@ -15,6 +15,7 @@
#include <bluetooth/gatt.h>
#include <bluetooth/services/ots.h>
#include "ots_internal.h"
#include "ots_dir_list_internal.h"
#include <logging/log.h>
@ -197,14 +198,25 @@ static void oacp_read_proc_cb(struct bt_gatt_ots_l2cap *l2cap_ctx,
}
ots->cur_obj->state.type = BT_GATT_OTS_OBJECT_IDLE_STATE;
if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) &&
ots->cur_obj->id == OTS_OBJ_ID_DIR_LIST) {
return;
}
ots->cb->obj_read(ots, conn, ots->cur_obj->id, NULL, 0,
offset);
return;
}
len = read_op->oacp_params.len - read_op->sent_len;
len = ots->cb->obj_read(ots, conn, ots->cur_obj->id, &obj_chunk, len,
offset);
if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) &&
ots->cur_obj->id == OTS_OBJ_ID_DIR_LIST) {
len = bt_ots_dir_list_content_get(ots, &obj_chunk, len, offset);
} else {
len = ots->cb->obj_read(ots, conn, ots->cur_obj->id, &obj_chunk,
len, offset);
}
ots->l2cap.tx_done = oacp_read_proc_cb;
err = bt_gatt_ots_l2cap_send(&ots->l2cap, obj_chunk, len);
@ -231,7 +243,10 @@ static void oacp_read_proc_execute(struct bt_ots *ots,
LOG_DBG("Executing Read procedure with offset: 0x%08X and "
"length: 0x%08X", params->offset, params->len);
if (ots->cb->obj_read) {
if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) &&
ots->cur_obj->id == OTS_OBJ_ID_DIR_LIST) {
oacp_read_proc_cb(&ots->l2cap, conn);
} else if (ots->cb->obj_read) {
oacp_read_proc_cb(&ots->l2cap, conn);
} else {
ots->cur_obj->state.type = BT_GATT_OTS_OBJECT_IDLE_STATE;

View file

@ -21,9 +21,6 @@ LOG_MODULE_DECLARE(bt_ots, CONFIG_BT_OTS_LOG_LEVEL);
/**Start of the usable range of Object IDs (values 0 to 0x100 are reserved)*/
#define OTS_OBJ_ID_START_RANGE 0x000000000100
#define OTS_OBJ_INDEX_TO_ID(_index) (OTS_OBJ_ID_START_RANGE + (_index))
#define OTS_OBJ_ID_TO_INDEX(_id) ((_id) - OTS_OBJ_ID_START_RANGE)
struct bt_gatt_ots_pool_item {
sys_dnode_t dnode;
struct bt_gatt_ots_object val;
@ -36,6 +33,32 @@ struct bt_gatt_ots_obj_manager {
bool is_assigned;
};
static uint64_t obj_id_to_index(uint64_t id)
{
if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)) {
if (id == OTS_OBJ_ID_DIR_LIST) {
return id;
} else {
return id - OTS_OBJ_ID_START_RANGE + 1;
}
} else {
return id - OTS_OBJ_ID_START_RANGE;
}
}
static uint64_t obj_index_to_id(uint64_t index)
{
if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)) {
if (index == 0) {
return OTS_OBJ_ID_DIR_LIST;
} else {
return OTS_OBJ_ID_START_RANGE + index - 1;
}
} else {
return OTS_OBJ_ID_START_RANGE + index;
}
}
int bt_gatt_ots_obj_manager_first_obj_get(
struct bt_gatt_ots_obj_manager *obj_manager,
struct bt_gatt_ots_object **obj)
@ -132,13 +155,15 @@ int bt_gatt_ots_obj_manager_obj_get(
struct bt_gatt_ots_obj_manager *obj_manager, uint64_t id,
struct bt_gatt_ots_object **object)
{
uint64_t i = OTS_OBJ_ID_TO_INDEX(id);
uint64_t i = obj_id_to_index(id);
if (sys_dlist_is_empty(&obj_manager->list)) {
return -ENOENT;
}
if (id < OTS_OBJ_ID_START_RANGE) {
if (id < OTS_OBJ_ID_START_RANGE ||
(IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) &&
id != OTS_OBJ_ID_DIR_LIST)) {
return -EINVAL;
}
@ -165,7 +190,7 @@ int bt_gatt_ots_obj_manager_obj_add(
if (!cur_obj->is_allocated) {
cur_obj->is_allocated = true;
cur_obj->val.id = OTS_OBJ_INDEX_TO_ID(i);
cur_obj->val.id = obj_index_to_id(i);
sys_dlist_append(&obj_manager->list, &cur_obj->dnode);
*object = &cur_obj->val;
@ -186,6 +211,11 @@ int bt_gatt_ots_obj_manager_obj_delete(struct bt_gatt_ots_object *obj)
return -EINVAL;
}
if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) &&
obj->id == OTS_OBJ_ID_DIR_LIST) {
return -EINVAL;
}
item->is_allocated = false;
sys_dlist_remove(&item->dnode);

View file

@ -16,6 +16,7 @@
#include <bluetooth/services/ots.h>
#include "ots_internal.h"
#include "ots_obj_manager_internal.h"
#include "ots_dir_list_internal.h"
#include <logging/log.h>
@ -283,6 +284,10 @@ ssize_t bt_gatt_ots_olcp_write(struct bt_conn *conn,
LOG_DBG("Selecting a new Current Object with id: %s",
log_strdup(id));
if (IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ)) {
bt_ots_dir_list_selected(ots);
}
if (ots->cb->obj_selected) {
ots->cb->obj_selected(ots, conn, ots->cur_obj->id);
}