使用一个字段作为任意消息的代理

发布于 2025-01-25 19:20:16 字数 3911 浏览 2 评论 0原文

Hello Nano开发人员,

我想意识到以下原始原型:

message container {
    enum MessageType {
        TYPE_UNKNOWN =  0;
        evt_resultStatus  =  1;
    }
    required MessageType mt = 1;
    optional bytes cmd_evt_transfer = 2;
}

message evt_resultStatus {
    required int32 operationMode = 1;
}

...

点表示,还有更多消息,其中包含数据类型的(多个)原始词。枚举也会同样增长,只是想简短。

容器的生成为:

typedef struct _container { 
    container_MessageType mt; 
    pb_callback_t cmd_evt_transfer; 
} container;

evt_resultStatus是:

typedef struct _evt_resultStatus { 
    int32_t operationMode; 
} evt_resultStatus;

字段cmd_evt_transfer应充当后续消息的代理,例如evt_resultStatus持有原始数据类型。 evt_resultstatus应编码为字节,并将其放置在cmd_evt_transfer字段中。 然后,容器应进行编码,并且编码结果将用于后续转移。

为什么这样做的背景是缩短原始定义并避免使用单一事物。不幸的是,语法版本3不完全支持,因此我们无法使用任何字段。

第一个问题是:这种方法可能有可能吗?

到目前为止,我所拥有的是编码,包括回调似乎表现不错。但另一方面,解码以某种方式跳过了回调。我已经阅读了问题在这里,这在使用oneof 和字节字段。

有人可以澄清如何继续这样做吗?

到目前为止,我得到的示例代码:

bool encode_msg_test(pb_byte_t* buffer, int32_t sval, size_t* sz, char* err) {
    evt_resultStatus rs = evt_resultStatus_init_zero;
    rs.operationMode = sval;
    pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));

    /*encode container*/
    container msg = container_init_zero;
    msg.mt = container_MessageType_evt_resultStatus;
    msg.cmd_evt_transfer.arg = &rs;
    msg.cmd_evt_transfer.funcs.encode = encode_cb;
    if(! pb_encode(&stream, container_fields, &msg)) {
        const char* local_err = PB_GET_ERROR(&stream);
        sprintf(err, "pb_encode error: %s", local_err);
        return false;
    }

    *sz = stream.bytes_written;
    return true;
}

bool encode_cb(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
    evt_resultStatus* rs = (evt_resultStatus*)(*arg);

//with the below in place a stream full error rises
//    if (! pb_encode_tag_for_field(stream, field)) {
//        return false;
//    }

    if(! pb_encode(stream, evt_resultStatus_fields, rs)) {
        return false;
    }

    return true;
}

//buffer holds previously encoded data
bool decode_msg_test(pb_byte_t* buffer, int32_t* sval, size_t msg_len, char* err) {
    container msg = container_init_zero;
    evt_resultStatus res = evt_resultStatus_init_zero;

    msg.cmd_evt_transfer.arg = &res;
    msg.cmd_evt_transfer.funcs.decode = decode_cb;
    pb_istream_t stream = pb_istream_from_buffer(buffer, msg_len);
    if(! pb_decode(&stream, container_fields, &msg)) {
        const char* local_err = PB_GET_ERROR(&stream);
        sprintf(err, "pb_encode error: %s", local_err);
        return false;
    }
    *sval = res.operationMode;
    return true;
}

bool decode_cb(pb_istream_t *istream, const pb_field_t *field, void **arg) {
    evt_resultStatus * rs = (evt_resultStatus*)(*arg);

    if(! pb_decode(istream, evt_resultStatus_fields, rs)) {
        return false;
    }

    return true;
}

我觉得,我对编码 /解码过程没有正确的理解。

假设是否正确:

  • pb_encode的第一个呼叫(在encode_msg_test中)负责mt字段mt字段
  • pb_encode的第二个呼叫(在encode_cb中)处理cmd_evt_transfer字段

如果我这样做:

bool encode_cb(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
    evt_resultStatus* rs = (evt_resultStatus*)(*arg);

    if (! pb_encode_tag_for_field(stream, field)) {
         return false;
    }

    if(! pb_encode(stream, evt_resultStatus_fields, rs)) {
        return false;
    }

    return true;
}

然后,我会在pb_encode的呼叫上获得流的完整错误。

这是为什么?

Hello nano developers,

I'd like to realize the following proto:

message container {
    enum MessageType {
        TYPE_UNKNOWN =  0;
        evt_resultStatus  =  1;
    }
    required MessageType mt = 1;
    optional bytes cmd_evt_transfer = 2;
}

message evt_resultStatus {
    required int32 operationMode = 1;
}

...

The dots denote, there are more messages with (multiple) primitive containing datatypes to come. The enum will grow likewise, just wanted to keep it short.

The container gets generated as:

typedef struct _container { 
    container_MessageType mt; 
    pb_callback_t cmd_evt_transfer; 
} container;

evt_resultStatus is:

typedef struct _evt_resultStatus { 
    int32_t operationMode; 
} evt_resultStatus;

The field cmd_evt_transfer should act as a proxy of subsequent messages like evt_resultStatus holding primitive datatypes.
evt_resultStatus shall be encoded into bytes and be placed into the cmd_evt_transfer field.
Then the container shall get encoded and the encoding result will be used for subsequent transfers.

The background why to do so, is to shorten the proto definition and avoid the oneof thing. Unfortunately syntax version 3 is not fully supported, so we can not make use of any fields.

The first question is: will this approach be possible?

What I've got so far is the encoding including the callback which seems to behave fine. But on the other side, decoding somehow skips the callback. I've read issues here, that this happened also when using oneof and bytes fields.

Can someone please clarify on how to proceed with this?

Sample code so far I got:

bool encode_msg_test(pb_byte_t* buffer, int32_t sval, size_t* sz, char* err) {
    evt_resultStatus rs = evt_resultStatus_init_zero;
    rs.operationMode = sval;
    pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));

    /*encode container*/
    container msg = container_init_zero;
    msg.mt = container_MessageType_evt_resultStatus;
    msg.cmd_evt_transfer.arg = &rs;
    msg.cmd_evt_transfer.funcs.encode = encode_cb;
    if(! pb_encode(&stream, container_fields, &msg)) {
        const char* local_err = PB_GET_ERROR(&stream);
        sprintf(err, "pb_encode error: %s", local_err);
        return false;
    }

    *sz = stream.bytes_written;
    return true;
}

bool encode_cb(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
    evt_resultStatus* rs = (evt_resultStatus*)(*arg);

//with the below in place a stream full error rises
//    if (! pb_encode_tag_for_field(stream, field)) {
//        return false;
//    }

    if(! pb_encode(stream, evt_resultStatus_fields, rs)) {
        return false;
    }

    return true;
}

//buffer holds previously encoded data
bool decode_msg_test(pb_byte_t* buffer, int32_t* sval, size_t msg_len, char* err) {
    container msg = container_init_zero;
    evt_resultStatus res = evt_resultStatus_init_zero;

    msg.cmd_evt_transfer.arg = &res;
    msg.cmd_evt_transfer.funcs.decode = decode_cb;
    pb_istream_t stream = pb_istream_from_buffer(buffer, msg_len);
    if(! pb_decode(&stream, container_fields, &msg)) {
        const char* local_err = PB_GET_ERROR(&stream);
        sprintf(err, "pb_encode error: %s", local_err);
        return false;
    }
    *sval = res.operationMode;
    return true;
}

bool decode_cb(pb_istream_t *istream, const pb_field_t *field, void **arg) {
    evt_resultStatus * rs = (evt_resultStatus*)(*arg);

    if(! pb_decode(istream, evt_resultStatus_fields, rs)) {
        return false;
    }

    return true;
}

I feel, I don't have a proper understanding of the encoding / decoding process.

Is it correct to assume:

  • the first call of pb_encode (in encode_msg_test) takes care of the mt field
  • the second call of pb_encode (in encode_cb) handles the cmd_evt_transfer field

If I do:

bool encode_cb(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
    evt_resultStatus* rs = (evt_resultStatus*)(*arg);

    if (! pb_encode_tag_for_field(stream, field)) {
         return false;
    }

    if(! pb_encode(stream, evt_resultStatus_fields, rs)) {
        return false;
    }

    return true;
}

then I get a stream full error on the call of pb_encode.

Why is that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

最好是你 2025-02-01 19:20:16

是的,方法是合理的。 NanOPB回调不在乎回调的实际数据是什么。

至于为什么您的解码回调不起作用,您需要发布用于解码的代码。

(顺便说一句,任何类型都可以在NanOPB中起作用,并由此测试案例。但是type_url在所有中包含的任何消息都使它们具有很大的开销。)

Yes, the approach is reasonable. Nanopb callbacks do not care what the actual data read or written by the callback is.

As for why your decode callback is not working, you'll need to post the code you are using for decoding.

(As an aside, Any type does work in nanopb and is covered by this test case. But the type_url included in all Any messages makes them have a quite large overhead.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文