Xavier's Blog
做更美好的自己
EC20
EC20 使用
EC20 上网
硬件描述: EC20 模块封装成标准的 PCIe 接口,和系统之家通讯主要通过 usb 通讯。 系统描述: 此处使用的是 Linux 3.0.1。
驱动支持
首先需要对 Linux 内核驱动做一定的修改,使操作系统能够支持 EC20。
Add VID add PID
File: [KERNEL]/drivers/usb/serial/option.c
static const struct usb_device_id option_ids[] = {
#if 1 //Added by Quectel
{ USB_DEVICE(0x05C6, 0x9090) }, /* Quectel UC15 */
{ USB_DEVICE(0x05C6, 0x9003) }, /* Quectel UC20 */
{ USB_DEVICE(0x05C6, 0x9215) }, /* Quectel EC20 */
{ USB_DEVICE(0x2C7C, 0x0125) }, /* Quectel EC25/EC20 R2.0 */
{ USB_DEVICE(0x2C7C, 0x0121) }, /* Quectel EC21 */
#endif
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD_LIGHT) },
Add the Zero Packet Mechanism
As required by the USB protocol, you need to add the mechanism for processing zero packets during bulkout transmission.
File: [KERNEL]/drivers/usb/serial/usb_wwan.c
static struct urb *usb_wwan_setup_urb(struct usb_serial *serial, int endpoint,
int dir, void *ctx, char *buf, int len,
void (*callback) (struct urb *))
{
struct urb *urb;
if (endpoint == -1)
return NULL; /* endpoint not needed */
urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
if (urb == NULL) {
dbg("%s: alloc for endpoint %d failed.", __func__, endpoint);
return NULL;
}
/* Fill URB using supplied data. */
usb_fill_bulk_urb(urb, serial->dev,
usb_sndbulkpipe(serial->dev, endpoint) | dir,
buf, len, callback, ctx);
#if 1 // 2017.3.7 add by zhaoxiaodong
if (dir == USB_DIR_OUT) {
struct usb_device_descriptor *desc = &serial->dev->descriptor;
if (desc->idVendor == cpu_to_le16(0x05C6) && desc->idProduct == cpu_to_le16(0x9090))
urb->transfer_flags |= URB_ZERO_PACKET;
if (desc->idVendor == cpu_to_le16(0x05C6) && desc->idProduct == cpu_to_le16(0x9003))
urb->transfer_flags |= URB_ZERO_PACKET;
if (desc->idVendor == cpu_to_le16(0x05C6) && desc->idProduct == cpu_to_le16(0x9215))
urb->transfer_flags |= URB_ZERO_PACKET;
if (desc->idVendor == cpu_to_le16(0x2C7C))
urb->transfer_flags |= URB_ZERO_PACKET;
}
#endif
return urb;
}
Add Reset Resume
Some USB host controllers/USB hubs will lost power or be reset when MCU entering into suspend/sleep mode, and they cannot resume USB devices when MCU exiting from suspend/sleep mode; instead, they will operate reset-resume. You should add the following statements.
For Linux Kernel Version newer than 3.4: File: [KERNEL]/drivers/usb/serial/option.c
static struct usb_serial_driver option_1port_device = {
……
#ifdef CONFIG_PM
.suspend = usb_wwan_suspend,
.resume = usb_wwan_resume,
#if 1 //Added by Quectel
.reset_resume = usb_wwan_resume,
#endif
#endif
};
For Linux Kernel Version older than 3.5: File: [KERNEL]/drivers/usb/serial/ usb-serial.c
static struct usb_driver usb_serial_driver = {
.name = "usbserial",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.suspend = usb_serial_suspend,
.resume = usb_serial_resume,
#if 1 // 2017.3.7 add by zhaoxiaodong
.reset_resume = usb_serial_resume,
#endif
.no_dynamic_id = 1,
.supports_autosuspend = 1,
};
Modify Kernel Configuration
Step 1:
cd <your kernel directory>
Step 2:
Set your environment variables, and import your board’s defconfig. The following is an example for Raspeberrypi board
export ARCH=arm
export CROSS_COMPILE=arm-none-linux-gnueabimake bcmrpi_defconfig
Step 3:
make menuconfig
Step 4:
Enable CONFIG_USB_SERIAL_OPTION
[*] Device Drivers →
[*] USB Support →
[*] USB Serial Converter support →
[*] USB driver for GSM and CDMA modems
Step 5: Configure Kernel to Support PPP
[*] Device Drivers →
[*] Network device support →
[*] PPP (point-to-point protocol) support
5. 编译内核
make
将编译好的内核下载到开发板。
模块测试
将重新编译好的内核下载到开发板之后,待系统重新启动,肉驱动添加正确,在 / dev / 目录下会出现如下设备节点:
/dev/ttyUSB0 /dev/ttyUSB1 /dev/ttyUSB2 /dev/ttyUSB3
EC20 的 AT 端口是 / dev/ttyUSB2,现在你可以使用 UART 端口工具如 “minicom” 或”busybox microcom”测试 AT 功能,结果如下:
#busybox microcom /dev/ttyUSB2
ati;+csub
Quectel
EC20F
Revision: EC20CEFDR02A09M4G
SubEdition: V04
OK
或者
cat /dev/ttyUSB2 & echo -e "AT+CGMI\r\n" >/dev/ttyUSB2
Quectel
OK
AT+CGMI
Quectel
OK
AT+CPIN?
拨号
方案一 通过几个不同的配置文件,在拨号的时候选择相应的配置文件,现将配置文件列举如下: 参考资料 https://linux.die.net/man/8/pppd
/etc/ppp/peers/quectel-ppp
# /etc/ppp/peers/quectel-pppd
# Usage:root>pppd call quectel-pppd
#Modem path, like /dev/ttyUSB3,/dev/ttyACM0, depend on your module, default path is /dev/ttyUSB3
/dev/ttyUSB3 115200
#Insert the username and password for authentication, default user and password are test
user "test" password "test"
# The chat script, customize your APN in this file
connect 'chat -s -v -f /etc/ppp/peers/quectel-chat-connect'
# The close script
disconnect 'chat -s -v -f /etc/ppp/peers/quectel-chat-disconnect'
# Hide password in debug messages
hide-password
# The phone is not required to authenticate
noauth
# Debug info from pppd
debug
# If you want to use the HSDPA link as your gateway
defaultroute
# pppd must not propose any IP address to the peer
noipdefault
# 使能一下两个选项可以实现ppp掉线自动重播
# lcp连接失败尝试次数
lcp-echo-failure 6
# lcp echo发送间隔
lcp-echo-interval 10
# No ppp compression
novj
novjccomp
noccp
ipcp-accept-local
ipcp-accept-remote
local
# For sanity, keep a lock on the serial line
lock
modem
dump
nodetach
# Hardware flow control
nocrtscts
remotename 3gppp
ipparam 3gppp
ipcp-max-failure 30
# Ask the peer for up to 2 DNS server addresses
usepeerdns
# 连接终止后不要退出,而是重新尝试连接,连接次数收到maxfail限制
persist
# 连接最大尝试次数,0无限制
#maxfail
/etc/ppp/peers/quectel-chat-connect
# /etc/ppp/peers/quectel-chat-connect
ABORT "BUSY"
ABORT "NO CARRIER"
ABORT "NO DIALTONE"
ABORT "ERROR"
ABORT "NO ANSWER"
TIMEOUT 30
"" AT
OK ATE0
OK ATI;+CSUB;+CSQ;+CPIN?;+COPS?;+CGREG?;&D2
# Insert the APN provided by your network operator, default apn is 3gnet
OK AT+CGDCONT=1,"IP","3gnet",,0,0
OK ATD*99#
CONNECT
/etc/ppp/peers/quectel-chat-disconnect
# /etc/ppp/peers/quectel-chat-disconnect
ABORT "ERROR"
ABORT "NO DIALTONE"
SAY "\nSending break to the modem\n"
"" +++
"" +++
"" +++
SAY "\nGoodbay\n"
/etc/ppp/peers/quectel-ppp-kill
#!/bin/sh
timeout=5
killall -15 pppd
sleep 1
killall -0 pppd
while [ $? -eq 0 ]
do
timeout=`expr $timeout - 1`
if [ $timeout -eq 0 ]
then
exit 1
fi
sleep 1
killall -0 pppd
done
if [ $? -ne 0 ]
then
killall -9 pppd
fi
ip-up脚本
之前的脚本如果没有问题,正常的话运行 pppd call gprs 就可以拨号成功,并且ifconfig后可以查看到ppp0这个网卡。但是如果你在拨号之前已经启用了以太网eth0,此时指定使用ppp0网卡ping指定ip或域名ping -I ppp0 www.baidu.com 并不能成功,原因有两个,一个是路由表中的默认网关是之前eth0生成的,一个是默认的dns服务器地址有问题。
解决默认网关问题
在pppd脚本中使能了defaultroute后,pppd会在拨号成功后向路由表中添加一条默认网关信息,但是因为之前已经有一条默认网关了,于是添加失败,默认网关依然是之前eth设置的,因此在pppd call gprs之前我们应该先route del default来删除默认路由(最好写个脚本来实现删除默认路由-拨号等一系列操作)。
或者将ppp0设置为默认路由。
先删除原来路由,route del default 再将ppp0设置为默认路由,route add default dev ppp0
如果不这样做,在我操作中ping 8.8.8.8是ping不通的,要指定网卡才能ping通,ping -I ppp0 8.8.8.8)
解决dns问题
在pppd脚本中使能了usepeerdns后,pppd会在拨号成功后,在/etc/ppp下生成resolv.conf,这是ISP运营商提供的dns,我们应该将拷贝或者连接到/etc目录下,当然这件事就可以交给ip-up来做。
#!/bin/bash
#ip-up
dns_file="/etc/resolv.conf"
rm "$dns_file"
ln /etc/ppp/resolv.conf "$dns_file"
#!/bin/sh
if [ -f /etc/ppp/resolv.conf ]; then
cp /etc/ppp/resolv.conf /etc/resolv.conf
elif [ -f /var/run/ppp/resolv.conf ]; then
cp /var/run/ppp/resolv.conf /etc/resolv.conf
else
echo nameserver $DNS1 > /etc/resolv.conf
echo nameserver $DNS2 >> /etc/resolv.conf
fi
ip-down脚本
按照ppp拨号过程中打印信息可以发现,在退出pppd进程时,会调用/etc/ppp/ip-down。因此删除默认网关,恢复dns就交由ip-down脚本做了。
#!/bin/bash
#ip-down
#set -vx
dns_file="/etc/resolv.conf"
rm $dns_file
cat > "$dns_file" <<EOF
# auto create by ip-down
nameserver 114.114.114.114
nameserver 8.8.8.8
EOF
chmod 755 "$dns_file"
/etc/init.d/networking restart
echo "Set dns for eth0"
编辑好这几个文件之后,便可以通过 pppd 进行拨号:
# pppd call quectel-ppp &
如果拨号成功会有以下信息打印出来:
[root@zx64352 peers]# pppd call quectel-ppp
pppd options in effect:
debug # (from /etc/ppp/peers/quectel-ppp)
nodetach # (from /etc/ppp/peers/quectel-ppp)
dump # (from /etc/ppp/peers/quectel-ppp)
noauth # (from /etc/ppp/peers/quectel-ppp)
user test # (from /etc/ppp/peers/quectel-ppp)
password ?????? # (from /etc/ppp/peers/quectel-ppp)
remotename 3gppp # (from /etc/ppp/peers/quectel-ppp)
/dev/ttyUSB3 # (from /etc/ppp/peers/quectel-ppp)
115200 # (from /etc/ppp/peers/quectel-ppp)
lock # (from /etc/ppp/peers/quectel-ppp)
connect chat -s -v -f /etc/ppp/peers/quectel-chat-connect # (from /etc/ppp/peers/quectel-ppp)
disconnect chat -s -v -f /etc/ppp/peers/quectel-chat-disconnect # (from /etc/ppp/peers/quectel-ppp)
nocrtscts # (from /etc/ppp/peers/quectel-ppp)
modem # (from /etc/ppp/peers/quectel-ppp)
hide-password # (from /etc/ppp/peers/quectel-ppp)
novj # (from /etc/ppp/peers/quectel-ppp)
novjccomp # (from /etc/ppp/peers/quectel-ppp)
ipcp-accept-local # (from /etc/ppp/peers/quectel-ppp)
ipcp-accept-remote # (from /etc/ppp/peers/quectel-ppp)
ipparam 3gppp # (from /etc/ppp/peers/quectel-ppp)
noipdefault # (from /etc/ppp/peers/quectel-ppp)
ipcp-max-failure 30 # (from /etc/ppp/peers/quectel-ppp)
defaultroute # (from /etc/ppp/peers/quectel-ppp)
usepeerdns # (from /etc/ppp/peers/quectel-ppp)
noccp # (from /etc/ppp/peers/quectel-ppp)
abort on (BUSY)
abort on (NO CARRIER)
abort on (NO DIALTONE)
abort on (ERROR)
abort on (NO ANSWER)
timeout set to 30 seconds
send (AT^M)
expect (OK)
AT^M^M
OK
-- got it
send (ATE0^M)
expect (OK)
^M
ATE0^M^M
OK
-- got it
send (ATI;+CSUB;+CSQ;+CPIN?;+COPS?;+CGREG?;&D2^M)
expect (OK)
^M
^M
Quectel^M
EC20F^M
Revision: EC20CEFDR02A09M4G^M
^M
SubEdition: V04^M
^M
+CSQ: 14,99^M
^M
+CPIN: READY^M
^M
+COPS: 0^M
^M
+CGREG: 0,0^M
^M
OK
-- got it
send (AT+CGDCONT=1,"IP","3gnet",,0,0^M)
expect (OK)
^M
^M
OK
-- got it
send (ATD*99#^M)
expect (CONNECT)
^M
^M
CONNECT
-- got it
Script chat -s -v -f /etc/ppp/peers/quectel-chat-connect finished (pid 785), status = 0x0
Serial connection established.
using channel 1
Using interface ppp0
Connect: ppp0 <--> /dev/ttyUSB3
sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x1f2b413> <pcomp> <accomp>]
rcvd [LCP ConfReq id=0x0 <asyncmap 0x0> <auth chap MD5> <magic 0xd11eadc2> <pcomp> <accomp>]
sent [LCP ConfAck id=0x0 <asyncmap 0x0> <auth chap MD5> <magic 0xd11eadc2> <pcomp> <accomp>]
rcvd [LCP ConfAck id=0x1 <asyncmap 0x0> <magic 0x1f2b413> <pcomp> <accomp>]
rcvd [LCP DiscReq id=0x1 magic=0xd11eadc2]
rcvd [CHAP Challenge id=0x1 <40aedf97298706e7675d614c0cea9175>, name = "UMTS_CHAP_SRVR"]
sent [CHAP Response id=0x1 <1bf312e7aa43615e474c49c28fbbaca5>, name = "test"]
rcvd [CHAP Success id=0x1 ""]
CHAP authentication succeeded
CHAP authentication succeeded
sent [IPCP ConfReq id=0x1 <addr 0.0.0.0> <ms-dns1 0.0.0.0> <ms-dns2 0.0.0.0>]
rcvd [IPCP ConfReq id=0x0]
sent [IPCP ConfNak id=0x0 <addr 0.0.0.0>]
rcvd [IPCP ConfNak id=0x1 <addr 10.35.149.45> <ms-dns1 218.4.4.4> <ms-dns2 218.2.2.2>]
sent [IPCP ConfReq id=0x2 <addr 10.35.149.45> <ms-dns1 218.4.4.4> <ms-dns2 218.2.2.2>]
rcvd [IPCP ConfReq id=0x1]
sent [IPCP ConfAck id=0x1]
rcvd [IPCP ConfAck id=0x2 <addr 10.35.149.45> <ms-dns1 218.4.4.4> <ms-dns2 218.2.2.2>]
Could not determine remote IP address: defaulting to 10.64.64.64
local IP address 10.35.149.45
remote IP address 10.64.64.64
primary DNS address 218.4.4.4
secondary DNS address 218.2.2.2
此时也会在 / etc/ppp / 目录下生成 resolv.conf 文件,存放 pppd 拨号获取到的 DNS,可以将改文件拷贝到 / etc / 目录下,这样便可以进行 DNS 解析了,至此开发板也可以通过 EC20 模块连接到互联网了。
方案二
方案一中的端口号、APN、用户名、密码等都是直接写在配置文件中,这样如果要更换这些内容的话要频繁修改配置文件,既消耗时间,又不太方便。所以便将几个配置文件融合到一个脚本中,并且可以通过传递参数那样修改需要修改的内容,脚本内容如下:
/etc/ppp/peers/quectel-pppd.sh
#!/bin/sh
#quectel-pppd devname apn user password
echo "quectel-pppd options in effect:"
QL_DEVNAME=/dev/ttyUSB3
QL_APN=3gnet
QL_USER=user
QL_PASSWORD=passwd
if [ $# -ge 1 ]; then
QL_DEVNAME=$1
echo "devname $QL_DEVNAME # (from command line)"
else
echo "devname $QL_DEVNAME # (default)"
fi
if [ $# -ge 2 ]; then
QL_APN=$2
echo "apn $QL_APN # (from command line)"
else
echo "apn $QL_APN # (default)"
fi
if [ $# -ge 3 ]; then
QL_USER=$3
echo "user $QL_USER # (from command line)"
else
echo "user $QL_USER # (default)"
fi
if [ $# -ge 4 ]; then
QL_PASSWORD=$4
echo "password $QL_PASSWORD # (from command line)"
else
echo "password $QL_PASSWORD # (default)"
fi
CONNECT="'chat -s -v ABORT BUSY ABORT \"NO CARRIER\" ABORT \"NO DIALTONE\" ABORT ERROR ABORT \"NO ANSWER\" TIMEOUT 30 \
\"\" AT OK ATE0 OK ATI\;+CSUB\;+CSQ\;+CPIN?\;+COPS?\;+CGREG?\;\&D2 \
OK AT+CGDCONT=1,\\\"IP\\\",\\\"$QL_APN\\\",,0,0 OK ATD*99# CONNECT'"
pppd $QL_DEVNAME 115200 user "$QL_USER" password "$QL_PASSWORD" \
connect "'$CONNECT'" \
disconnect 'chat -s -v ABORT ERROR ABORT "NO DIALTONE" SAY "\nSending break to the modem\n" "" +++ "" +++ "" +++ SAY "\nGood bay\n"' \
noauth debug defaultroute noipdefault novj novjccomp noccp ipcp-accept-local ipcp-accept-remote ipcp-max-configure 30 local lock modem dump nodetach nocrtscts usepeerdns
拨号
/etc/ppp/peers/quectel-pppd.sh &
``
输出信息跟方案一输出一样,同样会生成 / etc/ppp/resolv.conf 文件。
**注:** 在进行拨号之前一定要确保没有默认网关,如果已经设置了其他网卡的默认网关了,则 4G 模块没法正常上网,需要删除原来的默认网关,现以网卡 eth0 为例:
```sh
route del default
route del -host 255.255.255.255 dev eth0
各个运营商拨号上网设置
运营商(ISP) | APN | 拨号号码 | 账号 | 密码 |
---|---|---|---|---|
中国联通WCDMA(China Unicom)) | 3GNET | *99# | 空 | 空 |
中国电信CDMA2000(China Telecom) | 空 | #777 | ctnet@mycdma.cn | vnet.mobi |
中国移动 TD-SCDMA(China Mobile) | CMNET | *98*1# | 空 | 空 |
中国移动 CPRS(China Mobile) | CMNET | *99***1# | 空 | 空 |
验证模块通讯
设置模块ECHO OFF模式,并在后台持续输出/dev/ttyUSB2设备的信息。 echo -e “ATE0” > /dev/ttyUSB2 cat /dev/ttyUSB2 & echo -e “ATE1” > /dev/ttyUSB2
查看设备ID信息 echo -e “ATI” > /dev/ttyUSB2
查看设备的软件固件版本 echo -e “AT+GMR” > /dev/ttyUSB2
查看设备的IMEI编码 echo -e “AT+GSN” > /dev/ttyUSB2
查询当前SIM卡的运营商 cat /dev/ttyUSB2 & echo -e “AT+COPS?” > /dev/ttyUSB2
查询当前网络的信号质量 cat /dev/ttyUSB2 & echo -e “AT+CSQ” > /dev/ttyUSB2
使用如下命令进行 ppp 拨号(电信卡): sudo /home/pi/quectel-pppd.sh /dev/ttyUSB3 ctnet ctnet@mycdma.cn vnet.mobi 移动卡的拨号命令如下: sudo /home/pi/quectel-pppd.sh /dev/ttyUSB3 cmnet 联通卡的拨号命令如下: sudo /home/pi/quectel-pppd.sh /dev/ttyUSB3 wonet 命令后的三个参数分别是:拨号设备 APN username password