| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- using IACommService4CSharp;
- using Model;
- using PlcCom;
- using PlcComponent;
- using StandardLibrary;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- using System.Xml.Linq;
- namespace YangjieTester
- {
- public class BackgroundService
- {
- public static BackgroundService Instance { get; set; }
- public PlcDataMonitor MachineStateMonitor { get; private set; }
- public PlcDataMonitor AlarmMonitor { get; private set; }
- public PlcDataMonitor TipsMonitor { get; private set; }
- public IPlcComProtocol Protocol;
- private bool IsServiceAlive;
- private BackgroundService()
- {
- }
- public BackgroundService(IPlcComProtocol plcComProtocol):this()
- {
- this.Protocol = plcComProtocol;
- MachineStateMonitorInit();
- AlarmMonitorInit();
- TipsMonitorInit();
- }
- public bool Start()
- {
- if (IsServiceAlive)
- return false;
- StartAlarmTipsMonitor(0,200);
- IsServiceAlive = true;
- return true;
- }
- public void Stop()
- {
- if (IsServiceAlive)
- {
- StopAlarmTipsMonitor();
- }
- }
- void MachineStateMonitorInit()
- {
- MachineStateMonitor = new PlcDataMonitor();
- MachineStateMonitor.Protocol = Protocol;
- MachineStateMonitor.ReadNodes = AppSession.MachineState.PlcAddressPropertyPathsPairs
- .Select(n => new Node(n.Key))
- .ToList();
- MachineStateMonitor.OnMonitoredValuesChanged += MachineStateMonitor_OnMonitoredValuesChanged;
- }
- private void MachineStateMonitor_OnMonitoredValuesChanged(List<(Node node, object newValue)> obj)
- {
- foreach (var item in obj)
- {
- if (AppSession.MachineState.PlcAddressPropertyPathsPairs.TryGetValue(item.node.Value, out List<string> propertyPaths))
- {
- foreach (var propertyPath in propertyPaths)
- {
- ObjectPropertySetter.SetPropertyValue(AppSession.MachineState, propertyPath, item.newValue);
- }
- }
- }
- }
- void AlarmMonitorInit()
- {
- AlarmMonitor = new PlcDataMonitor();
- AlarmMonitor.Protocol=Protocol;
- AlarmMonitor.MonitorRules = Alarm.AlarmNodeWithMessage.Select(
- a => new MonitorRule()
- {
- Node = new Node(a.AlarmNode),
- Message = a.AlarmMessage,
- TargetValue = a.DesiredValue,
- CompareType= CompareType.ToTarget
- //MonitorType = MonitorType.RisingOrFallingEdge
- }).
- ToList();
- AlarmMonitor.OnDataTriggered += AlarmMonitor_OnDataTriggered;
- AlarmMonitor.OnDataCleared += AlarmMonitor_OnDataCleared;
- }
- private void AlarmMonitor_OnDataTriggered(object arg1, List<PlcDataMonitor.MonitorEventArgs> arg2)
- {
- AlarmService.LogBatch(arg2.Select(a => new Alarm() { AlarmMessage = a.Rule.Message, AlarmType = AlarmType.Error, Timestamp = a.Timestamp }), AppSession.CurrentUser);
- //AlarmService.Log(new Alarm() { AlarmMessage = arg2.Rule.Message, AlarmType = AlarmType.Error, Timestamp = arg2.Timestamp }, AppSession.CurrentUser);
- }
- private void AlarmMonitor_OnDataCleared(object arg1, List<PlcDataMonitor.MonitorEventArgs> arg2)
- {
- AlarmService.LogBatch(arg2.Select(a => new Alarm() { AlarmMessage = a.Rule.Message, AlarmType = AlarmType.Cleared, Timestamp = a.Timestamp }), AppSession.CurrentUser);
- }
- void TipsMonitorInit()
- {
- TipsMonitor = new PlcDataMonitor();
- TipsMonitor.Protocol = Protocol;
- TipsMonitor.MonitorRules = Tips.TipsNodeWithMessage.Select(
- t => new MonitorRule()
- {
- Node = new Node(t.Node),
- Message = t.Message,
- TargetValue = t.DesiredValue,
- MonitorType = MonitorType.RisingOrFallingEdge
- }).
- ToList();
- TipsMonitor.OnDataTriggered += TipsMonitor_OnDataTriggered;
- TipsMonitor.OnDataCleared += TipsMonitor_OnDataCleared;
- }
- private void TipsMonitor_OnDataTriggered(object arg1, List<PlcDataMonitor.MonitorEventArgs> arg2)
- {
- TipsService.LogBatch(arg2.Select(a => new Tips() { Message = a.Rule.Message, Type = TipsType.Common, Timestamp = a.Timestamp }), AppSession.CurrentUser);
- ////TipsService.Log(new Tips() { Message = arg2.Rule.Message, Type = TipsType.Common , Timestamp = arg2.Timestamp }, AppSession.CurrentUser);
- }
- private void TipsMonitor_OnDataCleared(object arg1, List<PlcDataMonitor.MonitorEventArgs> arg2)
- {
- TipsService.LogBatch(arg2.Select(a => new Tips() { Message = a.Rule.Message, Type = TipsType.Cleared, Timestamp = a.Timestamp }), AppSession.CurrentUser);
- ////TipsService.Log(new Tips() { Message = arg2.Rule.Message, Type = TipsType.Cleared, Timestamp = arg2.Timestamp }, AppSession.CurrentUser);
- }
- Timer _timerMonitor;
- private void StartAlarmTipsMonitor(int dueTime,int interval)
- {
- if (_timerMonitor != null)
- return; // 避免重复创建
- var invalidNodes= AlarmMonitor.RemoveInvalidNodes();//剔除掉地址错误的节点
- foreach (var item in invalidNodes)
- {
- string err = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + $" {this.GetType().Name}->AlarmMonitor->{item},读取失败";
- AppSession.ReadWriteErrors.Add(err);
- }
- invalidNodes = TipsMonitor.RemoveInvalidNodes();//剔除掉地址错误的节点
- foreach (var item in invalidNodes)
- {
- string err = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + $" {this.GetType().Name}->TipsMonitor->{item},读取失败";
- AppSession.ReadWriteErrors.Add(err);
- }
- invalidNodes = MachineStateMonitor.RemoveInvalidNodes();//剔除掉地址错误的节点
- foreach (var item in invalidNodes)
- {
- string err = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + $" {this.GetType().Name}->TipsMonitor->{item},读取失败";
- AppSession.ReadWriteErrors.Add(err);
- }
- // 创建 Timer
- // dueTime: intervalms 后第一次执行
- // period: 之后每 intervalms 执行一次
- _timerMonitor = new Timer(
- callback: OnTimerElapsed,
- state: null,
- dueTime: dueTime,
- period: interval
- );
- }
- private int _isExecuting = 0; // 0 = 空闲, 1 = 正在执行
- private void OnTimerElapsed(object state)
- {
- // ✅ 原子操作:尝试设置“正在执行”
- if (Interlocked.CompareExchange(ref _isExecuting, 1, 0) == 0)
- {
- try
- {
- // ✅ 只有获得锁的线程才能执行
- // 这个方法运行在**线程池线程**上
- AlarmMonitor.Read();
- TipsMonitor.Read();
- MachineStateMonitor.Read();
- }
- finally
- {
- // ✅ 释放:设置为 0
- Interlocked.Exchange(ref _isExecuting, 0);
- }
- }
- }
- private void StopAlarmTipsMonitor()
- {
- if (_timerMonitor != null)
- {
- _timerMonitor.Dispose(); // 或 _timerMonitor.Change(Timeout.Infinite, 0);
- _timerMonitor = null;
- }
- AlarmMonitor.OnDataTriggered -= AlarmMonitor_OnDataTriggered;
- AlarmMonitor.OnDataCleared -= AlarmMonitor_OnDataCleared;
- }
- public bool RefreshInstanceFromPLC(IPlcAddressToPropertyPaths instance)
- {
- PlcDataMonitor monitor = new PlcDataMonitor();
- monitor.Protocol = Protocol;
- monitor.ReadNodes = instance.PlcAddressPropertyPathsPairs
- .Select(n => new Node(n.Key))
- .ToList();
- var results = monitor.Read();
- if (results != null)
- {
- foreach (var kvp in monitor.NodeStringValuePairs)
- {
- //if (batch.PlcAddressPropertyPathPairs.TryGetValue(kvp.Key, out string propertyPath))
- //{
- // ObjectPropertySetter.SetPropertyValue(batch, propertyPath, kvp.Value);
- //}
- if (instance.PlcAddressPropertyPathsPairs.TryGetValue(kvp.Key, out List<string> propertyPaths))
- {
- foreach (var propertyPath in propertyPaths)
- {
- ObjectPropertySetter.SetPropertyValue(instance, propertyPath, kvp.Value);
- }
- }
- }
- return true;
- }
- else
- {
- return false;
- }
- }
- }
- }
|