先简单介绍一下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
#include
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;
}