248 lines
11 KiB
C#
248 lines
11 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using System.Net.Sockets;
|
||
using System.Threading.Tasks;
|
||
using UnityEditor.Search;
|
||
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 = "172.16.1.125";
|
||
private int serverPort = 12315;
|
||
public Queue<CarStatusData> modbusQueue;
|
||
public static ModbusTcpClient modbusTcpClient;
|
||
|
||
private void Awake()
|
||
{
|
||
modbusTcpClient = this;
|
||
|
||
tcpClient = new TcpClient();
|
||
modbusQueue = new Queue<CarStatusData>();
|
||
}
|
||
|
||
private void Start()
|
||
{
|
||
StartModbus();
|
||
}
|
||
|
||
async Task StartModbus()
|
||
{
|
||
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<CarStatusData>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 接口为TCP/IP接口。
|
||
/// 协议为MODBUS/TCP,数据为十六进制数据。
|
||
/// 硬件设备为服务器端,IP地址192.168.0.100,端口12315,电脑为客户端。
|
||
/// </summary>
|
||
public async Task ConnectToServer()
|
||
{
|
||
try
|
||
{
|
||
await tcpClient.ConnectAsync(serverIp, serverPort);
|
||
Debug.Log("已连接到Modbus服务器。");
|
||
// await SendModbusRequest();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Debug.Log("连接Modbus服务器时出错: " + ex.Message);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 连接成功后,电脑主动发送(十六进制数据): 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个数据
|
||
/// </summary>
|
||
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);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设备回复: 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是点火
|
||
/// 后面为预留。
|
||
/// </summary>
|
||
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();
|
||
Debug.Log("已关闭与Modbus服务器的连接。");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} |