*
*/
+#include <glib.h>
#include <string>
+#include <map>
#include <bluetooth.h>
#include <netinet/in.h>
#include "ble-plugin.h"
#define VINE_UUID "29AD"
+#define VINE_MANUFACTURER_ID 0x1111
+#define VINE_MAX_MANUFACTURER_DATA_LEN 31
typedef struct {
void *disc_handle;
+ char service_type[VINE_MAX_BLE_SERVICE_TYPE_LEN + 1];
bt_advertiser_h adv;
+ bt_scan_filter_h filter;
} vine_ble_s;
static vine_disc_plugin_callbacks event_callbacks;
handle->disc_handle = disc_handle;
handle->adv = NULL;
+ handle->filter = NULL;
*plugin_handle = handle;
return VINE_DISC_ERROR_NONE;
VINE_LOGD("BLE advertising state is changed. result: %d, state: %d", result, adv_state);
}
+static int __configure_advertiser(bt_advertiser_h adv,
+ const char *service_type, const char *service_name)
+{
+ int ret = bt_adapter_le_add_advertising_service_uuid(adv,
+ BT_ADAPTER_LE_PACKET_SCAN_RESPONSE, VINE_UUID);
+ RET_VAL_IF(ret != BT_ERROR_NONE, ret,
+ "bt_adapter_le_add_advertising_service_uuid() fails %d", ret);
+
+ // TODO: Determine which data should be set for service_data
+ // It should be set mandatorily?
+ // Or we don't have to set service_data if manufacturer data is set
+ char service_data[3] = {0x01, 0x02, 0x03};
+ // TODO: ALso set for BT_ADAPTER_LE_PACKET_ADVERTISING?
+ ret = bt_adapter_le_add_advertising_service_data(adv,
+ BT_ADAPTER_LE_PACKET_SCAN_RESPONSE,
+ VINE_UUID, service_data, sizeof(service_data));
+ RET_VAL_IF(ret != BT_ERROR_NONE, ret,
+ "bt_adapter_le_add_advertising_service_data() fails %d", ret);
+
+ // TODO: Also set for BT_ADAPTER_LE_PACKET_ADVERTISING?
+ ret = bt_adapter_le_set_advertising_device_name(adv,
+ BT_ADAPTER_LE_PACKET_SCAN_RESPONSE, true);
+ RET_VAL_IF(ret != BT_ERROR_NONE, ret,
+ "bt_adapter_le_set_advertising_device_name() fails %d", ret);
+
+ ret = bt_adapter_le_set_advertising_connectable(adv, true);
+ RET_VAL_IF(ret != BT_ERROR_NONE, ret,
+ "bt_adapter_le_set_advertising_connectable() fails %d", ret);
+
+ ret = bt_adapter_le_set_advertising_mode(adv,
+ BT_ADAPTER_LE_ADVERTISING_MODE_BALANCED);
+ RET_VAL_IF(ret != BT_ERROR_NONE, ret,
+ "bt_adapter_le_set_advertising_mode() fails %d", ret);
+
+ char manufacturer_data[VINE_MAX_MANUFACTURER_DATA_LEN + 1];
+ int manufacturer_len = strlen(service_type) + strlen(service_name) + 1;
+ RET_VAL_IF(manufacturer_len > 31, BT_ERROR_INVALID_PARAMETER,
+ "Too long service_type and service_name");
+
+ snprintf(manufacturer_data, VINE_MAX_MANUFACTURER_DATA_LEN + 1,
+ "%s.%s", service_type, service_name);
+
+ ret = bt_adapter_le_add_advertising_manufacturer_data(adv,
+ BT_ADAPTER_LE_PACKET_SCAN_RESPONSE, VINE_MANUFACTURER_ID,
+ manufacturer_data, manufacturer_len);
+ RET_VAL_IF(ret != BT_ERROR_NONE, ret,
+ "bt_adapter_le_add_advertising_manufacturer_data() fails %d", ret);
+
+
+ return BT_ERROR_NONE;
+}
+
vine_disc_error ble_publish(void *plugin_handle, const char *service_type,
const char *service_name, int port, const map<string, string> &attributes,
const char *iface_name)
RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL");
RET_VAL_IF(!service_type, VINE_DISC_ERROR_INVALID_PARAMETER, "service_type is NULL");
RET_VAL_IF(!service_name, VINE_DISC_ERROR_INVALID_PARAMETER, "service_name is NULL");
+ RET_VAL_IF(strlen(service_type) > VINE_MAX_BLE_SERVICE_TYPE_LEN, VINE_DISC_ERROR_INVALID_PARAMETER,
+ "too long service type");
+ RET_VAL_IF(strlen(service_name) > VINE_MAX_BLE_SERVICE_NAME_LEN, VINE_DISC_ERROR_INVALID_PARAMETER,
+ "too long service namr");
vine_ble_s *ble_handle = (vine_ble_s *)plugin_handle;
RET_VAL_IF(ble_handle->adv != NULL, VINE_DISC_ERROR_INVALID_PARAMETER, "Already published");
- // TODO: Determine which data should be set for service_data
- char service_data[3] = {0x01, 0x02, 0x03};
-
int ret = bt_adapter_le_create_advertiser(&ble_handle->adv);
RET_VAL_IF(ret != BT_ERROR_NONE, __convert_ble_error_to_vine_disc_error(ret),
"bt_adapter_le_create_advertiser() fails");
- ret = bt_adapter_le_add_advertising_service_uuid(ble_handle->adv,
- BT_ADAPTER_LE_PACKET_ADVERTISING, VINE_UUID);
- if (ret != BT_ERROR_NONE) {
- VINE_LOGE("bt_adapter_le_add_advertising_service_uuid() fails %d", ret);
- goto error;
- }
-
- // TODO: ALso set for BT_ADAPTER_LE_PACKET_ADVERTISING?
- ret = bt_adapter_le_add_advertising_service_data(ble_handle->adv,
- BT_ADAPTER_LE_PACKET_SCAN_RESPONSE,
- VINE_UUID, service_data, sizeof(service_data));
- if (ret != BT_ERROR_NONE) {
- VINE_LOGE("bt_adapter_le_add_advertising_service_data() fails %d", ret);
- goto error;
- }
-
- // TODO: Also set for BT_ADAPTER_LE_PACKET_SCAN_RESPONSE?
- ret = bt_adapter_le_set_advertising_device_name(ble_handle->adv,
- BT_ADAPTER_LE_PACKET_ADVERTISING, true);
- if (ret != BT_ERROR_NONE) {
- VINE_LOGE("bt_adapter_le_set_advertising_device_name() fails %d", ret);
- goto error;
- }
-
- ret = bt_adapter_le_set_advertising_connectable(ble_handle->adv, true);
- if (ret != BT_ERROR_NONE) {
- VINE_LOGE("bt_adapter_le_set_advertising_connectable() fails %d", ret);
- goto error;
- }
-
- ret = bt_adapter_le_set_advertising_mode(ble_handle->adv,
- BT_ADAPTER_LE_ADVERTISING_MODE_BALANCED);
+ ret = __configure_advertiser(ble_handle->adv, service_type, service_name);
if (ret != BT_ERROR_NONE) {
- VINE_LOGE("bt_adapter_le_set_advertising_mode() fails %d", ret);
- goto error;
+ VINE_LOGE("__configure_advertiser() fails %d", ret);
+ goto ERR;
}
ret = bt_adapter_le_start_advertising_new(ble_handle->adv,
__ble_advertising_state_changed_cb, ble_handle);
if (ret != BT_ERROR_NONE) {
VINE_LOGE("bt_adapter_le_start_advertising_new() fails %d", ret);
- goto error;
+ goto ERR;
}
-error:
+ return VINE_DISC_ERROR_NONE;
+
+ERR:
if (ble_handle->adv) {
bt_adapter_le_destroy_advertiser(ble_handle->adv);
ble_handle->adv = NULL;
{
RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL");
- return VINE_DISC_ERROR_NONE;
+ vine_ble_s *ble_handle = (vine_ble_s *)plugin_handle;
+ RET_VAL_IF(ble_handle->adv == NULL, VINE_DISC_ERROR_INVALID_PARAMETER, "No advertiser");
+
+ int ret = bt_adapter_le_stop_advertising(ble_handle->adv);
+ ble_handle->adv = NULL;
+
+ return __convert_ble_error_to_vine_disc_error(ret);
+}
+
+static int __configure_scan_filter(bt_scan_filter_h filter, const char *service_type)
+{
+ int ret = bt_adapter_le_scan_filter_set_service_uuid(filter, VINE_UUID);
+ RET_VAL_IF(ret != BT_ERROR_NONE, ret,
+ "bt_adapter_le_scan_filter_set_service_uuid() fails %d", ret);
+
+ ret = bt_adapter_le_scan_filter_register(filter);
+ RET_VAL_IF(ret != BT_ERROR_NONE, ret,
+ "bt_adapter_le_scan_filter_register() fails %d", ret);
+
+ return BT_ERROR_NONE;
+}
+
+static void __le_scan_result_cb(int result, bt_adapter_le_device_scan_result_info_s *info,
+ void *user_data)
+{
+ if (info == NULL)
+ return;
+
+ if (info->adv_data_len > 31 || info->scan_data_len > 31) {
+ VINE_LOGE("Invalid length");
+ return;
+ }
+
+ int manufacturer_id;
+ char *manufacturer_data;
+ int manufacturer_len;
+ // TODO: For now, check only scan_data
+ int ret = bt_adapter_le_get_scan_result_manufacturer_data(info, BT_ADAPTER_LE_PACKET_SCAN_RESPONSE,
+ &manufacturer_id, &manufacturer_data, &manufacturer_len);
+ RET_IF(ret != BT_ERROR_NONE, "Invalid Data");
+
+ vine_ble_s *ble_handle = (vine_ble_s *)user_data;
+ int service_type_len = strlen(ble_handle->service_type);
+ if (manufacturer_len > service_type_len &&
+ strncmp(manufacturer_data, ble_handle->service_type, service_type_len) == 0) {
+ char service_name[VINE_MAX_BLE_SERVICE_NAME_LEN + 1];
+ int service_name_len = manufacturer_len - 1 - service_type_len;
+ strncpy(service_name, manufacturer_data + service_type_len + 1, service_name_len);
+ if (event_callbacks.discovered_cb) {
+ std::map<string, string> empty_map;
+ event_callbacks.discovered_cb(ble_handle, true,
+ ble_handle->service_type, service_name, NULL, 0, empty_map,
+ NULL, 0, ble_handle->disc_handle);
+ }
+ }
+
+ g_free(manufacturer_data);
}
vine_disc_error ble_subscribe(void *plugin_handle,
{
RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL");
RET_VAL_IF(!service_type, VINE_DISC_ERROR_INVALID_PARAMETER, "service_type is NULL");
+ RET_VAL_IF(strlen(service_type) > VINE_MAX_BLE_SERVICE_TYPE_LEN, VINE_DISC_ERROR_INVALID_PARAMETER,
+ "too long service type");
vine_ble_s *ble_handle = (vine_ble_s *)plugin_handle;
+ RET_VAL_IF(ble_handle->filter != NULL, VINE_DISC_ERROR_INVALID_PARAMETER, "Already subscribed");
+
+ int ret = bt_adapter_le_scan_filter_create(&ble_handle->filter);
+ RET_VAL_IF(ret != BT_ERROR_NONE, __convert_ble_error_to_vine_disc_error(ret),
+ "bt_adapter_le_scan_filter_create() fails");
+
+ ret = __configure_scan_filter(ble_handle->filter, service_type);
+ if (ret != BT_ERROR_NONE) {
+ VINE_LOGE("__configure_scan_filter() fails %d", ret);
+ goto ERR;
+ }
+
+ ret = bt_adapter_le_start_scan(__le_scan_result_cb, NULL);
+ if (ret != BT_ERROR_NONE) {
+ VINE_LOGE("bt_adapter_le_start_scan() fails");
+ goto ERR;
+ }
+ strncpy(ble_handle->service_type, service_type, VINE_MAX_BLE_SERVICE_TYPE_LEN);
return VINE_DISC_ERROR_NONE;
+
+ERR:
+ bt_adapter_le_scan_filter_destroy(ble_handle->filter);
+ ble_handle->filter = NULL;
+
+ return __convert_ble_error_to_vine_disc_error(ret);
}
vine_disc_error ble_stop_subscribe(void *plugin_handle)
{
RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL");
+ vine_ble_s *ble_handle = (vine_ble_s *)plugin_handle;
+ RET_VAL_IF(ble_handle->filter == NULL, VINE_DISC_ERROR_INVALID_PARAMETER, "Not subscribed");
+
+ bt_adapter_le_stop_scan();
+
+ bt_adapter_le_scan_filter_unregister(ble_handle->filter);
+ bt_adapter_le_scan_filter_destroy(ble_handle->filter);
+ ble_handle->filter = NULL;
+
return VINE_DISC_ERROR_NONE;
}