- android下调试3G之自动拨号
本章简单讲述下android实现自动拨号的功能,该功能利用了系统启动的rild的服务来实现,因为rild的服务是杀不死的,所以利用这一点,可以使拨号失败或网络断掉后自动重拨,来增强上网的可靠性。这里只实现拨号功能,把ril库实现的一些功能都去掉了。
一、修改rild程序源码
把 .../hardware/ril里面的文件全部删掉,创建rild文件夹,把以下面代码放到新建的文件夹下。
1、rild.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
#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
;
}</sys></sys></utils></pthread.h></unistd.h>
|
2、ril_fun.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
#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;
}
</sys></termios.h></fcntl.h></sys></sys></stdlib.h></string.h></stdio.h>
|
3、ril_fun.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
#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
</cutils></utils></unistd.h>
|
4、Android.mk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#!/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 defaultroute usepeerdns crtscts user card password card noipdefault ipcp-accept-local \
ipcp-accept-remote
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
1
2
3
4
5
6
7
8
9
|
ABORT
"NO CARRIER"
ABORT
"NO DIALTONE"
ABORT
"ERROR"
ABORT
"NO ANSWER"
ABORT
"BUSY"
TIMEOUT
120
""
at
OK atd*
99
***
1
#
CONNECT
|
三、修改ini.rc脚本
再修改init.rc前一定要先编译好源码,因为修改的是编译后生成的文件,因为改源文件有点麻烦。
打开 .../ out/target/product/sabresd_6dq/root/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之后看看是不是该进程又运行了。