Confusion about right way to decode

53 views
Skip to first unread message

Prince Montano

unread,
Dec 24, 2023, 12:47:50 AM12/24/23
to nanopb
Hello,

I have a ServoTarget.pb.h which contains the following:

/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.8-dev */

#ifndef PB_MESSAGE_ACTUATION_SERVOTARGET_PB_H_INCLUDED
#define PB_MESSAGE_ACTUATION_SERVOTARGET_PB_H_INCLUDED
#include "pb.h"
#include "timestamp.pb.h"

#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif

typedef struct _message_actuation_ServoTarget {
/* / When the target was created */
bool has_time;
google_protobuf_Timestamp time;
/* / The ID of the servo being controlled */
uint32_t id;
/* / The position value of the destination. 0 to 4,095 (0xFFF) is available.
/ The unit is 0.088 [°]. If Goal Position is out of the range, Angle Limit
/ Error Bit (Bit1) of Status Packet is returned as ‘1’ and Alarm is
/ triggered as set in Alarm LED/Shutdown */
float position;
/* / Proportional gain. In proportion to the servo's position error. Gain
/ values are in range 0~254. K_p : p_gain / 8 */
float gain;
/* / Used to set the servo on or off. Typically either 0 (off) or 100 (on) */
float torque;
} message_actuation_ServoTarget;

typedef struct _message_actuation_ServoTargets {
pb_callback_t targets;
} message_actuation_ServoTargets;


#ifdef __cplusplus
extern "C" {
#endif

/* Initializer values for message structs */
#define message_actuation_ServoTarget_init_default {false, google_protobuf_Timestamp_init_default, 0, 0, 0, 0}
#define message_actuation_ServoTargets_init_default {{{NULL}, NULL}}
#define message_actuation_ServoTarget_init_zero {false, google_protobuf_Timestamp_init_zero, 0, 0, 0, 0}
#define message_actuation_ServoTargets_init_zero {{{NULL}, NULL}}

/* Field tags (for use in manual encoding/decoding) */
#define message_actuation_ServoTarget_time_tag 1
#define message_actuation_ServoTarget_id_tag 2
#define message_actuation_ServoTarget_position_tag 3
#define message_actuation_ServoTarget_gain_tag 4
#define message_actuation_ServoTarget_torque_tag 5
#define message_actuation_ServoTargets_targets_tag 1

/* Struct field encoding specification for nanopb */
#define message_actuation_ServoTarget_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, MESSAGE, time, 1) \
X(a, STATIC, SINGULAR, UINT32, id, 2) \
X(a, STATIC, SINGULAR, FLOAT, position, 3) \
X(a, STATIC, SINGULAR, FLOAT, gain, 4) \
X(a, STATIC, SINGULAR, FLOAT, torque, 5)
#define message_actuation_ServoTarget_CALLBACK NULL
#define message_actuation_ServoTarget_DEFAULT NULL
#define message_actuation_ServoTarget_time_MSGTYPE google_protobuf_Timestamp

#define message_actuation_ServoTargets_FIELDLIST(X, a) \
X(a, CALLBACK, REPEATED, MESSAGE, targets, 1)
#define message_actuation_ServoTargets_CALLBACK pb_default_field_callback
#define message_actuation_ServoTargets_DEFAULT NULL
#define message_actuation_ServoTargets_targets_MSGTYPE message_actuation_ServoTarget

extern const pb_msgdesc_t message_actuation_ServoTarget_msg;
extern const pb_msgdesc_t message_actuation_ServoTargets_msg;

/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define message_actuation_ServoTarget_fields &message_actuation_ServoTarget_msg
#define message_actuation_ServoTargets_fields &message_actuation_ServoTargets_msg

/* Maximum encoded size of messages (where known) */
/* message_actuation_ServoTargets_size depends on runtime parameters */
#define message_actuation_ServoTarget_size 45

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif

And I have provided the following callback function and structs:

typedef struct ServoTarget {
    uint8_t id;
    float position;
    float gain;
    float torque;
};

typedef struct ServoTargets {
    ServoTarget targets[20];
    size_t idx;
};

void nanopb_decode_callback(pb_istream_t *stream, const pb_field_t *field, void *arg) {
ServoTargets *servo_targets = (ServoTargets *)arg;
ServoTarget target;
if (!pb_decode(stream, message_actuation_ServoTarget_fields, &target)) {
    // Decoding failed
    return false;
}

if (servo_targets->idx < 20) {
    servo_targets->targets[servo_targets->idx++] = target;
}
else {
    // Expected repeated field size exceeded
    return false;
}
return true;
}

How do I set this as the decode callback function? Would it be like so?

// Decoding time
pb_istream_t input_stream = pb_istream_from_buffer(reinterpret_cast<const pb_byte_t*>(&pb_packets[0]), rx_buf_len - rx_buf_idx);

// Instance of ServoTargets to store the decoded messages
ServoTargets servo_targets_message = {0};

// Set up the callback to handle decoding of the repeated field
message_actuation_ServoTargets_msg.fields[0].cb_funcs.decode = &nanopb_decode_callback;
message_actuation_ServoTargets_msg.fields[0].ptr = &servo_targets_message;

Then accessing it like so, using the servo_targets_message struct:

// Iterate over the decoded ServoTarget messages
for (size_t i = 0; i < 20; i++) {
    ServoTarget *target = &servo_targets_message.targets[i];
    // Access fields of the individual ServoTarget message
    printf("ServoTarget %zu: ID=%lu, Position=%.2f, Gain=%.2f, Torque=%.2f\n",
    i + 1, target->id, target->position, target->gain, target->torque);
}

Is this in the right track? I have been trying to look at the docs (If there was some info that I could not find, I apologise in advance) and how other people did it with similar messages like mine, but I just could not find the cb_funcs.decode field nor the ptr field for message_actuation_ServoTargets_msg.fields[0] in any of the generated files, hence the skepticism.

Thank you very much in advance, and merry Christmas!\

Petteri Aimonen

unread,
Dec 24, 2023, 1:14:38 AM12/24/23
to nan...@googlegroups.com
Hi,

> typedef struct ServoTargets {
> ServoTarget targets[20];
> size_t idx;
> };

If you are going to allocate constant amount of storage for the repeated
field, you can just use field option "max_count = 20" and nanopb will handle
the array automatically. No need to use callbacks.

But I'll assume this is just a placeholder for future code that would have
no limit for the count.

> How do I set this as the decode callback function? Would it be like so?

It would be:

msg.targets.funcs.decode = &nanopb_decode_callback;

where msg is the instance of message_actuation_ServoTargets struct you
are going to pass as destination of pb_decode().

--
Petteri

Prince Montano

unread,
Dec 24, 2023, 2:05:04 AM12/24/23
to nanopb
Thank you for your reply.

In the pb.h file,  the struct is declared as 


typedef struct _message_actuation_ServoTargets {
    pb_callback_t targets;
} message_actuation_ServoTargets;

So should the instance be message_actuation_ServoTargets msg = message_actuation_ServoTargets_init_zero; instead?

And in the decode callback,

void nanopb_decode_callback(pb_istream_t *stream, const pb_field_t *field, void *arg) {
    ServoTargets *servo_targets = (ServoTargets *)arg;
    ServoTarget target;
    if (!pb_decode(stream, message_actuation_ServoTarget_fields, &target)) {
        // Decoding failed
        return false;
    }
    if (servo_targets->idx < 20) {
        servo_targets->targets[servo_targets->idx++] = target;
    }
    else {
        // Expected repeated field size exceeded
        return false;
    }
    return true;
}

Should 
ServoTargets * servo_targets = (ServoTargets *) arg; 
ServoTarget target;

instead be

message_actuation_ServoTargets* servo_targets = (_message_actuation_ServoTargets*) arg; 
message_actuation_ServoTarget target;? (i.e., I can just use the nanopb generated structs instead of the ones I created)

 Furthermore, do I still need to set msg.targets.arg =  to something? I don't really need that do I?

And for accessing I'm guessing its going to be 

for (size_t i = 0; i < 20; i++) {
                message_actuation_ServoTarget *target = msg.targets[i];
                // Access fields of the individual ServoTarget message
                printf("ServoTarget %zu: ID=%lu, Position=%.2f, Gain=%.2f, Torque=%.2f\n",
                    i + 1, target->id, target->position, target->gain, target->torque);
            }

Thank you very much in advance again, I'm still trying to wrap my head around the library so thank you for your patience.
Reply all
Reply to author
Forward
0 new messages