GSM 07.10 MUX(multiplexer protocol)

GSM 07.10 MUX(multiplexer protocol)


multiplexer protocol是GSM中比较重要的协议,在GSM 07.10中对该协议做了详细的描述。它是衔接手机(TE(Terminal Equipment))和模组(MS(Mobile Station))之间的纽带,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的协议栈

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

在这里插入图片描述


MUX帧结构

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

multiplexer protocol定义了下面这些类型服务:

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

基本协议数据单元(PDU)格式如下:

FlagAddressControlLength IndicatorInformationFCSFlag
1 octet1 octet1 octet1 or 2 octetsUnspecified length but integral number of octets1 octet1 octet
  • Flag是帧开始与结尾的标记,占一个字节,是一个常量值,在Basic模式里为0x9F。一次可传输多个帧,上一帧的结尾标记可作为下一帧的开始标记;
  • Address占一个字节,3~8bit表示MUX通道编号,1bit是扩展位,固定为1,2bit标记当前是命令帧还是响应帧;
  • Ctrl占一个字节,表示数据包的类型,其中5bit是P/F位;
  • Len占一到两个字节,1bit是扩展位,如果内容字段长度小于0x7F,Len占一个字节,扩展位为1,内容长度占Len的2~8bit;
  • Information是实际传输的数据。
  • FCS 是校验字节,是Flag后面,Info前面内容的校验信息,如果是UI类型的帧,还包含Info部分,校验算法文档有给出;

Control是用来描述数据包类型的,其描述如下:

Frame Type12345678Notes
SABM (Set Asynchronous Balanced Mode 建立逻辑通道)1111P/F100-
UA (Unnumbered Acknowledgement 响应建立通道)1100P/F110-
DM (Disconnected Mode 响应取消逻辑通道)1111P/F000-
DISC (Disconnect 取消逻辑通道)1100P/F010-
UIH (Unnumbered Information with Header check)1111P/F111-
UI (Unnumbered Information)1100P/F000Optional

所有在TE和MS间传输的帧都是上面描述的结构,部分控制帧没有Info字段,用Ctrl表示帧类型,AT命令等数据内容通常使用UIH类型帧传输。

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


DLC的创建与释放流程

应用打开设备准备发送数据前,MUX驱动会阻塞在打开进程中,直到打开成功。MUX驱动在收到打开消息时,会向打开通道发送SABM帧,如果DLC0此时没有被打开,还会先在DLC0上执行一次打开操作,待DLC0打开成功后才允许打开别的DLC通道。

一般来说,CP侧收到SABM帧后会响应UA帧表示建立通道,AP收到UA帧再返回打开成功状态。关闭DLC时发送DISC帧,等待响应DM帧时表示DLC关闭成功。理论上打开与关闭是对等的,AP与CP侧都可以主动发起,但项目实现中只有AP可以发起打开与关闭,并且HSIC通道0固定运行MUX协议,不能被关掉。以下给出理论上DLC打开与关闭流程。
在这里插入图片描述

另外,MUX驱动中还支持一个MSC(Modem Status Command), PN(Port Negotiation)等,主要是AP与CP侧MUX驱动同步一些状态,参考协议文档了解具体信息。


文章转载于:
multiplexer protocol研究笔记
GSM 07.10 MUX 协议驱动解析

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值