diff --git a/loc_api/Android.mk b/loc_api/Android.mk index dd7a8f31..5613c87d 100644 --- a/loc_api/Android.mk +++ b/loc_api/Android.mk @@ -27,6 +27,7 @@ endif 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)/ds_api/ endif #is-board-platform-in-list GPS_DIR_LIST += $(LOCAL_PATH)/libloc_api_50001/ diff --git a/loc_api/ds_api/Android.mk b/loc_api/ds_api/Android.mk new file mode 100644 index 00000000..ca04f51d --- /dev/null +++ b/loc_api/ds_api/Android.mk @@ -0,0 +1,49 @@ +ifneq ($(BUILD_TINY_ANDROID),true) + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := 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 diff --git a/loc_api/ds_api/ds_client.c b/loc_api/ds_api/ds_client.c new file mode 100644 index 00000000..2dcf0636 --- /dev/null +++ b/loc_api/ds_api/ds_client.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +//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;ievent_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, ¬ifier); + 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, + ¶m_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; +} diff --git a/loc_api/ds_api/ds_client.h b/loc_api/ds_api/ds_client.h new file mode 100644 index 00000000..044f96a3 --- /dev/null +++ b/loc_api/ds_api/ds_client.h @@ -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 diff --git a/loc_api/libloc_api_50001/LocApiAdapter.cpp b/loc_api/libloc_api_50001/LocApiAdapter.cpp index 8e5b1ee1..8d84b0d3 100644 --- a/loc_api/libloc_api_50001/LocApiAdapter.cpp +++ b/loc_api/libloc_api_50001/LocApiAdapter.cpp @@ -186,6 +186,18 @@ void LocApiAdapter::requestATL(int connHandle, AGpsType agps_type) 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) { 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)); 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); +} diff --git a/loc_api/libloc_api_50001/LocApiAdapter.h b/loc_api/libloc_api_50001/LocApiAdapter.h index 65fac91a..f0d4215b 100644 --- a/loc_api/libloc_api_50001/LocApiAdapter.h +++ b/loc_api/libloc_api_50001/LocApiAdapter.h @@ -141,7 +141,10 @@ public: void requestNiNotify(GpsNiNotification ¬ify, const void* data); void handleEngineDownEvent(); 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: // RPC, QMI, etc. The default implementation is empty. inline virtual enum loc_api_adapter_err @@ -230,6 +233,15 @@ public: inline bool isInSession() { return navigating; } 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); diff --git a/loc_api/libloc_api_50001/loc_eng.cpp b/loc_api/libloc_api_50001/loc_eng.cpp index 319b4de9..0422f505 100644 --- a/loc_api/libloc_api_50001/loc_eng.cpp +++ b/loc_api/libloc_api_50001/loc_eng.cpp @@ -60,7 +60,6 @@ #include #include #include - #include "log_util.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); } +/* + 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 @@ -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.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, false); #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, 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, true); #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, NULL, NULL, &loc_eng_data); @@ -1741,14 +1782,27 @@ static void loc_eng_deferred_action_thread(void* arg) loc_eng_data_p->client_handle, false); // 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 + LOC_LOGD("%s:%d]: Unsubscribed from agnss_nif", __func__, __LINE__); + } + else { ATLSubscriber s2(arlMsg->handle, loc_eng_data_p->internet_nif, loc_eng_data_p->client_handle, false); // 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 } } @@ -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; AgpsStateMachine* stateMachine; #ifdef FEATURE_IPV6 + LOC_LOGD("%s:%d]: AGPS_TYPE: %d\n", __func__, __LINE__, (int)aosMsg->agpsType); switch (aosMsg->agpsType) { case AGPS_TYPE_WIFI: { + LOC_LOGD("%s:%d]: AGPS Type wifi\n", __func__, __LINE__); stateMachine = loc_eng_data_p->wifi_nif; break; } case AGPS_TYPE_SUPL: { + LOC_LOGD("%s:%d]: AGPS Type supl\n", __func__, __LINE__); stateMachine = loc_eng_data_p->agnss_nif; break; } + case AGPS_TYPE_INVALID: { + stateMachine = loc_eng_data_p->ds_nif; + LOC_LOGD("%s:%d]: AGPS Type invalid\n", __func__, __LINE__); + } + break; default: { + LOC_LOGD("%s:%d]: AGPS Type default internet\n", __func__, __LINE__); 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; break; } + case AGPS_TYPE_INVALID: { + stateMachine = loc_eng_data_p->ds_nif; + break; + } default: { 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_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) { 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; + 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: LOC_LOGE("unsupported msgid = %d\n", msg->msgid); break; @@ -2273,4 +2359,3 @@ int loc_eng_read_config(void) EXIT_LOG(%d, 0); return 0; } - diff --git a/loc_api/libloc_api_50001/loc_eng.h b/loc_api/libloc_api_50001/loc_eng.h index d61cb12b..04d6714b 100644 --- a/loc_api/libloc_api_50001/loc_eng.h +++ b/loc_api/libloc_api_50001/loc_eng.h @@ -121,6 +121,8 @@ typedef struct AgpsStateMachine* agnss_nif; AgpsStateMachine* internet_nif; AgpsStateMachine* wifi_nif; + //State machine for Data Services + AgpsStateMachine* ds_nif; // GPS engine status GpsStatusValue engine_status; diff --git a/loc_api/libloc_api_50001/loc_eng_agps.cpp b/loc_api/libloc_api_50001/loc_eng_agps.cpp index 5bdae3d7..1d5a59bb 100644 --- a/loc_api/libloc_api_50001/loc_eng_agps.cpp +++ b/loc_api/libloc_api_50001/loc_eng_agps.cpp @@ -35,6 +35,7 @@ #include #include #include +#include //====================================================================== // C callbacks @@ -84,8 +85,8 @@ static bool notifySubscriber(void* fromCaller, void* fromList) const int Notification::BROADCAST_ALL = 0x80000000; const int Notification::BROADCAST_ACTIVE = 0x80000001; 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 //====================================================================== @@ -227,7 +228,29 @@ bool WIFISubscriber::notifyRsrcStatus(Notification ¬ification) return notify; } #endif - +bool DSSubscriber::notifyRsrcStatus(Notification ¬ification) +{ + 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 //====================================================================== @@ -249,13 +272,14 @@ public: AgpsState* AgpsReleasedState::onRsrcEvent(AgpsRsrcStatus event, void* data) { + LOC_LOGD("AgpsReleasedState::onRsrcEvent; event:%d\n", (int)event); if (mStateMachine->hasSubscribers()) { LOC_LOGE("Error: %s subscriber list not empty!!!", whoami()); // I don't know how to recover from it. I am adding this rather // for debugging purpose. } - AgpsState* nextState = this;; + AgpsState* nextState = this; switch (event) { case RSRC_SUBSCRIBE: @@ -263,13 +287,16 @@ AgpsState* AgpsReleasedState::onRsrcEvent(AgpsRsrcStatus event, void* data) // no notification until we get RSRC_GRANTED // but we need to add subscriber to the list mStateMachine->addSubscriber((Subscriber*)data); - // move the state to PENDING - nextState = mPendingState; - // request from connecivity service for NIF - mStateMachine->sendRsrcRequest(GPS_REQUEST_AGPS_DATA_CONN); + //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 + nextState = mPendingState; + } } - break; + break; case RSRC_UNSUBSCRIBE: { @@ -313,6 +340,7 @@ public: AgpsState* AgpsPendingState::onRsrcEvent(AgpsRsrcStatus event, void* data) { AgpsState* nextState = this;; + LOC_LOGD("AgpsPendingState::onRsrcEvent; event:%d\n", (int)event); switch (event) { case RSRC_SUBSCRIBE: @@ -351,7 +379,7 @@ AgpsState* AgpsPendingState::onRsrcEvent(AgpsRsrcStatus event, void* data) mStateMachine->sendRsrcRequest(GPS_RELEASE_AGPS_DATA_CONN); } } - break; + break; case RSRC_GRANTED: { @@ -408,6 +436,7 @@ public: AgpsState* AgpsAcquiredState::onRsrcEvent(AgpsRsrcStatus event, void* data) { AgpsState* nextState = this; + LOC_LOGD("AgpsAcquiredState::onRsrcEvent; event:%d\n", (int)event); switch (event) { case RSRC_SUBSCRIBE: @@ -441,7 +470,8 @@ AgpsState* AgpsAcquiredState::onRsrcEvent(AgpsRsrcStatus event, void* data) // tell connecivity service we can release NIF mStateMachine->sendRsrcRequest(GPS_RELEASE_AGPS_DATA_CONN); - } else if (!mStateMachine->hasActiveSubscribers()) { + } + else if (!mStateMachine->hasActiveSubscribers()) { // only inactive subscribers, move to RELEASING state nextState = mReleasingState; @@ -500,7 +530,9 @@ public: AgpsState* AgpsReleasingState::onRsrcEvent(AgpsRsrcStatus event, void* data) { AgpsState* nextState = this;; - switch (event) + LOC_LOGD("AgpsReleasingState::onRsrcEvent; event:%d\n", (int)event); + + switch (event) { case RSRC_SUBSCRIBE: { @@ -541,7 +573,7 @@ AgpsState* AgpsReleasingState::onRsrcEvent(AgpsRsrcStatus event, void* data) // by setting false, we keep subscribers on the linked list mStateMachine->notifySubscribers(notification); - if (mStateMachine->hasSubscribers()) { + if (mStateMachine->hasActiveSubscribers()) { nextState = mPendingState; // request from connecivity service for NIF mStateMachine->sendRsrcRequest(GPS_REQUEST_AGPS_DATA_CONN); @@ -561,20 +593,58 @@ AgpsState* AgpsReleasingState::onRsrcEvent(AgpsRsrcStatus event, void* data) whoami(), nextState->whoami(), event); 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(void (*servicer)(AGpsStatus* status), +AgpsStateMachine::AgpsStateMachine(servicerType servType, + void *cb_func, AGpsType type, bool enforceSingleSubscriber) : - mServicer(servicer), mType(type), - mStatePtr(new AgpsReleasedState(this)), + mStatePtr(new AgpsReleasedState(this)),mType(type), mAPN(NULL), mAPNLen(0), - mEnforceSingleSubscriber(enforceSingleSubscriber) + mEnforceSingleSubscriber(enforceSingleSubscriber), + mServicer(Servicer :: getServicer(servType, (void *)cb_func)) { linked_list_init(&mSubscribers); @@ -615,6 +685,7 @@ AgpsStateMachine::~AgpsStateMachine() delete releasedState; delete pendindState; delete releasingState; + delete mServicer; linked_list_destroy(&mSubscribers); if (NULL != mAPN) { @@ -669,6 +740,7 @@ void AgpsStateMachine::notifySubscribers(Notification& notification) const // rest of the list unprocessed. So we need a loop. linked_list_search(mSubscribers, (void**)&s, notifySubscriber, (void*)¬ification, true); + delete s; } } else { // 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; Notification notification(Notification::BROADCAST_ACTIVE); @@ -722,8 +794,9 @@ void AgpsStateMachine::sendRsrcRequest(AGpsStatusValue action) const #endif 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) @@ -758,3 +831,163 @@ bool AgpsStateMachine::hasActiveSubscribers() const hasSubscriber, (void*)¬ification, false); 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*)¬ification, 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*)¬ification, 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; +} diff --git a/loc_api/libloc_api_50001/loc_eng_agps.h b/loc_api/libloc_api_50001/loc_eng_agps.h index 22160c36..4fad021e 100644 --- a/loc_api/libloc_api_50001/loc_eng_agps.h +++ b/loc_api/libloc_api_50001/loc_eng_agps.h @@ -38,6 +38,7 @@ #include #include #include "loc_eng_msg.h" +#include // forward declaration class AgpsStateMachine; @@ -53,6 +54,18 @@ typedef enum { RSRC_STATUS_MAX } AgpsRsrcStatus; +typedef enum { + servicerTypeNoCbParam, + servicerTypeAgps, + servicerTypeExt +}servicerType; + +//DS Callback struct +typedef struct { + LocApiAdapter *mAdapter; + AGpsStatusValue action; +}dsCbData; + // information bundle for subscribers struct Notification { // goes to every subscriber @@ -101,7 +114,7 @@ class AgpsState { // no class members are public. We don't want // anyone but state machine to use state. friend class AgpsStateMachine; - + friend class DSStateMachine; // state transitions are done here. // Each state implements its own transitions (of course). inline virtual AgpsState* onRsrcEvent(AgpsRsrcStatus event, void* data) = 0; @@ -129,21 +142,56 @@ public: 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 { +protected: + // a linked list of subscribers. + void* mSubscribers; + //handle to whoever provides the service + Servicer *mServicer; // allows AgpsState to access private data // each state is really internal data to the // state machine, so it should be able to // access anything within the state machine. 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. AgpsState* mStatePtr; - // a linked list of subscribers. - void* mSubscribers; +private: + // NIF type: AGNSS or INTERNET. + const AGpsType mType; // apn to the NIF. Each state machine tracks // resource state of a particular NIF. For each // NIF, there is also an active APN. @@ -158,7 +206,8 @@ class AgpsStateMachine { bool mEnforceSingleSubscriber; public: - AgpsStateMachine(void (*servicer)(AGpsStatus* status), AGpsType type, bool enforceSingleSubscriber); + AgpsStateMachine(servicerType servType, void *cb_func, + AGpsType type, bool enforceSingleSubscriber); virtual ~AgpsStateMachine(); // self explanatory methods below @@ -179,11 +228,15 @@ public: // add a subscriber in the linked list, if not already there. void addSubscriber(Subscriber* subscriber) const; - void onRsrcEvent(AgpsRsrcStatus event); + virtual void onRsrcEvent(AgpsRsrcStatus event); // 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 { return !linked_list_empty(mSubscribers); } @@ -194,6 +247,24 @@ public: // private. Only a state gets to call this. 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 @@ -252,7 +323,7 @@ struct BITSubscriber : public Subscriber { } virtual bool equals(const Subscriber *s) const; - + inline virtual ~BITSubscriber(){} private: char ipv6Addr[16]; }; @@ -277,6 +348,7 @@ struct ATLSubscriber : public Subscriber { return new ATLSubscriber(ID, mStateMachine, mLocAdapter, mBackwardCompatibleMode); } + inline virtual ~ATLSubscriber(){} }; #ifdef FEATURE_IPV6 @@ -325,7 +397,28 @@ struct WIFISubscriber : public Subscriber { { return new WIFISubscriber(mStateMachine, mSSID, mPassword, senderId); } + inline virtual ~WIFISubscriber(){} }; #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 ¬ification); + 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__ diff --git a/loc_api/libloc_api_50001/loc_eng_log.cpp b/loc_api/libloc_api_50001/loc_eng_log.cpp index ce1bcdf5..9b4a21b9 100644 --- a/loc_api/libloc_api_50001/loc_eng_log.cpp +++ b/loc_api/libloc_api_50001/loc_eng_log.cpp @@ -108,7 +108,9 @@ static loc_name_val_s_type loc_eng_msgs[] = NAME_VAL( LOC_ENG_MSG_LPP_CONFIG ), NAME_VAL( ULP_MSG_INJECT_RAW_COMMAND ), 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); diff --git a/loc_api/libloc_api_50001/loc_eng_msg.h b/loc_api/libloc_api_50001/loc_eng_msg.h index df7cc092..116f551c 100644 --- a/loc_api/libloc_api_50001/loc_eng_msg.h +++ b/loc_api/libloc_api_50001/loc_eng_msg.h @@ -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 { const int handle; 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 struct loc_eng_msg_atl_open_success : public loc_eng_msg { - const AGpsStatusValue agpsType; + const AGpsType agpsType; const int length; char* const apn; const AGpsBearerType bearerType; inline loc_eng_msg_atl_open_success(void* instance, - AGpsStatusValue atype, + AGpsType atype, const char* name, int len, AGpsBearerType btype) : @@ -794,9 +811,9 @@ struct loc_eng_msg_atl_open_failed : public loc_eng_msg { #ifdef FEATURE_IPV6 struct loc_eng_msg_atl_closed : public loc_eng_msg { - const AGpsStatusValue agpsType; + const AGpsType agpsType; inline loc_eng_msg_atl_closed(void* instance, - AGpsStatusValue atype) : + AGpsType atype) : loc_eng_msg(instance, LOC_ENG_MSG_ATL_CLOSED), agpsType(atype) { diff --git a/loc_api/libloc_api_50001/loc_eng_msg_id.h b/loc_api/libloc_api_50001/loc_eng_msg_id.h index 7b0aee05..fb3dfd32 100644 --- a/loc_api/libloc_api_50001/loc_eng_msg_id.h +++ b/loc_api/libloc_api_50001/loc_eng_msg_id.h @@ -134,6 +134,12 @@ enum loc_eng_msg_ids_t { //Message is sent by LOC to do 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 diff --git a/loc_api/loc_api_v02/Android.mk b/loc_api/loc_api_v02/Android.mk index 8617f3cb..1835dc58 100644 --- a/loc_api/loc_api_v02/Android.mk +++ b/loc_api/loc_api_v02/Android.mk @@ -15,7 +15,8 @@ LOCAL_SHARED_LIBRARIES := \ libqmi_csi \ libqmi_common_so \ libloc_adapter \ - libgps.utils + libgps.utils \ + libds_api LOCAL_SRC_FILES += \ LocApiV02Adapter.cpp \ @@ -41,7 +42,8 @@ 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)/gps.utils \ + $(TARGET_OUT_HEADERS)/ds_api LOCAL_PRELINK_MODULE := false diff --git a/loc_api/loc_api_v02/LocApiV02Adapter.cpp b/loc_api/loc_api_v02/LocApiV02Adapter.cpp index d7276e95..16532e89 100644 --- a/loc_api/loc_api_v02/LocApiV02Adapter.cpp +++ b/loc_api/loc_api_v02/LocApiV02Adapter.cpp @@ -45,7 +45,6 @@ #include "LocApiAdapter.h" #include "loc_util_log.h" - /* Default session id ; TBD needs incrementing for each */ #define LOC_API_V02_DEF_SESSION_ID (1) @@ -160,6 +159,7 @@ locClientCallbacksType globalCallbacks = /* Constructor for LocApiV02Adapter */ LocApiV02Adapter :: LocApiV02Adapter(LocEng &locEng): + dsClientHandle(NULL), LocApiAdapter(locEng), clientHandle( LOC_CLIENT_INVALID_HANDLE_VALUE), eventMask(convertMask(locEng.eventMask)) { @@ -1059,28 +1059,36 @@ enum loc_api_adapter_err LocApiV02Adapter :: atlOpenStatus( { conn_status_req.statusType = eQMI_LOC_SERVER_REQ_STATUS_SUCCESS_V02; - strlcpy(conn_status_req.apnProfile.apnName, apn, - sizeof(conn_status_req.apnProfile.apnName) ); + if(apn != NULL) + strlcpy(conn_status_req.apnProfile.apnName, apn, + sizeof(conn_status_req.apnProfile.apnName) ); #ifdef FEATURE_IPV6 switch(bear) { - case AGPS_APN_BEARER_IPV4: + case AGPS_APN_BEARER_IPV4: 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; - case AGPS_APN_BEARER_IPV6: + case AGPS_APN_BEARER_IPV6: 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; - case AGPS_APN_BEARER_IPV4V6: + case AGPS_APN_BEARER_IPV4V6: 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; - default: + case AGPS_APN_BEARER_INVALID: + conn_status_req.apnProfile_valid = 0; + break; + + default: LOC_LOGE("%s:%d]:invalid bearer type\n",__func__,__LINE__); return LOC_API_ADAPTER_ERR_INVALID_HANDLE; } @@ -1089,7 +1097,6 @@ enum loc_api_adapter_err LocApiV02Adapter :: atlOpenStatus( eQMI_LOC_APN_PROFILE_PDN_TYPE_IPV4_V02; #endif - conn_status_req.apnProfile_valid = 1; } else { @@ -1523,7 +1530,6 @@ enum loc_api_adapter_err LocApiV02Adapter :: setAGLONASSProtocol(unsigned long a return LOC_API_ADAPTER_ERR_SUCCESS; } - /* Convert event mask from loc eng to loc_api_v02 format */ locClientEventMaskType LocApiV02Adapter :: convertMask( LOC_API_ADAPTER_EVENT_MASK_T mask) @@ -1908,39 +1914,42 @@ void LocApiV02Adapter :: reportNmea ( /* convert and report an ATL request to loc engine */ void LocApiV02Adapter :: reportAtlRequest( - const qmiLocEventLocationServerConnectionReqIndMsgT_v02 * server_request_ptr) + const qmiLocEventLocationServerConnectionReqIndMsgT_v02 * server_request_ptr) { - uint32_t connHandle = server_request_ptr->connHandle; - // service ATL open request; copy the WWAN type - if(server_request_ptr->requestType == eQMI_LOC_SERVER_REQUEST_OPEN_V02 ) - { - AGpsType agpsType; -#ifdef FEATURE_IPV6 - switch(server_request_ptr->wwanType) + uint32_t connHandle = server_request_ptr->connHandle; + // service ATL open request; copy the WWAN type + if(server_request_ptr->requestType == eQMI_LOC_SERVER_REQUEST_OPEN_V02 ) { - case eQMI_LOC_WWAN_TYPE_INTERNET_V02: - agpsType = AGPS_TYPE_WWAN_ANY; - break; - - case eQMI_LOC_WWAN_TYPE_AGNSS_V02: - agpsType = AGPS_TYPE_SUPL; - break; - - default: - agpsType = AGPS_TYPE_WWAN_ANY; - break; - } + AGpsType agpsType; +#ifdef FEATURE_IPV6 + switch(server_request_ptr->wwanType) + { + case eQMI_LOC_WWAN_TYPE_INTERNET_V02: + agpsType = AGPS_TYPE_WWAN_ANY; + LocApiAdapter::requestATL(connHandle, agpsType); + break; + case eQMI_LOC_WWAN_TYPE_AGNSS_V02: + agpsType = AGPS_TYPE_SUPL; + LocApiAdapter::requestATL(connHandle, agpsType); + break; + case eQMI_LOC_WWAN_TYPE_AGNSS_EMERGENCY_V02: + LocApiAdapter::requestSuplES(connHandle); + break; + default: + agpsType = AGPS_TYPE_WWAN_ANY; + LocApiAdapter::requestATL(connHandle, agpsType); + break; + } #else - agpsType = AGPS_TYPE_SUPL; + agpsType = AGPS_TYPE_SUPL; + LocApiAdapter::requestATL(connHandle, agpsType); #endif - LocApiAdapter::requestATL(connHandle, agpsType); - } - - // service the ATL close request - else if (server_request_ptr->requestType == eQMI_LOC_SERVER_REQUEST_CLOSE_V02) - { - LocApiAdapter::releaseATL(connHandle); - } + } + // service the ATL close request + else if (server_request_ptr->requestType == eQMI_LOC_SERVER_REQUEST_CLOSE_V02) + { + LocApiAdapter::releaseATL(connHandle); + } } /* conver the NI report to loc eng format and send t loc engine */ @@ -2255,3 +2264,98 @@ LocApiAdapter* getLocApiAdapter(LocEng &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; +} diff --git a/loc_api/loc_api_v02/LocApiV02Adapter.h b/loc_api/loc_api_v02/LocApiV02Adapter.h index 10ea4069..df5ab527 100644 --- a/loc_api/loc_api_v02/LocApiV02Adapter.h +++ b/loc_api/loc_api_v02/LocApiV02Adapter.h @@ -33,6 +33,7 @@ #include "loc_api_v02_client.h" #include #include +#include "ds_client.h" /* This class derives from the LocApiAdapter class. The members of this class are responsible for converting @@ -40,6 +41,8 @@ This class also implements some of the virtual functions that handle the requests from loc engine. */ class LocApiV02Adapter : public LocApiAdapter { + /*ds client handle*/ + dsClientHandleType dsClientHandle; /* loc api v02 handle*/ locClientHandleType clientHandle; @@ -110,6 +113,12 @@ public: void errorCb(locClientHandleType handle, 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 startFix();