2014-11-19 13:01:27

by Marcin Kraglak

[permalink] [raw]
Subject: [PATCH 0/8] Implement Read Multiple in gatt-client

This implementation is done in gatt-client and functionality
is exposed in btgatt-client tool.
This implementation was tested against PTS and corresponding
unit tests are added too.

Comments are welcome

Marcin Kraglak (8):
shared/gatt-client: Implement Read Multiple request
tools/btgatt-client: Add read_multiple_cmd
unit/test-gatt: Add /TP/GAR/CL/BV-05-C test
unit/test-gatt: Add /TP/GAR/CL/BI-18-C test
unit/test-gatt: Add /TP/GAR/CL/BI-19-C test
unit/test-gatt: Add /TP/GAR/CL/BI-20-C test
unit/test-gatt: Add /TP/GAR/CL/BI-21-C test
unit/test-gatt: Add /TP/GAR/CL/BI-22-C test

src/shared/gatt-client.c | 65 ++++++++++++++++++++++++++++
src/shared/gatt-client.h | 7 +++
tools/btgatt-client.c | 60 ++++++++++++++++++++++++++
unit/test-gatt.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 241 insertions(+)

--
1.9.3



2014-11-20 10:23:55

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH 0/8] Implement Read Multiple in gatt-client

Hi Marcin,

On Wed, Nov 19, 2014 at 3:01 PM, Marcin Kraglak
<[email protected]> wrote:
> This implementation is done in gatt-client and functionality
> is exposed in btgatt-client tool.
> This implementation was tested against PTS and corresponding
> unit tests are added too.
>
> Comments are welcome
>
> Marcin Kraglak (8):
> shared/gatt-client: Implement Read Multiple request
> tools/btgatt-client: Add read_multiple_cmd
> unit/test-gatt: Add /TP/GAR/CL/BV-05-C test
> unit/test-gatt: Add /TP/GAR/CL/BI-18-C test
> unit/test-gatt: Add /TP/GAR/CL/BI-19-C test
> unit/test-gatt: Add /TP/GAR/CL/BI-20-C test
> unit/test-gatt: Add /TP/GAR/CL/BI-21-C test
> unit/test-gatt: Add /TP/GAR/CL/BI-22-C test
>
> src/shared/gatt-client.c | 65 ++++++++++++++++++++++++++++
> src/shared/gatt-client.h | 7 +++
> tools/btgatt-client.c | 60 ++++++++++++++++++++++++++
> unit/test-gatt.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 241 insertions(+)
>
> --
> 1.9.3

Applied, thanks.


--
Luiz Augusto von Dentz

2014-11-19 13:01:32

by Marcin Kraglak

[permalink] [raw]
Subject: [PATCH 5/8] unit/test-gatt: Add /TP/GAR/CL/BI-19-C test

Verify Generic Attribute Profile client behavior when the
Read Multiple Characteristic Values procedure fails due to
valid handle.
---
unit/test-gatt.c | 13 +++++++++++++
1 file changed, 13 insertions(+)

diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index c138b63..bf9ef6e 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -705,6 +705,13 @@ const struct test_step test_multiple_read_2 = {
.expected_att_ecode = 0x02
};

+const struct test_step test_multiple_read_3 = {
+ .handle = 0x0003,
+ .end_handle = 0x0007,
+ .func = test_multiple_read,
+ .expected_att_ecode = 0x01
+};
+
static void read_by_type_cb(bool success, uint8_t att_ecode,
struct bt_gatt_result *result,
void *user_data)
@@ -950,5 +957,11 @@ int main(int argc, char *argv[])
raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
raw_pdu(0x01, 0x0e, 0x03, 0x00, 0x02));

+ define_test_client("/TP/GAR/CL/BI-19-C", test_client, service_data_1,
+ &test_multiple_read_3,
+ SERVICE_DATA_1_PDU,
+ raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
+ raw_pdu(0x01, 0x0e, 0x03, 0x00, 0x01));
+
return g_test_run();
}
--
1.9.3


2014-11-19 13:01:35

by Marcin Kraglak

[permalink] [raw]
Subject: [PATCH 8/8] unit/test-gatt: Add /TP/GAR/CL/BI-22-C test

Verify Generic Attribute Profile client behavior when the
Read Multiple Characteristic Values procedure fails due to
encryption key size.
---
unit/test-gatt.c | 13 +++++++++++++
1 file changed, 13 insertions(+)

diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index dc4d0b1..7923c8b 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -726,6 +726,13 @@ const struct test_step test_multiple_read_5 = {
.expected_att_ecode = 0x05
};

+const struct test_step test_multiple_read_6 = {
+ .handle = 0x0003,
+ .end_handle = 0x0007,
+ .func = test_multiple_read,
+ .expected_att_ecode = 0x0c
+};
+
static void read_by_type_cb(bool success, uint8_t att_ecode,
struct bt_gatt_result *result,
void *user_data)
@@ -989,5 +996,11 @@ int main(int argc, char *argv[])
raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
raw_pdu(0x01, 0x0e, 0x03, 0x00, 0x05));

+ define_test_client("/TP/GAR/CL/BI-21-C", test_client, service_data_1,
+ &test_multiple_read_6,
+ SERVICE_DATA_1_PDU,
+ raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
+ raw_pdu(0x01, 0x0e, 0x03, 0x00, 0x0c));
+
return g_test_run();
}
--
1.9.3


2014-11-19 13:01:33

by Marcin Kraglak

[permalink] [raw]
Subject: [PATCH 6/8] unit/test-gatt: Add /TP/GAR/CL/BI-20-C test

Verify Generic Attribute Profile client behavior when the
Read Multiple Characteristic Values procedure fails due to
insufficient authorization.
---
unit/test-gatt.c | 13 +++++++++++++
1 file changed, 13 insertions(+)

diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index bf9ef6e..1982629 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -712,6 +712,13 @@ const struct test_step test_multiple_read_3 = {
.expected_att_ecode = 0x01
};

+const struct test_step test_multiple_read_4 = {
+ .handle = 0x0003,
+ .end_handle = 0x0007,
+ .func = test_multiple_read,
+ .expected_att_ecode = 0x08
+};
+
static void read_by_type_cb(bool success, uint8_t att_ecode,
struct bt_gatt_result *result,
void *user_data)
@@ -963,5 +970,11 @@ int main(int argc, char *argv[])
raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
raw_pdu(0x01, 0x0e, 0x03, 0x00, 0x01));

+ define_test_client("/TP/GAR/CL/BI-20-C", test_client, service_data_1,
+ &test_multiple_read_4,
+ SERVICE_DATA_1_PDU,
+ raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
+ raw_pdu(0x01, 0x0e, 0x03, 0x00, 0x08));
+
return g_test_run();
}
--
1.9.3


2014-11-19 13:01:34

by Marcin Kraglak

[permalink] [raw]
Subject: [PATCH 7/8] unit/test-gatt: Add /TP/GAR/CL/BI-21-C test

Verify Generic Attribute Profile client behavior when the
Read Multiple Characteristic Values procedure fails due to
insufficient authentication.
---
unit/test-gatt.c | 13 +++++++++++++
1 file changed, 13 insertions(+)

diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 1982629..dc4d0b1 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -719,6 +719,13 @@ const struct test_step test_multiple_read_4 = {
.expected_att_ecode = 0x08
};

+const struct test_step test_multiple_read_5 = {
+ .handle = 0x0003,
+ .end_handle = 0x0007,
+ .func = test_multiple_read,
+ .expected_att_ecode = 0x05
+};
+
static void read_by_type_cb(bool success, uint8_t att_ecode,
struct bt_gatt_result *result,
void *user_data)
@@ -976,5 +983,11 @@ int main(int argc, char *argv[])
raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
raw_pdu(0x01, 0x0e, 0x03, 0x00, 0x08));

+ define_test_client("/TP/GAR/CL/BI-21-C", test_client, service_data_1,
+ &test_multiple_read_5,
+ SERVICE_DATA_1_PDU,
+ raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
+ raw_pdu(0x01, 0x0e, 0x03, 0x00, 0x05));
+
return g_test_run();
}
--
1.9.3


2014-11-19 13:01:30

by Marcin Kraglak

[permalink] [raw]
Subject: [PATCH 3/8] unit/test-gatt: Add /TP/GAR/CL/BV-05-C test

Verify that a Generic Attribute Profile client can read multiple
Characteristic Values selected by set of handles.
---
unit/test-gatt.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)

diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 9ded1f0..1c23ede 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -660,6 +660,44 @@ const struct test_step test_read_by_type_6 = {
.expected_att_ecode = 0x0c,
};

+static void multiple_read_cb(bool success, uint8_t att_ecode,
+ const uint8_t *value, uint16_t length,
+ void *user_data)
+{
+ struct context *context = user_data;
+ const struct test_step *step = context->data->step;
+
+ g_assert(att_ecode == step->expected_att_ecode);
+
+ if (success) {
+ g_assert(length == step->length);
+ g_assert(memcmp(value, step->value, length) == 0);
+ }
+
+ context_quit(context);
+}
+
+static void test_multiple_read(struct context *context)
+{
+ const struct test_step *step = context->data->step;
+ uint16_t handles[2];
+
+ handles[0] = step->handle;
+ handles[1] = step->end_handle;
+
+ g_assert(bt_gatt_client_read_multiple(context->client, handles, 2,
+ multiple_read_cb, context,
+ NULL));
+}
+
+const struct test_step test_multiple_read_1 = {
+ .handle = 0x0003,
+ .end_handle = 0x0007,
+ .func = test_multiple_read,
+ .value = read_data_1,
+ .length = 0x03
+};
+
static void read_by_type_cb(bool success, uint8_t att_ecode,
struct bt_gatt_result *result,
void *user_data)
@@ -893,5 +931,11 @@ int main(int argc, char *argv[])
raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x0d, 0x2a),
raw_pdu(0x01, 0x08, 0x0b, 0x00, 0x0c));

+ define_test_client("/TP/GAR/CL/BV-05-C", test_client, service_data_1,
+ &test_multiple_read_1,
+ SERVICE_DATA_1_PDU,
+ raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
+ raw_pdu(0x0f, 0x01, 0x02, 0x03));
+
return g_test_run();
}
--
1.9.3


2014-11-19 13:01:29

by Marcin Kraglak

[permalink] [raw]
Subject: [PATCH 2/8] tools/btgatt-client: Add read_multiple_cmd

---
tools/btgatt-client.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)

diff --git a/tools/btgatt-client.c b/tools/btgatt-client.c
index 7a1204f..ca84780 100644
--- a/tools/btgatt-client.c
+++ b/tools/btgatt-client.c
@@ -401,6 +401,65 @@ static void cmd_services(struct client *cli, char *cmd_str)
services_usage();
}

+static void read_multiple_usage(void)
+{
+ printf("Usage: read-multiple <handle_1> <handle_2> ...\n");
+}
+
+static void read_multiple_cb(bool success, uint8_t att_ecode,
+ const uint8_t *value, uint16_t length,
+ void *user_data)
+{
+ int i;
+
+ if (!success) {
+ PRLOG("\nRead multiple request failed: 0x%02x\n", att_ecode);
+ return;
+ }
+
+ printf("\nRead multiple value (%u bytes):", length);
+
+ for (i = 0; i < length; i++)
+ printf("%02x ", value[i]);
+
+ PRLOG("\n");
+}
+
+static void cmd_read_multiple(struct client *cli, char *cmd_str)
+{
+ int argc = 0;
+ uint16_t *value;
+ char *argv[512];
+ int i;
+ char *endptr = NULL;
+
+ if (!bt_gatt_client_is_ready(cli->gatt)) {
+ printf("GATT client not initialized\n");
+ return;
+ }
+
+ if (!parse_args(cmd_str, sizeof(argv), argv, &argc) || argc < 2) {
+ read_multiple_usage();
+ return;
+ }
+
+ value = malloc(sizeof(uint16_t) * argc);
+
+ for (i = 0; i < argc; i++) {
+ value[i] = strtol(argv[i], &endptr, 0);
+ if (endptr == argv[i] || *endptr != '\0' || !value[i]) {
+ printf("Invalid value byte: %s\n", argv[i]);
+ return;
+ }
+ }
+
+ if (!bt_gatt_client_read_multiple(cli->gatt, value, argc,
+ read_multiple_cb, NULL, NULL))
+ printf("Failed to initiate read multiple procedure\n");
+
+ free(value);
+}
+
static void read_value_usage(void)
{
printf("Usage: read-value <value_handle>\n");
@@ -873,6 +932,7 @@ static struct {
"\tRead a characteristic or descriptor value" },
{ "read-long-value", cmd_read_long_value,
"\tRead a long characteristic or desctriptor value" },
+ { "read-multiple", cmd_read_multiple, "\tRead Multiple" },
{ "write-value", cmd_write_value,
"\tWrite a characteristic or descriptor value" },
{ "write-long-value", cmd_write_long_value,
--
1.9.3


2014-11-19 13:01:31

by Marcin Kraglak

[permalink] [raw]
Subject: [PATCH 4/8] unit/test-gatt: Add /TP/GAR/CL/BI-18-C test

Verify Generic Attribute Profile client behavior when
the Read Multiple Characteristic Values procedure fails due
to read not permitted.
---
unit/test-gatt.c | 13 +++++++++++++
1 file changed, 13 insertions(+)

diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 1c23ede..c138b63 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -698,6 +698,13 @@ const struct test_step test_multiple_read_1 = {
.length = 0x03
};

+const struct test_step test_multiple_read_2 = {
+ .handle = 0x0003,
+ .end_handle = 0x0007,
+ .func = test_multiple_read,
+ .expected_att_ecode = 0x02
+};
+
static void read_by_type_cb(bool success, uint8_t att_ecode,
struct bt_gatt_result *result,
void *user_data)
@@ -937,5 +944,11 @@ int main(int argc, char *argv[])
raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
raw_pdu(0x0f, 0x01, 0x02, 0x03));

+ define_test_client("/TP/GAR/CL/BI-18-C", test_client, service_data_1,
+ &test_multiple_read_2,
+ SERVICE_DATA_1_PDU,
+ raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
+ raw_pdu(0x01, 0x0e, 0x03, 0x00, 0x02));
+
return g_test_run();
}
--
1.9.3


2014-11-19 13:01:28

by Marcin Kraglak

[permalink] [raw]
Subject: [PATCH 1/8] shared/gatt-client: Implement Read Multiple request

It will perform Read Multiple request and return atributes values.
---
src/shared/gatt-client.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
src/shared/gatt-client.h | 7 ++++++
2 files changed, 72 insertions(+)

diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index cf93d4b..4a645eb 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -1799,6 +1799,71 @@ bool bt_gatt_client_read_value(struct bt_gatt_client *client,
return true;
}

+static void read_multiple_cb(uint8_t opcode, const void *pdu, uint16_t length,
+ void *user_data)
+{
+ struct read_op *op = user_data;
+ uint8_t att_ecode;
+ bool success;
+
+ if (opcode != BT_ATT_OP_READ_MULT_RSP || (!pdu && length)) {
+ success = false;
+
+ if (opcode == BT_ATT_OP_ERROR_RSP)
+ att_ecode = process_error(pdu, length);
+ else
+ att_ecode = 0;
+
+ pdu = NULL;
+ length = 0;
+ } else {
+ success = true;
+ att_ecode = 0;
+ }
+
+ if (op->callback)
+ op->callback(success, att_ecode, pdu, length, op->user_data);
+}
+
+bool bt_gatt_client_read_multiple(struct bt_gatt_client *client,
+ uint16_t *handles, uint8_t num_handles,
+ bt_gatt_client_read_callback_t callback,
+ void *user_data,
+ bt_gatt_client_destroy_func_t destroy)
+{
+ uint8_t pdu[num_handles * 2];
+ struct read_op *op;
+ int i;
+
+ if (!client)
+ return false;
+
+ if (num_handles < 2)
+ return false;
+
+ if (num_handles * 2 > bt_att_get_mtu(client->att) - 1)
+ return false;
+
+ op = new0(struct read_op, 1);
+ if (!op)
+ return false;
+
+ op->callback = callback;
+ op->user_data = user_data;
+ op->destroy = destroy;
+
+ for (i = 0; i < num_handles; i++)
+ put_le16(handles[i], pdu + (2 * i));
+
+ if (!bt_att_send(client->att, BT_ATT_OP_READ_MULT_REQ, pdu, sizeof(pdu),
+ read_multiple_cb, op, destroy_read_op)) {
+ free(op);
+ return false;
+ }
+
+ return true;
+}
+
struct read_long_op {
struct bt_gatt_client *client;
int ref_count;
diff --git a/src/shared/gatt-client.h b/src/shared/gatt-client.h
index adccfc5..11b1f37 100644
--- a/src/shared/gatt-client.h
+++ b/src/shared/gatt-client.h
@@ -145,6 +145,13 @@ bool bt_gatt_client_read_long_value(struct bt_gatt_client *client,
void *user_data,
bt_gatt_client_destroy_func_t destroy);

+
+bool bt_gatt_client_read_multiple(struct bt_gatt_client *client,
+ uint16_t *handles, uint8_t num_handles,
+ bt_gatt_client_read_callback_t callback,
+ void *user_data,
+ bt_gatt_client_destroy_func_t destroy);
+
bool bt_gatt_client_write_without_response(struct bt_gatt_client *client,
uint16_t value_handle,
bool signed_write,
--
1.9.3