Bluetooth: Managing Bluetooth Devices
This tutorial demonstrates how you can use Bluetooth connections.
Warm-up
Become familiar with the Bluetooth API basics by learning about:
-
Initializing Bluetooth
Initialize Bluetooth for use.
-
Enabling and Disabling Bluetooth
Enable or disable Bluetooth.
-
Initializing Bluetooth and Checking the Adapter State
Initialize Bluetooth and check the Bluetooth adapter state.
-
Finding Other Devices
Find other devices using Bluetooth.
- Serial Port Profile (SPP) operations
-
Connecting to Other Devices Using SPP
Connect to other devices through SPP.
-
Exchanging Data Using SPP
Exchange data between devices through SPP.
-
Disconnecting from the Connected Device Using SPP
Disconnect from the connected devices.
-
Connecting to Other Devices Using SPP
- Bluetooth GATT operations
-
Managing the Client Operations
Create a client to connect to a remote service, get service details, read and set service attributes, and set and release callbacks when the characteristic value changes.
-
Managing Common Getter Operations
Get information used commonly in client operations.
-
Managing Common Setter Operations
Set the properties and values of attributes.
-
Managing the Client Operations
- Object Push Profile (OPP) operations
-
Exchanging Data Using OPP
Exchange data between devices through OPP.
-
Exchanging Data Using OPP
- Bluetooth LE operations
-
Managing Bluetooth LE Scans
Start the scan, handle the scanning results, and stop the scan.
-
Discovering Bluetooth LE Devices
Discover nearby Bluetooth LE-enabled devices
-
Adding Advertising Data to the LE Advertisement
Add advertising data to an LE advertisement or scan result.
-
Setting the Advertising Connectable Mode
Define whether the advertising type is connectable or non-connectable.
-
Setting the LE Advertising Mode
Control the advertising power and latency.
-
Starting and Stopping Advertising
Start and stop advertising with the advertising parameters.
-
Managing Bluetooth LE Scans
-
Releasing All Resources
Release all resources related to using the Bluetooth connection.
Initializing Bluetooth
To initialize Bluetooth:
-
To use the functions and data types of the Bluetooth API (in mobile and wearable applications), include the <bluetooth.h> header file in your application:
#include <bluetooth.h>
-
Initialize Bluetooth:
#include <dlog.h> bt_error_e ret; ret = bt_initialize(); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_initialize] Failed."); return; }
Enabling and Disabling Bluetooth
To enable or disable Bluetooth:
No Bluetooth API is provided to enable or disable Bluetooth. Use the Bluetooth ON/OFF application illustrated in the following figure (off screen on the left and on screen on the right).
Figure: Bluetooth ON/OFF application
#include <app_control.h> #include <dlog.h> int bt_onoff_operation(void) { int ret = 0; app_control_h service = NULL; app_control_create(&service); if (service == NULL) { dlog_print(DLOG_INFO, LOG_TAG, "service_create failed!\n"); return 0; } app_control_set_operation(service, "http://tizen.org/appcontrol/operation/edit"); app_control_set_mime(service, "application/x-bluetooth-on-off"); ret = app_control_send_launch_request(service, NULL, NULL); app_control_destroy(service); if (ret == APP_CONTROL_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "Succeeded to Bluetooth On/Off app!\n"); return 0; } else { dlog_print(DLOG_INFO, LOG_TAG, "Failed to relaunch Bluetooth On/Off app!\n"); return -1; } return 0; }
Initializing Bluetooth and Checking the Adapter State
To communicate with other devices using Bluetooth, learn how to check the Bluetooth adapter state:
- Check whether the Bluetooth adapter is enabled on your device:
bt_adapter_state_e adapter_state; // Check whether the Bluetooth Service is enabled ret = bt_adapter_get_state(&adapter_state); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_adapter_get_state] Failed"); return; } // If the Bluetooth Service is not enabled if (adapter_state == BT_ADAPTER_DISABLED) { dlog_print(DLOG_ERROR, LOG_TAG, "Bluetooth adapter is not enabled. You should enable Bluetooth!!"); }
Register the Bluetooth state change callback function in order to receive information about Bluetooth state changes.
- Define and register the Bluetooth adapter state callback function to get notified when the Bluetooth adapter has enabled or disabled:
#include <bluetooth.h> #include <dlog.h> bt_error_e ret; void adapter_state_changed_cb(int result, bt_adapter_state_e adapter_state, void* user_data) { if (result != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[adapter_state_changed_cb] Failed! result=%d", result); return; } if (adapter_state == BT_ADAPTER_ENABLED) { dlog_print(DLOG_INFO, LOG_TAG, "[adapter_state_changed_cb] Bluetooth is enabled!"); // Get information about Bluetooth adapter char *local_address = NULL; bt_adapter_get_address(&local_address); dlog_print(DLOG_INFO, LOG_TAG, "[adapter_state_changed_cb] Adapter address: %s.", local_address); if (local_address) free(local_address); char *local_name; bt_adapter_get_name(&local_name); dlog_print(DLOG_INFO, LOG_TAG, "[adapter_state_changed_cb] Adapter name: %s.", local_name); if (local_name) free(local_name); // Visibility mode of the Bluetooth device bt_adapter_visibility_mode_e mode; // Duration until the visibility mode is changed so that other devices cannot find your device int duration = 1; bt_adapter_get_visibility(&mode, &duration); switch (mode) { case BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE: dlog_print(DLOG_INFO, LOG_TAG, "[adapter_state_changed_cb] Visibility: NON_DISCOVERABLE"); break; case BT_ADAPTER_VISIBILITY_MODE_GENERAL_DISCOVERABLE: dlog_print(DLOG_INFO, LOG_TAG, "[adapter_state_changed_cb] Visibility: GENERAL_DISCOVERABLE"); break; case BT_ADAPTER_VISIBILITY_MODE_LIMITED_DISCOVERABLE: dlog_print(DLOG_INFO, LOG_TAG, "[adapter_state_changed_cb] Visibility: LIMITED_DISCOVERABLE"); break; } } else { dlog_print(DLOG_INFO, LOG_TAG, "[adapter_state_changed_cb] Bluetooth is disabled!"); // When you try to get device information // by invoking bt_adapter_get_name(), bt_adapter_get_address(), or bt_adapter_get_visibility(), // BT_ERROR_NOT_ENABLED occurs } } ret = bt_adapter_set_state_changed_cb(adapter_state_changed_cb, NULL); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_adapter_set_state_changed_cb()] Failed."); }
Finding Other Devices
To find remote Bluetooth devices either through device discovery or querying bonded devices:
Defining and Registering the Discovery State Callback Function
Discovering available Bluetooth-enabled devices is the first step to communicating with remote devices. There are 2 types of Bluetooth devices: classic Bluetooth devices and Bluetooth LE devices. Both device types use their own APIs to discover devices of the same type.
Define a callback with the following function signature to get information about a specific device type:
typedef void (*bt_adapter_device_discovery_state_changed_cb)(int result, bt_adapter_device_discovery_state_e discovery_state, bt_adapter_device_discovery_info_s *discovery_info, void *user_data); typedef void (*bt_adapter_le_device_discovery_state_changed_cb)(int result, bt_adapter_le_device_discovery_state_e discovery_state, bt_adapter_le_device_discovery_info_s *discovery_info, void *user_data);
The first parameter, result, specifies the result of the bt_adapter_start_device_discover() or bt_adapter_stop_device_discovery() function in classic Bluetooth, or the bt_adapter_le_start_discover_device() or bt_adapter_le_stop_device_discovery() function in Bluetooth LE.
This discovery start functions for the 2 types are declared as follows:
// Classic Bluetooth int bt_adapter_start_device_discovery(void); int bt_adapter_stop_device_discovery(void); // Bluetooth LE int bt_adapter_le_start_device_discovery(void); int bt_adapter_le_stop_device_discovery(void);
If discovering Bluetooth succeeds, you receive the BT_ERROR_NONE result as the first parameter in your bt_adapter_device_discovery_state_changed_cb() (classic Bluetooth) or bt_adapter_le_device_discovery_state_changed_cb() (Bluetooth LE) callback function. If your device did not start to discover devices due to an error, the result code is BT_ERROR_TIMEOUT.
If stopping the discovery succeeds, you can also receive BT_ERROR_CANCELLED.
The values in bt_adapter_device_discovery_state_e (classic Bluetooth) or bt_adapter_le_device_discovery_state_e (Bluetooth LE) are as follows:
Discovery state | Description |
---|---|
BT_ADAPTER_DEVICE_DISCOVERY_STARTED | When discovery is started |
BT_ADAPTER_DEVICE_DISCOVERY_FINISHED | When discovery is finished |
BT_ADAPTER_DEVICE_DISCOVERY_FOUND | When a device is found |
BT_ADAPTER_LE_DEVICE_DISCOVERY_STARTED | When LE discovery is started |
BT_ADAPTER_LE_DEVICE_DISCOVERY_FINISHED | When LE discovery is finished |
BT_ADAPTER_LE_DEVICE_DISCOVERY_FOUND | When an LE device is found |
When your implemented callback function is first called, the second parameter, discovery_state, is BT_ADAPTER_DEVICE_DISCOVERY_STARTED or BT_ADAPTER_LE_DEVICE_DISCOVERY_STARTED. This indicates that device discovery has begun.
Each time you find a remote Bluetooth device, discovery_state is in the BT_ADAPTER_DEVICE_DISCOVERY_FOUND or BT_ADAPTER_LE_DEVICE_DISCOVERY_FOUND state.
At the BT_ADAPTER_DEVICE_DISCOVERY_FOUND or BT_ADAPTER_LE_DEVICE_DISCOVERY_FOUND state, you can get some information about a discovered device, such as the device MAC address, name, class, rssi (received signal strength indicator), and bonding state. Using this information, you can connect to the discovered device.
discovery_info is a NULL value in the BT_ADAPTER_DEVICE_DISCOVERY_STARTED, BT_ADAPTER_LE_DEVICE_DISCOVERY_STARTED, BT_ADAPTER_DEVICE_DISCOVERY_FINISHED, or BT_ADAPTER_LE_DEVICE_DISCOVERY_FINISHED state.
An example implementation for classic Bluetooth (Bluetooth LE usage is the same):
#include <glib.h> // For GList void adapter_device_discovery_state_changed_cb(int result, bt_adapter_device_discovery_state_e discovery_state, bt_adapter_device_discovery_info_s *discovery_info, void* user_data) { if (result != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[adapter_device_discovery_state_changed_cb] Failed! result(%d).", result); return; } GList** searched_device_list = (GList**)user_data; switch (discovery_state) { case BT_ADAPTER_DEVICE_DISCOVERY_STARTED: dlog_print(DLOG_INFO, LOG_TAG, "BT_ADAPTER_DEVICE_DISCOVERY_STARTED"); break; case BT_ADAPTER_DEVICE_DISCOVERY_FINISHED: dlog_print(DLOG_INFO, LOG_TAG, "BT_ADAPTER_DEVICE_DISCOVERY_FINISHED"); break; case BT_ADAPTER_DEVICE_DISCOVERY_FOUND: dlog_print(DLOG_INFO, LOG_TAG, "BT_ADAPTER_DEVICE_DISCOVERY_FOUND"); if (discovery_info != NULL) { dlog_print(DLOG_INFO, LOG_TAG, "Device Address: %s", discovery_info->remote_address); dlog_print(DLOG_INFO, LOG_TAG, "Device Name is: %s", discovery_info->remote_name); bt_adapter_device_discovery_info_s * new_device_info = malloc(sizeof(bt_adapter_device_discovery_info_s)); if (new_device_info != NULL) { memcpy(new_device_info, discovery_info, sizeof(bt_adapter_device_discovery_info_s)); new_device_info->remote_address = strdup(discovery_info->remote_address); new_device_info->remote_name = strdup(discovery_info->remote_name); *searched_device_list = g_list_append(*searched_device_list, (gpointer)new_device_info); } } break; } }
Register the callback for classic Bluetooth (Bluetooth LE usage is the same):
GList *devices_list = NULL; ret = bt_adapter_set_device_discovery_state_changed_cb( adapter_device_discovery_state_changed_cb, (void*)&devices_list); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_adapter_set_device_discovery_state_changed_cb] Failed."); }
Finding Other Bluetooth Devices
If you want to stop the device discovery, call bt_adapter_stop_device_discovery() (classic Bluetooth) or bt_adapter_le_stop_device_discovery() (Bluetooth LE).
A remote Bluetooth device responds to the request if it is enabled and in a discovery mode. Classic Bluetooth and Bluetooth LE usages are the same.
// Classic Bluetooth ret = bt_adapter_start_device_discovery(); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_adapter_start_device_discovery] Failed."); }
Enabling Discovery
For other devices to find your device, your device must be discoverable.
To check the current visibility of your device, do the following:
// Visibility mode of the Bluetooth device bt_adapter_visibility_mode_e mode; // Duration until the visibility mode is changed so that other devices cannot find your device int duration = 1; bt_adapter_get_visibility(&mode, &duration); if (mode == BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE) { dlog_print(DLOG_INFO, LOG_TAG, "The device is not discoverable."); } else if (mode == BT_ADAPTER_VISIBILITY_MODE_GENERAL_DISCOVERABLE) { dlog_print(DLOG_INFO, LOG_TAG, "The device is discoverable. No time limit."); } else { dlog_print(DLOG_INFO, LOG_TAG, "The device is discoverable for a set period of time."); }
To change the visibility mode, use the Bluetooth visibility setting application (shown below with the initial screen on the left and the visibility setting screen on the right).
Figure: Bluetooth visibility setting application
#include <app_control.h> #include <dlog.h> int bt_set_visibility_operation(void) { int ret = 0; app_control_h service = NULL; app_control_create(&service); if (service == NULL) { dlog_print(DLOG_INFO, LOG_TAG, "service_create failed!\n"); return 0; } app_control_set_operation(service, "http://tizen.org/appcontrol/operation/edit"); app_control_set_mime(service, "application/x-bluetooth-visibility"); ret = app_control_send_launch_request(service, NULL, NULL); app_control_destroy(service); if (ret == APP_CONTROL_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "Succeeded to Bluetooth On/Off app!\n"); return 0; } else { dlog_print(DLOG_INFO, LOG_TAG, "Failed to relaunch Bluetooth On/Off app!\n"); return -1; } return 0; }
If you want to get a notification when the visibility is changed after 90 seconds, you must implement the following callback and register it.
typedef void(* bt_adapter_visibility_mode_changed_cb)(int result, bt_adapter_visibility_mode_e visibility_mode, void *user_data)
An example implementation:
void adapter_visibility_mode_changed_cb(int result, bt_adapter_visibility_mode_e visibility_mode, void* user_data) { if (result != BT_ERROR_NONE) { // Error handling return; } if (visibility_mode == BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE) { dlog_print(DLOG_INFO, LOG_TAG, "[visibility_mode_changed_cb] None discoverable mode!"); } else if (visibility_mode == BT_ADAPTER_VISIBILITY_MODE_GENERAL_DISCOVERABLE) { dlog_print(DLOG_INFO, LOG_TAG, "[visibility_mode_changed_cb] General discoverable mode!"); } else { dlog_print(DLOG_INFO, LOG_TAG, "[visibility_mode_changed_cb] Limited discoverable mode!"); } }
Register the callback:
ret = bt_adapter_set_visibility_mode_changed_cb(adapter_visibility_mode_changed_cb, NULL); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_adapter_set_visibility_mode_changed_cb] Failed."); }
Querying Bonded Devices
Before trying to find the remote devices nearby, you can query the list of bonded devices to get the basic information (such as device address and name) your device has stored for the bonded devices. In order to get all bonded devices, call bt_adapter_foreach_bonded_device(). You can get information about bonded devices in bt_adapter_bonded_device_cb(), which you need to call for each bonded device.
bt_adapter_foreach_bonded_device() is declared as follows:
int bt_adapter_foreach_bonded_device(bt_adapter_bonded_device_cb foreach_cb, void *user_data)
The callback function is declared as follows:
typedef bool(* bt_adapter_bonded_device_cb)(bt_device_info_s *device_info, void *user_data)
You can get information (such as the device name, service list, and Mac address) about the bonded device.
To continue performing iterations, your implemented callback function must return true. Otherwise, it returns false and stops performing additional iterations.
The following code sample describes how to query bonded devices and how to discover a desired device.
// Server address for connecting char *bt_server_address = NULL; const char *remote_server_name = "server device"; bool adapter_bonded_device_cb(bt_device_info_s *device_info, void *user_data) { if (device_info == NULL) { return true; } if (!strcmp(device_info->remote_name, (char*)user_data)) { dlog_print(DLOG_INFO, LOG_TAG, "The server device is found in bonded device list. address(%s)", device_info->remote_address); bt_server_address = strdup(device_info->remote_address); // If you want to stop iterating, you can return "false" } // Get information about bonded device int count_of_bonded_device = 1; dlog_print(DLOG_INFO, LOG_TAG, "Get information about the bonded device(%d)", count_of_bonded_device); dlog_print(DLOG_INFO, LOG_TAG, "remote address = %s.", device_info->remote_address); dlog_print(DLOG_INFO, LOG_TAG, "remote name = %s.", device_info->remote_name); dlog_print(DLOG_INFO, LOG_TAG, "service count = %d.", device_info->service_count); dlog_print(DLOG_INFO, LOG_TAG, "bonded?? %d.", device_info->is_bonded); dlog_print(DLOG_INFO, LOG_TAG, "connected?? %d.", device_info->is_connected); dlog_print(DLOG_INFO, LOG_TAG, "authorized?? %d.", device_info->is_authorized); dlog_print(DLOG_INFO, LOG_TAG, "major_device_class %d.", device_info->bt_class.major_device_class); dlog_print(DLOG_INFO, LOG_TAG, "minor_device_class %d.", device_info->bt_class.minor_device_class); dlog_print(DLOG_INFO, LOG_TAG, "major_service_class_mask %d.", device_info->bt_class.major_service_class_mask); count_of_bonded_device++; // Keep iterating return true; } ret = bt_adapter_foreach_bonded_device(adapter_bonded_device_cb, remote_server_name); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_adapter_foreach_bonded_device] Failed!"); } if (bt_server_address != NULL) free(bt_server_address);
Requesting Bonding with a Remote Bluetooth Device
You already got information about a remote device through device discovery or querying a bonded device. You can request to bond with that device using the bt_device_create_bond() function. If you want to cancel bonding, call bt_device_cancel_bonding().
To get notified when the bonding has finished, register a bt_device_bond_created_cb() callback function using the bt_device_set_bond_created_cb() function. From this callback, you can get the service list that the remote Bluetooth device provides and the service UUID from that service list.
The example below shows how to implement a bt_device_bond_created_cb() callback function and bond with a remote Bluetooth device.
void device_bond_created_cb(int result, bt_device_info_s *device_info, void *user_data) { if (result != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_device_bond_created_cb] Failed. result(%d).", result); return; } if (device_info != NULL && !strcmp(device_info->remote_address, remote_server_address)) { dlog_print(DLOG_INFO, LOG_TAG, "Callback: A bond with chat_server is created."); dlog_print(DLOG_INFO, LOG_TAG, "Callback: The number of service - %d.", device_info->service_count); int i = 0; dlog_print(DLOG_INFO, LOG_TAG, "Callback: is_bonded - %d.", device_info->is_bonded); dlog_print(DLOG_INFO, LOG_TAG, "Callback: is_connected - %d.", device_info->is_connected); } else { dlog_print(DLOG_ERROR, LOG_TAG, "Callback: A bond with another device is created."); } } // You can get bt_server_address from bt_adapter_bonded_device_cb() or bt_device_service_searched_cb() // device_info->remote_address in bt_adapter_bonded_device_cb() // sdp_info->remote_address in bt_device_service_searched_cb() ret = bt_device_set_bond_created_cb(device_bond_created_cb, bt_server_address); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_device_set_bond_created_cb] failed."); return; } ret = bt_device_create_bond(bt_server_address); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_device_create_bond] failed."); return; } else { dlog_print(DLOG_INFO, LOG_TAG, "[bt_device_create_bond] succeeded. device_bond_created_cb callback will be called."); }
After that, the remote device is included in the bonded device list. So next time you do not need to find it again. Without finding, you can get information (such as address and name) by querying the bonded device.
You can verify the bonding by calling the bt_adapter_foreach_bonded_device() function.
If you want to remove the device from the bonded list, call the bt_device_destroy_bond() function.
Connecting to Other Devices Using SPP
To connect to other devices:
Connecting as a Server
If you want your device to work as a server, establish a connection using an RFCOMM socket.
To establish a connection, create a RFCOMM Bluetooth socket using the bt_socket_create_rfcomm() function. It has the following signature:
int bt_socket_create_rfcomm(const char *port_uuid, int *socket_fd)
The first parameter, port_uuid, uniquely identifies which service to provide. It is the UUID of the service. This UUID must match for the connection to be accepted. The second parameter, socket_fd, is the RFCOMM socket ID as an output parameter.
The example below shows how to make an rfcomm socket with the Bluetooth API.
const char* my_uuid="00001101-0000-1000-8000-00805F9B34FB"; int server_socket_fd = -1; bt_error_e ret; ret = bt_socket_create_rfcomm(my_uuid, &server_socket_fd); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "bt_socket_create_rfcomm() failed."); }
To listen for an incoming connection, call the bt_socket_listen_and_accept_rfcomm() function.
This function is declared as follows:
int bt_socket_listen_and_accept_rfcomm(int socket_fd, int max_pending_connections)
- int socket_fd: socket fd passed from bt_socket_create_rfcomm(), which starts listening
- int max_pending_connections: maximum number of pending connections that a Bluetooth server can store
You can be notified about which device connects to your device by using the bt_socket_connection_state_changed_cb() function.
The callback function is declared as follows:
typedef void (* bt_socket_connection_state_changed_cb) (int result, bt_socket_connection_state_e connection_state, bt_socket_connection_s *connection, void *user_data)
The first parameter, result, is the change in the connection state. The second parameter, connection_state, is the connection state, itself, either BT_SOCKET_CONNECTED or BT_SOCKET_DISCONNECTED. The third parameter is the pointer to the structure bt_socket_connection_s, which can specify an RFCOMM Bluetooth socket. The bt_socket_connection_s structure contains socket_fd, role (client or server), and the opposite Bluetooth device's MAC address. The fourth parameter, user_data, is user-defined data.
The example below shows how to implement a callback function and start listening for Bluetooth client devices.
void socket_connection_state_changed(int result, bt_socket_connection_state_e connection_state, bt_socket_connection_s *connection, void *user_data) { if (result != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[socket_connection_state_changed_cb] Failed. result =%d.", result); return; } if (connection_state == BT_SOCKET_CONNECTED) { dlog_print(DLOG_INFO, LOG_TAG, "Callback: Connected."); if (connection != NULL) { dlog_print(DLOG_INFO, LOG_TAG, "Callback: Socket of connection - %d.", connection->socket_fd); dlog_print(DLOG_INFO, LOG_TAG, "Callback: Role of connection - %d.", connection->local_role); dlog_print(DLOG_INFO, LOG_TAG, "Callback: Address of connection - %s.", connection->remote_address); // socket_fd is used for sending data and disconnecting a device server_socket_fd = connection->socket_fd; } else { dlog_print(DLOG_INFO, LOG_TAG, "Callback: No connection data"); } } else { dlog_print(DLOG_INFO, LOG_TAG, "Callback: Disconnected."); if (connection != NULL) { dlog_print(DLOG_INFO, LOG_TAG, "Callback: Socket of disconnection - %d.", connection->socket_fd); dlog_print(DLOG_INFO, LOG_TAG, "Callback: Address of connection - %s.", connection->remote_address); } else { dlog_print(DLOG_INFO, LOG_TAG, "Callback: No connection data"); } } } bt_error_e ret; ret = bt_socket_set_connection_state_changed_cb(socket_connection_state_changed, NULL); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_socket_set_connection_state_changed_cb] failed."); return; } ret = bt_socket_listen_and_accept_rfcomm(server_socket_fd, 5); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_socket_listen_and_accept_rfcomm] failed."); return; } else { dlog_print(DLOG_INFO, LOG_TAG, "[bt_socket_listen_and_accept_rfcomm] Succeeded. bt_socket_connection_state_changed_cb will be called."); // Waiting for incoming connections }
If you do not want to accept any other connections or provide a service, call the bt_socket_destroy_rfcomm() function.
Connecting as a Client
Set up the bt_socket_connection_state_changed_cb() function that is called when your device is connected to a Bluetooth server device.
Note |
---|
When you connect to a Bluetooth server device, keep the server socket fd from bt_socket_connection_s->socket_fd in bt_socket_connection_state_changed_cb(). |
Request a connection to the Bluetooth server. The server socket fd is used when you send data or disconnect.
bt_socket_connect_rfcomm (const char *remote_address, const char *remote_port_uuid)
The first parameter, remote_address, is the address of the remote device. You can get this from the bt_device_info_s structure.
The second parameter, remote_port_uuid, is the UUID for the specific RFCOMM-based service on a remote device.
This remote_port_uuid must match the UUID used by the server device in the bt_socket_create_rfcomm() function.
The example below shows how to connect to a specific RFCOMM-based service on a remote device.
const char *service_uuid="00001101-0000-1000-8000-00805F9B34FB"; ret = bt_socket_set_connection_state_changed_cb(socket_connection_state_changed, NULL); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_socket_set_connection_state_changed_cb] failed."); return; } ret = bt_socket_connect_rfcomm(bt_server_address, service_uuid); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_socket_connect_rfcomm] failed."); return; } else { dlog_print(DLOG_INFO, LOG_TAG, "[bt_socket_connect_rfcomm] Succeeded. bt_socket_connection_state_changed_cb will be called."); }
Exchanging Data Using SPP
To share data between devices after establishing a connection:
-
To write data, use the bt_socket_send_data() function.
This function is declared as follows:
int bt_socket_send_data(int socket_fd, const char *data, int length)
The first parameter, socket_fd, is the socket ID from the bt_socket_connection_state_changed_cb() function. The second parameter, data, is the data to write. The third parameter, length, is the data length.
-
To read data from other devices, you must set up the bt_socket_data_received_cb() callback that is invoked when your device receives data from other Bluetooth devices.
To register a bt_socket_data_received_cb() callback function, call the bt_socket_set_data_received_cb() function. The callback function is declared as follows:
typedef void bt_socket_data_received_cb(bt_socket_received_data_s* data, void* user_data)
The first parameter, data, is the pointer to the structure bt_socket_received_data_s that can specify received data, data size, and socket fd. The second parameter, user_data, is user data. This callback is called whenever your device receives data from other Bluetooth devices. You can read the data in the callback.
bt_error_e ret; char data[] = "Sending test"; int client_socket_fd = 0; void bt_socket_data_received_cb(bt_socket_received_data_s* data, void* user_data) { if (data == NULL) { dlog_print(DLOG_INFO, LOG_TAG, "No received data!"); return; } dlog_print(DLOG_INFO, LOG_TAG, "Socket fd: %d", data->socket_fd); dlog_print(DLOG_INFO, LOG_TAG, "Data: %s", data->data); dlog_print(DLOG_INFO, LOG_TAG, "Size: %d", data->data_size); } ret = bt_socket_set_data_received_cb(bt_socket_data_received_cb, NULL); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_socket_data_received_cb] regist to fail."); } ret = bt_socket_send_data(client_socket_fd, data, sizeof(data)); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_socket_send_data] failed."); }
Disconnecting from the Connected Device Using SPP
To disconnect from a device, call the bt_socket_destroy_rfcomm() or bt_socket_disconnect_rfcomm() function:
- Disconnect the Bluetooth server:
bt_error_e ret; // You can get "server_socket_fd" from output of bt_socket_create_rfcomm() ret = bt_socket_destroy_rfcomm(server_socket_fd); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_socket_destroy_rfcomm] Failed."); } else { dlog_print(DLOG_INFO, LOG_TAG, "[bt_socket_destroy_rfcomm] Succeeded. socket_fd = %d", server_socket_fd); }
- Disconnect the Bluetooth client:
bt_error_e ret; // You can get "server_socket_fd" from bt_socket_connection_state_changed_cb() ret = bt_socket_disconnect_rfcomm(server_socket_fd); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_socket_destroy_rfcomm] Failed. server_socket_fd = %d.", server_socket_fd); } else { dlog_print(DLOG_INFO, LOG_TAG, "[bt_socket_destroy_rfcomm] Succeeded. server_socket_fd = %d.", server_socket_fd); }
Managing the Client Operations
To perform GATT client operations:
- Register a callback for connection state changes:
int ret = 0; // Register for GATT connection callback void __bt_gatt_connection_state_changed_cb(int result, bool connected, const char *remote_address, void *user_data) { if (connected) dlog_print(DLOG_INFO, LOG_TAG, "LE connected"); else dlog_print(DLOG_INFO, LOG_TAG, "LE disconnected"); } ret = bt_gatt_set_connection_state_changed_cb(__bt_gatt_connection_state_changed_cb, NULL);
- Create a client to connect to the remote service device:
int ret = 0; ret = bt_gatt_client_create(remote_addr, &client); if (ret == BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "Success"); break;
- Unregister the callback registered for connection state changes:
int ret = 0; // Unregister for GATT connection callback ret = bt_gatt_unset_connection_state_changed_cb();
- Destroy the client created to connect to the remote service device:
int ret = 0; ret = bt_gatt_client_destroy(client); if (ret == BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "Success"); break;
- Get the address of the remote device:
int ret = 0; char *addr = NULL; ret = bt_gatt_client_get_remote_address(client, &addr); if (ret == BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "Success"); break;
- Discover the service, characteristics, and descriptors of the remote service:
- Discover the service:
int ret = 0; ret = bt_gatt_client_foreach_services(client, __bt_gatt_client_foreach_svc_cb, (void *)test_id); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "fail"); } break;
- Use the bt_gatt_client_foreach_svc_cb() callback to initiate the service characteristics discovery:
bool __bt_gatt_client_foreach_svc_cb(int total, int index, bt_gatt_h svc_handle, void *data) { int test_id = (int)data; int ret; char *uuid = NULL; bt_gatt_get_uuid(svc_handle, &uuid); dlog_print(DLOG_INFO, LOG_TAG, "[%d / %d] (%s)", index, total, uuid); g_free(uuid); if (test_id == BT_UNIT_TEST_FUNCTION_GATT_CLIENT_PRINT_ALL) { ret = bt_gatt_service_foreach_characteristics(svc_handle, __bt_gatt_client_foreach_chr_cb, (void *)test_id); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_service_foreach_characteristics is failed : %d", ret); } return true; } }
- Use the bt_gatt_client_foreach_chr_cb() callback to discover the characteristic descriptors:
bool __bt_gatt_client_foreach_chr_cb(int total, int index, bt_gatt_h chr_handle, void *data) { int ret; char *uuid = NULL; bt_gatt_get_uuid(chr_handle, &uuid); dlog_print(DLOG_INFO, LOG_TAG, "\t[%d / %d] (%s)", index, total, uuid); __bt_gatt_client_print_value(chr_handle); g_free(uuid); ret = bt_gatt_characteristic_foreach_descriptors(chr_handle, __bt_gatt_client_foreach_desc_cb, NULL); if (ret != BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_characteristic_foreach_descriptors is failed : %d", ret); return true; }
- Use the bt_gatt_client_foreach_desc_cb() callback to get the descriptor data:
bool __bt_gatt_client_foreach_desc_cb(int total, int index, bt_gatt_h desc_handle, void *data) { char *uuid = NULL; bt_gatt_get_uuid(desc_handle, &uuid); dlog_print(DLOG_INFO, LOG_TAG, "\t\t[%d / %d] (%s)", index, total, uuid); __bt_gatt_client_print_value(desc_handle); g_free(uuid); return true; }
- Discover the service:
- Read the value of the given attribute handle:
{ char *svc_uuid = NULL; char *chr_uuid = NULL; char *desc_uuid = NULL; bt_gatt_h svc = NULL; bt_gatt_h chr = NULL; bt_gatt_h desc = NULL; if (g_test_param.param_count < 2) { dlog_print(DLOG_INFO, LOG_TAG, "Input parameters first"); break; } svc_uuid = g_test_param.params[0]; chr_uuid = g_test_param.params[1]; ret = bt_gatt_client_get_service(client, svc_uuid, &svc); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_client_get_service is failed : %d", ret); __bt_free_test_param(&g_test_param); break; } ret = bt_gatt_service_get_characteristic(svc, chr_uuid, &chr); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_service_get_characteristic is failed : %d", ret); __bt_free_test_param(&g_test_param); break; } if (g_test_param.param_count > 2) { desc_uuid = g_test_param.params[2]; ret = bt_gatt_characteristic_get_descriptor(chr, desc_uuid, &desc); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_characteristic_get_descriptor is failed : %d", ret); __bt_free_test_param(&g_test_param); break; } ret = bt_gatt_client_read_value(desc, __bt_gatt_client_read_complete_cb, NULL); } else { ret = bt_gatt_client_read_value(chr, __bt_gatt_client_read_complete_cb, NULL); } if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_client_read_value is failed : %d", ret); } __bt_free_test_param(&g_test_param); }
After the reading operation is complete, use the bt_gatt_client_read_complete_cb() callback to handle values:
void __bt_gatt_client_read_complete_cb(int result, bt_gatt_h gatt_handle, void *data) { char *uuid = NULL; bt_gatt_get_uuid(gatt_handle, &uuid); dlog_print(DLOG_INFO, LOG_TAG, "Read %s for (%s)", result == BT_ERROR_NONE ? "Success" : "Fail", uuid); g_free(uuid); if (result != BT_ERROR_NONE) return; __bt_gatt_client_print_value(gatt_handle); return; }
- Set a value for the given attribute handle:
{ char *svc_uuid = NULL; char *chr_uuid = NULL; char *desc_uuid = NULL; bt_gatt_h svc = NULL; bt_gatt_h chr = NULL; bt_gatt_h desc = NULL; if (g_test_param.param_count < 2) { dlog_print(DLOG_INFO, LOG_TAG, "Input parameters first"); break; } svc_uuid = g_test_param.params[0]; chr_uuid = g_test_param.params[1]; ret = bt_gatt_client_get_service(client, svc_uuid, &svc); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_client_get_service is failed : %d", ret); __bt_free_test_param(&g_test_param); break; } ret = bt_gatt_service_get_characteristic(svc, chr_uuid, &chr); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_service_get_characteristic is failed : %d", ret); __bt_free_test_param(&g_test_param); break; } if (g_test_param.param_count > 2) { desc_uuid = g_test_param.params[2]; ret = bt_gatt_characteristic_get_descriptor(chr, desc_uuid, &desc); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_characteristic_get_descriptor is failed : %d", ret); __bt_free_test_param(&g_test_param); break; } ret = __bt_gatt_client_set_value(g_test_param.params[3], g_test_param.params[4], desc); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_set_value is failed : %d", ret); __bt_free_test_param(&g_test_param); break; } ret = bt_gatt_client_write_value(desc, __bt_gatt_client_write_complete_cb, NULL); } else { ret = __bt_gatt_client_set_value(g_test_param.params[2], g_test_param.params[3], chr); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_set_value is failed : %d", ret); __bt_free_test_param(&g_test_param); break; } ret = bt_gatt_client_write_value(chr, __bt_gatt_client_write_complete_cb, NULL); } if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_client_write_value is failed : %d", ret); } __bt_free_test_param(&g_test_param); }
After the writing operation is complete, use the bt_gatt_client_write_complete_cb() callback to finish the task:
void __bt_gatt_client_write_complete_cb(int result, bt_gatt_h gatt_handle, void *data) { char *uuid = NULL; bt_gatt_get_uuid(gatt_handle, &uuid); dlog_print(DLOG_INFO, LOG_TAG, "Write %s for (%s)", result == BT_ERROR_NONE ? "Success" : "Fail", uuid); g_free(uuid); return; }
- Register a callback function to be invoked when the characteristic value changes on the remote device:
{ char *svc_uuid = NULL; char *chr_uuid = NULL; bt_gatt_h svc = NULL; bt_gatt_h chr = NULL; if (g_test_param.param_count < 2) { dlog_print(DLOG_INFO, LOG_TAG, "Input parameters first"); break; } svc_uuid = g_test_param.params[0]; chr_uuid = g_test_param.params[1]; ret = bt_gatt_client_get_service(client, svc_uuid, &svc); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_client_get_service is failed : %d", ret); __bt_free_test_param(&g_test_param); break; } ret = bt_gatt_service_get_characteristic(svc, chr_uuid, &chr); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_service_get_characteristic is failed : %d", ret); __bt_free_test_param(&g_test_param); break; } ret = bt_gatt_client_set_characteristic_value_changed_cb(chr, __bt_gatt_client_value_changed_cb, NULL); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_client_set_characteristic_value_changed_cb is failed : %d", ret); __bt_free_test_param(&g_test_param); } }
After registering the callback operation, use the __bt_gatt_client_value_changed_cb() callback to display the changed value:
void __bt_gatt_client_value_changed_cb(bt_gatt_h chr, char *value, int len, void *user_data) { char *uuid = NULL; int i; bt_gatt_get_uuid(chr, &uuid); dlog_print(DLOG_INFO, LOG_TAG, "Value changed for [%s]", uuid); dlog_print(DLOG_INFO, LOG_TAG, "len [%d]", len); for (i = 0; i < len; i++) { dlog_print(DLOG_INFO, LOG_TAG, "value %u", value[i]); } g_free(uuid); return; }
- Unregister the callback for characteristic value changes. Afterwards, you are not notified of the value changes.
{ char *svc_uuid = NULL; char *chr_uuid = NULL; bt_gatt_h svc = NULL; bt_gatt_h chr = NULL; if (g_test_param.param_count < 2) { dlog_print(DLOG_INFO, LOG_TAG, "Input parameters first"); break; } svc_uuid = g_test_param.params[0]; chr_uuid = g_test_param.params[1]; ret = bt_gatt_client_get_service(client, svc_uuid, &svc); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_client_get_service is failed : %d", ret); __bt_free_test_param(&g_test_param); break; } ret = bt_gatt_service_get_characteristic(svc, chr_uuid, &chr); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_service_get_characteristic is failed : %d", ret); __bt_free_test_param(&g_test_param); break; } ret = bt_gatt_client_unset_characteristic_value_changed_cb(chr); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_client_unset_characteristic_value_changed_cb is failed : %d", ret); __bt_free_test_param(&g_test_param); } }
- When you no longer need the client, disconnect from the remote service and destroy the client:
int ret = 0; ret = bt_gatt_client_destroy(client); if (ret == BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "Success"); client = NULL; break;
Managing Common Getter Operations
To perform getter operations for client-related information:
- Get the type of a service, characteristic, or descriptor handle:
{ int ret = 0; bt_gatt_h gatt_handle = NULL; bt_gatt_type_e gatt_type; // Handle is already created for service ret = bt_gatt_get_type(gatt_handle, &gatt_type); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_get_type is failed : %d", ret); } }
- Get the UUID of a service, characteristic, or descriptor handle:
{ int ret = 0; bt_gatt_h gatt_handle = NULL; char *uuid = NULL; // Handle is already created for service ret = bt_gatt_get_uuid(gatt_handle, &uuid); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_get_uuid is failed : %d", ret); } }
- Get the value of a characteristic or descriptor handle:
{ int ret = 0; int len = 0; bt_gatt_h gatt_handle = NULL; char *value = NULL; // Handle is already created for descriptor ret = bt_gatt_get_value(gatt_handle, &value, &len); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_get_value is failed : %d", ret); } }
- Get the value of a characteristic or descriptor handle as an integer type:
{ int ret = 0; int offset = 0; bt_data_type_int_e type,; bt_gatt_h gatt_handle = NULL; int value; // Assuming all the input parameters (gatt_handle, type, and offset) are available ret = bt_gatt_get_int_value(gatt_handle, type, offset, &value); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_get_int_value is failed : %d", ret); } }
- Get the value of a characteristic or descriptor handle as a float type:
{ int ret = 0; int offset = 0; bt_data_type_float_e type,; bt_gatt_h gatt_handle = NULL; float value; // Assuming all the input parameters (gatt_handle, type, and offset) are available ret = bt_gatt_get_float_value(gatt_handle, type, offset, &value); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_get_float_value is failed : %d", ret); } }
- Get a service handle with a specific UUID:
{ char *svc_uuid = NULL; bt_gatt_h svc = NULL; if (g_test_param.param_count < 2) { dlog_print(DLOG_INFO, LOG_TAG, "Input parameters first"); break; } svc_uuid = g_test_param.params[0]; ret = bt_gatt_client_get_service(client, svc_uuid, &svc); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_client_get_service is failed : %d", ret); __bt_free_test_param(&g_test_param); } }
- Get a characteristic handle with a specific UUID:
{ char *svc_uuid = NULL; char *chr_uuid = NULL; bt_gatt_h svc = NULL; bt_gatt_h chr = NULL; if (g_test_param.param_count < 2) { dlog_print(DLOG_INFO, LOG_TAG, "Input parameters first"); break; } svc_uuid = g_test_param.params[0]; chr_uuid = g_test_param.params[1]; ret = bt_gatt_client_get_service(client, svc_uuid, &svc); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_client_get_service is failed : %d", ret); __bt_free_test_param(&g_test_param); break; } ret = bt_gatt_service_get_characteristic(svc, chr_uuid, &chr); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_service_get_characteristic is failed : %d", ret); __bt_free_test_param(&g_test_param); } }
- Get a descriptor handle with a specific UUID:
{ char *svc_uuid = NULL; char *chr_uuid = NULL; char *desc_uuid = NULL; bt_gatt_h svc = NULL; bt_gatt_h chr = NULL; bt_gatt_h desc = NULL; if (g_test_param.param_count < 2) { dlog_print(DLOG_INFO, LOG_TAG, "Input parameters first"); break; } svc_uuid = g_test_param.params[0]; chr_uuid = g_test_param.params[1]; ret = bt_gatt_client_get_service(client, svc_uuid, &svc); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_client_get_service is failed : %d", ret); __bt_free_test_param(&g_test_param); break; } ret = bt_gatt_service_get_characteristic(svc, chr_uuid, &chr); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_service_get_characteristic is failed : %d", ret); __bt_free_test_param(&g_test_param); break; } if (g_test_param.param_count > 2) { desc_uuid = g_test_param.params[2]; ret = bt_gatt_characteristic_get_descriptor(chr, desc_uuid, &desc); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_characteristic_get_descriptor is failed : %d", ret); __bt_free_test_param(&g_test_param); } }
- Get the properties using the characteristic handle:
{ bt_gatt_h chr = NULL; int properties; // Get the characteristic handle using bt_gatt_service_get_characteristic() ret = bt_gatt_characteristic_get_properties(chr, &properties); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_characteristic_get_properties is failed : %d", ret); } }
- Get the service handle to which the specified characteristic belongs:
{ bt_gatt_h svc = NULL; bt_gatt_h chr = NULL; // chr = Assuming characteristic handle is already available ret = bt_gatt_characteristic_get_service(chr, &svc); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_characteristic_get_service is failed : %d", ret); } }
- Get the characteristic handle to which the specified descriptor belongs:
{ bt_gatt_h chr = NULL; bt_gatt_h dsc = NULL; // dsc = Assuming descriptor handle is already available ret = bt_gatt_descriptor_get_characteristic(des, &chr); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_descriptor_get_characteristic is failed : %d", ret); } }
- Get the client handle to which the specified service belongs:
{ bt_gatt_h svc = NULL; bt_gatt_client_h client = NULL; // svc = Assuming service handle is already available ret = bt_gatt_service_get_client(svc, &client); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_service_get_client is failed : %d", ret); } }
- Get the write type of the specified characteristic:
{ bt_gatt_h chr = NULL; bt_gatt_write_type_e write_type = NULL; // svc = Assuming characteristic handle is already available ret = bt_gatt_characteristic_get_write_type(chr, &write_type); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_characteristic_get_write_type is failed : %d", ret); } }
- Get an included service's handle with a specific UUID:
{ bt_gatt_h svc = NULL; bt_gatt_h included_svc = NULL; char *uuid = NULL; bt_gatt_write_type_e write_type = NULL; // svc = Assuming service handle and UUID are already available ret = bt_gatt_service_get_included_service(svc, uuid, &included_svc); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_INFO, LOG_TAG, "bt_gatt_service_get_included_service is failed : %d", ret); } }
Managing Common Setter Operations
The setter operations are common for both the server and client roles.
To set the properties and values of attributes:
- Set or update the characteristic value (unit8 or char type value):
int ret = 0; char char_value[1] = {1 + (rand()%100)}; // For client, the characteristic handle is retrieved from the client created using gatt_client_create() // by using bt_gatt_service_get_characteristic() ret = bt_gatt_set_value(characteristic_handle, char_value, 1); if (ret == BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "Success");
- Set or update the characteristic value (integer type value):
int ret = 0; int char_value = 60 + (rand()%60); // For client, the characteristic handle is retrieved from the client created using gatt_client_create() // by using bt_gatt_service_get_characteristic() ret = bt_gatt_set_int_value(characteristic_handle, BT_DATA_TYPE_UINT16, char_value, 1); if (ret == BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "Success");
- Set or update the characteristic value (float type value):
int ret = 0; // For client, the characteristic handle is retrieved from the client created using gatt_client_create() // by using bt_gatt_service_get_characteristic() // Here the char value is, value: 123 exponent -2 ret = bt_gatt_set_float_value(characteristic_handle, BT_DATA_TYPE_FLOAT, 123, -2, 1); if (ret == BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "Success");
- Set the characteristic write type:
int ret = 0; bt_gatt_h svc = NULL; bt_gatt_h control_point = NULL; char *svc_uuid = "000018f2-0000-1000-8000-00805f9b34fb"; char *chr_uuid = "00002af6-0000-1000-8000-00805f9b34fb"; ret = bt_gatt_client_get_service(client, svc_uuid, &ancs_svc); if (ret == BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "Success"); ret = bt_gatt_service_get_characteristic(svc, chr_uuid, &control_point); if (ret == BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "Success"); ret = bt_gatt_characteristic_set_write_type(control_point, BT_GATT_WRITE_TYPE_WRITE); if (ret == BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "Success"); ret = bt_gatt_set_value(control_point, value, len); if (ret == BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "Success"); ret = bt_gatt_client_write_value(control_point, __write_completed_cb, NULL); if (ret == BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "Success"); return ret; if (ret == BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "Success");
Exchanging Data Using OPP
To exchange data with Object Push Profile (OPP):
The OPP is a basic profile for sending objects, such as pictures, virtual business cards, or schedules. The sender, which is a client, always initiates the transactions (called "push"), not the receiver, which is a server.
Server Role
The API has a server role to initialize the status of an OPP server device.
bt_error_e ret; char *directory = NULL; storage_get_directory(0, STORAGE_DIRECTORY_DOWNLOADS, &directory); void connection_requested_cb_for_opp_server(const char *remote_address, void *user_data) { dlog_print(DLOG_INFO, LOG_TAG, "remote_address: %s", remote_address); } ret = bt_opp_server_initialize_by_connection_request(directory, connection_requested_cb_for_opp_server, NULL); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_opp_server_initialize_by_connection_request] Failed."); } free(directory);
This function initializes the OPP server device requested by the bt_opp_server_push_requested_cb(). The bt_opp_server_connection_requested_cb function is called when an OPP connection is requested.
When a client requests a file push, the server can accept or reject it using the following functions:
bt_error_e ret; const char file_name [18] = "tempfile"; void bt_opp_server_transfer_progress_cb_for_opp(const char *file, long long size, int percent, void *user_data) { dlog_print(DLOG_INFO, LOG_TAG, "file: %s", file); dlog_print(DLOG_INFO, LOG_TAG, "size: %ld", size); dlog_print(DLOG_INFO, LOG_TAG, "percent: %d", percent); } void bt_opp_server_transfer_finished_cb_for_opp(int result, const char *file, long long size, void *user_data) { dlog_print(DLOG_INFO, LOG_TAG, "result: %d", result); dlog_print(DLOG_INFO, LOG_TAG, "file: %s", file); dlog_print(DLOG_INFO, LOG_TAG, "size: %ld", size); } ret = bt_opp_server_accept(bt_opp_server_transfer_progress_cb_for_opp, bt_opp_server_transfer_finished_cb_for_opp, file_name, NULL, NULL); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_opp_server_accept] Failed."); } ret = bt_opp_server_reject(); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_opp_server_reject] Failed."); }
Client Role
Initialize the client using the bt_opp_client_initialize() function:
bt_error_e ret; ret = bt_opp_client_initialize(); if (ret != BLUETOOTH_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "bt_opp_client_initialize() fail"); return -1; }
You can get the information of a file that can be sent to the server device using the bt_opp_client_add_file() function:
bt_error_e ret; char *resource_path = NULL; char caller_id_path[1024] = {'\0', }; resource_path = app_get_resource_path(); snprintf(caller_id_path, sizeof(caller_id_path)-1, "%s/image1.jpg", resource_path); free(resource_path); ret = bt_opp_client_add_file(caller_id_path); if (ret != BLUETOOTH_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "bt_opp_client_add_file() fail"); return -1; }
You can send the files to the server using the bt_opp_client_push_files() function:
bt_error_e ret; char remote_addr[18] = REMOTE_DEVICE_MAC_ADDRESS; void __bt_opp_client_push_responded_cb(int result, const char *remote_address, void *user_data) { dlog_print(DLOG_INFO, LOG_TAG, "result: %d", result); dlog_print(DLOG_INFO, LOG_TAG, "remote_address: %s", remote_address); } void __bt_opp_client_push_progress_cb(const char *file, long long size, int percent, void *user_data) { dlog_print(DLOG_INFO, LOG_TAG, "size: %ld", (long)size); dlog_print(DLOG_INFO, LOG_TAG, "percent: %d", percent); dlog_print(DLOG_INFO, LOG_TAG, "file: %s", file); } void __bt_opp_client_push_finished_cb(int result, const char *remote_address, void *user_data) { dlog_print(DLOG_INFO, LOG_TAG, "result: %d", result); dlog_print(DLOG_INFO, LOG_TAG, "remote_address: %s", remote_address); } ret = bt_opp_client_push_files(remote_addr, __bt_opp_client_push_responded_cb, __bt_opp_client_push_progress_cb, __bt_opp_client_push_finished_cb, NULL); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_opp_client_push_files] Failed."); } else { dlog_print(DLOG_INFO, LOG_TAG, "[bt_opp_client_push_files] Succeeded."); }
After the push is finished by the client, call the bt_opp_client_clear_files() and bt_opp_client_deinitialize() to release the Bluetooth resources related to the OPP client:
bt_error_e ret; // Delete file info ret = bt_opp_client_clear_files(); if (ret != BLUETOOTH_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "bt_opp_client_clear_files() fail"); return -1; } ret = bt_opp_client_deinitialize(); if (ret != BLUETOOTH_ERROR_NONE) { ERR("bt_opp_client_initialize "); dlog_print(DLOG_ERROR, LOG_TAG, "bt_opp_client_initialize Failed."); return -1; }
Managing Bluetooth LE Scans
To discover nearby LE devices, perform an LE scan operation:
-
To start the BLE scan:
int main() { int ret = BT_ERROR_NONE; ret = bt_adapter_le_start_scan(__bt_adapter_le_scan_result_cb, NULL); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_adapter_le_start_scan] Failed."); } return; }
-
Use a registered callback to retrieve the scan results. The callback contains information of all the LE scanned devices, such as the device names, scanned devices' transmission level, service data list, appearance of the devices, and manufacture data of the devices.
To handle the scan result:
int ret; void __bt_adapter_le_scan_result_cb(int result, bt_adapter_le_device_scan_result_info_s *info, void *user_data) { bt_adapter_le_packet_type_e pkt_type = BT_ADAPTER_LE_PACKET_ADVERTISING; if (info == NULL) { dlog_print T(DLOG_INFO, LOG_TAG, "No discovery_info!"); return; } if (info->adv_data_len > 31 || info->scan_data_len > 31) { dlog_print (DLOG_INFO, LOG_TAG, "###################"); bt_adapter_le_stop_scan(); dlog_print (DLOG_INFO, LOG_TAG, "###################"); return; } for (i = 0; i < 2; i++) { char **uuids; char *device_name; int tx_power_level; bt_adapter_le_service_data_s *data_list; int appearance; int manufacturer_id; char *manufacturer_data; int manufacturer_data_len; int count; 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_service_uuids(info, pkt_type, &uuids, &count) == BT_ERROR_NONE) { int i; for (i = 0; i < count; i++) { DLOG_PRINT(DLOG_INFO, LOG_TAG, "UUID[%d] = %s", i + 1, uuids[i]); g_free(uuids[i]); } g_free(uuids); } if (bt_adapter_le_get_scan_result_device_name(info, pkt_type, &device_name) == BT_ERROR_NONE) { DLOG_PRINT(DLOG_INFO, LOG_TAG, "Device name = %s", device_name); g_free(device_name); } if (bt_adapter_le_get_scan_result_tx_power_level(info, pkt_type, &tx_power_level) == BT_ERROR_NONE) { DLOG_PRINT(DLOG_INFO, LOG_TAG, "TX Power level = %d", tx_power_level); } if (bt_adapter_le_get_scan_result_service_solicitation_uuids(info, pkt_type, &uuids, &count) == BT_ERROR_NONE) { int i; for (i = 0; i < count; i++) { DLOG_PRINT(DLOG_INFO, LOG_TAG, "Solicitation UUID[%d] = %s", i + 1, uuids[i]); g_free(uuids[i]); } g_free(uuids); } if (bt_adapter_le_get_scan_result_service_data_list(info, pkt_type, &data_list, &count) == BT_ERROR_NONE) { int i; for (i = 0; i < count; i++) DLOG_PRINT(DLOG_INFO, LOG_TAG, "Service Data[%d] = [0x%2.2X%2.2X:0x%.2X...]", i + 1, data_list[i].service_uuid[0], data_list[i].service_uuid[1], data_list[i].service_data[0]); bt_adapter_le_free_service_data_list(data_list, count); } if (bt_adapter_le_get_scan_result_appearance(info, pkt_type, &appearance) == BT_ERROR_NONE) { DLOG_PRINT(DLOG_INFO, LOG_TAG, "Appearance = %d", appearance); } if (bt_adapter_le_get_scan_result_manufacturer_data(info, pkt_type, &manufacturer_id, &manufacturer_data, &manufacturer_data_len) == BT_ERROR_NONE) { DLOG_PRINT(DLOG_INFO, LOG_TAG, "Manufacturer data[ID:%.4X, 0x%.2X%.2X...(len:%d)]", manufacturer_id, manufacturer_data[0], manufacturer_data[1], manufacturer_data_len); g_free(manufacturer_data); } } }
-
To stop the BLE scan operation:
int main() { int ret = BT_ERROR_NONE; ret = bt_adapter_le_stop_scan(); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_adapter_le_stop_scan] Failed."); } return; }
Discovering Bluetooth LE Devices
Perform the LE discovery operation to discover nearby Bluetooth LE devices. You can register and unregister callbacks for the LE discovery operation through the use of set and unset callback functions. The registered device discovery callback provides details of the discovered devices and the state of the discovery (started, finished, found).
Note |
---|
The APIs used in this use case are deprecated since Tizen 2.3.1. For scanning nearby BLE devices in Tizen 2.3.1 and later, see Managing Bluetooth LE Scans. |
To start the BLE discovery operation:
int main() { int ret = BT_ERROR_NONE; ret = bt_adapter_le_set_device_discovery_state_changed_cb(bt_adapter_le_device_discovery_state_changed_cb, NULL); ret = bt_adapter_le_start_device_discovery(); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_adapter_le_start_device_discovery] Failed."); } // To unset the LE device discovery state change callback ret = bt_adapter_le_unset_device_discovery_state_changed_cb return; }
Adding Advertising Data to the LE Advertisement
LE advertising data can be added to the LE advertisement or the scan response data. You can add various information, such as the device name, service UUID, service solicitation UUID, advertising appearance, advertising transmission power level, device name, and manufacturer data.
-
To add the advertising data:
static bt_advertiser_h advertiser = NULL; static bt_advertiser_h advertiser_list[3] = {NULL, }; static int advertiser_index = 0; int le_add_advertising_data() { int adv_data_type = 3; // Default all int manufacturer_id = 117; char *manufacture = NULL; char manufacture_0[] = {0x0, 0x0, 0x0, 0x0}; char manufacture_1[] = {0x01, 0x01, 0x01, 0x01}; char manufacture_2[] = {0x02, 0x02, 0x02, 0x02}; char manufacture_3[] = {0x03, 0x03, 0x03, 0x03}; char service_data[] = {0x01, 0x02, 0x03}; const char *time_svc_uuid_16 = "1805"; const char *battery_svc_uuid_16 = "180f"; const char *heart_rate_svc_uuid_16 = "180d"; const char *immediate_alert_svc_uuid_16 = "1802"; const char *ancs_uuid_128 = "7905F431-B5CE-4E99-A40F-4B1E122D00D0"; int appearance = 192; // 192 is a generic watch advertiser = advertiser_list[advertiser_index]; if (advertiser == NULL) { ret = bt_adapter_le_create_advertiser(&advertiser); dlog_print(DLOG_INFO, LOG_TAG, "created le advertiser(%d)", ret); advertiser_list[advertiser_index] = advertiser; } else { ret = bt_adapter_le_clear_advertising_data(advertiser, BT_ADAPTER_LE_PACKET_ADVERTISING); if (ret != BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "clear advertising data [0x%04x]", ret); ret = bt_adapter_le_clear_advertising_data(advertiser, BT_ADAPTER_LE_PACKET_SCAN_RESPONSE); if (ret != BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "clear scan response data [0x%04x]", ret); } if (g_test_param.param_count > 0) { adv_data_type = atoi(g_test_param.params[0]); __bt_free_test_param(&g_test_param); } switch (adv_data_type) { case 0: // Service UUID ret = bt_adapter_le_add_advertising_service_uuid(advertiser, BT_ADAPTER_LE_PACKET_ADVERTISING, time_svc_uuid_16); if (ret != BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "add service_uuid [0x%04x]", ret); ret = bt_adapter_le_add_advertising_service_uuid(advertiser, BT_ADAPTER_LE_PACKET_ADVERTISING, battery_svc_uuid_16); if (ret != BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "add service_uuid [0x%04x]", ret); manufacture = manufacture_0; break; case 1: // Service solicitation ret = bt_adapter_le_add_advertising_service_solicitation_uuid(advertiser, BT_ADAPTER_LE_PACKET_ADVERTISING, heart_rate_svc_uuid_16); if (ret != BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "dd service_solicitation_uuid [0x%04x]", ret); ret = bt_adapter_le_add_advertising_service_solicitation_uuid(advertiser, BT_ADAPTER_LE_PACKET_ADVERTISING, immediate_alert_svc_uuid_16); if (ret != BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "add service_solicitation_uuid [0x%04x]", ret); manufacture = manufacture_1; break; case 2: // Appearance & TX power level ret = bt_adapter_le_set_advertising_appearance(advertiser, BT_ADAPTER_LE_PACKET_ADVERTISING, appearance); if (ret != BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "add appearance data [0x%04x]", ret); ret = bt_adapter_le_set_advertising_tx_power_level(advertiser, BT_ADAPTER_LE_PACKET_ADVERTISING, true); if (ret != BT_ERROR_NONE) dlog_print (DLOG_INFO, LOG_TAG, "add appearance data [0x%04x]", ret); manufacture = manufacture_2; break; case 3: // All ret = bt_adapter_le_add_advertising_service_uuid(advertiser, BT_ADAPTER_LE_PACKET_ADVERTISING, time_svc_uuid_16); if (ret != BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "add service_uuid [0x%04x]", ret); ret = bt_adapter_le_add_advertising_service_uuid(advertiser, BT_ADAPTER_LE_PACKET_ADVERTISING, battery_svc_uuid_16); if (ret != BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "add service_uuid [0x%04x]", ret); ret = bt_adapter_le_add_advertising_service_solicitation_uuid(advertiser, BT_ADAPTER_LE_PACKET_ADVERTISING, heart_rate_svc_uuid_16); if (ret != BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "add service_solicitation_uuid [0x%04x]", ret); ret = bt_adapter_le_add_advertising_service_solicitation_uuid(advertiser, BT_ADAPTER_LE_PACKET_ADVERTISING, immediate_alert_svc_uuid_16); if (ret != BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "add service_solicitation_uuid [0x%04x]", ret); ret = bt_adapter_le_set_advertising_appearance(advertiser, BT_ADAPTER_LE_PACKET_ADVERTISING, appearance); if (ret != BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "add appearance data [0x%04x]", ret); ret = bt_adapter_le_set_advertising_tx_power_level(advertiser, BT_ADAPTER_LE_PACKET_ADVERTISING, true); if (ret != BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "add tx_power_level [0x%04x]", ret); manufacture = manufacture_3; break; case 4: // ANCS ret = bt_adapter_le_add_advertising_service_solicitation_uuid(advertiser, BT_ADAPTER_LE_PACKET_ADVERTISING, time_svc_uuid_16); if (ret != BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "add service_solicitation_uuid [0x%04x]", ret); ret = bt_adapter_le_add_advertising_service_solicitation_uuid(advertiser, BT_ADAPTER_LE_PACKET_ADVERTISING, ancs_uuid_128); if (ret != BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "add service_solicitation_uuid [0x%04x]", ret); ret = bt_adapter_le_set_advertising_device_name(advertiser, BT_ADAPTER_LE_PACKET_SCAN_RESPONSE, true); if (ret != BT_ERROR_NONE) dlog_print (DLOG_INFO, LOG_TAG, "set device name [0x%04x]", ret); return 0; default: dlog_print(DLOG_INFO, LOG_TAG, "No adv data"); break; } // Default scan response data ret = bt_adapter_le_add_advertising_service_data(advertiser, BT_ADAPTER_LE_PACKET_SCAN_RESPONSE, time_svc_uuid_16, service_data, sizeof(service_data)); if (ret != BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "add service_data [0x%04x]", ret); ret = bt_adapter_le_set_advertising_device_name(advertiser, BT_ADAPTER_LE_PACKET_SCAN_RESPONSE, true); if (ret != BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "set device name [0x%04x]", ret); ret = bt_adapter_le_add_advertising_manufacturer_data(advertiser, BT_ADAPTER_LE_PACKET_SCAN_RESPONSE, manufacturer_id, ;manufacture, sizeof(manufacture_0)); if (ret != BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "add manufacturer data [0x%04x]", ret); }
-
To destroy the LE advertiser:
{ int ret = BT_ERROR_NONE; ret = bt_adapter_le_destroy_advertiser(advertiser); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_adapter_le_destroy_advertiser] Failed."); } return; }
Setting the Advertising Connectable Mode
When advertising to the remote device, use the bt_adapter_le_set_advertising_connectable() function to define whether the advertising type is connectable or non-connectable:
static bt_advertiser_h advertiser = NULL; static bt_advertiser_h advertiser_list[3] = {NULL,}; static int advertiser_index = 0; int type = BT_ADAPTER_LE_ADVERTISING_CONNECTABLE; advertiser = advertiser_list[advertiser_index]; if (advertiser == NULL) { ret = bt_adapter_le_create_advertiser(&advertiser); dlog_print(DLOG_INFO, LOG_TAG, "created le advertiser(%d)", ret); advertiser_list[advertiser_index] = advertiser; } if (g_test_param.param_count > 0) { type = atoi(g_test_param.params[0]); __bt_free_test_param(&g_test_param); } ret = bt_adapter_le_set_advertising_connectable(advertiser, type); if (ret != BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "add scan response data [0x%04x]", ret);
Setting the LE Advertising Mode
The advertising mode controls the advertising power and latency, and can be set to the balanced, low latency, or low energy advertising mode.
To set the advertising mode:
static bt_advertiser_h advertiser = NULL; static bt_advertiser_h advertiser_list[3] = {NULL,}; static int advertiser_index = 0; int mode = BT_ADAPTER_LE_ADVERTISING_MODE_BALANCED; advertiser = advertiser_list[advertiser_index]; if (advertiser == NULL) { ret = bt_adapter_le_create_advertiser(&advertiser); dlog_print(DLOG_INFO, LOG_TAG, "created le advertiser(%d)", ret); advertiser_list[advertiser_index] = advertiser; } if (g_test_param.param_count > 0) { mode = atoi(g_test_param.params[0]); __bt_free_test_param(&g_test_param); } ret = bt_adapter_le_set_advertising_mode(advertiser, mode); if (ret != BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "add scan response data [0x%04x]", ret);
Starting and Stopping Advertising
To manage advertising:
-
To start advertising with the given advertiser and advertising parameters information, use the bt_adapter_le_start_advertising_new() function:
bt_adapter_le_advertising_state_changed_cb cb; if (advertiser_index == 0) cb = __bt_adapter_le_advertising_state_changed_cb; else if (advertiser_index == 0) cb = __bt_adapter_le_advertising_state_changed_cb_2; else cb = __bt_adapter_le_advertising_state_changed_cb_3; advertiser = advertiser_list[advertiser_index]; advertiser_index++; advertiser_index %= 3; if (advertiser == NULL) { ret = bt_adapter_le_create_advertiser(&advertiser); dlog_print(DLOG_INFO, LOG_TAG, "created le advertiser(%d)", ret); advertiser_list[advertiser_index] = advertiser; } ret = bt_adapter_le_start_advertising_new(advertiser, cb, NULL); if (ret < BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "failed with [0x%04x]", ret);
-
To stop advertising with the given advertiser, use the bt_adapter_le_stop_advertising() function:
if (advertiser != NULL) { ret = bt_adapter_le_stop_advertising(advertiser); if (ret < BT_ERROR_NONE) dlog_print(DLOG_INFO, LOG_TAG, "failed with [0x%04x]", ret); }
Releasing All Resources
To release all Bluetooth resources, call the bt_deinitialize() function:
// Unregister callbacks bt_adapter_unset_state_changed_cb(); bt_adapter_unset_device_discovery_state_changed_cb(); bt_device_unset_service_searched_cb(); bt_socket_unset_data_received_cb(); bt_socket_unset_connection_state_changed_cb(); // Release resources // Deinitialize Bluetooth ret = bt_deinitialize(); if (ret != BT_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "[bt_deinitialize] Failed."); }