diff --git a/star_lock/android/app/build.gradle b/star_lock/android/app/build.gradle index 2c82c384..afe6fa92 100644 --- a/star_lock/android/app/build.gradle +++ b/star_lock/android/app/build.gradle @@ -47,8 +47,10 @@ android { applicationId "com.example.star_lock" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion +// minSdkVersion flutter.minSdkVersion +// targetSdkVersion flutter.targetSdkVersion + minSdkVersion 25 + targetSdkVersion 33 versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/star_lock/android/app/src/main/AndroidManifest.xml b/star_lock/android/app/src/main/AndroidManifest.xml index 0f4383a6..8678a200 100644 --- a/star_lock/android/app/src/main/AndroidManifest.xml +++ b/star_lock/android/app/src/main/AndroidManifest.xml @@ -1,5 +1,14 @@ + + + + + + + + + + diff --git a/star_lock/android/app/src/profile/AndroidManifest.xml b/star_lock/android/app/src/profile/AndroidManifest.xml index bb198dd7..90a3ec8b 100644 --- a/star_lock/android/app/src/profile/AndroidManifest.xml +++ b/star_lock/android/app/src/profile/AndroidManifest.xml @@ -9,12 +9,4 @@ - - - - - - diff --git a/star_lock/android/build.gradle b/star_lock/android/build.gradle index f8803dea..0425fc73 100644 --- a/star_lock/android/build.gradle +++ b/star_lock/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.6.10' + ext.kotlin_version = '1.9.0' repositories { google() mavenCentral() @@ -27,6 +27,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/star_lock/ios/Runner.xcodeproj/project.pbxproj b/star_lock/ios/Runner.xcodeproj/project.pbxproj index 839de38c..f3bc27dd 100644 --- a/star_lock/ios/Runner.xcodeproj/project.pbxproj +++ b/star_lock/ios/Runner.xcodeproj/project.pbxproj @@ -359,7 +359,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.starLock; + PRODUCT_BUNDLE_IDENTIFIER = com.example.starLock123; PRODUCT_NAME = "$(TARGET_NAME)"; VERSIONING_SYSTEM = "apple-generic"; }; @@ -486,7 +486,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.starLock; + PRODUCT_BUNDLE_IDENTIFIER = com.example.starLock123; PRODUCT_NAME = "$(TARGET_NAME)"; VERSIONING_SYSTEM = "apple-generic"; }; @@ -506,7 +506,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.starLock; + PRODUCT_BUNDLE_IDENTIFIER = com.example.starLock123; PRODUCT_NAME = "$(TARGET_NAME)"; VERSIONING_SYSTEM = "apple-generic"; }; diff --git a/star_lock/ios/Runner/Info.plist b/star_lock/ios/Runner/Info.plist index 37f6a326..705a553a 100644 --- a/star_lock/ios/Runner/Info.plist +++ b/star_lock/ios/Runner/Info.plist @@ -2,22 +2,8 @@ - NSCameraUsageDescription - 这是你的自拍照 - NSMicrophoneUsageDescription - 用于音频插件 - NSPhotoLibraryUsageDescription - 用于相册 - UIBackgroundModes - - remote-notification - - NSContactsUsageDescription - Reason we need access to the contact list - NSBluetoothAlwaysUsageDescription - The app uses bluetooth to find, connect and transfer data between different devices - NSBluetoothPeripheralUsageDescription - The app uses bluetooth to find, connect and transfer data between different devices + CADisableMinimumFrameDurationOnPhone + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName @@ -40,6 +26,24 @@ $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS + NSBluetoothAlwaysUsageDescription + The app uses bluetooth to find, connect and transfer data between different devices + NSBluetoothPeripheralUsageDescription + The app uses bluetooth to find, connect and transfer data between different devices + NSCameraUsageDescription + 这是你的自拍照 + NSContactsUsageDescription + Reason we need access to the contact list + NSMicrophoneUsageDescription + 用于音频插件 + NSPhotoLibraryUsageDescription + 用于相册 + UIApplicationSupportsIndirectInputEvents + + UIBackgroundModes + + remote-notification + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -59,9 +63,5 @@ UIViewControllerBasedStatusBarAppearance - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - diff --git a/star_lock/lib/blue/blue_manage.dart b/star_lock/lib/blue/blue_manage.dart new file mode 100644 index 00000000..20ae7646 --- /dev/null +++ b/star_lock/lib/blue/blue_manage.dart @@ -0,0 +1,264 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_reactive_ble/flutter_reactive_ble.dart'; +import 'package:star_lock/blue/sender_manage.dart'; + +import '../app_settings/app_settings.dart'; +import 'io_tool/io_tool.dart'; +import 'io_tool/manager_event_bus.dart'; + +typedef ScanResultCallBack = void Function(List devices); + +class BlueManage{ + FlutterReactiveBle? _flutterReactiveBle; + List _scanDevices = []; + QualifiedCharacteristic? qualifiedCharacteristic; + DiscoveredCharacteristic? getDiscoveredCharacteristic; + Uuid serviceId = Uuid.parse('0000FFF0-0000-1000-8000-00805F9B34FB'); + final int _limitLen = 20; + final int _sleepTimes = AppPlatform.isAndroid ? 6 : 0; + + static BlueManage? _manager; + BlueManage._init(); + + static BlueManage? shareManager(){ + _manager ??= BlueManage._init(); + _manager!._initBlue(); + return _manager; + } + + factory BlueManage() => shareManager()!; + BlueManage? get manager => shareManager(); + + void _initBlue(){ + _flutterReactiveBle = FlutterReactiveBle(); + } + + /// 开始扫描蓝牙设备 + void startScan(ScanResultCallBack scanResultCallBack) { + _scanDevices.clear(); + _flutterReactiveBle!.scanForDevices(withServices: []).listen((device) { + // 判断名字为空的直接剔除 + if(device.name.isEmpty){ + return; + } + + if (((device.serviceUuids.isNotEmpty ? device.serviceUuids[0] : "").toString().contains("758824")) && (device.rssi >= -100)) { + // print("11111111111111111:${device}"); + final knownDeviceIndex = _scanDevices.indexWhere((d) => d.id == device.id); + + if (knownDeviceIndex >= 0) { + _scanDevices[knownDeviceIndex] = device; + } else { + _scanDevices.add(device); + } + // EventBusManager().eventBusFir(_scanDevices); + scanResultCallBack(_scanDevices); + } + // _pushState(); + }, onError: (Object e) { + print('Device scan fails with error: $e'); + }); + } + + /// 连接监听状态 + Future connect(String deviceMAC) async { + print("connect:$deviceMAC"); + _flutterReactiveBle!.connectToDevice(id: deviceMAC).listen((connectionStateUpdate) { + print('ConnectionState for device $deviceMAC : ${connectionStateUpdate.connectionState}'); + // EventBusManager().eventBusFir(connectionStateUpdate); + if(connectionStateUpdate.connectionState == DeviceConnectionState.connected){ + // getPublicKey(update.deviceId); + // 如果状态是连接的开始发现服务 + discoverServices(deviceMAC); + } + }, onError: (Object e){ + print('Connecting to device $deviceMAC resulted in error $e'); + } + ); + } + + Future disconnect(String deviceMAC) async { + try { + print('disconnecting to device: $deviceMAC'); + } on Exception catch (e, _) { + print("Error disconnecting from a device: $e"); + } finally { + EventBusManager().eventBusFir(ConnectionStateUpdate( + deviceId: deviceMAC, + connectionState: DeviceConnectionState.disconnected, + failure: null, + )); + } + } + + // 扫描服务,并过滤服务 + Future> discoverServices(String deviceId) async { + try { + print('Start discovering services for: $deviceId'); + List result = await _flutterReactiveBle!.discoverServices(deviceId); + print("mmmmmmmmm$result"); + if(result.isNotEmpty){ + for (var i = 0; i < result.length; i++) { + DiscoveredService discoveredService = result[i]; + print("objectdiscoveredService.serviceId.toString() ${discoveredService.serviceId.toString()}"); + if (discoveredService.serviceId.toString() == "fff0"){ + // getDiscoveredService = discoveredService; + for (var j = 0; j < discoveredService.characteristics.length; j++) { + DiscoveredCharacteristic discoveredCharacteristic = discoveredService.characteristics[j]; + + // print("hhhhhhhhhh${result[i].characteristicIds[j].toString()}"); + if (discoveredCharacteristic.characteristicId.toString() == "fff1") { + // 订阅用 + getDiscoveredCharacteristic = discoveredCharacteristic; + // print("1111111111111111characteristicId:${result[i].characteristicIds[j].toString()} serviceId:${result[i].serviceId} deviceId:$deviceId"); + } + if (discoveredCharacteristic.characteristicId.toString() == "fff2") { + + print("1111111111111111characteristicId:${discoveredCharacteristic.characteristicId} serviceId:${serviceId} deviceId:$deviceId"); + qualifiedCharacteristic = QualifiedCharacteristic(characteristicId: discoveredCharacteristic.characteristicId, serviceId:serviceId , deviceId: deviceId); + } + } + } + } + } + subScribeToCharacteristic(QualifiedCharacteristic(characteristicId: getDiscoveredCharacteristic!.characteristicId, serviceId: Uuid.parse("fff0"), deviceId: deviceId)); + print('Discovering services finished'); + + EventBusManager().eventBusFir(qualifiedCharacteristic); + return result; + } on Exception catch (e) { + print('Error occurred when discovering services: $e'); + rethrow; + } + } + + // 听上报来的数据,参数来自前面扫描到的结果 + subScribeToCharacteristic(QualifiedCharacteristic characteristic) { + print('Subscribing to characteristicId: ${characteristic.characteristicId} serviceId:${characteristic.serviceId} deviceId:${characteristic.deviceId}'); + _flutterReactiveBle!.subscribeToCharacteristic(characteristic).listen((data) { + // code to handle incoming data + print("subscribeToCharacteristic: deviceId = ${characteristic.deviceId} characteristicId =${characteristic.characteristicId}---上报来的数据data = $data"); + + }, onError: (dynamic error) { + print("subscribeToCharacteristic error:$error"); + }); + // return _ble.subscribeToCharacteristic(characteristic); + } + + // 写入 + Future writeCharacteristicWithResponse(QualifiedCharacteristic characteristic, List value) async { + print('Write with characteristicId:${characteristic.characteristicId} serviceId:${characteristic.serviceId} deviceId:${characteristic.deviceId} value : $value'); + try { + // await _flutterReactiveBle!.writeCharacteristicWithResponse(characteristic, value: value).onError((error, stackTrace){ + // print("writeCharacteristicWithResponse:$characteristic $value, error:$error stackTrace:$stackTrace}"); + // }); + + List oneList = []; + List twoList = []; + List threeList = []; + int ctn = getPackageCount(value, averageLen: _limitLen); + for (int i = 1; i <= ctn; i++){ + List subData = getSubData(index: i, average: _limitLen, data: value); + print("i:$i ctn:$ctn subData:$subData"); + print('Write with characteristicId:${characteristic.characteristicId} serviceId:${characteristic.serviceId} deviceId:${characteristic.deviceId} value : $subData'); + + switch (i) { + case 1: + { + oneList.addAll(subData); + } + break; + case 2: + { + twoList.addAll(subData); + } + break; + case 3: + { + threeList.addAll(subData); + } + break; + default: + } + + // await Future.delayed(Duration( + // milliseconds: i == ctn ? 0 : _sleepTimes, + // ),(){ + // // i++; + // }); + } + + print("oneList:$oneList"); + _flutterReactiveBle!.writeCharacteristicWithResponse(characteristic, value: oneList).onError((error, stackTrace){ + // print("writeCharacteristicWithResponse:$characteristic $subData, error:$error stackTrace:$stackTrace}"); + }); + + await Future.delayed(const Duration(milliseconds: 100,),(){ + print("twoList:$twoList"); + _flutterReactiveBle!.writeCharacteristicWithResponse(characteristic, value: twoList).onError((error, stackTrace){ + // print("writeCharacteristicWithResponse:$characteristic $subData, error:$error stackTrace:$stackTrace}"); + }); + }); + + await Future.delayed(const Duration(milliseconds: 100,),(){ + print("threeList:$threeList"); + _flutterReactiveBle!.writeCharacteristicWithResponse(characteristic, value: threeList).onError((error, stackTrace){ + // print("writeCharacteristicWithResponse:$characteristic $subData, error:$error stackTrace:$stackTrace}"); + }); + }); + + // _flutterReactiveBle!.writeCharacteristicWithResponse(characteristic, value: subData).onError((error, stackTrace){ + // // print("writeCharacteristicWithResponse:$characteristic $subData, error:$error stackTrace:$stackTrace}"); + // }); + + // while(i <= ctn) { + // print("object$i "); + // List subData = getSubData(index: i, average: _limitLen, data: value); + // print('Write with characteristicId:${characteristic.characteristicId} serviceId:${characteristic.serviceId} deviceId:${characteristic.deviceId} value : $subData'); + // await _flutterReactiveBle!.writeCharacteristicWithResponse(characteristic, value: subData).onError((error, stackTrace){ + // // print("writeCharacteristicWithResponse:$characteristic $subData, error:$error stackTrace:$stackTrace}"); + // }); + // await Future.delayed(Duration( + // milliseconds: i == ctn ? 0 : _sleepTimes, + // ),(){ + // i++; + // }); + // } + // i = 1; + // await readCharacteristic(characteristic); + + } on Exception catch (e, s) { + print('Error occurred when writing: $e',); + // ignore: avoid_print + print(s); + rethrow; + } + } + + // 读取 + Future> readCharacteristic(QualifiedCharacteristic characteristic) async { + try { + final result = await _flutterReactiveBle!.readCharacteristic(characteristic); + print("readListresult$result"); + return result; + } on Exception catch (e, s) { + print('Error occurred when reading ${characteristic.characteristicId} : $e',); + rethrow; + } + } + + + Future writeCharacteristicWithoutResponse( + QualifiedCharacteristic characteristic, List value) async { + try { + await _flutterReactiveBle!.writeCharacteristicWithoutResponse(characteristic, + value: value); + } on Exception catch (e, s) { + // ignore: avoid_print + print(s); + rethrow; + } + } + +} \ No newline at end of file diff --git a/star_lock/lib/command/io_protocol/io_addUser.dart b/star_lock/lib/blue/io_protocol/io_addUser.dart similarity index 75% rename from star_lock/lib/command/io_protocol/io_addUser.dart rename to star_lock/lib/blue/io_protocol/io_addUser.dart index b815c8b2..17b1fa2f 100644 --- a/star_lock/lib/command/io_protocol/io_addUser.dart +++ b/star_lock/lib/blue/io_protocol/io_addUser.dart @@ -51,16 +51,10 @@ class AddUserCommand extends SenderProtocol { } } -class RemoteControlReply extends Reply { - RemoteControlReply.parseData(CommandType commandType, List dataDetail, int endIndex) - : super.parseData(commandType, dataDetail, endIndex) { +class AddUserReply extends Reply { + AddUserReply.parseData(CommandType commandType, List dataDetail) + : super.parseData(commandType, dataDetail) { int index = 0; - while(index < endIndex){ - commandKey = byteUInt8(dataDetail, index); - index += offset_1!; - switch(commandKey){ - } - } } } \ No newline at end of file diff --git a/star_lock/lib/blue/io_protocol/io_getPublicKey.dart b/star_lock/lib/blue/io_protocol/io_getPublicKey.dart new file mode 100644 index 00000000..524321e1 --- /dev/null +++ b/star_lock/lib/blue/io_protocol/io_getPublicKey.dart @@ -0,0 +1,41 @@ +import 'dart:convert'; + +import '../io_tool/io_tool.dart'; +import 'io_reply.dart'; +import 'io_sender.dart'; +import 'io_type.dart'; + +class GetPublicKeyCommand extends SenderProtocol { + + String? lockID; + GetPublicKeyCommand({ + this.lockID, + }) : super(CommandType.getLockPublicKey); + + @override + List messageDetail() { + List data = []; + print("lockID:${lockID!} lockID.utf8.encode${utf8.encode(lockID!)}"); + data.addAll(utf8.encode(lockID!)); + for(int i = 0; i<24; i++){ + data.add(0); + } + print("dataaaaaa:$data"); + return data; + } +} + +class GetPublicKeyReply extends Reply { + GetPublicKeyReply.parseData(CommandType commandType, List dataDetail) + : super.parseData(commandType, dataDetail) { + print('获取公钥'); + int index = 0; + // while(index < endIndex){ + // commandKey = byteUInt8(dataDetail, index); + // index += offset_1; + // switch(commandKey){ + // + // } + // } + } +} \ No newline at end of file diff --git a/star_lock/lib/command/io_protocol/io_openDoor.dart b/star_lock/lib/blue/io_protocol/io_openDoor.dart similarity index 74% rename from star_lock/lib/command/io_protocol/io_openDoor.dart rename to star_lock/lib/blue/io_protocol/io_openDoor.dart index b44b5782..bf4b1853 100644 --- a/star_lock/lib/command/io_protocol/io_openDoor.dart +++ b/star_lock/lib/blue/io_protocol/io_openDoor.dart @@ -44,16 +44,10 @@ class OpenDoorCommand extends SenderProtocol { } } -class RemoteControlReply extends Reply { - RemoteControlReply.parseData(CommandType commandType, List dataDetail, int endIndex) - : super.parseData(commandType, dataDetail, endIndex) { +class OpenDoorReply extends Reply { + OpenDoorReply.parseData(CommandType commandType, List dataDetail) + : super.parseData(commandType, dataDetail) { int index = 0; - while(index < endIndex){ - commandKey = byteUInt8(dataDetail, index); - index += offset_1!; - switch(commandKey){ - } - } } } \ No newline at end of file diff --git a/star_lock/lib/command/io_protocol/io_reply.dart b/star_lock/lib/blue/io_protocol/io_reply.dart similarity index 86% rename from star_lock/lib/command/io_protocol/io_reply.dart rename to star_lock/lib/blue/io_protocol/io_reply.dart index b4e449e3..02c7d482 100644 --- a/star_lock/lib/command/io_protocol/io_reply.dart +++ b/star_lock/lib/blue/io_protocol/io_reply.dart @@ -14,7 +14,7 @@ abstract class Reply{ //command key flag int commandKey = 0; - Reply.parseData(this.commandType,List dataDetail,int endIndex); + Reply.parseData(this.commandType, List dataDetail); Reply({this.result}); diff --git a/star_lock/lib/blue/io_protocol/io_sender.dart b/star_lock/lib/blue/io_protocol/io_sender.dart new file mode 100644 index 00000000..e28adf52 --- /dev/null +++ b/star_lock/lib/blue/io_protocol/io_sender.dart @@ -0,0 +1,146 @@ +import 'dart:typed_data'; + +import '../io_tool/io_manager.dart'; +import '../io_tool/io_tool.dart'; +import 'io_type.dart'; + +abstract class IOData { + List messageDetail(); +} + +abstract class SenderProtocol extends IOData { + // var uint8View1 = Uint8List(300); + + CommandType? commandType; //指令类型 + final List header = [0XEF, 0X01, 0XEE, 0X02]; //帧头 固定取值 0XEF01EE02,长度 4 字节 + final int ask = 0X01 ; // 包类型:0X01 表示请求包,0X11 表示应答包,长度 1 字节 + int? _commandIndex = 1; //包序号 + final int identifier = 0x20; // 高 4 位表示包版本,低 4 位用来指示后面数据的加密类型,长度为 1 字节,加密类型取值说明,0:明文,1:AES128,2:SM4(事先约定密钥),3:SM4(设备指定密钥) + + List? commandData = []; //数据块 + // final int? tail = 0xFF; //用来校验包的完整性,采用 CRC 校验方法,长度为 2 个字节 + + SenderProtocol(this.commandType) { + _commandIndex = IoManager().commandIndex; + } + + //TODO:拼装数据 + List packageData() { + commandData = messageDetail(); + List commandList = []; + + // 帧头 + commandList.addAll(header); + print("header:$header"); + + //包类型 + commandList.add(ask); //包类型 + print("ask:$ask"); + + // 包序号 + int commandIndexChange = _commandIndex!; + double commandIndexChangeDouble = commandIndexChange/256; + int commandIndexChang1 = commandIndexChangeDouble.toInt(); + int commandIndexChang2 = commandIndexChange%256; + commandList.add(commandIndexChang1); + commandList.add(commandIndexChang2); + print("_commandIndex:$_commandIndex commandIndexChang1$commandIndexChang1 commandIndexChang2:$commandIndexChang2"); + + // 包标识 + commandList.add(identifier); + print("identifier:$identifier"); + + // 数据长度 + // int dataLength = dataSourceLength(); + // commandList.add(dataLength); + // print("dataLength:$dataLength"); + var dataLen = 42; + double dataLength = dataLen/256; + commandList.add(dataLength.toInt()); + commandList.add(42%256); + commandList.add(dataLength.toInt()); + commandList.add(42%256); + + // 指令类型 + int type = commandType!.typeValue; + double typeDouble = type/256; + int type1 = typeDouble.toInt(); + int type2 = type%256; + commandList.add(type1); + commandList.add(type2); + print("type:$type"); + print("type1:$type1"); + print("type2:$type2"); + + // 数据块 + commandList.addAll(commandData!); //数据块 + print("commandData:$commandData"); + + // 校验位 + var mcrc = crc_16(commandList); + double mcrcDouble = mcrc/256; + int mcrcDouble1 = mcrcDouble.toInt(); + int mcrcDouble2 = mcrc%256; + commandList.add(mcrcDouble1); //帧尾 + commandList.add(mcrcDouble2); + print("mcrc:$mcrc"); + print("mcrcDouble1:$mcrcDouble1"); + print("mcrcDouble2:$mcrcDouble2"); + return commandList; + } + + //TODO:长度 + int dataSourceLength() => commandData!.length; + + var crcTable =[ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0]; + + int crc_16(buffer) { + var len = buffer.length; + var value_ = 0x0000;//0xa635; //初始值,根据CRC类型设定 + var tmp; + for (var i = 0; i < buffer.length; i++) + { + tmp = reverse8(buffer[i]); + value_ = ((value_ << 8) ^ crcTable[((value_ >> 8) ^ tmp) & 0xFF]) & 0xFFFF; + } + value_ = reverse16(value_); + return value_; + } + + int reverse8(data) { + var i; + var temp=0; + for(i=0;i<8;i++) { + //字节反转 + temp |= ((data>>i) & 0x01)<<(7-i); + } + return temp; + } + + int reverse16(data) { + var i; + var temp=0; + for(i=0;i<16;i++) { + //反转 + temp |= ((data>>i) & 0x0001)<<(15-i); + } + return temp; + } + +} \ No newline at end of file diff --git a/star_lock/lib/command/io_protocol/io_type.dart b/star_lock/lib/blue/io_protocol/io_type.dart similarity index 100% rename from star_lock/lib/command/io_protocol/io_type.dart rename to star_lock/lib/blue/io_protocol/io_type.dart diff --git a/star_lock/lib/command/io_tool/io_manager.dart b/star_lock/lib/blue/io_tool/io_manager.dart similarity index 94% rename from star_lock/lib/command/io_tool/io_manager.dart rename to star_lock/lib/blue/io_tool/io_manager.dart index 46928819..8d8c8283 100644 --- a/star_lock/lib/command/io_tool/io_manager.dart +++ b/star_lock/lib/blue/io_tool/io_manager.dart @@ -21,7 +21,7 @@ class IoManager { ///蓝牙传输协议 void bleTransmission() => _dataTransmissionMode = DataTransmissionMode.ble; - int _commandIndex = 0; //割草机协议帧序号 + int _commandIndex = 1; //割草机协议帧序号 configCommandIdx(int idx) => _commandIndex = idx; Future increaseCommandIndex() async { _commandIndex < 255 ? _commandIndex++ : _commandIndex = 0; diff --git a/star_lock/lib/command/io_tool/io_model.dart b/star_lock/lib/blue/io_tool/io_model.dart similarity index 81% rename from star_lock/lib/command/io_tool/io_model.dart rename to star_lock/lib/blue/io_tool/io_model.dart index 391a2bc0..2c8f64cb 100644 --- a/star_lock/lib/command/io_tool/io_model.dart +++ b/star_lock/lib/blue/io_tool/io_model.dart @@ -1,4 +1,6 @@ +import 'package:uuid/uuid.dart'; + ///发送数据类 enum DataChannel{ ble @@ -9,10 +11,15 @@ extension Extension on DataChannel { } class EventSendModel { - List? data = []; + List data = []; String? topic = ''; DataChannel? sendChannel; - EventSendModel({required this.data,this.topic,this.sendChannel}); + + String? deviceId; + Uuid? serviceId; + Uuid? characteristicId; + + EventSendModel({required this.data,this.topic,this.sendChannel, this.deviceId, this.serviceId, this.characteristicId}); } ///接收数据类 diff --git a/star_lock/lib/command/io_tool/io_tool.dart b/star_lock/lib/blue/io_tool/io_tool.dart similarity index 83% rename from star_lock/lib/command/io_tool/io_tool.dart rename to star_lock/lib/blue/io_tool/io_tool.dart index 871c8899..45e2a442 100644 --- a/star_lock/lib/command/io_tool/io_tool.dart +++ b/star_lock/lib/blue/io_tool/io_tool.dart @@ -3,6 +3,32 @@ import 'dart:typed_data'; import 'package:flutter/services.dart'; +//int ---> 指定长度的hex (如指定长度为6的情况,0x000001 0x001234, 0xefab23) +String intToFormatHex(int num) { + String hexString = num.toRadixString(16); + print("hexString=$hexString"); + String formatString = hexString.padLeft(6, "0"); + print("formatHexString=$formatString"); + return formatString; +} + +String uint8ToHex(Uint8List byteArr) { + if (byteArr.isEmpty) { + return ""; + } + Uint8List result = Uint8List(byteArr.length << 1); + var hexTable = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']; //16进制字符表 + for (var i = 0; i < byteArr.length; i++) { + var bit = byteArr[i]; //取传入的byteArr的每一位 + var index = bit >> 4 & 15; //右移4位,取剩下四位 + var i2 = i << 1; //byteArr的每一位对应结果的两位,所以对于结果的操作位数要乘2 + result[i2] = hexTable[index].codeUnitAt(0); //左边的值取字符表,转为Unicode放进resut数组 + index = bit & 15; //取右边四位 + result[i2 + 1] = hexTable[index].codeUnitAt(0); //右边的值取字符表,转为Unicode放进resut数组 + } + return String.fromCharCodes(result); //Unicode转回为对应字符,生成字符串返回 +} + //TODO:int->两个字节 List 低字节在前,高字节在后(大端存储)=>嵌入式小端接收(协议用到) int byteInt8(List dataDetail, int index)=>_toInt8(dataDetail[index]); @@ -138,7 +164,7 @@ List getSubData({ required int average, required List data }){ - if(data == null || data.length == 0){ + if(data.isEmpty){ return []; } int totalLength = data.length; diff --git a/star_lock/lib/command/io_tool/manager_event_bus.dart b/star_lock/lib/blue/io_tool/manager_event_bus.dart similarity index 100% rename from star_lock/lib/command/io_tool/manager_event_bus.dart rename to star_lock/lib/blue/io_tool/manager_event_bus.dart diff --git a/star_lock/lib/blue/reciver_data.dart b/star_lock/lib/blue/reciver_data.dart new file mode 100644 index 00000000..5c101747 --- /dev/null +++ b/star_lock/lib/blue/reciver_data.dart @@ -0,0 +1,123 @@ + + +import 'io_protocol/io_addUser.dart'; +import 'io_protocol/io_getPublicKey.dart'; +import 'io_protocol/io_openDoor.dart'; +import 'io_protocol/io_reply.dart'; +import 'io_protocol/io_type.dart'; +import 'io_tool/io_tool.dart'; +import 'io_tool/manager_event_bus.dart'; + +class CommandReciverManager { + + static Future parseRobot(List data) async { + int commandIdx = data[1]; + int len = data.length; + var dataDetail = data.sublist(4,len -2); + int ioType = data[3]; + CommandType commandType = ExtensionCommandType.getCommandType(ioType); + + int endIndex = dataDetail.length - 1; + var reply; + switch(commandType) { + case CommandType.getLockPublicKey: + { + reply = GetPublicKeyReply.parseData(commandType, dataDetail); + } + break; + case CommandType.addUser: + { + reply = AddUserReply.parseData(commandType, dataDetail); + } + break; + case CommandType.openDoor: + { + reply = OpenDoorReply.parseData(commandType, dataDetail); + } + break; + } + return reply; + } + + + static int _bufSize = 0; + static int _index = 0; + static int _remainSize = 0; + static int _maxBufferSize = 260; + + static List _buffer = []; + + static void _clearBuffer(){ + _buffer = []; + _index = 0; + _bufSize = 0; + } + + static void appDataReceive(List data,{bool clear = false}) async { + ///解析数据 + if(clear){ + _clearBuffer(); + } + int data_size = data.length; + if(data_size > _maxBufferSize){ + return; + } + if(_bufSize+data_size > _maxBufferSize){ + _index = 0; + _bufSize = 0; + } + if(_index+_bufSize+data_size > _maxBufferSize){ + _buffer = _buffer.sublist(_index,_index + _bufSize); + _index = 0; + } + _buffer.addAll(data); + _bufSize += data.length; + int error; + // print('✅ 执行开始 _buffer:${_buffer.length}'); + do { + error = await appCheckProtocol(_buffer.sublist(_index),_bufSize); + // print('⚠️ $error'); + switch(error){ + case 0: + { + int protocolLen = _bufSize - _remainSize; + List tempData = _buffer.sublist(_index,_index + protocolLen); + _index += (_bufSize - _remainSize); + _bufSize = _remainSize; + if(tempData.isNotEmpty){ + parseRobot(tempData).then((value){ + EventBusManager().eventBusFir(value); + }); + } + } + break; + case 1: + break; + case 2: + { + ++_index; + --_bufSize; + } + break; + default: + error = 1; + break; + } + }while(error != 1); + // print('✅ 执行结束 _buffer:${_buffer.length}'); + } + + static Future appCheckProtocol(List data,int size) async{ + if(size < 7) return 1; + if(data[0] != 0xFA) return 2; + int payloadSize = data[2]; + if(payloadSize == 0) return 2; + int protocolSize = payloadSize +5; + if(size < protocolSize) return 1; + if(data[protocolSize-1] != 0xFF) return 2; + if(data[protocolSize-2] != checkSum(data.sublist(0,protocolSize - 2))) return 2; + _remainSize = size - protocolSize; + return 0; + } + +} \ No newline at end of file diff --git a/star_lock/lib/command/sender_data.dart b/star_lock/lib/blue/sender_data.dart similarity index 94% rename from star_lock/lib/command/sender_data.dart rename to star_lock/lib/blue/sender_data.dart index 8d9eee15..a1e670cd 100644 --- a/star_lock/lib/command/sender_data.dart +++ b/star_lock/lib/blue/sender_data.dart @@ -27,7 +27,7 @@ class CommandSenderManager { void managerSendData ({ required SenderProtocol command, CommandSendCallBack? callBack}) { - if (callBack != null && command.commandType != CommandType.readLockStatusInfo) { + if (callBack != null) { // if (!BluetoothManager().connected) { print('❌ 蓝牙断开了'); if (callBack != null) { @@ -39,12 +39,13 @@ class CommandSenderManager { } List value = command.packageData(); + // print("sendData:${value}"); _sendNormalData(value); - // startCommandCutDown(command.commandType, value, callBack); } void _sendNormalData(List data) async { - if (data != null && data.isNotEmpty) { + print("lllllll:${data}"); + if (data.isNotEmpty) { EventBusManager().eventBusFir(EventSendModel(data: data, sendChannel: DataChannel.ble)); } } diff --git a/star_lock/lib/blue/sender_manage.dart b/star_lock/lib/blue/sender_manage.dart new file mode 100644 index 00000000..fee15cdc --- /dev/null +++ b/star_lock/lib/blue/sender_manage.dart @@ -0,0 +1,51 @@ + +import 'io_protocol/io_addUser.dart'; +import 'io_protocol/io_getPublicKey.dart'; +import 'io_protocol/io_openDoor.dart'; +import 'sender_data.dart'; + +class IoSenderManage { + + //todo:获取公钥 + static void getPublicKey(String lockId ,{CommandSendCallBack? callBack}) { + CommandSenderManager().managerSendData(command: GetPublicKeyCommand( + lockID: lockId, + ), callBack:callBack); + } + + //todo:添加用户 + // static void senderAddUser({CommandSendCallBack? callBack}) { + // CommandSenderManager().managerSendData( + // command: AddUserCommand( + // cmdID: 0, + // lockID: "", + // authUserID: "", + // keyID: "", + // userID: "", + // openMode: 0, + // keyType: 0, + // startDate: 0, + // expireDate: 0, + // role: 0, + // password: "", + // token: 0, + // authCodeLen: 0, + // authCode: "", + // ), callBack:callBack); + // } + + //todo:开锁 + // static void senderOpenDoor({CommandSendCallBack? callBack}) { + // CommandSenderManager().managerSendData( + // command: OpenDoorCommand( + // cmdID: 0, + // keyID: "", + // userID: "", + // openMode: 0, + // openTime: 0, + // token: 0, + // authCodeLen: 0, + // authCode: "", + // ), callBack:callBack); + // } +} \ No newline at end of file diff --git a/star_lock/lib/command/io_protocol/io_sender.dart b/star_lock/lib/command/io_protocol/io_sender.dart deleted file mode 100644 index fcdedff0..00000000 --- a/star_lock/lib/command/io_protocol/io_sender.dart +++ /dev/null @@ -1,49 +0,0 @@ -import '../io_tool/io_manager.dart'; -import '../io_tool/io_tool.dart'; -import 'io_type.dart'; - -abstract class IOData { - List messageDetail(); -} - -abstract class SenderProtocol extends IOData { - - CommandType? commandType; //指令类型 - final int header = 0XEF01EE02; //帧头 固定取值 0XEF01EE02,长度 4 字节 - final int ask = 0X01 ; // 包类型:0X01 表示请求包,0X11 表示应答包,长度 1 字节 - int? _commandIndex; //帧序号 - final int identifier = 0x22 ; // 高 4 位表示包版本,低 4 位用来指示后面数据的加密类型,长度为 1 字节,加密类型取值说明,0:明文,1:AES128,2:SM4(事先约定密钥),3:SM4(设备指定密钥) - - List? commandData = []; //数据域 - final int? tail = 0xFF; //用来校验包的完整性,采用 CRC 校验方法,长度为 2 个字节 - - SenderProtocol(this.commandType) { - _commandIndex = IoManager().commandIndex; - } - - //TODO:拼装数据 - List packageData() { - commandData = messageDetail(); - List commandList = []; - commandList.add(header); //帧头 - commandList.add(_commandIndex!); //帧序号 - commandList.addAll(intToInt8List(dataSourceLength())); - int type = commandType!.typeValue; - commandList.addAll(intToInt8List(type)); //指令类型 - commandList.addAll(commandData!); //数据域 - commandList.add(checkSum(commandList)); //校验和 - commandList.add(tail!); //帧尾 - - //帧头 - // commandList.add(0xEF); - // commandList.add(0x01); - // commandList.add(0xEE); - // commandList.add(0x02); - - return commandList; - } - - //TODO:校验和 - int dataSourceLength() => commandData!.length; - -} \ No newline at end of file diff --git a/star_lock/lib/command/reciver_data.dart b/star_lock/lib/command/reciver_data.dart deleted file mode 100644 index 1a8a2960..00000000 --- a/star_lock/lib/command/reciver_data.dart +++ /dev/null @@ -1,6 +0,0 @@ - - -class CommandReciverManager { - - -} \ No newline at end of file diff --git a/star_lock/lib/command/sender_manage.dart b/star_lock/lib/command/sender_manage.dart deleted file mode 100644 index 7bd419b7..00000000 --- a/star_lock/lib/command/sender_manage.dart +++ /dev/null @@ -1,44 +0,0 @@ - -import 'package:star_lock/command/sender_data.dart'; - -import 'io_protocol/io_addUser.dart'; -import 'io_protocol/io_openDoor.dart'; - -class IoSenderManage { - - //todo:添加用户 - static void senderAddUser({CommandSendCallBack? callBack}) { - CommandSenderManager().managerSendData( - command: AddUserCommand( - cmdID: 0, - lockID: "", - authUserID: "", - keyID: "", - userID: "", - openMode: 0, - keyType: 0, - startDate: 0, - expireDate: 0, - role: 0, - password: "", - token: 0, - authCodeLen: 0, - authCode: "", - ), callBack:callBack); - } - - //todo:开锁 - static void senderOpenDoor({CommandSendCallBack? callBack}) { - CommandSenderManager().managerSendData( - command: OpenDoorCommand( - cmdID: 0, - keyID: "", - userID: "", - openMode: 0, - openTime: 0, - token: 0, - authCodeLen: 0, - authCode: "", - ), callBack:callBack); - } -} \ No newline at end of file diff --git a/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_logic.dart b/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_logic.dart index 521155bd..3d3df89f 100644 --- a/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_logic.dart +++ b/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_logic.dart @@ -5,50 +5,91 @@ import 'package:flutter_reactive_ble/flutter_reactive_ble.dart'; import 'package:get/get.dart'; import 'package:star_lock/tools/baseGetXController.dart'; +import '../../../blue/blue_manage.dart'; +import '../../../blue/io_tool/io_model.dart'; +import '../../../blue/io_tool/manager_event_bus.dart'; +import '../../../blue/sender_manage.dart'; import '../../../tools/reactiveBlueTool/getx_ble.dart'; import 'nearbyLock_state.dart'; class NearbyLockLogic extends BaseGetXController{ - // StreamSubscription? _streamSubscription; - // StreamSubscription? _connectionStreamSubscription; - // final flutterReactiveBle = FlutterReactiveBle(); - // List deviceList = []; - final NearbyLockState state = NearbyLockState(); - final logicGetxBle = Get.put(GetxBle()); - final StreamController _stateStreamController = StreamController(); - late StreamSubscription _streamSubscription; - void _initScheduleSubscription() { - _streamSubscription= _stateStreamController.stream.listen((BleScannerState) { - print("页面B接收到数据 $BleScannerState"); + // 点击复合要求的设备之后 连接 + void connect(String lockId){ + BlueManage().connect(lockId); + } + + // 监听蓝牙连接的状态 + late StreamSubscription _streamSubscription; + void _startListenIO(){ + _streamSubscription = EventBusManager().eventBus!.on().listen((event) async { + IoSenderManage.getPublicKey(state.seletLockName.value); }); + } + // 状态在线之后发现服务 + // Future scanDiscoverServices(String lockId) async { + // // 获取特征值 处理特征值 + // List list = await BlueManage().discoverServices(lockId); + // // 发送获取公钥 + // IoSenderManage.getPublicKey(state.seletLockName.value); + // } + + // 获取公钥 + // void getPublicKey(String lockId){ + // // print("seletGetPublicKey:${lockId}"); + // IoSenderManage.getPublicKey(lockId); + // } + + // 组装好数据后监听要发送消息的事件 + late StreamSubscription _sendStreamSubscription; + void _initSendStreamSubscription() { + _sendStreamSubscription = EventBusManager().eventBus!.on().listen(( + EventSendModel model) { + if (model.sendChannel == DataChannel.ble) { + print("fsdfgsdfgsdfgsdfgsdfgsdfg:${BlueManage().qualifiedCharacteristic}"); + BlueManage().writeCharacteristicWithResponse(QualifiedCharacteristic( + deviceId:BlueManage().qualifiedCharacteristic!.deviceId, + characteristicId: BlueManage().qualifiedCharacteristic!.characteristicId, + serviceId: BlueManage().serviceId), + model.data); + } + }); } @override void onReady() { // TODO: implement onReady super.onReady(); - _initScheduleSubscription(); + print("onReady()"); + + _initSendStreamSubscription(); + _startListenIO(); } @override void onInit() { // TODO: implement onInit super.onInit(); - logicGetxBle.scanner.startScan((List devices){ - // print("zzzzzzzzz:$devices"); - // print("ccccccccc:${state.devices}"); - bool isHave = state.devices.any((element) => element.id == devices[0].id); - if (isHave == false){ - state.devices.addAll(devices); - } + print("onInit()"); + // 进来第一步开始扫描 + GetxBle().scanner.startScan((v){ + bool isHave = state.devices.any((element) => element.id == v[0].id); + if (isHave == false){ + state.devices.addAll(v); + } }); } + @override + void onClose() { + // TODO: implement onClose + super.onClose(); + _sendStreamSubscription.cancel(); + } } diff --git a/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_page.dart b/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_page.dart index 066b04b2..3810c9f7 100644 --- a/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_page.dart +++ b/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_page.dart @@ -1,4 +1,7 @@ +import 'dart:convert'; +import 'dart:typed_data'; + import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_reactive_ble/flutter_reactive_ble.dart'; @@ -23,6 +26,22 @@ class _NearbyLockPageState extends State { @override Widget build(BuildContext context) { + + // var uint8View1 = Uint8List(300); + // uint8View1[0] = 0xEF; + // uint8View1[1] = 0x01; + // uint8View1[2] = 0xEE; + // uint8View1[3] = 0x02; + // // String bar = utf8.decode(uint8View1); + // print("barrrrr:$uint8View1"); + // + // for(int i = 0; i { itemCount: state.devices.length, itemBuilder: (c, index) { return nearbyLockItem('images/icon_lockGroup_item.png', state.devices[index], () { - Navigator.pushNamed(context, Routers.lockAddressPage); + // Navigator.pushNamed(context, Routers.lockAddressPage); + // logic.getPublicKey(state.devices[index].serviceUuids[0].toString()); + state.seletLockName.value = state.devices[index].name; + logic.connect(state.devices[index].id); }); }, separatorBuilder: (BuildContext context, int index) { @@ -107,8 +129,6 @@ class _NearbyLockPageState extends State { void dispose() { // TODO: implement dispose super.dispose(); - - logic.logicGetxBle.scanner.stopScan(); } - + } diff --git a/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_state.dart b/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_state.dart index 522a73b4..92afceec 100644 --- a/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_state.dart +++ b/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_state.dart @@ -1,9 +1,11 @@ +import 'dart:typed_data'; + import 'package:flutter_reactive_ble/flutter_reactive_ble.dart'; import 'package:get/get.dart'; class NearbyLockState { var devices = [].obs; - + var seletLockName = "".obs; } \ No newline at end of file diff --git a/star_lock/lib/tools/reactiveBlueTool/ble_device_connector.dart b/star_lock/lib/tools/reactiveBlueTool/ble_device_connector.dart index 338f4e0f..da7eda9e 100644 --- a/star_lock/lib/tools/reactiveBlueTool/ble_device_connector.dart +++ b/star_lock/lib/tools/reactiveBlueTool/ble_device_connector.dart @@ -2,6 +2,8 @@ import 'dart:async'; import 'package:flutter_reactive_ble/flutter_reactive_ble.dart'; import 'package:get/get.dart'; +import '../../blue/io_tool/manager_event_bus.dart'; + class BleDeviceConnector extends GetxController { BleDeviceConnector({ required FlutterReactiveBle ble, @@ -26,12 +28,15 @@ class BleDeviceConnector extends GetxController { late StreamSubscription _connection; Future connect(String deviceMAC) async { + print("connect:$deviceMAC"); _logMessage('Start connecting to $deviceMAC'); _connection = _ble.connectToDevice(id: deviceMAC).listen( (update) { - _logMessage( - 'ConnectionState for device $deviceMAC : ${update.connectionState}'); - _deviceConnectionController.add(update); + print('ConnectionState for device $deviceMAC : ${update.connectionState}'); + // _logMessage( + // 'ConnectionState for device $deviceMAC : ${update.connectionState}'); + // _deviceConnectionController.add(update); + EventBusManager().eventBusFir(update); }, onError: (Object e) => _logMessage('Connecting to device $deviceMAC resulted in error $e'), @@ -46,13 +51,18 @@ class BleDeviceConnector extends GetxController { _logMessage("Error disconnecting from a device: $e"); } finally { // Since [_connection] subscription is terminated, the "disconnected" state cannot be received and propagated - _deviceConnectionController.add( - ConnectionStateUpdate( - deviceId: deviceMAC, - connectionState: DeviceConnectionState.disconnected, - failure: null, - ), - ); + EventBusManager().eventBusFir(ConnectionStateUpdate( + deviceId: deviceMAC, + connectionState: DeviceConnectionState.disconnected, + failure: null, + )); + // _deviceConnectionController.add( + // ConnectionStateUpdate( + // deviceId: deviceMAC, + // connectionState: DeviceConnectionState.disconnected, + // failure: null, + // ), + // ); } } diff --git a/star_lock/lib/tools/reactiveBlueTool/ble_device_interactor.dart b/star_lock/lib/tools/reactiveBlueTool/ble_device_interactor.dart index e4e64501..1a599eb5 100644 --- a/star_lock/lib/tools/reactiveBlueTool/ble_device_interactor.dart +++ b/star_lock/lib/tools/reactiveBlueTool/ble_device_interactor.dart @@ -1,7 +1,10 @@ import 'dart:async'; +import 'dart:core'; import 'package:flutter_reactive_ble/flutter_reactive_ble.dart'; import 'package:get/get.dart'; +import '../../blue/io_tool/io_tool.dart'; + class BleDeviceInteractor extends GetxController { BleDeviceInteractor({ required FlutterReactiveBle ble, @@ -10,13 +13,30 @@ class BleDeviceInteractor extends GetxController { _logMessage = logMessage; final FlutterReactiveBle _ble; - final void Function(String message) _logMessage; + // 扫描服务,并过滤服务 Future> discoverServices(String deviceId) async { try { _logMessage('Start discovering services for: $deviceId'); - final result = await _ble.discoverServices(deviceId); + List result = await _ble.discoverServices(deviceId); + print("mmmmmmmmm$result"); + if(result.isNotEmpty){ + for (var i = 0; i < result.length; i++) { + for (var j = 0; j < result[i].characteristicIds.length; j++) { + print("hhhhhhhhhh${result[i].characteristicIds[j].toString()}"); + if (result[i].characteristicIds[j].toString() == "fff1") { + print("1111111111111111${result[i].characteristicIds[j].toString()}"); + _subScribeToCharacteristic(QualifiedCharacteristic(characteristicId: result[i].characteristicIds[j], serviceId: result[i].serviceId, deviceId: deviceId)); + } + if (result[i].characteristicIds[j].toString() == "fff2") { + // cd02 = res.characteristics[i].uuid; + // characteristics02 = res.characteristics[i]; + // isConnected = true; + } + } + } + } _logMessage('Discovering services finished'); return result; } on Exception catch (e) { @@ -25,6 +45,22 @@ class BleDeviceInteractor extends GetxController { } } + // 听上报来的数据,参数来自前面扫描到的结果 + _subScribeToCharacteristic(QualifiedCharacteristic characteristic) { + _logMessage('Subscribing to: ${characteristic.characteristicId} '); + + print("22222222222222222222${characteristic}"); + _ble.subscribeToCharacteristic(characteristic).listen((data) { + // code to handle incoming data + print("zzzzzzzzzzzzz subscribeToCharacteristic: deviceId = ${characteristic.deviceId} characteristicId =${characteristic.characteristicId}---上报来的数据data = $data"); + + }, onError: (dynamic error) { + print("xxxxxxxxxxxxx:$error"); + }); + // return _ble.subscribeToCharacteristic(characteristic); + } + + // 读取 Future> readCharacteristic( QualifiedCharacteristic characteristic) async { try { @@ -41,16 +77,69 @@ class BleDeviceInteractor extends GetxController { } } + // 写入 Future writeCharacteristicWithResponse( QualifiedCharacteristic characteristic, List value) async { try { - _logMessage( - 'Write with response value : $value to ${characteristic.characteristicId}'); - await _ble.writeCharacteristicWithResponse(characteristic, value: value); + // _logMessage('Write with response value : $value to ${characteristic.characteristicId}'); + print('Write with response value : $value to ${characteristic.characteristicId}'); + // await _ble.writeCharacteristicWithResponse(characteristic, value: value); + List oneList = []; + List twoList = []; + List threeList = []; + int ctn = getPackageCount(value, averageLen: 20); + for (int i = 1; i <= ctn; i++){ + List subData = getSubData(index: i, average: 20, data: value); + print("i:$i ctn:$ctn subData:$subData"); + print('Write with characteristicId:${characteristic.characteristicId} serviceId:${characteristic.serviceId} deviceId:${characteristic.deviceId} value : $subData'); + + switch (i) { + case 1: + { + oneList.addAll(subData); + } + break; + case 2: + { + twoList.addAll(subData); + } + break; + case 3: + { + threeList.addAll(subData); + } + break; + default: + } + + // await Future.delayed(Duration( + // milliseconds: i == ctn ? 0 : _sleepTimes, + // ),(){ + // // i++; + // }); + } + + print("oneList:$oneList"); + _ble.writeCharacteristicWithResponse(characteristic, value: oneList).onError((error, stackTrace){ + // print("writeCharacteristicWithResponse:$characteristic $subData, error:$error stackTrace:$stackTrace}"); + }); + + await Future.delayed(const Duration(milliseconds: 80,),(){}); + + print("twoList:$twoList"); + _ble.writeCharacteristicWithResponse(characteristic, value: twoList).onError((error, stackTrace){ + // print("writeCharacteristicWithResponse:$characteristic $subData, error:$error stackTrace:$stackTrace}"); + }); + + await Future.delayed(const Duration(milliseconds: 80,),(){}); + + print("threeList:$threeList"); + _ble.writeCharacteristicWithResponse(characteristic, value: threeList).onError((error, stackTrace){ + // print("writeCharacteristicWithResponse:$characteristic $subData, error:$error stackTrace:$stackTrace}"); + }); } on Exception catch (e, s) { - _logMessage( - 'Error occurred when writing ${characteristic.characteristicId} : $e', - ); + _logMessage('Error occurred when writing ${characteristic.characteristicId} : $e',); + print('Error occurred when writing ${characteristic.characteristicId} : $e',); // ignore: avoid_print print(s); rethrow; @@ -73,10 +162,4 @@ class BleDeviceInteractor extends GetxController { rethrow; } } - - Stream> subScribeToCharacteristic( - QualifiedCharacteristic characteristic) { - _logMessage('Subscribing to: ${characteristic.characteristicId} '); - return _ble.subscribeToCharacteristic(characteristic); - } } diff --git a/star_lock/lib/tools/reactiveBlueTool/ble_scanner.dart b/star_lock/lib/tools/reactiveBlueTool/ble_scanner.dart index b7a623e3..96ec1269 100644 --- a/star_lock/lib/tools/reactiveBlueTool/ble_scanner.dart +++ b/star_lock/lib/tools/reactiveBlueTool/ble_scanner.dart @@ -4,7 +4,6 @@ import 'package:flutter_reactive_ble/flutter_reactive_ble.dart'; import 'package:get/get.dart'; import 'package:meta/meta.dart'; -// typedef ScanResultCallBack = Function(List devices); typedef ScanResultCallBack = void Function(List devices); /// 这个类负责开启和关闭蓝牙扫描器并输出扫描结果 class BleScanner extends GetxController { @@ -48,7 +47,7 @@ class BleScanner extends GetxController { } if (((device.serviceUuids.isNotEmpty ? device.serviceUuids[0] : "").toString().contains("758824")) && (device.rssi >= -100)) { - print("11111111111111111:${device}"); + // print("11111111111111111:${device}"); final knownDeviceIndex = _devices.indexWhere((d) => d.id == device.id); if (knownDeviceIndex >= 0) {