You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
433 lines
13 KiB
433 lines
13 KiB
import 'dart:async';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:ble_service/ble_service.dart';
|
|
|
|
/// BLE测试控制器
|
|
/// 用于测试BLE服务插件的功能
|
|
class BleTestController extends GetxController {
|
|
// 设备列表
|
|
final deviceList = <BleDevice>[].obs;
|
|
|
|
// 扫描状态
|
|
final isScanning = false.obs;
|
|
|
|
// 连接状态
|
|
final isConnected = false.obs;
|
|
final connectionState = 0.obs;
|
|
|
|
// 设备信息
|
|
final connectedDeviceAddress = ''.obs;
|
|
final batteryLevel = 0.obs;
|
|
final firmwareVersion = ''.obs;
|
|
|
|
// 状态消息
|
|
final statusMessage = ''.obs;
|
|
|
|
// BLE服务
|
|
final _bleService = BleService();
|
|
|
|
// 订阅
|
|
late StreamSubscription _scanSubscription;
|
|
late StreamSubscription _connectionSubscription;
|
|
late StreamSubscription _dataSubscription;
|
|
late StreamSubscription _statusSubscription;
|
|
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
_initBleService();
|
|
}
|
|
|
|
/// 初始化BLE服务
|
|
Future<void> _initBleService() async {
|
|
try {
|
|
// 初始化BLE服务
|
|
final result = await _bleService.initialize();
|
|
if (result) {
|
|
statusMessage.value = 'BLE服务初始化成功';
|
|
|
|
// 注册回调
|
|
await _bleService.registerCallback();
|
|
|
|
// 订阅扫描结果
|
|
_scanSubscription = _bleService.onScanResults.listen((devices) {
|
|
if (devices.isEmpty) {
|
|
deviceList.clear();
|
|
return;
|
|
}
|
|
|
|
bool hasChanges = false;
|
|
|
|
for (final newDevice in devices) {
|
|
int existingIndex = deviceList.indexWhere((d) => d.id == newDevice.id);
|
|
if (existingIndex >= 0) {
|
|
BleDevice existing = deviceList[existingIndex];
|
|
if (existing.rssi != newDevice.rssi || existing.name != newDevice.name) {
|
|
deviceList[existingIndex] = newDevice;
|
|
hasChanges = true;
|
|
}
|
|
} else {
|
|
deviceList.add(newDevice);
|
|
hasChanges = true;
|
|
}
|
|
}
|
|
|
|
if (hasChanges) {
|
|
deviceList.refresh();
|
|
}
|
|
});
|
|
|
|
// 订阅连接状态
|
|
_connectionSubscription = _bleService.onConnectionChanged.listen((state) {
|
|
if (state is int) {
|
|
connectionState.value = state;
|
|
isConnected.value = state == BleConnectionState.connected;
|
|
statusMessage.value = '连接状态变更: ${_getStateString(state)}';
|
|
}
|
|
});
|
|
|
|
// 订阅数据
|
|
_dataSubscription = _bleService.onDataReceived.listen((data) {
|
|
if (data is Map) {
|
|
final type = data['type'];
|
|
if (type == 'wakeup') {
|
|
statusMessage.value = '收到唤醒信号';
|
|
} else if (type == 'audioData') {
|
|
statusMessage.value = '收到音频数据: ${(data['data'] as Uint8List).length} 字节';
|
|
} else if (type == 'rawData') {
|
|
statusMessage.value = '收到原始数据: ${(data['data'] as Uint8List).length} 字节';
|
|
}
|
|
}
|
|
});
|
|
|
|
// 订阅状态更新
|
|
_statusSubscription = _bleService.onStatusUpdated.listen((status) {
|
|
if (status is Map) {
|
|
final type = status['type'];
|
|
if (type == 'statusUpdate') {
|
|
// 更新状态
|
|
connectionState.value = status['connectionState'] as int? ?? 0;
|
|
isConnected.value = connectionState.value == BleConnectionState.connected;
|
|
batteryLevel.value = status['batteryLevel'] as int? ?? 0;
|
|
firmwareVersion.value = status['firmwareVersion'] as String? ?? '';
|
|
connectedDeviceAddress.value = status['connectedDevice'] as String? ?? '';
|
|
|
|
statusMessage.value = '状态更新: ${_getStateString(connectionState.value)}';
|
|
} else if (type == 'deviceInfo') {
|
|
// 设备信息
|
|
final infoType = status['infoType'] as int;
|
|
final infoData = status['infoData'] as String;
|
|
|
|
statusMessage.value = '设备信息: $infoData';
|
|
|
|
// 处理不同类型的设备信息
|
|
if (infoType == 0x80) { // 版本信息
|
|
firmwareVersion.value = infoData;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// 获取连接状态
|
|
_updateConnectionState();
|
|
} else {
|
|
statusMessage.value = 'BLE服务初始化失败';
|
|
}
|
|
} catch (e) {
|
|
statusMessage.value = '初始化异常: $e';
|
|
Get.snackbar('初始化失败', '无法初始化BLE服务: $e',
|
|
snackPosition: SnackPosition.BOTTOM);
|
|
}
|
|
}
|
|
|
|
/// 获取状态字符串
|
|
String _getStateString(int state) {
|
|
switch (state) {
|
|
case BleConnectionState.disconnected:
|
|
return '已断开';
|
|
case BleConnectionState.connecting:
|
|
return '连接中';
|
|
case BleConnectionState.connected:
|
|
return '已连接';
|
|
case BleConnectionState.disconnecting:
|
|
return '断开中';
|
|
case BleConnectionState.error:
|
|
return '连接错误';
|
|
default:
|
|
return '未知状态($state)';
|
|
}
|
|
}
|
|
|
|
/// 更新连接状态
|
|
Future<void> _updateConnectionState() async {
|
|
connectionState.value = await _bleService.getConnectionState();
|
|
isConnected.value = connectionState.value == BleConnectionState.connected;
|
|
|
|
if (isConnected.value) {
|
|
connectedDeviceAddress.value = await _bleService.getConnectedDeviceAddress() ?? '';
|
|
batteryLevel.value = await _bleService.getBatteryLevel();
|
|
firmwareVersion.value = await _bleService.getFirmwareVersion() ?? '';
|
|
}
|
|
}
|
|
|
|
/// 开始扫描设备
|
|
Future<void> startScan() async {
|
|
try {
|
|
// 清空设备列表
|
|
deviceList.clear();
|
|
|
|
// 设置扫描状态
|
|
isScanning.value = true;
|
|
statusMessage.value = '开始扫描...';
|
|
|
|
// 开始扫描
|
|
final result = await _bleService.startScan(timeout: 15000);
|
|
|
|
if (!result) {
|
|
statusMessage.value = '扫描失败';
|
|
Get.snackbar('扫描失败', '无法启动BLE扫描',
|
|
snackPosition: SnackPosition.BOTTOM);
|
|
}
|
|
} catch (e) {
|
|
statusMessage.value = '扫描异常: $e';
|
|
Get.snackbar('扫描错误', '扫描过程中出错: $e',
|
|
snackPosition: SnackPosition.BOTTOM);
|
|
} finally {
|
|
// 5秒后自动停止扫描
|
|
Future.delayed(const Duration(seconds: 15), () {
|
|
if (isScanning.value) {
|
|
stopScan();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
/// 停止扫描设备
|
|
Future<void> stopScan() async {
|
|
try {
|
|
await _bleService.stopScan();
|
|
isScanning.value = false;
|
|
statusMessage.value = '扫描已停止';
|
|
} catch (e) {
|
|
statusMessage.value = '停止扫描异常: $e';
|
|
Get.snackbar('停止扫描失败', '无法停止BLE扫描: $e',
|
|
snackPosition: SnackPosition.BOTTOM);
|
|
}
|
|
}
|
|
|
|
/// 连接到设备
|
|
Future<void> connectToDevice(String address) async {
|
|
try {
|
|
statusMessage.value = '正在连接到 $address...';
|
|
|
|
final result = await _bleService.connect(address);
|
|
|
|
if (!result) {
|
|
statusMessage.value = '连接失败';
|
|
Get.snackbar('连接失败', '无法连接到设备',
|
|
snackPosition: SnackPosition.BOTTOM);
|
|
} else {
|
|
connectedDeviceAddress.value = address;
|
|
statusMessage.value = '连接成功,正在获取设备信息...';
|
|
|
|
// 获取设备信息
|
|
await _bleService.getDeviceVersion();
|
|
await _bleService.getBatteryInfo();
|
|
}
|
|
} catch (e) {
|
|
statusMessage.value = '连接异常: $e';
|
|
Get.snackbar('连接错误', '连接过程中出错: $e',
|
|
snackPosition: SnackPosition.BOTTOM);
|
|
}
|
|
}
|
|
|
|
/// 断开设备连接
|
|
Future<void> disconnect() async {
|
|
try {
|
|
statusMessage.value = '正在断开连接...';
|
|
|
|
await _bleService.disconnect();
|
|
|
|
connectedDeviceAddress.value = '';
|
|
isConnected.value = false;
|
|
|
|
statusMessage.value = '已断开连接';
|
|
} catch (e) {
|
|
statusMessage.value = '断开连接异常: $e';
|
|
Get.snackbar('断开连接失败', '无法断开设备连接: $e',
|
|
snackPosition: SnackPosition.BOTTOM);
|
|
}
|
|
}
|
|
|
|
/// 获取设备版本信息
|
|
Future<void> getDeviceVersion() async {
|
|
try {
|
|
statusMessage.value = '正在获取设备版本...';
|
|
|
|
await _bleService.getDeviceVersion();
|
|
|
|
statusMessage.value = '版本获取命令已发送';
|
|
} catch (e) {
|
|
statusMessage.value = '获取版本异常: $e';
|
|
Get.snackbar('获取版本失败', '无法获取设备版本: $e',
|
|
snackPosition: SnackPosition.BOTTOM);
|
|
}
|
|
}
|
|
|
|
/// 获取电池信息
|
|
Future<void> getBatteryInfo() async {
|
|
try {
|
|
statusMessage.value = '正在获取电池信息...';
|
|
|
|
await _bleService.getBatteryInfo();
|
|
|
|
statusMessage.value = '电池信息获取命令已发送';
|
|
} catch (e) {
|
|
statusMessage.value = '获取电池信息异常: $e';
|
|
Get.snackbar('获取电池信息失败', '无法获取电池信息: $e',
|
|
snackPosition: SnackPosition.BOTTOM);
|
|
}
|
|
}
|
|
|
|
/// 打开编码器
|
|
Future<void> openEncoder() async {
|
|
try {
|
|
statusMessage.value = '正在打开编码器...';
|
|
|
|
await _bleService.openEncoder();
|
|
|
|
statusMessage.value = '编码器打开命令已发送';
|
|
} catch (e) {
|
|
statusMessage.value = '打开编码器异常: $e';
|
|
Get.snackbar('操作失败', '无法打开编码器: $e',
|
|
snackPosition: SnackPosition.BOTTOM);
|
|
}
|
|
}
|
|
|
|
/// 打开解码器
|
|
Future<void> openDecoder() async {
|
|
try {
|
|
statusMessage.value = '正在打开解码器...';
|
|
|
|
await _bleService.openDecoder();
|
|
|
|
statusMessage.value = '解码器打开命令已发送';
|
|
} catch (e) {
|
|
statusMessage.value = '打开解码器异常: $e';
|
|
Get.snackbar('操作失败', '无法打开解码器: $e',
|
|
snackPosition: SnackPosition.BOTTOM);
|
|
}
|
|
}
|
|
|
|
/// 关闭编解码器
|
|
Future<void> closeCodec() async {
|
|
try {
|
|
statusMessage.value = '正在关闭编解码器...';
|
|
|
|
await _bleService.closeCodec();
|
|
|
|
statusMessage.value = '编解码器关闭命令已发送';
|
|
} catch (e) {
|
|
statusMessage.value = '关闭编解码器异常: $e';
|
|
Get.snackbar('操作失败', '无法关闭编解码器: $e',
|
|
snackPosition: SnackPosition.BOTTOM);
|
|
}
|
|
}
|
|
|
|
/// 播放A2DP
|
|
Future<void> playA2DP() async {
|
|
try {
|
|
statusMessage.value = '正在播放A2DP...';
|
|
|
|
await _bleService.playA2DP();
|
|
|
|
statusMessage.value = 'A2DP播放命令已发送';
|
|
} catch (e) {
|
|
statusMessage.value = '播放A2DP异常: $e';
|
|
Get.snackbar('操作失败', '无法播放A2DP: $e',
|
|
snackPosition: SnackPosition.BOTTOM);
|
|
}
|
|
}
|
|
|
|
/// 音量增加
|
|
Future<void> volumeUp() async {
|
|
try {
|
|
statusMessage.value = '正在增加音量...';
|
|
|
|
await _bleService.volumeUp();
|
|
|
|
statusMessage.value = '音量增加命令已发送';
|
|
} catch (e) {
|
|
statusMessage.value = '增加音量异常: $e';
|
|
Get.snackbar('操作失败', '无法增加音量: $e',
|
|
snackPosition: SnackPosition.BOTTOM);
|
|
}
|
|
}
|
|
|
|
/// 音量减小
|
|
Future<void> volumeDown() async {
|
|
try {
|
|
statusMessage.value = '正在减小音量...';
|
|
|
|
await _bleService.volumeDown();
|
|
|
|
statusMessage.value = '音量减小命令已发送';
|
|
} catch (e) {
|
|
statusMessage.value = '减小音量异常: $e';
|
|
Get.snackbar('操作失败', '无法减小音量: $e',
|
|
snackPosition: SnackPosition.BOTTOM);
|
|
}
|
|
}
|
|
|
|
/// 发送音频数据
|
|
Future<void> sendAudioData(Uint8List data) async {
|
|
try {
|
|
statusMessage.value = '正在发送音频数据...';
|
|
|
|
await _bleService.sendAudioData(data);
|
|
|
|
statusMessage.value = '音频数据发送成功: ${data.length} 字节';
|
|
} catch (e) {
|
|
statusMessage.value = '发送音频数据异常: $e';
|
|
Get.snackbar('发送失败', '无法发送音频数据: $e',
|
|
snackPosition: SnackPosition.BOTTOM);
|
|
}
|
|
}
|
|
|
|
/// 清理资源
|
|
Future<void> cleanup() async {
|
|
try {
|
|
await _bleService.cleanup();
|
|
} catch (e) {
|
|
Get.snackbar('清理失败', '无法清理BLE资源: $e',
|
|
snackPosition: SnackPosition.BOTTOM);
|
|
}
|
|
}
|
|
|
|
@override
|
|
void onClose() {
|
|
// 取消所有订阅
|
|
_scanSubscription.cancel();
|
|
_connectionSubscription.cancel();
|
|
_dataSubscription.cancel();
|
|
_statusSubscription.cancel();
|
|
|
|
// 停止扫描
|
|
if (isScanning.value) {
|
|
stopScan();
|
|
}
|
|
|
|
// 断开连接
|
|
if (isConnected.value) {
|
|
disconnect();
|
|
}
|
|
|
|
// 清理资源
|
|
cleanup();
|
|
|
|
super.onClose();
|
|
}
|
|
}
|