Recently started exploring nanopb - apology if my questions sound sily. I faced some issues while assigning and retrieval of strings and integers when I modified simple example of nanopb. Let me give my steps before my questions -
- I defined simple.proto file
message Device{
optional string devid =1;
optional string mac = 2;
optional string cpu=3 [default = "x86"] ;
optional bool isSecured=4;
optional int32 uptime = 5 [default = 1234];
}
- Also defined simple.option
Device.devid max_size:64
Device.cpu max_size:64
Then I compiled as usual : protoc -osimple.pb simple.proto
- Here is my code :
3a) Using same string encode decode utility function as in How to encode a string when it is a pb_callback_t type
//string encode decode to pb
bool encode_string(pb_ostream_t* stream, const pb_field_t* field, void* const* arg)
{
const char* str = (const char*)(*arg);
if (!pb_encode_tag_for_field(stream, field))
return false;
return pb_encode_string(stream, (uint8_t*)str, strlen(str));
}
bool print_string(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint8_t buffer[1024] = {0};
/* We could read block-by-block to avoid the large buffer... */
if (stream->bytes_left > sizeof(buffer) - 1)
return false;
if (!pb_read(stream, buffer, stream->bytes_left))
return false;
/* Print the string, in format comparable with protoc --decode.
* Format comes from the arg defined in main(). */
printf((char*)*arg, buffer);
return true;
}
3b) here is my main code snippet based on simple.c of example -
/* This is the buffer where we will store our message. */
uint8_t buffer[128];
size_t message_length;
bool status;
/* Encode our message */
{
/* Allocate space on the stack to store the message data, check out the contents of simple.pb.h
* good to always initialize your structures so that no garbage data from RAM in there. */
//Device message = Device_init_zero; //init zero for empty
Device message = Device_init_default; //init default for default
/* Create a stream that will write to our buffer. */
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
/* Fill in the data */
message.devid.arg = "device1";
message.devid.funcs.encode = &encode_string;
//strcpy(message.devid,"device1"); // no easier way like this ?
message.isSecured = true; // should be 1 if printed with %d
message.uptime=9876; // should change, why it is not working ?
/* Now we are ready to encode the message! */
// encode stream to buffer , also get the buffer length
status = pb_encode(&stream, Device_fields, &message);
message_length = stream.bytes_written;
/* Then just check for any errors.. */
if (!status)
{
printf("Encoding failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
}
/* Now we could transmit the message over network, store it in a file etc. */
/* just decode it immediately. */
{
/* Allocate space for the decoded message. */
Device message = Device_init_zero;
/* Create a stream that reads from the buffer. */
pb_istream_t stream = pb_istream_from_buffer(buffer, message_length);
message.devid.funcs.decode = &print_string;
message.devid.arg = "before decode Device - devid: %s \n"; //works here
message.cpu.funcs.decode = &print_string;
message.cpu.arg = "before decode Device -cpu: %s \n"; //where in op?
printf("before decode isSecured %d\n",message.isSecured); // doesn't work
printf("before decode uptime %d\n",message.uptime); //doesn't work
/* Now ready to decode the message. */
// decode stream buffer into message
status = pb_decode(&stream, Device_fields, &message);
/* Check for errors... */
if (!status)
{
printf("Decoding failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
/* Print the data contained in the message. */
message.devid.funcs.decode = &print_string;
message.devid.arg = "after decode Devic - devid: %s \n"; // doesn't work here
printf(" after decode isSecured %d\n",message.isSecured); // prints default 0
printf(" after decode uptime %d\n",(int)message.uptime); //prints default assigned in proto
}
- The output after build and run :
$ ./simple
before decode isSecured 0
before decode uptime 0
before decode Device - devid: device1
after decode isSecured 0
after decode uptime 1234
My queries ( also added my inline comments in code) :
- In original simple.c message.lucky_number=13 assignment works but here message.uptime assignment is not working , it is taking default value. Similarly assigning boolean value to message.isSecured is not working. Please tell where is my fault.
- I used Device_init_default before pb_encode as some have default values and Device_init_zero before pb_decode call as it will populate after decode. Is my approach correct ?
- Is there any simpler way to assign string value using strcpy and printing it in C way by printf("%s",strvar) apart from the encode_string and decode_string util ?
- The string is printed only before pb_decode call but uptime default value is printed after pb_decode call. Also boolean value assignment is not working. Why ? What is my mistake ?
- I saw encode string and int functions in https://github.com/nanopb/nanopb/blob/master/tests/callbacks/encode_callbacks.c How to encode and decode float and boolean ?
Thanks in anticipation
If you look into the generated
.pb.h
file, you'll find that every optional field has a booleanhas_field
. You'll have to set that to true also, to signify that the field is present.That's fine.
Because you have already set a
max_size
for your string fields, they should be generated as achar
array instead of callbacks. You can try passing-v
switch like:../generator/nanopb_generator.py -v simple.pb
to see more verbose messages that can point out why the option is not applying. Perhaps the file name is incorrect or the message name is incorrect.Well, usually you wouldn't have to resort to callbacks. But if you decide you need them, you can encode booleans with
pb_encode_varint()
and floats withpb_encode_fixed32()
. For studying callbacks, the protobuf encoding documentation and this test case can be helpful.You may find the
network_server
example useful to study.Also, the Stack Overflow format works best when you have only a single question per post. That way the questions and answers remain focused and easy to follow.