2011-02-21 22:50:00

by Sheldon Demario

[permalink] [raw]
Subject: [PATCH 1/7] Improve help messages in interactive gatttool

Includes the parameters info on help.
---
attrib/interactive.c | 19 +++++++++++++------
1 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/attrib/interactive.c b/attrib/interactive.c
index edc465a..b491314 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -217,13 +217,19 @@ static void cmd_primary(int argcp, char **argvp)
static struct {
const char *cmd;
void (*func)(int argcp, char **argvp);
+ const char *params;
const char *desc;
} commands[] = {
- { "help", cmd_help, "Show this help"},
- { "exit", cmd_exit, "Exit interactive mode"},
- { "connect", cmd_connect, "Connect to a remote device"},
- { "disconnect", cmd_disconnect, "Disconnect from a remote device"},
- { "primary", cmd_primary, "Primary Service Discovery"},
+ { "help", cmd_help, "",
+ "Show this help"},
+ { "exit", cmd_exit, "",
+ "Exit interactive mode" },
+ { "connect", cmd_connect, "[address]",
+ "Connect to a remote device" },
+ { "disconnect", cmd_disconnect, "",
+ "Disconnect from a remote device" },
+ { "primary", cmd_primary, "[UUID]",
+ "Primary Service Discovery" },
{ NULL, NULL, NULL}
};

@@ -232,7 +238,8 @@ static void cmd_help(int argcp, char **argvp)
int i;

for (i = 0; commands[i].cmd; i++)
- printf("%-12s\t%s\n", commands[i].cmd, commands[i].desc);
+ printf("%-15s %-25s %s\n", commands[i].cmd,
+ commands[i].params, commands[i].desc);
}

static void parse_line(char *line_read)
--
1.7.1



2011-02-24 13:55:52

by Sheldon Demario

[permalink] [raw]
Subject: [PATCH v3 5/7] Add characteristics read options in interactive gatttool

---

Remove return statements at the end of void functions

attrib/interactive.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 142 insertions(+), 1 deletions(-)

diff --git a/attrib/interactive.c b/attrib/interactive.c
index b00d0bc..7f3f658 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -50,6 +50,13 @@ static gchar *opt_sec_level = NULL;
static int opt_psm = 0;
static int opt_mtu = 0;

+struct characteristic_data {
+ uint16_t orig_start;
+ uint16_t start;
+ uint16_t end;
+ uuid_t uuid;
+};
+
static void cmd_help(int argcp, char **argvp);

enum state {
@@ -210,6 +217,79 @@ static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen,
rl_forced_update_display();
}

+static void char_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
+ gpointer user_data)
+{
+ uint8_t value[ATT_MAX_MTU];
+ int i, vlen;
+
+ if (status != 0) {
+ printf("Characteristic value/descriptor read failed: %s\n",
+ att_ecode2str(status));
+ return;
+ }
+
+ if (!dec_read_resp(pdu, plen, value, &vlen)) {
+ printf("Protocol error\n");
+ return;
+ }
+
+ printf("\nCharacteristic value/descriptor: ");
+ for (i = 0; i < vlen; i++)
+ printf("%02x ", value[i]);
+ printf("\n");
+
+ rl_forced_update_display();
+}
+
+static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu,
+ guint16 plen, gpointer user_data)
+{
+ struct characteristic_data *char_data = user_data;
+ struct att_data_list *list;
+ int i;
+
+ if (status == ATT_ECODE_ATTR_NOT_FOUND &&
+ char_data->start != char_data->orig_start)
+ goto done;
+
+ if (status != 0) {
+ printf("Read characteristics by UUID failed: %s\n",
+ att_ecode2str(status));
+ goto done;
+ }
+
+ list = dec_read_by_type_resp(pdu, plen);
+ if (list == NULL)
+ goto done;
+
+ for (i = 0; i < list->num; i++) {
+ uint8_t *value = list->data[i];
+ int j;
+
+ char_data->start = att_get_u16(value) + 1;
+
+ printf("\nhandle: 0x%04x \t value: ", att_get_u16(value));
+ value += 2;
+ for (j = 0; j < list->len - 2; j++, value++)
+ printf("%02x ", *value);
+ printf("\n");
+ }
+
+ att_data_list_free(list);
+
+ gatt_read_char_by_uuid(attrib, char_data->start, char_data->end,
+ &char_data->uuid, char_read_by_uuid_cb,
+ char_data);
+
+ rl_forced_update_display();
+
+ return;
+
+done:
+ g_free(char_data);
+}
+
static void cmd_exit(int argcp, char **argvp)
{
rl_callback_handler_remove();
@@ -344,6 +424,63 @@ static void cmd_char_desc(int argcp, char **argvp)
gatt_find_info(attrib, start, end, char_desc_cb, NULL);
}

+static void cmd_read_hnd(int argcp, char **argvp)
+{
+ int handle;
+
+ if (conn_state != STATE_CONNECTED) {
+ printf("Command failed: disconnected\n");
+ return;
+ }
+
+ if (argcp < 2) {
+ printf("Missing argument: handle\n");
+ return;
+ }
+
+ if (strtohandle(&handle, argvp[1])) {
+ printf("Invalid handle: %s\n", argvp[1]);
+ return;
+ }
+
+ gatt_read_char(attrib, handle, char_read_cb, attrib);
+}
+
+static void cmd_read_uuid(int argcp, char **argvp)
+{
+ struct characteristic_data *char_data;
+ int start = 0x0001;
+ int end = 0xffff;
+ uuid_t uuid;
+
+ if (conn_state != STATE_CONNECTED) {
+ printf("Command failed: disconnected\n");
+ return;
+ }
+
+ if (argcp < 2) {
+ printf("Missing argument: UUID\n");
+ return;
+ }
+
+ if (bt_string2uuid(&uuid, argvp[1]) < 0) {
+ printf("Invalid UUID\n");
+ return;
+ }
+
+ if (set_handles(&start, &end, argcp - 1, argvp + 1))
+ return;
+
+ char_data = g_new(struct characteristic_data, 1);
+ char_data->orig_start = start;
+ char_data->start = start;
+ char_data->end = end;
+ char_data->uuid = uuid;
+
+ gatt_read_char_by_uuid(attrib, start, end, &char_data->uuid,
+ char_read_by_uuid_cb, char_data);
+}
+
static struct {
const char *cmd;
void (*func)(int argcp, char **argvp);
@@ -364,6 +501,10 @@ static struct {
"Characteristics Discovery" },
{ "char-desc", cmd_char_desc, "[start hnd] [end hnd]",
"Characteristics Descriptor Discovery" },
+ { "char-read-hnd", cmd_read_hnd, "<handle>",
+ "Characteristics Value/Descriptor Read by handle" },
+ { "char-read-uuid", cmd_read_uuid, "<UUID> [start hnd] [end hnd]",
+ "Characteristics Value/Descriptor Read by UUID" },
{ NULL, NULL, NULL}
};

@@ -372,7 +513,7 @@ static void cmd_help(int argcp, char **argvp)
int i;

for (i = 0; commands[i].cmd; i++)
- printf("%-15s %-25s %s\n", commands[i].cmd,
+ printf("%-15s %-30s %s\n", commands[i].cmd,
commands[i].params, commands[i].desc);
}

--
1.7.1


2011-02-24 13:54:09

by Sheldon Demario

[permalink] [raw]
Subject: [PATCH v3 4/7] Add Characteristics Descriptor Discovery option in interactive gatttool

---

Remove return statements at the end of void functions.

attrib/interactive.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 59 insertions(+), 0 deletions(-)

diff --git a/attrib/interactive.c b/attrib/interactive.c
index ed45894..b00d0bc 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -169,6 +169,47 @@ static void char_cb(GSList *characteristics, guint8 status, gpointer user_data)
rl_forced_update_display();
}

+static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen,
+ gpointer user_data)
+{
+ struct att_data_list *list;
+ guint8 format;
+ int i;
+
+ if (status != 0) {
+ printf("Discover all characteristic descriptors failed: "
+ "%s\n", att_ecode2str(status));
+ return;
+ }
+
+ list = dec_find_info_resp(pdu, plen, &format);
+ if (list == NULL)
+ return;
+
+ printf("\n");
+ for (i = 0; i < list->num; i++) {
+ char uuidstr[MAX_LEN_UUID_STR];
+ uint16_t handle;
+ uint8_t *value;
+ uuid_t uuid;
+
+ value = list->data[i];
+ handle = att_get_u16(value);
+
+ if (format == 0x01)
+ sdp_uuid16_create(&uuid, att_get_u16(&value[2]));
+ else
+ sdp_uuid128_create(&uuid, &value[2]);
+
+ sdp_uuid2strn(&uuid, uuidstr, MAX_LEN_UUID_STR);
+ printf("handle: 0x%04x, uuid: %s\n", handle, uuidstr);
+ }
+
+ att_data_list_free(list);
+
+ rl_forced_update_display();
+}
+
static void cmd_exit(int argcp, char **argvp)
{
rl_callback_handler_remove();
@@ -287,6 +328,22 @@ static void cmd_char(int argcp, char **argvp)
return;
}

+static void cmd_char_desc(int argcp, char **argvp)
+{
+ int start = 0x0001;
+ int end = 0xffff;
+
+ if (conn_state != STATE_CONNECTED) {
+ printf("Command failed: disconnected\n");
+ return;
+ }
+
+ if (set_handles(&start, &end, argcp, argvp))
+ return;
+
+ gatt_find_info(attrib, start, end, char_desc_cb, NULL);
+}
+
static struct {
const char *cmd;
void (*func)(int argcp, char **argvp);
@@ -305,6 +362,8 @@ static struct {
"Primary Service Discovery" },
{ "characteristics", cmd_char, "[start hnd] [end hnd]",
"Characteristics Discovery" },
+ { "char-desc", cmd_char_desc, "[start hnd] [end hnd]",
+ "Characteristics Descriptor Discovery" },
{ NULL, NULL, NULL}
};

--
1.7.1


2011-02-23 14:20:19

by Sheldon Demario

[permalink] [raw]
Subject: [PATCH v3 3/7] Create helper functions to deal with handles on interactive gatttool

---
attrib/interactive.c | 48 +++++++++++++++++++++++++++++++-----------------
1 files changed, 31 insertions(+), 17 deletions(-)

diff --git a/attrib/interactive.c b/attrib/interactive.c
index 7cc03bc..ed45894 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -238,36 +238,50 @@ static void cmd_primary(int argcp, char **argvp)
gatt_discover_primary(attrib, &uuid, primary_by_uuid_cb, NULL);
}

-static void cmd_char(int argcp, char **argvp)
+static int strtohandle(int *dst, const char *src)
{
- int start = 0x0001;
- int end = 0xffff;
+ char *e;

- if (conn_state != STATE_CONNECTED) {
- printf("Command failed: disconnected\n");
- return;
- }
+ errno = 0;
+ *dst = strtoll(src, &e, 16);
+ if (errno != 0 || *e != '\0')
+ return -1;

- if (argcp > 1) {
- char *e;
+ return 0;
+}

- start = strtoll(argvp[1], &e, 16);
- if (errno != 0 || *e != '\0') {
+static int set_handles(int *start, int *end, int argcp, char **argvp)
+{
+ if (argcp > 1) {
+ if (strtohandle(start, argvp[1])) {
printf("Invalid start handle: %s\n", argvp[1]);
- return;
+ return -1;
}
}

if (argcp > 2) {
- char *e;
-
- end = strtoll(argvp[2], &e, 16);
- if (errno != 0 || *e != '\0') {
+ if (strtohandle(end, argvp[2])) {
printf("Invalid end handle: %s\n", argvp[2]);
- return;
+ return -1;
}
}

+ return 0;
+}
+
+static void cmd_char(int argcp, char **argvp)
+{
+ int start = 0x0001;
+ int end = 0xffff;
+
+ if (conn_state != STATE_CONNECTED) {
+ printf("Command failed: disconnected\n");
+ return;
+ }
+
+ if (set_handles(&start, &end, argcp, argvp))
+ return;
+
gatt_discover_char(attrib, start, end, char_cb, NULL);

return;
--
1.7.1


2011-02-23 13:23:34

by Sheldon Demario

[permalink] [raw]
Subject: Re: [PATCH v2 3/7] Create helper functions to deal with handles on interactive gatttool

Hi Johan

On Wed, Feb 23, 2011 at 12:09 AM, Johan Hedberg <[email protected]> wrote:
> Hi Sheldon,
>
> On Tue, Feb 22, 2011, Sheldon Demario wrote:
>> + ? ? *dst = strtoll(src, &e, 16);
>> + ? ? if (errno != 0 || *e != '\0') {
>> + ? ? ? ? ? ? return -1;
>> ? ? ? }
>
> Firstly, you've got a coding style issue here: no {} for one-line
> scopes. Secondly, are you sure that this is the right way to check for
> strtoll failure? If there was some earlier libc function that failed
> errno might be set to != 0 even if strtoll succeeds, right? Or are all
> errno using libc functions guaranteed to set errno to 0 on success?
> Reading the man-page of strtoll it seems you should be checking for
> LLONG_MIN and LLONG_MAX return values.

If strtoll() returns LLONG_MIN or LLONG_MAX the errno is set to ERANGE
so it is not need to check for these returning values. However, as
Lizardo said, the errno must be set to 0 before strtoll() be called,
so will send this fix.

Sheldon.

2011-02-23 12:21:33

by Anderson Lizardo

[permalink] [raw]
Subject: Re: [PATCH v2 3/7] Create helper functions to deal with handles on interactive gatttool

Hi Johan,

On Wed, Feb 23, 2011 at 12:09 AM, Johan Hedberg <[email protected]> wrote:
> Hi Sheldon,
>
> On Tue, Feb 22, 2011, Sheldon Demario wrote:
>> + ? ? *dst = strtoll(src, &e, 16);
>> + ? ? if (errno != 0 || *e != '\0') {
>> + ? ? ? ? ? ? return -1;
>> ? ? ? }
>
> Firstly, you've got a coding style issue here: no {} for one-line
> scopes. Secondly, are you sure that this is the right way to check for
> strtoll failure? If there was some earlier libc function that failed
> errno might be set to != 0 even if strtoll succeeds, right? Or are all
> errno using libc functions guaranteed to set errno to 0 on success?
> Reading the man-page of strtoll it seems you should be checking for
> LLONG_MIN and LLONG_MAX return values.

Looking at "man errno", it is not guaranteed for errno to be set to
zero on success, therefore the recommended way is to set it to zero
prior to calling the function to be checked.

The NOTES section from "man strtoll" recommends using errno when
checking for errors:

"Since strtol() can legitimately return 0, LONG_MAX, or LONG_MIN
(LLONG_MAX or LLONG_MIN for strtoll()) on both success and failure,
the calling program should set errno to 0 before the call, and then
determine if an error occurred by checking whether errno has a
non-zero value after the call."

So I think the only missing bit here it to set errno to zero prior to
calling strtoll()

Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

2011-02-23 03:09:03

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH v2 3/7] Create helper functions to deal with handles on interactive gatttool

Hi Sheldon,

On Tue, Feb 22, 2011, Sheldon Demario wrote:
> + *dst = strtoll(src, &e, 16);
> + if (errno != 0 || *e != '\0') {
> + return -1;
> }

Firstly, you've got a coding style issue here: no {} for one-line
scopes. Secondly, are you sure that this is the right way to check for
strtoll failure? If there was some earlier libc function that failed
errno might be set to != 0 even if strtoll succeeds, right? Or are all
errno using libc functions guaranteed to set errno to 0 on success?
Reading the man-page of strtoll it seems you should be checking for
LLONG_MIN and LLONG_MAX return values.

I've pushed the first two patches since they were fine, but I'll stop
here until we get some clarification on this matter.

Johan

2011-02-22 19:11:58

by Sheldon Demario

[permalink] [raw]
Subject: [PATCH v2 1/7] Improve help messages in interactive gatttool

Includes the parameters info on help.
---
attrib/interactive.c | 19 +++++++++++++------
1 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/attrib/interactive.c b/attrib/interactive.c
index edc465a..b491314 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -217,13 +217,19 @@ static void cmd_primary(int argcp, char **argvp)
static struct {
const char *cmd;
void (*func)(int argcp, char **argvp);
+ const char *params;
const char *desc;
} commands[] = {
- { "help", cmd_help, "Show this help"},
- { "exit", cmd_exit, "Exit interactive mode"},
- { "connect", cmd_connect, "Connect to a remote device"},
- { "disconnect", cmd_disconnect, "Disconnect from a remote device"},
- { "primary", cmd_primary, "Primary Service Discovery"},
+ { "help", cmd_help, "",
+ "Show this help"},
+ { "exit", cmd_exit, "",
+ "Exit interactive mode" },
+ { "connect", cmd_connect, "[address]",
+ "Connect to a remote device" },
+ { "disconnect", cmd_disconnect, "",
+ "Disconnect from a remote device" },
+ { "primary", cmd_primary, "[UUID]",
+ "Primary Service Discovery" },
{ NULL, NULL, NULL}
};

@@ -232,7 +238,8 @@ static void cmd_help(int argcp, char **argvp)
int i;

for (i = 0; commands[i].cmd; i++)
- printf("%-12s\t%s\n", commands[i].cmd, commands[i].desc);
+ printf("%-15s %-25s %s\n", commands[i].cmd,
+ commands[i].params, commands[i].desc);
}

static void parse_line(char *line_read)
--
1.7.1


2011-02-22 19:12:04

by Sheldon Demario

[permalink] [raw]
Subject: [PATCH v2 7/7] Add Write Request in interactive gatttool

From: Bruna Moreira <[email protected]>

---

Add forgoten conn_state check on cmd_char_write_req()

attrib/interactive.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 52 insertions(+), 0 deletions(-)

diff --git a/attrib/interactive.c b/attrib/interactive.c
index a1c5671..9af3daa 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -487,6 +487,56 @@ static void cmd_read_uuid(int argcp, char **argvp)
return;
}

+static void char_write_req_cb(guint8 status, const guint8 *pdu, guint16 plen,
+ gpointer user_data)
+{
+ if (status != 0) {
+ printf("Characteristic Write Request failed: "
+ "%s\n", att_ecode2str(status));
+ return;
+ }
+
+ if (!dec_write_resp(pdu, plen)) {
+ printf("Protocol error\n");
+ return;
+ }
+
+ printf("Characteristic value was written successfully\n");
+}
+
+static void cmd_char_write_req(int argcp, char **argvp)
+{
+ uint8_t *value;
+ size_t plen;
+ int handle;
+
+ if (conn_state != STATE_CONNECTED) {
+ printf("Command failed: disconnected\n");
+ return;
+ }
+
+ if (argcp < 3) {
+ printf("Usage: char-write-req <handle> <new value>\n");
+ return;
+ }
+
+ handle = strtoll(argvp[1], NULL, 16);
+ if (errno != 0 || handle <= 0) {
+ printf("A valid handle is required\n");
+ return;
+ }
+
+ plen = gatt_attr_data_from_string(argvp[2], &value);
+ if (plen == 0) {
+ g_printerr("Invalid value\n");
+ return;
+ }
+
+ gatt_write_char(attrib, handle, value, plen, char_write_req_cb, NULL);
+
+ g_free(value);
+}
+
static struct {
const char *cmd;
void (*func)(int argcp, char **argvp);
@@ -511,6 +561,8 @@ static struct {
"Characteristics Value/Descriptor Read by handle" },
{ "char-read-uuid", cmd_read_uuid, "<UUID> [start hnd] [end hnd]",
"Characteristics Value/Descriptor Read by UUID" },
+ { "char-write-req", cmd_char_write_req, "<handle> <new value>",
+ "Characteristic Value Write (Write Request)" },
{ NULL, NULL, NULL}
};

--
1.7.1


2011-02-22 19:12:03

by Sheldon Demario

[permalink] [raw]
Subject: [PATCH v2 6/7] Move attr_data_from_string() to utils.c

From: Bruna Moreira <[email protected]>

The attr_data_from_string() function will be used in interactive and
usual gatttool so this function was moved to common file utils.c.
---
attrib/gatttool.c | 23 ++---------------------
attrib/gatttool.h | 1 +
attrib/utils.c | 19 +++++++++++++++++++
3 files changed, 22 insertions(+), 21 deletions(-)

diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index 7478043..d7887c6 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -313,25 +313,6 @@ static gboolean characteristics_read(gpointer user_data)
return FALSE;
}

-static size_t attr_data_from_string(const char *str, uint8_t **data)
-{
- char tmp[3];
- size_t size, i;
-
- size = strlen(str) / 2;
- *data = g_try_malloc0(size);
- if (*data == NULL)
- return 0;
-
- tmp[2] = '\0';
- for (i = 0; i < size; i++) {
- memcpy(tmp, str + (i * 2), 2);
- (*data)[i] = (uint8_t) strtol(tmp, NULL, 16);
- }
-
- return size;
-}
-
static void mainloop_quit(gpointer user_data)
{
uint8_t *value = user_data;
@@ -356,7 +337,7 @@ static gboolean characteristics_write(gpointer user_data)
goto error;
}

- len = attr_data_from_string(opt_value, &value);
+ len = gatt_attr_data_from_string(opt_value, &value);
if (len == 0) {
g_printerr("Invalid value\n");
goto error;
@@ -408,7 +389,7 @@ static gboolean characteristics_write_req(gpointer user_data)
goto error;
}

- len = attr_data_from_string(opt_value, &value);
+ len = gatt_attr_data_from_string(opt_value, &value);
if (len == 0) {
g_printerr("Invalid value\n");
goto error;
diff --git a/attrib/gatttool.h b/attrib/gatttool.h
index 7eae18d..2fd4a46 100644
--- a/attrib/gatttool.h
+++ b/attrib/gatttool.h
@@ -25,3 +25,4 @@ int interactive(gchar *dst, gboolean le);
GIOChannel *gatt_connect(const gchar *src, const gchar *dst,
const gchar *sec_level, int psm, int mtu,
BtIOConnect connect_cb);
+size_t gatt_attr_data_from_string(const char *str, uint8_t **data);
diff --git a/attrib/utils.c b/attrib/utils.c
index 4d0000d..8d1ca74 100644
--- a/attrib/utils.c
+++ b/attrib/utils.c
@@ -104,3 +104,22 @@ GIOChannel *gatt_connect(const gchar *src, const gchar *dst,

return chan;
}
+
+size_t gatt_attr_data_from_string(const char *str, uint8_t **data)
+{
+ char tmp[3];
+ size_t size, i;
+
+ size = strlen(str) / 2;
+ *data = g_try_malloc0(size);
+ if (*data == NULL)
+ return 0;
+
+ tmp[2] = '\0';
+ for (i = 0; i < size; i++) {
+ memcpy(tmp, str + (i * 2), 2);
+ (*data)[i] = (uint8_t) strtol(tmp, NULL, 16);
+ }
+
+ return size;
+}
--
1.7.1


2011-02-22 19:12:02

by Sheldon Demario

[permalink] [raw]
Subject: [PATCH v2 5/7] Add characteristics read options in interactive gatttool

---

Add forgoten conn_state check on cmd_read_hnd()

attrib/interactive.c | 147 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 146 insertions(+), 1 deletions(-)

diff --git a/attrib/interactive.c b/attrib/interactive.c
index 9389686..a1c5671 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -50,6 +50,13 @@ static gchar *opt_sec_level = NULL;
static int opt_psm = 0;
static int opt_mtu = 0;

+struct characteristic_data {
+ uint16_t orig_start;
+ uint16_t start;
+ uint16_t end;
+ uuid_t uuid;
+};
+
static void cmd_help(int argcp, char **argvp);

enum state {
@@ -210,6 +217,79 @@ static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen,
rl_forced_update_display();
}

+static void char_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
+ gpointer user_data)
+{
+ uint8_t value[ATT_MAX_MTU];
+ int i, vlen;
+
+ if (status != 0) {
+ printf("Characteristic value/descriptor read failed: %s\n",
+ att_ecode2str(status));
+ return;
+ }
+
+ if (!dec_read_resp(pdu, plen, value, &vlen)) {
+ printf("Protocol error\n");
+ return;
+ }
+
+ printf("\nCharacteristic value/descriptor: ");
+ for (i = 0; i < vlen; i++)
+ printf("%02x ", value[i]);
+ printf("\n");
+
+ rl_forced_update_display();
+}
+
+static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu,
+ guint16 plen, gpointer user_data)
+{
+ struct characteristic_data *char_data = user_data;
+ struct att_data_list *list;
+ int i;
+
+ if (status == ATT_ECODE_ATTR_NOT_FOUND &&
+ char_data->start != char_data->orig_start)
+ goto done;
+
+ if (status != 0) {
+ printf("Read characteristics by UUID failed: %s\n",
+ att_ecode2str(status));
+ goto done;
+ }
+
+ list = dec_read_by_type_resp(pdu, plen);
+ if (list == NULL)
+ goto done;
+
+ for (i = 0; i < list->num; i++) {
+ uint8_t *value = list->data[i];
+ int j;
+
+ char_data->start = att_get_u16(value) + 1;
+
+ printf("\nhandle: 0x%04x \t value: ", att_get_u16(value));
+ value += 2;
+ for (j = 0; j < list->len - 2; j++, value++)
+ printf("%02x ", *value);
+ printf("\n");
+ }
+
+ att_data_list_free(list);
+
+ gatt_read_char_by_uuid(attrib, char_data->start, char_data->end,
+ &char_data->uuid, char_read_by_uuid_cb,
+ char_data);
+
+ rl_forced_update_display();
+
+ return;
+
+done:
+ g_free(char_data);
+}
+
static void cmd_exit(int argcp, char **argvp)
{
rl_callback_handler_remove();
@@ -346,6 +426,67 @@ static void cmd_char_desc(int argcp, char **argvp)
return;
}

+static void cmd_read_hnd(int argcp, char **argvp)
+{
+ int handle;
+
+ if (conn_state != STATE_CONNECTED) {
+ printf("Command failed: disconnected\n");
+ return;
+ }
+
+ if (argcp < 2) {
+ printf("Missing argument: handle\n");
+ return;
+ }
+
+ if (strtohandle(&handle, argvp[1])) {
+ printf("Invalid handle: %s\n", argvp[1]);
+ return;
+ }
+
+ gatt_read_char(attrib, handle, char_read_cb, attrib);
+
+ return;
+}
+
+static void cmd_read_uuid(int argcp, char **argvp)
+{
+ struct characteristic_data *char_data;
+ int start = 0x0001;
+ int end = 0xffff;
+ uuid_t uuid;
+
+ if (conn_state != STATE_CONNECTED) {
+ printf("Command failed: disconnected\n");
+ return;
+ }
+
+ if (argcp < 2) {
+ printf("Missing argument: UUID\n");
+ return;
+ }
+
+ if (bt_string2uuid(&uuid, argvp[1]) < 0) {
+ printf("Invalid UUID\n");
+ return;
+ }
+
+ if (set_handles(&start, &end, argcp - 1, argvp + 1))
+ return;
+
+ char_data = g_new(struct characteristic_data, 1);
+ char_data->orig_start = start;
+ char_data->start = start;
+ char_data->end = end;
+ char_data->uuid = uuid;
+
+ gatt_read_char_by_uuid(attrib, start, end, &char_data->uuid,
+ char_read_by_uuid_cb, char_data);
+
+ return;
+}
+
static struct {
const char *cmd;
void (*func)(int argcp, char **argvp);
@@ -366,6 +507,10 @@ static struct {
"Characteristics Discovery" },
{ "char-desc", cmd_char_desc, "[start hnd] [end hnd]",
"Characteristics Descriptor Discovery" },
+ { "char-read-hnd", cmd_read_hnd, "<handle>",
+ "Characteristics Value/Descriptor Read by handle" },
+ { "char-read-uuid", cmd_read_uuid, "<UUID> [start hnd] [end hnd]",
+ "Characteristics Value/Descriptor Read by UUID" },
{ NULL, NULL, NULL}
};

@@ -374,7 +519,7 @@ static void cmd_help(int argcp, char **argvp)
int i;

for (i = 0; commands[i].cmd; i++)
- printf("%-15s %-25s %s\n", commands[i].cmd,
+ printf("%-15s %-30s %s\n", commands[i].cmd,
commands[i].params, commands[i].desc);
}

--
1.7.1


2011-02-22 19:12:01

by Sheldon Demario

[permalink] [raw]
Subject: [PATCH v2 4/7] Add Characteristics Descriptor Discovery option in interactive gatttool

---
attrib/interactive.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 61 insertions(+), 0 deletions(-)

diff --git a/attrib/interactive.c b/attrib/interactive.c
index e9f6019..9389686 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -169,6 +169,47 @@ static void char_cb(GSList *characteristics, guint8 status, gpointer user_data)
rl_forced_update_display();
}

+static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen,
+ gpointer user_data)
+{
+ struct att_data_list *list;
+ guint8 format;
+ int i;
+
+ if (status != 0) {
+ printf("Discover all characteristic descriptors failed: "
+ "%s\n", att_ecode2str(status));
+ return;
+ }
+
+ list = dec_find_info_resp(pdu, plen, &format);
+ if (list == NULL)
+ return;
+
+ printf("\n");
+ for (i = 0; i < list->num; i++) {
+ char uuidstr[MAX_LEN_UUID_STR];
+ uint16_t handle;
+ uint8_t *value;
+ uuid_t uuid;
+
+ value = list->data[i];
+ handle = att_get_u16(value);
+
+ if (format == 0x01)
+ sdp_uuid16_create(&uuid, att_get_u16(&value[2]));
+ else
+ sdp_uuid128_create(&uuid, &value[2]);
+
+ sdp_uuid2strn(&uuid, uuidstr, MAX_LEN_UUID_STR);
+ printf("handle: 0x%04x, uuid: %s\n", handle, uuidstr);
+ }
+
+ att_data_list_free(list);
+
+ rl_forced_update_display();
+}
+
static void cmd_exit(int argcp, char **argvp)
{
rl_callback_handler_remove();
@@ -287,6 +328,24 @@ static void cmd_char(int argcp, char **argvp)
return;
}

+static void cmd_char_desc(int argcp, char **argvp)
+{
+ int start = 0x0001;
+ int end = 0xffff;
+
+ if (conn_state != STATE_CONNECTED) {
+ printf("Command failed: disconnected\n");
+ return;
+ }
+
+ if (set_handles(&start, &end, argcp, argvp))
+ return;
+
+ gatt_find_info(attrib, start, end, char_desc_cb, NULL);
+
+ return;
+}
+
static struct {
const char *cmd;
void (*func)(int argcp, char **argvp);
@@ -305,6 +364,8 @@ static struct {
"Primary Service Discovery" },
{ "characteristics", cmd_char, "[start hnd] [end hnd]",
"Characteristics Discovery" },
+ { "char-desc", cmd_char_desc, "[start hnd] [end hnd]",
+ "Characteristics Descriptor Discovery" },
{ NULL, NULL, NULL}
};

--
1.7.1


2011-02-22 19:12:00

by Sheldon Demario

[permalink] [raw]
Subject: [PATCH v2 3/7] Create helper functions to deal with handles on interactive gatttool

---
attrib/interactive.c | 46 ++++++++++++++++++++++++++++++----------------
1 files changed, 30 insertions(+), 16 deletions(-)

diff --git a/attrib/interactive.c b/attrib/interactive.c
index 7cc03bc..e9f6019 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -238,36 +238,50 @@ static void cmd_primary(int argcp, char **argvp)
gatt_discover_primary(attrib, &uuid, primary_by_uuid_cb, NULL);
}

-static void cmd_char(int argcp, char **argvp)
+static int strtohandle(int *dst, const char *src)
{
- int start = 0x0001;
- int end = 0xffff;
+ char *e;

- if (conn_state != STATE_CONNECTED) {
- printf("Command failed: disconnected\n");
- return;
+ *dst = strtoll(src, &e, 16);
+ if (errno != 0 || *e != '\0') {
+ return -1;
}

- if (argcp > 1) {
- char *e;
+ return 0;
+}

- start = strtoll(argvp[1], &e, 16);
- if (errno != 0 || *e != '\0') {
+static int set_handles(int *start, int *end, int argcp, char **argvp)
+{
+ if (argcp > 1) {
+ if (strtohandle(start, argvp[1])) {
printf("Invalid start handle: %s\n", argvp[1]);
- return;
+ return -1;
}
}

if (argcp > 2) {
- char *e;
-
- end = strtoll(argvp[2], &e, 16);
- if (errno != 0 || *e != '\0') {
+ if (strtohandle(end, argvp[2])) {
printf("Invalid end handle: %s\n", argvp[2]);
- return;
+ return -1;
}
}

+ return 0;
+}
+
+static void cmd_char(int argcp, char **argvp)
+{
+ int start = 0x0001;
+ int end = 0xffff;
+
+ if (conn_state != STATE_CONNECTED) {
+ printf("Command failed: disconnected\n");
+ return;
+ }
+
+ if (set_handles(&start, &end, argcp, argvp))
+ return;
+
gatt_discover_char(attrib, start, end, char_cb, NULL);

return;
--
1.7.1


2011-02-22 19:11:59

by Sheldon Demario

[permalink] [raw]
Subject: [PATCH v2 2/7] Add Characteristics Discovery option to interactive gatttool

---
attrib/interactive.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 61 insertions(+), 0 deletions(-)

diff --git a/attrib/interactive.c b/attrib/interactive.c
index b491314..7cc03bc 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -22,6 +22,7 @@
*/
#include <string.h>
#include <stdlib.h>
+#include <errno.h>
#include <stdio.h>
#include <glib.h>

@@ -145,6 +146,29 @@ static void primary_by_uuid_cb(GSList *ranges, guint8 status,
rl_forced_update_display();
}

+static void char_cb(GSList *characteristics, guint8 status, gpointer user_data)
+{
+ GSList *l;
+
+ if (status) {
+ printf("Discover all characteristics failed: %s\n",
+ att_ecode2str(status));
+ return;
+ }
+
+ printf("\n");
+ for (l = characteristics; l; l = l->next) {
+ struct att_char *chars = l->data;
+
+ printf("handle: 0x%04x, char properties: 0x%02x, char value "
+ "handle: 0x%04x, uuid: %s\n", chars->handle,
+ chars->properties, chars->value_handle,
+ chars->uuid);
+ }
+
+ rl_forced_update_display();
+}
+
static void cmd_exit(int argcp, char **argvp)
{
rl_callback_handler_remove();
@@ -214,6 +238,41 @@ static void cmd_primary(int argcp, char **argvp)
gatt_discover_primary(attrib, &uuid, primary_by_uuid_cb, NULL);
}

+static void cmd_char(int argcp, char **argvp)
+{
+ int start = 0x0001;
+ int end = 0xffff;
+
+ if (conn_state != STATE_CONNECTED) {
+ printf("Command failed: disconnected\n");
+ return;
+ }
+
+ if (argcp > 1) {
+ char *e;
+
+ start = strtoll(argvp[1], &e, 16);
+ if (errno != 0 || *e != '\0') {
+ printf("Invalid start handle: %s\n", argvp[1]);
+ return;
+ }
+ }
+
+ if (argcp > 2) {
+ char *e;
+
+ end = strtoll(argvp[2], &e, 16);
+ if (errno != 0 || *e != '\0') {
+ printf("Invalid end handle: %s\n", argvp[2]);
+ return;
+ }
+ }
+
+ gatt_discover_char(attrib, start, end, char_cb, NULL);
+
+ return;
+}
+
static struct {
const char *cmd;
void (*func)(int argcp, char **argvp);
@@ -230,6 +289,8 @@ static struct {
"Disconnect from a remote device" },
{ "primary", cmd_primary, "[UUID]",
"Primary Service Discovery" },
+ { "characteristics", cmd_char, "[start hnd] [end hnd]",
+ "Characteristics Discovery" },
{ NULL, NULL, NULL}
};

--
1.7.1


2011-02-21 22:50:01

by Sheldon Demario

[permalink] [raw]
Subject: [PATCH 2/7] Add Characteristics Discovery option to interactive gatttool

---
attrib/interactive.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 61 insertions(+), 0 deletions(-)

diff --git a/attrib/interactive.c b/attrib/interactive.c
index b491314..7cc03bc 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -22,6 +22,7 @@
*/
#include <string.h>
#include <stdlib.h>
+#include <errno.h>
#include <stdio.h>
#include <glib.h>

@@ -145,6 +146,29 @@ static void primary_by_uuid_cb(GSList *ranges, guint8 status,
rl_forced_update_display();
}

+static void char_cb(GSList *characteristics, guint8 status, gpointer user_data)
+{
+ GSList *l;
+
+ if (status) {
+ printf("Discover all characteristics failed: %s\n",
+ att_ecode2str(status));
+ return;
+ }
+
+ printf("\n");
+ for (l = characteristics; l; l = l->next) {
+ struct att_char *chars = l->data;
+
+ printf("handle: 0x%04x, char properties: 0x%02x, char value "
+ "handle: 0x%04x, uuid: %s\n", chars->handle,
+ chars->properties, chars->value_handle,
+ chars->uuid);
+ }
+
+ rl_forced_update_display();
+}
+
static void cmd_exit(int argcp, char **argvp)
{
rl_callback_handler_remove();
@@ -214,6 +238,41 @@ static void cmd_primary(int argcp, char **argvp)
gatt_discover_primary(attrib, &uuid, primary_by_uuid_cb, NULL);
}

+static void cmd_char(int argcp, char **argvp)
+{
+ int start = 0x0001;
+ int end = 0xffff;
+
+ if (conn_state != STATE_CONNECTED) {
+ printf("Command failed: disconnected\n");
+ return;
+ }
+
+ if (argcp > 1) {
+ char *e;
+
+ start = strtoll(argvp[1], &e, 16);
+ if (errno != 0 || *e != '\0') {
+ printf("Invalid start handle: %s\n", argvp[1]);
+ return;
+ }
+ }
+
+ if (argcp > 2) {
+ char *e;
+
+ end = strtoll(argvp[2], &e, 16);
+ if (errno != 0 || *e != '\0') {
+ printf("Invalid end handle: %s\n", argvp[2]);
+ return;
+ }
+ }
+
+ gatt_discover_char(attrib, start, end, char_cb, NULL);
+
+ return;
+}
+
static struct {
const char *cmd;
void (*func)(int argcp, char **argvp);
@@ -230,6 +289,8 @@ static struct {
"Disconnect from a remote device" },
{ "primary", cmd_primary, "[UUID]",
"Primary Service Discovery" },
+ { "characteristics", cmd_char, "[start hnd] [end hnd]",
+ "Characteristics Discovery" },
{ NULL, NULL, NULL}
};

--
1.7.1


2011-02-21 22:50:04

by Sheldon Demario

[permalink] [raw]
Subject: [PATCH 5/7] Add characteristics read options in interactive gatttool

---
attrib/interactive.c | 142 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 141 insertions(+), 1 deletions(-)

diff --git a/attrib/interactive.c b/attrib/interactive.c
index 9389686..e9d74b9 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -50,6 +50,13 @@ static gchar *opt_sec_level = NULL;
static int opt_psm = 0;
static int opt_mtu = 0;

+struct characteristic_data {
+ uint16_t orig_start;
+ uint16_t start;
+ uint16_t end;
+ uuid_t uuid;
+};
+
static void cmd_help(int argcp, char **argvp);

enum state {
@@ -210,6 +217,79 @@ static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen,
rl_forced_update_display();
}

+static void char_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
+ gpointer user_data)
+{
+ uint8_t value[ATT_MAX_MTU];
+ int i, vlen;
+
+ if (status != 0) {
+ printf("Characteristic value/descriptor read failed: %s\n",
+ att_ecode2str(status));
+ return;
+ }
+
+ if (!dec_read_resp(pdu, plen, value, &vlen)) {
+ printf("Protocol error\n");
+ return;
+ }
+
+ printf("\nCharacteristic value/descriptor: ");
+ for (i = 0; i < vlen; i++)
+ printf("%02x ", value[i]);
+ printf("\n");
+
+ rl_forced_update_display();
+}
+
+static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu,
+ guint16 plen, gpointer user_data)
+{
+ struct characteristic_data *char_data = user_data;
+ struct att_data_list *list;
+ int i;
+
+ if (status == ATT_ECODE_ATTR_NOT_FOUND &&
+ char_data->start != char_data->orig_start)
+ goto done;
+
+ if (status != 0) {
+ printf("Read characteristics by UUID failed: %s\n",
+ att_ecode2str(status));
+ goto done;
+ }
+
+ list = dec_read_by_type_resp(pdu, plen);
+ if (list == NULL)
+ goto done;
+
+ for (i = 0; i < list->num; i++) {
+ uint8_t *value = list->data[i];
+ int j;
+
+ char_data->start = att_get_u16(value) + 1;
+
+ printf("\nhandle: 0x%04x \t value: ", att_get_u16(value));
+ value += 2;
+ for (j = 0; j < list->len - 2; j++, value++)
+ printf("%02x ", *value);
+ printf("\n");
+ }
+
+ att_data_list_free(list);
+
+ gatt_read_char_by_uuid(attrib, char_data->start, char_data->end,
+ &char_data->uuid, char_read_by_uuid_cb,
+ char_data);
+
+ rl_forced_update_display();
+
+ return;
+
+done:
+ g_free(char_data);
+}
+
static void cmd_exit(int argcp, char **argvp)
{
rl_callback_handler_remove();
@@ -346,6 +426,62 @@ static void cmd_char_desc(int argcp, char **argvp)
return;
}

+static void cmd_read_hnd(int argcp, char **argvp)
+{
+ int handle;
+
+ if (argcp < 2) {
+ printf("Missing argument: handle\n");
+ return;
+ }
+
+ if (strtohandle(&handle, argvp[1])) {
+ printf("Invalid handle: %s\n", argvp[1]);
+ return;
+ }
+
+ gatt_read_char(attrib, handle, char_read_cb, attrib);
+
+ return;
+}
+
+static void cmd_read_uuid(int argcp, char **argvp)
+{
+ struct characteristic_data *char_data;
+ int start = 0x0001;
+ int end = 0xffff;
+ uuid_t uuid;
+
+ if (conn_state != STATE_CONNECTED) {
+ printf("Command failed: disconnected\n");
+ return;
+ }
+
+ if (argcp < 2) {
+ printf("Missing argument: UUID\n");
+ return;
+ }
+
+ if (bt_string2uuid(&uuid, argvp[1]) < 0) {
+ printf("Invalid UUID\n");
+ return;
+ }
+
+ if (set_handles(&start, &end, argcp - 1, argvp + 1))
+ return;
+
+ char_data = g_new(struct characteristic_data, 1);
+ char_data->orig_start = start;
+ char_data->start = start;
+ char_data->end = end;
+ char_data->uuid = uuid;
+
+ gatt_read_char_by_uuid(attrib, start, end, &char_data->uuid,
+ char_read_by_uuid_cb, char_data);
+
+ return;
+}
+
static struct {
const char *cmd;
void (*func)(int argcp, char **argvp);
@@ -366,6 +502,10 @@ static struct {
"Characteristics Discovery" },
{ "char-desc", cmd_char_desc, "[start hnd] [end hnd]",
"Characteristics Descriptor Discovery" },
+ { "char-read-hnd", cmd_read_hnd, "<handle>",
+ "Characteristics Value/Descriptor Read by handle" },
+ { "char-read-uuid", cmd_read_uuid, "<UUID> [start hnd] [end hnd]",
+ "Characteristics Value/Descriptor Read by UUID" },
{ NULL, NULL, NULL}
};

@@ -374,7 +514,7 @@ static void cmd_help(int argcp, char **argvp)
int i;

for (i = 0; commands[i].cmd; i++)
- printf("%-15s %-25s %s\n", commands[i].cmd,
+ printf("%-15s %-30s %s\n", commands[i].cmd,
commands[i].params, commands[i].desc);
}

--
1.7.1


2011-02-21 22:50:06

by Sheldon Demario

[permalink] [raw]
Subject: [PATCH 7/7] Add Write Request in interactive gatttool

From: Bruna Moreira <[email protected]>

---
attrib/interactive.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 47 insertions(+), 0 deletions(-)

diff --git a/attrib/interactive.c b/attrib/interactive.c
index e9d74b9..30e9f60 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -482,6 +482,51 @@ static void cmd_read_uuid(int argcp, char **argvp)
return;
}

+static void char_write_req_cb(guint8 status, const guint8 *pdu, guint16 plen,
+ gpointer user_data)
+{
+ if (status != 0) {
+ printf("Characteristic Write Request failed: "
+ "%s\n", att_ecode2str(status));
+ return;
+ }
+
+ if (!dec_write_resp(pdu, plen)) {
+ printf("Protocol error\n");
+ return;
+ }
+
+ printf("Characteristic value was written successfully\n");
+}
+
+static void cmd_char_write_req(int argcp, char **argvp)
+{
+ uint8_t *value;
+ size_t plen;
+ int handle;
+
+ if (argcp < 3) {
+ printf("Usage: char-write-req <handle> <new value>\n");
+ return;
+ }
+
+ handle = strtoll(argvp[1], NULL, 16);
+ if (errno != 0 || handle <= 0) {
+ printf("A valid handle is required\n");
+ return;
+ }
+
+ plen = gatt_attr_data_from_string(argvp[2], &value);
+ if (plen == 0) {
+ g_printerr("Invalid value\n");
+ return;
+ }
+
+ gatt_write_char(attrib, handle, value, plen, char_write_req_cb, NULL);
+
+ g_free(value);
+}
+
static struct {
const char *cmd;
void (*func)(int argcp, char **argvp);
@@ -506,6 +551,8 @@ static struct {
"Characteristics Value/Descriptor Read by handle" },
{ "char-read-uuid", cmd_read_uuid, "<UUID> [start hnd] [end hnd]",
"Characteristics Value/Descriptor Read by UUID" },
+ { "char-write-req", cmd_char_write_req, "<handle> <new value>",
+ "Characteristic Value Write (Write Request)"},
{ NULL, NULL, NULL}
};

--
1.7.1


2011-02-21 22:50:05

by Sheldon Demario

[permalink] [raw]
Subject: [PATCH 6/7] Move attr_data_from_string() to utils.c

From: Bruna Moreira <[email protected]>

The attr_data_from_string() function will be used in interactive and
usual gatttool so this function was moved to common file utils.c.
---
attrib/gatttool.c | 23 ++---------------------
attrib/gatttool.h | 1 +
attrib/utils.c | 19 +++++++++++++++++++
3 files changed, 22 insertions(+), 21 deletions(-)

diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index 7478043..d7887c6 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -313,25 +313,6 @@ static gboolean characteristics_read(gpointer user_data)
return FALSE;
}

-static size_t attr_data_from_string(const char *str, uint8_t **data)
-{
- char tmp[3];
- size_t size, i;
-
- size = strlen(str) / 2;
- *data = g_try_malloc0(size);
- if (*data == NULL)
- return 0;
-
- tmp[2] = '\0';
- for (i = 0; i < size; i++) {
- memcpy(tmp, str + (i * 2), 2);
- (*data)[i] = (uint8_t) strtol(tmp, NULL, 16);
- }
-
- return size;
-}
-
static void mainloop_quit(gpointer user_data)
{
uint8_t *value = user_data;
@@ -356,7 +337,7 @@ static gboolean characteristics_write(gpointer user_data)
goto error;
}

- len = attr_data_from_string(opt_value, &value);
+ len = gatt_attr_data_from_string(opt_value, &value);
if (len == 0) {
g_printerr("Invalid value\n");
goto error;
@@ -408,7 +389,7 @@ static gboolean characteristics_write_req(gpointer user_data)
goto error;
}

- len = attr_data_from_string(opt_value, &value);
+ len = gatt_attr_data_from_string(opt_value, &value);
if (len == 0) {
g_printerr("Invalid value\n");
goto error;
diff --git a/attrib/gatttool.h b/attrib/gatttool.h
index 7eae18d..2fd4a46 100644
--- a/attrib/gatttool.h
+++ b/attrib/gatttool.h
@@ -25,3 +25,4 @@ int interactive(gchar *dst, gboolean le);
GIOChannel *gatt_connect(const gchar *src, const gchar *dst,
const gchar *sec_level, int psm, int mtu,
BtIOConnect connect_cb);
+size_t gatt_attr_data_from_string(const char *str, uint8_t **data);
diff --git a/attrib/utils.c b/attrib/utils.c
index 4d0000d..8d1ca74 100644
--- a/attrib/utils.c
+++ b/attrib/utils.c
@@ -104,3 +104,22 @@ GIOChannel *gatt_connect(const gchar *src, const gchar *dst,

return chan;
}
+
+size_t gatt_attr_data_from_string(const char *str, uint8_t **data)
+{
+ char tmp[3];
+ size_t size, i;
+
+ size = strlen(str) / 2;
+ *data = g_try_malloc0(size);
+ if (*data == NULL)
+ return 0;
+
+ tmp[2] = '\0';
+ for (i = 0; i < size; i++) {
+ memcpy(tmp, str + (i * 2), 2);
+ (*data)[i] = (uint8_t) strtol(tmp, NULL, 16);
+ }
+
+ return size;
+}
--
1.7.1


2011-02-21 22:50:03

by Sheldon Demario

[permalink] [raw]
Subject: [PATCH 4/7] Add Characteristics Descriptor Discovery option in interactive gatttool

---
attrib/interactive.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 61 insertions(+), 0 deletions(-)

diff --git a/attrib/interactive.c b/attrib/interactive.c
index e9f6019..9389686 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -169,6 +169,47 @@ static void char_cb(GSList *characteristics, guint8 status, gpointer user_data)
rl_forced_update_display();
}

+static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen,
+ gpointer user_data)
+{
+ struct att_data_list *list;
+ guint8 format;
+ int i;
+
+ if (status != 0) {
+ printf("Discover all characteristic descriptors failed: "
+ "%s\n", att_ecode2str(status));
+ return;
+ }
+
+ list = dec_find_info_resp(pdu, plen, &format);
+ if (list == NULL)
+ return;
+
+ printf("\n");
+ for (i = 0; i < list->num; i++) {
+ char uuidstr[MAX_LEN_UUID_STR];
+ uint16_t handle;
+ uint8_t *value;
+ uuid_t uuid;
+
+ value = list->data[i];
+ handle = att_get_u16(value);
+
+ if (format == 0x01)
+ sdp_uuid16_create(&uuid, att_get_u16(&value[2]));
+ else
+ sdp_uuid128_create(&uuid, &value[2]);
+
+ sdp_uuid2strn(&uuid, uuidstr, MAX_LEN_UUID_STR);
+ printf("handle: 0x%04x, uuid: %s\n", handle, uuidstr);
+ }
+
+ att_data_list_free(list);
+
+ rl_forced_update_display();
+}
+
static void cmd_exit(int argcp, char **argvp)
{
rl_callback_handler_remove();
@@ -287,6 +328,24 @@ static void cmd_char(int argcp, char **argvp)
return;
}

+static void cmd_char_desc(int argcp, char **argvp)
+{
+ int start = 0x0001;
+ int end = 0xffff;
+
+ if (conn_state != STATE_CONNECTED) {
+ printf("Command failed: disconnected\n");
+ return;
+ }
+
+ if (set_handles(&start, &end, argcp, argvp))
+ return;
+
+ gatt_find_info(attrib, start, end, char_desc_cb, NULL);
+
+ return;
+}
+
static struct {
const char *cmd;
void (*func)(int argcp, char **argvp);
@@ -305,6 +364,8 @@ static struct {
"Primary Service Discovery" },
{ "characteristics", cmd_char, "[start hnd] [end hnd]",
"Characteristics Discovery" },
+ { "char-desc", cmd_char_desc, "[start hnd] [end hnd]",
+ "Characteristics Descriptor Discovery" },
{ NULL, NULL, NULL}
};

--
1.7.1


2011-02-21 22:50:02

by Sheldon Demario

[permalink] [raw]
Subject: [PATCH 3/7] Create helper functions to deal with handles on interactive gatttool

---
attrib/interactive.c | 46 ++++++++++++++++++++++++++++++----------------
1 files changed, 30 insertions(+), 16 deletions(-)

diff --git a/attrib/interactive.c b/attrib/interactive.c
index 7cc03bc..e9f6019 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -238,36 +238,50 @@ static void cmd_primary(int argcp, char **argvp)
gatt_discover_primary(attrib, &uuid, primary_by_uuid_cb, NULL);
}

-static void cmd_char(int argcp, char **argvp)
+static int strtohandle(int *dst, const char *src)
{
- int start = 0x0001;
- int end = 0xffff;
+ char *e;

- if (conn_state != STATE_CONNECTED) {
- printf("Command failed: disconnected\n");
- return;
+ *dst = strtoll(src, &e, 16);
+ if (errno != 0 || *e != '\0') {
+ return -1;
}

- if (argcp > 1) {
- char *e;
+ return 0;
+}

- start = strtoll(argvp[1], &e, 16);
- if (errno != 0 || *e != '\0') {
+static int set_handles(int *start, int *end, int argcp, char **argvp)
+{
+ if (argcp > 1) {
+ if (strtohandle(start, argvp[1])) {
printf("Invalid start handle: %s\n", argvp[1]);
- return;
+ return -1;
}
}

if (argcp > 2) {
- char *e;
-
- end = strtoll(argvp[2], &e, 16);
- if (errno != 0 || *e != '\0') {
+ if (strtohandle(end, argvp[2])) {
printf("Invalid end handle: %s\n", argvp[2]);
- return;
+ return -1;
}
}

+ return 0;
+}
+
+static void cmd_char(int argcp, char **argvp)
+{
+ int start = 0x0001;
+ int end = 0xffff;
+
+ if (conn_state != STATE_CONNECTED) {
+ printf("Command failed: disconnected\n");
+ return;
+ }
+
+ if (set_handles(&start, &end, argcp, argvp))
+ return;
+
gatt_discover_char(attrib, start, end, char_cb, NULL);

return;
--
1.7.1