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项目,与充电宝项目无关



}
相关推荐
水饺编程23 分钟前
第1章,[Win32 章节]:Windows 的方方面面
c语言·c++·windows·visual studio
超级大福宝1 小时前
VS Code Remote-SSH 因 RemoteForward 端口冲突导致连接失败的排查与解决
运维·服务器·windows·vscode·ssh
Vex2une2 小时前
Windows PowerShell 发展史:从命令行工具到自动化核心
windows·自动化运维·命令行·powershell·cmd·脚本语言·对象管道
怎么没有名字注册了啊14 小时前
Qt开发:MessageBox怎么调出标题栏那个问号按钮?
windows
李子红了时15 小时前
EncFS MP中文版汉化下载(免费文件加密工具)
windows·安全
辻弋20115 小时前
五年前的旅行视频糊成马赛克?Video2X用Real-ESRGAN逐帧重建细节,但只支持Windows、集显用户建议直接放弃
服务器·数据库·windows·游戏引擎·电脑
会飞的土拨鼠呀15 小时前
Windows 系统关闭虚拟内存文件pagefile.sys
windows
传奇开心果编程17 小时前
【Compose Multiplatform 跨端开发学与练】第7课 平台适配与互操作
android·windows·学习·ui·ios·kotlin·composer
工作10年+,存储芯片行业18 小时前
Linux NVMe 中断排查与性能优化:CPU 亲和性
linux·运维·服务器·windows·性能优化·ssd·pcie
lpfasd12319 小时前
WinSW在Win7上失败真相-实测与修复
windows·nginx