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.
Mariusz Skamra (28):
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 definitions of characteristic uuids with bt_uuids
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: Add MIN definition
android/hog: Remove attrib/
android/hog: Remove glib dependencies
android/hog: Remove redundant code
android/Android.mk | 2 +
android/bas.c | 312 +++----------
android/bas.h | 4 +-
android/dis.c | 203 ++-------
android/dis.h | 4 +-
android/hidhost.c | 80 +++-
android/hog.c | 1132 ++++++++++++++++------------------------------
android/hog.h | 12 +-
android/scpp.c | 262 +++--------
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, 646 insertions(+), 1388 deletions(-)
--
1.9.1
Hi Mariusz,
On Wednesday 01 of April 2015 18:40:43 Mariusz Skamra wrote:
> All the glib functions and types have been replaced so that
> glib can be excluded
> ---
> android/hog.c | 27 +++++++++++++--------------
> 1 file changed, 13 insertions(+), 14 deletions(-)
>
> diff --git a/android/hog.c b/android/hog.c
> index c2017f8..a18275e 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"
> @@ -93,7 +91,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;
> @@ -263,9 +261,10 @@ 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);
This can return NULL.
> + memcpy(report->value, value, len);
> report->len = len;
> }
>
> @@ -274,7 +273,7 @@ static struct report *report_new(struct bt_hog *hog,
> uint16_t value_handle, {
> struct report *report;
>
> - report = g_new0(struct report, 1);
> + report = new0(struct report, 1);
Ditto.
> report->hog = hog;
> report->decl = new0(struct gatt_char, 1);
> report->decl->value_handle = value_handle;
> @@ -600,7 +599,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) {
> @@ -752,7 +751,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));
>
> @@ -854,9 +853,9 @@ static void report_free(void *data)
> {
> struct report *report = data;
>
> - g_free(report->value);
> + free(report->value);
> free(report->decl);
> - g_free(report);
> + free(report);
> }
>
> static void hog_free(void *data)
> @@ -872,8 +871,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,
> @@ -892,7 +891,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;
>
> @@ -912,7 +911,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);
Ditto.
> hog->vendor = vendor;
> hog->product = product;
> hog->version = version;
--
BR
Szymon Janc
On Wednesday 01 of April 2015 18:40:42 Mariusz Skamra wrote:
> All the attrib/ include files can be now removed since all the dependencies
> have been previously removed.
Make this commit subject a bit more intuitive, my first impression was 'why to
remove attrib/ folder in hog patch' :)
> ---
> android/hidhost.c | 2 +-
> android/hog.c | 62
> +++++++++++++++++++++++++++---------------------------- android/hog.h |
> 2 +-
> unit/test-hog.c | 2 +-
> 4 files changed, 33 insertions(+), 35 deletions(-)
>
> diff --git a/android/hidhost.c b/android/hidhost.c
> index 3d4ee85..9bd96a1 100644
> --- a/android/hidhost.c
> +++ b/android/hidhost.c
> @@ -816,7 +816,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 eb9c9d4..c2017f8 100644
> --- a/android/hog.c
> +++ b/android/hog.c
> @@ -50,10 +50,6 @@
> #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"
> @@ -94,7 +90,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;
> @@ -116,6 +111,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;
> @@ -162,8 +162,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);
Hmm I think we could have similar code2str function in src/shared/att.
> return;
> }
>
> @@ -201,8 +201,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;
> }
>
> @@ -258,8 +258,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;
> }
>
> @@ -312,8 +311,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;
> }
>
> @@ -403,7 +402,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;
> }
> }
> @@ -414,6 +413,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]);
> @@ -433,12 +433,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);
> @@ -490,7 +491,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)
> @@ -562,7 +563,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;
> }
>
> @@ -738,7 +739,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;
> }
>
> @@ -776,7 +777,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;
> }
>
> @@ -800,8 +801,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;
> }
>
> @@ -1022,7 +1023,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);
> }
>
> @@ -1049,14 +1050,13 @@ 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 = bt_gatt_client_get_db(hog->client);
>
> @@ -1077,7 +1077,7 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt,
> void *client) while (hog_entry) {
> struct bt_hog *instance = hog_entry->data;
>
> - bt_hog_attach(instance, gatt, client);
> + bt_hog_attach(instance, client);
> }
>
> if (queue_isempty(hog->reports)) {
> @@ -1096,7 +1096,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);
> @@ -1111,9 +1111,7 @@ void bt_hog_detach(struct bt_hog *hog)
>
> gatt_db_unref(hog->db);
> bt_gatt_client_unref(hog->client);
> - g_attrib_unref(hog->attrib);
> hog->client = NULL;
> - hog->attrib = NULL;
> }
>
> int bt_hog_set_control_point(struct bt_hog *hog, bool suspend)
> @@ -1149,13 +1147,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[])
--
BR
Szymon Janc
Hi Mariusz,
On Wednesday 01 of April 2015 18:40:41 Mariusz Skamra wrote:
> It's needed to delete attrib, where the previous definition was.
Just squeeze this patch with one that requires this macro.
> ---
> android/hog.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/android/hog.c b/android/hog.c
> index 9276d40..eb9c9d4 100644
> --- a/android/hog.c
> +++ b/android/hog.c
> @@ -59,6 +59,10 @@
> #include "android/bas.h"
> #include "android/hog.h"
>
> +#ifndef MIN
> +#define MIN(a, b) (((a) < (b)) ? (a) : (b))
> +#endif
> +
> #define HOG_REPORT_TYPE_INPUT 1
> #define HOG_REPORT_TYPE_OUTPUT 2
> #define HOG_REPORT_TYPE_FEATURE 3
--
BR
Szymon Janc
Hi Mariusz,
On Wednesday 01 of April 2015 18:40:38 Mariusz Skamra wrote:
> 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 shared.
shared code is required to be LGPL so I'd just skip this patch for now.
> ---
> 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 98eceee..3d4ee85 100644
> --- a/android/hidhost.c
> +++ b/android/hidhost.c
> @@ -862,7 +862,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 4565e86..b5b772c 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"
> @@ -82,9 +80,12 @@ static const bt_uuid_t report_uuid = { .type = BT_UUID16,
> static const bt_uuid_t protocol_mode_uuid = { .type = BT_UUID16,
> .value.u16 = 0x2A4E };
>
> +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;
> @@ -694,22 +695,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;
> @@ -881,15 +873,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;
>
> @@ -917,6 +912,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;
> @@ -1017,7 +1014,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]);
--
BR
Szymon Janc
Hi Mariusz,
On Wednesday 01 of April 2015 18:40:37 Mariusz Skamra wrote:
> This patch replaces gattrib with bt_gatt_client and strips glib
> dependencies. ---
> android/bas.c | 162
> ++++++++++++++++++---------------------------------------- android/bas.h |
> 4 +-
> android/hog.c | 40 ++-------------
> 3 files changed, 57 insertions(+), 149 deletions(-)
>
> diff --git a/android/bas.c b/android/bas.c
> index c5de3b1..3b641eb 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,76 @@ 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 = 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 78c1b26..4565e86 100644
> --- a/android/hog.c
> +++ b/android/hog.c
> @@ -990,15 +990,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);
> }
>
> @@ -1025,34 +1025,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;
> @@ -1073,8 +1045,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)
> @@ -1090,7 +1061,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;
> }
>
> @@ -1100,7 +1070,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) {
--
BR
Szymon Janc
Hi Mariusz,
On Wednesday 01 of April 2015 18:40:34 Mariusz Skamra wrote:
> From: Mariusz Skamra <[email protected]>
>
> This patch replaces gattrib with bt_gatt_client and strips glib
> dependencies. ---
> android/hog.c | 18 ++----
> android/scpp.c | 196
> +++++++++++++++++++++------------------------------------ android/scpp.h |
> 4 +-
> 3 files changed, 80 insertions(+), 138 deletions(-)
>
> diff --git a/android/hog.c b/android/hog.c
> index 71f8c50..78c1b26 100644
> --- a/android/hog.c
> +++ b/android/hog.c
> @@ -954,16 +954,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,
> @@ -1047,11 +1047,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);
> }
> @@ -1074,8 +1069,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))
> @@ -1101,7 +1095,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..37bd82e 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,122 @@ 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 = 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);
Missing 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);
--
BR
Szymon Janc
Hi Mariusz,
On Wednesday 01 of April 2015 18:40:30 Mariusz Skamra wrote:
> 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 e1ccaf3..9f4ca44 100644
> --- a/android/hog.c
> +++ b/android/hog.c
> @@ -106,7 +106,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;
> };
> @@ -870,7 +870,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);
> @@ -899,6 +899,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();
> @@ -907,7 +908,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;
> }
> @@ -1021,7 +1022,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)
> @@ -1090,7 +1091,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;
> @@ -1113,8 +1114,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);
> }
> @@ -1135,19 +1137,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)
> @@ -1182,7 +1176,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;
> @@ -1207,10 +1201,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;
> }
I think queue_get_entries() was meant to be used for early breaking from loop.
Why not just use queue_foreach() when doing foreach loop?
>
> return 0;
--
BR
Szymon Janc
Hi Mariusz,
On Wednesday 01 of April 2015 18:40:29 Mariusz Skamra wrote:
> 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 08196d4..e1ccaf3 100644
> --- a/android/hog.c
> +++ b/android/hog.c
> @@ -61,12 +61,6 @@
> #include "android/bas.h"
> #include "android/hog.h"
>
> -#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
> @@ -77,6 +71,17 @@
> #define HOG_REPORT_MAP_MAX_SIZE 512
> #define HID_INFO_SIZE 4
>
> +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 };
We usually keep those as defines and create by_uuid where needed. Since this
is used only in discovery (ie not performance critical) I'd just skip this
patch for now.
> +
> struct bt_hog {
> int ref_count;
> uint16_t service_handle;
> @@ -300,7 +305,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;
>
> @@ -315,12 +319,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();
> @@ -329,7 +333,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))
> @@ -823,18 +826,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);
>
> @@ -849,11 +845,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;
> }
> }
--
BR
Szymon Janc
Hi Mariusz,
On Wednesday 01 of April 2015 18:40:25 Mariusz Skamra wrote:
> 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 | 299
> ++++++++++++++++++++++-------------------------------- android/hog.h |
> 4 +-
> unit/test-hog.c | 2 +-
> 4 files changed, 125 insertions(+), 182 deletions(-)
>
> diff --git a/android/hidhost.c b/android/hidhost.c
> index 47e5840..8513a1d 100644
> --- a/android/hidhost.c
> +++ b/android/hidhost.c
> @@ -864,7 +864,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 85a2b6a..5b93cb5 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,19 @@ 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);
Shouldn't chrs queue be destroyed before returning from function?
> }
>
> static int report_cmp(gconstpointer a, gconstpointer b)
> @@ -824,21 +786,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 +802,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 +830,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 +848,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 +887,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 +914,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 +971,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 +1028,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 +1067,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 = 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 +1090,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 +1141,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);
> g_attrib_unref(hog->attrib);
> hog->client = NULL;
> 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]);
--
BR
Szymon Janc
Hi Mariusz,
On Wednesday 01 of April 2015 18:40:19 Mariusz Skamra 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..877abea 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 0;
Should be NULL instead of 0. I wonder why GCC didn't warn on this since
Wint-to-pointer-cast is enabled by default.
> +
> + return gatt_db_ref(client->db);
I'd leave getting reference to the user instead of doing this implicitly in
bt_gatt_client_get_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);
--
BR
Szymon Janc
Hi Mariusz,
On Wednesday 01 of April 2015 18:40:18 Mariusz Skamra 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 3da1130..47e5840 100644
> --- a/android/hidhost.c
> +++ b/android/hidhost.c
> @@ -818,7 +818,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;
> }
> @@ -864,7 +864,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..5b8c079 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,7 +1466,9 @@ 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);
> g_attrib_unref(hog->attrib);
> + hog->client = NULL;
> hog->attrib = NULL;
Usually we do this like:
unref(foo);
foo = NULL;
unref(bar);
bar = 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[])
--
BR
Szymon Janc
Hi Mariusz,
On Wednesday 01 of April 2015 18:40:17 Mariusz Skamra 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, 65
> insertions(+), 12 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..3da1130 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)
> @@ -142,8 +152,15 @@ static void hid_device_free(void *data)
> if (dev->uhid)
> bt_uhid_unref(dev->uhid);
>
> - if (dev->hog)
> + if (dev->hog) {
> bt_hog_unref(dev->hog);
> + dev->hog = NULL;
> + }
dev is freed few lines later so setting dev->hog to NULL shouldn't be needed.
> +
> + if (dev->db) {
> + gatt_db_unref(dev->db);
> + dev->db = NULL;
> + }
Same here.
>
> g_free(dev->rd_data);
> g_free(dev);
> @@ -792,10 +809,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 +851,8 @@ 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);
Shouldn't we NULL those to avoid dangling pointers?
> return;
> }
> goto fail;
> @@ -816,34 +862,39 @@ 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);
This can return NULL.
>
> + /* 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);
--
BR
Szymon Janc
---
android/hog.c | 8 --------
1 file changed, 8 deletions(-)
diff --git a/android/hog.c b/android/hog.c
index a18275e..9f64e41 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"
@@ -64,9 +59,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 const bt_uuid_t info_uuid = { .type = BT_UUID16,
.value.u16 = 0x2A4A };
static const bt_uuid_t report_map_uuid = { .type = BT_UUID16,
--
1.9.1
All the glib functions and types have been replaced so that
glib can be excluded
---
android/hog.c | 27 +++++++++++++--------------
1 file changed, 13 insertions(+), 14 deletions(-)
diff --git a/android/hog.c b/android/hog.c
index c2017f8..a18275e 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"
@@ -93,7 +91,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;
@@ -263,9 +261,10 @@ 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);
+ memcpy(report->value, value, len);
report->len = len;
}
@@ -274,7 +273,7 @@ static struct report *report_new(struct bt_hog *hog, uint16_t value_handle,
{
struct report *report;
- report = g_new0(struct report, 1);
+ report = new0(struct report, 1);
report->hog = hog;
report->decl = new0(struct gatt_char, 1);
report->decl->value_handle = value_handle;
@@ -600,7 +599,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) {
@@ -752,7 +751,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));
@@ -854,9 +853,9 @@ static void report_free(void *data)
{
struct report *report = data;
- g_free(report->value);
+ free(report->value);
free(report->decl);
- g_free(report);
+ free(report);
}
static void hog_free(void *data)
@@ -872,8 +871,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,
@@ -892,7 +891,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;
@@ -912,7 +911,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
All the attrib/ include files can be now removed since all the dependencies
have been previously removed.
---
android/hidhost.c | 2 +-
android/hog.c | 62 +++++++++++++++++++++++++++----------------------------
android/hog.h | 2 +-
unit/test-hog.c | 2 +-
4 files changed, 33 insertions(+), 35 deletions(-)
diff --git a/android/hidhost.c b/android/hidhost.c
index 3d4ee85..9bd96a1 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -816,7 +816,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 eb9c9d4..c2017f8 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -50,10 +50,6 @@
#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"
@@ -94,7 +90,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;
@@ -116,6 +111,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;
@@ -162,8 +162,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;
}
@@ -201,8 +201,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;
}
@@ -258,8 +258,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;
}
@@ -312,8 +311,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;
}
@@ -403,7 +402,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;
}
}
@@ -414,6 +413,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]);
@@ -433,12 +433,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);
@@ -490,7 +491,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)
@@ -562,7 +563,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;
}
@@ -738,7 +739,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;
}
@@ -776,7 +777,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;
}
@@ -800,8 +801,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;
}
@@ -1022,7 +1023,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);
}
@@ -1049,14 +1050,13 @@ 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 = bt_gatt_client_get_db(hog->client);
@@ -1077,7 +1077,7 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt, void *client)
while (hog_entry) {
struct bt_hog *instance = hog_entry->data;
- bt_hog_attach(instance, gatt, client);
+ bt_hog_attach(instance, client);
}
if (queue_isempty(hog->reports)) {
@@ -1096,7 +1096,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);
@@ -1111,9 +1111,7 @@ void bt_hog_detach(struct bt_hog *hog)
gatt_db_unref(hog->db);
bt_gatt_client_unref(hog->client);
- g_attrib_unref(hog->attrib);
hog->client = NULL;
- hog->attrib = NULL;
}
int bt_hog_set_control_point(struct bt_hog *hog, bool suspend)
@@ -1149,13 +1147,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
It's needed to delete attrib, where the previous definition was.
---
android/hog.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/android/hog.c b/android/hog.c
index 9276d40..eb9c9d4 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -59,6 +59,10 @@
#include "android/bas.h"
#include "android/hog.h"
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
#define HOG_REPORT_TYPE_INPUT 1
#define HOG_REPORT_TYPE_OUTPUT 2
#define HOG_REPORT_TYPE_FEATURE 3
--
1.9.1
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 b5b772c..9276d40 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -210,8 +210,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,
@@ -717,6 +715,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
---
android/bas.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/android/bas.c b/android/bas.c
index 3b641eb..ab33d59 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
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
This patch replaces gattrib with bt_gatt_client and strips glib dependencies.
---
android/bas.c | 162 ++++++++++++++++++----------------------------------------
android/bas.h | 4 +-
android/hog.c | 40 ++-------------
3 files changed, 57 insertions(+), 149 deletions(-)
diff --git a/android/bas.c b/android/bas.c
index c5de3b1..3b641eb 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,76 @@ 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 = 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);
+ 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 78c1b26..4565e86 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -990,15 +990,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);
}
@@ -1025,34 +1025,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;
@@ -1073,8 +1045,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)
@@ -1090,7 +1061,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;
}
@@ -1100,7 +1070,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
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 shared.
---
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 98eceee..3d4ee85 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -862,7 +862,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 4565e86..b5b772c 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"
@@ -82,9 +80,12 @@ static const bt_uuid_t report_uuid = { .type = BT_UUID16,
static const bt_uuid_t protocol_mode_uuid = { .type = BT_UUID16,
.value.u16 = 0x2A4E };
+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;
@@ -694,22 +695,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;
@@ -881,15 +873,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;
@@ -917,6 +912,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;
@@ -1017,7 +1014,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
From: Mariusz Skamra <[email protected]>
This patch replaces gattrib with bt_gatt_client and strips glib dependencies.
---
android/hog.c | 18 ++----
android/scpp.c | 196 +++++++++++++++++++++------------------------------------
android/scpp.h | 4 +-
3 files changed, 80 insertions(+), 138 deletions(-)
diff --git a/android/hog.c b/android/hog.c
index 71f8c50..78c1b26 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -954,16 +954,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,
@@ -1047,11 +1047,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);
}
@@ -1074,8 +1069,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))
@@ -1101,7 +1095,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..37bd82e 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,122 @@ 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 = 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);
+ 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
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 37bd82e..bf0a3db 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
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
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..4a28c5a 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 = 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 9f4ca44..71f8c50 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -976,17 +976,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);
}
}
@@ -1052,11 +1052,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);
}
@@ -1082,8 +1077,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;
@@ -1110,7 +1104,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
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
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 08196d4..e1ccaf3 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -61,12 +61,6 @@
#include "android/bas.h"
#include "android/hog.h"
-#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
@@ -77,6 +71,17 @@
#define HOG_REPORT_MAP_MAX_SIZE 512
#define HID_INFO_SIZE 4
+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;
@@ -300,7 +305,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;
@@ -315,12 +319,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();
@@ -329,7 +333,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))
@@ -823,18 +826,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);
@@ -849,11 +845,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
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 e1ccaf3..9f4ca44 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -106,7 +106,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;
};
@@ -870,7 +870,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);
@@ -899,6 +899,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();
@@ -907,7 +908,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;
}
@@ -1021,7 +1022,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)
@@ -1090,7 +1091,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;
@@ -1113,8 +1114,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);
}
@@ -1135,19 +1137,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)
@@ -1182,7 +1176,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;
@@ -1207,10 +1201,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
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 e3e79cb..08196d4 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);
@@ -320,10 +338,8 @@ static void external_report_reference_cb(bool success, uint8_t status,
queue_foreach(chrs, external_service_char_cb, hog);
}
-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;
@@ -339,14 +355,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,
@@ -856,7 +879,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);
}
@@ -879,6 +902,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();
@@ -887,7 +911,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;
}
@@ -1099,7 +1123,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);
@@ -1108,14 +1132,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;
}
@@ -1135,15 +1152,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
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 8513a1d..98eceee 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 ac8c819..e3e79cb 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
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 | 299 ++++++++++++++++++++++--------------------------------
android/hog.h | 4 +-
unit/test-hog.c | 2 +-
4 files changed, 125 insertions(+), 182 deletions(-)
diff --git a/android/hidhost.c b/android/hidhost.c
index 47e5840..8513a1d 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -864,7 +864,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 85a2b6a..5b93cb5 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,19 @@ 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);
}
static int report_cmp(gconstpointer a, gconstpointer b)
@@ -824,21 +786,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 +802,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 +830,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 +848,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 +887,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 +914,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 +971,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 +1028,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 +1067,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 = 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 +1090,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 +1141,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);
g_attrib_unref(hog->attrib);
hog->client = NULL;
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
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 5b93cb5..ac8c819 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -666,15 +666,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));
@@ -704,39 +746,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
---
android/hog.c | 38 ++++++++++++++++++++------------------
1 file changed, 20 insertions(+), 18 deletions(-)
diff --git a/android/hog.c b/android/hog.c
index bcda1af..85a2b6a 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
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 3f28ecb..bcda1af 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
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 ec81f0f..3f28ecb 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
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 4c39ad7..ec81f0f 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
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 5b8c079..4c39ad7 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);
g_attrib_unref(hog->attrib);
hog->client = NULL;
@@ -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
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..877abea 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 0;
+
+ return gatt_db_ref(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
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 3da1130..47e5840 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -818,7 +818,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;
}
@@ -864,7 +864,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..5b8c079 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,7 +1466,9 @@ 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);
g_attrib_unref(hog->attrib);
+ hog->client = NULL;
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
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, 65 insertions(+), 12 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..3da1130 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)
@@ -142,8 +152,15 @@ static void hid_device_free(void *data)
if (dev->uhid)
bt_uhid_unref(dev->uhid);
- if (dev->hog)
+ if (dev->hog) {
bt_hog_unref(dev->hog);
+ dev->hog = NULL;
+ }
+
+ if (dev->db) {
+ gatt_db_unref(dev->db);
+ dev->db = NULL;
+ }
g_free(dev->rd_data);
g_free(dev);
@@ -792,10 +809,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 +851,8 @@ 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);
return;
}
goto fail;
@@ -816,34 +862,39 @@ 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);
+ /* 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