2358 lines
75 KiB
C#
2358 lines
75 KiB
C#
using UnityEngine;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using BLEProtocol;
|
||
|
||
/// <summary>
|
||
/// BLE通信管理器 - 处理协议层通信
|
||
/// 基于 BluetoothManager 进行协议通信
|
||
/// </summary>
|
||
public class BLECommunicationManager : MonoBehaviour
|
||
{
|
||
public static BLECommunicationManager Instance { get; private set; }
|
||
|
||
// 事件定义
|
||
public event Action<DeviceRegistrationStatus> OnRegistrationStatusReceived; // 收到注册状态
|
||
public event Action<bool, string> OnRegisterResult; // 注册结果 (成功/失败, 消息)
|
||
public event Action<UserListResponse> OnUserListReceived; // 收到用户列表
|
||
public event Action<UnregisterUserResponse> OnUnregisterUserResult; // 注销用户结果
|
||
public event Action<UserLoginResponse> OnUserLoginResult; // 用户登录结果
|
||
public event Action<FingerprintEnableResponse> OnFingerprintEnableResult; // 指纹使能设置结果
|
||
public event Action<FingerprintRecordResponse> OnFingerprintRecordResult; // 指纹录制结果
|
||
public event Action<LanguageSetting> OnLanguageSettingReceived; // 收到语言设置
|
||
public event Action<TimeSetting> OnTimeSettingReceived; // 收到时间设置
|
||
public event Action<ScheduleTaskListResponse> OnScheduleTaskListReceived; // 收到定时任务列表
|
||
public event Action<LCDSleepSetting> OnLCDSleepSettingReceived; // 收到LCD休眠设置
|
||
public event Action<LCDBrightnessSetting> OnLCDBrightnessSettingReceived; // 收到LCD亮度设置
|
||
public event Action<RGBControl> OnRGBControlReceived; // 收到RGB控制设置
|
||
public event Action<WIFIControl> OnWIFIControlReceived; // 收到WIFI控制设置
|
||
public event Action<BLEControl> OnBLEControlReceived; // 收到BLE控制设置
|
||
public event Action<MultimediaControl> OnMultimediaControlReceived; // 收到多媒体控制设置
|
||
public event Action<FillLightControl> OnFillLightControlReceived; // 收到补光灯控制设置
|
||
public event Action<FillLightConnectionStatus> OnFillLightConnectionStatusReceived; // 收到补光灯连接状态
|
||
public event Action<VisibleLaserControl> OnVisibleLaserControlReceived; // 收到可见光激光器控制设置
|
||
public event Action<AngleControl> OnAngleControlReceived; // 收到角度控制设置
|
||
public event Action<DistanceControl> OnDistanceControlReceived; // 收到距离控制设置
|
||
public event Action<MillimeterWaveSetting> OnMillimeterWaveSettingReceived; // 收到毫米波雷达设置
|
||
public event Action<VisualDetectionSetting> OnVisualDetectionSettingReceived; // 收到视觉检测设置
|
||
public event Action<AccelerometerSetting> OnAccelerometerSettingReceived; // 收到加速度传感器设置
|
||
public event Action<AccelerometerData> OnAccelerometerDataReceived; // 收到加速度传感器数据
|
||
public event Action<TemperatureMonitorSetting> OnTemperatureMonitorSettingReceived; // 收到温度监控设置
|
||
public event Action<EnvironmentChangeTest> OnEnvironmentChangeStatusReceived; // 收到环境变化状态
|
||
public event Action<WorkModeSetting> OnWorkModeSettingReceived; // 收到工作模式设置
|
||
public event Action<HardwareStatus> OnHardwareStatusReceived; // 收到硬件状态
|
||
public event Action<DeviceInfo> OnDeviceInfoReceived; // 收到设备信息
|
||
public event Action<StatisticsData> OnStatisticsDataReceived; // 收到统计数据
|
||
public event Action<SensorData> OnSensorDataReceived; // 收到传感器数据
|
||
public event Action<MosquitoData> OnMosquitoDataReceived; // 收到蚊虫数据通知
|
||
public event Action<byte[]> OnDataReceived; // 收到原始数据
|
||
public event Action<string> OnRawDataReceived; // 收到原始数据(十六进制字符串)
|
||
public event Action<string> OnRawDataSent; // 发送原始数据(十六进制字符串)
|
||
public event Action<string> OnCommunicationError; // 通信错误
|
||
|
||
// 状态
|
||
public bool IsWaitingResponse { get; private set; }
|
||
public byte LastCommand { get; private set; }
|
||
|
||
// 响应超时设置 (OTA传输需要更长时间,增加到10秒)
|
||
public float ResponseTimeout = 10f;
|
||
|
||
// 数据接收缓冲区
|
||
private List<byte> _receiveBuffer = new List<byte>();
|
||
private float _responseTimer;
|
||
private Action<BLEResponse> _pendingCallback;
|
||
|
||
// 服务和特征UUID (根据实际设备配置)
|
||
public string ServiceUUID = "0000ffe0-0000-1000-8000-00805f9b34fb";
|
||
public string WriteCharacteristicUUID = "0000ffe1-0000-1000-8000-00805f9b34fb";
|
||
public string NotifyCharacteristicUUID = "0000ffe1-0000-1000-8000-00805f9b34fb";
|
||
|
||
// 是否自动初始化通信
|
||
public bool AutoInitialize = true;
|
||
|
||
private void Awake()
|
||
{
|
||
if (Instance == null)
|
||
{
|
||
Instance = this;
|
||
DontDestroyOnLoad(gameObject);
|
||
}
|
||
else
|
||
{
|
||
Destroy(gameObject);
|
||
}
|
||
}
|
||
|
||
private void Start()
|
||
{
|
||
Log("[BLECommunicationManager.Start] 开始执行...");
|
||
// 订阅蓝牙连接事件
|
||
if (BluetoothManager.Instance != null)
|
||
{
|
||
Log($"[BLECommunicationManager.Start] BluetoothManager.Instance 存在,IsConnected={BluetoothManager.Instance.IsConnected}");
|
||
BluetoothManager.Instance.OnConnectedSuccess += OnBluetoothConnected;
|
||
BluetoothManager.Instance.OnDisconnected += OnBluetoothDisconnected;
|
||
BluetoothManager.Instance.OnError += OnBluetoothError;
|
||
Log("[BLECommunicationManager.Start] 事件订阅完成");
|
||
|
||
// 如果已经连接(可能是自动连接已完成),立即初始化
|
||
if (BluetoothManager.Instance.IsConnected)
|
||
{
|
||
Log("[BLECommunicationManager.Start] 检测到蓝牙已连接,立即初始化通信...");
|
||
OnBluetoothConnected();
|
||
}
|
||
else
|
||
{
|
||
Log("[BLECommunicationManager.Start] 蓝牙未连接,等待连接事件...");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
LogError("[BLECommunicationManager.Start] BluetoothManager.Instance 为 null!");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 蓝牙错误回调
|
||
/// </summary>
|
||
private void OnBluetoothError(string error)
|
||
{
|
||
// 忽略 "Service not found" 错误,因为这是正常的(还没连接设备)
|
||
if (error.Contains("Service not found"))
|
||
{
|
||
Log("蓝牙服务未找到(正常:尚未连接设备)");
|
||
return;
|
||
}
|
||
|
||
LogError($"蓝牙错误: {error}");
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
// 取消订阅事件
|
||
if (BluetoothManager.Instance != null)
|
||
{
|
||
BluetoothManager.Instance.OnConnectedSuccess -= OnBluetoothConnected;
|
||
BluetoothManager.Instance.OnDisconnected -= OnBluetoothDisconnected;
|
||
BluetoothManager.Instance.OnError -= OnBluetoothError;
|
||
}
|
||
|
||
if (Instance == this)
|
||
{
|
||
Instance = null;
|
||
}
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
// 响应超时检测
|
||
if (IsWaitingResponse)
|
||
{
|
||
_responseTimer -= Time.deltaTime;
|
||
if (_responseTimer <= 0)
|
||
{
|
||
OnResponseTimeout();
|
||
}
|
||
}
|
||
}
|
||
|
||
#region 蓝牙连接和通知设置
|
||
|
||
/// <summary>
|
||
/// 蓝牙连接成功回调(特征发现完成后调用)
|
||
/// </summary>
|
||
private void OnBluetoothConnected()
|
||
{
|
||
if (AutoInitialize)
|
||
InitializeCommunication();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 蓝牙断开连接回调
|
||
/// </summary>
|
||
private void OnBluetoothDisconnected(string address)
|
||
{
|
||
Log($"蓝牙已断开: {address}");
|
||
// 清理状态
|
||
IsWaitingResponse = false;
|
||
_responseTimer = 0;
|
||
_pendingCallback = null;
|
||
_receiveBuffer.Clear();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化BLE通信 (连接成功后自动调用,也可手动调用)
|
||
/// </summary>
|
||
public void InitializeCommunication()
|
||
{
|
||
if (BluetoothManager.Instance == null || !BluetoothManager.Instance.IsConnected) return;
|
||
|
||
ServiceUUID = ServiceUUID.ToLower();
|
||
WriteCharacteristicUUID = WriteCharacteristicUUID.ToLower();
|
||
NotifyCharacteristicUUID = NotifyCharacteristicUUID.ToLower();
|
||
|
||
SubscribeToNotifications();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 订阅设备通知
|
||
/// </summary>
|
||
private void SubscribeToNotifications()
|
||
{
|
||
string deviceAddress = BluetoothManager.Instance.ConnectedDeviceAddress;
|
||
|
||
ServiceUUID = ServiceUUID.ToLower();
|
||
WriteCharacteristicUUID = WriteCharacteristicUUID.ToLower();
|
||
NotifyCharacteristicUUID = NotifyCharacteristicUUID.ToLower();
|
||
|
||
Log($"[BLE-DEBUG] 订阅通知: 地址={deviceAddress}");
|
||
|
||
try
|
||
{
|
||
BluetoothLEHardwareInterface.SubscribeCharacteristicWithDeviceAddress(
|
||
deviceAddress,
|
||
ServiceUUID,
|
||
NotifyCharacteristicUUID,
|
||
(notifyAddress, notifyCharacteristic) =>
|
||
{
|
||
Log($"[BLE-DEBUG] 订阅成功: {notifyCharacteristic}");
|
||
},
|
||
(address, characteristicUUID, bytes) =>
|
||
{
|
||
OnNotificationReceived(bytes);
|
||
}
|
||
);
|
||
}
|
||
catch (System.Exception ex)
|
||
{
|
||
LogError($"[BLE-DEBUG] 订阅异常: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 取消订阅通知
|
||
/// </summary>
|
||
public void UnsubscribeNotifications()
|
||
{
|
||
if (BluetoothManager.Instance == null || !BluetoothManager.Instance.IsConnected)
|
||
return;
|
||
|
||
string deviceAddress = BluetoothManager.Instance.ConnectedDeviceAddress;
|
||
|
||
BluetoothLEHardwareInterface.UnSubscribeCharacteristic(
|
||
deviceAddress,
|
||
ServiceUUID,
|
||
NotifyCharacteristicUUID,
|
||
null
|
||
);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 设备注册与认证接口
|
||
|
||
/// <summary>
|
||
/// 查询设备注册状态 (命令 0x01)
|
||
/// </summary>
|
||
public void QueryRegistrationStatus(Action<DeviceRegistrationStatus> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
// 构建查询帧
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_QUERY_REGISTRATION,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
if (response.IsSuccess && response.Data != null)
|
||
{
|
||
var status = DeviceRegistrationStatus.FromBytes(response.Data);
|
||
callback?.Invoke(status);
|
||
OnRegistrationStatusReceived?.Invoke(status);
|
||
}
|
||
else
|
||
{
|
||
LogError($"查询注册状态失败: 状态码={response.Status:X2}");
|
||
callback?.Invoke(new DeviceRegistrationStatus());
|
||
}
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设备注册绑定 (命令 0x02)
|
||
/// 注意:根据协议,只发送用户名,不发送密码
|
||
/// </summary>
|
||
/// <param name="username">用户名</param>
|
||
/// <param name="callback">回调 (成功/失败, 消息)</param>
|
||
public void RegisterDevice(string username, Action<bool, string> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
// 验证输入
|
||
if (string.IsNullOrEmpty(username) || username.Length > BLEConstants.MAX_USERNAME_LENGTH)
|
||
{
|
||
callback?.Invoke(false, $"用户名长度必须在1-{BLEConstants.MAX_USERNAME_LENGTH}之间");
|
||
return;
|
||
}
|
||
|
||
// 构建注册请求(只发送用户名)
|
||
var request = new DeviceRegisterRequest
|
||
{
|
||
Username = username
|
||
};
|
||
|
||
byte[] requestData = request.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_DEVICE_REGISTER,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)requestData.Length,
|
||
Data = requestData
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
string message = GetStatusMessage(response.Status);
|
||
|
||
if (success)
|
||
{
|
||
Log($"设备注册成功: 用户={username}");
|
||
if (response.Data != null && response.Data.Length > 0)
|
||
{
|
||
Log($"注册响应数据: {System.BitConverter.ToString(response.Data)}");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
LogError($"设备注册失败: {message}");
|
||
}
|
||
|
||
callback?.Invoke(success, message);
|
||
OnRegisterResult?.Invoke(success, message);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 用户登录 (命令 0x03)
|
||
/// 数据格式:用户名(16字节) + 解锁状态(1字节),解锁状态固定为1
|
||
/// </summary>
|
||
/// <param name="username">用户名</param>
|
||
/// <param name="callback">回调 (响应结果)</param>
|
||
public void UserLogin(string username, Action<UserLoginResponse> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
// 验证输入
|
||
if (string.IsNullOrEmpty(username) || username.Length > BLEConstants.MAX_USERNAME_LENGTH)
|
||
{
|
||
LogError($"用户名长度必须在1-{BLEConstants.MAX_USERNAME_LENGTH}之间");
|
||
callback?.Invoke(new UserLoginResponse { Status = BLEConstants.STATUS_PARAM_ERROR });
|
||
return;
|
||
}
|
||
|
||
// 构建登录请求
|
||
var request = new UserLoginRequest
|
||
{
|
||
Username = username,
|
||
UnlockStatus = 0x01 // 解锁状态固定为1
|
||
};
|
||
|
||
byte[] requestData = request.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_USER_LOGIN,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)requestData.Length,
|
||
Data = requestData
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var loginResponse = UserLoginResponse.FromBytes(response.Status);
|
||
|
||
if (loginResponse.IsSuccess)
|
||
{
|
||
Log($"用户登录成功: {username}");
|
||
}
|
||
else
|
||
{
|
||
LogError($"用户登录失败: {username}, 状态码={response.Status:X2}");
|
||
}
|
||
|
||
callback?.Invoke(loginResponse);
|
||
OnUserLoginResult?.Invoke(loginResponse);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 指纹登录使能设置 (命令 0x04)
|
||
/// 数据格式:用户名(16字节) + 使能状态(1字节)
|
||
/// </summary>
|
||
/// <param name="username">用户名</param>
|
||
/// <param name="enable">使能状态:true=使能, false=禁用</param>
|
||
/// <param name="callback">回调 (响应结果)</param>
|
||
public void SetFingerprintEnable(string username, bool enable, Action<FingerprintEnableResponse> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
// 验证输入
|
||
if (string.IsNullOrEmpty(username) || username.Length > BLEConstants.MAX_USERNAME_LENGTH)
|
||
{
|
||
LogError($"用户名长度必须在1-{BLEConstants.MAX_USERNAME_LENGTH}之间");
|
||
callback?.Invoke(new FingerprintEnableResponse { Status = BLEConstants.STATUS_PARAM_ERROR });
|
||
return;
|
||
}
|
||
|
||
// 构建请求
|
||
var request = new FingerprintEnableRequest
|
||
{
|
||
Username = username,
|
||
Enable = enable
|
||
};
|
||
|
||
byte[] requestData = request.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_FINGERPRINT_ENABLE,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)requestData.Length,
|
||
Data = requestData
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var enableResponse = FingerprintEnableResponse.FromBytes(response.Status);
|
||
|
||
if (enableResponse.IsSuccess)
|
||
{
|
||
Log($"指纹登录使能设置成功: {username}, 状态={(enable ? "使能" : "禁用")}");
|
||
}
|
||
else
|
||
{
|
||
LogError($"指纹登录使能设置失败: {username}, 状态码={response.Status:X2}");
|
||
}
|
||
|
||
callback?.Invoke(enableResponse);
|
||
OnFingerprintEnableResult?.Invoke(enableResponse);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 指纹录制请求 (命令 0x05)
|
||
/// 启动指纹注册流程
|
||
/// </summary>
|
||
/// <param name="username">用户名</param>
|
||
/// <param name="callback">回调 (响应结果)</param>
|
||
public void StartFingerprintRecord(string username, Action<FingerprintRecordResponse> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
// 验证输入
|
||
if (string.IsNullOrEmpty(username) || username.Length > BLEConstants.MAX_USERNAME_LENGTH)
|
||
{
|
||
LogError($"用户名长度必须在1-{BLEConstants.MAX_USERNAME_LENGTH}之间");
|
||
callback?.Invoke(new FingerprintRecordResponse { Status = BLEConstants.STATUS_PARAM_ERROR });
|
||
return;
|
||
}
|
||
|
||
// 构建请求
|
||
var request = new FingerprintRecordRequest
|
||
{
|
||
Username = username
|
||
};
|
||
|
||
byte[] requestData = request.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_FINGERPRINT_RECORD,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)requestData.Length,
|
||
Data = requestData
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var recordResponse = FingerprintRecordResponse.FromBytes(response.Status);
|
||
|
||
if (recordResponse.IsSuccess)
|
||
{
|
||
Log($"指纹录制请求成功: {username}");
|
||
}
|
||
else
|
||
{
|
||
LogError($"指纹录制请求失败: {username}, 状态码={response.Status:X2}");
|
||
}
|
||
|
||
callback?.Invoke(recordResponse);
|
||
OnFingerprintRecordResult?.Invoke(recordResponse);
|
||
});
|
||
}
|
||
|
||
#region 设备设置类接口 (0x10-0x1F)
|
||
|
||
/// <summary>
|
||
/// 读取语言设置 (命令 0x10)
|
||
/// </summary>
|
||
public void ReadLanguageSetting(Action<LanguageSetting> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_LANGUAGE_SETTING,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var setting = LanguageSetting.FromBytes(response.Data);
|
||
callback?.Invoke(setting);
|
||
OnLanguageSettingReceived?.Invoke(setting);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入语言设置 (命令 0x10)
|
||
/// </summary>
|
||
/// <param name="isChinese">true=中文, false=英文</param>
|
||
public void WriteLanguageSetting(bool isChinese, Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var setting = new LanguageSetting { Language = isChinese ? (byte)0x01 : (byte)0x00 };
|
||
byte[] data = setting.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_LANGUAGE_SETTING,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
Log($"语言设置成功: {(isChinese ? "中文" : "英文")}");
|
||
else
|
||
LogError($"语言设置失败, 状态码={response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取时间设置 (命令 0x11)
|
||
/// </summary>
|
||
public void ReadTimeSetting(Action<TimeSetting> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_TIME_SETTING,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var setting = TimeSetting.FromBytes(response.Data);
|
||
callback?.Invoke(setting);
|
||
OnTimeSettingReceived?.Invoke(setting);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入时间设置 (命令 0x11)
|
||
/// </summary>
|
||
public void WriteTimeSetting(TimeSetting setting, Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
byte[] data = setting.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_TIME_SETTING,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
Log($"时间设置成功: {setting}");
|
||
else
|
||
LogError($"时间设置失败, 状态码={response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取定时任务列表 (命令 0x12)
|
||
/// </summary>
|
||
public void ReadScheduleTasks(Action<ScheduleTaskListResponse> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_SCHEDULE_TASK,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var taskList = ScheduleTaskListResponse.FromBytes(response.Status, response.Data);
|
||
callback?.Invoke(taskList);
|
||
OnScheduleTaskListReceived?.Invoke(taskList);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入定时任务 (命令 0x12)
|
||
/// 支持一次写入单条或多条定时任务(最多5条)
|
||
/// </summary>
|
||
/// <param name="task">单条定时任务</param>
|
||
/// <param name="callback">回调 (成功/失败)</param>
|
||
public void WriteScheduleTask(ScheduleTask task, Action<bool> callback = null)
|
||
{
|
||
WriteScheduleTasks(new ScheduleTask[] { task }, callback);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入多条定时任务 (命令 0x12)
|
||
/// 支持一次写入最多5组定时任务(硬件已支持批量写入)
|
||
/// </summary>
|
||
/// <param name="tasks">定时任务数组(最多5条,每条8字节)</param>
|
||
/// <param name="callback">回调 (成功/失败)</param>
|
||
public void WriteScheduleTasks(ScheduleTask[] tasks, Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
if (tasks == null || tasks.Length == 0)
|
||
{
|
||
LogError("定时任务数组为空");
|
||
callback?.Invoke(false);
|
||
return;
|
||
}
|
||
|
||
if (tasks.Length > 5)
|
||
{
|
||
LogError("定时任务数量不能超过5条");
|
||
callback?.Invoke(false);
|
||
return;
|
||
}
|
||
|
||
// 计算总数据长度:每条任务8字节
|
||
int totalLength = tasks.Length * 8;
|
||
byte[] data = new byte[totalLength];
|
||
|
||
// 将所有任务序列化到字节数组
|
||
for (int i = 0; i < tasks.Length; i++)
|
||
{
|
||
byte[] taskBytes = tasks[i].ToBytes();
|
||
Buffer.BlockCopy(taskBytes, 0, data, i * 8, 8);
|
||
}
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_SCHEDULE_TASK,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
{
|
||
if (tasks.Length == 1)
|
||
Log($"定时任务设置成功: {tasks[0]}");
|
||
else
|
||
Log($"定时任务批量设置成功,共 {tasks.Length} 条任务");
|
||
}
|
||
else
|
||
{
|
||
LogError($"定时任务设置失败, 状态码={response.Status:X2}");
|
||
}
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 外设控制类接口 (0x20-0x3F)
|
||
|
||
/// <summary>
|
||
/// 读取LCD休眠设置 (命令 0x20)
|
||
/// </summary>
|
||
public void ReadLCDSleepSetting(Action<LCDSleepSetting> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_LCD_SLEEP_SETTING,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var setting = LCDSleepSetting.FromBytes(response.Data);
|
||
callback?.Invoke(setting);
|
||
OnLCDSleepSettingReceived?.Invoke(setting);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入LCD休眠设置 (命令 0x20)
|
||
/// </summary>
|
||
public void WriteLCDSleepSetting(LCDSleepSetting setting, Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
byte[] data = setting.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_LCD_SLEEP_SETTING,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
Log($"LCD休眠设置成功: 开关={(setting.Enable ? "开启" : "关闭")}, 时间={setting.GetSleepTimeString()}");
|
||
else
|
||
LogError($"LCD休眠设置失败, 状态码={response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取LCD亮度设置 (命令 0x21)
|
||
/// </summary>
|
||
public void ReadLCDBrightnessSetting(Action<LCDBrightnessSetting> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_LCD_BRIGHTNESS_SETTING,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var setting = LCDBrightnessSetting.FromBytes(response.Data);
|
||
callback?.Invoke(setting);
|
||
OnLCDBrightnessSettingReceived?.Invoke(setting);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入LCD亮度设置 (命令 0x21)
|
||
/// </summary>
|
||
public void WriteLCDBrightnessSetting(LCDBrightnessSetting setting, Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
byte[] data = setting.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_LCD_BRIGHTNESS_SETTING,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
Log($"LCD亮度设置响应: 状态码={response.Status:X2}, 成功={success}");
|
||
if (success)
|
||
Log($"LCD亮度设置成功: 自适应={(setting.AutoBrightness ? "开启" : "关闭")}, 亮度={setting.Brightness}%");
|
||
else
|
||
LogError($"LCD亮度设置失败, 状态码={response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取RGB指示灯控制 (命令 0x22)
|
||
/// </summary>
|
||
public void ReadRGBControl(Action<RGBControl> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_RGB_CONTROL,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var control = RGBControl.FromBytes(response.Data);
|
||
callback?.Invoke(control);
|
||
OnRGBControlReceived?.Invoke(control);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入RGB指示灯控制 (命令 0x22)
|
||
/// </summary>
|
||
public void WriteRGBControl(RGBControl control, Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
byte[] data = control.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_RGB_CONTROL,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
Log($"RGB控制设置成功: 开关={(control.Enable ? "开启" : "关闭")}, 颜色={control.Red},{control.Green},{control.Blue}");
|
||
else
|
||
LogError($"RGB控制设置失败, 状态码={response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取WIFI控制 (命令 0x23)
|
||
/// </summary>
|
||
public void ReadWIFIControl(Action<WIFIControl> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_WIFI_CONTROL,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var control = WIFIControl.FromBytes(response.Data);
|
||
callback?.Invoke(control);
|
||
OnWIFIControlReceived?.Invoke(control);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入WIFI控制 (命令 0x23)
|
||
/// </summary>
|
||
public void WriteWIFIControl(WIFIControl control, Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
byte[] data = control.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_WIFI_CONTROL,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
Log($"WIFI控制设置成功: 开关={(control.Enable ? "开启" : "关闭")}, SSID={control.SSID}");
|
||
else
|
||
LogError($"WIFI控制设置失败, 状态码={response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取BLE控制 (命令 0x24)
|
||
/// </summary>
|
||
public void ReadBLEControl(Action<BLEControl> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_BLE_CONTROL,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var control = BLEControl.FromBytes(response.Data);
|
||
callback?.Invoke(control);
|
||
OnBLEControlReceived?.Invoke(control);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入BLE控制 (命令 0x24)
|
||
/// </summary>
|
||
public void WriteBLEControl(BLEControl control, Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
byte[] data = control.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_BLE_CONTROL,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
Log($"BLE控制设置成功: 设备名称={control.DeviceName}");
|
||
else
|
||
LogError($"BLE控制设置失败, 状态码={response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取多媒体控制 (命令 0x25)
|
||
/// </summary>
|
||
public void ReadMultimediaControl(Action<MultimediaControl> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_MULTIMEDIA_CONTROL,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var control = MultimediaControl.FromBytes(response.Data);
|
||
callback?.Invoke(control);
|
||
OnMultimediaControlReceived?.Invoke(control);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入多媒体控制 (命令 0x25)
|
||
/// </summary>
|
||
public void WriteMultimediaControl(MultimediaControl control, Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
byte[] data = control.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_MULTIMEDIA_CONTROL,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
Log($"多媒体控制设置成功: 视频录制={(control.VideoRecordEnable ? "开启" : "关闭")}, 音效={(control.SoundEnable ? "开启" : "关闭")}");
|
||
else
|
||
LogError($"多媒体控制设置失败, 状态码={response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取补光灯控制 (命令 0x26)
|
||
/// </summary>
|
||
public void ReadFillLightControl(Action<FillLightControl> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_FILL_LIGHT_CONTROL,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var control = FillLightControl.FromBytes(response.Data);
|
||
callback?.Invoke(control);
|
||
OnFillLightControlReceived?.Invoke(control);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入补光灯控制 (命令 0x26)
|
||
/// </summary>
|
||
public void WriteFillLightControl(FillLightControl control, Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
byte[] data = control.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_FILL_LIGHT_CONTROL,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
Log($"补光灯控制设置成功: 开关={(control.Enable ? "开启" : "关闭")}, 类型={control.GetLightTypeString()}, 强度={control.GetIntensityString()}");
|
||
else
|
||
LogError($"补光灯控制设置失败, 状态码={response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取补光灯连接状态 (命令 0x27)
|
||
/// </summary>
|
||
public void ReadFillLightConnectionStatus(Action<FillLightConnectionStatus> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_FILL_LIGHT_CONNECTION_STATUS,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var status = FillLightConnectionStatus.FromBytes(response.Data);
|
||
callback?.Invoke(status);
|
||
OnFillLightConnectionStatusReceived?.Invoke(status);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取可见光激光器控制 (命令 0x28)
|
||
/// </summary>
|
||
public void ReadVisibleLaserControl(Action<VisibleLaserControl> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_VISIBLE_LASER_CONTROL,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var control = VisibleLaserControl.FromBytes(response.Data);
|
||
callback?.Invoke(control);
|
||
OnVisibleLaserControlReceived?.Invoke(control);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入可见光激光器控制 (命令 0x28)
|
||
/// </summary>
|
||
public void WriteVisibleLaserControl(VisibleLaserControl control, Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
byte[] data = control.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_VISIBLE_LASER_CONTROL,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
Log($"可见光激光器控制设置成功: 开关={(control.Enable ? "开启" : "关闭")}");
|
||
else
|
||
LogError($"可见光激光器控制设置失败, 状态码={response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 害虫消灭控制类接口 (0x40-0x4F)
|
||
|
||
/// <summary>
|
||
/// 读取角度控制设置 (命令 0x40)
|
||
/// </summary>
|
||
public void ReadAngleControl(Action<AngleControl> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_ANGLE_CONTROL,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var control = AngleControl.FromBytes(response.Data);
|
||
callback?.Invoke(control);
|
||
OnAngleControlReceived?.Invoke(control);
|
||
Log($"读取角度控制: {control}");
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入角度控制设置 (命令 0x40)
|
||
/// </summary>
|
||
/// <param name="control">角度控制设置</param>
|
||
public void WriteAngleControl(AngleControl control, Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
byte[] data = control.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_ANGLE_CONTROL,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
Log($"角度控制设置成功: {control}");
|
||
else
|
||
LogError($"角度控制设置失败, 状态码={response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取距离控制设置 (命令 0x41)
|
||
/// </summary>
|
||
public void ReadDistanceControl(Action<DistanceControl> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_DISTANCE_CONTROL,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var control = DistanceControl.FromBytes(response.Data);
|
||
callback?.Invoke(control);
|
||
OnDistanceControlReceived?.Invoke(control);
|
||
Log($"读取距离控制: {control}");
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入距离控制设置 (命令 0x41)
|
||
/// </summary>
|
||
/// <param name="control">距离控制设置</param>
|
||
public void WriteDistanceControl(DistanceControl control, Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
byte[] data = control.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_DISTANCE_CONTROL,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
Log($"距离控制设置成功: {control}");
|
||
else
|
||
LogError($"距离控制设置失败, 状态码={response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 安全设置类接口 (0x50-0x5F)
|
||
|
||
/// <summary>
|
||
/// 读取毫米波雷达设置 (命令 0x50)
|
||
/// </summary>
|
||
public void ReadMillimeterWaveSetting(Action<MillimeterWaveSetting> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_MILLIMETER_WAVE_SETTING,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var setting = MillimeterWaveSetting.FromBytes(response.Data);
|
||
callback?.Invoke(setting);
|
||
OnMillimeterWaveSettingReceived?.Invoke(setting);
|
||
Log($"读取毫米波雷达设置: {setting}");
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入毫米波雷达设置 (命令 0x50)
|
||
/// </summary>
|
||
public void WriteMillimeterWaveSetting(MillimeterWaveSetting setting, Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
byte[] data = setting.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_MILLIMETER_WAVE_SETTING,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
Log($"毫米波雷达设置成功: {setting}");
|
||
else
|
||
LogError($"毫米波雷达设置失败, 状态码={response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取视觉检测设置 (命令 0x51)
|
||
/// </summary>
|
||
public void ReadVisualDetectionSetting(Action<VisualDetectionSetting> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_VISUAL_DETECTION_SETTING,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var setting = VisualDetectionSetting.FromBytes(response.Data);
|
||
callback?.Invoke(setting);
|
||
OnVisualDetectionSettingReceived?.Invoke(setting);
|
||
Log($"读取视觉检测设置: {setting}");
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入视觉检测设置 (命令 0x51)
|
||
/// </summary>
|
||
public void WriteVisualDetectionSetting(VisualDetectionSetting setting, Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
byte[] data = setting.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_VISUAL_DETECTION_SETTING,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
Log($"视觉检测设置成功: {setting}");
|
||
else
|
||
LogError($"视觉检测设置失败, 状态码={response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取加速度传感器设置 (命令 0x52)
|
||
/// </summary>
|
||
public void ReadAccelerometerSetting(Action<AccelerometerSetting> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_ACCELEROMETER_SETTING,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var setting = AccelerometerSetting.FromBytes(response.Data);
|
||
callback?.Invoke(setting);
|
||
OnAccelerometerSettingReceived?.Invoke(setting);
|
||
Log($"读取加速度传感器设置: {setting}");
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入加速度传感器设置 (命令 0x52)
|
||
/// </summary>
|
||
public void WriteAccelerometerSetting(AccelerometerSetting setting, Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
byte[] data = setting.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_ACCELEROMETER_SETTING,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
Log($"加速度传感器设置成功: {setting}");
|
||
else
|
||
LogError($"加速度传感器设置失败, 状态码={response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查询加速度传感器数据 (命令 0x53)
|
||
/// </summary>
|
||
public void ReadAccelerometerData(Action<AccelerometerData> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_ACCELEROMETER_DATA,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var data = AccelerometerData.FromBytes(response.Data);
|
||
callback?.Invoke(data);
|
||
OnAccelerometerDataReceived?.Invoke(data);
|
||
Log($"读取加速度传感器数据: {data}");
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取温度监控设置 (命令 0x55)
|
||
/// </summary>
|
||
public void ReadTemperatureMonitorSetting(Action<TemperatureMonitorSetting> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_TEMPERATURE_MONITOR_SETTING,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var setting = TemperatureMonitorSetting.FromBytes(response.Data);
|
||
callback?.Invoke(setting);
|
||
OnTemperatureMonitorSettingReceived?.Invoke(setting);
|
||
Log($"读取温度监控设置: {setting}");
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入温度监控设置 (命令 0x55)
|
||
/// </summary>
|
||
public void WriteTemperatureMonitorSetting(TemperatureMonitorSetting setting, Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
byte[] data = setting.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_TEMPERATURE_MONITOR_SETTING,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
Log($"温度监控设置成功: {setting}");
|
||
else
|
||
LogError($"温度监控设置失败, 状态码={response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 状态查询类接口 (0xA0-0xBF)
|
||
|
||
/// <summary>
|
||
/// 读取工作模式 (命令 0xA0)
|
||
/// </summary>
|
||
public void ReadWorkMode(Action<WorkModeSetting> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_WORK_MODE_SETTING,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var setting = WorkModeSetting.FromBytes(response.Data);
|
||
callback?.Invoke(setting);
|
||
OnWorkModeSettingReceived?.Invoke(setting);
|
||
Log($"读取工作模式: {setting}");
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入工作模式 (命令 0xA0)
|
||
/// </summary>
|
||
public void WriteWorkMode(WorkModeSetting setting, Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
byte[] data = setting.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_WORK_MODE_SETTING,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
Log($"工作模式设置成功: {setting}");
|
||
else
|
||
LogError($"工作模式设置失败, 状态码={response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查询硬件状态 (命令 0xA1)
|
||
/// </summary>
|
||
public void ReadHardwareStatus(Action<HardwareStatus> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_HARDWARE_STATUS,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var status = HardwareStatus.FromBytes(response.Data);
|
||
callback?.Invoke(status);
|
||
OnHardwareStatusReceived?.Invoke(status);
|
||
Log($"查询硬件状态: {status}");
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查询设备信息 (命令 0xA2)
|
||
/// </summary>
|
||
public void ReadDeviceInfo(Action<DeviceInfo> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_DEVICE_INFO,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var info = DeviceInfo.FromBytes(response.Data);
|
||
callback?.Invoke(info);
|
||
OnDeviceInfoReceived?.Invoke(info);
|
||
Log($"查询设备信息: {info}");
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入设备信息 (命令 0xA2 写操作)
|
||
/// 写操作:接收56字节设备信息
|
||
/// </summary>
|
||
public void WriteDeviceInfo(DeviceInfoWrite deviceInfo, Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
byte[] data = deviceInfo.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_DEVICE_INFO,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
Log($"设备信息写入成功: {deviceInfo}");
|
||
else
|
||
LogError($"设备信息写入失败, 状态码={response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查询统计数据 (命令 0xA3)
|
||
/// </summary>
|
||
public void ReadStatisticsData(Action<StatisticsData> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_STATISTICS_DATA,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var stats = StatisticsData.FromBytes(response.Data);
|
||
callback?.Invoke(stats);
|
||
OnStatisticsDataReceived?.Invoke(stats);
|
||
Log($"查询统计数据: {stats}");
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查询蚊虫数据 (命令 0xA4)
|
||
/// </summary>
|
||
public void QueryMosquitoData(MosquitoDataQuery query, Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
byte[] data = query.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_MOSQUITO_DATA_QUERY,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
Log($"蚊虫数据查询成功: {query}");
|
||
else
|
||
LogError($"蚊虫数据查询失败, 状态码={response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查询传感器数据 (命令 0xA5)
|
||
/// </summary>
|
||
public void ReadSensorData(Action<SensorData> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_SENSOR_DATA,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var data = SensorData.FromBytes(response.Data);
|
||
callback?.Invoke(data);
|
||
OnSensorDataReceived?.Invoke(data);
|
||
Log($"查询传感器数据: {data}");
|
||
});
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 蚊虫数据查询 (0xA4 + 0x0B通知)
|
||
|
||
/// <summary>
|
||
/// 查询蚊虫数据数量 (命令 0xA4 读操作)
|
||
/// </summary>
|
||
public void ReadMosquitoDataCount(Action<MosquitoDataCount> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_MOSQUITO_DATA_QUERY,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var count = MosquitoDataCount.FromBytes(response.Data);
|
||
callback?.Invoke(count);
|
||
Log($"查询蚊虫数据数量: {count}");
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 请求蚊虫数据 (命令 0xA4 写操作)
|
||
/// 写操作成功后,设备通过通知机制发送数据
|
||
/// </summary>
|
||
public void RequestMosquitoData(uint count, Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
// 构建4字节数据(读取数量,小端序)
|
||
byte[] data = new byte[]
|
||
{
|
||
(byte)(count & 0xFF),
|
||
(byte)((count >> 8) & 0xFF),
|
||
(byte)((count >> 16) & 0xFF),
|
||
(byte)((count >> 24) & 0xFF)
|
||
};
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_MOSQUITO_DATA_QUERY,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
Log($"蚊虫数据请求成功,期望接收 {count} 条数据");
|
||
else
|
||
LogError($"蚊虫数据请求失败, 状态码={response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理蚊虫数据通知 (通知类型 0x0B)
|
||
/// </summary>
|
||
public void HandleMosquitoDataNotification(byte[] notifyData)
|
||
{
|
||
if (notifyData == null || notifyData.Length < 22)
|
||
{
|
||
LogError("蚊虫数据通知格式错误,数据长度不足22字节");
|
||
return;
|
||
}
|
||
|
||
var mosquitoData = MosquitoData.FromBytes(notifyData);
|
||
Log($"收到蚊虫数据通知: {mosquitoData}");
|
||
OnMosquitoDataReceived?.Invoke(mosquitoData);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取环境变化状态 (命令 0x56 读操作)
|
||
/// </summary>
|
||
public void ReadEnvironmentChangeStatus(Action<EnvironmentChangeTest> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_ENVIRONMENT_CHANGE_TEST,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var status = EnvironmentChangeTest.FromBytes(response.Data);
|
||
callback?.Invoke(status);
|
||
OnEnvironmentChangeStatusReceived?.Invoke(status);
|
||
Log($"读取环境变化状态: {status}");
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发激光试射测试 (命令 0x56 写操作)
|
||
/// 触发激光进行3次试射测试,每次间隔1秒,每次持续10ms
|
||
/// </summary>
|
||
public void TriggerLaserTest(Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
var test = new EnvironmentChangeTest { TriggerTest = true };
|
||
byte[] data = test.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_ENVIRONMENT_CHANGE_TEST,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)data.Length,
|
||
Data = data
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
Log("激光试射测试已触发:将进行3次试射,每次间隔1秒,每次持续10ms");
|
||
else
|
||
LogError($"激光试射测试触发失败, 状态码={response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 恢复出厂设置 (命令 0x60)
|
||
/// 需要管理员权限
|
||
/// 写操作:发送1字节确认码 0x01
|
||
/// </summary>
|
||
public void FactoryReset(Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
// 构建恢复出厂设置帧,发送确认码 0x01
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_FACTORY_RESET,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = 1,
|
||
Data = new byte[] { 0x01 }
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
bool success = response.IsSuccess;
|
||
if (success)
|
||
Log("恢复出厂设置命令发送成功,设备将恢复出厂设置");
|
||
else if (response.Status == BLEConstants.STATUS_PERMISSION_ERROR)
|
||
LogError("恢复出厂设置失败:需要管理员权限");
|
||
else
|
||
LogError($"恢复出厂设置失败, 状态码=0x{response.Status:X2}");
|
||
callback?.Invoke(success);
|
||
});
|
||
}
|
||
|
||
#endregion
|
||
|
||
/// <summary>
|
||
/// 查询用户列表 (命令 0x07)
|
||
/// </summary>
|
||
public void QueryUserList(Action<UserListResponse> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
// 构建查询帧
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_QUERY_USER_LIST,
|
||
ReadWrite = BLEConstants.RW_READ,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
if (response.IsSuccess && response.Data != null)
|
||
{
|
||
var userList = UserListResponse.FromBytes(response.Status, response.Data);
|
||
callback?.Invoke(userList);
|
||
OnUserListReceived?.Invoke(userList);
|
||
}
|
||
else
|
||
{
|
||
LogError($"查询用户列表失败: 状态码={response.Status:X2}");
|
||
callback?.Invoke(new UserListResponse() { Status = response.Status });
|
||
}
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 注销用户 (命令 0x08)
|
||
/// </summary>
|
||
/// <param name="username">要注销的用户名</param>
|
||
/// <param name="callback">回调 (响应结果)</param>
|
||
public void UnregisterUser(string username, Action<UnregisterUserResponse> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
// 验证输入
|
||
if (string.IsNullOrEmpty(username) || username.Length > BLEConstants.MAX_USERNAME_LENGTH)
|
||
{
|
||
LogError($"用户名长度必须在1-{BLEConstants.MAX_USERNAME_LENGTH}之间");
|
||
callback?.Invoke(new UnregisterUserResponse { Status = BLEConstants.STATUS_PARAM_ERROR });
|
||
return;
|
||
}
|
||
|
||
// 构建注销请求
|
||
var request = new UnregisterUserRequest
|
||
{
|
||
Username = username
|
||
};
|
||
|
||
byte[] requestData = request.ToBytes();
|
||
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_UNREGISTER_USER,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = (byte)requestData.Length,
|
||
Data = requestData
|
||
};
|
||
|
||
SendFrame(frame, (response) =>
|
||
{
|
||
var unregisterResponse = UnregisterUserResponse.FromBytes(response.Status);
|
||
|
||
if (unregisterResponse.IsSuccess)
|
||
{
|
||
Log($"用户注销成功: {username}");
|
||
}
|
||
else
|
||
{
|
||
LogError($"用户注销失败: {username}, 状态码={response.Status:X2}");
|
||
}
|
||
|
||
callback?.Invoke(unregisterResponse);
|
||
OnUnregisterUserResult?.Invoke(unregisterResponse);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 主动断开连接 (命令 0x70)
|
||
/// 注意:设备收到0x70后会立即断开BLE,所以不会收到响应,需要特殊处理
|
||
/// </summary>
|
||
public void Disconnect(Action<bool> callback = null)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
// 构建断开连接帧(无数据)
|
||
var frame = new BLEFrame
|
||
{
|
||
Header1 = BLEConstants.FRAME_HEADER_1,
|
||
Header2 = BLEConstants.FRAME_HEADER_2,
|
||
Command = BLEConstants.CMD_DISCONNECT,
|
||
ReadWrite = BLEConstants.RW_WRITE,
|
||
Length = 0,
|
||
Data = null
|
||
};
|
||
|
||
Log($"[BLE-DEBUG] Disconnect: 发送0x70命令: {System.BitConverter.ToString(frame.ToBytes())}");
|
||
SendFrameWithoutResponse(frame);
|
||
|
||
callback?.Invoke(true);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 底层通信方法
|
||
|
||
/// <summary>
|
||
/// 发送协议帧(不等待响应)
|
||
/// 用于0x70断开命令等特殊场景
|
||
/// </summary>
|
||
private void SendFrameWithoutResponse(BLEFrame frame)
|
||
{
|
||
if (!CheckConnection()) return;
|
||
|
||
byte[] frameBytes = frame.ToBytes();
|
||
string deviceAddress = BluetoothManager.Instance.ConnectedDeviceAddress;
|
||
|
||
Log($"[BLE-DEBUG] SendFrame: 地址={deviceAddress}, 数据={System.BitConverter.ToString(frameBytes)}, withResponse=false");
|
||
|
||
try
|
||
{
|
||
BluetoothLEHardwareInterface.WriteCharacteristic(
|
||
deviceAddress,
|
||
ServiceUUID.ToLower(),
|
||
WriteCharacteristicUUID.ToLower(),
|
||
frameBytes,
|
||
frameBytes.Length,
|
||
false,
|
||
(characteristicUUID) =>
|
||
{
|
||
Log($"[BLE-DEBUG] SendFrame完成");
|
||
}
|
||
);
|
||
}
|
||
catch (System.Exception ex)
|
||
{
|
||
LogError($"[BLE-DEBUG] SendFrame异常: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 发送协议帧(内部方法,供OTAManager使用)
|
||
/// </summary>
|
||
public void SendFrameInternal(BLEFrame frame, Action<BLEResponse> callback)
|
||
{
|
||
SendFrame(frame, callback);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 发送协议帧
|
||
/// </summary>
|
||
private void SendFrame(BLEFrame frame, Action<BLEResponse> callback)
|
||
{
|
||
if (!CheckConnection())
|
||
{
|
||
LogError("[BLE-DEBUG] CheckConnection failed, invoking callback with error");
|
||
callback?.Invoke(new BLEResponse { Status = BLEConstants.STATUS_DEVICE_ERROR });
|
||
return;
|
||
}
|
||
|
||
byte[] frameBytes = frame.ToBytes();
|
||
|
||
IsWaitingResponse = true;
|
||
_responseTimer = ResponseTimeout;
|
||
LastCommand = frame.Command;
|
||
_pendingCallback = callback;
|
||
|
||
// 清空接收缓冲区
|
||
_receiveBuffer.Clear();
|
||
|
||
// 通过BLE发送数据
|
||
string deviceAddress = BluetoothManager.Instance.ConnectedDeviceAddress;
|
||
|
||
// 确保UUID是小写
|
||
ServiceUUID = ServiceUUID.ToLower();
|
||
WriteCharacteristicUUID = WriteCharacteristicUUID.ToLower();
|
||
|
||
string hexData = System.BitConverter.ToString(frameBytes);
|
||
|
||
// 触发发送数据事件(用于UI显示)
|
||
OnRawDataSent?.Invoke(hexData);
|
||
|
||
try
|
||
{
|
||
BluetoothLEHardwareInterface.WriteCharacteristic(
|
||
deviceAddress,
|
||
ServiceUUID,
|
||
WriteCharacteristicUUID,
|
||
frameBytes,
|
||
frameBytes.Length,
|
||
true,
|
||
(characteristicUUID) => { }
|
||
);
|
||
}
|
||
catch (System.Exception ex)
|
||
{
|
||
LogError($"发送帧异常: {ex.Message}");
|
||
IsWaitingResponse = false;
|
||
callback?.Invoke(new BLEResponse { Status = BLEConstants.STATUS_DEVICE_ERROR });
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理收到的通知数据
|
||
/// </summary>
|
||
private void OnNotificationReceived(byte[] data)
|
||
{
|
||
if (data == null || data.Length == 0) return;
|
||
|
||
string hexString = System.BitConverter.ToString(data);
|
||
|
||
// 触发原始数据事件(用于UI显示)
|
||
OnRawDataReceived?.Invoke(hexString);
|
||
|
||
// 添加到接收缓冲区
|
||
_receiveBuffer.AddRange(data);
|
||
|
||
// 尝试解析帧
|
||
TryParseFrame();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 尝试从缓冲区解析帧
|
||
/// </summary>
|
||
private void TryParseFrame()
|
||
{
|
||
byte[] buffer = _receiveBuffer.ToArray();
|
||
|
||
// 查找帧头
|
||
for (int i = 0; i < buffer.Length - 1; i++)
|
||
{
|
||
if (buffer[i] == BLEConstants.FRAME_HEADER_1 &&
|
||
buffer[i + 1] == BLEConstants.FRAME_HEADER_2)
|
||
{
|
||
// 检查是否有足够的数据长度字段
|
||
if (i + 4 >= buffer.Length)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
byte dataLength = buffer[i + 4];
|
||
int totalFrameLength = 7 + dataLength; // 帧头(2) + 命令(1) + 读写(1) + 长度(1) + 数据(dataLength) + CRC(2)
|
||
|
||
// 检查是否有完整的帧
|
||
if (i + totalFrameLength > buffer.Length)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// 提取帧数据
|
||
byte[] frameBytes = new byte[totalFrameLength];
|
||
Buffer.BlockCopy(buffer, i, frameBytes, 0, totalFrameLength);
|
||
|
||
// 解析帧
|
||
if (BLEFrame.TryParse(frameBytes, out BLEFrame frame))
|
||
{
|
||
// 处理解析到的帧
|
||
HandleReceivedFrame(frame);
|
||
|
||
// 从缓冲区移除已解析的数据
|
||
_receiveBuffer.RemoveRange(0, i + totalFrameLength);
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
LogWarning("帧解析失败 (CRC校验可能失败)");
|
||
}
|
||
}
|
||
}
|
||
|
||
// 清理过期的缓冲区数据 (保留最后100字节)
|
||
if (_receiveBuffer.Count > 200)
|
||
{
|
||
_receiveBuffer.RemoveRange(0, _receiveBuffer.Count - 100);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理收到的帧
|
||
/// </summary>
|
||
private void HandleReceivedFrame(BLEFrame frame)
|
||
{
|
||
// 检查是否是对等待命令的响应
|
||
if (IsWaitingResponse && frame.Command == LastCommand)
|
||
{
|
||
IsWaitingResponse = false;
|
||
_responseTimer = 0;
|
||
|
||
var response = BLEResponse.FromFrame(frame);
|
||
_pendingCallback?.Invoke(response);
|
||
_pendingCallback = null;
|
||
}
|
||
else if (frame.ReadWrite == BLEConstants.RW_NOTIFY)
|
||
{
|
||
// 处理设备主动通知
|
||
OnDataReceived?.Invoke(frame.Data);
|
||
}
|
||
else if (IsWaitingResponse)
|
||
{
|
||
// 尝试处理非匹配的响应,可能是硬件响应延迟
|
||
IsWaitingResponse = false;
|
||
_responseTimer = 0;
|
||
|
||
var response = BLEResponse.FromFrame(frame);
|
||
_pendingCallback?.Invoke(response);
|
||
_pendingCallback = null;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 响应超时处理
|
||
/// </summary>
|
||
private void OnResponseTimeout()
|
||
{
|
||
IsWaitingResponse = false;
|
||
_responseTimer = 0;
|
||
|
||
LogError($"命令超时: 命令={LastCommand:X2}");
|
||
|
||
var timeoutResponse = new BLEResponse
|
||
{
|
||
Status = BLEConstants.STATUS_TIMEOUT
|
||
};
|
||
|
||
_pendingCallback?.Invoke(timeoutResponse);
|
||
_pendingCallback = null;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 辅助方法
|
||
|
||
/// <summary>
|
||
/// 检查蓝牙连接状态
|
||
/// </summary>
|
||
private bool CheckConnection()
|
||
{
|
||
if (BluetoothManager.Instance == null) return false;
|
||
if (!BluetoothManager.Instance.IsConnected) return false;
|
||
if (IsWaitingResponse) return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取状态码描述
|
||
/// </summary>
|
||
private string GetStatusMessage(byte status)
|
||
{
|
||
switch (status)
|
||
{
|
||
case BLEConstants.STATUS_SUCCESS: return "成功";
|
||
case BLEConstants.STATUS_PARAM_ERROR: return "参数错误";
|
||
case BLEConstants.STATUS_PERMISSION_ERROR: return "权限错误";
|
||
case BLEConstants.STATUS_DEVICE_BUSY: return "设备忙";
|
||
case BLEConstants.STATUS_CMD_NOT_SUPPORT: return "命令不支持";
|
||
case BLEConstants.STATUS_DATA_CHECK_FAIL: return "数据校验失败";
|
||
case BLEConstants.STATUS_TIMEOUT: return "超时";
|
||
case BLEConstants.STATUS_DEVICE_ERROR: return "设备错误";
|
||
default: return $"未知错误 (0x{status:X2})";
|
||
}
|
||
}
|
||
|
||
private void Log(string message)
|
||
{
|
||
Debug.Log($"[BLECommunication] {message}");
|
||
}
|
||
|
||
private void LogError(string message)
|
||
{
|
||
Debug.LogError($"[BLECommunication] {message}");
|
||
OnCommunicationError?.Invoke(message);
|
||
}
|
||
|
||
private void LogWarning(string message)
|
||
{
|
||
Debug.LogWarning($"[BLECommunication] {message}");
|
||
}
|
||
|
||
#endregion
|
||
}
|