博客專欄

        EEPW首頁 > 博客 > ASN.1 -- 使用asn1c完成ASN encode/decode

        ASN.1 -- 使用asn1c完成ASN encode/decode

        發布人:電子禪石 時間:2022-03-07 來源:工程師 發布文章

        asn1c官網:http://lionet.info/asn1c/blog/

        asn1c源代碼:https://github.com/vlm/asn1c


        一. 下載asn1c并編譯生成可執行文件(關掉交叉編譯)

        下載asn1c (此版本為主線版本asn1c-0.9.29,非release版本)

        git clone https://github.com/vlm/asn1c.git

        1



        進入下載好的代碼asn1c下,執行以下命令編譯源代碼(可參考INSTALL.md)

        test -f configure || autoreconf -iv

        sudo ./configure

        sudo make

        make install

        1

        2

        3

        4

        執行完以上命令之后,可以使用man asn1c查看命令


        二. 使用asn1c命令將.asn文件生成.c和.h文件

        準備*.asn文件


        新建目錄,將*.asn文件拷貝至./asn下



        在./下創建out文件夾


        v2x@ubuntu:~/ASN/parser$ tree

        .

        ├── asn

        │   ├── MsgFrame.asn

        │   ├── ***.asn

        └── out

        1

        2

        3

        4

        5

        6

        MsgFrame.asn如下所示:


        MessageFrame ::= CHOICE { 

        bsmFrame BasicSafetyMessage,

        mapFrame MapData,

        rsmFrame RoadsideSafetyMessage,

        spatFrame SPAT,

        rsiFrame RoadSideInformation,

        ...

        }

        1

        2

        3

        4

        5

        6

        7

        8

        在./執行以下命令,會在out中生成.c和.h文件

        默認生成帶UPER編解碼的版本

        asn1c asn/*.asn -D out/ -gen-autotools -no-gen-example

        1

        如果想要編譯帶例子的版本(正式代碼中不需要,如果想自己測試可以使用)

        asn1c asn/*.asn -D out/ -gen-autotools

        1

        之后會在./生成configure.ac Makefile.am

        生成configuare文件


        sudo autoreconf --force --install

        sudo autoconf -i

        1

        2

        編譯例子


        mkdir build

        sudo ./configure --prefix=$(pwd)/build

        sudo make install

        1

        2

        3

        會在./build下生成可執行文件和鏈接庫


        三.生成libasncodec.so(開啟交叉編譯)

        將out/下的*.c 和 *.h 分別拷貝到自己的代碼中,編譯成libasncodec.so



        四.開啟asn1c生成的代碼中的debug log

        在編譯libasncodec.so時,定義“-DEMIT_ASN_DEBUG=1”,CMakeLists.txt示例如下所示:


        源代碼中ASN_DEBUG的定義如下所示:


        五.encode示例

        //asn1c通過MsgFrame.asn自動生成

        /* MessageFrame */

        typedef struct MessageFrame {

        MessageFrame_PR present;

        union MessageFrame_u {

        BasicSafetyMessage_t bsmFrame;

        MapData_t mapFrame;

        RoadsideSafetyMessage_t rsmFrame;

        SPAT_t spatFrame;

        RoadSideInformation_t rsiFrame;

        PrivateMsg_t pmFrame;

        RTCMcorrections_t rtcmFrame;

        /*

        * This type is extensible,

        * possible extensions are below.

        */

        } choice;

        /* Context for parsing across buffer boundaries */

        asn_struct_ctx_t _asn_ctx;

        } MessageFrame_t;


        1

        2

        3

        4

        5

        6

        7

        8

        9

        10

        11

        12

        13

        14

        15

        16

        17

        18

        19

        20

        21

        #define MAX_PAYLOAD_LEN 1300

        asn_enc_rval_t er;

        MessageFrame* msg_frame_;

        msg_frame_ = (MessageFrame *)calloc(1, sizeof(MessageFrame));

        tran_inner_msg_to_asn(msg, msg_frame_);

        char buf_[MAX_PAYLOAD_LEN];

        //ATS_UNALIGNED_BASIC_PER:使用UPER編碼

        //msg_frame_ :asn1c自動生成的根ASN格式

        //buf_ :序列化之后的數據

        er = asn_encode_to_buffer(0, ATS_UNALIGNED_BASIC_PER, &asn_DEF_MessageFrame, msg_frame_, buf_, MAX_PAYLOAD_LEN);

        if (er.encoded > 0 && er.encoded <= MAX_PAYLOAD_LEN)

        {

        //success

            len_ = er.encoded;

        }

        else

        {

        //error

        }


        1

        2

        3

        4

        5

        6

        7

        8

        9

        10

        11

        12

        13

        14

        15

        16

        17

        18

        19

        //使用內存拷貝的方式將val拷貝到str

        int codec_asn_t::encode_string(const std::string val, OCTET_STRING_t &str)

        {

            if (val.empty())

            {

                return E_INVAL;

            }


            str.size = val.size();

            str.buf = (uint8_t *)malloc(str.size);

            if (NULL == str.buf)

            {

                return E_NOMEM;

            }


            memset(str.buf, 0, str.size);

            memcpy(str.buf, val.data(), str.size);


            return E_OK;

        }


        1

        2

        3

        4

        5

        6

        7

        8

        9

        10

        11

        12

        13

        14

        15

        16

        17

        18

        19

        20

        //此例的缺點:此例中傳入的變量val為int型,意味著在32位的機器中最大只能支持SIZE小于等于32個的bitstring

        int codec_asn_t::encode_bitstring(int val, int bit_num, BIT_STRING_t &str)

        {

            int len = (bit_num % 8 == 0) ? (bit_num / 8) : (bit_num / 8) + 1;

            int tmp_val = 0;

        //從源碼中可以看出size為字節數

            str.size = bit_num;

            str.buf = (uint8_t *)malloc(len);

            if (NULL == str.buf)

            {

                return E_NOMEM;

            }

            //str.buf中應該傳入的格式為:若asn中定義的bitstring的SIZE為16,

            //給asn中定義的(0)賦值為1,就將str.buf賦值為0x80(即10000000B);

            //給asn中定義的(1)也賦值為1,就將str.buf賦值為0xC0(即11000000B);

            //以此類推

            memset(str.buf, 0, len);

            tmp_val = 1;

            for (int i = 0; i < bit_num; i++)

            {

                if (val & tmp_val)

                {

                    str.buf[i / 8] |= (0x80 >> (i % 8));

                }

                tmp_val *= 2;

            }


            return E_OK;

        }


        1

        2

        3

        4

        5

        6

        7

        8

        9

        10

        11

        12

        13

        14

        15

        16

        17

        18

        19

        20

        21

        22

        23

        24

        25

        26

        27

        28

        29

        六.decode示例

        asn_dec_rval_t rval;

        //ATS_UNALIGNED_BASIC_PER:使用UPER編碼

        //msg_frame:接收decode之后的數據

        //buf:接收到的decode之前的數據

        rval = asn_decode(0, ATS_UNALIGNED_BASIC_PER, &asn_DEF_MessageFrame, (void **)(&msg_frame), (char *)buf, len);

        if (rval.code == RC_OK)

        {

        //success

            msg = tran_asn_to_inner_msg(msg_frame);

            ASN_STRUCT_FREE(asn_DEF_MessageFrame, msg_frame);

        }

        else

        {

        //error

        }

        1

        2

        3

        4

        5

        6

        7

        8

        9

        10

        11

        12

        13

        14

        15

        int codec_asn_t::decode_bitstring(const BIT_STRING_t &str, int &val)

        {

            if ((str.size <= 0) ||

                (NULL == str.buf))

            {

                return E_INVAL;

            }


            int tmp_val = 1;


            val = 0;

            for (int i = 0; i < str.size; i++)

            {

                if (str.buf[i / 8] & (0x80 >> (i % 8)))

                {

                    val |= tmp_val;

                }

                tmp_val *= 2;

            }

            return E_OK;

        }


        1

        2

        3

        4

        5

        6

        7

        8

        9

        10

        11

        12

        13

        14

        15

        16

        17

        18

        19

        20

        21

        七.BIT_STRING.c源碼分析


        由如下源代碼可知,若使用PER、OER編解碼格式,會使用單獨的編解碼函數;若使用其他編解碼格式,編解碼可復用OCTET_STRING

        asn_TYPE_operation_t asn_OP_BIT_STRING = {

        OCTET_STRING_free,         /* Implemented in terms of OCTET STRING */

        BIT_STRING_print,

        BIT_STRING_compare,

        OCTET_STRING_decode_ber,   /* Implemented in terms of OCTET STRING */

        OCTET_STRING_encode_der,   /* Implemented in terms of OCTET STRING */

        OCTET_STRING_decode_xer_binary,

        BIT_STRING_encode_xer,

        #ifdef ASN_DISABLE_OER_SUPPORT

        0,

        0,

        #else

        BIT_STRING_decode_oer,

        BIT_STRING_encode_oer,

        #endif  /* ASN_DISABLE_OER_SUPPORT */

        #ifdef ASN_DISABLE_PER_SUPPORT

        0,

        0,

        #else

        BIT_STRING_decode_uper, /* Unaligned PER decoder */

        BIT_STRING_encode_uper, /* Unaligned PER encoder */

        #endif  /* ASN_DISABLE_PER_SUPPORT */

        BIT_STRING_random_fill,

        0 /* Use generic outmost tag fetcher */

        };


        1

        2

        3

        4

        5

        6

        7

        8

        9

        10

        11

        12

        13

        14

        15

        16

        17

        18

        19

        20

        21

        22

        23

        24

        25

        BIT_STRING_encode_uper函數下調用的BIT_STRING__compactify會將bitstring進一步優化,將盡可能壓縮發送的byte,以及進一步填充bits_unused

        /* Figure out the size without the trailing bits */

            st = BIT_STRING__compactify(st, &compact_bstr);

        ————————————————


        原文鏈接:https://blog.csdn.net/mao834099514/article/details/109102770


        *博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。



        關鍵詞: asn1c

        技術專區

        關閉
        主站蜘蛛池模板: 文昌市| 常宁市| 东光县| 仲巴县| 祁东县| 阿克苏市| 蕲春县| 西乌| 林口县| 临夏市| 基隆市| 建阳市| 枣阳市| 绥宁县| 闽侯县| 沈丘县| 安阳县| 新余市| 赤城县| 阿克| 田阳县| 平南县| 宁安市| 富源县| 石阡县| 丹阳市| 米泉市| 湖州市| 玛沁县| 太原市| 钦州市| 青海省| 苍南县| 大新县| 比如县| 秀山| 伊宁市| 平泉县| 凤城市| 左权县| 中西区|