#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;
};
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;
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)
{
DBG("Immediate Alert service added");
}
+#endif
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)
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);
#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;
};
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;
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)
{
return 0;
}
+#endif
/* condev can be NULL */
static void link_loss_remove_condev(struct connected_device *condev)
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)
{
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;
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,
if (!svc_added)
goto err;
-
+#endif
DBG("Link Loss service added");
return;
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);
#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"
return "unknown";
}
+#ifndef __TIZEN_PATCH__
static void register_tx_power(struct btd_adapter *adapter)
{
uint16_t start_handle, h;
g_assert(h - start_handle == svc_size);
}
+#endif
static gboolean property_get_link_loss_level(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *data)
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);
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);
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