refactor: modbus/s7

This commit is contained in:
Diego
2024-06-27 10:43:31 +08:00
parent a0d2922aca
commit 5ba71e8109
7 changed files with 174 additions and 62 deletions

View File

@@ -66,7 +66,7 @@ internal class ModbusRtuSend : ISendMessage
byteBlock.WriteByte(ModbusAddress.Station);
byteBlock.WriteByte((byte)f);
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.Write(ModbusAddress.Data.Span);
}

View File

@@ -80,7 +80,7 @@ internal class ModbusTcpSend : ISendMessage
byteBlock.WriteByte(ModbusAddress.Station);
byteBlock.WriteByte((byte)f);
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.Write(ModbusAddress.Data.Span);
}

View File

@@ -200,8 +200,9 @@ public partial class ModbusMaster : ProtocolBase, IDtu
try
{
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();
return await ModbusRequestAsync(mAddress, false, cancellationToken);
}
@@ -214,12 +215,15 @@ public partial class ModbusMaster : ProtocolBase, IDtu
{
if (mAddress.BitIndex < 16)
{
mAddress.Length = 2;
var readData = await ModbusRequestAsync(mAddress, true, cancellationToken);
if (!readData.IsSuccess) return readData;
var writeData = ThingsGatewayBitConverter.ToUInt16(readData.Content, 0);
ushort mask = (ushort)(1 << mAddress.BitIndex);
ushort result = (ushort)(value[0] ? (writeData | mask) : (writeData & ~mask));
mAddress.Data = ThingsGatewayBitConverter.GetBytes(result);
for (int i = 0; i < value.Length; i++)
{
writeData=writeData.SetBit(mAddress.BitIndex.Value + i, value[i]);
}
mAddress.Data = ThingsGatewayBitConverter.GetBytes(writeData);
return await ModbusRequestAsync(mAddress, false, cancellationToken);
}
else

View File

@@ -512,6 +512,7 @@ public class ModbusSlave : ProtocolBase, ITcpService, IDtuClient
ModbusServer04ByteBlock.Write(mAddress.Data.Span);
return new();
case 3:
case 6:
case 16:
ModbusServer03ByteBlock.Position = mAddress.StartAddress * this.RegisterByteLength;
@@ -546,34 +547,66 @@ public class ModbusSlave : ProtocolBase, ITcpService, IDtuClient
}
/// <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);
mAddress.Data = value;
var result = ModbusRequest(mAddress, false, cancellationToken);
if (result.IsSuccess)
try
{
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/>
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);
mAddress.Data = value.BoolArrayToByte();
var result = ModbusRequest(mAddress, false, cancellationToken);
if (result.IsSuccess)
try
{
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);
}
}

View File

@@ -168,6 +168,14 @@ internal class S7Message : MessageBase, IResultMessage
}
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)
{
this.OperCode = 999;

View File

@@ -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;
byte len = (byte)data.Length;
byte len = (byte)address.Length;
bool isBit = (IsBit && len == 1);
ushort telegramLen = (ushort)(16 + 19 + len);
ushort parameterLen = 12 + 2;
//TPKT
@@ -181,7 +182,7 @@ internal class S7Send : ISendMessage
}
else
{
GetWriteByteCommand(ref byteBlock, SiemensAddress[0], IsBit);
GetWriteByteCommand(ref byteBlock, SiemensAddress[0]);
}
}
}

View File

@@ -108,49 +108,113 @@ public partial class SiemensS7Master : ProtocolBase
/// <summary>
/// 此方法并不会智能分组以最大化效率减少传输次数因为返回值是byte[],所以一切都按地址数组的顺序执行,最后合并数组
/// </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);
try
if (read)
{
foreach (var sAddress in sAddresss)
var byteBlock = new ValueByteBlock(2048);
try
{
int num = 0;
var addressLen = sAddress.Length==0?1: sAddress.Length;
while (num < addressLen)
foreach (var sAddress in sAddresss)
{
//pdu长度重复生成报文直至全部生成
int len = Math.Min(addressLen - num, PduLength);
sAddress.Length = len;
int num = 0;
var addressLen = sAddress.Length == 0 ? 1 : sAddress.Length;
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(
new S7Send([sAddress], read, isBit), cancellationToken: cancellationToken).ConfigureAwait(false);
if (!result.IsSuccess|| !read) return result;
if (read)
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 result;
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
finally
{
byteBlock.SafeDispose();
}
}
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
{
var sAddress = SiemensAddress.ParseFrom(address, length);
return S7RequestAsync([sAddress], true, false, cancellationToken);
return S7RequestAsync([sAddress], true, false, 0,cancellationToken);
}
catch (Exception ex)
{
@@ -177,7 +241,8 @@ public partial class SiemensS7Master : ProtocolBase
{
var sAddress = SiemensAddress.ParseFrom(address);
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)
{
@@ -196,7 +261,8 @@ public partial class SiemensS7Master : ProtocolBase
{
var sAddress = SiemensAddress.ParseFrom(address);
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)
{