266 lines
8.2 KiB
Dart
Raw Normal View History

import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
2023-09-07 18:36:16 +08:00
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';
2024-04-25 14:23:05 +08:00
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';
2023-09-07 18:36:16 +08:00
import 'package:star_lock/tools/baseGetXController.dart';
import 'package:star_lock/tools/commonDataManage.dart';
import 'package:star_lock/tools/storage.dart';
2023-09-07 18:36:16 +08:00
2024-04-26 15:38:59 +08:00
import '../../../../app_settings/app_settings.dart';
2023-09-07 18:36:16 +08:00
import 'lockEscalation_state.dart';
class LockEscalationLogic extends BaseGetXController {
2023-09-07 18:36:16 +08:00
LockEscalationState state = LockEscalationState();
StreamSubscription<Reply>? _replySubscription;
int otaCount = 0;
int otaIndex = 0;
Uint8List? otaBin;
int startSecond = 0;
2024-04-25 09:39:31 +08:00
Map? headJson = null;
2023-09-07 18:36:16 +08:00
2023-11-01 17:28:59 +08:00
// 锁升级
Future<void> setLockSetGeneralSetting() async {
2023-11-01 17:28:59 +08:00
// var entity = await ApiRepository.to.getLockVersionInfoData(
// lockId: state.getKeyInfosData.value.lockId.toString(),
// );
// if(entity.errorCode!.codeIsSuccessful){
//
// }
2023-09-07 18:36:16 +08:00
}
//手动升级
Future<void> otaUpdate() async {
var status = await PermissionDialog.request(
2024-04-29 18:25:48 +08:00
Permission.storage, '需要访问读写权限才能使用手动升级固件'.tr);
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();
2024-04-25 09:39:31 +08:00
headJson = await getHeadFile(data);
if (headJson is! Map) {
return;
}
2024-04-25 09:39:31 +08:00
otaBin = await checkFile(data, headJson!);
if (otaBin == null) {
return;
}
2024-04-25 09:39:31 +08:00
String md5Str = md5.convert(otaBin!).toString();
headJson!['fwMd5'] = md5Str;
2024-04-25 14:23:05 +08:00
blueOTAUpgrade(headJson!, [0, 0, 0, 0]);
}
//蓝牙操作 ota 升级
2024-04-25 09:39:31 +08:00
void blueOTAUpgrade(Map data, List<int> token) {
BlueManage().bludSendData(BlueManage().connectDeviceName,
(BluetoothConnectionState deviceConnectionState) async {
if (deviceConnectionState == BluetoothConnectionState.connected) {
var privateKey = await Storage.getStringList(saveBluePrivateKey);
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
2024-04-25 09:39:31 +08:00
var signKey = await Storage.getStringList(saveBlueSignKey);
List<int> signKeyDataList = changeStringListToIntList(signKey!);
2024-04-25 14:23:05 +08:00
String uid = await Storage.getUid() ?? '';
BlueManage().writeCharacteristicWithResponse(OTAUpgradeCommand(
2024-04-25 14:23:05 +08:00
lockID: BlueManage().connectDeviceName,
userID: uid,
keyID: BlueManage().connectDeviceName,
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,
2024-04-25 09:39:31 +08:00
token: token,
2024-04-25 14:23:05 +08:00
signKey: signKeyDataList,
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;
2024-04-25 09:39:31 +08:00
startOTAData();
}
if (otaCount <= otaIndex) {
int now = DateTime.now().millisecondsSinceEpoch ~/ 1000;
2024-04-25 14:23:05 +08:00
String msg =
'传输完成 时间:${now - startSecond}秒 otaCount:$otaCount otaIndex:$otaIndex ';
closeOTADAta();
2024-04-26 15:38:59 +08:00
AppLog.log(msg);
2024-04-25 14:23:05 +08:00
// showToast(msg);
return;
}
int star = otaIndex * 240;
int end = (otaIndex + 1) * 240;
if (end > length) {
end = length;
}
2024-04-25 14:23:05 +08:00
int size = end - star;
List<int> data = otaBin!.sublist(star, end);
state.otaProgress.value = otaIndex / otaCount;
await BlueManage().writeCharacteristicWithResponse(
2024-04-25 14:23:05 +08:00
ProcessOtaUpgradeCommand(index: otaIndex, size: size, 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 {
if (data.length <= 16) {
2024-04-29 18:25:48 +08:00
showToast('错误固件,请选择正确的文件'.tr);
return null;
}
// 检查文件头
String header;
try {
header = utf8.decode(data.sublist(0, 12));
} catch (e) {
2024-04-29 18:25:48 +08:00
showToast('非SYD固件请选择正确的文件'.tr);
return null;
}
if (header != 'SYD-BIN-DATA') {
2024-04-29 18:25:48 +08:00
showToast('非SYD固件请选择正确的文件'.tr);
return null;
}
// 解析元数据长度
Uint8List metaLenList;
int metaLen;
try {
metaLenList = data.sublist(12, 16);
metaLen = ByteData.sublistView(metaLenList).getUint32(0);
} catch (e) {
2024-04-29 18:25:48 +08:00
showToast('文件校验失败 0x01'.tr);
return null;
}
if (metaLen < 2 || metaLen > 10240) {
2024-04-29 18:25:48 +08:00
showToast('文件校验失败 0x01'.tr);
return null;
}
// 读取和解析元数据
Uint8List metaStrList;
String metaStr;
try {
metaStrList = data.sublist(16, 16 + metaLen);
metaStr = utf8.decode(metaStrList);
} catch (e) {
2024-04-29 18:25:48 +08:00
showToast('解析元数据失败,请选择正确的文件'.tr);
return null;
}
2024-04-26 15:38:59 +08:00
AppLog.log(metaStr);
var meta = jsonDecode(metaStr);
if (meta is! Map) {
2024-04-29 18:25:48 +08:00
showToast('解析元数据失败,请选择正确的文件'.tr);
return null;
}
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 校验有问题,暂时不解析
2024-04-25 14:23:05 +08:00
String md5Str = md5.convert(bin).toString().toUpperCase();
2024-04-26 15:38:59 +08:00
AppLog.log('---> $md5Str ${meta['fwMd5']}');
2024-04-25 14:23:05 +08:00
if (md5Str != meta['fwMd5']) {
2024-04-29 18:25:48 +08:00
showToast('文件校验失败 0x02'.tr);
2024-04-25 14:23:05 +08:00
return null;
}
if (bin.length != meta['fwSize']) {
2024-04-29 18:25:48 +08:00
showToast('文件校验失败 0x03'.tr);
return null;
}
return bin;
}
2023-09-07 18:36:16 +08:00
@override
void onReady() {
super.onReady();
setLockSetGeneralSetting();
}
@override
void onInit() {
super.onInit();
_replySubscription =
EventBusManager().eventBus!.on<Reply>().listen((reply) {
2024-04-25 09:39:31 +08:00
if (reply is OTAUpgradeReply) {
if (reply.status == 0x00) {
//验证通过,开始发送数据包
2024-04-25 14:23:05 +08:00
startOTAData();
2024-04-25 09:39:31 +08:00
processOtaUpgrade();
} else if (reply.status == 0x06) {
blueOTAUpgrade(headJson!, reply.token);
}
} else if (reply is ProcessOtaUpgradeReply && reply.status == 0x00) {
otaIndex++;
processOtaUpgrade();
} else if (reply is ConfirmationOTAUpgradeReply && reply.status == 0x00) {
closeOTADAta();
2024-04-29 18:25:48 +08:00
showToast('固件升级完成'.tr);
}
});
2023-09-07 18:36:16 +08:00
}
@override
void onClose() {
_replySubscription?.cancel();
2023-09-07 18:36:16 +08:00
}
2024-01-23 17:36:02 +08:00
}