繁体   English   中英

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

[英]using a bytes field as proxy for arbitrary messages

你好纳米开发者,

我想实现以下原型:

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字段中。 然后对容器进行编码,编码结果将用于后续传输。

这样做的背景,是为了缩短proto定义,避免one of thing。 不幸的是语法版本 3 没有得到完全支持,所以我们不能使用any字段。

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

到目前为止,我得到的是包括似乎表现良好的回调的编码。 但另一方面,解码会以某种方式跳过回调。 我在这里读过问题,当使用oneofbytes字段时也会发生这种情况。

有人可以澄清如何进行吗?

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

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字段
  • cmd_evt_transfer的第二次调用(在pb_encode中)处理encode_cb字段

如果我做:

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时收到 stream 完整错误。

这是为什么?

是的,这种做法是合理的。 Nanopb 回调不关心回调读取或写入的实际数据是什么。

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

(顺便说一句, Any类型确实在 nanopb 中工作,并且包含在这个测试用例中。但是所有Any消息中包含的type_url使它们有相当大的开销。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM