feat(device): 启动自动连接 USB 串口 + 隐藏设置页配置项 + 标题栏连接状态
- 新增 AutoSerialConnect 服务:启动后自动连接第一个 USB 串口设备, 固定 115200/8/N/1,连接失败时每 3s 重试,断开后重新进入重试循环 - main.dart 通过 ProviderContainer 在 runApp 之前触发 autoSerialConnectProvider - 移除设置页「串口配置」菜单项及对应面板分支 - StatusBar 在「设备运行状态」前增加串口连接状态指示(已连接/连接中/未连接)
This commit is contained in:
@@ -2,6 +2,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../../../core/database/database_service.dart';
|
||||
import '../models/serial_config.dart';
|
||||
import '../services/auto_serial_connect.dart';
|
||||
import '../services/device_message_service.dart';
|
||||
import '../services/json_protocol.dart';
|
||||
import '../services/runner_interface.dart';
|
||||
@@ -15,6 +16,18 @@ final serialPortServiceProvider = Provider<SerialPortService>((ref) {
|
||||
return service;
|
||||
});
|
||||
|
||||
/// 启动自动连接服务
|
||||
///
|
||||
/// 通过 [main] 中的 ProviderContainer 在 runApp 之前触发一次,
|
||||
/// 服务内部立即尝试连接第一个 USB 串口设备,失败时按 3s 间隔重试。
|
||||
final autoSerialConnectProvider = Provider<AutoSerialConnect>((ref) {
|
||||
final service = ref.watch(serialPortServiceProvider);
|
||||
final auto = AutoSerialConnect(service);
|
||||
auto.start();
|
||||
ref.onDispose(auto.dispose);
|
||||
return auto;
|
||||
});
|
||||
|
||||
/// JSON 协议编解码器(可在调试/真机协议不一致时整体替换)
|
||||
final jsonProtocolProvider = Provider<JsonProtocolService>((ref) {
|
||||
return JsonProtocolService();
|
||||
|
||||
109
lib/features/device/services/auto_serial_connect.dart
Normal file
109
lib/features/device/services/auto_serial_connect.dart
Normal file
@@ -0,0 +1,109 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:usb_serial/usb_serial.dart';
|
||||
|
||||
import '../models/serial_config.dart';
|
||||
import 'device_log.dart';
|
||||
import 'serial_port_service.dart';
|
||||
|
||||
/// 启动自动连接服务
|
||||
///
|
||||
/// App 启动时调用 [start],自动连接第一个可用的 USB 串口设备:
|
||||
/// - 固定 115200 波特率 / 8 数据位 / 1 停止位 / 默认其它
|
||||
/// - 连接失败时每 3 秒重试一次
|
||||
/// - 连接成功后停止重试;连接断开后重新进入重试循环
|
||||
class AutoSerialConnect {
|
||||
/// 重试间隔
|
||||
static const Duration retryInterval = Duration(seconds: 3);
|
||||
|
||||
/// 自动连接使用的固定参数
|
||||
static const SerialConfig autoConfig = SerialConfig(
|
||||
baudRate: 115200,
|
||||
dataBits: 8,
|
||||
stopBits: 1,
|
||||
);
|
||||
|
||||
final SerialPortService _service;
|
||||
Timer? _retryTimer;
|
||||
StreamSubscription<SerialConnectionState>? _stateSub;
|
||||
bool _disposed = false;
|
||||
|
||||
AutoSerialConnect(this._service);
|
||||
|
||||
/// 启动自动连接:立即尝试一次,失败则按 [retryInterval] 周期重试
|
||||
void start() {
|
||||
if (_stateSub != null) return;
|
||||
_stateSub = _service.connectionStateChanges.listen(_onStateChange);
|
||||
unawaited(_tryConnect());
|
||||
}
|
||||
|
||||
void _onStateChange(SerialConnectionState s) {
|
||||
if (_disposed) return;
|
||||
switch (s) {
|
||||
case SerialConnectionState.connected:
|
||||
// 连接成功:停止重试
|
||||
_cancelRetry();
|
||||
case SerialConnectionState.disconnected:
|
||||
case SerialConnectionState.error:
|
||||
// 设备断开或出错:进入重试
|
||||
_scheduleRetry();
|
||||
case SerialConnectionState.connecting:
|
||||
// 正在连接中,忽略
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _tryConnect() async {
|
||||
if (_disposed) return;
|
||||
if (_service.isConnected ||
|
||||
_service.state == SerialConnectionState.connecting) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<UsbDevice> devices;
|
||||
try {
|
||||
devices = await _service.listDevices();
|
||||
} catch (e) {
|
||||
DeviceLog.warn('列出 USB 设备失败: $e,${retryInterval.inSeconds}s 后重试');
|
||||
_scheduleRetry();
|
||||
return;
|
||||
}
|
||||
|
||||
if (devices.isEmpty) {
|
||||
DeviceLog.info('未检测到 USB 串口设备,${retryInterval.inSeconds}s 后重试');
|
||||
_scheduleRetry();
|
||||
return;
|
||||
}
|
||||
|
||||
final device = devices.first;
|
||||
final ok = await _service.connect(device, autoConfig);
|
||||
if (!ok) {
|
||||
DeviceLog.warn('串口自动连接失败: '
|
||||
'${_service.lastError ?? "未知错误"},${retryInterval.inSeconds}s 后重试');
|
||||
_scheduleRetry();
|
||||
}
|
||||
}
|
||||
|
||||
void _scheduleRetry() {
|
||||
if (_disposed) return;
|
||||
if (_retryTimer != null) return;
|
||||
_retryTimer = Timer(retryInterval, () {
|
||||
_retryTimer = null;
|
||||
unawaited(_tryConnect());
|
||||
});
|
||||
}
|
||||
|
||||
void _cancelRetry() {
|
||||
_retryTimer?.cancel();
|
||||
_retryTimer = null;
|
||||
}
|
||||
|
||||
/// 释放资源
|
||||
Future<void> dispose() async {
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
_cancelRetry();
|
||||
await _stateSub?.cancel();
|
||||
_stateSub = null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user