First draft for BLE GATT plugin 42/260742/8
authorSeonah Moon <seonah1.moon@samsung.com>
Fri, 2 Jul 2021 05:24:45 +0000 (14:24 +0900)
committerSeonah Moon <seonah1.moon@samsung.com>
Wed, 7 Jul 2021 02:41:35 +0000 (11:41 +0900)
Change-Id: I70065ea272a3fe63ca156188656112fce04333cc

plugins/ble/gatt-plugin.cpp [new file with mode: 0755]
src/include/vine-data-path-plugin.h

diff --git a/plugins/ble/gatt-plugin.cpp b/plugins/ble/gatt-plugin.cpp
new file mode 100755 (executable)
index 0000000..19898d0
--- /dev/null
@@ -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 <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;
+}
index 214d0d8..4a451d0 100755 (executable)
@@ -48,6 +48,7 @@ typedef enum {
        VINE_DP_IPV4_IPV6 = 0, // IPv6 has higer priority.
        VINE_DP_IPV4,
        VINE_DP_IPV6,
+       VINE_DP_NOT_IP
 } vine_dp_addr_family_e;
 
 typedef enum {