2014-06-22 11:58:55

by Ravi kumar Veeramally

[permalink] [raw]
Subject: [PATCH_v3 0/6] Initial implementation for MCAP data channel

v3: Fixed Szymon's comments.

v2: Few cleanups and support for streaming data channel.

v1: Patchset implements initial MCAP MDL creation and connection. On
successful MDL (reliable) connection fd will be passed to HAL.

PTS tests:

TC_SRC_CC_BV_03_C:

hl register_application bluez-android Bluez bluez-hdp health-device-profile 1 BTHL_MDEP_ROLE_SOURCE 4100 BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter

hl connect_channel 1 00:1b:dc:05:b5:54 0

TC_SRC_CC_BV_07_C:

hl register_application bluez-android Bluez bluez-hdp health-device-profile 2 BTHL_MDEP_ROLE_SOURCE 4100 BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter BTHL_MDEP_ROLE_SOURCE 4100 BTHL_CHANNEL_TYPE_STREAMING pulse-oximeter

hl connect_channel 1 00:1b:dc:05:b5:54 0
hl connect_channel 1 00:1b:dc:05:b5:54 1


TC_SNK_CC_BV_04_C:
TC_SNK_HCT_BV_01_I:

hl register_application bluez-android Bluez bluez-hdp health-device-profile 1 BTHL_MDEP_ROLE_SINK 4100 BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter

hl connect_channel 1 00:1b:dc:05:b5:54 0


TC_SNK_CC_BV_08_C:

hl register_application bluez-android Bluez bluez-hdp health-device-profile 2 BTHL_MDEP_ROLE_SINK 4100 BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter BTHL_MDEP_ROLE_SINK 4100 BTHL_CHANNEL_TYPE_STREAMING pulse-oximeter

hl connect_channel 1 00:1b:dc:05:b5:54 0
hl connect_channel 1 00:1b:dc:05:b5:54 1


Ravi kumar Veeramally (6):
android/health: Check if device and channel already exists or not
android/health: Cache remote mdep id on channel connect request
android/health: Notify channel status on channel destroy call
android/health: Create and connect MDL
android/health: Implement mcap_mdl_deleted_cb
anrdroid/client/health: Cache fd and close on channel disconnection

android/client/if-hl.c | 9 ++
android/health.c | 415 +++++++++++++++++++++++++++++++++++++++++++------
2 files changed, 376 insertions(+), 48 deletions(-)

--
1.9.1



2014-06-23 09:15:31

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH_v3 0/6] Initial implementation for MCAP data channel

Hi Ravi,

On Sunday 22 of June 2014 14:58:55 Ravi kumar Veeramally wrote:
> v3: Fixed Szymon's comments.
>
> v2: Few cleanups and support for streaming data channel.
>
> v1: Patchset implements initial MCAP MDL creation and connection. On
> successful MDL (reliable) connection fd will be passed to HAL.
>
> PTS tests:
>
> TC_SRC_CC_BV_03_C:
>
> hl register_application bluez-android Bluez bluez-hdp health-device-profile 1 BTHL_MDEP_ROLE_SOURCE 4100 BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter
>
> hl connect_channel 1 00:1b:dc:05:b5:54 0
>
> TC_SRC_CC_BV_07_C:
>
> hl register_application bluez-android Bluez bluez-hdp health-device-profile 2 BTHL_MDEP_ROLE_SOURCE 4100 BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter BTHL_MDEP_ROLE_SOURCE 4100 BTHL_CHANNEL_TYPE_STREAMING pulse-oximeter
>
> hl connect_channel 1 00:1b:dc:05:b5:54 0
> hl connect_channel 1 00:1b:dc:05:b5:54 1
>
>
> TC_SNK_CC_BV_04_C:
> TC_SNK_HCT_BV_01_I:
>
> hl register_application bluez-android Bluez bluez-hdp health-device-profile 1 BTHL_MDEP_ROLE_SINK 4100 BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter
>
> hl connect_channel 1 00:1b:dc:05:b5:54 0
>
>
> TC_SNK_CC_BV_08_C:
>
> hl register_application bluez-android Bluez bluez-hdp health-device-profile 2 BTHL_MDEP_ROLE_SINK 4100 BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter BTHL_MDEP_ROLE_SINK 4100 BTHL_CHANNEL_TYPE_STREAMING pulse-oximeter
>
> hl connect_channel 1 00:1b:dc:05:b5:54 0
> hl connect_channel 1 00:1b:dc:05:b5:54 1
>
>
> Ravi kumar Veeramally (6):
> android/health: Check if device and channel already exists or not
> android/health: Cache remote mdep id on channel connect request
> android/health: Notify channel status on channel destroy call
> android/health: Create and connect MDL
> android/health: Implement mcap_mdl_deleted_cb
> anrdroid/client/health: Cache fd and close on channel disconnection
>
> android/client/if-hl.c | 9 ++
> android/health.c | 415 +++++++++++++++++++++++++++++++++++++++++++------
> 2 files changed, 376 insertions(+), 48 deletions(-)
>
>

All patches are now applied, thanks.

--
Best regards,
Szymon Janc

2014-06-22 11:59:01

by Ravi kumar Veeramally

[permalink] [raw]
Subject: [PATCH_v3 6/6] anrdroid/client/health: Cache fd and close on channel disconnection

Cache fd and close them on channel disconnect or destroy notification.
When running PTS tests it is expecting to close all data channels before
exiting test case.
---
android/client/if-hl.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/android/client/if-hl.c b/android/client/if-hl.c
index 557a205..5940526 100644
--- a/android/client/if-hl.c
+++ b/android/client/if-hl.c
@@ -17,6 +17,7 @@

#include<stdio.h>
#include<ctype.h>
+#include<unistd.h>

#include<hardware/bluetooth.h>
#include<hardware/bt_hl.h>
@@ -52,6 +53,7 @@ SINTMAP(bthl_channel_state_t, -1, "(unknown)")
ENDMAP

const bthl_interface_t *if_hl = NULL;
+static int fd_list[256] = {-1};

static void app_reg_state_cb(int app_id, bthl_app_reg_state_t state)
{
@@ -69,6 +71,13 @@ static void channel_state_cb(int app_id, bt_bdaddr_t *bd_addr,
"channel_id=%d channel_state=%s fd=%d\n", __func__,
app_id, bt_bdaddr_t2str(bd_addr, addr), mdep_cfg_index,
channel_id, bthl_channel_state_t2str(state), fd);
+
+ if (state == BTHL_CONN_STATE_CONNECTED)
+ fd_list[channel_id] = fd;
+
+ if (state == BTHL_CONN_STATE_DISCONNECTED ||
+ state == BTHL_CONN_STATE_DESTROYED)
+ close(fd_list[channel_id]);
}

static bthl_callbacks_t hl_cbacks = {
--
1.9.1


2014-06-22 11:58:58

by Ravi kumar Veeramally

[permalink] [raw]
Subject: [PATCH_v3 3/6] android/health: Notify channel status on channel destroy call

---
android/health.c | 64 ++++++++++++++++++++++++++++----------------------------
1 file changed, 32 insertions(+), 32 deletions(-)

diff --git a/android/health.c b/android/health.c
index a68f5e9..c68bf15 100644
--- a/android/health.c
+++ b/android/health.c
@@ -115,6 +115,37 @@ struct health_app {
struct queue *devices;
};

+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 void send_channel_state_notify(struct health_channel *channel,
+ uint8_t state, int fd)
+{
+ struct hal_ev_health_channel_state ev;
+
+ DBG("");
+
+ bdaddr2android(&channel->dev->dst, ev.bdaddr);
+ ev.app_id = channel->dev->app_id;
+ ev.mdep_index = channel->mdep_id;
+ ev.channel_id = channel->id;
+ ev.channel_state = state;
+
+ ipc_send_notif_with_fd(hal_ipc, HAL_SERVICE_ID_HEALTH,
+ HAL_EV_HEALTH_CHANNEL_STATE,
+ sizeof(ev), &ev, fd);
+}
+
static void free_health_channel(void *data)
{
struct health_channel *channel = data;
@@ -132,7 +163,7 @@ static void destroy_channel(void *data)
if (!channel)
return;

- /* TODO: Notify channel connection status DESTROYED */
+ send_channel_state_notify(channel, HAL_HEALTH_CHANNEL_DESTROYED, -1);
queue_remove(channel->dev->channels, channel);
free_health_channel(channel);
}
@@ -187,37 +218,6 @@ 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 void send_channel_state_notify(struct health_channel *channel,
- uint8_t state, int fd)
-{
- struct hal_ev_health_channel_state ev;
-
- DBG("");
-
- bdaddr2android(&channel->dev->dst, ev.bdaddr);
- ev.app_id = channel->dev->app_id;
- ev.mdep_index = channel->mdep_id;
- ev.channel_id = channel->id;
- ev.channel_state = state;
-
- ipc_send_notif_with_fd(hal_ipc, HAL_SERVICE_ID_HEALTH,
- HAL_EV_HEALTH_CHANNEL_STATE,
- sizeof(ev), &ev, fd);
-}
-
static bool dev_by_addr(const void *data, const void *user_data)
{
const struct health_device *dev = data;
--
1.9.1


2014-06-22 11:58:59

by Ravi kumar Veeramally

[permalink] [raw]
Subject: [PATCH_v3 4/6] android/health: Create and connect MDL

Request for md_create_mdl and on successful response
connect mdl and pass fd. First data channel should be reliable
data channel.
---
android/health.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 119 insertions(+), 2 deletions(-)

diff --git a/android/health.c b/android/health.c
index c68bf15..6003aaa 100644
--- a/android/health.c
+++ b/android/health.c
@@ -146,6 +146,16 @@ static void send_channel_state_notify(struct health_channel *channel,
sizeof(ev), &ev, fd);
}

+static void unref_mdl(struct health_channel *channel)
+{
+ if (!channel || !channel->mdl)
+ return;
+
+ mcap_mdl_unref(channel->mdl);
+ channel->mdl = NULL;
+ channel->mdl_conn = false;
+}
+
static void free_health_channel(void *data)
{
struct health_channel *channel = data;
@@ -153,6 +163,7 @@ static void free_health_channel(void *data)
if (!channel)
return;

+ unref_mdl(channel);
free(channel);
}

@@ -1016,6 +1027,93 @@ static void mcap_mdl_reconn_req_cb(struct mcap_mdl *mdl, void *data)
DBG("Not Implemeneted");
}

+static void connect_mdl_cb(struct mcap_mdl *mdl, GError *gerr, gpointer data)
+{
+ struct health_channel *channel = data;
+ int fd;
+
+ DBG("");
+
+ if (gerr) {
+ error("health: error connecting to MDL %s", gerr->message);
+ goto fail;
+ }
+
+ fd = mcap_mdl_get_fd(channel->mdl);
+ if (fd < 0) {
+ error("health: error retrieving fd");
+ goto fail;
+ }
+
+ info("health: MDL connected");
+ channel->mdl_conn = true;
+
+ /* first data channel should be reliable data channel */
+ if (!queue_length(channel->dev->channels))
+ if (channel->type != CHANNEL_TYPE_RELIABLE)
+ goto fail;
+
+ send_channel_state_notify(channel, HAL_HEALTH_CHANNEL_CONNECTED, fd);
+
+ return;
+
+fail:
+ /* TODO: mcap_mdl_abort */
+ destroy_channel(channel);
+}
+
+static void create_mdl_cb(struct mcap_mdl *mdl, uint8_t type, GError *gerr,
+ gpointer data)
+{
+ struct health_channel *channel = data;
+ uint8_t mode;
+ GError *err = NULL;
+
+ DBG("");
+ if (gerr) {
+ error("health: error creating MDL %s", gerr->message);
+ goto fail;
+ }
+
+ if (channel->type == CHANNEL_TYPE_ANY && type != CHANNEL_TYPE_ANY)
+ channel->type = type;
+
+ /*
+ * if requested channel type is not same as preferred
+ * channel type from remote device, then abort the connection.
+ */
+ if (channel->type != type) {
+ /* TODO: abort mdl */
+ error("abort, channel-type requested %d, preferred %d not same",
+ channel->type, type);
+ goto fail;
+ }
+
+ if (!channel->mdl)
+ channel->mdl = mcap_mdl_ref(mdl);
+
+ channel->type = type;
+ channel->mdl_id = mcap_mdl_get_mdlid(mdl);
+
+ if (channel->type == CHANNEL_TYPE_RELIABLE)
+ mode = L2CAP_MODE_ERTM;
+ else
+ mode = L2CAP_MODE_STREAMING;
+
+ if (!mcap_connect_mdl(channel->mdl, mode, channel->dev->dcpsm,
+ connect_mdl_cb, channel,
+ NULL, &err)) {
+ error("health: error connecting to mdl");
+ g_error_free(err);
+ goto fail;
+ }
+
+ return;
+
+fail:
+ destroy_channel(channel);
+}
+
static bool check_role(uint8_t rec_role, uint8_t app_role)
{
if ((rec_role == HAL_HEALTH_MDEP_ROLE_SINK &&
@@ -1078,7 +1176,8 @@ static void get_mdep_cb(sdp_list_t *recs, int err, gpointer user_data)
struct health_channel *channel = user_data;
struct health_app *app;
struct mdep_cfg *mdep;
- uint8_t mdep_id;
+ uint8_t mdep_id, type;
+ GError *gerr = NULL;

if (err < 0 || !recs) {
error("health: error getting remote SDP records");
@@ -1102,7 +1201,18 @@ static void get_mdep_cb(sdp_list_t *recs, int err, gpointer user_data)

channel->remote_mdep = mdep_id;

- /* TODO : create mdl */
+ if (mdep->role == HAL_HEALTH_MDEP_ROLE_SOURCE)
+ type = channel->type;
+ else
+ type = CHANNEL_TYPE_ANY;
+
+ if (!mcap_create_mdl(channel->dev->mcl, channel->remote_mdep,
+ type, create_mdl_cb, channel, NULL, &gerr)) {
+ error("health: error creating mdl %s", gerr->message);
+ g_error_free(gerr);
+ goto fail;
+ }
+
return;

fail:
@@ -1345,6 +1455,13 @@ static void bt_health_connect_channel(const void *buf, uint16_t len)
if (!channel)
goto fail;

+ if (!queue_length(dev->channels)) {
+ if (channel->type != CHANNEL_TYPE_RELIABLE) {
+ error("error, first data shannel should be reliable");
+ goto fail;
+ }
+ }
+
if (!dev->mcl) {
if (connect_mcl(channel) < 0) {
error("health:error retrieving HDP SDP record");
--
1.9.1


2014-06-22 11:58:57

by Ravi kumar Veeramally

[permalink] [raw]
Subject: [PATCH_v3 2/6] android/health: Cache remote mdep id on channel connect request

Remote mdep is required to initiate MD_CREATE_MDL_REQ request.
---
android/health.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 123 insertions(+), 1 deletion(-)

diff --git a/android/health.c b/android/health.c
index 21c3bcd..a68f5e9 100644
--- a/android/health.c
+++ b/android/health.c
@@ -95,6 +95,11 @@ struct health_channel {

struct health_device *dev;

+ uint8_t remote_mdep;
+ struct mcap_mdl *mdl;
+ bool mdl_conn;
+ uint16_t mdl_id; /* MDL ID */
+
uint16_t id; /* channel id */
};

@@ -1011,6 +1016,111 @@ static void mcap_mdl_reconn_req_cb(struct mcap_mdl *mdl, void *data)
DBG("Not Implemeneted");
}

+static bool check_role(uint8_t rec_role, uint8_t app_role)
+{
+ if ((rec_role == HAL_HEALTH_MDEP_ROLE_SINK &&
+ app_role == HAL_HEALTH_MDEP_ROLE_SOURCE) ||
+ (rec_role == HAL_HEALTH_MDEP_ROLE_SOURCE &&
+ app_role == HAL_HEALTH_MDEP_ROLE_SINK))
+ return true;
+
+ return false;
+}
+
+static bool get_mdep_from_rec(const sdp_record_t *rec, uint8_t role,
+ uint16_t d_type, uint8_t *mdep)
+{
+ sdp_data_t *list, *feat;
+
+ if (!mdep)
+ return false;
+
+ list = sdp_data_get(rec, SDP_ATTR_SUPPORTED_FEATURES_LIST);
+ if (!list || !SDP_IS_SEQ(list->dtd))
+ return false;
+
+ for (feat = list->val.dataseq; feat; feat = feat->next) {
+ sdp_data_t *data_type, *mdepid, *role_t;
+
+ if (!SDP_IS_SEQ(feat->dtd))
+ continue;
+
+ mdepid = feat->val.dataseq;
+ if (!mdepid)
+ continue;
+
+ data_type = mdepid->next;
+ if (!data_type)
+ continue;
+
+ role_t = data_type->next;
+ if (!role_t)
+ continue;
+
+ if (data_type->dtd != SDP_UINT16 || mdepid->dtd != SDP_UINT8 ||
+ role_t->dtd != SDP_UINT8)
+ continue;
+
+ if (data_type->val.uint16 != d_type ||
+ !check_role(role_t->val.uint8, role))
+ continue;
+
+ *mdep = mdepid->val.uint8;
+
+ return true;
+ }
+
+ return false;
+}
+
+static void get_mdep_cb(sdp_list_t *recs, int err, gpointer user_data)
+{
+ struct health_channel *channel = user_data;
+ struct health_app *app;
+ struct mdep_cfg *mdep;
+ uint8_t mdep_id;
+
+ if (err < 0 || !recs) {
+ error("health: error getting remote SDP records");
+ goto fail;
+ }
+
+ app = queue_find(apps, app_by_app_id, INT_TO_PTR(channel->dev->app_id));
+ if (!app)
+ goto fail;
+
+ mdep = queue_find(app->mdeps, mdep_by_mdep_id,
+ INT_TO_PTR(channel->mdep_id));
+ if (!mdep)
+ goto fail;
+
+ if (!get_mdep_from_rec(recs->data, mdep->role, mdep->data_type,
+ &mdep_id)) {
+ error("health: no matching MDEP found");
+ goto fail;
+ }
+
+ channel->remote_mdep = mdep_id;
+
+ /* TODO : create mdl */
+ return;
+
+fail:
+ destroy_channel(channel);
+}
+
+static int get_mdep(struct health_channel *channel)
+{
+ uuid_t uuid;
+
+ DBG("");
+
+ bt_string2uuid(&uuid, HDP_UUID);
+
+ return bt_search_service(&adapter_addr, &channel->dev->dst, &uuid,
+ get_mdep_cb, channel, NULL, 0);
+}
+
static void create_mcl_cb(struct mcap_mcl *mcl, GError *err, gpointer data)
{
struct health_channel *channel = data;
@@ -1047,7 +1157,11 @@ static void create_mcl_cb(struct mcap_mcl *mcl, GError *err, gpointer data)
goto fail;
}

- /* TODO : create mdl */
+ if (get_mdep(channel) < 0) {
+ error("health: error getting remote MDEP from SDP record");
+ goto fail;
+ }
+
return;

fail:
@@ -1236,6 +1350,14 @@ static void bt_health_connect_channel(const void *buf, uint16_t len)
error("health:error retrieving HDP SDP record");
goto fail;
}
+ } else {
+ /* data channel is already connected */
+ if (channel->mdl && channel->mdl_conn)
+ goto fail;
+
+ /* create mdl if it does not exists */
+ if (!channel->mdl && get_mdep(channel) < 0)
+ goto fail;
}

rsp.channel_id = channel->id;
--
1.9.1


2014-06-22 11:59:00

by Ravi kumar Veeramally

[permalink] [raw]
Subject: [PATCH_v3 5/6] android/health: Implement mcap_mdl_deleted_cb

mcap_mdl_deleted_cb will be called if remote device sends MDL_DELETE_REQ.
Free channel data and notify channel is destroyed.
---
android/health.c | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/android/health.c b/android/health.c
index 6003aaa..effa5e2 100644
--- a/android/health.c
+++ b/android/health.c
@@ -1006,9 +1006,30 @@ static void mcap_mdl_closed_cb(struct mcap_mdl *mdl, void *data)
DBG("Not Implemeneted");
}

+static void notify_channel(void *data, void *user_data)
+{
+ struct health_channel *channel = data;
+
+ send_channel_state_notify(channel, HAL_HEALTH_CHANNEL_DESTROYED, -1);
+}
+
static void mcap_mdl_deleted_cb(struct mcap_mdl *mdl, void *data)
{
- DBG("Not Implemeneted");
+ struct health_channel *channel = data;
+ struct health_device *dev;
+
+ DBG("");
+
+ dev = channel->dev;
+ /* mdl == NULL means, delete all mdls */
+ if (!mdl) {
+ queue_foreach(dev->channels, notify_channel, NULL);
+ queue_destroy(dev->channels, free_health_channel);
+ dev->channels = NULL;
+ return;
+ }
+
+ destroy_channel(channel);
}

static void mcap_mdl_aborted_cb(struct mcap_mdl *mdl, void *data)
--
1.9.1


2014-06-22 11:58:56

by Ravi kumar Veeramally

[permalink] [raw]
Subject: [PATCH_v3 1/6] android/health: Check if device and channel already exists or not

On channel connect request, check if device is already exists or not.
Also check if channel is already created for remote device or not.
---
android/health.c | 107 ++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 83 insertions(+), 24 deletions(-)

diff --git a/android/health.c b/android/health.c
index 7553467..21c3bcd 100644
--- a/android/health.c
+++ b/android/health.c
@@ -213,6 +213,22 @@ static void send_channel_state_notify(struct health_channel *channel,
sizeof(ev), &ev, fd);
}

+static bool dev_by_addr(const void *data, const void *user_data)
+{
+ const struct health_device *dev = data;
+ const bdaddr_t *addr = user_data;
+
+ return !bacmp(&dev->dst, addr);
+}
+
+static bool channel_by_mdep_id(const void *data, const void *user_data)
+{
+ const struct health_channel *channel = data;
+ uint16_t mdep_id = PTR_TO_INT(user_data);
+
+ return channel->mdep_id == mdep_id;
+}
+
static bool mdep_by_mdep_role(const void *data, const void *user_data)
{
const struct mdep_cfg *mdep = data;
@@ -1094,8 +1110,14 @@ static int connect_mcl(struct health_channel *channel)

static struct health_device *create_device(uint16_t app_id, const uint8_t *addr)
{
+ struct health_app *app;
struct health_device *dev;

+ app = queue_find(apps, app_by_app_id, INT_TO_PTR(app_id));
+ if (!app)
+ return NULL;
+
+ /* create device and push it to devices queue */
dev = new0(struct health_device, 1);
if (!dev)
return NULL;
@@ -1108,11 +1130,35 @@ static struct health_device *create_device(uint16_t app_id, const uint8_t *addr)
return NULL;
}

+ if (!queue_push_tail(app->devices, dev)) {
+ free_health_device(dev);
+ return NULL;
+ }
+
return dev;
}

+static struct health_device *get_device(uint16_t app_id, const uint8_t *addr)
+{
+ struct health_app *app;
+ struct health_device *dev;
+ bdaddr_t bdaddr;
+
+ app = queue_find(apps, app_by_app_id, INT_TO_PTR(app_id));
+ if (!app)
+ return NULL;
+
+ android2bdaddr(addr, &bdaddr);
+ dev = queue_find(app->devices, dev_by_addr, &bdaddr);
+ if (dev)
+ return dev;
+
+ return create_device(app_id, addr);
+}
+
static struct health_channel *create_channel(uint16_t app_id,
- uint8_t mdep_index)
+ uint8_t mdep_index,
+ struct health_device *dev)
{
struct health_app *app;
struct mdep_cfg *mdep;
@@ -1120,6 +1166,9 @@ static struct health_channel *create_channel(uint16_t app_id,
uint8_t index;
static unsigned int channel_id = 1;

+ if (!dev)
+ return NULL;
+
app = queue_find(apps, app_by_app_id, INT_TO_PTR(app_id));
if (!app)
return NULL;
@@ -1129,53 +1178,64 @@ static struct health_channel *create_channel(uint16_t app_id,
if (!mdep)
return NULL;

+ /* create channel and push it to device */
channel = new0(struct health_channel, 1);
if (!channel)
return NULL;

- channel->mdep_id = mdep_index;
+ channel->mdep_id = mdep->id;
channel->type = mdep->channel_type;
channel->id = channel_id++;
+ channel->dev = dev;
+
+ if (!queue_push_tail(dev->channels, channel)) {
+ free_health_channel(channel);
+ return NULL;
+ }

return channel;
}

+static struct health_channel *get_channel(uint16_t app_id,
+ uint8_t mdep_index,
+ struct health_device *dev)
+{
+ struct health_channel *channel;
+ uint8_t index;
+
+ if (!dev)
+ return NULL;
+
+ index = mdep_index + 1;
+ channel = queue_find(dev->channels, channel_by_mdep_id,
+ INT_TO_PTR(index));
+ if (channel)
+ return channel;
+
+ return create_channel(app_id, mdep_index, dev);
+}
static void bt_health_connect_channel(const void *buf, uint16_t len)
{
const struct hal_cmd_health_connect_channel *cmd = buf;
struct hal_rsp_health_connect_channel rsp;
- struct health_app *app;
struct health_device *dev = NULL;
struct health_channel *channel = NULL;

DBG("");

- app = queue_find(apps, app_by_app_id, INT_TO_PTR(cmd->app_id));
- if (!app)
- goto fail;
-
- dev = create_device(cmd->app_id, cmd->bdaddr);
+ dev = get_device(cmd->app_id, cmd->bdaddr);
if (!dev)
goto fail;

- channel = create_channel(cmd->app_id, cmd->mdep_index);
+ channel = get_channel(cmd->app_id, cmd->mdep_index, dev);
if (!channel)
goto fail;

- channel->dev = dev;
-
- if (!queue_push_tail(app->devices, dev))
- goto fail;
-
- if (!queue_push_tail(dev->channels, channel)) {
- queue_remove(app->devices, dev);
- goto fail;
- }
-
- if (connect_mcl(channel) < 0) {
- error("error retrieving HDP SDP record");
- queue_remove(app->devices, dev);
- goto fail;
+ if (!dev->mcl) {
+ if (connect_mcl(channel) < 0) {
+ error("health:error retrieving HDP SDP record");
+ goto fail;
+ }
}

rsp.channel_id = channel->id;
@@ -1186,7 +1246,6 @@ static void bt_health_connect_channel(const void *buf, uint16_t len)

fail:
free_health_channel(channel);
- free_health_device(dev);
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_HEALTH,
HAL_OP_HEALTH_CONNECT_CHANNEL, HAL_STATUS_FAILED);
}
--
1.9.1