multiplexer protocol研究
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)在程序中表示如下:
| 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協議的基本原理差不多清楚了,但仍然有些細節不太明白,以后用的時候再說吧。歡迎大家和我交流。
?
注:
以上引用的代碼源于Motorola的Multiplexer實現,版權歸Motorola所有。
以上引用的數據源于GSM 07.10 version 7.1.0 Release 1998
?
~~end~~
總結
以上是生活随笔為你收集整理的multiplexer protocol研究的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 8个压箱底的资源网站,一个顶十个,再也不
- 下一篇: mysqladmin: Can't tu