// using System; // using System.Collections.Generic; // using UnityEngine; // using System.Threading; // using GeneralTools; // namespace DCX.Communication // { // /// // /// DCS项目串口通信管理器 // /// 基于DCS项目串口通信协议说明书实现 // /// 支持安卓平台的串口通信 // /// // public class DCSSerialManager : MonoBehaviour // { // #region 协议常量 // // 帧结构常量 // private const byte FRAME_HEADER_1 = 0xAA; // private const byte FRAME_HEADER_2 = 0x55; // private const byte FRAME_TAIL_1 = 0x0D; // private const byte FRAME_TAIL_2 = 0x0A; // // 命令字定义(基于协议文档) // public enum CommandType : byte // { // HandshakeResponse = 0x01, // 握手应答 + 时间同步(下→上) // HandshakeRequest = 0x02, // 握手请求(上→下) // HeartbeatReport = 0x03, // 心跳上报(上→下) // HeartbeatAck = 0x04, // 心跳应答(下→上) // AlarmControl = 0x05, // 报警控制命令(下→上) // DataReport = 0x06, // 数据上报(上→下) // ParameterQuery = 0x07, // 参数查询或设置(下→上) // AlarmFeedback = 0x08, // 告警状态反馈(上→下) // TimeSync = 0x09 // 时间同步命令(下→上) // } // // 报警代码定义 // public enum AlarmCode : byte // { // BatteryLow40 = 0x11, // 电池电量低(<40%) // LaserTempAbnormal = 0x22, // 激光器温度异常 // BatteryLow20 = 0x21, // 电池电量低(<20%) // BatteryEmpty5 = 0x31, // 电池电量空(<5%) // BFIAbnormal = 0x32, // BFI数值异常 // LaserWorkAbnormal = 0x33, // 激光器工作异常 // CommAbnormal = 0x34, // 通信异常 // BatteryFault = 0x35, // 电池故障 // ACNotConnected = 0x12 // 交流电未连接 // } // #endregion // #region 数据结构 // [Serializable] // public struct HeartbeatData // { // public float bfiValue; // BFI血流值 // public byte batteryLevel; // 电池电量 0-100% // public ushort batteryVoltage; // 电池电压 mV // public ushort temperature; // 内部温度 0.1°C // public byte laserStatus; // 激光器状态 0=异常,1=工作,2=停止 // public byte powerType; // 电源类型 0=AC,1=BAT // public uint reserved; // 保留字段 // } // [Serializable] // public struct AlarmCommand // { // public AlarmCode alarmCode; // 报警代码 // public byte priority; // 报警级别 0=低,1=中,2=高 // public byte status; // 报警状态 0=清除,1=触发 // } // #endregion // #region 事件定义 // public event Action OnConnected; // public event Action OnDisconnected; // public event Action OnHeartbeatReceived; // public event Action OnAlarmReceived; // public event Action OnError; // public event Action OnRawDataReceived; // #endregion // #region 私有字段 // private ISerialPortAdapter serialPort; // private Thread readThread; // private bool isRunning = false; // private Queue sendQueue = new Queue(); // private object lockObject = new object(); // private float lastHeartbeatTime = 0f; // private float lastDataReportTime = 0f; // private bool isHandshakeCompleted = false; // // 配置参数(从AndroidConfigHelper加载) // private string portName; // private int baudRate; // private int heartbeatInterval; // private int communicationTimeout; // private bool autoReconnect; // private int maxReconnectAttempts; // #endregion // #region Unity生命周期 // void Start() // { // LoadConfiguration(); // InitializeSerialPort(); // } // void Update() // { // ProcessSendQueue(); // CheckHeartbeat(); // // CheckDataReport(); // } // void OnDestroy() // { // Disconnect(); // } // #endregion // #region 配置加载 // private void LoadConfiguration() // { // // 根据平台设置默认串口名称 // string defaultPortName; // #if UNITY_ANDROID && !UNITY_EDITOR // defaultPortName = "/dev/ttyS4"; // #elif UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN // defaultPortName = "COM1"; // #elif UNITY_STANDALONE_LINUX || UNITY_EDITOR_LINUX // defaultPortName = "/dev/ttyS4"; // #elif UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX // defaultPortName = "/dev/cu.usbserial-1410"; // #else // defaultPortName = "COM1"; // #endif // portName = AndroidConfigHelper.GetConfig("serialPortName", "SerialPort", defaultPortName); // baudRate = AndroidConfigHelper.GetConfig("serialBaudRate", "SerialPort", 115200); // heartbeatInterval = AndroidConfigHelper.GetConfig("heartbeatInterval", "SerialPort", 1000); // communicationTimeout = AndroidConfigHelper.GetConfig("communicationTimeout", "SerialPort", 5000); // autoReconnect = AndroidConfigHelper.GetConfig("autoReconnect", "SerialPort", true); // maxReconnectAttempts = AndroidConfigHelper.GetConfig("maxReconnectAttempts", "SerialPort", 5); // Debug.Log($"DCS串口配置加载完成: {portName}, {baudRate}bps (平台: {Application.platform})"); // } // #endregion // #region 串口初始化和连接 // private void InitializeSerialPort() // { // try // { // #if UNITY_ANDROID && !UNITY_EDITOR // // 安卓平台使用JNI调用原生串口 // serialPort = new AndroidSerialPortAdapter(); // #elif UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN // // Windows平台使用真实串口 // serialPort = new WindowsSerialPortAdapter(); // Debug.Log("DCS使用Windows真实串口"); // #elif UNITY_STANDALONE_LINUX || UNITY_EDITOR_LINUX // // Linux平台使用真实串口 // serialPort = new WindowsSerialPortAdapter(); // 复用Windows适配器 // Debug.Log("DCS使用Linux真实串口"); // #else // // 其他平台使用模拟器 // serialPort = new SimulatedSerialPortAdapter(); // Debug.LogWarning("DCS使用串口模拟器(未支持平台)"); // #endif // Connect(); // } // catch (Exception e) // { // Debug.LogError($"DCS串口初始化失败: {e.Message}"); // OnError?.Invoke($"串口初始化失败: {e.Message}"); // } // } // public void Connect() // { // try // { // if (serialPort != null && serialPort.Open(portName, baudRate)) // { // isRunning = true; // StartReadThread(); // SendHandshakeRequest(); // OnConnected?.Invoke(); // Debug.Log("串口连接成功"); // } // else // { // OnError?.Invoke("串口连接失败"); // } // } // catch (Exception e) // { // OnError?.Invoke($"连接异常: {e.Message}"); // } // } // public void Disconnect() // { // isRunning = false; // if (readThread != null && readThread.IsAlive) // { // readThread.Join(1000); // 等待读取线程结束 // } // serialPort?.Close(); // OnDisconnected?.Invoke(); // Debug.Log("串口已断开"); // } // #endregion // #region 数据发送和接收 // private void StartReadThread() // { // readThread = new Thread(ReadDataThread) // { // IsBackground = true // }; // readThread.Start(); // } // private void ReadDataThread() // { // byte[] buffer = new byte[1024]; // while (isRunning) // { // try // { // if (serialPort != null && serialPort.IsOpen) // { // int bytesRead = serialPort.Read(buffer, 0, buffer.Length); // if (bytesRead > 0) // { // byte[] data = new byte[bytesRead]; // Array.Copy(buffer, 0, data, 0, bytesRead); // // 在主线程处理数据 // MainThreadDispatcher.Enqueue(() => ProcessReceivedData(data)); // } // } // } // catch (Exception e) // { // MainThreadDispatcher.Enqueue(() => OnError?.Invoke($"读取数据异常: {e.Message}")); // } // Thread.Sleep(10); // 避免过度占用CPU // } // } // private void ProcessReceivedData(byte[] data) // { // OnRawDataReceived?.Invoke(data); // // 解析协议帧 // for (int i = 0; i < data.Length - 6; i++) // 最小帧长度检查 // { // if (data[i] == FRAME_HEADER_1 && data[i + 1] == FRAME_HEADER_2) // { // if (TryParseFrame(data, i, out var frame)) // { // ProcessFrame(frame); // } // } // } // } // private bool TryParseFrame(byte[] data, int startIndex, out ProtocolFrame frame) // { // frame = new ProtocolFrame(); // try // { // if (startIndex + 6 >= data.Length) return false; // frame.Command = (CommandType)data[startIndex + 2]; // frame.DataLength = data[startIndex + 3]; // int totalFrameLength = 4 + frame.DataLength + 3; // 帧头+命令+长度+数据+校验+帧尾 // if (startIndex + totalFrameLength > data.Length) return false; // frame.Data = new byte[frame.DataLength]; // Array.Copy(data, startIndex + 4, frame.Data, 0, frame.DataLength); // frame.Checksum = data[startIndex + 4 + frame.DataLength]; // // 验证校验和 // byte calculatedChecksum = CalculateChecksum(data, startIndex + 2, 2 + frame.DataLength); // if (calculatedChecksum != frame.Checksum) // { // Debug.LogWarning("校验和不匹配"); // return false; // } // // 验证帧尾 // if (data[startIndex + 5 + frame.DataLength] != FRAME_TAIL_1 || // data[startIndex + 6 + frame.DataLength] != FRAME_TAIL_2) // { // Debug.LogWarning("帧尾不匹配"); // return false; // } // return true; // } // catch (Exception e) // { // Debug.LogError($"解析帧失败: {e.Message}"); // return false; // } // } // private void ProcessFrame(ProtocolFrame frame) // { // switch (frame.Command) // { // case CommandType.HeartbeatReport: // ProcessHeartbeatReport(frame.Data); // SendHeartbeatAck(); // break; // case CommandType.DataReport: // ProcessDataReport(frame.Data); // break; // case CommandType.AlarmFeedback: // ProcessAlarmFeedback(frame.Data); // break; // case CommandType.HandshakeRequest: // ProcessHandshakeRequest(frame.Data); // break; // default: // Debug.Log($"收到未处理的命令: {frame.Command}"); // break; // } // } // private void ProcessHeartbeatReport(byte[] data) // { // if (data.Length >= 15) // HeartbeatData结构体大小 // { // HeartbeatData heartbeat = new HeartbeatData // { // bfiValue = BitConverter.ToSingle(data, 0), // batteryLevel = data[4], // batteryVoltage = BitConverter.ToUInt16(data, 5), // temperature = BitConverter.ToUInt16(data, 7), // laserStatus = data[9], // powerType = data[10], // reserved = BitConverter.ToUInt32(data, 11) // }; // OnHeartbeatReceived?.Invoke(heartbeat); // lastHeartbeatTime = Time.time; // } // } // private void ProcessDataReport(byte[] data) // { // // 处理数据上报,格式与心跳报告相同 // ProcessHeartbeatReport(data); // lastDataReportTime = Time.time; // } // private void ProcessAlarmFeedback(byte[] data) // { // if (data.Length >= 3) // { // AlarmCommand alarm = new AlarmCommand // { // alarmCode = (AlarmCode)data[0], // priority = data[1], // status = data[2] // }; // OnAlarmReceived?.Invoke(alarm); // } // } // private void ProcessHandshakeRequest(byte[] data) // { // Debug.Log("收到握手请求,发送时间同步应答"); // SendHandshakeResponse(); // isHandshakeCompleted = true; // } // #endregion // #region 协议命令发送 // public void SendHandshakeRequest() // { // byte[] data = { 0x01 }; // 固件版本 // SendFrame(CommandType.HandshakeRequest, data); // } // public void SendHandshakeResponse() // { // DateTime now = DateTime.Now; // byte[] data = { // (byte)(now.Year % 100), // (byte)now.Month, // (byte)now.Day, // (byte)now.Hour, // (byte)now.Minute, // (byte)now.Second // }; // SendFrame(CommandType.HandshakeResponse, data); // } // public void SendHeartbeatAck() // { // byte[] data = { 0x00 }; // 简单应答 // SendFrame(CommandType.HeartbeatAck, data); // } // public void SendAlarmControl(AlarmCode alarmCode, byte priority, byte status) // { // byte[] data = { (byte)alarmCode, priority, status }; // SendFrame(CommandType.AlarmControl, data); // } // private void SendFrame(CommandType command, byte[] data) // { // try // { // List frame = new List(); // // 帧头 // frame.Add(FRAME_HEADER_1); // frame.Add(FRAME_HEADER_2); // // 命令字 // frame.Add((byte)command); // // 数据长度 // frame.Add((byte)data.Length); // // 数据 // frame.AddRange(data); // // 校验和 // byte checksum = CalculateChecksum(frame.ToArray(), 2, 2 + data.Length); // frame.Add(checksum); // // 帧尾 // frame.Add(FRAME_TAIL_1); // frame.Add(FRAME_TAIL_2); // var frameArray = frame.ToArray(); // var hexString = BitConverter.ToString(frameArray).Replace("-", " "); // Debug.Log($"[DCS发送队列] {GetCommandName(command)}: {hexString}"); // lock (lockObject) // { // sendQueue.Enqueue(frameArray); // } // } // catch (Exception e) // { // Debug.LogError($"DCS发送帧失败: {e.Message}"); // OnError?.Invoke($"发送帧失败: {e.Message}"); // } // } // private string GetCommandName(CommandType command) // { // return command switch // { // CommandType.HandshakeResponse => "握手应答", // CommandType.HandshakeRequest => "握手请求", // CommandType.HeartbeatReport => "心跳上报", // CommandType.HeartbeatAck => "心跳应答", // CommandType.AlarmControl => "报警控制", // CommandType.DataReport => "数据上报", // CommandType.ParameterQuery => "参数查询", // CommandType.AlarmFeedback => "报警反馈", // CommandType.TimeSync => "时间同步", // _ => $"未知命令({(byte)command:X2})" // }; // } // private void ProcessSendQueue() // { // lock (lockObject) // { // while (sendQueue.Count > 0) // { // byte[] frame = sendQueue.Dequeue(); // try // { // if (serialPort != null && serialPort.IsOpen) // { // serialPort.Write(frame, 0, frame.Length); // var hexString = BitConverter.ToString(frame).Replace("-", " "); // Debug.Log($"[DCS串口发送] {hexString}"); // } // else // { // Debug.LogError("DCS串口未打开,无法发送数据"); // } // } // catch (Exception e) // { // Debug.LogError($"DCS串口写入失败: {e.Message}"); // OnError?.Invoke($"串口写入失败: {e.Message}"); // } // } // } // } // #endregion // #region 辅助方法 // private byte CalculateChecksum(byte[] data, int offset, int length) // { // byte checksum = 0; // for (int i = offset; i < offset + length; i++) // { // checksum ^= data[i]; // } // return checksum; // } // private void CheckHeartbeat() // { // if (isHandshakeCompleted && Time.time - lastHeartbeatTime > communicationTimeout / 1000f) // { // Debug.LogWarning("心跳超时"); // if (autoReconnect) // { // Reconnect(); // } // } // } // private void CheckDataReport() // { // // 检查数据上报间隔 // float dataReportInterval = AndroidConfigHelper.GetConfig("dataReportInterval", "SerialPort", 1000) / 1000f; // if (Time.time - lastDataReportTime > dataReportInterval * 2) // { // Debug.LogWarning("数据上报超时"); // } // } // private void Reconnect() // { // Debug.Log("尝试重连..."); // Disconnect(); // Invoke(nameof(Connect), 2f); // 2秒后重连 // } // #endregion // #region 内部数据结构 // private struct ProtocolFrame // { // public CommandType Command; // public byte DataLength; // public byte[] Data; // public byte Checksum; // } // #endregion // } // #region 串口适配器接口 // public interface ISerialPortAdapter // { // bool Open(string portName, int baudRate); // void Close(); // bool IsOpen { get; } // int Read(byte[] buffer, int offset, int count); // void Write(byte[] buffer, int offset, int count); // } // // Windows平台串口适配器(使用System.IO.Ports) // public class WindowsSerialPortAdapter : ISerialPortAdapter // { // #if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN || UNITY_STANDALONE_LINUX || UNITY_EDITOR_LINUX // private System.IO.Ports.SerialPort serialPort; // public bool IsOpen => serialPort?.IsOpen ?? false; // public bool Open(string portName, int baudRate) // { // try // { // serialPort = new System.IO.Ports.SerialPort(portName, baudRate, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One) // { // ReadTimeout = 1000, // WriteTimeout = 1000 // }; // serialPort.Open(); // Debug.Log($"Windows串口打开成功: {portName} @ {baudRate}"); // return true; // } // catch (Exception e) // { // Debug.LogError($"Windows串口打开失败: {e.Message}"); // return false; // } // } // public void Close() // { // try // { // if (serialPort?.IsOpen == true) // { // serialPort.Close(); // serialPort.Dispose(); // serialPort = null; // Debug.Log("Windows串口已关闭"); // } // } // catch (Exception e) // { // Debug.LogError($"Windows串口关闭失败: {e.Message}"); // } // } // public int Read(byte[] buffer, int offset, int count) // { // try // { // if (serialPort != null && serialPort.IsOpen && serialPort.BytesToRead > 0) // { // return serialPort.Read(buffer, offset, count); // } // return 0; // } // catch (Exception e) // { // Debug.LogError($"Windows串口读取失败: {e.Message}"); // return 0; // } // } // public void Write(byte[] buffer, int offset, int count) // { // try // { // if (serialPort != null && serialPort.IsOpen) // { // serialPort.Write(buffer, offset, count); // } // } // catch (Exception e) // { // Debug.LogError($"Windows串口写入失败: {e.Message}"); // } // } // #else // public bool IsOpen => false; // public bool Open(string portName, int baudRate) { Debug.LogWarning("WindowsSerialPortAdapter不支持此平台"); return false; } // public void Close() { } // public int Read(byte[] buffer, int offset, int count) { return 0; } // public void Write(byte[] buffer, int offset, int count) { } // #endif // } // // 安卓平台串口适配器(需要JNI实现) // public class AndroidSerialPortAdapter : ISerialPortAdapter // { // private AndroidJavaObject serialPortJNI; // public bool IsOpen { get; private set; } // public bool Open(string portName, int baudRate) // { // try // { // #if UNITY_ANDROID && !UNITY_EDITOR // serialPortJNI = new AndroidJavaObject("com.dcx.serialport.SerialPortHelper"); // bool result = serialPortJNI.Call("openSerialPort", portName, baudRate); // IsOpen = result; // return result; // #else // return false; // #endif // } // catch (Exception e) // { // Debug.LogError($"Android串口打开失败: {e.Message}"); // return false; // } // } // public void Close() // { // try // { // #if UNITY_ANDROID && !UNITY_EDITOR // serialPortJNI?.Call("closeSerialPort"); // #endif // IsOpen = false; // } // catch (Exception e) // { // Debug.LogError($"Android串口关闭失败: {e.Message}"); // } // } // public int Read(byte[] buffer, int offset, int count) // { // try // { // #if UNITY_ANDROID && !UNITY_EDITOR // byte[] data = serialPortJNI.Call("readData", count); // if (data != null && data.Length > 0) // { // Array.Copy(data, 0, buffer, offset, Math.Min(data.Length, count)); // return data.Length; // } // #endif // return 0; // } // catch (Exception e) // { // Debug.LogError($"Android串口读取失败: {e.Message}"); // return 0; // } // } // public void Write(byte[] buffer, int offset, int count) // { // try // { // #if UNITY_ANDROID && !UNITY_EDITOR // byte[] data = new byte[count]; // Array.Copy(buffer, offset, data, 0, count); // serialPortJNI.Call("writeData", data); // #endif // } // catch (Exception e) // { // Debug.LogError($"Android串口写入失败: {e.Message}"); // } // } // } // // 模拟串口适配器(用于测试) // public class SimulatedSerialPortAdapter : ISerialPortAdapter // { // public bool IsOpen { get; private set; } // private Queue simulatedData = new Queue(); // private System.Random random = new System.Random(); // public bool Open(string portName, int baudRate) // { // IsOpen = true; // Debug.Log($"模拟串口已打开: {portName}@{baudRate}"); // return true; // } // public void Close() // { // IsOpen = false; // Debug.Log("模拟串口已关闭"); // } // public int Read(byte[] buffer, int offset, int count) // { // // 模拟接收心跳数据 // if (simulatedData.Count == 0 && random.NextDouble() < 0.1) // 10%概率生成数据 // { // GenerateSimulatedHeartbeat(); // } // int bytesRead = 0; // while (simulatedData.Count > 0 && bytesRead < count) // { // buffer[offset + bytesRead] = simulatedData.Dequeue(); // bytesRead++; // } // return bytesRead; // } // public void Write(byte[] buffer, int offset, int count) // { // string hex = BitConverter.ToString(buffer, offset, count); // Debug.Log($"模拟串口发送: {hex}"); // } // private void GenerateSimulatedHeartbeat() // { // // 生成模拟心跳帧 // List frame = new List // { // 0xAA, 0x55, // 帧头 // 0x03, // 心跳报告命令 // 0x0F, // 数据长度15字节 // }; // // BFI值 (float) // byte[] bfiBytes = BitConverter.GetBytes(50.0f + (float)(random.NextDouble() - 0.5) * 20); // frame.AddRange(bfiBytes); // // 电池电量 // frame.Add((byte)(80 + random.Next(0, 20))); // // 电池电压 (mV) // byte[] voltageBytes = BitConverter.GetBytes((ushort)(3700 + random.Next(0, 500))); // frame.AddRange(voltageBytes); // // 温度 // byte[] tempBytes = BitConverter.GetBytes((ushort)(250 + random.Next(0, 100))); // 25.0-35.0°C // frame.AddRange(tempBytes); // // 激光器状态 // frame.Add(0x01); // 工作中 // // 电源类型 // frame.Add(0x01); // 电池供电 // // 保留字段 // frame.AddRange(new byte[4]); // // 校验和 // byte checksum = 0; // for (int i = 2; i < frame.Count; i++) // { // checksum ^= frame[i]; // } // frame.Add(checksum); // // 帧尾 // frame.Add(0x0D); // frame.Add(0x0A); // foreach (byte b in frame) // { // simulatedData.Enqueue(b); // } // } // } // // 主线程调度器(用于在主线程处理串口数据) // public class MainThreadDispatcher : MonoBehaviour // { // private static MainThreadDispatcher instance; // private static Queue executionQueue = new Queue(); // public static void Enqueue(Action action) // { // lock (executionQueue) // { // executionQueue.Enqueue(action); // } // } // void Awake() // { // if (instance == null) // { // instance = this; // DontDestroyOnLoad(gameObject); // } // else // { // Destroy(gameObject); // } // } // void Update() // { // lock (executionQueue) // { // while (executionQueue.Count > 0) // { // executionQueue.Dequeue().Invoke(); // } // } // } // } // #endregion // }