织梦CMS - 轻松建站从此开始!

罗索

当前位置: 主页>老古董>『SMS』>

multiplexer protocol研究笔记

jackyhwei 发布于 2011-01-10 21:17 点击:次 
multiplexer protocol是GSM中比较重要的协议,在GSM 07.10中对该协议做了详细的描述。说它重要是因为它是衔接手机(TE)和模组(MS)之间的纽带,TE和MS通信,一般是通过一个串口进行,问题在于串口只有一个,而通信的数据类型却有很多种。
TAG:

导读:
multiplexer protocol是GSM中比较重要的协议,在GSM 07.10中对该协议做了详细的描述。说它重要是因为它是衔接手机(TE)和模组(MS)之间的纽带,TE和MS通信,一般是通过一个串口进行,问题在于串口只有一个,而通信的数据类型却有很多种。multiplexer protocol就是用来解决这个问题的:让不同类型的数据在一个串口上传输,而不至于发生紊乱。
multiplexer protocol研究笔记

转载时请注明出处:http://blog.csdn.net/absurd

multiplexer protocol是GSM中比较重要的协议,在GSM 07.10中对该协议做了详细的描述。说它重要是因为它是衔接手机(TE)和模组(MS)之间的纽带,TE和MS通信,一般是通过一个串口进行,问题在于串口只有一个,而通信的数据类型却有很多种。比如AT Command、voice、 fax、 data、 SMS、CBS、 phonebook、电量状态、GPRS和USSD 等等。如果传输时一个一个来,每种类型的数据都以独占的方式传输(比如在使用GPRS上网时,就不能接收/发送短信),虽然技术上可行,但是对用户来说不太友好。

multiplexer protocol就是用来解决这个问题的:让不同类型的数据在一个串口上传输,而不至于发生紊乱。想想我们的网卡,通常也只有一个,但可以用它来传输任何数据类型,可以用HTTP协议浏览网页,用FTP协议下载/上传文件,用即时通信协议聊天,这些事情同时进行,而不会发生任何干扰,这一切都是由TCP/IP这一系列的协议来保证的。

multiplexer protocol采用的方法是把一个串口模拟成多个串口,对上层应用程序来说,每一个虚拟的串口和普通串口几乎没有差别,只是每个虚拟串口都只能传输特定类型的数据。下面moto的定义:
VOICE_CALL "/dev/mux0"
SMS_MO "/dev/mux1"
SMS_MT "/dev/mux2"
PHONEBOOK "/dev/mux3"
MISC "/dev/mux4"
CSD "/dev/mux5"
GPRS1 "/dev/mux6"
GPRS2 "/dev/mux7"
CSD "/dev/mux8"
GPRS1 "/dev/mux9"
GPRS2 "/dev/mux10"
LOGGER_CMD "/dev/mux11"
LOGGER_DATA "/dev/mux12"
TEST_CMD "/dev/mux13"
AGPS "/dev/mux14"
NET_MONITOR "/dev/mux15"

多个虚拟串口上的数据最终要在一个串口上传输,所以需要用一个标识来区分它们,这就是Data Link Connection Identifier (DLCI)。其中DLC0比较特殊,它用于在MS和TE之间传递管理和控制数据包。比如建立其它DLCI、参数协商和退出multiplexer状态等等。

multiplexer protocol的协议栈如下:
l 最上层是应用层,应用层协议与具体应用有关,比如传递AT Command、Voice和GPRS数据,不同应用的协议是不一样的。
l 最下层是物理层,即串口协议,描述了诸如起始位,校验方式和速率等等。
l Multiplexer Layers: 传递字节流数据。
l Convergence Layers: 传递结构化数据。

具体如下图所示:

multiplexer protocol有三种工作模式:基本模式、不带错误恢复的高级模式和带错误恢复的高级模式。

multiplexer protocol定义了下面这些类型服务:
l Start up services 进入multiplexer模式。
l DLC establishment services 建立DLC连接,每个连接对应一个虚拟串口。
l Data services 传输数据。
l Power Control services 电源管理,进入睡眠和唤醒。
l DLC Release services 断开DLC连接。
l Close down services退出multiplexer模式。
l Control Services 控制服务,主要用于设置一些参数,比如超时时间,重传次数和速率等等。

基本协议数据单元(PDU)格式如下:
Flag Address Control Length Indicator Information FCS Flag
1 octet 1 octet 1 octet 1or2 octets Unspecified length but integral number of octets 1 octet 1 octet
前后的flag用来标识帧的起始和结束。
Address主要是DLCI,同时还一个c/r用来标识是命令还是命令的回应。
Length是数据的长度。
Information是实际传输的数据。
FCS是校验和,不同类型的帧的FCS计算方法不一样。
control是用来描述数据包类型的。其描述如下:
Frame Type 1 2 3 4 5 6 7 8 Notes
SABM (Set Asynchronous Balanced Mode) 1 1 1 1 P/F 1 0 0
UA (Unnumbered Acknowledgement) 1 1 0 0 P/F 1 1 0
DM (Disconnected Mode) 1 1 1 1 P/F 0 0 0
DISC (Disconnect) 1 1 0 0 P/F 0 1 0
UIH (Unnumbered Information with Header check) 1 1 1 1 P/F 1 1 1
UI (Unnumbered Information) 1 1 0 0 P/F 0 0 0 Optional

上述的PDU(short address/short length)在程序中表示如下:

  1. typedef struct
  2. __u8 ea:1; 
  3. __u8 cr:1; 
  4. __u8 d:1; 
  5. __u8 server_chn:5; 
  6. } __attribute__((packed)) address_field; 
  7.  
  8. typedef struct
  9. __u8 ea:1; 
  10. __u8 len:7; 
  11. } __attribute__((packed)) short_length; 
  12.  
  13. typedef struct
  14. address_field addr; 
  15. __u8 control; 
  16. short_length length; 
  17. } __attribute__((packed)) short_frame_head; 
  18.  
  19. typedef struct
  20. short_frame_head h; 
  21. __u8 data[0]; 
  22. } __attribute__((packed)) short_frame; 

在linux下虚拟串口,主要是实现一个tty_driver,和其它驱动程序一样,要实现诸如打开、关闭、读、写、控制等函数。下面我们看看数据的发送过程,也就是write函数的实现。

函数原型:

  1. static int mux_write(struct tty_struct * tty, int from_user, 
  2. const unsigned char *buf, int count) 

检查状态:

  1. dlci = tty2dlci[line]; 
  2. if( ts0710->dlci[0].state == FLOW_STOPPED ){ 
  3. TS0710_DEBUG("Flow stopped on all channels, returning zero /dev/mux%d\n", line); 
  4. return 0; 
  5. else if( ts0710->dlci[dlci].state == FLOW_STOPPED ){ 
  6. TS0710_DEBUG("Flow stopped, returning zero /dev/mux%d\n", line); 
  7. return 0; 
  8. else if( ts0710->dlci[dlci].state == CONNECTED ){ 

准备数据包:

  1. send_info->frame = d_buf; 
  2. queue_uih(send_info, c + 1, ts0710, dlci); 

发送数据包:

  1. mux_sched_send 
  2.  
  3. static void queue_uih(mux_send_struct *send_info, __u16 len, ts0710_con *ts0710, __u8 dlci) 
  4. __u32 size; 

长数据包:

  1. if (len >SHORT_PAYLOAD_SIZE) { 
  2. long_frame *l_pkt; 
  3.  
  4. size = sizeof(long_frame) + len + FCS_SIZE; 
  5. l_pkt = (long_frame *) (send_info->frame - sizeof(long_frame)); 
  6. set_uih_hdr((void*)l_pkt, dlci, len, ts0710->initiator); 
  7. l_pkt->data[len] = crc_calc((__u8*) l_pkt, LONG_CRC_CHECK); 
  8. send_info->frame = ( (__u8*)l_pkt ) - 1; 
  9. else { 

短数据包:

  1. short_frame *s_pkt; 
  2.  
  3. size = sizeof(short_frame) + len + FCS_SIZE; 
  4. s_pkt = (short_frame *) (send_info->frame - sizeof(short_frame)); 
  5. set_uih_hdr((void *)s_pkt, dlci, len, ts0710->initiator); 
  6. s_pkt->data[len] = crc_calc((__u8*) s_pkt, SHORT_CRC_CHECK); 
  7. send_info->frame = ( (__u8*)s_pkt ) - 1; 
  8. send_info->length = size; 
  9.  
  10. static void set_uih_hdr(short_frame *uih_pkt, __u8 dlci, __u32 len, __u8 cr) 
  11. uih_pkt->h.addr.ea = 1; 
  12. uih_pkt->h.addr.cr = cr; 
  13. uih_pkt->h.addr.d = dlci &0x1; 
  14. uih_pkt->h.addr.server_chn = dlci >>1; 
  15. uih_pkt->h.control = CLR_PF(UIH); /*奇怪:为什么不是SET_PF?*/ 
  16.  
  17. if (len >SHORT_PAYLOAD_SIZE) { 
  18. SET_LONG_LENGTH( ((long_frame*) uih_pkt)->h.length, len ); 
  19. else { 
  20. uih_pkt->h.length.ea = 1; 
  21. uih_pkt->h.length.len = len; 

Multiplexer是一个对称的协议,也就是说协议连接的双方是对等的,谁都可以发起请求,设置控制参数,或者断开连接(不过要注意应用层协议是非对等的)。

在GSM协议方面我完全是外行,花了两天时间,Multiplexer协议的基本原理差不多清楚了,但仍然有些细节不太明白,以后用的时候再说吧。欢迎大家和我交流。

注:
以上引用的代码源于Motorola的Multiplexer实现,版权归Motorola所有。
 

(absurd )
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201101/10739.html]
本文出处:CSDN博客 作者:absurd
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容