using System; using System.Collections; using System.Collections.Generic; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; using UnityEngine; public class CarStatusData { public int IgnitionSwitch { get; set; } // 钥匙开关数据 public short SteeringWheelAngle { get; set; } // 方向盘数据 public int HornStatus { get; set; } // 方向盘上喇叭状态 public int BrakePedalPosition { get; set; } // 刹车踏板数据 public int AcceleratorPedalPosition { get; set; } // 油门踏板数据 public int ClutchPedalPosition { get; set; } // 离合踏板数据 public int HandbrakeStatus { get; set; } // 手刹数据 public int GearPosition { get; set; } // 挡位数据 public int WiperStatus { get; set; } // 雨刮状态 public int LightStatus { get; set; } // 灯光状态 public int TurnSignalStatus { get; set; } // 转向灯状态 public int KeyStatus { get; set; } // 点火钥匙数据 public int ButtonData { get; set; } // 按键数据 } namespace ModbusManager { public class ModbusTcpClient:MonoBehaviour { private TcpClient tcpClient; private string serverIp = "192.168.1.100"; private int serverPort = 12315; public Queue modbusQueue; public static ModbusTcpClient modbusTcpClient; private CancellationTokenSource cancellationTokenSource; private void Awake() { modbusTcpClient = this; tcpClient = new TcpClient(); modbusQueue = new Queue(); } private void Start() { } public void StartModbus() { cancellationTokenSource = new CancellationTokenSource(); // MonitorConnection(cancellationTokenSource.Token); MonitorQueue(cancellationTokenSource.Token); // await ConnectToServer(); // while (true) // { // await SendModbusRequest(); // // await SendModbusRequest12(); // await Task.Delay(TimeSpan.FromSeconds(.1)); // } } private void OnDestroy() { CloseConnection(); } public ModbusTcpClient() { tcpClient = new TcpClient(); modbusQueue = new Queue(); string str= System.IO.File.ReadAllText(Application.streamingAssetsPath + "/setting.txt"); serverIp = str.Split(',')[0]; serverPort = int.Parse(str.Split(',')[1]); } /// /// 接口为TCP/IP接口。 /// 协议为MODBUS/TCP,数据为十六进制数据。 /// 硬件设备为服务器端,IP地址192.168.0.100,端口12315,电脑为客户端。 /// public async Task ConnectToServer() { try { await tcpClient.ConnectAsync(serverIp, serverPort); Debug.Log("已连接到Modbus服务器。"); await SendModbusRequest12(); } catch (Exception ex) { Debug.Log("连接Modbus服务器时出错: " + ex.Message); } } /// /// 连接成功后,电脑主动发送(十六进制数据): 00 00 00 00 00 06 01 03 00 00 00 10 /// "00 00 00 00 00 06"为TCP报文头,06表示后面有六个字节。 /// "01"表示硬件设备编号 /// "03"表示读数据 /// "00 00" 表示读数据从0000开始 /// "00 10" 表示读16个数据 /// public async Task SendModbusRequest() { byte[] request = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, 0x10 }; NetworkStream stream = tcpClient.GetStream(); if (stream.CanWrite) { await stream.WriteAsync(request, 0, request.Length); // Debug.Log("Modbus请求已发送。"); await ReadResponse(stream); } } public async Task SendModbusRequest12() { byte[] request = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x06, 0x00, 0x01, 0x00, 0x00 }; NetworkStream stream = tcpClient.GetStream(); if (stream.CanWrite) { await stream.WriteAsync(request, 0, request.Length); // Debug.Log("Modbus请求已发送。"); await ReadResponse(stream); } } private async Task MonitorConnection(CancellationToken token) { while (!token.IsCancellationRequested) { if (!tcpClient.Connected) { try { await ConnectToServer(); } catch (Exception ex) { Debug.Log("连接失败: " + ex.Message); await Task.Delay(TimeSpan.FromSeconds(1), token); // 重试前等待 } } await Task.Delay(TimeSpan.FromSeconds(1), token); // 检查间隔 } } private async Task MonitorQueue(CancellationToken token) { while (!token.IsCancellationRequested) { if (modbusQueue.Count == 0) { await SendModbusRequest(); await Task.Delay(TimeSpan.FromSeconds(3), token); // 队列检查频率 } else { await Task.Delay(TimeSpan.FromSeconds(1), token); // 等待一段时间后再次检查 } } } /// /// 设备回复: 00 00 00 00 00 24 01 03 20 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 09 00 0A 00 0B 00 0C 00 0D 00 0E 00 0F 00 10 /// "00 00 00 00 00 24" 为TCP报文头,24 表示后面有三十六个字节。 /// "01" 表示硬件设备编号。 /// "03" 表示读数据。 /// "20" 表示后面有三十二个字节数据,即16个数据。 /// 后续数据为硬件反馈回来的数据: /// - "00 01" 为钥匙开关数据,0 熄火,1 通电,2 启动。 /// - "00 02"为方向盘数据,左打方向盘为负数,右打方向盘为正数,打方向盘幅度越大,绝对值越大。 /// - "00 03" 为方向盘上喇叭状态,01 为喇叭按下。 /// - "00 04"为刹车踏板数据, 0-100,踩到底为100 /// - "00 05" 为油门踏板数据。0-100,踩到底为100 /// - "00 06" 为离合踏板数据。0-100,踩到底为100 /// - "00 07" 为手刹数据,01 表示手刹有效。 /// - "00 08" 为挡位数据,00 空挡,1 前进档,2 倒挡,3 为 P 档。 /// - "00 09" 为雨刮数据,00 空档,1 手动一次雨刮,2 自动雨刮慢速,3 自动雨刮快速。 /// - "00 0A" 为灯光数据,00 未开灯,1 近光,2 远光。 /// - "00 0B" 为转向灯数据,00 未开转向灯,1 左转向灯,2 右转向灯。 /// - "00 0C"为点火钥匙数据,00是熄火,1是通电,2是点火 /// 后面为预留。 /// private async Task ReadResponse(NetworkStream stream) { byte[] response = new byte[256]; int bytesRead = await stream.ReadAsync(response, 0, response.Length); //Debug.LogLine("已接收到Modbus服务器的响应。"); if (bytesRead > 9) // 确保响应长度足够 { int length = response[5]; byte deviceId = response[6]; byte functionCode = response[7]; //Debug.Log($"设备ID: {deviceId}, 功能码: {functionCode}, 数据长度: {length}"); CarStatusData carStatusData = new CarStatusData(); for (int i = 9; i < 9 + length; i += 2) { ushort dataValue = (ushort)(response[i] << 8 | response[i + 1]); switch ((i - 9) / 2) { case 0://s0熄火,1通电,2启动 // Debug.Log($"钥匙开关数据: {dataValue}"); carStatusData.IgnitionSwitch = dataValue; break; case 1://左打方向盘为负数,右打方向盘为正数,打方向盘打死一圈半,数值1500。 // Debug.Log($"方向盘数据: {(short)dataValue}"); carStatusData.SteeringWheelAngle = (short)dataValue; break; case 2://01为喇叭按下 // Debug.Log($"方向盘上喇叭状态: {dataValue}"); carStatusData.HornStatus = dataValue; break; case 3://0-100,踩到底为100 // Debug.Log($"刹车踏板数据: {dataValue}"); carStatusData.BrakePedalPosition = dataValue; break; case 4://0-100,踩到底为100 // Debug.Log($"油门踏板数据: {dataValue}"); carStatusData.AcceleratorPedalPosition = dataValue; break; case 5://0-100,踩到底为100 // Debug.Log($"离合踏板数据: {dataValue}"); carStatusData.ClutchPedalPosition = dataValue; break; case 6://01表示手刹有效 // Debug.Log($"手刹数据: {dataValue}"); carStatusData.HandbrakeStatus = dataValue; break; case 7://00空挡,1前进档,2倒挡,3为P档 // Debug.Log($"挡位数据: {dataValue}"); carStatusData.GearPosition = dataValue; break; case 8://00是空档,1是手动一次雨刮,2是自动雨刮慢速,3是自动雨刮快速 // Debug.Log($"雨刮状态: {dataValue}"); carStatusData.WiperStatus = dataValue; break; case 9://00是未开灯,1是示廓灯,2是近光远光。。没有找到远光信号。 // Debug.Log($"灯光状态: {dataValue}"); carStatusData.LightStatus = dataValue; break; case 10://00是未开转向灯,1是左转向灯,2是右转向灯 // Debug.Log($"转向灯状态: {dataValue}"); carStatusData.TurnSignalStatus = dataValue; break; case 11://00是熄火,1是通电,2是点火 //Debug.Log($"点火钥匙数据: {dataValue}"); carStatusData.KeyStatus = dataValue; break; case 12://上1,右2,下3,左4 // Debug.Log($"按键数据: {dataValue}"); carStatusData.ButtonData = dataValue; break; // default: // Debug.Log($"预留数据 {i / 2 - 4}: {dataValue}"); // break; } } modbusQueue.Enqueue(carStatusData); // Debug.Log(modbusQueue.Count); } else { Debug.Log("响应长度无效。"); } } public void CloseConnection() { if (tcpClient != null) { if (tcpClient.Connected) { tcpClient.GetStream().Close(); tcpClient.Close(); cancellationTokenSource.Cancel(); Debug.Log("已关闭与Modbus服务器的连接。"); } } } } }