来自: http://blog.csdn.net/hanbo622/article/details/41009037
本章简单讲述下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按照如下红色框进行修改
添加修改新加入文件权限的语句。
注:/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之后看看是不是该进程又运行了。