在嵌入式设备中使用protobuf

时间:2022-01-20 08:44:18

在嵌入式设备中使用protobuf

1 protobuf简介

 Protobuf的功能是将是结构化数据转化为二进制流,比如,

struct _msg

{

  Int val;

}msg;

Unsigned char streambuf[256];

Msg A;

A.val = 1;

Protobuf.encode(streambuf,A);

如上,将结构化数据转为二进制流存到streambuf

使用时,再将二进制充转化为结构化数据,如:

Msg B;

Protobuf.decode(streambuf,B);

B.val制就是A.val了。

好处应该是为了节省空间吧。

 

2 protobuf使用

protobuf有各种版本的代码包,C++JAVACOBJ-C.NET等。比如google原生的代码,针对桌面系统的C++/JAVA(https://github.com/search?utf8=%E2%9C%93&q=protobuf)

但它们的使用方法类似,主要如下:

1)在LINUX/WINDOWS/IOST系统下编译代码包,编译出工具链,如,protobuf可执行文件

2)用编译出来的工具链将.proto脚本转化为对应的语言文件,如转为C文件。

3)转化出来的文件配合protobuf的库或者源文件就可以在目标环境下使用了

 

嵌入式设备中的使用

嵌入式设备中使用的protobuf版本,我们选择的是nanoprobuf

 

Nanopb is a plain-C implementation of Google's Protocol Buffers data format. It is targeted at 32 bit microcontrollers, but is also fit for other embedded systems with tight (2-10 kB ROM, <1 kB RAM) memory constraints.

 

首先,从http://koti.kapsi.fi/~jpa/nanopb/download/下载Nanopb的最新版本。

Nanopb一般发布4个包,3个含系统名的包是针对该系统已编译好工具链的,另一个是源码包。比如,nanopb-0.3.5-linux-x86.tar.gz就是Linux环境下可直接使用的工具链。我们要下载的就是LINUX版本。

 

下载nanopb-0.3.5-linux-x86.tar.gz完毕后,用命令tar -xvf nanopb-0.3.5-linux-x86.tar.gz解压。

 

然后到example目录下,exampleprotobuf的使用例子,其中simple目录是最简单的一个例子,我们就用simple来说明。

 

进入simple目录,可以看到一个simple.csimle.proto脚本。.proto是结构化脚本,使用前要用工具链将其转为C文件。simplemain函数,里面调用proto脚本转化的C文件里的结果,并演示如何将结构数据转为二进制流,再将二进制流恢复为结构数据。

 

simple路径下,使用命令 ../../generator-bin/protoc --nanopb_out=. simple.proto,将simple.proto转化为simple.pb.csimple.pb.h两个文件。--nanopb_out=. 表示将转化的文件输出到当前目录。注意参数之间的空格。

 

可以看到在simple目录下,有个Makefile脚本,那么我们在simple路径下用make命令就可以编译出simple可执文件了。然后执行./simple,便可看到执行结果。

 

代码稍微解释一下:

第一段是将结构数据转为二进制流:

/* Encode our message */

    {

        /* Allocate space on the stack to store the message data.

         *

         * Nanopb generates simple struct definitions for all the messages.

         * - check out the contents of simple.pb.h!

         * It is a good idea to always initialize your structures

         * so that you do not have garbage data from RAM in there.

         */

        SimpleMessage message = SimpleMessage_init_zero;

        

        /* Create a stream that will write to our buffer. */

        pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));

        

        /* Fill in the lucky number */

        message.lucky_number = 13;

        

        /* Now we are ready to encode the message! */

        status = pb_encode(&stream, SimpleMessage_fields, &message);

        message_length = stream.bytes_written;

        

        /* Then just check for any errors.. */

        if (!status)

        {

            printf("Encoding failed: %s\n", PB_GET_ERROR(&stream));

            return 1;

        }

}

如上,是将message结构数据转为二进制流存到buffer里。这个buffer可以存到文件或者发送到网络。

 

第二段是将二进制流转化为结构数据:

{

        /* Allocate space for the decoded message. */

        SimpleMessage message = SimpleMessage_init_zero;

        

        /* Create a stream that reads from the buffer. */

        pb_istream_t stream = pb_istream_from_buffer(buffer, message_length);

        

        /* Now we are ready to decode the message. */

        status = pb_decode(&stream, SimpleMessage_fields, &message);

        

        /* Check for errors... */

        if (!status)

        {

            printf("Decoding failed: %s\n", PB_GET_ERROR(&stream));

            return 1;

        }

        

        /* Print the data contained in the message. */

        printf("Your lucky number was %d!\n", message.lucky_number);

}

如上,是将二进制流buffer转为message结构数据。

 

以上,都是在LINUX环境下的验证,最后我们要将所需的C文件移植到嵌入式平台上。打开Makefile脚本,可以看到,总共需要的文件是:

simple.c

simple.pb.c 

pb_encode.c

pb_decode.c

pb_common.c

 

Simple.cmain函数,是不用移植的,所以总共就除simple.c4个文件,以及它们对应的头文件:pb_encode.hpb_decode.hpb_common.hpb.hsimple.pb.hsimple.pb.hsimple目录下,其它的在nanopb-0.3.5-linux-x86目录下。将这些文件拷到嵌入式平台下编译就完成了。