refactor(蓝牙&多语言): 优化多项功能并修复问题

1. 更新多语言文件中星期的英文缩写为完整标准写法
2. 移除OTA传输中的额外延迟,优化传输速度
3. 蓝牙连接时请求高吞吐量MTU和连接优先级
4. 修复蚊虫数据请求前初始化容器的时序问题
5. 重构BLE帧解析逻辑,批量处理帧避免协程积压
This commit is contained in:
“虞渠成” 2026-07-14 08:56:20 +08:00
parent 8f20291be6
commit b83bf75330
5 changed files with 59 additions and 49 deletions

View File

@ -652,22 +652,22 @@
{
"key": "100131",
"zh": "一",
"en": "M"
"en": "Mon"
},
{
"key": "100132",
"zh": "二",
"en": "T"
"en": "Tue"
},
{
"key": "100133",
"zh": "三",
"en": "W"
"en": "Wed"
},
{
"key": "100134",
"zh": "四",
"en": "Th"
"en": "Thu"
},
{
"key": "100135",

View File

@ -2337,57 +2337,60 @@ namespace Kill.Bluetooth
/// </summary>
private void TryParseFrameInternal()
{
byte[] buffer = _receiveBuffer.ToArray();
// 收集所有完整帧,避免频繁 StartCoroutine 和 return 导致积压
var frames = new List<BLEFrame>();
int totalRemoved = 0;
// 查找帧头
for (int i = 0; i < buffer.Length - 1; i++)
while (totalRemoved < _receiveBuffer.Count)
{
if (buffer[i] == BLEConstants.FRAME_HEADER_1 &&
buffer[i + 1] == BLEConstants.FRAME_HEADER_2)
int searchStart = totalRemoved;
byte[] buffer = _receiveBuffer.ToArray();
bool found = false;
for (int i = searchStart; i < buffer.Length - 1; i++)
{
// 检查是否有足够的数据长度字段
if (i + 4 >= buffer.Length)
if (buffer[i] == BLEConstants.FRAME_HEADER_1 &&
buffer[i + 1] == BLEConstants.FRAME_HEADER_2)
{
continue;
}
if (i + 4 >= buffer.Length) continue;
byte dataLength = buffer[i + 4];
int totalFrameLength = 7 + dataLength; // 帧头(2) + 命令(1) + 读写(1) + 长度(1) + 数据(dataLength) + CRC(2)
byte dataLength = buffer[i + 4];
int totalFrameLength = 7 + dataLength;
// 检查是否有完整的帧
if (i + totalFrameLength > buffer.Length)
{
continue;
}
if (i + totalFrameLength > buffer.Length) continue;
// 提取帧数据
byte[] frameBytes = new byte[totalFrameLength];
Buffer.BlockCopy(buffer, i, frameBytes, 0, totalFrameLength);
byte[] frameBytes = new byte[totalFrameLength];
Buffer.BlockCopy(buffer, i, frameBytes, 0, totalFrameLength);
// 解析帧
if (BLEFrame.TryParse(frameBytes, out BLEFrame frame))
{
// 从缓冲区移除已解析的数据
int removeLength = i + totalFrameLength;
_receiveBuffer.RemoveRange(0, removeLength);
// 在锁外处理帧,避免死锁和重入问题
// 使用异步方式在下一帧处理
StartCoroutine(HandleFrameAsync(frame));
return;
}
else
{
LogWarning("帧解析失败 (CRC校验可能失败)");
if (BLEFrame.TryParse(frameBytes, out BLEFrame frame))
{
frames.Add(frame);
totalRemoved += (i - searchStart) + totalFrameLength;
searchStart = totalRemoved;
found = true;
break;
}
else
{
LogWarning("帧解析失败 (CRC校验可能失败)");
}
}
}
if (!found) break;
}
// 清理过期的缓冲区数据 (保留最后100字节)
// 移除已解析的数据
if (totalRemoved > 0)
_receiveBuffer.RemoveRange(0, totalRemoved);
// 清理过期缓冲区
if (_receiveBuffer.Count > 200)
{
_receiveBuffer.RemoveRange(0, _receiveBuffer.Count - 100);
}
// 在锁外批量处理帧
foreach (var frame in frames)
StartCoroutine(HandleFrameAsync(frame));
}
/// <summary>

View File

@ -4,6 +4,7 @@ using System.Collections.Generic;
using Kill.Core;
using Kill.UI;
using Kill.UI.Components;
using static BluetoothLEHardwareInterface;
namespace Kill.Bluetooth
{
@ -828,6 +829,14 @@ namespace Kill.Bluetooth
OnConnected?.Invoke(address);
// 请求高吞吐量MTU 512 + 高优先级连接间隔
BluetoothLEHardwareInterface.RequestMtu(address, 512, (addr, mtu) =>
{
Log($"MTU 协商完成: {mtu} 字节");
});
BluetoothLEHardwareInterface.BluetoothConnectionPriority(ConnectionPriority.High);
Log("已请求高优先级 BLE 连接");
// 延迟通知连接成功并可通信
Invoke(nameof(NotifyConnectedSuccess), 0.5f);
}

View File

@ -284,12 +284,6 @@ namespace Kill.Bluetooth
// 报告进度(无重试)
OnTransferProgress?.Invoke(i + 1, _totalPackets, 0, 0);
// 每包之间添加小延迟,避免设备处理不过来
if (i < _totalPackets - 1)
{
yield return new WaitForSeconds(0.01f);
}
}
SetState(OTAState.Ending);

View File

@ -1498,6 +1498,10 @@ namespace Kill.UI.Pages
Debug.Log($"检测到 {count.Count} 条蚊虫数据,正在请求...");
// 在请求前先初始化接收容器,避免通知先于主线程回调到达导致数据丢失
mosquitoDatas = new List<MosquitoData>();
aimMosquitoDataCount = (int)count.Count;
// 步骤2: 请求所有蚊虫数据
BLECommunicationManager.Instance.RequestMosquitoData(count.Count, (success) =>
{
@ -1509,12 +1513,12 @@ namespace Kill.UI.Pages
tip=tip.Replace("{0}",count.ToString());
ToastUI.ShowText(tip);
Debug.Log($"已请求 {count.Count} 条蚊虫数据,等待接收...");
mosquitoDatas=new List<MosquitoData>();
aimMosquitoDataCount=(int)count.Count;
}
else
{
Debug.Log("蚊虫数据请求失败");
mosquitoDatas = null;
aimMosquitoDataCount = 0;
LoadingUI.Hide();
}
});