Linux/Android系统通过PPP拨号上网
嵌入式系统经常需要具备无线上网的功能,但在有的应用场景中无法使用wifi,这时可以通过GPRS模块上网。GPRS模块是基于AT命令进行控制的。对于单片机这类没有复杂操作系统的平台来说,往往要通过应用程序,直接发送AT命令给GPRS模块,以使GPRS模块连接到网络并建立TCP连接,进而完成通信。对于具有Linux、Android等系统的平台而言,则不需要自己编写程序发送AT命令,可以使用ppp服务进行拨号上网。
在Linux系统下,执行man ppp,可以看到PPP的介绍。
PPP即Point to Point Protocol,是一种用于建立通过拨号调制解调器的网络连接、DSL连接或者其它类型的点对点连接的协议。
RIL:Radio Interface Layer。
在网上可以下载ppp源码,并编译出ppp拨号上网所必需的可执行文件,pppd和chat。除了这两个可执行程序外,还需要一些脚本,具体的脚本如下所示:
[root@Neolix /]# ls /etc/ppp/ -R /etc/ppp/: chap-secrets ioptions options resolv.conf connect-errors ip-down pap-secrets gprs-connect-chat ip-up peers /etc/ppp/peers: gprsdial
ip-up:ppp拨号成功后,会调用这个脚本进行一些设置;
ip-down:连接断开后,会调用这个脚本;
执行pppd call gpradial即可实现拨号,gprs-connect-chat里是chat与gprs模块之间聊天所需的AT命令及应答。
问题一:同样的脚本可以使3G模块正常拨号,但是2G模块拨号失败,拨号过程的信息如下:
pppd call gprsdial timeout set to 15 seconds abort on (DELAYED) abort on (BUSY) abort on (NO DIALTONE) abort on (NO CARRIER) timeout set to 40 seconds send (AT^M) expect (OK) ^M OK -- got it send (ATE0^M) expect (OK) ^M ^M OK -- got it send (AT+CGDCONT=1,"IP","CMNET"^M) expect (OK) ^M ^M OK -- got it send (AT+CGEQREQ=1,2,128,384,,,0,,,,,,^M) expect (OK) ^M ^M OK -- got it send (ATDT*98*1#^M) expect (CONNECT) ^M ^M CONNECT -- got it send (^M) Script /sbin/chat -s -v -f /etc/ppp/gprs-connect-chat finished (pid 131), status = 0x0 Serial connection established. using channel 2 Using interface ppp0 Connect: ppp0 <--> /dev/ttyS3 rcvd [LCP ConfReq id=0x1 <asyncmap 0xa0000> <auth pap> <pcomp> <accomp>] Warning - secret file /etc/ppp/pap-secrets has world and/or group access sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x7ae02b5a> <pcomp> <accomp>] No auth is possible sent [LCP ConfRej id=0x1 <auth pap>] rcvd [LCP ConfReq id=0x1 <asyncmap 0xa0000> <auth pap> <pcomp> <accomp>] No auth is possible sent [LCP ConfRej id=0x1 <auth pap>] sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x7ae02b5a> <pcomp> <accomp>] rcvd [LCP ConfReq id=0x1 <asyncmap 0xa0000> <auth pap> <pcomp> <accomp>] No auth is possible sent [LCP ConfRej id=0x1 <auth pap>] sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x7ae02b5a> <pcomp> <accomp>] rcvd [LCP ConfReq id=0x1 <asyncmap 0xa0000> <auth pap> <pcomp> <accomp>] No auth is possible sent [LCP ConfRej id=0x1 <auth pap>] sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x7ae02b5a> <pcomp> <accomp>] rcvd [LCP ConfReq id=0x1 <asyncmap 0xa0000> <auth pap> <pcomp> <accomp>] No auth is possible sent [LCP ConfRej id=0x1 <auth pap>] sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x7ae02b5a> <pcomp> <accomp>] rcvd [LCP ConfReq id=0x1 <asyncmap 0xa0000> <auth pap> <pcomp> <accomp>] No auth is possible sent [LCP ConfRej id=0x1 <auth pap>] sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x7ae02b5a> <pcomp> <accomp>] rcvd [LCP ConfReq id=0x1 <asyncmap 0xa0000> <auth pap> <pcomp> <accomp>] No auth is possible sent [LCP ConfRej id=0x1 <auth pap>] sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x7ae02b5a> <pcomp> <accomp>] rcvd [LCP ConfReq id=0x1 <asyncmap 0xa0000> <auth pap> <pcomp> <accomp>] No auth is possible sent [LCP ConfRej id=0x1 <auth pap>] sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x7ae02b5a> <pcomp> <accomp>] rcvd [LCP ConfReq id=0x1 <asyncmap 0xa0000> <auth pap> <pcomp> <accomp>] No auth is possible sent [LCP ConfRej id=0x1 <auth pap>] sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x7ae02b5a> <pcomp> <accomp>] rcvd [LCP ConfReq id=0x1 <asyncmap 0xa0000> <auth pap> <pcomp> <accomp>] No auth is possible sent [LCP ConfRej id=0x1 <auth pap>] sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x7ae02b5a> <pcomp> <accomp>] rcvd [LCP ConfReq id=0x1 <asyncmap 0xa0000> <auth pap> <pcomp> <accomp>] No auth is possible sent [LCP ConfRej id=0x1 <auth pap>] LCP: timeout sending Config-Requests Connection terminated. Modem hangup
解决方案是在pppd的脚本gprsdial中加上local选项,local的意思是不使用调制解调器的控制线路,pppd将会忽略载波检测。修改后的脚本内容如下:
# Usage: root>pppd call gprs /dev/ttyS3 115200 #crtscts modem noauth debug nodetach local #hide-password usepeerdns noipdefault defaultroute user "cmnet" 0.0.0.0:0.0.0.0
问题二:通过AT命令“ATD10001;”拨打电话时,模块返回“NO DIALTONE”,通过AT命令“ATD*99#”拨号进行数据连接时,模块返回“NO CARRIER”
原因:此问题是由于没有插天线,信号不好导致的。
问题三:2G的模块(sim800),用3G的SIM卡,能正常通信和拨打电话吗?
答案:可以。
问题四:ip-up:ppp拨号成功会,会调用这个脚本;
联网后,DNS不起作用!
可以在ip-up文件中添加设置DNS的命令,如下所示:
/system/bin/ndc resolver setifdns "$NAME" "$DNS1" "$DNS2" /system/bin/ndc resolver setdefaultif "$NAME"
调试过程中几个常用的AT命令:
AT+CSMINS? //查询是否插入SIM卡 AT+CSQ //查询信号质量 ATDxxxxxx; //拨打电话,命令尾一定要要分号
<pre class="plain" name="code">AT+CIMI //查询国际移动用户标识 AT+COPS? //查询运营商这两条命令均可以用于查询SIM卡是移动的还是联通的。
Android系统下增加自启动服务
首先,在init.rc脚本中增加pppd服务,实现开机自动拨号上网(但通常这一动作是由Android的RIL层触发的,函数为requestSetupDataCall())。Android中有专门的脚本init.gprs-pppd用于启动pppd,当然也可以自己写一个类似的脚本用于启动pppd服务。
service pppd /system/etc/ppp/init.gprs-pppd call gprsdial class main user root group radio cache inet misc service ril-daemon /system/bin/rild class main socket rild stream 660 root radio socket rild-debug stream 660 radio system user root group radio cache inet misc audio log service ril-daemon3 /system/bin/rild3 class main socket rild3 stream 660 root radio socket rild-debug stream 660 radio system user root group radio cache inet misc audio log
此步骤需要注意的是,pppd服务的class需要和rild服务的class保持一致。init.gprs-pppd脚本的内容如下:
#!/system/bin/sh # An unforunate wrapper script # so that the exit code of pppd may be retrieved # this is a workaround for issue #651747 #trap "/system/bin/sleep 1;exit 0" TERM PPPD_PID= /system/bin/setprop "net.gprs.ppp-exit" "" /system/bin/log -t pppd "Starting pppd" /system/bin/pppd $* PPPD_EXIT=$? PPPD_PID=$! /system/bin/log -t pppd "pppd exited with $PPPD_EXIT" /system/bin/setprop "net.gprs.ppp-exit" "$PPPD_EXIT"