ScannerService.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using TeamAAS_VP.Core.PLCs;
  7. using TeamAAS_VP.Core.Robots;
  8. using TeamAAS_VP.Core.Scanners;
  9. using TeamAAS_VP.Interfaces;
  10. using TeamAAS_VP.Models;
  11. using TeamAAS_VP.Models.Scanner;
  12. namespace TeamAAS_VP.Services
  13. {
  14. public class ScannerService : IScannerService, IDisposable
  15. {
  16. private readonly IPlcService _plcService;
  17. private readonly Dictionary<Guid, IScanner> _scannerCollection;
  18. private readonly object _sync = new object();
  19. public ScannerService(IPlcService plcService)
  20. {
  21. _scannerCollection = new Dictionary<Guid, IScanner>();
  22. _plcService = plcService;
  23. }
  24. /// <summary>
  25. /// 创建扫码枪
  26. /// </summary>
  27. /// <param name="id"></param>
  28. /// <param name="robotInfo"></param>
  29. /// <returns></returns>
  30. /// <exception cref="ArgumentNullException"></exception>
  31. public bool CreateScanner(Guid id, ScannerInfo scannerInfo)
  32. {
  33. if (scannerInfo == null) throw new ArgumentNullException(nameof(scannerInfo));
  34. var scanner = CreateScannerInstance(scannerInfo);
  35. scanner.Id = id;
  36. lock (_sync)
  37. {
  38. if (_scannerCollection.ContainsKey(id))
  39. {
  40. var currentScanner = _scannerCollection[id];
  41. try
  42. {
  43. currentScanner.Dispose();
  44. }
  45. catch
  46. {
  47. // 忽略单个扫码枪 Dispose 异常,继续替换
  48. }
  49. }
  50. _scannerCollection[id] = scanner;
  51. }
  52. return true;
  53. }
  54. /// <summary>
  55. /// 创建扫码枪
  56. /// </summary>
  57. /// <param name="id"></param>
  58. /// <param name="scannerInfo"></param>
  59. /// <returns></returns>
  60. public Task<bool> CreateScannerAsync(Guid id, ScannerInfo scannerInfo)
  61. {
  62. return Task.Run(() =>
  63. {
  64. return CreateScanner(id, scannerInfo);
  65. });
  66. }
  67. public IScanner GetScanner(Guid id)
  68. {
  69. lock (_sync)
  70. {
  71. if (_scannerCollection.TryGetValue(id, out var scanner))
  72. {
  73. return scanner;
  74. }
  75. }
  76. return null;
  77. }
  78. public Task<IScanner> GetScannerAsync(Guid id)
  79. {
  80. return Task.Run(() =>
  81. {
  82. return GetScanner(id);
  83. });
  84. }
  85. public void UnRegisterScanner(Guid id)
  86. {
  87. IScanner scanner = null;
  88. lock (_sync)
  89. {
  90. if (_scannerCollection.TryGetValue(id, out scanner))
  91. {
  92. _scannerCollection.Remove(id);
  93. }
  94. }
  95. if (scanner != null)
  96. {
  97. try
  98. {
  99. scanner.Dispose();
  100. }
  101. catch
  102. {
  103. // 忽略释放异常
  104. }
  105. }
  106. }
  107. public Task UnRegisterScannerAsync(Guid id)
  108. {
  109. return Task.Run(() => UnRegisterScanner(id));
  110. }
  111. /// <summary>
  112. /// 获取所有扫码枪
  113. /// </summary>
  114. /// <returns></returns>
  115. public IReadOnlyCollection<IScanner> GetAllScanners()
  116. {
  117. lock (_sync)
  118. {
  119. return _scannerCollection.Values.ToList().AsReadOnly();
  120. }
  121. }
  122. public Task<IReadOnlyCollection<IScanner>> GetAllScannersAsync()
  123. {
  124. return Task.Run(() =>
  125. {
  126. return GetAllScanners();
  127. });
  128. }
  129. /// <summary>
  130. /// 尝试获取扫码枪
  131. /// </summary>
  132. /// <param name="id"></param>
  133. /// <param name="scanner"></param>
  134. /// <returns></returns>
  135. public bool TryGetScanner(Guid id, out IScanner scanner)
  136. {
  137. lock (_sync)
  138. {
  139. return _scannerCollection.TryGetValue(id, out scanner);
  140. }
  141. }
  142. public Task<(bool found, IScanner scanner)> TryGetScannerAsync(Guid id)
  143. {
  144. return Task.Run(() =>
  145. {
  146. IScanner scanner;
  147. bool found;
  148. lock (_sync)
  149. {
  150. found = _scannerCollection.TryGetValue(id, out scanner);
  151. }
  152. return (found, scanner);
  153. });
  154. }
  155. /// <summary>
  156. /// 检查是否存在
  157. /// </summary>
  158. /// <param name="id"></param>
  159. /// <returns></returns>
  160. public bool ContainsScanner(Guid id)
  161. {
  162. lock (_sync)
  163. {
  164. return _scannerCollection.ContainsKey(id);
  165. }
  166. }
  167. public Task<bool> ContainsScannerAsync(Guid id)
  168. {
  169. return Task.Run(() =>
  170. {
  171. return ContainsScanner(id);
  172. });
  173. }
  174. /// <summary>
  175. /// 移除扫码枪并释放资源,返回是否成功移除
  176. /// </summary>
  177. /// <param name="id"></param>
  178. /// <returns></returns>
  179. public bool RemoveScanner(Guid id)
  180. {
  181. IScanner scanner = null;
  182. lock (_sync)
  183. {
  184. if (_scannerCollection.TryGetValue(id, out scanner))
  185. {
  186. _scannerCollection.Remove(id);
  187. }
  188. }
  189. if (scanner != null)
  190. {
  191. try
  192. {
  193. scanner.Dispose();
  194. }
  195. catch
  196. {
  197. // 忽略释放异常
  198. }
  199. return true;
  200. }
  201. return false;
  202. }
  203. public Task<bool> RemoveScannerAsync(Guid id)
  204. {
  205. return Task.Run(() =>
  206. {
  207. return RemoveScanner(id);
  208. });
  209. }
  210. public IScanner GetScannerByNumber(int scannerNo)
  211. {
  212. if (TryFindScannerByNumber(scannerNo, out _, out var scanner))
  213. {
  214. return scanner;
  215. }
  216. return null;
  217. }
  218. public Task<IScanner> GetScannerByNumberAsync(int scannerNo)
  219. {
  220. return Task.Run(() =>
  221. {
  222. return GetScannerByNumber(scannerNo);
  223. });
  224. }
  225. public Task UnRegisterScannerByNumberAsync(int scannerNo)
  226. {
  227. return Task.Run(() => UnRegisterScannerByNumber(scannerNo));
  228. }
  229. public void UnRegisterScannerByNumber(int scannerNo)
  230. {
  231. if (TryFindScannerByNumber(scannerNo, out var id, out var scanner))
  232. {
  233. // 复用已有的方法以保持行为一致(线程安全、异常处理)
  234. UnRegisterScanner(id);
  235. }
  236. }
  237. /// <summary>
  238. /// 移除所有扫码枪
  239. /// </summary>
  240. public void RemoveAllScanners()
  241. {
  242. //依次移除每个扫码枪,确保资源释放
  243. List<Guid> scannerIds;
  244. lock (_sync)
  245. {
  246. scannerIds = _scannerCollection.Keys.ToList();
  247. }
  248. foreach (var id in scannerIds)
  249. {
  250. RemoveScanner(id);
  251. }
  252. }
  253. /// <summary>
  254. /// 初始化所有扫码枪
  255. /// </summary>
  256. /// <param name="scanners"></param>
  257. /// <returns></returns>
  258. public (bool IsSucceed, string Message) InitializeAllScanners(ScannerInfo[] scanners)
  259. {
  260. //清除现有扫码枪集合
  261. RemoveAllScanners();
  262. //根据传入的扫码枪信息数组,依次创建并注册扫码枪实例
  263. foreach (var scannerInfo in scanners)
  264. {
  265. var scanner = CreateScannerInstance(scannerInfo);
  266. lock (_sync)
  267. {
  268. _scannerCollection[scanner.Id] = scanner;
  269. }
  270. }
  271. bool allConnected = true;
  272. StringBuilder errorMessages = new StringBuilder();
  273. //获取所有扫码枪并连接
  274. var allScanners = GetAllScanners();
  275. foreach (var scanner in allScanners)
  276. {
  277. try
  278. {
  279. scanner.Connect();
  280. }
  281. catch
  282. {
  283. //忽略单个扫码枪连接异常,继续连接其他扫码枪
  284. }
  285. if (!scanner.IsConnected)
  286. {
  287. allConnected = false;
  288. errorMessages.AppendLine($"扫码枪[{scanner.Name}]连接失败。");
  289. }
  290. }
  291. if (allConnected)
  292. {
  293. return (true, "所有扫码枪初始化并连接成功。");
  294. }
  295. else
  296. {
  297. return (false, errorMessages.ToString());
  298. }
  299. }
  300. /// <summary>
  301. /// 初始化所有扫码枪 (异步)
  302. /// </summary>
  303. /// <param name="scanners"></param>
  304. /// <returns></returns>
  305. public Task<(bool IsSucceed, string Message)> InitializeAllScannersAsync(ScannerInfo[] scanners)
  306. {
  307. return Task.Run(() =>
  308. {
  309. return InitializeAllScanners(scanners);
  310. });
  311. }
  312. // 私有工厂方法,避免重复代码
  313. private IScanner CreateScannerInstance(ScannerInfo scannerInfo)
  314. {
  315. if (scannerInfo == null) throw new ArgumentNullException(nameof(scannerInfo));
  316. IScanner scanner;
  317. if (scannerInfo.ScannerBrand == Enums.ScannerBrand.NLS)
  318. {
  319. scanner = new NlsScanner(scannerInfo);
  320. }
  321. else
  322. {
  323. scanner = new NlsScanner(scannerInfo);
  324. }
  325. return scanner;
  326. }
  327. /// <summary>
  328. /// 更新扫码枪编号
  329. /// </summary>
  330. /// <param name="id"></param>
  331. /// <param name="newNumber"></param>
  332. public void UpdateScannerNumber(Guid id, int newNumber)
  333. {
  334. IScanner scanner;
  335. lock (_sync)
  336. {
  337. if (_scannerCollection.TryGetValue(id, out scanner))
  338. {
  339. scanner.ScannerNo = newNumber;
  340. }
  341. }
  342. }
  343. // 私有帮助方法:通过扫码枪编号查找字典中的条目(线程安全)
  344. private bool TryFindScannerByNumber(int scannerNo, out Guid id, out IScanner scanner)
  345. {
  346. lock (_sync)
  347. {
  348. foreach (var kvp in _scannerCollection)
  349. {
  350. var r = kvp.Value;
  351. if (r == null) continue;
  352. object rawValue = null;
  353. var type = r.GetType();
  354. // 1. 直接在扫码枪对象上查找常见编号属性
  355. var prop = type.GetProperty("ScannerNo") ??
  356. type.GetProperty("ScannerNumber") ??
  357. type.GetProperty("Number") ??
  358. type.GetProperty("No");
  359. if (prop != null)
  360. {
  361. try
  362. {
  363. rawValue = prop.GetValue(r);
  364. }
  365. catch
  366. {
  367. rawValue = null;
  368. }
  369. }
  370. // 2. 如果未找到,尝试从 RobotInfo / Info 属性中获取编号
  371. if (rawValue == null)
  372. {
  373. var infoProp = type.GetProperty("ScannerInfo") ?? type.GetProperty("Info");
  374. if (infoProp != null)
  375. {
  376. try
  377. {
  378. var infoObj = infoProp.GetValue(r);
  379. if (infoObj != null)
  380. {
  381. var infoType = infoObj.GetType();
  382. var numberProp = infoType.GetProperty("ScannerNo") ??
  383. infoType.GetProperty("ScannerNumber") ??
  384. infoType.GetProperty("Number") ??
  385. infoType.GetProperty("No");
  386. if (numberProp != null)
  387. {
  388. try
  389. {
  390. rawValue = numberProp.GetValue(infoObj);
  391. }
  392. catch
  393. {
  394. rawValue = null;
  395. }
  396. }
  397. }
  398. }
  399. catch
  400. {
  401. // 忽略反射读取错误
  402. rawValue = null;
  403. }
  404. }
  405. }
  406. if (rawValue != null)
  407. {
  408. int parsed;
  409. try
  410. {
  411. if (rawValue is int) parsed = (int)rawValue;
  412. else parsed = Convert.ToInt32(rawValue);
  413. }
  414. catch
  415. {
  416. // 不能转换则跳过
  417. continue;
  418. }
  419. if (parsed == scannerNo)
  420. {
  421. id = kvp.Key;
  422. scanner = r;
  423. return true;
  424. }
  425. }
  426. }
  427. }
  428. id = Guid.Empty;
  429. scanner = null;
  430. return false;
  431. }
  432. // 实现 IDisposable,释放所有扫码枪并清空集合
  433. public void Dispose()
  434. {
  435. List<IScanner> scanners;
  436. lock (_sync)
  437. {
  438. scanners = _scannerCollection.Values.ToList();
  439. _scannerCollection.Clear();
  440. }
  441. foreach (var r in scanners)
  442. {
  443. try
  444. {
  445. r.Dispose();
  446. }
  447. catch
  448. {
  449. // 忽略单个释放异常
  450. }
  451. }
  452. GC.SuppressFinalize(this);
  453. }
  454. }
  455. }