IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> Protocol Buffer在MCU上的实现--C语言 -> 正文阅读

[嵌入式]Protocol Buffer在MCU上的实现--C语言

一 什么是Protocol Buffer

Protocol Buffer是一种支持多平台、多语言、可扩展的的数据序列化机制,相较于XML来说,protobuf更小更快更简单,支持自定义的数据结构,用protobuf编译器生成特定语言的源代码,目前protoBuf对主流的编程语言都提供了支持,非常方便的进行序列化和反序列化。

官方网址

官方支持的语言有:

  • Java
  • Python
  • Objective-C
  • C++
  • Dart
  • Go
  • Ruby
  • C#

这里对Protocol Buffer的语法不做过多解释,这篇文章主要介绍两部分内容

  • MCU端集成nanopb
  • Android端集成Protocol Buffer

Protocol Buffer语法

二 MCU端集成nanopb

可以看到官方并没有对C语言进行支持,想要在MCU上跑Protocol Buffer需要另外一个开源工具Nanopb

nanopb是protocol buffer协议的纯C实现,没有依赖其他库,只需要几个C文件就可以了。非常适合用来做嵌入式设备的通信协议。

Nanopb基础用法

1 移植nanopb

nanopb下载,解压到本地
在这里插入图片描述
在我们的工程中集成Nanopb只需要添加这几个文件就可以了。

  • pb.h
  • pb_common.c
  • pb_common.h
  • pb_decode.c
  • pb_decode.h
  • pb_encode.c
  • pb_encode.h

2 编译.proto文件

  1. 安装protoc

将protoc.exe放到C:\Windows\System32目录下,确保Path已经包含了C:\Windows\System32路径,如果没有,作为程序员的我们应该知道怎么配置Path了吧。

下载protoc.exe
在这里插入图片描述

在命令行验证是否安装成功
在这里插入图片描述
2. 编写一个简单的.proto

syntax = "proto2";

message SimpleMessage {
    required int32 lucky_number = 1;
	required string name = 2;
}

将文件保存成为simple.proto

  1. 开始编译

将simple.proto放到目录nanopb-0.4.5-windows-x86\generator

通过执行命令(.\nanopb_generator.py .\simple.proto)将simple.proto编译成.c和.h

在这里插入图片描述
在当前目录生成了simple.pb.h和simple.pb.c文件,将这两个文件添加到自己的工程。

3. 简单demo

/**
encode callbak
 **/
bool encode_string(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
    char *str = *arg;
    if (!pb_encode_tag_for_field(stream, field))
        return false;
    
    return pb_encode_string(stream, (uint8_t*)str, strlen(str));
}

/**
decode callbak
 **/
bool decode_string(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
    int i=0;
    char* tmp = *arg;
    while (stream->bytes_left)
    {
        uint64_t value;
        if (!pb_decode_varint(stream, &value))
            return false;
        *(tmp+i)=value;
        i++;
    }
    return true;
}

int simple_main(void)
{
    /* This is the buffer where we will store our message. */
    uint8_t buffer[128];
    size_t message_length;

	char* nameStr = "abcdefg";
    bool status;

	
    
    /* Encode our message */
    {
        /* Allocate space on the stack to store the message data.
         *
         * Nanopb generates simple struct definitions for all the messages.
         * - check out the contents of simple.pb.h!
         * It is a good idea to always initialize your structures
         * so that you do not have garbage data from RAM in there.
         */
        SimpleMessage message = SimpleMessage_init_zero;
        
        /* Create a stream that will write to our buffer. */
        pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
        
        /* Fill in the lucky number */
        message.lucky_number = 1569875;
		message.name.arg = nameStr;
		message.name.funcs.encode = encode_string;

		
        
        /* Now we are ready to encode the message! */
        status = pb_encode(&stream, SimpleMessage_fields, &message);
        message_length = stream.bytes_written;

		NRF_LOG_DEBUG("message_legth: %d",message_length);
        
        /* Then just check for any errors.. */
        if (!status)
        {
            NRF_LOG_DEBUG("Encoding failed: %s", PB_GET_ERROR(&stream));
            return 1;
        }
    }
    
    /* Now we could transmit the message over network, store it in a file or
     * wrap it to a pigeon's leg.
     */

    /* But because we are lazy, we will just decode it immediately. */
    
    {
        /* Allocate space for the decoded message. */
        SimpleMessage message = SimpleMessage_init_zero;
		char nameDe[64];
		memset(nameDe, 0, 64);
		message.name.funcs.decode = decode_string;
		message.name.arg = nameDe;
        
        /* Create a stream that reads from the buffer. */
        pb_istream_t stream = pb_istream_from_buffer(buffer, message_length);
        
        /* Now we are ready to decode the message. */
        status = pb_decode(&stream, SimpleMessage_fields, &message);
        
        /* Check for errors... */
        if (!status)
        {
            NRF_LOG_DEBUG("Decoding failed: %s", PB_GET_ERROR(&stream));
            return 1;
        }
        
        /* Print the data contained in the message. */
        NRF_LOG_DEBUG("Your lucky number was %d!", (int)message.lucky_number);

		NRF_LOG_DEBUG("Your name: %s",&nameDe[0]);
    }
    
    return 0;
}

至此我们的MCU端就集成完毕了,可以根据自己的业务需要编写对应的序列化和反序列换的接口函数。

三 Android端集成Protocol Buffer

1 工程配置

  1. 在工程的build.gradle中添加protobuf-gradle-plugin
   dependencies {
       classpath 'com.android.tools.build:gradle:3.2.1'
       classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.6' //for protoc
   }
  1. 在app的build.gradle中添加protobuf
apply plugin: 'com.google.protobuf' //for protoc

//编写编译任务,调用plugin编译生成java文件
protobuf {
    protoc {
        artifact = 'com.google.protobuf:protoc:3.0.0'//编译器版本
    }
    plugins {
        javalite {
            artifact = 'com.google.protobuf:protoc-gen-javalite:3.0.0'//指定当前工程使用的protobuf版本为javalite版,以生成javalite版的java类
        }
    }
    generateProtoTasks.generatedFilesBaseDir = "$projectDir/src/main/java/com/hytto/test/protocbuf/java" //指定编译生成java类的存放位置
    generateProtoTasks {
        all().each { task ->
            task.plugins {
                javalite {
                    outputSubDir = '' //指定存放位置的二级目录,这里未指定
                }
            }
        }
    }
}
//指定原始.proto文件的位置
android {
    sourceSets {
        main {
            java {
                srcDirs 'src/main/java/com/hytto/test/protocbuf/java'
            }
            proto {
                srcDirs 'src/main/java/com/hytto/test/protocbuf/proto'
            }
        }
    }
}

dependencies {
    implementation 'com.google.protobuf:protobuf-lite:3.0.0' //依赖protobuf-lite库
}

将simple.proto放到’src/main/java/com/hytto/test/protocbuf/proto’这个目录,然后点击编译。
编译成功之后可以看到Simple.java

在这里插入图片描述

2 简单的demo

  		/**
         * 序列化
         */
        
        Simple.SimpleMessage.Builder builder = Simple.SimpleMessage.newBuilder();

        String name = "abcdefg";
        builder.setLuckyNumber(1569875);
        builder.setName(name);

        Simple.SimpleMessage message = builder.build();

        msgBytes = message.toByteArray();

        String strMsg = "length " + msgBytes.length;
        for (int i = 0; i < msgBytes.length; i++){
            String str = String.format(" %02x", msgBytes[i]);
            strMsg += str;
        }
        Log.d(TAG, strMsg);
        

        /**
         * 反序列化
         */
        
        try {
            Simple.SimpleMessage messageDe = Simple.SimpleMessage.parseFrom(msgBytes);

            String nameDe = messageDe.getName();
            int luckNumDe = messageDe.getLuckyNumber();

            Log.d(TAG, "decode name: " + nameDe + "; luckNumDe: " + luckNumDe);
        } catch (InvalidProtocolBufferException e) {
            e.printStackTrace();
        }
        

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-08-05 17:31:05  更:2021-08-05 17:32:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 18:48:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码