fix: 增加获取锁状态接口
This commit is contained in:
parent
067489b37b
commit
e07e30f598
@ -47,6 +47,17 @@ class BleService {
|
||||
// 工厂构造函数,提供全局访问点
|
||||
factory BleService() => _instance;
|
||||
|
||||
/// 用于存储最新的私钥,避免在解密时需要异步读取SharedPreferences
|
||||
static List<int>? _cachedPrivateKey;
|
||||
|
||||
/// 获取缓存的私钥
|
||||
static List<int>? get cachedPrivateKey => _cachedPrivateKey;
|
||||
|
||||
/// 设置缓存的私钥
|
||||
static void setCachedPrivateKey(List<int> privateKey) {
|
||||
_cachedPrivateKey = List.from(privateKey);
|
||||
}
|
||||
|
||||
/// 用来存储搜索到的设备,并用于去重和过滤
|
||||
final Map<String, ScanResult> _discoveredDevices = {};
|
||||
|
||||
@ -281,23 +292,146 @@ class BleService {
|
||||
BaseBleCommand.MAX_PACKET_DATA_SIZE = mtu;
|
||||
}
|
||||
|
||||
/// 用于存储分包接收的数据
|
||||
final Map<int, List<int>> _pendingPackets = {};
|
||||
|
||||
/// 监听订阅值变化
|
||||
void _handleListenCharacteristicData(List<int> data) async {
|
||||
void _handleListenCharacteristicData(List<int> data) {
|
||||
AppLogger.highlight('✨✨✨ 📨 收到订阅数据:$data (长度: ${data.length}) ✨✨✨');
|
||||
|
||||
// 解析数据
|
||||
if (data.isNotEmpty) {
|
||||
dynamic result = await bleCommandManager.handleResponse(data);
|
||||
|
||||
if (result != null) {
|
||||
// 触发命令响应等待器
|
||||
_triggerCommandResponseWaiters(result);
|
||||
} else {
|
||||
AppLogger.warn('⚠️ 数据包解析失败或不匹配任何命令');
|
||||
// ✨✨✨ 处理分包数据重组 ✨✨✨
|
||||
List<int>? completePacket = _reassemblePacket(data);
|
||||
|
||||
if (completePacket != null) {
|
||||
// 如果有完整数据包,进行处理
|
||||
dynamic result = bleCommandManager.handleResponse(completePacket);
|
||||
|
||||
if (result != null) {
|
||||
// 触发命令响应等待器
|
||||
_triggerCommandResponseWaiters(result);
|
||||
} else {
|
||||
AppLogger.warn('⚠️ 数据包解析失败或不匹配任何命令');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
AppLogger.warn('✨✨✨ ⚠️ 收到空数据 ✨✨✨');
|
||||
}
|
||||
}
|
||||
|
||||
/// ✨✨✨ 重组分包数据 ✨✨✨
|
||||
/// [data] 接收到的数据片段
|
||||
/// 返回完整的数据包,如果数据不完整则返回null
|
||||
List<int>? _reassemblePacket(List<int> data) {
|
||||
try {
|
||||
// 1. 检查是否是包头开始的数据
|
||||
if (data.length >= 4 &&
|
||||
data[0] == BaseBleCommand.PACKET_HEADER[0] &&
|
||||
data[1] == BaseBleCommand.PACKET_HEADER[1] &&
|
||||
data[2] == BaseBleCommand.PACKET_HEADER[2] &&
|
||||
data[3] == BaseBleCommand.PACKET_HEADER[3]) {
|
||||
|
||||
// 这是一个新包的开始
|
||||
// 首先检查是否已有未完成的包,如果有则丢弃(超时处理)
|
||||
if (_pendingPackets.isNotEmpty) {
|
||||
AppLogger.warn('⚠️ 检测到新包开始,丢弃未完成的包');
|
||||
_pendingPackets.clear();
|
||||
}
|
||||
|
||||
// 解析包头信息以获取预期长度
|
||||
if (data.length >= 12) {
|
||||
// 解析包序号 (大端序)
|
||||
int packetSequence = (data[5] << 8) | data[6];
|
||||
|
||||
// 解析数据长度 (大端序: 高16位加密后长度 + 低16位原始长度)
|
||||
int combinedLength = (data[8] << 24) | (data[9] << 16) | (data[10] << 8) | data[11];
|
||||
int encryptedDataLength = (combinedLength >> 16) & 0xFFFF;
|
||||
int originalDataLength = combinedLength & 0xFFFF;
|
||||
|
||||
// 根据加密类型确定实际数据长度
|
||||
int encryptType = data[7] & 0x0F;
|
||||
int actualDataLength = (encryptType == BaseBleCommand.ENCRYPT_TYPE_PLAIN) ? originalDataLength : encryptedDataLength;
|
||||
|
||||
// 计算完整包的预期长度
|
||||
int expectedTotalLength = 12 + actualDataLength + 2; // 包头到数据长度(12) + 数据块 + CRC(2)
|
||||
|
||||
AppLogger.debug('📦 新包开始: 序号=$packetSequence, 预期长度=$expectedTotalLength, 实际长度=${data.length}');
|
||||
|
||||
if (data.length == expectedTotalLength) {
|
||||
// 数据完整,直接返回
|
||||
AppLogger.debug('✅ 数据包完整,无需重组');
|
||||
return data;
|
||||
} else if (data.length < expectedTotalLength) {
|
||||
// 数据不完整,存储到待处理队列
|
||||
AppLogger.debug('📥 数据包不完整,开始重组: 已接收${data.length}/$expectedTotalLength字节');
|
||||
_pendingPackets[packetSequence] = List.from(data);
|
||||
return null;
|
||||
} else {
|
||||
// 数据长度超过预期,可能存在错误
|
||||
AppLogger.warn('⚠️ 数据包长度异常: 实际${data.length}字节 > 预期$expectedTotalLength字节');
|
||||
return data;
|
||||
}
|
||||
} else {
|
||||
// 包头信息不完整
|
||||
AppLogger.warn('⚠️ 包头信息不完整,无法解析包长度');
|
||||
return data;
|
||||
}
|
||||
} else {
|
||||
// 这是数据片段,尝试追加到现有未完成的包
|
||||
if (_pendingPackets.isNotEmpty) {
|
||||
// 获取第一个(也是唯一一个)未完成的包
|
||||
int packetSequence = _pendingPackets.keys.first;
|
||||
List<int> pendingData = _pendingPackets[packetSequence]!;
|
||||
|
||||
// 追加数据
|
||||
pendingData.addAll(data);
|
||||
_pendingPackets[packetSequence] = pendingData;
|
||||
|
||||
AppLogger.debug('📥 追加数据片段: 当前长度${pendingData.length}字节');
|
||||
|
||||
// 尝试解析包头信息以检查是否完整
|
||||
if (pendingData.length >= 12) {
|
||||
// 解析数据长度
|
||||
int combinedLength = (pendingData[8] << 24) | (pendingData[9] << 16) | (pendingData[10] << 8) | pendingData[11];
|
||||
int encryptedDataLength = (combinedLength >> 16) & 0xFFFF;
|
||||
int originalDataLength = combinedLength & 0xFFFF;
|
||||
|
||||
// 根据加密类型确定实际数据长度
|
||||
int encryptType = pendingData[7] & 0x0F;
|
||||
int actualDataLength = (encryptType == BaseBleCommand.ENCRYPT_TYPE_PLAIN) ? originalDataLength : encryptedDataLength;
|
||||
|
||||
// 计算完整包的预期长度
|
||||
int expectedTotalLength = 12 + actualDataLength + 2; // 包头到数据长度(12) + 数据块 + CRC(2)
|
||||
|
||||
if (pendingData.length == expectedTotalLength) {
|
||||
// 数据完整,返回完整包并清理待处理队列
|
||||
AppLogger.debug('✅ 数据包重组完成: 序号=$packetSequence, 长度=$expectedTotalLength字节');
|
||||
List<int> completePacket = _pendingPackets.remove(packetSequence)!;
|
||||
return completePacket;
|
||||
} else if (pendingData.length > expectedTotalLength) {
|
||||
// 数据长度超过预期,可能存在错误
|
||||
AppLogger.warn('⚠️ 重组后数据包长度异常: 实际${pendingData.length}字节 > 预期$expectedTotalLength字节');
|
||||
_pendingPackets.clear();
|
||||
return pendingData;
|
||||
}
|
||||
// 如果长度还不够,继续等待更多数据
|
||||
}
|
||||
// 如果包头信息还不完整,继续等待更多数据
|
||||
return null;
|
||||
} else {
|
||||
// 没有未完成的包,但收到的数据不是包头开始的数据
|
||||
AppLogger.warn('⚠️ 收到无法关联的数据片段');
|
||||
return data;
|
||||
}
|
||||
}
|
||||
} catch (e, stackTrace) {
|
||||
AppLogger.error('❌ 数据包重组异常', error: e, stackTrace: stackTrace);
|
||||
_pendingPackets.clear(); // 清理异常状态
|
||||
return data; // 返回原始数据让后续处理尝试解析
|
||||
}
|
||||
}
|
||||
|
||||
/// ✨✨✨ 触发命令响应等待器 ✨✨✨
|
||||
void _triggerCommandResponseWaiters(dynamic response) {
|
||||
// 遍历所有等待中的命令,找到匹配的进行响应
|
||||
|
||||
@ -6,6 +6,7 @@ import 'package:starwork_flutter/ble/command/base/base_ble_command.dart';
|
||||
import 'package:starwork_flutter/ble/command/base/base_ble_response_parser.dart';
|
||||
import 'package:starwork_flutter/ble/command/response/ble_cmd_get_private_key_parser.dart';
|
||||
import 'package:starwork_flutter/ble/command/response/ble_cmd_get_public_key_parser.dart';
|
||||
import 'package:starwork_flutter/ble/command/response/ble_cmd_read_lock_status_parser.dart';
|
||||
import 'package:starwork_flutter/common/constant/cache_keys.dart';
|
||||
import 'package:starwork_flutter/common/sm4_encipher/sm4.dart';
|
||||
import 'package:starwork_flutter/common/utils/shared_preferences_utils.dart';
|
||||
@ -48,6 +49,7 @@ class BleCommandManager {
|
||||
// 注册获取公钥命令解析器
|
||||
registerParser(BleCmdGetPublicKeyParser());
|
||||
registerParser(BleCmdGetPrivateKeyParser());
|
||||
registerParser(BleCmdReadLockStatusParser());
|
||||
|
||||
// TODO: 在这里注册其他命令解析器
|
||||
// registerParser(BleCmdSetPasswordParser());
|
||||
@ -72,7 +74,7 @@ class BleCommandManager {
|
||||
/// ✨✨✨ 处理接收到的应答数据包 ✨✨✨
|
||||
/// [rawPacketData] 完整的原始数据包
|
||||
/// 返回解析后的业务数据,如果没有匹配的解析器则返回null
|
||||
dynamic handleResponse(List<int> rawPacketData) async {
|
||||
dynamic handleResponse(List<int> rawPacketData) {
|
||||
AppLogger.debug('📊 收到蓝牙数据 (${rawPacketData.length}字节): ${rawPacketData.map((b) => '0x${b.toRadixString(16).padLeft(2, '0')}').join(' ')}');
|
||||
|
||||
try {
|
||||
@ -92,7 +94,7 @@ class BleCommandManager {
|
||||
}
|
||||
|
||||
// ✨✨✨ 根据加密类型进行解密处理 ✨✨✨
|
||||
List<int> processedData = await _decryptDataIfNeeded(parsedPacket);
|
||||
List<int> processedData = _decryptDataIfNeededSync(parsedPacket);
|
||||
|
||||
// ✨✨✨ 提取命令ID (大端序) ✨✨✨
|
||||
int commandId = (processedData[0] << 8) | processedData[1];
|
||||
@ -132,6 +134,51 @@ class BleCommandManager {
|
||||
}
|
||||
}
|
||||
|
||||
/// ✨✨✨ 根据加密类型解密数据(同步版本) ✨✨✨
|
||||
/// [parsedPacket] 已解析的数据包
|
||||
/// 返回解密后的数据或原始数据(如果不需要解密)
|
||||
List<int> _decryptDataIfNeededSync(ParsedPacket parsedPacket) {
|
||||
// 如果是明文,直接返回原始数据
|
||||
if (parsedPacket.encryptType == BaseBleCommand.ENCRYPT_TYPE_PLAIN) {
|
||||
AppLogger.debug('🔓 数据未加密,直接使用原始数据');
|
||||
return parsedPacket.data;
|
||||
}
|
||||
|
||||
switch (parsedPacket.encryptType) {
|
||||
case BaseBleCommand.ENCRYPT_TYPE_AES128:
|
||||
return parsedPacket.data;
|
||||
case BaseBleCommand.ENCRYPT_TYPE_SM4_PRESET:
|
||||
var connectedDevice = BleService().connectedDevice;
|
||||
var platformName = connectedDevice?.platformName ?? '';
|
||||
if (platformName.isEmpty) {
|
||||
AppLogger.warn('⚠️ 解密数据时未找到设备名称');
|
||||
return parsedPacket.data;
|
||||
}
|
||||
var decrypt = SM4.decrypt(
|
||||
parsedPacket.data,
|
||||
key: utf8.encode(platformName),
|
||||
mode: SM4CryptoMode.ECB,
|
||||
);
|
||||
return decrypt;
|
||||
case BaseBleCommand.ENCRYPT_TYPE_SM4_DEVICE:
|
||||
// 使用缓存的私钥进行解密
|
||||
var cachedPrivateKey = BleService.cachedPrivateKey;
|
||||
if (cachedPrivateKey == null || cachedPrivateKey.isEmpty) {
|
||||
AppLogger.warn('⚠️ 解密数据时未找到缓存的私钥');
|
||||
return parsedPacket.data;
|
||||
}
|
||||
var decrypt = SM4.decrypt(
|
||||
parsedPacket.data,
|
||||
key: cachedPrivateKey,
|
||||
mode: SM4CryptoMode.ECB,
|
||||
);
|
||||
return decrypt;
|
||||
default:
|
||||
AppLogger.warn('⚠️ 未知的加密类型: ${parsedPacket.encryptType},使用原始数据');
|
||||
return parsedPacket.data;
|
||||
}
|
||||
}
|
||||
|
||||
/// ✨✨✨ 根据加密类型解密数据 ✨✨✨
|
||||
/// [parsedPacket] 已解析的数据包
|
||||
/// 返回解密后的数据或原始数据(如果不需要解密)
|
||||
|
||||
@ -2,6 +2,7 @@ import 'package:starwork_flutter/base/app_logger.dart';
|
||||
import 'package:starwork_flutter/ble/command/base/base_ble_command.dart';
|
||||
import 'package:starwork_flutter/ble/command/base/base_ble_response_parser.dart';
|
||||
import 'package:starwork_flutter/ble/command/request/ble_cmd_get_public_key.dart';
|
||||
import 'package:starwork_flutter/ble/command/request/ble_cmd_read_lock_status.dart';
|
||||
|
||||
/// ✨✨✨ 读取锁状态命令应答数据结构 ✨✨✨
|
||||
class ReadLockStatusResponse {
|
||||
@ -94,7 +95,7 @@ class ReadLockStatusResponse {
|
||||
/// ✨✨✨ 读取锁状态命令应答解析器 ✨✨✨
|
||||
class BleCmdReadLockStatusParser extends BaseBleResponseParser {
|
||||
@override
|
||||
int get commandId => BleCmdGetPublicKey.cmdId; // 0x3090
|
||||
int get commandId => BleCmdReadLockStatus.cmdId;
|
||||
|
||||
@override
|
||||
String get commandName => '读取锁状态命令';
|
||||
|
||||
@ -207,6 +207,9 @@ class SearchDeviceController extends BaseController {
|
||||
await SharedPreferencesUtils.saveIntList(CacheKeys.lockCommKey, privateKeyResponse.commKey);
|
||||
await SharedPreferencesUtils.saveIntList(CacheKeys.lockSignKey, privateKeyResponse.signKey);
|
||||
AppLogger.info('🎯 获取私钥成功: ${privateKeyResponse.toString()}');
|
||||
|
||||
// 更新缓存的私钥,以便在解密时使用
|
||||
BleService.setCachedPrivateKey(privateKeyResponse.commKey);
|
||||
|
||||
//读取锁状态
|
||||
BleCmdReadLockStatus readLockStatusCmd = BleCmdReadLockStatus(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user