簡體   English   中英

解碼一個 Nanopb

[英]Decoding oneof Nanopb

我目前正在使用 oneof 屬性。 我能夠毫無問題地對它們進行編碼,但是,解碼似乎是一個問題。 我不明白為什么它不起作用。

我的原型文件如下所示:

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# 應用程序發送一條消息,該消息在有效負載中包含 integer 時,解碼就沒有問題。 我也得到了正確的 int 值和 which_payload 值。

然后我嘗試發送一個浮點數。 這導致一個值與我通過 C# 發送的值不對應(這是有道理的,因為我使用“標准解碼器”,這意味着它將其視為 int 而不是 fixed32)我不知道該怎么說解碼器使用 fixed32 選項解碼此值。

最后發送包含消息的有效負載會導致 which_payload 值不正確(無類型:0)並且沒有相應的消息。 即使在解碼 function 之前我分配了一個回調 function 來解碼一個字符串(工作完美)。

附加信息:

這是我發送到 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 上沒有。 我應該做些什么?

編輯:

根據要求,我的解碼器測試 function:

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);
}

經過一番搜索和測試,我找到了解決方法!

我查看了這些示例,並認為在 oneof 字段中存在回調的可能性。 可以將 Nanopb 選項添加到 proto 文件中,該選項告訴消息它應該生成回調。 選項:

option (nanopb_msgopt).submsg_callback = true;

通過將此行添加到 proto 文件中,它將生成(據我所知)一個設置回調。 此回調在消息解碼開始時被調用。 這使我們有機會根據我們正在解碼的類型為 oneof 中的不同字段設置不同的回調。

oneof 之前的問題是無法將回調函數分配給 oneof 類型的字段,因為它們都共享相同的 memory 空間。 但是通過設置回調,我們實際上可以查看我們收到的內容並相應地分配回調。

但是,有一個問題。 我發現除了 oneof 中的消息之外,此選項不適用於任何其他內容。 這意味着不能將直接回調類型分配給 oneof 字段!

我使用的解決方法是將想要的回調封裝在消息中。 這將觸發設置回調,然后可用於在其中一個中分配正確的回調 function。

例子:

讓我們來看看這個 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 消息中為 integer arrays 分配大小。

目標是根據接收到的 oneof 類型(payloadmsg 或 payloadmsg2)解碼存儲在 payloadmsg 消息中的 arrays

然后必須創建設置回調:

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;
}

我們在解碼時查看我們收到的標簽,以查看必須分配哪種類型的回調。 這是通過訪問該字段來完成的。 通過使用 switch case,我們可以根據字段標簽決定分配什么解碼回調 function。 我們通過 arguments 和正常的解碼器功能,之后一切都設置正確。

最后,我們將此回調設置分配給編譯器生成的名為 cb_payload 的變量。 當您在 protofile 中輸入選項時,此變量將添加到您的消息結構中。 這是分配設置回調的方法:

  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 function,然后將其傳遞給正確分配的解碼器。

結果是,每當我解碼 payloadmsg 或 payloadmsg2 時,都會分配正確的解碼器,並且將正確的值解碼到結構中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM