上文说到安装ASN1C库,这篇文章将会说一下怎样使用asn1c命令来将自定义的.asn文件生成.c文件,并对自定义的结构体进行解码和组码。下面所有的代码源文件可以在我的资源下载:(https://download.csdn.net/download/adgentleman/11022636)
一、 建立.asn文件:
RawCircle DEFINITIONS AUTOMATIC TAGS ::= BEGIN
RawCircle ::= SEQUENCE {
x INTEGER,
y INTEGER,
r REAL
}
END
新建一个目录取名ASN,进入新建的目录,复制上面的代码保存为raw_circle.asn
二、 上面.asn文件的含义:
翻译成C语言代码就是定义了一个RawCircle_t的结构体,成员分别为x,y,r ,类型分别为long,long,double。如下所示:
typedef struct RawCircle {
long x;
long y;
double r;
} RawCircle_t;
顺便说一下,ASN的整型类型都用INTEGER(即C语言里的long类型),要表示浮点型可以用REAL。
三、 使用asn1c命令将.asn文件生成.c和.h文件
打开终端,cd到.asn文件所在目录,
执行
asn1c -no-gen-example raw_circle.asn
然后就会生成一大堆.c和.h文件啦!如下所示:
Copied /usr/local/share/asn1c/OCTET_STRING_oer.c -> OCTET_STRING_oer.c
Copied /usr/local/share/asn1c/NativeInteger_oer.c -> NativeInteger_oer.c
Copied /usr/local/share/asn1c/constr_CHOICE_oer.c -> constr_CHOICE_oer.c
Copied /usr/local/share/asn1c/constr_SEQUENCE_oer.c -> constr_SEQUENCE_oer.c
Generated Makefile.am.libasncodec
四、复制缺少的一个.c文件
asn1c有一个bug,就是生成的文件里面会缺少一个.c文件:BIT_STRING_oer.c
这里我们需要自己复制过去,这个文件在 /usr/local/share/asn1c/ 目录下,也就是上面贴的生成代码的log的那个路径。找到这个文件和那些生成的文件放在一起。
五、整理一下生成的文件
新建src和headers目录,分别将.c和.h放进去,删除生成的makefile
rm Makefile.am.libasncodec
mkdir src
mv *.c src/
mkdir headers
mv *.h headers/
六、写解码和组码函数
新建3个文件,然后解码和组码函数实现以及如何使用都会写在这里面啦~
touch raw_circle_asn.c
touch raw_circle_asn.h
touch main.c
贴上源码:
/*
*@file raw_circle_asn.c
*/
#include "raw_circle_asn.h"
/* copy from asn_application.c */
struct overrun_encoder_key
{
void *buffer;
uint32_t buffer_size;
uint32_t computed_size;
};
static int overrun_encoder_cb(const void *data, size_t size, void *keyp)
{
struct overrun_encoder_key *key = keyp;
if ((key->computed_size + size) > key->buffer_size)
{
/*
* Avoid accident on the next call:
* stop adding bytes to the buffer.
*/
key->buffer_size = 0;
}
else
{
memcpy(((char *)key->buffer + key->computed_size), data, size);
}
key->computed_size += (uint32_t)size;
return 0;
}
extern int32_t asn_encode_raw_circle(const RawCircle_t *raw_circle_asn, uint8_t *raw_data,
uint32_t raw_data_size, uint32_t *consumed_data_size)
{
int32_t ret = 0;
struct overrun_encoder_key callback_key;
asn_enc_rval_t result = {0};
memset(raw_data, 0, raw_data_size);
memset(&callback_key, 0, sizeof(callback_key));
callback_key.buffer = (void *)raw_data;
callback_key.buffer_size = raw_data_size;
result = asn_encode(NULL, ATS_BER, &asn_DEF_RawCircle, (const void *)raw_circle_asn, overrun_encoder_cb,
&callback_key);
if (0 <= result.encoded)
{
assert(result.encoded == callback_key.computed_size);
*consumed_data_size = result.encoded;
if (result.encoded < raw_data_size)
{
ret = 0;
}
else
{
*consumed_data_size += 1;
ret = -1;
}
}
else
{
*consumed_data_size = 0;
ret = -1;
}
return ret;
}
extern int32_t asn_decode_raw_circle(const uint8_t *raw_data, uint32_t raw_data_size, RawCircle_t *raw_circle,
uint32_t *consumed_data_size, enum asn_dec_rval_code_e *error_code)
{
int32_t ret = 0;
asn_dec_rval_t result;
memset(raw_circle, 0, sizeof(*raw_circle));
result = asn_decode(NULL, ATS_BER, &asn_DEF_RawCircle, (void **)&raw_circle, raw_data, raw_data_size);
*error_code = result.code;
if (RC_OK == result.code)
{
*consumed_data_size = result.consumed;
ret = 0;
}
else
{
*consumed_data_size = 0;
ret = -1;
}
return ret;
}
/*
*@file raw_circle_asn.h
*/
#ifndef RAW_CIRCLE_ASN_H
#define RAW_CIRCLE_ASN_H
#include "asn_application.h"
#include "RawCircle.h"
#include <stdlib.h>
/**
* @brief:convert RawCircle_t to uint8_t raw_data
*/
extern int32_t asn_encode_raw_circle(const RawCircle_t *raw_circle_asn, uint8_t *raw_data,
uint32_t raw_data_size, uint32_t *consumed_data_size);
/**
* @brief: convert uint8_t raw_data to RawCircle_t
*/
extern int32_t asn_decode_raw_circle(const uint8_t *raw_data, uint32_t raw_data_size, RawCircle_t *raw_circle,
uint32_t *consumed_data_size, enum asn_dec_rval_code_e *error_code);
#endif
/*
*@file main.c
*/
#include "raw_circle_asn.h"
#define BUFF_SIZE (32)
void print_raw_circle(const RawCircle_t *circle)
{
printf("x:%ld y:%ld r:%lf\n", circle->x, circle->y, circle->r);
}
int main()
{
RawCircle_t circle = {0};
RawCircle_t new_circle = {0};
uint8_t buff[BUFF_SIZE] = {0};
uint32_t consumed_data_size = 0;
enum asn_dec_rval_code_e error;
int ret = 0;
circle.x = 3;
circle.y = 4;
circle.r = 5.5;
print_raw_circle(&circle);
ret = asn_encode_raw_circle(&circle, buff, BUFF_SIZE, &consumed_data_size);
assert(ret == 0);
ret = asn_decode_raw_circle(buff, BUFF_SIZE, &new_circle, &consumed_data_size, &error);
assert(ret == 0);
print_raw_circle(&new_circle);
return 0;
}
七、构建项目
本人习惯用cmake来管理项目,下面贴上CMakelists.txt
在ASN目录下新建CMakelists.txt
touch CMakelists.txt
###CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(CIRCLE)
include_directories(
"${PROJECT_SOURCE_DIR}"
"${PROJECT_SOURCE_DIR}/headers"
)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} CIRCLE_SOURCE_FILE)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src CIRCLE_SOURCE_FILE)
add_executable(circle ${CIRCLE_SOURCE_FILE})
target_link_libraries(circle m)
注意这里一定要链接数学库,因为asn1c库会用到。
八、增加自动构建脚本
touch build_project.sh
chmod +x build_project.sh
shell脚本源码:
#!/bin/bash
PROJECT_DIR=`pwd`
BUILD_DIR=${PROJECT_DIR}/build
if [ -d ${BUILD_DIR} ];then
rm -rf ${BUILD_DIR}
fi
mkdir ${BUILD_DIR}
cd ${BUILD_DIR}
cmake ..
make
九、编译、运行
./build_project.sh
然后会生成build目录,可执行文件circle在build目录下面
./build/circle
运行程序,如果你看到下面的输出就恭喜你~~~
x:3 y:4 r:5.500000
x:3 y:4 r:5.500000
十、目录结构
├── build
├── build_project.sh
├── CMakeLists.txt
├── headers
│ ├── asn_application.h
│ ├── asn_bit_data.h
│ ├── asn_codecs.h
│ ├── asn_codecs_prim.h
│ ├── asn_internal.h
│ ├── asn_ioc.h
│ ├── asn_random_fill.h
│ ├── asn_system.h
│ ├── ber_decoder.h
│ ├── ber_tlv_length.h
│ ├── ber_tlv_tag.h
│ ├── BIT_STRING.h
│ ├── constraints.h
│ ├── constr_CHOICE.h
│ ├── constr_SEQUENCE.h
│ ├── constr_TYPE.h
│ ├── der_encoder.h
│ ├── INTEGER.h
│ ├── NativeInteger.h
│ ├── NativeReal.h
│ ├── OCTET_STRING.h
│ ├── oer_decoder.h
│ ├── oer_encoder.h
│ ├── oer_support.h
│ ├── OPEN_TYPE.h
│ ├── per_decoder.h
│ ├── per_encoder.h
│ ├── per_opentype.h
│ ├── per_support.h
│ ├── RawCircle.h
│ ├── REAL.h
│ ├── xer_decoder.h
│ ├── xer_encoder.h
│ └── xer_support.h
├── main.c
├── raw_circle.asn
├── raw_circle_asn.c
├── raw_circle_asn.h
└── src
├── asn_application.c
├── asn_bit_data.c
├── asn_codecs_prim.c
├── asn_internal.c
├── asn_random_fill.c
├── ber_decoder.c
├── ber_tlv_length.c
├── ber_tlv_tag.c
├── BIT_STRING.c
├── BIT_STRING_oer.c
├── constraints.c
├── constr_CHOICE.c
├── constr_CHOICE_oer.c
├── constr_SEQUENCE.c
├── constr_SEQUENCE_oer.c
├── constr_TYPE.c
├── der_encoder.c
├── INTEGER.c
├── INTEGER_oer.c
├── NativeInteger.c
├── NativeInteger_oer.c
├── NativeReal.c
├── OCTET_STRING.c
├── OCTET_STRING_oer.c
├── oer_decoder.c
├── oer_encoder.c
├── oer_support.c
├── OPEN_TYPE.c
├── OPEN_TYPE_oer.c
├── per_decoder.c
├── per_encoder.c
├── per_opentype.c
├── per_support.c
├── RawCircle.c
├── REAL.c
├── xer_decoder.c
├── xer_encoder.c
└── xer_support.c
3 directories, 78 files
好啦,到这里就说完了。大家不要嫌我讲得啰嗦哈~
呼一口长气~~~