• multiplexer protocol研究笔记


    multiplexer protocol研究笔记

     

    转载时请注明出处和作者联系方式:http://blog.csdn.net/absurd

    作者联系方式:Li XianJing <xianjimli at hotmail dot com>

    更新时间:2006-12-19

     

    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: 传递结构化数据。

     

    具体如下图所示:

    muxlayer 

    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)在程序中表示如下:

    typedef struct{

      __u8 ea:1;

      __u8 cr:1;

      __u8 d:1;

      __u8 server_chn:5;

    } __attribute__((packed)) address_field;

     

    typedef struct{

      __u8  ea:1;

      __u8  len:7;

    } __attribute__((packed)) short_length;

     

    typedef struct{

      address_field addr;

      __u8 control;

      short_length length;

    } __attribute__((packed)) short_frame_head;

     

    typedef struct{

      short_frame_head h;

      __u8 data[0];

    } __attribute__((packed)) short_frame;

     

     

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

     

    函数原型:

    static int mux_write(struct tty_struct * tty, int from_user,

               const unsigned char *buf, int count)

     

    检查状态:

      dlci = tty2dlci[line];

      if( ts0710->dlci[0].state == FLOW_STOPPED ){

        TS0710_DEBUG("Flow stopped on all channels, returning zero /dev/mux%d/n", line);

        return 0;

      } else if( ts0710->dlci[dlci].state == FLOW_STOPPED ){

        TS0710_DEBUG("Flow stopped, returning zero /dev/mux%d/n", line);

        return 0;

      } else if( ts0710->dlci[dlci].state == CONNECTED ){

     

    准备数据包:

        send_info->frame = d_buf;

        queue_uih(send_info, c + 1, ts0710, dlci);

     

    发送数据包:

             mux_sched_send

     

    static void queue_uih(mux_send_struct *send_info, __u16 len, ts0710_con *ts0710, __u8 dlci)

    {

      __u32 size;

     

       长数据包:

      if (len > SHORT_PAYLOAD_SIZE) {

        long_frame *l_pkt;

     

        size = sizeof(long_frame) + len + FCS_SIZE;

        l_pkt = (long_frame *) (send_info->frame - sizeof(long_frame));

        set_uih_hdr((void*)l_pkt, dlci, len, ts0710->initiator);

        l_pkt->data[len] = crc_calc((__u8*) l_pkt, LONG_CRC_CHECK);

        send_info->frame = ( (__u8*)l_pkt ) - 1;

      } else {

       短数据包:

        short_frame *s_pkt;

     

        size = sizeof(short_frame) + len + FCS_SIZE;

        s_pkt = (short_frame *) (send_info->frame - sizeof(short_frame));

        set_uih_hdr((void *)s_pkt, dlci, len, ts0710->initiator);

        s_pkt->data[len] = crc_calc((__u8*) s_pkt, SHORT_CRC_CHECK);

        send_info->frame = ( (__u8*)s_pkt ) - 1;

      }

      send_info->length = size;

    }

     

    static void set_uih_hdr(short_frame *uih_pkt, __u8 dlci, __u32 len, __u8 cr)

    {

      uih_pkt->h.addr.ea = 1;

      uih_pkt->h.addr.cr = cr;

      uih_pkt->h.addr.d = dlci & 0x1;

      uih_pkt->h.addr.server_chn = dlci >> 1;

      uih_pkt->h.control = CLR_PF(UIH); /*奇怪:为什么不是SET_PF?*/

     

      if (len > SHORT_PAYLOAD_SIZE) {

        SET_LONG_LENGTH( ((long_frame*) uih_pkt)->h.length, len );

      } else {

        uih_pkt->h.length.ea = 1;

        uih_pkt->h.length.len = len;

      }

    }

     

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

     

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

     

    注:

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

    以上引用的数据源于GSM 07.10 version 7.1.0 Release 1998

     

    ~~end~~

  • 相关阅读:
    聊天的时间显示
    Android下Affinities和Task
    android Notification 的使用
    Android Notification使用及取消
    类似微信发图片的样式
    Delphi---TServerSocket和TClientSocket发送和接收大数据包
    使用拷贝文件测试(BufferedInputStream,FileInputStream)
    android-getTextSize返回值是以像素(px)为单位的,setTextSize()以sp为单位
    怎样成为PHP 方向的一个合格的架构师
    mac 查看某个文件夹下所有隐藏文件(夹)的大小
  • 原文地址:https://www.cnblogs.com/zhangyunlin/p/6167799.html
Copyright © 2020-2023  润新知