198 lines
6.4 KiB
Dart
198 lines
6.4 KiB
Dart
import 'dart:async';
|
||
import 'dart:convert';
|
||
import 'dart:ffi';
|
||
|
||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||
import 'package:maibu_satabot_v2/features/remote_control/data/models/running_status_model.dart';
|
||
import 'package:maibu_satabot_v2/features/remote_control/presentation/bloc/remote_control_state.dart';
|
||
|
||
import '../../../../core/network/net_message_dispatcher.dart';
|
||
import '../../domain/entities/machine_control_status_entity.dart';
|
||
import '../../domain/repositories/remote_control_repository.dart';
|
||
import '../../domain/usecase/remote_control_usecase.dart';
|
||
|
||
class RemoteControlCubit extends Cubit<RemoteControlState> {
|
||
final RemoteControlRepository _repository;
|
||
final RequestControlPermissionUseCase _requestControlPermissionUseCase;
|
||
Timer? _timer;
|
||
StreamSubscription? _kickOutSub; // 新增:用于管理监听生命周期
|
||
final NetMessageDispatcher dispatcher;
|
||
|
||
RemoteControlCubit(this._repository, this._requestControlPermissionUseCase, this.dispatcher)
|
||
: super(
|
||
RemoteControlState(
|
||
controlEntity: MachineControlStatusEntity(),
|
||
runningStatusModel: RunningStatusModel(),
|
||
),
|
||
) {
|
||
_initPacketListener();
|
||
}
|
||
|
||
// 1. 初始化回包监听 (如 0x12 权限)
|
||
// void _initPacketListener() {
|
||
// _repository.responseStream.listen((packet) {
|
||
// if (packet.command == 0x12) {
|
||
// // 根据负载判断是否有权限,更新状态
|
||
// emit(state.copyWith(hasPermission: true));
|
||
// }
|
||
// });
|
||
// }
|
||
void _initPacketListener() {
|
||
print('>>> [RemoteControl] begin 初始化 0x12 监听器');
|
||
_kickOutSub?.cancel(); // 防止重复监听
|
||
|
||
_kickOutSub = dispatcher.onCommand(0x12).listen((packet) {
|
||
print('>>> [RemoteControl] 收到 0x12 原始包,payload 长度=${packet.payload.length}');
|
||
|
||
try {
|
||
// 🔥 关键:手动去掉最后 2 个 CRC 字节
|
||
String jsonString;
|
||
if (packet.payload.length > 2) {
|
||
jsonString = utf8.decode(packet.payload.sublist(0, packet.payload.length - 2));
|
||
} else {
|
||
jsonString = utf8.decode(packet.payload);
|
||
}
|
||
|
||
print('>>> [RemoteControl] 去除 CRC 后的 JSON: $jsonString');
|
||
|
||
final jsonMap = jsonDecode(jsonString);
|
||
final respond = jsonMap['request'] ?? '';
|
||
print('>>> [RemoteControl] ✅ 响应结果:$respond');
|
||
// 🔥 当 Web 端推送 switch_control 权限时,更新状态触发弹窗
|
||
if (respond == 'switch_control') {
|
||
print('>>> [RemoteControl] ✅ 获得控制权 (respond=switch_control),准备打开弹窗');
|
||
emit(state.copyWith(hasPermission: true, showPermissionRequestDialog: true));
|
||
} else if (respond == 'have_logged_in') {
|
||
// 如果是异地登录,也显示弹窗提示
|
||
print('>>> [RemoteControl] ⚠️ 检测到异地登录');
|
||
emit(state.copyWith(showPermissionRequestDialog: true));
|
||
}
|
||
} catch (e) {
|
||
print('>>> [RemoteControl] ❌ 解析失败:$e');
|
||
}
|
||
});
|
||
|
||
print('>>> [RemoteControl] ✅ 0x12 监听器已建立完成');
|
||
}
|
||
|
||
// 2. 开启 100ms 控制循环 (在进入遥控页面或点击“开始”时调用)
|
||
void startControlLoop() {
|
||
_timer?.cancel();
|
||
_timer = Timer.periodic(const Duration(milliseconds: 100), (timer) {
|
||
// 核心调用:直接把 state 里的实体丢给 repository
|
||
_repository.sendControlMachineCmd(state.controlEntity);
|
||
});
|
||
emit(state.copyWith(status: RemoteControlStatus.controlling));
|
||
}
|
||
|
||
// 3. 更新摇杆数据
|
||
void updateJoystick(double x, double y) {
|
||
final updatedEntity = state.controlEntity.copyWith(
|
||
x: x.toInt(),
|
||
y: y.toInt(),
|
||
);
|
||
emit(state.copyWith(controlEntity: updatedEntity));
|
||
}
|
||
|
||
// 4. 更新功能开关 (比如割刀速度、灯光、点火等)
|
||
void updateFunction({int? mower, int? lift, int? ignition, bool? emergency}) {
|
||
final updatedEntity = state.controlEntity.copyWith(
|
||
mower: mower,
|
||
lift: lift,
|
||
ignition: ignition,
|
||
emergency: emergency,
|
||
);
|
||
emit(state.copyWith(controlEntity: updatedEntity));
|
||
}
|
||
|
||
void updateOriginY(int y) {
|
||
final updatedEntity = state.controlEntity.copyWith(
|
||
y: y,
|
||
);
|
||
emit(state.copyWith(controlEntity: updatedEntity));
|
||
}
|
||
void updateOriginX(int x) {
|
||
final updatedEntity = state.controlEntity.copyWith(
|
||
x: x,
|
||
);
|
||
emit(state.copyWith(controlEntity: updatedEntity));
|
||
}
|
||
|
||
// 5. 停止控制循环
|
||
void stopControlLoop() {
|
||
_timer?.cancel();
|
||
_timer = null;
|
||
emit(state.copyWith(status: RemoteControlStatus.initial));
|
||
}
|
||
|
||
void toggleLock() {}
|
||
|
||
void togglePermissionDialog(bool show) {
|
||
emit(state.copyWith(showPermissionRequestDialog: show));
|
||
}
|
||
|
||
void requestControlPermission() {
|
||
// 1. 关闭弹窗
|
||
emit(state.copyWith(showPermissionRequestDialog: false));
|
||
|
||
// 2. 这里执行你发送 0x12 指令的逻辑
|
||
// _sendProtocolData(0x12, ...);
|
||
}
|
||
|
||
void toggleLeftPip() => emit(state.copyWith(showLeftPip: !state.showLeftPip));
|
||
void toggleRightPip() =>
|
||
emit(state.copyWith(showRightPip: !state.showRightPip));
|
||
|
||
@override
|
||
Future<void> close() {
|
||
_timer?.cancel(); // 退出页面时务必销毁定时器
|
||
return super.close();
|
||
}
|
||
|
||
void updateChassisLift(int i) {}
|
||
|
||
void updateEmergency(bool bool) {}
|
||
|
||
void respondPermission(bool bool) {}
|
||
|
||
void requestControlPermissionS(String deviceName, String deviceId) async {
|
||
// 1. 关闭弹窗
|
||
emit(state.copyWith(showPermissionRequestDialog: false));
|
||
|
||
// 2. 调用 UseCase
|
||
final result = await _requestControlPermissionUseCase(
|
||
RequestControlPermissionParams(
|
||
deviceName: deviceName,
|
||
deviceId: deviceId,
|
||
),
|
||
);
|
||
|
||
// 3. 处理结果
|
||
result.fold(
|
||
(failure) {
|
||
print('❌ [RemoteControl] 请求控制权限失败:${failure.message}');
|
||
// 可以在这里显示错误提示或重新打开弹窗
|
||
emit(state.copyWith(showPermissionRequestDialog: true));
|
||
|
||
},
|
||
(success) {
|
||
// 更新状态
|
||
print('✅ [RemoteControl] 请求控制权限成功:$success');
|
||
///处理result
|
||
if(success){
|
||
emit(state.copyWith(hasPermission: true));
|
||
}else{
|
||
emit(state.copyWith(hasPermission: false));
|
||
}
|
||
print('✅ c:$success');
|
||
// 权限申请已发送,等待 0x12 回包更新状态
|
||
},
|
||
);
|
||
}
|
||
|
||
|
||
|
||
|
||
}
|
||
|