123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.IO;
- using Aitex.Core.RT.Log;
- using Aitex.Core.RT.Event;
- namespace Aitex.Core.RT.IOCore
- {
- public class Interlock
- {
- string _errMessage;
- bool _isErr = false;
- object _locker = new object();
- Dictionary<IntlkNode, List<List<IntlkNode>>> _interlocks = new Dictionary<IntlkNode, List<List<IntlkNode>>>();
- List<SafePlcInterlockChecker> _safeDoList = new List<SafePlcInterlockChecker>();
- List<Tuple<int, int, string>> _diMap;
- List<Tuple<int, int, string>> _doMap;
- public Interlock()
- {
- }
- public void InitSafeDO(List<Tuple<DOAccessor, DIAccessor>> safedos)
- {
- lock (_locker)
- {
- _safeDoList.Clear();
- for (int i = 0; i < safedos.Count; i++)
- {
- _safeDoList.Add(new SafePlcInterlockChecker(safedos[i].Item1, safedos[i].Item2));
- }
- }
- }
- public Tuple<int, int, string> FindDI(int iodefineIndex)
- {
- return _diMap.Find(item => item.Item1 == iodefineIndex);
- }
- public Tuple<int, int, string> FindDO(int iodefineIndex)
- {
- return _doMap.Find(item => item.Item1 == iodefineIndex);
- }
- public bool Init(string cfgFile, List<Tuple<int, int, string>> diMap, List<Tuple<int, int, string>> doMap, out string reason)
- {
- _interlocks.Clear();
- _errMessage = "";
- _isErr = false;
- _diMap = diMap;
- _doMap = doMap;
-
- if (_isErr)
- _isErr = true;
- try
- {
- //read interlock table from config file
- //example: ADO100:ADI100,ADI50,ADO55,!DI34,!TDI34&!TDO33,DO345
- using (StreamReader sr = new StreamReader(cfgFile))
- {
- string strLine = sr.ReadLine();
- while (strLine != null)
- {
- strLine = strLine.TrimStart(' ', '\t');
- if (string.IsNullOrEmpty(strLine) || strLine[0] == '#')
- {
- strLine = sr.ReadLine();
- continue;
- }
- string[] str = strLine.Split(new char[] { ':', ',', ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
- IntlkNode key;
- ParseIO(str[0], out key);
- System.Diagnostics.Debug.Assert(!key.IoTypeIsDI);
- List<List<IntlkNode>> rules = new List<List<IntlkNode>>();
- for (int i = 1; i < str.Length; i++)
- {
- List<IntlkNode> singleRule = new List<IntlkNode>();
- string[] slist = str[i].Split(new char[] { '&' }, StringSplitOptions.RemoveEmptyEntries);
- foreach (var s1 in slist)
- {
- IntlkNode nd;
- ParseIO(s1, out nd);
- singleRule.Add(nd);
- }
- rules.Add(singleRule);
- }
- if (_interlocks.Keys.Contains(key))
- {
- _errMessage = string.Format("{0} is defined in more than one place.", str[0]);
- _isErr = true;
- //Notifier.PostEvent(EventEnum.InterlockFileBad, Reactor.PmName, _errMessage);
- reason = _errMessage;
- return false;
- }
- _interlocks.Add(key, rules);
- strLine = sr.ReadLine();
- }
- }
- //verify PmInterlock.cfg file
- foreach (var interlock in _interlocks)
- {
- var ruleHead = interlock.Key;
- if ((ruleHead.IoTypeIsDI && FindDI(ruleHead.Index)==null) ||
- (!ruleHead.IoTypeIsDI && FindDO(ruleHead.Index)==null))
- {
- _errMessage = string.Format("{0}-{1} not exist.", ruleHead.IoTypeIsDI ? "DI" : "DO", ruleHead.Index);
- _isErr = true;
- //Notifier.PostEvent(EventEnum.InterlockFileBad, Reactor.PmName, _errMessage);
- reason = _errMessage;
- return false;
- }
- foreach (var rule in interlock.Value)
- {
- foreach (var r1 in rule)
- {
- if ((r1.IoTypeIsDI && FindDI(r1.Index) == null) ||
- (!r1.IoTypeIsDI && FindDO(r1.Index) == null))
- {
- _errMessage = string.Format("{0}-{1} not exist", r1.IoTypeIsDI ? "DI" : "DO", r1.Index);
- _isErr = true;
- //Notifier.PostEvent(EventEnum.InterlockFileBad, Reactor.PmName, _errMessage);
- reason = _errMessage;
- return false;
- }
- }
- }
- }
- }
- catch (Exception ex)
- {
- _errMessage = ex.Message;
- _isErr = true;
- reason = _errMessage;
- LOG.Write(ex, string.Format("erro reading interlock config file {0}", cfgFile));
- return false;
- }
- reason = _errMessage;
- LOG.Write(string.Format("get {0} interlock items", _interlocks.Count));
- return true;
- }
- /// <summary>
- /// IO interlock monitoring
- /// </summary>
- public void Monitor()
- {
- //检查安全逻辑是否动作,如果有动作则撤销当前的DO设定值
- lock (_locker)
- {
- foreach (var safeItem in _safeDoList)
- {
- safeItem.Monitor();
- }
- }
- //监测当前软件DO点是否存在互锁情况
- foreach (var interlock in _interlocks)
- {
- try
- {
- var failReasonList = new List<List<IntlkNode>>();
- bool isTrigger = false;
- foreach (var rule in interlock.Value) //OR遍历
- {
- bool ret = true;
- foreach (var item in rule) //AND遍历
- {
- if (item.IoTypeIsDI && item.IsReversed)
- {
- ret &= (!IO.DI[FindDI(item.Index).Item3].RawData);
- }
- else if (item.IoTypeIsDI && !item.IsReversed)
- {
- ret &= IO.DI[FindDI(item.Index).Item3].RawData;
- }
- else if (!item.IoTypeIsDI && item.IsReversed)
- {
- ret &= (!IO.DO[FindDO(item.Index).Item3].Value);
- }
- else
- {
- ret &= IO.DO[FindDO(item.Index).Item3].Value;
- }
- }
- if (ret)
- {
- var andList = new List<IntlkNode>(rule);
- failReasonList.Add(andList);
- isTrigger = true;
- }
- }
- if (isTrigger)
- {
- if (IO.DO[FindDO(interlock.Key.Index).Item3].Value != interlock.Key.IsReversed)
- {
- string reason = string.Empty;
-
- reason = string.Format("DO-{0}({1}) can not match {2} interlock condition,force to {3}。",
- interlock.Key.Index,
- _doMap[interlock.Key.Index],
- failReasonList.Count,
- interlock.Key.IsReversed ? "ON" : "OFF");
- for (int i = 0; i < failReasonList.Count; i++)
- {
- reason += string.Format("{0}{1}. ", i == 0 ? "" : "\n", i + 1);
- for (int j = 0; j < failReasonList[i].Count; j++)
- {
- var it = failReasonList[i][j];
- reason += string.Format("{0}{1}-{2}({3})[{4}]",
- j == 0 ? "" : " & ",
- it.IoTypeIsDI ? "DI" : "DO",
- it.Index,
- it.IoTypeIsDI ? _diMap[it.Index] : _doMap[it.Index],
- (it.IoTypeIsDI ? IO.DI[FindDI(it.Index).Item3].Value : IO.DO[FindDO(it.Index).Item3].Value) ? "ON" : "OFF");
- }
- }
- //将DO进行强制操作
- string reason1;
- IO.DO[FindDO(interlock.Key.Index).Item3].SetValue(interlock.Key.IsReversed, out reason1);
- //将互锁消息发送给用户界面
- EV.PostMessage("IO", EventEnum.SwInterlock, "IO", reason);
- }
- }
- }
- catch (Exception ex)
- {
- LOG.Write(ex);
- }
- }
- }
- public bool CanSetDo(string doName, bool onOff, out string reason)
- {
- foreach (var item in _doMap)
- {
- if (item.Item3 == doName)
- return CanSetDo(item.Item1, onOff, out reason);
- }
- throw new ApplicationException("Can not find DO:"+doName);
- }
- public bool CanSetDo(int doIndex, bool onOff, out string reason)
- {
- reason = string.Empty;
- bool isTrigger = false;
- var failReasonList = new List<List<IntlkNode>>();
- foreach (var interlock in _interlocks)
- {
- if (!(interlock.Key.Index == doIndex &&
- interlock.Key.IoTypeIsDI == false))
- {
- continue;
- }
- if (onOff == interlock.Key.IsReversed)
- {
- //return true;
- continue;
- }
- foreach (var rule in interlock.Value)
- {
- bool ret = true;
- foreach (var item in rule)
- {
- if (item.IoTypeIsDI && item.IsReversed)
- {
- ret &= (!IO.DI[FindDI(item.Index).Item3].RawData);
- }
- else if (item.IoTypeIsDI && !item.IsReversed)
- {
- ret &= IO.DI[FindDI(item.Index).Item3].RawData;
- }
- else if (!item.IoTypeIsDI && item.IsReversed)
- {
- ret &= (!IO.DO[FindDO(item.Index).Item3].Value);
- }
- else
- {
- ret &= IO.DO[FindDO(item.Index).Item3].Value;
- }
- }
- if (ret)
- {
- var andList = new List<IntlkNode>(rule);
- failReasonList.Add(andList);
- isTrigger = true;
- }
- }
- }
- if (isTrigger)
- {
- //1. DI-1(Earthquake)[OFF] & DI-12(Smoke)[ON]
- //2. DO-105(ServiceMode)[ON]
- for (int i = 0; i < failReasonList.Count; i++)
- {
- reason += string.Format("{0}{1}. ", i == 0 ? "" : "\n", i + 1);
- for (int j = 0; j < failReasonList[i].Count; j++)
- {
- var it = failReasonList[i][j];
- reason += string.Format("{0}{1}-{2}({3})[{4}]",
- j == 0 ? "" : " & ",
- it.IoTypeIsDI ? "DI" : "DO",
- it.Index,
- it.IoTypeIsDI ? _diMap[it.Index] : _doMap[it.Index],
- (it.IoTypeIsDI ? IO.DI[FindDI(it.Index).Item3].Value : IO.DO[FindDO(it.Index).Item3].Value) ? "ON" : "OFF");
- }
- }
- }
- return !isTrigger;
- }
- void ParseIO(string ioName, out IntlkNode interlockNode)
- {
- interlockNode = new IntlkNode();
- ioName = ioName.Trim();
- if (ioName[0] == '!')
- {
- ioName = ioName.Remove(0, 1);
- interlockNode.IsReversed = true;
- }
- else
- {
- interlockNode.IsReversed = false;
- }
- switch (ioName.Substring(0, 2))
- {
- case "DO":
- interlockNode.IoTypeIsDI = false;
- break;
- case "DI":
- interlockNode.IoTypeIsDI = true;
- break;
- default:
- throw new Exception("interlock file found error, the io name should be DO or DI leading" + ioName);
- }
- ioName = ioName.Remove(0, 2);
- interlockNode.Index = Convert.ToInt32(ioName);
- if (interlockNode.Index < 0 && interlockNode.Index >= 1000)
- {
- throw new Exception(string.Format("{0} index out of range", ioName));
- }
- }
- }
- }
|