/* * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include "bluetooth.h" #include "bluetooth_internal.h" #include "bluetooth_private.h" typedef struct { bt_gatt_h linkloss_service; bt_gatt_h immediate_service; } bt_proximity_service_info_t; typedef struct { bt_proximity_service_info_t services; } bt_proximity_reporter_server_s; typedef struct { bt_proximity_reporter_server_s reporter_server; int services_supported; bool connected; const void *connection_callback; void *user_data; } bt_proximity_reporter_s; typedef struct { GSList *services; char *remote_address; bool services_discovered; bool connected; const void *connection_callback; void *user_data; } bt_proximity_monitor_s; GSList *proximity_monitor_list; static bool pxp_monitor_initialized = false; static bool pxp_reporter_initialized = false; static int pxp_monitor_supported_services = false; static bt_proximity_reporter_s *reporter_s = NULL; #define BT_CHECK_GATT_PXP_SUPPORT() \ { \ BT_CHECK_SUPPORTED_FEATURE(BT_FEATURE_COMMON); \ BT_CHECK_SUPPORTED_FEATURE(BT_FEATURE_LE); \ } /* LCOV_EXCL_START */ int bt_proximity_reporter_create(bt_proximity_reporter_h *reporter) { int error_code = BT_ERROR_NONE; BT_CHECK_GATT_PXP_SUPPORT(); BT_CHECK_INIT_STATUS(); if (reporter_s != NULL) return BT_ERROR_ALREADY_DONE; /* register Reporter Role Here */ error_code = _bt_get_error_code(bluetooth_proximity_reporter_register()); if (error_code != BT_ERROR_NONE) BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); else pxp_reporter_initialized = true; reporter_s = g_malloc0(sizeof(*reporter_s)); if (reporter_s == NULL) { error_code = BT_ERROR_OUT_OF_MEMORY; BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); return error_code; } *reporter = (bt_proximity_reporter_s *)reporter_s; error_code = bt_gatt_service_create(PXP_LINK_LOSS_SVC_UUID, BT_GATT_SERVICE_TYPE_PRIMARY, &reporter_s->reporter_server.services.linkloss_service); if (error_code != BT_ERROR_NONE) BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); error_code = bt_gatt_service_create(PXP_IMMEDIATE_ALERT_SVC_UUID, BT_GATT_SERVICE_TYPE_PRIMARY, &reporter_s->reporter_server.services.linkloss_service); if (error_code != BT_ERROR_NONE) BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); /* By default the bluez stack supports Link loss and immediate alert service when we register */ reporter_s->services_supported = BT_PROXIMITY_LINKLOSS_ALERT | BT_PROXIMITY_IMMEDIATE_ALERT; /* Start Advertising with Proximity services */ return error_code; } int bt_proximity_reporter_destroy(bt_proximity_reporter_h reporter) { int error_code = BT_ERROR_NONE; BT_CHECK_GATT_PXP_SUPPORT(); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(reporter); if (reporter_s == NULL) return BT_ERROR_NOT_INITIALIZED; if (!pxp_reporter_initialized) return BT_ERROR_NOT_INITIALIZED; /* Unregister Reporter Role Here */ error_code = _bt_get_error_code(bluetooth_proximity_reporter_unregister()); if (error_code != BT_ERROR_NONE) BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); else pxp_reporter_initialized = false; bt_gatt_destroy(reporter_s->reporter_server.services.linkloss_service); bt_gatt_destroy(reporter_s->reporter_server.services.linkloss_service); reporter_s->services_supported = 0; g_free(reporter_s); reporter_s = NULL; return error_code; } int _bt_check_proximity_is_initialized(bool *is_initialized) { BT_CHECK_GATT_PXP_SUPPORT(); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(is_initialized); if (pxp_reporter_initialized || pxp_monitor_initialized) *is_initialized = TRUE; else *is_initialized = FALSE; return BT_ERROR_NONE; } static bt_proximity_monitor_s *_bt_proximity_monitor_find(const char *remote_address) { GSList *l; for (l = proximity_monitor_list; l; l = g_slist_next(l)) { bt_proximity_monitor_s *c = (bt_proximity_monitor_s *)l->data; if ((c == NULL) || (c->remote_address == NULL)) { BT_ERR("_bt_proximity_monitor_find Error Parameter are NULL..\n"); continue; } else if (!g_ascii_strcasecmp(c->remote_address, remote_address)) { return c; } } return NULL; } int _bt_proximity_connection_set_state_changed(int result, const char *remote_address, bool connected) { int service_type = 0; int error_code = BT_ERROR_NONE; BT_DBG("bt_proximity_connection_state_changed"); if (pxp_monitor_initialized) { bt_proximity_monitor_s *monitor_s = NULL; monitor_s = _bt_proximity_monitor_find(remote_address); if (monitor_s) { bluetooth_device_address_t addr_hex = { {0,} }; _bt_convert_address_to_hex(&addr_hex, remote_address); error_code = bluetooth_proximity_monitor_get_supported_services(&addr_hex, &service_type); if (error_code != BT_ERROR_NONE) BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); monitor_s->connected = connected; monitor_s->services_discovered = service_type; pxp_monitor_supported_services = service_type; if (monitor_s->connection_callback) ((bt_proximity_monitor_connection_state_changed_cb)monitor_s->connection_callback) (result, remote_address, monitor_s, connected, service_type, monitor_s->user_data); } } if (pxp_reporter_initialized) { if (reporter_s) { service_type = reporter_s->services_supported; reporter_s->connected = connected; if (reporter_s->connection_callback) ((bt_proximity_reporter_connection_state_changed_cb)reporter_s->connection_callback) (result, remote_address, reporter_s, connected, service_type, reporter_s->user_data); } } return error_code; } int bt_proximity_monitor_create(const char *remote_address, bt_proximity_monitor_h *monitor) { int error_code = BT_ERROR_NONE; bt_proximity_monitor_s *monitor_s = NULL; bool connected = false; bluetooth_device_address_t addr_hex = { {0,} }; int service_type = 0; GSList *l; BT_CHECK_GATT_PXP_SUPPORT(); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(remote_address); BT_CHECK_INPUT_PARAMETER(monitor); for (l = proximity_monitor_list; l; l = g_slist_next(l)) { bt_proximity_monitor_s *c = (bt_proximity_monitor_s *)l->data; if ((c == NULL) || (c->remote_address == NULL)) { BT_ERR("bt_proximity_monitor_create Error Parameter are NULL..\n"); continue; } else if (!g_ascii_strcasecmp(c->remote_address, remote_address)) { BT_ERR("Gatt client for %s is already created", remote_address); return BT_ERROR_ALREADY_DONE; } } monitor_s = g_malloc0(sizeof(*monitor_s)); if (monitor_s == NULL) { error_code = BT_ERROR_OUT_OF_MEMORY; BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); return error_code; } monitor_s->remote_address = g_strdup(remote_address); if (monitor_s->remote_address == NULL) { g_free(monitor_s); error_code = BT_ERROR_OUT_OF_MEMORY; BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); return error_code; } *monitor = (bt_proximity_monitor_h)monitor_s; proximity_monitor_list = g_slist_append(proximity_monitor_list, monitor_s); if (bt_device_is_profile_connected(remote_address, BT_PROFILE_GATT, &connected) != BT_ERROR_NONE) BT_ERR("bt_device_is_profile_connected is failed"); monitor_s->connected = connected; _bt_convert_address_to_hex(&addr_hex, remote_address); if (bluetooth_proximity_monitor_get_supported_services(&addr_hex, &service_type) != BT_ERROR_NONE) BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); monitor_s->services_discovered = service_type; pxp_monitor_initialized = true; BT_INFO("Proximity Monitor Handle is created"); return error_code; } int bt_proximity_monitor_destroy(bt_proximity_monitor_h monitor) { bt_proximity_monitor_s *monitor_s = (bt_proximity_monitor_s *)monitor; BT_CHECK_GATT_PXP_SUPPORT(); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(monitor); if (_bt_proximity_monitor_find(monitor_s->remote_address) == NULL) return BT_ERROR_REMOTE_DEVICE_NOT_CONNECTED; if (monitor_s->connection_callback) { monitor_s->connection_callback = NULL; monitor_s->user_data = NULL; } pxp_monitor_supported_services = 0; g_free(monitor_s->remote_address); proximity_monitor_list = g_slist_remove(proximity_monitor_list, monitor_s); g_free(monitor_s); return BT_ERROR_NONE; } int bt_proximity_monitor_connect(bt_proximity_monitor_h monitor) { int error_code; bt_proximity_monitor_s *monitor_s = (bt_proximity_monitor_s *)monitor; BT_CHECK_GATT_PXP_SUPPORT(); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(monitor_s); if (_bt_proximity_monitor_find(monitor_s->remote_address) == NULL) return BT_ERROR_NOT_INITIALIZED; error_code = bt_gatt_connect(monitor_s->remote_address, FALSE); if (error_code != BT_ERROR_NONE) BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); return error_code; } int bt_proximity_monitor_disconnect(bt_proximity_monitor_h monitor) { int error_code; bt_proximity_monitor_s *monitor_s = (bt_proximity_monitor_s *)monitor; BT_CHECK_GATT_PXP_SUPPORT(); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(monitor_s); if (_bt_proximity_monitor_find(monitor_s->remote_address) == NULL) return BT_ERROR_REMOTE_DEVICE_NOT_CONNECTED; error_code = bt_gatt_disconnect(monitor_s->remote_address); if (error_code != BT_ERROR_NONE) BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); return error_code; } int bt_proximity_monitor_set_connection_state_changed_cb(bt_proximity_monitor_h monitor, bt_proximity_monitor_connection_state_changed_cb callback, void *user_data) { bt_proximity_monitor_s *monitor_s = (bt_proximity_monitor_s *)monitor; BT_CHECK_SUPPORTED_FEATURE(BT_FEATURE_COMMON); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(monitor_s); BT_CHECK_INPUT_PARAMETER(callback); if (_bt_proximity_monitor_find(monitor_s->remote_address) == NULL) return BT_ERROR_REMOTE_DEVICE_NOT_CONNECTED; /* register the callback */ monitor_s->connection_callback = callback; monitor_s->user_data = user_data; return BT_ERROR_NONE; } int bt_proximity_monitor_unset_connection_state_changed_cb(bt_proximity_monitor_h monitor) { bt_proximity_monitor_s *monitor_s = (bt_proximity_monitor_s *)monitor; BT_CHECK_SUPPORTED_FEATURE(BT_FEATURE_COMMON); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(monitor_s); if (_bt_proximity_monitor_find(monitor_s->remote_address) == NULL) return BT_ERROR_REMOTE_DEVICE_NOT_CONNECTED; /* unregister the callback */ monitor_s->connection_callback = NULL; monitor_s->user_data = NULL; return BT_ERROR_NONE; } int bt_proximity_reporter_set_connection_state_changed_cb(bt_proximity_reporter_h reporter, bt_proximity_reporter_connection_state_changed_cb callback, void *user_data) { bt_proximity_reporter_s *reporter_l = (bt_proximity_reporter_s *)reporter; BT_CHECK_SUPPORTED_FEATURE(BT_FEATURE_COMMON); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(reporter_l); BT_CHECK_INPUT_PARAMETER(callback); /* register the callback */ reporter_s->connection_callback = callback; reporter_s->user_data = user_data; return BT_ERROR_NONE; } int bt_proximity_reporter_unset_connection_state_changed_cb(bt_proximity_reporter_h reporter) { bt_proximity_reporter_s *reporter_l = (bt_proximity_reporter_s *)reporter; BT_CHECK_SUPPORTED_FEATURE(BT_FEATURE_COMMON); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(reporter_l); /* unregister the callback */ reporter_l->connection_callback = NULL; reporter_l->user_data = NULL; return BT_ERROR_NONE; } int bt_proximity_reporter_set_property_changed_cb(bt_proximity_reporter_h reporter, bt_proximity_reporter_property_changed_cb callback, void *user_data) { bt_proximity_reporter_s *reporter_l = (bt_proximity_reporter_s *)reporter; BT_CHECK_SUPPORTED_FEATURE(BT_FEATURE_COMMON); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(reporter_l); BT_CHECK_INPUT_PARAMETER(callback); /* register the callback */ _bt_set_cb(BT_EVENT_PROXIMITY_REPORTER_PROPERTY_CHANGED, callback, user_data); return BT_ERROR_NONE; } int bt_proximity_reporter_unset_property_changed_cb(bt_proximity_reporter_h reporter) { bt_proximity_reporter_s *reporter_l = (bt_proximity_reporter_s *)reporter; BT_CHECK_SUPPORTED_FEATURE(BT_FEATURE_COMMON); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(reporter_l); /* unregister the callback */ _bt_unset_cb(BT_EVENT_PROXIMITY_REPORTER_PROPERTY_CHANGED); return BT_ERROR_NONE; } int bt_proximity_monitor_set_linkloss_alert(bt_proximity_monitor_h monitor, int value) { int error_code = BT_ERROR_NONE; bt_proximity_monitor_s *monitor_s = (bt_proximity_monitor_s *)monitor; bluetooth_device_address_t addr_hex = { {0,} }; BT_CHECK_GATT_PXP_SUPPORT(); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(monitor); if (_bt_proximity_monitor_find(monitor_s->remote_address) == NULL) return BT_ERROR_REMOTE_DEVICE_NOT_CONNECTED; if (!(pxp_monitor_supported_services & BT_PROXIMITY_LINKLOSS_ALERT)) return BT_ERROR_NOT_SUPPORTED; _bt_convert_address_to_hex(&addr_hex, monitor_s->remote_address); error_code = _bt_get_error_code(bluetooth_proximity_monitor_set_property(&addr_hex, BT_PROXIMITY_LINKLOSS_ALERT, value)); if (error_code != BT_ERROR_NONE) BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); return error_code; } int bt_proximity_monitor_set_immediate_alert(bt_proximity_monitor_h monitor, int value) { int error_code = BT_ERROR_NONE; bt_proximity_monitor_s *monitor_s = (bt_proximity_monitor_s *)monitor; bluetooth_device_address_t addr_hex = { {0,} }; BT_CHECK_GATT_PXP_SUPPORT(); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(monitor); if (_bt_proximity_monitor_find(monitor_s->remote_address) == NULL) return BT_ERROR_REMOTE_DEVICE_NOT_CONNECTED; if (!(pxp_monitor_supported_services & BT_PROXIMITY_IMMEDIATE_ALERT)) return BT_ERROR_NOT_SUPPORTED; _bt_convert_address_to_hex(&addr_hex, monitor_s->remote_address); error_code = _bt_get_error_code(bluetooth_proximity_monitor_set_property(&addr_hex, BT_PROXIMITY_IMMEDIATE_ALERT, value)); if (error_code != BT_ERROR_NONE) BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); return error_code; } int bt_proximity_monitor_get_linkloss_alert(bt_proximity_monitor_h monitor, int *value) { int error_code = BT_ERROR_NONE; bt_proximity_monitor_s *monitor_s = (bt_proximity_monitor_s *)monitor; bluetooth_device_address_t addr_hex = { {0,} }; BT_CHECK_GATT_PXP_SUPPORT(); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(monitor); if (_bt_proximity_monitor_find(monitor_s->remote_address) == NULL) return BT_ERROR_REMOTE_DEVICE_NOT_CONNECTED; if (!(pxp_monitor_supported_services & BT_PROXIMITY_LINKLOSS_ALERT)) return BT_ERROR_NOT_SUPPORTED; _bt_convert_address_to_hex(&addr_hex, monitor_s->remote_address); error_code = _bt_get_error_code(bluetooth_proximity_monitor_get_property(&addr_hex, BT_PROXIMITY_LINKLOSS_ALERT, value)); if (error_code != BT_ERROR_NONE) BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); return error_code; } int bt_proximity_monitor_get_immediate_alert(bt_proximity_monitor_h monitor, int *value) { int error_code = BT_ERROR_NONE; bt_proximity_monitor_s *monitor_s = (bt_proximity_monitor_s *)monitor; bluetooth_device_address_t addr_hex = { {0,} }; BT_CHECK_GATT_PXP_SUPPORT(); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(monitor); if (_bt_proximity_monitor_find(monitor_s->remote_address) == NULL) return BT_ERROR_REMOTE_DEVICE_NOT_CONNECTED; if (!(pxp_monitor_supported_services & BT_PROXIMITY_IMMEDIATE_ALERT)) return BT_ERROR_NOT_SUPPORTED; _bt_convert_address_to_hex(&addr_hex, monitor_s->remote_address); error_code = _bt_get_error_code(bluetooth_proximity_monitor_get_property(&addr_hex, BT_PROXIMITY_IMMEDIATE_ALERT, value)); if (error_code != BT_ERROR_NONE) BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); return error_code; } int bt_proximity_monitor_get_signal_level(bt_proximity_monitor_h monitor, int *value) { int error_code = BT_ERROR_NONE; bt_proximity_monitor_s *monitor_s = (bt_proximity_monitor_s *)monitor; bluetooth_device_address_t addr_hex = { {0,} }; BT_CHECK_GATT_PXP_SUPPORT(); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(monitor); if (_bt_proximity_monitor_find(monitor_s->remote_address) == NULL) return BT_ERROR_REMOTE_DEVICE_NOT_CONNECTED; if (!(pxp_monitor_supported_services & BT_PROXIMITY_TX_POWER)) return BT_ERROR_NOT_SUPPORTED; _bt_convert_address_to_hex(&addr_hex, monitor_s->remote_address); error_code = _bt_get_error_code(bluetooth_proximity_monitor_get_property(&addr_hex, BT_PROXIMITY_TX_POWER, value)); if (error_code != BT_ERROR_NONE) BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); return error_code; } int bt_proximity_reporter_get_linkloss_alert(const char *remote_address, int *value) { int error_code = BT_ERROR_NONE; bluetooth_device_address_t addr_hex = { {0,} }; BT_CHECK_GATT_PXP_SUPPORT(); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(remote_address); if (reporter_s == NULL) return BT_ERROR_NOT_INITIALIZED; if (!(reporter_s->services_supported & BT_PROXIMITY_LINKLOSS_ALERT)) return BT_ERROR_NOT_SUPPORTED; _bt_convert_address_to_hex(&addr_hex, remote_address); error_code = _bt_get_error_code(bluetooth_proximity_reporter_get_property(&addr_hex, BT_PROXIMITY_LINKLOSS_ALERT, value)); if (error_code != BT_ERROR_NONE) BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); return error_code; } int bt_proximity_reporter_get_immediate_alert(const char *remote_address, int *value) { int error_code = BT_ERROR_NONE; bluetooth_device_address_t addr_hex = { {0,} }; BT_CHECK_GATT_PXP_SUPPORT(); BT_CHECK_INIT_STATUS(); BT_CHECK_INPUT_PARAMETER(remote_address); if (reporter_s == NULL) return BT_ERROR_NOT_INITIALIZED; if (!(reporter_s->services_supported & BT_PROXIMITY_IMMEDIATE_ALERT)) return BT_ERROR_NOT_SUPPORTED; _bt_convert_address_to_hex(&addr_hex, remote_address); error_code = _bt_get_error_code(bluetooth_proximity_reporter_get_property(&addr_hex, BT_PROXIMITY_IMMEDIATE_ALERT, value)); if (error_code != BT_ERROR_NONE) BT_ERR("%s(0x%08x)", _bt_convert_error_to_string(error_code), error_code); return error_code; } /* LCOV_EXCL_STOP */