[英]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.