用Flutter实现GaiaControl BLE OTA升级功能,支持Android/IOS

2023-11-03

代码基本移植官方GaiaControl Demo。
支持RWCP 断点续传 设置蓝牙mtu.协议。这里主要分析GAIA CSR ble ota的过程,协议等等,希望对你有所帮助。这里对蓝牙服务特性订阅都不谈。读者自行了解。

Gaia 是CSR 制定的一个上层使用协议,其在BR/EDR 基于RFCOMM,可以理解为一个特别UUID的SPP;经典蓝牙使用的UUID 0X1107。 ios只支持BLE所以重点关注SPP升级UUID 0X1101
Gaia 的UUID是00001107-D102-11E1-9B23-00025B00A5A5;
SPP 的UUID是00001101-0000-1000-8000-00805F9B34FB;
主要UUID如下
在这里插入图片描述

//升级服务UUID
Uuid otaUUID = Uuid.parse("00001100-d102-11e1-9b23-00025b00a5a5");
//升级服务订阅的特性
Uuid notifyUUID = Uuid.parse("00001102-d102-11e1-9b23-00025b00a5a5");
//升级服务写入特性
Uuid writeUUID = Uuid.parse("00001101-d102-11e1-9b23-00025b00a5a5");
//RWCP 更快的传输特性 不需要回包
Uuid writeNoResUUID = Uuid.parse("00001103-d102-11e1-9b23-00025b00a5a5");

GAIA协议流程非常繁琐,我们从头开始分析。
首先订阅升级通知通道 00001102-d102-11e1-9b23-00025b00a5a5
向00001101-d102-11e1-9b23-00025b00a5a5写入指令 0x000A400112 表示订阅升级通知
这里的000A400112组包格式如下

000A 4001 12

其中0x000A为固定字符vendorId 0x4001两个字节表示commandId 10x2表示订阅升级通知
订阅成功UUID 0x1102返回

000AC0010012

此时就可以开始发送升级请求

  void sendUpgradeConnect() async {
    GaiaPacketBLE packet = GaiaPacketBLE(GAIA.COMMAND_VM_UPGRADE_CONNECT);
    writeMsg(packet.getBytes());
  }

即发送0x0640 指令

000A0640

收到回包000A864000表示请求成功此时开始准备文件MD5信息用于校验,取文件MD5末尾4个字节。命令如下

000A0642130004F891C66F

这里的组包格式 vendorId + commandId + 操作符+数据 其中数据包含 长度+真正数据

000A 0642 13 0004 F891C66F

F891C66F为文件MD5;

此时会收到两条数据包

000A0642010000 //升级开始
000A40031214000600F891C66F03 //MD5接收完成 并携带上次传输步骤信息 其中0x03 表示正在升级并且上次传输步骤为0x00 
 void receiveSyncCFM(VMUPacket? packet) {
    List<int> data = packet?.mData ?? [];
    if (data.length >= 6) {
      int step = data[0];
      addLog("上次传输步骤 step $step");
      if (step == ResumePoints.IN_PROGRESS) {
        setResumePoint(step);
      } else {
        mResumePoint = step;
      }
    } else {
      mResumePoint = ResumePoints.DATA_TRANSFER;
    }
    sendStartReq();
  }
 void sendStartReq() {
    VMUPacket packet = VMUPacket.get(OpCodes.UPGRADE_START_REQ);
    sendVMUPacket(packet, false);
  }

接下来就是组包发送数据

  void sendStartDataReq() {
    setResumePoint(ResumePoints.DATA_TRANSFER);
    VMUPacket packet = VMUPacket.get(OpCodes.UPGRADE_START_DATA_REQ);
    sendVMUPacket(packet, false);
  }
   000A0642150000
void receiveDataBytesREQ(VMUPacket? packet) {
    List<int> data = packet?.mData ?? [];

    // Checking the data has the good length
    if (data.length == OpCodes.DATA_LENGTH) {
      // retrieving information from the received packet
      //REC 120300080000002400000000
      //SEND 000A064204000D0000030000FFFF0001FFFF0002
      var lengthByte = [data[0], data[1], data[2], data[3]];
      var fileByte = [data[4], data[5], data[6], data[7]];
      mBytesToSend = int.parse(StringUtils.byteToHexString(lengthByte), radix: 16);
      int fileOffset = int.parse(StringUtils.byteToHexString(fileByte), radix: 16);

      addLog(StringUtils.byteToHexString(data) + "本次发包: $fileOffset $mBytesToSend");
      // we check the value for the offset
      mStartOffset += (fileOffset > 0 && fileOffset + mStartOffset < (mBytesFile?.length ?? 0)) ? fileOffset : 0;

      // if the asked length doesn't fit with possibilities we use the maximum length we can use.
      mBytesToSend = (mBytesToSend > 0) ? mBytesToSend : 0;
      // if the requested length will look for bytes out of the array we reduce it to the remaining length.
      int remainingLength = mBytesFile?.length ?? 0 - mStartOffset;
      mBytesToSend = (mBytesToSend < remainingLength) ? mBytesToSend : remainingLength;
      if (mIsRWCPEnabled.value) {
        while (mBytesToSend > 0) {
          sendNextDataPacket();
        }
      } else {
        addLog("receiveDataBytesREQ: sendNextDataPacket");
        sendNextDataPacket();
      }
    } else {
      addLog("UpgradeError 数据传输失败");
      abortUpgrade();
    }
  }

断点续传的逻辑也在这。读取到fileOffset 进行文件偏移

最后一包数据格式0x01 + 数据 发送完毕

void sendData(bool lastPacket, List<int> data) {
    List<int> dataToSend = [];
    dataToSend.add(lastPacket ? 0x01 : 0x00);
    dataToSend.addAll(data);
    sendPkgCount++;
    VMUPacket packet = VMUPacket.get(OpCodes.UPGRADE_DATA, data: dataToSend);
    sendVMUPacket(packet, true);
  }

收到是否提交 我这里直接不询问提交

 static const UPGRADE_COMMIT_REQ = 0x0F;
 void askForConfirmation(int type) {
    int code = -1;
    switch (type) {
      case ConfirmationType.COMMIT:
        {
          code = OpCodes.UPGRADE_COMMIT_CFM;
        }
        break;
      case ConfirmationType.IN_PROGRESS:
        {
          code = OpCodes.UPGRADE_IN_PROGRESS_RES;
        }
        break;
      case ConfirmationType.TRANSFER_COMPLETE:
        {
          code = OpCodes.UPGRADE_TRANSFER_COMPLETE_RES;
        }
        break;
      case ConfirmationType.BATTERY_LOW_ON_DEVICE:
        {
          sendSyncReq();
        }
        return;
      case ConfirmationType.WARNING_FILE_IS_DIFFERENT:
        {
          stopUpgrade();
        }
        return;
    }
    addLog("askForConfirmation ConfirmationType type $type $code");
    VMUPacket packet = VMUPacket.get(code, data: [0]);
    sendVMUPacket(packet, false);
  }

提交完成蓝牙会自动断开 ,间隔1S后重连 重新订阅通知 再次发送升级请求跟文件md5 。如果数据正常 会收到是否安装的指令

 static const int COMMIT = 0x04

关于RWCP传输是基于以往0x1103中写入数据不等待返回通知,能大幅提高传输速率。

下一篇再整理RWCP传输过程

在这里插入图片描述
在这里插入图片描述

不懂得欢迎交流探讨
https://github.com/Liberations/Flutter-GAIAControl

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

用Flutter实现GaiaControl BLE OTA升级功能,支持Android/IOS 的相关文章

随机推荐

  • 【Linux入门之密码登陆】centOS密码输入正确却登陆不上,原来是我误会了

    搜索Linux修改密码 出来的基本都是修改root用户的密码 而我的GUI界面一打开显示的用户列表里是普通用户 每次登陆我都使用我刚改好的root密码 自然密码错误 无法登陆 我还跑到百度搜 centOS密码输入正确却登陆不上 等等相似的描
  • springboot项目热部署

    快捷键Ctrl Alt Shift 选Registry 勾选下面这个 然后 apply一下 pom xml
  • sc不是内部命令也不是外部命令处理方法

    sc不是内部命令也不是外部命令 用户环境变量里path里加上 SystemRoot system32
  • 【小沐学写作】程序员必备技能:在线协作文档汇总

    文章目录 1 简介 2 微软Office在线文档 2 1 功能简介 2 2 使用费用 2 3 用户体验 3 石墨文档 3 1 功能简介 3 2 使用费用 4 腾讯文档 4 1 功能简介 4 2 使用费用 5 语雀 5 1 功能简介 5 2
  • SQL grouping sets 子句

    grouping sets子句允许你指定多个group by 选项 增强了group by 的功能 可以通过一条select 语句实现复杂繁琐的多条select 语句的查询 并且更加的 高效 解析存储一条SQL于语句 下面通过使用 grou
  • 图像分割高铁扣件

    图像分割 针对高铁扣件 在对图像的研究和应用中 人们往往仅对图像中的某些部分感兴趣 这些部分通常被称为前景或目标 其余部分则称为背景 目标一般对应于图像中特定的 具有独特性质的区域 独特性质可以是像素的灰度值 物体轮廓曲线 颜色和纹理等 为
  • GBDT(GBM)调参方法

    GBM参数 总的来说GBM的参数可以被归为三类 树参数 调节模型中每个决定树的性质 Boosting参数 调节模型中boosting的操作 其他模型参数 调节模型总体的各项运作 GBDT类库弱学习器参数 即定义一个决定树所需要的参数 由于G
  • 【源码分析】zeebe actor模型源码解读

    zeebe actor 模型 如果有阅读过zeebe 源码的朋友一定能够经常看到actor run 之类的语法 那么这篇文章就围绕actor run 方法 说说zeebe actor 的模型 环境 zeebe release 8 1 14
  • Java统一返回结果自动封装组件【Response-boxing】

    0 需求 统一封装返回结果 包括code message data数据 不用手动封装 通过自定义注解标记即实现封装 如果controller结果已经手动封装 则不重复封装 1 项目结构 2 创建自定义注解 import java lang
  • Paxos算法的java实现demo(只是为了简单的测试)

    Paxos 的概念我就不在这里啰嗦了 网上有很多优秀的博客 下面是我推荐的一个写的比较好的 https www cnblogs com linbingdong p 6253479 html 我们直接上代码吧 代码里面都有注释 先看一下项目结
  • 基于mulitisim14仿真的数字电子称

    参考了下面的文章做了一个数字电子称 https www renrendoc com paper 119413660 html 仿真如下 需要仿真文件的私聊
  • 中国工程院院士郑纬民:元宇宙是一个赋能实体经济的重要新赛道

    2022年3月31日 元宇宙产业委共同主席郑纬民院士在第三届元宇宙产业论坛发表了题为 元宇宙创新应用全面启航 算力是基础 的演讲 以下为郑纬民院士的演讲全文 今年全国两会中一些代表和委员提出了关于元宇宙的建议和提案 说明元宇宙已经得到了大家
  • 吉林大学超星MOOC学习通高级语言程序设计 C++ 实验04 数组及其在程序设计中的应用(2021级)(1)

    1 索引数组排序 题目编号 Exp04 Enhance04 GJBook3 06 21 题目名称 索引数组排序 题目描述 已知n n 100 个元素的整型数组 A 未排序 一个索引数组 B 保存 A 的下标 编写程序 在不改变数组A的情况下
  • Unikernels 解读

    转载于https zhuanlan zhihu com p 29053035 Unikernels Beyond Containers to the Next Generation of Cloud是 Russ Pavlicek的一本动物书
  • (Animator详解二)Unity Animator的基本属性

    在Inspector下 Animator的第一项为状态机的名称 注意 这里的名称不是动画名称 Tag 当前动画的Tag标签 可以通过Tag值来处理一些逻辑 Motion 动画片段的名称 Speed 动画的播放速度 1表示正常播放 speed
  • spring一些捞到的东西

    spring指令重排和多线程 原来在编写程序的时候要考虑这么多东西 要想清楚每一个代码 每一个线程在哪执行 还有要懂得jvm 的一些优化的 任重而道远啊 单例模式 只允许一个实例的存在 构造函数是私有的 对外提供获取实例的方法 getIns
  • CSS -网页动画

    目录 制作网页动画 1 CSS变形 2 CSS过渡 3 CSS动画 4 总结 制作网页动画 1 CSS变形 CSS3变形是一些效果的集合 如平移 旋转 缩放 倾斜效果 每个效果都可以称为变形 transform 它们可以分别操控元素发生平移
  • 第七十六篇 MIPI简单说明

    MIPI 移动行业处理器接口 是Mobile Industry Processor Interface的缩写 MIPI是MIPI联盟发起的为移动应用处理器制定的开放标准 目的是把手机内部的接口如摄像头 显示屏接口 射频 基带接口等标准化 从
  • c++之重载函数学习总结

    一 C 中的函数重载 1 函数重载的概念 用同一个函数名定义不同的函数 当函数名和不同的参数搭配时函数的含义不同 注意 在c语言中是没有函数重载这个概念的 代码示例演示 include
  • 用Flutter实现GaiaControl BLE OTA升级功能,支持Android/IOS

    代码基本移植官方GaiaControl Demo 支持RWCP 断点续传 设置蓝牙mtu 协议 这里主要分析GAIA CSR ble ota的过程 协议等等 希望对你有所帮助 这里对蓝牙服务特性订阅都不谈 读者自行了解 Gaia 是CSR