added libgps (credit to tytung) and libhtc_ril_wrapper (credit to cedesmith)

This commit is contained in:
root 2011-06-15 00:08:00 +01:00
parent 9c8f0dd4b3
commit 095a0d6458
10 changed files with 3175 additions and 2 deletions

View File

@ -16,6 +16,8 @@ LOCAL_PATH := $(my-dir)
subdir_makefiles := \
$(LOCAL_PATH)/libreference-ril/Android.mk \
$(LOCAL_PATH)/libsensors/Android.mk \
$(LOCAL_PATH)/liblights/Android.mk
$(LOCAL_PATH)/liblights/Android.mk \
$(LOCAL_PATH)/libgps/Android.mk \
$(LOCAL_PATH)/libhtc_ril_wrapper/Android.mk
include $(subdir_makefiles)

4
leo.mk
View File

@ -101,7 +101,9 @@ PRODUCT_PACKAGES += \
gralloc.qsd8k \
copybit.qsd8k \
leo-reference-ril \
gps.leo
gps.leo \
libgps.o \
libhtc_ril_wrapper.so

18
libgps/Android.mk Normal file
View File

@ -0,0 +1,18 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := libgps
LOCAL_SHARED_LIBRARIES := libutils libcutils librpc
LOCAL_C_INCLUDES := \
$(TARGET_OUT_HEADERS)/librpc
LOCAL_SRC_FILES := \
leo-gps.c \
leo-gps-rpc.c \
time.cpp \
include $(BUILD_SHARED_LIBRARY)

358
libgps/gps.h Normal file
View File

@ -0,0 +1,358 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _HARDWARE_GPS_H
#define _HARDWARE_GPS_H
#include <stdint.h>
#include <stdlib.h>
#if __cplusplus
extern "C" {
#endif
/** Milliseconds since January 1, 1970 */
typedef int64_t GpsUtcTime;
/** Maximum number of SVs for gps_sv_status_callback(). */
#define GPS_MAX_SVS 32
/** Requested mode for GPS operation. */
typedef uint16_t GpsPositionMode;
// IMPORTANT: Note that the following values must match
// constants in GpsLocationProvider.java.
/** Mode for running GPS standalone (no assistance). */
#define GPS_POSITION_MODE_STANDALONE 0
/** AGPS MS-Based mode. */
#define GPS_POSITION_MODE_MS_BASED 1
/** AGPS MS-Assisted mode. */
#define GPS_POSITION_MODE_MS_ASSISTED 2
/** GPS status event values. */
typedef uint16_t GpsStatusValue;
// IMPORTANT: Note that the following values must match
// constants in GpsLocationProvider.java.
/** GPS status unknown. */
#define GPS_STATUS_NONE 0
/** GPS has begun navigating. */
#define GPS_STATUS_SESSION_BEGIN 1
/** GPS has stopped navigating. */
#define GPS_STATUS_SESSION_END 2
/** GPS has powered on but is not navigating. */
#define GPS_STATUS_ENGINE_ON 3
/** GPS is powered off. */
#define GPS_STATUS_ENGINE_OFF 4
/** Flags to indicate which values are valid in a GpsLocation. */
typedef uint16_t GpsLocationFlags;
// IMPORTANT: Note that the following values must match
// constants in GpsLocationProvider.java.
/** GpsLocation has valid latitude and longitude. */
#define GPS_LOCATION_HAS_LAT_LONG 0x0001
/** GpsLocation has valid altitude. */
#define GPS_LOCATION_HAS_ALTITUDE 0x0002
/** GpsLocation has valid speed. */
#define GPS_LOCATION_HAS_SPEED 0x0004
/** GpsLocation has valid bearing. */
#define GPS_LOCATION_HAS_BEARING 0x0008
/** GpsLocation has valid accuracy. */
#define GPS_LOCATION_HAS_ACCURACY 0x0010
/** Flags used to specify which aiding data to delete
when calling delete_aiding_data(). */
typedef uint16_t GpsAidingData;
// IMPORTANT: Note that the following values must match
// constants in GpsLocationProvider.java.
#define GPS_DELETE_EPHEMERIS 0x0001
#define GPS_DELETE_ALMANAC 0x0002
#define GPS_DELETE_POSITION 0x0004
#define GPS_DELETE_TIME 0x0008
#define GPS_DELETE_IONO 0x0010
#define GPS_DELETE_UTC 0x0020
#define GPS_DELETE_HEALTH 0x0040
#define GPS_DELETE_SVDIR 0x0080
#define GPS_DELETE_SVSTEER 0x0100
#define GPS_DELETE_SADATA 0x0200
#define GPS_DELETE_RTI 0x0400
#define GPS_DELETE_CELLDB_INFO 0x8000
#define GPS_DELETE_ALL 0xFFFF
/** AGPS type */
typedef uint16_t AGpsType;
#define AGPS_TYPE_SUPL 1
#define AGPS_TYPE_C2K 2
/** AGPS status event values. */
typedef uint16_t AGpsStatusValue;
/** GPS requests data connection for AGPS. */
#define GPS_REQUEST_AGPS_DATA_CONN 1
/** GPS releases the AGPS data connection. */
#define GPS_RELEASE_AGPS_DATA_CONN 2
/** AGPS data connection initiated */
#define GPS_AGPS_DATA_CONNECTED 3
/** AGPS data connection completed */
#define GPS_AGPS_DATA_CONN_DONE 4
/** AGPS data connection failed */
#define GPS_AGPS_DATA_CONN_FAILED 5
/**
* Name for the GPS XTRA interface.
*/
#define GPS_XTRA_INTERFACE "gps-xtra"
/**
* Name for the GPS DEBUG interface.
*/
#define GPS_DEBUG_INTERFACE "gps-debug"
/**
* Name for the AGPS interface.
*/
#define AGPS_INTERFACE "agps"
/**
* Name for the GPS privacy interface.
*/
#define GPS_PRIVACY_INTERFACE "privacy"
/** Represents a location. */
typedef struct {
/** Contains GpsLocationFlags bits. */
uint16_t flags;
/** Represents latitude in degrees. */
double latitude;
/** Represents longitude in degrees. */
double longitude;
/** Represents altitude in meters above the WGS 84 reference
* ellipsoid. */
double altitude;
/** Represents speed in meters per second. */
float speed;
/** Represents heading in degrees. */
float bearing;
/** Represents expected accuracy in meters. */
float accuracy;
/** Timestamp for the location fix. */
GpsUtcTime timestamp;
} GpsLocation;
/** Represents the status. */
typedef struct {
GpsStatusValue status;
} GpsStatus;
/** Represents SV information. */
typedef struct {
/** Pseudo-random number for the SV. */
int prn;
/** Signal to noise ratio. */
float snr;
/** Elevation of SV in degrees. */
float elevation;
/** Azimuth of SV in degrees. */
float azimuth;
} GpsSvInfo;
/** Represents SV status. */
typedef struct {
/** Number of SVs currently visible. */
int num_svs;
/** Contains an array of SV information. */
GpsSvInfo sv_list[GPS_MAX_SVS];
/** Represents a bit mask indicating which SVs
* have ephemeris data.
*/
uint32_t ephemeris_mask;
/** Represents a bit mask indicating which SVs
* have almanac data.
*/
uint32_t almanac_mask;
/**
* Represents a bit mask indicating which SVs
* were used for computing the most recent position fix.
*/
uint32_t used_in_fix_mask;
} GpsSvStatus;
/** Callback with location information. */
typedef void (* gps_location_callback)(GpsLocation* location);
/** Callback with status information. */
typedef void (* gps_status_callback)(GpsStatus* status);
/** Callback with SV status information. */
typedef void (* gps_sv_status_callback)(GpsSvStatus* sv_info);
/** Callback for reporting NMEA sentences. */
typedef void (* gps_nmea_callback)(GpsUtcTime timestamp, const char* nmea, int length);
/** GPS callback structure. */
typedef struct {
gps_location_callback location_cb;
gps_status_callback status_cb;
gps_sv_status_callback sv_status_cb;
gps_nmea_callback nmea_cb;
} GpsCallbacks;
/** Represents the standard GPS interface. */
typedef struct {
/**
* Opens the interface and provides the callback routines
* to the implemenation of this interface.
*/
int (*init)( GpsCallbacks* callbacks );
/** Starts navigating. */
int (*start)( void );
/** Stops navigating. */
int (*stop)( void );
/** Closes the interface. */
void (*cleanup)( void );
/** Injects the current time. */
int (*inject_time)(GpsUtcTime time, int64_t timeReference,
int uncertainty);
/** Injects current location from another location provider
* (typically cell ID).
* latitude and longitude are measured in degrees
* expected accuracy is measured in meters
*/
int (*inject_location)(double latitude, double longitude, float accuracy);
/**
* Specifies that the next call to start will not use the
* information defined in the flags. GPS_DELETE_ALL is passed for
* a cold start.
*/
void (*delete_aiding_data)(GpsAidingData flags);
/**
* fix_frequency represents the time between fixes in seconds.
* Set fix_frequency to zero for a single-shot fix.
*/
int (*set_position_mode)(GpsPositionMode mode, int fix_frequency);
/** Get a pointer to extension information. */
const void* (*get_extension)(const char* name);
} GpsInterface;
/** Callback to request the client to download XTRA data.
The client should download XTRA data and inject it by calling
inject_xtra_data(). */
typedef void (* gps_xtra_download_request)();
/** Callback structure for the XTRA interface. */
typedef struct {
gps_xtra_download_request download_request_cb;
} GpsXtraCallbacks;
/** Extended interface for XTRA support. */
typedef struct {
/**
* Opens the XTRA interface and provides the callback routines
* to the implemenation of this interface.
*/
int (*init)( GpsXtraCallbacks* callbacks );
/** Injects XTRA data into the GPS. */
int (*inject_xtra_data)( char* data, int length );
} GpsXtraInterface;
/** Extended interface for DEBUG support. */
typedef struct {
/**
* This function should return any information that the native
* implementation wishes to include in a bugreport.
*/
size_t (*get_internal_state)(char* buffer, size_t bufferSize);
} GpsDebugInterface;
/** Represents the status of AGPS. */
typedef struct {
AGpsType type;
AGpsStatusValue status;
} AGpsStatus;
/** Callback with AGPS status information. */
typedef void (* agps_status_callback)(AGpsStatus* status);
/** Callback structure for the AGPS interface. */
typedef struct {
agps_status_callback status_cb;
} AGpsCallbacks;
/** Extended interface for AGPS support. */
typedef struct {
/**
* Opens the AGPS interface and provides the callback routines
* to the implemenation of this interface.
*/
void (*init)( AGpsCallbacks* callbacks );
/**
* Notifies that a data connection is available and sets
* the name of the APN to be used for SUPL.
*/
int (*data_conn_open)( const char* apn );
/**
* Notifies that the AGPS data connection has been closed.
*/
int (*data_conn_closed)();
/**
* Notifies that a data connection is not available for AGPS.
*/
int (*data_conn_failed)();
/**
* Sets the hostname and port for the AGPS server.
*/
int (*set_server)( AGpsType type, const char* hostname, int port );
} AGpsInterface;
/** Extended interface for GPS privacy support. */
typedef struct {
/**
* Opens the AGPS interface and provides the callback routines
* to the implemenation of this interface.
*/
void (*set_privacy_lock)( int enable_lock );
} GpsPrivacyInterface;
/** Returns the hardware GPS interface. */
const GpsInterface* gps_get_hardware_interface();
/**
* Returns the qemu emulated GPS interface.
*/
const GpsInterface* gps_get_qemu_interface();
/**
* Returns the default GPS interface.
*/
const GpsInterface* gps_get_interface();
#if __cplusplus
} // extern "C"
#endif
#endif // _HARDWARE_GPS_H

772
libgps/leo-gps-rpc.c Normal file
View File

@ -0,0 +1,772 @@
/******************************************************************************
* RPC Client of GPS HAL (hardware abstraction layer) for HD2/Leo
*
* leo-gps-rpc.c
*
* Copyright (C) 2009-2010 The XDAndroid Project
* Copyright (C) 2010 dan1j3l @ xda-developers
* Copyright (C) 2011 tytung @ xda-developers
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <librpc/rpc/rpc.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <librpc/rpc/rpc_router_ioctl.h>
#include <pthread.h>
#include <cutils/log.h>
#include <gps.h>
#define LOG_TAG "gps_leo_rpc"
#define GPS_DEBUG 0
#if GPS_DEBUG
# define D(...) LOGD(__VA_ARGS__)
#else
# define D(...) ((void)0)
#endif
#define RPC_DEBUG 0
#if RPC_DEBUG
# define DD(...) LOGD(__VA_ARGS__)
#else
# define DD(...) ((void)0)
#endif
typedef struct registered_server_struct {
/* MUST BE AT OFFSET ZERO! The client code assumes this when it overwrites
* the XDR for server entries which represent a callback client. Those
* server entries do not have their own XDRs.
*/
XDR *xdr;
/* Because the xdr is NULL for callback clients (as opposed to true
* servers), we keep track of the program number and version number in this
* structure as well.
*/
rpcprog_t x_prog; /* program number */
rpcvers_t x_vers; /* program version */
int active;
struct registered_server_struct *next;
SVCXPRT *xprt;
__dispatch_fn_t dispatch;
} registered_server;
struct SVCXPRT {
fd_set fdset;
int max_fd;
pthread_attr_t thread_attr;
pthread_t svc_thread;
pthread_mutexattr_t lock_attr;
pthread_mutex_t lock;
registered_server *servers;
volatile int num_servers;
};
#define SEND_VAL(x) do { \
val=x;\
XDR_SEND_UINT32(clnt, &val);\
} while(0);
static uint32_t client_IDs[16];//highest known value is 0xb
static uint32_t can_send=1; //To prevent from sending get_position when EVENT_END hasn't been received
static uint32_t has_fix=0;
static struct CLIENT *_clnt;
static struct timeval timeout;
struct params {
uint32_t *data;
int length;
};
typedef struct pdsm_xtra_time_info {
uint32_t uncertainty;
uint64_t time_utc;
bool_t ref_to_utc_time;
bool_t force_flag;
} pdsm_xtra_time_info_type;
struct xtra_time_params {
uint32_t *data;
pdsm_xtra_time_info_type *time_info_ptr;
};
struct xtra_data_params {
uint32_t *data;
unsigned char *xtra_data_ptr;
uint32_t part_len;
uint8_t part;
uint8_t total_parts;
};
static bool_t xdr_args(XDR *clnt, struct params *par) {
int i;
uint32_t val=0;
for(i=0;par->length>i;++i)
SEND_VAL(par->data[i]);
return 1;
}
static bool_t xdr_result_int(XDR *clnt, uint32_t *result) {
XDR_RECV_UINT32(clnt, result);
return 1;
}
static bool_t xdr_xtra_data_args(XDR *xdrs, struct xtra_data_params *xtra_data) {
DD("%s() is called: 0x%x, %d, %d, %d", __FUNCTION__, (int) xtra_data->xtra_data_ptr, xtra_data->part_len, xtra_data->part, xtra_data->total_parts);
if (!xdr_u_long(xdrs, &xtra_data->data[0]))
return 0;
if (!xdr_int(xdrs, &xtra_data->data[1]))
return 0;
if (!xdr_u_long(xdrs, &xtra_data->data[2]))
return 0;
if (!xdr_u_long(xdrs, &xtra_data->part_len))
return 0;
if (!xdr_bytes(xdrs, (char **)&xtra_data->xtra_data_ptr, (u_int *)&xtra_data->part_len, ~0))
return 0;
if (!xdr_u_char(xdrs, &xtra_data->part))
return 0;
if (!xdr_u_char(xdrs, &xtra_data->total_parts))
return 0;
if (!xdr_u_long(xdrs, &xtra_data->data[3]))
return 0;
return 1;
}
bool_t xdr_pdsm_xtra_time_info(XDR *xdrs, pdsm_xtra_time_info_type *time_info_ptr) {
DD("%s() is called: %lld, %d", __FUNCTION__, time_info_ptr->time_utc, time_info_ptr->uncertainty);
if (!xdr_u_quad_t(xdrs, &time_info_ptr->time_utc))
return 0;
if (!xdr_u_long(xdrs, &time_info_ptr->uncertainty))
return 0;
if (!xdr_u_char(xdrs, &time_info_ptr->ref_to_utc_time))
return 0;
if (!xdr_u_char(xdrs, &time_info_ptr->force_flag))
return 0;
return 1;
}
static bool_t xdr_xtra_time_args(XDR *xdrs, struct xtra_time_params *xtra_time) {
DD("%s() is called", __FUNCTION__);
if (!xdr_u_long(xdrs, &xtra_time->data[0]))
return 0;
if (!xdr_int(xdrs, &xtra_time->data[1]))
return 0;
if (!xdr_u_long(xdrs, &xtra_time->data[2]))
return 0;
if (!xdr_pointer(xdrs, (char **)&xtra_time->time_info_ptr, sizeof(pdsm_xtra_time_info_type), (xdrproc_t) xdr_pdsm_xtra_time_info))
return 0;
return 1;
}
static int pdsm_client_init(struct CLIENT *clnt, int client) {
struct params par;
uint32_t res;
par.data=malloc(sizeof(int));
par.length=1;
par.data[0]=client;
if(clnt_call(clnt, 0x2, xdr_args, &par, xdr_result_int, &res, timeout)) {
D("pdsm_client_init(%x) failed\n", client);
free(par.data);
exit(-1);
}
D("pdsm_client_init(%x)=%x\n", client, res);
free(par.data);
client_IDs[client]=res;
return 0;
}
int pdsm_atl_l2_proxy_reg(struct CLIENT *clnt, int val0, int val1, int val2) {
struct params par;
uint32_t res;
par.data=malloc(sizeof(int)*3);
par.length=3;
par.data[0]=val0;
par.data[1]=val1;
par.data[2]=val2;
if(clnt_call(clnt, 0x3, xdr_args, &par, xdr_result_int, &res, timeout)) {
D("pdsm_atl_l2_proxy_reg(%d, %d, %d) failed\n", par.data[0], par.data[1], par.data[2]);
free(par.data);
exit(-1);
}
D("pdsm_atl_l2_proxy_reg(%d, %d, %d)=%d\n", par.data[0], par.data[1], par.data[2], res);
free(par.data);
return res;
}
int pdsm_atl_dns_proxy_reg(struct CLIENT *clnt, int val0, int val1) {
struct params par;
uint32_t res;
par.data=malloc(sizeof(int)*2);
par.length=2;
par.data[0]=val0;
par.data[1]=val1;
if(clnt_call(clnt, 0x6, xdr_args, &par, xdr_result_int, &res, timeout)) {
D("pdsm_atl_dns_proxy_reg(%d, %d) failed\n", par.data[0], par.data[1]);
free(par.data);
exit(-1);
}
D("pdsm_atl_dns_proxy(%d, %d)=%d\n", par.data[0], par.data[1], res);
free(par.data);
return res;
}
int pdsm_client_pd_reg(struct CLIENT *clnt, int client, int val0, int val1, int val2, int val3, int val4) {
struct params par;
uint32_t res;
par.data=malloc(sizeof(int)*6);
par.length=6;
par.data[0]=client_IDs[client];
par.data[1]=val0;
par.data[2]=val1;
par.data[3]=val2;
par.data[4]=val3;
par.data[5]=val4;
if(clnt_call(clnt, 0x4, xdr_args, &par, xdr_result_int, &res, timeout)) {
D("pdsm_client_pd_reg(%x, %d, %d, %d, %x, %d) failed\n", par.data[0], par.data[1], par.data[2], par.data[3], par.data[4], par.data[5]);
free(par.data);
exit(-1);
}
D("pdsm_client_pd_reg(%x, %d, %d, %d, %x, %d)=%d\n", par.data[0], par.data[1], par.data[2], par.data[3], par.data[4], par.data[5], res);
free(par.data);
return res;
}
int pdsm_client_pa_reg(struct CLIENT *clnt, int client, int val0, int val1, int val2, int val3, int val4) {
struct params par;
uint32_t res;
par.data=malloc(sizeof(int)*6);
par.length=6;
par.data[0]=client_IDs[client];
par.data[1]=val0;
par.data[2]=val1;
par.data[3]=val2;
par.data[4]=val3;
par.data[5]=val4;
if(clnt_call(clnt, 0x5, xdr_args, &par, xdr_result_int, &res, timeout)) {
D("pdsm_client_pa_reg(%x, %d, %d, %d, %x, %d) failed\n", par.data[0], par.data[1], par.data[2], par.data[3], par.data[4], par.data[5]);
free(par.data);
exit(-1);
}
D("pdsm_client_pa_reg(%x, %d, %d, %d, %x, %d)=%d\n", par.data[0], par.data[1], par.data[2], par.data[3], par.data[4], par.data[5], res);
free(par.data);
return res;
}
int pdsm_client_lcs_reg(struct CLIENT *clnt, int client, int val0, int val1, int val2, int val3, int val4) {
struct params par;
uint32_t res;
par.data=malloc(sizeof(int)*6);
par.length=6;
par.data[0]=client_IDs[client];
par.data[1]=val0;
par.data[2]=val1;
par.data[3]=val2;
par.data[4]=val3;
par.data[5]=val4;
if(clnt_call(clnt, 0x6, xdr_args, &par, xdr_result_int, &res, timeout)) {
D("pdsm_client_lcs_reg(%x, %d, %d, %d, %x, %d) failed\n", par.data[0], par.data[1], par.data[2], par.data[3], par.data[4], par.data[5]);
free(par.data);
exit(-1);
}
D("pdsm_client_lcs_reg(%x, %d, %d, %d, %x, %d)=%d\n", par.data[0], par.data[1], par.data[2], par.data[3], par.data[4], par.data[5], res);
free(par.data);
return res;
}
int pdsm_client_ext_status_reg(struct CLIENT *clnt, int client, int val0, int val1, int val2, int val3, int val4) {
struct params par;
uint32_t res;
par.data=malloc(sizeof(int)*6);
par.length=6;
par.data[0]=client_IDs[client];
par.data[1]=val0;
par.data[2]=val1;
par.data[3]=val2;
par.data[4]=val3;
par.data[5]=val4;
if(clnt_call(clnt, 0x8, xdr_args, &par, xdr_result_int, &res, timeout)) {
D("pdsm_client_ext_status_reg(%x, %d, %d, %d, %d, %d) failed\n", par.data[0], par.data[1], par.data[2], par.data[3], par.data[4], par.data[5]);
free(par.data);
exit(-1);
}
D("pdsm_client_ext_status_reg(%x, %d, %d, %d, %d, %d)=%d\n", par.data[0], par.data[1], par.data[2], par.data[3], par.data[4], par.data[5], res);
free(par.data);
return res;
}
int pdsm_client_xtra_reg(struct CLIENT *clnt, int client, int val0, int val1, int val2, int val3, int val4) {
struct params par;
uint32_t res;
par.data=malloc(sizeof(int)*6);
par.length=6;
par.data[0]=client_IDs[client];
par.data[1]=val0;
par.data[2]=val1;
par.data[3]=val2;
par.data[4]=val3;
par.data[5]=val4;
if(clnt_call(clnt, 0x7, xdr_args, &par, xdr_result_int, &res, timeout)) {
D("pdsm_client_xtra_reg(%x, %d, %d, %d, %d, %d) failed\n", par.data[0], par.data[1], par.data[2], par.data[3], par.data[4], par.data[5]);
free(par.data);
exit(-1);
}
D("pdsm_client_xtra_reg(%x, %d, %d, %d, %d, %d)=%d\n", par.data[0], par.data[1], par.data[2], par.data[3], par.data[4], par.data[5], res);
free(par.data);
return res;
}
int pdsm_client_act(struct CLIENT *clnt, int client) {
struct params par;
uint32_t res;
par.data=malloc(sizeof(int));
par.length=1;
par.data[0]=client_IDs[client];
if(clnt_call(clnt, 0x9, xdr_args, &par, xdr_result_int, &res, timeout)) {
D("pdsm_client_act(%x) failed\n", par.data[0]);
free(par.data);
exit(-1);
}
D("pdsm_client_act(%x)=%d\n", par.data[0], res);
free(par.data);
return res;
}
int pdsm_xtra_set_data(struct CLIENT *clnt, int val0, int client_ID, int val2, unsigned char *xtra_data_ptr, uint32_t part_len, uint8_t part, uint8_t total_parts, int val3) {
struct xtra_data_params xtra_data;
uint32_t res = -1;
xtra_data.data=malloc(sizeof(int)*4);
xtra_data.data[0]=val0;
xtra_data.data[1]=client_ID;
xtra_data.data[2]=val2;
xtra_data.xtra_data_ptr = xtra_data_ptr;
xtra_data.part_len = part_len;
xtra_data.part = part;
xtra_data.total_parts = total_parts;
xtra_data.data[3]=val3;
enum clnt_stat cs = -1;
cs = clnt_call(clnt, 0x1A,
(xdrproc_t) xdr_xtra_data_args,
(caddr_t) &xtra_data,
(xdrproc_t) xdr_result_int,
(caddr_t) &res, timeout);
DD("%s() is called: clnt_stat=%d", __FUNCTION__, cs);
if (cs != RPC_SUCCESS){
D("pdsm_xtra_set_data(%x, %x, %d, 0x%x, %d, %d, %d, %d) failed\n", val0, client_ID, val2, (int) xtra_data_ptr, part_len, part, total_parts, val3);
free(xtra_data.data);
exit(-1);
}
D("pdsm_xtra_set_data(%x, %x, %d, 0x%x, %d, %d, %d, %d)=%d\n", val0, client_ID, val2, (int) xtra_data_ptr, part_len, part, total_parts, val3, res);
free(xtra_data.data);
return res;
}
int pdsm_xtra_inject_time_info(struct CLIENT *clnt, int val0, int client_ID, int val2, pdsm_xtra_time_info_type *time_info_ptr) {
struct xtra_time_params xtra_time;
uint32_t res = -1;
xtra_time.data=malloc(sizeof(int)*3);
xtra_time.data[0]=val0;
xtra_time.data[1]=client_ID;
xtra_time.data[2]=val2;
xtra_time.time_info_ptr = time_info_ptr;
enum clnt_stat cs = -1;
cs = clnt_call(clnt, 0x1E,
(xdrproc_t) xdr_xtra_time_args,
(caddr_t) &xtra_time,
(xdrproc_t) xdr_result_int,
(caddr_t) &res, timeout);
DD("%s() is called: clnt_stat=%d", __FUNCTION__, cs);
if (cs != RPC_SUCCESS){
D("pdsm_xtra_inject_time_info(%x, %x, %d, %lld, %d) failed\n", val0, client_ID, val2, time_info_ptr->time_utc, time_info_ptr->uncertainty);
free(xtra_time.data);
exit(-1);
}
D("pdsm_xtra_inject_time_info(%x, %x, %d, %lld, %d)=%d\n", val0, client_ID, val2, time_info_ptr->time_utc, time_info_ptr->uncertainty, res);
free(xtra_time.data);
return res;
}
int pdsm_get_position(struct CLIENT *clnt, int val0, int val1, int val2, int val3, int val4, int val5, int val6, int val7, int val8, int val9, int val10, int val11, int val12, int val13, int val14, int val15, int val16, int
val17, int val18, int val19, int val20, int val21, int val22, int val23, int val24, int val25, int val26, int val27, int val28)
{
struct params par;
uint32_t res;
par.data=malloc(sizeof(int)*29);
par.length=29;
par.data[0]=val0;
par.data[1]=val1;
par.data[2]=val2;
par.data[3]=val3;
par.data[4]=val4;
par.data[5]=val5;
par.data[6]=val6;
par.data[7]=val7;
par.data[8]=val8;
par.data[9]=val9;
par.data[10]=val10;
par.data[11]=val11;
par.data[12]=val12;
par.data[13]=val13;
par.data[14]=val14;
par.data[15]=val15;
par.data[16]=val16;
par.data[17]=val17;
par.data[18]=val18;
par.data[19]=val19;
par.data[20]=val20;
par.data[21]=val21;
par.data[22]=val22;
par.data[23]=val23;
par.data[24]=val24;
par.data[25]=val25;
par.data[26]=val26;
par.data[27]=val27;
par.data[28]=val28;
if(clnt_call(clnt, 0xb,
(xdrproc_t)xdr_args,
(caddr_t)&par,
(xdrproc_t)xdr_result_int,
(caddr_t)&res, timeout))
{
D("pdsm_client_get_position() failed\n");
free(par.data);
exit(-1);
}
D("pdsm_client_get_position()=%d\n", res);
free(par.data);
return res;
}
enum pdsm_pd_events {
PDSM_PD_EVENT_POSITION = 0x1,
PDSM_PD_EVENT_VELOCITY = 0x2,
PDSM_PD_EVENT_HEIGHT = 0x4,
PDSM_PD_EVENT_DONE = 0x8,
PDSM_PD_EVENT_END = 0x10,
PDSM_PD_EVENT_BEGIN = 0x20,
PDSM_PD_EVENT_COMM_BEGIN = 0x40,
PDSM_PD_EVENT_COMM_CONNECTED = 0x80,
PDSM_PD_EVENT_COMM_DONE = 0x200,
PDSM_PD_EVENT_GPS_BEGIN = 0x4000,
PDSM_PD_EVENT_GPS_DONE = 0x8000,
PDSM_PD_EVENT_UPDATE_FAIL = 0x1000000,
};
//From leo-gps.c
extern void update_gps_location(GpsLocation *location);
extern void update_gps_status(GpsStatusValue value);
extern void update_gps_svstatus(GpsSvStatus *svstatus);
void dispatch_pdsm_pd(uint32_t *data) {
uint32_t event=ntohl(data[2]);
D("%s(): event=0x%x", __FUNCTION__, event);
if(event&PDSM_PD_EVENT_BEGIN) {
D("PDSM_PD_EVENT_BEGIN");
}
if(event&PDSM_PD_EVENT_GPS_BEGIN) {
D("PDSM_PD_EVENT_GPS_BEGIN");
}
if(event&PDSM_PD_EVENT_GPS_DONE) {
D("PDSM_PD_EVENT_GPS_DONE");
has_fix = 0;
}
GpsLocation fix;
fix.flags = 0;
if(event&PDSM_PD_EVENT_POSITION) {
D("PDSM_PD_EVENT_POSITION");
GpsSvStatus ret;
int i;
ret.num_svs=ntohl(data[82]) & 0x1F;
// debugged by tytung
//DD("pd %3d: %08x ", 77, ntohl(data[77]));
for(i=60;i<83;++i) {
DD("pd %3d: %08x ", i, ntohl(data[i]));
}
for(i=83;i<83+3*(ret.num_svs-1)+3;++i) {
DD("pd %3d: %d ", i, ntohl(data[i]));
}
for(i=0;i<ret.num_svs;++i) {
ret.sv_list[i].prn=ntohl(data[83+3*i]);
ret.sv_list[i].elevation=ntohl(data[83+3*i+1]);
ret.sv_list[i].azimuth=ntohl(data[83+3*i+2])/100;
ret.sv_list[i].snr=ntohl(data[83+3*i+2])%100;
}
ret.used_in_fix_mask=ntohl(data[77]);
update_gps_svstatus(&ret);
fix.timestamp = ntohl(data[8]);
if (!fix.timestamp) return;
// convert gps time to epoch time ms
fix.timestamp += 315964800; // 1/1/1970 to 1/6/1980
fix.timestamp -= 15; // 15 leap seconds between 1980 and 2011
fix.timestamp *= 1000; //ms
fix.flags |= GPS_LOCATION_HAS_LAT_LONG;
has_fix = 1;
if (ntohl(data[75])) {
fix.flags |= GPS_LOCATION_HAS_ACCURACY;
fix.accuracy = (float)ntohl(data[75]) / 10.0f * 2.5; // Measurement Precision = 2.5
}
union {
struct {
uint32_t lowPart;
int32_t highPart;
};
int64_t int64Part;
} latitude, longitude;
latitude.lowPart = ntohl(data[61]);
latitude.highPart = ntohl(data[60]);
longitude.lowPart = ntohl(data[63]);
longitude.highPart = ntohl(data[62]);
fix.latitude = (double)latitude.int64Part / 1.0E8;
fix.longitude = (double)longitude.int64Part / 1.0E8;
}
if (event&PDSM_PD_EVENT_VELOCITY)
{
D("PDSM_PD_EVENT_VELOCITY");
fix.flags |= GPS_LOCATION_HAS_SPEED|GPS_LOCATION_HAS_BEARING;
fix.speed = (float)ntohl(data[66]) / 10.0f / 3.6f; // convert kp/h to m/s
fix.bearing = (float)ntohl(data[67]) / 10.0f;
}
if (event&PDSM_PD_EVENT_HEIGHT)
{
D("PDSM_PD_EVENT_HEIGHT");
fix.flags |= GPS_LOCATION_HAS_ALTITUDE;
fix.altitude = (double)ntohl(data[64]) / 10.0f;
}
if (fix.flags)
{
update_gps_location(&fix);
}
if(event&PDSM_PD_EVENT_END)
{
D("PDSM_PD_EVENT_END");
}
if(event&PDSM_PD_EVENT_DONE)
{
D("PDSM_PD_EVENT_DONE");
can_send=1;
}
}
void dispatch_pdsm_ext(uint32_t *data) {
GpsSvStatus ret;
int i;
if (has_fix) return;
ret.num_svs=ntohl(data[8]);
D("%s() is called. num_svs=%d", __FUNCTION__, ret.num_svs);
// debugged by tytung
for(i=0;i<12;++i) {
DD("e %3d: %08x ", i, ntohl(data[i]));
}
for(i=101;i<101+12*(ret.num_svs-1)+6;++i) {
DD("e %3d: %d ", i, ntohl(data[i]));
}
for(i=0;i<ret.num_svs;++i) {
ret.sv_list[i].prn=ntohl(data[101+12*i+1]);
ret.sv_list[i].elevation=ntohl(data[101+12*i+5]);
ret.sv_list[i].azimuth=ntohl(data[101+12*i+4]);
ret.sv_list[i].snr=(float)ntohl(data[101+12*i+2])/10.0f;
}
//ret.used_in_fix_mask=ntohl(data[9]);
ret.used_in_fix_mask=0;
if (ret.num_svs) {
update_gps_svstatus(&ret);
}
}
void dispatch_pdsm(uint32_t *data) {
uint32_t procid=ntohl(data[5]);
D("%s() is called. data[5]=procid=%d", __FUNCTION__, procid);
if(procid==1)
dispatch_pdsm_pd(&(data[10]));
else if(procid==4)
dispatch_pdsm_ext(&(data[10]));
}
void dispatch_atl(uint32_t *data) {
D("%s() is called", __FUNCTION__);
// No clue what happens here.
}
void dispatch(struct svc_req* a, registered_server* svc) {
int i;
uint32_t *data=svc->xdr->in_msg;
uint32_t result=0;
uint32_t svid=ntohl(data[3]);
/*
D("received some kind of event\n");
for(i=0;i< svc->xdr->in_len/4;++i) {
D("%08x ", ntohl(data[i]));
}
D("\n");
for(i=0;i< svc->xdr->in_len/4;++i) {
D("%010d ", ntohl(data[i]));
}
D("\n");
*/
if(svid==0x3100005b) {
dispatch_pdsm(data);
} else if(svid==0x3100001d) {
dispatch_atl(data);
} else {
//Got dispatch for unknown serv id!
}
//ACK
svc_sendreply(svc, xdr_int, &result);
}
int pdsm_client_end_session(struct CLIENT *clnt, int val0, int val1, int val2, int client) {
struct params par;
uint32_t res;
par.data=malloc(sizeof(int)*4);
par.length=4;
par.data[0]=val0;
par.data[1]=val1;
par.data[2]=val2;
par.data[3]=client_IDs[client];
if(clnt_call(clnt, 0xc, xdr_args, &par, xdr_result_int, &res, timeout)) {
D("pdsm_client_end_session(%d, %d, %d, %x) failed\n", par.data[0], par.data[1], par.data[2], par.data[3]);
free(par.data);
exit(-1);
}
D("pdsm_client_end_session(%d, %d, %d, %x)=%x\n", par.data[0], par.data[1], par.data[2], par.data[3], res);
free(par.data);
return 0;
}
int init_leo()
{
struct CLIENT *clnt=clnt_create(NULL, 0x3000005B, 0x00010001, NULL);
struct CLIENT *clnt_atl=clnt_create(NULL, 0x3000001D, 0x00010001, NULL);
int i;
_clnt=clnt;
SVCXPRT *svc=svcrtr_create();
xprt_register(svc);
svc_register(svc, 0x3100005b, 0x00010001, (__dispatch_fn_t)dispatch, 0);
svc_register(svc, 0x3100005b, 0, (__dispatch_fn_t)dispatch, 0);
svc_register(svc, 0x3100001d, 0x00010001 /*xb93145f7*/, (__dispatch_fn_t)dispatch, 0);
svc_register(svc, 0x3100001d, 0 /*xb93145f7*/, (__dispatch_fn_t)dispatch, 0);
if(!clnt) {
D("Failed creating client\n");
return -1;
}
if(!svc) {
D("Failed creating server\n");
return -2;
}
// PDA
pdsm_client_init(clnt, 2);
pdsm_client_pd_reg(clnt, 2, 0, 0, 0, 0xF3F0FFFF, 0);
pdsm_client_pa_reg(clnt, 2, 0, 2, 0, 0x7ffefe0, 0);
pdsm_client_ext_status_reg(clnt, 2, 0, 0, 0, 0x4, 0);
pdsm_client_act(clnt, 2);
// XTRA
pdsm_client_init(clnt, 0xb);
pdsm_client_xtra_reg(clnt, 0xb, 0, 3, 0, 7, 0);
pdsm_client_act(clnt, 0xb);
pdsm_atl_l2_proxy_reg(clnt_atl, 1,0,0);
pdsm_atl_dns_proxy_reg(clnt_atl, 1,0);
// NI
pdsm_client_init(clnt, 4);
pdsm_client_lcs_reg(clnt, 4, 0,0,0,0x3f0, 0);
pdsm_client_act(clnt, 4);
return 0;
}
int init_gps_rpc()
{
init_leo();
return 0;
}
int gps_xtra_set_data(unsigned char *xtra_data_ptr, uint32_t part_len, uint8_t part, uint8_t total_parts)
{
uint32_t res = -1;
res = pdsm_xtra_set_data(_clnt, 0, client_IDs[0xb], 0, xtra_data_ptr, part_len, part, total_parts, 0);
return res;
}
extern int64_t elapsed_realtime();
int gps_xtra_inject_time_info(GpsUtcTime time, int64_t timeReference, int uncertainty)
{
uint32_t res = -1;
pdsm_xtra_time_info_type time_info_ptr;
time_info_ptr.uncertainty = uncertainty;
time_info_ptr.time_utc = time;
time_info_ptr.time_utc += (int64_t)(elapsed_realtime() - timeReference);
time_info_ptr.ref_to_utc_time = 1;
time_info_ptr.force_flag = 1;
res = pdsm_xtra_inject_time_info(_clnt, 0, client_IDs[0xb], 0, &time_info_ptr);
return res;
}
void gps_get_position()
{
D("%s() is called. can_send=%d", __FUNCTION__, can_send);
int i;
for(i = 3; i; --i) if(!can_send) sleep(1);//Time out of 3 seconds on can_send
can_send = 0;
pdsm_get_position(_clnt,
2, 0,
1,
1, 1,
0x3B9AC9FF, 1,
0,
0, 0,
0, 0,
0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
1, 50, 2,
client_IDs[2]);
}
void exit_gps_rpc()
{
pdsm_client_end_session(_clnt, 0, 0, 0, 2);
}
// END OF FILE

1053
libgps/leo-gps.c Normal file

File diff suppressed because it is too large Load Diff

15
libhtc_ril_wrapper/Android.mk Executable file
View File

@ -0,0 +1,15 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := libhtc_ril_wrapper.c
LOCAL_SHARED_LIBRARIES := liblog libdl libnetutils libcutils
LOCAL_CFLAGS := -std=c99
LOCAL_CFLAGS += -DRIL_SHLIB
#build shared library
LOCAL_MODULE:= libhtc_ril_wrapper
LOCAL_MODULE_TAGS := eng
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)

View File

190
libhtc_ril_wrapper/NOTICE Executable file
View File

@ -0,0 +1,190 @@
Copyright (c) 2005-2008, The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View File

@ -0,0 +1,763 @@
/*
* Credits go to LeTama for the data connection code and phh for the wrapper code
* Copyright (C) 2010 Sebastian Heinecke (gauner1986)
*
* 0.8 by cedesmith
*/
#include <telephony/ril.h>
#include <dlfcn.h>
#include <utils/Log.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/wait.h>
#include <termios.h>
#include <time.h>
#include <poll.h>
#include <cutils/properties.h>
#include <arpa/inet.h>
#undef LOG_TAG
#define LOG_TAG "RIL_WRAP"
#define RIL_onRequestComplete(t, e, response, responselen) s_rilenv->OnRequestComplete(t,e, response, responselen)
#define msleep(x) usleep(x*1000);
static const struct RIL_Env *s_rilenv;
static struct RIL_Env htcril_env;
static void *ril_handler=NULL;
static int rmnet_mode = 1;
static int nand_init = 0;
static volatile int pppd_pid;
static volatile int delayedNetworkReady=0;
static volatile RIL_Token request_registration_state_token = NULL;
char current_apn[80];
char current_user[80];
char current_addr[16];
static volatile int registrationState=0;
static volatile int gprsRegistrationState=0;
static volatile RIL_LastDataCallActivateFailCause lastDataError=PDP_FAIL_ERROR_UNSPECIFIED;
char* logtime()
{
static char sTime[10];
time_t t = time(NULL);
strftime(sTime, sizeof(sTime), "%H:%M:%S", localtime(&t));
return sTime;
}
typedef enum {
DATA_STATE_DISCONNECTED=0,
DATA_STATE_DISCONNECTING,
DATA_STATE_PPP_DIED,
DATA_STATE_CONNECTING,
DATA_STATE_CONNECTED,
DATA_STATE_CONNECTION_KILL,
} Wrap_DataCallState;
static volatile Wrap_DataCallState dataConnectionState=DATA_STATE_DISCONNECTED;
static volatile int fd_smd=-1;
int open_modem()
{
if(fd_smd!=-1) return fd_smd;
fd_smd = open ("/dev/smd0", O_RDWR);
if(fd_smd == -1) {
LOGE("%s: send_modem: Error opening smd0", logtime());
return -1; //AT_ERROR_GENERIC;
}
struct termios ios;
tcgetattr( fd_smd, &ios );
ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
tcsetattr( fd_smd, TCSANOW, &ios );
//fcntl(fd_smd, F_SETFL, O_NONBLOCK | fcntl(fd_smd, F_GETFL, 0));
return fd_smd;
}
void close_modem(){
if(fd_smd!=-1) {
close(fd_smd);
fd_smd=-1;
}
}
int send_modem(const char * cmd)
{
int err = 0;
size_t cur = 0;
ssize_t written;
size_t len = strlen(cmd);
if(open_modem() == -1) return -1; //AT_ERROR_GENERIC;
LOGD("%s: AT> %s", logtime(), cmd);
/* the main string */
while (cur < len) {
do {
written = write (fd_smd, cmd + cur, len - cur);
} while (written < 0 && errno == EINTR);
if (written < 0) return -1;// AT_ERROR_GENERIC;
cur += written;
}
/* the \r */
do {
written = write (fd_smd, "\r" , 1);
} while ((written < 0 && errno == EINTR) || (written == 0));
if (written < 0) {
LOGE("%s: send_modem: write failure", logtime());
return -1; //AT_ERROR_GENERIC;
}
return written;
}
int read_modem(char* response, size_t responseLen)
{
if(open_modem() == -1) return -1;
char *pread=response;
while( pread<response+responseLen){
if(read(fd_smd, pread, 1)<=0) break;
if((*pread=='\n' || *pread=='\r') && pread==response) continue;
if(*pread=='\r') break;
pread++;
}
*pread=0;
if(pread!=response) LOGD("%s: MODEM> %s", logtime(), response);
else LOGD("%s MODEM>", logtime());
return pread-response;
}
const char* requestToString(int request)
{
switch(request) {
case RIL_REQUEST_GET_SIM_STATUS: return "GET_SIM_STATUS";
case RIL_REQUEST_ENTER_SIM_PIN: return "ENTER_SIM_PIN";
case RIL_REQUEST_ENTER_SIM_PUK: return "ENTER_SIM_PUK";
case RIL_REQUEST_ENTER_SIM_PIN2: return "ENTER_SIM_PIN2";
case RIL_REQUEST_ENTER_SIM_PUK2: return "ENTER_SIM_PUK2";
case RIL_REQUEST_CHANGE_SIM_PIN: return "CHANGE_SIM_PIN";
case RIL_REQUEST_CHANGE_SIM_PIN2: return "CHANGE_SIM_PIN2";
case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION: return "ENTER_NETWORK_DEPERSONALIZATION";
case RIL_REQUEST_GET_CURRENT_CALLS: return "GET_CURRENT_CALLS";
case RIL_REQUEST_DIAL: return "DIAL";
case RIL_REQUEST_GET_IMSI: return "GET_IMSI";
case RIL_REQUEST_HANGUP: return "HANGUP";
case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: return "HANGUP_WAITING_OR_BACKGROUND";
case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: return "HANGUP_FOREGROUND_RESUME_BACKGROUND";
case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE: return "SWITCH_WAITING_OR_HOLDING_AND_ACTIVE";
case RIL_REQUEST_CONFERENCE: return "CONFERENCE";
case RIL_REQUEST_UDUB: return "UDUB";
case RIL_REQUEST_LAST_CALL_FAIL_CAUSE: return "LAST_CALL_FAIL_CAUSE";
case RIL_REQUEST_SIGNAL_STRENGTH: return "SIGNAL_STRENGTH";
case RIL_REQUEST_REGISTRATION_STATE: return "REGISTRATION_STATE";
case RIL_REQUEST_GPRS_REGISTRATION_STATE: return "GPRS_REGISTRATION_STATE";
case RIL_REQUEST_OPERATOR: return "OPERATOR";
case RIL_REQUEST_RADIO_POWER: return "RADIO_POWER";
case RIL_REQUEST_DTMF: return "DTMF";
case RIL_REQUEST_SEND_SMS: return "SEND_SMS";
case RIL_REQUEST_SEND_SMS_EXPECT_MORE: return "SEND_SMS_EXPECT_MORE";
case RIL_REQUEST_SETUP_DATA_CALL: return "SETUP_DATA_CALL";
case RIL_REQUEST_SIM_IO: return "SIM_IO";
case RIL_REQUEST_SEND_USSD: return "SEND_USSD";
case RIL_REQUEST_CANCEL_USSD: return "CANCEL_USSD";
case RIL_REQUEST_GET_CLIR: return "GET_CLIR";
case RIL_REQUEST_SET_CLIR: return "SET_CLIR";
case RIL_REQUEST_QUERY_CALL_FORWARD_STATUS: return "QUERY_CALL_FORWARD_STATUS";
case RIL_REQUEST_SET_CALL_FORWARD: return "SET_CALL_FORWARD";
case RIL_REQUEST_QUERY_CALL_WAITING: return "QUERY_CALL_WAITING";
case RIL_REQUEST_SET_CALL_WAITING: return "SET_CALL_WAITING";
case RIL_REQUEST_SMS_ACKNOWLEDGE: return "SMS_ACKNOWLEDGE";
case RIL_REQUEST_GET_IMEI: return "GET_IMEI";
case RIL_REQUEST_GET_IMEISV: return "GET_IMEISV";
case RIL_REQUEST_ANSWER: return "ANSWER";
case RIL_REQUEST_DEACTIVATE_DATA_CALL: return "DEACTIVATE_DATA_CALL";
case RIL_REQUEST_QUERY_FACILITY_LOCK: return "QUERY_FACILITY_LOCK";
case RIL_REQUEST_SET_FACILITY_LOCK: return "SET_FACILITY_LOCK";
case RIL_REQUEST_CHANGE_BARRING_PASSWORD: return "CHANGE_BARRING_PASSWORD";
case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE: return "QUERY_NETWORK_SELECTION_MODE";
case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC: return "SET_NETWORK_SELECTION_AUTOMATIC";
case RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL: return "SET_NETWORK_SELECTION_MANUAL";
case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS : return "QUERY_AVAILABLE_NETWORKS ";
case RIL_REQUEST_DTMF_START: return "DTMF_START";
case RIL_REQUEST_DTMF_STOP: return "DTMF_STOP";
case RIL_REQUEST_BASEBAND_VERSION: return "BASEBAND_VERSION";
case RIL_REQUEST_SEPARATE_CONNECTION: return "SEPARATE_CONNECTION";
case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: return "SET_PREFERRED_NETWORK_TYPE";
case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: return "GET_PREFERRED_NETWORK_TYPE";
case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS: return "GET_NEIGHBORING_CELL_IDS";
case RIL_REQUEST_SET_MUTE: return "SET_MUTE";
case RIL_REQUEST_GET_MUTE: return "GET_MUTE";
case RIL_REQUEST_QUERY_CLIP: return "QUERY_CLIP";
case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE: return "LAST_DATA_CALL_FAIL_CAUSE";
case RIL_REQUEST_DATA_CALL_LIST: return "DATA_CALL_LIST";
case RIL_REQUEST_RESET_RADIO: return "RESET_RADIO";
case RIL_REQUEST_OEM_HOOK_RAW: return "OEM_HOOK_RAW";
case RIL_REQUEST_OEM_HOOK_STRINGS: return "OEM_HOOK_STRINGS";
case RIL_REQUEST_SET_BAND_MODE: return "SET_BAND_MODE";
case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE: return "QUERY_AVAILABLE_BAND_MODE";
case RIL_REQUEST_STK_GET_PROFILE: return "STK_GET_PROFILE";
case RIL_REQUEST_STK_SET_PROFILE: return "STK_SET_PROFILE";
case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND: return "STK_SEND_ENVELOPE_COMMAND";
case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE: return "STK_SEND_TERMINAL_RESPONSE";
case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: return "STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM";
case RIL_REQUEST_SCREEN_STATE: return "SCREEN_STATE";
case RIL_REQUEST_EXPLICIT_CALL_TRANSFER: return "EXPLICIT_CALL_TRANSFER";
case RIL_REQUEST_SET_LOCATION_UPDATES: return "SET_LOCATION_UPDATES";
case RIL_REQUEST_CDMA_SET_SUBSCRIPTION:return"CDMA_SET_SUBSCRIPTION";
case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE:return"CDMA_SET_ROAMING_PREFERENCE";
case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE:return"CDMA_QUERY_ROAMING_PREFERENCE";
case RIL_REQUEST_SET_TTY_MODE:return"SET_TTY_MODE";
case RIL_REQUEST_QUERY_TTY_MODE:return"QUERY_TTY_MODE";
case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE:return"CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE";
case RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE:return"CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE";
case RIL_REQUEST_CDMA_FLASH:return"CDMA_FLASH";
case RIL_REQUEST_CDMA_BURST_DTMF:return"CDMA_BURST_DTMF";
case RIL_REQUEST_CDMA_SEND_SMS:return"CDMA_SEND_SMS";
case RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE:return"CDMA_SMS_ACKNOWLEDGE";
case RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG:return"GSM_GET_BROADCAST_SMS_CONFIG";
case RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG:return"GSM_SET_BROADCAST_SMS_CONFIG";
case RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG:return "CDMA_GET_BROADCAST_SMS_CONFIG";
case RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG:return "CDMA_SET_BROADCAST_SMS_CONFIG";
case RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION:return "CDMA_SMS_BROADCAST_ACTIVATION";
case RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY: return"CDMA_VALIDATE_AND_WRITE_AKEY";
case RIL_REQUEST_CDMA_SUBSCRIPTION: return"CDMA_SUBSCRIPTION";
case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM: return "CDMA_WRITE_SMS_TO_RUIM";
case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM: return "CDMA_DELETE_SMS_ON_RUIM";
case RIL_REQUEST_DEVICE_IDENTITY: return "DEVICE_IDENTITY";
case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE: return "EXIT_EMERGENCY_CALLBACK_MODE";
case RIL_REQUEST_GET_SMSC_ADDRESS: return "GET_SMSC_ADDRESS";
case RIL_REQUEST_SET_SMSC_ADDRESS: return "SET_SMSC_ADDRESS";
case RIL_REQUEST_REPORT_SMS_MEMORY_STATUS: return "REPORT_SMS_MEMORY_STATUS";
case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: return "UNSOL_RESPONSE_RADIO_STATE_CHANGED";
case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: return "UNSOL_RESPONSE_CALL_STATE_CHANGED";
case RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED: return "UNSOL_RESPONSE_NETWORK_STATE_CHANGED";
case RIL_UNSOL_RESPONSE_NEW_SMS: return "UNSOL_RESPONSE_NEW_SMS";
case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT: return "UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT";
case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM: return "UNSOL_RESPONSE_NEW_SMS_ON_SIM";
case RIL_UNSOL_ON_USSD: return "UNSOL_ON_USSD";
case RIL_UNSOL_ON_USSD_REQUEST: return "UNSOL_ON_USSD_REQUEST(obsolete)";
case RIL_UNSOL_NITZ_TIME_RECEIVED: return "UNSOL_NITZ_TIME_RECEIVED";
case RIL_UNSOL_SIGNAL_STRENGTH: return "UNSOL_SIGNAL_STRENGTH";
case RIL_UNSOL_STK_SESSION_END: return "UNSOL_STK_SESSION_END";
case RIL_UNSOL_STK_PROACTIVE_COMMAND: return "UNSOL_STK_PROACTIVE_COMMAND";
case RIL_UNSOL_STK_EVENT_NOTIFY: return "UNSOL_STK_EVENT_NOTIFY";
case RIL_UNSOL_STK_CALL_SETUP: return "UNSOL_STK_CALL_SETUP";
case RIL_UNSOL_SIM_SMS_STORAGE_FULL: return "UNSOL_SIM_SMS_STORAGE_FUL";
case RIL_UNSOL_SIM_REFRESH: return "UNSOL_SIM_REFRESH";
case RIL_UNSOL_DATA_CALL_LIST_CHANGED: return "UNSOL_DATA_CALL_LIST_CHANGED";
case RIL_UNSOL_CALL_RING: return "UNSOL_CALL_RING";
case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED: return "UNSOL_RESPONSE_SIM_STATUS_CHANGED";
case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS: return "UNSOL_NEW_CDMA_SMS";
case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS: return "UNSOL_NEW_BROADCAST_SMS";
case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL: return "UNSOL_CDMA_RUIM_SMS_STORAGE_FULL";
case RIL_UNSOL_RESTRICTED_STATE_CHANGED: return "UNSOL_RESTRICTED_STATE_CHANGED";
case RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE: return "UNSOL_ENTER_EMERGENCY_CALLBACK_MODE";
case RIL_UNSOL_CDMA_CALL_WAITING: return "UNSOL_CDMA_CALL_WAITING";
case RIL_UNSOL_CDMA_OTA_PROVISION_STATUS: return "UNSOL_CDMA_OTA_PROVISION_STATUS";
case RIL_UNSOL_CDMA_INFO_REC: return "UNSOL_CDMA_INFO_REC";
case RIL_UNSOL_OEM_HOOK_RAW: return "UNSOL_OEM_HOOK_RAW";
case RIL_UNSOL_RINGBACK_TONE: return "UNSOL_RINGBACK_TONE";
case RIL_UNSOL_RESEND_INCALL_MUTE: return "UNSOL_RESEND_INCALL_MUTE";
default: return "<unknown request>";
}
}
struct RequestInfo
{
RIL_Token token;
int request;
time_t startTime;
};
struct RequestInfo pendingRequests[200];
void requestStarted(RIL_Token t, int request)
{
LOGD("%s: Request Received %p %s", logtime(), t, requestToString(request));
for(size_t i=0; i<sizeof(pendingRequests)/sizeof(struct RequestInfo); i++) {
if(pendingRequests[i].token==NULL) {
pendingRequests[i].token=t;
pendingRequests[i].request=request;
pendingRequests[i].startTime=clock();
return;
}
}
LOGD("%s: Request list full", logtime());
}
void requestRemoveAt(int idx)
{
size_t i;
for(i=idx+1; i<sizeof(pendingRequests)/sizeof(struct RequestInfo) && pendingRequests[i].token!=NULL; i++)
pendingRequests[i-1]=pendingRequests[i];
pendingRequests[i-1].token=NULL;
pendingRequests[i-1].request=0;
pendingRequests[i-1].startTime=0;
}
struct RequestInfo requestCompleted(RIL_Token t)
{
struct RequestInfo r = { .token=NULL, .request=0, .startTime=0};
for(size_t i=0; i<sizeof(pendingRequests)/sizeof(struct RequestInfo) && pendingRequests[i].token!=NULL; i++) {
if(pendingRequests[i].token==t) {
r=pendingRequests[i];
LOGD("%s: Request Complete %p %s after %d ms", logtime(), r.token, requestToString(r.request), (unsigned int)(clock()-r.startTime)/(CLOCKS_PER_SEC/1000));
requestRemoveAt(i);
return r;
}
}
LOGD("%s: Request Complete %p not found in started list", logtime(),t);
return r;
}
unsigned requestsPending()
{
unsigned count=0;
for(size_t i=0; i<sizeof(pendingRequests)/sizeof(struct RequestInfo) && pendingRequests[i].token!=NULL; i++) {
if(pendingRequests[i].token!=NULL) {
if((clock()-pendingRequests[i].startTime)/CLOCKS_PER_SEC > 10)
{
LOGD("%s: Request delete %p %s after %d ms", logtime(), pendingRequests[i].token, requestToString(pendingRequests[i].request), (unsigned int)(clock()-pendingRequests[i].startTime)/(CLOCKS_PER_SEC/1000));
requestRemoveAt(i);
i--;
} else {
count++;
}
}
}
return count;
}
void requestsLOGD()
{
for(size_t i=0; i<sizeof(pendingRequests)/sizeof(struct RequestInfo) && pendingRequests[i].token!=NULL; i++)
LOGD(" %p %s for %d ms", pendingRequests[i].token, requestToString(pendingRequests[i].request), (unsigned int)(clock()-pendingRequests[i].startTime)/(CLOCKS_PER_SEC/1000));
}
void requestsWaitComplete(char *msg){
if(requestsPending()>0) {
LOGD("%s: Request pending... waiting to complete", logtime());
requestsLOGD();
while(requestsPending()>0) msleep(1);
LOGD("%s: Request completed... continue %s", logtime(), msg!=NULL ? msg : NULL);
}
}
void* pppd_thread(void *param)
{
LOGD("%s: pppd_thread enter", logtime());
requestsWaitComplete("pppd_thread");
pppd_pid = fork();
if(pppd_pid == 0) {
char buff[256];
kill(getppid(), SIGSTOP); //stop stealing my mojo
int act=0;
send_modem("AT+CGACT?");
do {
read_modem(buff, sizeof(buff));
char* actpos=strstr(buff, "+CGACT: 1,");
if(actpos!=NULL) act=atoi(actpos+10);
}while(buff[0]!='0');
if(act!=0) {
kill(getppid(), SIGCONT);
exit(202);
}
sprintf(buff, "AT+CGDCONT=1,\"IP\",\"%s\",,0,0", current_apn);
send_modem(buff);
read_modem(buff, sizeof(buff));
send_modem("ATD*99***1#");
//send_modem("AT+CGDATA=\"PPP\",1");
while(read_modem(buff, sizeof(buff))>0 && buff[0]=='+');
//read_modem(buff, sizeof(buff));
kill(getppid(), SIGCONT);
int atd=atoi(buff);
if(atd!=1 && atd!=3) exit(201);
sleep(1);
close_modem(); //close modem handle before we transform to pppd
int err = execl("/system/bin/pppd", "pppd", "/dev/smd1", "local","nodetach", "defaultroute", "noipdefault", "usepeerdns", "user", current_user, "debug", NULL);
LOGE("%s: PPPD EXEC FAILED (%d)", logtime(),err);
exit(200);
} else {
LOGD("%s: pppd pid is %d", logtime(),pppd_pid);
int status=0;
time_t start = time(NULL);
waitpid(pppd_pid, &status, 0);
pppd_pid=0;
int runTime = time(NULL)-start;
LOGD("%s: PPPD DIED after %d seconds with status %d", logtime(), runTime, status);
if(lastDataError==PDP_FAIL_ERROR_UNSPECIFIED && WIFEXITED(status)){
switch(WEXITSTATUS(status))
{
case 1: lastDataError=PDP_FAIL_INSUFFICIENT_RESOURCES; break;
case 2: lastDataError=PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED; break;
case 3:
case 4:
lastDataError=PDP_FAIL_PROTOCOL_ERRORS; break;
case 19: lastDataError=PDP_FAIL_USER_AUTHENTICATION; break;
}
}
requestsWaitComplete("pppd_thread");
send_modem("AT+CGACT=0,1");
if(dataConnectionState==DATA_STATE_CONNECTED || dataConnectionState==DATA_STATE_CONNECTION_KILL) {
dataConnectionState=DATA_STATE_DISCONNECTED;
RIL_Data_Call_Response dataCall={ .cid=1, .active=0, .type="IP", .apn=current_apn, .address=current_addr };
s_rilenv->OnUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED, &dataCall, sizeof(RIL_Data_Call_Response));
}
}
LOGD("%s: pppd_thread exit", logtime());
return NULL;
}
void* DeactivateData(void* t)
{
dataConnectionState = DATA_STATE_DISCONNECTING;
LOGD("%s: DeactivateData", logtime());
int pid=pppd_pid; //work with pppd_pid copy as thread will set it to 0 after kill
if(pid!=0) {
int status=0;
LOGD(" waiting for pppd to end %d", pid);
kill(pid, SIGTERM);
waitpid(pid, &status, 0);
LOGD("%s: DeactivateData: pppd ended", logtime());
}
//clear dns entries
property_set("net.ppp0.dns1", "");
property_set("net.ppp0.dns2", "");
dataConnectionState = DATA_STATE_DISCONNECTED;
RIL_onRequestComplete((RIL_Token) t, RIL_E_SUCCESS, NULL, 0);
return NULL;
}
void hackDeactivateData(void *data, size_t datalen, RIL_Token t)
{
LOGD("%s: DeactivateData Request", logtime());
char* cid = ((char **)data)[0];
if(atoi(cid)!=1) {
LOGE(" wrong CID %s expected 1", cid);
return;
}
pthread_t tid;
pthread_create(&tid, NULL, DeactivateData, t);
}
int ifc_get_info(const char *name, unsigned *addr, unsigned *mask, unsigned *flags);
int ifc_init(void);
void ifc_close(void);
void* SetupData(void* t)
{
//this should never happen but let's check
if(pppd_pid!=0 ) {
LOGD(" waiting pppd to die");
int status=0;
kill(pppd_pid, SIGTERM);
waitpid(pppd_pid, &status, 0);
}
//reset ppp.dns
property_set("net.ppp0.dns1", "0.0.0.0");
property_set("net.ppp0.dns2", "0.0.0.0");
strcpy(current_addr, "255.255.255.255");
pthread_t thread;
pthread_create(&thread, NULL, pppd_thread, NULL);
//wait for pppd connect
if(ifc_init()) {
LOGE("%s: IFC failed to init", logtime());
sleep(7);
} else {
clock_t start=clock();
//loop till timeout or connected
while(1) {
//check if ppp0 interface is up, if true break loop, else record dnschange value
unsigned addr, mask, flags;
ifc_get_info("ppp0", &addr, &mask, &flags);
if(flags & 1)
{
struct in_addr in_addr = {.s_addr=addr};
strcpy(current_addr, inet_ntoa(in_addr));
LOGD("%s: IP: %s", logtime(),current_addr);
break;
}
//if timeout goto error
if ( (clock()-start)/CLOCKS_PER_SEC > 60 ){
LOGE("%s: ppp0 connect timed out, giving up", logtime());
ifc_close();
goto error;
}
int status, pid=pppd_pid;
if(pid==0 || waitpid(pid, &status, WNOHANG)>0){
LOGE("%s: ppp0 connect timed out, giving up", logtime());
ifc_close();
goto error;
}
msleep(100);
}
}
ifc_close();
//if ip-up exists wait for dns change
char dns1[PROPERTY_VALUE_MAX];
char dns2[PROPERTY_VALUE_MAX];
struct stat sts;
if(stat("/etc/ppp/ip-up", &sts)==0 && (S_ISREG(sts.st_mode) || S_ISLNK(sts.st_mode))) {
clock_t start=clock();
while(1) {
//check if dnschange changed
property_get("net.ppp0.dns1", dns1, "0.0.0.0");
property_get("net.ppp0.dns2", dns2, "0.0.0.0");
if(strcmp(dns1, "0.0.0.0")!=0 && strcmp(dns2, "0.0.0.0")!=0) break;
if((clock()-start)/CLOCKS_PER_SEC > 2) {
LOGE("%s: timeout waiting for dns change", logtime());
break;
}
msleep(100);
}
}
//check ppp.dns values and set defaults if suspect wrong
property_get("net.ppp0.dns1", dns1, "");
if(strlen(dns1)<7 || strcmp(dns1,"0.0.0.0")==0 || strcmp(dns1, "10.11.12.13")==0) {
LOGD("%s: DNS1: %s wrong setting to 8.8.8.8", logtime(),dns1);
property_set("net.ppp0.dns1", "8.8.8.8");
} else {
LOGD("%s: DNS1: %s", logtime(),dns1);
}
property_get("net.ppp0.dns2", dns2, "");
if(strlen(dns2)<7 || strcmp(dns2, "0.0.0.0")==0 || strcmp(dns2, "10.11.12.14")==0) {
LOGD("%s: DNS2: %s wrong setting to 8.8.4.4", logtime(),dns2);
property_set("net.ppp0.dns2", "8.8.4.4");
} else {
LOGD("%s: DNS2: %s", logtime(),dns2);
}
char *response[3] = { "1", "ppp0", current_addr };
dataConnectionState=DATA_STATE_CONNECTED;
RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
return NULL;
error:
dataConnectionState=DATA_STATE_DISCONNECTED;
RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
return NULL;
}
void hackSetupData(char **data, size_t datalen, RIL_Token t)
{
LOGD("%s: SetupData(%s) Request", logtime(),((const char **)data)[2]);
lastDataError=PDP_FAIL_ERROR_UNSPECIFIED;
if(*data[0]=='0') {
LOGE(" Android want us to connect as CDMA while we are a GSM phone !");
goto error;
}
if(!registrationState) {
LOGE(" network registration state wrong");
lastDataError=PDP_FAIL_REGISTRATION_FAIL;
goto error;
}
if(!gprsRegistrationState) {
LOGE(" gprs registration state wrong");
lastDataError=PDP_FAIL_GPRS_REGISTRATION_FAIL;
goto error;
}
dataConnectionState = DATA_STATE_CONNECTING;
char *apn = ((char **)data)[2];
char *user = ((char **)data)[3];
char *pass = ((char **)data)[4];
if(apn==NULL) apn="";
if(user==NULL || strlen(user)<2) user = "dummy";
if(pass==NULL || strlen(pass)<2) pass = "dummy";
strcpy(current_apn, apn);
strcpy(current_user, user);
//save auth
truncate("/etc/ppp/pap-secrets", 0);
truncate("/etc/ppp/chap-secrets", 0);
char buff[128];
sprintf(buff, "%s * %s\n", user, pass);
int fd;
if((fd=creat("/etc/ppp/pap-secrets", S_IRUSR|S_IWUSR))==-1) {
LOGE("Failed to create /etc/ppp/pap-secrets");
lastDataError=PDP_FAIL_USER_AUTHENTICATION;
goto error;
}
write(fd, buff, strlen(buff));
close(fd);
if((fd=creat("/etc/ppp/chap-secrets", S_IRUSR|S_IWUSR))==-1) {
LOGE("Failed to create /etc/ppp/chap-secrets");
lastDataError=PDP_FAIL_USER_AUTHENTICATION;
goto error;
}
write(fd, buff, strlen(buff));
close(fd);
pthread_t tid;
pthread_create(&tid, NULL, SetupData, t);
return;
error:
dataConnectionState=DATA_STATE_DISCONNECTED;
RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
}
void interceptOnRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen)
{
if(!rmnet_mode) {
struct RequestInfo requestInfo= requestCompleted(t);
if( requestInfo.request==RIL_REQUEST_REGISTRATION_STATE) {
if(responselen>=14*sizeof(char *)) {
char **strings = (char **)response;
int registration = atoi(strings[0]); //1 - Registered, home network; 5 - Registered, roaming
int radio = atoi(strings[3]); //0 == unknown
registrationState=((registration==1 || registration==5) && radio!=0);
LOGD("%s: Registration state %d %d = %d", logtime(), registration, radio, registrationState);
if(!registrationState && pppd_pid!=0 && dataConnectionState==DATA_STATE_CONNECTED){
LOGE("%s: data disconnect due to network registration state", logtime());
lastDataError=PDP_FAIL_REGISTRATION_FAIL;
dataConnectionState=DATA_STATE_CONNECTION_KILL;
kill(pppd_pid, SIGTERM);
}
}
}
if( requestInfo.request==RIL_REQUEST_GPRS_REGISTRATION_STATE) {
if(responselen>=4*sizeof(char *)) {
char **strings = (char **)response;
int registration = atoi(strings[0]); //1 - Registered, home network; 5 - Registered, roaming
int radio = atoi(strings[3]); //0 == unknown; 4 ("unknown") is treated as "out of service" in the Android telephony system
gprsRegistrationState=((registration==1 || registration==5) && (radio!=0 && radio!=4));
LOGD("%s: Registration state %d %d = %d", logtime(), registration, radio, gprsRegistrationState);
if(!gprsRegistrationState && pppd_pid!=0 && dataConnectionState==DATA_STATE_CONNECTED){
LOGE("%s: data disconnect due to gprs registration state", logtime());
lastDataError=PDP_FAIL_GPRS_REGISTRATION_FAIL;
dataConnectionState=DATA_STATE_CONNECTION_KILL;
kill(pppd_pid, SIGTERM);
}
}
}
}
s_rilenv->OnRequestComplete(t, e, response, responselen);
}
void hackDataCallList(char **data, size_t datalen, RIL_Token t)
{
RIL_Data_Call_Response dataCall={ .cid=1, .active=0, .type="IP", .apn=current_apn, .address=current_addr };
LOGD("%s: DataCallList", logtime());
LOGD(" cid=%d, active=%d, type=%s, apn=%s, add=%s", dataCall.cid, dataCall.active, dataCall.type, dataCall.apn, dataCall.address);
s_rilenv->OnRequestComplete(t, RIL_E_SUCCESS, &dataCall, sizeof(RIL_Data_Call_Response));
}
void interceptOnUnsolicitedResponse(int unsolResponse, const void *data, size_t datalen)
{
LOGD("%s: UNSOL %s", logtime(), requestToString(unsolResponse));
s_rilenv->OnUnsolicitedResponse(unsolResponse, data, datalen);
}
void (*htc_onRequest)(int request, void *data, size_t datalen, RIL_Token t);
void onRequest(int request, void *data, size_t datalen, RIL_Token t) {
if(!rmnet_mode) {
switch(request) {
case RIL_REQUEST_SETUP_DATA_CALL:
return hackSetupData(data, datalen, t);
case RIL_REQUEST_DEACTIVATE_DATA_CALL:
return hackDeactivateData(data, datalen, t);
case RIL_REQUEST_DATA_CALL_LIST:
return hackDataCallList(data, datalen, t);
case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE:
s_rilenv->OnRequestComplete(t, RIL_E_SUCCESS,(RIL_LastDataCallActivateFailCause*) &lastDataError, sizeof(RIL_LastDataCallActivateFailCause));
return;
}
requestStarted(t, request);
}
return htc_onRequest(request, data, datalen, t);
}
void writeAdditionalNandInit(){
LOGD("NAND boot, writing additional init commands to /dev/smd0");
send_modem("AT@BRIC=0");
send_modem("AT+CFUN=0");
send_modem("AT+COPS=2");
}
const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
{
int i;
int ril_argc = 0;
char **ril_argv;
RIL_RadioFunctions *(*htc_RIL_Init)(const struct RIL_Env *env, int argc, char **argv);
RIL_RadioFunctions *s_callbacks;
s_rilenv = env;
LOGD("----------- HTC Ril Wrapper v0.8b5 starting ------------");
// we never free this, but we can't tell if htc ril uses argv after init
ril_argv = (char **)malloc(argc * sizeof(char*));
struct stat sts;
if(stat("/system/ppp", &sts)==0 && (S_ISREG(sts.st_mode) || S_ISLNK(sts.st_mode))) rmnet_mode = 0;
LOGD("rmnet_mode=%d", rmnet_mode);
// Parse command line and prepare ril command line
for(i = 0; i < argc ; i++) {
LOGW("RIL_Init arg[%d]=%s", i, argv[i]);
if(strcmp(argv[i], "rmnet_mode") == 0) continue;
if(strcmp(argv[i], "nand_init") == 0)
nand_init = 1;
else {
ril_argv[ril_argc++] = argv[i];
}
}
if(nand_init) writeAdditionalNandInit();
ril_handler=dlopen("/system/lib/libhtc_ril.so", 0/*Need to RTFM, 0 seems fine*/);
htc_RIL_Init = dlsym(ril_handler, "RIL_Init");
// re-route to our man in the middle functions
htcril_env.OnRequestComplete = interceptOnRequestComplete;
htcril_env.OnUnsolicitedResponse = interceptOnUnsolicitedResponse;
htcril_env.RequestTimedCallback = s_rilenv->RequestTimedCallback;
s_callbacks = htc_RIL_Init(&htcril_env, ril_argc, ril_argv);
htc_onRequest = s_callbacks->onRequest;
s_callbacks->onRequest=onRequest;
return s_callbacks;
}