前段時間做完一個是視頻數據傳輸終端,使用4G模塊撥號,接上攝像頭,當一個路由器來傳輸視頻信號;以及本身會帶一些遠程管理功能;當然這不是本文的重點;在此僅重點介紹4G撥號相關的內容,因爲從開發到上線到量產過程中,撥號穩定性一直是一個考驗;
設備使用的是openwrt系統,Ulong9300 LTE模塊,MiniPcie接口,其實就是usb;
首先介紹幾個相關的工具:
comgt:主要是發送AT指令以及讀取結果,非常輕量級,一個.c文件,支持多種語法,可以自行編寫配置腳本
pppd:3g ppp 協議撥號 工具,使用配置文件配置撥號參數:如APN,用戶名,斷線檢測週期等等
usbserial: usb轉tty驅動
option: usb轉tty驅動
Ndis: LTE撥號專有驅動,與usbserial虛擬成串口不同,ndis虛擬成網口,可以獲得更高的速率
下面根據使用流程一個一個做相關詳細介紹:
驅動:如果使用usbserial驅動,Linux Kernel自帶,無需配置,直接install即可;Option驅動同樣;
使用ndis驅動,需要LTE模塊廠家提供相關的驅動包,以及應用層撥號程序
pppd參數:主要是APN和Dialnumber,用戶名和密碼一般不需要;APN及Dialnumber 可以諮詢運營商,每個運營商固定的,不過地區不同也可能存在差別,尤其是現在IOT的M2M卡,專用卡等等。
可以通過SIM卡ICCID來判斷運營商類別,然後設定相關的APN和Dialnumber。參考comgt腳本如下:
:cimi
waitquiet 1 0.2
send "AT+CIMI^m"
waitfor 3 "46000" "46002" "46007" "46001" "46006" "46003" "46005" "46011"
if % = -1 goto err
if % = 0 goto cmnet
if % = 1 goto cmnet
if % = 2 goto cmnet
if % = 3 goto net3g
if % = 4 goto net3g
if % = 5 goto ctlte
if % = 6 goto ctlte
if % = 7 goto ctlte
# default
goto webset
:err
exit 1
:cmnet
send "AT+CGDCONT=1,\"IP\",\"CMNET\"^m"
print "CMNET\n"
goto waitret
:net3g
send "AT+CGDCONT=1,\"IP\",\"3GNET\"^m"
print "3GNET\n"
goto waitret
:ctlte
send "AT+CGDCONT=1,\"IP\",\"CTLTE\"^m"
print "CTLTE\n"
:waitret
openwrt撥號機制:
- hotplug,探測到lte usb拔插,系統通過hotplug自動調用pppd
- pppd設定配置,由procd進程來管理,自動啓動
- pppd主要撥號腳本爲3g.sh,參考內容爲:
#!/bin/sh [ -n "$INCLUDE_ONLY" ] || { NOT_INCLUDED=1 INCLUDE_ONLY=1 . ../netifd-proto.sh . ./ppp.sh init_proto "$@" } proto_3g_init_config() { no_device=1 available=1 ppp_generic_init_config proto_config_add_string "device:device" proto_config_add_string "apn" proto_config_add_string "service" proto_config_add_string "pincode" proto_config_add_string "dialnumber" proto_config_add_string "username" proto_config_add_string "password" proto_config_add_string "at_port" proto_config_add_string "private_dial" } proto_3g_setup() { local interface="$1" local chatcfg 。。。發送一些AT指令,如查詢SIM卡,信號質量,註冊的網絡等等,反正目的是爲了查詢保證撥號的條件 。。。 ppp_generic_setup "$interface" \ noaccomp \ ${username:+user "$username" password "$password"} \ nopcomp \ novj \ nobsdcomp \ noauth \ lock \ modem \ crtscts \ 115200 "$device" return 0 } proto_3g_teardown() { proto_kill_command "$interface" } [ -z "NOT_INCLUDED" ] || add_protocol 3g
- 撥號成功後調用腳本ppp-up
主要是設定主路由表並通知相關模塊;可以自行創建dialok等文件表示撥號成功,不需要再特別去查詢;這樣簡單方便;當然失敗時需要自行刪除文件。#!/bin/sh PPP_IPPARAM="$6" . /lib/netifd/netifd-proto.sh echo -n > /tmp/dialcount touch /tmp/dialok proto_init_update "$IFNAME" 1 1 proto_set_keep 1 [ -n "$PPP_IPPARAM" ] && { [ -n "$IPLOCAL" ] && proto_add_ipv4_address "$IPLOCAL" 32 "" "${IPREMOTE:-2.2.2.2}" [ -n "$IPREMOTE" ] && proto_add_ipv4_route 0.0.0.0 0 "$IPREMOTE" [ -n "$LLLOCAL" ] && proto_add_ipv6_address "$LLLOCAL" 128 [ -n "$DNS1" ] && proto_add_dns_server "$DNS1" [ -n "$DNS2" -a "$DNS1" != "$DNS2" ] && proto_add_dns_server "$DNS2" } proto_send_update "$PPP_IPPARAM" [ -d /etc/ppp/ip-up.d ] && { for SCRIPT in /etc/ppp/ip-up.d/* do [ -x "$SCRIPT" ] && "$SCRIPT" "$@" done } if [ -n "$AUTOIPV6" ]; then json_init json_add_string name "${PPP_IPPARAM}_6" json_add_string ifname "@$PPP_IPPARAM" json_add_string proto "dhcpv6" json_close_object ubus call network add_dynamic "$(json_dump)" fi
- 撥號由成功到失敗時運行腳本ppp-down
#!/bin/sh PPP_IPPARAM="$6" . /lib/netifd/netifd-proto.sh rm -f /tmp/dialok echo "$(date)- ppp down ###" >> /tmp/at_failed_ret proto_init_update "$IFNAME" 0 proto_send_update "$PPP_IPPARAM" [ -d /etc/ppp/ip-down.d ] && { for SCRIPT in /etc/ppp/ip-down.d/* do [ -x "$SCRIPT" ] && "$SCRIPT" "$@" done }
以上爲一次撥號流程;那麼如何保證24小時在線?就需要另外一套機制來保證;最簡單的就是輪詢了
openwrt 自帶crond,PC上使用廣泛的任務輪詢調度模塊,可以配置在幾點幾分周幾,間隔多久運行什麼程序,非常靈活;
本文設定每5分鐘檢測一次;檢測腳本如下:
#!/bin/sh
resetmodule()
{
echo Init > /tmp/sim-info
echo 0 > /tmp/sig
echo 1 > /sys/class/leds/modrst/brightness
echo "$(date)-repower-4g-module" >> /tmp/repower-4g-module
echo "$(date)-repower-4g-module" >> /tmp/at_failed_ret
sleep 5
echo 0 > /sys/class/leds/modrst/brightness
}
checkat()
{
# other process has do at-cmd
local num="$(ps |grep /etc/gcom |wc -l)"
[ $num -gt 1 ] && return 1
gcom -d "$1" -s /etc/gcom/checkpin.gcom > /tmp/sim-info
num="$(ps |grep /etc/gcom |wc -l)"
[ $num -gt 1 ] && return 1
gcom -d "$1" -s /etc/gcom/getstrength.gcom > /tmp/sig
num="$(ps |grep /etc/gcom |wc -l)"
[ $num -gt 1 ] && return 1
gcom -d "$1" -s /etc/gcom/check_status.gcom > /tmp/module_status_file
if cat /tmp/sim-info | grep -qi 'Ready'; then
[ ! -e "/tmp/sim_ready" ] && touch /tmp/sim_ready
# no dialing ; no 3g-ppp; sim-card ok
ifconfig 3g-ppp | grep -qi 'inet addr:' || /sbin/ifup ppp
elif ifconfig 3g-ppp | grep -qi 'inet addr:'; then
# no dialing; 3g-ppp ok' ; sim-card error; detecting error
echo Ready > /tmp/sim-info
[ ! -e "/tmp/sim_ready" ] && touch /tmp/sim_ready
else
logger -t ltecheck "Check:SIM-error and ppp failed"
echo "$(date)-SIM-error and ppp dial failed" >> /tmp/at_failed_ret
cat /tmp/module_status_file >> /tmp/at_failed_ret
rm -f /tmp/dialok
fi
}
rm -rf /tmp/gcom*
# ttyUSBx is not exist
[ ! -e "$1" ] && return 1
[ ! -e "/tmp/cfuncount" ] && echo -n > /tmp/cfuncount
[ ! -e "/tmp/dialcount" ] && echo -n > /tmp/dialcount
[ ! -e "/tmp/at_failed_ret" ] && echo -n > /tmp/at_failed_ret
num="$(cat /tmp/at_failed_ret | wc -l)"
if [ $num -ge 800 ]; then
echo -n > /tmp/at_failed_ret
fi
if [ -e "/tmp/dialok" ]; then
checkat "$1"
echo -n > /tmp/dialcount
echo -n > /tmp/cfuncount
else
ifdown ppp
sleep 5
num="$(cat /tmp/cfuncount | wc -l)"
if [ $num -ge 3 ]; then
logger -t ltecheck "cfuncount>3,to reset module"
#cfun=0
gcom -d "$1" -s /etc/gcom/clearcfun.gcom
echo -n > /tmp/dialcount
echo -n > /tmp/cfuncount
resetmodule
sleep 20
ifup ppp
else
num="$(cat /tmp/dialcount | wc -l)"
if [ $num -ge 5 ]; then
logger -t ltecheck "dialcount>5,to reset cfun"
gcom -d "$1" -s /etc/gcom/clearcfun.gcom
gcom -d "$1" -s /etc/gcom/setcfun.gcom
echo "$(date)-cfun-reset" >> /tmp/cfuncount
echo "$(date)-cfun-reset" >> /tmp/at_failed_ret
echo -n > /tmp/dialcount
ifup ppp
else
logger -t ltecheck "$(date) ppp redial"
echo "$(date) ppp redial" >> /tmp/at_failed_ret
cat /tmp/module_status_file >> /tmp/at_failed_ret
ifup ppp
fi
fi
fi
主要流程爲:
首先檢測dialok文件(由ppp-up創建)在不在,再繼續查詢AT,當然AT有可能查詢失敗,AT結果寫入tmp文件
然後判斷文件或文件內容,此處文件不一定可靠,因爲是人爲創建的,如果考慮的不全,文件該清除的時候沒清楚,該創建的時候沒創建的情況也是有的;因此文件不對時,再查詢一次系統實際情況,如ifconfig等,然後比較,即可判斷出實際情況;
關於resetmodule,爲什麼要reset模塊,因此模塊裏面也是系統也有程序,也是人寫的;而且網絡環境非常複雜,尤其在中國,因此模塊也有一定機率出錯,表現情況就是:AT一直失敗,撥號一直不成功等;此時,就需要reset模塊;一般來說有兩種方法,軟復位:設置CFUN,所有模塊通用;硬復位:通過控制模塊復位腳,需要硬件預先設計;
復位之後,模塊重啓,openwrt會自動檢測到模塊接入,然後執行撥號流程,如果沒有,那麼crond輪詢程序在超時後也會主動檢測一次;
理論上,crond可以保證永遠撥號;crond自身做的工作很少,其穩定性可以保證;
到此,基本介紹完畢;
後續可能的優化:不使用hotplug機制,不使用procd自動調用機制,純粹依靠crond來輪詢執行;雖然撥號過程慢一些,但穩定性更加的得到提升;