更新眠花糖兼容wifi配置

This commit is contained in:
wyf
2025-10-28 14:51:28 +08:00
parent 7cfd3bf8f5
commit 3c5db3bdf2
14 changed files with 1259 additions and 882 deletions

View File

@@ -8,6 +8,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/component/tool/cmd.dart';
import 'package:vbvs_app/pages/mh_page/device/controller/mht_bluetooth_controller.dart';
import 'package:ef/ef.dart'; // THapp 所在的包
@@ -86,7 +87,7 @@ class MultiDeviceFirmwareUpdater {
throw Exception("[蓝牙指令执行日志] 设备 $mac 正在升级中".tr);
}
}
// await sendBlogAndDlogCommands(thapp);
final completer = Completer<void>();
final task = UpgradeTask(
mac: mac,
@@ -98,25 +99,24 @@ class MultiDeviceFirmwareUpdater {
_upgradeTasks[mac] = task;
_updateUiProgress(mac, 0, 'waiting');
_processUpgradeQueue();
_processUpgradeQueue(thapp);
return completer.future;
}
void _processUpgradeQueue() {
void _processUpgradeQueue(THapp thapp) {
final waitingTasks =
_upgradeTasks.values.where((task) => task.status == 'waiting').toList();
for (final task in waitingTasks) {
if (_currentConcurrentUpgrades < _maxConcurrentUpgrades) {
_currentConcurrentUpgrades++;
_startSingleUpgrade(task);
_startSingleUpgrade(task, thapp);
}
//screen shots
}
}
Future<void> _startSingleUpgrade(UpgradeTask task) async {
Future<void> _startSingleUpgrade(UpgradeTask task, THapp thapp) async {
try {
task.status = 'downloading';
@@ -129,7 +129,8 @@ class MultiDeviceFirmwareUpdater {
}
// await _sendCommand(task.thapp, "blog disable");
_sendCommand(task.thapp, "blog disable");
// _sendCommand(task.thapp, "blog disable");
await Future.delayed(Duration(milliseconds: 200));
task.status = 'upgrading';
@@ -137,9 +138,8 @@ class MultiDeviceFirmwareUpdater {
await _sendFirmwareFrames(task);
await _sendCommand(task.thapp, "blog enable");
// await _sendCommand(task.thapp, "blog enable");
await _verifyFirmware(task);
task.status = 'completed';
task.endTime = DateTime.now();
_updateUiProgress(task.mac, 100, 'completed');
@@ -162,13 +162,7 @@ class MultiDeviceFirmwareUpdater {
} finally {
_currentConcurrentUpgrades--;
_cleanupTask(task.mac);
_processUpgradeQueue();
try {
await _sendCommand(task.thapp, "blog enable");
} catch (e, stack) {
ef.log("[蓝牙指令执行日志] 重新开启日志失败: $e\n$stack");
}
_processUpgradeQueue(thapp);
}
}
@@ -192,88 +186,141 @@ class MultiDeviceFirmwareUpdater {
}
}
// Future<void> _sendFirmwareFrames(UpgradeTask task) async {
// final firmwareData = _firmwareDataCache[task.mac];
// if (firmwareData == null) {
// throw Exception("[蓝牙指令执行日志] 固件数据为空".tr);
// }
// final totalFrames =
// (firmwareData.length / UpgradeConfig.maxFrameSize).ceil();
// ef.log("[蓝牙指令执行日志] 固件总帧数:$totalFrames");
// final stopwatch = Stopwatch()..start();
// DateTime lastFrameTime = DateTime.now();
// for (int sentFrames = 0; sentFrames < totalFrames; sentFrames++) {
// if (task.status == 'cancelled') {
// throw Exception("[蓝牙指令执行日志] 升级已取消".tr);
// }
// final elapsed = stopwatch.elapsed;
// final frameInterval = UpgradeConfig.getFrameInterval(elapsed);
// final now = DateTime.now();
// if (now.difference(lastFrameTime) < frameInterval) {
// await Future.delayed(Duration(milliseconds: 10));
// continue;
// }
// final offset = sentFrames * UpgradeConfig.maxFrameSize;
// final end = offset + UpgradeConfig.maxFrameSize;
// final frameData = firmwareData.sublist(
// offset,
// end > firmwareData.length ? firmwareData.length : end,
// );
// final base64Data = base64Encode(frameData);
// final mmxCommand =
// '''mmx path="/root/mtd/update" write base64 len=${frameData.length} offset=$offset data="$base64Data"''';
// try {
// await _sendCommand(task.thapp, mmxCommand);
// await Future.delayed(Duration(milliseconds: sentFrames<500?100:10));
// } catch (e, stack) {
// ef.log("[蓝牙指令执行日志] 发送固件帧失败: $e\n$stack");
// rethrow;
// }
// final waitTime = frameInterval - now.difference(lastFrameTime);
// if (waitTime > Duration.zero) await Future.delayed(waitTime);
// final progress = ((sentFrames + 1) / totalFrames * 100).round();
// _updateUiProgress(task.mac, progress, 'upgrading');
// lastFrameTime = now;
// }
// stopwatch.stop();
// }
Future<void> _sendFirmwareFrames(UpgradeTask task) async {
final firmwareData = _firmwareDataCache[task.mac];
if (firmwareData == null) {
throw Exception("[蓝牙指令执行日志] 固件数据为空".tr);
}
final totalFrames =
(firmwareData.length / UpgradeConfig.maxFrameSize).ceil();
final stopwatch = Stopwatch()..start();
DateTime lastFrameTime = DateTime.now();
try {
ef.log("[蓝牙指令执行日志] 开始执行 OTA 升级流程");
for (int sentFrames = 0; sentFrames < totalFrames; sentFrames++) {
if (task.status == 'cancelled') {
throw Exception("[蓝牙指令执行日志] 升级已取消".tr);
}
final elapsed = stopwatch.elapsed;
final frameInterval = UpgradeConfig.getFrameInterval(elapsed);
final now = DateTime.now();
if (now.difference(lastFrameTime) < frameInterval) {
await Future.delayed(Duration(milliseconds: 10));
continue;
}
final offset = sentFrames * UpgradeConfig.maxFrameSize;
final end = offset + UpgradeConfig.maxFrameSize;
final frameData = firmwareData.sublist(
offset,
end > firmwareData.length ? firmwareData.length : end,
// 调用 THapp 封装的 otaStart 方法
int result = await task.thapp.otaStart(
firmwareData,
chunkSize: UpgradeConfig.maxFrameSize, // 单帧大小
retryPerChunk: 2, // 每帧重试次数
timeoutMs: 3000, // 每帧超时时间
firststepsframes: 300, // 前300帧延时发送防止过载
firststepdelayms: 30, // 前300帧延迟 30ms
onceDelayms: 10, // 之后帧间延迟
disableBlog: true, // 升级时关闭日志
withResponse: false, // 一般OTA不需要响应确认
binmode: false, // 使用文本命令模式发送mmx命令
onProgress: (double progress) {
// 更新 UI 进度
final percent = (progress * 100).clamp(0, 100).round();
_updateUiProgress(task.mac, percent, 'upgrading');
},
);
final base64Data = base64Encode(frameData);
final mmxCommand =
'''mmx path="/root/mtd/update" write base64 len=${frameData.length} offset=$offset data="$base64Data"''';
try {
await _sendCommand(task.thapp, mmxCommand);
} catch (e, stack) {
ef.log("[蓝牙指令执行日志] 发送固件帧失败: $e\n$stack");
rethrow;
// 根据返回码判断状态
switch (result) {
case 0:
ef.log("[蓝牙指令执行日志] OTA 升级完成 ✅");
_updateUiProgress(task.mac, 100, 'completed');
break;
case -1:
throw Exception("固件为空或格式错误");
case -2:
throw Exception("数据发送失败");
case -3:
throw Exception("日志操作失败");
case -4:
throw Exception("vota 命令执行失败");
default:
throw Exception("未知错误: $result");
}
final waitTime = frameInterval - now.difference(lastFrameTime);
if (waitTime > Duration.zero) await Future.delayed(waitTime);
final progress = ((sentFrames + 1) / totalFrames * 100).round();
_updateUiProgress(task.mac, progress, 'upgrading');
lastFrameTime = now;
} catch (e, stack) {
ef.log("[蓝牙指令执行日志] OTA 升级失败: $e\n$stack");
rethrow;
}
stopwatch.stop();
}
Future<void> _verifyFirmware(UpgradeTask task) async {
try {
final success = await _sendVotaCommand(task.thapp);
if (!success) {
throw Exception("[蓝牙指令执行日志] 固件验证失败".tr);
}
try {
final success = await _sendVotaCommand(task.thapp);
await Future.delayed(Duration(seconds: 10));
bool deviceRestarted = false;
for (int i = 0; i < 10; i++) {
if (!task.thapp.isConnected) {
deviceRestarted = true;
break;
if (!success) {
throw Exception("[蓝牙指令执行日志] 固件验证失败".tr);
}
await Future.delayed(Duration(seconds: 1));
}
if (!deviceRestarted) {
throw Exception("[蓝牙指令执行日志] 设备未重启,可能升级失败".tr);
await Future.delayed(Duration(seconds: 10));
bool deviceRestarted = false;
for (int i = 0; i < 10; i++) {
if (!task.thapp.isConnected) {
deviceRestarted = true;
break;
}
await Future.delayed(Duration(seconds: 1));
}
if (!deviceRestarted) {
throw Exception("[蓝牙指令执行日志] 设备未重启,可能升级失败".tr);
}
} catch (e, stack) {
ef.log("[蓝牙指令执行日志] 固件校验失败: $e\n$stack");
throw Exception("[蓝牙指令执行日志] 固件校验失败".tr);
}
} catch (e, stack) {
ef.log("[蓝牙指令执行日志] 固件校验失败: $e\n$stack");
throw Exception("[蓝牙指令执行日志] 固件校验失败".tr);
}
}
Future<dynamic> _sendCommand(THapp thapp, String command,
{bool needResponse = false}) async {
@@ -337,6 +384,7 @@ class MultiDeviceFirmwareUpdater {
"status": status,
"updateTime": DateTime.now().millisecondsSinceEpoch,
};
// ef.log("[蓝牙指令执行日志] 更新进度: $progress, 状态: $status");
controller.update();
}
}
@@ -429,7 +477,7 @@ class MultiDeviceFirmwareUpdater {
}
return false;
}, 0, 20000 // vota 命令可能需要更长时间
}, 3, 20000 // vota 命令可能需要更长时间
);
return result == true;