/// <summary> /// 检查当前的Modbus-Rtu响应是否是正确的 /// </summary> /// <param name="send">发送的数据信息</param> /// <returns>带是否成功的结果数据</returns> protected virtual OperateResult <byte[]> CheckModbusTcpResponse(byte[] send) { // 核心交互 OperateResult <byte[]> result = ReadBase(send); if (!result.IsSuccess) { return(result); } // 长度校验 if (result.Content.Length < 5) { return(new OperateResult <byte[]>(StringResources.Language.ReceiveDataLengthTooShort + "5")); } // 检查crc if (!SoftCRC16.CheckCRC16(result.Content)) { return(new OperateResult <byte[]>(StringResources.Language.ModbusCRCCheckFailed)); } // 发生了错误 if ((send[1] + 0x80) == result.Content[1]) { return(new OperateResult <byte[]>(result.Content[2], ModbusInfo.GetDescriptionByErrorCode(result.Content[2]))); } // 移除CRC校验 byte[] buffer = new byte[result.Content.Length - 2]; Array.Copy(result.Content, 0, buffer, 0, buffer.Length); return(OperateResult.CreateSuccessResult(buffer)); }
/// <summary> /// 检查当前的Modbus-Ascii响应是否是正确的 /// </summary> /// <param name="send">发送的数据信息</param> /// <returns>带是否成功的结果数据</returns> protected override OperateResult <byte[]> CheckModbusTcpResponse(byte[] send) { // 转ascii byte[] modbus_ascii = ModbusInfo.TransRtuToAsciiPackCommand(send); // 核心交互 OperateResult <byte[]> result = ReadBase(modbus_ascii); if (!result.IsSuccess) { return(result); } // 还原modbus报文 OperateResult <byte[]> modbus_core = ModbusInfo.TransAsciiPackCommandToRtu(result.Content); if (!modbus_core.IsSuccess) { return(modbus_core); } // 发生了错误 if ((send[1] + 0x80) == modbus_core.Content[1]) { return new OperateResult <byte[]>( ) { ErrorCode = modbus_core.Content[2], Message = ModbusInfo.GetDescriptionByErrorCode(modbus_core.Content[2]) } } ; // 成功的消息 return(OperateResult.CreateSuccessResult(modbus_core.Content)); }
/// <summary> /// 从Modbus服务器批量读取寄存器的信息,需要指定起始地址,读取长度 /// </summary> /// <param name="address">起始地址,格式为"1234",或者是带功能码格式x=3;1234</param> /// <param name="length">读取的数量</param> /// <returns>带有成功标志的字节信息</returns> /// <remarks> /// 富地址格式,支持携带站号信息,功能码信息,具体参照类的示例代码 /// </remarks> /// <example> /// 此处演示批量读取的示例 /// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Modbus\Modbus.cs" region="ReadExample1" title="Read示例" /> /// </example> public override OperateResult <byte[]> Read(string address, ushort length) { OperateResult <ModbusAddress> analysis = ModbusInfo.AnalysisAddress(address, isAddressStartWithZero, ModbusInfo.ReadRegister); if (!analysis.IsSuccess) { return(OperateResult.CreateFailedResult <byte[]>(analysis)); } List <byte> lists = new List <byte>( ); ushort alreadyFinished = 0; while (alreadyFinished < length) { ushort lengthTmp = (ushort)Math.Min((length - alreadyFinished), 120); OperateResult <byte[]> read = ReadModBusBase(analysis.Content.AddressAdd(alreadyFinished), lengthTmp); if (!read.IsSuccess) { return(OperateResult.CreateFailedResult <byte[]>(read)); } lists.AddRange(read.Content); alreadyFinished += lengthTmp; } return(OperateResult.CreateSuccessResult(lists.ToArray( ))); }
/// <summary> /// 生成一个读取寄存器的指令头 /// </summary> /// <param name="address">地址</param> /// <param name="length">长度</param> /// <returns>携带有命令字节</returns> private OperateResult <byte[]> BuildReadRegisterCommand(ModbusAddress address, ushort length) { ushort messageId = (ushort)softIncrementCount.GetCurrentValue( ); // 生成最终tcp指令 byte[] buffer = ModbusInfo.PackCommandToTcp(address.CreateReadRegister(station, length), messageId); return(OperateResult.CreateSuccessResult(buffer)); }
/// <summary> /// 生成一个读取线圈的指令头 /// </summary> /// <param name="address">地址</param> /// <param name="count">长度</param> /// <returns>携带有命令字节</returns> private OperateResult <byte[]> BuildReadCoilCommand(string address, ushort count) { OperateResult <ModbusAddress> analysis = ModbusInfo.AnalysisReadAddress(address, isAddressStartWithZero); if (!analysis.IsSuccess) { return(OperateResult.CreateFailedResult <byte[]>(analysis)); } // 生成最终tcp指令 byte[] buffer = ModbusInfo.PackCommandToRtu(analysis.Content.CreateReadCoils(station, count)); return(OperateResult.CreateSuccessResult(buffer)); }
private OperateResult <byte[]> BuildWriteRegisterCommand(string address, byte[] values) { OperateResult <ModbusAddress> analysis = ModbusInfo.AnalysisReadAddress(address, isAddressStartWithZero); if (!analysis.IsSuccess) { return(OperateResult.CreateFailedResult <byte[]>(analysis)); } // 生成最终tcp指令 byte[] buffer = ModbusInfo.PackCommandToRtu(analysis.Content.CreateWriteRegister(station, values)); return(OperateResult.CreateSuccessResult(buffer)); }
/// <summary> /// 生成一个读取寄存器的指令头 /// </summary> /// <param name="address">地址</param> /// <param name="length">长度</param> /// <returns>携带有命令字节</returns> public OperateResult <byte[]> BuildReadRegisterCommand(string address, ushort length) { OperateResult <ModbusAddress> analysis = ModbusInfo.AnalysisReadAddress(address, isAddressStartWithZero); if (!analysis.IsSuccess) { return(OperateResult.CreateFailedResult <byte[]>(analysis)); } // 生成最终rtu指令 byte[] buffer = ModbusInfo.PackCommandToRtu(analysis.Content.CreateReadRegister(station, length)); return(OperateResult.CreateSuccessResult(buffer)); }
/// <summary> /// 生成批量写入单个线圈的报文信息 /// </summary> /// <param name="address">地址</param> /// <param name="values">实际数据值</param> /// <returns>包含结果对象的报文</returns> public OperateResult <byte[]> BuildWriteCoilCommand(string address, bool[] values) { OperateResult <ModbusAddress> analysis = ModbusInfo.AnalysisAddress(address, isAddressStartWithZero, ModbusInfo.WriteCoil); if (!analysis.IsSuccess) { return(OperateResult.CreateFailedResult <byte[]>(analysis)); } // 生成最终rtu指令 byte[] buffer = ModbusInfo.PackCommandToRtu(analysis.Content.CreateWriteCoil(station, values)); return(OperateResult.CreateSuccessResult(buffer)); }
private OperateResult <byte[]> BuildWriteRegisterCommand(string address, byte[] values) { OperateResult <ModbusAddress> analysis = ModbusInfo.AnalysisReadAddress(address, isAddressStartWithZero); if (!analysis.IsSuccess) { return(OperateResult.CreateFailedResult <byte[]>(analysis)); } ushort messageId = (ushort)softIncrementCount.GetCurrentValue( ); // 生成最终tcp指令 byte[] buffer = ModbusInfo.PackCommandToTcp(analysis.Content.CreateWriteRegister(station, values), messageId); return(OperateResult.CreateSuccessResult(buffer)); }
/// <summary> /// 检查当前的Modbus-Tcp响应是否是正确的 /// </summary> /// <param name="send">发送的数据信息</param> /// <returns>带是否成功的结果数据</returns> private OperateResult <byte[]> CheckModbusTcpResponse(byte[] send) { OperateResult <byte[]> resultBytes = ReadFromCoreServer(send); if (resultBytes.IsSuccess) { if ((send[7] + 0x80) == resultBytes.Content[7]) { // 发生了错误 resultBytes.IsSuccess = false; resultBytes.Message = ModbusInfo.GetDescriptionByErrorCode(resultBytes.Content[8]); resultBytes.ErrorCode = resultBytes.Content[8]; } } return(resultBytes); }
/// <summary> /// 生成批量写入单个线圈的报文信息 /// </summary> /// <param name="address">地址</param> /// <param name="values">实际数据值</param> /// <returns>包含结果对象的报文</returns> public OperateResult <byte[]> BuildWriteCoilCommand(string address, bool[] values) { // 解析富地址 OperateResult <ModbusAddress> analysis = ModbusInfo.AnalysisAddress(address, isAddressStartWithZero, ModbusInfo.WriteCoil); if (!analysis.IsSuccess) { return(OperateResult.CreateFailedResult <byte[]>(analysis)); } // 获取消息号 ushort messageId = (ushort)softIncrementCount.GetCurrentValue( ); // 生成最终tcp指令 byte[] buffer = ModbusInfo.PackCommandToTcp(analysis.Content.CreateWriteCoil(station, values), messageId); return(OperateResult.CreateSuccessResult(buffer)); }
/// <summary> /// 检查当前的Modbus-Tcp响应是否是正确的 /// </summary> /// <param name="send">发送的数据信息</param> /// <returns>带是否成功的结果数据</returns> private OperateResult <byte[]> CheckModbusTcpResponse(byte[] send) { OperateResult <byte[]> result = ReadBase(send); if (!result.IsSuccess) { return(result); } if (result.Content.Length < 5) { return(new OperateResult <byte[]>( ) { IsSuccess = false, Message = "接收数据长度不能小于5", }); } if (!SoftCRC16.CheckCRC16(result.Content)) { return(new OperateResult <byte[]>( ) { IsSuccess = false, Message = "CRC校验失败", }); } if ((send[1] + 0x80) == result.Content[1]) { // 发生了错误 return(new OperateResult <byte[]>( ) { IsSuccess = false, Message = ModbusInfo.GetDescriptionByErrorCode(result.Content[2]), ErrorCode = result.Content[2], }); } else { // 移除CRC校验 byte[] buffer = new byte[result.Content.Length - 2]; Array.Copy(result.Content, 0, buffer, 0, buffer.Length); return(OperateResult.CreateSuccessResult(buffer)); } }
/// <summary> /// 检查当前的Modbus-Rtu响应是否是正确的 /// </summary> /// <param name="send">发送的数据信息</param> /// <returns>带是否成功的结果数据</returns> protected virtual OperateResult <byte[]> CheckModbusTcpResponse(byte[] send) { // 核心交互 OperateResult <byte[]> result = ReadBase(send); if (!result.IsSuccess) { return(result); } // 长度校验 if (result.Content.Length < 5) { return new OperateResult <byte[]>( ) { IsSuccess = false, Message = "接收数据长度不能小于5" } } ; // 检查crc if (!SoftCRC16.CheckCRC16(result.Content)) { return new OperateResult <byte[]>( ) { Message = "CRC校验失败" } } ; // 发生了错误 if ((send[1] + 0x80) == result.Content[1]) { return new OperateResult <byte[]>( ) { ErrorCode = result.Content[2], Message = ModbusInfo.GetDescriptionByErrorCode(result.Content[2]) } } ; // 移除CRC校验 byte[] buffer = new byte[result.Content.Length - 2]; Array.Copy(result.Content, 0, buffer, 0, buffer.Length); return(OperateResult.CreateSuccessResult(buffer)); }
/// <summary> /// 批量读取线圈或是离散的数据信息,需要指定地址和长度,具体的结果取决于实现 /// </summary> /// <param name="address">数据地址</param> /// <param name="length">数据长度</param> /// <returns>带有成功标识的bool[]数组</returns> public override OperateResult <bool[]> ReadBool(string address, ushort length) { OperateResult <ModbusAddress> analysis = ModbusInfo.AnalysisAddress(address, isAddressStartWithZero, ModbusInfo.ReadCoil); if (!analysis.IsSuccess) { return(OperateResult.CreateFailedResult <bool[]>(analysis)); } var read = ReadModBusBase((byte)analysis.Content.Function, address, length); if (!read.IsSuccess) { return(OperateResult.CreateFailedResult <bool[]>(read)); } return(OperateResult.CreateSuccessResult(SoftBasic.ByteToBoolArray(read.Content, length))); }
private void SocketAsyncCallBack(IAsyncResult ar) { if (ar.AsyncState is AppSession session) { try { int receiveCount = session.WorkSocket.EndReceive(ar); ModbusTcpMessage mdMessage = new ModbusTcpMessage( ); OperateResult <byte[]> read1 = ReceiveByMessage(session.WorkSocket, 5000, mdMessage); if (!read1.IsSuccess) { LogNet?.WriteDebug(ToString( ), string.Format(StringResources.Language.ClientOfflineInfo, session.IpEndPoint)); RemoveClient(session); return; } ; ushort id = (ushort)(read1.Content[0] * 256 + read1.Content[1]); byte[] back = ModbusInfo.PackCommandToTcp(ReadFromModbusCore(SoftBasic.BytesArrayRemoveBegin(read1.Content, 6)), id); if (back != null) { session.WorkSocket.Send(back); } else { session.WorkSocket.Close( ); RemoveClient(session); return; } RaiseDataReceived(read1.Content); session.WorkSocket.BeginReceive(new byte[0], 0, 0, SocketFlags.None, new AsyncCallback(SocketAsyncCallBack), session); } catch { // 关闭连接,记录日志 session.WorkSocket?.Close( ); LogNet?.WriteDebug(ToString( ), string.Format(StringResources.Language.ClientOfflineInfo, session.IpEndPoint)); RemoveClient(session); return; } } }
/// <summary> /// 读取自定义的寄存器的值。按照字为单位 /// </summary> /// <param name="address">起始地址,示例:"100","x=4;100"</param> /// <param name="length">数据长度</param> /// <exception cref="IndexOutOfRangeException"></exception> /// <returns>byte数组值</returns> public override OperateResult <byte[]> Read(string address, ushort length) { OperateResult <ModbusAddress> analysis = ModbusInfo.AnalysisAddress(address, true, ModbusInfo.ReadRegister); if (!analysis.IsSuccess) { return(OperateResult.CreateFailedResult <byte[]>(analysis)); } if (analysis.Content.Function == ModbusInfo.ReadRegister) { return(OperateResult.CreateSuccessResult(registerBuffer.GetBytes(analysis.Content.Address * 2, length * 2))); } else if (analysis.Content.Function == ModbusInfo.ReadInputRegister) { return(OperateResult.CreateSuccessResult(inputRegisterBuffer.GetBytes(analysis.Content.Address * 2, length * 2))); } else { return(new OperateResult <byte[]>(StringResources.Language.NotSupportedDataType)); } }
/// <summary> /// 写入自定义的数据到数据内存中去 /// </summary> /// <param name="address">地址</param> /// <param name="value">数据值</param> /// <returns>是否写入成功的结果对象</returns> public override OperateResult Write(string address, byte[] value) { OperateResult <ModbusAddress> analysis = ModbusInfo.AnalysisReadAddress(address, true); if (!analysis.IsSuccess) { return(OperateResult.CreateFailedResult <byte[]>(analysis)); } if (analysis.Content.Function == ModbusInfo.ReadRegister) { registerBuffer.SetBytes(value, analysis.Content.Address * 2); return(OperateResult.CreateSuccessResult( )); } else if (analysis.Content.Function == ModbusInfo.ReadInputRegister) { inputRegisterBuffer.SetBytes(value, analysis.Content.Address * 2); return(OperateResult.CreateSuccessResult( )); } else { return(new OperateResult <byte[]>(StringResources.Language.NotSupportedDataType)); } }
/// <summary> /// 生成一个读取寄存器的指令头 /// </summary> /// <param name="address">地址</param> /// <param name="length">长度</param> /// <returns>携带有命令字节</returns> private OperateResult <byte[]> BuildReadRegisterCommand(ModbusAddress address, ushort length) { // 生成最终tcp指令 byte[] buffer = ModbusInfo.PackCommandToRtu(address.CreateReadRegister(station, length)); return(OperateResult.CreateSuccessResult(buffer)); }
/// <summary> /// 接收到串口数据的时候触发 /// </summary> /// <param name="sender">串口对象</param> /// <param name="e">消息</param> private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) { int rCount = 0; byte[] buffer = new byte[1024]; byte[] receive = null; while (true) { System.Threading.Thread.Sleep(20); // 此处做个微小的延时,等待数据接收完成 int count = serialPort.Read(buffer, rCount, serialPort.BytesToRead); rCount += count; if (count == 0) { break; } receive = new byte[rCount]; Array.Copy(buffer, 0, receive, 0, count); } if (receive == null) { return; } if (receive.Length < 3) { LogNet?.WriteError(ToString( ), $"Uknown Data:" + SoftBasic.ByteToHexString(receive, ' ')); return; } if (Serial.SoftCRC16.CheckCRC16(receive)) { byte[] modbusCore = SoftBasic.BytesArrayRemoveLast(receive, 2); if (!CheckModbusMessageLegal(modbusCore)) { // 指令长度验证错误,关闭网络连接 LogNet?.WriteError(ToString( ), $"Receive Nosense Modbus-rtu : " + SoftBasic.ByteToHexString(receive, ' ')); return; } // 验证站号是否一致 if (station >= 0 && station != modbusCore[0]) { LogNet?.WriteError(ToString( ), $"Station not match Modbus-rtu : " + SoftBasic.ByteToHexString(receive, ' ')); return; } // LogNet?.WriteError( ToString( ), $"Success:" + BasicFramework.SoftBasic.ByteToHexString( receive, ' ' ) ); // 需要回发消息 byte[] copy = ModbusInfo.PackCommandToRtu(ReadFromModbusCore(modbusCore)); serialPort.Write(copy, 0, copy.Length); if (IsStarted) { RaiseDataReceived(receive); } } else { LogNet?.WriteWarn("CRC Check Failed : " + SoftBasic.ByteToHexString(receive, ' ')); } }