【问题标题】:DecodeError when reading Proto Buffer message from nanopb从 nanopb 读取 Proto Buffer 消息时出现 DecodeError
【发布时间】:2021-11-30 07:53:47
【问题描述】:

我为 IoT 设备实现了一个小型 HttpClient,并希望使用 Proto Buffer 作为通信格式。由于平台的限制,我使用的是 nanopb。这是C中的相关代码:

#include <pb_encode.h>
#include "device_data.pb.h"
#include <ESP8266HTTPClient.h>

[...]
pb_MEvent m_event = pb_MEvent_init_zero;
uint8_t m_buffer[21];
pb_ostream_t stream = pb_ostream_from_buffer(m_buffer, 21);
pb_encode(&stream, pb_MEvent_fields, &m_event);

int httpCode = httpClient.POST(m_buffer, stream.bytes_written);
[...]

我创建了一个暴露端点的小型烧瓶服务器。当我尝试解码消息时,我收到以下错误:google.protobuf.message.DecodeError: Error parsing message with type 'pb.MEvent'

它的代码:

from flask import Flask, request

from device_data_pb2 import MEvent

app = Flask(__name__)

@app.route("/", methods = ['POST', "GET"])
def hello_world():
    m_event = MEvent()

    m_event.ParseFromString(request.data)
    print(m_event)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port= 5000)

我尝试使用 io.ByteStream 并随后读取它,我还尝试使用 ASCII 和 UTF-8 对字节进行编码,但这些方法都不起作用。

您能帮我找出问题所在吗?错误消息没有那么有用。

更新

这是 proto 文件的内容:

syntax = "proto2";
package pb;

message MEvent {
    required float accelX = 1;
    required float accelY = 2;
    required float accelZ = 3;
    required float gyroX = 4;
    required float gyroY = 5;
    required float gyroZ = 6;
    required int64 msec = 7;
}

这里有一些数据点:

DATA:
0.16 -0.08 9.96 0.00 -0.00 0.02 0
HEX:
0d:98:d7:27:3e:15:bf:f7:ad:bd:1d:46:70:1f:41:25:b5:33:70:3b:2d

DATA:
0.16 -0.09 9.96 0.00 -0.00 0.02 0
HEX:
0d:cd:7d:20:3e:15:56:ab:bc:bd:1d:5f:6b:1f:41:25:79:22:a0:3b:2d


DATA:
0.15 -0.10 9.96 0.00 -0.00 0.02 0
HEX:
0d:89:0a:1e:3e:15:21:05:c4:bd:1d:de:52:1f:41:25:b5:33:70:3b:2d

【问题讨论】:

  • 请在 .proto 文件中包含 MEvent 的消息定义,并在 request.data 中包含原始数据的十六进制转储。
  • 我添加了 float 和 int 数据及其对应的十六进制表示。我把它打印在板上和烧瓶服务器上,没有区别。所以板子和服务器之间的通信正常,看来数据本身有问题。

标签: c flask protocol-buffers iot nanopb


【解决方案1】:

数据:0.16 -0.08 9.96 0.00 -0.00 0.02 0 十六进制:0d:98:d7:27:3e:15:bf:f7:ad:bd:1d:46:70:1f:41:25:b5:33:70:3b:2d

我正在使用nanopb/tests/raw_decode 对此进行分析。 Marc Gravell 的 decode utility 曾经对此非常有用,但由于某种原因,它不再适用于损坏的数据。

user@host:~/nanopb/tests$ echo 0d:98:d7:27:3e:15:bf:f7:ad:bd:1d:46:70:1f:41:25:b5:33:70:3b :2d \ | tr -d ':' | xxd -r -p |构建/raw_decode/raw_decode 在 0:字段标签 1,线类型 5(32BIT),固定 32 值(4 字节):0x3e27d798 在 5:字段标签 2,电线类型 5(32BIT),固定 32 值(4 字节):0xbdadf7bf 在 10:字段标签 3,电线类型 5(32BIT),固定 32 值(4 字节):0x411f7046 在 15:字段标签 4,电线类型 5(32BIT),固定 32 值(4 字节):0x3b7033b5 在 20:字段标签 5,电线类型 5 (32BIT) 错误:无法解析fixed32:io错误 读取的最新字节(21 到 21):

您的消息似乎被缩短了。 您在此行预留的缓冲区空间不够大:

uint8_t m_buffer[21];

如果你检查pb_encode()的返回值,它可能也返回falsestream.errmsg表示缓冲区已满。

【讨论】:

  • 感谢您的回答!由于过去的某种原因,stream.bytes_written 返回 21,我将其视为常量。我重新评估了这个,现在它可以工作了。
  • 是的,protobuf 是可变长度格式。 Nanopb 在标头中生成一个#define MEvent_size xxx,您可以将其用于缓冲区大小,它是消息类型将具有的最大编码大小。
猜你喜欢
  • 1970-01-01
  • 2021-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
  • 1970-01-01
  • 1970-01-01
  • 2021-12-27
相关资源
最近更新 更多