AutoManager.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. using System;
  2. using System.Threading;
  3. using GSG.NET.Concurrent;
  4. using GSG.NET.Logging;
  5. using OHV.Common.Shareds;
  6. using VehicleControlSystem.ControlLayer.IO;
  7. using Prism.Events;
  8. using OHV.SqliteDAL;
  9. using OHV.Common.Model;
  10. using OHV.Common.Events;
  11. using VehicleControlSystem.ControlLayer;
  12. using GSG.NET.Utils;
  13. using System.Collections.Generic;
  14. using System.Linq;
  15. using GSG.NET.LINQ;
  16. namespace VehicleControlSystem.Managers
  17. {
  18. /// <summary>
  19. /// Vehicle 전체 상태를 관리.
  20. /// </summary>
  21. public class AutoManager : IDisposable
  22. {
  23. static Logger logger = Logger.GetLogger();
  24. Thread threadWorker = null;
  25. bool isThreadAlive = false;
  26. IIO iO = null;
  27. private bool isErrorProcessing = false;
  28. public bool IsErrorProcessing
  29. {
  30. get { return this.isErrorProcessing; }
  31. set
  32. {
  33. //if (this.isErrorProcessing == value) return;
  34. this.isErrorProcessing = value;
  35. if (value)
  36. {
  37. //if ( this.activeAlarm == null ) return;
  38. //this.OnOccurAlarm?.BeginInvoke( this.activeAlarm.AlarmId, null, null );
  39. }
  40. else
  41. {
  42. this.ActiveAlarms.ForEach(x =>
  43. {
  44. this.OnClearAlarm?.Invoke(x.AlarmId);
  45. var al = ObjectCopyUtils.DeepClone<Alarm>(x);
  46. var args = new ActiveAlarmEventArgs(al, false);
  47. this.eventAggregator.GetEvent<ActiveAlarmPubSubEvent>().Publish(args);
  48. });
  49. this.ActiveAlarms.Clear();
  50. //if ( this.activeAlarm == null ) return;
  51. //this.OnClearAlarm?.BeginInvoke( this.activeAlarm.AlarmId, null, null );
  52. //this.activeAlarm = null;
  53. this.BuzzerOnOff(false);
  54. }
  55. }
  56. }
  57. private bool isBlockedMoving = false;
  58. public bool IsBlockedMoving //210812 Kkm
  59. {
  60. get { return this.isBlockedMoving; }
  61. set
  62. {
  63. if (this.isBlockedMoving == value) return;
  64. this.isBlockedMoving = value;
  65. if (value)
  66. {
  67. this.BuzzerOnOff(false); //Kkm Blocked 상태는 무조건 Off
  68. this.LampStateChange(eLampState.Blocked);
  69. }
  70. else
  71. {
  72. this.BuzzerOnOff(true, eBuzzerKind.Moving);
  73. this.LampStateChange(eLampState.AutoRunNChargingFull);
  74. }
  75. }
  76. }
  77. public event Action<int> OnOccurAlarm;
  78. public event Action<int> OnClearAlarm;
  79. Alarm activeAlarm = null;
  80. //Alarm List
  81. List<Alarm> Alarms { get; set; }
  82. //현재 발생 된 알람 리스트
  83. public List<Alarm> ActiveAlarms { get; set; }
  84. IEventAggregator eventAggregator = null;
  85. SqliteManager sql = null;
  86. private eOperatationMode operationMode;
  87. public eOperatationMode OperationModeProperty
  88. {
  89. get { return operationMode; }
  90. set
  91. {
  92. if (operationMode == value) return;
  93. operationMode = value;
  94. logger.D($"[AutoManager] OperationMode - {value}");
  95. this.OnOperationModeChanged?.Invoke(value);
  96. if (value == eOperatationMode.AutoMode)
  97. this.iO.OutputOff("OUT_TEACH_MODE");
  98. else
  99. this.iO.OutputOn("OUT_TEACH_MODE");
  100. }
  101. }
  102. public event Action<eOperatationMode> OnOperationModeChanged;
  103. private eAutoModeState autoModeState;
  104. public eAutoModeState AutoModeStateProperty
  105. {
  106. get { return autoModeState; }
  107. set
  108. {
  109. if (autoModeState == value) return;
  110. autoModeState = value;
  111. logger.D($"[AutoManager] AutoModeState - {value}");
  112. switch (value)
  113. {
  114. case eAutoModeState.ErrorStop:
  115. this.LampStateProperty = eLampState.Alarm;
  116. break;
  117. case eAutoModeState.StartRun:
  118. this.LampStateProperty = eLampState.AutoRunNChargingFull;
  119. break;
  120. case eAutoModeState.Run:
  121. this.LampStateProperty = eLampState.AutoRunNChargingFull;
  122. break;
  123. case eAutoModeState.Stop:
  124. this.LampStateProperty = eLampState.Manual;
  125. break;
  126. case eAutoModeState.WaitStop:
  127. this.LampStateProperty = eLampState.Manual;
  128. break;
  129. default:
  130. break;
  131. }
  132. }
  133. }
  134. private eLampState lampState = eLampState.None;
  135. public eLampState LampStateProperty
  136. {
  137. get { return lampState; }
  138. set
  139. {
  140. if (lampState == value) return;
  141. lampState = value;
  142. this.LampStateChange(value);
  143. }
  144. }
  145. private eBuzzerKind buzzerState;
  146. public eBuzzerKind BuzzerStateProperty
  147. {
  148. get { return buzzerState; }
  149. set { buzzerState = value; }
  150. }
  151. Vehicle vehicle = null;
  152. public AutoManager(IIO io, IEventAggregator ea, SqliteManager sql, List<Alarm> al)
  153. {
  154. this.iO = io;
  155. this.eventAggregator = ea;
  156. this.sql = sql;
  157. this.Alarms = al;
  158. this.ActiveAlarms = new List<Alarm>();
  159. }
  160. #region Vehicle Events
  161. private void Vehicle_OnChargingFull()
  162. {
  163. if (this.OperationModeProperty == eOperatationMode.AutoMode)
  164. LampStateChange(eLampState.AutoRunNChargingFull);
  165. else
  166. LampStateChange(eLampState.Manual);
  167. }
  168. private void Vehicle_OnCharging()
  169. {
  170. LampStateChange(eLampState.Charging);
  171. }
  172. private void Vehicle_OnMoveFinish()
  173. {
  174. BuzzerOnOff(false);
  175. logger.D("Vehicle Move Finish");
  176. }
  177. private void Vehicle_OnMoving()
  178. {
  179. BuzzerOnOff(true, eBuzzerKind.Moving);
  180. logger.D("Vehicle Moving");
  181. }
  182. private void Vehicle_OnMoveReady()
  183. {
  184. BuzzerOnOff(true, eBuzzerKind.StartWarn);
  185. logger.D("Vehicle Move Ready");
  186. }
  187. #endregion
  188. public void Init(Vehicle vehicle)
  189. {
  190. this.OperationModeProperty = eOperatationMode.ManualMode;
  191. this.AutoModeStateProperty = eAutoModeState.Stop;
  192. this.isThreadAlive = true;
  193. this.threadWorker = ThreadUtils.Invoke(this.ThreadWork);
  194. this.vehicle = vehicle;
  195. this.vehicle.OnMoveReady += Vehicle_OnMoveReady;
  196. this.vehicle.OnMoving += Vehicle_OnMoving;
  197. this.vehicle.OnMoveFinish += Vehicle_OnMoveFinish;
  198. this.vehicle.OnCharging += Vehicle_OnCharging;
  199. this.vehicle.OnChargingFull += Vehicle_OnChargingFull;
  200. }
  201. #region Lamp & Buzzer
  202. void LampStateChange(eLampState state)
  203. {
  204. this.iO.OutputOff("OUT_TOWER_LAMP_RED");
  205. this.iO.OutputOff("OUT_TOWER_LAMP_GREEN");
  206. switch (state)
  207. {
  208. case eLampState.Manual:
  209. case eLampState.Alarm:
  210. this.iO.OutputOn("OUT_TOWER_LAMP_RED");
  211. break;
  212. case eLampState.Charging:
  213. this.iO.OutputOn("OUT_TOWER_LAMP_RED");
  214. this.iO.OutputOn("OUT_TOWER_LAMP_GREEN");
  215. break;
  216. case eLampState.AutoRunNChargingFull:
  217. this.iO.OutputOn("OUT_TOWER_LAMP_GREEN");
  218. break;
  219. case eLampState.Blocked: //210812 Kkm 진행 막혀있는 상태 시 Buzzer 및 Lamp 상태 변경
  220. this.iO.OutputOn("OUT_TOWER_LAMP_RED");
  221. this.iO.OutputOn("OUT_TOWER_LAMP_GREEN");
  222. break;
  223. default:
  224. break;
  225. }
  226. }
  227. void BuzzerOnOff(bool isOn, eBuzzerKind kind = eBuzzerKind.Alarm)
  228. {
  229. this.iO.OutputOff("OUT_BUZZER_00");
  230. this.iO.OutputOff("OUT_BUZZER_01");
  231. this.iO.OutputOff("OUT_BUZZER_02");
  232. if (!isOn)
  233. return;
  234. //21.09.16. Kang. 주행중 Buzzer 사용 선택.
  235. if (kind == eBuzzerKind.Moving)
  236. {
  237. var useMovingBuzzer = sql.ConfigDal.Get(_ => _.ID.Equals(ConstString.UseMovingBuzzer)).FirstOrDefault();
  238. if (useMovingBuzzer != null)
  239. {
  240. if (useMovingBuzzer.Value.FwIntOf() <= 0)
  241. return;
  242. }
  243. }
  244. switch (kind)
  245. {
  246. case eBuzzerKind.Alarm:
  247. this.iO.OutputOn("OUT_BUZZER_00");
  248. break;
  249. case eBuzzerKind.StartWarn:
  250. this.iO.OutputOn("OUT_BUZZER_01");
  251. break;
  252. case eBuzzerKind.Moving:
  253. this.iO.OutputOn("OUT_BUZZER_02");
  254. break;
  255. //case eBuzzerKind.Blocked: //210812 Kkm 진행 막혀있는 상태 시 Buzzer 및 Lamp 상태 변경
  256. // break;
  257. default:
  258. break;
  259. }
  260. }
  261. #endregion
  262. void ThreadWork()
  263. {
  264. Thread.CurrentThread.Name = $"{this.GetType().Name}-Work";
  265. while (this.isThreadAlive)
  266. {
  267. try
  268. {
  269. Thread.Sleep(100);
  270. DoWork();
  271. }
  272. catch (Exception ex)
  273. {
  274. logger.E($"{GetType().Name} - Thread Exception : {ex.StackTrace}");
  275. }
  276. }
  277. logger.D("[AutoManager] - Work Thread Dispose");
  278. }
  279. public void DoWork()
  280. {
  281. switch (this.OperationModeProperty)
  282. {
  283. case eOperatationMode.ManualMode:
  284. break;
  285. case eOperatationMode.AutoMode:
  286. switch (this.AutoModeStateProperty)
  287. {
  288. case eAutoModeState.ErrorStop:
  289. this.AutoModeStateProperty = eAutoModeState.WaitStop;
  290. break;
  291. case eAutoModeState.WaitStop:
  292. this.AutoModeStateProperty = eAutoModeState.Stop;
  293. break;
  294. case eAutoModeState.Stop:
  295. if (IsAllProcessStop())
  296. {
  297. //TODO: 여기서 메인명령을 정리하자.
  298. this.sql.SubCmdDAL.Clean();
  299. this.sql.CommandDAL.Clean();
  300. this.OperationModeProperty = eOperatationMode.ManualMode;
  301. }
  302. break;
  303. case eAutoModeState.StartRun:
  304. if (IsAllProcessStart())
  305. this.AutoModeStateProperty = eAutoModeState.Run;
  306. break;
  307. case eAutoModeState.Run:
  308. break;
  309. default:
  310. break;
  311. }
  312. break;
  313. case eOperatationMode.InitialMode:
  314. break;
  315. default:
  316. break;
  317. }
  318. }
  319. public void ProcessAlarm(int alarmID)
  320. {
  321. HisAlarm hisAlarm = new HisAlarm();
  322. var alarm = this.Alarms.Where(x => x.AlarmId == alarmID).FirstOrDefault();
  323. if (alarm == null)
  324. {
  325. hisAlarm.AlarmId = alarmID;
  326. hisAlarm.Text = "Not Define Alarm";
  327. alarm = new Alarm();
  328. alarm.AlarmId = alarmID;
  329. alarm.Level = eAlarmLevel.Fault;
  330. alarm.Text = "Not Define Alarm";
  331. logger.E($"[{this.GetType().Name}] - Alarm Process / Not Define Alarm No {alarmID}");
  332. }
  333. else
  334. {
  335. hisAlarm.AlarmId = alarmID;
  336. hisAlarm.Text = alarm.Name + " - " + alarm.Text;
  337. hisAlarm.Solution = alarm.Solution;
  338. }
  339. //Add History
  340. sql.HisAlarmDAL.Insert(hisAlarm);
  341. logger.I($"[Alarm Occur] - ID : {alarmID} / Text : {hisAlarm.Text}");
  342. if (this.ActiveAlarms == null)
  343. return;
  344. if (!this.ActiveAlarms.Any(x => x.AlarmId == alarmID))
  345. {
  346. //OCS Report
  347. this.OnOccurAlarm?.Invoke(alarm.AlarmId);
  348. var cloneAlarm = ObjectCopyUtils.DeepClone<Alarm>(alarm);
  349. this.activeAlarm = cloneAlarm;
  350. this.ActiveAlarms.Add(cloneAlarm); //Clear 보고를 위한 List Add
  351. var args = new ActiveAlarmEventArgs(cloneAlarm);
  352. this.eventAggregator.GetEvent<ActiveAlarmPubSubEvent>().Publish(args);
  353. }
  354. if (alarm.Level == eAlarmLevel.Warn)
  355. return;
  356. this.AutoModeStateProperty = eAutoModeState.ErrorStop;
  357. this.LampStateProperty = eLampState.Alarm;
  358. this.BuzzerStateProperty = eBuzzerKind.Alarm;
  359. this.BuzzerOnOff(true, eBuzzerKind.Alarm);
  360. this.sql.CommandDAL.Clean();
  361. this.sql.SubCmdDAL.Clean();
  362. //UI 로는 처음 발생한 Error 만 전송한다.
  363. if (IsErrorProcessing)
  364. return;
  365. IsErrorProcessing = true;
  366. var msg = new GUIMessageEventArgs
  367. {
  368. Kind = GUIMessageEventArgs.eGUIMessageKind.ModelPropertyChange,
  369. MessageKey = MessageKey.Alarm,
  370. MessageText = hisAlarm.Text,
  371. Args = hisAlarm,
  372. };
  373. this.eventAggregator.GetEvent<GUIMessagePubSubEvent>().Publish(msg);
  374. }
  375. /// <summary>
  376. /// Alarm Clear 를 여기서 모아서 하자.
  377. /// </summary>
  378. /// <param name="alarmID"></param>
  379. public void ClearAlarm(int alarmID)
  380. {
  381. var alarm = this.ActiveAlarms.FirstOrDefault(x => x.AlarmId == alarmID);
  382. if (alarm == null)
  383. return;
  384. this.ActiveAlarms.Remove(alarm);
  385. logger.I($"[{this.GetType().Name}] - Alarm Clear [{alarmID}]");
  386. this.OnClearAlarm?.Invoke(alarm.AlarmId);
  387. var al = ObjectCopyUtils.DeepClone<Alarm>(alarm);
  388. var args = new ActiveAlarmEventArgs(al, false);
  389. this.eventAggregator.GetEvent<ActiveAlarmPubSubEvent>().Publish(args);
  390. }
  391. bool IsAllProcessStop()
  392. {
  393. if (vehicle.IsAutoRun)
  394. return false;
  395. return true;
  396. }
  397. bool IsAllProcessStart()
  398. {
  399. return vehicle.IsAutoRun;
  400. }
  401. #region IDisposable Support
  402. private bool disposedValue = false; // 중복 호출을 검색하려면
  403. protected virtual void Dispose(bool disposing)
  404. {
  405. if (!disposedValue)
  406. {
  407. if (disposing)
  408. {
  409. // TODO: 관리되는 상태(관리되는 개체)를 삭제합니다.
  410. this.isThreadAlive = false;
  411. if (!this.threadWorker.Join(3000))
  412. ThreadUtils.Kill(this.threadWorker);
  413. }
  414. // TODO: 관리되지 않는 리소스(관리되지 않는 개체)를 해제하고 아래의 종료자를 재정의합니다.
  415. // TODO: 큰 필드를 null로 설정합니다.
  416. disposedValue = true;
  417. }
  418. }
  419. // TODO: 위의 Dispose(bool disposing)에 관리되지 않는 리소스를 해제하는 코드가 포함되어 있는 경우에만 종료자를 재정의합니다.
  420. // ~AutoManager()
  421. // {
  422. // // 이 코드를 변경하지 마세요. 위의 Dispose(bool disposing)에 정리 코드를 입력하세요.
  423. // Dispose(false);
  424. // }
  425. // 삭제 가능한 패턴을 올바르게 구현하기 위해 추가된 코드입니다.
  426. public void Dispose()
  427. {
  428. // 이 코드를 변경하지 마세요. 위의 Dispose(bool disposing)에 정리 코드를 입력하세요.
  429. Dispose(true);
  430. // TODO: 위의 종료자가 재정의된 경우 다음 코드 줄의 주석 처리를 제거합니다.
  431. // GC.SuppressFinalize(this);
  432. }
  433. #endregion
  434. }
  435. }