Skip to content

Commit

Permalink
读写数据前后,根据物模型编解码点位数据
Browse files Browse the repository at this point in the history
  • Loading branch information
nnhy committed Dec 19, 2023
1 parent 4dc24e7 commit 1b5fd3e
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 196 deletions.
35 changes: 22 additions & 13 deletions NewLife.Siemens/Drivers/SiemensS7Driver.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
using System.ComponentModel;
using System.Runtime.CompilerServices;
using NewLife.IoT;
using NewLife.IoT.Drivers;
using NewLife.IoT.ThingModels;
using NewLife.Log;
using NewLife.Omron.Drivers;
using NewLife.Serialization;
using NewLife.Siemens.Models;
using NewLife.Siemens.Protocols;

Expand All @@ -28,7 +25,12 @@ public class SiemensS7Driver : DriverBase
/// 销毁时,关闭连接
/// </summary>
/// <param name="disposing"></param>
protected override void Dispose(Boolean disposing) => base.Dispose(disposing);
protected override void Dispose(Boolean disposing)
{
base.Dispose(disposing);

_plcConn.TryDispose();
}
#endregion

#region 方法
Expand All @@ -39,6 +41,7 @@ public class SiemensS7Driver : DriverBase
protected override IDriverParameter OnCreateParameter() => new SiemensParameter
{
Address = "127.0.0.1:102",
CpuType = CpuType.S7200Smart,
Rack = 0,
Slot = 0,
};
Expand All @@ -57,7 +60,7 @@ public override INode Open(IDevice device, IDriverParameter parameter)
if (address.IsNullOrEmpty()) throw new ArgumentException("参数中未指定地址address");

//var p = address.IndexOfAny(new[] { ':', '.' }); // p为3,最后截取不到正确ip
var p = address.IndexOfAny(new[] { ':' });
var p = address.IndexOfAny([':']);
if (p < 0) throw new ArgumentException($"参数中地址address格式错误:{address}");

var cpuType = pm.CpuType;
Expand Down Expand Up @@ -130,6 +133,7 @@ public override IDictionary<String, Object> Read(INode node, IPoint[] points)

if (points == null || points.Length == 0) return dic;

var spec = node.Device?.Specification;
foreach (var point in points)
{
var addr = GetAddress(point);
Expand All @@ -150,7 +154,12 @@ public override IDictionary<String, Object> Read(INode node, IPoint[] points)

var data = _plcConn.ReadBytes(dataType, db, startByteAdr, (UInt16)point.Length);

dic[point.Name] = data;
// 借助物模型转换数据类型
var v = spec?.DecodeByThingModel(data, point);
if (v != null)
dic[point.Name] = v;
else
dic[point.Name] = data;
}

return dic;
Expand Down Expand Up @@ -181,20 +190,22 @@ public virtual String GetAddress(IPoint point)
/// <param name="value">数值</param>
public override Object Write(INode node, IPoint point, Object value)
{
using var span = Tracer?.NewSpan("write_value", new { point, value });

var addr = GetAddress(point);
if (addr.IsNullOrWhiteSpace()) return null;

span.AppendTag($"addr:{addr}");
// 借助物模型转换数据类型
var spec = node.Device?.Specification;
if (spec != null && value is not Byte[])
{
// 普通数值转为字节数组
value = spec.EncodeByThingModel(value, point);
}

// 操作字节数组,不用设置bitNumber,但是解析需要带上
if (addr.IndexOf('.') == -1) addr += ".0";

var plc_adr = new PLCAddress(addr);

span.AppendTag($"plc_addr:{plc_adr}");

var dataType = plc_adr.DataType;
var db = plc_adr.DbNumber;
var startByteAdr = plc_adr.StartByte;
Expand Down Expand Up @@ -222,8 +233,6 @@ public override Object Write(INode node, IPoint point, Object value)
};
}

span.AppendTag($"转换完成bytes:{bytes.ToHex()}");

_plcConn.WriteBytes(dataType, db, startByteAdr, bytes);

return null;
Expand Down
26 changes: 7 additions & 19 deletions NewLife.Siemens/Protocols/COTP.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public enum PduType : Byte
Data = 0xf0,
ConnectionConfirmed = 0xd0
}

/// <summary>
/// Describes a COTP TPDU (Transport protocol data unit)
/// </summary>
Expand Down Expand Up @@ -48,28 +49,17 @@ public TPDU(TPKT tPKT)
/// See: https://tools.ietf.org/html/rfc905
/// </summary>
/// <param name="stream">The socket to read from</param>
/// <param name="cancellationToken"></param>
/// <returns>COTP DPDU instance</returns>
public static async Task<TPDU> ReadAsync(Stream stream, CancellationToken cancellationToken)
{
var tpkt = await TPKT.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
if (tpkt.Length == 0)
{
throw new TPDUInvalidException("No protocol data received");
}
return new TPDU(tpkt);
}
if (tpkt.Length == 0) throw new TPDUInvalidException("No protocol data received");

public override String ToString()
{
return String.Format("Length: {0} PDUType: {1} TPDUNumber: {2} Last: {3} Segment Data: {4}",
HeaderLength,
PDUType,
TPDUNumber,
LastDataUnit,
BitConverter.ToString(Data)
);
return new TPDU(tpkt);
}

public override String ToString() => $"Length: {HeaderLength} PDUType: {PDUType} TPDUNumber: {TPDUNumber} Last: {LastDataUnit} Segment Data: {BitConverter.ToString(Data)}";
}

/// <summary>
Expand All @@ -82,15 +72,13 @@ public class TSDU
/// See: https://tools.ietf.org/html/rfc905
/// </summary>
/// <param name="stream">The stream to read from</param>
/// <param name="cancellationToken"></param>
/// <returns>Data in TSDU</returns>
public static async Task<Byte[]> ReadAsync(Stream stream, CancellationToken cancellationToken)
{
var segment = await TPDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false);

if (segment.LastDataUnit)
{
return segment.Data;
}
if (segment.LastDataUnit) return segment.Data;

// More segments are expected, prepare a buffer to store all data
var buffer = new Byte[segment.Data.Length];
Expand Down
19 changes: 5 additions & 14 deletions NewLife.Siemens/Protocols/DataItemAddress.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,25 @@ namespace NewLife.Siemens.Protocols;
/// <summary>
/// Represents an area of memory in the PLC
/// </summary>
internal class DataItemAddress
internal class DataItemAddress(DataType dataType, Int32 db, Int32 startByteAddress, Int32 byteLength)
{
public DataItemAddress(DataType dataType, Int32 db, Int32 startByteAddress, Int32 byteLength)
{
DataType = dataType;
DB = db;
StartByteAddress = startByteAddress;
ByteLength = byteLength;
}


/// <summary>
/// Memory area to read
/// </summary>
public DataType DataType { get; }
public DataType DataType { get; } = dataType;

/// <summary>
/// Address of memory area to read (example: for DB1 this value is 1, for T45 this value is 45)
/// </summary>
public Int32 DB { get; }
public Int32 DB { get; } = db;

/// <summary>
/// Address of the first byte to read
/// </summary>
public Int32 StartByteAddress { get; }
public Int32 StartByteAddress { get; } = startByteAddress;

/// <summary>
/// Length of data to read
/// </summary>
public Int32 ByteLength { get; }
public Int32 ByteLength { get; } = byteLength;
}
2 changes: 1 addition & 1 deletion NewLife.Siemens/Protocols/PLCAddress.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static void Parse(String input, out DataType dataType, out Int32 dbNumber
switch (input[..2])
{
case "DB":
var strings = input.Split(new Char[] { '.' });
var strings = input.Split(['.']);
if (strings.Length < 2)
throw new InvalidAddressException("To few periods for DB address");

Expand Down
Loading

0 comments on commit 1b5fd3e

Please sign in to comment.