我目前正在处理其中一个财产。我可以在没有问题的情况下对它们进行编码,然而,解码似乎是一个问题。我不明白为什么不起作用。
我的proto文件如下:
syntax = "proto2";
message stringCallback{
required string name = 1;
required string surname = 2;
required int32 age = 3;
repeated sint32 values = 4;
repeated metrics metric_data = 5;
oneof payload {
int32 i_val = 6;
float f_val = 7;
string msg = 8;
}
}
message metrics{
required int32 id = 1;
required string type = 2;
required sint32 value = 3;
}每当我从C#应用程序发送一条包含在有效负载中的整数的消息时,就没有问题解码。我也得到了正确的int值和which_payload值。
然后我试着送一只花车。这导致了一个与我通过C#发送的值不相对应的值(这很有意义,因为我使用了“标准解码器”,这意味着它把它当作int而不是fixed32),我不知道如何告诉解码器用fixed32选项来解码这个值。
最后,发送包含消息的有效负载导致不正确的which_payload值(输入None: 0),而没有相应的消息。即使在解码函数之前,我也分配了一个回调函数来解码字符串(工作得很好)。
更多信息:
这是我发送给包含有效负载中的字符串的Nanopb代码的字节数组:
0A 04 4B 65 65 73 12 07 76 61 6E 20 44 61 6D 18 34 20 02 20 04 20 06 20 08 20 0A 20 0C 20 0E 20 10 20 12 20 14 20 16 20 18 2A 0C 08 01 12 06 53 65 6E 73 6F 72 18 04 2A 0A 08 02 12 04 44 61 74 61 18 0A 2A 0E 08 03 12 08 57 69 72 65 6C 65 73 73 18 0E 2A 0D 08 04 12 07 54 65 73 74 69 6E 67 18 04 2A 10 08 05 12 0A 46 72 6F 6E 74 20 64 6F 6F 72 18 0A 2A 1B 08 06 12 15 54 68 69 73 20 69 73 20 61 20 72 61 6E 64 6F 6D 20 6E 61 6D 65 18 0E 42 10 48 65 6C 6C 6F 20 66 72 6F 6D 20 6F 6E 65 6F 66我从一个在线译码器得到正确的解码变量,但不是在Nanopb上。我该怎么做?
编辑:
根据要求,我的解码器测试功能:
void test_decode(byte* payload, unsigned int length){
IntArray I_array = {0, 0};
MetricArray M_array = {0,0};
char name[MAX_STRING_LENGTH];
char surname[MAX_STRING_LENGTH];
char msg[MAX_STRING_LENGTH];
stringCallback message = stringCallback_init_zero;
message.name.funcs.decode = String_decode;
message.name.arg = &name;
message.surname.funcs.decode = String_decode;
message.surname.arg = &surname;
message.values.funcs.decode = IntArray_decode;
message.values.arg = &I_array;
message.metric_data.funcs.decode = MetricArray_decode;
message.metric_data.arg = &M_array;
message.payload.msg.arg = &msg;
message.payload.msg.funcs.decode = String_decode;
pb_istream_t istream = pb_istream_from_buffer(payload, length);
if(!pb_decode(&istream, stringCallback_fields, &message)){
Serial.println("Total decoding failed!");
return;
}
Serial.println(name);
Serial.println(surname);
Serial.println(message.age);
Serial.println(I_array.count);
Serial.println(M_array.count);
Serial.println();
MetricArray_print(&M_array);
Serial.println();
Serial.println("Oneof: ");
Serial.println(message.which_payload);
}发布于 2022-08-30 12:37:46
经过一些搜索和测试,我找到了一个解决办法!
我查看了这些示例,并指出有可能在其中一个字段中进行回调。有可能将Nanopb选项添加到proto文件中,它告诉消息应该生成回调。备选方案:
option (nanopb_msgopt).submsg_callback = true;通过将这一行添加到proto文件中,它将生成(据我理解)一个设置回调。此回调在解码消息的开始时被调用。这使我们有机会为不同字段设置不同的回调,这取决于我们正在解码的类型。
前面的问题是,不可能将回调函数分配给类型字段,因为它们都共享相同的内存空间。但是,通过设置回调,我们实际上可以查看所接收的内容,并相应地分配回调。
,然而,,有一个陷阱。我发现,该选项将不适用于其中一个中的消息以外的其他任何内容。--这意味着不能将直接回调类型分配给一个字段!
我使用的解决方法是将想要的回调封装在消息中。这将触发设置回调,然后可用于在其中一个中分配正确的回调函数。
例子:
让我们拿出这个proto文件:
syntax = "proto2";
message callback{
required string name = 1;
required string surname = 2;
required int32 age = 3;
repeated sint32 values = 4;
repeated metrics metric_data = 5;
oneof payload {
int32 i_val = 6;
float f_val = 7;
string msg = 8;
payloadmsg p_msg = 9;
payloadmsg2 p_msg2 = 10;
}
}
message metrics{
required int32 id = 1;
required string type = 2;
required sint32 value = 3;
}
message payloadmsg{
required int32 id = 1;
required string type = 2;
required string msg = 3;
repeated sint32 values = 4;
}
message payloadmsg2{
required int32 id = 1;
required string type = 2;
required string msg = 3;
repeated sint32 values = 4;
}我给了这个proto文件中的字符串一个最大长度,它删除了它们的回调类型,并将其交换为一个字符数组。
出于测试目的,我没有为payloadmsg消息中的整数数组指定大小。
目标是解码存储在payloadmsg消息中的数组,具体取决于接收的类型(payloadmsg或payloadmsg2)
然后必须创建设置回调:
bool Oneof_decode(pb_istream_t *stream, const pb_field_t *field, void** arg){
Callback* msg = (Callback*)field->message;
switch(field->tag){
case stringCallback_p_msg_tag:{
Serial.println("Oneof type: p_msg detected!");
payloadmsg* p_message = (payloadmsg*)field->pData;
IntArray* array = (IntArray*)*arg;
p_message->values.arg = array;
p_message->values.funcs.decode = IntArray_decode;
break;
}
case stringCallback_p_msg2_tag:{
Serial.println("Oneof type: p_msg2 detected!");
payloadmsg2* p_message2 = (payloadmsg2*)field->pData;
IntArray* array = (IntArray*)*arg;
p_message2->values.arg = array;
p_message2->values.funcs.decode = IntArray_decode;
break;
}
}
return true;
}我们在解码时查看接收到的标记,以确定必须分配哪种类型的回调。这是通过访问字段来完成的。通过使用开关情况,我们可以根据字段标记来决定要分配什么解码回调函数。我们像普通一样传递参数和解码器函数,之后一切都被正确设置.
最后,我们将这个回调集分配给编译器生成的变量cb_payload。当您在原型文件中输入该选项时,此变量将被添加到您的邮件结构中。这是如何分配设置回调:
message.cb_payload.arg = &I_array;
message.cb_payload.funcs.decode = Oneof_decode;
pb_istream_t istream = pb_istream_from_buffer(payload, length);
if(!pb_decode(&istream, stringCallback_fields, &message)){
Serial.println("Total decoding failed!");
return;
}我将自己的IntArray结构作为参数传递给cb_payload函数,然后将其传递给正确分配的解码器。
其结果是,每当我解码payloadmsg或payloadmsg2时,正确的解码器就会被分配,正确的值将被解码为结构。
https://stackoverflow.com/questions/73529672
复制相似问题