Next patches are aplied over the MCAP patches sended to thie mailing list by
Santiago Carot. This a first patches manage the creation of links beetween
instances and begins the support for creating data chanels, but doesn't
finish it yet.
Regards
Hi Jose,
* Jose Antonio Santos Cadenas <[email protected]> [2010-06-02 15:18:56 +0200]:
> Next patches are aplied over the MCAP patches sended to thie mailing list by
> Santiago Carot. This a first patches manage the creation of links beetween
> instances and begins the support for creating data chanels, but doesn't
> finish it yet.
For debug use the DBG() function instead of debug(). Change your patches
to match this and use the new dynamic debug feature.
--
Gustavo F. Padovan
http://padovan.org
Hi,
El Wednesday 02 June 2010 15:51:59 Johan Hedberg escribi?:
> Hi,
>
> On Wed, Jun 02, 2010, Jose Antonio Santos Cadenas wrote:
> > Next patches are aplied over the MCAP patches sended to thie mailing list
> > by Santiago Carot. This a first patches manage the creation of links
> > beetween instances and begins the support for creating data chanels, but
> > doesn't finish it yet.
>
> Could you give the address of your public git tree, please. It'd be
> easier to deal with than this huge amount of patches on the mailing
> list.
We are using gitorious for developing. All the sent patches (mcap and hdp) are
applied on this branch:
http://gitorious.org/bluez-mcap-hdp/bluez-mcap-hdp/commits/hdp_mcap_sent
Clone url:
git://gitorious.org/bluez-mcap-hdp/bluez-mcap-hdp.git
Branch:
hdp_mcap_sent
>
> Johan
Regards
Jose.
Hi,
On Wed, Jun 02, 2010, Jose Antonio Santos Cadenas wrote:
> Next patches are aplied over the MCAP patches sended to thie mailing list by
> Santiago Carot. This a first patches manage the creation of links beetween
> instances and begins the support for creating data chanels, but doesn't
> finish it yet.
Could you give the address of your public git tree, please. It'd be
easier to deal with than this huge amount of patches on the mailing
list.
Johan
---
health/hdp.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++----
health/hdp_types.h | 5 ++++
2 files changed, 67 insertions(+), 6 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index a38cbe0..1d626d7 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -107,6 +107,13 @@ static struct hdp_link *find_health_link(struct hdp_adapter *adapter,
return NULL;
}
+static int hdp_supp_fts_mdepcmp(gconstpointer ft, gconstpointer mdepid)
+{
+ const struct hdp_supp_fts *fts = ft;
+
+ return bcmp(&fts->mdepid, mdepid, sizeof(uint8_t));
+}
+
static int hdp_instance_idcmp(gconstpointer instance, gconstpointer p)
{
const struct hdp_instance *hdpi = instance;
@@ -379,19 +386,65 @@ static void hdp_mcap_mdl_closed_cb(struct mcap_mdl *mdl, void *data)
debug("TODO: Incomplete callback, mdl closed");
}
-static uint8_t hdp_mcap_mdl_conn_req_cb(struct mcap_mdl *mdl, void *data)
+static uint8_t hdp_mcap_mdl_reconn_req_cb(struct mcap_mdl *mdl, void *data)
{
/* struct hdp_link *hdpl = data; */
debug("TODO: Incomplete callback, mdl connection request");
return MCAP_REQUEST_NOT_SUPPORTED;
}
-static uint8_t hdp_mcap_mdl_reconn_req_cb(struct mcap_mcl *mcl,
- uint8_t mdepid, uint16_t mdlid,
- uint8_t *conf, void *data)
+static uint8_t hdp_mcap_mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid,
+ uint16_t mdlid, uint8_t *conf, void *data)
{
- debug("TODO: Incomplete callback, mdl reconnection request");
- return MCAP_REQUEST_NOT_SUPPORTED;
+ struct hdp_link *hdpl = data;
+ struct hdp_supp_fts *f;
+ struct hdp_dc *dc;
+ uint8_t new_conf;
+ GSList *l;
+
+ l = g_slist_find_custom(hdpl->hdpi->config->supp_fts, &mdepid,
+ hdp_supp_fts_mdepcmp);
+ if (!l)
+ return MCAP_INVALID_MDEP;
+ f = l->data;
+
+ /* Check if is the first dc if so,
+ * only reliable configuration is allowed */
+ switch(*conf) {
+ case HDP_NO_PREFERENCE_DC:
+ if (f->role == HDP_SINK)
+ return MCAP_CONFIGURATION_REJECTED;
+ else
+ new_conf = HDP_RELIABLE_DC;
+ break;
+ case HDP_STREAMING_DC:
+ if (g_slist_length(hdpl->channels) == 0)
+ return MCAP_CONFIGURATION_REJECTED;
+ case HDP_RELIABLE_DC:
+ if (f->role == HDP_SOURCE)
+ return MCAP_CONFIGURATION_REJECTED;
+ new_conf = *conf;
+ break;
+ default:
+ /* Special case defined in HDP spec 3.4. When an invalid
+ * configuration is received we need close the MCL when
+ * we are still processing the callback. When MCL is
+ * closed in a callback the returned value won't be
+ * proccesed in MCAP */
+ /* TODO: Send MCL disconnection to agent */
+ g_dbus_unregister_interface(hdpl->hdpi->adapter->conn,
+ hdpl->path, HEALTH_LINK);
+ return MCAP_CONFIGURATION_REJECTED; /* not processed */
+ }
+ *conf = new_conf;
+
+ dc = g_new0(struct hdp_dc, 1);
+ dc->hdpl = hdpl;
+ dc->conf = *conf;
+ dc->mdlid = mdlid;
+
+ hdpl->ndc = dc;
+ return MCAP_SUCCESS;
}
static void health_link_free(struct hdp_link *hdpl)
@@ -406,6 +459,9 @@ static void health_link_free(struct hdp_link *hdpl)
if (hdpl->path)
g_free(hdpl->path);
+ if (hdpl->ndc)
+ g_free(hdpl->ndc);
+
hdpl->hdpi->hlink = g_slist_remove(hdpl->hdpi->hlink, hdpl);
g_free(hdpl);
}
diff --git a/health/hdp_types.h b/health/hdp_types.h
index 6d41e2b..abbfbf3 100644
--- a/health/hdp_types.h
+++ b/health/hdp_types.h
@@ -46,6 +46,10 @@
#define HEALTH_DEVICE "org.bluez.HealthDevice"
#define HEALTH_LINK "org.bluez.HealthLink"
+#define HDP_NO_PREFERENCE_DC 0x00
+#define HDP_RELIABLE_DC 0x01
+#define HDP_STREAMING_DC 0x02
+
typedef enum {
HDP_DIC_PARSE_ERROR,
HDP_DIC_ENTRY_PARSE_ERROR,
@@ -113,6 +117,7 @@ struct hdp_link {
GSList *channels; /* Data channels */
char *path; /* HDP link path */
uint32_t id; /* Health link id */
+ struct hdp_dc *ndc; /* Data channel negotiated */
};
struct hdp_dc {
--
1.6.3.3
---
health/hdp_util.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 69 insertions(+), 5 deletions(-)
diff --git a/health/hdp_util.c b/health/hdp_util.c
index a6d09c5..b59e4e3 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -781,11 +781,6 @@ static gboolean register_data_exchange_spec(struct hdp_config *config,
return TRUE;
}
-GSList *hdp_get_end_points(const sdp_record_t *rec)
-{
- return NULL;
-}
-
static gboolean register_mcap_features(sdp_record_t *sdp_record)
{
sdp_data_t *mcap_proc;
@@ -887,3 +882,72 @@ gboolean hdp_get_data_exchange_spec(const sdp_record_t *rec, guint8 *val)
*val = exspec->val.uint8;
return TRUE;
}
+
+static gint cmp_feat_mdep(gconstpointer a, gconstpointer b)
+{
+ const struct hdp_supp_fts *fts = a;
+ const guint8 *mdep = b;
+
+ if (fts->mdepid == *mdep)
+ return 0;
+ return -1;
+}
+
+static GSList *get_feature(GSList *epl, sdp_data_t *feat_seq)
+{
+ struct hdp_supp_fts *fts;
+ struct hdp_feature *feat;
+ GSList *l;
+ sdp_data_t *mdepid, *dtype, *role, *desc;
+
+ mdepid = feat_seq;
+ if (!mdepid || mdepid->dtd != SDP_UINT8)
+ return epl;
+ dtype = mdepid->next;
+ if (!dtype || dtype->dtd != SDP_UINT16)
+ return epl;
+ role = dtype->next;
+ if (!role || role->dtd != SDP_UINT8)
+ return epl;
+ desc = role->next;
+
+ l = g_slist_find_custom(epl, &mdepid->val.uint8, cmp_feat_mdep);
+ if (l) {
+ fts = l->data;
+ if (fts->role != role->val.uint8)
+ return epl;
+ } else {
+ fts = g_new0(struct hdp_supp_fts, 1);
+ fts->mdepid = mdepid->val.uint8;
+ fts->role = role->val.uint8;
+ epl = g_slist_prepend(epl, fts);
+ }
+
+ feat = g_new0(struct hdp_feature, 1);
+ feat->dtype = dtype->val.uint16;
+ if (desc && desc->dtd == SDP_TEXT_STR8)
+ feat->dscr = g_strdup(desc->val.str);
+ fts->features = g_slist_prepend(fts->features, feat);
+ return epl;
+}
+
+GSList *hdp_get_end_points(const sdp_record_t *rec)
+{
+ GSList *epl = NULL;
+ sdp_data_t *end_points, *l;
+
+ end_points = sdp_data_get(rec, SDP_ATTR_SUPPORTED_FEATURES_LIST);
+
+ if (end_points->dtd != SDP_SEQ8)
+ return NULL;
+
+ for (l = end_points->val.dataseq; l; l = l->next) {
+ if (l->dtd != SDP_SEQ8)
+ continue;
+ epl = get_feature(epl, l->val.dataseq);
+ }
+
+ g_slist_foreach(epl, print_features, NULL);
+
+ return epl;
+}
--
1.6.3.3
---
health/hdp.c | 42 ++++++++++++++++++++++++++++++++++++++++--
1 files changed, 40 insertions(+), 2 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 10621c4..25a644c 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -117,7 +117,8 @@ static int hdp_instance_idcmp(gconstpointer instance, gconstpointer p)
return -1;
}
-static int hdp_link_mcl_cmp(gconstpointer link, gconstpointer mcl){
+static int hdp_link_mcl_cmp(gconstpointer link, gconstpointer mcl)
+{
const struct hdp_link *hdpl = link;
if (hdpl->mcl == mcl)
@@ -125,6 +126,17 @@ static int hdp_link_mcl_cmp(gconstpointer link, gconstpointer mcl){
return -1;
}
+static int hdp_link_addr_cmp(gconstpointer link, gconstpointer addr)
+{
+ const struct hdp_link *hdpl = link;
+ const bdaddr_t *dst;
+ bdaddr_t mcl_addr;
+
+ dst = addr;
+ mcl_addr = mcap_mcl_get_addr(hdpl->mcl);
+ return bacmp(addr, &mcl_addr);
+}
+
static void set_health_link_path(struct hdp_link *hdpl)
{
char path[MAX_PATH_LENGTH + 1];
@@ -534,12 +546,27 @@ fail:
g_dbus_send_message(device->conn, reply);
}
+static struct hdp_link *get_health_link(struct hdp_instance *hdpi,
+ struct hdp_device *device)
+{
+ bdaddr_t dst;
+ GSList *l;
+
+ device_get_address(device->dev, &dst);
+ l = g_slist_find_custom(hdpi->hlink, &dst, hdp_link_addr_cmp);
+ if (l)
+ return l->data;
+ return NULL;
+}
+
static DBusMessage *hdp_connect(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
struct hdp_device *device = user_data;
struct hdp_connection_cb *cb_data;
struct btd_adapter *adapter;
+ struct hdp_instance *hdpi;
+ struct hdp_link *hdpl;
bdaddr_t src, dst;
uint32_t lid, rid;
uuid_t uuid;
@@ -561,9 +588,20 @@ static DBusMessage *hdp_connect(DBusConnection *conn,
ERROR_INTERFACE ".InvalidArguments",
"Invalid local health instance id");
+ hdpi = l->data;
+ hdpl = get_health_link(hdpi, device);
+ if (hdpl) {
+ if (hdpl->closed) {
+ debug("Need a reconection");
+ /* TODO: Reconnect */;
+ } else
+ return g_dbus_create_reply(msg, DBUS_TYPE_OBJECT_PATH,
+ &hdpl->path, DBUS_TYPE_INVALID);
+ }
+
cb_data = g_new0(struct hdp_connection_cb, 1);
cb_data->device = device;
- cb_data->hdpi = l->data;
+ cb_data->hdpi = hdpi;
cb_data->rem_id = rid;
cb_data->msg = dbus_message_ref(msg);
--
1.6.3.3
---
health/hdp.c | 28 +++++++++++++++-------------
1 files changed, 15 insertions(+), 13 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 25a644c..a38cbe0 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -401,13 +401,10 @@ static void health_link_free(struct hdp_link *hdpl)
if (hdpl->mcl) {
mcap_close_mcl(hdpl->mcl, FALSE);
mcap_mcl_unref(hdpl->mcl);
- hdpl->mcl = NULL;
}
- if (hdpl->path) {
+ if (hdpl->path)
g_free(hdpl->path);
- hdpl->path = NULL;
- }
hdpl->hdpi->hlink = g_slist_remove(hdpl->hdpi->hlink, hdpl);
g_free(hdpl);
@@ -623,32 +620,37 @@ static DBusMessage *hdp_disconnect(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
struct hdp_device *device = user_data;
- struct hdp_link *hlink;
+ struct hdp_link *hdpl;
const char *path;
- const gboolean *del;
+ gboolean cache;
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_BOOLEAN, &del,
- DBUS_TYPE_INVALID)){
+ DBUS_TYPE_BOOLEAN, &cache,
+ DBUS_TYPE_INVALID)){
return g_dbus_create_error(msg,
ERROR_INTERFACE ".InvalidArguments",
"Invalid arguments in method call");
}
- hlink = find_health_link(device->hdp_adapter, path);
- if (!hlink)
+ hdpl = find_health_link(device->hdp_adapter, path);
+ if (!hdpl)
return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
"Health link does not found");
- return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
- "Not yet implemented");
+ if (cache) {
+ mcap_close_mcl(hdpl->mcl, cache);
+ hdpl->closed = TRUE;
+ } else
+ g_dbus_unregister_interface(conn, hdpl->path, HEALTH_LINK);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
static GDBusMethodTable device_methods[] = {
{ "GetHealthInstances", "", "aa{sv}", get_health_instances,
G_DBUS_METHOD_FLAG_ASYNC },
{ "Connect", "uu", "o", hdp_connect, G_DBUS_METHOD_FLAG_ASYNC },
- { "Diconnect", "ob", "", hdp_disconnect },
+ { "Disconnect", "ob", "", hdp_disconnect },
{ NULL }
};
--
1.6.3.3
---
health/hdp_types.h | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/health/hdp_types.h b/health/hdp_types.h
index 5db8e0d..6d41e2b 100644
--- a/health/hdp_types.h
+++ b/health/hdp_types.h
@@ -115,6 +115,13 @@ struct hdp_link {
uint32_t id; /* Health link id */
};
+struct hdp_dc {
+ struct hdp_link *hdpl; /* Health link */
+ struct mcap_mdl *mdl; /* MCAP MDL structure */
+ uint8_t conf; /* Requested conf */
+ uint16_t mdlid; /* MDL id */
+};
+
struct hdp_device {
DBusConnection *conn; /* For name listener handling */
struct btd_device *dev; /* Device reference */
--
1.6.3.3
---
health/hdp.c | 6 +++---
health/hdp_types.h | 7 ++++---
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index cd344d0..e99e00a 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -964,11 +964,11 @@ int hdp_adapter_register(DBusConnection *conn, struct btd_adapter *btd_adapter)
adapter = g_new0(struct hdp_adapter, 1);
debug("HDP init");
- if (!g_dbus_register_interface(conn, path, HEALTH_MANAGER_INTERFACE,
+ if (!g_dbus_register_interface(conn, path, HEALTH_MANAGER,
hdp_methods, NULL, NULL,
adapter, hdp_path_unregister)) {
error("Failed to register %s interface to %s",
- HEALTH_MANAGER_INTERFACE, path);
+ HEALTH_MANAGER, path);
g_free(adapter);
return -1;
}
@@ -988,7 +988,7 @@ void hdp_adapter_unregister(struct btd_adapter *btd_adapter)
g_dbus_unregister_interface(adapter->conn,
adapter_get_path(btd_adapter),
- HEALTH_MANAGER_INTERFACE);
+ HEALTH_MANAGER);
dbus_connection_unref(adapter->conn);
btd_adapter_unref(adapter->btd_adapter);
adapters = g_slist_remove(adapters, adapter);
diff --git a/health/hdp_types.h b/health/hdp_types.h
index abbfbf3..aff116e 100644
--- a/health/hdp_types.h
+++ b/health/hdp_types.h
@@ -42,9 +42,10 @@
#define HDP_ERROR g_quark_from_static_string("hdp-error-quark")
-#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
-#define HEALTH_DEVICE "org.bluez.HealthDevice"
-#define HEALTH_LINK "org.bluez.HealthLink"
+#define HEALTH_MANAGER "org.bluez.HealthAdapter"
+#define HEALTH_DEVICE "org.bluez.HealthDevice"
+#define HEALTH_LINK "org.bluez.HealthLink"
+#define HEALTH_AGENT "org.bluez.HealthAgent"
#define HDP_NO_PREFERENCE_DC 0x00
#define HDP_RELIABLE_DC 0x01
--
1.6.3.3
---
health/hdp.c | 58 ++++++++++++++++++++++++++++++++++++++++++---------
health/hdp_types.h | 5 ++++
health/hdp_util.c | 19 ++++++++++++----
3 files changed, 66 insertions(+), 16 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 19ff2f9..cb05324 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -37,10 +37,6 @@
#include "../src/dbus-common.h"
-#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
-#define HEALTH_DEVICE "org.bluez.HealthDevice"
-#define HEALTH_LINK "org.bluez.HealthLink"
-
static GSList *adapters = NULL;
static GSList *devices = NULL;
@@ -102,6 +98,14 @@ static int hdp_instance_idcmp(gconstpointer instance, gconstpointer p)
return -1;
}
+static int hdp_link_mcl_cmp(gconstpointer link, gconstpointer mcl){
+ const struct hdp_link *hdpl = link;
+
+ if (hdpl->mcl == mcl)
+ return 0;
+ return -1;
+}
+
static void set_health_link_path(struct hdp_link *hdpl)
{
char path[MAX_PATH_LENGTH + 1];
@@ -617,7 +621,7 @@ static void mcl_connected(struct mcap_mcl *mcl, gpointer data)
struct hdp_link *hdpl;
GError *err = NULL;
- debug("TODO: implement mcl_connected");
+ debug("mcl_connected");
hdpl = create_health_link(hdpi, mcl, &err);
if (err)
return;
@@ -627,20 +631,52 @@ static void mcl_connected(struct mcap_mcl *mcl, gpointer data)
static void mcl_reconnected(struct mcap_mcl *mcl, gpointer data)
{
- /* struct hdp_instance *hdpi = data; */
- debug("TODO: implement mcl_reconnected");
+ struct hdp_instance *hdpi = data;
+ struct hdp_link *hdpl;
+ GSList *l;
+
+ debug("mcl_reconnected");
+ l = g_slist_find_custom(hdpi->hlink, mcl, hdp_link_mcl_cmp);
+ if (l) {
+ hdpl = l->data;
+ hdpl->closed = FALSE;
+ return;
+ }
+
+ mcl_connected(mcl, data);
}
static void mcl_disconnected(struct mcap_mcl *mcl, gpointer data)
{
- /* struct hdp_instance *hdpi = data; */
- debug("TODO: implement mcl_disconnected");
+ struct hdp_instance *hdpi = data;
+ struct hdp_link *hdpl;
+ GSList *l;
+
+ debug("mcl_disconnected");
+ l = g_slist_find_custom(hdpi->hlink, mcl, hdp_link_mcl_cmp);
+ if (!l)
+ return;
+
+ hdpl = l->data;
+ hdpl->closed = TRUE;
}
static void mcl_uncached(struct mcap_mcl *mcl, gpointer data)
{
- /* struct hdp_instance *hdpi = data; */
- debug("TODO: implement mcl_uncached");
+ struct hdp_instance *hdpi = data;
+ struct hdp_link *hdpl;
+ GSList *l;
+
+ debug("mcl_uncached");
+ l = g_slist_find_custom(hdpi->hlink, mcl, hdp_link_mcl_cmp);
+ if (!l)
+ return;
+
+ hdpl = l->data;
+
+ hdpi->hlink = g_slist_remove(hdpi->hlink, hdpl);
+ g_dbus_unregister_interface(hdpi->adapter->conn, hdpl->path,
+ HEALTH_LINK);
}
static DBusMessage *hdp_create_instance(DBusConnection *conn,
diff --git a/health/hdp_types.h b/health/hdp_types.h
index 79419a1..5db8e0d 100644
--- a/health/hdp_types.h
+++ b/health/hdp_types.h
@@ -42,6 +42,10 @@
#define HDP_ERROR g_quark_from_static_string("hdp-error-quark")
+#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
+#define HEALTH_DEVICE "org.bluez.HealthDevice"
+#define HEALTH_LINK "org.bluez.HealthLink"
+
typedef enum {
HDP_DIC_PARSE_ERROR,
HDP_DIC_ENTRY_PARSE_ERROR,
@@ -105,6 +109,7 @@ struct hdp_instance {
struct hdp_link {
struct hdp_instance *hdpi; /* HDP session */
struct mcap_mcl *mcl; /* MCAP mcl */
+ gboolean closed; /* MCL is closed but cached */
GSList *channels; /* Data channels */
char *path; /* HDP link path */
uint32_t id; /* Health link id */
diff --git a/health/hdp_util.c b/health/hdp_util.c
index c54f55c..72d06df 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -109,15 +109,24 @@ static void free_config(struct hdp_config *config)
g_free(config);
}
+static void hdp_link_unregister(gpointer link, gpointer data)
+{
+ struct hdp_link *hdpl = link;
+ struct hdp_instance *hdpi = hdpl->hdpi;
+
+ hdpi->hlink = g_slist_remove(hdpi->hlink, hdpl);
+ g_dbus_unregister_interface(hdpi->adapter->conn, hdpl->path,
+ HEALTH_LINK);
+}
+
void hdp_instance_free(struct hdp_instance *hdpi)
{
debug("HDP instance %d is deleted", hdpi->id);
/* TODO: Complete this part */
- /*
- g_slist_foreach(hdpi->devices, hdp_device_unregister, NULL);
- g_slist_free(hdpi->devices);
- hdpi->devices = NULL;
- */
+
+ g_slist_foreach(hdpi->hlink, hdp_link_unregister, NULL);
+ g_slist_free(hdpi->hlink);
+ hdpi->hlink = NULL;
if (hdpi->dbus_watcher)
g_dbus_remove_watch(hdpi->adapter->conn, hdpi->dbus_watcher);
--
1.6.3.3
---
test/test-health | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 61 insertions(+), 0 deletions(-)
create mode 100755 test/test-health
diff --git a/test/test-health b/test/test-health
new file mode 100755
index 0000000..2129923
--- /dev/null
+++ b/test/test-health
@@ -0,0 +1,61 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import dbus
+import dbus.service
+import gobject
+from dbus.mainloop.glib import DBusGMainLoop
+
+agent_iface = 'org.bluez.HealthAgent'
+obj_path = "/org/bluez/test/health/agent"
+
+DBusGMainLoop(set_as_default=True)
+loop = gobject.MainLoop()
+
+bus = dbus.SystemBus()
+manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+ "org.bluez.Manager")
+
+hdp = dbus.Interface(bus.get_object("org.bluez", manager.DefaultAdapter()),
+ "org.bluez.HealthAdapter")
+
+class HDP(dbus.service.Object):
+ def __init__(self, bus, obj_path):
+ self.bus = bus
+ dbus.service.Object.__init__(self, self.bus, obj_path)
+ @dbus.service.method(agent_iface, in_signature='o', out_signature='',
+ sender_keyword='sender')
+ def LinkConnected(self, path, sender=None):
+ print "Connected new link %s: (sender %s)" % (path, sender)
+ @dbus.service.method(agent_iface, in_signature='o', out_signature='',
+ sender_keyword='sender')
+ def LinkDisconnected(self, path, sender=None):
+ print "Link %s: disconnected (sender: %s)" % (path, sender)
+
+session_id = hdp.CreateInstance(dbus.ObjectPath(obj_path),
+ {"data_spec": dbus.Byte(1, variant_level=1),
+ "end_points":dbus.Array([{ "role": dbus.String("sink", variant_level=1),
+ "specs": dbus.Array([{
+ "data_type":
+ dbus.UInt16(4100, variant_level =1),
+ "description":
+ dbus.String("Oximeter",
+ variant_level = 1),
+ },{
+ "data_type":
+ dbus.UInt16(4103, variant_level =1),
+ "description":
+ dbus.String("Blood pressure",
+ variant_level = 1),
+ }
+ ], variant_level=1),
+ },
+ ], variant_level=1)})
+
+hdp_obj = HDP(bus, obj_path);
+
+try:
+ print "Waiting for connections, push Ctrl+C to stop"
+ loop.run()
+except:
+ print "Loop interrupted, closing session"
--
1.6.3.3
---
health/hdp.c | 20 ++++++++++++--------
1 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 9678baa..7a726e0 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -56,6 +56,7 @@ struct hdp_connection_cb {
struct hdp_instance *hdpi;
uint32_t rem_id;
DBusMessage *msg;
+ struct hdp_link *hdpl;
};
static struct hdp_adapter *find_adapter(GSList *list,
@@ -554,11 +555,15 @@ static void hdp_mcl_connect_cb(struct mcap_mcl *mcl, GError *err, void *data)
if (err)
goto fail;
- hdpl = create_health_link(hdpi, mcl, &gerr);
- if (gerr)
- goto fail;
+ if (cb_data->hdpl)
+ hdpl = cb_data->hdpl;
+ else {
+ hdpl = create_health_link(hdpi, mcl, &gerr);
+ if (gerr)
+ goto fail;
+ hdpi->hlink = g_slist_prepend(hdpi->hlink, hdpl);
+ }
- hdpi->hlink = g_slist_prepend(hdpi->hlink, hdpl);
reply = g_dbus_create_reply(msg, DBUS_TYPE_OBJECT_PATH, &hdpl->path,
DBUS_TYPE_INVALID);
g_dbus_send_message(device->conn, reply);
@@ -664,10 +669,7 @@ static DBusMessage *hdp_connect(DBusConnection *conn,
hdpi = l->data;
hdpl = get_health_link(hdpi, device);
if (hdpl) {
- if (hdpl->closed) {
- debug("Need a reconection");
- /* TODO: Reconnect */;
- } else
+ if (!hdpl->closed)
return g_dbus_create_reply(msg, DBUS_TYPE_OBJECT_PATH,
&hdpl->path, DBUS_TYPE_INVALID);
}
@@ -677,6 +679,8 @@ static DBusMessage *hdp_connect(DBusConnection *conn,
cb_data->hdpi = hdpi;
cb_data->rem_id = rid;
cb_data->msg = dbus_message_ref(msg);
+ /* Used for reconnections */
+ cb_data->hdpl = hdpl;
adapter = device->hdp_adapter->btd_adapter;
adapter_get_address(adapter, &src);
--
1.6.3.3
From: José Antonio Santos Cadenas <[email protected]>
Whenever a MCL is discoinnected we shall notify to agents using
D-Bus callback.
---
health/hdp.c | 82 +++++++++++++++++++++++++++++++++++++--------------------
1 files changed, 53 insertions(+), 29 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index f7146eb..9678baa 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -393,10 +393,46 @@ static uint8_t hdp_mcap_mdl_reconn_req_cb(struct mcap_mdl *mdl, void *data)
return MCAP_REQUEST_NOT_SUPPORTED;
}
+static void health_link_free(struct hdp_link *hdpl)
+{
+ /*TODO: Release structures related with Data Channels */
+
+ if (hdpl->mcl) {
+ mcap_close_mcl(hdpl->mcl, FALSE);
+ mcap_mcl_unref(hdpl->mcl);
+ }
+
+ if (hdpl->path)
+ g_free(hdpl->path);
+
+ if (hdpl->ndc)
+ g_free(hdpl->ndc);
+
+ g_free(hdpl);
+}
+
+static gboolean agent_mcl_disconnect_msg(struct hdp_link *hdpl)
+{
+ struct hdp_instance *hdpi = hdpl->hdpi;
+ DBusMessage* message;
+
+ message = dbus_message_new_method_call(hdpi->aname, hdpi->apath,
+ HEALTH_AGENT, "LinkDisconnected");
+ if (!message) {
+ error("Couldn't allocate D-Bus message");
+ return FALSE;
+ }
+
+ dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &hdpl->path,
+ DBUS_TYPE_INVALID);
+ return g_dbus_send_message(hdpi->adapter->conn, message);
+}
+
static uint8_t hdp_mcap_mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid,
uint16_t mdlid, uint8_t *conf, void *data)
{
struct hdp_link *hdpl = data;
+ struct hdp_instance *hdpi;
struct hdp_supp_fts *f;
struct hdp_dc *dc;
uint8_t new_conf;
@@ -418,7 +454,7 @@ static uint8_t hdp_mcap_mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid,
new_conf = HDP_RELIABLE_DC;
break;
case HDP_STREAMING_DC:
- if (g_slist_length(hdpl->channels) == 0)
+ if (!hdpl->channels)
return MCAP_CONFIGURATION_REJECTED;
case HDP_RELIABLE_DC:
if (f->role == HDP_SOURCE)
@@ -427,13 +463,16 @@ static uint8_t hdp_mcap_mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid,
break;
default:
/* Special case defined in HDP spec 3.4. When an invalid
- * configuration is received we need close the MCL when
+ * configuration is received we shall close the MCL when
* we are still processing the callback. When MCL is
* closed in a callback the returned value won't be
* proccesed in MCAP */
- /* TODO: Send MCL disconnection to agent */
- g_dbus_unregister_interface(hdpl->hdpi->adapter->conn,
- hdpl->path, HEALTH_LINK);
+ hdpi = hdpl->hdpi;
+ hdpi->hlink = g_slist_remove(hdpi->hlink, hdpl);
+ agent_mcl_disconnect_msg(hdpl);
+ if (!g_dbus_unregister_interface(hdpi->adapter->conn,
+ hdpl->path, HEALTH_LINK))
+ health_link_free(hdpl);
return MCAP_CONFIGURATION_REJECTED; /* not processed */
}
*conf = new_conf;
@@ -447,25 +486,6 @@ static uint8_t hdp_mcap_mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid,
return MCAP_SUCCESS;
}
-static void health_link_free(struct hdp_link *hdpl)
-{
- /*TODO: Release structures related with Data Channels */
-
- if (hdpl->mcl) {
- mcap_close_mcl(hdpl->mcl, FALSE);
- mcap_mcl_unref(hdpl->mcl);
- }
-
- if (hdpl->path)
- g_free(hdpl->path);
-
- if (hdpl->ndc)
- g_free(hdpl->ndc);
-
- hdpl->hdpi->hlink = g_slist_remove(hdpl->hdpi->hlink, hdpl);
- g_free(hdpl);
-}
-
static void health_link_path_unregister(void *data)
{
struct hdp_link *hdpl = data;
@@ -696,8 +716,11 @@ static DBusMessage *hdp_disconnect(DBusConnection *conn,
if (cache) {
mcap_close_mcl(hdpl->mcl, cache);
hdpl->closed = TRUE;
- } else
- g_dbus_unregister_interface(conn, hdpl->path, HEALTH_LINK);
+ } else {
+ hdpl->hdpi->hlink = g_slist_remove(hdpl->hdpi->hlink, hdpl);
+ if (!g_dbus_unregister_interface(conn, hdpl->path, HEALTH_LINK))
+ health_link_free(hdpl);
+ }
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
@@ -788,7 +811,6 @@ static void mcl_connected(struct mcap_mcl *mcl, gpointer data)
}
error("D-Bus send failed");
health_link_free(hdpl);
- dbus_message_unref(message);
}
static void mcl_reconnected(struct mcap_mcl *mcl, gpointer data)
@@ -837,8 +859,10 @@ static void mcl_uncached(struct mcap_mcl *mcl, gpointer data)
hdpl = l->data;
hdpi->hlink = g_slist_remove(hdpi->hlink, hdpl);
- g_dbus_unregister_interface(hdpi->adapter->conn, hdpl->path,
- HEALTH_LINK);
+ agent_mcl_disconnect_msg(hdpl);
+ if (!g_dbus_unregister_interface(hdpi->adapter->conn, hdpl->path,
+ HEALTH_LINK))
+ health_link_free(hdpl);
}
static DBusMessage *hdp_create_instance(DBusConnection *conn,
--
1.6.3.3
---
health/hdp.c | 27 ++++++++++++++++++++++++---
src/bluetooth.conf | 1 +
2 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index e99e00a..f7146eb 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -760,14 +760,35 @@ static void mcl_connected(struct mcap_mcl *mcl, gpointer data)
{
struct hdp_instance *hdpi = data;
struct hdp_link *hdpl;
+ DBusMessage* message;
GError *err = NULL;
debug("mcl_connected");
+
+ message = dbus_message_new_method_call(hdpi->aname, hdpi->apath,
+ HEALTH_AGENT, "LinkConnected");
+ if (!message) {
+ error("Couldn't allocate D-Bus message");
+ return;
+ }
+
hdpl = create_health_link(hdpi, mcl, &err);
- if (err)
+ if (err) {
+ dbus_message_unref(message);
return;
- /* TODO: Send the notification to the Agent */
- hdpi->hlink = g_slist_prepend(hdpi->hlink, hdpl);
+ }
+
+ dbus_message_append_args(message,
+ DBUS_TYPE_OBJECT_PATH, &hdpl->path,
+ DBUS_TYPE_INVALID);
+
+ if (g_dbus_send_message(hdpi->adapter->conn, message)) {
+ hdpi->hlink = g_slist_prepend(hdpi->hlink, hdpl);
+ return;
+ }
+ error("D-Bus send failed");
+ health_link_free(hdpl);
+ dbus_message_unref(message);
}
static void mcl_reconnected(struct mcap_mcl *mcl, gpointer data)
diff --git a/src/bluetooth.conf b/src/bluetooth.conf
index 56e7a83..4471da5 100644
--- a/src/bluetooth.conf
+++ b/src/bluetooth.conf
@@ -12,6 +12,7 @@
<allow send_destination="org.bluez"/>
<allow send_interface="org.bluez.Agent"/>
<allow send_interface="org.bluez.HandsfreeAgent"/>
+ <allow send_interface="org.bluez.HealthAgent"/>
</policy>
<policy at_console="true">
--
1.6.3.3
---
health/hdp.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 45 insertions(+), 0 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index cb05324..10621c4 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -88,6 +88,25 @@ static struct hdp_device *find_device(GSList *devices, struct btd_device *dev)
return NULL;
}
+static struct hdp_link *find_health_link(struct hdp_adapter *adapter,
+ const char *link_path)
+{
+ struct hdp_instance *hdpi;
+ struct hdp_link *hdpl;
+ GSList *l, *ll;
+
+ for (l = adapter->instances; l; l = l->next) {
+ hdpi = l->data;
+ for (ll = hdpi->hlink; ll; ll = ll->next) {
+ hdpl = ll->data;
+ if (!strcmp(hdpl->path, link_path))
+ return hdpl;
+ }
+ }
+
+ return NULL;
+}
+
static int hdp_instance_idcmp(gconstpointer instance, gconstpointer p)
{
const struct hdp_instance *hdpi = instance;
@@ -562,10 +581,36 @@ static DBusMessage *hdp_connect(DBusConnection *conn,
"Error getting remote information");
}
+static DBusMessage *hdp_disconnect(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct hdp_device *device = user_data;
+ struct hdp_link *hlink;
+ const char *path;
+ const gboolean *del;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_BOOLEAN, &del,
+ DBUS_TYPE_INVALID)){
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+ }
+
+ hlink = find_health_link(device->hdp_adapter, path);
+ if (!hlink)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Health link does not found");
+
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Not yet implemented");
+}
+
static GDBusMethodTable device_methods[] = {
{ "GetHealthInstances", "", "aa{sv}", get_health_instances,
G_DBUS_METHOD_FLAG_ASYNC },
{ "Connect", "uu", "o", hdp_connect, G_DBUS_METHOD_FLAG_ASYNC },
+ { "Diconnect", "ob", "", hdp_disconnect },
{ NULL }
};
--
1.6.3.3
---
health/hdp.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 1d626d7..cd344d0 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -266,7 +266,7 @@ static void fill_up_health_instances(DBusMessageIter *dict, gpointer data)
}
}
-static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
+static void health_records_found(sdp_list_t *recs, int err, gpointer user_data)
{
struct instances_aux *cb_data = user_data;
DBusMessage *msg = cb_data->msg;
@@ -314,7 +314,7 @@ static DBusMessage *get_health_instances(DBusConnection *conn,
bt_string2uuid(&uuid, HDP_UUID);
- if (bt_search_service(&src, &dst, &uuid, sink_health_instances,
+ if (bt_search_service(&src, &dst, &uuid, health_records_found,
cb_data, NULL) == 0)
return NULL;
--
1.6.3.3
---
health/hdp.c | 82 ++++++++++++++++++++++++++++++++++++---------------------
1 files changed, 52 insertions(+), 30 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 7f25144..0a98118 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -369,28 +369,17 @@ static GDBusMethodTable health_link_methods[] = {
{ NULL }
};
-static void hdp_mcl_connect_cb(struct mcap_mcl *mcl, GError *err, void *data)
+static struct hdp_link *create_health_link(struct hdp_instance *hdpi,
+ struct mcap_mcl *mcl, GError **err)
{
- struct hdp_connection_cb *cb_data = data;
- struct hdp_device *device = cb_data->device;
- struct hdp_instance *hdpi = cb_data->hdpi;
- DBusMessage *msg = cb_data->msg;
- struct hdp_link *hdpl = NULL;
- GError *cberr = NULL;
- DBusMessage *reply;
-
- g_free(cb_data);
-
- if (err)
- goto fail;
+ struct hdp_link *hdpl;
hdpl = g_new0(struct hdp_link, 1);
hdpl->hdpi = hdpi;
- hdpl->dev = device;
hdpl->mcl = mcap_mcl_ref(mcl);
set_health_link_path(hdpl);
- mcap_mcl_set_cb(mcl, &cberr, hdpl,
+ mcap_mcl_set_cb(mcl, err, hdpl,
MCAP_MDL_CB_CONNECTED, hdp_mcap_mdl_connected_cb,
MCAP_MDL_CB_CLOSED, hdp_mcap_mdl_closed_cb,
MCAP_MDL_CB_DELETED, hdp_mcap_mdl_deleted_cb,
@@ -399,16 +388,46 @@ static void hdp_mcl_connect_cb(struct mcap_mcl *mcl, GError *err, void *data)
MCAP_MDL_CB_REMOTE_RECONN_REQ, hdp_mcap_mdl_reconn_req_cb,
MCAP_MDL_CB_INVALID);
- if (cberr)
- goto fail;
+ if (*err)
+ return NULL;
- if (!g_dbus_register_interface(hdpl->dev->conn, hdpl->path, HEALTH_LINK,
+ if (g_dbus_register_interface(hdpl->dev->conn, hdpl->path, HEALTH_LINK,
health_link_methods, NULL, NULL,
- hdpl, health_link_path_unregister)) {
- error("D-Bus failed to register %s interface to %s",
+ hdpl, health_link_path_unregister))
+ return hdpl;
+
+ g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Cant register the health link in the bus");
+
+ /* TODO create a function to free health link correctly */
+ /* MCAP will close the MCL and won't cache it if we didn't
+ * increase the MCL reference counter during the callback. */
+ mcap_mcl_unref(hdpl->mcl);
+ g_free(hdpl->path);
+ g_free(hdpl);
+ error("D-Bus failed to register %s interface to %s",
HEALTH_LINK, hdpl->path);
+ return NULL;
+}
+
+static void hdp_mcl_connect_cb(struct mcap_mcl *mcl, GError *err, void *data)
+{
+ struct hdp_connection_cb *cb_data = data;
+ struct hdp_device *device = cb_data->device;
+ struct hdp_instance *hdpi = cb_data->hdpi;
+ DBusMessage *msg = cb_data->msg;
+ struct hdp_link *hdpl = NULL;
+ GError *gerr = NULL;
+ DBusMessage *reply;
+
+ g_free(cb_data);
+
+ if (err)
+ goto fail;
+
+ hdpl = create_health_link(hdpi, mcl, &gerr);
+ if (gerr)
goto fail;
- }
hdpi->hlink = g_slist_prepend(hdpi->hlink, hdpl);
reply = g_dbus_create_reply(msg, DBUS_TYPE_OBJECT_PATH, &hdpl->path,
@@ -417,14 +436,9 @@ static void hdp_mcl_connect_cb(struct mcap_mcl *mcl, GError *err, void *data)
return;
fail:
reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HdpError",
- (err ? err->message : cberr->message));
- if (cberr) {
- /* MCAP will close the MCL and won't cache it if we didn't
- * increase the MCL reference counter during the callback. */
- mcap_mcl_unref(hdpl->mcl);
- g_free(hdpl->path);
- g_free(hdpl);
- g_error_free(cberr);
+ (err ? err->message : gerr->message));
+ if (gerr) {
+ g_error_free(gerr);
}
g_dbus_send_message(device->conn, reply);
@@ -578,8 +592,16 @@ static void client_disconnected(DBusConnection *connection, void *user_data)
static void mcl_connected(struct mcap_mcl *mcl, gpointer data)
{
- /* struct hdp_instance *hdpi = data; */
+ struct hdp_instance *hdpi = data;
+ struct hdp_link *hdpl;
+ GError *err = NULL;
+
debug("TODO: implement mcl_connected");
+ hdpl = create_health_link(hdpi, mcl, &err);
+ if (err)
+ return;
+ /* TODO: Send the notification to the Agent */
+ hdpi->hlink = g_slist_prepend(hdpi->hlink, hdpl);
}
static void mcl_reconnected(struct mcap_mcl *mcl, gpointer data)
--
1.6.3.3
---
health/hdp.c | 1 +
health/hdp_util.c | 52 +++++++++++++++++++++++++++++++++++++---------------
2 files changed, 38 insertions(+), 15 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 88e7235..7f25144 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -462,6 +462,7 @@ static void connect_health_instance(sdp_list_t *recs, int err, gpointer data)
goto fail;
}
+ info("psm = 0x%x, version = 0x%x", ccpsm, version);
device_get_address(device->dev, &dst);
mcap_create_mcl(hdpi->mi, &dst, ccpsm, &gerr, hdp_mcl_connect_cb,
cb_data);
diff --git a/health/hdp_util.c b/health/hdp_util.c
index 5ba61dc..c54f55c 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -884,29 +884,51 @@ gboolean hdp_get_data_exchange_spec(const sdp_record_t *rec, guint8 *val)
return TRUE;
}
+static gboolean get_prot_desc_entry(sdp_data_t *entry, int type, guint16 *val)
+{
+ sdp_data_t *iter;
+ int proto;
+
+ if (!entry || (entry->dtd != SDP_SEQ8))
+ return FALSE;
+
+ iter = entry->val.dataseq;
+ if (!(iter->dtd & SDP_UUID_UNSPEC))
+ return FALSE;
+
+ proto = sdp_uuid_to_proto(&iter->val.uuid);
+ if (proto != type)
+ return FALSE;
+
+ iter = iter->next;
+ if (iter->dtd != SDP_UINT16)
+ return FALSE;
+ if (val) {
+ *val = iter->val.uint16;
+ }
+ return TRUE;
+}
+
gboolean hdp_get_prot_desc_list(const sdp_record_t *rec, guint16 *psm,
guint16 *version)
{
- if (!(psm || version))
+ sdp_data_t *pdl, *p0, *p1;
+
+ if (!psm && !version)
return TRUE;
- /* TODO:
- sdp_data_t *pdl, *l;
+ pdl = sdp_data_get(rec, SDP_ATTR_PROTO_DESC_LIST);
+ if (pdl->dtd != SDP_SEQ8)
+ return FALSE;
+
+ p0 = pdl->val.dataseq;
- exspec = sdp_data_get(rec, SDP_ATTR_PROTO_DESC_LIST);
- if (exspec->dtd != SDP_SEQ8)
+ if (!get_prot_desc_entry(p0, L2CAP_UUID, psm))
+ return FALSE;
+ p1 = p0->next;
+ if (!get_prot_desc_entry(p1, MCAP_CTRL_UUID, version))
return FALSE;
- for (l = pdl->val.dataseq; l; l = l->next) {
- if (l->dtd != SDP_SEQ8)
- continue;
- epl = get_feature(epl, l->val.dataseq);
- }
- */
- if (psm)
- *psm = 0x1001;
- if (version)
- *version = 0x0100;
return TRUE;
}
--
1.6.3.3
---
health/hdp.c | 27 ++++++++++++++++++++++++---
1 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 70ffde5..19ff2f9 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -359,10 +359,32 @@ static uint8_t hdp_mcap_mdl_reconn_req_cb(struct mcap_mcl *mcl,
return MCAP_REQUEST_NOT_SUPPORTED;
}
+static void health_link_free(struct hdp_link *hdpl)
+{
+ /*TODO: Release structures related with Data Channels */
+
+ if (hdpl->mcl) {
+ mcap_close_mcl(hdpl->mcl, FALSE);
+ mcap_mcl_unref(hdpl->mcl);
+ hdpl->mcl = NULL;
+ }
+
+ if (hdpl->path) {
+ g_free(hdpl->path);
+ hdpl->path = NULL;
+ }
+
+ hdpl->hdpi->hlink = g_slist_remove(hdpl->hdpi->hlink, hdpl);
+ g_free(hdpl);
+}
+
static void health_link_path_unregister(void *data)
{
- /* struct hdp_link *hdpl = data */
- /* TODO: Unregister hdp_link*/
+ struct hdp_link *hdpl = data;
+
+ debug("Unregistered interface %s on path %s", HEALTH_LINK, hdpl->path);
+
+ health_link_free(hdpl);
}
static GDBusMethodTable health_link_methods[] = {
@@ -399,7 +421,6 @@ static struct hdp_link *create_health_link(struct hdp_instance *hdpi,
g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
"Cant register the health link in the bus");
- /* TODO create a function to free health link correctly */
/* MCAP will close the MCL and won't cache it if we didn't
* increase the MCL reference counter during the callback. */
mcap_mcl_unref(hdpl->mcl);
--
1.6.3.3
---
health/hdp.c | 6 +++---
health/hdp_types.h | 1 -
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 0a98118..70ffde5 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -391,9 +391,9 @@ static struct hdp_link *create_health_link(struct hdp_instance *hdpi,
if (*err)
return NULL;
- if (g_dbus_register_interface(hdpl->dev->conn, hdpl->path, HEALTH_LINK,
- health_link_methods, NULL, NULL,
- hdpl, health_link_path_unregister))
+ if (g_dbus_register_interface(hdpl->hdpi->adapter->conn, hdpl->path,
+ HEALTH_LINK, health_link_methods,
+ NULL, NULL, hdpl, health_link_path_unregister))
return hdpl;
g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
diff --git a/health/hdp_types.h b/health/hdp_types.h
index 05bfbfe..79419a1 100644
--- a/health/hdp_types.h
+++ b/health/hdp_types.h
@@ -104,7 +104,6 @@ struct hdp_instance {
struct hdp_link {
struct hdp_instance *hdpi; /* HDP session */
- struct hdp_device *dev; /* Health Device */
struct mcap_mcl *mcl; /* MCAP mcl */
GSList *channels; /* Data channels */
char *path; /* HDP link path */
--
1.6.3.3
---
health/hdp.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 50 insertions(+), 12 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 6d18626..44b3c8f 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -76,6 +76,16 @@ static struct hdp_device *find_device(GSList *devices, struct btd_device *dev)
return NULL;
}
+static int hdp_instance_idcmp(gconstpointer instance, gconstpointer p)
+{
+ const struct hdp_instance *hdpi = instance;
+ const uint32_t *id = p;
+
+ if (hdpi->id == *id)
+ return 0;
+ return -1;
+}
+
static void append_dict_features(DBusMessageIter *iter, GSList *end_points)
{
DBusMessageIter entry, array;
@@ -225,9 +235,40 @@ static void dev_path_unregister(void *data)
health_device_free(device);
}
+static DBusMessage *hdp_connect(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct hdp_device *device = user_data;
+ struct hdp_instance *hdpi;
+ uint32_t lid, rid;
+ GSList *l;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_UINT32, &lid,
+ DBUS_TYPE_UINT32, &rid,
+ DBUS_TYPE_INVALID)) {
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+ }
+
+ l = g_slist_find_custom(device->hdp_adapter->instances, &lid,
+ hdp_instance_idcmp);
+ if (!l)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid local instance id");
+ hdpi = l->data;
+
+
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".HdpError",
+ "Function is not yet implemented");
+}
+
static GDBusMethodTable device_methods[] = {
{ "GetHealthInstances", "", "aa{sv}", get_health_instances,
G_DBUS_METHOD_FLAG_ASYNC },
+ { "Connect", "uu", "o", hdp_connect, G_DBUS_METHOD_FLAG_ASYNC },
{ NULL }
};
@@ -235,33 +276,30 @@ static struct hdp_device *create_health_device(DBusConnection *conn,
struct btd_device *device)
{
const gchar *path = device_get_path(device);
+ struct btd_adapter *adapter = device_get_adapter(device);
struct hdp_device *dev;
dev = g_new0(struct hdp_device, 1);
dev->conn = dbus_connection_ref(conn);
dev->dev = btd_device_ref(device);
+ dev->hdp_adapter = find_adapter(adapters, adapter);
+
+ if (!dev->hdp_adapter)
+ goto fail;
if (!g_dbus_register_interface(conn, path,
HEALTH_DEVICE,
device_methods, NULL, NULL,
dev, dev_path_unregister)) {
error("D-Bus failed to register %s interface", HEALTH_DEVICE);
- health_device_free(dev);
- return NULL;
+ goto fail;
}
debug("Registered interface %s on path %s", HEALTH_DEVICE, path);
return dev;
-}
-
-static int hdp_instance_idcmp(gconstpointer instance, gconstpointer p)
-{
- const struct hdp_instance *hdpi = instance;
- const uint32_t *id = p;
-
- if (hdpi->id == *id)
- return 0;
- return -1;
+fail:
+ health_device_free(dev);
+ return NULL;
}
static void hdp_set_instance_id(struct hdp_instance *hdpi)
--
1.6.3.3
---
health/hdp.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++-----
health/hdp_types.h | 12 +++++++++-
2 files changed, 68 insertions(+), 8 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 0d3265f..88e7235 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -37,8 +37,9 @@
#include "../src/dbus-common.h"
-#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
-#define HEALTH_DEVICE "org.bluez.HealthDevice"
+#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
+#define HEALTH_DEVICE "org.bluez.HealthDevice"
+#define HEALTH_LINK "org.bluez.HealthLink"
static GSList *adapters = NULL;
static GSList *devices = NULL;
@@ -101,6 +102,18 @@ static int hdp_instance_idcmp(gconstpointer instance, gconstpointer p)
return -1;
}
+static void set_health_link_path(struct hdp_link *hdpl)
+{
+ char path[MAX_PATH_LENGTH + 1];
+
+ hdpl->id = hdpl->hdpi->hlc++;
+ snprintf(path, MAX_PATH_LENGTH, "%s/health_link_%d_%d",
+ adapter_get_path(hdpl->hdpi->adapter->btd_adapter),
+ hdpl->hdpi->id, hdpl->id);
+
+ hdpl->path = g_strdup(path);
+}
+
static void fill_up_one_spec(DBusMessageIter *dict, gpointer data)
{
struct hdp_feature *feature = data;
@@ -346,12 +359,23 @@ static uint8_t hdp_mcap_mdl_reconn_req_cb(struct mcap_mcl *mcl,
return MCAP_REQUEST_NOT_SUPPORTED;
}
+static void health_link_path_unregister(void *data)
+{
+ /* struct hdp_link *hdpl = data */
+ /* TODO: Unregister hdp_link*/
+}
+
+static GDBusMethodTable health_link_methods[] = {
+ { NULL }
+};
+
static void hdp_mcl_connect_cb(struct mcap_mcl *mcl, GError *err, void *data)
{
struct hdp_connection_cb *cb_data = data;
struct hdp_device *device = cb_data->device;
- /* struct hdp_instance *hdpi = cb_data->hdpi; */
+ struct hdp_instance *hdpi = cb_data->hdpi;
DBusMessage *msg = cb_data->msg;
+ struct hdp_link *hdpl = NULL;
GError *cberr = NULL;
DBusMessage *reply;
@@ -360,8 +384,13 @@ static void hdp_mcl_connect_cb(struct mcap_mcl *mcl, GError *err, void *data)
if (err)
goto fail;
- /* Create and Register HealthLink interface */
- mcap_mcl_set_cb(mcl, &cberr, NULL /*health_link*/,
+ hdpl = g_new0(struct hdp_link, 1);
+ hdpl->hdpi = hdpi;
+ hdpl->dev = device;
+ hdpl->mcl = mcap_mcl_ref(mcl);
+ set_health_link_path(hdpl);
+
+ mcap_mcl_set_cb(mcl, &cberr, hdpl,
MCAP_MDL_CB_CONNECTED, hdp_mcap_mdl_connected_cb,
MCAP_MDL_CB_CLOSED, hdp_mcap_mdl_closed_cb,
MCAP_MDL_CB_DELETED, hdp_mcap_mdl_deleted_cb,
@@ -369,14 +398,35 @@ static void hdp_mcl_connect_cb(struct mcap_mcl *mcl, GError *err, void *data)
MCAP_MDL_CB_REMOTE_CONN_REQ, hdp_mcap_mdl_conn_req_cb,
MCAP_MDL_CB_REMOTE_RECONN_REQ, hdp_mcap_mdl_reconn_req_cb,
MCAP_MDL_CB_INVALID);
+
if (cberr)
goto fail;
+
+ if (!g_dbus_register_interface(hdpl->dev->conn, hdpl->path, HEALTH_LINK,
+ health_link_methods, NULL, NULL,
+ hdpl, health_link_path_unregister)) {
+ error("D-Bus failed to register %s interface to %s",
+ HEALTH_LINK, hdpl->path);
+ goto fail;
+ }
+
+ hdpi->hlink = g_slist_prepend(hdpi->hlink, hdpl);
+ reply = g_dbus_create_reply(msg, DBUS_TYPE_OBJECT_PATH, &hdpl->path,
+ DBUS_TYPE_INVALID);
+ g_dbus_send_message(device->conn, reply);
return;
fail:
reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HdpError",
(err ? err->message : cberr->message));
- if (!cberr)
+ if (cberr) {
+ /* MCAP will close the MCL and won't cache it if we didn't
+ * increase the MCL reference counter during the callback. */
+ mcap_mcl_unref(hdpl->mcl);
+ g_free(hdpl->path);
+ g_free(hdpl);
g_error_free(cberr);
+ }
+
g_dbus_send_message(device->conn, reply);
}
@@ -421,8 +471,8 @@ static void connect_health_instance(sdp_list_t *recs, int err, gpointer data)
reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
"Error getting remote protocol descriptor list");
fail:
- g_dbus_send_message(device->conn, reply);
g_free(cb_data);
+ g_dbus_send_message(device->conn, reply);
}
static DBusMessage *hdp_connect(DBusConnection *conn,
diff --git a/health/hdp_types.h b/health/hdp_types.h
index 3bab4ea..05bfbfe 100644
--- a/health/hdp_types.h
+++ b/health/hdp_types.h
@@ -99,10 +99,20 @@ struct hdp_instance {
struct hdp_config *config; /* Configuration */
uint32_t sdp_handler; /* SDP record handler */
guint dbus_watcher; /* Client D-Bus conn watcher */
+ uint16_t hlc; /* Health link id. counter */
+};
+
+struct hdp_link {
+ struct hdp_instance *hdpi; /* HDP session */
+ struct hdp_device *dev; /* Health Device */
+ struct mcap_mcl *mcl; /* MCAP mcl */
+ GSList *channels; /* Data channels */
+ char *path; /* HDP link path */
+ uint32_t id; /* Health link id */
};
struct hdp_device {
- DBusConnection *conn; /* for name listener handling */
+ DBusConnection *conn; /* For name listener handling */
struct btd_device *dev; /* Device reference */
struct hdp_adapter *hdp_adapter; /* hdp_adapater */
};
--
1.6.3.3
---
health/hdp.c | 73 ++++++++++++++++++++++++++++++++++++++++------------
health/hdp_util.c | 3 +-
2 files changed, 58 insertions(+), 18 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index f5487c2..a15667b 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -457,6 +457,30 @@ static void client_disconnected(DBusConnection *connection, void *user_data)
hdp_instance_free(hdpi);
}
+static void mcl_connected(struct mcap_mcl *mcl, gpointer data)
+{
+ /* struct hdp_instance *hdpi = data; */
+ debug("TODO: implement mcl_connected");
+}
+
+static void mcl_reconnected(struct mcap_mcl *mcl, gpointer data)
+{
+ /* struct hdp_instance *hdpi = data; */
+ debug("TODO: implement mcl_reconnected");
+}
+
+static void mcl_disconnected(struct mcap_mcl *mcl, gpointer data)
+{
+ /* struct hdp_instance *hdpi = data; */
+ debug("TODO: implement mcl_disconnected");
+}
+
+static void mcl_uncached(struct mcap_mcl *mcl, gpointer data)
+{
+ /* struct hdp_instance *hdpi = data; */
+ debug("TODO: implement mcl_uncached");
+}
+
static DBusMessage *hdp_create_instance(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
@@ -472,17 +496,24 @@ static DBusMessage *hdp_create_instance(DBusConnection *conn,
dbus_message_iter_init(msg, &iter);
ctype = dbus_message_iter_get_arg_type(&iter);
if (ctype != DBUS_TYPE_OBJECT_PATH)
- goto error;
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
dbus_message_iter_get_basic(&iter, &path);
dbus_message_iter_next(&iter);
config = hdp_get_config(&iter, &err);
- if (err)
- goto error;
+ if (err) {
+ reply = g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments: %s", err->message);
+ g_error_free(err);
+ return reply;
+ }
name = dbus_message_get_sender(msg);
if (!name) {
- g_set_error(&err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
- "Can't get sender name");
- goto error;
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Can't get sender name");
}
hdpi = g_new0(struct hdp_instance, 1);
@@ -494,7 +525,20 @@ static DBusMessage *hdp_create_instance(DBusConnection *conn,
hdpi->dbus_watcher = g_dbus_add_disconnect_watch(adapter->conn, name,
client_disconnected, hdpi, NULL);
- /* TODO: Create mcap instance */
+ hdpi->mi = mcap_create_instance(adapter->btd_adapter, BT_IO_SEC_MEDIUM,
+ 0, 0, &err, mcl_connected,
+ mcl_reconnected, mcl_disconnected,
+ mcl_uncached, hdpi);
+ if (err)
+ goto error;
+
+ hdpi->ccpsm = mcap_get_ctrl_psm(hdpi->mi, &err);
+ if (err)
+ goto error;
+
+ hdpi->dcpsm = mcap_get_data_psm(hdpi->mi, &err);
+ if (err)
+ goto error;
if (!hdp_register_sdp_record(hdpi)) {
hdp_instance_free(hdpi);
@@ -503,19 +547,14 @@ static DBusMessage *hdp_create_instance(DBusConnection *conn,
}
adapter->instances = g_slist_prepend(adapter->instances, hdpi);
- info("HDP instance created with path %d", hdpi->id);
+ debug("HDP instance created with id %d", hdpi->id);
return g_dbus_create_reply(msg, DBUS_TYPE_UINT32, &hdpi->id,
DBUS_TYPE_INVALID);
error:
- if (err) {
- reply = g_dbus_create_error(msg,
- ERROR_INTERFACE ".InvalidArguments",
- "Invalid arguments: %s", err->message);
- g_error_free(err);
- } else
- reply = g_dbus_create_error(msg,
- ERROR_INTERFACE ".InvalidArguments",
- "Invalid arguments in method call");
+ reply = g_dbus_create_error(msg,ERROR_INTERFACE ".HealthError",
+ err->message);
+ g_error_free(err);
+ hdp_instance_free(hdpi);
return reply;
}
diff --git a/health/hdp_util.c b/health/hdp_util.c
index 844cd8c..5ba61dc 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -123,7 +123,8 @@ void hdp_instance_free(struct hdp_instance *hdpi)
g_dbus_remove_watch(hdpi->adapter->conn, hdpi->dbus_watcher);
if (hdpi->sdp_handler)
remove_record_from_server(hdpi->sdp_handler);
- /* TODO: stop mcap instance */
+ if (hdpi->mi)
+ mcap_release_instance(hdpi->mi);
if (hdpi->apath)
g_free(hdpi->apath);
if (hdpi->aname)
--
1.6.3.3
---
health/hdp.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 73 insertions(+), 3 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index a15667b..0d3265f 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -33,6 +33,8 @@
#include "glib-helper.h"
+#include "../mcap/mcap.h"
+
#include "../src/dbus-common.h"
#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
@@ -305,12 +307,77 @@ static sdp_record_t *get_record(sdp_list_t *recs, uint32_t handle)
return NULL;
}
+static void hdp_mcap_mdl_connected_cb(struct mcap_mdl *mdl, void *data)
+{
+ /* struct hdp_link *hdpl = data; */
+ debug("TODO: Incomplete callback, mdl connected");
+}
+
+static void hdp_mcap_mdl_deleted_cb(struct mcap_mdl *mdl, void *data)
+{
+ /* struct hdp_link *hdpl = data; */
+ debug("TODO: Incomplete callback, mdl deleted");
+}
+
+static void hdp_mcap_mdl_aborted_cb(struct mcap_mdl *mdl, void *data)
+{
+ /* struct hdp_link *hdpl = data; */
+ debug("TODO: Incomplete callback, mdl aborted");
+}
+
+static void hdp_mcap_mdl_closed_cb(struct mcap_mdl *mdl, void *data)
+{
+ /* struct hdp_link *hdpl = data; */
+ debug("TODO: Incomplete callback, mdl closed");
+}
+
+static uint8_t hdp_mcap_mdl_conn_req_cb(struct mcap_mdl *mdl, void *data)
+{
+ /* struct hdp_link *hdpl = data; */
+ debug("TODO: Incomplete callback, mdl connection request");
+ return MCAP_REQUEST_NOT_SUPPORTED;
+}
+
+static uint8_t hdp_mcap_mdl_reconn_req_cb(struct mcap_mcl *mcl,
+ uint8_t mdepid, uint16_t mdlid,
+ uint8_t *conf, void *data)
+{
+ debug("TODO: Incomplete callback, mdl reconnection request");
+ return MCAP_REQUEST_NOT_SUPPORTED;
+}
+
static void hdp_mcl_connect_cb(struct mcap_mcl *mcl, GError *err, void *data)
{
struct hdp_connection_cb *cb_data = data;
+ struct hdp_device *device = cb_data->device;
+ /* struct hdp_instance *hdpi = cb_data->hdpi; */
+ DBusMessage *msg = cb_data->msg;
+ GError *cberr = NULL;
+ DBusMessage *reply;
- /* TODO */
g_free(cb_data);
+
+ if (err)
+ goto fail;
+
+ /* Create and Register HealthLink interface */
+ mcap_mcl_set_cb(mcl, &cberr, NULL /*health_link*/,
+ MCAP_MDL_CB_CONNECTED, hdp_mcap_mdl_connected_cb,
+ MCAP_MDL_CB_CLOSED, hdp_mcap_mdl_closed_cb,
+ MCAP_MDL_CB_DELETED, hdp_mcap_mdl_deleted_cb,
+ MCAP_MDL_CB_ABORTED, hdp_mcap_mdl_aborted_cb,
+ MCAP_MDL_CB_REMOTE_CONN_REQ, hdp_mcap_mdl_conn_req_cb,
+ MCAP_MDL_CB_REMOTE_RECONN_REQ, hdp_mcap_mdl_reconn_req_cb,
+ MCAP_MDL_CB_INVALID);
+ if (cberr)
+ goto fail;
+ return;
+fail:
+ reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HdpError",
+ (err ? err->message : cberr->message));
+ if (!cberr)
+ g_error_free(cberr);
+ g_dbus_send_message(device->conn, reply);
}
static void connect_health_instance(sdp_list_t *recs, int err, gpointer data)
@@ -383,7 +450,7 @@ static DBusMessage *hdp_connect(DBusConnection *conn,
if (!l)
return g_dbus_create_error(msg,
ERROR_INTERFACE ".InvalidArguments",
- "Invalid local instance id");
+ "Invalid local health instance id");
cb_data = g_new0(struct hdp_connection_cb, 1);
cb_data->device = device;
@@ -400,6 +467,7 @@ static DBusMessage *hdp_connect(DBusConnection *conn,
cb_data, NULL) == 0)
return NULL;
+ g_free(cb_data);
return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
"Error getting remote information");
}
@@ -499,6 +567,7 @@ static DBusMessage *hdp_create_instance(DBusConnection *conn,
return g_dbus_create_error(msg,
ERROR_INTERFACE ".InvalidArguments",
"Invalid arguments in method call");
+
dbus_message_iter_get_basic(&iter, &path);
dbus_message_iter_next(&iter);
config = hdp_get_config(&iter, &err);
@@ -509,6 +578,7 @@ static DBusMessage *hdp_create_instance(DBusConnection *conn,
g_error_free(err);
return reply;
}
+
name = dbus_message_get_sender(msg);
if (!name) {
return g_dbus_create_error(msg,
@@ -552,7 +622,7 @@ static DBusMessage *hdp_create_instance(DBusConnection *conn,
DBUS_TYPE_INVALID);
error:
reply = g_dbus_create_error(msg,ERROR_INTERFACE ".HealthError",
- err->message);
+ err->message);
g_error_free(err);
hdp_instance_free(hdpi);
return reply;
--
1.6.3.3
---
health/hdp.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++---
health/hdp_util.c | 26 ++++++++++++++
health/hdp_util.h | 2 +
3 files changed, 123 insertions(+), 5 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index abae2df..f5487c2 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -52,6 +52,13 @@ struct health_instances_aux {
GSList *end_points;
};
+struct hdp_connection_cb {
+ struct hdp_device *device;
+ struct hdp_instance *hdpi;
+ uint32_t rem_id;
+ DBusMessage *msg;
+};
+
static struct hdp_adapter *find_adapter(GSList *list,
struct btd_adapter *btd_adapter)
{
@@ -240,7 +247,7 @@ static DBusMessage *get_health_instances(DBusConnection *conn,
bdaddr_t src, dst;
uuid_t uuid;
- adapter = device_get_adapter(device->dev);
+ adapter = device->hdp_adapter->btd_adapter;
adapter_get_address(adapter, &src);
device_get_address(device->dev, &dst);
@@ -284,12 +291,82 @@ static void dev_path_unregister(void *data)
health_device_free(device);
}
+static sdp_record_t *get_record(sdp_list_t *recs, uint32_t handle)
+{
+ sdp_record_t *rec;
+ sdp_list_t *l;
+
+ for (l = recs; l; l = l->next) {
+ rec = l->data;
+ if (rec->handle == handle)
+ return rec;
+ }
+
+ return NULL;
+}
+
+static void hdp_mcl_connect_cb(struct mcap_mcl *mcl, GError *err, void *data)
+{
+ struct hdp_connection_cb *cb_data = data;
+
+ /* TODO */
+ g_free(cb_data);
+}
+
+static void connect_health_instance(sdp_list_t *recs, int err, gpointer data)
+{
+ struct hdp_connection_cb *cb_data = data;
+ struct hdp_device *device = cb_data->device;
+ struct hdp_instance *hdpi = cb_data->hdpi;
+ GError *gerr = NULL;
+ uint32_t rid = cb_data->rem_id;
+ DBusMessage *msg = cb_data->msg;
+ DBusMessage *reply;
+ sdp_record_t *rec;
+ guint16 ccpsm, version;
+ bdaddr_t dst;
+
+ if (err != 0) {
+ reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Error getting remote information");
+ goto fail;
+ }
+
+ rec = get_record(recs, rid);
+ if (!rec) {
+ reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Error getting remote information");
+ goto fail;
+ }
+
+ if (!hdp_get_prot_desc_list(rec, &ccpsm, &version)) {
+ reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Error getting remote protocol descriptor list");
+ goto fail;
+ }
+
+ device_get_address(device->dev, &dst);
+ mcap_create_mcl(hdpi->mi, &dst, ccpsm, &gerr, hdp_mcl_connect_cb,
+ cb_data);
+ if (!gerr)
+ return;
+
+ reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Error getting remote protocol descriptor list");
+fail:
+ g_dbus_send_message(device->conn, reply);
+ g_free(cb_data);
+}
+
static DBusMessage *hdp_connect(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
struct hdp_device *device = user_data;
- struct hdp_instance *hdpi;
+ struct hdp_connection_cb *cb_data;
+ struct btd_adapter *adapter;
+ bdaddr_t src, dst;
uint32_t lid, rid;
+ uuid_t uuid;
GSList *l;
if (!dbus_message_get_args(msg, NULL,
@@ -307,11 +384,24 @@ static DBusMessage *hdp_connect(DBusConnection *conn,
return g_dbus_create_error(msg,
ERROR_INTERFACE ".InvalidArguments",
"Invalid local instance id");
- hdpi = l->data;
+ cb_data = g_new0(struct hdp_connection_cb, 1);
+ cb_data->device = device;
+ cb_data->hdpi = l->data;
+ cb_data->rem_id = rid;
+ cb_data->msg = dbus_message_ref(msg);
- return g_dbus_create_error(msg, ERROR_INTERFACE ".HdpError",
- "Function is not yet implemented");
+ adapter = device->hdp_adapter->btd_adapter;
+ adapter_get_address(adapter, &src);
+ device_get_address(device->dev, &dst);
+
+ bt_string2uuid(&uuid, HDP_UUID);
+ if (bt_search_service(&src, &dst, &uuid, connect_health_instance,
+ cb_data, NULL) == 0)
+ return NULL;
+
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Error getting remote information");
}
static GDBusMethodTable device_methods[] = {
diff --git a/health/hdp_util.c b/health/hdp_util.c
index 4f50550..844cd8c 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -883,6 +883,32 @@ gboolean hdp_get_data_exchange_spec(const sdp_record_t *rec, guint8 *val)
return TRUE;
}
+gboolean hdp_get_prot_desc_list(const sdp_record_t *rec, guint16 *psm,
+ guint16 *version)
+{
+ if (!(psm || version))
+ return TRUE;
+
+ /* TODO:
+ sdp_data_t *pdl, *l;
+
+ exspec = sdp_data_get(rec, SDP_ATTR_PROTO_DESC_LIST);
+ if (exspec->dtd != SDP_SEQ8)
+ return FALSE;
+
+ for (l = pdl->val.dataseq; l; l = l->next) {
+ if (l->dtd != SDP_SEQ8)
+ continue;
+ epl = get_feature(epl, l->val.dataseq);
+ }
+ */
+ if (psm)
+ *psm = 0x1001;
+ if (version)
+ *version = 0x0100;
+ return TRUE;
+}
+
static gint cmp_feat_mdep(gconstpointer a, gconstpointer b)
{
const struct hdp_supp_fts *fts = a;
diff --git a/health/hdp_util.h b/health/hdp_util.h
index 08e6471..03a7256 100644
--- a/health/hdp_util.h
+++ b/health/hdp_util.h
@@ -37,6 +37,8 @@ typedef void (*hdp_dbus_fill_up)(DBusMessageIter *iter, gpointer data);
struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err);
gboolean hdp_register_sdp_record(struct hdp_instance *hdps);
gboolean hdp_get_data_exchange_spec(const sdp_record_t *rec, guint8 *val);
+gboolean hdp_get_prot_desc_list(const sdp_record_t *rec, guint16 *psm,
+ guint16 *version);
GSList *hdp_get_end_points(const sdp_record_t *rec);
void hdp_instance_free(struct hdp_instance *hdpi);
--
1.6.3.3
---
health/hdp.c | 169 ++++++++++++++++++++++++++++++++++-------------------
health/hdp_util.c | 56 +++++++++++++++++-
health/hdp_util.h | 12 ++++
3 files changed, 175 insertions(+), 62 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 44b3c8f..abae2df 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -46,6 +46,12 @@ struct instances_aux {
DBusMessage *msg;
};
+struct health_instances_aux {
+ guint32 handler;
+ guint8 data_spec;
+ GSList *end_points;
+};
+
static struct hdp_adapter *find_adapter(GSList *list,
struct btd_adapter *btd_adapter)
{
@@ -86,41 +92,114 @@ static int hdp_instance_idcmp(gconstpointer instance, gconstpointer p)
return -1;
}
-static void append_dict_features(DBusMessageIter *iter, GSList *end_points)
+static void fill_up_one_spec(DBusMessageIter *dict, gpointer data)
{
- DBusMessageIter entry, array;
-
- dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY,
- NULL, &entry);
- dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, "end_points");
-
- dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
- DBUS_TYPE_VARIANT_AS_STRING
- DBUS_TYPE_ARRAY_AS_STRING
- DBUS_TYPE_ARRAY_AS_STRING
- DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
- DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
- DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
-
- dbus_message_iter_close_container(&entry, &array);
- dbus_message_iter_close_container(iter, &entry);
+ struct hdp_feature *feature = data;
+
+ dict_append_entry(dict, "dtype", DBUS_TYPE_UINT16, &feature->dtype);
+ if (feature->dscr)
+ dict_append_entry(dict, "description", DBUS_TYPE_STRING,
+ &feature->dscr);
}
-static void append_array_entry(DBusMessageIter *iter, uint32_t *handler,
- uint8_t *spec, GSList *end_points)
+static void fill_up_specs(DBusMessageIter *dict, gpointer data)
{
- DBusMessageIter dict;
+ GSList *specs = data;
+ GSList *l;
+ struct hdp_feature *feature;
+
- dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
- DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
- DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
- DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+ for (l = specs; l; l = l->next) {
+ feature = l->data;
- dict_append_entry(&dict, "id", DBUS_TYPE_UINT32, handler);
- dict_append_entry(&dict, "data_spec", DBUS_TYPE_BYTE, spec);
- append_dict_features(&dict, end_points);
+ hdp_append_dict(dict, fill_up_one_spec, feature);
+ }
+}
+
+static void fill_up_specs_array(DBusMessageIter *array, gpointer data)
+{
+ hdp_append_array_of_dicts(array, fill_up_specs, data);
+}
- dbus_message_iter_close_container(iter, &dict);
+static void fill_up_one_end_point(DBusMessageIter *dict, gpointer data)
+{
+ struct hdp_supp_fts *fts = data;
+ const char *role;
+
+ if (fts->role == HDP_SOURCE)
+ role = HDP_SOURCE_ROLE_AS_STRING;
+ else if (fts->role == HDP_SINK)
+ role = HDP_SINK_ROLE_AS_STRING;
+
+ dict_append_entry(dict, "mdepid", DBUS_TYPE_BYTE, &fts->mdepid);
+ dict_append_entry(dict, "role", DBUS_TYPE_STRING, &role);
+ hdp_append_variant_array_entry(dict, "specs", fill_up_specs_array,
+ fts->features);
+}
+
+static void fill_up_end_points(DBusMessageIter *dict, gpointer data)
+{
+ GSList *end_points = data;
+ struct hdp_supp_fts *fts;
+ GSList *l;
+
+ for (l = end_points; l; l = l->next) {
+ fts = l->data;
+
+ if (fts->role != HDP_SOURCE && fts->role != HDP_SINK)
+ continue;
+
+ hdp_append_dict(dict, fill_up_one_end_point, fts);
+ }
+}
+
+static void fill_up_end_points_array(DBusMessageIter *iter, gpointer data)
+{
+ hdp_append_array_of_dicts(iter, fill_up_end_points, data);
+}
+
+static void fill_up_instance(DBusMessageIter *entry, gpointer data)
+{
+ struct health_instances_aux *aux = data;
+ guint32 handler = aux->handler;
+ guint8 data_spec = aux->data_spec;
+ GSList *end_points = aux->end_points;
+
+ dict_append_entry(entry, "id", DBUS_TYPE_UINT32, &handler);
+ dict_append_entry(entry, "data_spec", DBUS_TYPE_BYTE, &data_spec);
+ hdp_append_variant_array_entry(entry, "end_points",
+ fill_up_end_points_array, end_points);
+}
+
+static void fill_up_health_instances(DBusMessageIter *dict, gpointer data)
+{
+ sdp_list_t *recs = data;
+ sdp_record_t *rec;
+ sdp_list_t *l;
+ guint8 data_spec;
+ GSList *end_points;
+ struct health_instances_aux *aux;
+
+ for (l = recs; l; l = l->next) {
+ rec = l->data;
+ debug("Record found 0x%x", rec->handle);
+
+ if (!hdp_get_data_exchange_spec(rec, &data_spec)) {
+ error("Error getting data exchange info");
+ continue;
+ }
+ end_points = hdp_get_end_points(rec);
+ if (!end_points) {
+ error("Error getting end points");
+ continue;
+ }
+ aux = g_new0(struct health_instances_aux, 1);
+ aux->handler = rec->handle;
+ aux->data_spec = data_spec;
+ aux->end_points = end_points;
+ hdp_append_dict(dict, fill_up_instance, aux);
+ g_free(aux);
+ }
}
static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
@@ -129,11 +208,7 @@ static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
DBusMessage *msg = cb_data->msg;
struct hdp_device *device = cb_data->device;
DBusMessage *reply;
- sdp_record_t *rec;
- sdp_list_t *l;
- guint8 data_spec;
- GSList *end_points;
- DBusMessageIter iter, dict;
+ DBusMessageIter iter;
g_free(cb_data);
@@ -151,34 +226,8 @@ static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
dbus_message_iter_init_append(reply, &iter);
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_ARRAY_AS_STRING
- DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
- DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
- DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
- for (l = recs; l; l = l->next) {
- rec = l->data;
- debug("Record found 0x%x", rec->handle);
+ hdp_append_array_of_dicts(&iter, fill_up_health_instances, recs);
- if (!hdp_get_data_exchange_spec(rec, &data_spec)) {
- error("Error getting data exchange info");
- continue;
- }
- end_points = hdp_get_end_points(rec);
- if (!end_points) {
- error("Error getting end points");
- continue;
- }
- append_array_entry(&dict, &rec->handle, &data_spec,
- end_points);
- }
-
- dbus_message_iter_close_container(&iter, &dict);
-/*
- reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
- "Not implemented yet");
-*/
g_dbus_send_message(device->conn, reply);
}
diff --git a/health/hdp_util.c b/health/hdp_util.c
index f6ab8e7..4f50550 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -328,9 +328,9 @@ static gboolean parse_role(DBusMessageIter *iter, GError **err, gpointer data)
}
dbus_message_iter_get_basic(string, &role);
- if (g_strcmp0(role, "sink") == 0)
+ if (g_strcmp0(role, HDP_SINK_ROLE_AS_STRING) == 0)
fts->role = HDP_SINK;
- else if (g_strcmp0(role, "source") == 0)
+ else if (g_strcmp0(role, HDP_SOURCE_ROLE_AS_STRING) == 0)
fts->role = HDP_SOURCE;
else {
g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
@@ -949,3 +949,55 @@ GSList *hdp_get_end_points(const sdp_record_t *rec)
return epl;
}
+
+void hdp_append_array_of_dicts(DBusMessageIter *iter, hdp_dbus_fill_up fill_up,
+ gpointer user_data)
+{
+ DBusMessageIter dict;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ fill_up(&dict, user_data);
+
+ dbus_message_iter_close_container(iter, &dict);
+}
+
+void hdp_append_dict(DBusMessageIter *iter, hdp_dbus_fill_up fill_up,
+ gpointer user_data)
+{
+ DBusMessageIter entry;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &entry);
+
+ fill_up(&entry, user_data);
+
+ dbus_message_iter_close_container(iter, &entry);
+}
+
+void hdp_append_variant_array_entry(DBusMessageIter *iter, char *key,
+ hdp_dbus_fill_up fill_up, gpointer user_data)
+{
+ DBusMessageIter entry, array;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
+
+ fill_up(&array, user_data);
+
+ dbus_message_iter_close_container(&entry, &array);
+ dbus_message_iter_close_container(iter, &entry);
+}
diff --git a/health/hdp_util.h b/health/hdp_util.h
index beafa00..08e6471 100644
--- a/health/hdp_util.h
+++ b/health/hdp_util.h
@@ -29,10 +29,22 @@
#include <gdbus.h>
#include "hdp_types.h"
+#define HDP_SINK_ROLE_AS_STRING "sink"
+#define HDP_SOURCE_ROLE_AS_STRING "source"
+
+typedef void (*hdp_dbus_fill_up)(DBusMessageIter *iter, gpointer data);
+
struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err);
gboolean hdp_register_sdp_record(struct hdp_instance *hdps);
gboolean hdp_get_data_exchange_spec(const sdp_record_t *rec, guint8 *val);
GSList *hdp_get_end_points(const sdp_record_t *rec);
void hdp_instance_free(struct hdp_instance *hdpi);
+void hdp_append_array_of_dicts(DBusMessageIter *iter, hdp_dbus_fill_up fill_up,
+ gpointer user_data);
+void hdp_append_dict(DBusMessageIter *iter, hdp_dbus_fill_up fil_up,
+ gpointer user_data);
+void hdp_append_variant_array_entry(DBusMessageIter *iter, char *key,
+ hdp_dbus_fill_up fill_up, gpointer user_data);
+
#endif /* __HDP_UTIL_H__ */
--
1.6.3.3
---
health/hdp.c | 11 +++++++++++
health/hdp_types.h | 1 +
health/hdp_util.c | 2 ++
3 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 6e3c2fc..9ca2e52 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -163,6 +163,15 @@ static void hdp_set_instance_id(struct hdp_instance *hdpi)
hdpi->id = adapter->ic++;
}
+static void client_disconnected(DBusConnection *connection, void *user_data)
+{
+ struct hdp_instance *hdpi = user_data;
+ struct hdp_adapter *adapter = hdpi->adapter;
+ debug("Client disconnected from the bus, deleting hdp instance");
+ adapter->instances = g_slist_remove(adapter->instances, hdpi);
+ hdp_instance_free(hdpi);
+}
+
static DBusMessage *hdp_create_instance(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
@@ -197,6 +206,8 @@ static DBusMessage *hdp_create_instance(DBusConnection *conn,
hdpi->apath = g_strdup(path);
hdpi->config = config;
hdp_set_instance_id(hdpi);
+ hdpi->dbus_watcher = g_dbus_add_disconnect_watch(adapter->conn, name,
+ client_disconnected, hdpi, NULL);
/* TODO: Create mcap instance */
diff --git a/health/hdp_types.h b/health/hdp_types.h
index 171910a..3bab4ea 100644
--- a/health/hdp_types.h
+++ b/health/hdp_types.h
@@ -98,6 +98,7 @@ struct hdp_instance {
char *aname; /* HDP agent name */
struct hdp_config *config; /* Configuration */
uint32_t sdp_handler; /* SDP record handler */
+ guint dbus_watcher; /* Client D-Bus conn watcher */
};
struct hdp_device {
diff --git a/health/hdp_util.c b/health/hdp_util.c
index b047aa2..42f28bf 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -119,6 +119,8 @@ void hdp_instance_free(struct hdp_instance *hdpi)
hdpi->devices = NULL;
*/
+ if (hdpi->dbus_watcher)
+ g_dbus_remove_watch(hdpi->adapter->conn, hdpi->dbus_watcher);
if (hdpi->sdp_handler)
remove_record_from_server(hdpi->sdp_handler);
/* TODO: stop mcap instance */
--
1.6.3.3
---
health/hdp.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++--
health/hdp_util.c | 2 -
2 files changed, 57 insertions(+), 5 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 68bd809..6d18626 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -76,6 +76,43 @@ static struct hdp_device *find_device(GSList *devices, struct btd_device *dev)
return NULL;
}
+static void append_dict_features(DBusMessageIter *iter, GSList *end_points)
+{
+ DBusMessageIter entry, array;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, "end_points");
+
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
+
+ dbus_message_iter_close_container(&entry, &array);
+ dbus_message_iter_close_container(iter, &entry);
+}
+
+static void append_array_entry(DBusMessageIter *iter, uint32_t *handler,
+ uint8_t *spec, GSList *end_points)
+{
+ DBusMessageIter dict;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ dict_append_entry(&dict, "id", DBUS_TYPE_UINT32, handler);
+ dict_append_entry(&dict, "data_spec", DBUS_TYPE_BYTE, spec);
+ append_dict_features(&dict, end_points);
+
+ dbus_message_iter_close_container(iter, &dict);
+}
+
static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
{
struct instances_aux *cb_data = user_data;
@@ -86,6 +123,7 @@ static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
sdp_list_t *l;
guint8 data_spec;
GSList *end_points;
+ DBusMessageIter iter, dict;
g_free(cb_data);
@@ -97,10 +135,22 @@ static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
return;
}
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
for (l = recs; l; l = l->next) {
rec = l->data;
debug("Record found 0x%x", rec->handle);
- /* TODO: Check record */
+
if (!hdp_get_data_exchange_spec(rec, &data_spec)) {
error("Error getting data exchange info");
continue;
@@ -110,11 +160,15 @@ static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
error("Error getting end points");
continue;
}
- debug("Get data exchange spec %d", data_spec);
+ append_array_entry(&dict, &rec->handle, &data_spec,
+ end_points);
}
+ dbus_message_iter_close_container(&iter, &dict);
+/*
reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
"Not implemented yet");
+*/
g_dbus_send_message(device->conn, reply);
}
@@ -172,7 +226,7 @@ static void dev_path_unregister(void *data)
}
static GDBusMethodTable device_methods[] = {
- { "GetHealthInstances", "", "a{sv}", get_health_instances,
+ { "GetHealthInstances", "", "aa{sv}", get_health_instances,
G_DBUS_METHOD_FLAG_ASYNC },
{ NULL }
};
diff --git a/health/hdp_util.c b/health/hdp_util.c
index b59e4e3..f6ab8e7 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -947,7 +947,5 @@ GSList *hdp_get_end_points(const sdp_record_t *rec)
epl = get_feature(epl, l->val.dataseq);
}
- g_slist_foreach(epl, print_features, NULL);
-
return epl;
}
--
1.6.3.3
---
health/hdp.c | 64 +++++++++++++++++++++++++++++++++++++++++++----------
health/hdp_util.c | 35 +++++++++++++++++++++++++++-
2 files changed, 85 insertions(+), 14 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index ae6add4..6e3c2fc 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -34,7 +34,6 @@
#include "../src/dbus-common.h"
#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
-#define HEALTH_INSTANCE_INTERFACE "org.bluez.HealthInstance"
#define HEALTH_DEVICE "org.bluez.HealthDevice"
static GSList *adapters = NULL;
@@ -147,6 +146,16 @@ static struct hdp_device *create_health_device(DBusConnection *conn,
return dev;
}
+static int hdp_instance_idcmp(gconstpointer instance, gconstpointer p)
+{
+ const struct hdp_instance *hdpi = instance;
+ const uint32_t *id = p;
+
+ if (hdpi->id == *id)
+ return 0;
+ return -1;
+}
+
static void hdp_set_instance_id(struct hdp_instance *hdpi)
{
struct hdp_adapter *adapter = hdpi->adapter;
@@ -187,24 +196,20 @@ static DBusMessage *hdp_create_instance(DBusConnection *conn,
hdpi->aname = g_strdup(name);
hdpi->apath = g_strdup(path);
hdpi->config = config;
- if (!config->svc_dsc)
- config->svc_dsc = g_strdup(HDP_SERVICE_DSC);
- if (!config->svc_name)
- config->svc_name = g_strdup(HDP_SERVICE_NAME);
- if (!config->svc_prov)
- config->svc_prov = g_strdup(HDP_SERVICE_PROVIDER);
hdp_set_instance_id(hdpi);
/* TODO: Create mcap instance */
if (!hdp_register_sdp_record(hdpi)) {
+ hdp_instance_free(hdpi);
return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
"Session can't be registered");
}
- return g_dbus_create_error(msg,
- ERROR_INTERFACE ".HealthError",
- "Incomplete call yet");
+ adapter->instances = g_slist_prepend(adapter->instances, hdpi);
+ info("HDP instance created with path %d", hdpi->id);
+ return g_dbus_create_reply(msg, DBUS_TYPE_UINT32, &hdpi->id,
+ DBUS_TYPE_INVALID);
error:
if (err) {
reply = g_dbus_create_error(msg,
@@ -218,16 +223,51 @@ error:
return reply;
}
+static DBusMessage *hdp_delete_instance(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct hdp_adapter *adapter = user_data;
+ struct hdp_instance *hdpi;
+ GSList *l;
+ const char *name;
+ uint32_t id;
+
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &id,
+ DBUS_TYPE_INVALID))
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+
+ l = g_slist_find_custom(adapter->instances, &id, hdp_instance_idcmp);
+ if (!l)
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".NotFound",
+ "The session was not found");
+
+ name = dbus_message_get_sender(msg);
+ hdpi = l->data;
+ if (g_strcmp0(hdpi->aname, name) != 0)
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "This session was created by an other process");
+ adapter->instances = g_slist_remove(adapter->instances, hdpi);
+ hdp_instance_free(hdpi);
+
+ debug("Stop HDP Session %d deleted", id);
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
static GDBusMethodTable hdp_methods[] = {
{ "CreateInstance", "oa{sv}", "u", hdp_create_instance },
+ { "DeleteInstance", "u", "", hdp_delete_instance },
{ NULL }
};
void hdp_delete_instance_iter(gpointer data, gpointer user_data)
{
- /* struct hdp_instance *hdpi = data; */
+ struct hdp_instance *hdpi = data;
- /* TODO: Create a free function */
+ hdp_instance_free(hdpi);
}
static void hdp_path_unregister(void *data)
diff --git a/health/hdp_util.c b/health/hdp_util.c
index 816078a..b047aa2 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -109,6 +109,28 @@ static void free_config(struct hdp_config *config)
g_free(config);
}
+void hdp_instance_free(struct hdp_instance *hdpi)
+{
+ debug("HDP instance %d is deleted", hdpi->id);
+ /* TODO: Complete this part */
+ /*
+ g_slist_foreach(hdpi->devices, hdp_device_unregister, NULL);
+ g_slist_free(hdpi->devices);
+ hdpi->devices = NULL;
+ */
+
+ if (hdpi->sdp_handler)
+ remove_record_from_server(hdpi->sdp_handler);
+ /* TODO: stop mcap instance */
+ if (hdpi->apath)
+ g_free(hdpi->apath);
+ if (hdpi->aname)
+ g_free(hdpi->aname);
+ if (hdpi->config)
+ free_config(hdpi->config);
+ g_free(hdpi);
+}
+
static gboolean parse_dict_entry(struct dict_entry_func dict_context[],
DBusMessageIter *iter,
GError **err,
@@ -441,8 +463,17 @@ struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err)
"\"data_spec\" and \"end_point\" should be set or not");
goto error;
}
- if (!config->ds_present)
- goto error;
+ if (!config->ds_present) {
+ g_free(config);
+ return NULL;
+ }
+ if (!config->svc_dsc)
+ config->svc_dsc = g_strdup(HDP_SERVICE_DSC);
+ if (!config->svc_name)
+ config->svc_name = g_strdup(HDP_SERVICE_NAME);
+ if (!config->svc_prov)
+ config->svc_prov = g_strdup(HDP_SERVICE_PROVIDER);
+
debug("config->data_spec %d", config->data_spec);
g_slist_foreach(config->supp_fts, print_features, NULL);
return config;
--
1.6.3.3
---
health/hdp.c | 80 ++++++++++++++++++++++++++++++++++++++++++++--------
health/hdp_util.c | 5 +++
health/hdp_util.h | 1 +
3 files changed, 73 insertions(+), 13 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 9ca2e52..68bd809 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -31,6 +31,8 @@
#include "hdp_util.h"
#include "device.h"
+#include "glib-helper.h"
+
#include "../src/dbus-common.h"
#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
@@ -39,6 +41,11 @@
static GSList *adapters = NULL;
static GSList *devices = NULL;
+struct instances_aux {
+ struct hdp_device *device;
+ DBusMessage *msg;
+};
+
static struct hdp_adapter *find_adapter(GSList *list,
struct btd_adapter *btd_adapter)
{
@@ -69,27 +76,73 @@ static struct hdp_device *find_device(GSList *devices, struct btd_device *dev)
return NULL;
}
+static void sink_health_instances(sdp_list_t *recs, int err, gpointer user_data)
+{
+ struct instances_aux *cb_data = user_data;
+ DBusMessage *msg = cb_data->msg;
+ struct hdp_device *device = cb_data->device;
+ DBusMessage *reply;
+ sdp_record_t *rec;
+ sdp_list_t *l;
+ guint8 data_spec;
+ GSList *end_points;
+
+ g_free(cb_data);
+
+ if (err != 0) {
+ error("Error getting sink records");
+ reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Error getting remote information");
+ g_dbus_send_message(device->conn, reply);
+ return;
+ }
+
+ for (l = recs; l; l = l->next) {
+ rec = l->data;
+ debug("Record found 0x%x", rec->handle);
+ /* TODO: Check record */
+ if (!hdp_get_data_exchange_spec(rec, &data_spec)) {
+ error("Error getting data exchange info");
+ continue;
+ }
+ end_points = hdp_get_end_points(rec);
+ if (!end_points) {
+ error("Error getting end points");
+ continue;
+ }
+ debug("Get data exchange spec %d", data_spec);
+ }
+
+ reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Not implemented yet");
+ g_dbus_send_message(device->conn, reply);
+}
+
static DBusMessage *get_health_instances(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
struct hdp_device *device = user_data;
- const sdp_record_t *rec;
- guint8 data_spec;
+ struct btd_adapter *adapter;
+ struct instances_aux *cb_data;
+ bdaddr_t src, dst;
+ uuid_t uuid;
- rec = btd_device_get_record(device->dev, HDP_UUID);
+ adapter = device_get_adapter(device->dev);
+ adapter_get_address(adapter, &src);
+ device_get_address(device->dev, &dst);
- if (!rec) {
- debug("No record found");
- goto error;
- }
+ cb_data = g_new0(struct instances_aux, 1);
+ cb_data->device = device;
+ cb_data->msg = dbus_message_ref(msg);
- if (!hdp_get_data_exchange_spec(rec, &data_spec))
- goto error;
- debug("Get data exchange spec %d", data_spec);
-error:
+ bt_string2uuid(&uuid, HDP_UUID);
+ if (bt_search_service(&src, &dst, &uuid, sink_health_instances,
+ cb_data, NULL) == 0)
+ return NULL;
+
return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
- "Cannot get the remote SDP record");
+ "Error getting remote information");
}
static void health_device_free(struct hdp_device *device)
@@ -119,7 +172,8 @@ static void dev_path_unregister(void *data)
}
static GDBusMethodTable device_methods[] = {
- { "GetHealthInstances", "", "a{sv}", get_health_instances },
+ { "GetHealthInstances", "", "a{sv}", get_health_instances,
+ G_DBUS_METHOD_FLAG_ASYNC },
{ NULL }
};
diff --git a/health/hdp_util.c b/health/hdp_util.c
index 42f28bf..a6d09c5 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -781,6 +781,11 @@ static gboolean register_data_exchange_spec(struct hdp_config *config,
return TRUE;
}
+GSList *hdp_get_end_points(const sdp_record_t *rec)
+{
+ return NULL;
+}
+
static gboolean register_mcap_features(sdp_record_t *sdp_record)
{
sdp_data_t *mcap_proc;
diff --git a/health/hdp_util.h b/health/hdp_util.h
index 0fdaaec..beafa00 100644
--- a/health/hdp_util.h
+++ b/health/hdp_util.h
@@ -32,6 +32,7 @@
struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err);
gboolean hdp_register_sdp_record(struct hdp_instance *hdps);
gboolean hdp_get_data_exchange_spec(const sdp_record_t *rec, guint8 *val);
+GSList *hdp_get_end_points(const sdp_record_t *rec);
void hdp_instance_free(struct hdp_instance *hdpi);
#endif /* __HDP_UTIL_H__ */
--
1.6.3.3
---
health/hdp.c | 5 +-
health/hdp_util.c | 393 +++++++++++++++++++++++++++++++++++++++++++++++++++++
health/hdp_util.h | 1 +
3 files changed, 398 insertions(+), 1 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 281be05..ede4186 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -101,7 +101,10 @@ static DBusMessage *hdp_create_instance(DBusConnection *conn,
/* TODO: Create mcap instance */
- /* TODO: Create SDP record if needed. */
+ if (!hdp_register_sdp_record(hdpi)) {
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Session can't be registered");
+ }
return g_dbus_create_error(msg,
ERROR_INTERFACE ".HealthError",
diff --git a/health/hdp_util.c b/health/hdp_util.c
index 8f6befc..b386be5 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -24,8 +24,14 @@
*/
#include <gdbus.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
#include "logging.h"
+#include "sdpd.h"
+
#include "hdp_types.h"
+#include "hdp_util.h"
+#include "mcap.h"
typedef gboolean (*parse_item_f)(DBusMessageIter *iter, GError **err,
gpointer user_data);
@@ -445,3 +451,390 @@ error:
free_config(config);
return NULL;
}
+
+static gboolean is_session_role(struct hdp_instance *hdps, HdpRole role)
+{
+ GSList *l;
+ struct hdp_supp_fts *fts;
+
+ if (!hdps->config)
+ return FALSE;
+ for (l = hdps->config->supp_fts; l; l = l->next) {
+ fts = l->data;
+ if (fts->role == role)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean register_service_protocols(struct hdp_instance *hdps,
+ sdp_record_t *sdp_record)
+{
+ gboolean error = FALSE;
+ uuid_t l2cap_uuid, mcap_c_uuid;
+ sdp_list_t *l2cap_list = NULL,
+ *proto_list = NULL,
+ *mcap_list = NULL,
+ *access_proto_list = NULL;
+ sdp_data_t *psm = NULL,
+ *mcap_ver = NULL;
+ uint16_t version = MCAP_VERSION;
+
+ // set l2cap information
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ l2cap_list = sdp_list_append(NULL, &l2cap_uuid);
+ if (!l2cap_list) {
+ error = TRUE;
+ goto end;
+ }
+ psm = sdp_data_alloc(SDP_UINT16, &hdps->ccpsm);
+ if (!psm) {
+ error = TRUE;
+ goto end;
+ }
+ if (!sdp_list_append(l2cap_list, psm)) {
+ error = TRUE;
+ goto end;
+ }
+ proto_list = sdp_list_append(NULL, l2cap_list);
+ if (!proto_list) {
+ error = TRUE;
+ goto end;
+ }
+
+ // set mcap information
+ sdp_uuid16_create(&mcap_c_uuid, MCAP_CTRL_UUID);
+ mcap_list = sdp_list_append(NULL, &mcap_c_uuid);
+ if (!mcap_list) {
+ error = TRUE;
+ goto end;
+ }
+ mcap_ver = sdp_data_alloc(SDP_UINT16, &version);
+ if (!mcap_ver) {
+ error = TRUE;
+ goto end;
+ }
+ if (!sdp_list_append( mcap_list, mcap_ver)) {
+ error = TRUE;
+ goto end;
+ }
+ if (!sdp_list_append( proto_list, mcap_list)) {
+ error = TRUE;
+ goto end;
+ }
+
+ // attach protocol information to service record
+ access_proto_list = sdp_list_append(NULL, proto_list);
+ if (!access_proto_list) {
+ error = TRUE;
+ goto end;
+ }
+ if (sdp_set_access_protos(sdp_record, access_proto_list) < 0)
+ error = TRUE;
+end:
+ if (l2cap_list)
+ sdp_list_free(l2cap_list, NULL);
+ if (mcap_list)
+ sdp_list_free(mcap_list, NULL);
+ if (proto_list)
+ sdp_list_free(proto_list, NULL);
+ if (access_proto_list)
+ sdp_list_free(access_proto_list, NULL);
+ if (psm)
+ sdp_data_free(psm);
+ if (mcap_ver)
+ sdp_data_free(mcap_ver);
+ return !error;
+}
+
+static gboolean register_service_profiles(sdp_record_t *sdp_record)
+{
+ gboolean error = FALSE;
+ sdp_list_t *profile_list = NULL;
+ sdp_profile_desc_t hdp_profile;
+
+ // set hdp information
+ sdp_uuid16_create( &hdp_profile.uuid, MDP_SVCLASS_ID);
+ hdp_profile.version = HDP_VERSION;
+ profile_list = sdp_list_append(NULL, &hdp_profile);
+ if (!profile_list)
+ return FALSE;
+ // set profile descriptor list
+ if (sdp_set_profile_descs(sdp_record, profile_list) < 0)
+ error = TRUE;
+
+ sdp_list_free(profile_list, NULL);
+ return !error;
+}
+
+static gboolean register_service_aditional_protocols(struct hdp_instance *hdps,
+ sdp_record_t *sdp_record)
+{
+ gboolean error = FALSE;
+ uuid_t l2cap_uuid, mcap_d_uuid;
+ sdp_list_t *l2cap_list = NULL,
+ *proto_list = NULL,
+ *mcap_list = NULL,
+ *access_proto_list = NULL;
+ sdp_data_t *psm = NULL;
+
+ // set l2cap information
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ l2cap_list = sdp_list_append(NULL, &l2cap_uuid);
+ if (!l2cap_list) {
+ error = TRUE;
+ goto end;
+ }
+ psm = sdp_data_alloc(SDP_UINT16, &hdps->dcpsm);
+ if (!psm) {
+ error = TRUE;
+ goto end;
+ }
+ if (!sdp_list_append(l2cap_list, psm)) {
+ error = TRUE;
+ goto end;
+ }
+ proto_list = sdp_list_append(NULL, l2cap_list);
+ if (!proto_list) {
+ error = TRUE;
+ goto end;
+ }
+
+ // set mcap information
+ sdp_uuid16_create(&mcap_d_uuid, MCAP_DATA_UUID);
+ mcap_list = sdp_list_append(NULL, &mcap_d_uuid);
+ if (!mcap_list) {
+ error = TRUE;
+ goto end;
+ }
+ if (!sdp_list_append( proto_list, mcap_list)) {
+ error = TRUE;
+ goto end;
+ }
+
+ // attach protocol information to service record
+ access_proto_list = sdp_list_append(NULL, proto_list);
+ if (!access_proto_list) {
+ error = TRUE;
+ goto end;
+ }
+ if (sdp_set_add_access_protos(sdp_record, access_proto_list) < 0)
+ error = TRUE;
+end:
+ if (l2cap_list)
+ sdp_list_free(l2cap_list, NULL);
+ if (mcap_list)
+ sdp_list_free(mcap_list, NULL);
+ if (proto_list)
+ sdp_list_free(proto_list, NULL);
+ if (access_proto_list)
+ sdp_list_free(access_proto_list, NULL);
+ if (psm)
+ sdp_data_free(psm);
+ return !error;
+}
+
+static sdp_list_t *feature_to_sdplist(struct hdp_supp_fts *fts,
+ struct hdp_feature *f)
+{
+ sdp_data_t *mdepid,
+ *dtype = NULL,
+ *role = NULL,
+ *desc = NULL;
+ sdp_list_t *f_list = NULL;
+
+ mdepid = sdp_data_alloc(SDP_UINT8, &fts->mdepid);
+ if (!mdepid)
+ return NULL;
+ dtype = sdp_data_alloc(SDP_UINT16, &f->dtype);
+ if (!dtype)
+ goto error;
+ role = sdp_data_alloc(SDP_UINT8, &fts->role);
+ if (!role)
+ goto error;
+ if (f->dscr) {
+ desc = sdp_data_alloc(SDP_TEXT_STR8, f->dscr);
+ if (!desc)
+ goto error;
+ }
+ f_list = sdp_list_append(NULL, mdepid);
+ if (!f_list)
+ goto error;
+ if (!sdp_list_append(f_list, dtype))
+ goto error;
+ if (!sdp_list_append(f_list, role))
+ goto error;
+ if (desc)
+ if (!sdp_list_append(f_list, desc))
+ goto error;
+ return f_list;
+error:
+ if (f_list)
+ 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 (desc)
+ sdp_data_free(desc);
+ return NULL;
+}
+
+static gboolean register_features(struct hdp_supp_fts *fts,
+ sdp_list_t **sup_features)
+{
+ GSList *l;
+ sdp_list_t *hdp_feature = NULL;
+
+ for (l = fts->features; l; l = l->next){
+ hdp_feature = feature_to_sdplist(fts, l->data);
+ if (!hdp_feature)
+ goto error;
+
+ if (!*sup_features) {
+ *sup_features = sdp_list_append(NULL, hdp_feature);
+ if (!*sup_features)
+ goto error;
+ } else if (!sdp_list_append(*sup_features, hdp_feature))
+ goto error;
+ hdp_feature = NULL;
+ }
+ return TRUE;
+error:
+ if (hdp_feature)
+ sdp_list_free(hdp_feature, (sdp_free_func_t)sdp_data_free);
+ return FALSE;
+}
+
+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);
+}
+
+static gboolean register_service_sup_features(struct hdp_config *config,
+ sdp_record_t *sdp_record)
+{
+ GSList *l;
+ sdp_list_t *sup_features = NULL;
+ for (l = config->supp_fts; l; l = l->next) {
+ if (!register_features(l->data, &sup_features))
+ return FALSE;
+ }
+ if (sdp_set_supp_feat(sdp_record, sup_features) < 0) {
+ sdp_list_free(sup_features, free_hdp_list);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean register_data_exchange_spec(struct hdp_config *config,
+ sdp_record_t *record)
+{
+ sdp_data_t *spec;
+
+ spec = sdp_data_alloc(SDP_UINT8, &config->data_spec);
+ if (!spec)
+ return FALSE;
+ if (sdp_attr_add(record, SDP_ATTR_DATA_EXCHANGE_SPEC, spec) < 0) {
+ sdp_data_free(spec);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean register_mcap_features(sdp_record_t *sdp_record)
+{
+ sdp_data_t *mcap_proc;
+ uint8_t mcap_sup_proc = MCAP_SUP_PROC;
+
+ mcap_proc = sdp_data_alloc(SDP_UINT8, &mcap_sup_proc);
+ if (!mcap_proc)
+ return FALSE;
+ if (sdp_attr_add(sdp_record, SDP_ATTR_MCAP_SUPPORTED_PROCEDURES,
+ mcap_proc) < 0) {
+ sdp_data_free(mcap_proc);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean set_sdp_services_uuid(sdp_record_t *record, HdpRole role)
+{
+ uuid_t svc_uuid_source, svc_uuid_sink;
+ sdp_list_t *svc_list = NULL;
+
+ sdp_uuid16_create(&svc_uuid_sink, MDP_SINK_SVCLASS_ID);
+ sdp_uuid16_create(&svc_uuid_source, MDP_SOURCE_SVCLASS_ID);
+
+ sdp_get_service_classes(record, &svc_list);
+
+ if (role == HDP_SOURCE) {
+ if (sdp_list_find(svc_list, &svc_uuid_source, sdp_uuid_cmp) == NULL)
+ svc_list = sdp_list_append(svc_list, &svc_uuid_source);
+ }
+ else if (role == HDP_SINK) {
+ if (sdp_list_find(svc_list, &svc_uuid_sink, sdp_uuid_cmp) == NULL)
+ svc_list = sdp_list_append(svc_list, &svc_uuid_sink);
+ }
+
+ if (sdp_set_service_classes(record, svc_list) < 0) {
+ sdp_list_free(svc_list, NULL);
+ return FALSE;
+ }
+
+ sdp_list_free(svc_list, NULL);
+ return TRUE;
+}
+
+gboolean hdp_register_sdp_record(struct hdp_instance *hdps)
+{
+ sdp_record_t *sdp_record;
+ struct hdp_config *config;
+ bdaddr_t addr;
+
+ if (!hdps->config) /* Record is not needed */
+ return TRUE;
+ config = hdps->config;
+
+ sdp_record = sdp_record_alloc();
+ if (!sdp_record)
+ return FALSE;
+ sdp_record->handle = 0xffffffff; /* Set automatically */
+
+ if (is_session_role(hdps, HDP_SINK))
+ set_sdp_services_uuid(sdp_record, HDP_SINK);
+ if (is_session_role(hdps, HDP_SOURCE))
+ set_sdp_services_uuid(sdp_record, HDP_SOURCE);
+
+ if (!register_service_protocols(hdps, sdp_record))
+ goto error;
+ if (!register_service_profiles(sdp_record))
+ goto error;
+ if (!register_service_aditional_protocols(hdps, sdp_record))
+ goto error;
+ sdp_set_info_attr(sdp_record, config->svc_name, config->svc_prov,
+ config->svc_dsc);
+ if (!register_service_sup_features(config, sdp_record))
+ goto error;
+ if (!register_data_exchange_spec(config, sdp_record))
+ goto error;
+
+ register_mcap_features(sdp_record);
+
+ adapter_get_address(hdps->adapter->btd_adapter, &addr);
+
+ if (add_record_to_server(&addr, sdp_record) < 0)
+ goto error;
+ hdps->sdp_handler = sdp_record->handle;
+ return TRUE;
+error:
+ if (sdp_record)
+ sdp_record_free(sdp_record);
+ return FALSE;
+}
diff --git a/health/hdp_util.h b/health/hdp_util.h
index f09e9a6..fb114c7 100644
--- a/health/hdp_util.h
+++ b/health/hdp_util.h
@@ -30,5 +30,6 @@
#include "hdp_types.h"
struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err);
+gboolean hdp_register_sdp_record(struct hdp_instance *hdps);
#endif /* __HDP_UTIL_H__ */
--
1.6.3.3
From: José Antonio Santos Cadenas <[email protected]>
Register interface for each hdp_driver plugged
Unregister driver
Device_get_health_instances method added
Add function to get data exchange spec from a remote record
---
health/hdp.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++---
health/hdp.h | 4 +-
health/hdp_types.h | 10 ++++
health/hdp_util.c | 11 +++++
health/hdp_util.h | 2 +
health/manager.c | 20 +++-----
6 files changed, 151 insertions(+), 22 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index 1094170..ae6add4 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -29,12 +29,16 @@
#include "hdp_types.h"
#include "hdp_util.h"
-
-#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
+#include "device.h"
#include "../src/dbus-common.h"
+#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
+#define HEALTH_INSTANCE_INTERFACE "org.bluez.HealthInstance"
+#define HEALTH_DEVICE "org.bluez.HealthDevice"
+
static GSList *adapters = NULL;
+static GSList *devices = NULL;
static struct hdp_adapter *find_adapter(GSList *list,
struct btd_adapter *btd_adapter)
@@ -51,6 +55,98 @@ static struct hdp_adapter *find_adapter(GSList *list,
return NULL;
}
+static struct hdp_device *find_device(GSList *devices, struct btd_device *dev)
+{
+ GSList *l;
+ struct hdp_device *device;
+
+ for (l = devices; l != NULL; l = l->next) {
+ device = l->data;
+
+ if (device->dev == dev)
+ return device;
+ }
+
+ return NULL;
+}
+
+static DBusMessage *get_health_instances(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct hdp_device *device = user_data;
+ const sdp_record_t *rec;
+ guint8 data_spec;
+
+ rec = btd_device_get_record(device->dev, HDP_UUID);
+
+ if (!rec) {
+ debug("No record found");
+ goto error;
+ }
+
+ if (!hdp_get_data_exchange_spec(rec, &data_spec))
+ goto error;
+
+ debug("Get data exchange spec %d", data_spec);
+error:
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
+ "Cannot get the remote SDP record");
+}
+
+static void health_device_free(struct hdp_device *device)
+{
+ if (device->conn) {
+ dbus_connection_unref(device->conn);
+ device->conn = NULL;
+ }
+
+ if (device->dev) {
+ btd_device_unref(device->dev);
+ device->dev = NULL;
+ }
+
+ g_free(device);
+}
+
+static void dev_path_unregister(void *data)
+{
+ struct hdp_device *device = data;
+
+
+ debug("Unregistered interface %s on path %s", HEALTH_DEVICE,
+ device_get_path(device->dev));
+ devices = g_slist_remove(devices, device);
+ health_device_free(device);
+}
+
+static GDBusMethodTable device_methods[] = {
+ { "GetHealthInstances", "", "a{sv}", get_health_instances },
+ { NULL }
+};
+
+static struct hdp_device *create_health_device(DBusConnection *conn,
+ struct btd_device *device)
+{
+ const gchar *path = device_get_path(device);
+ struct hdp_device *dev;
+
+ dev = g_new0(struct hdp_device, 1);
+ dev->conn = dbus_connection_ref(conn);
+ dev->dev = btd_device_ref(device);
+
+ if (!g_dbus_register_interface(conn, path,
+ HEALTH_DEVICE,
+ device_methods, NULL, NULL,
+ dev, dev_path_unregister)) {
+ error("D-Bus failed to register %s interface", HEALTH_DEVICE);
+ health_device_free(dev);
+ return NULL;
+ }
+
+ debug("Registered interface %s on path %s", HEALTH_DEVICE, path);
+ return dev;
+}
+
static void hdp_set_instance_id(struct hdp_instance *hdpi)
{
struct hdp_adapter *adapter = hdpi->adapter;
@@ -59,7 +155,7 @@ static void hdp_set_instance_id(struct hdp_instance *hdpi)
}
static DBusMessage *hdp_create_instance(DBusConnection *conn,
- DBusMessage *msg, void *user_data)
+ DBusMessage *msg, void *user_data)
{
struct hdp_adapter *adapter = user_data;
const char *path, *name;
@@ -185,13 +281,29 @@ void hdp_adapter_unregister(struct btd_adapter *btd_adapter)
debug("HDP exit");
}
-int health_device_register(struct btd_device *device, const char *uuid)
+int hdp_device_register(DBusConnection *conn, struct btd_device *device)
{
- debug("HDP_DRIVER_PROBE with uuid %s", uuid);
+ struct hdp_device *hdp_dev;
+
+ hdp_dev = find_device(devices, device);
+ if (!hdp_dev) {
+ hdp_dev = create_health_device(conn, device);
+ if (!hdp_dev)
+ return -1;
+ devices = g_slist_append(devices, hdp_dev);
+ }
return 0;
}
-void health_device_unregister(struct btd_device *device)
+void hdp_device_unregister(struct btd_device *device)
{
- debug("TODO: Remove device");
+ struct hdp_device *hdp_dev;
+ const char *path;
+
+ hdp_dev = find_device(devices, device);
+ if (!hdp_dev)
+ return;
+
+ path = device_get_path(hdp_dev->dev);
+ g_dbus_unregister_interface(hdp_dev->conn, path, HEALTH_DEVICE);
}
diff --git a/health/hdp.h b/health/hdp.h
index 0aae7b9..edb06a0 100644
--- a/health/hdp.h
+++ b/health/hdp.h
@@ -26,5 +26,5 @@
int hdp_adapter_register(DBusConnection *conn, struct btd_adapter *btd_adapter);
void hdp_adapter_unregister(struct btd_adapter *btd_adapter);
-int health_device_register(struct btd_device *device, const char *uuid);
-void health_device_unregister(struct btd_device *device);
+int hdp_device_register(DBusConnection *conn, struct btd_device *device);
+void hdp_device_unregister(struct btd_device *device);
diff --git a/health/hdp_types.h b/health/hdp_types.h
index 2db9adf..171910a 100644
--- a/health/hdp_types.h
+++ b/health/hdp_types.h
@@ -30,6 +30,10 @@
#include <glib.h>
#include "mcap_lib.h"
+#define HDP_UUID "00001400-0000-1000-8000-00805F9B34FB"
+#define HDP_SOURCE_UUID "00001401-0000-1000-8000-00805F9B34FB"
+#define HDP_SINK_UUID "00001402-0000-1000-8000-00805F9B34FB"
+
#define HDP_SERVICE_NAME "Bluez HDP"
#define HDP_SERVICE_DSC "A Bluez health device profile implementation"
#define HDP_SERVICE_PROVIDER "Bluez"
@@ -96,4 +100,10 @@ struct hdp_instance {
uint32_t sdp_handler; /* SDP record handler */
};
+struct hdp_device {
+ DBusConnection *conn; /* for name listener handling */
+ struct btd_device *dev; /* Device reference */
+ struct hdp_adapter *hdp_adapter; /* hdp_adapater */
+};
+
#endif /* __HDP_TYPES_H__ */
diff --git a/health/hdp_util.c b/health/hdp_util.c
index b386be5..816078a 100644
--- a/health/hdp_util.c
+++ b/health/hdp_util.c
@@ -838,3 +838,14 @@ error:
sdp_record_free(sdp_record);
return FALSE;
}
+
+gboolean hdp_get_data_exchange_spec(const sdp_record_t *rec, guint8 *val)
+{
+ sdp_data_t *exspec;
+
+ exspec = sdp_data_get(rec, SDP_ATTR_DATA_EXCHANGE_SPEC);
+ if (exspec->dtd != SDP_UINT8)
+ return FALSE;
+ *val = exspec->val.uint8;
+ return TRUE;
+}
diff --git a/health/hdp_util.h b/health/hdp_util.h
index fb114c7..0fdaaec 100644
--- a/health/hdp_util.h
+++ b/health/hdp_util.h
@@ -31,5 +31,7 @@
struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err);
gboolean hdp_register_sdp_record(struct hdp_instance *hdps);
+gboolean hdp_get_data_exchange_spec(const sdp_record_t *rec, guint8 *val);
+void hdp_instance_free(struct hdp_instance *hdpi);
#endif /* __HDP_UTIL_H__ */
diff --git a/health/manager.c b/health/manager.c
index 9b3b1a5..2f87db9 100644
--- a/health/manager.c
+++ b/health/manager.c
@@ -28,20 +28,19 @@
#endif
#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
#include <glib.h>
#include <gdbus.h>
-#include "adapter.h"
-#include "device.h"
+#include "hdp_types.h"
#include "logging.h"
#include "manager.h"
#include "hdp.h"
-#define HDP_UUID "00001400-0000-1000-8000-00805F9B34FB"
-#define HDP_SOURCE_UUID "00001401-0000-1000-8000-00805F9B34FB"
-#define HDP_SINK_UUID "00001402-0000-1000-8000-00805F9B34FB"
+#include "device.h"
+#include "glib-helper.h"
static DBusConnection *connection = NULL;
@@ -63,22 +62,17 @@ static struct btd_adapter_driver hdp_adapter_driver = {
static int hdp_driver_probe(struct btd_device *device, GSList *uuids)
{
- while (uuids) {
- health_device_register(device, uuids->data);
- uuids = uuids->next;
- }
-
- return 0;
+ return hdp_device_register(connection, device);
}
static void hdp_driver_remove(struct btd_device *device)
{
- health_device_unregister(device);
+ hdp_device_unregister(device);
}
static struct btd_device_driver hdp_device_driver = {
.name = "hdp-device-driver",
- .uuids = BTD_UUIDS(HDP_UUID, HDP_SOURCE_UUID, HDP_SINK_UUID),
+ .uuids = BTD_UUIDS(HDP_UUID),
.probe = hdp_driver_probe,
.remove = hdp_driver_remove,
};
--
1.6.3.3
From: José Antonio Santos Cadenas <[email protected]>
---
health/hdp.c | 11 +++++++++++
health/hdp.h | 3 +++
health/manager.c | 10 +++++++---
3 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/health/hdp.c b/health/hdp.c
index ede4186..1094170 100644
--- a/health/hdp.c
+++ b/health/hdp.c
@@ -184,3 +184,14 @@ void hdp_adapter_unregister(struct btd_adapter *btd_adapter)
debug("HDP exit");
}
+
+int health_device_register(struct btd_device *device, const char *uuid)
+{
+ debug("HDP_DRIVER_PROBE with uuid %s", uuid);
+ return 0;
+}
+
+void health_device_unregister(struct btd_device *device)
+{
+ debug("TODO: Remove device");
+}
diff --git a/health/hdp.h b/health/hdp.h
index 893f745..0aae7b9 100644
--- a/health/hdp.h
+++ b/health/hdp.h
@@ -25,3 +25,6 @@
int hdp_adapter_register(DBusConnection *conn, struct btd_adapter *btd_adapter);
void hdp_adapter_unregister(struct btd_adapter *btd_adapter);
+
+int health_device_register(struct btd_device *device, const char *uuid);
+void health_device_unregister(struct btd_device *device);
diff --git a/health/manager.c b/health/manager.c
index b5dec5a..9b3b1a5 100644
--- a/health/manager.c
+++ b/health/manager.c
@@ -63,17 +63,21 @@ static struct btd_adapter_driver hdp_adapter_driver = {
static int hdp_driver_probe(struct btd_device *device, GSList *uuids)
{
- debug("hdp driver probe");
+ while (uuids) {
+ health_device_register(device, uuids->data);
+ uuids = uuids->next;
+ }
+
return 0;
}
static void hdp_driver_remove(struct btd_device *device)
{
- debug("hdp driver remove");
+ health_device_unregister(device);
}
static struct btd_device_driver hdp_device_driver = {
- .name = "hdp_device-driver",
+ .name = "hdp-device-driver",
.uuids = BTD_UUIDS(HDP_UUID, HDP_SOURCE_UUID, HDP_SINK_UUID),
.probe = hdp_driver_probe,
.remove = hdp_driver_remove,
--
1.6.3.3
Creates the basic structure of the plugin, registering
adapter and device drivers.
---
Makefile.am | 8 +
acinclude.m4 | 8 +-
health/hdp.c | 183 +++++++++++++++++++++
health/hdp.h | 27 +++
health/hdp_types.h | 99 ++++++++++++
health/hdp_util.c | 447 ++++++++++++++++++++++++++++++++++++++++++++++++++++
health/hdp_util.h | 34 ++++
health/main.c | 60 +++++++
health/manager.c | 101 ++++++++++++
health/manager.h | 27 +++
10 files changed, 993 insertions(+), 1 deletions(-)
create mode 100644 health/hdp.c
create mode 100644 health/hdp.h
create mode 100644 health/hdp_types.h
create mode 100644 health/hdp_util.c
create mode 100644 health/hdp_util.h
create mode 100644 health/main.c
create mode 100644 health/manager.c
create mode 100644 health/manager.h
diff --git a/Makefile.am b/Makefile.am
index 9ab5be2..d30850f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -169,6 +169,14 @@ builtin_modules += service
builtin_sources += plugins/service.c
endif
+if HEALTHPLUGIN
+builtin_modules += health
+builtin_sources += health/main.c \
+ health/manager.h health/manager.c \
+ health/hdp.h health/hdp.c \
+ health/hdp_util.h health/hdp_util.c
+endif
+
if MCAP
mcap_sources += mcap/mcap_internal.h \
mcap/mcap_lib.h mcap/sync.c \
diff --git a/acinclude.m4 b/acinclude.m4
index b512cfb..23c594a 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -167,6 +167,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
serial_enable=yes
network_enable=yes
service_enable=yes
+ health_enable=no
mcap_enable=no
pnat_enable=no
tracer_enable=no
@@ -216,6 +217,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
service_enable=${enableval}
])
+ AC_ARG_ENABLE(health, AC_HELP_STRING([--enable-health], [enable health plugin]), [
+ health_enable=${enableval}
+ ])
+
AC_ARG_ENABLE(mcap, AC_HELP_STRING([--enable-mcap], [enable mcap support]), [
mcap_enable=${enableval}
])
@@ -330,7 +335,8 @@ AC_DEFUN([AC_ARG_BLUEZ], [
AM_CONDITIONAL(SERIALPLUGIN, test "${serial_enable}" = "yes")
AM_CONDITIONAL(NETWORKPLUGIN, test "${network_enable}" = "yes")
AM_CONDITIONAL(SERVICEPLUGIN, test "${service_enable}" = "yes")
- AM_CONDITIONAL(MCAP, test "${mcap_enable}" = "yes")
+ AM_CONDITIONAL(HEALTHPLUGIN, test "${health_enable}" = "yes")
+ AM_CONDITIONAL(MCAP, test "${mcap_enable}" = "yes" || test "${health_enable}" = "yes")
AM_CONDITIONAL(ECHOPLUGIN, test "no" = "yes")
AM_CONDITIONAL(PNATPLUGIN, test "${pnat_enable}" = "yes")
AM_CONDITIONAL(TRACER, test "${tracer_enable}" = "yes")
diff --git a/health/hdp.c b/health/hdp.c
new file mode 100644
index 0000000..281be05
--- /dev/null
+++ b/health/hdp.c
@@ -0,0 +1,183 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#include <gdbus.h>
+
+#include "logging.h"
+#include "error.h"
+
+#include "hdp_types.h"
+#include "hdp_util.h"
+
+#define HEALTH_MANAGER_INTERFACE "org.bluez.HealthAdapter"
+
+#include "../src/dbus-common.h"
+
+static GSList *adapters = NULL;
+
+static struct hdp_adapter *find_adapter(GSList *list,
+ struct btd_adapter *btd_adapter)
+{
+ GSList *l;
+ struct hdp_adapter *adapter;
+
+ for (l = list; l; l = l->next) {
+ adapter = l->data;
+ if (adapter->btd_adapter == btd_adapter)
+ return adapter;
+ }
+
+ return NULL;
+}
+
+static void hdp_set_instance_id(struct hdp_instance *hdpi)
+{
+ struct hdp_adapter *adapter = hdpi->adapter;
+
+ hdpi->id = adapter->ic++;
+}
+
+static DBusMessage *hdp_create_instance(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct hdp_adapter *adapter = user_data;
+ const char *path, *name;
+ DBusMessageIter iter;
+ GError *err = NULL;
+ DBusMessage *reply;
+ struct hdp_instance *hdpi;
+ struct hdp_config *config;
+ int ctype;
+
+ dbus_message_iter_init(msg, &iter);
+ ctype = dbus_message_iter_get_arg_type(&iter);
+ if (ctype != DBUS_TYPE_OBJECT_PATH)
+ goto error;
+ dbus_message_iter_get_basic(&iter, &path);
+ dbus_message_iter_next(&iter);
+ config = hdp_get_config(&iter, &err);
+ if (err)
+ goto error;
+ name = dbus_message_get_sender(msg);
+ if (!name) {
+ g_set_error(&err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Can't get sender name");
+ goto error;
+ }
+
+ hdpi = g_new0(struct hdp_instance, 1);
+ hdpi->adapter = adapter;
+ hdpi->aname = g_strdup(name);
+ hdpi->apath = g_strdup(path);
+ hdpi->config = config;
+ if (!config->svc_dsc)
+ config->svc_dsc = g_strdup(HDP_SERVICE_DSC);
+ if (!config->svc_name)
+ config->svc_name = g_strdup(HDP_SERVICE_NAME);
+ if (!config->svc_prov)
+ config->svc_prov = g_strdup(HDP_SERVICE_PROVIDER);
+ hdp_set_instance_id(hdpi);
+
+ /* TODO: Create mcap instance */
+
+ /* TODO: Create SDP record if needed. */
+
+ return g_dbus_create_error(msg,
+ ERROR_INTERFACE ".HealthError",
+ "Incomplete call yet");
+error:
+ if (err) {
+ reply = g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments: %s", err->message);
+ g_error_free(err);
+ } else
+ reply = g_dbus_create_error(msg,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Invalid arguments in method call");
+ return reply;
+}
+
+static GDBusMethodTable hdp_methods[] = {
+ { "CreateInstance", "oa{sv}", "u", hdp_create_instance },
+ { NULL }
+};
+
+void hdp_delete_instance_iter(gpointer data, gpointer user_data)
+{
+ /* struct hdp_instance *hdpi = data; */
+
+ /* TODO: Create a free function */
+}
+
+static void hdp_path_unregister(void *data)
+{
+ struct hdp_adapter *adapter = data;
+
+ g_slist_foreach(adapter->instances, hdp_delete_instance_iter, NULL);
+ g_slist_free(adapter->instances);
+ adapter->instances = NULL;
+ debug("All hdp instance for removed adapter were closed");
+}
+
+int hdp_adapter_register(DBusConnection *conn, struct btd_adapter *btd_adapter)
+{
+ const char *path = adapter_get_path(btd_adapter);
+
+ struct hdp_adapter *adapter;
+ adapter = g_new0(struct hdp_adapter, 1);
+
+ debug("HDP init");
+ if (!g_dbus_register_interface(conn, path, HEALTH_MANAGER_INTERFACE,
+ hdp_methods, NULL, NULL,
+ adapter, hdp_path_unregister)) {
+ error("Failed to register %s interface to %s",
+ HEALTH_MANAGER_INTERFACE, path);
+ g_free(adapter);
+ return -1;
+ }
+ adapter->conn = dbus_connection_ref(conn);
+ adapter->btd_adapter = btd_adapter_ref(btd_adapter);
+ adapters = g_slist_prepend(adapters, adapter);
+ return 0;
+}
+
+void hdp_adapter_unregister(struct btd_adapter *btd_adapter)
+{
+ struct hdp_adapter *adapter;
+
+ adapter = find_adapter(adapters, btd_adapter);
+ if (!adapter)
+ return;
+
+ g_dbus_unregister_interface(adapter->conn,
+ adapter_get_path(btd_adapter),
+ HEALTH_MANAGER_INTERFACE);
+ dbus_connection_unref(adapter->conn);
+ btd_adapter_unref(adapter->btd_adapter);
+ adapters = g_slist_remove(adapters, adapter);
+ g_free(adapter);
+
+ debug("HDP exit");
+}
diff --git a/health/hdp.h b/health/hdp.h
new file mode 100644
index 0000000..893f745
--- /dev/null
+++ b/health/hdp.h
@@ -0,0 +1,27 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+int hdp_adapter_register(DBusConnection *conn, struct btd_adapter *btd_adapter);
+void hdp_adapter_unregister(struct btd_adapter *btd_adapter);
diff --git a/health/hdp_types.h b/health/hdp_types.h
new file mode 100644
index 0000000..2db9adf
--- /dev/null
+++ b/health/hdp_types.h
@@ -0,0 +1,99 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+
+#ifndef __HDP_TYPES_H__
+#define __HDP_TYPES_H__
+
+#include <glib.h>
+#include "mcap_lib.h"
+
+#define HDP_SERVICE_NAME "Bluez HDP"
+#define HDP_SERVICE_DSC "A Bluez health device profile implementation"
+#define HDP_SERVICE_PROVIDER "Bluez"
+
+#define HDP_VERSION 0x0100
+
+#define HDP_ERROR g_quark_from_static_string("hdp-error-quark")
+
+typedef enum {
+ HDP_DIC_PARSE_ERROR,
+ HDP_DIC_ENTRY_PARSE_ERROR,
+ HDP_UNSPECIFIED_ERROR,
+ HDP_UNKNOWN_ERROR
+} HdpError;
+
+enum data_specs {
+ DATA_EXCHANGE_SPEC_11073 = 0x01
+};
+
+typedef enum {
+ HDP_SOURCE = 0x00,
+ HDP_SINK = 0x01
+} HdpRole;
+
+struct hdp_feature {
+ guint16 dtype; /* Data type (see 5.2.9.2) */
+ gboolean dtype_present; /* Data type present in config */
+ char *dscr; /* Displayable TextName */
+};
+
+struct hdp_supp_fts {
+ guint8 mdepid; /* (0x01-0x7F) Available for use */
+ HdpRole role; /* Role (see table 5.3) */
+ gboolean role_present; /* Role present in config */
+ GSList *features; /* Feature list */
+};
+
+struct hdp_config {
+ guint8 data_spec; /* Data exchange specification */
+ GSList *supp_fts; /* Supported features list */
+ char *svc_name; /* Service name to register in SDP */
+ char *svc_dsc; /* Service description */
+ char *svc_prov; /* Service provider */
+ gboolean ds_present; /* Data spec has been assigned */
+};
+
+struct hdp_adapter {
+ struct btd_adapter *btd_adapter;
+ DBusConnection *conn; /* DBus connection */
+ GSList *instances; /* HDP instances list */
+ uint16_t ic; /* Instances counter */
+};
+
+struct hdp_instance {
+ struct hdp_adapter *adapter; /* HDP adapter */
+ struct mcap_instance *mi; /* MCAP instance */
+ uint16_t ccpsm; /* Control channel psm */
+ uint16_t dcpsm; /* Data channel psm */
+ GSList *hlink; /* Health Links */
+ uint32_t id; /* HDP instance id */
+ char *apath; /* HDP agent path */
+ char *aname; /* HDP agent name */
+ struct hdp_config *config; /* Configuration */
+ uint32_t sdp_handler; /* SDP record handler */
+};
+
+#endif /* __HDP_TYPES_H__ */
diff --git a/health/hdp_util.c b/health/hdp_util.c
new file mode 100644
index 0000000..8f6befc
--- /dev/null
+++ b/health/hdp_util.c
@@ -0,0 +1,447 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <gdbus.h>
+#include "logging.h"
+#include "hdp_types.h"
+
+typedef gboolean (*parse_item_f)(DBusMessageIter *iter, GError **err,
+ gpointer user_data);
+
+struct dict_entry_func {
+ char *key;
+ parse_item_f func;
+};
+
+static gboolean check_feature(struct hdp_feature *feature)
+{
+ return feature->dtype_present;
+}
+
+static gboolean check_feature_list(struct hdp_supp_fts *fts)
+{
+ return fts->role_present && (fts->features != NULL);
+}
+
+static gboolean check_config(struct hdp_config *config)
+{
+ if (config->ds_present)
+ return config->supp_fts != NULL;
+ return TRUE;
+}
+
+static gboolean hdp_check_data_spec(guint8 data_spec)
+{
+ /* Future versions may edit this function
+ * If there are more supported data exchange specifications
+ */
+ return data_spec == DATA_EXCHANGE_SPEC_11073;
+}
+
+static void free_feature(struct hdp_feature *feature)
+{
+ if (feature->dscr) {
+ g_free(feature->dscr);
+ feature->dscr = NULL;
+ }
+ g_free(feature);
+}
+
+static void free_feature_list(struct hdp_supp_fts *fts)
+{
+ GSList *l;
+
+ for (l = fts->features; l; l = l->next)
+ free_feature(l->data);
+ g_slist_free(fts->features);
+ fts->features = NULL;
+ g_free(fts);
+}
+
+static void free_config(struct hdp_config *config)
+{
+ GSList *l;
+
+ for (l = config->supp_fts; l; l = l->next)
+ free_feature_list(l->data);
+ g_slist_free(config->supp_fts);
+ config->supp_fts = NULL;
+ if (config->svc_dsc) {
+ g_free(config->svc_dsc);
+ config->svc_dsc = NULL;
+ }
+ if (config->svc_name) {
+ g_free(config->svc_name);
+ config->svc_name = NULL;
+ }
+ if (config->svc_prov) {
+ g_free(config->svc_prov);
+ config->svc_prov = NULL;
+ }
+ g_free(config);
+}
+
+static gboolean parse_dict_entry(struct dict_entry_func dict_context[],
+ DBusMessageIter *iter,
+ GError **err,
+ gpointer user_data)
+{
+ DBusMessageIter entry;
+ char *key;
+ int ctype, i;
+ struct dict_entry_func df;
+
+ dbus_message_iter_recurse(iter, &entry);
+ ctype = dbus_message_iter_get_arg_type(&entry);
+ if (ctype != DBUS_TYPE_STRING) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
+ "Dictionary entries should have a string as key");
+ return FALSE;
+ }
+ dbus_message_iter_get_basic(&entry, &key);
+ dbus_message_iter_next(&entry);
+ /* Find function and call it */
+ for (i = 0, df = dict_context[0]; df.key; i++, df = dict_context[i]) {
+ if (g_strcmp0(df.key, key) == 0) {
+ return df.func(&entry, err, user_data);
+ }
+ }
+ g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
+ "No function found for parsing value for key %s", key);
+ return FALSE;
+}
+
+static gboolean parse_dict(struct dict_entry_func dict_context[],
+ DBusMessageIter *iter,
+ GError **err,
+ gpointer user_data)
+{
+ int ctype;
+ DBusMessageIter dict;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ if (ctype != DBUS_TYPE_ARRAY) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_PARSE_ERROR,
+ "Dictionary should be an array");
+ return FALSE;
+ }
+ dbus_message_iter_recurse(iter, &dict);
+ while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
+ DBUS_TYPE_INVALID) {
+ if (ctype != DBUS_TYPE_DICT_ENTRY) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_PARSE_ERROR,
+ "Dictionary array should "
+ "contain dict entries");
+ return FALSE;
+ }
+ /* Start parsing entry */
+ if (!parse_dict_entry(dict_context, &dict, err,
+ user_data))
+ return FALSE;
+ /* Finish entry parsing */
+ dbus_message_iter_next(&dict);
+ }
+ return TRUE;
+}
+
+static gboolean parse_description(DBusMessageIter *iter, GError **err,
+ gpointer data)
+{
+ struct hdp_feature *feat = data;
+ DBusMessageIter *string, variant;
+ int ctype;
+ const char *desc;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ string = iter;
+ if (ctype == DBUS_TYPE_VARIANT) {
+ /* Get value inside the variable */
+ dbus_message_iter_recurse(iter, &variant);
+ ctype = dbus_message_iter_get_arg_type(&variant);
+ string = &variant;
+ }
+
+ if (ctype != DBUS_TYPE_STRING) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
+ "Value data spec should be variable or string");
+ return FALSE;
+ }
+
+ dbus_message_iter_get_basic(string, &desc);
+ feat->dscr = g_strdup(desc);
+ return TRUE;
+}
+
+static gboolean parse_data_type(DBusMessageIter *iter, GError **err,
+ gpointer data)
+{
+ struct hdp_feature *feat = data;
+ DBusMessageIter *value, variant;
+ int ctype;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ value = iter;
+ if (ctype == DBUS_TYPE_VARIANT) {
+ /* Get value inside the variable */
+ dbus_message_iter_recurse(iter, &variant);
+ ctype = dbus_message_iter_get_arg_type(&variant);
+ value = &variant;
+ }
+
+ if (ctype != DBUS_TYPE_UINT16) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
+ "Final value for data type should be a uint16");
+ return FALSE;
+ }
+ dbus_message_iter_get_basic(value, &feat->dtype);
+
+ /*
+ * This data should be check by the application layer because it
+ * depends on the data_spec values and is specific for each value
+ */
+ feat->dtype_present = TRUE;
+
+ return TRUE;
+}
+
+static struct dict_entry_func specs_context[] = {
+ {"data_type", parse_data_type},
+ {"description", parse_description},
+ {NULL, NULL}
+};
+
+static gboolean parse_specs(DBusMessageIter *iter, GError **err, gpointer data)
+{
+ struct hdp_supp_fts *fts = data;
+ struct hdp_feature *feature = NULL;
+ DBusMessageIter *array, value, dict;
+ int ctype;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ array = iter;
+ if (ctype == DBUS_TYPE_VARIANT) {
+ /* Get value inside the variable */
+ dbus_message_iter_recurse(iter, &value);
+ ctype = dbus_message_iter_get_arg_type(&value);
+ array = &value;
+ }
+ if (ctype != DBUS_TYPE_ARRAY) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
+ "Value specs should be variable or array");
+ return FALSE;
+ }
+ dbus_message_iter_recurse(array, &dict);
+ while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
+ DBUS_TYPE_INVALID){
+ feature = g_new0(struct hdp_feature, 1);
+ if (!parse_dict(specs_context, &dict, err, feature))
+ goto error;
+ if (!check_feature(feature)) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
+ "Field \"data_type\" is mandatory");
+ goto error;
+ }
+ fts->features = g_slist_append(fts->features, feature);
+ dbus_message_iter_next(&dict);
+ }
+
+ return TRUE;
+error:
+ if (feature)
+ free_feature(feature);
+ return FALSE;
+}
+
+static gboolean parse_role(DBusMessageIter *iter, GError **err, gpointer data)
+{
+ struct hdp_supp_fts *fts = data;
+ DBusMessageIter value;
+ DBusMessageIter *string;
+ int ctype;
+ const char *role;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ string = iter;
+ if (ctype == DBUS_TYPE_VARIANT) {
+ /* Get value inside the variable */
+ dbus_message_iter_recurse(iter, &value);
+ ctype = dbus_message_iter_get_arg_type(&value);
+ string = &value;
+ }
+
+ if (ctype != DBUS_TYPE_STRING) {
+ g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Value data spec should be variable or string");
+ return FALSE;
+ }
+
+ dbus_message_iter_get_basic(string, &role);
+ if (g_strcmp0(role, "sink") == 0)
+ fts->role = HDP_SINK;
+ else if (g_strcmp0(role, "source") == 0)
+ fts->role = HDP_SOURCE;
+ else {
+ g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Role value should be \"source\" or \"sink\"");
+ return FALSE;
+ }
+ fts->role_present = TRUE;
+ return TRUE;
+}
+
+static struct dict_entry_func end_point_context[] = {
+ {"role", parse_role},
+ {"specs", parse_specs},
+ {NULL, NULL}
+};
+
+static gboolean parse_end_points(DBusMessageIter *iter, GError **err,
+ gpointer data)
+{
+ struct hdp_config *config = data;
+ struct hdp_supp_fts *fts = NULL;
+ DBusMessageIter array, dict;
+ int ctype;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ if (ctype != DBUS_TYPE_VARIANT) {
+ g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Value for end points should be variable");
+ return FALSE;
+ }
+ dbus_message_iter_recurse(iter, &array);
+ ctype = dbus_message_iter_get_arg_type(&array);
+ if (ctype != DBUS_TYPE_ARRAY) {
+ g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Value end_point should be array inside variable");
+ return FALSE;
+ }
+
+ dbus_message_iter_recurse(&array, &dict);
+ while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
+ DBUS_TYPE_INVALID){
+
+ if (ctype != DBUS_TYPE_ARRAY) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_PARSE_ERROR,
+ "Dictionary should be an array");
+ return FALSE;
+ }
+ fts = g_new0(struct hdp_supp_fts, 1);
+ if (!parse_dict(end_point_context, &dict, err, fts))
+ goto error;
+ if (!check_feature_list(fts)) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_PARSE_ERROR,
+ "Role field and specs are mandatory");
+ goto error;
+ }
+ config->supp_fts = g_slist_append(config->supp_fts, fts);
+ dbus_message_iter_next(&dict);
+ }
+ return TRUE;
+error:
+ if (fts)
+ free_feature_list(fts);
+ return FALSE;
+}
+
+static gboolean parse_data_spec(DBusMessageIter *iter, GError **err,
+ gpointer data)
+{
+ struct hdp_config *config = data;
+ DBusMessageIter value;
+ int ctype;
+
+ ctype = dbus_message_iter_get_arg_type(iter);
+ if (ctype != DBUS_TYPE_VARIANT) {
+ g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Value data spec should be variable");
+ return FALSE;
+ }
+ dbus_message_iter_recurse(iter, &value);
+ ctype = dbus_message_iter_get_arg_type(&value);
+ if (ctype != DBUS_TYPE_BYTE) {
+ g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
+ "Final value data spec should be byte");
+ return FALSE;
+ }
+
+ dbus_message_iter_get_basic(&value, &config->data_spec);
+
+ if (!hdp_check_data_spec(config->data_spec))
+ return FALSE;
+ config->ds_present = TRUE;
+ return TRUE;
+}
+
+static struct dict_entry_func main_context[] = {
+ {"data_spec", parse_data_spec},
+ {"end_points", parse_end_points},
+ {NULL, NULL}
+};
+
+static void print_feature(gpointer elem, gpointer data)
+{
+ struct hdp_feature *feat = elem;
+
+ debug(" Feature:");
+ debug(" description: %s", feat->dscr);
+ debug(" data type: %u", feat->dtype);
+}
+
+static void print_features(gpointer elem, gpointer data)
+{
+ struct hdp_supp_fts *fts = elem;
+
+ debug("Mdep:");
+ debug(" mdepid %u", fts->mdepid);
+ debug(" role %d", fts->role);
+ g_slist_foreach(fts->features, print_feature, NULL);
+}
+
+struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err)
+{
+ struct hdp_config *config;
+
+ config = g_new0(struct hdp_config, 1);
+
+ if (!parse_dict(main_context, iter, err, config))
+ goto error;
+
+ /* TODO check config */
+ if (!check_config(config)) {
+ g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
+ "\"data_spec\" and \"end_point\" should be set or not");
+ goto error;
+ }
+ if (!config->ds_present)
+ goto error;
+ debug("config->data_spec %d", config->data_spec);
+ g_slist_foreach(config->supp_fts, print_features, NULL);
+ return config;
+error:
+ if (config)
+ free_config(config);
+ return NULL;
+}
diff --git a/health/hdp_util.h b/health/hdp_util.h
new file mode 100644
index 0000000..f09e9a6
--- /dev/null
+++ b/health/hdp_util.h
@@ -0,0 +1,34 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __HDP_UTIL_H__
+#define __HDP_UTIL_H__
+
+#include <gdbus.h>
+#include "hdp_types.h"
+
+struct hdp_config *hdp_get_config(DBusMessageIter *iter, GError **err);
+
+#endif /* __HDP_UTIL_H__ */
diff --git a/health/main.c b/health/main.c
new file mode 100644
index 0000000..6ece69b
--- /dev/null
+++ b/health/main.c
@@ -0,0 +1,60 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <gdbus.h>
+
+#include "plugin.h"
+#include "manager.h"
+
+static DBusConnection *connection;
+
+static int hdp_init(void)
+{
+ connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (connection == NULL)
+ return -EIO;
+
+ if (hdp_manager_init(connection) < 0) {
+ dbus_connection_unref(connection);
+ return -EIO;
+ }
+ return 0;
+}
+
+static void hdp_exit(void)
+{
+ hdp_manager_exit();
+
+ dbus_connection_unref(connection);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(health, VERSION,
+ BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, hdp_init, hdp_exit)
diff --git a/health/manager.c b/health/manager.c
new file mode 100644
index 0000000..b5dec5a
--- /dev/null
+++ b/health/manager.c
@@ -0,0 +1,101 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <bluetooth/sdp.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "adapter.h"
+#include "device.h"
+
+#include "logging.h"
+#include "manager.h"
+#include "hdp.h"
+
+#define HDP_UUID "00001400-0000-1000-8000-00805F9B34FB"
+#define HDP_SOURCE_UUID "00001401-0000-1000-8000-00805F9B34FB"
+#define HDP_SINK_UUID "00001402-0000-1000-8000-00805F9B34FB"
+
+static DBusConnection *connection = NULL;
+
+static int hdp_adapter_probe(struct btd_adapter *adapter)
+{
+ return hdp_adapter_register(connection, adapter);
+}
+
+static void hdp_adapter_remove(struct btd_adapter *adapter)
+{
+ hdp_adapter_unregister(adapter);
+}
+
+static struct btd_adapter_driver hdp_adapter_driver = {
+ .name = "hdp-adapter-driver",
+ .probe = hdp_adapter_probe,
+ .remove = hdp_adapter_remove,
+};
+
+static int hdp_driver_probe(struct btd_device *device, GSList *uuids)
+{
+ debug("hdp driver probe");
+ return 0;
+}
+
+static void hdp_driver_remove(struct btd_device *device)
+{
+ debug("hdp driver remove");
+}
+
+static struct btd_device_driver hdp_device_driver = {
+ .name = "hdp_device-driver",
+ .uuids = BTD_UUIDS(HDP_UUID, HDP_SOURCE_UUID, HDP_SINK_UUID),
+ .probe = hdp_driver_probe,
+ .remove = hdp_driver_remove,
+};
+
+int hdp_manager_init(DBusConnection *conn)
+{
+ connection = dbus_connection_ref(conn);
+
+ btd_register_adapter_driver(&hdp_adapter_driver);
+ btd_register_device_driver(&hdp_device_driver);
+
+ debug("hdp manager init");
+ return 0;
+}
+
+void hdp_manager_exit(void)
+{
+ btd_unregister_device_driver(&hdp_device_driver);
+ btd_unregister_adapter_driver(&hdp_adapter_driver);
+
+ dbus_connection_unref(connection);
+ connection = NULL;
+ debug("hdp manager exit");
+}
diff --git a/health/manager.h b/health/manager.h
new file mode 100644
index 0000000..b91ef75
--- /dev/null
+++ b/health/manager.h
@@ -0,0 +1,27 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ * Authors:
+ * Santiago Carot Nemesio <sancane at gmail.com>
+ * Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+int hdp_manager_init(DBusConnection *conn);
+void hdp_manager_exit(void);
--
1.6.3.3
This API describes the interface shown by the Health plugin through d-bus
---
doc/health-api.txt | 217 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 217 insertions(+), 0 deletions(-)
create mode 100644 doc/health-api.txt
diff --git a/doc/health-api.txt b/doc/health-api.txt
new file mode 100644
index 0000000..83e29af
--- /dev/null
+++ b/doc/health-api.txt
@@ -0,0 +1,217 @@
+BlueZ D-Bus Health API description
+**********************************
+
+ Santiago Carot-Nemesio <[email protected]>
+ José Antonio Santos-Cadenas <[email protected]>
+ Elvis Pfützenreuter <[email protected]>
+
+Health Device Profile hierarchy
+===============================
+
+Service org.bluez
+Interface org.bluez.HealthAdapter
+Object path [variable prefix]/{hci0,hci1,...}
+
+Methods:
+
+ uint32 CreateInstance(object path, dict config)
+
+ Returns the id of the new created instance. The path parameter
+ is the path of the remote object with the callbacks to notify
+ events (see org.bluez.HealthAgent at the end of this document)
+ This petition starts an mcap instance and also register in the
+ SDP if is needed.
+
+ Dict is defined as bellow:
+ { "data_spec" : The data_spec is the data exchange specification
+ (see section 5.2.10 of the specification
+ document) possible values:
+ 0x00 = reserved,
+ 0x01 [IEEE 11073-20601],
+ 0x02..0xff reserved,
+ (optional)
+ "end_points" : [{ (optional)
+ "mdepid" : uint8, (optional)
+ "role" : ("source" or "sink"), (mandatory)
+ "specs" :[{ (mandatory)
+ "data_type" : uint16, (mandatory)
+ "description" : string, (optional)
+ }]
+ }]
+ }
+
+ if "data_spec" is not set, no SDP record will be registered, so
+ all the other data in the dictionary will be ignored.
+
+ Instance will be closed by the call or implicitly when the
+ programs leaves the bus.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+
+ void CloseInstance(uint32 )
+
+ Closes the HDP instance identified by the object path. Also
+ instance will be closed if the process that started leaves the
+ bus. If there is a SDP record associated to this instance it
+ will be removed.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotFound
+
+--------------------------------------------------------------------------------
+
+Service org.bluez
+Interface org.bluez.HealthDevice
+Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+Methods:
+
+ array GetHealthInstances()
+
+ Gets the information of the remote instances present in this
+ device and published on its SDP record. The returned data
+ follows this format.
+
+ [{"id": uint32,
+ "data_spec" : data spec,
+ "end_points":
+ ["mdepid": uint8,
+ "role" : "source" or "sink" ,
+ "specs" : [{
+ "dtype" : uint16,
+ "description" : string, (optional)
+ }]
+ ]
+ }];
+
+ object Connect(uint32 local_instance_id, uint32 remote_instance_id)
+
+ Connects the local instance with the remote instance and returns
+ the path of the HealthLink object. You should get the remote
+ instance id running GetHealthInstances.
+
+ Only the bus client that created the local session will be able
+ to create connections using it.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.HealthError
+
+ void Disconnect(object link, boolean cache)
+
+ Disconnect from the link. If cache is false, state will also be
+ deleted. Otherwise, the state will be kept for allowing future
+ reconnections until the adapter holding the local session is
+ removed.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotFound
+ org.bluez.Error.HealthError
+
+--------------------------------------------------------------------------------
+
+Service org.bluez
+Interface org.bluez.HealthLink
+Object path [variable prefix]/{hci0,hci1,...}/{hdp0,hdp1,...}/rem_inst_id
+
+Methods:
+
+ boolean Echo(array{byte})
+
+ Sends an echo petition to the remote intance. Returns True if
+ response matches with the buffer sent. If some error is detected
+ False value is returned and the associated MCL is closed.
+
+ uint16 OpenDataChannel(byte mdepid, byte config)
+
+ Creates a new data channel with the indicated config to the
+ remote MCAP Data End Point (MDEP).
+ The configuration should indicate the channel quality of
+ service. In the current version of HDP, valid values are 0x01
+ for reliable channels and 0x02 for streaming data channel.
+
+ Returns the data channel id.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.HealthError
+
+ array GetDataChannelFileDescriptor(uint16 mdlid)
+
+ Gets a file descriptor where data can be read or
+ written for receive or sent by the data channel.
+ Returns an array of file descriptors one for write
+ and other for read.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotFound
+ org.bluez.Error.HealthError
+
+ void DeleteDataChannel(uint16 mdlid)
+
+ Deletes a data channel so it will not be available for
+ use.
+
+ Possible errors: org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotFound
+ org.bluez.Error.HealthError
+
+ void DeleteAllDataChannels()
+
+ Deletes all data channels so it will not be available
+ for use. Typically this function is called when the
+ connection with the remote device will be closed
+ permanently
+
+ Possible errors: org.bluez.Error.HealthError
+
+ dict GetDataChannelStatus()
+
+ Return a dictionary with all the data channels that
+ can be used to send data right now. The dictionary
+ is formed like follows:
+ {
+ "reliable": [mdlid_r1, mdlid_r2, ...],
+ "streaming" : [mdlid_s1, mdlid_s2, ...]
+ }
+
+ The fist reliable data channel will always be the first
+ data channel in reliable array.
+
+HealthAgent hierarchy
+=====================
+
+(this object is implemented by the HDP user in order to receive notifications)
+
+Service unique name
+Interface org.bluez.HealthAgent
+Object path freely definable
+
+Methods:
+
+ void LinkConnected(object path)
+
+ This method is called whenever a new connection has been
+ established over the control channel of the current HDP
+ instance. The object path paremeter contains the object path of
+ the created HealthLink.
+
+ void LinkDisconnected(object path)
+
+ This method is called when a remote device is disconnected
+ definitively. Any future reconnections will fail. Also all data
+ channels associated to this device will be closed.
+
+ void CreatedDataChannel(object path, uint16 mdlid, byte conf)
+
+ This method is called when a new data channel is created
+
+ The path contains the object path of the HealthLink where the
+ new connection is created, the mdlid is the data channel
+ identificator and conf is the que quality of service of the data
+ channel (0x01 reliable, 0x02 streaming).
+
+ void DeletedDataChannel(object path, uint16 mdlid)
+
+ This method is called when a data channel is closed.
+
+ After this call the data channel id will not be valid and can be
+ reused for future created data channels.
--
1.6.3.3