using Aitex.Core.RT.Event; using Aitex.Core.RT.IOCore; using Aitex.Core.RT.Log; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using System; using System.Threading.Tasks; using System.Xml; namespace Aitex.Core.RT.Device.Devices { internal class IoHeartBeat : BaseDevice, IDevice { public float Feedback { get { if (_ai != null) { return _isFloatAioType ? _ai.Value : _ai.Value; } return 0; } } public float SetPoint { get { if (_ao != null) { return _isFloatAioType ? _ao.Value : _ao.Value; } return 0; } set { if (_ao != null) { if (_isFloatAioType) _ao.Value = value; else _ao.Value = (short)value; } } } //IO private AIAccessor _ai = null; private AOAccessor _ao = null; private bool _isFloatAioType = false; private readonly DeviceTimer _timHeartBeatOfRange = new(); private readonly R_TRIG _trigHeartBeatError = new(); private short _counter = 0; private PeriodicJob _thread; private bool _isModuleInstalled; 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); _isFloatAioType = !string.IsNullOrEmpty(node.GetAttribute("aioType")) && (node.GetAttribute("aioType") == "float"); } public bool Initialize() { _thread = new PeriodicJob(1000, OnTimer, "PLC Write Thread", false); _isModuleInstalled= SC.SafeGetValue($"System.SetUp.Is{Module}Installed", false); //防止UI没启动,就进行EV.Post Task.Delay(1000 * 30).ContinueWith((a) => _thread.Start()); return true; } public bool OnTimer() { try { if (!_isModuleInstalled)//模块未安装直接退出 return true; if (Feedback != SetPoint && _timHeartBeatOfRange.IsIdle())//检测值是否相等 _timHeartBeatOfRange.Start(1000 * 10); if (Feedback == SetPoint)//有数据搬运机制,把AO中的数值,映射到AI中,所以二者会实时相同, { SetHeartBeatValue();//执行每秒自加一 _timHeartBeatOfRange.Stop(); } _trigHeartBeatError.CLK = _timHeartBeatOfRange.IsTimeout();//超时后才会置true if (_trigHeartBeatError.Q) EV.PostAlarmLog(Module, $"Alarm:PLC heartbeat error , Time ovre 10s"); } catch (Exception ex) { LOG.Write(ex); } return true; } private void SetHeartBeatValue() { _counter++; if (_counter > 1000) _counter = 0; SetPoint = _counter; } public void Terminate() { } public void Monitor() { } public void Reset() { _trigHeartBeatError.RST = true; } } }