2014-06-16 15:01:34

by Ravi kumar Veeramally

[permalink] [raw]
Subject: [PATCH_v2 0/6] HDP initial implementaion

v2: Fixed comments from Szymon (optimized cache patch,
split notify patch, other issues).
v1: Fixed comments from szymon.

RFC_v2: Fixed comments by szymon and fixed issues while sebastian
testing with PTS.

RFC_v1: patchset is initial implementaion for HDP at daemon side.
Cacheing application data and prepare SDP record based on MDEPs
configuration and notify app state.

Ravi kumar Veeramally (6):
android/health: Cache health application data on app register call
android/health: Perform clean up on app unregister call
android/health: Add HDP SDP record
android/health: Notify application registration status
android/health: Notify application deregistration status
profile/health: Free sdp list after adding it to record

android/health.c | 717 ++++++++++++++++++++++++++++++++++++++++++++-
profiles/health/hdp_util.c | 2 +
2 files changed, 711 insertions(+), 8 deletions(-)

--
1.9.1



2014-06-16 16:41:10

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH_v2 0/6] HDP initial implementaion

Hi Ravi,

On Monday 16 June 2014 18:01:34 Ravi kumar Veeramally wrote:
> v2: Fixed comments from Szymon (optimized cache patch,
> split notify patch, other issues).
> v1: Fixed comments from szymon.
>
> RFC_v2: Fixed comments by szymon and fixed issues while sebastian
> testing with PTS.
>
> RFC_v1: patchset is initial implementaion for HDP at daemon side.
> Cacheing application data and prepare SDP record based on MDEPs
> configuration and notify app state.
>
> Ravi kumar Veeramally (6):
> android/health: Cache health application data on app register call
> android/health: Perform clean up on app unregister call
> android/health: Add HDP SDP record
> android/health: Notify application registration status
> android/health: Notify application deregistration status
> profile/health: Free sdp list after adding it to record
>
> android/health.c | 717
> ++++++++++++++++++++++++++++++++++++++++++++- profiles/health/hdp_util.c |
> 2 +
> 2 files changed, 711 insertions(+), 8 deletions(-)

Patches 1-5 are now applied (with changes we discussed on IRC), thanks.

--
Szymon K. Janc
[email protected]

2014-06-16 15:01:40

by Ravi kumar Veeramally

[permalink] [raw]
Subject: [PATCH_v2 6/6] profile/health: Free sdp list after adding it to record

---
profiles/health/hdp_util.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/profiles/health/hdp_util.c b/profiles/health/hdp_util.c
index 58770b5..47c464e 100644
--- a/profiles/health/hdp_util.c
+++ b/profiles/health/hdp_util.c
@@ -652,6 +652,8 @@ static gboolean register_service_sup_features(GSList *app_list,
return FALSE;
}

+ sdp_list_free(sup_features, free_hdp_list);
+
return TRUE;
}

--
1.9.1


2014-06-16 15:01:39

by Ravi kumar Veeramally

[permalink] [raw]
Subject: [PATCH_v2 5/6] android/health: Notify application deregistration status

---
android/health.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/android/health.c b/android/health.c
index 4862b76..36ed6e7 100644
--- a/android/health.c
+++ b/android/health.c
@@ -731,6 +731,8 @@ static void bt_health_unregister_app(const void *buf, uint16_t len)
return;
}

+ send_app_reg_notify(app, HAL_HEALTH_APP_DEREG_SUCCESS);
+
if (record_id > 0) {
bt_adapter_remove_record(record_id);
record_id = 0;
--
1.9.1


2014-06-16 15:01:36

by Ravi kumar Veeramally

[permalink] [raw]
Subject: [PATCH_v2 2/6] android/health: Perform clean up on app unregister call

---
android/health.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/android/health.c b/android/health.c
index 4bad7c4..59a97c0 100644
--- a/android/health.c
+++ b/android/health.c
@@ -266,10 +266,21 @@ fail:

static void bt_health_unregister_app(const void *buf, uint16_t len)
{
- DBG("Not implemented");
+ const struct hal_cmd_health_unreg_app *cmd = buf;
+ struct health_app *app;
+
+ DBG("");
+
+ app = queue_remove_if(apps, app_by_app_id, INT_TO_PTR(cmd->app_id));
+ if (!app) {
+ ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_HEALTH,
+ HAL_OP_HEALTH_UNREG_APP, HAL_STATUS_INVALID);
+ return;
+ }

- ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_HEALTH, HAL_OP_HEALTH_UNREG_APP,
- HAL_STATUS_UNSUPPORTED);
+ free_health_app(app);
+ ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_HEALTH,
+ HAL_OP_HEALTH_UNREG_APP, HAL_STATUS_SUCCESS);
}

static void bt_health_connect_channel(const void *buf, uint16_t len)
--
1.9.1


2014-06-16 15:01:38

by Ravi kumar Veeramally

[permalink] [raw]
Subject: [PATCH_v2 4/6] android/health: Notify application registration status

---
android/health.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)

diff --git a/android/health.c b/android/health.c
index 3029439..4862b76 100644
--- a/android/health.c
+++ b/android/health.c
@@ -105,6 +105,19 @@ static void free_health_app(void *data)
free(app);
}

+static void send_app_reg_notify(struct health_app *app, uint8_t state)
+{
+ struct hal_ev_health_app_reg_state ev;
+
+ DBG("");
+
+ ev.id = app->id;
+ ev.state = state;
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_HEALTH,
+ HAL_EV_HEALTH_APP_REG_STATE, sizeof(ev), &ev);
+}
+
static bool mdep_by_mdep_role(const void *data, const void *user_data)
{
const struct mdep_cfg *mdep = data;
@@ -686,6 +699,8 @@ static void bt_health_mdep_cfg_data(const void *buf, uint16_t len)
goto fail;
}

+ send_app_reg_notify(app, HAL_HEALTH_APP_REG_SUCCESS);
+
send_rsp:
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_HEALTH, HAL_OP_HEALTH_MDEP,
HAL_STATUS_SUCCESS);
--
1.9.1


2014-06-16 15:01:35

by Ravi kumar Veeramally

[permalink] [raw]
Subject: [PATCH_v2 1/6] android/health: Cache health application data on app register call

---
android/health.c | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 200 insertions(+), 5 deletions(-)

diff --git a/android/health.c b/android/health.c
index 8279f87..4bad7c4 100644
--- a/android/health.c
+++ b/android/health.c
@@ -35,6 +35,8 @@
#include "lib/sdp.h"
#include "lib/sdp_lib.h"
#include "src/log.h"
+#include "src/shared/util.h"
+#include "src/shared/queue.h"

#include "hal-msg.h"
#include "ipc-common.h"
@@ -45,10 +47,113 @@

static bdaddr_t adapter_addr;
static struct ipc *hal_ipc = NULL;
+static struct queue *apps = NULL;
+
+struct mdep_cfg {
+ uint8_t role;
+ uint16_t data_type;
+ uint8_t channel_type;
+ char *descr;
+
+ uint8_t id; /* mdep id */
+};
+
+struct health_app {
+ char *app_name;
+ char *provider_name;
+ char *service_name;
+ char *service_descr;
+ uint8_t num_of_mdep;
+ struct queue *mdeps;
+
+ uint8_t id; /* app id */
+};
+
+static void free_mdep_cfg(void *data)
+{
+ struct mdep_cfg *cfg = data;
+
+ if (!cfg)
+ return;
+
+ free(cfg->descr);
+ free(cfg);
+}
+
+static void free_health_app(void *data)
+{
+ struct health_app *app = data;
+
+ if (!app)
+ return;
+
+ free(app->app_name);
+ free(app->provider_name);
+ free(app->service_name);
+ free(app->service_descr);
+ queue_destroy(app->mdeps, free_mdep_cfg);
+ free(app);
+}
+
+static bool app_by_app_id(const void *data, const void *user_data)
+{
+ const struct health_app *app = data;
+ uint16_t app_id = PTR_TO_INT(user_data);
+
+ return app->id == app_id;
+}
+
+static struct health_app *create_health_app(const char *app_name,
+ const char *provider, const char *srv_name,
+ const char *srv_descr, uint8_t mdeps)
+{
+ struct health_app *app;
+
+ DBG("");
+
+ app = new0(struct health_app, 1);
+ if (!app)
+ return NULL;
+
+ app->id = queue_length(apps) + 1;
+ app->num_of_mdep = mdeps;
+ app->app_name = strdup(app_name);
+
+ if (provider) {
+ app->provider_name = strdup(provider);
+ if (!app->provider_name)
+ goto fail;
+ }
+
+ if (srv_name) {
+ app->service_name = strdup(srv_name);
+ if (!app->service_name)
+ goto fail;
+ }
+
+ if (srv_descr) {
+ app->service_descr = strdup(srv_descr);
+ if (!app->service_descr)
+ goto fail;
+ }
+
+ return app;
+
+fail:
+ free_health_app(app);
+ return NULL;
+}

static void bt_health_register_app(const void *buf, uint16_t len)
{
const struct hal_cmd_health_reg_app *cmd = buf;
+ struct hal_rsp_health_reg_app rsp;
+ struct health_app *app;
+ uint16_t off;
+ uint16_t app_name_len, provider_len, srv_name_len, srv_descr_len;
+ char *app_name, *provider = NULL, *srv_name = NULL, *srv_descr = NULL;
+
+ DBG("");

if (len != sizeof(*cmd) + cmd->len ||
cmd->app_name_off > cmd->provider_name_off ||
@@ -60,18 +165,103 @@ static void bt_health_register_app(const void *buf, uint16_t len)
return;
}

- DBG("Not implemented");
+ app_name = (char *) cmd->data;
+ app_name_len = cmd->provider_name_off - cmd->app_name_off;

- ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_HEALTH, HAL_OP_HEALTH_REG_APP,
- HAL_STATUS_UNSUPPORTED);
+ off = app_name_len;
+ provider_len = cmd->service_name_off - off;
+ if (provider_len > 0)
+ provider = (char *) cmd->data + off;
+
+ off += provider_len;
+ srv_name_len = cmd->service_descr_off - off;
+ if (srv_name_len > 0)
+ srv_name = (char *) cmd->data + off;
+
+ off += srv_name_len;
+ srv_descr_len = cmd->len - off;
+ if (srv_descr_len > 0)
+ srv_descr = (char *) cmd->data + off;
+
+ app = create_health_app(app_name, provider, srv_name, srv_descr,
+ cmd->num_of_mdep);
+
+ if (!queue_push_tail(apps, app))
+ goto fail;
+
+ rsp.app_id = app->id;
+ ipc_send_rsp_full(hal_ipc, HAL_SERVICE_ID_HEALTH, HAL_OP_HEALTH_REG_APP,
+ sizeof(rsp), &rsp, -1);
+ return;
+
+fail:
+ free_health_app(app);
+ ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_HEALTH, HAL_OP_HEALTH_MDEP,
+ HAL_STATUS_FAILED);
}

static void bt_health_mdep_cfg_data(const void *buf, uint16_t len)
{
- DBG("Not implemented");
+ const struct hal_cmd_health_mdep *cmd = buf;
+ struct health_app *app;
+ struct mdep_cfg *mdep = NULL;
+ uint8_t status;
+
+ DBG("");
+
+ app = queue_find(apps, app_by_app_id, INT_TO_PTR(cmd->app_id));
+ if (!app) {
+ status = HAL_STATUS_INVALID;
+ goto fail;
+ }
+
+ mdep = new0(struct mdep_cfg, 1);
+ if (!mdep) {
+ status = HAL_STATUS_INVALID;
+ goto fail;
+ }

+ mdep->role = cmd->role;
+ mdep->data_type = cmd->data_type;
+ mdep->channel_type = cmd->channel_type;
+ mdep->id = queue_length(app->mdeps) + 1;
+
+ if (cmd->descr_len > 0) {
+ mdep->descr = malloc0(cmd->descr_len);
+ memcpy(mdep->descr, cmd->descr, cmd->descr_len);
+ }
+
+ if (app->num_of_mdep > 0 && !app->mdeps) {
+ app->mdeps = queue_new();
+ if (!app->mdeps) {
+ status = HAL_STATUS_FAILED;
+ goto fail;
+ }
+ }
+
+ if (!queue_push_tail(app->mdeps, mdep)) {
+ status = HAL_STATUS_FAILED;
+ goto fail;
+ }
+
+ if (app->num_of_mdep != queue_length(app->mdeps))
+ goto send_rsp;
+
+ /* TODO: Create MCAP instance and prepare SDP profile */
+send_rsp:
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_HEALTH, HAL_OP_HEALTH_MDEP,
- HAL_STATUS_UNSUPPORTED);
+ HAL_STATUS_SUCCESS);
+ return;
+
+fail:
+ if (status != HAL_STATUS_SUCCESS) {
+ free_mdep_cfg(mdep);
+ queue_remove(apps, app);
+ free_health_app(app);
+ }
+
+ ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_HEALTH, HAL_OP_HEALTH_MDEP,
+ status);
}

static void bt_health_unregister_app(const void *buf, uint16_t len)
@@ -123,6 +313,10 @@ bool bt_health_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode)
bacpy(&adapter_addr, addr);

hal_ipc = ipc;
+ apps = queue_new();
+ if (!apps)
+ return false;
+
ipc_register(hal_ipc, HAL_SERVICE_ID_HEALTH, cmd_handlers,
G_N_ELEMENTS(cmd_handlers));

@@ -133,6 +327,7 @@ void bt_health_unregister(void)
{
DBG("");

+ queue_destroy(apps, free_health_app);
ipc_unregister(hal_ipc, HAL_SERVICE_ID_HEALTH);
hal_ipc = NULL;
}
--
1.9.1


2014-06-16 15:01:37

by Ravi kumar Veeramally

[permalink] [raw]
Subject: [PATCH_v2 3/6] android/health: Add HDP SDP record

SDP record preparation code copied from profiles/health/hdp_uitl.c.
So applying GSyC copyrights.
---
android/health.c | 480 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 479 insertions(+), 1 deletion(-)

diff --git a/android/health.c b/android/health.c
index 59a97c0..3029439 100644
--- a/android/health.c
+++ b/android/health.c
@@ -3,6 +3,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2014 Intel Corporation. All rights reserved.
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
*
*
* This library is free software; you can redistribute it and/or
@@ -31,6 +32,7 @@
#include <unistd.h>
#include <glib.h>

+#include "btio/btio.h"
#include "lib/bluetooth.h"
#include "lib/sdp.h"
#include "lib/sdp_lib.h"
@@ -44,10 +46,18 @@
#include "utils.h"
#include "bluetooth.h"
#include "health.h"
+#include "mcap-lib.h"
+
+#define SVC_HINT_HEALTH 0x00
+#define HDP_VERSION 0x0101
+#define DATA_EXCHANGE_SPEC_11073 0x01

static bdaddr_t adapter_addr;
static struct ipc *hal_ipc = NULL;
static struct queue *apps = NULL;
+static struct mcap_instance *mcap = NULL;
+static uint32_t record_id = 0;
+static uint32_t record_state = 0;

struct mdep_cfg {
uint8_t role;
@@ -95,6 +105,14 @@ static void free_health_app(void *data)
free(app);
}

+static bool mdep_by_mdep_role(const void *data, const void *user_data)
+{
+ const struct mdep_cfg *mdep = data;
+ uint16_t role = PTR_TO_INT(user_data);
+
+ return mdep->role == role;
+}
+
static bool app_by_app_id(const void *data, const void *user_data)
{
const struct health_app *app = data;
@@ -103,6 +121,413 @@ static bool app_by_app_id(const void *data, const void *user_data)
return app->id == app_id;
}

+static int register_service_protocols(sdp_record_t *rec,
+ struct health_app *app)
+{
+ uuid_t l2cap_uuid, mcap_c_uuid;
+ sdp_list_t *l2cap_list, *proto_list = NULL, *mcap_list = NULL;
+ sdp_list_t *access_proto_list = NULL;
+ sdp_data_t *psm = NULL, *mcap_ver = NULL;
+ uint32_t ccpsm;
+ uint16_t version = MCAP_VERSION;
+ GError *err = NULL;
+ int ret = -1;
+
+ DBG("");
+
+ /* set l2cap information */
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ l2cap_list = sdp_list_append(NULL, &l2cap_uuid);
+ if (!l2cap_list)
+ goto fail;
+
+ ccpsm = mcap_get_ctrl_psm(mcap, &err);
+ if (err)
+ goto fail;
+
+ psm = sdp_data_alloc(SDP_UINT16, &ccpsm);
+ if (!psm)
+ goto fail;
+
+ if (!sdp_list_append(l2cap_list, psm))
+ goto fail;
+
+ proto_list = sdp_list_append(NULL, l2cap_list);
+ if (!proto_list)
+ goto fail;
+
+ /* set mcap information */
+ sdp_uuid16_create(&mcap_c_uuid, MCAP_CTRL_UUID);
+ mcap_list = sdp_list_append(NULL, &mcap_c_uuid);
+ if (!mcap_list)
+ goto fail;
+
+ mcap_ver = sdp_data_alloc(SDP_UINT16, &version);
+ if (!mcap_ver)
+ goto fail;
+
+ if (!sdp_list_append(mcap_list, mcap_ver))
+ goto fail;
+
+ if (!sdp_list_append(proto_list, mcap_list))
+ goto fail;
+
+ /* attach protocol information to service record */
+ access_proto_list = sdp_list_append(NULL, proto_list);
+ if (!access_proto_list)
+ goto fail;
+
+ sdp_set_access_protos(rec, access_proto_list);
+ ret = 0;
+
+fail:
+ sdp_list_free(l2cap_list, NULL);
+ sdp_list_free(mcap_list, NULL);
+ sdp_list_free(proto_list, NULL);
+ sdp_list_free(access_proto_list, NULL);
+
+ if (psm)
+ sdp_data_free(psm);
+
+ if (mcap_ver)
+ sdp_data_free(mcap_ver);
+
+ if (err)
+ g_error_free(err);
+
+ return ret;
+}
+
+static int register_service_profiles(sdp_record_t *rec)
+{
+ int ret;
+ sdp_list_t *profile_list;
+ sdp_profile_desc_t hdp_profile;
+
+ DBG("");
+
+ /* set hdp information */
+ sdp_uuid16_create(&hdp_profile.uuid, HDP_SVCLASS_ID);
+ hdp_profile.version = HDP_VERSION;
+ profile_list = sdp_list_append(NULL, &hdp_profile);
+ if (!profile_list)
+ return -1;
+
+ /* set profile descriptor list */
+ ret = sdp_set_profile_descs(rec, profile_list);
+ sdp_list_free(profile_list, NULL);
+
+ return ret;
+}
+
+static int register_service_additional_protocols(sdp_record_t *rec,
+ struct health_app *app)
+{
+ int ret = -1;
+ uuid_t l2cap_uuid, mcap_d_uuid;
+ sdp_list_t *l2cap_list, *proto_list = NULL, *mcap_list = NULL;
+ sdp_list_t *access_proto_list = NULL;
+ sdp_data_t *psm = NULL;
+ uint32_t dcpsm;
+ GError *err;
+
+ DBG("");
+
+ /* set l2cap information */
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ l2cap_list = sdp_list_append(NULL, &l2cap_uuid);
+ if (!l2cap_list)
+ goto fail;
+
+ dcpsm = mcap_get_ctrl_psm(mcap, &err);
+ if (err)
+ goto fail;
+
+ psm = sdp_data_alloc(SDP_UINT16, &dcpsm);
+ if (!psm)
+ goto fail;
+
+ if (!sdp_list_append(l2cap_list, psm))
+ goto fail;
+
+ proto_list = sdp_list_append(NULL, l2cap_list);
+ if (!proto_list)
+ goto fail;
+
+ /* set mcap information */
+ sdp_uuid16_create(&mcap_d_uuid, MCAP_DATA_UUID);
+ mcap_list = sdp_list_append(NULL, &mcap_d_uuid);
+ if (!mcap_list)
+ goto fail;
+
+ if (!sdp_list_append(proto_list, mcap_list))
+ goto fail;
+
+ /* attach protocol information to service record */
+ access_proto_list = sdp_list_append(NULL, proto_list);
+ if (!access_proto_list)
+ goto fail;
+
+ sdp_set_add_access_protos(rec, access_proto_list);
+ ret = 0;
+
+fail:
+ sdp_list_free(l2cap_list, NULL);
+ sdp_list_free(mcap_list, NULL);
+ sdp_list_free(proto_list, NULL);
+ sdp_list_free(access_proto_list, NULL);
+
+ if (psm)
+ sdp_data_free(psm);
+
+ if (err)
+ g_error_free(err);
+
+ return ret;
+}
+
+static sdp_list_t *mdeps_to_sdp_features(struct mdep_cfg *mdep)
+{
+ sdp_data_t *mdepid, *dtype = NULL, *role = NULL, *descr = NULL;
+ sdp_list_t *f_list = NULL;
+
+ DBG("");
+
+ mdepid = sdp_data_alloc(SDP_UINT8, &mdep->id);
+ if (!mdepid)
+ return NULL;
+
+ dtype = sdp_data_alloc(SDP_UINT16, &mdep->data_type);
+ if (!dtype)
+ goto fail;
+
+ role = sdp_data_alloc(SDP_UINT8, &mdep->role);
+ if (!role)
+ goto fail;
+
+ if (mdep->descr) {
+ descr = sdp_data_alloc(SDP_TEXT_STR8, mdep->descr);
+ if (!descr)
+ goto fail;
+ }
+
+ f_list = sdp_list_append(NULL, mdepid);
+ if (!f_list)
+ goto fail;
+
+ if (!sdp_list_append(f_list, dtype))
+ goto fail;
+
+ if (!sdp_list_append(f_list, role))
+ goto fail;
+
+ if (descr && !sdp_list_append(f_list, descr))
+ goto fail;
+
+ return f_list;
+
+fail:
+ sdp_list_free(f_list, NULL);
+
+ if (mdepid)
+ sdp_data_free(mdepid);
+
+ if (dtype)
+ sdp_data_free(dtype);
+
+ if (role)
+ sdp_data_free(role);
+
+ if (descr)
+ sdp_data_free(descr);
+
+ return NULL;
+}
+
+static void free_hdp_list(void *list)
+{
+ sdp_list_t *hdp_list = list;
+
+ sdp_list_free(hdp_list, (sdp_free_func_t)sdp_data_free);
+ hdp_list = NULL;
+}
+
+static void register_features(void *data, void *user_data)
+{
+ struct mdep_cfg *mdep = data;
+ sdp_list_t **sup_features = user_data;
+ sdp_list_t *hdp_feature;
+
+ DBG("");
+
+ hdp_feature = mdeps_to_sdp_features(mdep);
+ if (!hdp_feature)
+ return;
+
+ if (!*sup_features) {
+ *sup_features = sdp_list_append(NULL, hdp_feature);
+ if (!*sup_features)
+ sdp_list_free(hdp_feature,
+ (sdp_free_func_t)sdp_data_free);
+ } else if (!sdp_list_append(*sup_features, hdp_feature)) {
+ sdp_list_free(hdp_feature,
+ (sdp_free_func_t)sdp_data_free);
+ }
+}
+
+static int register_service_sup_features(sdp_record_t *rec,
+ struct health_app *app)
+{
+ sdp_list_t *sup_features = NULL;
+
+ DBG("");
+
+ queue_foreach(app->mdeps, register_features, &sup_features);
+ if (!sup_features)
+ return -1;
+
+ if (sdp_set_supp_feat(rec, sup_features) < 0) {
+ sdp_list_free(sup_features, free_hdp_list);
+ return -1;
+ }
+
+ sdp_list_free(sup_features, free_hdp_list);
+ return 0;
+}
+
+static int register_data_exchange_spec(sdp_record_t *rec)
+{
+ sdp_data_t *spec;
+ uint8_t data_spec = DATA_EXCHANGE_SPEC_11073;
+ /* As of now only 11073 is supported, so we set it as default */
+
+ DBG("");
+
+ spec = sdp_data_alloc(SDP_UINT8, &data_spec);
+ if (!spec)
+ return -1;
+
+ if (sdp_attr_add(rec, SDP_ATTR_DATA_EXCHANGE_SPEC, spec) < 0) {
+ sdp_data_free(spec);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int register_mcap_features(sdp_record_t *rec)
+{
+ sdp_data_t *mcap_proc;
+ uint8_t mcap_sup_proc = MCAP_SUP_PROC;
+
+ DBG("");
+
+ mcap_proc = sdp_data_alloc(SDP_UINT8, &mcap_sup_proc);
+ if (!mcap_proc)
+ return -1;
+
+ if (sdp_attr_add(rec, SDP_ATTR_MCAP_SUPPORTED_PROCEDURES,
+ mcap_proc) < 0) {
+ sdp_data_free(mcap_proc);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int set_sdp_services_uuid(sdp_record_t *rec, uint8_t role)
+{
+ uuid_t source, sink;
+ sdp_list_t *list = NULL;
+
+ sdp_uuid16_create(&sink, HDP_SINK_SVCLASS_ID);
+ sdp_uuid16_create(&source, HDP_SOURCE_SVCLASS_ID);
+ sdp_get_service_classes(rec, &list);
+
+ switch (role) {
+ case HAL_HEALTH_MDEP_ROLE_SOURCE:
+ if (!sdp_list_find(list, &source, sdp_uuid_cmp))
+ list = sdp_list_append(list, &source);
+ break;
+ case HAL_HEALTH_MDEP_ROLE_SINK:
+ if (!sdp_list_find(list, &sink, sdp_uuid_cmp))
+ list = sdp_list_append(list, &sink);
+ break;
+ }
+
+ if (sdp_set_service_classes(rec, list) < 0) {
+ sdp_list_free(list, NULL);
+ return -1;
+ }
+
+ sdp_list_free(list, NULL);
+
+ return 0;
+}
+
+static int update_sdp_record(struct health_app *app)
+{
+ sdp_record_t *rec;
+ uint8_t role;
+
+ DBG("");
+
+ if (record_id > 0) {
+ bt_adapter_remove_record(record_id);
+ record_id = 0;
+ }
+
+ rec = sdp_record_alloc();
+ if (!rec)
+ return -1;
+
+ role = HAL_HEALTH_MDEP_ROLE_SOURCE;
+ if (queue_find(app->mdeps, mdep_by_mdep_role, INT_TO_PTR(role)))
+ set_sdp_services_uuid(rec, role);
+
+ role = HAL_HEALTH_MDEP_ROLE_SINK;
+ if (queue_find(app->mdeps, mdep_by_mdep_role, INT_TO_PTR(role)))
+ set_sdp_services_uuid(rec, role);
+
+ sdp_set_info_attr(rec, app->service_name, app->provider_name,
+ app->service_descr);
+
+ if (register_service_protocols(rec, app) < 0)
+ goto fail;
+
+ if (register_service_profiles(rec) < 0)
+ goto fail;
+
+ if (register_service_additional_protocols(rec, app) < 0)
+ goto fail;
+
+ if (register_service_sup_features(rec, app) < 0)
+ goto fail;
+
+ if (register_data_exchange_spec(rec) < 0)
+ goto fail;
+
+ if (register_mcap_features(rec) < 0)
+ goto fail;
+
+ if (sdp_set_record_state(rec, record_state++) < 0)
+ goto fail;
+
+ if (bt_adapter_add_record(rec, SVC_HINT_HEALTH) < 0) {
+ error("Failed to register HEALTH record");
+ goto fail;
+ }
+
+ record_id = rec->handle;
+
+ return 0;
+
+fail:
+ sdp_record_free(rec);
+
+ return -1;
+}
+
static struct health_app *create_health_app(const char *app_name,
const char *provider, const char *srv_name,
const char *srv_descr, uint8_t mdeps)
@@ -247,7 +672,20 @@ static void bt_health_mdep_cfg_data(const void *buf, uint16_t len)
if (app->num_of_mdep != queue_length(app->mdeps))
goto send_rsp;

- /* TODO: Create MCAP instance and prepare SDP profile */
+ /* add sdp record from app configuration data */
+ /*
+ * TODO: Check what to be done if mupltple applications are trying to
+ * register with different role and different configurations.
+ * 1) Does device supports SOURCE and SINK at the same time ?
+ * 2) Does it require different SDP records or one record with
+ * multile MDEP configurations ?
+ */
+ if (update_sdp_record(app) < 0) {
+ error("Error creating HDP SDP record");
+ status = HAL_STATUS_FAILED;
+ goto fail;
+ }
+
send_rsp:
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_HEALTH, HAL_OP_HEALTH_MDEP,
HAL_STATUS_SUCCESS);
@@ -278,6 +716,11 @@ static void bt_health_unregister_app(const void *buf, uint16_t len)
return;
}

+ if (record_id > 0) {
+ bt_adapter_remove_record(record_id);
+ record_id = 0;
+ }
+
free_health_app(app);
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_HEALTH,
HAL_OP_HEALTH_UNREG_APP, HAL_STATUS_SUCCESS);
@@ -317,12 +760,46 @@ static const struct ipc_handler cmd_handlers[] = {
sizeof(struct hal_cmd_health_destroy_channel) },
};

+static void mcl_connected(struct mcap_mcl *mcl, gpointer data)
+{
+ DBG("Not implemented");
+}
+
+static void mcl_reconnected(struct mcap_mcl *mcl, gpointer data)
+{
+ DBG("Not implemented");
+}
+
+static void mcl_disconnected(struct mcap_mcl *mcl, gpointer data)
+{
+ DBG("Not implemented");
+}
+
+static void mcl_uncached(struct mcap_mcl *mcl, gpointer data)
+{
+ DBG("Not implemented");
+}
+
bool bt_health_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode)
{
+ GError *err = NULL;
+
DBG("");

bacpy(&adapter_addr, addr);

+ mcap = mcap_create_instance(&adapter_addr, BT_IO_SEC_MEDIUM, 0, 0,
+ mcl_connected, mcl_reconnected,
+ mcl_disconnected, mcl_uncached,
+ NULL, /* CSP is not used right now */
+ NULL, &err);
+
+ if (!mcap) {
+ error("Error creating MCAP instance : %s", err->message);
+ g_error_free(err);
+ return false;
+ }
+
hal_ipc = ipc;
apps = queue_new();
if (!apps)
@@ -338,6 +815,7 @@ void bt_health_unregister(void)
{
DBG("");

+ mcap_instance_unref(mcap);
queue_destroy(apps, free_health_app);
ipc_unregister(hal_ipc, HAL_SERVICE_ID_HEALTH);
hal_ipc = NULL;
--
1.9.1