refactor: modbus/s7
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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)
|
||||
{
|
||||
|
Reference in New Issue
Block a user