2011年5月16日星期一

  深入学习gsm/gprs源代码系列一:mac_gsm.cpp

平时打手机,用手机上网用的最多的就是2G/2.5G的gsm和gprs。究竟有多少人知道这个GSM/GPRS协议栈是如何工作的?

现在3G:WCDMA/CDMA2000/TDSCDMA等3G技术,即UMTS越来越扮演者重要的角色。但是究竟有多少人知道原来UMTS的数据传输除了空中接口即,a-bis接口发生了巨大变化外,其他的协议部分整体上是与GSM/GPRS,尤其是GPRS很相近的。

大家都学过TCP/IP协议栈,都知道MAC/IP/TCP+UDP/APP的协议结构。但是未来越来越重要的移动通信的基础的协议栈有谁留意过吗?

TCP/IP有开源的源代码,而GSM/GPRS的源代码可是有着非常强的版权保护的。我们都知道MTK是中国山寨的鼻祖,他家的核心技术之一当然就是通信芯片,而通信芯片中的核心当然就是协议栈啦,而他家的协议栈据我了解其实是英国CCWW公司授权的,也就是从外国人那里买过来的源代码,跟高通卖CDMA的方式差不多啦。

我们有没有必要深入的学习一下GSM/GPRS这个已经似乎有点过时的协议栈呢?我想现在很多喜欢操作系统的同学一定知道当今的Linux2.6和Linux0.1之间的血脉关系吧:虽然基本全变了(我们的GSM/GPRS和如今的UMTS可不是基本全变啊~),但是其哲学原理还是一样的(强烈推荐《操作系统之哲学原理》这本书,看的热血沸腾哦)

因为兴趣,因为项目的原因,我将会努力的把这个系列写完,为了鞭策自己,也可以给大家学习提供一些小小的参考。

这个系列和关于GSM/GPRS的教科书最大的区别就是完全以源代码为主线,而已经被国内外的无数教材和标准规范写烂了的内容,这里就会尽量少的设计。这个系列不是一个GSM/GPRS的入门读物,最开始的形式我尽可能的写的通俗易懂、由浅入深,从整体到局部,从概念到原理。但是这个总归是我的学习过程的一个小的总结和抽象,以为个人的背景知识不同,可能理解的程度也不同,我写的有不好的地方,请大家多多包涵。如果有什么问题,当然希望一起讨论,留言我会一一回复的。

各位看官,因为我们的重点是源代码,而商用的GSM/GPRS代码又是有版权的,而且现如今,除了OpenBTS这个开源的基站端协议栈有源代码外,我们没有可以参考的商用代码。但是,我们不是有协议方针工具吗,庆幸的是,我手头上有一份可以参考的部分GSM源代码。这个GSM源代码包括MS端和BS端,实现了大部分的功能。可以在协议方针工具中正确的运行。因此,我就以此套代码为基础,来一层一层的剖析这个GSM源代码,然后一点一点的过渡到GPRS上去。

好,废话不多说了。让我开始吧:

源代码包括:

cellular_gsm.h layer3_gsm.h mac_gsm.h phy_gsm.h Layer3_gsm.cpp mac_gsm.cpp phy_gsm.cpp

我们先从mac_gsm.cpp开始

mac_gsm.cpp

首先分析mac_gsm.cpp就不得不要先看一下mac.cpp,mac.cpp我们所使用的协议仿真软件中用来实现mac层的源文件。因为GSM协议只是这个协议方针软件中的一种MAC层协议而已,而为了我们未来要添加实现自己的GPRS协议栈,我们非常有必要看一看这个mac.cpp文件。

学习这个mac.cpp文件的目的是要知道在mac_gsm.cpp中的那些函数:初始化函数,分配器,从上下层接收数据,以及其他的由mac.cpp调用的函数是如何在mac.cpp中组织的。

在mac.cpp中: 1 头文件

要包含mac_gsm.h,这里面定义了一些结构,所以当添加自己的mac协议时,也要添加相应的一个头文件。

clip_image002

2 IPv4AddressToHWAddress

这个函数是将IP地址转换成MacHWAddress

clip_image004

clip_image006

clip_image008

其中MAC_PROTOCOL_GSM这个宏常量是在mac.h中定义的

clip_image010

所以,如果要添加自己的协议,也要在这里添加一个常量

3 MacConfigureHWAddress

clip_image012

这里表示如果macProtocolName==GSM的话,就使用MAC_SetFourByteMacAddress,也就是使用4个字节的MAC地址

clip_image014

3 AddNodeToSubnet

clip_image016

这个AddNodeToSubnet函数很长,我们来从总体上分析一下这个函数:

从结构上来看:

最前面的部分是对个别的几个协议进行特殊地处理

然后从这里开始:

clip_image018

开始初始化这些协议

PHY-MODEL

一直到这里:下面出现的协议需要一个PHY模型

clip_image020

显示做一下需要的预处理功能

然后开始处理各个协议:

clip_image022

总体上分为两部分:FCSC-一部分,非FSCS一部分。我们的GSM需要的PHY MODEL就属于这个非FSCS中的一部分:

clip_image024

所以,如果添加一个类似GSM的协议,这里应当也要填上一个对应的处理项

到这里:需要添加PHY MODEL就完了,简短的做一下下一步的预处理,然后正是开始一个一个处理协议:根据macProtocolName,让相应的mac 层协议进行初始化

clip_image026

我关注的GSM的初始化在这里:

clip_image028

其中重点是MacGsmInit(node,interfaceIndex,nodeInput,nodesInSubnet),这个函数定义在mac_gsm.cpp中

4 AddNodeToIpv6Network

这里的情况和AddNodeToSubnet差不多,只不过是Ipv6版本的。

也是有一个处理PHY-MODEL:

clip_image030

然后初始化mac 层协议:

clip_image032

5 ProcessLinkLine:

clip_image034

这个函数中也出现了GSM相关的配置:

clip_image036

#暂不知道用途

6 ProcessSubnetLine

clip_image038

这里也出现了GSM相关的配置:

clip_image040

#暂不知道用途

6 MAC_processEvent

用来模拟MAC层收到消息时的行为

clip_image042

调用MAC_PROTOCOL_GSM时的分配器,将调用的结点,结点中的接口索引号,和消息传给GSM MAC层的分配器:GacGsmLayer,在mac_gsm中定义

clip_image044

7 MAC_NetworkLayerHasPacketToSend

当网络层队列为空时,处理从网络层来的数据包

clip_image046

调用mac_gsm.cpp中定义的GSM协议对应的处理函数

clip_image048

在进一步跟进MacGsmNetworkLayerHasPacketToSend()函数到mac_gsm.cpp中时,发现这个函数是个空的:

clip_image050

#悬疑

8 MAC_ReceivePacketFromPhy

clip_image052

在这个函数里,调用mac_gsm.cpp中定义的MacGsmReceivePacketFromPhy

clip_image054

9 MAC_ReceivePhyStatusChangeNotificatio

clip_image056

调用mac_gsm.cpp中定义的MacGsmReceivePhyStatusChangeNotification()

clip_image058

10 MAC_Finalize

clip_image060

调用GSM的finalize函数

clip_image062

11 MAC_IsWirelessNetwork

clip_image064

如果是MAC_PROTOCOL_GSM,那么此函数就返回true

clip_image066

12 MAC_IsOneHopBroadcastNetwork

clip_image068

clip_image070

 

上面就是mac.cpp中使用的有关GSM的函数,我们接下来进入mac_gsm.cpp来深入的看看。

在mac_gsm.cpp中

一共就3500行代码,看看我如何将它分解,分而治之

1 MacGsmInit

clip_image072

函数定义:

本函数用来初始化MS和BS的MAC层

输入参数为:

1 需要被初始化地结点
2 输入的config文件

函数的行为:

1 先定义一些需要用的变量

clip_image074

2 为MacDataGsm结构体gsm分配内存空间,使用MEM_malloc,这个由QualNet提供的main.h中声明。估计这是封装了普通的内存分配,然后更好的防治内存泄露等问题。

clip_image076

3 调用ctoa( getSimTime( node ),clockStr ); ctoa()和getSimTime()都在QualNet提供的clock.h中声明。还不知道这个的作用

clip_image078

4 然后是打印一则调试信息,这里使用了一个小技巧:通过宏来控制打印不同级别的调试信息:

clip_image080

5 初始化gsm,这里遵守的是何时使用合适初始化

clip_image082

6 初始化随机数,具体的作用现在还不解:

clip_image084

RANDOM_SetSeed()在QualNet提供的Random.cpp中定义

7 初始化wasFound变量,这个变量用来检查后面读入配置文件是否正常返回。

clip_image086

8 读入配置文件并判断是否正常返回,否则抛出异常:

clip_image088

这里IO_ReadString()在QualNet提供的Fileio.h中提供

ERROR_Assert()则在QualNet_error.h中声明。

这种用法在《系统程序员成长计划》有所描述。大概就是说:如果用错误的参数测试,期望assert被触发,但如果assert被触发了,自动程序测试就死掉了,一旦自动测试程序死掉,就无法继续验证下一个assert了。为了解决这个悖论,我从glib里面学了一招,在检查时不用assert,而只是打印出一个警告,代码也很简明,按它的方式,我这样检查:

return_val_if_fail(cursor !=NULL, DLIST_RET_INVALID_PARAMS);

我需要定义一个宏:

#define return_val_if_fail(p,ret) if(!(p)) \
{printf("%s:%d Warning: "#p" failed. \n", __func__,__LINE__);return (ret);}

这样一来,遇到无效参数时,我们可以看到一个警告信息,同时又不会影响自动测试

9 接下来是重点,本函数会根据varStrValue的值,分三种情况进行处理

A GSM-MS
B GSM-BS
C GSM-MSC

我会进一步分析其中的内容,稍后

10 调用MacGsmInitStats( node,nodeInput,interfaceIndex ); 这个函数也在mac_gsm.cpp中定义。
应该是初始化统计信息用的函数,这个函数很短,这里就看一下:

clip_image090

 

我们接下来针对MS端地MAC层初始化,更进一步的来看一下初始化过程

varStrValue == GSM-MS

1 声明一个MacGsmMsInfo的指针 msInfo

2 打印调试信息:Node x: GSM_MS

3 设置结构体MacDataGsm gsm中的一些变量:

gsm->nodeType
gsm->msInfo

为其分配一个MacGsmMsInfo结构体大小的空间,然后初始化为0

msInfo->downlinkControlChannelIndex ;int
msInfo->cellSelectionTimer ;Message指针

4 读入GSM-CONTROL-CHANNEL,根据读入的信息,初始化:

msInfo->numControlChannels ;int
msInfo->controlChannels ;short []

5 初始化

msInfo->numBcchChannels ;int
msInfo->nextBcchChannelToListen ;int

6 初始化,

msInfo->bcchList[] ;GsmBcchListEntry []

7 调用MacGsmMsStartListeningToBcchListChannels( node, gsm );

此函数在mac_gsm.cpp中定义

让MS开始根据配置文件中定的BCCH信道上侦听

clip_image092

8 初始化

msInfo->cellSelectionTimer
通过调用MacGsmStartTimer();

clip_image094

9 初始化

msInfo->isDedicatedChannelAssigned
msInfo->isCellSelected
msInfo->timeSinceCellSelected
msInfo->slotNumber
msInfo->controlFrameNumber
msInfo->frameNumber

10 读PHY-GSM-TX-POWER,

初始化 msInfo->txPower_dbm

11 读PHY-GSM-RX-THRESHOLD

初始化 msInfo->rxLevAccessMin_dbm

12 初始化

msInfo->maxTxPower_dbm
初始化 node->gsmNodeParameters->cellIdentity
node->gsmNodeParameters->lac

原来node.h中还有gsm专用的结构体:gsmNodeParameters,这个结构体在Cellular_gsm.h中定义:

clip_image096

 

BS端的初始化过程咱略,以后补充

varStrValue == GSM-BS varStrValue == GSM-MSC     函数关系图:

今日针对MacGsmInit这个初始化函数,由哪些其他的函数被调用,如下图:

clip_image098

大家可能已经看到上图中函数名前的一些编号,这些编号的索引如下图:
我会把已经分析或者用到过的函数标注出来,这样一是可以知道我们当前的进度,而是可以知道还有哪些没有分析到的地方。

Function Name No. IsUsed MacGsmStartTimer 1 Yes MacGsmStopListeningToChannel 2   MacGsmMsStartListenningToBcchListChannels 3 Yes MacGsmBsGetPhyNumberFromChannel 4   MacGsmGetUpLinkSlotNumber 5   MacGsmGetReverseUpLinkSlotNumber 6   GsmMacSendMessageOverPhy 7   GsmMacBsBuildSysInfoType3Msg 8   GsmMacBsSendSysInfoType3Msg 9   GsmMacBsBuildSysInfoType2Msg 10   GsmMacBsBuildDummyBurstMsg 11   GsmMacBsSendDummyBurstMsg 12   GsmMacMsSendMeasurementReportMsg 13   MacGsmStartListeningToChannel 14   MacGsmMsStopListeningToBcchListChannels 15   MacGsmIsFcchMsg 16   MacGsmBuildFcchMsg 17 Yes MacGsmIsBcchFcchSchSlot 18   MacGsmIsBcchSlot 19   MacGsmIsSchSlot 20   MacGsmBsSendSchMsg 21   MacGsmIsFcchSlot 22   MacGsmIsPagchSlot 23   MacGsmIsSacchMsgFrame 24   MacGsmIsCurrentTchFrameWithIdleSlot 25   MacGsmIsNextTchFrameWithIdleSlot 26   MacGsmIsNotDownLinkCtrlSlot 27   MacGsmInitializeSlotTimer 28 Yes MacGsmUpdateSlotTimer 29   MacGsmComputerC1 30   MacGsmIsCellReselectionNeeded 31   MacGsmPerformCellSelection 32   MacGsmCheckForCellSelection 33   MacGsmHandleTchIdleSlotStartTimer 34   MacGsmHandleTchIdleSlotEndTimer 35   MacGsmIsThereAMsgToBeSent 36   MacGsmHandleMsSlotTimer 37   MacGsmHandleMsSlotTimer 38   MacGsmUpdateMsBcchMeasurements 39   MacGsmUpdateMsDedicatedChMeasurements 40   MacGsmUpdateBsDedicatedChMeasurements 41   MacGsmInitStats 42 Yes GsmParseChannelList 43 Yes GsmParseAdditionalInfo 44   MacGsmIsBcchChannel 45   MacGsmInit 46 Yes MacGsmReceivePacketFromPhy 47   MacGsmReceiveInternalMessageFromLayer3 48   MacGsmReceivePhyStatusChangeNotification 49   MacGsmLayer 50   MacGsmFinalize 51   GsmMapRxLev 52   GsmMapRxQual 53   mapGsmPowerControlLevelToDbm 54   MacGsmNetworkLayerHasPacketToSend 55   MacGsmHandlePromiscuousMode 56  

今天就先到这里吧

 

 

没有评论:

发表评论