3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2012 Texas Instruments Corporation
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 #include <bluetooth/uuid.h>
31 #include <dbus/dbus.h>
38 #include "att-database.h"
39 #include "gatt-service.h"
40 #include "attrib-server.h"
43 #include "dbus-common.h"
47 struct imm_alert_adapter {
48 struct btd_adapter *adapter;
50 GSList *connected_devices;
53 struct connected_device {
54 struct btd_device *device;
55 struct imm_alert_adapter *adapter;
60 static GSList *imm_alert_adapters;
62 static int imdevice_cmp(gconstpointer a, gconstpointer b)
64 const struct connected_device *condev = a;
65 const struct btd_device *device = b;
67 if (condev->device == device)
73 static struct connected_device *
74 find_connected_device(struct imm_alert_adapter *ia, struct btd_device *device)
76 GSList *l = g_slist_find_custom(ia->connected_devices, device,
84 static int imadapter_cmp(gconstpointer a, gconstpointer b)
86 const struct imm_alert_adapter *imadapter = a;
87 const struct btd_adapter *adapter = b;
89 if (imadapter->adapter == adapter)
95 static struct imm_alert_adapter *
96 find_imm_alert_adapter(struct btd_adapter *adapter)
98 GSList *l = g_slist_find_custom(imm_alert_adapters, adapter,
106 const char *imm_alert_get_level(struct btd_device *device)
108 struct imm_alert_adapter *imadapter;
109 struct connected_device *condev;
112 return get_alert_level_string(NO_ALERT);
114 imadapter = find_imm_alert_adapter(device_get_adapter(device));
116 return get_alert_level_string(NO_ALERT);
118 condev = find_connected_device(imadapter, device);
120 return get_alert_level_string(NO_ALERT);
122 return get_alert_level_string(condev->alert_level);
125 static void imm_alert_emit_alert_signal(struct connected_device *condev,
128 struct imm_alert_adapter *adapter;
129 const char *path, *alert_level_str;
134 adapter = condev->adapter;
135 path = device_get_path(condev->device);
136 alert_level_str = get_alert_level_string(alert_level);
138 DBG("alert %s remote %s", alert_level_str, path);
140 emit_property_changed(adapter->conn, path,
141 PROXIMITY_REPORTER_INTERFACE, "ImmediateAlertLevel",
142 DBUS_TYPE_STRING, &alert_level_str);
145 static void imm_alert_remove_condev(struct connected_device *condev)
147 struct imm_alert_adapter *ia;
152 ia = condev->adapter;
154 if (condev->callback_id && condev->device)
155 btd_device_remove_attio_callback(condev->device,
156 condev->callback_id);
159 btd_device_unref(condev->device);
161 ia->connected_devices = g_slist_remove(ia->connected_devices, condev);
165 /* condev can be NULL */
166 static void imm_alert_disc_cb(gpointer user_data)
168 struct connected_device *condev = user_data;
173 DBG("immediate alert remove device %p", condev->device);
175 imm_alert_emit_alert_signal(condev, NO_ALERT);
176 imm_alert_remove_condev(condev);
179 static uint8_t imm_alert_alert_lvl_write(struct attribute *a,
180 struct btd_device *device, gpointer user_data)
183 struct imm_alert_adapter *ia = user_data;
184 struct connected_device *condev = NULL;
189 condev = find_connected_device(ia, device);
192 DBG("Illegal alert level length");
197 if (value != NO_ALERT && value != MILD_ALERT && value != HIGH_ALERT) {
198 DBG("Illegal alert value");
202 /* Register a disconnect cb if the alert level is non-zero */
203 if (value != NO_ALERT && !condev) {
204 condev = g_new0(struct connected_device, 1);
205 condev->device = btd_device_ref(device);
206 condev->adapter = ia;
207 condev->callback_id = btd_device_add_attio_callback(device,
208 NULL, imm_alert_disc_cb, condev);
209 ia->connected_devices = g_slist_append(ia->connected_devices,
211 DBG("added connected dev %p", device);
214 if (value != NO_ALERT) {
215 condev->alert_level = value;
216 imm_alert_emit_alert_signal(condev, value);
220 * Emit NO_ALERT if the alert level was non-zero before. This is
221 * guaranteed when there's a condev.
223 if (value == NO_ALERT && condev)
224 imm_alert_disc_cb(condev);
226 DBG("alert level set to %d by device %p", value, device);
230 error("Set immediate alert level for dev %p", device);
231 /* remove alerts by erroneous devices */
232 imm_alert_disc_cb(condev);
236 void imm_alert_register(struct btd_adapter *adapter, DBusConnection *conn)
240 struct imm_alert_adapter *imadapter;
242 bt_uuid16_create(&uuid, IMMEDIATE_ALERT_SVC_UUID);
244 imadapter = g_new0(struct imm_alert_adapter, 1);
245 imadapter->adapter = adapter;
246 imadapter->conn = dbus_connection_ref(conn);
248 imm_alert_adapters = g_slist_append(imm_alert_adapters, imadapter);
250 /* Immediate Alert Service */
251 svc_added = gatt_service_add(adapter,
252 GATT_PRIM_SVC_UUID, &uuid,
253 /* Alert level characteristic */
254 GATT_OPT_CHR_UUID, ALERT_LEVEL_CHR_UUID,
256 ATT_CHAR_PROPER_WRITE_WITHOUT_RESP,
257 GATT_OPT_CHR_VALUE_CB, ATTRIB_WRITE,
258 imm_alert_alert_lvl_write, imadapter,
262 imm_alert_unregister(adapter);
266 DBG("Immediate Alert service added");
269 static void remove_condev_list_item(gpointer data, gpointer user_data)
271 struct connected_device *condev = data;
273 imm_alert_remove_condev(condev);
276 void imm_alert_unregister(struct btd_adapter *adapter)
278 struct imm_alert_adapter *imadapter;
280 imadapter = find_imm_alert_adapter(adapter);
284 g_slist_foreach(imadapter->connected_devices, remove_condev_list_item,
286 dbus_connection_unref(imadapter->conn);
288 imm_alert_adapters = g_slist_remove(imm_alert_adapters, imadapter);