Skip to content

Commit

Permalink
DataItem使用的类型并不是VarType,而是0x03和0x04;
Browse files Browse the repository at this point in the history
西门子PLC的DBD和DBX点位控制测试通过
  • Loading branch information
nnhy committed Jan 10, 2024
1 parent 5c1543d commit 35c8d1d
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 96 deletions.
23 changes: 16 additions & 7 deletions NewLife.Siemens/Messages/DataItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ public class DataItem
/// <summary>错误码。0xFF表示成功,写入请求时置零</summary>
public ReadWriteErrorCode Code { get; set; }

/// <summary>变量类型</summary>
public VarType Type { get; set; }
/// <summary>传输数据类型。按字为04,按位为03</summary>
public Byte TransportSize { get; set; }

/// <summary>数据</summary>
public Byte[]? Data { get; set; }
Expand All @@ -21,7 +21,7 @@ public class DataItem
#region 构造函数
/// <summary>已重载。</summary>
/// <returns></returns>
public override String ToString() => Type > 0 ? $"{Type}({Data.ToHex()})" : $"{Code}";
public override String ToString() => TransportSize > 0 ? $"{TransportSize}({Data.ToHex()})" : $"{Code}";
#endregion

#region 方法
Expand All @@ -36,9 +36,13 @@ public void Read(Binary reader)
// WriteResponse中只有Code
if (reader.EndOfStream()) return;

Type = (VarType)reader.ReadByte();
var b = reader.ReadByte();
TransportSize = b;

var len = reader.ReadUInt16();
// BIT=0x03 / Byte/Word/DWord=0x04
if (b == 0x04) len /= 8;

var len = reader.ReadUInt16() / 8;
Data = reader.ReadBytes(len);
}

Expand All @@ -47,10 +51,15 @@ public void Read(Binary reader)
public void Writer(Binary writer)
{
writer.WriteByte((Byte)Code);
writer.WriteByte((Byte)Type);
writer.WriteByte((Byte)TransportSize);

var len = Data?.Length ?? 0;
writer.WriteUInt16((UInt16)(len * 8));

// BIT=0x03 / Byte/Word/DWord=0x04
var b = (Byte)TransportSize;
if (b == 0x04) len *= 8;

writer.WriteUInt16((UInt16)len);

if (Data != null) writer.Write(Data, 0, Data.Length);
}
Expand Down
10 changes: 5 additions & 5 deletions NewLife.Siemens/Messages/RequestItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ public class RequestItem
/// <summary>寻址模式。任意类型S7ANY用0x10</summary>
public Byte SyntaxId { get; set; }

/// <summary>变量类型</summary>
public VarType Type { get; set; }
/// <summary>传输数据类型。按字为02,按位为01</summary>
public Byte TransportSize { get; set; }

/// <summary>个数</summary>
public UInt16 Count { get; set; }
Expand All @@ -33,7 +33,7 @@ public class RequestItem
#region 构造函数
/// <summary>已重载。</summary>
/// <returns></returns>
public override String ToString() => $"{Type}({Area}:{DbNumber}:{Address}, {Count})";
public override String ToString() => $"{(TransportSize > 1 ? "BYTE" : "BIT")}({Area}:{DbNumber}:{Address}, {Count})";
#endregion

#region 方法
Expand All @@ -46,7 +46,7 @@ public void Read(Binary reader)
var len = reader.ReadByte();

SyntaxId = reader.ReadByte();
Type = (VarType)reader.ReadByte();
TransportSize = reader.ReadByte();
Count = reader.ReadUInt16();
DbNumber = reader.ReadUInt16();
Area = (DataType)reader.ReadByte();
Expand All @@ -66,7 +66,7 @@ public void Writer(Binary writer)
var len = 1 + 1 + 2 + 2 + 1 + 3;
writer.WriteByte((Byte)len);
writer.WriteByte(SyntaxId);
writer.WriteByte((Byte)Type);
writer.WriteByte(TransportSize);
writer.Write(Count);
writer.Write(DbNumber);
writer.WriteByte((Byte)Area);
Expand Down
7 changes: 4 additions & 3 deletions NewLife.Siemens/NewLife.Siemens.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,16 @@
</PropertyGroup>

<ItemGroup>
<Compile Remove="Common\**" />
<Compile Remove="Types\**" />
<EmbeddedResource Remove="Common\**" />
<EmbeddedResource Remove="Types\**" />
<None Remove="Common\**" />
<None Remove="Types\**" />
</ItemGroup>

<ItemGroup>
<Compile Remove="Common\Conversion.cs" />
<Compile Remove="Common\PLCHelpers.cs" />
<Compile Remove="Common\StreamExtensions.cs" />
<Compile Remove="Protocols\DataItemAddress.cs" />
</ItemGroup>

<ItemGroup>
Expand Down
5 changes: 2 additions & 3 deletions NewLife.Siemens/Protocols/COTP.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using NewLife.Data;
using NewLife.Serialization;
using NewLife.Siemens.Common;

namespace NewLife.Siemens.Protocols;

Expand Down Expand Up @@ -260,10 +259,10 @@ public void SetParameter(COTPParameter parameter)
public static async Task<COTP> ReadAsync(Stream stream, CancellationToken cancellationToken)
{
var data = await TPKT.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
if (data.Length == 0) throw new TPDUInvalidException("No protocol data received");
if (data.Length == 0) throw new InvalidDataException("No protocol data received");

var cotp = new COTP();
if (!cotp.Read(data)) throw new TPDUInvalidException("Invalid protocol data received");
if (!cotp.Read(data)) throw new InvalidDataException("Invalid protocol data received");

return cotp;
}
Expand Down
52 changes: 20 additions & 32 deletions NewLife.Siemens/Protocols/PLCAddress.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System.Net;
using NewLife.Siemens.Common;
using NewLife.Siemens.Models;
using NewLife.Siemens.Models;

namespace NewLife.Siemens.Protocols;

Expand Down Expand Up @@ -42,7 +40,6 @@ public PLCAddress(String address)
/// <param name="varType"></param>
/// <param name="address"></param>
/// <param name="bitNumber"></param>
/// <exception cref="InvalidAddressException"></exception>
public static void Parse(String input, out DataType dataType, out Int32 dbNumber, out VarType varType, out Int32 address, out Int32 bitNumber)
{
bitNumber = -1;
Expand All @@ -53,11 +50,11 @@ public static void Parse(String input, out DataType dataType, out Int32 dbNumber
case "DB":
var strings = input.Split(['.']);
if (strings.Length < 2)
throw new InvalidAddressException("To few periods for DB address");
throw new InvalidDataException("To few periods for DB address");

dataType = DataType.DataBlock;
dbNumber = Int32.Parse(strings[0][2..]);
address = GetAddress(strings[1][3..]);
address = Int32.Parse(strings[1][3..]);

var dbType = strings[1][..3];
switch (dbType)
Expand All @@ -74,34 +71,34 @@ public static void Parse(String input, out DataType dataType, out Int32 dbNumber
case "DBX":
bitNumber = Int32.Parse(strings[2]);
if (bitNumber > 7)
throw new InvalidAddressException("Bit can only be 0-7");
throw new InvalidDataException("Bit can only be 0-7");
varType = VarType.Bit;
return;
default:
throw new InvalidAddressException();
throw new InvalidDataException();
}
case "IB":
case "EB":
// Input byte
dataType = DataType.Input;
dbNumber = 0;
address = GetAddress(input[2..]);
address = Int32.Parse(input[2..]);
varType = VarType.Byte;
return;
case "IW":
case "EW":
// Input word
dataType = DataType.Input;
dbNumber = 0;
address = GetAddress(input[2..]);
address = Int32.Parse(input[2..]);
varType = VarType.Word;
return;
case "ID":
case "ED":
// Input double-word
dataType = DataType.Input;
dbNumber = 0;
address = GetAddress(input[2..]);
address = Int32.Parse(input[2..]);
varType = VarType.DWord;
return;
case "QB":
Expand All @@ -110,7 +107,7 @@ public static void Parse(String input, out DataType dataType, out Int32 dbNumber
// Output byte
dataType = DataType.Output;
dbNumber = 0;
address = GetAddress(input[2..]);
address = Int32.Parse(input[2..]);
varType = VarType.Byte;
return;
case "QW":
Expand All @@ -119,7 +116,7 @@ public static void Parse(String input, out DataType dataType, out Int32 dbNumber
// Output word
dataType = DataType.Output;
dbNumber = 0;
address = GetAddress(input[2..]);
address = Int32.Parse(input[2..]);
varType = VarType.Word;
return;
case "QD":
Expand All @@ -128,28 +125,28 @@ public static void Parse(String input, out DataType dataType, out Int32 dbNumber
// Output double-word
dataType = DataType.Output;
dbNumber = 0;
address = GetAddress(input[2..]);
address = Int32.Parse(input[2..]);
varType = VarType.DWord;
return;
case "MB":
// Memory byte
dataType = DataType.Memory;
dbNumber = 0;
address = GetAddress(input[2..]);
address = Int32.Parse(input[2..]);
varType = VarType.Byte;
return;
case "MW":
// Memory word
dataType = DataType.Memory;
dbNumber = 0;
address = GetAddress(input[2..]);
address = Int32.Parse(input[2..]);
varType = VarType.Word;
return;
case "MD":
// Memory double-word
dataType = DataType.Memory;
dbNumber = 0;
address = GetAddress(input[2..]);
address = Int32.Parse(input[2..]);
varType = VarType.DWord;
return;
default:
Expand Down Expand Up @@ -177,40 +174,31 @@ public static void Parse(String input, out DataType dataType, out Int32 dbNumber
// Timer
dataType = DataType.Timer;
dbNumber = 0;
address = GetAddress(input[1..]);
address = Int32.Parse(input[1..]);
varType = VarType.Timer;
return;
case "Z":
case "C":
// Counter
dataType = DataType.Counter;
dbNumber = 0;
address = GetAddress(input[1..]);
address = Int32.Parse(input[1..]);
varType = VarType.Counter;
return;
default:
throw new InvalidAddressException(String.Format("{0} is not a valid address", input[..1]));
throw new InvalidDataException(String.Format("{0} is not a valid address", input[..1]));
}

var txt2 = input[1..];
if (txt2.IndexOf(".") == -1)
throw new InvalidAddressException("To few periods for DB address");
throw new InvalidDataException("To few periods for DB address");

address = GetAddress(txt2[..txt2.IndexOf(".")]);
address = Int32.Parse(txt2[..txt2.IndexOf(".")]);
bitNumber = Int32.Parse(txt2[(txt2.IndexOf(".") + 1)..]);
if (bitNumber > 7)
throw new InvalidAddressException("Bit can only be 0-7");
throw new InvalidDataException("Bit can only be 0-7");

return;
}
}

static Int32 GetAddress(String value)
{
var addrs = value.SplitAsInt();
if (addrs.Length > 1)
return addrs[0] * 8 + addrs[1];
else
return addrs[0] * 8;
}
}
30 changes: 12 additions & 18 deletions NewLife.Siemens/Protocols/S7Client.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using System.Net.Sockets;
using NewLife.Data;
using NewLife.Log;
using NewLife.Remoting;
using NewLife.Siemens.Common;
using NewLife.Siemens.Messages;
using NewLife.Siemens.Models;

Expand Down Expand Up @@ -225,7 +223,7 @@ private async Task<COTP> RequestAsync(Stream stream, COTP request, CancellationT
}
catch (Exception exc)
{
if (exc is TPDUInvalidException || exc is TPKTInvalidException)
if (exc is InvalidDataException)
{
Close();
}
Expand All @@ -249,7 +247,9 @@ public Byte[] ReadBytes(PLCAddress address, Int32 count)
// 最大PDU大小
var maxToRead = Math.Min(count, MaxPDUSize - 18);

var request = BuildRead(address.DataType, address.DbNumber, address.VarType, address.StartByte + index, maxToRead);
var addr = (address.StartByte + index) * 8;
if (address.BitNumber > 0) addr += address.BitNumber;
var request = BuildRead(address.DataType, address.DbNumber, address.VarType, addr, maxToRead);

// 发起请求
var rs = InvokeAsync(request).ConfigureAwait(false).GetAwaiter().GetResult();
Expand All @@ -273,26 +273,18 @@ public Byte[] ReadBytes(PLCAddress address, Int32 count)
return ms.ToArray();
}

private static ReadRequest BuildRead(DataType dataType, Int32 db, VarType varType, Int32 startByteAdr, Int32 count)
private static ReadRequest BuildRead(DataType dataType, Int32 db, VarType varType, Int32 address, Int32 count)
{
var ri = new RequestItem
{
// S7ANY
SyntaxId = 0x10,
// BIT
Type = VarType.Byte,
TransportSize = (Byte)(varType == VarType.Bit ? 1 : 2),
Count = (UInt16)count,
DbNumber = (UInt16)db,
Area = dataType,

Address = (UInt32)startByteAdr,
};

ri.Type = dataType switch
{
DataType.Timer => VarType.Timer,
DataType.Counter => VarType.Counter,
_ => VarType.Byte,
Address = (UInt32)address,
};

var request = new ReadRequest();
Expand All @@ -314,7 +306,9 @@ public void WriteBytes(PLCAddress address, Byte[] value)
{
var pdu = Math.Min(count, MaxPDUSize - 28);

var request = BuildWrite(address.DataType, address.DbNumber, address.VarType, address.StartByte + index, value, index, pdu);
var addr = (address.StartByte + index) * 8;
if (address.BitNumber > 0) addr += address.BitNumber;
var request = BuildWrite(address.DataType, address.DbNumber, address.VarType, addr, value, index, pdu);

// 发起请求
var rs = InvokeAsync(request).ConfigureAwait(false).GetAwaiter().GetResult();
Expand All @@ -338,15 +332,15 @@ private WriteRequest BuildWrite(DataType dataType, Int32 db, VarType varType, In
{
SpecType = 0x12,
SyntaxId = 0x10,
Type = VarType.Byte,
TransportSize = (Byte)(varType == VarType.Bit ? 1 : 2),
Count = (UInt16)count,
DbNumber = (UInt16)db,
Area = dataType,
Address = (UInt32)address
});
request.DataItems.Add(new DataItem
{
Type = VarType.DWord,
TransportSize = (Byte)(varType == VarType.Bit ? 0x03 : 0x04),
Data = value.ReadBytes(offset, count),
});

Expand Down
Loading

0 comments on commit 35c8d1d

Please sign in to comment.