我正在尝试将数据流式传输到微 Controller 上 SD 卡上的日志文件,该微 Controller 从一些传感器读取数据并将值存储在文件中。
为了序列化数据,我将使用 NanoPB,C 的 protobuf 实现,它非常节省资源。
日志文件结构如下:需要写一个由GUID和固件版本组成的短头。在 header 之后,数据流应该是连续的,它应该记录来自传感器的字段而不是 header 值(这应该只发生一次并且在开始时)。
限制是我只能使用一个 .proto 文件进行序列化和反序列化,我想避免使用 .proto 中的“重复”字段然后使用 nanopb 的 C 实现而出现的 Pb_callback 函数。 https://jpa.kapsi.fi/nanopb/docs/concepts.html .
我尝试过的实现如下(字段只是示例):
syntax = "proto3";
import "timestamp.proto";
import "nanopb.proto";
message LogHeader {
string firmware = 1 [(nanopb).max_size = 11];
string GUID = 2 [(nanopb).max_size = 11];
}
message Sensors {
int32 TimeStamp = 3;
// Sensory data
int32 Sens1 = 4;
int32 Sens2 = 5;
int32 Sens3 = 6;
int32 Sens4 = 7;
int32 Sense5 = 8;
我们的想法是拥有一个经过处理后看起来像这样的日志文件:
firmware "1.0.0"
GUID "1231214211321" (example)
Timestamp 123123
Sens1 2343
Sens2 13123
Sens3 13443
Sens4 1231
Sens5 190
Timestamp 123124
Sens1 2345
Sens2 2312
...
但是如果所有字段都在同一条消息中,则每次重复都会记录 GUID 和固件。如果我将它分成 2 条消息,我将无法使用一个原始文件一次性反序列化它们。我需要知道前两条消息的长度,反序列化它们,然后从那里开始处理日志。
最佳答案
I want to avoid Pb_callback functions that emerge from using "repeated" fields in the .proto
请注意,您可以像为字符串指定 max_size
一样为重复字段指定 max_count
,然后您将获得一个简单的数组而不是回调。
While if I split it in 2 messages I have not been able to deserialize them in one go with one proto file.
Protobuf反序列化需要知道消息类型。处理此问题的最常见方法是使用带有子消息的单个顶级消息:
message LogMessage {
optional LogHeader header = 1;
optional Sensors sensors = 2;
}
然后您可以将 header 和传感器字段中的一个或两个设置为 true 或 false,以指示是否要包含该子字段。但是无论内容如何,您总是将序列化和反序列化为 LogMessage
,因此不同消息类型之间不会混淆。
I would need to know the length of the first two messages, deserialize them and then start from there on with the log.
是的,这也是 protobuf 初学者常见的问题。 Protobuf 消息本身不对其长度进行编码,因此如果您在单个文件中有多个消息,则需要以某种方式将它们分开。
A quite common way就是添加一个长度前缀,就像nanopb的pb_encode_delimited()
和pb_decode_delimited()
一样。 C++ protobuf 库也支持这种格式。然而,这样做的一个缺点是许多命令行工具如 protoc
不支持分隔格式,例如Python protobuf 库使它们解码 somewhat complex .
另一种选择是使整个文件看起来像一条消息,但将其分成多个部分。 Protobuf 具有合并功能,也就是说,如果您只是一个接一个地附加消息,它们就会合并在一起。这可以通过在 LogMessage
中包含重复字段来完成:
message LogMessage {
optional LogHeader header = 1;
repeated Sensors sensors = 2 [(nanopb).max_count = 1];
}
现在,如果您对 LogMessage
的多个副本进行编码,每个副本都有一个 sensors
条目,它们将合并在一起。然后,如果您对该文件进行解码,它将显示为带有多个 sensors
条目的单个 LogMessage
。
关于c - 使用 ProtoBuf 将数据流式传输到带有 header 的日志文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58518051/