aboutsummaryrefslogtreecommitdiff
path: root/gps/loc_api/ds_api
diff options
context:
space:
mode:
authorBruno Martins <bgcngm@gmail.com>2016-12-04 12:06:39 +0000
committerdavidevinavil <davidevinavil@gmail.com>2017-01-21 18:29:23 +0100
commit4bfff05a88cb2baca116cd03a27b6bc8937e07f7 (patch)
tree06e60070c6e3d4ccc6643b65b06a9e94726146d5 /gps/loc_api/ds_api
parent6818ac6afaa76a95c469707f5c1ddcfead73a634 (diff)
z2_plus: Import QC location source
* Tag: LA.UM.5.5.r1-01800-8x96.0 Change-Id: Ib33b01591c1743dd8b217a81a580bc3c2b13bd05
Diffstat (limited to 'gps/loc_api/ds_api')
-rw-r--r--gps/loc_api/ds_api/Android.mk49
-rw-r--r--gps/loc_api/ds_api/ds_client.c834
-rw-r--r--gps/loc_api/ds_api/ds_client.h279
3 files changed, 1162 insertions, 0 deletions
diff --git a/gps/loc_api/ds_api/Android.mk b/gps/loc_api/ds_api/Android.mk
new file mode 100644
index 0000000..3bc94f2
--- /dev/null
+++ b/gps/loc_api/ds_api/Android.mk
@@ -0,0 +1,49 @@
+ifneq ($(BUILD_TINY_ANDROID),true)
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libloc_ds_api
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SHARED_LIBRARIES := \
+ libutils \
+ libcutils \
+ libqmi_cci \
+ libqmi_common_so \
+ libgps.utils \
+ libdsi_netctrl \
+ libqmiservices \
+ libloc_pla
+
+LOCAL_SRC_FILES += \
+ ds_client.c
+
+LOCAL_CFLAGS += \
+ -fno-short-enums \
+ -D_ANDROID_
+
+LOCAL_COPY_HEADERS_TO:= libloc_ds_api/
+
+LOCAL_COPY_HEADERS:= \
+ ds_client.h
+
+LOCAL_LDFLAGS += -Wl,--export-dynamic
+
+## Includes
+LOCAL_C_INCLUDES := \
+ $(TARGET_OUT_HEADERS)/libloc_eng \
+ $(TARGET_OUT_HEADERS)/qmi-framework/inc \
+ $(TARGET_OUT_HEADERS)/qmi/inc \
+ $(TARGET_OUT_HEADERS)/gps.utils \
+ $(TARGET_OUT_HEADERS)/data/inc \
+ $(TARGET_OUT_HEADERS)/libloc_pla
+
+
+LOCAL_PRELINK_MODULE := false
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif # not BUILD_TINY_ANDROID
diff --git a/gps/loc_api/ds_api/ds_client.c b/gps/loc_api/ds_api/ds_client.c
new file mode 100644
index 0000000..c8250bd
--- /dev/null
+++ b/gps/loc_api/ds_api/ds_client.c
@@ -0,0 +1,834 @@
+/* Copyright (c) 2013, 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation, nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_ds_client"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <wireless_data_service_v01.h>
+#include <loc_log.h>
+#include <qmi_client.h>
+#include <qmi_idl_lib.h>
+#include <qmi_cci_target_ext.h>
+#include <qmi_cci_target.h>
+#include <qmi_cci_common.h>
+#include <dsi_netctrl.h>
+#include <ds_client.h>
+#include <sys/time.h>
+#include <platform_lib_includes.h>
+
+/**
+ * @file
+ * @brief DS client API declaration.
+ *
+ * @ingroup loc_ds_api
+ */
+
+/**
+ * @addtogroup loc_ds_api DS client support for location
+ * @{
+ */
+
+//Timeout to wait for wds service notification from qmi
+#define DS_CLIENT_SERVICE_TIMEOUT (4000)
+//Max timeout for the service to come up
+#define DS_CLIENT_SERVICE_TIMEOUT_TOTAL (40000)
+//Timeout for the service to respond to sync msg
+#define DS_CLIENT_SYNC_MSG_TIMEOUT (5000)
+/*Request messages the WDS client can send to the WDS service*/
+typedef union
+{
+ /*Requests the service for a list of all profiles present*/
+ wds_get_profile_list_req_msg_v01 *p_get_profile_list_req;
+ /*Requests the service for a profile's settings*/
+ wds_get_profile_settings_req_msg_v01 *p_get_profile_settings_req;
+}ds_client_req_union_type;
+
+/*Response indications that are sent by the WDS service*/
+typedef union
+{
+ wds_get_profile_list_resp_msg_v01 *p_get_profile_list_resp;
+ wds_get_profile_settings_resp_msg_v01 *p_get_profile_setting_resp;
+}ds_client_resp_union_type;
+
+static const loc_name_val_s_type event_string_tbl[DSI_EVT_MAX] =
+{
+ NAME_VAL(DSI_EVT_INVALID),
+ NAME_VAL(DSI_EVT_NET_IS_CONN),
+ NAME_VAL(DSI_EVT_NET_NO_NET),
+ NAME_VAL(DSI_EVT_PHYSLINK_DOWN_STATE),
+ NAME_VAL(DSI_EVT_PHYSLINK_UP_STATE),
+ NAME_VAL(DSI_EVT_NET_RECONFIGURED),
+ NAME_VAL(DSI_EVT_WDS_CONNECTED)
+};
+
+typedef struct
+{
+ ds_client_event_ind_cb_type *event_cb;
+ void *caller_cookie;
+}ds_caller_data;
+
+typedef struct {
+ //Global dsi handle
+ dsi_hndl_t dsi_net_handle;
+ //Handle to caller's data
+ ds_caller_data caller_data;
+} ds_client_session_data;
+
+static void net_ev_cb
+(
+ dsi_hndl_t handle,
+ void* user_data,
+ dsi_net_evt_t evt,
+ dsi_evt_payload_t *payload_ptr
+)
+{
+ int i;
+ (void)handle;
+ (void)user_data;
+ (void)payload_ptr;
+ ds_caller_data *callback_data = (ds_caller_data *)user_data;
+
+ LOC_LOGD("%s:%d]: Enter. Callback data: %p\n", __func__, __LINE__, callback_data);
+ if(evt > DSI_EVT_INVALID && evt < DSI_EVT_MAX)
+ {
+ LOC_LOGE("%s:%d]: Callback received: %s",
+ __func__, __LINE__,
+ loc_get_name_from_val(event_string_tbl,
+ sizeof(event_string_tbl)/sizeof(event_string_tbl[0]), evt));
+
+ switch(evt) {
+ case DSI_EVT_NET_IS_CONN:
+ case DSI_EVT_WDS_CONNECTED:
+ {
+ LOC_LOGD("%s:%d]: Emergency call started\n", __func__, __LINE__);
+ callback_data->event_cb(E_DS_CLIENT_DATA_CALL_CONNECTED,
+ callback_data->caller_cookie);
+ break;
+ }
+ case DSI_EVT_NET_NO_NET:
+ {
+ LOC_LOGD("%s:%d]: Emergency call stopped\n", __func__, __LINE__);
+ callback_data->event_cb(E_DS_CLIENT_DATA_CALL_DISCONNECTED,
+ callback_data->caller_cookie);
+ break;
+ }
+ default:
+ LOC_LOGD("%s:%d]: uninteresting event\n", __func__, __LINE__);
+ }
+ }
+ LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
+}
+
+/*This function is called to obtain a handle to the QMI WDS service*/
+static ds_client_status_enum_type
+ds_client_qmi_ctrl_point_init(qmi_client_type *p_wds_qmi_client)
+{
+ qmi_client_type wds_qmi_client, notifier = NULL;
+ ds_client_status_enum_type status = E_DS_CLIENT_SUCCESS;
+ qmi_service_info *p_service_info = NULL;
+ uint32_t num_services = 0, num_entries = 0;
+ qmi_client_error_type ret = QMI_NO_ERR;
+ unsigned char no_signal = 0;
+ qmi_client_os_params os_params;
+ int timeout = 0;
+
+ LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
+
+ //Get service object for QMI_WDS service
+ qmi_idl_service_object_type ds_client_service_object =
+ wds_get_service_object_v01();
+ if(ds_client_service_object == NULL) {
+ LOC_LOGE("%s:%d]: wds_get_service_object_v01 failed\n" ,
+ __func__, __LINE__);
+ status = E_DS_CLIENT_FAILURE_INTERNAL;
+ goto err;
+ }
+
+ //get service addressing information
+ ret = qmi_client_get_service_list(ds_client_service_object, NULL, NULL,
+ &num_services);
+ LOC_LOGD("%s:%d]: qmi_client_get_service_list() first try ret %d, "
+ "num_services %d]\n", __func__, __LINE__, ret, num_services);
+ if(ret != QMI_NO_ERR) {
+ //Register for service notification
+ ret = qmi_client_notifier_init(ds_client_service_object, &os_params, &notifier);
+ if (ret != QMI_NO_ERR) {
+ LOC_LOGE("%s:%d]: qmi_client_notifier_init failed %d\n",
+ __func__, __LINE__, ret);
+ status = E_DS_CLIENT_FAILURE_INTERNAL;
+ goto err;
+ }
+
+ do {
+ QMI_CCI_OS_SIGNAL_CLEAR(&os_params);
+ ret = qmi_client_get_service_list(ds_client_service_object, NULL,
+ NULL, &num_services);
+ if(ret != QMI_NO_ERR) {
+ QMI_CCI_OS_SIGNAL_WAIT(&os_params, DS_CLIENT_SERVICE_TIMEOUT);
+ no_signal = QMI_CCI_OS_SIGNAL_TIMED_OUT(&os_params);
+ if(!no_signal)
+ ret = qmi_client_get_service_list(ds_client_service_object, NULL,
+ NULL, &num_services);
+ }
+ timeout += DS_CLIENT_SERVICE_TIMEOUT;
+ LOC_LOGV("%s:%d]: qmi_client_get_service_list() returned ret: %d,"
+ "no_signal: %d, total timeout: %d\n", __func__, __LINE__,
+ ret, no_signal, timeout);
+ } while( (timeout < DS_CLIENT_SERVICE_TIMEOUT_TOTAL) &&
+ no_signal &&
+ (ret != QMI_NO_ERR) );
+ }
+
+ //Handle failure cases
+ if(num_services == 0 || ret != QMI_NO_ERR) {
+ if(!no_signal) {
+ LOC_LOGE("%s:%d]: qmi_client_get_service_list failed even though"
+ "service is up! Error: %d \n", __func__, __LINE__, ret);
+ status = E_DS_CLIENT_FAILURE_INTERNAL;
+ }
+ else {
+ LOC_LOGE("%s:%d]: qmi_client_get_service_list failed after retries"
+ "Error: %d \n", __func__, __LINE__, ret);
+ status = E_DS_CLIENT_FAILURE_TIMEOUT;
+ }
+ goto err;
+ }
+
+ LOC_LOGD("%s:%d]: qmi_client_get_service_list succeeded\n", __func__, __LINE__);
+
+ //Success
+ p_service_info = (qmi_service_info *)malloc(num_services * sizeof(qmi_service_info));
+ if(p_service_info == NULL) {
+ LOC_LOGE("%s:%d]: could not allocate memory for serviceInfo !!\n",
+ __func__, __LINE__);
+ status = E_DS_CLIENT_FAILURE_INTERNAL;
+ goto err;
+ }
+ num_entries = num_services;
+
+ //Populate service info
+ ret = qmi_client_get_service_list(ds_client_service_object, p_service_info,
+ &num_entries, &num_services);
+ if(ret != QMI_NO_ERR) {
+ LOC_LOGE("%s:%d]: qmi_client_get_service_list failed. ret: %d \n",
+ __func__, __LINE__, ret);
+ status = E_DS_CLIENT_FAILURE_INTERNAL;
+ goto err;
+ }
+
+ //Initialize wds_qmi_client
+ LOC_LOGD("%s:%d]: Initializing WDS client with qmi_client_init\n", __func__,
+ __LINE__);
+ ret = qmi_client_init(&p_service_info[0], ds_client_service_object,
+ NULL, NULL, NULL, &wds_qmi_client);
+ if(ret != QMI_NO_ERR) {
+ LOC_LOGE("%s:%d]: qmi_client_init Error. ret: %d\n", __func__, __LINE__, ret);
+ status = E_DS_CLIENT_FAILURE_INTERNAL;
+ goto err;
+ }
+ LOC_LOGD("%s:%d]: WDS client initialized with qmi_client_init\n", __func__,
+ __LINE__);
+
+ //Store WDS QMI client handle in the parameter passed in
+ *p_wds_qmi_client = wds_qmi_client;
+
+ status = E_DS_CLIENT_SUCCESS;
+ LOC_LOGD("%s:%d]: init success\n", __func__, __LINE__);
+
+ if(notifier)
+ qmi_client_release(notifier);
+
+err:
+ if(p_service_info)
+ free(p_service_info);
+
+ LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
+ return status;
+}
+
+/*This function reads the error code from within the response struct*/
+static ds_client_status_enum_type ds_client_convert_qmi_response(
+ uint32_t req_id,
+ ds_client_resp_union_type *resp_union)
+{
+ ds_client_status_enum_type ret = E_DS_CLIENT_FAILURE_GENERAL;
+ LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
+ switch(req_id)
+ {
+ case QMI_WDS_GET_PROFILE_LIST_REQ_V01 :
+ {
+ if(resp_union->p_get_profile_list_resp->resp.error !=
+ QMI_ERR_NONE_V01) {
+ LOC_LOGE("%s:%d]: Response error: %d", __func__, __LINE__,
+ resp_union->p_get_profile_list_resp->resp.error);
+ }
+ else
+ ret = E_DS_CLIENT_SUCCESS;
+ }
+ break;
+
+ case QMI_WDS_GET_PROFILE_SETTINGS_REQ_V01 :
+ {
+ if(resp_union->p_get_profile_setting_resp->resp.error !=
+ QMI_ERR_NONE_V01) {
+ LOC_LOGE("%s:%d]: Response error: %d", __func__, __LINE__,
+ resp_union->p_get_profile_setting_resp->resp.error);
+ }
+ else
+ ret = E_DS_CLIENT_SUCCESS;
+ }
+ break;
+
+ default:
+ LOC_LOGE("%s:%d]: Unknown request ID\n", __func__, __LINE__);
+ }
+ LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
+ return ret;
+}
+
+
+static ds_client_status_enum_type ds_client_send_qmi_sync_req(
+ qmi_client_type *ds_client_handle,
+ uint32_t req_id,
+ ds_client_resp_union_type *resp_union,
+ ds_client_req_union_type *req_union)
+{
+ uint32_t req_len = 0;
+ uint32_t resp_len = 0;
+ ds_client_status_enum_type ret = E_DS_CLIENT_SUCCESS;
+ qmi_client_error_type qmi_ret = QMI_NO_ERR;
+ LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
+ switch(req_id)
+ {
+ case QMI_WDS_GET_PROFILE_LIST_REQ_V01 :
+ {
+ req_len = sizeof(wds_get_profile_list_req_msg_v01);
+ resp_len = sizeof(wds_get_profile_list_resp_msg_v01);
+ LOC_LOGD("%s:%d]: req_id = GET_PROFILE_LIST_REQ\n",
+ __func__, __LINE__);
+ }
+ break;
+
+ case QMI_WDS_GET_PROFILE_SETTINGS_REQ_V01 :
+ {
+ req_len = sizeof(wds_get_profile_settings_req_msg_v01);
+ resp_len = sizeof(wds_get_profile_settings_resp_msg_v01);
+ LOC_LOGD("%s:%d]: req_id = GET_PROFILE_SETTINGS_REQ\n",
+ __func__, __LINE__);
+ }
+ break;
+
+ default:
+ LOC_LOGE("%s:%d]: Error unknown req_id=%d\n", __func__, __LINE__,
+ req_id);
+ ret = E_DS_CLIENT_FAILURE_INVALID_PARAMETER;
+ goto err;
+ }
+
+ LOC_LOGD("%s:%d]: req_id=%d, len = %d; resp_len= %d\n", __func__, __LINE__,
+ req_id, req_len, resp_len);
+ //Send msg through QCCI
+ qmi_ret = qmi_client_send_msg_sync(
+ *ds_client_handle,
+ req_id,
+ (void *)req_union->p_get_profile_list_req,
+ req_len,
+ (void *)resp_union->p_get_profile_list_resp,
+ resp_len,
+ DS_CLIENT_SYNC_MSG_TIMEOUT);
+ LOC_LOGD("%s:%d]: qmi_client_send_msg_sync returned: %d", __func__, __LINE__, qmi_ret);
+
+ if(qmi_ret != QMI_NO_ERR) {
+ ret = E_DS_CLIENT_FAILURE_INTERNAL;
+ goto err;
+ }
+
+ ret = ds_client_convert_qmi_response(req_id, resp_union);
+
+err:
+ LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
+ return ret;
+}
+
+/*This function obtains the list of supported profiles*/
+static ds_client_status_enum_type ds_client_get_profile_list(
+ qmi_client_type *ds_client_handle,
+ ds_client_resp_union_type *profile_list_resp_msg,
+ wds_profile_type_enum_v01 profile_type)
+{
+ ds_client_status_enum_type ret = E_DS_CLIENT_SUCCESS;
+ ds_client_req_union_type req_union;
+ LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
+
+ req_union.p_get_profile_list_req = NULL;
+ req_union.p_get_profile_list_req = (wds_get_profile_list_req_msg_v01 *)
+ calloc(1, sizeof(wds_get_profile_list_req_msg_v01));
+ if(req_union.p_get_profile_list_req == NULL) {
+ LOC_LOGE("%s:%d]: Could not allocate memory for"
+ "wds_get_profile_list_req_msg_v01\n", __func__, __LINE__);
+ goto err;
+ }
+ //Populate required members of the request structure
+ req_union.p_get_profile_list_req->profile_type_valid = 1;
+ req_union.p_get_profile_list_req->profile_type = profile_type;
+ ret = ds_client_send_qmi_sync_req(ds_client_handle,
+ QMI_WDS_GET_PROFILE_LIST_REQ_V01,
+ profile_list_resp_msg, &req_union);
+ if(ret != E_DS_CLIENT_SUCCESS) {
+ LOC_LOGE("%s:%d]: ds_client_send_qmi_req failed. ret: %d\n",
+ __func__, __LINE__, ret);
+ goto err;
+ }
+err:
+ LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
+ if(req_union.p_get_profile_list_req)
+ free(req_union.p_get_profile_list_req);
+ return ret;
+}
+
+/*This function obtains settings for the profile specified by
+ the profile_identifier*/
+static ds_client_status_enum_type ds_client_get_profile_settings(
+ qmi_client_type *ds_client_handle,
+ ds_client_resp_union_type *profile_settings_resp_msg,
+ wds_profile_identifier_type_v01 *profile_identifier)
+{
+ ds_client_status_enum_type ret = E_DS_CLIENT_SUCCESS;
+ ds_client_req_union_type req_union;
+
+ LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
+ //Since it's a union containing a pointer to a structure,
+ //following entities have the same address
+ //- req_union
+ //- req_union.p_get_profile_settings_req
+ //- req_union.p_get_profile_settings_req->profile
+ //so we can very well assign req_union = profile_identifier
+ req_union.p_get_profile_settings_req =
+ (wds_get_profile_settings_req_msg_v01 *)profile_identifier;
+ ret = ds_client_send_qmi_sync_req(ds_client_handle,
+ QMI_WDS_GET_PROFILE_SETTINGS_REQ_V01,
+ profile_settings_resp_msg, &req_union);
+ if(ret != E_DS_CLIENT_SUCCESS) {
+ LOC_LOGE("%s:%d]: ds_client_send_qmi_req failed. ret: %d\n",
+ __func__, __LINE__, ret);
+ goto err;
+ }
+err:
+ LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
+ return ret;
+}
+
+/**
+ * @brief Starts a data call using the profile number provided
+ *
+ * The function uses parameters provided from @a ds_client_open_call_type
+ * call result.
+ *
+ * @param[in] client_handle Client handle
+ * @param[in] profile_index Profile index
+ * @param[in] pdp_type PDP type
+ *
+ * @return Operation result
+ * @retval E_DS_CLIENT_SUCCESS On success.
+ * @retval E_DS_CLIENT_FAILURE... On error.
+ */
+static ds_client_status_enum_type ds_client_start_call
+(
+ dsClientHandleType client_handle,
+ int profile_index,
+ int pdp_type
+)
+{
+ ds_client_status_enum_type ret = E_DS_CLIENT_FAILURE_GENERAL;
+ dsi_call_param_value_t param_info;
+ dsi_hndl_t dsi_handle;
+ ds_client_session_data *ds_global_data = (ds_client_session_data *)client_handle;
+ LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
+ if(ds_global_data == NULL) {
+ LOC_LOGE("%s:%d]: Null callback parameter\n", __func__, __LINE__);
+ goto err;
+ }
+ dsi_handle = ds_global_data->dsi_net_handle;
+ //Set profile index as call parameter
+ param_info.buf_val = NULL;
+ param_info.num_val = profile_index;
+ dsi_set_data_call_param(dsi_handle,
+ DSI_CALL_INFO_UMTS_PROFILE_IDX,
+ &param_info);
+
+ //Set IP Version as call parameter
+ param_info.buf_val = NULL;
+ param_info.num_val = pdp_type;
+ dsi_set_data_call_param(dsi_handle,
+ DSI_CALL_INFO_IP_VERSION,
+ &param_info);
+ LOC_LOGD("%s:%d]: Starting emergency call with profile index %d; pdp_type:%d\n",
+ __func__, __LINE__, profile_index, pdp_type);
+ if(dsi_start_data_call(dsi_handle) == DSI_SUCCESS) {
+ LOC_LOGD("%s:%d]: Sent request to start data call\n",
+ __func__, __LINE__);
+ ret = E_DS_CLIENT_SUCCESS;
+ }
+ else {
+ LOC_LOGE("%s:%d]: Could not send req to start data call \n", __func__, __LINE__);
+ ret = E_DS_CLIENT_FAILURE_GENERAL;
+ goto err;
+ }
+
+err:
+ LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
+ return ret;
+
+}
+
+/**
+ * @brief Prepares for call.
+ *
+ * Obtains a handle to the dsi_netctrl layer and looks up the profile
+ * to make the call. As of now. It only searches for profiles that
+ * support emergency calls.
+ *
+ * Function to open an emergency call. Does the following things:
+ * - Obtains a handle to the WDS service
+ * - Obtains a list of profiles configured in the modem
+ * - Queries each profile and obtains settings to check if emergency calls
+ * are supported
+ * - Returns the profile index that supports emergency calls
+ * - Returns handle to dsi_netctrl
+ *
+ * @param[out] client_handle Client handle to initialize.
+ * @param[in] callback Pointer to callback function table.
+ * @param[in] cookie Client's cookie for using with callback calls.
+ * @param[out] profile_index Pointer to profile index number.
+ * @param[out] pdp_type Pointer to PDP type.
+ *
+ * @return Operation result
+ * @retval E_DS_CLIENT_SUCCESS On success. Output parameters are initialized.
+ * @retval E_DS_CLIENT_FAILURE... On error.
+ */
+static ds_client_status_enum_type ds_client_open_call
+(
+ dsClientHandleType *client_handle,
+ const ds_client_cb_data *callback,
+ void *cookie,
+ int *profile_index,
+ int *pdp_type
+)
+{
+ ds_client_status_enum_type ret = E_DS_CLIENT_FAILURE_GENERAL;
+ ds_client_resp_union_type profile_list_resp_msg;
+ ds_client_resp_union_type profile_settings_resp_msg;
+ wds_profile_identifier_type_v01 profile_identifier;
+ uint32_t i=0;
+ dsi_hndl_t dsi_handle;
+ ds_client_session_data **ds_global_data = (ds_client_session_data **)client_handle;
+ unsigned char call_profile_index_found = 0;
+ uint32_t emergency_profile_index=0;
+ qmi_client_type wds_qmi_client;
+
+ profile_list_resp_msg.p_get_profile_list_resp = NULL;
+ profile_settings_resp_msg.p_get_profile_setting_resp = NULL;
+
+ LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
+ if(callback == NULL || ds_global_data == NULL) {
+ LOC_LOGE("%s:%d]: Null callback parameter\n", __func__, __LINE__);
+ goto err;
+ }
+
+ ret = ds_client_qmi_ctrl_point_init(&wds_qmi_client);
+ if(ret != E_DS_CLIENT_SUCCESS) {
+ LOC_LOGE("%s:%d]: ds_client_qmi_ctrl_point_init failed. ret: %d\n",
+ __func__, __LINE__, ret);
+ goto err;
+ }
+
+ //Allocate memory for the response msg to obtain a list of profiles
+ profile_list_resp_msg.p_get_profile_list_resp = (wds_get_profile_list_resp_msg_v01 *)
+ calloc(1, sizeof(wds_get_profile_list_resp_msg_v01));
+ if(profile_list_resp_msg.p_get_profile_list_resp == NULL) {
+ LOC_LOGE("%s:%d]: Could not allocate memory for"
+ "p_get_profile_list_resp\n", __func__, __LINE__);
+ ret = E_DS_CLIENT_FAILURE_NOT_ENOUGH_MEMORY;
+ goto err;
+ }
+
+ LOC_LOGD("%s:%d]: Getting profile list\n", __func__, __LINE__);
+ ret = ds_client_get_profile_list(&wds_qmi_client,
+ &profile_list_resp_msg,
+ WDS_PROFILE_TYPE_3GPP_V01);
+ if(ret != E_DS_CLIENT_SUCCESS) {
+ LOC_LOGE("%s:%d]: ds_client_get_profile_list failed. ret: %d\n",
+ __func__, __LINE__, ret);
+ goto err;
+ }
+ LOC_LOGD("%s:%d]: Got profile list; length = %d\n", __func__, __LINE__,
+ profile_list_resp_msg.p_get_profile_list_resp->profile_list_len);
+
+ //Allocate memory for the response msg to obtain profile settings
+ //We allocate memory for only one response msg and keep re-using it
+ profile_settings_resp_msg.p_get_profile_setting_resp =
+ (wds_get_profile_settings_resp_msg_v01 *)
+ calloc(1, sizeof(wds_get_profile_settings_resp_msg_v01));
+ if(profile_settings_resp_msg.p_get_profile_setting_resp == NULL) {
+ LOC_LOGE("%s:%d]: Could not allocate memory for"
+ "p_get_profile_setting_resp\n", __func__, __LINE__);
+ ret = E_DS_CLIENT_FAILURE_NOT_ENOUGH_MEMORY;
+ goto err;
+ }
+
+ //Loop over the list of profiles to find a profile that supports
+ //emergency calls
+ for(i=0; i < profile_list_resp_msg.p_get_profile_list_resp->profile_list_len; i++) {
+ /*QMI_WDS_GET_PROFILE_SETTINGS_REQ requires an input data
+ structure that is of type wds_profile_identifier_type_v01
+ We have to fill that structure for each profile from the
+ info obtained from the profile list*/
+ //copy profile type
+ profile_identifier.profile_type =
+ profile_list_resp_msg.p_get_profile_list_resp->profile_list[i].profile_type;
+ //copy profile index
+ profile_identifier.profile_index =
+ profile_list_resp_msg.p_get_profile_list_resp->profile_list[i].profile_index;
+
+ ret = ds_client_get_profile_settings(&wds_qmi_client,
+ &profile_settings_resp_msg,
+ &profile_identifier);
+ if(ret != E_DS_CLIENT_SUCCESS) {
+ LOC_LOGE("%s:%d]: ds_client_get_profile_settings failed. ret: %d\n",
+ __func__, __LINE__, ret);
+ goto err;
+ }
+ LOC_LOGD("%s:%d]: Got profile setting for profile %d; name: %s\n",
+ __func__, __LINE__, i,
+ profile_settings_resp_msg.p_get_profile_setting_resp->profile_name);
+
+ if(profile_settings_resp_msg.p_get_profile_setting_resp->support_emergency_calls_valid) {
+ if(profile_settings_resp_msg.p_get_profile_setting_resp->support_emergency_calls) {
+ LOC_LOGD("%s:%d]: Found emergency profile in profile %d"
+ , __func__, __LINE__, i);
+ call_profile_index_found = 1;
+ emergency_profile_index = profile_identifier.profile_index;
+
+ if(profile_settings_resp_msg.p_get_profile_setting_resp->pdp_type_valid) {
+ *pdp_type = (int)profile_settings_resp_msg.p_get_profile_setting_resp->pdp_type;
+ LOC_LOGD("%s:%d]: pdp_type: %d\n", __func__, __LINE__, *pdp_type);
+ switch(*pdp_type) {
+ case WDS_PDP_TYPE_PDP_IPV4_V01:
+ *pdp_type = DSI_IP_VERSION_4;
+ break;
+ case WDS_PDP_TYPE_PDP_IPV6_V01:
+ *pdp_type = DSI_IP_VERSION_6;
+ break;
+ case WDS_PDP_TYPE_PDP_IPV4V6_V01:
+ *pdp_type = DSI_IP_VERSION_4_6;
+ break;
+ default:
+ LOC_LOGE("%s:%d]: pdp_type unknown. Setting default as ipv4/v6\n",
+ __func__, __LINE__);
+ *pdp_type = DSI_IP_VERSION_4;
+
+ }
+ }
+ else {
+ LOC_LOGD("%s:%d]: pdp type not valid in profile setting. Default ipv4\n",
+ __func__, __LINE__);
+ *pdp_type = DSI_IP_VERSION_4;
+ }
+ //Break out of for loop since we found the emergency profile
+ break;
+ }
+ else
+ LOC_LOGE("%s:%d]: Emergency profile valid but not supported in profile: %d "
+ , __func__, __LINE__, i);
+ }
+ //Since this struct is loaded with settings for the next profile,
+ //it is important to clear out the memory to avoid values/flags
+ //from being carried over
+ memset((void *)profile_settings_resp_msg.p_get_profile_setting_resp,
+ 0, sizeof(wds_get_profile_settings_resp_msg_v01));
+ }
+
+ //Release qmi client handle
+ if(qmi_client_release(wds_qmi_client) != QMI_NO_ERR) {
+ LOC_LOGE("%s:%d]: Could not release qmi client handle\n",
+ __func__, __LINE__);
+ ret = E_DS_CLIENT_FAILURE_GENERAL;
+ }
+
+ if(call_profile_index_found) {
+ *profile_index = emergency_profile_index;
+ *ds_global_data = (ds_client_session_data *)calloc(1, sizeof(ds_client_session_data));
+ if(*ds_global_data == NULL) {
+ LOC_LOGE("%s:%d]: Could not allocate memory for ds_global_data. Failing\n",
+ __func__, __LINE__);
+ ret = E_DS_CLIENT_FAILURE_NOT_ENOUGH_MEMORY;
+ goto err;
+ }
+
+ (*ds_global_data)->caller_data.event_cb = callback->event_cb;
+ (*ds_global_data)->caller_data.caller_cookie = cookie;
+ dsi_handle = dsi_get_data_srvc_hndl(net_ev_cb, &(*ds_global_data)->caller_data);
+ if(dsi_handle == NULL) {
+ LOC_LOGE("%s:%d]: Could not get data handle. Retry Later\n",
+ __func__, __LINE__);
+ ret = E_DS_CLIENT_RETRY_LATER;
+ goto err;
+ }
+ else
+ (*ds_global_data)->dsi_net_handle = dsi_handle;
+ }
+ else {
+ LOC_LOGE("%s:%d]: Could not find a profile that supports emergency calls",
+ __func__, __LINE__);
+ ret = E_DS_CLIENT_FAILURE_GENERAL;
+ }
+err:
+ if(profile_list_resp_msg.p_get_profile_list_resp)
+ free(profile_list_resp_msg.p_get_profile_list_resp);
+ if(profile_settings_resp_msg.p_get_profile_setting_resp)
+ free(profile_settings_resp_msg.p_get_profile_setting_resp);
+ LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
+ return ret;
+}
+
+/**
+ * @brief Stops a data call associated with the handle
+ *
+ * @param[in] client_handle Client handle
+ *
+ * @return Operation result
+ * @retval E_DS_CLIENT_SUCCESS On success.
+ * @retval E_DS_CLIENT_FAILURE... On error.
+ */
+static ds_client_status_enum_type ds_client_stop_call(dsClientHandleType client_handle)
+{
+ ds_client_status_enum_type ret = E_DS_CLIENT_SUCCESS;
+ ds_client_session_data *p_ds_global_data = (ds_client_session_data *)client_handle;
+ LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
+
+ if(client_handle == NULL) {
+ LOC_LOGE("%s:%d]: Null argument received. Failing\n", __func__, __LINE__);
+ ret = E_DS_CLIENT_FAILURE_GENERAL;
+ goto err;
+ }
+
+ if(dsi_stop_data_call(p_ds_global_data->dsi_net_handle) == DSI_SUCCESS) {
+ LOC_LOGD("%s:%d]: Sent request to stop data call\n", __func__, __LINE__);
+ }
+ else {
+ LOC_LOGE("%s:%d]: Could not send request to stop data call\n",
+ __func__, __LINE__);
+ ret = E_DS_CLIENT_FAILURE_GENERAL;
+ goto err;
+ }
+
+err:
+ LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
+ return ret;
+}
+
+/**
+ * @brief Releases the handle used for making data calls
+ *
+ * @param[in,out] client_handle Client handle pointer
+ *
+ * @return None
+ */
+static void ds_client_close_call(dsClientHandleType *client_handle)
+{
+ ds_client_session_data **ds_global_data = (ds_client_session_data **)client_handle;
+ LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
+ if(client_handle == NULL || *client_handle == NULL) {
+ LOC_LOGE("%s:%d]: Null argument received. Failing\n", __func__, __LINE__);
+ goto err;
+ }
+ dsi_rel_data_srvc_hndl((*ds_global_data)->dsi_net_handle);
+ (*ds_global_data)->dsi_net_handle = NULL;
+ free(*ds_global_data);
+ *ds_global_data = NULL;
+ LOC_LOGD("%s:%d]: Released Data handle\n", __func__, __LINE__);
+err:
+ LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
+ return;
+}
+
+/**
+ * @brief Initialize the DS client service
+ *
+ * This function is to be called as a first step by each process that
+ * needs to use data services. This call internally calls dsi_init()
+ * and prepares the module for making data calls.
+ * Needs to be called once for every process
+ *
+ * @return Operation result
+ * @retval E_DS_CLIENT_SUCCESS On success.
+ * @retval E_DS_CLIENT_FAILURE... On error.
+ */
+static ds_client_status_enum_type ds_client_init()
+{
+ ds_client_status_enum_type ret = E_DS_CLIENT_SUCCESS;
+ LOC_LOGD("%s:%d]:Enter", __func__, __LINE__);
+ if(DSI_SUCCESS != dsi_init(DSI_MODE_GENERAL))
+ {
+ LOC_LOGE("%s:%d]:dsi_init failed", __func__, __LINE__);
+ ret = E_DS_CLIENT_FAILURE_GENERAL;
+ }
+ LOC_LOGD("%s:%d]:Exit", __func__, __LINE__);
+ return ret;
+}
+
+/**
+ * @brief DS client function interface table definition.
+ */
+static const ds_client_iface_type iface =
+{
+ .pfn_init = ds_client_init,
+ .pfn_open_call = ds_client_open_call,
+ .pfn_start_call = ds_client_start_call,
+ .pfn_stop_call = ds_client_stop_call,
+ .pfn_close_call = ds_client_close_call
+};
+
+/**
+ * @brief Function for accessing DS client functional interface
+ *
+ * @return Pointer to interface structure.
+ */
+const ds_client_iface_type *ds_client_get_interface()
+{
+ return &iface;
+}
+
+/**
+ * @}
+ */
diff --git a/gps/loc_api/ds_api/ds_client.h b/gps/loc_api/ds_api/ds_client.h
new file mode 100644
index 0000000..ae97077
--- /dev/null
+++ b/gps/loc_api/ds_api/ds_client.h
@@ -0,0 +1,279 @@
+/* Copyright (c) 2013, 2015 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation, nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DS_CLIENT_H_
+#define _DS_CLIENT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file
+ * @brief DS client API declaration.
+ *
+ * @ingroup loc_ds_api
+ */
+
+/**
+ * @addtogroup loc_ds_api DS client support for location
+ * @{
+ */
+
+/**
+ * @brief Function name for DS client interface query.
+ *
+ * @sa ds_client_get_interface
+ */
+#define DS_CLIENT_GET_INTERFACE_FN "ds_client_get_interface"
+/**
+ * @brief Library name for loading DS client
+ */
+#ifdef USE_GLIB
+#define DS_CLIENT_LIB_NAME "libloc_ds_api.so.1"
+#else
+#define DS_CLIENT_LIB_NAME "libloc_ds_api.so"
+#endif
+
+typedef void* dsClientHandleType;
+
+typedef enum
+{
+ E_DS_CLIENT_SUCCESS = 0,
+ /**< Request was successful. */
+
+ E_DS_CLIENT_FAILURE_GENERAL = 1,
+ /**< Failed because of a general failure. */
+
+ E_DS_CLIENT_FAILURE_UNSUPPORTED = 2,
+ /**< Failed because the service does not support the command. */
+
+ E_DS_CLIENT_FAILURE_INVALID_PARAMETER = 3,
+ /**< Failed because the request contained invalid parameters. */
+
+ E_DS_CLIENT_FAILURE_ENGINE_BUSY = 4,
+ /**< Failed because the engine is busy. */
+
+ E_DS_CLIENT_FAILURE_PHONE_OFFLINE = 5,
+ /**< Failed because the phone is offline. */
+
+ E_DS_CLIENT_FAILURE_TIMEOUT = 6,
+ /**< Failed because of a timeout. */
+
+ E_DS_CLIENT_FAILURE_SERVICE_NOT_PRESENT = 7,
+ /**< Failed because the service is not present. */
+
+ E_DS_CLIENT_FAILURE_SERVICE_VERSION_UNSUPPORTED = 8,
+ /**< Failed because the service version is unsupported. */
+
+ E_DS_CLIENT_FAILURE_CLIENT_VERSION_UNSUPPORTED = 9,
+ /**< Failed because the service does not support client version. */
+
+ E_DS_CLIENT_FAILURE_INVALID_HANDLE = 10,
+ /**< Failed because an invalid handle was specified. */
+
+ E_DS_CLIENT_FAILURE_INTERNAL = 11,
+ /**< Failed because of an internal error in the service. */
+
+ E_DS_CLIENT_FAILURE_NOT_INITIALIZED = 12,
+ /**< Failed because the service has not been initialized. */
+
+ E_DS_CLIENT_FAILURE_NOT_ENOUGH_MEMORY = 13,
+ /**< Failed because not rnough memory to do the operation.*/
+
+ E_DS_CLIENT_SERVICE_ALREADY_STARTED = 14,
+ /*Service is already started*/
+
+ E_DS_CLIENT_DATA_CALL_CONNECTED = 15,
+
+ E_DS_CLIENT_DATA_CALL_DISCONNECTED = 16,
+
+ E_DS_CLIENT_RETRY_LATER = 17
+} ds_client_status_enum_type;
+
+/**
+ * @brief Callback function interface for handling DS service indications
+ *
+ * @param[in] result Operation result (error code).
+ * @param[in] cookie Client cookie provided when call is opened.
+ *
+ * @sa ds_client_cb_data
+ */
+typedef void ds_client_event_ind_cb_type
+(
+ ds_client_status_enum_type result,
+ void* loc_adapter_cookie
+);
+
+/**
+ * @brief Client callback function table
+ *
+ * This structure contains callback functions provided by client of DS client
+ * API for delivering event notifications.
+ *
+ * @sa ds_client_open_call_type
+ */
+typedef struct {
+ ds_client_event_ind_cb_type *event_cb;
+} ds_client_cb_data;
+
+/**
+ * @brief Initialize the DS client service
+ *
+ * This function is to be called as a first step by each process that
+ * needs to use data services. This call internally calls dsi_init()
+ * and prepares the module for making data calls.
+ * Needs to be called once for every process
+ *
+ * @return Operation result
+ * @retval E_DS_CLIENT_SUCCESS On success.
+ * @retval E_DS_CLIENT_FAILURE... On error.
+ */
+typedef ds_client_status_enum_type ds_client_init_type();
+
+/**
+ * @brief Prepares for call.
+ *
+ * Obtains a handle to the dsi_netctrl layer and looks up the profile
+ * to make the call. As of now. It only searches for profiles that
+ * support emergency calls.
+ *
+ * Function to open an emergency call. Does the following things:
+ * - Obtains a handle to the WDS service
+ * - Obtains a list of profiles configured in the modem
+ * - Queries each profile and obtains settings to check if emergency calls
+ * are supported
+ * - Returns the profile index that supports emergency calls
+ * - Returns handle to dsi_netctrl
+ *
+ * @param[out] client_handle Client handle to initialize.
+ * @param[in] callback Pointer to callback function table.
+ * @param[in] cookie Client's cookie for using with callback calls.
+ * @param[out] profile_index Pointer to profile index number.
+ * @param[out] pdp_type Pointer to PDP type.
+ *
+ * @return Operation result
+ * @retval E_DS_CLIENT_SUCCESS On success. Output parameters are initialized.
+ * @retval E_DS_CLIENT_FAILURE... On error.
+ */
+typedef ds_client_status_enum_type ds_client_open_call_type
+(
+ dsClientHandleType *client_handle,
+ const ds_client_cb_data *callback,
+ void *cookie,
+ int *profile_index,
+ int *pdp_type
+);
+
+/**
+ * @brief Starts a data call using the profile number provided
+ *
+ * The function uses parameters provided from @a ds_client_open_call_type
+ * call result.
+ *
+ * @param[in] client_handle Client handle
+ * @param[in] profile_index Profile index
+ * @param[in] pdp_type PDP type
+ *
+ * @return Operation result
+ * @retval E_DS_CLIENT_SUCCESS On success.
+ * @retval E_DS_CLIENT_FAILURE... On error.
+ */
+typedef ds_client_status_enum_type ds_client_start_call_type
+(
+ dsClientHandleType client_handle,
+ int profile_index,
+ int pdp_type
+);
+
+/**
+ * @brief Stops a data call associated with the handle
+ *
+ * @param[in] client_handle Client handle
+ *
+ * @return Operation result
+ * @retval E_DS_CLIENT_SUCCESS On success.
+ * @retval E_DS_CLIENT_FAILURE... On error.
+ */
+typedef ds_client_status_enum_type ds_client_stop_call_type
+(
+ dsClientHandleType client_handle
+);
+
+/**
+ * @brief Releases the handle used for making data calls
+ *
+ * @param[in,out] client_handle Client handle pointer
+ *
+ * @return None
+ */
+typedef void ds_client_close_call_type
+(
+ dsClientHandleType *client_handle
+);
+
+/**
+ * @brief DS client functional interface table
+ *
+ * This table contains all supported DS client operations. If the operation
+ * is not supported, the corresponding entry is NULL.
+ *
+ * @sa ds_client_get_interface
+ */
+typedef struct
+{
+ ds_client_init_type *pfn_init;
+ ds_client_open_call_type *pfn_open_call;
+ ds_client_start_call_type *pfn_start_call;
+ ds_client_stop_call_type *pfn_stop_call;
+ ds_client_close_call_type *pfn_close_call;
+} ds_client_iface_type;
+
+/**
+ * @brief Function for accessing DS client functional interface
+ *
+ * @return Pointer to interface structure.
+ */
+typedef const ds_client_iface_type *ds_client_get_iface_fn();
+
+/**
+ * @brief Function for accessing DS client functional interface
+ *
+ * @return Pointer to interface structure.
+ */
+ds_client_get_iface_fn ds_client_get_interface;
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @}
+ */
+
+#endif /* _DS_CLIENT_H_ */