zephyr/subsys/bluetooth/services/ots/ots_obj_manager.c
Asbjørn Sæbø e8620a7416 Bluetooth: Object Transfer Service: Defines for allowed object ID values
Add #defines for the maximum and minimum allowed values for object
IDs.

Moves the #define for the directory listing object ID to the public
header file

Having these limits available is useful for applications wanting to
ensure they pass in (or handle) valid object ID values.

Signed-off-by: Asbjørn Sæbø <asbjorn.sabo@nordicsemi.no>
2021-09-16 10:32:19 +02:00

260 lines
5.5 KiB
C

/*
* Copyright (c) 2020 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 <logging/log.h>
LOG_MODULE_DECLARE(bt_ots, CONFIG_BT_OTS_LOG_LEVEL);
struct bt_gatt_ots_pool_item {
sys_dnode_t dnode;
struct bt_gatt_ots_object val;
bool is_allocated;
};
struct bt_gatt_ots_obj_manager {
sys_dlist_t list;
struct bt_gatt_ots_pool_item pool[CONFIG_BT_OTS_MAX_OBJ_CNT];
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 - BT_OTS_OBJ_ID_MIN + 1;
}
} else {
return id - BT_OTS_OBJ_ID_MIN;
}
}
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 BT_OTS_OBJ_ID_MIN + index - 1;
}
} else {
return BT_OTS_OBJ_ID_MIN + index;
}
}
int bt_gatt_ots_obj_manager_first_obj_get(
struct bt_gatt_ots_obj_manager *obj_manager,
struct bt_gatt_ots_object **obj)
{
sys_dnode_t *obj_dnode;
struct bt_gatt_ots_pool_item *first_item;
if (sys_dlist_is_empty(&obj_manager->list)) {
return -ENOENT;
}
obj_dnode = sys_dlist_peek_head_not_empty(&obj_manager->list);
first_item = CONTAINER_OF(obj_dnode, struct bt_gatt_ots_pool_item,
dnode);
*obj = &first_item->val;
return 0;
}
int bt_gatt_ots_obj_manager_last_obj_get(
struct bt_gatt_ots_obj_manager *obj_manager,
struct bt_gatt_ots_object **obj)
{
sys_dnode_t *obj_dnode;
struct bt_gatt_ots_pool_item *last_item;
if (sys_dlist_is_empty(&obj_manager->list)) {
return -ENOENT;
}
obj_dnode = sys_dlist_peek_tail(&obj_manager->list);
last_item = CONTAINER_OF(obj_dnode, struct bt_gatt_ots_pool_item,
dnode);
*obj = &last_item->val;
return 0;
}
int bt_gatt_ots_obj_manager_prev_obj_get(
struct bt_gatt_ots_obj_manager *obj_manager,
const struct bt_gatt_ots_object *cur_obj,
struct bt_gatt_ots_object **prev_obj)
{
sys_dnode_t *prev_obj_dnode;
struct bt_gatt_ots_pool_item *cur_item, *prev_item;
if (sys_dlist_is_empty(&obj_manager->list)) {
return -ENOENT;
}
cur_item = CONTAINER_OF(cur_obj, struct bt_gatt_ots_pool_item, val);
prev_obj_dnode = sys_dlist_peek_prev_no_check(&obj_manager->list,
&cur_item->dnode);
if (!prev_obj_dnode) {
return -ENFILE;
}
prev_item = CONTAINER_OF(prev_obj_dnode,
struct bt_gatt_ots_pool_item,
dnode);
*prev_obj = &prev_item->val;
return 0;
}
int bt_gatt_ots_obj_manager_next_obj_get(
struct bt_gatt_ots_obj_manager *obj_manager,
const struct bt_gatt_ots_object *cur_obj,
struct bt_gatt_ots_object **next_obj)
{
sys_dnode_t *next_obj_dnode;
struct bt_gatt_ots_pool_item *cur_item, *next_item;
if (sys_dlist_is_empty(&obj_manager->list)) {
return -ENOENT;
}
cur_item = CONTAINER_OF(cur_obj, struct bt_gatt_ots_pool_item, val);
next_obj_dnode = sys_dlist_peek_next_no_check(&obj_manager->list,
&cur_item->dnode);
if (!next_obj_dnode) {
return -ENFILE;
}
next_item = CONTAINER_OF(next_obj_dnode,
struct bt_gatt_ots_pool_item,
dnode);
*next_obj = &next_item->val;
return 0;
}
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 index;
if (sys_dlist_is_empty(&obj_manager->list)) {
return -ENOENT;
}
if (id < BT_OTS_OBJ_ID_MIN &&
(IS_ENABLED(CONFIG_BT_OTS_DIR_LIST_OBJ) &&
id != OTS_OBJ_ID_DIR_LIST)) {
return -EINVAL;
}
index = obj_id_to_index(id);
if (index >= ARRAY_SIZE(obj_manager->pool)) {
return -EINVAL;
}
if (!obj_manager->pool[index].is_allocated) {
return -EINVAL;
}
*object = &obj_manager->pool[index].val;
return 0;
}
int bt_gatt_ots_obj_manager_obj_add(
struct bt_gatt_ots_obj_manager *obj_manager,
struct bt_gatt_ots_object **object)
{
for (uint64_t i = 0; i < ARRAY_SIZE(obj_manager->pool); i++) {
struct bt_gatt_ots_pool_item *cur_obj =
&obj_manager->pool[i];
if (!cur_obj->is_allocated) {
cur_obj->is_allocated = true;
cur_obj->val.id = obj_index_to_id(i);
sys_dlist_append(&obj_manager->list, &cur_obj->dnode);
*object = &cur_obj->val;
return 0;
}
}
return -ENOMEM;
}
int bt_gatt_ots_obj_manager_obj_delete(struct bt_gatt_ots_object *obj)
{
struct bt_gatt_ots_pool_item *item;
item = CONTAINER_OF(obj, struct bt_gatt_ots_pool_item, val);
if (!item->is_allocated) {
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);
return 0;
}
bool bt_gatt_ots_obj_manager_obj_contains(struct bt_gatt_ots_obj_manager *obj_manager,
struct bt_gatt_ots_object *obj)
{
struct bt_gatt_ots_pool_item *item;
item = CONTAINER_OF(obj, struct bt_gatt_ots_pool_item, val);
return PART_OF_ARRAY(obj_manager->pool, item);
}
void *bt_gatt_ots_obj_manager_assign(void)
{
static struct bt_gatt_ots_obj_manager
obj_manager[CONFIG_BT_OTS_MAX_INST_CNT];
struct bt_gatt_ots_obj_manager *cur_manager;
for (cur_manager = obj_manager;
cur_manager != obj_manager + CONFIG_BT_OTS_MAX_INST_CNT;
cur_manager++) {
if (!cur_manager->is_assigned) {
break;
}
}
if (cur_manager->is_assigned) {
return NULL;
}
cur_manager->is_assigned = true;
sys_dlist_init(&cur_manager->list);
return cur_manager;
}