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"