diff --git a/AMWD.Protocols.Modbus.Common/Contracts/ModbusClientBase.cs b/AMWD.Protocols.Modbus.Common/Contracts/ModbusClientBase.cs index d00c99b..5a59f3d 100644 --- a/AMWD.Protocols.Modbus.Common/Contracts/ModbusClientBase.cs +++ b/AMWD.Protocols.Modbus.Common/Contracts/ModbusClientBase.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; -using System.Threading.Tasks; -using System.Threading; using System.Linq; using System.Text; +using System.Threading; +using System.Threading.Tasks; namespace AMWD.Protocols.Modbus.Common.Contracts { diff --git a/AMWD.Protocols.Modbus.Common/Exceptions/ModbusException.cs b/AMWD.Protocols.Modbus.Common/Exceptions/ModbusException.cs index 377e9f2..87cfdad 100644 --- a/AMWD.Protocols.Modbus.Common/Exceptions/ModbusException.cs +++ b/AMWD.Protocols.Modbus.Common/Exceptions/ModbusException.cs @@ -1,6 +1,8 @@ using System; using System.Diagnostics.CodeAnalysis; +#if !NET8_0_OR_GREATER using System.Runtime.Serialization; +#endif namespace AMWD.Protocols.Modbus.Common { diff --git a/AMWD.Protocols.Modbus.Common/Models/ModbusObject.cs b/AMWD.Protocols.Modbus.Common/Models/ModbusObject.cs index c7b91b0..a6e3b6b 100644 --- a/AMWD.Protocols.Modbus.Common/Models/ModbusObject.cs +++ b/AMWD.Protocols.Modbus.Common/Models/ModbusObject.cs @@ -1,4 +1,6 @@ -using System; +#if NET6_0_OR_GREATER +using System; +#endif namespace AMWD.Protocols.Modbus.Common { diff --git a/AMWD.Protocols.Modbus.Common/Protocols/RtuOverTcpProtocol.cs b/AMWD.Protocols.Modbus.Common/Protocols/RtuOverTcpProtocol.cs index 72089b4..3815822 100644 --- a/AMWD.Protocols.Modbus.Common/Protocols/RtuOverTcpProtocol.cs +++ b/AMWD.Protocols.Modbus.Common/Protocols/RtuOverTcpProtocol.cs @@ -10,7 +10,9 @@ namespace AMWD.Protocols.Modbus.Common.Protocols /// /// /// The Modbus RTU over Modbus TCP is rarely used. - /// It is a non-standard variant of Modbus TCP that includes wrapps a Modbus RTU message within a Modbus TCP message. + /// It is a non-standard variant: + /// You can define it as RTU message with an additional TCP header + /// or as TCP message with an additional CRC16 checksum at the end (header not included!). ///
/// Definition found on Fernhill Software. ///
diff --git a/AMWD.Protocols.Modbus.Proxy/ModbusTcpProxy.cs b/AMWD.Protocols.Modbus.Proxy/ModbusTcpProxy.cs index 40987e0..ce1ef23 100644 --- a/AMWD.Protocols.Modbus.Proxy/ModbusTcpProxy.cs +++ b/AMWD.Protocols.Modbus.Proxy/ModbusTcpProxy.cs @@ -370,7 +370,7 @@ namespace AMWD.Protocols.Modbus.Proxy responseBytes.Add((byte)ModbusErrorCode.SlaveDeviceFailure); } - return [.. responseBytes]; + return ReturnResponse(responseBytes); } private async Task HandleReadDiscreteInputsAsync(byte[] requestBytes, CancellationToken cancellationToken) @@ -409,7 +409,7 @@ namespace AMWD.Protocols.Modbus.Proxy responseBytes.Add((byte)ModbusErrorCode.SlaveDeviceFailure); } - return [.. responseBytes]; + return ReturnResponse(responseBytes); } private async Task HandleReadHoldingRegistersAsync(byte[] requestBytes, CancellationToken cancellationToken) @@ -443,7 +443,7 @@ namespace AMWD.Protocols.Modbus.Proxy responseBytes.Add((byte)ModbusErrorCode.SlaveDeviceFailure); } - return [.. responseBytes]; + return ReturnResponse(responseBytes); } private async Task HandleReadInputRegistersAsync(byte[] requestBytes, CancellationToken cancellationToken) @@ -477,7 +477,7 @@ namespace AMWD.Protocols.Modbus.Proxy responseBytes.Add((byte)ModbusErrorCode.SlaveDeviceFailure); } - return [.. responseBytes]; + return ReturnResponse(responseBytes); } private async Task HandleWriteSingleCoilAsync(byte[] requestBytes, CancellationToken cancellationToken) @@ -494,7 +494,8 @@ namespace AMWD.Protocols.Modbus.Proxy { responseBytes[7] |= 0x80; responseBytes.Add((byte)ModbusErrorCode.IllegalDataValue); - return [.. responseBytes]; + + return ReturnResponse(responseBytes); } try @@ -524,7 +525,7 @@ namespace AMWD.Protocols.Modbus.Proxy responseBytes.Add((byte)ModbusErrorCode.SlaveDeviceFailure); } - return [.. responseBytes]; + return ReturnResponse(responseBytes); } private async Task HandleWriteSingleRegisterAsync(byte[] requestBytes, CancellationToken cancellationToken) @@ -564,7 +565,7 @@ namespace AMWD.Protocols.Modbus.Proxy responseBytes.Add((byte)ModbusErrorCode.SlaveDeviceFailure); } - return [.. responseBytes]; + return ReturnResponse(responseBytes); } private async Task HandleWriteMultipleCoilsAsync(byte[] requestBytes, CancellationToken cancellationToken) @@ -583,7 +584,8 @@ namespace AMWD.Protocols.Modbus.Proxy { responseBytes[7] |= 0x80; responseBytes.Add((byte)ModbusErrorCode.IllegalDataValue); - return [.. responseBytes]; + + return ReturnResponse(responseBytes); } try @@ -623,7 +625,7 @@ namespace AMWD.Protocols.Modbus.Proxy responseBytes.Add((byte)ModbusErrorCode.SlaveDeviceFailure); } - return [.. responseBytes]; + return ReturnResponse(responseBytes); } private async Task HandleWriteMultipleRegistersAsync(byte[] requestBytes, CancellationToken cancellationToken) @@ -642,7 +644,8 @@ namespace AMWD.Protocols.Modbus.Proxy { responseBytes[7] |= 0x80; responseBytes.Add((byte)ModbusErrorCode.IllegalDataValue); - return [.. responseBytes]; + + return ReturnResponse(responseBytes); } try @@ -679,7 +682,7 @@ namespace AMWD.Protocols.Modbus.Proxy responseBytes.Add((byte)ModbusErrorCode.SlaveDeviceFailure); } - return [.. responseBytes]; + return ReturnResponse(responseBytes); } private async Task HandleEncapsulatedInterfaceAsync(byte[] requestBytes, CancellationToken cancellationToken) @@ -691,7 +694,8 @@ namespace AMWD.Protocols.Modbus.Proxy { responseBytes[7] |= 0x80; responseBytes.Add((byte)ModbusErrorCode.IllegalFunction); - return [.. responseBytes]; + + return ReturnResponse(responseBytes); } var firstObject = (ModbusDeviceIdentificationObject)requestBytes[10]; @@ -699,7 +703,8 @@ namespace AMWD.Protocols.Modbus.Proxy { responseBytes[7] |= 0x80; responseBytes.Add((byte)ModbusErrorCode.IllegalDataAddress); - return [.. responseBytes]; + + return ReturnResponse(responseBytes); } var category = (ModbusDeviceIdentificationCategory)requestBytes[9]; @@ -707,7 +712,8 @@ namespace AMWD.Protocols.Modbus.Proxy { responseBytes[7] |= 0x80; responseBytes.Add((byte)ModbusErrorCode.IllegalDataValue); - return [.. responseBytes]; + + return ReturnResponse(responseBytes); } try @@ -764,7 +770,8 @@ namespace AMWD.Protocols.Modbus.Proxy bodyBytes[5] = numberOfObjects; responseBytes.AddRange(bodyBytes); - return [.. responseBytes]; + + return ReturnResponse(responseBytes); } bodyBytes.AddRange(objBytes); @@ -773,13 +780,15 @@ namespace AMWD.Protocols.Modbus.Proxy bodyBytes[5] = numberOfObjects; responseBytes.AddRange(bodyBytes); - return [.. responseBytes]; + + return ReturnResponse(responseBytes); } catch { responseBytes[7] |= 0x80; responseBytes.Add((byte)ModbusErrorCode.SlaveDeviceFailure); - return [.. responseBytes]; + + return ReturnResponse(responseBytes); } } @@ -863,6 +872,16 @@ namespace AMWD.Protocols.Modbus.Proxy return [.. result]; } + private static byte[] ReturnResponse(List response) + { + ushort followingBytes = (ushort)(response.Count - 6); + byte[] bytes = followingBytes.ToBigEndianBytes(); + response[4] = bytes[0]; + response[5] = bytes[1]; + + return [.. response]; + } + #endregion Request Handling } } diff --git a/AMWD.Protocols.Modbus.Serial/ModbusSerialConnection.cs b/AMWD.Protocols.Modbus.Serial/ModbusSerialConnection.cs index 8d54951..94cc1fa 100644 --- a/AMWD.Protocols.Modbus.Serial/ModbusSerialConnection.cs +++ b/AMWD.Protocols.Modbus.Serial/ModbusSerialConnection.cs @@ -107,9 +107,7 @@ namespace AMWD.Protocols.Modbus.Serial set => _serialPort.PortName = value; } - /// - /// Gets or sets the serial baud rate. - /// + /// public virtual BaudRate BaudRate { get => (BaudRate)_serialPort.BaudRate; @@ -118,7 +116,11 @@ namespace AMWD.Protocols.Modbus.Serial /// /// - /// Should be 7 for ASCII mode and 8 for RTU mode. + /// From the Specs: + ///
+ /// On it can be 7 or 8. + ///
+ /// On it has to be 8. ///
public virtual int DataBits { @@ -159,9 +161,9 @@ namespace AMWD.Protocols.Modbus.Serial /// /// From the Specs: ///
- /// Should be for or and + /// Should be for or . ///
- /// should be for . + /// Should be for . ///
public virtual StopBits StopBits { @@ -188,7 +190,6 @@ namespace AMWD.Protocols.Modbus.Serial try { - _processingTask.Wait(); _processingTask.Dispose(); } catch diff --git a/CHANGELOG.md b/CHANGELOG.md index 006455c..ede9233 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The `ModbusTcpProxy.ReadWriteTimeout` has a default value of 100 seconds (same default as a `HttpClient` has). +### Fixed + +- Wrong _following bytes_ calculation in `ModbusTcpProxy`. + ## [v0.3.2] (2024-09-04)