886 lines
31 KiB
C#
886 lines
31 KiB
C#
// using System;
|
||
// using System.Collections.Generic;
|
||
// using UnityEngine;
|
||
// using System.Threading;
|
||
// using GeneralTools;
|
||
|
||
// namespace DCX.Communication
|
||
// {
|
||
// /// <summary>
|
||
// /// DCS项目串口通信管理器
|
||
// /// 基于DCS项目串口通信协议说明书实现
|
||
// /// 支持安卓平台的串口通信
|
||
// /// </summary>
|
||
// 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<HeartbeatData> OnHeartbeatReceived;
|
||
// public event Action<AlarmCommand> OnAlarmReceived;
|
||
// public event Action<string> OnError;
|
||
// public event Action<byte[]> OnRawDataReceived;
|
||
// #endregion
|
||
|
||
// #region 私有字段
|
||
// private ISerialPortAdapter serialPort;
|
||
// private Thread readThread;
|
||
// private bool isRunning = false;
|
||
// private Queue<byte[]> sendQueue = new Queue<byte[]>();
|
||
// 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<byte> frame = new List<byte>();
|
||
|
||
// // 帧头
|
||
// 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<bool>("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<byte[]>("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<byte> simulatedData = new Queue<byte>();
|
||
// 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<byte> frame = new List<byte>
|
||
// {
|
||
// 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<Action> executionQueue = new Queue<Action>();
|
||
|
||
// 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
|
||
// } |