暂时提交
This commit is contained in:
parent
2dd4013f6f
commit
8e879b009a
@ -50,7 +50,14 @@ namespace Kill.Bluetooth
|
|||||||
public event Action<StatisticsData> OnStatisticsDataReceived; // 收到统计数据
|
public event Action<StatisticsData> OnStatisticsDataReceived; // 收到统计数据
|
||||||
public event Action<SensorData> OnSensorDataReceived; // 收到传感器数据
|
public event Action<SensorData> OnSensorDataReceived; // 收到传感器数据
|
||||||
public event Action<MosquitoData> OnMosquitoDataReceived; // 收到蚊虫数据通知
|
public event Action<MosquitoData> OnMosquitoDataReceived; // 收到蚊虫数据通知
|
||||||
|
public event Action<DeviceStateChangeNotification> OnDeviceStateChangeNotification; // 设备状态变化通知(0x01)
|
||||||
|
public event Action<ErrorStatusNotification> OnErrorStatusNotification; // 错误状态上报通知(0x02)
|
||||||
|
public event Action<ParameterChangeNotification> OnParameterChangeNotification; // 参数变化通知(0x06)
|
||||||
|
public event Action<CapacitorStateNotification> OnCapacitorStateNotification; // 蓄能状态通知(0x08)
|
||||||
|
public event Action<FillLightConnectionNotification> OnFillLightConnectionNotification; // 补光灯连接状态通知(0x09)
|
||||||
|
public event Action<byte, string> OnDeviceNotificationReceived; // 通用通知(命令码 + 设备MAC)用于按 MAC 隔离广播
|
||||||
public event Action<string> OnRawDataReceived; // 收到原始数据(十六进制字符串)
|
public event Action<string> OnRawDataReceived; // 收到原始数据(十六进制字符串)
|
||||||
|
public event Action<BLEDeviceState, BLEDeviceStateField> OnDeviceStateChanged; // 本地设备状态变化(设备状态、字段)
|
||||||
public event Action<string> OnRawDataSent; // 发送原始数据(十六进制字符串)
|
public event Action<string> OnRawDataSent; // 发送原始数据(十六进制字符串)
|
||||||
public event Action<string> OnCommunicationError; // 通信错误
|
public event Action<string> OnCommunicationError; // 通信错误
|
||||||
|
|
||||||
@ -89,6 +96,83 @@ namespace Kill.Bluetooth
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<string, BLEDeviceState> _deviceStates =
|
||||||
|
new Dictionary<string, BLEDeviceState>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
private readonly object _deviceStateLock = new object();
|
||||||
|
private string _lastStateMac;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前连接设备对应的本地状态对象。
|
||||||
|
/// 状态仓库按设备 MAC 隔离,旧设备通知不会覆盖当前设备。
|
||||||
|
/// </summary>
|
||||||
|
public BLEDeviceState GetDeviceState(string deviceMac)
|
||||||
|
{
|
||||||
|
string normalizedMac = NormalizeDeviceMac(deviceMac);
|
||||||
|
if (string.IsNullOrEmpty(normalizedMac))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (_deviceStateLock)
|
||||||
|
{
|
||||||
|
if (!_deviceStates.TryGetValue(normalizedMac, out BLEDeviceState state))
|
||||||
|
{
|
||||||
|
state = new BLEDeviceState(normalizedMac);
|
||||||
|
_deviceStates[normalizedMac] = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新当前设备状态,并仅在值发生变化时广播状态事件。
|
||||||
|
/// </summary>
|
||||||
|
private bool UpdateDeviceState(string deviceMac, BLEDeviceStateField field, Action<BLEDeviceState> update)
|
||||||
|
{
|
||||||
|
if (update == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BLEDeviceState state = GetDeviceState(deviceMac);
|
||||||
|
if (state == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool changed;
|
||||||
|
lock (_deviceStateLock)
|
||||||
|
{
|
||||||
|
changed = update(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OnDeviceStateChanged?.Invoke(state, field);
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
LogError($"OnDeviceStateChanged 处理异常: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool UpdateStateFromResponse(BLEResponse response, BLEDeviceStateField field, Action<BLEDeviceState> update)
|
||||||
|
{
|
||||||
|
return response != null && response.IsSuccess &&
|
||||||
|
UpdateDeviceState(GetCurrentDeviceMac(), field, update);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string NormalizeDeviceMac(string deviceMac)
|
||||||
|
{
|
||||||
|
return string.IsNullOrWhiteSpace(deviceMac) ? string.Empty : deviceMac.Trim().ToUpperInvariant();
|
||||||
|
}
|
||||||
|
|
||||||
// 服务和特征UUID (根据实际设备配置)
|
// 服务和特征UUID (根据实际设备配置)
|
||||||
public string ServiceUUID = "0000ffe0-0000-1000-8000-00805f9b34fb";
|
public string ServiceUUID = "0000ffe0-0000-1000-8000-00805f9b34fb";
|
||||||
public string WriteCharacteristicUUID = "0000ffe1-0000-1000-8000-00805f9b34fb";
|
public string WriteCharacteristicUUID = "0000ffe1-0000-1000-8000-00805f9b34fb";
|
||||||
@ -190,6 +274,16 @@ namespace Kill.Bluetooth
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnBluetoothConnected()
|
private void OnBluetoothConnected()
|
||||||
{
|
{
|
||||||
|
string stateMac = GetCurrentDeviceMac();
|
||||||
|
if (!string.IsNullOrEmpty(stateMac))
|
||||||
|
{
|
||||||
|
_lastStateMac = stateMac;
|
||||||
|
UpdateDeviceState(
|
||||||
|
stateMac,
|
||||||
|
BLEDeviceStateField.Connection,
|
||||||
|
state => state.SetConnection(true));
|
||||||
|
}
|
||||||
|
|
||||||
if (AutoInitialize)
|
if (AutoInitialize)
|
||||||
InitializeCommunication();
|
InitializeCommunication();
|
||||||
}
|
}
|
||||||
@ -200,6 +294,19 @@ namespace Kill.Bluetooth
|
|||||||
private void OnBluetoothDisconnected(string address)
|
private void OnBluetoothDisconnected(string address)
|
||||||
{
|
{
|
||||||
Log($"蓝牙已断开: {address}");
|
Log($"蓝牙已断开: {address}");
|
||||||
|
|
||||||
|
// 使用断开参数作为设备状态键;部分平台会在清空地址前触发事件。
|
||||||
|
string stateMac = NormalizeDeviceMac(address);
|
||||||
|
if (string.IsNullOrEmpty(stateMac))
|
||||||
|
{
|
||||||
|
stateMac = string.IsNullOrEmpty(_lastStateMac) ? GetCurrentDeviceMac() : _lastStateMac;
|
||||||
|
}
|
||||||
|
_lastStateMac = string.IsNullOrEmpty(stateMac) ? _lastStateMac : stateMac;
|
||||||
|
UpdateDeviceState(
|
||||||
|
stateMac,
|
||||||
|
BLEDeviceStateField.Connection,
|
||||||
|
state => state.SetConnection(false));
|
||||||
|
|
||||||
// 清理状态
|
// 清理状态
|
||||||
IsWaitingResponse = false;
|
IsWaitingResponse = false;
|
||||||
_responseTimer = 0;
|
_responseTimer = 0;
|
||||||
@ -562,6 +669,15 @@ namespace Kill.Bluetooth
|
|||||||
SendFrame(frame, (response) =>
|
SendFrame(frame, (response) =>
|
||||||
{
|
{
|
||||||
var setting = LanguageSetting.FromBytes(response.Data);
|
var setting = LanguageSetting.FromBytes(response.Data);
|
||||||
|
if (!response.IsSuccess)
|
||||||
|
{
|
||||||
|
LogError($"读取语言设置失败: 状态码={response.Status:X2}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateStateFromResponse(response, BLEDeviceStateField.Language,
|
||||||
|
state => state.SetLanguage(setting));
|
||||||
|
}
|
||||||
callback?.Invoke(setting);
|
callback?.Invoke(setting);
|
||||||
OnLanguageSettingReceived?.Invoke(setting);
|
OnLanguageSettingReceived?.Invoke(setting);
|
||||||
});
|
});
|
||||||
@ -592,9 +708,15 @@ namespace Kill.Bluetooth
|
|||||||
{
|
{
|
||||||
bool success = response.IsSuccess;
|
bool success = response.IsSuccess;
|
||||||
if (success)
|
if (success)
|
||||||
|
{
|
||||||
Log($"语言设置成功: {(isChinese ? "中文" : "英文")}");
|
Log($"语言设置成功: {(isChinese ? "中文" : "英文")}");
|
||||||
|
UpdateStateFromResponse(response, BLEDeviceStateField.Language,
|
||||||
|
state => state.SetLanguage(setting));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
LogError($"语言设置失败, 状态码={response.Status:X2}");
|
LogError($"语言设置失败, 状态码={response.Status:X2}");
|
||||||
|
}
|
||||||
callback?.Invoke(success);
|
callback?.Invoke(success);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -674,6 +796,15 @@ namespace Kill.Bluetooth
|
|||||||
SendFrame(frame, (response) =>
|
SendFrame(frame, (response) =>
|
||||||
{
|
{
|
||||||
var taskList = ScheduleTaskListResponse.FromBytes(response.Status, response.Data);
|
var taskList = ScheduleTaskListResponse.FromBytes(response.Status, response.Data);
|
||||||
|
if (!response.IsSuccess)
|
||||||
|
{
|
||||||
|
LogError($"读取定时任务失败: 状态码={response.Status:X2}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateStateFromResponse(response, BLEDeviceStateField.ScheduleTasks,
|
||||||
|
state => state.SetScheduleTasks(taskList.Tasks));
|
||||||
|
}
|
||||||
callback?.Invoke(taskList);
|
callback?.Invoke(taskList);
|
||||||
OnScheduleTaskListReceived?.Invoke(taskList);
|
OnScheduleTaskListReceived?.Invoke(taskList);
|
||||||
});
|
});
|
||||||
@ -1116,6 +1247,8 @@ namespace Kill.Bluetooth
|
|||||||
SendFrame(frame, (response) =>
|
SendFrame(frame, (response) =>
|
||||||
{
|
{
|
||||||
var control = FillLightControl.FromBytes(response.Data);
|
var control = FillLightControl.FromBytes(response.Data);
|
||||||
|
UpdateStateFromResponse(response, BLEDeviceStateField.FillLight,
|
||||||
|
state => state.SetFillLight(control));
|
||||||
callback?.Invoke(control);
|
callback?.Invoke(control);
|
||||||
OnFillLightControlReceived?.Invoke(control);
|
OnFillLightControlReceived?.Invoke(control);
|
||||||
});
|
});
|
||||||
@ -1145,9 +1278,15 @@ namespace Kill.Bluetooth
|
|||||||
{
|
{
|
||||||
bool success = response.IsSuccess;
|
bool success = response.IsSuccess;
|
||||||
if (success)
|
if (success)
|
||||||
|
{
|
||||||
Log($"补光灯控制设置成功: 开关={(control.Enable ? "开启" : "关闭")}, 类型={control.GetLightTypeString()}, 强度={control.GetIntensityString()}");
|
Log($"补光灯控制设置成功: 开关={(control.Enable ? "开启" : "关闭")}, 类型={control.GetLightTypeString()}, 强度={control.GetIntensityString()}");
|
||||||
|
UpdateStateFromResponse(response, BLEDeviceStateField.FillLight,
|
||||||
|
state => state.SetFillLight(control));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
LogError($"补光灯控制设置失败, 状态码={response.Status:X2}");
|
LogError($"补光灯控制设置失败, 状态码={response.Status:X2}");
|
||||||
|
}
|
||||||
callback?.Invoke(success);
|
callback?.Invoke(success);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1172,6 +1311,8 @@ namespace Kill.Bluetooth
|
|||||||
SendFrame(frame, (response) =>
|
SendFrame(frame, (response) =>
|
||||||
{
|
{
|
||||||
var status = FillLightConnectionStatus.FromBytes(response.Data);
|
var status = FillLightConnectionStatus.FromBytes(response.Data);
|
||||||
|
UpdateStateFromResponse(response, BLEDeviceStateField.FillLightConnection,
|
||||||
|
state => state.SetFillLightConnection(status));
|
||||||
callback?.Invoke(status);
|
callback?.Invoke(status);
|
||||||
OnFillLightConnectionStatusReceived?.Invoke(status);
|
OnFillLightConnectionStatusReceived?.Invoke(status);
|
||||||
});
|
});
|
||||||
@ -1254,6 +1395,8 @@ namespace Kill.Bluetooth
|
|||||||
Debug.Log($"[ReadDeviceLockControl] 收到响应: Status={response.Status:X2}, Data={BitConverter.ToString(response.Data)}");
|
Debug.Log($"[ReadDeviceLockControl] 收到响应: Status={response.Status:X2}, Data={BitConverter.ToString(response.Data)}");
|
||||||
var control = DeviceLockControl.FromBytes(response.Data);
|
var control = DeviceLockControl.FromBytes(response.Data);
|
||||||
Debug.Log($"[ReadDeviceLockControl] 解析结果: IsLocked={control.IsLocked}");
|
Debug.Log($"[ReadDeviceLockControl] 解析结果: IsLocked={control.IsLocked}");
|
||||||
|
UpdateStateFromResponse(response, BLEDeviceStateField.LockState,
|
||||||
|
state => state.SetLockState(control));
|
||||||
callback?.Invoke(control);
|
callback?.Invoke(control);
|
||||||
OnDeviceLockControlReceived?.Invoke(control);
|
OnDeviceLockControlReceived?.Invoke(control);
|
||||||
});
|
});
|
||||||
@ -1287,9 +1430,15 @@ namespace Kill.Bluetooth
|
|||||||
Debug.Log($"[WriteDeviceLockControl] 收到响应: Status={response.Status:X2}");
|
Debug.Log($"[WriteDeviceLockControl] 收到响应: Status={response.Status:X2}");
|
||||||
bool success = response.IsSuccess;
|
bool success = response.IsSuccess;
|
||||||
if (success)
|
if (success)
|
||||||
|
{
|
||||||
Log($"设备{(isLocked ? "锁定" : "解锁")}成功");
|
Log($"设备{(isLocked ? "锁定" : "解锁")}成功");
|
||||||
|
UpdateStateFromResponse(response, BLEDeviceStateField.LockState,
|
||||||
|
state => state.SetLockState(control));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
LogError($"设备{(isLocked ? "锁定" : "解锁")}失败, 状态码={response.Status:X2}");
|
LogError($"设备{(isLocked ? "锁定" : "解锁")}失败, 状态码={response.Status:X2}");
|
||||||
|
}
|
||||||
callback?.Invoke(success);
|
callback?.Invoke(success);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1318,6 +1467,8 @@ namespace Kill.Bluetooth
|
|||||||
SendFrame(frame, (response) =>
|
SendFrame(frame, (response) =>
|
||||||
{
|
{
|
||||||
var control = AngleControl.FromBytes(response.Data);
|
var control = AngleControl.FromBytes(response.Data);
|
||||||
|
UpdateStateFromResponse(response, BLEDeviceStateField.Angle,
|
||||||
|
state => state.SetAngle(control));
|
||||||
callback?.Invoke(control);
|
callback?.Invoke(control);
|
||||||
OnAngleControlReceived?.Invoke(control);
|
OnAngleControlReceived?.Invoke(control);
|
||||||
Log($"读取角度控制: {control}");
|
Log($"读取角度控制: {control}");
|
||||||
@ -1348,9 +1499,15 @@ namespace Kill.Bluetooth
|
|||||||
{
|
{
|
||||||
bool success = response.IsSuccess;
|
bool success = response.IsSuccess;
|
||||||
if (success)
|
if (success)
|
||||||
|
{
|
||||||
Log($"角度控制设置成功: {control}");
|
Log($"角度控制设置成功: {control}");
|
||||||
|
UpdateStateFromResponse(response, BLEDeviceStateField.Angle,
|
||||||
|
state => state.SetAngle(control));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
LogError($"角度控制设置失败, 状态码={response.Status:X2}");
|
LogError($"角度控制设置失败, 状态码={response.Status:X2}");
|
||||||
|
}
|
||||||
callback?.Invoke(success);
|
callback?.Invoke(success);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1375,6 +1532,8 @@ namespace Kill.Bluetooth
|
|||||||
SendFrame(frame, (response) =>
|
SendFrame(frame, (response) =>
|
||||||
{
|
{
|
||||||
var control = DistanceControl.FromBytes(response.Data);
|
var control = DistanceControl.FromBytes(response.Data);
|
||||||
|
UpdateStateFromResponse(response, BLEDeviceStateField.Distance,
|
||||||
|
state => state.SetDistance(control));
|
||||||
callback?.Invoke(control);
|
callback?.Invoke(control);
|
||||||
OnDistanceControlReceived?.Invoke(control);
|
OnDistanceControlReceived?.Invoke(control);
|
||||||
Log($"读取距离控制: {control}");
|
Log($"读取距离控制: {control}");
|
||||||
@ -1405,9 +1564,15 @@ namespace Kill.Bluetooth
|
|||||||
{
|
{
|
||||||
bool success = response.IsSuccess;
|
bool success = response.IsSuccess;
|
||||||
if (success)
|
if (success)
|
||||||
|
{
|
||||||
Log($"距离控制设置成功: {control}");
|
Log($"距离控制设置成功: {control}");
|
||||||
|
UpdateStateFromResponse(response, BLEDeviceStateField.Distance,
|
||||||
|
state => state.SetDistance(control));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
LogError($"距离控制设置失败, 状态码={response.Status:X2}");
|
LogError($"距离控制设置失败, 状态码={response.Status:X2}");
|
||||||
|
}
|
||||||
callback?.Invoke(success);
|
callback?.Invoke(success);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1492,6 +1657,8 @@ namespace Kill.Bluetooth
|
|||||||
SendFrame(frame, (response) =>
|
SendFrame(frame, (response) =>
|
||||||
{
|
{
|
||||||
var setting = VisualDetectionSetting.FromBytes(response.Data);
|
var setting = VisualDetectionSetting.FromBytes(response.Data);
|
||||||
|
UpdateStateFromResponse(response, BLEDeviceStateField.VisualDetection,
|
||||||
|
state => state.SetVisualDetection(setting));
|
||||||
callback?.Invoke(setting);
|
callback?.Invoke(setting);
|
||||||
OnVisualDetectionSettingReceived?.Invoke(setting);
|
OnVisualDetectionSettingReceived?.Invoke(setting);
|
||||||
Log($"读取视觉检测设置: {setting}");
|
Log($"读取视觉检测设置: {setting}");
|
||||||
@ -1521,9 +1688,15 @@ namespace Kill.Bluetooth
|
|||||||
{
|
{
|
||||||
bool success = response.IsSuccess;
|
bool success = response.IsSuccess;
|
||||||
if (success)
|
if (success)
|
||||||
|
{
|
||||||
Log($"视觉检测设置成功: {setting}");
|
Log($"视觉检测设置成功: {setting}");
|
||||||
|
UpdateStateFromResponse(response, BLEDeviceStateField.VisualDetection,
|
||||||
|
state => state.SetVisualDetection(setting));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
LogError($"视觉检测设置失败, 状态码={response.Status:X2}");
|
LogError($"视觉检测设置失败, 状态码={response.Status:X2}");
|
||||||
|
}
|
||||||
callback?.Invoke(success);
|
callback?.Invoke(success);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1690,6 +1863,15 @@ namespace Kill.Bluetooth
|
|||||||
SendFrame(frame, (response) =>
|
SendFrame(frame, (response) =>
|
||||||
{
|
{
|
||||||
var setting = WorkModeSetting.FromBytes(response.Data);
|
var setting = WorkModeSetting.FromBytes(response.Data);
|
||||||
|
if (!response.IsSuccess)
|
||||||
|
{
|
||||||
|
LogError($"读取工作模式失败: 状态码={response.Status:X2}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateStateFromResponse(response, BLEDeviceStateField.WorkMode,
|
||||||
|
state => state.SetWorkMode(setting.Mode));
|
||||||
|
}
|
||||||
callback?.Invoke(setting);
|
callback?.Invoke(setting);
|
||||||
OnWorkModeSettingReceived?.Invoke(setting);
|
OnWorkModeSettingReceived?.Invoke(setting);
|
||||||
Log($"读取工作模式: {setting}");
|
Log($"读取工作模式: {setting}");
|
||||||
@ -1719,9 +1901,15 @@ namespace Kill.Bluetooth
|
|||||||
{
|
{
|
||||||
bool success = response.IsSuccess;
|
bool success = response.IsSuccess;
|
||||||
if (success)
|
if (success)
|
||||||
|
{
|
||||||
Log($"工作模式设置成功: {setting}");
|
Log($"工作模式设置成功: {setting}");
|
||||||
|
UpdateStateFromResponse(response, BLEDeviceStateField.WorkMode,
|
||||||
|
state => state.SetWorkMode(setting.Mode));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
LogError($"工作模式设置失败, 状态码={response.Status:X2}");
|
LogError($"工作模式设置失败, 状态码={response.Status:X2}");
|
||||||
|
}
|
||||||
callback?.Invoke(success);
|
callback?.Invoke(success);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1746,6 +1934,8 @@ namespace Kill.Bluetooth
|
|||||||
SendFrame(frame, (response) =>
|
SendFrame(frame, (response) =>
|
||||||
{
|
{
|
||||||
var status = HardwareStatus.FromBytes(response.Data);
|
var status = HardwareStatus.FromBytes(response.Data);
|
||||||
|
UpdateStateFromResponse(response, BLEDeviceStateField.HardwareStatus,
|
||||||
|
state => state.SetHardwareStatus(status));
|
||||||
callback?.Invoke(status);
|
callback?.Invoke(status);
|
||||||
OnHardwareStatusReceived?.Invoke(status);
|
OnHardwareStatusReceived?.Invoke(status);
|
||||||
Log($"查询硬件状态: {status}");
|
Log($"查询硬件状态: {status}");
|
||||||
@ -2420,14 +2610,17 @@ namespace Kill.Bluetooth
|
|||||||
{
|
{
|
||||||
bool wasWaitingResponse = IsWaitingResponse;
|
bool wasWaitingResponse = IsWaitingResponse;
|
||||||
|
|
||||||
// 优先处理设备主动通知,避免被等待响应的流程拦截
|
// 通知帧优先处理,并且绝对不影响命令队列(IsWaitingResponse / _pendingCallback / _responseTimer)
|
||||||
if (frame.ReadWrite == BLEConstants.RW_NOTIFY)
|
// 设备主动通知是异步旁路通道,与当前等待响应的命令是两条独立链路
|
||||||
|
if (frame.ReadWrite == BLEConstants.RW_NOTIFY || frame.Command == BLEConstants.NOTIFY_COMMAND_CODE)
|
||||||
{
|
{
|
||||||
HandleNotification(frame.Data);
|
HandleNotification(frame.Data);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else if (IsWaitingResponse && frame.Command == LastCommand)
|
|
||||||
|
// 响应帧:优先匹配当前等待的命令。
|
||||||
|
if (IsWaitingResponse && frame.Command == LastCommand)
|
||||||
{
|
{
|
||||||
// 匹配到等待的响应
|
|
||||||
IsWaitingResponse = false;
|
IsWaitingResponse = false;
|
||||||
_responseTimer = 0;
|
_responseTimer = 0;
|
||||||
|
|
||||||
@ -2437,7 +2630,7 @@ namespace Kill.Bluetooth
|
|||||||
}
|
}
|
||||||
else if (IsWaitingResponse)
|
else if (IsWaitingResponse)
|
||||||
{
|
{
|
||||||
// 尝试处理非匹配的响应,可能是硬件响应延迟
|
// 保留原兼容行为:设备响应延迟时仍允许结束当前等待任务。
|
||||||
IsWaitingResponse = false;
|
IsWaitingResponse = false;
|
||||||
_responseTimer = 0;
|
_responseTimer = 0;
|
||||||
|
|
||||||
@ -2445,8 +2638,7 @@ namespace Kill.Bluetooth
|
|||||||
_pendingCallback?.Invoke(response);
|
_pendingCallback?.Invoke(response);
|
||||||
_pendingCallback = null;
|
_pendingCallback = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果之前有等待响应,现在响应已处理,继续处理队列
|
|
||||||
if (wasWaitingResponse)
|
if (wasWaitingResponse)
|
||||||
{
|
{
|
||||||
ProcessCommandQueue();
|
ProcessCommandQueue();
|
||||||
@ -2454,19 +2646,243 @@ namespace Kill.Bluetooth
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 通用的设备通知分发器,按命令类型路由到对应处理逻辑
|
/// 通用的设备通知分发器,按通知类型路由到对应处理逻辑
|
||||||
|
/// 通知帧约定:data[0]=通知类型,data[1..]=通知数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void HandleNotification(byte[] data)
|
private void HandleNotification(byte[] data)
|
||||||
{
|
{
|
||||||
byte command=data[0];
|
if (data == null || data.Length == 0)
|
||||||
switch (command)
|
{
|
||||||
|
LogWarning("收到空通知数据");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte notifyType = data[0];
|
||||||
|
|
||||||
|
// 按 MAC 隔离:仅当通知来自当前已连接设备时才向下分发
|
||||||
|
string currentMac = GetCurrentDeviceMac();
|
||||||
|
if (!string.IsNullOrEmpty(currentMac))
|
||||||
|
{
|
||||||
|
// 触发通用通知事件(携带通知类型 + 当前设备 MAC),便于业务侧按 MAC 二次过滤
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OnDeviceNotificationReceived?.Invoke(notifyType, currentMac);
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
LogError($"OnDeviceNotificationReceived 处理异常: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (notifyType)
|
||||||
{
|
{
|
||||||
case BLEConstants.NOTIFY_MOSQUITO_DATA:
|
case BLEConstants.NOTIFY_MOSQUITO_DATA:
|
||||||
HandleMosquitoDataNotification(data);
|
HandleMosquitoDataNotification(data);
|
||||||
break;
|
break;
|
||||||
default:
|
case BLEConstants.NOTIFY_DEVICE_STATE_CHANGE:
|
||||||
Log($"未处理的设备通知 0x{command:X2}");
|
HandleDeviceStateChangeNotification(data);
|
||||||
break;
|
break;
|
||||||
|
case BLEConstants.NOTIFY_ERROR_STATUS:
|
||||||
|
HandleErrorStatusNotification(data);
|
||||||
|
break;
|
||||||
|
case BLEConstants.NOTIFY_PARAMETER_CHANGE:
|
||||||
|
HandleParameterChangeNotification(data);
|
||||||
|
break;
|
||||||
|
case BLEConstants.NOTIFY_CAPACITOR_STATE:
|
||||||
|
HandleCapacitorStateNotification(data);
|
||||||
|
break;
|
||||||
|
case BLEConstants.NOTIFY_FILL_LIGHT_CONNECTION:
|
||||||
|
HandleFillLightConnectionNotification(data);
|
||||||
|
break;
|
||||||
|
case BLEConstants.NOTIFY_STATISTICS_UPDATE:
|
||||||
|
case BLEConstants.NOTIFY_SECURITY_ALERT:
|
||||||
|
Log($"收到通知类型 0x{notifyType:X2}(暂未实现具体业务解析)");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log($"未处理的设备通知类型 0x{notifyType:X2}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前已连接设备的 MAC(用于按 MAC 隔离通知事件)
|
||||||
|
/// 优先使用 iOS 端从广播中解析出的真实 MAC,否则回退到 BLE 地址
|
||||||
|
/// </summary>
|
||||||
|
public string GetCurrentDeviceMac()
|
||||||
|
{
|
||||||
|
if (BluetoothManager.Instance == null || !BluetoothManager.Instance.IsConnected)
|
||||||
|
return null;
|
||||||
|
string mac = BluetoothManager.Instance.ConnectedDeviceMacAddress;
|
||||||
|
if (string.IsNullOrEmpty(mac))
|
||||||
|
mac = BluetoothManager.Instance.ConnectedDeviceAddress;
|
||||||
|
return string.IsNullOrEmpty(mac) ? null : mac.ToUpperInvariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetStateMac()
|
||||||
|
{
|
||||||
|
string currentMac = GetCurrentDeviceMac();
|
||||||
|
return string.IsNullOrEmpty(currentMac) && !string.IsNullOrEmpty(_lastStateMac)
|
||||||
|
? _lastStateMac
|
||||||
|
: currentMac;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleDeviceStateChangeNotification(byte[] data)
|
||||||
|
{
|
||||||
|
var notify = DeviceStateChangeNotification.FromBytes(data);
|
||||||
|
if (notify.WorkMode > (byte)WorkMode.Eliminate)
|
||||||
|
{
|
||||||
|
LogWarning($"设备状态变化通知包含无效工作模式: 0x{notify.WorkMode:X2}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log($"设备状态变化通知: 工作模式=0x{notify.WorkMode:X2}");
|
||||||
|
UpdateDeviceState(
|
||||||
|
GetCurrentDeviceMac(),
|
||||||
|
BLEDeviceStateField.WorkMode,
|
||||||
|
state => state.SetWorkMode((WorkMode)notify.WorkMode));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OnDeviceStateChangeNotification?.Invoke(notify);
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
LogError($"OnDeviceStateChangeNotification 处理异常: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleErrorStatusNotification(byte[] data)
|
||||||
|
{
|
||||||
|
var notify = ErrorStatusNotification.FromBytes(data);
|
||||||
|
if (data != null && data.Length >= 8)
|
||||||
|
{
|
||||||
|
UpdateDeviceState(
|
||||||
|
GetCurrentDeviceMac(),
|
||||||
|
BLEDeviceStateField.HardwareStatus,
|
||||||
|
state => state.SetHardwareStatus(notify.Status));
|
||||||
|
}
|
||||||
|
Log($"错误状态上报通知: {notify.Status}");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OnErrorStatusNotification?.Invoke(notify);
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
LogError($"OnErrorStatusNotification 处理异常: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleParameterChangeNotification(byte[] data)
|
||||||
|
{
|
||||||
|
var notify = ParameterChangeNotification.FromBytes(data);
|
||||||
|
Log($"参数变化通知: 命令=0x{notify.CommandCode:X2}, 数据长度={(notify.Payload?.Length ?? 0)}");
|
||||||
|
|
||||||
|
// 优先回写本地状态仓库并按字段广播 OnDeviceStateChanged,便于业务侧按字段做局部刷新
|
||||||
|
ApplyParameterChangeToDeviceState(notify);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OnParameterChangeNotification?.Invoke(notify);
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
LogError($"OnParameterChangeNotification 处理异常: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 把 0x06 参数变化通知解析后回写到 BLEDeviceState 仓库,仅在值变化时通过 OnDeviceStateChanged 按字段广播
|
||||||
|
/// </summary>
|
||||||
|
private void ApplyParameterChangeToDeviceState(ParameterChangeNotification notify)
|
||||||
|
{
|
||||||
|
string deviceMac = GetCurrentDeviceMac();
|
||||||
|
if (string.IsNullOrEmpty(deviceMac) || notify.Payload == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
switch (notify.CommandCode)
|
||||||
|
{
|
||||||
|
case BLEConstants.CMD_LANGUAGE_SETTING:
|
||||||
|
UpdateDeviceState(deviceMac, BLEDeviceStateField.Language,
|
||||||
|
state => state.SetLanguage(LanguageSetting.FromBytes(notify.Payload)));
|
||||||
|
break;
|
||||||
|
case BLEConstants.CMD_SCHEDULE_TASK:
|
||||||
|
UpdateDeviceState(deviceMac, BLEDeviceStateField.ScheduleTasks,
|
||||||
|
state => state.SetScheduleTasks(ScheduleTaskListResponse.FromBytes(0x00, notify.Payload).Tasks));
|
||||||
|
break;
|
||||||
|
case BLEConstants.CMD_FILL_LIGHT_CONTROL:
|
||||||
|
UpdateDeviceState(deviceMac, BLEDeviceStateField.FillLight,
|
||||||
|
state => state.SetFillLight(FillLightControl.FromBytes(notify.Payload)));
|
||||||
|
break;
|
||||||
|
case BLEConstants.CMD_ANGLE_CONTROL:
|
||||||
|
UpdateDeviceState(deviceMac, BLEDeviceStateField.Angle,
|
||||||
|
state => state.SetAngle(AngleControl.FromBytes(notify.Payload)));
|
||||||
|
break;
|
||||||
|
case BLEConstants.CMD_DISTANCE_CONTROL:
|
||||||
|
UpdateDeviceState(deviceMac, BLEDeviceStateField.Distance,
|
||||||
|
state => state.SetDistance(DistanceControl.FromBytes(notify.Payload)));
|
||||||
|
break;
|
||||||
|
case BLEConstants.CMD_VISUAL_DETECTION_SETTING:
|
||||||
|
UpdateDeviceState(deviceMac, BLEDeviceStateField.VisualDetection,
|
||||||
|
state => state.SetVisualDetection(VisualDetectionSetting.FromBytes(notify.Payload)));
|
||||||
|
break;
|
||||||
|
case BLEConstants.CMD_FILL_LIGHT_CONNECTION_STATUS:
|
||||||
|
UpdateDeviceState(deviceMac, BLEDeviceStateField.FillLightConnection,
|
||||||
|
state => state.SetFillLightConnection(FillLightConnectionStatus.FromBytes(notify.Payload)));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// 未映射的字段:不写仓库,避免误覆盖
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
LogError($"参数变化通知写仓库异常(命令=0x{notify.CommandCode:X2}): {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleCapacitorStateNotification(byte[] data)
|
||||||
|
{
|
||||||
|
var notify = CapacitorStateNotification.FromBytes(data);
|
||||||
|
if (data != null && data.Length >= 2)
|
||||||
|
{
|
||||||
|
UpdateDeviceState(
|
||||||
|
GetCurrentDeviceMac(),
|
||||||
|
BLEDeviceStateField.CapacitorState,
|
||||||
|
state => state.SetCapacitorState(notify));
|
||||||
|
}
|
||||||
|
Log($"蓄能状态通知: state=0x{notify.State:X2}");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OnCapacitorStateNotification?.Invoke(notify);
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
LogError($"OnCapacitorStateNotification 处理异常: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleFillLightConnectionNotification(byte[] data)
|
||||||
|
{
|
||||||
|
var notify = FillLightConnectionNotification.FromBytes(data);
|
||||||
|
if (data != null && data.Length >= 2)
|
||||||
|
{
|
||||||
|
var status = new FillLightConnectionStatus { IsConnected = notify.IsConnected };
|
||||||
|
UpdateDeviceState(
|
||||||
|
GetCurrentDeviceMac(),
|
||||||
|
BLEDeviceStateField.FillLightConnection,
|
||||||
|
state => state.SetFillLightConnection(status));
|
||||||
|
}
|
||||||
|
Log($"补光灯连接状态通知: IsConnected={notify.IsConnected}");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OnFillLightConnectionNotification?.Invoke(notify);
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
LogError($"OnFillLightConnectionNotification 处理异常: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
245
Assets/Scripts/Bluetooth/BLEDeviceState.cs
Normal file
245
Assets/Scripts/Bluetooth/BLEDeviceState.cs
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Kill.Bluetooth.Protocol;
|
||||||
|
|
||||||
|
namespace Kill.Bluetooth
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 设备配置变化字段。
|
||||||
|
/// </summary>
|
||||||
|
public enum BLEDeviceStateField : byte
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Connection,
|
||||||
|
WorkMode,
|
||||||
|
LockState,
|
||||||
|
ScheduleTasks,
|
||||||
|
Angle,
|
||||||
|
Distance,
|
||||||
|
FillLight,
|
||||||
|
FillLightConnection,
|
||||||
|
VisualDetection,
|
||||||
|
MillimeterWave,
|
||||||
|
Language,
|
||||||
|
HardwareStatus,
|
||||||
|
CapacitorState
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 蓝牙设备运行状态。
|
||||||
|
/// 以设备 MAC 为边界保存状态,避免切换设备时旧设备数据覆盖当前设备。
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public sealed class BLEDeviceState
|
||||||
|
{
|
||||||
|
public string DeviceMac { get; private set; }
|
||||||
|
|
||||||
|
public bool IsConnected { get; private set; }
|
||||||
|
|
||||||
|
public WorkMode? WorkMode { get; private set; }
|
||||||
|
|
||||||
|
public DeviceLockControl? LockState { get; private set; }
|
||||||
|
|
||||||
|
public ScheduleTask[] ScheduleTasks { get; private set; } = new ScheduleTask[0];
|
||||||
|
|
||||||
|
public AngleControl? Angle { get; private set; }
|
||||||
|
|
||||||
|
public DistanceControl? Distance { get; private set; }
|
||||||
|
|
||||||
|
public FillLightControl? FillLight { get; private set; }
|
||||||
|
|
||||||
|
public FillLightConnectionStatus? FillLightConnection { get; private set; }
|
||||||
|
|
||||||
|
public VisualDetectionSetting? VisualDetection { get; private set; }
|
||||||
|
|
||||||
|
public LanguageSetting? Language { get; private set; }
|
||||||
|
|
||||||
|
public HardwareStatus? HardwareStatus { get; private set; }
|
||||||
|
|
||||||
|
public CapacitorStateNotification? CapacitorState { get; private set; }
|
||||||
|
|
||||||
|
public DateTime LastUpdatedAt { get; private set; }
|
||||||
|
|
||||||
|
public BLEDeviceState(string deviceMac)
|
||||||
|
{
|
||||||
|
DeviceMac = deviceMac ?? string.Empty;
|
||||||
|
LastUpdatedAt = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool SetConnection(bool connected)
|
||||||
|
{
|
||||||
|
if (IsConnected == connected)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
IsConnected = connected;
|
||||||
|
MarkUpdated();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool SetWorkMode(WorkMode mode)
|
||||||
|
{
|
||||||
|
if (WorkMode.HasValue && WorkMode.Value == mode)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkMode = mode;
|
||||||
|
MarkUpdated();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool SetLockState(DeviceLockControl lockState)
|
||||||
|
{
|
||||||
|
if (LockState.HasValue && LockState.Value.IsLocked == lockState.IsLocked)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LockState = lockState;
|
||||||
|
MarkUpdated();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool SetScheduleTasks(ScheduleTask[] tasks)
|
||||||
|
{
|
||||||
|
ScheduleTask[] newTasks = tasks == null ? new ScheduleTask[0] : (ScheduleTask[])tasks.Clone();
|
||||||
|
if (ScheduleTasksEqual(ScheduleTasks, newTasks))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScheduleTasks = newTasks;
|
||||||
|
MarkUpdated();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool SetAngle(AngleControl angle)
|
||||||
|
{
|
||||||
|
if (Angle.HasValue && Angle.Value.AngleRange == angle.AngleRange)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Angle = angle;
|
||||||
|
MarkUpdated();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool SetDistance(DistanceControl distance)
|
||||||
|
{
|
||||||
|
if (Distance.HasValue &&
|
||||||
|
Distance.Value.DetectionDistance == distance.DetectionDistance &&
|
||||||
|
Distance.Value.AimDistance == distance.AimDistance)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Distance = distance;
|
||||||
|
MarkUpdated();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool SetFillLight(FillLightControl fillLight)
|
||||||
|
{
|
||||||
|
if (FillLight.HasValue &&
|
||||||
|
FillLight.Value.Enable == fillLight.Enable &&
|
||||||
|
FillLight.Value.LightType == fillLight.LightType &&
|
||||||
|
FillLight.Value.Intensity == fillLight.Intensity)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FillLight = fillLight;
|
||||||
|
MarkUpdated();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool SetFillLightConnection(FillLightConnectionStatus status)
|
||||||
|
{
|
||||||
|
if (FillLightConnection.HasValue &&
|
||||||
|
FillLightConnection.Value.IsConnected == status.IsConnected)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FillLightConnection = status;
|
||||||
|
MarkUpdated();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool SetVisualDetection(VisualDetectionSetting setting)
|
||||||
|
{
|
||||||
|
if (VisualDetection.HasValue &&
|
||||||
|
VisualDetection.Value.Enable == setting.Enable &&
|
||||||
|
VisualDetection.Value.Sensitivity == setting.Sensitivity)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualDetection = setting;
|
||||||
|
MarkUpdated();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool SetLanguage(LanguageSetting language)
|
||||||
|
{
|
||||||
|
if (Language.HasValue && Language.Value.Language == language.Language)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Language = language;
|
||||||
|
MarkUpdated();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool SetHardwareStatus(HardwareStatus hardwareStatus)
|
||||||
|
{
|
||||||
|
if (HardwareStatus.HasValue && HardwareStatus.Value.Equals(hardwareStatus))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HardwareStatus = hardwareStatus;
|
||||||
|
MarkUpdated();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool SetCapacitorState(CapacitorStateNotification capacitorState)
|
||||||
|
{
|
||||||
|
if (CapacitorState.HasValue && CapacitorState.Value.State == capacitorState.State)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CapacitorState = capacitorState;
|
||||||
|
MarkUpdated();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MarkUpdated()
|
||||||
|
{
|
||||||
|
LastUpdatedAt = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool ScheduleTasksEqual(ScheduleTask[] left, ScheduleTask[] right)
|
||||||
|
{
|
||||||
|
if (left == null || right == null || left.Length != right.Length)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < left.Length; i++)
|
||||||
|
{
|
||||||
|
if (!left[i].Equals(right[i]))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/Scripts/Bluetooth/BLEDeviceState.cs.meta
Normal file
11
Assets/Scripts/Bluetooth/BLEDeviceState.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7e69a1efed6be8643ab6d0cf88657497
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
2105
Assets/Scripts/Bluetooth/BLE通信方案V2.2.md
Normal file
2105
Assets/Scripts/Bluetooth/BLE通信方案V2.2.md
Normal file
File diff suppressed because it is too large
Load Diff
7
Assets/Scripts/Bluetooth/BLE通信方案V2.2.md.meta
Normal file
7
Assets/Scripts/Bluetooth/BLE通信方案V2.2.md.meta
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8db7a756f6f76fb4ebb36b63755dd084
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -27,7 +27,17 @@ namespace Kill.Bluetooth.Protocol
|
|||||||
public const byte CMD_UNREGISTER_USER = 0x08; // 注销用户
|
public const byte CMD_UNREGISTER_USER = 0x08; // 注销用户
|
||||||
|
|
||||||
// 通知类型
|
// 通知类型
|
||||||
public const byte NOTIFY_MOSQUITO_DATA = 0x0B; // 蚊虫数据通知
|
public const byte NOTIFY_DEVICE_STATE_CHANGE = 0x01; // 设备状态变化(工作模式变化)
|
||||||
|
public const byte NOTIFY_ERROR_STATUS = 0x02; // 错误状态上报(7字节硬件错误状态)
|
||||||
|
public const byte NOTIFY_STATISTICS_UPDATE = 0x03; // 统计数据更新
|
||||||
|
public const byte NOTIFY_SECURITY_ALERT = 0x05; // 安全告警(人体检测等)
|
||||||
|
public const byte NOTIFY_PARAMETER_CHANGE = 0x06; // 参数变化通知
|
||||||
|
public const byte NOTIFY_CAPACITOR_STATE = 0x08; // 蓄能状态通知
|
||||||
|
public const byte NOTIFY_FILL_LIGHT_CONNECTION = 0x09; // 补光灯连接状态通知
|
||||||
|
public const byte NOTIFY_MOSQUITO_DATA = 0x0B; // 蚊虫数据通知
|
||||||
|
|
||||||
|
// 通知帧的"命令码"字段(与读写命令区分,统一使用 0xF0)
|
||||||
|
public const byte NOTIFY_COMMAND_CODE = 0xF0;
|
||||||
|
|
||||||
// 命令码 - 设备设置类 (0x10-0x1F)
|
// 命令码 - 设备设置类 (0x10-0x1F)
|
||||||
public const byte CMD_LANGUAGE_SETTING = 0x10; // 语言设置
|
public const byte CMD_LANGUAGE_SETTING = 0x10; // 语言设置
|
||||||
@ -2259,5 +2269,118 @@ namespace Kill.Bluetooth.Protocol
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region 通知数据 (0xF0 通知帧)
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设备状态变化通知
|
||||||
|
/// 通知类型 0x01:data[0]=0x01,data[1]=工作模式状态码(0=待机 1=扫描 2=消杀)
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public struct DeviceStateChangeNotification
|
||||||
|
{
|
||||||
|
public byte WorkMode; // 0x00=待机, 0x01=扫描, 0x02=消杀
|
||||||
|
|
||||||
|
public static DeviceStateChangeNotification FromBytes(byte[] data)
|
||||||
|
{
|
||||||
|
var notify = new DeviceStateChangeNotification();
|
||||||
|
if (data != null && data.Length >= 2)
|
||||||
|
{
|
||||||
|
notify.WorkMode = data[1];
|
||||||
|
}
|
||||||
|
return notify;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 错误状态上报通知
|
||||||
|
/// 通知类型 0x02:data[0]=0x02,data[1..7]=7字节硬件错误状态(与 0xA1 读响应一致)
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public struct ErrorStatusNotification
|
||||||
|
{
|
||||||
|
public HardwareStatus Status;
|
||||||
|
|
||||||
|
public static ErrorStatusNotification FromBytes(byte[] data)
|
||||||
|
{
|
||||||
|
var notify = new ErrorStatusNotification();
|
||||||
|
if (data != null && data.Length >= 8)
|
||||||
|
{
|
||||||
|
byte[] statusBytes = new byte[7];
|
||||||
|
Buffer.BlockCopy(data, 1, statusBytes, 0, 7);
|
||||||
|
notify.Status = HardwareStatus.FromBytes(statusBytes);
|
||||||
|
}
|
||||||
|
return notify;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 参数变化通知
|
||||||
|
/// 通知类型 0x06:data[0]=0x06,data[1]=发生变化的命令码,data[2..]=参数数据(与对应读响应一致)
|
||||||
|
/// 用于通知 APP 设备端参数被修改,无需 APP 主动查询即可同步
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public struct ParameterChangeNotification
|
||||||
|
{
|
||||||
|
public byte CommandCode; // 发生变化的命令码(如 0x10=语言, 0x12=定时任务, 0x22=RGB, 0x26=补光灯 等)
|
||||||
|
public byte[] Payload; // 参数原始字节(不含通知类型与命令码字节)
|
||||||
|
|
||||||
|
public static ParameterChangeNotification FromBytes(byte[] data)
|
||||||
|
{
|
||||||
|
var notify = new ParameterChangeNotification();
|
||||||
|
if (data != null && data.Length >= 2)
|
||||||
|
{
|
||||||
|
notify.CommandCode = data[1];
|
||||||
|
if (data.Length > 2)
|
||||||
|
{
|
||||||
|
notify.Payload = new byte[data.Length - 2];
|
||||||
|
Buffer.BlockCopy(data, 2, notify.Payload, 0, notify.Payload.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return notify;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 补光灯连接状态通知
|
||||||
|
/// 通知类型 0x09:data[0]=0x09,data[1]=连接状态(0=断开 1=连接)
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public struct FillLightConnectionNotification
|
||||||
|
{
|
||||||
|
public bool IsConnected;
|
||||||
|
|
||||||
|
public static FillLightConnectionNotification FromBytes(byte[] data)
|
||||||
|
{
|
||||||
|
var notify = new FillLightConnectionNotification();
|
||||||
|
if (data != null && data.Length >= 2)
|
||||||
|
{
|
||||||
|
notify.IsConnected = data[1] == 0x01;
|
||||||
|
}
|
||||||
|
return notify;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 蓄能状态通知
|
||||||
|
/// 通知类型 0x08:data[0]=0x08,data[1]=状态(0=充电开始 1=充电完成)
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public struct CapacitorStateNotification
|
||||||
|
{
|
||||||
|
public byte State; // 0=充电开始, 1=充电完成
|
||||||
|
|
||||||
|
public static CapacitorStateNotification FromBytes(byte[] data)
|
||||||
|
{
|
||||||
|
var notify = new CapacitorStateNotification();
|
||||||
|
if (data != null && data.Length >= 2)
|
||||||
|
{
|
||||||
|
notify.State = data[1];
|
||||||
|
}
|
||||||
|
return notify;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -161,6 +161,9 @@ namespace Kill.UI.Pages
|
|||||||
BLECommunicationManager.Instance.OnVisualDetectionSettingReceived += OnVisualDetectionReceived;
|
BLECommunicationManager.Instance.OnVisualDetectionSettingReceived += OnVisualDetectionReceived;
|
||||||
// 订阅蚊虫数据事件
|
// 订阅蚊虫数据事件
|
||||||
BLECommunicationManager.Instance.OnMosquitoDataReceived += OnMosquitoDataReceived;
|
BLECommunicationManager.Instance.OnMosquitoDataReceived += OnMosquitoDataReceived;
|
||||||
|
|
||||||
|
// 订阅本地状态变化事件(按字段局部刷新,保留首次全量拉取)
|
||||||
|
BLECommunicationManager.Instance.OnDeviceStateChanged += OnDeviceStateChanged;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,6 +198,9 @@ namespace Kill.UI.Pages
|
|||||||
BLECommunicationManager.Instance.OnVisualDetectionSettingReceived -= OnVisualDetectionReceived;
|
BLECommunicationManager.Instance.OnVisualDetectionSettingReceived -= OnVisualDetectionReceived;
|
||||||
// 取消订阅蚊虫数据事件
|
// 取消订阅蚊虫数据事件
|
||||||
BLECommunicationManager.Instance.OnMosquitoDataReceived -= OnMosquitoDataReceived;
|
BLECommunicationManager.Instance.OnMosquitoDataReceived -= OnMosquitoDataReceived;
|
||||||
|
|
||||||
|
// 取消订阅本地状态变化事件
|
||||||
|
BLECommunicationManager.Instance.OnDeviceStateChanged -= OnDeviceStateChanged;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -482,6 +488,106 @@ namespace Kill.UI.Pages
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region 本地设备状态变化 (按字段局部刷新)
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 按 MAC 隔离:当前设备不匹配(已切换/未连接/选中设备不同)则丢弃通知
|
||||||
|
/// </summary>
|
||||||
|
private bool IsNotificationForCurrentDevice()
|
||||||
|
{
|
||||||
|
string mac = BLECommunicationManager.Instance?.GetCurrentDeviceMac();
|
||||||
|
string selectedMac = selectedDevice?.ble_mac;
|
||||||
|
if (string.IsNullOrEmpty(mac) || string.IsNullOrEmpty(selectedMac)) return false;
|
||||||
|
return string.Equals(mac, selectedMac, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 本地设备状态变化回调(按字段局部刷新)
|
||||||
|
/// 0x01/0x06 通知已由 BLECommunicationManager 解析后回写仓库并按字段广播
|
||||||
|
/// 首次全量拉取阶段保留原路径,让读响应触发 UI 更新,避免重复刷新
|
||||||
|
/// </summary>
|
||||||
|
private void OnDeviceStateChanged(BLEDeviceState state, BLEDeviceStateField field)
|
||||||
|
{
|
||||||
|
if (state == null) return;
|
||||||
|
if (!IsNotificationForCurrentDevice()) return;
|
||||||
|
if (isDeviceStateInitializing) return;
|
||||||
|
|
||||||
|
switch (field)
|
||||||
|
{
|
||||||
|
case BLEDeviceStateField.WorkMode:
|
||||||
|
if (state.WorkMode.HasValue)
|
||||||
|
{
|
||||||
|
int mode = (int)state.WorkMode.Value;
|
||||||
|
currentWorkMode = state.WorkMode.Value;
|
||||||
|
DataManager.Instance.deviceConfig.work_mode = DeviceConfig.ToServerString(state.WorkMode.Value);
|
||||||
|
pendingUIUpdates.Add(() => deviceCtrl?.InitWrokMode(mode));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BLEDeviceStateField.Angle:
|
||||||
|
if (state.Angle.HasValue && !FovSettingPage.IsSettingPageActive())
|
||||||
|
{
|
||||||
|
int fov = (int)state.Angle.Value.ActualAngle;
|
||||||
|
pendingUIUpdates.Add(() => deviceCtrl?.InitFovText(fov));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BLEDeviceStateField.Distance:
|
||||||
|
if (state.Distance.HasValue && !LensSettingPage.IsSettingPageActive())
|
||||||
|
{
|
||||||
|
float detectionDistance = state.Distance.Value.DetectionDistance / 10f;
|
||||||
|
pendingUIUpdates.Add(() =>
|
||||||
|
deviceCtrl?.InitLensText(detectionDistance, DataManager.Instance.userInfo.unit_system));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BLEDeviceStateField.FillLight:
|
||||||
|
if (state.FillLight.HasValue && !LightSettingPage.IsSettingPageActive())
|
||||||
|
{
|
||||||
|
bool enable = state.FillLight.Value.Enable;
|
||||||
|
pendingUIUpdates.Add(() => deviceCtrl?.InitLightText(enable));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BLEDeviceStateField.VisualDetection:
|
||||||
|
if (state.VisualDetection.HasValue && !SafetySettingPage.IsSettingPageActive())
|
||||||
|
{
|
||||||
|
bool enable = state.VisualDetection.Value.Enable;
|
||||||
|
pendingUIUpdates.Add(() => deviceCtrl?.InitSafeText(enable));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BLEDeviceStateField.LockState:
|
||||||
|
if (state.LockState.HasValue)
|
||||||
|
{
|
||||||
|
bool isLocked = state.LockState.Value.IsLocked;
|
||||||
|
pendingUIUpdates.Add(() => deviceCtrl?.InitDeviceControl(!isLocked));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BLEDeviceStateField.ScheduleTasks:
|
||||||
|
if (!ScheduleSettingPage.IsSettingPageActive())
|
||||||
|
{
|
||||||
|
var tasks = state.ScheduleTasks;
|
||||||
|
if (tasks != null && tasks.Length > 0)
|
||||||
|
{
|
||||||
|
pendingUIUpdates.Add(() => deviceSchedule?.Init(tasks));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pendingUIUpdates.Add(() => deviceSchedule?.DisplayNoSchedule());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BLEDeviceStateField.Language:
|
||||||
|
if (state.Language.HasValue)
|
||||||
|
{
|
||||||
|
DataManager.Instance.deviceConfig.language = state.Language.Value.IsChinese ? 1 : 0;
|
||||||
|
DataManager.Instance.SyncDeviceConfigToServer();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// 其他字段(Connection / LockState / HardwareStatus / CapacitorState / FillLightConnection)暂不在主页直接刷新
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region 网络状态事件处理
|
#region 网络状态事件处理
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
2
SyntaxCheck/Program.cs
Normal file
2
SyntaxCheck/Program.cs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
// See https://aka.ms/new-console-template for more information
|
||||||
|
Console.WriteLine("Hello, World!");
|
||||||
61
SyntaxCheck/obj/SyntaxCheck.csproj.nuget.dgspec.json
Normal file
61
SyntaxCheck/obj/SyntaxCheck.csproj.nuget.dgspec.json
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"format": 1,
|
||||||
|
"restore": {
|
||||||
|
"D:\\unity_project\\Kill\\SyntaxCheck\\SyntaxCheck.csproj": {}
|
||||||
|
},
|
||||||
|
"projects": {
|
||||||
|
"D:\\unity_project\\Kill\\SyntaxCheck\\SyntaxCheck.csproj": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"restore": {
|
||||||
|
"projectUniqueName": "D:\\unity_project\\Kill\\SyntaxCheck\\SyntaxCheck.csproj",
|
||||||
|
"projectName": "SyntaxCheck",
|
||||||
|
"projectPath": "D:\\unity_project\\Kill\\SyntaxCheck\\SyntaxCheck.csproj",
|
||||||
|
"packagesPath": "C:\\Users\\YQC\\.nuget\\packages\\",
|
||||||
|
"outputPath": "D:\\unity_project\\Kill\\SyntaxCheck\\obj\\",
|
||||||
|
"projectStyle": "PackageReference",
|
||||||
|
"configFilePaths": [
|
||||||
|
"C:\\Users\\YQC\\AppData\\Roaming\\NuGet\\NuGet.Config"
|
||||||
|
],
|
||||||
|
"originalTargetFrameworks": [
|
||||||
|
"net8.0"
|
||||||
|
],
|
||||||
|
"sources": {
|
||||||
|
"https://api.nuget.org/v3/index.json": {}
|
||||||
|
},
|
||||||
|
"frameworks": {
|
||||||
|
"net8.0": {
|
||||||
|
"targetAlias": "net8.0",
|
||||||
|
"projectReferences": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"warningProperties": {
|
||||||
|
"warnAsError": [
|
||||||
|
"NU1605"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"frameworks": {
|
||||||
|
"net8.0": {
|
||||||
|
"targetAlias": "net8.0",
|
||||||
|
"imports": [
|
||||||
|
"net461",
|
||||||
|
"net462",
|
||||||
|
"net47",
|
||||||
|
"net471",
|
||||||
|
"net472",
|
||||||
|
"net48",
|
||||||
|
"net481"
|
||||||
|
],
|
||||||
|
"assetTargetFallback": true,
|
||||||
|
"warn": true,
|
||||||
|
"frameworkReferences": {
|
||||||
|
"Microsoft.NETCore.App": {
|
||||||
|
"privateAssets": "all"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\8.0.113/PortableRuntimeIdentifierGraph.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
SyntaxCheck/obj/SyntaxCheck.csproj.nuget.g.props
Normal file
15
SyntaxCheck/obj/SyntaxCheck.csproj.nuget.g.props
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
|
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
|
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
|
||||||
|
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
|
||||||
|
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
|
||||||
|
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
||||||
|
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\YQC\.nuget\packages\</NuGetPackageFolders>
|
||||||
|
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
||||||
|
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.8.1</NuGetToolVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
|
<SourceRoot Include="C:\Users\YQC\.nuget\packages\" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
2
SyntaxCheck/obj/SyntaxCheck.csproj.nuget.g.targets
Normal file
2
SyntaxCheck/obj/SyntaxCheck.csproj.nuget.g.targets
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
|
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />
|
||||||
66
SyntaxCheck/obj/project.assets.json
Normal file
66
SyntaxCheck/obj/project.assets.json
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"targets": {
|
||||||
|
"net8.0": {}
|
||||||
|
},
|
||||||
|
"libraries": {},
|
||||||
|
"projectFileDependencyGroups": {
|
||||||
|
"net8.0": []
|
||||||
|
},
|
||||||
|
"packageFolders": {
|
||||||
|
"C:\\Users\\YQC\\.nuget\\packages\\": {}
|
||||||
|
},
|
||||||
|
"project": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"restore": {
|
||||||
|
"projectUniqueName": "D:\\unity_project\\Kill\\SyntaxCheck\\SyntaxCheck.csproj",
|
||||||
|
"projectName": "SyntaxCheck",
|
||||||
|
"projectPath": "D:\\unity_project\\Kill\\SyntaxCheck\\SyntaxCheck.csproj",
|
||||||
|
"packagesPath": "C:\\Users\\YQC\\.nuget\\packages\\",
|
||||||
|
"outputPath": "D:\\unity_project\\Kill\\SyntaxCheck\\obj\\",
|
||||||
|
"projectStyle": "PackageReference",
|
||||||
|
"configFilePaths": [
|
||||||
|
"C:\\Users\\YQC\\AppData\\Roaming\\NuGet\\NuGet.Config"
|
||||||
|
],
|
||||||
|
"originalTargetFrameworks": [
|
||||||
|
"net8.0"
|
||||||
|
],
|
||||||
|
"sources": {
|
||||||
|
"https://api.nuget.org/v3/index.json": {}
|
||||||
|
},
|
||||||
|
"frameworks": {
|
||||||
|
"net8.0": {
|
||||||
|
"targetAlias": "net8.0",
|
||||||
|
"projectReferences": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"warningProperties": {
|
||||||
|
"warnAsError": [
|
||||||
|
"NU1605"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"frameworks": {
|
||||||
|
"net8.0": {
|
||||||
|
"targetAlias": "net8.0",
|
||||||
|
"imports": [
|
||||||
|
"net461",
|
||||||
|
"net462",
|
||||||
|
"net47",
|
||||||
|
"net471",
|
||||||
|
"net472",
|
||||||
|
"net48",
|
||||||
|
"net481"
|
||||||
|
],
|
||||||
|
"assetTargetFallback": true,
|
||||||
|
"warn": true,
|
||||||
|
"frameworkReferences": {
|
||||||
|
"Microsoft.NETCore.App": {
|
||||||
|
"privateAssets": "all"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\8.0.113/PortableRuntimeIdentifierGraph.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
SyntaxCheck/obj/project.nuget.cache
Normal file
8
SyntaxCheck/obj/project.nuget.cache
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"dgSpecHash": "vIdeVNNgNyV9g05vzz3zmuhU/jhHrG+wZsLvVl3eSXOZZKrYzX6bKgJanV1KB2n7qJpxJWpw9zhuwF9gTFQftw==",
|
||||||
|
"success": true,
|
||||||
|
"projectFilePath": "D:\\unity_project\\Kill\\SyntaxCheck\\SyntaxCheck.csproj",
|
||||||
|
"expectedPackageFiles": [],
|
||||||
|
"logs": []
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user