338 lines
10 KiB
C#
338 lines
10 KiB
C#
|
|
using System;
|
||
|
|
using System.Collections;
|
||
|
|
using UnityEngine;
|
||
|
|
using UnityEngine.UI;
|
||
|
|
using TMPro;
|
||
|
|
|
||
|
|
public class StandByPanel : BasePanel
|
||
|
|
{
|
||
|
|
|
||
|
|
[Header("UI组件")]
|
||
|
|
public Image CompanyLogoImage; // 公司图标
|
||
|
|
public Image LoadingProgressBar; // 加载进度条
|
||
|
|
public TextMeshProUGUI LoadingStatusText; // 加载状态文本
|
||
|
|
private CanvasGroup SplashCanvasGroup; // 启动界面Canvas Group用于淡入淡出
|
||
|
|
|
||
|
|
[Header("动画参数")]
|
||
|
|
[SerializeField] private float LogoFadeInDuration = 0.5f; // 图标淡入时间
|
||
|
|
[SerializeField] private float MinSplashDuration = 3f; // 最小启动界面显示时间(秒)
|
||
|
|
[SerializeField] private float ConnectionTimeOut = 10f; // 连接超时时间(秒)
|
||
|
|
[SerializeField] private float FadeOutDuration = 0.5f; // 淡出时间
|
||
|
|
|
||
|
|
[Header("串口配置")]
|
||
|
|
[SerializeField] private string WindowsPortName = "COM1"; // Windows 默认串口名
|
||
|
|
[SerializeField] private string AndroidPortPath = "/dev/ttyS4"; // 安卓默认设备路径(示例)
|
||
|
|
[SerializeField] private int DefaultBaudRate = 115200; // 默认波特率
|
||
|
|
|
||
|
|
|
||
|
|
private SerialCommunicationService _serialService;
|
||
|
|
private DCSAlarmManager _alarmManager;
|
||
|
|
private bool _isConnectionSuccessful = true;
|
||
|
|
private bool _communicationErrorDetected = false;
|
||
|
|
private DateTime _startTime;
|
||
|
|
|
||
|
|
private const string COMMUNICATION_ERROR_TITLE = "通讯异常";
|
||
|
|
private const string COMMUNICATION_ERROR_MESSAGE = "设备通讯异常,请检查:\n1. 数据线连接是否正常\n2. 设备是否已开启\n3. 重启应用重新尝试\n\n无法进入应用。";
|
||
|
|
|
||
|
|
public override void Init()
|
||
|
|
{
|
||
|
|
// 获取服务
|
||
|
|
_serialService = ServiceLocator.Get<ISerialCommunicationService>() as SerialCommunicationService;
|
||
|
|
_alarmManager = DCSAlarmManager.Instance;
|
||
|
|
|
||
|
|
InitializeUI();
|
||
|
|
|
||
|
|
_startTime = DateTime.Now;
|
||
|
|
StartCoroutine(InitializationSequence());
|
||
|
|
}
|
||
|
|
|
||
|
|
private void InitializeUI()
|
||
|
|
{
|
||
|
|
// 确保Canvas Group存在
|
||
|
|
if (SplashCanvasGroup == null)
|
||
|
|
{
|
||
|
|
SplashCanvasGroup = GetComponent<CanvasGroup>();
|
||
|
|
if (SplashCanvasGroup == null)
|
||
|
|
{
|
||
|
|
SplashCanvasGroup = gameObject.AddComponent<CanvasGroup>();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 初始化进度条
|
||
|
|
if (LoadingProgressBar != null)
|
||
|
|
{
|
||
|
|
LoadingProgressBar.fillAmount = 0f;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 初始化文本
|
||
|
|
if (LoadingStatusText != null)
|
||
|
|
{
|
||
|
|
LoadingStatusText.text = "初始化中...";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 启动序列:动画 -> 连接 -> 验证 -> 进入界面
|
||
|
|
/// </summary>
|
||
|
|
private IEnumerator InitializationSequence()
|
||
|
|
{
|
||
|
|
// Step 1: 淡入公司图标
|
||
|
|
yield return StartCoroutine(FadeInLogo());
|
||
|
|
|
||
|
|
// Step 2: 在动画期间进行串口连接
|
||
|
|
UpdateLoadingStatus("连接设备中...", 0.2f);
|
||
|
|
yield return StartCoroutine(ConnectSerialPort());
|
||
|
|
|
||
|
|
// Step 3: 检查通讯状态
|
||
|
|
UpdateLoadingStatus("验证通讯中...", 0.5f);
|
||
|
|
yield return StartCoroutine(VerifyCommunication());
|
||
|
|
|
||
|
|
// Step 4: 确保最小显示时间
|
||
|
|
float elapsedTime = (float)(DateTime.Now - _startTime).TotalSeconds;
|
||
|
|
if (elapsedTime < MinSplashDuration)
|
||
|
|
{
|
||
|
|
UpdateLoadingStatus("准备就绪...", 0.8f);
|
||
|
|
yield return new WaitForSeconds(MinSplashDuration - elapsedTime);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Step 5: 根据连接结果处理
|
||
|
|
if (_communicationErrorDetected)
|
||
|
|
{
|
||
|
|
yield return StartCoroutine(ShowCommunicationErrorDialog());
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
UpdateLoadingStatus("进入应用...", 1f);
|
||
|
|
yield return StartCoroutine(FadeOutAndEnterApp());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 淡入公司图标
|
||
|
|
/// </summary>
|
||
|
|
private IEnumerator FadeInLogo()
|
||
|
|
{
|
||
|
|
if (CompanyLogoImage != null)
|
||
|
|
{
|
||
|
|
CompanyLogoImage.color = new Color(1, 1, 1, 0);
|
||
|
|
|
||
|
|
float elapsedTime = 0f;
|
||
|
|
while (elapsedTime < LogoFadeInDuration)
|
||
|
|
{
|
||
|
|
elapsedTime += Time.deltaTime;
|
||
|
|
float alpha = Mathf.Clamp01(elapsedTime / LogoFadeInDuration);
|
||
|
|
CompanyLogoImage.color = new Color(1, 1, 1, alpha);
|
||
|
|
yield return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
CompanyLogoImage.color = new Color(1, 1, 1, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
yield return new WaitForSeconds(0.5f);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 连接串口
|
||
|
|
/// </summary>
|
||
|
|
private IEnumerator ConnectSerialPort()
|
||
|
|
{
|
||
|
|
if (_serialService == null)
|
||
|
|
{
|
||
|
|
Debug.LogError("[SplashScreen] SerialCommunicationService not found!");
|
||
|
|
_isConnectionSuccessful = false;
|
||
|
|
yield break;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 订阅通讯错误事件
|
||
|
|
_serialService.OnCommunicationError -= OnSerialCommunicationError;
|
||
|
|
_serialService.OnCommunicationError += OnSerialCommunicationError;
|
||
|
|
|
||
|
|
// 尝试连接
|
||
|
|
float connectionStartTime = Time.time;
|
||
|
|
|
||
|
|
// 根据平台选择串口名/设备路径
|
||
|
|
string portName = GetPortNameForPlatform();
|
||
|
|
UpdateLoadingStatus($"正在连接: {portName} @ {DefaultBaudRate}", 0.25f);
|
||
|
|
Debug.Log($"[SplashScreen] 尝试连接串口: {portName} @ {DefaultBaudRate}");
|
||
|
|
bool connected = _serialService.Connect(portName, DefaultBaudRate);
|
||
|
|
|
||
|
|
if (!connected)
|
||
|
|
{
|
||
|
|
Debug.LogWarning("[SplashScreen] Failed to connect serial port");
|
||
|
|
_isConnectionSuccessful = false;
|
||
|
|
_communicationErrorDetected = true;
|
||
|
|
yield break;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Debug.Log("[SplashScreen] Serial port connected, waiting for handshake...");
|
||
|
|
// _serialService.SendHandshakeRequest();
|
||
|
|
|
||
|
|
// // 等待握手完成或超时
|
||
|
|
// float timeoutTime = Time.time + ConnectionTimeOut;
|
||
|
|
// while (!_serialService.IsHandshakeCompleted && Time.time < timeoutTime)
|
||
|
|
// {
|
||
|
|
// yield return new WaitForSeconds(0.1f);
|
||
|
|
// }
|
||
|
|
|
||
|
|
// if (!_serialService.IsHandshakeCompleted)
|
||
|
|
// {
|
||
|
|
// Debug.LogWarning("[SplashScreen] Serial handshake timeout!");
|
||
|
|
// _communicationErrorDetected = true;
|
||
|
|
// }
|
||
|
|
// else
|
||
|
|
// {
|
||
|
|
// Debug.Log("[SplashScreen] Serial handshake completed successfully!");
|
||
|
|
// }
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 返回当前平台的串口名/设备路径
|
||
|
|
/// 注意:安卓端通常为 /dev/ttyS* 或 /dev/ttyUSB*
|
||
|
|
/// 实际设备路径应根据硬件与驱动调整,可通过日志或配置下发
|
||
|
|
/// </summary>
|
||
|
|
private string GetPortNameForPlatform()
|
||
|
|
{
|
||
|
|
#if UNITY_ANDROID && !UNITY_EDITOR
|
||
|
|
return string.IsNullOrEmpty(AndroidPortPath) ? "/dev/ttyS4" : AndroidPortPath;
|
||
|
|
#else
|
||
|
|
return string.IsNullOrEmpty(WindowsPortName) ? "COM1" : WindowsPortName;
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 验证通讯状态
|
||
|
|
/// </summary>
|
||
|
|
private IEnumerator VerifyCommunication()
|
||
|
|
{
|
||
|
|
// 等待一段时间,让心跳报告处理完成
|
||
|
|
yield return new WaitForSeconds(1f);
|
||
|
|
|
||
|
|
// 检查DCSAlarmManager是否在启动阶段检测到通讯异常
|
||
|
|
if (_alarmManager != null && _alarmManager.HasCommunicationErrorDuringStartup)
|
||
|
|
{
|
||
|
|
Debug.LogError("[SplashScreen] Communication error detected by DCSAlarmManager!");
|
||
|
|
_communicationErrorDetected = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 如果未检测到通讯错误,则认为通讯正常
|
||
|
|
if (!_communicationErrorDetected)
|
||
|
|
{
|
||
|
|
Debug.Log("[SplashScreen] Communication verification passed!");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 显示通讯异常对话框
|
||
|
|
/// </summary>
|
||
|
|
private IEnumerator ShowCommunicationErrorDialog()
|
||
|
|
{
|
||
|
|
// 淡出启动界面
|
||
|
|
yield return StartCoroutine(FadeOut());
|
||
|
|
|
||
|
|
// 显示错误对话框
|
||
|
|
bool dialogClosed = false;
|
||
|
|
ConfirmDialog.Show(
|
||
|
|
COMMUNICATION_ERROR_TITLE,
|
||
|
|
COMMUNICATION_ERROR_MESSAGE,
|
||
|
|
onConfirm: () =>
|
||
|
|
{
|
||
|
|
dialogClosed = true;
|
||
|
|
// 关闭应用
|
||
|
|
#if UNITY_EDITOR
|
||
|
|
UnityEditor.EditorApplication.isPlaying = false;
|
||
|
|
#else
|
||
|
|
Application.Quit();
|
||
|
|
#endif
|
||
|
|
},
|
||
|
|
onCancel: null,
|
||
|
|
confirmText: "关闭应用",
|
||
|
|
cancelText: "",
|
||
|
|
isWarning: true,
|
||
|
|
showCancelButton: false
|
||
|
|
);
|
||
|
|
|
||
|
|
// 等待用户关闭对话框
|
||
|
|
while (!dialogClosed)
|
||
|
|
{
|
||
|
|
yield return new WaitForSeconds(0.1f);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 淡出并进入应用
|
||
|
|
/// </summary>
|
||
|
|
private IEnumerator FadeOutAndEnterApp()
|
||
|
|
{
|
||
|
|
yield return StartCoroutine(FadeOut());
|
||
|
|
|
||
|
|
// 进入登录界面
|
||
|
|
UIManager.Instance.ShowPanel<LoginPanel>();
|
||
|
|
|
||
|
|
// 销毁启动界面
|
||
|
|
Destroy(gameObject);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 淡出启动界面
|
||
|
|
/// </summary>
|
||
|
|
private IEnumerator FadeOut()
|
||
|
|
{
|
||
|
|
if (SplashCanvasGroup == null)
|
||
|
|
yield break;
|
||
|
|
|
||
|
|
float elapsedTime = 0f;
|
||
|
|
while (elapsedTime < FadeOutDuration)
|
||
|
|
{
|
||
|
|
elapsedTime += Time.deltaTime;
|
||
|
|
SplashCanvasGroup.alpha = Mathf.Lerp(1f, 0f, elapsedTime / FadeOutDuration);
|
||
|
|
yield return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
SplashCanvasGroup.alpha = 0f;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 更新加载状态文本和进度条
|
||
|
|
/// </summary>
|
||
|
|
private void UpdateLoadingStatus(string statusText, float progress)
|
||
|
|
{
|
||
|
|
if (LoadingStatusText != null)
|
||
|
|
{
|
||
|
|
LoadingStatusText.text = statusText;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (LoadingProgressBar != null)
|
||
|
|
{
|
||
|
|
LoadingProgressBar.fillAmount = Mathf.Clamp01(progress);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 处理通讯错误事件
|
||
|
|
/// </summary>
|
||
|
|
private void OnSerialCommunicationError()
|
||
|
|
{
|
||
|
|
Debug.LogWarning("[SplashScreen] Serial communication error detected!");
|
||
|
|
_communicationErrorDetected = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void OnDestroy()
|
||
|
|
{
|
||
|
|
// 取消订阅
|
||
|
|
if (_serialService != null)
|
||
|
|
{
|
||
|
|
_serialService.OnCommunicationError -= OnSerialCommunicationError;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public void GenerateLoginUI()
|
||
|
|
{
|
||
|
|
// 生成登录界面的逻辑
|
||
|
|
UIManager.Instance.ShowPanel<LoginPanel>();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
}
|
||
|
|
|