sample: bluetooth: OTS sample add checksum
central_otc: read checksum after object data read. peripheral_ots: add checksum calculate cb. Signed-off-by: Pirun Lee <pirun.lee@nordicsemi.no>
This commit is contained in:
parent
1e6f36cca7
commit
7015578ff4
4 changed files with 75 additions and 19 deletions
|
@ -9,7 +9,7 @@ Overview
|
||||||
Similar to the :ref:`Central <bluetooth_central>` sample, except that this
|
Similar to the :ref:`Central <bluetooth_central>` sample, except that this
|
||||||
application specifically looks for the OTS (Object Transfer) GATT Service.
|
application specifically looks for the OTS (Object Transfer) GATT Service.
|
||||||
And this sample is to select object sequentially, to read metadata, to write data,
|
And this sample is to select object sequentially, to read metadata, to write data,
|
||||||
to read data of selected ojects.
|
to read data, and to calculate checksum of selected ojects.
|
||||||
|
|
||||||
Requirements
|
Requirements
|
||||||
************
|
************
|
||||||
|
|
|
@ -33,6 +33,7 @@ static struct bt_gatt_discover_params discover_params;
|
||||||
static struct bt_gatt_subscribe_params *oacp_sub_params;
|
static struct bt_gatt_subscribe_params *oacp_sub_params;
|
||||||
static struct bt_gatt_subscribe_params *olcp_sub_params;
|
static struct bt_gatt_subscribe_params *olcp_sub_params;
|
||||||
static unsigned char obj_data_buf[OBJ_MAX_SIZE];
|
static unsigned char obj_data_buf[OBJ_MAX_SIZE];
|
||||||
|
static uint32_t last_checksum;
|
||||||
|
|
||||||
static bool first_selected;
|
static bool first_selected;
|
||||||
static void on_obj_selected(struct bt_ots_client *ots_inst, struct bt_conn *conn, int err);
|
static void on_obj_selected(struct bt_ots_client *ots_inst, struct bt_conn *conn, int err);
|
||||||
|
@ -81,19 +82,25 @@ static void print_hex_number(const uint8_t *num, size_t len)
|
||||||
#error "Unsupported board: This sample need 4 buttons to run"
|
#error "Unsupported board: This sample need 4 buttons to run"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios, {0});
|
static const struct gpio_dt_spec button0 = GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios, {0});
|
||||||
static const struct gpio_dt_spec button1 = GPIO_DT_SPEC_GET_OR(SW1_NODE, gpios, {0});
|
static const struct gpio_dt_spec button1 = GPIO_DT_SPEC_GET_OR(SW1_NODE, gpios, {0});
|
||||||
static const struct gpio_dt_spec button2 = GPIO_DT_SPEC_GET_OR(SW2_NODE, gpios, {0});
|
static const struct gpio_dt_spec button2 = GPIO_DT_SPEC_GET_OR(SW2_NODE, gpios, {0});
|
||||||
static const struct gpio_dt_spec button3 = GPIO_DT_SPEC_GET_OR(SW3_NODE, gpios, {0});
|
static const struct gpio_dt_spec button3 = GPIO_DT_SPEC_GET_OR(SW3_NODE, gpios, {0});
|
||||||
#define BTN_COUNT 4
|
#define BTN_COUNT 4
|
||||||
|
|
||||||
static const struct gpio_dt_spec btns[BTN_COUNT] = {button, button1, button2, button3};
|
static const struct gpio_dt_spec btns[BTN_COUNT] = {button0, button1, button2, button3};
|
||||||
static struct gpio_callback button_cb_data;
|
static struct gpio_callback button_cb_data;
|
||||||
struct otc_btn_work_info {
|
struct otc_btn_work_info {
|
||||||
struct k_work_delayable work;
|
struct k_work_delayable work;
|
||||||
uint32_t pins;
|
uint32_t pins;
|
||||||
} otc_btn_work;
|
} otc_btn_work;
|
||||||
|
|
||||||
|
struct otc_checksum_work_info {
|
||||||
|
struct k_work_delayable work;
|
||||||
|
off_t offset;
|
||||||
|
size_t len;
|
||||||
|
} otc_checksum_work;
|
||||||
|
|
||||||
static void otc_btn_work_fn(struct k_work *work)
|
static void otc_btn_work_fn(struct k_work *work)
|
||||||
{
|
{
|
||||||
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
|
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
|
||||||
|
@ -101,7 +108,7 @@ static void otc_btn_work_fn(struct k_work *work)
|
||||||
int err;
|
int err;
|
||||||
size_t size_to_write;
|
size_t size_to_write;
|
||||||
|
|
||||||
if (btn_work->pins == BIT(button.pin)) {
|
if (btn_work->pins == BIT(button0.pin)) {
|
||||||
if (!first_selected) {
|
if (!first_selected) {
|
||||||
err = bt_ots_client_select_id(&otc, default_conn, BT_OTS_OBJ_ID_MIN);
|
err = bt_ots_client_select_id(&otc, default_conn, BT_OTS_OBJ_ID_MIN);
|
||||||
first_selected = true;
|
first_selected = true;
|
||||||
|
@ -111,8 +118,7 @@ static void otc_btn_work_fn(struct k_work *work)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
printk("Failed to select object\n");
|
printk("Failed to select object (err %d)\n", err);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printk("Selecting object succeeded\n");
|
printk("Selecting object succeeded\n");
|
||||||
|
@ -121,8 +127,7 @@ static void otc_btn_work_fn(struct k_work *work)
|
||||||
err = bt_ots_client_read_object_metadata(&otc, default_conn,
|
err = bt_ots_client_read_object_metadata(&otc, default_conn,
|
||||||
BT_OTS_METADATA_REQ_ALL);
|
BT_OTS_METADATA_REQ_ALL);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
printk("Failed to read object metadata\n");
|
printk("Failed to read object metadata (err %d)\n", err);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (btn_work->pins == BIT(button2.pin)) {
|
} else if (btn_work->pins == BIT(button2.pin)) {
|
||||||
|
@ -134,12 +139,13 @@ static void otc_btn_work_fn(struct k_work *work)
|
||||||
obj_data_buf[idx] = UINT8_MAX - (idx % UINT8_MAX);
|
obj_data_buf[idx] = UINT8_MAX - (idx % UINT8_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
last_checksum = bt_ots_client_calc_checksum(obj_data_buf, size_to_write);
|
||||||
|
printk("Data sent checksum 0x%08x\n", last_checksum);
|
||||||
err = bt_ots_client_write_object_data(&otc, default_conn, obj_data_buf,
|
err = bt_ots_client_write_object_data(&otc, default_conn, obj_data_buf,
|
||||||
size_to_write, 0,
|
size_to_write, 0,
|
||||||
BT_OTS_OACP_WRITE_OP_MODE_NONE);
|
BT_OTS_OACP_WRITE_OP_MODE_NONE);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
printk("Failed to write object (%d)\n", err);
|
printk("Failed to write object (err %d)\n", err);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
printk("This OBJ does not support WRITE OP\n");
|
printk("This OBJ does not support WRITE OP\n");
|
||||||
|
@ -151,7 +157,6 @@ static void otc_btn_work_fn(struct k_work *work)
|
||||||
err = bt_ots_client_read_object_data(&otc, default_conn);
|
err = bt_ots_client_read_object_data(&otc, default_conn);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
printk("Failed to read object %d\n", err);
|
printk("Failed to read object %d\n", err);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
printk("This OBJ does not support READ OP\n");
|
printk("This OBJ does not support READ OP\n");
|
||||||
|
@ -159,6 +164,20 @@ static void otc_btn_work_fn(struct k_work *work)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void otc_checksum_work_fn(struct k_work *work)
|
||||||
|
{
|
||||||
|
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
|
||||||
|
struct otc_checksum_work_info *checksum_work =
|
||||||
|
CONTAINER_OF(dwork, struct otc_checksum_work_info, work);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = bt_ots_client_get_object_checksum(&otc, default_conn, checksum_work->offset,
|
||||||
|
checksum_work->len);
|
||||||
|
if (err != 0) {
|
||||||
|
printk("bt_ots_client_get_object_checksum failed (%d)\n", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
|
static void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
|
||||||
{
|
{
|
||||||
otc_btn_work.pins = pins;
|
otc_btn_work.pins = pins;
|
||||||
|
@ -538,7 +557,7 @@ BT_CONN_CB_DEFINE(conn_callbacks) = {
|
||||||
|
|
||||||
static void on_obj_selected(struct bt_ots_client *ots_inst, struct bt_conn *conn, int err)
|
static void on_obj_selected(struct bt_ots_client *ots_inst, struct bt_conn *conn, int err)
|
||||||
{
|
{
|
||||||
printk("Current object selected cb %d\n", err);
|
printk("Current object selected cb OLCP result (%d)\n", err);
|
||||||
|
|
||||||
if (err == BT_GATT_OTS_OLCP_RES_OPERATION_FAILED) {
|
if (err == BT_GATT_OTS_OLCP_RES_OPERATION_FAILED) {
|
||||||
printk("BT_GATT_OTS_OLCP_RES_OPERATION_FAILED %d\n", err);
|
printk("BT_GATT_OTS_OLCP_RES_OPERATION_FAILED %d\n", err);
|
||||||
|
@ -568,6 +587,9 @@ static int on_obj_data_read(struct bt_ots_client *ots_inst, struct bt_conn *conn
|
||||||
printk("Object total received %d\n", len + offset);
|
printk("Object total received %d\n", len + offset);
|
||||||
print_hex_number(obj_data_buf, len + offset);
|
print_hex_number(obj_data_buf, len + offset);
|
||||||
(void)memset(obj_data_buf, 0, OBJ_MAX_SIZE);
|
(void)memset(obj_data_buf, 0, OBJ_MAX_SIZE);
|
||||||
|
otc_checksum_work.offset = 0;
|
||||||
|
otc_checksum_work.len = otc.cur_object.size.cur;
|
||||||
|
k_work_schedule(&otc_checksum_work.work, K_NO_WAIT);
|
||||||
return BT_OTS_STOP;
|
return BT_OTS_STOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -589,7 +611,22 @@ static void on_obj_metadata_read(struct bt_ots_client *ots_inst, struct bt_conn
|
||||||
}
|
}
|
||||||
static void on_obj_data_written(struct bt_ots_client *ots_inst, struct bt_conn *conn, size_t len)
|
static void on_obj_data_written(struct bt_ots_client *ots_inst, struct bt_conn *conn, size_t len)
|
||||||
{
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
printk("Object been written %d\n", len);
|
printk("Object been written %d\n", len);
|
||||||
|
/* Update object size after write done*/
|
||||||
|
err = bt_ots_client_read_object_metadata(&otc, default_conn,
|
||||||
|
BT_OTS_METADATA_REQ_ALL);
|
||||||
|
if (err != 0) {
|
||||||
|
printk("Failed to read object metadata (err %d)\n", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_obj_checksum_calculated(struct bt_ots_client *ots_inst,
|
||||||
|
struct bt_conn *conn, int err, uint32_t checksum)
|
||||||
|
{
|
||||||
|
printk("Object Calculate checksum OACP result (%d)\nChecksum 0x%08x last sent 0x%08x %s\n",
|
||||||
|
err, checksum, last_checksum, (checksum == last_checksum) ? "match" : "not match");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bt_otc_init(void)
|
static void bt_otc_init(void)
|
||||||
|
@ -598,6 +635,7 @@ static void bt_otc_init(void)
|
||||||
otc_cb.obj_selected = on_obj_selected;
|
otc_cb.obj_selected = on_obj_selected;
|
||||||
otc_cb.obj_metadata_read = on_obj_metadata_read;
|
otc_cb.obj_metadata_read = on_obj_metadata_read;
|
||||||
otc_cb.obj_data_written = on_obj_data_written;
|
otc_cb.obj_data_written = on_obj_data_written;
|
||||||
|
otc_cb.obj_checksum_calculated = on_obj_checksum_calculated;
|
||||||
otc.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
|
otc.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
|
||||||
otc.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
|
otc.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
|
||||||
printk("Current object selected callback: %p\n", otc_cb.obj_selected);
|
printk("Current object selected callback: %p\n", otc_cb.obj_selected);
|
||||||
|
@ -614,6 +652,7 @@ void main(void)
|
||||||
first_selected = false;
|
first_selected = false;
|
||||||
discovery_state = ATOMIC_INIT(0);
|
discovery_state = ATOMIC_INIT(0);
|
||||||
k_work_init_delayable(&otc_btn_work.work, otc_btn_work_fn);
|
k_work_init_delayable(&otc_btn_work.work, otc_btn_work_fn);
|
||||||
|
k_work_init_delayable(&otc_checksum_work.work, otc_checksum_work_fn);
|
||||||
|
|
||||||
configure_buttons();
|
configure_buttons();
|
||||||
err = bt_enable(NULL);
|
err = bt_enable(NULL);
|
||||||
|
|
|
@ -8,7 +8,7 @@ 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_CREATE_SUPPORT=y
|
||||||
CONFIG_BT_OTS_OACP_DELETE_SUPPORT=y
|
CONFIG_BT_OTS_OACP_DELETE_SUPPORT=y
|
||||||
|
CONFIG_BT_OTS_OACP_CHECKSUM_SUPPORT=y
|
||||||
CONFIG_LOG=y
|
CONFIG_LOG=y
|
||||||
CONFIG_ASSERT=y
|
CONFIG_ASSERT=y
|
||||||
# This sample needs more memory on BT_RX_THREAD
|
# This sample needs more memory on BT_RX_THREAD
|
||||||
|
|
|
@ -43,6 +43,8 @@ struct object_creation_data {
|
||||||
uint32_t props;
|
uint32_t props;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define OTS_OBJ_ID_TO_OBJ_IDX(id) (((id) - BT_OTS_OBJ_ID_MIN) % ARRAY_SIZE(objects))
|
||||||
|
|
||||||
static struct object_creation_data *object_being_created;
|
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)
|
||||||
|
@ -133,11 +135,12 @@ static void ots_obj_selected(struct bt_ots *ots, struct bt_conn *conn,
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t ots_obj_read(struct bt_ots *ots, struct bt_conn *conn,
|
static ssize_t ots_obj_read(struct bt_ots *ots, struct bt_conn *conn,
|
||||||
uint64_t id, void **data, size_t len,
|
uint64_t id, void **data, size_t len,
|
||||||
off_t offset)
|
off_t offset)
|
||||||
{
|
{
|
||||||
char id_str[BT_OTS_OBJ_ID_STR_LEN];
|
char id_str[BT_OTS_OBJ_ID_STR_LEN];
|
||||||
uint32_t obj_index = ((id - BT_OTS_OBJ_ID_MIN) % ARRAY_SIZE(objects));
|
uint32_t obj_index = OTS_OBJ_ID_TO_OBJ_IDX(id);
|
||||||
|
|
||||||
bt_ots_obj_id_to_str(id, id_str, sizeof(id_str));
|
bt_ots_obj_id_to_str(id, id_str, sizeof(id_str));
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
@ -168,7 +171,7 @@ static ssize_t ots_obj_write(struct bt_ots *ots, struct bt_conn *conn,
|
||||||
off_t offset, size_t rem)
|
off_t offset, size_t rem)
|
||||||
{
|
{
|
||||||
char id_str[BT_OTS_OBJ_ID_STR_LEN];
|
char id_str[BT_OTS_OBJ_ID_STR_LEN];
|
||||||
uint32_t obj_index = ((id - BT_OTS_OBJ_ID_MIN) % ARRAY_SIZE(objects));
|
uint32_t obj_index = OTS_OBJ_ID_TO_OBJ_IDX(id);
|
||||||
|
|
||||||
bt_ots_obj_id_to_str(id, id_str, sizeof(id_str));
|
bt_ots_obj_id_to_str(id, id_str, sizeof(id_str));
|
||||||
|
|
||||||
|
@ -192,6 +195,19 @@ static void ots_obj_name_written(struct bt_ots *ots, struct bt_conn *conn,
|
||||||
id_str, cur_name, new_name);
|
id_str, cur_name, new_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ots_obj_cal_checksum(struct bt_ots *ots, struct bt_conn *conn, uint64_t id,
|
||||||
|
off_t offset, size_t len, void **data)
|
||||||
|
{
|
||||||
|
uint32_t obj_index = OTS_OBJ_ID_TO_OBJ_IDX(id);
|
||||||
|
|
||||||
|
if (obj_index >= OBJ_POOL_SIZE) {
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
*data = &objects[obj_index].data[offset];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct bt_ots_cb ots_callbacks = {
|
static struct bt_ots_cb ots_callbacks = {
|
||||||
.obj_created = ots_obj_created,
|
.obj_created = ots_obj_created,
|
||||||
.obj_deleted = ots_obj_deleted,
|
.obj_deleted = ots_obj_deleted,
|
||||||
|
@ -199,6 +215,7 @@ static struct bt_ots_cb ots_callbacks = {
|
||||||
.obj_read = ots_obj_read,
|
.obj_read = ots_obj_read,
|
||||||
.obj_write = ots_obj_write,
|
.obj_write = ots_obj_write,
|
||||||
.obj_name_written = ots_obj_name_written,
|
.obj_name_written = ots_obj_name_written,
|
||||||
|
.obj_cal_checksum = ots_obj_cal_checksum,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ots_init(void)
|
static int ots_init(void)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue