using OxyPlot; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using TeamAAS_VP.Core.PLCs; using TeamAAS_VP.Core.Robots; using TeamAAS_VP.Interfaces; using TeamAAS_VP.Models; using TeamAAS_VP.Resources.Languages; namespace TeamAAS_VP.Services { public class PlcService : IPlcService, IDisposable { private readonly Dictionary _plcCollection; private readonly object _sync = new object(); public PlcService() { _plcCollection = new Dictionary(); } public bool CreatePlc(Guid id, PlcInfo plcInfo) { if (plcInfo == null) throw new ArgumentNullException(nameof(plcInfo)); var plc = CreatePlcInstance(plcInfo); if (plc == null) return false; lock (_sync) { if (_plcCollection.ContainsKey(id)) { try { _plcCollection[id].Dispose(); } catch { // 忽略单个 Dispose 异常 } } _plcCollection[id] = plc; } return true; } public Task CreatePlcAsync(Guid id, PlcInfo plcInfo) { return Task.Run(() => CreatePlc(id, plcInfo)); } public IPlc GetPlc(Guid id) { lock (_sync) { if (_plcCollection.TryGetValue(id, out var plc)) return plc; } return null; } public Task GetPlcAsync(Guid id) { var plc = GetPlc(id); return Task.FromResult(plc); } public void UnRegisterPlc(Guid id) { IPlc plc = null; lock (_sync) { if (_plcCollection.TryGetValue(id, out plc)) { _plcCollection.Remove(id); } } if (plc != null) { try { plc.Dispose(); } catch { // 忽略释放异常 } } } public Task UnRegisterPlcAsync(Guid id) { UnRegisterPlc(id); return Task.CompletedTask; } public IReadOnlyCollection GetAllPlcs() { lock (_sync) { return _plcCollection.Values.ToList().AsReadOnly(); } } public Task> GetAllPlcsAsync() { var snapshot = GetAllPlcs(); return Task.FromResult(snapshot); } public bool TryGetPlc(Guid id, out IPlc plc) { lock (_sync) { return _plcCollection.TryGetValue(id, out plc); } } public Task<(bool found, IPlc plc)> TryGetPlcAsync(Guid id) { IPlc plc; bool found; lock (_sync) { found = _plcCollection.TryGetValue(id, out plc); } return Task.FromResult((found, plc)); } public bool ContainsPlc(Guid id) { lock (_sync) { return _plcCollection.ContainsKey(id); } } public Task ContainsPlcAsync(Guid id) { var exists = ContainsPlc(id); return Task.FromResult(exists); } public bool RemovePlc(Guid id) { IPlc plc = null; lock (_sync) { if (_plcCollection.TryGetValue(id, out plc)) { _plcCollection.Remove(id); } } if (plc != null) { try { plc.Dispose(); } catch { // 忽略释放异常 } return true; } return false; } public Task RemovePlcAsync(Guid id) { var removed = RemovePlc(id); return Task.FromResult(removed); } public IPlc GetPlcByNumber(int number) { if (TryFindPlcByNumber(number, out _, out var plc)) return plc; return null; } public Task GetPlcByNumberAsync(int number) { var plc = GetPlcByNumber(number); return Task.FromResult(plc); } public Task UnRegisterPlcByNumberAsync(int number) { UnRegisterPlcByNumber(number); return Task.CompletedTask; } public void UnRegisterPlcByNumber(int number) { if (TryFindPlcByNumber(number, out var id, out var plc)) { UnRegisterPlc(id); } } private IPlc CreatePlcInstance(PlcInfo plcInfo) { if (plcInfo == null) return null; if (plcInfo.CommunicationType == Enums.CommunicationType.OPC_UA_Client) { return new OpcUaClientPLC(plcInfo); } return null; } private bool TryFindPlcByNumber(int number, out Guid id, out IPlc plc) { lock (_sync) { foreach (var kvp in _plcCollection) { var p = kvp.Value; if (p == null) continue; if (p.Index==number) { id = kvp.Key; plc = kvp.Value; return true; } } } id = Guid.Empty; plc = null; return false; } public void Dispose() { List plcs; lock (_sync) { plcs = _plcCollection.Values.ToList(); _plcCollection.Clear(); } foreach (var p in plcs) { try { p.Dispose(); } catch { // 忽略单个释放异常 } } GC.SuppressFinalize(this); } public (bool IsSucceed, string Message) InitializePlc(PlcInfo[] plcs) { if (plcs == null) { return (false, Lang.plcs参数为null); } if (plcs.Length == 0) { return (true, Lang.没有需要初始化的PLC); } var failures = new List(); var successes = 0; for (var i = 0; i < plcs.Length; i++) { var info = plcs[i]; if (info == null) { failures.Add(string.Format(Lang.索引0PlcInfo为null,i)); continue; } // 尝试从 plcInfo 中提取编号(若有) int? number = null; try { var infoType = info.GetType(); var numberProp = infoType.GetProperty("PlcNo") ?? infoType.GetProperty("PlcNumber") ?? infoType.GetProperty("Number") ?? infoType.GetProperty("No"); if (numberProp != null) { var raw = numberProp.GetValue(info); if (raw != null) { if (raw is int ri) number = ri; else { try { number = Convert.ToInt32(raw); } catch { number = null; } } } } } catch { number = null; } // 如果存在相同编号的 PLC,则先卸载它 try { if (number.HasValue) { if (TryFindPlcByNumber(number.Value, out var existingId, out var existingPlc)) { try { UnRegisterPlc(existingId); } catch { // 忽略单个卸载异常,之后尝试创建新的实例 } } } } catch { // 忽略查找/卸载过程中的异常,继续尝试创建 } var id = Guid.NewGuid(); bool created; try { created = CreatePlc(id, info); } catch (Exception ex) { created = false; failures.Add($"{Lang.索引} {i}{(number.HasValue ? $" (编号 {number.Value})" : "")}: {Lang.创建PLC时抛出异常}{ex.Message}"); } if (!created) { failures.Add($"{Lang.索引} {i}{(number.HasValue ? $" (编号 {number.Value})" : "")}: {Lang.创建PLC失败}"); } else { successes++; } } if (failures.Count == 0) { return (true, string.Format(Lang.已成功初始化0个PLC, successes)); } var message = string.Format(Lang.初始化完成0成功1失败2失败原因3, successes, failures.Count, string.Join(" | ", failures)); return (false, message); } public Task<(bool IsSucceed, string Message)> InitializePlcAsync(PlcInfo[] plcs) { return Task.Run(() => InitializePlc(plcs)); } public bool RemoveAllPlcs() { List plcs; lock (_sync) { if (_plcCollection.Count == 0) return false; plcs = _plcCollection.Values.ToList(); _plcCollection.Clear(); } var removedAny = false; foreach (var p in plcs) { if (p == null) continue; try { p.Dispose(); removedAny = true; } catch { // 忽略单个释放异常 removedAny = true; // 已尝试移除,仍视为移除过 } } return removedAny; } public Task RemoveAllPlcsAsync() { var result = RemoveAllPlcs(); return Task.FromResult(result); } /// /// 更新PLC编号 /// /// /// public void UpdatePlcNumber(Guid id, int newNumber) { lock (_sync) { if (_plcCollection.TryGetValue(id, out var plc)) { if (plc != null) { plc.Index=newNumber; } } } } } }