using System;
using System.Collections.Generic;
using S7.Net;
using Newtonsoft.Json.Linq;
using ProjectBase.Data.Logs;
using ProjectBase.Data.Redis;
using ProjectBase.Data.BaseDAL;
using SIMDP.BLL;
using SIMDP.Model;
using ProjectBase.Util;
using System.Timers;
using System.Reflection;
namespace SIMDP.Device
{
public class PlcS7Net : AbstractBaseDevice
{
#region 数据定义
///
/// PLC对象
///
protected Plc S7Plc;
///
/// 数据节点字典 key-变量名称, value-节点信息
///
protected Dictionary allPoints = new Dictionary();
///
/// 监控节点列表
///
protected List monitorPoints = new List();
#endregion
#region TYPE定义
public class S7NetPlcConfig
{
public S7NetPlcConfig(string json)
{
JObject jObject = JObject.Parse(json);
CPU = getCpuTypeByName((string)jObject["CPU"]);
JToken token = jObject["IP"];
if (token != null)
IP = (string)token;
token = jObject["Rack"];
if (token != null)
RACK = (short)token;
token = jObject["Slot"];
if (token != null)
SLOT = (short)token;
token = jObject["Timer"];
if (token != null)
TIMER = Convert.ToDouble(token.ToString());
}
public CpuType CPU { get; set; }
public string IP { get; set; } = "192.168.0.1";
public short RACK { get; set; } = 0;
public short SLOT { get; set; } = 1;
public double TIMER { get; set; } = 1000;
CpuType getCpuTypeByName(string cpuName)
{
if (cpuName.Contains("1200"))
return CpuType.S71200;
else if (cpuName.Contains("1500"))
return CpuType.S71500;
else if (cpuName.Contains("200"))
return CpuType.S7200;
else if (cpuName.Contains("300"))
return CpuType.S7300;
else if (cpuName.Contains("400"))
return CpuType.S7400;
else
return CpuType.S71500; // 默认为1500
}
}
public class S7NetDataPointInfo
{
// 节点配置信息
public MoDataPoint mo;
// 节点属性
public short DB { get; set; }
public short ADDR { get; set; }
public VarType TYPE { get; set; }
public byte BIT { get; set; } = 0;
// 节点值及动作定义
public object value = null;
public MethodInfo proc = null;
public S7NetDataPointInfo(MoDataPoint _mo)
{
mo = _mo;
JObject jObject = JObject.Parse(mo.DataPointSource);
DB = Convert.ToInt16((string)jObject["DB"]);
ADDR = Convert.ToInt16((string)jObject["ADDR"]);
TYPE = getVarTypeByDataPointType(mo.DataPointType);
JToken token = jObject["BIT"];
if (token != null)
BIT = Convert.ToByte(token.ToString());
}
VarType getVarTypeByDataPointType(long type)
{
if (type == 1)
return VarType.Bit;
else if (type == 2)
return VarType.Byte;
else if (type == 3)
return VarType.Int;
else if (type == 4)
return VarType.Word;
else if (type == 5)
return VarType.DInt;
else if (type == 6)
return VarType.DWord;
else if (type == 7)
return VarType.Real;
else if (type == 9)
return VarType.String;
else
return VarType.Bit;
}
}
#endregion
#region 接口实现
public override void Start(MoPlcInfo _plcInfo, List _dataPoints)
{
plcInfo = _plcInfo;
S7NetPlcConfig plcConfig = new S7NetPlcConfig(plcInfo.LinkConfig);
S7Plc = new Plc(plcConfig.CPU, plcConfig.IP, plcConfig.RACK, plcConfig.SLOT);
timer.Interval = plcConfig.TIMER;
timer.Elapsed += timer_Elapsed;
timer.AutoReset = false;
// PLC未连接状态
SetRedisPlcDisConnect();
// 创建PLC数据点表
CreateDataPointList(_dataPoints);
// 初始化自定义函数
actionStart();
// 启动时尝试连接一次设备
Connect();
// 启动定时器
timerStopped = false;
timer.Start();
}
public override bool isConnected()
{
return S7Plc.IsConnected;
}
protected override bool Connect()
{
S7Plc.Open();
SetRedisPlcConnected();
LogHelper.log.Info("已连接到PLC:" + S7Plc.IP);
return isConnected();
}
protected override void Disconnect()
{
if (S7Plc != null)
S7Plc.Close();
SetRedisPlcDisConnect();
}
void CreateDataPointList(List dataPoints)
{
if (redis == null)
redis = new RedisHelper();
Type t = this.GetType();
foreach (MoDataPoint dataPoint in dataPoints)
{
S7NetDataPointInfo dataPointInfo = new S7NetDataPointInfo(dataPoint);
allPoints.Add(dataPoint.DataPointName, dataPointInfo);
redis.SetString(dataPoint.DataPointId.ToString() + dataPoint.DataPointName, "");
//if (BLLFactory.Instance.IsSignalGroupById(dataPoint.DataPointGroupId))
// 不再按照信号组类型区分是否为监控节点,只按照是否有执行逻辑
if (dataPoint.DataProc.Trim() != "")
{
dataPointInfo.proc = t.GetMethod(dataPoint.DataProc);
monitorPoints.Add(dataPointInfo);
}
}
}
#endregion
#region 读写操作
///
/// 读取节点数据
///
public bool Read(string dataPointName, out object value)
{
value = null;
if (!allPoints.ContainsKey(dataPointName))
{
return false;
}
S7NetDataPointInfo p = allPoints[dataPointName];
return Read(p, out value);
}
public bool Read(S7NetDataPointInfo p, out object value)
{
switch (p.TYPE)
{
case VarType.Bit:
value = Convert.ToBoolean(S7Plc.Read(DataType.DataBlock, p.DB, p.ADDR, p.TYPE, 1, p.BIT));
break;
case VarType.Byte:
value = Convert.ToByte(S7Plc.Read(DataType.DataBlock, p.DB, p.ADDR, p.TYPE, 1));
break;
case VarType.Int:
value = Convert.ToInt16(S7Plc.Read(DataType.DataBlock, p.DB, p.ADDR, p.TYPE, 1));
break;
case VarType.Word:
value = Convert.ToUInt16(S7Plc.Read(DataType.DataBlock, p.DB, p.ADDR, p.TYPE, 1));
break;
case VarType.DInt:
value = Convert.ToInt32(S7Plc.Read(DataType.DataBlock, p.DB, p.ADDR, p.TYPE, 1));
break;
case VarType.DWord:
value = Convert.ToUInt32(S7Plc.Read(DataType.DataBlock, p.DB, p.ADDR, p.TYPE, 1));
break;
case VarType.Real:
value = Convert.ToDouble(S7Plc.Read(DataType.DataBlock, p.DB, p.ADDR, p.TYPE, 1));
break;
case VarType.String:
byte length = (byte)S7Plc.Read(DataType.DataBlock, p.DB, p.ADDR + 1, VarType.Byte, 1);
value = S7Plc.Read(DataType.DataBlock, p.DB, p.ADDR + 2, p.TYPE, length).ToString();
break;
default:
value = null;
return false;
}
UpdataRedisDataPoint(p.mo, value.ToString());
return true;
}
///
/// 写入节点数据
///
public bool Write(string dataPointName, object value)
{
if (!allPoints.ContainsKey(dataPointName))
{
return false;
}
S7NetDataPointInfo p = allPoints[dataPointName];
switch (p.TYPE)
{
case VarType.Bit:
S7Plc.WriteBit(DataType.DataBlock, p.DB, p.ADDR, p.BIT, Convert.ToBoolean(value));
break;
case VarType.Byte:
S7Plc.Write(DataType.DataBlock, p.DB, p.ADDR, Convert.ToByte(value));
break;
case VarType.Int:
S7Plc.Write(DataType.DataBlock, p.DB, p.ADDR, Convert.ToInt16(value));
break;
case VarType.Word:
S7Plc.Write(DataType.DataBlock, p.DB, p.ADDR, Convert.ToUInt16(value));
break;
case VarType.DInt:
S7Plc.Write(DataType.DataBlock, p.DB, p.ADDR, Convert.ToInt32(value));
break;
case VarType.DWord:
S7Plc.Write(DataType.DataBlock, p.DB, p.ADDR, Convert.ToUInt32(value));
break;
case VarType.Real:
S7Plc.Write(DataType.DataBlock, p.DB, p.ADDR, Convert.ToDouble(value));
break;
case VarType.String:
S7Plc.Write(DataType.DataBlock, p.DB, p.ADDR + 1, Convert.ToByte(value.ToString().Length));
S7Plc.Write(DataType.DataBlock, p.DB, p.ADDR + 2, value.ToString());
break;
default:
return false;
}
UpdataRedisDataPoint(p.mo, value.ToString());
return true;
}
#endregion
}
}