基站侧与核心网侧进行交互涉及PLMN和PLMN ID换算及其代码实现

128 篇文章 0 订阅
4 篇文章 1 订阅

先简单介绍一下PLMN的格式:

        PLMN(Public Land Mobile Network,公共陆地移动网络)由政府或它所批准的经营者,为公众提供陆地移动通信业务目的而建立和经营的网络。PLMN = MCC + MNC。例如中国移动的PLMN为46000,中国联通的PLMN为46001,中国电信的PLMN为46003。其中,MCC:Mobile Country Code,移动国家码,MCC的资源由国际电联(ITU)统一分配和管理,唯一识别移动用户所属的国家,共3位,中国为460; MNC:Mobile Network Code,移动网络码,共2位或者3位,但中国的三大运营商是由2位组成的。中国移动TD系统使用00,中国联通GSM系统使用01,中国移动GSM系统使用02,中国电信CDMA系统使用03。

接下来说一说PLMN ID的格式:

       在计算机和通信中,他们的编码方式不一样,通信中应尽量提升码的利用率。由于PLMN的码流特性(0-9),于是将计算机中的PLMN的二进制码进行了BCD码(一种对数字的编码方式)的转换,可以将6字节的PLMN转成3字节的PLMN ID,这样在传输过程中减少了一般的码流传输。可知,PLMN ID的格式为3字节。

PLMN和PLMN ID转换关系:

       PLMN中的都是0-9的数字,0-9之间的数字在计算机中用4bit就可以表示。通过这种表示关系也可知6字节的PLMN可以转成3字节的PLMN ID。那么他们间的转换关系在通信协议标准上规定是如何的呢?

      通信协议标准规定:

      MCC digit2 + MCC digit1 --> PLMN ID digit1

      MNC digit3 + MCC digit3 --> PLMN ID digit2

      MNC digit2 + MNC digit1 --> PLMN ID digit3

      MNC有2位或者3位的,有些运营商的MNC码是2位,则在转成PLMN ID中 MNC digit3用全F代替。这样我们在将PLMN ID转成PLMN时可以通过这个特性来判断MNC是2位码还是3位码。

     MCC digit1 =  PLMN ID digit1 & 0x0F

     MCC digit2 = PLMN ID digit1 & 0xF0 >> 4

     MCC digit3 = PLMN ID digit2 & 0x0F

     判断PLMN ID digit2 & 0xF0 >> 4 是否等于0x0F,如果是:则MNC digit3 = 0,可知MNC是由2位码组成;如果否:则MNC digit3 = PLMN ID digit2 & 0xF0 >> 4。

    MNC digit1 = PLMN ID digit3 & 0x0F

    MNC digit2 = PLMN ID digit3 & 0xF0 >> 4

下面由代码实现上述转换:

#include <string.h>
#include <iostream>

using namespace std;
namespace
{
	struct Plmn
	{
		unsigned char mcc[3];
		unsigned char mnc[3];
		unsigned short mncLen;
	};

	struct PlmnId
	{
		unsigned char data[3];
	};

	inline bool isValidDigit(const unsigned char* data, unsigned short size)
	{
		if (size > 3)
			return false;

		for (int i = 0; i < size; ++i)
		{
			if (!(data[i] >= 0 && data[i] <= 9))
				return false;
		}

		return true;
	}

	inline bool isValid(const Plmn& plmn)
	{
		return isValidDigit(plmn.mcc, 3) && isValidDigit(plmn.mnc, plmn.mncLen);
	}

	bool Plmn2PlmnId(const Plmn& plmn, PlmnId& plmnId)
	{
		if (!isValid(plmn))
			return false;

		plmnId.data[0] = ((plmn.mcc[1] & 0x0F) << 4) | (plmn.mcc[0] & 0x0F);
		if (plmn.mncLen == 3)
		{
			plmnId.data[1] = ((plmn.mnc[2] & 0x0F) << 4) | (plmn.mcc[2] & 0x0F);
		}
		else
		{
			plmnId.data[1] = (0x0F << 4) | (plmn.mcc[2] & 0x0F);
		}

		plmnId.data[2] = ((plmn.mnc[1] & 0x0F) << 4) | (plmn.mnc[0] & 0x0F);

		return true;
	}
	///
	inline bool isBCD(unsigned char data)
	{
		if ((data >> 4) >= 10 || (data & 0x0F) >= 10)
			return false;
		return true;
	}

	bool isValid(const PlmnId& plmnId)
	{
		if ((plmnId.data[1] & 0xF0 ) == 0xF0)
			return isBCD(plmnId.data[0]) && isBCD(plmnId.data[1] & 0x0F) && isBCD(plmnId.data[2]);
		else
			return isBCD(plmnId.data[0]) && isBCD(plmnId.data[1]) && isBCD(plmnId.data[2]);
	}

	inline void revertToMcc(const PlmnId& plmnId, Plmn& plmn)
	{
		plmn.mcc[0] = plmnId.data[0] & 0x0F;
		plmn.mcc[1] = (plmnId.data[0] & 0xF0) >> 4;
		plmn.mcc[2] = plmnId.data[1] & 0x0F;
	}

	inline void revertToMnc(const PlmnId& plmnId, Plmn& plmn)
	{
		if ((plmnId.data[1] & 0xF0) == 0xF0)
		{
			plmn.mncLen = 2;
		}
		else
		{
			plmn.mncLen = 3;
			plmn.mnc[2] = (plmnId.data[1] & 0xF0) >> 4;
		}

		plmn.mnc[0] = plmnId.data[2] & 0x0F;
		plmn.mnc[1] = (plmnId.data[2] & 0xF0) >> 4;
	}

	bool PlmnId2Plmn(const PlmnId& plmnId, Plmn& plmn)
	{
		if (!isValid(plmnId))
			return false;

		revertToMcc(plmnId, plmn);
		revertToMnc(plmnId, plmn);

		return true;
	}
}
//
int main(int argc, char **argv)
{
	Plmn plmn;
	::memset(&plmn, 0x00, sizeof(plmn));
	plmn.mcc[0] = 4, plmn.mcc[1] = 6, plmn.mcc[2] = 0;
	plmn.mnc[0] = 0, plmn.mnc[1] = 0;
	plmn.mncLen = 2;

	PlmnId plmnId;
	::memset(&plmnId, 0x00, sizeof(plmnId));
	if (!Plmn2PlmnId(plmn, plmnId))
	{
		cout << "Plmn2PlmnId failure" << endl;
		return -1;
	}

	Plmn destPlmn;
	::memset(&destPlmn, 0x00, sizeof(destPlmn));
	if (!PlmnId2Plmn(plmnId, destPlmn))
	{
		cout << "PlmnId2Plmn failure" << endl;
		return -1;
	}

	if (::memcmp(&plmn, &destPlmn, sizeof(Plmn)) != 0)
	{
		cout << "assert equal failure" << endl;
		return -1;
	}
	else
	{
		cout << "Congratulation!!!!!!" << endl;
	}

	return 0;
}





 

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值