fix: 增加获取锁状态接口
This commit is contained in:
parent
067489b37b
commit
e07e30f598
@ -47,6 +47,17 @@ class BleService {
|
|||||||
// 工厂构造函数,提供全局访问点
|
// 工厂构造函数,提供全局访问点
|
||||||
factory BleService() => _instance;
|
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 = {};
|
final Map<String, ScanResult> _discoveredDevices = {};
|
||||||
|
|
||||||
@ -281,23 +292,146 @@ class BleService {
|
|||||||
BaseBleCommand.MAX_PACKET_DATA_SIZE = mtu;
|
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) {
|
if (data.isNotEmpty) {
|
||||||
dynamic result = await bleCommandManager.handleResponse(data);
|
// ✨✨✨ 处理分包数据重组 ✨✨✨
|
||||||
|
List<int>? completePacket = _reassemblePacket(data);
|
||||||
if (result != null) {
|
|
||||||
// 触发命令响应等待器
|
if (completePacket != null) {
|
||||||
_triggerCommandResponseWaiters(result);
|
// 如果有完整数据包,进行处理
|
||||||
} else {
|
dynamic result = bleCommandManager.handleResponse(completePacket);
|
||||||
AppLogger.warn('⚠️ 数据包解析失败或不匹配任何命令');
|
|
||||||
|
if (result != null) {
|
||||||
|
// 触发命令响应等待器
|
||||||
|
_triggerCommandResponseWaiters(result);
|
||||||
|
} else {
|
||||||
|
AppLogger.warn('⚠️ 数据包解析失败或不匹配任何命令');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
AppLogger.warn('✨✨✨ ⚠️ 收到空数据 ✨✨✨');
|
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) {
|
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/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_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_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/constant/cache_keys.dart';
|
||||||
import 'package:starwork_flutter/common/sm4_encipher/sm4.dart';
|
import 'package:starwork_flutter/common/sm4_encipher/sm4.dart';
|
||||||
import 'package:starwork_flutter/common/utils/shared_preferences_utils.dart';
|
import 'package:starwork_flutter/common/utils/shared_preferences_utils.dart';
|
||||||
@ -48,6 +49,7 @@ class BleCommandManager {
|
|||||||
// 注册获取公钥命令解析器
|
// 注册获取公钥命令解析器
|
||||||
registerParser(BleCmdGetPublicKeyParser());
|
registerParser(BleCmdGetPublicKeyParser());
|
||||||
registerParser(BleCmdGetPrivateKeyParser());
|
registerParser(BleCmdGetPrivateKeyParser());
|
||||||
|
registerParser(BleCmdReadLockStatusParser());
|
||||||
|
|
||||||
// TODO: 在这里注册其他命令解析器
|
// TODO: 在这里注册其他命令解析器
|
||||||
// registerParser(BleCmdSetPasswordParser());
|
// registerParser(BleCmdSetPasswordParser());
|
||||||
@ -72,7 +74,7 @@ class BleCommandManager {
|
|||||||
/// ✨✨✨ 处理接收到的应答数据包 ✨✨✨
|
/// ✨✨✨ 处理接收到的应答数据包 ✨✨✨
|
||||||
/// [rawPacketData] 完整的原始数据包
|
/// [rawPacketData] 完整的原始数据包
|
||||||
/// 返回解析后的业务数据,如果没有匹配的解析器则返回null
|
/// 返回解析后的业务数据,如果没有匹配的解析器则返回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(' ')}');
|
AppLogger.debug('📊 收到蓝牙数据 (${rawPacketData.length}字节): ${rawPacketData.map((b) => '0x${b.toRadixString(16).padLeft(2, '0')}').join(' ')}');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -92,7 +94,7 @@ class BleCommandManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ✨✨✨ 根据加密类型进行解密处理 ✨✨✨
|
// ✨✨✨ 根据加密类型进行解密处理 ✨✨✨
|
||||||
List<int> processedData = await _decryptDataIfNeeded(parsedPacket);
|
List<int> processedData = _decryptDataIfNeededSync(parsedPacket);
|
||||||
|
|
||||||
// ✨✨✨ 提取命令ID (大端序) ✨✨✨
|
// ✨✨✨ 提取命令ID (大端序) ✨✨✨
|
||||||
int commandId = (processedData[0] << 8) | processedData[1];
|
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] 已解析的数据包
|
/// [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_command.dart';
|
||||||
import 'package:starwork_flutter/ble/command/base/base_ble_response_parser.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_get_public_key.dart';
|
||||||
|
import 'package:starwork_flutter/ble/command/request/ble_cmd_read_lock_status.dart';
|
||||||
|
|
||||||
/// ✨✨✨ 读取锁状态命令应答数据结构 ✨✨✨
|
/// ✨✨✨ 读取锁状态命令应答数据结构 ✨✨✨
|
||||||
class ReadLockStatusResponse {
|
class ReadLockStatusResponse {
|
||||||
@ -94,7 +95,7 @@ class ReadLockStatusResponse {
|
|||||||
/// ✨✨✨ 读取锁状态命令应答解析器 ✨✨✨
|
/// ✨✨✨ 读取锁状态命令应答解析器 ✨✨✨
|
||||||
class BleCmdReadLockStatusParser extends BaseBleResponseParser {
|
class BleCmdReadLockStatusParser extends BaseBleResponseParser {
|
||||||
@override
|
@override
|
||||||
int get commandId => BleCmdGetPublicKey.cmdId; // 0x3090
|
int get commandId => BleCmdReadLockStatus.cmdId;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get commandName => '读取锁状态命令';
|
String get commandName => '读取锁状态命令';
|
||||||
|
|||||||
@ -207,6 +207,9 @@ class SearchDeviceController extends BaseController {
|
|||||||
await SharedPreferencesUtils.saveIntList(CacheKeys.lockCommKey, privateKeyResponse.commKey);
|
await SharedPreferencesUtils.saveIntList(CacheKeys.lockCommKey, privateKeyResponse.commKey);
|
||||||
await SharedPreferencesUtils.saveIntList(CacheKeys.lockSignKey, privateKeyResponse.signKey);
|
await SharedPreferencesUtils.saveIntList(CacheKeys.lockSignKey, privateKeyResponse.signKey);
|
||||||
AppLogger.info('🎯 获取私钥成功: ${privateKeyResponse.toString()}');
|
AppLogger.info('🎯 获取私钥成功: ${privateKeyResponse.toString()}');
|
||||||
|
|
||||||
|
// 更新缓存的私钥,以便在解密时使用
|
||||||
|
BleService.setCachedPrivateKey(privateKeyResponse.commKey);
|
||||||
|
|
||||||
//读取锁状态
|
//读取锁状态
|
||||||
BleCmdReadLockStatus readLockStatusCmd = BleCmdReadLockStatus(
|
BleCmdReadLockStatus readLockStatusCmd = BleCmdReadLockStatus(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user