cflaskprotocol-buffersiotnanopb

DecodeError when reading Proto Buffer message from nanopb


I implemented a small HttpClient for an IoT device and wanted to use Proto Buffer as a communication format. Because of the constraints of the platform I am using nanopb. That's the relevant code in 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);
[...]

I created a small flask server which exposes an endpoint. When I try to decode the message, I get the following error: google.protobuf.message.DecodeError: Error parsing message with type 'pb.MEvent'

That the code for it:

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)

I tried to use io.ByteStream and read it then and I also tried to encode the bytes with ASCII and UTF-8 but neither of that approaches worked.

Could you please help me find out, what is causing the problem? The error message is not that helpful.

Update

This is the content fo the proto file:

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;
}

And here are some data points:

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

Solution

  • 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

    I'm using the nanopb/tests/raw_decode to analyze this. Marc Gravell's decode utility used to be great for this but for some reason it does not work very well for corrupted data anymore.

    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 | build/raw_decode/raw_decode
    
    At 0: field tag 1, wire type 5 (32BIT), fixed32 value (4 bytes): 0x3e27d798
    At 5: field tag 2, wire type 5 (32BIT), fixed32 value (4 bytes): 0xbdadf7bf
    At 10: field tag 3, wire type 5 (32BIT), fixed32 value (4 bytes): 0x411f7046
    At 15: field tag 4, wire type 5 (32BIT), fixed32 value (4 bytes): 0x3b7033b5
    At 20: field tag 5, wire type 5 (32BIT)
    ERROR: Failed to parse fixed32: io error
    LATEST BYTES READ (21 to 21): 
    

    It appears your message is cut short. The amount of buffer space you reserve on this line is not large enough:

    uint8_t m_buffer[21];

    If you check the return value of pb_encode() it is probably also returning false and stream.errmsg indicates that the buffer is full.