using UnityEngine; using System.Collections.Generic; using System; #if UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_STANDALONE_LINUX || UNITY_EDITOR || UNITY_ANDROID using System.IO.Ports; #endif /// /// Modbus设备控制器,用于控制和管理Modbus设备的开关状态。 /// public class ModbusDeviceController : MonoBehaviour { [System.Serializable] public class ModbusDevice { public string deviceName = "未命名设备"; public ushort registerAddress = 0x0000; public byte[] openCommand = new byte[8]; public byte[] closeCommand = new byte[8]; public bool isActive = false; /// /// 构造函数,用于创建Modbus设备实例。 /// /// /// /// /// public ModbusDevice(string name, ushort address, string openHex, string closeHex) { deviceName = name; registerAddress = address; openCommand = HexStringToByteArray(openHex); closeCommand = HexStringToByteArray(closeHex); } /// /// 将十六进制字符串转换为字节数组。 /// /// /// /// private static byte[] HexStringToByteArray(string hex) { hex = hex.Replace(" ", "").Replace("-", "").Trim(); if (hex.Length % 2 != 0) { throw new ArgumentException($"十六进制字符串长度必须为偶数: {hex}"); } byte[] bytes = new byte[hex.Length / 2]; for (int i = 0; i < bytes.Length; i++) { string hexByte = hex.Substring(i * 2, 2); bytes[i] = Convert.ToByte(hexByte, 16); } return bytes; } } [Header("串口配置")] [Tooltip("串口号,如COM3、COM4等")] public string portName = "COM3"; [Range(9600, 115200)] public int baudRate = 9600; [Header("设备列表 - 共13个控制功能")] public List deviceList = new List(); [Header("控制设置")] [Tooltip("启用调试日志")] public bool enableDebug = true; [Tooltip("命令发送间隔(秒)")] public float commandInterval = 0.1f; [Header("设备状态")] [Tooltip("显示设备当前状态")] public List deviceStatus = new List(); #if UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_STANDALONE_LINUX || UNITY_EDITOR || UNITY_ANDROID private SerialPort serialPort; #endif private float lastCommandTime = 0f; private void Start() { InitializeDeviceList(); InitializeDeviceStatus(); ScanSerialPorts(); } /// /// 初始化设备列表,根据实际需求添加或修改Modbus设备的配置。 /// private void InitializeDeviceList() { deviceList.Clear(); // 第一组:管路控制(1-5路) deviceList.Add(new ModbusDevice("第一路红色管路", 0x0000, "01 05 00 00 FF 00 8C 3A", "01 05 00 00 00 00 CD CA")); deviceList.Add(new ModbusDevice("第二路绿色管路", 0x0001, "01 05 00 01 FF 00 DD FA", "01 05 00 01 00 00 9C 0A")); deviceList.Add(new ModbusDevice("第三路蓝色管路", 0x0002, "01 05 00 02 FF 00 2D FA", "01 05 00 02 00 00 6C 0A")); deviceList.Add(new ModbusDevice("第四路罐体", 0x0003, "01 05 00 03 FF 00 7C 3A", "01 05 00 03 00 00 3D CA")); deviceList.Add(new ModbusDevice("第五路照明", 0x0004, "01 05 00 04 FF 00 CD FB", "01 05 00 04 00 00 8C 0B")); // 第二组:设备控制(6-12路,注意地址0-4与上面重复) deviceList.Add(new ModbusDevice("第一路空压机转动", 0x0000, "01 05 00 00 FF 00 8C 3A", "01 05 00 00 00 00 CD CA")); deviceList.Add(new ModbusDevice("第二路控制柜亮", 0x0001, "01 05 00 01 FF 00 DD FA", "01 05 00 01 00 00 9C 0A")); deviceList.Add(new ModbusDevice("第三路红色管路流动", 0x0002, "01 05 00 02 FF 00 2D FA", "01 05 00 02 00 00 6C 0A")); deviceList.Add(new ModbusDevice("第四路第一个罐上升", 0x0003, "01 05 00 03 FF 00 7C 3A", "01 05 00 03 00 00 3D CA")); deviceList.Add(new ModbusDevice("第五路蓝色管路流动", 0x0004, "01 05 00 04 FF 00 CD FB", "01 05 00 04 00 00 8C 0B")); deviceList.Add(new ModbusDevice("第六路第二个罐亮", 0x0005, "01 05 00 05 FF 00 9C 3B", "01 05 00 05 00 00 DD CB")); deviceList.Add(new ModbusDevice("第七路第二个汽轮机工作", 0x0006, "01 05 00 06 FF 00 6C 3B", "01 05 00 06 00 00 2D CB")); if (enableDebug) { Debug.Log($"设备列表初始化完成,共 {deviceList.Count} 个控制功能"); } } /// /// 初始化设备状态列表,确保每个设备的初始状态为"未连接"。 /// private void InitializeDeviceStatus() { deviceStatus.Clear(); for (int i = 0; i < deviceList.Count; i++) { deviceStatus.Add("未连接"); } } /// /// 扫描并列出所有可用的串口。 /// /// public bool OpenSerialPort() { #if UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_STANDALONE_LINUX || UNITY_EDITOR || UNITY_ANDROID try { if (serialPort != null && serialPort.IsOpen) { if (enableDebug) Debug.Log($"串口 {portName} 已打开"); return true; } serialPort = new SerialPort(portName, baudRate) { DataBits = 8, Parity = Parity.None, StopBits = StopBits.One, Handshake = Handshake.None, ReadTimeout = 1000, WriteTimeout = 1000 }; serialPort.Open(); if (enableDebug) { Debug.Log($"串口 {portName} 打开成功"); Debug.Log($"串口配置: 波特率={baudRate}, 8N1"); } return true; } catch (Exception ex) { if (enableDebug) Debug.LogError($"打开串口失败: {ex.Message}"); return false; } #else if (enableDebug) Debug.LogWarning("当前平台不支持System.IO.Ports,使用模拟模式"); return true; #endif } /// /// 发送设备命令到串口。 /// /// /// /// public bool SendDeviceCommand(int deviceIndex, bool turnOn) { if (deviceIndex < 0 || deviceIndex >= deviceList.Count) { if (enableDebug) Debug.LogError($"设备索引 {deviceIndex} 无效"); return false; } if (Time.time - lastCommandTime < commandInterval) { if (enableDebug) Debug.LogWarning($"命令发送过于频繁,请等待 {commandInterval:F2} 秒"); return false; } ModbusDevice device = deviceList[deviceIndex]; byte[] command = turnOn ? device.openCommand : device.closeCommand; if (enableDebug) { string action = turnOn ? "打开" : "关闭"; string hexStr = ByteArrayToHexString(command); Debug.Log($"[{device.deviceName}] {action}"); Debug.Log($"指令: {hexStr}"); } bool success = SendSerialData(command); if (success) { deviceList[deviceIndex].isActive = turnOn; deviceStatus[deviceIndex] = turnOn ? "已打开" : "已关闭"; lastCommandTime = Time.time; } else { deviceStatus[deviceIndex] = "发送失败"; } return success; } /// /// 切换指定设备的状态(打开/关闭)。如果设备已开启,则关闭;反之,则开启。 /// /// public void ToggleDevice(int deviceIndex) { if (deviceIndex >= 0 && deviceIndex < deviceList.Count) { bool newState = !deviceList[deviceIndex].isActive; SendDeviceCommand(deviceIndex, newState); } } /// /// 通过设备名称控制设备的开关状态。如果找到匹配的设备,则发送命令;否则,记录错误信息。 /// /// /// public void ControlDeviceByName(string deviceName, bool turnOn) { for (int i = 0; i < deviceList.Count; i++) { if (deviceList[i].deviceName == deviceName) { SendDeviceCommand(i, turnOn); return; } } if (enableDebug) Debug.LogError($"未找到设备: {deviceName}"); } /// /// 打开所有设备。如果启用调试,则记录日志信息。 /// public void TurnOnAllDevices() { if (enableDebug) Debug.Log("打开所有设备"); for (int i = 0; i < deviceList.Count; i++) { SendDeviceCommand(i, true); } } /// /// 关闭所有设备。如果启用调试,则记录日志信息。 /// public void TurnOffAllDevices() { if (enableDebug) Debug.Log("关闭所有设备"); for (int i = 0; i < deviceList.Count; i++) { SendDeviceCommand(i, false); } } /// /// 打开指定设备组。如果启用调试,则记录日志信息。如果结束索引超出范围,只处理到列表末尾为止。 /// /// /// public void TurnOnGroup(int startIndex, int endIndex) { if (enableDebug) Debug.Log($"打开设备组 {startIndex}-{endIndex}"); for (int i = startIndex; i <= endIndex && i < deviceList.Count; i++) { SendDeviceCommand(i, true); } } /// /// 关闭指定设备组。如果启用调试,则记录日志信息。如果结束索引超出范围,只处理到列表末尾为止。 /// /// /// public void TurnOffGroup(int startIndex, int endIndex) { if (enableDebug) Debug.Log($"关闭设备组 {startIndex}-{endIndex}"); for (int i = startIndex; i <= endIndex && i < deviceList.Count; i++) { SendDeviceCommand(i, false); } } /// /// 控制第一路红色管路 /// /// public void ControlRedPipe(bool on) => ControlDeviceByName("第一路红色管路", on); /// /// 控制第二路绿色管路 /// /// public void ControlGreenPipe(bool on) => ControlDeviceByName("第二路绿色管路", on); /// /// 控制第三路蓝色管路 /// /// public void ControlBluePipe(bool on) => ControlDeviceByName("第三路蓝色管路", on); /// /// 控制第四路罐体 /// /// public void ControlTank(bool on) => ControlDeviceByName("第四路罐体", on); /// /// 控制第五路照明 /// /// public void ControlLighting(bool on) => ControlDeviceByName("第五路照明", on); /// /// 控制第一路空压机转动 /// /// public void ControlAirCompressor(bool on) => ControlDeviceByName("第一路空压机转动", on); /// /// 控制第二路控制柜亮 /// /// public void ControlCabinetLight(bool on) => ControlDeviceByName("第二路控制柜亮", on); /// /// 控制第三路红色管路流动 /// /// public void ControlRedPipeFlow(bool on) => ControlDeviceByName("第三路红色管路流动", on); /// /// 控制第四路第一个罐上升 /// /// public void ControlTankUp(bool on) => ControlDeviceByName("第四路第一个罐上升", on); /// /// 控制第五路蓝色管路流动 /// /// public void ControlBluePipeFlow(bool on) => ControlDeviceByName("第五路蓝色管路流动", on); /// /// 控制第六路第二个罐亮 /// /// public void ControlSecondTankLight(bool on) => ControlDeviceByName("第六路第二个罐亮", on); /// /// 控制第七路第二个汽轮机工作 /// /// public void ControlSecondTurbine(bool on) => ControlDeviceByName("第七路第二个汽轮机工作", on); /// /// 发送设备命令 /// /// /// private bool SendSerialData(byte[] data) { #if UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_STANDALONE_LINUX || UNITY_EDITOR || UNITY_ANDROID if (serialPort == null || !serialPort.IsOpen) { if (!OpenSerialPort()) { return false; } } try { serialPort.Write(data, 0, data.Length); return true; } catch (Exception ex) { if (enableDebug) Debug.LogError($"发送数据失败: {ex.Message}"); return false; } #else if (enableDebug) Debug.Log("模拟发送: 成功"); return true; #endif } /// /// 扫描可用串口。只在调试模式下执行,用于测试和验证。如果启用调试,则记录日志信息。 /// private void ScanSerialPorts() { #if UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_STANDALONE_LINUX || UNITY_EDITOR || UNITY_ANDROID try { string[] ports = SerialPort.GetPortNames(); if (ports.Length > 0) { Debug.Log($"可用串口: {string.Join(", ", ports)}"); } else { Debug.LogWarning("未找到可用串口"); } } catch { if (enableDebug) Debug.LogError("扫描串口失败"); } #endif } /// /// 获取当前设备控制状态的总览字符串。如果启用调试,则记录日志信息。 /// /// public string GetStatusSummary() { System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.AppendLine("=== 设备控制状态总结 ==="); sb.AppendLine($"总共 {deviceList.Count} 个控制功能"); sb.AppendLine(); // 管路控制组 sb.AppendLine("【管路控制组】"); for (int i = 0; i < 5; i++) { sb.AppendLine($" {i + 1}. {deviceList[i].deviceName}: {deviceStatus[i]}"); } sb.AppendLine(); sb.AppendLine("【设备控制组】"); for (int i = 5; i < deviceList.Count; i++) { sb.AppendLine($" {i - 4}. {deviceList[i].deviceName}: {deviceStatus[i]}"); } sb.AppendLine(); sb.AppendLine($"串口: {portName}, 波特率: {baudRate}"); return sb.ToString(); } /// /// 打印当前设备控制状态的总览字符串。如果启用调试,则记录日志信息。 /// public void PrintStatus() { if (enableDebug) { Debug.Log(GetStatusSummary()); } } /// /// 测试所有命令,依次打开每个设备。如果启用调试,则记录日志信息。 /// public void TestAllCommands() { if (enableDebug) Debug.Log("开始测试所有命令..."); for (int i = 0; i < deviceList.Count; i++) { if (enableDebug) Debug.Log($"测试设备 {i + 1}: {deviceList[i].deviceName}"); SendDeviceCommand(i, true); } if (enableDebug) Debug.Log("所有命令测试完成"); } /// /// 将字节数组转换为十六进制字符串格式。如果启用调试,则记录日志信息。 /// /// /// private string ByteArrayToHexString(byte[] bytes) { return BitConverter.ToString(bytes).Replace("-", " "); } /// /// 打开串口并初始化。如果启用调试,则记录日志信息。 /// public void CloseSerialPort() { #if UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_STANDALONE_LINUX || UNITY_EDITOR || UNITY_ANDROID if (serialPort != null && serialPort.IsOpen) { serialPort.Close(); if (enableDebug) Debug.Log("串口已关闭"); } #endif } private void OnApplicationQuit() { CloseSerialPort(); } private void OnDestroy() { CloseSerialPort(); } } // UI控制示例 public class DeviceControlUI : MonoBehaviour { public ModbusDeviceController controller; // Unity UI按钮可以绑定这些方法 public void OpenAllDevices() { if (controller != null) { controller.TurnOnAllDevices(); } } public void CloseAllDevices() { if (controller != null) { controller.TurnOffAllDevices(); } } public void ControlRedPipeOn() => controller.ControlRedPipe(true); public void ControlRedPipeOff() => controller.ControlRedPipe(false); public void ControlGreenPipeOn() => controller.ControlGreenPipe(true); public void ControlGreenPipeOff() => controller.ControlGreenPipe(false); public void ControlBluePipeOn() => controller.ControlBluePipe(true); public void ControlBluePipeOff() => controller.ControlBluePipe(false); public void ControlAirCompressorOn() => controller.ControlAirCompressor(true); public void ControlAirCompressorOff() => controller.ControlAirCompressor(false); [ContextMenu("显示设备状态")] public void ShowStatus() { if (controller != null) { controller.PrintStatus(); } } }