Help with decoding submessages

476 views
Skip to first unread message

Sean McFarlane

unread,
Mar 29, 2021, 11:32:41 PM3/29/21
to nanopb
Im trying to implement nanopb on a esp8266 and I'm having a problem accessing the submessage members to assign a decode function

Here is the relevant portion of my proto file

message Payload {
    message Metric {

        optional string   tagname       = 1;        // Metric name - should only be included on birth
        optional uint64   alias         = 2;        // Metric alias - tied to name on birth and included in all later DATA messages
        optional uint64   timestamp     = 3;        // Timestamp associated with data acquisition time
        optional uint32   datatype      = 4;        // DataType of the metric/tag value
        optional bool     is_historical = 5;        // If this is historical data and should not update real time tag
        optional bool     is_transient  = 6;        // Tells consuming clients such as MQTT Engine to not store this as a tag
        optional bool     is_null       = 7;        // If this is null - explicitly say so rather than using -1, false, etc for some datatypes.
        optional MetaData metadata      = 8;        // Metadata for the payload
        optional PropertySet properties = 9;

        oneof value {
            uint32   int_value                      = 10;
            uint64   long_value                     = 11;
            float    float_value                    = 12;
            double   double_value                   = 13;
            bool     boolean_value                  = 14;
            string   string_value                   = 15;
            bytes    bytes_value                    = 16;       // Bytes, File
            DataSet  dataset_value                  = 17;
            Template template_value                 = 18;
            MetricValueExtension extension_value    = 19;
        }
     .....
     repeated Metric metrics = 2
}

So Metric is a submessage of Payload. This is the code where I initialize my message and do the decoding

Payload test_payload = Payload_init_zero;
 pb_istream_t stream = pb_istream_from_buffer(payload, length);
 test_payload.metrics.funcs.decode = metrics_decode;
 test_payload.metrics.tagname.funcs.decode = print_string;

If I attempt to assign the decode function here as Petteri does in his decode examples 


Then the arduino compiler gives me the following error

mqtt_esp8266:104:24: error: 'pb_callback_t' has no member named 'tagname'
   test_payload.metrics.tagname.funcs.decode = print_string;


However, if I do the same in my metrics_decode callback function I don't get any errors

bool metrics_decode(pb_istream_t *stream, const pb_field_t *field, void** args) {
  Serial.println("metrics decode executed");
  String tagname;
  Payload_Metric payload_metrics = Payload_Metric_init_zero;
  payload_metrics.tagname.funcs.decode = print_string;
.
.
.
}

Is this the correct way to decode submessages? Assigning the function pointers inside the callback of the parent message? Based on the example I must be doing something wrong but I'm confused as to why it would recognize that tagname is a field at one level but not another.



Petteri Aimonen

unread,
Mar 29, 2021, 11:58:15 PM3/29/21
to nan...@googlegroups.com
Hi,

> Is this the correct way to decode submessages? Assigning the function
> pointers inside the callback of the parent message? Based on the example I
> must be doing something wrong but I'm confused as to why it would recognize
> that tagname is a field at one level but not another.

It's because the message structure for the submessage does not exist
before you create it in the callback.

But the normal way to use nanopb would be to assing maximum sizes &
counts to fields whenever that is possible, and only use callbacks when
really needed. In the network_server example, all strings are assigned
maximum sizes and only the repeated submessage list needs a callback.

--
Petteri

Sean McFarlane

unread,
Mar 30, 2021, 6:52:57 AM3/30/21
to nanopb
> It's because the message structure for the submessage does not exist
before you create it in the callback.

Isn't that what the initializer Payload_init_zero is for?

I appreciate the quick response.

Petteri Aimonen

unread,
Mar 30, 2021, 6:56:45 AM3/30/21
to nan...@googlegroups.com
Hi,

> Isn't that what the initializer Payload_init_zero is for?

The idea of callbacks is that the Payload structure does not actually
contain any storage for Payload_Metric. Such a message only exists
when the callback allocates it on the stack.

--
Petteri

Sean McFarlane

unread,
Mar 30, 2021, 12:00:04 PM3/30/21
to nanopb
How do I use the data outside of my callback function then?

Petteri Aimonen

unread,
Mar 30, 2021, 12:12:19 PM3/30/21
to nan...@googlegroups.com
Hi,

> How do I use the data outside of my callback function then?

Usually you would use it right there, inside the callback.
That's the point of the callbacks, to avoid allocating storage for all
the data.

If you just want to store the data in memory and use it at your leisure,
define max_count/max_size for the fields and you get normal, easy to use
C arrays.

--
Petteri

Sean McFarlane

unread,
Mar 30, 2021, 10:45:11 PM3/30/21
to nanopb
Thanks for the help Petteri!
Reply all
Reply to author
Forward
0 new messages