Fins_Tcp.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. namespace Universal.IO;
  2. public class Fins_Tcp : IDisposable
  3. {
  4. private FinsTcpBase? _Service;
  5. private ITcpConnectNority? _tcpConnect;
  6. private string _IP = string.Empty;
  7. private int _port = 0;
  8. private Timer? _reconnectTimer;
  9. private Timer? _heartBeatTimer;
  10. private volatile ushort _heartBeatMissCount = 0;
  11. private ushort _maxHeartBeatMissCount = 5;
  12. private Func<bool>? _heartBeatCallBack;
  13. public bool Initialize(ITcpConnectNority? tcpConnect)
  14. {
  15. if (this._Service is not null)
  16. return false;
  17. this._Service = new FinsTcpBase();
  18. this._tcpConnect = tcpConnect;
  19. return true;
  20. }
  21. public bool Connect(string IP, int port, Func<bool> func, ushort heartBeatMissCount = 5, short heartBeatInterval = 1000, int sendTimeout = 1000, int receiveTimeout = 1000)
  22. {
  23. if (this._Service is null)
  24. return false;
  25. this._IP = IP;
  26. this._port = port;
  27. try
  28. {
  29. if (!this._Service.Link(IP, port, sendTimeout, receiveTimeout))
  30. return false;
  31. this._tcpConnect?.Connect(IP, port);
  32. this.StartHeartBeat(func, heartBeatMissCount, heartBeatInterval);
  33. }
  34. catch
  35. {
  36. return false;
  37. }
  38. return true;
  39. }
  40. private bool StartHeartBeat(Func<bool> func, ushort missCount = 5, short interval_ms = 1000)
  41. {
  42. if (this._heartBeatTimer is not null)
  43. return false;
  44. if (this._Service is null)
  45. return false;
  46. if (func is null)
  47. return false;
  48. this._maxHeartBeatMissCount = missCount;
  49. this._heartBeatCallBack = func;
  50. this._heartBeatTimer = new(HeatBeaterTimerCallBack, func, 0, interval_ms);
  51. return true;
  52. }
  53. private void HeatBeaterTimerCallBack(object? state)
  54. {
  55. if (this._heartBeatCallBack is null)
  56. return;
  57. if (this._heartBeatCallBack.Invoke())
  58. return;
  59. if (++_heartBeatMissCount <= this._maxHeartBeatMissCount)
  60. return;
  61. this._heartBeatTimer?.Dispose();
  62. this._tcpConnect?.DisConnect(this._IP, this._port);
  63. StartAutoReconnectTimer();
  64. }
  65. private void StartAutoReconnectTimer()
  66. {
  67. this._heartBeatTimer?.Dispose();
  68. this._heartBeatTimer = null;
  69. this._heartBeatMissCount = 0;
  70. this._reconnectTimer = new(ReconnectTimerCallBack, null, 0, 3000);
  71. }
  72. private void ReconnectTimerCallBack(object? state)
  73. {
  74. this._Service?.Close();
  75. this._Service = null;
  76. this._heartBeatTimer?.Dispose();
  77. this.Initialize(this._tcpConnect);
  78. if (!this.Connect(this._IP, this._port, this._heartBeatCallBack!, this._maxHeartBeatMissCount))
  79. return;
  80. this._reconnectTimer?.Dispose();
  81. }
  82. public bool GetData<T>(string address, out T? data)
  83. {
  84. data = default;
  85. if (this._Service is null)
  86. return false;
  87. try
  88. {
  89. switch (Type.GetTypeCode(typeof(T)))
  90. {
  91. case TypeCode.Boolean:
  92. if (!this._Service.GetBitState(address, out short state))
  93. return false;
  94. data = (T)(object)state;
  95. return true;
  96. case TypeCode.Int16:
  97. if (!this._Service.ReadWord(address, out short s))
  98. return false;
  99. data = (T)(object)s;
  100. return true;
  101. case TypeCode.Int32:
  102. if (!this._Service.ReadInt32(address, out int i))
  103. return false;
  104. data = (T)(object)i;
  105. return true;
  106. case TypeCode.Single:
  107. if (!this._Service.ReadReal(address, out float f))
  108. return false;
  109. data = (T)(object)f;
  110. return true;
  111. default:
  112. return false;
  113. }
  114. }
  115. catch
  116. {
  117. return false;
  118. }
  119. }
  120. public bool SetData<T>(string address, T data) where T : new()
  121. {
  122. if (this._Service is null)
  123. return false;
  124. try
  125. {
  126. return data switch
  127. {
  128. bool b => this._Service.SetBitState(address, b ? BitState.ON : BitState.OFF),
  129. short s => this._Service.WriteWord(address, s),
  130. int i => this._Service.WriteInt32(address, i),
  131. float f => this._Service.WriteReal(address, f),
  132. _ => false
  133. };
  134. }
  135. catch
  136. {
  137. return false;
  138. }
  139. }
  140. #region Dispose
  141. private bool disposedValue;
  142. protected virtual void Dispose(bool disposing)
  143. {
  144. if (!disposedValue)
  145. {
  146. if (disposing)
  147. {
  148. this._Service?.Close();
  149. this._Service = null;
  150. this._heartBeatTimer?.Dispose();
  151. this._reconnectTimer?.Dispose();
  152. this._tcpConnect?.DisConnect(this._IP, this._port);
  153. this._heartBeatMissCount = 0;
  154. }
  155. disposedValue = true;
  156. }
  157. }
  158. public void Dispose()
  159. {
  160. // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
  161. Dispose(disposing: true);
  162. GC.SuppressFinalize(this);
  163. }
  164. #endregion
  165. }