Search code examples
nanopb

Nanopb encode empty when only fields in submessages


With this settings.proto file

syntax = "proto3";

message SerialPort
{
    int32 baudrate = 3;
}

message Settings
{
    SerialPort serialInterface = 1;
    int32 test = 2;
}

I try to encode a message that only has the baudrate set with this:

#include "Arduino.h"

#include <stdio.h>
#include <stdlib.h>
#include "settings.pb.h"
#include <pb_encode.h>
#include <pb_decode.h>
#include <pb_common.h>
#include <pb.h>


void setup() {
    // Create a Settings message with a non-zero baudrate
    Settings settings = Settings_init_zero;
    settings.serialInterface.baudrate = 9600;

    // Allocate a buffer to hold the encoded message
    uint8_t buffer[Settings_size] = {0};

    // Encode the message into the buffer
    pb_ostream_t stream = pb_ostream_from_buffer(buffer, Settings_size);
    pb_encode(&stream, Settings_fields, &settings);
    printf("written %d\r\n", stream.bytes_written);
    // Print the contents of the buffer (for debugging purposes)
    for (int i = 0; i < Settings_size; i++)
    {
        printf("%X ", buffer[i]);
    }
    printf("\n");
    delay(100000);
}

void loop(){}

I expected an encoded array, but I get the following output:

written 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 

If I add settings.test = 1000; to the code, I get the output:

written 3
10 E8 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 

Testing with Python, I get the same 3 bytes output with a message that only has the test:

import settings_pb2
import google.protobuf.message
from google.protobuf.json_format import MessageToJson
from cobs import cobs
import binascii
import base64

s = project_settings_pb2.Settings()
s.test = 1000
print(MessageToJson(s))
try:
    s_pb_encoded = s.SerializeToString()
except google.protobuf.message.EncodeError as e:
    log.exception(e)
    exit(1)
print(f"encoded  {(''.join(f'0x{c:02x} ' for c in s_pb_encoded))}")

and if I add s.serialInterface.baudrate = 9600 i get

{
  "test": 1000,
  "serialInterface": {
    "baudrate": 9600
  }
}
encoded  0x10 0xe8 0x07 0x52 0x03 0x18 0x80 0x4b 

So it looks like the way I encode with Nanopb does not include submessages. What am I doing wrong?


Solution

  • Submessage fields have a separate boolean has_field that determines whether the submessage is present. You need to set it to true.