当前位置: 首页 > news >正文

Charge-BleMessage

作用

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

分包机制解析

假设要发送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 时,说明接收完成

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

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;

构造函数

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)); //合并数据 }

提供给外部的get方法

//判断是否已接收完所有分片 bool get isAll => size == offset; //命令执行是否成功 bool get isSuccess { if(_response ) { if(payload.last != 0) { return false; } } return true; }

代码示例

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项目,与充电宝项目无关 }
http://www.jsqmd.com/news/1208227/

相关文章:

  • 2026广州A-Level国际高中怎么选:华美英语实验学校30多年办学经验与16万平校园优势深度解析 - 运营方法论
  • Cursor搜索响应超2s?立即执行这6项性能调优操作,5分钟内见效
  • 北京古驰包包回收热门款热度不减,经典双环扣酒神包成色分级标准透明 - 分享测评官
  • 植物大战僵尸大喷菇实战指南:穿透攻击与夜间关卡性价比解析
  • Grasscutter Tools 技术架构深度解析:跨平台游戏辅助工具的设计与实现
  • CANN/asc-devkit排序临时空间API
  • CANN/asc-devkit TPipe销毁函数
  • hass-oidc-auth与主流身份提供商集成指南:Authentik/Authelia/Keycloak配置详解
  • Pyfakefs入门教程:从安装到编写第一个虚拟文件系统测试
  • GPT-5时代三大高潜职业:AI智能体架构、多模态产品与数据评估
  • Docker 29.6.2 发布:修复多个安全漏洞,更新多项组件版本
  • 联想笔记本麦克风故障排查与修复全攻略
  • PDCA 循环自动化:OpenClaw 跟踪计划执行、检查结果、处理问题、迭代优化流程
  • Ascend C TBufPool构造函数
  • 农业科研必备:一文读懂WOFOST与PCSE作物模型的原理、参数校准与Python实战
  • Mac上本地部署Claude Code全指南:Node.js+VS Code深度集成
  • ObjectLayoutInspector性能优化:避免小结构体包装导致的内存膨胀
  • Opus 4.7与Claude Code:面向高确定性软件工程的推理引擎
  • FPGA在AI视觉中的低延迟与高能效实践
  • 3种登录方式+智能分P管理:BilibiliUploader让B站投稿效率提升500%
  • HPM5361EVK开发板程序下载与调试环境搭建指南
  • OMI/Aura 二氧化氮 (NO2) 总浓度和对流层柱浓度 1 轨道 L2 幅宽 13x24 km V003 (OMNO2) 位于 GES DISC
  • 《 Three.js 三阶魔方:完整版+字母贴纸+计时步数》
  • 终极指南:如何彻底禁用Windows Defender释放系统性能
  • 丢掉那些随时会断的爬虫:如何在生产环境构建一个高可用、零维护成本的多市场行情同步管道?
  • 如何快速上手Medusa:10分钟创建你的第一个JavaFX仪表盘
  • 终极指南:如何在macOS上使用OpenMTP实现高速Android文件传输
  • SQL-Eval与云函数集成:自动化评估结果上传到BigQuery
  • Windows Server 2022网卡驱动配置与优化指南
  • 3步快速上手HunterPie:打造《怪物猎人:世界》智能狩猎伴侣