Nanopb是一个ANSI-C库,用于以Google的协议缓冲区格式编码和解码消息,而对RAM和代码空间的要求最低。
它主要适用于32位微控制器。
本文档适用于nanopb 0.4.0及更高版本。有关旧版本的文档,请参见此处。
对于运行时程序,对于类型声明,始终需要pb.h,对于基本函数,始终需要pb_common.h / c。根据您是否要编码,解码还是同时进行编码,还需要pb_encode.h / c或pb_decode.h / c。
高级编码和解码功能采用指向pb_msgdesc_t结构的指针,该结构描述了消息结构的字段。通常,您希望这些文件从.proto文件自动生成。工具脚本nanopb_generator.py完成了此任务。
因此,典型的项目可能包含以下文件:
Nanopb运行库:
- pb.h
- pb_common.h和pb_common.c(始终需要)
- pb_decode.h和pb_decode.c(用于解码消息)
- pb_encode.h和pb_encode.c(编码消息所需)
协议描述(可以有很多):
- person.proto(仅作为示例)
- person.pb.c(自动生成,包含const数组的初始化程序)
- person.pb.h(自动生成,包含类型声明)
特征
- 纯C运行
- 小代码量(5–10 kB,取决于处理器和编译选项,以及任何消息定义)
- 小型ram用法(通常为〜300字节堆栈,加上任何消息结构)
- 允许指定字符串和数组的最大大小,以便可以静态分配它们。
- 不需要malloc:所有内容都可以静态分配或在堆栈上分配。可选的malloc支持。
- 您可以单独使用编码器或解码器将代码大小减半。
- 支持大多数protobuf功能,包括:所有数据类型,嵌套子消息,默认值,重复和可选字段,一个,打包数组,扩展字段。
- 回调机制,用于处理大于可用RAM容量的消息。
- 广泛的测试集。
局限性
- 为了缩减代码大小,已经牺牲了一些速度。
- 编码侧重于写入流。仅对于内存缓冲区,可以使其效率更高。
- 不支持不赞成使用的协议缓冲区功能,称为“组”。
- 生成的结构中的字段按标记号排序,而不是.proto文件中的自然排序。
- 解码和重新编码消息时,不会保留未知字段。
- 不支持反射(运行时自省)。例如,您不能通过在字符串中给出名称来请求字段。
- 数字数组始终被编码为压缩,即使未在.proto中标记为压缩。
- 仅在回调和malloc模式下支持消息之间的循环引用。
- Nanopb在版本之间没有稳定的ABI(应用程序二进制接口),因此将其用作共享库(.so / .dll)需要格外小心。
对于初学者,请考虑以下简单消息:
message Example {
required int32 value = 1;
}
将其保存在message.proto中并进行编译:
user@host:~$ python nanopb/generator/nanopb_generator.py message.proto
您现在应该在message.pb.h中:
typedef struct {
int32_t value;
} Example;
extern const pb_msgdesc_t Example_msg;
#define Example_fields &Example_msg
然后,您必须包括nanopb头文件和生成的头文件:
#include <pb_encode.h>
#include "message.pb.h"
现在在您的主程序中执行以下操作以对消息进行编码:
Example mymessage = {42};
uint8_t buffer[10];
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
pb_encode(&stream, Example_fields, &mymessage);
之后,缓冲区将包含编码后的消息。消息中的字节数存储在stream.bytes_write中。您可以将消息提供给protoc --decode = Example message.proto以验证其有效性。
有关简单案例的完整示例,请参见examples / simple / simple.c。有关具有网络接口的更复杂示例,请参见examples / network_server子目录。
Nanopb应该使用大多数与ansi-C兼容的编译器进行编译。但是,它需要一些头文件才能使用:
- string.h,具有以下功能:strlen,memcpy,memset
- stdint.h,用于int32_t等的定义。
- stddef.h,用于定义size_t
- stdbool.h,用于定义bool
- limits.h,用于定义CHAR_BIT
如果编译器没有随附这些头文件,则可以使用extra / pb_syshdr.h文件。它包含有关如何提供依赖关系的示例。您可能需要对其进行一些修改以适合您的自定义平台。
要使用pb_syshdr.h,请将 PB_SYSTEM_HEADER定义为“ pb_syshdr.h”(包括引号)。同样,您可以提供一个自定义包含文件,该文件应提供上面列出的所有依赖项。
广泛的单元测试和测试用例包含在测试文件夹下。
要构建测试,您将需要scons构建系统。这些测试应可在大多数平台上运行。Windows和Linux版本均经过定期测试。这些测试还支持嵌入式目标:定期测试STM32(ARM Cortex-M)和AVR版本。
除了构建系统之外,您还需要有效的Google Protocol Buffers 协议编译器以及Protocol Buffers的Python绑定。
安装依赖项的最简单方法是使用Python软件包管理器pip,该软件包可在Python支持的所有平台上运行:
pip install scons protobuf grpcio-tools