From b3f741429b3a17354fd694a413d27bc181d29e9e Mon Sep 17 00:00:00 2001 From: Cheoleun Moon Date: Mon, 28 Jun 2021 16:21:11 +0900 Subject: [PATCH] ble plugin: Implement basic operation Change-Id: I8dd59934cdd897172b0ef36100b670e2ed4f02f1 Signed-off-by: Cheoleun Moon --- packaging/capi-network-vine.spec | 2 +- plugins/ble/ble-plugin.cpp | 202 +++++++++++++++++++++++++++++++-------- src/include/vine-constants.h | 5 + 3 files changed, 168 insertions(+), 41 deletions(-) diff --git a/packaging/capi-network-vine.spec b/packaging/capi-network-vine.spec index 462fbc3..34cf751 100755 --- a/packaging/capi-network-vine.spec +++ b/packaging/capi-network-vine.spec @@ -3,7 +3,7 @@ %bcond_without use_glib_event_loop Name: capi-network-vine Summary: An service discovery framework -Version: 1.0.10 +Version: 1.1.1 Release: 0 Group: Network & Connectivity/API License: Apache-2.0 diff --git a/plugins/ble/ble-plugin.cpp b/plugins/ble/ble-plugin.cpp index 53db819..97adf93 100755 --- a/plugins/ble/ble-plugin.cpp +++ b/plugins/ble/ble-plugin.cpp @@ -15,7 +15,9 @@ * */ +#include #include +#include #include #include @@ -30,10 +32,14 @@ #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; @@ -75,6 +81,7 @@ vine_disc_error ble_init(void **plugin_handle, void *disc_handle) handle->disc_handle = disc_handle; handle->adv = NULL; + handle->filter = NULL; *plugin_handle = handle; return VINE_DISC_ERROR_NONE; @@ -97,6 +104,58 @@ static void __ble_advertising_state_changed_cb(int result, bt_advertiser_h adver 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 &attributes, const char *iface_name) @@ -104,62 +163,34 @@ vine_disc_error ble_publish(void *plugin_handle, const char *service_type, 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; @@ -172,7 +203,63 @@ vine_disc_error ble_stop_publish(void *plugin_handle) { 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 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, @@ -180,16 +267,51 @@ 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; } diff --git a/src/include/vine-constants.h b/src/include/vine-constants.h index 26de5b3..0082fab 100644 --- a/src/include/vine-constants.h +++ b/src/include/vine-constants.h @@ -29,4 +29,9 @@ #define VINE_MAX_TOPIC_LEN 63 +// Actually, max length of service_type and service_name for ble cannot be restricted strictly. +// Even though the constraits is met, the operation can be failed. +#define VINE_MAX_BLE_SERVICE_TYPE_LEN 15 +#define VINE_MAX_BLE_SERVICE_NAME_LEN 15 + #endif /* __VINE_SERV__VINE_CONSTANTS_H__ICE_H__ */ -- 2.7.4