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 } }