2 * Bluetooth-frwk low energy
4 * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Hocheol Seo <hocheol.seo@samsung.com>
7 * Chanyeol Park <chanyeol.park@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
25 #include<glib/gprintf.h>
30 #include "bt-common.h"
32 #define NUMBER_OF_FLAGS 10
34 GDBusConnection *g_conn;
37 static gboolean new_service = FALSE;
38 static gboolean new_char = FALSE;
39 static int serv_id = 1;
41 /* Introspection data for the service we are exporting */
42 static const gchar service_introspection_xml[] =
44 " <interface name='org.bluez.GattService1'>"
45 " <property type='s' name='UUID' access='read'>"
47 " <property type='s' name='Includes' access='read'>"
52 /* Introspection data for the characteristics we are exporting */
53 static const gchar characteristics_introspection_xml[] =
55 " <interface name='org.bluez.GattCharacteristic1'>"
56 " <property type='s' name='UUID' access='read'>"
58 " <property type='o' name='Service' access='read'>"
60 " <property type='ay' name='Value' access='readwrite'>"
62 " <property type='as' name='Flags' access='read'>"
67 /* Introspection data for the descriptor we are exporting */
68 static const gchar descriptor_introspection_xml[] =
70 " <interface name='org.bluez.GattDescriptor1'>"
71 " <property type='s' name='UUID' access='read'>"
73 " <property type='o' name='Characteristic' access='read'>"
75 " <property type='ay' name='Value' access='readwrite'>"
77 " <property type='s' name='Permissions' access='read'>"
82 static const gchar manager_introspection_xml[] =
84 " <interface name='org.freedesktop.DBus.ObjectManager'>"
85 " <method name='GetManagedObjects'>"
86 " <arg type='a{oa{sa{sv}}}' name='object_paths_interfaces_and_properties' direction='out'/>"
91 static const gchar properties_introspection_xml[] =
93 " <interface name='org.freedesktop.DBus.Properties'>"
94 " <method name='Set'>"
95 " <arg type='s' name='interface' direction='in'/>"
96 " <arg type='s' name='name' direction='in'/>"
97 " <arg type='v' name='value' direction='in'/>"
102 struct gatt_service_info {
109 gboolean is_svc_registered;
112 struct gatt_char_info {
117 gchar *char_flags[NUMBER_OF_FLAGS];
123 struct gatt_desc_info {
131 static GSList *gatt_services = NULL;
133 #define BT_GATT_SERVICE_NAME "org.frwk.gatt_service"
134 #define BT_GATT_SERVICE_PATH "/org/frwk/gatt_service"
136 #define GATT_SERV_OBJECT_PATH "/service"
138 #define GATT_MNGR_INTERFACE "org.bluez.GattManager1"
139 #define GATT_SERV_INTERFACE "org.bluez.GattService1"
140 #define GATT_CHAR_INTERFACE "org.bluez.GattCharacteristic1"
141 #define GATT_DESC_INTERFACE "org.bluez.GattDescriptor1"
143 static GDBusProxy *manager_gproxy = NULL;
145 static void __bt_gatt_manager_method_call(GDBusConnection *connection,
147 const gchar *object_path,
148 const gchar *interface_name,
149 const gchar *method_name,
150 GVariant *parameters,
151 GDBusMethodInvocation *invocation,
154 if (g_strcmp0(method_name, "GetManagedObjects") == 0) {
156 BT_DBG("Getting values for service, chars and descriptors");
157 GVariantBuilder *builder;
159 builder = g_variant_builder_new(
160 G_VARIANT_TYPE("a{oa{sa{sv}}}"));
162 /* Prepare inner builder for GattService1 interface */
164 GVariantBuilder *svc_builder = NULL;
165 GVariantBuilder *inner_builder = NULL;
167 GSList *l1 = g_slist_last(gatt_services);
168 struct gatt_service_info *serv_info = l1->data;
169 if (serv_info == NULL) {
170 BT_ERR("service info value is NULL");
171 g_dbus_method_invocation_return_value(invocation, NULL);
175 /* Prepare inner builder for GattService1 interface */
176 BT_DBG("Creating builder for service");
177 svc_builder = g_variant_builder_new(
178 G_VARIANT_TYPE("a{sa{sv}}"));
179 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
181 g_variant_builder_add(inner_builder, "{sv}", "UUID",
182 g_variant_new_string(serv_info->service_uuid));
184 g_variant_builder_add(svc_builder, "{sa{sv}}",
188 g_variant_builder_add(builder, "{oa{sa{sv}}}",
189 serv_info->serv_path,
192 /* Prepare inner builder for GattCharacteristic1 interface */
194 GSList *l2 = serv_info->char_data;
195 BT_DBG("Creating builder for characteristics \n");
198 BT_DBG("characteristic data is NULL");
200 for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
202 GVariantBuilder *char_builder = NULL;
203 GVariantBuilder *inner_builder = NULL;
204 GVariantBuilder *builder1 = NULL;
205 GVariantBuilder *builder2 = NULL;
206 GVariant *char_val = NULL;
207 GVariant *flags_val = NULL;
210 char_builder = g_variant_builder_new(
213 inner_builder = g_variant_builder_new(
217 struct gatt_char_info *char_info = l2->data;
218 if (char_info == NULL) {
219 BT_ERR("char_info is NULL");
224 g_variant_builder_add(inner_builder, "{sv}", "UUID",
225 g_variant_new_string(char_info->char_uuid));
227 g_variant_builder_add(inner_builder, "{sv}", "Service",
228 g_variant_new("o", serv_info->serv_path));
230 builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
232 if(char_info->char_value != NULL) {
233 for (i = 0; i < char_info->value_length; i++) {
234 g_variant_builder_add(builder1, "y",
235 char_info->char_value[i]);
237 char_val = g_variant_new("ay", builder1);
238 g_variant_builder_add(inner_builder, "{sv}",
242 builder2 = g_variant_builder_new(G_VARIANT_TYPE("as"));
244 for (i = 0; i < char_info->flags_length; i++) {
245 g_variant_builder_add(builder2, "s",
246 char_info->char_flags[i]);
249 flags_val = g_variant_new("as", builder2);
250 g_variant_builder_add(inner_builder, "{sv}", "Flags",
253 g_variant_builder_add(char_builder, "{sa{sv}}",
254 GATT_CHAR_INTERFACE , inner_builder);
255 g_variant_builder_add(builder, "{oa{sa{sv}}}",
256 char_info->char_path, char_builder);
258 /*Prepare inner builder for GattDescriptor1 interface*/
260 GSList *l3 = char_info->desc_data;
263 BT_DBG("descriptor data is NULL");
265 for (l3 = char_info->desc_data; l3 != NULL; l3 = l3->next) {
267 BT_DBG("Creating builder for descriptor \n");
269 GVariantBuilder *desc_builder = NULL;
270 GVariantBuilder *inner_builder = NULL;
271 GVariantBuilder *builder1 = NULL;
272 GVariant *desc_val = NULL;
274 desc_builder = g_variant_builder_new(
277 inner_builder = g_variant_builder_new(
281 struct gatt_desc_info *desc_info = l3->data;
282 if (desc_info == NULL) {
283 BT_ERR("desc_info is NULL");
288 g_variant_builder_add(inner_builder,
290 g_variant_new_string(
291 desc_info->desc_uuid));
294 g_variant_builder_add(inner_builder, "{sv}",
297 char_info->char_path));
300 builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
302 if(desc_info->desc_value != NULL) {
303 for (i = 0; i < desc_info->value_length; i++) {
304 g_variant_builder_add(builder1, "y",
305 desc_info->desc_value[i]);
307 desc_val = g_variant_new("ay", builder1);
308 g_variant_builder_add(inner_builder, "{sv}",
312 g_variant_builder_add(desc_builder, "{sa{sv}}",
316 g_variant_builder_add(builder, "{oa{sa{sv}}}",
317 desc_info->desc_path,
320 /*unref descriptor builder pointers*/
321 g_variant_builder_unref(builder1);
322 g_variant_builder_unref(inner_builder);
323 g_variant_builder_unref(desc_builder);
326 /*unref char builder pointers*/
327 g_variant_builder_unref(builder1);
328 g_variant_builder_unref(builder2);
329 g_variant_builder_unref(inner_builder);
330 g_variant_builder_unref(char_builder);
333 /*unref service builder pointers*/
334 g_variant_builder_unref(inner_builder);
335 g_variant_builder_unref(svc_builder);
337 /* Return builder as method reply */
338 BT_DBG("Sending gatt service builder values to Bluez");
339 g_dbus_method_invocation_return_value(invocation,
346 static void __bt_gatt_prop_method_call(GDBusConnection *connection,
348 const gchar *object_path,
349 const gchar *interface_name,
350 const gchar *method_name,
351 GVariant *parameters,
352 GDBusMethodInvocation *invocation,
355 g_dbus_method_invocation_return_value(invocation, NULL);
358 gboolean __bt_gatt_emit_interface_removed(gchar *object_path, gchar *interface)
361 GError *error = NULL;
362 GVariantBuilder *array_builder;
364 array_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
365 g_variant_builder_init(array_builder, G_VARIANT_TYPE ("as"));
366 g_variant_builder_add(array_builder, "s", interface);
368 ret = g_dbus_connection_emit_signal(g_conn, NULL, "/",
369 "org.freedesktop.Dbus.Objectmanager",
371 g_variant_new ("(oas)",
372 object_path, array_builder),
377 /* dbus gives error cause */
378 BT_ERR("d-bus api failure: errcode[%x], message[%s]",
379 error->code, error->message);
380 g_clear_error(&error);
383 g_variant_builder_unref(array_builder);
388 static gboolean __bt_gatt_desc_set_property(GDBusConnection *connection,
389 const gchar *sender, const gchar *object_path,
390 const gchar *interface_name,
391 const gchar *property_name,
393 GError **err, gpointer user_data)
400 static gboolean __bt_gatt_char_set_property(GDBusConnection *connection,
401 const gchar *sender, const gchar *object_path,
402 const gchar *interface_name,
403 const gchar *property_name,
405 GError **err, gpointer user_data)
409 if (g_strcmp0(property_name, "Value") == 0) {
410 GVariantIter *var = NULL;
411 bt_gatt_char_value_t char_val = {0, };
412 bt_user_info_t *user_info = NULL;
415 g_variant_get(value, "ay", &var);
416 len = g_variant_get_size(var);
418 char_val.char_handle = object_path;
420 char_val.char_value = (guint8 *)malloc(len);
421 if (!char_val.char_value)
424 for (i = 0; i < len; i++)
425 g_variant_iter_loop(var, "y", &char_val.char_value[i]);
426 char_val.val_len = len;
427 user_info = _bt_get_user_data(BT_COMMON);
428 if (user_info != NULL)
430 BLUETOOTH_EVENT_GATT_SERVER_CHARACTERISTIC_VALUE_CHANGED,
431 BLUETOOTH_ERROR_NONE, &char_val,
432 user_info->cb, user_info->user_data);
434 bluetooth_gatt_update_characteristic(object_path, char_val.char_value,
437 free(char_val.char_value);
443 static GVariant *__bt_gatt_desc_get_property(GDBusConnection *connection,
444 const gchar *sender, const gchar *object_path,
445 const gchar *interface_name,
446 const gchar *property_name,
447 GError **error, gpointer user_data)
454 static GVariant *__bt_gatt_char_get_property(GDBusConnection *connection,
455 const gchar *sender, const gchar *object_path,
456 const gchar *interface_name,
457 const gchar *property_name,
458 GError **error, gpointer user_data)
465 static GVariant *__bt_gatt_serv_get_property(GDBusConnection *connection,
466 const gchar *sender, const gchar *object_path,
467 const gchar *interface_name,
468 const gchar *property_name,
469 GError **error, gpointer user_data)
476 static const GDBusInterfaceVTable desc_interface_vtable = {
478 __bt_gatt_desc_get_property,
479 __bt_gatt_desc_set_property
482 static const GDBusInterfaceVTable char_interface_vtable = {
484 __bt_gatt_char_get_property,
485 __bt_gatt_char_set_property,
488 static const GDBusInterfaceVTable serv_interface_vtable = {
490 __bt_gatt_serv_get_property,
494 static const GDBusInterfaceVTable manager_interface_vtable = {
495 __bt_gatt_manager_method_call,
500 static const GDBusInterfaceVTable properties_interface_vtable = {
501 __bt_gatt_prop_method_call,
506 static GDBusNodeInfo *__bt_gatt_create_method_node_info(
507 const gchar *introspection_data)
510 GDBusNodeInfo *node_info = NULL;
512 if (introspection_data == NULL)
515 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
518 BT_ERR("Unable to create node: %s", err->message);
524 static struct gatt_service_info *__bt_gatt_find_gatt_service_info(
525 const char *service_path)
529 for (l = gatt_services; l != NULL; l = l->next) {
530 struct gatt_service_info *info = l->data;
532 if (g_strcmp0(info->serv_path, service_path) == 0)
535 BT_ERR("Gatt service not found");
539 static struct gatt_char_info *__bt_gatt_find_gatt_char_info(
540 const char *service_path, const char *char_path)
544 for (l1 = gatt_services; l1 != NULL; l1 = l1->next) {
545 struct gatt_service_info *serv_info = l1->data;
547 if (g_strcmp0(serv_info->serv_path, service_path) == 0) {
549 for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
550 struct gatt_char_info *char_info = l2->data;
552 if (g_strcmp0(char_info->char_path, char_path)
556 BT_ERR("Gatt characteristic not found");
560 BT_ERR("Gatt service not found");
564 static struct gatt_desc_info *__bt_gatt_find_gatt_desc_info(
565 const char *serv_path, const char *char_path,
566 const char *desc_path)
568 GSList *l1, *l2, *l3;
570 for (l1 = gatt_services; l1 != NULL; l1 = l1->next) {
571 struct gatt_service_info *serv_info = l1->data;
573 if (g_strcmp0(serv_info->serv_path, serv_path) == 0) {
574 for (l2 = serv_info->char_data; l2 != NULL; l2 = l2->next) {
575 struct gatt_char_info *char_info = l2->data;
577 if (g_strcmp0(char_info->char_path, char_path)
579 for (l3 = char_info->desc_data; l3 != NULL; l3 = l3->next) {
580 struct gatt_desc_info *desc_info = l3->data;
581 if (g_strcmp0(desc_info->desc_path,
590 BT_ERR("Gatt descriptor not found");
595 static GDBusProxy *__bt_gatt_gdbus_init_manager_proxy(const gchar *service,
596 const gchar *path, const gchar *interface)
602 g_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM,
607 BT_ERR("Unable to connect to gdbus: %s", err->message);
613 proxy = g_dbus_proxy_new_sync(g_conn,
614 G_DBUS_PROXY_FLAGS_NONE, NULL,
616 interface, NULL, &err);
620 BT_ERR("Unable to create proxy: %s", err->message);
625 manager_gproxy = proxy;
630 static GDBusProxy *__bt_gatt_gdbus_get_manager_proxy(const gchar *service,
631 const gchar *path, const gchar *interface)
633 return (manager_gproxy) ? manager_gproxy :
634 __bt_gatt_gdbus_init_manager_proxy(service,
638 static gboolean __bt_gatt_export_properties_method(const char *svc_path)
641 GDBusNodeInfo *prop_info;
642 GError *error = NULL;
643 struct gatt_service_info *svc_info;
645 BT_DBG("svc_path %s", svc_path);
646 svc_info = __bt_gatt_find_gatt_service_info(svc_path);
649 BT_ERR("Unable to find service info");
653 /* Register ObjectManager interface */
654 prop_info = __bt_gatt_create_method_node_info(
655 properties_introspection_xml);
657 if (prop_info == NULL) {
658 BT_ERR("failed to get node info");
662 prop_id = g_dbus_connection_register_object(g_conn, svc_path,
663 prop_info->interfaces[0],
664 &properties_interface_vtable,
668 BT_ERR("failed to register: %s", error->message);
672 svc_info->prop_id = prop_id;
677 int bluetooth_gatt_convert_prop2string(
678 bt_gatt_characteristic_property_t properties,
679 char *char_properties[])
683 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_BROADCAST) {
684 char_properties[flag_count] = g_strdup("broadcast");
687 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ) {
688 char_properties[flag_count] = g_strdup("read");
691 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE_NO_RESPONSE) {
692 char_properties[flag_count] = g_strdup("write-without-response");
695 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE) {
696 char_properties[flag_count] = g_strdup("write");
699 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_NOTIFY) {
700 char_properties[flag_count] = g_strdup("notify");
703 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_INDICATE) {
704 char_properties[flag_count] = g_strdup("indicate");
707 if (properties & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_SIGNED_WRITE) {
708 char_properties[flag_count] = g_strdup("authenticated-signed-writes");
712 if (flag_count == 0) {
713 char_properties[flag_count] = g_strdup("read");
720 static void __bt_gatt_set_service_state(const char *service_path,
723 struct gatt_service_info *svc_info = NULL;
724 svc_info = __bt_gatt_find_gatt_service_info(service_path);
726 if (svc_info != NULL) {
727 BT_DBG("Updating the gatt service register state %d", state);
728 svc_info->is_svc_registered = state;
732 BT_DBG("gatt service not found");
735 static gboolean __bt_gatt_get_service_state(const char *service_path)
737 struct gatt_service_info *svc_info = NULL;
739 svc_info = __bt_gatt_find_gatt_service_info(service_path);
741 if (svc_info != NULL) {
742 BT_DBG("Return the state of the gatt service %d",
743 svc_info->is_svc_registered);
744 return svc_info->is_svc_registered;
747 BT_DBG("gatt service info is NULL");
751 void get_service_cb(GObject *object, GAsyncResult *res, gpointer user_data)
753 GError *error = NULL;
755 GVariantIter *iter = NULL;
756 const gchar *key = NULL;
757 GVariant *value = NULL;
758 gchar *service = NULL;
759 gchar *characteristic = NULL;
760 gchar *descriptor = NULL;
764 result = g_dbus_proxy_call_finish(manager_gproxy, res, &error);
766 if (result == NULL) {
767 /* dBUS-RPC is failed */
768 BT_ERR("Dbus-RPC is failed\n");
771 /* dBUS gives error cause */
772 BT_ERR("D-Bus API failure: errCode[%x], message[%s]\n",
773 error->code, error->message);
774 g_clear_error(&error);
777 char *char_cmp = NULL;
778 g_variant_get (result, "(a{sv})", &iter);
779 char_cmp = g_strdup_printf("Characteristic%d", n_char);
781 while (g_variant_iter_loop(iter, "{sv}", &key, &value)) {
782 if (g_strcmp0(key, "Service") == 0) {
783 service = g_variant_get_string(value, NULL);
784 BT_DBG("Service %s", service);
785 } else if (g_strcmp0(key, char_cmp) == 0) {
786 characteristic = g_variant_get_string(value, NULL);
788 char_cmp = g_strdup_printf("Characteristic%d", ++n_char);
789 BT_DBG("%s", characteristic);
790 } else if (g_strcmp0(key, "Descriptor") == 0) {
791 descriptor = g_variant_get_string(value, NULL);
792 BT_DBG("Descriptor %s", descriptor);
795 /* TODO: Store the service informationa and
796 * Send respponse to CAPI layer. */
798 g_variant_unref(result);
803 void register_service_cb(GObject *object, GAsyncResult *res, gpointer user_data)
805 BT_DBG("register_service_cb\n");
807 GError *error = NULL;
810 result = g_dbus_proxy_call_finish(manager_gproxy, res, &error);
812 if (result == NULL) {
813 /* dBUS-RPC is failed */
814 BT_ERR("Dbus-RPC is failed\n");
817 /* dBUS gives error cause */
818 BT_ERR("D-Bus API failure: errCode[%x], message[%s]\n",
819 error->code, error->message);
820 g_clear_error(&error);
825 void unregister_service_cb(GObject *object, GAsyncResult *res,
828 BT_DBG("unregister_service_cb\n");
830 GError *error = NULL;
833 result = g_dbus_proxy_call_finish(manager_gproxy, res, &error);
835 if (result == NULL) {
836 /* dBUS-RPC is failed */
837 BT_ERR("Dbus-RPC is failed\n");
840 /* dBUS gives error cause */
841 BT_ERR("D-Bus API failure: errCode[%x], message[%s]\n",
842 error->code, error->message);
843 g_clear_error(&error);
848 static int __bt_gatt_unregister_service(const char *service_path)
850 if (!__bt_gatt_get_service_state(service_path)) {
851 BT_DBG("service not registered \n");
852 return BLUETOOTH_ERROR_NOT_FOUND;
855 GDBusProxy *proxy = NULL;
857 proxy = __bt_gatt_gdbus_get_manager_proxy("org.bluez",
858 "/org/bluez", GATT_MNGR_INTERFACE);
861 return BLUETOOTH_ERROR_INTERNAL;
863 /* Async Call to Unregister Service */
864 g_dbus_proxy_call(proxy,
868 G_DBUS_CALL_FLAGS_NONE, -1,
870 (GAsyncReadyCallback) unregister_service_cb,
873 __bt_gatt_set_service_state(service_path, FALSE);
875 return BLUETOOTH_ERROR_NONE;
878 static GDBusConnection *__bt_gatt_get_gdbus_connection(void)
880 GDBusConnection *local_system_gconn = NULL;
883 if (g_conn == NULL) {
884 g_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
887 BT_ERR("Unable to connect to dbus: %s", err->message);
892 } else if (g_dbus_connection_is_closed(g_conn)) {
893 local_system_gconn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
895 if (!local_system_gconn) {
896 BT_ERR("Unable to connect to dbus: %s", err->message);
900 g_conn = local_system_gconn;
906 BT_EXPORT_API int bluetooth_gatt_init(void)
909 GDBusConnection *conn;
910 GDBusNodeInfo *obj_info;
911 GError *error = NULL;
913 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
914 BT_GATT_SERVICE_NAME,
915 G_BUS_NAME_OWNER_FLAGS_NONE,
916 NULL, NULL, NULL, NULL, NULL);
918 BT_DBG("owner_id is [%d]", owner_id);
922 conn = __bt_gatt_get_gdbus_connection();
924 BT_ERR("Unable to get connection");
925 return BLUETOOTH_ERROR_INTERNAL;
928 /* Register ObjectManager interface */
929 obj_info = __bt_gatt_create_method_node_info(
930 manager_introspection_xml);
932 if (obj_info == NULL) {
933 BT_ERR("failed to get node info");
934 return BLUETOOTH_ERROR_INTERNAL;
937 manager_id = g_dbus_connection_register_object(g_conn, "/",
938 obj_info->interfaces[0],
939 &manager_interface_vtable,
942 if (manager_id == 0) {
943 BT_ERR("failed to register: %s", error->message);
945 return BLUETOOTH_ERROR_INTERNAL;
948 return BLUETOOTH_ERROR_NONE;
951 BT_EXPORT_API int bluetooth_gatt_deinit()
953 /* Unown gdbus bus */
956 /* remove/unregister all services */
957 BT_DBG("removing all registered gatt service\n");
958 bluetooth_gatt_delete_services();
960 g_bus_unown_name(owner_id);
962 /* unregister the exported interface for object manager */
963 g_dbus_connection_unregister_object(g_conn,
966 BT_DBG("Gatt service deinitialized \n");
968 g_slist_free(gatt_services);
969 gatt_services = NULL;
971 return BLUETOOTH_ERROR_NONE;
974 return BLUETOOTH_ERROR_NOT_FOUND;
977 BT_EXPORT_API int bluetooth_gatt_add_service(const char *svc_uuid,
980 GError *error = NULL;
982 GDBusNodeInfo *node_info;
984 GVariantBuilder *builder = NULL;
985 GVariantBuilder *inner_builder = NULL;
986 struct gatt_service_info *serv_info = NULL;
988 node_info = __bt_gatt_create_method_node_info(
989 service_introspection_xml);
991 if (node_info == NULL)
992 return BLUETOOTH_ERROR_INTERNAL;
994 path = g_strdup_printf(GATT_SERV_OBJECT_PATH"%d", serv_id++);
995 BT_DBG("gatt service path is [%s]", path);
997 object_id = g_dbus_connection_register_object(g_conn, path,
998 node_info->interfaces[0],
999 &serv_interface_vtable,
1000 NULL, NULL, &error);
1002 if (object_id == 0) {
1003 BT_ERR("failed to register: %s", error->message);
1004 g_error_free(error);
1007 return BLUETOOTH_ERROR_INTERNAL;
1010 /* Add object_id/gatt service information; it's required at the time of
1011 * service unregister and Getmanagedobjects
1013 serv_info = g_new0(struct gatt_service_info, 1);
1015 serv_info->serv_path = g_strdup(path);
1016 serv_info->serv_id = object_id;
1017 serv_info->service_uuid = g_strdup(svc_uuid);
1018 serv_info->is_svc_registered = FALSE;
1020 gatt_services = g_slist_append(gatt_services, serv_info);
1022 /* emit interfacesadded signal here for service path */
1023 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
1024 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1026 g_variant_builder_add(inner_builder, "{sv}",
1027 "UUID", g_variant_new_string(svc_uuid));
1029 g_variant_builder_add(builder, "{sa{sv}}",
1030 GATT_SERV_INTERFACE, inner_builder);
1032 g_dbus_connection_emit_signal(g_conn, NULL, "/",
1033 "org.freedesktop.Dbus.ObjectManager",
1035 g_variant_new("(oa{sa{sv}})",
1041 *svc_path = g_strdup(path);
1044 g_variant_builder_unref(inner_builder);
1045 g_variant_builder_unref(builder);
1047 return BLUETOOTH_ERROR_NONE;
1050 BT_EXPORT_API int bluetooth_gatt_add_new_characteristic(
1051 const char *svc_path, const char *char_uuid,
1052 bt_gatt_characteristic_property_t properties,
1056 GError *error = NULL;
1058 GDBusNodeInfo *node_info;
1060 GVariantBuilder *builder = NULL;
1061 GVariantBuilder *inner_builder = NULL;
1062 struct gatt_service_info *serv_info = NULL;
1063 struct gatt_char_info *char_info = NULL;
1064 GVariantBuilder *builder2 = NULL;
1065 GVariant *flags_val = NULL;
1067 char *char_flags[NUMBER_OF_FLAGS];
1072 new_service = FALSE;
1075 BT_DBG("gatt svc_path path is [%s]", svc_path);
1076 serv_info = __bt_gatt_find_gatt_service_info(svc_path);
1077 if (serv_info == NULL)
1078 return BLUETOOTH_ERROR_INVALID_PARAM;
1080 node_info = __bt_gatt_create_method_node_info(
1081 characteristics_introspection_xml);
1083 if (node_info == NULL)
1084 return BLUETOOTH_ERROR_INTERNAL;
1086 path = g_strdup_printf("%s/characteristic%d", svc_path, char_id++);
1087 BT_DBG("gatt characteristic path is [%s]", path);
1089 object_id = g_dbus_connection_register_object(g_conn, path,
1090 node_info->interfaces[0],
1091 &char_interface_vtable,
1092 NULL, NULL, &error);
1094 if (object_id == 0) {
1095 BT_ERR("failed to register: %s", error->message);
1096 g_error_free(error);
1099 return BLUETOOTH_ERROR_INTERNAL;
1102 flag_count = bluetooth_gatt_convert_prop2string(properties, char_flags);
1104 char_info = g_new0(struct gatt_char_info, 1);
1106 char_info->char_path = g_strdup(path);
1107 char_info->char_id = object_id;
1108 char_info->char_uuid = g_strdup(char_uuid);
1110 for (i = 0; i < flag_count; i++) {
1111 char_info->char_flags[i] = char_flags[i];
1114 char_info->flags_length = flag_count;
1116 serv_info->char_data = g_slist_append(serv_info->char_data, char_info);
1118 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
1119 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1121 g_variant_builder_add(inner_builder, "{sv}", "UUID",
1122 g_variant_new("s", char_uuid));
1123 g_variant_builder_add(inner_builder, "{sv}", "Service",
1124 g_variant_new("o", svc_path));
1126 builder2 = g_variant_builder_new(G_VARIANT_TYPE("as"));
1128 for (i = 0; i < flag_count; i++) {
1129 g_variant_builder_add(builder2, "s", char_flags[i]);
1132 flags_val = g_variant_new("as", builder2);
1133 g_variant_builder_add(inner_builder, "{sv}", "Flags",
1136 g_variant_builder_add(builder, "{sa{sv}}",
1137 GATT_CHAR_INTERFACE,
1140 g_dbus_connection_emit_signal(g_conn, NULL, "/",
1141 "org.freedesktop.Dbus.ObjectManager",
1143 g_variant_new("(oa{sa{sv}})",
1147 *char_path = g_strdup(path);
1153 g_variant_builder_unref(inner_builder);
1154 g_variant_builder_unref(builder);
1155 g_variant_builder_unref(builder2);
1157 return BLUETOOTH_ERROR_NONE;
1160 BT_EXPORT_API int bluetooth_gatt_set_characteristic_value(
1161 const char *characteristic, const char *char_value,
1164 gchar **line_argv = NULL;
1165 char *serv_path = NULL;
1166 struct gatt_char_info *char_info = NULL;
1167 GVariantBuilder *builder1 = NULL;
1168 GVariantBuilder *builder = NULL;
1169 GVariantBuilder *inner_builder = NULL;
1170 GVariant *char_val = NULL;
1171 GError *error = NULL;
1174 line_argv = g_strsplit_set(characteristic, "/", 0);
1175 serv_path = g_strdup_printf("/%s", line_argv[1]);
1177 char_info = __bt_gatt_find_gatt_char_info(serv_path, characteristic);
1179 if (char_info == NULL) {
1180 g_strfreev(line_argv);
1181 return BLUETOOTH_ERROR_INVALID_PARAM;
1184 char_info->value_length = value_length;
1186 char_info->char_value = (char *)malloc(value_length);
1187 for (i = 0; i < value_length; i++)
1188 char_info->char_value[i] = char_value[i];
1190 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
1191 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1193 builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
1195 for (i = 0; i < value_length; i++) {
1196 g_variant_builder_add(builder1, "y", char_value[i]);
1199 char_val = g_variant_new("ay", builder1);
1200 g_variant_builder_add(inner_builder, "{sv}", "Value", char_val);
1202 g_variant_builder_add(builder, "{sa{sv}}",
1203 GATT_CHAR_INTERFACE,
1206 g_dbus_connection_emit_signal(g_conn, NULL, "/",
1207 "org.freedesktop.Dbus.ObjectManager",
1209 g_variant_new("(oa{sa{sv}})",
1210 char_info->char_path, builder),
1213 g_strfreev(line_argv);
1214 g_variant_builder_unref(inner_builder);
1215 g_variant_builder_unref(builder);
1216 g_variant_builder_unref(builder1);
1218 return BLUETOOTH_ERROR_NONE;
1221 BT_EXPORT_API int bluetooth_gatt_add_descriptor(
1222 const char *char_path, const char *desc_uuid,
1225 static int desc_id = 1;
1226 GError *error = NULL;
1228 GDBusNodeInfo *node_info;
1230 GVariantBuilder *builder = NULL;
1231 GVariantBuilder *inner_builder = NULL;
1232 struct gatt_char_info *char_info = NULL;
1233 struct gatt_desc_info *desc_info = NULL;
1234 gchar **line_argv = NULL;
1242 line_argv = g_strsplit_set(char_path, "/", 0);
1243 serv_path = g_strdup_printf("/%s", line_argv[1]);
1245 char_info = __bt_gatt_find_gatt_char_info(serv_path, char_path);
1249 if (char_info == NULL) {
1250 g_strfreev(line_argv);
1251 return BLUETOOTH_ERROR_INVALID_PARAM;
1254 node_info = __bt_gatt_create_method_node_info(
1255 descriptor_introspection_xml);
1257 if (node_info == NULL) {
1258 g_strfreev(line_argv);
1259 return BLUETOOTH_ERROR_INTERNAL;
1262 path = g_strdup_printf("%s/descriptor%d", char_path, desc_id++);
1263 BT_DBG("gatt descriptor path is [%s]", path);
1265 object_id = g_dbus_connection_register_object(g_conn, path,
1266 node_info->interfaces[0],
1267 &desc_interface_vtable,
1268 NULL, NULL, &error);
1270 if (object_id == 0) {
1271 BT_ERR("failed to register: %s", error->message);
1272 g_error_free(error);
1274 g_strfreev(line_argv);
1276 return BLUETOOTH_ERROR_INTERNAL;
1279 desc_info = g_new0(struct gatt_desc_info, 1);
1281 desc_info->desc_path = g_strdup(path);
1282 desc_info->desc_id = object_id;
1283 desc_info->desc_uuid = g_strdup(desc_uuid);
1285 char_info->desc_data = g_slist_append(char_info->desc_data, desc_info);
1287 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
1288 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1290 g_variant_builder_add(inner_builder, "{sv}", "UUID",
1291 g_variant_new("s", desc_uuid));
1292 g_variant_builder_add(inner_builder, "{sv}", "Characteristic",
1293 g_variant_new("o", char_path));
1295 g_variant_builder_add(builder, "{sa{sv}}",
1296 GATT_DESC_INTERFACE,
1299 g_dbus_connection_emit_signal(g_conn, NULL, "/",
1300 "org.freedesktop.Dbus.ObjectManager",
1302 g_variant_new("(oa{sa{sv}})",
1306 *desc_path = g_strdup(path);
1309 g_strfreev(line_argv);
1310 g_variant_builder_unref(inner_builder);
1311 g_variant_builder_unref(builder);
1313 return BLUETOOTH_ERROR_NONE;
1316 BT_EXPORT_API int bluetooth_gatt_set_descriptor_value(
1317 const char *desc_path, const char *desc_value,
1320 GError *error = NULL;
1321 GVariantBuilder *builder = NULL;
1322 GVariantBuilder *inner_builder = NULL;
1323 GVariantBuilder *builder1 = NULL;
1324 struct gatt_desc_info *desc_info = NULL;
1325 gchar **line_argv = NULL;
1327 GVariant *desc_val = NULL;
1328 char *serv_path = NULL;
1331 line_argv = g_strsplit_set(desc_path, "/", 0);
1332 serv_path = g_strdup_printf("/%s", line_argv[1]);
1333 char_path = g_strdup_printf("%s/%s", serv_path, line_argv[2]);
1335 desc_info = __bt_gatt_find_gatt_desc_info(serv_path, char_path, desc_path);
1337 if (desc_info == NULL) {
1338 g_strfreev(line_argv);
1339 return BLUETOOTH_ERROR_INVALID_PARAM;
1342 desc_info->desc_value = (char *)malloc(value_length);
1344 for (i = 0; i < value_length; i++)
1345 desc_info->desc_value[i] = desc_value[i];
1347 desc_info->value_length = value_length;
1349 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sa{sv}}"));
1350 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1352 builder1 = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
1354 for (i = 0; i < value_length; i++) {
1355 g_variant_builder_add(builder1, "y", desc_value[i]);
1357 desc_val = g_variant_new("ay", builder1);
1358 g_variant_builder_add(inner_builder, "{sv}", "Value", desc_val);
1360 g_variant_builder_add(builder, "{sa{sv}}",
1361 GATT_DESC_INTERFACE,
1364 g_dbus_connection_emit_signal(g_conn, NULL, "/",
1365 "org.freedesktop.Dbus.ObjectManager",
1367 g_variant_new("(oa{sa{sv}})",
1368 desc_info->desc_path, builder),
1371 g_strfreev(line_argv);
1372 g_variant_builder_unref(inner_builder);
1373 g_variant_builder_unref(builder);
1374 g_variant_builder_unref(builder1);
1376 return BLUETOOTH_ERROR_NONE;
1379 int bluetooth_gatt_get_service(const char *svc_uuid)
1381 GDBusProxy *proxy = NULL;
1384 proxy = __bt_gatt_gdbus_get_manager_proxy("org.bluez",
1385 "/org/bluez", GATT_MNGR_INTERFACE);
1387 return BLUETOOTH_ERROR_INTERNAL;
1389 uuid = g_strdup(svc_uuid);
1391 g_dbus_proxy_call(proxy,
1393 g_variant_new("(s)",
1395 G_DBUS_CALL_FLAGS_NONE, -1,
1397 (GAsyncReadyCallback) get_service_cb,
1402 return BLUETOOTH_ERROR_NONE;
1405 BT_EXPORT_API int bluetooth_gatt_register_service(
1406 const char *svc_path)
1408 GDBusProxy *proxy = NULL;
1411 if (__bt_gatt_get_service_state(svc_path)) {
1412 BT_DBG("service already registered \n");
1413 return BLUETOOTH_ERROR_NONE;
1416 if (!__bt_gatt_export_properties_method(svc_path)) {
1417 BT_ERR("Failed to export Object manager method");
1418 return BLUETOOTH_ERROR_INTERNAL;
1421 proxy = __bt_gatt_gdbus_get_manager_proxy("org.bluez",
1422 "/org/bluez", GATT_MNGR_INTERFACE);
1424 return BLUETOOTH_ERROR_INTERNAL;
1426 path = g_strdup(svc_path);
1428 g_dbus_proxy_call(proxy,
1430 g_variant_new("(oa{sv})",
1432 G_DBUS_CALL_FLAGS_NONE, -1,
1434 (GAsyncReadyCallback) register_service_cb,
1437 __bt_gatt_set_service_state(svc_path, TRUE);
1441 return BLUETOOTH_ERROR_NONE;
1444 BT_EXPORT_API int bluetooth_gatt_delete_services(void)
1447 int error = BLUETOOTH_ERROR_NONE;
1451 for (l = gatt_services; l != NULL; l = l->next) {
1452 struct gatt_service_info *info = l->data;
1453 BT_DBG("svc_path is %s", info->serv_path);
1454 if (bluetooth_gatt_unregister_service(info->serv_path)
1455 != BLUETOOTH_ERROR_NONE) {
1456 error = BLUETOOTH_ERROR_INTERNAL;
1457 BT_DBG(" Error in removing service %s \n",
1461 BT_DBG(" All services removed successfully.\n ");
1464 BT_DBG(" There are no registered services.\n ");
1467 g_slist_free(gatt_services);
1468 gatt_services = NULL;
1471 if (error != BLUETOOTH_ERROR_NONE)
1474 return BLUETOOTH_ERROR_NONE;
1477 BT_EXPORT_API int bluetooth_gatt_update_characteristic(
1478 const char *char_path, const char* char_value,
1481 GVariantBuilder *outer_builder;
1482 GVariantBuilder *inner_builder;
1483 GVariantBuilder *invalidated_builder;
1484 GVariant *update_value = NULL;
1485 GError *error = NULL;
1486 gboolean ret = FALSE;
1487 int err = BLUETOOTH_ERROR_NONE;
1489 gchar **line_argv = NULL;
1490 gchar *serv_path = NULL;
1492 line_argv = g_strsplit_set(char_path, "/", 0);
1493 serv_path = g_strdup_printf("/%s", line_argv[1]);
1495 if (!__bt_gatt_get_service_state(serv_path)) {
1496 BT_DBG("service not registered for this characteristic \n");
1497 g_strfreev(line_argv);
1499 return BLUETOOTH_ERROR_INTERNAL;
1503 outer_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1504 invalidated_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
1506 inner_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
1507 for (i = 0; i < value_length; i++) {
1508 g_variant_builder_add(inner_builder, "y", char_value[i]);
1511 update_value = g_variant_new("ay", inner_builder);
1513 outer_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
1514 g_variant_builder_add(outer_builder, "{sv}", "Value",
1517 BT_DBG("Updating characteristic value \n");
1518 ret = g_dbus_connection_emit_signal(g_conn, NULL,
1520 "org.freedesktop.DBus.Properties",
1521 "PropertiesChanged",
1522 g_variant_new("(sa{sv}as)",
1523 "org.bluez.GattCharacteristic1",
1524 outer_builder, invalidated_builder),
1528 if (error != NULL) {
1529 BT_ERR("D-Bus API failure: errCode[%x], \
1531 error->code, error->message);
1532 g_clear_error(&error);
1534 err = BLUETOOTH_ERROR_INTERNAL;
1537 g_strfreev(line_argv);
1538 g_variant_builder_unref(inner_builder);
1539 g_variant_builder_unref(outer_builder);
1540 g_variant_builder_unref(invalidated_builder);
1545 BT_EXPORT_API int bluetooth_gatt_unregister_service(const char *svc_path)
1548 struct gatt_service_info *svc_info;
1550 int err = BLUETOOTH_ERROR_NONE;
1553 BT_DBG("svc_path %s", svc_path);
1554 svc_info = __bt_gatt_find_gatt_service_info(svc_path);
1557 BT_ERR("Unable to find service info");
1558 return BLUETOOTH_ERROR_NOT_FOUND;
1561 err = __bt_gatt_unregister_service(svc_path);
1562 if (err != BLUETOOTH_ERROR_NONE) {
1563 BT_DBG("Could not unregister application");
1567 for (l = svc_info->char_data; l != NULL; l = l->next) {
1568 struct gatt_char_info *char_info = l->data;
1570 for (l1 = char_info->desc_data; l1 != NULL; l1 = l1->next) {
1571 struct gatt_desc_info *desc_info = l1->data;
1573 ret = g_dbus_connection_unregister_object(g_conn,
1574 desc_info->desc_id);
1576 __bt_gatt_emit_interface_removed(
1577 desc_info->desc_path,
1578 GATT_DESC_INTERFACE);
1580 err = BLUETOOTH_ERROR_INTERNAL;
1583 ret = g_dbus_connection_unregister_object(g_conn,
1584 char_info->char_id);
1586 __bt_gatt_emit_interface_removed(char_info->char_path,
1587 GATT_CHAR_INTERFACE);
1589 err = BLUETOOTH_ERROR_INTERNAL;
1592 ret = g_dbus_connection_unregister_object(g_conn, svc_info->serv_id);
1594 __bt_gatt_emit_interface_removed(svc_info->serv_path,
1595 GATT_SERV_INTERFACE);
1597 err = BLUETOOTH_ERROR_INTERNAL;
1600 ret = g_dbus_connection_unregister_object(g_conn, svc_info->prop_id);
1602 BT_DBG("Unregistered the service on properties interface");
1605 for (tmp = gatt_services; tmp != NULL; tmp = tmp->next) {
1606 struct gatt_service_info *info = tmp->data;
1608 if (g_strcmp0(info->serv_path, svc_path) == 0) {
1609 g_slist_delete_link(gatt_services, tmp->data);
1613 new_service = FALSE;
1615 if (gatt_services->next == NULL)