Merge "Add support for SUPL Emergency Services"

This commit is contained in:
Linux Build Service Account 2013-06-22 10:22:52 -07:00 committed by Gerrit - the friendly Code Review server
commit e100c681e1
16 changed files with 1576 additions and 88 deletions

View file

@ -27,6 +27,7 @@ endif
ifeq ($(call is-board-platform-in-list,$(QMI_BOARD_PLATFORM_LIST)),true) ifeq ($(call is-board-platform-in-list,$(QMI_BOARD_PLATFORM_LIST)),true)
GPS_DIR_LIST += $(LOCAL_PATH)/loc_api_v02/ GPS_DIR_LIST += $(LOCAL_PATH)/loc_api_v02/
GPS_DIR_LIST += $(LOCAL_PATH)/ds_api/
endif #is-board-platform-in-list endif #is-board-platform-in-list
GPS_DIR_LIST += $(LOCAL_PATH)/libloc_api_50001/ GPS_DIR_LIST += $(LOCAL_PATH)/libloc_api_50001/

49
loc_api/ds_api/Android.mk Normal file
View file

@ -0,0 +1,49 @@
ifneq ($(BUILD_TINY_ANDROID),true)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libds_api
LOCAL_MODULE_TAGS := optional
LOCAL_SHARED_LIBRARIES := \
libutils \
libcutils \
libqmi_cci \
libqmi_csi \
libqmi_common_so \
libgps.utils \
libdsi_netctrl \
libqmiservices
LOCAL_SRC_FILES += \
ds_client.c
LOCAL_CFLAGS += \
-fno-short-enums \
-D_ANDROID_
LOCAL_COPY_HEADERS_TO:= 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
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)
endif # not BUILD_TINY_ANDROID

704
loc_api/ds_api/ds_client.c Normal file
View file

@ -0,0 +1,704 @@
/* Copyright (c) 2013, 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 <utils/Log.h>
#include <log_util.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>
//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;
struct event_strings_s
{
char * str;
dsi_net_evt_t evt;
};
struct event_strings_s 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),
};
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;
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\n", __func__, __LINE__);
if(evt > DSI_EVT_INVALID && evt < DSI_EVT_MAX)
{
for(i=0;i<DSI_EVT_MAX;i++)
{
if(event_string_tbl[i].evt == evt)
LOC_LOGE("%s:%d]: Callback received: %s",
__func__, __LINE__, event_string_tbl[i].str);
}
switch(evt) {
case DSI_EVT_NET_IS_CONN:
{
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;
}
/*
Starts data call using the handle and the profile index
*/
ds_client_status_enum_type
ds_client_start_call(dsClientHandleType client_handle, int profile_index)
{
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);
LOC_LOGD("%s:%d]: Starting emergency call with profile index %d\n",
__func__, __LINE__, param_info.num_val);
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;
}
/*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*/
ds_client_status_enum_type
ds_client_open_call(dsClientHandleType *client_handle,
ds_client_cb_data *callback,
void *caller_cookie,
int *profile_index)
{
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\n", __func__, __LINE__, i);
LOC_LOGD("%s:%d]: Profile name: %s\n", __func__, __LINE__,
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;
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 = caller_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;
}
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;
}
/*
Stops data call associated with the data handle
*/
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;
}
int ds_client_init()
{
int ret = 0;
LOC_LOGD("%s:%d]:Enter\n", __func__, __LINE__);
if(DSI_SUCCESS != dsi_init(DSI_MODE_GENERAL))
{
LOC_LOGE("%s:%d]:dsi_init failed\n", __func__, __LINE__);
ret = -1;
}
LOC_LOGD("%s:%d]:Exit\n", __func__, __LINE__);
return ret;
}

142
loc_api/ds_api/ds_client.h Normal file
View file

@ -0,0 +1,142 @@
/* Copyright (c) 2013, 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
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;
typedef enum {
DATA_CALL_NONE = 0,
DATA_CALL_OPEN,
DATA_CALL_CLOSE
}data_call_request_enum_type;
typedef void (*ds_client_event_ind_cb_type)(ds_client_status_enum_type result,
void* loc_adapter_cookie);
typedef struct {
ds_client_event_ind_cb_type event_cb;
}ds_client_cb_data;
/*
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
*/
int ds_client_init();
/*
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
*/
ds_client_status_enum_type ds_client_open_call(dsClientHandleType *client_handle,
ds_client_cb_data *callback,
void *loc_adapter_cookie,
int *profile_index);
/*
Starts a data call using the profile number provided
*/
ds_client_status_enum_type ds_client_start_call(dsClientHandleType client_handle,
int profile_index);
/*
Stops a data call associated with the handle
*/
ds_client_status_enum_type ds_client_stop_call(dsClientHandleType client_handle);
/*
Releases the handle used for making data calls
*/
void ds_client_close_call(dsClientHandleType *client_handle);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -186,6 +186,18 @@ void LocApiAdapter::requestATL(int connHandle, AGpsType agps_type)
locEngHandle.sendMsge(locEngHandle.owner, msg); locEngHandle.sendMsge(locEngHandle.owner, msg);
} }
void LocApiAdapter::requestSuplES(int connHandle)
{
loc_eng_msg_request_supl_es *msg(new loc_eng_msg_request_supl_es(locEngHandle.owner, connHandle));
locEngHandle.sendMsge(locEngHandle.owner, msg);
}
void LocApiAdapter::releaseDataHandle(void)
{
loc_eng_msg_close_data_call *msg(new loc_eng_msg_close_data_call(locEngHandle.owner));
locEngHandle.sendMsge(locEngHandle.owner, msg);
}
void LocApiAdapter::releaseATL(int connHandle) void LocApiAdapter::releaseATL(int connHandle)
{ {
loc_eng_msg_release_atl *msg(new loc_eng_msg_release_atl(locEngHandle.owner, connHandle)); loc_eng_msg_release_atl *msg(new loc_eng_msg_release_atl(locEngHandle.owner, connHandle));
@ -234,3 +246,18 @@ void LocApiAdapter::handleEngineUpEvent()
loc_eng_msg *msg(new loc_eng_msg(locEngHandle.owner, LOC_ENG_MSG_ENGINE_UP)); loc_eng_msg *msg(new loc_eng_msg(locEngHandle.owner, LOC_ENG_MSG_ENGINE_UP));
locEngHandle.sendMsge(locEngHandle.owner, msg); locEngHandle.sendMsge(locEngHandle.owner, msg);
} }
void LocApiAdapter::reportDataCallOpened()
{
loc_eng_msg_atl_open_success *msg(new loc_eng_msg_atl_open_success(locEngHandle.owner,
AGPS_TYPE_INVALID,
NULL, 0, 0));
locEngHandle.sendMsge(locEngHandle.owner, msg);
}
void LocApiAdapter::reportDataCallClosed()
{
loc_eng_msg_atl_closed *msg(new loc_eng_msg_atl_closed(locEngHandle.owner,
AGPS_TYPE_INVALID));
locEngHandle.sendMsge(locEngHandle.owner, msg);
}

View file

@ -141,7 +141,10 @@ public:
void requestNiNotify(GpsNiNotification &notify, const void* data); void requestNiNotify(GpsNiNotification &notify, const void* data);
void handleEngineDownEvent(); void handleEngineDownEvent();
void handleEngineUpEvent(); void handleEngineUpEvent();
void requestSuplES(int connHandle);
void releaseDataHandle(void);
void reportDataCallOpened(void);
void reportDataCallClosed(void);
// All below functions are to be defined by adapter specific modules: // All below functions are to be defined by adapter specific modules:
// RPC, QMI, etc. The default implementation is empty. // RPC, QMI, etc. The default implementation is empty.
inline virtual enum loc_api_adapter_err inline virtual enum loc_api_adapter_err
@ -230,6 +233,15 @@ public:
inline bool isInSession() { return navigating; } inline bool isInSession() { return navigating; }
inline virtual void setInSession(bool inSession) { navigating = inSession; } inline virtual void setInSession(bool inSession) { navigating = inSession; }
inline virtual int openAndStartDataCall()
{LOC_LOGW("%s: default implementation invoked", __func__); return -1;}
inline virtual void stopDataCall()
{LOC_LOGW("%s: default implementation invoked", __func__);}
inline virtual void closeDataCall()
{LOC_LOGW("%s: default implementation invoked", __func__);}
inline virtual int initDataServiceClient()
{LOC_LOGW("%s: default implementation invoked", __func__); return -1;}
}; };
extern "C" LocApiAdapter* getLocApiAdapter(LocEng &locEng); extern "C" LocApiAdapter* getLocApiAdapter(LocEng &locEng);

View file

@ -60,7 +60,6 @@
#include <loc_eng_nmea.h> #include <loc_eng_nmea.h>
#include <msg_q.h> #include <msg_q.h>
#include <loc.h> #include <loc.h>
#include "log_util.h" #include "log_util.h"
#include "loc_eng_log.h" #include "loc_eng_log.h"
@ -810,6 +809,38 @@ static void loc_inform_gps_status(loc_eng_data_s_type &loc_eng_data, GpsStatusVa
EXIT_LOG(%s, VOID_RET); EXIT_LOG(%s, VOID_RET);
} }
/*
Callback function passed to Data Services State Machine
This becomes part of the state machine's servicer and
is used to send requests to the data services client
*/
static int dataCallCb(void *cb_data)
{
LOC_LOGD("Enter dataCallCb\n");
int ret=0;
if(cb_data != NULL) {
dsCbData *cbData = (dsCbData *)cb_data;
LocApiAdapter *locAdapter = (LocApiAdapter *)cbData->mAdapter;
if(cbData->action == GPS_REQUEST_AGPS_DATA_CONN) {
LOC_LOGD("dataCallCb GPS_REQUEST_AGPS_DATA_CONN\n");
ret = locAdapter->openAndStartDataCall();
}
else if(cbData->action == GPS_RELEASE_AGPS_DATA_CONN) {
LOC_LOGD("dataCallCb GPS_RELEASE_AGPS_DATA_CONN\n");
locAdapter->stopDataCall();
}
}
else {
LOC_LOGE("NULL argument received. Failing.\n");
ret = -1;
goto err;
}
err:
LOC_LOGD("Exit dataCallCb ret = %d\n", ret);
return ret;
}
/*=========================================================================== /*===========================================================================
FUNCTION loc_eng_agps_reinit FUNCTION loc_eng_agps_reinit
@ -876,17 +907,27 @@ void loc_eng_agps_init(loc_eng_data_s_type &loc_eng_data, AGpsCallbacks* callbac
} }
loc_eng_data.agps_status_cb = callbacks->status_cb; loc_eng_data.agps_status_cb = callbacks->status_cb;
loc_eng_data.agnss_nif = new AgpsStateMachine(loc_eng_data.agps_status_cb, loc_eng_data.agnss_nif = new AgpsStateMachine(servicerTypeAgps,
(void *)loc_eng_data.agps_status_cb,
AGPS_TYPE_SUPL, AGPS_TYPE_SUPL,
false); false);
#ifdef FEATURE_IPV6 #ifdef FEATURE_IPV6
loc_eng_data.internet_nif = new AgpsStateMachine(loc_eng_data.agps_status_cb, loc_eng_data.internet_nif = new AgpsStateMachine(servicerTypeAgps,
(void *)loc_eng_data.agps_status_cb,
AGPS_TYPE_WWAN_ANY, AGPS_TYPE_WWAN_ANY,
false); false);
loc_eng_data.wifi_nif = new AgpsStateMachine(loc_eng_data.agps_status_cb, loc_eng_data.wifi_nif = new AgpsStateMachine(servicerTypeAgps,
(void *)loc_eng_data.agps_status_cb,
AGPS_TYPE_WIFI, AGPS_TYPE_WIFI,
true); true);
#endif #endif
if(!loc_eng_data.client_handle->initDataServiceClient()) {
LOC_LOGD("%s:%d]: Creating new ds state machine\n", __func__, __LINE__);
loc_eng_data.ds_nif = new DSStateMachine(servicerTypeExt,
(void *)dataCallCb,
loc_eng_data.client_handle);
LOC_LOGD("%s:%d]: Created new ds state machine\n", __func__, __LINE__);
}
loc_eng_dmn_conn_loc_api_server_launch(callbacks->create_thread_cb, loc_eng_dmn_conn_loc_api_server_launch(callbacks->create_thread_cb,
NULL, NULL, &loc_eng_data); NULL, NULL, &loc_eng_data);
@ -1741,14 +1782,27 @@ static void loc_eng_deferred_action_thread(void* arg)
loc_eng_data_p->client_handle, loc_eng_data_p->client_handle,
false); false);
// attempt to unsubscribe from agnss_nif first // attempt to unsubscribe from agnss_nif first
if (! loc_eng_data_p->agnss_nif->unsubscribeRsrc((Subscriber*)&s1)) { if (loc_eng_data_p->agnss_nif->unsubscribeRsrc((Subscriber*)&s1)) {
#ifdef FEATURE_IPV6 #ifdef FEATURE_IPV6
LOC_LOGD("%s:%d]: Unsubscribed from agnss_nif", __func__, __LINE__);
}
else {
ATLSubscriber s2(arlMsg->handle, ATLSubscriber s2(arlMsg->handle,
loc_eng_data_p->internet_nif, loc_eng_data_p->internet_nif,
loc_eng_data_p->client_handle, loc_eng_data_p->client_handle,
false); false);
// if unsuccessful, try internet_nif // if unsuccessful, try internet_nif
loc_eng_data_p->internet_nif->unsubscribeRsrc((Subscriber*)&s2); if(loc_eng_data_p->internet_nif->unsubscribeRsrc((Subscriber*)&s2)) {
LOC_LOGD("%s:%d]: Unsubscribed from internet_nif", __func__, __LINE__);
}
else {
DSSubscriber s3(loc_eng_data_p->ds_nif,
arlMsg->handle);
LOC_LOGD("%s:%d]: Request to stop Emergency call. Handle: %d\n",
__func__, __LINE__, arlMsg->handle);
loc_eng_data_p->ds_nif->unsubscribeRsrc((Subscriber*)&s3);
LOC_LOGD("%s:%d]: Unsubscribed from ds_nif", __func__, __LINE__);
}
#endif #endif
} }
} }
@ -1827,16 +1881,25 @@ static void loc_eng_deferred_action_thread(void* arg)
loc_eng_msg_atl_open_success *aosMsg = (loc_eng_msg_atl_open_success*)msg; loc_eng_msg_atl_open_success *aosMsg = (loc_eng_msg_atl_open_success*)msg;
AgpsStateMachine* stateMachine; AgpsStateMachine* stateMachine;
#ifdef FEATURE_IPV6 #ifdef FEATURE_IPV6
LOC_LOGD("%s:%d]: AGPS_TYPE: %d\n", __func__, __LINE__, (int)aosMsg->agpsType);
switch (aosMsg->agpsType) { switch (aosMsg->agpsType) {
case AGPS_TYPE_WIFI: { case AGPS_TYPE_WIFI: {
LOC_LOGD("%s:%d]: AGPS Type wifi\n", __func__, __LINE__);
stateMachine = loc_eng_data_p->wifi_nif; stateMachine = loc_eng_data_p->wifi_nif;
break; break;
} }
case AGPS_TYPE_SUPL: { case AGPS_TYPE_SUPL: {
LOC_LOGD("%s:%d]: AGPS Type supl\n", __func__, __LINE__);
stateMachine = loc_eng_data_p->agnss_nif; stateMachine = loc_eng_data_p->agnss_nif;
break; break;
} }
case AGPS_TYPE_INVALID: {
stateMachine = loc_eng_data_p->ds_nif;
LOC_LOGD("%s:%d]: AGPS Type invalid\n", __func__, __LINE__);
}
break;
default: { default: {
LOC_LOGD("%s:%d]: AGPS Type default internet\n", __func__, __LINE__);
stateMachine = loc_eng_data_p->internet_nif; stateMachine = loc_eng_data_p->internet_nif;
} }
} }
@ -1864,6 +1927,10 @@ static void loc_eng_deferred_action_thread(void* arg)
stateMachine = loc_eng_data_p->agnss_nif; stateMachine = loc_eng_data_p->agnss_nif;
break; break;
} }
case AGPS_TYPE_INVALID: {
stateMachine = loc_eng_data_p->ds_nif;
break;
}
default: { default: {
stateMachine = loc_eng_data_p->internet_nif; stateMachine = loc_eng_data_p->internet_nif;
} }
@ -1928,7 +1995,7 @@ static void loc_eng_deferred_action_thread(void* arg)
{ {
loc_eng_msg_request_phone_context *contextReqMsg = (loc_eng_msg_request_phone_context*)msg; loc_eng_msg_request_phone_context *contextReqMsg = (loc_eng_msg_request_phone_context*)msg;
LOC_LOGD("Received phone context request from ULP.context_type 0x%x,request_type 0x%x ", LOC_LOGD("Received phone context request from ULP.context_type 0x%x,request_type 0x%x ",
contextReqMsg->contextRequest.context_type,contextReqMsg->contextRequest.request_type) contextReqMsg->contextRequest.context_type,contextReqMsg->contextRequest.request_type);
if(loc_eng_data_p->ulp_phone_context_req_cb != NULL) if(loc_eng_data_p->ulp_phone_context_req_cb != NULL)
{ {
loc_eng_data_p->ulp_phone_context_req_cb((UlpPhoneContextRequest*)&(contextReqMsg->contextRequest)); loc_eng_data_p->ulp_phone_context_req_cb((UlpPhoneContextRequest*)&(contextReqMsg->contextRequest));
@ -1944,6 +2011,25 @@ static void loc_eng_deferred_action_thread(void* arg)
} }
break; break;
case LOC_ENG_MSG_REQUEST_SUPL_ES:
{
loc_eng_msg_request_supl_es *reqMsg =
(loc_eng_msg_request_supl_es *)msg;
AgpsStateMachine *stateMachine = loc_eng_data_p->ds_nif;
DSSubscriber subscriber(stateMachine, reqMsg->handle);
LOC_LOGD("%s:%d]: Starting data call\n", __func__, __LINE__);
stateMachine->subscribeRsrc((Subscriber *)&subscriber);
}
break;
case LOC_ENG_MSG_CLOSE_DATA_CALL:
{
loc_eng_data_p->client_handle->closeDataCall();
LOC_LOGD("%s:%d]: Request to close data call\n",
__func__, __LINE__);
}
break;
default: default:
LOC_LOGE("unsupported msgid = %d\n", msg->msgid); LOC_LOGE("unsupported msgid = %d\n", msg->msgid);
break; break;
@ -2273,4 +2359,3 @@ int loc_eng_read_config(void)
EXIT_LOG(%d, 0); EXIT_LOG(%d, 0);
return 0; return 0;
} }

View file

@ -121,6 +121,8 @@ typedef struct
AgpsStateMachine* agnss_nif; AgpsStateMachine* agnss_nif;
AgpsStateMachine* internet_nif; AgpsStateMachine* internet_nif;
AgpsStateMachine* wifi_nif; AgpsStateMachine* wifi_nif;
//State machine for Data Services
AgpsStateMachine* ds_nif;
// GPS engine status // GPS engine status
GpsStatusValue engine_status; GpsStatusValue engine_status;

View file

@ -35,6 +35,7 @@
#include <log_util.h> #include <log_util.h>
#include <loc_eng_dmn_conn_handler.h> #include <loc_eng_dmn_conn_handler.h>
#include <loc_eng_dmn_conn.h> #include <loc_eng_dmn_conn.h>
#include<sys/time.h>
//====================================================================== //======================================================================
// C callbacks // C callbacks
@ -84,8 +85,8 @@ static bool notifySubscriber(void* fromCaller, void* fromList)
const int Notification::BROADCAST_ALL = 0x80000000; const int Notification::BROADCAST_ALL = 0x80000000;
const int Notification::BROADCAST_ACTIVE = 0x80000001; const int Notification::BROADCAST_ACTIVE = 0x80000001;
const int Notification::BROADCAST_INACTIVE = 0x80000002; const int Notification::BROADCAST_INACTIVE = 0x80000002;
const unsigned char DSStateMachine::MAX_START_DATA_CALL_RETRIES = 4;
const unsigned int DSStateMachine::DATA_CALL_RETRY_DELAY_MSEC = 500;
//====================================================================== //======================================================================
// Subscriber: BITSubscriber / ATLSubscriber / WIFISubscriber // Subscriber: BITSubscriber / ATLSubscriber / WIFISubscriber
//====================================================================== //======================================================================
@ -227,7 +228,29 @@ bool WIFISubscriber::notifyRsrcStatus(Notification &notification)
return notify; return notify;
} }
#endif #endif
bool DSSubscriber::notifyRsrcStatus(Notification &notification)
{
bool notify = forMe(notification);
LOC_LOGD("DSSubscriber::notifyRsrcStatus. notify:%d \n",(int)(notify));
if(notify) {
switch(notification.rsrcStatus) {
case RSRC_UNSUBSCRIBE:
case RSRC_RELEASED:
case RSRC_DENIED:
case RSRC_GRANTED:
((DSStateMachine *)mStateMachine)->informStatus(notification.rsrcStatus, ID);
break;
default:
notify = false;
}
}
return notify;
}
void DSSubscriber :: setInactive()
{
mIsInactive = true;
((DSStateMachine *)mStateMachine)->informStatus(RSRC_UNSUBSCRIBE, ID);
}
//====================================================================== //======================================================================
// AgpsState: AgpsReleasedState / AgpsPendingState / AgpsAcquiredState // AgpsState: AgpsReleasedState / AgpsPendingState / AgpsAcquiredState
//====================================================================== //======================================================================
@ -249,13 +272,14 @@ public:
AgpsState* AgpsReleasedState::onRsrcEvent(AgpsRsrcStatus event, void* data) AgpsState* AgpsReleasedState::onRsrcEvent(AgpsRsrcStatus event, void* data)
{ {
LOC_LOGD("AgpsReleasedState::onRsrcEvent; event:%d\n", (int)event);
if (mStateMachine->hasSubscribers()) { if (mStateMachine->hasSubscribers()) {
LOC_LOGE("Error: %s subscriber list not empty!!!", whoami()); LOC_LOGE("Error: %s subscriber list not empty!!!", whoami());
// I don't know how to recover from it. I am adding this rather // I don't know how to recover from it. I am adding this rather
// for debugging purpose. // for debugging purpose.
} }
AgpsState* nextState = this;; AgpsState* nextState = this;
switch (event) switch (event)
{ {
case RSRC_SUBSCRIBE: case RSRC_SUBSCRIBE:
@ -263,11 +287,14 @@ AgpsState* AgpsReleasedState::onRsrcEvent(AgpsRsrcStatus event, void* data)
// no notification until we get RSRC_GRANTED // no notification until we get RSRC_GRANTED
// but we need to add subscriber to the list // but we need to add subscriber to the list
mStateMachine->addSubscriber((Subscriber*)data); mStateMachine->addSubscriber((Subscriber*)data);
// request from connecivity service for NIF
//The if condition is added so that if the data call setup fails
//for DS State Machine, we want to retry in released state.
//for AGps State Machine, sendRsrcRequest() will always return success
if(!mStateMachine->sendRsrcRequest(GPS_REQUEST_AGPS_DATA_CONN)) {
// move the state to PENDING // move the state to PENDING
nextState = mPendingState; nextState = mPendingState;
}
// request from connecivity service for NIF
mStateMachine->sendRsrcRequest(GPS_REQUEST_AGPS_DATA_CONN);
} }
break; break;
@ -313,6 +340,7 @@ public:
AgpsState* AgpsPendingState::onRsrcEvent(AgpsRsrcStatus event, void* data) AgpsState* AgpsPendingState::onRsrcEvent(AgpsRsrcStatus event, void* data)
{ {
AgpsState* nextState = this;; AgpsState* nextState = this;;
LOC_LOGD("AgpsPendingState::onRsrcEvent; event:%d\n", (int)event);
switch (event) switch (event)
{ {
case RSRC_SUBSCRIBE: case RSRC_SUBSCRIBE:
@ -408,6 +436,7 @@ public:
AgpsState* AgpsAcquiredState::onRsrcEvent(AgpsRsrcStatus event, void* data) AgpsState* AgpsAcquiredState::onRsrcEvent(AgpsRsrcStatus event, void* data)
{ {
AgpsState* nextState = this; AgpsState* nextState = this;
LOC_LOGD("AgpsAcquiredState::onRsrcEvent; event:%d\n", (int)event);
switch (event) switch (event)
{ {
case RSRC_SUBSCRIBE: case RSRC_SUBSCRIBE:
@ -441,7 +470,8 @@ AgpsState* AgpsAcquiredState::onRsrcEvent(AgpsRsrcStatus event, void* data)
// tell connecivity service we can release NIF // tell connecivity service we can release NIF
mStateMachine->sendRsrcRequest(GPS_RELEASE_AGPS_DATA_CONN); mStateMachine->sendRsrcRequest(GPS_RELEASE_AGPS_DATA_CONN);
} else if (!mStateMachine->hasActiveSubscribers()) { }
else if (!mStateMachine->hasActiveSubscribers()) {
// only inactive subscribers, move to RELEASING state // only inactive subscribers, move to RELEASING state
nextState = mReleasingState; nextState = mReleasingState;
@ -500,6 +530,8 @@ public:
AgpsState* AgpsReleasingState::onRsrcEvent(AgpsRsrcStatus event, void* data) AgpsState* AgpsReleasingState::onRsrcEvent(AgpsRsrcStatus event, void* data)
{ {
AgpsState* nextState = this;; AgpsState* nextState = this;;
LOC_LOGD("AgpsReleasingState::onRsrcEvent; event:%d\n", (int)event);
switch (event) switch (event)
{ {
case RSRC_SUBSCRIBE: case RSRC_SUBSCRIBE:
@ -541,7 +573,7 @@ AgpsState* AgpsReleasingState::onRsrcEvent(AgpsRsrcStatus event, void* data)
// by setting false, we keep subscribers on the linked list // by setting false, we keep subscribers on the linked list
mStateMachine->notifySubscribers(notification); mStateMachine->notifySubscribers(notification);
if (mStateMachine->hasSubscribers()) { if (mStateMachine->hasActiveSubscribers()) {
nextState = mPendingState; nextState = mPendingState;
// request from connecivity service for NIF // request from connecivity service for NIF
mStateMachine->sendRsrcRequest(GPS_REQUEST_AGPS_DATA_CONN); mStateMachine->sendRsrcRequest(GPS_REQUEST_AGPS_DATA_CONN);
@ -561,20 +593,58 @@ AgpsState* AgpsReleasingState::onRsrcEvent(AgpsRsrcStatus event, void* data)
whoami(), nextState->whoami(), event); whoami(), nextState->whoami(), event);
return nextState; return nextState;
} }
//======================================================================
//Servicer
//======================================================================
Servicer* Servicer :: getServicer(servicerType type, void *cb_func)
{
LOC_LOGD(" Enter getServicer type:%d\n", (int)type);
switch(type) {
case servicerTypeNoCbParam:
return (new Servicer(cb_func));
case servicerTypeExt:
return (new ExtServicer(cb_func));
case servicerTypeAgps:
return (new AGpsServicer(cb_func));
default:
return NULL;
}
}
int Servicer :: requestRsrc(void *cb_data)
{
callback();
return 0;
}
int ExtServicer :: requestRsrc(void *cb_data)
{
int ret=-1;
LOC_LOGD("Enter ExtServicer :: requestRsrc\n");
ret = callbackExt(cb_data);
LOC_LOGD("Exit ExtServicer :: requestRsrc\n");
return(ret);
}
int AGpsServicer :: requestRsrc(void *cb_data)
{
callbackAGps((AGpsStatus *)cb_data);
return 0;
}
//====================================================================== //======================================================================
// AgpsStateMachine // AgpsStateMachine
//====================================================================== //======================================================================
AgpsStateMachine::AgpsStateMachine(void (*servicer)(AGpsStatus* status), AgpsStateMachine::AgpsStateMachine(servicerType servType,
void *cb_func,
AGpsType type, AGpsType type,
bool enforceSingleSubscriber) : bool enforceSingleSubscriber) :
mServicer(servicer), mType(type), mStatePtr(new AgpsReleasedState(this)),mType(type),
mStatePtr(new AgpsReleasedState(this)),
mAPN(NULL), mAPN(NULL),
mAPNLen(0), mAPNLen(0),
mEnforceSingleSubscriber(enforceSingleSubscriber) mEnforceSingleSubscriber(enforceSingleSubscriber),
mServicer(Servicer :: getServicer(servType, (void *)cb_func))
{ {
linked_list_init(&mSubscribers); linked_list_init(&mSubscribers);
@ -615,6 +685,7 @@ AgpsStateMachine::~AgpsStateMachine()
delete releasedState; delete releasedState;
delete pendindState; delete pendindState;
delete releasingState; delete releasingState;
delete mServicer;
linked_list_destroy(&mSubscribers); linked_list_destroy(&mSubscribers);
if (NULL != mAPN) { if (NULL != mAPN) {
@ -669,6 +740,7 @@ void AgpsStateMachine::notifySubscribers(Notification& notification) const
// rest of the list unprocessed. So we need a loop. // rest of the list unprocessed. So we need a loop.
linked_list_search(mSubscribers, (void**)&s, notifySubscriber, linked_list_search(mSubscribers, (void**)&s, notifySubscriber,
(void*)&notification, true); (void*)&notification, true);
delete s;
} }
} else { } else {
// no loop needed if it the last param sets to false, which // no loop needed if it the last param sets to false, which
@ -690,7 +762,7 @@ void AgpsStateMachine::addSubscriber(Subscriber* subscriber) const
} }
} }
void AgpsStateMachine::sendRsrcRequest(AGpsStatusValue action) const int AgpsStateMachine::sendRsrcRequest(AGpsStatusValue action) const
{ {
Subscriber* s = NULL; Subscriber* s = NULL;
Notification notification(Notification::BROADCAST_ACTIVE); Notification notification(Notification::BROADCAST_ACTIVE);
@ -722,8 +794,9 @@ void AgpsStateMachine::sendRsrcRequest(AGpsStatusValue action) const
#endif #endif
CALLBACK_LOG_CALLFLOW("agps_cb", %s, loc_get_agps_status_name(action)); CALLBACK_LOG_CALLFLOW("agps_cb", %s, loc_get_agps_status_name(action));
(*mServicer)(&nifRequest); mServicer->requestRsrc((void *)&nifRequest);
} }
return 0;
} }
void AgpsStateMachine::subscribeRsrc(Subscriber *subscriber) void AgpsStateMachine::subscribeRsrc(Subscriber *subscriber)
@ -758,3 +831,163 @@ bool AgpsStateMachine::hasActiveSubscribers() const
hasSubscriber, (void*)&notification, false); hasSubscriber, (void*)&notification, false);
return NULL != s; return NULL != s;
} }
//======================================================================
// DSStateMachine
//======================================================================
void delay_callback(void *callbackData, int result)
{
if(callbackData) {
DSStateMachine *DSSMInstance = (DSStateMachine *)callbackData;
DSSMInstance->retryCallback();
}
else {
LOC_LOGE(" NULL argument received. Failing.\n");
goto err;
}
err:
return;
}
DSStateMachine :: DSStateMachine(servicerType type, void *cb_func,
LocApiAdapter* adapterHandle):
AgpsStateMachine(type, cb_func, AGPS_TYPE_INVALID,false),
mLocAdapter(adapterHandle)
{
LOC_LOGD("%s:%d]: New DSStateMachine\n", __func__, __LINE__);
mRetries = 0;
}
void DSStateMachine :: retryCallback(void)
{
DSSubscriber *subscriber = NULL;
Notification notification(Notification::BROADCAST_ACTIVE);
linked_list_search(mSubscribers, (void**)&subscriber, hasSubscriber,
(void*)&notification, false);
if(subscriber)
mLocAdapter->requestSuplES(subscriber->ID);
else
LOC_LOGE("DSStateMachine :: retryCallback: No subscriber found." \
"Cannot retry data call\n");
return;
}
int DSStateMachine :: sendRsrcRequest(AGpsStatusValue action) const
{
DSSubscriber* s = NULL;
dsCbData cbData;
int ret=-1;
int connHandle=-1;
LOC_LOGD("Enter DSStateMachine :: sendRsrcRequest\n");
Notification notification(Notification::BROADCAST_ACTIVE);
linked_list_search(mSubscribers, (void**)&s, hasSubscriber,
(void*)&notification, false);
if(s) {
connHandle = s->ID;
LOC_LOGD("DSStateMachine :: sendRsrcRequest - subscriber found\n");
}
else
LOC_LOGD("DSStateMachine :: sendRsrcRequest - No subscriber found\n");
cbData.action = action;
cbData.mAdapter = mLocAdapter;
ret = mServicer->requestRsrc((void *)&cbData);
//Only the request to start data call returns a success/failure
//The request to stop data call will always succeed
//Hence, the below block will only be executed when the
//request to start the data call fails
switch(ret) {
case LOC_API_ADAPTER_ERR_ENGINE_BUSY:
LOC_LOGD("DSStateMachine :: sendRsrcRequest - Failure returned: %d\n",ret);
((DSStateMachine *)this)->incRetries();
if(mRetries > MAX_START_DATA_CALL_RETRIES) {
LOC_LOGE(" Failed to start Data call. Fallback to normal ATL SUPL\n");
informStatus(RSRC_DENIED, connHandle);
}
else {
if(loc_timer_start(DATA_CALL_RETRY_DELAY_MSEC, delay_callback, (void *)this)) {
LOC_LOGE("Error: Could not start delay thread\n");
ret = -1;
goto err;
}
}
break;
case LOC_API_ADAPTER_ERR_UNSUPPORTED:
LOC_LOGE("No profile found for emergency call. Fallback to normal SUPL ATL\n");
informStatus(RSRC_DENIED, connHandle);
break;
case LOC_API_ADAPTER_ERR_SUCCESS:
LOC_LOGD("%s:%d]: Request to start data call sent\n", __func__, __LINE__);
break;
case -1:
//One of the ways this case can be encountered is if the callback function
//receives a null argument, it just exits with -1 error
LOC_LOGE("Error: Something went wrong somewhere. Falling back to normal SUPL ATL\n");
informStatus(RSRC_DENIED, connHandle);
break;
default:
LOC_LOGE("%s:%d]: Unrecognized return value\n", __func__, __LINE__);
}
err:
LOC_LOGD("EXIT DSStateMachine :: sendRsrcRequest; ret = %d\n", ret);
return ret;
}
void DSStateMachine :: onRsrcEvent(AgpsRsrcStatus event)
{
void* currState = (void *)mStatePtr;
LOC_LOGD("Enter DSStateMachine :: onRsrcEvent. event = %d\n", (int)event);
switch (event)
{
case RSRC_GRANTED:
LOC_LOGD("DSStateMachine :: onRsrcEvent RSRC_GRANTED\n");
mStatePtr = mStatePtr->onRsrcEvent(event, NULL);
break;
case RSRC_RELEASED:
LOC_LOGD("DSStateMachine :: onRsrcEvent RSRC_RELEASED\n");
mStatePtr = mStatePtr->onRsrcEvent(event, NULL);
//To handle the case where we get a RSRC_RELEASED in
//pending state, we translate that to a RSRC_DENIED state
//since the callback from DSI is either RSRC_GRANTED or RSRC_RELEASED
//for when the call is connected or disconnected respectively.
if((void *)mStatePtr != currState)
break;
else {
event = RSRC_DENIED;
LOC_LOGE(" Switching event to RSRC_DENIED\n");
}
case RSRC_DENIED:
mStatePtr = mStatePtr->onRsrcEvent(event, NULL);
break;
default:
LOC_LOGW("AgpsStateMachine: unrecognized event %d", event);
break;
}
LOC_LOGD("Exit DSStateMachine :: onRsrcEvent. event = %d\n", (int)event);
}
void DSStateMachine :: informStatus(AgpsRsrcStatus status, int ID) const
{
LOC_LOGD("DSStateMachine :: informStatus. Status=%d\n",(int)status);
switch(status) {
case RSRC_UNSUBSCRIBE:
((LocApiAdapter*)mLocAdapter)->atlCloseStatus(ID, 1);
break;
case RSRC_RELEASED:
((LocApiAdapter*)mLocAdapter)->releaseDataHandle();
break;
case RSRC_DENIED:
((DSStateMachine *)this)->mRetries = 0;
mLocAdapter->requestATL(ID, AGPS_TYPE_SUPL);
break;
case RSRC_GRANTED:
((LocApiAdapter*)mLocAdapter)->atlOpenStatus(ID, 1,
NULL,
AGPS_APN_BEARER_INVALID,
AGPS_TYPE_INVALID);
break;
default:
LOC_LOGW("DSStateMachine :: informStatus - unknown status");
}
return;
}

View file

@ -38,6 +38,7 @@
#include <linked_list.h> #include <linked_list.h>
#include <LocApiAdapter.h> #include <LocApiAdapter.h>
#include "loc_eng_msg.h" #include "loc_eng_msg.h"
#include <loc_timer.h>
// forward declaration // forward declaration
class AgpsStateMachine; class AgpsStateMachine;
@ -53,6 +54,18 @@ typedef enum {
RSRC_STATUS_MAX RSRC_STATUS_MAX
} AgpsRsrcStatus; } AgpsRsrcStatus;
typedef enum {
servicerTypeNoCbParam,
servicerTypeAgps,
servicerTypeExt
}servicerType;
//DS Callback struct
typedef struct {
LocApiAdapter *mAdapter;
AGpsStatusValue action;
}dsCbData;
// information bundle for subscribers // information bundle for subscribers
struct Notification { struct Notification {
// goes to every subscriber // goes to every subscriber
@ -101,7 +114,7 @@ class AgpsState {
// no class members are public. We don't want // no class members are public. We don't want
// anyone but state machine to use state. // anyone but state machine to use state.
friend class AgpsStateMachine; friend class AgpsStateMachine;
friend class DSStateMachine;
// state transitions are done here. // state transitions are done here.
// Each state implements its own transitions (of course). // Each state implements its own transitions (of course).
inline virtual AgpsState* onRsrcEvent(AgpsRsrcStatus event, void* data) = 0; inline virtual AgpsState* onRsrcEvent(AgpsRsrcStatus event, void* data) = 0;
@ -129,21 +142,56 @@ public:
inline virtual char* whoami() = 0; inline virtual char* whoami() = 0;
}; };
class Servicer {
void (*callback)(void);
public:
static Servicer* getServicer(servicerType type, void *cb_func);
virtual int requestRsrc(void *cb_data);
Servicer() {}
Servicer(void *cb_func)
{ callback = (void(*)(void))(cb_func); }
virtual ~Servicer(){}
inline virtual char *whoami() {return (char*)"Servicer";}
};
class ExtServicer : public Servicer {
int (*callbackExt)(void *cb_data);
public:
int requestRsrc(void *cb_data);
ExtServicer() {}
ExtServicer(void *cb_func)
{ callbackExt = (int(*)(void *))(cb_func); }
virtual ~ExtServicer(){}
inline virtual char *whoami() {return (char*)"ExtServicer";}
};
class AGpsServicer : public Servicer {
void (*callbackAGps)(AGpsStatus* status);
public:
int requestRsrc(void *cb_data);
AGpsServicer() {}
AGpsServicer(void *cb_func)
{ callbackAGps = (void(*)(AGpsStatus *))(cb_func); }
virtual ~AGpsServicer(){}
inline virtual char *whoami() {return (char*)"AGpsServicer";}
};
class AgpsStateMachine { class AgpsStateMachine {
protected:
// a linked list of subscribers.
void* mSubscribers;
//handle to whoever provides the service
Servicer *mServicer;
// allows AgpsState to access private data // allows AgpsState to access private data
// each state is really internal data to the // each state is really internal data to the
// state machine, so it should be able to // state machine, so it should be able to
// access anything within the state machine. // access anything within the state machine.
friend class AgpsState; friend class AgpsState;
// handle to whoever provides the service
void (* const mServicer)(AGpsStatus* status);
// NIF type: AGNSS or INTERNET.
const AGpsType mType;
// pointer to the current state. // pointer to the current state.
AgpsState* mStatePtr; AgpsState* mStatePtr;
// a linked list of subscribers. private:
void* mSubscribers; // NIF type: AGNSS or INTERNET.
const AGpsType mType;
// apn to the NIF. Each state machine tracks // apn to the NIF. Each state machine tracks
// resource state of a particular NIF. For each // resource state of a particular NIF. For each
// NIF, there is also an active APN. // NIF, there is also an active APN.
@ -158,7 +206,8 @@ class AgpsStateMachine {
bool mEnforceSingleSubscriber; bool mEnforceSingleSubscriber;
public: public:
AgpsStateMachine(void (*servicer)(AGpsStatus* status), AGpsType type, bool enforceSingleSubscriber); AgpsStateMachine(servicerType servType, void *cb_func,
AGpsType type, bool enforceSingleSubscriber);
virtual ~AgpsStateMachine(); virtual ~AgpsStateMachine();
// self explanatory methods below // self explanatory methods below
@ -179,11 +228,15 @@ public:
// add a subscriber in the linked list, if not already there. // add a subscriber in the linked list, if not already there.
void addSubscriber(Subscriber* subscriber) const; void addSubscriber(Subscriber* subscriber) const;
void onRsrcEvent(AgpsRsrcStatus event); virtual void onRsrcEvent(AgpsRsrcStatus event);
// put the data together and send the FW // put the data together and send the FW
void sendRsrcRequest(AGpsStatusValue action) const; virtual int sendRsrcRequest(AGpsStatusValue action) const;
//if list is empty, linked_list_empty returns 1
//else if list is not empty, returns 0
//so hasSubscribers() returns 1 if list is not empty
//and returns 0 if list is empty
inline bool hasSubscribers() const inline bool hasSubscribers() const
{ return !linked_list_empty(mSubscribers); } { return !linked_list_empty(mSubscribers); }
@ -194,6 +247,24 @@ public:
// private. Only a state gets to call this. // private. Only a state gets to call this.
void notifySubscribers(Notification& notification) const; void notifySubscribers(Notification& notification) const;
};
class DSStateMachine : public AgpsStateMachine {
static const unsigned char MAX_START_DATA_CALL_RETRIES;
static const unsigned int DATA_CALL_RETRY_DELAY_MSEC;
LocApiAdapter* mLocAdapter;
unsigned char mRetries;
public:
DSStateMachine(servicerType type,
void *cb_func,
LocApiAdapter* adapterHandle);
int sendRsrcRequest(AGpsStatusValue action) const;
void onRsrcEvent(AgpsRsrcStatus event);
void retryCallback();
void informStatus(AgpsRsrcStatus status, int ID) const;
inline void incRetries() {mRetries++;}
inline virtual char *whoami() {return (char*)"DSStateMachine";}
}; };
// each subscriber is a AGPS client. In the case of ATL, there could be // each subscriber is a AGPS client. In the case of ATL, there could be
@ -252,7 +323,7 @@ struct BITSubscriber : public Subscriber {
} }
virtual bool equals(const Subscriber *s) const; virtual bool equals(const Subscriber *s) const;
inline virtual ~BITSubscriber(){}
private: private:
char ipv6Addr[16]; char ipv6Addr[16];
}; };
@ -277,6 +348,7 @@ struct ATLSubscriber : public Subscriber {
return new ATLSubscriber(ID, mStateMachine, mLocAdapter, return new ATLSubscriber(ID, mStateMachine, mLocAdapter,
mBackwardCompatibleMode); mBackwardCompatibleMode);
} }
inline virtual ~ATLSubscriber(){}
}; };
#ifdef FEATURE_IPV6 #ifdef FEATURE_IPV6
@ -325,7 +397,28 @@ struct WIFISubscriber : public Subscriber {
{ {
return new WIFISubscriber(mStateMachine, mSSID, mPassword, senderId); return new WIFISubscriber(mStateMachine, mSSID, mPassword, senderId);
} }
inline virtual ~WIFISubscriber(){}
}; };
#endif #endif
struct DSSubscriber : public Subscriber {
bool mIsInactive;
inline DSSubscriber(const AgpsStateMachine *stateMachine,
const int id) :
Subscriber(id, stateMachine)
{
mIsInactive = false;
}
inline virtual void setIPAddresses(uint32_t &v4, char* v6) {}
virtual Subscriber* clone()
{return new DSSubscriber(mStateMachine, ID);}
virtual bool notifyRsrcStatus(Notification &notification);
inline virtual bool waitForCloseComplete() { return true; }
virtual void setInactive();
inline virtual bool isInactive()
{ return mIsInactive; }
inline virtual ~DSSubscriber(){}
inline virtual char *whoami() {return (char*)"DSSubscriber";}
};
#endif //__LOC_ENG_AGPS_H__ #endif //__LOC_ENG_AGPS_H__

View file

@ -108,7 +108,9 @@ static loc_name_val_s_type loc_eng_msgs[] =
NAME_VAL( LOC_ENG_MSG_LPP_CONFIG ), NAME_VAL( LOC_ENG_MSG_LPP_CONFIG ),
NAME_VAL( ULP_MSG_INJECT_RAW_COMMAND ), NAME_VAL( ULP_MSG_INJECT_RAW_COMMAND ),
NAME_VAL( LOC_ENG_MSG_A_GLONASS_PROTOCOL ), NAME_VAL( LOC_ENG_MSG_A_GLONASS_PROTOCOL ),
NAME_VAL( LOC_ENG_MSG_LOC_INIT ) NAME_VAL( LOC_ENG_MSG_LOC_INIT ),
NAME_VAL( LOC_ENG_MSG_REQUEST_SUPL_ES ),
NAME_VAL( LOC_ENG_MSG_CLOSE_DATA_CALL)
}; };
static int loc_eng_msgs_num = sizeof(loc_eng_msgs) / sizeof(loc_name_val_s_type); static int loc_eng_msgs_num = sizeof(loc_eng_msgs) / sizeof(loc_name_val_s_type);

View file

@ -597,6 +597,23 @@ struct loc_eng_msg_request_atl : public loc_eng_msg {
} }
}; };
struct loc_eng_msg_request_supl_es : public loc_eng_msg {
const int handle;
inline loc_eng_msg_request_supl_es(void* instance, int hndl) :
loc_eng_msg(instance, LOC_ENG_MSG_REQUEST_SUPL_ES),
handle(hndl)
{
LOC_LOGV("handle: %d\n", handle);
}
};
struct loc_eng_msg_close_data_call: public loc_eng_msg {
inline loc_eng_msg_close_data_call(void *instance) :
loc_eng_msg(instance, LOC_ENG_MSG_CLOSE_DATA_CALL)
{
LOC_LOGV("%s:%d]Close data call: ", __func__, __LINE__);
}
};
struct loc_eng_msg_release_atl : public loc_eng_msg { struct loc_eng_msg_release_atl : public loc_eng_msg {
const int handle; const int handle;
inline loc_eng_msg_release_atl(void* instance, int hndl) : inline loc_eng_msg_release_atl(void* instance, int hndl) :
@ -722,12 +739,12 @@ struct loc_eng_msg_inject_xtra_data : public loc_eng_msg {
#ifdef FEATURE_IPV6 #ifdef FEATURE_IPV6
struct loc_eng_msg_atl_open_success : public loc_eng_msg { struct loc_eng_msg_atl_open_success : public loc_eng_msg {
const AGpsStatusValue agpsType; const AGpsType agpsType;
const int length; const int length;
char* const apn; char* const apn;
const AGpsBearerType bearerType; const AGpsBearerType bearerType;
inline loc_eng_msg_atl_open_success(void* instance, inline loc_eng_msg_atl_open_success(void* instance,
AGpsStatusValue atype, AGpsType atype,
const char* name, const char* name,
int len, int len,
AGpsBearerType btype) : AGpsBearerType btype) :
@ -794,9 +811,9 @@ struct loc_eng_msg_atl_open_failed : public loc_eng_msg {
#ifdef FEATURE_IPV6 #ifdef FEATURE_IPV6
struct loc_eng_msg_atl_closed : public loc_eng_msg { struct loc_eng_msg_atl_closed : public loc_eng_msg {
const AGpsStatusValue agpsType; const AGpsType agpsType;
inline loc_eng_msg_atl_closed(void* instance, inline loc_eng_msg_atl_closed(void* instance,
AGpsStatusValue atype) : AGpsType atype) :
loc_eng_msg(instance, LOC_ENG_MSG_ATL_CLOSED), loc_eng_msg(instance, LOC_ENG_MSG_ATL_CLOSED),
agpsType(atype) agpsType(atype)
{ {

View file

@ -134,6 +134,12 @@ enum loc_eng_msg_ids_t {
//Message is sent by LOC to do LOC INIT //Message is sent by LOC to do LOC INIT
LOC_ENG_MSG_LOC_INIT, LOC_ENG_MSG_LOC_INIT,
/*Message is sent by modem to request emergency call setup*/
LOC_ENG_MSG_REQUEST_SUPL_ES,
/*Ask the DS client to close the data call by releasing the handle*/
LOC_ENG_MSG_CLOSE_DATA_CALL,
}; };
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -15,7 +15,8 @@ LOCAL_SHARED_LIBRARIES := \
libqmi_csi \ libqmi_csi \
libqmi_common_so \ libqmi_common_so \
libloc_adapter \ libloc_adapter \
libgps.utils libgps.utils \
libds_api
LOCAL_SRC_FILES += \ LOCAL_SRC_FILES += \
LocApiV02Adapter.cpp \ LocApiV02Adapter.cpp \
@ -41,7 +42,8 @@ LOCAL_C_INCLUDES := \
$(TARGET_OUT_HEADERS)/libloc_eng \ $(TARGET_OUT_HEADERS)/libloc_eng \
$(TARGET_OUT_HEADERS)/qmi-framework/inc \ $(TARGET_OUT_HEADERS)/qmi-framework/inc \
$(TARGET_OUT_HEADERS)/qmi/inc \ $(TARGET_OUT_HEADERS)/qmi/inc \
$(TARGET_OUT_HEADERS)/gps.utils $(TARGET_OUT_HEADERS)/gps.utils \
$(TARGET_OUT_HEADERS)/ds_api
LOCAL_PRELINK_MODULE := false LOCAL_PRELINK_MODULE := false

View file

@ -45,7 +45,6 @@
#include "LocApiAdapter.h" #include "LocApiAdapter.h"
#include "loc_util_log.h" #include "loc_util_log.h"
/* Default session id ; TBD needs incrementing for each */ /* Default session id ; TBD needs incrementing for each */
#define LOC_API_V02_DEF_SESSION_ID (1) #define LOC_API_V02_DEF_SESSION_ID (1)
@ -160,6 +159,7 @@ locClientCallbacksType globalCallbacks =
/* Constructor for LocApiV02Adapter */ /* Constructor for LocApiV02Adapter */
LocApiV02Adapter :: LocApiV02Adapter(LocEng &locEng): LocApiV02Adapter :: LocApiV02Adapter(LocEng &locEng):
dsClientHandle(NULL),
LocApiAdapter(locEng), clientHandle( LOC_CLIENT_INVALID_HANDLE_VALUE), LocApiAdapter(locEng), clientHandle( LOC_CLIENT_INVALID_HANDLE_VALUE),
eventMask(convertMask(locEng.eventMask)) eventMask(convertMask(locEng.eventMask))
{ {
@ -1059,6 +1059,7 @@ enum loc_api_adapter_err LocApiV02Adapter :: atlOpenStatus(
{ {
conn_status_req.statusType = eQMI_LOC_SERVER_REQ_STATUS_SUCCESS_V02; conn_status_req.statusType = eQMI_LOC_SERVER_REQ_STATUS_SUCCESS_V02;
if(apn != NULL)
strlcpy(conn_status_req.apnProfile.apnName, apn, strlcpy(conn_status_req.apnProfile.apnName, apn,
sizeof(conn_status_req.apnProfile.apnName) ); sizeof(conn_status_req.apnProfile.apnName) );
@ -1068,16 +1069,23 @@ enum loc_api_adapter_err LocApiV02Adapter :: atlOpenStatus(
case AGPS_APN_BEARER_IPV4: case AGPS_APN_BEARER_IPV4:
conn_status_req.apnProfile.pdnType = conn_status_req.apnProfile.pdnType =
eQMI_LOC_APN_PROFILE_PDN_TYPE_IPV4_V02; eQMI_LOC_APN_PROFILE_PDN_TYPE_IPV4_V02;
conn_status_req.apnProfile_valid = 1;
break; break;
case AGPS_APN_BEARER_IPV6: case AGPS_APN_BEARER_IPV6:
conn_status_req.apnProfile.pdnType = conn_status_req.apnProfile.pdnType =
eQMI_LOC_APN_PROFILE_PDN_TYPE_IPV6_V02; eQMI_LOC_APN_PROFILE_PDN_TYPE_IPV6_V02;
conn_status_req.apnProfile_valid = 1;
break; break;
case AGPS_APN_BEARER_IPV4V6: case AGPS_APN_BEARER_IPV4V6:
conn_status_req.apnProfile.pdnType = conn_status_req.apnProfile.pdnType =
eQMI_LOC_APN_PROFILE_PDN_TYPE_IPV4V6_V02; eQMI_LOC_APN_PROFILE_PDN_TYPE_IPV4V6_V02;
conn_status_req.apnProfile_valid = 1;
break;
case AGPS_APN_BEARER_INVALID:
conn_status_req.apnProfile_valid = 0;
break; break;
default: default:
@ -1089,7 +1097,6 @@ enum loc_api_adapter_err LocApiV02Adapter :: atlOpenStatus(
eQMI_LOC_APN_PROFILE_PDN_TYPE_IPV4_V02; eQMI_LOC_APN_PROFILE_PDN_TYPE_IPV4_V02;
#endif #endif
conn_status_req.apnProfile_valid = 1;
} }
else else
{ {
@ -1523,7 +1530,6 @@ enum loc_api_adapter_err LocApiV02Adapter :: setAGLONASSProtocol(unsigned long a
return LOC_API_ADAPTER_ERR_SUCCESS; return LOC_API_ADAPTER_ERR_SUCCESS;
} }
/* Convert event mask from loc eng to loc_api_v02 format */ /* Convert event mask from loc eng to loc_api_v02 format */
locClientEventMaskType LocApiV02Adapter :: convertMask( locClientEventMaskType LocApiV02Adapter :: convertMask(
LOC_API_ADAPTER_EVENT_MASK_T mask) LOC_API_ADAPTER_EVENT_MASK_T mask)
@ -1920,22 +1926,25 @@ void LocApiV02Adapter :: reportAtlRequest(
{ {
case eQMI_LOC_WWAN_TYPE_INTERNET_V02: case eQMI_LOC_WWAN_TYPE_INTERNET_V02:
agpsType = AGPS_TYPE_WWAN_ANY; agpsType = AGPS_TYPE_WWAN_ANY;
LocApiAdapter::requestATL(connHandle, agpsType);
break; break;
case eQMI_LOC_WWAN_TYPE_AGNSS_V02: case eQMI_LOC_WWAN_TYPE_AGNSS_V02:
agpsType = AGPS_TYPE_SUPL; agpsType = AGPS_TYPE_SUPL;
LocApiAdapter::requestATL(connHandle, agpsType);
break;
case eQMI_LOC_WWAN_TYPE_AGNSS_EMERGENCY_V02:
LocApiAdapter::requestSuplES(connHandle);
break; break;
default: default:
agpsType = AGPS_TYPE_WWAN_ANY; agpsType = AGPS_TYPE_WWAN_ANY;
LocApiAdapter::requestATL(connHandle, agpsType);
break; break;
} }
#else #else
agpsType = AGPS_TYPE_SUPL; agpsType = AGPS_TYPE_SUPL;
#endif
LocApiAdapter::requestATL(connHandle, agpsType); LocApiAdapter::requestATL(connHandle, agpsType);
#endif
} }
// service the ATL close request // service the ATL close request
else if (server_request_ptr->requestType == eQMI_LOC_SERVER_REQUEST_CLOSE_V02) else if (server_request_ptr->requestType == eQMI_LOC_SERVER_REQUEST_CLOSE_V02)
{ {
@ -2255,3 +2264,98 @@ LocApiAdapter* getLocApiAdapter(LocEng &locEng)
{ {
return(new LocApiV02Adapter(locEng)); return(new LocApiV02Adapter(locEng));
} }
static void ds_client_global_event_cb(ds_client_status_enum_type result,
void *loc_adapter_cookie)
{
LocApiV02Adapter *locApiV02AdapterInstance =
(LocApiV02Adapter *)loc_adapter_cookie;
locApiV02AdapterInstance->ds_client_event_cb(result);
return;
}
void LocApiV02Adapter::ds_client_event_cb(ds_client_status_enum_type result)
{
if(result == E_DS_CLIENT_DATA_CALL_CONNECTED) {
LOC_LOGD("%s:%d]: Emergency call is up", __func__, __LINE__);
LocApiAdapter::reportDataCallOpened();
}
else if(result == E_DS_CLIENT_DATA_CALL_DISCONNECTED) {
LOC_LOGE("%s:%d]: Emergency call is stopped", __func__, __LINE__);
LocApiAdapter::reportDataCallClosed();
}
return;
}
ds_client_cb_data ds_client_cb{
ds_client_global_event_cb
};
int LocApiV02Adapter :: openAndStartDataCall()
{
enum loc_api_adapter_err ret;
int profile_index;
ds_client_status_enum_type result = ds_client_open_call(&dsClientHandle,
&ds_client_cb,
(void *)this,
&profile_index);
if(result == E_DS_CLIENT_SUCCESS) {
result = ds_client_start_call(dsClientHandle, profile_index);
if(result == E_DS_CLIENT_SUCCESS) {
LOC_LOGD("%s:%d]: Request to start Emergency call sent\n",
__func__, __LINE__);
ret = LOC_API_ADAPTER_ERR_SUCCESS;
}
else {
LOC_LOGE("%s:%d]: Unable to bring up emergency call using DS. ret = %d",
__func__, __LINE__, (int)ret);
ret = LOC_API_ADAPTER_ERR_UNSUPPORTED;
}
}
else if(result == E_DS_CLIENT_RETRY_LATER) {
LOC_LOGE("%s:%d]: Could not start emergency call. Retry after delay\n",
__func__, __LINE__);
ret = LOC_API_ADAPTER_ERR_ENGINE_BUSY;
}
else {
LOC_LOGE("%s:%d]: Unable to bring up emergency call using DS. ret = %d",
__func__, __LINE__, (int)ret);
ret = LOC_API_ADAPTER_ERR_UNSUPPORTED;
}
return (int)ret;
}
void LocApiV02Adapter :: stopDataCall()
{
ds_client_status_enum_type ret =
ds_client_stop_call(dsClientHandle);
if (ret == E_DS_CLIENT_SUCCESS) {
LOC_LOGD("%s:%d]: Request to Close SUPL ES call sent\n", __func__, __LINE__);
}
else {
if (ret == E_DS_CLIENT_FAILURE_INVALID_HANDLE) {
LOC_LOGE("%s:%d]: Conn handle not found for SUPL ES",
__func__, __LINE__);
}
LOC_LOGE("%s:%d]: Could not close SUPL ES call. Ret: %d\n"
,__func__, __LINE__, ret);
}
return;
}
void LocApiV02Adapter :: closeDataCall()
{
ds_client_close_call(&dsClientHandle);
LOC_LOGD("%s:%d]: Release data client handle\n", __func__, __LINE__);
return;
}
int LocApiV02Adapter :: initDataServiceClient()
{
int ret=0;
ret = ds_client_init();
LOC_LOGD("%s:%d]: ret = %d\n", __func__, __LINE__,ret);
return ret;
}

View file

@ -33,6 +33,7 @@
#include "loc_api_v02_client.h" #include "loc_api_v02_client.h"
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include "ds_client.h"
/* This class derives from the LocApiAdapter class. /* This class derives from the LocApiAdapter class.
The members of this class are responsible for converting The members of this class are responsible for converting
@ -40,6 +41,8 @@
This class also implements some of the virtual functions that This class also implements some of the virtual functions that
handle the requests from loc engine. */ handle the requests from loc engine. */
class LocApiV02Adapter : public LocApiAdapter { class LocApiV02Adapter : public LocApiAdapter {
/*ds client handle*/
dsClientHandleType dsClientHandle;
/* loc api v02 handle*/ /* loc api v02 handle*/
locClientHandleType clientHandle; locClientHandleType clientHandle;
@ -110,6 +113,12 @@ public:
void errorCb(locClientHandleType handle, void errorCb(locClientHandleType handle,
locClientErrorEnumType errorId); locClientErrorEnumType errorId);
void ds_client_event_cb(ds_client_status_enum_type result);
int openAndStartDataCall();
void stopDataCall();
void closeDataCall();
int initDataServiceClient();
virtual enum loc_api_adapter_err reinit(); virtual enum loc_api_adapter_err reinit();
virtual enum loc_api_adapter_err startFix(); virtual enum loc_api_adapter_err startFix();