摘要:
在Linux上使用不带GPRS协议栈的GSM模块,很容易会陷入僵局:无法使用pppd的同时又发送AT指令
给模块。此文从此角度出发,着手解决问题。
应用:
Modem--MCU使用PPP连接(DUP)发送数据编码。MCU需要频繁的检查模块的状态,包括:模块信号强度,检查短信和发送短信等等
常用解决办法
通常完成任务,需要使用以下技术:
•当有数据需要传送时,建立PPP连接(DUN)。检测模块状态时,断开PPP连接,释放COM端口。在检测完模块状态以后,重新建立PPP连接,发送数据。
•使用CMUX 串口复用,一路做PPP连接,一路输入at 指令。这需要在MCU和MODEM中加入CMUX协议。
第一种解决方法频繁的断开/连接将增大不稳定的可能性,通常DUN需要几秒时间才能正常连接。
Instead of requiring separate physical interfaces to manage different data communication technologies, CMUX provides a virtualized communication interface. A virtual communication port consists of placing a layer of abstraction between hardware units and the software running on them, abstracting available system resources from a single physical unit and making it act as multiple, independent logical entities.
通过多路复用协议和GSM模组通讯,使得可以在通过GPRS拨号上网时可以同时拨打电话和收发短信。
在网上无意中发现了motorola的多路复用实现,看了一下,觉得不大好:
motorola在linux下实现多路复用协议的方法是通过实现一个内核模块,在该内核模块实现了多路复用协议,并创建了多个tty设备给用户空间的程序使用,每个tty设备是多路复用的一个虚拟通路。这样MMI后台可以使用不同的tty设备实现和GSM模组的多路通讯。这种方法在使用上有几个不好的地方:
A. 首先是将其实现为一个内核模块,增加了编译时的麻烦,
B. 当内核升级后,该内核模块就无法编译通过了,需要修改源代码。
C. 不好查看打印信息,只有控制台才能看到内核模块的打印信息,在远程登录的终端上是看不到的,而远程登录是常用的工作方式。
D. 不好控制模组的激活和关闭,多路复用的内核模块和用户空间的进程(MMI后台)通讯不方便。
看来在用户空间实现多路复用协议,并将其实现为一个独立的后台进程倒是一个不错的方法。但如何在用户空间实现一个tty设备呢,可以用伪终端技术来实现。
伪终端是BSD UNIX提出并实现的一个虚拟终端设备的技术,其特点是可以在用户空间创建一个虚拟tty设备,供其他使用tty设备的进程使用,使该进程认为是和真实的tty设备交互,实际上却可能是通过网络接口和远程计算机通讯。
伪终端技术通过在内核实现虚拟设备向用户空间提供了一对伪终端设备,分别是伪终端主设备和伪终端从设备。伪终端从设备就是虚拟tty设备,伪终端主设备则由实际的通讯进程使用,可以是socket通讯进程,串口通讯进程。使用tty设备的进程向伪终端从设备写入的数据,则可以从伪终端主设备读到,实际的通讯进程向伪终端主设备写入的数据,则可以从伪终端从设备读到,从而实现了将一个实际的网络通讯伪装为与tty设备的通讯。
伪终端的使用步骤如下所示。
int fdm fds;/* master , slave*/
char *slavename;
extern char *ptsname();
fdm = open("/dev/ptmx", O_RDWR); /* open master */
grantpt(fdm); /* change permission of slave */
unlockpt(fdm); /* unlock slave */
slavename = ptsname(fdm); /* get name of slave */
fds = open(slavename, O_RDWR); /* open slave */
ioctl(fds, I_PUSH, "ptem"); /* push ptem */
ioctl(fds, I_PUSH, "ldterm"); /* push ldterm */
通过函数open()打开设备“/dev/ptmx”,可以得到一对伪终端的主从设备,得到的fd是主设备的文件描述符,从设备的设备名可以通过函数ptsname()得到,用open()函数打开从设备名的设备,即可得到从设备的文件描述符。但此时从设备还不能打开,需要调用函数grantpt()接受从设备,修改从设备的访问权限,调用函数unlockpt()解锁从设备,才能够打开从设备。ptsname(),grantpt(),unlockpt()这几个函数的具体作用大家可以通过man命令查看。
因此,可以创建一个实现了多路复用协议的独立后台进程,由其为每个虚拟串口创建一个虚拟tty设备,供MMI后台和PPPD进程使用。MMI后台和PPD进程使用不同的虚拟tty设备,以实现同时进行GPRS拨号上网和拨打电话、收发短信的功能。
具体做法是:
a) 多路复用的后台进程通过三次打开“/dev/ptmx”设备,得到三对伪终端的主从设备
b) 然后调用函数grantpt()和unlockpt()使得从设备可用,
c) 通过函数ptsname()得到从设备的设备名。
d) 在指定的虚拟tty设备名和实际得到的从设备名之间建立一个符号链接,MMI后台和PPPD进程就可以打开指定的虚拟tty设备通过多路复用协议和模组进行通讯了。
具体的实现方法和代码可以参考链接。
参考文档:
1.伪终端驱动-ptm和pts,Pseudo-tty drivers -- ptm and pts
2.多路复用协议的实现,http://developer.berlios.de/projects/gsmmux/
3.用gsmmux 测试via cdma多路复用功能 http://blog.lytsing.org/archives/33.html
参考代码
1.http://download.csdn.net/detail/zanget/3945662
2.http://download.csdn.net/detail/zanget/3945627