using System; using System.Xml; using Aitex.Core.RT.Device; using Aitex.Core.RT.Event; using Aitex.Core.RT.IOCore; using Aitex.Core.Util; namespace Aitex.Core.RT.Device.Unit { /// /// 心跳包机制 /// /// 功能: /// 1.C#送出给PLC,如果PLC检测到C#心跳信号停止,则判定C#程序运行异常,从而触发安全逻辑动作。 /// 2.C#检测PLC返回的心跳包信号,如果检测到PLC心跳信号停止,则判定PLC程序运行异常,从而进行报警处理。 /// public class IoHeartbeat : BaseDevice, IDevice { private readonly int PLC_Heart_Beat_Timeout_ms = 1000 * 120; private readonly AIAccessor _ai; private readonly AOAccessor _ao; private readonly DeviceTimer _updateTimer = new DeviceTimer(); //更新 AO信号 给PLC private readonly int MAX = 0x7FFF; private float _prevAiValue; private readonly DeviceTimer _connectTimer = new DeviceTimer(); private readonly R_TRIG _trigConnectionLost = new R_TRIG(); // --------------------------Constructor----------------------- // public IoHeartbeat(string module, XmlElement node, string ioModule = "") { base.Module = module; base.Name = node.GetAttribute("id"); base.Display = node.GetAttribute("display"); base.DeviceID = node.GetAttribute("schematicId"); _ai = ParseAiNode("ai", node, ioModule); _ao = ParseAoNode("ao", node, ioModule); } public bool Initialize() { _updateTimer.Start(500); _connectTimer.Start(PLC_Heart_Beat_Timeout_ms); return true; } public void Monitor() { if (Math.Abs(_prevAiValue - _GetRealFloat(_ai)) > 0.01) { _connectTimer.Start(PLC_Heart_Beat_Timeout_ms); } _trigConnectionLost.CLK = _connectTimer.IsTimeout(); if (_trigConnectionLost.Q) { EV.PostMessage(Module, EventEnum.PlcHeartBeatFail, Module, Display); } _prevAiValue = _GetRealFloat(_ai); //如果计时到达,则翻转心跳信号 if (_updateTimer.IsTimeout()) { float beat_val = _GetRealFloat(_ao); beat_val++; if (beat_val >= MAX) { beat_val = 0; } _SetRealFloat(_ao, beat_val); _updateTimer.Start(2000); //500 ms } } public void Terminate() { } public void Reset() { _connectTimer.Start(PLC_Heart_Beat_Timeout_ms); _trigConnectionLost.RST = true; } } }