2015-04-03 13:43:29

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 00/27] HoG: Replace gattrib with gatt_client

These patches replace gattrib with bt_gatt_client.
It is part of HoG deduplication. HoG, ScPP, DIS, BAS have been
cleaned from glib, btio, attrib dependencies.

Note, that unit/test-hog tests are no longer valid and won't work since
were written to be used with attrib. Fixes for unit tests will be
sent in the next set of patches.

v2:
Fixed dangling pointers;
Added check if pointer to allocated mem isn't null
Merged "Add MIN definition" and "Remove attrib" patches
Corrected commit subjects and messages

Mariusz Skamra (27):
android/hidhost: Create bt_gatt_client
android/hog: Introduce bt_gatt_client
shared/gatt-client: Expose gatt_db
android/hog: Remove tracking gatt operations
android/hog: Use bt_gatt_client to read characteristic value
android/hog: Use bt_gatt_client to register for notifications
android/hog: Use bt_gatt_client to write without response
android/hog: Replace gatt_write_char with bt_gatt_client_write_value
android/hog: Use gatt_db to search for services and characteristics in
db
android/hog: Add helper to create uhid device
lib/uuid: Add define for HoG UUID
android/hog: Replace list of reports with a queue of reports
android/hog: Replace GSList of hog instances with queue of instances
android/dis: Remove tracking pending gatt operations
android/dis: Introduce bt_gatt_client
android/scpp: Remove tracking pending gatt operations
android/scpp: Introduce bt_gatt_client
android/scpp: Merge refresh_discovered_cb with iwin_discovered_cb
android/bas: Remove tracking pending gatt operations
android/bas: Start using bt_gatt_client
android/hog: Strip btio dependencies
android/hog: Enable Input Report notifications only if uhid is created
android/bas: Enable Battery Level notifications after reconnection
android/hog: Clean the code from attrib dependencies
android/hog: Remove glib dependencies
android/hog: Remove redundant code
android/hog: Replace definitions of characteristic uuids with bt_uuids

android/Android.mk | 2 +
android/bas.c | 313 +++----------
android/bas.h | 4 +-
android/dis.c | 203 ++------
android/dis.h | 4 +-
android/hidhost.c | 80 +++-
android/hog.c | 1150 ++++++++++++++++------------------------------
android/hog.h | 12 +-
android/scpp.c | 263 +++--------
android/scpp.h | 4 +-
lib/uuid.h | 1 +
src/shared/gatt-client.c | 8 +
src/shared/gatt-client.h | 1 +
unit/test-hog.c | 9 +-
14 files changed, 664 insertions(+), 1390 deletions(-)

--
1.9.1



2015-04-08 10:11:10

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCHv2 04/27] android/hog: Remove tracking gatt operations

Hi Mariusz,

On Wed, Apr 8, 2015 at 11:47 AM, Skamra Mariusz
<[email protected]> wrote:
> Hi Luiz
>
>
> On 2015-04-07 09:50, Luiz Augusto von Dentz wrote:
>>
>> Hi Mariusz,
>>
>> On Fri, Apr 3, 2015 at 4:43 PM, Mariusz Skamra <[email protected]>
>> wrote:
>>>
>>> Since the use of bt_gatt_client there is no need to queue pending gatt
>>> operations. bt_gatt_client already keeps track on that, so that
>>> on bt_gatt_client_unref the queue of pending requests is destroyed.
>>
>>
>> This assumption that unref will properly cancel the pending request is
>> not correct, it will only do what you are saying if it is the last
>> reference so we still need to track the requests and properly cancel
>> them since we have no idea how many references of bt_gatt_client
>> exists.
>
>
> Thanks for that. I will remove this patch from hog as well as other profiles
> (scpp, dis, bas). I already discussed that with Szymon, and my intention was
> to delete all the requests after the last gatt_client dereference (just like
> you wrote). I assumed that if we want to disconnect/remove device, all the
> pending requests, no matter of which gatt based service will be removed.

I would actually attempt to move this logic into bt_gatt_client, first
it needs to track the requests per instance so when an instance needs
to be freed we should be able to cancel all request done by that
instance, the second step is to create bt_gatt_client_clone so we can
clone/dup existing instances skipping the service discovery but
reusing the same bt_att and bt_gatt_db, that way bt_hog could clone on
bt_hog_attach then the cloned instance would be used to track the
requests and cancel if necessary. Anyway this can come in a separate
set, this set is already too big imo.



--
Luiz Augusto von Dentz

2015-04-08 08:47:28

by Mariusz Skamra

[permalink] [raw]
Subject: Re: [PATCHv2 04/27] android/hog: Remove tracking gatt operations

Hi Luiz

On 2015-04-07 09:50, Luiz Augusto von Dentz wrote:
> Hi Mariusz,
>
> On Fri, Apr 3, 2015 at 4:43 PM, Mariusz Skamra <[email protected]> wrote:
>> Since the use of bt_gatt_client there is no need to queue pending gatt
>> operations. bt_gatt_client already keeps track on that, so that
>> on bt_gatt_client_unref the queue of pending requests is destroyed.
>
> This assumption that unref will properly cancel the pending request is
> not correct, it will only do what you are saying if it is the last
> reference so we still need to track the requests and properly cancel
> them since we have no idea how many references of bt_gatt_client
> exists.

Thanks for that. I will remove this patch from hog as well as other
profiles (scpp, dis, bas). I already discussed that with Szymon, and my
intention was to delete all the requests after the last gatt_client
dereference (just like you wrote). I assumed that if we want to
disconnect/remove device, all the pending requests, no matter of which
gatt based service will be removed.


2015-04-07 08:01:14

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCHv2 03/27] shared/gatt-client: Expose gatt_db

Hi Mariusz,

On Fri, Apr 3, 2015 at 4:43 PM, Mariusz Skamra <[email protected]> wrote:
> This patch adds the bt_gatt_client_get_db function, which allows
> to get a reference to db from client structure. This is useful
> when as a client we need to have an access db, to explore some
> attributes.
> ---
> src/shared/gatt-client.c | 8 ++++++++
> src/shared/gatt-client.h | 1 +
> 2 files changed, 9 insertions(+)
>
> diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
> index 729bd87..f006ae6 100644
> --- a/src/shared/gatt-client.c
> +++ b/src/shared/gatt-client.c
> @@ -1760,6 +1760,14 @@ uint16_t bt_gatt_client_get_mtu(struct bt_gatt_client *client)
> return bt_att_get_mtu(client->att);
> }
>
> +struct gatt_db *bt_gatt_client_get_db(struct bt_gatt_client *client)
> +{
> + if (!client || !client->db)
> + return NULL;
> +
> + return client->db;
> +}
> +
> static bool match_req_id(const void *a, const void *b)
> {
> const struct request *req = a;
> diff --git a/src/shared/gatt-client.h b/src/shared/gatt-client.h
> index 8e5e0f5..f539a61 100644
> --- a/src/shared/gatt-client.h
> +++ b/src/shared/gatt-client.h
> @@ -70,6 +70,7 @@ bool bt_gatt_client_set_debug(struct bt_gatt_client *client,
> bt_gatt_client_destroy_func_t destroy);
>
> uint16_t bt_gatt_client_get_mtu(struct bt_gatt_client *client);
> +struct gatt_db *bt_gatt_client_get_db(struct bt_gatt_client *client);
>
> bool bt_gatt_client_cancel(struct bt_gatt_client *client, unsigned int id);
> bool bt_gatt_client_cancel_all(struct bt_gatt_client *client);
> --
> 1.9.1

I went ahead and applied this one.


--
Luiz Augusto von Dentz

2015-04-07 07:50:43

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCHv2 04/27] android/hog: Remove tracking gatt operations

Hi Mariusz,

On Fri, Apr 3, 2015 at 4:43 PM, Mariusz Skamra <[email protected]> wrote:
> Since the use of bt_gatt_client there is no need to queue pending gatt
> operations. bt_gatt_client already keeps track on that, so that
> on bt_gatt_client_unref the queue of pending requests is destroyed.

This assumption that unref will properly cancel the pending request is
not correct, it will only do what you are saying if it is the last
reference so we still need to track the requests and properly cancel
them since we have no idea how many references of bt_gatt_client
exists.


--
Luiz Augusto von Dentz

2015-04-07 07:44:42

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCHv2 02/27] android/hog: Introduce bt_gatt_client

Hi Mariusz,

On Fri, Apr 3, 2015 at 4:43 PM, Mariusz Skamra <[email protected]> wrote:
> This patch introduces bt_gatt_client to HoG. Service handle will be used
> to obtain the attribute from cached database.
> ---
> android/hidhost.c | 4 ++--
> android/hog.c | 30 +++++++++++++++++++++---------
> android/hog.h | 6 +++---
> unit/test-hog.c | 4 ++--
> 4 files changed, 28 insertions(+), 16 deletions(-)
>
> diff --git a/android/hidhost.c b/android/hidhost.c
> index 26a8013..00b6efa 100644
> --- a/android/hidhost.c
> +++ b/android/hidhost.c
> @@ -814,7 +814,7 @@ static void client_ready_cb(bool success, uint8_t att_ecode, void *user_data)
> goto fail;
> }
>
> - if (!bt_hog_attach(dev->hog, dev->attrib)) {
> + if (!bt_hog_attach(dev->hog, dev->attrib, dev->client)) {
> error("HoG: unable to attach");
> goto fail;
> }
> @@ -862,7 +862,7 @@ static void hog_conn_cb(const bdaddr_t *addr, int err, void *attrib)
> if (!dev->hog) {
> /* TODO: Get device details */
> dev->hog = bt_hog_new_default("bluez-input-device", dev->vendor,
> - dev->product, dev->version, NULL);
> + dev->product, dev->version, NULL, 0);
> if (!dev->hog) {
> error("HoG: unable to create session");
> goto fail;
> diff --git a/android/hog.c b/android/hog.c
> index ff77bb3..931ac0b 100644
> --- a/android/hog.c
> +++ b/android/hog.c
> @@ -45,6 +45,9 @@
> #include "src/shared/util.h"
> #include "src/shared/uhid.h"
> #include "src/shared/queue.h"
> +#include "src/shared/att.h"
> +#include "src/shared/gatt-db.h"
> +#include "src/shared/gatt-client.h"
> #include "src/log.h"
>
> #include "attrib/att.h"
> @@ -79,6 +82,7 @@
>
> struct bt_hog {
> int ref_count;
> + uint16_t service_handle;

Call it just handle.

> char *name;
> uint16_t vendor;
> uint16_t product;
> @@ -103,6 +107,7 @@ struct bt_hog {
> struct queue *bas;
> GSList *instances;
> struct queue *gatt_op;
> + struct bt_gatt_client *client;
> };
>
> struct report {
> @@ -1173,14 +1178,15 @@ static void hog_free(void *data)
>
> struct bt_hog *bt_hog_new_default(const char *name, uint16_t vendor,
> uint16_t product, uint16_t version,
> - void *primary)
> + void *primary, uint16_t service_handle)
> {
> - return bt_hog_new(-1, name, vendor, product, version, primary);
> + return bt_hog_new(-1, name, vendor, product, version, primary,
> + service_handle);
> }
>
> struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
> uint16_t product, uint16_t version,
> - void *primary)
> + void *primary, uint16_t service_handle)
> {
> struct bt_hog *hog;
>
> @@ -1211,6 +1217,9 @@ struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
> if (primary)
> hog->primary = g_memdup(primary, sizeof(*hog->primary));
>
> + if (service_handle)
> + hog->service_handle = service_handle;
> +
> return bt_hog_ref(hog);
> }
>
> @@ -1321,14 +1330,14 @@ static void hog_attach_hog(struct bt_hog *hog, struct gatt_primary *primary)
> }
>
> instance = bt_hog_new(hog->uhid_fd, hog->name, hog->vendor,
> - hog->product, hog->version, primary);
> + hog->product, hog->version, primary, 0);
> if (!instance)
> return;
>
> find_included(instance, hog->attrib, primary->range.start,
> primary->range.end, find_included_cb, instance);
>
> - bt_hog_attach(instance, hog->attrib);
> + bt_hog_attach(instance, hog->attrib, hog->client);
> hog->instances = g_slist_append(hog->instances, instance);
> }
>
> @@ -1377,15 +1386,16 @@ static void primary_cb(uint8_t status, GSList *services, void *user_data)
> }
> }
>
> -bool bt_hog_attach(struct bt_hog *hog, void *gatt)
> +bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)
> {
> struct gatt_primary *primary = hog->primary;
> GSList *l;
>
> - if (hog->attrib)
> + if (hog->attrib || hog->client)
> return false;
>
> hog->attrib = g_attrib_ref(gatt);
> + hog->client = bt_gatt_client_ref(client);
>
> if (!primary) {
> discover_primary(hog, hog->attrib, NULL, primary_cb, hog);
> @@ -1403,7 +1413,7 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt)
> for (l = hog->instances; l; l = l->next) {
> struct bt_hog *instance = l->data;
>
> - bt_hog_attach(instance, gatt);
> + bt_hog_attach(instance, gatt, client);
> }
>
> if (hog->reports == NULL) {
> @@ -1429,7 +1439,7 @@ void bt_hog_detach(struct bt_hog *hog)
> {
> GSList *l;
>
> - if (!hog->attrib)
> + if (!hog->attrib || !hog->client)
> return;
>
> queue_foreach(hog->bas, (void *) bt_bas_detach, NULL);
> @@ -1456,6 +1466,8 @@ void bt_hog_detach(struct bt_hog *hog)
> bt_dis_detach(hog->dis);
>
> queue_foreach(hog->gatt_op, (void *) cancel_gatt_req, NULL);
> + bt_gatt_client_unref(hog->client);
> + hog->client = NULL;
> g_attrib_unref(hog->attrib);
> hog->attrib = NULL;
> }
> diff --git a/android/hog.h b/android/hog.h
> index 2a9b899..61d756c 100644
> --- a/android/hog.h
> +++ b/android/hog.h
> @@ -25,16 +25,16 @@ struct bt_hog;
>
> struct bt_hog *bt_hog_new_default(const char *name, uint16_t vendor,
> uint16_t product, uint16_t version,
> - void *primary);
> + void *primary, uint16_t service_handle);
>
> struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
> uint16_t product, uint16_t version,
> - void *primary);
> + void *primary, uint16_t service_handle);
>
> struct bt_hog *bt_hog_ref(struct bt_hog *hog);
> void bt_hog_unref(struct bt_hog *hog);
>
> -bool bt_hog_attach(struct bt_hog *hog, void *gatt);
> +bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client);
> void bt_hog_detach(struct bt_hog *hog);
>
> int bt_hog_set_control_point(struct bt_hog *hog, bool suspend);
> diff --git a/unit/test-hog.c b/unit/test-hog.c
> index 2a25d09..c7c64e4 100644
> --- a/unit/test-hog.c
> +++ b/unit/test-hog.c
> @@ -196,7 +196,7 @@ static struct context *create_context(gconstpointer data)
> fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
> g_assert(fd > 0);
>
> - context->hog = bt_hog_new(fd, name, vendor, product, version, NULL);
> + context->hog = bt_hog_new(fd, name, vendor, product, version, NULL, 0);
> g_assert(context->hog);
>
> channel = g_io_channel_unix_new(sv[1]);
> @@ -222,7 +222,7 @@ static void test_hog(gconstpointer data)
> {
> struct context *context = create_context(data);
>
> - g_assert(bt_hog_attach(context->hog, context->attrib));
> + g_assert(bt_hog_attach(context->hog, context->attrib, NULL));
> }
>
> int main(int argc, char *argv[])
> --
> 1.9.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html



--
Luiz Augusto von Dentz

2015-04-03 16:33:45

by Michael Janssen

[permalink] [raw]
Subject: Re: [PATCHv2 01/27] android/hidhost: Create bt_gatt_client

Hi Mariusz,

Just a minor thing.

On Fri, Apr 3, 2015 at 6:43 AM, Mariusz Skamra <[email protected]> wrote:
> From: Mariusz Skamra <[email protected]>
>
> This patch introduces bt_gatt_client to be used by HoG profile.
> As long as the android/gatt doesn't use bt_gatt_client, initialization
> can be performed here.
> ---
> android/Android.mk | 2 ++
> android/hidhost.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++--------
> 2 files changed, 66 insertions(+), 11 deletions(-)
>
> diff --git a/android/Android.mk b/android/Android.mk
> index f218805..b9dd1c8 100644
> --- a/android/Android.mk
> +++ b/android/Android.mk
> @@ -72,6 +72,8 @@ LOCAL_SRC_FILES := \
> bluez/src/shared/crypto.c \
> bluez/src/shared/uhid.c \
> bluez/src/shared/att.c \
> + bluez/src/shared/gatt-helpers.c \
> + bluez/src/shared/gatt-client.c \
> bluez/src/sdpd-database.c \
> bluez/src/sdpd-service.c \
> bluez/src/sdpd-request.c \
> diff --git a/android/hidhost.c b/android/hidhost.c
> index 729b884..26a8013 100644
> --- a/android/hidhost.c
> +++ b/android/hidhost.c
> @@ -36,15 +36,22 @@
>
> #include "btio/btio.h"
> #include "lib/bluetooth.h"
> +#include "lib/uuid.h"
> #include "lib/sdp.h"
> #include "lib/sdp_lib.h"
> #include "src/shared/mgmt.h"
> +#include "src/shared/queue.h"
> #include "src/shared/util.h"
> #include "src/shared/uhid.h"
> +#include "src/shared/att.h"
> +#include "src/shared/gatt-db.h"
> +#include "src/shared/gatt-client.h"
> #include "src/sdp-client.h"
> #include "src/uuid-helper.h"
> #include "src/log.h"
>
> +#include "attrib/gattrib.h"
> +
> #include "hal-msg.h"
> #include "ipc-common.h"
> #include "ipc.h"
> @@ -113,6 +120,9 @@ struct hid_device {
> uint8_t last_hid_msg;
> struct bt_hog *hog;
> int sec_level;
> + GAttrib *attrib;
> + struct gatt_db *db;
> + struct bt_gatt_client *client;
> };
>
> static int device_cmp(gconstpointer s, gconstpointer user_data)
> @@ -145,6 +155,9 @@ static void hid_device_free(void *data)
> if (dev->hog)
> bt_hog_unref(dev->hog);
>
> + if (dev->db)
> + gatt_db_unref(dev->db);
> +

gatt_db_unref already checks for null, so you don't need a check here.
bt_hog_unref does too although it's unrelated.

> g_free(dev->rd_data);
> g_free(dev);
> }
> @@ -792,10 +805,37 @@ fail:
> hid_device_remove(dev);
> }
>
> +static void client_ready_cb(bool success, uint8_t att_ecode, void *user_data)
> +{
> + struct hid_device *dev = user_data;
> +
> + if (!success) {
> + error("HoG: client not ready");
> + goto fail;
> + }
> +
> + if (!bt_hog_attach(dev->hog, dev->attrib)) {
> + error("HoG: unable to attach");
> + goto fail;
> + }
> +
> + bt_hid_notify_state(dev, HAL_HIDHOST_STATE_CONNECTED);
> +
> + if (!bt_gatt_add_autoconnect(hog_app, &dev->dst))
> + error("HoG: Could not add to autoconnect list");
> +
> + return;
> +fail:
> + bt_hid_notify_state(dev, HAL_HIDHOST_STATE_DISCONNECTED);
> + hid_device_remove(dev);
> +}
> +
> static void hog_conn_cb(const bdaddr_t *addr, int err, void *attrib)
> {
> GSList *l;
> struct hid_device *dev;
> + struct bt_att *att;
> + uint16_t mtu;
>
> l = g_slist_find_custom(devices, addr, device_cmp);
> dev = l ? l->data : NULL;
> @@ -807,6 +847,10 @@ static void hog_conn_cb(const bdaddr_t *addr, int err, void *attrib)
> bt_hid_notify_state(dev,
> HAL_HIDHOST_STATE_DISCONNECTED);
> bt_hog_detach(dev->hog);
> + bt_gatt_client_unref(dev->client);
> + g_attrib_unref(dev->attrib);
> + dev->attrib = NULL;
> + dev->client = NULL;
> return;
> }
> goto fail;
> @@ -816,34 +860,43 @@ static void hog_conn_cb(const bdaddr_t *addr, int err, void *attrib)
> dev = hid_device_new(addr);
>
> if (!dev->hog) {
> - /* TODO: Get device details and primary */
> + /* TODO: Get device details */
> dev->hog = bt_hog_new_default("bluez-input-device", dev->vendor,
> dev->product, dev->version, NULL);
> if (!dev->hog) {
> error("HoG: unable to create session");
> goto fail;
> }
> - }
>
> - if (!bt_hog_attach(dev->hog, attrib)) {
> - error("HoG: unable to attach");
> - goto fail;
> + dev->db = gatt_db_new();
> + if (!dev->db) {
> + error("HoG: unable to create gatt_db");
> + goto fail;
> + }
> }
>
> - if (!bt_gatt_set_security(addr, BT_IO_SEC_MEDIUM)) {
> + att = g_attrib_get_att(attrib);
> + dev->attrib = g_attrib_ref(attrib);
> + mtu = bt_att_get_mtu(att);
> +
> + /* Enable encryption before gatt_client starts discovering services */
> + if (!bt_att_set_sec_level(att, BT_SECURITY_MEDIUM)) {
> error("Failed to set security level");
> goto fail;
> }
>
> DBG("");
>
> - bt_hid_notify_state(dev, HAL_HIDHOST_STATE_CONNECTED);
> -
> - if (!bt_gatt_add_autoconnect(hog_app, &dev->dst))
> - error("hidhost: Could not add to autoconnect list");
> + dev->client = bt_gatt_client_new(dev->db, att, mtu);
> + if (!dev->client) {
> + error("Failed to create gatt_client");
> + goto fail;
> + }
>
> + /* Wait until client is initialized */
> + bt_gatt_client_set_ready_handler(dev->client, client_ready_cb,
> + dev, NULL);
> return;
> -
> fail:
> bt_hid_notify_state(dev, HAL_HIDHOST_STATE_DISCONNECTED);
> hid_device_remove(dev);
> --
> 1.9.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html



--
Michael Janssen

2015-04-03 13:43:36

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 07/27] android/hog: Use bt_gatt_client to write without response

This patch replaces gatt_write_cmd with
bt_gatt_client_write_without_response.
---
android/hog.c | 23 +++++++++++++----------
1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/android/hog.c b/android/hog.c
index 58c9d48..88f3ca1 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -449,8 +449,9 @@ static void forward_report(struct uhid_event *ev, void *user_data)
gatt_write_char(hog->attrib, report->decl->value_handle,
data, size, output_written_cb, hog);
else if (report->decl->properties & GATT_CHR_PROP_WRITE_WITHOUT_RESP)
- gatt_write_cmd(hog->attrib, report->decl->value_handle,
- data, size, NULL, NULL);
+ bt_gatt_client_write_without_response(hog->client,
+ report->decl->value_handle,
+ false, data, size);
}

static void get_feature(struct uhid_event *ev, void *user_data)
@@ -816,8 +817,9 @@ static void proto_mode_read_cb(bool success, uint8_t att_ecode,

DBG("HoG is operating in Boot Procotol Mode");

- gatt_write_cmd(hog->attrib, hog->proto_mode_handle, &nval,
- sizeof(nval), NULL, NULL);
+ bt_gatt_client_write_without_response(hog->client,
+ hog->proto_mode_handle, false,
+ &nval, sizeof(nval));
} else if (value[0] == HOG_PROTO_MODE_REPORT)
DBG("HoG is operating in Report Protocol Mode");
}
@@ -1207,14 +1209,14 @@ int bt_hog_set_control_point(struct bt_hog *hog, bool suspend)
{
uint8_t value = suspend ? 0x00 : 0x01;

- if (hog->attrib == NULL)
+ if (hog->client == NULL)
return -ENOTCONN;

if (hog->ctrlpt_handle == 0)
return -ENOTSUP;

- gatt_write_cmd(hog->attrib, hog->ctrlpt_handle, &value,
- sizeof(value), NULL, NULL);
+ bt_gatt_client_write_without_response(hog->client, hog->ctrlpt_handle,
+ false, &value, sizeof(value));

return 0;
}
@@ -1227,7 +1229,7 @@ int bt_hog_send_report(struct bt_hog *hog, void *data, size_t size, int type)
if (!hog)
return -EINVAL;

- if (!hog->attrib)
+ if (!hog->client)
return -ENOTCONN;

report = find_report(hog, type, 0);
@@ -1241,8 +1243,9 @@ int bt_hog_send_report(struct bt_hog *hog, void *data, size_t size, int type)
data, size, output_written_cb, hog);

if (report->decl->properties & GATT_CHR_PROP_WRITE_WITHOUT_RESP)
- gatt_write_cmd(hog->attrib, report->decl->value_handle,
- data, size, NULL, NULL);
+ bt_gatt_client_write_without_response(hog->client,
+ report->decl->value_handle,
+ false, data, size);

for (l = hog->instances; l; l = l->next) {
struct bt_hog *instance = l->data;
--
1.9.1


2015-04-03 13:43:43

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 14/27] android/dis: Remove tracking pending gatt operations

Since the use of bt_gatt_client there is no need to queue pending gatt
operations. bt_gatt_client already keeps track on that, so that
on bt_gatt_client_unref the queue of pending requests is destroyed.
---
android/dis.c | 107 +++-------------------------------------------------------
1 file changed, 4 insertions(+), 103 deletions(-)

diff --git a/android/dis.c b/android/dis.c
index 75dbe3d..f699046 100644
--- a/android/dis.c
+++ b/android/dis.c
@@ -57,7 +57,6 @@ struct bt_dis {
struct gatt_primary *primary; /* Primary details */
bt_dis_notify notify;
void *notify_data;
- struct queue *gatt_op;
};

struct characteristic {
@@ -65,25 +64,11 @@ struct characteristic {
struct bt_dis *d; /* deviceinfo where the char belongs */
};

-struct gatt_request {
- unsigned int id;
- struct bt_dis *dis;
- void *user_data;
-};
-
-static void destroy_gatt_req(struct gatt_request *req)
-{
- queue_remove(req->dis->gatt_op, req);
- bt_dis_unref(req->dis);
- free(req);
-}
-
static void dis_free(struct bt_dis *dis)
{
bt_dis_detach(dis);

g_free(dis->primary);
- queue_destroy(dis->gatt_op, (void *) destroy_gatt_req);
g_free(dis);
}

@@ -95,12 +80,6 @@ struct bt_dis *bt_dis_new(void *primary)
if (!dis)
return NULL;

- dis->gatt_op = queue_new();
- if (!dis->gatt_op) {
- dis_free(dis);
- return NULL;
- }
-
if (primary)
dis->primary = g_memdup(primary, sizeof(*dis->primary));

@@ -128,39 +107,13 @@ void bt_dis_unref(struct bt_dis *dis)
dis_free(dis);
}

-static struct gatt_request *create_request(struct bt_dis *dis,
- void *user_data)
-{
- struct gatt_request *req;
-
- req = new0(struct gatt_request, 1);
- if (!req)
- return NULL;
-
- req->user_data = user_data;
- req->dis = bt_dis_ref(dis);
-
- return req;
-}
-
-static bool set_and_store_gatt_req(struct bt_dis *dis,
- struct gatt_request *req,
- unsigned int id)
-{
- req->id = id;
- return queue_push_head(dis->gatt_op, req);
-}
-
static void read_pnpid_cb(guint8 status, const guint8 *pdu, guint16 len,
gpointer user_data)
{
- struct gatt_request *req = user_data;
- struct bt_dis *dis = req->user_data;
+ struct bt_dis *dis = user_data;
uint8_t value[PNP_ID_SIZE];
ssize_t vlen;

- destroy_gatt_req(req);
-
if (status != 0) {
error("Error reading PNP_ID value: %s", att_ecode2str(status));
return;
@@ -190,57 +143,12 @@ static void read_pnpid_cb(guint8 status, const guint8 *pdu, guint16 len,
dis->version, dis->notify_data);
}

-static void read_char(struct bt_dis *dis, GAttrib *attrib, uint16_t handle,
- GAttribResultFunc func, gpointer user_data)
-{
- struct gatt_request *req;
- unsigned int id;
-
- req = create_request(dis, user_data);
- if (!req)
- return;
-
- id = gatt_read_char(attrib, handle, func, req);
-
- if (set_and_store_gatt_req(dis, req, id))
- return;
-
- error("dis: Could not read characteristic");
- g_attrib_cancel(attrib, id);
- free(req);
-}
-
-static void discover_char(struct bt_dis *dis, GAttrib *attrib,
- uint16_t start, uint16_t end,
- bt_uuid_t *uuid, gatt_cb_t func,
- gpointer user_data)
-{
- struct gatt_request *req;
- unsigned int id;
-
- req = create_request(dis, user_data);
- if (!req)
- return;
-
- id = gatt_discover_char(attrib, start, end, uuid, func, req);
-
- if (set_and_store_gatt_req(dis, req, id))
- return;
-
- error("dis: Could not send discover characteristic");
- g_attrib_cancel(attrib, id);
- free(req);
-}
-
static void configure_deviceinfo_cb(uint8_t status, GSList *characteristics,
void *user_data)
{
- struct gatt_request *req = user_data;
- struct bt_dis *d = req->user_data;
+ struct bt_dis *d = user_data;
GSList *l;

- destroy_gatt_req(req);
-
if (status != 0) {
error("Discover deviceinfo characteristics: %s",
att_ecode2str(status));
@@ -252,7 +160,7 @@ static void configure_deviceinfo_cb(uint8_t status, GSList *characteristics,

if (strcmp(c->uuid, PNPID_UUID) == 0) {
d->handle = c->value_handle;
- read_char(d, d->attrib, d->handle, read_pnpid_cb, d);
+ gatt_read_char(d->attrib, d->handle, read_pnpid_cb, d);
break;
}
}
@@ -268,25 +176,18 @@ bool bt_dis_attach(struct bt_dis *dis, void *attrib)
dis->attrib = g_attrib_ref(attrib);

if (!dis->handle)
- discover_char(dis, dis->attrib, primary->range.start,
+ gatt_discover_char(dis->attrib, primary->range.start,
primary->range.end, NULL,
configure_deviceinfo_cb, dis);

return true;
}

-static void cancel_gatt_req(struct gatt_request *req)
-{
- if (g_attrib_cancel(req->dis->attrib, req->id))
- destroy_gatt_req(req);
-}
-
void bt_dis_detach(struct bt_dis *dis)
{
if (!dis->attrib)
return;

- queue_foreach(dis->gatt_op, (void *) cancel_gatt_req, NULL);
g_attrib_unref(dis->attrib);
dis->attrib = NULL;
}
--
1.9.1


2015-04-03 13:43:53

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 24/27] android/hog: Clean the code from attrib dependencies

All the attrib include files can be now removed since all the dependencies
have been removed.
---
android/hidhost.c | 2 +-
android/hog.c | 74 +++++++++++++++++++++++++------------------------------
android/hog.h | 2 +-
unit/test-hog.c | 2 +-
4 files changed, 37 insertions(+), 43 deletions(-)

diff --git a/android/hidhost.c b/android/hidhost.c
index f9b7c24..32789fb 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -812,7 +812,7 @@ static void client_ready_cb(bool success, uint8_t att_ecode, void *user_data)
goto fail;
}

- if (!bt_hog_attach(dev->hog, dev->attrib, dev->client)) {
+ if (!bt_hog_attach(dev->hog, dev->client)) {
error("HoG: unable to attach");
goto fail;
}
diff --git a/android/hog.c b/android/hog.c
index 790f362..fdcd95a 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -50,15 +50,15 @@
#include "src/shared/gatt-client.h"
#include "src/log.h"

-#include "attrib/att.h"
-#include "attrib/gattrib.h"
-#include "attrib/gatt.h"
-
#include "android/scpp.h"
#include "android/dis.h"
#include "android/bas.h"
#include "android/hog.h"

+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
#define HOG_INFO_UUID 0x2A4A
#define HOG_REPORT_MAP_UUID 0x2A4B
#define HOG_REPORT_UUID 0x2A4D
@@ -85,7 +85,6 @@ struct bt_hog {
uint16_t vendor;
uint16_t product;
uint16_t version;
- GAttrib *attrib;
struct queue *reports;
struct bt_uhid *uhid;
int uhid_fd;
@@ -107,6 +106,11 @@ struct bt_hog {
struct gatt_db *db;
};

+struct gatt_char {
+ uint8_t properties;
+ uint16_t value_handle;
+};
+
struct report {
struct bt_hog *hog;
uint8_t id;
@@ -153,8 +157,8 @@ static void report_value_cb(uint16_t value_handle, const uint8_t *value,
static void report_ccc_written_cb(uint16_t status, void *user_data)
{
if (status != 0) {
- error("Write report characteristic descriptor failed: %s",
- att_ecode2str(status));
+ error("Write report characteristic descriptor failed: %d",
+ status);
return;
}

@@ -192,8 +196,8 @@ static void report_reference_cb(bool success, uint8_t status,
struct report *report = user_data;

if (!success) {
- error("Read Report Reference descriptor failed: %s",
- att_ecode2str(status));
+ error("Read Report Reference descriptor failed: att_ecode %d",
+ status);
return;
}

@@ -249,8 +253,7 @@ static void report_read_cb(bool success, uint8_t att_ecode,
struct report *report = user_data;

if (!success) {
- error("Error reading Report value: %s",
- att_ecode2str(att_ecode));
+ error("Error reading Report value: att_ecode %d", att_ecode);
return;
}

@@ -304,8 +307,8 @@ static void external_report_reference_cb(bool success, uint8_t status,
struct queue *chrs;

if (!success) {
- error("Read External Report Reference descriptor failed: %s",
- att_ecode2str(status));
+ error("Read External Report Reference descriptor failed: %d",
+ status);
return;
}

@@ -397,7 +400,7 @@ static struct report *find_report_by_rtype(struct bt_hog *hog, uint8_t rtype,
static void output_written_cb(bool success, uint8_t status, void *user_data)
{
if (!success) {
- error("Write output report failed: %s", att_ecode2str(status));
+ error("Write output report failed: att_ecode %d", status);
return;
}
}
@@ -408,6 +411,7 @@ static void forward_report(struct uhid_event *ev, void *user_data)
struct report *report;
void *data;
int size;
+ uint8_t properties;

report = find_report_by_rtype(hog, ev->u.output.rtype,
ev->u.output.data[0]);
@@ -427,12 +431,13 @@ static void forward_report(struct uhid_event *ev, void *user_data)
if (hog->client == NULL)
return;

- if (report->decl->properties & GATT_CHR_PROP_WRITE)
+ properties = report->decl->properties;
+ if (properties & BT_GATT_CHRC_PROP_WRITE)
bt_gatt_client_write_value(hog->client,
report->decl->value_handle,
data, size, output_written_cb,
hog, NULL);
- else if (report->decl->properties & GATT_CHR_PROP_WRITE_WITHOUT_RESP)
+ else if (properties & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP)
bt_gatt_client_write_without_response(hog->client,
report->decl->value_handle,
false, data, size);
@@ -484,7 +489,7 @@ static void set_report_cb(bool success, uint8_t status, void *user_data)
rsp.u.set_report_reply.err = status;

if (!success)
- error("Error setting Report value: %s", att_ecode2str(status));
+ error("Error setting Report value: att_ecode %d", status);

err = bt_uhid_send(hog->uhid, &rsp);
if (err < 0)
@@ -556,7 +561,7 @@ static void get_report_cb(bool success, uint8_t status, const uint8_t *value,
rsp.u.get_report_reply.id = hog->getrep_id;

if (!success) {
- error("Error reading Report value: %s", att_ecode2str(status));
+ error("Error reading Report value: att_ecode %d", status);
goto exit;
}

@@ -732,7 +737,7 @@ static void report_map_read_cb(bool success, uint8_t att_ecode,
int i;

if (!success) {
- error("Report Map read failed: %s", att_ecode2str(att_ecode));
+ error("Report Map read failed: att_ecode %d", att_ecode);
return;
}

@@ -770,7 +775,7 @@ static void info_read_cb(bool success, uint8_t status, const uint8_t *value,
struct bt_hog *hog = user_data;

if (!success) {
- error("HID Information read failed: %s", att_ecode2str(status));
+ error("HID Information read failed: att_ecode %d", status);
return;
}

@@ -794,8 +799,8 @@ static void proto_mode_read_cb(bool success, uint8_t att_ecode,
struct bt_hog *hog = user_data;

if (!success) {
- error("Protocol Mode characteristic read failed: %s",
- att_ecode2str(att_ecode));
+ error("Protocol Mode characteristic read failed: att_ecode %d",
+ att_ecode);
return;
}

@@ -1023,7 +1028,7 @@ static void hog_attach_hog(struct bt_hog *hog, uint16_t service_handle)
if (!instance)
return;

- bt_hog_attach(instance, hog->attrib, hog->client);
+ bt_hog_attach(instance, hog->client);
queue_push_tail(hog->instances, instance);
}

@@ -1050,14 +1055,11 @@ static void service_cb(struct gatt_db_attribute *attrib, void *user_data)
hog_attach_bas(hog, service_handle);
}

-bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)
+bool bt_hog_attach(struct bt_hog *hog, void *client)
{
- const struct queue_entry *hog_entry;
-
- if (hog->attrib || hog->client)
+ if (hog->client)
return false;

- hog->attrib = g_attrib_ref(gatt);
hog->client = bt_gatt_client_ref(client);
hog->db = gatt_db_ref(bt_gatt_client_get_db(hog->client));

@@ -1073,13 +1075,7 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)
bt_dis_attach(hog->dis, hog->client);

queue_foreach(hog->bas, (void *) bt_bas_attach, hog->client);
-
- hog_entry = queue_get_entries(hog->instances);
- while (hog_entry) {
- struct bt_hog *instance = hog_entry->data;
-
- bt_hog_attach(instance, gatt, client);
- }
+ queue_foreach(hog->instances, (void *) bt_hog_attach, hog->client);

if (queue_isempty(hog->reports)) {
struct gatt_db_attribute *service;
@@ -1097,7 +1093,7 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)

void bt_hog_detach(struct bt_hog *hog)
{
- if (!hog->attrib || !hog->client)
+ if (!hog->client)
return;

queue_foreach(hog->bas, (void *) bt_bas_detach, NULL);
@@ -1113,8 +1109,6 @@ void bt_hog_detach(struct bt_hog *hog)
gatt_db_unref(hog->db);
bt_gatt_client_unref(hog->client);
hog->client = NULL;
- g_attrib_unref(hog->attrib);
- hog->attrib = NULL;
}

int bt_hog_set_control_point(struct bt_hog *hog, bool suspend)
@@ -1150,13 +1144,13 @@ int bt_hog_send_report(struct bt_hog *hog, void *data, size_t size, int type)

DBG("hog: Write report, handle 0x%X", report->decl->value_handle);

- if (report->decl->properties & GATT_CHR_PROP_WRITE)
+ if (report->decl->properties & BT_GATT_CHRC_PROP_WRITE)
bt_gatt_client_write_value(hog->client,
report->decl->value_handle,
data, size, output_written_cb,
hog, NULL);

- if (report->decl->properties & GATT_CHR_PROP_WRITE_WITHOUT_RESP)
+ if (report->decl->properties & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP)
bt_gatt_client_write_without_response(hog->client,
report->decl->value_handle,
false, data, size);
diff --git a/android/hog.h b/android/hog.h
index 8fe8422..fa3d114 100644
--- a/android/hog.h
+++ b/android/hog.h
@@ -36,7 +36,7 @@ struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
struct bt_hog *bt_hog_ref(struct bt_hog *hog);
void bt_hog_unref(struct bt_hog *hog);

-bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client);
+bool bt_hog_attach(struct bt_hog *hog, void *client);
void bt_hog_detach(struct bt_hog *hog);

int bt_hog_set_control_point(struct bt_hog *hog, bool suspend);
diff --git a/unit/test-hog.c b/unit/test-hog.c
index 16805e7..81aada2 100644
--- a/unit/test-hog.c
+++ b/unit/test-hog.c
@@ -227,7 +227,7 @@ static void test_hog(gconstpointer data)
{
struct context *context = create_context(data);

- g_assert(bt_hog_attach(context->hog, context->attrib, NULL));
+ g_assert(bt_hog_attach(context->hog, NULL));
}

int main(int argc, char *argv[])
--
1.9.1


2015-04-03 13:43:56

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 27/27] android/hog: Replace definitions of characteristic uuids with bt_uuids

Instead of using simply define and then convert the uuid values to
bt_uuid everytime the char_discovered_cb is called, it's better to
define these bt_uuids directly.
---
android/hog.c | 40 ++++++++++++++++++----------------------
1 file changed, 18 insertions(+), 22 deletions(-)

diff --git a/android/hog.c b/android/hog.c
index ad047f0..a456b0c 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -52,12 +52,6 @@
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif

-#define HOG_INFO_UUID 0x2A4A
-#define HOG_REPORT_MAP_UUID 0x2A4B
-#define HOG_REPORT_UUID 0x2A4D
-#define HOG_PROTO_MODE_UUID 0x2A4E
-#define HOG_CONTROL_POINT_UUID 0x2A4C
-
#define HOG_REPORT_TYPE_INPUT 1
#define HOG_REPORT_TYPE_OUTPUT 2
#define HOG_REPORT_TYPE_FEATURE 3
@@ -67,6 +61,17 @@

static bdaddr_t adapter_addr;

+static const bt_uuid_t info_uuid = { .type = BT_UUID16,
+ .value.u16 = 0x2A4A };
+static const bt_uuid_t report_map_uuid = { .type = BT_UUID16,
+ .value.u16 = 0x2A4B };
+static const bt_uuid_t control_point_uuid = { .type = BT_UUID16,
+ .value.u16 = 0x2A4C };
+static const bt_uuid_t report_uuid = { .type = BT_UUID16,
+ .value.u16 = 0x2A4D };
+static const bt_uuid_t protocol_mode_uuid = { .type = BT_UUID16,
+ .value.u16 = 0x2A4E };
+
struct bt_hog {
int ref_count;
uint16_t service_handle;
@@ -318,7 +323,6 @@ static void external_report_reference_cb(bool success, uint8_t status,
void *user_data)
{
struct bt_hog *hog = user_data;
- uint16_t uuid16;
bt_uuid_t uuid;
struct queue *chrs;

@@ -333,12 +337,12 @@ static void external_report_reference_cb(bool success, uint8_t status,
return;
}

- uuid16 = get_le16(value);
- DBG("External report reference read, external report characteristic "
- "UUID: 0x%04x", uuid16);
+ DBG("External report characteristic UUID: 0x%04x", get_le16(value));
+
+ bt_uuid16_create(&uuid, get_le16(value));

/* Do not discover if is not a Report */
- if (uuid16 != HOG_REPORT_UUID)
+ if (bt_uuid_cmp(&uuid, &report_uuid))
return;

chrs = queue_new();
@@ -347,7 +351,6 @@ static void external_report_reference_cb(bool success, uint8_t status,
return;
}

- bt_uuid16_create(&uuid, uuid16);
gatt_db_read_by_type(hog->db, 0x0001, 0xffff, uuid, chrs);

if (queue_isempty(chrs))
@@ -836,18 +839,11 @@ static void char_discovered_cb(struct gatt_db_attribute *attrib,
void *user_data)
{
struct bt_hog *hog = user_data;
- bt_uuid_t report_uuid, report_map_uuid, proto_mode_uuid, ctrlpt_uuid;
- bt_uuid_t info_uuid, uuid;
+ bt_uuid_t uuid;
struct report *report;
uint16_t value_handle;
uint8_t properties;

- bt_uuid16_create(&report_uuid, HOG_REPORT_UUID);
- bt_uuid16_create(&report_map_uuid, HOG_REPORT_MAP_UUID);
- bt_uuid16_create(&info_uuid, HOG_INFO_UUID);
- bt_uuid16_create(&proto_mode_uuid, HOG_PROTO_MODE_UUID);
- bt_uuid16_create(&ctrlpt_uuid, HOG_CONTROL_POINT_UUID);
-
gatt_db_attribute_get_char_data(attrib, NULL, &value_handle,
&properties, &uuid);

@@ -865,11 +861,11 @@ static void char_discovered_cb(struct gatt_db_attribute *attrib,
} else if (!bt_uuid_cmp(&uuid, &info_uuid)) {
bt_gatt_client_read_value(hog->client, value_handle,
info_read_cb, hog, NULL);
- } else if (!bt_uuid_cmp(&uuid, &proto_mode_uuid)) {
+ } else if (!bt_uuid_cmp(&uuid, &protocol_mode_uuid)) {
hog->proto_mode_handle = value_handle;
bt_gatt_client_read_value(hog->client, value_handle,
proto_mode_read_cb, hog, NULL);
- } else if (!bt_uuid_cmp(&uuid, &ctrlpt_uuid)) {
+ } else if (!bt_uuid_cmp(&uuid, &control_point_uuid)) {
hog->ctrlpt_handle = value_handle;
}
}
--
1.9.1


2015-04-03 13:43:50

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 21/27] android/hog: Strip btio dependencies

bt_io_get from btio library is used only to get address of adapter
and connected hid device. We can just simply pass this addresses
using bt_hog_new argument list. It's temporary solution, just to
be able to move the code to profiles/input.
---
android/hidhost.c | 3 ++-
android/hog.c | 36 +++++++++++++++++-------------------
android/hog.h | 10 ++++++----
unit/test-hog.c | 7 ++++++-
4 files changed, 31 insertions(+), 25 deletions(-)

diff --git a/android/hidhost.c b/android/hidhost.c
index e1392f6..f9b7c24 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -860,7 +860,8 @@ static void hog_conn_cb(const bdaddr_t *addr, int err, void *attrib)
if (!dev->hog) {
/* TODO: Get device details */
dev->hog = bt_hog_new_default("bluez-input-device", dev->vendor,
- dev->product, dev->version, 0);
+ dev->product, dev->version, addr,
+ &adapter_addr, 0);
if (!dev->hog) {
error("HoG: unable to create session");
goto fail;
diff --git a/android/hog.c b/android/hog.c
index eaac097..d7a00ba 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -54,8 +54,6 @@
#include "attrib/gattrib.h"
#include "attrib/gatt.h"

-#include "btio/btio.h"
-
#include "android/scpp.h"
#include "android/dis.h"
#include "android/bas.h"
@@ -77,9 +75,12 @@
#define HOG_REPORT_MAP_MAX_SIZE 512
#define HID_INFO_SIZE 4

+static bdaddr_t adapter_addr;
+
struct bt_hog {
int ref_count;
uint16_t service_handle;
+ bdaddr_t device_addr;
char *name;
uint16_t vendor;
uint16_t product;
@@ -692,22 +693,13 @@ static bool uhid_create(struct bt_hog *hog, const uint8_t *value, uint16_t vlen)
{
struct uhid_event ev;
int err;
- GError *gerr = NULL;

/* create uHID device */
memset(&ev, 0, sizeof(ev));
ev.type = UHID_CREATE;

- bt_io_get(g_attrib_get_channel(hog->attrib), &gerr,
- BT_IO_OPT_SOURCE, ev.u.create.phys,
- BT_IO_OPT_DEST, ev.u.create.uniq,
- BT_IO_OPT_INVALID);
- if (gerr) {
- error("Failed to connection details: %s", gerr->message);
- g_error_free(gerr);
- return false;
- }
-
+ ba2str(&adapter_addr, (char *) ev.u.create.phys);
+ ba2str(&hog->device_addr, (char *) ev.u.create.uniq);
strcpy((char *) ev.u.create.name, hog->name);
ev.u.create.vendor = hog->vendor;
ev.u.create.product = hog->product;
@@ -886,15 +878,18 @@ static void hog_free(void *data)
}

struct bt_hog *bt_hog_new_default(const char *name, uint16_t vendor,
- uint16_t product, uint16_t version,
- uint16_t service_handle)
+ uint16_t product, uint16_t version,
+ const bdaddr_t *addr, const bdaddr_t *adapter,
+ uint16_t service_handle)
{
- return bt_hog_new(-1, name, vendor, product, version, service_handle);
+ return bt_hog_new(-1, name, vendor, product, version, addr, adapter,
+ service_handle);
}

struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
- uint16_t product, uint16_t version,
- uint16_t service_handle)
+ uint16_t product, uint16_t version,
+ const bdaddr_t *addr, const bdaddr_t *adapter,
+ uint16_t service_handle)
{
struct bt_hog *hog;

@@ -922,6 +917,8 @@ struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
hog->vendor = vendor;
hog->product = product;
hog->version = version;
+ bacpy(&hog->device_addr, addr);
+ bacpy(&adapter_addr, adapter);

if (service_handle)
hog->service_handle = service_handle;
@@ -1022,7 +1019,8 @@ static void hog_attach_hog(struct bt_hog *hog, uint16_t service_handle)
}

instance = bt_hog_new(hog->uhid_fd, hog->name, hog->vendor,
- hog->product, hog->version, service_handle);
+ hog->product, hog->version, &hog->device_addr,
+ &adapter_addr, service_handle);
if (!instance)
return;

diff --git a/android/hog.h b/android/hog.h
index cfe6873..8fe8422 100644
--- a/android/hog.h
+++ b/android/hog.h
@@ -24,12 +24,14 @@
struct bt_hog;

struct bt_hog *bt_hog_new_default(const char *name, uint16_t vendor,
- uint16_t product, uint16_t version,
- uint16_t service_handle);
+ uint16_t product, uint16_t version,
+ const bdaddr_t *addr, const bdaddr_t *adapter,
+ uint16_t service_handle);

struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
- uint16_t product, uint16_t version,
- uint16_t service_handle);
+ uint16_t product, uint16_t version,
+ const bdaddr_t *addr, const bdaddr_t *adapter,
+ uint16_t service_handle);

struct bt_hog *bt_hog_ref(struct bt_hog *hog);
void bt_hog_unref(struct bt_hog *hog);
diff --git a/unit/test-hog.c b/unit/test-hog.c
index 5794c5e..16805e7 100644
--- a/unit/test-hog.c
+++ b/unit/test-hog.c
@@ -32,6 +32,8 @@

#include <glib.h>

+#include "lib/bluetooth.h"
+
#include "src/shared/util.h"
#include "src/shared/tester.h"

@@ -179,6 +181,8 @@ static struct context *create_context(gconstpointer data)
uint16_t vendor = 0x0002;
uint16_t product = 0x0001;
uint16_t version = 0x0001;
+ const bdaddr_t *device_addr = NULL;
+ const bdaddr_t *adapter_addr = NULL;

context = g_new0(struct context, 1);
err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
@@ -196,7 +200,8 @@ static struct context *create_context(gconstpointer data)
fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
g_assert(fd > 0);

- context->hog = bt_hog_new(fd, name, vendor, product, version, 0);
+ context->hog = bt_hog_new(fd, name, vendor, product, version,
+ device_addr, adapter_addr, 0);
g_assert(context->hog);

channel = g_io_channel_unix_new(sv[1]);
--
1.9.1


2015-04-03 13:43:55

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 26/27] android/hog: Remove redundant code

---
android/hog.c | 8 --------
1 file changed, 8 deletions(-)

diff --git a/android/hog.c b/android/hog.c
index 22aac76..ad047f0 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -31,13 +31,8 @@
#include <stdlib.h>
#include <stdbool.h>
#include <errno.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>

#include "lib/bluetooth.h"
-#include "lib/sdp.h"
#include "lib/uuid.h"

#include "src/shared/util.h"
@@ -70,9 +65,6 @@
#define HOG_PROTO_MODE_BOOT 0
#define HOG_PROTO_MODE_REPORT 1

-#define HOG_REPORT_MAP_MAX_SIZE 512
-#define HID_INFO_SIZE 4
-
static bdaddr_t adapter_addr;

struct bt_hog {
--
1.9.1


2015-04-03 13:43:54

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 25/27] android/hog: Remove glib dependencies

All the glib functions and types have been replaced so that
glib can be excluded
---
android/hog.c | 62 ++++++++++++++++++++++++++++++++++++++---------------------
1 file changed, 40 insertions(+), 22 deletions(-)

diff --git a/android/hog.c b/android/hog.c
index fdcd95a..22aac76 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -36,8 +36,6 @@
#include <sys/stat.h>
#include <fcntl.h>

-#include <glib.h>
-
#include "lib/bluetooth.h"
#include "lib/sdp.h"
#include "lib/uuid.h"
@@ -88,7 +86,7 @@ struct bt_hog {
struct queue *reports;
struct bt_uhid *uhid;
int uhid_fd;
- gboolean has_report_id;
+ bool has_report_id;
uint16_t bcdhid;
uint8_t bcountrycode;
uint16_t proto_mode_handle;
@@ -246,6 +244,15 @@ static void discover_report_cb(struct gatt_db_attribute *attrib,
report_reference_cb, report, NULL);
}

+static void report_free(void *data)
+{
+ struct report *report = data;
+
+ free(report->value);
+ free(report->decl);
+ free(report);
+}
+
static void report_read_cb(bool success, uint8_t att_ecode,
const uint8_t *value, uint16_t len,
void *user_data)
@@ -258,9 +265,15 @@ static void report_read_cb(bool success, uint8_t att_ecode,
}

if (report->value)
- g_free(report->value);
+ free(report->value);

- report->value = g_memdup(value, len);
+ report->value = new0(uint8_t, len);
+ if (!report->value) {
+ report_free(report);
+ return;
+ }
+
+ memcpy(report->value, value, len);
report->len = len;
}

@@ -269,9 +282,17 @@ static struct report *report_new(struct bt_hog *hog, uint16_t value_handle,
{
struct report *report;

- report = g_new0(struct report, 1);
- report->hog = hog;
+ report = new0(struct report, 1);
+ if (!report)
+ return NULL;
+
report->decl = new0(struct gatt_char, 1);
+ if (!report->decl) {
+ free(report);
+ return NULL;
+ }
+
+ report->hog = hog;
report->decl->value_handle = value_handle;
report->decl->properties = properties;
queue_push_tail(hog->reports, report);
@@ -294,6 +315,9 @@ static void external_service_char_cb(void *data, void *user_data)
&properties, NULL);

report = report_new(hog, value_handle, properties);
+ if (!report)
+ return;
+
gatt_db_service_foreach_desc(attrib, discover_report_cb, report);
}

@@ -598,7 +622,7 @@ static void get_report(struct uhid_event *ev, void *user_data)
{
struct bt_hog *hog = user_data;
struct report *report;
- guint8 err;
+ uint8_t err;

/* uhid never sends reqs in parallel; if there's a req, it timed out */
if (hog->getrep_att) {
@@ -750,7 +774,7 @@ static void report_map_read_cb(bool success, uint8_t att_ecode,
&long_item)) {
/* Report ID is short item with prefix 100001xx */
if (!long_item && (value[i] & 0xfc) == 0x84)
- hog->has_report_id = TRUE;
+ hog->has_report_id = true;

DBG("\t%s", item2string(itemstr, &value[i], ilen));

@@ -837,6 +861,9 @@ static void char_discovered_cb(struct gatt_db_attribute *attrib,

if (!bt_uuid_cmp(&uuid, &report_uuid)) {
report = report_new(hog, value_handle, properties);
+ if (!report)
+ return;
+
gatt_db_service_foreach_desc(attrib, discover_report_cb,
report);
} else if (!bt_uuid_cmp(&uuid, &report_map_uuid)) {
@@ -855,15 +882,6 @@ static void char_discovered_cb(struct gatt_db_attribute *attrib,
}
}

-static void report_free(void *data)
-{
- struct report *report = data;
-
- g_free(report->value);
- free(report->decl);
- g_free(report);
-}
-
static void hog_free(void *data)
{
struct bt_hog *hog = data;
@@ -877,8 +895,8 @@ static void hog_free(void *data)
bt_dis_unref(hog->dis);
bt_uhid_unref(hog->uhid);
queue_destroy(hog->reports, report_free);
- g_free(hog->name);
- g_free(hog);
+ free(hog->name);
+ free(hog);
}

struct bt_hog *bt_hog_new_default(const char *name, uint16_t vendor,
@@ -897,7 +915,7 @@ struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
{
struct bt_hog *hog;

- hog = g_try_new0(struct bt_hog, 1);
+ hog = new0(struct bt_hog, 1);
if (!hog)
return NULL;

@@ -917,7 +935,7 @@ struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
return NULL;
}

- hog->name = g_strdup(name);
+ hog->name = strdup(name);
hog->vendor = vendor;
hog->product = product;
hog->version = version;
--
1.9.1


2015-04-03 13:43:45

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 16/27] android/scpp: Remove tracking pending gatt operations

From: Mariusz Skamra <[email protected]>

Since the use of bt_gatt_client there is no need to queue pending gatt
operations. bt_gatt_client already keeps track on that, so that
on bt_gatt_client_unref the queue of pending requests is destroyed.
---
android/scpp.c | 72 ++++------------------------------------------------------
1 file changed, 4 insertions(+), 68 deletions(-)

diff --git a/android/scpp.c b/android/scpp.c
index f8f81f3..a28fbb6 100644
--- a/android/scpp.c
+++ b/android/scpp.c
@@ -62,62 +62,13 @@ struct bt_scpp {
uint16_t iwhandle;
uint16_t refresh_handle;
guint refresh_cb_id;
- struct queue *gatt_op;
};

-static void discover_char(struct bt_scpp *scpp, GAttrib *attrib,
- uint16_t start, uint16_t end,
- bt_uuid_t *uuid, gatt_cb_t func,
- gpointer user_data)
-{
- unsigned int id;
-
- id = gatt_discover_char(attrib, start, end, uuid, func, user_data);
-
- if (queue_push_head(scpp->gatt_op, UINT_TO_PTR(id)))
- return;
-
- error("scpp: Could not discover characteristic");
- g_attrib_cancel(attrib, id);
-}
-
-static void discover_desc(struct bt_scpp *scpp, GAttrib *attrib,
- uint16_t start, uint16_t end, bt_uuid_t *uuid,
- gatt_cb_t func, gpointer user_data)
-{
- unsigned int id;
-
- id = gatt_discover_desc(attrib, start, end, uuid, func, user_data);
-
- if (queue_push_head(scpp->gatt_op, UINT_TO_PTR(id)))
- return;
-
- error("scpp: Could not discover descriptor");
- g_attrib_cancel(attrib, id);
-}
-
-static void write_char(struct bt_scpp *scan, GAttrib *attrib, uint16_t handle,
- const uint8_t *value, size_t vlen,
- GAttribResultFunc func,
- gpointer user_data)
-{
- unsigned int id;
-
- id = gatt_write_char(attrib, handle, value, vlen, func, user_data);
-
- if (queue_push_head(scan->gatt_op, UINT_TO_PTR(id)))
- return;
-
- error("scpp: Could not read char");
- g_attrib_cancel(attrib, id);
-}
-
static void scpp_free(struct bt_scpp *scan)
{
bt_scpp_detach(scan);

g_free(scan->primary);
- queue_destroy(scan->gatt_op, NULL); /* cleared in bt_scpp_detach */
g_free(scan);
}

@@ -132,12 +83,6 @@ struct bt_scpp *bt_scpp_new(void *primary)
scan->interval = SCAN_INTERVAL;
scan->window = SCAN_WINDOW;

- scan->gatt_op = queue_new();
- if (!scan->gatt_op) {
- scpp_free(scan);
- return NULL;
- }
-
if (primary)
scan->primary = g_memdup(primary, sizeof(*scan->primary));

@@ -213,7 +158,7 @@ static void write_ccc(struct bt_scpp *scan, GAttrib *attrib, uint16_t handle,

put_le16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);

- write_char(scan, attrib, handle, value, sizeof(value), ccc_written_cb,
+ gatt_write_char(attrib, handle, value, sizeof(value), ccc_written_cb,
user_data);
}

@@ -266,7 +211,7 @@ static void refresh_discovered_cb(uint8_t status, GSList *chars,

bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);

- discover_desc(scan, scan->attrib, start, end, &uuid,
+ gatt_discover_desc(scan->attrib, start, end, &uuid,
discover_descriptor_cb, user_data);
}

@@ -304,7 +249,7 @@ bool bt_scpp_attach(struct bt_scpp *scan, void *attrib)
scan->window);
else {
bt_uuid16_create(&iwin_uuid, SCAN_INTERVAL_WIN_UUID);
- discover_char(scan, scan->attrib, scan->primary->range.start,
+ gatt_discover_char(scan->attrib, scan->primary->range.start,
scan->primary->range.end, &iwin_uuid,
iwin_discovered_cb, scan);
}
@@ -315,7 +260,7 @@ bool bt_scpp_attach(struct bt_scpp *scan, void *attrib)
refresh_value_cb, scan, NULL);
else {
bt_uuid16_create(&refresh_uuid, SCAN_REFRESH_UUID);
- discover_char(scan, scan->attrib, scan->primary->range.start,
+ gatt_discover_char(scan->attrib, scan->primary->range.start,
scan->primary->range.end, &refresh_uuid,
refresh_discovered_cb, scan);
}
@@ -323,14 +268,6 @@ bool bt_scpp_attach(struct bt_scpp *scan, void *attrib)
return true;
}

-static void cancel_gatt_req(void *data, void *user_data)
-{
- unsigned int id = PTR_TO_UINT(data);
- struct bt_scpp *scan = user_data;
-
- g_attrib_cancel(scan->attrib, id);
-}
-
void bt_scpp_detach(struct bt_scpp *scan)
{
if (!scan || !scan->attrib)
@@ -341,7 +278,6 @@ void bt_scpp_detach(struct bt_scpp *scan)
scan->refresh_cb_id = 0;
}

- queue_foreach(scan->gatt_op, cancel_gatt_req, scan);
g_attrib_unref(scan->attrib);
scan->attrib = NULL;
}
--
1.9.1


2015-04-03 13:43:52

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 23/27] android/bas: Enable Battery Level notifications after reconnection

---
android/bas.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/android/bas.c b/android/bas.c
index d70a44d..145d4da 100644
--- a/android/bas.c
+++ b/android/bas.c
@@ -149,6 +149,10 @@ bool bt_bas_attach(struct bt_bas *bas, struct bt_gatt_client *client)

if (!bas->handle)
gatt_db_service_foreach_char(attrib, bas_discovered_cb, bas);
+ else
+ bas->id = bt_gatt_client_register_notify(bas->client,
+ bas->handle, ccc_written_cb,
+ notification_cb, bas, NULL);

return true;
}
--
1.9.1


2015-04-03 13:43:51

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 22/27] android/hog: Enable Input Report notifications only if uhid is created

This prevents against the situation when notification is received
before uhid is created. Otherwise bt_uhid error message appears.
---
android/hog.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/android/hog.c b/android/hog.c
index d7a00ba..790f362 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -205,8 +205,6 @@ static void report_reference_cb(bool success, uint8_t status,
report->id = value[0];
report->type = value[1];
DBG("Report ID: 0x%02x Report type: 0x%02x", value[0], value[1]);
-
- report_enable_notif(report, NULL);
}

static void external_report_reference_cb(bool success, uint8_t status,
@@ -715,6 +713,7 @@ static bool uhid_create(struct bt_hog *hog, const uint8_t *value, uint16_t vlen)
return false;
}

+ queue_foreach(hog->reports, report_enable_notif, NULL);
bt_uhid_register(hog->uhid, UHID_OUTPUT, forward_report, hog);
bt_uhid_register(hog->uhid, UHID_FEATURE, get_feature, hog);
bt_uhid_register(hog->uhid, UHID_GET_REPORT, get_report, hog);
--
1.9.1


2015-04-03 13:43:49

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 20/27] android/bas: Start using bt_gatt_client

This patch replaces gattrib with bt_gatt_client and strips glib dependencies.
---
android/bas.c | 163 ++++++++++++++++++----------------------------------------
android/bas.h | 4 +-
android/hog.c | 40 ++------------
3 files changed, 58 insertions(+), 149 deletions(-)

diff --git a/android/bas.c b/android/bas.c
index c5de3b1..d70a44d 100644
--- a/android/bas.c
+++ b/android/bas.c
@@ -28,53 +28,47 @@
#include <stdbool.h>
#include <errno.h>

-#include <glib.h>
-
#include "src/log.h"

#include "lib/bluetooth.h"
-#include "lib/sdp.h"
#include "lib/uuid.h"

#include "src/shared/util.h"
#include "src/shared/queue.h"
-
-#include "attrib/gattrib.h"
-#include "attrib/att.h"
-#include "attrib/gatt.h"
+#include "src/shared/att.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-client.h"

#include "android/bas.h"

-#define ATT_NOTIFICATION_HEADER_SIZE 3
-#define ATT_READ_RESPONSE_HEADER_SIZE 1
-
struct bt_bas {
int ref_count;
- GAttrib *attrib;
- struct gatt_primary *primary;
- uint16_t handle;
- uint16_t ccc_handle;
- guint id;
+ uint16_t service_handle; /* Battery service start handle */
+ uint16_t handle; /* Battery level value handle */
+ uint32_t id;
+ struct bt_gatt_client *client;
+ struct gatt_db *db;
};

static void bas_free(struct bt_bas *bas)
{
bt_bas_detach(bas);

- g_free(bas->primary);
- g_free(bas);
+ free(bas);
}

-struct bt_bas *bt_bas_new(void *primary)
+struct bt_bas *bt_bas_new(uint16_t service_handle)
{
struct bt_bas *bas;

- bas = g_try_new0(struct bt_bas, 1);
+ if (!service_handle)
+ return NULL;
+
+ bas = new0(struct bt_bas, 1);
if (!bas)
return NULL;

- if (primary)
- bas->primary = g_memdup(primary, sizeof(*bas->primary));
+ bas->service_handle = service_handle;

return bt_bas_ref(bas);
}
@@ -100,132 +94,77 @@ void bt_bas_unref(struct bt_bas *bas)
bas_free(bas);
}

-static void notification_cb(const guint8 *pdu, guint16 len, gpointer user_data)
-{
- DBG("Battery Level at %u", pdu[ATT_NOTIFICATION_HEADER_SIZE]);
-}
-
-static void read_value_cb(guint8 status, const guint8 *pdu, guint16 len,
- gpointer user_data)
-{
- DBG("Battery Level at %u", pdu[ATT_READ_RESPONSE_HEADER_SIZE]);
-}
-
-static void ccc_written_cb(guint8 status, const guint8 *pdu,
- guint16 plen, gpointer user_data)
+static void notification_cb(uint16_t value_handle, const uint8_t *value,
+ uint16_t length, void *user_data)
{
- struct bt_bas *bas = user_data;
-
- if (status != 0) {
- error("Write Scan Refresh CCC failed: %s",
- att_ecode2str(status));
- return;
- }
-
- DBG("Battery Level: notification enabled");
-
- bas->id = g_attrib_register(bas->attrib, ATT_OP_HANDLE_NOTIFY,
- bas->handle, notification_cb, bas,
- NULL);
+ DBG("Battery Level at %u", value[0]);
}

-static void write_ccc(struct bt_bas *bas, GAttrib *attrib, uint16_t handle,
- void *user_data)
+static void read_value_cb(bool success, uint8_t att_ecode, const uint8_t *value,
+ uint16_t length, void *user_data)
{
- uint8_t value[2];
+ if (!success)
+ error("Read battery level failed: att_ecode %d", att_ecode);

- put_le16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);
-
- gatt_write_char(attrib, handle, value, sizeof(value), ccc_written_cb,
- user_data);
+ DBG("Battery Level at %u", value[0]);
}

-static void ccc_read_cb(guint8 status, const guint8 *pdu, guint16 len,
- gpointer user_data)
+static void ccc_written_cb(uint16_t att_ecode, void *user_data)
{
- struct bt_bas *bas = user_data;
-
- if (status != 0) {
- error("Error reading CCC value: %s", att_ecode2str(status));
- return;
- }
-
- write_ccc(bas, bas->attrib, bas->ccc_handle, bas);
-}
-
-static void discover_descriptor_cb(uint8_t status, GSList *descs,
- void *user_data)
-{
- struct bt_bas *bas = user_data;
- struct gatt_desc *desc;
-
- if (status != 0) {
- error("Discover descriptors failed: %s", att_ecode2str(status));
- return;
- }
-
- /* There will be only one descriptor on list and it will be CCC */
- desc = descs->data;
- bas->ccc_handle = desc->handle;
-
- gatt_read_char(bas->attrib, desc->handle, ccc_read_cb, bas);
+ DBG("Battery Level: notification enabled");
}

-static void bas_discovered_cb(uint8_t status, GSList *chars, void *user_data)
+static void bas_discovered_cb(struct gatt_db_attribute *attrib, void *user_data)
{
struct bt_bas *bas = user_data;
- struct gatt_char *chr;
- uint16_t start, end;
+ uint16_t value_handle;
bt_uuid_t uuid;

- if (status) {
- error("Battery: %s", att_ecode2str(status));
- return;
- }
+ gatt_db_attribute_get_char_data(attrib, NULL, &value_handle,
+ NULL, &uuid);

- chr = chars->data;
- bas->handle = chr->value_handle;
+ bas->handle = value_handle;

DBG("Battery handle: 0x%04x", bas->handle);

- gatt_read_char(bas->attrib, bas->handle, read_value_cb, bas);
-
- start = chr->value_handle + 1;
- end = bas->primary->range.end;
+ bt_gatt_client_read_value(bas->client, bas->handle, read_value_cb,
+ bas, NULL);

- bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
+ bas->id = bt_gatt_client_register_notify(bas->client, bas->handle,
+ ccc_written_cb, notification_cb, bas, NULL);

- gatt_discover_desc(bas->attrib, start, end, &uuid,
- discover_descriptor_cb, bas);
+ /* TODO Characteristic Presentation Format shall be read */
}

-bool bt_bas_attach(struct bt_bas *bas, void *attrib)
+bool bt_bas_attach(struct bt_bas *bas, struct bt_gatt_client *client)
{
- if (!bas || bas->attrib || !bas->primary)
- return false;
+ struct gatt_db_attribute *attrib;

- bas->attrib = g_attrib_ref(attrib);
+ if (!bas || bas->client || !bas->service_handle)
+ return false;

- if (bas->handle > 0)
- return true;
+ bas->client = bt_gatt_client_ref(client);
+ bas->db = gatt_db_ref(bt_gatt_client_get_db(client));
+ attrib = gatt_db_get_attribute(bas->db, bas->service_handle);

- gatt_discover_char(bas->attrib, bas->primary->range.start,
- bas->primary->range.end, NULL,
- bas_discovered_cb, bas);
+ if (!bas->handle)
+ gatt_db_service_foreach_char(attrib, bas_discovered_cb, bas);

return true;
}

void bt_bas_detach(struct bt_bas *bas)
{
- if (!bas || !bas->attrib)
+ if (!bas || !bas->client)
return;

- if (bas->id > 0) {
- g_attrib_unregister(bas->attrib, bas->id);
+ if (bas->id) {
+ bt_gatt_client_unregister_notify(bas->client, bas->id);
bas->id = 0;
}

- g_attrib_unref(bas->attrib);
- bas->attrib = NULL;
+ gatt_db_unref(bas->db);
+ bas->db = NULL;
+ bt_gatt_client_unref(bas->client);
+ bas->client = NULL;
}
diff --git a/android/bas.h b/android/bas.h
index 3e175b5..ce903e3 100644
--- a/android/bas.h
+++ b/android/bas.h
@@ -23,10 +23,10 @@

struct bt_bas;

-struct bt_bas *bt_bas_new(void *primary);
+struct bt_bas *bt_bas_new(uint16_t service_handle);

struct bt_bas *bt_bas_ref(struct bt_bas *bas);
void bt_bas_unref(struct bt_bas *bas);

-bool bt_bas_attach(struct bt_bas *bas, void *gatt);
+bool bt_bas_attach(struct bt_bas *bas, struct bt_gatt_client *client);
void bt_bas_detach(struct bt_bas *bas);
diff --git a/android/hog.c b/android/hog.c
index 609df58..eaac097 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -995,15 +995,15 @@ static void hog_attach_dis(struct bt_hog *hog, uint16_t service_handle)
}
}

-static void hog_attach_bas(struct bt_hog *hog, struct gatt_primary *primary)
+static void hog_attach_bas(struct bt_hog *hog, uint16_t service_handle)
{
struct bt_bas *instance;

- instance = bt_bas_new(primary);
+ instance = bt_bas_new(service_handle);
if (!instance)
return;

- bt_bas_attach(instance, hog->attrib);
+ bt_bas_attach(instance, hog->client);
queue_push_head(hog->bas, instance);
}

@@ -1030,34 +1030,6 @@ static void hog_attach_hog(struct bt_hog *hog, uint16_t service_handle)
queue_push_tail(hog->instances, instance);
}

-static void primary_cb(uint8_t status, GSList *services, void *user_data)
-{
- struct bt_hog *hog = user_data;
- struct gatt_primary *primary;
- GSList *l;
-
- DBG("");
-
- if (status) {
- const char *str = att_ecode2str(status);
- DBG("Discover primary failed: %s", str);
- return;
- }
-
- if (!services) {
- DBG("No primary service found");
- return;
- }
-
- for (l = services; l; l = l->next) {
- primary = l->data;
-
- if (strcmp(primary->uuid, BATTERY_UUID) == 0) {
- hog_attach_bas(hog, primary);
- }
- }
-}
-
static void service_cb(struct gatt_db_attribute *attrib, void *user_data)
{
struct bt_hog *hog = user_data;
@@ -1078,8 +1050,7 @@ static void service_cb(struct gatt_db_attribute *attrib, void *user_data)
else if (!bt_uuid_strcmp(uuid, DEVICE_INFORMATION_UUID))
hog_attach_dis(hog, service_handle);
else if (!bt_uuid_strcmp(uuid, BATTERY_UUID))
- /* TODO */
- return;
+ hog_attach_bas(hog, service_handle);
}

bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)
@@ -1095,7 +1066,6 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)

if (!hog->service_handle) {
gatt_db_foreach_service(hog->db, NULL, service_cb, hog);
- gatt_discover_primary(hog->attrib, NULL, primary_cb, hog);
return true;
}

@@ -1105,7 +1075,7 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)
if (hog->dis)
bt_dis_attach(hog->dis, hog->client);

- queue_foreach(hog->bas, (void *) bt_bas_attach, gatt);
+ queue_foreach(hog->bas, (void *) bt_bas_attach, hog->client);

hog_entry = queue_get_entries(hog->instances);
while (hog_entry) {
--
1.9.1


2015-04-03 13:43:48

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 19/27] android/bas: Remove tracking pending gatt operations

Since the use of bt_gatt_client there is no need to queue pending gatt
operations. bt_gatt_client already keeps track on that, so that
on bt_gatt_client_unref the queue of pending requests is destroyed.
---
android/bas.c | 166 ++++------------------------------------------------------
1 file changed, 9 insertions(+), 157 deletions(-)

diff --git a/android/bas.c b/android/bas.c
index dcbf9de..c5de3b1 100644
--- a/android/bas.c
+++ b/android/bas.c
@@ -55,28 +55,13 @@ struct bt_bas {
uint16_t handle;
uint16_t ccc_handle;
guint id;
- struct queue *gatt_op;
};

-struct gatt_request {
- unsigned int id;
- struct bt_bas *bas;
- void *user_data;
-};
-
-static void destroy_gatt_req(struct gatt_request *req)
-{
- queue_remove(req->bas->gatt_op, req);
- bt_bas_unref(req->bas);
- free(req);
-}
-
static void bas_free(struct bt_bas *bas)
{
bt_bas_detach(bas);

g_free(bas->primary);
- queue_destroy(bas->gatt_op, (void *) destroy_gatt_req);
g_free(bas);
}

@@ -88,12 +73,6 @@ struct bt_bas *bt_bas_new(void *primary)
if (!bas)
return NULL;

- bas->gatt_op = queue_new();
- if (!bas->gatt_op) {
- bas_free(bas);
- return NULL;
- }
-
if (primary)
bas->primary = g_memdup(primary, sizeof(*bas->primary));

@@ -121,114 +100,6 @@ void bt_bas_unref(struct bt_bas *bas)
bas_free(bas);
}

-static struct gatt_request *create_request(struct bt_bas *bas,
- void *user_data)
-{
- struct gatt_request *req;
-
- req = new0(struct gatt_request, 1);
- if (!req)
- return NULL;
-
- req->user_data = user_data;
- req->bas = bt_bas_ref(bas);
-
- return req;
-}
-
-static bool set_and_store_gatt_req(struct bt_bas *bas,
- struct gatt_request *req,
- unsigned int id)
-{
- req->id = id;
- return queue_push_head(bas->gatt_op, req);
-}
-
-static void write_char(struct bt_bas *bas, GAttrib *attrib, uint16_t handle,
- const uint8_t *value, size_t vlen,
- GAttribResultFunc func,
- gpointer user_data)
-{
- struct gatt_request *req;
- unsigned int id;
-
- req = create_request(bas, user_data);
- if (!req)
- return;
-
- id = gatt_write_char(attrib, handle, value, vlen, func, req);
-
- if (set_and_store_gatt_req(bas, req, id))
- return;
-
- error("bas: Could not write characteristic");
- g_attrib_cancel(attrib, id);
- free(req);
-
-}
-
-static void read_char(struct bt_bas *bas, GAttrib *attrib, uint16_t handle,
- GAttribResultFunc func, gpointer user_data)
-{
- struct gatt_request *req;
- unsigned int id;
-
- req = create_request(bas, user_data);
- if (!req)
- return;
-
- id = gatt_read_char(attrib, handle, func, req);
-
- if (set_and_store_gatt_req(bas, req, id))
- return;
-
- error("bas: Could not read characteristic");
- g_attrib_cancel(attrib, id);
- free(req);
-}
-
-static void discover_char(struct bt_bas *bas, GAttrib *attrib,
- uint16_t start, uint16_t end,
- bt_uuid_t *uuid, gatt_cb_t func,
- gpointer user_data)
-{
- struct gatt_request *req;
- unsigned int id;
-
- req = create_request(bas, user_data);
- if (!req)
- return;
-
- id = gatt_discover_char(attrib, start, end, uuid, func, req);
-
- if (set_and_store_gatt_req(bas, req, id))
- return;
-
- error("bas: Could not discover characteristic");
- g_attrib_cancel(attrib, id);
- free(req);
-}
-
-static void discover_desc(struct bt_bas *bas, GAttrib *attrib,
- uint16_t start, uint16_t end, bt_uuid_t *uuid,
- gatt_cb_t func, gpointer user_data)
-{
- struct gatt_request *req;
- unsigned int id;
-
- req = create_request(bas, user_data);
- if (!req)
- return;
-
- id = gatt_discover_desc(attrib, start, end, uuid, func, req);
- if (set_and_store_gatt_req(bas, req, id))
- return;
-
- error("bas: Could not discover descriptor");
- g_attrib_cancel(attrib, id);
- free(req);
-}
-
static void notification_cb(const guint8 *pdu, guint16 len, gpointer user_data)
{
DBG("Battery Level at %u", pdu[ATT_NOTIFICATION_HEADER_SIZE]);
@@ -243,10 +114,7 @@ static void read_value_cb(guint8 status, const guint8 *pdu, guint16 len,
static void ccc_written_cb(guint8 status, const guint8 *pdu,
guint16 plen, gpointer user_data)
{
- struct gatt_request *req = user_data;
- struct bt_bas *bas = req->user_data;
-
- destroy_gatt_req(req);
+ struct bt_bas *bas = user_data;

if (status != 0) {
error("Write Scan Refresh CCC failed: %s",
@@ -268,17 +136,14 @@ static void write_ccc(struct bt_bas *bas, GAttrib *attrib, uint16_t handle,

put_le16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);

- write_char(bas, attrib, handle, value, sizeof(value), ccc_written_cb,
+ gatt_write_char(attrib, handle, value, sizeof(value), ccc_written_cb,
user_data);
}

static void ccc_read_cb(guint8 status, const guint8 *pdu, guint16 len,
gpointer user_data)
{
- struct gatt_request *req = user_data;
- struct bt_bas *bas = req->user_data;
-
- destroy_gatt_req(req);
+ struct bt_bas *bas = user_data;

if (status != 0) {
error("Error reading CCC value: %s", att_ecode2str(status));
@@ -291,12 +156,9 @@ static void ccc_read_cb(guint8 status, const guint8 *pdu, guint16 len,
static void discover_descriptor_cb(uint8_t status, GSList *descs,
void *user_data)
{
- struct gatt_request *req = user_data;
- struct bt_bas *bas = req->user_data;
+ struct bt_bas *bas = user_data;
struct gatt_desc *desc;

- destroy_gatt_req(req);
-
if (status != 0) {
error("Discover descriptors failed: %s", att_ecode2str(status));
return;
@@ -306,19 +168,16 @@ static void discover_descriptor_cb(uint8_t status, GSList *descs,
desc = descs->data;
bas->ccc_handle = desc->handle;

- read_char(bas, bas->attrib, desc->handle, ccc_read_cb, bas);
+ gatt_read_char(bas->attrib, desc->handle, ccc_read_cb, bas);
}

static void bas_discovered_cb(uint8_t status, GSList *chars, void *user_data)
{
- struct gatt_request *req = user_data;
- struct bt_bas *bas = req->user_data;
+ struct bt_bas *bas = user_data;
struct gatt_char *chr;
uint16_t start, end;
bt_uuid_t uuid;

- destroy_gatt_req(req);
-
if (status) {
error("Battery: %s", att_ecode2str(status));
return;
@@ -329,14 +188,14 @@ static void bas_discovered_cb(uint8_t status, GSList *chars, void *user_data)

DBG("Battery handle: 0x%04x", bas->handle);

- read_char(bas, bas->attrib, bas->handle, read_value_cb, bas);
+ gatt_read_char(bas->attrib, bas->handle, read_value_cb, bas);

start = chr->value_handle + 1;
end = bas->primary->range.end;

bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);

- discover_desc(bas, bas->attrib, start, end, &uuid,
+ gatt_discover_desc(bas->attrib, start, end, &uuid,
discover_descriptor_cb, bas);
}

@@ -350,19 +209,13 @@ bool bt_bas_attach(struct bt_bas *bas, void *attrib)
if (bas->handle > 0)
return true;

- discover_char(bas, bas->attrib, bas->primary->range.start,
+ gatt_discover_char(bas->attrib, bas->primary->range.start,
bas->primary->range.end, NULL,
bas_discovered_cb, bas);

return true;
}

-static void cancel_gatt_req(struct gatt_request *req)
-{
- if (g_attrib_cancel(req->bas->attrib, req->id))
- destroy_gatt_req(req);
-}
-
void bt_bas_detach(struct bt_bas *bas)
{
if (!bas || !bas->attrib)
@@ -373,7 +226,6 @@ void bt_bas_detach(struct bt_bas *bas)
bas->id = 0;
}

- queue_foreach(bas->gatt_op, (void *) cancel_gatt_req, NULL);
g_attrib_unref(bas->attrib);
bas->attrib = NULL;
}
--
1.9.1


2015-04-03 13:43:47

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 18/27] android/scpp: Merge refresh_discovered_cb with iwin_discovered_cb

This two callbacks do the same work when used with
gatt_db_service_foreach_char, because search for characteristic with
specificis not performed, so they can be merged.
---
android/scpp.c | 56 ++++++++++++++++++++------------------------------------
1 file changed, 20 insertions(+), 36 deletions(-)

diff --git a/android/scpp.c b/android/scpp.c
index 0f388c0..95e4db6 100644
--- a/android/scpp.c
+++ b/android/scpp.c
@@ -138,51 +138,36 @@ static void ccc_written_cb(uint16_t att_ecode, void *user_data)
DBG("Scan Refresh: notification enabled");
}

-static void refresh_discovered_cb(struct gatt_db_attribute *attrib,
- void *user_data)
+static void characteristic_cb(struct gatt_db_attribute *attrib, void *user_data)
{
struct bt_scpp *scan = user_data;
- bt_uuid_t uuid, refresh_uuid;
+ bt_uuid_t uuid, iwin_uuid, refresh_uuid;
uint16_t value_handle;

gatt_db_attribute_get_char_data(attrib, NULL, &value_handle, NULL,
&uuid);
-
+ bt_uuid16_create(&iwin_uuid, SCAN_INTERVAL_WIN_UUID);
bt_uuid16_create(&refresh_uuid, SCAN_REFRESH_UUID);

- if (bt_uuid_cmp(&uuid, &refresh_uuid))
- return;
+ if (!scan->iwhandle && !bt_uuid_cmp(&uuid, &iwin_uuid)) {
+ scan->iwhandle = value_handle;

- scan->refresh_handle = value_handle;
+ DBG("Scan Interval Window handle: 0x%04x", scan->iwhandle);

- DBG("Scan Refresh handle: 0x%04x", scan->refresh_handle);
+ write_scan_params(scan->client, scan->iwhandle, scan->interval,
+ scan->window);
+ }

- scan->refresh_cb_id = bt_gatt_client_register_notify(scan->client,
- scan->refresh_handle, ccc_written_cb,
+ if (!scan->refresh_handle && !bt_uuid_cmp(&uuid, &refresh_uuid)) {
+ uint32_t id = bt_gatt_client_register_notify(scan->client,
+ value_handle, ccc_written_cb,
refresh_value_cb, scan, NULL);
-}
-
-static void iwin_discovered_cb(struct gatt_db_attribute *attrib,
- void *user_data)
-{
- struct bt_scpp *scan = user_data;
- bt_uuid_t uuid, iwin_uuid;
- uint16_t value_handle;

- gatt_db_attribute_get_char_data(attrib, NULL, &value_handle, NULL,
- &uuid);
-
- bt_uuid16_create(&iwin_uuid, SCAN_INTERVAL_WIN_UUID);
-
- if (bt_uuid_cmp(&uuid, &iwin_uuid))
- return;
-
- scan->iwhandle = value_handle;
+ DBG("Scan Refresh handle: 0x%04x", value_handle);

- DBG("Scan Interval Window handle: 0x%04x", scan->iwhandle);
-
- write_scan_params(scan->client, scan->iwhandle, scan->interval,
- scan->window);
+ scan->refresh_handle = value_handle;
+ scan->refresh_cb_id = id;
+ }
}

bool bt_scpp_attach(struct bt_scpp *scan, struct bt_gatt_client *client)
@@ -199,17 +184,16 @@ bool bt_scpp_attach(struct bt_scpp *scan, struct bt_gatt_client *client)
if (scan->iwhandle)
write_scan_params(scan->client, scan->iwhandle, scan->interval,
scan->window);
- else
- gatt_db_service_foreach_char(attrib, iwin_discovered_cb, scan);

if (scan->refresh_handle) {
uint32_t id = bt_gatt_client_register_notify(scan->client,
scan->refresh_handle, ccc_written_cb,
refresh_value_cb, scan, NULL);
scan->refresh_cb_id = id;
- } else
- gatt_db_service_foreach_char(attrib, refresh_discovered_cb,
- scan);
+ }
+
+ if (!scan->iwhandle || !scan->refresh_handle)
+ gatt_db_service_foreach_char(attrib, characteristic_cb, scan);

return true;
}
--
1.9.1


2015-04-03 13:43:46

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 17/27] android/scpp: Introduce bt_gatt_client

From: Mariusz Skamra <[email protected]>

This patch replaces gattrib with bt_gatt_client and strips glib dependencies.
---
android/hog.c | 18 ++----
android/scpp.c | 197 +++++++++++++++++++++------------------------------------
android/scpp.h | 4 +-
3 files changed, 81 insertions(+), 138 deletions(-)

diff --git a/android/hog.c b/android/hog.c
index 091a9a5..609df58 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -959,16 +959,16 @@ static void find_included_cb(struct gatt_db_attribute *attrib, void *user_data)
DBG("included: handle %x", start_handle);
}

-static void hog_attach_scpp(struct bt_hog *hog, struct gatt_primary *primary)
+static void hog_attach_scpp(struct bt_hog *hog, uint16_t service_handle)
{
if (hog->scpp) {
- bt_scpp_attach(hog->scpp, hog->attrib);
+ bt_scpp_attach(hog->scpp, hog->client);
return;
}

- hog->scpp = bt_scpp_new(primary);
+ hog->scpp = bt_scpp_new(service_handle);
if (hog->scpp)
- bt_scpp_attach(hog->scpp, hog->attrib);
+ bt_scpp_attach(hog->scpp, hog->client);
}

static void dis_notify(uint8_t source, uint16_t vendor, uint16_t product,
@@ -1052,11 +1052,6 @@ static void primary_cb(uint8_t status, GSList *services, void *user_data)
for (l = services; l; l = l->next) {
primary = l->data;

- if (strcmp(primary->uuid, SCAN_PARAMETERS_UUID) == 0) {
- hog_attach_scpp(hog, primary);
- continue;
- }
-
if (strcmp(primary->uuid, BATTERY_UUID) == 0) {
hog_attach_bas(hog, primary);
}
@@ -1079,8 +1074,7 @@ static void service_cb(struct gatt_db_attribute *attrib, void *user_data)
if (!bt_uuid_strcmp(uuid, HOG_UUID))
hog_attach_hog(hog, service_handle);
else if (!bt_uuid_strcmp(uuid, SCAN_PARAMETERS_UUID))
- /* TODO */
- return;
+ hog_attach_scpp(hog, service_handle);
else if (!bt_uuid_strcmp(uuid, DEVICE_INFORMATION_UUID))
hog_attach_dis(hog, service_handle);
else if (!bt_uuid_strcmp(uuid, BATTERY_UUID))
@@ -1106,7 +1100,7 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)
}

if (hog->scpp)
- bt_scpp_attach(hog->scpp, gatt);
+ bt_scpp_attach(hog->scpp, hog->client);

if (hog->dis)
bt_dis_attach(hog->dis, hog->client);
diff --git a/android/scpp.c b/android/scpp.c
index a28fbb6..0f388c0 100644
--- a/android/scpp.c
+++ b/android/scpp.c
@@ -26,23 +26,16 @@
#include <config.h>
#endif

-#include <stdbool.h>
-#include <errno.h>
-
-#include <glib.h>
-
#include "src/log.h"

#include "lib/bluetooth.h"
-#include "lib/sdp.h"
#include "lib/uuid.h"

#include "src/shared/util.h"
#include "src/shared/queue.h"
-
-#include "attrib/att.h"
-#include "attrib/gattrib.h"
-#include "attrib/gatt.h"
+#include "src/shared/att.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-client.h"

#include "android/scpp.h"

@@ -55,36 +48,37 @@

struct bt_scpp {
int ref_count;
- GAttrib *attrib;
- struct gatt_primary *primary;
+ uint16_t service_handle;
uint16_t interval;
uint16_t window;
uint16_t iwhandle;
uint16_t refresh_handle;
- guint refresh_cb_id;
+ uint32_t refresh_cb_id;
+ struct bt_gatt_client *client;
+ struct gatt_db *db;
};

static void scpp_free(struct bt_scpp *scan)
{
bt_scpp_detach(scan);

- g_free(scan->primary);
- g_free(scan);
+ free(scan);
}

-struct bt_scpp *bt_scpp_new(void *primary)
+struct bt_scpp *bt_scpp_new(uint16_t service_handle)
{
struct bt_scpp *scan;

- scan = g_try_new0(struct bt_scpp, 1);
+ if (!service_handle)
+ return NULL;
+
+ scan = new0(struct bt_scpp, 1);
if (!scan)
return NULL;

scan->interval = SCAN_INTERVAL;
scan->window = SCAN_WINDOW;
-
- if (primary)
- scan->primary = g_memdup(primary, sizeof(*scan->primary));
+ scan->service_handle = service_handle;

return bt_scpp_ref(scan);
}
@@ -110,7 +104,7 @@ void bt_scpp_unref(struct bt_scpp *scan)
scpp_free(scan);
}

-static void write_scan_params(GAttrib *attrib, uint16_t handle,
+static void write_scan_params(struct bt_gatt_client *client, uint16_t handle,
uint16_t interval, uint16_t window)
{
uint8_t value[4];
@@ -118,168 +112,123 @@ static void write_scan_params(GAttrib *attrib, uint16_t handle,
put_le16(interval, &value[0]);
put_le16(window, &value[2]);

- gatt_write_cmd(attrib, handle, value, sizeof(value), NULL, NULL);
+ bt_gatt_client_write_without_response(client, handle, NULL, value,
+ sizeof(value));
}

-static void refresh_value_cb(const uint8_t *pdu, uint16_t len,
- gpointer user_data)
+static void refresh_value_cb(uint16_t value_handle, const uint8_t *value,
+ uint16_t length, void *user_data)
{
struct bt_scpp *scan = user_data;

- DBG("Server requires refresh: %d", pdu[3]);
+ DBG("Server requires refresh: %d", value[0]);

- if (pdu[3] == SERVER_REQUIRES_REFRESH)
- write_scan_params(scan->attrib, scan->iwhandle, scan->interval,
+ if (value[0] == SERVER_REQUIRES_REFRESH)
+ write_scan_params(scan->client, scan->iwhandle, scan->interval,
scan->window);
}

-static void ccc_written_cb(guint8 status, const guint8 *pdu,
- guint16 plen, gpointer user_data)
+static void ccc_written_cb(uint16_t att_ecode, void *user_data)
{
- struct bt_scpp *scan = user_data;
-
- if (status != 0) {
- error("Write Scan Refresh CCC failed: %s",
- att_ecode2str(status));
+ if (att_ecode != 0) {
+ error("Write Scan Refresh CCC failed: att_ecode %d", att_ecode);
return;
}

DBG("Scan Refresh: notification enabled");
-
- scan->refresh_cb_id = g_attrib_register(scan->attrib,
- ATT_OP_HANDLE_NOTIFY, scan->refresh_handle,
- refresh_value_cb, scan, NULL);
}

-static void write_ccc(struct bt_scpp *scan, GAttrib *attrib, uint16_t handle,
+static void refresh_discovered_cb(struct gatt_db_attribute *attrib,
void *user_data)
{
- uint8_t value[2];
-
- put_le16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);
+ struct bt_scpp *scan = user_data;
+ bt_uuid_t uuid, refresh_uuid;
+ uint16_t value_handle;

- gatt_write_char(attrib, handle, value, sizeof(value), ccc_written_cb,
- user_data);
-}
+ gatt_db_attribute_get_char_data(attrib, NULL, &value_handle, NULL,
+ &uuid);

-static void discover_descriptor_cb(uint8_t status, GSList *descs,
- void *user_data)
-{
- struct bt_scpp *scan = user_data;
- struct gatt_desc *desc;
+ bt_uuid16_create(&refresh_uuid, SCAN_REFRESH_UUID);

- if (status != 0) {
- error("Discover descriptors failed: %s", att_ecode2str(status));
+ if (bt_uuid_cmp(&uuid, &refresh_uuid))
return;
- }

- /* There will be only one descriptor on list and it will be CCC */
- desc = descs->data;
+ scan->refresh_handle = value_handle;
+
+ DBG("Scan Refresh handle: 0x%04x", scan->refresh_handle);

- write_ccc(scan, scan->attrib, desc->handle, scan);
+ scan->refresh_cb_id = bt_gatt_client_register_notify(scan->client,
+ scan->refresh_handle, ccc_written_cb,
+ refresh_value_cb, scan, NULL);
}

-static void refresh_discovered_cb(uint8_t status, GSList *chars,
+static void iwin_discovered_cb(struct gatt_db_attribute *attrib,
void *user_data)
{
struct bt_scpp *scan = user_data;
- struct gatt_char *chr;
- uint16_t start, end;
- bt_uuid_t uuid;
+ bt_uuid_t uuid, iwin_uuid;
+ uint16_t value_handle;

- if (status) {
- error("Scan Refresh %s", att_ecode2str(status));
- return;
- }
+ gatt_db_attribute_get_char_data(attrib, NULL, &value_handle, NULL,
+ &uuid);

- if (!chars) {
- DBG("Scan Refresh not supported");
- return;
- }
-
- chr = chars->data;
-
- DBG("Scan Refresh handle: 0x%04x", chr->value_handle);
-
- start = chr->value_handle + 1;
- end = scan->primary->range.end;
-
- if (start > end)
- return;
-
- scan->refresh_handle = chr->value_handle;
-
- bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
+ bt_uuid16_create(&iwin_uuid, SCAN_INTERVAL_WIN_UUID);

- gatt_discover_desc(scan->attrib, start, end, &uuid,
- discover_descriptor_cb, user_data);
-}
-
-static void iwin_discovered_cb(uint8_t status, GSList *chars, void *user_data)
-{
- struct bt_scpp *scan = user_data;
- struct gatt_char *chr;
-
- if (status) {
- error("Discover Scan Interval Window: %s",
- att_ecode2str(status));
+ if (bt_uuid_cmp(&uuid, &iwin_uuid))
return;
- }

- chr = chars->data;
- scan->iwhandle = chr->value_handle;
+ scan->iwhandle = value_handle;

DBG("Scan Interval Window handle: 0x%04x", scan->iwhandle);

- write_scan_params(scan->attrib, scan->iwhandle, scan->interval,
+ write_scan_params(scan->client, scan->iwhandle, scan->interval,
scan->window);
}

-bool bt_scpp_attach(struct bt_scpp *scan, void *attrib)
+bool bt_scpp_attach(struct bt_scpp *scan, struct bt_gatt_client *client)
{
- bt_uuid_t iwin_uuid, refresh_uuid;
+ struct gatt_db_attribute *attrib;

- if (!scan || scan->attrib || !scan->primary)
+ if (!scan || scan->client || !scan->service_handle)
return false;

- scan->attrib = g_attrib_ref(attrib);
+ scan->client = bt_gatt_client_ref(client);
+ scan->db = gatt_db_ref(bt_gatt_client_get_db(client));
+ attrib = gatt_db_get_attribute(scan->db, scan->service_handle);

if (scan->iwhandle)
- write_scan_params(scan->attrib, scan->iwhandle, scan->interval,
+ write_scan_params(scan->client, scan->iwhandle, scan->interval,
scan->window);
- else {
- bt_uuid16_create(&iwin_uuid, SCAN_INTERVAL_WIN_UUID);
- gatt_discover_char(scan->attrib, scan->primary->range.start,
- scan->primary->range.end, &iwin_uuid,
- iwin_discovered_cb, scan);
- }
-
- if (scan->refresh_handle)
- scan->refresh_cb_id = g_attrib_register(scan->attrib,
- ATT_OP_HANDLE_NOTIFY, scan->refresh_handle,
- refresh_value_cb, scan, NULL);
- else {
- bt_uuid16_create(&refresh_uuid, SCAN_REFRESH_UUID);
- gatt_discover_char(scan->attrib, scan->primary->range.start,
- scan->primary->range.end, &refresh_uuid,
- refresh_discovered_cb, scan);
- }
+ else
+ gatt_db_service_foreach_char(attrib, iwin_discovered_cb, scan);
+
+ if (scan->refresh_handle) {
+ uint32_t id = bt_gatt_client_register_notify(scan->client,
+ scan->refresh_handle, ccc_written_cb,
+ refresh_value_cb, scan, NULL);
+ scan->refresh_cb_id = id;
+ } else
+ gatt_db_service_foreach_char(attrib, refresh_discovered_cb,
+ scan);

return true;
}

void bt_scpp_detach(struct bt_scpp *scan)
{
- if (!scan || !scan->attrib)
+ if (!scan || !scan->client)
return;

if (scan->refresh_cb_id > 0) {
- g_attrib_unregister(scan->attrib, scan->refresh_cb_id);
+ bt_gatt_client_unregister_notify(scan->client,
+ scan->refresh_cb_id);
scan->refresh_cb_id = 0;
}

- g_attrib_unref(scan->attrib);
- scan->attrib = NULL;
+ gatt_db_unref(scan->db);
+ scan->db = NULL;
+ bt_gatt_client_unref(scan->client);
+ scan->client = NULL;
}

bool bt_scpp_set_interval(struct bt_scpp *scan, uint16_t value)
diff --git a/android/scpp.h b/android/scpp.h
index 048fb9f..65e54c1 100644
--- a/android/scpp.h
+++ b/android/scpp.h
@@ -23,12 +23,12 @@

struct bt_scpp;

-struct bt_scpp *bt_scpp_new(void *primary);
+struct bt_scpp *bt_scpp_new(uint16_t service_handle);

struct bt_scpp *bt_scpp_ref(struct bt_scpp *scan);
void bt_scpp_unref(struct bt_scpp *scan);

-bool bt_scpp_attach(struct bt_scpp *scan, void *gatt);
+bool bt_scpp_attach(struct bt_scpp *scan, struct bt_gatt_client *client);
void bt_scpp_detach(struct bt_scpp *scan);

bool bt_scpp_set_interval(struct bt_scpp *scan, uint16_t value);
--
1.9.1


2015-04-03 13:43:38

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 09/27] android/hog: Use gatt_db to search for services and characteristics in db

With this patch services and characteristics are searched in previously
cached database. This required changes in declarations of callbacks.
char_discovered_cb has been rebuilt to be called everytime when some
characteristic is found. Method of discovering report and external
report has been also simplified.

Moreover this patch:

1. Separates callbacks for services discovery:
services_cb: Services which already use database cached by bt_gatt_client
primary_cb: for attrib

2. Instead of using gatt_primary to create new instance of service
service handle will be used. On attach, having service handle we can call
gatt_db_get_attribute.
---
android/hidhost.c | 2 +-
android/hog.c | 300 ++++++++++++++++++++++--------------------------------
android/hog.h | 4 +-
unit/test-hog.c | 2 +-
4 files changed, 126 insertions(+), 182 deletions(-)

diff --git a/android/hidhost.c b/android/hidhost.c
index 00b6efa..0f28120 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -862,7 +862,7 @@ static void hog_conn_cb(const bdaddr_t *addr, int err, void *attrib)
if (!dev->hog) {
/* TODO: Get device details */
dev->hog = bt_hog_new_default("bluez-input-device", dev->vendor,
- dev->product, dev->version, NULL, 0);
+ dev->product, dev->version, 0);
if (!dev->hog) {
error("HoG: unable to create session");
goto fail;
diff --git a/android/hog.c b/android/hog.c
index 5aceecd..8570cab 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -86,7 +86,6 @@ struct bt_hog {
uint16_t vendor;
uint16_t product;
uint16_t version;
- struct gatt_primary *primary;
GAttrib *attrib;
GSList *reports;
struct bt_uhid *uhid;
@@ -106,6 +105,7 @@ struct bt_hog {
struct queue *bas;
GSList *instances;
struct bt_gatt_client *client;
+ struct gatt_db *db;
};

struct report {
@@ -196,71 +196,35 @@ static void external_report_reference_cb(bool success, uint8_t status,
const uint8_t *value, uint16_t length,
void *user_data);

-static void discover_external_cb(uint8_t status, GSList *descs, void *user_data)
+static void discover_external_cb(struct gatt_db_attribute *attrib,
+ void *user_data)
{
struct bt_hog *hog = user_data;
+ bt_uuid_t ext_rep_uuid;
+ const bt_uuid_t *uuid = gatt_db_attribute_get_type(attrib);
+ uint16_t handle = gatt_db_attribute_get_handle(attrib);

- if (status != 0) {
- error("Discover external descriptors failed: %s",
- att_ecode2str(status));
- return;
- }
-
- for ( ; descs; descs = descs->next) {
- struct gatt_desc *desc = descs->data;
+ bt_uuid16_create(&ext_rep_uuid, GATT_EXTERNAL_REPORT_REFERENCE);

- bt_gatt_client_read_value(hog->client, desc->handle,
+ if (!bt_uuid_cmp(&ext_rep_uuid, uuid))
+ bt_gatt_client_read_value(hog->client, handle,
external_report_reference_cb, hog, NULL);
- }
-}
-
-static void discover_external(struct bt_hog *hog, GAttrib *attrib,
- uint16_t start, uint16_t end,
- gpointer user_data)
-{
- bt_uuid_t uuid;
-
- if (start > end)
- return;
-
- bt_uuid16_create(&uuid, GATT_EXTERNAL_REPORT_REFERENCE);
-
- gatt_discover_desc(attrib, start, end, NULL, discover_external_cb,
- user_data);
}

-static void discover_report_cb(uint8_t status, GSList *descs, void *user_data)
+static void discover_report_cb(struct gatt_db_attribute *attrib,
+ void *user_data)
{
struct report *report = user_data;
struct bt_hog *hog = report->hog;
+ bt_uuid_t rep_ref_uuid;
+ const bt_uuid_t *uuid = gatt_db_attribute_get_type(attrib);
+ uint16_t handle = gatt_db_attribute_get_handle(attrib);

- if (status != 0) {
- error("Discover report descriptors failed: %s",
- att_ecode2str(status));
- return;
- }
+ bt_uuid16_create(&rep_ref_uuid, GATT_REPORT_REFERENCE);

- for ( ; descs; descs = descs->next) {
- struct gatt_desc *desc = descs->data;
-
- switch (desc->uuid16) {
- case GATT_REPORT_REFERENCE:
- bt_gatt_client_read_value(hog->client, desc->handle,
+ if (!bt_uuid_cmp(&rep_ref_uuid, uuid))
+ bt_gatt_client_read_value(hog->client, handle,
report_reference_cb, report, NULL);
- break;
- }
- }
-}
-
-static void discover_report(struct bt_hog *hog, GAttrib *attrib,
- uint16_t start, uint16_t end,
- gpointer user_data)
-{
- if (start > end)
- return;
-
- gatt_discover_desc(attrib, start, end, NULL, discover_report_cb,
- user_data);
}

static void report_read_cb(bool success, uint8_t att_ecode,
@@ -282,50 +246,37 @@ static void report_read_cb(bool success, uint8_t att_ecode,
report->len = len;
}

-static struct report *report_new(struct bt_hog *hog, struct gatt_char *chr)
+static struct report *report_new(struct bt_hog *hog, uint16_t value_handle,
+ uint8_t properties)
{
struct report *report;

report = g_new0(struct report, 1);
report->hog = hog;
- report->decl = g_memdup(chr, sizeof(*chr));
+ report->decl = new0(struct gatt_char, 1);
+ report->decl->value_handle = value_handle;
+ report->decl->properties = properties;
hog->reports = g_slist_append(hog->reports, report);

- bt_gatt_client_read_value(hog->client, chr->value_handle,
+ bt_gatt_client_read_value(hog->client, value_handle,
report_read_cb, report, NULL);

return report;
}

-static void external_service_char_cb(uint8_t status, GSList *chars,
- void *user_data)
+static void external_service_char_cb(void *data, void *user_data)
{
struct bt_hog *hog = user_data;
- struct gatt_primary *primary = hog->primary;
+ struct gatt_db_attribute *attrib = data;
struct report *report;
- GSList *l;
+ uint16_t value_handle;
+ uint8_t properties;

- if (status != 0) {
- const char *str = att_ecode2str(status);
- DBG("Discover external service characteristic failed: %s", str);
- return;
- }
-
- for (l = chars; l; l = g_slist_next(l)) {
- struct gatt_char *chr, *next;
- uint16_t start, end;
-
- chr = l->data;
- next = l->next ? l->next->data : NULL;
-
- DBG("0x%04x UUID: %s properties: %02x",
- chr->handle, chr->uuid, chr->properties);
+ gatt_db_attribute_get_char_data(attrib, NULL, &value_handle,
+ &properties, NULL);

- report = report_new(hog, chr);
- start = chr->value_handle + 1;
- end = (next ? next->handle - 1 : primary->range.end);
- discover_report(hog, hog->attrib, start, end, report);
- }
+ report = report_new(hog, value_handle, properties);
+ gatt_db_service_foreach_desc(attrib, discover_report_cb, report);
}

static void external_report_reference_cb(bool success, uint8_t status,
@@ -335,6 +286,7 @@ static void external_report_reference_cb(bool success, uint8_t status,
struct bt_hog *hog = user_data;
uint16_t uuid16;
bt_uuid_t uuid;
+ struct queue *chrs;

if (!success) {
error("Read External Report Reference descriptor failed: %s",
@@ -355,9 +307,20 @@ static void external_report_reference_cb(bool success, uint8_t status,
if (uuid16 != HOG_REPORT_UUID)
return;

+ chrs = queue_new();
+ if (!chrs) {
+ error("Insufficient resources");
+ return;
+ }
+
bt_uuid16_create(&uuid, uuid16);
- gatt_discover_char(hog->attrib, 0x0001, 0xffff, &uuid,
- external_service_char_cb, hog);
+ gatt_db_read_by_type(hog->db, 0x0001, 0xffff, uuid, chrs);
+
+ if (queue_isempty(chrs))
+ return;
+
+ queue_foreach(chrs, external_service_char_cb, hog);
+ queue_destroy(chrs, NULL);
}

static int report_cmp(gconstpointer a, gconstpointer b)
@@ -824,21 +787,15 @@ static void proto_mode_read_cb(bool success, uint8_t att_ecode,
DBG("HoG is operating in Report Protocol Mode");
}

-static void char_discovered_cb(uint8_t status, GSList *chars, void *user_data)
+static void char_discovered_cb(struct gatt_db_attribute *attrib,
+ void *user_data)
{
struct bt_hog *hog = user_data;
- struct gatt_primary *primary = hog->primary;
- bt_uuid_t report_uuid, report_map_uuid, info_uuid;
- bt_uuid_t proto_mode_uuid, ctrlpt_uuid;
+ bt_uuid_t report_uuid, report_map_uuid, proto_mode_uuid, ctrlpt_uuid;
+ bt_uuid_t info_uuid, uuid;
struct report *report;
- GSList *l;
- uint16_t info_handle = 0, proto_mode_handle = 0;
-
- if (status != 0) {
- const char *str = att_ecode2str(status);
- DBG("Discover all characteristics failed: %s", str);
- return;
- }
+ uint16_t value_handle;
+ uint8_t properties;

bt_uuid16_create(&report_uuid, HOG_REPORT_UUID);
bt_uuid16_create(&report_map_uuid, HOG_REPORT_MAP_UUID);
@@ -846,47 +803,27 @@ static void char_discovered_cb(uint8_t status, GSList *chars, void *user_data)
bt_uuid16_create(&proto_mode_uuid, HOG_PROTO_MODE_UUID);
bt_uuid16_create(&ctrlpt_uuid, HOG_CONTROL_POINT_UUID);

- for (l = chars; l; l = g_slist_next(l)) {
- struct gatt_char *chr, *next;
- bt_uuid_t uuid;
- uint16_t start, end;
-
- chr = l->data;
- next = l->next ? l->next->data : NULL;
-
- DBG("0x%04x UUID: %s properties: %02x",
- chr->handle, chr->uuid, chr->properties);
-
- bt_string_to_uuid(&uuid, chr->uuid);
-
- start = chr->value_handle + 1;
- end = (next ? next->handle - 1 : primary->range.end);
-
- if (bt_uuid_cmp(&uuid, &report_uuid) == 0) {
- report = report_new(hog, chr);
- discover_report(hog, hog->attrib, start, end, report);
- } else if (bt_uuid_cmp(&uuid, &report_map_uuid) == 0) {
- bt_gatt_client_read_long_value(hog->client,
- chr->value_handle, 0, report_map_read_cb,
- hog, NULL);
- discover_external(hog, hog->attrib, start, end, hog);
- } else if (bt_uuid_cmp(&uuid, &info_uuid) == 0)
- info_handle = chr->value_handle;
- else if (bt_uuid_cmp(&uuid, &proto_mode_uuid) == 0)
- proto_mode_handle = chr->value_handle;
- else if (bt_uuid_cmp(&uuid, &ctrlpt_uuid) == 0)
- hog->ctrlpt_handle = chr->value_handle;
- }
-
- if (proto_mode_handle) {
- hog->proto_mode_handle = proto_mode_handle;
- bt_gatt_client_read_value(hog->client, proto_mode_handle,
+ gatt_db_attribute_get_char_data(attrib, NULL, &value_handle,
+ &properties, &uuid);
+
+ if (!bt_uuid_cmp(&uuid, &report_uuid)) {
+ report = report_new(hog, value_handle, properties);
+ gatt_db_service_foreach_desc(attrib, discover_report_cb,
+ report);
+ } else if (!bt_uuid_cmp(&uuid, &report_map_uuid)) {
+ bt_gatt_client_read_long_value(hog->client, value_handle, 0,
+ report_map_read_cb, hog, NULL);
+ gatt_db_service_foreach_desc(attrib, discover_external_cb, hog);
+ } else if (!bt_uuid_cmp(&uuid, &info_uuid)) {
+ bt_gatt_client_read_value(hog->client, value_handle,
+ info_read_cb, hog, NULL);
+ } else if (!bt_uuid_cmp(&uuid, &proto_mode_uuid)) {
+ hog->proto_mode_handle = value_handle;
+ bt_gatt_client_read_value(hog->client, value_handle,
proto_mode_read_cb, hog, NULL);
+ } else if (!bt_uuid_cmp(&uuid, &ctrlpt_uuid)) {
+ hog->ctrlpt_handle = value_handle;
}
-
- if (info_handle)
- bt_gatt_client_read_value(hog->client, info_handle,
- info_read_cb, hog, NULL);
}

static void report_free(void *data)
@@ -894,7 +831,7 @@ static void report_free(void *data)
struct report *report = data;

g_free(report->value);
- g_free(report->decl);
+ free(report->decl);
g_free(report);
}

@@ -912,21 +849,19 @@ static void hog_free(void *data)
bt_uhid_unref(hog->uhid);
g_slist_free_full(hog->reports, report_free);
g_free(hog->name);
- g_free(hog->primary);
g_free(hog);
}

struct bt_hog *bt_hog_new_default(const char *name, uint16_t vendor,
uint16_t product, uint16_t version,
- void *primary, uint16_t service_handle)
+ uint16_t service_handle)
{
- return bt_hog_new(-1, name, vendor, product, version, primary,
- service_handle);
+ return bt_hog_new(-1, name, vendor, product, version, service_handle);
}

struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
uint16_t product, uint16_t version,
- void *primary, uint16_t service_handle)
+ uint16_t service_handle)
{
struct bt_hog *hog;

@@ -953,9 +888,6 @@ struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
hog->product = product;
hog->version = version;

- if (primary)
- hog->primary = g_memdup(primary, sizeof(*hog->primary));
-
if (service_handle)
hog->service_handle = service_handle;

@@ -983,24 +915,13 @@ void bt_hog_unref(struct bt_hog *hog)
hog_free(hog);
}

-static void find_included_cb(uint8_t status, GSList *services, void *user_data)
+static void find_included_cb(struct gatt_db_attribute *attrib, void *user_data)
{
- GSList *l;
-
- DBG("");
-
- if (status) {
- const char *str = att_ecode2str(status);
- DBG("Find included failed: %s", str);
- return;
- }
+ uint16_t start_handle;

- for (l = services; l; l = l->next) {
- struct gatt_included *include = l->data;
+ gatt_db_attribute_get_incl_data(attrib, NULL, &start_handle, NULL);

- DBG("included: handle %x, uuid %s",
- include->handle, include->uuid);
- }
+ DBG("included: handle %x", start_handle);
}

static void hog_attach_scpp(struct bt_hog *hog, struct gatt_primary *primary)
@@ -1051,28 +972,25 @@ static void hog_attach_bas(struct bt_hog *hog, struct gatt_primary *primary)
queue_push_head(hog->bas, instance);
}

-static void hog_attach_hog(struct bt_hog *hog, struct gatt_primary *primary)
+static void hog_attach_hog(struct bt_hog *hog, uint16_t service_handle)
{
struct bt_hog *instance;
+ struct gatt_db_attribute *attrib;
+
+ attrib = gatt_db_get_attribute(hog->db, service_handle);

- if (!hog->primary) {
- hog->primary = g_memdup(primary, sizeof(*primary));
- gatt_discover_char(hog->attrib, primary->range.start,
- primary->range.end, NULL,
- char_discovered_cb, hog);
- gatt_find_included(hog->attrib, primary->range.start,
- primary->range.end, find_included_cb, hog);
+ if (!hog->service_handle) {
+ hog->service_handle = service_handle;
+ gatt_db_service_foreach_char(attrib, char_discovered_cb, hog);
+ gatt_db_service_foreach_incl(attrib, find_included_cb, hog);
return;
}

instance = bt_hog_new(hog->uhid_fd, hog->name, hog->vendor,
- hog->product, hog->version, primary, 0);
+ hog->product, hog->version, service_handle);
if (!instance)
return;

- gatt_find_included(hog->attrib, primary->range.start,
- primary->range.end, find_included_cb, instance);
-
bt_hog_attach(instance, hog->attrib, hog->client);
hog->instances = g_slist_append(hog->instances, instance);
}
@@ -1111,17 +1029,38 @@ static void primary_cb(uint8_t status, GSList *services, void *user_data)

if (strcmp(primary->uuid, BATTERY_UUID) == 0) {
hog_attach_bas(hog, primary);
- continue;
}
-
- if (strcmp(primary->uuid, HOG_UUID) == 0)
- hog_attach_hog(hog, primary);
}
}

+static void service_cb(struct gatt_db_attribute *attrib, void *user_data)
+{
+ struct bt_hog *hog = user_data;
+ bt_uuid_t service_uuid;
+ char uuid[MAX_LEN_UUID_STR + 1];
+ uint16_t service_handle;
+
+ if (!gatt_db_attribute_get_service_data(attrib, &service_handle,
+ NULL, NULL, &service_uuid))
+ return;
+
+ bt_uuid_to_string(&service_uuid, uuid, sizeof(uuid));
+
+ if (!bt_uuid_strcmp(uuid, HOG_UUID))
+ hog_attach_hog(hog, service_handle);
+ else if (!bt_uuid_strcmp(uuid, SCAN_PARAMETERS_UUID))
+ /* TODO */
+ return;
+ else if (!bt_uuid_strcmp(uuid, DEVICE_INFORMATION_UUID))
+ /* TODO */
+ return;
+ else if (!bt_uuid_strcmp(uuid, BATTERY_UUID))
+ /* TODO */
+ return;
+}
+
bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)
{
- struct gatt_primary *primary = hog->primary;
GSList *l;

if (hog->attrib || hog->client)
@@ -1129,8 +1068,10 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)

hog->attrib = g_attrib_ref(gatt);
hog->client = bt_gatt_client_ref(client);
+ hog->db = gatt_db_ref(bt_gatt_client_get_db(hog->client));

- if (!primary) {
+ if (!hog->service_handle) {
+ gatt_db_foreach_service(hog->db, NULL, service_cb, hog);
gatt_discover_primary(hog->attrib, NULL, primary_cb, hog);
return true;
}
@@ -1150,9 +1091,11 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)
}

if (hog->reports == NULL) {
- gatt_discover_char(hog->attrib, primary->range.start,
- primary->range.end, NULL,
- char_discovered_cb, hog);
+ struct gatt_db_attribute *service;
+
+ service = gatt_db_get_attribute(hog->db, hog->service_handle);
+ gatt_db_service_foreach_char(service, char_discovered_cb, hog);
+ gatt_db_service_foreach_incl(service, find_included_cb, hog);
return true;
}

@@ -1199,6 +1142,7 @@ void bt_hog_detach(struct bt_hog *hog)
if (hog->dis)
bt_dis_detach(hog->dis);

+ gatt_db_unref(hog->db);
bt_gatt_client_unref(hog->client);
hog->client = NULL;
g_attrib_unref(hog->attrib);
diff --git a/android/hog.h b/android/hog.h
index 61d756c..cfe6873 100644
--- a/android/hog.h
+++ b/android/hog.h
@@ -25,11 +25,11 @@ struct bt_hog;

struct bt_hog *bt_hog_new_default(const char *name, uint16_t vendor,
uint16_t product, uint16_t version,
- void *primary, uint16_t service_handle);
+ uint16_t service_handle);

struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
uint16_t product, uint16_t version,
- void *primary, uint16_t service_handle);
+ uint16_t service_handle);

struct bt_hog *bt_hog_ref(struct bt_hog *hog);
void bt_hog_unref(struct bt_hog *hog);
diff --git a/unit/test-hog.c b/unit/test-hog.c
index c7c64e4..5794c5e 100644
--- a/unit/test-hog.c
+++ b/unit/test-hog.c
@@ -196,7 +196,7 @@ static struct context *create_context(gconstpointer data)
fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
g_assert(fd > 0);

- context->hog = bt_hog_new(fd, name, vendor, product, version, NULL, 0);
+ context->hog = bt_hog_new(fd, name, vendor, product, version, 0);
g_assert(context->hog);

channel = g_io_channel_unix_new(sv[1]);
--
1.9.1


2015-04-03 13:43:40

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 11/27] lib/uuid: Add define for HoG UUID

From: Mariusz Skamra <[email protected]>

This patch moves the HOG_UUID define to lib/uuid.
---
android/hidhost.c | 2 --
android/hog.c | 2 --
lib/uuid.h | 1 +
3 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/android/hidhost.c b/android/hidhost.c
index 0f28120..e1392f6 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -90,8 +90,6 @@
/* HID Virtual Cable Unplug */
#define HID_VIRTUAL_CABLE_UNPLUG 0x05

-#define HOG_UUID "00001812-0000-1000-8000-00805f9b34fb"
-
static bdaddr_t adapter_addr;

static GIOChannel *ctrl_io = NULL;
diff --git a/android/hog.c b/android/hog.c
index 4dcba4d..fda7a88 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -61,8 +61,6 @@
#include "android/bas.h"
#include "android/hog.h"

-#define HOG_UUID "00001812-0000-1000-8000-00805f9b34fb"
-
#define HOG_INFO_UUID 0x2A4A
#define HOG_REPORT_MAP_UUID 0x2A4B
#define HOG_REPORT_UUID 0x2A4D
diff --git a/lib/uuid.h b/lib/uuid.h
index 2dcfe9e..fd67ebb 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -88,6 +88,7 @@ extern "C" {
#define HDP_SINK_UUID "00001402-0000-1000-8000-00805f9b34fb"

#define HID_UUID "00001124-0000-1000-8000-00805f9b34fb"
+#define HOG_UUID "00001812-0000-1000-8000-00805f9b34fb"

#define DUN_GW_UUID "00001103-0000-1000-8000-00805f9b34fb"

--
1.9.1


2015-04-03 13:43:44

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 15/27] android/dis: Introduce bt_gatt_client

This patch replaces gattrib with bt_gatt_client and strips glib dependencies.
---
android/dis.c | 104 ++++++++++++++++++++++------------------------------------
android/dis.h | 4 +--
android/hog.c | 18 ++++------
3 files changed, 48 insertions(+), 78 deletions(-)

diff --git a/android/dis.c b/android/dis.c
index f699046..0d9d7d3 100644
--- a/android/dis.c
+++ b/android/dis.c
@@ -27,61 +27,52 @@
#include <stdbool.h>
#include <errno.h>

-#include <glib.h>
-
#include "src/log.h"

#include "lib/bluetooth.h"
-#include "lib/sdp.h"
#include "lib/uuid.h"

#include "src/shared/util.h"
#include "src/shared/queue.h"
-
-#include "attrib/gattrib.h"
-#include "attrib/att.h"
-#include "attrib/gatt.h"
+#include "src/shared/att.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-client.h"

#include "android/dis.h"

-#define PNP_ID_SIZE 7
-
struct bt_dis {
int ref_count;
+ uint16_t service_handle;
uint16_t handle;
uint8_t source;
uint16_t vendor;
uint16_t product;
uint16_t version;
- GAttrib *attrib; /* GATT connection */
- struct gatt_primary *primary; /* Primary details */
bt_dis_notify notify;
void *notify_data;
-};
-
-struct characteristic {
- struct gatt_char attr; /* Characteristic */
- struct bt_dis *d; /* deviceinfo where the char belongs */
+ struct bt_gatt_client *client;
+ struct gatt_db *db;
};

static void dis_free(struct bt_dis *dis)
{
bt_dis_detach(dis);

- g_free(dis->primary);
- g_free(dis);
+ free(dis);
}

-struct bt_dis *bt_dis_new(void *primary)
+struct bt_dis *bt_dis_new(uint16_t service_handle)
{
struct bt_dis *dis;

- dis = g_try_new0(struct bt_dis, 1);
+ if (!service_handle)
+ return NULL;
+
+ dis = new0(struct bt_dis, 1);
if (!dis)
return NULL;

- if (primary)
- dis->primary = g_memdup(primary, sizeof(*dis->primary));
+ dis->service_handle = service_handle;

return bt_dis_ref(dis);
}
@@ -107,26 +98,13 @@ void bt_dis_unref(struct bt_dis *dis)
dis_free(dis);
}

-static void read_pnpid_cb(guint8 status, const guint8 *pdu, guint16 len,
- gpointer user_data)
+static void read_pnpid_cb(bool success, uint8_t att_ecode, const uint8_t *value,
+ uint16_t length, void *user_data)
{
struct bt_dis *dis = user_data;
- uint8_t value[PNP_ID_SIZE];
- ssize_t vlen;
-
- if (status != 0) {
- error("Error reading PNP_ID value: %s", att_ecode2str(status));
- return;
- }
-
- vlen = dec_read_resp(pdu, len, value, sizeof(value));
- if (vlen < 0) {
- error("Error reading PNP_ID: Protocol error");
- return;
- }

- if (vlen < 7) {
- error("Error reading PNP_ID: Invalid pdu length received");
+ if (length < 7) {
+ error("Error reading PNP_ID: Invalid length received");
return;
}

@@ -143,53 +121,51 @@ static void read_pnpid_cb(guint8 status, const guint8 *pdu, guint16 len,
dis->version, dis->notify_data);
}

-static void configure_deviceinfo_cb(uint8_t status, GSList *characteristics,
+static void configure_deviceinfo_cb(struct gatt_db_attribute *attrib,
void *user_data)
{
- struct bt_dis *d = user_data;
- GSList *l;
+ struct bt_dis *dis = user_data;
+ bt_uuid_t uuid, pnpid_uuid;
+ uint16_t value_handle;

- if (status != 0) {
- error("Discover deviceinfo characteristics: %s",
- att_ecode2str(status));
- return;
- }
+ gatt_db_attribute_get_char_data(attrib, NULL, &value_handle,
+ NULL, &uuid);

- for (l = characteristics; l; l = l->next) {
- struct gatt_char *c = l->data;
+ bt_string_to_uuid(&pnpid_uuid, PNPID_UUID);

- if (strcmp(c->uuid, PNPID_UUID) == 0) {
- d->handle = c->value_handle;
- gatt_read_char(d->attrib, d->handle, read_pnpid_cb, d);
- break;
- }
+ if (!bt_uuid_cmp(&uuid, &pnpid_uuid)) {
+ dis->handle = value_handle;
+ bt_gatt_client_read_value(dis->client, value_handle,
+ read_pnpid_cb, dis, NULL);
}
}

-bool bt_dis_attach(struct bt_dis *dis, void *attrib)
+bool bt_dis_attach(struct bt_dis *dis, struct bt_gatt_client *client)
{
- struct gatt_primary *primary = dis->primary;
+ struct gatt_db_attribute *attrib;

- if (dis->attrib || !primary)
+ if (!dis || dis->client || !dis->service_handle)
return false;

- dis->attrib = g_attrib_ref(attrib);
+ dis->client = bt_gatt_client_ref(client);
+ dis->db = gatt_db_ref(bt_gatt_client_get_db(client));
+ attrib = gatt_db_get_attribute(dis->db, dis->service_handle);

if (!dis->handle)
- gatt_discover_char(dis->attrib, primary->range.start,
- primary->range.end, NULL,
- configure_deviceinfo_cb, dis);
+ gatt_db_service_foreach_char(attrib, configure_deviceinfo_cb,
+ dis);

return true;
}

void bt_dis_detach(struct bt_dis *dis)
{
- if (!dis->attrib)
+ if (!dis->client)
return;

- g_attrib_unref(dis->attrib);
- dis->attrib = NULL;
+ gatt_db_unref(dis->db);
+ bt_gatt_client_unref(dis->client);
+ dis->client = NULL;
}

bool bt_dis_set_notification(struct bt_dis *dis, bt_dis_notify func,
diff --git a/android/dis.h b/android/dis.h
index faf27b3..55c6625 100644
--- a/android/dis.h
+++ b/android/dis.h
@@ -23,12 +23,12 @@

struct bt_dis;

-struct bt_dis *bt_dis_new(void *primary);
+struct bt_dis *bt_dis_new(uint16_t service_handle);

struct bt_dis *bt_dis_ref(struct bt_dis *dis);
void bt_dis_unref(struct bt_dis *dis);

-bool bt_dis_attach(struct bt_dis *dis, void *gatt);
+bool bt_dis_attach(struct bt_dis *dis, struct bt_gatt_client *client);
void bt_dis_detach(struct bt_dis *dis);

typedef void (*bt_dis_notify) (uint8_t source, uint16_t vendor,
diff --git a/android/hog.c b/android/hog.c
index 6bec2aa..091a9a5 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -981,17 +981,17 @@ static void dis_notify(uint8_t source, uint16_t vendor, uint16_t product,
hog->version = version;
}

-static void hog_attach_dis(struct bt_hog *hog, struct gatt_primary *primary)
+static void hog_attach_dis(struct bt_hog *hog, uint16_t service_handle)
{
if (hog->dis) {
- bt_dis_attach(hog->dis, hog->attrib);
+ bt_dis_attach(hog->dis, hog->client);
return;
}

- hog->dis = bt_dis_new(primary);
+ hog->dis = bt_dis_new(service_handle);
if (hog->dis) {
bt_dis_set_notification(hog->dis, dis_notify, hog);
- bt_dis_attach(hog->dis, hog->attrib);
+ bt_dis_attach(hog->dis, hog->client);
}
}

@@ -1057,11 +1057,6 @@ static void primary_cb(uint8_t status, GSList *services, void *user_data)
continue;
}

- if (strcmp(primary->uuid, DEVICE_INFORMATION_UUID) == 0) {
- hog_attach_dis(hog, primary);
- continue;
- }
-
if (strcmp(primary->uuid, BATTERY_UUID) == 0) {
hog_attach_bas(hog, primary);
}
@@ -1087,8 +1082,7 @@ static void service_cb(struct gatt_db_attribute *attrib, void *user_data)
/* TODO */
return;
else if (!bt_uuid_strcmp(uuid, DEVICE_INFORMATION_UUID))
- /* TODO */
- return;
+ hog_attach_dis(hog, service_handle);
else if (!bt_uuid_strcmp(uuid, BATTERY_UUID))
/* TODO */
return;
@@ -1115,7 +1109,7 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)
bt_scpp_attach(hog->scpp, gatt);

if (hog->dis)
- bt_dis_attach(hog->dis, gatt);
+ bt_dis_attach(hog->dis, hog->client);

queue_foreach(hog->bas, (void *) bt_bas_attach, gatt);

--
1.9.1


2015-04-03 13:43:32

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 03/27] shared/gatt-client: Expose gatt_db

This patch adds the bt_gatt_client_get_db function, which allows
to get a reference to db from client structure. This is useful
when as a client we need to have an access db, to explore some
attributes.
---
src/shared/gatt-client.c | 8 ++++++++
src/shared/gatt-client.h | 1 +
2 files changed, 9 insertions(+)

diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 729bd87..f006ae6 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -1760,6 +1760,14 @@ uint16_t bt_gatt_client_get_mtu(struct bt_gatt_client *client)
return bt_att_get_mtu(client->att);
}

+struct gatt_db *bt_gatt_client_get_db(struct bt_gatt_client *client)
+{
+ if (!client || !client->db)
+ return NULL;
+
+ return client->db;
+}
+
static bool match_req_id(const void *a, const void *b)
{
const struct request *req = a;
diff --git a/src/shared/gatt-client.h b/src/shared/gatt-client.h
index 8e5e0f5..f539a61 100644
--- a/src/shared/gatt-client.h
+++ b/src/shared/gatt-client.h
@@ -70,6 +70,7 @@ bool bt_gatt_client_set_debug(struct bt_gatt_client *client,
bt_gatt_client_destroy_func_t destroy);

uint16_t bt_gatt_client_get_mtu(struct bt_gatt_client *client);
+struct gatt_db *bt_gatt_client_get_db(struct bt_gatt_client *client);

bool bt_gatt_client_cancel(struct bt_gatt_client *client, unsigned int id);
bool bt_gatt_client_cancel_all(struct bt_gatt_client *client);
--
1.9.1


2015-04-03 13:43:42

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 13/27] android/hog: Replace GSList of hog instances with queue of instances

Thanks to this patch hog instances can be now stored in queue.
This will help to clean the code from glib dependencies.
---
android/hog.c | 34 +++++++++++++++-------------------
1 file changed, 15 insertions(+), 19 deletions(-)

diff --git a/android/hog.c b/android/hog.c
index 9b76357..6bec2aa 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -101,7 +101,7 @@ struct bt_hog {
struct bt_scpp *scpp;
struct bt_dis *dis;
struct queue *bas;
- GSList *instances;
+ struct queue *instances;
struct bt_gatt_client *client;
struct gatt_db *db;
};
@@ -875,7 +875,7 @@ static void hog_free(void *data)
bt_hog_detach(hog);

queue_destroy(hog->bas, (void *) bt_bas_unref);
- g_slist_free_full(hog->instances, hog_free);
+ queue_destroy(hog->instances, hog_free);

bt_scpp_unref(hog->scpp);
bt_dis_unref(hog->dis);
@@ -904,6 +904,7 @@ struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,

hog->bas = queue_new();
hog->reports = queue_new();
+ hog->instances = queue_new();

if (fd < 0)
hog->uhid = bt_uhid_new_default();
@@ -912,7 +913,7 @@ struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,

hog->uhid_fd = fd;

- if (!hog->bas || !hog->uhid || !hog->reports) {
+ if (!hog->bas || !hog->uhid || !hog->reports || !hog->instances) {
hog_free(hog);
return NULL;
}
@@ -1026,7 +1027,7 @@ static void hog_attach_hog(struct bt_hog *hog, uint16_t service_handle)
return;

bt_hog_attach(instance, hog->attrib, hog->client);
- hog->instances = g_slist_append(hog->instances, instance);
+ queue_push_tail(hog->instances, instance);
}

static void primary_cb(uint8_t status, GSList *services, void *user_data)
@@ -1095,7 +1096,7 @@ static void service_cb(struct gatt_db_attribute *attrib, void *user_data)

bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)
{
- GSList *l;
+ const struct queue_entry *hog_entry;

if (hog->attrib || hog->client)
return false;
@@ -1118,8 +1119,9 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)

queue_foreach(hog->bas, (void *) bt_bas_attach, gatt);

- for (l = hog->instances; l; l = l->next) {
- struct bt_hog *instance = l->data;
+ hog_entry = queue_get_entries(hog->instances);
+ while (hog_entry) {
+ struct bt_hog *instance = hog_entry->data;

bt_hog_attach(instance, gatt, client);
}
@@ -1140,19 +1142,11 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)

void bt_hog_detach(struct bt_hog *hog)
{
- GSList *l;
-
if (!hog->attrib || !hog->client)
return;

queue_foreach(hog->bas, (void *) bt_bas_detach, NULL);
-
- for (l = hog->instances; l; l = l->next) {
- struct bt_hog *instance = l->data;
-
- bt_hog_detach(instance);
- }
-
+ queue_foreach(hog->instances, (void *) bt_hog_detach, NULL);
queue_foreach(hog->reports, report_disable_notif, NULL);

if (hog->scpp)
@@ -1187,7 +1181,7 @@ int bt_hog_set_control_point(struct bt_hog *hog, bool suspend)
int bt_hog_send_report(struct bt_hog *hog, void *data, size_t size, int type)
{
struct report *report;
- GSList *l;
+ const struct queue_entry *hog_entry;

if (!hog)
return -EINVAL;
@@ -1212,10 +1206,12 @@ int bt_hog_send_report(struct bt_hog *hog, void *data, size_t size, int type)
report->decl->value_handle,
false, data, size);

- for (l = hog->instances; l; l = l->next) {
- struct bt_hog *instance = l->data;
+ hog_entry = queue_get_entries(hog->instances);
+ while (hog_entry) {
+ struct bt_hog *instance = hog_entry->data;

bt_hog_send_report(instance, data, size, type);
+ hog_entry = hog_entry->next;
}

return 0;
--
1.9.1


2015-04-03 13:43:41

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 12/27] android/hog: Replace list of reports with a queue of reports

From: Mariusz Skamra <[email protected]>

Thanks to this patch reports can be now stored in queue. This will help
to clean the code from glib dependencies.
Two helpers for enable/disable notification have been added to be used with
queue_foreach.
---
android/hog.c | 79 +++++++++++++++++++++++++++++++++--------------------------
1 file changed, 44 insertions(+), 35 deletions(-)

diff --git a/android/hog.c b/android/hog.c
index fda7a88..9b76357 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -85,7 +85,7 @@ struct bt_hog {
uint16_t product;
uint16_t version;
GAttrib *attrib;
- GSList *reports;
+ struct queue *reports;
struct bt_uhid *uhid;
int uhid_fd;
gboolean has_report_id;
@@ -160,12 +160,35 @@ static void report_ccc_written_cb(uint16_t status, void *user_data)
DBG("Report characteristic descriptor written: notifications enabled");
}

+static void report_enable_notif(void *data, void *user_data)
+{
+ struct report *report = data;
+ struct bt_gatt_client *client = report->hog->client;
+
+ /* Enable notifications only for Input Reports */
+ if (report->type == HOG_REPORT_TYPE_INPUT)
+ report->notifyid = bt_gatt_client_register_notify(client,
+ report->decl->value_handle,
+ report_ccc_written_cb,
+ report_value_cb, report, NULL);
+}
+
+static void report_disable_notif(void *data, void *user_data)
+{
+ struct report *report = data;
+ struct bt_gatt_client *client = report->hog->client;
+
+ if (report->notifyid > 0) {
+ bt_gatt_client_unregister_notify(client, report->notifyid);
+ report->notifyid = 0;
+ }
+}
+
static void report_reference_cb(bool success, uint8_t status,
const uint8_t *value, uint16_t length,
void *user_data)
{
struct report *report = user_data;
- struct bt_gatt_client *client = report->hog->client;

if (!success) {
error("Read Report Reference descriptor failed: %s",
@@ -182,12 +205,7 @@ static void report_reference_cb(bool success, uint8_t status,
report->type = value[1];
DBG("Report ID: 0x%02x Report type: 0x%02x", value[0], value[1]);

- /* Enable notifications only for Input Reports */
- if (report->type == HOG_REPORT_TYPE_INPUT)
- report->notifyid = bt_gatt_client_register_notify(client,
- report->decl->value_handle,
- report_ccc_written_cb,
- report_value_cb, report, NULL);
+ report_enable_notif(report, NULL);
}

static void external_report_reference_cb(bool success, uint8_t status,
@@ -254,7 +272,7 @@ static struct report *report_new(struct bt_hog *hog, uint16_t value_handle,
report->decl = new0(struct gatt_char, 1);
report->decl->value_handle = value_handle;
report->decl->properties = properties;
- hog->reports = g_slist_append(hog->reports, report);
+ queue_push_tail(hog->reports, report);

bt_gatt_client_read_value(hog->client, value_handle,
report_read_cb, report, NULL);
@@ -321,10 +339,8 @@ static void external_report_reference_cb(bool success, uint8_t status,
queue_destroy(chrs, NULL);
}

-static int report_cmp(gconstpointer a, gconstpointer b)
+static int report_cmp(const struct report *ra, const struct report *rb)
{
- const struct report *ra = a, *rb = b;
-
/* sort by type first.. */
if (ra->type != rb->type)
return ra->type - rb->type;
@@ -340,14 +356,21 @@ static int report_cmp(gconstpointer a, gconstpointer b)
static struct report *find_report(struct bt_hog *hog, uint8_t type, uint8_t id)
{
struct report cmp;
- GSList *l;
+ const struct queue_entry *report_entry;

cmp.type = type;
cmp.id = hog->has_report_id ? id : 0;

- l = g_slist_find_custom(hog->reports, &cmp, report_cmp);
+ report_entry = queue_get_entries(hog->reports);
+ while (report_entry) {
+ struct report *report = report_entry->data;
+
+ if (!report_cmp(report, &cmp))
+ return report;

- return l ? l->data : NULL;
+ report_entry = report_entry->next;
+ }
+ return NULL;
}

static struct report *find_report_by_rtype(struct bt_hog *hog, uint8_t rtype,
@@ -857,7 +880,7 @@ static void hog_free(void *data)
bt_scpp_unref(hog->scpp);
bt_dis_unref(hog->dis);
bt_uhid_unref(hog->uhid);
- g_slist_free_full(hog->reports, report_free);
+ queue_destroy(hog->reports, report_free);
g_free(hog->name);
g_free(hog);
}
@@ -880,6 +903,7 @@ struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
return NULL;

hog->bas = queue_new();
+ hog->reports = queue_new();

if (fd < 0)
hog->uhid = bt_uhid_new_default();
@@ -888,7 +912,7 @@ struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,

hog->uhid_fd = fd;

- if (!hog->bas || !hog->uhid) {
+ if (!hog->bas || !hog->uhid || !hog->reports) {
hog_free(hog);
return NULL;
}
@@ -1100,7 +1124,7 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)
bt_hog_attach(instance, gatt, client);
}

- if (hog->reports == NULL) {
+ if (queue_isempty(hog->reports)) {
struct gatt_db_attribute *service;

service = gatt_db_get_attribute(hog->db, hog->service_handle);
@@ -1109,14 +1133,7 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)
return true;
}

- for (l = hog->reports; l; l = l->next) {
- struct report *r = l->data;
- if (r->type == HOG_REPORT_TYPE_INPUT)
- r->notifyid = bt_gatt_client_register_notify(client,
- r->decl->value_handle,
- report_ccc_written_cb,
- report_value_cb, r, NULL);
- }
+ queue_foreach(hog->reports, report_enable_notif, NULL);

return true;
}
@@ -1136,15 +1153,7 @@ void bt_hog_detach(struct bt_hog *hog)
bt_hog_detach(instance);
}

- for (l = hog->reports; l; l = l->next) {
- struct report *r = l->data;
-
- if (r->notifyid > 0) {
- bt_gatt_client_unregister_notify(hog->client,
- r->notifyid);
- r->notifyid = 0;
- }
- }
+ queue_foreach(hog->reports, report_disable_notif, NULL);

if (hog->scpp)
bt_scpp_detach(hog->scpp);
--
1.9.1


2015-04-03 13:43:37

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 08/27] android/hog: Replace gatt_write_char with bt_gatt_client_write_value

---
android/hog.c | 38 ++++++++++++++++++++------------------
1 file changed, 20 insertions(+), 18 deletions(-)

diff --git a/android/hog.c b/android/hog.c
index 88f3ca1..5aceecd 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -411,10 +411,9 @@ static struct report *find_report_by_rtype(struct bt_hog *hog, uint8_t rtype,
return find_report(hog, type, id);
}

-static void output_written_cb(guint8 status, const guint8 *pdu,
- guint16 plen, gpointer user_data)
+static void output_written_cb(bool success, uint8_t status, void *user_data)
{
- if (status != 0) {
+ if (!success) {
error("Write output report failed: %s", att_ecode2str(status));
return;
}
@@ -442,12 +441,14 @@ static void forward_report(struct uhid_event *ev, void *user_data)
DBG("Sending report type %d ID %d to handle 0x%X", report->type,
report->id, report->decl->value_handle);

- if (hog->attrib == NULL)
+ if (hog->client == NULL)
return;

if (report->decl->properties & GATT_CHR_PROP_WRITE)
- gatt_write_char(hog->attrib, report->decl->value_handle,
- data, size, output_written_cb, hog);
+ bt_gatt_client_write_value(hog->client,
+ report->decl->value_handle,
+ data, size, output_written_cb,
+ hog, NULL);
else if (report->decl->properties & GATT_CHR_PROP_WRITE_WITHOUT_RESP)
bt_gatt_client_write_without_response(hog->client,
report->decl->value_handle,
@@ -486,8 +487,7 @@ done:
error("bt_uhid_send: %s", strerror(-err));
}

-static void set_report_cb(guint8 status, const guint8 *pdu,
- guint16 plen, gpointer user_data)
+static void set_report_cb(bool success, uint8_t status, void *user_data)
{
struct bt_hog *hog = user_data;
struct uhid_event rsp;
@@ -500,7 +500,7 @@ static void set_report_cb(guint8 status, const guint8 *pdu,
rsp.u.set_report_reply.id = hog->setrep_id;
rsp.u.set_report_reply.err = status;

- if (status != 0)
+ if (!success)
error("Error setting Report value: %s", att_ecode2str(status));

err = bt_uhid_send(hog->uhid, &rsp);
@@ -518,7 +518,7 @@ static void set_report(struct uhid_event *ev, void *user_data)

/* uhid never sends reqs in parallel; if there's a req, it timed out */
if (hog->setrep_att) {
- g_attrib_cancel(hog->attrib, hog->setrep_att);
+ bt_gatt_client_cancel(hog->client, hog->setrep_att);
hog->setrep_att = 0;
}

@@ -541,13 +541,13 @@ static void set_report(struct uhid_event *ev, void *user_data)
DBG("Sending report type %d ID %d to handle 0x%X", report->type,
report->id, report->decl->value_handle);

- if (hog->attrib == NULL)
+ if (hog->client == NULL)
return;

- hog->setrep_att = gatt_write_char(hog->attrib,
- report->decl->value_handle,
- data, size, set_report_cb,
- hog);
+ hog->setrep_att = bt_gatt_client_write_value(hog->client,
+ report->decl->value_handle, data, size,
+ set_report_cb, hog, NULL);
+
if (!hog->setrep_att) {
err = ENOMEM;
goto fail;
@@ -556,7 +556,7 @@ static void set_report(struct uhid_event *ev, void *user_data)
return;
fail:
/* cancel the request on failure */
- set_report_cb(err, NULL, 0, hog);
+ set_report_cb(false, err, hog);
}

static void get_report_cb(bool success, uint8_t status, const uint8_t *value,
@@ -1239,8 +1239,10 @@ int bt_hog_send_report(struct bt_hog *hog, void *data, size_t size, int type)
DBG("hog: Write report, handle 0x%X", report->decl->value_handle);

if (report->decl->properties & GATT_CHR_PROP_WRITE)
- gatt_write_char(hog->attrib, report->decl->value_handle,
- data, size, output_written_cb, hog);
+ bt_gatt_client_write_value(hog->client,
+ report->decl->value_handle,
+ data, size, output_written_cb,
+ hog, NULL);

if (report->decl->properties & GATT_CHR_PROP_WRITE_WITHOUT_RESP)
bt_gatt_client_write_without_response(hog->client,
--
1.9.1


2015-04-03 13:43:34

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 05/27] android/hog: Use bt_gatt_client to read characteristic value

This patch replaces gatt_read_char from gattib library with equivalent
bt_gatt_client_read_value function. It requires some changes in declaration
list of callbacks. Since the actual value is read, not pdu, some changes
in code are necessary.
---
android/hog.c | 149 +++++++++++++++++++++++++++-------------------------------
1 file changed, 69 insertions(+), 80 deletions(-)

diff --git a/android/hog.c b/android/hog.c
index 458ddc4..32109c2 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -204,25 +204,26 @@ static void ccc_read_cb(guint8 status, const guint8 *pdu, guint16 len,
write_ccc(report->hog, report->hog->attrib, report->ccc_handle, report);
}

-static void report_reference_cb(guint8 status, const guint8 *pdu,
- guint16 plen, gpointer user_data)
+static void report_reference_cb(bool success, uint8_t status,
+ const uint8_t *value, uint16_t length,
+ void *user_data)
{
struct report *report = user_data;

- if (status != 0) {
+ if (!success) {
error("Read Report Reference descriptor failed: %s",
att_ecode2str(status));
return;
}

- if (plen != 3) {
+ if (length != 2) {
error("Malformed ATT read response");
return;
}

- report->id = pdu[1];
- report->type = pdu[2];
- DBG("Report ID: 0x%02x Report type: 0x%02x", pdu[1], pdu[2]);
+ report->id = value[0];
+ report->type = value[1];
+ DBG("Report ID: 0x%02x Report type: 0x%02x", value[0], value[1]);

/* Enable notifications only for Input Reports */
if (report->type == HOG_REPORT_TYPE_INPUT)
@@ -230,8 +231,9 @@ static void report_reference_cb(guint8 status, const guint8 *pdu,
ccc_read_cb, report);
}

-static void external_report_reference_cb(guint8 status, const guint8 *pdu,
- guint16 plen, gpointer user_data);
+static void external_report_reference_cb(bool success, uint8_t status,
+ const uint8_t *value, uint16_t length,
+ void *user_data);

static void discover_external_cb(uint8_t status, GSList *descs, void *user_data)
{
@@ -246,9 +248,8 @@ static void discover_external_cb(uint8_t status, GSList *descs, void *user_data)
for ( ; descs; descs = descs->next) {
struct gatt_desc *desc = descs->data;

- gatt_read_char(hog->attrib, desc->handle,
- external_report_reference_cb,
- hog);
+ bt_gatt_client_read_value(hog->client, desc->handle,
+ external_report_reference_cb, hog, NULL);
}
}

@@ -286,8 +287,8 @@ static void discover_report_cb(uint8_t status, GSList *descs, void *user_data)
report->ccc_handle = desc->handle;
break;
case GATT_REPORT_REFERENCE:
- gatt_read_char(hog->attrib, desc->handle,
- report_reference_cb, report);
+ bt_gatt_client_read_value(hog->client, desc->handle,
+ report_reference_cb, report, NULL);
break;
}
}
@@ -304,20 +305,22 @@ static void discover_report(struct bt_hog *hog, GAttrib *attrib,
user_data);
}

-static void report_read_cb(guint8 status, const guint8 *pdu, guint16 len,
- gpointer user_data)
+static void report_read_cb(bool success, uint8_t att_ecode,
+ const uint8_t *value, uint16_t len,
+ void *user_data)
{
struct report *report = user_data;

- if (status != 0) {
- error("Error reading Report value: %s", att_ecode2str(status));
+ if (!success) {
+ error("Error reading Report value: %s",
+ att_ecode2str(att_ecode));
return;
}

if (report->value)
g_free(report->value);

- report->value = g_memdup(pdu, len);
+ report->value = g_memdup(value, len);
report->len = len;
}

@@ -330,7 +333,8 @@ static struct report *report_new(struct bt_hog *hog, struct gatt_char *chr)
report->decl = g_memdup(chr, sizeof(*chr));
hog->reports = g_slist_append(hog->reports, report);

- gatt_read_char(hog->attrib, chr->value_handle, report_read_cb, report);
+ bt_gatt_client_read_value(hog->client, chr->value_handle,
+ report_read_cb, report, NULL);

return report;
}
@@ -366,25 +370,26 @@ static void external_service_char_cb(uint8_t status, GSList *chars,
}
}

-static void external_report_reference_cb(guint8 status, const guint8 *pdu,
- guint16 plen, gpointer user_data)
+static void external_report_reference_cb(bool success, uint8_t status,
+ const uint8_t *value, uint16_t length,
+ void *user_data)
{
struct bt_hog *hog = user_data;
uint16_t uuid16;
bt_uuid_t uuid;

- if (status != 0) {
+ if (!success) {
error("Read External Report Reference descriptor failed: %s",
att_ecode2str(status));
return;
}

- if (plen != 3) {
+ if (length != 2) {
error("Malformed ATT read response");
return;
}

- uuid16 = get_le16(&pdu[1]);
+ uuid16 = get_le16(value);
DBG("External report reference read, external report characteristic "
"UUID: 0x%04x", uuid16);

@@ -595,8 +600,8 @@ fail:
set_report_cb(err, NULL, 0, hog);
}

-static void get_report_cb(guint8 status, const guint8 *pdu, guint16 len,
- gpointer user_data)
+static void get_report_cb(bool success, uint8_t status, const uint8_t *value,
+ uint16_t len, void *user_data)
{
struct bt_hog *hog = user_data;
struct uhid_event rsp;
@@ -608,7 +613,7 @@ static void get_report_cb(guint8 status, const guint8 *pdu, guint16 len,
rsp.type = UHID_GET_REPORT_REPLY;
rsp.u.get_report_reply.id = hog->getrep_id;

- if (status != 0) {
+ if (!success) {
error("Error reading Report value: %s", att_ecode2str(status));
goto exit;
}
@@ -619,21 +624,21 @@ static void get_report_cb(guint8 status, const guint8 *pdu, guint16 len,
goto exit;
}

- if (pdu[0] != 0x0b) {
- error("Error reading Report, invalid response: %02x", pdu[0]);
+ if (value[0] != 0x0b) {
+ error("Error reading Report, invalid response: %02x", value[0]);
status = EPROTO;
goto exit;
}

--len;
- ++pdu;
+ ++value;
if (hog->has_report_id && len > 0) {
--len;
- ++pdu;
+ ++value;
}

rsp.u.get_report_reply.size = len;
- memcpy(rsp.u.get_report_reply.data, pdu, len);
+ memcpy(rsp.u.get_report_reply.data, value, len);

exit:
rsp.u.get_report_reply.err = status;
@@ -650,7 +655,7 @@ static void get_report(struct uhid_event *ev, void *user_data)

/* uhid never sends reqs in parallel; if there's a req, it timed out */
if (hog->getrep_att) {
- g_attrib_cancel(hog->attrib, hog->getrep_att);
+ bt_gatt_client_cancel(hog->client, hog->getrep_att);
hog->getrep_att = 0;
}

@@ -663,9 +668,9 @@ static void get_report(struct uhid_event *ev, void *user_data)
goto fail;
}

- hog->getrep_att = gatt_read_char(hog->attrib,
+ hog->getrep_att = bt_gatt_client_read_value(hog->client,
report->decl->value_handle,
- get_report_cb, hog);
+ get_report_cb, hog, NULL);
if (!hog->getrep_att) {
err = ENOMEM;
goto fail;
@@ -675,11 +680,11 @@ static void get_report(struct uhid_event *ev, void *user_data)

fail:
/* cancel the request on failure */
- get_report_cb(err, NULL, 0, hog);
+ get_report_cb(false, err, NULL, 0, hog);
}

-static bool get_descriptor_item_info(uint8_t *buf, ssize_t blen, ssize_t *len,
- bool *is_long)
+static bool get_descriptor_item_info(const uint8_t *buf, ssize_t blen,
+ ssize_t *len, bool *is_long)
{
if (!blen)
return false;
@@ -718,7 +723,7 @@ static bool get_descriptor_item_info(uint8_t *buf, ssize_t blen, ssize_t *len,
return *len <= blen;
}

-static char *item2string(char *str, uint8_t *buf, uint8_t len)
+static char *item2string(char *str, const uint8_t *buf, uint8_t len)
{
char *p = str;
int i;
@@ -740,25 +745,18 @@ static char *item2string(char *str, uint8_t *buf, uint8_t len)
return str;
}

-static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
- gpointer user_data)
+static void report_map_read_cb(bool success, uint8_t att_ecode,
+ const uint8_t *value, uint16_t vlen,
+ void *user_data)
{
struct bt_hog *hog = user_data;
- uint8_t value[HOG_REPORT_MAP_MAX_SIZE];
struct uhid_event ev;
- ssize_t vlen;
char itemstr[20]; /* 5x3 (data) + 4 (continuation) + 1 (null) */
int i, err;
GError *gerr = NULL;

- if (status != 0) {
- error("Report Map read failed: %s", att_ecode2str(status));
- return;
- }
-
- vlen = dec_read_resp(pdu, plen, value, sizeof(value));
- if (vlen < 0) {
- error("ATT protocol error");
+ if (!success) {
+ error("Report Map read failed: %s", att_ecode2str(att_ecode));
return;
}

@@ -805,7 +803,7 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
ev.u.create.version = hog->version;
ev.u.create.country = hog->bcountrycode;
ev.u.create.bus = BUS_BLUETOOTH;
- ev.u.create.rd_data = value;
+ ev.u.create.rd_data = (uint8_t *) value;
ev.u.create.rd_size = vlen;

err = bt_uhid_send(hog->uhid, &ev);
@@ -820,20 +818,16 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
bt_uhid_register(hog->uhid, UHID_SET_REPORT, set_report, hog);
}

-static void info_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
- gpointer user_data)
+static void info_read_cb(bool success, uint8_t status, const uint8_t *value,
+ uint16_t vlen, void *user_data)
{
struct bt_hog *hog = user_data;
- uint8_t value[HID_INFO_SIZE];
- ssize_t vlen;

- if (status != 0) {
- error("HID Information read failed: %s",
- att_ecode2str(status));
+ if (!success) {
+ error("HID Information read failed: %s", att_ecode2str(status));
return;
}

- vlen = dec_read_resp(pdu, plen, value, sizeof(value));
if (vlen != 4) {
error("ATT protocol error");
return;
@@ -847,33 +841,26 @@ static void info_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
hog->bcdhid, hog->bcountrycode, hog->flags);
}

-static void proto_mode_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
- gpointer user_data)
+static void proto_mode_read_cb(bool success, uint8_t att_ecode,
+ const uint8_t *value, uint16_t length,
+ void *user_data)
{
struct bt_hog *hog = user_data;
- uint8_t value;
- ssize_t vlen;

- if (status != 0) {
+ if (!success) {
error("Protocol Mode characteristic read failed: %s",
- att_ecode2str(status));
- return;
- }
-
- vlen = dec_read_resp(pdu, plen, &value, sizeof(value));
- if (vlen < 0) {
- error("ATT protocol error");
+ att_ecode2str(att_ecode));
return;
}

- if (value == HOG_PROTO_MODE_BOOT) {
+ if (value[0] == HOG_PROTO_MODE_BOOT) {
uint8_t nval = HOG_PROTO_MODE_REPORT;

DBG("HoG is operating in Boot Procotol Mode");

gatt_write_cmd(hog->attrib, hog->proto_mode_handle, &nval,
sizeof(nval), NULL, NULL);
- } else if (value == HOG_PROTO_MODE_REPORT)
+ } else if (value[0] == HOG_PROTO_MODE_REPORT)
DBG("HoG is operating in Report Protocol Mode");
}

@@ -919,8 +906,9 @@ static void char_discovered_cb(uint8_t status, GSList *chars, void *user_data)
report = report_new(hog, chr);
discover_report(hog, hog->attrib, start, end, report);
} else if (bt_uuid_cmp(&uuid, &report_map_uuid) == 0) {
- gatt_read_char(hog->attrib, chr->value_handle,
- report_map_read_cb, hog);
+ bt_gatt_client_read_long_value(hog->client,
+ chr->value_handle, 0, report_map_read_cb,
+ hog, NULL);
discover_external(hog, hog->attrib, start, end, hog);
} else if (bt_uuid_cmp(&uuid, &info_uuid) == 0)
info_handle = chr->value_handle;
@@ -932,12 +920,13 @@ static void char_discovered_cb(uint8_t status, GSList *chars, void *user_data)

if (proto_mode_handle) {
hog->proto_mode_handle = proto_mode_handle;
- gatt_read_char(hog->attrib, proto_mode_handle,
- proto_mode_read_cb, hog);
+ bt_gatt_client_read_value(hog->client, proto_mode_handle,
+ proto_mode_read_cb, hog, NULL);
}

if (info_handle)
- gatt_read_char(hog->attrib, info_handle, info_read_cb, hog);
+ bt_gatt_client_read_value(hog->client, info_handle,
+ info_read_cb, hog, NULL);
}

static void report_free(void *data)
--
1.9.1


2015-04-03 13:43:39

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 10/27] android/hog: Add helper to create uhid device

This patch moves the code responsible for creation of uhid device
into separate function. This improves code readability.
---
android/hog.c | 82 ++++++++++++++++++++++++++++++++++-------------------------
1 file changed, 47 insertions(+), 35 deletions(-)

diff --git a/android/hog.c b/android/hog.c
index 8570cab..4dcba4d 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -667,15 +667,57 @@ static char *item2string(char *str, const uint8_t *buf, uint8_t len)
return str;
}

+static bool uhid_create(struct bt_hog *hog, const uint8_t *value, uint16_t vlen)
+{
+ struct uhid_event ev;
+ int err;
+ GError *gerr = NULL;
+
+ /* create uHID device */
+ memset(&ev, 0, sizeof(ev));
+ ev.type = UHID_CREATE;
+
+ bt_io_get(g_attrib_get_channel(hog->attrib), &gerr,
+ BT_IO_OPT_SOURCE, ev.u.create.phys,
+ BT_IO_OPT_DEST, ev.u.create.uniq,
+ BT_IO_OPT_INVALID);
+ if (gerr) {
+ error("Failed to connection details: %s", gerr->message);
+ g_error_free(gerr);
+ return false;
+ }
+
+ strcpy((char *) ev.u.create.name, hog->name);
+ ev.u.create.vendor = hog->vendor;
+ ev.u.create.product = hog->product;
+ ev.u.create.version = hog->version;
+ ev.u.create.country = hog->bcountrycode;
+ ev.u.create.bus = BUS_BLUETOOTH;
+ ev.u.create.rd_data = (uint8_t *) value;
+ ev.u.create.rd_size = vlen;
+
+ err = bt_uhid_send(hog->uhid, &ev);
+ if (err < 0) {
+ error("bt_uhid_send: %s", strerror(-err));
+ return false;
+ }
+
+ bt_uhid_register(hog->uhid, UHID_OUTPUT, forward_report, hog);
+ bt_uhid_register(hog->uhid, UHID_FEATURE, get_feature, hog);
+ bt_uhid_register(hog->uhid, UHID_GET_REPORT, get_report, hog);
+ bt_uhid_register(hog->uhid, UHID_SET_REPORT, set_report, hog);
+
+ return true;
+}
+
static void report_map_read_cb(bool success, uint8_t att_ecode,
const uint8_t *value, uint16_t vlen,
void *user_data)
{
struct bt_hog *hog = user_data;
- struct uhid_event ev;
+
char itemstr[20]; /* 5x3 (data) + 4 (continuation) + 1 (null) */
- int i, err;
- GError *gerr = NULL;
+ int i;

if (!success) {
error("Report Map read failed: %s", att_ecode2str(att_ecode));
@@ -705,39 +747,9 @@ static void report_map_read_cb(bool success, uint8_t att_ecode,
}
}

- /* create uHID device */
- memset(&ev, 0, sizeof(ev));
- ev.type = UHID_CREATE;
-
- bt_io_get(g_attrib_get_channel(hog->attrib), &gerr,
- BT_IO_OPT_SOURCE, ev.u.create.phys,
- BT_IO_OPT_DEST, ev.u.create.uniq,
- BT_IO_OPT_INVALID);
- if (gerr) {
- error("Failed to connection details: %s", gerr->message);
- g_error_free(gerr);
+ /* TODO Error handling */
+ if (!uhid_create(hog, value, vlen))
return;
- }
-
- strcpy((char *) ev.u.create.name, hog->name);
- ev.u.create.vendor = hog->vendor;
- ev.u.create.product = hog->product;
- ev.u.create.version = hog->version;
- ev.u.create.country = hog->bcountrycode;
- ev.u.create.bus = BUS_BLUETOOTH;
- ev.u.create.rd_data = (uint8_t *) value;
- ev.u.create.rd_size = vlen;
-
- err = bt_uhid_send(hog->uhid, &ev);
- if (err < 0) {
- error("bt_uhid_send: %s", strerror(-err));
- return;
- }
-
- bt_uhid_register(hog->uhid, UHID_OUTPUT, forward_report, hog);
- bt_uhid_register(hog->uhid, UHID_FEATURE, get_feature, hog);
- bt_uhid_register(hog->uhid, UHID_GET_REPORT, get_report, hog);
- bt_uhid_register(hog->uhid, UHID_SET_REPORT, set_report, hog);
}

static void info_read_cb(bool success, uint8_t status, const uint8_t *value,
--
1.9.1


2015-04-03 13:43:35

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 06/27] android/hog: Use bt_gatt_client to register for notifications

This patch replaces g_attrib_register with bt_gatt_client_register_notify
to register for notifications of report reference.

Since bt_gatt_client_notify_callback_t returns a pointer to value
not pdu, notification header is not present and
ATT_NOTIFICATION_HEADER_SIZE can be removed.

There is no need to read and store ccc_handle, because it's already cached
and keep by bt_gatt_client. To register for notification only
characteristic value handle is needed.
---
android/hog.c | 73 +++++++++++++----------------------------------------------
1 file changed, 16 insertions(+), 57 deletions(-)

diff --git a/android/hog.c b/android/hog.c
index 32109c2..58c9d48 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -78,7 +78,6 @@

#define HOG_REPORT_MAP_MAX_SIZE 512
#define HID_INFO_SIZE 4
-#define ATT_NOTIFICATION_HEADER_SIZE 3

struct bt_hog {
int ref_count;
@@ -113,14 +112,14 @@ struct report {
struct bt_hog *hog;
uint8_t id;
uint8_t type;
- uint16_t ccc_handle;
- guint notifyid;
+ uint32_t notifyid;
struct gatt_char *decl;
uint16_t len;
uint8_t *value;
};

-static void report_value_cb(const guint8 *pdu, guint16 len, gpointer user_data)
+static void report_value_cb(uint16_t value_handle, const uint8_t *value,
+ uint16_t len, void *user_data)
{
struct report *report = user_data;
struct bt_hog *hog = report->hog;
@@ -128,14 +127,6 @@ static void report_value_cb(const guint8 *pdu, guint16 len, gpointer user_data)
uint8_t *buf;
int err;

- if (len < ATT_NOTIFICATION_HEADER_SIZE) {
- error("Malformed ATT notification");
- return;
- }
-
- pdu += ATT_NOTIFICATION_HEADER_SIZE;
- len -= ATT_NOTIFICATION_HEADER_SIZE;
-
memset(&ev, 0, sizeof(ev));
ev.type = UHID_INPUT;
buf = ev.u.input.data;
@@ -143,11 +134,11 @@ static void report_value_cb(const guint8 *pdu, guint16 len, gpointer user_data)
if (hog->has_report_id) {
buf[0] = report->id;
len = MIN(len, sizeof(ev.u.input.data) - 1);
- memcpy(buf + 1, pdu, len);
+ memcpy(buf + 1, value, len);
ev.u.input.size = ++len;
} else {
len = MIN(len, sizeof(ev.u.input.data));
- memcpy(buf, pdu, len);
+ memcpy(buf, value, len);
ev.u.input.size = len;
}

@@ -160,55 +151,23 @@ static void report_value_cb(const guint8 *pdu, guint16 len, gpointer user_data)
DBG("HoG report (%u bytes)", ev.u.input.size);
}

-static void report_ccc_written_cb(guint8 status, const guint8 *pdu,
- guint16 plen, gpointer user_data)
+static void report_ccc_written_cb(uint16_t status, void *user_data)
{
- struct report *report = user_data;
- struct bt_hog *hog = report->hog;
-
if (status != 0) {
error("Write report characteristic descriptor failed: %s",
att_ecode2str(status));
return;
}

- report->notifyid = g_attrib_register(hog->attrib,
- ATT_OP_HANDLE_NOTIFY,
- report->decl->value_handle,
- report_value_cb, report, NULL);
-
DBG("Report characteristic descriptor written: notifications enabled");
}

-static void write_ccc(struct bt_hog *hog, GAttrib *attrib, uint16_t handle,
- void *user_data)
-{
- uint8_t value[2];
-
- put_le16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);
-
- gatt_write_char(attrib, handle, value, sizeof(value),
- report_ccc_written_cb, user_data);
-}
-
-static void ccc_read_cb(guint8 status, const guint8 *pdu, guint16 len,
- gpointer user_data)
-{
- struct report *report = user_data;
-
- if (status != 0) {
- error("Error reading CCC value: %s", att_ecode2str(status));
- return;
- }
-
- write_ccc(report->hog, report->hog->attrib, report->ccc_handle, report);
-}
-
static void report_reference_cb(bool success, uint8_t status,
const uint8_t *value, uint16_t length,
void *user_data)
{
struct report *report = user_data;
+ struct bt_gatt_client *client = report->hog->client;

if (!success) {
error("Read Report Reference descriptor failed: %s",
@@ -227,8 +186,10 @@ static void report_reference_cb(bool success, uint8_t status,

/* Enable notifications only for Input Reports */
if (report->type == HOG_REPORT_TYPE_INPUT)
- gatt_read_char(report->hog->attrib, report->ccc_handle,
- ccc_read_cb, report);
+ report->notifyid = bt_gatt_client_register_notify(client,
+ report->decl->value_handle,
+ report_ccc_written_cb,
+ report_value_cb, report, NULL);
}

static void external_report_reference_cb(bool success, uint8_t status,
@@ -283,9 +244,6 @@ static void discover_report_cb(uint8_t status, GSList *descs, void *user_data)
struct gatt_desc *desc = descs->data;

switch (desc->uuid16) {
- case GATT_CLIENT_CHARAC_CFG_UUID:
- report->ccc_handle = desc->handle;
- break;
case GATT_REPORT_REFERENCE:
bt_gatt_client_read_value(hog->client, desc->handle,
report_reference_cb, report, NULL);
@@ -1198,10 +1156,10 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)

for (l = hog->reports; l; l = l->next) {
struct report *r = l->data;
-
- r->notifyid = g_attrib_register(hog->attrib,
- ATT_OP_HANDLE_NOTIFY,
+ if (r->type == HOG_REPORT_TYPE_INPUT)
+ r->notifyid = bt_gatt_client_register_notify(client,
r->decl->value_handle,
+ report_ccc_written_cb,
report_value_cb, r, NULL);
}

@@ -1227,7 +1185,8 @@ void bt_hog_detach(struct bt_hog *hog)
struct report *r = l->data;

if (r->notifyid > 0) {
- g_attrib_unregister(hog->attrib, r->notifyid);
+ bt_gatt_client_unregister_notify(hog->client,
+ r->notifyid);
r->notifyid = 0;
}
}
--
1.9.1


2015-04-03 13:43:33

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 04/27] android/hog: Remove tracking gatt operations

Since the use of bt_gatt_client there is no need to queue pending gatt
operations. bt_gatt_client already keeps track on that, so that
on bt_gatt_client_unref the queue of pending requests is destroyed.
---
android/hog.c | 283 +++++++---------------------------------------------------
1 file changed, 33 insertions(+), 250 deletions(-)

diff --git a/android/hog.c b/android/hog.c
index 931ac0b..458ddc4 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -106,7 +106,6 @@ struct bt_hog {
struct bt_dis *dis;
struct queue *bas;
GSList *instances;
- struct queue *gatt_op;
struct bt_gatt_client *client;
};

@@ -121,168 +120,6 @@ struct report {
uint8_t *value;
};

-struct gatt_request {
- unsigned int id;
- struct bt_hog *hog;
- void *user_data;
-};
-
-static struct gatt_request *create_request(struct bt_hog *hog,
- void *user_data)
-{
- struct gatt_request *req;
-
- req = new0(struct gatt_request, 1);
- if (!req)
- return NULL;
-
- req->user_data = user_data;
- req->hog = bt_hog_ref(hog);
-
- return req;
-}
-
-static bool set_and_store_gatt_req(struct bt_hog *hog,
- struct gatt_request *req,
- unsigned int id)
-{
- req->id = id;
- return queue_push_head(hog->gatt_op, req);
-}
-
-static void destroy_gatt_req(struct gatt_request *req)
-{
- queue_remove(req->hog->gatt_op, req);
- bt_hog_unref(req->hog);
- free(req);
-}
-
-static void write_char(struct bt_hog *hog, GAttrib *attrib, uint16_t handle,
- const uint8_t *value, size_t vlen,
- GAttribResultFunc func,
- gpointer user_data)
-{
- struct gatt_request *req;
- unsigned int id;
-
- req = create_request(hog, user_data);
- if (!req)
- return;
-
- id = gatt_write_char(attrib, handle, value, vlen, func, req);
-
- if (set_and_store_gatt_req(hog, req, id))
- return;
-
- error("hog: Could not read char");
- g_attrib_cancel(attrib, id);
- free(req);
-}
-
-static void read_char(struct bt_hog *hog, GAttrib *attrib, uint16_t handle,
- GAttribResultFunc func, gpointer user_data)
-{
- struct gatt_request *req;
- unsigned int id;
-
- req = create_request(hog, user_data);
- if (!req)
- return;
-
- id = gatt_read_char(attrib, handle, func, req);
-
- if (set_and_store_gatt_req(hog, req, id))
- return;
-
- error("hog: Could not read char");
- g_attrib_cancel(attrib, id);
- free(req);
-}
-
-static void discover_desc(struct bt_hog *hog, GAttrib *attrib,
- uint16_t start, uint16_t end, gatt_cb_t func,
- gpointer user_data)
-{
- struct gatt_request *req;
- unsigned int id;
-
- req = create_request(hog, user_data);
- if (!req)
- return;
-
- id = gatt_discover_desc(attrib, start, end, NULL, func, req);
- if (set_and_store_gatt_req(hog, req, id))
- return;
-
- error("hog: Could not discover descriptors");
- g_attrib_cancel(attrib, id);
- free(req);
-}
-
-static void discover_char(struct bt_hog *hog, GAttrib *attrib,
- uint16_t start, uint16_t end,
- bt_uuid_t *uuid, gatt_cb_t func,
- gpointer user_data)
-{
- struct gatt_request *req;
- unsigned int id;
-
- req = create_request(hog, user_data);
- if (!req)
- return;
-
- id = gatt_discover_char(attrib, start, end, uuid, func, req);
-
- if (set_and_store_gatt_req(hog, req, id))
- return;
-
- error("hog: Could not discover characteristic");
- g_attrib_cancel(attrib, id);
- free(req);
-}
-
-static void discover_primary(struct bt_hog *hog, GAttrib *attrib,
- bt_uuid_t *uuid, gatt_cb_t func,
- gpointer user_data)
-{
- struct gatt_request *req;
- unsigned int id;
-
- req = create_request(hog, user_data);
- if (!req)
- return;
-
- id = gatt_discover_primary(attrib, uuid, func, req);
-
- if (set_and_store_gatt_req(hog, req, id))
- return;
-
- error("hog: Could not send discover primary");
- g_attrib_cancel(attrib, id);
- free(req);
-}
-
-static void find_included(struct bt_hog *hog, GAttrib *attrib,
- uint16_t start, uint16_t end,
- gatt_cb_t func, gpointer user_data)
-{
- struct gatt_request *req;
- unsigned int id;
-
- req = create_request(hog, user_data);
- if (!req)
- return;
-
- id = gatt_find_included(attrib, start, end, func, req);
-
- if (set_and_store_gatt_req(hog, req, id))
- return;
-
- error("Could not find included");
- g_attrib_cancel(attrib, id);
- free(req);
-}
-
static void report_value_cb(const guint8 *pdu, guint16 len, gpointer user_data)
{
struct report *report = user_data;
@@ -326,12 +163,9 @@ static void report_value_cb(const guint8 *pdu, guint16 len, gpointer user_data)
static void report_ccc_written_cb(guint8 status, const guint8 *pdu,
guint16 plen, gpointer user_data)
{
- struct gatt_request *req = user_data;
- struct report *report = req->user_data;
+ struct report *report = user_data;
struct bt_hog *hog = report->hog;

- destroy_gatt_req(req);
-
if (status != 0) {
error("Write report characteristic descriptor failed: %s",
att_ecode2str(status));
@@ -353,17 +187,14 @@ static void write_ccc(struct bt_hog *hog, GAttrib *attrib, uint16_t handle,

put_le16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);

- write_char(hog, attrib, handle, value, sizeof(value),
+ gatt_write_char(attrib, handle, value, sizeof(value),
report_ccc_written_cb, user_data);
}

static void ccc_read_cb(guint8 status, const guint8 *pdu, guint16 len,
gpointer user_data)
{
- struct gatt_request *req = user_data;
- struct report *report = req->user_data;
-
- destroy_gatt_req(req);
+ struct report *report = user_data;

if (status != 0) {
error("Error reading CCC value: %s", att_ecode2str(status));
@@ -376,10 +207,7 @@ static void ccc_read_cb(guint8 status, const guint8 *pdu, guint16 len,
static void report_reference_cb(guint8 status, const guint8 *pdu,
guint16 plen, gpointer user_data)
{
- struct gatt_request *req = user_data;
- struct report *report = req->user_data;
-
- destroy_gatt_req(req);
+ struct report *report = user_data;

if (status != 0) {
error("Read Report Reference descriptor failed: %s",
@@ -398,7 +226,7 @@ static void report_reference_cb(guint8 status, const guint8 *pdu,

/* Enable notifications only for Input Reports */
if (report->type == HOG_REPORT_TYPE_INPUT)
- read_char(report->hog, report->hog->attrib, report->ccc_handle,
+ gatt_read_char(report->hog->attrib, report->ccc_handle,
ccc_read_cb, report);
}

@@ -407,10 +235,7 @@ static void external_report_reference_cb(guint8 status, const guint8 *pdu,

static void discover_external_cb(uint8_t status, GSList *descs, void *user_data)
{
- struct gatt_request *req = user_data;
- struct bt_hog *hog = req->user_data;
-
- destroy_gatt_req(req);
+ struct bt_hog *hog = user_data;

if (status != 0) {
error("Discover external descriptors failed: %s",
@@ -421,7 +246,7 @@ static void discover_external_cb(uint8_t status, GSList *descs, void *user_data)
for ( ; descs; descs = descs->next) {
struct gatt_desc *desc = descs->data;

- read_char(hog, hog->attrib, desc->handle,
+ gatt_read_char(hog->attrib, desc->handle,
external_report_reference_cb,
hog);
}
@@ -438,18 +263,15 @@ static void discover_external(struct bt_hog *hog, GAttrib *attrib,

bt_uuid16_create(&uuid, GATT_EXTERNAL_REPORT_REFERENCE);

- discover_desc(hog, attrib, start, end, discover_external_cb,
+ gatt_discover_desc(attrib, start, end, NULL, discover_external_cb,
user_data);
}

static void discover_report_cb(uint8_t status, GSList *descs, void *user_data)
{
- struct gatt_request *req = user_data;
- struct report *report = req->user_data;
+ struct report *report = user_data;
struct bt_hog *hog = report->hog;

- destroy_gatt_req(req);
-
if (status != 0) {
error("Discover report descriptors failed: %s",
att_ecode2str(status));
@@ -464,7 +286,7 @@ static void discover_report_cb(uint8_t status, GSList *descs, void *user_data)
report->ccc_handle = desc->handle;
break;
case GATT_REPORT_REFERENCE:
- read_char(hog, hog->attrib, desc->handle,
+ gatt_read_char(hog->attrib, desc->handle,
report_reference_cb, report);
break;
}
@@ -478,16 +300,14 @@ static void discover_report(struct bt_hog *hog, GAttrib *attrib,
if (start > end)
return;

- discover_desc(hog, attrib, start, end, discover_report_cb, user_data);
+ gatt_discover_desc(attrib, start, end, NULL, discover_report_cb,
+ user_data);
}

static void report_read_cb(guint8 status, const guint8 *pdu, guint16 len,
gpointer user_data)
{
- struct gatt_request *req = user_data;
- struct report *report = req->user_data;
-
- destroy_gatt_req(req);
+ struct report *report = user_data;

if (status != 0) {
error("Error reading Report value: %s", att_ecode2str(status));
@@ -510,7 +330,7 @@ static struct report *report_new(struct bt_hog *hog, struct gatt_char *chr)
report->decl = g_memdup(chr, sizeof(*chr));
hog->reports = g_slist_append(hog->reports, report);

- read_char(hog, hog->attrib, chr->value_handle, report_read_cb, report);
+ gatt_read_char(hog->attrib, chr->value_handle, report_read_cb, report);

return report;
}
@@ -518,14 +338,11 @@ static struct report *report_new(struct bt_hog *hog, struct gatt_char *chr)
static void external_service_char_cb(uint8_t status, GSList *chars,
void *user_data)
{
- struct gatt_request *req = user_data;
- struct bt_hog *hog = req->user_data;
+ struct bt_hog *hog = user_data;
struct gatt_primary *primary = hog->primary;
struct report *report;
GSList *l;

- destroy_gatt_req(req);
-
if (status != 0) {
const char *str = att_ecode2str(status);
DBG("Discover external service characteristic failed: %s", str);
@@ -552,13 +369,10 @@ static void external_service_char_cb(uint8_t status, GSList *chars,
static void external_report_reference_cb(guint8 status, const guint8 *pdu,
guint16 plen, gpointer user_data)
{
- struct gatt_request *req = user_data;
- struct bt_hog *hog = req->user_data;
+ struct bt_hog *hog = user_data;
uint16_t uuid16;
bt_uuid_t uuid;

- destroy_gatt_req(req);
-
if (status != 0) {
error("Read External Report Reference descriptor failed: %s",
att_ecode2str(status));
@@ -579,7 +393,7 @@ static void external_report_reference_cb(guint8 status, const guint8 *pdu,
return;

bt_uuid16_create(&uuid, uuid16);
- discover_char(hog, hog->attrib, 0x0001, 0xffff, &uuid,
+ gatt_discover_char(hog->attrib, 0x0001, 0xffff, &uuid,
external_service_char_cb, hog);
}

@@ -637,10 +451,6 @@ static struct report *find_report_by_rtype(struct bt_hog *hog, uint8_t rtype,
static void output_written_cb(guint8 status, const guint8 *pdu,
guint16 plen, gpointer user_data)
{
- struct gatt_request *req = user_data;
-
- destroy_gatt_req(req);
-
if (status != 0) {
error("Write output report failed: %s", att_ecode2str(status));
return;
@@ -673,7 +483,7 @@ static void forward_report(struct uhid_event *ev, void *user_data)
return;

if (report->decl->properties & GATT_CHR_PROP_WRITE)
- write_char(hog, hog->attrib, report->decl->value_handle,
+ gatt_write_char(hog->attrib, report->decl->value_handle,
data, size, output_written_cb, hog);
else if (report->decl->properties & GATT_CHR_PROP_WRITE_WITHOUT_RESP)
gatt_write_cmd(hog->attrib, report->decl->value_handle,
@@ -933,8 +743,7 @@ static char *item2string(char *str, uint8_t *buf, uint8_t len)
static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
gpointer user_data)
{
- struct gatt_request *req = user_data;
- struct bt_hog *hog = req->user_data;
+ struct bt_hog *hog = user_data;
uint8_t value[HOG_REPORT_MAP_MAX_SIZE];
struct uhid_event ev;
ssize_t vlen;
@@ -942,8 +751,6 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
int i, err;
GError *gerr = NULL;

- destroy_gatt_req(req);
-
if (status != 0) {
error("Report Map read failed: %s", att_ecode2str(status));
return;
@@ -1016,13 +823,10 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
static void info_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
gpointer user_data)
{
- struct gatt_request *req = user_data;
- struct bt_hog *hog = req->user_data;
+ struct bt_hog *hog = user_data;
uint8_t value[HID_INFO_SIZE];
ssize_t vlen;

- destroy_gatt_req(req);
-
if (status != 0) {
error("HID Information read failed: %s",
att_ecode2str(status));
@@ -1046,13 +850,10 @@ static void info_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
static void proto_mode_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
gpointer user_data)
{
- struct gatt_request *req = user_data;
- struct bt_hog *hog = req->user_data;
+ struct bt_hog *hog = user_data;
uint8_t value;
ssize_t vlen;

- destroy_gatt_req(req);
-
if (status != 0) {
error("Protocol Mode characteristic read failed: %s",
att_ecode2str(status));
@@ -1078,8 +879,7 @@ static void proto_mode_read_cb(guint8 status, const guint8 *pdu, guint16 plen,

static void char_discovered_cb(uint8_t status, GSList *chars, void *user_data)
{
- struct gatt_request *req = user_data;
- struct bt_hog *hog = req->user_data;
+ struct bt_hog *hog = user_data;
struct gatt_primary *primary = hog->primary;
bt_uuid_t report_uuid, report_map_uuid, info_uuid;
bt_uuid_t proto_mode_uuid, ctrlpt_uuid;
@@ -1087,8 +887,6 @@ static void char_discovered_cb(uint8_t status, GSList *chars, void *user_data)
GSList *l;
uint16_t info_handle = 0, proto_mode_handle = 0;

- destroy_gatt_req(req);
-
if (status != 0) {
const char *str = att_ecode2str(status);
DBG("Discover all characteristics failed: %s", str);
@@ -1121,7 +919,7 @@ static void char_discovered_cb(uint8_t status, GSList *chars, void *user_data)
report = report_new(hog, chr);
discover_report(hog, hog->attrib, start, end, report);
} else if (bt_uuid_cmp(&uuid, &report_map_uuid) == 0) {
- read_char(hog, hog->attrib, chr->value_handle,
+ gatt_read_char(hog->attrib, chr->value_handle,
report_map_read_cb, hog);
discover_external(hog, hog->attrib, start, end, hog);
} else if (bt_uuid_cmp(&uuid, &info_uuid) == 0)
@@ -1134,12 +932,12 @@ static void char_discovered_cb(uint8_t status, GSList *chars, void *user_data)

if (proto_mode_handle) {
hog->proto_mode_handle = proto_mode_handle;
- read_char(hog, hog->attrib, proto_mode_handle,
+ gatt_read_char(hog->attrib, proto_mode_handle,
proto_mode_read_cb, hog);
}

if (info_handle)
- read_char(hog, hog->attrib, info_handle, info_read_cb, hog);
+ gatt_read_char(hog->attrib, info_handle, info_read_cb, hog);
}

static void report_free(void *data)
@@ -1151,12 +949,6 @@ static void report_free(void *data)
g_free(report);
}

-static void cancel_gatt_req(struct gatt_request *req)
-{
- if (g_attrib_cancel(req->hog->attrib, req->id))
- destroy_gatt_req(req);
-}
-
static void hog_free(void *data)
{
struct bt_hog *hog = data;
@@ -1172,7 +964,6 @@ static void hog_free(void *data)
g_slist_free_full(hog->reports, report_free);
g_free(hog->name);
g_free(hog->primary);
- queue_destroy(hog->gatt_op, (void *) destroy_gatt_req);
g_free(hog);
}

@@ -1194,7 +985,6 @@ struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
if (!hog)
return NULL;

- hog->gatt_op = queue_new();
hog->bas = queue_new();

if (fd < 0)
@@ -1204,7 +994,7 @@ struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,

hog->uhid_fd = fd;

- if (!hog->gatt_op || !hog->bas || !hog->uhid) {
+ if (!hog->bas || !hog->uhid) {
hog_free(hog);
return NULL;
}
@@ -1246,13 +1036,10 @@ void bt_hog_unref(struct bt_hog *hog)

static void find_included_cb(uint8_t status, GSList *services, void *user_data)
{
- struct gatt_request *req = user_data;
GSList *l;

DBG("");

- destroy_gatt_req(req);
-
if (status) {
const char *str = att_ecode2str(status);
DBG("Find included failed: %s", str);
@@ -1321,10 +1108,10 @@ static void hog_attach_hog(struct bt_hog *hog, struct gatt_primary *primary)

if (!hog->primary) {
hog->primary = g_memdup(primary, sizeof(*primary));
- discover_char(hog, hog->attrib, primary->range.start,
+ gatt_discover_char(hog->attrib, primary->range.start,
primary->range.end, NULL,
char_discovered_cb, hog);
- find_included(hog, hog->attrib, primary->range.start,
+ gatt_find_included(hog->attrib, primary->range.start,
primary->range.end, find_included_cb, hog);
return;
}
@@ -1334,7 +1121,7 @@ static void hog_attach_hog(struct bt_hog *hog, struct gatt_primary *primary)
if (!instance)
return;

- find_included(instance, hog->attrib, primary->range.start,
+ gatt_find_included(hog->attrib, primary->range.start,
primary->range.end, find_included_cb, instance);

bt_hog_attach(instance, hog->attrib, hog->client);
@@ -1343,15 +1130,12 @@ static void hog_attach_hog(struct bt_hog *hog, struct gatt_primary *primary)

static void primary_cb(uint8_t status, GSList *services, void *user_data)
{
- struct gatt_request *req = user_data;
- struct bt_hog *hog = req->user_data;
+ struct bt_hog *hog = user_data;
struct gatt_primary *primary;
GSList *l;

DBG("");

- destroy_gatt_req(req);
-
if (status) {
const char *str = att_ecode2str(status);
DBG("Discover primary failed: %s", str);
@@ -1398,7 +1182,7 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)
hog->client = bt_gatt_client_ref(client);

if (!primary) {
- discover_primary(hog, hog->attrib, NULL, primary_cb, hog);
+ gatt_discover_primary(hog->attrib, NULL, primary_cb, hog);
return true;
}

@@ -1417,7 +1201,7 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)
}

if (hog->reports == NULL) {
- discover_char(hog, hog->attrib, primary->range.start,
+ gatt_discover_char(hog->attrib, primary->range.start,
primary->range.end, NULL,
char_discovered_cb, hog);
return true;
@@ -1465,7 +1249,6 @@ void bt_hog_detach(struct bt_hog *hog)
if (hog->dis)
bt_dis_detach(hog->dis);

- queue_foreach(hog->gatt_op, (void *) cancel_gatt_req, NULL);
bt_gatt_client_unref(hog->client);
hog->client = NULL;
g_attrib_unref(hog->attrib);
@@ -1506,7 +1289,7 @@ int bt_hog_send_report(struct bt_hog *hog, void *data, size_t size, int type)
DBG("hog: Write report, handle 0x%X", report->decl->value_handle);

if (report->decl->properties & GATT_CHR_PROP_WRITE)
- write_char(hog, hog->attrib, report->decl->value_handle,
+ gatt_write_char(hog->attrib, report->decl->value_handle,
data, size, output_written_cb, hog);

if (report->decl->properties & GATT_CHR_PROP_WRITE_WITHOUT_RESP)
--
1.9.1


2015-04-03 13:43:31

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 02/27] android/hog: Introduce bt_gatt_client

This patch introduces bt_gatt_client to HoG. Service handle will be used
to obtain the attribute from cached database.
---
android/hidhost.c | 4 ++--
android/hog.c | 30 +++++++++++++++++++++---------
android/hog.h | 6 +++---
unit/test-hog.c | 4 ++--
4 files changed, 28 insertions(+), 16 deletions(-)

diff --git a/android/hidhost.c b/android/hidhost.c
index 26a8013..00b6efa 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -814,7 +814,7 @@ static void client_ready_cb(bool success, uint8_t att_ecode, void *user_data)
goto fail;
}

- if (!bt_hog_attach(dev->hog, dev->attrib)) {
+ if (!bt_hog_attach(dev->hog, dev->attrib, dev->client)) {
error("HoG: unable to attach");
goto fail;
}
@@ -862,7 +862,7 @@ static void hog_conn_cb(const bdaddr_t *addr, int err, void *attrib)
if (!dev->hog) {
/* TODO: Get device details */
dev->hog = bt_hog_new_default("bluez-input-device", dev->vendor,
- dev->product, dev->version, NULL);
+ dev->product, dev->version, NULL, 0);
if (!dev->hog) {
error("HoG: unable to create session");
goto fail;
diff --git a/android/hog.c b/android/hog.c
index ff77bb3..931ac0b 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -45,6 +45,9 @@
#include "src/shared/util.h"
#include "src/shared/uhid.h"
#include "src/shared/queue.h"
+#include "src/shared/att.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-client.h"
#include "src/log.h"

#include "attrib/att.h"
@@ -79,6 +82,7 @@

struct bt_hog {
int ref_count;
+ uint16_t service_handle;
char *name;
uint16_t vendor;
uint16_t product;
@@ -103,6 +107,7 @@ struct bt_hog {
struct queue *bas;
GSList *instances;
struct queue *gatt_op;
+ struct bt_gatt_client *client;
};

struct report {
@@ -1173,14 +1178,15 @@ static void hog_free(void *data)

struct bt_hog *bt_hog_new_default(const char *name, uint16_t vendor,
uint16_t product, uint16_t version,
- void *primary)
+ void *primary, uint16_t service_handle)
{
- return bt_hog_new(-1, name, vendor, product, version, primary);
+ return bt_hog_new(-1, name, vendor, product, version, primary,
+ service_handle);
}

struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
uint16_t product, uint16_t version,
- void *primary)
+ void *primary, uint16_t service_handle)
{
struct bt_hog *hog;

@@ -1211,6 +1217,9 @@ struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
if (primary)
hog->primary = g_memdup(primary, sizeof(*hog->primary));

+ if (service_handle)
+ hog->service_handle = service_handle;
+
return bt_hog_ref(hog);
}

@@ -1321,14 +1330,14 @@ static void hog_attach_hog(struct bt_hog *hog, struct gatt_primary *primary)
}

instance = bt_hog_new(hog->uhid_fd, hog->name, hog->vendor,
- hog->product, hog->version, primary);
+ hog->product, hog->version, primary, 0);
if (!instance)
return;

find_included(instance, hog->attrib, primary->range.start,
primary->range.end, find_included_cb, instance);

- bt_hog_attach(instance, hog->attrib);
+ bt_hog_attach(instance, hog->attrib, hog->client);
hog->instances = g_slist_append(hog->instances, instance);
}

@@ -1377,15 +1386,16 @@ static void primary_cb(uint8_t status, GSList *services, void *user_data)
}
}

-bool bt_hog_attach(struct bt_hog *hog, void *gatt)
+bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)
{
struct gatt_primary *primary = hog->primary;
GSList *l;

- if (hog->attrib)
+ if (hog->attrib || hog->client)
return false;

hog->attrib = g_attrib_ref(gatt);
+ hog->client = bt_gatt_client_ref(client);

if (!primary) {
discover_primary(hog, hog->attrib, NULL, primary_cb, hog);
@@ -1403,7 +1413,7 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt)
for (l = hog->instances; l; l = l->next) {
struct bt_hog *instance = l->data;

- bt_hog_attach(instance, gatt);
+ bt_hog_attach(instance, gatt, client);
}

if (hog->reports == NULL) {
@@ -1429,7 +1439,7 @@ void bt_hog_detach(struct bt_hog *hog)
{
GSList *l;

- if (!hog->attrib)
+ if (!hog->attrib || !hog->client)
return;

queue_foreach(hog->bas, (void *) bt_bas_detach, NULL);
@@ -1456,6 +1466,8 @@ void bt_hog_detach(struct bt_hog *hog)
bt_dis_detach(hog->dis);

queue_foreach(hog->gatt_op, (void *) cancel_gatt_req, NULL);
+ bt_gatt_client_unref(hog->client);
+ hog->client = NULL;
g_attrib_unref(hog->attrib);
hog->attrib = NULL;
}
diff --git a/android/hog.h b/android/hog.h
index 2a9b899..61d756c 100644
--- a/android/hog.h
+++ b/android/hog.h
@@ -25,16 +25,16 @@ struct bt_hog;

struct bt_hog *bt_hog_new_default(const char *name, uint16_t vendor,
uint16_t product, uint16_t version,
- void *primary);
+ void *primary, uint16_t service_handle);

struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor,
uint16_t product, uint16_t version,
- void *primary);
+ void *primary, uint16_t service_handle);

struct bt_hog *bt_hog_ref(struct bt_hog *hog);
void bt_hog_unref(struct bt_hog *hog);

-bool bt_hog_attach(struct bt_hog *hog, void *gatt);
+bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client);
void bt_hog_detach(struct bt_hog *hog);

int bt_hog_set_control_point(struct bt_hog *hog, bool suspend);
diff --git a/unit/test-hog.c b/unit/test-hog.c
index 2a25d09..c7c64e4 100644
--- a/unit/test-hog.c
+++ b/unit/test-hog.c
@@ -196,7 +196,7 @@ static struct context *create_context(gconstpointer data)
fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
g_assert(fd > 0);

- context->hog = bt_hog_new(fd, name, vendor, product, version, NULL);
+ context->hog = bt_hog_new(fd, name, vendor, product, version, NULL, 0);
g_assert(context->hog);

channel = g_io_channel_unix_new(sv[1]);
@@ -222,7 +222,7 @@ static void test_hog(gconstpointer data)
{
struct context *context = create_context(data);

- g_assert(bt_hog_attach(context->hog, context->attrib));
+ g_assert(bt_hog_attach(context->hog, context->attrib, NULL));
}

int main(int argc, char *argv[])
--
1.9.1


2015-04-03 13:43:30

by Mariusz Skamra

[permalink] [raw]
Subject: [PATCHv2 01/27] android/hidhost: Create bt_gatt_client

From: Mariusz Skamra <[email protected]>

This patch introduces bt_gatt_client to be used by HoG profile.
As long as the android/gatt doesn't use bt_gatt_client, initialization
can be performed here.
---
android/Android.mk | 2 ++
android/hidhost.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 66 insertions(+), 11 deletions(-)

diff --git a/android/Android.mk b/android/Android.mk
index f218805..b9dd1c8 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -72,6 +72,8 @@ LOCAL_SRC_FILES := \
bluez/src/shared/crypto.c \
bluez/src/shared/uhid.c \
bluez/src/shared/att.c \
+ bluez/src/shared/gatt-helpers.c \
+ bluez/src/shared/gatt-client.c \
bluez/src/sdpd-database.c \
bluez/src/sdpd-service.c \
bluez/src/sdpd-request.c \
diff --git a/android/hidhost.c b/android/hidhost.c
index 729b884..26a8013 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -36,15 +36,22 @@

#include "btio/btio.h"
#include "lib/bluetooth.h"
+#include "lib/uuid.h"
#include "lib/sdp.h"
#include "lib/sdp_lib.h"
#include "src/shared/mgmt.h"
+#include "src/shared/queue.h"
#include "src/shared/util.h"
#include "src/shared/uhid.h"
+#include "src/shared/att.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-client.h"
#include "src/sdp-client.h"
#include "src/uuid-helper.h"
#include "src/log.h"

+#include "attrib/gattrib.h"
+
#include "hal-msg.h"
#include "ipc-common.h"
#include "ipc.h"
@@ -113,6 +120,9 @@ struct hid_device {
uint8_t last_hid_msg;
struct bt_hog *hog;
int sec_level;
+ GAttrib *attrib;
+ struct gatt_db *db;
+ struct bt_gatt_client *client;
};

static int device_cmp(gconstpointer s, gconstpointer user_data)
@@ -145,6 +155,9 @@ static void hid_device_free(void *data)
if (dev->hog)
bt_hog_unref(dev->hog);

+ if (dev->db)
+ gatt_db_unref(dev->db);
+
g_free(dev->rd_data);
g_free(dev);
}
@@ -792,10 +805,37 @@ fail:
hid_device_remove(dev);
}

+static void client_ready_cb(bool success, uint8_t att_ecode, void *user_data)
+{
+ struct hid_device *dev = user_data;
+
+ if (!success) {
+ error("HoG: client not ready");
+ goto fail;
+ }
+
+ if (!bt_hog_attach(dev->hog, dev->attrib)) {
+ error("HoG: unable to attach");
+ goto fail;
+ }
+
+ bt_hid_notify_state(dev, HAL_HIDHOST_STATE_CONNECTED);
+
+ if (!bt_gatt_add_autoconnect(hog_app, &dev->dst))
+ error("HoG: Could not add to autoconnect list");
+
+ return;
+fail:
+ bt_hid_notify_state(dev, HAL_HIDHOST_STATE_DISCONNECTED);
+ hid_device_remove(dev);
+}
+
static void hog_conn_cb(const bdaddr_t *addr, int err, void *attrib)
{
GSList *l;
struct hid_device *dev;
+ struct bt_att *att;
+ uint16_t mtu;

l = g_slist_find_custom(devices, addr, device_cmp);
dev = l ? l->data : NULL;
@@ -807,6 +847,10 @@ static void hog_conn_cb(const bdaddr_t *addr, int err, void *attrib)
bt_hid_notify_state(dev,
HAL_HIDHOST_STATE_DISCONNECTED);
bt_hog_detach(dev->hog);
+ bt_gatt_client_unref(dev->client);
+ g_attrib_unref(dev->attrib);
+ dev->attrib = NULL;
+ dev->client = NULL;
return;
}
goto fail;
@@ -816,34 +860,43 @@ static void hog_conn_cb(const bdaddr_t *addr, int err, void *attrib)
dev = hid_device_new(addr);

if (!dev->hog) {
- /* TODO: Get device details and primary */
+ /* TODO: Get device details */
dev->hog = bt_hog_new_default("bluez-input-device", dev->vendor,
dev->product, dev->version, NULL);
if (!dev->hog) {
error("HoG: unable to create session");
goto fail;
}
- }

- if (!bt_hog_attach(dev->hog, attrib)) {
- error("HoG: unable to attach");
- goto fail;
+ dev->db = gatt_db_new();
+ if (!dev->db) {
+ error("HoG: unable to create gatt_db");
+ goto fail;
+ }
}

- if (!bt_gatt_set_security(addr, BT_IO_SEC_MEDIUM)) {
+ att = g_attrib_get_att(attrib);
+ dev->attrib = g_attrib_ref(attrib);
+ mtu = bt_att_get_mtu(att);
+
+ /* Enable encryption before gatt_client starts discovering services */
+ if (!bt_att_set_sec_level(att, BT_SECURITY_MEDIUM)) {
error("Failed to set security level");
goto fail;
}

DBG("");

- bt_hid_notify_state(dev, HAL_HIDHOST_STATE_CONNECTED);
-
- if (!bt_gatt_add_autoconnect(hog_app, &dev->dst))
- error("hidhost: Could not add to autoconnect list");
+ dev->client = bt_gatt_client_new(dev->db, att, mtu);
+ if (!dev->client) {
+ error("Failed to create gatt_client");
+ goto fail;
+ }

+ /* Wait until client is initialized */
+ bt_gatt_client_set_ready_handler(dev->client, client_ready_cb,
+ dev, NULL);
return;
-
fail:
bt_hid_notify_state(dev, HAL_HIDHOST_STATE_DISCONNECTED);
hid_device_remove(dev);
--
1.9.1