Nanopbサブメッセージの繰り返し構造フィールドをエンコード/デコードする正しい方法は何ですか?生成された出力は、デコード操作が繰り返される構成フィールドのどれも検出しないことを示します。 興味深いのは、 エンコードコールバックが2回呼び出され、また問題になることです。私は何が欠けていますか?Nanopbがサブメッセージの繰り返し構造フィールドを正しくエンコードおよびデコードする
この例では、 のためにこの例が変更されていれば、復号化に成功します。encodeとdecodeはTopMessageではなくSubMessage1で開始するようにしてください。また、 この場合、エンコードコールバックは期待どおりに1回だけ呼び出されます。
以下は原定義です。問題のフィールドはSubMessage1のサブメッセージ11 です。
syntax = "proto2";
import 'nanopb.proto';
message SubMessage11
{
required uint64 int64Val = 1;
};
message SubMessage1
{
repeated SubMessage11 subMessage11 = 1;
};
message SubMessage2
{
required uint32 intVal = 1;
};
message TopMessage
{
oneof choice
{
SubMessage1 subMessage1 = 1;
SubMessage2 subMessage2 = 2;
}
};
プロト定義を使用するC++コードのコードされた:生成された出力である
#include "pb_encode.h"
#include "pb_decode.h"
#include "t.pb.h"
#include "debug.hpp"
bool subMessage11EncodeCb(pb_ostream_t *stream, const pb_field_t *field,
void * const *arg)
{
dprintf("called, field->tag=%d field->type=%d", field->tag, field->type);
for(int i=0; i<4; i++)
{
if(pb_encode_tag_for_field(stream, field) == false)
{
dprintf("encode failed");
return false;
}
SubMessage11 subMessage11 = SubMessage11_init_zero;
subMessage11.int64Val = 0xaabbccddeef0 + i;
if(pb_encode_submessage(stream, SubMessage11_fields, &subMessage11) == false)
{
dprintf("encode failed");
return false;
}
}
return true;
}
bool subMessage11DecodeCb(pb_istream_t *stream, const pb_field_t *field,
void **arg)
{
dprintf("called");
SubMessage11 subMessage11 = SubMessage11_init_zero;
if(pb_decode(stream, SubMessage11_fields, &subMessage11) == false)
{
dprintf("error decoding: %s", stream->errmsg);
return false;
}
dprintf("int64Val=%lx", subMessage11.int64Val);
return true;
}
bool encodeMsg(uint8_t buf[], size_t& bufsz)
{
dprintf("begin encoding");
pb_ostream_t stream = pb_ostream_from_buffer(buf, bufsz);
TopMessage topMessage = TopMessage_init_zero;
topMessage.which_choice = TopMessage_subMessage1_tag;
SubMessage1& subMessage1 = topMessage.choice.subMessage1;
subMessage1.subMessage11.funcs.encode = subMessage11EncodeCb;
bool status = pb_encode(&stream, TopMessage_fields, &topMessage);
if(status != true)
{
dprintf("error encoding: %s", stream.errmsg);
bufsz = 0;
return status;
}
bufsz = stream.bytes_written;
dprintf("done encoding");
return status;
}
bool decodeMsg(uint8_t buf[], size_t bufsz)
{
dprintf("begin decoding");
pb_istream_t stream = pb_istream_from_buffer(buf, bufsz);
TopMessage topMessage;
topMessage.which_choice = TopMessage_subMessage1_tag;
SubMessage1& subMessage1 = topMessage.choice.subMessage1;
int val;
subMessage1.subMessage11.arg = (void *)&val;
subMessage1.subMessage11.funcs.decode = &subMessage11DecodeCb;
bool status = pb_decode(&stream, TopMessage_fields, &topMessage);
if(status != true)
{
dprintf("error decoding: %s", stream.errmsg);
return false;
}
dprintf("decoded fields: ");
dprintf("done decoding");
return status;
}
int main(int ac, char *av[])
{
uint8_t encBuf[1024];
size_t encSz = sizeof(encBuf);
if(encodeMsg(encBuf, encSz) != true)
{
dprintf("Encode failed");
return 1;
}
hexdump(encBuf, encSz);
if(decodeMsg(encBuf, encSz) != true)
{
dprintf("Decode failed");
return 1;
}
}
:
c.cpp:55:encodeMsg: begin encoding
c.cpp:12:subMessage11EncodeCb: called, field->tag=1 field->type=103
c.cpp:12:subMessage11EncodeCb: called, field->tag=1 field->type=103
c.cpp:74:encodeMsg: done encoding
[0000] 0A 28 0A 08 08 F0 DD F7 E6 BC D7 2A 0A 08 08 F1 ........ ........
[0010] DD F7 E6 BC D7 2A 0A 08 08 F2 DD F7 E6 BC D7 2A ........ ........
[0020] 0A 08 08 F3 DD F7 E6 BC D7 2A ........ ..
c.cpp:80:decodeMsg: begin decoding
c.cpp:97:decodeMsg: decoded fields:
c.cpp:99:decodeMsg: done decoding
少なくとも、コールバックが現在いずれかの構造体内でサポートされていないことを知っていれば、少なくとも問題の一部を回避することができます。しかし、エンコード側では、エンコードする要素が4つ以上繰り返されると、2つのコールバックしか表示されません。その場合、私は何が欠けていますか? – Cap
4つの要素のループがコールバック内にあり、サブメッセージにそれ以上のコールバックがないようです。したがって、コールバックは1回の呼び出しで4つの要素すべてを処理します。 – jpa