using IoTClient.Common.Helpers; using IoTServer.Common; using Newtonsoft.Json; using System; using System.IO.Ports; using System.Linq; using System.Text; namespace IoTServer.Servers.ModBus { /// /// ModBusAscii 服务端模拟 /// public class ModBusAsciiServer { private SerialPort serialPort; DataPersist dataPersist; public ModBusAsciiServer(string portName, int baudRate, int dataBits, StopBits stopBits, Parity parity) { if (serialPort == null) serialPort = new SerialPort(); serialPort.PortName = portName; serialPort.BaudRate = baudRate; serialPort.DataBits = dataBits; serialPort.StopBits = stopBits; serialPort.Encoding = Encoding.ASCII; serialPort.Parity = parity; #if !DEBUG serialPort.ReadTimeout = 1000;//1秒 #endif serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceived); dataPersist = new DataPersist("ModBusTcpServer"); } /// /// 启动服务 /// public void Start() { serialPort.Open(); } /// /// 停止服务 /// public void Stop() { serialPort.Close(); serialPort.Dispose(); } /// /// 接收数据回调用 /// /// /// private void DataReceived(object sender, SerialDataReceivedEventArgs e) { try { byte[] requetData = new byte[serialPort.BytesToRead]; serialPort.Read(requetData, 0, requetData.Length); var address = $"{requetData[5]}-{requetData[6]}-{requetData[7]}-{requetData[8]}"; byte[] tempData = new byte[requetData.Length - 3]; Buffer.BlockCopy(requetData, 1, tempData, 0, tempData.Length); var requetAsciiData = DataConvert.AsciiArrayToByteArray(tempData); var type = $"{requetData[3].ToString("X2")}{requetData[4].ToString("X2")}"; switch (type) { //读取线圈 case "3031": { var value = dataPersist.Read(address); var bytes = JsonConvert.DeserializeObject(value); byte[] data = null; //没有存储过的数据的,默认响应false if (bytes == null) { data = DataConvert.StringToByteArray("01 01 01 00"); } else { if (bytes[0].ToString("X2") != "3A" || bytes[bytes.Length - 2].ToString("X2") != "0D" || bytes[bytes.Length - 1].ToString("X2") != "0A") { throw new Exception("标记验证失败"); } byte[] asciiData = new byte[bytes.Length - 3]; Buffer.BlockCopy(bytes, 1, asciiData, 0, asciiData.Length); var byteDataArray = DataConvert.AsciiArrayToByteArray(asciiData); //true if (byteDataArray[4].ToString("X2") == "FF" && byteDataArray[5].ToString("X2") == "00") data = DataConvert.StringToByteArray("01 01 01 01"); else//false data = DataConvert.StringToByteArray("01 01 01 00"); } var dataString = string.Join("", LRC.GetLRC(data).Select(t => t.ToString("X2"))); var databyte = Encoding.ASCII.GetBytes(dataString); var responseData = new byte[databyte.Length + 3]; Buffer.BlockCopy(databyte, 0, responseData, 1, databyte.Length); responseData[0] = 0x3A; responseData[responseData.Length - 2] = 0x0D; responseData[responseData.Length - 1] = 0x0A; serialPort.Write(responseData, 0, responseData.Length); } break; //写入线圈 case "3035": { dataPersist.Write(address, JsonConvert.SerializeObject(requetData)); serialPort.Write(requetData, 0, requetData.Length); } break; //读取 case "3033": { var value = dataPersist.Read(address); var bytes = JsonConvert.DeserializeObject(value); byte[] data = null; if (bytes == null) { data = new byte[2 + 3]; data[2] = 2;//数据长度 } else { if (bytes[0].ToString("X2") != "3A" || bytes[bytes.Length - 2].ToString("X2") != "0D" || bytes[bytes.Length - 1].ToString("X2") != "0A") { throw new Exception("标记验证失败"); } byte[] asciiData = new byte[bytes.Length - 3]; Buffer.BlockCopy(bytes, 1, asciiData, 0, asciiData.Length); var byteDataArray = DataConvert.AsciiArrayToByteArray(asciiData); data = new byte[byteDataArray[6] + 3]; data[2] = byteDataArray[6];//数据长度 Buffer.BlockCopy(byteDataArray, 7, data, 3, data.Length - 3); } data[0] = requetAsciiData[0];//站号 data[1] = 0x03;//功能码 var dataString = string.Join("", LRC.GetLRC(data).Select(t => t.ToString("X2"))); var databyte = Encoding.ASCII.GetBytes(dataString); var responseData = new byte[databyte.Length + 3]; Buffer.BlockCopy(databyte, 0, responseData, 1, databyte.Length); responseData[0] = 0x3A; responseData[responseData.Length - 2] = 0x0D; responseData[responseData.Length - 1] = 0x0A; serialPort.Write(responseData, 0, responseData.Length); } break; //写入3130 对应十进制16 十六进制 10 case "3130": { dataPersist.Write(address, JsonConvert.SerializeObject(requetData)); serialPort.Write(requetData, 0, requetData.Length); } break; } } catch (Exception ex) { } } } }