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