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