I have a proto message defined as:
message SimpleMessage {
repeated int32 number = 1;}
now, after compiling, the field is of pb_callback_t
and I suppose to write that function. (without .options file)
now, where and what should the function contain? where does the data itself being stored and how can I access it/ assign new data to it?
* EDIT *
according to @Groo 's answer, this is the code I tried:
typedef struct {
int numbers_decoded;
} DecodingState;
bool read_single_number(pb_istream_t *istream, const pb_field_t *field, void **arg)
{
// get the pointer to the custom state
DecodingState *state = (DecodingState*)(*arg);
int32_t value;
if (!pb_decode_varint32(istream, &value))
{
const char * error = PB_GET_ERROR(istream);
printf("Protobuf error: %s", error);
return false;
}
printf("Decoded successfully: %d", value);
state->numbers_decoded++;
return true;
}
int main(void) {
int32_t arr[3] = {10, 22, 342};
uint8_t buffer[128];
size_t message_length;
bool status;
SimpleMessage simple = SimpleMessage_init_zero;
printf("\nbefore : arr[0] = %d\n",arr[0]);
// set the argument and the callback fn
simple.number.arg = &arr;
simple.number.funcs.decode = read_single_number;
pb_ostream_t ostream = pb_ostream_from_buffer(buffer, sizeof(buffer));
status = pb_encode(&ostream, SimpleMessage_fields, &simple);
message_length = ostream.bytes_written;
SimpleMessage simple1 = SimpleMessage_init_zero;
simple = simple1;
arr[0] = 0;
pb_istream_t istream = pb_istream_from_buffer(buffer, message_length);
// this function will call read_single_number several times
status = pb_decode(&istream, SimpleMessage_fields, &simple);
printf("\nafter : arr[0] = %d\n",arr[0]);
return EXIT_SUCCESS;
}
and the output is:
before : arr[0] = 10
Decoded successfully: 17
after : arr[0] = 0
what do I do wrong?
You can use some nanopb-specific proto flags to force nanopb to generate structs with statically allocated arrays.
However, the default behavior of nanopb's protogen is to generate a callback function which is called by nanopb during encoding (once for the entire list) and decoding (once for each item in the list). This is sometimes preferred in low-memory embedded systems, because you don't need to allocate more than one item at a time.
So, for your
.proto
file:You might get something like:
Meaning you will have to create your own callback function which will be called for each item in succession.
So for simplicity, let's say you have a simple "variable length" list like this:
Obviously, for such an example, using callbacks wouldn't make any sense, but it makes the example simple.
Encoding callback must iterate through the list, and write the protobuf tag and the value for each item in the list:
Decoding callback is called once for each item, and "appends" to the list:
With these two in place, you must be careful to assign the right callback to the right function:
And similar for decoding:
If you have a repeated struct inside your message, your callback will not use nanopb primitive functions (like
pb_decode_varint32
above), but againpb_decode
for each concrete message type. Your callback can also attach new callbacks to those nested structs, if needed.