--- /dev/null
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
+*.[oa]
+*~
+build-stamp
+cmake_build_tmp
+configure-stamp
+.project
+.cproject
+.settings
--- /dev/null
+Danny Jeongseok Seo <s.seo@samsung.com>
+Misun Kim <ms0123.kim@samsung.com>
+Sanghoon Cho <sanghoon80.cho@samsung.com>
+Kyoungyoup Park <gynaru.park@samsung.com>
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(weconn)
+
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+SET(LIBDIR "${PREFIX}/lib")
+SET(INCLUDEDIR "${PREFIX}/include")
+SET(PKGCONFIGDIR "${PREFIX}/lib/pkgconfig" CACHE PATH PKGCONFIGDIR)
+SET(INTROSPECTION "${CMAKE_SOURCE_DIR}/introspection")
+SET(WECONNLIB "${LIBDIR}/${PROJECT_NAME}")
+SET(BINDIR "${PREFIX}/sbin")
+SET(main_PROGRAM "weconnd")
+
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(pkgs REQUIRED
+ dlog
+ vconf
+ gio-2.0
+ glib-2.0
+ gio-unix-2.0
+ alarm-service
+ sap-client-stub-api
+ capi-appfw-application
+ capi-network-bluetooth
+ capi-system-info
+)
+
+FOREACH(flag ${pkgs_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/include/)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -Wall -Werror -Wextra -fvisibility=hidden -fdata-sections -ffunction-sections -Wl,--gc-sections")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-parameter -Wno-missing-field-initializers -Wdeclaration-after-statement -Wmissing-declarations")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-local-typedefs -Wcast-align -Wconversion")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed -Wl,-z,nodelete")
+
+ADD_DEFINITIONS("-DVERSION=\"${VERSION}\"")
+ADD_DEFINITIONS("-DEXPORT_API=__attribute__((visibility(\"default\")))")
+ADD_DEFINITIONS("-DWECONN_PLUGIN_PATH=\"${WECONNLIB}\"")
+
+MESSAGE(${CMAKE_C_FLAGS})
+MESSAGE(${pkgs_LDFLAGS})
+
+REMOVE_DEFINITIONS("-DLOG_TAG=\"CAPI_NETWORK_WECONN\"")
+ADD_DEFINITIONS("-DLOG_TAG=\"WECONN\"")
+
+
+SET(SRCS
+ src/dbus.c
+ src/main.c
+ src/util.c
+ src/error.c
+ src/driver.c
+ src/object.c
+ src/service.c
+ src/technology.c
+ src/control/control.c
+)
+
+CONFIGURE_FILE(client/include/weconn_type.h include/weconn_type.h COPYONLY)
+
+ADD_CUSTOM_COMMAND(
+ WORKING_DIRECTORY
+ OUTPUT ${CMAKE_BINARY_DIR}/generated-code.c
+ COMMAND gdbus-codegen --interface-prefix net.weconn. --generate-c-code generated-code --c-namespace weconn --c-generate-object-manager --generate-docbook generated-docs
+ ${INTROSPECTION}/service.xml
+ ${INTROSPECTION}/technology.xml
+ COMMENT "Generating GDBus .c/.h")
+
+ADD_EXECUTABLE(${main_PROGRAM} ${SRCS} ${CMAKE_BINARY_DIR}/generated-code.c)
+TARGET_LINK_LIBRARIES(${main_PROGRAM} ${pkgs_LDFLAGS} "-ldl -L${CMAKE_BINARY_DIR}")
+
+INSTALL(TARGETS ${main_PROGRAM} DESTINATION ${BINDIR})
+
+
+# Wearable device connection controller plugins
+ADD_SUBDIRECTORY(plugins)
+
+# Wearable device connection controller API library in TIZEN C API (Development)
+ADD_SUBDIRECTORY(client)
+
+# Wearable connection manager API sample
+ADD_SUBDIRECTORY(test)
--- /dev/null
+Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
--- /dev/null
+SET(CLIENT "weconn")
+
+REMOVE_DEFINITIONS("-DLOG_TAG=\"WECONN\"")
+ADD_DEFINITIONS("-DLOG_TAG=\"CAPI_NETWORK_WECONN\"")
+
+
+CONFIGURE_FILE(../src/util.c src/util.c COPYONLY)
+
+SET(CLIENT_SRCS
+ src/util.c
+ src/weconnection.c
+)
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include/)
+
+ADD_LIBRARY(${CLIENT} SHARED ${CLIENT_SRCS})
+TARGET_LINK_LIBRARIES(${CLIENT} ${pkgs_LDFLAGS})
+SET_TARGET_PROPERTIES(${CLIENT} PROPERTIES VERSION ${VERSION} SOVERSION 0 OUTPUT_NAME ${CLIENT})
+
+# pkgconfig file
+CONFIGURE_FILE(${CLIENT}.pc.in ${CLIENT}.pc @ONLY)
+
+# install
+INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ DESTINATION include/${CLIENT})
+INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${CLIENT}.pc DESTINATION ${LIBDIR}/pkgconfig)
+INSTALL(TARGETS ${CLIENT} DESTINATION ${LIBDIR})
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __WECONN_CLIENT_H__
+#define __WECONN_CLIENT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <tizen.h>
+
+#include "weconn_type.h"
+
+/**
+ * @addtogroup CAPI_WEARABLE_DEVICE_CONNECTION_MANAGER_MODULE
+ * @{
+ */
+
+/**
+ * @brief The wearable connection handle for all connection functions.
+ */
+typedef void *weconn_h;
+
+/**
+* @brief Called after weconn_connect_service() is completed.
+* @param[in] result The result
+* @param[in] user_data The user data passed from weconn_connect_service()
+* @pre weconn_connect_service() will invoke this callback function.
+* @see weconn_connect_service()
+*/
+typedef void (*weconn_connected_cb) (int result, void *user_data);
+
+/**
+ * @brief Creates a handle for managing wearable connections.
+ * @remarks @a handle must be released with weconn_destroy().
+ * @param[out] conn The handle of the wearable connection
+ * @return On success, 0 is returned. On error, -1 or -errno is returned.
+ * All the errno numbers specified by POSIX, the ISO C standard.
+ * @see weconn_destroy()
+ */
+int weconn_create(weconn_h *conn);
+
+/**
+ * @brief Destroys the wearable connection handle.
+ * @param[in] conn The handle of the wearable connection
+ * @return On success, 0 is returned. On error, -1 or -errno is returned.
+ * All the errno numbers specified by POSIX, the ISO C standard.
+ * @see weconn_create()
+ */
+int weconn_destroy(weconn_h conn);
+
+/**
+ * @brief Gets the wearable connection service state.
+ * @details The returned state is for the wearable connection service type.
+ * @param[in] conn The handle of the wearable connection
+ * @param[in] type The wearable connection service type
+ * @param[out] state The state of wearable connection service type
+ * @return On success, 0 is returned. On error, -1 or -errno is returned.
+ * All the errno numbers specified by POSIX, the ISO C standard.
+ */
+int weconn_get_service_state(weconn_h conn,
+ weconn_service_type_e type, weconn_service_state_e *state);
+
+/**
+ * @brief Gets the wearable device state.
+ * @details The returned state is for the connection device type.
+ * @param[in] conn The handle of the wearable connection
+ * @param[in] type The wearable connection device type
+ * @param[out] state The state of wearable connection device type
+ * @return On success, 0 is returned. On error, -1 or -errno is returned.
+ * All the errno numbers specified by POSIX, the ISO C standard.
+ */
+int weconn_get_device_state(weconn_h conn,
+ weconn_device_type_e type, weconn_device_state_e *state);
+
+/**
+ * @brief Connect a service..
+ * @param[in] conn The handle of the wearable connection
+ * @param[in] type The wearable connection service type
+ * @param[in] callback The callback function to be called.
+ * This can be NULL if you don't want to get the notification.
+ * @param[in] user_data The user data passed to the callback function
+ * @return On success, 0 is returned. On error, -1 or -errno is returned.
+ * All the errno numbers specified by POSIX, the ISO C standard.
+ */
+int weconn_connect_service(weconn_h conn, weconn_service_type_e type,
+ weconn_connected_cb callback, void *user_data);
+
+/**
+ * @brief Disconnect a service..
+ * @param[in] conn The handle of the wearable connection
+ * @param[in] type The wearable connection service type
+ * @param[in] callback The callback function to be called.
+ * This can be NULL if you don't want to get the notification.
+ * @param[in] user_data The user data passed to the callback function
+ * @return On success, 0 is returned. On error, -1 or -errno is returned.
+ * All the errno numbers specified by POSIX, the ISO C standard.
+ */
+int weconn_disconnect_service(weconn_h conn, weconn_service_type_e type,
+ weconn_connected_cb callback, void *user_data);
+
+/**
+ * @brief Called when the state of service is changed
+ * @param[out] state The state of service
+ * @param[out] user_data The user data passed from the callback
+ * registration function
+ * @see weconn_set_service_state_change_cb()
+ * @see weconn_unset_service_state_change_cb()
+ */
+typedef void(*weconn_service_state_changed_cb)
+ (weconn_service_state_e state, void *user_data);
+
+/**
+ * @brief Registers the callback called when the state of service is
+ * changed.
+ * @param[in] conn The handle of the wearable connection
+ * @param[in] callback The callback function to be called
+ * @param[in] type The wearable connection service type
+ * @param[in] user_data The user data passed from the callback
+ * registration function
+ * @return On success, 0 is returned. On error, -1 or -errno is returned.
+ * All the errno numbers specified by POSIX, the ISO C standard.
+ */
+int weconn_set_service_state_change_cb(weconn_h conn,
+ weconn_service_state_changed_cb callback,
+ weconn_service_type_e type, void *user_data);
+
+/**
+ * @brief Unregisters the callback called when the state of service is
+ * changed.
+ * @param[in] conn The handle of the wearable connection
+ * @param[in] type The wearable connection service type
+ * @return On success, 0 is returned. On error, -1 or -errno is returned.
+ * All the errno numbers specified by POSIX, the ISO C standard.
+ */
+int weconn_unset_service_state_change_cb(weconn_h conn,
+ weconn_service_type_e type);
+/**
+* @}
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_CLIENT_H__ */
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __WECONN_TYPE_H__
+#define __WECONN_TYPE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @addtogroup CAPI_WEARABLE_DEVICE_CONNECTION_ENUMERATION_TYPE
+ * @{
+ */
+
+/**
+ * @brief Enumerations of wearable connection service type.
+ */
+typedef enum
+{
+ /* Generic connectivity */
+ W_SERVICE_TYPE_HOST_TO_WEARABLE_CONNECTIVITY = 0x01,
+ /* Generic connectivity between host and wearable devices */
+ W_SERVICE_TYPE_INTERNET_CONNECTIVITY = 0x02,
+ /* Generic connectivity into the Internet accessibility */
+
+ /* Specific technology based connectivity */
+ W_SERVICE_TYPE_BT_HFP = 0x11, /* Bluetooth Hands-Free Profile */
+ W_SERVICE_TYPE_BT_SPP = 0x12, /* Bluetooth Serial Port Profile */
+ W_SERVICE_TYPE_BT_PAN = 0x13, /* Bluetooth Personal Area Network */
+ W_SERVICE_TYPE_BT_GATT = 0x14,
+ /* Bluetooth Generic Attribute Profile */
+ W_SERVICE_TYPE_CELLULAR = 0x15, /* Cellular Network */
+ W_SERVICE_TYPE_WIFI = 0x16, /* Wi-Fi Network */
+ W_SERVICE_TYPE_WIFI_P2P = 0x17, /* Wi-Fi P2P Network */
+ W_SERVICE_TYPE_WIFI_ADHOC = 0x18, /* Wi-Fi Ad-hoc Network */
+ W_SERVICE_TYPE_ETHERNET = 0x19, /* Cable Network */
+} weconn_service_type_e;
+
+/**
+ * @brief Enumerations of wearable connection service state.
+ */
+typedef enum
+{
+ W_SERVICE_STATE_DISCONNECTED = 0x01,
+ W_SERVICE_STATE_CONNECTING = 0x02,
+ W_SERVICE_STATE_CONNECTED = 0x03,
+ W_SERVICE_STATE_DISCONNECTING = 0x04,
+} weconn_service_state_e;
+
+/**
+ * @brief Enumerations of wearable connection device type.
+ */
+typedef enum
+{
+ W_DEVICE_TYPE_BT = 0x01, /* Bluetooth */
+ W_DEVICE_TYPE_CELLULAR = 0x02, /* Cellular */
+ W_DEVICE_TYPE_WIFI = 0x03, /* Wi-Fi */
+ W_DEVICE_TYPE_WIFI_P2P = 0x04, /* Wi-Fi P2P */
+ W_DEVICE_TYPE_WIFI_ADHOC = 0x05, /* Wi-Fi Ad-hoc */
+ W_DEVICE_TYPE_ETHERNET = 0x06, /* Cable */
+} weconn_device_type_e;
+
+/**
+ * @brief Enumerations of wearable connection device state.
+ */
+typedef enum
+{
+ W_DEVICE_STATE_DISABLED = 0x01,
+ W_DEVICE_STATE_ENABLED = 0x02,
+} weconn_device_state_e;
+
+/**
+* @}
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_TYPE_H__ */
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <glib.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <gio/gio.h>
+
+#include "log.h"
+#include "dbus.h"
+#include "util.h"
+#include "weconn.h"
+
+struct weconn_connection {
+ GDBusConnection *connection;
+ GCancellable *cancellable;
+
+ weconn_service_type_e connect_service_type;
+ weconn_connected_cb connected_callback;
+ void *connect_user_data;
+
+ weconn_service_type_e disconnect_service_type;
+ weconn_connected_cb disconnected_callback;
+ void *disconnect_user_data;
+
+ int ref_count;
+ bool lazy_destroy;
+};
+
+struct weconn_service_handle {
+ weconn_h conn;
+ weconn_service_state_changed_cb callback;
+ void *user_data;
+};
+
+static __thread void *handle_libweconn = NULL;
+static __thread GHashTable *weconn_handle_hash = NULL;
+
+static __thread GHashTable *wc_internet_service_con_changed_cb_hash = NULL;
+static __thread GHashTable *wc_wearable_service_con_changed_cb_hash = NULL;
+
+static __thread guint weconn_conn_subscribe_id_weconn_state = 0;
+
+static bool __weconn_check_handle_validity(weconn_h conn)
+{
+ struct weconn_connection *h;
+
+ if (!conn || !weconn_handle_hash)
+ return false;
+
+ h = g_hash_table_lookup(weconn_handle_hash, conn);
+ if (!h)
+ return false;
+
+ if (h->lazy_destroy)
+ return false;
+
+ return true;
+}
+
+static GDBusConnection *__weconn_call_ref(struct weconn_connection *h)
+{
+ if (h->lazy_destroy)
+ return NULL;
+
+ g_object_ref(h->connection);
+
+ __sync_fetch_and_add(&h->ref_count, 1);
+
+ return h->connection;
+}
+
+static void __weconn_call_unref(struct weconn_connection *h)
+{
+ __sync_synchronize();
+ if (h->ref_count < 1)
+ return;
+
+ g_object_unref(h->connection);
+
+ if (__sync_sub_and_fetch(&h->ref_count, 1) < 1 && h->lazy_destroy)
+ g_hash_table_remove(weconn_handle_hash, h);
+}
+
+static const char *__weconn_get_technology_path4service(
+ weconn_service_type_e service_type)
+{
+ switch (service_type) {
+ case W_SERVICE_TYPE_BT_HFP:
+ case W_SERVICE_TYPE_BT_SPP:
+ case W_SERVICE_TYPE_BT_PAN:
+ case W_SERVICE_TYPE_BT_GATT:
+ return WECONN_TECHNOLOGY_BLUETOOTH_PATH;
+ case W_SERVICE_TYPE_CELLULAR:
+ return WECONN_TECHNOLOGY_CELLULAR_PATH;
+ case W_SERVICE_TYPE_WIFI:
+ return WECONN_TECHNOLOGY_WIFI_PATH;
+ case W_SERVICE_TYPE_WIFI_P2P:
+ return WECONN_TECHNOLOGY_WIFI_P2P_PATH;
+ case W_SERVICE_TYPE_WIFI_ADHOC:
+ return WECONN_TECHNOLOGY_WIFI_ADHOC_PATH;
+ case W_SERVICE_TYPE_ETHERNET:
+ return WECONN_TECHNOLOGY_ETHERNET_PATH;
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static const char *__weconn_get_technology_path4device(
+ weconn_device_type_e device_type)
+{
+ switch (device_type) {
+ case W_DEVICE_TYPE_BT:
+ return WECONN_TECHNOLOGY_BLUETOOTH_PATH;
+ case W_DEVICE_TYPE_CELLULAR:
+ return WECONN_TECHNOLOGY_CELLULAR_PATH;
+ case W_DEVICE_TYPE_WIFI:
+ return WECONN_TECHNOLOGY_WIFI_PATH;
+ case W_DEVICE_TYPE_WIFI_P2P:
+ return WECONN_TECHNOLOGY_WIFI_P2P_PATH;
+ case W_DEVICE_TYPE_WIFI_ADHOC:
+ return WECONN_TECHNOLOGY_WIFI_ADHOC_PATH;
+ case W_DEVICE_TYPE_ETHERNET:
+ return WECONN_TECHNOLOGY_ETHERNET_PATH;
+ }
+
+ return NULL;
+}
+
+static GDBusConnection *__weconn_setup_dbus(void)
+{
+ GError *error = NULL;
+ GDBusConnection *connection = NULL;
+
+ connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+ if (!connection) {
+ ERR("Failed to get system bus %s", error->message);
+ g_error_free(error);
+ return NULL;
+ }
+
+ return connection;
+}
+
+static void __weconn_destroy_handle(gpointer data)
+{
+ g_free(data);
+
+ if (handle_libweconn && g_hash_table_size(weconn_handle_hash) < 1) {
+ dlclose(handle_libweconn);
+ handle_libweconn = NULL;
+ }
+}
+
+static void __weconn_bt_connection_response(struct weconn_connection *conn,
+ int result, gpointer user_data)
+{
+ struct weconn_connection *h = conn;
+ if (!h)
+ return;
+
+ h->connected_callback(result, h->connect_user_data);
+ h->connected_callback = NULL;
+ h->connect_service_type = 0;
+}
+
+static void __weconn_bt_disconnection_response(struct weconn_connection *conn,
+ int result, gpointer user_data)
+{
+ struct weconn_connection *h = conn;
+ if (!h)
+ return;
+
+ h->disconnected_callback(result, h->disconnect_user_data);
+ h->disconnected_callback = NULL;
+ h->disconnect_service_type = 0;
+}
+
+static void __weconn_connection_response(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ struct weconn_connection *h = NULL;
+ int *result;
+
+
+ h = (struct weconn_connection *)key;
+ if (!h)
+ return;
+
+ result = (int *)user_data;
+
+ if (h->connected_callback) {
+ switch (h->connect_service_type) {
+ case W_SERVICE_TYPE_BT_HFP:
+ case W_SERVICE_TYPE_BT_SPP:
+ case W_SERVICE_TYPE_BT_PAN:
+ case W_SERVICE_TYPE_BT_GATT:
+ __weconn_bt_connection_response(h, *result, user_data);
+ break;
+ case W_SERVICE_TYPE_CELLULAR:
+ break;
+ case W_SERVICE_TYPE_WIFI:
+ break;
+ case W_SERVICE_TYPE_WIFI_P2P:
+ break;
+ case W_SERVICE_TYPE_WIFI_ADHOC:
+ break;
+ case W_SERVICE_TYPE_ETHERNET:
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void __weconn_disconnection_response(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ struct weconn_connection *h = NULL;
+ int *result;
+
+
+ h = (struct weconn_connection *)key;
+ if (!h)
+ return;
+
+ result = (int *)user_data;
+
+ if (h->disconnected_callback) {
+ switch (h->disconnect_service_type) {
+ case W_SERVICE_TYPE_BT_HFP:
+ case W_SERVICE_TYPE_BT_SPP:
+ case W_SERVICE_TYPE_BT_PAN:
+ case W_SERVICE_TYPE_BT_GATT:
+ __weconn_bt_disconnection_response(h, *result, user_data);
+ break;
+ case W_SERVICE_TYPE_CELLULAR:
+ break;
+ case W_SERVICE_TYPE_WIFI:
+ break;
+ case W_SERVICE_TYPE_WIFI_P2P:
+ break;
+ case W_SERVICE_TYPE_WIFI_ADHOC:
+ break;
+ case W_SERVICE_TYPE_ETHERNET:
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void __weconn_pan_service_state_changed(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ weconn_h conn;
+ struct weconn_service_handle *h_service = NULL;
+ int *state = NULL;
+
+ conn = (weconn_h)key;
+ if (!conn)
+ return;
+
+ h_service = (struct weconn_service_handle *)value;
+ if (!h_service)
+ return;
+
+ state = (int *)user_data;
+ if (!state)
+ return;
+
+ if (h_service->callback) {
+ h_service->callback(*state, h_service->user_data);
+ }
+}
+
+static void __weconn_technology_signal_filter(GDBusConnection *conn,
+ const gchar *name, const gchar *path, const gchar *interface,
+ const gchar *sig, GVariant *param, gpointer user_data)
+{
+ const char *service;
+ int result;
+
+ if (g_strcmp0(sig, WECONN_TECHNOLOGY_SIGNAL_CONNECTION_RESULT) == 0) {
+ g_variant_get(param, "(si)", &service, &result);
+
+ if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_HFP), service) == 0) {
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_SPP), service) == 0) {
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_PAN), service) == 0) {
+ g_hash_table_foreach(weconn_handle_hash,
+ __weconn_connection_response, &result);
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_GATT), service) == 0) {
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_CELLULAR), service) == 0) {
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI), service) == 0) {
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI_P2P), service) == 0) {
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI_ADHOC), service) == 0) {
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_ETHERNET), service) == 0) {
+ }
+ } else if (g_strcmp0(sig, WECONN_TECHNOLOGY_SIGNAL_DISCONNECTION_RESULT) == 0) {
+ g_variant_get(param, "(si)", &service, &result);
+
+ if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_HFP), service) == 0) {
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_SPP), service) == 0) {
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_PAN), service) == 0) {
+ g_hash_table_foreach(weconn_handle_hash,
+ __weconn_disconnection_response, &result);
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_GATT), service) == 0) {
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_CELLULAR), service) == 0) {
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI), service) == 0) {
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI_P2P), service) == 0) {
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI_ADHOC), service) == 0) {
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_ETHERNET), service) == 0) {
+ }
+ } else if (g_strcmp0(sig, WECONN_TECHNOLOGY_SIGNAL_SERVICE_STATE_CHANGED) == 0) {
+ g_variant_get(param, "(si)", &service, &result);
+
+ if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_HFP), service) == 0) {
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_SPP), service) == 0) {
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_PAN), service) == 0) {
+ g_hash_table_foreach(wc_internet_service_con_changed_cb_hash,
+ __weconn_pan_service_state_changed, &result);
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_GATT), service) == 0) {
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_CELLULAR), service) == 0) {
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI), service) == 0) {
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI_P2P), service) == 0) {
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI_ADHOC), service) == 0) {
+ } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_ETHERNET), service) == 0) {
+ }
+ } else {
+ ERR("No handle signal(%s)", sig);
+ }
+}
+
+static bool __weconn_register_signal(void)
+{
+ GDBusConnection *connection = NULL;
+ guint id;
+
+ connection = __weconn_setup_dbus();
+ if (connection == NULL)
+ return false;
+
+ id = g_dbus_connection_signal_subscribe(
+ connection,
+ WECONN_SERVICE_DBUS,
+ WECONN_TECHNOLOGY_INTERFACE,
+ NULL,
+ NULL,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ __weconn_technology_signal_filter,
+ NULL,
+ NULL);
+ if (id == 0) {
+ ERR("Failed register signals (%d)", id);
+ return false;
+ }
+
+ weconn_conn_subscribe_id_weconn_state = id;
+
+ return true;
+}
+
+static void __weconn_deregister_signal(void)
+{
+ GDBusConnection *connection = NULL;
+
+ connection = __weconn_setup_dbus();
+ if (connection == NULL)
+ return;
+
+ g_dbus_connection_signal_unsubscribe(connection,
+ weconn_conn_subscribe_id_weconn_state);
+}
+
+EXPORT_API int weconn_create(weconn_h *conn)
+{
+ struct weconn_connection *h;
+
+ if (!conn || __weconn_check_handle_validity(*conn))
+ return -EINVAL;
+
+ if (!weconn_handle_hash) {
+ g_type_init();
+
+ weconn_handle_hash = g_hash_table_new_full(g_direct_hash,
+ g_direct_equal, NULL, __weconn_destroy_handle);
+ }
+
+ if (!handle_libweconn)
+ handle_libweconn = dlopen("/usr/lib/libweconn.so", RTLD_LAZY);
+
+ if (!wc_internet_service_con_changed_cb_hash)
+ wc_internet_service_con_changed_cb_hash = g_hash_table_new_full(
+ g_str_hash, g_str_equal, NULL, g_free);
+
+ if (!wc_wearable_service_con_changed_cb_hash)
+ wc_wearable_service_con_changed_cb_hash = g_hash_table_new_full(
+ g_str_hash, g_str_equal, NULL, g_free);
+
+ h = g_try_new0(struct weconn_connection, 1);
+ if (!h)
+ return -ENOMEM;
+
+ h->connection = __weconn_setup_dbus();
+ if (!h->connection) {
+ g_free(h);
+ return -EIO;
+ }
+
+ h->cancellable = g_cancellable_new();
+ *conn = (weconn_h)h;
+
+ g_hash_table_replace(weconn_handle_hash, *conn, *conn);
+
+ __weconn_register_signal();
+
+ return 0;
+}
+
+EXPORT_API int weconn_destroy(weconn_h conn)
+{
+ struct weconn_connection *h;
+
+ if (!__weconn_check_handle_validity(conn))
+ return -EINVAL;
+
+ h = (struct weconn_connection *)conn;
+ g_object_unref(h->connection);
+ g_cancellable_cancel(h->cancellable);
+
+ if (wc_internet_service_con_changed_cb_hash) {
+ g_hash_table_destroy(wc_internet_service_con_changed_cb_hash);
+ wc_internet_service_con_changed_cb_hash = NULL;
+ }
+
+ if (wc_wearable_service_con_changed_cb_hash) {
+ g_hash_table_destroy(wc_wearable_service_con_changed_cb_hash);
+ wc_wearable_service_con_changed_cb_hash = NULL;
+ }
+
+ __sync_synchronize();
+ if (h->ref_count > 0)
+ h->lazy_destroy = true;
+ else
+ g_hash_table_remove(weconn_handle_hash, conn);
+
+ __weconn_deregister_signal();
+
+ return 0;
+}
+
+EXPORT_API int weconn_get_service_state(weconn_h conn,
+ weconn_service_type_e type, weconn_service_state_e *state)
+{
+ GVariant *reply, *inner;
+ GError *error = NULL;
+ struct weconn_connection *h = (struct weconn_connection *)conn;
+ const char *service_type = NULL;
+ const char *value = NULL;
+ weconn_service_state_e value_e;
+ const char *technology_path = NULL;
+
+ if (!state || !__weconn_check_handle_validity(conn))
+ return -EINVAL;
+
+ service_type = wc_service_type_enum2string(type);
+ if (!service_type) {
+
+ /* TODO: please make more general to care all of technologies */
+
+ if (type == W_SERVICE_TYPE_HOST_TO_WEARABLE_CONNECTIVITY)
+ type = W_SERVICE_TYPE_BT_SPP;
+ else if (type == W_SERVICE_TYPE_INTERNET_CONNECTIVITY)
+ type = W_SERVICE_TYPE_BT_PAN;
+ else
+ return -EINVAL;
+
+ service_type = wc_service_type_enum2string(type);
+ }
+
+ technology_path = __weconn_get_technology_path4service(type);
+ if (!technology_path)
+ return -EINVAL;
+
+ reply = g_dbus_connection_call_sync(__weconn_call_ref(h),
+ WECONN_SERVICE_DBUS,
+ technology_path,
+ WECONN_TECHNOLOGY_INTERFACE,
+ "GetProperty",
+ g_variant_new("(s)", service_type),
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_REPLY_TIMEOUT,
+ h->cancellable,
+ &error);
+
+ __weconn_call_unref(h);
+
+ if (error) {
+ ERR("Failed to request (%s)", error->message);
+ g_error_free(error);
+
+ if (reply)
+ g_variant_unref(reply);
+
+ return -EIO;
+ }
+
+ if (!reply) {
+ ERR("Failed to request");
+ return -EIO;
+ }
+
+ g_variant_get(reply, "(v)", &inner);
+ value = g_variant_get_string(inner, NULL);
+ g_variant_unref(inner);
+
+ value_e = wc_service_state_string2enum(value);
+ g_variant_unref(reply);
+
+ if (value_e)
+ *state = value_e;
+ else
+ return -EIO;
+
+ return 0;
+}
+
+EXPORT_API int weconn_get_device_state(weconn_h conn,
+ weconn_device_type_e type, weconn_device_state_e *state)
+{
+ GVariant *reply, *inner;
+ GError *error = NULL;
+ struct weconn_connection *h = (struct weconn_connection *)conn;
+ const char *device_type = NULL;
+ const char *value = NULL;
+ weconn_device_state_e value_e;
+ const char *technology_path = NULL;
+
+ if (!state || !__weconn_check_handle_validity(conn))
+ return -EINVAL;
+
+ device_type = wc_device_type_enum2string(type);
+ if (!device_type)
+ return -EINVAL;
+
+ technology_path = __weconn_get_technology_path4device(type);
+ if (!technology_path)
+ return -EINVAL;
+
+ reply = g_dbus_connection_call_sync(__weconn_call_ref(h),
+ WECONN_SERVICE_DBUS,
+ technology_path,
+ WECONN_TECHNOLOGY_INTERFACE,
+ "GetProperty",
+ g_variant_new("(s)", device_type),
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_REPLY_TIMEOUT,
+ h->cancellable,
+ &error);
+
+ __weconn_call_unref(h);
+
+ if (error) {
+ ERR("Failed to request (%s)", error->message);
+ g_error_free(error);
+
+ if (reply)
+ g_variant_unref(reply);
+
+ return -EIO;
+ }
+
+ if (!reply) {
+ ERR("Failed to request");
+ return -EIO;
+ }
+
+ g_variant_get(reply, "(v)", &inner);
+ value = g_variant_get_string(inner, NULL);
+ g_variant_unref(inner);
+
+ value_e = wc_device_state_string2enum(value);
+ g_variant_unref(reply);
+
+ if (value_e)
+ *state = value_e;
+ else
+ return -EIO;
+
+ return 0;
+}
+
+EXPORT_API int weconn_connect_service(weconn_h conn,
+ weconn_service_type_e type, weconn_connected_cb callback,
+ void *user_data)
+{
+ int err = -EIO;
+ GVariant *reply;
+ GError *error = NULL;
+ struct weconn_connection *h = (struct weconn_connection *)conn;
+ const char *service_type = NULL;
+ const char *technology_path = NULL;
+
+ if (!__weconn_check_handle_validity(conn))
+ return -EINVAL;
+
+ if (h->connected_callback) {
+ DBG("connection is inprogress");
+ return -EINPROGRESS;
+ }
+
+ service_type = wc_service_type_enum2string(type);
+ if (!service_type) {
+ /* TODO: please make more general to care all of technologies */
+
+ if (type == W_SERVICE_TYPE_HOST_TO_WEARABLE_CONNECTIVITY)
+ type = W_SERVICE_TYPE_BT_SPP;
+ else if (type == W_SERVICE_TYPE_INTERNET_CONNECTIVITY)
+ type = W_SERVICE_TYPE_BT_PAN;
+ else
+ return -EINVAL;
+
+ service_type = wc_service_type_enum2string(type);
+ }
+
+ technology_path = __weconn_get_technology_path4service(type);
+ if (!technology_path)
+ return -EINVAL;
+
+ reply = g_dbus_connection_call_sync(__weconn_call_ref(h),
+ WECONN_SERVICE_DBUS,
+ technology_path,
+ WECONN_TECHNOLOGY_INTERFACE,
+ "Connect",
+ g_variant_new("(s)", service_type),
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_REPLY_TIMEOUT,
+ h->cancellable,
+ &error);
+
+ __weconn_call_unref(h);
+
+ if (error) {
+ ERR("Failed to request (%s)", error->message);
+ if (g_strrstr(error->message, "AlreadyConnected"))
+ err = -EISCONN;
+ else if (g_strrstr(error->message, "NotConnected"))
+ err = -ENOTCONN;
+ else if (g_strrstr(error->message, "InProgress"))
+ err = -EINPROGRESS;
+ else if (g_strrstr(error->message, "LostConnection"))
+ err = -EIO;
+
+ g_error_free(error);
+
+ if (reply)
+ g_variant_unref(reply);
+
+ return err;
+ }
+
+ if (!reply) {
+ ERR("Failed to request");
+ return err;
+ }
+
+ g_variant_unref(reply);
+
+ if (callback) {
+ h->connect_service_type = type;
+ h->connected_callback = callback;
+ if (user_data)
+ h->connect_user_data = user_data;
+ }
+
+ return 0;
+}
+
+EXPORT_API int weconn_disconnect_service(weconn_h conn,
+ weconn_service_type_e type, weconn_connected_cb callback,
+ void *user_data)
+{
+ int err = -EIO;
+ GVariant *reply;
+ GError *error = NULL;
+ struct weconn_connection *h = (struct weconn_connection *)conn;
+ const char *service_type = NULL;
+ const char *technology_path = NULL;
+
+ if (!__weconn_check_handle_validity(conn))
+ return -EINVAL;
+
+ if (h->disconnected_callback) {
+ DBG("disconnection is inprogress");
+ return -EINPROGRESS;
+ }
+
+ service_type = wc_service_type_enum2string(type);
+ if (!service_type) {
+
+ /* TODO: please make more general to care all of technologies */
+
+ if (type == W_SERVICE_TYPE_HOST_TO_WEARABLE_CONNECTIVITY)
+ type = W_SERVICE_TYPE_BT_SPP;
+ else if (type == W_SERVICE_TYPE_INTERNET_CONNECTIVITY)
+ type = W_SERVICE_TYPE_BT_PAN;
+ else
+ return -EINVAL;
+
+ service_type = wc_service_type_enum2string(type);
+ }
+
+ technology_path = __weconn_get_technology_path4service(type);
+ if (!technology_path)
+ return -EINVAL;
+
+ reply = g_dbus_connection_call_sync(__weconn_call_ref(h),
+ WECONN_SERVICE_DBUS,
+ technology_path,
+ WECONN_TECHNOLOGY_INTERFACE,
+ "Disconnect",
+ g_variant_new("(s)", service_type),
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_REPLY_TIMEOUT,
+ h->cancellable,
+ &error);
+
+ __weconn_call_unref(h);
+
+ if (error) {
+ ERR("Failed to request (%s)", error->message);
+ if (g_strrstr(error->message, "AlreadyConnected"))
+ err = -EISCONN;
+ else if (g_strrstr(error->message, "NotConnected"))
+ err = -ENOTCONN;
+
+ g_error_free(error);
+
+ if (reply)
+ g_variant_unref(reply);
+
+ return err;
+ }
+
+ if (!reply) {
+ ERR("Failed to request");
+ return err;
+ }
+
+ g_variant_unref(reply);
+
+ if (callback) {
+ h->disconnect_service_type = type;
+ h->disconnected_callback = callback;
+ if (user_data)
+ h->disconnect_user_data = user_data;
+ }
+
+ return 0;
+}
+
+EXPORT_API int weconn_set_service_state_change_cb(weconn_h conn,
+ weconn_service_state_changed_cb callback,
+ weconn_service_type_e type, void *user_data)
+{
+ struct weconn_service_handle *h_service = NULL;
+
+ if (!__weconn_check_handle_validity(conn) || callback == NULL)
+ return -EINVAL;
+
+ h_service = g_try_malloc0(sizeof(struct weconn_service_handle));
+ if (h_service == NULL)
+ return -EINVAL;
+
+ h_service->conn = conn;
+ h_service->callback = callback;
+ h_service->user_data = user_data;
+
+ switch (type) {
+ case W_SERVICE_TYPE_HOST_TO_WEARABLE_CONNECTIVITY:
+ g_hash_table_replace(wc_wearable_service_con_changed_cb_hash,
+ conn, h_service);
+ break;
+ case W_SERVICE_TYPE_INTERNET_CONNECTIVITY:
+ g_hash_table_replace(wc_internet_service_con_changed_cb_hash,
+ conn, h_service);
+ break;
+ case W_SERVICE_TYPE_BT_PAN:
+ case W_SERVICE_TYPE_BT_HFP:
+ case W_SERVICE_TYPE_BT_SPP:
+ case W_SERVICE_TYPE_BT_GATT:
+ case W_SERVICE_TYPE_CELLULAR:
+ case W_SERVICE_TYPE_WIFI:
+ case W_SERVICE_TYPE_WIFI_P2P:
+ case W_SERVICE_TYPE_WIFI_ADHOC:
+ case W_SERVICE_TYPE_ETHERNET:
+ default:
+ ERR("Not support service type (%d)", type);
+ g_free(h_service);
+ break;
+ }
+
+ return 0;
+}
+
+EXPORT_API int weconn_unset_service_state_change_cb(weconn_h conn,
+ weconn_service_type_e type)
+{
+ if (!__weconn_check_handle_validity(conn))
+ return -EINVAL;
+
+ switch (type) {
+ case W_SERVICE_TYPE_HOST_TO_WEARABLE_CONNECTIVITY:
+ g_hash_table_remove(wc_wearable_service_con_changed_cb_hash,
+ conn);
+ break;
+ case W_SERVICE_TYPE_INTERNET_CONNECTIVITY:
+ g_hash_table_remove(wc_internet_service_con_changed_cb_hash,
+ conn);
+ break;
+ case W_SERVICE_TYPE_BT_PAN:
+ case W_SERVICE_TYPE_BT_HFP:
+ case W_SERVICE_TYPE_BT_SPP:
+ case W_SERVICE_TYPE_BT_GATT:
+ case W_SERVICE_TYPE_CELLULAR:
+ case W_SERVICE_TYPE_WIFI:
+ case W_SERVICE_TYPE_WIFI_P2P:
+ case W_SERVICE_TYPE_WIFI_ADHOC:
+ case W_SERVICE_TYPE_ETHERNET:
+ default:
+ break;
+ }
+
+ return 0;
+}
--- /dev/null
+prefix=@PREFIX@
+exec_prefix=@PREFIX@
+libdir=@LIBDIR@
+includedir=@INCLUDEDIR@/weconn
+
+Name: weconn
+Description: Wearable device connection controller API library in TIZEN C API (Development)
+Requires: dlog glib-2.0 gobject-2.0
+Version: @VERSION@
+Libs: -L${libdir} -lweconn
+Cflags: -I${includedir}
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __WECONN_H__
+#define __WECONN_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_H__ */
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __WECONN_CONTROL_H__
+#define __WECONN_CONTROL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "log.h"
+#include "events.h"
+#include "object.h"
+
+#define PROP_CONTROL_TYPE_HOST 0x00
+#define PROP_CONTROL_TYPE_WEARABLE 0x01
+
+int wc_control_add_bearer(WcObject * wo_bearer);
+WcObject *wc_control_get_object(void);
+int wc_control_get_device_type(void);
+
+int control_init(void);
+void control_cleanup(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_CONTROL_H__ */
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __WECONN_DBUS_H__
+#define __WECONN_DBUS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <gio/gio.h>
+
+#include "conn.h"
+
+#define DBUS_REPLY_TIMEOUT (120 * 1000)
+
+#define WECONN_SERVICE_DBUS "net.weconn"
+#define WECONN_PATH_DBUS "/net/weconn"
+
+#define WECONN_SERVICE_INTERFACE WECONN_SERVICE_DBUS ".Service"
+#define WECONN_TECHNOLOGY_INTERFACE WECONN_SERVICE_DBUS ".Technology"
+
+#define WECONN_SERVICE_PATH WECONN_PATH_DBUS "/service"
+#define WECONN_TECHNOLOGY_PATH WECONN_PATH_DBUS "/technology"
+#define WECONN_TECHNOLOGY_BLUETOOTH_PATH WECONN_TECHNOLOGY_PATH "/bluetooth"
+#define WECONN_TECHNOLOGY_CELLULAR_PATH WECONN_TECHNOLOGY_PATH "/cellular"
+#define WECONN_TECHNOLOGY_WIFI_PATH WECONN_TECHNOLOGY_PATH "/wifi"
+#define WECONN_TECHNOLOGY_WIFI_P2P_PATH WECONN_TECHNOLOGY_PATH "/p2p"
+#define WECONN_TECHNOLOGY_WIFI_ADHOC_PATH WECONN_TECHNOLOGY_PATH "/adhoc"
+#define WECONN_TECHNOLOGY_ETHERNET_PATH WECONN_TECHNOLOGY_PATH "/ethernet"
+
+#define WECONN_TECHNOLOGY_SIGNAL_CONNECTION_RESULT "SignalConnectionResult"
+#define WECONN_TECHNOLOGY_SIGNAL_DISCONNECTION_RESULT "SignalDisconnectionResult"
+#define WECONN_TECHNOLOGY_SIGNAL_SERVICE_STATE_CHANGED "SignalServiceStateChanged"
+
+int dbus_init(GBusType bus_type, const char *bus_name, const char *obj_path,
+ void (*__init_cb)(void));
+void dbus_cleanup(void);
+
+GDBusConnection *dbus_get_connection(void);
+
+const char *dbus_name2path(const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_DBUS_H__ */
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __WECONN_DRIVER_H__
+#define __WECONN_DRIVER_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "object.h"
+
+int wc_bearer_driver_init(WcObject *wo, const char *desc_name);
+int wc_bearer_driver_activate(WcObject *wo, const char *desc_name);
+int wc_bearer_driver_deactivate(WcObject *wo, const char *desc_name);
+int wc_bearer_driver_connect(WcObject *wo, const char *address,
+ const char *desc_name);
+int wc_bearer_driver_disconnect(WcObject *wo, const char *desc_name);
+void wc_bearer_driver_exit(WcObject *wo, const char *desc_name);
+
+int driver_init(const char *driver_path);
+void driver_cleanup(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_DRIVER_H__ */
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __WECONN_ERROR_H__
+#define __WECONN_ERROR_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <gio/gio.h>
+
+void wc_error_add(const gchar *msg, ...);
+void wc_error_return(GDBusMethodInvocation *invocation);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_ERROR_H__ */
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __WECONN_EVENTSH__
+#define __WECONN_EVENTSH__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Generic property changed */
+#define WC_OBJECT_EVENT_PROPERTY_CHANGED "PropertiesChanged"
+
+/* Bearer events */
+#define WC_BEARER_EVENT_BT_CONNECTED_SPP "BtConnectedSpp"
+#define WC_BEARER_EVENT_BT_CONNECTED_GATT "BtConnectedGatt"
+#define WC_BEARER_EVENT_BT_CONNECTED_HFP "BtConnectedHfp"
+#define WC_BEARER_EVENT_BT_CONNECTED_PAN "BtConnectedPan"
+
+/* Technology events */
+
+/* Service events */
+
+/* Bearer (plug-in) events */
+#define WC_OBJECT_EVENT_BEARER_ENABLED "BearerEnabled"
+#define WC_OBJECT_EVENT_BEARER_DISABLED "BearerDisabled"
+
+/* eSAP events */
+/* For example, to send data uses WC_OBJECT_EVENT_SAP_SEND_DATA
+ * wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, data);
+ * to receive data uses
+ * WC_OBJECT_EVENT_SAP_RECEIVE_DATA[main_cmd][sub_cmd][response_type]
+ * wc_object_add_callback(wo,
+ * WC_OBJECT_EVENT_SAP_RECEIVE_DATA[main_cmd][sub_cmd][response_type],
+ * user_data);
+ */
+#define WC_OBJECT_EVENT_SAP_SEND_DATA "eSAP-send"
+#define WC_OBJECT_EVENT_SAP_RECEIVE_DATA "eSAP-receive"
+
+
+/* TODO: to plug-in developer,
+ * develop each plug-in APIs and define each event for those APIs.
+ */
+#define WC_OBJECT_EVENT_SAP_BCMSERVICE_STATUS "bcmservice_status"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_EVENTSH__ */
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __WECONN_LOG_H__
+#define __WECONN_LOG_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <dlog.h>
+
+#define ERR(fmt, args...) do { LOGE(fmt, ## args); } while(0)
+#define WARN(fmt, args...) do { LOGW(fmt, ## args); } while(0)
+#define DBG(fmt, args...) do { LOGI(fmt, ## args); } while(0)
+
+#define SECURE_ERR(fmt, args...) do { SECURE_LOGE(fmt, ## args); } while(0)
+#define SECURE_WARN(fmt, args...) do { SECURE_LOGW(fmt, ## args); } while(0)
+#define SECURE_DBG(fmt, args...) do { SECURE_LOGI(fmt, ## args); } while(0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_LOG_H__ */
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __WECONN_OBJECT_H__
+#define __WECONN_OBJECT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <gio/gio.h>
+
+#include "log.h"
+
+#define WC_OBJECT_TYPE_DEFAULT 0xFF000000
+#define WC_OBJECT_TYPE_BEARER_DRIVER (WC_OBJECT_TYPE_DEFAULT | 0x00010000)
+#define WC_OBJECT_TYPE_SERVICE (WC_OBJECT_TYPE_DEFAULT | 0x00020000)
+#define WC_OBJECT_TYPE_TECHNOLOGY (WC_OBJECT_TYPE_DEFAULT | 0x00030000)
+#define WC_OBJECT_TYPE_CONTROL (WC_OBJECT_TYPE_DEFAULT | 0x00040000)
+
+#define WC_OBJECT_CHECK(o,t) \
+ if (!o) { WARN("WcObject is NULL"); return; } \
+ if (wc_object_get_type(o) != t) \
+ { WARN("type(0x%x != 0x%x) mismatch", wc_object_get_type(o), t); return; }
+#define WC_OBJECT_CHECK_RETURN(o,t,r) \
+ if (!o) { WARN("WcObject is NULL"); return r; } \
+ if (wc_object_get_type(o) != t) \
+ { WARN("type(0x%x != 0x%x) mismatch", wc_object_get_type(o), t); return r; }
+
+#define WC_OBJECT_KEY_FIND(keys, k) \
+ g_slist_find_custom((keys), (k), (GCompareFunc)g_strcmp0)
+
+typedef struct wc_object WcObject;
+typedef gboolean (*WcObjectCallback)(WcObject *wo, const void *event_info,
+ void *user_data);
+
+WcObject *wc_object_new(const char *name, unsigned int type);
+void wc_object_free(WcObject *wo);
+WcObject *wc_object_find(const char *name);
+
+const char *wc_object_get_name(WcObject *wo);
+const char *wc_object_peek_name(WcObject *wo);
+unsigned int wc_object_get_type(WcObject *wo);
+
+int wc_object_append_element(WcObject *wo,
+ const char *element_name, void *element);
+void *wc_object_get_element(WcObject *wo, const char *element_name);
+
+typedef void (*wc_object_foreach_get_elements_cb)(WcObject *wo,
+ const char *element_name, void *element, void *user_data);
+int wc_object_foreach_get_elements(WcObject *wo,
+ wc_object_foreach_get_elements_cb callback, void *user_data);
+
+int wc_object_set_dbus_interface(WcObject *wo, GDBusInterfaceSkeleton *di);
+GDBusInterfaceSkeleton *wc_object_get_dbus_interface(WcObject *wo);
+
+int wc_object_export(WcObject *wo, const char *path);
+int wc_object_unexport(WcObject *wo);
+
+int wc_object_add_callback(WcObject *wo, const char *event,
+ WcObjectCallback callback, void *user_data);
+int wc_object_del_callback(WcObject *wo, const char *event,
+ WcObjectCallback callback);
+int wc_object_emit_callback(WcObject *wo, const char *event,
+ const void *event_info);
+
+#define wc_object_set_property(co, ...) \
+ wc_object_set_property_full(co, __VA_ARGS__, NULL, NULL)
+
+int wc_object_set_property_full(WcObject *wo, const char *first_property, ...);
+char *wc_object_get_property(WcObject *wo, const char *key);
+
+const char *wc_object_peek_property(WcObject *wo, const char *key);
+GHashTable *wc_object_peek_property_hash(WcObject *wo);
+
+void wc_object_set_timeout_connecting(WcObject *wo,
+ guint timeout, const char *service);
+guint wc_object_get_timeout_connecting(WcObject *wo);
+char *wc_object_get_connecting_service(WcObject *wo);
+void wc_object_set_timeout_disconnecting(WcObject *wo,
+ guint timeout, const char *service);
+guint wc_object_get_timeout_disconnecting(WcObject *wo);
+char *wc_object_get_disconnecting_service(WcObject *wo);
+#endif /* __WECONN_OBJECT_H__ */
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __WECONN_SERVICE_H__
+#define __WECONN_SERVICE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int service_init(void);
+void service_cleanup(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_SERVICE_H__ */
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __WECONN_TECHNOLOGY_H__
+#define __WECONN_TECHNOLOGY_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define WC_TECHNOLOGY_BLUETOOTH "bluetooth"
+#define WC_TECHNOLOGY_CELLULAR "cellular"
+#define WC_TECHNOLOGY_WIFI "Wi-Fi"
+#define WC_TECHNOLOGY_ETHERNET "ethernet"
+
+
+#define CONNMAN_SERVICE "net.connman"
+#define CONNMAN_SERVICE_INTERFACE CONNMAN_SERVICE ".Service"
+#define CONNMAN_SIGNAL_PROPERTY_CHANGED "PropertyChanged"
+
+/**
+ * @brief Enumerations of wearable connection service state.
+ */
+typedef enum
+{
+ WC_SERVICE_STATE_IDLE = 0x00,
+ WC_SERVICE_STATE_FAILURE = 0x01,
+ WC_SERVICE_STATE_DISCONNECTED = 0x02,
+ WC_SERVICE_STATE_ASSOCIATION = 0x03,
+ WC_SERVICE_STATE_CONFIGURATION = 0x04,
+ WC_SERVICE_STATE_READY = 0x05,
+ WC_SERVICE_STATE_ONLINE = 0x06,
+} wc_technology_service_state_e;
+
+
+int wc_technology_add_bearer(WcObject *wo);
+WcObject *wc_technology_get_bearer(const char *technology);
+
+int technology_init(void);
+void technology_cleanup(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_TECHNOLOGY_H__ */
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __WECONN_UTIL_H__
+#define __WECONN_UTIL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <app_service.h>
+#include "weconn_type.h"
+
+#define XSTR(X) #X
+
+/**
+ * @brief Enumerations of wearable connection popup type.
+ */
+typedef enum
+{
+ WC_POPUP_TYPE_PAN_CONNECT = 0x01,
+ WC_POPUP_TYPE_PAN_DISCONNECT = 0x02,
+} weconn_popup_type_e;
+
+weconn_service_type_e wc_service_type_string2enum(const char *service_type);
+const char *wc_service_type_enum2string(weconn_service_type_e service_type);
+weconn_service_state_e wc_service_state_string2enum(const char *service_state);
+const char *wc_service_state_enum2string(weconn_service_state_e service_state);
+weconn_device_type_e wc_device_type_string2enum(const char *device_type);
+const char *wc_device_type_enum2string(weconn_device_type_e device_type);
+weconn_device_state_e wc_device_state_string2enum(const char *device_state);
+const char *wc_device_state_enum2string(weconn_device_state_e device_state);
+weconn_device_type_e wc_device_get_type_from_path(const char *path);
+int wc_launch_popup(weconn_popup_type_e type, service_reply_cb callback,
+ void *user_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_UTIL_H__ */
--- /dev/null
+<node>
+ <interface name="net.weconn.Service">
+ <signal name="PropertyChanged">
+ <arg name="name" type="s"/>
+ <arg name="value" type="v"/>
+ </signal>
+ </interface>
+</node>
--- /dev/null
+<node>
+ <interface name="net.weconn.Technology">
+ <method name="GetProperties">
+ <arg name="properties" type="a{sv}" direction="out"/>
+ </method>
+ <method name="GetProperty">
+ <arg name="name" type="s" direction="in"/>
+ <arg name="value" type="v" direction="out"/>
+ </method>
+ <method name="SetProperty">
+ <arg name="name" type="s" direction="in"/>
+ <arg name="value" type="v" direction="in"/>
+ </method>
+ <method name="Scan">
+ </method>
+ <method name="Connect">
+ <arg name="service" type="s" direction="in"/>
+ </method>
+ <method name="Disconnect">
+ <arg name="service" type="s" direction="in"/>
+ </method>
+ <signal name="PropertyChanged">
+ <arg name="name" type="s"/>
+ <arg name="value" type="v"/>
+ </signal>
+ </interface>
+</node>
--- /dev/null
+Name: weconn
+Summary: WEarable device CONNection controller framework (We connect all)
+Version: 0.1.56
+Release: 1
+Group: System/Network
+License: Apache-2.0
+Source0: %{name}-%{version}.tar.gz
+BuildRequires: cmake
+BuildRequires: python-xml
+BuildRequires: pkgconfig(dlog)
+BuildRequires: pkgconfig(vconf)
+BuildRequires: pkgconfig(gio-2.0)
+BuildRequires: pkgconfig(glib-2.0)
+BuildRequires: pkgconfig(capi-base-common)
+BuildRequires: pkgconfig(sap-client-stub-api)
+BuildRequires: pkgconfig(capi-appfw-application)
+BuildRequires: pkgconfig(capi-network-bluetooth)
+BuildRequires: pkgconfig(capi-system-info)
+BuildRequires: pkgconfig(alarm-service)
+Requires(post): /sbin/ldconfig
+Requires(post): /usr/bin/vconftool
+Requires(postun): /sbin/ldconfig
+Requires: /usr/bin/vconftool
+
+%description
+Wearable device requires an automatic controller to manage various connection bearers
+without UI based control panel. Wearable connection controller provides client and
+daemon for managing various connection bearers within wearable devices running the
+Linux operating system.
+
+%package devel
+Summary: WEarable device CONNection controller API library (devel)
+Group: System/Network
+License: Apache
+Requires: %{name} = %{version}-%{release}
+
+%description devel
+Wearable device connection controller API library in TIZEN C API (Development)
+
+%prep
+%setup -q
+
+
+%build
+cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} -DVERSION=%{version}
+make %{?_smp_mflags}
+
+
+%install
+%make_install
+
+#Systemd service file
+mkdir -p %{buildroot}%{_libdir}/systemd/system/
+cp resources/usr/lib/systemd/system/weconn.service %{buildroot}%{_libdir}/systemd/system/weconn.service
+mkdir -p %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants/
+ln -s ../weconn.service %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants/weconn.service
+
+mkdir -p %{buildroot}%{_datadir}/dbus-1/services/
+cp resources/usr/share/dbus-1/services/net.weconn.service %{buildroot}%{_datadir}/dbus-1/services/net.weconn.service
+
+#DBus DAC (manifest enables DBus SMACK)
+mkdir -p %{buildroot}%{_sysconfdir}/dbus-1/system.d/
+cp resources/etc/dbus-1/system.d/weconn.conf %{buildroot}%{_sysconfdir}/dbus-1/system.d/
+
+#appcessory
+mkdir -p %{buildroot}%{_datadir}/appcessory/
+cp resources/usr/share/appcessory/wearable-connection.xml %{buildroot}%{_datadir}/appcessory/
+
+#FOTA patch
+mkdir -p %{buildroot}%{_sysconfdir}/opt/upgrade/
+cp resources/etc/opt/upgrade/500.net.weconn.patch.sh %{buildroot}%{_sysconfdir}/opt/upgrade/
+
+#License
+mkdir -p %{buildroot}%{_datadir}/license
+cp LICENSE %{buildroot}%{_datadir}/license/weconn
+
+%post
+
+#Systemd enhanced BT power on
+mkdir -p %{_sysconfdir}/systemd/default-extra-dependencies/ignore-units.d/
+ln -s %{_libdir}/systemd/system/weconn.service %{_sysconfdir}/systemd/default-extra-dependencies/ignore-units.d/
+
+vconftool set -t int file/private/weconn/connected_bt_version 0 -s system::vconf_network
+vconftool set -t int file/private/weconn/disconnected_manually 0 -s system::vconf_network
+vconftool set -t string file/private/weconn/connected_manufacturer "" -s system::vconf_network
+vconftool set -t string file/private/weconn/autoconnectable_unique_bt_target_address "" -s system::vconf_network
+vconftool set -t int file/private/weconn/last_bt_status 0 -s system::vconf_network
+vconftool set -tf int memory/private/weconn/all_connected 0 -s system::vconf_network -i
+
+%postun -p /sbin/ldconfig
+
+
+%files
+%manifest weconn.manifest
+%attr(644,-,-) %{_libdir}/*.so.*
+%attr(500,root,root) %{_sbindir}/*
+%attr(400,root,root) %{_libdir}/weconn/*.so
+%attr(644,root,root) %{_datadir}/dbus-1/services/*
+#DBus DAC
+%attr(644,root,root) %{_sysconfdir}/dbus-1/system.d/*
+%attr(644,root,root) %{_libdir}/systemd/system/weconn.service
+%attr(644,root,root) %{_libdir}/systemd/system/multi-user.target.wants/weconn.service
+%attr(700,root,root) %{_sysconfdir}/opt/upgrade/500.net.weconn.patch.sh
+%{_datadir}/license/weconn
+%{_datadir}/appcessory/wearable-connection.xml
+
+%files devel
+%{_libdir}/libweconn.so
+%{_includedir}/weconn
+%{_libdir}/pkgconfig/weconn.pc
--- /dev/null
+REMOVE_DEFINITIONS("-DLOG_TAG=\"CAPI_NETWORK_WECONN\"")
+ADD_DEFINITIONS("-DLOG_TAG=\"WECONN\"")
+
+
+SET(PLUGINS
+ pan
+ esap
+ bluetooth
+)
+
+FOREACH(plugin ${PLUGINS})
+ ADD_LIBRARY(${plugin} SHARED ${plugin}.c ../src/util.c)
+ TARGET_LINK_LIBRARIES(${plugin} ${pkgs_LDFLAGS} "-L${CMAKE_BINARY_DIR}")
+ SET_TARGET_PROPERTIES(${plugin} PROPERTIES PREFIX "" OUTPUT_NAME ${plugin})
+ INSTALL(TARGETS ${plugin} LIBRARY DESTINATION ${WECONNLIB})
+ENDFOREACH(plugin)
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <alarm.h>
+#include <vconf.h>
+#include <bluetooth.h>
+#include <vconf-keys.h>
+
+#include "esap.h"
+#include "plugin.h"
+
+#define BT_ADVERTISING_INTERVAL_FAST 150.0f //msec
+#define BT_ADVERTISING_INTERVAL_NORMAL 500.0f //msec
+#define FAST_ADVERTISING_TIMEOUT 30 //sec
+
+#define BT_ADV_MANUFACTURER_COMPANY 0x75
+#define BT_ADV_MANUFACTURER_SERVICE_ID 0x02
+#define BT_ADV_MANUFACTURER_VERSION 0x01
+#define BT_ADV_MANUFACTURER_PKG_NAME "watchmanager"
+
+#define VCONFKEY_WECONN_LAST_BT_STATUS \
+ "file/private/weconn/last_bt_status"
+
+static int sap_rfcomm_ready = 0;
+static int sap_connected = 0;
+static bool hf_connected = false;
+
+static gboolean mBTRecoveryState = FALSE;
+
+static alarm_id_t fast_advertising_timer_id = 0;
+
+static void __bt_start_advertising(bool fast);
+static void __bt_page_scan(bool on);
+
+static bool __bt_check_bonded_device_cb(bt_device_info_s *device_info,
+ void *user_data)
+{
+ if (device_info && device_info->bt_class.major_device_class
+ == BT_MAJOR_DEVICE_CLASS_AUDIO_VIDEO) {
+ int ret;
+ bool is_a2dp_connected = false;
+
+ DBG("Major class[0x%x]", device_info->bt_class.major_device_class);
+
+ ret = bt_device_is_profile_connected(device_info->remote_address,
+ BT_PROFILE_A2DP, &is_a2dp_connected);
+
+ DBG("ret[%d], is_a2dp_connected [%d]", ret, is_a2dp_connected);
+
+ if (ret == BT_ERROR_NONE && is_a2dp_connected == false)
+ __bt_page_scan(true);
+ }
+
+ return true;
+}
+
+static void __bt_notify_all_connected(int connected)
+{
+ int all_connected = 0;
+
+ if (vconf_get_int(VCONFKEY_WECONN_ALL_CONNECTED, &all_connected) < 0) {
+ ERR("Failed to get all connected status");
+ } else {
+ if (all_connected == connected) {
+ ERR("Not changed all connected state");
+ return;
+ }
+ }
+
+ if (connected == 0)
+ vconf_set_int(VCONFKEY_WECONN_ALL_CONNECTED, 0);
+ else
+ vconf_set_int(VCONFKEY_WECONN_ALL_CONNECTED, 1);
+
+ DBG("All connected");
+}
+
+static void __bt_page_scan(bool on)
+{
+ int err;
+ bool prev_status = false;
+
+ err = bt_adapter_get_connectable(&prev_status);
+ if (err != BT_ERROR_NONE) {
+ ERR("Failed to get bt_adapter_get_connectable(%d)", err);
+ return;
+ }
+
+ if (prev_status == false && on == true) {
+ err = bt_adapter_set_connectable(true);
+ if (err != BT_ERROR_NONE)
+ ERR("Failed to start page scan(%d)", err);
+ else
+ DBG("Page scan started");
+ } else if (prev_status == true && on == false) {
+ err = bt_adapter_set_connectable(false);
+ if (err != BT_ERROR_NONE)
+ ERR("Failed to stop page scan(%d)", err);
+ else
+ DBG("Page scan stopped");
+
+ /* check bonded device and enable page scan if AV headset is paired*/
+ if (bt_adapter_foreach_bonded_device(__bt_check_bonded_device_cb,
+ NULL) != BT_ERROR_NONE)
+ ERR("Failed to check bonded devices");
+ } else {
+ DBG("Skip setting: old(%d), new(%d)", prev_status, on);
+ }
+}
+
+static int __get_setup_wizard_state(void)
+{
+ int ret = 0, state = 0;
+
+ ret = vconf_get_bool(VCONFKEY_SETUP_WIZARD_FIRST_BOOT, &state);
+ if (ret < 0) {
+ ERR("Failed to get state(%d)", ret);
+ return -EIO;
+ }
+
+ DBG("Setup wizard running state(%d)", state);
+
+ return state;
+}
+
+static void __bt_set_advertising_manufacturer_data(int setup_wizard_state)
+{
+ int err = 0;
+ static char prev_data[24] = {0, };
+ char data[24] = {0, };
+ int len = 0;
+
+ /* Complete manufacturer data */
+ // Company
+ data[0] = 0x00;
+ data[1] = BT_ADV_MANUFACTURER_COMPANY;
+
+ // TODO: Read value from somewhere
+ // Version
+ data[2] = BT_ADV_MANUFACTURER_VERSION;
+
+ // Service ID
+ data[3] = 0x00;
+ data[4] = BT_ADV_MANUFACTURER_SERVICE_ID;
+
+ // TODO : Read value from somewhere
+ // Device ID (b2 : 0x01, wingtip : 0x02)
+ data[5] = 0x00;
+ data[6] = 0x01;
+
+ if (setup_wizard_state == 1) {
+ // Purpose (setup : 0x01, auto connection : 0x02)
+ data[7] = 0x01;
+
+ /* Data for Quick Connect */
+ // Length of package name
+ data[8] = 0x0c;
+
+ // Package name for auto installation
+ memcpy(&data[9], BT_ADV_MANUFACTURER_PKG_NAME,
+ sizeof(BT_ADV_MANUFACTURER_PKG_NAME));
+ len = 9 + strlen(BT_ADV_MANUFACTURER_PKG_NAME);
+
+ // BT rssi calibrating constant
+ data[len] = 0x00;
+ len++;
+ } else {/* setup wizard is not running */
+ data[7] = 0x02;
+ len = 8;
+ }
+
+ DBG("len(%d)", len);
+ memcpy(prev_data, data, sizeof(data));
+
+ err = bt_adapter_set_advertising_manufacturer_data(data, len);
+ if (err != BT_ERROR_NONE)
+ ERR("Failed to set manufacturer data(%d)", err);
+}
+
+static bool __device_check_gatt_cb(bt_profile_e profile, void *user_data)
+{
+ bool *is_connected = (bool *)user_data;
+
+ if (profile == BT_PROFILE_GATT) {
+ *is_connected = true;
+ DBG("LE is connected");
+ return false;
+ }
+
+ return true;
+}
+
+static bool __device_check_hfp_cb(bt_profile_e profile, void *user_data)
+{
+ bool *is_connected = (bool *)user_data;
+
+ if (profile == BT_PROFILE_AG) {
+ *is_connected = true;
+ DBG("HFP is connected");
+ return false;
+ }
+
+ return true;
+}
+
+static bool __bt_check_connection_status(const char *addr,
+ bt_device_connected_profile func)
+{
+ int ret;
+ bool is_connected = false;
+
+ if (!addr || !func || addr[0] == '\0')
+ return false;
+
+ SECURE_DBG("Addr[%s]", addr);
+ ret = bt_device_foreach_connected_profiles(addr, func, &is_connected);
+ if (ret != BT_ERROR_NONE) {
+ ERR("Failed to bt_device_foreach_connected_profiles(0x%08x)", ret);
+ return false;
+ }
+
+ return is_connected;
+}
+
+static int __fast_advertising_timeout_cb(alarm_id_t alarm_id, void * data)
+{
+ DBG("fast advertising timer expired!!");
+
+ if (fast_advertising_timer_id > 0) {
+ alarmmgr_remove_alarm(fast_advertising_timer_id);
+ fast_advertising_timer_id = 0;
+ }
+
+ if (sap_connected != SAP_CONNECTED && hf_connected != true)
+ __bt_start_advertising(false);
+
+ return 0;
+}
+
+static void __fast_advertising_timer_stop(void)
+{
+ if (fast_advertising_timer_id <= 0)
+ return;
+
+ DBG("Alarm unregistered(%d)", fast_advertising_timer_id);
+ alarmmgr_remove_alarm(fast_advertising_timer_id);
+ fast_advertising_timer_id = 0;
+}
+
+static void __fast_advertising_timer_start(void)
+{
+ int result = 0;
+
+ __fast_advertising_timer_stop();
+
+ result = alarmmgr_set_cb(__fast_advertising_timeout_cb, NULL);
+ if (result != ALARMMGR_RESULT_SUCCESS) {
+ ERR("Failed to set timer(%d)", result);
+ return;
+ }
+
+ result = alarmmgr_add_alarm(ALARM_TYPE_VOLATILE, FAST_ADVERTISING_TIMEOUT,
+ 0, NULL, &fast_advertising_timer_id);
+ if (result != ALARMMGR_RESULT_SUCCESS) {
+ ERR("Failed to add alarm(%d)", result);
+ return;
+ }
+
+ DBG("Alarm registered(%d)", fast_advertising_timer_id);
+}
+
+static void __bt_update_white_list(const char *bt_target_address,
+ int setup_wizard_state)
+{
+ int ret = 0;
+ bool is_advertising = false;
+
+ ret = bt_adapter_is_advertising(&is_advertising);
+ if (ret == BT_ERROR_NONE && is_advertising == true)
+ bt_adapter_stop_advertising();
+
+ /* should remove the previous connected addresses */
+ DBG("Clear white list");
+ ret = bt_adapter_clear_white_list();
+ if (ret != BT_ERROR_NONE)
+ ERR("Failed to clear white list(%d)", ret);
+
+ if (!bt_target_address) {
+ DBG("target address is NULL");
+ return;
+ }
+
+ if (strlen(bt_target_address) < 17) {
+ /* BT address formatted [xx:xx:xx:xx:xx:xx] */
+ DBG("Invalid mac address");
+ return;
+ }
+
+ if (setup_wizard_state == 1) {
+ DBG("Setup Wizard is running");
+ return;
+ }
+
+ WARN("Adding white list[%c%c:%c%c:%c%c]",
+ bt_target_address[0], bt_target_address[1],
+ bt_target_address[3], bt_target_address[4],
+ bt_target_address[15], bt_target_address[16]);
+ SECURE_DBG("white list[%s]", bt_target_address);
+ ret = bt_adapter_add_white_list(bt_target_address);
+ if (ret != BT_ERROR_NONE)
+ ERR("Failed to add white list(%d)", ret);
+}
+
+static void __bt_start_advertising(bool fast)
+{
+ int ret = 0;
+ bool is_advertising = false;
+ bt_adapter_advertising_params_s adv_params = { 0, };
+ bt_adapter_state_e device_status;
+ int setup_wizard_state = 0;
+ int disconnected_manually = 0;
+ const char *autoconnectable_bt_address = NULL;
+
+ bt_adapter_get_state(&device_status);
+ if (device_status != BT_ADAPTER_ENABLED) {
+ ERR("BT disabled");
+ return;
+ }
+
+ if (sap_connected == SAP_CONNECTED || hf_connected == true) {
+ ERR("SPP(%d) HFP(%d)", sap_connected, hf_connected);
+ return;
+ }
+
+ /* page scan should be on, even if LE does not advertised */
+ __bt_page_scan(true);
+
+ vconf_get_int(VCONFKEY_WECONN_DISCONNECTED_MANUALLY, &disconnected_manually);
+ if (disconnected_manually) {
+ DBG("Disconnected manually(%d)", disconnected_manually);
+ return;
+ }
+
+ /* Important: BT auto-connectable address should be set by WMS,
+ * when EULA acceptance has been made by an user.
+ */
+ autoconnectable_bt_address =
+ vconf_get_str(VCONFKEY_WECONN_AUTOCONNECTABLE_BT_ADDRESS);
+ if (autoconnectable_bt_address && strlen(autoconnectable_bt_address) > 0 &&
+ __bt_check_connection_status(autoconnectable_bt_address,
+ __device_check_gatt_cb) == true) {
+ return;
+ }
+
+ DBG("fast(%d)", fast);
+ if (fast) {
+ __fast_advertising_timer_start();
+
+ adv_params.interval_max = BT_ADVERTISING_INTERVAL_FAST;
+ adv_params.interval_min = BT_ADVERTISING_INTERVAL_FAST;
+ } else {
+ adv_params.interval_max = BT_ADVERTISING_INTERVAL_NORMAL;
+ adv_params.interval_min = BT_ADVERTISING_INTERVAL_NORMAL;
+ }
+
+ setup_wizard_state = __get_setup_wizard_state();
+
+ __bt_update_white_list(autoconnectable_bt_address, setup_wizard_state);
+
+ if (setup_wizard_state == 1) {
+ adv_params.filter_policy = BT_ADAPTER_ADVERTISING_FILTER_ALLOW_CONN_WL;
+ adv_params.interval_max = BT_ADVERTISING_INTERVAL_FAST;
+ adv_params.interval_min = BT_ADVERTISING_INTERVAL_FAST;
+ } else {
+ if (autoconnectable_bt_address &&
+ strlen(autoconnectable_bt_address) > 0) {
+ adv_params.filter_policy =
+ BT_ADAPTER_ADVERTISING_FILTER_ALLOW_SCAN_CONN_WL;
+ } else {
+ WARN("Start advertising without white list");
+ adv_params.filter_policy = BT_ADAPTER_ADVERTISING_FILTER_DEFAULT;
+ }
+ }
+
+ g_free((gpointer)autoconnectable_bt_address);
+
+ ret = bt_adapter_is_advertising(&is_advertising);
+ if (ret == BT_ERROR_NONE && is_advertising == true)
+ bt_adapter_stop_advertising();
+
+ __bt_set_advertising_manufacturer_data(setup_wizard_state);
+
+ ret = bt_adapter_start_advertising(&adv_params);
+ if (ret == BT_ERROR_NONE) {
+ DBG("LE Advertising is started(%.2fms)", adv_params.interval_max);
+ return;
+ }
+
+ ERR("Failed to start advertising(%d)", ret);
+}
+
+static void __bt_stop_advertising(void)
+{
+ int ret = 0;
+ bool is_advertising = FALSE;
+
+ /* Either HFP or SPP connected, stop advertising and disable page scan */
+ if (fast_advertising_timer_id > 0) {
+ alarmmgr_remove_alarm(fast_advertising_timer_id);
+ fast_advertising_timer_id = 0;
+ }
+
+ ret = bt_adapter_is_advertising(&is_advertising);
+ if (ret == BT_ERROR_NONE && is_advertising == false)
+ goto page_scan_off;
+
+ ret = bt_adapter_stop_advertising();
+ if (ret == BT_ERROR_NONE)
+ DBG("LE Advertising is stopped");
+ else
+ ERR("Fail to stop advertising(%d)", ret);
+
+page_scan_off:
+ if(__get_setup_wizard_state() != 1)
+ __bt_page_scan(false);
+}
+
+static void __bt_set_visibility(bt_adapter_visibility_mode_e mode)
+{
+ int ret = 0;
+ bt_adapter_visibility_mode_e visibility = 0;
+ int setup_wizard_state = __get_setup_wizard_state();
+
+ if (setup_wizard_state == 1) {
+ ERR("Setup wizard is running and no need to set visibility");
+ return;
+ }
+
+ ret = bt_adapter_get_visibility(&visibility, NULL);
+ if (ret != BT_ERROR_NONE) {
+ ERR("Failed to get bt_adapter_get_visibility(%d)", ret);
+ return;
+ }
+
+ DBG("Visibility(%d), mode(%d)", visibility, mode);
+ if (visibility != mode) {
+ bt_adapter_set_visibility(mode, 0);
+ if (ret != BT_ERROR_NONE)
+ ERR("Failed to set bt_adapter_set_visibility(%d)", ret);
+ }
+}
+
+static void __setup_wizard_state_cb(keynode_t *node, void *user_data)
+{
+ int err = 0, state = 0;
+ WcObject * wo = (WcObject*)user_data;
+
+ if (!wo)
+ return;
+
+ if (node)
+ state = vconf_keynode_get_bool(node);
+ else
+ err = vconf_get_bool(VCONFKEY_SETUP_WIZARD_FIRST_BOOT, &state);
+ if (err < 0) {
+ ERR("Failed to get setup wizard state");
+ return;
+ }
+
+ DBG("setup wizard state: %d", state);
+ if (state == 0)
+ __bt_page_scan(false);
+}
+
+static void __power_saving_mode_cb(keynode_t *node, void *user_data)
+{
+ int ret = 0;
+ int ps_mode = 0;
+ bt_adapter_state_e last_bt_status = BT_ADAPTER_DISABLED;
+ WcObject * wo = (WcObject*)user_data;
+
+ if (!wo)
+ return;
+
+ if (node)
+ ps_mode = vconf_keynode_get_int(node);
+ else {
+ ret = vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &ps_mode);
+ if (ret < 0) {
+ ERR("Failed to get power saving mode");
+ return;
+ }
+ }
+
+ if (ps_mode == SETTING_PSMODE_WEARABLE) {
+ ret = bt_adapter_get_state(&last_bt_status);
+ if (ret != BT_ERROR_NONE) {
+ ERR("Failed to get bluetooth status (%d)", ret);
+ return;
+ }
+
+ DBG("bluetooth status : %d", last_bt_status);
+ if (last_bt_status != BT_ADAPTER_ENABLED)
+ return;
+
+ vconf_set_int(VCONFKEY_WECONN_LAST_BT_STATUS, last_bt_status);
+
+ ret = bt_adapter_disable();
+ if (ret != BT_ERROR_NONE)
+ ERR("Failed to disable bluetooth (%d)", ret);
+ } else if (ps_mode == SETTING_PSMODE_NORMAL) {
+ vconf_get_int(VCONFKEY_WECONN_LAST_BT_STATUS, (int*)&last_bt_status);
+ if (last_bt_status == BT_ADAPTER_ENABLED) {
+ ret = bt_adapter_enable();
+ if (ret != BT_ERROR_NONE)
+ ERR("Failed to enable bluetooth (%d)", ret);
+ } else
+ DBG("bluetooth was not enabled");
+ } else
+ DBG("Invalid value : %d", ps_mode);
+}
+
+static void __rfcomm_ready_status_changed_cb(keynode_t *node, void *user_data)
+{
+ int err = 0, rfcomm_ready = 0;
+ WcObject * wo = (WcObject*)user_data;
+
+ if (!wo)
+ return;
+
+ if (node)
+ rfcomm_ready = vconf_keynode_get_int(node);
+ else
+ err = vconf_get_int(VCONFKEY_RFCOMM_READY_STATUS, &rfcomm_ready);
+
+ if (err < 0) {
+ ERR("Failed to get rfcomm ready status");
+ return;
+ }
+
+ sap_rfcomm_ready = rfcomm_ready;
+ DBG("rfcomm_ready(%d), SPP(%d), HFP(%d)",
+ rfcomm_ready, sap_connected, hf_connected);
+
+ if (rfcomm_ready == 1) {
+ if (sap_connected != SAP_CONNECTED && hf_connected != true)
+ __bt_start_advertising(true);
+ } else
+ __bt_stop_advertising();
+}
+
+static void __pm_key_ignore_cb(keynode_t *node, void *user_data)
+{
+ int ret = 0;
+ int mode = 0;
+ bt_adapter_state_e bt_status = BT_ADAPTER_DISABLED;
+ static bt_adapter_state_e prev_bt_status = BT_ADAPTER_DISABLED;
+
+ if (node)
+ mode = vconf_keynode_get_int(node);
+ else
+ ret = vconf_get_int(VCONFKEY_PM_KEY_IGNORE, &mode);
+
+ DBG("current pm mode : %s mode", mode ? "clock" : "normal");
+
+ ret = bt_adapter_get_state(&bt_status);
+ if (ret != BT_ERROR_NONE) {
+ ERR("Failed to get bluetooth status (%d)", ret);
+ return;
+ }
+ DBG("bluetooth status : %d", bt_status);
+
+ if (mode == 1) {
+ if (bt_status != BT_ADAPTER_ENABLED)
+ return;
+
+ ret = bt_adapter_disable();
+ if (ret != BT_ERROR_NONE)
+ ERR("Failed to disable bluetooth (%d)", ret);
+ } else {
+ if (bt_status != BT_ADAPTER_DISABLED)
+ return;
+ else if (prev_bt_status == BT_ADAPTER_ENABLED) {
+ ret = bt_adapter_enable();
+ if (ret != BT_ERROR_NONE)
+ ERR("Failed to enable bluetooth (%d)", ret);
+ }
+ }
+
+ prev_bt_status = bt_status;
+}
+
+static void __bt_fatal_recovery(void)
+{
+ int ret;
+ bt_adapter_state_e state = BT_ADAPTER_DISABLED;
+
+ ret = bt_adapter_get_state(&state);
+ if (ret != BT_ERROR_NONE)
+ ERR("Fatally failed to get BT state(%d)", ret);
+
+ WARN("BT state(%d)", state);
+ bt_adapter_disable();
+
+ mBTRecoveryState = TRUE;
+}
+
+static void __bt_check_fatal_recovery(void)
+{
+ const char *autoconnectable_bt_address = NULL;
+
+ /* Important: BT auto-connectable address should be set by WMS,
+ * when EULA acceptance has been made by an user.
+ */
+ autoconnectable_bt_address =
+ vconf_get_str(VCONFKEY_WECONN_AUTOCONNECTABLE_BT_ADDRESS);
+ if (autoconnectable_bt_address && strlen(autoconnectable_bt_address) > 0 &&
+ __bt_check_connection_status(autoconnectable_bt_address,
+ __device_check_gatt_cb) == true) {
+ g_free((gpointer)autoconnectable_bt_address);
+
+ ERR("Fatal error: both EDR and LE was connected");
+
+ __bt_fatal_recovery();
+ return;
+ }
+
+ g_free((gpointer)autoconnectable_bt_address);
+}
+
+static void __sap_connection_status_changed_cb(keynode_t *node, void *user_data)
+{
+ int err = 0, sap_conn = 0;
+ int disconnected_manually = 0;
+ WcObject * wo = (WcObject*)user_data;
+
+ if (!wo)
+ return;
+
+ if (node)
+ sap_conn = vconf_keynode_get_int(node);
+ else
+ err = vconf_get_int(VCONFKEY_SAP_CONNECTION_STATUS, &sap_conn);
+
+ if (err < 0) {
+ ERR("Failed to get sap connection status");
+ return;
+ }
+
+ if (sap_connected == sap_conn) {
+ ERR("sap connection is not changed(%d)", sap_conn);
+ return;
+ }
+
+ sap_connected = sap_conn;
+ DBG("rfcomm_ready(%d), SPP(%d), HFP(%d)", sap_rfcomm_ready, sap_conn, hf_connected);
+ if (sap_conn == SAP_CONNECTED) {
+ __bt_stop_advertising();
+ __bt_set_visibility(BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE);
+
+ if (hf_connected) {
+ __bt_notify_all_connected(1);
+
+ vconf_get_int(VCONFKEY_WECONN_DISCONNECTED_MANUALLY,
+ &disconnected_manually);
+ if (disconnected_manually)
+ vconf_set_int(VCONFKEY_WECONN_DISCONNECTED_MANUALLY, 0);
+ }
+
+ wc_object_set_property(wo, XSTR(W_SERVICE_TYPE_BT_SPP),
+ XSTR(W_SERVICE_STATE_CONNECTED));
+ } else {
+ __bt_notify_all_connected(0);
+
+ if (hf_connected != true)
+ __bt_check_fatal_recovery();
+
+ if (sap_rfcomm_ready == 1 && hf_connected != true) {
+ /* start LE advertising */
+ DBG("HFP is disconnected");
+ __bt_start_advertising(false);
+ }
+
+ wc_object_set_property(wo, XSTR(W_SERVICE_TYPE_BT_SPP),
+ XSTR(W_SERVICE_STATE_DISCONNECTED));
+ }
+}
+
+static void __on_bt_adapter_state_changed(int result, bt_adapter_state_e state,
+ void *user_data)
+{
+ int sap_conn = SAP_DISCONNECTED;
+ const char *autoconnectable_bt_address = NULL;
+ WcObject *wo = (WcObject *)user_data;
+
+ if (mBTRecoveryState == TRUE && state == BT_ADAPTER_DISABLED) {
+ ERR("BT fatal recovery tries to turn BT power on");
+
+ bt_adapter_enable();
+ mBTRecoveryState = FALSE;
+
+ return;
+ }
+
+ if (!wo)
+ return;
+
+ DBG("result = %d, state = %d", result, state);
+ switch (state) {
+ case BT_ADAPTER_ENABLED:
+ /* BT ON */
+ wc_object_emit_callback(wo, WC_OBJECT_EVENT_BEARER_ENABLED, NULL);
+
+ /* Update SPP state */
+ if (vconf_get_int(VCONFKEY_SAP_CONNECTION_STATUS, &sap_conn) < 0) {
+ ERR("Failed to get sap connection status, but go ahead.");
+ sap_connected = SAP_DISCONNECTED;
+ } else
+ sap_connected = sap_conn;
+
+ autoconnectable_bt_address =
+ vconf_get_str(VCONFKEY_WECONN_AUTOCONNECTABLE_BT_ADDRESS);
+ SECURE_DBG("last connected BT address(%s)", autoconnectable_bt_address);
+ if (autoconnectable_bt_address &&
+ strlen(autoconnectable_bt_address) > 0) {
+ /* Update HFP status */
+ hf_connected = __bt_check_connection_status(
+ autoconnectable_bt_address, __device_check_hfp_cb);
+ } else {
+ /* If not, clear white list, for example, factory reset */
+ __bt_update_white_list(NULL, 0);
+ }
+
+ g_free((gpointer)autoconnectable_bt_address);
+
+ vconf_set_int(VCONFKEY_WECONN_LAST_BT_STATUS, 0);
+
+ DBG("BT power(%d), rfcomm_ready(%d), SPP(%d) HFP(%d)",
+ state, sap_rfcomm_ready, sap_connected, hf_connected);
+ if (sap_rfcomm_ready == 1 &&
+ sap_connected != SAP_CONNECTED && hf_connected != true)
+ __bt_start_advertising(true);
+
+ wc_object_set_property(wo, XSTR(W_DEVICE_TYPE_BT),
+ XSTR(W_DEVICE_STATE_ENABLED));
+
+ break;
+ case BT_ADAPTER_DISABLED:
+ /* BT OFF */
+ wc_object_emit_callback(wo, WC_OBJECT_EVENT_BEARER_DISABLED, NULL);
+
+ hf_connected = false;
+ sap_connected = false;
+
+ __fast_advertising_timer_stop();
+
+ wc_object_set_property(wo, XSTR(W_DEVICE_TYPE_BT),
+ XSTR(W_DEVICE_STATE_DISABLED));
+
+ break;
+ }
+}
+
+static void __on_bt_audio_connection_state_changed_cb(int result,
+ bool connected, const char *remote_address,
+ bt_audio_profile_type_e type, void *user_data)
+{
+ int disconnected_manually = 0;
+ WcObject *wo = (WcObject *)user_data;
+
+ DBG("result %d, type %d, rfcomm_ready(%d), SPP(%d), HFP(%d)",
+ result, type, sap_rfcomm_ready, sap_connected, connected);
+ SECURE_DBG("remote(%s)", remote_address);
+
+ if (type != BT_AUDIO_PROFILE_TYPE_AG) {
+ if (type == BT_AUDIO_PROFILE_TYPE_A2DP) {
+ if (connected == false)
+ __bt_page_scan(true);
+ else
+ if (hf_connected == true || sap_connected == SAP_CONNECTED)
+ bt_adapter_set_connectable(false);
+ }
+ return;
+ }
+
+ if (!wo)
+ return;
+
+ hf_connected = connected;
+ if (connected) {
+ __bt_stop_advertising();
+ __bt_set_visibility(BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE);
+
+ if (sap_connected == SAP_CONNECTED) {
+ __bt_notify_all_connected(1);
+
+ vconf_get_int(VCONFKEY_WECONN_DISCONNECTED_MANUALLY,
+ &disconnected_manually);
+ if (disconnected_manually)
+ vconf_set_int(VCONFKEY_WECONN_DISCONNECTED_MANUALLY, 0);
+ }
+
+ wc_object_set_property(wo, XSTR(W_SERVICE_TYPE_BT_HFP),
+ XSTR(W_SERVICE_STATE_CONNECTED));
+ } else {
+ __bt_notify_all_connected(0);
+
+ if (sap_connected != SAP_CONNECTED)
+ __bt_check_fatal_recovery();
+
+ if (sap_rfcomm_ready == 1 && sap_connected != SAP_CONNECTED) {
+ /* start LE advertising */
+ DBG("SAP is disconnected");
+ __bt_start_advertising(false);
+ }
+
+ wc_object_set_property(wo, XSTR(W_SERVICE_TYPE_BT_HFP),
+ XSTR(W_SERVICE_STATE_DISCONNECTED));
+ }
+}
+
+static void __on_bt_socket_connection_state_changed_cb(int result,
+ bt_socket_connection_state_e state,
+ bt_socket_connection_s *connection, void *user_data)
+{
+ WcObject *wo = (WcObject *)user_data;
+
+ DBG("result %d, state %d", result, state);
+
+ if (!wo)
+ return;
+
+/*
+ if (state == BT_SOCKET_CONNECTED)
+ wc_object_set_property(wo, XSTR(W_SERVICE_TYPE_BT_SPP),
+ XSTR(W_SERVICE_STATE_CONNECTED));
+ else
+ wc_object_set_property(wo, XSTR(W_SERVICE_TYPE_BT_SPP),
+ XSTR(W_SERVICE_STATE_DISCONNECTED));
+*/
+}
+
+static void __on_bt_device_connection_state_changed_cb(bool connected,
+ const char *remote_address, void *user_data)
+{
+ WcObject *wo = (WcObject *)user_data;
+
+ DBG("result %d ", connected);
+ if(remote_address != NULL)
+ SECURE_DBG("remote address [%s]", remote_address);
+
+ if (!wo)
+ return;
+
+/* This callback is triggered by ACL connected / disconnected event
+ if (connected)
+ wc_object_set_property(wo, XSTR(W_SERVICE_TYPE_BT_HFP),
+ XSTR(W_SERVICE_STATE_CONNECTED));
+ else
+ wc_object_set_property(wo, XSTR(W_SERVICE_TYPE_BT_HFP),
+ XSTR(W_SERVICE_STATE_DISCONNECTED));
+*/
+}
+
+static void __on_bt_device_bond_destroy_cb(int result,
+ char *remote_address, void *user_data)
+{
+ WcObject *wo = (WcObject *)user_data;
+
+ if (!wo || !remote_address)
+ return;
+
+ DBG("result(%d) address(%s)", result, remote_address);
+ if (result == BT_ERROR_NONE) {
+ // Disable page scan if HFP or SAP is connected
+ if (hf_connected == true || sap_connected == SAP_CONNECTED)
+ __bt_page_scan(false);
+ }
+
+ return;
+}
+
+static void __on_bt_device_bond_created_cb(int result,
+ bt_device_info_s *device_info, void *user_data)
+{
+ WcObject *wo = (WcObject *)user_data;
+
+ if (!wo || !device_info)
+ return;
+
+ DBG("result(%d), device class(%d)", result,
+ device_info->bt_class.major_device_class);
+ if (device_info->bt_class.major_device_class != BT_MAJOR_DEVICE_CLASS_PHONE)
+ return;
+}
+
+static gboolean __on_bt_sap_cmd_cb(WcObject *wo,
+ const void *event_info, void *user_data)
+{
+ struct SAP_event_data *evt_data = NULL;
+ struct SAP_event_data *new_data = NULL;
+ char buf[SAP_DATA_LEN_MAX] = { '\0', };
+ char *bt_address = NULL;
+ // TODO: All of them should be from BT framework.
+ char *profiles = "HFP SPP GATT PAN";
+ char cod[3] = {0x28, 0x07, 0x04};
+ char services = 0x07;
+ unsigned int pos = 0;
+ int res, mainCmd, subCmd, cmdType, btVersion;
+
+ evt_data = (struct SAP_event_data *)event_info;
+ if (evt_data == NULL)
+ return TRUE;
+
+ mainCmd = (int)evt_data->data[1];
+ if (mainCmd != SAP_PDU_CMD_BLUETOOTH) {
+ ERR("Invalid bluetooth command %d", mainCmd);
+ return TRUE;
+ }
+
+ subCmd = (int)evt_data->data[2];
+ switch(subCmd) {
+ case SAP_PDU_BT_CMD_GET_VERSION:
+ DBG("SAP_PDU_BT_CMD_GET_VERSION");
+
+ cmdType = (int)evt_data->data[3];
+ switch (cmdType) {
+ case SAP_PDU_CMD_TYPE_REQ:
+ new_data = g_try_malloc0(sizeof(struct SAP_event_data));
+ if (new_data == NULL)
+ return TRUE;
+
+ new_data->count = evt_data->count;
+ new_data->index = evt_data->index;
+ new_data->data_len = SAP_DATA_LEN_MIN + 1;
+
+ buf[pos++] = (char)new_data->data_len;
+ buf[pos++] = (char)SAP_PDU_CMD_BLUETOOTH;
+ buf[pos++] = (char)SAP_PDU_BT_CMD_GET_VERSION;
+ buf[pos++] = (char)SAP_PDU_CMD_TYPE_REQ_OK;
+ buf[pos++] = (char)SAP_PDU_BT_VER_40_P;
+ memcpy(new_data->data, buf, new_data->data_len);
+
+ wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, new_data);
+ g_free(new_data);
+ break;
+ case SAP_PDU_CMD_TYPE_REQ_OK:
+ btVersion = (int)evt_data->data[SAP_DATA_LEN_MIN];
+ switch (btVersion) {
+ case SAP_PDU_BT_VER_30:
+ vconf_set_int(VCONFKEY_WECONN_CONNECTED_BT_VERSION,
+ SAP_PDU_BT_VER_30);
+ break;
+ case SAP_PDU_BT_VER_40_LE:
+ vconf_set_int(VCONFKEY_WECONN_CONNECTED_BT_VERSION,
+ SAP_PDU_BT_VER_40_LE);
+ break;
+ case SAP_PDU_BT_VER_40_DUAL:
+ vconf_set_int(VCONFKEY_WECONN_CONNECTED_BT_VERSION,
+ SAP_PDU_BT_VER_40_DUAL);
+ break;
+ case SAP_PDU_BT_VER_40_P:
+ vconf_set_int(VCONFKEY_WECONN_CONNECTED_BT_VERSION,
+ SAP_PDU_BT_VER_40_P);
+ break;
+ case SAP_PDU_BT_VER_41:
+ vconf_set_int(VCONFKEY_WECONN_CONNECTED_BT_VERSION,
+ SAP_PDU_BT_VER_41);
+ break;
+ default:
+ DBG("Unknown BT version");
+ break;
+ }
+ break;
+ }
+
+ break;
+ case SAP_PDU_BT_CMD_GET_ADDRESS:
+ DBG("SAP_PDU_BT_CMD_GET_ADDRESS");
+
+ cmdType = (int)evt_data->data[3];
+ switch (cmdType) {
+ case SAP_PDU_CMD_TYPE_REQ:
+ new_data = g_try_malloc0(sizeof(struct SAP_event_data));
+ if (new_data == NULL)
+ return TRUE;
+
+ new_data->count = evt_data->count;
+ new_data->index = evt_data->index;
+
+ res = bt_adapter_get_address(&bt_address);
+ if (res == BT_ERROR_NONE && bt_address) {
+ new_data->data_len = SAP_DATA_LEN_MIN + strlen(bt_address);
+
+ buf[pos++] = (char)new_data->data_len;
+ buf[pos++] = (char)SAP_PDU_CMD_BLUETOOTH;
+ buf[pos++] = (char)SAP_PDU_BT_CMD_GET_ADDRESS;
+ buf[pos++] = (char)SAP_PDU_CMD_TYPE_REQ_OK;
+ memcpy(&buf[pos], bt_address, strlen(bt_address));
+ memcpy(new_data->data, buf, new_data->data_len);
+
+ free(bt_address);
+ } else {
+ new_data->data_len = SAP_DATA_LEN_MIN;
+ buf[pos++] = (char)new_data->data_len;
+ buf[pos++] = (char)SAP_PDU_CMD_BLUETOOTH;
+ buf[pos++] = (char)SAP_PDU_BT_CMD_GET_ADDRESS;
+ buf[pos++] = (char)SAP_PDU_CMD_TYPE_RESP_ERR;
+ memcpy(new_data->data, buf, new_data->data_len);
+ }
+
+ wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, new_data);
+ g_free(new_data);
+ break;
+ case SAP_PDU_CMD_TYPE_REQ_OK:
+ pos = evt_data->data_len - (unsigned int)SAP_DATA_LEN_MIN;
+
+ bt_address = g_strndup(&evt_data->data[SAP_DATA_LEN_MIN], pos);
+ vconf_set_str(VCONFKEY_WECONN_AUTOCONNECTABLE_BT_ADDRESS,
+ bt_address);
+ g_free(bt_address);
+
+ break;
+ }
+
+ break;
+ case SAP_PDU_BT_CMD_GET_PROFILES:
+ DBG("SAP_PDU_BT_CMD_GET_PROFILES");
+
+ cmdType = (int)evt_data->data[3];
+ switch (cmdType) {
+ case SAP_PDU_CMD_TYPE_REQ:
+ new_data = g_try_malloc0(sizeof(struct SAP_event_data));
+ if (new_data == NULL)
+ return TRUE;
+
+ new_data->count = evt_data->count;
+ new_data->index = evt_data->index;
+ new_data->data_len = SAP_DATA_LEN_MIN + strlen(profiles);
+
+ buf[pos++] = (char)new_data->data_len;
+ buf[pos++] = (char)SAP_PDU_CMD_BLUETOOTH;
+ buf[pos++] = (char)SAP_PDU_BT_CMD_GET_PROFILES;
+ buf[pos++] = (char)SAP_PDU_CMD_TYPE_REQ_OK;
+ memcpy(&buf[pos], profiles, strlen(profiles));
+ memcpy(new_data->data, buf, new_data->data_len);
+
+ wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, new_data);
+ g_free(new_data);
+ break;
+ }
+
+ break;
+ case SAP_PDU_BT_CMD_GET_COD:
+ DBG("SAP_PDU_BT_CMD_GET_COD");
+
+ cmdType = (int)evt_data->data[3];
+ switch (cmdType) {
+ case SAP_PDU_CMD_TYPE_REQ:
+ new_data = g_try_malloc0(sizeof(struct SAP_event_data));
+ if (new_data == NULL)
+ return TRUE;
+
+ new_data->count = evt_data->count;
+ new_data->index = evt_data->index;
+ new_data->data_len = SAP_DATA_LEN_MIN + sizeof(cod);
+
+ buf[pos++] = (char)new_data->data_len;
+ buf[pos++] = (char)SAP_PDU_CMD_BLUETOOTH;
+ buf[pos++] = (char)SAP_PDU_BT_CMD_GET_COD;
+ buf[pos++] = (char)SAP_PDU_CMD_TYPE_REQ_OK;
+ memcpy(&buf[pos], cod, sizeof(cod));
+ memcpy(new_data->data, buf, new_data->data_len);
+
+ wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, new_data);
+ g_free(new_data);
+ break;
+ case SAP_PDU_CMD_TYPE_REQ_OK:
+ break;
+ }
+
+ break;
+ case SAP_PDU_BT_CMD_GET_SERVICES:
+ DBG("SAP_PDU_BT_CMD_GET_SERVICES");
+
+ cmdType = (int)evt_data->data[3];
+ switch (cmdType) {
+ case SAP_PDU_CMD_TYPE_REQ:
+ new_data = g_try_malloc0(sizeof(struct SAP_event_data));
+ if (new_data == NULL)
+ return TRUE;
+
+ new_data->count = evt_data->count;
+ new_data->index = evt_data->index;
+ new_data->data_len = SAP_DATA_LEN_MIN + 1;
+
+ buf[pos++] = (char)new_data->data_len;
+ buf[pos++] = (char)SAP_PDU_CMD_BLUETOOTH;
+ buf[pos++] = (char)SAP_PDU_BT_CMD_GET_SERVICES;
+ buf[pos++] = (char)SAP_PDU_CMD_TYPE_REQ_OK;
+ buf[pos++] = services;
+ memcpy(new_data->data, buf, new_data->data_len);
+
+ wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, new_data);
+ g_free(new_data);
+ break;
+ case SAP_PDU_CMD_TYPE_REQ_OK:
+ break;
+ }
+
+ break;
+ case SAP_PDU_BT_CMD_DISCONNECTED_MANUALLY:
+ DBG("SAP_PDU_BT_CMD_DISCONNECTED_MANUALLY");
+
+ cmdType = (int)evt_data->data[3];
+ switch (cmdType) {
+ case SAP_PDU_CMD_TYPE_NOTI:
+ new_data = g_try_malloc0(sizeof(struct SAP_event_data));
+ if (new_data == NULL)
+ return TRUE;
+
+ vconf_set_int(VCONFKEY_WECONN_DISCONNECTED_MANUALLY, 1);
+
+ new_data->count = evt_data->count;
+ new_data->index = evt_data->index;
+ new_data->data_len = SAP_DATA_LEN_MIN;
+
+ buf[pos++] = (char)new_data->data_len;
+ buf[pos++] = (char)SAP_PDU_CMD_BLUETOOTH;
+ buf[pos++] = evt_data->data[2];
+ buf[pos++] = (char)SAP_PDU_CMD_TYPE_REQ_OK;
+ memcpy(new_data->data, buf, new_data->data_len);
+
+ wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, new_data);
+ g_free(new_data);
+ break;
+ default:
+ ERR("Invalid bt sub command %d", evt_data->data[3]);
+ break;
+ }
+
+ break;
+ default:
+ ERR("Invalid bt sub command %d", evt_data->data[2]);
+ break;
+ }
+
+ return TRUE;
+}
+
+static void _bt_bearer_register_events(WcObject *wo)
+{
+ enum SAP_PDU_commands_type cmd_type = SAP_PDU_CMD_TYPE_REQ;
+ enum SAP_PDU_BT_commands bt_cmds = SAP_PDU_BT_CMD_GET_VERSION;
+ char *cmd = NULL;
+ char *event = NULL;
+
+ cmd = g_strdup_printf("%s[%d]",
+ WC_OBJECT_EVENT_SAP_RECEIVE_DATA, SAP_PDU_CMD_BLUETOOTH);
+
+ while (cmd_type < SAP_PDU_CMD_TYPE_MAX ) {
+ while (bt_cmds < SAP_PDU_BT_CMD_MAX) {
+ event = g_strdup_printf("%s[%d][%d]", cmd, bt_cmds, cmd_type);
+ wc_object_add_callback(wo, event, __on_bt_sap_cmd_cb, NULL);
+ g_free(event);
+
+ bt_cmds++;
+
+ if (bt_cmds == SAP_PDU_BT_CMD_FX_MAX)
+ bt_cmds = SAP_PDU_BT_CMD_DISCONNECTED_MANUALLY;
+ }
+
+ bt_cmds = SAP_PDU_BT_CMD_GET_VERSION;
+ cmd_type++;
+ }
+
+ g_free(cmd);
+}
+
+static void _bt_bearer_deregister_events(WcObject *wo)
+{
+ enum SAP_PDU_commands_type cmd_type = SAP_PDU_CMD_TYPE_REQ;
+ enum SAP_PDU_BT_commands bt_cmds = SAP_PDU_BT_CMD_GET_VERSION;
+ char *cmd = NULL;
+ char *event = NULL;
+
+ cmd = g_strdup_printf("%s[%d]",
+ WC_OBJECT_EVENT_SAP_RECEIVE_DATA, SAP_PDU_CMD_BLUETOOTH);
+
+ while (cmd_type < SAP_PDU_CMD_TYPE_MAX ) {
+ while (bt_cmds < SAP_PDU_BT_CMD_MAX) {
+ event = g_strdup_printf("%s[%d][%d]", cmd, bt_cmds, cmd_type);
+ wc_object_del_callback(wo, event, __on_bt_sap_cmd_cb);
+ g_free(event);
+
+ bt_cmds++;
+
+ if (bt_cmds == SAP_PDU_BT_CMD_FX_MAX)
+ bt_cmds = SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_ON;
+ }
+
+ bt_cmds = SAP_PDU_BT_CMD_GET_VERSION;
+ cmd_type++;
+ }
+
+ g_free(cmd);
+}
+
+static void _register_vconf_callback(WcObject *wo)
+{
+ int ret = VCONF_OK;
+
+ if (!wo)
+ return;
+
+ DBG("");
+
+ // TODO: use sap event callback
+ ret = vconf_notify_key_changed(VCONFKEY_SAP_CONNECTION_STATUS,
+ __sap_connection_status_changed_cb, wo);
+ if (ret != VCONF_OK)
+ ERR("Failed to register sap connection status callback(%d)", ret);
+
+ ret = vconf_notify_key_changed(VCONFKEY_RFCOMM_READY_STATUS,
+ __rfcomm_ready_status_changed_cb, wo);
+ if (ret != VCONF_OK)
+ ERR("Failed to register sap connection status callback(%d)", ret);
+
+ ret = vconf_notify_key_changed(VCONFKEY_SETUP_WIZARD_FIRST_BOOT,
+ __setup_wizard_state_cb, wo);
+ if (ret != VCONF_OK)
+ ERR("Failed to register setup wizard state callback(%d)", ret);
+
+ ret = vconf_notify_key_changed(VCONFKEY_SETAPPL_PSMODE, __power_saving_mode_cb, wo);
+ if (ret != VCONF_OK)
+ ERR("Failed to register power saving mode callback (%d)", ret);
+
+ ret = vconf_notify_key_changed(VCONFKEY_PM_KEY_IGNORE, __pm_key_ignore_cb, wo);
+ if (ret != VCONF_OK)
+ ERR("Failed to register pm key ignore callback (%d)", ret);
+}
+
+static void _deregister_vconf_callback(void)
+{
+ int ret = VCONF_OK;
+
+ DBG("");
+
+ ret = vconf_ignore_key_changed(VCONFKEY_SAP_CONNECTION_STATUS,
+ __sap_connection_status_changed_cb);
+ if (ret != VCONF_OK)
+ ERR("Failed to de-register sap connection status callback(%d)", ret);
+
+ ret = vconf_ignore_key_changed(VCONFKEY_RFCOMM_READY_STATUS,
+ __rfcomm_ready_status_changed_cb);
+ if (ret != VCONF_OK)
+ ERR("Failed to register sap connection status callback(%d)", ret);
+
+ ret = vconf_ignore_key_changed(VCONFKEY_SETUP_WIZARD_FIRST_BOOT,
+ __setup_wizard_state_cb);
+ if (ret != VCONF_OK)
+ ERR("Failed to de-register setup wizard state callback(%d)", ret);
+
+ ret = vconf_ignore_key_changed(VCONFKEY_SETAPPL_PSMODE,
+ __power_saving_mode_cb);
+ if (ret != VCONF_OK)
+ ERR("Failed to de-register power saving mode callback (%d)", ret);
+
+ ret = vconf_ignore_key_changed(VCONFKEY_PM_KEY_IGNORE,
+ __pm_key_ignore_cb);
+ if (ret != VCONF_OK)
+ ERR("Failed to de-register pm key ignore callback (%d)", ret);
+}
+
+static void _register_bt_event_listener(WcObject *wo)
+{
+ if (!wo)
+ return;
+
+ DBG("");
+
+ /* BT power event listener */
+ bt_adapter_set_state_changed_cb(
+ __on_bt_adapter_state_changed, wo);
+
+ /* BT HFP event listener */
+ bt_audio_set_connection_state_changed_cb(
+ __on_bt_audio_connection_state_changed_cb, wo);
+
+ /* BT SPP event listener */
+ /* TODO: should register eSAP event listener */
+ bt_socket_set_connection_state_changed_cb(
+ __on_bt_socket_connection_state_changed_cb, wo);
+
+ /* TODO: use HFP rather than device state */
+ bt_device_set_connection_state_changed_cb(
+ __on_bt_device_connection_state_changed_cb, wo);
+
+ bt_device_set_bond_created_cb(
+ __on_bt_device_bond_created_cb, wo);
+
+ bt_device_set_bond_destroyed_cb(
+ __on_bt_device_bond_destroy_cb, wo);
+}
+
+static void _deregister_bt_event_listener(void)
+{
+ DBG("");
+
+ bt_adapter_unset_state_changed_cb();
+
+ bt_device_unset_bond_created_cb();
+
+ bt_device_unset_connection_state_changed_cb();
+
+ bt_audio_unset_connection_state_changed_cb();
+
+ bt_socket_unset_connection_state_changed_cb();
+}
+
+static int bt_bearer_init(WcObject *wo)
+{
+ int ret;
+ int sap_conn = SAP_DISCONNECTED;
+ const char *autoconnectable_bt_address = NULL;
+ bt_adapter_state_e state = BT_ADAPTER_DISABLED;
+
+ ret = bt_initialize();
+ if (ret != BT_ERROR_NONE)
+ return ret;
+
+ ret = bt_audio_initialize();
+ if (ret != BT_ERROR_NONE)
+ return ret;
+
+ ret = alarmmgr_init("weconn");
+ if (ret != ALARMMGR_RESULT_SUCCESS)
+ ERR("alarmmgr_init FAILED (%d)", ret);
+
+ ret = bt_adapter_get_state(&state);
+ if (ret != BT_ERROR_NONE)
+ return ret;
+
+ if (state == BT_ADAPTER_ENABLED) {
+ wc_object_emit_callback(wo, WC_OBJECT_EVENT_BEARER_ENABLED, NULL);
+
+ /* Update SPP state */
+ if (vconf_get_int(VCONFKEY_SAP_CONNECTION_STATUS, &sap_conn) < 0) {
+ ERR("Failed to get sap connection status, but go ahead.");
+ sap_connected = SAP_DISCONNECTED;
+ } else
+ sap_connected = sap_conn;
+
+ autoconnectable_bt_address =
+ vconf_get_str(VCONFKEY_WECONN_AUTOCONNECTABLE_BT_ADDRESS);
+ DBG("last connected BT address(%s)", autoconnectable_bt_address);
+ if (autoconnectable_bt_address &&
+ strlen(autoconnectable_bt_address) > 0) {
+ /* Update HFP status */
+ hf_connected = __bt_check_connection_status(
+ autoconnectable_bt_address, __device_check_hfp_cb);
+ } else {
+ /* If not, clear white list, for example, factory reset */
+ __bt_update_white_list(NULL, 0);
+ }
+
+ g_free((gpointer)autoconnectable_bt_address);
+
+ DBG("BT power(%d), rfcomm_ready(%d), SPP(%d) HFP(%d)",
+ state, sap_rfcomm_ready, sap_connected, hf_connected);
+ if (sap_rfcomm_ready == 1 &&
+ sap_connected != SAP_CONNECTED && hf_connected != true)
+ __bt_start_advertising(true);
+
+ wc_object_set_property(wo, XSTR(W_DEVICE_TYPE_BT),
+ XSTR(W_DEVICE_STATE_ENABLED));
+ }
+
+ _register_vconf_callback(wo);
+
+ _register_bt_event_listener(wo);
+
+ _bt_bearer_register_events(wo);
+
+ return ret;
+}
+
+static int bt_bearer_activate(WcObject *wo)
+{
+ int ret;
+ bt_adapter_state_e state = BT_ADAPTER_DISABLED;
+
+ ret = bt_adapter_get_state(&state);
+ if (ret != BT_ERROR_NONE)
+ return ret;
+
+ DBG("BT state = %d", state);
+ if (state == BT_ADAPTER_DISABLED) {
+ ret = bt_adapter_enable();
+ if (ret != BT_ERROR_NONE) {
+ ERR("Failed to enable bluetooth device");
+ return ret;
+ }
+ }
+
+ DBG("Activated");
+
+ return 0;
+}
+
+static int bt_bearer_deactivate(WcObject *wo)
+{
+ int ret;
+ bt_adapter_state_e state = BT_ADAPTER_DISABLED;
+
+ DBG("Deactivated");
+
+ ret = bt_adapter_get_state(&state);
+ if (ret != BT_ERROR_NONE)
+ return ret;
+
+ DBG("BT state = %d", state);
+ if (state == BT_ADAPTER_ENABLED)
+ bt_adapter_disable();
+
+ return 0;
+}
+
+static void bt_bearer_exit(WcObject *wo)
+{
+ DBG("Unloaded");
+
+ _bt_bearer_deregister_events(wo);
+
+ _deregister_vconf_callback();
+
+ _deregister_bt_event_listener();
+
+ bt_deinitialize();
+
+ alarmmgr_fini();
+}
+
+EXPORT_API struct bearer_driver_desc bearer_driver_desc = {
+ .name = "bluetooth",
+ .technology = WC_TECHNOLOGY_BLUETOOTH,
+
+ .init = bt_bearer_init,
+ .activate = bt_bearer_activate,
+ .deactivate = bt_bearer_deactivate,
+ .exit = bt_bearer_exit,
+};
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <vconf.h>
+#include <vconf-keys.h>
+#include <system_info.h>
+#include <SAPInterface.h>
+
+#include "esap.h"
+#include "control.h"
+#include "plugin.h"
+
+
+#define BUF_SIZE 1024
+#define SAP_CHANNEL_ID 222
+
+#define SAP_CONNECTION_VCONF_NOTIFICATION "memory/private/sap/conn_status"
+
+struct esap_private_data {
+ WcObject *wo_esap;
+ unsigned char role;
+};
+
+static unsigned int sap_service_handle;
+static unsigned int sap_local_agentId;
+static struct esap_private_data *gpd;
+static GSList *send_pdu_list = NULL;
+
+static int __util_send_sap_pdu_data(GSList *pdu_list);
+static int __util_process_sap_pdu_data(WcObject *wo, GSList **pdu_list);
+static unsigned int __util_encode_sap_pdu_data(GSList *pdu_list, char **dst);
+static int __util_decode_sap_pdu_data(char *src, unsigned int src_len, GSList **pdu_list);
+
+static int __util_process_sap_pdu_data(WcObject *wo, GSList **pdu_list)
+{
+ unsigned int index = 0;
+ int count = 0;
+ char *event;
+ GSList *list;
+ struct SAP_PDU_data *pdu_data = NULL;
+ struct SAP_event_data *evt_data = NULL;
+
+ index = g_slist_length(send_pdu_list);
+ for (list = *pdu_list; list; list = list->next) {
+ pdu_data = (struct SAP_PDU_data *)list->data;
+ if (pdu_data != NULL) {
+ evt_data = g_try_malloc0(sizeof(struct SAP_event_data));
+ if (evt_data == NULL)
+ return -1;
+
+ evt_data->index = index;
+ evt_data->count = g_slist_length(*pdu_list);
+ evt_data->data_len = (unsigned int)pdu_data->length;
+ memcpy(evt_data->data, pdu_data->data, evt_data->data_len);
+
+ event = g_strdup_printf("%s[%d][%d][%d]", WC_OBJECT_EVENT_SAP_RECEIVE_DATA,
+ evt_data->data[1], evt_data->data[2], evt_data->data[3]);
+
+ wc_object_emit_callback(wo, event, evt_data);
+ g_free(evt_data);
+ g_free(event);
+ count++;
+ }
+ }
+
+ return count;
+}
+
+static int __util_send_sap_pdu_data(GSList *pdu_list)
+{
+ char *buf;
+ unsigned int len = 0;
+ int res = -1;
+
+ if (g_slist_length(pdu_list) <= 0) {
+ ERR("No PDU data to send");
+ return -1;
+ }
+
+ len = __util_encode_sap_pdu_data(pdu_list, &buf);
+ if (len > 0) {
+ res = sendData(sap_service_handle, SAP_CHANNEL_ID, (unsigned short int)len, (void*)buf);
+ if (res == 0)
+ DBG("Completed to send data %d byte", len);
+ else
+ ERR("Failed to send data, error %d", res);
+
+ g_free(buf);
+ }
+
+ return res;
+}
+
+static unsigned int __util_encode_sap_pdu_data(GSList *pdu_list, char **dst)
+{
+ GSList *list;
+ struct SAP_PDU_data *pdu_data = NULL;
+ char buf[SAP_DATA_LEN_MAX] = {0};
+ unsigned int length = 0;
+ unsigned int index = 0;
+
+ for (list = pdu_list; list != NULL; list = list->next) {
+ pdu_data = (struct SAP_PDU_data *)list->data;
+ if (pdu_data != NULL) {
+ if (pdu_data->main_cmd == 0 || pdu_data->sub_cmd == 0 ||
+ pdu_data->type_cmd == 0) {
+ ERR("Invalid PDU data: main_cmd[%d], sub_cmd[%d], type_cmd[%d]",
+ pdu_data->main_cmd, pdu_data->sub_cmd, pdu_data->type_cmd);
+ continue;
+ }
+
+ length = (unsigned int)pdu_data->length + (unsigned int)SAP_DATA_LEN_MIN;
+ buf[index++] = (char)length;
+ buf[index++] = pdu_data->main_cmd;
+ buf[index++] = pdu_data->sub_cmd;
+ buf[index++] = pdu_data->type_cmd;
+ memcpy(&buf[index], pdu_data->data, (unsigned int)pdu_data->length);
+
+ index += (unsigned int)pdu_data->length;
+ }
+ }
+
+ *dst = g_try_malloc0(index + 1);
+ g_strlcat(*dst, buf, index + 1);
+
+ DBG("Completed to encode data %d byte", index);
+ return index;
+}
+
+static int __util_decode_sap_pdu_data(char *src, unsigned int src_len, GSList **pdu_list)
+{
+ int res = -1;
+ unsigned int pos = 0;
+ unsigned int data_len = 0;
+ struct SAP_PDU_data *pdu_data = NULL;
+
+ if (src_len < SAP_DATA_LEN_MIN) {
+ ERR("invalid data length, %d", src_len);
+ return res;
+ }
+
+ while (pos < src_len) {
+ pdu_data = g_try_malloc0(sizeof(struct SAP_PDU_data));
+ if (!pdu_data || !src) {
+ ERR("invalid input parameter !!!");
+ return res;
+ }
+
+ data_len = (unsigned int)src[pos];
+ if (data_len < SAP_DATA_LEN_MIN) {
+ ERR("invalid pdu data length, %d", data_len);
+ goto error;
+ }
+
+ memcpy(pdu_data->data, &src[pos], data_len);
+ pdu_data->length = (char)data_len;
+
+ *pdu_list = g_slist_append(*pdu_list, pdu_data);
+ pos += data_len;
+ }
+
+ if (*pdu_list) {
+ res = (int)g_slist_length(*pdu_list);
+ DBG("Done decode data counts = %d", res);
+ }
+
+ return res;
+
+error:
+ if (g_slist_length(*pdu_list) > 0)
+ g_slist_free_full(*pdu_list, g_free);
+ else {
+ if (pdu_data != NULL)
+ g_free(pdu_data);
+ }
+
+ return res;
+}
+
+static int _request_feature_exchange(GSList *feat_list)
+{
+ GSList *list;
+ GSList *pdu_list = NULL;
+ struct SAP_PDU_data *sap_data = NULL;
+
+ if (feat_list == NULL)
+ return 0;
+
+ for (list = feat_list; list != NULL; list = list->next) {
+ if (g_strcmp0(list->data, XSTR(SAP_PDU_BT_CMD_GET_VERSION)) == 0) {
+ sap_data = g_try_malloc0(sizeof(struct SAP_PDU_data));
+ if (!sap_data) {
+ ERR("invalid input parameter !!!");
+ return -1;
+ }
+
+ sap_data->main_cmd = SAP_PDU_CMD_BLUETOOTH;
+ sap_data->sub_cmd = SAP_PDU_BT_CMD_GET_VERSION;
+ sap_data->type_cmd = SAP_PDU_CMD_TYPE_REQ;
+ pdu_list = g_slist_append(pdu_list, sap_data);
+ } else if (g_strcmp0(list->data, XSTR(SAP_PDU_BT_CMD_GET_ADDRESS)) == 0) {
+ sap_data = g_try_malloc0(sizeof(struct SAP_PDU_data));
+ if (!sap_data) {
+ ERR("invalid input parameter !!!");
+ return -1;
+ }
+
+ sap_data->main_cmd = SAP_PDU_CMD_BLUETOOTH;
+ sap_data->sub_cmd = SAP_PDU_BT_CMD_GET_ADDRESS;
+ sap_data->type_cmd = SAP_PDU_CMD_TYPE_REQ;
+ pdu_list = g_slist_append(pdu_list, sap_data);
+ } else if (g_strcmp0(list->data, XSTR(SAP_PDU_BT_CMD_GET_PROFILES)) == 0) {
+ sap_data = g_try_malloc0(sizeof(struct SAP_PDU_data));
+ if (!sap_data) {
+ ERR("invalid input parameter !!!");
+ return -1;
+ }
+
+ sap_data->main_cmd = SAP_PDU_CMD_BLUETOOTH;
+ sap_data->sub_cmd = SAP_PDU_BT_CMD_GET_PROFILES;
+ sap_data->type_cmd = SAP_PDU_CMD_TYPE_REQ;
+ pdu_list = g_slist_append(pdu_list, sap_data);
+ } else if (g_strcmp0(list->data, XSTR(SAP_PDU_GENERIC_CMD_GET_MANUFACTURER)) == 0) {
+ sap_data = g_try_malloc0(sizeof(struct SAP_PDU_data));
+ if (!sap_data) {
+ ERR("invalid input parameter !!!");
+ return -1;
+ }
+
+ sap_data->main_cmd = SAP_PDU_CMD_GENERIC;
+ sap_data->sub_cmd = SAP_PDU_GENERIC_CMD_GET_MANUFACTURER;
+ sap_data->type_cmd = SAP_PDU_CMD_TYPE_REQ;
+ pdu_list = g_slist_append(pdu_list, sap_data);
+ } else {
+ ERR("Not support feature : %s", (char *)list->data);
+ }
+ }
+
+ __util_send_sap_pdu_data(pdu_list);
+
+ g_slist_free_full(pdu_list, g_free);
+
+ return 0;
+}
+
+static void on_register_service_agent_confirm(int wStatusCode, unsigned int uwLocalAgentId)
+{
+ DBG("wStatusCode: %d, uwLocalAgentId: %d", wStatusCode, uwLocalAgentId);
+
+ if (wStatusCode != RESULT_SUCCESS) {
+ DBG("Register service agent failed.\n");
+ return;
+ }
+
+ sap_local_agentId = uwLocalAgentId;
+
+ if (gpd->role == SAP_ROLE_PROVIDER) {
+ DBG("No need to call findPeerAgent!!");
+ return;
+ }
+
+ if (findPeerAgent(uwLocalAgentId) != RESULT_SUCCESS) {
+ DBG("fail to call findPeerAgent.\n");
+ // TBD: error handling
+ return;
+ }
+ DBG("success to call findPeerAgent\n");
+}
+
+static void on_deregister_service_agent_confirm(int wStatusCode, unsigned int uwLocalAgentId)
+{
+ DBG("wStatusCode: %d, uwLocalAgentId: %d", wStatusCode, uwLocalAgentId);
+}
+
+static void on_peer_agent(unsigned int uwLocalAgentId, PeerAgent* pPeerAgent, int wStatusCode)
+{
+ DBG("wStatusCode: %d, uwLocalAgentId: %d", wStatusCode, uwLocalAgentId);
+
+ if (wStatusCode != RESULT_SUCCESS) {
+ DBG("find peer agent failed.");
+ //TBD: error handling
+ return;
+ } else if (wStatusCode == RESULT_SUCCESS) {
+ DBG("find peer agent success: ALE Name %s, Id %s", pPeerAgent->pchALEName, pPeerAgent->pchASPID);
+
+ if(createServiceConnection(uwLocalAgentId, pPeerAgent) != RESULT_SUCCESS) {
+ ERR("fail to create service connection");
+ // TBD: error handling
+ return;
+ }
+ }
+}
+
+static void on_service_connection_confirm(unsigned int uwLocalAgentId, unsigned int uwServiceHandle, PeerAgent* pPeerAgent, int wStatusCode)
+{
+ DBG("uwLocalAgentId: %d, uwServiceHandle: %d, wStatusCode: %d", uwLocalAgentId, uwServiceHandle, wStatusCode);
+
+ if (wStatusCode != RESULT_SUCCESS) {
+ DBG("service connection fail.\n");
+ // TBD: retry logic
+ } else {
+ DBG("service connection success.\n");
+ sap_service_handle = uwServiceHandle;
+ }
+}
+
+static void on_service_connection_indication(unsigned int uwLocalAgentId, unsigned int uwServiceHandle, PeerAgent* pPeerAgent)
+{
+ WcObject *wo = NULL;
+
+ DBG("uwLocalAgentId: %d, uwServiceHandle: %d",
+ uwLocalAgentId, uwServiceHandle);
+
+ if (acceptServiceConnection(uwLocalAgentId, uwServiceHandle,
+ pPeerAgent) != RESULT_SUCCESS) {
+ ERR("fail to accept service connection");
+ // TBD: error handling
+ return;
+ } else {
+ GSList *list = NULL;
+
+ DBG("success to accept service connection");
+ // wait for service connection confirm? - Need to check.
+ sap_service_handle = uwServiceHandle;
+
+ wo = wc_object_find(WC_TECHNOLOGY_BLUETOOTH);
+ if (wo) {
+ wc_object_set_property(wo, WC_OBJECT_EVENT_SAP_BCMSERVICE_STATUS,
+ XSTR(W_SERVICE_STATE_CONNECTED));
+ }
+
+ list = g_slist_append(list, XSTR(SAP_PDU_BT_CMD_GET_VERSION));
+ list = g_slist_append(list, XSTR(SAP_PDU_GENERIC_CMD_GET_MANUFACTURER));
+
+ _request_feature_exchange(list);
+ }
+}
+
+static void on_service_termination_indication(unsigned int uwServiceHandle, int wStatusCode)
+{
+ WcObject *wo = NULL;
+
+ DBG("uwServiceHandle: %d, wStatusCode: %d", uwServiceHandle, wStatusCode);
+
+ wo = wc_object_find(WC_TECHNOLOGY_BLUETOOTH);
+ if (!wo) {
+ ERR("No technology");
+ return;
+ }
+
+ wc_object_set_property(wo, WC_OBJECT_EVENT_SAP_BCMSERVICE_STATUS,
+ XSTR(W_SERVICE_STATE_DISCONNECTED));
+}
+
+static void on_receive(unsigned int uwServiceHandle,
+ unsigned short int uwChannelId,
+ unsigned int uwPayloadLength, void *pvBuffer)
+{
+ int res = 0;
+ WcObject *wo = NULL;
+ GSList *pdu_list = NULL;
+ char payload[BUF_SIZE] = { '\0', };
+
+ if (pvBuffer == NULL)
+ return;
+
+ DBG("uwServiceHandle:%d, uwChannelId:%d, uwPayloadLength:%d\n",
+ uwServiceHandle, uwChannelId, uwPayloadLength);
+
+ wo = wc_object_find(WC_TECHNOLOGY_BLUETOOTH);
+ if (!wo) {
+ ERR("No technology");
+ return;
+ }
+
+ memset(payload, 0, BUF_SIZE);
+ memcpy(payload, pvBuffer, uwPayloadLength);
+
+ res = __util_decode_sap_pdu_data(payload, uwPayloadLength, &pdu_list);
+ if (res > 0) {
+ res = __util_process_sap_pdu_data(wo, &pdu_list);
+ DBG("processed %d data", res);
+ } else {
+ ERR("Mal-formed data");
+ }
+}
+
+static void on_space_available(unsigned int uwServiceHandle,
+ unsigned short int uwChannelId, unsigned int ulSpaceAvailable)
+{
+ DBG("uwChannelId: %d, ulSpaceAvailable: %d", uwChannelId, ulSpaceAvailable);
+}
+
+static void on_error(unsigned int uwServiceHandle, unsigned int dwErrorCode)
+{
+ DBG("uwServiceHandle: %d, dwErrorCode: %d\n", uwServiceHandle, dwErrorCode);
+}
+
+static SAPNotification sap_noti_funcs = {
+ on_register_service_agent_confirm,
+ on_receive,
+ on_service_connection_indication,
+ on_service_termination_indication,
+ on_service_connection_confirm,
+ on_peer_agent,
+ on_space_available,
+ on_error,
+ on_deregister_service_agent_confirm,
+};
+
+static gboolean _esap_service_init(WcObject *wo)
+{
+ ServiceDesc *service;
+ ChannelDesc *channel;
+ int ret;
+
+ if (!gpd || !wo)
+ return FALSE;
+
+ // register callbacks
+ ret = registerNotifications(sap_noti_funcs);
+ if (ret != RESULT_SUCCESS) {
+ ERR("Fail to register notification");
+ return FALSE;
+ }
+
+ DBG("registerNotifications success: sap_service_handle %d", sap_service_handle);
+ // Define service description
+ service = (ServiceDesc *)g_try_malloc0(sizeof(ServiceDesc));
+ if (service == NULL) {
+ ERR("Memory allocation fail for ServiceDesc");
+ return FALSE;
+ }
+
+ channel = (ChannelDesc *)g_try_malloc0(sizeof(ChannelDesc));
+ if (channel == NULL) {
+ ERR("Memory allocation fail for ChannelDesc");
+ g_free(service);
+ return FALSE;
+ }
+
+ channel->wChannelID = SAP_CHANNEL_ID;
+ channel->ubNoOfPayloadType = 1; // which value is to be set???
+ channel->payloadTypeList = SAP_ALL_PAYLOAD; // Json or binary
+
+ service->pchASPID = "/system/bcmservice";
+ service->pchSPFName = "/system/bcmservice";
+ service->wConnectionTypeMask = SAP_ALL; // all connectivity
+ service->ubRole = gpd->role;
+ service->pChDescArray = channel;
+ service->numChannels = 1;
+
+ // register service
+ // ret = getRegisteredServiceAgent(service->pchASPID, SERVICE_AGENT_ROLE_PROVIDER);
+ ret = registerServiceAgent(service);
+ if (ret != RESULT_SUCCESS) {
+ ERR("registerServiceAgent Fail with reason: %d", ret);
+ g_free(service);
+ g_free(channel);
+ return FALSE;
+ }
+
+ wc_object_set_property(wo, WC_OBJECT_EVENT_SAP_BCMSERVICE_STATUS,
+ XSTR(W_SERVICE_STATE_DISCONNECTED));
+
+ DBG("SAP service registered(%s)", (gpd->role == SAP_ROLE_PROVIDER) ? "PROVIDER" : "CONSUMER");
+ return TRUE;
+}
+
+static gboolean __on_esap_event_send_data_cb(WcObject *wo,
+ const void *event_info, void *user_data)
+{
+ struct SAP_event_data *evt_data = NULL;
+ struct SAP_send_data *send_data = NULL;
+ int res;
+
+ evt_data = (struct SAP_event_data *)event_info;
+ if (evt_data == NULL)
+ return TRUE;
+
+ if (evt_data->count > 1) {
+ send_data = g_slist_nth_data(send_pdu_list, evt_data->index);
+ if (send_data == NULL) {
+ send_data = g_try_malloc0(sizeof(struct SAP_send_data));
+ if (send_data == NULL)
+ return TRUE;
+
+ send_data->count = 1;
+ send_data->data_len = evt_data->data_len;
+ memcpy(send_data->data, evt_data->data, evt_data->data_len);
+ send_pdu_list = g_slist_append(send_pdu_list, send_data);
+ } else {
+ send_data->count++;
+
+ if (send_data->count == evt_data->count) {
+ memcpy(&send_data->data[send_data->data_len],
+ evt_data->data, evt_data->data_len);
+ send_data->data_len += evt_data->data_len;
+
+ res = sendData(sap_service_handle, SAP_CHANNEL_ID,
+ (unsigned short int)send_data->data_len,
+ (void*)send_data->data);
+ if (res == 0)
+ DBG("Completed to send data %d byte", send_data->data_len);
+ else
+ ERR("Failed to send data, error %d", res);
+
+ g_free(send_data);
+ send_pdu_list = g_slist_remove(send_pdu_list, send_data);
+ } else {
+ memcpy(&send_data->data[send_data->data_len],
+ evt_data->data, evt_data->data_len);
+ send_data->data_len += evt_data->data_len;
+ }
+ }
+ } else {
+ res = sendData(sap_service_handle, SAP_CHANNEL_ID,
+ (unsigned short int)evt_data->data_len,
+ (void*)evt_data->data);
+ if (res == 0)
+ DBG("Completed to send data %d byte", evt_data->data_len);
+ else
+ ERR("Failed to send data, error %d", res);
+ }
+
+ return TRUE;
+}
+
+static gboolean _on_generic_sap_cmd_cb(WcObject *wo,
+ const void *event_info, void *user_data)
+{
+ struct SAP_event_data *evt_data = NULL;
+ struct SAP_event_data *new_data = NULL;
+ char buf[SAP_DATA_LEN_MAX] = { '\0', };
+ char *value = NULL;
+ unsigned int len;
+ unsigned int pos = 0;
+ int mainCmd, subCmd, cmdType;
+ int ret;
+
+ evt_data = (struct SAP_event_data *)event_info;
+ if (evt_data == NULL)
+ return TRUE;
+
+ mainCmd = (int)evt_data->data[1];
+ if (mainCmd != SAP_PDU_CMD_GENERIC) {
+ ERR("Invalid generic command %d", mainCmd);
+ return TRUE;
+ }
+
+ subCmd = (int)evt_data->data[2];
+ switch (subCmd) {
+ case SAP_PDU_GENERIC_CMD_GET_PLATFORM_NAME:
+ DBG("SAP_PDU_GENERIC_CMD_GET_PLATFORM_NAME");
+
+ cmdType = (int)evt_data->data[3];
+ switch (cmdType) {
+ case SAP_PDU_CMD_TYPE_REQ:
+ ret = system_info_get_value_string(SYSTEM_INFO_KEY_PLATFORM_NAME,
+ &value);
+ if (ret == 0 && value != NULL) {
+ new_data = g_try_malloc0(sizeof(struct SAP_event_data));
+ if (new_data == NULL)
+ return TRUE;
+
+ new_data->count = evt_data->count;
+ new_data->index = evt_data->index;
+ new_data->data_len = SAP_DATA_LEN_MIN + strlen(value);
+
+ buf[pos++] = (char)new_data->data_len;
+ buf[pos++] = (char)SAP_PDU_CMD_GENERIC;
+ buf[pos++] = (char)SAP_PDU_GENERIC_CMD_GET_PLATFORM_VERSION;
+ buf[pos++] = (char)SAP_PDU_CMD_TYPE_REQ_OK;
+ memcpy(&buf[pos], value, strlen(value));
+ memcpy(new_data->data, buf, new_data->data_len);
+
+ g_free(value);
+
+ wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, new_data);
+ g_free(new_data);
+ }
+ break;
+ case SAP_PDU_CMD_TYPE_REQ_OK:
+ break;
+ default:
+ break;
+ }
+ break;
+ case SAP_PDU_GENERIC_CMD_GET_PLATFORM_VERSION:
+ DBG("SAP_PDU_GENERIC_CMD_GET_PLATFORM_VERSION");
+
+ cmdType = (int)evt_data->data[3];
+ switch (cmdType) {
+ case SAP_PDU_CMD_TYPE_REQ:
+ ret = system_info_get_value_string(SYSTEM_INFO_KEY_TIZEN_VERSION,
+ &value);
+ if (ret == 0 && value != NULL) {
+ new_data = g_try_malloc0(sizeof(struct SAP_event_data));
+ if (new_data == NULL)
+ return TRUE;
+
+ new_data->count = evt_data->count;
+ new_data->index = evt_data->index;
+ new_data->data_len = SAP_DATA_LEN_MIN + strlen(value);
+
+ buf[pos++] = (char)new_data->data_len;
+ buf[pos++] = (char)SAP_PDU_CMD_GENERIC;
+ buf[pos++] = (char)SAP_PDU_GENERIC_CMD_GET_PLATFORM_VERSION;
+ buf[pos++] = (char)SAP_PDU_CMD_TYPE_REQ_OK;
+ memcpy(&buf[pos], value, strlen(value));
+ memcpy(new_data->data, buf, new_data->data_len);
+
+ g_free(value);
+
+ wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, new_data);
+ g_free(new_data);
+ }
+ break;
+ case SAP_PDU_CMD_TYPE_REQ_OK:
+ break;
+ default:
+ ERR("Invalid generic type command(%d)", cmdType);
+ break;
+ }
+ break;
+ case SAP_PDU_GENERIC_CMD_GET_MANUFACTURER:
+ DBG("SAP_PDU_GENERIC_CMD_GET_MANUFACTURER");
+
+ cmdType = (int)evt_data->data[3];
+ switch (cmdType) {
+ case SAP_PDU_CMD_TYPE_REQ:
+ ret = system_info_get_value_string(SYSTEM_INFO_KEY_MANUFACTURER,
+ &value);
+ if (ret == 0 && value != NULL) {
+ new_data = g_try_malloc0(sizeof(struct SAP_event_data));
+ if (new_data == NULL)
+ return TRUE;
+
+ new_data->count = evt_data->count;
+ new_data->index = evt_data->index;
+ new_data->data_len = SAP_DATA_LEN_MIN + strlen(value);
+
+ buf[pos++] = (char)new_data->data_len;
+ buf[pos++] = (char)SAP_PDU_CMD_GENERIC;
+ buf[pos++] = (char)SAP_PDU_GENERIC_CMD_GET_MANUFACTURER;
+ buf[pos++] = (char)SAP_PDU_CMD_TYPE_REQ_OK;
+ memcpy(&buf[pos], value, strlen(value));
+ memcpy(new_data->data, buf, new_data->data_len);
+
+ g_free(value);
+
+ wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, new_data);
+ g_free(new_data);
+ }
+ break;
+ case SAP_PDU_CMD_TYPE_REQ_OK:
+ len = evt_data->data_len - (unsigned int)SAP_DATA_LEN_MIN;
+
+ value = g_strndup(&evt_data->data[SAP_DATA_LEN_MIN], len);
+ vconf_set_str(VCONFKEY_WECONN_CONNECTED_MANUFACTURER, value);
+
+ g_free(value);
+ break;
+ case SAP_PDU_CMD_TYPE_RESP_ERR:
+ break;
+ case SAP_PDU_CMD_TYPE_NOTI:
+ break;
+ default:
+ ERR("Invalid generic type command(%d)", cmdType);
+ break;
+ }
+ break;
+ default:
+ ERR("Invalid generic sub command(%d)", subCmd);
+ break;
+ }
+
+ return TRUE;
+}
+
+static void _esap_bearer_register_events(WcObject *wo)
+{
+ enum SAP_PDU_commands_type cmd_type = SAP_PDU_CMD_TYPE_REQ;
+ enum SAP_PDU_GENERIC_commands generic_cmds = SAP_PDU_GENERIC_CMD_GET_PLATFORM_NAME;
+ char *cmd = NULL;
+ char *event = NULL;
+
+ cmd = g_strdup_printf("%s[%d]",
+ WC_OBJECT_EVENT_SAP_RECEIVE_DATA, SAP_PDU_CMD_GENERIC);
+
+ while (cmd_type < SAP_PDU_CMD_TYPE_MAX ) {
+ while (generic_cmds < SAP_PDU_GENERIC_CMD_MAX) {
+ event = g_strdup_printf("%s[%d][%d]", cmd, generic_cmds, cmd_type);
+ wc_object_add_callback(wo, event, _on_generic_sap_cmd_cb, NULL);
+ g_free(event);
+
+ generic_cmds++;
+ }
+
+ generic_cmds = SAP_PDU_GENERIC_CMD_GET_PLATFORM_NAME;
+ cmd_type++;
+ }
+
+ wc_object_add_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA,
+ __on_esap_event_send_data_cb, NULL);
+
+ g_free(cmd);
+}
+
+static void _esap_bearer_deregister_events(WcObject *wo)
+{
+ enum SAP_PDU_commands_type cmd_type = SAP_PDU_CMD_TYPE_REQ;
+ enum SAP_PDU_GENERIC_commands generic_cmds = SAP_PDU_GENERIC_CMD_GET_PLATFORM_NAME;
+ char *cmd = NULL;
+ char *event = NULL;
+
+ cmd = g_strdup_printf("%s[%d]",
+ WC_OBJECT_EVENT_SAP_RECEIVE_DATA, SAP_PDU_CMD_GENERIC);
+
+ while (cmd_type < SAP_PDU_CMD_TYPE_MAX ) {
+ while (generic_cmds < SAP_PDU_GENERIC_CMD_MAX) {
+ event = g_strdup_printf("%s[%d][%d]", cmd, generic_cmds, cmd_type);
+ wc_object_del_callback(wo, event, _on_generic_sap_cmd_cb);
+ g_free(event);
+
+ generic_cmds++;
+ }
+
+ generic_cmds = SAP_PDU_GENERIC_CMD_GET_PLATFORM_NAME;
+ cmd_type++;
+ }
+
+ wc_object_del_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA,
+ __on_esap_event_send_data_cb);
+
+ g_free(cmd);
+}
+
+static void __esap_connection_changed_cb(keynode_t *key, void *data)
+{
+ int status = 0;
+ WcObject *wo = (WcObject *)data;
+
+ vconf_get_int(SAP_CONNECTION_VCONF_NOTIFICATION, &status);
+ DBG("status : %d", status);
+
+ if (status == 1) {
+ _esap_service_init(wo);
+
+ _esap_bearer_register_events(wo);
+ } else {
+ DBG("%s is disconnected", SAP_CONNECTION_VCONF_NOTIFICATION);
+
+ _esap_bearer_deregister_events(wo);
+
+ wc_object_set_property(wo, WC_OBJECT_EVENT_SAP_BCMSERVICE_STATUS,
+ XSTR(W_SERVICE_STATE_DISCONNECTED));
+ }
+}
+
+static int esap_bearer_init(WcObject *wo)
+{
+ int type;
+ unsigned char role;
+
+ type = wc_control_get_device_type();
+ if (type == PROP_CONTROL_TYPE_WEARABLE) {
+ role = SAP_ROLE_PROVIDER;
+ } else if (type == PROP_CONTROL_TYPE_HOST) {
+ role = SAP_ROLE_CONSUMER;
+ } else {
+ ERR("Unknown type");
+ return -EINVAL;
+ }
+
+ gpd = g_try_new0(struct esap_private_data, 1);
+ if (!gpd)
+ return -ENOMEM;
+
+ /* FIXME: why WcObject -> wo.element -> WcObject (circular dependency) */
+ gpd->wo_esap = wo;
+ gpd->role = role;
+
+ /* FIXEME: test code */
+ do {
+ int status = 0;
+ vconf_get_int(SAP_CONNECTION_VCONF_NOTIFICATION, &status);
+
+ if (status == 1)
+ _esap_service_init(wo);
+ else
+ vconf_notify_key_changed(SAP_CONNECTION_VCONF_NOTIFICATION,
+ __esap_connection_changed_cb, wo);
+ } while(0);
+
+ return 0;
+}
+
+static int esap_bearer_activate(WcObject *wo)
+{
+ gboolean ret;
+
+ ret = _esap_service_init(wo);
+ DBG("Activated: %d", ret);
+ return 0;
+}
+
+static int esap_bearer_deactivate(WcObject *wo)
+{
+ DBG("Deactivated");
+
+ return 0;
+}
+
+static int esap_bearer_connect(WcObject *wo, const char* address)
+{
+ DBG("Connected");
+ // TBD: request connect() through SAP interface
+ return 0;
+}
+
+static int esap_bearer_disconnect(WcObject *wo)
+{
+ DBG("Disconnected");
+ // TBD: request disconnect() through SAP interface
+ return 0;
+}
+
+static void esap_bearer_exit(WcObject *wo)
+{
+ vconf_ignore_key_changed(SAP_CONNECTION_VCONF_NOTIFICATION,
+ __esap_connection_changed_cb);
+
+ if (gpd) {
+ g_free(gpd);
+ gpd = NULL;
+ }
+}
+
+EXPORT_API struct bearer_driver_desc bearer_driver_desc = {
+ .name = "esap",
+ .technology = WC_TECHNOLOGY_BLUETOOTH,
+
+ .init = esap_bearer_init,
+ .activate = esap_bearer_activate,
+ .deactivate = esap_bearer_deactivate,
+ .connect = esap_bearer_connect,
+ .disconnect = esap_bearer_disconnect,
+ .exit = esap_bearer_exit,
+};
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __WECONN_ESAP_H__
+#define __WECONN_ESAP_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "log.h"
+#include "events.h"
+#include "object.h"
+
+#define SAP_ROLE_PROVIDER 0x00
+#define SAP_ROLE_CONSUMER 0x01
+
+#define SAP_DATA_LEN_MIN 4
+#define SAP_DATA_LEN_MAX 255
+#define SAP_DATA_MAC_ADDR_LEN 17
+
+#define VCONFKEY_WECONN_CONNECTED_BT_VERSION \
+ "file/private/weconn/connected_bt_version"
+#define VCONFKEY_WECONN_DISCONNECTED_MANUALLY \
+ "file/private/weconn/disconnected_manually"
+#define VCONFKEY_WECONN_CONNECTED_MANUFACTURER \
+ "file/private/weconn/connected_manufacturer"
+#define VCONFKEY_WECONN_AUTOCONNECTABLE_BT_ADDRESS \
+ "file/private/weconn/autoconnectable_unique_bt_target_address"
+
+#define VCONFKEY_WECONN_ALL_CONNECTED "memory/private/weconn/all_connected"
+#define VCONFKEY_RFCOMM_READY_STATUS "memory/private/sap/rfcomm_ready"
+#define VCONFKEY_SAP_CONNECTION_STATUS "memory/private/sap/conn_status"
+#define SAP_DISCONNECTED 0
+#define SAP_CONNECTED 1
+
+enum SAP_PDU_commands_type {
+ SAP_PDU_CMD_TYPE_REQ = 0x01,
+ SAP_PDU_CMD_TYPE_REQ_OK = 0x02,
+ SAP_PDU_CMD_TYPE_RESP_ERR = 0x03,
+ SAP_PDU_CMD_TYPE_NOTI = 0x04,
+ SAP_PDU_CMD_TYPE_MAX = 0x05,
+};
+
+enum SAP_PDU_commands {
+ SAP_PDU_CMD_GENERIC = 0x01,
+ SAP_PDU_CMD_BLUETOOTH = 0x02,
+ SAP_PDU_CMD_WIFI = 0x03,
+ SAP_PDU_CMD_CELLULAR = 0x04,
+ SAP_PDU_CMD_ETHERNET = 0x05,
+};
+
+enum SAP_PDU_BT_commands {
+ SAP_PDU_BT_CMD_UNKNOWN = 0x00,
+ SAP_PDU_BT_CMD_GET_VERSION = 0x01,
+ SAP_PDU_BT_CMD_GET_ADDRESS = 0x02,
+ SAP_PDU_BT_CMD_GET_PROFILES = 0x03,
+ SAP_PDU_BT_CMD_GET_COD = 0x04,
+ SAP_PDU_BT_CMD_GET_SERVICES = 0x05,
+ SAP_PDU_BT_CMD_FX_MAX = 0x06,
+
+ SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_ON = 0x11,
+ SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_OFF = 0x12,
+ SAP_PDU_BT_CMD_SET_PAN_CONNECTION = 0x13,
+ SAP_PDU_BT_CMD_DISCONNECTED_MANUALLY = 0x14,
+ SAP_PDU_BT_CMD_MAX = 0x15,
+};
+
+enum SAP_PDU_BT_version {
+ SAP_PDU_BT_VER_UNKOWN = 0x00, // unknown
+ SAP_PDU_BT_VER_30 = 0x01, // 3.0
+ SAP_PDU_BT_VER_40_LE = 0x02, // 4.0 LE ONLY
+ SAP_PDU_BT_VER_40_DUAL = 0x03, // 4.0 DUAL
+ SAP_PDU_BT_VER_40_P = 0x04, // 4.0'
+ SAP_PDU_BT_VER_41 = 0x05, // 4.1
+};
+
+enum SAP_PDU_BT_profile {
+ SAP_PDU_BT_PROFILE_UNKOWN = 0x00,
+ SAP_PDU_BT_PROFILE_HFP = 0x01,
+ SAP_PDU_BT_PROFILE_SPP = 0x02,
+ SAP_PDU_BT_PROFILE_GATT = 0x03,
+ SAP_PDU_BT_PROFILE_PAN = 0x04,
+ SAP_PDU_BT_PROFILE_MAX = 0x05,
+};
+
+enum SAP_PDU_WIFI_commands {
+ SAP_PDU_WIFI_CMD_UNKNOWN = 0x00,
+ SAP_PDU_WIFI_CMD_GET_VERSION = 0x01,
+ SAP_PDU_WIFI_CMD_GET_MAC_ADDR = 0x02,
+ SAP_PDU_WIFI_CMD_GET_IP_ADDR = 0x03,
+ SAP_PDU_WIFI_CMD_MAX = 0x04,
+};
+
+enum SAP_PDU_CELLULAR_commands {
+ SAP_PDU_CELLULAR_CMD_UNKNOWN = 0x00,
+ SAP_PDU_CELLULAR_CMD_GET_IP_ADDR = 0x01,
+ SAP_PDU_CELLULAR_CMD_MAX = 0x02,
+};
+
+enum SAP_PDU_ETHERNET_commands {
+ SAP_PDU_ETHERNET_CMD_UNKNOWN = 0x00,
+ SAP_PDU_ETHERNET_CMD_GET_MAC_ADDR = 0x01,
+ SAP_PDU_ETHERNET_CMD_GET_IP_ADDR = 0x02,
+ SAP_PDU_ETHERNET_CMD_MAX = 0x03,
+};
+
+enum SAP_PDU_GENERIC_commands {
+ SAP_PDU_GENERIC_CMD_UNKNOWN = 0x00,
+ SAP_PDU_GENERIC_CMD_GET_PLATFORM_NAME = 0x01,
+ SAP_PDU_GENERIC_CMD_GET_PLATFORM_VERSION = 0x02,
+ SAP_PDU_GENERIC_CMD_GET_MANUFACTURER = 0x03,
+ SAP_PDU_GENERIC_CMD_MAX = 0x04,
+};
+
+struct SAP_PDU_data {
+ char length;
+ char main_cmd;
+ char sub_cmd;
+ char type_cmd;
+ char data[SAP_DATA_LEN_MAX];
+};
+
+struct SAP_event_data {
+ unsigned int index;
+ unsigned int count;
+ unsigned int data_len;
+ char data[SAP_DATA_LEN_MAX];
+};
+
+struct SAP_send_data {
+ unsigned int index;
+ unsigned int count;
+ unsigned int data_len;
+ char data[SAP_DATA_LEN_MAX];
+};
+
+typedef struct _SAP_PDU_CMD_Callbacks SAP_PDU_CMD_Callbacks;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_PLUGIN_H__ */
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "util.h"
+#include "plugin.h"
+#include "esap.h"
+#include "technology.h"
+
+static __thread guint weconn_conn_subscribe_id_connman_state = 0;
+
+static int pan_bearer_connect(WcObject *wo, const char *address);
+static int pan_bearer_disconnect(WcObject *wo);
+
+static const char **__get_pan_profile(GDBusConnection *connection)
+{
+ GVariant *reply;
+ unsigned int n = 0;
+ GError *error = NULL;
+ const char *obj_path = NULL;
+ const char **obj_array = NULL;
+ GVariantIter *iter = NULL, *next = NULL;
+ GSList *string_list = NULL, *slist;
+
+ reply = g_dbus_connection_call_sync(connection,
+ "net.connman",
+ "/",
+ "net.connman.Manager",
+ "GetServices",
+ NULL,
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_REPLY_TIMEOUT,
+ NULL,
+ &error);
+
+ if (error) {
+ ERR("Failed to request (%s)", error->message);
+ g_error_free(error);
+
+ if (reply)
+ g_variant_unref(reply);
+
+ return NULL;
+ }
+
+ if (!reply) {
+ ERR("Failed to request");
+ return NULL;
+ }
+
+ g_variant_get(reply, "(a(oa{sv}))", &iter);
+ while (g_variant_iter_loop(iter, "(oa{sv})", &obj_path, &next)) {
+ if (g_str_has_prefix(obj_path, "/net/connman/service/bluetooth_")
+ != TRUE)
+ continue;
+
+ n++;
+ string_list = g_slist_prepend(string_list, g_strdup(obj_path));
+ }
+
+ if (iter)
+ g_variant_iter_free(iter);
+
+ if (next)
+ g_variant_iter_free(next);
+
+ g_variant_unref(reply);
+
+ obj_array = g_try_new(const char *, n + 1);
+ if (!obj_array) {
+ ERR("No memory");
+ return NULL;
+ }
+
+ obj_array[n--] = NULL;
+ for (slist = string_list; slist; slist = slist->next)
+ obj_array[n--] = slist->data;
+
+ g_slist_free(string_list);
+
+ return obj_array;
+}
+
+#ifdef USE_STATIC_IP
+static int __request_pan_set_dns(GDBusConnection *connection,
+ const char *obj_path)
+{
+ GVariantBuilder *builder;
+ GVariant *params = NULL;
+ GVariant *reply = NULL;
+ GError *error = NULL;
+ int err = -EIO;
+
+ const char *prop_nameserver_config = "Nameservers.Configuration";
+ const char *dns = "192.168.44.1";
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE ("as"));
+ g_variant_builder_add(builder, "s", dns);
+ params = g_variant_new("(sv)",
+ prop_nameserver_config, g_variant_builder_end(builder));
+ g_variant_builder_unref(builder);
+
+ reply = g_dbus_connection_call_sync(connection,
+ "net.connman",
+ obj_path,
+ "net.connman.Service",
+ "SetProperty",
+ params,
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_REPLY_TIMEOUT,
+ NULL,
+ &error);
+
+ if (error) {
+ ERR("Failed to request (%s)", error->message);
+ if (g_strrstr(error->message, "net.connman.Error.AlreadyConnected"))
+ err = -EISCONN;
+ else if (g_strrstr(error->message, "net.connman.Error.NotConnected"))
+ err = -ENOTCONN;
+
+ g_error_free(error);
+
+ if (reply)
+ g_variant_unref(reply);
+
+ return err;
+ }
+
+ if (!reply) {
+ ERR("Failed to request");
+ return -EIO;
+ }
+
+ g_variant_unref(reply);
+
+ return 0;
+}
+
+static int __request_pan_set_static_ip(GDBusConnection *connection,
+ const char *obj_path)
+{
+ GVariantBuilder *builder;
+ GVariant *params = NULL;
+ GVariant *reply = NULL;
+ GError *error = NULL;
+ int err = -EIO;
+
+ const char *prop_ipv4_config = "IPv4.Configuration";
+ const char *prop_method = "Method";
+ const char *prop_address = "Address";
+ const char *prop_gateway = "Gateway";
+ const char *prop_netmask = "Netmask";
+ const char *manual_method = "manual";
+ const char *ipaddress = "192.168.44.179";
+ const char *netmask = "255.255.255.0";
+ const char *gateway = "192.168.44.1";
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE ("a{sv}"));
+
+ g_variant_builder_add(builder, "{sv}", prop_method, g_variant_new_string(manual_method));
+ g_variant_builder_add(builder, "{sv}", prop_address, g_variant_new_string(ipaddress));
+ g_variant_builder_add(builder, "{sv}", prop_netmask, g_variant_new_string(netmask));
+ g_variant_builder_add(builder, "{sv}", prop_gateway, g_variant_new_string(gateway));
+
+ params = g_variant_new("(sv)",
+ prop_ipv4_config, g_variant_builder_end(builder));
+ g_variant_builder_unref(builder);
+
+ reply = g_dbus_connection_call_sync(connection,
+ "net.connman",
+ obj_path,
+ "net.connman.Service",
+ "SetProperty",
+ params,
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_REPLY_TIMEOUT,
+ NULL,
+ &error);
+
+ if (error) {
+ ERR("Failed to request (%s)", error->message);
+ if (g_strrstr(error->message, "net.connman.Error.AlreadyConnected"))
+ err = -EISCONN;
+ else if (g_strrstr(error->message, "net.connman.Error.NotConnected"))
+ err = -ENOTCONN;
+
+ g_error_free(error);
+
+ if (reply)
+ g_variant_unref(reply);
+
+ return err;
+ }
+
+ if (!reply) {
+ ERR("Failed to request");
+ return -EIO;
+ }
+
+ g_variant_unref(reply);
+
+ return 0;
+}
+#endif
+
+static int __request_pan_command(GDBusConnection *connection,
+ const char *obj_path, const char *method)
+{
+ int err = -EIO;
+ GVariant *reply;
+ GError *error = NULL;
+
+#ifdef USE_STATIC_IP
+ err = __request_pan_set_static_ip(connection, obj_path);
+ if (err < 0)
+ SECURE_ERR("Failed to set static IP(%d)", err);
+
+ err = __request_pan_set_dns(connection, obj_path);
+ if (err < 0)
+ SECURE_ERR("Failed to set DNS(%d)", err);
+#endif
+
+ reply = g_dbus_connection_call_sync(connection,
+ "net.connman",
+ obj_path,
+ "net.connman.Service",
+ method,
+ NULL,
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_REPLY_TIMEOUT,
+ NULL,
+ &error);
+
+ if (error) {
+ ERR("Failed to request (%s)", error->message);
+ if (g_strrstr(error->message, "net.connman.Error.AlreadyConnected"))
+ err = -EISCONN;
+ else if (g_strrstr(error->message, "net.connman.Error.NotConnected"))
+ err = -ENOTCONN;
+
+ g_error_free(error);
+
+ if (reply)
+ g_variant_unref(reply);
+
+ return err;
+ }
+
+ if (!reply) {
+ ERR("Failed to request");
+ return -EIO;
+ }
+
+ g_variant_unref(reply);
+
+ return 0;
+}
+
+static int _pan_bearer_request_pan_configuration(WcObject *wo, gboolean enable)
+{
+ struct SAP_event_data *new_data = NULL;
+ char buf[SAP_DATA_LEN_MAX] = { '\0', };
+ int pos = 0;
+
+ new_data = g_try_malloc0(sizeof(struct SAP_event_data));
+ if (new_data == NULL)
+ return -ENOMEM;
+
+ new_data->count = 1;
+ new_data->index = 1;
+ new_data->data_len = (char)SAP_DATA_LEN_MIN;
+
+ buf[pos++] = (char)new_data->data_len;
+ buf[pos++] = (char)SAP_PDU_CMD_BLUETOOTH;
+
+ if (enable == TRUE)
+ buf[pos++] = (char)SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_ON;
+ else
+ buf[pos++] = (char)SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_OFF;
+
+ buf[pos++] = (char)SAP_PDU_CMD_TYPE_REQ;
+
+ memcpy(new_data->data, buf, new_data->data_len);
+
+ wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, new_data);
+ g_free(new_data);
+
+ return 0;
+}
+
+static GVariant *_get_properties(GDBusConnection *connection,
+ const char *obj_path)
+{
+ GVariant *reply;
+ GError *error = NULL;
+
+ if (!connection || !obj_path)
+ return NULL;
+
+ reply = g_dbus_connection_call_sync(connection,
+ "net.connman",
+ obj_path,
+ "net.connman.Service",
+ "GetProperties",
+ NULL,
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_REPLY_TIMEOUT,
+ NULL,
+ &error);
+
+ if (error) {
+ ERR("Failed to request (%s)", error->message);
+ g_error_free(error);
+
+ if (reply)
+ g_variant_unref(reply);
+
+ return NULL;
+ }
+
+ if (!reply) {
+ ERR("Failed to request");
+ return NULL;
+ }
+
+ return reply;
+}
+
+static int _get_pan_state(WcObject *wo)
+{
+ int ret = W_SERVICE_STATE_DISCONNECTED;
+ unsigned int i, num = 0;
+ GError *error = NULL;
+ const char **obj_array = NULL;
+ GDBusConnection *connection = NULL;
+ GVariantIter *iter = NULL;
+ GVariant *reply;
+ GVariant *value = NULL;
+ gchar *key = NULL;
+
+ if (!wo)
+ return -EINVAL;
+
+ DBG("");
+
+ connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+ if (!connection) {
+ ERR("Failed to get system bus[%s]", error->message);
+ g_error_free(error);
+ return -EIO;
+ }
+
+ obj_array = __get_pan_profile(connection);
+ num = g_strv_length((char **)obj_array);
+ if (!num) {
+ ERR("Failed to get profiles");
+ return -ENXIO;
+ }
+
+ for (i=0; i<num; i++) {
+ reply = _get_properties(connection, obj_array[i]);
+ if (reply != NULL) {
+ g_variant_get(reply, "(a{sv})", &iter);
+ while (g_variant_iter_loop(iter, "{sv}", &key, &value)) {
+ const gchar *state = NULL;
+
+ if (g_strcmp0(key, "State") == 0) {
+ state = g_variant_get_string(value, NULL);
+ if (g_strcmp0(state, "association") == 0)
+ ret = W_SERVICE_STATE_CONNECTING;
+ else if (g_strcmp0(state, "configuration") == 0)
+ ret = W_SERVICE_STATE_CONNECTING;
+ else if (g_strcmp0(state, "ready") == 0)
+ ret = W_SERVICE_STATE_CONNECTED;
+ else if (g_strcmp0(state, "online") == 0)
+ ret = W_SERVICE_STATE_CONNECTED;
+ else
+ ret = W_SERVICE_STATE_DISCONNECTED;
+ }
+
+ if (ret != W_SERVICE_STATE_DISCONNECTED)
+ break;
+ }
+
+ g_variant_unref(reply);
+ }
+ }
+
+ return ret;
+}
+
+static void __pan_set_property(WcObject *wo, char *key, char *property)
+{
+ char *property_old = NULL;
+
+ if (!key || !property)
+ return;
+
+ property_old = wc_object_get_property(wo, key);
+ if (property_old != NULL) {
+ if (g_strcmp0(property_old, property) == 0) {
+ DBG("not changed property : %s", property);
+ g_free(property_old);
+ return;
+ }
+ g_free(property_old);
+ }
+
+ wc_object_set_property(wo, key, property);
+}
+
+static int _pan_connect(WcObject *wo)
+{
+ int err = -EIO;
+ unsigned int i, num = 0;
+ GError *error = NULL;
+ const char **obj_array = NULL;
+ GDBusConnection *connection = NULL;
+
+ if (!wo)
+ return -EINVAL;
+
+ DBG("");
+
+ connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+ if (!connection) {
+ ERR("Failed to get system bus[%s]", error->message);
+ g_error_free(error);
+ return -EIO;
+ }
+
+ obj_array = __get_pan_profile(connection);
+ num = g_strv_length((char **)obj_array);
+ if (!num) {
+ ERR("Failed to get profiles");
+ return -ENXIO;
+ }
+
+ for (i=0; i<num; i++) {
+ err = __request_pan_command(connection, obj_array[i], "Connect");
+ if (err == 0 || err == -EISCONN)
+ break;
+ }
+
+ g_strfreev((char **)obj_array);
+
+ if (err == 0)
+ DBG("PAN successfully connected");
+
+ g_object_unref(connection);
+
+ return err;
+}
+
+static int _pan_disconnect(WcObject *wo)
+{
+ int err = -EIO;
+ unsigned int i, num = 0;
+ GError *error = NULL;
+ const char **obj_array = NULL;
+ GDBusConnection *connection = NULL;
+
+ if (!wo)
+ return -EINVAL;
+
+ connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+ if (!connection) {
+ ERR("Failed to get system bus %s", error->message);
+ g_error_free(error);
+ return -EIO;
+ }
+
+ obj_array = __get_pan_profile(connection);
+ num = g_strv_length((char **)obj_array);
+ if (!num) {
+ ERR("Failed to get profiles");
+ return -ENXIO;
+ }
+
+ for (i=0; i<num; i++) {
+ err = __request_pan_command(connection, obj_array[i], "Disconnect");
+ if (err == 0)
+ break;
+ }
+
+ g_strfreev((char **)obj_array);
+
+ if (err == 0) {
+ DBG("PAN successfully disconnected");
+ _pan_bearer_request_pan_configuration(wo, FALSE);
+ } else
+ ERR("failed to disconnect [%d]", err);
+
+ g_object_unref(connection);
+
+ return err;
+}
+
+static gboolean _on_pan_sap_cmd_cb(WcObject *wo,
+ const void *event_info, void *user_data)
+{
+ struct SAP_event_data *evt_data = NULL;
+ int res, mainCmd, subCmd, cmdType;
+ char *pan_state = NULL;
+
+ evt_data = (struct SAP_event_data *)event_info;
+ if (evt_data == NULL)
+ return TRUE;
+
+ mainCmd = (int)evt_data->data[1];
+ if (mainCmd != SAP_PDU_CMD_BLUETOOTH) {
+ ERR("Invalid bluetooth command(%02x)", mainCmd);
+ return TRUE;
+ }
+
+ subCmd = (int)evt_data->data[2];
+ switch (subCmd) {
+ case SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_ON:
+ DBG("SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_ON");
+ break;
+ case SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_OFF:
+ DBG("SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_OFF");
+ break;
+ case SAP_PDU_BT_CMD_SET_PAN_CONNECTION:
+ DBG("SAP_PDU_BT_CMD_SET_PAN_CONNECTION");
+
+ cmdType = (int)evt_data->data[3];
+ switch (cmdType) {
+ case SAP_PDU_CMD_TYPE_REQ:
+ res = _pan_connect(wo);
+ if (res < 0) {
+ ERR("Failed pan connect");
+
+ __pan_set_property(wo, XSTR(W_SERVICE_TYPE_BT_PAN),
+ XSTR(W_SERVICE_STATE_DISCONNECTED));
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ break;
+ case SAP_PDU_BT_CMD_DISCONNECTED_MANUALLY:
+ DBG("SAP_PDU_BT_CMD_DISCONNECTED_MANUALLY");
+
+ cmdType = (int)evt_data->data[3];
+ switch (cmdType) {
+ case SAP_PDU_CMD_TYPE_NOTI:
+ pan_state = wc_object_get_property(wo, XSTR(W_SERVICE_TYPE_BT_PAN));
+ if (g_strcmp0(pan_state, XSTR(W_SERVICE_STATE_CONNECTED)) == 0) {
+ res = _pan_disconnect(wo);
+ if (res < 0)
+ ERR("Failed pan connect");
+ }
+
+ g_free(pan_state);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+static void _pan_bearer_register_events(WcObject *wo)
+{
+ enum SAP_PDU_commands_type cmd_type = SAP_PDU_CMD_TYPE_REQ;
+ enum SAP_PDU_BT_commands pan_cmds = SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_ON;
+ char *cmd = NULL;
+ char *event = NULL;
+
+ cmd = g_strdup_printf("%s[%d]",
+ WC_OBJECT_EVENT_SAP_RECEIVE_DATA, SAP_PDU_CMD_BLUETOOTH);
+
+ while (cmd_type < SAP_PDU_CMD_TYPE_MAX ) {
+ while (pan_cmds < SAP_PDU_BT_CMD_MAX) {
+ event = g_strdup_printf("%s[%d][%d]", cmd, pan_cmds, cmd_type);
+ wc_object_add_callback(wo, event, _on_pan_sap_cmd_cb, NULL);
+ g_free(event);
+
+ pan_cmds++;
+ }
+
+ pan_cmds = SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_ON;
+ cmd_type++;
+ }
+
+ g_free(cmd);
+}
+
+static void _pan_connect_cb(service_h request,
+ service_h reply, service_result_e result, void *user_data)
+{
+ int ret;
+ char *resp = NULL;
+ const char *connected = NULL;
+ WcObject *wo = (WcObject *)user_data;
+
+ if (!wo) {
+ ERR("WcObject is NULL");
+ return;
+ }
+
+ if (result != SERVICE_RESULT_SUCCEEDED) {
+ ERR("service reply failed = [%d]", result);
+ return;
+ }
+
+ ret = service_get_extra_data(reply, "_WCPOPUP_RESP_", &resp);
+ if (ret != SERVICE_ERROR_NONE) {
+ ERR("failed to retrieve response = [%d]", ret);
+ return;
+ }
+
+ if (g_strcmp0(resp, "OK") == 0) {
+ connected = (const char *)g_hash_table_lookup(
+ wc_object_peek_property_hash(wo), XSTR(W_SERVICE_TYPE_BT_SPP));
+ if (g_strcmp0(connected, XSTR(W_SERVICE_STATE_CONNECTED)) != 0) {
+ ERR("CM does not connected correctly");
+ __pan_set_property(wo, XSTR(W_SERVICE_TYPE_BT_PAN),
+ XSTR(W_SERVICE_STATE_DISCONNECTED));
+ return;
+ }
+
+ ret = _pan_bearer_request_pan_configuration(wo, TRUE);
+ if (ret < 0)
+ ERR("Failed pan configuration on");
+ else
+ DBG("Requested pan configuration on");
+ } else if (g_strcmp0(resp, "CANCEL") == 0) {
+ __pan_set_property(wo, XSTR(W_SERVICE_TYPE_BT_PAN),
+ XSTR(W_SERVICE_STATE_DISCONNECTED));
+ }
+}
+
+static void _pan_disconnect_cb(service_h request,
+ service_h reply, service_result_e result, void *user_data)
+{
+ int ret;
+ char *resp = NULL;
+ const char *connected = NULL;
+ WcObject *wo = (WcObject *)user_data;
+
+ if (!wo) {
+ ERR("WcObject is NULL");
+ return;
+ }
+
+ if (result != SERVICE_RESULT_SUCCEEDED) {
+ ERR("service reply failed = [%d]", result);
+ return;
+ }
+
+ ret = service_get_extra_data(reply, "_WCPOPUP_RESP_", &resp);
+ if (ret != SERVICE_ERROR_NONE) {
+ ERR("failed to retrieve response = [%d]", ret);
+ return;
+ }
+
+ if (g_strcmp0(resp, "OK") == 0) {
+ ret = _pan_disconnect(wo);
+ if (ret < 0)
+ ERR("Failed pan connect");
+ } else if (g_strcmp0(resp, "CANCEL") == 0) {
+ connected = (const char *)g_hash_table_lookup(
+ wc_object_peek_property_hash(wo), XSTR(W_SERVICE_TYPE_BT_SPP));
+ if (g_strcmp0(connected, XSTR(W_SERVICE_STATE_CONNECTED)) == 0) {
+ __pan_set_property(wo, XSTR(W_SERVICE_TYPE_BT_PAN),
+ XSTR(W_SERVICE_STATE_CONNECTED));
+ }
+ }
+}
+
+static void __notify_bt_service_state_changed(const char *state, void *user_data)
+{
+ static wc_technology_service_state_e pan_service_state_old = 0;
+
+ WcObject *wo = (WcObject *)user_data;
+ if (!wo)
+ return;
+
+ if (!state) {
+ ERR("state is NULL");
+ return;
+ }
+
+ DBG("bt_service_state_changed : %s", state);
+
+ if (g_strcmp0(state, "idle") == 0) {
+ pan_service_state_old = WC_SERVICE_STATE_IDLE;
+ } else if (g_strcmp0(state, "disconnect") == 0) {
+ if (pan_service_state_old > WC_SERVICE_STATE_DISCONNECTED) {
+ __pan_set_property(wo, XSTR(W_SERVICE_TYPE_BT_PAN),
+ XSTR(W_SERVICE_STATE_DISCONNECTED));
+ }
+ pan_service_state_old = WC_SERVICE_STATE_DISCONNECTED;
+ } else if (g_strcmp0(state, "failure") == 0) {
+ if (pan_service_state_old > WC_SERVICE_STATE_DISCONNECTED) {
+ __pan_set_property(wo, XSTR(W_SERVICE_TYPE_BT_PAN),
+ XSTR(W_SERVICE_STATE_DISCONNECTED));
+ }
+ pan_service_state_old = WC_SERVICE_STATE_FAILURE;
+ } else if (g_strcmp0(state, "association") == 0) {
+ pan_service_state_old = WC_SERVICE_STATE_ASSOCIATION;
+ } else if (g_strcmp0(state, "configuration") == 0) {
+ pan_service_state_old = WC_SERVICE_STATE_CONFIGURATION;
+ } else if (g_strcmp0(state, "ready") == 0) {
+ if (pan_service_state_old < WC_SERVICE_STATE_READY) {
+ __pan_set_property(wo, XSTR(W_SERVICE_TYPE_BT_PAN),
+ XSTR(W_SERVICE_STATE_CONNECTED));
+ }
+ pan_service_state_old = WC_SERVICE_STATE_READY;
+ } else if (g_strcmp0(state, "online") == 0) {
+ if (pan_service_state_old < WC_SERVICE_STATE_READY) {
+ __pan_set_property(wo, XSTR(W_SERVICE_TYPE_BT_PAN),
+ XSTR(W_SERVICE_STATE_CONNECTED));
+ }
+ pan_service_state_old = WC_SERVICE_STATE_ONLINE;
+ }
+}
+
+static void __handle_service_state_changed(const gchar *path,
+ const char *key, const char *state, void *user_data)
+{
+ weconn_device_type_e device_type;
+
+ if (path == NULL || key == NULL || state == NULL)
+ return;
+
+ device_type = wc_device_get_type_from_path(path);
+ switch (device_type) {
+ case W_DEVICE_TYPE_BT:
+ __notify_bt_service_state_changed(state, user_data);
+ break;
+ case W_DEVICE_TYPE_CELLULAR:
+ break;
+ case W_DEVICE_TYPE_WIFI:
+ break;
+ case W_DEVICE_TYPE_WIFI_P2P:
+ break;
+ case W_DEVICE_TYPE_WIFI_ADHOC:
+ break;
+ case W_DEVICE_TYPE_ETHERNET:
+ break;
+ default:
+ break;
+ }
+}
+
+static void __pan_connman_service_signal_filter(GDBusConnection *conn,
+ const gchar *name, const gchar *path, const gchar *interface,
+ const gchar *sig, GVariant *param, gpointer user_data)
+{
+ const char *key = NULL;
+ const char *value = NULL;
+ GVariant *var;
+
+ if (g_strcmp0(sig, CONNMAN_SIGNAL_PROPERTY_CHANGED) == 0) {
+ g_variant_get(param, "(sv)", &key, &var);
+
+ if (g_strcmp0(key, "State") == 0) {
+ g_variant_get(var, "s", &value);
+ __handle_service_state_changed(path, key, value, user_data);
+ } else if (g_strcmp0(key, "Error") == 0) {
+ g_variant_get(var, "s", &value);
+ ERR("Error (%s)", value);
+ }
+
+ g_free((gchar *)value);
+ g_free((gchar *)key);
+ if (var != NULL)
+ g_variant_unref(var);
+ } else {
+ ERR("No handle signal(%s)", sig);
+ }
+}
+
+static int pan_bearer_init(WcObject *wo)
+{
+ GError *error = NULL;
+ GDBusConnection *connection = NULL;
+ guint id;
+
+ _pan_bearer_register_events(wo);
+
+ connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+ if (!connection) {
+ ERR("Failed to get system bus %s", error->message);
+ g_error_free(error);
+ return -1;
+ }
+
+ id = g_dbus_connection_signal_subscribe(
+ connection,
+ CONNMAN_SERVICE,
+ CONNMAN_SERVICE_INTERFACE,
+ CONNMAN_SIGNAL_PROPERTY_CHANGED,
+ NULL,
+ "State",
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ __pan_connman_service_signal_filter,
+ wo,
+ NULL);
+
+ if (id == 0) {
+ ERR("Failed register signals (%d)", id);
+ return -1;
+ }
+
+ weconn_conn_subscribe_id_connman_state = id;
+
+ return 0;
+}
+
+static int pan_bearer_connect(WcObject *wo, const char *address)
+{
+ int err = -EIO;
+ char *connected = NULL;
+ weconn_service_state_e state;
+
+ if (!wo)
+ return -EINVAL;
+
+ connected = wc_object_get_property(wo, WC_OBJECT_EVENT_SAP_BCMSERVICE_STATUS);
+ if (connected != NULL) {
+ if (g_strcmp0(connected, XSTR(W_SERVICE_STATE_CONNECTED)) != 0) {
+ ERR("CM does not connected correctly");
+ g_free(connected);
+ return -EIO;
+ }
+ g_free(connected);
+ }
+
+
+ state = _get_pan_state(wo);
+ if (state == W_SERVICE_STATE_CONNECTING) {
+ DBG("InProgress...");
+ return -EINPROGRESS;
+ } else if (state == W_SERVICE_STATE_CONNECTED) {
+ DBG("already connected");
+ return -EISCONN;
+ }
+
+ err = wc_launch_popup(WC_POPUP_TYPE_PAN_CONNECT, _pan_connect_cb, wo);
+ if (err < 0)
+ ERR("failed launch pan popup");
+
+ return err;
+}
+
+static int pan_bearer_disconnect(WcObject *wo)
+{
+ int err = -EIO;
+ weconn_service_state_e state;
+
+ state = _get_pan_state(wo);
+ if (state == W_SERVICE_STATE_CONNECTING) {
+ DBG("InProgress...");
+ return -EINPROGRESS;
+ } else if (state == W_SERVICE_STATE_DISCONNECTED) {
+ DBG("Not connected");
+ return -ENOTCONN;
+ }
+
+ err = wc_launch_popup(WC_POPUP_TYPE_PAN_DISCONNECT, _pan_disconnect_cb, wo);
+ if (err < 0)
+ ERR("failed launch pan popup");
+
+ return err;
+}
+
+static void pan_bearer_exit(WcObject *wo)
+{
+ GError *error = NULL;
+ GDBusConnection *connection = NULL;
+
+ DBG("Unloaded");
+
+ connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+ if (!connection) {
+ ERR("Failed to get system bus %s", error->message);
+ g_error_free(error);
+ return;
+ }
+
+ g_dbus_connection_signal_unsubscribe(connection,
+ weconn_conn_subscribe_id_connman_state);
+}
+
+EXPORT_API struct bearer_driver_desc bearer_driver_desc = {
+ .name = "pan",
+ .technology = WC_TECHNOLOGY_BLUETOOTH,
+
+ .init = pan_bearer_init,
+ .connect = pan_bearer_connect,
+ .disconnect = pan_bearer_disconnect,
+ .exit = pan_bearer_exit,
+};
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __WECONN_PLUGIN_H__
+#define __WECONN_PLUGIN_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <errno.h>
+
+#include "log.h"
+#include "dbus.h"
+#include "util.h"
+#include "events.h"
+#include "object.h"
+#include "technology.h"
+
+struct bearer_driver_desc {
+ const char *name;
+ const char *technology;
+
+ int (*init)(WcObject *wcdrv);
+ int (*activate)(WcObject *wcdrv);
+ int (*deactivate)(WcObject *wcdrv);
+ int (*connect)(WcObject *wcdrv, const char *address);
+ int (*disconnect)(WcObject *wcdrv);
+ void (*exit)(WcObject *wcdrv);
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_PLUGIN_H__ */
--- /dev/null
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+ <policy user="0">
+ <allow own="net.weconn"/>
+ <allow send_destination="net.weconn"/>
+ <allow send_interface="net.weconn.Service"/>
+ <allow send_interface="net.netcon.Technology"/>
+ </policy>
+ <policy user="5000">
+ <allow own="net.weconn"/>
+ <allow send_destination="net.weconn"/>
+ <allow send_interface="net.netconfig.Service"/>
+ <allow send_interface="net.netconfig.Technology"/>
+ </policy>
+ <policy at_console="true">
+ <allow send_destination="net.weconn"/>
+ </policy>
+ <policy context="default">
+ <deny send_destination="net.weconn"/>
+ </policy>
+</busconfig>
--- /dev/null
+#!/bin/sh
+
+#vconf
+if [ ! -e /opt/var/kdb/memory/private/weconn/all_connected ]; then
+/usr/bin/vconftool set -tf int memory/private/weconn/all_connected 0 -s system::vconf_network -i
+fi
--- /dev/null
+[Unit]
+Description=Wearable device connection controller
+
+[Service]
+Type=forking
+BusName=net.weconn
+ExecStart=/usr/sbin/weconnd
+Restart=always
+
+[Install]
+WantedBy=multi-user.target
--- /dev/null
+<!DOCTYPE resources [
+<!ELEMENT resources (application)>
+<!ELEMENT application (serviceProfile)+>
+<!ELEMENT supportedTransports (transport)+>
+<!ELEMENT serviceProfile (supportedTransports, serviceChannel+)>
+<!ELEMENT transport EMPTY>
+<!ELEMENT serviceChannel EMPTY>
+<!ATTLIST application name CDATA #REQUIRED>
+<!ATTLIST application xmlns:android CDATA #IMPLIED>
+<!ATTLIST serviceProfile xmlns:android CDATA #IMPLIED>
+<!ATTLIST serviceProfile serviceImpl CDATA #REQUIRED>
+<!ATTLIST serviceProfile role (provider | consumer) #REQUIRED>
+<!ATTLIST serviceProfile name CDATA #REQUIRED>
+<!ATTLIST serviceProfile id CDATA #REQUIRED>
+<!ATTLIST serviceProfile version CDATA #REQUIRED>
+<!ATTLIST serviceProfile serviceLimit (ANY | ONE_ACCESSORY | ONE_PEERAGENT | any | one_accessory | one_peeragent) "ANY">
+<!ATTLIST serviceProfile serviceTimeout CDATA #IMPLIED>
+<!ATTLIST supportedTransports xmlns:android CDATA #IMPLIED>
+<!ATTLIST transport xmlns:android CDATA #IMPLIED>
+<!ATTLIST transport type (TRANSPORT_WIFI | TRANSPORT_BT | TRANSPORT_BLE | TRANSPORT_USB | transport_wifi | transport_bt | transport_ble | transport_usb) #REQUIRED>
+<!ATTLIST serviceChannel xmlns:android CDATA #IMPLIED>
+<!ATTLIST serviceChannel id CDATA #REQUIRED>
+<!ATTLIST serviceChannel dataRate (Low | High | low | high) #REQUIRED>
+<!ATTLIST serviceChannel priority (Low | Medium | High | low | medium | high) #REQUIRED>
+<!ATTLIST serviceChannel reliability (enable | disable | ENABLE | DISABLE) #REQUIRED>
+]>
+
+
+<resources>
+ <application name="/usr/sbin/weconnd">
+ <serviceProfile
+ id="/system/bcmservice"
+ name="BCMService"
+ role="Provider"
+ serviceImpl="/usr/sbin/weconnd"
+ version="1.0">
+ <supportedTransports>
+ <transport type="TRANSPORT_BT"/>
+ </supportedTransports>
+ <serviceChannel
+ id="222"
+ dataRate="Low"
+ priority="Low"
+ reliability="disable"/>
+ </serviceProfile>
+ </application>
+</resources>
--- /dev/null
+[D-BUS Service]
+Name=net.weconn
+Exec=/bin/false
+User=root
+SystemdService=weconn.service
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <errno.h>
+
+#include "control.h"
+#include "driver.h"
+
+struct wc_control {
+ int device_type;
+ const GSList *driver_list;
+};
+
+static WcObject *wo_control;
+
+static gboolean on_spp_connected(WcObject *wo_control, const void *event_info,
+ void *user_data)
+{
+ int ret;
+ WcObject *wo_bearer = (WcObject*)user_data;
+
+ /* FIXME: when spp is connected, what do you want to activate here? */
+ ret = wc_bearer_driver_activate(wo_bearer, "correct name");
+ DBG("activate request: %d", ret);
+
+ return TRUE;
+}
+
+static gboolean on_bearer_created(WcObject *wo_bearer, const void *event_info,
+ void *user_data)
+{
+ const char *name = NULL;
+
+ if (!wo_bearer) {
+ DBG("no bearer object!!");
+ return FALSE;
+ }
+
+ name = wc_object_get_name(wo_bearer);
+
+ if (!name)
+ return FALSE;
+
+ /* FIXME: it doesn't work correctly */
+ if (g_strcmp0(name, "eSAP") == 0) {
+ int ret;
+ ret = wc_object_add_callback(wo_control,
+ WC_BEARER_EVENT_BT_CONNECTED_SPP, on_spp_connected, wo_bearer);
+ DBG("add callback for SPP connection: %d", ret);
+ } else {
+ DBG("%s bearer added", name);
+ }
+
+ return TRUE;
+}
+
+int wc_control_add_bearer(WcObject *wo_bearer)
+{
+ /* FIXME: controller is a one of bearer?? what does that mean? */
+ wc_object_add_callback(wo_bearer, WC_OBJECT_EVENT_BEARER_ENABLED,
+ on_bearer_created, NULL);
+
+ return 0;
+}
+
+WcObject *wc_control_get_object(void)
+{
+ if (!wo_control) {
+ ERR("control object is NULL !!");
+ return NULL;
+ }
+
+ return wo_control;
+}
+
+EXPORT_API int wc_control_get_device_type(void)
+{
+ struct wc_control *cd = NULL;
+
+ if (!wo_control)
+ return -EINVAL;
+
+ cd = wc_object_get_element(wo_control, "control_driver");
+ if (cd)
+ return cd->device_type;
+
+ return -EINVAL;
+}
+
+int control_init(void)
+{
+ struct wc_control *cd = NULL;
+
+ wo_control = wc_object_new("control", WC_OBJECT_TYPE_CONTROL);
+ if (!wo_control)
+ return -ENOMEM;
+
+ cd = g_try_new0 (struct wc_control, 1);
+ if (!cd)
+ return -ENOMEM;
+
+ /* FIXME */
+ /* TBD: determine current mode Host or Wearable */
+ cd->device_type = PROP_CONTROL_TYPE_WEARABLE;
+ wc_object_append_element(wo_control, "control_driver", cd);
+
+ /*
+ * TODO: According to the various wearable device scenarios,
+ * each control should be implemented.
+ *
+ * All of controls are based on wearable device scenarios.
+ */
+ DBG("control init success.");
+
+ return 0;
+}
+
+static void __clean_control_elements(WcObject *wo,
+ const char *element_name, void *element, void *user_data)
+{
+ g_free((gpointer)element_name);
+ g_free(element);
+}
+
+void control_cleanup(void)
+{
+ if (!wo_control)
+ return;
+
+ WC_OBJECT_CHECK(wo_control, WC_OBJECT_TYPE_CONTROL);
+
+ wc_object_foreach_get_elements(wo_control, __clean_control_elements, NULL);
+
+ wc_object_free(wo_control);
+}
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "log.h"
+#include "dbus.h"
+
+static GDBusConnection *__connection = NULL;
+static GDBusObjectManagerServer *__object_manager_server = NULL;
+
+
+static void __request_name_cb(GDBusConnection *conn, const gchar *name,
+ gpointer user_data)
+{
+ void (*__init_cb)(void) = user_data;
+
+ /* Successfully register DBus name */
+ __connection = conn;
+
+ g_dbus_object_manager_server_set_connection(__object_manager_server, conn);
+
+ if (__init_cb)
+ __init_cb();
+}
+
+static void __lost_name_cb(GDBusConnection *conn, const gchar *name,
+ gpointer user_data)
+{
+ /* May service name is already in use */
+ ERR("Service name is already in use");
+
+ /* The result of DBus name request is only permitted,
+ * such as DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER.
+ */
+ exit(1);
+}
+
+GDBusConnection *dbus_get_connection(void)
+{
+ return __connection;
+}
+
+const char *dbus_name2path(const char *name)
+{
+ size_t len, i, j;
+ char *buf;
+ char hex[3];
+
+ if (!name)
+ return NULL;
+
+ len = strlen(name);
+ if (len == 0)
+ return NULL;
+
+ buf = g_malloc0(len * 4);
+ if (!buf)
+ return NULL;
+
+ for (i = 0, j = 0; i < len; i++) {
+ if (g_ascii_isalnum(name[i]) || name[i] == '_' || name[i] == '/') {
+ buf[j] = name[i];
+ j++;
+ } else {
+ snprintf(hex, 3, "%02X", name[i]);
+ buf[j++] = '_';
+ buf[j++] = hex[0];
+ buf[j++] = hex[1];
+ buf[j++] = '_';
+ }
+ }
+
+ return buf;
+}
+
+int dbus_init(GBusType bus_type, const char *bus_name, const char *obj_path,
+ void (*__init_cb)(void))
+{
+ guint id;
+
+ __object_manager_server = g_dbus_object_manager_server_new(obj_path);
+ if (!__object_manager_server)
+ return -ENOMEM;
+
+ id = g_bus_own_name(bus_type, bus_name, G_BUS_NAME_OWNER_FLAGS_NONE, NULL,
+ __request_name_cb, __lost_name_cb, __init_cb, NULL);
+ if (id == 0) {
+ ERR("Failed to get system bus");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+void dbus_cleanup(void)
+{
+ g_object_unref(__object_manager_server);
+ __object_manager_server = NULL;
+
+ g_object_unref(__connection);
+ __connection = NULL;
+}
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <gio/gio.h>
+
+#include "dbus.h"
+#include "driver.h"
+#include "technology.h"
+#include "plugins/plugin.h"
+
+#include "generated-code.h"
+
+struct bearer_driver {
+ const struct bearer_driver_desc *desc;
+
+ const char *path;
+ void *user_data;
+ void *handle;
+};
+
+static GSList *driver_list;
+
+/* TIP: driver is an element of WcObject
+ * For example, there might be a bluetooth WcObject,
+ * which has bluetooth, esap and pan elements.
+ */
+
+static WcObject *wc_bearer_driver_new(const char *filename,
+ const struct bearer_driver_desc *desc, void *dl_handle)
+{
+ int err;
+ WcObject *wo;
+ struct bearer_driver *bd;
+
+ wo = wc_object_find(desc->technology);
+ if (!wo) {
+ wo = wc_object_new(desc->technology, WC_OBJECT_TYPE_BEARER_DRIVER);
+ if (!wo)
+ return NULL;
+ }
+
+ bd = g_try_new0(struct bearer_driver, 1);
+ if (!bd)
+ return NULL;
+
+ bd->desc = desc;
+ bd->handle = dl_handle;
+ bd->path = g_strdup(filename);
+
+ err = wc_object_append_element(wo, desc->name, bd);
+ if (err < 0)
+ g_free(bd);
+
+ return wo;
+}
+
+static void wc_bearer_driver_free(struct bearer_driver *bd)
+{
+ if (!bd)
+ return;
+
+ g_free((gpointer)bd->path);
+ dlclose(bd->handle);
+ g_free(bd);
+}
+
+static int __add_bearer(const char *filename, gpointer handle)
+{
+ GSList *list;
+ WcObject *wo;
+ struct bearer_driver_desc *desc;
+
+ desc = dlsym(handle, "bearer_driver_desc");
+ if (!desc)
+ return -EIO;
+
+ wo = wc_bearer_driver_new(filename, desc, handle);
+ if (!wo)
+ return -ENOMEM;
+
+ wc_technology_add_bearer(wo);
+
+ wc_bearer_driver_init(wo, desc->name);
+
+ /* Check already registered */
+ for (list = driver_list; list; list = list->next) {
+ if (wo == list->data) {
+ DBG("driver %s, %p, %p, %s(%s) registered",
+ filename, desc, handle, desc->technology, desc->name);
+
+ return -EALREADY;
+ }
+ }
+
+ driver_list = g_slist_append(driver_list, wo);
+
+ DBG("driver %s, %p, %p, %s(%s) created",
+ filename, desc, handle, desc->technology, desc->name);
+
+ return 0;
+}
+
+int wc_bearer_driver_init(WcObject *wo, const char *desc_name)
+{
+ struct bearer_driver *bd;
+
+ WC_OBJECT_CHECK_RETURN(wo, WC_OBJECT_TYPE_BEARER_DRIVER, -EINVAL);
+
+ bd = wc_object_get_element(wo, desc_name);
+ if (!bd)
+ return -EINVAL;
+
+ if (bd->desc->init)
+ return bd->desc->init(wo);
+
+ return -ENXIO;
+}
+
+int wc_bearer_driver_activate(WcObject *wo, const char *desc_name)
+{
+ struct bearer_driver *bd;
+
+ WC_OBJECT_CHECK_RETURN(wo, WC_OBJECT_TYPE_BEARER_DRIVER, -EINVAL);
+
+ bd = wc_object_get_element(wo, desc_name);
+ if (!bd)
+ return -EINVAL;
+
+ if (bd->desc->activate)
+ return bd->desc->activate(wo);
+
+ return -ENXIO;
+}
+
+int wc_bearer_driver_deactivate(WcObject *wo, const char *desc_name)
+{
+ struct bearer_driver *bd;
+
+ WC_OBJECT_CHECK_RETURN(wo, WC_OBJECT_TYPE_BEARER_DRIVER, -EINVAL);
+
+ bd = wc_object_get_element(wo, desc_name);
+ if (!bd)
+ return -EINVAL;
+
+ if (bd->desc->deactivate)
+ return bd->desc->deactivate(wo);
+
+ return -ENXIO;
+}
+
+int wc_bearer_driver_connect(WcObject *wo, const char *address,
+ const char *desc_name)
+{
+ struct bearer_driver *bd;
+
+ WC_OBJECT_CHECK_RETURN(wo, WC_OBJECT_TYPE_BEARER_DRIVER, -EINVAL);
+
+ bd = wc_object_get_element(wo, desc_name);
+ if (!bd)
+ return -EINVAL;
+
+ if (bd->desc->connect)
+ return bd->desc->connect(wo, address);
+
+ return -ENXIO;
+}
+
+int wc_bearer_driver_disconnect(WcObject *wo, const char *desc_name)
+{
+ struct bearer_driver *bd;
+
+ WC_OBJECT_CHECK_RETURN(wo, WC_OBJECT_TYPE_BEARER_DRIVER, -EINVAL);
+
+ bd = wc_object_get_element(wo, desc_name);
+ if (!bd)
+ return -EINVAL;
+
+ if (bd->desc->disconnect)
+ return bd->desc->disconnect(wo);
+
+ return -ENXIO;
+}
+
+void wc_bearer_driver_exit(WcObject *wo, const char *desc_name)
+{
+ struct bearer_driver *bd;
+
+ WC_OBJECT_CHECK(wo, WC_OBJECT_TYPE_BEARER_DRIVER);
+
+ bd = wc_object_get_element(wo, desc_name);
+ if (!bd)
+ return;
+
+ if (bd->desc->exit)
+ bd->desc->exit(wo);
+}
+
+int driver_init(const char *driver_path)
+{
+ int err;
+ void *h;
+ GDir *dir;
+ char *filename;
+ const gchar *file;
+
+ if (!driver_path)
+ return -EINVAL;
+
+ dir = g_dir_open(driver_path, 0, NULL);
+ if (!dir) {
+ ERR("Failed to open driver(%s)", driver_path);
+ return -EIO;
+ }
+
+ while ((file = g_dir_read_name(dir)) != NULL) {
+ if (g_str_has_prefix(file, "lib") == TRUE ||
+ g_str_has_suffix(file, ".so") == FALSE)
+ continue;
+
+ filename = g_build_filename(driver_path, file, NULL);
+
+ h = dlopen(filename, RTLD_NOW);
+ if (!h) {
+ ERR("Failed to open (%s) %s", filename, dlerror());
+ g_free(filename);
+ continue;
+ }
+
+ err = __add_bearer(filename, h);
+ if (err < 0 && err != -EALREADY)
+ dlclose(h);
+
+ g_free(filename);
+ }
+
+ g_dir_close(dir);
+
+ return 0;
+}
+
+static void __clean_bearer_driver_elements(WcObject *wo,
+ const char *element_name, void *element, void *user_data)
+{
+ struct bearer_driver *bd = (struct bearer_driver *)element;
+
+ wc_bearer_driver_exit(wo, element_name);
+
+ wc_bearer_driver_free(bd);
+
+ g_free((gpointer)element_name);
+ g_free(element);
+}
+
+static void __clean_bearer_drivers(gpointer data)
+{
+ WcObject *wo = data;
+
+ if (!wo)
+ return;
+
+ WC_OBJECT_CHECK(wo, WC_OBJECT_TYPE_BEARER_DRIVER);
+
+ wc_object_foreach_get_elements(wo, __clean_bearer_driver_elements, NULL);
+
+ wc_object_unexport(wo);
+ wc_object_free(wo);
+}
+
+void driver_cleanup(void)
+{
+ g_slist_free_full(driver_list, __clean_bearer_drivers);
+}
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "log.h"
+#include "error.h"
+
+static char *__error_message;
+
+void wc_error_add(const char *msg, ...)
+{
+ va_list ap;
+ gchar buf[1024] = { 0, };
+ char *new_message;
+
+ va_start(ap, msg);
+ vsnprintf(buf, 1023, msg, ap);
+ va_end(ap);
+
+ if (__error_message) {
+ new_message = g_strdup_printf("%s; %s", __error_message, buf);
+
+ g_free(__error_message);
+ __error_message = new_message;
+ } else
+ __error_message = g_strdup(buf);
+
+ ERR("%s", __error_message);
+}
+
+void wc_error_return(GDBusMethodInvocation *invocation)
+{
+ if (!invocation)
+ return;
+
+ if (!__error_message)
+ g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED, "No error message");
+ else
+ g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED, __error_message);
+
+ g_free(__error_message);
+ __error_message = NULL;
+}
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "log.h"
+#include "dbus.h"
+#include "driver.h"
+#include "control.h"
+#include "service.h"
+#include "technology.h"
+
+
+static void __on_log_glib(const gchar *log_domain, GLogLevelFlags log_level,
+ const gchar *msg, gpointer user_data)
+{
+ ERR("glib %s", msg);
+}
+
+static void __init(void)
+{
+ technology_init();
+
+ service_init();
+
+ control_init();
+
+ driver_init(WECONN_PLUGIN_PATH);
+}
+
+static void __cleanup(void)
+{
+ control_cleanup();
+
+ driver_cleanup();
+
+ service_cleanup();
+
+ technology_cleanup();
+}
+
+int main (int argc, char *argv[])
+{
+ int err;
+ GMainLoop *main_loop;
+
+ umask(0077);
+
+ DBG("Wearable Connection Controller %s", VERSION);
+
+ if (daemon(0, 0) != 0)
+ DBG("Cannot start daemon");
+
+ g_type_init();
+
+#if 0
+ g_log_set_always_fatal(
+ G_LOG_FATAL_MASK | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING);
+#endif
+
+ g_log_set_default_handler(__on_log_glib, NULL);
+
+ main_loop = g_main_loop_new(NULL, FALSE);
+
+ err = dbus_init(G_BUS_TYPE_SYSTEM, WECONN_SERVICE_DBUS, WECONN_PATH_DBUS,
+ __init);
+ if (err < 0)
+ return -1;
+
+ g_main_loop_run(main_loop);
+
+ __cleanup();
+
+ dbus_cleanup();
+
+ return 0;
+}
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <errno.h>
+#include <stdarg.h>
+
+#include "log.h"
+#include "dbus.h"
+#include "error.h"
+#include "events.h"
+#include "object.h"
+
+#include "weconn_type.h"
+
+struct wc_callback_type {
+ const char *event;
+ WcObjectCallback callback;
+ void *user_data;
+};
+
+struct wc_element_type {
+ const char *element_name;
+ void *element;
+};
+
+struct wc_object {
+ const char *name;
+ unsigned int type;
+
+ GSList *element_list;
+
+ GSList *callbacks;
+ GHashTable *property;
+ void *user_data;
+
+ char *service_connecting;
+ guint timeout_connecting;
+ char *service_disconnecting;
+ guint timeout_disconnecting;
+
+ GDBusInterfaceSkeleton *di;
+};
+
+static GSList *object_list;
+
+EXPORT_API WcObject *wc_object_new(const char *name, unsigned int type)
+{
+ struct wc_object *wo;
+
+ if (!name)
+ return NULL;
+
+ wo = g_try_new0(struct wc_object, 1);
+ if (!wo)
+ return NULL;
+
+ wo->name = g_strdup(name);
+ wo->type = type;
+ wo->property = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, g_free);
+
+ object_list = g_slist_append(object_list, wo);
+
+ return wo;
+}
+
+EXPORT_API void wc_object_free(WcObject *wo)
+{
+ GSList *list = NULL;
+ struct wc_callback_type *wcb = NULL;
+ struct wc_element_type *we;
+
+ if (!wo)
+ return;
+
+ g_free((gpointer)wo->name);
+ g_object_unref(wo->di);
+ g_hash_table_destroy(wo->property);
+
+ if (wo->callbacks) {
+ for (list = wo->callbacks; list; list = list->next) {
+ wcb = (struct wc_callback_type *)list->data;
+ if (!wcb)
+ continue;
+
+ if (wcb->event)
+ g_free((gpointer)wcb->event);
+
+ g_free(wcb);
+ }
+
+ g_slist_free(wo->callbacks);
+ wo->callbacks = NULL;
+ }
+
+ for (list = wo->element_list; list; list = list->next) {
+ we = (struct wc_element_type *)list->data;
+
+ g_free((gpointer)we->element_name);
+ g_free(we->element);
+ }
+
+ g_slist_free(wo->element_list);
+
+ object_list = g_slist_remove(object_list, wo);
+
+ g_free(wo);
+}
+
+EXPORT_API WcObject *wc_object_find(const char *name)
+{
+ GSList *list = object_list;
+ WcObject *wo;
+
+ if (!name)
+ return NULL;
+
+ while (list) {
+ wo = (WcObject *)list->data;
+ if (g_strcmp0(wo->name, name) == 0)
+ return wo;
+
+ list = list->next;
+ }
+
+ return NULL;
+}
+
+EXPORT_API const char *wc_object_get_name(WcObject *wo)
+{
+ if (!wo)
+ return NULL;
+
+ return g_strdup(wo->name);
+}
+
+EXPORT_API const char *wc_object_peek_name(WcObject *wo)
+{
+ if (!wo)
+ return NULL;
+
+ return wo->name;
+}
+
+EXPORT_API unsigned int wc_object_get_type(WcObject *wo)
+{
+ if (!wo)
+ return 0;
+
+ return wo->type;
+}
+
+EXPORT_API int wc_object_append_element(WcObject *wo,
+ const char *element_name, void *element)
+{
+ GSList *list;
+ struct wc_element_type *we;
+
+ if (!wo || !element_name)
+ return -EINVAL;
+
+ if (strlen(element_name) < 1)
+ return -EINVAL;
+
+ /* Check already registered */
+ for (list = wo->element_list; list; list = list->next) {
+ we = (struct wc_element_type *)list->data;
+
+ if (we && g_strcmp0(element_name, we->element_name) == 0)
+ return -EALREADY;
+ }
+
+ we = g_try_new0(struct wc_element_type, 1);
+ if (!we)
+ return -ENOMEM;
+
+ we->element_name = g_strdup(element_name);
+ we->element = element;
+
+ wo->element_list = g_slist_append(wo->element_list, we);
+
+ return 0;
+}
+
+EXPORT_API void *wc_object_get_element(WcObject *wo, const char *element_name)
+{
+ GSList *list;
+ struct wc_element_type *we;
+
+ if (!wo || !element_name)
+ return NULL;
+
+ if (strlen(element_name) < 1)
+ return NULL;
+
+ for (list = wo->element_list; list; list = list->next) {
+ we = (struct wc_element_type *)list->data;
+
+ if (we && g_strcmp0(element_name, we->element_name) == 0)
+ return we->element;
+ }
+
+ return NULL;
+}
+
+EXPORT_API int wc_object_foreach_get_elements(WcObject *wo,
+ wc_object_foreach_get_elements_cb callback, void *user_data)
+{
+ GSList *list;
+ struct wc_element_type *we;
+
+ if (!wo || !callback)
+ return -EINVAL;
+
+ for (list = wo->element_list; list; list = list->next) {
+ we = (struct wc_element_type *)list->data;
+
+ callback(wo, we->element_name, we->element, user_data);
+ }
+
+ return 0;
+}
+
+EXPORT_API int wc_object_set_dbus_interface(WcObject *wo,
+ GDBusInterfaceSkeleton *di)
+{
+ if (!wo || !di)
+ return -EINVAL;
+
+ wo->di = di;
+ return 0;
+}
+
+EXPORT_API GDBusInterfaceSkeleton *wc_object_get_dbus_interface(WcObject *wo)
+{
+ if (!wo)
+ return NULL;
+
+ return wo->di;
+}
+
+EXPORT_API int wc_object_export(WcObject *wo, const char *path)
+{
+ GError *error = NULL;
+ gboolean ret;
+ const char *real_path = NULL;
+
+ if (!wo || !path)
+ return -EINVAL;
+
+ if (!wo->di)
+ return -EINVAL;
+
+ real_path = dbus_name2path(path);
+
+ if (g_variant_is_object_path(real_path) == FALSE) {
+ wc_error_add("InvalidName %s", real_path);
+ g_free((gpointer)real_path);
+ return -EINVAL;
+ }
+
+ ret = g_dbus_interface_skeleton_export(wo->di, dbus_get_connection(),
+ real_path, &error);
+ if (ret == FALSE) {
+ if (error) {
+ wc_error_add("%s", error->message);
+ g_error_free(error);
+ } else
+ wc_error_add("DBusObjectPathFailed");
+
+ g_free((gpointer)real_path);
+ return -EIO;
+ }
+
+ wc_object_set_property(wo, "object-path", real_path);
+
+ g_free((gpointer)real_path);
+
+ return 0;
+}
+
+EXPORT_API int wc_object_unexport(WcObject *wo)
+{
+ if (!wo)
+ return -EINVAL;
+
+ if (!wo->di)
+ return -EINVAL;
+
+ g_dbus_interface_skeleton_unexport(wo->di);
+
+ return 0;
+}
+
+EXPORT_API int wc_object_add_callback(WcObject *wo, const char *event,
+ WcObjectCallback callback, void *user_data)
+{
+ GSList *list;
+ struct wc_callback_type *wcb = NULL;
+
+ if (!wo || !event || !callback)
+ return -EINVAL;
+
+ if (strlen(event) < 1)
+ return -EINVAL;
+
+ /* Check already registered */
+ list = wo->callbacks;
+ while (list) {
+ wcb = (struct wc_callback_type *)list->data;
+ if (wcb && wcb->callback == callback && g_strcmp0(wcb->event, event) == 0)
+ return -EALREADY;
+
+ list = list->next;
+ }
+
+ wcb = g_try_new0(struct wc_callback_type, 1);
+ if (!wcb)
+ return -ENOMEM;
+
+ wcb->event = g_strdup(event);
+ wcb->callback = callback;
+ wcb->user_data = user_data;
+
+ wo->callbacks = g_slist_append(wo->callbacks, wcb);
+
+ return 0;
+}
+
+EXPORT_API int wc_object_del_callback(WcObject *wo, const char *event,
+ WcObjectCallback callback)
+{
+ struct wc_callback_type *wcb = NULL;
+ GSList *l = NULL;
+
+ if (!wo || !event || !callback || !wo->callbacks)
+ return -EINVAL;
+
+ if (strlen(event) < 1)
+ return -EINVAL;
+
+ l = wo->callbacks;
+ while (l) {
+ wcb = l->data;
+ if (!wcb) {
+ l = l->next;
+ continue;
+ }
+
+ if (wcb->callback != callback) {
+ l = l->next;
+ continue;
+ }
+
+ if (g_strcmp0(wcb->event, event) != 0) {
+ l = l->next;
+ continue;
+ }
+
+ l = l->next;
+ wo->callbacks = g_slist_remove(wo->callbacks, wcb);
+ g_free((gpointer)wcb->event);
+ g_free(wcb);
+ }
+
+ return 0;
+}
+
+EXPORT_API int wc_object_emit_callback(WcObject *wo, const char *event,
+ const void *event_info)
+{
+ struct wc_callback_type *wcb = NULL;
+ GSList *l = NULL;
+ size_t event_len;
+
+ if (!wo || !event)
+ return -EINVAL;
+
+ event_len = strlen(event);
+ if (event_len < 1)
+ return -EINVAL;
+
+ l = wo->callbacks;
+ while (l) {
+ wcb = l->data;
+ if (!wcb) {
+ l = l->next;
+ continue;
+ }
+
+ if (g_strcmp0(wcb->event, event) != 0) {
+ l = l->next;
+ continue;
+ }
+
+ if (wcb->callback) {
+ int ret = wcb->callback(wo, event_info, wcb->user_data);
+ if (ret == FALSE) {
+ l = l->next;
+ wo->callbacks = g_slist_remove(wo->callbacks, wcb);
+ continue;
+ }
+ }
+
+ l = l->next;
+ }
+
+ if (wo->di && event_len > 5 && g_str_has_prefix(event, "dbus-") == TRUE) {
+ /*
+ * if event is 'dbus-xxx', emit dbus signal 'xxx'
+ * but, only support one parameter.
+ *
+ * if you want use multiple parameters,
+ * use g_signal_emit_by_name() directly.
+ */
+ g_signal_emit_by_name(wo->di, event + 5, event_info);
+ }
+
+ return 0;
+}
+
+static GSList *_set_property_real(WcObject *wo, const char *key,
+ const char *value, GSList *list)
+{
+ if (!wo || !key)
+ return list;
+
+ if (!value) {
+ g_hash_table_remove(wo->property, key);
+
+ return g_slist_append(list, (gpointer)key);
+ }
+
+ g_hash_table_replace(wo->property, g_strdup(key), g_strdup(value));
+
+ return g_slist_append(list, (gpointer)key);
+}
+
+EXPORT_API int wc_object_set_property_full(WcObject *wo,
+ const char *first_property, ...)
+{
+ va_list argptr;
+ GSList *list = NULL;
+ const char *k;
+ const char *v;
+
+ if (!wo || !first_property)
+ return -EINVAL;
+
+ va_start(argptr, first_property);
+
+ k = first_property;
+ v = va_arg(argptr, char *);
+ list = _set_property_real(wo, k, v, list);
+
+ while (1) {
+ k = va_arg(argptr, char *);
+ if (!k)
+ break;
+
+ v = va_arg(argptr, char *);
+ list = _set_property_real(wo, k, v, list);
+ }
+
+ va_end(argptr);
+
+ if (!list)
+ return -ENODATA;
+
+ if (g_slist_length(list) > 0)
+ wc_object_emit_callback(wo, WC_OBJECT_EVENT_PROPERTY_CHANGED, list);
+
+ g_slist_free(list);
+
+ return 0;
+}
+
+EXPORT_API char *wc_object_get_property(WcObject *wo, const char *key)
+{
+ if (!wo || !key)
+ return NULL;
+
+ return g_strdup(g_hash_table_lookup(wo->property, key));
+}
+
+EXPORT_API const char *wc_object_peek_property(WcObject *wo, const char *key)
+{
+ if (!wo || !key)
+ return NULL;
+
+ return g_hash_table_lookup(wo->property, key);
+}
+
+EXPORT_API GHashTable *wc_object_peek_property_hash(WcObject *wo)
+{
+ if (!wo)
+ return NULL;
+
+ return wo->property;
+}
+
+EXPORT_API void wc_object_set_timeout_connecting(WcObject *wo,
+ guint timeout, const char *service)
+{
+ if (!wo)
+ return;
+
+ wo->timeout_connecting = timeout;
+
+ if (wo->service_connecting != NULL) {
+ g_free(wo->service_connecting);
+ wo->service_connecting = NULL;
+ }
+
+ if (service != NULL)
+ wo->service_connecting = g_strdup(service);
+}
+
+EXPORT_API guint wc_object_get_timeout_connecting(WcObject *wo)
+{
+ if (!wo)
+ return 0;
+
+ return wo->timeout_connecting;
+}
+
+EXPORT_API char *wc_object_get_connecting_service(WcObject *wo)
+{
+ if (!wo)
+ return 0;
+
+ return wo->service_connecting;
+}
+
+EXPORT_API void wc_object_set_timeout_disconnecting(WcObject *wo,
+ guint timeout, const char *service)
+{
+ if (!wo)
+ return;
+
+ wo->timeout_disconnecting = timeout;
+
+ if (wo->service_disconnecting != NULL) {
+ g_free(wo->service_disconnecting);
+ wo->service_disconnecting = NULL;
+ }
+
+ if (service != NULL)
+ wo->service_disconnecting = g_strdup(service);
+}
+
+EXPORT_API guint wc_object_get_timeout_disconnecting(WcObject *wo)
+{
+ if (!wo)
+ return 0;
+
+ return wo->timeout_disconnecting;
+}
+
+EXPORT_API char *wc_object_get_disconnecting_service(WcObject *wo)
+{
+ if (!wo)
+ return 0;
+
+ return wo->service_disconnecting;
+}
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <errno.h>
+#include <gio/gio.h>
+
+#include "log.h"
+#include "dbus.h"
+#include "object.h"
+#include "service.h"
+
+#include "generated-code.h"
+
+static WcObject *wo_service;
+
+int service_init(void)
+{
+ GDBusInterfaceSkeleton *di;
+
+ wo_service = wc_object_new("service", WC_OBJECT_TYPE_SERVICE);
+ if (!wo_service)
+ return -ENOMEM;
+
+ di = G_DBUS_INTERFACE_SKELETON(weconn_service_skeleton_new());
+
+ /* TODO: extend technology to get bearers' properties */
+ wc_object_append_element(wo_service, "service", NULL);
+ wc_object_set_dbus_interface(wo_service, di);
+ wc_object_export(wo_service, WECONN_SERVICE_PATH);
+
+ return 0;
+}
+
+void service_cleanup(void)
+{
+ /* TODO: clean all of services */
+
+ wc_object_unexport(wo_service);
+ wc_object_free(wo_service);
+}
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <errno.h>
+#include <gio/gio.h>
+
+#include "log.h"
+#include "dbus.h"
+#include "util.h"
+#include "error.h"
+#include "driver.h"
+#include "events.h"
+#include "object.h"
+#include "technology.h"
+
+#include "generated-code.h"
+
+#define CONNECT_TIMEOUT 120
+
+static GSList *technology_list = NULL;
+
+static void __dbus_builder_add_sv(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ GVariantBuilder *b = user_data;
+ if (!b)
+ return;
+
+ g_variant_builder_add(b, "{sv}", key, g_variant_new_string(value));
+}
+
+static gboolean __get_properties(GDBusInterfaceSkeleton *di,
+ GDBusMethodInvocation *invocation, gpointer user_data)
+{
+ WcObject *wo = (WcObject *)user_data;
+ GVariant *result = NULL;
+ GVariantBuilder *b;
+
+ DBG("");
+
+ if (!wo) {
+ wc_error_add("InvalidArguments");
+ wc_error_return(invocation);
+ return TRUE;
+ }
+
+ b = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+
+ g_hash_table_foreach(wc_object_peek_property_hash(wo),
+ __dbus_builder_add_sv, b);
+
+ result = g_variant_builder_end(b);
+
+ g_variant_builder_unref(b);
+
+ g_dbus_method_invocation_return_value(invocation,
+ g_variant_new("(@a{sv})", result));
+
+ return TRUE;
+}
+
+static gboolean __get_property(GDBusInterfaceSkeleton *di,
+ GDBusMethodInvocation *invocation,
+ const gchar *name, gpointer user_data)
+{
+ gpointer value;
+ WcObject *wo = (WcObject *)user_data;
+ weconn_service_type_e service_type;
+ weconn_device_type_e device_type;
+ const char *default_property = NULL;
+
+ DBG("%s", name);
+
+ if (!wo || !name) {
+ wc_error_add("InvalidArguments");
+ wc_error_return(invocation);
+ return TRUE;
+ }
+
+ service_type = wc_service_type_string2enum(name);
+ if (service_type)
+ default_property = XSTR(W_SERVICE_STATE_DISCONNECTED);
+ else {
+ device_type = wc_device_type_string2enum(name);
+
+ if (device_type)
+ default_property = XSTR(W_DEVICE_STATE_DISABLED);
+ else {
+ wc_error_add("InvalidArguments");
+ wc_error_return(invocation);
+ return TRUE;
+ }
+ }
+
+ value = g_hash_table_lookup(wc_object_peek_property_hash(wo), name);
+ if (value) {
+ g_dbus_method_invocation_return_value(invocation,
+ g_variant_new("(v)", g_variant_new_string(value)));
+ } else {
+ g_dbus_method_invocation_return_value(invocation,
+ g_variant_new("(v)", g_variant_new_string(default_property)));
+ }
+
+ return TRUE;
+}
+
+static gboolean __set_property(GDBusInterfaceSkeleton *di,
+ GDBusMethodInvocation *invocation,
+ const gchar *name, gpointer user_data)
+{
+ WcObject *wo = (WcObject *)user_data;
+
+ DBG("%s", name);
+
+ if (!wo || !name) {
+ wc_error_add("InvalidArguments");
+ wc_error_return(invocation);
+ return TRUE;
+ }
+
+ /* TODO: set property */
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("()"));
+
+ return TRUE;
+}
+
+static gboolean __scan(GDBusInterfaceSkeleton *di,
+ GDBusMethodInvocation *invocation, gpointer user_data)
+{
+ WcObject *wo = (WcObject *)user_data;
+
+ DBG("");
+
+ if (!wo) {
+ wc_error_add("InvalidArguments");
+ wc_error_return(invocation);
+ return TRUE;
+ }
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("()"));
+
+ return TRUE;
+}
+
+static const char *__service_type_string2_driver_name(const char *service_type)
+{
+ if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_HFP), service_type) == 0)
+ return "bluetooth";
+ else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_SPP), service_type) == 0)
+ return "esap";
+ else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_PAN), service_type) == 0)
+ return "pan";
+ else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_GATT), service_type) == 0)
+ return "bluetooth";
+ else if (g_strcmp0(XSTR(W_SERVICE_TYPE_CELLULAR), service_type) == 0)
+ return "cellular";
+ else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI), service_type) == 0)
+ return "wifi";
+ else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI_P2P), service_type) == 0)
+ return "p2p";
+ else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI_ADHOC), service_type) == 0)
+ return "adhoc";
+ else if (g_strcmp0(XSTR(W_SERVICE_TYPE_ETHERNET), service_type) == 0)
+ return "ethernet";
+
+ return NULL;
+}
+
+static void __connect_result_emit_signal(WcObject *wo,
+ const gchar *service, const char *signal_name, int result)
+{
+ GDBusConnection *connection = NULL;
+ GError *error = NULL;
+ GVariant *variant = NULL;
+
+ if (!wo)
+ return;
+
+ if (!service) {
+ ERR("service is NULL");
+ return;
+ }
+
+ connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+ if (!connection) {
+ ERR("Failed to get system bus[%s]", error->message);
+ g_error_free(error);
+ return;
+ }
+
+ variant = g_variant_new("(si)", service, result);
+
+ g_dbus_connection_emit_signal(connection, NULL,
+ WECONN_PATH_DBUS, WECONN_TECHNOLOGY_INTERFACE,
+ signal_name, variant, NULL);
+
+ g_object_unref(connection);
+}
+
+static gboolean __connect_timeout_cb(gpointer user_data)
+{
+ char *service = NULL;
+ char *state = NULL;
+ WcObject *wo = (WcObject *)user_data;
+ if (!wo)
+ return FALSE;
+
+ service = wc_object_get_connecting_service(wo);
+ if (!service)
+ return FALSE;
+
+ state = wc_object_get_property(wo, service);
+ if (state != NULL) {
+ if (g_strcmp0(state, XSTR(W_SERVICE_STATE_DISCONNECTED)) != 0)
+ wc_object_set_property(wo, service,
+ XSTR(W_SERVICE_STATE_DISCONNECTED));
+
+ g_free(state);
+ }
+
+ __connect_result_emit_signal(wo, service,
+ WECONN_TECHNOLOGY_SIGNAL_CONNECTION_RESULT, -ETIMEDOUT);
+
+ wc_object_set_timeout_connecting(wo, 0, NULL);
+
+ DBG("connect_timeout callback");
+ return FALSE;
+}
+
+static gboolean __disconnect_timeout_cb(gpointer user_data)
+{
+ char *service = NULL;
+ char *state = NULL;
+ WcObject *wo = (WcObject *)user_data;
+ if (!wo)
+ return FALSE;
+
+ service = wc_object_get_disconnecting_service(wo);
+ if (!service)
+ return FALSE;
+
+ state = wc_object_get_property(wo, service);
+ if (state != NULL) {
+ if (g_strcmp0(state, XSTR(W_SERVICE_STATE_CONNECTED)) != 0)
+ wc_object_set_property(wo, service,
+ XSTR(W_SERVICE_STATE_CONNECTED));
+
+ g_free(state);
+ }
+
+ __connect_result_emit_signal(wo, service,
+ WECONN_TECHNOLOGY_SIGNAL_DISCONNECTION_RESULT, -ETIMEDOUT);
+
+ wc_object_set_timeout_disconnecting(wo, 0, NULL);
+
+ DBG("disconnect_timeout callback");
+ return FALSE;
+}
+
+static void __connect_timer_clear(WcObject *wo)
+{
+ guint timer = 0;
+
+ if (!wo)
+ return;
+
+ timer = wc_object_get_timeout_connecting(wo);
+ if (timer > 0) {
+ g_source_remove(timer);
+ wc_object_set_timeout_connecting(wo, 0, NULL);
+ }
+
+ DBG("connect_timer cleared");
+}
+
+static void __disconnect_timer_clear(WcObject *wo)
+{
+ guint timer = 0;
+
+ if (!wo)
+ return;
+
+ timer = wc_object_get_timeout_disconnecting(wo);
+ if (timer > 0) {
+ g_source_remove(timer);
+ wc_object_set_timeout_disconnecting(wo, 0, NULL);
+ }
+
+ DBG("disconnect_timer cleared");
+}
+
+static gboolean __connect(GDBusInterfaceSkeleton *di,
+ GDBusMethodInvocation *invocation,
+ const gchar *service, gpointer user_data)
+{
+ int err;
+ guint timer;
+ char *service_state;
+ WcObject *wo = (WcObject *)user_data;
+
+ DBG("");
+
+ /* TODO:
+ * 1. If host CM, at first configure PAN, BT tethering on,
+ * and send PAN_CONNECTION command to wearable CM.
+ * 2. If wearable CM, send PAN_CONFIGURATION command to host CM.
+ */
+
+ // __request_pan_configuration();
+
+ /* TODO:
+ * After PAN_CONNECTION request from host CM, do following procedure.
+ */
+
+ if (!wo || wc_object_get_type(wo) != WC_OBJECT_TYPE_BEARER_DRIVER) {
+ wc_error_add("InvalidArguments");
+ wc_error_return(invocation);
+ return TRUE;
+ }
+
+ service_state = wc_object_get_property(wo, service);
+ if (service_state != NULL) {
+ if (g_strcmp0(service_state, XSTR(W_SERVICE_STATE_CONNECTING)) == 0) {
+ wc_error_add("InProgress");
+ wc_error_return(invocation);
+ g_free(service_state);
+ return TRUE;
+ }
+ g_free(service_state);
+ }
+
+ err = wc_bearer_driver_connect(wo, NULL,
+ __service_type_string2_driver_name(service));
+ if (err == -EISCONN) {
+ wc_error_add("AlreadyConnected");
+ wc_error_return(invocation);
+ return TRUE;
+ } else if (err == -EIO) {
+ wc_error_add("LostConnection");
+ wc_error_return(invocation);
+ return TRUE;
+ } else if (err < 0) {
+ /* TODO: specific error code should be defined */
+ wc_error_add("ConnectionFailed");
+ wc_error_return(invocation);
+ return TRUE;
+ }
+
+ if (wc_object_get_timeout_connecting(wo) == 0) {
+ wc_object_set_property(wo, service, XSTR(W_SERVICE_STATE_CONNECTING));
+ timer = g_timeout_add_seconds(CONNECT_TIMEOUT,
+ __connect_timeout_cb, wo);
+ wc_object_set_timeout_connecting(wo, timer, service);
+ }
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("()"));
+ return TRUE;
+}
+
+static gboolean __disconnect(GDBusInterfaceSkeleton *di,
+ GDBusMethodInvocation *invocation,
+ const gchar *service, gpointer user_data)
+{
+ int err;
+ guint timer;
+ char *service_state;
+ WcObject *wo = (WcObject *)user_data;
+
+ DBG("");
+
+ if (!wo || wc_object_get_type(wo) != WC_OBJECT_TYPE_BEARER_DRIVER) {
+ wc_error_add("InvalidArguments");
+ wc_error_return(invocation);
+ return TRUE;
+ }
+
+ service_state = wc_object_get_property(wo, service);
+ if (service_state != NULL) {
+ if (g_strcmp0(service_state, XSTR(W_SERVICE_STATE_DISCONNECTING)) == 0) {
+ wc_error_add("InProgress");
+ wc_error_return(invocation);
+ g_free(service_state);
+ return TRUE;
+ }
+ g_free(service_state);
+ }
+
+ err = wc_bearer_driver_disconnect(wo,
+ __service_type_string2_driver_name(service));
+ if (err == -ENOTCONN) {
+ wc_error_add("NotConnected");
+ wc_error_return(invocation);
+
+ return TRUE;
+ } else if (err < 0) {
+ /* TODO: specific error code should be defined */
+ wc_error_add("DisconnectionFailed");
+ wc_error_return(invocation);
+ return TRUE;
+ }
+
+ if (wc_object_get_timeout_disconnecting(wo) == 0) {
+ wc_object_set_property(wo, service, XSTR(W_SERVICE_STATE_DISCONNECTING));
+ timer = g_timeout_add_seconds(CONNECT_TIMEOUT,
+ __disconnect_timeout_cb, wo);
+ wc_object_set_timeout_disconnecting(wo, timer, service);
+ }
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("()"));
+ return TRUE;
+}
+
+static gboolean __wc_technology_bt_property_changed_cb(WcObject *wo,
+ const void *event_info, void *user_data)
+{
+ const char *key = NULL;
+ char *state = NULL;
+ char *service = NULL;
+ char *bcmservice_state = NULL;
+ GSList *list_properies = NULL;
+ GSList *list = NULL;
+
+ list_properies = (GSList *)event_info;
+ if (!list_properies)
+ return TRUE;
+
+ if (g_slist_length(list_properies) < 1) {
+ ERR("No property");
+ return TRUE;
+ }
+
+ for (list = list_properies; list; list = list->next) {
+ key = (const char *)list->data;
+ DBG("property : %s", key);
+ if (g_strcmp0(key, XSTR(W_SERVICE_TYPE_BT_PAN)) == 0) {
+ state = wc_object_get_property(wo, key);
+ if (!state)
+ continue;
+
+ DBG("state : %s", state);
+
+ if (g_strcmp0(state, XSTR(W_SERVICE_STATE_CONNECTED)) == 0) {
+
+ service = wc_object_get_connecting_service(wo);
+ if (g_strcmp0(service, key) == 0) {
+ __connect_result_emit_signal(wo, key,
+ WECONN_TECHNOLOGY_SIGNAL_CONNECTION_RESULT, 0);
+ __connect_timer_clear(wo);
+ }
+
+ service = wc_object_get_disconnecting_service(wo);
+ if (g_strcmp0(service, key) == 0) {
+ __connect_result_emit_signal(wo, key,
+ WECONN_TECHNOLOGY_SIGNAL_DISCONNECTION_RESULT, -ECANCELED);
+ __disconnect_timer_clear(wo);
+ return TRUE;
+ }
+
+ __connect_result_emit_signal(wo, key,
+ WECONN_TECHNOLOGY_SIGNAL_SERVICE_STATE_CHANGED,
+ W_SERVICE_STATE_CONNECTED);
+
+ } else if (g_strcmp0(state, XSTR(W_SERVICE_STATE_DISCONNECTED)) == 0) {
+
+ service = wc_object_get_connecting_service(wo);
+ if (g_strcmp0(service, key) == 0) {
+ bcmservice_state = wc_object_get_property(wo,
+ WC_OBJECT_EVENT_SAP_BCMSERVICE_STATUS);
+ if (g_strcmp0(bcmservice_state, XSTR(W_SERVICE_STATE_CONNECTED)) == 0)
+ __connect_result_emit_signal(wo, key,
+ WECONN_TECHNOLOGY_SIGNAL_CONNECTION_RESULT, -ECANCELED);
+ else
+ __connect_result_emit_signal(wo, key,
+ WECONN_TECHNOLOGY_SIGNAL_DISCONNECTION_RESULT, -EIO);
+
+ __connect_result_emit_signal(wo, key,
+ WECONN_TECHNOLOGY_SIGNAL_CONNECTION_RESULT, -ECANCELED);
+ __connect_timer_clear(wo);
+ return TRUE;
+ }
+
+ service = wc_object_get_disconnecting_service(wo);
+ if (g_strcmp0(service, key) == 0) {
+ bcmservice_state = wc_object_get_property(wo,
+ WC_OBJECT_EVENT_SAP_BCMSERVICE_STATUS);
+ if (g_strcmp0(bcmservice_state, XSTR(W_SERVICE_STATE_CONNECTED)) == 0)
+ __connect_result_emit_signal(wo, key,
+ WECONN_TECHNOLOGY_SIGNAL_DISCONNECTION_RESULT, 0);
+ else
+ __connect_result_emit_signal(wo, key,
+ WECONN_TECHNOLOGY_SIGNAL_DISCONNECTION_RESULT, -ENOTCONN);
+ __disconnect_timer_clear(wo);
+ }
+
+ __connect_result_emit_signal(wo, key,
+ WECONN_TECHNOLOGY_SIGNAL_SERVICE_STATE_CHANGED,
+ W_SERVICE_STATE_DISCONNECTED);
+ }
+
+ g_free(state);
+ }
+ }
+
+ return TRUE;
+}
+
+static void __wc_technology_register_service_state_changed(WcObject *wo)
+{
+ const char *technology;
+
+ if (!wo)
+ return;
+
+ technology = wc_object_peek_name(wo);
+ if (g_strcmp0(technology, WC_TECHNOLOGY_BLUETOOTH) == 0) {
+ wc_object_add_callback(wo, WC_OBJECT_EVENT_PROPERTY_CHANGED,
+ __wc_technology_bt_property_changed_cb, NULL);
+ } else if (g_strcmp0(technology, WC_TECHNOLOGY_CELLULAR) == 0) {
+
+ }
+}
+
+static gboolean __wc_technology_bearer_enabled_cb(WcObject *wo,
+ const void *event_info, void *user_data)
+{
+ const char *path;
+ GDBusInterfaceSkeleton *di;
+
+ DBG("technology %s added", wc_object_peek_name(wo));
+
+ if (!wo)
+ return TRUE;
+
+ di = G_DBUS_INTERFACE_SKELETON(weconn_technology_skeleton_new());
+
+ g_signal_connect(di, "handle-get-properties",
+ G_CALLBACK(__get_properties), wo);
+ g_signal_connect(di, "handle-get-property",
+ G_CALLBACK(__get_property), wo);
+ g_signal_connect(di, "handle-set-property",
+ G_CALLBACK(__set_property), wo);
+ g_signal_connect(di, "handle-get-properties",
+ G_CALLBACK(__scan), wo);
+ g_signal_connect(di, "handle-connect",
+ G_CALLBACK(__connect), wo);
+ g_signal_connect(di, "handle-disconnect",
+ G_CALLBACK(__disconnect), wo);
+
+ wc_object_set_dbus_interface(wo, di);
+
+ technology_list = g_slist_prepend(technology_list, wo);
+
+ path = g_strdup_printf("%s/%s",
+ WECONN_TECHNOLOGY_PATH, wc_object_peek_name(wo));
+
+ wc_object_export(wo, path);
+ g_free((gpointer)path);
+
+ __wc_technology_register_service_state_changed(wo);
+
+ return TRUE;
+}
+
+static gboolean __wc_technology_bearer_disabled_cb(WcObject *wo,
+ const void *event_info, void *user_data)
+{
+ if (!wo)
+ return TRUE;
+
+ wc_object_unexport(wo);
+
+ /* TODO: g_signal_connect_closure for each c_handler */
+
+ technology_list = g_slist_remove(technology_list, wo);
+
+ return TRUE;
+}
+
+int wc_technology_add_bearer(WcObject *wo)
+{
+ int err;
+
+ err = wc_object_add_callback(wo, WC_OBJECT_EVENT_BEARER_ENABLED,
+ __wc_technology_bearer_enabled_cb, NULL);
+ if (err < 0 && err != -EALREADY)
+ return err;
+
+ err = wc_object_add_callback(wo, WC_OBJECT_EVENT_BEARER_DISABLED,
+ __wc_technology_bearer_disabled_cb, NULL);
+
+ return err;
+}
+
+WcObject *wc_technology_get_bearer(const char *technology)
+{
+ GSList *list = technology_list;
+ WcObject *wo;
+
+ if (!technology)
+ return NULL;
+
+ while (list) {
+ wo = (WcObject *)list->data;
+ if (wo && g_strcmp0(technology, wc_object_peek_name(wo)) == 0)
+ return wo;
+
+ list = list->next;
+ }
+
+ return NULL;
+}
+
+int technology_init(void)
+{
+ /* TODO: initialize default technologies */
+
+ return 0;
+}
+
+void technology_cleanup(void)
+{
+ /* TODO: clean all of technologies */
+}
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <glib.h>
+
+#include "log.h"
+#include "util.h"
+
+#define CONNMAN_PATH "/net/connman"
+#define CONNMAN_CELLULAR_SERVICE_PROFILE_PREFIX \
+ CONNMAN_PATH "/service/cellular_"
+#define CONNMAN_WIFI_SERVICE_PROFILE_PREFIX \
+ CONNMAN_PATH "/service/wifi_"
+#define CONNMAN_ETHERNET_SERVICE_PROFILE_PREFIX \
+ CONNMAN_PATH "/service/ethernet_"
+#define CONNMAN_BLUETOOTH_SERVICE_PROFILE_PREFIX \
+ CONNMAN_PATH "/service/bluetooth_"
+
+weconn_service_type_e wc_service_type_string2enum(const char *service_type)
+{
+ if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_HFP), service_type) == 0)
+ return W_SERVICE_TYPE_BT_HFP;
+ else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_SPP), service_type) == 0)
+ return W_SERVICE_TYPE_BT_SPP;
+ else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_PAN), service_type) == 0)
+ return W_SERVICE_TYPE_BT_PAN;
+ else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_GATT), service_type) == 0)
+ return W_SERVICE_TYPE_BT_GATT;
+ else if (g_strcmp0(XSTR(W_SERVICE_TYPE_CELLULAR), service_type) == 0)
+ return W_SERVICE_TYPE_CELLULAR;
+ else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI), service_type) == 0)
+ return W_SERVICE_TYPE_WIFI;
+ else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI_P2P), service_type) == 0)
+ return W_SERVICE_TYPE_WIFI_P2P;
+ else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI_ADHOC), service_type) == 0)
+ return W_SERVICE_TYPE_WIFI_ADHOC;
+ else if (g_strcmp0(XSTR(W_SERVICE_TYPE_ETHERNET), service_type) == 0)
+ return W_SERVICE_TYPE_ETHERNET;
+
+ return 0x00;
+}
+
+const char *wc_service_type_enum2string(weconn_service_type_e service_type)
+{
+ switch (service_type) {
+ case W_SERVICE_TYPE_BT_HFP:
+ return XSTR(W_SERVICE_TYPE_BT_HFP);
+ case W_SERVICE_TYPE_BT_SPP:
+ return XSTR(W_SERVICE_TYPE_BT_SPP);
+ case W_SERVICE_TYPE_BT_PAN:
+ return XSTR(W_SERVICE_TYPE_BT_PAN);
+ case W_SERVICE_TYPE_BT_GATT:
+ return XSTR(W_SERVICE_TYPE_BT_GATT);
+ case W_SERVICE_TYPE_CELLULAR:
+ return XSTR(W_SERVICE_TYPE_CELLULAR);
+ case W_SERVICE_TYPE_WIFI:
+ return XSTR(W_SERVICE_TYPE_WIFI);
+ case W_SERVICE_TYPE_WIFI_P2P:
+ return XSTR(W_SERVICE_TYPE_WIFI_P2P);
+ case W_SERVICE_TYPE_WIFI_ADHOC:
+ return XSTR(W_SERVICE_TYPE_WIFI_ADHOC);
+ case W_SERVICE_TYPE_ETHERNET:
+ return XSTR(W_SERVICE_TYPE_ETHERNET);
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+weconn_service_state_e wc_service_state_string2enum(const char *service_state)
+{
+ if (g_strcmp0(XSTR(W_SERVICE_STATE_DISCONNECTED), service_state) == 0)
+ return W_SERVICE_STATE_DISCONNECTED;
+ else if (g_strcmp0(XSTR(W_SERVICE_STATE_CONNECTING), service_state) == 0)
+ return W_SERVICE_STATE_CONNECTING;
+ else if (g_strcmp0(XSTR(W_SERVICE_STATE_CONNECTED), service_state) == 0)
+ return W_SERVICE_STATE_CONNECTED;
+ else if (g_strcmp0(XSTR(W_SERVICE_STATE_DISCONNECTING), service_state) == 0)
+ return W_SERVICE_STATE_DISCONNECTING;
+
+ return 0x00;
+}
+
+const char *wc_service_state_enum2string(weconn_service_state_e service_state)
+{
+ switch (service_state) {
+ case W_SERVICE_STATE_DISCONNECTED:
+ return XSTR(W_SERVICE_STATE_DISCONNECTED);
+ case W_SERVICE_STATE_CONNECTING:
+ return XSTR(W_SERVICE_STATE_CONNECTING);
+ case W_SERVICE_STATE_CONNECTED:
+ return XSTR(W_SERVICE_STATE_CONNECTED);
+ case W_SERVICE_STATE_DISCONNECTING:
+ return XSTR(W_SERVICE_STATE_DISCONNECTING);
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+weconn_device_type_e wc_device_type_string2enum(const char *device_type)
+{
+ if (g_strcmp0(XSTR(W_DEVICE_TYPE_BT), device_type) == 0)
+ return W_DEVICE_TYPE_BT;
+ else if (g_strcmp0(XSTR(W_DEVICE_TYPE_CELLULAR), device_type) == 0)
+ return W_DEVICE_TYPE_CELLULAR;
+ else if (g_strcmp0(XSTR(W_DEVICE_TYPE_WIFI), device_type) == 0)
+ return W_DEVICE_TYPE_WIFI;
+ else if (g_strcmp0(XSTR(W_DEVICE_TYPE_WIFI_P2P), device_type) == 0)
+ return W_DEVICE_TYPE_WIFI_P2P;
+ else if (g_strcmp0(XSTR(W_DEVICE_TYPE_WIFI_ADHOC), device_type) == 0)
+ return W_DEVICE_TYPE_WIFI_ADHOC;
+ else if (g_strcmp0(XSTR(W_DEVICE_TYPE_ETHERNET), device_type) == 0)
+ return W_DEVICE_TYPE_ETHERNET;
+
+ return 0x00;
+}
+
+const char *wc_device_type_enum2string(weconn_device_type_e device_type)
+{
+ switch (device_type) {
+ case W_DEVICE_TYPE_BT:
+ return XSTR(W_DEVICE_TYPE_BT);
+ case W_DEVICE_TYPE_CELLULAR:
+ return XSTR(W_DEVICE_TYPE_CELLULAR);
+ case W_DEVICE_TYPE_WIFI:
+ return XSTR(W_DEVICE_TYPE_WIFI);
+ case W_DEVICE_TYPE_WIFI_P2P:
+ return XSTR(W_DEVICE_TYPE_WIFI_P2P);
+ case W_DEVICE_TYPE_WIFI_ADHOC:
+ return XSTR(W_DEVICE_TYPE_WIFI_ADHOC);
+ case W_DEVICE_TYPE_ETHERNET:
+ return XSTR(W_DEVICE_TYPE_ETHERNET);
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+weconn_device_state_e wc_device_state_string2enum(const char *device_state)
+{
+ if (g_strcmp0(XSTR(W_DEVICE_STATE_DISABLED), device_state) == 0)
+ return W_DEVICE_STATE_DISABLED;
+ else if (g_strcmp0(XSTR(W_DEVICE_STATE_ENABLED), device_state) == 0)
+ return W_DEVICE_STATE_ENABLED;
+
+ return 0x00;
+}
+
+const char *wc_device_state_enum2string(weconn_device_state_e device_state)
+{
+ switch (device_state) {
+ case W_DEVICE_STATE_DISABLED:
+ return XSTR(W_DEVICE_STATE_DISABLED);
+ case W_DEVICE_STATE_ENABLED:
+ return XSTR(W_DEVICE_STATE_ENABLED);
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+weconn_device_type_e wc_device_get_type_from_path(const char *path)
+{
+ if (g_str_has_prefix(path,
+ CONNMAN_WIFI_SERVICE_PROFILE_PREFIX) == TRUE)
+ return W_DEVICE_TYPE_WIFI;
+ else if (g_str_has_prefix(path,
+ CONNMAN_CELLULAR_SERVICE_PROFILE_PREFIX) == TRUE)
+ return W_DEVICE_TYPE_CELLULAR;
+ else if (g_str_has_prefix(path,
+ CONNMAN_ETHERNET_SERVICE_PROFILE_PREFIX) == TRUE)
+ return W_DEVICE_TYPE_ETHERNET;
+ else if (g_str_has_prefix(path,
+ CONNMAN_BLUETOOTH_SERVICE_PROFILE_PREFIX) == TRUE)
+ return W_DEVICE_TYPE_BT;
+
+ return 0x00;
+}
+
+int wc_launch_popup(weconn_popup_type_e type, service_reply_cb callback,
+ void *user_data)
+{
+ int ret;
+ service_h service = NULL;
+
+ ret = service_create(&service);
+ if (ret != SERVICE_ERROR_NONE) {
+ DBG("failed to create service [%d]", ret);
+ return -1;
+ }
+
+ switch (type) {
+ case WC_POPUP_TYPE_PAN_CONNECT:
+ service_add_extra_data(service, "_WCPOPUP_TYPE_", "pan_connect");
+ break;
+ case WC_POPUP_TYPE_PAN_DISCONNECT:
+ service_add_extra_data(service, "_WCPOPUP_TYPE_", "pan_disconnect");
+ break;
+ default:
+ ERR("Not support popup type [%d]", type);
+ service_destroy(service);
+ return -1;
+ }
+
+ service_set_package(service, "net.wc-popup");
+ ret = service_send_launch_request(service, callback, user_data);
+ if (ret != SERVICE_ERROR_NONE) {
+ DBG("failed service launch request [%d]", ret);
+ return -1;
+ }
+
+ service_destroy(service);
+
+ return 0;
+}
--- /dev/null
+SET(weconn_test "${PROJECT_NAME}-test")
+
+SET(dependents "capi-base-common gio-2.0 glib-2.0")
+SET(pc_dependents "capi-base-common")
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/client/include/)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(${weconn_test} REQUIRED ${dependents})
+FOREACH(flag ${${weconn_test}_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -Wall")
+
+aux_source_directory(. sources)
+FOREACH(src ${sources})
+ GET_FILENAME_COMPONENT(src_name ${src} NAME_WE)
+ MESSAGE("${src_name}")
+ ADD_EXECUTABLE(${src_name} ${src})
+ TARGET_LINK_LIBRARIES(${src_name} weconn ${${weconn_test}_LDFLAGS})
+ENDFOREACH()
--- /dev/null
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <glib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <weconn.h>
+#include <tizen_error.h>
+
+gboolean test_thread(GIOChannel *source, GIOCondition condition, gpointer data);
+
+static weconn_h connection = NULL;
+
+static int __get_service_type(void)
+{
+ int input, rv;
+
+ printf("Input service type:\n");
+ printf("1: W_SERVICE_TYPE_BT_HFP\n");
+ printf("2: W_SERVICE_TYPE_BT_SPP\n");
+ printf("3: W_SERVICE_TYPE_BT_PAN\n");
+ printf("4: W_SERVICE_TYPE_BT_GATT\n");
+ printf("5: W_SERVICE_TYPE_CELLULAR\n");
+ printf("6: W_SERVICE_TYPE_WIFI\n");
+ printf("7: W_SERVICE_TYPE_WIFI_P2P\n");
+ printf("8: W_SERVICE_TYPE_WIFI_ADHOC\n");
+ printf("9: W_SERVICE_TYPE_ETHERNET\n");
+ printf("11: W_SERVICE_TYPE_HOST_TO_WEARABLE_CONNECTIVITY\n");
+ printf("12: W_SERVICE_TYPE_INTERNET_CONNECTIVITY\n");
+
+ rv = scanf("%d", &input);
+ if (rv < 0)
+ return -EINVAL;
+
+ /* convert the real enum of service type */
+ printf("service type %02X\n", input);
+ if (input < 10) {
+ input = input + 0x10;
+ if (W_SERVICE_TYPE_BT_HFP <= input && input <= W_SERVICE_TYPE_ETHERNET)
+ return input;
+ } else {
+ input = input - 10;
+ if (W_SERVICE_TYPE_HOST_TO_WEARABLE_CONNECTIVITY == input ||
+ W_SERVICE_TYPE_INTERNET_CONNECTIVITY == input)
+ return input;
+ }
+
+ return -EINVAL;
+}
+
+static void __print_service_state(weconn_service_state_e state)
+{
+ switch (state) {
+ case W_SERVICE_STATE_DISCONNECTED:
+ printf("Disconnected\n");
+ break;
+ case W_SERVICE_STATE_CONNECTING:
+ printf("Connecting\n");
+ break;
+ case W_SERVICE_STATE_CONNECTED:
+ printf("Connected\n");
+ break;
+ case W_SERVICE_STATE_DISCONNECTING:
+ printf("Disconnected\n");
+ break;
+ default:
+ printf("Unknown\n");
+ }
+}
+
+static int __get_device_type(void)
+{
+ int input, rv;
+
+ printf("Input device type:\n");
+ printf("1: W_DEVICE_TYPE_BT\n");
+ printf("2: W_DEVICE_TYPE_CELLULAR\n");
+ printf("3: W_DEVICE_TYPE_WIFI\n");
+ printf("4: W_DEVICE_TYPE_WIFI_P2P\n");
+ printf("5: W_DEVICE_TYPE_WIFI_ADHOC\n");
+ printf("6: W_DEVICE_TYPE_ETHERNET\n");
+
+ rv = scanf("%d", &input);
+ if (rv < 0)
+ return -EINVAL;
+
+ printf("device type %d\n", input);
+ if (W_DEVICE_TYPE_BT <= input && input <= W_DEVICE_TYPE_ETHERNET)
+ return input;
+
+ return -EINVAL;
+}
+
+static void __print_device_state(weconn_service_state_e state)
+{
+ switch (state) {
+ case W_DEVICE_STATE_DISABLED:
+ printf("Disabled\n");
+ break;
+ case W_DEVICE_STATE_ENABLED:
+ printf("Enabled\n");
+ break;
+ default:
+ printf("Unknown\n");
+ }
+}
+
+static int test_register_client(void)
+{
+ int err = weconn_create(&connection);
+
+ if (err < 0) {
+ printf("Client registration failed [%d]\n", err);
+ return -EIO;
+ }
+
+ printf("Client registered successfully\n");
+
+ return 0;
+}
+
+static int test_deregister_client(void)
+{
+ int err = 0;
+
+ if (connection != NULL)
+ err = weconn_destroy(connection);
+ else {
+ printf("Cannot de-register: handle is NULL\n");
+ err = -EINVAL;
+ }
+
+ if (err < 0) {
+ printf("Client de-registration fail [%d]\n", err);
+ return err;
+ }
+
+ connection = NULL;
+
+ printf("Client de-registration success\n");
+
+ return 0;
+}
+
+static int test_get_service_state(void)
+{
+ int type, err;
+ weconn_service_state_e state;
+
+ type = __get_service_type();
+
+ err = weconn_get_service_state(connection, type, &state);
+ if (err < 0) {
+ printf("Failed to get service state [%d]", err);
+ return err;
+ }
+
+ __print_service_state(state);
+ return 0;
+}
+
+static int test_get_device_state(void)
+{
+ int type, err;
+ weconn_device_state_e state;
+
+ type = __get_device_type();
+
+ err = weconn_get_device_state(connection, type, &state);
+ if (err < 0) {
+ printf("Failed to get device state [%d]", err);
+ return err;
+ }
+
+ __print_device_state(state);
+ return 0;
+}
+
+static void __test_connect_service_callback(int result, void *user_data)
+{
+ if (result == 0)
+ printf("Succeed to connect\n");
+ else
+ printf("Failed to connect [%d]\n", result);
+}
+
+static void __test_disconnect_service_callback(int result, void *user_data)
+{
+ if (result == 0)
+ printf("Succeed to disconnect\n");
+ else
+ printf("Failed to disconnect [%d]\n", result);
+}
+
+static int test_connect_service(void)
+{
+ int err = 0;
+ weconn_service_type_e type;
+
+ type = __get_service_type();
+
+ err = weconn_connect_service(connection, type,
+ __test_connect_service_callback, NULL);
+ if (err < 0) {
+ printf("Failed to connect service [%d]", err);
+ return err;
+ }
+
+ return err;
+}
+
+static int test_disconnect_service(void)
+{
+ int err = 0;
+ weconn_service_type_e type;
+
+ type = __get_service_type();
+
+ err = weconn_disconnect_service(connection, type,
+ __test_disconnect_service_callback, NULL);
+ if (err < 0) {
+ printf("Failed to get device state [%d]", err);
+ return err;
+ }
+
+ return err;
+}
+
+static void _test_wearable_service_state_changed_cb(
+ weconn_service_state_e state, void *user_data)
+{
+ printf("wearable service state changed = %d\n", state);
+}
+
+static void _test_internet_service_state_changed_cb(
+ weconn_service_state_e state, void *user_data)
+{
+ printf("internet service state changed = %d\n", state);
+}
+
+static int test_register_service_connection_cb(void)
+{
+ int err = 0;
+ weconn_service_type_e type;
+
+ type = __get_service_type();
+
+ switch (type) {
+ case W_SERVICE_TYPE_HOST_TO_WEARABLE_CONNECTIVITY:
+ err = weconn_set_service_state_change_cb(connection,
+ _test_wearable_service_state_changed_cb, type, NULL);
+ if (err < 0) {
+ printf("Register_service_connectionn failed [%d]\n", err);
+ return -EIO;
+ }
+ break;
+ case W_SERVICE_TYPE_INTERNET_CONNECTIVITY :
+ err = weconn_set_service_state_change_cb(connection,
+ _test_internet_service_state_changed_cb, type, NULL);
+ if (err < 0) {
+ printf("Register_service_connectionn failed [%d]\n", err);
+ return -EIO;
+ }
+ break;
+ case W_SERVICE_TYPE_BT_HFP:
+ case W_SERVICE_TYPE_BT_SPP:
+ case W_SERVICE_TYPE_BT_PAN:
+ case W_SERVICE_TYPE_BT_GATT:
+ case W_SERVICE_TYPE_CELLULAR:
+ case W_SERVICE_TYPE_WIFI:
+ case W_SERVICE_TYPE_WIFI_P2P:
+ case W_SERVICE_TYPE_WIFI_ADHOC:
+ case W_SERVICE_TYPE_ETHERNET:
+ printf("Not support service type [%d]\n", type);
+ return -EINVAL;
+ }
+
+ printf("Register_service_connectionn successfully\n");
+
+ return 0;
+}
+
+static int test_unregister_service_connection_cb(void)
+{
+ int err = 0;
+ weconn_service_type_e type;
+
+ type = __get_service_type();
+
+ if (type > W_SERVICE_TYPE_INTERNET_CONNECTIVITY)
+ printf("Not support service type [%d]\n", type);
+
+ err = weconn_unset_service_state_change_cb(connection, type);
+ if (err < 0) {
+ printf("Unregister_service_connectionn failed [%d]\n", err);
+ return -EIO;
+ }
+
+ printf("Unregister_service_connectionn successfully\n");
+
+ return 0;
+}
+
+static void __print_menu(void)
+{
+ printf("\nWearable Connection API Test App\n\n");
+ printf("Options..\n");
+ printf("1 - Create Handle\n");
+ printf("2 - Destroy Handle(unset callbacks automatically)\n");
+ printf("3 - Get wearable service state\n");
+ printf("4 - Get wearable device state\n");
+ printf("5 - Connect wearable service\n");
+ printf("6 - Disconnect wearable service\n");
+ printf("7 - Register wearable service connection callback\n");
+ printf("8 - Unregister wearable service connection callback\n");
+ printf("0 - Exit \n");
+ printf("ENTER - Show options menu.......\n");
+}
+
+int main(int argc, char **argv)
+{
+ GMainLoop *mainloop;
+ GIOChannel *channel;
+ mainloop = g_main_loop_new (NULL, FALSE);
+
+ channel = g_io_channel_unix_new(0);
+ g_io_add_watch(channel, (G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL),
+ test_thread,NULL );
+
+ __print_menu();
+
+ g_main_loop_run (mainloop);
+
+ return 0;
+}
+
+gboolean test_thread(GIOChannel *source, GIOCondition condition, gpointer data)
+{
+ int rv = 0;
+ char cmds[100];
+ char cmd;
+
+ memset(cmds, '\0', 100);
+ rv = read(0, cmds, 100);
+
+ cmd = *cmds;
+
+ if (cmd == '\n' || cmd == '\r'){
+ __print_menu();
+
+ return TRUE;
+ }
+
+ switch (cmd) {
+ case '0':
+ if (connection != NULL)
+ test_deregister_client();
+
+ exit(1);
+ case '1':
+ rv = test_register_client();
+ break;
+ case '2':
+ rv = test_deregister_client();
+ break;
+ case '3':
+ rv = test_get_service_state();
+ break;
+ case '4':
+ rv = test_get_device_state();
+ break;
+ case '5':
+ rv = test_connect_service();
+ break;
+ case '6':
+ rv = test_disconnect_service();
+ break;
+ case '7':
+ rv = test_register_service_connection_cb();
+ break;
+ case '8':
+ rv = test_unregister_service_connection_cb();
+ break;
+ default:
+ break;
+ }
+
+ if (rv == 0)
+ printf("Operation succeeded!\n\n");
+ else
+ printf("Operation failed!\n\n");
+
+ return TRUE;
+}
--- /dev/null
+<manifest>
+ <define>
+ <domain name="weconn"/>
+ <request>
+ <smack request="dbus" type="rwx"/>
+ <smack request="connman" type="rwx"/>
+ <smack request="aul::launch" type="x"/>
+ <smack request="bt-service::gap" type="rwx"/>
+ <smack request="bt-service::admin" type="rwx"/>
+ <smack request="bt-service::manager" type="rwx"/>
+ <smack request="alarm-server::alarm" type="rwx"/>
+ <smack request="sys-assert::core" type="rwxat"/>
+ <smack request="system::use_internet" type="rwx"/>
+ <smack request="system::vconf" type="rx"/>
+ <smack request="system::vconf_system" type="rwx"/>
+ <smack request="system::vconf_network" type="rwx"/>
+ <smack request="system::vconf_setting" type="rwx"/>
+ <smack request="telephony_framework::api_private" type="rw"/>
+ </request>
+ <permit>
+ <smack permit="dbus" type="rwx"/>
+ <smack permit="system::use_internet" type="rwx"/>
+ </permit>
+ </define>
+ <assign>
+ <filesystem path="/etc/dbus-1/system.d/weconn.conf" label="_"/>
+ <filesystem path="/usr/lib/systemd/system/weconn.service" label="_"/>
+ <filesystem path="/usr/lib/systemd/system/multi-user.target.wants/weconn.service" label="_"/>
+ <filesystem path="/usr/share/dbus-1/services/net.weconn.service" label="_"/>
+ <filesystem path="/etc/opt/upgrade/500.net.weconn.patch.sh" label="_" exec_label="none"/>
+ <filesystem path="/usr/share/appcessory/wearable-connection.xml" label="_"/>
+ <filesystem path="/usr/lib/libweconn.so.0" label="_" exec_label="none"/>
+ <filesystem path="/usr/lib/libweconn.so.0.*" label="_" exec_label="none"/>
+ <filesystem path="/usr/share/license/weconn" label="_"/>
+ <dbus name="net.weconn" own="weconn" bus="system">
+ <node name="/">
+ <interface name="net.weconn.Service">
+ <annotation name="net.weconn.smack" value="weconn"/>
+ </interface>
+ <interface name="net.weconn.Technology">
+ <annotation name="net.weconn.smack" value="weconn"/>
+ </interface>
+ </node>
+ </dbus>
+ <dbus name="net.weconn" own="weconn" bus="system">
+ <node name="/net/weconn/*">
+ <interface name="net.weconn.Service">
+ <annotation name="net.weconn.smack" value="weconn"/>
+ </interface>
+ <interface name="net.weconn.Technology">
+ <annotation name="net.weconn.smack" value="weconn"/>
+ </interface>
+ </node>
+ </dbus>
+ </assign>
+ <request>
+ <domain name="weconn"/>
+ </request>
+</manifest>