feat(device): 添加USB设备通信支持和程序参数优化

- 在AndroidManifest.xml中添加USB Host权限和设备过滤器配置
- 新增设备控制国际化词条包括速度档位、吹气时间等
- 重构数据库结构将速度相关字段统一为档位数值存储
- 添加通用KV存储方法用于settings表数据读写
- 优化首页导航实现tab间跳转和状态保持功能
- 更新程序详情页面布局和参数表单界面
- 移除模拟运行器相关测试代码
- 添加USB串口通信依赖包usb_serial
This commit is contained in:
Developer
2026-06-04 15:13:36 +08:00
parent 67e2c7c76c
commit d53c41c300
24 changed files with 795 additions and 635 deletions

View File

@@ -0,0 +1,126 @@
import 'dart:convert';
/// 串口奇偶校验
enum SerialParity { none, odd, even, mark, space }
/// 串口流控
enum SerialFlowControl { none, rtsCts, xonXoff, dtrDsr }
/// 串口配置
///
/// 持久化到 settings 表的 `serial_config` key 中;
/// 打开串口时根据此配置构造底层 `UsbConfig`。
class SerialConfig {
/// 设备 Vendor ID十六进制
final int vendorId;
/// 设备 Product ID十六进制0 表示不指定
final int productId;
/// 波特率
final int baudRate;
/// 数据位 (5/6/7/8)
final int dataBits;
/// 停止位 (1/2)
final int stopBits;
/// 校验位
final SerialParity parity;
/// 流控
final SerialFlowControl flowControl;
/// 读超时(毫秒)
final int readTimeoutMs;
/// 写超时(毫秒)
final int writeTimeoutMs;
const SerialConfig({
this.vendorId = 0x1A86,
this.productId = 0x7523,
this.baudRate = 9600,
this.dataBits = 8,
this.stopBits = 1,
this.parity = SerialParity.none,
this.flowControl = SerialFlowControl.none,
this.readTimeoutMs = 2000,
this.writeTimeoutMs = 2000,
});
/// 默认配置
static const SerialConfig defaults = SerialConfig();
/// 常用波特率
static const List<int> commonBaudRates = [
1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800,
];
SerialConfig copyWith({
int? vendorId,
int? productId,
int? baudRate,
int? dataBits,
int? stopBits,
SerialParity? parity,
SerialFlowControl? flowControl,
int? readTimeoutMs,
int? writeTimeoutMs,
}) {
return SerialConfig(
vendorId: vendorId ?? this.vendorId,
productId: productId ?? this.productId,
baudRate: baudRate ?? this.baudRate,
dataBits: dataBits ?? this.dataBits,
stopBits: stopBits ?? this.stopBits,
parity: parity ?? this.parity,
flowControl: flowControl ?? this.flowControl,
readTimeoutMs: readTimeoutMs ?? this.readTimeoutMs,
writeTimeoutMs: writeTimeoutMs ?? this.writeTimeoutMs,
);
}
/// 编码为 JSON 字符串(用于持久化)
String toJsonString() => jsonEncode({
'vendorId': vendorId,
'productId': productId,
'baudRate': baudRate,
'dataBits': dataBits,
'stopBits': stopBits,
'parity': parity.name,
'flowControl': flowControl.name,
'readTimeoutMs': readTimeoutMs,
'writeTimeoutMs': writeTimeoutMs,
});
/// 从 JSON 字符串解码;解析失败时返回默认值
factory SerialConfig.fromJsonString(String? raw) {
if (raw == null || raw.isEmpty) return defaults;
try {
final map = jsonDecode(raw) as Map<String, dynamic>;
return SerialConfig(
vendorId: (map['vendorId'] as num?)?.toInt() ?? defaults.vendorId,
productId: (map['productId'] as num?)?.toInt() ?? defaults.productId,
baudRate: (map['baudRate'] as num?)?.toInt() ?? defaults.baudRate,
dataBits: (map['dataBits'] as num?)?.toInt() ?? defaults.dataBits,
stopBits: (map['stopBits'] as num?)?.toInt() ?? defaults.stopBits,
parity: SerialParity.values.firstWhere(
(e) => e.name == map['parity'],
orElse: () => defaults.parity,
),
flowControl: SerialFlowControl.values.firstWhere(
(e) => e.name == map['flowControl'],
orElse: () => defaults.flowControl,
),
readTimeoutMs:
(map['readTimeoutMs'] as num?)?.toInt() ?? defaults.readTimeoutMs,
writeTimeoutMs:
(map['writeTimeoutMs'] as num?)?.toInt() ?? defaults.writeTimeoutMs,
);
} catch (_) {
return defaults;
}
}
}