starwork_flutter/lib/ble/command/ble_command_manager.dart

222 lines
8.5 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:convert';
import 'package:starwork_flutter/base/app_logger.dart';
import 'package:starwork_flutter/ble/ble_service.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/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/common/constant/cache_keys.dart';
import 'package:starwork_flutter/common/sm4_encipher/sm4.dart';
import 'package:starwork_flutter/common/utils/shared_preferences_utils.dart';
/// ✨✨✨ 蓝牙命令管理器 - 统一管理所有命令解析器 ✨✨✨
class BleCommandManager {
// 私有构造函数
BleCommandManager._() {
// ✅ 这里就是单例初始化的地方
// 只会执行一次(第一次获取实例时)
_initialize();
}
// 单例实例
static final BleCommandManager _instance = BleCommandManager._();
// 工厂构造函数,提供全局访问点
factory BleCommandManager() => _instance;
/// 所有已注册的命令解析器
final Map<int, BaseBleResponseParser> _parsers = {};
/// ✨✨✨ 初始化命令管理器 ✨✨✨
void _initialize() {
AppLogger.highlight('✨✨✨ 🚀 初始化蓝牙命令管理器 ✨✨✨');
// 注册所有命令解析器
_registerParsers();
AppLogger.info('📋 已注册命令解析器数量: ${_parsers.length}');
_parsers.forEach((commandId, parser) {
AppLogger.debug(' • 0x${commandId.toRadixString(16).padLeft(4, '0')}: ${parser.commandName}');
});
AppLogger.highlight('✨✨✨ ✅ 蓝牙命令管理器初始化完成 ✨✨✨');
}
/// ✨✨✨ 注册所有命令解析器 ✨✨✨
void _registerParsers() {
// 注册获取公钥命令解析器
registerParser(BleCmdGetPublicKeyParser());
registerParser(BleCmdGetPrivateKeyParser());
// TODO: 在这里注册其他命令解析器
// registerParser(BleCmdSetPasswordParser());
// registerParser(BleCmdUnlockParser());
// 等等...
}
/// ✨✨✨ 注册命令解析器 ✨✨✨
void registerParser(BaseBleResponseParser parser) {
_parsers[parser.commandId] = parser;
AppLogger.debug('📝 注册命令解析器: 0x${parser.commandId.toRadixString(16).padLeft(4, '0')} - ${parser.commandName}');
}
/// ✨✨✨ 移除命令解析器 ✨✨✨
void unregisterParser(int commandId) {
BaseBleResponseParser? removed = _parsers.remove(commandId);
if (removed != null) {
AppLogger.debug('🗑️ 移除命令解析器: 0x${commandId.toRadixString(16).padLeft(4, '0')} - ${removed.commandName}');
}
}
/// ✨✨✨ 处理接收到的应答数据包 ✨✨✨
/// [rawPacketData] 完整的原始数据包
/// 返回解析后的业务数据如果没有匹配的解析器则返回null
dynamic handleResponse(List<int> rawPacketData) async {
AppLogger.debug('📊 收到蓝牙数据 (${rawPacketData.length}字节): ${rawPacketData.map((b) => '0x${b.toRadixString(16).padLeft(2, '0')}').join(' ')}');
try {
// ✨✨✨ 首先解析数据包以获取命令ID ✨✨✨
var parsedPacket = BaseBleCommand.parsePacket(rawPacketData);
// 检查数据包是否有效
if (!parsedPacket.isValid) {
AppLogger.warn('⚠️ 数据包无效: ${parsedPacket.errorMessage}');
return null;
}
// 检查数据长度是否足够包含命令ID
if (parsedPacket.data.length < 2) {
AppLogger.warn('⚠️ 应答数据长度不足无法包含命令ID: ${parsedPacket.data.length}字节');
return null;
}
// ✨✨✨ 根据加密类型进行解密处理 ✨✨✨
List<int> processedData = await _decryptDataIfNeeded(parsedPacket);
// ✨✨✨ 提取命令ID (大端序) ✨✨✨
int commandId = (processedData[0] << 8) | processedData[1];
AppLogger.debug('🔍 提取命令ID: 0x${commandId.toRadixString(16).padLeft(4, '0')}');
// ✨✨✨ 直接通过命令ID查找对应的解析器 ✨✨✨
BaseBleResponseParser? parser = _parsers[commandId];
if (parser != null) {
AppLogger.debug('🎯 找到匹配的解析器: ${parser.commandName}');
// 创建一个新的ParsedPacket对象使用解密后的数据
ParsedPacket decryptedPacket = ParsedPacket(
isValid: parsedPacket.isValid,
packetType: parsedPacket.packetType,
packetSequence: parsedPacket.packetSequence,
version: parsedPacket.version,
encryptType: parsedPacket.encryptType,
encryptedDataLength: parsedPacket.encryptedDataLength,
originalDataLength: parsedPacket.originalDataLength,
data: processedData,
crc16: parsedPacket.crc16,
errorMessage: parsedPacket.errorMessage,
);
// 传递解密后的数据给解析器
dynamic result = parser.parseResponse(decryptedPacket, processedData);
return result;
} else {
// 没有找到匹配的解析器
AppLogger.warn('⚠️ 未找到命令ID 0x${commandId.toRadixString(16).padLeft(4, '0')} 对应的解析器');
_logUnknownPacket(rawPacketData);
return null;
}
} catch (e, stackTrace) {
AppLogger.error('❌ 处理蓝牙应答异常', error: e, stackTrace: stackTrace);
return null;
}
}
/// ✨✨✨ 根据加密类型解密数据 ✨✨✨
/// [parsedPacket] 已解析的数据包
/// 返回解密后的数据或原始数据(如果不需要解密)
Future<List<int>> _decryptDataIfNeeded(ParsedPacket parsedPacket) async {
// 如果是明文,直接返回原始数据
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;
var decrypt = SM4.decrypt(
parsedPacket.data,
key: utf8.encode(platformName!),
mode: SM4CryptoMode.ECB,
);
return decrypt;
case BaseBleCommand.ENCRYPT_TYPE_SM4_DEVICE:
var lockCommKey = await SharedPreferencesUtils.getString(CacheKeys.lockCommKey);
if (lockCommKey == null) {
AppLogger.warn('⚠️ 解密订阅数据时未找到私钥');
return parsedPacket.data;
}
var decrypt = SM4.decrypt(
parsedPacket.data,
key: utf8.encode(lockCommKey),
mode: SM4CryptoMode.ECB,
);
return decrypt;
default:
AppLogger.warn('⚠️ 未知的加密类型: ${parsedPacket.encryptType},使用原始数据');
return parsedPacket.data;
}
}
/// ✨✨✨ 根据命令ID获取解析器 ✨✨✨
BaseBleResponseParser? getParser(int commandId) {
return _parsers[commandId];
}
/// ✨✨✨ 获取所有已注册的命令ID ✨✨✨
List<int> getRegisteredCommandIds() {
return _parsers.keys.toList();
}
/// ✨✨✨ 获取所有已注册的解析器信息 ✨✨✨
Map<int, String> getRegisteredParsersInfo() {
return _parsers.map((commandId, parser) => MapEntry(commandId, parser.commandName));
}
/// ✨✨✨ 记录未知数据包信息 ✨✨✨
void _logUnknownPacket(List<int> rawPacketData) {
try {
// 尝试基本解析以获取更多信息
var parsedPacket = BaseBleCommand.parsePacket(rawPacketData);
if (parsedPacket.isValid && parsedPacket.data.length >= 2) {
int commandId = (parsedPacket.data[0] << 8) | parsedPacket.data[1];
AppLogger.warn('🔍 未知命令应答: 命令ID=0x${commandId.toRadixString(16).padLeft(4, '0')}, ' +
'包类型=0x${parsedPacket.packetType.toRadixString(16).padLeft(2, '0')}, ' +
'数据长度=${parsedPacket.data.length}字节');
} else {
AppLogger.warn('🔍 无效或无法识别的数据包');
}
} catch (e) {
AppLogger.warn('🔍 无法解析的数据包: $e');
}
}
/// ✨✨✨ 清除所有解析器 ✨✨✨
void clear() {
AppLogger.info('🧹 清除所有命令解析器');
_parsers.clear();
}
/// ✨✨✨ 重新初始化 ✨✨✨
void reinitialize() {
AppLogger.info('🔄 重新初始化命令管理器');
clear();
_initialize();
}
}