EzIO.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  1. using GSG.NET.Concurrent;
  2. using GSG.NET.Excel;
  3. using GSG.NET.Logging;
  4. using GSG.NET.Quartz;
  5. using GSG.NET.Utils;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. using System.Threading;
  10. using VehicleControlSystem.ControlLayer.Lib.EziPlusE;
  11. namespace VehicleControlSystem.ControlLayer.IO
  12. {
  13. public partial class EzIO : IIO, IDisposable
  14. {
  15. #region Bit Mask
  16. public readonly uint[] bitOnMask =
  17. {
  18. 0x00000001, 0x00000002, 0x00000004, 0x00000008,
  19. 0x00000010, 0x00000020, 0x00000040, 0x00000080,
  20. 0x00000100, 0x00000200, 0x00000400, 0x00000800,
  21. 0x00001000, 0x00002000, 0x00004000, 0x00008000,
  22. 0x00010000, 0x00020000, 0x00040000, 0x00080000,
  23. 0x00100000, 0x00200000, 0x00400000, 0x00800000,
  24. 0x01000000, 0x02000000, 0x04000000, 0x08000000,
  25. 0x10000000, 0x20000000, 0x40000000, 0x80000000
  26. };
  27. public readonly uint[] bitOffMask =
  28. {
  29. 0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFB, 0xFFFFFFF7,
  30. 0xFFFFFFEF, 0xFFFFFFDF, 0xFFFFFFBF, 0xFFFFFF7F,
  31. 0xFFFFFEFF, 0xFFFFFDFF, 0xFFFFFBFF, 0xFFFFF7FF,
  32. 0xFFFFEFFF, 0xFFFFDFFF, 0xFFFFBFFF, 0xFFFF7FFF,
  33. 0xFFFEFFFF, 0xFFFDFFFF, 0xFFFBFFFF, 0xFFF7FFFF,
  34. 0xFFEFFFFF, 0xFFDFFFFF, 0xFFBFFFFF, 0xFF7FFFFF,
  35. 0xFEFFFFFF, 0xFDFFFFFF, 0xFBFFFFFF, 0xF7FFFFFF,
  36. 0xEFFFFFFF, 0xDFFFFFFF, 0xBFFFFFFF, 0x7FFFFFFF
  37. };
  38. public readonly uint[] servoAmpInputBitOnMask =
  39. {
  40. 0x04000000, 0x08000000, 0x10000000, 0x20000000,
  41. 0x40000000, 0x80000000, 0x00400000, 0x00800000,
  42. 0x01000000
  43. };
  44. public readonly uint[] servoAmpOutputBitMask =
  45. {
  46. 0x00008000, 0x00010000, 0x00020000, 0x00040000,
  47. 0x00080000, 0x00100000, 0x00200000, 0x00400000,
  48. 0x00800000
  49. };
  50. #endregion
  51. static Logger logger = Logger.GetLogger();
  52. bool IsThreadAlive = true;
  53. public List<EzBoard> BoardList = new List<EzBoard>();
  54. List<BitBlock> _inPutIOList = null;
  55. public List<BitBlock> InPutIOList
  56. {
  57. get => this._inPutIOList;
  58. }
  59. List<BitBlock> _outPutIOList = null;
  60. public List<BitBlock> OutPutIOList
  61. {
  62. get => this._outPutIOList;
  63. }
  64. UInt16[] _incomingBuffer;
  65. UInt16[] _outcomingBuffer;
  66. Thread _readThread;
  67. bool isConnectError = false;
  68. public bool IsConnectError
  69. {
  70. get => this.isConnectError;
  71. set
  72. {
  73. if (this.isConnectError == value)
  74. return;
  75. this.isConnectError = value;
  76. if (isConnectError)
  77. this.qQ.Enqueue(new QoDiconnected());
  78. else
  79. this.qQ.Enqueue(new QoConnected());
  80. }
  81. }
  82. TsMap<string, SyncObject> ddWaitChgBlock = new TsMap<string, SyncObject>();
  83. #region Pull Thread
  84. public TsQueue<QueueObject> qQ = new TsQueue<QueueObject>(512);
  85. public Thread pullThread;
  86. #endregion
  87. #region public Method
  88. public int GetBit(uint usIOAddr, bool pbval)
  89. {
  90. throw new NotImplementedException();
  91. }
  92. public int GetBit(string strIOAddr, bool pbVal)
  93. {
  94. throw new NotImplementedException();
  95. }
  96. public int GetByte(uint usIOAddr, byte pcValue)
  97. {
  98. throw new NotImplementedException();
  99. }
  100. public int GetByte(string strIOAddr, byte pcValue)
  101. {
  102. throw new NotImplementedException();
  103. }
  104. public int GetWord(uint usIOAddr, short pwValue)
  105. {
  106. throw new NotImplementedException();
  107. }
  108. public int GetWord(string strIOAddr, short pwValue)
  109. {
  110. throw new NotImplementedException();
  111. }
  112. public int Initialize(List<EzBoard> ezBoards)
  113. {
  114. this.BoardList = ezBoards;
  115. this._incomingBuffer = new ushort[ezBoards.Count];
  116. this._outcomingBuffer = new ushort[ezBoards.Count];
  117. this.IsThreadAlive = true;
  118. _readThread = new Thread(this.IOThread);
  119. this._readThread.IsBackground = true;
  120. this._readThread.Start();
  121. return 0;
  122. }
  123. #endregion
  124. public bool IsDeviceOpened()
  125. {
  126. throw new NotImplementedException();
  127. }
  128. public bool IsOff(uint usIOAddr)
  129. {
  130. throw new NotImplementedException();
  131. }
  132. public bool IsOff(string ioTag, bool isInput = true)
  133. {
  134. BitBlock bit = null;
  135. if (isInput)
  136. bit = this._inPutIOList.Where(x => ioTag.Equals(x.Tag)).FirstOrDefault();
  137. else
  138. bit = this._outPutIOList.Where(x => ioTag.Equals(x.Tag)).FirstOrDefault();
  139. return !bit.IsBitOn;
  140. }
  141. public bool IsOn(uint usIOAddr)
  142. {
  143. throw new NotImplementedException();
  144. }
  145. //public int IsOn( string strIOAddr, bool pbVal )
  146. //{
  147. // var io = this._inPutIOList.Where( x => strIOAddr.Equals( x.Tag ) ).FirstOrDefault();
  148. // if( io == null )
  149. // return -1;
  150. // else
  151. // {
  152. // }
  153. // return 0;
  154. //}
  155. public bool IsOn(string ioTag, bool isInput = true)
  156. {
  157. BitBlock bit = null;
  158. if (isInput)
  159. bit = this._inPutIOList.Where(x => ioTag.Equals(x.Tag)).FirstOrDefault();
  160. else
  161. bit = this._outPutIOList.Where(x => ioTag.Equals(x.Tag)).FirstOrDefault();
  162. return bit.IsBitOn;
  163. }
  164. public bool WaitChangeInputIO(bool exp, int timeout, string tag)
  165. {
  166. if (exp == IsOn(tag))
  167. return true;
  168. Assert.IsFalse(ddWaitChgBlock.ContainsKey(tag), "WaitChg InputIO already waiting:{0}", tag);
  169. try
  170. {
  171. var so = new SyncObject { };
  172. ddWaitChgBlock.Add(tag, so);
  173. so.Lock();
  174. return so.Await(timeout);
  175. }
  176. finally
  177. {
  178. this.ddWaitChgBlock.Remove(tag);
  179. }
  180. }
  181. public int LoadIOMap(string strFileName)
  182. {
  183. var bl = new ExcelMapper(strFileName).Fetch<EzBoard>("BOARD").ToList();
  184. this.BoardList = bl;
  185. var il = new ExcelMapper(strFileName).Fetch<BitBlock>("IN_IO").ToList();
  186. var inputIO = il.Where(x => !string.IsNullOrEmpty(x.Tag)).ToList();
  187. this._inPutIOList = inputIO;
  188. var ol = new ExcelMapper(strFileName).Fetch<BitBlock>("OUT_IO").ToList();
  189. var outputIO = ol.Where(x => !string.IsNullOrEmpty(x.Tag)).ToList();
  190. this._outPutIOList = outputIO;
  191. return 0;
  192. }
  193. public int OutputOff(uint usIOAddr)
  194. {
  195. throw new NotImplementedException();
  196. }
  197. public int OutputOff(string strIOAddr)
  198. {
  199. int result = 0;
  200. var outIO = this._outPutIOList.Where(x => strIOAddr.Equals(x.Tag)).FirstOrDefault();
  201. var boardType = this.BoardList.Where(x => x.BoardID == outIO.BoardNo).FirstOrDefault().BoardType;
  202. uint bitMask = 0;
  203. if (boardType == E_EzboardType.Servo)
  204. {
  205. bitMask = this.servoAmpOutputBitMask[outIO.Index];
  206. result = EziMOTIONPlusELib.FAS_SetIOOutput(outIO.BoardNo, 0, bitMask);
  207. }
  208. else
  209. {
  210. bitMask = bitOnMask[outIO.Index];
  211. result = EziMOTIONPlusELib.FAS_SetOutput(outIO.BoardNo, 0, bitMask);
  212. }
  213. return result;
  214. }
  215. public int OutputOn(uint usIOAddr)
  216. {
  217. //var outIO = this._inPutIOList.Where( x => strIOAddr.Equals( x.Tag ) ).FirstOrDefault();
  218. //EziMOTIONPlusELib.FAS_SetIOOutput( boardNo, writeMask, 0 );
  219. return 0;
  220. }
  221. public int OutputOn(string outputTag)
  222. {
  223. int result = 0;
  224. var outIO = this._outPutIOList.Where(x => outputTag.Equals(x.Tag)).FirstOrDefault();
  225. var boardType = this.BoardList.Where(x => x.BoardID == outIO.BoardNo).FirstOrDefault().BoardType;
  226. uint bitMask = 0;
  227. if (boardType == E_EzboardType.Servo)
  228. {
  229. bitMask = this.servoAmpOutputBitMask[outIO.Index];
  230. result = EziMOTIONPlusELib.FAS_SetIOOutput(outIO.BoardNo, bitMask, 0);
  231. }
  232. else
  233. {
  234. bitMask = bitOnMask[outIO.Index];
  235. result = EziMOTIONPlusELib.FAS_SetOutput(outIO.BoardNo, bitMask, 0);
  236. }
  237. return result;
  238. }
  239. #region 일정시간 이후 동작 구현
  240. void WriteOutputOn(string outputTag)
  241. {
  242. int result = 0;
  243. var outIO = this._outPutIOList.Where(x => outputTag.Equals(x.Tag)).FirstOrDefault();
  244. var boardType = this.BoardList.Where(x => x.BoardID == outIO.BoardNo).FirstOrDefault().BoardType;
  245. uint bitMask = 0;
  246. if (boardType == E_EzboardType.Servo)
  247. {
  248. bitMask = this.servoAmpOutputBitMask[outIO.Index];
  249. result = EziMOTIONPlusELib.FAS_SetIOOutput(outIO.BoardNo, bitMask, 0);
  250. }
  251. else
  252. {
  253. bitMask = bitOnMask[outIO.Index];
  254. result = EziMOTIONPlusELib.FAS_SetOutput(outIO.BoardNo, bitMask, 0);
  255. }
  256. }
  257. void WriteOutputOff(string strIOAddr)
  258. {
  259. int result = 0;
  260. var outIO = this._outPutIOList.Where(x => strIOAddr.Equals(x.Tag)).FirstOrDefault();
  261. var boardType = this.BoardList.Where(x => x.BoardID == outIO.BoardNo).FirstOrDefault().BoardType;
  262. uint bitMask = 0;
  263. if (boardType == E_EzboardType.Servo)
  264. {
  265. bitMask = this.servoAmpOutputBitMask[outIO.Index];
  266. result = EziMOTIONPlusELib.FAS_SetIOOutput(outIO.BoardNo, 0, bitMask);
  267. }
  268. else
  269. {
  270. bitMask = bitOnMask[outIO.Index];
  271. result = EziMOTIONPlusELib.FAS_SetOutput(outIO.BoardNo, 0, bitMask);
  272. }
  273. }
  274. public void WriteOutputIO(string tag, bool on, int after = 0)
  275. {
  276. if ( on)
  277. {
  278. if (after > 0)
  279. TimerUtils.Once(after, WriteOutputOn, tag);
  280. else
  281. WriteOutputOn(tag);
  282. }
  283. else
  284. {
  285. if (after > 0)
  286. TimerUtils.Once(after, WriteOutputOff, tag);
  287. else
  288. WriteOutputOff(tag);
  289. }
  290. }
  291. #endregion
  292. public int OutputToggle(uint usIOAddr)
  293. {
  294. throw new NotImplementedException();
  295. }
  296. public int OutputToggle(string strIOAddr)
  297. {
  298. throw new NotImplementedException();
  299. }
  300. public int PutByte(uint usIOAddr, byte pcValue)
  301. {
  302. throw new NotImplementedException();
  303. }
  304. public int PutByte(string strIOAddr, byte pcValue)
  305. {
  306. throw new NotImplementedException();
  307. }
  308. public int PutWord(uint usIOAddr, short pwValue)
  309. {
  310. throw new NotImplementedException();
  311. }
  312. public int PutWord(string strIOAddr, short pwValue)
  313. {
  314. throw new NotImplementedException();
  315. }
  316. #region Thread
  317. public void RunIOThread()
  318. {
  319. try
  320. {
  321. ThreadStart();
  322. }
  323. catch (Exception)
  324. {
  325. }
  326. finally
  327. {
  328. }
  329. }
  330. public void ThreadStart()
  331. {
  332. this.IsThreadAlive = true;
  333. this._readThread = ThreadUtils.Invoke(IOThread);
  334. this.pullThread = ThreadUtils.Invoke(PullQueueThread);
  335. }
  336. void IOThread()
  337. {
  338. var sTime = SwUtils.CurrentTimeMillis;
  339. while (IsThreadAlive)
  340. {
  341. Thread.Sleep(5);
  342. try
  343. {
  344. if (!IsConnetedAllBoard())
  345. {
  346. if (!ConnectAllBoard())
  347. {
  348. IsConnectError = true;
  349. }
  350. Thread.Sleep(1000);
  351. continue;
  352. }
  353. IsConnectError = false;
  354. ReadBoardIO();
  355. //Console.WriteLine( $"Read Time - { SwUtils.Elapsed( sTime ) } mm" );
  356. //sTime = SwUtils.CurrentTimeMillis;
  357. }
  358. catch (Exception ex)
  359. {
  360. logger.E($"Exception [EzIO IORead Thread] - {ex.StackTrace}");
  361. }
  362. }
  363. }
  364. void ReadBoardIO()
  365. {
  366. foreach (var board in this.BoardList)
  367. {
  368. if (!IsConnetedBoard(board.BoardID))
  369. continue;
  370. switch (board.BoardType)
  371. {
  372. case E_EzboardType.Servo:
  373. {
  374. uint axisDIn = 0, axisDOut = 0, axisStatus = 0;
  375. int cmdPos = 0, actPos = 0, posErr = 0, actVel = 0;
  376. ushort posItemNo = 0;
  377. if (EziMOTIONPlusELib.FAS_GetAllStatus(board.BoardID, ref axisDIn, ref axisDOut, ref axisStatus,
  378. ref cmdPos, ref actPos, ref posErr, ref actVel, ref posItemNo) == EziMOTIONPlusELib.FMM_OK)
  379. {
  380. var input = this._inPutIOList.Where(x => x.BoardNo == board.BoardID).DefaultIfEmpty().ToList();
  381. input.ForEach(i =>
  382. {
  383. var isOn = Convert.ToBoolean(axisDIn & this.servoAmpInputBitOnMask[i.Index]) ? true : false;
  384. if (i.IsBitOn != isOn) i.IsChanged = true;
  385. i.IsBitOn = isOn;
  386. });
  387. var output = this._outPutIOList.Where(x => x.BoardNo == board.BoardID).DefaultIfEmpty().ToList();
  388. output.ForEach(o =>
  389. {
  390. var isOn = Convert.ToBoolean(axisDOut & this.servoAmpOutputBitMask[o.Index]) ? true : false;
  391. if (o.IsBitOn != isOn) o.IsChanged = true;
  392. o.IsBitOn = isOn;
  393. });
  394. }
  395. }
  396. break;
  397. case E_EzboardType.IOInput:
  398. {
  399. uint inValue = 0, latchValue = 0;
  400. int result = EziMOTIONPlusELib.FMM_OK;
  401. result = EziMOTIONPlusELib.FAS_GetInput(board.BoardID, ref inValue, ref latchValue);
  402. if (result == EziMOTIONPlusELib.FMM_OK)
  403. {
  404. var input = this._inPutIOList.Where(x => x.BoardNo == board.BoardID).DefaultIfEmpty().ToList();
  405. input.ForEach(i =>
  406. {
  407. var isOn = Convert.ToBoolean(inValue & this.bitOnMask[i.Index]) ? true : false;
  408. if (i.IsBitOn != isOn) i.IsChanged = true;
  409. i.IsBitOn = isOn;
  410. });
  411. }
  412. else
  413. logger.E($"EzIO - [{board.BoardID}] Read Fail Error Code {result}");
  414. }
  415. break;
  416. case E_EzboardType.IOOutput:
  417. {
  418. uint outValue = 0, outStatus = 0;
  419. int result = EziMOTIONPlusELib.FMM_OK;
  420. result = EziMOTIONPlusELib.FAS_GetOutput(board.BoardID, ref outValue, ref outStatus);
  421. if (result == EziMOTIONPlusELib.FMM_OK)
  422. {
  423. var output = this._outPutIOList.Where(x => x.BoardNo == board.BoardID).DefaultIfEmpty().ToList();
  424. output.ForEach(o =>
  425. {
  426. var isOn = Convert.ToBoolean(outValue & this.bitOnMask[o.Index]) ? true : false;
  427. if (o.IsBitOn != isOn) o.IsChanged = true;
  428. o.IsBitOn = isOn;
  429. });
  430. }
  431. else
  432. logger.E($"EzIO - [{board.BoardID}] Read Fail Error Code {result}");
  433. }
  434. break;
  435. default:
  436. break;
  437. }
  438. }
  439. FireChangedIO();
  440. }
  441. void FireChangedIO()
  442. {
  443. this.InPutIOList.ForEach(i =>
  444. {
  445. if (i.IsChanged)
  446. {
  447. i.IsChanged = false;
  448. var clone = ObjectCopyUtils.DeepClone<BitBlock>(i);
  449. this.qQ.Enqueue(new QoChangedIO { Arg0 = clone });
  450. NotifySyncBit(clone);
  451. }
  452. });
  453. this.OutPutIOList.ForEach(o =>
  454. {
  455. if (o.IsChanged)
  456. {
  457. o.IsChanged = false;
  458. var clone = ObjectCopyUtils.DeepClone<BitBlock>(o);
  459. this.qQ.Enqueue(new QoChangedIO { Arg0 = clone });
  460. }
  461. });
  462. }
  463. void PullQueueThread()
  464. {
  465. for (; ; )
  466. {
  467. try
  468. {
  469. var o = qQ.Dequeue();
  470. if (o is QoConnected)
  471. DelegateUtils.Invoke(OnContd);
  472. else if (o is QoDiconnected)
  473. DelegateUtils.Invoke(OnDiscontd);
  474. else if (o is QoChangedIO)
  475. DelegateUtils.Invoke(OnChangedIO, o.Arg0);
  476. else if (o is QoWriteIO)
  477. DelegateUtils.Invoke(OnWriteIO, o.Arg0);
  478. else if (o is QoLog)
  479. DelegateUtils.Invoke(OnLog, o.Arg0, o.Arg1);
  480. else
  481. Assert.Fail("Unk Object {0}", o);
  482. }
  483. catch (ThreadAbortException) { }
  484. catch (Exception e)
  485. {
  486. logger.E(e);
  487. }
  488. }
  489. }
  490. #endregion
  491. /// <summary>
  492. /// InputIO 변경 알림
  493. /// </summary>
  494. /// <param name="block"></param>
  495. void NotifySyncBit(BitBlock block)
  496. {
  497. if (ddWaitChgBlock.ContainsKey(block.Tag))
  498. {
  499. var so = ddWaitChgBlock[block.Tag];
  500. so.Expect = block;
  501. so.Notify();
  502. }
  503. }
  504. bool IsConnetedBoard(int boardNo)
  505. {
  506. return EziMOTIONPlusELib.FAS_IsSlaveExist(boardNo) == 1;
  507. }
  508. bool IsConnetedAllBoard()
  509. {
  510. foreach (var b in this.BoardList)
  511. {
  512. if (!IsConnetedBoard(b.BoardID))
  513. {
  514. this.qQ.Clear();//연결이 끊어지면 내용을 삭제.
  515. return false;
  516. }
  517. }
  518. return true;
  519. }
  520. bool ConnectAllBoard()
  521. {
  522. foreach (var b in this.BoardList)
  523. {
  524. if (IsConnetedBoard(b.BoardID))
  525. continue;
  526. if (EziMOTIONPlusELib.FAS_Connect((byte)192, (byte)168, (byte)0, (byte)b.BoardID, b.BoardID) != EziMOTIONPlusELib.FMM_OK)
  527. {
  528. logger.E($"EzIO - Connect Fail {b.BoardID}");
  529. return false;
  530. }
  531. }
  532. return true;
  533. }
  534. public int Terminate()
  535. {
  536. this.IsThreadAlive = false;
  537. if (this._readThread != null && this._readThread.IsAlive)
  538. {
  539. if (!this._readThread.Join(3000))
  540. this._readThread.Abort();
  541. }
  542. this.BoardList.ForEach(b =>
  543. {
  544. EziMOTIONPlusELib.FAS_Close(b.BoardID);
  545. });
  546. return 0;
  547. }
  548. public int Initialize()
  549. {
  550. throw new NotImplementedException();
  551. }
  552. int GetModuleAndBitNoByAddress(uint usIOAddr, out int boardNo, out int bitNo)
  553. {
  554. long nOffset = 0;
  555. long nCount = 0;
  556. long nAddress = usIOAddr;
  557. int INPUT_ORIGIN = 1000;
  558. int OUTPUT_ORIGIN = 2000;
  559. boardNo = 0;
  560. bitNo = 0;
  561. if (usIOAddr < OUTPUT_ORIGIN)
  562. {
  563. nOffset = usIOAddr - INPUT_ORIGIN;
  564. for (int nModNo = 0; nModNo < this.BoardList.Count; nModNo++)
  565. {
  566. // Get Input CH Count Using Module ID
  567. //AxdInfoGetInputCount( nModNo, nCount );
  568. if (nOffset - nCount < 0)
  569. {
  570. boardNo = nModNo;
  571. bitNo = (int)nOffset;
  572. return 0;
  573. }
  574. nOffset -= nCount;
  575. }
  576. }
  577. else
  578. {
  579. nOffset = usIOAddr - OUTPUT_ORIGIN;
  580. for (int nModNo = 0; nModNo < this.BoardList.Count; nModNo++)
  581. {
  582. // Get Output CH Count Using Module ID
  583. //AxdInfoGetOutputCount( nModNo, nCount );
  584. if (nOffset - nCount < 0)
  585. {
  586. boardNo = nModNo;
  587. bitNo = (int)nOffset;
  588. return 0;
  589. }
  590. nOffset -= nCount;
  591. }
  592. }
  593. return 0;
  594. }
  595. #region IDisposable Support
  596. private bool disposedValue = false; // 중복 호출을 검색하려면
  597. protected virtual void Dispose(bool disposing)
  598. {
  599. if (!disposedValue)
  600. {
  601. if (disposing)
  602. {
  603. // TODO: 관리되는 상태(관리되는 개체)를 삭제합니다.
  604. if (this._readThread != null)
  605. {
  606. this.IsThreadAlive = false;
  607. if (!this._readThread.Join(3000) && this._readThread.IsAlive)
  608. {
  609. this._readThread.Abort();
  610. }
  611. this._readThread = null;
  612. }
  613. ThreadUtils.Kill(this.pullThread);
  614. Terminate(); //Board Close
  615. }
  616. // TODO: 관리되지 않는 리소스(관리되지 않는 개체)를 해제하고 아래의 종료자를 재정의합니다.
  617. // TODO: 큰 필드를 null로 설정합니다.
  618. disposedValue = true;
  619. }
  620. }
  621. // TODO: 위의 Dispose(bool disposing)에 관리되지 않는 리소스를 해제하는 코드가 포함되어 있는 경우에만 종료자를 재정의합니다.
  622. // ~EzIO()
  623. // {
  624. // // 이 코드를 변경하지 마세요. 위의 Dispose(bool disposing)에 정리 코드를 입력하세요.
  625. // Dispose(false);
  626. // }
  627. // 삭제 가능한 패턴을 올바르게 구현하기 위해 추가된 코드입니다.
  628. public void Dispose()
  629. {
  630. // 이 코드를 변경하지 마세요. 위의 Dispose(bool disposing)에 정리 코드를 입력하세요.
  631. Dispose(true);
  632. // TODO: 위의 종료자가 재정의된 경우 다음 코드 줄의 주석 처리를 제거합니다.
  633. // GC.SuppressFinalize(this);
  634. }
  635. #endregion
  636. }
  637. }