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();
}
}
}