1. 3GPP的文本格式
3GPP OTA的二进制数据,通过Wireshark(tshark)解析后可以生成文本格式,该文本格式的缩进是4空格。针对此4空格的格式,使用Python脚本可以获取感兴趣的数据段落。
对于数据段落可以根据自己的需求,使用正则表达式提取部分字段以方便查看。
2. 源码
2.1 提取感兴趣的字段
extract.py:
class ExtractMultiline(object):
'''
3GPP Decoder工具对OTA二进制数据解析,生成文本,该文本格式是4个空格的文本格式。
为方便解析该文本中的数据,我们需要对感兴趣的数据段落进行提取。
该类用于提取这些数据段落。
'''
def get_filecontent_lines(self, multilines_file):
'''
Parameters
----------
multilines_file : string
文件名称
Returns
-------
lines : string
文件内容
'''
f = open(multilines_file, 'r', encoding='UTF-8', errors='ignore')
lines = f.readlines()
f.close()
return lines
def get_multilines(self, entry_string, tag_string, lines):
'''
Parameters
----------
entry_string : string
如果该字符串包含在某行中,该行作为启动捕获期望获取的多行字符串的开始。该标记为避免(减少)直接使用tag_string引起的冲突。
tag_string : string
期望获取的多行字符串的标记
lines : string
输入的多行文本
Returns
-------
multilines_array : array
期望获取的多行字符串,有可能有多个,这里用array返回
'''
entry_flag = False
entry_nest_count = 0
nest_count = 0
multilines = []
multilines_array = []
tag_state = 'IDLE'
tag_count = 0
for line in lines:
spaceNum = len(line.rstrip()) - len(line.strip())
nest_count = int(spaceNum/4)
if entry_string == line.strip():
entry_flag = True
entry_nest_count = nest_count
elif entry_flag and nest_count <= entry_nest_count:
entry_flag = False
if entry_flag:
if tag_string in line:
tag_state = 'START'
tag_count = nest_count
elif tag_state == 'START' and nest_count <= tag_count:
tag_state = 'END'
if tag_state == 'START':
multilines.append(line)
if tag_state == 'END':
tag_state = 'IDLE'
multilines_array.append(multilines)
multilines = []
# 文件结束还处于START状态的特殊处理,表示该最后一段multilines也需要记录下来
if tag_state == 'START':
tag_state = 'IDLE'
multilines_array.append(multilines)
return multilines_array
if __name__ == '__main__':
extract_multiline = ExtractMultiline()
lines = extract_multiline.get_filecontent_lines(r'nr-ueCapabilityEnquiry.txt')
multilines_array = extract_multiline.get_multilines('ue-CapabilityRAT-RequestList:', 'UE-CapabilityRAT-Request', lines)
print(multilines_array)
2.2 例子
2.2.1 获取LTE能力请求信息中的Band信息
get_capability_enquiry_for_lte.py:
import re
from tools.extract import ExtractMultiline
class UeCapabilityEnquiryForLTE(object):
# 获取RAT类型列表
def get_rat(self, multilines):
re_rat_type = '\s*RAT-Type: (\S+) .+'
rat_type_list = []
for line in multilines:
m_rat_type = re.match(re_rat_type, line)
if m_rat_type:
rat_type_list.append(m_rat_type.group(1))
return rat_type_list
def analyse_ota(self, ota_file):
extract_multiline = ExtractMultiline()
lines = extract_multiline.get_filecontent_lines(ota_file)
multilines_array = extract_multiline.get_multilines('ueCapabilityEnquiry-r8', 'ue-CapabilityRequest:', lines)
rat_type_list = []
if len(multilines_array) >= 1:
rat_type_list = self.get_rat(multilines_array[0])
return rat_type_list
if __name__ == '__main__':
ue_capability_enquiry_for_lte = UeCapabilityEnquiryForLTE()
rat_type_list = ue_capability_enquiry_for_lte.analyse_ota(r'lte-ueCapabilityEnquiry.txt')
print(rat_type_list)
2.2.2 获取NR能力请求信息中的Band信息
get_capability_enquiry_for_nr.py:
import re
from tools.extract import ExtractMultiline
class UeCapabilityEnquiryForNR(object):
# 获取RAT类型列表
def get_rat(self, multilines_array):
re_rat_type = '\s*rat-Type: (\S+) .+'
rat_type_list = []
for multilines in multilines_array:
for line in multilines:
m_rat_type = re.match(re_rat_type, line)
if m_rat_type:
rat_type_list.append(m_rat_type.group(1))
return rat_type_list
def analyse_ota(self, ota_file):
extract_multiline = ExtractMultiline()
lines = extract_multiline.get_filecontent_lines(ota_file)
multilines_array = extract_multiline.get_multilines('ue-CapabilityRAT-RequestList:', 'UE-CapabilityRAT-Request', lines)
rat_type_list = self.get_rat(multilines_array)
return rat_type_list
if __name__ == '__main__':
ue_capability_enquiry_for_nr = UeCapabilityEnquiryForNR()
rat_type_list = ue_capability_enquiry_for_nr.analyse_ota(r'nr-ueCapabilityEnquiry.txt')
print(rat_type_list)
2.2.3 获取能力上报信息中的Band信息(包括CA和EN-DC信息)
get_capability_information.py:
import re
from tools.extract import ExtractMultiline
class UeCapabilityInformation(object):
# LTE Band list
def supported_band_list_eutra(self, multilines):
re_bandEUTRA = '\s*bandEUTRA: (\d*)'
bandlist = []
for line in multilines:
m_bandEUTRA = re.match(re_bandEUTRA, line)
if m_bandEUTRA:
bandlist.append(m_bandEUTRA.group(1))
return bandlist
# LTE Band list extend(v9e0)
def supported_band_list_eutra_v9e0(self, multilines):
re_bandEUTRA_v9e0 = '\s*bandEUTRA-v9e0: (\d*)'
bandlist_v9e0_str = ''
bandlist_v9e0 = []
for line in multilines:
if 'SupportedBandEUTRA-v9e0' in line:
bandlist_v9e0_str = bandlist_v9e0_str + ':B'
m_bandEUTRA_v9e0 = re.match(re_bandEUTRA_v9e0, line)
if m_bandEUTRA_v9e0:
bandlist_v9e0_str = bandlist_v9e0_str + m_bandEUTRA_v9e0.group(1)
if len(bandlist_v9e0_str) > 1:
bandlist_v9e0 = bandlist_v9e0_str[1:].split(':')
bandlist_v9e0 = [item.replace('B','') for item in bandlist_v9e0]
return bandlist_v9e0
# LTE CA band combination
def supported_band_combination_r10(self, multilines):
ca_array = []
ca_str = ''
re_bandEUTRA_r10 = '\s*bandEUTRA-r10: (\d*)'
re_ca_BandwidthClassUL_r10 = '\s*ca-BandwidthClassUL-r10: ([abcde]{1}) .+'
re_ca_BandwidthClassDL_r10 = '\s*ca-BandwidthClassDL-r10: ([abcde]{1}) .+'
for line in multilines:
m_bandEUTRA_r10 = re.match(re_bandEUTRA_r10, line)
m_ca_BandwidthClassUL_r10 = re.match(re_ca_BandwidthClassUL_r10, line)
m_ca_BandwidthClassDL_r10 = re.match(re_ca_BandwidthClassDL_r10, line)
if 'BandCombinationParameters-r10' in line:
ca_str = ca_str + ':'
if m_bandEUTRA_r10:
ca_str = ca_str + ';B' + m_bandEUTRA_r10.group(1)
if m_ca_BandwidthClassUL_r10:
ca_str = ca_str + '-UL' + m_ca_BandwidthClassUL_r10.group(1)
if m_ca_BandwidthClassDL_r10:
ca_str = ca_str + '-DL' + m_ca_BandwidthClassDL_r10.group(1)
if len(ca_str) > 1:
ca_array = ca_str[1:].split(':')
ca_array = [item[1:] for item in ca_array] # or item.replace(';','',1)
return ca_array
# LTE CA band extend
def supported_band_combination_v1090(self, multilines):
ca_extend_str = ''
ca_extend_array = []
re_bandEUTRA_v1090 = '\s*bandEUTRA-v1090: (\d*)'
for line in multilines:
m_bandEUTRA_v1090 = re.match(re_bandEUTRA_v1090, line)
if 'BandCombinationParameters-v1090' in line:
ca_extend_str = ca_extend_str + ':'
if 'BandParameters-v1090' in line:
ca_extend_str = ca_extend_str + ';'
if m_bandEUTRA_v1090:
ca_extend_str = ca_extend_str + m_bandEUTRA_v1090.group(1)
if len(ca_extend_str) > 1:
ca_extend_array = ca_extend_str[1:].split(':')
return ca_extend_array
# LTE CA set
def supported_band_combination_ext_r10(self, multilines):
ca_set_str = ''
ca_set_array = []
for line in multilines:
m = re.match('\s*supportedBandwidthCombinationSet-r10: ([0-9abcdefABCDEF]*) .*', line)
if 'BandCombinationParametersExt-r10' in line:
ca_set_str = ca_set_str + ':'
if m:
ca_set_str = ca_set_str + m.group(1)
if len(ca_set_str) > 1:
ca_set_array = ca_set_str[1:].split(':')
for index in range(0, len(ca_set_array)):
if ca_set_array[index] != '':
ca_set_array[index] = (bin(int(ca_set_array[index],16))).replace('0b', '').replace('0', '')
return ca_set_array
# NR Band list
def supported_band_list_nr(self, multilines):
re_bandNR = '\s*bandNR: (\d*)'
bandlist = []
for line in multilines:
m_bandNR= re.match(re_bandNR, line)
if m_bandNR:
bandlist.append(m_bandNR.group(1))
return bandlist
# NR CA band combination
def supported_band_combination_list_nr(self, multilines):
ca_array = []
ca_str = ''
re_bandNR = '\s*bandNR: (\d*)'
re_ca_BandwidthClassUL_NR = '\s*ca-BandwidthClassUL-NR: ([abcde]{1}) .+'
re_ca_BandwidthClassDL_NR = '\s*ca-BandwidthClassDL-NR: ([abcde]{1}) .+'
for line in multilines:
m_bandNR = re.match(re_bandNR, line)
m_ca_BandwidthClassUL_NR = re.match(re_ca_BandwidthClassUL_NR, line)
m_ca_BandwidthClassDL_NR = re.match(re_ca_BandwidthClassDL_NR, line)
if 'BandCombination' == line.strip():
ca_str = ca_str + ':'
if m_bandNR:
ca_str = ca_str + ';N' + m_bandNR.group(1)
if m_ca_BandwidthClassUL_NR:
ca_str = ca_str + '-UL' + m_ca_BandwidthClassUL_NR.group(1)
if m_ca_BandwidthClassDL_NR:
ca_str = ca_str + '-DL' + m_ca_BandwidthClassDL_NR.group(1)
if len(ca_str) > 1:
ca_array = ca_str[1:].split(':')
ca_array = [item[1:] for item in ca_array] # or item.replace(';','',1)
return ca_array
# MRDC CA band combination
def supported_band_combination_list_mrdc(self, multilines):
mrdc_array = []
mrdc_str = ''
re_bandEUTRA = '\s*bandEUTRA: (\d*)'
re_ca_BandwidthClassUL_EUTRA = '\s*ca-BandwidthClassUL-EUTRA: ([abcde]{1}) .+'
re_ca_BandwidthClassDL_EUTRA = '\s*ca-BandwidthClassDL-EUTRA: ([abcde]{1}) .+'
re_bandNR = '\s*bandNR: (\d*)'
re_ca_BandwidthClassUL_NR = '\s*ca-BandwidthClassUL-NR: ([abcde]{1}) .+'
re_ca_BandwidthClassDL_NR = '\s*ca-BandwidthClassDL-NR: ([abcde]{1}) .+'
for line in multilines:
m_bandEUTRA = re.match(re_bandEUTRA, line)
m_ca_BandwidthClassUL_EUTRA = re.match(re_ca_BandwidthClassUL_EUTRA, line)
m_ca_BandwidthClassDL_EUTRA = re.match(re_ca_BandwidthClassDL_EUTRA, line)
m_bandNR = re.match(re_bandNR, line)
m_ca_BandwidthClassUL_NR = re.match(re_ca_BandwidthClassUL_NR, line)
m_ca_BandwidthClassDL_NR = re.match(re_ca_BandwidthClassDL_NR, line)
if 'BandCombination' == line.strip():
mrdc_str = mrdc_str + ':'
if m_bandNR:
mrdc_str = mrdc_str + ';N' + m_bandNR.group(1)
if m_ca_BandwidthClassUL_NR:
mrdc_str = mrdc_str + '-UL' + m_ca_BandwidthClassUL_NR.group(1)
if m_ca_BandwidthClassDL_NR:
mrdc_str = mrdc_str + '-DL' + m_ca_BandwidthClassDL_NR.group(1)
if m_bandEUTRA:
mrdc_str = mrdc_str + ';B' + m_bandEUTRA.group(1)
if m_ca_BandwidthClassUL_EUTRA:
mrdc_str = mrdc_str + '-UL' + m_ca_BandwidthClassUL_EUTRA.group(1)
if m_ca_BandwidthClassDL_EUTRA:
mrdc_str = mrdc_str + '-DL' + m_ca_BandwidthClassDL_EUTRA.group(1)
#print('MRDC str', mrdc_str)
if len(mrdc_str) > 1:
mrdc_array = mrdc_str[1:].split(':')
mrdc_array = [item[1:] for item in mrdc_array] # or item.replace(';','',1)
return mrdc_array
# all information
def output_ue_information(self, ota_file):
lte_band = []
lte_ca = []
nr_band = []
nr_ca = []
mrdc = []
extract_multiline = ExtractMultiline()
lines = extract_multiline.get_filecontent_lines(ota_file)
bandlist = []
bandlist_v9e0 = []
ca_array = []
ca_extend_array = []
ca_set_array = []
# LTE Band list
multilines_array = extract_multiline.get_multilines('UE-EUTRA-Capability', 'supportedBandListEUTRA:', lines)
if len(multilines_array) >= 1:
bandlist = self.supported_band_list_eutra(multilines_array[0])
# LTE Band list extend(v9e0)
multilines_array = extract_multiline.get_multilines('UE-EUTRA-Capability', 'supportedBandListEUTRA-v9e0:', lines)
if len(multilines_array) >= 1:
bandlist_v9e0 = self.supported_band_list_eutra_v9e0(multilines_array[0])
# LTE CA band combination
multilines_array = extract_multiline.get_multilines('UE-EUTRA-Capability', 'supportedBandCombination-r10:', lines)
if len(multilines_array) >= 1:
ca_array = self.supported_band_combination_r10(multilines_array[0])
# LTE CA band extend
multilines_array = extract_multiline.get_multilines('UE-EUTRA-Capability', 'supportedBandCombination-v1090:', lines)
if len(multilines_array) >= 1:
ca_extend_array = self.supported_band_combination_v1090(multilines_array[0])
# LTE CA set
multilines_array = extract_multiline.get_multilines('UE-EUTRA-Capability', 'supportedBandCombinationExt-r10:', lines)
if len(multilines_array) >= 1:
ca_set_array = self.supported_band_combination_ext_r10(multilines_array[0])
#print('bandlist: ', bandlist)
#print('bandlist_v9e0: ', bandlist_v9e0)
#print('ca_array: ', ca_array)
#print('ca_extend_array: ', ca_extend_array)
#print('ca_set_array: ', ca_set_array)
# LTE Band and CA
for index in range(0, len(bandlist)):
if bandlist[index] != '64':
lte_band.append(bandlist[index])
else:
lte_band.append(bandlist_v9e0[index])
for index in range(0, len(ca_array)):
ca = ca_array[index]
if len(ca_extend_array) >= 1:
for band_extend in ca_extend_array[index].split(';')[1:]:
if band_extend != '':
ca = ca.replace('B64', 'B'+band_extend, 1)
lte_ca.append(ca + '; BW comb set: ' + ca_set_array[index])
print('LTE Band: ', lte_band)
print('LTE CA: ', lte_ca)
#for item in lte_ca:
# print(item)
# NR Band list
multilines_array = extract_multiline.get_multilines('UE-NR-Capability', 'supportedBandListNR:', lines)
if len(multilines_array) >= 1:
nr_band = self.supported_band_list_nr(multilines_array[0])
print('NR Band:', nr_band)
# NR CA band combination
multilines_array = extract_multiline.get_multilines('UE-NR-Capability', 'supportedBandCombinationList:', lines)
if len(multilines_array) >= 1:
nr_ca = self.supported_band_combination_list_nr(multilines_array[0])
print('NR CA:', nr_ca)
# MRDC
multilines_array = extract_multiline.get_multilines('UE-MRDC-Capability', 'supportedBandCombinationList:', lines)
if len(multilines_array) >= 1:
mrdc = self.supported_band_combination_list_mrdc(multilines_array[0])
print('MRDC:', mrdc)
return [lte_band, lte_ca, nr_band, nr_ca, mrdc]
if __name__ == '__main__':
ue_capability_information = UeCapabilityInformation()
#[lte_band, lte_ca, nr_band, nr_ca, mrdc] = ue_capability_information.output_ue_information(r'nr-ueCapabilityInformation.txt')
[lte_band, lte_ca, nr_band, nr_ca, mrdc] = ue_capability_information.output_ue_information(r'lte-ueCapabilityInformation.txt')
3. 测试数据
测试数据EN-DC ueCapabilityInformation:
38 03 08 13 ad d9 a0 4b 00 10 40 c1 c9 99 36 7d 2a 75 02 e5 ff f9 1f f9 7f fe 47 fe 5f ff 91 ff 97 ff e4 7f e5 ff f9 1f f9 7f fe 47 fe 5f ff 91 ff 97 ff e4 7f e5 ff f9 1f f9 7f fe 47 fe 5f ff 91 ff 97 ff e4 7f ff f3 ff af a2 08 00 8c 87 0c a7 4a 93 bb f1 59 c0 80 00 00 7d bf f0 00 00 00 78 d4 00 c0 0a 00 40 00 34 05 af aa dc bf ff 1a 06 38 00 20 01 80 00 08 20 61 00 02 08 18 80 00 80 06 30 00 20 81 a6 00 08 00 6c 80 02 00 1b 60 00 80 02 f8 40 03 94 00 10 00 e7 00 04 00 3a 00 01 00 1c 00 00 40 47 08 00 e3 80 02 02 00 40 1b 2f ff c8 ff cb ff f2 3f f2 ff fc 8f fc bf ff 23 ff 2f ff c8 ff cb ff f2 3f f2 ff fc 8f fc bf ff 23 ff 2f ff c8 ff cb ff f2 3f f2 ff fc 8f fc bf ff 23 ff 2f ff c8 ff cb ff f2 3f ff fe c0 00 19 8d 00 08 bc 5d 98 a2 27 38 10 70 0c f6 91 84 92 5f ff ff fe ef 73 5e 08 04 cc 11 99 41 24 30 00 80 05 09 08 25 cf 01 80 00 08 06 01 c1 b0 9c 4d 78 08 00 00 08 51 90 00 00 00 cd 07 ff 20 00 70 c1 96 03 80 00 10 08 03 00 e0 d8 4e 26 d8 05 83 15 e1 a0 3f a0 47 4e 7a ef ff ff af 01 40 78 2e 02 03 c1 27 be 7f ff ff 80 07 03 1b ef 80 01 40 dc 04 07 e3 80 f5 17 c0 0f f8 bc 21 d8 be 08 21 fd 50 08 83 d9 51 d2 20 62 4f ac 41 e4 20 f0 81 42 5b e7 e4 ff e3 f8 00 3f f8 fe 00 00 d8 05 00 07 42 a2 f8 05 ff 17 84 3b 17 c1 04 3f aa 01 10 7b 2a 3a 44 0c 49 f5 88 3c 84 1e 10 28 4b 7c fc 9f f8 7e 00 07 fe 1f 80 00 1b 00 a0 00 e8 54 5f 01 3f e2 f0 87 62 f8 20 87 f5 40 22 0f 65 47 48 81 89 3e b1 07 90 83 c2 05 09 6f 9f 93 f8 0e 00 00 fe 03 80 00 03 60 14 00 1d 0a 8b e0 37 fc 5e 10 ec 5f 04 10 fe a8 04 41 ec a8 e9 10 31 27 d6 20 f2 10 78 40 a1 2d f3 f2 7f f1 fc 00 1f fc 7f 00 00 6c 02 80 03 a1 51 7c 07 ff 8b c2 1d 8b e0 82 1f d5 00 88 3d 95 1d 22 06 24 fa c4 1e 42 0f 08 14 25 be 7e 42 00 08 00 0d 80 50 00 74 2a 2f 83 7f f1 78 43 b1 7c 10 43 fa a0 11 07 b2 a3 a4 40 c4 9f 58 83 c8 41 e1 02 84 b7 cf c9 fd 07 40 00 7f 41 d0 00 01 b0 0a 00 0e 85 45 f0 9f fe 2f 08 76 2f 82 08 7f 54 02 20 f6 54 74 88 18 93 eb 10 79 08 3c 20 50 96 f9 f9 08 00 20 00 36 01 40 01 d0 a8 be 26 ff c5 e1 0e c5 f0 41 0f ea 80 44 1e ca 8e 91 03 12 7d 62 0f 21 07 84 0a 12 df 3f 27 7f 1f f0 01 df c7 fc 00 06 e0 28 00 3a 00 d9 40 00 14 00 00 00 4a 0f 00 00 03 09 a0 00 03 d0 2a 0e 00 00 e2 68 00 00 13 d0 20 0e 00 04 04 d0 0e 00 01 50 d8 0a 14 e9 db 24 f8 10 a7 4e d9 27 c0 00 38 10 c6 0f ff f8 00 02 e0 3e 00 28 00 30 1c 04 07 03 10 5c 07 00 07 00 06 03 e0 40 82 00 00 00 41 00 00 02 20 80 00 02 10 40 00 01 88 20 00 01 04 10 00 00 a2 08 00 00 61 04 00 00 38 82 00 00 20 08 60 6d 60 ed 64 ed 60 cd 64 cd 64 6d 65 0d 65 2d e5 4d 02 01 00 00 09 65 94 04 00 00 65 96 50 10 00 02 96 59 40 40 00 0e 59 65 01 00 00 49 65 94 04 00 01 65 96 50 10 00 06 96 59 40 40 00 1e 59 65 01 00 00 89 65 94 02 14 0e 2a 83 c5 52 78 aa 0d 15 49 a2 a9 1c 55 28 8a a5 31 74 aa 28 18 d2 01 1e 6f c0 70 1c 01 e6 fc 07 01 c0 1e 6f c0 70 1c 01 e6 fc 07 01 c0 1e 6f c0 70 1c 01 e6 fc 07 01 c0 1e 6f c0 70 1c 01 e6 fc 07 01 c0 1e 6f c0 70 1c 00 00 01 08 98 01 00 30 04 00 a0 0c 01 c0 18 03 80 40 09 00 a0 16 01 40 2c 00 80 18 06 00 d0 0c 01 84 c0 10 00 80 70 01 00 40 02 01 c0 04 04 00 08 02 00 10 10 00 20 24 00 40 10 00 80 90 00 11 30 02 00 20 08 00 40 18 00 80 30 01 00 80 02 01 40 04 02 80 08 01 00 10 0c 00 20 18 00 09 80 20 05 00 e0 1e 00 80 14 03 80 78 08 01 10 04 00 a0 20 04 40 48 09 80 20 05 01 20 24 6a c2 c0 00 81 01 81 c4 c6 46 c7 c9 49 ca 1d c0 00 00 00 d0 4a 65 3a 18 ff 02 f0 58 38 07 00 00 00 00 10 3d 19 03 e0 b0 00 0e 26 80 00 01 20 7a 32 04 01 c0 00 80 9a 01 c0 00 2a 1a 81 42 9d 3b 64 9f 02 14 e9 db 24 f8 00 07 01 0c 60 e0 04 20 40 10 08 02 01 03 00 40 0a 00 c0 18 40 80 40 10 08 02 06 00 80 14 04 80 9c 00 00