From: Seonah Moon Date: Mon, 5 Jul 2021 02:21:58 +0000 (+0900) Subject: Seperate GATT from BLE plugin X-Git-Tag: submit/tizen/20210714.100702~7 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=99174aea0dace47bcf4f4be517711c3976bfc5fc;p=platform%2Fcore%2Fapi%2Fvine.git Seperate GATT from BLE plugin Change-Id: I341ad739a779a0d4659da478e6acf00d8c4a8d2c --- diff --git a/CMakeLists.txt b/CMakeLists.txt index eae5055..a6834a7 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,6 +127,7 @@ ENDIF(USE_LIBWEBSOCKETS) ADD_SUBDIRECTORY(plugins/dns-sd) IF(BT_SUPPORT) ADD_SUBDIRECTORY(plugins/ble) + ADD_SUBDIRECTORY(plugins/ble-gatt) ENDIF(BT_SUPPORT) ADD_SUBDIRECTORY(include) diff --git a/plugins/ble-gatt/CMakeLists.txt b/plugins/ble-gatt/CMakeLists.txt new file mode 100755 index 0000000..977029e --- /dev/null +++ b/plugins/ble-gatt/CMakeLists.txt @@ -0,0 +1,51 @@ +# 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}") diff --git a/plugins/ble-gatt/ble-gatt-plugin.cpp b/plugins/ble-gatt/ble-gatt-plugin.cpp new file mode 100755 index 0000000..19898d0 --- /dev/null +++ b/plugins/ble-gatt/ble-gatt-plugin.cpp @@ -0,0 +1,504 @@ +/* + * 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 + +#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; +} diff --git a/plugins/ble-gatt/ble-gatt-plugin.h b/plugins/ble-gatt/ble-gatt-plugin.h new file mode 100755 index 0000000..d1766f0 --- /dev/null +++ b/plugins/ble-gatt/ble-gatt-plugin.h @@ -0,0 +1,18 @@ +/* + * 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 diff --git a/plugins/ble/gatt-plugin.cpp b/plugins/ble/gatt-plugin.cpp deleted file mode 100755 index 19898d0..0000000 --- a/plugins/ble/gatt-plugin.cpp +++ /dev/null @@ -1,504 +0,0 @@ -/* - * 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 - -#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; -}