In order to bring consistency in-tree, migrate all samples to the use
the new prefix <zephyr/...>. Note that the conversion has been scripted:
```python
from pathlib import Path
import re
EXTENSIONS = ("c", "h", "cpp", "rst")
for p in Path(".").glob("samples/**/*"):
if not p.is_file() or p.suffix and p.suffix[1:] not in EXTENSIONS:
continue
content = ""
with open(p) as f:
for line in f:
m = re.match(r"^(.*)#include <(.*)>(.*)$", line)
if (m and
not m.group(2).startswith("zephyr/") and
(Path(".") / "include" / "zephyr" / m.group(2)).exists()):
content += (
m.group(1) +
"#include <zephyr/" + m.group(2) +">" +
m.group(3) + "\n"
)
else:
content += line
with open(p, "w") as f:
f.write(content)
```
Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
330 lines
8.4 KiB
C
330 lines
8.4 KiB
C
/*
|
|
* Copyright (c) 2020 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/types.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <zephyr/sys/printk.h>
|
|
#include <zephyr/zephyr.h>
|
|
|
|
#include <zephyr/bluetooth/bluetooth.h>
|
|
#include <zephyr/bluetooth/conn.h>
|
|
#include <zephyr/bluetooth/gatt.h>
|
|
|
|
#include <zephyr/bluetooth/services/ots.h>
|
|
|
|
#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
|
|
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
|
|
|
|
#define OBJ_POOL_SIZE CONFIG_BT_OTS_MAX_OBJ_CNT
|
|
#define OBJ_MAX_SIZE 100
|
|
|
|
static const struct bt_data ad[] = {
|
|
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
|
|
BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
|
|
};
|
|
|
|
static const struct bt_data sd[] = {
|
|
BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_OTS_VAL)),
|
|
};
|
|
|
|
static struct {
|
|
uint8_t data[OBJ_MAX_SIZE];
|
|
char name[CONFIG_BT_OTS_OBJ_MAX_NAME_LEN + 1];
|
|
} 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) {
|
|
printk("Connection failed (err %u)\n", err);
|
|
return;
|
|
}
|
|
|
|
printk("Connected\n");
|
|
}
|
|
|
|
static void disconnected(struct bt_conn *conn, uint8_t reason)
|
|
{
|
|
printk("Disconnected (reason %u)\n", reason);
|
|
}
|
|
|
|
BT_CONN_CB_DEFINE(conn_callbacks) = {
|
|
.connected = connected,
|
|
.disconnected = disconnected,
|
|
};
|
|
|
|
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));
|
|
|
|
if (obj_cnt >= ARRAY_SIZE(objects)) {
|
|
printk("No item from Object pool is available for Object "
|
|
"with %s ID\n", id_str);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
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 int ots_obj_deleted(struct bt_ots *ots, struct bt_conn *conn,
|
|
uint64_t id)
|
|
{
|
|
char id_str[BT_OTS_OBJ_ID_STR_LEN];
|
|
|
|
bt_ots_obj_id_to_str(id, id_str, sizeof(id_str));
|
|
|
|
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,
|
|
uint64_t id)
|
|
{
|
|
char id_str[BT_OTS_OBJ_ID_STR_LEN];
|
|
|
|
bt_ots_obj_id_to_str(id, id_str, sizeof(id_str));
|
|
|
|
printk("Object with %s ID has been selected\n", id_str);
|
|
}
|
|
|
|
static ssize_t ots_obj_read(struct bt_ots *ots, struct bt_conn *conn,
|
|
uint64_t id, void **data, size_t len,
|
|
off_t offset)
|
|
{
|
|
char id_str[BT_OTS_OBJ_ID_STR_LEN];
|
|
uint32_t obj_index = (id % ARRAY_SIZE(objects));
|
|
|
|
bt_ots_obj_id_to_str(id, id_str, sizeof(id_str));
|
|
|
|
if (!data) {
|
|
printk("Object with %s ID has been successfully read\n",
|
|
id_str);
|
|
|
|
return 0;
|
|
}
|
|
|
|
*data = &objects[obj_index].data[offset];
|
|
|
|
/* Send even-indexed objects in 20 byte packets
|
|
* to demonstrate fragmented transmission.
|
|
*/
|
|
if ((obj_index % 2) == 0) {
|
|
len = (len < 20) ? len : 20;
|
|
}
|
|
|
|
printk("Object with %s ID is being read\n"
|
|
"Offset = %lu, Length = %zu\n",
|
|
id_str, (long)offset, len);
|
|
|
|
return len;
|
|
}
|
|
|
|
static ssize_t ots_obj_write(struct bt_ots *ots, struct bt_conn *conn,
|
|
uint64_t id, const void *data, size_t len,
|
|
off_t offset, size_t rem)
|
|
{
|
|
char id_str[BT_OTS_OBJ_ID_STR_LEN];
|
|
uint32_t obj_index = (id % ARRAY_SIZE(objects));
|
|
|
|
bt_ots_obj_id_to_str(id, id_str, sizeof(id_str));
|
|
|
|
printk("Object with %s ID is being written\n"
|
|
"Offset = %lu, Length = %zu, Remaining= %zu\n",
|
|
id_str, (long)offset, len, rem);
|
|
|
|
(void)memcpy(&objects[obj_index].data[offset], data, len);
|
|
|
|
return len;
|
|
}
|
|
|
|
static void ots_obj_name_written(struct bt_ots *ots, struct bt_conn *conn,
|
|
uint64_t id, const char *cur_name, const char *new_name)
|
|
{
|
|
char id_str[BT_OTS_OBJ_ID_STR_LEN];
|
|
|
|
bt_ots_obj_id_to_str(id, id_str, sizeof(id_str));
|
|
|
|
printk("Name for object with %s ID is being changed from '%s' to '%s'\n",
|
|
id_str, cur_name, new_name);
|
|
}
|
|
|
|
static struct bt_ots_cb ots_callbacks = {
|
|
.obj_created = ots_obj_created,
|
|
.obj_deleted = ots_obj_deleted,
|
|
.obj_selected = ots_obj_selected,
|
|
.obj_read = ots_obj_read,
|
|
.obj_write = ots_obj_write,
|
|
.obj_name_written = ots_obj_name_written,
|
|
};
|
|
|
|
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_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;
|
|
uint32_t alloc_size;
|
|
|
|
ots = bt_ots_free_instance_get();
|
|
if (!ots) {
|
|
printk("Failed to retrieve OTS instance\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* Configure OTS initialization. */
|
|
(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;
|
|
|
|
/* Initialize OTS instance. */
|
|
err = bt_ots_init(ots, &ots_init);
|
|
if (err) {
|
|
printk("Failed to init OTS (err:%d)\n", err);
|
|
return err;
|
|
}
|
|
|
|
/* Prepare first object demo data and add it to the instance. */
|
|
cur_size = sizeof(objects[0].data) / 2;
|
|
alloc_size = sizeof(objects[0].data);
|
|
for (uint32_t i = 0; i < cur_size; i++) {
|
|
objects[0].data[i] = i + 1;
|
|
}
|
|
|
|
(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);
|
|
(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;
|
|
|
|
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;
|
|
}
|
|
|
|
/* Prepare second object demo data and add it to the instance. */
|
|
cur_size = sizeof(objects[0].data);
|
|
alloc_size = sizeof(objects[0].data);
|
|
for (uint32_t i = 0; i < cur_size; i++) {
|
|
objects[1].data[i] = i * 2;
|
|
}
|
|
|
|
(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);
|
|
(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;
|
|
|
|
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;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void main(void)
|
|
{
|
|
int err;
|
|
|
|
printk("Starting Bluetooth Peripheral OTS example\n");
|
|
|
|
err = bt_enable(NULL);
|
|
if (err) {
|
|
printk("Bluetooth init failed (err %d)\n", err);
|
|
return;
|
|
}
|
|
|
|
printk("Bluetooth initialized\n");
|
|
|
|
err = ots_init();
|
|
if (err) {
|
|
printk("Failed to init OTS (err:%d)\n", err);
|
|
return;
|
|
}
|
|
|
|
err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad),
|
|
sd, ARRAY_SIZE(sd));
|
|
if (err) {
|
|
printk("Advertising failed to start (err %d)\n", err);
|
|
return;
|
|
}
|
|
|
|
printk("Advertising successfully started\n");
|
|
}
|