build: Remove deprecated profiles
This removes deprecated GATT profiles that are no longer supported
and should instead be implemented over D-Bus.
diff --git a/Makefile.plugins b/Makefile.plugins
index 8a3605c..ecf6f08 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -87,35 +87,6 @@
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 2f6e3cd..0000000
--- 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 <marcel@holtmann.org>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdbool.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include <glib.h>
-
-#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 e447725..0000000
--- 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 <config.h>
-#endif
-
-#include <errno.h>
-#include <stdbool.h>
-
-#include <glib.h>
-
-#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 9e8c499..0000000
--- 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 <config.h>
-#endif
-
-#include <errno.h>
-#include <stdbool.h>
-#include <glib.h>
-
-#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 b0fc3e0..0000000
--- 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 <config.h>
-#endif
-
-#include <stdbool.h>
-#include <errno.h>
-
-#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[] = {
- "<reserved>",
- "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 2289c6a..0000000
--- 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 <marcel@holtmann.org>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <time.h>
-#include <errno.h>
-#include <string.h>
-#include <stdbool.h>
-
-#include <glib.h>
-
-#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)