LightSourceManager.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading.Tasks;
  5. using TeamAAS.Communication.Interfaces;
  6. using TeamAAS.Communication.LightSources;
  7. namespace TeamAAS.Communication
  8. {
  9. /// <summary>
  10. /// 光源管理器。懒汉单例:<c>LightSourceManager.Instance</c>。
  11. /// 提供两种使用模式:
  12. /// 1) 直接调用:传入 serialDeviceName + LightModel,内部 new 临时 controller 执行完即释放;
  13. /// 2) 长期持有:通过 Register/Get/Remove 管理命名 controller,适合 UI 长期绑定场景。
  14. /// 同时保留静态工具方法(GetChannelCount/GetProtocolName)供反射或下拉框使用。
  15. /// </summary>
  16. public class LightSourceManager
  17. {
  18. #region 单例
  19. private static readonly Lazy<LightSourceManager> _instance =
  20. new Lazy<LightSourceManager>(() => new LightSourceManager(), isThreadSafe: true);
  21. /// <summary>
  22. /// 懒汉单例入口。首次访问时初始化,线程安全。
  23. /// </summary>
  24. public static LightSourceManager Instance => _instance.Value;
  25. #endregion
  26. #region 长期持有的控制器池
  27. private readonly object _poolLock = new object();
  28. private readonly Dictionary<string, LightSourceController> _pool =
  29. new Dictionary<string, LightSourceController>();
  30. /// <summary>
  31. /// 注册一个长期持有的光源控制器(按 name 索引)。
  32. /// 已存在同名 controller 会先 Dispose 旧的再替换。
  33. /// </summary>
  34. public LightSourceController Register(string name, LightModel model, ICommunication comm)
  35. {
  36. if (string.IsNullOrWhiteSpace(name))
  37. throw new ArgumentException("name 不能为空", nameof(name));
  38. if (comm == null)
  39. throw new ArgumentNullException(nameof(comm));
  40. var controller = new LightSourceController(model, GetChannelCount(model))
  41. {
  42. Name = name
  43. };
  44. controller.AttachCommunication(comm);
  45. LightSourceController old = null;
  46. lock (_poolLock)
  47. {
  48. if (_pool.TryGetValue(name, out old))
  49. _pool[name] = controller;
  50. else
  51. _pool.Add(name, controller);
  52. }
  53. if (old != null && !ReferenceEquals(old, controller))
  54. {
  55. try { old.Disconnect(); } catch { }
  56. try { old.Dispose(); } catch { }
  57. }
  58. return controller;
  59. }
  60. /// <summary>
  61. /// 获取已注册的光源控制器(按 name)。不存在返回 null。
  62. /// </summary>
  63. public LightSourceController Get(string name)
  64. {
  65. if (string.IsNullOrWhiteSpace(name)) return null;
  66. lock (_poolLock)
  67. {
  68. return _pool.TryGetValue(name, out var c) ? c : null;
  69. }
  70. }
  71. /// <summary>
  72. /// 移除并释放已注册的光源控制器。
  73. /// </summary>
  74. public bool Remove(string name)
  75. {
  76. if (string.IsNullOrWhiteSpace(name)) return false;
  77. LightSourceController controller;
  78. lock (_poolLock)
  79. {
  80. if (!_pool.TryGetValue(name, out controller))
  81. return false;
  82. _pool.Remove(name);
  83. }
  84. if (controller != null)
  85. {
  86. try { controller.Disconnect(); } catch { }
  87. try { controller.Dispose(); } catch { }
  88. }
  89. return true;
  90. }
  91. /// <summary>
  92. /// 获取所有已注册控制器的快照。
  93. /// </summary>
  94. public IReadOnlyList<LightSourceController> GetAll()
  95. {
  96. lock (_poolLock)
  97. {
  98. return _pool.Values.ToList().AsReadOnly();
  99. }
  100. }
  101. /// <summary>
  102. /// 清空并释放所有已注册控制器。
  103. /// </summary>
  104. public void Clear()
  105. {
  106. List<LightSourceController> snapshot;
  107. lock (_poolLock)
  108. {
  109. snapshot = _pool.Values.ToList();
  110. _pool.Clear();
  111. }
  112. foreach (var c in snapshot)
  113. {
  114. try { c.Disconnect(); } catch { }
  115. try { c.Dispose(); } catch { }
  116. }
  117. }
  118. #endregion
  119. #region 直接操作模式(按需 new 临时 controller)
  120. /// <summary>
  121. /// 直接设置亮度(不长期持有 controller)。
  122. /// </summary>
  123. public async Task<bool> SetBrightnessAsync(string serialDeviceName, LightModel model,
  124. int channel, int brightness, int timeoutMs = 1000)
  125. {
  126. var comm = ResolveCommunication(serialDeviceName);
  127. if (comm == null) return false;
  128. int channelCount = GetChannelCount(model);
  129. var controller = new LightSourceController(model, channelCount);
  130. try
  131. {
  132. controller.AttachCommunication(comm);
  133. return await controller.SetBrightnessAsync(channel, brightness, timeoutMs);
  134. }
  135. finally { controller.Dispose(); }
  136. }
  137. /// <summary>
  138. /// 直接全开(不长期持有 controller)。
  139. /// </summary>
  140. public async Task<bool> TurnOnAllAsync(string serialDeviceName, LightModel model,
  141. int timeoutMs = 1000)
  142. {
  143. var comm = ResolveCommunication(serialDeviceName);
  144. if (comm == null) return false;
  145. int channelCount = GetChannelCount(model);
  146. var controller = new LightSourceController(model, channelCount);
  147. try
  148. {
  149. controller.AttachCommunication(comm);
  150. return await controller.TurnOnAllAsync(timeoutMs);
  151. }
  152. finally { controller.Dispose(); }
  153. }
  154. /// <summary>
  155. /// 直接全关(不长期持有 controller)。
  156. /// </summary>
  157. public async Task<bool> TurnOffAllAsync(string serialDeviceName, LightModel model,
  158. int timeoutMs = 1000)
  159. {
  160. var comm = ResolveCommunication(serialDeviceName);
  161. if (comm == null) return false;
  162. int channelCount = GetChannelCount(model);
  163. var controller = new LightSourceController(model, channelCount);
  164. try
  165. {
  166. controller.AttachCommunication(comm);
  167. return await controller.TurnOffAllAsync(timeoutMs);
  168. }
  169. finally { controller.Dispose(); }
  170. }
  171. /// <summary>
  172. /// 直接读取某通道亮度(不长期持有 controller)。
  173. /// </summary>
  174. public async Task<int> ReadBrightnessAsync(string serialDeviceName, LightModel model,
  175. int channel, int timeoutMs = 1000)
  176. {
  177. var comm = ResolveCommunication(serialDeviceName);
  178. if (comm == null) return 0;
  179. int channelCount = GetChannelCount(model);
  180. var controller = new LightSourceController(model, channelCount);
  181. try
  182. {
  183. controller.AttachCommunication(comm);
  184. return await controller.ReadBrightnessAsync(channel, timeoutMs);
  185. }
  186. finally { controller.Dispose(); }
  187. }
  188. private ICommunication ResolveCommunication(string serialDeviceName)
  189. {
  190. if (string.IsNullOrWhiteSpace(serialDeviceName)) return null;
  191. var comm = CommunicationManager.Instance.GetByName(serialDeviceName);
  192. return comm?.IsConnected == true ? comm : null;
  193. }
  194. #endregion
  195. #region 静态工具方法
  196. /// <summary>
  197. /// 根据型号获取通道数量
  198. /// </summary>
  199. public static int GetChannelCount(LightModel model)
  200. {
  201. switch (model)
  202. {
  203. case LightModel.KCS_KDC_12V60W_4T: return 4;
  204. case LightModel.KCS_KDC3_24V300W_8T: return 8;
  205. case LightModel.TSD_DPA12024V_4T_3_0: return 4;
  206. default: return 4;
  207. }
  208. }
  209. /// <summary>
  210. /// 根据型号获取协议名称
  211. /// </summary>
  212. public static string GetProtocolName(LightModel model)
  213. {
  214. switch (model)
  215. {
  216. case LightModel.KCS_KDC_12V60W_4T:
  217. case LightModel.KCS_KDC3_24V300W_8T: return "KCS";
  218. case LightModel.TSD_DPA12024V_4T_3_0: return "TSD";
  219. default: return "Unknown";
  220. }
  221. }
  222. #endregion
  223. }
  224. }