EzIO.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  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().Type;
  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().Type;
  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().Type;
  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().Type;
  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. logger.D("[EzIO] - Dispose");
  364. }
  365. void ReadBoardIO()
  366. {
  367. foreach (var board in this.BoardList)
  368. {
  369. if (!IsConnetedBoard(board.BoardID))
  370. continue;
  371. switch (board.Type)
  372. {
  373. case E_EzboardType.Servo:
  374. {
  375. uint axisDIn = 0, axisDOut = 0, axisStatus = 0;
  376. int cmdPos = 0, actPos = 0, posErr = 0, actVel = 0;
  377. ushort posItemNo = 0;
  378. if (EziMOTIONPlusELib.FAS_GetAllStatus(board.BoardID, ref axisDIn, ref axisDOut, ref axisStatus,
  379. ref cmdPos, ref actPos, ref posErr, ref actVel, ref posItemNo) == EziMOTIONPlusELib.FMM_OK)
  380. {
  381. var input = this._inPutIOList.Where(x => x.BoardNo == board.BoardID).DefaultIfEmpty().ToList();
  382. input.ForEach(i =>
  383. {
  384. var isOn = Convert.ToBoolean(axisDIn & this.servoAmpInputBitOnMask[i.Index]) ? true : false;
  385. if (i.IsBitOn != isOn) i.IsChanged = true;
  386. i.IsBitOn = isOn;
  387. });
  388. var output = this._outPutIOList.Where(x => x.BoardNo == board.BoardID).DefaultIfEmpty().ToList();
  389. output.ForEach(o =>
  390. {
  391. var isOn = Convert.ToBoolean(axisDOut & this.servoAmpOutputBitMask[o.Index]) ? true : false;
  392. if (o.IsBitOn != isOn) o.IsChanged = true;
  393. o.IsBitOn = isOn;
  394. });
  395. }
  396. }
  397. break;
  398. case E_EzboardType.IOInput:
  399. {
  400. uint inValue = 0, latchValue = 0;
  401. int result = EziMOTIONPlusELib.FMM_OK;
  402. result = EziMOTIONPlusELib.FAS_GetInput(board.BoardID, ref inValue, ref latchValue);
  403. if (result == EziMOTIONPlusELib.FMM_OK)
  404. {
  405. var input = this._inPutIOList.Where(x => x.BoardNo == board.BoardID).DefaultIfEmpty().ToList();
  406. input.ForEach(i =>
  407. {
  408. var isOn = Convert.ToBoolean(inValue & this.bitOnMask[i.Index]) ? true : false;
  409. if (i.IsBitOn != isOn) i.IsChanged = true;
  410. i.IsBitOn = isOn;
  411. });
  412. }
  413. else
  414. logger.E($"EzIO - [{board.BoardID}] Read Fail Error Code {result}");
  415. }
  416. break;
  417. case E_EzboardType.IOOutput:
  418. {
  419. uint outValue = 0, outStatus = 0;
  420. int result = EziMOTIONPlusELib.FMM_OK;
  421. result = EziMOTIONPlusELib.FAS_GetOutput(board.BoardID, ref outValue, ref outStatus);
  422. if (result == EziMOTIONPlusELib.FMM_OK)
  423. {
  424. var output = this._outPutIOList.Where(x => x.BoardNo == board.BoardID).DefaultIfEmpty().ToList();
  425. output.ForEach(o =>
  426. {
  427. var isOn = Convert.ToBoolean(outValue & this.bitOnMask[o.Index]) ? true : false;
  428. if (o.IsBitOn != isOn) o.IsChanged = true;
  429. o.IsBitOn = isOn;
  430. });
  431. }
  432. else
  433. logger.E($"EzIO - [{board.BoardID}] Read Fail Error Code {result}");
  434. }
  435. break;
  436. default:
  437. break;
  438. }
  439. }
  440. FireChangedIO();
  441. }
  442. void FireChangedIO()
  443. {
  444. this.InPutIOList.ForEach(i =>
  445. {
  446. if (i.IsChanged)
  447. {
  448. i.IsChanged = false;
  449. var clone = ObjectCopyUtils.DeepClone<BitBlock>(i);
  450. this.qQ.Enqueue(new QoChangedIO { Arg0 = clone });
  451. NotifySyncBit(clone);
  452. }
  453. });
  454. this.OutPutIOList.ForEach(o =>
  455. {
  456. if (o.IsChanged)
  457. {
  458. o.IsChanged = false;
  459. var clone = ObjectCopyUtils.DeepClone<BitBlock>(o);
  460. this.qQ.Enqueue(new QoChangedIO { Arg0 = clone });
  461. }
  462. });
  463. }
  464. void PullQueueThread()
  465. {
  466. while(IsThreadAlive)
  467. {
  468. try
  469. {
  470. var o = qQ.Dequeue();
  471. if (o is QoConnected)
  472. DelegateUtils.Invoke(OnContd);
  473. else if (o is QoDiconnected)
  474. DelegateUtils.Invoke(OnDiscontd);
  475. else if (o is QoChangedIO)
  476. DelegateUtils.Invoke(OnChangedIO, o.Arg0);
  477. else if (o is QoWriteIO)
  478. DelegateUtils.Invoke(OnWriteIO, o.Arg0);
  479. else if (o is QoLog)
  480. DelegateUtils.Invoke(OnLog, o.Arg0, o.Arg1);
  481. else
  482. Assert.Fail("Unk Object {0}", o);
  483. }
  484. catch (ThreadAbortException)
  485. {
  486. }
  487. catch (Exception e)
  488. {
  489. logger.E(e);
  490. }
  491. }
  492. logger.D("[EzIO] - PullQueue Thread Dispose");
  493. }
  494. #endregion
  495. /// <summary>
  496. /// InputIO 변경 알림
  497. /// </summary>
  498. /// <param name="block"></param>
  499. void NotifySyncBit(BitBlock block)
  500. {
  501. if (ddWaitChgBlock.ContainsKey(block.Tag))
  502. {
  503. var so = ddWaitChgBlock[block.Tag];
  504. so.Expect = block;
  505. so.Notify();
  506. }
  507. }
  508. bool IsConnetedBoard(int boardNo)
  509. {
  510. return EziMOTIONPlusELib.FAS_IsSlaveExist(boardNo) == 1;
  511. }
  512. bool IsConnetedAllBoard()
  513. {
  514. foreach (var b in this.BoardList)
  515. {
  516. if (!IsConnetedBoard(b.BoardID))
  517. {
  518. this.qQ.Clear();//연결이 끊어지면 내용을 삭제.
  519. return false;
  520. }
  521. }
  522. return true;
  523. }
  524. bool ConnectAllBoard()
  525. {
  526. foreach (var b in this.BoardList)
  527. {
  528. if (IsConnetedBoard(b.BoardID))
  529. continue;
  530. var addr = b.IPAddress.Split( '.' );
  531. byte boardNo = Convert.ToByte( addr[3] );
  532. if (EziMOTIONPlusELib.FAS_Connect((byte)192, (byte)168, (byte)0, boardNo, b.BoardID ) != EziMOTIONPlusELib.FMM_OK)
  533. {
  534. logger.E($"EzIO - Connect Fail {b.BoardID}");
  535. return false;
  536. }
  537. }
  538. return true;
  539. }
  540. public int Terminate()
  541. {
  542. this.IsThreadAlive = false;
  543. if (this._readThread != null && this._readThread.IsAlive)
  544. {
  545. if (!this._readThread.Join(3000))
  546. this._readThread.Abort();
  547. }
  548. this.BoardList.ForEach(b =>
  549. {
  550. EziMOTIONPlusELib.FAS_Close(b.BoardID);
  551. });
  552. return 0;
  553. }
  554. public int Initialize()
  555. {
  556. throw new NotImplementedException();
  557. }
  558. int GetModuleAndBitNoByAddress(uint usIOAddr, out int boardNo, out int bitNo)
  559. {
  560. long nOffset = 0;
  561. long nCount = 0;
  562. long nAddress = usIOAddr;
  563. int INPUT_ORIGIN = 1000;
  564. int OUTPUT_ORIGIN = 2000;
  565. boardNo = 0;
  566. bitNo = 0;
  567. if (usIOAddr < OUTPUT_ORIGIN)
  568. {
  569. nOffset = usIOAddr - INPUT_ORIGIN;
  570. for (int nModNo = 0; nModNo < this.BoardList.Count; nModNo++)
  571. {
  572. // Get Input CH Count Using Module ID
  573. //AxdInfoGetInputCount( nModNo, nCount );
  574. if (nOffset - nCount < 0)
  575. {
  576. boardNo = nModNo;
  577. bitNo = (int)nOffset;
  578. return 0;
  579. }
  580. nOffset -= nCount;
  581. }
  582. }
  583. else
  584. {
  585. nOffset = usIOAddr - OUTPUT_ORIGIN;
  586. for (int nModNo = 0; nModNo < this.BoardList.Count; nModNo++)
  587. {
  588. // Get Output CH Count Using Module ID
  589. //AxdInfoGetOutputCount( nModNo, nCount );
  590. if (nOffset - nCount < 0)
  591. {
  592. boardNo = nModNo;
  593. bitNo = (int)nOffset;
  594. return 0;
  595. }
  596. nOffset -= nCount;
  597. }
  598. }
  599. return 0;
  600. }
  601. #region IDisposable Support
  602. private bool disposedValue = false; // 중복 호출을 검색하려면
  603. protected virtual void Dispose(bool disposing)
  604. {
  605. if (!disposedValue)
  606. {
  607. if (disposing)
  608. {
  609. // TODO: 관리되는 상태(관리되는 개체)를 삭제합니다.
  610. if (this.pullThread != null)
  611. {
  612. this.IsThreadAlive = false;
  613. if (!this.pullThread.Join(2000) && this.pullThread.IsAlive)
  614. {
  615. this.pullThread.Abort();
  616. }
  617. this.pullThread = null;
  618. }
  619. ThreadUtils.Kill(this.pullThread);
  620. Terminate(); //Board Close
  621. }
  622. // TODO: 관리되지 않는 리소스(관리되지 않는 개체)를 해제하고 아래의 종료자를 재정의합니다.
  623. // TODO: 큰 필드를 null로 설정합니다.
  624. disposedValue = true;
  625. }
  626. }
  627. // TODO: 위의 Dispose(bool disposing)에 관리되지 않는 리소스를 해제하는 코드가 포함되어 있는 경우에만 종료자를 재정의합니다.
  628. // ~EzIO()
  629. // {
  630. // // 이 코드를 변경하지 마세요. 위의 Dispose(bool disposing)에 정리 코드를 입력하세요.
  631. // Dispose(false);
  632. // }
  633. // 삭제 가능한 패턴을 올바르게 구현하기 위해 추가된 코드입니다.
  634. public void Dispose()
  635. {
  636. // 이 코드를 변경하지 마세요. 위의 Dispose(bool disposing)에 정리 코드를 입력하세요.
  637. Dispose(true);
  638. // TODO: 위의 종료자가 재정의된 경우 다음 코드 줄의 주석 처리를 제거합니다.
  639. // GC.SuppressFinalize(this);
  640. }
  641. #endregion
  642. }
  643. }