概要
Nanopb 是 Google Protocol Buffers数据格式的纯 C 实现 。它针对 32 位微控制器,但也适用于内存限制严格(<10 kB ROM、<1 kB RAM)的其他嵌入式系统。用过ProtoBuf
的人,再去理解nanopb
就不难了。可以理解为ProtoBuf
的C语言版本,适用于嵌入式的版本。
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 (<10 kB ROM, <1 kB RAM) memory constraints.
nanopb的维护还是很贴心的,即为喜欢“折腾”的人提供了源码和各种应用场景下的例程、脚本,官网也提供了适合“小白”使用的版本。
本文中,主要针对小白使用进行说明,因为你不需要给你的电脑配置任何环境和依赖库,这一点非常便捷。
基本步骤
To use the nanopb library, you need to do two things:
-
Compile your .proto files for nanopb, using protoc.
-
Include pb_encode.c, pb_decode.c and pb_common.c in your project.
就是两步:
-
把自己的proto文件编译为c语言的头文件和源文件;
-
把编译生成的文件和nanopb相关的头文件和源文件放到我们的项目文件中使用。
编译proto文件
Windows
和Linux
版本操作基本一致,以Windows
为例。
首先从这里下载release版本。[Nanopb - downloads]
里,我们下载0.4.7
的Windows
和Linux
版本。
然后解压,只需要generator-bin
这个文件夹即可。
然后再generator-bin
的目录再新建2个文件夹,my_proto
用于存放自己的待编译的proto文件,generated
用于存放编译后的头文件和源文件,这样的目的是为了方便进行分类管理。
比如my_proto
文件夹下面存放了2个proto文件。
然后打开终端,输入下面的命令: .\generator-bin\nanopb_generator.exe -I .\my_proto -D .\generated simple.proto simple2.proto
-I
制定proto文件的目录,-D
是生成文件的目录。执行完成后,generated
文件夹下有就生成了对应的头文件和源文件,如下图所示。
至此,编译proto的任务完成。
在项目代码中使用
把上文中编译到generated
文件夹中的文件和generator-bin
中的下面7个文件拷贝到项目中就可以编译了。
使用demo
examples
有很多例子,这里不再赘述。
#include <stdio.h>
#include <pb_encode.h>
#include <pb_decode.h>
#include "simple.pb.h"
int main()
{
/* This is the buffer where we will store our message. */
uint8_t buffer[128];
size_t message_length;
bool status;
/* 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;
}
}
/* Now we could transmit the message over network, store it in a file or
* wrap it to a pigeon's leg.
*/
/* But because we are lazy, we will just decode it immediately. */
{
/* 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", (int)message.lucky_number);
}
return 0;
}
引用
code:https://github.com/nanopb/nanopb
移植报错解决
这里使用的是c99,所以需要定义
#define PB_C99_STATIC_ASSERT
/* Test that PB_STATIC_ASSERT works
* If you get errors here, you may need to do one of these:
* - Enable C11 standard support in your compiler
* - Define PB_C99_STATIC_ASSERT to enable C99 standard support
* - Define PB_NO_STATIC_ASSERT to disable static asserts altogether
*/
PB_STATIC_ASSERT(1, STATIC_ASSERT_IS_NOT_WORKING)