ADD_SUBDIRECTORY(plugins/dns-sd)
IF(BT_SUPPORT)
ADD_SUBDIRECTORY(plugins/ble)
+ ADD_SUBDIRECTORY(plugins/ble-gatt)
ENDIF(BT_SUPPORT)
ADD_SUBDIRECTORY(include)
--- /dev/null
+# Copyright (c) 2021 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.
+#
+
+SET(BLE_GATT_PLUGIN "vine-plugin-ble-gatt")
+
+SET(BLE_GATT_PLUGIN_VERSION_MAJOR "1")
+SET(BLE_GATT_PLUGIN_VERSION_MINOR "0")
+SET(BLE_GATT_PLUGIN_VERSION_PATCH "0")
+SET(BLE_GATT_PLUGIN_VERSION ${BLE_GATT_PLUGIN_VERSION_MAJOR}.${BLE_GATT_PLUGIN_VERSION_MINOR}.${BLE_GATT_PLUGIN_VERSION_PATCH})
+
+PKG_CHECK_MODULES(BLE_DEPS REQUIRED "capi-network-bluetooth")
+
+INCLUDE_DIRECTORIES(
+ ${VINE_PATH}/include
+ ${VINE_LOGGER_PATH}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${${fw_name}_INCLUDE_DIRS}
+ ${BLE_DEPS_INCLUDE_DIRS}
+)
+
+FILE(GLOB VINE_BLE_GATT_PLUGIN_SOURCES *.cpp)
+
+ADD_DEFINITIONS("-fvisibility=default")
+ADD_LIBRARY(${BLE_GATT_PLUGIN} SHARED ${VINE_BLE_GATT_PLUGIN_SOURCES})
+
+SET_TARGET_PROPERTIES(
+ ${BLE_GATT_PLUGIN}
+ PROPERTIES
+ SOVERSION ${BLE_GATT_PLUGIN_VERSION_MAJOR}
+)
+
+TARGET_LINK_LIBRARIES(${BLE_GATT_PLUGIN}
+ ${VINE_LOGGER}
+ ${BLE_DEPS_LIBRARIES}
+ ${fw_name_deps_LIBRARIES}
+ dl
+)
+
+INSTALL(TARGETS ${BLE_GATT_PLUGIN} DESTINATION "${LIB_DIR}")
--- /dev/null
+/*
+ * Copyright (c) 2021 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 <bluetooth.h>
+
+#include "vine-data-path-plugin.h"
+#include "vine-log.h"
+#include "vine-utils.h"
+
+using namespace std;
+
+// TODO: change UUIDs
+#define VINE_GATT_SERVICE_UUID "000018f2-0000-1000-8000-00805f9b34fb"
+#define VINE_GATT_CHAR_UUID "00002af6-0000-1000-8000-00805f9b34fb"
+#define VINE_GATT_DESC_UUID "fa87c0d0-afac-11de-8a39-0800200c9a66"
+
+typedef enum {
+ VINE_GATT_ROLE_UNKNOWN = 0,
+ VINE_GATT_ROLE_SERVER,
+ VINE_GATT_ROLE_CLIENT,
+} vine_gatt_role_e;
+
+typedef struct {
+ bt_gatt_h service;
+ bt_gatt_h characteristic;
+ bt_gatt_h descriptor;
+
+ vine_gatt_role_e type;
+ union {
+ bt_gatt_server_h server;
+ bt_gatt_client_h client;
+ } role;
+
+ char *remote_address;
+ bool is_accepted;
+ void *user; // vine_data_path_h
+} vine_gatt_s;
+
+static vine_dp_plugin_callbacks g_callbacks = {
+ .pollfd_cb = NULL,
+ .opened_cb = NULL,
+ .accepted_cb = NULL,
+ .connected_cb = NULL,
+ .received_cb = NULL,
+ .written_cb = NULL,
+ .terminated_cb = NULL,
+};
+
+static vine_gatt_s *_create_gatt(void);
+
+static vine_data_path_error __convert_bt_error_to_data_path_error(int error)
+{
+ switch (error) {
+ case BT_ERROR_NONE:
+ return VINE_DATA_PATH_ERROR_NONE;
+ case BT_ERROR_OUT_OF_MEMORY:
+ return VINE_DATA_PATH_ERROR_OUT_OF_MEMORY;
+ case BT_ERROR_INVALID_PARAMETER:
+ return VINE_DATA_PATH_ERROR_INVALID_PARAMETER;
+ case BT_ERROR_OPERATION_FAILED:
+ default:
+ return VINE_DATA_PATH_ERROR_OPERATION_FAILED;
+ }
+}
+
+static void __invoke_accepted_cb(const char *remote_address, vine_gatt_s *gatt, void *user_data)
+{
+ if (!g_callbacks.accepted_cb)
+ return;
+
+ vine_gatt_s *accepted_gatt = _create_gatt();
+ RET_IF(accepted_gatt == NULL, "Failed to create accepted_gatt.");
+
+ accepted_gatt->remote_address = STRDUP(remote_address);
+
+ // refer to server's gatt handles.
+ accepted_gatt->service = gatt->service;
+ accepted_gatt->characteristic = gatt->characteristic;
+ accepted_gatt->descriptor = gatt->descriptor;
+
+ accepted_gatt->is_accepted = true;
+ accepted_gatt->user = user_data;
+
+ g_callbacks.accepted_cb(VINE_DP_NOT_IP, accepted_gatt->remote_address, 0, accepted_gatt, user_data);
+}
+
+static void __invoke_connected_cb(int result, void *user_data)
+{
+ if (!g_callbacks.connected_cb)
+ return;
+ g_callbacks.connected_cb(result, user_data);
+}
+
+static void __invoke_terminated_cb(void *user_data)
+{
+ if (!g_callbacks.terminated_cb)
+ return;
+ g_callbacks.terminated_cb(user_data);
+}
+
+// Server Callbacks
+static void __gatt_server_read_value_requested_cb(
+ const char *remote_address, int request_id,
+ bt_gatt_server_h server, bt_gatt_h gatt_handle,
+ int offset, void *user_data)
+{
+ // TODO: Send response.
+}
+
+static void __gatt_server_write_value_requested_cb(const char *remote_address,
+ int request_id, bt_gatt_server_h server,
+ bt_gatt_h gatt_handle, bool response_needed, int offset,
+ const char *value, int len, void *user_data)
+{
+ VINE_LOGI("Got write value requestment from %s.", remote_address);
+
+ // TODO: Send response.
+}
+
+void __gatt_server_noti_state_changed_cb(bool notify, bt_gatt_server_h server,
+ bt_gatt_h gatt_handle, void *user_data)
+{
+ VINE_LOGI("Noti state changed. notify[%d] characteristic[%p]", notify, gatt_handle);
+}
+
+// Client Callbacks
+static void __gatt_client_service_changed_cb(bt_gatt_client_h client,
+ bt_gatt_client_service_change_type_e type, const char *uuid, void *user_data)
+{
+ VINE_LOGI("gatt[%p] service[%s] is %s",
+ type == BT_GATT_CLIENT_SERVICE_ADDED ? "added." : "removed." );
+}
+
+static int __update_gatt_service_info(const char *remote_address, vine_gatt_s *gatt)
+{
+ RET_VAL_IF(gatt == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "gatt is NULL");
+ RET_VAL_IF(remote_address == NULL,
+ VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "remote_address is NULL");
+
+ bt_gatt_client_h client = NULL;
+ bt_gatt_h service = NULL;
+ bt_gatt_h characteristic = NULL;
+ int ret;
+
+ ret = bt_gatt_client_create(remote_address, &client);
+ if (ret != BT_ERROR_NONE || !client)
+ return __convert_bt_error_to_data_path_error(ret);
+
+ ret = bt_gatt_client_set_service_changed_cb(client, __gatt_client_service_changed_cb, gatt);
+ if (ret != BT_ERROR_NONE)
+ goto ERR;
+
+ ret = bt_gatt_client_get_service(client, VINE_GATT_SERVICE_UUID, &service);
+ if (ret != BT_ERROR_NONE)
+ goto ERR;
+
+ ret = bt_gatt_service_get_characteristic(service, VINE_GATT_CHAR_UUID, &characteristic);
+ if (ret != BT_ERROR_NONE)
+ goto ERR;
+
+ gatt->role.client = client;
+ gatt->service = service;
+ gatt->characteristic = characteristic;
+
+ VINE_LOGE("Succeeded to update GATT service info.");
+ return VINE_DATA_PATH_ERROR_NONE;
+
+ERR:
+ VINE_LOGE("Failed to update GATT service info.");
+ bt_gatt_client_destroy(client);
+ return __convert_bt_error_to_data_path_error(ret);
+}
+
+static void __gatt_connection_state_changed_cb(int result, bool connected,
+ const char *remote_address, void *user_data)
+{
+ RET_IF(user_data == NULL, "user_data is NULL");
+
+ vine_gatt_s *gatt = (vine_gatt_s *)user_data;
+
+ VINE_LOGI("gatt[%p] result[%d] connected[%d] remote address[%s]",
+ gatt, result, connected, remote_address);
+
+ if (!connected) {
+ __invoke_terminated_cb(gatt->user);
+ return;
+ }
+
+ if (gatt->type == VINE_GATT_ROLE_SERVER) {
+ __invoke_accepted_cb(remote_address, gatt, gatt->user);
+ } else if (gatt->type == VINE_GATT_ROLE_CLIENT) {
+ if (__update_gatt_service_info(remote_address, gatt) != VINE_DATA_PATH_ERROR_NONE) {
+ bt_gatt_disconnect(remote_address);
+ result = -1;
+ }
+ __invoke_connected_cb(result, gatt->user);
+ }
+}
+
+static vine_gatt_s *_create_gatt(void)
+{
+ vine_gatt_s *gatt = (vine_gatt_s *)calloc(1, sizeof(vine_gatt_s));
+ RET_VAL_IF(gatt == NULL, NULL, "Out of memory");
+
+ if (bt_gatt_set_connection_state_changed_cb(__gatt_connection_state_changed_cb,
+ (void *)gatt) != BT_ERROR_NONE) {
+ VINE_LOGE("Failed to register GATT connection state changed callback");
+ free(gatt);
+ return NULL;
+ }
+ return gatt;
+}
+
+static bt_gatt_h _add_gatt_characteristic(bt_gatt_h service, vine_dp_plugin_h handle)
+{
+ bt_gatt_h characteristic = NULL;
+ char initial_value[1] = {'0'}; // TODO: will be changed.
+ int permissions = BT_GATT_PERMISSION_READ | BT_GATT_PERMISSION_WRITE;
+ int properties = BT_GATT_PROPERTY_BROADCAST | BT_GATT_PROPERTY_READ |
+ BT_GATT_PROPERTY_WRITE | BT_GATT_PROPERTY_NOTIFY;
+
+ if (bt_gatt_characteristic_create(VINE_GATT_CHAR_UUID,
+ permissions, properties,
+ initial_value, sizeof(initial_value), &characteristic) != BT_ERROR_NONE)
+ return NULL;
+
+ if (bt_gatt_server_set_read_value_requested_cb(characteristic,
+ __gatt_server_read_value_requested_cb, handle) != BT_ERROR_NONE)
+ goto ERR;
+
+ if (bt_gatt_server_set_write_value_requested_cb(characteristic,
+ __gatt_server_write_value_requested_cb, handle) != BT_ERROR_NONE)
+ goto ERR;
+
+ if (bt_gatt_server_set_characteristic_notification_state_change_cb(characteristic,
+ __gatt_server_noti_state_changed_cb, handle) != BT_ERROR_NONE)
+ goto ERR;
+
+ if (bt_gatt_service_add_characteristic(service, characteristic) != BT_ERROR_NONE)
+ goto ERR;
+
+ VINE_LOGI("Succeeded to add GATT characteristic.");
+ return characteristic;
+
+ERR:
+ bt_gatt_characteristic_destroy(characteristic);
+ return NULL;
+}
+
+static bt_gatt_h _add_gatt_descriptor(bt_gatt_h characteristic)
+{
+ bt_gatt_h descriptor = NULL;
+ char initial_value[1] = {'0'}; // TODO: will be changed
+ int permissions = BT_GATT_PERMISSION_READ | BT_GATT_PERMISSION_WRITE;
+
+ // TODO: Change UUID
+ if (bt_gatt_descriptor_create("2902", permissions,
+ initial_value, sizeof(initial_value), &descriptor) != BT_ERROR_NONE)
+ return NULL;
+
+ if (bt_gatt_characteristic_add_descriptor(characteristic, descriptor) != BT_ERROR_NONE) {
+ bt_gatt_descriptor_destroy(descriptor);
+ return NULL;
+ }
+ return descriptor;
+}
+
+int gatt_init(void)
+{
+ return VINE_DATA_PATH_ERROR_NONE;
+}
+
+void gatt_deinit(void)
+{
+}
+
+void gatt_register_callbacks(vine_dp_plugin_callbacks callbacks)
+{
+ g_callbacks = callbacks;
+}
+
+void gatt_process_event(int gatt_fd, int events)
+{
+ // Do nothing. use g_main_loop.
+}
+
+int gatt_create(vine_dp_plugin_h *handle, void *plugin_data, void *user)
+{
+ RET_VAL_IF(handle == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "handle is NULL");
+ RET_VAL_IF(user == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "user is NULL");
+
+ vine_gatt_s *gatt = _create_gatt();
+ RET_VAL_IF(gatt == NULL, VINE_DATA_PATH_ERROR_OUT_OF_MEMORY, "Out of memory");
+
+ gatt->user = user;
+ *handle = gatt;
+
+ return VINE_DATA_PATH_ERROR_NONE;
+}
+
+int gatt_destroy(vine_dp_plugin_h handle)
+{
+ RET_VAL_IF(handle == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "handle is NULL");
+
+ vine_gatt_s *gatt = (vine_gatt_s *)handle;
+
+ if (gatt->type == VINE_GATT_ROLE_SERVER) {
+ bt_gatt_server_destroy(gatt->role.server);
+ gatt->role.server = NULL;
+ bt_gatt_service_destroy(gatt->service);
+ bt_gatt_characteristic_destroy(gatt->characteristic);
+ bt_gatt_descriptor_destroy(gatt->descriptor);
+ } else if (gatt->type == VINE_GATT_ROLE_CLIENT) {
+ // bt_gatt_h handles will be freed during bt_gatt_client_destroy().
+ bt_gatt_client_destroy(gatt->role.client);
+ gatt->role.client = NULL;
+ }
+
+ gatt->service = NULL;
+ gatt->characteristic = NULL;
+ gatt->descriptor = NULL;
+ free(gatt->remote_address);
+ gatt->remote_address = NULL;
+ free(gatt);
+
+ return VINE_DATA_PATH_ERROR_NONE;
+}
+
+// All parameters except handle are not used in BT GATT.
+int gatt_open(vine_dp_plugin_h handle, int addr_family,
+ int gatt_port, const char *iface_name, int max_conn, vine_dp_ssl ssl) // server only
+{
+ RET_VAL_IF(handle == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "handle is NULL");
+
+ vine_gatt_s *gatt = (vine_gatt_s *)handle;
+ bt_gatt_server_h server = NULL;
+ bt_gatt_h service = NULL;
+ bt_gatt_h characteristic = NULL;
+ bt_gatt_h descriptor = NULL;
+ int ret = BT_ERROR_OPERATION_FAILED;
+
+ // This returns OPERATION_FAILED when already initialized. ignore it.
+ bt_gatt_server_initialize();
+
+ ret = bt_gatt_server_create(&server);
+ if (ret != BT_ERROR_NONE || !server) {
+ VINE_LOGE("Failed to create GATT server");
+ goto ERR;
+ }
+
+ ret = bt_gatt_service_create(VINE_GATT_SERVICE_UUID, BT_GATT_SERVICE_TYPE_PRIMARY, &service);
+ if (ret != BT_ERROR_NONE) {
+ VINE_LOGE("Failed to create service.");
+ goto ERR;
+ }
+
+ characteristic = _add_gatt_characteristic(service, handle);
+ if (!characteristic) {
+ VINE_LOGE("Failed to add characteristc.");
+ goto ERR;
+ }
+
+ descriptor = _add_gatt_descriptor(characteristic);
+ if (!characteristic) {
+ VINE_LOGE("Failed to add descriptor.");
+ goto ERR;
+ }
+
+ ret = bt_gatt_server_register_service(server, service);
+ if (ret != BT_ERROR_NONE) {
+ VINE_LOGE("Failed to register service.");
+ goto ERR;
+ }
+
+ ret = bt_gatt_server_start();
+ if (ret != BT_ERROR_NONE) {
+ VINE_LOGE("Failed to start GATT server.");
+ goto ERR;
+ }
+
+ gatt->type = VINE_GATT_ROLE_SERVER;
+ gatt->role.server = server;
+ gatt->service = service;
+ gatt->characteristic = characteristic;
+ gatt->descriptor = descriptor;
+
+ VINE_LOGI("Succeeded to start GATT server.");
+ return VINE_DATA_PATH_ERROR_NONE;
+
+ERR:
+ if (server)
+ bt_gatt_server_destroy(server);
+ if (service)
+ bt_gatt_service_destroy(service);
+ if (characteristic)
+ bt_gatt_characteristic_destroy(characteristic);
+ if (descriptor)
+ bt_gatt_descriptor_destroy(descriptor);
+ return ret;
+}
+
+// All parameters except handle and addr are not used in BT GATT.
+int gatt_connect(vine_dp_plugin_h handle, int addr_family,
+ const char *addr, int gatt_port, const char *iface_name, vine_dp_ssl ssl)
+{
+ RET_VAL_IF(handle == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "handle is NULL");
+ RET_VAL_IF(addr == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "addr is NULL");
+
+ vine_gatt_s *gatt = (vine_gatt_s *)handle;
+ bt_gatt_client_h client = NULL;
+ int ret;
+
+ ret = bt_gatt_connect(addr, false);
+ if (ret != BT_ERROR_NONE) {
+ VINE_LOGE("Failed to connect remote LE based service.");
+ return __convert_bt_error_to_data_path_error(ret);
+ }
+
+ gatt->type = VINE_GATT_ROLE_CLIENT;
+ gatt->role.client = client;
+ gatt->remote_address = STRDUP(addr);
+
+ VINE_LOGI("Succeed to request to GATT connect.");
+ return VINE_DATA_PATH_ERROR_NONE;
+}
+
+int gatt_read(vine_dp_plugin_h handle, unsigned char *buf, size_t len)
+{
+ return VINE_DATA_PATH_ERROR_NONE;
+}
+
+int gatt_write(vine_dp_plugin_h handle, unsigned char *buf, size_t len)
+{
+ RET_VAL_IF(handle == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "handle is NULL");
+ RET_VAL_IF(buf == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "buf is NULL");
+ RET_VAL_IF(len <= 0, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "len is less than 0");
+
+ // TODO
+ // vine_gatt_s *gatt = (vine_gatt_s *)handle;
+
+ return VINE_DATA_PATH_ERROR_NONE;
+}
+
+int gatt_close(vine_dp_plugin_h handle)
+{
+ return VINE_DATA_PATH_ERROR_NONE;
+}
+
+int gatt_get_local_address_info(vine_dp_plugin_h handle,
+ int *addr_family, char local_ip[], int *port)
+{
+ return VINE_DATA_PATH_ERROR_NONE;
+}
+
+int gatt_set_token(vine_dp_plugin_h handle, const char *token)
+{
+ return VINE_DATA_PATH_ERROR_NONE;
+}
+
+int gatt_get_token(vine_dp_plugin_h handle, char **token)
+{
+ return VINE_DATA_PATH_ERROR_NONE;
+}
+
+int gatt_set_host_name(vine_dp_plugin_h handle, const char *name)
+{
+ return VINE_DATA_PATH_ERROR_NONE;
+}
+
+void vine_data_path_plugin_init(vine_dp_plugin_fn *fn)
+{
+ fn->init = gatt_init;
+ fn->deinit = gatt_deinit;
+ fn->register_callbacks = gatt_register_callbacks;
+ fn->process_event = gatt_process_event;
+
+ fn->create = gatt_create;
+ fn->destroy = gatt_destroy;
+ fn->open = gatt_open;
+ fn->connect = gatt_connect;
+ fn->read = gatt_read;
+ fn->write = gatt_write;
+ fn->close = gatt_close;
+
+ fn->get_local_address_info = gatt_get_local_address_info;
+
+ fn->set_token = gatt_set_token;
+ fn->get_token = gatt_get_token;
+ fn->set_host_name = gatt_set_host_name;
+}
--- /dev/null
+/*
+ * Copyright (c) 2021 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.
+ *
+*/
+
+#pragma once
+++ /dev/null
-/*
- * Copyright (c) 2021 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 <bluetooth.h>
-
-#include "vine-data-path-plugin.h"
-#include "vine-log.h"
-#include "vine-utils.h"
-
-using namespace std;
-
-// TODO: change UUIDs
-#define VINE_GATT_SERVICE_UUID "000018f2-0000-1000-8000-00805f9b34fb"
-#define VINE_GATT_CHAR_UUID "00002af6-0000-1000-8000-00805f9b34fb"
-#define VINE_GATT_DESC_UUID "fa87c0d0-afac-11de-8a39-0800200c9a66"
-
-typedef enum {
- VINE_GATT_ROLE_UNKNOWN = 0,
- VINE_GATT_ROLE_SERVER,
- VINE_GATT_ROLE_CLIENT,
-} vine_gatt_role_e;
-
-typedef struct {
- bt_gatt_h service;
- bt_gatt_h characteristic;
- bt_gatt_h descriptor;
-
- vine_gatt_role_e type;
- union {
- bt_gatt_server_h server;
- bt_gatt_client_h client;
- } role;
-
- char *remote_address;
- bool is_accepted;
- void *user; // vine_data_path_h
-} vine_gatt_s;
-
-static vine_dp_plugin_callbacks g_callbacks = {
- .pollfd_cb = NULL,
- .opened_cb = NULL,
- .accepted_cb = NULL,
- .connected_cb = NULL,
- .received_cb = NULL,
- .written_cb = NULL,
- .terminated_cb = NULL,
-};
-
-static vine_gatt_s *_create_gatt(void);
-
-static vine_data_path_error __convert_bt_error_to_data_path_error(int error)
-{
- switch (error) {
- case BT_ERROR_NONE:
- return VINE_DATA_PATH_ERROR_NONE;
- case BT_ERROR_OUT_OF_MEMORY:
- return VINE_DATA_PATH_ERROR_OUT_OF_MEMORY;
- case BT_ERROR_INVALID_PARAMETER:
- return VINE_DATA_PATH_ERROR_INVALID_PARAMETER;
- case BT_ERROR_OPERATION_FAILED:
- default:
- return VINE_DATA_PATH_ERROR_OPERATION_FAILED;
- }
-}
-
-static void __invoke_accepted_cb(const char *remote_address, vine_gatt_s *gatt, void *user_data)
-{
- if (!g_callbacks.accepted_cb)
- return;
-
- vine_gatt_s *accepted_gatt = _create_gatt();
- RET_IF(accepted_gatt == NULL, "Failed to create accepted_gatt.");
-
- accepted_gatt->remote_address = STRDUP(remote_address);
-
- // refer to server's gatt handles.
- accepted_gatt->service = gatt->service;
- accepted_gatt->characteristic = gatt->characteristic;
- accepted_gatt->descriptor = gatt->descriptor;
-
- accepted_gatt->is_accepted = true;
- accepted_gatt->user = user_data;
-
- g_callbacks.accepted_cb(VINE_DP_NOT_IP, accepted_gatt->remote_address, 0, accepted_gatt, user_data);
-}
-
-static void __invoke_connected_cb(int result, void *user_data)
-{
- if (!g_callbacks.connected_cb)
- return;
- g_callbacks.connected_cb(result, user_data);
-}
-
-static void __invoke_terminated_cb(void *user_data)
-{
- if (!g_callbacks.terminated_cb)
- return;
- g_callbacks.terminated_cb(user_data);
-}
-
-// Server Callbacks
-static void __gatt_server_read_value_requested_cb(
- const char *remote_address, int request_id,
- bt_gatt_server_h server, bt_gatt_h gatt_handle,
- int offset, void *user_data)
-{
- // TODO: Send response.
-}
-
-static void __gatt_server_write_value_requested_cb(const char *remote_address,
- int request_id, bt_gatt_server_h server,
- bt_gatt_h gatt_handle, bool response_needed, int offset,
- const char *value, int len, void *user_data)
-{
- VINE_LOGI("Got write value requestment from %s.", remote_address);
-
- // TODO: Send response.
-}
-
-void __gatt_server_noti_state_changed_cb(bool notify, bt_gatt_server_h server,
- bt_gatt_h gatt_handle, void *user_data)
-{
- VINE_LOGI("Noti state changed. notify[%d] characteristic[%p]", notify, gatt_handle);
-}
-
-// Client Callbacks
-static void __gatt_client_service_changed_cb(bt_gatt_client_h client,
- bt_gatt_client_service_change_type_e type, const char *uuid, void *user_data)
-{
- VINE_LOGI("gatt[%p] service[%s] is %s",
- type == BT_GATT_CLIENT_SERVICE_ADDED ? "added." : "removed." );
-}
-
-static int __update_gatt_service_info(const char *remote_address, vine_gatt_s *gatt)
-{
- RET_VAL_IF(gatt == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "gatt is NULL");
- RET_VAL_IF(remote_address == NULL,
- VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "remote_address is NULL");
-
- bt_gatt_client_h client = NULL;
- bt_gatt_h service = NULL;
- bt_gatt_h characteristic = NULL;
- int ret;
-
- ret = bt_gatt_client_create(remote_address, &client);
- if (ret != BT_ERROR_NONE || !client)
- return __convert_bt_error_to_data_path_error(ret);
-
- ret = bt_gatt_client_set_service_changed_cb(client, __gatt_client_service_changed_cb, gatt);
- if (ret != BT_ERROR_NONE)
- goto ERR;
-
- ret = bt_gatt_client_get_service(client, VINE_GATT_SERVICE_UUID, &service);
- if (ret != BT_ERROR_NONE)
- goto ERR;
-
- ret = bt_gatt_service_get_characteristic(service, VINE_GATT_CHAR_UUID, &characteristic);
- if (ret != BT_ERROR_NONE)
- goto ERR;
-
- gatt->role.client = client;
- gatt->service = service;
- gatt->characteristic = characteristic;
-
- VINE_LOGE("Succeeded to update GATT service info.");
- return VINE_DATA_PATH_ERROR_NONE;
-
-ERR:
- VINE_LOGE("Failed to update GATT service info.");
- bt_gatt_client_destroy(client);
- return __convert_bt_error_to_data_path_error(ret);
-}
-
-static void __gatt_connection_state_changed_cb(int result, bool connected,
- const char *remote_address, void *user_data)
-{
- RET_IF(user_data == NULL, "user_data is NULL");
-
- vine_gatt_s *gatt = (vine_gatt_s *)user_data;
-
- VINE_LOGI("gatt[%p] result[%d] connected[%d] remote address[%s]",
- gatt, result, connected, remote_address);
-
- if (!connected) {
- __invoke_terminated_cb(gatt->user);
- return;
- }
-
- if (gatt->type == VINE_GATT_ROLE_SERVER) {
- __invoke_accepted_cb(remote_address, gatt, gatt->user);
- } else if (gatt->type == VINE_GATT_ROLE_CLIENT) {
- if (__update_gatt_service_info(remote_address, gatt) != VINE_DATA_PATH_ERROR_NONE) {
- bt_gatt_disconnect(remote_address);
- result = -1;
- }
- __invoke_connected_cb(result, gatt->user);
- }
-}
-
-static vine_gatt_s *_create_gatt(void)
-{
- vine_gatt_s *gatt = (vine_gatt_s *)calloc(1, sizeof(vine_gatt_s));
- RET_VAL_IF(gatt == NULL, NULL, "Out of memory");
-
- if (bt_gatt_set_connection_state_changed_cb(__gatt_connection_state_changed_cb,
- (void *)gatt) != BT_ERROR_NONE) {
- VINE_LOGE("Failed to register GATT connection state changed callback");
- free(gatt);
- return NULL;
- }
- return gatt;
-}
-
-static bt_gatt_h _add_gatt_characteristic(bt_gatt_h service, vine_dp_plugin_h handle)
-{
- bt_gatt_h characteristic = NULL;
- char initial_value[1] = {'0'}; // TODO: will be changed.
- int permissions = BT_GATT_PERMISSION_READ | BT_GATT_PERMISSION_WRITE;
- int properties = BT_GATT_PROPERTY_BROADCAST | BT_GATT_PROPERTY_READ |
- BT_GATT_PROPERTY_WRITE | BT_GATT_PROPERTY_NOTIFY;
-
- if (bt_gatt_characteristic_create(VINE_GATT_CHAR_UUID,
- permissions, properties,
- initial_value, sizeof(initial_value), &characteristic) != BT_ERROR_NONE)
- return NULL;
-
- if (bt_gatt_server_set_read_value_requested_cb(characteristic,
- __gatt_server_read_value_requested_cb, handle) != BT_ERROR_NONE)
- goto ERR;
-
- if (bt_gatt_server_set_write_value_requested_cb(characteristic,
- __gatt_server_write_value_requested_cb, handle) != BT_ERROR_NONE)
- goto ERR;
-
- if (bt_gatt_server_set_characteristic_notification_state_change_cb(characteristic,
- __gatt_server_noti_state_changed_cb, handle) != BT_ERROR_NONE)
- goto ERR;
-
- if (bt_gatt_service_add_characteristic(service, characteristic) != BT_ERROR_NONE)
- goto ERR;
-
- VINE_LOGI("Succeeded to add GATT characteristic.");
- return characteristic;
-
-ERR:
- bt_gatt_characteristic_destroy(characteristic);
- return NULL;
-}
-
-static bt_gatt_h _add_gatt_descriptor(bt_gatt_h characteristic)
-{
- bt_gatt_h descriptor = NULL;
- char initial_value[1] = {'0'}; // TODO: will be changed
- int permissions = BT_GATT_PERMISSION_READ | BT_GATT_PERMISSION_WRITE;
-
- // TODO: Change UUID
- if (bt_gatt_descriptor_create("2902", permissions,
- initial_value, sizeof(initial_value), &descriptor) != BT_ERROR_NONE)
- return NULL;
-
- if (bt_gatt_characteristic_add_descriptor(characteristic, descriptor) != BT_ERROR_NONE) {
- bt_gatt_descriptor_destroy(descriptor);
- return NULL;
- }
- return descriptor;
-}
-
-int gatt_init(void)
-{
- return VINE_DATA_PATH_ERROR_NONE;
-}
-
-void gatt_deinit(void)
-{
-}
-
-void gatt_register_callbacks(vine_dp_plugin_callbacks callbacks)
-{
- g_callbacks = callbacks;
-}
-
-void gatt_process_event(int gatt_fd, int events)
-{
- // Do nothing. use g_main_loop.
-}
-
-int gatt_create(vine_dp_plugin_h *handle, void *plugin_data, void *user)
-{
- RET_VAL_IF(handle == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "handle is NULL");
- RET_VAL_IF(user == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "user is NULL");
-
- vine_gatt_s *gatt = _create_gatt();
- RET_VAL_IF(gatt == NULL, VINE_DATA_PATH_ERROR_OUT_OF_MEMORY, "Out of memory");
-
- gatt->user = user;
- *handle = gatt;
-
- return VINE_DATA_PATH_ERROR_NONE;
-}
-
-int gatt_destroy(vine_dp_plugin_h handle)
-{
- RET_VAL_IF(handle == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "handle is NULL");
-
- vine_gatt_s *gatt = (vine_gatt_s *)handle;
-
- if (gatt->type == VINE_GATT_ROLE_SERVER) {
- bt_gatt_server_destroy(gatt->role.server);
- gatt->role.server = NULL;
- bt_gatt_service_destroy(gatt->service);
- bt_gatt_characteristic_destroy(gatt->characteristic);
- bt_gatt_descriptor_destroy(gatt->descriptor);
- } else if (gatt->type == VINE_GATT_ROLE_CLIENT) {
- // bt_gatt_h handles will be freed during bt_gatt_client_destroy().
- bt_gatt_client_destroy(gatt->role.client);
- gatt->role.client = NULL;
- }
-
- gatt->service = NULL;
- gatt->characteristic = NULL;
- gatt->descriptor = NULL;
- free(gatt->remote_address);
- gatt->remote_address = NULL;
- free(gatt);
-
- return VINE_DATA_PATH_ERROR_NONE;
-}
-
-// All parameters except handle are not used in BT GATT.
-int gatt_open(vine_dp_plugin_h handle, int addr_family,
- int gatt_port, const char *iface_name, int max_conn, vine_dp_ssl ssl) // server only
-{
- RET_VAL_IF(handle == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "handle is NULL");
-
- vine_gatt_s *gatt = (vine_gatt_s *)handle;
- bt_gatt_server_h server = NULL;
- bt_gatt_h service = NULL;
- bt_gatt_h characteristic = NULL;
- bt_gatt_h descriptor = NULL;
- int ret = BT_ERROR_OPERATION_FAILED;
-
- // This returns OPERATION_FAILED when already initialized. ignore it.
- bt_gatt_server_initialize();
-
- ret = bt_gatt_server_create(&server);
- if (ret != BT_ERROR_NONE || !server) {
- VINE_LOGE("Failed to create GATT server");
- goto ERR;
- }
-
- ret = bt_gatt_service_create(VINE_GATT_SERVICE_UUID, BT_GATT_SERVICE_TYPE_PRIMARY, &service);
- if (ret != BT_ERROR_NONE) {
- VINE_LOGE("Failed to create service.");
- goto ERR;
- }
-
- characteristic = _add_gatt_characteristic(service, handle);
- if (!characteristic) {
- VINE_LOGE("Failed to add characteristc.");
- goto ERR;
- }
-
- descriptor = _add_gatt_descriptor(characteristic);
- if (!characteristic) {
- VINE_LOGE("Failed to add descriptor.");
- goto ERR;
- }
-
- ret = bt_gatt_server_register_service(server, service);
- if (ret != BT_ERROR_NONE) {
- VINE_LOGE("Failed to register service.");
- goto ERR;
- }
-
- ret = bt_gatt_server_start();
- if (ret != BT_ERROR_NONE) {
- VINE_LOGE("Failed to start GATT server.");
- goto ERR;
- }
-
- gatt->type = VINE_GATT_ROLE_SERVER;
- gatt->role.server = server;
- gatt->service = service;
- gatt->characteristic = characteristic;
- gatt->descriptor = descriptor;
-
- VINE_LOGI("Succeeded to start GATT server.");
- return VINE_DATA_PATH_ERROR_NONE;
-
-ERR:
- if (server)
- bt_gatt_server_destroy(server);
- if (service)
- bt_gatt_service_destroy(service);
- if (characteristic)
- bt_gatt_characteristic_destroy(characteristic);
- if (descriptor)
- bt_gatt_descriptor_destroy(descriptor);
- return ret;
-}
-
-// All parameters except handle and addr are not used in BT GATT.
-int gatt_connect(vine_dp_plugin_h handle, int addr_family,
- const char *addr, int gatt_port, const char *iface_name, vine_dp_ssl ssl)
-{
- RET_VAL_IF(handle == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "handle is NULL");
- RET_VAL_IF(addr == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "addr is NULL");
-
- vine_gatt_s *gatt = (vine_gatt_s *)handle;
- bt_gatt_client_h client = NULL;
- int ret;
-
- ret = bt_gatt_connect(addr, false);
- if (ret != BT_ERROR_NONE) {
- VINE_LOGE("Failed to connect remote LE based service.");
- return __convert_bt_error_to_data_path_error(ret);
- }
-
- gatt->type = VINE_GATT_ROLE_CLIENT;
- gatt->role.client = client;
- gatt->remote_address = STRDUP(addr);
-
- VINE_LOGI("Succeed to request to GATT connect.");
- return VINE_DATA_PATH_ERROR_NONE;
-}
-
-int gatt_read(vine_dp_plugin_h handle, unsigned char *buf, size_t len)
-{
- return VINE_DATA_PATH_ERROR_NONE;
-}
-
-int gatt_write(vine_dp_plugin_h handle, unsigned char *buf, size_t len)
-{
- RET_VAL_IF(handle == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "handle is NULL");
- RET_VAL_IF(buf == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "buf is NULL");
- RET_VAL_IF(len <= 0, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "len is less than 0");
-
- // TODO
- // vine_gatt_s *gatt = (vine_gatt_s *)handle;
-
- return VINE_DATA_PATH_ERROR_NONE;
-}
-
-int gatt_close(vine_dp_plugin_h handle)
-{
- return VINE_DATA_PATH_ERROR_NONE;
-}
-
-int gatt_get_local_address_info(vine_dp_plugin_h handle,
- int *addr_family, char local_ip[], int *port)
-{
- return VINE_DATA_PATH_ERROR_NONE;
-}
-
-int gatt_set_token(vine_dp_plugin_h handle, const char *token)
-{
- return VINE_DATA_PATH_ERROR_NONE;
-}
-
-int gatt_get_token(vine_dp_plugin_h handle, char **token)
-{
- return VINE_DATA_PATH_ERROR_NONE;
-}
-
-int gatt_set_host_name(vine_dp_plugin_h handle, const char *name)
-{
- return VINE_DATA_PATH_ERROR_NONE;
-}
-
-void vine_data_path_plugin_init(vine_dp_plugin_fn *fn)
-{
- fn->init = gatt_init;
- fn->deinit = gatt_deinit;
- fn->register_callbacks = gatt_register_callbacks;
- fn->process_event = gatt_process_event;
-
- fn->create = gatt_create;
- fn->destroy = gatt_destroy;
- fn->open = gatt_open;
- fn->connect = gatt_connect;
- fn->read = gatt_read;
- fn->write = gatt_write;
- fn->close = gatt_close;
-
- fn->get_local_address_info = gatt_get_local_address_info;
-
- fn->set_token = gatt_set_token;
- fn->get_token = gatt_get_token;
- fn->set_host_name = gatt_set_host_name;
-}