refactor: modbus/s7
This commit is contained in:
@@ -66,7 +66,7 @@ internal class ModbusRtuSend : ISendMessage
|
|||||||
byteBlock.WriteByte(ModbusAddress.Station);
|
byteBlock.WriteByte(ModbusAddress.Station);
|
||||||
byteBlock.WriteByte((byte)f);
|
byteBlock.WriteByte((byte)f);
|
||||||
byteBlock.WriteUInt16(ModbusAddress.StartAddress, EndianType.Big);
|
byteBlock.WriteUInt16(ModbusAddress.StartAddress, EndianType.Big);
|
||||||
byteBlock.WriteUInt16((ushort)Math.Ceiling(ModbusAddress.Data.Length / 2.0), EndianType.Big);
|
byteBlock.WriteUInt16((ushort)Math.Ceiling(f==15?ModbusAddress.Data.Length*8: ModbusAddress.Data.Length / 2.0), EndianType.Big);
|
||||||
byteBlock.WriteByte((byte)ModbusAddress.Data.Length);
|
byteBlock.WriteByte((byte)ModbusAddress.Data.Length);
|
||||||
byteBlock.Write(ModbusAddress.Data.Span);
|
byteBlock.Write(ModbusAddress.Data.Span);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ internal class ModbusTcpSend : ISendMessage
|
|||||||
byteBlock.WriteByte(ModbusAddress.Station);
|
byteBlock.WriteByte(ModbusAddress.Station);
|
||||||
byteBlock.WriteByte((byte)f);
|
byteBlock.WriteByte((byte)f);
|
||||||
byteBlock.WriteUInt16(ModbusAddress.StartAddress, EndianType.Big);
|
byteBlock.WriteUInt16(ModbusAddress.StartAddress, EndianType.Big);
|
||||||
byteBlock.WriteUInt16((ushort)Math.Ceiling(ModbusAddress.Data.Length / 2.0), EndianType.Big);
|
byteBlock.WriteUInt16((ushort)Math.Ceiling(f==15?ModbusAddress.Data.Length*8: ModbusAddress.Data.Length / 2.0), EndianType.Big);
|
||||||
byteBlock.WriteByte((byte)ModbusAddress.Data.Length);
|
byteBlock.WriteByte((byte)ModbusAddress.Data.Length);
|
||||||
byteBlock.Write(ModbusAddress.Data.Span);
|
byteBlock.Write(ModbusAddress.Data.Span);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -200,8 +200,9 @@ public partial class ModbusMaster : ProtocolBase, IDtu
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var mAddress = ModbusAddress.ParseFrom(address, Station, DtuId);
|
var mAddress = ModbusAddress.ParseFrom(address, Station, DtuId);
|
||||||
if (value.Length > 1 || mAddress.WriteFunctionCode == 15)
|
if (value.Length > 1 && mAddress.FunctionCode == 1)
|
||||||
{
|
{
|
||||||
|
mAddress.WriteFunctionCode = 15;
|
||||||
mAddress.Data = value.BoolArrayToByte();
|
mAddress.Data = value.BoolArrayToByte();
|
||||||
return await ModbusRequestAsync(mAddress, false, cancellationToken);
|
return await ModbusRequestAsync(mAddress, false, cancellationToken);
|
||||||
}
|
}
|
||||||
@@ -214,12 +215,15 @@ public partial class ModbusMaster : ProtocolBase, IDtu
|
|||||||
{
|
{
|
||||||
if (mAddress.BitIndex < 16)
|
if (mAddress.BitIndex < 16)
|
||||||
{
|
{
|
||||||
|
mAddress.Length = 2;
|
||||||
var readData = await ModbusRequestAsync(mAddress, true, cancellationToken);
|
var readData = await ModbusRequestAsync(mAddress, true, cancellationToken);
|
||||||
if (!readData.IsSuccess) return readData;
|
if (!readData.IsSuccess) return readData;
|
||||||
var writeData = ThingsGatewayBitConverter.ToUInt16(readData.Content, 0);
|
var writeData = ThingsGatewayBitConverter.ToUInt16(readData.Content, 0);
|
||||||
ushort mask = (ushort)(1 << mAddress.BitIndex);
|
for (int i = 0; i < value.Length; i++)
|
||||||
ushort result = (ushort)(value[0] ? (writeData | mask) : (writeData & ~mask));
|
{
|
||||||
mAddress.Data = ThingsGatewayBitConverter.GetBytes(result);
|
writeData=writeData.SetBit(mAddress.BitIndex.Value + i, value[i]);
|
||||||
|
}
|
||||||
|
mAddress.Data = ThingsGatewayBitConverter.GetBytes(writeData);
|
||||||
return await ModbusRequestAsync(mAddress, false, cancellationToken);
|
return await ModbusRequestAsync(mAddress, false, cancellationToken);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -512,6 +512,7 @@ public class ModbusSlave : ProtocolBase, ITcpService, IDtuClient
|
|||||||
ModbusServer04ByteBlock.Write(mAddress.Data.Span);
|
ModbusServer04ByteBlock.Write(mAddress.Data.Span);
|
||||||
return new();
|
return new();
|
||||||
|
|
||||||
|
case 3:
|
||||||
case 6:
|
case 6:
|
||||||
case 16:
|
case 16:
|
||||||
ModbusServer03ByteBlock.Position = mAddress.StartAddress * this.RegisterByteLength;
|
ModbusServer03ByteBlock.Position = mAddress.StartAddress * this.RegisterByteLength;
|
||||||
@@ -546,34 +547,66 @@ public class ModbusSlave : ProtocolBase, ITcpService, IDtuClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override ValueTask<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default)
|
public override async ValueTask<OperResult> WriteAsync(string address, byte[] value, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
ModbusAddress mAddress = ModbusAddress.ParseFrom(address, this.Station);
|
try
|
||||||
mAddress.Data = value;
|
|
||||||
var result = ModbusRequest(mAddress, false, cancellationToken);
|
|
||||||
if (result.IsSuccess)
|
|
||||||
{
|
{
|
||||||
return EasyValueTask.FromResult(new OperResult());
|
await EasyValueTask.CompletedTask;
|
||||||
|
var mAddress = ModbusAddress.ParseFrom(address, Station, DtuId);
|
||||||
|
mAddress.Data = value;
|
||||||
|
return ModbusRequest(mAddress, false, cancellationToken);
|
||||||
}
|
}
|
||||||
else
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
return EasyValueTask.FromResult(new OperResult(result));
|
return new OperResult(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override ValueTask<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default)
|
public override async ValueTask<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
ModbusAddress mAddress = ModbusAddress.ParseFrom(address, this.Station);
|
try
|
||||||
mAddress.Data = value.BoolArrayToByte();
|
|
||||||
var result = ModbusRequest(mAddress, false, cancellationToken);
|
|
||||||
if (result.IsSuccess)
|
|
||||||
{
|
{
|
||||||
return EasyValueTask.FromResult(new OperResult());
|
await EasyValueTask.CompletedTask;
|
||||||
|
var mAddress = ModbusAddress.ParseFrom(address, Station, DtuId);
|
||||||
|
if (value.Length > 1 && mAddress.FunctionCode == 1)
|
||||||
|
{
|
||||||
|
mAddress.WriteFunctionCode = 15;
|
||||||
|
mAddress.Data = value.BoolArrayToByte();
|
||||||
|
ModbusRequest(mAddress, false, cancellationToken);
|
||||||
|
return OperResult.Success;
|
||||||
|
}
|
||||||
|
else if (mAddress.BitIndex == null)
|
||||||
|
{
|
||||||
|
mAddress.Data = value[0] ? new byte[2] { 255, 0 } : [0, 0];
|
||||||
|
ModbusRequest(mAddress, false, cancellationToken);
|
||||||
|
return OperResult.Success;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (mAddress.BitIndex < 16)
|
||||||
|
{
|
||||||
|
mAddress.Length = 2;
|
||||||
|
var readData = ModbusRequest(mAddress, true, cancellationToken);
|
||||||
|
if (!readData.IsSuccess) return readData;
|
||||||
|
var writeData = TouchSocketBitConverter.BigEndian.To<ushort>(readData.Content.Span);
|
||||||
|
for (int i = 0; i < value.Length; i++)
|
||||||
|
{
|
||||||
|
writeData = writeData.SetBit(mAddress.BitIndex.Value + i, value[i]);
|
||||||
|
}
|
||||||
|
mAddress.Data = ThingsGatewayBitConverter.GetBytes(writeData);
|
||||||
|
ModbusRequest(mAddress, false, cancellationToken);
|
||||||
|
return OperResult.Success;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new OperResult(ModbusResource.Localizer["ValueOverlimit", nameof(mAddress.BitIndex), 16]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
return EasyValueTask.FromResult(new OperResult(result));
|
return new OperResult(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -168,6 +168,14 @@ internal class S7Message : MessageBase, IResultMessage
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (byteBlock[pos + 13] + byteBlock[pos + 14] > 0) // 如果错误代码不为0
|
||||||
|
{
|
||||||
|
Response.ErrorCode = byteBlock[pos + 14];
|
||||||
|
this.OperCode = 999;
|
||||||
|
this.ErrorMessage = SiemensS7Resource.Localizer["ReturnError", byteBlock[pos + 13].ToString("X2"), byteBlock[pos + 14].ToString("X2")];
|
||||||
|
return FilterResult.Success;
|
||||||
|
}
|
||||||
|
|
||||||
if (byteBlock.Length < pos + 18)
|
if (byteBlock.Length < pos + 18)
|
||||||
{
|
{
|
||||||
this.OperCode = 999;
|
this.OperCode = 999;
|
||||||
|
|||||||
@@ -125,10 +125,11 @@ internal class S7Send : ISendMessage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void GetWriteByteCommand<TByteBlock>(ref TByteBlock valueByteBlock, SiemensAddress address, bool isBit) where TByteBlock : IByteBlock
|
internal void GetWriteByteCommand<TByteBlock>(ref TByteBlock valueByteBlock, SiemensAddress address) where TByteBlock : IByteBlock
|
||||||
{
|
{
|
||||||
var data = address.Data;
|
var data = address.Data;
|
||||||
byte len = (byte)data.Length;
|
byte len = (byte)address.Length;
|
||||||
|
bool isBit = (IsBit && len == 1);
|
||||||
ushort telegramLen = (ushort)(16 + 19 + len);
|
ushort telegramLen = (ushort)(16 + 19 + len);
|
||||||
ushort parameterLen = 12 + 2;
|
ushort parameterLen = 12 + 2;
|
||||||
//TPKT
|
//TPKT
|
||||||
@@ -181,7 +182,7 @@ internal class S7Send : ISendMessage
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GetWriteByteCommand(ref byteBlock, SiemensAddress[0], IsBit);
|
GetWriteByteCommand(ref byteBlock, SiemensAddress[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,49 +108,113 @@ public partial class SiemensS7Master : ProtocolBase
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 此方法并不会智能分组以最大化效率,减少传输次数,因为返回值是byte[],所以一切都按地址数组的顺序执行,最后合并数组
|
/// 此方法并不会智能分组以最大化效率,减少传输次数,因为返回值是byte[],所以一切都按地址数组的顺序执行,最后合并数组
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async ValueTask<OperResult<byte[]>> S7RequestAsync(SiemensAddress[] sAddresss, bool read, bool isBit, CancellationToken cancellationToken = default)
|
public async ValueTask<OperResult<byte[]>> S7RequestAsync(SiemensAddress[] sAddresss, bool read, bool isBit,int bitLength=0, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var byteBlock = new ValueByteBlock(2048);
|
if (read)
|
||||||
try
|
|
||||||
{
|
{
|
||||||
foreach (var sAddress in sAddresss)
|
var byteBlock = new ValueByteBlock(2048);
|
||||||
|
try
|
||||||
{
|
{
|
||||||
int num = 0;
|
foreach (var sAddress in sAddresss)
|
||||||
var addressLen = sAddress.Length==0?1: sAddress.Length;
|
|
||||||
while (num < addressLen)
|
|
||||||
{
|
{
|
||||||
//pdu长度,重复生成报文,直至全部生成
|
int num = 0;
|
||||||
int len = Math.Min(addressLen - num, PduLength);
|
var addressLen = sAddress.Length == 0 ? 1 : sAddress.Length;
|
||||||
sAddress.Length = len;
|
while (num < addressLen)
|
||||||
|
{
|
||||||
|
//pdu长度,重复生成报文,直至全部生成
|
||||||
|
int len = Math.Min(addressLen - num, PduLength);
|
||||||
|
sAddress.Length = len;
|
||||||
|
|
||||||
|
var result = await this.SendThenReturnAsync(
|
||||||
|
new S7Send([sAddress], read, isBit), cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||||
|
if (!result.IsSuccess) return result;
|
||||||
|
|
||||||
|
byteBlock.Write(result.Content);
|
||||||
|
num += len;
|
||||||
|
|
||||||
|
if (sAddress.DataCode == (byte)S7WordLength.Timer || sAddress.DataCode == (byte)S7WordLength.Counter)
|
||||||
|
{
|
||||||
|
sAddress.AddressStart += len / 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sAddress.AddressStart += len * 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new OperResult<byte[]>() { Content = byteBlock.ToArray() };
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return new OperResult<byte[]>(ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
byteBlock.SafeDispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var sAddress = sAddresss[0];
|
||||||
|
if (sAddresss.Length > 1) return new OperResult<byte[]>("Only supports single write");
|
||||||
|
if (sAddress.Length > 1 && isBit)
|
||||||
|
{
|
||||||
|
//读取,再写入
|
||||||
|
var byteBlock = new ValueByteBlock(2048);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var addressLen = sAddress.Length == 0 ? 1 : sAddress.Length;
|
||||||
|
|
||||||
|
if (addressLen > PduLength)
|
||||||
|
return new OperResult<byte[]>("Write length exceeds limit");
|
||||||
|
|
||||||
|
var result = await this.SendThenReturnAsync(
|
||||||
|
new S7Send([sAddress], true, isBit), cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (!result.IsSuccess) return result;
|
||||||
|
var vaue = sAddress.Data.ByteToBoolArray(bitLength);
|
||||||
|
for (int i = sAddress.BitCode; i < vaue.Length+ sAddress.BitCode; i++)
|
||||||
|
{
|
||||||
|
result.Content[i/8] = result.Content[i/8].SetBit( (i%8), vaue[i- sAddress.BitCode]);
|
||||||
|
}
|
||||||
|
sAddress.Data = result.Content;
|
||||||
|
return await this.SendThenReturnAsync(
|
||||||
|
new S7Send([sAddress], false, isBit), cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return new OperResult<byte[]>(ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
byteBlock.SafeDispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var byteBlock = new ValueByteBlock(2048);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var addressLen = sAddress.Length == 0 ? 1 : sAddress.Length;
|
||||||
|
|
||||||
|
if (addressLen > PduLength)
|
||||||
|
return new OperResult<byte[]>("Write length exceeds limit");
|
||||||
|
|
||||||
var result = await this.SendThenReturnAsync(
|
var result = await this.SendThenReturnAsync(
|
||||||
new S7Send([sAddress], read, isBit), cancellationToken: cancellationToken).ConfigureAwait(false);
|
new S7Send([sAddress], read, isBit), cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||||
if (!result.IsSuccess|| !read) return result;
|
return result;
|
||||||
|
}
|
||||||
if (read)
|
catch (Exception ex)
|
||||||
byteBlock.Write(result.Content);
|
{
|
||||||
num += len;
|
return new OperResult<byte[]>(ex);
|
||||||
|
}
|
||||||
if (sAddress.DataCode == (byte)S7WordLength.Timer || sAddress.DataCode == (byte)S7WordLength.Counter)
|
finally
|
||||||
{
|
{
|
||||||
sAddress.AddressStart += len / 2;
|
byteBlock.SafeDispose();
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sAddress.AddressStart += len * 8;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new OperResult<byte[]>() { Content = byteBlock.ToArray() };
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
return new OperResult<byte[]>(ex);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
byteBlock.SafeDispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +226,7 @@ public partial class SiemensS7Master : ProtocolBase
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var sAddress = SiemensAddress.ParseFrom(address, length);
|
var sAddress = SiemensAddress.ParseFrom(address, length);
|
||||||
return S7RequestAsync([sAddress], true, false, cancellationToken);
|
return S7RequestAsync([sAddress], true, false, 0,cancellationToken);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -177,7 +241,8 @@ public partial class SiemensS7Master : ProtocolBase
|
|||||||
{
|
{
|
||||||
var sAddress = SiemensAddress.ParseFrom(address);
|
var sAddress = SiemensAddress.ParseFrom(address);
|
||||||
sAddress.Data = value;
|
sAddress.Data = value;
|
||||||
return await S7RequestAsync([sAddress], false, false, cancellationToken);
|
sAddress.Length = value.Length;
|
||||||
|
return await S7RequestAsync([sAddress], false, false, 0,cancellationToken);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -196,7 +261,8 @@ public partial class SiemensS7Master : ProtocolBase
|
|||||||
{
|
{
|
||||||
var sAddress = SiemensAddress.ParseFrom(address);
|
var sAddress = SiemensAddress.ParseFrom(address);
|
||||||
sAddress.Data = value.BoolArrayToByte();
|
sAddress.Data = value.BoolArrayToByte();
|
||||||
return await S7RequestAsync([sAddress], false, true, cancellationToken);
|
sAddress.Length = sAddress.Data.Length;
|
||||||
|
return await S7RequestAsync([sAddress], false, true, value.Length,cancellationToken);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user