[置顶] android下调试3G之自动拨号

      本章简单讲述下android实现自动拨号的功能,该功能利用了系统启动的rild的服务来实现,因为rild的服务是杀不死的,所以利用这一点,可以使拨号失败或网络断掉后自动重拨,来增强上网的可靠性。这里只实现拨号功能,把ril库实现的一些功能都去掉了。

一、修改rild程序源码

     把 .../hardware/ril里面的文件全部删掉,创建rild文件夹,把以下面代码放到新建的文件夹下。

      1、rild.c

#define LOG_TAG "RILD"
#include <unistd.h>
#include <pthread.h>
#include <utils/Log.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "ril_fun.h"
int main(int argc, char *argv[])
{
	int opt;
	int err;
	pthread_t tid;
	char buf[PROPERTY_VALUE_MAX];
	static int device_fd;
	static char * device_path = NULL;
	umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
    while ( -1 != (opt = getopt(argc, argv, "d:"))) {//用来分析main函数传递的命令行参数
		switch (opt) {
            case 'd':
                device_path = optarg;
                ALOGD("Opening tty device %s\n", device_path);
            break;
            default:
                ALOGD("Not tty device");
                goto done;
        }
    }
	device_fd = device_open(device_path);//打开设备节点
	device_init(device_fd);//初始化设备节点
	property_set("ctl.stop", PPPD_SERVICE_NAME);//设置pppd_gprs属性为停止
	request_setup_datacall(device_fd);//继续执行拨号
		
	pthread_create(&tid,NULL,ip_detection,(void *)device_fd);//创建查询IP线程,使断网后重新拨号
done:
	while(1){
		sleep(0x00ffffff);
	}
	return 0;
}

      2、ril_fun.c

#define LOG_TAG "RIL"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/select.h>
#include "ril_fun.h"

#define PPPD_EXIT_CODE      "net.gprs.ppp-exit"
#define PPP_NET_LOCAL_IP    "net.ppp0.local-ip"
#define PPP_SYSFS_RETRY	    5
#define PPP_OPERSTATE_PATH  "/sys/class/net/ppp0/operstate"

static int pppd_started = 0;

int device_open(char *device_path)
{
	int device_fd = -1;
	while (device_fd < 0) { 
        if (device_path != NULL) {
            device_fd = open (device_path, O_RDWR);//打开串口AT模块的设备 
        }
        if (device_fd < 0) {
			ALOGD ("opening AT interface. retrying...");
			sleep(3);
		}
    }
	return device_fd;
}
void device_init(int device_fd)
{
	struct termios options;
	tcgetattr(device_fd, &options);//获取串口属性
	
	cfsetispeed(&options, B115200);//设置接收波特率
	cfsetospeed(&options, B115200);//设置发送波特率

	options.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|IGNCR|ICRNL|IXON);

	options.c_cflag &= ~PARENB; //无奇偶校验位
	options.c_cflag &= ~CSTOPB;	//停止位为1位
	options.c_cflag &= ~CSIZE;	
	options.c_cflag |= CS8;		//数据位为8位
	
	options.c_lflag   &=   ~(ICANON   |   ECHO   |   ECHOE   |   ISIG);
	
	tcsetattr(device_fd,TCSANOW,&options);
} 
int at_send_command(int device_fd, char *cmd)
{
	int ret;	
	ret = write(device_fd, cmd, strlen(cmd));
	return ret;
}
void request_setup_datacall(int device_fd) 
{
	const char *apn = "cmnet";
    char *cmd = NULL;
    int err;

    ALOGD("requesting data connection to APN '%s'", apn);

    if(pppd_started) {
		ALOGD("Stop existing PPPd before activating PDP");
		property_set("ctl.stop", PPPD_SERVICE_NAME);//设置pppd_gprs属性为停止
		pppd_started = 0;
    }

    err = at_send_command(device_fd, "at$qcpdplt=0");

    asprintf(&cmd, "AT+CGDCONT=1,\"IP\",\"%s\",,0,0", apn);//设置PDP上下文
    err = at_send_command(device_fd, cmd);
    free(cmd);
    if (err < 0 ) {
        ALOGD("AT Send Command error!");
    }

    err = property_set(PPPD_EXIT_CODE, "");//设置net.gprs.ppp-exit为空
    if (err < 0) {
		ALOGW("Set PPPD_EXIT_CODE failed!");
		goto ppp_error;
	}
    err = property_set(PPP_NET_LOCAL_IP, "");//设置net.ppp0.local-ip为空
    if (err < 0) {
		ALOGW("Set PPPD_NET_LOCAL_IP failed!");
		goto ppp_error;
	}
    err = property_set("ctl.start", PPPD_SERVICE_NAME);//设置pppd_gprs属性为启动
    pppd_started = 1;
    if (err < 0) {
		ALOGW("Can not start PPPd");
		goto ppp_error;
    }
    ALOGD("PPPd started");

    return;
ppp_error:
    at_send_command(device_fd, "AT+CGACT=0,1");//PDP上下文去激活

    if(pppd_started) {
		property_set("ctl.stop", PPPD_SERVICE_NAME);
		pppd_started = 0;
    }

}
void *ip_detection(void *arg) 
{
	int fd;
	int err;
	int device_fd = (int)arg;
    char buffer[20];
    char exit_code[PROPERTY_VALUE_MAX];
    static char local_ip[PROPERTY_VALUE_MAX];
	static int pppd_started = 0;

    sleep(2);
    while(1){
		property_get(PPPD_EXIT_CODE, exit_code, "");//获取pppd的退出状态
		if(strcmp(exit_code, "") != 0) {//检测pppd是否异常退出
			ALOGW("PPPd exit with code %s", exit_code);
			request_setup_datacall(device_fd);//继续执行拨号
			goto done;
		}
        fd  = open(PPP_OPERSTATE_PATH, O_RDONLY);//读取/sys/class/net/ppp0/operstate来监控数据网络数据的状态
        if (fd >= 0)  {
			buffer[0] = 0;
            read(fd, buffer, sizeof(buffer));
			close(fd);
			ALOGW("buffer = %s", buffer);
			if(!strncmp(buffer, "up", strlen("up")) || !strncmp(buffer, "unknown", strlen("unknown"))) {
				memset(local_ip,'\0',sizeof(local_ip));
				err = property_get(PPP_NET_LOCAL_IP, local_ip, "");//获取IP
				if (err < 0) {
					ALOGW("Get PPPD_NET_LOCAL_IP failed!");
				}
				if(!strcmp(local_ip, "")) {
					ALOGW("PPP link is up but no local IP is assigned. Will retry times after %d seconds",PPP_SYSFS_RETRY);
					property_set("ctl.stop", PPPD_SERVICE_NAME);//如果没有IP停止pppd
				} else {
					ALOGD("PPP link is up with local IP address %s", local_ip);
				}
			} else {
				ALOGW("PPP link status in %s is %s. Will retry times after %d seconds", \
				PPP_OPERSTATE_PATH, buffer, PPP_SYSFS_RETRY);
				property_set("ctl.stop", PPPD_SERVICE_NAME);//如果数据网络数据的状态不对停止pppd
			}
		} else {
    	    ALOGW("Can not detect PPP state in %s. Will retry  times after %d seconds", \
		    PPP_OPERSTATE_PATH ,PPP_SYSFS_RETRY);
			request_setup_datacall(device_fd);//继续执行拨号
		}
done:
        sleep(PPP_SYSFS_RETRY);
    }

    return NULL;
}

      3、ril_fun.h

#ifndef _RIL_FUN_H_
#define _RIL_FUN_H_

#include <unistd.h>
#include <utils/Log.h> //ALOG*()
#include <cutils/properties.h> //property_set()

#define	PPPD_SERVICE_NAME "pppd_gprs"

/*************************************************************
* 功能:	打开串口设备文件
* 参数:	device_path: 串口设备文件名
* 返回值:	串口设备文件描述符
**************************************************************/
int device_open(char *device_path);
/*************************************************************
* 功能:	初始化设备节点
* 参数:	device_fd: 串口设备文件描述符          
* 返回值:	无
**************************************************************/
void device_init(int device_fd);
/*************************************************************
* 功能:	发送AT指令函数
* 参数:	device_fd: 串口设备文件描述符
*           cmd:AT命令          
* 返回值:	ret:状态
**************************************************************/
int at_send_command(int device_fd, char *cmd);
/*************************************************************
* 功能:	建立拨号函数
* 参数:	device_fd: 串口设备文件描述符          
* 返回值:	无
**************************************************************/
void request_setup_datacall(int device_fd);
/*************************************************************
* 功能:	创建查询IP线程
* 参数:	arg: void类型指针         
* 返回值:	NULL
**************************************************************/
void *ip_detection(void *arg);

#endif

      4、Android.mk

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
	rild.c \
	ril_fun.c


LOCAL_SHARED_LIBRARIES := \
	libcutils \
	libdl

LOCAL_LDLIBS += -lpthread
LOCAL_MODULE:= rild
LOCAL_MODULE_TAGS := optional

include $(BUILD_EXECUTABLE)

      上述文件添加好后,进行编译,在编译前如果之前编译过要进行清理,执行make  clean

二、把下面的脚本放到板子的/etc/ppp下

      1、init.gprs-pppd

#!/system/bin/sh
# An unforunate wrapper script 
# so that the exit code of pppd may be retrieved

PPPD_PID=

/system/bin/setprop "net.gprs.ppp-exit" "" #设置net.gprs.ppp-exit为空
/system/bin/log -t pppd "Starting pppd"

/system/bin/pppd connect 'chat -v -s -r "/var/log/chat.log" -f "/etc/ppp/3gdata_call.conf"' disconnect \
'chat -r "/var/log/chat.log" -t 30 -e -v "" +++ATH "NO CARRIER"' /dev/ttyUSB3 115200 mru 1280 mtu 1280 \
nodetach debug dump defaultroute usepeerdns novj novjccomp crtscts user card password card noipdefault ipcp-accept-local  \
ipcp-accept-remote linkname ppp0

PPPD_EXIT=$? #获得执行命令后的返回值
PPPD_PID=$!  #最后运行的后台进程的PID

/system/bin/log -t pppd "pppd exited with $PPPD_EXIT" 
/system/bin/setprop "net.gprs.ppp-exit" "$PPPD_EXIT" #把返回值设置给net.gprs.ppp-exit

      注:脚本中的/dev/ttyUSB3为模块USB串口的Modem口。

      2、3gdata_call.conf

ABORT "NO CARRIER"
ABORT "NO DIALTONE"
ABORT "ERROR"
ABORT "NO ANSWER"
ABORT "BUSY"
TIMEOUT 120
"" at
OK atd*99***1#
CONNECT

 

三、修改ini.rc脚本 

      打开 .../device/fsl/imx6/etc/init.rc按照如下红色框进行修改

      [置顶] android下调试3G之自动拨号_第1张图片

      添加修改新加入文件权限的语句。

     

      注:/dev/ttyUSB2是模块USB串口的AT口。

到此,就可以进行打包 make  snod ,烧写镜像进行测试了。

可以用命令:logcat  -b  radio 查看rild 输出的信息进行调试。如果一切正常会打印出IP(或用命令 necfg 查看IP),有IP后用命令 ping  202.108.22.5 (百度IP)看下网络是否能ping通。如果能ping通证明自动拨号已经成功。此时用命令 ps查看rild和pppd进程号,用命令kill  -9  <进程号> 杀死随便一个进程,在5s之后看看是不是该进程又运行了。

    

 

你可能感兴趣的:(linux,android,网络,3G,自动拨号)