Languages

Menu
Sites
Language
Tizen Bonding Problem

I'm developing sample native application(not companion) for Gear3 which is communicating my test device through BLE.

 

Gear3(Tizen watch) is working as central, my test device is working as peripheral and Gear is connected to the android device through bluetooth also.

Usually, bonding with the test device is  successful while gear is connected to the android device but if I disconnected the android device and put gear in standalone mode (for example, turn off the android device).

After that,  I got failed  when I tried to bonding with my test device with a 'unable to connect' popup message .

If I tested it again after turnning on the android device, bonding process is successful again.

 

Sum up the situation,

  1. Gear3 is conneted to the android device(phone).

  2. Creating bond [bt_device_create_bond()] with my test device using my sample application. The result is success. 

  3. Deleting bond then turn off the android device and make sure that gear3 is working in standalone.

  4. Creating bond with my test device. "unable to connect" popup shows and the result is failed.

       bt_device_bond_created_cb() is called with BT_ERROR_OPERATION_FAILED​.

   5. Turn on the android device and make sure that watch is connected to the android device.

   6. Creating bond is succesful again.

 

The device information is below.

Gear S3 Frontier

Model Number : SM-R760

Tizen version : 2.3.2.4

Software version : R760XXU2BQH1 

 SDK : Tizen Wearable 2.3.2

 

Could you help me fix this problem?

 

Edited by: Anonymous on 04 Jan, 2018

Responses

9 Replies
Safwan

So, There are three devices, right?

i) An android phone

ii) A Gear S3

iii) A test device

Please share some Info about the 'test device'.

Yes, there are three devices.

 
Gear3 is connected to android phone and Gear3 is connected to a test device .
Each connection is independent, I mean each connection isn't associated.
 
The test device is made by our company. we are using Nordic module. (nRF51822AB)
BLE 4.1 is supported.  Device information service(0000180a-0000-1000-8000-00805f9b34fb) and custom service(uart - 6e400001-b5a3-f393-e0a9-e50e24dcca9e) are provided.

This issue is related to the test device?
Please explain what kind of information about the test device you need.
 
It seems that this problem happens after I disconnected to Gear3 from android phone by turning off the phone or turning bluetooth off through setting menu in the phone.
If I disconnected to Gear3 from android phone through 'disconnect' button in Samsung Gear Application in the phone, this issue doesn't happen.

 

Safwan

Please share your Tizen Native Code Snippet for BLE communication. Then, it might be possible to test your code on my environment and share the feedback.

​Safwan,

I made additional sample application and I am able to reproduce this issue using it.

Unbonded function is not supported by this application so please use other way or implement it, if you need.

1. When a application starts, init bt and start scan
2. if a peripheral device is found, add it into gen list.
3. if a user selects the device, try to bond it.
4.  #3,  it is failed with "unalbe to connect" message during Gear3 is disconnect to a phone by turning off a phone or a turning off a phone's bluetooth. 
 
 
#include "bletest.h"
#include "log.h"
#include <bluetooth.h>
#include <system_info.h>
typedef struct data_node data_n;
struct data_node
{
 char *name;
 char *addr;
 data_n *next;
};
typedef struct appdata {
 Evas_Object *win;
 Evas_Object *conform;
 Evas_Object *scanned_device_genlist;
 data_n *header_data_list;
 boolean is_scanning;
} appdata_s;
typedef struct _item_data
{
 int index;
 Elm_Object_Item *item;
 char *name;
 char *addr;
 appdata_s *ad;
} item_data;

static void clear_data_list(appdata_s *ad) {
 data_n *item = ad->header_data_list;
 data_n *next_item = NULL;
 while(item != NULL) {
  next_item = item->next;
  if(item->name != NULL) {
   free(item->name);
  }
  if(item->addr != NULL) {
   free(item->addr);
  }
  free(item);
  item = next_item;
 }
 ad->header_data_list = NULL;
}
static void
win_delete_request_cb(void *data, Evas_Object *obj, void *event_info)
{
 ui_app_exit();
}
static void
win_back_cb(void *data, Evas_Object *obj, void *event_info)
{
 appdata_s *ad = data;
 /* Let window go to hide state. */
 elm_win_lower(ad->win);
}
static void gl_selected_cb(void *data, Evas_Object *obj, void *event_info)
{
 Elm_Object_Item *it = (Elm_Object_Item *)event_info;
 item_data *id = (item_data *)elm_object_item_data_get((Elm_Object_Item *)event_info);
 elm_genlist_item_selected_set(it, EINA_FALSE);
 if(is_scanning) {
  if(bt_adapter_le_stop_scan() != BT_ERROR_NONE) {
   KLOGW(LOG_TAG, "stop scan is failed.");
  } else {
   KLOGW(LOG_TAG, "stop scan is success");
  }
 }
 int btRet = BT_ERROR_NONE;
 bt_device_info_s *device_info = NULL;
 bt_adapter_get_bonded_device_info (id->addr, &device_info);
 bt_adapter_le_state_e adapter_le_state = BT_ADAPTER_LE_DISABLED;
 btRet = bt_adapter_le_get_state(&adapter_le_state);
 KLOGI(LOG_TAG, "le get state %d %d", btRet, adapter_le_state);
 if(device_info == NULL) {
  btRet = bt_device_create_bond(id->addr);
  KLOGI(LOG_TAG, "create_bond %s %d", id->addr, btRet);
 } else {
  bt_adapter_free_device_info(device_info);
 }
}
static char *_gl_menu_title_text_get(void *data, Evas_Object *obj, const char *part)
{
 char buf[1024];
 snprintf(buf, 1023, "%s", "TEST");
 return strdup(buf);
}
static char *_gl_menu_text_get(void *data, Evas_Object *obj, const char *part)
{
 char buf[1024];
 item_data *id = (item_data *)data;
 if(id->name != NULL) {
  snprintf(buf, 1023, "%s", id->name);
  return strdup(buf);
 }
 return strdup("N/A");
}
static void _gl_menu_del(void *data, Evas_Object *obj)
{
 item_data *id = (item_data *)data;
 if (id) {
  if(id->name != NULL) {
   free(id->name);
  }
  if(id->addr != NULL) {
   free(id->addr);
  }
  free(id);
 }
}
static void _gl_sel(void *data, Evas_Object *obj, void *event_info) {
 KLOGD(LOG_TAG, "_gl_sel");
}
void refresh_data_item(appdata_s *ad) {
 if(ad->scanned_device_genlist != NULL) {
  elm_genlist_clear(ad->scanned_device_genlist);
  Elm_Genlist_Item_Class *ttc = elm_genlist_item_class_new();
  ttc->item_style = "title";
  ttc->func.text_get = _gl_menu_title_text_get;
  ttc->func.del = _gl_menu_del;
  elm_genlist_item_append(ad->scanned_device_genlist, ttc, NULL, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
  elm_genlist_item_class_free(ttc);

  data_n *item = ad->header_data_list;
  int index = 0;
  while(item != NULL) {
   Elm_Genlist_Item_Class *itc = elm_genlist_item_class_new();
   itc->item_style = "1text";
   itc->func.text_get = _gl_menu_text_get;
   itc->func.del = _gl_menu_del;
   item_data *id = calloc(sizeof(item_data), 1);
   id->index = index;
   id->name = strdup(item->name);
   id->addr = strdup(item->addr);
   id->item = elm_genlist_item_append(ad->scanned_device_genlist, itc, id, NULL, ELM_GENLIST_ITEM_NONE, _gl_sel, ad);
   elm_genlist_item_class_free(itc);
   item = item->next;
   index++;
  }
  Elm_Genlist_Item_Class *ptc = elm_genlist_item_class_new();
  ptc->item_style = "padding";
  ptc->func.del = _gl_menu_del;
  elm_genlist_item_append(ad->scanned_device_genlist, ptc, NULL, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
  elm_genlist_item_class_free(ptc);
 }
}
static void
create_base_gui(appdata_s *ad)
{
 /* Window */
 ad->win = elm_win_util_standard_add(PACKAGE, PACKAGE);
 elm_win_autodel_set(ad->win, EINA_TRUE);
 if (elm_win_wm_rotation_supported_get(ad->win)) {
  int rots[4] = { 0, 90, 180, 270 };
  elm_win_wm_rotation_available_rotations_set(ad->win, (const int *)(&rots), 4);
 }
 evas_object_smart_callback_add(ad->win, "delete,request", win_delete_request_cb, NULL);
 eext_object_event_callback_add(ad->win, EEXT_CALLBACK_BACK, win_back_cb, ad);
 /* Conformant */
 ad->conform = elm_conformant_add(ad->win);
 elm_win_indicator_mode_set(ad->win, ELM_WIN_INDICATOR_SHOW);
 elm_win_indicator_opacity_set(ad->win, ELM_WIN_INDICATOR_OPAQUE);
 evas_object_size_hint_weight_set(ad->conform, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
 elm_win_resize_object_add(ad->win, ad->conform);
 evas_object_show(ad->conform);

 Elm_Genlist_Item_Class *ttc = elm_genlist_item_class_new();
 Elm_Genlist_Item_Class *ptc = elm_genlist_item_class_new();
 ad->scanned_device_genlist = elm_genlist_add(ad->conform);
 elm_genlist_mode_set(ad->scanned_device_genlist, ELM_LIST_COMPRESS);
 evas_object_smart_callback_add(ad->scanned_device_genlist, "selected", gl_selected_cb, NULL);
 ttc->item_style = "title";
 ttc->func.text_get = _gl_menu_title_text_get;
 ttc->func.del = _gl_menu_del;
 ptc->item_style = "padding";
 ptc->func.del = _gl_menu_del;
 elm_genlist_item_append(ad->scanned_device_genlist, ttc, NULL, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
 elm_genlist_item_append(ad->scanned_device_genlist, ptc, NULL, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
 elm_genlist_item_class_free(ttc);
 elm_genlist_item_class_free(ptc);
 evas_object_size_hint_weight_set(ad->scanned_device_genlist, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
 elm_object_content_set(ad->conform, ad->scanned_device_genlist);
 /* Show window after base gui is set up */
 evas_object_show(ad->win);
}
static bool __is_feature_supported(const char *feature)
{
 bool is_supported = false;
 int ret = system_info_get_platform_bool(feature, &is_supported);
 if (ret != SYSTEM_INFO_ERROR_NONE) {
  KLOGE(LOG_TAG, "Function system_info_get_platform_bool() failed with error: %d.", get_error_message(ret));
  return false;
 }
 return is_supported;
}
/*s
 * @brief: Check whether Bluetooth feature is supported by the platform.
 * The Bluetooth feature is specified as "http://tizen.org/feature/network.bluetooth".
 * @return: the function returns 'true' if the Bluetooth feature is supported by the platform,
 * otherwise 'false' is returned.
 */
bool bt_common_is_bluetooth_supported(void)
{
 return __is_feature_supported(FEATURE_BLUETOOTH);
}
/*
 * @brief: Check whether Bluetooth LE feature is supported by the platform.
 * The Bluetooth LE feature is specified as "http://tizen.org/feature/network.bluetooth.le".
 * @return: the function returns 'true' if the Bluetooth LE feature is supported by the platform,
 * otherwise 'false' is returned.
 */
bool bt_common_is_bluetooth_le_supported(void)
{
 return __is_feature_supported(FEATURE_BLUETOOTH_LE);
}
void bt_device_bond_created(int result, bt_device_info_s * device_info, void*user_data) {
 KLOGW(LOG_TAG, "name:%s result:%d", device_info->remote_name, result);
}
void bt_init(void) {
 if(bt_initialize() != BT_ERROR_NONE) {
  KLOGW(LOG_TAG, "Bluetooth is not supported.");
  return;
 }
 bt_device_set_bond_created_cb(bt_device_bond_created, NULL);
}
void le_scan_result_received_cb(int result, bt_adapter_le_device_scan_result_info_s *info, void *user_data) {
 appdata_s *ad = (appdata_s *)user_data;
 char *deviceName = NULL;
 if(result != BT_ERROR_NONE || info == NULL || info->remote_address == NULL) {
  return;
 }
 KLOGD(LOG_TAG, "scanned(addr:%s)", info->remote_address);
 bt_adapter_le_packet_type_e pkt_type = BT_ADAPTER_LE_PACKET_ADVERTISING;
 for(int i = 0 ; i < 2 ; i++) {
  if(i == 1) {
   pkt_type = BT_ADAPTER_LE_PACKET_SCAN_RESPONSE;
  }
  if((pkt_type == BT_ADAPTER_LE_PACKET_ADVERTISING && info->adv_data != NULL)
   || (pkt_type == BT_ADAPTER_LE_PACKET_SCAN_RESPONSE && info->scan_data != NULL)) {
   if(bt_adapter_le_get_scan_result_device_name(info, pkt_type, &deviceName) == BT_ERROR_NONE
     && deviceName != NULL) {
 
   // check if same device is added already by device's name
    data_n *data = ad->header_data_list;
    while(data != NULL) {
     if(strcmp(deviceName, data->name) == 0) {
      free(deviceName);
      return;
     }
     data = data->next;
    }
    data_n *new_data = ad->header_data_list;
    while(!(new_data == NULL || new_data->next == NULL)) {
     new_data = new_data->next;
    }
    if(new_data == NULL) {
     new_data = calloc(sizeof(data_n), 1);
     ad->header_data_list = new_data;
    } else {
     new_data->next = calloc(sizeof(data_n), 1);
     new_data = new_data->next;
    }
    new_data->name = strdup(deviceName);
    new_data->addr = strdup(info->remote_address);
    free(deviceName);
    refresh_data_item(ad);
   }
  }
 }
}
static bool
app_create(void *data)
{
 /* Hook to take necessary actions before main event loop starts
  Initialize UI resources and application's data
  If this function returns true, the main loop of application starts
  If this function returns false, the application is terminated */
 appdata_s *ad = data;
 if (!bt_common_is_bluetooth_supported())
  KLOGW(LOG_TAG, "Bluetooth is not supported.");
 if (!bt_common_is_bluetooth_le_supported())
  KLOGW(LOG_TAG, "Bluetooth Low Energy is not supported.");
 bt_init();
 create_base_gui(ad);

 return true;
}
static void
app_control(app_control_h app_control, void *data)
{
 /* Handle the launch request. */
}
static void
app_pause(void *data)
{
 /* Take necessary actions when application becomes invisible. */
 if(is_scanning) {
  if(bt_adapter_le_stop_scan() != BT_ERROR_NONE) {
   KLOGW(LOG_TAG, "stop scan is failed.");
  } else {
   KLOGW(LOG_TAG, "stop scan is success");
  }
 }
}
static void
app_resume(void *data)
{
 int bRet;
 /* Take necessary actions when application becomes visible. */
 clear_data_list(data);
 if((bRet = bt_adapter_le_start_scan(le_scan_result_received_cb, data)) != BT_ERROR_NONE) {
  KLOGW(LOG_TAG, "start scan is failed. %d", bRet);
 } else {
  KLOGW(LOG_TAG, "start scan is success");
  is_scanning = true;
 }
}
static void
app_terminate(void *data)
{
 /* Release all resources. */
 clear_data_list(data);
}
static void
ui_app_lang_changed(app_event_info_h event_info, void *user_data)
{
 /*APP_EVENT_LANGUAGE_CHANGED*/
 char *locale = NULL;
 system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_LANGUAGE, &locale);
 elm_language_set(locale);
 free(locale);
 return;
}
static void
ui_app_orient_changed(app_event_info_h event_info, void *user_data)
{
 /*APP_EVENT_DEVICE_ORIENTATION_CHANGED*/
 return;
}
static void
ui_app_region_changed(app_event_info_h event_info, void *user_data)
{
 /*APP_EVENT_REGION_FORMAT_CHANGED*/
}
static void
ui_app_low_battery(app_event_info_h event_info, void *user_data)
{
 /*APP_EVENT_LOW_BATTERY*/
}
static void
ui_app_low_memory(app_event_info_h event_info, void *user_data)
{
 /*APP_EVENT_LOW_MEMORY*/
}
int
main(int argc, char *argv[])
{
 appdata_s ad = {0,};
 int ret = 0;
 ui_app_lifecycle_callback_s event_callback = {0,};
 app_event_handler_h handlers[5] = {NULL, };
 event_callback.create = app_create;
 event_callback.terminate = app_terminate;
 event_callback.pause = app_pause;
 event_callback.resume = app_resume;
 event_callback.app_control = app_control;
 ui_app_add_event_handler(&handlers[APP_EVENT_LOW_BATTERY], APP_EVENT_LOW_BATTERY, ui_app_low_battery, &ad);
 ui_app_add_event_handler(&handlers[APP_EVENT_LOW_MEMORY], APP_EVENT_LOW_MEMORY, ui_app_low_memory, &ad);
 ui_app_add_event_handler(&handlers[APP_EVENT_DEVICE_ORIENTATION_CHANGED], APP_EVENT_DEVICE_ORIENTATION_CHANGED, ui_app_orient_changed, &ad);
 ui_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED], APP_EVENT_LANGUAGE_CHANGED, ui_app_lang_changed, &ad);
 ui_app_add_event_handler(&handlers[APP_EVENT_REGION_FORMAT_CHANGED], APP_EVENT_REGION_FORMAT_CHANGED, ui_app_region_changed, &ad);
 ui_app_remove_event_handler(handlers[APP_EVENT_LOW_MEMORY]);
 ret = ui_app_main(argc, argv, &event_callback, &ad);
 if (ret != APP_ERROR_NONE) {
  dlog_print(DLOG_ERROR, LOG_TAG, "app_main() is failed. err = %d", ret);
 }
 return ret;
}
Safwan

Thanks, I'll get back to you once I've got some progress.

Safwan

Confirming....

Kim, I am able to create bond using your code only when my Gear S2 is connected to phone, But when the Gear S2 is in standalone mode it's just "Unable to connect" message. Though it can scan nearby devices, but bond creation isn't successful. My environment:

 

i) Samsung Gear S2

ii) iPhone SE

ii) another Samsung Gear S2 ( in place of your 'test device' )

 

I tested with iPhone instead of android, anyways the result seems same as yours .

 

 

Now, One of two things can happen,

 

i) Either This is the way it meant to be. A wearable device should create bond with another bluetooth peripheral only when it's connected with a phone (android/iOS).  Creating bond with another bluetooth peripheral is not designed for standalone mode.

ii) Or this is a BUG.

 

I would suggest you to report a bug on Tizen bug Tracker explaining the scenario. Here's a guideline on how to report bugs.

BLE communication is done in static library which I made so I can't share my exact source code but simply snippet and flow is as below.

 

1.  bt_initialize is called and register callbacks.

  int iRet = bt_initialize();
  if(iRet != BT_ERROR_NONE) {
   return RCODE_ERROR_BLUETOOTH;
  }
...
  bt_device_set_bond_created_cb(bt_device_bond_created_cb, null);
  iRet = bt_gatt_set_connection_state_changed_cb(gattConnectionStateChanged_cb, null);
...
 
void bt_device_bond_created_cb(int result, bt_device_info_s * device_info, void*user_data) {
  KDC_LOGI(KDC_LOG_GROUP_LESMART, TAG, "name:%s result:%d", device_info->remote_name, result);
...
 

1. Tizen Native App calls startScan first like this.

 if((btRet = bt_adapter_le_start_scan(leScanResultReceived, null))
   != BT_ERROR_NONE) {

....

 

2. If bt_adapter_le_scan_result_cb​(leScanResultReceived) is called, app adds item into gen list to display it.

Item info is composed of device name and address.

 

3. If  a user selects specific device to bond. App stops scan and calls create bond api.

 if((btRet = bt_adapter_le_stop_scan()) != BT_ERROR_NONE) {
  iRet = RCODE_ERROR_BLUETOOTH;
 }

....

    bt_adapter_get_bonded_device_info (remote_address, &device_info);
    if(device_info == nullptr) {
      btRet = bt_device_create_bond(remote_address);
...
 
4. I also made additional menu in app to unbond device.
...
bt_device_destroy_bond(remote_address);
 
 
 
Yasin Ali

Have you found anything yet that may solve your problem ?

 

dev madrad

I suggest you to update Gear S3 device to Tizen 3.0.