using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;
namespace Modbus.Net.Siemens
{
///
/// 西门子协议类型
///
public enum SiemensType
{
///
/// PPI
///
Ppi = 0,
#pragma warning disable
///
/// MPI
///
//Mpi = 1,
#pragma warning restore
///
/// 以太网
///
Tcp = 2
}
///
/// 西门子设备类型
///
public enum SiemensMachineModel
{
///
/// S7-200
///
S7_200 = 0,
///
/// S7-200 Smart
///
S7_200_Smart = 1,
///
/// S7-300
///
S7_300 = 2,
///
/// S7-400
///
S7_400 = 3,
///
/// S7-1200
///
S7_1200 = 4,
///
/// S7-1500
///
S7_1500 = 5
}
///
/// 西门子通讯Api入口
///
public class SiemensUtility : BaseUtility, PipeUnit>
{
private static readonly ILogger logger = LogProvider.CreateLogger();
private readonly ushort _maxCalled;
private readonly ushort _maxCalling;
private readonly ushort _maxPdu;
private readonly ushort _taspSrc;
private readonly byte _tdpuSize;
private readonly ushort _tsapDst;
private ushort _sendCount;
private readonly object _counterLock = new object();
private SiemensType _siemensType;
///
/// 构造函数
///
/// 连接类型
/// 连接字符串
/// 设备类型
/// 从站地址
/// 主站地址
/// 本机模块位,0到7,200为本地栈号,比如10.01则填写0x01
/// PLC模块位,0到7,200为远程栈号,比如10.02则填写0x02
/// 300和400为槽号机架号,机架号为1,比如槽号为3,则填写0x13
public SiemensUtility(SiemensType connectionType, string connectionString, SiemensMachineModel model,
byte slaveAddress, byte masterAddress, byte src = 0, byte dst = 1) : base(slaveAddress, masterAddress)
{
ConnectionString = connectionString;
switch (model)
{
case SiemensMachineModel.S7_200:
{
_tdpuSize = 0x09;
_taspSrc = (ushort)(0x1000 + src);
_tsapDst = (ushort)(0x1000 + dst);
_maxCalling = 0x0001;
_maxCalled = 0x0001;
_maxPdu = 0x03c0;
break;
}
case SiemensMachineModel.S7_300:
case SiemensMachineModel.S7_400:
{
_tdpuSize = 0x1a;
_taspSrc = 0x4b54;
_tsapDst = (ushort)(0x0300 + dst);
_maxCalling = 0x0001;
_maxCalled = 0x0001;
_maxPdu = 0x00f0;
break;
}
case SiemensMachineModel.S7_1200:
case SiemensMachineModel.S7_1500:
{
_tdpuSize = 0x0a;
_taspSrc = 0x1011;
_tsapDst = (ushort)(0x0300 + dst);
_maxCalling = 0x0003;
_maxCalled = 0x0003;
_maxPdu = 0x0100;
break;
}
case SiemensMachineModel.S7_200_Smart:
{
_tdpuSize = 0x0a;
_taspSrc = 0x0101;
_tsapDst = 0x0101;
_maxCalling = 0x0001;
_maxCalled = 0x0001;
_maxPdu = 0x03c0;
break;
}
default:
{
throw new NotImplementedException("Siemens PLC Model not Supported");
}
}
ConnectionType = connectionType;
AddressTranslator = new AddressTranslatorSiemens();
_sendCount = 0;
}
///
/// 端格式
///
public override Endian Endian => Endian.BigEndianLsb;
///
/// IP地址
///
protected string ConnectionStringIp
{
get
{
if (ConnectionString == null) return null;
return ConnectionString.Contains(":") ? ConnectionString.Split(':')[0] : ConnectionString;
}
}
///
/// 端口
///
protected int? ConnectionStringPort
{
get
{
if (ConnectionString == null) return null;
if (!ConnectionString.Contains(":")) return null;
var connectionStringSplit = ConnectionString.Split(':');
try
{
return connectionStringSplit.Length < 2 ? (int?)null : int.Parse(connectionStringSplit[1]);
}
catch (Exception e)
{
logger.LogError(e, $"SiemensUtility: {ConnectionString} format error");
return null;
}
}
}
///
/// 西门子连接类型
///
public SiemensType ConnectionType
{
get { return _siemensType; }
set
{
_siemensType = value;
switch (_siemensType)
{
//PPI
case SiemensType.Ppi:
{
Wrapper = ConnectionString == null
? new SiemensPpiProtocol(SlaveAddress, MasterAddress)
: new SiemensPpiProtocol(ConnectionString, SlaveAddress, MasterAddress);
break;
}
//MPI
//case SiemensType.Mpi:
//{
//throw new NotImplementedException();
//}
//Ethenet
case SiemensType.Tcp:
{
Wrapper = ConnectionString == null
? new SiemensTcpProtocol(_tdpuSize, _taspSrc, _tsapDst, _maxCalling, _maxCalled, _maxPdu)
: (ConnectionStringPort == null
? new SiemensTcpProtocol(_tdpuSize, _taspSrc, _tsapDst, _maxCalling, _maxCalled, _maxPdu,
ConnectionString)
: new SiemensTcpProtocol(_tdpuSize, _taspSrc, _tsapDst, _maxCalling, _maxCalled, _maxPdu,
ConnectionStringIp, ConnectionStringPort.Value));
break;
}
}
}
}
///
/// 设置连接类型
///
/// 需要设置的连接类型
public override void SetConnectionType(int connectionType)
{
ConnectionType = (SiemensType)connectionType;
}
///
/// 读数据
///
/// 开始地址
/// 读取字节个数
/// 读取原始个数
/// 从设备中读取的数据
public override async Task> GetDatasAsync(string startAddress, int getByteCount, int getOriginalCount)
{
try
{
ReadRequestSiemensInputStruct readRequestSiemensInputStruct;
lock (_counterLock)
{
_sendCount = (ushort)(_sendCount % ushort.MaxValue + 1);
readRequestSiemensInputStruct = new ReadRequestSiemensInputStruct(SlaveAddress, MasterAddress,
_sendCount, SiemensTypeCode.Byte, startAddress, (ushort)getByteCount, AddressTranslator);
}
var readRequestSiemensOutputStruct =
await
Wrapper.SendReceiveAsync(
Wrapper[typeof(ReadRequestSiemensProtocol)],
readRequestSiemensInputStruct);
return new ReturnStruct
{
Datas = readRequestSiemensOutputStruct?.GetValue,
IsSuccess = true,
ErrorCode = 0,
ErrorMsg = ""
};
}
catch (SiemensProtocolErrorException e)
{
logger.LogError(e, $"SiemensUtility -> GetDatas: {ConnectionString} error: {e.Message}");
return new ReturnStruct
{
Datas = null,
IsSuccess = false,
ErrorCode = e.ErrorCode,
ErrorMsg = e.Message
};
}
catch (FormatException e)
{
logger.LogError(e, $"SiemensUtility -> GetDatas: {ConnectionString} error: {e.Message}");
return new ReturnStruct
{
Datas = null,
IsSuccess = false,
ErrorCode = -1,
ErrorMsg = e.Message
};
}
}
///
/// 写数据
///
/// 开始地址
/// 需要写入的数据
/// 写入数据的原始长度
/// 写入是否成功
public override async Task> SetDatasAsync(string startAddress, object[] setContents, int setOriginalCount)
{
try
{
WriteRequestSiemensInputStruct writeRequestSiemensInputStruct;
lock (_counterLock)
{
_sendCount = (ushort)(_sendCount % ushort.MaxValue + 1);
writeRequestSiemensInputStruct = new WriteRequestSiemensInputStruct(SlaveAddress, MasterAddress,
_sendCount, startAddress, setContents, AddressTranslator);
}
var writeRequestSiemensOutputStruct =
await
Wrapper.SendReceiveAsync(
Wrapper[typeof(WriteRequestSiemensProtocol)],
writeRequestSiemensInputStruct);
return new ReturnStruct
{
Datas = writeRequestSiemensOutputStruct?.AccessResult == SiemensAccessResult.NoError,
IsSuccess = writeRequestSiemensOutputStruct?.AccessResult == SiemensAccessResult.NoError,
ErrorCode = writeRequestSiemensOutputStruct?.AccessResult == SiemensAccessResult.NoError ? 0 : (int)writeRequestSiemensOutputStruct?.AccessResult,
ErrorMsg = writeRequestSiemensOutputStruct?.AccessResult.ToString()
};
}
catch (SiemensProtocolErrorException e)
{
logger.LogError(e, $"ModbusUtility -> SetDatas: {ConnectionString} error: {e.Message}");
return new ReturnStruct
{
Datas = false,
IsSuccess = false,
ErrorCode = e.ErrorCode,
ErrorMsg = e.Message
};
}
catch (FormatException e)
{
logger.LogError(e, $"SiemensUtility -> GetDatas: {ConnectionString} error: {e.Message}");
return new ReturnStruct
{
Datas = false,
IsSuccess = false,
ErrorCode = -1,
ErrorMsg = e.Message
};
}
}
}
}