using System;
using System.Timers;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using ProjectBase.Data.Logs;
using ProjectBase.Data.Redis;
using ProjectBase.Data.BaseDAL;
using Modbus.Device;
using SIMDP.Model;
using ProjectBase.Util;
using SIMDP.BLL;
using System.Linq;
using System.Reflection;
using System.Net.Sockets;
namespace SIMDP.Device
{
public class ModbusTcp : AbstractBaseDevice
{
#region 数据定义
///
/// ModbusTcp配置信息
///
protected ModbusTcpConfig config;
///
/// Modbus对象
///
protected IModbusMaster master;
///
/// TCP连接对象
///
protected TcpClient tcpClient;
///
/// 数据节点字典 key-变量名称, value-节点信息
///
protected Dictionary allPoints = new Dictionary();
///
/// 监控节点列表
///
protected List monitorPoints = new List();
///
/// 连接状态
///
protected bool isConnect = false;
#endregion
#region TYPE定义
public class ModbusTcpConfig
{
public ModbusTcpConfig(string json)
{
JObject jObject = JObject.Parse(json);
JToken token;
if ((token = jObject["IP"]) != null)
IP = (string)token;
if ((token = jObject["PORT"]) != null)
PORT = (int)token;
if ((token = jObject["TIMER"]) != null)
TIMER = (double)token;
}
// 串口属性
public string IP { get; set; } = "127.0.0.1";
public int PORT { get; set; } = 502;
// 轮询时间
public double TIMER { get; set; } = 200;
}
public class ModbusDataPointInfo
{
// 节点配置信息
public MoDataPoint mo;
// 节点属性
public string 类型 { get; set; }
public byte 站号 { get; set; }
public ushort 地址 { get; set; }
public ushort 长度 { get; set; } = 1;
// 节点值及动作定义
public object value = null;
public MethodInfo proc = null;
public ModbusDataPointInfo(MoDataPoint _mo)
{
mo = _mo;
类型 = SysEnvironment.dirType.FirstOrDefault(p => p.Key == mo.DataPointType).Value;
JObject jObject = JObject.Parse(mo.DataPointSource);
站号 = Convert.ToByte((string)jObject["站号"]);
地址 = Convert.ToUInt16((string)jObject["地址"]);
if (jObject["长度"] != null)
长度 = Convert.ToUInt16((string)jObject["长度"]);
}
}
#endregion
#region 接口实现
public override void Start(MoPlcInfo _plcInfo, List _dataPoints)
{
plcInfo = _plcInfo;
config = new ModbusTcpConfig(plcInfo.LinkConfig);
timer.Interval = config.TIMER;
timer.Elapsed += timer_Elapsed;
timer.AutoReset = false;
// PLC未连接状态
SetRedisPlcDisConnect();
// 创建PLC数据点表
CreateDataPointList(_dataPoints);
// 初始化自定义函数
actionStart();
// 启动时尝试连接一次设备
Connect();
// 启动定时器
timerStopped = false;
timer.Start();
}
///
/// PLC连接状态
///
public override bool isConnected()
{
return isConnect;
}
protected override bool Connect()
{
tcpClient = new TcpClient
{
ReceiveTimeout = 1000
};
tcpClient.Connect(config.IP, config.PORT);
master = ModbusIpMaster.CreateIp(tcpClient);
SetRedisPlcConnected();
LogHelper.log.Info("已连接到Modbus TCP: " + config.IP);
isConnect = true;
actionConnected();
return isConnected();
}
protected override void Disconnect()
{
if (tcpClient != null)
tcpClient.Close();
isConnect = false;
if (master != null)
master.Dispose();
SetRedisPlcDisConnect();
}
protected void CreateDataPointList(List dataPoints)
{
if (redis == null)
redis = new RedisHelper();
Type t = this.GetType();
foreach (MoDataPoint dataPoint in dataPoints)
{
ModbusDataPointInfo dataPointInfo = new ModbusDataPointInfo(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;
}
ModbusDataPointInfo pointInfo = allPoints[dataPointName];
return Read(pointInfo, out value);
}
public bool Read(ModbusDataPointInfo pointInfo, out object value)
{
bool[] coilsBuffer; //线圈数组
ushort[] registerBuffer; // 寄存器数组
value = (Decimal)0;
string binary = "";
try
{
if (pointInfo.类型 == "BOOL")
{
coilsBuffer = master.ReadCoils(pointInfo.站号, pointInfo.地址, pointInfo.长度);
for (int i = 0; i < coilsBuffer.Length; i++)
{
value = (Decimal)value * 2 + (coilsBuffer[i] ? 1 : 0);
binary += coilsBuffer[i] ? "1" : "0";
}
UpdataRedisDataPoint(pointInfo.mo, binary);
}
else
{
registerBuffer = master.ReadHoldingRegisters(pointInfo.站号, pointInfo.地址, pointInfo.长度);
for (int i = 0; i < registerBuffer.Length; i++)
{
value = (Decimal)value * 256 + registerBuffer[i];
}
UpdataRedisDataPoint(pointInfo.mo, value.ToString());
}
return true;
}
catch (Exception ex)
{
LogHelper.log.Error("读取Modbus(" + config.IP + ")信号(" + pointInfo.mo.DataPointName + ")发生异常:" + ex.Message);
Disconnect();
return false;
}
}
#endregion
}
}