--- /dev/null
+/*
+ * Copyright (c) 2019 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 <bluetooth_internal.h>
+#include <dlog.h>
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "HID_KEYBOARD"
+
+/**
+ * Variables
+ **/
+static GMainLoop *g_mainloop = NULL;
+static bt_adapter_state_e bt_state = BT_ADAPTER_DISABLED;
+static char remote_addr[18] = "F6:FB:8F:D8:C8:7C";
+static bool address_input = false;
+static bool scanning = false;
+static bool setup_in_progress = false;
+static GSList *le_scan_list;
+static bool g_wait_flag;
+static int g_wait_count;
+
+static bool device_bonded = false;
+static bool hid_connected = false;
+static bool audio_connected = false;
+
+#define PRT(format, args...) printf("%s:%d() "format, __FUNCTION__, __LINE__, ##args)
+#define HID_PRT(format, args...) PRT(format"\n", ##args)
+
+#define WAIT_FOR_SYNC {\
+ g_wait_flag = true;\
+ g_wait_count = 0;\
+ while (g_wait_flag == true && g_wait_count < 50) {\
+ usleep(1000);\
+ HID_PRT("Initial Setup...");\
+ g_main_context_iteration(NULL, true);\
+ g_wait_count++;\
+ }\
+}
+
+typedef struct {
+ const char *tc_name;
+ int tc_code;
+} tc_table_t;
+
+typedef enum {
+ BT_HID_DEVICE_SET_ADDRESS = 1,
+ BT_HID_DEVICE_TEST_SETUP,
+ BT_HID_DEVICE_TEST_VOLUME_UP,
+ BT_HID_DEVICE_TEST_VOLUME_DOWN,
+ BT_HID_DEVICE_TEST_CHANNEL_UP,
+ BT_HID_DEVICE_TEST_CHANNEL_DOWN,
+ BT_HID_DEVICE_TEST_CONNECT_HID,
+ BT_HID_DEVICE_TEST_DISCONNECT_HID,
+ BT_HID_DEVICE_TEST_CONNECT_AUDIO,
+ BT_HID_DEVICE_TEST_DISCONNECT_AUDIO,
+ BT_HID_DEVICE_TEST_SEARCH,
+ BT_HID_DEVICE_TEST_STOP_SEARCH,
+ BT_HID_DEVICE_TEST_FINISH = 0xFF,
+} bt_hid_test_type_e;
+
+tc_table_t tc_hid_device[] = {
+ {"SET ADDRESS"
+ , BT_HID_DEVICE_SET_ADDRESS},
+ {"Initial Setup (Bond & Connects)"
+ , BT_HID_DEVICE_TEST_SETUP},
+ {"Volume Up"
+ , BT_HID_DEVICE_TEST_VOLUME_UP},
+ {"Volume Down"
+ , BT_HID_DEVICE_TEST_VOLUME_DOWN},
+ {"Channel Up"
+ , BT_HID_DEVICE_TEST_CHANNEL_UP},
+ {"Channel Down"
+ , BT_HID_DEVICE_TEST_CHANNEL_DOWN},
+ {"AUDIO Connect only"
+ , BT_HID_DEVICE_TEST_CONNECT_AUDIO},
+ {"AUDIO Disconnect only"
+ , BT_HID_DEVICE_TEST_DISCONNECT_AUDIO},
+ {"HID Connect only"
+ , BT_HID_DEVICE_TEST_CONNECT_HID},
+ {"HID Disconnect only"
+ , BT_HID_DEVICE_TEST_DISCONNECT_HID},
+ {"Search TV"
+ , BT_HID_DEVICE_TEST_SEARCH},
+ {"Stop to search"
+ , BT_HID_DEVICE_TEST_STOP_SEARCH},
+ {"Finish"
+ , BT_HID_DEVICE_TEST_FINISH},
+ {NULL, 0x0000},
+};
+
+static const char *__bt_get_error_message(bt_error_e err)
+{
+ const char *err_str = NULL;
+
+ switch (err) {
+ case BT_ERROR_NONE:
+ err_str = "BT_ERROR_NONE";
+ break;
+ case BT_ERROR_CANCELLED:
+ err_str = "BT_ERROR_CANCELLED";
+ break;
+ case BT_ERROR_INVALID_PARAMETER:
+ err_str = "BT_ERROR_INVALID_PARAMETER";
+ break;
+ case BT_ERROR_OUT_OF_MEMORY:
+ err_str = "BT_ERROR_OUT_OF_MEMORY";
+ break;
+ case BT_ERROR_RESOURCE_BUSY:
+ err_str = "BT_ERROR_RESOURCE_BUSY";
+ break;
+ case BT_ERROR_TIMED_OUT:
+ err_str = "BT_ERROR_TIMED_OUT";
+ break;
+ case BT_ERROR_NOW_IN_PROGRESS:
+ err_str = "BT_ERROR_NOW_IN_PROGRESS";
+ break;
+ case BT_ERROR_NOT_INITIALIZED:
+ err_str = "BT_ERROR_NOT_INITIALIZED";
+ break;
+ case BT_ERROR_NOT_ENABLED:
+ err_str = "BT_ERROR_NOT_ENABLED";
+ break;
+ case BT_ERROR_ALREADY_DONE:
+ err_str = "BT_ERROR_ALREADY_DONE";
+ break;
+ case BT_ERROR_OPERATION_FAILED:
+ err_str = "BT_ERROR_OPERATION_FAILED";
+ break;
+ case BT_ERROR_NOT_IN_PROGRESS:
+ err_str = "BT_ERROR_NOT_IN_PROGRESS";
+ break;
+ case BT_ERROR_REMOTE_DEVICE_NOT_BONDED:
+ err_str = "BT_ERROR_REMOTE_DEVICE_NOT_BONDED";
+ break;
+ case BT_ERROR_AUTH_REJECTED:
+ err_str = "BT_ERROR_AUTH_REJECTED";
+ break;
+ case BT_ERROR_AUTH_FAILED:
+ err_str = "BT_ERROR_AUTH_FAILED";
+ break;
+ case BT_ERROR_REMOTE_DEVICE_NOT_FOUND:
+ err_str = "BT_ERROR_REMOTE_DEVICE_NOT_FOUND";
+ break;
+ case BT_ERROR_SERVICE_SEARCH_FAILED:
+ err_str = "BT_ERROR_SERVICE_SEARCH_FAILED";
+ break;
+ case BT_ERROR_REMOTE_DEVICE_NOT_CONNECTED:
+ err_str = "BT_ERROR_REMOTE_DEVICE_NOT_CONNECTED";
+ break;
+ case BT_ERROR_PERMISSION_DENIED:
+ err_str = "BT_ERROR_PERMISSION_DENIED";
+ break;
+ case BT_ERROR_SERVICE_NOT_FOUND:
+ err_str = "BT_ERROR_SERVICE_NOT_FOUND";
+ break;
+ case BT_ERROR_NO_DATA:
+ err_str = "BT_ERROR_NO_DATA";
+ break;
+ case BT_ERROR_NOT_SUPPORTED:
+ err_str = "BT_ERROR_NOT_SUPPORTED";
+ break;
+ case BT_ERROR_DEVICE_POLICY_RESTRICTION:
+ err_str = "DEVICE_POLICY_RESTRICTION";
+ break;
+ default:
+ err_str = "NOT Defined";
+ break;
+ }
+
+ return err_str;
+}
+
+/**
+ * Callback functions
+ **/
+static gboolean __bt_timeout_func(gpointer data)
+{
+ HID_PRT("Timeout.");
+ if (g_mainloop)
+ g_main_loop_quit((GMainLoop *)data);
+
+ return FALSE;
+}
+
+static void __bt_hid_device_connection_state_changed_cb(int result,
+ bool connected, const char *remote_address, void *user_data)
+{
+ HID_PRT("result: %s", __bt_get_error_message(result));
+ HID_PRT("Remote Address: %s", remote_address);
+ HID_PRT("Connected [%d]", connected);
+
+ g_wait_flag = false;
+
+ if (connected == true && result == BT_ERROR_NONE) {
+ g_strlcpy(remote_addr, remote_address, 18);
+ hid_connected = true;
+ } else {
+ hid_connected = false;
+ }
+}
+
+void __bt_audio_connection_state_changed_cb(int result,
+ bool connected, const char *remote_address,
+ bt_audio_profile_type_e type, void *user_data)
+{
+ HID_PRT("result [%s]", __bt_get_error_message(result));
+ HID_PRT("connected [%d]", connected);
+ HID_PRT("address [%s]", remote_address);
+ HID_PRT("type [%d]", type);
+
+ g_wait_flag = false;
+
+ if (connected == true && result == BT_ERROR_NONE) {
+ g_strlcpy(remote_addr, remote_address, 18);
+ audio_connected = true;
+ } else {
+ audio_connected = false;
+ }
+}
+
+static bool __bt_adapter_hid_profile_connected_devices_cb(
+ const char *remote_address, void *user_data)
+{
+ HID_PRT("remote_address: %s", remote_address);
+
+ g_strlcpy(remote_addr, remote_address, 18);
+
+ hid_connected = true;
+
+ return true;
+}
+
+static bool __bt_adapter_a2dp_profile_connected_devices_cb(
+ const char *remote_address, void *user_data)
+{
+ HID_PRT("remote_address: %s", remote_address);
+
+ g_strlcpy(remote_addr, remote_address, 18);
+
+ audio_connected = true;
+
+ return true;
+}
+
+void __bt_device_bond_created_cb(int result,
+ bt_device_info_s *device_info, void *user_data)
+{
+ if (result == BT_ERROR_NONE) {
+ HID_PRT("Callback: A bond is created.");
+ HID_PRT("Callback: is_bonded - %d.", device_info->is_bonded);
+ device_bonded = true;
+ } else {
+ HID_PRT("Callback: Creating a bond is failed.");
+ HID_PRT("result: %s", __bt_get_error_message(result));
+ }
+
+ g_wait_flag = false;
+}
+
+static void __bt_state_changed_impl(int result,
+ bt_adapter_state_e adapter_state,
+ void *user_data)
+{
+ if (adapter_state == BT_ADAPTER_ENABLED) {
+ if (result == BT_ERROR_NONE) {
+ HID_PRT("Callback: BT was enabled successfully.");
+ bt_state = BT_ADAPTER_ENABLED;
+ } else {
+ HID_PRT("Callback: Failed to enable BT.");
+ }
+ }
+
+ if (g_mainloop)
+ g_main_loop_quit(g_mainloop);
+}
+
+gint __bt_compare_address(gpointer *a, gpointer *b)
+{
+ bt_adapter_le_device_scan_result_info_s *info = (bt_adapter_le_device_scan_result_info_s *)a;
+ char *address = (char *)b;
+ return g_strcmp0(info->remote_address, address);
+}
+
+static void __bt_adapter_le_scan_result_cb(
+ int result, bt_adapter_le_device_scan_result_info_s *info,
+ void *user_data)
+{
+ int i;
+ bt_adapter_le_packet_type_e pkt_type = BT_ADAPTER_LE_PACKET_ADVERTISING;
+ bt_adapter_le_device_scan_result_info_s *adv_info;
+
+ if (info == NULL) {
+ HID_PRT("No discovery_info!");
+ return;
+ }
+
+ if (info->adv_data_len > 31 || info->scan_data_len > 31) {
+ HID_PRT("###################");
+ bt_adapter_le_stop_scan();
+ HID_PRT("###################");
+ return;
+ }
+
+ GSList *l = NULL;
+ l = g_slist_find_custom(le_scan_list, info->remote_address,
+ (GCompareFunc)__bt_compare_address);
+
+ if (l != NULL) {
+ adv_info = l->data;
+ adv_info->rssi = info->rssi;
+ return;
+ }
+
+ adv_info = g_malloc0(sizeof(bt_adapter_le_device_scan_result_info_s));
+ adv_info->remote_address= g_strdup(info->remote_address);
+ adv_info->rssi = info->rssi;
+ le_scan_list = g_slist_append(le_scan_list, adv_info);
+
+ for (i = 0; i < 2; i++) {
+ char *device_name;
+
+ pkt_type += i;
+ if (pkt_type == BT_ADAPTER_LE_PACKET_ADVERTISING
+ && info->adv_data == NULL) continue;
+ if (pkt_type == BT_ADAPTER_LE_PACKET_SCAN_RESPONSE
+ && info->scan_data == NULL) break;
+
+ if (bt_adapter_le_get_scan_result_device_name(
+ info, pkt_type, &device_name) == BT_ERROR_NONE) {
+
+ HID_PRT("\n%s Adv %d Scan resp %d RSSI %d Addr_type %d",
+ info->remote_address, info->adv_data_len,
+ info->scan_data_len, info->rssi,
+ info->address_type);
+
+ HID_PRT("Device name = %s", device_name);
+ if (adv_info->adv_data == NULL)
+ adv_info->adv_data= g_strdup(device_name);
+ g_free(device_name);
+ return;
+ }
+ }
+}
+
+static void __bt_find_remote_tv(void)
+{
+ int ret = BT_ERROR_NONE;
+ bt_scan_filter_h scan_filter = NULL;
+ int manufacturer_id = 117; /* samsung */
+
+ scanning = true;
+
+ ret = bt_adapter_le_scan_filter_unregister_all();
+ if (ret != BT_ERROR_NONE)
+ HID_PRT("failed with [0x%04x]", ret);
+
+ ret = bt_adapter_le_scan_filter_create(&scan_filter);
+ if (ret != BT_ERROR_NONE)
+ HID_PRT("failed with [0x%04x]", ret);
+
+ ret = bt_adapter_le_scan_filter_set_manufacturer_data(scan_filter,
+ manufacturer_id, NULL, 0);
+ if (ret != BT_ERROR_NONE)
+ HID_PRT("failed with [0x%04x]", ret);
+
+ ret = bt_adapter_le_scan_filter_register(scan_filter);
+ if (ret != BT_ERROR_NONE)
+ HID_PRT("failed with [0x%04x]", ret);
+
+ ret = bt_adapter_le_scan_filter_destroy(scan_filter);
+ if (ret != BT_ERROR_NONE)
+ HID_PRT("failed with [0x%04x]", ret);
+
+ ret = bt_adapter_le_start_scan(__bt_adapter_le_scan_result_cb, NULL);
+ HID_PRT("returns %s\n", __bt_get_error_message(ret));
+
+ if (ret == BT_ERROR_NONE)
+ scanning = true;
+}
+
+static gboolean __bt_start_service(gpointer user_data)
+{
+ int ret = BT_ERROR_NONE;
+
+ ret = bt_audio_initialize();
+
+ ret = bt_audio_select_role(BT_A2DP_SINK);
+
+ ret = bt_device_set_bond_created_cb(__bt_device_bond_created_cb, NULL);
+
+ ret = bt_audio_set_connection_state_changed_cb(
+ __bt_audio_connection_state_changed_cb, NULL);
+
+ ret = bt_hid_device_activate(
+ __bt_hid_device_connection_state_changed_cb,
+ NULL);
+ HID_PRT("returns %s", __bt_get_error_message(ret));
+
+ if (ret != BT_ERROR_NONE && ret != BT_ERROR_NOW_IN_PROGRESS) {
+ HID_PRT("bt_hid_device_activate() failed.");
+ g_main_loop_quit(g_mainloop);
+ return FALSE;
+ }
+
+ ret = bt_adapter_foreach_profile_connected_devices(BT_PROFILE_SERVICE_UUID_HID,
+ __bt_adapter_hid_profile_connected_devices_cb, NULL);
+ HID_PRT("HID connected devices returns %s\n", __bt_get_error_message(ret));
+
+ ret = bt_adapter_foreach_profile_connected_devices(BT_PROFILE_SERVICE_UUID_A2DP_SOURCE,
+ __bt_adapter_a2dp_profile_connected_devices_cb, NULL);
+ HID_PRT("A2DP connected devices returns %s\n", __bt_get_error_message(ret));
+
+ if (hid_connected == false && audio_connected == false) {
+ HID_PRT("No TV is connected, try to search...");
+ __bt_find_remote_tv();
+ }
+
+ return FALSE;
+}
+
+static void __bt_stop_setup(void)
+{
+ setup_in_progress = false;
+}
+
+static int __bt_initial_setup(void)
+{
+ int ret = BT_ERROR_NONE;
+ bt_device_info_s *device_info = NULL;
+
+ setup_in_progress = true;
+
+ ret = bt_adapter_get_bonded_device_info(remote_addr, &device_info);
+ HID_PRT("returns %s\n", __bt_get_error_message(ret));
+
+ if (ret == BT_ERROR_NONE) {
+ /* Already bond */
+ HID_PRT("Device is already paired");
+ device_bonded = true;
+ } else {
+ /* Create Bond */
+ ret = bt_device_create_bond(remote_addr);
+ HID_PRT("returns %s\n", __bt_get_error_message(ret));
+
+ if (ret != BT_ERROR_NONE)
+ return ret;
+
+ WAIT_FOR_SYNC;
+ }
+
+ if (device_bonded == false)
+ return BT_ERROR_OPERATION_FAILED;
+
+ /* Connect HID first */
+ ret = bt_hid_device_connect(remote_addr);
+ HID_PRT("HID connect for %s: returns %s", remote_addr, __bt_get_error_message(ret));
+
+ if (ret == BT_ERROR_NONE)
+ WAIT_FOR_SYNC;
+
+ /* Connect Audio */
+ ret = bt_audio_connect(remote_addr, BT_AUDIO_PROFILE_TYPE_A2DP_SINK);
+ HID_PRT("Audio connect for %s: returns %s", remote_addr, __bt_get_error_message(ret));
+
+ if (ret == BT_ERROR_NONE)
+ WAIT_FOR_SYNC;
+
+ if (hid_connected == false || audio_connected == false)
+ ret = BT_ERROR_OPERATION_FAILED;
+
+ setup_in_progress = false;
+
+ return ret;
+}
+
+
+static void __bt_tc_usage_print(void)
+{
+ int i = 0;
+ tc_table_t *tc_table = tc_hid_device;
+
+
+ while (tc_table[i].tc_name) {
+ HID_PRT("Key %d : usage %s", tc_table[i].tc_code,
+ tc_table[i].tc_name);
+ i++;
+ }
+ HID_PRT("\n");
+}
+
+static int __bt_test_input_callback(void *data)
+{
+ int ret = 0;
+ int test_id = (int)data;
+ GSList *l = NULL;
+ int cnt = 0;
+ bt_adapter_le_device_scan_result_info_s *info;
+ unsigned char report_id = 0xF7;
+ char pressed_data[6] = {0x07, 0x00, 0x00, 0x00, 0x00, 0x00};
+ char released_data[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ if (setup_in_progress == true &&
+ test_id != BT_HID_DEVICE_TEST_SETUP &&
+ test_id != BT_HID_DEVICE_TEST_FINISH) {
+ HID_PRT("Initial Setup is in progress,,");
+ HID_PRT("Wait to finish setup");
+ return 0;
+ }
+
+ switch (test_id) {
+ case BT_HID_DEVICE_SET_ADDRESS:
+ HID_PRT("Input the address of remote device."
+ "(e.g.,F6:FB:8F:D8:C8:7C)\n\n");
+
+ address_input = true;
+
+ break;
+ case BT_HID_DEVICE_TEST_SETUP:
+ if (setup_in_progress == true) {
+ HID_PRT("Stop the initial setup");
+ __bt_stop_setup();
+ } else {
+ if (__bt_initial_setup() != BT_ERROR_NONE) {
+ HID_PRT("Fail to setup: %s", __bt_get_error_message(ret));
+ }
+ }
+ break;
+ case BT_HID_DEVICE_TEST_VOLUME_UP:
+ pressed_data[0] = 0x07; /* Vol up */
+
+ ret = bt_hid_device_send_custom_event(remote_addr,
+ report_id, pressed_data, 6);
+ HID_PRT("returns %d\n", ret);
+
+ ret = bt_hid_device_send_custom_event(remote_addr,
+ report_id, released_data, 6);
+ break;
+ case BT_HID_DEVICE_TEST_VOLUME_DOWN:
+ pressed_data[0] = 0x0B; /* Vol down */
+
+ ret = bt_hid_device_send_custom_event(remote_addr,
+ report_id, pressed_data, 6);
+ HID_PRT("returns %d\n", ret);
+
+ ret = bt_hid_device_send_custom_event(remote_addr,
+ report_id, released_data, 6);
+ break;
+ case BT_HID_DEVICE_TEST_CHANNEL_UP:
+ pressed_data[0] = 0x12; /* CH up */
+
+ ret = bt_hid_device_send_custom_event(remote_addr,
+ report_id, pressed_data, 6);
+ HID_PRT("returns %d\n", ret);
+
+ ret = bt_hid_device_send_custom_event(remote_addr,
+ report_id, released_data, 6);
+ break;
+ case BT_HID_DEVICE_TEST_CHANNEL_DOWN:
+ pressed_data[0] = 0x10; /* CH down */
+
+ ret = bt_hid_device_send_custom_event(remote_addr,
+ report_id, pressed_data, 6);
+ HID_PRT("returns %d\n", ret);
+
+ ret = bt_hid_device_send_custom_event(remote_addr,
+ report_id, released_data, 6);
+ break;
+ case BT_HID_DEVICE_TEST_CONNECT_AUDIO:
+ ret = bt_audio_connect(remote_addr, BT_AUDIO_PROFILE_TYPE_A2DP_SINK);
+ HID_PRT("returns %s", __bt_get_error_message(ret));
+ break;
+ case BT_HID_DEVICE_TEST_DISCONNECT_AUDIO:
+ ret = bt_audio_disconnect(remote_addr, BT_AUDIO_PROFILE_TYPE_A2DP_SINK);
+ HID_PRT("returns %s", __bt_get_error_message(ret));
+ break;
+ case BT_HID_DEVICE_TEST_CONNECT_HID:
+ ret = bt_hid_device_connect(remote_addr);
+ HID_PRT("returns %s", __bt_get_error_message(ret));
+ break;
+ case BT_HID_DEVICE_TEST_DISCONNECT_HID:
+ ret = bt_hid_device_disconnect(remote_addr);
+ HID_PRT("returns %s", __bt_get_error_message(ret));
+ break;
+ case BT_HID_DEVICE_TEST_SEARCH:
+ __bt_find_remote_tv();
+ break;
+ case BT_HID_DEVICE_TEST_STOP_SEARCH:
+ scanning = false;
+
+ ret = bt_adapter_le_stop_scan();
+ HID_PRT("returns %s\n", __bt_get_error_message(ret));
+
+ HID_PRT("LE scan result :\n");
+ for (l = le_scan_list; l != NULL; l = g_slist_next(l)) {
+ info = l->data;
+ if (info) {
+ if (info->adv_data)
+ HID_PRT("[%d] %s, %d dBm, %s", ++cnt, info->remote_address, info->rssi, info->adv_data);
+
+ g_free(info->remote_address);
+ g_free(info->adv_data);
+ g_free(info);
+ }
+ }
+ g_slist_free(le_scan_list);
+ le_scan_list = NULL;
+
+ break;
+ case BT_HID_DEVICE_TEST_FINISH:
+ HID_PRT("Finished");
+ g_main_loop_quit(g_mainloop);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+static gboolean __bt_key_event_cb(GIOChannel *chan,
+ GIOCondition cond,
+ gpointer data)
+{
+ char buf[49] = { 0 };
+
+#ifdef ARCH64
+ unsigned long len = 0;
+#else
+ unsigned int len = 0;
+#endif
+ int test_id;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (g_io_channel_read_chars(chan, buf, sizeof(buf),
+ &len, NULL) == G_IO_STATUS_ERROR) {
+ HID_PRT("IO Channel read error");
+ return FALSE;
+ }
+
+ HID_PRT("%s", buf);
+
+ if (address_input == true) {
+ memcpy(remote_addr, buf, 17);
+ remote_addr[17] = 0;
+ address_input = false;
+ }
+
+ if (scanning == true) {
+ test_id = BT_HID_DEVICE_TEST_STOP_SEARCH;
+#ifdef ARCH64
+ g_idle_add(__bt_test_input_callback, (void *)(uintptr_t)test_id);
+#else
+ g_idle_add(__bt_test_input_callback, (void *)test_id);
+#endif
+ return TRUE;
+ }
+
+ test_id = atoi(buf);
+
+ __bt_tc_usage_print();
+
+#ifdef ARCH64
+ g_idle_add(__bt_test_input_callback, (void *)(uintptr_t)test_id);
+#else
+ g_idle_add(__bt_test_input_callback, (void *)test_id);
+#endif
+ return TRUE;
+}
+
+int main()
+{
+ int timeout_id = -1;
+ int ret = BT_ERROR_NONE;
+ GIOChannel *key_io;
+
+ g_mainloop = g_main_loop_new(NULL, FALSE);
+
+ HID_PRT("HID Keyboard starts");
+
+ if (bt_initialize() != BT_ERROR_NONE) {
+ HID_PRT("bt_initialize() failed.");
+ return -1;
+ }
+
+ if (bt_adapter_get_state(&bt_state) != BT_ERROR_NONE) {
+ HID_PRT("bt_adapter_get_state() failed.");
+ return -1;
+ }
+
+ /* Enable BT */
+ if (bt_state == BT_ADAPTER_DISABLED) {
+ if (bt_adapter_set_state_changed_cb(
+ __bt_state_changed_impl, NULL) != BT_ERROR_NONE) {
+ HID_PRT("bt_adapter_set_state_changed_cb() failed.");
+ return -1;
+ }
+
+ if (bt_adapter_enable() == BT_ERROR_NONE) {
+ HID_PRT("bt_adapter_state_changed_cb will be called.");
+ timeout_id = g_timeout_add(60000,
+ __bt_timeout_func, g_mainloop);
+ g_main_loop_run(g_mainloop);
+ g_source_remove(timeout_id);
+ } else {
+ HID_PRT("bt_adapter_enable() failed.");
+ return -1;
+ }
+ } else {
+ HID_PRT("BT was already enabled.");
+ }
+
+ if (bt_state != BT_ADAPTER_ENABLED) {
+ HID_PRT("BT is not enabled.");
+ return -1;
+ }
+
+ g_idle_add(__bt_start_service, NULL);
+
+ key_io = g_io_channel_unix_new(fileno(stdin));
+
+ g_io_channel_set_encoding(key_io, NULL, NULL);
+ g_io_channel_set_flags(key_io, G_IO_FLAG_NONBLOCK, NULL);
+
+ g_io_add_watch(key_io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ __bt_key_event_cb, NULL);
+
+ g_io_channel_unref(key_io);
+
+ g_main_loop_run(g_mainloop);
+
+ ret = bt_hid_device_deactivate();
+ HID_PRT("returns %s\n", __bt_get_error_message(ret));
+
+ bt_deinitialize();
+
+ HID_PRT("HID Keyboard ends.");
+ return 0;
+}