Add support for SUPL Emergency Services

Introduced support for handling modem request
to start an emergency call using QMI WDS profiles
or fallback to an ATL request if the call does
not succeed.

Change-Id: I29b617687db0d3f26610bc74f8dc95940574f52d
This commit is contained in:
Tushar Janefalkar 2013-02-25 11:40:32 -08:00 committed by Gerrit - the friendly Code Review server
parent 711863f2f3
commit 0f66892e50
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();