达是酒中趣,琴上偶然音

一只大疆 4G dongle,拆开发现里面跑着 Linux(一)

· Technology

下一篇:树莓派上的短信与 eSIM 网关

大疆有一个给无人机和遥控器用的 4G 配件,一只 U 盘大小的东西,插上 SIM 卡就能让设备联网。二手市场上很便宜。买它的人大多拿它当上网卡用。

把它插到电脑上,第一印象也确实就是个上网卡:macOS 什么反应都没有,Linux 冒出一排叫 ttyUSB0ttyUSB3 的设备。看上去乏善可陈。

但它里面其实是一台完整的 LTE 模组——跑着 Linux,有 root 权限的调试接口,能打电话、收发短信、读写 eSIM。接下来这个系列会把它接到树莓派、Mac、iPhone 和安卓平板上,让它真的当一部电话用。所有后面的东西,都建立在这一篇搞清楚的几件事上。

先解释两个词,后面会反复出现:

它到底是什么

先问它自己是谁:

ATI
Baiwang
QDC507
Revision: QDC507GLEFM21

查下来是这样一台东西:

项目
USB 标识(大疆版)2CA3:4006
USB 标识(通用版)2C7C:0125(和移远 EC25 系列同一个 ID)
基带芯片高通 MDM9607,Cat.4 LTE
模组内部系统Linux,内核 3.18.44,调试服务以 root 运行
AT 命令风格移远(Quectel)系,AT+QCFGAT+QNETDEVCTLAT+QGPS 这一套

这个发现很有用:网上关于移远 EC20/EC25 的资料基本都能套用——AT 命令、USB 配置、驱动都一样。大疆版和市面上的通用版在我们要用的功能上没有区别,后面统一叫它 QDC507。

插上去之后,究竟露出了什么

一个 USB 设备可以同时提供好几个”接口”,就像一根线里塞了好几条独立通道。模组露出哪几条,由一个叫 usbcfg 的配置决定:

AT+QCFG="usbcfg"
+QCFG: "usbcfg",0x2C7C,0x125,1,1,1,1,1,1,1
                             │ │ │ │ │ │ └─ USB 音频
                             │ │ │ │ │ └─── ADB
                             │ │ │ │ └───── 网卡
                             │ │ │ └─────── Modem
                             │ │ └───────── AT
                             │ └─────────── NMEA(GPS)
                             └───────────── DIAG(诊断)

最后两位是整个系列的钥匙。

ADB 开着,意味着可以像调试安卓手机那样 adb shell 进到模组里面的 Linux,而且直接就是 root。ADB 是安卓的调试桥,高通的模组普遍带着它。

音频开着,意味着模组会额外伪装成一块 USB 声卡。通话的声音将来就从这块声卡进出。

手上这只大疆版出厂就是两个都开。另一只通用版出厂是两个都关,需要先解锁:AT+QADBKEY? 会给一个 8 位挑战码,用 MD5-crypt 算出应答,再用 AT+QADBKEY="…" 提交,然后才能改 usbcfg。改完发 AT+CFUN=1,1 让模组重启,USB 会重新枚举一次,不用拔插。

还有一个细节,它决定了后面每个平台的命运:前五个接口都是 USB 厂商自定义类。USB 有一套标准分类(键盘是一类,U 盘是一类,声卡是一类),操作系统看到标准类就自动装驱动。厂商自定义类等于告诉系统”这是我自己的东西,你别管”。结果是:

平台能看到什么
Linuxoption 驱动认领这些接口,出现 ttyUSB0~3,网卡另有驱动认领
macOS没有任何驱动认领,所以 /dev/cu.* 里根本不会出现这只模组
Android同样没有驱动,App 只能用 USB Host API 自己去碰

也就是说,在 Mac 和安卓上,那条”发 AT 命令”的常规通道从一开始就不存在。

绕过去:模组内部有一条通道

既然外面没有串口,那就从里面走。adb shell 进去看看:

adb shell
# ls /dev/smd*
/dev/smd7 ...

/dev/smd7 是模组内部直通基带 AT 解释器的一个设备节点。只要 ADB 能用,任何平台都可以这样发 AT 命令:

adb shell "cat /dev/smd7 > /tmp/at.out 2>/dev/null & CP=\$!; sleep 0.3; \
  printf 'ATI\r' > /dev/smd7; sleep 2; kill \$CP 2>/dev/null; cat /tmp/at.out"

看着别扭,但它管用,而且它成了后来 Mac App 和安卓 App 共同的控制通道。一个没有驱动的平台,只要能说 ADB,就能完整指挥这只模组。

四种联网方式

模组怎么把网络交给主机,也是可配置的:

AT+QCFG="usbnet",N     改完要 AT+CFUN=1,1 重启生效
N模式LinuxmacOSAndroid
0QMI有驱动,但要自己拨号没有没有
1ECM有驱动直接出现一块网卡直接当 USB 以太网
2MBIM有驱动没有部分支持
3RNDIS有驱动没有部分支持

ECM 是这里面最省事的一个:模组自己做 NAT 和 DHCP,主机拿到一个 192.168.225.x 的地址,模组自己是 .1。插上就有网,什么都不用配。中国移动的卡还会直接下发原生 IPv6。

这个”省事”后面会变成一个麻烦,第五篇会讲到——它省事到你根本不知道自己的流量已经走了 SIM 卡。

拨通了,但没有声音

这是第一个真正让人困惑的地方。

ATD10086; 能拨出去,AT+CLCC 能查到通话处于接通状态,对面也确实接了——但两边都听不到任何声音。

原因是信令和声音是两套完全独立的东西。AT 命令负责信令:拨号、振铃、接通、挂断。声音走的是另一条路,而这条路默认是断的。

移远系列模组传统上有个 AT+QPCMV 命令,可以把通话音频从 USB 串口里吐出来。这个固件上它是个空壳:AT+QPCMV=? 说支持,真去执行 AT+QPCMV=1,0ERROR,而用 AT+CLAC 列出的 246 条可用命令里根本没有它。

真正的路径在模组内部:加载语音驱动,跑一遍音频校准,再启动一个桥接程序,把高通 DSP 里的通话音频接到那块 USB 声卡上。主机侧看到的,就是一块 8 kHz 单声道 16 bit 的声卡——电话音质的标准规格。

这条路细节很多,留到第四篇。这里只要记住一件事:ATD 只负责信令,声音要另外搭,而且每通电话之前都得检查一遍。

还有几个能力

刚上手就会撞到的五个坑

这些不是什么高深问题,但每一个都足够让人卡上大半天。

USB 序列号是 256 个 0xAA

现象:Mac 上 adb devices 明明能看到设备,但程序里发出去的所有 adb 命令都像石沉大海,没有任何输出。

原因:这个固件的 USB 序列号字段是 256 个字节的 0xAA,不是合法的 UTF-8 文本。Swift 的严格解码直接返回 nil,之后所有命令都带着一个空序列号,静默失败。

怎么办:解码要宽松。更重要的是,不要用序列号区分模组,因为每一只都一模一样。用 adb -t <transport_id> 寻址,用 USB 物理路径(比如 usb:1-1.2)作为持久身份——transport id 每次重新枚举都会变,USB 路径不会。

两只一样的模组分不清

同样的原因:Linux 上两只 2c7c:0125 也无法靠厂商 ID、产品 ID 或序列号区分。一次重新枚举之后,两只模组的 ttyUSB 编号整段互换,所有写死的路径同时失效。真正的解法是按物理端口写规则,第二篇给出具体写法。

adb forward 看起来成功,其实不通

adb forward tcp:PORT dev:/dev/smd7 能建立,返回也正常,但读写都没有任何数据。不要在它上面搭任何东西。

来电提示根本没发到你在读的地方

AT+QURCCFG="urcport"
+QURCCFG: "urcport","usbat"

模组主动上报的事件(RING 来电、+CLIP 来电号码、+CMTI 新短信)叫 URC,而这个配置说:URC 只发到 USB 的 AT 接口。

于是,通过 ADB 读 /dev/smd7 的程序永远收不到来电通知。你的代码没错,事件发到了另一扇门。

两个办法一起用:把 URC 端口改成 "all"(它是掉电保存的参数,先读再改,别每次启动都写);同时把轮询 AT+CLCC 和定期检查短信收件箱当作真正的事实来源,URC 只当”提醒你快去看一眼”。

AT+CFUN=1,1 会清空一切

这条命令重启模组。模组的 /tmp 是内存盘,重启后加载进去的语音驱动、校准标记、桥接进程全部消失,USB 也重新枚举一次。

结论是:任何”装一次就好了”的设计在这里都会失败。所有状态都必须做成每次检查、按需重建。这一条贯穿整个系列。

这一篇的结论

直觉实际
一个上网卡一台跑着 Linux、带 root 调试口的 LTE 模组
没有串口就没法控制adb shell 进去,走 /dev/smd7
拨通了就该有声音声音要在模组内部另外搭一条路由
来电会有提示提示发到了你没在读的那个端口

下一篇把它插到树莓派上,让它开始干活:收发短信、管理 eSIM、给局域网共享 4G。

全系列

  1. 它到底是什么
  2. 树莓派上的短信与 eSIM 网关
  3. 从零实现 VoWiFi
  4. USB 话机、浏览器通话与 ESP32
  5. 插在 Mac 上
  6. iPhone 客户端
  7. 安卓平板直接驱动

这个系列是个人学习和技术研究记录。模组的语音驱动是 GPL 衍生物,不随项目分发,需要自行准备。请遵守所在地法律法规和运营商服务条款。