2014-04-30 09:13:31

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 00/38] android/gatt: GATT server implementation

This patch set adds major part of GATT server support for Android:
* GATT database extension to get, read and write data
* Handling GATT Server Android requests
* Create listening socket for BLE.
* Support GATT Service
* Support Device Information Service
* Support Service Changed (skeleton)
* some bugfixes

Still some improvements are needed.

Tested on PC and Nexus 5 as peripheral device.

v2:
* Handled comments from Johan
* Added complete callback to database requests
* some bugfixes found during tests with haltest
* Rebase on upstream

v3:
* fixed android/gatt: Add support for send indication

v4:
* simplify communication between gatt server and database
* Some bugfixes

Grzegorz Kolodziejczyk (3):
android/gatt: Add support for ATT read by type
android/gatt: Add MTU request cmd handling
android/gatt: Add Find info gatt server cmd handling

Jakub Tyszkowski (3):
android/gatt: Remove redundant find function parameter
android/gatt: Register device information service
android/gatt: Register GATT service

Lukasz Rymanowski (21):
android/gatt: Rename listen_clients to listen_apps
android/gatt: Add listening socket for GATT
android/gatt: Assume that each server wants waits for connection
android/gatt: Add ATT msg handler
shared/gatt: Use bdaddr instead of request_id
shared/gatt: Extend read/write callback with offset
shared/gatt: Add att_opcode to read/write callback
android/bluetooth: Add function for getting device Android name
android/gatt: Add register GAP Service
gatt: Add some characteristics uuids
android/gatt: Add support for ATT read by group type
shared/gatt: Add support to read from database
android/gatt: Add support to read request
shared/gatt: Add support for write request
android/gatt: Add support for write request
android/gatt: Add support for execute write
android/gatt: Add write_cb to GATT server
android/gatt: Add read_cb for GATT Server
android/hal-gatt-api: Fix IPC definition for send response
android/gatt: Add support for GATT server send response
android/gatt: Add support for send indication

Marcin Kraglak (11):
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 handling of start service command
android/gatt: Add stop service command handling
android/gatt: Add descriptor implementation
shared/gatt: Add function to read by group type
shared/gatt: Add function to find by type
shared/gatt: Add function to read by type
shared/gatt: Add function to find information

android/bluetooth.c | 5 +
android/bluetooth.h | 1 +
android/gatt.c | 1249 +++++++++++++++++++++++++++++++++++++++++++++++---
android/hal-gatt.c | 7 +-
android/hal-msg.h | 3 +
lib/uuid.h | 7 +
src/shared/gatt-db.c | 322 +++++++++++++
src/shared/gatt-db.h | 60 ++-
8 files changed, 1577 insertions(+), 77 deletions(-)

--
1.8.4



2014-04-30 15:31:35

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH v4 00/38] android/gatt: GATT server implementation

Hi,

On Wednesday 30 of April 2014 11:13:31 Lukasz Rymanowski wrote:
> This patch set adds major part of GATT server support for Android:
> * GATT database extension to get, read and write data
> * Handling GATT Server Android requests
> * Create listening socket for BLE.
> * Support GATT Service
> * Support Device Information Service
> * Support Service Changed (skeleton)
> * some bugfixes
>
> Still some improvements are needed.
>
> Tested on PC and Nexus 5 as peripheral device.
>
> v2:
> * Handled comments from Johan
> * Added complete callback to database requests
> * some bugfixes found during tests with haltest
> * Rebase on upstream
>
> v3:
> * fixed android/gatt: Add support for send indication
>
> v4:
> * simplify communication between gatt server and database
> * Some bugfixes
>
> Grzegorz Kolodziejczyk (3):
> android/gatt: Add support for ATT read by type
> android/gatt: Add MTU request cmd handling
> android/gatt: Add Find info gatt server cmd handling
>
> Jakub Tyszkowski (3):
> android/gatt: Remove redundant find function parameter
> android/gatt: Register device information service
> android/gatt: Register GATT service
>
> Lukasz Rymanowski (21):
> android/gatt: Rename listen_clients to listen_apps
> android/gatt: Add listening socket for GATT
> android/gatt: Assume that each server wants waits for connection
> android/gatt: Add ATT msg handler
> shared/gatt: Use bdaddr instead of request_id
> shared/gatt: Extend read/write callback with offset
> shared/gatt: Add att_opcode to read/write callback
> android/bluetooth: Add function for getting device Android name
> android/gatt: Add register GAP Service
> gatt: Add some characteristics uuids
> android/gatt: Add support for ATT read by group type
> shared/gatt: Add support to read from database
> android/gatt: Add support to read request
> shared/gatt: Add support for write request
> android/gatt: Add support for write request
> android/gatt: Add support for execute write
> android/gatt: Add write_cb to GATT server
> android/gatt: Add read_cb for GATT Server
> android/hal-gatt-api: Fix IPC definition for send response
> android/gatt: Add support for GATT server send response
> android/gatt: Add support for send indication
>
> Marcin Kraglak (11):
> 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 handling of start service command
> android/gatt: Add stop service command handling
> android/gatt: Add descriptor implementation
> shared/gatt: Add function to read by group type
> shared/gatt: Add function to find by type
> shared/gatt: Add function to read by type
> shared/gatt: Add function to find information
>
> android/bluetooth.c | 5 +
> android/bluetooth.h | 1 +
> android/gatt.c | 1249 +++++++++++++++++++++++++++++++++++++++++++++++---
> android/hal-gatt.c | 7 +-
> android/hal-msg.h | 3 +
> lib/uuid.h | 7 +
> src/shared/gatt-db.c | 322 +++++++++++++
> src/shared/gatt-db.h | 60 ++-
> 8 files changed, 1577 insertions(+), 77 deletions(-)
>
>

A modified version of this patchset is now pushed upstream.

--
Best regards,
Szymon Janc

2014-04-30 11:31:52

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH v4 00/38] android/gatt: GATT server implementation

Hi,

On Wednesday 30 of April 2014 11:13:31 Lukasz Rymanowski wrote:
> This patch set adds major part of GATT server support for Android:
> * GATT database extension to get, read and write data
> * Handling GATT Server Android requests
> * Create listening socket for BLE.
> * Support GATT Service
> * Support Device Information Service
> * Support Service Changed (skeleton)
> * some bugfixes
>
> Still some improvements are needed.
>
> Tested on PC and Nexus 5 as peripheral device.
>
> v2:
> * Handled comments from Johan
> * Added complete callback to database requests
> * some bugfixes found during tests with haltest
> * Rebase on upstream
>
> v3:
> * fixed android/gatt: Add support for send indication
>
> v4:
> * simplify communication between gatt server and database
> * Some bugfixes
>
> Grzegorz Kolodziejczyk (3):
> android/gatt: Add support for ATT read by type
> android/gatt: Add MTU request cmd handling
> android/gatt: Add Find info gatt server cmd handling
>
> Jakub Tyszkowski (3):
> android/gatt: Remove redundant find function parameter
> android/gatt: Register device information service
> android/gatt: Register GATT service
>
> Lukasz Rymanowski (21):
> android/gatt: Rename listen_clients to listen_apps
> android/gatt: Add listening socket for GATT
> android/gatt: Assume that each server wants waits for connection
> android/gatt: Add ATT msg handler
> shared/gatt: Use bdaddr instead of request_id
> shared/gatt: Extend read/write callback with offset
> shared/gatt: Add att_opcode to read/write callback
> android/bluetooth: Add function for getting device Android name
> android/gatt: Add register GAP Service
> gatt: Add some characteristics uuids
> android/gatt: Add support for ATT read by group type
> shared/gatt: Add support to read from database
> android/gatt: Add support to read request
> shared/gatt: Add support for write request
> android/gatt: Add support for write request
> android/gatt: Add support for execute write
> android/gatt: Add write_cb to GATT server
> android/gatt: Add read_cb for GATT Server
> android/hal-gatt-api: Fix IPC definition for send response
> android/gatt: Add support for GATT server send response
> android/gatt: Add support for send indication
>
> Marcin Kraglak (11):
> 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 handling of start service command
> android/gatt: Add stop service command handling
> android/gatt: Add descriptor implementation
> shared/gatt: Add function to read by group type
> shared/gatt: Add function to find by type
> shared/gatt: Add function to read by type
> shared/gatt: Add function to find information
>
> android/bluetooth.c | 5 +
> android/bluetooth.h | 1 +
> android/gatt.c | 1249 +++++++++++++++++++++++++++++++++++++++++++++++---
> android/hal-gatt.c | 7 +-
> android/hal-msg.h | 3 +
> lib/uuid.h | 7 +
> src/shared/gatt-db.c | 322 +++++++++++++
> src/shared/gatt-db.h | 60 ++-
> 8 files changed, 1577 insertions(+), 77 deletions(-)
>
>

Patches 1-9 are now applied (with some whitespace fixes), thanks.

--
Best regards,
Szymon Janc

2014-04-30 09:13:39

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 08/38] android/gatt: Add stop service command handling

From: Marcin Kraglak <[email protected]>

It will stop service in local database.
---
android/gatt.c | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index 2913007..e888268 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -3372,25 +3372,33 @@ 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_app *server;
uint8_t status;

DBG("");

+ memset(&ev, 0, sizeof(ev));
+
server = find_app_by_id(cmd->server_if);
if (!server) {
- error("gatt: server_if=%d not found", cmd->server_if);
status = HAL_STATUS_FAILED;
goto failed;
}

- status = HAL_STATUS_SUCCESS;
-
- /* TODO: stop service in attribute database */
- DBG("Stop service: server: %d, srvc_hnd: %d", cmd->server_if,
- cmd->service_handle);
+ if (!gatt_db_service_set_active(gatt_db, cmd->service_handle, false))
+ 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, status);
}
--
1.8.4


2014-04-30 09:14:02

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 31/38] shared/gatt: Add support for write request

---
src/shared/gatt-db.c | 24 ++++++++++++++++++++++++
src/shared/gatt-db.h | 4 ++++
2 files changed, 28 insertions(+)

diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index 1f57c8a..f63a7fd 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -704,6 +704,30 @@ bool gatt_db_read(struct gatt_db *db, uint16_t handle, uint16_t offset,

a->read_func(handle, offset, att_opcode, bdaddr, a->user_data);

+ return true;
+}
+
+bool gatt_db_write(struct gatt_db *db, uint16_t handle, uint16_t offset,
+ const uint8_t *value, size_t len,
+ uint8_t att_opcode, bdaddr_t *bdaddr)
+{
+ struct gatt_db_service *service;
+ uint16_t service_handle;
+ struct gatt_db_attribute *a;
+
+ service = queue_find(db->services, find_service_for_handle,
+ INT_TO_PTR(handle));
+ if (!service)
+ return false;
+
+ service_handle = service->attributes[0]->handle;
+
+ a = service->attributes[handle - service_handle];
+ if (!a || !a->write_func)
+ return false;
+
+ a->write_func(handle, offset, value, len, att_opcode, bdaddr,
+ a->user_data);

return true;
}
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index 6cf07db..f704b8e 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -107,3 +107,7 @@ void gatt_db_find_information(struct gatt_db *db, uint16_t start_handle,

bool gatt_db_read(struct gatt_db *db, uint16_t handle, uint16_t offset,
uint8_t att_opcode, bdaddr_t *bdaddr);
+
+bool gatt_db_write(struct gatt_db *db, uint16_t handle, uint16_t offset,
+ const uint8_t *value, size_t len,
+ uint8_t att_opcode, bdaddr_t *bdaddr);
--
1.8.4


2014-04-30 09:13:59

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 28/38] android/gatt: Add support to read request

Added support for read and read blob
---
android/gatt.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)

diff --git a/android/gatt.c b/android/gatt.c
index 2c13522..2177c968 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -3733,6 +3733,37 @@ static uint8_t read_by_type(const uint8_t *cmd, uint16_t cmd_len,
return 0;
}

+static uint8_t read_request(const uint8_t *cmd, uint16_t cmd_len,
+ struct gatt_device *dev)
+{
+ uint16_t handle;
+ uint16_t len;
+ uint16_t offset = 0;
+
+ DBG("");
+
+ switch (cmd[0]) {
+ case ATT_OP_READ_BLOB_REQ:
+ len = dec_read_blob_req(cmd, cmd_len, &handle, &offset);
+ if (!len)
+ return ATT_ECODE_INVALID_PDU;
+ break;
+ case ATT_OP_READ_REQ:
+ len = dec_read_req(cmd, cmd_len, &handle);
+ if (!len)
+ return ATT_ECODE_INVALID_PDU;
+ break;
+ default:
+ error("gatt: Unexpected read type 0x%02x", cmd[0]);
+ return ATT_ECODE_REQ_NOT_SUPP;
+ }
+
+ if (!gatt_db_read(gatt_db, handle, offset, cmd[0], &dev->bdaddr))
+ return ATT_ECODE_UNLIKELY;
+
+ return 0;
+}
+
static void att_handler(const uint8_t *ipdu, uint16_t len, gpointer user_data)
{
struct gatt_device *dev = user_data;
@@ -3760,6 +3791,11 @@ static void att_handler(const uint8_t *ipdu, uint16_t len, gpointer user_data)
break;
case ATT_OP_READ_REQ:
case ATT_OP_READ_BLOB_REQ:
+ status = read_request(ipdu, len, dev);
+ if (!status)
+ /* Response will be sent in callback */
+ return;
+ break;
case ATT_OP_MTU_REQ:
case ATT_OP_FIND_INFO_REQ:
case ATT_OP_WRITE_REQ:
--
1.8.4


2014-04-30 09:14:07

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 36/38] android/hal-gatt-api: Fix IPC definition for send response

---
android/hal-gatt.c | 7 +++++--
android/hal-msg.h | 3 +++
2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/android/hal-gatt.c b/android/hal-gatt.c
index 16b5607..e1faccb 100644
--- a/android/hal-gatt.c
+++ b/android/hal-gatt.c
@@ -1237,9 +1237,12 @@ static bt_status_t send_response(int conn_id, int trans_id, int status,
cmd->conn_id = conn_id;
cmd->trans_id = trans_id;
cmd->status = status;
- cmd->len = sizeof(*response);
+ cmd->handle = response->attr_value.handle;
+ cmd->offset = response->attr_value.offset;
+ cmd->auth_req = response->attr_value.auth_req;
+ cmd->len = response->attr_value.len;

- memcpy(cmd->data, response, sizeof(*response));
+ memcpy(cmd->data, response->attr_value.value, cmd->len);

return hal_ipc_cmd(HAL_SERVICE_ID_GATT,
HAL_OP_GATT_SERVER_SEND_RESPONSE,
diff --git a/android/hal-msg.h b/android/hal-msg.h
index 9d28866..09bd9a0 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -847,6 +847,9 @@ struct hal_cmd_gatt_server_send_indication {
struct hal_cmd_gatt_server_send_response {
int32_t conn_id;
int32_t trans_id;
+ uint16_t handle;
+ uint16_t offset;
+ uint8_t auth_req;
int32_t status;
uint16_t len;
uint8_t data[0];
--
1.8.4


2014-04-30 09:14:08

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 37/38] android/gatt: Add support for GATT server send response

---
android/gatt.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 69 insertions(+), 3 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index 6164044..db83707 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -3297,6 +3297,8 @@ static void send_gatt_response(uint8_t opcode, uint16_t handle,
uint16_t length;
uint8_t pdu[ATT_DEFAULT_LE_MTU];

+ DBG("");
+
dev = find_device_by_addr(bdaddr);
if (!dev) {
error("gatt: send_gatt_response, could not find dev");
@@ -3306,9 +3308,34 @@ static void send_gatt_response(uint8_t opcode, uint16_t handle,
if (!status) {
length = enc_error_resp(opcode, handle, status, pdu,
sizeof(pdu));
- g_attrib_send(dev->attrib, 0, pdu, length, NULL, NULL, NULL);
+ goto done;
+ }
+
+ switch (opcode) {
+ case ATT_OP_EXEC_WRITE_REQ:
+ length = enc_exec_write_resp(pdu);
+ break;
+ case ATT_OP_WRITE_REQ:
+ length = enc_write_resp(pdu);
+ break;
+ case ATT_OP_PREP_WRITE_REQ:
+ length = enc_prep_write_resp(handle, offset, data, len, pdu,
+ sizeof(pdu));
+ break;
+ case ATT_OP_READ_BLOB_REQ:
+ length = enc_read_blob_resp((uint8_t *)data, len, offset, pdu,
+ sizeof(pdu));
+ break;
+ case ATT_OP_READ_REQ:
+ length = enc_read_resp((uint8_t *)data, len, pdu, sizeof(pdu));
+ break;
+ default:
+ error("gatt: Unexpected opcode");
+ return;
}
- /* TODO: Send responses for other commands */
+
+done:
+ g_attrib_send(dev->attrib, 0, pdu, length, NULL, NULL, NULL);
}

static void set_trans_id(struct gatt_app *app, unsigned int id, int8_t opcode)
@@ -3317,6 +3344,13 @@ static void set_trans_id(struct gatt_app *app, unsigned int id, int8_t opcode)
app->trans_id.opcode = opcode;
}

+static void clear_trans_id(struct gatt_app *app)
+{
+ app->trans_id.id = 0;
+ app->trans_id.opcode = 0;
+
+}
+
static void read_cb(uint16_t handle, uint16_t offset, uint8_t att_opcode,
bdaddr_t *bdaddr, void *user_data)
{
@@ -3640,10 +3674,42 @@ static void handle_server_send_indication(const void *buf, uint16_t len)

static void handle_server_send_response(const void *buf, uint16_t len)
{
+ const struct hal_cmd_gatt_server_send_response *cmd = buf;
+ struct app_connection *conn;
+ struct gatt_app *app;
+ uint8_t status;
+
DBG("");

+ conn = find_connection_by_id(cmd->conn_id);
+ if (!conn) {
+ error("gatt: cound not found connection");
+ status = HAL_STATUS_FAILED;
+ goto reply;
+ }
+
+ app = conn->app;
+
+ if ((unsigned int)cmd->trans_id != app->trans_id.id) {
+ error("gatt: trans_id != pend_trans_id (%d!=%d)",
+ cmd->trans_id, app->trans_id.id);
+
+ status = HAL_STATUS_FAILED;
+ goto reply;
+ }
+
+ send_gatt_response(conn->app->trans_id.opcode, cmd->handle, cmd->offset,
+ cmd->status, cmd->len, cmd->data,
+ &conn->device->bdaddr);
+
+ /* Clean request data */
+ clear_trans_id(app);
+
+ status = HAL_STATUS_SUCCESS;
+
+reply:
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_OP_GATT_SERVER_SEND_RESPONSE, HAL_STATUS_FAILED);
+ HAL_OP_GATT_SERVER_SEND_RESPONSE, status);
}

static const struct ipc_handler cmd_handlers[] = {
--
1.8.4


2014-04-30 09:14:09

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 38/38] android/gatt: Add support for send indication

With this patch Android app can send indication to remote device
---
android/gatt.c | 30 +++++++++++++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/android/gatt.c b/android/gatt.c
index db83707..0fcd2ad 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -3666,10 +3666,38 @@ failed:

static void handle_server_send_indication(const void *buf, uint16_t len)
{
+ const struct hal_cmd_gatt_server_send_indication *cmd = buf;
+ uint8_t pdu[ATT_DEFAULT_LE_MTU];
+ struct app_connection *conn;
+ uint8_t status;
+ uint16_t length;
+
DBG("");

+ conn = find_connection_by_id(cmd->conn_id);
+ if (!conn) {
+ error("gatt: Could not find connection");
+ status = HAL_STATUS_FAILED;
+ goto reply;
+ }
+
+ if (cmd->confirm)
+ /* TODO: Add data to track confirmation for this request */
+ length = enc_indication(cmd->attribute_handle,
+ (uint8_t *)cmd->value, cmd->len,
+ pdu, sizeof(pdu));
+ else
+ length = enc_notification(cmd->attribute_handle,
+ (uint8_t *)cmd->value, cmd->len,
+ pdu, sizeof(pdu));
+
+ g_attrib_send(conn->device->attrib, 0, pdu, length, NULL, NULL, NULL);
+
+ status = HAL_STATUS_SUCCESS;
+
+reply:
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_OP_GATT_SERVER_SEND_INDICATION, HAL_STATUS_FAILED);
+ HAL_OP_GATT_SERVER_SEND_INDICATION, status);
}

static void handle_server_send_response(const void *buf, uint16_t len)
--
1.8.4


2014-04-30 09:14:06

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 35/38] android/gatt: Add read_cb for GATT Server

This patch attach read callback to descriptors and characteristics
registered by Android app.
---
android/gatt.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 46 insertions(+), 2 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index 5a1c9ce..6164044 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -3317,6 +3317,50 @@ static void set_trans_id(struct gatt_app *app, unsigned int id, int8_t opcode)
app->trans_id.opcode = opcode;
}

+static void read_cb(uint16_t handle, uint16_t offset, uint8_t att_opcode,
+ bdaddr_t *bdaddr, void *user_data)
+{
+ struct hal_ev_gatt_server_request_read ev;
+ struct gatt_app *app;
+ struct app_connection *conn;
+ int32_t id = PTR_TO_INT(user_data);
+ static int32_t trans_id = 1;
+
+ app = find_app_by_id(id);
+ if (!app) {
+ error("gatt: read_cb, cound not found app id");
+ goto failed;
+ }
+
+ conn = find_conn(bdaddr, app->id);
+ if (!conn) {
+ error("gatt: read_cb, cound not found connection");
+ goto failed;
+ }
+
+ memset(&ev, 0, sizeof(ev));
+
+ /* Store the request data, complete callback and transaction id */
+ set_trans_id(app, trans_id++, att_opcode);
+
+ bdaddr2android(bdaddr, ev.bdaddr);
+ ev.conn_id = conn->id;
+ ev.attr_handle = handle;
+ ev.offset = offset;
+ ev.is_long = att_opcode == ATT_OP_READ_BLOB_REQ ? true : false;
+ ev.trans_id = app->trans_id.id;
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_SERVER_REQUEST_READ,
+ sizeof(ev), &ev);
+
+ return;
+
+failed:
+ send_gatt_response(att_opcode, handle, 0, ATT_ECODE_UNLIKELY, 0,
+ NULL, bdaddr);
+}
+
static void write_cb(uint16_t handle, uint16_t offset,
const uint8_t *value, size_t len,
uint8_t att_opcode, bdaddr_t *bdaddr,
@@ -3411,7 +3455,7 @@ static void handle_server_add_characteristic(const void *buf, uint16_t len)
cmd->service_handle,
&uuid, cmd->permissions,
cmd->properties,
- NULL, write_cb,
+ read_cb, write_cb,
INT_TO_PTR(app_id));
if (!ev.char_handle)
status = HAL_STATUS_FAILED;
@@ -3457,7 +3501,7 @@ static void handle_server_add_descriptor(const void *buf, uint16_t len)
ev.descr_handle = gatt_db_add_char_descriptor(gatt_db,
cmd->service_handle,
&uuid, cmd->permissions,
- NULL, write_cb,
+ read_cb, write_cb,
INT_TO_PTR(app_id));
if (!ev.descr_handle)
status = HAL_STATUS_FAILED;
--
1.8.4


2014-04-30 09:14:05

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 34/38] android/gatt: Add write_cb to GATT server

Write callback is now attached to characteristics and descriptors
registered by Android app.

Transaction id is generated and stored in gatt_app together with
att_opcode
---
android/gatt.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 117 insertions(+), 6 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index b0795d1..5a1c9ce 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -74,6 +74,11 @@ typedef enum {
APP_SERVER,
} gatt_app_type_t;

+struct pending_trans_data {
+ unsigned int id;
+ uint8_t opcode;
+};
+
struct gatt_app {
int32_t id;
uint8_t uuid[16];
@@ -82,6 +87,9 @@ struct gatt_app {

/* Valid for client applications */
struct queue *notifications;
+
+ /* Transaction data valid for server application */
+ struct pending_trans_data trans_id;
};

struct element_id {
@@ -3280,6 +3288,103 @@ failed:
HAL_OP_GATT_SERVER_ADD_INC_SERVICE, status);
}

+static void send_gatt_response(uint8_t opcode, uint16_t handle,
+ uint16_t offset, uint8_t status,
+ uint16_t len, const uint8_t *data,
+ bdaddr_t *bdaddr)
+{
+ struct gatt_device *dev;
+ uint16_t length;
+ uint8_t pdu[ATT_DEFAULT_LE_MTU];
+
+ dev = find_device_by_addr(bdaddr);
+ if (!dev) {
+ error("gatt: send_gatt_response, could not find dev");
+ return;
+ }
+
+ if (!status) {
+ length = enc_error_resp(opcode, handle, status, pdu,
+ sizeof(pdu));
+ g_attrib_send(dev->attrib, 0, pdu, length, NULL, NULL, NULL);
+ }
+ /* TODO: Send responses for other commands */
+}
+
+static void set_trans_id(struct gatt_app *app, unsigned int id, int8_t opcode)
+{
+ app->trans_id.id = id;
+ app->trans_id.opcode = opcode;
+}
+
+static void write_cb(uint16_t handle, uint16_t offset,
+ const uint8_t *value, size_t len,
+ uint8_t att_opcode, bdaddr_t *bdaddr,
+ void *user_data)
+{
+ struct hal_ev_gatt_server_request_exec_write write_exec_ev;
+ struct hal_ev_gatt_server_request_write write_ev;
+ struct gatt_app *app;
+ int32_t id = PTR_TO_INT(user_data);
+ static int32_t trans_id = 1;
+ struct app_connection *conn;
+
+ app = find_app_by_id(id);
+ if (!app) {
+ error("gatt: write_cb, cound not found app id");
+ goto failed;
+ }
+
+ conn = find_conn(bdaddr, app->id);
+ if (!conn) {
+ error("gatt: write_cb, cound not found connection");
+ goto failed;
+ }
+
+ /* Store the request data, complete callback and transaction id */
+ set_trans_id(app, trans_id++, att_opcode);
+
+ if (att_opcode == ATT_OP_EXEC_WRITE_REQ) {
+ memset(&write_exec_ev, 0, sizeof(write_exec_ev));
+
+
+ bdaddr2android(bdaddr, write_exec_ev.bdaddr);
+ write_exec_ev.conn_id = conn->id;
+ write_exec_ev.trans_id = app->trans_id.id;
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_SERVER_REQUEST_EXEC_WRITE,
+ sizeof(write_exec_ev), &write_exec_ev);
+ } else {
+ memset(&write_ev, 0, sizeof(write_ev));
+
+ bdaddr2android(bdaddr, write_exec_ev.bdaddr);
+ write_ev.attr_handle = handle;
+ write_ev.offset = offset;
+
+ write_ev.conn_id = conn->id;
+ write_ev.trans_id = app->trans_id.id;
+
+ write_ev.is_prep =
+ att_opcode == ATT_OP_PREP_WRITE_REQ ? true : false;
+ write_ev.need_rsp =
+ att_opcode == ATT_OP_WRITE_REQ ? true : false;
+
+ write_ev.length = len;
+ memcpy(&write_ev.value, value, len);
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_SERVER_REQUEST_WRITE,
+ sizeof(write_ev), &write_ev);
+ }
+
+ return;
+
+failed:
+ send_gatt_response(att_opcode, handle, 0, ATT_ECODE_UNLIKELY, 0, NULL,
+ bdaddr);
+}
+
static void handle_server_add_characteristic(const void *buf, uint16_t len)
{
const struct hal_cmd_gatt_server_add_characteristic *cmd = buf;
@@ -3287,12 +3392,13 @@ static void handle_server_add_characteristic(const void *buf, uint16_t len)
struct gatt_app *server;
bt_uuid_t uuid;
uint8_t status;
+ int32_t app_id = cmd->server_if;

DBG("");

memset(&ev, 0, sizeof(ev));

- server = find_app_by_id(cmd->server_if);
+ server = find_app_by_id(app_id);
if (!server) {
status = HAL_STATUS_FAILED;
goto failed;
@@ -3300,11 +3406,13 @@ static void handle_server_add_characteristic(const void *buf, uint16_t len)

android2uuid(cmd->uuid, &uuid);

+ /*FIXME: Handle properties. Register callback if needed. */
ev.char_handle = gatt_db_add_characteristic(gatt_db,
cmd->service_handle,
&uuid, cmd->permissions,
cmd->properties,
- NULL, NULL, NULL);
+ NULL, write_cb,
+ INT_TO_PTR(app_id));
if (!ev.char_handle)
status = HAL_STATUS_FAILED;
else
@@ -3313,7 +3421,7 @@ static void handle_server_add_characteristic(const void *buf, uint16_t len)
failed:
ev.srvc_handle = cmd->service_handle;
ev.status = status;
- ev.server_if = cmd->server_if;
+ ev.server_if = app_id;
ev.status = status == HAL_STATUS_SUCCESS ? GATT_SUCCESS : GATT_FAILURE;
memcpy(ev.uuid, cmd->uuid, sizeof(cmd->uuid));

@@ -3331,12 +3439,13 @@ static void handle_server_add_descriptor(const void *buf, uint16_t len)
struct gatt_app *server;
bt_uuid_t uuid;
uint8_t status;
+ int32_t app_id = cmd->server_if;

DBG("");

memset(&ev, 0, sizeof(ev));

- server = find_app_by_id(cmd->server_if);
+ server = find_app_by_id(app_id);
if (!server) {
status = HAL_STATUS_FAILED;
goto failed;
@@ -3344,17 +3453,19 @@ static void handle_server_add_descriptor(const void *buf, uint16_t len)

android2uuid(cmd->uuid, &uuid);

+ /*FIXME: Handle properties. Register callback if needed. */
ev.descr_handle = gatt_db_add_char_descriptor(gatt_db,
cmd->service_handle,
&uuid, cmd->permissions,
- NULL, NULL, NULL);
+ NULL, write_cb,
+ INT_TO_PTR(app_id));
if (!ev.descr_handle)
status = HAL_STATUS_FAILED;
else
status = HAL_STATUS_SUCCESS;

failed:
- ev.server_if = cmd->server_if;
+ ev.server_if = app_id;
ev.srvc_handle = cmd->service_handle;
memcpy(ev.uuid, cmd->uuid, sizeof(cmd->uuid));
ev.status = status == HAL_STATUS_SUCCESS ? GATT_SUCCESS : GATT_FAILURE;
--
1.8.4


2014-04-30 09:14:03

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 32/38] android/gatt: Add support for write request

This patch add support for write request, command and prepare write
---
android/gatt.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 47 insertions(+), 2 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index dfe7dec..785e6d2 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -3892,6 +3892,47 @@ static uint8_t find_info_handle(const uint8_t *cmd, uint16_t cmd_len,
return 0;
}

+static uint8_t write_request(const uint8_t *cmd, uint16_t cmd_len,
+ struct gatt_device *dev)
+{
+ uint16_t handle;
+ uint16_t offset = 0;
+ uint16_t len;
+ uint8_t value[ATT_DEFAULT_LE_MTU];
+ size_t vlen;
+
+ switch (cmd[0]) {
+ case ATT_OP_WRITE_CMD:
+ len = dec_write_cmd(cmd, cmd_len, &handle, value, &vlen);
+ if (!len)
+ return ATT_ECODE_INVALID_PDU;
+
+ break;
+ case ATT_OP_WRITE_REQ:
+ len = dec_write_req(cmd, cmd_len, &handle, value, &vlen);
+ if (!len)
+ return ATT_ECODE_INVALID_PDU;
+
+ break;
+ case ATT_OP_PREP_WRITE_REQ:
+ len = dec_prep_write_req(cmd, cmd_len, &handle, &offset,
+ value, &vlen);
+ if (!len)
+ return ATT_ECODE_INVALID_PDU;
+
+ break;
+ default:
+ error("gatt: Unexpected write type 0x02%x", cmd[0]);
+ return ATT_ECODE_REQ_NOT_SUPP;
+ }
+
+ if (!gatt_db_write(gatt_db, handle, offset, value, vlen, cmd[0],
+ &dev->bdaddr))
+ return ATT_ECODE_UNLIKELY;
+
+ return 0;
+}
+
static void att_handler(const uint8_t *ipdu, uint16_t len, gpointer user_data)
{
struct gatt_device *dev = user_data;
@@ -3934,13 +3975,17 @@ static void att_handler(const uint8_t *ipdu, uint16_t len, gpointer user_data)
break;
case ATT_OP_WRITE_REQ:
case ATT_OP_WRITE_CMD:
+ case ATT_OP_PREP_WRITE_REQ:
+ status = write_request(ipdu, len, dev);
+ if (!status)
+ return;
+ break;
+ case ATT_OP_EXEC_WRITE_REQ:
case ATT_OP_FIND_BY_TYPE_REQ:
case ATT_OP_HANDLE_CNF:
case ATT_OP_HANDLE_IND:
case ATT_OP_HANDLE_NOTIFY:
case ATT_OP_READ_MULTI_REQ:
- case ATT_OP_PREP_WRITE_REQ:
- case ATT_OP_EXEC_WRITE_REQ:
default:
DBG("Unsupported request 0x%02x", ipdu[0]);
status = ATT_ECODE_REQ_NOT_SUPP;
--
1.8.4


2014-04-30 09:14:00

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 29/38] android/gatt: Add MTU request cmd handling

From: Grzegorz Kolodziejczyk <[email protected]>

The Exchange MTU Request is used by the client to inform the server of
client's maximum receive MTU size and request the server to respond with
its maximum receive MTU size.
---
android/gatt.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)

diff --git a/android/gatt.c b/android/gatt.c
index 2177c968..962c71c 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -138,6 +138,8 @@ struct gatt_device {
guint watch_id;
guint server_id;

+ guint mtu_size;
+
int ref;
int conn_cnt;
};
@@ -3764,6 +3766,47 @@ static uint8_t read_request(const uint8_t *cmd, uint16_t cmd_len,
return 0;
}

+static uint8_t mtu_att_handle(const uint8_t *cmd, uint16_t cmd_len,
+ uint8_t *rsp, size_t rsp_size,
+ struct gatt_device *dev,
+ uint16_t *length)
+{
+ uint16_t mtu, imtu;
+ GIOChannel *io;
+ GError *gerr = NULL;
+ uint16_t len;
+
+ DBG("");
+
+ len = dec_mtu_req(cmd, cmd_len, &mtu);
+ if (!len)
+ return ATT_ECODE_INVALID_PDU;
+
+ if (mtu < ATT_DEFAULT_LE_MTU)
+ return ATT_ECODE_REQ_NOT_SUPP;
+
+ io = g_attrib_get_channel(dev->attrib);
+
+ bt_io_get(io, &gerr, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_INVALID);
+
+ if (gerr) {
+ error("bt_io_get: %s", gerr->message);
+ g_error_free(gerr);
+ return ATT_ECODE_UNLIKELY;
+ }
+
+ dev->mtu_size = MIN(mtu, imtu);
+ g_attrib_set_mtu(dev->attrib, dev->mtu_size);
+
+ len = enc_mtu_resp(imtu, rsp, rsp_size);
+ if (!len)
+ return ATT_ECODE_UNLIKELY;
+
+ *length = len;
+
+ return 0;
+}
+
static void att_handler(const uint8_t *ipdu, uint16_t len, gpointer user_data)
{
struct gatt_device *dev = user_data;
@@ -3797,6 +3840,9 @@ static void att_handler(const uint8_t *ipdu, uint16_t len, gpointer user_data)
return;
break;
case ATT_OP_MTU_REQ:
+ status = mtu_att_handle(ipdu, len, opdu, sizeof(opdu), dev,
+ &length);
+ break;
case ATT_OP_FIND_INFO_REQ:
case ATT_OP_WRITE_REQ:
case ATT_OP_WRITE_CMD:
--
1.8.4


2014-04-30 09:14:04

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 33/38] android/gatt: Add support for execute write

---
android/gatt.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/android/gatt.c b/android/gatt.c
index 785e6d2..b0795d1 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -3921,6 +3921,13 @@ static uint8_t write_request(const uint8_t *cmd, uint16_t cmd_len,
return ATT_ECODE_INVALID_PDU;

break;
+ case ATT_OP_EXEC_WRITE_REQ:
+ len = dec_exec_write_req(cmd, cmd_len, value);
+ if (!len)
+ return ATT_ECODE_INVALID_PDU;
+
+ vlen = 1;
+ break;
default:
error("gatt: Unexpected write type 0x02%x", cmd[0]);
return ATT_ECODE_REQ_NOT_SUPP;
@@ -3976,11 +3983,11 @@ static void att_handler(const uint8_t *ipdu, uint16_t len, gpointer user_data)
case ATT_OP_WRITE_REQ:
case ATT_OP_WRITE_CMD:
case ATT_OP_PREP_WRITE_REQ:
+ case ATT_OP_EXEC_WRITE_REQ:
status = write_request(ipdu, len, dev);
if (!status)
return;
break;
- case ATT_OP_EXEC_WRITE_REQ:
case ATT_OP_FIND_BY_TYPE_REQ:
case ATT_OP_HANDLE_CNF:
case ATT_OP_HANDLE_IND:
--
1.8.4


2014-04-30 09:13:58

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 27/38] shared/gatt: Add support to read from database

---
src/shared/gatt-db.c | 36 ++++++++++++++++++++++++++++++++++++
src/shared/gatt-db.h | 3 +++
2 files changed, 39 insertions(+)

diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index cbdd8a0..1f57c8a 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -671,3 +671,39 @@ void gatt_db_find_information(struct gatt_db *db, uint16_t start_handle,

queue_foreach(db->services, find_information, &data);
}
+
+static bool find_service_for_handle(const void *data, const void *user_data)
+{
+ const struct gatt_db_service *service = data;
+ uint16_t handle = PTR_TO_INT(user_data);
+ uint16_t start, end;
+
+ start = service->attributes[0]->handle;
+ end = start + service->num_handles;
+
+ return (start <= handle) && (handle < end);
+}
+
+bool gatt_db_read(struct gatt_db *db, uint16_t handle, uint16_t offset,
+ uint8_t att_opcode, bdaddr_t *bdaddr)
+{
+ struct gatt_db_service *service;
+ uint16_t service_handle;
+ struct gatt_db_attribute *a;
+
+ service = queue_find(db->services, find_service_for_handle,
+ INT_TO_PTR(handle));
+ if (!service)
+ return false;
+
+ service_handle = service->attributes[0]->handle;
+
+ a = service->attributes[handle - service_handle];
+ if (!a || !a->read_func)
+ return false;
+
+ a->read_func(handle, offset, att_opcode, bdaddr, a->user_data);
+
+
+ return true;
+}
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index a91c798..6cf07db 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -104,3 +104,6 @@ struct gatt_db_find_information {
void gatt_db_find_information(struct gatt_db *db, uint16_t start_handle,
uint16_t end_handle,
struct queue *queue);
+
+bool gatt_db_read(struct gatt_db *db, uint16_t handle, uint16_t offset,
+ uint8_t att_opcode, bdaddr_t *bdaddr);
--
1.8.4


2014-04-30 09:14:01

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 30/38] android/gatt: Add Find info gatt server cmd handling

From: Grzegorz Kolodziejczyk <[email protected]>

The Find Information Request is used to obtain the mapping of
attribute handles with their associated types. This allows a
client to discover the list of attributes and their types on
a server.
---
android/gatt.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 88 insertions(+)

diff --git a/android/gatt.c b/android/gatt.c
index 962c71c..dfe7dec 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -3631,6 +3631,31 @@ static void copy_to_att_list_type(void *data, void *user_data)
memcpy(&value[2], hdl_val->value, hdl_val->length);
}

+static void copy_to_att_list_info(void *data, void *user_data)
+{
+ struct copy_att_list_data *l = user_data;
+ struct gatt_db_find_information *info = data;
+ uint8_t *value;
+
+ value = l->adl->data[l->iterator++];
+
+ put_le16(info->handle, value);
+
+ switch (info->uuid.type) {
+ case BT_UUID16:
+ memcpy(&value[2], &info->uuid.value.u16,
+ bt_uuid_len(&info->uuid));
+ break;
+ case BT_UUID128:
+ memcpy(&value[2], &info->uuid.value.u128,
+ bt_uuid_len(&info->uuid));
+ break;
+ default:
+ error("gatt: Unexpected UUID type");
+ break;
+ }
+}
+
static uint8_t read_by_group_type(const uint8_t *cmd, uint16_t cmd_len,
uint8_t *rsp, size_t rsp_size,
uint16_t *length)
@@ -3807,6 +3832,66 @@ static uint8_t mtu_att_handle(const uint8_t *cmd, uint16_t cmd_len,
return 0;
}

+static uint8_t find_info_handle(const uint8_t *cmd, uint16_t cmd_len,
+ uint8_t *rsp, size_t rsp_size,
+ uint16_t *length)
+{
+ struct queue *q;
+ struct gatt_db_find_information *last_element;
+ struct copy_att_list_data l;
+ struct att_data_list *adl;
+ uint16_t start, end;
+ uint16_t num;
+ uint8_t format;
+ uint16_t len;
+
+ DBG("");
+
+ len = dec_find_info_req(cmd, cmd_len, &start, &end);
+ if (!len)
+ return ATT_ECODE_INVALID_PDU;
+
+ q = queue_new();
+ if (!q)
+ return ATT_ECODE_UNLIKELY;
+
+ gatt_db_find_information(gatt_db, start, end, q);
+
+ if (queue_isempty(q)) {
+ queue_destroy(q, NULL);
+ return ATT_ECODE_ATTR_NOT_FOUND;
+ }
+
+ len = queue_length(q);
+
+ last_element = queue_peek_head(q);
+
+ if (last_element->uuid.type == BT_UUID16) {
+ num = sizeof(uint16_t);
+ format = ATT_FIND_INFO_RESP_FMT_16BIT;
+ } else {
+ num = sizeof(uint128_t);
+ format = ATT_FIND_INFO_RESP_FMT_128BIT;
+ }
+
+ adl = att_data_list_alloc(len, num + sizeof(uint16_t));
+
+ l.iterator = 0;
+ l.adl = adl;
+
+ queue_foreach(q, copy_to_att_list_info, &l);
+
+ len = enc_find_info_resp(format, adl, rsp, rsp_size);
+ if (!len)
+ return ATT_ECODE_UNLIKELY;
+
+ *length = len;
+ att_data_list_free(adl);
+ queue_destroy(q, free);
+
+ return 0;
+}
+
static void att_handler(const uint8_t *ipdu, uint16_t len, gpointer user_data)
{
struct gatt_device *dev = user_data;
@@ -3844,6 +3929,9 @@ static void att_handler(const uint8_t *ipdu, uint16_t len, gpointer user_data)
&length);
break;
case ATT_OP_FIND_INFO_REQ:
+ status = find_info_handle(ipdu, len, opdu, sizeof(opdu),
+ &length);
+ break;
case ATT_OP_WRITE_REQ:
case ATT_OP_WRITE_CMD:
case ATT_OP_FIND_BY_TYPE_REQ:
--
1.8.4


2014-04-30 09:13:55

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 24/38] shared/gatt: Add function to find information

From: Marcin Kraglak <[email protected]>

It will return list of handle and uuid
---
src/shared/gatt-db.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/shared/gatt-db.h | 9 ++++++++
2 files changed, 67 insertions(+)

diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index 60d3140..cbdd8a0 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -613,3 +613,61 @@ void gatt_db_read_by_type(struct gatt_db *db, uint16_t start_handle,

queue_foreach(db->services, read_by_type, &data);
}
+
+
+struct find_information_data {
+ struct queue *queue;
+ uint16_t start_handle;
+ uint16_t end_handle;
+};
+
+static void find_information(void *data, void *user_data)
+{
+ struct find_information_data *search_data = user_data;
+ struct gatt_db_service *service = data;
+ struct gatt_db_attribute *attribute;
+ struct gatt_db_find_information *value;
+ int i;
+
+ if (!service->active)
+ return;
+
+ /* Check if service is in range */
+ if ((service->attributes[0]->handle + service->num_handles - 1) <
+ search_data->start_handle)
+ return;
+
+ for (i = 0; i < service->num_handles; i++) {
+ attribute = service->attributes[i];
+ if (!attribute)
+ continue;
+
+ if (attribute->handle < search_data->start_handle)
+ continue;
+
+ if (attribute->handle > search_data->end_handle)
+ return;
+
+ value = new0(struct gatt_db_find_information, 1);
+ if (!value)
+ return;
+
+ value->handle = attribute->handle;
+ value->uuid = attribute->uuid;
+ if (!queue_push_tail(search_data->queue, value))
+ free(value);
+ }
+}
+
+void gatt_db_find_information(struct gatt_db *db, uint16_t start_handle,
+ uint16_t end_handle,
+ struct queue *queue)
+{
+ struct find_information_data data;
+
+ data.start_handle = start_handle;
+ data.end_handle = end_handle;
+ data.queue = queue;
+
+ queue_foreach(db->services, find_information, &data);
+}
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index b5f9073..a91c798 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -95,3 +95,12 @@ void gatt_db_read_by_type(struct gatt_db *db, uint16_t start_handle,
uint16_t end_handle,
const bt_uuid_t type,
struct queue *queue);
+
+struct gatt_db_find_information {
+ uint16_t handle;
+ bt_uuid_t uuid;
+};
+
+void gatt_db_find_information(struct gatt_db *db, uint16_t start_handle,
+ uint16_t end_handle,
+ struct queue *queue);
--
1.8.4


2014-04-30 09:13:57

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 26/38] android/gatt: Add support for ATT read by type

From: Grzegorz Kolodziejczyk <[email protected]>

---
android/gatt.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 68 insertions(+)

diff --git a/android/gatt.c b/android/gatt.c
index d4d6a38..2c13522 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -3616,6 +3616,19 @@ static void copy_to_att_list(void *data, void *user_data)
memcpy(&value[4], group->value, group->len);
}

+static void copy_to_att_list_type(void *data, void *user_data)
+{
+ struct copy_att_list_data *l = user_data;
+ struct gatt_db_handle_value *hdl_val = data;
+ uint8_t *value;
+
+ value = l->adl->data[l->iterator++];
+
+ put_le16(hdl_val->handle, value);
+
+ memcpy(&value[2], hdl_val->value, hdl_val->length);
+}
+
static uint8_t read_by_group_type(const uint8_t *cmd, uint16_t cmd_len,
uint8_t *rsp, size_t rsp_size,
uint16_t *length)
@@ -3667,6 +3680,59 @@ static uint8_t read_by_group_type(const uint8_t *cmd, uint16_t cmd_len,
return 0;
}

+static uint8_t read_by_type(const uint8_t *cmd, uint16_t cmd_len,
+ uint8_t *rsp, size_t rsp_size,
+ uint16_t *length)
+{
+ uint16_t start, end;
+ uint16_t len;
+ bt_uuid_t uuid;
+ struct queue *q;
+ struct att_data_list *adl;
+ struct copy_att_list_data l;
+ struct gatt_db_handle_value *h;
+
+ DBG("");
+
+ len = dec_read_by_type_req(cmd, cmd_len, &start, &end, &uuid);
+ if (!len)
+ return ATT_ECODE_INVALID_PDU;
+
+ q = queue_new();
+ if (!q)
+ return ATT_ECODE_INSUFF_RESOURCES;
+
+ gatt_db_read_by_type(gatt_db, start, end, uuid, q);
+
+ if (queue_isempty(q)) {
+ queue_destroy(q, NULL);
+ return ATT_ECODE_ATTR_NOT_FOUND;
+ }
+
+ len = queue_length(q);
+ h = queue_peek_tail(q);
+
+ /* Element here is handle + value*/
+ adl = att_data_list_alloc(len, sizeof(uint16_t) + h->length);
+ if (adl == NULL) {
+ queue_destroy(q, NULL);
+ return ATT_ECODE_INSUFF_RESOURCES;
+ }
+
+ l.iterator = 0;
+ l.adl = adl;
+
+ queue_foreach(q, copy_to_att_list_type, &l);
+
+ len = enc_read_by_type_resp(adl, rsp, rsp_size);
+ *length = len;
+
+ att_data_list_free(adl);
+ queue_destroy(q, free);
+
+ return 0;
+}
+
static void att_handler(const uint8_t *ipdu, uint16_t len, gpointer user_data)
{
struct gatt_device *dev = user_data;
@@ -3690,6 +3756,8 @@ static void att_handler(const uint8_t *ipdu, uint16_t len, gpointer user_data)
&length);
break;
case ATT_OP_READ_BY_TYPE_REQ:
+ status = read_by_type(ipdu, len, opdu, sizeof(opdu), &length);
+ break;
case ATT_OP_READ_REQ:
case ATT_OP_READ_BLOB_REQ:
case ATT_OP_MTU_REQ:
--
1.8.4


2014-04-30 09:13:56

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 25/38] android/gatt: Add support for ATT read by group type

---
android/gatt.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)

diff --git a/android/gatt.c b/android/gatt.c
index d588a56..d4d6a38 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -3597,17 +3597,98 @@ static const struct ipc_handler cmd_handlers[] = {
sizeof(struct hal_cmd_gatt_server_send_response) },
};

+struct copy_att_list_data {
+ int iterator;
+ struct att_data_list *adl;
+};
+
+static void copy_to_att_list(void *data, void *user_data)
+{
+ struct copy_att_list_data *l = user_data;
+ struct gatt_db_group *group = data;
+ uint8_t *value;
+
+ value = l->adl->data[l->iterator++];
+
+ put_le16(group->handle, value);
+ put_le16(group->end_group, &value[2]);
+
+ memcpy(&value[4], group->value, group->len);
+}
+
+static uint8_t read_by_group_type(const uint8_t *cmd, uint16_t cmd_len,
+ uint8_t *rsp, size_t rsp_size,
+ uint16_t *length)
+{
+ uint16_t start, end;
+ uint16_t len;
+ bt_uuid_t uuid;
+ struct queue *q;
+ struct att_data_list *adl;
+ struct copy_att_list_data l;
+ struct gatt_db_group *d;
+
+ len = dec_read_by_grp_req(cmd, cmd_len, &start, &end, &uuid);
+ if (!len)
+ return ATT_ECODE_INVALID_PDU;
+
+ q = queue_new();
+ if (!q)
+ return ATT_ECODE_INSUFF_RESOURCES;
+
+ gatt_db_read_by_group_type(gatt_db, start, end, uuid, q);
+
+ if (queue_isempty(q)) {
+ queue_destroy(q, NULL);
+ return ATT_ECODE_ATTR_NOT_FOUND;
+ }
+
+ len = queue_length(q);
+ d = queue_peek_head(q);
+
+ /* Element contains start/end handle + size of uuid */
+ adl = att_data_list_alloc(len, 2 * sizeof(uint16_t) + d->len);
+ if (adl == NULL) {
+ queue_destroy(q, NULL);
+ return ATT_ECODE_INSUFF_RESOURCES;
+ }
+
+ l.iterator = 0;
+ l.adl = adl;
+
+ queue_foreach(q, copy_to_att_list, &l);
+
+ len = enc_read_by_grp_resp(adl, rsp, rsp_size);
+ *length = len;
+
+ att_data_list_free(adl);
+ queue_destroy(q, free);
+
+ return 0;
+}
+
static void att_handler(const uint8_t *ipdu, uint16_t len, gpointer user_data)
{
struct gatt_device *dev = user_data;
uint8_t opdu[ATT_DEFAULT_LE_MTU];
uint8_t status;
uint16_t length = 0;
+ size_t vlen;
+ uint8_t *value = g_attrib_get_buffer(dev->attrib, &vlen);

DBG("op 0x%02x", ipdu[0]);

+ if (len > vlen) {
+ error("Too much data on ATT socket %p", value);
+ status = ATT_ECODE_INVALID_PDU;
+ goto done;
+ }
+
switch (ipdu[0]) {
case ATT_OP_READ_BY_GROUP_REQ:
+ status = read_by_group_type(ipdu, len, opdu, sizeof(opdu),
+ &length);
+ break;
case ATT_OP_READ_BY_TYPE_REQ:
case ATT_OP_READ_REQ:
case ATT_OP_READ_BLOB_REQ:
--
1.8.4


2014-04-30 09:13:53

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 22/38] shared/gatt: Add function to find by type

From: Marcin Kraglak <[email protected]>

It will look for attributes with given uuid and value.
---
src/shared/gatt-db.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/shared/gatt-db.h | 12 +++++++++
2 files changed, 84 insertions(+)

diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index 26fdc84..c3645f1 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -480,3 +480,75 @@ void gatt_db_read_by_group_type(struct gatt_db *db, uint16_t start_handle,

queue_foreach(db->services, read_by_group_type, &data);
}
+
+struct find_by_type_value_data {
+ struct queue *queue;
+ bt_uuid_t uuid;
+ uint16_t start_handle;
+ uint16_t end_handle;
+ uint16_t value_length;
+ const uint8_t *value;
+};
+
+static void find_by_type_value(void *data, void *user_data)
+{
+ struct find_by_type_value_data *search_data = user_data;
+ struct gatt_db_service *service = data;
+ struct gatt_db_attribute *attribute;
+ struct gatt_db_range *range;
+ int i;
+
+ if (!service->active)
+ return;
+
+ for (i = 0; i < service->num_handles; i++) {
+ attribute = service->attributes[i];
+
+ if (!attribute)
+ continue;
+
+ if ((attribute->handle < search_data->start_handle) ||
+ (attribute->handle > search_data->end_handle))
+ continue;
+
+ if (bt_uuid_cmp(&search_data->uuid, &attribute->uuid))
+ continue;
+
+ if (attribute->value_len != search_data->value_length)
+ continue;
+
+ if (!memcmp(attribute->value, search_data->value,
+ attribute->value_len))
+ continue;
+
+ range = new0(struct gatt_db_range, 1);
+ if (!range)
+ return;
+
+ range->handle = attribute->handle;
+ range->end_group = service->attributes[0]->handle +
+ service->num_handles - 1;
+
+ if (!queue_push_tail(search_data->queue, range))
+ free(range);
+ }
+}
+
+void gatt_db_find_by_type_value(struct gatt_db *db, uint16_t start_handle,
+ uint16_t end_handle,
+ const bt_uuid_t type,
+ const uint8_t *value,
+ uint16_t length,
+ struct queue *queue)
+{
+ struct find_by_type_value_data data;
+
+ data.uuid = type;
+ data.start_handle = start_handle;
+ data.end_handle = end_handle;
+ data.queue = queue;
+ data.value_length = length;
+ data.value = value;
+
+ queue_foreach(db->services, find_by_type_value, &data);
+}
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index 8c04c0f..9bfdb12 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -72,3 +72,15 @@ void gatt_db_read_by_group_type(struct gatt_db *db, uint16_t start_handle,
uint16_t end_handle,
const bt_uuid_t type,
struct queue *queue);
+
+struct gatt_db_range {
+ uint16_t handle;
+ uint16_t end_group;
+};
+
+void gatt_db_find_by_type_value(struct gatt_db *db, uint16_t start_handle,
+ uint16_t end_handle,
+ const bt_uuid_t type,
+ const uint8_t *value,
+ uint16_t length,
+ struct queue *queue);
--
1.8.4


2014-04-30 09:13:45

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 14/38] shared/gatt: Extend read/write callback with offset

Offset is needed for read blob and prep write
---
src/shared/gatt-db.h | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index 0261e5b..d05f4c1 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -30,12 +30,12 @@ uint16_t gatt_db_add_service(struct gatt_db *db, const bt_uuid_t *uuid,
bool primary, 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, bdaddr_t *bdaddr,
- void *user_data);
+typedef void (*gatt_db_read_t) (uint16_t handle, uint16_t offset,
+ bdaddr_t *bdaddr, void *user_data);

-typedef void (*gatt_db_write_t) (uint16_t handle, const uint8_t *value,
- size_t len, bdaddr_t *bdaddr,
- void *user_data);
+typedef void (*gatt_db_write_t) (uint16_t handle, uint16_t offset,
+ const uint8_t *value, size_t len,
+ bdaddr_t *bdaddr, void *user_data);

uint16_t gatt_db_add_characteristic(struct gatt_db *db, uint16_t handle,
const bt_uuid_t *uuid,
--
1.8.4


2014-04-30 09:13:44

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 13/38] shared/gatt: Use bdaddr instead of request_id

As it turns out we do not need request_id but bdaddr. It is because
response to remote device will be sent from read/write callback.
---
src/shared/gatt-db.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index f68f4b3..0261e5b 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -30,12 +30,12 @@ uint16_t gatt_db_add_service(struct gatt_db *db, const bt_uuid_t *uuid,
bool primary, 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, uint16_t request_id,
+typedef void (*gatt_db_read_t) (uint16_t handle, bdaddr_t *bdaddr,
void *user_data);

-typedef void (*gatt_db_write_t) (uint16_t handle, uint16_t request_id,
- const uint8_t *value, size_t len,
- void *user_data);
+typedef void (*gatt_db_write_t) (uint16_t handle, const uint8_t *value,
+ size_t len, bdaddr_t *bdaddr,
+ void *user_data);

uint16_t gatt_db_add_characteristic(struct gatt_db *db, uint16_t handle,
const bt_uuid_t *uuid,
--
1.8.4


2014-04-30 09:13:54

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 23/38] shared/gatt: Add function to read by type

From: Marcin Kraglak <[email protected]>

It will return list of attributes with given type.
---
src/shared/gatt-db.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/shared/gatt-db.h | 11 ++++++++++
2 files changed, 72 insertions(+)

diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index c3645f1..60d3140 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -552,3 +552,64 @@ void gatt_db_find_by_type_value(struct gatt_db *db, uint16_t start_handle,

queue_foreach(db->services, find_by_type_value, &data);
}
+
+struct read_by_type_data {
+ struct queue *queue;
+ bt_uuid_t uuid;
+ uint16_t start_handle;
+ uint16_t end_handle;
+};
+
+static void read_by_type(void *data, void *user_data)
+{
+ struct read_by_type_data *search_data = user_data;
+ struct gatt_db_service *service = data;
+ struct gatt_db_attribute *attribute;
+ struct gatt_db_handle_value *value;
+ int i;
+
+ if (!service->active)
+ return;
+
+ for (i = 0; i < service->num_handles; i++) {
+ attribute = service->attributes[i];
+ if (!attribute)
+ continue;
+
+ if (attribute->handle < search_data->start_handle)
+ continue;
+
+ if (attribute->handle > search_data->end_handle)
+ return;
+
+ if (bt_uuid_cmp(&search_data->uuid, &attribute->uuid))
+ continue;
+
+ value = malloc0(sizeof(struct gatt_db_handle_value) +
+ attribute->value_len);
+ if (!value)
+ return;
+
+ value->handle = attribute->handle;
+ value->length = attribute->value_len;
+ if (attribute->value_len)
+ memcpy(value->value, attribute->value, value->length);
+
+ if (!queue_push_tail(search_data->queue, value))
+ free(value);
+ }
+}
+
+void gatt_db_read_by_type(struct gatt_db *db, uint16_t start_handle,
+ uint16_t end_handle,
+ const bt_uuid_t type,
+ struct queue *queue)
+{
+ struct read_by_type_data data;
+ data.uuid = type;
+ data.start_handle = start_handle;
+ data.end_handle = end_handle;
+ data.queue = queue;
+
+ queue_foreach(db->services, read_by_type, &data);
+}
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index 9bfdb12..b5f9073 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -84,3 +84,14 @@ void gatt_db_find_by_type_value(struct gatt_db *db, uint16_t start_handle,
const uint8_t *value,
uint16_t length,
struct queue *queue);
+
+struct gatt_db_handle_value {
+ uint16_t handle;
+ uint16_t length;
+ uint8_t value[0];
+};
+
+void gatt_db_read_by_type(struct gatt_db *db, uint16_t start_handle,
+ uint16_t end_handle,
+ const bt_uuid_t type,
+ struct queue *queue);
--
1.8.4


2014-04-30 09:13:49

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 18/38] gatt: Add some characteristics uuids

These characteristics uuids will be used in following patch
---
lib/uuid.h | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/lib/uuid.h b/lib/uuid.h
index 237145b..814fd92 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -118,6 +118,13 @@ extern "C" {
#define GATT_CHARAC_RECONNECTION_ADDRESS 0x2A03
#define GATT_CHARAC_PERIPHERAL_PREF_CONN 0x2A04
#define GATT_CHARAC_SERVICE_CHANGED 0x2A05
+#define GATT_CHARAC_SYSTEM_ID 0x2A23
+#define GATT_CHARAC_MODEL_NUMBER_STRING 0x2A24
+#define GATT_CHARAC_SERIAL_NUMBER_STRING 0x2A25
+#define GATT_CHARAC_FIRMWARE_REVISION_STRING 0x2A26
+#define GATT_CHARAC_HARDWARE_REVISION_STRING 0x2A27
+#define GATT_CHARAC_SOFTWARE_REVISION_STRING 0x2A28
+#define GATT_CHARAC_MANUFACTURER_NAME_STRING 0x2A29

/* GATT Characteristic Descriptors */
#define GATT_CHARAC_EXT_PROPER_UUID 0x2900
--
1.8.4


2014-04-30 09:13:48

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 17/38] android/gatt: Add register GAP Service

Register GAP service with device name characteristic,
appearance and peripheral privacy flag
---
android/gatt.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 97 insertions(+)

diff --git a/android/gatt.c b/android/gatt.c
index c2f43b5..ef8bd7c 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -3706,6 +3706,101 @@ static void connect_event(GIOChannel *io, GError *gerr, void *user_data)
error("gatt: Could not attach to server");
}

+struct gap_srvc_handles {
+ uint16_t srvc;
+
+ /* Characteristics */
+ uint16_t dev_name;
+ uint16_t appear;
+ uint16_t priv;
+};
+
+static struct gap_srvc_handles gap_srvc_data;
+
+#define APPEARANCE_GENERIC_PHONE 0x0040
+#define PERIPHERAL_PRIVACY_DISABLE 0x00
+
+static void gap_read_cb(uint16_t handle, uint16_t offset, uint8_t att_opcode,
+ bdaddr_t *bdaddr, void *user_data)
+{
+ uint8_t pdu[ATT_DEFAULT_LE_MTU];
+ uint16_t len;
+ struct gatt_device *dev;
+
+ DBG("");
+
+ dev = find_device_by_addr(bdaddr);
+ if (!dev) {
+ error("gatt: Could not find device ?!");
+ return;
+ }
+
+ if (handle == gap_srvc_data.dev_name) {
+ const char *name = bt_get_adapter_name();
+
+ len = enc_read_resp((uint8_t *)name, strlen(name),
+ pdu, sizeof(pdu));
+ goto done;
+ }
+
+ if (handle == gap_srvc_data.appear) {
+ uint8_t val[2];
+ put_le16(APPEARANCE_GENERIC_PHONE, val);
+ len = enc_read_resp(val, sizeof(val), pdu, sizeof(pdu));
+ goto done;
+ }
+
+ if (handle == gap_srvc_data.priv) {
+ uint8_t val = PERIPHERAL_PRIVACY_DISABLE;
+ len = enc_read_resp(&val, sizeof(val), pdu, sizeof(pdu));
+ goto done;
+ }
+
+ error("gatt: Unknown handle 0x%02x", handle);
+ len = enc_error_resp(ATT_OP_READ_REQ, handle,
+ ATT_ECODE_UNLIKELY, pdu, sizeof(pdu));
+
+done:
+ g_attrib_send(dev->attrib, 0, pdu, len, NULL, NULL, NULL);
+}
+
+static void register_gap_service(void)
+{
+ bt_uuid_t uuid;
+
+ /* GAP UUID */
+ bt_uuid16_create(&uuid, 0x1800);
+ gap_srvc_data.srvc = gatt_db_add_service(gatt_db, &uuid, true, 7);
+
+ /* Device name characteristic */
+ bt_uuid16_create(&uuid, GATT_CHARAC_DEVICE_NAME);
+ gap_srvc_data.dev_name =
+ gatt_db_add_characteristic(gatt_db, gap_srvc_data.srvc,
+ &uuid, 0,
+ GATT_CHR_PROP_READ,
+ gap_read_cb, NULL,
+ NULL);
+
+ /* Appearance */
+ bt_uuid16_create(&uuid, GATT_CHARAC_APPEARANCE);
+ gap_srvc_data.appear =
+ gatt_db_add_characteristic(gatt_db, gap_srvc_data.srvc,
+ &uuid, 0,
+ GATT_CHR_PROP_READ,
+ gap_read_cb, NULL,
+ NULL);
+
+ /* Pripheral privacy flag */
+ bt_uuid16_create(&uuid, GATT_CHARAC_PERIPHERAL_PRIV_FLAG);
+ gap_srvc_data.priv =
+ gatt_db_add_characteristic(gatt_db, gap_srvc_data.srvc,
+ &uuid, 0,
+ GATT_CHR_PROP_READ,
+ gap_read_cb, NULL,
+ NULL);
+
+ gatt_db_service_set_active(gatt_db, gap_srvc_data.srvc , true);
+}
static int start_listen_socket(void)
{
GError *gerr = NULL;
@@ -3772,6 +3867,8 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
if (start_listen_socket() < 0)
error("Could not start GATT listening");

+ register_gap_service();
+
return true;
}

--
1.8.4


2014-04-30 09:13:52

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 21/38] shared/gatt: Add function to read by group type

From: Marcin Kraglak <[email protected]>

It will return list of gropu values, starting handle, end handle and
service attrtbute value.
---
src/shared/gatt-db.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/shared/gatt-db.h | 13 ++++++++++
2 files changed, 84 insertions(+)

diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index 8675dcc..26fdc84 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -409,3 +409,74 @@ bool gatt_db_service_set_active(struct gatt_db *db, uint16_t handle,

return true;
}
+
+struct read_by_group_type_data {
+ struct queue *queue;
+ bt_uuid_t uuid;
+ uint16_t start_handle;
+ uint16_t end_handle;
+ uint16_t uuid_size;
+ bool stop_search;
+};
+
+static void read_by_group_type(void *data, void *user_data)
+{
+ struct read_by_group_type_data *search_data = user_data;
+ struct gatt_db_service *service = data;
+ struct gatt_db_group *group;
+
+ if (!service->active)
+ return;
+
+ /* Don't want more results as they have different size*/
+ if (search_data->stop_search)
+ return;
+
+ if (bt_uuid_cmp(&search_data->uuid, &service->attributes[0]->uuid))
+ return;
+
+ if (service->attributes[0]->handle < search_data->start_handle)
+ return;
+
+ /* Remember size of uuid */
+ if (!search_data->uuid_size) {
+ search_data->uuid_size = service->attributes[0]->value_len;
+ } else if (search_data->uuid_size !=
+ service->attributes[0]->value_len) {
+
+ /* Don't want more results. This is last */
+ search_data->stop_search = true;
+ return;
+ }
+
+ group = malloc0(sizeof(struct gatt_db_group) +
+ service->attributes[0]->value_len);
+ if (!group)
+ return;
+
+ group->len = service->attributes[0]->value_len;
+ memcpy(group->value, service->attributes[0]->value, group->len);
+ group->handle = service->attributes[0]->handle;
+ group->end_group = service->attributes[0]->handle +
+ service->num_handles - 1;
+
+ if (!queue_push_tail(search_data->queue, group))
+ free(group);
+}
+
+void gatt_db_read_by_group_type(struct gatt_db *db, uint16_t start_handle,
+ uint16_t end_handle,
+ const bt_uuid_t type,
+ struct queue *queue)
+{
+ struct read_by_group_type_data data;
+
+ data.uuid = type;
+ data.start_handle = start_handle;
+ data.end_handle = end_handle;
+ data.queue = queue;
+ data.uuid_size = 0;
+ data.stop_search = false;
+
+ queue_foreach(db->services, read_by_group_type, &data);
+}
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index 74817a0..8c04c0f 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -59,3 +59,16 @@ uint16_t gatt_db_add_included_service(struct gatt_db *db, uint16_t handle,

bool gatt_db_service_set_active(struct gatt_db *db, uint16_t handle,
bool active);
+
+struct gatt_db_group {
+ uint16_t handle;
+ uint16_t end_group;
+ uint16_t len;
+ uint8_t value[0];
+};
+
+/* Returns queue with struct gatt_db_group */
+void gatt_db_read_by_group_type(struct gatt_db *db, uint16_t start_handle,
+ uint16_t end_handle,
+ const bt_uuid_t type,
+ struct queue *queue);
--
1.8.4


2014-04-30 09:13:51

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 20/38] android/gatt: Register GATT service

From: Jakub Tyszkowski <[email protected]>

This adds database record about gatt's 'services changed'
characteristic. Proper flag in device is being set to mark it for
notification if gatt services are changed.
---
android/gatt.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)

diff --git a/android/gatt.c b/android/gatt.c
index f5aad93..d588a56 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -133,6 +133,8 @@ struct gatt_device {
GIOChannel *att_io;
struct queue *services;

+ bool notify_services_changed;
+
guint watch_id;
guint server_id;

@@ -3898,6 +3900,49 @@ static void register_device_info_service(void)
gatt_db_service_set_active(gatt_db, srvc_handle, true);
}

+static void gatt_srvc_change_register_cb(uint16_t handle, uint16_t offset,
+ const uint8_t *val, size_t len,
+ uint8_t att_opcode,
+ bdaddr_t *bdaddr,
+ void *user_data)
+{
+ uint8_t pdu[ATT_DEFAULT_LE_MTU];
+ struct gatt_device *dev;
+ uint16_t length;
+
+ dev = find_device_by_addr(bdaddr);
+ if (!dev) {
+ error("gatt: Could not find device ?!");
+ return;
+ }
+
+ /* Set services changed notification flag */
+ dev->notify_services_changed = !!(*val);
+
+ length = enc_write_resp(pdu);
+
+ g_attrib_send(dev->attrib, 0, pdu, length, NULL, NULL, NULL);
+}
+
+static void register_gatt_service(void)
+{
+ bt_uuid_t uuid;
+ uint16_t srvc_handle;
+
+ DBG("");
+
+ bt_uuid16_create(&uuid, 0x1801);
+ srvc_handle = gatt_db_add_service(gatt_db, &uuid, true, 3);
+
+ bt_uuid16_create(&uuid, GATT_CHARAC_SERVICE_CHANGED);
+ gatt_db_add_characteristic(gatt_db, srvc_handle, &uuid, 0,
+ GATT_CHR_PROP_INDICATE,
+ NULL, gatt_srvc_change_register_cb,
+ NULL);
+
+ gatt_db_service_set_active(gatt_db, srvc_handle, true);
+}
+
static int start_listen_socket(void)
{
GError *gerr = NULL;
@@ -3966,6 +4011,7 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)

register_gap_service();
register_device_info_service();
+ register_gatt_service();

return true;
}
--
1.8.4


2014-04-30 09:13:50

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 19/38] android/gatt: Register device information service

From: Jakub Tyszkowski <[email protected]>

This adds placeholder data to device information service. To get
real data we should figure out the best way to get Android's system
properties and expose them to profiles for reading.
---
android/gatt.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 98 insertions(+)

diff --git a/android/gatt.c b/android/gatt.c
index ef8bd7c..f5aad93 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -3801,6 +3801,103 @@ static void register_gap_service(void)

gatt_db_service_set_active(gatt_db, gap_srvc_data.srvc , true);
}
+
+/* TODO: Get those data from device possible via androig/bluetooth.c */
+static struct device_info {
+ const char *manufacturer_name;
+ const char *system_id;
+ const char *model_number;
+ const char *serial_number;
+ const char *firmware_rev;
+ const char *hardware_rev;
+ const char *software_rev;
+} device_info = {
+ .manufacturer_name = "BlueZ",
+ .system_id = "BlueZ for Android",
+ .model_number = "model no",
+ .serial_number = "serial no",
+ .firmware_rev = "firmware rev",
+ .hardware_rev = "hardware rev",
+ .software_rev = "software rev",
+};
+
+static void device_info_read_cb(uint16_t handle, uint16_t offset,
+ uint8_t att_opcode, bdaddr_t *bdaddr,
+ void *user_data)
+{
+ uint8_t pdu[ATT_DEFAULT_LE_MTU];
+ struct gatt_device *dev;
+ char *buf = user_data;
+ uint16_t len;
+
+ dev = find_device_by_addr(bdaddr);
+ if (!dev) {
+ error("gatt: Could not find device ?!");
+ return;
+ }
+
+ len = enc_read_resp((uint8_t *) buf, strlen(buf), pdu, sizeof(pdu));
+
+ g_attrib_send(dev->attrib, 0, pdu, len, NULL, NULL, NULL);
+}
+
+static void register_device_info_service(void)
+{
+ bt_uuid_t uuid;
+ uint16_t srvc_handle;
+
+ DBG("");
+
+ /* Device Information Service */
+ bt_uuid16_create(&uuid, 0x180a);
+ srvc_handle = gatt_db_add_service(gatt_db, &uuid, true, 15);
+
+ /* User data are not const hence (void *) cast is used */
+ bt_uuid16_create(&uuid, GATT_CHARAC_SYSTEM_ID);
+ gatt_db_add_characteristic(gatt_db, srvc_handle, &uuid, 0,
+ GATT_CHR_PROP_READ,
+ device_info_read_cb, NULL,
+ (void *) device_info.system_id);
+
+ bt_uuid16_create(&uuid, GATT_CHARAC_MODEL_NUMBER_STRING);
+ gatt_db_add_characteristic(gatt_db, srvc_handle, &uuid, 0,
+ GATT_CHR_PROP_READ,
+ device_info_read_cb, NULL,
+ (void *) device_info.model_number);
+
+ bt_uuid16_create(&uuid, GATT_CHARAC_SERIAL_NUMBER_STRING);
+ gatt_db_add_characteristic(gatt_db, srvc_handle, &uuid, 0,
+ GATT_CHR_PROP_READ,
+ device_info_read_cb, NULL,
+ (void *) device_info.serial_number);
+
+ bt_uuid16_create(&uuid, GATT_CHARAC_FIRMWARE_REVISION_STRING);
+ gatt_db_add_characteristic(gatt_db, srvc_handle, &uuid, 0,
+ GATT_CHR_PROP_READ,
+ device_info_read_cb, NULL,
+ (void *) device_info.firmware_rev);
+
+ bt_uuid16_create(&uuid, GATT_CHARAC_HARDWARE_REVISION_STRING);
+ gatt_db_add_characteristic(gatt_db, srvc_handle, &uuid, 0,
+ GATT_CHR_PROP_READ,
+ device_info_read_cb, NULL,
+ (void *) device_info.hardware_rev);
+
+ bt_uuid16_create(&uuid, GATT_CHARAC_SOFTWARE_REVISION_STRING);
+ gatt_db_add_characteristic(gatt_db, srvc_handle, &uuid, 0,
+ GATT_CHR_PROP_READ,
+ device_info_read_cb, NULL,
+ (void *) device_info.software_rev);
+
+ bt_uuid16_create(&uuid, GATT_CHARAC_MANUFACTURER_NAME_STRING);
+ gatt_db_add_characteristic(gatt_db, srvc_handle, &uuid, 0,
+ GATT_CHR_PROP_READ,
+ device_info_read_cb, NULL,
+ (void *) device_info.manufacturer_name);
+
+ gatt_db_service_set_active(gatt_db, srvc_handle, true);
+}
+
static int start_listen_socket(void)
{
GError *gerr = NULL;
@@ -3868,6 +3965,7 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
error("Could not start GATT listening");

register_gap_service();
+ register_device_info_service();

return true;
}
--
1.8.4


2014-04-30 09:13:46

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 15/38] shared/gatt: Add att_opcode to read/write callback

This is because there is many types of read/write requests and user
needs to know if and what response send back.
---
src/shared/gatt-db.h | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index d05f4c1..74817a0 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -31,11 +31,13 @@ uint16_t gatt_db_add_service(struct gatt_db *db, const bt_uuid_t *uuid,
bool gatt_db_remove_service(struct gatt_db *db, uint16_t handle);

typedef void (*gatt_db_read_t) (uint16_t handle, uint16_t offset,
- bdaddr_t *bdaddr, void *user_data);
+ uint8_t att_opcode, bdaddr_t *bdaddr,
+ void *user_data);

typedef void (*gatt_db_write_t) (uint16_t handle, uint16_t offset,
const uint8_t *value, size_t len,
- bdaddr_t *bdaddr, void *user_data);
+ uint8_t att_opcode, bdaddr_t *bdaddr,
+ void *user_data);

uint16_t gatt_db_add_characteristic(struct gatt_db *db, uint16_t handle,
const bt_uuid_t *uuid,
--
1.8.4


2014-04-30 09:13:47

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 16/38] android/bluetooth: Add function for getting device Android name

This will be used by GATT HAL
---
android/bluetooth.c | 5 +++++
android/bluetooth.h | 1 +
2 files changed, 6 insertions(+)

diff --git a/android/bluetooth.c b/android/bluetooth.c
index 03b8576..655fb1e 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -1198,6 +1198,11 @@ uint8_t bt_get_device_android_type(const bdaddr_t *addr)
return get_device_android_type(dev);
}

+const char *bt_get_adapter_name(void)
+{
+ return adapter.name;
+}
+
static bool rssi_above_threshold(int old, int new)
{
/* only 8 dBm or more */
diff --git a/android/bluetooth.h b/android/bluetooth.h
index 649c9ba..dddbf20 100644
--- a/android/bluetooth.h
+++ b/android/bluetooth.h
@@ -48,3 +48,4 @@ bool bt_le_set_advertising(bool advertising, bt_le_set_advertising_done cb,
void *user_data);

uint8_t bt_get_device_android_type(const bdaddr_t *addr);
+const char *bt_get_adapter_name(void);
--
1.8.4


2014-04-30 09:13:43

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 12/38] android/gatt: Add ATT msg handler

This patch adds skeleton for ATT msg handler and also attach it to the
attrib on connect_cb and connect_event
---
android/gatt.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 56 insertions(+), 1 deletion(-)

diff --git a/android/gatt.c b/android/gatt.c
index f035e3f..c2f43b5 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -134,6 +134,7 @@ struct gatt_device {
struct queue *services;

guint watch_id;
+ guint server_id;

int ref;
int conn_cnt;
@@ -494,6 +495,9 @@ static void connection_cleanup(struct gatt_device *device)
device->att_io = NULL;
}

+ if (device->server_id > 0)
+ g_attrib_unregister(device->attrib, device->server_id);
+
if (device->attrib) {
GAttrib *attrib = device->attrib;
device->attrib = NULL;
@@ -962,6 +966,8 @@ static void send_app_connect_notifications(void *data, void *user_data)
send_app_connect_notify(conn, con_data->status);
}

+static void att_handler(const uint8_t *ipdu, uint16_t len, gpointer user_data);
+
static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
{
struct gatt_device *dev = user_data;
@@ -997,6 +1003,12 @@ static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
dev->watch_id = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
disconnected_cb, dev);

+ dev->server_id = g_attrib_register(attrib, GATTRIB_ALL_REQS,
+ GATTRIB_ALL_HANDLES,
+ att_handler, dev, NULL);
+ if (dev->server_id == 0)
+ error("gatt: Could not attach to server");
+
device_set_state(dev, DEVICE_CONNECTED);

status = GATT_SUCCESS;
@@ -3583,6 +3595,45 @@ static const struct ipc_handler cmd_handlers[] = {
sizeof(struct hal_cmd_gatt_server_send_response) },
};

+static void att_handler(const uint8_t *ipdu, uint16_t len, gpointer user_data)
+{
+ struct gatt_device *dev = user_data;
+ uint8_t opdu[ATT_DEFAULT_LE_MTU];
+ uint8_t status;
+ uint16_t length = 0;
+
+ DBG("op 0x%02x", ipdu[0]);
+
+ switch (ipdu[0]) {
+ case ATT_OP_READ_BY_GROUP_REQ:
+ case ATT_OP_READ_BY_TYPE_REQ:
+ case ATT_OP_READ_REQ:
+ case ATT_OP_READ_BLOB_REQ:
+ case ATT_OP_MTU_REQ:
+ case ATT_OP_FIND_INFO_REQ:
+ case ATT_OP_WRITE_REQ:
+ case ATT_OP_WRITE_CMD:
+ case ATT_OP_FIND_BY_TYPE_REQ:
+ case ATT_OP_HANDLE_CNF:
+ case ATT_OP_HANDLE_IND:
+ case ATT_OP_HANDLE_NOTIFY:
+ case ATT_OP_READ_MULTI_REQ:
+ case ATT_OP_PREP_WRITE_REQ:
+ case ATT_OP_EXEC_WRITE_REQ:
+ default:
+ DBG("Unsupported request 0x%02x", ipdu[0]);
+ status = ATT_ECODE_REQ_NOT_SUPP;
+ goto done;
+ }
+
+done:
+ if (status)
+ length = enc_error_resp(ipdu[0], 0x0000, status, opdu,
+ ATT_DEFAULT_LE_MTU);
+
+ g_attrib_send(dev->attrib, 0, opdu, length, NULL, NULL, NULL);
+}
+
static void create_listen_connections(void *data, void *user_data)
{
struct gatt_device *dev = user_data;
@@ -3648,7 +3699,11 @@ static void connect_event(GIOChannel *io, GError *gerr, void *user_data)

queue_foreach(app_connections, send_app_connect_notifications, &data);

- /* TODO: Attach to attrib db */
+ dev->server_id = g_attrib_register(attrib, GATTRIB_ALL_REQS,
+ GATTRIB_ALL_HANDLES,
+ att_handler, dev, NULL);
+ if (dev->server_id == 0)
+ error("gatt: Could not attach to server");
}

static int start_listen_socket(void)
--
1.8.4


2014-04-30 09:13:41

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 10/38] android/gatt: Add listening socket for GATT

For now we do listen on BLE transport
---
android/gatt.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 97 insertions(+)

diff --git a/android/gatt.c b/android/gatt.c
index 115fb1a..9e950ec 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -156,6 +156,8 @@ static struct queue *app_connections = NULL;
static struct queue *listen_apps = NULL;
static struct gatt_db *gatt_db = NULL;

+static GIOChannel *listening_sk = NULL;
+
static void bt_le_discovery_stop_cb(void);

static void android2uuid(const uint8_t *uuid, bt_uuid_t *dst)
@@ -3574,6 +3576,98 @@ static const struct ipc_handler cmd_handlers[] = {
sizeof(struct hal_cmd_gatt_server_send_response) },
};

+static void create_listen_connections(void *data, void *user_data)
+{
+ struct gatt_device *dev = user_data;
+ int32_t id = PTR_TO_INT(data);
+ struct gatt_app *app;
+
+ app = find_app_by_id(id);
+ if (app)
+ create_connection(dev, app);
+}
+
+static void connect_event(GIOChannel *io, GError *gerr, void *user_data)
+{
+ struct gatt_device *dev;
+ GAttrib *attrib;
+ uint8_t dst_type;
+ bdaddr_t src, dst;
+ struct connect_data data;
+
+ DBG("");
+
+ if (gerr) {
+ error("gatt: %s", gerr->message);
+ g_error_free(gerr);
+ return;
+ }
+
+ bt_io_get(io, &gerr,
+ BT_IO_OPT_SOURCE_BDADDR, &src,
+ BT_IO_OPT_DEST_BDADDR, &dst,
+ BT_IO_OPT_DEST_TYPE, &dst_type,
+ BT_IO_OPT_INVALID);
+ if (gerr) {
+ error("gatt: bt_io_get: %s", gerr->message);
+ g_error_free(gerr);
+ return;
+ }
+
+ dev = create_device(&dst);
+ if (!dev) {
+ error("gatt: Could not create device");
+ return;
+ }
+
+ dev->bdaddr_type = dst_type;
+
+ attrib = g_attrib_new(io);
+ if (!attrib) {
+ error("gatt: unable to create new GAttrib instance");
+ destroy_device(dev);
+ return;
+ }
+
+ dev->attrib = attrib;
+ dev->watch_id = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ disconnected_cb, dev);
+
+ queue_foreach(listen_apps, create_listen_connections, dev);
+
+ data.dev = dev;
+ data.status = GATT_SUCCESS;
+ device_set_state(dev, DEVICE_CONNECTED);
+
+ queue_foreach(app_connections, send_app_connect_notifications, &data);
+
+ /* TODO: Attach to attrib db */
+}
+
+static int start_listen_socket(void)
+{
+ GError *gerr = NULL;
+
+ DBG("");
+
+ /*For now only listen on BLE */
+ listening_sk = bt_io_listen(connect_event, NULL,
+ &listening_sk, NULL, &gerr,
+ BT_IO_OPT_SOURCE_TYPE, BDADDR_LE_PUBLIC,
+ BT_IO_OPT_CID, ATT_CID,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+ BT_IO_OPT_INVALID);
+
+ if (!listening_sk) {
+ int ret = gerr->code;
+ error("%s", gerr->message);
+ g_error_free(gerr);
+ return ret;
+ }
+
+ return 0;
+}
+
bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
{
DBG("");
@@ -3613,6 +3707,9 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
ipc_register(hal_ipc, HAL_SERVICE_ID_GATT, cmd_handlers,
G_N_ELEMENTS(cmd_handlers));

+ if (start_listen_socket() < 0)
+ error("Could not start GATT listening");
+
return true;
}

--
1.8.4


2014-04-30 09:13:40

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 09/38] android/gatt: Add descriptor implementation

From: Marcin Kraglak <[email protected]>

It will add characteristic descriptor attribute to local database.
---
android/gatt.c | 31 +++++++++++++++++++++----------
1 file changed, 21 insertions(+), 10 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index e888268..115fb1a 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -3302,30 +3302,41 @@ failed:
static void handle_server_add_descriptor(const void *buf, uint16_t len)
{
const struct hal_cmd_gatt_server_add_descriptor *cmd = buf;
- char uuidstr[MAX_LEN_UUID_STR];
+ struct hal_ev_gatt_server_descriptor_added ev;
struct gatt_app *server;
- bt_uuid_t descr_uuid;
+ bt_uuid_t uuid;
uint8_t status;

DBG("");

+ memset(&ev, 0, sizeof(ev));
+
server = find_app_by_id(cmd->server_if);
if (!server) {
- error("gatt: server_if=%d not found", cmd->server_if);
status = HAL_STATUS_FAILED;
goto failed;
}

- android2uuid(cmd->uuid, &descr_uuid);
- bt_uuid_to_string(&descr_uuid, uuidstr, MAX_LEN_UUID_STR);
-
- /* TODO: Add descriptor to attribute database */
- DBG("Add descriptor: server: %d, srvc_hnd: %d, uuid: %s, perm: %d",
- cmd->server_if, cmd->service_handle, uuidstr, cmd->permissions);
+ android2uuid(cmd->uuid, &uuid);

- status = HAL_STATUS_SUCCESS;
+ ev.descr_handle = gatt_db_add_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, status);
}
--
1.8.4


2014-04-30 09:13:42

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 11/38] android/gatt: Assume that each server wants waits for connection

---
android/gatt.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/android/gatt.c b/android/gatt.c
index 9e950ec..f035e3f 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -575,6 +575,13 @@ static int register_app(const uint8_t *uuid, gatt_app_type_t app_type)
return 0;
}

+ if ((app->type == APP_SERVER) &&
+ !queue_push_tail(listen_apps, INT_TO_PTR(app->id))) {
+ error("gatt: Cannot push server on the list");
+ destroy_gatt_app(app);
+ return 0;
+ }
+
return app->id;
}

--
1.8.4


2014-04-30 09:13:38

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 07/38] android/gatt: Add handling of start service command

From: Marcin Kraglak <[email protected]>

It will start service added to local database.
---
android/gatt.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index 7522c65..2913007 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -3333,26 +3333,38 @@ 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_app *server;
uint8_t status;

DBG("");

+ memset(&ev, 0, sizeof(ev));
+
server = find_app_by_id(cmd->server_if);
if (!server) {
- error("gatt: server_if=%d not found", cmd->server_if);
status = HAL_STATUS_FAILED;
goto failed;
}

/* TODO: support BR/EDR (cmd->transport) */
- /* TODO: activate service in attribute database */
- DBG("Start service: server: %d, srvc_hnd: %d, transport_layer: %d",
- cmd->server_if, cmd->service_handle, cmd->transport);
+
+ if (!gatt_db_service_set_active(gatt_db, cmd->service_handle, true)) {
+ /* 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, status);
}
--
1.8.4


2014-04-30 09:13:37

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 06/38] android/gatt: Add characteristic implementation

From: Marcin Kraglak <[email protected]>

It will add characteristic declaration and value attributes to
local database.
---
android/gatt.c | 34 +++++++++++++++++++++++-----------
1 file changed, 23 insertions(+), 11 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index f8398fc..7522c65 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -3258,31 +3258,43 @@ failed:
static void handle_server_add_characteristic(const void *buf, uint16_t len)
{
const struct hal_cmd_gatt_server_add_characteristic *cmd = buf;
- char uuidstr[MAX_LEN_UUID_STR];
+ struct hal_ev_gatt_server_characteristic_added ev;
struct gatt_app *server;
- bt_uuid_t char_uuid;
+ bt_uuid_t uuid;
uint8_t status;

DBG("");

+ memset(&ev, 0, sizeof(ev));
+
server = find_app_by_id(cmd->server_if);
if (!server) {
- error("gatt: server_if=%d not found", cmd->server_if);
status = HAL_STATUS_FAILED;
goto failed;
}

- android2uuid(cmd->uuid, &char_uuid);
- bt_uuid_to_string(&char_uuid, uuidstr, MAX_LEN_UUID_STR);
+ android2uuid(cmd->uuid, &uuid);

- /* TODO: Add characteristic to database */
- DBG("Add char: server: %d, uuid: %s, srvc_hnd: %d, prop: %d, perm: %d",
- cmd->server_if, uuidstr, cmd->service_handle, cmd->properties,
- cmd->permissions);
-
- status = HAL_STATUS_SUCCESS;
+ ev.char_handle = gatt_db_add_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, status);
}
--
1.8.4


2014-04-30 09:13:33

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 02/38] android/gatt: Remove redundant find function parameter

From: Jakub Tyszkowski <[email protected]>

As client and server apps id is guaranteed to be unique, there is no
need for this search function parameter.
---
android/gatt.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index f9eff30..0bb5a70 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -1248,8 +1248,7 @@ static void handle_client_unregister(const void *buf, uint16_t len)
HAL_OP_GATT_CLIENT_UNREGISTER, status);
}

-static struct app_connection *find_conn(const bdaddr_t *addr, int32_t app_id,
- int32_t app_type)
+static struct app_connection *find_conn(const bdaddr_t *addr, int32_t app_id)
{
struct app_connection conn_match;
struct gatt_device *dev = NULL;
@@ -2891,7 +2890,7 @@ static void handle_client_register_for_notification(const void *buf,

android2bdaddr(&cmd->bdaddr, &addr);

- conn = find_conn(&addr, cmd->client_if, APP_CLIENT);
+ conn = find_conn(&addr, cmd->client_if);
if (!conn) {
status = HAL_STATUS_FAILED;
goto failed;
@@ -2997,7 +2996,7 @@ static void handle_client_deregister_for_notification(const void *buf,

android2bdaddr(&cmd->bdaddr, &addr);

- conn = find_conn(&addr, cmd->client_if, APP_CLIENT);
+ conn = find_conn(&addr, cmd->client_if);
if (!conn) {
status = HAL_STATUS_FAILED;
goto failed;
--
1.8.4


2014-04-30 09:13:36

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 05/38] android/gatt: Add included service implementation

From: Marcin Kraglak <[email protected]>

It will add included service attribute to database.
---
android/gatt.c | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index e4ef1ea..f8398fc 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -3219,25 +3219,38 @@ 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_app *server;
uint8_t status;

DBG("");

+ memset(&ev, 0, sizeof(ev));
+
server = find_app_by_id(cmd->server_if);
if (!server) {
- error("gatt: server_if=%d not found", cmd->server_if);
status = HAL_STATUS_FAILED;
goto failed;
}

- /* TODO: Add included service to attribute database */
- DBG("Add included service: server: %d, srvc_hnd: %d, incl_hnd: %d",
- cmd->server_if, cmd->service_handle, cmd->included_handle);
+ ev.incl_srvc_handle = gatt_db_add_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, status);
}
--
1.8.4


2014-04-30 09:13:35

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 04/38] android/gatt: Add implementation of delete service

From: Marcin Kraglak <[email protected]>

It will delete sarvice from local database
---
android/gatt.c | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index 6e578e1..e4ef1ea 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -3361,27 +3361,37 @@ failed:
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_app *server;
uint8_t status;

DBG("");

+ memset(&ev, 0, sizeof(ev));
+
server = find_app_by_id(cmd->server_if);
if (!server) {
- error("gatt: server_if=%d not found", cmd->server_if);
status = HAL_STATUS_FAILED;
goto failed;
}

- /* TODO: delete service from attribute database */
- DBG("Delete service: server: %d, srvc_hnd: %d", cmd->server_if,
- cmd->service_handle);
+ 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, status);
+ HAL_OP_GATT_SERVER_DELETE_SERVICE, status);
}

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


2014-04-30 09:13:34

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 03/38] android/gatt: Add service functionality

From: Marcin Kraglak <[email protected]>

It will Add service to local database.
---
android/gatt.c | 40 ++++++++++++++++++++++++++++++----------
1 file changed, 30 insertions(+), 10 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index 0bb5a70..6e578e1 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"
@@ -153,6 +154,7 @@ static struct queue *gatt_devices = NULL;
static struct queue *app_connections = NULL;

static struct queue *listen_apps = NULL;
+static struct gatt_db *gatt_db = NULL;

static void bt_le_discovery_stop_cb(void);

@@ -3175,32 +3177,43 @@ static void handle_server_disconnect(const void *buf, uint16_t len)
static void handle_server_add_service(const void *buf, uint16_t len)
{
const struct hal_cmd_gatt_server_add_service *cmd = buf;
- char uuidstr[MAX_LEN_UUID_STR];
+ struct hal_ev_gatt_server_service_added ev;
struct gatt_app *server;
- struct element_id srvc_id;
uint8_t status;
+ bt_uuid_t uuid;

DBG("");

+ memset(&ev, 0, sizeof(ev));
+
server = find_app_by_id(cmd->server_if);
if (!server) {
- error("gatt: server_if=%d not found", cmd->server_if);
status = HAL_STATUS_FAILED;
goto failed;
}

- hal_srvc_id_to_element_id(&cmd->srvc_id, &srvc_id);
- bt_uuid_to_string(&srvc_id.uuid, uuidstr, MAX_LEN_UUID_STR);
+ android2uuid(cmd->srvc_id.uuid, &uuid);

- /* TODO: execute attribute database transaction */
- DBG("Add primary service: server: %d, srvc_uuid: %s, num_handles: %d",
- cmd->server_if, uuidstr, cmd->num_handles);
+ ev.srvc_handle = gatt_db_add_service(gatt_db, &uuid,
+ cmd->srvc_id.is_primary,
+ 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, status);
+ HAL_OP_GATT_SERVER_ADD_SERVICE, status);
}

static void handle_server_add_included_service(const void *buf, uint16_t len)
@@ -3503,9 +3516,10 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
gatt_apps = queue_new();
app_connections = queue_new();
listen_apps = queue_new();
+ gatt_db = gatt_db_new();

if (!gatt_devices || !gatt_apps || !listen_apps ||
- !app_connections) {
+ !app_connections || !gatt_db) {
error("gatt: Failed to allocate memory for queues");

queue_destroy(gatt_apps, NULL);
@@ -3520,6 +3534,9 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
queue_destroy(listen_apps, NULL);
listen_apps = NULL;

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

@@ -3551,4 +3568,7 @@ void bt_gatt_unregister(void)

queue_destroy(listen_apps, NULL);
listen_apps = NULL;
+
+ gatt_db_destroy(gatt_db);
+ gatt_db = NULL;
}
--
1.8.4


2014-04-30 09:13:32

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v4 01/38] android/gatt: Rename listen_clients to listen_apps

This is because on this list there will be also servers id
---
android/gatt.c | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index 4775ecc..f9eff30 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -152,7 +152,7 @@ static struct queue *gatt_apps = NULL;
static struct queue *gatt_devices = NULL;
static struct queue *app_connections = NULL;

-static struct queue *listen_clients = NULL;
+static struct queue *listen_apps = NULL;

static void bt_le_discovery_stop_cb(void);

@@ -1380,7 +1380,7 @@ static void set_advertising_cb(uint8_t status, void *user_data)
* 2. Stop succeed
*/
if ((l->start && status) || (!l->start && !status))
- queue_remove(listen_clients, INT_TO_PTR(l->client_id));
+ queue_remove(listen_apps, INT_TO_PTR(l->client_id));

free(l);
}
@@ -1401,7 +1401,7 @@ static void handle_client_listen(const void *buf, uint16_t len)
goto reply;
}

- listening_client = queue_find(listen_clients, match_by_value,
+ listening_client = queue_find(listen_apps, match_by_value,
INT_TO_PTR(cmd->client_if));
/* Start listening */
if (cmd->start) {
@@ -1410,7 +1410,7 @@ static void handle_client_listen(const void *buf, uint16_t len)
goto reply;
}

- if (!queue_push_tail(listen_clients,
+ if (!queue_push_tail(listen_apps,
INT_TO_PTR(cmd->client_if))) {
error("gatt: Could not put client on listen queue");
status = HAL_STATUS_FAILED;
@@ -1418,7 +1418,7 @@ static void handle_client_listen(const void *buf, uint16_t len)
}

/* If listen is already on just return success*/
- if (queue_length(listen_clients) > 1) {
+ if (queue_length(listen_apps) > 1) {
status = HAL_STATUS_SUCCESS;
goto reply;
}
@@ -1435,8 +1435,8 @@ static void handle_client_listen(const void *buf, uint16_t len)
* In case there is more listening clients don't stop
* advertising
*/
- if (queue_length(listen_clients) > 1) {
- queue_remove(listen_clients,
+ if (queue_length(listen_apps) > 1) {
+ queue_remove(listen_apps,
INT_TO_PTR(cmd->client_if));
status = HAL_STATUS_SUCCESS;
goto reply;
@@ -3503,9 +3503,9 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
gatt_devices = queue_new();
gatt_apps = queue_new();
app_connections = queue_new();
- listen_clients = queue_new();
+ listen_apps = queue_new();

- if (!gatt_devices || !gatt_apps || !listen_clients ||
+ if (!gatt_devices || !gatt_apps || !listen_apps ||
!app_connections) {
error("gatt: Failed to allocate memory for queues");

@@ -3518,8 +3518,8 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
queue_destroy(app_connections, NULL);
app_connections = NULL;

- queue_destroy(listen_clients, NULL);
- listen_clients = NULL;
+ queue_destroy(listen_apps, NULL);
+ listen_apps = NULL;

return false;
}
@@ -3550,6 +3550,6 @@ void bt_gatt_unregister(void)
queue_destroy(gatt_devices, destroy_device);
gatt_devices = NULL;

- queue_destroy(listen_clients, NULL);
- listen_clients = NULL;
+ queue_destroy(listen_apps, NULL);
+ listen_apps = NULL;
}
--
1.8.4