vine-ble-test: Add test for BLE 45/261445/3
authorCheoleun Moon <chleun.moon@samsung.com>
Mon, 19 Jul 2021 05:48:20 +0000 (14:48 +0900)
committerCheoleun Moon <chleun.moon@samsung.com>
Mon, 19 Jul 2021 07:14:54 +0000 (16:14 +0900)
Change-Id: Ia270a49e509d9e2b3b6b415e176d09894fb1f28a
Signed-off-by: Cheoleun Moon <chleun.moon@samsung.com>
tests/vine-test/vine-ble-test.cpp [new file with mode: 0755]

diff --git a/tests/vine-test/vine-ble-test.cpp b/tests/vine-test/vine-ble-test.cpp
new file mode 100755 (executable)
index 0000000..711bcac
--- /dev/null
@@ -0,0 +1,577 @@
+/*
+ * 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 <glib.h>
+#include <list>
+#include <iterator>
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <time.h>
+#include <vine.h>
+#include <vine-log.h>
+
+#include "vine-test-utils.h"
+
+#define MAX_EVENTS 16
+#define TEST_DEBUG
+
+#define CHECK_SESSION \
+       do { \
+               if (!g_session) { \
+                       _test_print_error("No Session"); \
+                       return; \
+               } \
+       } while (0)
+
+#define MAX_SERVICE_TYPE_LEN 15
+#define MAX_SERVICE_NAME_LEN 15
+#define VINE_MAC_LEN 17
+
+GMainLoop *main_loop = NULL;
+static vine_session_h g_session = NULL;
+static vine_service_h g_service = NULL;
+static vine_dp_h g_server_dp = NULL;
+static vine_dp_h g_client_dp = NULL;
+
+static std::list<vine_dp_h> g_datapath_list;
+static std::list<vine_service_h> g_service_list;
+
+static bool test_get_user_string(const char *msg, char *buf, int buf_size)
+{
+       if (msg == NULL || buf == NULL || buf_size < 2)
+               return false;
+
+       int ret;
+       printf("%s", msg);
+       fflush(stdout);
+       memset(buf, 0, buf_size);
+       ret = read(0, buf, buf_size - 1);
+
+       if (ret < 0 || buf[0] == '\0' || buf[0] == '\n' || buf[0] == '\r') {
+               buf[0] = '\0';
+               return false;
+       }
+
+       buf[ret - 1] = '\0';
+       return true;
+}
+
+static void __quit()
+{
+       PRINT_IF_ERROR(vine_deinitialize(), "vine_initialize()");
+       g_main_loop_quit(main_loop);
+       exit(1);
+}
+
+static void __init()
+{
+       PRINT_IF_ERROR(vine_set_event_loop(VINE_EVENT_LOOP_EXTERNAL_GLIB), "vine_set_event_loop");
+       PRINT_IF_ERROR(vine_initialize(), "vine_initialize()");
+}
+
+static void __registered_cb(vine_session_h session,
+               const char *service_name, vine_error_e error, void *user_data)
+{
+       if (error == VINE_ERROR_NONE) {
+               PRINT_RESULT(error, "Successfully registered");
+               printf("Service Name: %s\n", service_name);
+       } else if (error == VINE_ERROR_NAME_CONFLICT) {
+               PRINT_RESULT(error, "Successfully registered, but service name conflicted");
+               printf("Service Name: %s\n", service_name);
+       } else {
+               PRINT_IF_ERROR(error, "Failed to register a service");
+       }
+}
+
+static void __discovered_cb(vine_session_h session, vine_service_h service,
+               vine_service_state_e state, void *user_data)
+{
+       printf("\t++ Service Discovered\n");
+
+       int ret;
+       char *service_type;
+       char *service_name;
+       char *mac;
+
+       ret = vine_service_get_type(service, &service_type);
+       PRINT_IF_ERROR(ret, "vine_service_get_type");
+       ret = vine_service_get_name(service, &service_name);
+       PRINT_IF_ERROR(ret, "vine_service_get_name");
+       ret = vine_service_get_mac(service, &mac);
+       PRINT_IF_ERROR(ret, "vine_service_get_mac");
+
+       printf("\t   > State: %s\n",
+                       state == VINE_SERVICE_UNAVAILABLE ? "Unavailable" : "Available");
+       printf("\t   > Service Type: %s\n", service_type);
+       printf("\t   > Service Name: %s\n", service_name);
+       printf("\t   > Mac: %s\n", mac);
+       printf("\n");
+       fflush(stdout);
+
+       vine_service_h s;
+       vine_service_clone(service, &s);
+       g_service_list.push_back(s);
+       free(service_type);
+       free(service_name);
+       free(mac);
+}
+
+static void __print_received_data(unsigned char *buf, size_t len)
+{
+       for (int i = 0; i < (int)len; i++)
+               printf("%c", buf[i]);
+       printf("\n");
+}
+
+static void __received_cb(vine_dp_h dp, size_t received_len, void *user_data)
+{
+       unsigned char buf[20] = {0, };
+       size_t bytes = 0;
+
+       printf(COLOR_GRN "[RECV_CB] %p received %zd bytes." COLOR_RESET "\n", dp, received_len);
+       do {
+               vine_dp_recv(dp, buf, 20, &bytes);
+               __print_received_data(buf, bytes);
+               received_len -= bytes;
+       } while (received_len > 0);
+}
+
+static void __terminated_cb(vine_dp_h dp, void *user_data)
+{
+       printf(COLOR_GRN "[TERMINATED_CB] %p is terminated." COLOR_RESET "\n", dp);
+       g_datapath_list.remove(dp);
+       vine_dp_destroy(dp);
+}
+
+static void __add_new_dp(vine_dp_h dp)
+{
+       g_datapath_list.push_back(dp);
+       vine_dp_set_received_cb(dp, __received_cb, NULL);
+       vine_dp_set_terminated_cb(dp, __terminated_cb, NULL);
+}
+
+static void __opened_cb(vine_dp_h dp, vine_error_e result, void *user_data)
+{
+       printf(COLOR_GRN "[OPENED_CB] %p is %s." COLOR_RESET "\n",
+                       dp, (result == VINE_ERROR_NONE) ? "opened" : "not opened");
+       if (dp == g_client_dp)
+               __add_new_dp(dp);
+}
+
+static void __set_callbacks()
+{
+       CHECK_SESSION;
+       PRINT_IF_ERROR(vine_session_set_registered_cb(g_session, __registered_cb, NULL),
+                       "vine_session_set_registered_cb");
+       PRINT_IF_ERROR(vine_session_set_discovered_cb(g_session, __discovered_cb, NULL),
+                       "vine_session_set_discovered_cb");
+}
+
+static void __create_session()
+{
+       int ret;
+       ret = vine_session_create(&g_session);
+       if (ret != VINE_ERROR_NONE) {
+               PRINT_IF_ERROR(ret,  "vine_session_create");
+               return;
+       }
+
+       ret = vine_session_set_discovery_method(g_session, VINE_DISCOVERY_METHOD_BLE);
+       if (ret != VINE_ERROR_NONE) {
+               PRINT_IF_ERROR(ret,  "vine_session_create");
+               vine_session_destroy(g_session);
+               return;
+       }
+
+       __set_callbacks();
+       printf("Session Created\n");
+}
+
+static void __destroy_session()
+{
+       CHECK_SESSION;
+       PRINT_IF_ERROR(vine_session_destroy(g_session),
+                       "vine_session_destroy");
+}
+
+static void __set_service_type()
+{
+       CHECK_SESSION;
+       char type[MAX_SERVICE_TYPE_LEN + 1];
+       printf(" >> Service Type: ");
+       if (scanf(" %15s", type) < 1) {
+               _test_print_error("Scan failed");
+               return;
+       }
+       PRINT_RESULT(vine_service_set_type(g_service, type),
+                       "vine_service_set_type");
+}
+
+static void __set_service_name()
+{
+       CHECK_SESSION;
+       char name[MAX_SERVICE_NAME_LEN + 1];
+       printf(" >> Service Name (Max length 15): ");
+       if (scanf(" %15s", name) < 1) {
+               _test_print_error("Scan failed");
+               return;
+       }
+       PRINT_RESULT(vine_service_set_name(g_service, name),
+                       "vine_service_set_name");
+}
+
+static void __create_service()
+{
+       int ret;
+       ret = vine_service_create(&g_service);
+       if (ret != VINE_ERROR_NONE) {
+               PRINT_IF_ERROR(ret,  "vine_service_create");
+               return;
+       }
+
+       __set_service_type();
+       __set_service_name();
+
+       printf("Service Created\n");
+}
+
+static void __destroy_service()
+{
+       CHECK_SESSION;
+       PRINT_IF_ERROR(vine_service_destroy(g_service), "vine_service_destroy");
+}
+
+static void __register()
+{
+       CHECK_SESSION;
+       PRINT_IF_ERROR(vine_session_register(g_session, g_service, NULL), "vine_session_register");
+       printf("Registered\n");
+}
+
+static void __unregister()
+{
+       CHECK_SESSION;
+       PRINT_IF_ERROR(vine_session_unregister(g_session), "vine_session_unregister");
+       printf("Unregistered\n");
+}
+
+static void __start_discovery()
+{
+       CHECK_SESSION;
+       char type[20];
+       printf(" >> Service Type: ");
+       if (scanf(" %19s", type) < 1) {
+               _test_print_error("Scan failed");
+               return;
+       }
+
+       PRINT_IF_ERROR(vine_session_start_discovery(g_session, type, NULL),
+               "vine_session_start_discovery");
+       printf("Discovery started\n");
+}
+
+static void __stop_discovery()
+{
+       CHECK_SESSION;
+       PRINT_IF_ERROR(vine_session_stop_discovery(g_session), "vine_session_stop_discovery");
+       printf("Discovery stopped\n");
+}
+
+#ifdef TEST_DEBUG
+#define VINE_LOGGER_TIME_MESSAGE_LEN 17
+static void __get_current_time(char *buf)
+{
+       int hour, min, sec, day, month;
+       time_t now;
+       struct tm *local;
+
+       time(&now);
+       local = localtime(&now);
+
+       hour = local->tm_hour;
+       min = local->tm_min;
+       sec = local->tm_sec;
+       day = local->tm_mday;
+       month = local->tm_mon + 1;
+
+       snprintf(buf, VINE_LOGGER_TIME_MESSAGE_LEN,
+                       "[%02u-%02u %02u:%02u:%02u]", month, day, hour, min, sec);
+}
+
+void __logger(int log_level, const char *log)
+{
+       char timestamp[VINE_LOGGER_TIME_MESSAGE_LEN];
+       __get_current_time(timestamp);
+       printf("%s[T%5u] ", timestamp, (unsigned int)syscall(__NR_gettid));
+
+       switch (log_level) {
+       case VINE_LOG_DEBUG:
+               printf("D/");
+               break;
+       case VINE_LOG_INFO:
+               printf("I/");
+               break;
+       case VINE_LOG_ERROR:
+               printf(COLOR_RED "E/");
+               break;
+       }
+       printf("%s" COLOR_RESET "\n", log);
+}
+#endif
+
+static void __debug_on_off()
+{
+       static int __debug_on = 0;
+       __debug_on = 1 - __debug_on;
+       printf("Debug %s\n", __debug_on ? "ON" : "OFF");
+#ifdef TEST_DEBUG
+       if (__debug_on) {
+               vine_set_logger(__logger);
+               vine_set_log_level(VINE_LOG_DEBUG | VINE_LOG_INFO | VINE_LOG_ERROR);
+       } else {
+               vine_set_logger(NULL);
+       }
+#endif
+}
+
+static void __accepted_cb(vine_dp_h dp, vine_dp_h accepted_dp, void *user_data)
+{
+       printf(COLOR_GRN "[ACCEPTED_CB] %p is accepted." COLOR_RESET "\n", accepted_dp);
+       __add_new_dp(accepted_dp);
+}
+
+static void __open_server()
+{
+       CHECK_SESSION;
+
+       vine_dp_create(g_session, VINE_DP_TYPE_SERVER, &g_server_dp);
+       vine_dp_set_method(g_server_dp, VINE_DP_METHOD_BLE_GATT);
+       vine_dp_set_accepted_cb(g_server_dp, __accepted_cb, NULL);
+       vine_dp_set_terminated_cb(g_server_dp, __terminated_cb, NULL);
+
+       PRINT_RESULT(vine_dp_open(g_server_dp, __opened_cb, NULL), "vine_dp_open");
+}
+
+static void __connect_server()
+{
+       CHECK_SESSION;
+
+       char mac[VINE_MAC_LEN + 1] = {0, };
+
+       printf(" >> Mac address: ");
+       if (scanf(" %17s", mac) < 1) {
+               _test_print_error("Scan failed");
+               return;
+       }
+
+       vine_dp_create(g_session, VINE_DP_TYPE_CLIENT, &g_client_dp);
+       vine_dp_set_method(g_client_dp, VINE_DP_METHOD_BLE_GATT);
+       vine_dp_set_remote_address(g_client_dp, mac);
+
+       PRINT_RESULT(vine_dp_open(g_client_dp, __opened_cb, NULL), "vine_dp_open");
+}
+
+void __print_datapath_list()
+{
+       int idx = -1;
+       for (const auto &dp : g_datapath_list)
+               printf("\t %d: datapath[%p]\n", ++idx, dp);
+}
+
+static void __send_data()
+{
+       CHECK_SESSION;
+
+       const char *test_str[3] = {
+               "12345678910",
+               "Hello! This is a test string.",
+               "Tizen is an open and flexible operating system" \
+               "built from the ground up to address the needs of all stakeholders of the mobile"\
+               "and connected device ecosystem, including device manufacturers, mobile operators,"\
+               "application developers and independent software vendors (ISVs)."\
+               "Tizen is developed by a community of developers, under open source governance,"\
+               "and is open to all members who wish to participate."
+       };
+
+       __print_datapath_list();
+
+       int idx;
+       printf(" >> Select peer: \n");
+       if (scanf("%d", &idx) < 0)
+               return;
+
+       auto it = g_datapath_list.begin();
+       std::advance(it, idx);
+       vine_dp_h dp = *it;
+
+       for (int i = 0; i < 3; i++) {
+               int ret = vine_dp_send(dp,
+                       (unsigned char *)test_str[i], strlen(test_str[i]));
+               PRINT_IF_ERROR(ret, "vine_data_path_write");
+       }
+}
+
+static void __close_data_path()
+{
+       __print_datapath_list();
+
+       int idx;
+       printf(" >> Select peer: \n");
+       if (scanf("%d", &idx) < 0)
+               return;
+
+       auto it = g_datapath_list.begin();
+       std::advance(it, idx);
+       vine_dp_h dp = *it;
+
+       PRINT_RESULT(vine_dp_close(dp), "vine_dp_close");
+       g_datapath_list.remove(dp);
+       PRINT_RESULT(vine_dp_destroy(dp), "vine_dp_destroy");
+}
+
+enum {
+       CMD_QUIT = 0,
+       CMD_CREATE_SESSION,
+       CMD_DESTROY_SESSION,
+       CMD_CREATE_SERVICE,
+       CMD_DESTROY_SERVICE,
+       CMD_REGISTER,
+       CMD_UNREGISTER,
+       CMD_START_DISCOVERY,
+       CMD_STOP_DISCOVERY,
+       CMD_OPEN_SERVER,
+       CMD_CONNECT_SERVER,
+       CMD_SEND_DATA,
+       CMD_CLOSE_DATA_PATH,
+       CMD_DEBUG,
+       CMD_INVALID,
+};
+
+static struct {
+       const char *str;
+       void (*func)(void);
+} __menus[] = {
+       [CMD_QUIT] = {"quit", __quit},
+       [CMD_CREATE_SESSION] = {"Create session", __create_session},
+       [CMD_DESTROY_SESSION] = {"Destroy session", __destroy_session},
+       [CMD_CREATE_SERVICE] = {"Create service", __create_service},
+       [CMD_DESTROY_SERVICE] = {"Destroy service", __destroy_service},
+       [CMD_REGISTER] = {"Register a service", __register},
+       [CMD_UNREGISTER] = {"Unregister a service", __unregister},
+       [CMD_START_DISCOVERY] = {"Start discovery", __start_discovery},
+       [CMD_STOP_DISCOVERY] = {"Stop discovery", __stop_discovery},
+       [CMD_OPEN_SERVER] = {"Open server", __open_server},
+       [CMD_CONNECT_SERVER] = {"Connect to server", __connect_server},
+       [CMD_SEND_DATA] = {"Send data to peer", __send_data},
+       [CMD_CLOSE_DATA_PATH] = {"Close datapath", __close_data_path},
+       [CMD_DEBUG] = {"Debug on/off", __debug_on_off},
+  {NULL, NULL},
+};
+
+static void __show_menus()
+{
+       printf("\n-- Vine Test\n");
+       for (int i = 0; __menus[i].str; ++i)
+               printf("%02d %s\n", i, __menus[i].str);
+       printf("> ");
+       fflush(stdout);
+}
+
+static inline int __is_digit(const char* str)
+{
+       int len;
+       int i;
+
+       if (str == NULL)
+               return -1;
+
+       if (strlen(str) == 0)
+               return -1;
+
+       len = strlen(str);
+       for (i = 0; i < len; i++)       {
+               if (str[i] < '0' || str[i] > '9')
+                       return -2;
+       }
+
+       return 0;
+}
+
+static void __process_input(const char *input)
+{
+       int cmd = -1;
+
+       cmd = strtol(input, NULL, 0);
+       if (__is_digit(input) < 0 || strlen(input) == 0 || errno == ERANGE || errno
+                       == EINVAL)
+               cmd = CMD_INVALID;
+
+       if (cmd >= CMD_INVALID || cmd < CMD_QUIT) {
+               printf("Invalid CMD\n");
+               return;
+       }
+       __menus[cmd].func();
+}
+
+static void __terminal_read_std_input()
+{
+       int fd = 0;
+
+       static char buf[1024];
+       int n;
+
+       errno = 0;
+       n = read(fd, buf, 1024);
+       if (n == 0) {
+               printf("Error: read() from stdin returns 0.\n");
+       } else if (n < 0) {
+               printf("input: read, err\n");
+       } else if (n - 1 > 0 && n < 1024) {
+               buf[n - 1] = '\0'; /* remove new line... */
+               printf("\n\n");
+               __process_input(buf);
+       } else {
+               if (buf[0] == '\n' || buf[0] == '\r')
+                       __show_menus();
+               else
+               printf("invalid input\n");
+       }
+}
+
+static gboolean __io_handler(GIOChannel *source, GIOCondition condition, gpointer data)
+{
+       __terminal_read_std_input();
+       return TRUE;
+}
+
+int main()
+{
+       __init();
+       __show_menus();
+
+       main_loop = g_main_loop_new(NULL, FALSE);
+
+       GIOChannel *channel = g_io_channel_unix_new(0);
+       g_io_add_watch(channel, (GIOCondition)(G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL),
+                       __io_handler, NULL);
+       g_main_loop_run(main_loop);
+       g_main_loop_unref(main_loop);
+
+       return 0;
+}