From afc66b8d68242e53aa9e2680d9bcf4c8a6f5c5ef Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 27 Sep 2016 15:26:41 +0300 Subject: [PATCH] build: Remove deprecated profiles This removes deprecated GATT profiles that are no longer supported and should instead be implemented over D-Bus. --- Makefile.plugins | 29 - profiles/alert/server.c | 1044 -------------------- profiles/cyclingspeed/cyclingspeed.c | 1266 ------------------------ profiles/heartrate/heartrate.c | 870 ----------------- profiles/thermometer/thermometer.c | 1321 -------------------------- profiles/time/server.c | 283 ------ 6 files changed, 4813 deletions(-) delete mode 100644 profiles/alert/server.c delete mode 100644 profiles/cyclingspeed/cyclingspeed.c delete mode 100644 profiles/heartrate/heartrate.c delete mode 100644 profiles/thermometer/thermometer.c delete mode 100644 profiles/time/server.c diff --git a/Makefile.plugins b/Makefile.plugins index 8a3605c8c..ecf6f08be 100644 --- a/Makefile.plugins +++ b/Makefile.plugins @@ -87,35 +87,6 @@ builtin_sources += profiles/scanparam/scan.c builtin_modules += deviceinfo builtin_sources += profiles/deviceinfo/deviceinfo.c -if DEPRECATED -builtin_modules += alert -builtin_sources += profiles/alert/server.c - -builtin_modules += time -builtin_sources += profiles/time/server.c - -builtin_modules += proximity -builtin_sources += profiles/proximity/main.c profiles/proximity/manager.h \ - profiles/proximity/manager.c \ - profiles/proximity/monitor.h \ - profiles/proximity/monitor.c \ - profiles/proximity/reporter.h \ - profiles/proximity/reporter.c \ - profiles/proximity/linkloss.h \ - profiles/proximity/linkloss.c \ - profiles/proximity/immalert.h \ - profiles/proximity/immalert.c - -builtin_modules += thermometer -builtin_sources += profiles/thermometer/thermometer.c - -builtin_modules += heartrate -builtin_sources += profiles/heartrate/heartrate.c - -builtin_modules += cyclingspeed -builtin_sources += profiles/cyclingspeed/cyclingspeed.c -endif - if SIXAXIS plugin_LTLIBRARIES += plugins/sixaxis.la plugins_sixaxis_la_SOURCES = plugins/sixaxis.c diff --git a/profiles/alert/server.c b/profiles/alert/server.c deleted file mode 100644 index 2f6e3cde1..000000000 --- a/profiles/alert/server.c +++ /dev/null @@ -1,1044 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2011 Nokia Corporation - * Copyright (C) 2011 Marcel Holtmann - * - * - * 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 -#endif - -#include -#include -#include -#include -#include -#include - -#include - -#include "lib/bluetooth.h" -#include "lib/hci.h" -#include "lib/hci_lib.h" -#include "lib/sdp.h" -#include "lib/uuid.h" - -#include "gdbus/gdbus.h" - -#include "src/plugin.h" -#include "src/dbus-common.h" -#include "attrib/att.h" -#include "src/adapter.h" -#include "src/device.h" -#include "attrib/att-database.h" -#include "src/log.h" -#include "attrib/gatt-service.h" -#include "attrib/gattrib.h" -#include "src/attrib-server.h" -#include "attrib/gatt.h" -#include "src/profile.h" -#include "src/error.h" -#include "src/textfile.h" -#include "src/attio.h" - -#define PHONE_ALERT_STATUS_SVC_UUID 0x180E -#define ALERT_NOTIF_SVC_UUID 0x1811 - -#define ALERT_STATUS_CHR_UUID 0x2A3F -#define RINGER_CP_CHR_UUID 0x2A40 -#define RINGER_SETTING_CHR_UUID 0x2A41 - -#define ALERT_NOTIF_CP_CHR_UUID 0x2A44 -#define UNREAD_ALERT_CHR_UUID 0x2A45 -#define NEW_ALERT_CHR_UUID 0x2A46 -#define SUPP_NEW_ALERT_CAT_CHR_UUID 0x2A47 -#define SUPP_UNREAD_ALERT_CAT_CHR_UUID 0x2A48 - -#define ALERT_OBJECT_PATH "/org/bluez" -#define ALERT_INTERFACE "org.bluez.Alert1" -#define ALERT_AGENT_INTERFACE "org.bluez.AlertAgent1" - -/* Maximum length for "Text String Information" */ -#define NEW_ALERT_MAX_INFO_SIZE 18 -/* Maximum length for New Alert Characteristic Value */ -#define NEW_ALERT_CHR_MAX_VALUE_SIZE (NEW_ALERT_MAX_INFO_SIZE + 2) - -enum { - ENABLE_NEW_INCOMING, - ENABLE_UNREAD_CAT, - DISABLE_NEW_INCOMING, - DISABLE_UNREAD_CAT, - NOTIFY_NEW_INCOMING, - NOTIFY_UNREAD_CAT, -}; - -enum { - RINGER_SILENT_MODE = 1, - RINGER_MUTE_ONCE, - RINGER_CANCEL_SILENT_MODE, -}; - -/* Ringer Setting characteristic values */ -enum { - RINGER_SILENT, - RINGER_NORMAL, -}; - -enum notify_type { - NOTIFY_RINGER_SETTING = 0, - NOTIFY_ALERT_STATUS, - NOTIFY_NEW_ALERT, - NOTIFY_UNREAD_ALERT, - NOTIFY_SIZE, -}; - -struct alert_data { - const char *category; - char *srv; - char *path; - guint watcher; -}; - -struct alert_adapter { - struct btd_adapter *adapter; - uint16_t supp_new_alert_cat_handle; - uint16_t supp_unread_alert_cat_handle; - uint16_t hnd_ccc[NOTIFY_SIZE]; - uint16_t hnd_value[NOTIFY_SIZE]; -}; - -struct notify_data { - struct alert_adapter *al_adapter; - enum notify_type type; - uint8_t *value; - size_t len; -}; - -struct notify_callback { - struct notify_data *notify_data; - struct btd_device *device; - guint id; -}; - -static GSList *registered_alerts = NULL; -static GSList *alert_adapters = NULL; -static uint8_t ringer_setting = RINGER_NORMAL; -static uint8_t alert_status = 0; - -static const char * const anp_categories[] = { - "simple", - "email", - "news", - "call", - "missed-call", - "sms-mms", - "voice-mail", - "schedule", - "high-priority", - "instant-message", -}; - -static const char * const pasp_categories[] = { - "ringer", - "vibrate", - "display", -}; - -static int adapter_cmp(gconstpointer a, gconstpointer b) -{ - const struct alert_adapter *al_adapter = a; - const struct btd_adapter *adapter = b; - - return al_adapter->adapter == adapter ? 0 : -1; -} - -static struct alert_adapter *find_alert_adapter(struct btd_adapter *adapter) -{ - GSList *l = g_slist_find_custom(alert_adapters, adapter, adapter_cmp); - - return l ? l->data : NULL; -} - -static void alert_data_destroy(gpointer user_data) -{ - struct alert_data *alert = user_data; - - if (alert->watcher) - g_dbus_remove_watch(btd_get_dbus_connection(), alert->watcher); - - g_free(alert->srv); - g_free(alert->path); - g_free(alert); -} - -static void alert_release(gpointer user_data) -{ - struct alert_data *alert = user_data; - DBusMessage *msg; - - msg = dbus_message_new_method_call(alert->srv, alert->path, - ALERT_AGENT_INTERFACE, - "Release"); - if (msg) - g_dbus_send_message(btd_get_dbus_connection(), msg); - - alert_data_destroy(alert); -} - -static void alert_destroy(gpointer user_data) -{ - DBG(""); - - g_slist_free_full(registered_alerts, alert_release); - registered_alerts = NULL; -} - -static const char *valid_category(const char *category) -{ - unsigned i; - - for (i = 0; i < G_N_ELEMENTS(anp_categories); i++) { - if (g_str_equal(anp_categories[i], category)) - return anp_categories[i]; - } - - for (i = 0; i < G_N_ELEMENTS(pasp_categories); i++) { - if (g_str_equal(pasp_categories[i], category)) - return pasp_categories[i]; - } - - return NULL; -} - -static struct alert_data *get_alert_data_by_category(const char *category) -{ - GSList *l; - struct alert_data *alert; - - for (l = registered_alerts; l; l = g_slist_next(l)) { - alert = l->data; - if (g_str_equal(alert->category, category)) - return alert; - } - - return NULL; -} - -static gboolean registered_category(const char *category) -{ - struct alert_data *alert; - - alert = get_alert_data_by_category(category); - if (alert) - return TRUE; - - return FALSE; -} - -static gboolean pasp_category(const char *category) -{ - unsigned i; - - for (i = 0; i < G_N_ELEMENTS(pasp_categories); i++) - if (g_str_equal(category, pasp_categories[i])) - return TRUE; - - return FALSE; -} - -static gboolean valid_description(const char *category, - const char *description) -{ - if (!pasp_category(category)) { - if (strlen(description) >= NEW_ALERT_MAX_INFO_SIZE) - return FALSE; - - return TRUE; - } - - if (g_str_equal(description, "active") || - g_str_equal(description, "not active")) - return TRUE; - - if (g_str_equal(category, "ringer")) - if (g_str_equal(description, "enabled") || - g_str_equal(description, "disabled")) - return TRUE; - - return FALSE; -} - -static gboolean valid_count(const char *category, uint16_t count) -{ - if (!pasp_category(category) && count > 0 && count <= 255) - return TRUE; - - if (pasp_category(category) && count == 1) - return TRUE; - - return FALSE; -} - -static void update_supported_categories(gpointer data, gpointer user_data) -{ - struct alert_adapter *al_adapter = data; - struct btd_adapter *adapter = al_adapter->adapter; - uint8_t value[2]; - unsigned int i; - - memset(value, 0, sizeof(value)); - - for (i = 0; i < G_N_ELEMENTS(anp_categories); i++) { - if (registered_category(anp_categories[i])) - hci_set_bit(i, value); - } - - attrib_db_update(adapter, al_adapter->supp_new_alert_cat_handle, NULL, - value, sizeof(value), NULL); - - /* FIXME: For now report all registered categories as supporting unread - * status, until it is known which ones should be supported */ - attrib_db_update(adapter, al_adapter->supp_unread_alert_cat_handle, - NULL, value, sizeof(value), NULL); -} - -static void watcher_disconnect(DBusConnection *conn, void *user_data) -{ - struct alert_data *alert = user_data; - - DBG("Category %s was disconnected", alert->category); - - registered_alerts = g_slist_remove(registered_alerts, alert); - alert_data_destroy(alert); - - g_slist_foreach(alert_adapters, update_supported_categories, NULL); -} - -static gboolean is_notifiable_device(struct btd_device *device, uint16_t ccc) -{ - char *filename; - GKeyFile *key_file; - char handle[6]; - char *str; - uint16_t val; - gboolean result; - - sprintf(handle, "%hu", ccc); - - filename = btd_device_get_storage_path(device, "ccc"); - if (!filename) { - warn("Unable to get ccc storage path for device"); - return FALSE; - } - - key_file = g_key_file_new(); - g_key_file_load_from_file(key_file, filename, 0, NULL); - - str = g_key_file_get_string(key_file, handle, "Value", NULL); - if (!str) { - result = FALSE; - goto end; - } - - val = strtol(str, NULL, 16); - if (!(val & 0x0001)) { - result = FALSE; - goto end; - } - - result = TRUE; -end: - g_free(str); - g_free(filename); - g_key_file_free(key_file); - - return result; -} - -static void destroy_notify_callback(guint8 status, const guint8 *pdu, guint16 len, - gpointer user_data) -{ - struct notify_callback *cb = user_data; - - DBG("status=%#x", status); - - btd_device_remove_attio_callback(cb->device, cb->id); - btd_device_unref(cb->device); - g_free(cb->notify_data->value); - g_free(cb->notify_data); - g_free(cb); -} - -static void attio_connected_cb(GAttrib *attrib, gpointer user_data) -{ - struct notify_callback *cb = user_data; - struct notify_data *nd = cb->notify_data; - enum notify_type type = nd->type; - struct alert_adapter *al_adapter = nd->al_adapter; - size_t len; - uint8_t *pdu = g_attrib_get_buffer(attrib, &len); - - - switch (type) { - case NOTIFY_RINGER_SETTING: - len = enc_notification(al_adapter->hnd_value[type], - &ringer_setting, sizeof(ringer_setting), - pdu, len); - break; - case NOTIFY_ALERT_STATUS: - len = enc_notification(al_adapter->hnd_value[type], - &alert_status, sizeof(alert_status), - pdu, len); - break; - case NOTIFY_NEW_ALERT: - case NOTIFY_UNREAD_ALERT: - len = enc_notification(al_adapter->hnd_value[type], - nd->value, nd->len, pdu, len); - break; - case NOTIFY_SIZE: - default: - DBG("Unknown type, could not send notification"); - goto end; - } - - DBG("Send notification for handle: 0x%04x, ccc: 0x%04x", - al_adapter->hnd_value[type], - al_adapter->hnd_ccc[type]); - - g_attrib_send(attrib, 0, pdu, len, destroy_notify_callback, cb, NULL); - - return; - -end: - btd_device_remove_attio_callback(cb->device, cb->id); - btd_device_unref(cb->device); - g_free(cb->notify_data->value); - g_free(cb->notify_data); - g_free(cb); -} - -static void filter_devices_notify(struct btd_device *device, void *user_data) -{ - struct notify_data *notify_data = user_data; - struct alert_adapter *al_adapter = notify_data->al_adapter; - enum notify_type type = notify_data->type; - struct notify_callback *cb; - - if (!is_notifiable_device(device, al_adapter->hnd_ccc[type])) - return; - - cb = g_new0(struct notify_callback, 1); - cb->notify_data = notify_data; - cb->device = btd_device_ref(device); - cb->id = btd_device_add_attio_callback(device, - attio_connected_cb, NULL, cb); -} - -static void notify_devices(struct alert_adapter *al_adapter, - enum notify_type type, uint8_t *value, size_t len) -{ - struct notify_data *notify_data; - - notify_data = g_new0(struct notify_data, 1); - notify_data->al_adapter = al_adapter; - notify_data->type = type; - notify_data->value = g_memdup(value, len); - notify_data->len = len; - - btd_adapter_for_each_device(al_adapter->adapter, filter_devices_notify, - notify_data); -} - -static void pasp_notification(enum notify_type type) -{ - GSList *it; - struct alert_adapter *al_adapter; - - for (it = alert_adapters; it; it = g_slist_next(it)) { - al_adapter = it->data; - - notify_devices(al_adapter, type, NULL, 0); - } -} - -static DBusMessage *register_alert(DBusConnection *conn, DBusMessage *msg, - void *data) -{ - const char *sender = dbus_message_get_sender(msg); - char *path; - const char *category; - const char *c; - struct alert_data *alert; - - if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &c, - DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) - return btd_error_invalid_args(msg); - - category = valid_category(c); - if (!category) { - DBG("Invalid category: %s", c); - return btd_error_invalid_args(msg); - } - - if (registered_category(category)) { - DBG("Category %s already registered", category); - return dbus_message_new_method_return(msg); - } - - alert = g_new0(struct alert_data, 1); - alert->srv = g_strdup(sender); - alert->path = g_strdup(path); - alert->category = category; - alert->watcher = g_dbus_add_disconnect_watch(conn, alert->srv, - watcher_disconnect, alert, NULL); - - if (alert->watcher == 0) { - alert_data_destroy(alert); - DBG("Could not register disconnect watcher"); - return btd_error_failed(msg, - "Could not register disconnect watcher"); - } - - registered_alerts = g_slist_append(registered_alerts, alert); - - g_slist_foreach(alert_adapters, update_supported_categories, NULL); - - DBG("RegisterAlert(\"%s\", \"%s\")", alert->category, alert->path); - - return dbus_message_new_method_return(msg); -} - -static void update_new_alert(gpointer data, gpointer user_data) -{ - struct alert_adapter *al_adapter = data; - struct btd_adapter *adapter = al_adapter->adapter; - uint8_t *value = user_data; - - attrib_db_update(adapter, al_adapter->hnd_value[NOTIFY_NEW_ALERT], NULL, - &value[1], value[0], NULL); - - notify_devices(al_adapter, NOTIFY_NEW_ALERT, &value[1], value[0]); -} - -static void update_phone_alerts(const char *category, const char *description) -{ - unsigned int i; - - if (g_str_equal(category, "ringer")) { - if (g_str_equal(description, "enabled")) { - ringer_setting = RINGER_NORMAL; - pasp_notification(NOTIFY_RINGER_SETTING); - return; - } else if (g_str_equal(description, "disabled")) { - ringer_setting = RINGER_SILENT; - pasp_notification(NOTIFY_RINGER_SETTING); - return; - } - } - - for (i = 0; i < G_N_ELEMENTS(pasp_categories); i++) { - if (g_str_equal(pasp_categories[i], category)) { - if (g_str_equal(description, "active")) { - alert_status |= (1 << i); - pasp_notification(NOTIFY_ALERT_STATUS); - } else if (g_str_equal(description, "not active")) { - alert_status &= ~(1 << i); - pasp_notification(NOTIFY_ALERT_STATUS); - } - break; - } - } -} - -static DBusMessage *new_alert(DBusConnection *conn, DBusMessage *msg, - void *data) -{ - const char *sender = dbus_message_get_sender(msg); - const char *category, *description; - struct alert_data *alert; - uint16_t count; - unsigned int i; - size_t dlen; - - if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &category, - DBUS_TYPE_UINT16, &count, DBUS_TYPE_STRING, - &description, DBUS_TYPE_INVALID)) - return btd_error_invalid_args(msg); - - alert = get_alert_data_by_category(category); - if (!alert) { - DBG("Category %s not registered", category); - return btd_error_invalid_args(msg); - } - - if (!g_str_equal(alert->srv, sender)) { - DBG("Sender %s is not registered in category %s", sender, - category); - return btd_error_invalid_args(msg); - } - - if (!valid_description(category, description)) { - DBG("Description %s is invalid for %s category", - description, category); - return btd_error_invalid_args(msg); - } - - if (!valid_count(category, count)) { - DBG("Count %d is invalid for %s category", count, category); - return btd_error_invalid_args(msg); - } - - dlen = strlen(description); - - for (i = 0; i < G_N_ELEMENTS(anp_categories); i++) { - uint8_t value[NEW_ALERT_CHR_MAX_VALUE_SIZE + 1]; - uint8_t *ptr = value; - - if (!g_str_equal(anp_categories[i], category)) - continue; - - memset(value, 0, sizeof(value)); - - *ptr++ = 2; /* Attribute value size */ - *ptr++ = i; /* Category ID (mandatory) */ - *ptr++ = count; /* Number of New Alert (mandatory) */ - /* Text String Information (optional) */ - strncpy((char *) ptr, description, - NEW_ALERT_MAX_INFO_SIZE - 1); - - if (dlen > 0) - *value += dlen + 1; - - g_slist_foreach(alert_adapters, update_new_alert, value); - } - - if (pasp_category(category)) - update_phone_alerts(category, description); - - DBG("NewAlert(\"%s\", %d, \"%s\")", category, count, description); - - return dbus_message_new_method_return(msg); -} - -static int agent_ringer_mute_once(void) -{ - struct alert_data *alert; - DBusMessage *msg; - - alert = get_alert_data_by_category("ringer"); - if (!alert) { - DBG("Category ringer is not registered"); - return -EINVAL; - } - - msg = dbus_message_new_method_call(alert->srv, alert->path, - ALERT_AGENT_INTERFACE, "MuteOnce"); - if (!msg) - return -ENOMEM; - - dbus_message_set_no_reply(msg, TRUE); - g_dbus_send_message(btd_get_dbus_connection(), msg); - - return 0; -} - -static int agent_ringer_set_ringer(const char *mode) -{ - struct alert_data *alert; - DBusMessage *msg; - - alert = get_alert_data_by_category("ringer"); - if (!alert) { - DBG("Category ringer is not registered"); - return -EINVAL; - } - - msg = dbus_message_new_method_call(alert->srv, alert->path, - ALERT_AGENT_INTERFACE, "SetRinger"); - if (!msg) - return -ENOMEM; - - dbus_message_append_args(msg, DBUS_TYPE_STRING, &mode, - DBUS_TYPE_INVALID); - - dbus_message_set_no_reply(msg, TRUE); - g_dbus_send_message(btd_get_dbus_connection(), msg); - - return 0; -} - -static void update_unread_alert(gpointer data, gpointer user_data) -{ - struct alert_adapter *al_adapter = data; - struct btd_adapter *adapter = al_adapter->adapter; - uint8_t *value = user_data; - - attrib_db_update(adapter, - al_adapter->hnd_value[NOTIFY_UNREAD_ALERT], NULL, value, - 2, NULL); - - notify_devices(al_adapter, NOTIFY_UNREAD_ALERT, value, 2); -} - -static DBusMessage *unread_alert(DBusConnection *conn, DBusMessage *msg, - void *data) -{ - const char *sender = dbus_message_get_sender(msg); - struct alert_data *alert; - const char *category; - unsigned int i; - uint16_t count; - - if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &category, - DBUS_TYPE_UINT16, &count, - DBUS_TYPE_INVALID)) - return btd_error_invalid_args(msg); - - alert = get_alert_data_by_category(category); - if (!alert) { - DBG("Category %s not registered", category); - return btd_error_invalid_args(msg); - } - - if (!valid_count(category, count)) { - DBG("Count %d is invalid for %s category", count, category); - return btd_error_invalid_args(msg); - } - - if (!g_str_equal(alert->srv, sender)) { - DBG("Sender %s is not registered in category %s", sender, - category); - return btd_error_invalid_args(msg); - } - - for (i = 0; i < G_N_ELEMENTS(anp_categories); i++) { - if (g_str_equal(anp_categories[i], category)) { - uint8_t value[2]; - - value[0] = i; /* Category ID */ - value[1] = count; /* Unread count */ - - g_slist_foreach(alert_adapters, update_unread_alert, - value); - } - } - - DBG("category %s, count %d", category, count); - - return dbus_message_new_method_return(msg); -} - -static uint8_t ringer_cp_write(struct attribute *a, - struct btd_device *device, - gpointer user_data) -{ - DBG("a = %p", a); - - if (a->len > 1) { - DBG("Invalid command size (%zu)", a->len); - return 0; - } - - switch (a->data[0]) { - case RINGER_SILENT_MODE: - DBG("Silent Mode"); - agent_ringer_set_ringer("disabled"); - break; - case RINGER_MUTE_ONCE: - DBG("Mute Once"); - agent_ringer_mute_once(); - break; - case RINGER_CANCEL_SILENT_MODE: - DBG("Cancel Silent Mode"); - agent_ringer_set_ringer("enabled"); - break; - default: - DBG("Invalid command (0x%02x)", a->data[0]); - } - - return 0; -} - -static uint8_t alert_status_read(struct attribute *a, - struct btd_device *device, - gpointer user_data) -{ - struct btd_adapter *adapter = user_data; - - DBG("a = %p", a); - - if (a->data == NULL || a->data[0] != alert_status) - attrib_db_update(adapter, a->handle, NULL, &alert_status, - sizeof(alert_status), NULL); - - return 0; -} - -static uint8_t ringer_setting_read(struct attribute *a, - struct btd_device *device, - gpointer user_data) -{ - struct btd_adapter *adapter = user_data; - - DBG("a = %p", a); - - if (a->data == NULL || a->data[0] != ringer_setting) - attrib_db_update(adapter, a->handle, NULL, &ringer_setting, - sizeof(ringer_setting), NULL); - - return 0; -} - -static void register_phone_alert_service(struct alert_adapter *al_adapter) -{ - bt_uuid_t uuid; - - bt_uuid16_create(&uuid, PHONE_ALERT_STATUS_SVC_UUID); - - /* Phone Alert Status Service */ - gatt_service_add(al_adapter->adapter, GATT_PRIM_SVC_UUID, &uuid, - /* Alert Status characteristic */ - GATT_OPT_CHR_UUID16, ALERT_STATUS_CHR_UUID, - GATT_OPT_CHR_PROPS, GATT_CHR_PROP_READ | - GATT_CHR_PROP_NOTIFY, - GATT_OPT_CHR_VALUE_CB, ATTRIB_READ, - alert_status_read, al_adapter->adapter, - GATT_OPT_CCC_GET_HANDLE, - &al_adapter->hnd_ccc[NOTIFY_ALERT_STATUS], - GATT_OPT_CHR_VALUE_GET_HANDLE, - &al_adapter->hnd_value[NOTIFY_ALERT_STATUS], - /* Ringer Control Point characteristic */ - GATT_OPT_CHR_UUID16, RINGER_CP_CHR_UUID, - GATT_OPT_CHR_PROPS, GATT_CHR_PROP_WRITE_WITHOUT_RESP, - GATT_OPT_CHR_VALUE_CB, ATTRIB_WRITE, - ringer_cp_write, NULL, - /* Ringer Setting characteristic */ - GATT_OPT_CHR_UUID16, RINGER_SETTING_CHR_UUID, - GATT_OPT_CHR_PROPS, GATT_CHR_PROP_READ | - GATT_CHR_PROP_NOTIFY, - GATT_OPT_CHR_VALUE_CB, ATTRIB_READ, - ringer_setting_read, al_adapter->adapter, - GATT_OPT_CCC_GET_HANDLE, - &al_adapter->hnd_ccc[NOTIFY_RINGER_SETTING], - GATT_OPT_CHR_VALUE_GET_HANDLE, - &al_adapter->hnd_value[NOTIFY_RINGER_SETTING], - GATT_OPT_INVALID); -} - -static uint8_t supp_new_alert_cat_read(struct attribute *a, - struct btd_device *device, - gpointer user_data) -{ - struct btd_adapter *adapter = user_data; - uint8_t value[] = { 0x00, 0x00 }; - - DBG("a = %p", a); - - if (a->data == NULL) - attrib_db_update(adapter, a->handle, NULL, value, sizeof(value), - NULL); - - return 0; -} - -static uint8_t supp_unread_alert_cat_read(struct attribute *a, - struct btd_device *device, - gpointer user_data) -{ - struct btd_adapter *adapter = user_data; - uint8_t value[] = { 0x00, 0x00 }; - - DBG("a = %p", a); - - if (a->data == NULL) - attrib_db_update(adapter, a->handle, NULL, value, sizeof(value), - NULL); - - return 0; -} - -static uint8_t alert_notif_cp_write(struct attribute *a, - struct btd_device *device, - gpointer user_data) -{ - DBG("a = %p", a); - - if (a->len < 2) - return 0; - - switch (a->data[0]) { - case ENABLE_NEW_INCOMING: - DBG("ENABLE_NEW_INCOMING: 0x%02x", a->data[1]); - break; - case ENABLE_UNREAD_CAT: - DBG("ENABLE_UNREAD_CAT: 0x%02x", a->data[1]); - break; - case DISABLE_NEW_INCOMING: - DBG("DISABLE_NEW_INCOMING: 0x%02x", a->data[1]); - break; - case DISABLE_UNREAD_CAT: - DBG("DISABLE_UNREAD_CAT: 0x%02x", a->data[1]); - break; - case NOTIFY_NEW_INCOMING: - DBG("NOTIFY_NEW_INCOMING: 0x%02x", a->data[1]); - break; - case NOTIFY_UNREAD_CAT: - DBG("NOTIFY_UNREAD_CAT: 0x%02x", a->data[1]); - break; - default: - DBG("0x%02x 0x%02x", a->data[0], a->data[1]); - } - - return 0; -} - -static void register_alert_notif_service(struct alert_adapter *al_adapter) -{ - bt_uuid_t uuid; - - bt_uuid16_create(&uuid, ALERT_NOTIF_SVC_UUID); - - /* Alert Notification Service */ - gatt_service_add(al_adapter->adapter, GATT_PRIM_SVC_UUID, &uuid, - /* Supported New Alert Category */ - GATT_OPT_CHR_UUID16, SUPP_NEW_ALERT_CAT_CHR_UUID, - GATT_OPT_CHR_PROPS, GATT_CHR_PROP_READ, - GATT_OPT_CHR_VALUE_CB, ATTRIB_READ, - supp_new_alert_cat_read, al_adapter->adapter, - GATT_OPT_CHR_VALUE_GET_HANDLE, - &al_adapter->supp_new_alert_cat_handle, - /* New Alert */ - GATT_OPT_CHR_UUID16, NEW_ALERT_CHR_UUID, - GATT_OPT_CHR_PROPS, GATT_CHR_PROP_NOTIFY, - GATT_OPT_CCC_GET_HANDLE, - &al_adapter->hnd_ccc[NOTIFY_NEW_ALERT], - GATT_OPT_CHR_VALUE_GET_HANDLE, - &al_adapter->hnd_value[NOTIFY_NEW_ALERT], - /* Supported Unread Alert Category */ - GATT_OPT_CHR_UUID16, SUPP_UNREAD_ALERT_CAT_CHR_UUID, - GATT_OPT_CHR_PROPS, GATT_CHR_PROP_READ, - GATT_OPT_CHR_VALUE_CB, ATTRIB_READ, - supp_unread_alert_cat_read, al_adapter->adapter, - GATT_OPT_CHR_VALUE_GET_HANDLE, - &al_adapter->supp_unread_alert_cat_handle, - /* Unread Alert Status */ - GATT_OPT_CHR_UUID16, UNREAD_ALERT_CHR_UUID, - GATT_OPT_CHR_PROPS, GATT_CHR_PROP_NOTIFY, - GATT_OPT_CCC_GET_HANDLE, - &al_adapter->hnd_ccc[NOTIFY_UNREAD_ALERT], - GATT_OPT_CHR_VALUE_GET_HANDLE, - &al_adapter->hnd_value[NOTIFY_UNREAD_ALERT], - /* Alert Notification Control Point */ - GATT_OPT_CHR_UUID16, ALERT_NOTIF_CP_CHR_UUID, - GATT_OPT_CHR_PROPS, GATT_CHR_PROP_WRITE, - GATT_OPT_CHR_VALUE_CB, ATTRIB_WRITE, - alert_notif_cp_write, NULL, - GATT_OPT_INVALID); -} - -static int alert_server_probe(struct btd_profile *p, - struct btd_adapter *adapter) -{ - struct alert_adapter *al_adapter; - - al_adapter = g_new0(struct alert_adapter, 1); - al_adapter->adapter = btd_adapter_ref(adapter); - - alert_adapters = g_slist_append(alert_adapters, al_adapter); - - register_phone_alert_service(al_adapter); - register_alert_notif_service(al_adapter); - - return 0; -} - -static void alert_server_remove(struct btd_profile *p, - struct btd_adapter *adapter) -{ - struct alert_adapter *al_adapter; - - al_adapter = find_alert_adapter(adapter); - if (!al_adapter) - return; - - alert_adapters = g_slist_remove(alert_adapters, al_adapter); - btd_adapter_unref(al_adapter->adapter); - - g_free(al_adapter); -} - -static struct btd_profile alert_profile = { - .name = "gatt-alert-server", - .adapter_probe = alert_server_probe, - .adapter_remove = alert_server_remove, -}; - -static const GDBusMethodTable alert_methods[] = { - { GDBUS_METHOD("RegisterAlert", - GDBUS_ARGS({ "category", "s" }, - { "agent", "o" }), NULL, - register_alert) }, - { GDBUS_METHOD("NewAlert", - GDBUS_ARGS({ "category", "s" }, - { "count", "q" }, - { "description", "s" }), NULL, - new_alert) }, - { GDBUS_METHOD("UnreadAlert", - GDBUS_ARGS({ "category", "s" }, { "count", "q" }), NULL, - unread_alert) }, - { } -}; - -static int alert_server_init(void) -{ - if (!g_dbus_register_interface(btd_get_dbus_connection(), - ALERT_OBJECT_PATH, ALERT_INTERFACE, - alert_methods, NULL, NULL, NULL, - alert_destroy)) { - error("D-Bus failed to register %s interface", - ALERT_INTERFACE); - return -EIO; - } - - return btd_profile_register(&alert_profile); -} - -static void alert_server_exit(void) -{ - btd_profile_unregister(&alert_profile); - - g_dbus_unregister_interface(btd_get_dbus_connection(), - ALERT_OBJECT_PATH, ALERT_INTERFACE); -} - -static int alert_init(void) -{ - return alert_server_init(); -} - -static void alert_exit(void) -{ - alert_server_exit(); -} - -BLUETOOTH_PLUGIN_DEFINE(alert, VERSION, - BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, - alert_init, alert_exit) diff --git a/profiles/cyclingspeed/cyclingspeed.c b/profiles/cyclingspeed/cyclingspeed.c deleted file mode 100644 index e44772560..000000000 --- a/profiles/cyclingspeed/cyclingspeed.c +++ /dev/null @@ -1,1266 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2012 Tieto Poland - * - * 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 -#endif - -#include -#include - -#include - -#include "lib/bluetooth.h" -#include "lib/sdp.h" -#include "lib/uuid.h" - -#include "gdbus/gdbus.h" - -#include "src/plugin.h" -#include "src/adapter.h" -#include "src/device.h" -#include "src/profile.h" -#include "src/service.h" -#include "src/dbus-common.h" -#include "src/shared/util.h" -#include "src/error.h" -#include "attrib/gattrib.h" -#include "attrib/att.h" -#include "attrib/gatt.h" -#include "src/attio.h" -#include "src/log.h" - -/* min length for ATT indication or notification: opcode (1b) + handle (2b) */ -#define ATT_HDR_LEN 3 - -#define ATT_TIMEOUT 30 - -#define CYCLINGSPEED_INTERFACE "org.bluez.CyclingSpeed1" -#define CYCLINGSPEED_MANAGER_INTERFACE "org.bluez.CyclingSpeedManager1" -#define CYCLINGSPEED_WATCHER_INTERFACE "org.bluez.CyclingSpeedWatcher1" - -#define WHEEL_REV_SUPPORT 0x01 -#define CRANK_REV_SUPPORT 0x02 -#define MULTI_SENSOR_LOC_SUPPORT 0x04 - -#define WHEEL_REV_PRESENT 0x01 -#define CRANK_REV_PRESENT 0x02 - -#define SET_CUMULATIVE_VALUE 0x01 -#define START_SENSOR_CALIBRATION 0x02 -#define UPDATE_SENSOR_LOC 0x03 -#define REQUEST_SUPPORTED_SENSOR_LOC 0x04 -#define RESPONSE_CODE 0x10 - -#define RSP_SUCCESS 0x01 -#define RSP_NOT_SUPPORTED 0x02 -#define RSP_INVALID_PARAM 0x03 -#define RSP_FAILED 0x04 - -struct csc; - -struct controlpoint_req { - struct csc *csc; - uint8_t opcode; - guint timeout; - GDBusPendingReply reply_id; - DBusMessage *msg; - - uint8_t pending_location; -}; - -struct csc_adapter { - struct btd_adapter *adapter; - GSList *devices; /* list of registered devices */ - GSList *watchers; -}; - -struct csc { - struct btd_device *dev; - struct csc_adapter *cadapter; - - GAttrib *attrib; - guint attioid; - /* attio id for measurement characteristics value notifications */ - guint attio_measurement_id; - /* attio id for SC Control Point characteristics value indications */ - guint attio_controlpoint_id; - - struct att_range *svc_range; - - uint16_t measurement_ccc_handle; - uint16_t controlpoint_val_handle; - - uint16_t feature; - gboolean has_location; - uint8_t location; - uint8_t num_locations; - uint8_t *locations; - - struct controlpoint_req *pending_req; -}; - -struct watcher { - struct csc_adapter *cadapter; - guint id; - char *srv; - char *path; -}; - -struct measurement { - struct csc *csc; - - bool has_wheel_rev; - uint32_t wheel_rev; - uint16_t last_wheel_time; - - bool has_crank_rev; - uint16_t crank_rev; - uint16_t last_crank_time; -}; - -struct characteristic { - struct csc *csc; - char uuid[MAX_LEN_UUID_STR + 1]; -}; - -static GSList *csc_adapters = NULL; - -static const char * const location_enum[] = { - "other", "top-of-shoe", "in-shoe", "hip", "front-wheel", "left-crank", - "right-crank", "left-pedal", "right-pedal", "front-hub", - "rear-dropout", "chainstay", "rear-wheel", "rear-hub" -}; - -static const char *location2str(uint8_t value) -{ - if (value < G_N_ELEMENTS(location_enum)) - return location_enum[value]; - - info("Body Sensor Location [%d] is RFU", value); - - return location_enum[0]; -} - -static int str2location(const char *location) -{ - size_t i; - - for (i = 0; i < G_N_ELEMENTS(location_enum); i++) - if (!strcmp(location_enum[i], location)) - return i; - - return -1; -} - -static int cmp_adapter(gconstpointer a, gconstpointer b) -{ - const struct csc_adapter *cadapter = a; - const struct btd_adapter *adapter = b; - - if (adapter == cadapter->adapter) - return 0; - - return -1; -} - -static int cmp_device(gconstpointer a, gconstpointer b) -{ - const struct csc *csc = a; - const struct btd_device *dev = b; - - if (dev == csc->dev) - return 0; - - return -1; -} - -static int cmp_watcher(gconstpointer a, gconstpointer b) -{ - const struct watcher *watcher = a; - const struct watcher *match = b; - int ret; - - ret = g_strcmp0(watcher->srv, match->srv); - if (ret != 0) - return ret; - - return g_strcmp0(watcher->path, match->path); -} - -static struct csc_adapter *find_csc_adapter(struct btd_adapter *adapter) -{ - GSList *l = g_slist_find_custom(csc_adapters, adapter, cmp_adapter); - - if (!l) - return NULL; - - return l->data; -} - -static void destroy_watcher(gpointer user_data) -{ - struct watcher *watcher = user_data; - - g_free(watcher->path); - g_free(watcher->srv); - g_free(watcher); -} - -static struct watcher *find_watcher(GSList *list, const char *sender, - const char *path) -{ - struct watcher *match; - GSList *l; - - match = g_new0(struct watcher, 1); - match->srv = g_strdup(sender); - match->path = g_strdup(path); - - l = g_slist_find_custom(list, match, cmp_watcher); - destroy_watcher(match); - - if (l != NULL) - return l->data; - - return NULL; -} - -static void remove_watcher(gpointer user_data) -{ - struct watcher *watcher = user_data; - - g_dbus_remove_watch(btd_get_dbus_connection(), watcher->id); -} - -static void destroy_csc_adapter(gpointer user_data) -{ - struct csc_adapter *cadapter = user_data; - - g_slist_free_full(cadapter->watchers, remove_watcher); - - g_free(cadapter); -} - -static void destroy_csc(gpointer user_data) -{ - struct csc *csc = user_data; - - if (csc->attioid > 0) - btd_device_remove_attio_callback(csc->dev, csc->attioid); - - if (csc->attrib != NULL) { - g_attrib_unregister(csc->attrib, csc->attio_measurement_id); - g_attrib_unregister(csc->attrib, csc->attio_controlpoint_id); - g_attrib_unref(csc->attrib); - } - - btd_device_unref(csc->dev); - g_free(csc->svc_range); - g_free(csc->locations); - g_free(csc); -} - -static void char_write_cb(guint8 status, const guint8 *pdu, guint16 len, - gpointer user_data) -{ - char *msg = user_data; - - if (status != 0) - error("%s failed", msg); - - g_free(msg); -} - -static gboolean controlpoint_timeout(gpointer user_data) -{ - struct controlpoint_req *req = user_data; - - if (req->opcode == UPDATE_SENSOR_LOC) { - g_dbus_pending_property_error(req->reply_id, - ERROR_INTERFACE ".Failed", - "Operation failed (timeout)"); - } else if (req->opcode == SET_CUMULATIVE_VALUE) { - DBusMessage *reply; - - reply = btd_error_failed(req->msg, - "Operation failed (timeout)"); - - g_dbus_send_message(btd_get_dbus_connection(), reply); - - dbus_message_unref(req->msg); - } - - req->csc->pending_req = NULL; - g_free(req); - - return FALSE; -} - -static void controlpoint_write_cb(guint8 status, const guint8 *pdu, guint16 len, - gpointer user_data) -{ - struct controlpoint_req *req = user_data; - - if (status == 0) { - req->timeout = g_timeout_add_seconds(ATT_TIMEOUT, - controlpoint_timeout, - req); - return; - } - - error("SC Control Point write failed (opcode=%d)", req->opcode); - - if (req->opcode == UPDATE_SENSOR_LOC) { - g_dbus_pending_property_error(req->reply_id, - ERROR_INTERFACE ".Failed", - "Operation failed (%d)", status); - } else if (req->opcode == SET_CUMULATIVE_VALUE) { - DBusMessage *reply; - - reply = btd_error_failed(req->msg, "Operation failed"); - - g_dbus_send_message(btd_get_dbus_connection(), reply); - - dbus_message_unref(req->msg); - } - - req->csc->pending_req = NULL; - g_free(req); -} - -static void read_supported_locations(struct csc *csc) -{ - struct controlpoint_req *req; - - req = g_new0(struct controlpoint_req, 1); - req->csc = csc; - req->opcode = REQUEST_SUPPORTED_SENSOR_LOC; - - csc->pending_req = req; - - gatt_write_char(csc->attrib, csc->controlpoint_val_handle, - &req->opcode, sizeof(req->opcode), - controlpoint_write_cb, req); -} - -static void read_feature_cb(guint8 status, const guint8 *pdu, guint16 len, - gpointer user_data) -{ - struct csc *csc = user_data; - uint8_t value[2]; - ssize_t vlen; - - if (status) { - error("CSC Feature read failed: %s", att_ecode2str(status)); - return; - } - - vlen = dec_read_resp(pdu, len, value, sizeof(value)); - if (vlen < 0) { - error("Protocol error"); - return; - } - - if (vlen != sizeof(value)) { - error("Invalid value length for CSC Feature"); - return; - } - - csc->feature = get_le16(value); - - if ((csc->feature & MULTI_SENSOR_LOC_SUPPORT) - && (csc->locations == NULL)) - read_supported_locations(csc); -} - -static void read_location_cb(guint8 status, const guint8 *pdu, - guint16 len, gpointer user_data) -{ - struct csc *csc = user_data; - uint8_t value; - ssize_t vlen; - - if (status) { - error("Sensor Location read failed: %s", att_ecode2str(status)); - return; - } - - vlen = dec_read_resp(pdu, len, &value, sizeof(value)); - if (vlen < 0) { - error("Protocol error"); - return; - } - - if (vlen != sizeof(value)) { - error("Invalid value length for Sensor Location"); - return; - } - - csc->has_location = TRUE; - csc->location = value; - - g_dbus_emit_property_changed(btd_get_dbus_connection(), - device_get_path(csc->dev), - CYCLINGSPEED_INTERFACE, "Location"); -} - -static void discover_desc_cb(guint8 status, GSList *descs, gpointer user_data) -{ - struct characteristic *ch = user_data; - struct gatt_desc *desc; - uint8_t attr_val[2]; - char *msg = NULL; - - if (status != 0) { - error("Discover %s descriptors failed: %s", ch->uuid, - att_ecode2str(status)); - goto done; - } - - /* There will be only one descriptor on list and it will be CCC */ - desc = descs->data; - - if (g_strcmp0(ch->uuid, CSC_MEASUREMENT_UUID) == 0) { - ch->csc->measurement_ccc_handle = desc->handle; - - if (g_slist_length(ch->csc->cadapter->watchers) == 0) { - put_le16(0x0000, attr_val); - msg = g_strdup("Disable measurement"); - } else { - put_le16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, - attr_val); - msg = g_strdup("Enable measurement"); - } - } else if (g_strcmp0(ch->uuid, SC_CONTROL_POINT_UUID) == 0) { - put_le16(GATT_CLIENT_CHARAC_CFG_IND_BIT, attr_val); - msg = g_strdup("Enable SC Control Point indications"); - } else { - goto done; - } - - gatt_write_char(ch->csc->attrib, desc->handle, attr_val, - sizeof(attr_val), char_write_cb, msg); - -done: - g_free(ch); -} - -static void discover_desc(struct csc *csc, struct gatt_char *c, - struct gatt_char *c_next) -{ - struct characteristic *ch; - uint16_t start, end; - bt_uuid_t uuid; - - start = c->value_handle + 1; - - if (c_next != NULL) { - if (start == c_next->handle) - return; - end = c_next->handle - 1; - } else if (c->value_handle != csc->svc_range->end) { - end = csc->svc_range->end; - } else { - return; - } - - ch = g_new0(struct characteristic, 1); - ch->csc = csc; - memcpy(ch->uuid, c->uuid, sizeof(c->uuid)); - - bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID); - - gatt_discover_desc(csc->attrib, start, end, &uuid, discover_desc_cb, - ch); -} - -static void update_watcher(gpointer data, gpointer user_data) -{ - struct watcher *w = data; - struct measurement *m = user_data; - struct csc *csc = m->csc; - const char *path = device_get_path(csc->dev); - DBusMessageIter iter; - DBusMessageIter dict; - DBusMessage *msg; - - msg = dbus_message_new_method_call(w->srv, w->path, - CYCLINGSPEED_WATCHER_INTERFACE, "MeasurementReceived"); - if (msg == NULL) - return; - - dbus_message_iter_init_append(msg, &iter); - - dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH , &path); - - 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); - - if (m->has_wheel_rev) { - dict_append_entry(&dict, "WheelRevolutions", - DBUS_TYPE_UINT32, &m->wheel_rev); - dict_append_entry(&dict, "LastWheelEventTime", - DBUS_TYPE_UINT16, &m->last_wheel_time); - } - - if (m->has_crank_rev) { - dict_append_entry(&dict, "CrankRevolutions", - DBUS_TYPE_UINT16, &m->crank_rev); - dict_append_entry(&dict, "LastCrankEventTime", - DBUS_TYPE_UINT16, &m->last_crank_time); - } - - dbus_message_iter_close_container(&iter, &dict); - - dbus_message_set_no_reply(msg, TRUE); - g_dbus_send_message(btd_get_dbus_connection(), msg); -} - -static void process_measurement(struct csc *csc, const uint8_t *pdu, - uint16_t len) -{ - struct measurement m; - uint8_t flags; - - flags = *pdu; - - pdu++; - len--; - - memset(&m, 0, sizeof(m)); - - if ((flags & WHEEL_REV_PRESENT) && (csc->feature & WHEEL_REV_SUPPORT)) { - if (len < 6) { - error("Wheel revolutions data fields missing"); - return; - } - - m.has_wheel_rev = true; - m.wheel_rev = get_le32(pdu); - m.last_wheel_time = get_le16(pdu + 4); - pdu += 6; - len -= 6; - } - - if ((flags & CRANK_REV_PRESENT) && (csc->feature & CRANK_REV_SUPPORT)) { - if (len < 4) { - error("Crank revolutions data fields missing"); - return; - } - - m.has_crank_rev = true; - m.crank_rev = get_le16(pdu); - m.last_crank_time = get_le16(pdu + 2); - pdu += 4; - len -= 4; - } - - /* Notify all registered watchers */ - m.csc = csc; - g_slist_foreach(csc->cadapter->watchers, update_watcher, &m); -} - -static void measurement_notify_handler(const uint8_t *pdu, uint16_t len, - gpointer user_data) -{ - struct csc *csc = user_data; - - /* should be at least opcode (1b) + handle (2b) */ - if (len < 3) { - error("Invalid PDU received"); - return; - } - - process_measurement(csc, pdu + 3, len - 3); -} - -static void controlpoint_property_reply(struct controlpoint_req *req, - uint8_t code) -{ - switch (code) { - case RSP_SUCCESS: - g_dbus_pending_property_success(req->reply_id); - break; - - case RSP_NOT_SUPPORTED: - g_dbus_pending_property_error(req->reply_id, - ERROR_INTERFACE ".NotSupported", - "Feature is not supported"); - break; - - case RSP_INVALID_PARAM: - g_dbus_pending_property_error(req->reply_id, - ERROR_INTERFACE ".InvalidArguments", - "Invalid arguments in method call"); - break; - - case RSP_FAILED: - g_dbus_pending_property_error(req->reply_id, - ERROR_INTERFACE ".Failed", - "Operation failed"); - break; - - default: - g_dbus_pending_property_error(req->reply_id, - ERROR_INTERFACE ".Failed", - "Operation failed (%d)", code); - break; - } -} - -static void controlpoint_method_reply(struct controlpoint_req *req, - uint8_t code) -{ - DBusMessage *reply; - - switch (code) { - case RSP_SUCCESS: - reply = dbus_message_new_method_return(req->msg); - break; - case RSP_NOT_SUPPORTED: - reply = btd_error_not_supported(req->msg); - break; - case RSP_INVALID_PARAM: - reply = btd_error_invalid_args(req->msg); - break; - case RSP_FAILED: - reply = btd_error_failed(req->msg, "Failed"); - break; - default: - reply = btd_error_failed(req->msg, "Unknown error"); - break; - } - - g_dbus_send_message(btd_get_dbus_connection(), reply); - - dbus_message_unref(req->msg); -} - -static void controlpoint_ind_handler(const uint8_t *pdu, uint16_t len, - gpointer user_data) -{ - struct csc *csc = user_data; - struct controlpoint_req *req = csc->pending_req; - uint8_t opcode; - uint8_t req_opcode; - uint8_t rsp_code; - uint8_t *opdu; - uint16_t olen; - size_t plen; - - if (len < ATT_HDR_LEN) { - error("Invalid PDU received"); - return; - } - - /* skip ATT header */ - pdu += ATT_HDR_LEN; - len -= ATT_HDR_LEN; - - if (len < 1) { - error("Op Code missing"); - goto done; - } - - opcode = *pdu; - pdu++; - len--; - - if (opcode != RESPONSE_CODE) { - DBG("Unsupported Op Code received (%d)", opcode); - goto done; - } - - if (len < 2) { - error("Invalid Response Code PDU received"); - goto done; - } - - req_opcode = *pdu; - rsp_code = *(pdu + 1); - pdu += 2; - len -= 2; - - if (req == NULL || req->opcode != req_opcode) { - DBG("Indication received without pending request"); - goto done; - } - - switch (req->opcode) { - case SET_CUMULATIVE_VALUE: - controlpoint_method_reply(req, rsp_code); - break; - - case REQUEST_SUPPORTED_SENSOR_LOC: - if (rsp_code == RSP_SUCCESS) { - csc->num_locations = len; - csc->locations = g_memdup(pdu, len); - } else { - error("Failed to read Supported Sendor Locations"); - } - break; - - case UPDATE_SENSOR_LOC: - csc->location = req->pending_location; - - controlpoint_property_reply(req, rsp_code); - - g_dbus_emit_property_changed(btd_get_dbus_connection(), - device_get_path(csc->dev), - CYCLINGSPEED_INTERFACE, "Location"); - break; - } - - csc->pending_req = NULL; - g_source_remove(req->timeout); - g_free(req); - -done: - opdu = g_attrib_get_buffer(csc->attrib, &plen); - olen = enc_confirmation(opdu, plen); - if (olen > 0) - g_attrib_send(csc->attrib, 0, opdu, olen, NULL, NULL, NULL); -} - -static void discover_char_cb(uint8_t status, GSList *chars, void *user_data) -{ - struct csc *csc = user_data; - uint16_t feature_val_handle = 0; - - if (status) { - error("Discover CSCS characteristics: %s", - att_ecode2str(status)); - return; - } - - for (; chars; chars = chars->next) { - struct gatt_char *c = chars->data; - struct gatt_char *c_next = - (chars->next ? chars->next->data : NULL); - - if (g_strcmp0(c->uuid, CSC_MEASUREMENT_UUID) == 0) { - csc->attio_measurement_id = - g_attrib_register(csc->attrib, - ATT_OP_HANDLE_NOTIFY, c->value_handle, - measurement_notify_handler, csc, NULL); - - discover_desc(csc, c, c_next); - } else if (g_strcmp0(c->uuid, CSC_FEATURE_UUID) == 0) { - feature_val_handle = c->value_handle; - } else if (g_strcmp0(c->uuid, SENSOR_LOCATION_UUID) == 0) { - DBG("Sensor Location supported"); - gatt_read_char(csc->attrib, c->value_handle, - read_location_cb, csc); - } else if (g_strcmp0(c->uuid, SC_CONTROL_POINT_UUID) == 0) { - DBG("SC Control Point supported"); - csc->controlpoint_val_handle = c->value_handle; - - csc->attio_controlpoint_id = g_attrib_register( - csc->attrib, ATT_OP_HANDLE_IND, - c->value_handle, - controlpoint_ind_handler, csc, NULL); - - discover_desc(csc, c, c_next); - } - } - - if (feature_val_handle > 0) - gatt_read_char(csc->attrib, feature_val_handle, - read_feature_cb, csc); -} - -static void enable_measurement(gpointer data, gpointer user_data) -{ - struct csc *csc = data; - uint16_t handle = csc->measurement_ccc_handle; - uint8_t value[2]; - char *msg; - - if (csc->attrib == NULL || !handle) - return; - - put_le16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value); - msg = g_strdup("Enable measurement"); - - gatt_write_char(csc->attrib, handle, value, sizeof(value), - char_write_cb, msg); -} - -static void disable_measurement(gpointer data, gpointer user_data) -{ - struct csc *csc = data; - uint16_t handle = csc->measurement_ccc_handle; - uint8_t value[2]; - char *msg; - - if (csc->attrib == NULL || !handle) - return; - - put_le16(0x0000, value); - msg = g_strdup("Disable measurement"); - - gatt_write_char(csc->attrib, handle, value, sizeof(value), - char_write_cb, msg); -} - -static void attio_connected_cb(GAttrib *attrib, gpointer user_data) -{ - struct csc *csc = user_data; - - DBG(""); - - csc->attrib = g_attrib_ref(attrib); - - gatt_discover_char(csc->attrib, csc->svc_range->start, - csc->svc_range->end, NULL, - discover_char_cb, csc); -} - -static void attio_disconnected_cb(gpointer user_data) -{ - struct csc *csc = user_data; - - DBG(""); - - if (csc->attio_measurement_id > 0) { - g_attrib_unregister(csc->attrib, csc->attio_measurement_id); - csc->attio_measurement_id = 0; - } - - if (csc->attio_controlpoint_id > 0) { - g_attrib_unregister(csc->attrib, csc->attio_controlpoint_id); - csc->attio_controlpoint_id = 0; - } - - g_attrib_unref(csc->attrib); - csc->attrib = NULL; -} - -static void watcher_exit_cb(DBusConnection *conn, void *user_data) -{ - struct watcher *watcher = user_data; - struct csc_adapter *cadapter = watcher->cadapter; - - DBG("cycling watcher [%s] disconnected", watcher->path); - - cadapter->watchers = g_slist_remove(cadapter->watchers, watcher); - g_dbus_remove_watch(conn, watcher->id); - - if (g_slist_length(cadapter->watchers) == 0) - g_slist_foreach(cadapter->devices, disable_measurement, 0); -} - -static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg, - void *data) -{ - struct csc_adapter *cadapter = data; - struct watcher *watcher; - const char *sender = dbus_message_get_sender(msg); - char *path; - - if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - return btd_error_invalid_args(msg); - - watcher = find_watcher(cadapter->watchers, sender, path); - if (watcher != NULL) - return btd_error_already_exists(msg); - - watcher = g_new0(struct watcher, 1); - watcher->cadapter = cadapter; - watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit_cb, - watcher, destroy_watcher); - watcher->srv = g_strdup(sender); - watcher->path = g_strdup(path); - - if (g_slist_length(cadapter->watchers) == 0) - g_slist_foreach(cadapter->devices, enable_measurement, 0); - - cadapter->watchers = g_slist_prepend(cadapter->watchers, watcher); - - DBG("cycling watcher [%s] registered", path); - - return dbus_message_new_method_return(msg); -} - -static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg, - void *data) -{ - struct csc_adapter *cadapter = data; - struct watcher *watcher; - const char *sender = dbus_message_get_sender(msg); - char *path; - - if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - return btd_error_invalid_args(msg); - - watcher = find_watcher(cadapter->watchers, sender, path); - if (watcher == NULL) - return btd_error_does_not_exist(msg); - - cadapter->watchers = g_slist_remove(cadapter->watchers, watcher); - g_dbus_remove_watch(conn, watcher->id); - - if (g_slist_length(cadapter->watchers) == 0) - g_slist_foreach(cadapter->devices, disable_measurement, 0); - - DBG("cycling watcher [%s] unregistered", path); - - return dbus_message_new_method_return(msg); -} - -static const GDBusMethodTable cyclingspeed_manager_methods[] = { - { GDBUS_METHOD("RegisterWatcher", - GDBUS_ARGS({ "agent", "o" }), NULL, - register_watcher) }, - { GDBUS_METHOD("UnregisterWatcher", - GDBUS_ARGS({ "agent", "o" }), NULL, - unregister_watcher) }, - { } -}; - -static int csc_adapter_probe(struct btd_profile *p, struct btd_adapter *adapter) -{ - struct csc_adapter *cadapter; - - cadapter = g_new0(struct csc_adapter, 1); - cadapter->adapter = adapter; - - if (!g_dbus_register_interface(btd_get_dbus_connection(), - adapter_get_path(adapter), - CYCLINGSPEED_MANAGER_INTERFACE, - cyclingspeed_manager_methods, - NULL, NULL, cadapter, - destroy_csc_adapter)) { - error("D-Bus failed to register %s interface", - CYCLINGSPEED_MANAGER_INTERFACE); - destroy_csc_adapter(cadapter); - return -EIO; - } - - csc_adapters = g_slist_prepend(csc_adapters, cadapter); - - return 0; -} - -static void csc_adapter_remove(struct btd_profile *p, - struct btd_adapter *adapter) -{ - struct csc_adapter *cadapter; - - cadapter = find_csc_adapter(adapter); - if (cadapter == NULL) - return; - - csc_adapters = g_slist_remove(csc_adapters, cadapter); - - g_dbus_unregister_interface(btd_get_dbus_connection(), - adapter_get_path(cadapter->adapter), - CYCLINGSPEED_MANAGER_INTERFACE); -} - -static gboolean property_get_location(const GDBusPropertyTable *property, - DBusMessageIter *iter, void *data) -{ - struct csc *csc = data; - const char *loc; - - if (!csc->has_location) - return FALSE; - - loc = location2str(csc->location); - - dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &loc); - - return TRUE; -} - -static void property_set_location(const GDBusPropertyTable *property, - DBusMessageIter *iter, - GDBusPendingPropertySet id, void *data) -{ - struct csc *csc = data; - char *loc; - int loc_val; - uint8_t att_val[2]; - struct controlpoint_req *req; - - if (csc->pending_req != NULL) { - g_dbus_pending_property_error(id, - ERROR_INTERFACE ".InProgress", - "Operation already in progress"); - return; - } - - if (!(csc->feature & MULTI_SENSOR_LOC_SUPPORT)) { - g_dbus_pending_property_error(id, - ERROR_INTERFACE ".NotSupported", - "Feature is not supported"); - return; - } - - if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) { - g_dbus_pending_property_error(id, - ERROR_INTERFACE ".InvalidArguments", - "Invalid arguments in method call"); - return; - } - - dbus_message_iter_get_basic(iter, &loc); - - loc_val = str2location(loc); - - if (loc_val < 0) { - g_dbus_pending_property_error(id, - ERROR_INTERFACE ".InvalidArguments", - "Invalid arguments in method call"); - return; - } - - req = g_new(struct controlpoint_req, 1); - req->csc = csc; - req->reply_id = id; - req->opcode = UPDATE_SENSOR_LOC; - req->pending_location = loc_val; - - csc->pending_req = req; - - att_val[0] = UPDATE_SENSOR_LOC; - att_val[1] = loc_val; - - gatt_write_char(csc->attrib, csc->controlpoint_val_handle, att_val, - sizeof(att_val), controlpoint_write_cb, req); -} - -static gboolean property_exists_location(const GDBusPropertyTable *property, - void *data) -{ - struct csc *csc = data; - - return csc->has_location; -} - -static gboolean property_get_locations(const GDBusPropertyTable *property, - DBusMessageIter *iter, void *data) -{ - struct csc *csc = data; - DBusMessageIter entry; - int i; - - if (!(csc->feature & MULTI_SENSOR_LOC_SUPPORT)) - return FALSE; - - dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_STRING_AS_STRING, &entry); - for (i = 0; i < csc->num_locations; i++) { - char *loc = g_strdup(location2str(csc->locations[i])); - dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &loc); - g_free(loc); - } - - dbus_message_iter_close_container(iter, &entry); - - return TRUE; -} - -static gboolean property_exists_locations(const GDBusPropertyTable *property, - void *data) -{ - struct csc *csc = data; - - return !!(csc->feature & MULTI_SENSOR_LOC_SUPPORT); -} - -static gboolean property_get_wheel_rev_sup(const GDBusPropertyTable *property, - DBusMessageIter *iter, void *data) -{ - struct csc *csc = data; - dbus_bool_t val; - - val = !!(csc->feature & WHEEL_REV_SUPPORT); - dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &val); - - return TRUE; -} - -static gboolean property_get_multi_loc_sup(const GDBusPropertyTable *property, - DBusMessageIter *iter, void *data) -{ - struct csc *csc = data; - dbus_bool_t val; - - val = !!(csc->feature & MULTI_SENSOR_LOC_SUPPORT); - dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &val); - - return TRUE; -} - -static const GDBusPropertyTable cyclingspeed_device_properties[] = { - { "Location", "s", property_get_location, property_set_location, - property_exists_location }, - { "SupportedLocations", "as", property_get_locations, NULL, - property_exists_locations }, - { "WheelRevolutionDataSupported", "b", property_get_wheel_rev_sup }, - { "MultipleLocationsSupported", "b", property_get_multi_loc_sup }, - { } -}; - -static DBusMessage *set_cumulative_wheel_rev(DBusConnection *conn, - DBusMessage *msg, void *data) -{ - struct csc *csc = data; - dbus_uint32_t value; - struct controlpoint_req *req; - uint8_t att_val[5]; /* uint8 opcode + uint32 value */ - - if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &value, - DBUS_TYPE_INVALID)) - return btd_error_invalid_args(msg); - - if (csc->pending_req != NULL) - return btd_error_in_progress(msg); - - req = g_new(struct controlpoint_req, 1); - req->csc = csc; - req->opcode = SET_CUMULATIVE_VALUE; - req->msg = dbus_message_ref(msg); - - csc->pending_req = req; - - att_val[0] = SET_CUMULATIVE_VALUE; - put_le32(value, att_val + 1); - - gatt_write_char(csc->attrib, csc->controlpoint_val_handle, att_val, - sizeof(att_val), controlpoint_write_cb, req); - - return NULL; -} - -static const GDBusMethodTable cyclingspeed_device_methods[] = { - { GDBUS_ASYNC_METHOD("SetCumulativeWheelRevolutions", - GDBUS_ARGS({ "value", "u" }), NULL, - set_cumulative_wheel_rev) }, - { } -}; - -static int csc_device_probe(struct btd_service *service) -{ - struct btd_device *device = btd_service_get_device(service); - struct btd_adapter *adapter; - struct csc_adapter *cadapter; - struct csc *csc; - struct gatt_primary *prim; - - prim = btd_device_get_primary(device, CYCLING_SC_UUID); - if (prim == NULL) - return -EINVAL; - - adapter = device_get_adapter(device); - - cadapter = find_csc_adapter(adapter); - if (cadapter == NULL) - return -1; - - csc = g_new0(struct csc, 1); - csc->dev = btd_device_ref(device); - csc->cadapter = cadapter; - - if (!g_dbus_register_interface(btd_get_dbus_connection(), - device_get_path(device), - CYCLINGSPEED_INTERFACE, - cyclingspeed_device_methods, - NULL, - cyclingspeed_device_properties, - csc, destroy_csc)) { - error("D-Bus failed to register %s interface", - CYCLINGSPEED_INTERFACE); - destroy_csc(csc); - return -EIO; - } - - csc->svc_range = g_new0(struct att_range, 1); - csc->svc_range->start = prim->range.start; - csc->svc_range->end = prim->range.end; - - cadapter->devices = g_slist_prepend(cadapter->devices, csc); - - csc->attioid = btd_device_add_attio_callback(device, attio_connected_cb, - attio_disconnected_cb, csc); - - return 0; -} - -static void csc_device_remove(struct btd_service *service) -{ - struct btd_device *device = btd_service_get_device(service); - struct btd_adapter *adapter; - struct csc_adapter *cadapter; - struct csc *csc; - GSList *l; - - adapter = device_get_adapter(device); - - cadapter = find_csc_adapter(adapter); - if (cadapter == NULL) - return; - - l = g_slist_find_custom(cadapter->devices, device, cmp_device); - if (l == NULL) - return; - - csc = l->data; - - cadapter->devices = g_slist_remove(cadapter->devices, csc); - - g_dbus_unregister_interface(btd_get_dbus_connection(), - device_get_path(device), - CYCLINGSPEED_INTERFACE); -} - -static struct btd_profile cscp_profile = { - .name = "Cycling Speed and Cadence GATT Driver", - .remote_uuid = CYCLING_SC_UUID, - - .adapter_probe = csc_adapter_probe, - .adapter_remove = csc_adapter_remove, - - .device_probe = csc_device_probe, - .device_remove = csc_device_remove, -}; - -static int cyclingspeed_init(void) -{ - return btd_profile_register(&cscp_profile); -} - -static void cyclingspeed_exit(void) -{ - btd_profile_unregister(&cscp_profile); -} - -BLUETOOTH_PLUGIN_DEFINE(cyclingspeed, VERSION, - BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, - cyclingspeed_init, cyclingspeed_exit) diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c deleted file mode 100644 index 9e8c49931..000000000 --- a/profiles/heartrate/heartrate.c +++ /dev/null @@ -1,870 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2012 Tieto Poland - * - * 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 -#endif - -#include -#include -#include - -#include "lib/bluetooth.h" -#include "lib/sdp.h" -#include "lib/uuid.h" - -#include "gdbus/gdbus.h" - -#include "src/plugin.h" -#include "src/adapter.h" -#include "src/dbus-common.h" -#include "src/device.h" -#include "src/profile.h" -#include "src/shared/util.h" -#include "src/service.h" -#include "src/error.h" -#include "attrib/gattrib.h" -#include "attrib/att.h" -#include "attrib/gatt.h" -#include "src/attio.h" -#include "src/log.h" - -#define HEART_RATE_INTERFACE "org.bluez.HeartRate1" -#define HEART_RATE_MANAGER_INTERFACE "org.bluez.HeartRateManager1" -#define HEART_RATE_WATCHER_INTERFACE "org.bluez.HeartRateWatcher1" - -#define HR_VALUE_FORMAT 0x01 -#define SENSOR_CONTACT_DETECTED 0x02 -#define SENSOR_CONTACT_SUPPORT 0x04 -#define ENERGY_EXP_STATUS 0x08 -#define RR_INTERVAL 0x10 - -struct heartrate_adapter { - struct btd_adapter *adapter; - GSList *devices; - GSList *watchers; -}; - -struct heartrate { - struct btd_device *dev; - struct heartrate_adapter *hradapter; - GAttrib *attrib; - guint attioid; - guint attionotid; - - struct att_range *svc_range; /* primary svc range */ - - uint16_t measurement_ccc_handle; - uint16_t hrcp_val_handle; - - gboolean has_location; - uint8_t location; -}; - -struct watcher { - struct heartrate_adapter *hradapter; - guint id; - char *srv; - char *path; -}; - -struct measurement { - struct heartrate *hr; - uint16_t value; - gboolean has_energy; - uint16_t energy; - gboolean has_contact; - gboolean contact; - uint16_t num_interval; - uint16_t *interval; -}; - -static GSList *heartrate_adapters = NULL; - -static const char * const location_enum[] = { - "other", - "chest", - "wrist", - "finger", - "hand", - "earlobe", - "foot", -}; - -static const char *location2str(uint8_t value) -{ - if (value < G_N_ELEMENTS(location_enum)) - return location_enum[value]; - - error("Body Sensor Location [%d] is RFU", value); - - return NULL; -} - -static int cmp_adapter(gconstpointer a, gconstpointer b) -{ - const struct heartrate_adapter *hradapter = a; - const struct btd_adapter *adapter = b; - - if (adapter == hradapter->adapter) - return 0; - - return -1; -} - -static int cmp_device(gconstpointer a, gconstpointer b) -{ - const struct heartrate *hr = a; - const struct btd_device *dev = b; - - if (dev == hr->dev) - return 0; - - return -1; -} - -static int cmp_watcher(gconstpointer a, gconstpointer b) -{ - const struct watcher *watcher = a; - const struct watcher *match = b; - int ret; - - ret = g_strcmp0(watcher->srv, match->srv); - if (ret != 0) - return ret; - - return g_strcmp0(watcher->path, match->path); -} - -static struct heartrate_adapter * -find_heartrate_adapter(struct btd_adapter *adapter) -{ - GSList *l = g_slist_find_custom(heartrate_adapters, adapter, - cmp_adapter); - if (!l) - return NULL; - - return l->data; -} - -static void destroy_watcher(gpointer user_data) -{ - struct watcher *watcher = user_data; - - g_free(watcher->path); - g_free(watcher->srv); - g_free(watcher); -} - -static struct watcher *find_watcher(GSList *list, const char *sender, - const char *path) -{ - struct watcher *match; - GSList *l; - - match = g_new0(struct watcher, 1); - match->srv = g_strdup(sender); - match->path = g_strdup(path); - - l = g_slist_find_custom(list, match, cmp_watcher); - destroy_watcher(match); - - if (l != NULL) - return l->data; - - return NULL; -} - -static void destroy_heartrate(gpointer user_data) -{ - struct heartrate *hr = user_data; - - if (hr->attioid > 0) - btd_device_remove_attio_callback(hr->dev, hr->attioid); - - if (hr->attrib != NULL) { - g_attrib_unregister(hr->attrib, hr->attionotid); - g_attrib_unref(hr->attrib); - } - - btd_device_unref(hr->dev); - g_free(hr->svc_range); - g_free(hr); -} - -static void remove_watcher(gpointer user_data) -{ - struct watcher *watcher = user_data; - - g_dbus_remove_watch(btd_get_dbus_connection(), watcher->id); -} - -static void destroy_heartrate_adapter(gpointer user_data) -{ - struct heartrate_adapter *hradapter = user_data; - - g_slist_free_full(hradapter->watchers, remove_watcher); - - g_free(hradapter); -} - -static void read_sensor_location_cb(guint8 status, const guint8 *pdu, - guint16 len, gpointer user_data) -{ - struct heartrate *hr = user_data; - uint8_t value; - ssize_t vlen; - - if (status != 0) { - error("Body Sensor Location read failed: %s", - att_ecode2str(status)); - return; - } - - vlen = dec_read_resp(pdu, len, &value, sizeof(value)); - if (vlen < 0) { - error("Protocol error"); - return; - } - - if (vlen != sizeof(value)) { - error("Invalid length for Body Sensor Location"); - return; - } - - hr->has_location = TRUE; - hr->location = value; -} - -static void char_write_cb(guint8 status, const guint8 *pdu, guint16 len, - gpointer user_data) -{ - char *msg = user_data; - - if (status != 0) - error("%s failed", msg); - - g_free(msg); -} - -static void update_watcher(gpointer data, gpointer user_data) -{ - struct watcher *w = data; - struct measurement *m = user_data; - struct heartrate *hr = m->hr; - const char *path = device_get_path(hr->dev); - DBusMessageIter iter; - DBusMessageIter dict; - DBusMessage *msg; - - msg = dbus_message_new_method_call(w->srv, w->path, - HEART_RATE_WATCHER_INTERFACE, "MeasurementReceived"); - if (msg == NULL) - return; - - dbus_message_iter_init_append(msg, &iter); - - dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH , &path); - - 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, "Value", DBUS_TYPE_UINT16, &m->value); - - if (m->has_energy) - dict_append_entry(&dict, "Energy", DBUS_TYPE_UINT16, - &m->energy); - - if (m->has_contact) - dict_append_entry(&dict, "Contact", DBUS_TYPE_BOOLEAN, - &m->contact); - - if (m->num_interval > 0) - dict_append_array(&dict, "Interval", DBUS_TYPE_UINT16, - &m->interval, m->num_interval); - - dbus_message_iter_close_container(&iter, &dict); - - dbus_message_set_no_reply(msg, TRUE); - g_dbus_send_message(btd_get_dbus_connection(), msg); -} - -static void process_measurement(struct heartrate *hr, const uint8_t *pdu, - uint16_t len) -{ - struct measurement m; - uint8_t flags; - - flags = *pdu; - - pdu++; - len--; - - memset(&m, 0, sizeof(m)); - - if (flags & HR_VALUE_FORMAT) { - if (len < 2) { - error("Heart Rate Measurement field missing"); - return; - } - - m.value = get_le16(pdu); - pdu += 2; - len -= 2; - } else { - if (len < 1) { - error("Heart Rate Measurement field missing"); - return; - } - - m.value = *pdu; - pdu++; - len--; - } - - if (flags & ENERGY_EXP_STATUS) { - if (len < 2) { - error("Energy Expended field missing"); - return; - } - - m.has_energy = TRUE; - m.energy = get_le16(pdu); - pdu += 2; - len -= 2; - } - - if (flags & RR_INTERVAL) { - int i; - - if (len == 0 || (len % 2 != 0)) { - error("RR-Interval field malformed"); - return; - } - - m.num_interval = len / 2; - m.interval = g_new(uint16_t, m.num_interval); - - for (i = 0; i < m.num_interval; pdu += 2, i++) - m.interval[i] = get_le16(pdu); - } - - if (flags & SENSOR_CONTACT_SUPPORT) { - m.has_contact = TRUE; - m.contact = !!(flags & SENSOR_CONTACT_DETECTED); - } - - /* Notify all registered watchers */ - m.hr = hr; - g_slist_foreach(hr->hradapter->watchers, update_watcher, &m); - - g_free(m.interval); -} - -static void notify_handler(const uint8_t *pdu, uint16_t len, gpointer user_data) -{ - struct heartrate *hr = user_data; - - /* should be at least opcode (1b) + handle (2b) */ - if (len < 3) { - error("Invalid PDU received"); - return; - } - - process_measurement(hr, pdu + 3, len - 3); -} - -static void discover_ccc_cb(uint8_t status, GSList *descs, void *user_data) -{ - struct heartrate *hr = user_data; - struct gatt_desc *desc; - uint8_t attr_val[2]; - char *msg; - - if (status != 0) { - error("Discover Heart Rate Measurement descriptors failed: %s", - att_ecode2str(status)); - return; - } - - /* There will be only one descriptor on list and it will be CCC */ - desc = descs->data; - - hr->measurement_ccc_handle = desc->handle; - - if (g_slist_length(hr->hradapter->watchers) == 0) { - put_le16(0x0000, attr_val); - msg = g_strdup("Disable measurement"); - } else { - put_le16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, attr_val); - msg = g_strdup("Enable measurement"); - } - - gatt_write_char(hr->attrib, desc->handle, attr_val, sizeof(attr_val), - char_write_cb, msg); -} - -static void discover_measurement_ccc(struct heartrate *hr, - struct gatt_char *c, struct gatt_char *c_next) -{ - uint16_t start, end; - bt_uuid_t uuid; - - start = c->value_handle + 1; - - if (c_next != NULL) { - if (start == c_next->handle) - return; - end = c_next->handle - 1; - } else if (c->value_handle != hr->svc_range->end) { - end = hr->svc_range->end; - } else { - return; - } - - bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID); - - gatt_discover_desc(hr->attrib, start, end, &uuid, discover_ccc_cb, hr); -} - -static void discover_char_cb(uint8_t status, GSList *chars, void *user_data) -{ - struct heartrate *hr = user_data; - - if (status) { - error("Discover HRS characteristics failed: %s", - att_ecode2str(status)); - return; - } - - for (; chars; chars = chars->next) { - struct gatt_char *c = chars->data; - - if (g_strcmp0(c->uuid, HEART_RATE_MEASUREMENT_UUID) == 0) { - struct gatt_char *c_next = - (chars->next ? chars->next->data : NULL); - - hr->attionotid = g_attrib_register(hr->attrib, - ATT_OP_HANDLE_NOTIFY, - c->value_handle, - notify_handler, hr, NULL); - - discover_measurement_ccc(hr, c, c_next); - } else if (g_strcmp0(c->uuid, BODY_SENSOR_LOCATION_UUID) == 0) { - DBG("Body Sensor Location supported"); - - gatt_read_char(hr->attrib, c->value_handle, - read_sensor_location_cb, hr); - } else if (g_strcmp0(c->uuid, - HEART_RATE_CONTROL_POINT_UUID) == 0) { - DBG("Heart Rate Control Point supported"); - hr->hrcp_val_handle = c->value_handle; - } - } -} - -static void enable_measurement(gpointer data, gpointer user_data) -{ - struct heartrate *hr = data; - uint16_t handle = hr->measurement_ccc_handle; - uint8_t value[2]; - char *msg; - - if (hr->attrib == NULL || !handle) - return; - - put_le16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value); - msg = g_strdup("Enable measurement"); - - gatt_write_char(hr->attrib, handle, value, sizeof(value), - char_write_cb, msg); -} - -static void disable_measurement(gpointer data, gpointer user_data) -{ - struct heartrate *hr = data; - uint16_t handle = hr->measurement_ccc_handle; - uint8_t value[2]; - char *msg; - - if (hr->attrib == NULL || !handle) - return; - - put_le16(0x0000, value); - msg = g_strdup("Disable measurement"); - - gatt_write_char(hr->attrib, handle, value, sizeof(value), - char_write_cb, msg); -} - -static void attio_connected_cb(GAttrib *attrib, gpointer user_data) -{ - struct heartrate *hr = user_data; - - DBG(""); - - hr->attrib = g_attrib_ref(attrib); - - gatt_discover_char(hr->attrib, hr->svc_range->start, hr->svc_range->end, - NULL, discover_char_cb, hr); -} - -static void attio_disconnected_cb(gpointer user_data) -{ - struct heartrate *hr = user_data; - - DBG(""); - - if (hr->attionotid > 0) { - g_attrib_unregister(hr->attrib, hr->attionotid); - hr->attionotid = 0; - } - - g_attrib_unref(hr->attrib); - hr->attrib = NULL; -} - -static void watcher_exit_cb(DBusConnection *conn, void *user_data) -{ - struct watcher *watcher = user_data; - struct heartrate_adapter *hradapter = watcher->hradapter; - - DBG("heartrate watcher [%s] disconnected", watcher->path); - - hradapter->watchers = g_slist_remove(hradapter->watchers, watcher); - g_dbus_remove_watch(conn, watcher->id); - - if (g_slist_length(hradapter->watchers) == 0) - g_slist_foreach(hradapter->devices, disable_measurement, 0); -} - -static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg, - void *data) -{ - struct heartrate_adapter *hradapter = data; - struct watcher *watcher; - const char *sender = dbus_message_get_sender(msg); - char *path; - - if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - return btd_error_invalid_args(msg); - - watcher = find_watcher(hradapter->watchers, sender, path); - if (watcher != NULL) - return btd_error_already_exists(msg); - - watcher = g_new0(struct watcher, 1); - watcher->hradapter = hradapter; - watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit_cb, - watcher, destroy_watcher); - watcher->srv = g_strdup(sender); - watcher->path = g_strdup(path); - - if (g_slist_length(hradapter->watchers) == 0) - g_slist_foreach(hradapter->devices, enable_measurement, 0); - - hradapter->watchers = g_slist_prepend(hradapter->watchers, watcher); - - DBG("heartrate watcher [%s] registered", path); - - return dbus_message_new_method_return(msg); -} - -static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg, - void *data) -{ - struct heartrate_adapter *hradapter = data; - struct watcher *watcher; - const char *sender = dbus_message_get_sender(msg); - char *path; - - if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - return btd_error_invalid_args(msg); - - watcher = find_watcher(hradapter->watchers, sender, path); - if (watcher == NULL) - return btd_error_does_not_exist(msg); - - hradapter->watchers = g_slist_remove(hradapter->watchers, watcher); - g_dbus_remove_watch(conn, watcher->id); - - if (g_slist_length(hradapter->watchers) == 0) - g_slist_foreach(hradapter->devices, disable_measurement, 0); - - DBG("heartrate watcher [%s] unregistered", path); - - return dbus_message_new_method_return(msg); -} - -static const GDBusMethodTable heartrate_manager_methods[] = { - { GDBUS_METHOD("RegisterWatcher", - GDBUS_ARGS({ "agent", "o" }), NULL, - register_watcher) }, - { GDBUS_METHOD("UnregisterWatcher", - GDBUS_ARGS({ "agent", "o" }), NULL, - unregister_watcher) }, - { } -}; - -static gboolean property_get_location(const GDBusPropertyTable *property, - DBusMessageIter *iter, void *data) -{ - struct heartrate *hr = data; - char *loc; - - if (!hr->has_location) - return FALSE; - - loc = g_strdup(location2str(hr->location)); - - if (loc == NULL) - return FALSE; - - dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &loc); - - g_free(loc); - - return TRUE; -} - -static gboolean property_exists_location(const GDBusPropertyTable *property, - void *data) -{ - struct heartrate *hr = data; - - if (!hr->has_location || location2str(hr->location) == NULL) - return FALSE; - - return TRUE; -} - -static gboolean property_get_reset_supported(const GDBusPropertyTable *property, - DBusMessageIter *iter, void *data) -{ - struct heartrate *hr = data; - dbus_bool_t has_reset = !!hr->hrcp_val_handle; - - dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &has_reset); - - return TRUE; -} - -static DBusMessage *hrcp_reset(DBusConnection *conn, DBusMessage *msg, - void *data) -{ - struct heartrate *hr = data; - uint8_t value; - char *vmsg; - - if (!hr->hrcp_val_handle) - return btd_error_not_supported(msg); - - if (!hr->attrib) - return btd_error_not_available(msg); - - value = 0x01; - vmsg = g_strdup("Reset Control Point"); - gatt_write_char(hr->attrib, hr->hrcp_val_handle, &value, - sizeof(value), char_write_cb, vmsg); - - DBG("Energy Expended Value has been reset"); - - return dbus_message_new_method_return(msg); -} - -static const GDBusMethodTable heartrate_device_methods[] = { - { GDBUS_METHOD("Reset", NULL, NULL, hrcp_reset) }, - { } -}; - -static const GDBusPropertyTable heartrate_device_properties[] = { - { "Location", "s", property_get_location, NULL, - property_exists_location }, - { "ResetSupported", "b", property_get_reset_supported }, - { } -}; - -static int heartrate_adapter_register(struct btd_adapter *adapter) -{ - struct heartrate_adapter *hradapter; - - hradapter = g_new0(struct heartrate_adapter, 1); - hradapter->adapter = adapter; - - if (!g_dbus_register_interface(btd_get_dbus_connection(), - adapter_get_path(adapter), - HEART_RATE_MANAGER_INTERFACE, - heartrate_manager_methods, - NULL, NULL, hradapter, - destroy_heartrate_adapter)) { - error("D-Bus failed to register %s interface", - HEART_RATE_MANAGER_INTERFACE); - destroy_heartrate_adapter(hradapter); - return -EIO; - } - - heartrate_adapters = g_slist_prepend(heartrate_adapters, hradapter); - - return 0; -} - -static void heartrate_adapter_unregister(struct btd_adapter *adapter) -{ - struct heartrate_adapter *hradapter; - - hradapter = find_heartrate_adapter(adapter); - if (hradapter == NULL) - return; - - heartrate_adapters = g_slist_remove(heartrate_adapters, hradapter); - - g_dbus_unregister_interface(btd_get_dbus_connection(), - adapter_get_path(hradapter->adapter), - HEART_RATE_MANAGER_INTERFACE); -} - -static int heartrate_device_register(struct btd_device *device, - struct gatt_primary *prim) -{ - struct btd_adapter *adapter; - struct heartrate_adapter *hradapter; - struct heartrate *hr; - - adapter = device_get_adapter(device); - - hradapter = find_heartrate_adapter(adapter); - - if (hradapter == NULL) - return -1; - - hr = g_new0(struct heartrate, 1); - hr->dev = btd_device_ref(device); - hr->hradapter = hradapter; - - if (!g_dbus_register_interface(btd_get_dbus_connection(), - device_get_path(device), - HEART_RATE_INTERFACE, - heartrate_device_methods, - NULL, - heartrate_device_properties, - hr, destroy_heartrate)) { - error("D-Bus failed to register %s interface", - HEART_RATE_INTERFACE); - destroy_heartrate(hr); - return -EIO; - } - - hr->svc_range = g_new0(struct att_range, 1); - hr->svc_range->start = prim->range.start; - hr->svc_range->end = prim->range.end; - - hradapter->devices = g_slist_prepend(hradapter->devices, hr); - - hr->attioid = btd_device_add_attio_callback(device, attio_connected_cb, - attio_disconnected_cb, hr); - - return 0; -} - -static void heartrate_device_unregister(struct btd_device *device) -{ - struct btd_adapter *adapter; - struct heartrate_adapter *hradapter; - struct heartrate *hr; - GSList *l; - - adapter = device_get_adapter(device); - - hradapter = find_heartrate_adapter(adapter); - if (hradapter == NULL) - return; - - l = g_slist_find_custom(hradapter->devices, device, cmp_device); - if (l == NULL) - return; - - hr = l->data; - - hradapter->devices = g_slist_remove(hradapter->devices, hr); - - g_dbus_unregister_interface(btd_get_dbus_connection(), - device_get_path(device), HEART_RATE_INTERFACE); -} - -static int heartrate_adapter_probe(struct btd_profile *p, - struct btd_adapter *adapter) -{ - return heartrate_adapter_register(adapter); -} - -static void heartrate_adapter_remove(struct btd_profile *p, - struct btd_adapter *adapter) -{ - heartrate_adapter_unregister(adapter); -} - -static int heartrate_device_probe(struct btd_service *service) -{ - struct btd_device *device = btd_service_get_device(service); - struct gatt_primary *prim; - - prim = btd_device_get_primary(device, HEART_RATE_UUID); - if (prim == NULL) - return -EINVAL; - - return heartrate_device_register(device, prim); -} - -static void heartrate_device_remove(struct btd_service *service) -{ - struct btd_device *device = btd_service_get_device(service); - - heartrate_device_unregister(device); -} - -static struct btd_profile hrp_profile = { - .name = "Heart Rate GATT Driver", - .remote_uuid = HEART_RATE_UUID, - - .device_probe = heartrate_device_probe, - .device_remove = heartrate_device_remove, - - .adapter_probe = heartrate_adapter_probe, - .adapter_remove = heartrate_adapter_remove, -}; - -static int heartrate_init(void) -{ - return btd_profile_register(&hrp_profile); -} - -static void heartrate_exit(void) -{ - btd_profile_unregister(&hrp_profile); -} - -BLUETOOTH_PLUGIN_DEFINE(heartrate, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, - heartrate_init, heartrate_exit) diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c deleted file mode 100644 index b0fc3e005..000000000 --- a/profiles/thermometer/thermometer.c +++ /dev/null @@ -1,1321 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos. - * - * 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 -#endif - -#include -#include - -#include "lib/bluetooth.h" -#include "lib/sdp.h" -#include "lib/uuid.h" - -#include "gdbus/gdbus.h" - -#include "src/plugin.h" -#include "src/dbus-common.h" -#include "src/adapter.h" -#include "src/device.h" -#include "src/profile.h" -#include "src/service.h" -#include "src/shared/util.h" -#include "src/error.h" -#include "src/log.h" -#include "attrib/gattrib.h" -#include "src/attio.h" -#include "attrib/att.h" -#include "attrib/gatt.h" - -#define THERMOMETER_INTERFACE "org.bluez.Thermometer1" -#define THERMOMETER_MANAGER_INTERFACE "org.bluez.ThermometerManager1" -#define THERMOMETER_WATCHER_INTERFACE "org.bluez.ThermometerWatcher1" - -/* Temperature measurement flag fields */ -#define TEMP_UNITS 0x01 -#define TEMP_TIME_STAMP 0x02 -#define TEMP_TYPE 0x04 - -#define FLOAT_MAX_MANTISSA 16777216 /* 2^24 */ - -#define VALID_RANGE_DESC_SIZE 4 -#define TEMPERATURE_TYPE_SIZE 1 -#define MEASUREMENT_INTERVAL_SIZE 2 - -struct thermometer_adapter { - struct btd_adapter *adapter; - GSList *devices; - GSList *fwatchers; /* Final measurements */ - GSList *iwatchers; /* Intermediate measurements */ -}; - -struct thermometer { - struct btd_device *dev; /* Device reference */ - struct thermometer_adapter *tadapter; - GAttrib *attrib; /* GATT connection */ - struct att_range *svc_range; /* Thermometer range */ - guint attioid; /* Att watcher id */ - /* attio id for Temperature Measurement value indications */ - guint attio_measurement_id; - /* attio id for Intermediate Temperature value notifications */ - guint attio_intermediate_id; - /* attio id for Measurement Interval value indications */ - guint attio_interval_id; - gboolean intermediate; - uint8_t type; - uint16_t interval; - uint16_t max; - uint16_t min; - gboolean has_type; - gboolean has_interval; - - uint16_t measurement_ccc_handle; - uint16_t intermediate_ccc_handle; - uint16_t interval_val_handle; -}; - -struct characteristic { - struct thermometer *t; /* Thermometer where the char belongs */ - char uuid[MAX_LEN_UUID_STR + 1]; -}; - -struct watcher { - struct thermometer_adapter *tadapter; - guint id; - char *srv; - char *path; -}; - -struct measurement { - struct thermometer *t; - int16_t exp; - int32_t mant; - uint64_t time; - gboolean suptime; - char *unit; - char *type; - char *value; -}; - -struct tmp_interval_data { - struct thermometer *thermometer; - uint16_t interval; -}; - -static GSList *thermometer_adapters = NULL; - -static const char * const temp_type[] = { - "", - "armpit", - "body", - "ear", - "finger", - "intestines", - "mouth", - "rectum", - "toe", - "tympanum" -}; - -static const char *temptype2str(uint8_t value) -{ - if (value > 0 && value < G_N_ELEMENTS(temp_type)) - return temp_type[value]; - - error("Temperature type %d reserved for future use", value); - return NULL; -} - -static void destroy_watcher(gpointer user_data) -{ - struct watcher *watcher = user_data; - - g_free(watcher->path); - g_free(watcher->srv); - g_free(watcher); -} - -static void remove_watcher(gpointer user_data) -{ - struct watcher *watcher = user_data; - - g_dbus_remove_watch(btd_get_dbus_connection(), watcher->id); -} - -static void destroy_thermometer(gpointer user_data) -{ - struct thermometer *t = user_data; - - if (t->attioid > 0) - btd_device_remove_attio_callback(t->dev, t->attioid); - - if (t->attrib != NULL) { - g_attrib_unregister(t->attrib, t->attio_measurement_id); - g_attrib_unregister(t->attrib, t->attio_intermediate_id); - g_attrib_unregister(t->attrib, t->attio_interval_id); - g_attrib_unref(t->attrib); - } - - btd_device_unref(t->dev); - g_free(t->svc_range); - g_free(t); -} - -static void destroy_thermometer_adapter(gpointer user_data) -{ - struct thermometer_adapter *tadapter = user_data; - - if (tadapter->devices != NULL) - g_slist_free_full(tadapter->devices, destroy_thermometer); - - if (tadapter->fwatchers != NULL) - g_slist_free_full(tadapter->fwatchers, remove_watcher); - - g_free(tadapter); -} - -static int cmp_adapter(gconstpointer a, gconstpointer b) -{ - const struct thermometer_adapter *tadapter = a; - const struct btd_adapter *adapter = b; - - if (adapter == tadapter->adapter) - return 0; - - return -1; -} - -static int cmp_device(gconstpointer a, gconstpointer b) -{ - const struct thermometer *t = a; - const struct btd_device *dev = b; - - if (dev == t->dev) - return 0; - - return -1; -} - -static int cmp_watcher(gconstpointer a, gconstpointer b) -{ - const struct watcher *watcher = a; - const struct watcher *match = b; - int ret; - - ret = g_strcmp0(watcher->srv, match->srv); - if (ret != 0) - return ret; - - return g_strcmp0(watcher->path, match->path); -} - -static struct thermometer_adapter * -find_thermometer_adapter(struct btd_adapter *adapter) -{ - GSList *l = g_slist_find_custom(thermometer_adapters, adapter, - cmp_adapter); - if (!l) - return NULL; - - return l->data; -} - -static void change_property(struct thermometer *t, const char *name, - gpointer value) { - if (g_strcmp0(name, "Intermediate") == 0) { - gboolean *intermediate = value; - if (t->intermediate == *intermediate) - return; - - t->intermediate = *intermediate; - } else if (g_strcmp0(name, "Interval") == 0) { - uint16_t *interval = value; - if (t->has_interval && t->interval == *interval) - return; - - t->has_interval = TRUE; - t->interval = *interval; - } else if (g_strcmp0(name, "Maximum") == 0) { - uint16_t *max = value; - if (t->max == *max) - return; - - t->max = *max; - } else if (g_strcmp0(name, "Minimum") == 0) { - uint16_t *min = value; - if (t->min == *min) - return; - - t->min = *min; - } else { - DBG("%s is not a thermometer property", name); - return; - } - - g_dbus_emit_property_changed(btd_get_dbus_connection(), - device_get_path(t->dev), - THERMOMETER_INTERFACE, name); -} - -static void update_watcher(gpointer data, gpointer user_data) -{ - struct watcher *w = data; - struct measurement *m = user_data; - const char *path = device_get_path(m->t->dev); - DBusMessageIter iter; - DBusMessageIter dict; - DBusMessage *msg; - - msg = dbus_message_new_method_call(w->srv, w->path, - THERMOMETER_WATCHER_INTERFACE, - "MeasurementReceived"); - if (msg == NULL) - return; - - dbus_message_iter_init_append(msg, &iter); - - dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH , &path); - - 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, "Exponent", DBUS_TYPE_INT16, &m->exp); - dict_append_entry(&dict, "Mantissa", DBUS_TYPE_INT32, &m->mant); - dict_append_entry(&dict, "Unit", DBUS_TYPE_STRING, &m->unit); - - if (m->suptime) - dict_append_entry(&dict, "Time", DBUS_TYPE_UINT64, &m->time); - - dict_append_entry(&dict, "Type", DBUS_TYPE_STRING, &m->type); - dict_append_entry(&dict, "Measurement", DBUS_TYPE_STRING, &m->value); - - dbus_message_iter_close_container(&iter, &dict); - - dbus_message_set_no_reply(msg, TRUE); - g_dbus_send_message(btd_get_dbus_connection(), msg); -} - -static void recv_measurement(struct thermometer *t, struct measurement *m) -{ - GSList *wlist; - - m->t = t; - - if (g_strcmp0(m->value, "intermediate") == 0) - wlist = t->tadapter->iwatchers; - else - wlist = t->tadapter->fwatchers; - - g_slist_foreach(wlist, update_watcher, m); -} - -static void proc_measurement(struct thermometer *t, const uint8_t *pdu, - uint16_t len, gboolean final) -{ - struct measurement m; - const char *type = NULL; - uint8_t flags; - uint32_t raw; - - /* skip opcode and handle */ - pdu += 3; - len -= 3; - - if (len < 1) { - DBG("Mandatory flags are not provided"); - return; - } - - memset(&m, 0, sizeof(m)); - - flags = *pdu; - - if (flags & TEMP_UNITS) - m.unit = "fahrenheit"; - else - m.unit = "celsius"; - - pdu++; - len--; - - if (len < 4) { - DBG("Mandatory temperature measurement value is not provided"); - return; - } - - raw = get_le32(pdu); - m.mant = raw & 0x00FFFFFF; - m.exp = ((int32_t) raw) >> 24; - - if (m.mant & 0x00800000) { - /* convert to C2 negative value */ - m.mant = m.mant - FLOAT_MAX_MANTISSA; - } - - pdu += 4; - len -= 4; - - if (flags & TEMP_TIME_STAMP) { - struct tm ts; - time_t time; - - if (len < 7) { - DBG("Time stamp is not provided"); - return; - } - - ts.tm_year = get_le16(pdu) - 1900; - ts.tm_mon = *(pdu + 2) - 1; - ts.tm_mday = *(pdu + 3); - ts.tm_hour = *(pdu + 4); - ts.tm_min = *(pdu + 5); - ts.tm_sec = *(pdu + 6); - ts.tm_isdst = -1; - - time = mktime(&ts); - m.time = (uint64_t) time; - m.suptime = TRUE; - - pdu += 7; - len -= 7; - } - - if (flags & TEMP_TYPE) { - if (len < 1) { - DBG("Temperature type is not provided"); - return; - } - - type = temptype2str(*pdu); - } else if (t->has_type) { - type = temptype2str(t->type); - } - - m.type = g_strdup(type); - m.value = final ? "final" : "intermediate"; - - recv_measurement(t, &m); - g_free(m.type); -} - - -static void measurement_ind_handler(const uint8_t *pdu, uint16_t len, - gpointer user_data) -{ - struct thermometer *t = user_data; - uint8_t *opdu; - uint16_t olen; - size_t plen; - - if (len < 3) { - DBG("Bad pdu received"); - return; - } - - proc_measurement(t, pdu, len, TRUE); - - opdu = g_attrib_get_buffer(t->attrib, &plen); - olen = enc_confirmation(opdu, plen); - - if (olen > 0) - g_attrib_send(t->attrib, 0, opdu, olen, NULL, NULL, NULL); -} - -static void intermediate_notify_handler(const uint8_t *pdu, uint16_t len, - gpointer user_data) -{ - struct thermometer *t = user_data; - - if (len < 3) { - DBG("Bad pdu received"); - return; - } - - proc_measurement(t, pdu, len, FALSE); -} - -static void interval_ind_handler(const uint8_t *pdu, uint16_t len, - gpointer user_data) -{ - struct thermometer *t = user_data; - uint16_t interval; - uint8_t *opdu; - uint16_t olen; - size_t plen; - - if (len < 5) { - DBG("Bad pdu received"); - return; - } - - interval = get_le16(pdu + 3); - change_property(t, "Interval", &interval); - - opdu = g_attrib_get_buffer(t->attrib, &plen); - olen = enc_confirmation(opdu, plen); - - if (olen > 0) - g_attrib_send(t->attrib, 0, opdu, olen, NULL, NULL, NULL); -} - -static void valid_range_desc_cb(guint8 status, const guint8 *pdu, guint16 len, - gpointer user_data) -{ - struct thermometer *t = user_data; - uint8_t value[VALID_RANGE_DESC_SIZE]; - uint16_t max, min; - ssize_t vlen; - - if (status != 0) { - DBG("Valid Range descriptor read failed: %s", - att_ecode2str(status)); - return; - } - - vlen = dec_read_resp(pdu, len, value, sizeof(value)); - if (vlen < 0) { - DBG("Protocol error\n"); - return; - } - - if (vlen < 4) { - DBG("Invalid range received"); - return; - } - - min = get_le16(&value[0]); - max = get_le16(&value[2]); - - if (min == 0 || min > max) { - DBG("Invalid range"); - return; - } - - change_property(t, "Maximum", &max); - change_property(t, "Minimum", &min); -} - -static void write_ccc_cb(guint8 status, const guint8 *pdu, - guint16 len, gpointer user_data) -{ - char *msg = user_data; - - if (status != 0) - error("%s failed", msg); - - g_free(msg); -} - -static void process_thermometer_desc(struct characteristic *ch, uint16_t uuid, - uint16_t handle) -{ - uint8_t atval[2]; - uint16_t val; - char *msg; - - if (uuid == GATT_CHARAC_VALID_RANGE_UUID) { - if (g_strcmp0(ch->uuid, MEASUREMENT_INTERVAL_UUID) == 0) - gatt_read_char(ch->t->attrib, handle, - valid_range_desc_cb, ch->t); - return; - } - - if (uuid != GATT_CLIENT_CHARAC_CFG_UUID) - return; - - if (g_strcmp0(ch->uuid, TEMPERATURE_MEASUREMENT_UUID) == 0) { - ch->t->measurement_ccc_handle = handle; - - if (g_slist_length(ch->t->tadapter->fwatchers) == 0) { - val = 0x0000; - msg = g_strdup("Disable Temperature Measurement ind"); - } else { - val = GATT_CLIENT_CHARAC_CFG_IND_BIT; - msg = g_strdup("Enable Temperature Measurement ind"); - } - } else if (g_strcmp0(ch->uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0) { - ch->t->intermediate_ccc_handle = handle; - - if (g_slist_length(ch->t->tadapter->iwatchers) == 0) { - val = 0x0000; - msg = g_strdup("Disable Intermediate Temperature noti"); - } else { - val = GATT_CLIENT_CHARAC_CFG_NOTIF_BIT; - msg = g_strdup("Enable Intermediate Temperature noti"); - } - } else if (g_strcmp0(ch->uuid, MEASUREMENT_INTERVAL_UUID) == 0) { - val = GATT_CLIENT_CHARAC_CFG_IND_BIT; - msg = g_strdup("Enable Measurement Interval indication"); - } else { - return; - } - - put_le16(val, atval); - gatt_write_char(ch->t->attrib, handle, atval, sizeof(atval), - write_ccc_cb, msg); -} - -static void discover_desc_cb(guint8 status, GSList *descs, gpointer user_data) -{ - struct characteristic *ch = user_data; - - if (status != 0) { - error("Discover all characteristic descriptors failed [%s]: %s", - ch->uuid, att_ecode2str(status)); - goto done; - } - - for ( ; descs; descs = descs->next) { - struct gatt_desc *desc = descs->data; - - process_thermometer_desc(ch, desc->uuid16, desc->handle); - } - -done: - g_free(ch); -} - -static void discover_desc(struct thermometer *t, struct gatt_char *c, - struct gatt_char *c_next) -{ - struct characteristic *ch; - uint16_t start, end; - - start = c->value_handle + 1; - - if (c_next != NULL) { - if (start == c_next->handle) - return; - end = c_next->handle - 1; - } else if (c->value_handle != t->svc_range->end) { - end = t->svc_range->end; - } else { - return; - } - - ch = g_new0(struct characteristic, 1); - ch->t = t; - memcpy(ch->uuid, c->uuid, sizeof(c->uuid)); - - gatt_discover_desc(t->attrib, start, end, NULL, discover_desc_cb, ch); -} - -static void read_temp_type_cb(guint8 status, const guint8 *pdu, guint16 len, - gpointer user_data) -{ - struct thermometer *t = user_data; - uint8_t value[TEMPERATURE_TYPE_SIZE]; - ssize_t vlen; - - if (status != 0) { - DBG("Temperature Type value read failed: %s", - att_ecode2str(status)); - return; - } - - vlen = dec_read_resp(pdu, len, value, sizeof(value)); - if (vlen < 0) { - DBG("Protocol error."); - return; - } - - if (vlen != 1) { - DBG("Invalid length for Temperature type"); - return; - } - - t->has_type = TRUE; - t->type = value[0]; -} - -static void read_interval_cb(guint8 status, const guint8 *pdu, guint16 len, - gpointer user_data) -{ - struct thermometer *t = user_data; - uint8_t value[MEASUREMENT_INTERVAL_SIZE]; - uint16_t interval; - ssize_t vlen; - - if (status != 0) { - DBG("Measurement Interval value read failed: %s", - att_ecode2str(status)); - return; - } - - vlen = dec_read_resp(pdu, len, value, sizeof(value)); - if (vlen < 0) { - DBG("Protocol error\n"); - return; - } - - if (vlen < 2) { - DBG("Invalid Interval received"); - return; - } - - interval = get_le16(&value[0]); - change_property(t, "Interval", &interval); -} - -static void process_thermometer_char(struct thermometer *t, - struct gatt_char *c, struct gatt_char *c_next) -{ - if (g_strcmp0(c->uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0) { - gboolean intermediate = TRUE; - change_property(t, "Intermediate", &intermediate); - - t->attio_intermediate_id = g_attrib_register(t->attrib, - ATT_OP_HANDLE_NOTIFY, c->value_handle, - intermediate_notify_handler, t, NULL); - - discover_desc(t, c, c_next); - } else if (g_strcmp0(c->uuid, TEMPERATURE_MEASUREMENT_UUID) == 0) { - - t->attio_measurement_id = g_attrib_register(t->attrib, - ATT_OP_HANDLE_IND, c->value_handle, - measurement_ind_handler, t, NULL); - - discover_desc(t, c, c_next); - } else if (g_strcmp0(c->uuid, TEMPERATURE_TYPE_UUID) == 0) { - gatt_read_char(t->attrib, c->value_handle, - read_temp_type_cb, t); - } else if (g_strcmp0(c->uuid, MEASUREMENT_INTERVAL_UUID) == 0) { - bool need_desc = false; - - gatt_read_char(t->attrib, c->value_handle, read_interval_cb, t); - - if (c->properties & GATT_CHR_PROP_WRITE) { - t->interval_val_handle = c->value_handle; - need_desc = true; - } - - if (c->properties & GATT_CHR_PROP_INDICATE) { - t->attio_interval_id = g_attrib_register(t->attrib, - ATT_OP_HANDLE_IND, c->value_handle, - interval_ind_handler, t, NULL); - need_desc = true; - } - - if (need_desc) - discover_desc(t, c, c_next); - } -} - -static void configure_thermometer_cb(uint8_t status, GSList *characteristics, - void *user_data) -{ - struct thermometer *t = user_data; - GSList *l; - - if (status != 0) { - error("Discover thermometer characteristics: %s", - att_ecode2str(status)); - return; - } - - for (l = characteristics; l; l = l->next) { - struct gatt_char *c = l->data; - struct gatt_char *c_next = (l->next ? l->next->data : NULL); - - process_thermometer_char(t, c, c_next); - } -} - -static void write_interval_cb(guint8 status, const guint8 *pdu, guint16 len, - gpointer user_data) -{ - struct tmp_interval_data *data = user_data; - - if (status != 0) { - error("Interval Write Request failed %s", - att_ecode2str(status)); - goto done; - } - - if (!dec_write_resp(pdu, len)) { - error("Interval Write Request: protocol error"); - goto done; - } - - change_property(data->thermometer, "Interval", &data->interval); - -done: - g_free(user_data); -} - -static void enable_final_measurement(gpointer data, gpointer user_data) -{ - struct thermometer *t = data; - uint16_t handle = t->measurement_ccc_handle; - uint8_t value[2]; - char *msg; - - if (t->attrib == NULL || !handle) - return; - - put_le16(GATT_CLIENT_CHARAC_CFG_IND_BIT, value); - msg = g_strdup("Enable Temperature Measurement indications"); - - gatt_write_char(t->attrib, handle, value, sizeof(value), - write_ccc_cb, msg); -} - -static void enable_intermediate_measurement(gpointer data, gpointer user_data) -{ - struct thermometer *t = data; - uint16_t handle = t->intermediate_ccc_handle; - uint8_t value[2]; - char *msg; - - if (t->attrib == NULL || !handle) - return; - - put_le16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value); - msg = g_strdup("Enable Intermediate Temperature notifications"); - - gatt_write_char(t->attrib, handle, value, sizeof(value), - write_ccc_cb, msg); -} - -static void disable_final_measurement(gpointer data, gpointer user_data) -{ - struct thermometer *t = data; - uint16_t handle = t->measurement_ccc_handle; - uint8_t value[2]; - char *msg; - - if (t->attrib == NULL || !handle) - return; - - put_le16(0x0000, value); - msg = g_strdup("Disable Temperature Measurement indications"); - - gatt_write_char(t->attrib, handle, value, sizeof(value), - write_ccc_cb, msg); -} - -static void disable_intermediate_measurement(gpointer data, gpointer user_data) -{ - struct thermometer *t = data; - uint16_t handle = t->intermediate_ccc_handle; - uint8_t value[2]; - char *msg; - - if (t->attrib == NULL || !handle) - return; - - put_le16(0x0000, value); - msg = g_strdup("Disable Intermediate Temperature notifications"); - - gatt_write_char(t->attrib, handle, value, sizeof(value), - write_ccc_cb, msg); -} - -static void remove_int_watcher(struct thermometer_adapter *tadapter, - struct watcher *w) -{ - if (!g_slist_find(tadapter->iwatchers, w)) - return; - - tadapter->iwatchers = g_slist_remove(tadapter->iwatchers, w); - - if (g_slist_length(tadapter->iwatchers) == 0) - g_slist_foreach(tadapter->devices, - disable_intermediate_measurement, 0); -} - -static void watcher_exit(DBusConnection *conn, void *user_data) -{ - struct watcher *watcher = user_data; - struct thermometer_adapter *tadapter = watcher->tadapter; - - DBG("Thermometer watcher %s disconnected", watcher->path); - - remove_int_watcher(tadapter, watcher); - - tadapter->fwatchers = g_slist_remove(tadapter->fwatchers, watcher); - g_dbus_remove_watch(btd_get_dbus_connection(), watcher->id); - - if (g_slist_length(tadapter->fwatchers) == 0) - g_slist_foreach(tadapter->devices, - disable_final_measurement, 0); -} - -static struct watcher *find_watcher(GSList *list, const char *sender, - const char *path) -{ - struct watcher *match; - GSList *l; - - match = g_new0(struct watcher, 1); - match->srv = g_strdup(sender); - match->path = g_strdup(path); - - l = g_slist_find_custom(list, match, cmp_watcher); - destroy_watcher(match); - - if (l != NULL) - return l->data; - - return NULL; -} - -static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg, - void *data) -{ - const char *sender = dbus_message_get_sender(msg); - struct thermometer_adapter *tadapter = data; - struct watcher *watcher; - char *path; - - if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - return btd_error_invalid_args(msg); - - watcher = find_watcher(tadapter->fwatchers, sender, path); - if (watcher != NULL) - return btd_error_already_exists(msg); - - DBG("Thermometer watcher %s registered", path); - - watcher = g_new0(struct watcher, 1); - watcher->srv = g_strdup(sender); - watcher->path = g_strdup(path); - watcher->tadapter = tadapter; - watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit, - watcher, destroy_watcher); - - if (g_slist_length(tadapter->fwatchers) == 0) - g_slist_foreach(tadapter->devices, enable_final_measurement, 0); - - tadapter->fwatchers = g_slist_prepend(tadapter->fwatchers, watcher); - - return dbus_message_new_method_return(msg); -} - -static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg, - void *data) -{ - const char *sender = dbus_message_get_sender(msg); - struct thermometer_adapter *tadapter = data; - struct watcher *watcher; - char *path; - - if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - return btd_error_invalid_args(msg); - - watcher = find_watcher(tadapter->fwatchers, sender, path); - if (watcher == NULL) - return btd_error_does_not_exist(msg); - - DBG("Thermometer watcher %s unregistered", path); - - remove_int_watcher(tadapter, watcher); - - tadapter->fwatchers = g_slist_remove(tadapter->fwatchers, watcher); - g_dbus_remove_watch(btd_get_dbus_connection(), watcher->id); - - if (g_slist_length(tadapter->fwatchers) == 0) - g_slist_foreach(tadapter->devices, - disable_final_measurement, 0); - - return dbus_message_new_method_return(msg); -} - -static DBusMessage *enable_intermediate(DBusConnection *conn, DBusMessage *msg, - void *data) -{ - const char *sender = dbus_message_get_sender(msg); - struct thermometer_adapter *ta = data; - struct watcher *watcher; - char *path; - - if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - return btd_error_invalid_args(msg); - - watcher = find_watcher(ta->fwatchers, sender, path); - if (watcher == NULL) - return btd_error_does_not_exist(msg); - - if (find_watcher(ta->iwatchers, sender, path)) - return btd_error_already_exists(msg); - - DBG("Intermediate measurement watcher %s registered", path); - - if (g_slist_length(ta->iwatchers) == 0) - g_slist_foreach(ta->devices, - enable_intermediate_measurement, 0); - - ta->iwatchers = g_slist_prepend(ta->iwatchers, watcher); - - return dbus_message_new_method_return(msg); -} - -static DBusMessage *disable_intermediate(DBusConnection *conn, DBusMessage *msg, - void *data) -{ - const char *sender = dbus_message_get_sender(msg); - struct thermometer_adapter *ta = data; - struct watcher *watcher; - char *path; - - if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - return btd_error_invalid_args(msg); - - watcher = find_watcher(ta->iwatchers, sender, path); - if (watcher == NULL) - return btd_error_does_not_exist(msg); - - DBG("Intermediate measurement %s unregistered", path); - - remove_int_watcher(ta, watcher); - - return dbus_message_new_method_return(msg); -} - -static gboolean property_get_intermediate(const GDBusPropertyTable *property, - DBusMessageIter *iter, void *data) -{ - struct thermometer *t = data; - dbus_bool_t val; - - val = !!t->intermediate; - - dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &val); - - return TRUE; -} - -static gboolean property_get_interval(const GDBusPropertyTable *property, - DBusMessageIter *iter, void *data) -{ - struct thermometer *t = data; - - if (!t->has_interval) - return FALSE; - - dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &t->interval); - - return TRUE; -} - -static void property_set_interval(const GDBusPropertyTable *property, - DBusMessageIter *iter, - GDBusPendingPropertySet id, void *data) -{ - struct thermometer *t = data; - struct tmp_interval_data *interval_data; - uint16_t val; - uint8_t atval[2]; - - if (t->interval_val_handle == 0) { - g_dbus_pending_property_error(id, - ERROR_INTERFACE ".NotSupported", - "Operation is not supported"); - return; - } - - if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16) { - g_dbus_pending_property_error(id, - ERROR_INTERFACE ".InvalidArguments", - "Invalid arguments in method call"); - return; - } - - dbus_message_iter_get_basic(iter, &val); - - if (val < t->min || val > t->max) { - g_dbus_pending_property_error(id, - ERROR_INTERFACE ".InvalidArguments", - "Invalid arguments in method call"); - return; - } - - put_le16(val, &atval[0]); - - interval_data = g_new0(struct tmp_interval_data, 1); - interval_data->thermometer = t; - interval_data->interval = val; - gatt_write_char(t->attrib, t->interval_val_handle, atval, sizeof(atval), - write_interval_cb, interval_data); - - g_dbus_pending_property_success(id); -} - -static gboolean property_exists_interval(const GDBusPropertyTable *property, - void *data) -{ - struct thermometer *t = data; - - return t->has_interval; -} - -static gboolean property_get_maximum(const GDBusPropertyTable *property, - DBusMessageIter *iter, void *data) -{ - struct thermometer *t = data; - - if (!t->has_interval) - return FALSE; - - dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &t->max); - - return TRUE; -} - -static gboolean property_get_minimum(const GDBusPropertyTable *property, - DBusMessageIter *iter, void *data) -{ - struct thermometer *t = data; - - if (!t->has_interval) - return FALSE; - - dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &t->min); - - return TRUE; -} - -static const GDBusPropertyTable thermometer_properties[] = { - { "Intermediate", "b", property_get_intermediate }, - { "Interval", "q", property_get_interval, property_set_interval, - property_exists_interval }, - { "Maximum", "q", property_get_maximum, NULL, - property_exists_interval }, - { "Minimum", "q", property_get_minimum, NULL, - property_exists_interval }, - { } -}; - -static void attio_connected_cb(GAttrib *attrib, gpointer user_data) -{ - struct thermometer *t = user_data; - - t->attrib = g_attrib_ref(attrib); - - gatt_discover_char(t->attrib, t->svc_range->start, t->svc_range->end, - NULL, configure_thermometer_cb, t); -} - -static void attio_disconnected_cb(gpointer user_data) -{ - struct thermometer *t = user_data; - - DBG("GATT Disconnected"); - - if (t->attio_measurement_id > 0) { - g_attrib_unregister(t->attrib, t->attio_measurement_id); - t->attio_measurement_id = 0; - } - - if (t->attio_intermediate_id > 0) { - g_attrib_unregister(t->attrib, t->attio_intermediate_id); - t->attio_intermediate_id = 0; - } - - if (t->attio_interval_id > 0) { - g_attrib_unregister(t->attrib, t->attio_interval_id); - t->attio_interval_id = 0; - } - - g_attrib_unref(t->attrib); - t->attrib = NULL; -} - -static int thermometer_register(struct btd_device *device, - struct gatt_primary *tattr) -{ - const char *path = device_get_path(device); - struct thermometer *t; - struct btd_adapter *adapter; - struct thermometer_adapter *tadapter; - - adapter = device_get_adapter(device); - - tadapter = find_thermometer_adapter(adapter); - - if (tadapter == NULL) - return -1; - - t = g_new0(struct thermometer, 1); - t->dev = btd_device_ref(device); - t->tadapter = tadapter; - t->svc_range = g_new0(struct att_range, 1); - t->svc_range->start = tattr->range.start; - t->svc_range->end = tattr->range.end; - - tadapter->devices = g_slist_prepend(tadapter->devices, t); - - if (!g_dbus_register_interface(btd_get_dbus_connection(), - path, THERMOMETER_INTERFACE, - NULL, NULL, thermometer_properties, - t, destroy_thermometer)) { - error("D-Bus failed to register %s interface", - THERMOMETER_INTERFACE); - destroy_thermometer(t); - return -EIO; - } - - t->attioid = btd_device_add_attio_callback(device, attio_connected_cb, - attio_disconnected_cb, t); - return 0; -} - -static void thermometer_unregister(struct btd_device *device) -{ - struct thermometer *t; - struct btd_adapter *adapter; - struct thermometer_adapter *tadapter; - GSList *l; - - adapter = device_get_adapter(device); - - tadapter = find_thermometer_adapter(adapter); - - if (tadapter == NULL) - return; - - l = g_slist_find_custom(tadapter->devices, device, cmp_device); - if (l == NULL) - return; - - t = l->data; - - tadapter->devices = g_slist_remove(tadapter->devices, t); - - g_dbus_unregister_interface(btd_get_dbus_connection(), - device_get_path(t->dev), THERMOMETER_INTERFACE); -} - -static const GDBusMethodTable thermometer_manager_methods[] = { - { GDBUS_METHOD("RegisterWatcher", - GDBUS_ARGS({ "agent", "o" }), NULL, - register_watcher) }, - { GDBUS_METHOD("UnregisterWatcher", - GDBUS_ARGS({ "agent", "o" }), NULL, - unregister_watcher) }, - { GDBUS_METHOD("EnableIntermediateMeasurement", - GDBUS_ARGS({ "agent", "o" }), NULL, - enable_intermediate) }, - { GDBUS_METHOD("DisableIntermediateMeasurement", - GDBUS_ARGS({ "agent", "o" }), NULL, - disable_intermediate) }, - { } -}; - -static int thermometer_adapter_register(struct btd_adapter *adapter) -{ - struct thermometer_adapter *tadapter; - - tadapter = g_new0(struct thermometer_adapter, 1); - tadapter->adapter = adapter; - - if (!g_dbus_register_interface(btd_get_dbus_connection(), - adapter_get_path(adapter), - THERMOMETER_MANAGER_INTERFACE, - thermometer_manager_methods, - NULL, NULL, tadapter, - destroy_thermometer_adapter)) { - error("D-Bus failed to register %s interface", - THERMOMETER_MANAGER_INTERFACE); - destroy_thermometer_adapter(tadapter); - return -EIO; - } - - thermometer_adapters = g_slist_prepend(thermometer_adapters, tadapter); - - return 0; -} - -static void thermometer_adapter_unregister(struct btd_adapter *adapter) -{ - struct thermometer_adapter *tadapter; - - tadapter = find_thermometer_adapter(adapter); - if (tadapter == NULL) - return; - - thermometer_adapters = g_slist_remove(thermometer_adapters, tadapter); - - g_dbus_unregister_interface(btd_get_dbus_connection(), - adapter_get_path(tadapter->adapter), - THERMOMETER_MANAGER_INTERFACE); -} - -static int thermometer_device_probe(struct btd_service *service) -{ - struct btd_device *device = btd_service_get_device(service); - struct gatt_primary *tattr; - - tattr = btd_device_get_primary(device, HEALTH_THERMOMETER_UUID); - if (tattr == NULL) - return -EINVAL; - - return thermometer_register(device, tattr); -} - -static void thermometer_device_remove(struct btd_service *service) -{ - struct btd_device *device = btd_service_get_device(service); - - thermometer_unregister(device); -} - -static int thermometer_adapter_probe(struct btd_profile *p, - struct btd_adapter *adapter) -{ - return thermometer_adapter_register(adapter); -} - -static void thermometer_adapter_remove(struct btd_profile *p, - struct btd_adapter *adapter) -{ - thermometer_adapter_unregister(adapter); -} - -static struct btd_profile thermometer_profile = { - .name = "Health Thermometer GATT driver", - .remote_uuid = HEALTH_THERMOMETER_UUID, - .device_probe = thermometer_device_probe, - .device_remove = thermometer_device_remove, - .adapter_probe = thermometer_adapter_probe, - .adapter_remove = thermometer_adapter_remove -}; - -static int thermometer_init(void) -{ - return btd_profile_register(&thermometer_profile); -} - -static void thermometer_exit(void) -{ - btd_profile_unregister(&thermometer_profile); -} - -BLUETOOTH_PLUGIN_DEFINE(thermometer, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, - thermometer_init, thermometer_exit) diff --git a/profiles/time/server.c b/profiles/time/server.c deleted file mode 100644 index 2289c6a43..000000000 --- a/profiles/time/server.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2011 Nokia Corporation - * Copyright (C) 2011 Marcel Holtmann - * - * - * 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 -#endif - -#include -#include -#include -#include - -#include - -#include "lib/bluetooth.h" -#include "lib/sdp.h" -#include "lib/uuid.h" - -#include "src/adapter.h" -#include "src/device.h" -#include "src/profile.h" -#include "src/plugin.h" -#include "attrib/gattrib.h" -#include "attrib/att.h" -#include "attrib/gatt.h" -#include "attrib/att-database.h" -#include "src/shared/util.h" -#include "src/attrib-server.h" -#include "attrib/gatt-service.h" -#include "src/log.h" - -#define CURRENT_TIME_SVC_UUID 0x1805 -#define REF_TIME_UPDATE_SVC_UUID 0x1806 - -#define LOCAL_TIME_INFO_CHR_UUID 0x2A0F -#define TIME_UPDATE_CTRL_CHR_UUID 0x2A16 -#define TIME_UPDATE_STAT_CHR_UUID 0x2A17 -#define CT_TIME_CHR_UUID 0x2A2B - -enum { - UPDATE_RESULT_SUCCESSFUL = 0, - UPDATE_RESULT_CANCELED = 1, - UPDATE_RESULT_NO_CONN = 2, - UPDATE_RESULT_ERROR = 3, - UPDATE_RESULT_TIMEOUT = 4, - UPDATE_RESULT_NOT_ATTEMPTED = 5, -}; - -enum { - UPDATE_STATE_IDLE = 0, - UPDATE_STATE_PENDING = 1, -}; - -enum { - GET_REFERENCE_UPDATE = 1, - CANCEL_REFERENCE_UPDATE = 2, -}; - -static int encode_current_time(uint8_t value[10]) -{ - struct timespec tp; - struct tm tm; - - if (clock_gettime(CLOCK_REALTIME, &tp) == -1) { - int err = -errno; - - error("clock_gettime: %s", strerror(-err)); - return err; - } - - if (localtime_r(&tp.tv_sec, &tm) == NULL) { - error("localtime_r() failed"); - /* localtime_r() does not set errno */ - return -EINVAL; - } - - put_le16(1900 + tm.tm_year, &value[0]); /* Year */ - value[2] = tm.tm_mon + 1; /* Month */ - value[3] = tm.tm_mday; /* Day */ - value[4] = tm.tm_hour; /* Hours */ - value[5] = tm.tm_min; /* Minutes */ - value[6] = tm.tm_sec; /* Seconds */ - value[7] = tm.tm_wday == 0 ? 7 : tm.tm_wday; /* Day of Week */ - /* From Time Profile spec: "The number of 1/256 fractions of a second." - * In 1s there are 256 fractions, in 1ns there are 256/10^9 fractions. - * To avoid integer overflow, we use the equivalent 1/3906250 ratio. */ - value[8] = tp.tv_nsec / 3906250; /* Fractions256 */ - value[9] = 0x00; /* Adjust Reason */ - - return 0; -} - -static uint8_t current_time_read(struct attribute *a, - struct btd_device *device, gpointer user_data) -{ - struct btd_adapter *adapter = user_data; - uint8_t value[10]; - - if (encode_current_time(value) < 0) - return ATT_ECODE_IO; - - attrib_db_update(adapter, a->handle, NULL, value, sizeof(value), NULL); - - return 0; -} - -static uint8_t local_time_info_read(struct attribute *a, - struct btd_device *device, gpointer user_data) -{ - struct btd_adapter *adapter = user_data; - uint8_t value[2]; - - DBG("a=%p", a); - - tzset(); - - /* Convert POSIX "timezone" (seconds West of GMT) to Time Profile - * format (offset from UTC in number of 15 minutes increments). */ - value[0] = (uint8_t) (-1 * timezone / (60 * 15)); - - /* FIXME: POSIX "daylight" variable only indicates whether there - * is DST for the local time or not. The offset is unknown. */ - value[1] = daylight ? 0xff : 0x00; - - attrib_db_update(adapter, a->handle, NULL, value, sizeof(value), NULL); - - return 0; -} - -static gboolean register_current_time_service(struct btd_adapter *adapter) -{ - bt_uuid_t uuid; - - bt_uuid16_create(&uuid, CURRENT_TIME_SVC_UUID); - - /* Current Time service */ - return gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid, - /* CT Time characteristic */ - GATT_OPT_CHR_UUID16, CT_TIME_CHR_UUID, - GATT_OPT_CHR_PROPS, GATT_CHR_PROP_READ | - GATT_CHR_PROP_NOTIFY, - GATT_OPT_CHR_VALUE_CB, ATTRIB_READ, - current_time_read, adapter, - - /* Local Time Information characteristic */ - GATT_OPT_CHR_UUID16, LOCAL_TIME_INFO_CHR_UUID, - GATT_OPT_CHR_PROPS, GATT_CHR_PROP_READ, - GATT_OPT_CHR_VALUE_CB, ATTRIB_READ, - local_time_info_read, adapter, - - GATT_OPT_INVALID); -} - -static uint8_t time_update_control(struct attribute *a, - struct btd_device *device, - gpointer user_data) -{ - DBG("handle 0x%04x", a->handle); - - if (a->len != 1) - DBG("Invalid control point value size: %zu", a->len); - - switch (a->data[0]) { - case GET_REFERENCE_UPDATE: - DBG("Get Reference Update"); - break; - case CANCEL_REFERENCE_UPDATE: - DBG("Cancel Reference Update"); - break; - default: - DBG("Unknown command: 0x%02x", a->data[0]); - } - - return 0; -} - -static uint8_t time_update_status(struct attribute *a, - struct btd_device *device, - gpointer user_data) -{ - struct btd_adapter *adapter = user_data; - uint8_t value[2]; - - DBG("handle 0x%04x", a->handle); - - value[0] = UPDATE_STATE_IDLE; - value[1] = UPDATE_RESULT_SUCCESSFUL; - attrib_db_update(adapter, a->handle, NULL, value, sizeof(value), NULL); - - return 0; -} - -static gboolean register_ref_time_update_service(struct btd_adapter *adapter) -{ - bt_uuid_t uuid; - - bt_uuid16_create(&uuid, REF_TIME_UPDATE_SVC_UUID); - - /* Reference Time Update service */ - return gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid, - /* Time Update control point */ - GATT_OPT_CHR_UUID16, TIME_UPDATE_CTRL_CHR_UUID, - GATT_OPT_CHR_PROPS, - GATT_CHR_PROP_WRITE_WITHOUT_RESP, - GATT_OPT_CHR_VALUE_CB, ATTRIB_WRITE, - time_update_control, adapter, - - /* Time Update status */ - GATT_OPT_CHR_UUID16, TIME_UPDATE_STAT_CHR_UUID, - GATT_OPT_CHR_PROPS, GATT_CHR_PROP_READ, - GATT_OPT_CHR_VALUE_CB, ATTRIB_READ, - time_update_status, adapter, - - GATT_OPT_INVALID); -} - -static int time_server_init(struct btd_profile *p, struct btd_adapter *adapter) -{ - const char *path = adapter_get_path(adapter); - - DBG("path %s", path); - - if (!register_current_time_service(adapter)) { - error("Current Time Service could not be registered"); - return -EIO; - } - - if (!register_ref_time_update_service(adapter)) { - error("Reference Time Update Service could not be registered"); - return -EIO; - } - - return 0; -} - -static void time_server_exit(struct btd_profile *p, - struct btd_adapter *adapter) -{ - const char *path = adapter_get_path(adapter); - - DBG("path %s", path); -} - -struct btd_profile time_profile = { - .name = "gatt-time-server", - .adapter_probe = time_server_init, - .adapter_remove = time_server_exit, -}; - -static int time_init(void) -{ - return btd_profile_register(&time_profile); -} - -static void time_exit(void) -{ - btd_profile_unregister(&time_profile); -} - -BLUETOOTH_PLUGIN_DEFINE(time, VERSION, - BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, - time_init, time_exit) -- 2.47.3