Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions src/FluentModbus/Client/ModbusClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public abstract partial class ModbusClient
/// <param name="unitIdentifier">The unit identifier.</param>
/// <param name="functionCode">The function code.</param>
/// <param name="extendFrame">An action to be called to extend the prepared Modbus frame with function code specific data.</param>
protected abstract Span<byte> TransceiveFrame(byte unitIdentifier, ModbusFunctionCode functionCode, Action<ExtendedBinaryWriter> extendFrame);
protected abstract Span<byte> TransceiveFrame(byte unitIdentifier, ModbusFunctionCode functionCode, Action<SpanWriter> extendFrame);

internal void ProcessError(ModbusFunctionCode functionCode, ModbusExceptionCode exceptionCode)
{
Expand Down Expand Up @@ -214,7 +214,7 @@ public void WriteMultipleRegisters(byte unitIdentifier, ushort startingAddress,

writer.Write((byte)(quantity * 2)); // 12 Byte Count = Quantity of Registers * 2

writer.Write(dataset, 0, dataset.Length);
writer.Write(dataset);
});
}

Expand Down Expand Up @@ -422,7 +422,10 @@ public void WriteSingleRegister(byte unitIdentifier, ushort registerAddress, byt
else
writer.Write(registerAddress); // 08-09 Starting Address

writer.Write(value); // 10-11 Value
foreach (var b in value)
{
writer.Write(b);
}
});
}

Expand Down Expand Up @@ -463,7 +466,10 @@ public void WriteMultipleCoils(int unitIdentifier, int startingAddress, bool[] v

writer.Write((byte)byteCount); // 12 Byte Count = Outputs

writer.Write(convertedData);
foreach (var b in convertedData)
{
writer.Write(b);
}
});
}

Expand Down Expand Up @@ -562,7 +568,10 @@ public Span<byte> ReadWriteMultipleRegisters(byte unitIdentifier, ushort readSta

writer.Write((byte)(writeQuantity * 2)); // 16 Byte Count = Quantity to Write * 2

writer.Write(dataset, 0, dataset.Length);
foreach (var b in dataset)
{
writer.Write(b);
}
});

if (buffer.Length < readQuantity * 2 + 2)
Expand Down
24 changes: 12 additions & 12 deletions src/FluentModbus/Client/ModbusClientAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public abstract partial class ModbusClient
/// <param name="functionCode">The function code.</param>
/// <param name="extendFrame">An action to be called to extend the prepared Modbus frame with function code specific data.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
protected abstract Task<Memory<byte>> TransceiveFrameAsync(byte unitIdentifier, ModbusFunctionCode functionCode, Action<ExtendedBinaryWriter> extendFrame, CancellationToken cancellationToken = default);
protected abstract Task<Memory<byte>> TransceiveFrameAsync(byte unitIdentifier, ModbusFunctionCode functionCode, Action<SpanWriter> extendFrame, CancellationToken cancellationToken = default);

/// <summary>
/// Reads the specified number of values of type <typeparamref name="T"/> from the holding registers.
Expand All @@ -33,8 +33,8 @@ public async Task<Memory<T>> ReadHoldingRegistersAsync<T>(int unitIdentifier, in
var startingAddress_converted = ConvertUshort(startingAddress);
var count_converted = ConvertUshort(count);

var dataset = SpanExtensions.Cast<byte, T>(await
ReadHoldingRegistersAsync(unitIdentifier_converted, startingAddress_converted, ConvertSize<T>(count_converted), cancellationToken).ConfigureAwait(false));
var dataset = MemoryMarshal.Cast<byte, T>((await
ReadHoldingRegistersAsync(unitIdentifier_converted, startingAddress_converted, ConvertSize<T>(count_converted), cancellationToken).ConfigureAwait(false)).Span);

if (SwapBytes)
ModbusUtils.SwitchEndianness(dataset);
Expand Down Expand Up @@ -125,7 +125,7 @@ await TransceiveFrameAsync(unitIdentifier, ModbusFunctionCode.WriteMultipleRegis

writer.Write((byte)(quantity * 2)); // 12 Byte Count = Quantity of Registers * 2

writer.Write(dataset, 0, dataset.Length);
writer.Write(dataset);
}, cancellationToken).ConfigureAwait(false);
}

Expand Down Expand Up @@ -213,8 +213,8 @@ public async Task<Memory<T>> ReadInputRegistersAsync<T>(int unitIdentifier, int
var startingAddress_converted = ConvertUshort(startingAddress);
var count_converted = ConvertUshort(count);

var dataset = SpanExtensions.Cast<byte, T>(await
ReadInputRegistersAsync(unitIdentifier_converted, startingAddress_converted, ConvertSize<T>(count_converted), cancellationToken).ConfigureAwait(false));
var dataset = MemoryMarshal.Cast<byte, T>((await
ReadInputRegistersAsync(unitIdentifier_converted, startingAddress_converted, ConvertSize<T>(count_converted), cancellationToken).ConfigureAwait(false)).Span);

if (SwapBytes)
ModbusUtils.SwitchEndianness(dataset);
Expand Down Expand Up @@ -339,7 +339,7 @@ await TransceiveFrameAsync(unitIdentifier, ModbusFunctionCode.WriteSingleRegiste
else
writer.Write(registerAddress); // 08-09 Starting Address

writer.Write(value); // 10-11 Value
writer.Write(value);
}, cancellationToken).ConfigureAwait(false);
}

Expand All @@ -350,7 +350,7 @@ await TransceiveFrameAsync(unitIdentifier, ModbusFunctionCode.WriteSingleRegiste
/// <param name="startingAddress">The coil register start address for the write operation.</param>
/// <param name="values">The values to write to the server.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
public void WriteMultipleCoilsAsync(int unitIdentifier, int startingAddress, bool[] values, CancellationToken cancellationToken = default)
public async Task WriteMultipleCoilsAsync(int unitIdentifier, int startingAddress, bool[] values, CancellationToken cancellationToken = default)
{
var unitIdentifier_converted = ConvertUnitIdentifier(unitIdentifier);
var startingAddress_converted = ConvertUshort(startingAddress);
Expand All @@ -361,7 +361,7 @@ public void WriteMultipleCoilsAsync(int unitIdentifier, int startingAddress, boo
new BitArray(values)
.CopyTo(convertedData, 0);

TransceiveFrameAsync(unitIdentifier_converted, ModbusFunctionCode.WriteMultipleCoils, writer =>
await TransceiveFrameAsync(unitIdentifier_converted, ModbusFunctionCode.WriteMultipleCoils, writer =>
{
writer.Write((byte)ModbusFunctionCode.WriteMultipleCoils); // 07 Function Code

Expand All @@ -380,7 +380,7 @@ public void WriteMultipleCoilsAsync(int unitIdentifier, int startingAddress, boo
writer.Write((byte)byteCount); // 12 Byte Count = Outputs

writer.Write(convertedData);
}, cancellationToken);
}, cancellationToken).ConfigureAwait(false);
}

/// <summary>
Expand Down Expand Up @@ -435,7 +435,7 @@ public async Task<Memory<TRead>> ReadWriteMultipleRegistersAsync<TRead, TWrite>(
var readQuantity = ConvertSize<TRead>(readCount_converted);
var byteData = MemoryMarshal.Cast<TWrite, byte>(dataset).ToArray();

var dataset2 = SpanExtensions.Cast<byte, TRead>(await ReadWriteMultipleRegistersAsync(unitIdentifier_converted, readStartingAddress_converted, readQuantity, writeStartingAddress_converted, byteData, cancellationToken).ConfigureAwait(false));
var dataset2 = MemoryMarshal.Cast<byte, TRead>((await ReadWriteMultipleRegistersAsync(unitIdentifier_converted, readStartingAddress_converted, readQuantity, writeStartingAddress_converted, byteData, cancellationToken).ConfigureAwait(false)).Span);

if (SwapBytes)
ModbusUtils.SwitchEndianness(dataset2);
Expand Down Expand Up @@ -480,7 +480,7 @@ public async Task<Memory<byte>> ReadWriteMultipleRegistersAsync(byte unitIdentif

writer.Write((byte)(writeQuantity * 2)); // 16 Byte Count = Quantity to Write * 2

writer.Write(dataset, 0, dataset.Length);
writer.Write(dataset);
}, cancellationToken).ConfigureAwait(false);

if (buffer.Length < readQuantity * 2 + 2)
Expand Down
34 changes: 17 additions & 17 deletions src/FluentModbus/Client/ModbusRtuClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ public void Close()
}

///<inheritdoc/>
protected override Span<byte> TransceiveFrame(byte unitIdentifier, ModbusFunctionCode functionCode, Action<ExtendedBinaryWriter> extendFrame)
protected override Span<byte> TransceiveFrame(byte unitIdentifier, ModbusFunctionCode functionCode, Action<SpanWriter> extendFrame)
{
// WARNING: IF YOU EDIT THIS METHOD, REFLECT ALL CHANGES ALSO IN TransceiveFrameAsync!

Expand Down Expand Up @@ -174,32 +174,31 @@ protected override Span<byte> TransceiveFrame(byte unitIdentifier, ModbusFunctio
}
}

_frameBuffer.Writer.Seek(0, SeekOrigin.Begin);
_frameBuffer.Writer.Write(unitIdentifier); // 00 Unit Identifier
extendFrame(_frameBuffer.Writer);
frameLength = (int)_frameBuffer.Writer.BaseStream.Position;
var writer = new SpanWriter(_frameBuffer.Buffer.Span);
writer.Write(unitIdentifier); // 00 Unit Identifier
extendFrame(writer);
frameLength = writer.Position;

// add CRC
crc = ModbusUtils.CalculateCRC(_frameBuffer.Buffer.AsMemory()[..frameLength]);
_frameBuffer.Writer.Write(crc);
frameLength = (int)_frameBuffer.Writer.BaseStream.Position;
crc = ModbusUtils.CalculateCRC(_frameBuffer.Buffer.Slice(0, frameLength));
writer.Write(crc);
frameLength = writer.Position;

// send request
_serialPort!.Value.Value.Write(_frameBuffer.Buffer, 0, frameLength);
_serialPort!.Value.Value.Write(_frameBuffer.Buffer.Slice(0, frameLength));

// special case: broadcast (only for write commands)
if (unitIdentifier == 0)
return _frameBuffer.Buffer.AsSpan(0, 0);
return _frameBuffer.Buffer.Span.Slice(0, 0);

// wait for and process response
frameLength = 0;
_frameBuffer.Reader.BaseStream.Seek(0, SeekOrigin.Begin);

while (true)
{
frameLength += _serialPort!.Value.Value.Read(_frameBuffer.Buffer, frameLength, _frameBuffer.Buffer.Length - frameLength);
frameLength += _serialPort!.Value.Value.Read(_frameBuffer.Buffer.Slice(frameLength));

if (ModbusUtils.DetectResponseFrame(unitIdentifier, _frameBuffer.Buffer.AsMemory()[..frameLength]))
if (ModbusUtils.DetectResponseFrame(unitIdentifier, _frameBuffer.Buffer.Slice(0, frameLength)))
{
break;
}
Expand All @@ -213,16 +212,17 @@ protected override Span<byte> TransceiveFrame(byte unitIdentifier, ModbusFunctio
}
}

_ = _frameBuffer.Reader.ReadByte();
rawFunctionCode = _frameBuffer.Reader.ReadByte();
var reader = new SpanReader(_frameBuffer.Buffer.Span);
_ = reader.ReadByte();
rawFunctionCode = reader.ReadByte();

if (rawFunctionCode == (byte)ModbusFunctionCode.Error + (byte)functionCode)
ProcessError(functionCode, (ModbusExceptionCode)_frameBuffer.Buffer[2]);
ProcessError(functionCode, (ModbusExceptionCode)_frameBuffer.Buffer.Span[2]);

else if (rawFunctionCode != (byte)functionCode)
throw new ModbusException(ErrorMessage.ModbusClient_InvalidResponseFunctionCode);

return _frameBuffer.Buffer.AsSpan(1, frameLength - 3);
return _frameBuffer.Buffer.Span.Slice(1, frameLength - 3);
}

#endregion
Expand Down
34 changes: 17 additions & 17 deletions src/FluentModbus/Client/ModbusRtuClientAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace FluentModbus
public partial class ModbusRtuClient
{
///<inheritdoc/>
protected override async Task<Memory<byte>> TransceiveFrameAsync(byte unitIdentifier, ModbusFunctionCode functionCode, Action<ExtendedBinaryWriter> extendFrame, CancellationToken cancellationToken = default)
protected override async Task<Memory<byte>> TransceiveFrameAsync(byte unitIdentifier, ModbusFunctionCode functionCode, Action<SpanWriter> extendFrame, CancellationToken cancellationToken = default)
{
// WARNING: IF YOU EDIT THIS METHOD, REFLECT ALL CHANGES ALSO IN TransceiveFrameAsync!

Expand Down Expand Up @@ -35,32 +35,31 @@ protected override async Task<Memory<byte>> TransceiveFrameAsync(byte unitIdenti
}
}

_frameBuffer.Writer.Seek(0, SeekOrigin.Begin);
_frameBuffer.Writer.Write(unitIdentifier); // 00 Unit Identifier
extendFrame(_frameBuffer.Writer);
frameLength = (int)_frameBuffer.Writer.BaseStream.Position;
var writer = new SpanWriter(_frameBuffer.Buffer.Span);
writer.Write(unitIdentifier); // 00 Unit Identifier
extendFrame(writer);
frameLength = writer.Position;

// add CRC
crc = ModbusUtils.CalculateCRC(_frameBuffer.Buffer.AsMemory()[..frameLength]);
_frameBuffer.Writer.Write(crc);
frameLength = (int)_frameBuffer.Writer.BaseStream.Position;
crc = ModbusUtils.CalculateCRC(_frameBuffer.Buffer.Slice(0, frameLength));
writer.Write(crc);
frameLength = writer.Position;

// send request
await _serialPort!.Value.Value.WriteAsync(_frameBuffer.Buffer, 0, frameLength, cancellationToken).ConfigureAwait(false);
await _serialPort!.Value.Value.WriteAsync(_frameBuffer.Buffer.Slice(0, frameLength), cancellationToken).ConfigureAwait(false);

// special case: broadcast (only for write commands)
if (unitIdentifier == 0)
return _frameBuffer.Buffer.AsMemory(0, 0);
return _frameBuffer.Buffer.Slice(0, 0);

// wait for and process response
frameLength = 0;
_frameBuffer.Reader.BaseStream.Seek(0, SeekOrigin.Begin);

while (true)
{
frameLength += await _serialPort!.Value.Value.ReadAsync(_frameBuffer.Buffer, frameLength, _frameBuffer.Buffer.Length - frameLength, cancellationToken).ConfigureAwait(false);
frameLength += await _serialPort!.Value.Value.ReadAsync(_frameBuffer.Buffer.Slice(frameLength), cancellationToken).ConfigureAwait(false);

if (ModbusUtils.DetectResponseFrame(unitIdentifier, _frameBuffer.Buffer.AsMemory()[..frameLength]))
if (ModbusUtils.DetectResponseFrame(unitIdentifier, _frameBuffer.Buffer.Slice(0, frameLength)))
{
break;
}
Expand All @@ -74,16 +73,17 @@ protected override async Task<Memory<byte>> TransceiveFrameAsync(byte unitIdenti
}
}

_ = _frameBuffer.Reader.ReadByte();
rawFunctionCode = _frameBuffer.Reader.ReadByte();
var reader = new SpanReader(_frameBuffer.Buffer.Span);
_ = reader.ReadByte();
rawFunctionCode = reader.ReadByte();

if (rawFunctionCode == (byte)ModbusFunctionCode.Error + (byte)functionCode)
ProcessError(functionCode, (ModbusExceptionCode)_frameBuffer.Buffer[2]);
ProcessError(functionCode, (ModbusExceptionCode)_frameBuffer.Buffer.Span[2]);

else if (rawFunctionCode != (byte)functionCode)
throw new ModbusException(ErrorMessage.ModbusClient_InvalidResponseFunctionCode);

return _frameBuffer.Buffer.AsMemory(1, frameLength - 3);
return _frameBuffer.Buffer.Slice(1, frameLength - 3);
}
}
}
Loading