nanopb 使用

nanopb 的使用

这个文档写的还可以.

https://jpa.kapsi.fi/nanopb/docs/concepts.html#compiling-proto-files-for-nanopb

c 用法

定义一个 repeated 字段, 怎么进行 encode /decode

参考这个的 demo 进行修改
https://blog.csdn.net/fjlhlonng/article/details/131181948

我们添加一个 repeated 字段

syntax = "proto2";

message TestMessage
{
    required string name = 1;
    required uint32 age = 2;
    optional fixed32 grade = 3;
    repeated float data = 4;  //  add  
}

不用 options 文件指定长度…
进行编译
可以看到编译出来的是 pb_callback_t 类型
/* Struct definitions /
typedef struct _TestMessage {
char name[32];
uint32_t age;
bool has_grade;
uint32_t grade;
pb_callback_t data;
/
@@protoc_insertion_point(struct:TestMessage) */
} TestMessage;

struct pb_callback_s {
    /* New function signature, which allows modifying arg contents in callback. */
    union {
        bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void **arg);
        bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, void * const *arg);
    } funcs;
    /* Free arg for use by callback */
    void *arg;
};
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
 
#include "pb_decode.h"
#include "pb_encode.h"
#include "test.pb.h"
 

typedef unsigned char uint8_t;

/**
 * Structure to be used with pb_encode_float_arr_cb & pb_decode_float_arr_cb
 */
typedef struct pb_float_arr_arg
{
  /* Where to place the decoded float array */
  float *arr;
  /* Length of the float array */
  uint8_t arr_len;
  /* Array index used for decoding.
     Must be initialized to 0 prior to calling pb_decode_float_arr_cb*/
  uint8_t *arr_index;
} pb_float_arr_arg;



bool
pb_encode_float_arr_cb(pb_ostream_t *stream, const pb_field_t *field,
    void *const *arg)
{
  pb_float_arr_arg *arr = (pb_float_arr_arg*)*arg;
  float *f_data = (float*)arr->arr;
  if(!pb_encode_tag(stream, PB_WT_STRING, field->tag))
    return false;
  if(!pb_encode_varint(stream, arr->arr_len * 4))
    return false;

  for(int i = 0; i < arr->arr_len; i++)
  {
    if(!pb_encode_fixed32(stream, &f_data[i]))
      return false;
  }
  return true;
}


bool
pb_decode_float_arr_cb(pb_istream_t *stream, const pb_field_t *field,
    void **arg)
{
  pb_float_arr_arg const *arr = (pb_float_arr_arg const*)*arg;
  float *f_arr = arr->arr;

  while(0 != stream->bytes_left)
  {
    if(*arr->arr_index >= arr->arr_len)
    {
      pb_skip_field(stream, PB_WT_32BIT);
    }
    else if(!pb_decode_fixed32(stream, &(f_arr[*arr->arr_index])))
      return false;

    (*arr->arr_index)++;
  }

  return true;
}



int main (int argc, char *argv[])
{
    uint8_t buf[64];
    size_t len;
    TestMessage o = TestMessage_init_default;
    TestMessage n = TestMessage_init_default;
 
 
    pb_ostream_t o_stream = {0};
    pb_istream_t i_stream = {0};
     

    strcat(o.name, "Mike jordan");
    o.age = 17;
    // encode  
    float temp[4] ={1.5,2.8,3.7,4.5};
    uint8_t arr_index = 0;
    pb_float_arr_arg encode_arg = {.arr = (float *)temp, .arr_len = 4,
    .arr_index = &arr_index};
   o.data.funcs.encode = &pb_encode_float_arr_cb;
   o.data.arg = &encode_arg;

    o_stream = pb_ostream_from_buffer(buf, sizeof(buf));
    pb_encode(&o_stream, TestMessage_fields, &o);
    len = o_stream.bytes_written;
    printf("len: %ld\n", len);
 
  //  decode 

    i_stream = pb_istream_from_buffer(buf, len);
     float decode_args[4] = { 0 };
     arr_index = 0;
    pb_float_arr_arg arg = {.arr = decode_args, .arr_len = 4, .arr_index = &arr_index};

    n.data = (struct pb_callback_s)
      {.funcs.decode = &pb_decode_float_arr_cb, .arg = &arg};

    pb_decode(&i_stream, TestMessage_fields, &n);
 
    printf("name: %s\n", n.name);
    printf("age: %u\n", n.age);
    for(int i=0;i<4;i++)
      printf("%f\n",decode_args[i]);


    return 0;
}

运行下 结果如下:
$./start
len: 33
name: Mike jordan
age: 17
1.500000
2.800000
3.700000
4.500000
运行成功.
如果类型是 pb_callback_t 类型的话,就是这样操作。
如果不是pb_callback_t 类型的话, 直接赋值即可,比较简单

string 类型的解析

在 proto 文件添加类型
required string string_data = 4 ;
编译
/* Struct definitions /
typedef struct _TestMessage {
char name[32];
uint32_t age;
bool has_grade;
uint32_t grade;
pb_callback_t string_data;
/
@@protoc_insertion_point(struct:TestMessage) */
} TestMessage;
看到还是一个 pb_callback_t 类型.
要自己写个 encode/deconde 的函数

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
 
#include "pb_decode.h"
#include "pb_encode.h"
#include "test.pb.h"
 

typedef struct pb_buffer_arg
{
  /* Buffer to be written, or reference to read buffer */
  void const *buf;
  /* Length of buf */
  size_t buf_len;
} pb_buffer_arg;


bool
pb_encode_string_cb(pb_ostream_t *stream, const pb_field_t *field,
    void *const *arg)
{
  pb_buffer_arg *data = (pb_buffer_arg*)*arg;
  if(pb_encode_tag_for_field(stream, field) &&
     pb_encode_string(stream, data->buf, data->buf_len))
    return true;

  return false;
}


bool
pb_decode_string_cb(pb_istream_t *stream, const pb_field_t *field,
    void **arg)
{
  pb_buffer_arg *data = (pb_buffer_arg*)*arg;

  data->buf_len = stream->bytes_left;
  data->buf = stream->state;
  return pb_read(stream, (pb_byte_t*)NULL, stream->bytes_left);
}


int main (int argc, char *argv[])
{
    uint8_t buf[64];
    size_t len;
    TestMessage o = TestMessage_init_default;
    TestMessage n = TestMessage_init_default;
 
 
    pb_ostream_t o_stream = {0};
    pb_istream_t i_stream = {0};
 
    strcat(o.name, "Mike jordan");
    o.age = 17;
   // encode 
    char const ecnode_string[] = "test string";
    o.string_data.funcs.encode = pb_encode_string_cb;
    o.string_data.arg   = & ((pb_buffer_arg) {.buf = ecnode_string, .buf_len = sizeof (ecnode_string) });


    o_stream = pb_ostream_from_buffer(buf, sizeof(buf));
    pb_encode(&o_stream, TestMessage_fields, &o);
    len = o_stream.bytes_written;
    printf("len: %ld\n", len);
 
 
    i_stream = pb_istream_from_buffer(buf, len);
        //decode 
    pb_buffer_arg  decode_string = {.buf = NULL, .buf_len = 0 };
        n.string_data.arg          = &decode_string;
        n.string_data.funcs.decode = pb_decode_string_cb;

    pb_decode(&i_stream, TestMessage_fields, &n);
 
    printf("name: %s\n", n.name);
    printf("age: %u\n", n.age);

    printf("decode_string:%s , buf_len:%zu\n",decode_string.buf, decode_string.buf_len);

    return 0;
}

运行结果
$./start
len: 29
name: Mike jordan
age: 17
decode_string:test string , buf_len:12
符合预期. 完成
这里有个困惑,decode_string 中的 buf 传进去的时候是为 NULL 的。
是在哪里分配了空间吗? 用 gdb 跑一下看下

gdb ./start --tui (加上 tui 参数,有图形界面,好看一点)
在这里插入图片描述
buf 地址确实是为空

跑完 decode 后,就有地址了。 说明分配空间了.
在这里插入图片描述

int 类型

像 int 这种基础的类似,操作比较简单,直接赋值即可。这里不在写

c++ 使用

先使用 protobuf 实验:

还是使用

syntax = "proto2";
 
message TestMessage
{
    required string name = 1;
    required uint32 age = 2;
    optional fixed32 grade = 3;
}
 
//TestMessage.name max_size:32

先编译 test.proto
/home/xxx/protobuf-3.6.1/protobuf/bin/protoc -I=./ --cpp_out=./ test.proto
测试文件:

#include <iostream>
#include <string>
#include "test.pb.h"
using namespace std;

int main(void) {
   
    GOOGLE_PROTOBUF_VERIFY_VERSION;

    TestMessage t1; 
    t1.set_age(10);
    t1.set_name("bob");
    string serializedStr;
    t1.SerializeToString(&serializedStr);

    TestMessage t2;
    if(!t2.ParseFromString(serializedStr)){
      cout << "Failed to parse student." << endl;
      return -1;
    }
    cout << t2.age() << endl;
    cout << t2.name() << endl;

    return 0;
}

编译测试文件
g++ -I /home/xxx/protobuf-3.6.1/protobuf/include test.pb.cc main.cpp -std=c++11 -L /home/xxx/protobuf-3.6.1/protobuf/lib -lprotobuf
导入环境变量:
export LD_LIBRARY_PATH=/home/xxx/protobuf-3.6.1/protobuf/lib
执行:
$./a.out
10
bob
正确…

SerializeToString : 将对象 序列化成二进制数据,保存到字符串中
如果要发送的话,则是发送这个 比如:

static void
send_config_req(ssc_connection *conn, sensor_uid const *suid)
{
  string pb_req_msg_encoded;
  string config_encoded;
  sns_client_request_msg pb_req_msg;
  sns_std_sensor_config config;
  config.set_sample_rate(SAMPLE_RATE);
  config.SerializeToString(&config_encoded);

  pb_req_msg.set_msg_id(SNS_STD_SENSOR_MSGID_SNS_STD_SENSOR_CONFIG);
  pb_req_msg.mutable_request()->set_payload(config_encoded);
  pb_req_msg.mutable_suid()->set_suid_high(suid->high);
  pb_req_msg.mutable_suid()->set_suid_low(suid->low);
  pb_req_msg.mutable_susp_config()->
    set_delivery_type(SNS_CLIENT_DELIVERY_WAKEUP);
  pb_req_msg.mutable_susp_config()->
    set_client_proc_type(SNS_STD_CLIENT_PROCESSOR_APSS);
  pb_req_msg.mutable_request()->mutable_batching()->
    set_batch_period(BATCH_PERIOD);
  pb_req_msg.SerializeToString(&pb_req_msg_encoded);
  conn->send_request(pb_req_msg_encoded);
}

贴上一个链接地址,写的还挺好的,挺详细的.
https://blog.csdn.net/lizhichao410/category_11936113.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值