2016-10-04 2 views
0

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 

答えて

1

エンコードコールバックは、サブメッセージに対して複数回呼び出されるexpected behaviourあります。

コールバックがサブメッセージで使用されている場合、それはpb_encodeへの単一の呼び出し中に複数回呼び出されます:最初の呼び出しは、サブメッセージ本体を書き出すことができる前に知っていなければならないサイズを算出するものです。この場合、毎回同じ量のデータを生成する必要があります。コールバックがメインメッセージ内に直接存在する場合、コールバックは1回だけ呼び出されます。 oneofのは、文字列フィールドを持つサブメッセージが含まれている場合

、エンコードコールバックが2回呼び出され、およびデコードコールバック:あなたの復号化が機能しない理由については

は、現在are not supported inside oneof constructsコールバック決して呼ばれない。

+0

少なくとも、コールバックが現在いずれかの構造体内でサポートされていないことを知っていれば、少なくとも問題の一部を回避することができます。しかし、エンコード側では、エンコードする要素が4つ以上繰り返されると、2つのコールバックしか表示されません。その場合、私は何が欠けていますか? – Cap

+0

4つの要素のループがコールバック内にあり、サブメッセージにそれ以上のコールバックがないようです。したがって、コールバックは1回の呼び出しで4つの要素すべてを処理します。 – jpa

関連する問題