chore(project): 初始化项目基础配置文件
- 添加 CodeGraph、Android 和通用 gitignore 配置 - 创建项目元数据文件跟踪 Flutter 项目属性 - 添加 Codex AI 指导文档 AGENTS.md 说明项目架构 - 配置代码分析选项 analysis_options.yaml - 设置 Android 应用清单权限和 Kiosk 模式配置 - 实现中英文国际化支持 AppLocalizations - 配置 GoRouter 应用路由导航 - 创建明亮工业控制风格的主题配置 AppTheme
This commit is contained in:
190
lib/features/device/services/mock_runner.dart
Normal file
190
lib/features/device/services/mock_runner.dart
Normal file
@@ -0,0 +1,190 @@
|
||||
import 'dart:async';
|
||||
import '../../programs/models/step.dart';
|
||||
import '../../programs/models/program.dart';
|
||||
|
||||
/// 模拟运行器回调
|
||||
typedef RunProgressCallback = void Function(
|
||||
int currentStepIndex,
|
||||
int remainingSeconds,
|
||||
double progress,
|
||||
String currentWell,
|
||||
);
|
||||
|
||||
typedef RunCompleteCallback = void Function();
|
||||
|
||||
/// 模拟运行器
|
||||
/// 用于在没有实际硬件连接时模拟程序执行过程
|
||||
class MockRunner {
|
||||
Timer? _timer;
|
||||
Program? _currentProgram;
|
||||
List<Step> _steps = [];
|
||||
int _currentStepIndex = 0;
|
||||
int _remainingSeconds = 0;
|
||||
bool _isPaused = false;
|
||||
RunProgressCallback? _onProgress;
|
||||
RunCompleteCallback? _onComplete;
|
||||
|
||||
/// 是否正在运行
|
||||
bool get isRunning => _timer != null && !_isPaused;
|
||||
|
||||
/// 是否已暂停
|
||||
bool get isPaused => _isPaused;
|
||||
|
||||
/// 当前程序
|
||||
Program? get currentProgram => _currentProgram;
|
||||
|
||||
/// 开始运行程序
|
||||
void start(
|
||||
Program program,
|
||||
List<Step> steps,
|
||||
RunProgressCallback onProgress,
|
||||
RunCompleteCallback onComplete,
|
||||
) {
|
||||
_currentProgram = program;
|
||||
_steps = steps;
|
||||
_onProgress = onProgress;
|
||||
_onComplete = onComplete;
|
||||
_currentStepIndex = 0;
|
||||
_isPaused = false;
|
||||
|
||||
if (steps.isEmpty) {
|
||||
onComplete();
|
||||
return;
|
||||
}
|
||||
|
||||
// 开始执行第一个步骤
|
||||
_startStep(steps[0]);
|
||||
}
|
||||
|
||||
/// 暂停运行
|
||||
void pause() {
|
||||
if (_timer != null && !_isPaused) {
|
||||
_isPaused = true;
|
||||
_timer!.cancel();
|
||||
_timer = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// 继续运行
|
||||
void resume() {
|
||||
if (_isPaused && _currentProgram != null) {
|
||||
_isPaused = false;
|
||||
_resumeStep();
|
||||
}
|
||||
}
|
||||
|
||||
/// 停止运行
|
||||
void stop() {
|
||||
_timer?.cancel();
|
||||
_timer = null;
|
||||
_currentProgram = null;
|
||||
_steps = [];
|
||||
_currentStepIndex = 0;
|
||||
_remainingSeconds = 0;
|
||||
_isPaused = false;
|
||||
}
|
||||
|
||||
/// 开始执行步骤
|
||||
void _startStep(Step step) {
|
||||
// 计算步骤总时间(混合时间 + 吸磁时间 + 吹气时间)
|
||||
_remainingSeconds = step.mixTime + step.magnetTime + step.blowTime;
|
||||
|
||||
// 如果步骤时间为0,设置最小演示时间(5秒)
|
||||
if (_remainingSeconds == 0) {
|
||||
_remainingSeconds = 5;
|
||||
}
|
||||
|
||||
// 启动定时器,每秒更新
|
||||
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||
_remainingSeconds--;
|
||||
|
||||
// 计算总进度
|
||||
final totalSeconds = _calculateTotalSeconds();
|
||||
final elapsedSeconds = _calculateElapsedSeconds();
|
||||
final progress = totalSeconds > 0 ? elapsedSeconds / totalSeconds : 0.0;
|
||||
|
||||
// 回调进度更新
|
||||
_onProgress?.call(
|
||||
_currentStepIndex,
|
||||
_remainingSeconds,
|
||||
progress,
|
||||
step.position,
|
||||
);
|
||||
|
||||
// 步骤完成
|
||||
if (_remainingSeconds <= 0) {
|
||||
timer.cancel();
|
||||
_timer = null;
|
||||
_nextStep();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// 继续执行步骤(从暂停恢复)
|
||||
void _resumeStep() {
|
||||
if (_currentStepIndex >= _steps.length) return;
|
||||
|
||||
final step = _steps[_currentStepIndex];
|
||||
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||
_remainingSeconds--;
|
||||
|
||||
final totalSeconds = _calculateTotalSeconds();
|
||||
final elapsedSeconds = _calculateElapsedSeconds();
|
||||
final progress = totalSeconds > 0 ? elapsedSeconds / totalSeconds : 0.0;
|
||||
|
||||
_onProgress?.call(
|
||||
_currentStepIndex,
|
||||
_remainingSeconds,
|
||||
progress,
|
||||
step.position,
|
||||
);
|
||||
|
||||
if (_remainingSeconds <= 0) {
|
||||
timer.cancel();
|
||||
_timer = null;
|
||||
_nextStep();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// 执行下一个步骤
|
||||
void _nextStep() {
|
||||
_currentStepIndex++;
|
||||
|
||||
if (_currentStepIndex >= _steps.length) {
|
||||
// 所有步骤完成
|
||||
_onComplete?.call();
|
||||
stop();
|
||||
} else {
|
||||
// 执行下一个步骤
|
||||
_startStep(_steps[_currentStepIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
/// 计算总执行时间
|
||||
int _calculateTotalSeconds() {
|
||||
int total = 0;
|
||||
for (final step in _steps) {
|
||||
int stepTime = step.mixTime + step.magnetTime + step.blowTime;
|
||||
if (stepTime == 0) stepTime = 5;
|
||||
total += stepTime;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/// 计算已执行时间
|
||||
int _calculateElapsedSeconds() {
|
||||
int elapsed = 0;
|
||||
for (int i = 0; i < _currentStepIndex; i++) {
|
||||
int stepTime = _steps[i].mixTime + _steps[i].magnetTime + _steps[i].blowTime;
|
||||
if (stepTime == 0) stepTime = 5;
|
||||
elapsed += stepTime;
|
||||
}
|
||||
// 加上当前步骤已执行的时间
|
||||
final currentStep = _steps[_currentStepIndex];
|
||||
int currentStepTime = currentStep.mixTime + currentStep.magnetTime + currentStep.blowTime;
|
||||
if (currentStepTime == 0) currentStepTime = 5;
|
||||
elapsed += currentStepTime - _remainingSeconds;
|
||||
return elapsed;
|
||||
}
|
||||
}
|
||||
114
lib/features/device/services/mock_runner_impl.dart
Normal file
114
lib/features/device/services/mock_runner_impl.dart
Normal file
@@ -0,0 +1,114 @@
|
||||
import '../../programs/models/program.dart';
|
||||
import '../../programs/models/step.dart';
|
||||
import 'runner_interface.dart';
|
||||
|
||||
/// 模拟运行器(用于开发测试)
|
||||
/// 模拟硬件运行过程
|
||||
class MockRunner implements Runner {
|
||||
@override
|
||||
RunnerStatus status = RunnerStatus.idle;
|
||||
|
||||
bool _isRunning = false;
|
||||
int _currentStep = 0;
|
||||
int _remainingSeconds = 0;
|
||||
RunnerCallbacks? _callbacks;
|
||||
List<Step> _steps = [];
|
||||
|
||||
@override
|
||||
void start(Program program, List<Step> steps, RunnerCallbacks callbacks) {
|
||||
if (steps.isEmpty) {
|
||||
callbacks.onError?.call('No steps to run');
|
||||
status = RunnerStatus.error;
|
||||
return;
|
||||
}
|
||||
|
||||
_steps = steps;
|
||||
_callbacks = callbacks;
|
||||
_currentStep = 0;
|
||||
_isRunning = true;
|
||||
status = RunnerStatus.running;
|
||||
|
||||
// 开始模拟运行
|
||||
_runSimulation();
|
||||
}
|
||||
|
||||
void _runSimulation() {
|
||||
if (!_isRunning || _currentStep >= _steps.length) {
|
||||
_completeRun();
|
||||
return;
|
||||
}
|
||||
|
||||
final step = _steps[_currentStep];
|
||||
// 计算步骤时间(混合时间 + 吸磁时间 + 吹气时间 + 5秒最小)
|
||||
final stepTime = (step.mixTime ?? 0) + (step.magnetTime ?? 0) + (step.blowTime ?? 0) + 5;
|
||||
_remainingSeconds = stepTime.clamp(5, 300);
|
||||
|
||||
// 模拟倒计时
|
||||
_simulateStepProgress(stepTime);
|
||||
}
|
||||
|
||||
void _simulateStepProgress(int totalSeconds) {
|
||||
// 简化模拟:每秒更新进度
|
||||
int elapsed = 0;
|
||||
while (_isRunning && elapsed < totalSeconds) {
|
||||
elapsed++;
|
||||
final remaining = totalSeconds - elapsed;
|
||||
final progress = elapsed / totalSeconds;
|
||||
|
||||
_callbacks?.onProgress?.call(
|
||||
_currentStep,
|
||||
remaining,
|
||||
(_currentStep + progress) / _steps.length,
|
||||
_steps[_currentStep].position,
|
||||
);
|
||||
|
||||
// 实际实现需要使用 Timer
|
||||
// await Future.delayed(Duration(seconds: 1));
|
||||
}
|
||||
|
||||
if (_isRunning) {
|
||||
_currentStep++;
|
||||
_runSimulation();
|
||||
}
|
||||
}
|
||||
|
||||
void _completeRun() {
|
||||
status = RunnerStatus.completed;
|
||||
_isRunning = false;
|
||||
_callbacks?.onComplete?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
void pause() {
|
||||
if (status == RunnerStatus.running) {
|
||||
_isRunning = false;
|
||||
status = RunnerStatus.paused;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void resume() {
|
||||
if (status == RunnerStatus.paused) {
|
||||
_isRunning = true;
|
||||
status = RunnerStatus.running;
|
||||
// 继续运行
|
||||
_runSimulation();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void stop() {
|
||||
_isRunning = false;
|
||||
status = RunnerStatus.idle;
|
||||
_currentStep = 0;
|
||||
_remainingSeconds = 0;
|
||||
}
|
||||
|
||||
@override
|
||||
RunnerStatus getStatus() => status;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
54
lib/features/device/services/runner_interface.dart
Normal file
54
lib/features/device/services/runner_interface.dart
Normal file
@@ -0,0 +1,54 @@
|
||||
import '../../programs/models/program.dart';
|
||||
import '../../programs/models/step.dart';
|
||||
|
||||
/// 运行器状态
|
||||
enum RunnerStatus {
|
||||
idle,
|
||||
running,
|
||||
paused,
|
||||
completed,
|
||||
error,
|
||||
}
|
||||
|
||||
/// 运行器回调
|
||||
class RunnerCallbacks {
|
||||
/// 步骤进度回调: (stepIndex, remainingSeconds, progress, currentWell)
|
||||
final void Function(int stepIndex, int remainingSeconds, double progress, String well)? onProgress;
|
||||
|
||||
/// 运行完成回调
|
||||
final void Function()? onComplete;
|
||||
|
||||
/// 错误回调
|
||||
final void Function(String error)? onError;
|
||||
|
||||
const RunnerCallbacks({
|
||||
this.onProgress,
|
||||
this.onComplete,
|
||||
this.onError,
|
||||
});
|
||||
}
|
||||
|
||||
/// 运行器抽象接口
|
||||
/// 定义硬件运行控制的标准接口
|
||||
abstract class Runner {
|
||||
/// 当前状态
|
||||
RunnerStatus status = RunnerStatus.idle;
|
||||
|
||||
/// 启动程序运行
|
||||
void start(Program program, List<Step> steps, RunnerCallbacks callbacks);
|
||||
|
||||
/// 暂停运行
|
||||
void pause();
|
||||
|
||||
/// 继续运行
|
||||
void resume();
|
||||
|
||||
/// 停止运行
|
||||
void stop();
|
||||
|
||||
/// 获取当前状态
|
||||
RunnerStatus getStatus();
|
||||
|
||||
/// 释放资源
|
||||
void dispose();
|
||||
}
|
||||
91
lib/features/device/services/serial_runner.dart
Normal file
91
lib/features/device/services/serial_runner.dart
Normal file
@@ -0,0 +1,91 @@
|
||||
import '../../programs/models/program.dart';
|
||||
import '../../programs/models/step.dart';
|
||||
import 'runner_interface.dart';
|
||||
|
||||
/// 串口运行器(真实硬件实现)
|
||||
/// 实现与设备的串口通信
|
||||
class SerialRunner implements Runner {
|
||||
@override
|
||||
RunnerStatus status = RunnerStatus.idle;
|
||||
|
||||
/// 串口配置
|
||||
final String portName;
|
||||
final int baudRate;
|
||||
final int dataBits;
|
||||
final int stopBits;
|
||||
|
||||
SerialRunner({
|
||||
this.portName = '/dev/ttyUSB0',
|
||||
this.baudRate = 9600,
|
||||
this.dataBits = 8,
|
||||
this.stopBits = 1,
|
||||
});
|
||||
|
||||
@override
|
||||
void start(Program program, List<Step> steps, RunnerCallbacks callbacks) {
|
||||
// TODO: 实现串口通信启动逻辑
|
||||
// 1. 打开串口连接
|
||||
// 2. 发送程序配置
|
||||
// 3. 按步骤发送控制指令
|
||||
// 4. 接收设备反馈并更新状态
|
||||
|
||||
status = RunnerStatus.running;
|
||||
|
||||
// 示例:发送启动指令
|
||||
// _sendCommand('START', program.code);
|
||||
|
||||
// 示例:监听设备状态
|
||||
// _listenToDevice(callbacks);
|
||||
}
|
||||
|
||||
@override
|
||||
void pause() {
|
||||
if (status == RunnerStatus.running) {
|
||||
// _sendCommand('PAUSE');
|
||||
status = RunnerStatus.paused;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void resume() {
|
||||
if (status == RunnerStatus.paused) {
|
||||
// _sendCommand('RESUME');
|
||||
status = RunnerStatus.running;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void stop() {
|
||||
// _sendCommand('STOP');
|
||||
// _closeConnection();
|
||||
status = RunnerStatus.idle;
|
||||
}
|
||||
|
||||
@override
|
||||
RunnerStatus getStatus() => status;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
stop();
|
||||
}
|
||||
|
||||
/// 发送控制指令(待硬件协议确定后实现)
|
||||
Future<void> _sendCommand(String command, [String? data]) async {
|
||||
// TODO: 根据硬件通信协议实现
|
||||
// 示例协议格式: [CMD:data] 或 二进制协议
|
||||
}
|
||||
|
||||
/// 监听设备反馈(待硬件协议确定后实现)
|
||||
void _listenToDevice(RunnerCallbacks callbacks) {
|
||||
// TODO: 解析设备返回的状态数据
|
||||
// 状态格式示例: [STEP:1,TIME:60,POS:A1]
|
||||
}
|
||||
|
||||
/// 执行单个步骤
|
||||
Future<void> _executeStep(Step step) async {
|
||||
// TODO: 根据步骤参数生成控制指令
|
||||
// 混合: MIX(position, time, speed)
|
||||
// 吸磁: MAGNET(position, time)
|
||||
// 吹气: BLOW(position, speed, time)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user