使用asn1tools进行asn1编解码
最近在做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
|
||
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编解码的更多相关文章
- iOS8系统H264视频硬件编解码说明
公司项目原因,接触了一下视频流H264的编解码知识,之前项目使用的是FFMpeg多媒体库,利用CPU做视频的编码和解码,俗称为软编软解.该方法比较通用,但是占用CPU资源,编解码效率不高.一般系统都会 ...
- IOS和Android支持的音频编解码
1.IOS编码 参考文档地址:https://developer.apple.com/library/ios/documentation/AudioVideo/Conceptual/Multimedi ...
- java编解码技术,netty nio
对于java提供的对象输入输出流ObjectInputStream与ObjectOutputStream,可以直接把java对象作为可存储 的字节数组写入文件,也可以传输到网络上去.对与java开放人 ...
- 编解码-marshalling
JBoss的Marshalling序列化框架,它是JBoss内部使用的序列化框架,Netty提供了Marshalling编码和解码器,方便用户在Netty中使用Marshalling. JBoss M ...
- 编解码-protobuf
Google的Protobuf在业界非常流行,很多商业项目选择Protobuf作为编解码框架,Protobuf的优点. (1)在谷歌内部长期使用,产品成熟度高: (2)跨语言,支持多种语言,包括C++ ...
- 编解码-java序列化
大多数Java程序员接触到的第一种序列化或者编解码技术就是Java的默认序列化,只需要序列化的POJO对象实现java.io.Serializable接口,根据实际情况生成序列ID,这个类就能够通过j ...
- ilbc编解码
针对国内的博客或者技术论坛对 ILBC的论述都是把文章抄来抄去, 本人在此对 ILBC的具体代码实现详细列出代码. ILBC是由Global IP Sound公司提出的一种专为包交换网络通信设计的编解 ...
- 各种音视频编解码学习详解 h264 ,mpeg4 ,aac 等所有音视频格式
编解码学习笔记(一):基本概念 媒体业务是网络的主要业务之间.尤其移动互联网业务的兴起,在运营商和应用开发商中,媒体业务份量极重,其中媒体的编解码服务涉及需求分析.应用开发.释放 license收费等 ...
- 【GPU编解码】GPU硬解码---DXVA
前面介绍利用NVIDIA公司提供的CUVID库进行视频硬解码,下面将介绍利用DXVA进行硬解码. 一.DXVA介绍 DXVA是微软公司专门定制的视频加速规范,是一种接口规范.DXVA规范制定硬件加速解 ...
随机推荐
- MSSQL数据库导入导出大全二(SQL语句)
Excel文件导入数据库多个Sheet if exists(select 1 from sysobjects where name=N'p_import_excel' and type='P')dro ...
- javascript 数组 find
find() 方法返回通过测试(函数内判断)的数组的第一个元素的值. let arr = [1,2,3,4] console.log(arr.find(i => {return i>1}) ...
- EasyUI 鼠标经过 显示气泡一例
$(function(){ $('#contacts').tooltip({ position: 'bottom', content: '<c:forEach items="${rec ...
- 转: Appium ---移动自动化测试
转自:http://www.cnblogs.com/nbkhic/p/3803830.html 什么是appium? 下面这段介绍来自于appium的官网. Appium is an open-sou ...
- String、StringBuffer、StringBuilder区别并验证
© 版权声明:本文为博主原创文章,转载请注明出处 String.StringBuffer.StringBuilder的区别 1.String是一个常量,其对象一旦创建完毕就无法改变,当使用“+”拼接字 ...
- Debian 升级到 PHP 7,并支持并行安装
Debian 开发者 Ondřej Surý 前几天在一个邮件列表中宣布他们开始迁移到 PHP 7.x 了,并支持多版本并行安装co-installable.而此前几天,Ubuntu 也宣布其下一个版 ...
- EasyNetQ操作RabbitMQ(高级消息队列)
RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件).写消息队列的时候用RabbitMQ比较好,但是写的时候需要自己封装下,自己的封装,就需要对RabbitM ...
- sersync简介与测试报告
在分布式应用中会遇到一个问题,就是多个服务器间的文件如何能始终保持一致.一种经典的办法是将需要保持一致的文件存储在NFS上,这种方法虽然简单方便但却将本来多点的应用在文件存储上又变成了单点,这违背了分 ...
- 机器学习12—FP-growth学习笔记
test12.py #-*- coding:utf-8 import sys sys.path.append("fpGrowth.py") import fpGrowth from ...
- homebrew可以管理众多开源软件的安装和卸载
通过homebrew可以管理众多开源软件的安装和卸载. 参考https://github.com/mxcl/homebrew/wiki 1. 安装: ruby -e "$(curl -fsS ...