首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Nanopb解码

Nanopb解码
EN

Stack Overflow用户
提问于 2022-08-29 13:34:46
回答 1查看 111关注 0票数 0

我目前正在处理其中一个财产。我可以在没有问题的情况下对它们进行编码,然而,解码似乎是一个问题。我不明白为什么不起作用。

我的proto文件如下:

代码语言:javascript
复制
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代码的字节数组:

代码语言:javascript
复制
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上。我该怎么做?

编辑:

根据要求,我的解码器测试功能:

代码语言:javascript
复制
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);
}
EN

回答 1

Stack Overflow用户

发布于 2022-08-30 12:37:46

经过一些搜索和测试,我找到了一个解决办法!

我查看了这些示例,并指出有可能在其中一个字段中进行回调。有可能将Nanopb选项添加到proto文件中,它告诉消息应该生成回调。备选方案:

代码语言:javascript
复制
option (nanopb_msgopt).submsg_callback = true;

通过将这一行添加到proto文件中,它将生成(据我理解)一个设置回调。此回调在解码消息的开始时被调用。这使我们有机会为不同字段设置不同的回调,这取决于我们正在解码的类型。

前面的问题是,不可能将回调函数分配给类型字段,因为它们都共享相同的内存空间。但是,通过设置回调,我们实际上可以查看所接收的内容,并相应地分配回调。

,然而,,有一个陷阱。我发现,该选项将不适用于其中一个中的消息以外的其他任何内容。--这意味着不能将直接回调类型分配给一个字段!

我使用的解决方法是将想要的回调封装在消息中。这将触发设置回调,然后可用于在其中一个中分配正确的回调函数。

例子:

让我们拿出这个proto文件:

代码语言:javascript
复制
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)

然后必须创建设置回调:

代码语言:javascript
复制
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。当您在原型文件中输入该选项时,此变量将被添加到您的邮件结构中。这是如何分配设置回调:

代码语言:javascript
复制
  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时,正确的解码器就会被分配,正确的值将被解码为结构。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73529672

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档