tizen 2.3 release
[framework/connectivity/bluez.git] / profiles / proximity / reporter.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2011  Nokia Corporation
6  *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
7  *
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <stdbool.h>
30 #include <errno.h>
31
32 #include <glib.h>
33
34 #include <dbus/dbus.h>
35 #include <gdbus/gdbus.h>
36
37 #include "src/log.h"
38
39 #include "lib/uuid.h"
40 #include "src/dbus-common.h"
41 #include "src/error.h"
42 #include "src/adapter.h"
43 #include "src/device.h"
44 #include "src/profile.h"
45 #include "src/service.h"
46 #include "src/hcid.h"
47 #include "attrib/gattrib.h"
48 #include "attrib/att.h"
49 #include "attrib/gatt.h"
50 #include "attrib/att-database.h"
51 #include "src/attrib-server.h"
52
53 #include "reporter.h"
54 #include "linkloss.h"
55 #include "immalert.h"
56
57 struct reporter_adapter {
58         struct btd_adapter *adapter;
59         GSList *devices;
60 };
61
62 static GSList *reporter_adapters;
63
64 static int radapter_cmp(gconstpointer a, gconstpointer b)
65 {
66         const struct reporter_adapter *radapter = a;
67         const struct btd_adapter *adapter = b;
68
69         if (radapter->adapter == adapter)
70                 return 0;
71
72         return -1;
73 }
74
75 static struct reporter_adapter *
76 find_reporter_adapter(struct btd_adapter *adapter)
77 {
78         GSList *l = g_slist_find_custom(reporter_adapters, adapter,
79                                                                 radapter_cmp);
80         if (!l)
81                 return NULL;
82
83         return l->data;
84 }
85
86 const char *get_alert_level_string(uint8_t level)
87 {
88         switch (level) {
89         case NO_ALERT:
90                 return "none";
91         case MILD_ALERT:
92                 return "mild";
93         case HIGH_ALERT:
94                 return "high";
95         }
96
97         return "unknown";
98 }
99
100 static void register_tx_power(struct btd_adapter *adapter)
101 {
102         uint16_t start_handle, h;
103         const int svc_size = 4;
104         uint8_t atval[256];
105         bt_uuid_t uuid;
106
107         bt_uuid16_create(&uuid, TX_POWER_SVC_UUID);
108         start_handle = attrib_db_find_avail(adapter, &uuid, svc_size);
109         if (start_handle == 0) {
110                 error("Not enough free handles to register service");
111                 return;
112         }
113
114         DBG("start_handle=0x%04x", start_handle);
115
116         h = start_handle;
117
118         /* Primary service definition */
119         bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
120         att_put_u16(TX_POWER_SVC_UUID, &atval[0]);
121         attrib_db_add(adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);
122
123         /* Power level characteristic */
124         bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
125         atval[0] = ATT_CHAR_PROPER_READ | ATT_CHAR_PROPER_NOTIFY;
126         att_put_u16(h + 1, &atval[1]);
127         att_put_u16(POWER_LEVEL_CHR_UUID, &atval[3]);
128         attrib_db_add(adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5);
129
130         /* Power level value */
131         bt_uuid16_create(&uuid, POWER_LEVEL_CHR_UUID);
132         att_put_u8(0x00, &atval[0]);
133         attrib_db_add(adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 1);
134
135         /* Client characteristic configuration */
136         bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
137         atval[0] = 0x00;
138         atval[1] = 0x00;
139         attrib_db_add(adapter, h++, &uuid, ATT_NONE, ATT_NONE, atval, 2);
140
141         g_assert(h - start_handle == svc_size);
142 }
143
144 static gboolean property_get_link_loss_level(const GDBusPropertyTable *property,
145                                         DBusMessageIter *iter, void *data)
146 {
147         struct btd_device *device = data;
148         const char *level;
149
150         level = link_loss_get_alert_level(device);
151
152         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &level);
153
154         return TRUE;
155 }
156
157 static gboolean property_get_immediate_alert_level(
158                                         const GDBusPropertyTable *property,
159                                         DBusMessageIter *iter, void *data)
160 {
161         struct btd_device *device = data;
162         const char *level;
163
164         level = imm_alert_get_level(device);
165
166         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &level);
167
168         return TRUE;
169 }
170
171 static const GDBusPropertyTable reporter_device_properties[] = {
172         { "LinkLossAlertLevel", "s", property_get_link_loss_level },
173         { "ImmediateAlertLevel", "s", property_get_immediate_alert_level },
174         { }
175 };
176
177 static void unregister_reporter_device(gpointer data, gpointer user_data)
178 {
179         struct btd_device *device = data;
180         struct reporter_adapter *radapter = user_data;
181         const char *path = device_get_path(device);
182
183         DBG("unregister on device %s", path);
184
185         g_dbus_unregister_interface(btd_get_dbus_connection(), path,
186                                         PROXIMITY_REPORTER_INTERFACE);
187
188         radapter->devices = g_slist_remove(radapter->devices, device);
189         btd_device_unref(device);
190 }
191
192 static void register_reporter_device(struct btd_device *device,
193                                         struct reporter_adapter *radapter)
194 {
195         const char *path = device_get_path(device);
196
197         DBG("register on device %s", path);
198
199         g_dbus_register_interface(btd_get_dbus_connection(), path,
200                                         PROXIMITY_REPORTER_INTERFACE,
201                                         NULL, NULL, reporter_device_properties,
202                                         device, NULL);
203
204         btd_device_ref(device);
205         radapter->devices = g_slist_prepend(radapter->devices, device);
206 }
207
208 int reporter_device_probe(struct btd_service *service)
209 {
210         struct btd_device *device = btd_service_get_device(service);
211         struct reporter_adapter *radapter;
212         struct btd_adapter *adapter = device_get_adapter(device);
213
214         radapter = find_reporter_adapter(adapter);
215         if (!radapter)
216                 return -1;
217
218         register_reporter_device(device, radapter);
219
220         return 0;
221 }
222
223 void reporter_device_remove(struct btd_service *service)
224 {
225         struct btd_device *device = btd_service_get_device(service);
226         struct reporter_adapter *radapter;
227         struct btd_adapter *adapter = device_get_adapter(device);
228
229         radapter = find_reporter_adapter(adapter);
230         if (!radapter)
231                 return;
232
233         unregister_reporter_device(device, radapter);
234 }
235
236 int reporter_adapter_probe(struct btd_profile *p, struct btd_adapter *adapter)
237 {
238         struct reporter_adapter *radapter;
239
240         radapter = g_new0(struct reporter_adapter, 1);
241         radapter->adapter = adapter;
242
243         link_loss_register(adapter);
244         register_tx_power(adapter);
245         imm_alert_register(adapter);
246
247         reporter_adapters = g_slist_prepend(reporter_adapters, radapter);
248         DBG("Proximity Reporter for adapter %p", adapter);
249
250         return 0;
251 }
252
253 void reporter_adapter_remove(struct btd_profile *p,
254                                                 struct btd_adapter *adapter)
255 {
256         struct reporter_adapter *radapter = find_reporter_adapter(adapter);
257         if (!radapter)
258                 return;
259
260         g_slist_foreach(radapter->devices, unregister_reporter_device,
261                                                                 radapter);
262
263         link_loss_unregister(adapter);
264         imm_alert_unregister(adapter);
265
266         reporter_adapters = g_slist_remove(reporter_adapters, radapter);
267         g_free(radapter);
268 }