2014-04-09 07:06:58

by Marcin Kraglak

[permalink] [raw]
Subject: [RFC 00/16] Gatt database initial implementation

This is proposal how gatt database implementation could look and
how it can be used in Android. Current implementation contains:
- create/destroy gatt_db
- adding services, with given number of handles. This function returns
service attribute andle
- adding characteristics, descriptors and included services
- function to start/stop service - it will be used when we expose services
to client

Next steps in gatt_db implementation should be:
- handling read/write callbacks
- handling attribute's permissions
- now we just increment available handle. We should check if we have free handles
between existing services

Comments are welcome
Marcin Kraglak

Marcin Kraglak (16):
gatt: Add skeleton of gatt-db
gatt: Add services list to gatt_db struct
gatt: Add method for creating services in gatt_db
gatt: Remove service functionality
gatt: Add new sharacteristic functionality
gatt: Add characteristic descriptor method
gatt: Add included service functionality
android/gatt: Add service functionality
android/gatt: Add implementation of delete service
android/gatt: Add included service implementation
android/gatt: Add characteristic implementation
android/gatt: Add descriptor implementation
gatt: Add start/stop service functionality
android/gatt: Add handling of start service command
android/gatt: Add stop service command handling
android/gatt: Fix typo in event handlers array

android/Android.mk | 1 +
android/Makefile.am | 1 +
android/gatt.c | 242 +++++++++++++++++++++++++++++++-
android/hal-gatt.c | 2 +-
src/shared/gatt-db.c | 388 +++++++++++++++++++++++++++++++++++++++++++++++++++
src/shared/gatt-db.h | 67 +++++++++
6 files changed, 693 insertions(+), 8 deletions(-)
create mode 100644 src/shared/gatt-db.c
create mode 100644 src/shared/gatt-db.h

--
1.8.5.3



2014-04-16 12:25:32

by Claudio Takahasi

[permalink] [raw]
Subject: Re: [RFC 01/16] gatt: Add skeleton of gatt-db

Hi Marcin,

On Mon, Apr 14, 2014 at 4:15 PM, Marcin Kraglak
<[email protected]> wrote:
> Hi Claudio,
>
> On 14 April 2014 16:12, Claudio Takahasi <[email protected]> wrote:
>> Hi Marcin,
>>
>> On Wed, Apr 9, 2014 at 4:06 AM, Marcin Kraglak <[email protected]> wrote:
>>> This change adds new() and destroy() fuctions for gatt_db,
>>> which will be used for storing local attributes.
>>> ---
>>> android/Android.mk | 1 +
>>> android/Makefile.am | 1 +
>>> src/shared/gatt-db.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
>>> src/shared/gatt-db.h | 27 +++++++++++++++++++++++++++
>>> 4 files changed, 76 insertions(+)
>>> create mode 100644 src/shared/gatt-db.c
>>> create mode 100644 src/shared/gatt-db.h
>>>
>>> diff --git a/android/Android.mk b/android/Android.mk
>>> index 5f4e70c..4c9cfb5 100644
>>> --- a/android/Android.mk
>>> +++ b/android/Android.mk
>>> @@ -51,6 +51,7 @@ LOCAL_SRC_FILES := \
>>> bluez/src/shared/queue.c \
>>> bluez/src/shared/ringbuf.c \
>>> bluez/src/shared/hfp.c \
>>> + bluez/src/shared/gatt-db.c \
>>> bluez/src/shared/io-glib.c \
>>> bluez/src/sdpd-database.c \
>>> bluez/src/sdpd-service.c \
>>> diff --git a/android/Makefile.am b/android/Makefile.am
>>> index c51cce2..70e1dec 100644
>>> --- a/android/Makefile.am
>>> +++ b/android/Makefile.am
>>> @@ -29,6 +29,7 @@ android_bluetoothd_SOURCES = android/main.c \
>>> src/shared/mgmt.h src/shared/mgmt.c \
>>> src/shared/ringbuf.h src/shared/ringbuf.c \
>>> src/shared/hfp.h src/shared/hfp.c \
>>> + src/shared/gatt-db.h src/shared/gatt-db.c \
>>> android/bluetooth.h android/bluetooth.c \
>>> android/hidhost.h android/hidhost.c \
>>> android/ipc-common.h \
>>> diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
>>> new file mode 100644
>>> index 0000000..e56b381
>>> --- /dev/null
>>> +++ b/src/shared/gatt-db.c
>>> @@ -0,0 +1,47 @@
>>> +/*
>>> + *
>>> + * BlueZ - Bluetooth protocol stack for Linux
>>> + *
>>> + * Copyright (C) 2014 Intel Corporation. All rights reserved.
>>> + *
>>> + *
>>> + * This library is free software; you can redistribute it and/or
>>> + * modify it under the terms of the GNU Lesser General Public
>>> + * License as published by the Free Software Foundation; either
>>> + * version 2.1 of the License, or (at your option) any later version.
>>> + *
>>> + * This library is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>>> + * Lesser General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU Lesser General Public
>>> + * License along with this library; if not, write to the Free Software
>>> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
>>> + *
>>> + */
>>> +
>>> +#include "src/shared/util.h"
>>> +#include "src/shared/gatt-db.h"
>>> +
>>> +struct gatt_db {
>>> + uint16_t next_handle;
>>> +};
>>> +
>>> +struct gatt_db *gatt_db_new(void)
>>> +{
>>> + struct gatt_db *db;
>>> +
>>> + db = new0(struct gatt_db, 1);
>>> + if (!db)
>>> + return NULL;
>>> +
>>> + db->next_handle = 0x0001;
>>> +
>>> + return db;
>>> +}
>>
>> Are you considering to use the same function to allocate/create a
>> database to represent the remote "virtual" database?
>> My point is: the same infra-structure could be used to represent a
>> local database(per adapter maybe) or remote database.
>>
>
> We could add argument to new() like type: remote or local. What you
> think about it?

My intention was only to raise the possibility of having a common
database for both: client and servers.
We don't need to support it now, but we need to define a flexible
architecture to allow extending it later.

Claudio

2014-04-15 12:59:20

by Claudio Takahasi

[permalink] [raw]
Subject: Re: [RFC 15/16] android/gatt: Add stop service command handling

Hi Marcin,

On Wed, Apr 9, 2014 at 4:07 AM, Marcin Kraglak <[email protected]> wrote:
> It will stop service in local database.
> ---
> android/gatt.c | 26 +++++++++++++++++++++++++-
> 1 file changed, 25 insertions(+), 1 deletion(-)
>
> diff --git a/android/gatt.c b/android/gatt.c
> index edcb7aa..f5324f3 100644
> --- a/android/gatt.c
> +++ b/android/gatt.c
> @@ -2881,10 +2881,34 @@ failed:
>
> static void handle_server_stop_service(const void *buf, uint16_t len)
> {
> + const struct hal_cmd_gatt_server_stop_service *cmd = buf;
> + struct hal_ev_gatt_server_service_stopped ev;
> + struct gatt_server *server;
> + uint8_t status;

"status" could be initialized to "HAL_STATUS_FAILED"

> +
> DBG("");
>
> + server = find_server_by_id(cmd->server_if);
> + if (!server) {
> + status = HAL_STATUS_FAILED;
> + goto failed;
> + }
> +
> + if (!gatt_db_stop_service(gatt_db, cmd->service_handle))
> + status = HAL_STATUS_FAILED;
> + else
> + status = HAL_STATUS_SUCCESS;
> +
> +failed:
> + ev.status = status == HAL_STATUS_SUCCESS ? GATT_SUCCESS : GATT_FAILURE;

Use conversion helper (hal ->gatt)?

> + ev.server_if = cmd->server_if;
> + ev.srvc_handle = cmd->service_handle;
> +
> + ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
> + HAL_EV_GATT_SERVER_SERVICE_STOPPED, sizeof(ev), &ev);
> +
> ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
> - HAL_OP_GATT_SERVER_STOP_SERVICE, HAL_STATUS_FAILED);
> + HAL_OP_GATT_SERVER_STOP_SERVICE, status);
> }
>
> static void handle_server_delete_service(const void *buf, uint16_t len)
> --
> 1.8.5.3
>

Claudio

2014-04-15 12:59:00

by Claudio Takahasi

[permalink] [raw]
Subject: Re: [RFC 14/16] android/gatt: Add handling of start service command

Hi Marcin,

On Wed, Apr 9, 2014 at 4:07 AM, Marcin Kraglak <[email protected]> wrote:
> It will start service added to local database.
> ---
> android/gatt.c | 29 ++++++++++++++++++++++++++++-
> 1 file changed, 28 insertions(+), 1 deletion(-)
>
> diff --git a/android/gatt.c b/android/gatt.c
> index acaa2a9..edcb7aa 100644
> --- a/android/gatt.c
> +++ b/android/gatt.c
> @@ -2846,10 +2846,37 @@ failed:
>
> static void handle_server_start_service(const void *buf, uint16_t len)
> {
> + const struct hal_cmd_gatt_server_start_service *cmd = buf;
> + struct hal_ev_gatt_server_service_started ev;
> + struct gatt_server *server;
> + uint8_t status;

"status" could be initialized to "HAL_STATUS_FAILED"

> +
> DBG("");
>
> + server = find_server_by_id(cmd->server_if);
> + if (!server) {
> + status = HAL_STATUS_FAILED;
> + goto failed;
> + }
> +
> + if (!gatt_db_start_service(gatt_db, cmd->service_handle)) {
> + /* we ignore service now */
> + status = HAL_STATUS_FAILED;
> + goto failed;
> + }
> +
> + status = HAL_STATUS_SUCCESS;
> +
> +failed:
> + ev.status = status == HAL_STATUS_SUCCESS ? GATT_SUCCESS : GATT_FAILURE;

Use conversion helper (hal ->gatt)?

> + ev.server_if = cmd->server_if;
> + ev.srvc_handle = cmd->service_handle;
> +
> + ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
> + HAL_EV_GATT_SERVER_SERVICE_STARTED, sizeof(ev), &ev);
> +
> ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
> - HAL_OP_GATT_SERVER_START_SERVICE, HAL_STATUS_FAILED);
> + HAL_OP_GATT_SERVER_START_SERVICE, status);
> }
>
> static void handle_server_stop_service(const void *buf, uint16_t len)
> --
> 1.8.5.3
>

Claudio

2014-04-15 12:58:21

by Claudio Takahasi

[permalink] [raw]
Subject: Re: [RFC 12/16] android/gatt: Add descriptor implementation

Hi Marcin,

On Wed, Apr 9, 2014 at 4:07 AM, Marcin Kraglak <[email protected]> wrote:
> It will add characteristic descriptor attribute to local database.
> ---
> android/gatt.c | 34 +++++++++++++++++++++++++++++++++-
> 1 file changed, 33 insertions(+), 1 deletion(-)
>
> diff --git a/android/gatt.c b/android/gatt.c
> index 25cd7f1..acaa2a9 100644
> --- a/android/gatt.c
> +++ b/android/gatt.c
> @@ -2806,10 +2806,42 @@ failed:
>
> static void handle_server_add_descriptor(const void *buf, uint16_t len)
> {
> + const struct hal_cmd_gatt_server_add_descriptor *cmd = buf;
> + struct hal_ev_gatt_server_descriptor_added ev;
> + struct gatt_server *server;
> + bt_uuid_t uuid;
> + uint8_t status;

"status" could be initialized to " HAL_STATUS_FAILED"

> +
> DBG("");
>
> + server = find_server_by_id(cmd->server_if);
> + if (!server) {
> + status = HAL_STATUS_FAILED;
> + goto failed;
> + }
> +
> + android2uuid(cmd->uuid, &uuid);
> +
> + ev.descr_handle = gatt_db_new_char_descriptor(gatt_db,
> + cmd->service_handle,
> + &uuid, cmd->permissions,
> + NULL, NULL, NULL);

Read & Write callbacks are not informed here.

> + if (!ev.descr_handle)
> + status = HAL_STATUS_FAILED;
> + else
> + status = HAL_STATUS_SUCCESS;
> +
> +failed:
> + ev.server_if = cmd->server_if;
> + ev.srvc_handle = cmd->service_handle;
> + memcpy(ev.uuid, cmd->uuid, sizeof(cmd->uuid));
> + ev.status = status == HAL_STATUS_SUCCESS ? GATT_SUCCESS : GATT_FAILURE;

Use conversion helper (hal ->gatt) ?

> +
> + ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
> + HAL_EV_GATT_SERVER_DESCRIPTOR_ADDED, sizeof(ev), &ev);
> +
> ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
> - HAL_OP_GATT_SERVER_ADD_DESCRIPTOR, HAL_STATUS_FAILED);
> + HAL_OP_GATT_SERVER_ADD_DESCRIPTOR, status);
> }
>
> static void handle_server_start_service(const void *buf, uint16_t len)
> --
> 1.8.5.3

Claudio

2014-04-15 12:57:49

by Claudio Takahasi

[permalink] [raw]
Subject: Re: [RFC 11/16] android/gatt: Add characteristic implementation

Hi Marcin,

On Wed, Apr 9, 2014 at 4:07 AM, Marcin Kraglak <[email protected]> wrote:
> It will add characteristic declaration and value attributes to local database.
> ---
> android/gatt.c | 36 +++++++++++++++++++++++++++++++++++-
> 1 file changed, 35 insertions(+), 1 deletion(-)
>
> diff --git a/android/gatt.c b/android/gatt.c
> index 10e3dfd..25cd7f1 100644
> --- a/android/gatt.c
> +++ b/android/gatt.c
> @@ -2763,11 +2763,45 @@ failed:
>
> static void handle_server_add_characteristic(const void *buf, uint16_t len)
> {
> + const struct hal_cmd_gatt_server_add_characteristic *cmd = buf;
> + struct hal_ev_gatt_server_characteristic_added ev;
> + struct gatt_server *server;
> + bt_uuid_t uuid;
> + uint8_t status;

"status" could be initialized to "HAL_STATUS_FAILED"

> +
> DBG("");
>
> + server = find_server_by_id(cmd->server_if);
> + if (!server) {
> + status = HAL_STATUS_FAILED;
> + goto failed;
> + }
> +
> + android2uuid(cmd->uuid, &uuid);
> +
> + ev.char_handle = gatt_db_new_characteristic(gatt_db,
> + cmd->service_handle,
> + &uuid, cmd->permissions,
> + cmd->properties,
> + NULL, NULL, NULL);

Read & Write callbacks missing.

> + if (!ev.char_handle)
> + status = HAL_STATUS_FAILED;
> + else
> + status = HAL_STATUS_SUCCESS;
> +
> +failed:
> + ev.srvc_handle = cmd->service_handle;
> + ev.status = status;
> + ev.server_if = cmd->server_if;
> + ev.status = status == HAL_STATUS_SUCCESS ? GATT_SUCCESS : GATT_FAILURE;

Use conversion helper (hal ->gatt) ?

> + memcpy(ev.uuid, cmd->uuid, sizeof(cmd->uuid));
> +
> + ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
> + HAL_EV_GATT_SERVER_CHAR_ADDED, sizeof(ev), &ev);
> +
> ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
> HAL_OP_GATT_SERVER_ADD_CHARACTERISTIC,
> - HAL_STATUS_FAILED);
> + status);
> }
>
> static void handle_server_add_descriptor(const void *buf, uint16_t len)
> --
> 1.8.5.3

Claudio

2014-04-15 12:55:59

by Claudio Takahasi

[permalink] [raw]
Subject: Re: [RFC 10/16] android/gatt: Add included service implementation

Hi Marcin

On Wed, Apr 9, 2014 at 4:07 AM, Marcin Kraglak <[email protected]> wrote:
> It will add included service attribute to database.
> ---
> android/gatt.c | 31 ++++++++++++++++++++++++++++++-
> 1 file changed, 30 insertions(+), 1 deletion(-)
>
> diff --git a/android/gatt.c b/android/gatt.c
> index 5f054c7..10e3dfd 100644
> --- a/android/gatt.c
> +++ b/android/gatt.c
> @@ -2726,10 +2726,39 @@ failed:
>
> static void handle_server_add_included_service(const void *buf, uint16_t len)
> {
> + const struct hal_cmd_gatt_server_add_inc_service *cmd = buf;
> + struct hal_ev_gatt_server_inc_srvc_added ev;
> + struct gatt_server *server;
> + uint8_t status;

"status" could be initialized to " HAL_STATUS_FAILED"

> +
> DBG("");
>
> + server = find_server_by_id(cmd->server_if);
> + if (!server) {
> + status = HAL_STATUS_FAILED;
> + goto failed;
> + }
> +
> + ev.incl_srvc_handle = gatt_db_new_included_service(gatt_db,
> + cmd->service_handle,
> + cmd->included_handle);
> + if (!ev.incl_srvc_handle) {
> + status = HAL_STATUS_FAILED;
> + goto failed;
> + }
> +
> + status = HAL_STATUS_SUCCESS;

Missing empty line

> +failed:
> + ev.srvc_handle = cmd->service_handle;
> + ev.status = status;
> + ev.server_if = cmd->server_if;
> + ev.status = status == HAL_STATUS_SUCCESS ? GATT_SUCCESS : GATT_FAILURE;

Same comment here.

> +
> + ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
> + HAL_EV_GATT_SERVER_INC_SRVC_ADDED, sizeof(ev), &ev);
> +
> ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
> - HAL_OP_GATT_SERVER_ADD_INC_SERVICE, HAL_STATUS_FAILED);
> + HAL_OP_GATT_SERVER_ADD_INC_SERVICE, status);
> }
>
> static void handle_server_add_characteristic(const void *buf, uint16_t len)
> --

Claudio

2014-04-15 12:55:22

by Claudio Takahasi

[permalink] [raw]
Subject: Re: [RFC 09/16] android/gatt: Add implementation of delete service

Hi Marcin,

On Wed, Apr 9, 2014 at 4:07 AM, Marcin Kraglak <[email protected]> wrote:
> It will delete saervice from local database
> ---
> android/gatt.c | 30 +++++++++++++++++++++++++++++-
> 1 file changed, 29 insertions(+), 1 deletion(-)
>
> diff --git a/android/gatt.c b/android/gatt.c
> index 76753a8..5f054c7 100644
> --- a/android/gatt.c
> +++ b/android/gatt.c
> @@ -2767,10 +2767,38 @@ static void handle_server_stop_service(const void *buf, uint16_t len)
>
> static void handle_server_delete_service(const void *buf, uint16_t len)
> {
> + const struct hal_cmd_gatt_server_delete_service *cmd = buf;
> + struct hal_ev_gatt_server_service_deleted ev;
> + struct gatt_server *server;
> + uint8_t status;
> +

"status" could be initialized to "HAL_STATUS_FAILED"

> DBG("");
>
> + memset(&ev, 0, sizeof(ev));
> +
> + server = find_server_by_id(cmd->server_if);
> + if (!server) {
> + status = HAL_STATUS_FAILED;
> + goto failed;
> + }
> +
> + if (!gatt_db_remove_service(gatt_db, cmd->service_handle)) {
> + status = HAL_STATUS_FAILED;
> + goto failed;
> + }
> +
> + status = HAL_STATUS_SUCCESS;
> +
> +failed:
> + ev.status = status == HAL_STATUS_SUCCESS ? GATT_SUCCESS : GATT_FAILURE;

Same comment of the previous patch.

> + ev.srvc_handle = cmd->service_handle;
> + ev.server_if = cmd->server_if;
> +
> + ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
> + HAL_EV_GATT_SERVER_SERVICE_DELETED, sizeof(ev), &ev);
> +
> ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
> - HAL_OP_GATT_SERVER_DELETE_SERVICE, HAL_STATUS_FAILED);
> + HAL_OP_GATT_SERVER_DELETE_SERVICE, status);
> }
>
> static void handle_server_send_indication(const void *buf, uint16_t len)

Claudio

2014-04-15 12:54:52

by Claudio Takahasi

[permalink] [raw]
Subject: Re: [RFC 08/16] android/gatt: Add service functionality

Hi Marcin,

On Wed, Apr 9, 2014 at 4:07 AM, Marcin Kraglak <[email protected]> wrote:
> It will Add service to local database.
> ---
> android/gatt.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 55 insertions(+), 1 deletion(-)
>
> diff --git a/android/gatt.c b/android/gatt.c
> index a33ce25..76753a8 100644
> --- a/android/gatt.c
> +++ b/android/gatt.c
> @@ -43,6 +43,7 @@
> #include "utils.h"
> #include "src/shared/util.h"
> #include "src/shared/queue.h"
> +#include "src/shared/gatt-db.h"
> #include "attrib/gattrib.h"
> #include "attrib/att.h"
> #include "attrib/gatt.h"
> @@ -130,6 +131,8 @@ static struct queue *conn_list = NULL; /* Connected devices */
> static struct queue *conn_wait_queue = NULL; /* Devs waiting to connect */
> static struct queue *disc_dev_list = NULL; /* Disconnected devices */
>
> +static struct gatt_db *gatt_db = NULL;
> +
> static void bt_le_discovery_stop_cb(void);
>
> static void android2uuid(const uint8_t *uuid, bt_uuid_t *dst)
> @@ -2669,12 +2672,56 @@ static void handle_server_disconnect(const void *buf, uint16_t len)
> HAL_OP_GATT_SERVER_DISCONNECT, HAL_STATUS_FAILED);
> }
>
> +static struct gatt_server *find_server_by_id(int32_t id)
> +{
> + return queue_find(gatt_servers, match_server_by_id, INT_TO_PTR(id));
> +}
> +
> static void handle_server_add_service(const void *buf, uint16_t len)
> {
> + const struct hal_cmd_gatt_server_add_service *cmd = buf;
> + struct hal_ev_gatt_server_service_added ev;
> + enum gatt_db_service_type type;
> + struct gatt_server *server;
> + uint8_t status;
> + bt_uuid_t uuid;
> +
> DBG("");
>
> + memset(&ev, 0, sizeof(ev));
> +
> + server = find_server_by_id(cmd->server_if);
> + if (!server) {
> + status = HAL_STATUS_FAILED;
> + goto failed;
> + }
> +
> + if (cmd->srvc_id.is_primary)
> + type = GATT_DB_SERVICE_PRIMARY;
> + else
> + type = GATT_DB_SERVICE_SECONDARY;
> +
> + android2uuid(cmd->srvc_id.uuid, &uuid);
> +
> + ev.srvc_handle = gatt_db_new_service(gatt_db, &uuid, type,
> + cmd->num_handles);
> + if (!ev.srvc_handle) {
> + status = HAL_STATUS_FAILED;
> + goto failed;
> + }
> +
> + status = HAL_STATUS_SUCCESS;
> +
> +failed:
> + ev.status = status == HAL_STATUS_SUCCESS ? GATT_SUCCESS : GATT_FAILURE;

I am not sure how many errors are planned, maybe it will be more
convenient to add an error conversion helper: hal ->gatt

> + ev.srvc_id = cmd->srvc_id;
> + ev.server_if = cmd->server_if;
> +
> + ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
> + HAL_EV_GATT_SERVER_SERVICE_ADDED, sizeof(ev), &ev);
> +
> ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
> - HAL_OP_GATT_SERVER_ADD_SERVICE, HAL_STATUS_FAILED);
> + HAL_OP_GATT_SERVER_ADD_SERVICE, status);
> }
>
> static void handle_server_add_included_service(const void *buf, uint16_t len)
> @@ -2859,6 +2906,7 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
> gatt_clients = queue_new();
> gatt_servers = queue_new();
> disc_dev_list = queue_new();
> + gatt_db = gatt_db_new();
>
> if (!conn_list || !conn_wait_queue || !gatt_clients || !gatt_servers ||
> !disc_dev_list) {
> @@ -2879,6 +2927,9 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
> queue_destroy(disc_dev_list, NULL);
> disc_dev_list = NULL;
>
> + gatt_db_destroy(gatt_db);
> + gatt_db = NULL;
> +
> return false;
> }
>
> @@ -2913,4 +2964,7 @@ void bt_gatt_unregister(void)
>
> queue_destroy(disc_dev_list, destroy_device);
> disc_dev_list = NULL;
> +
> + gatt_db_destroy(gatt_db);
> + gatt_db = NULL;
> }
> --
> 1.8.5.3
>

Claudio

2014-04-15 12:53:30

by Claudio Takahasi

[permalink] [raw]
Subject: Re: [RFC 07/16] gatt: Add included service functionality

Hi Marcin,

On Wed, Apr 9, 2014 at 4:07 AM, Marcin Kraglak <[email protected]> wrote:
> It will add included service to service attribute list.
> ---
> src/shared/gatt-db.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
> src/shared/gatt-db.h | 3 +++
> 2 files changed, 47 insertions(+)
>
> diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
> index 26b36d9..2886bb8 100644
> --- a/src/shared/gatt-db.c
> +++ b/src/shared/gatt-db.c
> @@ -29,6 +29,7 @@
> #include "src/shared/gatt-db.h"
>
> #define MAX_CHAR_DECL_VALUE_LEN 19
> +#define MAX_INCLUDED_VALUE_LEN 6
>
> static const bt_uuid_t primary_service_uuid = { .type = BT_UUID16,
> .value.u16 = GATT_PRIM_SVC_UUID };
> @@ -36,6 +37,8 @@ static const bt_uuid_t secondary_service_uuid = { .type = BT_UUID16,
> .value.u16 = GATT_SND_SVC_UUID };
> static const bt_uuid_t characteristic_uuid = { .type = BT_UUID16,
> .value.u16 = GATT_CHARAC_UUID };
> +static const bt_uuid_t included_service_uuid = { .type = BT_UUID16,
> + .value.u16 = GATT_INCLUDE_UUID };
>
> struct gatt_db {
> uint16_t next_handle;
> @@ -314,3 +317,44 @@ uint16_t gatt_db_new_char_descriptor(struct gatt_db *db, uint16_t handle,
>
> return update_attribute_handle(service, i);
> }
> +
> +uint16_t gatt_db_new_included_service(struct gatt_db *db, uint16_t handle,
> + uint16_t included_handle)
> +{
> + struct gatt_db_service *included_service;
> + uint8_t value[MAX_INCLUDED_VALUE_LEN];
> + uint16_t len = sizeof(uint16_t) * 2;
> + struct gatt_db_service *service;
> + int index;
> +
> + service = queue_find(db->services, match_service_by_handle,
> + INT_TO_PTR(handle));
> + if (!service)
> + return 0;
> +
> + included_service = queue_find(db->services, match_service_by_handle,
> + INT_TO_PTR(included_handle));

Circular references may occur.

> +
> + if (!included_service)
> + return 0;
> +
> + put_le16(included_handle, &value[0]);
> + put_le16(included_handle + included_service->num_handles - 1,
> + &value[2]);

According to the BT core spec:
"The Service UUID shall only be present when the UUID is a 16-bit
Bluetooth UUID"

It'd be relevant to add this comment here.

> + if (included_service->attributes[0]->val_len == 2) {
> + memcpy(&value[4], included_service->attributes[0]->value,
> + included_service->attributes[0]->val_len);
> + len += included_service->attributes[0]->val_len;
> + }
> +
> + index = get_attribute_index(service, 1);
> + if (!index)
> + return 0;
> +
> + service->attributes[index] = new_attribute(&included_service_uuid,
> + value, len);
> + if (!service->attributes[index])
> + return 0;
> +
> + return update_attribute_handle(service, index);
> +}
> diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
> index 1191614..a421e9e 100644
> --- a/src/shared/gatt-db.h
> +++ b/src/shared/gatt-db.h
> @@ -58,3 +58,6 @@ uint16_t gatt_db_new_char_descriptor(struct gatt_db *db, uint16_t handle,
> gatt_db_read_t read_func,
> gatt_db_write_t write_func,
> void *user_data);
> +

Please add a brief description here

> +uint16_t gatt_db_new_included_service(struct gatt_db *db, uint16_t handle,
> + uint16_t included_handle);
> --
> 1.8.5.3
>

Claudio

2014-04-15 12:51:34

by Claudio Takahasi

[permalink] [raw]
Subject: Re: [RFC 06/16] gatt: Add characteristic descriptor method

Hi Marcin,

On Wed, Apr 9, 2014 at 4:07 AM, Marcin Kraglak <[email protected]> wrote:
> It will add characteristic descriptor to service attribute's list.
> ---
> src/shared/gatt-db.c | 29 +++++++++++++++++++++++++++++
> src/shared/gatt-db.h | 7 +++++++
> 2 files changed, 36 insertions(+)
>
> diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
> index 294179f..26b36d9 100644
> --- a/src/shared/gatt-db.c
> +++ b/src/shared/gatt-db.c
> @@ -285,3 +285,32 @@ uint16_t gatt_db_new_characteristic(struct gatt_db *db, uint16_t handle,
>
> return update_attribute_handle(service, i);
> }
> +
> +uint16_t gatt_db_new_char_descriptor(struct gatt_db *db, uint16_t handle,
> + const bt_uuid_t *uuid,
> + uint8_t permissions,
> + gatt_db_read_t read_func,
> + gatt_db_write_t write_func,
> + void *user_data)
> +{
> + struct gatt_db_service *service;
> + int i;
> +
> + service = queue_find(db->services, match_service_by_handle,
> + INT_TO_PTR(handle));
> + if (!service)
> + return 0;
> +
> + i = get_attribute_index(service, 0);
> + if (!i)
> + return 0;

Descriptor belongs to characteristics. If service handle is more
suitable for this function, how are you associating characteristic and
descriptors?
Is there any restriction (order) to call this helper function?

> +
> + service->attributes[i] = new_attribute(uuid, NULL, 0);
> + if (!service->attributes[i])
> + return 0;
> +
> + set_attribute_data(service->attributes[i], read_func, write_func,
> + permissions, user_data);
> +
> + return update_attribute_handle(service, i);
> +}
> diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
> index 8d9107a..1191614 100644
> --- a/src/shared/gatt-db.h
> +++ b/src/shared/gatt-db.h
> @@ -51,3 +51,10 @@ uint16_t gatt_db_new_characteristic(struct gatt_db *db, uint16_t handle,
> gatt_db_read_t read_func,
> gatt_db_write_t write_func,
> void *user_data);
> +
> +uint16_t gatt_db_new_char_descriptor(struct gatt_db *db, uint16_t handle,
> + const bt_uuid_t *uuid,
> + uint8_t permissions,
> + gatt_db_read_t read_func,
> + gatt_db_write_t write_func,
> + void *user_data);
> --


Why permissions is required? My understanding is that in some cases
the upper layer can define extra "requirements".
Maybe it'd better to add "properties" later.

Claudio

2014-04-15 12:50:26

by Claudio Takahasi

[permalink] [raw]
Subject: Re: [RFC 05/16] gatt: Add new sharacteristic functionality

HI Marcin,

On Wed, Apr 9, 2014 at 4:07 AM, Marcin Kraglak <[email protected]> wrote:
> It will attach characteristic declaration and value, and return value
> handle.
> ---
> src/shared/gatt-db.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> src/shared/gatt-db.h | 15 +++++++++
> 2 files changed, 110 insertions(+)
>
> diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
> index 3ff017c..294179f 100644
> --- a/src/shared/gatt-db.c
> +++ b/src/shared/gatt-db.c
> @@ -28,10 +28,14 @@
> #include "src/shared/queue.h"
> #include "src/shared/gatt-db.h"
>
> +#define MAX_CHAR_DECL_VALUE_LEN 19
> +
> static const bt_uuid_t primary_service_uuid = { .type = BT_UUID16,
> .value.u16 = GATT_PRIM_SVC_UUID };
> static const bt_uuid_t secondary_service_uuid = { .type = BT_UUID16,
> .value.u16 = GATT_SND_SVC_UUID };
> +static const bt_uuid_t characteristic_uuid = { .type = BT_UUID16,
> + .value.u16 = GATT_CHARAC_UUID };
>
> struct gatt_db {
> uint16_t next_handle;
> @@ -43,6 +47,10 @@ struct gatt_db_attribute {
> bt_uuid_t uuid;
> uint16_t val_len;
> uint8_t value[0];
> + uint8_t permissions;
> + gatt_db_read_t read_func;
> + gatt_db_write_t write_func;
> + void *user_data;
> };
>
> struct gatt_db_service {
> @@ -190,3 +198,90 @@ bool gatt_db_remove_service(struct gatt_db *db, uint16_t handle)
>
> return true;
> }
> +
> +static uint16_t get_attribute_index(struct gatt_db_service *service,
> + int end_offset)
> +{
> + int i = 0;
> +
> + while (service->attributes[i] && i < service->num_handles - end_offset)
> + i++;
> +
> + return i == service->num_handles - end_offset + 1 ? 0 : i;

why "end_offset" is needed? It looks that "end_offset" is always "1"
(hard-coded) in the code.

> +}
> +
> +static uint16_t get_handle_at_index(struct gatt_db_service *service,
> + int index)
> +{
> + return service->attributes[index]->handle;
> +}
> +
> +static uint16_t update_attribute_handle(struct gatt_db_service *service,
> + int index)
> +{
> + uint16_t previous_handle;
> +
> + previous_handle = service->attributes[index - 1]->handle;
> + service->attributes[index]->handle = previous_handle + 1;
> +
> + return service->attributes[index]->handle;
> +}
> +
> +static void set_attribute_data(struct gatt_db_attribute *attribute,
> + gatt_db_read_t read_func,
> + gatt_db_write_t write_func,
> + uint8_t permissions,
> + void *user_data)
> +{
> + attribute->permissions = permissions;
> + attribute->read_func = read_func;
> + attribute->write_func = write_func;
> + attribute->user_data = user_data;
> +}
> +
> +uint16_t gatt_db_new_characteristic(struct gatt_db *db, uint16_t handle,
> + const bt_uuid_t *uuid,
> + uint8_t permissions,
> + uint8_t properties,
> + gatt_db_read_t read_func,
> + gatt_db_write_t write_func,
> + void *user_data)
> +{
> + uint8_t value[MAX_CHAR_DECL_VALUE_LEN];
> + struct gatt_db_service *service;
> + uint16_t len = 0;
> + int i;

The same entity which created the service will create the
characteristics. Does it make sense to pass "gatt_db_service" instead
of the gatt_db?

> +
> + service = queue_find(db->services, match_service_by_handle,
> + INT_TO_PTR(handle));
> + if (!service)
> + return 0;
> +
> + i = get_attribute_index(service, 1);
> + if (!i)
> + return 0;
> +
> + value[0] = properties;
> + len += sizeof(properties);

"len" doesn't need to be initialized if you use "len = sizeof(properties);"

> + put_le16(get_handle_at_index(service, i - 1) + 2, &value[1]);

Characteristics are added sequentially. Is it possible to add a
counter to get the handle easily?

> + len += sizeof(uint16_t);
> + len += uuid_to_le(uuid, &value[3]);
> +
> + service->attributes[i] = new_attribute(&characteristic_uuid, value,
> + len);
> + if (!service->attributes[i])
> + return 0;
> +
> + update_attribute_handle(service, i++);
> +
> + service->attributes[i] = new_attribute(uuid, NULL, 0);
> + if (!service->attributes[i]) {
> + free(service->attributes[i - 1]);
> + return 0;
> + }
> +
> + set_attribute_data(service->attributes[i], read_func, write_func,
> + permissions, user_data);
> +
> + return update_attribute_handle(service, i);
> +}
> diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
> index f543a87..8d9107a 100644
> --- a/src/shared/gatt-db.h
> +++ b/src/shared/gatt-db.h
> @@ -36,3 +36,18 @@ uint16_t gatt_db_new_service(struct gatt_db *db, const bt_uuid_t *uuid,
> uint16_t num_handles);
>
> bool gatt_db_remove_service(struct gatt_db *db, uint16_t handle);
> +

Please add comments describing the arguments.
Is it necessary to inform the address type?

> +typedef void (*gatt_db_read_t) (uint16_t handle, const bdaddr_t *bdaddr,
> + uint16_t request_id, void *user_data);
> +
> +typedef void (*gatt_db_write_t) (uint16_t handle, const bdaddr_t *bdaddr,
> + uint16_t request_id, const uint8_t *value,
> + size_t len);
> +
> +uint16_t gatt_db_new_characteristic(struct gatt_db *db, uint16_t handle,
> + const bt_uuid_t *uuid,
> + uint8_t permissions,
> + uint8_t properties,
> + gatt_db_read_t read_func,
> + gatt_db_write_t write_func,
> + void *user_data);
> --
> 1.8.5.3
>

Claudio

2014-04-14 19:57:11

by Marcin Kraglak

[permalink] [raw]
Subject: Re: [RFC 02/16] gatt: Add services list to gatt_db struct

Hi Claudio,

On 14 April 2014 16:11, Claudio Takahasi <[email protected]> wrote:
> Hi Marcin,
>
> On Wed, Apr 9, 2014 at 4:07 AM, Marcin Kraglak <[email protected]> wrote:
>> Gatt database will store all services in queue services. Each service
>> contains attributes, number of handles included and flag if it is
>> active service.
>> ---
>> src/shared/gatt-db.c | 32 ++++++++++++++++++++++++++++++++
>> 1 file changed, 32 insertions(+)
>>
>> diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
>> index e56b381..47915c7 100644
>> --- a/src/shared/gatt-db.c
>> +++ b/src/shared/gatt-db.c
>> @@ -21,11 +21,24 @@
>> *
>> */
>>
>> +#include <stdbool.h>
>> +
>> #include "src/shared/util.h"
>> +#include "src/shared/queue.h"
>> #include "src/shared/gatt-db.h"
>>
>> struct gatt_db {
>> uint16_t next_handle;
>> + struct queue *services;
>> +};
>> +
>> +struct gatt_db_attribute {
>> +};
>> +
>> +struct gatt_db_service {
>> + bool active;
>> + uint16_t num_handles;
>> + struct gatt_db_attribute **attributes;
>
> If the plan is to support handle allocation, maybe it'd better to have
> continuous memory allocation instead of attributes pointers.
>
> Claudio.
>
> <snip>

We store attribute value in attribute struct, and it's easier to
iterate through array of pointers. But we can store pointer to
attribute value, then continuous memory will be better. I can change
it.

BR
Marcin

2014-04-14 19:15:13

by Marcin Kraglak

[permalink] [raw]
Subject: Re: [RFC 01/16] gatt: Add skeleton of gatt-db

Hi Claudio,

On 14 April 2014 16:12, Claudio Takahasi <[email protected]> wrote:
> Hi Marcin,
>
> On Wed, Apr 9, 2014 at 4:06 AM, Marcin Kraglak <[email protected]> wrote:
>> This change adds new() and destroy() fuctions for gatt_db,
>> which will be used for storing local attributes.
>> ---
>> android/Android.mk | 1 +
>> android/Makefile.am | 1 +
>> src/shared/gatt-db.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
>> src/shared/gatt-db.h | 27 +++++++++++++++++++++++++++
>> 4 files changed, 76 insertions(+)
>> create mode 100644 src/shared/gatt-db.c
>> create mode 100644 src/shared/gatt-db.h
>>
>> diff --git a/android/Android.mk b/android/Android.mk
>> index 5f4e70c..4c9cfb5 100644
>> --- a/android/Android.mk
>> +++ b/android/Android.mk
>> @@ -51,6 +51,7 @@ LOCAL_SRC_FILES := \
>> bluez/src/shared/queue.c \
>> bluez/src/shared/ringbuf.c \
>> bluez/src/shared/hfp.c \
>> + bluez/src/shared/gatt-db.c \
>> bluez/src/shared/io-glib.c \
>> bluez/src/sdpd-database.c \
>> bluez/src/sdpd-service.c \
>> diff --git a/android/Makefile.am b/android/Makefile.am
>> index c51cce2..70e1dec 100644
>> --- a/android/Makefile.am
>> +++ b/android/Makefile.am
>> @@ -29,6 +29,7 @@ android_bluetoothd_SOURCES = android/main.c \
>> src/shared/mgmt.h src/shared/mgmt.c \
>> src/shared/ringbuf.h src/shared/ringbuf.c \
>> src/shared/hfp.h src/shared/hfp.c \
>> + src/shared/gatt-db.h src/shared/gatt-db.c \
>> android/bluetooth.h android/bluetooth.c \
>> android/hidhost.h android/hidhost.c \
>> android/ipc-common.h \
>> diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
>> new file mode 100644
>> index 0000000..e56b381
>> --- /dev/null
>> +++ b/src/shared/gatt-db.c
>> @@ -0,0 +1,47 @@
>> +/*
>> + *
>> + * BlueZ - Bluetooth protocol stack for Linux
>> + *
>> + * Copyright (C) 2014 Intel Corporation. All rights reserved.
>> + *
>> + *
>> + * This library is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public
>> + * License as published by the Free Software Foundation; either
>> + * version 2.1 of the License, or (at your option) any later version.
>> + *
>> + * This library is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>> + * Lesser General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU Lesser General Public
>> + * License along with this library; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
>> + *
>> + */
>> +
>> +#include "src/shared/util.h"
>> +#include "src/shared/gatt-db.h"
>> +
>> +struct gatt_db {
>> + uint16_t next_handle;
>> +};
>> +
>> +struct gatt_db *gatt_db_new(void)
>> +{
>> + struct gatt_db *db;
>> +
>> + db = new0(struct gatt_db, 1);
>> + if (!db)
>> + return NULL;
>> +
>> + db->next_handle = 0x0001;
>> +
>> + return db;
>> +}
>
> Are you considering to use the same function to allocate/create a
> database to represent the remote "virtual" database?
> My point is: the same infra-structure could be used to represent a
> local database(per adapter maybe) or remote database.
>

We could add argument to new() like type: remote or local. What you
think about it?
> <snip>
>
> Regards,
> Claudio

2014-04-14 14:14:15

by Claudio Takahasi

[permalink] [raw]
Subject: Re: [RFC 03/16] gatt: Add method for creating services in gatt_db

Hi Marcin,

On Wed, Apr 9, 2014 at 4:07 AM, Marcin Kraglak <[email protected]> wrote:
> This function will reserve number of handles and create service attribute. Allowed
> service types are PRIMARY and SECONDARY.
> ---
> src/shared/gatt-db.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> src/shared/gatt-db.h | 9 +++++
> 2 files changed, 101 insertions(+)
>
> diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
> index 47915c7..15e2f95 100644
> --- a/src/shared/gatt-db.c
> +++ b/src/shared/gatt-db.c
> @@ -23,16 +23,26 @@
>
> #include <stdbool.h>
>
> +#include "lib/uuid.h"
> #include "src/shared/util.h"
> #include "src/shared/queue.h"
> #include "src/shared/gatt-db.h"
>
> +static const bt_uuid_t primary_service_uuid = { .type = BT_UUID16,
> + .value.u16 = GATT_PRIM_SVC_UUID };
> +static const bt_uuid_t secondary_service_uuid = { .type = BT_UUID16,
> + .value.u16 = GATT_SND_SVC_UUID };
> +
> struct gatt_db {
> uint16_t next_handle;
> struct queue *services;
> };
>
> struct gatt_db_attribute {
> + uint16_t handle;
> + bt_uuid_t uuid;
> + uint16_t val_len;
> + uint8_t value[0];
> };
>
> struct gatt_db_service {
> @@ -77,3 +87,85 @@ void gatt_db_destroy(struct gatt_db *db)
> queue_destroy(db->services, gatt_db_service_destroy);
> free(db);
> }
> +
> +static struct gatt_db_attribute *new_attribute(const bt_uuid_t *type,
> + const uint8_t *val,
> + uint16_t len)
> +{
> + struct gatt_db_attribute *attribute;
> +
> + attribute = malloc0(sizeof(struct gatt_db_attribute) + len);
> + if (!attribute)
> + return NULL;
> +
> + attribute->uuid = *type;
> + memcpy(&attribute->value, val, len);
> + attribute->val_len = len;
> +
> + return attribute;
> +}
> +
> +static int uuid_to_le(const bt_uuid_t *uuid, uint8_t *dst)
> +{
> + switch (uuid->type) {
> + case BT_UUID16:
> + put_le16(uuid->value.u16, dst);
> + break;
> + case BT_UUID32:
> + put_le32(uuid->value.u32, dst);
> + break;
> + default:
> + bswap_128(&uuid->value.u128, dst);
> + break;
> + }
> +
> + return bt_uuid_len(uuid);
> +}
> +
> +uint16_t gatt_db_new_service(struct gatt_db *db, const bt_uuid_t *uuid,
> + enum gatt_db_service_type service_type,
> + uint16_t num_handles)

Just one suggestion, not sure if it will be possible. Plug-ins or
other files using this function should have access to gatt_db, *maybe*
it could be hidden.

<snip>

> + if (!queue_push_tail(db->services, service)) {
> + gatt_db_service_destroy(service);
> + return 0;
> + }
> +
> + service->attributes[0]->handle = db->next_handle;
> + db->next_handle += num_handles;
> + service->num_handles = num_handles;
> +
> + return service->attributes[0]->handle;
> +}
> diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
> index 2901afb..7c03013 100644
> --- a/src/shared/gatt-db.h
> +++ b/src/shared/gatt-db.h
> @@ -23,5 +23,14 @@
>
> struct gatt_db;
>
> +enum gatt_db_service_type {
> + GATT_DB_SERVICE_PRIMARY,
> + GATT_DB_SERVICE_SECONDARY
> +};

"bool" should be enough to inform if the service is primary or secondary.


<snip>

Claudio

2014-04-14 14:12:43

by Claudio Takahasi

[permalink] [raw]
Subject: Re: [RFC 01/16] gatt: Add skeleton of gatt-db

Hi Marcin,

On Wed, Apr 9, 2014 at 4:06 AM, Marcin Kraglak <[email protected]> wrote:
> This change adds new() and destroy() fuctions for gatt_db,
> which will be used for storing local attributes.
> ---
> android/Android.mk | 1 +
> android/Makefile.am | 1 +
> src/shared/gatt-db.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
> src/shared/gatt-db.h | 27 +++++++++++++++++++++++++++
> 4 files changed, 76 insertions(+)
> create mode 100644 src/shared/gatt-db.c
> create mode 100644 src/shared/gatt-db.h
>
> diff --git a/android/Android.mk b/android/Android.mk
> index 5f4e70c..4c9cfb5 100644
> --- a/android/Android.mk
> +++ b/android/Android.mk
> @@ -51,6 +51,7 @@ LOCAL_SRC_FILES := \
> bluez/src/shared/queue.c \
> bluez/src/shared/ringbuf.c \
> bluez/src/shared/hfp.c \
> + bluez/src/shared/gatt-db.c \
> bluez/src/shared/io-glib.c \
> bluez/src/sdpd-database.c \
> bluez/src/sdpd-service.c \
> diff --git a/android/Makefile.am b/android/Makefile.am
> index c51cce2..70e1dec 100644
> --- a/android/Makefile.am
> +++ b/android/Makefile.am
> @@ -29,6 +29,7 @@ android_bluetoothd_SOURCES = android/main.c \
> src/shared/mgmt.h src/shared/mgmt.c \
> src/shared/ringbuf.h src/shared/ringbuf.c \
> src/shared/hfp.h src/shared/hfp.c \
> + src/shared/gatt-db.h src/shared/gatt-db.c \
> android/bluetooth.h android/bluetooth.c \
> android/hidhost.h android/hidhost.c \
> android/ipc-common.h \
> diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
> new file mode 100644
> index 0000000..e56b381
> --- /dev/null
> +++ b/src/shared/gatt-db.c
> @@ -0,0 +1,47 @@
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2014 Intel Corporation. All rights reserved.
> + *
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + */
> +
> +#include "src/shared/util.h"
> +#include "src/shared/gatt-db.h"
> +
> +struct gatt_db {
> + uint16_t next_handle;
> +};
> +
> +struct gatt_db *gatt_db_new(void)
> +{
> + struct gatt_db *db;
> +
> + db = new0(struct gatt_db, 1);
> + if (!db)
> + return NULL;
> +
> + db->next_handle = 0x0001;
> +
> + return db;
> +}

Are you considering to use the same function to allocate/create a
database to represent the remote "virtual" database?
My point is: the same infra-structure could be used to represent a
local database(per adapter maybe) or remote database.

<snip>

Regards,
Claudio

2014-04-14 14:11:42

by Claudio Takahasi

[permalink] [raw]
Subject: Re: [RFC 02/16] gatt: Add services list to gatt_db struct

Hi Marcin,

On Wed, Apr 9, 2014 at 4:07 AM, Marcin Kraglak <[email protected]> wrote:
> Gatt database will store all services in queue services. Each service
> contains attributes, number of handles included and flag if it is
> active service.
> ---
> src/shared/gatt-db.c | 32 ++++++++++++++++++++++++++++++++
> 1 file changed, 32 insertions(+)
>
> diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
> index e56b381..47915c7 100644
> --- a/src/shared/gatt-db.c
> +++ b/src/shared/gatt-db.c
> @@ -21,11 +21,24 @@
> *
> */
>
> +#include <stdbool.h>
> +
> #include "src/shared/util.h"
> +#include "src/shared/queue.h"
> #include "src/shared/gatt-db.h"
>
> struct gatt_db {
> uint16_t next_handle;
> + struct queue *services;
> +};
> +
> +struct gatt_db_attribute {
> +};
> +
> +struct gatt_db_service {
> + bool active;
> + uint16_t num_handles;
> + struct gatt_db_attribute **attributes;

If the plan is to support handle allocation, maybe it'd better to have
continuous memory allocation instead of attributes pointers.

Claudio.

<snip>

2014-04-14 14:10:07

by Claudio Takahasi

[permalink] [raw]
Subject: Re: [RFC 00/16] Gatt database initial implementation

Hi Marcin,

On Wed, Apr 9, 2014 at 4:06 AM, Marcin Kraglak <[email protected]> wrote:
> This is proposal how gatt database implementation could look and
> how it can be used in Android. Current implementation contains:
> - create/destroy gatt_db
> - adding services, with given number of handles. This function returns
> service attribute andle
> - adding characteristics, descriptors and included services
> - function to start/stop service - it will be used when we expose services
> to client
>
> Next steps in gatt_db implementation should be:
> - handling read/write callbacks
> - handling attribute's permissions
> - now we just increment available handle. We should check if we have free handles
> between existing services
>
> Comments are welcome
> Marcin Kraglak

IMO, the database could be used to represent both: local and remote. I
am not familiar with Android BlueZ storage, does it make sense to have
a common storage for attributes declarations (remote attribute
caching)?

When the GATT service is local, we need to store the mapping between
handles and applications(or UUIDs). Remember that CCC storage is per
device. For remote attribute caching, we will need to store the
declarations only.

Regards,
Claudio

2014-04-09 07:07:05

by Marcin Kraglak

[permalink] [raw]
Subject: [RFC 07/16] gatt: Add included service functionality

It will add included service to service attribute list.
---
src/shared/gatt-db.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
src/shared/gatt-db.h | 3 +++
2 files changed, 47 insertions(+)

diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index 26b36d9..2886bb8 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -29,6 +29,7 @@
#include "src/shared/gatt-db.h"

#define MAX_CHAR_DECL_VALUE_LEN 19
+#define MAX_INCLUDED_VALUE_LEN 6

static const bt_uuid_t primary_service_uuid = { .type = BT_UUID16,
.value.u16 = GATT_PRIM_SVC_UUID };
@@ -36,6 +37,8 @@ static const bt_uuid_t secondary_service_uuid = { .type = BT_UUID16,
.value.u16 = GATT_SND_SVC_UUID };
static const bt_uuid_t characteristic_uuid = { .type = BT_UUID16,
.value.u16 = GATT_CHARAC_UUID };
+static const bt_uuid_t included_service_uuid = { .type = BT_UUID16,
+ .value.u16 = GATT_INCLUDE_UUID };

struct gatt_db {
uint16_t next_handle;
@@ -314,3 +317,44 @@ uint16_t gatt_db_new_char_descriptor(struct gatt_db *db, uint16_t handle,

return update_attribute_handle(service, i);
}
+
+uint16_t gatt_db_new_included_service(struct gatt_db *db, uint16_t handle,
+ uint16_t included_handle)
+{
+ struct gatt_db_service *included_service;
+ uint8_t value[MAX_INCLUDED_VALUE_LEN];
+ uint16_t len = sizeof(uint16_t) * 2;
+ struct gatt_db_service *service;
+ int index;
+
+ service = queue_find(db->services, match_service_by_handle,
+ INT_TO_PTR(handle));
+ if (!service)
+ return 0;
+
+ included_service = queue_find(db->services, match_service_by_handle,
+ INT_TO_PTR(included_handle));
+
+ if (!included_service)
+ return 0;
+
+ put_le16(included_handle, &value[0]);
+ put_le16(included_handle + included_service->num_handles - 1,
+ &value[2]);
+ if (included_service->attributes[0]->val_len == 2) {
+ memcpy(&value[4], included_service->attributes[0]->value,
+ included_service->attributes[0]->val_len);
+ len += included_service->attributes[0]->val_len;
+ }
+
+ index = get_attribute_index(service, 1);
+ if (!index)
+ return 0;
+
+ service->attributes[index] = new_attribute(&included_service_uuid,
+ value, len);
+ if (!service->attributes[index])
+ return 0;
+
+ return update_attribute_handle(service, index);
+}
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index 1191614..a421e9e 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -58,3 +58,6 @@ uint16_t gatt_db_new_char_descriptor(struct gatt_db *db, uint16_t handle,
gatt_db_read_t read_func,
gatt_db_write_t write_func,
void *user_data);
+
+uint16_t gatt_db_new_included_service(struct gatt_db *db, uint16_t handle,
+ uint16_t included_handle);
--
1.8.5.3


2014-04-09 07:07:02

by Marcin Kraglak

[permalink] [raw]
Subject: [RFC 04/16] gatt: Remove service functionality

This will remove service with given handle and its attributes.
---
src/shared/gatt-db.c | 21 +++++++++++++++++++++
src/shared/gatt-db.h | 2 ++
2 files changed, 23 insertions(+)

diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index 15e2f95..3ff017c 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -51,6 +51,13 @@ struct gatt_db_service {
struct gatt_db_attribute **attributes;
};

+static bool match_service_by_handle(const void *data, const void *user_data)
+{
+ const struct gatt_db_service *service = data;
+
+ return service->attributes[0]->handle == PTR_TO_INT(user_data);
+}
+
struct gatt_db *gatt_db_new(void)
{
struct gatt_db *db;
@@ -169,3 +176,17 @@ uint16_t gatt_db_new_service(struct gatt_db *db, const bt_uuid_t *uuid,

return service->attributes[0]->handle;
}
+
+bool gatt_db_remove_service(struct gatt_db *db, uint16_t handle)
+{
+ struct gatt_db_service *service;
+
+ service = queue_remove_if(db->services, match_service_by_handle,
+ INT_TO_PTR(handle));
+ if (!service)
+ return false;
+
+ gatt_db_service_destroy(service);
+
+ return true;
+}
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index 7c03013..f543a87 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -34,3 +34,5 @@ void gatt_db_destroy(struct gatt_db *db);
uint16_t gatt_db_new_service(struct gatt_db *db, const bt_uuid_t *uuid,
enum gatt_db_service_type service_type,
uint16_t num_handles);
+
+bool gatt_db_remove_service(struct gatt_db *db, uint16_t handle);
--
1.8.5.3


2014-04-09 07:07:10

by Marcin Kraglak

[permalink] [raw]
Subject: [RFC 12/16] android/gatt: Add descriptor implementation

It will add characteristic descriptor attribute to local database.
---
android/gatt.c | 34 +++++++++++++++++++++++++++++++++-
1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/android/gatt.c b/android/gatt.c
index 25cd7f1..acaa2a9 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -2806,10 +2806,42 @@ failed:

static void handle_server_add_descriptor(const void *buf, uint16_t len)
{
+ const struct hal_cmd_gatt_server_add_descriptor *cmd = buf;
+ struct hal_ev_gatt_server_descriptor_added ev;
+ struct gatt_server *server;
+ bt_uuid_t uuid;
+ uint8_t status;
+
DBG("");

+ server = find_server_by_id(cmd->server_if);
+ if (!server) {
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ android2uuid(cmd->uuid, &uuid);
+
+ ev.descr_handle = gatt_db_new_char_descriptor(gatt_db,
+ cmd->service_handle,
+ &uuid, cmd->permissions,
+ NULL, NULL, NULL);
+ if (!ev.descr_handle)
+ status = HAL_STATUS_FAILED;
+ else
+ status = HAL_STATUS_SUCCESS;
+
+failed:
+ ev.server_if = cmd->server_if;
+ ev.srvc_handle = cmd->service_handle;
+ memcpy(ev.uuid, cmd->uuid, sizeof(cmd->uuid));
+ ev.status = status == HAL_STATUS_SUCCESS ? GATT_SUCCESS : GATT_FAILURE;
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_SERVER_DESCRIPTOR_ADDED, sizeof(ev), &ev);
+
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_OP_GATT_SERVER_ADD_DESCRIPTOR, HAL_STATUS_FAILED);
+ HAL_OP_GATT_SERVER_ADD_DESCRIPTOR, status);
}

static void handle_server_start_service(const void *buf, uint16_t len)
--
1.8.5.3


2014-04-09 07:07:09

by Marcin Kraglak

[permalink] [raw]
Subject: [RFC 11/16] android/gatt: Add characteristic implementation

It will add characteristic declaration and value attributes to local database.
---
android/gatt.c | 36 +++++++++++++++++++++++++++++++++++-
1 file changed, 35 insertions(+), 1 deletion(-)

diff --git a/android/gatt.c b/android/gatt.c
index 10e3dfd..25cd7f1 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -2763,11 +2763,45 @@ failed:

static void handle_server_add_characteristic(const void *buf, uint16_t len)
{
+ const struct hal_cmd_gatt_server_add_characteristic *cmd = buf;
+ struct hal_ev_gatt_server_characteristic_added ev;
+ struct gatt_server *server;
+ bt_uuid_t uuid;
+ uint8_t status;
+
DBG("");

+ server = find_server_by_id(cmd->server_if);
+ if (!server) {
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ android2uuid(cmd->uuid, &uuid);
+
+ ev.char_handle = gatt_db_new_characteristic(gatt_db,
+ cmd->service_handle,
+ &uuid, cmd->permissions,
+ cmd->properties,
+ NULL, NULL, NULL);
+ if (!ev.char_handle)
+ status = HAL_STATUS_FAILED;
+ else
+ status = HAL_STATUS_SUCCESS;
+
+failed:
+ ev.srvc_handle = cmd->service_handle;
+ ev.status = status;
+ ev.server_if = cmd->server_if;
+ ev.status = status == HAL_STATUS_SUCCESS ? GATT_SUCCESS : GATT_FAILURE;
+ memcpy(ev.uuid, cmd->uuid, sizeof(cmd->uuid));
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_SERVER_CHAR_ADDED, sizeof(ev), &ev);
+
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
HAL_OP_GATT_SERVER_ADD_CHARACTERISTIC,
- HAL_STATUS_FAILED);
+ status);
}

static void handle_server_add_descriptor(const void *buf, uint16_t len)
--
1.8.5.3


2014-04-09 07:07:08

by Marcin Kraglak

[permalink] [raw]
Subject: [RFC 10/16] android/gatt: Add included service implementation

It will add included service attribute to database.
---
android/gatt.c | 31 ++++++++++++++++++++++++++++++-
1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/android/gatt.c b/android/gatt.c
index 5f054c7..10e3dfd 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -2726,10 +2726,39 @@ failed:

static void handle_server_add_included_service(const void *buf, uint16_t len)
{
+ const struct hal_cmd_gatt_server_add_inc_service *cmd = buf;
+ struct hal_ev_gatt_server_inc_srvc_added ev;
+ struct gatt_server *server;
+ uint8_t status;
+
DBG("");

+ server = find_server_by_id(cmd->server_if);
+ if (!server) {
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ ev.incl_srvc_handle = gatt_db_new_included_service(gatt_db,
+ cmd->service_handle,
+ cmd->included_handle);
+ if (!ev.incl_srvc_handle) {
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ status = HAL_STATUS_SUCCESS;
+failed:
+ ev.srvc_handle = cmd->service_handle;
+ ev.status = status;
+ ev.server_if = cmd->server_if;
+ ev.status = status == HAL_STATUS_SUCCESS ? GATT_SUCCESS : GATT_FAILURE;
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_SERVER_INC_SRVC_ADDED, sizeof(ev), &ev);
+
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_OP_GATT_SERVER_ADD_INC_SERVICE, HAL_STATUS_FAILED);
+ HAL_OP_GATT_SERVER_ADD_INC_SERVICE, status);
}

static void handle_server_add_characteristic(const void *buf, uint16_t len)
--
1.8.5.3


2014-04-09 07:07:11

by Marcin Kraglak

[permalink] [raw]
Subject: [RFC 13/16] gatt: Add start/stop service functionality

Only active services can be read by client.
---
src/shared/gatt-db.c | 28 ++++++++++++++++++++++++++++
src/shared/gatt-db.h | 4 ++++
2 files changed, 32 insertions(+)

diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index 2886bb8..976885a 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -358,3 +358,31 @@ uint16_t gatt_db_new_included_service(struct gatt_db *db, uint16_t handle,

return update_attribute_handle(service, index);
}
+
+bool gatt_db_start_service(struct gatt_db *db, uint16_t handle)
+{
+ struct gatt_db_service *service;
+
+ service = queue_find(db->services, match_service_by_handle,
+ INT_TO_PTR(handle));
+ if (!service)
+ return false;
+
+ service->active = true;
+
+ return true;
+}
+
+bool gatt_db_stop_service(struct gatt_db *db, uint16_t handle)
+{
+ struct gatt_db_service *service;
+
+ service = queue_find(db->services, match_service_by_handle,
+ INT_TO_PTR(handle));
+ if (!service)
+ return false;
+
+ service->active = false;
+
+ return true;
+}
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index a421e9e..ff371e6 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -61,3 +61,7 @@ uint16_t gatt_db_new_char_descriptor(struct gatt_db *db, uint16_t handle,

uint16_t gatt_db_new_included_service(struct gatt_db *db, uint16_t handle,
uint16_t included_handle);
+
+bool gatt_db_start_service(struct gatt_db *db, uint16_t handle);
+
+bool gatt_db_stop_service(struct gatt_db *db, uint16_t handle);
--
1.8.5.3


2014-04-09 07:07:14

by Marcin Kraglak

[permalink] [raw]
Subject: [RFC 16/16] android/gatt: Fix typo in event handlers array

---
android/hal-gatt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/android/hal-gatt.c b/android/hal-gatt.c
index 5e7443c..d8c0d54 100644
--- a/android/hal-gatt.c
+++ b/android/hal-gatt.c
@@ -536,7 +536,7 @@ static const struct hal_ipc_handler ev_handlers[] = {
sizeof(struct hal_ev_gatt_server_service_added) },
/* HAL_EV_GATT_SERVER_INC_SRVC_ADDED */
{ handle_included_service_added, false,
- sizeof(struct hal_ev_gatt_server_service_added) },
+ sizeof(struct hal_ev_gatt_server_inc_srvc_added) },
/* HAL_EV_GATT_SERVER_CHAR_ADDED */
{ handle_characteristic_added, false,
sizeof(struct hal_ev_gatt_server_characteristic_added) },
--
1.8.5.3


2014-04-09 07:07:13

by Marcin Kraglak

[permalink] [raw]
Subject: [RFC 15/16] android/gatt: Add stop service command handling

It will stop service in local database.
---
android/gatt.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/android/gatt.c b/android/gatt.c
index edcb7aa..f5324f3 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -2881,10 +2881,34 @@ failed:

static void handle_server_stop_service(const void *buf, uint16_t len)
{
+ const struct hal_cmd_gatt_server_stop_service *cmd = buf;
+ struct hal_ev_gatt_server_service_stopped ev;
+ struct gatt_server *server;
+ uint8_t status;
+
DBG("");

+ server = find_server_by_id(cmd->server_if);
+ if (!server) {
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ if (!gatt_db_stop_service(gatt_db, cmd->service_handle))
+ status = HAL_STATUS_FAILED;
+ else
+ status = HAL_STATUS_SUCCESS;
+
+failed:
+ ev.status = status == HAL_STATUS_SUCCESS ? GATT_SUCCESS : GATT_FAILURE;
+ ev.server_if = cmd->server_if;
+ ev.srvc_handle = cmd->service_handle;
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_SERVER_SERVICE_STOPPED, sizeof(ev), &ev);
+
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_OP_GATT_SERVER_STOP_SERVICE, HAL_STATUS_FAILED);
+ HAL_OP_GATT_SERVER_STOP_SERVICE, status);
}

static void handle_server_delete_service(const void *buf, uint16_t len)
--
1.8.5.3


2014-04-09 07:07:06

by Marcin Kraglak

[permalink] [raw]
Subject: [RFC 08/16] android/gatt: Add service functionality

It will Add service to local database.
---
android/gatt.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 55 insertions(+), 1 deletion(-)

diff --git a/android/gatt.c b/android/gatt.c
index a33ce25..76753a8 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -43,6 +43,7 @@
#include "utils.h"
#include "src/shared/util.h"
#include "src/shared/queue.h"
+#include "src/shared/gatt-db.h"
#include "attrib/gattrib.h"
#include "attrib/att.h"
#include "attrib/gatt.h"
@@ -130,6 +131,8 @@ static struct queue *conn_list = NULL; /* Connected devices */
static struct queue *conn_wait_queue = NULL; /* Devs waiting to connect */
static struct queue *disc_dev_list = NULL; /* Disconnected devices */

+static struct gatt_db *gatt_db = NULL;
+
static void bt_le_discovery_stop_cb(void);

static void android2uuid(const uint8_t *uuid, bt_uuid_t *dst)
@@ -2669,12 +2672,56 @@ static void handle_server_disconnect(const void *buf, uint16_t len)
HAL_OP_GATT_SERVER_DISCONNECT, HAL_STATUS_FAILED);
}

+static struct gatt_server *find_server_by_id(int32_t id)
+{
+ return queue_find(gatt_servers, match_server_by_id, INT_TO_PTR(id));
+}
+
static void handle_server_add_service(const void *buf, uint16_t len)
{
+ const struct hal_cmd_gatt_server_add_service *cmd = buf;
+ struct hal_ev_gatt_server_service_added ev;
+ enum gatt_db_service_type type;
+ struct gatt_server *server;
+ uint8_t status;
+ bt_uuid_t uuid;
+
DBG("");

+ memset(&ev, 0, sizeof(ev));
+
+ server = find_server_by_id(cmd->server_if);
+ if (!server) {
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ if (cmd->srvc_id.is_primary)
+ type = GATT_DB_SERVICE_PRIMARY;
+ else
+ type = GATT_DB_SERVICE_SECONDARY;
+
+ android2uuid(cmd->srvc_id.uuid, &uuid);
+
+ ev.srvc_handle = gatt_db_new_service(gatt_db, &uuid, type,
+ cmd->num_handles);
+ if (!ev.srvc_handle) {
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ status = HAL_STATUS_SUCCESS;
+
+failed:
+ ev.status = status == HAL_STATUS_SUCCESS ? GATT_SUCCESS : GATT_FAILURE;
+ ev.srvc_id = cmd->srvc_id;
+ ev.server_if = cmd->server_if;
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_SERVER_SERVICE_ADDED, sizeof(ev), &ev);
+
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_OP_GATT_SERVER_ADD_SERVICE, HAL_STATUS_FAILED);
+ HAL_OP_GATT_SERVER_ADD_SERVICE, status);
}

static void handle_server_add_included_service(const void *buf, uint16_t len)
@@ -2859,6 +2906,7 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
gatt_clients = queue_new();
gatt_servers = queue_new();
disc_dev_list = queue_new();
+ gatt_db = gatt_db_new();

if (!conn_list || !conn_wait_queue || !gatt_clients || !gatt_servers ||
!disc_dev_list) {
@@ -2879,6 +2927,9 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
queue_destroy(disc_dev_list, NULL);
disc_dev_list = NULL;

+ gatt_db_destroy(gatt_db);
+ gatt_db = NULL;
+
return false;
}

@@ -2913,4 +2964,7 @@ void bt_gatt_unregister(void)

queue_destroy(disc_dev_list, destroy_device);
disc_dev_list = NULL;
+
+ gatt_db_destroy(gatt_db);
+ gatt_db = NULL;
}
--
1.8.5.3


2014-04-09 07:07:12

by Marcin Kraglak

[permalink] [raw]
Subject: [RFC 14/16] android/gatt: Add handling of start service command

It will start service added to local database.
---
android/gatt.c | 29 ++++++++++++++++++++++++++++-
1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/android/gatt.c b/android/gatt.c
index acaa2a9..edcb7aa 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -2846,10 +2846,37 @@ failed:

static void handle_server_start_service(const void *buf, uint16_t len)
{
+ const struct hal_cmd_gatt_server_start_service *cmd = buf;
+ struct hal_ev_gatt_server_service_started ev;
+ struct gatt_server *server;
+ uint8_t status;
+
DBG("");

+ server = find_server_by_id(cmd->server_if);
+ if (!server) {
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ if (!gatt_db_start_service(gatt_db, cmd->service_handle)) {
+ /* we ignore service now */
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ status = HAL_STATUS_SUCCESS;
+
+failed:
+ ev.status = status == HAL_STATUS_SUCCESS ? GATT_SUCCESS : GATT_FAILURE;
+ ev.server_if = cmd->server_if;
+ ev.srvc_handle = cmd->service_handle;
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_SERVER_SERVICE_STARTED, sizeof(ev), &ev);
+
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_OP_GATT_SERVER_START_SERVICE, HAL_STATUS_FAILED);
+ HAL_OP_GATT_SERVER_START_SERVICE, status);
}

static void handle_server_stop_service(const void *buf, uint16_t len)
--
1.8.5.3


2014-04-09 07:07:07

by Marcin Kraglak

[permalink] [raw]
Subject: [RFC 09/16] android/gatt: Add implementation of delete service

It will delete saervice from local database
---
android/gatt.c | 30 +++++++++++++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/android/gatt.c b/android/gatt.c
index 76753a8..5f054c7 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -2767,10 +2767,38 @@ static void handle_server_stop_service(const void *buf, uint16_t len)

static void handle_server_delete_service(const void *buf, uint16_t len)
{
+ const struct hal_cmd_gatt_server_delete_service *cmd = buf;
+ struct hal_ev_gatt_server_service_deleted ev;
+ struct gatt_server *server;
+ uint8_t status;
+
DBG("");

+ memset(&ev, 0, sizeof(ev));
+
+ server = find_server_by_id(cmd->server_if);
+ if (!server) {
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ if (!gatt_db_remove_service(gatt_db, cmd->service_handle)) {
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ status = HAL_STATUS_SUCCESS;
+
+failed:
+ ev.status = status == HAL_STATUS_SUCCESS ? GATT_SUCCESS : GATT_FAILURE;
+ ev.srvc_handle = cmd->service_handle;
+ ev.server_if = cmd->server_if;
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_SERVER_SERVICE_DELETED, sizeof(ev), &ev);
+
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_OP_GATT_SERVER_DELETE_SERVICE, HAL_STATUS_FAILED);
+ HAL_OP_GATT_SERVER_DELETE_SERVICE, status);
}

static void handle_server_send_indication(const void *buf, uint16_t len)
--
1.8.5.3


2014-04-09 07:07:03

by Marcin Kraglak

[permalink] [raw]
Subject: [RFC 05/16] gatt: Add new sharacteristic functionality

It will attach characteristic declaration and value, and return value
handle.
---
src/shared/gatt-db.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/shared/gatt-db.h | 15 +++++++++
2 files changed, 110 insertions(+)

diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index 3ff017c..294179f 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -28,10 +28,14 @@
#include "src/shared/queue.h"
#include "src/shared/gatt-db.h"

+#define MAX_CHAR_DECL_VALUE_LEN 19
+
static const bt_uuid_t primary_service_uuid = { .type = BT_UUID16,
.value.u16 = GATT_PRIM_SVC_UUID };
static const bt_uuid_t secondary_service_uuid = { .type = BT_UUID16,
.value.u16 = GATT_SND_SVC_UUID };
+static const bt_uuid_t characteristic_uuid = { .type = BT_UUID16,
+ .value.u16 = GATT_CHARAC_UUID };

struct gatt_db {
uint16_t next_handle;
@@ -43,6 +47,10 @@ struct gatt_db_attribute {
bt_uuid_t uuid;
uint16_t val_len;
uint8_t value[0];
+ uint8_t permissions;
+ gatt_db_read_t read_func;
+ gatt_db_write_t write_func;
+ void *user_data;
};

struct gatt_db_service {
@@ -190,3 +198,90 @@ bool gatt_db_remove_service(struct gatt_db *db, uint16_t handle)

return true;
}
+
+static uint16_t get_attribute_index(struct gatt_db_service *service,
+ int end_offset)
+{
+ int i = 0;
+
+ while (service->attributes[i] && i < service->num_handles - end_offset)
+ i++;
+
+ return i == service->num_handles - end_offset + 1 ? 0 : i;
+}
+
+static uint16_t get_handle_at_index(struct gatt_db_service *service,
+ int index)
+{
+ return service->attributes[index]->handle;
+}
+
+static uint16_t update_attribute_handle(struct gatt_db_service *service,
+ int index)
+{
+ uint16_t previous_handle;
+
+ previous_handle = service->attributes[index - 1]->handle;
+ service->attributes[index]->handle = previous_handle + 1;
+
+ return service->attributes[index]->handle;
+}
+
+static void set_attribute_data(struct gatt_db_attribute *attribute,
+ gatt_db_read_t read_func,
+ gatt_db_write_t write_func,
+ uint8_t permissions,
+ void *user_data)
+{
+ attribute->permissions = permissions;
+ attribute->read_func = read_func;
+ attribute->write_func = write_func;
+ attribute->user_data = user_data;
+}
+
+uint16_t gatt_db_new_characteristic(struct gatt_db *db, uint16_t handle,
+ const bt_uuid_t *uuid,
+ uint8_t permissions,
+ uint8_t properties,
+ gatt_db_read_t read_func,
+ gatt_db_write_t write_func,
+ void *user_data)
+{
+ uint8_t value[MAX_CHAR_DECL_VALUE_LEN];
+ struct gatt_db_service *service;
+ uint16_t len = 0;
+ int i;
+
+ service = queue_find(db->services, match_service_by_handle,
+ INT_TO_PTR(handle));
+ if (!service)
+ return 0;
+
+ i = get_attribute_index(service, 1);
+ if (!i)
+ return 0;
+
+ value[0] = properties;
+ len += sizeof(properties);
+ put_le16(get_handle_at_index(service, i - 1) + 2, &value[1]);
+ len += sizeof(uint16_t);
+ len += uuid_to_le(uuid, &value[3]);
+
+ service->attributes[i] = new_attribute(&characteristic_uuid, value,
+ len);
+ if (!service->attributes[i])
+ return 0;
+
+ update_attribute_handle(service, i++);
+
+ service->attributes[i] = new_attribute(uuid, NULL, 0);
+ if (!service->attributes[i]) {
+ free(service->attributes[i - 1]);
+ return 0;
+ }
+
+ set_attribute_data(service->attributes[i], read_func, write_func,
+ permissions, user_data);
+
+ return update_attribute_handle(service, i);
+}
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index f543a87..8d9107a 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -36,3 +36,18 @@ uint16_t gatt_db_new_service(struct gatt_db *db, const bt_uuid_t *uuid,
uint16_t num_handles);

bool gatt_db_remove_service(struct gatt_db *db, uint16_t handle);
+
+typedef void (*gatt_db_read_t) (uint16_t handle, const bdaddr_t *bdaddr,
+ uint16_t request_id, void *user_data);
+
+typedef void (*gatt_db_write_t) (uint16_t handle, const bdaddr_t *bdaddr,
+ uint16_t request_id, const uint8_t *value,
+ size_t len);
+
+uint16_t gatt_db_new_characteristic(struct gatt_db *db, uint16_t handle,
+ const bt_uuid_t *uuid,
+ uint8_t permissions,
+ uint8_t properties,
+ gatt_db_read_t read_func,
+ gatt_db_write_t write_func,
+ void *user_data);
--
1.8.5.3


2014-04-09 07:07:01

by Marcin Kraglak

[permalink] [raw]
Subject: [RFC 03/16] gatt: Add method for creating services in gatt_db

This function will reserve number of handles and create service attribute. Allowed
service types are PRIMARY and SECONDARY.
---
src/shared/gatt-db.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/shared/gatt-db.h | 9 +++++
2 files changed, 101 insertions(+)

diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index 47915c7..15e2f95 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -23,16 +23,26 @@

#include <stdbool.h>

+#include "lib/uuid.h"
#include "src/shared/util.h"
#include "src/shared/queue.h"
#include "src/shared/gatt-db.h"

+static const bt_uuid_t primary_service_uuid = { .type = BT_UUID16,
+ .value.u16 = GATT_PRIM_SVC_UUID };
+static const bt_uuid_t secondary_service_uuid = { .type = BT_UUID16,
+ .value.u16 = GATT_SND_SVC_UUID };
+
struct gatt_db {
uint16_t next_handle;
struct queue *services;
};

struct gatt_db_attribute {
+ uint16_t handle;
+ bt_uuid_t uuid;
+ uint16_t val_len;
+ uint8_t value[0];
};

struct gatt_db_service {
@@ -77,3 +87,85 @@ void gatt_db_destroy(struct gatt_db *db)
queue_destroy(db->services, gatt_db_service_destroy);
free(db);
}
+
+static struct gatt_db_attribute *new_attribute(const bt_uuid_t *type,
+ const uint8_t *val,
+ uint16_t len)
+{
+ struct gatt_db_attribute *attribute;
+
+ attribute = malloc0(sizeof(struct gatt_db_attribute) + len);
+ if (!attribute)
+ return NULL;
+
+ attribute->uuid = *type;
+ memcpy(&attribute->value, val, len);
+ attribute->val_len = len;
+
+ return attribute;
+}
+
+static int uuid_to_le(const bt_uuid_t *uuid, uint8_t *dst)
+{
+ switch (uuid->type) {
+ case BT_UUID16:
+ put_le16(uuid->value.u16, dst);
+ break;
+ case BT_UUID32:
+ put_le32(uuid->value.u32, dst);
+ break;
+ default:
+ bswap_128(&uuid->value.u128, dst);
+ break;
+ }
+
+ return bt_uuid_len(uuid);
+}
+
+uint16_t gatt_db_new_service(struct gatt_db *db, const bt_uuid_t *uuid,
+ enum gatt_db_service_type service_type,
+ uint16_t num_handles)
+{
+ struct gatt_db_service *service;
+ const bt_uuid_t *type;
+ uint8_t value[16];
+ uint16_t len;
+
+ service = new0(struct gatt_db_service, 1);
+ if (!service)
+ return 0;
+
+ service->attributes = new0(struct gatt_db_attribute *, num_handles);
+ if (!service->attributes) {
+ free(service);
+ return 0;
+ }
+
+ switch (service_type) {
+ case GATT_DB_SERVICE_SECONDARY:
+ type = &secondary_service_uuid;
+ break;
+ default:
+ type = &primary_service_uuid;
+ break;
+ }
+
+ len = uuid_to_le(uuid, value);
+
+ service->attributes[0] = new_attribute(type, value, len);
+ if (!service->attributes[0]) {
+ gatt_db_service_destroy(service);
+ return 0;
+ }
+
+ if (!queue_push_tail(db->services, service)) {
+ gatt_db_service_destroy(service);
+ return 0;
+ }
+
+ service->attributes[0]->handle = db->next_handle;
+ db->next_handle += num_handles;
+ service->num_handles = num_handles;
+
+ return service->attributes[0]->handle;
+}
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index 2901afb..7c03013 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -23,5 +23,14 @@

struct gatt_db;

+enum gatt_db_service_type {
+ GATT_DB_SERVICE_PRIMARY,
+ GATT_DB_SERVICE_SECONDARY
+};
+
struct gatt_db *gatt_db_new(void);
void gatt_db_destroy(struct gatt_db *db);
+
+uint16_t gatt_db_new_service(struct gatt_db *db, const bt_uuid_t *uuid,
+ enum gatt_db_service_type service_type,
+ uint16_t num_handles);
--
1.8.5.3


2014-04-09 07:07:04

by Marcin Kraglak

[permalink] [raw]
Subject: [RFC 06/16] gatt: Add characteristic descriptor method

It will add characteristic descriptor to service attribute's list.
---
src/shared/gatt-db.c | 29 +++++++++++++++++++++++++++++
src/shared/gatt-db.h | 7 +++++++
2 files changed, 36 insertions(+)

diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index 294179f..26b36d9 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -285,3 +285,32 @@ uint16_t gatt_db_new_characteristic(struct gatt_db *db, uint16_t handle,

return update_attribute_handle(service, i);
}
+
+uint16_t gatt_db_new_char_descriptor(struct gatt_db *db, uint16_t handle,
+ const bt_uuid_t *uuid,
+ uint8_t permissions,
+ gatt_db_read_t read_func,
+ gatt_db_write_t write_func,
+ void *user_data)
+{
+ struct gatt_db_service *service;
+ int i;
+
+ service = queue_find(db->services, match_service_by_handle,
+ INT_TO_PTR(handle));
+ if (!service)
+ return 0;
+
+ i = get_attribute_index(service, 0);
+ if (!i)
+ return 0;
+
+ service->attributes[i] = new_attribute(uuid, NULL, 0);
+ if (!service->attributes[i])
+ return 0;
+
+ set_attribute_data(service->attributes[i], read_func, write_func,
+ permissions, user_data);
+
+ return update_attribute_handle(service, i);
+}
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index 8d9107a..1191614 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -51,3 +51,10 @@ uint16_t gatt_db_new_characteristic(struct gatt_db *db, uint16_t handle,
gatt_db_read_t read_func,
gatt_db_write_t write_func,
void *user_data);
+
+uint16_t gatt_db_new_char_descriptor(struct gatt_db *db, uint16_t handle,
+ const bt_uuid_t *uuid,
+ uint8_t permissions,
+ gatt_db_read_t read_func,
+ gatt_db_write_t write_func,
+ void *user_data);
--
1.8.5.3


2014-04-09 07:06:59

by Marcin Kraglak

[permalink] [raw]
Subject: [RFC 01/16] gatt: Add skeleton of gatt-db

This change adds new() and destroy() fuctions for gatt_db,
which will be used for storing local attributes.
---
android/Android.mk | 1 +
android/Makefile.am | 1 +
src/shared/gatt-db.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
src/shared/gatt-db.h | 27 +++++++++++++++++++++++++++
4 files changed, 76 insertions(+)
create mode 100644 src/shared/gatt-db.c
create mode 100644 src/shared/gatt-db.h

diff --git a/android/Android.mk b/android/Android.mk
index 5f4e70c..4c9cfb5 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -51,6 +51,7 @@ LOCAL_SRC_FILES := \
bluez/src/shared/queue.c \
bluez/src/shared/ringbuf.c \
bluez/src/shared/hfp.c \
+ bluez/src/shared/gatt-db.c \
bluez/src/shared/io-glib.c \
bluez/src/sdpd-database.c \
bluez/src/sdpd-service.c \
diff --git a/android/Makefile.am b/android/Makefile.am
index c51cce2..70e1dec 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -29,6 +29,7 @@ android_bluetoothd_SOURCES = android/main.c \
src/shared/mgmt.h src/shared/mgmt.c \
src/shared/ringbuf.h src/shared/ringbuf.c \
src/shared/hfp.h src/shared/hfp.c \
+ src/shared/gatt-db.h src/shared/gatt-db.c \
android/bluetooth.h android/bluetooth.c \
android/hidhost.h android/hidhost.c \
android/ipc-common.h \
diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
new file mode 100644
index 0000000..e56b381
--- /dev/null
+++ b/src/shared/gatt-db.c
@@ -0,0 +1,47 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "src/shared/util.h"
+#include "src/shared/gatt-db.h"
+
+struct gatt_db {
+ uint16_t next_handle;
+};
+
+struct gatt_db *gatt_db_new(void)
+{
+ struct gatt_db *db;
+
+ db = new0(struct gatt_db, 1);
+ if (!db)
+ return NULL;
+
+ db->next_handle = 0x0001;
+
+ return db;
+}
+
+void gatt_db_destroy(struct gatt_db *db)
+{
+ free(db);
+}
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
new file mode 100644
index 0000000..2901afb
--- /dev/null
+++ b/src/shared/gatt-db.h
@@ -0,0 +1,27 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+struct gatt_db;
+
+struct gatt_db *gatt_db_new(void);
+void gatt_db_destroy(struct gatt_db *db);
--
1.8.5.3


2014-04-09 07:07:00

by Marcin Kraglak

[permalink] [raw]
Subject: [RFC 02/16] gatt: Add services list to gatt_db struct

Gatt database will store all services in queue services. Each service
contains attributes, number of handles included and flag if it is
active service.
---
src/shared/gatt-db.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)

diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index e56b381..47915c7 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -21,11 +21,24 @@
*
*/

+#include <stdbool.h>
+
#include "src/shared/util.h"
+#include "src/shared/queue.h"
#include "src/shared/gatt-db.h"

struct gatt_db {
uint16_t next_handle;
+ struct queue *services;
+};
+
+struct gatt_db_attribute {
+};
+
+struct gatt_db_service {
+ bool active;
+ uint16_t num_handles;
+ struct gatt_db_attribute **attributes;
};

struct gatt_db *gatt_db_new(void)
@@ -36,12 +49,31 @@ struct gatt_db *gatt_db_new(void)
if (!db)
return NULL;

+ db->services = queue_new();
+ if (!db->services) {
+ free(db);
+ return NULL;
+ }
+
db->next_handle = 0x0001;

return db;
}

+static void gatt_db_service_destroy(void *data)
+{
+ struct gatt_db_service *service = data;
+ int i;
+
+ for (i = 0; i < service->num_handles; i++)
+ free(service->attributes[i]);
+
+ free(service->attributes);
+ free(service);
+}
+
void gatt_db_destroy(struct gatt_db *db)
{
+ queue_destroy(db->services, gatt_db_service_destroy);
free(db);
}
--
1.8.5.3