在嵌入式設備中使用nanopb協議傳輸

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++、JAVA、C、OBJ-C、.NET等。比如google原生的代碼,針對桌面系統的C++/JAVA等(https://github.com/google/protobuf/releases)。

但它們的使用方法類似,主要如下:
1)在LINUX/WINDOWS/IOST系統下編譯代碼包,編譯出工具鏈,如,protobuf可執行文件
2)用編譯出來的工具鏈將.proto腳本轉化爲對應的語言文件,如轉爲C文件。

3)轉化出來的文件配合protobuf的庫或者源文件就可以在目標環境下使用了

3 嵌入式設備中的使用
嵌入式設備中使用的protobuf版本,我們選擇的是nanoprobuf。Nanopb是Google  Protocol Buffers數據格式的簡單C實現它針對32位微控制器,但也適用於其他緊湊(2-10 kB ROM,<1 kB RAM)內存限制的嵌入式系統。

首先,從https://jpa.kapsi.fi/nanopb/download/下載Nanopb的最新版本。Nanopb一般發佈4個包,3個含系統名的包是針對該系統已編譯好工具鏈的,另一個是源碼包。比如,nanopb-0.3.9-linux-x86.tar.gz就是Linux環境下可直接使用的工具鏈。我們要下載的就是LINUX版本。

下載nanopb-0.3.9-linux-x86.tar.gz完畢後,用命令tar -xvf nanopb-0.3.9-linux-x86.tar.gz解壓。
然後到example目錄下,example是protobuf的使用例子,其中simple目錄是最簡單的一個例子,我們就用simple來說明。
進入simple目錄,可以看到一個simple.c和simle.proto腳本。.proto是結構化腳本,使用前要用工具鏈將其轉爲C文件。simple是main函數,裏面調用proto腳本轉化的C文件裏的結果,並演示如何將結構數據轉爲二進制流,再將二進制流恢復爲結構數據。

在simple路徑下,使用命令 ../../generator-bin/protoc --nanopb_out=. simple.proto,將simple.proto轉化爲simple.pb.c和simple.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.c是main函數,是不用移植的,所以總共就除simple.c的4個文件,以及它們對應的頭文件:pb_encode.h、pb_decode.h、pb_common.h、pb.h、simple.pb.h,simple.pb.h在simple目錄下,其它的在nanopb-0.3.5-linux-x86目錄下。將這些文件拷到嵌入式平臺下編譯就完成了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章