Charge-BleMessage

作用

将硬件发来的原始字节流(List<int>)解析成结构化的消息对象,并处理可能的分包(多个数据包拼成一条完整消息)。

分包机制解析

Dart 复制代码
假设要发送100字节的数据,但蓝牙MTU限制每次只能传20字节
硬件会把数据分成5个包发送

第1包: size=5, offset=1, data=[前20字节]
第2包: size=5, offset=2, data=[第21-40字节]
第3包: size=5, offset=3, data=[第41-60字节]
第4包: size=5, offset=4, data=[第61-80字节]
第5包: size=5, offset=5, data=[第81-100字节]

BleMessage 的工作:
1. 从第一包知道总共有5包
2. 接收每一包,把数据合并到 payload
3. 当 size == offset 时,说明接收完成

定义变量,根据需要和协议的协定,定义变量

Dart 复制代码
  late int cmd; //命令类型

  List<int> payload = []; //实际数据内容

  late int len; //数据长度

  bool _response = false; //判断是否为回复

  bool success = true; //通信是否成功

  late final List<int> raw; //原始数据

  /// 总包数
  int size = 0;
  /// 当前包
  int offset = 0;

构造函数

Dart 复制代码
  BleMessage.from(List<int> data) {
    //协议头
    cmd = data[1] & 0xFF; //命令类型

    _response = data[2] == 0x02; //判断是否为回复

    size = (data[3] & 0xF0) >> 4; //前四位为总帧数

    offset = data[3] & 0x0F; //后四位为帧序号

    len = data[4] & 0xFF; //数据长度

    //提取实际数据
    payload.addAll( data.sublist(5));
    //如果是回复包,检查最后一个字节
    if(_response ) {
      success = data.last == 0; //协议协定
    }
    raw = data;
    Log.d("size: $size length: $len");

  }

合并后续分片的方法

Dart 复制代码
  void contact(List<int> data) {

    raw.addAll(data); //保存原始数据

    //空安全检查
    if(size == 0 || data[1] != cmd || data[3] & 0x0F == 0) {
      Log.d("message contact error");
      return;
    }

    Log.d("size: $size offset $offset");

    offset = data[3] & 0x0F; //更新当前包序号

    payload.addAll(data.sublist(5)); //合并数据
  }

提供给外部的get方法

Dart 复制代码
  //判断是否已接收完所有分片
  bool get isAll =>  size == offset;

  //命令执行是否成功
  bool get isSuccess {
    if(_response ) {
      if(payload.last != 0) {
        return false;
      }
    }
    return true;
  }

代码示例

Dart 复制代码
import '../log.dart';
import 'cmd_type.dart';

///蓝牙接收类(处理分包)

// enum  ErrorCode{  //OTA项目,与充电宝项目无关
//   success,
//   failed,
//   lengthError,
//   cmdError,
//   indexError,
//   notSupport,
//   switchError,
//   checkError,
//   packetLost,
// }


class BleMessage {

  //变量定义
  late int cmd; //命令类型

  List<int> payload = []; //实际数据内容

  late int len; //数据长度

  bool _response = false; //判断是否为回复

  bool success = true; //通信是否成功

  late final List<int> raw; //原始数据

  /// 总包数
  int size = 0;
  /// 当前包
  int offset = 0;


  // bool get response {  //耳机项目,与充电宝无关
  //   if(payload.isNotEmpty &&
  //       payload.length > 1 &&
  //       (payload[0] == DeviceInfoType.battery ||
  //           payload[0] == DeviceInfoType.firmware ||
  //           payload[0] == DeviceInfoType.port ||
  //           payload[0] == DeviceInfoType.capacity ||
  //           payload[0] == DeviceInfoType.model ||
  //           payload[0] == DeviceInfoType.temperature
  //           payload[0] == DeviceInfoType.mtu ||
  //           payload[0] == DeviceInfoType.tws ||
  //           payload[0] == DeviceInfoType.twsState ||
  //           payload[0] == DeviceInfoType.eq ||
  //           payload[0] == DeviceInfoType.noiseLevel ||
  //           payload[0] == DeviceInfoType.noiseLevelCount ||
  //           payload[0] == DeviceInfoType.transparentLevel ||
  //           payload[0] == DeviceInfoType.transparentLevelCount ||
  //           payload[0] == DeviceInfoType.name ||
  //           payload[0] == DeviceInfoType.version ||
  //           payload[0] == DeviceInfoType.button ||
  //           payload[0] == DeviceInfoType.language ||
  //           payload[0] == DeviceInfoType.autoAnswer ||
  //           payload[0] == DeviceInfoType.led ||
  //           payload[0] == DeviceInfoType.mode ||
  //           payload[0] == DeviceInfoType.face
  //       )) {
  //     return false;
  //   }
  //   return _response;
  // }

  //构造函数
  BleMessage.from(List<int> data) {
    //协议头
    cmd = data[1] & 0xFF; //命令类型

    _response = data[2] == 0x02; //判断是否为回复

    size = (data[3] & 0xF0) >> 4; //前四位为总帧数

    offset = data[3] & 0x0F; //后四位为帧序号

    len = data[4] & 0xFF; //数据长度

    //提取实际数据
    payload.addAll( data.sublist(5));
    //如果是回复包,检查最后一个字节
    if(_response ) {
      success = data.last == 0; //协议协定
    }
    raw = data;
    Log.d("size: $size length: $len");

  }

  //合并后续分片数据
  void contact(List<int> data) {

    raw.addAll(data); //保存原始数据

    //空安全检查
    if(size == 0 || data[1] != cmd || data[3] & 0x0F == 0) {
      Log.d("message contact error");
      return;
    }

    Log.d("size: $size offset $offset");

    offset = data[3] & 0x0F; //更新当前包序号

    payload.addAll(data.sublist(5)); //合并数据
  }

  //判断是否已接收完所有分片
  bool get isAll =>  size == offset;

  //命令执行是否成功
  bool get isSuccess {
    if(_response ) {
      if(payload.last != 0) {
        return false;
      }
    }
    return true;
  }

 // int get errorCode => payload.last; //OTA项目,与充电宝项目无关



}
相关推荐
雾沉川13 小时前
WinRAR 压缩解压软件 功能介绍、硬件适配、横向对比及安装使用教程
windows·winrar·压缩软件
sukalot15 小时前
windows 驱动实例分析系列: wireguard-nt驱动分析-driver篇(一)
windows·驱动开发
百事牛科技15 小时前
Excel部分单元格禁止修改:锁住该锁的,放开该放的
windows·excel
水饺编程16 小时前
第5章,[Win32 章节] :创建、选择和删除画笔
c语言·c++·windows·visual studio
曹牧17 小时前
C#与Java后台交互
java·windows·microsoft·c#
꯭爿꯭巎꯭18 小时前
视频画质修复软件
windows
凯哥Java18 小时前
ChatGPT Windows 客户端突然打不开?提示找不到 Codex CLI,我这样解决了
windows·chatgpt
薛定猫AI1 天前
OpenAI Codex本地完整配置教程|(Windows/Mac/Linux全平台,修复鉴权报错)
linux·windows·macos
w01_02_032 天前
deepseek, harness , windows , 安装。
windows
辻弋2012 天前
手动关服务会自动重启、组策略家庭版用不了——Windows Update Blocker用“禁用+锁定”双保险,让Win10/11自动更新彻底闭嘴
服务器·人工智能·windows·电脑·开源软件