using System;
using System.Timers;
using System.IO.Ports;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using ProjectBase.Data.Logs;
using ProjectBase.Data.Redis;
using Modbus.Device;
using SIMDP.Model;
using ProjectBase.Util;
using System.Linq;
using System.Reflection;
namespace SIMDP.Device
{
public class ModbusRtu : AbstractBaseDevice
{
#region 数据定义
///
/// Modbus对象
///
protected IModbusMaster master;
///
/// 串口对象
///
protected SerialPort port;
///
/// 数据节点字典 key-变量名称, value-节点信息
///
protected Dictionary allPoints = new Dictionary();
///
/// 监控节点列表
///
protected List monitorPoints = new List();
///
/// 连接状态
///
protected bool isConnect = false;
#endregion
#region TYPE定义
public class ModbusRtuConfig
{
public ModbusRtuConfig(string json)
{
JObject jObject = JObject.Parse(json);
JToken token;
if ((token = jObject["PORT"]) != null)
PORT = (string)token;
if ((token = jObject["baudRate"]) != null)
baudRate = (int)token;
if ((token = jObject["parity"]) != null)
parity = (Parity)(int)token;
if ((token = jObject["dataBits"]) != null)
dataBits = (int)token;
if ((token = jObject["stopBits"]) != null)
stopBits = (StopBits)(int)token;
if ((token = jObject["TIMER"]) != null)
TIMER = (double)token;
}
// 串口属性
public string PORT { get; set; } = "COM1";
public int baudRate { get; set; } = 9600;
public Parity parity { get; set; } = Parity.None;
public int dataBits { get; set; } = 8;
public StopBits stopBits { get; set; } = StopBits.One;
// 轮询时间
public double TIMER { get; set; } = 500;
}
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;
ModbusRtuConfig config = new ModbusRtuConfig(plcInfo.LinkConfig);
port = new SerialPort(config.PORT, config.baudRate, config.parity, config.dataBits, config.stopBits);
port.ReadTimeout = 1000;
timer.Interval = config.TIMER;
timer.Elapsed += timer_Elapsed;
timer.AutoReset = false;
// PLC未连接状态
SetRedisPlcDisConnect();
// 创建PLC数据点表
CreateDataPointList(_dataPoints);
// 初始化自定义函数
actionStart();
// 启动时尝试连接一次设备
Connect();
// 启动定时器
timerStopped = false;
timer.Start();
}
public override bool isConnected()
{
return isConnect;
}
protected override bool Connect()
{
master = ModbusSerialMaster.CreateRtu(port);
port.Open();
port.Close();
SetRedisPlcConnected();
LogHelper.log.Info("已连接到Modbus RTU: " + port.PortName);
isConnect = true;
return isConnected();
}
protected override void Disconnect()
{
if (port.IsOpen)
port.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;
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);
}
}
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(" + port.PortName + ")信号(" + pointInfo.mo.DataPointName + ")发生异常:" + ex.Message);
Disconnect();
return false;
}
}
#endregion
}
}