--- /dev/null
+/*
+ * Bluetooth-frwk
+ *
+ * Contact: Abhishek Chandra (abhishek.ch@samsung.com)
+ *
+ * Copyright (c) 2018-2019 Samsung Electronics Co., Ltd.
+ *
+ * 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 <glib.h>
+#include <dlog.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <bluetooth-api.h>
+
+#include "bluetooth.h"
+#include "bluetooth_private.h"
+#include "bluetooth_internal.h"
+
+
+#define BT_CHECK_HRS_SUPPORT() \
+{ \
+ BT_CHECK_SUPPORTED_FEATURE(BT_FEATURE_COMMON); \
+ BT_CHECK_SUPPORTED_FEATURE(BT_FEATURE_LE); \
+ BT_CHECK_SUPPORTED_FEATURE(BT_FEATURE_HRS); \
+}
+
+/*======================================================================================================
+ Heart Rate Server - Structures
+========================================================================================================*/
+#define HEART_RATE_UUID "180d"
+#define HEART_RATE_MEASUREMENT_UUID "2a37"
+#define BODY_SENSOR_LOCATION_UUID "2a38"
+#define HEART_RATE_CONTROL_POINT_UUID "2a39"
+#define DEVICE_INFORMATION_UUID "180a"
+
+#define HEART_RATE_CHARAC_CFG_UUID "2902"
+#define DEVICE_INFO_CHARAC_MANUFACTURER_NAME_STRING "2A29"
+#define TODO 0
+//Connected Collector List
+typedef struct {
+ char *remote_address;
+ bool isconnected;
+} bt_hrp_collector_notify_info_s;
+
+//Server Info Local Structure
+typedef struct bt_hrp_server_info_s {
+ //fill with Setter API's
+ bool is_notify_cb_set;
+ bool is_hr_value_init;
+ int hr_value;
+ bool is_energy_supported;
+ int energy_value;
+ bool is_in_contact;
+ bool is_rr_interval_set;
+ int rr_interval;
+ bool is_manuf_name_set;
+ char *manufname;
+ bool is_bsl_set;
+ bt_gatt_server_h hrp_sensor; //Server Created only once
+ bt_gatt_h hrp_service; //heart rate service
+ bt_gatt_h dis_service; //device information service
+ bt_gatt_h hrs_characteristic; // heart rate char
+ bt_gatt_h dis_characteristic; // device info char
+ bt_gatt_h hrs_descriptor; // hrs cccd
+ bt_gatt_h bsl_characteristic; // body sensor location
+ bt_advertiser_h advertiser;
+ bt_hrp_sensor_advertising_state_changed_cb adv_app_cb; //application callback for updating state changes
+ bt_gatt_server_characteristic_notification_state_changed_cb notif_app_cb; //application callback for updating notification
+ bt_body_sensor_location_e body_sensor_location; //body sensor location
+ bool cccd_enabled;
+ GSList *hrs_collector_connected_list; //connected collector list , to be updated when read or write cccd request comes from client
+} bt_hrp_server_info_s;
+
+static guint adv_timer_id;
+GSList *sensor_list;
+static bt_hrp_server_info_s hrp_server_info_s;
+
+/*======================================================================================================
+ Heart Rate Server - Utility
+========================================================================================================*/
+
+/*Internal Functions*/
+static void __bt_hrp_sensor_read_value_requested_cb(
+ const char *remote_address, int request_id,
+ bt_gatt_server_h server, bt_gatt_h gatt_handle,
+ int offset, void *user_data)
+{
+
+ BT_INFO("[HR] __bt_gatt_server_read_value_requested_cb");
+ BT_INFO("[HR] remote_address %s", remote_address);
+ BT_INFO("[HR] req_id %d", request_id);
+ BT_INFO("[HR] server %s", (char *)server);
+ BT_INFO("[HR] gatt_handle %s", (char *)gatt_handle);
+ BT_INFO("[HR] Offset %d", offset);
+
+#if TODO
+ else {
+ /* Send Cached response*/
+ bt_gatt_server_send_response(request_id,
+ BLUETOOTH_GATT_ATT_REQUEST_TYPE_READ, offset,
+ resp_status, char_value_1, 3 - offset);
+ }
+#endif
+
+
+}
+
+
+static void __bt_hrp_sensor_write_value_requested_cb(const char *remote_address,
+ int request_id, bt_gatt_server_h server,
+ bt_gatt_h gatt_handle, bool response_needed, int offset,
+ const char *value, int len, void *user_data)
+{
+
+ BT_INFO("[HR] __bt_gatt_server_read_value_requested_cb");
+ BT_INFO("[HR] remote_address %s", remote_address);
+ BT_INFO("[HR] req_id %d", request_id);
+ BT_INFO("[HR] server %s", (char *)server);
+ BT_INFO("[HR] gatt_handle %s", (char *)gatt_handle);
+ BT_INFO("[HR] Offset %d", offset);
+
+#if TODO
+ else {
+ /* Send Cached response*/
+ bt_gatt_server_send_response(request_id,
+ BLUETOOTH_GATT_ATT_REQUEST_TYPE_WRITE, offset,
+ resp_status, char_value_1, 3 - offset);
+ }
+#endif
+}
+
+static void __bt_hrp_notification_send_cb(int result,
+ const char *remote_address, bt_gatt_server_h server,
+ bt_gatt_h characteristic, bool completed, void *user_data)
+{
+ BT_INFO("result [%s]", _bt_convert_error_to_string(result));
+ BT_INFO("remote_address : %s", remote_address);
+ BT_INFO("completed : %d", completed);
+ BT_INFO("characteristic : %p", characteristic);
+
+}
+
+static void __bt_hrp_reduced_interval_adv_state_changed_cb(int result,
+ bt_advertiser_h advertiser, bt_adapter_le_advertising_state_e adv_state,
+ void *user_data)
+{
+ BT_INFO("[HR]Result : %d", result);
+ BT_INFO("[HR]Advertiser : %p", advertiser);
+ BT_INFO("[HR]Advertising %s [%d]",
+ adv_state == BT_ADAPTER_LE_ADVERTISING_STARTED ?
+ "started" : "stopped", adv_state);
+
+ if (hrp_server_info_s.adv_app_cb && adv_state == BT_ADAPTER_LE_ADVERTISING_STOPPED)
+ hrp_server_info_s.adv_app_cb(result, adv_state, user_data);
+}
+
+static gboolean __hrp_timeout(gpointer user_data)
+{
+ int error_code = BT_ERROR_NONE;
+
+ BT_INFO("__hrp_timeout Timeout !!!\n");
+ adv_timer_id = -1;
+ error_code = bt_adapter_le_stop_advertising(hrp_server_info_s.advertiser);
+ if (error_code != BT_ERROR_NONE)
+ BT_ERR("[HR]add scan response data [0x%04x]", error_code);
+
+ return FALSE;
+}
+
+static void __bt_hrp_gatt_server_set_char_notification_state_change_cb(bool notify,
+ bt_gatt_server_h server, bt_gatt_h gatt_handle,
+ void *user_data)
+{
+ BT_INFO("[HR]__bt_gatt_server_notification_state_change_cb");
+ BT_INFO("[HR]notify %d", notify);
+ BT_INFO("[HR]server %s", (char *)server);
+ BT_INFO("[HR]gatt_handle %s", (char *)gatt_handle);
+
+ if (hrp_server_info_s.notif_app_cb)
+ hrp_server_info_s.notif_app_cb(notify, server, gatt_handle, user_data);
+
+}
+
+static void __bt_hrp_fast_interval_adv_state_changed_cb(int result,
+ bt_advertiser_h advertiser, bt_adapter_le_advertising_state_e adv_state,
+ void *user_data)
+{
+ BT_INFO("[HR]Result : %d", result);
+ BT_INFO("[HR]Advertiser : %p", advertiser);
+ BT_INFO("[HR]Advertising %s [%d]",
+ adv_state == BT_ADAPTER_LE_ADVERTISING_STARTED ?
+ "started" : "stopped", adv_state);
+
+ if (adv_state == BT_ADAPTER_LE_ADVERTISING_STARTED) {
+ adv_timer_id =
+ g_timeout_add_seconds(29/*Todo :30 Secs , 29 + time to set mode and restart adv*/,
+ __hrp_timeout, hrp_server_info_s.hrp_sensor);
+ } else { /*Advertisement Stopped*/
+ //cancel timer as User requested to STOP
+ if (adv_timer_id != -1) {
+ BT_DBG("g_source is removed");
+ g_source_remove(adv_timer_id);
+ adv_timer_id = -1;
+ } else { //Changing mode to Low energy as 30seconds are passed
+ int error_code = bt_adapter_le_set_advertising_mode(hrp_server_info_s.advertiser,
+ BT_ADAPTER_LE_ADVERTISING_MODE_LOW_ENERGY);
+ if (error_code != BT_ERROR_NONE)
+ BT_ERR("[HR]add scan response data [0x%04x]", error_code);
+
+ error_code = bt_adapter_le_start_advertising_new(hrp_server_info_s.advertiser,
+ __bt_hrp_reduced_interval_adv_state_changed_cb, NULL);
+ if (error_code < BT_ERROR_NONE)
+ BT_ERR("[HR]failed with [0x%04x]", error_code);
+
+ return;
+ }
+ }
+ /*todo : Send Start and stop enums*/
+ if (hrp_server_info_s.adv_app_cb)
+ hrp_server_info_s.adv_app_cb(result, adv_state, user_data);
+
+}
+
+static int __bt_hrp_create_primary_service(void)
+{
+ int error_code = BT_ERROR_NOT_INITIALIZED;
+ char hrs_char_value[3] ;
+ char desc_value[2] = {1, 0}; /* Notification enabled ,Indication disabled default*/
+
+ if (hrp_server_info_s.hrp_sensor == NULL)
+ return error_code;
+
+ error_code = bt_gatt_service_create(HEART_RATE_UUID, BT_GATT_SERVICE_TYPE_PRIMARY,
+ &hrp_server_info_s.hrp_service);
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]__createPrimaryService : %s \n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+
+ hrs_char_value[0] = (hrp_server_info_s.hr_value > 255) ? 1 : 0;//Uint-16 and Uint-8
+ hrs_char_value[1] = hrp_server_info_s.hr_value; /*Measurement Value*/
+ hrs_char_value[2] = 0; //??
+
+ BT_INFO("[HR] PRIMARY SERVICE CHAR CREATE\n");
+ error_code = bt_gatt_characteristic_create(HEART_RATE_MEASUREMENT_UUID, BT_GATT_PERMISSION_READ,
+ BT_GATT_PROPERTY_NOTIFY, hrs_char_value, sizeof(hrs_char_value),
+ &hrp_server_info_s.hrs_characteristic);
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]bt_gatt_characteristic_create HEART_RATE_MEASUREMENT_UUID : %s\n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+
+ BT_INFO("[HR] PRIMARY SERVICE SET READ CB\n");
+
+ error_code = bt_gatt_service_add_characteristic(hrp_server_info_s.hrp_service, hrp_server_info_s.hrs_characteristic);
+
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]bt_gatt_service_add_characteristic : %s\n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+
+ BT_INFO("[HR] PRIMARY SERVICE DESCRIPTOR CREATE\n");
+ error_code = bt_gatt_descriptor_create(HEART_RATE_CHARAC_CFG_UUID, BT_GATT_PERMISSION_READ | BT_GATT_PERMISSION_WRITE,
+ desc_value, sizeof(desc_value), &hrp_server_info_s.hrs_descriptor);
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]bt_gatt_descriptor_create HEART_RATE_CHARAC_CFG_UUID : %s\n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+
+ BT_INFO("[HR] PRIMARY SERVICE ADD DESCRIPTOR\n");
+
+ error_code = bt_gatt_characteristic_add_descriptor(hrp_server_info_s.hrs_characteristic, hrp_server_info_s.hrs_descriptor);
+
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]bt_gatt_characteristic_add_descriptor : %s\n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+ error_code = bt_gatt_server_set_read_value_requested_cb(hrp_server_info_s.hrs_descriptor,
+ __bt_hrp_sensor_read_value_requested_cb, NULL);
+
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]bt_gatt_server_set_read_value_requested_cb : %s\n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+
+ error_code = bt_gatt_server_set_write_value_requested_cb(hrp_server_info_s.hrs_descriptor,
+ __bt_hrp_sensor_write_value_requested_cb, NULL);
+
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]bt_gatt_server_set_read_value_requested_cb : %s\n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+
+
+ BT_INFO("[HR] PRIMARY SERVICE BSL\n");
+
+ if (hrp_server_info_s.body_sensor_location != BT_BSL_NOTSUPPORTED) {
+
+ char bs_location = hrp_server_info_s.body_sensor_location;
+
+ error_code = bt_gatt_characteristic_create(BODY_SENSOR_LOCATION_UUID, BT_GATT_PERMISSION_READ, BT_GATT_PROPERTY_READ,
+ &bs_location, sizeof(bs_location),
+ &hrp_server_info_s.bsl_characteristic);
+ BT_INFO("[HR] PRIMARY SERVICE BSL SET REQUEST CB\n");
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]bt_gatt_characteristic_create BODY_SENSOR_LOCATION_UUID : %s\n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+
+ bt_gatt_server_set_read_value_requested_cb(hrp_server_info_s.bsl_characteristic,
+ __bt_hrp_sensor_read_value_requested_cb, NULL);
+
+
+ if ((NULL != hrp_server_info_s.hrp_service) && (hrp_server_info_s.bsl_characteristic != NULL)) {
+ BT_INFO("[HR] PRIMARY SERVICE BSL ADD CHAR CB\n");
+
+ error_code = bt_gatt_service_add_characteristic(hrp_server_info_s.hrp_service, hrp_server_info_s.bsl_characteristic);
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]bt_gatt_service_add_characteristic : %s\n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+ }
+
+ BT_INFO("[HR] PRIMARY SERVICE REGISTER SERVICE\n");
+
+ error_code = bt_gatt_server_register_service(hrp_server_info_s.hrp_sensor, hrp_server_info_s.hrp_service);
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]bt_gatt_server_register_service : %s\n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+ }
+ BT_INFO("[HR] PRIMARY SERVICE EXIT!!!\n");
+
+ return error_code;
+}
+
+static int __bt_hrp_create_secondary_service(void)
+{
+ int error_code = BT_ERROR_NOT_INITIALIZED;
+
+ if (hrp_server_info_s.hrp_sensor == NULL)
+ return error_code;
+
+ error_code = bt_gatt_service_create(DEVICE_INFORMATION_UUID,
+ BT_GATT_SERVICE_TYPE_SECONDARY, &hrp_server_info_s.dis_service);
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]bt_gatt_service_create : %s \n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+
+ error_code = bt_gatt_characteristic_create(DEVICE_INFO_CHARAC_MANUFACTURER_NAME_STRING, BT_GATT_PERMISSION_READ,
+ BT_GATT_PROPERTY_READ, hrp_server_info_s.manufname,
+ strlen(hrp_server_info_s.manufname), &hrp_server_info_s.dis_characteristic);
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]bt_gatt_characteristic_create : %s\n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+
+ bt_gatt_server_set_read_value_requested_cb(hrp_server_info_s.dis_characteristic,
+ __bt_hrp_sensor_read_value_requested_cb, NULL);
+
+ error_code = bt_gatt_service_add_characteristic(hrp_server_info_s.dis_service, hrp_server_info_s.dis_characteristic);
+
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]bt_gatt_service_add_characteristic : %s\n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+
+ error_code = bt_gatt_server_set_characteristic_notification_state_change_cb
+ (hrp_server_info_s.hrs_characteristic,
+ __bt_hrp_gatt_server_set_char_notification_state_change_cb, NULL);
+
+ if (error_code != BT_ERROR_NONE)
+ BT_ERR("[HR]bt_gatt_server_set_characteristic_notification_state_change_cb : %s\n", _bt_convert_error_to_string(error_code));
+
+ error_code = bt_gatt_server_register_service(hrp_server_info_s.hrp_sensor, hrp_server_info_s.dis_service);
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]bt_gatt_server_register_service : %s\n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+
+ return error_code;
+}
+
+static int __bt_hrp_sensor_create_service(void)
+{
+
+ int error_code = BT_ERROR_NOT_INITIALIZED;
+
+ if (NULL == hrp_server_info_s.hrp_sensor) {
+ BT_ERR("[bt_hrp_sensor_create_service] Call Create First !!\n");
+ return error_code;
+ }
+
+ BT_INFO("[HR] CREATE SERVICE PRIMARY \n");
+ error_code = __bt_hrp_create_primary_service();
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]__bt_hrp_create_primary_service : %s \n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+
+ BT_INFO("[HR] CREATE SERVICE SECONDARY \n");
+ error_code = __bt_hrp_create_secondary_service();
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]__bt_hrp_create_secondary_service : %s \n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+ return error_code;
+}
+
+static void _bt_hrp_sensor_client_info_free(gpointer object)
+{
+ bt_hrp_collector_notify_info_s *client_s = (bt_hrp_collector_notify_info_s *)object;
+ g_free(client_s->remote_address);
+ client_s->isconnected = false;
+}
+
+static void _bt_hrp_sensor_initilize(void)
+{
+ hrp_server_info_s.is_notify_cb_set = false;
+ hrp_server_info_s.hrp_sensor = NULL;
+ hrp_server_info_s.hrp_service = NULL;
+ hrp_server_info_s.dis_service = NULL;
+ hrp_server_info_s.hrs_characteristic = NULL;
+ hrp_server_info_s.dis_characteristic = NULL;
+ hrp_server_info_s.hrs_descriptor = NULL;
+ hrp_server_info_s.advertiser = NULL;
+ hrp_server_info_s.adv_app_cb = NULL;
+ hrp_server_info_s.hrs_collector_connected_list = NULL;
+ hrp_server_info_s.is_in_contact = true;
+
+ hrp_server_info_s.cccd_enabled = true; //by default
+
+ if (hrp_server_info_s.is_hr_value_init == false)
+ hrp_server_info_s.hr_value = 0;
+
+ if (hrp_server_info_s.is_bsl_set == false)
+ hrp_server_info_s.body_sensor_location = BT_BSL_OTHER;
+
+ if (hrp_server_info_s.is_energy_supported == false)
+ hrp_server_info_s.energy_value = 0;
+
+ if (hrp_server_info_s.is_rr_interval_set == false)
+ hrp_server_info_s.rr_interval = 2; //Fill with some default value
+
+ if (hrp_server_info_s.is_manuf_name_set == false)
+ hrp_server_info_s.manufname = g_strdup("SAMSUNG");
+}
+
+void __bt_hrp_le_connection_state_changed_cb(int result,
+ const char *remote_address, bool connected)
+{
+
+ BT_INFO("[HR] bt_hrp_le_connection_state_changed_cb Result : %d", result);
+ BT_INFO("[HR]IsConnected : %d", connected);
+ BT_INFO("[HR]Remote Address : %s", remote_address);
+ bool isappend = true;
+ int error_code = BT_ERROR_NOT_INITIALIZED;
+
+ GSList *iter = hrp_server_info_s.hrs_collector_connected_list;
+
+ for (; iter; iter = g_slist_next(iter)) {
+ if ((iter) && (iter->data != NULL) &&
+ (((bt_hrp_collector_notify_info_s *)iter->data)->remote_address != NULL)) {
+ if (!g_ascii_strcasecmp(((bt_hrp_collector_notify_info_s *)iter->data)->remote_address,
+ remote_address)) {
+ ((bt_hrp_collector_notify_info_s *)iter->data)->isconnected = connected;
+ isappend = false;
+ break;
+ }
+ }
+ }
+
+ if (isappend) {
+ bt_hrp_collector_notify_info_s *client_s = g_malloc(sizeof(bt_hrp_collector_notify_info_s));
+ client_s->isconnected = connected;
+ client_s->remote_address = g_strdup(remote_address);
+ hrp_server_info_s.hrs_collector_connected_list =
+ g_slist_append(hrp_server_info_s.hrs_collector_connected_list, (gpointer)client_s);
+ }
+
+ if (connected == true && hrp_server_info_s.is_notify_cb_set == false) {
+ error_code = bt_gatt_server_notify_characteristic_changed_value(hrp_server_info_s.hrs_characteristic,
+ __bt_hrp_notification_send_cb, NULL, NULL);
+ if (error_code != BT_ERROR_NONE)
+ BT_ERR("bt_gatt_server_notify_characteristic_changed_value : %s\n", _bt_convert_error_to_string(error_code));
+ hrp_server_info_s.is_notify_cb_set = true;
+ }
+
+}
+
+/*Application Interfaces*/
+
+int bt_hrp_sensor_set_heartrate_value(int heartrate)
+{
+
+ BT_CHECK_HRS_SUPPORT();
+ BT_CHECK_INIT_STATUS();
+
+ if (heartrate < 0)
+ return BT_ERROR_INVALID_PARAMETER;
+
+ hrp_server_info_s.hr_value = heartrate;
+ hrp_server_info_s.is_hr_value_init = true;
+
+ return BT_ERROR_NONE;
+}
+
+int bt_hrp_sensor_set_location_value(bt_body_sensor_location_e location)
+{
+ BT_CHECK_HRS_SUPPORT();
+ BT_CHECK_INIT_STATUS();
+
+ if (location == BT_BSL_NOTSUPPORTED)
+ return BT_ERROR_INVALID_PARAMETER;
+
+
+ hrp_server_info_s.body_sensor_location = location;
+ hrp_server_info_s.is_bsl_set = true;
+
+ return BT_ERROR_NONE;
+}
+
+int bt_hrp_sensor_set_energy_value(int energy_value)
+{
+ BT_CHECK_HRS_SUPPORT();
+ BT_CHECK_INIT_STATUS();
+
+ if ((energy_value < 0) || (energy_value > 9))
+ return BT_ERROR_INVALID_PARAMETER;
+
+ hrp_server_info_s.energy_value = energy_value;
+ hrp_server_info_s.is_energy_supported = true;
+
+ return BT_ERROR_NOT_SUPPORTED;
+
+}
+
+int bt_hrp_sensor_set_contact_value(bool enable)
+{
+ BT_CHECK_HRS_SUPPORT();
+ BT_CHECK_INIT_STATUS();
+
+ hrp_server_info_s.is_in_contact = enable;
+
+ return BT_ERROR_NONE;
+}
+
+int bt_hrp_sensor_set_rr_interval(int interval)
+{
+ BT_CHECK_HRS_SUPPORT();
+ BT_CHECK_INIT_STATUS();
+
+ if ((interval < 0) || (interval > 9)) //Todo : Check for EE support
+ return BT_ERROR_INVALID_PARAMETER;
+
+ hrp_server_info_s.rr_interval = interval;
+ hrp_server_info_s.is_rr_interval_set = true;
+
+ return BT_ERROR_NOT_SUPPORTED;
+}
+
+int bt_hrp_sensor_set_device_manufacturer_name(char *manuf_name)
+{
+ BT_CHECK_HRS_SUPPORT();
+ BT_CHECK_INIT_STATUS();
+ BT_CHECK_INPUT_PARAMETER(manuf_name);
+
+ if (hrp_server_info_s.manufname)
+ g_free(hrp_server_info_s.manufname);
+
+ //Todo : Parsing Logic for manufacturer name .
+
+ hrp_server_info_s.manufname = g_strdup(manuf_name);
+ hrp_server_info_s.is_manuf_name_set = true;
+
+ return BT_ERROR_NONE;
+}
+
+int bt_hrp_sensor_set_sensor_notification_state_change_cb(
+ bt_gatt_server_characteristic_notification_state_changed_cb callback, void *user_data)
+{
+ BT_CHECK_HRS_SUPPORT();
+ BT_CHECK_INIT_STATUS();
+ BT_CHECK_INPUT_PARAMETER(callback);
+
+ hrp_server_info_s.notif_app_cb = callback;
+
+ return BT_ERROR_NONE;
+}
+
+int bt_hrp_sensor_create(void)
+{
+ int error_code = BT_ERROR_NONE;
+ bool is_in_use = false;
+
+ BT_CHECK_HRS_SUPPORT();
+ BT_CHECK_INIT_STATUS();
+
+ error_code = bt_adapter_is_service_used(HEART_RATE_UUID, &is_in_use);
+
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HRP- Sensor Create] bt_adapter_is_service_used : %s \n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+
+ if (true == is_in_use) {
+ BT_ERR("[HRP- Sensor Create] bt_adapter_is_service_used Server Already Created !!");
+ return BT_ERROR_ALREADY_DONE;
+ }
+
+ _bt_hrp_sensor_initilize();
+
+ error_code = bt_gatt_server_initialize();
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HRP- Sensor Create] Gatt Server Initialize error code : %s \n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+
+ error_code = bt_gatt_server_create(&hrp_server_info_s.hrp_sensor);
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HRP- Sensor Create] bt_gatt_server_create : %s \n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+
+ error_code = __bt_hrp_sensor_create_service();
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HRP- Sensor Create] __bt_hrp_sensor_create_service : %s \n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+ return error_code;
+}
+
+int bt_hrp_sensor_start(bt_hrp_sensor_advertising_state_changed_cb cb)
+{
+ int error_code = BT_ERROR_NOT_INITIALIZED;
+
+ BT_CHECK_HRS_SUPPORT();
+ BT_CHECK_INIT_STATUS();
+ BT_CHECK_INPUT_PARAMETER(cb);
+
+ if (NULL == hrp_server_info_s.hrp_sensor) {
+ BT_ERR("[HR Sensor START] Call Create First !!\n");
+ return error_code;
+ }
+
+ BT_INFO("[HR] START GATT SERVER \n");
+ error_code = bt_gatt_server_start();
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]bt_gatt_server_start : %s \n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+
+ if (hrp_server_info_s.advertiser == NULL) {
+
+ error_code = bt_adapter_le_create_advertiser(&hrp_server_info_s.advertiser);
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR Sensor START] bt_adapter_le_create_advertiser : %s \n", _bt_convert_error_to_string(error_code));
+ return error_code;
+ }
+ } else {
+
+ error_code = bt_adapter_le_clear_advertising_data(hrp_server_info_s.advertiser,
+ BT_ADAPTER_LE_PACKET_ADVERTISING);
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR Sensor START] clear advertising data [0x%04x]", error_code);
+ return error_code;
+ }
+ error_code = bt_adapter_le_clear_advertising_data(hrp_server_info_s.advertiser,
+ BT_ADAPTER_LE_PACKET_SCAN_RESPONSE);
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR Sensor START] clear scan response data [0x%04x]", error_code);
+ return error_code;
+ }
+ }
+
+ error_code = bt_adapter_le_add_advertising_service_solicitation_uuid(hrp_server_info_s.advertiser,
+ BT_ADAPTER_LE_PACKET_ADVERTISING, HEART_RATE_UUID);
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR Sensor START] add service_solicitation_uuid [0x%04x]", error_code);
+ return error_code;
+ }
+
+ error_code = bt_adapter_le_set_advertising_device_name(hrp_server_info_s.advertiser,
+ BT_ADAPTER_LE_PACKET_ADVERTISING, true);
+
+ if (error_code != BT_ERROR_NONE)
+ BT_ERR("[HR Sensor START] set device name [0x%04x]", error_code);
+
+
+ /*interval = 150*/
+ error_code = bt_adapter_le_set_advertising_mode(hrp_server_info_s.advertiser, BT_ADAPTER_LE_ADVERTISING_MODE_LOW_LATENCY);
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR Sensor START] add scan response data [0x%04x]", error_code);
+ return error_code;
+ }
+
+ hrp_server_info_s.adv_app_cb = cb;
+
+ error_code = bt_adapter_le_set_advertising_device_name(hrp_server_info_s.advertiser,
+ BT_ADAPTER_LE_PACKET_SCAN_RESPONSE, true);
+
+ if (error_code != BT_ERROR_NONE)
+ BT_ERR("[HR Sensor START] set device name [0x%04x]", error_code);
+
+ error_code = bt_adapter_le_start_advertising_new(hrp_server_info_s.advertiser,
+ __bt_hrp_fast_interval_adv_state_changed_cb, NULL);
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR Sensor START] failed with [0x%04x]", error_code);
+ return error_code;
+ }
+
+ BT_INFO("[HR Sensor START] bt_hrp_sensor_start exit\n");
+ return error_code;
+
+}
+
+int bt_hrp_sensor_stop()
+{
+ BT_CHECK_HRS_SUPPORT();
+ BT_CHECK_INIT_STATUS();
+
+ int error_code = BT_ERROR_NOT_INITIALIZED;
+
+ error_code = bt_adapter_le_stop_advertising(hrp_server_info_s.advertiser);
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]bt_hrp_sensor_stop failed with [0x%04x]", error_code);
+ return error_code;
+ }
+
+ return error_code;
+
+}
+
+int bt_hrp_sensor_update_heartrate_value(int heartrate)
+{
+ BT_CHECK_HRS_SUPPORT();
+ BT_CHECK_INIT_STATUS();
+
+ int error_code = BT_ERROR_NOT_INITIALIZED;
+
+ if (NULL == hrp_server_info_s.hrp_sensor) {
+ BT_ERR("[HR Sensor START] Call Create First !!\n");
+ return error_code;
+ }
+
+ if (hrp_server_info_s.cccd_enabled) {
+ error_code = bt_gatt_set_int_value(hrp_server_info_s.hrs_characteristic,
+ BT_DATA_TYPE_UINT16, heartrate, 1);
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]bt_gatt_set_int_value failed with [0x%04x]", error_code);
+ return error_code;
+ }
+ }
+
+ return error_code;
+
+}
+
+int bt_hrp_sensor_destroy()
+{
+ BT_CHECK_HRS_SUPPORT();
+ BT_CHECK_INIT_STATUS();
+
+ BT_INFO("[HR]bt_gatt_server_destroy GATT Destroy\n");
+
+ int error_code = BT_ERROR_NOT_INITIALIZED;
+ bt_gatt_destroy(hrp_server_info_s.hrs_descriptor);
+ bt_gatt_destroy(hrp_server_info_s.hrs_characteristic);
+ bt_gatt_destroy(hrp_server_info_s.dis_characteristic);
+ bt_gatt_destroy(hrp_server_info_s.bsl_characteristic);
+ bt_gatt_destroy(hrp_server_info_s.dis_service);
+ bt_gatt_destroy(hrp_server_info_s.hrp_service);
+
+ BT_INFO("[HR]bt_gatt_server_destroy Advertiser Destroy\n");
+
+ error_code = bt_adapter_le_destroy_advertiser(hrp_server_info_s.advertiser);
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]bt_hrp_sensor_stop failed with [0x%04x]", error_code);
+ return error_code;
+ }
+
+ BT_INFO("[HR]bt_gatt_server_destroy Server Destroy\n");
+
+ error_code = bt_gatt_server_destroy(hrp_server_info_s.hrp_sensor);
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]bt_gatt_server_destroy failed with [0x%04x]", error_code);
+ return error_code;
+ }
+
+ BT_INFO("[HR]bt_gatt_server_destroy Server Deinit\n");
+
+ error_code = bt_gatt_server_deinitialize();
+ if (error_code != BT_ERROR_NONE) {
+ BT_ERR("[HR]bt_gatt_server_destroy failed with [0x%04x]", error_code);
+ return error_code;
+ }
+
+ hrp_server_info_s.is_notify_cb_set = false;
+ hrp_server_info_s.is_hr_value_init = false;
+ hrp_server_info_s.hr_value = 0;
+ hrp_server_info_s.is_energy_supported = false;
+ hrp_server_info_s.energy_value = 0;
+ hrp_server_info_s.is_in_contact = false;
+ hrp_server_info_s.is_rr_interval_set = false;
+ hrp_server_info_s.rr_interval = 0;
+ hrp_server_info_s.is_manuf_name_set = false;
+ hrp_server_info_s.is_bsl_set = false;
+ hrp_server_info_s.hrp_service = NULL;
+ hrp_server_info_s.dis_service = NULL;
+ hrp_server_info_s.bsl_characteristic = NULL;
+ hrp_server_info_s.dis_characteristic = NULL;
+ hrp_server_info_s.hrs_characteristic = NULL;
+ hrp_server_info_s.hrs_descriptor = NULL;
+ hrp_server_info_s.advertiser = NULL;
+
+ if (hrp_server_info_s.manufname)
+ g_free(hrp_server_info_s.manufname);
+
+ hrp_server_info_s.adv_app_cb = NULL;
+ hrp_server_info_s.notif_app_cb = NULL;
+ hrp_server_info_s.body_sensor_location = BT_BSL_NOTSUPPORTED;
+ hrp_server_info_s.cccd_enabled = false;
+
+ g_slist_free_full(hrp_server_info_s.hrs_collector_connected_list, _bt_hrp_sensor_client_info_free);
+
+ hrp_server_info_s.hrs_collector_connected_list = NULL;
+
+ BT_INFO("[HR]bt_gatt_server_destroy Exit\n");
+
+
+ return error_code;
+
+}
+