嵌入式系统经常需要具备无线上网的功能,但在有的应用场景中无法使用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"