1534 lines
51 KiB
C++
1534 lines
51 KiB
C++
/* Copyright (c) 2009,2011 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_NDDEBUG 0
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
#include <pthread.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
|
|
#include <rpc/rpc.h>
|
|
#include "loc_api_rpc_glue.h"
|
|
#include "loc_apicb_appinit.h"
|
|
|
|
#include <cutils/properties.h>
|
|
#include <cutils/sched_policy.h>
|
|
#include <utils/SystemClock.h>
|
|
|
|
#include <loc_eng.h>
|
|
#include <loc_eng_ni.h>
|
|
|
|
#define LOG_TAG "lib_locapi"
|
|
#include <utils/Log.h>
|
|
|
|
// comment this out to enable logging
|
|
// #undef LOGD
|
|
// #define LOGD(...) {}
|
|
|
|
#define DEBUG_MOCK_NI 0
|
|
|
|
// Function declarations for sLocEngInterface
|
|
static int loc_eng_init(GpsCallbacks* callbacks);
|
|
static int loc_eng_start();
|
|
static int loc_eng_stop();
|
|
static int loc_eng_set_position_mode(GpsPositionMode mode, GpsPositionRecurrence recurrence,
|
|
uint32_t min_interval, uint32_t preferred_accuracy, uint32_t preferred_time);
|
|
static void loc_eng_cleanup();
|
|
static int loc_eng_inject_time(GpsUtcTime time, int64_t timeReference, int uncertainty);
|
|
static int loc_eng_inject_location(double latitude, double longitude, float accuracy);
|
|
static void loc_eng_delete_aiding_data (GpsAidingData f);
|
|
static const void* loc_eng_get_extension(const char* name);
|
|
|
|
// Function declarations for sLocEngAGpsInterface
|
|
static void loc_eng_agps_init(AGpsCallbacks* callbacks);
|
|
static int loc_eng_agps_data_conn_open(const char* apn);
|
|
static int loc_eng_agps_data_conn_closed();
|
|
static int loc_eng_agps_data_conn_failed();
|
|
static int loc_eng_agps_set_server(AGpsType type, const char* hostname, int port);
|
|
|
|
|
|
static int32 loc_event_cb (rpc_loc_client_handle_type client_handle,
|
|
rpc_loc_event_mask_type loc_event,
|
|
const rpc_loc_event_payload_u_type* loc_event_payload);
|
|
static void loc_eng_report_position (const rpc_loc_parsed_position_s_type *location_report_ptr);
|
|
static void loc_eng_report_sv (const rpc_loc_gnss_info_s_type *gnss_report_ptr);
|
|
static void loc_eng_report_status (const rpc_loc_status_event_s_type *status_report_ptr);
|
|
static void loc_eng_report_nmea (const rpc_loc_nmea_report_s_type *nmea_report_ptr);
|
|
static void loc_eng_process_conn_request (const rpc_loc_server_request_s_type *server_request_ptr);
|
|
|
|
static void loc_eng_process_deferred_action (void* arg);
|
|
static void loc_eng_process_atl_deferred_action (int flags);
|
|
static void loc_eng_delete_aiding_data_deferred_action (void);
|
|
|
|
static int set_agps_server();
|
|
|
|
// Defines the GpsInterface in gps.h
|
|
static const GpsInterface sLocEngInterface =
|
|
{
|
|
sizeof(GpsInterface),
|
|
loc_eng_init,
|
|
loc_eng_start,
|
|
loc_eng_stop,
|
|
loc_eng_cleanup,
|
|
loc_eng_inject_time,
|
|
loc_eng_inject_location,
|
|
loc_eng_delete_aiding_data,
|
|
loc_eng_set_position_mode,
|
|
loc_eng_get_extension,
|
|
};
|
|
|
|
static const AGpsInterface sLocEngAGpsInterface =
|
|
{
|
|
sizeof(AGpsInterface),
|
|
loc_eng_agps_init,
|
|
loc_eng_agps_data_conn_open,
|
|
loc_eng_agps_data_conn_closed,
|
|
loc_eng_agps_data_conn_failed,
|
|
loc_eng_agps_set_server,
|
|
};
|
|
|
|
// Global data structure for location engine
|
|
loc_eng_data_s_type loc_eng_data;
|
|
|
|
/*===========================================================================
|
|
FUNCTION gps_get_hardware_interface
|
|
|
|
DESCRIPTION
|
|
Returns the GPS hardware interaface based on LOC API
|
|
if GPS is enabled.
|
|
|
|
DEPENDENCIES
|
|
None
|
|
|
|
RETURN VALUE
|
|
0: success
|
|
|
|
SIDE EFFECTS
|
|
N/A
|
|
|
|
===========================================================================*/
|
|
const GpsInterface* gps_get_hardware_interface ()
|
|
{
|
|
char propBuf[PROPERTY_VALUE_MAX];
|
|
|
|
// check to see if GPS should be disabled
|
|
property_get("gps.disable", propBuf, "");
|
|
if (propBuf[0] == '1')
|
|
{
|
|
LOGD("gps_get_interface returning NULL because gps.disable=1\n");
|
|
return NULL;
|
|
}
|
|
|
|
return &sLocEngInterface;
|
|
}
|
|
|
|
/*===========================================================================
|
|
FUNCTION loc_eng_init
|
|
|
|
DESCRIPTION
|
|
Initialize the location engine, this include setting up global datas
|
|
and registers location engien with loc api service.
|
|
|
|
DEPENDENCIES
|
|
None
|
|
|
|
RETURN VALUE
|
|
0: success
|
|
|
|
SIDE EFFECTS
|
|
N/A
|
|
|
|
===========================================================================*/
|
|
|
|
// fully shutting down the GPS is temporarily disabled to avoid intermittent BP crash
|
|
#define DISABLE_CLEANUP 1
|
|
|
|
static int loc_eng_init(GpsCallbacks* callbacks)
|
|
{
|
|
#if DISABLE_CLEANUP
|
|
if (loc_eng_data.deferred_action_thread) {
|
|
// already initialized
|
|
return 0;
|
|
}
|
|
#endif
|
|
// Start the LOC api RPC service
|
|
loc_api_glue_init ();
|
|
|
|
callbacks->set_capabilities_cb(GPS_CAPABILITY_SCHEDULING | GPS_CAPABILITY_MSA | GPS_CAPABILITY_MSB);
|
|
|
|
memset (&loc_eng_data, 0, sizeof (loc_eng_data_s_type));
|
|
|
|
// LOC ENG module data initialization
|
|
loc_eng_data.location_cb = callbacks->location_cb;
|
|
loc_eng_data.sv_status_cb = callbacks->sv_status_cb;
|
|
loc_eng_data.status_cb = callbacks->status_cb;
|
|
loc_eng_data.nmea_cb = callbacks->nmea_cb;
|
|
loc_eng_data.acquire_wakelock_cb = callbacks->acquire_wakelock_cb;
|
|
loc_eng_data.release_wakelock_cb = callbacks->release_wakelock_cb;
|
|
|
|
rpc_loc_event_mask_type event = RPC_LOC_EVENT_PARSED_POSITION_REPORT |
|
|
RPC_LOC_EVENT_SATELLITE_REPORT |
|
|
RPC_LOC_EVENT_LOCATION_SERVER_REQUEST |
|
|
RPC_LOC_EVENT_ASSISTANCE_DATA_REQUEST |
|
|
RPC_LOC_EVENT_IOCTL_REPORT |
|
|
RPC_LOC_EVENT_STATUS_REPORT |
|
|
RPC_LOC_EVENT_NMEA_POSITION_REPORT |
|
|
RPC_LOC_EVENT_NI_NOTIFY_VERIFY_REQUEST;
|
|
|
|
loc_eng_data.client_handle = loc_open (event, loc_event_cb);
|
|
|
|
pthread_mutex_init (&(loc_eng_data.deferred_action_mutex), NULL);
|
|
pthread_cond_init (&(loc_eng_data.deferred_action_cond) , NULL);
|
|
pthread_mutex_init (&(loc_eng_data.deferred_stop_mutex), NULL);
|
|
|
|
loc_eng_data.loc_event = 0;
|
|
loc_eng_data.deferred_action_flags = 0;
|
|
memset (loc_eng_data.apn_name, 0, sizeof (loc_eng_data.apn_name));
|
|
|
|
loc_eng_data.aiding_data_for_deletion = 0;
|
|
loc_eng_data.engine_status = GPS_STATUS_NONE;
|
|
|
|
// XTRA module data initialization
|
|
loc_eng_data.xtra_module_data.download_request_cb = NULL;
|
|
|
|
// IOCTL module data initialization
|
|
loc_eng_data.ioctl_data.cb_is_selected = FALSE;
|
|
loc_eng_data.ioctl_data.cb_is_waiting = FALSE;
|
|
loc_eng_data.ioctl_data.client_handle = RPC_LOC_CLIENT_HANDLE_INVALID;
|
|
memset (&(loc_eng_data.ioctl_data.cb_payload),
|
|
0,
|
|
sizeof (rpc_loc_ioctl_callback_s_type));
|
|
|
|
pthread_mutex_init (&(loc_eng_data.ioctl_data.cb_data_mutex), NULL);
|
|
pthread_cond_init(&loc_eng_data.ioctl_data.cb_arrived_cond, NULL);
|
|
|
|
loc_eng_data.deferred_action_thread = callbacks->create_thread_cb("loc_api",
|
|
loc_eng_process_deferred_action, NULL);
|
|
|
|
LOGD ("loc_eng_init called, client id = %d\n", (int32) loc_eng_data.client_handle);
|
|
return 0;
|
|
}
|
|
|
|
/*===========================================================================
|
|
FUNCTION loc_eng_cleanup
|
|
|
|
DESCRIPTION
|
|
Cleans location engine. The location client handle will be released.
|
|
|
|
DEPENDENCIES
|
|
None
|
|
|
|
RETURN VALUE
|
|
None
|
|
|
|
SIDE EFFECTS
|
|
N/A
|
|
|
|
===========================================================================*/
|
|
static void loc_eng_cleanup()
|
|
{
|
|
#if DISABLE_CLEANUP
|
|
return;
|
|
#else
|
|
if (loc_eng_data.deferred_action_thread)
|
|
{
|
|
/* Terminate deferred action working thread */
|
|
pthread_mutex_lock(&loc_eng_data.deferred_action_mutex);
|
|
/* hold a wake lock while events are pending for deferred_action_thread */
|
|
loc_eng_data.acquire_wakelock_cb();
|
|
loc_eng_data.deferred_action_flags |= DEFERRED_ACTION_QUIT;
|
|
pthread_cond_signal(&loc_eng_data.deferred_action_cond);
|
|
pthread_mutex_unlock(&loc_eng_data.deferred_action_mutex);
|
|
|
|
void* ignoredValue;
|
|
pthread_join(loc_eng_data.deferred_action_thread, &ignoredValue);
|
|
loc_eng_data.deferred_action_thread = NULL;
|
|
}
|
|
|
|
// clean up
|
|
(void) loc_close (loc_eng_data.client_handle);
|
|
|
|
pthread_mutex_destroy (&loc_eng_data.deferred_action_mutex);
|
|
pthread_cond_destroy (&loc_eng_data.deferred_action_cond);
|
|
|
|
pthread_mutex_destroy (&loc_eng_data.ioctl_data.cb_data_mutex);
|
|
pthread_cond_destroy (&loc_eng_data.ioctl_data.cb_arrived_cond);
|
|
|
|
// Do not call this as it can result in the ARM9 crashing if it sends events while we are disabled
|
|
// loc_apicb_app_deinit();
|
|
#endif
|
|
}
|
|
|
|
|
|
/*===========================================================================
|
|
FUNCTION loc_eng_start
|
|
|
|
DESCRIPTION
|
|
Starts the tracking session
|
|
|
|
DEPENDENCIES
|
|
None
|
|
|
|
RETURN VALUE
|
|
0: success
|
|
|
|
SIDE EFFECTS
|
|
N/A
|
|
|
|
===========================================================================*/
|
|
static int loc_eng_start()
|
|
{
|
|
int ret_val;
|
|
LOGD ("loc_eng_start\n");
|
|
|
|
if (loc_eng_data.position_mode != GPS_POSITION_MODE_STANDALONE &&
|
|
loc_eng_data.agps_server_host[0] != 0 &&
|
|
loc_eng_data.agps_server_port != 0) {
|
|
int result = set_agps_server();
|
|
LOGD ("set_agps_server returned = %d\n", result);
|
|
}
|
|
|
|
ret_val = loc_start_fix (loc_eng_data.client_handle);
|
|
|
|
if (ret_val != RPC_LOC_API_SUCCESS)
|
|
{
|
|
LOGD ("loc_eng_start returned error = %d\n", ret_val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*===========================================================================
|
|
FUNCTION loc_eng_stop
|
|
|
|
DESCRIPTION
|
|
Stops the tracking session
|
|
|
|
DEPENDENCIES
|
|
None
|
|
|
|
RETURN VALUE
|
|
0: success
|
|
|
|
SIDE EFFECTS
|
|
N/A
|
|
|
|
===========================================================================*/
|
|
static int loc_eng_stop()
|
|
{
|
|
int ret_val;
|
|
|
|
LOGD ("loc_eng_stop\n");
|
|
|
|
pthread_mutex_lock(&(loc_eng_data.deferred_stop_mutex));
|
|
// work around problem with loc_eng_stop when AGPS requests are pending
|
|
// we defer stopping the engine until the AGPS request is done
|
|
if (loc_eng_data.agps_request_pending)
|
|
{
|
|
loc_eng_data.stop_request_pending = true;
|
|
LOGD ("deferring stop until AGPS data call is finished\n");
|
|
pthread_mutex_unlock(&(loc_eng_data.deferred_stop_mutex));
|
|
return 0;
|
|
}
|
|
pthread_mutex_unlock(&(loc_eng_data.deferred_stop_mutex));
|
|
|
|
ret_val = loc_stop_fix (loc_eng_data.client_handle);
|
|
if (ret_val != RPC_LOC_API_SUCCESS)
|
|
{
|
|
LOGD ("loc_eng_stop returned error = %d\n", ret_val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int loc_eng_set_gps_lock(rpc_loc_lock_e_type lock_type)
|
|
{
|
|
rpc_loc_ioctl_data_u_type ioctl_data;
|
|
boolean ret_val;
|
|
|
|
LOGD ("loc_eng_set_gps_lock mode, client = %d, lock_type = %d\n",
|
|
(int32) loc_eng_data.client_handle, lock_type);
|
|
|
|
ioctl_data.rpc_loc_ioctl_data_u_type_u.engine_lock = lock_type;
|
|
ioctl_data.disc = RPC_LOC_IOCTL_SET_ENGINE_LOCK;
|
|
|
|
ret_val = loc_eng_ioctl (loc_eng_data.client_handle,
|
|
RPC_LOC_IOCTL_SET_ENGINE_LOCK,
|
|
&ioctl_data,
|
|
LOC_IOCTL_DEFAULT_TIMEOUT,
|
|
NULL /* No output information is expected*/);
|
|
|
|
if (ret_val != TRUE)
|
|
{
|
|
LOGD ("loc_eng_set_gps_lock mode failed\n");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*===========================================================================
|
|
FUNCTION loc_eng_set_position_mode
|
|
|
|
DESCRIPTION
|
|
Sets the mode and fix frequency for the tracking session.
|
|
|
|
DEPENDENCIES
|
|
None
|
|
|
|
RETURN VALUE
|
|
0: success
|
|
|
|
SIDE EFFECTS
|
|
N/A
|
|
|
|
===========================================================================*/
|
|
static int loc_eng_set_position_mode(GpsPositionMode mode, GpsPositionRecurrence recurrence,
|
|
uint32_t min_interval, uint32_t preferred_accuracy, uint32_t preferred_time)
|
|
{
|
|
rpc_loc_ioctl_data_u_type ioctl_data;
|
|
rpc_loc_fix_criteria_s_type *fix_criteria_ptr;
|
|
boolean ret_val;
|
|
|
|
LOGD ("loc_eng_set_position mode, client = %d, interval = %d, mode = %d\n",
|
|
(int32) loc_eng_data.client_handle, min_interval, mode);
|
|
|
|
loc_eng_data.position_mode = mode;
|
|
ioctl_data.disc = RPC_LOC_IOCTL_SET_FIX_CRITERIA;
|
|
|
|
fix_criteria_ptr = &(ioctl_data.rpc_loc_ioctl_data_u_type_u.fix_criteria);
|
|
fix_criteria_ptr->valid_mask = RPC_LOC_FIX_CRIT_VALID_PREFERRED_OPERATION_MODE |
|
|
RPC_LOC_FIX_CRIT_VALID_RECURRENCE_TYPE;
|
|
|
|
switch (mode) {
|
|
case GPS_POSITION_MODE_MS_BASED:
|
|
fix_criteria_ptr->preferred_operation_mode = RPC_LOC_OPER_MODE_MSB;
|
|
break;
|
|
case GPS_POSITION_MODE_MS_ASSISTED:
|
|
fix_criteria_ptr->preferred_operation_mode = RPC_LOC_OPER_MODE_MSA;
|
|
break;
|
|
case GPS_POSITION_MODE_STANDALONE:
|
|
default:
|
|
fix_criteria_ptr->preferred_operation_mode = RPC_LOC_OPER_MODE_STANDALONE;
|
|
break;
|
|
}
|
|
if (min_interval > 0) {
|
|
fix_criteria_ptr->min_interval = min_interval;
|
|
fix_criteria_ptr->valid_mask |= RPC_LOC_FIX_CRIT_VALID_MIN_INTERVAL;
|
|
}
|
|
if (preferred_accuracy > 0) {
|
|
fix_criteria_ptr->preferred_accuracy = preferred_accuracy;
|
|
fix_criteria_ptr->valid_mask |= RPC_LOC_FIX_CRIT_VALID_PREFERRED_ACCURACY;
|
|
}
|
|
if (preferred_time > 0) {
|
|
fix_criteria_ptr->preferred_response_time = preferred_time;
|
|
fix_criteria_ptr->valid_mask |= RPC_LOC_FIX_CRIT_VALID_PREFERRED_RESPONSE_TIME;
|
|
}
|
|
|
|
switch (recurrence) {
|
|
case GPS_POSITION_RECURRENCE_SINGLE:
|
|
fix_criteria_ptr->recurrence_type = RPC_LOC_SINGLE_FIX;
|
|
break;
|
|
case GPS_POSITION_RECURRENCE_PERIODIC:
|
|
default:
|
|
fix_criteria_ptr->recurrence_type = RPC_LOC_PERIODIC_FIX;
|
|
break;
|
|
}
|
|
|
|
ret_val = loc_eng_ioctl(loc_eng_data.client_handle,
|
|
RPC_LOC_IOCTL_SET_FIX_CRITERIA,
|
|
&ioctl_data,
|
|
LOC_IOCTL_DEFAULT_TIMEOUT,
|
|
NULL /* No output information is expected*/);
|
|
|
|
if (ret_val != TRUE)
|
|
{
|
|
LOGD ("loc_eng_set_position mode failed\n");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*===========================================================================
|
|
FUNCTION loc_eng_inject_time
|
|
|
|
DESCRIPTION
|
|
This is used by Java native function to do time injection.
|
|
|
|
DEPENDENCIES
|
|
None
|
|
|
|
RETURN VALUE
|
|
RPC_LOC_API_SUCCESS
|
|
|
|
SIDE EFFECTS
|
|
N/A
|
|
|
|
===========================================================================*/
|
|
static int loc_eng_inject_time (GpsUtcTime time, int64_t timeReference, int uncertainty)
|
|
{
|
|
rpc_loc_ioctl_data_u_type ioctl_data;
|
|
rpc_loc_assist_data_time_s_type *time_info_ptr;
|
|
boolean ret_val;
|
|
|
|
LOGD ("loc_eng_inject_time, uncertainty = %d\n", uncertainty);
|
|
|
|
ioctl_data.disc = RPC_LOC_IOCTL_INJECT_UTC_TIME;
|
|
|
|
time_info_ptr = &(ioctl_data.rpc_loc_ioctl_data_u_type_u.assistance_data_time);
|
|
time_info_ptr->time_utc = time;
|
|
time_info_ptr->time_utc += (int64_t)(android::elapsedRealtime() - timeReference);
|
|
time_info_ptr->uncertainty = uncertainty; // Uncertainty in ms
|
|
|
|
ret_val = loc_eng_ioctl (loc_eng_data.client_handle,
|
|
RPC_LOC_IOCTL_INJECT_UTC_TIME,
|
|
&ioctl_data,
|
|
LOC_IOCTL_DEFAULT_TIMEOUT,
|
|
NULL /* No output information is expected*/);
|
|
|
|
if (ret_val != TRUE)
|
|
{
|
|
LOGD ("loc_eng_inject_time failed\n");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int loc_eng_inject_location (double latitude, double longitude, float accuracy)
|
|
{
|
|
/* not yet implemented */
|
|
return 0;
|
|
}
|
|
|
|
/*===========================================================================
|
|
FUNCTION loc_eng_delete_aiding_data
|
|
|
|
DESCRIPTION
|
|
This is used by Java native function to delete the aiding data. The function
|
|
updates the global variable for the aiding data to be deleted. If the GPS
|
|
engine is off, the aiding data will be deleted. Otherwise, the actual action
|
|
will happen when gps engine is turned off.
|
|
|
|
DEPENDENCIES
|
|
Assumes the aiding data type specified in GpsAidingData matches with
|
|
LOC API specification.
|
|
|
|
RETURN VALUE
|
|
RPC_LOC_API_SUCCESS
|
|
|
|
SIDE EFFECTS
|
|
N/A
|
|
|
|
===========================================================================*/
|
|
static void loc_eng_delete_aiding_data (GpsAidingData f)
|
|
{
|
|
pthread_mutex_lock(&(loc_eng_data.deferred_action_mutex));
|
|
|
|
// Currently, LOC API only support deletion of all aiding data,
|
|
if (f)
|
|
loc_eng_data.aiding_data_for_deletion = GPS_DELETE_ALL;
|
|
|
|
if ((loc_eng_data.engine_status != GPS_STATUS_SESSION_BEGIN) &&
|
|
(loc_eng_data.aiding_data_for_deletion != 0))
|
|
{
|
|
/* hold a wake lock while events are pending for deferred_action_thread */
|
|
loc_eng_data.acquire_wakelock_cb();
|
|
loc_eng_data.deferred_action_flags |= DEFERRED_ACTION_DELETE_AIDING;
|
|
pthread_cond_signal(&(loc_eng_data.deferred_action_cond));
|
|
|
|
// In case gps engine is ON, the assistance data will be deleted when the engine is OFF
|
|
}
|
|
|
|
pthread_mutex_unlock(&(loc_eng_data.deferred_action_mutex));
|
|
}
|
|
|
|
/*===========================================================================
|
|
FUNCTION loc_eng_get_extension
|
|
|
|
DESCRIPTION
|
|
Get the gps extension to support XTRA.
|
|
|
|
DEPENDENCIES
|
|
N/A
|
|
|
|
RETURN VALUE
|
|
The GPS extension interface.
|
|
|
|
SIDE EFFECTS
|
|
N/A
|
|
|
|
===========================================================================*/
|
|
static const void* loc_eng_get_extension(const char* name)
|
|
{
|
|
if (strcmp(name, GPS_XTRA_INTERFACE) == 0)
|
|
{
|
|
return &sLocEngXTRAInterface;
|
|
}
|
|
else if (strcmp(name, AGPS_INTERFACE) == 0)
|
|
{
|
|
return &sLocEngAGpsInterface;
|
|
}
|
|
else if (strcmp(name, GPS_NI_INTERFACE) == 0)
|
|
{
|
|
return &sLocEngNiInterface;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#if DEBUG_MOCK_NI == 1
|
|
/*===========================================================================
|
|
FUNCTION mock_ni
|
|
|
|
DESCRIPTION
|
|
DEBUG tool: simulate an NI request
|
|
|
|
DEPENDENCIES
|
|
N/A
|
|
|
|
RETURN VALUE
|
|
None
|
|
|
|
SIDE EFFECTS
|
|
N/A
|
|
|
|
===========================================================================*/
|
|
static void* mock_ni(void* arg)
|
|
{
|
|
static int busy = 0;
|
|
|
|
if (busy) return NULL;
|
|
|
|
busy = 1;
|
|
|
|
sleep(5);
|
|
|
|
rpc_loc_client_handle_type client_handle;
|
|
rpc_loc_event_mask_type loc_event;
|
|
rpc_loc_event_payload_u_type payload;
|
|
rpc_loc_ni_event_s_type *ni_req;
|
|
rpc_loc_ni_supl_notify_verify_req_s_type *supl_req;
|
|
|
|
client_handle = (rpc_loc_client_handle_type) arg;
|
|
|
|
loc_event = RPC_LOC_EVENT_NI_NOTIFY_VERIFY_REQUEST;
|
|
payload.disc = loc_event;
|
|
|
|
ni_req = &payload.rpc_loc_event_payload_u_type_u.ni_request;
|
|
ni_req->event = RPC_LOC_NI_EVENT_SUPL_NOTIFY_VERIFY_REQ;
|
|
supl_req = &ni_req->payload.rpc_loc_ni_event_payload_u_type_u.supl_req;
|
|
|
|
// Encodings for Spirent Communications
|
|
char client_name[80] = {0x53,0x78,0x5A,0x5E,0x76,0xD3,0x41,0xC3,0x77,
|
|
0xBB,0x5D,0x77,0xA7,0xC7,0x61,0x7A,0xFA,0xED,0x9E,0x03};
|
|
char requestor_id[80] = {0x53,0x78,0x5A,0x5E,0x76,0xD3,0x41,0xC3,0x77,
|
|
0xBB,0x5D,0x77,0xA7,0xC7,0x61,0x7A,0xFA,0xED,0x9E,0x03};
|
|
|
|
supl_req->flags = RPC_LOC_NI_CLIENT_NAME_PRESENT |
|
|
RPC_LOC_NI_REQUESTOR_ID_PRESENT |
|
|
RPC_LOC_NI_ENCODING_TYPE_PRESENT;
|
|
|
|
supl_req->datacoding_scheme = RPC_LOC_NI_SUPL_GSM_DEFAULT;
|
|
|
|
supl_req->client_name.data_coding_scheme = RPC_LOC_NI_SUPL_GSM_DEFAULT; // no coding
|
|
supl_req->client_name.client_name_string.client_name_string_len = strlen(client_name);
|
|
supl_req->client_name.client_name_string.client_name_string_val = client_name;
|
|
supl_req->client_name.string_len = strlen(client_name);
|
|
|
|
supl_req->requestor_id.data_coding_scheme = RPC_LOC_NI_SUPL_GSM_DEFAULT;
|
|
supl_req->requestor_id.requestor_id_string.requestor_id_string_len = strlen(requestor_id);
|
|
supl_req->requestor_id.requestor_id_string.requestor_id_string_val = requestor_id;
|
|
supl_req->requestor_id.string_len = strlen(requestor_id);
|
|
|
|
supl_req->notification_priv_type = RPC_LOC_NI_USER_NOTIFY_VERIFY_ALLOW_NO_RESP;
|
|
supl_req->user_response_timer = 10;
|
|
|
|
loc_event_cb(client_handle, loc_event, &payload);
|
|
|
|
busy = 0;
|
|
|
|
return NULL;
|
|
}
|
|
#endif // DEBUG_MOCK_NI
|
|
|
|
/*===========================================================================
|
|
FUNCTION loc_event_cb
|
|
|
|
DESCRIPTION
|
|
This is the callback function registered by loc_open.
|
|
|
|
DEPENDENCIES
|
|
N/A
|
|
|
|
RETURN VALUE
|
|
RPC_LOC_API_SUCCESS
|
|
|
|
SIDE EFFECTS
|
|
N/A
|
|
|
|
===========================================================================*/
|
|
static int32 loc_event_cb(
|
|
rpc_loc_client_handle_type client_handle,
|
|
rpc_loc_event_mask_type loc_event,
|
|
const rpc_loc_event_payload_u_type* loc_event_payload
|
|
)
|
|
{
|
|
LOGV ("loc_event_cb, client = %d, loc_event = 0x%x", (int32) client_handle, (uint32) loc_event);
|
|
if (client_handle == loc_eng_data.client_handle)
|
|
{
|
|
pthread_mutex_lock(&loc_eng_data.deferred_action_mutex);
|
|
loc_eng_data.loc_event = loc_event;
|
|
memcpy(&loc_eng_data.loc_event_payload, loc_event_payload, sizeof(*loc_event_payload));
|
|
|
|
/* hold a wake lock while events are pending for deferred_action_thread */
|
|
loc_eng_data.acquire_wakelock_cb();
|
|
loc_eng_data.deferred_action_flags |= DEFERRED_ACTION_EVENT;
|
|
pthread_cond_signal(&loc_eng_data.deferred_action_cond);
|
|
pthread_mutex_unlock(&loc_eng_data.deferred_action_mutex);
|
|
}
|
|
else
|
|
{
|
|
LOGD ("loc client mismatch: received = %d, expected = %d \n", (int32) client_handle, (int32) loc_eng_data.client_handle);
|
|
}
|
|
|
|
return RPC_LOC_API_SUCCESS;
|
|
}
|
|
|
|
/*===========================================================================
|
|
FUNCTION loc_eng_report_position
|
|
|
|
DESCRIPTION
|
|
Reports position information to the Java layer.
|
|
|
|
DEPENDENCIES
|
|
N/A
|
|
|
|
RETURN VALUE
|
|
N/A
|
|
|
|
SIDE EFFECTS
|
|
N/A
|
|
|
|
===========================================================================*/
|
|
static void loc_eng_report_position (const rpc_loc_parsed_position_s_type *location_report_ptr)
|
|
{
|
|
GpsLocation location;
|
|
|
|
LOGV ("loc_eng_report_position: location report, valid mask = 0x%x, sess status = %d\n",
|
|
(uint32) location_report_ptr->valid_mask, location_report_ptr->session_status);
|
|
|
|
memset (&location, 0, sizeof(location));
|
|
location.size = sizeof(location);
|
|
if (location_report_ptr->valid_mask & RPC_LOC_POS_VALID_SESSION_STATUS)
|
|
{
|
|
// Not a position report, return
|
|
if (location_report_ptr->session_status == RPC_LOC_SESS_STATUS_SUCCESS)
|
|
{
|
|
if (location_report_ptr->valid_mask & RPC_LOC_POS_VALID_TIMESTAMP_UTC)
|
|
{
|
|
location.timestamp = location_report_ptr->timestamp_utc;
|
|
}
|
|
|
|
if ((location_report_ptr->valid_mask & RPC_LOC_POS_VALID_LATITUDE) &&
|
|
(location_report_ptr->valid_mask & RPC_LOC_POS_VALID_LONGITUDE))
|
|
{
|
|
location.flags |= GPS_LOCATION_HAS_LAT_LONG;
|
|
location.latitude = location_report_ptr->latitude;
|
|
location.longitude = location_report_ptr->longitude;
|
|
}
|
|
|
|
if (location_report_ptr->valid_mask & RPC_LOC_POS_VALID_ALTITUDE_WRT_ELLIPSOID )
|
|
{
|
|
location.flags |= GPS_LOCATION_HAS_ALTITUDE;
|
|
location.altitude = location_report_ptr->altitude_wrt_ellipsoid;
|
|
}
|
|
|
|
if ((location_report_ptr->valid_mask & RPC_LOC_POS_VALID_SPEED_HORIZONTAL) &&
|
|
(location_report_ptr->valid_mask & RPC_LOC_POS_VALID_SPEED_VERTICAL))
|
|
{
|
|
location.flags |= GPS_LOCATION_HAS_SPEED;
|
|
location.speed = sqrt(location_report_ptr->speed_horizontal * location_report_ptr->speed_horizontal +
|
|
location_report_ptr->speed_vertical * location_report_ptr->speed_vertical);
|
|
}
|
|
|
|
if (location_report_ptr->valid_mask & RPC_LOC_POS_VALID_HEADING)
|
|
{
|
|
location.flags |= GPS_LOCATION_HAS_BEARING;
|
|
location.bearing = location_report_ptr->heading;
|
|
}
|
|
|
|
if (location_report_ptr->valid_mask & RPC_LOC_POS_VALID_HOR_UNC_CIRCULAR)
|
|
{
|
|
location.flags |= GPS_LOCATION_HAS_ACCURACY;
|
|
location.accuracy = location_report_ptr->hor_unc_circular;
|
|
}
|
|
|
|
if (loc_eng_data.location_cb != NULL)
|
|
{
|
|
LOGV ("loc_eng_report_position: fire callback\n");
|
|
loc_eng_data.location_cb (&location);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOGV ("loc_eng_report_position: ignore position report when session status = %d\n", location_report_ptr->session_status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOGV ("loc_eng_report_position: ignore position report when session status is not set\n");
|
|
}
|
|
}
|
|
|
|
/*===========================================================================
|
|
FUNCTION loc_eng_report_sv
|
|
|
|
DESCRIPTION
|
|
Reports GPS satellite information to the Java layer.
|
|
|
|
DEPENDENCIES
|
|
N/A
|
|
|
|
RETURN VALUE
|
|
N/A
|
|
|
|
SIDE EFFECTS
|
|
N/A
|
|
|
|
===========================================================================*/
|
|
static void loc_eng_report_sv (const rpc_loc_gnss_info_s_type *gnss_report_ptr)
|
|
{
|
|
GpsSvStatus SvStatus;
|
|
int num_svs_max, i;
|
|
const rpc_loc_sv_info_s_type *sv_info_ptr;
|
|
|
|
LOGV ("loc_eng_report_sv: valid_mask = 0x%x, num of sv = %d\n",
|
|
(uint32) gnss_report_ptr->valid_mask,
|
|
gnss_report_ptr->sv_count);
|
|
|
|
num_svs_max = 0;
|
|
memset (&SvStatus, 0, sizeof (GpsSvStatus));
|
|
if (gnss_report_ptr->valid_mask & RPC_LOC_GNSS_INFO_VALID_SV_COUNT)
|
|
{
|
|
num_svs_max = gnss_report_ptr->sv_count;
|
|
if (num_svs_max > GPS_MAX_SVS)
|
|
{
|
|
num_svs_max = GPS_MAX_SVS;
|
|
}
|
|
}
|
|
|
|
if (gnss_report_ptr->valid_mask & RPC_LOC_GNSS_INFO_VALID_SV_LIST)
|
|
{
|
|
SvStatus.num_svs = 0;
|
|
|
|
for (i = 0; i < num_svs_max; i++)
|
|
{
|
|
sv_info_ptr = &(gnss_report_ptr->sv_list.sv_list_val[i]);
|
|
if (sv_info_ptr->valid_mask & RPC_LOC_SV_INFO_VALID_SYSTEM)
|
|
{
|
|
if (sv_info_ptr->system == RPC_LOC_SV_SYSTEM_GPS)
|
|
{
|
|
SvStatus.sv_list[SvStatus.num_svs].size = sizeof(GpsSvStatus);
|
|
SvStatus.sv_list[SvStatus.num_svs].prn = sv_info_ptr->prn;
|
|
|
|
// We only have the data field to report gps eph and alm mask
|
|
if ((sv_info_ptr->valid_mask & RPC_LOC_SV_INFO_VALID_HAS_EPH) &&
|
|
(sv_info_ptr->has_eph == 1))
|
|
{
|
|
SvStatus.ephemeris_mask |= (1 << (sv_info_ptr->prn-1));
|
|
}
|
|
|
|
if ((sv_info_ptr->valid_mask & RPC_LOC_SV_INFO_VALID_HAS_ALM) &&
|
|
(sv_info_ptr->has_alm == 1))
|
|
{
|
|
SvStatus.almanac_mask |= (1 << (sv_info_ptr->prn-1));
|
|
}
|
|
|
|
if ((sv_info_ptr->valid_mask & RPC_LOC_SV_INFO_VALID_PROCESS_STATUS) &&
|
|
(sv_info_ptr->process_status == RPC_LOC_SV_STATUS_TRACK))
|
|
{
|
|
SvStatus.used_in_fix_mask |= (1 << (sv_info_ptr->prn-1));
|
|
}
|
|
}
|
|
// SBAS: GPS RPN: 120-151,
|
|
// In exteneded measurement report, we follow nmea standard, which is from 33-64.
|
|
else if (sv_info_ptr->system == RPC_LOC_SV_SYSTEM_SBAS)
|
|
{
|
|
SvStatus.sv_list[SvStatus.num_svs].prn = sv_info_ptr->prn + 33 - 120;
|
|
}
|
|
// Gloness: Slot id: 1-32
|
|
// In extended measurement report, we follow nmea standard, which is 65-96
|
|
else if (sv_info_ptr->system == RPC_LOC_SV_SYSTEM_GLONASS)
|
|
{
|
|
SvStatus.sv_list[SvStatus.num_svs].prn = sv_info_ptr->prn + (65-1);
|
|
}
|
|
// Unsupported SV system
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (sv_info_ptr->valid_mask & RPC_LOC_SV_INFO_VALID_SNR)
|
|
{
|
|
SvStatus.sv_list[SvStatus.num_svs].snr = sv_info_ptr->snr;
|
|
}
|
|
|
|
if (sv_info_ptr->valid_mask & RPC_LOC_SV_INFO_VALID_ELEVATION)
|
|
{
|
|
SvStatus.sv_list[SvStatus.num_svs].elevation = sv_info_ptr->elevation;
|
|
}
|
|
|
|
if (sv_info_ptr->valid_mask & RPC_LOC_SV_INFO_VALID_AZIMUTH)
|
|
{
|
|
SvStatus.sv_list[SvStatus.num_svs].azimuth = sv_info_ptr->azimuth;
|
|
}
|
|
|
|
SvStatus.num_svs++;
|
|
}
|
|
}
|
|
|
|
LOGV ("num_svs = %d, eph mask = %d, alm mask = %d\n", SvStatus.num_svs, SvStatus.ephemeris_mask, SvStatus.almanac_mask );
|
|
if ((SvStatus.num_svs != 0) && (loc_eng_data.sv_status_cb != NULL))
|
|
{
|
|
loc_eng_data.sv_status_cb(&SvStatus);
|
|
}
|
|
}
|
|
|
|
/*===========================================================================
|
|
FUNCTION loc_eng_report_status
|
|
|
|
DESCRIPTION
|
|
Reports GPS engine state to Java layer.
|
|
|
|
DEPENDENCIES
|
|
N/A
|
|
|
|
RETURN VALUE
|
|
N/A
|
|
|
|
SIDE EFFECTS
|
|
N/A
|
|
|
|
===========================================================================*/
|
|
static void loc_eng_report_status (const rpc_loc_status_event_s_type *status_report_ptr)
|
|
{
|
|
GpsStatus status;
|
|
|
|
LOGV ("loc_eng_report_status: event = %d\n", status_report_ptr->event);
|
|
|
|
memset (&status, 0, sizeof(status));
|
|
status.size = sizeof(status);
|
|
status.status = GPS_STATUS_NONE;
|
|
if (status_report_ptr->event == RPC_LOC_STATUS_EVENT_ENGINE_STATE)
|
|
{
|
|
if (status_report_ptr->payload.rpc_loc_status_event_payload_u_type_u.engine_state == RPC_LOC_ENGINE_STATE_ON)
|
|
{
|
|
// GPS_STATUS_SESSION_BEGIN implies GPS_STATUS_ENGINE_ON
|
|
status.status = GPS_STATUS_SESSION_BEGIN;
|
|
loc_eng_data.status_cb(&status);
|
|
}
|
|
else if (status_report_ptr->payload.rpc_loc_status_event_payload_u_type_u.engine_state == RPC_LOC_ENGINE_STATE_OFF)
|
|
{
|
|
// GPS_STATUS_SESSION_END implies GPS_STATUS_ENGINE_OFF
|
|
status.status = GPS_STATUS_ENGINE_OFF;
|
|
loc_eng_data.status_cb(&status);
|
|
}
|
|
}
|
|
|
|
pthread_mutex_lock(&loc_eng_data.deferred_action_mutex);
|
|
loc_eng_data.engine_status = status.status;
|
|
|
|
// Wake up the thread for aiding data deletion.
|
|
if ((loc_eng_data.engine_status != GPS_STATUS_SESSION_BEGIN) &&
|
|
(loc_eng_data.aiding_data_for_deletion != 0))
|
|
{
|
|
/* hold a wake lock while events are pending for deferred_action_thread */
|
|
loc_eng_data.acquire_wakelock_cb();
|
|
loc_eng_data.deferred_action_flags |= DEFERRED_ACTION_DELETE_AIDING;
|
|
pthread_cond_signal(&(loc_eng_data.deferred_action_cond));
|
|
// In case gps engine is ON, the assistance data will be deleted when the engine is OFF
|
|
}
|
|
|
|
pthread_mutex_unlock(&loc_eng_data.deferred_action_mutex);
|
|
}
|
|
|
|
static void loc_eng_report_nmea (const rpc_loc_nmea_report_s_type *nmea_report_ptr)
|
|
{
|
|
if (loc_eng_data.nmea_cb != NULL)
|
|
{
|
|
struct timeval tv;
|
|
|
|
gettimeofday(&tv, (struct timezone *) NULL);
|
|
long long now = tv.tv_sec * 1000LL + tv.tv_usec / 1000;
|
|
|
|
#if (AMSS_VERSION==3200)
|
|
loc_eng_data.nmea_cb(now, nmea_report_ptr->nmea_sentences.nmea_sentences_val,
|
|
nmea_report_ptr->nmea_sentences.nmea_sentences_len);
|
|
#else
|
|
loc_eng_data.nmea_cb(now, nmea_report_ptr->nmea_sentences, nmea_report_ptr->length);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*===========================================================================
|
|
FUNCTION loc_eng_process_conn_request
|
|
|
|
DESCRIPTION
|
|
Requests data connection to be brought up/tore down with the location server.
|
|
|
|
DEPENDENCIES
|
|
N/A
|
|
|
|
RETURN VALUE
|
|
N/A
|
|
|
|
SIDE EFFECTS
|
|
N/A
|
|
|
|
===========================================================================*/
|
|
static void loc_eng_process_conn_request (const rpc_loc_server_request_s_type *server_request_ptr)
|
|
{
|
|
LOGD ("loc_event_cb: get loc event location server request, event = %d\n", server_request_ptr->event);
|
|
|
|
// Signal DeferredActionThread to send the APN name
|
|
pthread_mutex_lock(&loc_eng_data.deferred_action_mutex);
|
|
|
|
// This implemenation is based on the fact that modem now at any time has only one data connection for AGPS at any given time
|
|
if (server_request_ptr->event == RPC_LOC_SERVER_REQUEST_OPEN)
|
|
{
|
|
loc_eng_data.conn_handle = server_request_ptr->payload.rpc_loc_server_request_u_type_u.open_req.conn_handle;
|
|
loc_eng_data.agps_status = GPS_REQUEST_AGPS_DATA_CONN;
|
|
loc_eng_data.agps_request_pending = true;
|
|
}
|
|
else
|
|
{
|
|
loc_eng_data.conn_handle = server_request_ptr->payload.rpc_loc_server_request_u_type_u.close_req.conn_handle;
|
|
loc_eng_data.agps_status = GPS_RELEASE_AGPS_DATA_CONN;
|
|
loc_eng_data.agps_request_pending = false;
|
|
}
|
|
|
|
/* hold a wake lock while events are pending for deferred_action_thread */
|
|
loc_eng_data.acquire_wakelock_cb();
|
|
loc_eng_data.deferred_action_flags |= DEFERRED_ACTION_AGPS_STATUS;
|
|
pthread_cond_signal(&loc_eng_data.deferred_action_cond);
|
|
pthread_mutex_unlock(&loc_eng_data.deferred_action_mutex);
|
|
}
|
|
|
|
/*===========================================================================
|
|
FUNCTION loc_eng_agps_init
|
|
|
|
DESCRIPTION
|
|
|
|
|
|
DEPENDENCIES
|
|
NONE
|
|
|
|
RETURN VALUE
|
|
0
|
|
|
|
SIDE EFFECTS
|
|
N/A
|
|
|
|
===========================================================================*/
|
|
static void loc_eng_agps_init(AGpsCallbacks* callbacks)
|
|
{
|
|
LOGV("loc_eng_agps_init\n");
|
|
loc_eng_data.agps_status_cb = callbacks->status_cb;
|
|
}
|
|
|
|
static int loc_eng_agps_data_conn_open(const char* apn)
|
|
{
|
|
int apn_len;
|
|
LOGD("loc_eng_agps_data_conn_open: %s\n", apn);
|
|
|
|
pthread_mutex_lock(&(loc_eng_data.deferred_action_mutex));
|
|
|
|
if (apn != NULL)
|
|
{
|
|
apn_len = strlen (apn);
|
|
|
|
if (apn_len >= sizeof(loc_eng_data.apn_name))
|
|
{
|
|
LOGD ("loc_eng_set_apn: error, apn name exceeds maximum lenght of 100 chars\n");
|
|
apn_len = sizeof(loc_eng_data.apn_name) - 1;
|
|
}
|
|
|
|
memcpy (loc_eng_data.apn_name, apn, apn_len);
|
|
loc_eng_data.apn_name[apn_len] = '\0';
|
|
}
|
|
|
|
/* hold a wake lock while events are pending for deferred_action_thread */
|
|
loc_eng_data.acquire_wakelock_cb();
|
|
loc_eng_data.deferred_action_flags |= DEFERRED_ACTION_AGPS_DATA_SUCCESS;
|
|
pthread_cond_signal(&(loc_eng_data.deferred_action_cond));
|
|
pthread_mutex_unlock(&(loc_eng_data.deferred_action_mutex));
|
|
return 0;
|
|
}
|
|
|
|
static int loc_eng_agps_data_conn_closed()
|
|
{
|
|
LOGD("loc_eng_agps_data_conn_closed\n");
|
|
pthread_mutex_lock(&(loc_eng_data.deferred_action_mutex));
|
|
/* hold a wake lock while events are pending for deferred_action_thread */
|
|
loc_eng_data.acquire_wakelock_cb();
|
|
loc_eng_data.deferred_action_flags |= DEFERRED_ACTION_AGPS_DATA_CLOSED;
|
|
pthread_cond_signal(&(loc_eng_data.deferred_action_cond));
|
|
pthread_mutex_unlock(&(loc_eng_data.deferred_action_mutex));
|
|
return 0;
|
|
}
|
|
|
|
static int loc_eng_agps_data_conn_failed()
|
|
{
|
|
LOGD("loc_eng_agps_data_conn_failed\n");
|
|
|
|
pthread_mutex_lock(&(loc_eng_data.deferred_action_mutex));
|
|
/* hold a wake lock while events are pending for deferred_action_thread */
|
|
loc_eng_data.acquire_wakelock_cb();
|
|
loc_eng_data.deferred_action_flags |= DEFERRED_ACTION_AGPS_DATA_FAILED;
|
|
pthread_cond_signal(&(loc_eng_data.deferred_action_cond));
|
|
pthread_mutex_unlock(&(loc_eng_data.deferred_action_mutex));
|
|
return 0;
|
|
}
|
|
|
|
static int set_agps_server()
|
|
{
|
|
rpc_loc_ioctl_data_u_type ioctl_data;
|
|
rpc_loc_server_info_s_type *server_info_ptr;
|
|
boolean ret_val;
|
|
uint16 port_temp;
|
|
unsigned char *b_ptr;
|
|
|
|
if (loc_eng_data.agps_server_host[0] == 0 || loc_eng_data.agps_server_port == 0)
|
|
return -1;
|
|
|
|
if (loc_eng_data.agps_server_address == 0) {
|
|
struct hostent* he = gethostbyname(loc_eng_data.agps_server_host);
|
|
if (he)
|
|
loc_eng_data.agps_server_address = *(uint32_t *)he->h_addr_list[0];
|
|
}
|
|
if (loc_eng_data.agps_server_address == 0)
|
|
return -1;
|
|
|
|
b_ptr = (unsigned char*) (&loc_eng_data.agps_server_address);
|
|
|
|
|
|
server_info_ptr = &(ioctl_data.rpc_loc_ioctl_data_u_type_u.server_addr);
|
|
ioctl_data.disc = RPC_LOC_IOCTL_SET_UMTS_SLP_SERVER_ADDR;
|
|
server_info_ptr->addr_type = RPC_LOC_SERVER_ADDR_URL;
|
|
server_info_ptr->addr_info.disc = RPC_LOC_SERVER_ADDR_URL;
|
|
|
|
#if (AMSS_VERSION==3200)
|
|
char url[24];
|
|
memset(url, 0, sizeof(url));
|
|
snprintf(url, sizeof(url) - 1, "%d.%d.%d.%d:%d",
|
|
(*(b_ptr + 0) & 0x000000ff), (*(b_ptr+1) & 0x000000ff),
|
|
(*(b_ptr + 2) & 0x000000ff), (*(b_ptr+3) & 0x000000ff),
|
|
(loc_eng_data.agps_server_port & (0x0000ffff)));
|
|
|
|
server_info_ptr->addr_info.rpc_loc_server_addr_u_type_u.url.addr.addr_val = url;
|
|
server_info_ptr->addr_info.rpc_loc_server_addr_u_type_u.url.addr.addr_len = strlen(url);
|
|
LOGD ("set_agps_server, addr = %s\n", server_info_ptr->addr_info.rpc_loc_server_addr_u_type_u.url.addr.addr_val);
|
|
#else
|
|
char* buf = server_info_ptr->addr_info.rpc_loc_server_addr_u_type_u.url.addr;
|
|
int buf_len = sizeof(server_info_ptr->addr_info.rpc_loc_server_addr_u_type_u.url.addr);
|
|
memset(buf, 0, buf_len);
|
|
snprintf(buf, buf_len - 1, "%d.%d.%d.%d:%d",
|
|
(*(b_ptr + 0) & 0x000000ff), (*(b_ptr+1) & 0x000000ff),
|
|
(*(b_ptr + 2) & 0x000000ff), (*(b_ptr+3) & 0x000000ff),
|
|
(loc_eng_data.agps_server_port & (0x0000ffff)));
|
|
|
|
server_info_ptr->addr_info.rpc_loc_server_addr_u_type_u.url.length = buf_len;
|
|
LOGD ("set_agps_server, addr = %s\n", buf);
|
|
#endif
|
|
|
|
ret_val = loc_eng_ioctl (loc_eng_data.client_handle,
|
|
RPC_LOC_IOCTL_SET_UMTS_SLP_SERVER_ADDR,
|
|
&ioctl_data,
|
|
LOC_IOCTL_DEFAULT_TIMEOUT,
|
|
NULL /* No output information is expected*/);
|
|
|
|
if (ret_val != TRUE)
|
|
{
|
|
LOGD ("set_agps_server failed\n");
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
LOGV ("set_agps_server successful\n");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int loc_eng_agps_set_server(AGpsType type, const char* hostname, int port)
|
|
{
|
|
LOGD ("loc_eng_set_default_agps_server, type = %d, hostname = %s, port = %d\n", type, hostname, port);
|
|
|
|
if (type != AGPS_TYPE_SUPL)
|
|
return -1;
|
|
|
|
strncpy(loc_eng_data.agps_server_host, hostname, sizeof(loc_eng_data.agps_server_host) - 1);
|
|
loc_eng_data.agps_server_port = port;
|
|
return 0;
|
|
}
|
|
|
|
/*===========================================================================
|
|
FUNCTION loc_eng_delete_aiding_data_deferred_action
|
|
|
|
DESCRIPTION
|
|
This is used to remove the aiding data when GPS engine is off.
|
|
|
|
DEPENDENCIES
|
|
Assumes the aiding data type specified in GpsAidingData matches with
|
|
LOC API specification.
|
|
|
|
RETURN VALUE
|
|
RPC_LOC_API_SUCCESS
|
|
|
|
SIDE EFFECTS
|
|
N/A
|
|
|
|
===========================================================================*/
|
|
static void loc_eng_delete_aiding_data_deferred_action (void)
|
|
{
|
|
// Currently, we only support deletion of all aiding data,
|
|
// since the Android defined aiding data mask matches with modem,
|
|
// so just pass them down without any translation
|
|
rpc_loc_ioctl_data_u_type ioctl_data;
|
|
rpc_loc_assist_data_delete_s_type *assist_data_ptr;
|
|
boolean ret_val;
|
|
|
|
ioctl_data.disc = RPC_LOC_IOCTL_DELETE_ASSIST_DATA;
|
|
assist_data_ptr = &(ioctl_data.rpc_loc_ioctl_data_u_type_u.assist_data_delete);
|
|
assist_data_ptr->type = loc_eng_data.aiding_data_for_deletion;
|
|
loc_eng_data.aiding_data_for_deletion = 0;
|
|
|
|
memset (&(assist_data_ptr->reserved), 0, sizeof (assist_data_ptr->reserved));
|
|
|
|
ret_val = loc_eng_ioctl (loc_eng_data.client_handle,
|
|
RPC_LOC_IOCTL_DELETE_ASSIST_DATA ,
|
|
&ioctl_data,
|
|
LOC_IOCTL_DEFAULT_TIMEOUT,
|
|
NULL);
|
|
|
|
LOGD("loc_eng_ioctl for aiding data deletion returned %d, 1 for success\n", ret_val);
|
|
}
|
|
|
|
/*===========================================================================
|
|
FUNCTION loc_eng_process_atl_deferred_action
|
|
|
|
DESCRIPTION
|
|
This is used to inform the location engine of the processing status for
|
|
data connection open/close request.
|
|
|
|
DEPENDENCIES
|
|
None
|
|
|
|
RETURN VALUE
|
|
RPC_LOC_API_SUCCESS
|
|
|
|
SIDE EFFECTS
|
|
N/A
|
|
|
|
===========================================================================*/
|
|
static void loc_eng_process_atl_deferred_action (int flags)
|
|
{
|
|
rpc_loc_server_open_status_s_type *conn_open_status_ptr;
|
|
rpc_loc_server_close_status_s_type *conn_close_status_ptr;
|
|
rpc_loc_ioctl_data_u_type ioctl_data;
|
|
boolean ret_val;
|
|
int agps_status = -1;
|
|
|
|
LOGV("loc_eng_process_atl_deferred_action, agps_status = %d\n", loc_eng_data.agps_status);
|
|
|
|
memset (&ioctl_data, 0, sizeof (rpc_loc_ioctl_data_u_type));
|
|
|
|
if (flags & DEFERRED_ACTION_AGPS_DATA_CLOSED)
|
|
{
|
|
ioctl_data.disc = RPC_LOC_IOCTL_INFORM_SERVER_CLOSE_STATUS;
|
|
conn_close_status_ptr = &(ioctl_data.rpc_loc_ioctl_data_u_type_u.conn_close_status);
|
|
conn_close_status_ptr->conn_handle = loc_eng_data.conn_handle;
|
|
conn_close_status_ptr->close_status = RPC_LOC_SERVER_CLOSE_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
ioctl_data.disc = RPC_LOC_IOCTL_INFORM_SERVER_OPEN_STATUS;
|
|
conn_open_status_ptr = &ioctl_data.rpc_loc_ioctl_data_u_type_u.conn_open_status;
|
|
conn_open_status_ptr->conn_handle = loc_eng_data.conn_handle;
|
|
if (flags & DEFERRED_ACTION_AGPS_DATA_SUCCESS)
|
|
{
|
|
conn_open_status_ptr->open_status = RPC_LOC_SERVER_OPEN_SUCCESS;
|
|
// Both buffer are of the same maximum size, and the source is null terminated
|
|
// strcpy (&(ioctl_data.rpc_loc_ioctl_data_u_type_u.conn_open_status.apn_name), &(loc_eng_data.apn_name));
|
|
#if (AMSS_VERSION==3200)
|
|
conn_open_status_ptr->apn_name = loc_eng_data.apn_name;
|
|
#else
|
|
memset(conn_open_status_ptr->apn_name, 0, sizeof(conn_open_status_ptr->apn_name));
|
|
strncpy(conn_open_status_ptr->apn_name, loc_eng_data.apn_name,
|
|
sizeof(conn_open_status_ptr->apn_name) - 1);
|
|
#endif
|
|
// Delay this so that PDSM ATL module will behave properly
|
|
sleep (1);
|
|
LOGD("loc_eng_ioctl for ATL with apn_name = %s\n", conn_open_status_ptr->apn_name);
|
|
}
|
|
else // data_connection_failed
|
|
{
|
|
conn_open_status_ptr->open_status = RPC_LOC_SERVER_OPEN_FAIL;
|
|
}
|
|
// Delay this so that PDSM ATL module will behave properly
|
|
sleep (1);
|
|
}
|
|
|
|
ret_val = loc_eng_ioctl (loc_eng_data.client_handle,
|
|
ioctl_data.disc,
|
|
&ioctl_data,
|
|
LOC_IOCTL_DEFAULT_TIMEOUT,
|
|
NULL);
|
|
|
|
LOGD("loc_eng_ioctl for ATL returned %d (1 for success)\n", ret_val);
|
|
}
|
|
|
|
/*===========================================================================
|
|
FUNCTION loc_eng_process_loc_event
|
|
|
|
DESCRIPTION
|
|
This is used to process events received from the location engine.
|
|
|
|
DEPENDENCIES
|
|
None
|
|
|
|
RETURN VALUE
|
|
N/A
|
|
|
|
SIDE EFFECTS
|
|
N/A
|
|
|
|
===========================================================================*/
|
|
static void loc_eng_process_loc_event (rpc_loc_event_mask_type loc_event,
|
|
rpc_loc_event_payload_u_type* loc_event_payload)
|
|
{
|
|
if (loc_event & RPC_LOC_EVENT_PARSED_POSITION_REPORT)
|
|
{
|
|
loc_eng_report_position (&(loc_event_payload->rpc_loc_event_payload_u_type_u.parsed_location_report));
|
|
}
|
|
|
|
if (loc_event & RPC_LOC_EVENT_SATELLITE_REPORT)
|
|
{
|
|
loc_eng_report_sv (&(loc_event_payload->rpc_loc_event_payload_u_type_u.gnss_report));
|
|
}
|
|
|
|
if (loc_event & RPC_LOC_EVENT_STATUS_REPORT)
|
|
{
|
|
loc_eng_report_status (&(loc_event_payload->rpc_loc_event_payload_u_type_u.status_report));
|
|
}
|
|
|
|
if (loc_event & RPC_LOC_EVENT_NMEA_POSITION_REPORT)
|
|
{
|
|
loc_eng_report_nmea (&(loc_event_payload->rpc_loc_event_payload_u_type_u.nmea_report));
|
|
}
|
|
|
|
// Android XTRA interface supports only XTRA download
|
|
if (loc_event & RPC_LOC_EVENT_ASSISTANCE_DATA_REQUEST)
|
|
{
|
|
if (loc_event_payload->rpc_loc_event_payload_u_type_u.assist_data_request.event ==
|
|
RPC_LOC_ASSIST_DATA_PREDICTED_ORBITS_REQ)
|
|
{
|
|
LOGD ("loc_event_cb: xtra download requst");
|
|
|
|
// Call Registered callback
|
|
if (loc_eng_data.xtra_module_data.download_request_cb != NULL)
|
|
{
|
|
loc_eng_data.xtra_module_data.download_request_cb ();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (loc_event & RPC_LOC_EVENT_IOCTL_REPORT)
|
|
{
|
|
// Process the received RPC_LOC_EVENT_IOCTL_REPORT
|
|
(void) loc_eng_ioctl_process_cb (loc_eng_data.client_handle,
|
|
&(loc_event_payload->rpc_loc_event_payload_u_type_u.ioctl_report));
|
|
}
|
|
|
|
if (loc_event & RPC_LOC_EVENT_LOCATION_SERVER_REQUEST)
|
|
{
|
|
loc_eng_process_conn_request (&(loc_event_payload->rpc_loc_event_payload_u_type_u.loc_server_request));
|
|
}
|
|
|
|
loc_eng_ni_callback(loc_event, loc_event_payload);
|
|
|
|
#if DEBUG_MOCK_NI == 1
|
|
// DEBUG only
|
|
if ((loc_event & RPC_LOC_EVENT_STATUS_REPORT) &&
|
|
loc_event_payload->rpc_loc_event_payload_u_type_u.status_report.
|
|
payload.rpc_loc_status_event_payload_u_type_u.engine_state
|
|
== RPC_LOC_ENGINE_STATE_OFF)
|
|
{
|
|
// Mock an NI request
|
|
pthread_t th;
|
|
pthread_create (&th, NULL, mock_ni, (void*) client_handle);
|
|
}
|
|
#endif /* DEBUG_MOCK_NI == 1 */
|
|
}
|
|
|
|
/*===========================================================================
|
|
FUNCTION loc_eng_process_deferred_action
|
|
|
|
DESCRIPTION
|
|
Main routine for the thread to execute certain commands
|
|
that are not safe to be done from within an RPC callback.
|
|
|
|
DEPENDENCIES
|
|
None
|
|
|
|
RETURN VALUE
|
|
None
|
|
|
|
SIDE EFFECTS
|
|
N/A
|
|
|
|
===========================================================================*/
|
|
static void loc_eng_process_deferred_action (void* arg)
|
|
{
|
|
AGpsStatus status;
|
|
status.size = sizeof(status);
|
|
status.type = AGPS_TYPE_SUPL;
|
|
|
|
LOGD("loc_eng_process_deferred_action started\n");
|
|
|
|
// make sure we do not run in background scheduling group
|
|
set_sched_policy(gettid(), SP_FOREGROUND);
|
|
|
|
// disable the GPS lock
|
|
LOGD("Setting GPS privacy lock to RPC_LOC_LOCK_NONE\n");
|
|
loc_eng_set_gps_lock(RPC_LOC_LOCK_NONE);
|
|
|
|
while (1)
|
|
{
|
|
GpsAidingData aiding_data_for_deletion;
|
|
GpsStatusValue engine_status;
|
|
|
|
rpc_loc_event_mask_type loc_event;
|
|
rpc_loc_event_payload_u_type loc_event_payload;
|
|
|
|
// Wait until we are signalled to do a deferred action, or exit
|
|
pthread_mutex_lock(&loc_eng_data.deferred_action_mutex);
|
|
|
|
// If we have an event we should process it immediately,
|
|
// otherwise wait until we are signalled
|
|
if (loc_eng_data.deferred_action_flags == 0) {
|
|
// do not hold a wake lock while waiting for an event...
|
|
loc_eng_data.release_wakelock_cb();
|
|
pthread_cond_wait(&loc_eng_data.deferred_action_cond,
|
|
&loc_eng_data.deferred_action_mutex);
|
|
// but after we are signalled reacquire the wake lock
|
|
// until we are done processing the event.
|
|
loc_eng_data.acquire_wakelock_cb();
|
|
}
|
|
|
|
if (loc_eng_data.deferred_action_flags & DEFERRED_ACTION_QUIT)
|
|
{
|
|
pthread_mutex_unlock(&loc_eng_data.deferred_action_mutex);
|
|
break;
|
|
}
|
|
|
|
// copy anything we need before releasing the mutex
|
|
loc_event = loc_eng_data.loc_event;
|
|
if (loc_event != 0) {
|
|
memcpy(&loc_event_payload, &loc_eng_data.loc_event_payload, sizeof(loc_event_payload));
|
|
loc_eng_data.loc_event = 0;
|
|
}
|
|
|
|
int flags = loc_eng_data.deferred_action_flags;
|
|
loc_eng_data.deferred_action_flags = 0;
|
|
engine_status = loc_eng_data.agps_status;
|
|
aiding_data_for_deletion = loc_eng_data.aiding_data_for_deletion;
|
|
status.status = loc_eng_data.agps_status;
|
|
loc_eng_data.agps_status = 0;
|
|
|
|
// perform all actions after releasing the mutex to avoid blocking RPCs from the ARM9
|
|
pthread_mutex_unlock(&(loc_eng_data.deferred_action_mutex));
|
|
|
|
if (loc_event != 0) {
|
|
loc_eng_process_loc_event(loc_event, &loc_event_payload);
|
|
}
|
|
|
|
// send_delete_aiding_data must be done when GPS engine is off
|
|
if ((engine_status != GPS_STATUS_SESSION_BEGIN) && (aiding_data_for_deletion != 0))
|
|
{
|
|
loc_eng_delete_aiding_data_deferred_action ();
|
|
}
|
|
|
|
if (flags & (DEFERRED_ACTION_AGPS_DATA_SUCCESS |
|
|
DEFERRED_ACTION_AGPS_DATA_CLOSED |
|
|
DEFERRED_ACTION_AGPS_DATA_FAILED))
|
|
{
|
|
loc_eng_process_atl_deferred_action(flags);
|
|
|
|
pthread_mutex_lock(&(loc_eng_data.deferred_stop_mutex));
|
|
// work around problem with loc_eng_stop when AGPS requests are pending
|
|
// we defer stopping the engine until the AGPS request is done
|
|
loc_eng_data.agps_request_pending = false;
|
|
if (loc_eng_data.stop_request_pending)
|
|
{
|
|
LOGD ("handling deferred stop\n");
|
|
if (loc_stop_fix(loc_eng_data.client_handle) != RPC_LOC_API_SUCCESS)
|
|
{
|
|
LOGD ("loc_stop_fix failed!\n");
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&(loc_eng_data.deferred_stop_mutex));
|
|
}
|
|
|
|
if (status.status != 0 && loc_eng_data.agps_status_cb) {
|
|
loc_eng_data.agps_status_cb(&status);
|
|
}
|
|
}
|
|
|
|
// reenable the GPS lock
|
|
LOGD("Setting GPS privacy lock to RPC_LOC_LOCK_ALL\n");
|
|
loc_eng_set_gps_lock(RPC_LOC_LOCK_ALL);
|
|
|
|
LOGD("loc_eng_process_deferred_action thread exiting\n");
|
|
loc_eng_data.release_wakelock_cb();
|
|
|
|
loc_eng_data.deferred_action_thread = 0;
|
|
}
|
|
|
|
// for gps.c
|
|
extern "C" const GpsInterface* get_gps_interface()
|
|
{
|
|
return &sLocEngInterface;
|
|
}
|