MotionSafetyGuard.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. using System;
  2. using System.Threading;
  3. using TeamAAS.Global.Devices;
  4. using TeamAAS.Motion.Models;
  5. namespace TeamAAS.Motion.Motions
  6. {
  7. /// <summary>
  8. /// 连接后轮询急停/停止 DI。急停边沿急停+持续下使能;停止边沿停轴并禁止新运动。
  9. /// </summary>
  10. internal sealed class MotionSafetyGuard : IDisposable
  11. {
  12. private readonly Func<MotionDeviceConfig> _cfg;
  13. private readonly Func<MotionIoBank, int, bool> _readDi;
  14. private readonly Action _onEstopRise;
  15. private readonly Action _onEstopHold;
  16. private readonly Action _onStopRise;
  17. private readonly object _sync = new object();
  18. private Timer _timer;
  19. private bool _estop;
  20. private bool _stop;
  21. public bool EstopActive { get { lock (_sync) return _estop; } }
  22. public bool StopActive { get { lock (_sync) return _stop; } }
  23. public event EventHandler Changed;
  24. public MotionSafetyGuard(
  25. Func<MotionDeviceConfig> cfg,
  26. Func<MotionIoBank, int, bool> readDi,
  27. Action onEstopRise,
  28. Action onEstopHold,
  29. Action onStopRise)
  30. {
  31. _cfg = cfg;
  32. _readDi = readDi;
  33. _onEstopRise = onEstopRise;
  34. _onEstopHold = onEstopHold;
  35. _onStopRise = onStopRise;
  36. }
  37. public void Start()
  38. {
  39. Stop();
  40. _timer = new Timer(_ => Poll(), null, 30, 30);
  41. }
  42. public void Stop()
  43. {
  44. var t = _timer;
  45. _timer = null;
  46. t?.Dispose();
  47. lock (_sync)
  48. {
  49. _estop = false;
  50. _stop = false;
  51. }
  52. }
  53. public bool AllowEnable(out string reason)
  54. {
  55. if (EstopActive)
  56. {
  57. reason = "急停有效:禁止使能";
  58. return false;
  59. }
  60. reason = null;
  61. return true;
  62. }
  63. public bool AllowMotion(out string reason)
  64. {
  65. if (EstopActive)
  66. {
  67. reason = "急停有效:禁止运动";
  68. return false;
  69. }
  70. if (StopActive)
  71. {
  72. reason = "停止信号有效:禁止运动";
  73. return false;
  74. }
  75. reason = null;
  76. return true;
  77. }
  78. public void Dispose() => Stop();
  79. private void Poll()
  80. {
  81. MotionDeviceConfig cfg;
  82. try { cfg = _cfg(); }
  83. catch { return; }
  84. if (cfg == null) return;
  85. bool estop = ReadActive(cfg.EstopDiBank, cfg.EstopDiIndex, cfg.EstopActiveHigh);
  86. bool stop = ReadActive(cfg.StopDiBank, cfg.StopDiIndex, cfg.StopActiveHigh);
  87. bool estopRise, stopRise, changed;
  88. lock (_sync)
  89. {
  90. estopRise = estop && !_estop;
  91. stopRise = stop && !_stop;
  92. changed = estop != _estop || stop != _stop;
  93. _estop = estop;
  94. _stop = stop;
  95. }
  96. try
  97. {
  98. if (estopRise)
  99. _onEstopRise?.Invoke();
  100. if (estop)
  101. _onEstopHold?.Invoke();
  102. else if (stopRise)
  103. _onStopRise?.Invoke();
  104. }
  105. catch { }
  106. if (changed)
  107. {
  108. try { Changed?.Invoke(this, EventArgs.Empty); }
  109. catch { }
  110. }
  111. }
  112. private bool ReadActive(MotionIoBank bank, int di, bool activeHigh)
  113. {
  114. if (di < 0) return false;
  115. bool bit;
  116. try { bit = _readDi(bank, di); }
  117. catch { return false; }
  118. return activeHigh ? bit : !bit;
  119. }
  120. }
  121. }