feat:完成 ota 升级调用,优化蓝牙传输速度

This commit is contained in:
anfe 2024-04-24 16:04:07 +08:00
parent c505fcd2f3
commit ad4f6c286f
18 changed files with 1262 additions and 307 deletions

View File

@ -769,7 +769,7 @@
"异常警告":"Abnormal warning",
"短信提醒":"SMS reminder",
"邮件提醒":"Email reminder",
"关锁":"关锁",
"功能":"功能",
"配件":"配件"
"关锁":"close lock",
"功能":"function",
"配件":"parts"
}

View File

@ -41,7 +41,41 @@ PODS:
- ReachabilitySwift
- device_info_plus (0.0.1):
- Flutter
- DKImagePickerController/Core (4.3.8):
- DKImagePickerController/ImageDataManager
- DKImagePickerController/Resource
- DKImagePickerController/ImageDataManager (4.3.8)
- DKImagePickerController/PhotoGallery (4.3.8):
- DKImagePickerController/Core
- DKPhotoGallery
- DKImagePickerController/Resource (4.3.8)
- DKPhotoGallery (0.0.17):
- DKPhotoGallery/Core (= 0.0.17)
- DKPhotoGallery/Model (= 0.0.17)
- DKPhotoGallery/Preview (= 0.0.17)
- DKPhotoGallery/Resource (= 0.0.17)
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Core (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Preview
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Model (0.0.17):
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Preview (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Resource
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Resource (0.0.17):
- SDWebImage
- SwiftyGif
- EMASRest (11.1.1.2)
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
- Flutter (1.0.0)
- flutter_blue_plus (0.0.1):
- Flutter
@ -95,12 +129,16 @@ PODS:
- permission_handler_apple (9.3.0):
- Flutter
- ReachabilitySwift (5.2.2)
- SDWebImage (5.19.1):
- SDWebImage/Core (= 5.19.1)
- SDWebImage/Core (5.19.1)
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- sqflite (0.0.3):
- Flutter
- FlutterMacOS
- SwiftyGif (5.4.5)
- system_settings (0.0.1):
- Flutter
- Toast (4.1.1)
@ -126,6 +164,7 @@ DEPENDENCIES:
- camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`)
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- Flutter (from `Flutter`)
- flutter_blue_plus (from `.symlinks/plugins/flutter_blue_plus/ios`)
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
@ -163,11 +202,15 @@ SPEC REPOS:
- AMap3DMap
- AMapFoundation
- AMapLocation
- DKImagePickerController
- DKPhotoGallery
- GoogleMaps
- ios-voice-processor
- JCore
- JPush
- ReachabilitySwift
- SDWebImage
- SwiftyGif
- Toast
- WechatOpenSDK-XCFramework
@ -194,6 +237,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/connectivity_plus/ios"
device_info_plus:
:path: ".symlinks/plugins/device_info_plus/ios"
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
Flutter:
:path: Flutter
flutter_blue_plus:
@ -261,7 +306,10 @@ SPEC CHECKSUMS:
camera_avfoundation: 8b8d780bcfb6a4a02b0fbe2b4bd17b5b71946e68
connectivity_plus: bf0076dd84a130856aa636df1c71ccaff908fa1d
device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed
DKImagePickerController: a7836546cfdfe014171694f643a7d575bc8ace7f
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
EMASRest: 8df6f87836767a9415ad5cc4af739bc9d215b475
file_picker: ce3938a0df3cc1ef404671531facef740d03f920
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
flutter_blue_plus: 4837da7d00cf5d441fdd6635b3a57f936778ea96
flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086
@ -284,8 +332,10 @@ SPEC CHECKSUMS:
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
ReachabilitySwift: 2128f3a8c9107e1ad33574c6e58e8285d460b149
SDWebImage: 40b0b4053e36c660a764958bff99eed16610acbb
shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
system_settings: 8f5cdbfa72c677fc8d665b863bcc20d393d87e9d
Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e
url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812

View File

@ -1,4 +1,3 @@
import 'dart:async';
import 'dart:io';
@ -12,7 +11,8 @@ import 'reciver_data.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
//
typedef ConnectStateCallBack = Function(BluetoothConnectionState connectionState);
typedef ConnectStateCallBack = Function(
BluetoothConnectionState connectionState);
typedef ScanDevicesCallBack = Function(List<ScanResult>);
class BlueManage {
@ -57,7 +57,8 @@ class BlueManage {
ScanResult? scanResult;
//
BluetoothConnectionState? bluetoothConnectionState = BluetoothConnectionState.disconnected;
BluetoothConnectionState? bluetoothConnectionState =
BluetoothConnectionState.disconnected;
BluetoothAdapterState? _adapterState = BluetoothAdapterState.unknown;
StreamSubscription<BluetoothAdapterState>? _adapterStateStateSubscription;
@ -80,6 +81,7 @@ class BlueManage {
void _initBlue() {
Get.log("蓝牙功能初始化监听");
FlutterBluePlus.setLogLevel(LogLevel.error, color: true);
_initSendStreamSubscription();
_initAdapterStateStateSubscription();
// _initListenscanResults();
@ -94,7 +96,8 @@ class BlueManage {
}
void _initAdapterStateStateSubscription() {
_adapterStateStateSubscription ??= FlutterBluePlus.adapterState.listen((state) {
_adapterStateStateSubscription ??=
FlutterBluePlus.adapterState.listen((state) {
_adapterState = state;
});
}
@ -142,14 +145,18 @@ class BlueManage {
_connectionStateSubscription?.cancel();
_connectionStateSubscription = null;
_connectionStateSubscription = bluetoothConnectDevice!.connectionState.listen((state) async {
_connectionStateSubscription =
bluetoothConnectDevice!.connectionState.listen((state) async {
bluetoothConnectionState = state;
print("蓝牙连接状态:$state");
});
}
void _initSendStreamSubscription() {
_sendStreamSubscription ??= EventBusManager().eventBus!.on<EventSendModel>().listen((EventSendModel model) {
_sendStreamSubscription ??= EventBusManager()
.eventBus!
.on<EventSendModel>()
.listen((EventSendModel model) {
if (model.sendChannel == DataChannel.ble) {
FlutterBluePlus.isSupported.then((isAvailable) async {
if (isAvailable) {
@ -157,9 +164,7 @@ class BlueManage {
//
writeCharacteristicWithResponse(model.data);
} else {
try {
} catch (e) {
try {} catch (e) {
print("Error Turning On:");
}
}
@ -172,7 +177,8 @@ class BlueManage {
}
///
Future<void> startScanSingle(String deviceName, int timeout, ScanDevicesCallBack scanDevicesCallBack) async {
Future<void> startScanSingle(String deviceName, int timeout,
ScanDevicesCallBack scanDevicesCallBack) async {
FlutterBluePlus.isSupported.then((isAvailable) async {
if (isAvailable) {
if (_adapterState == BluetoothAdapterState.on) {
@ -180,8 +186,10 @@ class BlueManage {
FlutterBluePlus.startScan(timeout: Duration(seconds: timeout));
Completer<dynamic> completer = Completer<dynamic>();
var subscription = FlutterBluePlus.scanResults.listen((results) {
print("startScanSingle扫描到的设备:$results");
bool isExit = results.any((element) => (element.device.platformName == deviceName) || (element.advertisementData.advName == deviceName));
// print("startScanSingle扫描到的设备:$results");
bool isExit = results.any((element) =>
(element.device.platformName == deviceName) ||
(element.advertisementData.advName == deviceName));
if (isExit) {
for (var scanResult in results) {
if (((scanResult.advertisementData.serviceUuids.isNotEmpty
@ -191,8 +199,11 @@ class BlueManage {
.contains("758824")) &&
(scanResult.rssi >= -100)) {
// id相同的元素
final knownDeviceIndex = scanDevices
.indexWhere((d) => (d.device.platformName == scanResult.device.platformName) || (d.advertisementData.advName == scanResult.advertisementData.advName));
final knownDeviceIndex = scanDevices.indexWhere((d) =>
(d.device.platformName ==
scanResult.device.platformName) ||
(d.advertisementData.advName ==
scanResult.advertisementData.advName));
// -1
if (knownDeviceIndex >= 0) {
scanDevices[knownDeviceIndex] = scanResult;
@ -231,7 +242,8 @@ class BlueManage {
}
///
Future<void> startScan(int timeout, ScanDevicesCallBack scanDevicesCallBack, {List<Guid>? idList}) async {
Future<void> startScan(int timeout, ScanDevicesCallBack scanDevicesCallBack,
{List<Guid>? idList}) async {
FlutterBluePlus.isSupported.then((isAvailable) async {
if (isAvailable) {
if (_adapterState == BluetoothAdapterState.on) {
@ -255,8 +267,11 @@ class BlueManage {
.contains("758824")) &&
(scanResult.rssi >= -100)) {
// id相同的元素
final knownDeviceIndex = scanDevices
.indexWhere((d) => (d.device.platformName == scanResult.device.platformName) || (d.advertisementData.advName == scanResult.advertisementData.advName));
final knownDeviceIndex = scanDevices.indexWhere((d) =>
(d.device.platformName ==
scanResult.device.platformName) ||
(d.advertisementData.advName ==
scanResult.advertisementData.advName));
// -1
if (knownDeviceIndex >= 0) {
scanDevices[knownDeviceIndex] = scanResult;
@ -294,7 +309,9 @@ class BlueManage {
}
/// List senderData,
Future<void> bludSendData(String deviceName, ConnectStateCallBack stateCallBack, {bool isAddEquipment = false}) async {
Future<void> bludSendData(
String deviceName, ConnectStateCallBack stateCallBack,
{bool isAddEquipment = false}) async {
FlutterBluePlus.isSupported.then((isAvailable) async {
if (isAvailable) {
if (_adapterState == BluetoothAdapterState.on) {
@ -321,33 +338,43 @@ class BlueManage {
}
///
Future<void> _connect(String deviceName, ConnectStateCallBack connectStateCallBack,
Future<void> _connect(
String deviceName, ConnectStateCallBack connectStateCallBack,
{bool isAddEquipment = false}) async {
connectDeviceName = deviceName;
List<ScanResult> devicesList = scanDevices;
//
bool isExistDevice = scanDevices.any((element) => element.device.platformName == connectDeviceName || element.advertisementData.advName == connectDeviceName);
bool isExistDevice = scanDevices.any((element) =>
element.device.platformName == connectDeviceName ||
element.advertisementData.advName == connectDeviceName);
if (isAddEquipment == false && isExistDevice == false) {
// startScan(10, (scanDevices){
startScanSingle(deviceName, 10, (List<ScanResult> scanDevices) {
print("扫描到的设备:$scanDevices");
devicesList = scanDevices;
_connectDevice(devicesList, deviceName, connectStateCallBack, isAddEquipment: isAddEquipment);
_connectDevice(devicesList, deviceName, connectStateCallBack,
isAddEquipment: isAddEquipment);
});
} else {
_connectDevice(devicesList, deviceName, connectStateCallBack, isAddEquipment: isAddEquipment);
_connectDevice(devicesList, deviceName, connectStateCallBack,
isAddEquipment: isAddEquipment);
}
}
Future<void> _connectDevice(
List<ScanResult> devicesList, String deviceName, ConnectStateCallBack connectStateCallBack,
Future<void> _connectDevice(List<ScanResult> devicesList, String deviceName,
ConnectStateCallBack connectStateCallBack,
{bool isAddEquipment = false}) async {
//
print("devicesList:$devicesList");
final knownDeviceIndex = devicesList.indexWhere((d) => (d.device.platformName == deviceName) || (d.advertisementData.advName == deviceName));
final knownDeviceIndex = devicesList.indexWhere((d) =>
(d.device.platformName == deviceName) ||
(d.advertisementData.advName == deviceName));
if (knownDeviceIndex >= 0) {
//
connectDeviceMacAddress = devicesList[knownDeviceIndex].advertisementData.advName.isNotEmpty ? devicesList[knownDeviceIndex].advertisementData.advName : devicesList[knownDeviceIndex].device.platformName;
connectDeviceMacAddress =
devicesList[knownDeviceIndex].advertisementData.advName.isNotEmpty
? devicesList[knownDeviceIndex].advertisementData.advName
: devicesList[knownDeviceIndex].device.platformName;
bluetoothConnectDevice = devicesList[knownDeviceIndex].device;
print('bluetoothConnectDevice: $bluetoothConnectDevice');
@ -356,7 +383,8 @@ class BlueManage {
_initGetMtuSubscription();
_initListenConnectionState();
}
print("1 connectDeviceId:$connectDeviceMacAddress connectDeviceName:$connectDeviceName");
print(
"1 connectDeviceId:$connectDeviceMacAddress connectDeviceName:$connectDeviceName");
// stopScan();
if (connectDeviceMacAddress.isEmpty) {
// connectStateCallBack(BluetoothConnectionState.disconnected!);
@ -366,7 +394,8 @@ class BlueManage {
print("调用了停止扫描的方法");
await stopScan();
if ((scanResult!.advertisementData.serviceUuids[0].toString()[31] == "0") && isAddEquipment == false) {
if ((scanResult!.advertisementData.serviceUuids[0].toString()[31] == "0") &&
isAddEquipment == false) {
connectStateCallBack(BluetoothConnectionState.disconnected);
EasyLoading.showToast("该锁已被重置", duration: 2000.milliseconds);
return;
@ -403,12 +432,14 @@ class BlueManage {
" service.characteristics:${service.characteristics}"
" service.includedServices:${service.includedServices}");
if (service.uuid == _serviceIdConnect) {
for (BluetoothCharacteristic characteristic in service.characteristics) {
for (BluetoothCharacteristic characteristic
in service.characteristics) {
// Get.log("22222characteristic.remoteId:${characteristic.remoteId}"
// " characteristic.uuid:${characteristic.uuid}"
// " characteristic.secondaryServiceUuid:${characteristic.secondaryServiceUuid}"
// " characteristic.characteristicUuid:${characteristic.characteristicUuid}");
if (characteristic.characteristicUuid == _characteristicIdSubscription) {
if (characteristic.characteristicUuid ==
_characteristicIdSubscription) {
_subScribeToCharacteristic(characteristic);
print('Discovering services finished');
bluetoothConnectionState = BluetoothConnectionState.connected;
@ -446,18 +477,21 @@ class BlueManage {
}
// code to handle incoming data
// print("subscribeToCharacteristic: deviceId = ${characteristic.deviceId} characteristicId =${characteristic.characteristicId}---上报来的数据data = $data");
if ((data[0] == 0xEF) && (data[1] == 0x01) && (data[2] == 0xEE) && (data[3] == 0x02)) {
if ((data[0] == 0xEF) &&
(data[1] == 0x01) &&
(data[2] == 0xEE) &&
(data[3] == 0x02)) {
//
//
dataLen = data[8] * 256 + data[9]; // 16
print("dataLen1111:$dataLen getDataLength:${data.length} data:$data");
// print("dataLen1111:$dataLen getDataLength:${data.length} data:$data");
if (dataLen! + 12 > data.length) {
//
allData.addAll(data);
} else {
//
allData.addAll(data);
print("dataLen2222:$dataLen getDataLength:${data.length}");
// print("dataLen2222:$dataLen getDataLength:${data.length}");
CommandReciverManager.appDataReceive(allData);
//
allData = <int>[];
@ -466,7 +500,8 @@ class BlueManage {
//
allData.addAll(data);
// var len = allData[8] * 256 + allData[9];
print("dataLen3333:$dataLen allData.length:${allData.length} allData:$allData");
print(
"dataLen3333:$dataLen allData.length:${allData.length} allData:$allData");
if ((dataLen! + 14) <= allData.length) {
print("44444数据被解析了");
//
@ -530,44 +565,44 @@ class BlueManage {
//
Future<void> writeCharacteristicWithResponse(List<int> value) async {
bluetoothConnectDevice!.discoverServices().then((services) async {
for (BluetoothService service in services) {
// print("33333 service.remoteId:${service.remoteId}"
// " service.uuid:${service.uuid}\n\n"
// " service.characteristics:${service.characteristics}\n\n"
// " service.includedServices:${service.includedServices}");
if (service.uuid == _serviceIdConnect) {
for (BluetoothCharacteristic characteristic in service.characteristics) {
// print("44444 characteristic.remoteId:${characteristic.remoteId}"
// " characteristic.uuid:${characteristic.uuid}\n\n"
// " characteristic.secondaryServiceUuid:${characteristic
// .secondaryServiceUuid}\n\n"
// " characteristic.characteristicUuid:${characteristic
// .characteristicUuid}");
if (characteristic.characteristicUuid == _characteristicIdWrite) {
try {
List<int> valueList = value;
List subData = splitList(valueList, _mtuSize!);
print('writeCharacteristicWithResponse _mtuSize:$_mtuSize 得到的分割数据:$subData');
for (int i = 0; i < subData.length; i++) {
await characteristic.write(subData[i]).then((value) async {
await Future.delayed(const Duration(milliseconds: 1)).then((
value) async {
print('分包发送成功了');
});
});
}
} on Exception catch (e, s) {
print('Error occurred when writing: $e');
// Get.log(s);
rethrow;
List<BluetoothService> services =
await bluetoothConnectDevice!.discoverServices();
for (BluetoothService service in services) {
// print("33333 service.remoteId:${service.remoteId}"
// " service.uuid:${service.uuid}\n\n"
// " service.characteristics:${service.characteristics}\n\n"
// " service.includedServices:${service.includedServices}");
if (service.uuid == _serviceIdConnect) {
for (BluetoothCharacteristic characteristic
in service.characteristics) {
// print("44444 characteristic.remoteId:${characteristic.remoteId}"
// " characteristic.uuid:${characteristic.uuid}\n\n"
// " characteristic.secondaryServiceUuid:${characteristic
// .secondaryServiceUuid}\n\n"
// " characteristic.characteristicUuid:${characteristic
// .characteristicUuid}");
if (characteristic.characteristicUuid == _characteristicIdWrite) {
try {
List<int> valueList = value;
List subData = splitList(valueList, _mtuSize!);
// print('writeCharacteristicWithResponse _mtuSize:$_mtuSize 得到的分割数据:$subData');
for (int i = 0; i < subData.length; i++) {
await characteristic.write(subData[i],withoutResponse: true).then((value) async {
// await Future.delayed(const Duration(milliseconds: 1)).then((
// value) async {
// print('分包发送成功了');
// });
});
}
} on Exception catch (e, s) {
print('Error occurred when writing: $e');
// Get.log(s);
rethrow;
}
}
}
}
});
}
// List<BluetoothService> services = await bluetoothConnectDevice!.discoverServices();
// BluetoothCharacteristic characteristic = services
// .firstWhere((service) => service.uuid == _serviceIdWrite)

View File

@ -0,0 +1,149 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:get/get.dart';
import '../io_tool/io_tool.dart';
import '../sm4Encipher/sm4.dart';
import '../io_reply.dart';
import '../io_sender.dart';
import '../io_type.dart';
import 'package:crypto/crypto.dart' as crypto;
//oat升级
class OTAUpgradeCommand extends SenderProtocol {
String? lockID;
String? userID;
String? keyID;
int? platform;
int? product;
String? hwVersion;
String? fwVersion;
int? fwSize;
String? fwMD5;
int? needAuthor;
List<int>? publicKey;
List<int>? privateKey;
List<int>? token;
OTAUpgradeCommand(
{this.lockID,
this.userID,
this.keyID,
this.platform,
this.product,
this.hwVersion,
this.fwVersion,
this.fwSize,
this.fwMD5,
this.needAuthor,
this.publicKey,
this.privateKey,
this.token})
: super(CommandType.startOATUpgrade);
@override
List<int> messageDetail() {
List<int> data = [];
List<int> ebcData = [];
//
int type = commandType!.typeValue;
double typeDouble = type / 256;
int type1 = typeDouble.toInt();
int type2 = type % 256;
data.add(type1);
data.add(type2);
// id 40
int lockIDLength = utf8.encode(lockID!).length;
data.addAll(utf8.encode(lockID!));
data = getFixedLengthList(data, 40 - lockIDLength);
//userID 20
int userIDLength = utf8.encode(userID!).length;
data.addAll(utf8.encode(userID!));
data = getFixedLengthList(data, 20 - userIDLength);
//platform 2
int platform0 = (platform! & 0xFF00) >> 8;
int platform1 = platform! & 0xFF;
data.add(platform0);
data.add(platform1);
//product 2
int product0 = (product! & 0xFF00) >> 8;
int product1 = product! & 0xFF;
data.add(product0);
data.add(product1);
//HwVersion 20
int hwVersionLength = utf8.encode(hwVersion!).length;
data.addAll(utf8.encode(hwVersion!));
data = getFixedLengthList(data, 20 - hwVersionLength);
//FwVersion 20
int fwVersionLength = utf8.encode(fwVersion!).length;
data.addAll(utf8.encode(fwVersion!));
data = getFixedLengthList(data, 20 - fwVersionLength);
//fwSize 4
ByteData bytes = ByteData(4); // 4
bytes.setInt32(0, fwSize!);
List<int> byteList = bytes.buffer.asUint8List();
data.addAll(byteList);
//fwMD5 16
int fwMD5Length = utf8.encode(fwMD5!).length;
data.addAll(utf8.encode(fwMD5!));
data = getFixedLengthList(data, 16 - fwMD5Length);
// token 4 Token 0 token失效或者第一次发送的时候token为0
data.addAll(token!);
if (needAuthor == 0) {
//AuthCodeLen 1
data.add(0);
} else {
List<int> authCodeData = [];
//authUserID
authCodeData.addAll(utf8.encode(userID!));
//KeyID
authCodeData.addAll(utf8.encode(keyID!));
//token 4 Token 0
authCodeData.addAll(token!);
authCodeData.addAll(publicKey!);
// KeyIDauthUserIDmd5加密之后就是authCode
var authCode = crypto.md5.convert(authCodeData);
data.add(authCode.bytes.length);
data.addAll(authCode.bytes);
}
if ((data.length % 16) != 0) {
int add = (16 - data.length % 16);
for (int i = 0; i < add; i++) {
data.add(0);
}
}
Get.log("${commandType!.typeName} SM4Data:$data");
// LockId进行SM4 ECB加密 key:544d485f633335373034383064613864
ebcData = SM4.encrypt(data, key: privateKey, mode: SM4CryptoMode.ECB);
return ebcData;
}
}
class OTAUpgradeReply extends Reply {
OTAUpgradeReply.parseData(CommandType commandType, List<int> dataDetail)
: super.parseData(commandType, dataDetail) {
data = dataDetail;
int status = data[6];
errorWithStstus(status);
}
}

View File

@ -0,0 +1,74 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:get/get.dart';
import '../io_tool/io_tool.dart';
import '../sm4Encipher/sm4.dart';
import '../io_reply.dart';
import '../io_sender.dart';
import '../io_type.dart';
import 'package:crypto/crypto.dart' as crypto;
//oat升级
class ProcessOtaUpgradeCommand extends SenderProtocol {
int? index;
int? size;
List<int>? data;
ProcessOtaUpgradeCommand({
this.index,
this.size,
this.data,
}) : super(CommandType.processOTAUpgrade);
@override
List<int> messageDetail() {
List<int> data = [];
//
int type = commandType!.typeValue;
double typeDouble = type / 256;
int type1 = typeDouble.toInt();
int type2 = type % 256;
data.add(type1);
data.add(type2);
//index 2
ByteData indexBytes = ByteData(2); // 4
indexBytes.setInt16(0, index!);
List<int> indexList = indexBytes.buffer.asUint8List();
data.addAll(indexList);
//size 2
ByteData bytes = ByteData(2); // 4
bytes.setInt16(0, size!);
List<int> byteList = bytes.buffer.asUint8List();
data.addAll(byteList);
data.addAll(this.data!);
//
return data;
}
}
class ProcessOtaUpgradeReply extends Reply {
ProcessOtaUpgradeReply.parseData(
CommandType commandType, List<int> dataDetail)
: super.parseData(commandType, dataDetail) {
data = dataDetail;
int status = data[2];
errorWithStstus(status);
}
}
class ConfirmationOTAUpgradeReply extends Reply {
ConfirmationOTAUpgradeReply.parseData(
CommandType commandType, List<int> dataDetail)
: super.parseData(commandType, dataDetail) {
data = dataDetail;
int status = data[2];
errorWithStstus(status);
}
}

View File

@ -14,11 +14,11 @@ abstract class Reply{
Reply.parseData(this.commandType, List<int> dataDetail);
void errorWithStstus(int status){
Get.log("errorWithStstus status:$status commandType:$commandType");
// Get.log("errorWithStstus status:$status commandType:$commandType");
switch(status){
case 0x00:
//
Get.log("$commandType成功");
// Get.log("$commandType成功");
break;
case 0x01:
//
@ -134,4 +134,9 @@ abstract class Reply{
void showErrorMessage(String message){
EasyLoading.showToast(message, duration: 2000.milliseconds);
}
@override
String toString() {
return 'Reply{commandType: $commandType, status: $status, data: $data}';
}
}

View File

@ -12,11 +12,17 @@ abstract class SenderProtocol extends IOData {
// var uint8View1 = Uint8List(300);
CommandType? commandType; //
final List<int> header = [0XEF, 0X01, 0XEE, 0X02]; // 0XEF01EE02 4
final int ask = 0X01 ; // 0X01 0X11 1
final List<int> header = [
0XEF,
0X01,
0XEE,
0X02
]; // 0XEF01EE02 4
final int ask = 0X01; // 0X01 0X11 1
int? _commandIndex = 1; //
int identifier = 0x20; // 4 4 1 01AES1282SM43SM4
int identifier =
0x20; // 4 4 1 01AES1282SM43SM4
List<int>? commandData = []; //
// final int? tail = 0xFF; // CRC 2
@ -40,9 +46,9 @@ abstract class SenderProtocol extends IOData {
//
int commandIndexChange = _commandIndex!;
double commandIndexChangeDouble = commandIndexChange/256;
double commandIndexChangeDouble = commandIndexChange / 256;
int commandIndexChang1 = commandIndexChangeDouble.toInt();
int commandIndexChang2 = commandIndexChange%256;
int commandIndexChang2 = commandIndexChange % 256;
commandList.add(commandIndexChang1);
commandList.add(commandIndexChang2);
// print("_commandIndex:$_commandIndex commandIndexChang1$commandIndexChang1 commandIndexChang2:$commandIndexChang2");
@ -57,11 +63,11 @@ abstract class SenderProtocol extends IOData {
// commandList.add(dataLength);
// print("dataLen:$dataLen");
// var dataLen = 42;
double dataLength = dataLen/256;
double dataLength = dataLen / 256;
commandList.add(dataLength.toInt());
commandList.add(dataLen%256);
commandList.add(dataLen % 256);
commandList.add(dataLength.toInt());
commandList.add(dataLen%256);
commandList.add(dataLen % 256);
//
commandList.addAll(commandData!); //
@ -69,46 +75,284 @@ abstract class SenderProtocol extends IOData {
//
var mcrc = crc_16(commandList);
double mcrcDouble = mcrc/256;
double mcrcDouble = mcrc / 256;
int mcrcDouble1 = mcrcDouble.toInt();
int mcrcDouble2 = mcrc%256;
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];
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 value_ = 0x0000; //0xa635; //CRC类型设定
var tmp;
for (var i = 0; i < buffer.length; i++)
{
for (var i = 0; i < buffer.length; i++) {
tmp = reverse8(buffer[i]);
value_ = ((value_ << 8) ^ crcTable[((value_ >> 8) ^ tmp) & 0xFF]) & 0xFFFF;
value_ =
((value_ << 8) ^ crcTable[((value_ >> 8) ^ tmp) & 0xFF]) & 0xFFFF;
}
value_ = reverse16(value_);
return value_;
@ -116,22 +360,21 @@ abstract class SenderProtocol extends IOData {
int reverse8(data) {
var i;
var temp=0;
for(i=0;i<8;i++) {
var temp = 0;
for (i = 0; i < 8; i++) {
//
temp |= ((data>>i) & 0x01)<<(7-i);
temp |= ((data >> i) & 0x01) << (7 - i);
}
return temp;
}
int reverse16(data) {
var i;
var temp=0;
for(i=0;i<16;i++) {
var temp = 0;
for (i = 0; i < 16; i++) {
//
temp |= ((data>>i) & 0x0001)<<(15-i);
temp |= ((data >> i) & 0x0001) << (15 - i);
}
return temp;
}
}
}

View File

@ -1,15 +1,12 @@
import 'package:uuid/uuid.dart';
///
enum DataChannel{
ble,
udp
}
enum DataChannel { ble, udp }
extension Extension on DataChannel {
bool get isBLE => this == DataChannel.ble;
bool get isUDP => this == DataChannel.udp;
bool get isBLE => this == DataChannel.ble;
bool get isUDP => this == DataChannel.udp;
}
class EventSendModel {
@ -20,8 +17,16 @@ class EventSendModel {
String? deviceId;
Uuid? serviceId;
Uuid? characteristicId;
bool? allowLongWrite = false;
EventSendModel({required this.data,this.topic,this.sendChannel, this.deviceId, this.serviceId, this.characteristicId});
EventSendModel(
{required this.data,
this.topic,
this.sendChannel,
this.deviceId,
this.serviceId,
this.characteristicId,
this.allowLongWrite});
}
///
@ -30,26 +35,23 @@ class EventReceiveModel {
String? tag = '';
DataChannel? sendChannel;
EventReceiveModel({
required this.data,
this.sendChannel,
this.tag});
EventReceiveModel({required this.data, this.sendChannel, this.tag});
}
///
class EventParseModel {
int? type;
int? commandIndex;
dynamic data;
EventParseModel({required this.type, required this.data, this.commandIndex});
}
///debug info model
class StateModel {
final String title;
final String subTitle;
final bool result;
StateModel({this.title= '',this.subTitle = '',this.result = false});
}
StateModel({this.title = '', this.subTitle = '', this.result = false});
}

View File

@ -1,4 +1,3 @@
//TODO:
enum CommandType {
addUser, // = 0x3001
@ -13,6 +12,9 @@ enum CommandType {
getLockPrivateKey, // = 0x3091
calibrationTime, // = 0x30f0
readStarLockStatusInfo, // 0x3040
startOATUpgrade, //OTA升级开始 0x30E0
confirmationOTAUpgrade, //OTA升级开始 0x30E1
processOTAUpgrade, //OTA升级过程 0x30E2
generalExtendedCommond, // = 0x3030
gecChangeAdministratorPassword, // - = 2
@ -41,11 +43,10 @@ enum CommandType {
gecAddFaceConfirmation, // - = 84
}
extension ExtensionCommandType on CommandType {
static CommandType getCommandType(int value){
extension ExtensionCommandType on CommandType {
static CommandType getCommandType(int value) {
CommandType type = CommandType.readLockStatusInfo;
switch(value){
switch (value) {
case 0x3001:
{
type = CommandType.addUser;
@ -111,6 +112,21 @@ extension ExtensionCommandType on CommandType {
type = CommandType.readStarLockStatusInfo;
}
break;
case 0x30E0:
{
type = CommandType.startOATUpgrade;
}
break;
case 0x30E1:
{
type = CommandType.processOTAUpgrade;
}
break;
case 0x30E2:
{
type = CommandType.confirmationOTAUpgrade;
}
break;
default:
{
type = CommandType.readLockStatusInfo;
@ -122,7 +138,7 @@ extension ExtensionCommandType on CommandType {
int get typeValue {
int type = 0x300A;
switch(this){
switch (this) {
case CommandType.addUser:
type = 0x3001;
break;
@ -162,6 +178,15 @@ extension ExtensionCommandType on CommandType {
case CommandType.readStarLockStatusInfo:
type = 0x3040;
break;
case CommandType.startOATUpgrade:
type = 0x30E0;
break;
case CommandType.processOTAUpgrade:
type = 0x30E1;
break;
case CommandType.confirmationOTAUpgrade:
type = 0x30E2;
break;
default:
type = 0x300A;
break;
@ -171,10 +196,13 @@ extension ExtensionCommandType on CommandType {
return type;
}
//
int get identifierValue {
int type = 0x23;
switch(this){
switch (this) {
case CommandType.getLockPublicKey:
case CommandType.processOTAUpgrade:
//
type = 0x20;
break;
case CommandType.getLockPrivateKey:
@ -187,64 +215,73 @@ extension ExtensionCommandType on CommandType {
return type;
}
String get typeName {
String t = '';
switch(typeValue){
String get typeName {
String t = '';
switch (typeValue) {
case 0x3001:
t = '增加用户';
t = '增加用户';
break;
case 0x3002:
t = '删除用户';
t = '删除用户';
break;
case 0x3003:
t = '修改用户';
t = '修改用户';
break;
case 0x3004:
t = '恢复出厂设置';
t = '恢复出厂设置';
break;
case 0x3005:
t = '开门';
t = '开门';
break;
case 0x300A:
t = '读取锁状态信息';
t = '读取锁状态信息';
break;
case 0x300B:
t = '转移权限';
t = '转移权限';
break;
case 0x3020:
t = '开门记录上报';
t = '开门记录上报';
break;
case 0x3030:
t = '通用扩展指令';
t = '通用扩展指令';
break;
case 0x3090:
t = '获取锁公钥';
t = '获取锁公钥';
break;
case 0x3091:
t = '获取锁私钥';
t = '获取锁私钥';
break;
case 0x30f0:
t = '校时';
t = '校时';
break;
case 0x30f1:
t = '同步位置信息';
t = '同步位置信息';
break;
case 0x30f2:
t = '运维开锁';
t = '运维开锁';
break;
case 0x3016:
t = '写酒店信息';
t = '写酒店信息';
break;
case 0x3017:
t = '读酒店信息';
t = '读酒店信息';
break;
case 0x3040:
t = '读星锁状态信息';
t = '读星锁状态信息';
break;
case 0x30E0:
t = 'oat升级';
break;
case 0x30E2:
t = '确认oat升级';
break;
case 0x30E1:
t = 'oat升级过程';
break;
default:
t = '读星锁状态信息';
t = '读星锁状态信息';
break;
}
return t;
}
}
}

View File

@ -9,6 +9,8 @@ import 'package:star_lock/blue/io_protocol/io_deletUser.dart';
import 'package:star_lock/blue/io_protocol/io_editUser.dart';
import 'package:star_lock/blue/io_protocol/io_factoryDataReset.dart';
import 'package:star_lock/blue/io_protocol/io_getLockStatu.dart';
import 'package:star_lock/blue/io_protocol/io_otaUpgrade.dart';
import 'package:star_lock/blue/io_protocol/io_processOtaUpgrade.dart';
import 'package:star_lock/blue/io_protocol/io_queryingFaceStatus.dart';
import 'package:star_lock/blue/io_protocol/io_readAdminPassword.dart';
import 'package:star_lock/blue/io_protocol/io_readSupportFunctionsNoParameters.dart';
@ -20,11 +22,14 @@ import 'package:star_lock/blue/io_protocol/io_timing.dart';
import 'package:star_lock/blue/io_protocol/io_transferPermissions.dart';
import '../tools/storage.dart';
// import 'io_protocol/io_addFingerprint.dart';
import 'io_protocol/io_addFingerprintWithTimeCycleCoercion.dart';
// import 'io_protocol/io_addICCard.dart';
import 'io_protocol/io_addICCardWithTimeCycleCoercion.dart';
import 'io_protocol/io_addStressFingerprint.dart';
// import 'io_protocol/io_addStressICCard.dart';
import 'io_protocol/io_addStressPassword.dart';
import 'io_protocol/io_addUser.dart';
@ -59,7 +64,7 @@ class CommandReciverManager {
return;
}
Get.log("appDataReceiveData:$data"); // &&(data[4] == 0x11)
// Get.log("appDataReceiveData:$data"); // &&(data[4] == 0x11)
if ((data[0] == 0xEF) &&
(data[1] == 0x01) &&
(data[2] == 0xEE) &&
@ -69,7 +74,7 @@ class CommandReciverManager {
var dataLen = data[8] * 256 + data[9]; // 16
var oriLen = data[10] * 256 + data[11]; // 16
print("dataLen:$dataLen oriLen:$oriLen");
// print("dataLen:$dataLen oriLen:$oriLen");
// List<int> dataList = [];
List<int> oriDataList = [];
switch (tmpType) {
@ -109,11 +114,11 @@ class CommandReciverManager {
oriDataList = SM4.decrypt(getDataList,
key: getPrivateKeyList, mode: SM4CryptoMode.ECB);
oriDataList = oriDataList.sublist(0, oriLen);
print("SM4 oriDataList:$oriDataList");
// print("SM4 oriDataList:$oriDataList");
break;
}
parseData(oriDataList).then((value) async {
Get.log("parseData222 data:$value");
// Get.log("parseData222 data:$value");
EasyLoading.dismiss();
await EventBusManager().eventBusFir(value);
}).catchError((error) {
@ -129,7 +134,7 @@ class CommandReciverManager {
CommandType commandType = ExtensionCommandType.getCommandType(cmd);
await IoManager().increaseCommandIndex();
// data.removeRange(0, 2);
Get.log("parseData cmd:$cmd commandType:$commandType data:$data");
// Get.log("parseData cmd:$cmd commandType:$commandType data:$data");
var reply;
switch (commandType) {
case CommandType.getLockPublicKey:
@ -154,7 +159,7 @@ class CommandReciverManager {
break;
case CommandType.openLock:
{
Get.log("openLockReply data:$data");
// Get.log("openLockReply data:$data");
reply = OpenDoorReply.parseData(commandType, data);
}
break;
@ -189,6 +194,21 @@ class CommandReciverManager {
reply = GetStarLockStatuInfoReply.parseData(commandType, data);
}
break;
case CommandType.startOATUpgrade:
{
reply = OTAUpgradeReply.parseData(commandType, data);
}
break;
case CommandType.confirmationOTAUpgrade:
{
reply = ConfirmationOTAUpgradeReply.parseData(commandType, data);
}
break;
case CommandType.processOTAUpgrade:
{
reply = ProcessOtaUpgradeReply.parseData(commandType, data);
}
break;
case CommandType.generalExtendedCommond:
{
//
@ -279,8 +299,9 @@ class CommandReciverManager {
case 36:
{
// (...)
reply = SenderAddFingerprintWithTimeCycleCoercionReply.parseData(
commandType, data);
reply =
SenderAddFingerprintWithTimeCycleCoercionReply.parseData(
commandType, data);
}
break;
case 40:

View File

@ -1,4 +1,3 @@
import 'dart:async';
import '../app_settings/app_settings.dart';
@ -11,22 +10,26 @@ import 'io_tool/manager_event_bus.dart';
import 'sender_beforeDataManage.dart';
typedef CommandSendCallBack = void Function(ErrorType errorType);
class CommandSenderManager {
class CommandSenderManager {
static final CommandSenderManager _manager = CommandSenderManager._init();
factory CommandSenderManager()=>_manager;
static CommandSenderManager getInstance()=>_manager;
CommandSenderManager._init(){
factory CommandSenderManager() => _manager;
static CommandSenderManager getInstance() => _manager;
CommandSenderManager._init() {
init();
}
init(){
init() {
initLockAddUserSucceedEvent();
}
//
StreamSubscription? _passCurrentLockInformationEvent;
List<int> dataBeforeAddTheUser = [];
void initLockAddUserSucceedEvent() {
// eventBus
_passCurrentLockInformationEvent = eventBus.on<LockAddUserSucceedEvent>().listen((event) {
@ -55,7 +58,7 @@ class CommandSenderManager {
}
List<int> value = command.packageData();
print("CommonDataManage().currentLockUserNo:${CommonDataManage().currentLockUserNo}");
// print("CommonDataManage().currentLockUserNo:${CommonDataManage().currentLockUserNo}");
if(CommonDataManage().currentLockUserNo == 0){
//
var entity = await SenderBeforeDataManage().getAddUserKeyData();
@ -63,7 +66,7 @@ class CommandSenderManager {
dataBeforeAddTheUser = value;
return;
}else{
print("继续发送数据了继续发送数据了继续发送数据了");
// print("继续发送数据了继续发送数据了继续发送数据了");
_sendNormalData(value);
}
}
@ -132,4 +135,4 @@ class CommandSenderManager {
dispose() {
_passCurrentLockInformationEvent?.cancel();
}
}
}

View File

@ -1,9 +1,12 @@
import 'package:star_lock/blue/io_protocol/io_addFace.dart';
// import 'package:star_lock/blue/io_protocol/io_addICCard.dart';
// import 'package:star_lock/blue/io_protocol/io_addStressICCard.dart';
import 'package:star_lock/blue/io_protocol/io_changeAdministratorPassword.dart';
import 'package:star_lock/blue/io_protocol/io_deletUser.dart';
import 'package:star_lock/blue/io_protocol/io_getLockStatu.dart';
import 'package:star_lock/blue/io_protocol/io_otaUpgrade.dart';
import 'package:star_lock/blue/io_protocol/io_processOtaUpgrade.dart';
import 'package:star_lock/blue/io_protocol/io_queryingFaceStatus.dart';
import 'package:star_lock/blue/io_protocol/io_readAdminPassword.dart';
@ -359,23 +362,22 @@ class IoSenderManage {
//todo:(...)
static void senderAddFingerprintWithTimeCycleCoercionCommand(
{
required String? keyID,
required String? userID,
required int? fingerNo,
required int? useCountLimit,
required int? isForce,
required List<int>? token,
required int? isRound,
required int? weekRound,
required int? startDate,
required int? endDate,
required String? startTime,
required String? endTime,
required int? needAuthor,
required List<int>? signKey,
required List<int>? privateKey,
CommandSendCallBack? callBack}) {
{required String? keyID,
required String? userID,
required int? fingerNo,
required int? useCountLimit,
required int? isForce,
required List<int>? token,
required int? isRound,
required int? weekRound,
required int? startDate,
required int? endDate,
required String? startTime,
required String? endTime,
required int? needAuthor,
required List<int>? signKey,
required List<int>? privateKey,
CommandSendCallBack? callBack}) {
CommandSenderManager().managerSendData(
command: SenderAddFingerprintWithTimeCycleCoercionCommand(
keyID: keyID,
@ -428,23 +430,22 @@ class IoSenderManage {
//todo:(...)
static void senderAddCardWithTimeCycleCoercionCommand(
{
required String? keyID,
required String? userID,
required int? cardNo,
required int? useCountLimit,
required int? isForce,
required List<int>? token,
required int? isRound,
required int? weekRound,
required int? startDate,
required int? endDate,
required String? startTime,
required String? endTime,
required int? needAuthor,
required List<int>? signKey,
required List<int>? privateKey,
CommandSendCallBack? callBack}) {
{required String? keyID,
required String? userID,
required int? cardNo,
required int? useCountLimit,
required int? isForce,
required List<int>? token,
required int? isRound,
required int? weekRound,
required int? startDate,
required int? endDate,
required String? startTime,
required String? endTime,
required int? needAuthor,
required List<int>? signKey,
required List<int>? privateKey,
CommandSendCallBack? callBack}) {
CommandSenderManager().managerSendData(
command: SenderAddICCardWithTimeCycleCoercionCommand(
keyID: keyID,
@ -469,20 +470,20 @@ class IoSenderManage {
//todo:
static void senderAddFaceCommand(
{required String? keyID,
required String? userID,
required int? faceNo,
required int? useCountLimit,
required int? isForce,
required List<int>? token,
required int? isRound,
required int? weekRound,
required int? startDate,
required int? endDate,
required String? startTime,
required String? endTime,
required int? needAuthor,
required List<int>? signKey,
required List<int>? privateKey,
required String? userID,
required int? faceNo,
required int? useCountLimit,
required int? isForce,
required List<int>? token,
required int? isRound,
required int? weekRound,
required int? startDate,
required int? endDate,
required String? startTime,
required String? endTime,
required int? needAuthor,
required List<int>? signKey,
required List<int>? privateKey,
CommandSendCallBack? callBack}) {
CommandSenderManager().managerSendData(
command: SenderAddFaceCommand(
@ -709,12 +710,12 @@ class IoSenderManage {
//todo:wifi列表
static void getWifiListCommand(
{required String? keyID,
required String? userID,
required List<int>? token,
required int? needAuthor,
required List<int>? publicKey,
required List<int>? privateKey,
CommandSendCallBack? callBack}) {
required String? userID,
required List<int>? token,
required int? needAuthor,
required List<int>? publicKey,
required List<int>? privateKey,
CommandSendCallBack? callBack}) {
CommandSenderManager().managerSendData(
command: SenderGetWifiCommand(
keyID: keyID,
@ -977,4 +978,54 @@ class IoSenderManage {
),
callBack: callBack);
}
//ota
static void senderOTAUpgradeCommand(
{required String? lockID,
required String? userID,
required String? keyID,
required int? platform,
required int? product,
required String? hwVersion,
required String? fwVersion,
required int? fwSize,
required String? fwMD5,
required int? needAuthor,
required List<int>? token,
required List<int>? publicKey,
required List<int>? privateKey,
CommandSendCallBack? callBack}) {
CommandSenderManager().managerSendData(
command: OTAUpgradeCommand(
lockID: lockID,
userID: userID,
keyID: keyID,
platform: platform,
product: product,
hwVersion: hwVersion,
fwVersion: fwVersion,
fwSize: fwSize,
fwMD5: fwMD5,
token: token,
needAuthor: needAuthor,
publicKey: publicKey,
privateKey: privateKey,
),
callBack: callBack);
}
//ota
static void senderProcessOtaUpgradeCommand(
{required int? index,
required int? size,
required List<int>? data,
CommandSendCallBack? callBack}) {
CommandSenderManager().managerSendData(
command: ProcessOtaUpgradeCommand(
index: index,
size: size,
data: data,
),
callBack: callBack);
}
}

View File

@ -34,7 +34,7 @@ class LockDetailLogic extends BaseGetXController {
//
void initReplySubscription() {
state.replySubscription = EventBusManager().eventBus!.on<Reply>().listen((reply) async {
Get.log("锁详情收到了蓝牙解析消息 reply:${reply.commandType}");
// Get.log("锁详情收到了蓝牙解析消息 reply:${reply.commandType}");
//
if (reply is OpenDoorReply && state.ifCurrentScreen.value == true) {
_replyOpenLock(reply);

View File

@ -1,14 +1,41 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:crypto/crypto.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:get/get.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:star_lock/blue/blue_manage.dart';
import 'package:star_lock/blue/io_protocol/io_otaUpgrade.dart';
import 'package:star_lock/blue/io_protocol/io_processOtaUpgrade.dart';
import 'package:star_lock/blue/io_reply.dart';
import 'package:star_lock/blue/io_tool/io_tool.dart';
import 'package:star_lock/blue/io_tool/manager_event_bus.dart';
import 'package:star_lock/blue/sender_manage.dart';
import 'package:star_lock/main/lockDetail/lockSet/lockSet/lockSet_logic.dart';
import 'package:star_lock/permission/permission_dialog.dart';
import 'package:star_lock/tools/advancedCalendar/src/datetime_util.dart';
import 'package:star_lock/tools/baseGetXController.dart';
import 'package:star_lock/tools/commonDataManage.dart';
import 'package:star_lock/tools/pickers/time_picker/time_utils.dart';
import 'package:star_lock/tools/storage.dart';
import 'lockEscalation_state.dart';
class LockEscalationLogic extends BaseGetXController{
class LockEscalationLogic extends BaseGetXController {
LockEscalationState state = LockEscalationState();
StreamSubscription<Reply>? _replySubscription;
int otaCount = 0;
int otaIndex = 0;
Uint8List? otaBin;
int startSecond = 0;
//
Future<void> setLockSetGeneralSetting() async{
Future<void> setLockSetGeneralSetting() async {
// var entity = await ApiRepository.to.getLockVersionInfoData(
// lockId: state.getKeyInfosData.value.lockId.toString(),
// );
@ -17,24 +44,193 @@ class LockEscalationLogic extends BaseGetXController{
// }
}
//
Future<void> otaUpdate() async {
var status = await PermissionDialog.request(
Permission.storage, '需要访问读写权限才能使用手动升级固件');
if (status != true) {
return;
}
FilePickerResult? result = await FilePicker.platform.pickFiles();
if (result == null || result.files.single.path is! String) {
return;
}
File file = File(result.files.single.path!);
Uint8List data = await file.readAsBytes();
Map? headJson = await getHeadFile(data);
if (headJson is! Map) {
return;
}
otaBin = await checkFile(data, headJson);
if (otaBin == null) {
return;
}
startOTAData();
blueOTAUpgrade(headJson);
}
// ota
void blueOTAUpgrade(Map data) {
BlueManage().bludSendData(BlueManage().connectDeviceName,
(BluetoothConnectionState deviceConnectionState) async {
if (deviceConnectionState == BluetoothConnectionState.connected) {
var privateKey = await Storage.getStringList(saveBluePrivateKey);
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
var token = await Storage.getStringList(saveBlueToken);
List<int> getTokenList = changeStringListToIntList(token!);
var publicKey = await Storage.getStringList(saveBluePublicKey);
List<int> getPublicKeyList = changeStringListToIntList(publicKey!);
String lockID = CommonDataManage.shareManager()
?.currentLockSetInfoData
.lockId
?.toString() ??
'';
String keyID =
CommonDataManage.shareManager()?.currentKeyInfo.keyId?.toString() ??
'';
BlueManage().writeCharacteristicWithResponse(OTAUpgradeCommand(
lockID: lockID,
userID: await Storage.getUid(),
keyID: keyID,
platform: int.tryParse(data['platform']) ?? 0,
product: int.tryParse(data['product']) ?? 0,
hwVersion: data['hwVersion'],
fwVersion: data['fwVersion'],
fwSize: data['fwSize'],
fwMD5: data['fwMd5'],
needAuthor: 1,
token: getTokenList,
publicKey: getPublicKeyList,
privateKey: getPrivateKeyList)
.packageData());
} else if (deviceConnectionState ==
BluetoothConnectionState.disconnected) {}
});
}
//
Future<void> processOtaUpgrade() async {
if (!state.otaUpdateIng.value) {
return;
}
int length = otaBin?.length ?? 0;
if (otaCount == 0) {
//
int difference = length % 240;
otaCount = length ~/ 240 + (difference > 0 ? 1 : 0);
startSecond = DateTime.now().millisecondsSinceEpoch ~/ 1000;
}
if (otaCount <= otaIndex) {
int now = DateTime.now().millisecondsSinceEpoch ~/ 1000;
String msg = '传输完成 时间:${now - startSecond}';
closeOTADAta();
print(msg);
showToast(msg);
return;
}
int star = otaIndex * 240;
int end = (otaIndex + 1) * 240;
if (end > length) {
end = length;
}
List<int> data = otaBin!.sublist(star, end);
state.otaProgress.value = otaIndex / otaCount;
await BlueManage().writeCharacteristicWithResponse(
ProcessOtaUpgradeCommand(index: otaIndex, size: length, data: data)
.packageData());
}
// ota升级
void startOTAData() {
state.otaUpdateIng.value = true;
}
// ata
void closeOTADAta() {
state.otaUpdateIng.value = false;
state.otaProgress.value = 0;
otaIndex = 0;
otaCount = 0;
startSecond = 0;
otaBin = null;
}
//
void getBack() {
if (state.otaUpdateIng.value) {
closeOTADAta();
} else {
Get.back();
}
}
//
Future<Map?> getHeadFile(Uint8List data) async {
//
String header = utf8.decode(data.sublist(0, 12));
if (header != 'SYD-BIN-DATA') {
showToast('非SYD固件请选择正确的文件');
return null;
}
//
Uint8List metaLenList = data.sublist(12, 16);
int metaLen = ByteData.sublistView(metaLenList).getUint32(0);
if (metaLen < 2 || metaLen > 10240) {
showToast('元数据长度错误');
return null;
}
//
Uint8List metaStrList = data.sublist(16, 16 + metaLen);
String metaStr = utf8.decode(metaStrList);
print(metaStr);
var meta = jsonDecode(metaStr);
return meta..['metaLen'] = metaLen;
}
// bin
Future<Uint8List?> checkFile(Uint8List data, Map meta) async {
num binOffset = 16 + (meta['metaLen'] ?? 0);
//
Uint8List bin = data.sublist(binOffset.toInt(), data.length);
//md5
// String md5Str = md5.convert(bin).toString();
// if (md5Str != meta['fwMd5']) {
// showToast('固件MD5校验失败');
// return false;
// }
if (bin.length != meta['fwSize']) {
showToast('固件校验失败');
return null;
}
return bin;
}
@override
void onReady() {
// TODO: implement onReady
super.onReady();
print("onReady()");
setLockSetGeneralSetting();
}
@override
void onInit() {
// TODO: implement onInit
super.onInit();
print("onInit()");
_replySubscription =
EventBusManager().eventBus!.on<Reply>().listen((reply) {
if (reply is OTAUpgradeReply && reply.status == 0x00) {
//
processOtaUpgrade();
} else if (reply is ProcessOtaUpgradeReply && reply.status == 0x00) {
otaIndex++;
processOtaUpgrade();
} else if (reply is ConfirmationOTAUpgradeReply && reply.status == 0x00) {
closeOTADAta();
showToast('固件升级完成');
}
});
}
@override
void onClose() {
// TODO: implement onClose
_replySubscription?.cancel();
}
}

View File

@ -16,66 +16,152 @@ class LockEscalationPage extends StatefulWidget {
}
class _LockEscalationPageState extends State<LockEscalationPage> {
final logic = Get.put(LockEscalationLogic());
final state = Get.find<LockEscalationLogic>().state;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: TitleAppBar(
barTitle: TranslationLoader.lanKeys!.lockEscalation!.tr,
haveBack: true,
backgroundColor: AppColors.mainColor),
body: Container(
padding: EdgeInsets.all(30.w),
child: Column(
children: [
SizedBox(
height: 60.h,
return GetBuilder<LockEscalationLogic>(
init: LockEscalationLogic(),
builder: (LockEscalationLogic logic) {
return Scaffold(
backgroundColor: Colors.white,
appBar: TitleAppBar(
barTitle: TranslationLoader.lanKeys!.lockEscalation!.tr,
haveBack: true,
backgroundColor: AppColors.mainColor,
backAction: logic.getBack,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'images/main/icon_main_lockSet_lockEscalation.png',
width: 36.w,
height: 36.w,
),
SizedBox(
width: 10.w,
),
Text(
TranslationLoader.lanKeys!.haveNewVersion!.tr,
style:
TextStyle(fontSize: 24.sp, fontWeight: FontWeight.w600),
)
],
),
SizedBox(
height: 30.h,
),
Text(
"${TranslationLoader.lanKeys!.currentVersion!.tr}1.0.0",
style: TextStyle(
fontSize: 18.sp, color: AppColors.darkGrayTextColor),
),
SizedBox(
height: 10.h,
),
Text(
// "${TranslationLoader.lanKeys!.newVersion!.tr}1.0.1",
"未发现新版本",
style: TextStyle(color: AppColors.mainColor, fontSize: 18.sp),
),
SizedBox(
height: 40.h,
),
SubmitBtn(
btnName: TranslationLoader.lanKeys!.upgrade!.tr,
onClick: () {}),
],
),
));
body: Container(
padding: EdgeInsets.all(30.w),
child: Column(
children: [
Obx(() {
return logic.state.otaUpdateIng.value
? PopScope(
canPop: false,
onPopInvoked: (didPop) async {
if (logic.state.otaUpdateIng.value) {
logic.closeOTADAta();
}
},
child: SizedBox(),
)
: SizedBox();
}),
SizedBox(
height: 60.h,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'images/main/icon_main_lockSet_lockEscalation.png',
width: 36.w,
height: 36.w,
),
SizedBox(
width: 10.w,
),
Text(
TranslationLoader.lanKeys!.haveNewVersion!.tr,
style: TextStyle(
fontSize: 24.sp, fontWeight: FontWeight.w600),
)
],
),
SizedBox(
height: 30.h,
),
Text(
"${TranslationLoader.lanKeys!.currentVersion!.tr}1.0.0",
style: TextStyle(
fontSize: 18.sp, color: AppColors.darkGrayTextColor),
),
SizedBox(
height: 10.h,
),
Obx(() {
return !logic.state.otaUpdateIng.value
? Stack(
children: [
Container(
margin: EdgeInsets.only(top: 8, bottom: 8),
width: Get.width,
child: Center(
child: Text(
// "${TranslationLoader.lanKeys!.newVersion!.tr}1.0.1",
"未发现新版本",
style: TextStyle(
color: AppColors.mainColor,
fontSize: 18.sp),
),
),
),
Positioned(
right: 80.w,
child: GestureDetector(
onTap: () {
logic.otaUpdate();
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'手动升级',
style: TextStyle(
color: AppColors.mainColor,
fontSize: 18.sp,
fontWeight: FontWeight.w400),
),
),
),
)
],
)
: Padding(
padding: EdgeInsets.symmetric(
horizontal: 50.w, vertical: 15.h),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'固件传输中',
style: TextStyle(
color: AppColors.mainColor,
fontSize: 18.sp,
fontWeight: FontWeight.w400),
),
SizedBox(
width: 10.w,
),
Expanded(
child: ClipRRect(
borderRadius: BorderRadius.all(
Radius.circular(10.r)),
child: LinearProgressIndicator(
value: logic
.state.otaProgress.value, // 50%
backgroundColor: Colors.grey[200],
valueColor:
AlwaysStoppedAnimation<Color>(
AppColors.mainColor),
),
),
),
],
),
);
}),
SizedBox(
height: 40.h,
),
Obx(() {
return !logic.state.otaUpdateIng.value
? SubmitBtn(
btnName: TranslationLoader.lanKeys!.upgrade!.tr,
onClick: () {})
: SizedBox();
}),
],
),
));
});
}
}

View File

@ -1,4 +1,6 @@
import 'package:get/get.dart';
class LockEscalationState{
class LockEscalationState {
var otaUpdateIng = false.obs;
var otaProgress = 0.00.obs;
}

View File

@ -84,7 +84,7 @@ class PermissionDialog {
}
//
static Future<bool> request(Permission permission) async {
static Future<bool> request(Permission permission, [String? content]) async {
if (Get.context == null) {
return false;
}
@ -99,7 +99,7 @@ class PermissionDialog {
canPop: false,
child: CupertinoAlertDialog(
title: Text('${'申请'.tr}${titles[permission] ?? ''}${'权限'.tr}'),
content: Text(contents[permission] ?? ''),
content: Text(content ?? contents[permission] ?? ''),
actions: [
CupertinoDialogAction(
child: Text('不允许'.tr),

View File

@ -94,7 +94,7 @@ dependencies:
#跳转到外部
url_launcher: ^6.1.10
#蓝牙
# flutter_reactive_ble: ^5.1.1
# flutter_reactive_ble: ^5.1.1
flutter_blue_plus: ^1.31.16
#
event_bus: ^2.0.0
@ -123,7 +123,7 @@ dependencies:
# 谷歌地图
google_maps_flutter: ^2.2.5
# geocoding: ^2.1.0
# geocoding: ^2.1.0
# 允许App发现网络的相关信息并且进行相应的配置
network_info_plus: ^4.0.2
@ -144,12 +144,12 @@ dependencies:
image_gallery_saver: ^2.0.3
convert: ^3.1.1
just_audio: ^0.9.36
# flutter_sound: ^9.2.13
# ffmpeg_kit_flutter: 5.1.0-LTS
# flutter_sound: ^9.2.13
# ffmpeg_kit_flutter: 5.1.0-LTS
fast_gbk: ^1.0.0
flutter_pcm_sound: ^1.1.0
intl: ^0.18.0
# flutter_audio_capture: <1.1.5
# flutter_audio_capture: <1.1.5
flutter_voice_processor: ^1.1.1
#监听网络连接状态
@ -165,6 +165,7 @@ dependencies:
system_settings: ^2.0.0
expandable: ^5.0.1
colorfilter_generator: ^0.0.8
file_picker: ^5.3.1
dev_dependencies: