最近在做3GPP的编解码,发现有两个第三方库比较好用。一个是ASN1C(c语言编译环境),一个是python第三方库asn1tools。这里介绍下asn1tools的使用方法:

1 第一步:生成asn文件

将需要编码的数据结构保存在asn后缀名的文件中

3GPP中的结构如下:

-- ASN1START

BCCH-BCH-Message-NB ::= SEQUENCE {

message                BCCH-BCH-MessageType-NB

}

BCCH-BCH-MessageType-NB::= MasterInformationBlock-NB

-- ASN1STOP

对应的.asn文件的基本结构如下:也就是讲ASN1START和ASN1STOP中的数据提取出来。然后上asn自己的头信息

EUTRA-RRC-Definitions DEFINITIONS AUTOMATIC TAGS ::=

BEGIN

BCCH-BCH-Message ::= SEQUENCE {

message                                    BCCH-BCH-MessageType

}

END

在3GPP中有大量的类似结构,如果一个个手动的拷贝,太耗费时间了。因此用下面的代码将3GPP中的数据结构自动提取出来保存在asn文件中。代码如下:

#include <iostream>

#include <fstream>

#include <string>

#include <vector>

using namespace std;

int main()

{

std::string output_file;

std::string input_file = "D:/code_block_prj/gen_asn/protol.txt";

std::cout<<input_file.c_str()<<std::endl;

int pos = input_file.find('.');

if (pos == std::string::npos )

{

output_file = input_file + ".asn";

}

else

{

output_file = input_file.substr(0,pos) + ".asn";

}

std::fstream input;

input.open(input_file.c_str(), std::fstream::in );

if ( input.fail() == true)

{

std::cout<<"Please check input file is correct !"<<std::endl;

return 1;

}

std::fstream output;

output.open(output_file.c_str(), std::fstream::out );

if ( output.fail() == true)

{

std::cout<<"The output file can not be created here !"<<std::endl;

return 1;

}

std::string input_line;

std::vector<std::string > vec_asn;

std::vector<std::string >::iterator itr;

const unsigned long cul_asn_idle  = 0x0;

const unsigned long cul_asn_start = 0x1;

unsigned long asn_state = cul_asn_idle;

while ( std::getline(input, input_line) )

{

if ( cul_asn_idle == asn_state )

{

if ( input_line.find("-- ASN1START") != std::string::npos )

{

asn_state |=  cul_asn_start;

}

continue;

}

if ( 0 != (cul_asn_start & asn_state) )

{

if ( input_line.find("-- ASN1STOP") != std::string::npos )

{

asn_state = cul_asn_idle;

}

else

{

vec_asn.push_back(input_line);

}

}

}

for ( itr  = vec_asn.begin(); itr != vec_asn.end(); ++itr )

{

output<<*itr<<std::endl;

}

input.close();

output.close();

return 0;

}

2:打开36331的word文档并另存为txt文件

3:运行上面的程序,其中input_file就是保存txt文件的位置,需要自己设置。运行完后会在本地文件夹下面生成一个asn文件

第二步:利用asn1tools进行编解码:

一:首先pip3 install asn1tools进行模块安装

二:在3GPP中有大量的数据结构,例如sequence, bit string, octer string, bool, sequence of等等,这些结构体在python对应的结构体如下表。

ASN.1 type

Python type

Example

BOOLEAN

bool

True

'ackNackSRS-SimultaneousTransmission': True

INTEGER

int

87

'p0-NominalPUCCH': -127,

REAL

float

33.12

NULL

None

BIT STRING

tuple(bytes, int)

(b'\x50', 4)

元组第一个参数为值,第二个参数为bit长度

示例:

ac-BarringForSpecialAC                            BIT STRING (SIZE(5))

'ac-BarringForSpecialAC': (b'\xf0', 5)

OCTET STRING

bytes

b'\x44\x1e\xff'

hnb-Name                                                          OCTET STRING (SIZE(1..48))

'hnb-Name': b'4'

OBJECT IDENTIFIER

str

'1.33.2'

ENUMERATED

str

'one'

ac-BarringTime                                                  ENUMERATED {s4, s8, s16, s32, s64, s128, s256, s512},

代码:

'ac-BarringTime': 's128',

SEQUENCE

dict

{'a': 52, 'b': 1}

SEQUENCE OF

list

[1, 3]采用list列表的方法[]

示例一:

InterFreqCarrierFreqList ::=       SEQUENCE (SIZE (1..maxFreq)) OF InterFreqCarrierFreqInfo

'interFreqCarrierFreqList': ['dl-CarrierFreq': 1,

'q-RxLevMin': -45,

't-ReselectionEUTRA': 0,

'threshX-High': 31,

'threshX-Low': 29,

'allowedMeasBandwidth': 'mbw6',

'presenceAntennaPort1': True,

'neighCellConfig': (b'\x00', 2),

'q-OffsetFreq': 'dB0]

 

SET

dict

{'foo': 'bar'}

SET OF

list

[3, 0, 7]

CHOICE

tuple

('a', 5)

UTF8String

str

'hello'

NumericString

str

'234359'

PrintableString

str

'goo'

IA5String

str

'name'

VisibleString

str

'gle'

GeneralString

str

'abc'

BMPString

str

'ko'

GraphicString

str

'a b'

TeletexString

str

'ßø'

UniversalString

str

'åäö'

UTCTime

datetime.datetime

datetime(2018, 6, 11)

GeneralizedTime

datetime.datetime

datetime(2018, 1, 31)

ObjectDescriptor

三:对结构进行赋值。以BCCH-DL-SCH-Message-NB结构为例,首先需要根据BCCH-DL-SCH-Message-NB的结构用python的结构体进行赋值。如下所示。具体的赋值方法参考上面的表格。

BCCH_DL_SCH_Message_NB={

'message':(

'c1',(

'systemInformationBlockType1-r13',{

'hyperSFN-MSB-r13':(b'\x07',8),

'cellAccessRelatedInfo-r13':{

'plmn-IdentityList-r13':[

{'plmn-Identity-r13':{'mcc':[0,0,1],'mnc':[0,1]},

'cellReservedForOperatorUse-r13':'notReserved',

'attachWithoutPDN-Connectivity-r13':'true'}],

'trackingAreaCode-r13':(b'\x00\x01',16),

'cellIdentity-r13':(b'\x00\x01\x10\x10',28),

'cellBarred-r13':'notBarred',

'intraFreqReselection-r13':'notAllowed',

},

'cellSelectionInfo-r13':{

'q-RxLevMin-r13':-53,

'q-QualMin-r13':-20

},

'freqBandIndicator-r13':8,

'schedulingInfoList-r13':[{'si-Periodicity-r13':'rf64','si-RepetitionPattern-r13':'every8thRF','sib-MappingInfo-r13':[],'si-TB-r13':'b552'}],

'si-WindowLength-r13':'ms160'

}

)

)

}

四:进行编码。在encode函数中第一个参数就是asn文件中的结构体名称。第二个参数就是上面赋值的字典结构。最终得到16进制的码流

def asn1tools__3GPP():

foo = asn1tools.compile_files('protol.asn', 'uper')

encoded = foo.encode('BCCH-DL-SCH-Message-NB',BCCH_DL_SCH_Message_NB)

print(encoded.hex())

五:数据可视化:16进制的码流对于观测不方便。因此将前面编码得到的16进制码流再进行解码并保存在json文件中,然后通过jsonViewer工具进行查看。代码如下

class MyEncoder(json.JSONEncoder):

def default(self, obj):

if isinstance(obj, bytes):

return str(obj, encoding='utf-8');

return json.JSONEncoder.default(self, obj)

def asn1tools__3GPP():

foo = asn1tools.compile_files('protol.asn', 'uper')

encoded = foo.encode('BCCH-DL-SCH-Message-NB',BCCH_DL_SCH_Message_NB)

print(encoded.hex())

decoded=foo.decode('BCCH-DL-SCH-Message-NB',encoded)

value=json.dumps(decoded,indent=1,cls=MyEncoder,ensure_ascii=False)

print(decoded,value)

f=open('BCCH.json','wb')

f.write(value.encode("utf-8"))

f.close()

在jsonViewer中打开json文件,可以更直观的观测结构

但是这样会有一个问题,在编译BIT STRING或者OCTER STRING的时候,编译完后的数据无法写入json文件。原因在于json文件是utf-8的编码格式。某些字节utf-8无法识别,例如0x80这样的数据。如果将trackingAreaCode-r13改成如下的值,那么在写入json文件的时候就会提示utf-8 can’t decode \0x80的错误

'trackingAreaCode-r13':(b'\x80\x01',16),

那么代码修改如下。用uper和jer两种编码方式编译asn文件。然后将UPER解码得到的数据用jer的方法进行编码。然后再写入json文件。

def asn1tools__3GPP():

foo = asn1tools.compile_files('protol.asn', 'uper')

foo_jer=asn1tools.compile_files('protol.asn', 'jer')

encoded = foo.encode('BCCH-DL-SCH-Message-NB',BCCH_DL_SCH_Message_NB)

print(encoded.hex())

decoded=foo.decode('BCCH-DL-SCH-Message-NB',encoded)

value_jer = foo_jer.encode('BCCH-DL-SCH-Message-NB', decoded)

with open('BCCH.json','wb') as f:

f.write(value_jer)

这样做的原理是UPER是将数据以字节的形式编码,而jer是以字符串的形式编码。因此写入json文件没有任何问题。得到的结构数据如下。

使用asn1tools进行asn1编解码的更多相关文章

  1. iOS8系统H264视频硬件编解码说明

    公司项目原因,接触了一下视频流H264的编解码知识,之前项目使用的是FFMpeg多媒体库,利用CPU做视频的编码和解码,俗称为软编软解.该方法比较通用,但是占用CPU资源,编解码效率不高.一般系统都会 ...

  2. IOS和Android支持的音频编解码

    1.IOS编码 参考文档地址:https://developer.apple.com/library/ios/documentation/AudioVideo/Conceptual/Multimedi ...

  3. java编解码技术,netty nio

    对于java提供的对象输入输出流ObjectInputStream与ObjectOutputStream,可以直接把java对象作为可存储 的字节数组写入文件,也可以传输到网络上去.对与java开放人 ...

  4. 编解码-marshalling

    JBoss的Marshalling序列化框架,它是JBoss内部使用的序列化框架,Netty提供了Marshalling编码和解码器,方便用户在Netty中使用Marshalling. JBoss M ...

  5. 编解码-protobuf

    Google的Protobuf在业界非常流行,很多商业项目选择Protobuf作为编解码框架,Protobuf的优点. (1)在谷歌内部长期使用,产品成熟度高: (2)跨语言,支持多种语言,包括C++ ...

  6. 编解码-java序列化

    大多数Java程序员接触到的第一种序列化或者编解码技术就是Java的默认序列化,只需要序列化的POJO对象实现java.io.Serializable接口,根据实际情况生成序列ID,这个类就能够通过j ...

  7. ilbc编解码

    针对国内的博客或者技术论坛对 ILBC的论述都是把文章抄来抄去, 本人在此对 ILBC的具体代码实现详细列出代码. ILBC是由Global IP Sound公司提出的一种专为包交换网络通信设计的编解 ...

  8. 各种音视频编解码学习详解 h264 ,mpeg4 ,aac 等所有音视频格式

    编解码学习笔记(一):基本概念 媒体业务是网络的主要业务之间.尤其移动互联网业务的兴起,在运营商和应用开发商中,媒体业务份量极重,其中媒体的编解码服务涉及需求分析.应用开发.释放 license收费等 ...

  9. 【GPU编解码】GPU硬解码---DXVA

    前面介绍利用NVIDIA公司提供的CUVID库进行视频硬解码,下面将介绍利用DXVA进行硬解码. 一.DXVA介绍 DXVA是微软公司专门定制的视频加速规范,是一种接口规范.DXVA规范制定硬件加速解 ...

随机推荐

  1. SOYO的主板如何进入BIOS系统

    1 开机按Del键进入BIOS系统   2 进入Advanced BIOS Features   3 选择 Hard Disk Boot Priority 按ENTER   4 选择要启动的设备,比如 ...

  2. vscode - 添加背景图片

    首先,Ctrl+Shift+P安装backround , 而后重启vscode会有默认的背景图片 修改背景图,可自定义三张 具体请看gif图 最开始时,发现png根本不是全透明,用ps处理了一下(下列 ...

  3. react-native 常用组件的用法(一)

    1.View组件 View是一个支持Flexbox布局.样式.一些触摸处理.和一些无障碍功能的容器,并且它可以放到其它的视图里,也可以有任意多个任意类型的子视图. View的设计初衷是和StyleSh ...

  4. zabbix监控客户端本地网络的延时状态

    配置zabbix客户端配置文件 vim /etc/zabbix/zabbix_agentd.conf 添加  Include=/etc/zabbix/zabbix_agentd.d/ 添加脚本对服务器 ...

  5. ios侧滑返回:完美解决 interactivePopGestureRecognizer 卡住的问题

    interactivePopGestureRecognizer是iOS7推出的解决VeiwController滑动后退的新功能,虽然很实用,但是坑也很多啊(比如在rootViewcontroller下 ...

  6. MQTT--mosquitto使用详解

    mosquitto_pub(发布)的用法 用法: mosquitto_pub [-d] [-h hostname] [-i client_id] [-I client id prefix] [-p p ...

  7. css 用 display: inline-block; 代替 float

    浮动可以将两个块级元素浮动在同一水平上.但float的缺点也有很多,还需要其他样式弥补. 早年我使用过 display: inline-block; 但苦于兼容性问题一直没敢全面使用. 近几年主要玩移 ...

  8. python 用win32修改注册表,修改打开IE浏览器的配置

    打开注册表:win+r, regedit,注册表的管理是按照文件夹的形式的. 注册表总共有五项: HKEY_CLASSES_ROOT 是HKEY_LOCAL_MACHINE\Software的子项,保 ...

  9. Spring在注入bean异常时的替换

    情形:需要把数据库1的连接池A注入到DAO中,但是如果数据库A的连接池实例化失败了整个项目也启动不了,这个时候希望用数据库2的连接池来替换. 这里没有想到什么好的解决方法,只是想到了工厂方法提供Bea ...

  10. Linux中终端和控制台区别

    Linux中终端和控制台区别: 终端:英文名叫terminal 控制台:英文名叫console 两者区别要从以前的多人使用的计算机开始 以前,由于计算机很昂贵,所用一台计算机一般由多个人同时使用.这样 ...