笔者之前在《使用EC20模块配合asterisk及freepbx实现短信转发和网络电话》里提到,EC20虽然能通过AT+QMBNCFG切换运营商配置,但模块内置的配置数量很少。以手上的EC20 R06为例,只有ROW、联通、电信和移动四份;另一台类似EG25的模块虽然有二十份,也没有一些香港运营商的volte配置。
这些运营商配置就是Qualcomm的MBN(Modem Configuration)。如果SIM需要的VoLTE参数不在固件里,且运营商不认ROW固件里的参数的话,单独执行AT+QCFG="ims",1并不能让模块强行注册VoLTE。于是笔者尝试从基带分支相近的高通手机固件中提取MBN,再通过模块正式支持的AT接口加入EC20/EG25。
确认EC20/EG25内置的MBN配置
查看模块现有的MBN:
AT+QMBNCFG="List"
笔者这台EC20 R06最初只有以下几列:
ROW_Generic_3GPP
OpenMkt-Commercial-CU
OpenMkt-Commercial-CT
Volte_OpenMkt-Commercial-CMCC
名字里有运营商并不代表一定支持该运营商的VoLTE。例如这里的联通OpenMkt-Commercial-CU其实是旧的CSFB配置,缺少完整IMS注册和Ut/XCAP参数。相反,通用的ROW_Generic_3GPP在这台EC20上反而可以注册联通IMS。
模块启动时会根据SIM的ICCID和PLMN自动选择一份MBN,然后把其中的NV、APN和运营商策略加载到基带。AT+QMBNCFG="List"中每一项的两个状态位分别是selected和activated:
+QMBNCFG: "List",0,1,1,"ROW_Generic_3GPP",...
只有1,1才表示这份配置已经在本次启动中实际生效。
找一台基带足够接近的手机
此处主要需要关注手机的几个特性:
- modem target,例如
9607_GEN或8937_GENNS(本质是高通骁龙430); - MPSS分支,例如
MPSS.JO.1.2或MPSS.JO.3.0; - MCFG格式。EC20 R06使用format 3,手机里的format 4配置即使能加入列表,也可能一直无法activated。
EC20 R06的基带属于9607_GEN / MPSS.JO.1.2.C1。顺着相邻的Qualcomm modem软件族,笔者检查了几台早期小米手机:
| 机型 | 代号 / SoC | Modem分支 | MCFG | 结果 |
|---|---|---|---|---|
| 红米4标准版 | prada / MSM8937 | MPSS.JO.1.2.C2 | 3 | 分支最近,但没有新版联通VoLTE |
| 红米3S/3X | land / MSM8937 | MPSS.JO.1.2.C4 | 3 | 同样缺少所需联通配置 |
| 红米4A | rolex / MSM8917 | MPSS.JO.1.2.C2 | 3 | 格式合适,但配置较旧 |
| 红米5A Android 7.1 | riva / MSM8917 | MPSS.JO.3.0 | 3 | 有联通CU_VoLTE和3HK等大量配置 |
| 红米5A Android 8.1 | riva / MSM8917 | MPSS.JO.3.1 | 4 | 可作参数参考,不适合直接给EC20 R06使用 |
选择小米主要是因为旧机型的firmware包容易下载,NON-HLOS.bin没有再套一层厂商专用封装,而且同一个包里保留了很多地区的Qualcomm MBN。红米5A V10.1.1.0里有90份可用于商用网络的format 3配置,即使小米没有在对应地区销售这台手机,其中仍然包括3HK、HKT、SmarTone、AT&T、T-Mobile、Verizon和许多欧洲运营商。不过需要注意的是,由于骁龙430是一个比较旧的平台(2015年发布),因此小米固件的最后一次更新集中在2019年左右,对应的mbn也是那个时代的。
下载固件并提取MBN
小米旧固件可以从Xiaomi Firmware Updater下载。本文最后采用的是红米5A国行V10.1.1.0:
fw_riva_miui_HM5A_V10.1.1.0.NCKCNFI_2e5ec8a9df_7.1.zip
解压出NON-HLOS.bin:
unzip fw_riva_miui_HM5A_V10.1.1.0.NCKCNFI_2e5ec8a9df_7.1.zip \
firmware-update/NON-HLOS.bin
这份文件本身是FAT文件系统,在Linux上可以只读挂载:
sudo mkdir -p /mnt/riva-modem
sudo mount -o loop,ro firmware-update/NON-HLOS.bin /mnt/riva-modem
运营商配置位于:
/mnt/riva-modem/image/modem_pr/mcfg/configs/mcfg_sw/generic/
例如联通和3HK分别是:
CHINA/CU/COMMERCI/VOLTE_OP/MCFG_SW.MBN
SEA/3HK/VOLTE/HK/MCFG_SW.MBN
还可以先从镜像确认MPSS版本:
strings -a firmware-update/NON-HLOS.bin \
| grep -m1 -E 'MPSS\.(JO|TA).*(GEN|PACK)'
笔者使用了mbn-mcfg-tools检查内部哈希和MCFG metadata:
mbn-tool -c MCFG_SW.MBN
mbn-tool -e MCFG_SW.MBN extracted-mbn
在提取后,最好在extracted-mbn/meta里确认以下的metadata之后才能安全加入EC20:
format_type与模块兼容;operator是预期的运营商;- ICCID和MCC/MNC匹配自己的SIM;
- MBN内部哈希检查通过。
这次得到的两个例子为:
| 运营商 | MBN名称 | 版本 | 匹配 |
|---|---|---|---|
| 中国联通 | CU_VoLTE | 0x0501154B | 460-01/06/09 |
| 3HK | 3HK_HongKong | 0x0501360D | 454-03 |
把MBN加入EC20/EG25
上传前先停掉会占用AT串口的Asterisk或ModemManager,并记录原始状态:
ATI
AT+QMBNCFG="List"
AT+QMBNCFG="AutoSel"
AT+QCFG="ims"
AT+COPS?
AT+QNWINFO
AT+CGDCONT?
AT+CGACT?
Quectel提供了QFUPL,可以直接把文件上传到模块RAM:
AT+QFUPL="RAM:carrier.mbn",<文件字节数>,60
CONNECT
<立即发送原始MBN二进制,不能经过文本转换>
+QFUPL: <文件字节数>,<校验值>
OK
这一段适合用pyserial写一个小脚本完成:先发送QFUPL,收到CONNECT后写入文件的全部原始字节,再等待+QFUPL和OK。上传完成后加入MBN:
AT+QMBNCFG="Add","RAM:carrier.mbn"
AT+QMBNCFG="List"
RAM:里的上传文件重启后会消失,因此要在重启前执行Add;加入MBN列表后的配置会持久保存。
第一次测试建议关闭自动选择,手工指定刚加入的配置:
AT+QMBNCFG="AutoSel",0
AT+QMBNCFG="Select","3HK_HongKong"
AT+QCFG="ims",1
AT+CFUN=1,1
Select之后列表通常先显示1,0,重启并等待基带重新上线后才应变成1,1。确认候选可以稳定激活后,如果它的ICCID/PLMN规则正确,就可以重新打开自动选择:
AT+QMBNCFG="AutoSel",1
AT+CFUN=1,1
笔者在3HK配置上没有手工执行Select,只保留AutoSel=1并重启,模块就自动把3HK_HongKong设为selected和activated,说明自动匹配规则有效。
确认VoLTE是否真的注册
首先,我们需要确认配置已经激活:
AT+QMBNCFG="List"
+QMBNCFG: "List",20,1,1,"3HK_HongKong",0x0501360D,...
然后查看MBN是否确实写入了运营商APN,并检查IMS bearer:
AT+CGDCONT?
AT+CGACT?
AT+CGPADDR
以3HK配置为例,模块建立了ims.lte.three.com.hk bearer并取得IP地址。这证明MBN已经执行到IMS承载这一层,但仍不等于IMS注册成功。
最后检查:
AT+QCFG="ims"
结果的含义为:
+QCFG: "ims",1,1 IMS已启用并且已经注册
+QCFG: "ims",1,0 IMS已启用,但没有注册
只有第二个值为1,才能认为IMS真正注册成功。最好再拨打一通电话,确认通话期间仍保持LTE并有双向语音。
这次测试中,红米5A的3HK MBN可以在QDC507/类似EG25模块上自动激活,也可以建立IMS bearer,但由于SIM当时在境外漫游,而且账户可能没有有效语音套餐,IMS仍是1,0。因此可以确认MBN与模块兼容,但没法据此确认3HK VoLTE已经开通。
联通CU_VoLTE也能在EC20 R06上selected+activated并写入APN,但跨MPSS.JO.3.0到JO.1.2后没有建立IMS注册。
不再使用时删除MBN
先切回已知可用的ROW并重启:
AT+QMBNCFG="AutoSel",0
AT+QMBNCFG="Select","ROW_Generic_3GPP"
AT+CFUN=1,1
等待模块恢复后确认ROW为1,1,再删除候选:
AT+QMBNCFG="Delete","3HK_HongKong"
AT+QMBNCFG="List"
最后把AutoSel和IMS设置恢复成测试前记录的值,而不是固定照抄某个值:
AT+QMBNCFG="AutoSel",<原值>
AT+QCFG="ims",<原值>
还要注意,两个MBN如果使用相同carrier ID,后加入的高版本可能替换原来的配置。删除候选后,旧配置不一定自动回来,因此测试前最好从原始固件保留一份原MBN,以便重新Add。
总结
EC20/EG25的VoLTE支持不完全由AT+QCFG="ims"的开关决定,MBN里还包含大量运营商专用参数。在寻找候选时,我们应优先匹配modem target、MPSS分支和MCFG格式,再考虑运营商名称。由于旧款小米高通手机的firmware比较容易取得,所以笔者在本文中以它作为例子,读者也可以根据实际情况,提取适用于自己的运营商的手机的固件(但最好需要使用Soc是MSM8937或者高通X6基带的Soc)。其中红米5A Android 7.1的format 3配置库尤其适合作为EC20/EG25的候选来源。
不过MBN只能解决终端配置这一部分。最终能否注册IMS,还取决于基带兼容性、SIM账户的VoLTE权限、归属或漫游网络、运营商认证和网络侧策略。判断成功的标准始终是AT+QCFG="ims"返回1,1并完成实际VoLTE通话。