Embedded C language protobuf implements nanopb

Protobuf is a data format developed by Google. Similar to XML, it can serialize structured data and can be used for data storage and communication protocols. It is language and platform independent and extremely extensible.

nanopb is a lightweight protobuf in C language, suitable for resource-constrained MCU

Nanopb – downloads Download the latest version of nanopb

After decompression, add the path where the generator-bin directory is located to the Path environment variable

Create a protobuf protocol file student.proto

syntax = "proto2";
message CourseScore{
    required string coursename = 1;
    required uint32 score = 2;
}
message Student
{
     required string name = 1;
     required uint32 studentid = 2;
     optional string phonenum = 3;
     repeated CourseScore coursescores = 4;
}

You can specify the length of the string and create a student.option file

Student.name max_size:128
Student.phonenum max_size: 12
CourseScore. coursename max_size: 128

The next step is to generate student.pb.h student.pb.c by command

protoc --nanopb_out=.student.proto

Copy student.pb.h student.pb.c and several decompressed pb files into your project directory

pb.h
pb_common.c
pb_common.h
pb_decode.c
pb_decode.h
pb_encode.c
pb_encode.h
student.pb.h
student.pb.c

Now write the test program

#include <stdio.h>
#include "student.pb.h"
#include "pb_encode.h"
#include "pb_decode.h"
#include <stdint.h>
#define MAX_COURCE_NUM 3

typedef struct _StuourseScore{
     char coursename[128];
     uint32_t score;
}CourseScoreInfo;

typedef struct _StudentInfo{
     char name[128];
     uint32_t studentid;
     char phonenum[12];
     CourseScoreInfo coursescores[MAX_COURCE_NUM];
     int realCourseNum;
}StudentInfo;


static bool courseScoreEncode(pb_ostream_t* stream, const pb_field_t* field, void* const* arg){
    StudentInfo *studentInfo=(const StudentInfo *)*arg;
    CourseScore stuCourseScore;
    for(int i=0;i<studentInfo->realCourseNum;i + + ){
        strcpy(stuCourseScore. coursename, studentInfo->coursescores[i].coursename);
        stuCourseScore.score = studentInfo->coursescores[i].score;
        if (!pb_encode_tag_for_field(stream, field)) {
            return false;
        }
        if (!pb_encode_submessage(stream, CourseScore_fields, & amp; stuCourseScore)) {
            return false;
        }
    }
    return true;
}

static bool courseScoreDecode(pb_istream_t* stream, const pb_field_t* field, void** arg){

    CourseScore courseScore = CourseScore_init_default;
    StudentInfo *studentInfoOut=(const StudentInfo *)*arg;
    if (!pb_decode(stream, CourseScore_fields, &courseScore)) {
        return false;
    }

    strcpy(studentInfoOut->coursescores[studentInfoOut->realCourseNum].coursename,courseScore.coursename);
    studentInfoOut->coursescores[studentInfoOut->realCourseNum].score=courseScore.score;
    studentInfoOut->realCourseNum++;
    return true;
}


int encodeMsg(const Student *pack_stu,uint8_t *buffer,int manxBufferLen){
    pb_ostream_t o_stream = {0};
    o_stream = pb_ostream_from_buffer(buffer, manxBufferLen);
    if(pb_encode( &o_stream, Student_fields, pack_stu)==false){
        printf("encode failed\\
");
        return 0;
    }
    return o_stream.bytes_written;
}

int decodeMsg(const uint8_t *buffer, int encodeBufferLen, Student *unpack_stu){
    // unpack
    pb_istream_t i_stream = {0};
    i_stream = pb_istream_from_buffer(buffer, encodeBufferLen);
    if(pb_decode( & amp;i_stream, Student_fields, unpack_stu)==true){
        return 1;
    }
    return 0;
}

// embedded hodgepodge
void protobuf_test(void)
{
  StudentInfo studentInfoIn;
  strcpy(studentInfoIn.name,"kaijdtf");
  studentInfoIn.studentid=123456;
  strcpy(studentInfoIn.phonenum,"98765432101");

  strcpy(studentInfoIn.coursescores[0].coursename,"shuxue");
  studentInfoIn.coursescores[0].score=60;
  strcpy(studentInfoIn.coursescores[1].coursename,"yingyu");
  studentInfoIn.coursescores[1].score=70;
  strcpy(studentInfoIn.coursescores[2].coursename,"yuwen");
  studentInfoIn.coursescores[2].score=80;
  studentInfoIn.realCourseNum=3;


  // package
  uint8_t encodeBuffer[1024] = {0};
  int encodeBufferLen=0;
  Student pack_stu = Student_init_zero;
  strcpy(pack_stu.name,studentInfoIn.name);
  pack_stu.studentid=studentInfoIn.studentid;
  pack_stu.has_phonenum=true;
  strcpy(pack_stu.phonenum,studentInfoIn.phonenum);
  pack_stu.coursescores.funcs.encode=courseScoreEncode;
  pack_stu.coursescores.arg= &studentInfoIn;
  if((encodeBufferLen=encodeMsg( & amp;pack_stu,encodeBuffer,1024))<=0){
      return;
  }

  printf("mgsEncodeLen=%d\\
",encodeBufferLen);
  for(int i=0;i<encodeBufferLen;i++)
      printf(" X ", encodeBuffer[i]);
  printf("\\
");



  StudentInfo studentInfoOut;
  memset( & studentInfoOut, 0, sizeof(StudentInfo));
  Student unpack_stu = Student_init_zero;
  unpack_stu.coursescores.funcs.decode=courseScoreDecode;
  unpack_stu.coursescores.arg= &studentInfoOut;

  if(decodeMsg(encodeBuffer,encodeBufferLen, &unpack_stu)){
      strcpy(studentInfoOut.name, unpack_stu.name);
      studentInfoOut.studentid=unpack_stu.studentid;
      if(unpack_stu.has_phonenum)
            strcpy(studentInfoOut.phonenum,unpack_stu.phonenum);

      printf("studentInfoOut.name = %s\\
", studentInfoOut.name);
      printf("studentInfoOut.studentid = %u\\
", studentInfoOut.studentid);
      printf("studentInfoOut.phonenum = %s\\
", studentInfoOut.phonenum);
      if(studentInfoOut. realCourseNum>0){
          for(int i=0;i<studentInfoOut.realCourseNum;i++)
              printf("course name:%s score:%u\\
",studentInfoOut.coursescores[i].coursename,studentInfoOut.coursescores[i].score);

      }

  }
}

int main()
{

    protobuf_test();
    return 0;
}

printout:

mgsEncodeLen=61
0A 07 6B 61 69 6A 64 74 66 10 C0 C4 07 1A 0B 39 38 37 36 35 34 33 32 31 30 31 22 0A 0A 06 73 68 75 78 75 65 10 3C 22 0A 0A 06 79 69 6E 67 79 75 10 46 22 09 0A 05 79 75 77 65 6E 10 50
studentInfoOut.name = kaijdtf
studentInfoOut. studentid = 123456
studentInfoOut.phonenum = 98765432101
cource name:shuxue score:60
cource name:yingyu score:70
cource name:yuwen score:80