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



}
相关推荐
YCOSA20254 小时前
雨晨 Windows 10 企业版 LTSC x64 中度精简 1809 迎双节 17763.9257 特别版
windows
sukalot5 小时前
windows 驱动实例分析系列: HidHide 驱动分析 - drivers 篇(四)
windows·驱动开发
ι:10 小时前
NUC12 Pro 安装 Ubuntu 24.04 LTS 详细教程
linux·windows·ubuntu·nuc
YCOSA202510 小时前
微软宣布将于10月7日举行Windows与Surface发布会,聚焦“Windows、NVIDIA RTX Spark、Surface,以及更广泛PC生态”
windows
Source.Liu11 小时前
【A11】 labelprinter(Tauri 版)新建步骤
windows·rust
Punchline27812 小时前
解决 Windows 环境变量 Path 设置时提示“字符太长”的完整指南
windows·环境变量·path
chushiyunen12 小时前
claude code笔记(二)、claude桌面端(内网不好用)
windows
d_benhua13 小时前
以太网测试步骤
windows
冯一川13 小时前
DeepSeek在Windows系统上部署
windows·python
解道Jdon15 小时前
JDK 27发布:紧凑对象头、G1默认、量子安全TLS
ide·windows·git·svn·eclipse·github·visual studio