3GPP WCDMA下行数据解码流程,从Bits数据流解码到语音和短信,C++实战演示代码
为了学习验证从空中扫频,到解码出语音短信这个流程。所以只解析了必要的BBCH_BCH(为了获取频点信息),以及FACH和DPCH这三个通道的数据。
用了一些自己定义的数据结构Buffer_t这类,无关乎流程。整个解析代码,从bits流解到每个通道的MAC,RLC,到RRC流程交互,都是自己全手工编写完成,没有参考样例,没有经过大量数据测试,无责任不保证有大量错误。
RRC消息结构解析用的asn1c(吐槽:)当年的asn1c还不甚完善,会生成大量重复的结构定义,耗费了不少时间手工修改,不知道现在改进了没。
Milenage和Kasumi解密算法代码在另外两篇博文中。
程序解码流程根据标准文档编写,整个流程能成功走完。先用ReadBitsFile函数读取bits数据流文本文件(自定义格式),拿到几个通道的数据,然后用L3Decode函数解码流程,保存解码出来的语音和短信文件。
代码中有好几处地方不太确定,比如sfn,cfn和hfn的值计算,以及后面做f8解密时,解密参数count的计算。代码流程仅供学习参考。
(吐槽:)f8的解密参数bearer是用RB identity-1,而RB identity获取时,则是用承载序号+1。这个小小的细节,做f8解密时整整卡了我2个星期翻英文的TS25.331标准文档,比较尴尬的是,中文的翻译版反而看不懂流程…
L3Decode.h
#ifndef _L3_DECODE_H_INCLUDE_
#define _L3_DECODE_H_INCLUDE_
static const int DATA_LENGTH_BCH = 246;
static const int DATA_LENGTH_FACH = 168;
static const int DATA_LENGTH_DPCH = 148;
static const char* CH_TYPE_BCH = "DL_BCCH_BCH";
static const char* CH_TYPE_FACH = "FACH";
static const char* CH_TYPE_DPCH = "DPCH";
static const char* VOICE_FILE_OUT_NAME = "voice.amr";
static const char* RRC_TMSI_LIST_FILE_OUT_NAME = "rrc_tmsi_list.txt";
typedef struct asn_TYPE_descriptor_s asn_TYPE_descriptor_t;
struct TimeCode_t
{
TimeCode_t()
{
Clear();
}
void Clear()
{
cfn = 0;
wHour = 0;
wMinute = 0;
wSecond = 0;
}
uint32_t cfn;
uint16_t wHour;
uint16_t wMinute;
uint16_t wSecond;
};
struct PDULineInfo_t
{
PDULineInfo_t()
{
Clear();
};
void Clear()
{
chIdx = 0;
timeCode.Clear();
pduLine.clear();
};
TimeCode_t timeCode;
string pduLine;
string chType;
uint8_t chIdx;
};
struct BitBuffer_t : public Buffer_t
{
BitBuffer_t() : Buffer_t(), m_nLastSkipBits(0) { };
BitBuffer_t(PBYTE pData, UINT nDataSize, UINT nLastSkipBits) : Buffer_t(pData, nDataSize), m_nLastSkipBits(nLastSkipBits) { };
BitBuffer_t(const BitBuffer_t& st) : Buffer_t(st), m_nLastSkipBits(st.m_nLastSkipBits) { };
virtual BitBuffer_t& operator =(const BitBuffer_t& st)
{
this->m_nLastSkipBits = st.m_nLastSkipBits;
*(Buffer_t *)this = st;
return *this;
}
virtual void Free()
{
Buffer_t::Free();
m_nLastSkipBits = 0;
}
virtual void ClearData()
{
Buffer_t::ClearData();
m_nLastSkipBits = 0;
}
virtual size_t GetDataBits()
{
return m_nDataSize * 8 - m_nLastSkipBits;
}
virtual BOOL Allocate(INT nBufferSize)
{
if (Buffer_t::Allocate(nBufferSize))
{
m_nLastSkipBits = 0;
return TRUE;
}
return FALSE;
}
uint8_t m_nLastSkipBits;
};
struct PDUData_t
{
PDUData_t()
{
desType = 0;
isRepeatedSN = 0;
}
string chType;
asn_TYPE_descriptor_t* desType;
string desMAC;
string desRLC;
string modeRLC;
Buffer_t dataMAC;
Buffer_t dataRLC;
BitBuffer_t dataPDU;
BitBuffer_t dataF8PDU;
bool isRepeatedSN;
};
struct PDU_CH_SN_Data_t
{
PDU_CH_SN_Data_t()
{
sn = -1;
}
int sn;
BitBuffer_t data;
vector<BitBuffer_t > pduDataList;
};
struct SIBInfo_t
{
SIBInfo_t()
{
sibDesType = 0;
sibType = 0;
sibCount = 0;
};
asn_TYPE_descriptor_t* sibDesType;
int sibType;
int sibCount;
map<int, BitBuffer_t> sibData;
};
struct RRCConnectInfo_t
{
RRCConnectInfo_t()
{
tmsi = 0;
dpchFrameOffset = 0;
sf = 0;
codeNumber = 0;
};
uint32_t tmsi;
long dpchFrameOffset;
long sf;
long codeNumber;
};
struct L3DecodeSys_t
{
L3DecodeSys_t()
{
cn_DomainIdentity = 0;
memset(ki, 0, 16);
memset(opc, 0, 16);
Init();
};
~L3DecodeSys_t()
{
Close();
};
void Init()
{
dpchPDUSNList.clear();
bchPDUSNList.clear();
fachPDUSNList.clear();
//bearer = 0;
direction = 1; //目前只能解码下行
rrcInfoFilter = false;
tmsiFilter = 0;
start = 0;
hfn_um = 0;
hfn_am = 0;
hfn_tm = 0;
doff = 0;
sfn = 0;
cfn = 0;
trRbChMap.clear();
trSizeMap.clear();
isF8Ciphering = false;
sibList.clear();
rrcConnected = false;
radioBearerSetup = false;
radioBearerReconfiguration = false;
bVoiceData = false;
rrcConnectInfoList.clear();
tmsiInfoList.clear();
rrc_decode_info.clear();
rrc_decode_info_simplify.clear();
};
void Reset()
{
rrcConnected = false;
radioBearerSetup = false;
radioBearerReconfiguration = false;
bVoiceData = false;
isF8Ciphering = false;
f8CipheringActiveTimeList.clear();
};
void Close()
{
if (fdVoiceFile.is_open())
{
fdVoiceFile.close();
}
};
// int: ch
map<size_t, PDU_CH_SN_Data_t> dpchPDUSNList;
map<size_t, PDU_CH_SN_Data_t> fachPDUSNList;
map<size_t, PDU_CH_SN_Data_t> bchPDUSNList;
int direction;
bool rrcInfoFilter;
uint32_t tmsiFilter;
uint8_t ki[16];
uint8_t opc[16];
// start
uint32_t start;
// UM HFN
uint32_t hfn_um;
// AM HFN
uint32_t hfn_am;
// TM HFN
uint32_t hfn_tm;
// sfn->cfn
uint32_t doff;
uint32_t sfn;
uint8_t cfn;
map<uint32_t, uint32_t> trRbChMap;
map<uint32_t, uint32_t> trSizeMap;
// f8 ciphering
bool isF8Ciphering;
map<int, int> f8CipheringActiveTimeList;
int cn_DomainIdentity;
map<int, vector<uint8_t>> cn_Rand;
map<int, vector<uint8_t>> cn_Domain_ck;
// sib list
vector<SIBInfo_t> sibList;
// state
bool rrcConnected;
bool radioBearerSetup;
bool radioBearerReconfiguration;
//voice file
bool bVoiceData;
ofstream fdVoiceFile;
vector<int8_t> buffVoice;
bs_t bitsVoice;
// decode info
string rrc_decode_info;
string rrc_decode_info_simplify;
vector<RRCConnectInfo_t> rrcConnectInfoList;
string tmsiInfoList;
};
static inline bool CheckHex(char c)
{
if ((c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F') ||
(c >= '0' && c <= '9'))
{
return true;
}
return false;
}
static inline UINT Text2Data(LPCSTR dataType, LPCSTR text, BitBuffer_t& data)
{
UINT nBitsCount = 0;
int textLen = strlen(text);
if (strstr(dataType, "Bits"))
{
data.Allocate((textLen + 7) / 8);
memset(data.m_pBuffer, 0, data.m_nBufferSize);
bs_s bs;
bs_init(&bs, data.m_pBuffer, data.m_nBufferSize);
int iByte = 0;
for (INT i = 0; i < textLen; i++)
{
if (text[i] == '0')
{
bs_write(&bs, 1, 0);
++nBitsCount;
}
else if (text[i] == '1')
{
//buff.m_pBuffer[nBitsCount / 8] |= (1 << (nBitsCount % 8));
bs_write(&bs, 1, 1);
++nBitsCount;
}
}
data.m_nDataSize = (nBitsCount + 7) / 8;
data.m_nLastSkipBits = data.m_nDataSize * 8 - nBitsCount;
}
else if (strstr(dataType, "Hex"))
{
data.Allocate(textLen / 2);
for (INT i = 0; i < textLen; )
{
if (!CheckHex(text[i]) ||
(i + 1) >= textLen ||
!CheckHex(text[i + 1]))
{
++i;
continue;
}
BYTE t;
if (1 == sscanf(text + i, "%02hhx", &t))
{
data.m_pBuffer[nBitsCount / 8] = t;
++data.m_nDataSize;
nBitsCount += 8;
}
i += 2;
}
}
return nBitsCount;
}
static inline UINT Text2Data(LPCTSTR dataType, LPCTSTR text, BitBuffer_t& data)
{
return Text2Data(t2a(dataType).c_str(), t2a(text).c_str(), data);
}
static inline UINT Text2Data(const string& dataType, const string& text, BitBuffer_t& data)
{
return Text2Data(dataType.c_str(), text.c_str(), data);
}
static inline string Data2Text(LPCSTR dataType, const uint8_t *pData, UINT nBitsCount)
{
string msg;
if (strstr(dataType, "Hex"))
{
char text[3] = { 0 };
for (UINT i = 0; i < nBitsCount; )
{
_snprintf(text, 3, "%02hhX", pData[i / 8]);
msg += text;
i += 8;
if (0 == (i % 256))
msg += "\n";
else if (0 == (i % 64))
msg += " ";
else if (0 == (i % 8))
msg += ' ';
}
}
else if (strstr(dataType, "Bits"))
{
bs_s bs;
bs_init(&bs, (void *)pData, (nBitsCount + 7) / 8);
for (UINT i = 0; i < nBitsCount; )
{
if (bs_read1(&bs) > 0)
{
msg += '1';
}
else
{
msg += '0';
}
++i;
if (0 == (i % 64))
msg += "\n";
else if (0 == (i % 8))
msg += ' ';
}
}
return msg;
}
static inline string Data2Text(LPCSTR dataType, const Buffer_t& data, UINT nBitsCount)
{
return Data2Text(dataType, data.m_pData, nBitsCount);
}
static inline string Data2Text(const string& dataType, const Buffer_t& data, UINT nBitsCount)
{
return Data2Text(dataType.c_str(), data, nBitsCount);
}
static inline string_t Data2Text(LPCTSTR dataType, const Buffer_t& data, UINT nBitsCount)
{
return a2t(Data2Text(t2a(dataType), data, nBitsCount));
}
static inline int get_des_field_number(LPCSTR desField, const string& des)
{
int i = des.find(desField);
if (i < 0)
return i;
LPCSTR p = des.c_str() + i + strlen(desField);
return atol(p);
}
static inline UINT32 bs_read_data(bs_t& bsR, bs_t& bsW, int nRead, UINT& nLen)
{
UINT32 n = bs_read(&bsR, nRead);
bs_write(&bsW, nRead, n);
nLen += nRead;
return n;
}
static inline string get_li_des(BYTE li)
{
string text;
s_sprintf(&text, "LI:%u ", li);
if (li == 0x00) /*0000000*/ // 第一个SDU开始标记
{
text += "noLI:0000000 ";
}
else if (li == 0x7C) /*1111100*/ // 第一个SDU开始标记
{
text += "umdFirst:1111100 ";
}
else if (li == 0x7D /*1111101*/) // 第一个SDU开始标记
{
text += "umdFirst:1111101 ";
}
else if (li == 0x7E /*1111110*/)
{
text += "STATUS:1111101 ";
}
else if (li == 0x7F /*1111111*/) // PAD内容,丢弃并结束
{
text += "PAD:1111111 ";
}
return text;
}
string decode_sms(Buffer_t& nasMessage);
string l3_decode_bch(BitBuffer_t& dataPDU, PDUData_t& pduInfo);
string l3_decode_fach(BitBuffer_t& dataPDU, PDUData_t& pduInfo);
string l3_decode_dpch(BitBuffer_t& dataPDU, PDUData_t& pduInfo);
string l3_decode_rrc(BYTE* pData, UINT nBitsCount, UINT nSkipBits, asn_TYPE_descriptor_t *asn_type_des, void **msg);
void ReadBitsFile(ifstream &fd, multimap<DWORD, PDULineInfo_t> &pduLineList);
void L3Decode(L3DecodeSys_t &sys, multimap<DWORD, PDULineInfo_t> &pduLineList);
#endif //_L3_DECODE_H_INCLUDE_
L3Decode.cpp
/*
* Ryan chen 2018
* Contact: 70565912@qq.com
*/
#include "Common.h"
#include "L3Decode.h"
#include "RRCDecode.h"
#include "kasumi.h"
#include "Milenage.h"
static void write_bits(bs_t &bs, uint8_t *pData, UINT bits)
{
// 按位写数据
for (int i_bits = 0; i_bits < bits; ++i_bits)
{
// 注意:bs_write是先写高位
bs_write(&bs, 1, (pData[0] >> (7 - (i_bits % 8))));
if (0 == ((i_bits + 1) % 8))
++pData;
}
}
string l3_decode_rrc(BYTE* pData, UINT nBitsCount, UINT nSkipBits, asn_TYPE_descriptor_t *asn_type_des, void **msg)
{
string des;
char text[MAX_PATH];
char *p_name = NULL;
long consumed = 0;
char *p_des = 0;
size_t des_size = 0;
int ret = rrc_def_decode(pData, nBitsCount, nSkipBits, &p_name, &consumed, asn_type_des, msg, &p_des, &des_size);
if (ret < 0)
{
_snprintf(text, MAX_PATH, "Broken decoding at byte %ld.\n", (long)consumed);
return text;
}
if (ret > 0)
{
des = "Need more data.\n";
return des;
}
if (p_des && des_size)
{
des.append(p_des, des_size);
des += "\n";
free(p_des);
}
return des;
}
static bool check_rrc_connect_release(L3DecodeSys_t &sys, DL_DCCH_Message *msg)
{
if (msg->message.present == DL_DCCH_MessageType_PR_rrcConnectionRelease)
{
#if 0 // 暂不做释放
sys.Reset();
#endif
return true;
}
return false;
}
static bool check_rrc_connect_release(L3DecodeSys_t &sys, DL_CCCH_Message *msg)
{
#if 0 // 暂不做释放
if (msg->message.present == DL_CCCH_MessageType_PR_rrcConnectionRelease)
{
sys.rrcConnected = false;
// f8加密结束
sys.isF8Ciphering = false;
sys.f8CipheringActiveTimeList.clear();
return true;
}
#endif
return false;
}
static void save_rrc_info(L3DecodeSys_t &sys, string &decodeInfo)
{
vector<RRCConnectInfo_t> &infoList = sys.rrcConnectInfoList;
if (!infoList.size())
return;
RRCConnectInfo_t rrcInfo = (infoList.size() == 1) ? infoList.front() : infoList.back();
char text[MAX_PATH];
string tmsiInfo;
BitBuffer_t tmsiData;
tmsiData.FillData((LPBYTE)&rrcInfo.tmsi, 4);
string bitsTextTMSI = Data2Text("Bits", tmsiData, 32);
snprintf(text, MAX_PATH, "TMSI: %s ", bitsTextTMSI.c_str());
tmsiInfo += text;
snprintf(text, MAX_PATH, "DPCH-FrameOffset: %d ", rrcInfo.dpchFrameOffset);
tmsiInfo += text;
text[0] = 0;
switch (rrcInfo.sf)
{
case SF512_AndCodeNumber_PR_sf4:
snprintf(text, MAX_PATH, "SF4: %d\n", rrcInfo.codeNumber);
break;
case SF512_AndCodeNumber_PR_sf8:
snprintf(text, MAX_PATH, "SF8: %d\n", rrcInfo.codeNumber);
break;
case SF512_AndCodeNumber_PR_sf16:
snprintf(text, MAX_PATH, "SF16: %d\n", rrcInfo.codeNumber);
break;
case SF512_AndCodeNumber_PR_sf32:
snprintf(text, MAX_PATH, "SF32: %d\n", rrcInfo.codeNumber);
break;
case SF512_AndCodeNumber_PR_sf64:
snprintf(text, MAX_PATH, "SF64: %d\n", rrcInfo.codeNumber);
break;
case SF512_AndCodeNumber_PR_sf128:
snprintf(text, MAX_PATH, "SF128: %d\n", rrcInfo.codeNumber);
break;
case SF512_AndCodeNumber_PR_sf256:
snprintf(text, MAX_PATH, "SF256: %d\n", rrcInfo.codeNumber);
break;
case SF512_AndCodeNumber_PR_sf512:
snprintf(text, MAX_PATH, "SF512: %d\n", rrcInfo.codeNumber);
break;
}
tmsiInfo += text;
// 文件保存
ofstream fd;
if (infoList.size() == 1)
fd.open(RRC_TMSI_LIST_FILE_OUT_NAME, ios::out);
else
fd.open(RRC_TMSI_LIST_FILE_OUT_NAME, ios::out | ios::app);
if (fd.is_open())
{
fd.write(tmsiInfo.c_str(), tmsiInfo.size());
}
// 列表保存
sys.tmsiInfoList += tmsiInfo;
// 保存日志
decodeInfo += "RRCConnectionSetup :" + tmsiInfo;
}
static string get_sms_number(uint8_t* pData, int& idx, int len)
{
string des;
uint8_t n;
char t[2];
for (int i = 0; i < len * 2; i++)
{
if ((i % 2) == 0)
{
++idx;
n = pData[idx] & 0x0F;
}
else
{
n = pData[idx] >> 4;
}
if (n == 0x0F)
break;
snprintf(t, 2, "%hhu", n);
des += t;
}
++idx;
return des;
}
string decode_sms(Buffer_t& nasMessage)
{
int idx = 0;
string smsText;
if (nasMessage.m_nDataSize < 3)
return smsText;
if (nasMessage.m_pData[0] != 0x09 && nasMessage.m_pData[1] != 0x01)
return smsText;
uint8_t naslen = nasMessage.m_pData[2];
if (nasMessage.m_nDataSize - 3 != naslen)
return smsText;
idx = 5;
uint8_t dataLen = nasMessage.m_pData[idx++];
smsText += "Number:";
smsText += get_sms_number(nasMessage.m_pData, idx, dataLen);
uint8_t rpD_len = nasMessage.m_pData[idx++];
idx += rpD_len;
uint8_t rpUser_len = nasMessage.m_pData[idx++];
idx += 1;
uint8_t numLen = nasMessage.m_pData[idx++];
smsText += " Number:";
smsText += get_sms_number(nasMessage.m_pData, idx, dataLen);
idx += 2;
uint8_t nYear = nasMessage.m_pData[idx++];
uint8_t nMonth = nasMessage.m_pData[idx++];
uint8_t nDay = nasMessage.m_pData[idx++];
uint8_t nHour = nasMessage.m_pData[idx++];
uint8_t nMinute = nasMessage.m_pData[idx++];
uint8_t nSecond = nasMessage.m_pData[idx++];
uint8_t nTimeZone = nasMessage.m_pData[idx++];
uint8_t tp_udl = nasMessage.m_pData[idx++];
uint8_t UDHL = nasMessage.m_pData[idx++];
idx += UDHL;
if (idx >= nasMessage.m_nDataSize)
return smsText;
int smsLen = tp_udl - 1 - UDHL;
if (smsLen + idx != nasMessage.m_nDataSize)
return smsText;
//Win32是UTF-16LE,需要调换顺序
vector<uint8_t> utf16le;
utf16le.resize(smsLen + 2);
memset(&utf16le[0], 0, smsLen + 2);
for (int i = 0; i < smsLen / 2; i++)
{
utf16le[i * 2 + 1] = nasMessage.m_pData[idx++];
utf16le[i * 2] = nasMessage.m_pData[idx++];
}
smsText += "\nSMS:";
smsText += w2a((wchar_t *)&utf16le[0]);//UTF16LE转为窄字符编码
return smsText;
}
static uint32_t check_rrc_connect_setup(L3DecodeSys_t &sys, DL_CCCH_Message *msg, string &decodeInfo)
{
uint32_t tmsi = 0;
long defaultDPCH_OffsetValue = 0;
long dpch_FrameOffset = 0;
long sf = 0;
long codeNumber = 0;
if (msg->message.present != DL_CCCH_MessageType_PR_rrcConnectionSetup)
return 0;
RRCConnectionSetup_t *rrcConnectionSetup = &msg->message.choice.rrcConnectionSetup;
if (rrcConnectionSetup->present != RRCConnectionSetup_PR_r3)
return 0;
RRCConnectionSetup_r3_IEs_t *rrcConnectionSetup_r3 = &rrcConnectionSetup->choice.r3.rrcConnectionSetup_r3;
InitialUE_Identity_t *initialUE_Identity = &rrcConnectionSetup_r3->initialUE_Identity;
if (initialUE_Identity->present != InitialUE_Identity_PR_tmsi_and_LAI)
return 0;
TMSI_and_LAI_GSM_MAP_t *tmsi_and_LAI = &initialUE_Identity->choice.tmsi_and_LAI;
if (tmsi_and_LAI->tmsi.size == 4)
{
tmsi = htonl(*(uint32_t*)tmsi_and_LAI->tmsi.buf);
// 过滤掉非需要的tmsi连接消息
if (sys.tmsiFilter && sys.tmsiFilter != tmsi)
{
return tmsi;
}
}
// 获取rb id与tr id
for (int iRb = 0; iRb < rrcConnectionSetup_r3->srb_InformationSetupList.list.count; ++iRb)
{
SRB_InformationSetup *srbInfo = rrcConnectionSetup_r3->srb_InformationSetupList.list.array[iRb];
if (srbInfo->rb_MappingInfo.list.count > 0)
{
RB_MappingOption *rbOp = srbInfo->rb_MappingInfo.list.array[0];
for (int iCh = 0; iCh < rbOp->dl_LogicalChannelMappingList->list.count; ++iCh)
{
DL_LogicalChannelMapping *dl_loChMap = rbOp->dl_LogicalChannelMappingList->list.array[iCh];
if (dl_loChMap->logicalChannelIdentity)
{
// TS25.331 8.6.4.1
// apply a default value of the IE "RB identity" equal to 1 for the first IE "Signalling RB information to setup";
// and increase the default value by 1 for each occurrence.
sys.trRbChMap[*dl_loChMap->logicalChannelIdentity] = iRb + 1;
}
}
}
}
DL_CommonInformation *dl_CommonInformation = rrcConnectionSetup_r3->dl_CommonInformation;
if (dl_CommonInformation)
{
if (dl_CommonInformation->modeSpecificInfo.present == DL_CommonInformation__modeSpecificInfo_PR_fdd)
{
if (dl_CommonInformation->modeSpecificInfo.choice.fdd.defaultDPCH_OffsetValue)
{
//-- Actual value DefaultDPCH-OffsetValueFDD = IE value * 512
defaultDPCH_OffsetValue = *dl_CommonInformation->modeSpecificInfo.choice.fdd.defaultDPCH_OffsetValue * 512;
}
}
}
DL_InformationPerRL_List *dl_InformationPerRL_List = rrcConnectionSetup_r3->dl_InformationPerRL_List;
if (dl_InformationPerRL_List)
{
for (int i = 0; i < dl_InformationPerRL_List->list.count; i++)
{
DL_InformationPerRL *info = dl_InformationPerRL_List->list.array[i];
if (info->dl_DPCH_InfoPerRL->present == DL_DPCH_InfoPerRL_PR_fdd)
{
//-- Actual value DPCH-FrameOffset = IE value * 256
dpch_FrameOffset = info->dl_DPCH_InfoPerRL->choice.fdd.dpch_FrameOffset * 256;
if (info->dl_DPCH_InfoPerRL->choice.fdd.dl_ChannelisationCodeList.list.count)
{
struct DL_ChannelisationCode *dl_chSationCode = info->dl_DPCH_InfoPerRL->choice.fdd.dl_ChannelisationCodeList.list.array[0];
sf = dl_chSationCode->sf_AndCodeNumber.present;
codeNumber = dl_chSationCode->sf_AndCodeNumber.choice.sf128;
}
}
}
}
/* TS25.331 8.6.6.14
1 > The UE shall :
2 > if only one Radio Link is included in the message :
3 > if the UE is configured for DPCH:
4 > if (Default DPCH Offset Value) mod 38400 = DPCH frame offset :
5 > set DOFF(see subclause 8.5.15.1) to Default DPCH Offset Value.
4 > else:
5 > set the variable INVALID_CONFIGURATION to TRUE.
3 > if the UE is configured for F-DPCH:
4 > if (Default DPCH Offset Value) mod 38400 = DPCH frame offset :
5 > set DOFF(see subclause 8.5.15.1) to Default DPCH Offset Value.
4 > else if (Default DPCH Offset Value + 256) mod 38400 = DPCH frame offset :
5 > set DOFF(see subclause 8.5.15.1) to Default DPCH Offset Value + 256.
4 > else:
5 > set the variable INVALID_CONFIGURATION to TRUE.
*/
// F-DPCH
if ((defaultDPCH_OffsetValue % 38400) == dpch_FrameOffset)
{
sys.doff = defaultDPCH_OffsetValue;
}
else if (((defaultDPCH_OffsetValue + 256) % 38400) == dpch_FrameOffset)
{
sys.doff = defaultDPCH_OffsetValue + 256;
}
sys.rrcConnected = true;
RRCConnectInfo_t rrcInfo;
rrcInfo.tmsi = htonl(tmsi);
rrcInfo.dpchFrameOffset = dpch_FrameOffset / 256;
rrcInfo.sf = sf;
rrcInfo.codeNumber = codeNumber;
sys.rrcConnectInfoList.push_back(rrcInfo);
save_rrc_info(sys, decodeInfo);
return tmsi;
}
static void check_radio_bearer_setup(L3DecodeSys_t &sys, DL_DCCH_Message *msg, string &decodeInfo)
{
if (msg->message.present != DL_DCCH_MessageType_PR_radioBearerSetup)
return;
RadioBearerSetup_t *radioBearerSetup = &msg->message.choice.radioBearerSetup;
if (radioBearerSetup->present != RadioBearerSetup_PR_r3)
return;
RadioBearerSetup_r3_IEs_t *radioBearerSetup_r3 = &radioBearerSetup->choice.r3.radioBearerSetup_r3;
if (!radioBearerSetup_r3->rab_InformationSetupList)
return;
for (int iRab = 0; iRab < radioBearerSetup_r3->rab_InformationSetupList->list.count; iRab++)
{
struct RAB_InformationSetup *rabInfo = radioBearerSetup_r3->rab_InformationSetupList->list.array[iRab];
for (int iRb = 0; iRb < rabInfo->rb_InformationSetupList.list.count; iRb++)
{
RB_InformationSetup *rbInfo = rabInfo->rb_InformationSetupList.list.array[iRb];
long rb_id = rbInfo->rb_Identity;
for (int iRbInfo = 0; iRbInfo < rbInfo->rb_MappingInfo.list.count; ++iRbInfo)
{
struct RB_MappingOption *rbMapInfo = rbInfo->rb_MappingInfo.list.array[iRbInfo];
if (rbMapInfo->dl_LogicalChannelMappingList)
{
for (int iLogCh = 0; iLogCh < rbMapInfo->dl_LogicalChannelMappingList->list.count; ++iLogCh)
{
DL_LogicalChannelMapping *loChMap = rbMapInfo->dl_LogicalChannelMappingList->list.array[iLogCh];
if (loChMap->dl_TransportChannelType.present == DL_TransportChannelType_PR_dch)
{
long tr_id = loChMap->dl_TransportChannelType.choice.dch;
sys.trRbChMap[tr_id] = rb_id;
}
}
}
}
}
if (!radioBearerSetup_r3->ul_AddReconfTransChInfoList)
return;
for (int iUlAddTrCh = 0; iUlAddTrCh < radioBearerSetup_r3->ul_AddReconfTransChInfoList->list.count; iUlAddTrCh++)
{
UL_AddReconfTransChInformation *ulReInfo = radioBearerSetup_r3->ul_AddReconfTransChInfoList->list.array[iUlAddTrCh];
long tr_id = ulReInfo->transportChannelIdentity;
if (ulReInfo->transportFormatSet.present == TransportFormatSet_PR_dedicatedTransChTFS)
{
DedicatedTransChTFS_t *dedicatedTransChTFS = &ulReInfo->transportFormatSet.choice.dedicatedTransChTFS;
if (dedicatedTransChTFS->tti.present == DedicatedTransChTFS__tti_PR_tti20)
{
DedicatedDynamicTF_InfoList_t *tti20 = &dedicatedTransChTFS->tti.choice.tti20;
for (int iTti = 0; iTti < tti20->list.count; iTti++)
{
DedicatedDynamicTF_Info *ddtInfo = tti20->list.array[iTti];
int rlc_bit_size = 0;
if (ddtInfo->rlc_Size.present == DedicatedDynamicTF_Info__rlc_Size_PR_bitMode)
{
rlc_bit_size = ddtInfo->rlc_Size.choice.bitMode.choice.sizeType1;
}
else
{
rlc_bit_size = ddtInfo->rlc_Size.choice.octetModeType1.choice.sizeType1 * 8;
}
sys.trSizeMap[rlc_bit_size] = tr_id;
}
}
}
}
}
sys.radioBearerSetup = true;
sys.hfn_tm = 0;
decodeInfo += "RadioBearerSetup\n";
}
static void check_radio_bearer_reconfiguration(L3DecodeSys_t &sys, DL_DCCH_Message *msg, string &decodeInfo)
{
if (msg->message.present != DL_DCCH_MessageType_PR_radioBearerReconfiguration)
return;
sys.radioBearerReconfiguration = true;
sys.hfn_tm = 0;
decodeInfo += "RadioBearerReconfiguration :HFN begin counting.\n";
}
static void check_security_mode_command(L3DecodeSys_t &sys, DL_DCCH_Message *msg, string &decodeInfo)
{
if (sys.isF8Ciphering) // 已经进入F8 ciphering状态,不用再check SecurityModeCommand消息
return;
if (msg->message.present == DL_DCCH_MessageType_PR_securityModeCommand)
{
if (msg->message.choice.securityModeCommand.present == SecurityModeCommand_PR_r3)
{
SecurityModeCommand_r3_IEs_t *securityModeCommand_r3 = &msg->message.choice.securityModeCommand.choice.r3.securityModeCommand_r3;
if (securityModeCommand_r3->cipheringModeInfo)
{
CipheringModeInfo *cipheringModeInfo = securityModeCommand_r3->cipheringModeInfo;
if (cipheringModeInfo->rb_DL_CiphActivationTimeInfo)
{
RB_ActivationTimeInfoList *rb_DL_CiphActivationTimeInfo = cipheringModeInfo->rb_DL_CiphActivationTimeInfo;
sys.f8CipheringActiveTimeList.clear();
for (int i = 0; i < rb_DL_CiphActivationTimeInfo->list.count; i++)
{
int rb_id = rb_DL_CiphActivationTimeInfo->list.array[i]->rb_Identity;
int rlc_sn = rb_DL_CiphActivationTimeInfo->list.array[i]->rlc_SequenceNumber;
sys.f8CipheringActiveTimeList[rb_id] = rlc_sn;
}
}
// 当前作用域
sys.cn_DomainIdentity = securityModeCommand_r3->cn_DomainIdentity;
// 计算当前作用域的CK
map<int, vector<uint8_t>>::iterator pos = sys.cn_Rand.find(sys.cn_DomainIdentity);
if (pos != sys.cn_Rand.end())
{
//RES RES = f2;
BYTE RES[0x08] = { 0x00 };
//IK IK = f4;
BYTE IK[0x10] = { 0x00 };
//AK AK = f5;
BYTE AK[0x06] = { 0x00 };
vector<uint8_t> ck;
ck.resize(16);
f2345(sys.opc, sys.ki, &pos->second[0], RES, &ck[0], IK, AK);
sys.cn_Domain_ck[sys.cn_DomainIdentity] = ck;
}
// TS25.331 8.1.12.3
sys.hfn_um = (sys.start << 5); // 20位->25位 TS33.102 6.6.4
sys.hfn_am = (sys.start); // 20位
// f8加密开始
sys.isF8Ciphering = true;
decodeInfo += "SecurityModeCommand: Begin F8 Chiphering(Domain:" + (sys.cn_DomainIdentity > 0 ? string("PS") : string("CS")) + ").\n";
}
}
}
}
static void check_downlink_direct_transfer(L3DecodeSys_t &sys, DL_DCCH_Message *msg, Buffer_t& nasMessage, string &decodeInfo)
{
if (msg->message.present == DL_DCCH_MessageType_PR_downlinkDirectTransfer)
{
DownlinkDirectTransfer_t *downlinkDirectTransfer = &msg->message.choice.downlinkDirectTransfer;
if (downlinkDirectTransfer->present == DownlinkDirectTransfer_PR_r3)
{
DownlinkDirectTransfer_r3_IEs_t *downlinkDirectTransfer_r3 = &downlinkDirectTransfer->choice.r3.downlinkDirectTransfer_r3;
NAS_Message_t *nas_Message = &downlinkDirectTransfer_r3->nas_Message;
int cn_DomainId = downlinkDirectTransfer_r3->cn_DomainIdentity;
// 查找短信
if (nas_Message->size > 0 && (nas_Message->buf[0] & 0xF) == 0x09) // SMS message
{
nasMessage.FillData(nas_Message->buf, nas_Message->size);
}
// 获取鉴权随机数
if (nas_Message->size == 37 && nas_Message->buf[0] == 0x05 && nas_Message->buf[1] == 0x12)
{
//检查随机数
vector<uint8_t> cn_Rand;
cn_Rand.resize(16);
memcpy(&cn_Rand[0], nas_Message->buf + 3, 16);
sys.cn_Rand[cn_DomainId] = cn_Rand;
decodeInfo += "DownlinkDirectTransfer: New Rand(Domain:" + (cn_DomainId > 0 ? string("PS") : string("CS")) + ").";
// 收到新的鉴权key,在rrc已经连接或者SecurityModeCommand确认进入加密模式下,Start置0
if (sys.rrcConnected || sys.isF8Ciphering)
{
// Start置0
sys.start = 0;
decodeInfo += "START set 0.";
}
decodeInfo += '\n';
}
}
}
}
// 支持的解析类型才返回true
static bool set_sib_info(SIBInfo_t &sibInfo, long sib_Type, long sibCount, long sibIdx, uint8_t *buf, int size, int lastSkipBits)
{
switch (sib_Type)
{
case SIB_Type_masterInformationBlock:
sibInfo.sibDesType = &asn_DEF_MasterInformationBlock;
break;
case SIB_Type_systemInformationBlockType1:
sibInfo.sibDesType = &asn_DEF_SysInfoType1;
break;
case SIB_Type_systemInformationBlockType3:
sibInfo.sibDesType = &asn_DEF_SysInfoType3;
break;
case SIB_Type_systemInformationBlockType5:
sibInfo.sibDesType = &asn_DEF_SysInfoType5;
break;
case SIB_Type_systemInformationBlockType7:
sibInfo.sibDesType = &asn_DEF_SysInfoType7;
break;
case SIB_Type_systemInformationBlockType12:
sibInfo.sibDesType = &asn_DEF_SysInfoType12;
break;
default:
break;
}
sibInfo.sibType = sib_Type;
sibInfo.sibCount = sibCount;
sibInfo.sibData[sibIdx] = BitBuffer_t(buf, size, lastSkipBits);
return sibInfo.sibDesType ? true : false;
}
static void check_bcch_message(L3DecodeSys_t &sys, BCCH_BCH_Message *msg)
{
// for test fixed
// 步长为2 -- Actual value SFN-Prime = 2 * IE value
sys.sfn = msg->message.sfn_Prime * 2;
// 计算CFN
// TS25.331 8.5.15 CELL_DCH
uint8_t cfn = ((sys.sfn - sys.doff / 38400) % 256);
if (cfn < sys.cfn)
{
// 溢出累计hfn
++sys.hfn_tm;
}
sys.cfn = cfn;
}
static string check_sib_message(L3DecodeSys_t &sys, BCCH_BCH_Message *msg)
{
// sib组包
switch (msg->message.payload.present)
{
case SystemInformation_BCH__payload_PR_completeSIB_List:
{
// 多个完整包
CompleteSIB_List_t *payload = &msg->message.payload.choice.completeSIB_List;
for (int i = 0; i < payload->list.count; i++)
{
CompleteSIBshort *completeSIBshort = payload->list.array[i];
long sib_Type = completeSIBshort->sib_Type;
uint8_t *buf = completeSIBshort->sib_Data_variable.buf;
int size = completeSIBshort->sib_Data_variable.size;
int lastSkipBits = completeSIBshort->sib_Data_variable.bits_unused;
SIBInfo_t sibInfo;
if (set_sib_info(sibInfo, sib_Type, 1, 0, buf, size, lastSkipBits))
{
sys.sibList.push_back(sibInfo);
}
}
break;
}
case SystemInformation_BCH__payload_PR_firstSegment:
case SystemInformation_BCH__payload_PR_subsequentSegment:
case SystemInformation_BCH__payload_PR_lastSegmentShort:
{
switch (msg->message.payload.present)
{
case SystemInformation_BCH__payload_PR_firstSegment:
{
// 第一个包,新建
FirstSegment_t *firstSegment = &msg->message.payload.choice.firstSegment;
SIB_Data_fixed_t *sib_Data_fixed = &firstSegment->sib_Data_fixed;
long sib_Type = firstSegment->sib_Type;
uint8_t *buf = sib_Data_fixed->buf;
int size = sib_Data_fixed->size;
int count = firstSegment->seg_Count;
int lastSkipBits = sib_Data_fixed->bits_unused;
SIBInfo_t sibInfo;
if (set_sib_info(sibInfo, sib_Type, count, 0, buf, size, lastSkipBits))
{
sys.sibList.push_back(sibInfo);
}
break;
}
case SystemInformation_BCH__payload_PR_subsequentSegment:
{
// 中间包,插入
SubsequentSegment *subsequentSegment = &msg->message.payload.choice.subsequentSegment;
SIB_Data_fixed_t *sib_Data_fixed = &subsequentSegment->sib_Data_fixed;
long sib_Type = subsequentSegment->sib_Type;
uint8_t *buf = sib_Data_fixed->buf;
int size = sib_Data_fixed->size;
int idx = subsequentSegment->segmentIndex;
int lastSkipBits = sib_Data_fixed->bits_unused;
for (size_t i = 0; i < sys.sibList.size(); i++)
{
if (sys.sibList[i].sibType == sib_Type)
{
sys.sibList[i].sibData[idx] = BitBuffer_t(buf, size, lastSkipBits);
break;
}
}
break;
}
case SystemInformation_BCH__payload_PR_lastSegmentShort:
{
// 结束包,插入
LastSegmentShort_t *lastSegmentShort = &msg->message.payload.choice.lastSegmentShort;
SIB_Data_variable_t *sib_Data_variable = &lastSegmentShort->sib_Data_variable;
long sib_Type = lastSegmentShort->sib_Type;
uint8_t *buf = sib_Data_variable->buf;
int size = sib_Data_variable->size;
int idx = lastSegmentShort->segmentIndex;
int lastSkipBits = sib_Data_variable->bits_unused;
for (size_t i = 0; i < sys.sibList.size(); i++)
{
if (sys.sibList[i].sibType == sib_Type)
{
sys.sibList[i].sibData[idx] = BitBuffer_t(buf, size, lastSkipBits);
break;
}
}
break;
}
default:
break;
}
break;
}
default:
break;
}
// sib解码
string sibDes;
for (vector<SIBInfo_t>::iterator itSibInfo = sys.sibList.begin(); itSibInfo != sys.sibList.end(); )
{
if (itSibInfo->sibCount == itSibInfo->sibData.size()) // 完成组包
{
// 获取数据字节长度
int sibBitsLen = 0;
for (map<int, BitBuffer_t>::iterator itSibData = itSibInfo->sibData.begin();
itSibData != itSibInfo->sibData.end();
++itSibData)
{
sibBitsLen += itSibData->second.GetDataBits();
}
// 初始化数据缓存
Buffer_t sibData;
bs_s bits;
sibData.Allocate((sibBitsLen + 7) / 8);
memset(sibData.m_pBuffer, 0, sibData.m_nBufferSize);
bs_init(&bits, sibData.m_pBuffer, sibData.m_nBufferSize);
// 循环组包
for (map<int, BitBuffer_t>::iterator itSibData = itSibInfo->sibData.begin();
itSibData != itSibInfo->sibData.end();
++itSibData)
{
write_bits(bits, itSibData->second.m_pData, itSibData->second.GetDataBits());
}
// 解码sib
string rrcDes = l3_decode_rrc(sibData.m_pData, sibBitsLen, 0, itSibInfo->sibDesType, NULL);
if (rrcDes.size())
sibDes += rrcDes;
itSibInfo = sys.sibList.erase(itSibInfo);
}
else
++itSibInfo;
}
return sibDes;
}
static void l3_decode_pdu(L3DecodeSys_t &sys, PDUData_t& info)
{
char text[256];
map<size_t, PDU_CH_SN_Data_t> *pduSNList = NULL;
Buffer_t nasMessage;
// 重发确认包不用解析
if (info.isRepeatedSN)
return;
if (info.chType == CH_TYPE_BCH)
pduSNList = &sys.bchPDUSNList;
else if (info.chType == CH_TYPE_FACH)
pduSNList = &sys.fachPDUSNList;
else if (info.chType == CH_TYPE_DPCH)
pduSNList = &sys.dpchPDUSNList;
else
return;
for (map<uint32_t, PDU_CH_SN_Data_t>::iterator pCH = pduSNList->begin();
pCH != pduSNList->end(); pCH++)
{
vector<BitBuffer_t>& pduDataList = pCH->second.pduDataList;
for (UINT i = 0; i < pduDataList.size(); i++)
{
string textHex;
string textRrc;
string textSib;
string decodeInfo;
void *msg = 0;
textHex = Data2Text("Hex", pduDataList[i], pduDataList[i].GetDataBits());
textRrc = l3_decode_rrc(pduDataList[i].m_pData, pduDataList[i].GetDataBits(), 0, info.desType, &msg);
if (msg && info.desType == &asn_DEF_BCCH_BCH_Message)
{
// 获取SFN
check_bcch_message(sys, (BCCH_BCH_Message *)msg);
// 组包并解码sib
textSib = check_sib_message(sys, (BCCH_BCH_Message *)msg);
}
if (msg && info.desType == &asn_DEF_DL_CCCH_Message)
{
// 检查释放f8加密状态
check_rrc_connect_release(sys, (DL_CCCH_Message *)msg);
// 检查释放f8加密状态,获取dpch-FrameOffset
uint32_t tmsi = check_rrc_connect_setup(sys, (DL_CCCH_Message *)msg, decodeInfo);
// TMSI过滤
if (sys.tmsiFilter && tmsi)
{
if (sys.tmsiFilter != tmsi)
{
textRrc = "<RRCConnectionSetup> TMSI filter, Can be to ignore...\n";
}
}
}
nasMessage.ClearData();
if (msg && info.desType == &asn_DEF_DL_DCCH_Message)
{
// 获取鉴权随机数
check_downlink_direct_transfer(sys, (DL_DCCH_Message *)msg, nasMessage, decodeInfo);
// 检查释放f8加密状态
check_rrc_connect_release(sys, (DL_DCCH_Message *)msg);
// 检查进入加密状态
check_security_mode_command(sys, (DL_DCCH_Message *)msg, decodeInfo);
// 获取RB通道配置
check_radio_bearer_setup(sys, (DL_DCCH_Message *)msg, decodeInfo);
// 获取RB通道重配置
check_radio_bearer_reconfiguration(sys, (DL_DCCH_Message *)msg, decodeInfo);
}
if (info.desType && msg)
ASN_STRUCT_FREE(*info.desType, msg);
// 过滤RRC信息
if (sys.rrcInfoFilter)
{
#define FILTER_RRC_TEXT(t)\
if (t.size()){\
int split = t.find('\n');\
if (split > 0)\
t.erase(split, t.size() - 1 - split);\
}\
FILTER_RRC_TEXT(textRrc);
FILTER_RRC_TEXT(textSib);
}
// 输出明文和RRC解码消息
if (textHex.size())
{
sys.rrc_decode_info += "RRC:" + textHex + '\n' + textRrc;
}
// 输出SIB解码消息
if (textSib.size())
{
sys.rrc_decode_info += "SIB:" + textSib;
}
// 输出BCH的SFN日志
if (info.desType == &asn_DEF_BCCH_BCH_Message)
{
snprintf(text, 256, "SFN-Prime:%u CFN:%hhu HFN:%u\n", sys.sfn, sys.cfn, sys.hfn_tm);
sys.rrc_decode_info += text;
}
// 输出短消息的NASMessage
if (nasMessage.m_nDataSize)
{
string sms = decode_sms(nasMessage);
sys.rrc_decode_info += "NASMessage:" + Data2Text("Hex", nasMessage.m_pData, nasMessage.m_nDataSize * 8) + "\n";
if (sms.size())
{
decodeInfo += "SMSMessage:\n" + sms + '\n';
}
}
// 记录解码日志
sys.rrc_decode_info += decodeInfo;
sys.rrc_decode_info_simplify += decodeInfo;
}
// 解析后即清理
pduDataList.clear();
}
return;
}
static void f8_ciphering(L3DecodeSys_t &sys, PDUData_t& pduInfo, int ch, int sn)
{
if (!sys.isF8Ciphering)
return;
// F8解密
pduInfo.dataF8PDU = pduInfo.dataPDU;
// 查找解密作用域对应的CK
map<int, vector<uint8_t>>::iterator pCK = sys.cn_Domain_ck.find(sys.cn_DomainIdentity);
if (pCK == sys.cn_Domain_ck.end())
return;
vector<uint8_t> ck = pCK->second;
// AM/UM模式,Bearer使用逻辑通道号查询rb id并-1
// TS25.331 8.6.4.3
// start to perform ciphering on the radio bearer in lower layers, using the value of the IE "RB identity" minus
// one as the value of BEARER in the ciphering algorithm.
int bearer = sys.trRbChMap[ch] - 1;
// pduInfo.modeRLC == "AM"
int c = (sys.hfn_am << 12); // HFN 20位
c |= (sn & 0xFFF); // RLC SN 12位
if (pduInfo.modeRLC == "UM")
{
c = (sys.hfn_um << 7); // HFN 25位
c |= (sn & 0x7F); // RLC SN 7位
}
else if (pduInfo.modeRLC == "TM")
{
// 提前到来的语音数据会干扰hfn起始值计算
if (!sys.radioBearerSetup && !sys.radioBearerReconfiguration)
return;
if (!sys.bVoiceData)
{
if (!sys.radioBearerReconfiguration)
sys.hfn_tm -= 1; // ??? fixed it,目前可能拿不到RADIO BEARER RECONFIGURATION消息,暂用-1方案
sys.hfn_tm |= ((sys.start + 2) << 4); // TM模式下HFN 24位,取START 20位在高位
sys.bVoiceData = true;
}
c = sys.hfn_tm << 8; // HFN 24位
c |= (sys.cfn & 0xFF); // CFN 8位
// 根据数据大小查询逻辑通道id
long tr_id = sys.trSizeMap[pduInfo.dataF8PDU.GetDataBits()];
// 使用逻辑通道id查询无线承载id
long rb_id = sys.trRbChMap[tr_id];
// Bearer使用查询的无线承载id并-1
// TS25.331 8.6.4.3
// start to perform ciphering on the radio bearer in lower layers, using the value of the IE "RB identity" minus
// one as the value of BEARER in the ciphering algorithm.
bearer = rb_id - 1;
}
// 生成f8明文
f8(&ck[0], c, bearer, sys.direction,
pduInfo.dataF8PDU.m_pData, pduInfo.dataF8PDU.GetDataBits());
}
static void save_voice_file(L3DecodeSys_t &sys, PDUData_t& pduInfo)
{
BitBuffer_t &f8Data = pduInfo.dataF8PDU;
if (!f8Data.m_nDataSize)
return;
if (!sys.fdVoiceFile.is_open())
{
sys.fdVoiceFile.open(VOICE_FILE_OUT_NAME, ios::out | ios::binary);
if (!sys.fdVoiceFile.is_open())
return;
sys.fdVoiceFile.write("#!AMR\n", 6);
sys.rrc_decode_info_simplify += "Begin Save Voice AMR Data.\n";
}
if (f8Data.GetDataBits() == 81)
{
int frameLen = 1 + (244 + 7) / 8;
// 重置buff
sys.buffVoice.resize(frameLen);
memset(&sys.buffVoice[0], 0, frameLen);
bs_init(&sys.bitsVoice, &sys.buffVoice[0], frameLen);
// 设置头部
uint8_t amrHeader = 0x3C;
bs_write(&sys.bitsVoice, 8, amrHeader);
}
// 设置数据
write_bits(sys.bitsVoice, f8Data.m_pData, f8Data.GetDataBits());
if (f8Data.GetDataBits() == 60)
{
// 写入文件
sys.fdVoiceFile.write((const char *)&sys.buffVoice[0], sys.buffVoice.size());
}
}
static int l3_combine_pdu(L3DecodeSys_t &sys, PDUData_t& pduInfo)
{
char text[256];
// int: ch
map<size_t, PDU_CH_SN_Data_t> *pduSNList = NULL;
if (pduInfo.chType == CH_TYPE_BCH)
pduSNList = &sys.bchPDUSNList;
else if (pduInfo.chType == CH_TYPE_FACH)
pduSNList = &sys.fachPDUSNList;
else if (pduInfo.chType == CH_TYPE_DPCH)
pduSNList = &sys.dpchPDUSNList;
else
return -1;
// TM不参与组包流程
if (pduInfo.modeRLC == "TM")
{
// 语音数据需要F8解密,不参与解包
if (pduInfo.chType == CH_TYPE_DPCH)
{
f8_ciphering(sys, pduInfo, -1, -1);
return 0;
}
// TM数据直接参与解包
if (pduInfo.dataF8PDU.m_nDataSize)
(*pduSNList)[0].pduDataList.push_back(pduInfo.dataF8PDU);
else
(*pduSNList)[0].pduDataList.push_back(pduInfo.dataPDU);
return 0;
}
// 控制报文不参与组包流程
if (pduInfo.desRLC.find("ControlType") != -1)
{
return 0;
}
int ch = -1;
int sn = -1;
// 没有逻辑通道的数据在-1通道上组包
ch = get_des_field_number("LogicalChannel:", pduInfo.desMAC);
// 必须有序号才能按序组包
sn = get_des_field_number("SequenceNumber:", pduInfo.desRLC);
if (sn < 0)
return -1;
int ret = -1;
do
{
if (sn > -1 && sn == (*pduSNList)[ch].sn)
{
// 重复包不参与组包流程
pduInfo.isRepeatedSN = true;
snprintf(text, 256, "Repeated SequenceNumber(LogicalChannel:%d SN:%d).\n", ch, sn);
sys.rrc_decode_info += text;
return 0;
}
// 检查组包序号
if (0 == sn)
{
// 重新开始组包
(*pduSNList)[ch].data.ClearData();
}
else if (sn != (*pduSNList)[ch].sn + 1)
{
// 非连续包
(*pduSNList)[ch].data.ClearData();
snprintf(text, 256, "SN is not continuity(LogicalChannel:%d SN:%d->%d).Restart combine PDU.\n",
ch, sn, (*pduSNList)[ch].sn + 1);
sys.rrc_decode_info += text;
}
(*pduSNList)[ch].sn = sn;
// F8加密状态
if (pduInfo.desType == &asn_DEF_DL_DCCH_Message)
{
// ch 1 - 4
if (ch > -1 && (int)sys.f8CipheringActiveTimeList.size() >= ch && sn >= sys.f8CipheringActiveTimeList[ch])
{
f8_ciphering(sys, pduInfo, ch, sn);
}
}
BYTE* pData = (pduInfo.dataF8PDU.m_nDataSize) ? pduInfo.dataF8PDU.m_pData : pduInfo.dataPDU.m_pData;
int dataLen = pduInfo.dataPDU.m_nDataSize;
// 序号连续,进入组包
//int p = get_des_field_number(_T("P:"), pduInfo.desRLC);
int e = get_des_field_number("E:", pduInfo.desRLC);
// 有长度指示器
if (e > 0)
{
// 循环读取长度指示器
vector<uint8_t> liLenList;
for (int i = 0; i < dataLen; i++)
{
BYTE liLen = pData[i] >> 1;
bool e = (pData[i] & 0x1) > 0 ? true : false;
liLenList.push_back(liLen);
if (!e) // 结束
break;
}
// 数据长度有问题????
if (liLenList.size() == 0)
{
snprintf(text, 256, "Length Indicator count(%u) is Zero.\n", liLenList.size());
sys.rrc_decode_info += text;
break;
}
// 长度指示器目前观察不会超过3个
if (liLenList.size() > 3)
{
snprintf(text, 256, "Length Indicator count(%u) is too more.\n", liLenList.size());
sys.rrc_decode_info += text;
break;
}
if (pduInfo.modeRLC == "UM")
{
// UM长度指示器为1111100时为数据包开始
if (liLenList[0] == 0x7C)
{
int nLen = dataLen - liLenList.size();
(*pduSNList)[ch].data.FillData(pData + liLenList.size(), nLen);
// 有第2段长度指示器,使用指定的长度结束
if (liLenList.size() > 1 && liLenList[1] <= nLen)
{
(*pduSNList)[ch].data.m_nDataSize = liLenList[1];
(*pduSNList)[ch].pduDataList.push_back((*pduSNList)[ch].data);
(*pduSNList)[ch].data.ClearData();
}
}
// UM长度指示器为0时数据包结束
else if (liLenList[0] == 0)
{
(*pduSNList)[ch].pduDataList.push_back((*pduSNList)[ch].data);
(*pduSNList)[ch].data.ClearData();
}
}
else
{
// 长度指示器分段
int li1 = (liLenList[0] > dataLen - liLenList.size()) ? 0 : liLenList[0];
int li2 = (liLenList.size() > 1) ? liLenList[1] : 0;
// AM第一个长度指示器指示当前包结束位置
(*pduSNList)[ch].data.AppendData(pData + liLenList.size(), li1);
(*pduSNList)[ch].pduDataList.push_back((*pduSNList)[ch].data);
(*pduSNList)[ch].data.ClearData();
int nLen2 = dataLen - liLenList.size() - li1;
if (li2 != 0x7F) // 1111111
{
// 记录后半截数据整段数,不包括pading
(*pduSNList)[ch].data.FillData(pData + liLenList.size() + li1, nLen2);
}
// 有正确的第二个长度指示器
if (li2 > 0 && li2 <= nLen2)
{
// 第二个包结束,使用li2长度重新记录后半截数据
(*pduSNList)[ch].data.m_nDataSize = li2;
(*pduSNList)[ch].pduDataList.push_back((*pduSNList)[ch].data);
(*pduSNList)[ch].data.ClearData();
}
}
}
else
{
// 没有长度指示器,整段数据纳入当前包
(*pduSNList)[ch].data.AppendData(pData, dataLen);
}
ret = 0;
} while (false);
return ret;
}
static void l3_decode_rlc(string& desRLC, const string& pdu_mode, bs_t& bs, bs_t& bsRLC, UINT& lenRLC)
{
char text[MAX_PATH];
// 判断MAC Header
if (pdu_mode == "UM")
{
//读取RLC Sequence Number和E结束标志
UINT16 sn = bs_read_data(bs, bsRLC, 7, lenRLC);
BYTE e = bs_read_data(bs, bsRLC, 1, lenRLC);
_snprintf(text, MAX_PATH, "SequenceNumber:%hu E:%C", sn, (e > 0) ? '1' : '0');
desRLC += text;
#if 0
// 循环读取Length Indicator
while (e)
{
BYTE li = bs_read_data(bs, bsRLC, 7, lenRLC);
e = bs_read_data(bs, bsRLC, 1, lenRLC);
fachInfo.desRLC += get_li_des(li);
}
#endif
}
else if (pdu_mode == "AM")
{
BYTE dc = bs_read_data(bs, bsRLC, 1, lenRLC);
if (dc > 0)
{
// Data PDU
UINT sn = bs_read_data(bs, bsRLC, 12, lenRLC);
UINT p = bs_read_data(bs, bsRLC, 1, lenRLC);
UINT he = bs_read_data(bs, bsRLC, 2, lenRLC);
UINT e = (he & 0x1);
_snprintf(text, MAX_PATH, "SequenceNumber:%u P:%C HE:%x ", sn, (p > 0) ? '1' : '0', he);
desRLC += text;
#if 0
while (e)
{
if (bs.p >= bs.p_end)
break;
BYTE li = bs_read_data(bs, bsRLC, 7, lenRLC);
e = bs_read_data(bs, bsRLC, 1, lenRLC);
fachInfo.desRLC += get_li_des(li);
}
#endif
}
else
{
// Control PDU
UINT pdu_type = bs_read_data(bs, bsRLC, 3, lenRLC);
BYTE sufi_type = 0;
BYTE sufi_len = 0;
UINT16 sufi_sn = 0;
switch (pdu_type)
{
case 0:
desRLC += " ControlType:STATUS";
sufi_type = bs_read_data(bs, bsRLC, 4, lenRLC);
if (!sufi_type)
{
strcpy(text, " NO_MORE");
desRLC += text;
}
while (sufi_type)
{
if (sufi_type == 1)
{
//0001 Window Size(WINDOW)
sufi_sn = bs_read_data(bs, bsRLC, 12, lenRLC);
_snprintf(text, MAX_PATH, " Window:%hu", sufi_sn);
desRLC += text;
}
else if (sufi_type == 2)
{
//0010 Acknowledgement(ACK)
sufi_sn = bs_read_data(bs, bsRLC, 12, lenRLC);
_snprintf(text, MAX_PATH, " ACK:%hu", sufi_sn);
desRLC += text;
}
else if (sufi_type == 3)
{
//0011 List(LIST)
sufi_len = bs_read_data(bs, bsRLC, 4, lenRLC);
_snprintf(text, MAX_PATH, " LIST:%hhu", sufi_len);
desRLC += text;
#if 0
for (BYTE i = 0; i < sufi_len; i++)
{
UINT16 list_sni = bs_read_data(bs, bsRLC, 12, lenRLC);
BYTE list_li = bs_read_data(bs, bsRLC, 4, lenRLC);
_snprintf(text, MAX_PATH, "[%hu:%hhu]", list_sni, list_li);
desRLC += text;
}
#endif
}
else if (sufi_type == 4)
{
//0100 Bitmap(BITMAP)
sufi_len = bs_read_data(bs, bsRLC, 4, lenRLC);
_snprintf(text, MAX_PATH, " BITMAP:%hhu", sufi_len);
desRLC += text;
#if 0
for (BYTE i = 0; i < sufi_len; i++)
{
UINT16 bmp_fsn = bs_read_data(bs, bsRLC, 12, lenRLC);
bs_read_data(bs, bsRLC, bmp_fsn, lenRLC);
_snprintf(text, MAX_PATH, "[%hu]", bmp_fsn);
desRLC += text;
}
#endif
}
else if (sufi_type == 5)
{
//0101 Relative list(Rlist)
sufi_len = bs_read_data(bs, bsRLC, 4, lenRLC);
sufi_sn = bs_read_data(bs, bsRLC, 12, lenRLC);
_snprintf(text, MAX_PATH, " Rlist:0x%hhu %hu", sufi_len, sufi_sn);
desRLC += text;
#if 0
for (BYTE i = 0; i < sufi_len; i++)
{
BYTE rlist_cw = bs_read_data(bs, bsRLC, 4, lenRLC);
_snprintf(text, MAX_PATH, "[%hhu]", rlist_cw);
desRLC += text;
}
#endif
}
else if (sufi_type == 6)
{
//0110 Move Receiving Window(MRW)
sufi_len = bs_read_data(bs, bsRLC, 4, lenRLC);
sufi_sn = bs_read_data(bs, bsRLC, 12, lenRLC);
_snprintf(text, MAX_PATH, " MRW:0x%hhu %hu", sufi_len, sufi_sn);
desRLC += text;
}
else if (sufi_type == 7)
{
//0111 Move Receiving Window Acknowledgement (MRW_ACK)
sufi_len = bs_read_data(bs, bsRLC, 4, lenRLC);
_snprintf(text, MAX_PATH, " MRW_ACK:0x%hhx", sufi_len);
desRLC += text;
#if 0
for (BYTE i = 0; i < sufi_len; i++)
{
UINT16 mrw_ack_sn = bs_read_data(bs, bsRLC, 12, lenRLC);
_snprintf(text, MAX_PATH, "[%hu]", mrw_ack_sn);
desRLC += text;
}
for (BYTE i = 0; i < sufi_len; i++)
{
BYTE mrw_ack_len = bs_read_data(bs, bsRLC, 4, lenRLC);
_snprintf(text, MAX_PATH, "[%hu]", mrw_ack_len);
desRLC += text;
}
#endif
}
else if (sufi_type == 8)
{
//1000 Poll(POLL)
sufi_sn = bs_read_data(bs, bsRLC, 12, lenRLC);
_snprintf(text, MAX_PATH, " POLL:%hu", sufi_sn);
desRLC += text;
}
else
break;
if (bs_eof(&bs))
break;
sufi_type = bs_read_data(bs, bsRLC, 4, lenRLC);
}
break;
case 1:
desRLC += " ControlType:RESET";
break;
case 2:
desRLC += " ControlType:RESET ACK";
break;
}
}
}
}
//////////////////////////////////////////////////////////////////////////
string l3_decode_bch(BitBuffer_t& dataPDU, PDUData_t& pduInfo)
{
char text[MAX_PATH];
string des;
if (dataPDU.GetDataBits() < DATA_LENGTH_BCH)
{
_snprintf(text, MAX_PATH, "Data length(%u-%u bits) is too short.", dataPDU.GetDataBits(), DATA_LENGTH_BCH);
return text;
}
pduInfo.desType = &asn_DEF_BCCH_BCH_Message;
pduInfo.desRLC = "Mode:TM";
pduInfo.modeRLC = "TM";
pduInfo.dataPDU = dataPDU;
dataPDU.Free();
return des;
}
string l3_decode_fach(BitBuffer_t& dataPDU, PDUData_t& pduInfo)
{
char text[MAX_PATH];
string des;
if (dataPDU.GetDataBits() < DATA_LENGTH_FACH)
{
_snprintf(text, MAX_PATH, "Data length(%u bits) is too short.", dataPDU.GetDataBits());
return text;
}
bs_t bs;
bs_init(&bs, dataPDU.m_pData, dataPDU.m_nDataSize);
pduInfo.dataMAC.Allocate(5);
memset(pduInfo.dataMAC.m_pBuffer, 0, 5);
bs_t bsMAC;
bs_init(&bsMAC, pduInfo.dataMAC.m_pBuffer, 5);
pduInfo.dataRLC.Allocate(20);
memset(pduInfo.dataRLC.m_pBuffer, 0, 20);
bs_t bsRLC;
bs_init(&bsRLC, pduInfo.dataRLC.m_pBuffer, 20);
UINT ct = 0;
string rlcMode = "TM";
UINT nMACBits = 0;
// BCCH
if ((dataPDU.m_pData[0] >> 6) == 0x00)
{
pduInfo.desType = &asn_DEF_BCCH_FACH_Message;
pduInfo.desMAC += pduInfo.desType->name;
// skip TCTF
bs_read_data(bs, bsMAC, 2, nMACBits);
}
// CCCH
else if (dataPDU.m_pData[0] == 0x40)
{
pduInfo.desType = &asn_DEF_DL_CCCH_Message;
pduInfo.desMAC += pduInfo.desType->name;
// skip TCTF
bs_read_data(bs, bsMAC, 8, nMACBits);
rlcMode = "UM";
}
// MCCH
else if (dataPDU.m_pData[0] == 0x50)
{
pduInfo.desType = &asn_DEF_MCCH_Message;
pduInfo.desMAC += pduInfo.desType->name;
// skip TCTF
bs_read_data(bs, bsMAC, 8, nMACBits);
}
// MSCH
else if (dataPDU.m_pData[0] == 0x5F)
{
pduInfo.desType = &asn_DEF_MCCH_Message;
pduInfo.desMAC += pduInfo.desType->name;
// skip TCTF
bs_read_data(bs, bsMAC, 8, nMACBits);
}
// MTCH
else if ((dataPDU.m_pData[0] >> 4) == 0x6)
{
//pduInfo.desType = &asn_DEF_MTCH_Message;
pduInfo.desMAC += "MTCH";//pduInfo.desType->name;
// skip TCTF
bs_read_data(bs, bsMAC, 2, nMACBits);
}
// CTCH
else if (dataPDU.m_pData[0] == 0x80)
{
//pduInfo.desType = &asn_DEF_CTCH_Message;
pduInfo.desMAC += "CTCH";//pduInfo.desType->name;
// skip TCTF
bs_read_data(bs, bsMAC, 8, nMACBits);
}
// DCCH/DTCH voer FACH
else if ((dataPDU.m_pData[0] >> 6) == 0x3)
{
UINT32 n;
// skip TCTF
bs_read_data(bs, bsMAC, 2, nMACBits);
// skip UI-Type
n = bs_read_data(bs, bsMAC, 2, nMACBits);
// skip UE-Id
string ui_type;
UINT32 ui_id = 0;
if (n > 0)
{
// C-RNTI
ui_id = bs_read_data(bs, bsMAC, 16, nMACBits);
ui_type = "C-RNIT";
}
else
{
// U-RNTI
ui_id = bs_read_data(bs, bsMAC, 32, nMACBits);
ui_type = "U-RNIT";
}
// skip C/T
ct = bs_read_data(bs, bsMAC, 4, nMACBits);
// C/T决定PDU Type
rlcMode = "AM";
if (ct > 14)
{
//pduInfo.desType = &asn_DEF_DL_DCCH_Message; // DTCH ??
pduInfo.desMAC += "DTCH";
rlcMode = "TM";
}
else
{
pduInfo.desType = &asn_DEF_DL_DCCH_Message;
pduInfo.desMAC += pduInfo.desType->name;
//if (ct < 1)
// pdu_mode = _T("UM");
//else
rlcMode = "AM";
}
_snprintf(text, MAX_PATH, " %s UE-Id:%u ", ui_type.c_str(), ui_id);
pduInfo.desMAC += text;
_snprintf(text, MAX_PATH, "LogicalChannel:%u ", ct + 1);
pduInfo.desMAC += text;
}
else
{
pduInfo.desType = 0;
pduInfo.desMAC += "Unknow TCTF";
}
if (pduInfo.desType)
{
_snprintf(text, MAX_PATH, "Mode:%s ", rlcMode.c_str());
pduInfo.desRLC += text;
}
pduInfo.dataMAC.m_nDataSize = (nMACBits + 7) / 8;
pduInfo.modeRLC = rlcMode;
// 解码RLC
UINT nRLCBits = 0;
s_sprintf(&pduInfo.desRLC, "Mode:%s ", rlcMode.c_str());
l3_decode_rlc(pduInfo.desRLC, rlcMode, bs, bsRLC, nRLCBits);
pduInfo.dataRLC.m_nDataSize = (nRLCBits + 7) / 8;
BYTE byteRead;
int dataBits = DATA_LENGTH_FACH - nMACBits - nRLCBits;
while (dataBits > 0)
{
int nRead = (dataBits >= 8) ? 8 : dataBits;
byteRead = bs_read(&bs, nRead);
pduInfo.dataPDU.AppendData(&byteRead, 1);
dataBits -= nRead;
}
dataPDU.Free();
return des;
}
string l3_decode_dpch(BitBuffer_t& dataPDU, PDUData_t& pduInfo)
{
string des;
char text[MAX_PATH];
if (dataPDU.GetDataBits() < 8)
{
_snprintf(text, MAX_PATH, "Data length(%u bits) is too short.", dataPDU.GetDataBits());
dataPDU.ClearData();
return text;
}
pduInfo.dataMAC.Allocate(1);
memset(pduInfo.dataMAC.m_pBuffer, 0, 1);
bs_t bsMAC;
bs_init(&bsMAC, pduInfo.dataMAC.m_pBuffer, 1);
pduInfo.dataRLC.Allocate(20);
memset(pduInfo.dataRLC.m_pBuffer, 0, 20);
bs_t bsRLC;
bs_init(&bsRLC, pduInfo.dataRLC.m_pBuffer, 20);
bs_t bs;
bs_init(&bs, dataPDU.m_pData, dataPDU.m_nDataSize);
UINT ct = 0;
UINT nMACBits = 0;
UINT nRLCBits = 0;
if (dataPDU.GetDataBits() != DATA_LENGTH_DPCH)
{
// 通过长度判断语音数据
pduInfo.modeRLC = "TM";
}
else
{
// C/T
ct = bs_read_data(bs, bsMAC, 4, nMACBits);
s_sprintf(&pduInfo.desMAC, "LogicalChannel:%u ", ct + 1);
// 信令数据,C/T决定PDU Type
if (ct > 0)
{
pduInfo.modeRLC = "AM";
}
else
{
pduInfo.modeRLC = "UM";
}
// DCCH/DTCH
pduInfo.desType = &asn_DEF_DL_DCCH_Message;
pduInfo.dataMAC.m_nDataSize = (nMACBits + 7) / 8;
// 解码RLC
s_sprintf(&pduInfo.desRLC, "Mode:%s ", pduInfo.modeRLC.c_str());
l3_decode_rlc(pduInfo.desRLC, pduInfo.modeRLC, bs, bsRLC, nRLCBits);
pduInfo.dataRLC.m_nDataSize = (nRLCBits + 7) / 8;
}
BYTE byteRead;
int nDataBits = dataPDU.GetDataBits() - nMACBits - nRLCBits;
while (nDataBits > 0)
{
int nRead = (nDataBits >= 8) ? 8 : nDataBits;
byteRead = bs_read(&bs, nRead);
pduInfo.dataPDU.AppendData(&byteRead, 1);
nDataBits -= nRead;
}
pduInfo.dataPDU.m_nLastSkipBits = dataPDU.m_nLastSkipBits;
dataPDU.Free();
return des;
}
void ReadBitsFile(ifstream &fd, multimap<DWORD, PDULineInfo_t> &pduLineList)
{
string line;
uint32_t idx;
DWORD tcCode = 0;
char lastCRC = '0';
while (getline(fd, line))
{
if (line.size() > 1024)
continue;
PDULineInfo_t lineInfo;
// 读取时码
idx = line.find("cfn:");
if (idx != line.npos)
{
sscanf(line.c_str() + idx + strlen("cfn:"), " %u ", &tcCode);
}
lineInfo.timeCode.cfn = tcCode;
// 读取时间
idx = line.find("ts:");
if (idx != line.npos)
{
sscanf(line.c_str() + idx + strlen("ts:"), " %hu:%hu:%hu ",
&lineInfo.timeCode.wHour, &lineInfo.timeCode.wMinute, &lineInfo.timeCode.wSecond);
}
// 数据长度
uint32_t pduBitsLen = 0;
bool isNoCRC = false;
if (line.find("DL_BCCH_BCH") != line.npos)
{
lineInfo.chType = "DL_BCCH_BCH";
pduBitsLen = DATA_LENGTH_BCH;
}
else if (line.find("fach") != line.npos)
{
lineInfo.chType = "FACH";
pduBitsLen = DATA_LENGTH_FACH;
}
else if (line.find("dpch") != line.npos)
{
lineInfo.chType = "DPCH";
pduBitsLen = DATA_LENGTH_DPCH;
// 读取通道
idx = line.find("channel");
if (idx != line.npos)
{
sscanf(line.c_str() + idx, "channel %hhu:",
&lineInfo.chIdx);
}
// 读取长度
idx = line.find('-');
if (idx != line.npos)
{
uint32_t bitsIdx = line.find("bits", idx);
if (bitsIdx != line.npos)
{
sscanf(line.c_str() + idx, "- %u bits:",
&pduBitsLen);
// 没有crc校验
if (pduBitsLen == 103 || pduBitsLen == 60)
{
// 以上一次校验为准
if (lastCRC == '1')
isNoCRC = true;
}
line.erase(0, bitsIdx + 5);
}
}
if (!pduBitsLen)
continue;
}
char crc1 = 0, crc2 = 0;
idx = line.find("bits:");
if (idx != line.npos)
{
line.erase(0, idx + 5);
}
// 读取CRC信息
idx = line.find("<-- data --- crc --> ");
if (idx != line.npos)
{
if (lineInfo.chType == "DL_BCCH_BCH")
{
sscanf(line.c_str() + idx + strlen("<-- data --- crc --> "),
"%c", &crc1);
line.erase(idx);
}
else if (lineInfo.chType == "FACH")
{
sscanf(line.c_str() + idx + strlen("<-- data --- crc --> "),
"%c %c", &crc1, &crc2);
line.erase(idx);
}
else if (lineInfo.chType == "DPCH")
{
if (sscanf(line.c_str() + idx + strlen("<-- data --- crc --> "), "%c", &crc1) > 0)
{
lastCRC = crc1;
}
line.erase(idx);
}
}
// 没有crc校验行
if (isNoCRC)
crc1 = '1';
// 根据长度读取bits数据
for (uint32_t i = 0, readLen = 0; i < line.size(); i++)
{
const char &crc_ok = (readLen < pduBitsLen) ? crc1 : crc2;
if (crc_ok == '1')
{
if (line[i] == '0' || line[i] == '1')
{
++readLen;
lineInfo.pduLine.push_back(line[i]);
}
if (lineInfo.pduLine.size() == pduBitsLen)
{
pduLineList.insert(make_pair(lineInfo.timeCode.cfn, lineInfo));
lineInfo.pduLine.clear(); // fach有两段数据,清空后继续读取
}
}
}
}
fd.close();
}
void L3Decode(L3DecodeSys_t &sys, multimap<DWORD, PDULineInfo_t> &pduLineList)
{
char t[MAX_PATH];
for (multimap<DWORD, PDULineInfo_t>::iterator ptrPDU = pduLineList.begin();
ptrPDU != pduLineList.end(); ptrPDU++)
{
PDULineInfo_t *pPDUInfo = &ptrPDU->second;
BitBuffer_t dataPDU;
Text2Data("Bits", pPDUInfo->pduLine.c_str(), dataPDU);
// Add ch type/time code info
_snprintf(t, MAX_PATH, "CFN:%u %hu:%hu:%hu %s_%hhu %ubits:",
pPDUInfo->timeCode.cfn,
pPDUInfo->timeCode.wHour,
pPDUInfo->timeCode.wMinute,
pPDUInfo->timeCode.wSecond,
pPDUInfo->chType.c_str(),
pPDUInfo->chIdx,
dataPDU.GetDataBits());
sys.rrc_decode_info += t;
// Add Hex Text msg
sys.rrc_decode_info += Data2Text("Hex", dataPDU, dataPDU.GetDataBits()) + "\n";
// Add MAC and RLC Dec
if (pPDUInfo->chType == CH_TYPE_BCH)
{
PDUData_t pduInfo;
pduInfo.chType = pPDUInfo->chType;
sys.rrc_decode_info += l3_decode_bch(dataPDU, pduInfo);
sys.rrc_decode_info += "RLC:" + Data2Text("Hex", pduInfo.dataRLC, pduInfo.dataRLC.m_nDataSize * 8) + " " + pduInfo.desRLC + "\n";
l3_combine_pdu(sys, pduInfo);
l3_decode_pdu(sys, pduInfo);
}
else if (pPDUInfo->chType == CH_TYPE_FACH)
{
PDUData_t pduInfo;
pduInfo.chType = pPDUInfo->chType;
sys.rrc_decode_info += l3_decode_fach(dataPDU, pduInfo);
sys.rrc_decode_info += "MAC:" + Data2Text("Hex", pduInfo.dataMAC, pduInfo.dataMAC.m_nDataSize * 8) + " " + pduInfo.desMAC + "\n";
sys.rrc_decode_info += "RLC:" + Data2Text("Hex", pduInfo.dataRLC, pduInfo.dataRLC.m_nDataSize * 8) + " " + pduInfo.desRLC + "\n";
sys.rrc_decode_info += "DATA:" + Data2Text("Hex", pduInfo.dataPDU, pduInfo.dataPDU.m_nDataSize * 8) + "\n";
l3_combine_pdu(sys, pduInfo);
l3_decode_pdu(sys, pduInfo);
}
else if (pPDUInfo->chType == CH_TYPE_DPCH)
{
PDUData_t pduInfo;
pduInfo.chType = pPDUInfo->chType;
sys.rrc_decode_info += l3_decode_dpch(dataPDU, pduInfo);
if (pduInfo.desType)
{
sys.rrc_decode_info += "MAC:" + Data2Text("Hex", pduInfo.dataMAC, pduInfo.dataMAC.m_nDataSize * 8) + " " + pduInfo.desMAC + "\n";
sys.rrc_decode_info += "RLC:" + Data2Text("Hex", pduInfo.dataRLC, pduInfo.dataRLC.m_nDataSize * 8) + " " + pduInfo.desRLC + "\n";
sys.rrc_decode_info += "DATA:" + Data2Text("Hex", pduInfo.dataPDU, pduInfo.dataPDU.m_nDataSize * 8) + "\n";
}
l3_combine_pdu(sys, pduInfo);
if (sys.isF8Ciphering && pduInfo.dataF8PDU.m_nDataSize)
{
sys.rrc_decode_info += "F8 :" + Data2Text("Hex", pduInfo.dataF8PDU, pduInfo.dataF8PDU.GetDataBits()) + "\n";
}
if (pduInfo.desType)
{
l3_decode_pdu(sys, pduInfo);
}
else
{
// 保存解码语音数据
save_voice_file(sys, pduInfo);
}
}
// 换行
sys.rrc_decode_info += '\n';
}
}