killapp/Assets/Scripts/Base/OTAManager.cs
2026-03-30 16:25:00 +08:00

630 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using BLEProtocol;
/// <summary>
/// OTA版本信息
/// </summary>
[Serializable]
public class OTAVersionInfo
{
public uint FirmwareVersion; // 固件版本 (4字节)
public uint HardwareVersion; // 硬件版本 (4字节)
public uint OTAVersion; // OTA版本 (4字节)
public override string ToString()
{
return $"固件版本: {FirmwareVersion}, 硬件版本: {HardwareVersion}, OTA版本: {OTAVersion}";
}
}
/// <summary>
/// OTA升级状态
/// </summary>
public enum OTAState
{
Idle, // 空闲
QueryingVersion, // 查询版本中
Starting, // 开始升级中
Transferring, // 传输数据中
Ending, // 结束传输中
Cancelling, // 取消升级中
Completed, // 完成
Error // 错误
}
/// <summary>
/// OTA升级管理器 - 处理固件OTA升级
/// </summary>
public class OTAManager : MonoBehaviour
{
public static OTAManager Instance { get; private set; }
// 事件定义
public event Action<OTAVersionInfo> OnVersionInfoReceived; // 收到版本信息
public event Action<bool> OnStartUpgradeResult; // 开始升级结果
public event Action<int, int, int, int> OnTransferProgress; // 传输进度 (当前包, 总包数, 重试次数, 最大重试次数)
public event Action<bool> OnTransferComplete; // 传输完成
public event Action<bool> OnCancelResult; // 取消结果
public event Action<string> OnError; // 错误事件
public event Action<OTAState> OnStateChanged; // 状态变化
// 状态
public OTAState CurrentState { get; private set; } = OTAState.Idle;
// 升级参数
private byte[] _firmwareData; // 固件数据
private uint _firmwareVersion; // 固件版本
private int _currentPacketIndex; // 当前包序号
private int _totalPackets; // 总包数
private const int PACKET_SIZE = 512; // 每包数据大小根据设备MTU调整
private void Awake()
{
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}
private void OnDestroy()
{
if (Instance == this)
{
Instance = null;
}
}
#region OTA命令接口
/// <summary>
/// 查询OTA版本信息 (命令 0x80)
/// </summary>
public void QueryVersionInfo(Action<OTAVersionInfo> callback = null)
{
if (!CheckConnection()) return;
SetState(OTAState.QueryingVersion);
var frame = new BLEFrame
{
Header1 = BLEConstants.FRAME_HEADER_1,
Header2 = BLEConstants.FRAME_HEADER_2,
Command = BLEConstants.CMD_OTA_QUERY_VERSION,
ReadWrite = BLEConstants.RW_READ,
Length = 0,
Data = null
};
SendFrame(frame, (response) =>
{
if (response.IsSuccess && response.Data != null && response.Data.Length >= 12)
{
var info = new OTAVersionInfo
{
FirmwareVersion = BitConverter.ToUInt32(response.Data, 0),
HardwareVersion = BitConverter.ToUInt32(response.Data, 4),
OTAVersion = BitConverter.ToUInt32(response.Data, 8)
};
SetState(OTAState.Idle);
OnVersionInfoReceived?.Invoke(info);
callback?.Invoke(info);
}
else
{
SetState(OTAState.Error);
OnError?.Invoke("查询OTA版本信息失败");
callback?.Invoke(null);
}
});
}
/// <summary>
/// 开始OTA升级 (命令 0x81)
/// </summary>
/// <param name="firmwareData">固件数据</param>
/// <param name="firmwareVersion">固件版本</param>
/// <param name="callback">回调</param>
public void StartUpgrade(byte[] firmwareData, uint firmwareVersion, Action<bool> callback = null)
{
if (!CheckConnection())
{
callback?.Invoke(false);
return;
}
if (firmwareData == null || firmwareData.Length == 0)
{
LogError("固件数据为空");
callback?.Invoke(false);
return;
}
_firmwareData = firmwareData;
_firmwareVersion = firmwareVersion;
_currentPacketIndex = 0;
_totalPackets = (int)Math.Ceiling((double)firmwareData.Length / PACKET_SIZE);
SetState(OTAState.Starting);
// 计算CRC16
ushort crc16 = CalculateCRC16(firmwareData);
// 构建数据: 版本号(4) + 大小(4) + CRC16(2)
byte[] data = new byte[10];
BitConverter.GetBytes(firmwareVersion).CopyTo(data, 0);
BitConverter.GetBytes((uint)firmwareData.Length).CopyTo(data, 4);
BitConverter.GetBytes(crc16).CopyTo(data, 8);
var frame = new BLEFrame
{
Header1 = BLEConstants.FRAME_HEADER_1,
Header2 = BLEConstants.FRAME_HEADER_2,
Command = BLEConstants.CMD_OTA_START,
ReadWrite = BLEConstants.RW_WRITE,
Length = (byte)data.Length,
Data = data
};
// 使用协程来处理响应和延迟
StartCoroutine(StartUpgradeCoroutineInternal(frame, callback));
}
private IEnumerator StartUpgradeCoroutineInternal(BLEFrame frame, Action<bool> callback)
{
BLEResponse response = new BLEResponse { Status = BLEConstants.STATUS_DEVICE_ERROR };
bool completed = false;
SendFrame(frame, (resp) =>
{
response = resp;
completed = true;
});
yield return new WaitUntil(() => completed);
bool success = response.IsSuccess;
if (success)
{
// 检查连接状态,如果断开则等待重连
int retryCount = 0;
const int maxRetries = 10;
while (BluetoothManager.Instance != null && !BluetoothManager.Instance.IsConnected && retryCount < maxRetries)
{
yield return new WaitForSeconds(0.5f);
retryCount++;
}
if (BluetoothManager.Instance == null || !BluetoothManager.Instance.IsConnected)
{
SetState(OTAState.Error);
OnStartUpgradeResult?.Invoke(false);
callback?.Invoke(false);
yield break;
}
// 实际测试连接是否可用 - 发送一个查询版本命令
bool testCompleted = false;
bool testSuccess = false;
var testFrame = new BLEFrame
{
Header1 = BLEConstants.FRAME_HEADER_1,
Header2 = BLEConstants.FRAME_HEADER_2,
Command = BLEConstants.CMD_OTA_QUERY_VERSION,
ReadWrite = BLEConstants.RW_READ,
Length = 0,
Data = null
};
SendFrame(testFrame, (testResponse) =>
{
testSuccess = testResponse.IsSuccess;
testCompleted = true;
});
// 等待最多3秒
float testStartTime = Time.time;
while (!testCompleted && Time.time - testStartTime < 3f)
{
yield return null;
}
if (!testCompleted)
{
LogError("[OTA-DEBUG] 连接测试超时BLE连接可能已断开");
SetState(OTAState.Error);
OnStartUpgradeResult?.Invoke(false);
callback?.Invoke(false);
yield break;
}
if (!testSuccess)
{
SetState(OTAState.Error);
OnStartUpgradeResult?.Invoke(false);
callback?.Invoke(false);
yield break;
}
SetState(OTAState.Transferring);
OnStartUpgradeResult?.Invoke(true);
callback?.Invoke(true);
}
else
{
SetState(OTAState.Error);
OnStartUpgradeResult?.Invoke(false);
callback?.Invoke(false);
}
}
/// <summary>
/// 传输固件数据包 (命令 0x82)
/// </summary>
public IEnumerator TransferFirmware(Action<bool> callback = null)
{
if (_firmwareData == null)
{
LogError("没有固件数据");
callback?.Invoke(false);
yield break;
}
SetState(OTAState.Transferring);
// 每包实际数据长度(不包括包序号)
const int DATA_PER_PACKET = 253; // 255 - 2 (包序号)
// 重新计算总包数
_totalPackets = (_firmwareData.Length + DATA_PER_PACKET - 1) / DATA_PER_PACKET;
for (int i = 0; i < _totalPackets; i++)
{
_currentPacketIndex = i;
int offset = i * DATA_PER_PACKET; // 使用实际数据长度计算偏移
int length = Mathf.Min(DATA_PER_PACKET, _firmwareData.Length - offset);
// 构建数据包: 包序号(2) + 数据(N)
byte[] packetData = new byte[2 + length];
BitConverter.GetBytes((ushort)i).CopyTo(packetData, 0);
Buffer.BlockCopy(_firmwareData, offset, packetData, 2, length);
var frame = new BLEFrame
{
Header1 = BLEConstants.FRAME_HEADER_1,
Header2 = BLEConstants.FRAME_HEADER_2,
Command = BLEConstants.CMD_OTA_TRANSFER_DATA,
ReadWrite = BLEConstants.RW_WRITE,
Length = (byte)packetData.Length,
Data = packetData
};
// 发送数据包,带重试机制
bool packetSuccess = false;
int retryCount = 0;
const int maxRetries = 5;
while (!packetSuccess && retryCount < maxRetries)
{
if (retryCount > 0)
{
OnTransferProgress?.Invoke(i + 1, _totalPackets, retryCount, maxRetries);
yield return new WaitForSeconds(0.5f);
}
yield return SendFrameCoroutine(frame, (response) =>
{
packetSuccess = response.IsSuccess;
});
if (!packetSuccess)
{
retryCount++;
}
}
if (!packetSuccess)
{
SetState(OTAState.Error);
OnError?.Invoke($"传输包 {_currentPacketIndex} 失败");
callback?.Invoke(false);
yield break;
}
// 报告进度(无重试)
OnTransferProgress?.Invoke(i + 1, _totalPackets, 0, 0);
// 每包之间添加小延迟,避免设备处理不过来
if (i < _totalPackets - 1)
{
yield return new WaitForSeconds(0.01f);
}
}
SetState(OTAState.Ending);
OnTransferComplete?.Invoke(true);
callback?.Invoke(true);
}
/// <summary>
/// 结束传输 (命令 0x83)
/// </summary>
public void EndTransfer(Action<bool> callback = null)
{
if (!CheckConnection())
{
callback?.Invoke(false);
return;
}
SetState(OTAState.Ending);
// 数据: 总大小(4) + CRC16(2)
byte[] data = new byte[6];
BitConverter.GetBytes((uint)_firmwareData.Length).CopyTo(data, 0);
ushort crc16 = CalculateCRC16(_firmwareData);
BitConverter.GetBytes(crc16).CopyTo(data, 4);
var frame = new BLEFrame
{
Header1 = BLEConstants.FRAME_HEADER_1,
Header2 = BLEConstants.FRAME_HEADER_2,
Command = BLEConstants.CMD_OTA_END_TRANSFER,
ReadWrite = BLEConstants.RW_WRITE,
Length = (byte)data.Length,
Data = data
};
SendFrame(frame, (response) =>
{
bool success = response.IsSuccess;
if (success)
{
SetState(OTAState.Completed);
}
else
{
SetState(OTAState.Error);
}
callback?.Invoke(success);
});
}
/// <summary>
/// 取消升级 (命令 0x85)
/// </summary>
public void CancelUpgrade(Action<bool> callback = null)
{
if (!CheckConnection())
{
callback?.Invoke(false);
return;
}
SetState(OTAState.Cancelling);
// 数据: 取消标志(1)
byte[] data = new byte[] { 0x01 };
var frame = new BLEFrame
{
Header1 = BLEConstants.FRAME_HEADER_1,
Header2 = BLEConstants.FRAME_HEADER_2,
Command = BLEConstants.CMD_OTA_CANCEL,
ReadWrite = BLEConstants.RW_WRITE,
Length = (byte)data.Length,
Data = data
};
SendFrame(frame, (response) =>
{
bool success = response.IsSuccess;
if (success)
{
SetState(OTAState.Idle);
_firmwareData = null;
}
else
{
SetState(OTAState.Error);
}
OnCancelResult?.Invoke(success);
callback?.Invoke(success);
});
}
#endregion
#region
/// <summary>
/// 执行完整OTA升级流程
/// </summary>
public IEnumerator PerformFullUpgrade(byte[] firmwareData, uint firmwareVersion, Action<bool> callback = null)
{
// 0. 先取消可能存在的未完成升级
bool cancelSuccess = false;
yield return CancelUpgradeCoroutine((success) => cancelSuccess = success);
if (cancelSuccess)
{
yield return new WaitForSeconds(1f);
}
// 1. 查询版本信息
OTAVersionInfo versionInfo = null;
yield return QueryVersionInfoCoroutine((info) => versionInfo = info);
if (versionInfo == null)
{
callback?.Invoke(false);
yield break;
}
// 2. 开始升级
bool startSuccess = false;
yield return StartUpgradeCoroutine(firmwareData, firmwareVersion, (success) => startSuccess = success);
if (!startSuccess)
{
callback?.Invoke(false);
yield break;
}
// 3. 传输数据
bool transferSuccess = false;
yield return TransferFirmware((success) => transferSuccess = success);
if (!transferSuccess)
{
callback?.Invoke(false);
yield break;
}
// 4. 结束传输
bool endSuccess = false;
yield return EndTransferCoroutine((success) => endSuccess = success);
if (!endSuccess)
{
callback?.Invoke(false);
yield break;
}
callback?.Invoke(true);
}
#endregion
#region
private bool CheckConnection()
{
if (BLECommunicationManager.Instance == null) return false;
if (BluetoothManager.Instance == null || !BluetoothManager.Instance.IsConnected) return false;
return true;
}
private void SetState(OTAState newState)
{
if (CurrentState != newState)
{
CurrentState = newState;
OnStateChanged?.Invoke(newState);
}
}
private void SendFrame(BLEFrame frame, Action<BLEResponse> callback)
{
BLECommunicationManager.Instance.SendFrameInternal(frame, callback);
}
private IEnumerator SendFrameCoroutine(BLEFrame frame, Action<BLEResponse> callback)
{
bool completed = false;
BLEResponse response = new BLEResponse { Status = BLEConstants.STATUS_DEVICE_ERROR };
SendFrame(frame, (resp) =>
{
response = resp;
completed = true;
});
yield return new WaitUntil(() => completed);
callback?.Invoke(response);
}
private IEnumerator QueryVersionInfoCoroutine(Action<OTAVersionInfo> callback)
{
OTAVersionInfo info = null;
QueryVersionInfo((result) => info = result);
yield return new WaitUntil(() => CurrentState != OTAState.QueryingVersion || info != null);
callback?.Invoke(info);
}
private IEnumerator StartUpgradeCoroutine(byte[] firmwareData, uint firmwareVersion, Action<bool> callback)
{
bool completed = false;
bool success = false;
StartUpgrade(firmwareData, firmwareVersion, (result) =>
{
success = result;
completed = true;
});
yield return new WaitUntil(() => completed);
callback?.Invoke(success);
}
private IEnumerator CancelUpgradeCoroutine(Action<bool> callback)
{
bool completed = false;
bool success = false;
CancelUpgrade((result) =>
{
success = result;
completed = true;
});
yield return new WaitUntil(() => completed);
callback?.Invoke(success);
}
private IEnumerator EndTransferCoroutine(Action<bool> callback)
{
bool completed = false;
bool success = false;
EndTransfer((result) =>
{
success = result;
completed = true;
});
yield return new WaitUntil(() => completed);
callback?.Invoke(success);
}
/// <summary>
/// 计算CRC16校验
/// </summary>
private ushort CalculateCRC16(byte[] data)
{
ushort crc = 0xFFFF;
for (int i = 0; i < data.Length; i++)
{
crc ^= (ushort)(data[i] << 8);
for (int j = 0; j < 8; j++)
{
if ((crc & 0x8000) != 0)
crc = (ushort)((crc << 1) ^ 0x1021);
else
crc <<= 1;
}
}
return crc;
}
private void Log(string message)
{
Debug.Log($"[OTAManager] {message}");
}
private void LogError(string message)
{
Debug.LogError($"[OTAManager] {message}");
}
#endregion
}