From: Luiz Augusto von Dentz <[email protected]>
---
{profiles/input => android}/hog.c | 0
1 file changed, 0 insertions(+), 0 deletions(-)
copy {profiles/input => android}/hog.c (100%)
diff --git a/profiles/input/hog.c b/android/hog.c
similarity index 100%
copy from profiles/input/hog.c
copy to android/hog.c
--
1.9.3
Hi Lukasz,
On Tue, Jun 10, 2014 at 11:08 PM, Lukasz Rymanowski
<[email protected]> wrote:
> Hi Luiz,
>
> On Tue, Jun 10, 2014 at 5:53 PM, Luiz Augusto von Dentz
> <[email protected]> wrote:
>> From: Luiz Augusto von Dentz <[email protected]>
>>
>> This in future gonna be used by HoG to receive connection notifications.
>> ---
>> android/gatt.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++-----------
>> android/gatt.h | 15 ++++++
>> 2 files changed, 130 insertions(+), 28 deletions(-)
>>
>> diff --git a/android/gatt.c b/android/gatt.c
>> index 3fd88fa..c25aed4 100644
>> --- a/android/gatt.c
>> +++ b/android/gatt.c
>> @@ -87,11 +87,6 @@ static const char const *device_state_str[] = {
>> "CONNECTED",
>> };
>>
>> -typedef enum {
>> - APP_CLIENT,
>> - APP_SERVER,
>> -} gatt_app_type_t;
>> -
> Change of those names seems to be unrelated. Maybe topic for separate patch.
Well I had to change the name since this is now a public API we
normally use proper namespace prefix, so I have say this is relevant
to the changes proposed.
>> struct pending_trans_data {
>> unsigned int id;
>> uint8_t opcode;
>> @@ -101,10 +96,12 @@ struct gatt_app {
>> int32_t id;
>> uint8_t uuid[16];
>>
>> - gatt_app_type_t type;
>> + gatt_type_t type;
>>
>> /* Valid for client applications */
>> struct queue *notifications;
>> +
>> + gatt_conn_cb_t func;
>> };
>>
>> struct element_id {
>> @@ -617,7 +614,7 @@ static void destroy_gatt_app(void *data)
>> * too. So remove all elements and then destroy queue.
>> */
>>
>> - if (app->type == APP_CLIENT)
>> + if (app->type == GATT_CLIENT)
>> while (queue_peek_head(app->notifications)) {
>> struct notification_data *notification;
>>
>> @@ -630,14 +627,14 @@ static void destroy_gatt_app(void *data)
>> free(app);
>> }
>>
>> -static int register_app(const uint8_t *uuid, gatt_app_type_t app_type)
>> +static struct gatt_app *register_app(const uint8_t *uuid, gatt_type_t type)
>
> Maybe it would be better to extend parameters here with gatt_conn_cb_t
> function? At least less code changes it would introduce. And it would
> make more sense to attach callback already in register function.
I have actually started with that but most of the callback would be
set to NULL so Ive keep the callback only for the public API, but now
thinking about it again it might be useful to actually replace the
notify path by having a proper notification callback registered
upfront but this will introduce yet more changes.
>> {
>> static int32_t application_id = 1;
>> struct gatt_app *app;
>>
>> if (queue_find(gatt_apps, match_app_by_uuid, uuid)) {
>> error("gatt: app uuid is already on list");
>> - return 0;
>> + return NULL;
>> }
>>
>> app = new0(struct gatt_app, 1);
>> @@ -646,14 +643,14 @@ static int register_app(const uint8_t *uuid, gatt_app_type_t app_type)
>> return 0;
>> }
>>
>> - app->type = app_type;
>> + app->type = type;
>>
>> - if (app->type == APP_CLIENT) {
>> + if (app->type == GATT_CLIENT) {
>> app->notifications = queue_new();
>> if (!app->notifications) {
>> error("gatt: couldn't allocate notifications queue");
>> destroy_gatt_app(app);
>> - return 0;
>> + return NULL;
>> }
>> }
>>
>> @@ -664,33 +661,35 @@ static int register_app(const uint8_t *uuid, gatt_app_type_t app_type)
>> if (!queue_push_head(gatt_apps, app)) {
>> error("gatt: Cannot push app on the list");
>> destroy_gatt_app(app);
>> - return 0;
>> + return NULL;
>> }
>>
>> - if ((app->type == APP_SERVER) &&
>> + if ((app->type == GATT_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 NULL;
>> }
>>
>> - return app->id;
>> + return app;
>> }
>>
>> static void handle_client_register(const void *buf, uint16_t len)
>> {
>> const struct hal_cmd_gatt_client_register *cmd = buf;
>> struct hal_ev_gatt_client_register_client ev;
>> + struct gatt_app *app;
>>
>> DBG("");
>>
>> memset(&ev, 0, sizeof(ev));
>>
>> - ev.client_if = register_app(cmd->uuid, APP_CLIENT);
>> + app = register_app(cmd->uuid, GATT_CLIENT);
>>
>> - if (ev.client_if)
>> + if (app) {
>> + ev.client_if = app->id;
>> ev.status = GATT_SUCCESS;
>> - else
>> + } else
>> ev.status = GATT_FAILURE;
>>
>> /* We should send notification with given in cmd UUID */
>> @@ -708,6 +707,12 @@ static void send_client_disconnection_notify(struct app_connection *connection,
>> {
>> struct hal_ev_gatt_client_disconnect ev;
>>
>> + if (connection->app->func) {
>> + connection->app->func(&connection->device->bdaddr, -ENOTCONN,
>> + connection->device->attrib);
>> + return;
>> + }
>> +
>> ev.client_if = connection->app->id;
>> ev.conn_id = connection->id;
>> ev.status = status;
>> @@ -716,6 +721,7 @@ static void send_client_disconnection_notify(struct app_connection *connection,
>>
>> ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
>> HAL_EV_GATT_CLIENT_DISCONNECT, sizeof(ev), &ev);
>> +
> not related to this change.
I Will fix this.
>>
> }
>>
>> static void send_client_connection_notify(struct app_connection *connection,
>> @@ -723,6 +729,13 @@ static void send_client_connection_notify(struct app_connection *connection,
>> {
>> struct hal_ev_gatt_client_connect ev;
>>
>> + if (connection->app->func) {
>> + connection->app->func(&connection->device->bdaddr,
>> + status == GATT_SUCCESS ? 0 : -ENOTCONN,
>> + connection->device->attrib);
>> + return;
>> + }
>> +
>> ev.client_if = connection->app->id;
>> ev.conn_id = connection->id;
>> ev.status = status;
>> @@ -738,6 +751,13 @@ static void send_server_connection_notify(struct app_connection *connection,
>> {
>> struct hal_ev_gatt_server_connection ev;
>>
>> + if (connection->app->func) {
>> + connection->app->func(&connection->device->bdaddr,
>> + connected ? 0 : -ENOTCONN,
>> + connection->device->attrib);
>> + return;
>> + }
>> +
>> ev.server_if = connection->app->id;
>> ev.conn_id = connection->id;
>> ev.connected = connected;
>> @@ -751,7 +771,7 @@ static void send_server_connection_notify(struct app_connection *connection,
>> static void send_app_disconnect_notify(struct app_connection *connection,
>> int32_t status)
>> {
>> - if (connection->app->type == APP_CLIENT)
>> + if (connection->app->type == GATT_CLIENT)
>> send_client_disconnection_notify(connection, status);
>> else
>> send_server_connection_notify(connection, !!status);
>> @@ -760,9 +780,9 @@ static void send_app_disconnect_notify(struct app_connection *connection,
>> static void send_app_connect_notify(struct app_connection *connection,
>> int32_t status)
>> {
>> - if (connection->app->type == APP_CLIENT)
>> + if (connection->app->type == GATT_CLIENT)
>> send_client_connection_notify(connection, status);
>> - else
>> + else if (connection->app->type == GATT_SERVER)
>> send_server_connection_notify(connection, !status);
>> }
>>
>> @@ -3568,9 +3588,11 @@ static void handle_client_test_command(const void *buf, uint16_t len)
>> switch (cmd->command) {
>> case GATT_CLIENT_TEST_CMD_ENABLE:
>> if (cmd->u1) {
>> - if (!test_client_if)
>> - test_client_if = register_app(TEST_UUID,
>> - APP_CLIENT);
>> + if (!test_client_if) {
>> + app = register_app(TEST_UUID, GATT_CLIENT);
>> + if (app)
>> + test_client_if = app->id;
>> + }
>>
>> if (test_client_if)
>> status = HAL_STATUS_SUCCESS;
>> @@ -3615,16 +3637,18 @@ static void handle_server_register(const void *buf, uint16_t len)
>> {
>> const struct hal_cmd_gatt_server_register *cmd = buf;
>> struct hal_ev_gatt_server_register ev;
>> + struct gatt_app *app;
>>
>> DBG("");
>>
>> memset(&ev, 0, sizeof(ev));
>>
>> - ev.server_if = register_app(cmd->uuid, APP_SERVER);
>> + app = register_app(cmd->uuid, GATT_SERVER);
>>
>> - if (ev.server_if)
>> + if (app) {
>> + ev.server_if = app->id;
>> ev.status = GATT_SUCCESS;
>> - else
>> + } else
>> ev.status = GATT_FAILURE;
>>
>> memcpy(ev.uuid, cmd->uuid, sizeof(ev.uuid));
>> @@ -5978,3 +6002,66 @@ void bt_gatt_unregister(void)
>> bt_crypto_unref(crypto);
>> crypto = NULL;
>> }
>> +
>> +
>> +unsigned int bt_gatt_register_app(const char *uuid, gatt_type_t type,
>> + gatt_conn_cb_t func)
>> +{
>> + struct gatt_app *app;
>> + bt_uuid_t uuid128;
>> +
>> + bt_string_to_uuid(&uuid128, uuid);
>> + app = register_app((void *) &uuid128.value.u128, type);
>> + if (!app)
>> + return 0;
>> +
>> + app->func = func;
>> +
>> + return app->id;
>> +}
>> +
>> +bool bt_gatt_unregister_app(unsigned int id)
>> +{
>> + uint8_t status;
>> +
>> + status = unregister_client(id);
>> +
>> + return status != HAL_STATUS_FAILED;
>> +}
>> +
>> +bool bt_gatt_connect_app(unsigned int id, const bdaddr_t *addr)
>> +{
>> + uint8_t status;
>> +
>> + status = handle_connect(id, addr);
>> +
>> + return status != HAL_STATUS_FAILED;
>> +}
>> +
>> +bool bt_gatt_disconnect_app(unsigned int id, const bdaddr_t *addr)
>> +{
>> + struct app_connection match;
>> + struct app_connection *conn;
>> + struct gatt_device *device;
>> + struct gatt_app *app;
>> +
>> + app = find_app_by_id(id);
>> + if (!app)
>> + return false;
>> +
>> + device = find_device_by_addr(addr);
>> + if (!device)
>> + return false;
>> +
>> + match.device = device;
>> + match.app = app;
>> +
>> + conn = queue_find(app_connections, match_connection_by_device_and_app,
>> + &match);
>> + if (!conn)
>> + return false;
>> +
>> + trigger_disconnection(conn);
>> +
>> + return true;
>> +}
>> diff --git a/android/gatt.h b/android/gatt.h
>> index d4392d9..5ba9161 100644
>> --- a/android/gatt.h
>> +++ b/android/gatt.h
>> @@ -23,3 +23,18 @@
>>
>> bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr);
>> void bt_gatt_unregister(void);
>> +
>> +
>> +typedef enum {
>> + GATT_CLIENT,
>> + GATT_SERVER,
>> +} gatt_type_t;
>> +
>> +typedef void (*gatt_conn_cb_t)(const bdaddr_t *addr, int err, void *attrib);
>> +
>> +unsigned int bt_gatt_register_app(const char *uuid, gatt_type_t type,
>> + gatt_conn_cb_t func);
>> +bool bt_gatt_unregister_app(unsigned int id);
>> +
>> +bool bt_gatt_connect_app(unsigned int id, const bdaddr_t *addr);
>> +bool bt_gatt_disconnect_app(unsigned int id, const bdaddr_t *addr);
>> --
>> 1.9.3
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
>> the body of a message to [email protected]
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
> BR
> Lukasz
--
Luiz Augusto von Dentz
Hi Luiz,
On Tue, Jun 10, 2014 at 5:53 PM, Luiz Augusto von Dentz
<[email protected]> wrote:
> From: Luiz Augusto von Dentz <[email protected]>
>
> This in future gonna be used by HoG to receive connection notifications.
> ---
> android/gatt.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++-----------
> android/gatt.h | 15 ++++++
> 2 files changed, 130 insertions(+), 28 deletions(-)
>
> diff --git a/android/gatt.c b/android/gatt.c
> index 3fd88fa..c25aed4 100644
> --- a/android/gatt.c
> +++ b/android/gatt.c
> @@ -87,11 +87,6 @@ static const char const *device_state_str[] = {
> "CONNECTED",
> };
>
> -typedef enum {
> - APP_CLIENT,
> - APP_SERVER,
> -} gatt_app_type_t;
> -
Change of those names seems to be unrelated. Maybe topic for separate patch.
> struct pending_trans_data {
> unsigned int id;
> uint8_t opcode;
> @@ -101,10 +96,12 @@ struct gatt_app {
> int32_t id;
> uint8_t uuid[16];
>
> - gatt_app_type_t type;
> + gatt_type_t type;
>
> /* Valid for client applications */
> struct queue *notifications;
> +
> + gatt_conn_cb_t func;
> };
>
> struct element_id {
> @@ -617,7 +614,7 @@ static void destroy_gatt_app(void *data)
> * too. So remove all elements and then destroy queue.
> */
>
> - if (app->type == APP_CLIENT)
> + if (app->type == GATT_CLIENT)
> while (queue_peek_head(app->notifications)) {
> struct notification_data *notification;
>
> @@ -630,14 +627,14 @@ static void destroy_gatt_app(void *data)
> free(app);
> }
>
> -static int register_app(const uint8_t *uuid, gatt_app_type_t app_type)
> +static struct gatt_app *register_app(const uint8_t *uuid, gatt_type_t type)
Maybe it would be better to extend parameters here with gatt_conn_cb_t
function? At least less code changes it would introduce. And it would
make more sense to attach callback already in register function.
> {
> static int32_t application_id = 1;
> struct gatt_app *app;
>
> if (queue_find(gatt_apps, match_app_by_uuid, uuid)) {
> error("gatt: app uuid is already on list");
> - return 0;
> + return NULL;
> }
>
> app = new0(struct gatt_app, 1);
> @@ -646,14 +643,14 @@ static int register_app(const uint8_t *uuid, gatt_app_type_t app_type)
> return 0;
> }
>
> - app->type = app_type;
> + app->type = type;
>
> - if (app->type == APP_CLIENT) {
> + if (app->type == GATT_CLIENT) {
> app->notifications = queue_new();
> if (!app->notifications) {
> error("gatt: couldn't allocate notifications queue");
> destroy_gatt_app(app);
> - return 0;
> + return NULL;
> }
> }
>
> @@ -664,33 +661,35 @@ static int register_app(const uint8_t *uuid, gatt_app_type_t app_type)
> if (!queue_push_head(gatt_apps, app)) {
> error("gatt: Cannot push app on the list");
> destroy_gatt_app(app);
> - return 0;
> + return NULL;
> }
>
> - if ((app->type == APP_SERVER) &&
> + if ((app->type == GATT_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 NULL;
> }
>
> - return app->id;
> + return app;
> }
>
> static void handle_client_register(const void *buf, uint16_t len)
> {
> const struct hal_cmd_gatt_client_register *cmd = buf;
> struct hal_ev_gatt_client_register_client ev;
> + struct gatt_app *app;
>
> DBG("");
>
> memset(&ev, 0, sizeof(ev));
>
> - ev.client_if = register_app(cmd->uuid, APP_CLIENT);
> + app = register_app(cmd->uuid, GATT_CLIENT);
>
> - if (ev.client_if)
> + if (app) {
> + ev.client_if = app->id;
> ev.status = GATT_SUCCESS;
> - else
> + } else
> ev.status = GATT_FAILURE;
>
> /* We should send notification with given in cmd UUID */
> @@ -708,6 +707,12 @@ static void send_client_disconnection_notify(struct app_connection *connection,
> {
> struct hal_ev_gatt_client_disconnect ev;
>
> + if (connection->app->func) {
> + connection->app->func(&connection->device->bdaddr, -ENOTCONN,
> + connection->device->attrib);
> + return;
> + }
> +
> ev.client_if = connection->app->id;
> ev.conn_id = connection->id;
> ev.status = status;
> @@ -716,6 +721,7 @@ static void send_client_disconnection_notify(struct app_connection *connection,
>
> ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
> HAL_EV_GATT_CLIENT_DISCONNECT, sizeof(ev), &ev);
> +
not related to this change.
>
}
>
> static void send_client_connection_notify(struct app_connection *connection,
> @@ -723,6 +729,13 @@ static void send_client_connection_notify(struct app_connection *connection,
> {
> struct hal_ev_gatt_client_connect ev;
>
> + if (connection->app->func) {
> + connection->app->func(&connection->device->bdaddr,
> + status == GATT_SUCCESS ? 0 : -ENOTCONN,
> + connection->device->attrib);
> + return;
> + }
> +
> ev.client_if = connection->app->id;
> ev.conn_id = connection->id;
> ev.status = status;
> @@ -738,6 +751,13 @@ static void send_server_connection_notify(struct app_connection *connection,
> {
> struct hal_ev_gatt_server_connection ev;
>
> + if (connection->app->func) {
> + connection->app->func(&connection->device->bdaddr,
> + connected ? 0 : -ENOTCONN,
> + connection->device->attrib);
> + return;
> + }
> +
> ev.server_if = connection->app->id;
> ev.conn_id = connection->id;
> ev.connected = connected;
> @@ -751,7 +771,7 @@ static void send_server_connection_notify(struct app_connection *connection,
> static void send_app_disconnect_notify(struct app_connection *connection,
> int32_t status)
> {
> - if (connection->app->type == APP_CLIENT)
> + if (connection->app->type == GATT_CLIENT)
> send_client_disconnection_notify(connection, status);
> else
> send_server_connection_notify(connection, !!status);
> @@ -760,9 +780,9 @@ static void send_app_disconnect_notify(struct app_connection *connection,
> static void send_app_connect_notify(struct app_connection *connection,
> int32_t status)
> {
> - if (connection->app->type == APP_CLIENT)
> + if (connection->app->type == GATT_CLIENT)
> send_client_connection_notify(connection, status);
> - else
> + else if (connection->app->type == GATT_SERVER)
> send_server_connection_notify(connection, !status);
> }
>
> @@ -3568,9 +3588,11 @@ static void handle_client_test_command(const void *buf, uint16_t len)
> switch (cmd->command) {
> case GATT_CLIENT_TEST_CMD_ENABLE:
> if (cmd->u1) {
> - if (!test_client_if)
> - test_client_if = register_app(TEST_UUID,
> - APP_CLIENT);
> + if (!test_client_if) {
> + app = register_app(TEST_UUID, GATT_CLIENT);
> + if (app)
> + test_client_if = app->id;
> + }
>
> if (test_client_if)
> status = HAL_STATUS_SUCCESS;
> @@ -3615,16 +3637,18 @@ static void handle_server_register(const void *buf, uint16_t len)
> {
> const struct hal_cmd_gatt_server_register *cmd = buf;
> struct hal_ev_gatt_server_register ev;
> + struct gatt_app *app;
>
> DBG("");
>
> memset(&ev, 0, sizeof(ev));
>
> - ev.server_if = register_app(cmd->uuid, APP_SERVER);
> + app = register_app(cmd->uuid, GATT_SERVER);
>
> - if (ev.server_if)
> + if (app) {
> + ev.server_if = app->id;
> ev.status = GATT_SUCCESS;
> - else
> + } else
> ev.status = GATT_FAILURE;
>
> memcpy(ev.uuid, cmd->uuid, sizeof(ev.uuid));
> @@ -5978,3 +6002,66 @@ void bt_gatt_unregister(void)
> bt_crypto_unref(crypto);
> crypto = NULL;
> }
> +
> +
> +unsigned int bt_gatt_register_app(const char *uuid, gatt_type_t type,
> + gatt_conn_cb_t func)
> +{
> + struct gatt_app *app;
> + bt_uuid_t uuid128;
> +
> + bt_string_to_uuid(&uuid128, uuid);
> + app = register_app((void *) &uuid128.value.u128, type);
> + if (!app)
> + return 0;
> +
> + app->func = func;
> +
> + return app->id;
> +}
> +
> +bool bt_gatt_unregister_app(unsigned int id)
> +{
> + uint8_t status;
> +
> + status = unregister_client(id);
> +
> + return status != HAL_STATUS_FAILED;
> +}
> +
> +bool bt_gatt_connect_app(unsigned int id, const bdaddr_t *addr)
> +{
> + uint8_t status;
> +
> + status = handle_connect(id, addr);
> +
> + return status != HAL_STATUS_FAILED;
> +}
> +
> +bool bt_gatt_disconnect_app(unsigned int id, const bdaddr_t *addr)
> +{
> + struct app_connection match;
> + struct app_connection *conn;
> + struct gatt_device *device;
> + struct gatt_app *app;
> +
> + app = find_app_by_id(id);
> + if (!app)
> + return false;
> +
> + device = find_device_by_addr(addr);
> + if (!device)
> + return false;
> +
> + match.device = device;
> + match.app = app;
> +
> + conn = queue_find(app_connections, match_connection_by_device_and_app,
> + &match);
> + if (!conn)
> + return false;
> +
> + trigger_disconnection(conn);
> +
> + return true;
> +}
> diff --git a/android/gatt.h b/android/gatt.h
> index d4392d9..5ba9161 100644
> --- a/android/gatt.h
> +++ b/android/gatt.h
> @@ -23,3 +23,18 @@
>
> bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr);
> void bt_gatt_unregister(void);
> +
> +
> +typedef enum {
> + GATT_CLIENT,
> + GATT_SERVER,
> +} gatt_type_t;
> +
> +typedef void (*gatt_conn_cb_t)(const bdaddr_t *addr, int err, void *attrib);
> +
> +unsigned int bt_gatt_register_app(const char *uuid, gatt_type_t type,
> + gatt_conn_cb_t func);
> +bool bt_gatt_unregister_app(unsigned int id);
> +
> +bool bt_gatt_connect_app(unsigned int id, const bdaddr_t *addr);
> +bool bt_gatt_disconnect_app(unsigned int id, const bdaddr_t *addr);
> --
> 1.9.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
BR
Lukasz
From: Luiz Augusto von Dentz <[email protected]>
---
android/gatt.c | 637 ++++++++++++++++++++++++++++++++-------------------------
1 file changed, 353 insertions(+), 284 deletions(-)
diff --git a/android/gatt.c b/android/gatt.c
index 8f65827..2fad341 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -791,6 +791,9 @@ static void send_client_disconnection_notify(struct app_connection *connection,
static void send_app_disconnect_notify(struct app_connection *connection,
int32_t status)
{
+ if (!connection->app)
+ return;
+
if (connection->app->type == GATT_CLIENT)
send_client_disconnection_notify(connection, status);
else
@@ -800,6 +803,9 @@ static void send_app_disconnect_notify(struct app_connection *connection,
static void send_app_connect_notify(struct app_connection *connection,
int32_t status)
{
+ if (!connection->app)
+ return;
+
if (connection->app->type == GATT_CLIENT)
send_client_connection_notify(connection, status);
else if (connection->app->type == GATT_SERVER)
@@ -811,7 +817,7 @@ static void disconnect_notify_by_device(void *data, void *user_data)
struct app_connection *conn = data;
struct gatt_device *dev = user_data;
- if (dev != conn->device)
+ if (dev != conn->device || !conn->app)
return;
if (dev->state == DEVICE_CONNECTED)
@@ -968,6 +974,317 @@ static void notify_att_range_change(struct gatt_device *dev,
g_attrib_send(dev->attrib, 0, pdu, length, NULL, NULL, NULL);
}
+static struct app_connection *create_connection(struct gatt_device *device,
+ struct gatt_app *app)
+{
+ struct app_connection *new_conn;
+ static int32_t last_conn_id = 1;
+
+ /* Check if already connected */
+ new_conn = new0(struct app_connection, 1);
+ if (!new_conn)
+ return NULL;
+
+ /* Make connection id unique to connection record (app, device) pair */
+ new_conn->app = app;
+ new_conn->id = last_conn_id++;
+
+ new_conn->transactions = queue_new();
+ if (!new_conn->transactions) {
+ free(new_conn);
+ return NULL;
+ }
+
+ if (!queue_push_head(app_connections, new_conn)) {
+ error("gatt: Cannot push client on the client queue!?");
+ queue_destroy(new_conn->transactions, free);
+ free(new_conn);
+ return NULL;
+ }
+
+ new_conn->device = device_ref(device);
+ new_conn->device->conn_cnt++;
+
+ return new_conn;
+}
+
+static struct service *create_service(uint8_t id, bool primary, char *uuid,
+ void *data)
+{
+ struct service *s;
+
+ s = new0(struct service, 1);
+ if (!s) {
+ error("gatt: Cannot allocate memory for gatt_primary");
+ return NULL;
+ }
+
+ s->chars = queue_new();
+ if (!s->chars) {
+ error("gatt: Cannot allocate memory for char cache");
+ free(s);
+ return NULL;
+ }
+
+ if (bt_string_to_uuid(&s->id.uuid, uuid) < 0) {
+ error("gatt: Cannot convert string to uuid");
+ queue_destroy(s->chars, NULL);
+ free(s);
+ return NULL;
+ }
+
+ s->id.instance = id;
+
+ /* Put primary service to our local list */
+ s->primary = primary;
+ if (s->primary) {
+ memcpy(&s->prim, data, sizeof(s->prim));
+ } else {
+ memcpy(&s->incl, data, sizeof(s->incl));
+ return s;
+ }
+
+ /* For primary service allocate queue for included services */
+ s->included = queue_new();
+ if (!s->included) {
+ queue_destroy(s->chars, NULL);
+ free(s);
+ return NULL;
+ }
+
+ return s;
+}
+
+static void send_client_primary_notify(void *data, void *user_data)
+{
+ struct hal_ev_gatt_client_search_result ev;
+ struct service *p = data;
+ int32_t conn_id = PTR_TO_INT(user_data);
+
+ /* In service queue we will have also included services */
+ if (!p->primary)
+ return;
+
+ ev.conn_id = conn_id;
+ element_id_to_hal_srvc_id(&p->id, 1, &ev.srvc_id);
+
+ uuid2android(&p->id.uuid, ev.srvc_id.uuid);
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_CLIENT_SEARCH_RESULT, sizeof(ev), &ev);
+}
+
+static void send_client_search_complete_notify(int32_t status, int32_t conn_id)
+{
+ struct hal_ev_gatt_client_search_complete ev;
+
+ ev.status = status;
+ ev.conn_id = conn_id;
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_CLIENT_SEARCH_COMPLETE, sizeof(ev), &ev);
+}
+
+struct discover_srvc_data {
+ bt_uuid_t uuid;
+ struct app_connection *conn;
+};
+
+static void discover_srvc_by_uuid_cb(uint8_t status, GSList *ranges,
+ void *user_data)
+{
+ struct discover_srvc_data *cb_data = user_data;
+ struct gatt_primary prim;
+ struct service *s;
+ int32_t gatt_status;
+ struct gatt_device *dev = cb_data->conn->device;
+ uint8_t instance_id = queue_length(dev->services);
+
+ DBG("Status %d", status);
+
+ if (status) {
+ error("gatt: Discover pri srvc filtered by uuid failed: %s",
+ att_ecode2str(status));
+ gatt_status = GATT_FAILURE;
+ goto reply;
+ }
+
+ if (!ranges) {
+ info("gatt: No primary services searched by uuid found");
+ gatt_status = GATT_SUCCESS;
+ goto reply;
+ }
+
+ bt_uuid_to_string(&cb_data->uuid, prim.uuid, sizeof(prim.uuid));
+ /*
+ * If multiple instances of the same service (as identified by UUID)
+ * exist, the first instance of the service is returned.
+ */
+ memcpy(&prim.range, ranges->data, sizeof(prim.range));
+
+ s = create_service(instance_id++, true, prim.uuid, &prim);
+ if (!s) {
+ gatt_status = GATT_FAILURE;
+ goto reply;
+ }
+
+ if (!queue_push_tail(dev->services, s)) {
+ error("gatt: Cannot push primary service to the list");
+ gatt_status = GATT_FAILURE;
+ goto reply;
+ }
+
+ send_client_primary_notify(s, INT_TO_PTR(cb_data->conn->id));
+
+ DBG("attr handle = 0x%04x, end grp handle = 0x%04x uuid: %s",
+ prim.range.start, prim.range.end, prim.uuid);
+
+ /* Partial search service scanning was performed */
+ dev->partial_srvc_search = true;
+ gatt_status = GATT_SUCCESS;
+
+reply:
+ send_client_search_complete_notify(gatt_status, cb_data->conn->id);
+ free(cb_data);
+}
+
+static void discover_srvc_all_cb(uint8_t status, GSList *services,
+ void *user_data)
+{
+ struct discover_srvc_data *cb_data = user_data;
+ struct gatt_device *dev = cb_data->conn->device;
+ int32_t gatt_status;
+ GSList *l;
+ /*
+ * There might be multiply services with same uuid. Therefore make sure
+ * each primary service one has unique instance_id
+ */
+ uint8_t instance_id = queue_length(dev->services);
+
+ DBG("Status %d", status);
+
+ if (status) {
+ error("gatt: Discover all primary services failed: %s",
+ att_ecode2str(status));
+ gatt_status = GATT_FAILURE;
+ goto reply;
+ }
+
+ if (!services) {
+ info("gatt: No primary services found");
+ gatt_status = GATT_SUCCESS;
+ goto reply;
+ }
+
+ for (l = services; l; l = l->next) {
+ struct gatt_primary *prim = l->data;
+ struct service *p;
+
+ if (queue_find(dev->services, match_srvc_by_range,
+ &prim->range))
+ continue;
+
+ p = create_service(instance_id++, true, prim->uuid, prim);
+ if (!p)
+ continue;
+
+ if (!queue_push_tail(dev->services, p)) {
+ error("gatt: Cannot push primary service to the list");
+ free(p);
+ continue;
+ }
+
+ DBG("attr handle = 0x%04x, end grp handle = 0x%04x uuid: %s",
+ prim->range.start, prim->range.end, prim->uuid);
+ }
+
+ /*
+ * Send all found services notifications - first cache,
+ * then send notifies
+ */
+ queue_foreach(dev->services, send_client_primary_notify,
+ INT_TO_PTR(cb_data->conn->id));
+
+ /* Full search service scanning was performed */
+ dev->partial_srvc_search = false;
+ gatt_status = GATT_SUCCESS;
+
+reply:
+ send_client_search_complete_notify(gatt_status, cb_data->conn->id);
+ free(cb_data);
+}
+
+static void discover_primary_cb(uint8_t status, GSList *services,
+ void *user_data)
+{
+ struct discover_srvc_data *cb_data = user_data;
+ struct app_connection *conn = cb_data->conn;
+ struct gatt_device *dev = conn->device;
+ GSList *l, *uuids = NULL;
+
+ DBG("Status %d", status);
+
+ if (status) {
+ error("gatt: Discover all primary services failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ if (!services) {
+ info("gatt: No primary services found");
+ return;
+ }
+
+ for (l = services; l; l = l->next) {
+ struct gatt_primary *prim = l->data;
+ uint8_t *new_uuid;
+ bt_uuid_t uuid;
+
+ DBG("uuid: %s", prim->uuid);
+
+ if (bt_string_to_uuid(&uuid, prim->uuid) < 0) {
+ error("gatt: Cannot convert string to uuid");
+ continue;
+ }
+
+ new_uuid = g_memdup(&uuid.value.u128, sizeof(uuid.value.u128));
+
+ uuids = g_slist_prepend(uuids, new_uuid);
+ }
+
+ bt_device_set_uuids(&dev->bdaddr, uuids);
+
+ free(cb_data);
+ queue_remove(app_connections, conn);
+ destroy_connection(conn);
+}
+
+static guint search_dev_for_srvc(struct app_connection *conn, bt_uuid_t *uuid)
+{
+ struct discover_srvc_data *cb_data =
+ new0(struct discover_srvc_data, 1);
+
+ if (!cb_data) {
+ error("gatt: Cannot allocate cb data");
+ return 0;
+ }
+
+ cb_data->conn = conn;
+
+ if (uuid) {
+ memcpy(&cb_data->uuid, uuid, sizeof(cb_data->uuid));
+ return gatt_discover_primary(conn->device->attrib, uuid,
+ discover_srvc_by_uuid_cb, cb_data);
+ }
+
+
+ if (conn->app)
+ return gatt_discover_primary(conn->device->attrib, NULL,
+ discover_srvc_all_cb, cb_data);
+
+ return gatt_discover_primary(conn->device->attrib, NULL,
+ discover_primary_cb, cb_data);
+}
+
struct connect_data {
struct gatt_device *dev;
int32_t status;
@@ -1051,6 +1368,19 @@ static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
status = GATT_SUCCESS;
reply:
+ if (!dev->conn_cnt) {
+ struct app_connection *conn;
+
+ if (!dev->attrib)
+ return;
+
+ conn = create_connection(dev, NULL);
+ if (!conn)
+ return;
+
+ search_dev_for_srvc(conn, NULL);
+ }
+
data.dev = dev;
data.status = status;
queue_foreach(app_connections, send_app_connect_notifications, &data);
@@ -1215,105 +1545,39 @@ static struct gatt_app *register_app(const uint8_t *uuid, gatt_type_t type)
if ((app->type == GATT_SERVER) &&
!queue_push_tail(listen_apps, INT_TO_PTR(app->id))) {
error("gatt: Cannot push server on the list");
- destroy_gatt_app(app);
- return NULL;
- }
-
- return app;
-}
-
-static void handle_client_register(const void *buf, uint16_t len)
-{
- const struct hal_cmd_gatt_client_register *cmd = buf;
- struct hal_ev_gatt_client_register_client ev;
- struct gatt_app *app;
-
- DBG("");
-
- memset(&ev, 0, sizeof(ev));
-
- app = register_app(cmd->uuid, GATT_CLIENT);
-
- if (app) {
- ev.client_if = app->id;
- ev.status = GATT_SUCCESS;
- } else
- ev.status = GATT_FAILURE;
-
- /* We should send notification with given in cmd UUID */
- memcpy(ev.app_uuid, cmd->uuid, sizeof(ev.app_uuid));
-
- ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_EV_GATT_CLIENT_REGISTER_CLIENT, sizeof(ev), &ev);
-
- ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT, HAL_OP_GATT_CLIENT_REGISTER,
- HAL_STATUS_SUCCESS);
-}
-
-static void send_client_primary_notify(void *data, void *user_data)
-{
- struct hal_ev_gatt_client_search_result ev;
- struct service *p = data;
- int32_t conn_id = PTR_TO_INT(user_data);
-
- /* In service queue we will have also included services */
- if (!p->primary)
- return;
-
- ev.conn_id = conn_id;
- element_id_to_hal_srvc_id(&p->id, 1, &ev.srvc_id);
-
- uuid2android(&p->id.uuid, ev.srvc_id.uuid);
+ destroy_gatt_app(app);
+ return NULL;
+ }
- ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_EV_GATT_CLIENT_SEARCH_RESULT, sizeof(ev), &ev);
+ return app;
}
-static struct service *create_service(uint8_t id, bool primary, char *uuid,
- void *data)
+static void handle_client_register(const void *buf, uint16_t len)
{
- struct service *s;
+ const struct hal_cmd_gatt_client_register *cmd = buf;
+ struct hal_ev_gatt_client_register_client ev;
+ struct gatt_app *app;
- s = new0(struct service, 1);
- if (!s) {
- error("gatt: Cannot allocate memory for gatt_primary");
- return NULL;
- }
+ DBG("");
- s->chars = queue_new();
- if (!s->chars) {
- error("gatt: Cannot allocate memory for char cache");
- free(s);
- return NULL;
- }
+ memset(&ev, 0, sizeof(ev));
- if (bt_string_to_uuid(&s->id.uuid, uuid) < 0) {
- error("gatt: Cannot convert string to uuid");
- queue_destroy(s->chars, NULL);
- free(s);
- return NULL;
- }
+ app = register_app(cmd->uuid, GATT_CLIENT);
- s->id.instance = id;
+ if (app) {
+ ev.client_if = app->id;
+ ev.status = GATT_SUCCESS;
+ } else
+ ev.status = GATT_FAILURE;
- /* Put primary service to our local list */
- s->primary = primary;
- if (s->primary) {
- memcpy(&s->prim, data, sizeof(s->prim));
- } else {
- memcpy(&s->incl, data, sizeof(s->incl));
- return s;
- }
+ /* We should send notification with given in cmd UUID */
+ memcpy(ev.app_uuid, cmd->uuid, sizeof(ev.app_uuid));
- /* For primary service allocate queue for included services */
- s->included = queue_new();
- if (!s->included) {
- queue_destroy(s->chars, NULL);
- free(s);
- return NULL;
- }
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_CLIENT_REGISTER_CLIENT, sizeof(ev), &ev);
- return s;
+ ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT, HAL_OP_GATT_CLIENT_REGISTER,
+ HAL_STATUS_SUCCESS);
}
static void handle_client_scan(const void *buf, uint16_t len)
@@ -1373,40 +1637,6 @@ static void bt_le_discovery_stop_cb(void)
bt_le_discovery_start();
}
-static struct app_connection *create_connection(struct gatt_device *device,
- struct gatt_app *app)
-{
- struct app_connection *new_conn;
- static int32_t last_conn_id = 1;
-
- /* Check if already connected */
- new_conn = new0(struct app_connection, 1);
- if (!new_conn)
- return NULL;
-
- /* Make connection id unique to connection record (app, device) pair */
- new_conn->app = app;
- new_conn->id = last_conn_id++;
-
- new_conn->transactions = queue_new();
- if (!new_conn->transactions) {
- free(new_conn);
- return NULL;
- }
-
- if (!queue_push_head(app_connections, new_conn)) {
- error("gatt: Cannot push client on the client queue!?");
- queue_destroy(new_conn->transactions, free);
- free(new_conn);
- return NULL;
- }
-
- new_conn->device = device_ref(device);
- new_conn->device->conn_cnt++;
-
- return new_conn;
-}
-
static void trigger_disconnection(struct app_connection *connection)
{
/* Notify client */
@@ -1757,167 +1987,6 @@ done:
status);
}
-struct discover_srvc_data {
- bt_uuid_t uuid;
- struct app_connection *conn;
-};
-
-static void send_client_search_complete_notify(int32_t status, int32_t conn_id)
-{
- struct hal_ev_gatt_client_search_complete ev;
-
- ev.status = status;
- ev.conn_id = conn_id;
- ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_EV_GATT_CLIENT_SEARCH_COMPLETE, sizeof(ev), &ev);
-}
-
-static void discover_srvc_all_cb(uint8_t status, GSList *services,
- void *user_data)
-{
- struct discover_srvc_data *cb_data = user_data;
- struct gatt_device *dev = cb_data->conn->device;
- int32_t gatt_status;
- GSList *l;
- /*
- * There might be multiply services with same uuid. Therefore make sure
- * each primary service one has unique instance_id
- */
- uint8_t instance_id = queue_length(dev->services);
-
- DBG("Status %d", status);
-
- if (status) {
- error("gatt: Discover all primary services failed: %s",
- att_ecode2str(status));
- gatt_status = GATT_FAILURE;
- goto reply;
- }
-
- if (!services) {
- info("gatt: No primary services found");
- gatt_status = GATT_SUCCESS;
- goto reply;
- }
-
- for (l = services; l; l = l->next) {
- struct gatt_primary *prim = l->data;
- struct service *p;
-
- if (queue_find(dev->services, match_srvc_by_range,
- &prim->range))
- continue;
-
- p = create_service(instance_id++, true, prim->uuid, prim);
- if (!p)
- continue;
-
- if (!queue_push_tail(dev->services, p)) {
- error("gatt: Cannot push primary service to the list");
- free(p);
- continue;
- }
-
- DBG("attr handle = 0x%04x, end grp handle = 0x%04x uuid: %s",
- prim->range.start, prim->range.end, prim->uuid);
- }
-
- /*
- * Send all found services notifications - first cache,
- * then send notifies
- */
- queue_foreach(dev->services, send_client_primary_notify,
- INT_TO_PTR(cb_data->conn->id));
-
- /* Full search service scanning was performed */
- dev->partial_srvc_search = false;
- gatt_status = GATT_SUCCESS;
-
-reply:
- send_client_search_complete_notify(gatt_status, cb_data->conn->id);
- free(cb_data);
-}
-
-static void discover_srvc_by_uuid_cb(uint8_t status, GSList *ranges,
- void *user_data)
-{
- struct discover_srvc_data *cb_data = user_data;
- struct gatt_primary prim;
- struct service *s;
- int32_t gatt_status;
- struct gatt_device *dev = cb_data->conn->device;
- uint8_t instance_id = queue_length(dev->services);
-
- DBG("Status %d", status);
-
- if (status) {
- error("gatt: Discover pri srvc filtered by uuid failed: %s",
- att_ecode2str(status));
- gatt_status = GATT_FAILURE;
- goto reply;
- }
-
- if (!ranges) {
- info("gatt: No primary services searched by uuid found");
- gatt_status = GATT_SUCCESS;
- goto reply;
- }
-
- bt_uuid_to_string(&cb_data->uuid, prim.uuid, sizeof(prim.uuid));
- /*
- * If multiple instances of the same service (as identified by UUID)
- * exist, the first instance of the service is returned.
- */
- memcpy(&prim.range, ranges->data, sizeof(prim.range));
-
- s = create_service(instance_id++, true, prim.uuid, &prim);
- if (!s) {
- gatt_status = GATT_FAILURE;
- goto reply;
- }
-
- if (!queue_push_tail(dev->services, s)) {
- error("gatt: Cannot push primary service to the list");
- gatt_status = GATT_FAILURE;
- goto reply;
- }
-
- send_client_primary_notify(s, INT_TO_PTR(cb_data->conn->id));
-
- DBG("attr handle = 0x%04x, end grp handle = 0x%04x uuid: %s",
- prim.range.start, prim.range.end, prim.uuid);
-
- /* Partial search service scanning was performed */
- dev->partial_srvc_search = true;
- gatt_status = GATT_SUCCESS;
-
-reply:
- send_client_search_complete_notify(gatt_status, cb_data->conn->id);
- free(cb_data);
-}
-
-static guint search_dev_for_srvc(struct app_connection *conn, bt_uuid_t *uuid)
-{
- struct discover_srvc_data *cb_data =
- new0(struct discover_srvc_data, 1);
-
- if (!cb_data) {
- error("gatt: Cannot allocate cb data");
- return 0;
- }
-
- cb_data->conn = conn;
-
- if (uuid) {
- memcpy(&cb_data->uuid, uuid, sizeof(cb_data->uuid));
- return gatt_discover_primary(conn->device->attrib, uuid,
- discover_srvc_by_uuid_cb, cb_data);
- }
-
- return gatt_discover_primary(conn->device->attrib, NULL,
- discover_srvc_all_cb, cb_data);
-}
-
static void handle_client_search_service(const void *buf, uint16_t len)
{
const struct hal_cmd_gatt_client_search_service *cmd = buf;
--
1.9.3
From: Luiz Augusto von Dentz <[email protected]>
This is needed in Android in order react to services found.
---
android/gatt.c | 23 +++++++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)
diff --git a/android/gatt.c b/android/gatt.c
index 2fad341..d162c7b 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -68,6 +68,8 @@
#define GATT_PERM_WRITE_SIGNED 0x00010000
#define GATT_PERM_WRITE_SIGNED_MITM 0x00020000
+#define GATT_CONN_TIMEOUT 2
+
static const uint8_t BLUETOOTH_UUID[] = {
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
@@ -169,6 +171,8 @@ struct app_connection {
struct queue *transactions;
int32_t id;
+ guint timeout_id;
+
bool wait_execute_write;
};
@@ -831,6 +835,9 @@ static void destroy_connection(void *data)
{
struct app_connection *conn = data;
+ if (conn->timeout_id > 0)
+ g_source_remove(conn->timeout_id);
+
if (!queue_find(gatt_devices, match_by_value, conn->device))
goto cleanup;
@@ -1212,6 +1219,17 @@ reply:
send_client_search_complete_notify(gatt_status, cb_data->conn->id);
free(cb_data);
}
+static gboolean connection_timeout(void *user_data)
+{
+ struct app_connection *conn = user_data;
+
+ conn->timeout_id = 0;
+
+ queue_remove(app_connections, conn);
+ destroy_connection(conn);
+
+ return FALSE;
+}
static void discover_primary_cb(uint8_t status, GSList *services,
void *user_data)
@@ -1254,8 +1272,9 @@ static void discover_primary_cb(uint8_t status, GSList *services,
bt_device_set_uuids(&dev->bdaddr, uuids);
free(cb_data);
- queue_remove(app_connections, conn);
- destroy_connection(conn);
+
+ conn->timeout_id = g_timeout_add_seconds(GATT_CONN_TIMEOUT,
+ connection_timeout, conn);
}
static guint search_dev_for_srvc(struct app_connection *conn, bt_uuid_t *uuid)
--
1.9.3
From: Luiz Augusto von Dentz <[email protected]>
Devices bonded should be connected so later their services can be
discovered.
---
android/gatt.c | 617 +++++++++++++++++++++++++++++----------------------------
1 file changed, 310 insertions(+), 307 deletions(-)
diff --git a/android/gatt.c b/android/gatt.c
index 8a8419c..8f65827 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -627,151 +627,99 @@ static void destroy_gatt_app(void *data)
free(app);
}
-static void le_device_found_handler(const bdaddr_t *addr, uint8_t addr_type,
- int rssi, uint16_t eir_len,
- const void *eir,
- bool discoverable, bool bonded)
-{
- uint8_t buf[IPC_MTU];
- struct hal_ev_gatt_client_scan_result *ev = (void *) buf;
- struct gatt_device *dev;
- char bda[18];
-
- if (!scanning || (!discoverable && !bonded))
- goto connect;
-
- ba2str(addr, bda);
- DBG("LE Device found: %s, rssi: %d, adv_data: %d", bda, rssi, !!eir);
-
- bdaddr2android(addr, ev->bda);
- ev->rssi = rssi;
- ev->len = eir_len;
-
- memcpy(ev->adv_data, eir, ev->len);
+enum pend_req_state {
+ REQUEST_INIT,
+ REQUEST_PENDING,
+ REQUEST_DONE,
+};
- ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_EV_GATT_CLIENT_SCAN_RESULT,
- sizeof(*ev) + ev->len, ev);
+struct pending_request {
+ uint16_t handle;
+ int length;
+ uint8_t *value;
+ uint16_t offset;
-connect:
- dev = find_device_by_addr(addr);
- if (!dev || (dev->state != DEVICE_CONNECT_INIT))
- return;
+ uint8_t *filter_value;
+ uint16_t filter_vlen;
- device_set_state(dev, DEVICE_CONNECT_READY);
- dev->bdaddr_type = addr_type;
+ enum pend_req_state state;
+ uint8_t error;
+};
- if (!scanning) {
- connect_next_dev();
- return;
- }
+static void destroy_pending_request(void *data)
+{
+ struct pending_request *entry = data;
- /*
- * We are ok to perform connect now. Stop discovery
- * and once it is stopped continue with creating ACL
- */
- bt_le_discovery_stop(bt_le_discovery_stop_cb);
+ free(entry->value);
+ free(entry->filter_value);
+ free(entry);
}
-static struct gatt_app *register_app(const uint8_t *uuid, gatt_type_t type)
+static void destroy_device(void *data)
{
- static int32_t application_id = 1;
- struct gatt_app *app;
-
- if (queue_find(gatt_apps, match_app_by_uuid, uuid)) {
- error("gatt: app uuid is already on list");
- return NULL;
- }
-
- /* Register LE once the first app register */
- if (queue_isempty(gatt_apps))
- bt_le_register(le_device_found_handler);
-
- app = new0(struct gatt_app, 1);
- if (!app) {
- error("gatt: Cannot allocate memory for registering app");
- return 0;
- }
-
- app->type = type;
+ struct gatt_device *dev = data;
- if (app->type == GATT_CLIENT) {
- app->notifications = queue_new();
- if (!app->notifications) {
- error("gatt: couldn't allocate notifications queue");
- destroy_gatt_app(app);
- return NULL;
- }
- }
+ if (!dev)
+ return;
- memcpy(app->uuid, uuid, sizeof(app->uuid));
+ queue_destroy(dev->services, destroy_service);
+ queue_destroy(dev->pending_requests, destroy_pending_request);
- app->id = application_id++;
+ free(dev);
+}
- if (!queue_push_head(gatt_apps, app)) {
- error("gatt: Cannot push app on the list");
- destroy_gatt_app(app);
+static struct gatt_device *device_ref(struct gatt_device *device)
+{
+ if (!device)
return NULL;
- }
- if ((app->type == GATT_SERVER) &&
- !queue_push_tail(listen_apps, INT_TO_PTR(app->id))) {
- error("gatt: Cannot push server on the list");
- destroy_gatt_app(app);
- return NULL;
- }
+ device->ref++;
- return app;
+ return device;
}
-static void handle_client_register(const void *buf, uint16_t len)
+static void device_unref(struct gatt_device *device)
{
- const struct hal_cmd_gatt_client_register *cmd = buf;
- struct hal_ev_gatt_client_register_client ev;
- struct gatt_app *app;
-
- DBG("");
-
- memset(&ev, 0, sizeof(ev));
-
- app = register_app(cmd->uuid, GATT_CLIENT);
-
- if (app) {
- ev.client_if = app->id;
- ev.status = GATT_SUCCESS;
- } else
- ev.status = GATT_FAILURE;
-
- /* We should send notification with given in cmd UUID */
- memcpy(ev.app_uuid, cmd->uuid, sizeof(ev.app_uuid));
+ if (!device)
+ return;
- ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_EV_GATT_CLIENT_REGISTER_CLIENT, sizeof(ev), &ev);
+ if (--device->ref)
+ return;
- ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT, HAL_OP_GATT_CLIENT_REGISTER,
- HAL_STATUS_SUCCESS);
+ destroy_device(device);
}
-static void send_client_disconnection_notify(struct app_connection *connection,
- int32_t status)
+static struct gatt_device *create_device(const bdaddr_t *addr)
{
- struct hal_ev_gatt_client_disconnect ev;
+ struct gatt_device *dev;
- if (connection->app->func) {
- connection->app->func(&connection->device->bdaddr, -ENOTCONN,
- connection->device->attrib);
- return;
- }
+ dev = new0(struct gatt_device, 1);
+ if (!dev)
+ return NULL;
- ev.client_if = connection->app->id;
- ev.conn_id = connection->id;
- ev.status = status;
+ bacpy(&dev->bdaddr, addr);
- bdaddr2android(&connection->device->bdaddr, &ev.bda);
+ dev->services = queue_new();
+ if (!dev->services) {
+ error("gatt: Failed to allocate memory for client");
+ destroy_device(dev);
+ return NULL;
+ }
- ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_EV_GATT_CLIENT_DISCONNECT, sizeof(ev), &ev);
+ dev->pending_requests = queue_new();
+ if (!dev->pending_requests) {
+ error("gatt: Failed to allocate memory for client");
+ destroy_device(dev);
+ return NULL;
+ }
+
+ if (!queue_push_head(gatt_devices, dev)) {
+ error("gatt: Cannot push device to queue");
+ destroy_device(dev);
+ return NULL;
+ }
+ return device_ref(dev);
}
static void send_client_connection_notify(struct app_connection *connection,
@@ -818,6 +766,28 @@ static void send_server_connection_notify(struct app_connection *connection,
HAL_EV_GATT_SERVER_CONNECTION, sizeof(ev), &ev);
}
+static void send_client_disconnection_notify(struct app_connection *connection,
+ int32_t status)
+{
+ struct hal_ev_gatt_client_disconnect ev;
+
+ if (connection->app->func) {
+ connection->app->func(&connection->device->bdaddr, -ENOTCONN,
+ connection->device->attrib);
+ return;
+ }
+
+ ev.client_if = connection->app->id;
+ ev.conn_id = connection->id;
+ ev.status = status;
+
+ bdaddr2android(&connection->device->bdaddr, &ev.bda);
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_CLIENT_DISCONNECT, sizeof(ev), &ev);
+
+}
+
static void send_app_disconnect_notify(struct app_connection *connection,
int32_t status)
{
@@ -851,68 +821,6 @@ static void disconnect_notify_by_device(void *data, void *user_data)
send_app_connect_notify(conn, GATT_FAILURE);
}
-enum pend_req_state {
- REQUEST_INIT,
- REQUEST_PENDING,
- REQUEST_DONE,
-};
-
-struct pending_request {
- uint16_t handle;
- int length;
- uint8_t *value;
- uint16_t offset;
-
- uint8_t *filter_value;
- uint16_t filter_vlen;
-
- enum pend_req_state state;
- uint8_t error;
-};
-
-static void destroy_pending_request(void *data)
-{
- struct pending_request *entry = data;
-
- free(entry->value);
- free(entry->filter_value);
- free(entry);
-}
-
-static void destroy_device(void *data)
-{
- struct gatt_device *dev = data;
-
- if (!dev)
- return;
-
- queue_destroy(dev->services, destroy_service);
- queue_destroy(dev->pending_requests, destroy_pending_request);
-
- free(dev);
-}
-
-static struct gatt_device *device_ref(struct gatt_device *device)
-{
- if (!device)
- return NULL;
-
- device->ref++;
-
- return device;
-}
-
-static void device_unref(struct gatt_device *device)
-{
- if (!device)
- return;
-
- if (--device->ref)
- return;
-
- destroy_device(device);
-}
-
static void destroy_connection(void *data)
{
struct app_connection *conn = data;
@@ -940,72 +848,6 @@ static void device_disconnect_clients(struct gatt_device *dev)
destroy_connection);
}
-static void send_client_primary_notify(void *data, void *user_data)
-{
- struct hal_ev_gatt_client_search_result ev;
- struct service *p = data;
- int32_t conn_id = PTR_TO_INT(user_data);
-
- /* In service queue we will have also included services */
- if (!p->primary)
- return;
-
- ev.conn_id = conn_id;
- element_id_to_hal_srvc_id(&p->id, 1, &ev.srvc_id);
-
- uuid2android(&p->id.uuid, ev.srvc_id.uuid);
-
- ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_EV_GATT_CLIENT_SEARCH_RESULT, sizeof(ev), &ev);
-}
-
-static struct service *create_service(uint8_t id, bool primary, char *uuid,
- void *data)
-{
- struct service *s;
-
- s = new0(struct service, 1);
- if (!s) {
- error("gatt: Cannot allocate memory for gatt_primary");
- return NULL;
- }
-
- s->chars = queue_new();
- if (!s->chars) {
- error("gatt: Cannot allocate memory for char cache");
- free(s);
- return NULL;
- }
-
- if (bt_string_to_uuid(&s->id.uuid, uuid) < 0) {
- error("gatt: Cannot convert string to uuid");
- queue_destroy(s->chars, NULL);
- free(s);
- return NULL;
- }
-
- s->id.instance = id;
-
- /* Put primary service to our local list */
- s->primary = primary;
- if (s->primary) {
- memcpy(&s->prim, data, sizeof(s->prim));
- } else {
- memcpy(&s->incl, data, sizeof(s->incl));
- return s;
- }
-
- /* For primary service allocate queue for included services */
- s->included = queue_new();
- if (!s->included) {
- queue_destroy(s->chars, NULL);
- free(s);
- return NULL;
- }
-
- return s;
-}
-
static gboolean disconnected_cb(GIOChannel *io, GIOCondition cond,
gpointer user_data)
{
@@ -1023,20 +865,6 @@ static gboolean disconnected_cb(GIOChannel *io, GIOCondition cond,
return FALSE;
}
-struct connect_data {
- struct gatt_device *dev;
- int32_t status;
-};
-
-static void send_app_connect_notifications(void *data, void *user_data)
-{
- struct app_connection *conn = data;
- struct connect_data *con_data = user_data;
-
- if (conn->device == con_data->dev)
- send_app_connect_notify(conn, con_data->status);
-}
-
static void att_handler(const uint8_t *ipdu, uint16_t len, gpointer user_data);
static void exchange_mtu_cb(guint8 status, const guint8 *pdu, guint16 plen,
@@ -1136,8 +964,22 @@ static void notify_att_range_change(struct gatt_device *dev,
break;
}
- if (length)
- g_attrib_send(dev->attrib, 0, pdu, length, NULL, NULL, NULL);
+ if (length)
+ g_attrib_send(dev->attrib, 0, pdu, length, NULL, NULL, NULL);
+}
+
+struct connect_data {
+ struct gatt_device *dev;
+ int32_t status;
+};
+
+static void send_app_connect_notifications(void *data, void *user_data)
+{
+ struct app_connection *conn = data;
+ struct connect_data *con_data = user_data;
+
+ if (conn->device == con_data->dev)
+ send_app_connect_notify(conn, con_data->status);
}
static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
@@ -1267,6 +1109,213 @@ static int connect_le(struct gatt_device *dev)
return 0;
}
+static int connect_next_dev(void)
+{
+ struct gatt_device *dev;
+
+ DBG("");
+
+ dev = find_device_by_state(DEVICE_CONNECT_READY);
+ if (!dev)
+ return -ENODEV;
+
+ return connect_le(dev);
+}
+
+static void le_device_found_handler(const bdaddr_t *addr, uint8_t addr_type,
+ int rssi, uint16_t eir_len,
+ const void *eir,
+ bool discoverable, bool bonded)
+{
+ uint8_t buf[IPC_MTU];
+ struct hal_ev_gatt_client_scan_result *ev = (void *) buf;
+ struct gatt_device *dev;
+ char bda[18];
+
+ if (!scanning || (!discoverable && !bonded))
+ goto connect;
+
+ ba2str(addr, bda);
+ DBG("LE Device found: %s, rssi: %d, adv_data: %d", bda, rssi, !!eir);
+
+ bdaddr2android(addr, ev->bda);
+ ev->rssi = rssi;
+ ev->len = eir_len;
+
+ memcpy(ev->adv_data, eir, ev->len);
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_CLIENT_SCAN_RESULT,
+ sizeof(*ev) + ev->len, ev);
+
+connect:
+ dev = find_device_by_addr(addr);
+ if (!dev) {
+ if (!bonded)
+ return;
+
+ dev = create_device(addr);
+ if (!dev)
+ return;
+ connect_le(dev);
+ return;
+ }
+
+ device_set_state(dev, DEVICE_CONNECT_READY);
+ dev->bdaddr_type = addr_type;
+
+ /*
+ * We are ok to perform connect now. Stop discovery
+ * and once it is stopped continue with creating ACL
+ */
+ bt_le_discovery_stop(bt_le_discovery_stop_cb);
+}
+
+static struct gatt_app *register_app(const uint8_t *uuid, gatt_type_t type)
+{
+ static int32_t application_id = 1;
+ struct gatt_app *app;
+
+ if (queue_find(gatt_apps, match_app_by_uuid, uuid)) {
+ error("gatt: app uuid is already on list");
+ return NULL;
+ }
+
+ /* Register LE once the first app register */
+ if (queue_isempty(gatt_apps))
+ bt_le_register(le_device_found_handler);
+
+ app = new0(struct gatt_app, 1);
+ if (!app) {
+ error("gatt: Cannot allocate memory for registering app");
+ return 0;
+ }
+
+ app->type = type;
+
+ if (app->type == GATT_CLIENT) {
+ app->notifications = queue_new();
+ if (!app->notifications) {
+ error("gatt: couldn't allocate notifications queue");
+ destroy_gatt_app(app);
+ return NULL;
+ }
+ }
+
+ memcpy(app->uuid, uuid, sizeof(app->uuid));
+
+ app->id = application_id++;
+
+ if (!queue_push_head(gatt_apps, app)) {
+ error("gatt: Cannot push app on the list");
+ destroy_gatt_app(app);
+ return NULL;
+ }
+
+ if ((app->type == GATT_SERVER) &&
+ !queue_push_tail(listen_apps, INT_TO_PTR(app->id))) {
+ error("gatt: Cannot push server on the list");
+ destroy_gatt_app(app);
+ return NULL;
+ }
+
+ return app;
+}
+
+static void handle_client_register(const void *buf, uint16_t len)
+{
+ const struct hal_cmd_gatt_client_register *cmd = buf;
+ struct hal_ev_gatt_client_register_client ev;
+ struct gatt_app *app;
+
+ DBG("");
+
+ memset(&ev, 0, sizeof(ev));
+
+ app = register_app(cmd->uuid, GATT_CLIENT);
+
+ if (app) {
+ ev.client_if = app->id;
+ ev.status = GATT_SUCCESS;
+ } else
+ ev.status = GATT_FAILURE;
+
+ /* We should send notification with given in cmd UUID */
+ memcpy(ev.app_uuid, cmd->uuid, sizeof(ev.app_uuid));
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_CLIENT_REGISTER_CLIENT, sizeof(ev), &ev);
+
+ ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT, HAL_OP_GATT_CLIENT_REGISTER,
+ HAL_STATUS_SUCCESS);
+}
+
+static void send_client_primary_notify(void *data, void *user_data)
+{
+ struct hal_ev_gatt_client_search_result ev;
+ struct service *p = data;
+ int32_t conn_id = PTR_TO_INT(user_data);
+
+ /* In service queue we will have also included services */
+ if (!p->primary)
+ return;
+
+ ev.conn_id = conn_id;
+ element_id_to_hal_srvc_id(&p->id, 1, &ev.srvc_id);
+
+ uuid2android(&p->id.uuid, ev.srvc_id.uuid);
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_CLIENT_SEARCH_RESULT, sizeof(ev), &ev);
+}
+
+static struct service *create_service(uint8_t id, bool primary, char *uuid,
+ void *data)
+{
+ struct service *s;
+
+ s = new0(struct service, 1);
+ if (!s) {
+ error("gatt: Cannot allocate memory for gatt_primary");
+ return NULL;
+ }
+
+ s->chars = queue_new();
+ if (!s->chars) {
+ error("gatt: Cannot allocate memory for char cache");
+ free(s);
+ return NULL;
+ }
+
+ if (bt_string_to_uuid(&s->id.uuid, uuid) < 0) {
+ error("gatt: Cannot convert string to uuid");
+ queue_destroy(s->chars, NULL);
+ free(s);
+ return NULL;
+ }
+
+ s->id.instance = id;
+
+ /* Put primary service to our local list */
+ s->primary = primary;
+ if (s->primary) {
+ memcpy(&s->prim, data, sizeof(s->prim));
+ } else {
+ memcpy(&s->incl, data, sizeof(s->incl));
+ return s;
+ }
+
+ /* For primary service allocate queue for included services */
+ s->included = queue_new();
+ if (!s->included) {
+ queue_destroy(s->chars, NULL);
+ free(s);
+ return NULL;
+ }
+
+ return s;
+}
+
static void handle_client_scan(const void *buf, uint16_t len)
{
const struct hal_cmd_gatt_client_scan *cmd = buf;
@@ -1315,19 +1364,6 @@ reply:
status);
}
-static int connect_next_dev(void)
-{
- struct gatt_device *dev;
-
- DBG("");
-
- dev = find_device_by_state(DEVICE_CONNECT_READY);
- if (!dev)
- return -ENODEV;
-
- return connect_le(dev);
-}
-
static void bt_le_discovery_stop_cb(void)
{
DBG("");
@@ -1337,39 +1373,6 @@ static void bt_le_discovery_stop_cb(void)
bt_le_discovery_start();
}
-static struct gatt_device *create_device(const bdaddr_t *addr)
-{
- struct gatt_device *dev;
-
- dev = new0(struct gatt_device, 1);
- if (!dev)
- return NULL;
-
- bacpy(&dev->bdaddr, addr);
-
- dev->services = queue_new();
- if (!dev->services) {
- error("gatt: Failed to allocate memory for client");
- destroy_device(dev);
- return NULL;
- }
-
- dev->pending_requests = queue_new();
- if (!dev->pending_requests) {
- error("gatt: Failed to allocate memory for client");
- destroy_device(dev);
- return NULL;
- }
-
- if (!queue_push_head(gatt_devices, dev)) {
- error("gatt: Cannot push device to queue");
- destroy_device(dev);
- return NULL;
- }
-
- return device_ref(dev);
-}
-
static struct app_connection *create_connection(struct gatt_device *device,
struct gatt_app *app)
{
--
1.9.3
From: Luiz Augusto von Dentz <[email protected]>
---
android/bluetooth.c | 13 +++++++++++++
android/bluetooth.h | 1 +
2 files changed, 14 insertions(+)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 834d687..f8e9181 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -1409,6 +1409,19 @@ bool bt_device_is_bonded(const bdaddr_t *bdaddr)
return false;
}
+bool bt_device_set_uuids(const bdaddr_t *addr, GSList *uuids)
+{
+ struct device *dev;
+
+ dev = find_device(addr);
+ if (!dev)
+ return false;
+
+ set_device_uuids(dev, uuids);
+
+ return true;
+}
+
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 7c64bab..eb50fe1 100644
--- a/android/bluetooth.h
+++ b/android/bluetooth.h
@@ -61,6 +61,7 @@ bool bt_is_device_le(const bdaddr_t *addr);
const char *bt_get_adapter_name(void);
bool bt_device_is_bonded(const bdaddr_t *bdaddr);
+bool bt_device_set_uuids(const bdaddr_t *bdaddr, GSList *uuids);
typedef void (*bt_read_device_rssi_done)(uint8_t status, const bdaddr_t *addr,
int8_t rssi, void *user_data);
--
1.9.3
From: Luiz Augusto von Dentz <[email protected]>
If scanning is not set the discovery might have been initiated by another
HAL so do not stop it.
---
android/gatt.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/android/gatt.c b/android/gatt.c
index f797e7d..8a8419c 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -661,6 +661,11 @@ connect:
device_set_state(dev, DEVICE_CONNECT_READY);
dev->bdaddr_type = addr_type;
+ if (!scanning) {
+ connect_next_dev();
+ return;
+ }
+
/*
* We are ok to perform connect now. Stop discovery
* and once it is stopped continue with creating ACL
--
1.9.3
From: Luiz Augusto von Dentz <[email protected]>
This is necessary so that devices found during regular discovery can be
handled by gatt HAL.
---
android/bluetooth.c | 42 ++++++++++++++-------
android/bluetooth.h | 5 ++-
android/gatt.c | 105 ++++++++++++++++++++++++++++++----------------------
3 files changed, 92 insertions(+), 60 deletions(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index d275297..834d687 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -179,6 +179,7 @@ static struct {
uint32_t current_settings;
uint32_t supported_settings;
+ bool le_scanning;
uint8_t cur_discovery_type;
uint8_t exp_discovery_type;
uint32_t discoverable_timeout;
@@ -1301,10 +1302,8 @@ static void mgmt_discovering_event(uint16_t index, uint16_t length,
}
type = adapter.exp_discovery_type;
- adapter.exp_discovery_type = SCAN_TYPE_NONE;
-
- if (type == SCAN_TYPE_NONE && gatt_device_found_cb)
- type = SCAN_TYPE_LE;
+ adapter.exp_discovery_type = adapter.le_scanning ? SCAN_TYPE_LE :
+ SCAN_TYPE_NONE;
if (type != SCAN_TYPE_NONE)
start_discovery(type);
@@ -3392,42 +3391,57 @@ bool bt_le_set_advertising(bool advertising, bt_le_set_advertising_done cb,
return false;
}
+bool bt_le_register(bt_le_device_found cb)
+{
+ if (gatt_device_found_cb)
+ return false;
+
+ gatt_device_found_cb = cb;
+
+ return true;
+}
+
+void bt_le_unregister(void)
+{
+ gatt_device_found_cb = NULL;
+}
+
bool bt_le_discovery_stop(bt_le_discovery_stopped cb)
{
+ if (!(adapter.current_settings & MGMT_SETTING_POWERED))
+ return false;
+
+ adapter.le_scanning = false;
+
if (adapter.cur_discovery_type != SCAN_TYPE_LE) {
if (cb)
cb();
- gatt_device_found_cb = NULL;
-
return true;
}
if (!stop_discovery(SCAN_TYPE_LE))
return false;
- gatt_device_found_cb = NULL;
gatt_discovery_stopped_cb = cb;
adapter.exp_discovery_type = SCAN_TYPE_NONE;
return true;
}
-bool bt_le_discovery_start(bt_le_device_found cb)
+bool bt_le_discovery_start(void)
{
if (!(adapter.current_settings & MGMT_SETTING_POWERED))
return false;
+ adapter.le_scanning = true;
+
/* If core is discovering, don't bother */
- if (adapter.cur_discovery_type != SCAN_TYPE_NONE) {
- gatt_device_found_cb = cb;
+ if (adapter.cur_discovery_type != SCAN_TYPE_NONE)
return true;
- }
- if (start_discovery(SCAN_TYPE_LE)) {
- gatt_device_found_cb = cb;
+ if (start_discovery(SCAN_TYPE_LE))
return true;
- }
return false;
}
diff --git a/android/bluetooth.h b/android/bluetooth.h
index 2409d46..7c64bab 100644
--- a/android/bluetooth.h
+++ b/android/bluetooth.h
@@ -44,7 +44,10 @@ typedef void (*bt_le_device_found)(const bdaddr_t *addr, uint8_t addr_type,
int rssi, uint16_t eir_len,
const void *eir, bool discoverable,
bool bonded);
-bool bt_le_discovery_start(bt_le_device_found cb);
+bool bt_le_register(bt_le_device_found cb);
+void bt_le_unregister(void);
+
+bool bt_le_discovery_start(void);
typedef void (*bt_le_discovery_stopped)(void);
bool bt_le_discovery_stop(bt_le_discovery_stopped cb);
diff --git a/android/gatt.c b/android/gatt.c
index c25aed4..f797e7d 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -627,6 +627,47 @@ static void destroy_gatt_app(void *data)
free(app);
}
+static void le_device_found_handler(const bdaddr_t *addr, uint8_t addr_type,
+ int rssi, uint16_t eir_len,
+ const void *eir,
+ bool discoverable, bool bonded)
+{
+ uint8_t buf[IPC_MTU];
+ struct hal_ev_gatt_client_scan_result *ev = (void *) buf;
+ struct gatt_device *dev;
+ char bda[18];
+
+ if (!scanning || (!discoverable && !bonded))
+ goto connect;
+
+ ba2str(addr, bda);
+ DBG("LE Device found: %s, rssi: %d, adv_data: %d", bda, rssi, !!eir);
+
+ bdaddr2android(addr, ev->bda);
+ ev->rssi = rssi;
+ ev->len = eir_len;
+
+ memcpy(ev->adv_data, eir, ev->len);
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_CLIENT_SCAN_RESULT,
+ sizeof(*ev) + ev->len, ev);
+
+connect:
+ dev = find_device_by_addr(addr);
+ if (!dev || (dev->state != DEVICE_CONNECT_INIT))
+ return;
+
+ device_set_state(dev, DEVICE_CONNECT_READY);
+ dev->bdaddr_type = addr_type;
+
+ /*
+ * We are ok to perform connect now. Stop discovery
+ * and once it is stopped continue with creating ACL
+ */
+ bt_le_discovery_stop(bt_le_discovery_stop_cb);
+}
+
static struct gatt_app *register_app(const uint8_t *uuid, gatt_type_t type)
{
static int32_t application_id = 1;
@@ -637,6 +678,10 @@ static struct gatt_app *register_app(const uint8_t *uuid, gatt_type_t type)
return NULL;
}
+ /* Register LE once the first app register */
+ if (queue_isempty(gatt_apps))
+ bt_le_register(le_device_found_handler);
+
app = new0(struct gatt_app, 1);
if (!app) {
error("gatt: Cannot allocate memory for registering app");
@@ -956,47 +1001,6 @@ static struct service *create_service(uint8_t id, bool primary, char *uuid,
return s;
}
-static void le_device_found_handler(const bdaddr_t *addr, uint8_t addr_type,
- int rssi, uint16_t eir_len,
- const void *eir,
- bool discoverable, bool bonded)
-{
- uint8_t buf[IPC_MTU];
- struct hal_ev_gatt_client_scan_result *ev = (void *) buf;
- struct gatt_device *dev;
- char bda[18];
-
- if (!scanning || (!discoverable && !bonded))
- goto connect;
-
- ba2str(addr, bda);
- DBG("LE Device found: %s, rssi: %d, adv_data: %d", bda, rssi, !!eir);
-
- bdaddr2android(addr, ev->bda);
- ev->rssi = rssi;
- ev->len = eir_len;
-
- memcpy(ev->adv_data, eir, ev->len);
-
- ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_EV_GATT_CLIENT_SCAN_RESULT,
- sizeof(*ev) + ev->len, ev);
-
-connect:
- dev = find_device_by_addr(addr);
- if (!dev || (dev->state != DEVICE_CONNECT_INIT))
- return;
-
- device_set_state(dev, DEVICE_CONNECT_READY);
- dev->bdaddr_type = addr_type;
-
- /*
- * We are ok to perform connect now. Stop discovery
- * and once it is stopped continue with creating ACL
- */
- bt_le_discovery_stop(bt_le_discovery_stop_cb);
-}
-
static gboolean disconnected_cb(GIOChannel *io, GIOCondition cond,
gpointer user_data)
{
@@ -1207,7 +1211,7 @@ reply:
/* Check if we should restart scan */
if (scanning)
- bt_le_discovery_start(le_device_found_handler);
+ bt_le_discovery_start();
/* FIXME: What to do if discovery won't start here. */
}
@@ -1293,7 +1297,7 @@ static void handle_client_scan(const void *buf, uint16_t len)
}
/* Turn on scan */
- if (!bt_le_discovery_start(le_device_found_handler)) {
+ if (!bt_le_discovery_start()) {
error("gatt: LE scan switch failed");
status = HAL_STATUS_FAILED;
goto reply;
@@ -1325,7 +1329,7 @@ static void bt_le_discovery_stop_cb(void)
/* Check now if there is any device ready to connect */
if (connect_next_dev() < 0)
- bt_le_discovery_start(le_device_found_handler);
+ bt_le_discovery_start();
}
static struct gatt_device *create_device(const bdaddr_t *addr)
@@ -1434,7 +1438,7 @@ static bool trigger_connection(struct app_connection *connection)
/* after state change trigger discovering */
if (!scanning && (connection->device->state == DEVICE_CONNECT_INIT))
- if (!bt_le_discovery_start(le_device_found_handler)) {
+ if (!bt_le_discovery_start()) {
error("gatt: Could not start scan");
return false;
@@ -5917,6 +5921,15 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
if (!start_listening_io())
return false;
+ if (!bt_le_register(le_device_found_handler)) {
+ error("gatt: bt_le_register failed");
+
+ g_io_channel_unref(listening_io);
+ listening_io = NULL;
+
+ return false;
+ }
+
crypto = bt_crypto_new();
if (!crypto) {
error("gatt: Failed to setup crypto");
@@ -6001,6 +6014,8 @@ void bt_gatt_unregister(void)
bt_crypto_unref(crypto);
crypto = NULL;
+
+ bt_le_unregister();
}
--
1.9.3
From: Luiz Augusto von Dentz <[email protected]>
This enables using hidhost HAL for LE devices since this is how HoG is
implemented in Android.
---
android/hidhost.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 106 insertions(+)
diff --git a/android/hidhost.c b/android/hidhost.c
index 4a158c6..90a3409 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -48,6 +48,9 @@
#include "hal-msg.h"
#include "ipc-common.h"
#include "ipc.h"
+#include "bluetooth.h"
+#include "gatt.h"
+#include "hog.h"
#include "hidhost.h"
#include "utils.h"
@@ -77,11 +80,14 @@
/* HID Virtual Cable Unplug */
#define HID_VIRTUAL_CABLE_UNPLUG 0x05
+#define HOG_UUID "00001812-0000-1000-8000-00805f9b34fb"
+
static bdaddr_t adapter_addr;
static GIOChannel *ctrl_io = NULL;
static GIOChannel *intr_io = NULL;
static GSList *devices = NULL;
+static unsigned int hog_app = 0;
static struct ipc *hal_ipc = NULL;
@@ -102,6 +108,7 @@ struct hid_device {
guint intr_watch;
struct bt_uhid *uhid;
uint8_t last_hid_msg;
+ struct bt_hog *hog;
};
static int device_cmp(gconstpointer s, gconstpointer user_data)
@@ -131,6 +138,9 @@ static void hid_device_free(void *data)
if (dev->uhid)
bt_uhid_unref(dev->uhid);
+ if (dev->hog)
+ bt_hog_unref(dev->hog);
+
g_free(dev->rd_data);
g_free(dev);
}
@@ -722,6 +732,67 @@ fail:
hid_device_remove(dev);
}
+static void hog_conn_cb(const bdaddr_t *addr, int err, void *attrib)
+{
+ GSList *l;
+ struct hid_device *dev;
+
+ l = g_slist_find_custom(devices, addr, device_cmp);
+ dev = l ? l->data : NULL;
+
+ if (err < 0) {
+ if (!dev)
+ return;
+ goto fail;
+ }
+
+ if (!dev) {
+ dev = g_new0(struct hid_device, 1);
+ bacpy(&dev->dst, addr);
+ devices = g_slist_append(devices, dev);
+ bt_hid_notify_state(dev, HAL_HIDHOST_STATE_CONNECTING);
+ }
+
+ if (!dev->hog) {
+ /* TODO: Get device details and primary */
+ dev->hog = bt_hog_new("bluez-input-device", dev->vendor,
+ dev->product, dev->version, NULL);
+ if (!dev->hog) {
+ error("HoG: unable to create session");
+ goto fail;
+ }
+ }
+
+ if (!bt_hog_attach(dev->hog, attrib)) {
+ error("HoG: unable to attach");
+ goto fail;
+ }
+
+ bt_hid_notify_state(dev, HAL_HIDHOST_STATE_CONNECTED);
+
+ return;
+
+fail:
+ bt_hid_notify_state(dev, HAL_HIDHOST_STATE_DISCONNECTED);
+ hid_device_remove(dev);
+}
+
+static bool hog_connect(struct hid_device *dev)
+{
+ DBG("");
+
+ if (hog_app)
+ return bt_gatt_connect_app(hog_app, &dev->dst);
+
+ hog_app = bt_gatt_register_app(HOG_UUID, GATT_CLIENT, hog_conn_cb);
+ if (!hog_app) {
+ error("hidhost: bt_gatt_register_app failed");
+ return false;
+ }
+
+ return bt_gatt_connect_app(hog_app, &dev->dst);
+}
+
static void bt_hid_connect(const void *buf, uint16_t len)
{
const struct hal_cmd_hidhost_connect *cmd = buf;
@@ -748,6 +819,14 @@ static void bt_hid_connect(const void *buf, uint16_t len)
ba2str(&dev->dst, addr);
DBG("connecting to %s", addr);
+ if (bt_is_device_le(&dst)) {
+ if (!hog_connect(dev)) {
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+ goto done;
+ }
+
sdp_uuid16_create(&uuid, PNP_INFO_SVCLASS_ID);
if (bt_search_service(&adapter_addr, &dev->dst, &uuid,
hid_sdp_did_search_cb, dev, NULL, 0) < 0) {
@@ -757,6 +836,7 @@ static void bt_hid_connect(const void *buf, uint16_t len)
goto failed;
}
+done:
devices = g_slist_append(devices, dev);
bt_hid_notify_state(dev, HAL_HIDHOST_STATE_CONNECTING);
@@ -767,6 +847,20 @@ failed:
status);
}
+static bool hog_disconnect(struct hid_device *dev)
+{
+ DBG("");
+
+ bt_hid_notify_state(dev, HAL_HIDHOST_STATE_DISCONNECTING);
+
+ if (!bt_gatt_disconnect_app(hog_app, &dev->dst)) {
+ bt_hid_notify_state(dev, HAL_HIDHOST_STATE_DISCONNECTED);
+ hid_device_remove(dev);
+ }
+
+ return true;
+}
+
static void bt_hid_disconnect(const void *buf, uint16_t len)
{
const struct hal_cmd_hidhost_disconnect *cmd = buf;
@@ -786,6 +880,13 @@ static void bt_hid_disconnect(const void *buf, uint16_t len)
}
dev = l->data;
+ if (bt_is_device_le(&dst)) {
+ if (!hog_disconnect(dev)) {
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+ goto done;
+ }
/* Wait either channels to HUP */
if (dev->intr_io)
@@ -796,6 +897,8 @@ static void bt_hid_disconnect(const void *buf, uint16_t len)
bt_hid_notify_state(dev, HAL_HIDHOST_STATE_DISCONNECTING);
+
+done:
status = HAL_STATUS_SUCCESS;
failed:
@@ -1342,6 +1445,9 @@ void bt_hid_unregister(void)
{
DBG("");
+ if (hog_app > 0)
+ bt_gatt_unregister_app(hog_app);
+
g_slist_free_full(devices, hid_device_free);
devices = NULL;
--
1.9.3
From: Luiz Augusto von Dentz <[email protected]>
This strip any dependecy from input plugin so the code can be used by
hidhost interface.
---
android/Android.mk | 1 +
android/Makefile.am | 1 +
android/hog.c | 448 ++++++++++++++++---------------------------
android/{sco-msg.h => hog.h} | 17 +-
4 files changed, 171 insertions(+), 296 deletions(-)
copy android/{sco-msg.h => hog.h} (70%)
diff --git a/android/Android.mk b/android/Android.mk
index a9a0982..45a9af7 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -32,6 +32,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
bluez/android/main.c \
bluez/android/bluetooth.c \
+ bluez/android/hog.c \
bluez/android/hidhost.c \
bluez/android/socket.c \
bluez/android/ipc.c \
diff --git a/android/Makefile.am b/android/Makefile.am
index 3e48ddc..0414c90 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -35,6 +35,7 @@ android_bluetoothd_SOURCES = android/main.c \
src/shared/uhid.h src/shared/uhid.c \
android/bluetooth.h android/bluetooth.c \
android/hidhost.h android/hidhost.c \
+ android/hog.h android/hog.c \
android/ipc-common.h \
android/ipc.h android/ipc.c \
android/avdtp.h android/avdtp.c \
diff --git a/android/hog.c b/android/hog.c
index 3753343..bfb9c17 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -2,6 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
+ * Copyright (C) 2014 Intel Corporation.
* Copyright (C) 2012 Marcel Holtmann <[email protected]>
* Copyright (C) 2012 Nordic Semiconductor Inc.
* Copyright (C) 2012 Instituto Nokia de Tecnologia - INdT
@@ -42,21 +43,17 @@
#include "src/log.h"
#include "lib/uuid.h"
-#include "src/adapter.h"
-#include "src/device.h"
-#include "src/profile.h"
-#include "src/service.h"
#include "src/shared/util.h"
#include "src/shared/uhid.h"
-#include "src/plugin.h"
-
-#include "suspend.h"
#include "attrib/att.h"
#include "attrib/gattrib.h"
-#include "src/attio.h"
#include "attrib/gatt.h"
+#include "btio/btio.h"
+
+#include "android/hog.h"
+
#define HOG_UUID "00001812-0000-1000-8000-00805f9b34fb"
#define HOG_INFO_UUID 0x2A4A
@@ -76,12 +73,14 @@
#define HID_INFO_SIZE 4
#define ATT_NOTIFICATION_HEADER_SIZE 3
-struct hog_device {
- uint16_t id;
- struct btd_device *device;
+struct bt_hog {
+ int ref_count;
+ char *name;
+ uint16_t vendor;
+ uint16_t product;
+ uint16_t version;
+ struct gatt_primary *primary;
GAttrib *attrib;
- guint attioid;
- struct gatt_primary *hog_primary;
GSList *reports;
struct bt_uhid *uhid;
gboolean has_report_id;
@@ -93,20 +92,17 @@ struct hog_device {
};
struct report {
+ struct bt_hog *hog;
uint8_t id;
uint8_t type;
guint notifyid;
struct gatt_char *decl;
- struct hog_device *hogdev;
};
-static gboolean suspend_supported = FALSE;
-static GSList *devices = NULL;
-
static void report_value_cb(const guint8 *pdu, guint16 len, gpointer user_data)
{
struct report *report = user_data;
- struct hog_device *hogdev = report->hogdev;
+ struct bt_hog *hog = report->hog;
struct uhid_event ev;
uint8_t *buf;
int err;
@@ -123,7 +119,7 @@ static void report_value_cb(const guint8 *pdu, guint16 len, gpointer user_data)
ev.type = UHID_INPUT;
buf = ev.u.input.data;
- if (hogdev->has_report_id) {
+ if (hog->has_report_id) {
buf[0] = report->id;
len = MIN(len, sizeof(ev.u.input.data) - 1);
memcpy(buf + 1, pdu, len);
@@ -134,7 +130,7 @@ static void report_value_cb(const guint8 *pdu, guint16 len, gpointer user_data)
ev.u.input.size = len;
}
- err = bt_uhid_send(hogdev->uhid, &ev);
+ err = bt_uhid_send(hog->uhid, &ev);
if (err < 0) {
error("bt_uhid_send: %s (%d)", strerror(-err), -err);
return;
@@ -147,7 +143,7 @@ static void report_ccc_written_cb(guint8 status, const guint8 *pdu,
guint16 plen, gpointer user_data)
{
struct report *report = user_data;
- struct hog_device *hogdev = report->hogdev;
+ struct bt_hog *hog = report->hog;
if (status != 0) {
error("Write report characteristic descriptor failed: %s",
@@ -155,7 +151,7 @@ static void report_ccc_written_cb(guint8 status, const guint8 *pdu,
return;
}
- report->notifyid = g_attrib_register(hogdev->attrib,
+ report->notifyid = g_attrib_register(hog->attrib,
ATT_OP_HANDLE_NOTIFY,
report->decl->value_handle,
report_value_cb, report, NULL);
@@ -166,10 +162,10 @@ static void report_ccc_written_cb(guint8 status, const guint8 *pdu,
static void write_ccc(uint16_t handle, gpointer user_data)
{
struct report *report = user_data;
- struct hog_device *hogdev = report->hogdev;
+ struct bt_hog *hog = report->hog;
uint8_t value[] = { 0x01, 0x00 };
- gatt_write_char(hogdev->attrib, handle, value, sizeof(value),
+ gatt_write_char(hog->attrib, handle, value, sizeof(value),
report_ccc_written_cb, report);
}
@@ -202,7 +198,7 @@ static void discover_descriptor_cb(uint8_t status, GSList *descs,
void *user_data)
{
struct report *report;
- struct hog_device *hogdev;
+ struct bt_hog *hog;
GAttrib *attrib = NULL;
if (status != 0) {
@@ -217,20 +213,20 @@ static void discover_descriptor_cb(uint8_t status, GSList *descs,
switch (desc->uuid16) {
case GATT_CLIENT_CHARAC_CFG_UUID:
report = user_data;
- attrib = report->hogdev->attrib;
+ attrib = report->hog->attrib;
write_ccc(desc->handle, report);
break;
case GATT_REPORT_REFERENCE:
report = user_data;
- attrib = report->hogdev->attrib;
+ attrib = report->hog->attrib;
gatt_read_char(attrib, desc->handle,
report_reference_cb, report);
break;
case GATT_EXTERNAL_REPORT_REFERENCE:
- hogdev = user_data;
- attrib = hogdev->attrib;
+ hog = user_data;
+ attrib = hog->attrib;
gatt_read_char(attrib, desc->handle,
- external_report_reference_cb, hogdev);
+ external_report_reference_cb, hog);
break;
}
}
@@ -249,8 +245,8 @@ static void discover_descriptor(GAttrib *attrib, uint16_t start, uint16_t end,
static void external_service_char_cb(uint8_t status, GSList *chars,
void *user_data)
{
- struct hog_device *hogdev = user_data;
- struct gatt_primary *prim = hogdev->hog_primary;
+ struct bt_hog *hog = user_data;
+ struct gatt_primary *primary = hog->primary;
struct report *report;
GSList *l;
@@ -271,19 +267,19 @@ static void external_service_char_cb(uint8_t status, GSList *chars,
chr->handle, chr->uuid, chr->properties);
report = g_new0(struct report, 1);
- report->hogdev = hogdev;
+ report->hog = hog;
report->decl = g_memdup(chr, sizeof(*chr));
- hogdev->reports = g_slist_append(hogdev->reports, report);
+ hog->reports = g_slist_append(hog->reports, report);
start = chr->value_handle + 1;
- end = (next ? next->handle - 1 : prim->range.end);
- discover_descriptor(hogdev->attrib, start, end, report);
+ end = (next ? next->handle - 1 : primary->range.end);
+ discover_descriptor(hog->attrib, start, end, report);
}
}
static void external_report_reference_cb(guint8 status, const guint8 *pdu,
guint16 plen, gpointer user_data)
{
- struct hog_device *hogdev = user_data;
+ struct bt_hog *hog = user_data;
uint16_t uuid16;
bt_uuid_t uuid;
@@ -302,8 +298,8 @@ static void external_report_reference_cb(guint8 status, const guint8 *pdu,
DBG("External report reference read, external report characteristic "
"UUID: 0x%04x", uuid16);
bt_uuid16_create(&uuid, uuid16);
- gatt_discover_char(hogdev->attrib, 0x00, 0xff, &uuid,
- external_service_char_cb, hogdev);
+ gatt_discover_char(hog->attrib, 0x00, 0xff, &uuid,
+ external_service_char_cb, hog);
}
static int report_type_cmp(gconstpointer a, gconstpointer b)
@@ -325,14 +321,14 @@ static void output_written_cb(guint8 status, const guint8 *pdu,
static void forward_report(struct uhid_event *ev, void *user_data)
{
- struct hog_device *hogdev = user_data;
+ struct bt_hog *hog = user_data;
struct report *report;
GSList *l;
void *data;
int size;
guint type;
- if (hogdev->has_report_id) {
+ if (hog->has_report_id) {
data = ev->u.output.data + 1;
size = ev->u.output.size - 1;
} else {
@@ -351,24 +347,24 @@ static void forward_report(struct uhid_event *ev, void *user_data)
return;
}
- l = g_slist_find_custom(hogdev->reports, GUINT_TO_POINTER(type),
+ l = g_slist_find_custom(hog->reports, GUINT_TO_POINTER(type),
report_type_cmp);
if (!l)
return;
report = l->data;
- DBG("Sending report type %d to device 0x%04X handle 0x%X", type,
- hogdev->id, report->decl->value_handle);
+ DBG("Sending report type %d to handle 0x%X", type,
+ report->decl->value_handle);
- if (hogdev->attrib == NULL)
+ if (hog->attrib == NULL)
return;
if (report->decl->properties & GATT_CHR_PROP_WRITE)
- gatt_write_char(hogdev->attrib, report->decl->value_handle,
- data, size, output_written_cb, hogdev);
+ gatt_write_char(hog->attrib, report->decl->value_handle,
+ data, size, output_written_cb, hog);
else if (report->decl->properties & GATT_CHR_PROP_WRITE_WITHOUT_RESP)
- gatt_write_cmd(hogdev->attrib, report->decl->value_handle,
+ gatt_write_cmd(hog->attrib, report->decl->value_handle,
data, size, NULL, NULL);
}
@@ -437,14 +433,13 @@ static char *item2string(char *str, uint8_t *buf, uint8_t len)
static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
gpointer user_data)
{
- struct hog_device *hogdev = user_data;
- struct btd_adapter *adapter = device_get_adapter(hogdev->device);
+ struct bt_hog *hog = user_data;
uint8_t value[HOG_REPORT_MAP_MAX_SIZE];
struct uhid_event ev;
- uint16_t vendor_src, vendor, product, version;
ssize_t vlen;
char itemstr[20]; /* 5x3 (data) + 4 (continuation) + 1 (null) */
int i, err;
+ GError *gerr = NULL;
if (status != 0) {
error("Report Map read failed: %s", att_ecode2str(status));
@@ -466,7 +461,7 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
&long_item)) {
/* Report ID is short item with prefix 100001xx */
if (!long_item && (value[i] & 0xfc) == 0x84)
- hogdev->has_report_id = TRUE;
+ hog->has_report_id = TRUE;
DBG("\t%s", item2string(itemstr, &value[i], ilen));
@@ -480,45 +475,43 @@ static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
}
}
- vendor_src = btd_device_get_vendor_src(hogdev->device);
- vendor = btd_device_get_vendor(hogdev->device);
- product = btd_device_get_product(hogdev->device);
- version = btd_device_get_version(hogdev->device);
- DBG("DIS information: vendor_src=0x%X, vendor=0x%X, product=0x%X, "
- "version=0x%X", vendor_src, vendor, product, version);
-
/* create uHID device */
memset(&ev, 0, sizeof(ev));
ev.type = UHID_CREATE;
- if (device_name_known(hogdev->device))
- device_get_name(hogdev->device, (char *) ev.u.create.name,
- sizeof(ev.u.create.name));
- else
- strcpy((char *) ev.u.create.name, "bluez-hog-device");
- ba2str(btd_adapter_get_address(adapter), (char *) ev.u.create.phys);
- ba2str(device_get_address(hogdev->device), (char *) ev.u.create.uniq);
- ev.u.create.vendor = vendor;
- ev.u.create.product = product;
- ev.u.create.version = version;
- ev.u.create.country = hogdev->bcountrycode;
+
+ bt_io_get(g_attrib_get_channel(hog->attrib), &gerr,
+ BT_IO_OPT_SOURCE, ev.u.create.phys,
+ BT_IO_OPT_DEST, ev.u.create.uniq,
+ BT_IO_OPT_INVALID);
+ if (gerr) {
+ error("Failed to connection details: %s", gerr->message);
+ g_error_free(gerr);
+ return;
+ }
+
+ strcpy((char *) ev.u.create.name, hog->name);
+ ev.u.create.vendor = hog->vendor;
+ ev.u.create.product = hog->product;
+ ev.u.create.version = hog->version;
+ ev.u.create.country = hog->bcountrycode;
ev.u.create.bus = BUS_BLUETOOTH;
ev.u.create.rd_data = value;
ev.u.create.rd_size = vlen;
- err = bt_uhid_send(hogdev->uhid, &ev);
+ err = bt_uhid_send(hog->uhid, &ev);
if (err < 0) {
error("bt_uhid_send: %s", strerror(-err));
return;
}
- bt_uhid_register(hogdev->uhid, UHID_OUTPUT, forward_report, hogdev);
- bt_uhid_register(hogdev->uhid, UHID_FEATURE, forward_report, hogdev);
+ bt_uhid_register(hog->uhid, UHID_OUTPUT, forward_report, hog);
+ bt_uhid_register(hog->uhid, UHID_FEATURE, forward_report, hog);
}
static void info_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
gpointer user_data)
{
- struct hog_device *hogdev = user_data;
+ struct bt_hog *hog = user_data;
uint8_t value[HID_INFO_SIZE];
ssize_t vlen;
@@ -534,18 +527,18 @@ static void info_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
return;
}
- hogdev->bcdhid = get_le16(&value[0]);
- hogdev->bcountrycode = value[2];
- hogdev->flags = value[3];
+ hog->bcdhid = get_le16(&value[0]);
+ hog->bcountrycode = value[2];
+ hog->flags = value[3];
DBG("bcdHID: 0x%04X bCountryCode: 0x%02X Flags: 0x%02X",
- hogdev->bcdhid, hogdev->bcountrycode, hogdev->flags);
+ hog->bcdhid, hog->bcountrycode, hog->flags);
}
static void proto_mode_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
gpointer user_data)
{
- struct hog_device *hogdev = user_data;
+ struct bt_hog *hog = user_data;
uint8_t value;
ssize_t vlen;
@@ -564,20 +557,18 @@ static void proto_mode_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
if (value == HOG_PROTO_MODE_BOOT) {
uint8_t nval = HOG_PROTO_MODE_REPORT;
- DBG("HoG device 0x%04X is operating in Boot Procotol Mode",
- hogdev->id);
+ DBG("HoG is operating in Boot Procotol Mode");
- gatt_write_cmd(hogdev->attrib, hogdev->proto_mode_handle, &nval,
+ gatt_write_cmd(hog->attrib, hog->proto_mode_handle, &nval,
sizeof(nval), NULL, NULL);
} else if (value == HOG_PROTO_MODE_REPORT)
- DBG("HoG device 0x%04X is operating in Report Protocol Mode",
- hogdev->id);
+ DBG("HoG is operating in Report Protocol Mode");
}
static void char_discovered_cb(uint8_t status, GSList *chars, void *user_data)
{
- struct hog_device *hogdev = user_data;
- struct gatt_primary *prim = hogdev->hog_primary;
+ struct bt_hog *hog = user_data;
+ struct gatt_primary *primary = hog->primary;
bt_uuid_t report_uuid, report_map_uuid, info_uuid;
bt_uuid_t proto_mode_uuid, ctrlpt_uuid;
struct report *report;
@@ -610,277 +601,160 @@ static void char_discovered_cb(uint8_t status, GSList *chars, void *user_data)
bt_string_to_uuid(&uuid, chr->uuid);
start = chr->value_handle + 1;
- end = (next ? next->handle - 1 : prim->range.end);
+ end = (next ? next->handle - 1 : primary->range.end);
if (bt_uuid_cmp(&uuid, &report_uuid) == 0) {
report = g_new0(struct report, 1);
- report->hogdev = hogdev;
+ report->hog = hog;
report->decl = g_memdup(chr, sizeof(*chr));
- hogdev->reports = g_slist_append(hogdev->reports,
+ hog->reports = g_slist_append(hog->reports,
report);
- discover_descriptor(hogdev->attrib, start, end, report);
+ discover_descriptor(hog->attrib, start, end, report);
} else if (bt_uuid_cmp(&uuid, &report_map_uuid) == 0) {
- gatt_read_char(hogdev->attrib, chr->value_handle,
- report_map_read_cb, hogdev);
- discover_descriptor(hogdev->attrib, start, end, hogdev);
+ gatt_read_char(hog->attrib, chr->value_handle,
+ report_map_read_cb, hog);
+ discover_descriptor(hog->attrib, start, end, hog);
} else if (bt_uuid_cmp(&uuid, &info_uuid) == 0)
info_handle = chr->value_handle;
else if (bt_uuid_cmp(&uuid, &proto_mode_uuid) == 0)
proto_mode_handle = chr->value_handle;
else if (bt_uuid_cmp(&uuid, &ctrlpt_uuid) == 0)
- hogdev->ctrlpt_handle = chr->value_handle;
+ hog->ctrlpt_handle = chr->value_handle;
}
if (proto_mode_handle) {
- hogdev->proto_mode_handle = proto_mode_handle;
- gatt_read_char(hogdev->attrib, proto_mode_handle,
- proto_mode_read_cb, hogdev);
+ hog->proto_mode_handle = proto_mode_handle;
+ gatt_read_char(hog->attrib, proto_mode_handle,
+ proto_mode_read_cb, hog);
}
if (info_handle)
- gatt_read_char(hogdev->attrib, info_handle, info_read_cb,
- hogdev);
-}
-
-static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
-{
- struct hog_device *hogdev = user_data;
- struct gatt_primary *prim = hogdev->hog_primary;
- GSList *l;
-
- DBG("HoG connected");
-
- hogdev->attrib = g_attrib_ref(attrib);
-
- if (hogdev->reports == NULL) {
- gatt_discover_char(hogdev->attrib, prim->range.start,
- prim->range.end, NULL,
- char_discovered_cb, hogdev);
- return;
- }
-
- for (l = hogdev->reports; l; l = l->next) {
- struct report *r = l->data;
-
- r->notifyid = g_attrib_register(hogdev->attrib,
- ATT_OP_HANDLE_NOTIFY,
- r->decl->value_handle,
- report_value_cb, r, NULL);
- }
-}
-
-static void attio_disconnected_cb(gpointer user_data)
-{
- struct hog_device *hogdev = user_data;
- GSList *l;
-
- DBG("HoG disconnected");
-
- for (l = hogdev->reports; l; l = l->next) {
- struct report *r = l->data;
-
- g_attrib_unregister(hogdev->attrib, r->notifyid);
- }
-
- g_attrib_unref(hogdev->attrib);
- hogdev->attrib = NULL;
-}
-
-static struct hog_device *hog_new_device(struct btd_device *device,
- uint16_t id)
-{
- struct hog_device *hogdev;
-
- hogdev = g_try_new0(struct hog_device, 1);
- if (!hogdev)
- return NULL;
-
- hogdev->id = id;
- hogdev->device = btd_device_ref(device);
-
- return hogdev;
+ gatt_read_char(hog->attrib, info_handle, info_read_cb,
+ hog);
}
static void report_free(void *data)
{
struct report *report = data;
- struct hog_device *hogdev = report->hogdev;
+ struct bt_hog *hog = report->hog;
- if (hogdev->attrib)
- g_attrib_unregister(hogdev->attrib, report->notifyid);
+ if (hog->attrib)
+ g_attrib_unregister(hog->attrib, report->notifyid);
g_free(report->decl);
g_free(report);
}
-static void hog_free_device(struct hog_device *hogdev)
+static void hog_free(struct bt_hog *hog)
{
- btd_device_unref(hogdev->device);
- g_slist_free_full(hogdev->reports, report_free);
- g_attrib_unref(hogdev->attrib);
- g_free(hogdev->hog_primary);
- g_free(hogdev);
+ bt_uhid_unref(hog->uhid);
+ g_slist_free_full(hog->reports, report_free);
+ g_attrib_unref(hog->attrib);
+ g_free(hog->name);
+ g_free(hog->primary);
+ g_free(hog);
}
-static struct hog_device *hog_register_device(struct btd_device *device,
- struct gatt_primary *prim)
+struct bt_hog *bt_hog_new(const char *name, uint16_t vendor, uint16_t product,
+ uint16_t version, void *primary)
{
- struct hog_device *hogdev;
+ struct bt_hog *hog;
- hogdev = hog_new_device(device, prim->range.start);
- if (!hogdev)
+ hog = g_try_new0(struct bt_hog, 1);
+ if (!hog)
return NULL;
- hogdev->uhid = bt_uhid_new_default();
- if (!hogdev->uhid) {
- error("bt_uhid_new_default: failed");
- hog_free_device(hogdev);
+ hog->uhid = bt_uhid_new_default();
+ if (!hog->uhid) {
+ hog_free(hog);
return NULL;
}
- hogdev->hog_primary = g_memdup(prim, sizeof(*prim));
-
- hogdev->attioid = btd_device_add_attio_callback(device,
- attio_connected_cb,
- attio_disconnected_cb,
- hogdev);
-
- return hogdev;
-}
-
-static int hog_unregister_device(struct hog_device *hogdev)
-{
- btd_device_remove_attio_callback(hogdev->device, hogdev->attioid);
- bt_uhid_unref(hogdev->uhid);
- hog_free_device(hogdev);
-
- return 0;
-}
-
-static int set_control_point(struct hog_device *hogdev, gboolean suspend)
-{
- uint8_t value = suspend ? 0x00 : 0x01;
-
- if (hogdev->attrib == NULL)
- return -ENOTCONN;
-
- DBG("0x%4X HID Control Point: %s", hogdev->id, suspend ?
- "Suspend" : "Exit Suspend");
-
- if (hogdev->ctrlpt_handle == 0)
- return -ENOTSUP;
-
- gatt_write_cmd(hogdev->attrib, hogdev->ctrlpt_handle, &value,
- sizeof(value), NULL, NULL);
+ hog->name = g_strdup(name);
+ hog->vendor = vendor;
+ hog->product = product;
+ hog->version = version;
+ hog->primary = g_memdup(primary, sizeof(*primary));
- return 0;
-}
-
-static void set_suspend(gpointer data, gpointer user_data)
-{
- struct hog_device *hogdev = data;
- gboolean suspend = GPOINTER_TO_INT(user_data);
-
- set_control_point(hogdev, suspend);
+ return bt_hog_ref(hog);
}
-static void suspend_callback(void)
+struct bt_hog *bt_hog_ref(struct bt_hog *hog)
{
- gboolean suspend = TRUE;
+ if (!hog)
+ return NULL;
- DBG("Suspending ...");
+ __sync_fetch_and_add(&hog->ref_count, 1);
- g_slist_foreach(devices, set_suspend, GINT_TO_POINTER(suspend));
+ return hog;
}
-static void resume_callback(void)
+void bt_hog_unref(struct bt_hog *hog)
{
- gboolean suspend = FALSE;
+ if (!hog)
+ return;
- DBG("Resuming ...");
+ if (__sync_sub_and_fetch(&hog->ref_count, 1))
+ return;
- g_slist_foreach(devices, set_suspend, GINT_TO_POINTER(suspend));
+ hog_free(hog);
}
-static int hog_probe(struct btd_service *service)
+bool bt_hog_attach(struct bt_hog *hog, void *gatt)
{
- struct btd_device *device = btd_service_get_device(service);
- const char *path = device_get_path(device);
- GSList *primaries, *l;
-
- DBG("path %s", path);
+ struct gatt_primary *primary = hog->primary;
+ GSList *l;
- primaries = btd_device_get_primaries(device);
- if (primaries == NULL)
- return -EINVAL;
+ if (hog->attrib)
+ return false;
- for (l = primaries; l; l = g_slist_next(l)) {
- struct gatt_primary *prim = l->data;
- struct hog_device *hogdev;
+ hog->attrib = g_attrib_ref(gatt);
- if (strcmp(prim->uuid, HOG_UUID) != 0)
- continue;
+ if (hog->reports == NULL) {
+ gatt_discover_char(hog->attrib, primary->range.start,
+ primary->range.end, NULL,
+ char_discovered_cb, hog);
+ return true;
+ }
- hogdev = hog_register_device(device, prim);
- if (hogdev == NULL)
- continue;
+ for (l = hog->reports; l; l = l->next) {
+ struct report *r = l->data;
- devices = g_slist_append(devices, hogdev);
+ r->notifyid = g_attrib_register(hog->attrib,
+ ATT_OP_HANDLE_NOTIFY,
+ r->decl->value_handle,
+ report_value_cb, r, NULL);
}
- return 0;
+ return true;
}
-static void remove_device(gpointer a, gpointer b)
+void bt_hog_detach(struct bt_hog *hog)
{
- struct hog_device *hogdev = a;
- struct btd_device *device = b;
-
- if (hogdev->device != device)
- return;
-
- devices = g_slist_remove(devices, hogdev);
- hog_unregister_device(hogdev);
-}
+ GSList *l;
-static void hog_remove(struct btd_service *service)
-{
- struct btd_device *device = btd_service_get_device(service);
- const char *path = device_get_path(device);
+ for (l = hog->reports; l; l = l->next) {
+ struct report *r = l->data;
- DBG("path %s", path);
+ g_attrib_unregister(hog->attrib, r->notifyid);
+ }
- g_slist_foreach(devices, remove_device, device);
+ g_attrib_unref(hog->attrib);
+ hog->attrib = NULL;
}
-static struct btd_profile hog_profile = {
- .name = "input-hog",
- .remote_uuid = HOG_UUID,
- .device_probe = hog_probe,
- .device_remove = hog_remove,
-};
-
-static int hog_init(void)
+int bt_hog_set_control_point(struct bt_hog *hog, bool suspend)
{
- int err;
+ uint8_t value = suspend ? 0x00 : 0x01;
- err = suspend_init(suspend_callback, resume_callback);
- if (err < 0)
- error("Loading suspend plugin failed: %s (%d)", strerror(-err),
- -err);
- else
- suspend_supported = TRUE;
+ if (hog->attrib == NULL)
+ return -ENOTCONN;
- return btd_profile_register(&hog_profile);
-}
+ if (hog->ctrlpt_handle == 0)
+ return -ENOTSUP;
-static void hog_exit(void)
-{
- if (suspend_supported)
- suspend_exit();
+ gatt_write_cmd(hog->attrib, hog->ctrlpt_handle, &value,
+ sizeof(value), NULL, NULL);
- btd_profile_unregister(&hog_profile);
+ return 0;
}
-
-BLUETOOTH_PLUGIN_DEFINE(hog, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
- hog_init, hog_exit)
diff --git a/android/sco-msg.h b/android/hog.h
similarity index 70%
copy from android/sco-msg.h
copy to android/hog.h
index df0d858..7cf446b 100644
--- a/android/sco-msg.h
+++ b/android/hog.h
@@ -21,16 +21,15 @@
*
*/
-static const char BLUEZ_SCO_SK_PATH[] = "\0bluez_sco_socket";
+struct bt_hog;
-#define SCO_SERVICE_ID 0
+struct bt_hog *bt_hog_new(const char *name, uint16_t vendor, uint16_t product,
+ uint16_t version, void *primary);
-#define SCO_STATUS_SUCCESS IPC_STATUS_SUCCESS
-#define SCO_STATUS_FAILED 0x01
+struct bt_hog *bt_hog_ref(struct bt_hog *hog);
+void bt_hog_unref(struct bt_hog *hog);
-#define SCO_OP_STATUS IPC_OP_STATUS
+bool bt_hog_attach(struct bt_hog *hog, void *gatt);
+void bt_hog_detach(struct bt_hog *hog);
-#define SCO_OP_CONNECT 0x01
-struct sco_rsp_connect {
- uint16_t mtu;
-} __attribute__((packed));
+int bt_hog_set_control_point(struct bt_hog *hog, bool suspend);
--
1.9.3
From: Luiz Augusto von Dentz <[email protected]>
This adds support to auto discover primary service stopping once HoG
UUID is found.
---
android/hog.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 99 insertions(+), 1 deletion(-)
diff --git a/android/hog.c b/android/hog.c
index bfb9c17..e929d7d 100644
--- a/android/hog.c
+++ b/android/hog.c
@@ -674,7 +674,9 @@ struct bt_hog *bt_hog_new(const char *name, uint16_t vendor, uint16_t product,
hog->vendor = vendor;
hog->product = product;
hog->version = version;
- hog->primary = g_memdup(primary, sizeof(*primary));
+
+ if (primary)
+ hog->primary = g_memdup(primary, sizeof(*hog->primary));
return bt_hog_ref(hog);
}
@@ -700,6 +702,97 @@ void bt_hog_unref(struct bt_hog *hog)
hog_free(hog);
}
+static void find_included_cb(uint8_t status, GSList *services, void *user_data)
+{
+ struct bt_hog *hog = user_data;
+ struct gatt_included *include;
+ GSList *l;
+
+ DBG("");
+
+ if (hog->primary)
+ return;
+
+ if (status) {
+ const char *str = att_ecode2str(status);
+ DBG("Find included failed: %s", str);
+ return;
+ }
+
+ if (!services) {
+ DBG("No included service found");
+ return;
+ }
+
+ for (l = services; l; l = l->next) {
+ include = l->data;
+
+ if (strcmp(include->uuid, HOG_UUID) == 0)
+ break;
+
+ gatt_find_included(hog->attrib, include->range.start,
+ include->range.end, find_included_cb, hog);
+ }
+
+ if (!l)
+ return;
+
+ hog->primary = g_new0(struct gatt_primary, 1);
+ memcpy(hog->primary->uuid, include->uuid, sizeof(include->uuid));
+ memcpy(&hog->primary->range, &include->range, sizeof(include->range));
+
+ gatt_discover_char(hog->attrib, hog->primary->range.start,
+ hog->primary->range.end, NULL,
+ char_discovered_cb, hog);
+}
+
+static void primary_cb(uint8_t status, GSList *services, void *user_data)
+{
+ struct bt_hog *hog = user_data;
+ struct gatt_primary *primary;
+ GSList *l;
+
+ DBG("");
+
+ if (status) {
+ const char *str = att_ecode2str(status);
+ DBG("Discover primary failed: %s", str);
+ return;
+ }
+
+ if (!services) {
+ DBG("No primary service found");
+ return;
+ }
+
+ for (l = services; l; l = l->next) {
+ primary = l->data;
+
+ if (strcmp(primary->uuid, HOG_UUID) == 0)
+ break;
+
+ gatt_find_included(hog->attrib, primary->range.start,
+ primary->range.end, find_included_cb, hog);
+ }
+
+ if (!l) {
+ for (l = services; l; l = l->next) {
+ primary = l->data;
+
+ gatt_find_included(hog->attrib, primary->range.start,
+ primary->range.end, find_included_cb,
+ hog);
+ }
+ return;
+ }
+
+ hog->primary = g_memdup(primary, sizeof(*primary));
+
+ gatt_discover_char(hog->attrib, hog->primary->range.start,
+ hog->primary->range.end, NULL,
+ char_discovered_cb, hog);
+}
+
bool bt_hog_attach(struct bt_hog *hog, void *gatt)
{
struct gatt_primary *primary = hog->primary;
@@ -710,6 +803,11 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt)
hog->attrib = g_attrib_ref(gatt);
+ if (!primary) {
+ gatt_discover_primary(hog->attrib, NULL, primary_cb, hog);
+ return true;
+ }
+
if (hog->reports == NULL) {
gatt_discover_char(hog->attrib, primary->range.start,
primary->range.end, NULL,
--
1.9.3
From: Luiz Augusto von Dentz <[email protected]>
This in future gonna be used by HoG to receive connection notifications.
---
android/gatt.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++-----------
android/gatt.h | 15 ++++++
2 files changed, 130 insertions(+), 28 deletions(-)
diff --git a/android/gatt.c b/android/gatt.c
index 3fd88fa..c25aed4 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -87,11 +87,6 @@ static const char const *device_state_str[] = {
"CONNECTED",
};
-typedef enum {
- APP_CLIENT,
- APP_SERVER,
-} gatt_app_type_t;
-
struct pending_trans_data {
unsigned int id;
uint8_t opcode;
@@ -101,10 +96,12 @@ struct gatt_app {
int32_t id;
uint8_t uuid[16];
- gatt_app_type_t type;
+ gatt_type_t type;
/* Valid for client applications */
struct queue *notifications;
+
+ gatt_conn_cb_t func;
};
struct element_id {
@@ -617,7 +614,7 @@ static void destroy_gatt_app(void *data)
* too. So remove all elements and then destroy queue.
*/
- if (app->type == APP_CLIENT)
+ if (app->type == GATT_CLIENT)
while (queue_peek_head(app->notifications)) {
struct notification_data *notification;
@@ -630,14 +627,14 @@ static void destroy_gatt_app(void *data)
free(app);
}
-static int register_app(const uint8_t *uuid, gatt_app_type_t app_type)
+static struct gatt_app *register_app(const uint8_t *uuid, gatt_type_t type)
{
static int32_t application_id = 1;
struct gatt_app *app;
if (queue_find(gatt_apps, match_app_by_uuid, uuid)) {
error("gatt: app uuid is already on list");
- return 0;
+ return NULL;
}
app = new0(struct gatt_app, 1);
@@ -646,14 +643,14 @@ static int register_app(const uint8_t *uuid, gatt_app_type_t app_type)
return 0;
}
- app->type = app_type;
+ app->type = type;
- if (app->type == APP_CLIENT) {
+ if (app->type == GATT_CLIENT) {
app->notifications = queue_new();
if (!app->notifications) {
error("gatt: couldn't allocate notifications queue");
destroy_gatt_app(app);
- return 0;
+ return NULL;
}
}
@@ -664,33 +661,35 @@ static int register_app(const uint8_t *uuid, gatt_app_type_t app_type)
if (!queue_push_head(gatt_apps, app)) {
error("gatt: Cannot push app on the list");
destroy_gatt_app(app);
- return 0;
+ return NULL;
}
- if ((app->type == APP_SERVER) &&
+ if ((app->type == GATT_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 NULL;
}
- return app->id;
+ return app;
}
static void handle_client_register(const void *buf, uint16_t len)
{
const struct hal_cmd_gatt_client_register *cmd = buf;
struct hal_ev_gatt_client_register_client ev;
+ struct gatt_app *app;
DBG("");
memset(&ev, 0, sizeof(ev));
- ev.client_if = register_app(cmd->uuid, APP_CLIENT);
+ app = register_app(cmd->uuid, GATT_CLIENT);
- if (ev.client_if)
+ if (app) {
+ ev.client_if = app->id;
ev.status = GATT_SUCCESS;
- else
+ } else
ev.status = GATT_FAILURE;
/* We should send notification with given in cmd UUID */
@@ -708,6 +707,12 @@ static void send_client_disconnection_notify(struct app_connection *connection,
{
struct hal_ev_gatt_client_disconnect ev;
+ if (connection->app->func) {
+ connection->app->func(&connection->device->bdaddr, -ENOTCONN,
+ connection->device->attrib);
+ return;
+ }
+
ev.client_if = connection->app->id;
ev.conn_id = connection->id;
ev.status = status;
@@ -716,6 +721,7 @@ static void send_client_disconnection_notify(struct app_connection *connection,
ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
HAL_EV_GATT_CLIENT_DISCONNECT, sizeof(ev), &ev);
+
}
static void send_client_connection_notify(struct app_connection *connection,
@@ -723,6 +729,13 @@ static void send_client_connection_notify(struct app_connection *connection,
{
struct hal_ev_gatt_client_connect ev;
+ if (connection->app->func) {
+ connection->app->func(&connection->device->bdaddr,
+ status == GATT_SUCCESS ? 0 : -ENOTCONN,
+ connection->device->attrib);
+ return;
+ }
+
ev.client_if = connection->app->id;
ev.conn_id = connection->id;
ev.status = status;
@@ -738,6 +751,13 @@ static void send_server_connection_notify(struct app_connection *connection,
{
struct hal_ev_gatt_server_connection ev;
+ if (connection->app->func) {
+ connection->app->func(&connection->device->bdaddr,
+ connected ? 0 : -ENOTCONN,
+ connection->device->attrib);
+ return;
+ }
+
ev.server_if = connection->app->id;
ev.conn_id = connection->id;
ev.connected = connected;
@@ -751,7 +771,7 @@ static void send_server_connection_notify(struct app_connection *connection,
static void send_app_disconnect_notify(struct app_connection *connection,
int32_t status)
{
- if (connection->app->type == APP_CLIENT)
+ if (connection->app->type == GATT_CLIENT)
send_client_disconnection_notify(connection, status);
else
send_server_connection_notify(connection, !!status);
@@ -760,9 +780,9 @@ static void send_app_disconnect_notify(struct app_connection *connection,
static void send_app_connect_notify(struct app_connection *connection,
int32_t status)
{
- if (connection->app->type == APP_CLIENT)
+ if (connection->app->type == GATT_CLIENT)
send_client_connection_notify(connection, status);
- else
+ else if (connection->app->type == GATT_SERVER)
send_server_connection_notify(connection, !status);
}
@@ -3568,9 +3588,11 @@ static void handle_client_test_command(const void *buf, uint16_t len)
switch (cmd->command) {
case GATT_CLIENT_TEST_CMD_ENABLE:
if (cmd->u1) {
- if (!test_client_if)
- test_client_if = register_app(TEST_UUID,
- APP_CLIENT);
+ if (!test_client_if) {
+ app = register_app(TEST_UUID, GATT_CLIENT);
+ if (app)
+ test_client_if = app->id;
+ }
if (test_client_if)
status = HAL_STATUS_SUCCESS;
@@ -3615,16 +3637,18 @@ static void handle_server_register(const void *buf, uint16_t len)
{
const struct hal_cmd_gatt_server_register *cmd = buf;
struct hal_ev_gatt_server_register ev;
+ struct gatt_app *app;
DBG("");
memset(&ev, 0, sizeof(ev));
- ev.server_if = register_app(cmd->uuid, APP_SERVER);
+ app = register_app(cmd->uuid, GATT_SERVER);
- if (ev.server_if)
+ if (app) {
+ ev.server_if = app->id;
ev.status = GATT_SUCCESS;
- else
+ } else
ev.status = GATT_FAILURE;
memcpy(ev.uuid, cmd->uuid, sizeof(ev.uuid));
@@ -5978,3 +6002,66 @@ void bt_gatt_unregister(void)
bt_crypto_unref(crypto);
crypto = NULL;
}
+
+
+unsigned int bt_gatt_register_app(const char *uuid, gatt_type_t type,
+ gatt_conn_cb_t func)
+{
+ struct gatt_app *app;
+ bt_uuid_t uuid128;
+
+ bt_string_to_uuid(&uuid128, uuid);
+ app = register_app((void *) &uuid128.value.u128, type);
+ if (!app)
+ return 0;
+
+ app->func = func;
+
+ return app->id;
+}
+
+bool bt_gatt_unregister_app(unsigned int id)
+{
+ uint8_t status;
+
+ status = unregister_client(id);
+
+ return status != HAL_STATUS_FAILED;
+}
+
+bool bt_gatt_connect_app(unsigned int id, const bdaddr_t *addr)
+{
+ uint8_t status;
+
+ status = handle_connect(id, addr);
+
+ return status != HAL_STATUS_FAILED;
+}
+
+bool bt_gatt_disconnect_app(unsigned int id, const bdaddr_t *addr)
+{
+ struct app_connection match;
+ struct app_connection *conn;
+ struct gatt_device *device;
+ struct gatt_app *app;
+
+ app = find_app_by_id(id);
+ if (!app)
+ return false;
+
+ device = find_device_by_addr(addr);
+ if (!device)
+ return false;
+
+ match.device = device;
+ match.app = app;
+
+ conn = queue_find(app_connections, match_connection_by_device_and_app,
+ &match);
+ if (!conn)
+ return false;
+
+ trigger_disconnection(conn);
+
+ return true;
+}
diff --git a/android/gatt.h b/android/gatt.h
index d4392d9..5ba9161 100644
--- a/android/gatt.h
+++ b/android/gatt.h
@@ -23,3 +23,18 @@
bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr);
void bt_gatt_unregister(void);
+
+
+typedef enum {
+ GATT_CLIENT,
+ GATT_SERVER,
+} gatt_type_t;
+
+typedef void (*gatt_conn_cb_t)(const bdaddr_t *addr, int err, void *attrib);
+
+unsigned int bt_gatt_register_app(const char *uuid, gatt_type_t type,
+ gatt_conn_cb_t func);
+bool bt_gatt_unregister_app(unsigned int id);
+
+bool bt_gatt_connect_app(unsigned int id, const bdaddr_t *addr);
+bool bt_gatt_disconnect_app(unsigned int id, const bdaddr_t *addr);
--
1.9.3
From: Luiz Augusto von Dentz <[email protected]>
---
android/bluetooth.c | 11 +++++++++++
android/bluetooth.h | 2 ++
2 files changed, 13 insertions(+)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 36b073e..d275297 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -1386,6 +1386,17 @@ uint8_t bt_get_device_android_type(const bdaddr_t *addr)
return get_device_android_type(dev);
}
+bool bt_is_device_le(const bdaddr_t *addr)
+{
+ struct device *dev;
+
+ dev = find_device(addr);
+ if (!dev)
+ return false;
+
+ return dev->le;
+}
+
const char *bt_get_adapter_name(void)
{
return adapter.name;
diff --git a/android/bluetooth.h b/android/bluetooth.h
index b4a5f32..2409d46 100644
--- a/android/bluetooth.h
+++ b/android/bluetooth.h
@@ -54,6 +54,8 @@ 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);
+bool bt_is_device_le(const bdaddr_t *addr);
+
const char *bt_get_adapter_name(void);
bool bt_device_is_bonded(const bdaddr_t *bdaddr);
--
1.9.3