From 5915a4398897b2c563c6d049f1b5a74890cec113 Mon Sep 17 00:00:00 2001 From: Gowtham Anandha Babu Date: Thu, 27 Oct 2016 17:50:38 +0530 Subject: [PATCH] [PXP Reporter]: Port proximity profiles to new GATT arch 1) Ported to new GATT architecure 2) Added RegisterProximty and UnregisterProximity DBus methods on org.bluez.ProximityReporter1 interface. 3) Since TxPower in not implemented in BlueZ, commented for now. Change-Id: I749de3345639dfeab05384df950ea6918376092a Signed-off-by: Gowtham Anandha Babu --- profiles/proximity/immalert.c | 166 +++++++++++++++++++++++++++++++++ profiles/proximity/linkloss.c | 209 +++++++++++++++++++++++++++++++++++++++++- profiles/proximity/reporter.c | 62 ++++++++++++- profiles/proximity/reporter.h | 2 +- 4 files changed, 436 insertions(+), 3 deletions(-) diff --git a/profiles/proximity/immalert.c b/profiles/proximity/immalert.c index 26a0ac9..3448625 100644 --- a/profiles/proximity/immalert.c +++ b/profiles/proximity/immalert.c @@ -49,11 +49,22 @@ #include "src/attio.h" #include "src/dbus-common.h" +#ifdef __TIZEN_PATCH__ +#include "src/shared/queue.h" +#include "src/shared/gatt-db.h" +#include "src/shared/att.h" + #include "btio/btio.h" +#include "src/gatt-database.h" +#endif + #include "reporter.h" #include "immalert.h" struct imm_alert_adapter { struct btd_adapter *adapter; +#ifdef __TIZEN_PATCH__ + struct gatt_db_attribute *imservice; +#endif GSList *connected_devices; }; @@ -66,6 +77,32 @@ struct connected_device { static GSList *imm_alert_adapters; +#ifdef __TIZEN_PATCH__ +static bool get_dest_info(struct bt_att *att, bdaddr_t *dst, uint8_t *dst_type) +{ + GIOChannel *io = NULL; + GError *gerr = NULL; + + io = g_io_channel_unix_new(bt_att_get_fd(att)); + if (!io) + return false; + + bt_io_get(io, &gerr, BT_IO_OPT_DEST_BDADDR, dst, + BT_IO_OPT_DEST_TYPE, dst_type, + BT_IO_OPT_INVALID); + + if (gerr) { + error("gatt: bt_io_get: %s", gerr->message); + g_error_free(gerr); + g_io_channel_unref(io); + return false; + } + + g_io_channel_unref(io); + return true; +} +#endif + static int imdevice_cmp(gconstpointer a, gconstpointer b) { const struct connected_device *condev = a; @@ -180,6 +217,124 @@ static void imm_alert_disc_cb(gpointer user_data) imm_alert_remove_condev(condev); } +#ifdef __TIZEN_PATCH__ +static void imm_alert_alert_lvl_write(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + const uint8_t *value, size_t len, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct imm_alert_adapter *ia = user_data; + struct connected_device *condev = NULL; + uint8_t ecode = 0; + bdaddr_t bdaddr; + uint8_t bdaddr_type; + struct btd_device *device = NULL; + + if (!value || len == 0) { + ecode = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN; + goto done; + } + + if (offset != 0) { + ecode = BT_ATT_ERROR_INVALID_OFFSET; + goto done; + } + + if (!get_dest_info(att, &bdaddr, &bdaddr_type)) { + ecode = BT_ATT_ERROR_UNLIKELY; + goto done; + } + + device = btd_adapter_get_device(ia->adapter, &bdaddr, bdaddr_type); + if (!device) { + ecode = BT_ATT_ERROR_UNLIKELY; + goto done; + } + + /* Write value should be anyone of 0x00, 0x01, 0x02 */ + if (value[0] > 0x02) { + ecode = 0x80; + goto done; + } + + /* condev might remain NULL here if nothing is found */ + condev = find_connected_device(ia, device); + + /* Register a disconnect cb if the alert level is non-zero */ + if (value[0] != NO_ALERT && !condev) { + condev = g_new0(struct connected_device, 1); + condev->device = btd_device_ref(device); + condev->adapter = ia; + condev->callback_id = btd_device_add_attio_callback(device, + NULL, imm_alert_disc_cb, condev); + ia->connected_devices = g_slist_append(ia->connected_devices, + condev); + DBG("added connected dev %p", device); + } + + if (condev) { + if (value[0] != NO_ALERT) { + condev->alert_level = value[0]; + imm_alert_emit_alert_signal(condev, value[0]); + } else { + imm_alert_emit_alert_signal(condev, value[0]); + imm_alert_disc_cb(condev); + } + } + + DBG("alert level set to %d by device %p", value[0], device); + gatt_db_attribute_write_result(attrib, id, ecode); + return; + +done: + error("Set immediate alert level for dev %p", device); + /* remove alerts by erroneous devices */ + imm_alert_disc_cb(condev); + gatt_db_attribute_write_result(attrib, id, ecode); +} + +void imm_alert_register(struct btd_adapter *adapter) +{ + bt_uuid_t uuid; + struct imm_alert_adapter *imadapter; + struct gatt_db_attribute *service, *charc; + struct gatt_db *db; + + imadapter = g_new0(struct imm_alert_adapter, 1); + imadapter->adapter = adapter; + + imm_alert_adapters = g_slist_append(imm_alert_adapters, imadapter); + db = (struct gatt_db *) btd_gatt_database_get_db(btd_adapter_get_database(adapter)); + + /* Immediate Alert Service */ + bt_uuid16_create(&uuid, IMMEDIATE_ALERT_SVC_UUID); + service = gatt_db_add_service(db, &uuid, true, 3); + if (!service) + goto err; + + imadapter->imservice = service; + + /* + * Alert Level characteristic. + */ + bt_uuid16_create(&uuid, ALERT_LEVEL_CHR_UUID); + charc = gatt_db_service_add_characteristic(service, &uuid, BT_ATT_PERM_WRITE, + BT_GATT_CHRC_PROP_WRITE, + NULL, + imm_alert_alert_lvl_write, imadapter); + if (!charc) + goto err; + + gatt_db_service_set_active(service, true); + + DBG("Immediate Alert service added"); + return; +err: + DBG("Error adding Immediate Alert service"); + imm_alert_unregister(adapter); +} +#else static uint8_t imm_alert_alert_lvl_write(struct attribute *a, struct btd_device *device, gpointer user_data) { @@ -268,6 +423,7 @@ void imm_alert_register(struct btd_adapter *adapter) DBG("Immediate Alert service added"); } +#endif static void remove_condev_list_item(gpointer data, gpointer user_data) { @@ -279,6 +435,9 @@ static void remove_condev_list_item(gpointer data, gpointer user_data) void imm_alert_unregister(struct btd_adapter *adapter) { struct imm_alert_adapter *imadapter; +#ifdef __TIZEN_PATCH__ + struct gatt_db *db; +#endif imadapter = find_imm_alert_adapter(adapter); if (!imadapter) @@ -286,6 +445,13 @@ void imm_alert_unregister(struct btd_adapter *adapter) g_slist_foreach(imadapter->connected_devices, remove_condev_list_item, NULL); +#ifdef __TIZEN_PATCH__ + /* Remove registered service */ + if (imadapter->imservice) { + db = (struct gatt_db *) btd_gatt_database_get_db(btd_adapter_get_database(adapter)); + gatt_db_remove_service(db, imadapter->imservice); + } +#endif imm_alert_adapters = g_slist_remove(imm_alert_adapters, imadapter); g_free(imadapter); diff --git a/profiles/proximity/linkloss.c b/profiles/proximity/linkloss.c index 2f1ab13..da22f3d 100644 --- a/profiles/proximity/linkloss.c +++ b/profiles/proximity/linkloss.c @@ -50,12 +50,24 @@ #include "src/attio.h" #include "src/dbus-common.h" +#ifdef __TIZEN_PATCH__ +#include "src/shared/queue.h" +#include "src/shared/gatt-db.h" +#include "src/shared/att.h" +#include "btio/btio.h" +#include "src/gatt-database.h" +#endif + #include "reporter.h" #include "linkloss.h" struct link_loss_adapter { struct btd_adapter *adapter; +#ifdef __TIZEN_PATCH__ + struct gatt_db_attribute *llservice; +#else uint16_t alert_lvl_value_handle; +#endif GSList *connected_devices; }; @@ -69,6 +81,32 @@ struct connected_device { static GSList *link_loss_adapters; +#ifdef __TIZEN_PATCH__ +static bool get_dest_info(struct bt_att *att, bdaddr_t *dst, uint8_t *dst_type) +{ + GIOChannel *io = NULL; + GError *gerr = NULL; + + io = g_io_channel_unix_new(bt_att_get_fd(att)); + if (!io) + return false; + + bt_io_get(io, &gerr, BT_IO_OPT_DEST_BDADDR, dst, + BT_IO_OPT_DEST_TYPE, dst_type, + BT_IO_OPT_INVALID); + + if (gerr) { + error("gatt: bt_io_get: %s", gerr->message); + g_error_free(gerr); + g_io_channel_unref(io); + return false; + } + + g_io_channel_unref(io); + return true; +} +#endif + static int lldevice_cmp(gconstpointer a, gconstpointer b) { const struct connected_device *llcondev = a; @@ -147,7 +185,54 @@ static void link_loss_emit_alert_signal(struct connected_device *condev) g_dbus_emit_property_changed(btd_get_dbus_connection(), path, PROXIMITY_REPORTER_INTERFACE, "LinkLossAlertLevel"); } +#ifdef __TIZEN_PATCH__ +static void link_loss_alert_lvl_read(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct link_loss_adapter *la = user_data; + struct connected_device *condev; + uint8_t value; + uint8_t ecode = 0; + bdaddr_t bdaddr; + uint8_t bdaddr_type; + struct btd_device *device; + + value = NO_ALERT; + + if (offset != 0) { + ecode = BT_ATT_ERROR_INVALID_OFFSET; + goto out; + } + + if (!get_dest_info(att, &bdaddr, &bdaddr_type)) { + ecode = BT_ATT_ERROR_UNLIKELY; + goto out; + } + + device = btd_adapter_get_device(la->adapter, &bdaddr, bdaddr_type); + if (!device) { + ecode = BT_ATT_ERROR_UNLIKELY; + goto out; + } + + condev = find_connected_device(la, device); + if (!condev) { + ecode = BT_ATT_ERROR_UNLIKELY; + goto out; + } + if (condev->alert_level) + value = condev->alert_level; + else + DBG("Alert Level is NULL"); + + DBG("Alert Level %d", value); +out: + gatt_db_attribute_read_result(attrib, id, ecode, &value, sizeof(value)); +} +#else static uint8_t link_loss_alert_lvl_read(struct attribute *a, struct btd_device *device, gpointer user_data) { @@ -173,6 +258,7 @@ out: return 0; } +#endif /* condev can be NULL */ static void link_loss_remove_condev(struct connected_device *condev) @@ -224,6 +310,85 @@ static void link_loss_local_disc(struct btd_device *device, DBG("alert level zeroed for locally disconnecting dev %p", device); } +#ifdef __TIZEN_PATCH__ +static void link_loss_alert_lvl_write(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + const uint8_t *value, size_t len, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct link_loss_adapter *la = user_data; + struct connected_device *condev = NULL; + uint8_t ecode = 0; + bdaddr_t bdaddr; + uint8_t bdaddr_type; + struct btd_device *device = NULL; + + if (!value || len == 0) { + ecode = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN; + goto done; + } + + if (offset != 0) { + ecode = BT_ATT_ERROR_INVALID_OFFSET; + goto done; + } + + if (!get_dest_info(att, &bdaddr, &bdaddr_type)) { + ecode = BT_ATT_ERROR_UNLIKELY; + goto done; + } + + device = btd_adapter_get_device(la->adapter, &bdaddr, bdaddr_type); + if (!device) { + ecode = BT_ATT_ERROR_UNLIKELY; + goto done; + } + + /* Write value should be anyone of 0x00, 0x01, 0x02 */ + if (value[0] > 0x02) { + ecode = 0x80; + goto done; + } + + /* condev might remain NULL here if nothing is found */ + condev = find_connected_device(la, device); + + /* Register a disconnect cb if the alert level is non-zero */ + if (value[0] != NO_ALERT && !condev) { + condev = g_new0(struct connected_device, 1); + condev->device = btd_device_ref(device); + condev->adapter = la; + condev->callback_id = btd_device_add_attio_callback(device, + NULL, link_loss_disc_cb, condev); + condev->local_disc_id = device_add_disconnect_watch(device, + link_loss_local_disc, condev, NULL); + + la->connected_devices = g_slist_append(la->connected_devices, + condev); + } + + if (condev) { + if (value[0] != NO_ALERT) { + condev->alert_level = value[0]; + link_loss_emit_alert_signal(condev); + } else { + link_loss_emit_alert_signal(condev); + link_loss_remove_condev(condev); + condev = NULL; + } + } + + DBG("alert level set to %d by device %p", value[0], device); + gatt_db_attribute_write_result(attrib, id, ecode); + return; +done: + DBG("Set link loss alert level for dev %p", device); + /* reset alert level on erroneous devices */ + link_loss_remove_condev(condev); + gatt_db_attribute_write_result(attrib, id, ecode); +} +#else static uint8_t link_loss_alert_lvl_write(struct attribute *a, struct btd_device *device, gpointer user_data) { @@ -278,10 +443,16 @@ set_error: link_loss_remove_condev(condev); return ATT_ECODE_IO; } +#endif void link_loss_register(struct btd_adapter *adapter) { +#ifdef __TIZEN_PATCH__ + struct gatt_db_attribute *service, *charc; + struct gatt_db *db; +#else gboolean svc_added; +#endif bt_uuid_t uuid; struct link_loss_adapter *lladapter; @@ -291,7 +462,32 @@ void link_loss_register(struct btd_adapter *adapter) lladapter->adapter = adapter; link_loss_adapters = g_slist_append(link_loss_adapters, lladapter); +#ifdef __TIZEN_PATCH__ + db = (struct gatt_db *) btd_gatt_database_get_db(btd_adapter_get_database(adapter)); + + /* + * Link Loss Service + */ + service = gatt_db_add_service(db, &uuid, true, 3); + if (!service) + goto err; + lladapter->llservice = service; + + /* + * Alert Level characteristic. + */ + bt_uuid16_create(&uuid, ALERT_LEVEL_CHR_UUID); + charc = gatt_db_service_add_characteristic(service, &uuid, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE, + BT_GATT_CHRC_PROP_READ | BT_GATT_CHRC_PROP_WRITE, + link_loss_alert_lvl_read, + link_loss_alert_lvl_write, lladapter); + + if (!charc) + goto err; + + gatt_db_service_set_active(service, true); +#else /* Link Loss Service */ svc_added = gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid, @@ -309,7 +505,7 @@ void link_loss_register(struct btd_adapter *adapter) if (!svc_added) goto err; - +#endif DBG("Link Loss service added"); return; @@ -328,12 +524,23 @@ static void remove_condev_list_item(gpointer data, gpointer user_data) void link_loss_unregister(struct btd_adapter *adapter) { struct link_loss_adapter *lladapter; +#ifdef __TIZEN_PATCH__ + struct gatt_db *db; +#endif + lladapter = find_link_loss_adapter(adapter); if (!lladapter) return; g_slist_foreach(lladapter->connected_devices, remove_condev_list_item, NULL); +#ifdef __TIZEN_PATCH__ + /* Remove registered service */ + if (lladapter->llservice) { + db = (struct gatt_db *) btd_gatt_database_get_db(btd_adapter_get_database(adapter)); + gatt_db_remove_service(db, lladapter->llservice); + } +#endif link_loss_adapters = g_slist_remove(link_loss_adapters, lladapter); g_free(lladapter); diff --git a/profiles/proximity/reporter.c b/profiles/proximity/reporter.c index 366d96b..3a88354 100644 --- a/profiles/proximity/reporter.c +++ b/profiles/proximity/reporter.c @@ -52,6 +52,10 @@ #include "attrib/att-database.h" #include "src/attrib-server.h" +#ifdef __TIZEN_PATCH__ +#include "src/error.h" +#endif + #include "reporter.h" #include "linkloss.h" #include "immalert.h" @@ -99,6 +103,7 @@ const char *get_alert_level_string(uint8_t level) return "unknown"; } +#ifndef __TIZEN_PATCH__ static void register_tx_power(struct btd_adapter *adapter) { uint16_t start_handle, h; @@ -142,6 +147,7 @@ static void register_tx_power(struct btd_adapter *adapter) g_assert(h - start_handle == svc_size); } +#endif static gboolean property_get_link_loss_level(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) @@ -222,6 +228,53 @@ int reporter_device_probe(struct btd_service *service) return 0; } +#ifdef __TIZEN_PATCH__ +static DBusMessage *register_proximity(DBusConnection *conn, DBusMessage *msg, + void *user_data) +{ + struct btd_adapter *adapter = user_data; + + if(adapter == NULL) { + DBG("Adapter is NULL"); + return btd_error_invalid_args(msg); + } + + link_loss_register(adapter); + imm_alert_register(adapter); + + /* TODO: TX Power service implementation + * is incomplete in BlueZ. + */ + //register_tx_power(adapter); + + return dbus_message_new_method_return(msg); +} + +static DBusMessage *unregister_proximity(DBusConnection *conn, DBusMessage *msg, + void *user_data) +{ + struct btd_adapter *adapter = user_data; + + if(adapter == NULL) { + DBG("Adapter is NULL"); + return btd_error_invalid_args(msg); + } + + link_loss_unregister(adapter); + imm_alert_unregister(adapter); + + return dbus_message_new_method_return(msg); +} + +static const GDBusMethodTable reporter_adapter_methods[] = { + { GDBUS_METHOD("RegisterProximity", NULL, NULL, + register_proximity) }, + { GDBUS_METHOD("UnregisterProximity", NULL, NULL, + unregister_proximity) }, + { } +}; +#endif + void reporter_device_remove(struct btd_service *service) { struct btd_device *device = btd_service_get_device(service); @@ -241,11 +294,18 @@ int reporter_adapter_probe(struct btd_profile *p, struct btd_adapter *adapter) radapter = g_new0(struct reporter_adapter, 1); radapter->adapter = adapter; +#ifdef __TIZEN_PATCH__ + const char *path = adapter_get_path(adapter); + g_dbus_register_interface(btd_get_dbus_connection(), path, + PROXIMITY_REPORTER_INTERFACE, + reporter_adapter_methods, + NULL, NULL, adapter, NULL); +#else link_loss_register(adapter); register_tx_power(adapter); imm_alert_register(adapter); - +#endif reporter_adapters = g_slist_prepend(reporter_adapters, radapter); DBG("Proximity Reporter for adapter %p", adapter); diff --git a/profiles/proximity/reporter.h b/profiles/proximity/reporter.h index a8e1aac..ed2c4dc 100644 --- a/profiles/proximity/reporter.h +++ b/profiles/proximity/reporter.h @@ -43,4 +43,4 @@ int reporter_adapter_probe(struct btd_profile *p, struct btd_adapter *adapter); void reporter_adapter_remove(struct btd_profile *p, struct btd_adapter *adapter); -const char *get_alert_level_string(uint8_t level); +const char *get_alert_level_string(uint8_t level); \ No newline at end of file -- 2.7.4