using Cognex.VisionPro; using CSScripting; using Prism.Events; using Prism.Ioc; using Prism.Mvvm; using Prism.Regions; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Media; using Team.FFFeederService.Interfaces; using TeamAAS_VP.Core.PLCs; using TeamAAS_VP.Core.ScrewDriver; using TeamAAS_VP.Enums; using TeamAAS_VP.Events; using TeamAAS_VP.Interfaces; using TeamAAS_VP.Models; using TeamAAS_VP.Resources.Languages; using TeamAAS_VP.ViewModels; using TeamAAS_VP.ViewModels.Home; using TouchSocket.Core; using TouchSocket.Sockets; namespace TeamAAS_VP.Core { public class Management : BindableBase { #region 字段 IRegionManager _regionManager; IEventAggregator _eventAggregator; IContainerProvider _container; IConfigService _configService; IRobotService _robotService; ICameraService _cameraService; IFeederService _feederService; IPlcService _plcService; ILightManagerService _lightManagerService; IProductService _productService; ICalibrationService _calibrationService; IRemoteCommandService _remoteCommandService; ISystemDatabaseService _systemDatabaseService; IMesService _mesService; Timer yieldtimer; private DateTime StartTime = DateTime.Now; /// /// 产品主sn /// string ProductMainSN = ""; string wo = ""; #endregion #region 属性 public string[] CsvData = new string[50]; public int[] ResultData = new int[200]; public string code = ""; List lockResultsAll = new List();//一个产品的总结果 private ObservableCollection _Renders; private double _CTtime; public int ResultDataCount; private bool _ShowMes_Query; /// /// 显示查询结果 /// public bool ShowMes_Query { get { return _ShowMes_Query; } set { SetProperty(ref _ShowMes_Query, value); } } private bool _ShowMes_Result; /// /// 显示上传结果 /// public bool ShowMes_Result { get { return _ShowMes_Result; } set { SetProperty(ref _ShowMes_Result, value); } } /// /// ct /// public double CTtime { get { return _CTtime; } set { SetProperty(ref _CTtime, value); } } /// /// 显示界面 /// public ObservableCollection Renders { get { return _Renders; } set { SetProperty(ref _Renders, value); } } private ProductModel _CurrentProduct; /// /// 当前产品 /// public ProductModel CurrentProduct { get { return _CurrentProduct; } set { SetProperty(ref _CurrentProduct, value); } } public BgCommunicate BgCommunicate { get; private set; } public BgModbusTcpCommunicate BgModbusTcpCommunicate { get; private set; } private ObservableCollection _Status = new ObservableCollection(); /// /// 状态栏集合 /// public ObservableCollection Status { get { return _Status; } set { SetProperty(ref _Status, value); } } private Int64 _TotalQuantity; /// /// 总产量 /// public Int64 TotalQuantity { get { return _TotalQuantity; } set { SetProperty(ref _TotalQuantity, value); } } private Int64 _TotalQuantityToday; /// /// 当天的总产量 /// public Int64 TotalQuantityToday { get { return _TotalQuantityToday; } set { SetProperty(ref _TotalQuantityToday, value); } } private Int64 _CurrentUPH; /// /// 当前的UPH /// public Int64 CurrentUPH { get { return _CurrentUPH; } set { SetProperty(ref _CurrentUPH, value); } } private Int64 _NgNumber; /// /// 当前的NG数量 /// public Int64 NgNumber { get { return _NgNumber; } set { SetProperty(ref _NgNumber, value); } } private double _Yield; /// /// 当前的NG数量 /// public double Yield { get { return _Yield; } set { SetProperty(ref _Yield, value); } } private XYD_ScrewDriver _ScrewDriver; public XYD_ScrewDriver ScrewDriver { get { return _ScrewDriver; } set { SetProperty(ref _ScrewDriver, value); } } public Dictionary BackupObject { get; set; } = new Dictionary(); #endregion #region 命令 #endregion #region 事件 #endregion public Management(IRegionManager regionManager, IEventAggregator ea, IContainerProvider container, IConfigService configService, IRobotService robotService, ICameraService cameraService, IFeederService feederService, IPlcService plcService, IProductService productService, ICalibrationService calibrationService, IRemoteCommandService remoteCommandService, ISystemDatabaseService systemDatabaseService, ILightManagerService lightManagerService, IMesService mesService) { _regionManager = regionManager; _eventAggregator = ea; _container = container; _configService = configService; _robotService = robotService; _cameraService = cameraService; _feederService = feederService; _plcService = plcService; _calibrationService = calibrationService; yieldtimer = new Timer(DoYieldTime, null, 10000, 1000); Renders = new ObservableCollection(); _configService = configService; _productService = productService; _remoteCommandService = remoteCommandService; _systemDatabaseService = systemDatabaseService; _lightManagerService = lightManagerService; _mesService = mesService; } #region 初始化硬件模块 /// /// 初始化Feeder /// /// public async Task<(bool IsSucceed, string Msg)> InitFeeders() { var feeders = _configService.GetAllFeeders(); StringBuilder sb = new StringBuilder(); foreach (var item in feeders) { _feederService.CreateFeeder(item.Id, item.FeederNo, item.FeederName, item.IP, item.Port, item.FeederBrand); var feeder = _feederService.GetFeeder(item.Id); Status.Add(new StatusInfo(item.Id, item.FeederName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red))); try { feeder.FeederConnectionStatusChanged += Management_FeederConnectionStatusChanged; await feeder.ConnectAsync(); //连接Feeder //SendTaskMessage($"{item.FeederName}已连接!", MessageLevel.Debug); } catch (Exception ex) { sb.AppendLine($"{item.FeederName}:{Lang.断开连接}![{ex.Message}]"); SendTaskMessage($"{item.FeederName}{Lang.断开连接}!", MessageLevel.Alarm); } } if (sb.Length == 0) { return (true, ""); } else { return (false, sb.ToString()); } } /// /// 初始化机器人 /// /// public async Task<(bool IsSucceed, string Msg)> InitRobots() { var robots = _configService.GetAllRobots(); StringBuilder sb = new StringBuilder(); foreach (var item in robots) { _robotService.CreateRobot(item.Id, item); try { Status.Add(new StatusInfo(item.Id, item.RobotName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red))); var robot = _robotService.GetRobot(item.Id); robot.ReceivedEvent += Management_ReceivedEvent; robot.SendEvent += Management_SendEvent; robot.ConnectedEvent += Management_ConnectedEvent; robot.DisconnectedEvent += Management_DisconnectedEvent; await robot.ConnectAsync(); //连接Robot SendTaskMessage($"{item.RobotName}{Lang.已连接}!", MessageLevel.Debug); } catch (Exception ex) { sb.AppendLine($"{item.RobotName}:{Lang.断开连接}![{ex.Message}]"); SendTaskMessage($"{item.RobotName}{Lang.断开连接}!", MessageLevel.Alarm); } } if (sb.Length == 0) { return (true, ""); } else { return (false, sb.ToString()); } } /// /// 初始化PLC /// /// public async Task<(bool IsSucceed, string Msg)> InitPlc() { var plcs = _configService.GetAllPlcs(); StringBuilder sb = new StringBuilder(); foreach (var item in plcs) { try { _plcService.CreatePlc(item.Id, item); var plc = _plcService.GetPlc(item.Id); Status.Add(new StatusInfo(item.Id, item.Name + $"{Lang.未连接}", new SolidColorBrush(Colors.Red))); plc.ConnectChangedEvent += Management_PlcConnectChangedEvent; await plc.ConnectAsync(); //连接PLC //SendTaskMessage($"{item.Name}{Lang.已连接}!", MessageLevel.Debug); } catch (Exception ex) { sb.AppendLine($"{item.Name}:{Lang.断开连接}![{ex.Message}]"); SendTaskMessage($"{item.Name}{Lang.断开连接}!", MessageLevel.Alarm); } } try { await WriteSystemParameterToPlcAsync(_configService.GetSystemConfiguration()); RegisterPlcMonitorAddress(); } catch (Exception ex) { LogHelper.WriteLogError("为PLC写入系统参数和订阅变量时出错", ex); } if (sb.Length == 0) { return (true, ""); } else { return (false, sb.ToString()); } } /// /// 初始化相机 /// /// public async Task<(bool IsSucceed, string Msg)> InitCameras() { var cameras = _configService.GetAllCameras(); StringBuilder sb = new StringBuilder(); foreach (var item in cameras) { if (item.DisplatConfigs != null) { foreach (var item1 in item.DisplatConfigs) { Renders.Add(new ShowRender() { Id = item1.Id, DisplayName = item1.DisplayName }); } } _cameraService.CreateCamera(item.Id, item); try { var camera = _cameraService.GetCamera(item.Id); Status.Add(new StatusInfo(item.Id, item.CameraName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red))); camera.CameraConnectChangedEvent += Management_CameraConnectChangedEvent; camera.ImageCallbackEvent += Camera_ImageCallbackEvent; try { if (await camera.OpenDeviceAsync()) { SendTaskMessage($"{item.CameraName}{Lang.已连接}!", MessageLevel.Debug); } else { SendTaskMessage($"{item.CameraName}{Lang.连接失败}!", MessageLevel.Alarm); sb.AppendLine($"{item.CameraName}:{Lang.连接失败}!"); } } catch (Exception ex) { SendTaskMessage($"{item.CameraName}{ex.Message}!", MessageLevel.Alarm); sb.AppendLine($"{item.CameraName}:{ex.Message}!"); } } catch (Exception ex) { SendTaskMessage($"{item.CameraName}{Lang.连接失败}!", MessageLevel.Alarm); sb.AppendLine($"{item.CameraName}:{Lang.连接失败}!:{ex.Message}"); } } _container.Resolve().Renders = Renders; if (sb.Length == 0) { return (true, ""); } else { return (false, sb.ToString()); } } private void Camera_ImageCallbackEvent(ICogImage arg1, TimeSpan arg2, string arg3, Guid cameraId) { var camera = _configService.GetCamera(cameraId); SendTaskMessage($"相机[{camera.CameraName}]图像接收完成!", MessageLevel.Info); //if (camera.CameraNo == 1) //{ // ImageData[1] = 1; //} //else if (camera.CameraNo == 2) //{ // ImageData[2] = 1; //} //else if (camera.CameraNo == 3) //{ // ImageData[3] = 1; // ImageData[4] = 1; //} //_eventAggregator.GetEvent().Publish(new ShowRender() //{ // CameraName = camera.CameraName, // Id = cameraId, // Image = arg1, // Graphic = null, // Record = null, // Result = false, // IsShow = true, //}); // 通知等待方:该相机新图到达 //SignalImageArrived(cameraId, arg1); } /// /// 初始化光源控制器 /// /// public async Task<(bool IsSucceed, string Msg)> InitLightControllers() { var lightcontrollers = _configService.GetAllLightControllers(); StringBuilder sb = new StringBuilder(); foreach (var item in lightcontrollers) { try { var lishtCtr = await _lightManagerService.RegisterControllerAsync(item.Id, item); //var lightcontroller = _cameraService.GetLightController(item.Id); //await lightcontroller.ConnectAsync(); //连接光源控制器 //SendTaskMessage($"{item.LightControllerName}{Lang.已连接}!", MessageLevel.Debug); } catch (Exception ex) { //sb.AppendLine($"{item.LightControllerName}:{Lang.断开连接}![{ex.Message}]"); //SendTaskMessage($"{item.LightControllerName}{Lang.断开连接}!", MessageLevel.Alarm); } } if (lightcontrollers.Count > 0) { var result = await _lightManagerService.ConnectAllAsync(); if (result) { return (true, ""); } else { return (false, "Light Controller Connect Failed!"); } } return (true, ""); //if (sb.Length == 0) //{ // return (true, ""); //} //else //{ // return (false, sb.ToString()); //} } /// /// 初始化后台TCP服务器通讯 /// public void InitBgTcp() { var config = _configService.GetBgTcp(); try { BgCommunicate = new BgCommunicate(config); BgCommunicate.ConnectedEvent += BgCommunicate_ConnectedEvent; BgCommunicate.DisconnectedEvent += BgCommunicate_DisconnectedEvent; BgCommunicate.ReceivedEvent += BgCommunicate_ReceivedEvent; BgCommunicate.SendEvent += BgCommunicate_SendEvent; BgCommunicate.StartListening(); SendTaskMessage($"{Lang.已开启监听端口}:{config.Port}", MessageLevel.Debug); } catch (Exception ex) { SendTaskMessage($"{Lang.未开启监听端口}:{config.Port}", MessageLevel.Error); LogHelper.WriteLogError("开启后台服务器通讯时出错!", ex); } } /// /// 初始化后台ModbusTCP从站 /// public void InitModbusTcp() { try { var config = _configService.GetBgModbusTcp(); BgModbusTcpCommunicate = new BgModbusTcpCommunicate(config); if (config.IsEnabled) { BgModbusTcpCommunicate.Listen(); SendTaskMessage($"Start Modbus Tcp Slave:{BgModbusTcpCommunicate.IP}:{BgModbusTcpCommunicate.Port}:{BgModbusTcpCommunicate.SlaveID}", MessageLevel.Debug); } } catch (Exception ex) { SendTaskMessage($"No Start Modbus Tcp Slave:{ex.Message}", MessageLevel.Alarm); LogHelper.WriteLogError("开启后台Modbus TCP通讯时出错!", ex); } } /// /// 初始化后台脚本 /// public void InitBackgroundcript() { try { if (!Directory.Exists(FilePath.BackgroundScriptPath)) { Directory.CreateDirectory(FilePath.BackgroundScriptPath); } try { string[] files = Directory.GetFiles(FilePath.BackgroundScriptPath); List ScriptFilesCollection = new List(); foreach (string file in files) { string fileName = Path.GetFileName(file); string fileExtension = Path.GetExtension(file); if (fileExtension == ".cs") { ScriptFilesCollection.Add(file); } } foreach (var item in ScriptFilesCollection) { try { string script = FileHelper.ReadFile(item); SendTaskMessage($"{Lang.执行脚本}:{item}", MessageLevel.Info); Task.Factory.StartNew(() => { ScriptHelper.ExecuteScriptingAsync(script, _regionManager, _eventAggregator, _container, rst => { if (!rst.Item1) { foreach (var err in rst.Item2) { SendTaskMessage($"{Lang.后台脚本出错}:{err}", MessageLevel.Error); } } }); }); } catch (Exception ex) { LogHelper.WriteLogError($"开启脚本时出错:{item}", ex); } } } catch (Exception ex) { LogHelper.WriteLogError("读取本地脚本文件列表时出错", ex); } } catch (Exception ex) { LogHelper.WriteLogError("开启后台脚本时出错!", ex); } } /// /// 初始化电批 /// /// public async Task InitScrewDriver() { try { var screwDriverConfig = _configService.GetScrewDriverConfig(); ScrewDriver = new XYD_ScrewDriver(screwDriverConfig.IPAdress, screwDriverConfig.Port); Status.Add(new StatusInfo(ScrewDriver.Id, "电批未连接", new SolidColorBrush(Colors.Red))); ScrewDriver.ConnectStateChangedEvent += ScrewDriver_ConnectStateChangedEvent; ScrewDriver.SendTimeout = screwDriverConfig.SendTimeout; screwDriverConfig.ReceiveTimeout = screwDriverConfig.ReceiveTimeout; var isConnected = await ScrewDriver.ConnectAsync(); if (isConnected) { SendTaskMessage($"电批已连接", MessageLevel.Debug); } else { SendTaskMessage($"电批连接失败", MessageLevel.Error); } } catch (Exception ex) { SendTaskMessage($"电批连接失败:{ex.Message}", MessageLevel.Alarm); LogHelper.WriteLogError("连接电批时出错!", ex); } } #endregion #region 机器人指令执行 public Dictionary RobotTCPCollection = new Dictionary(); /// /// 机器人TCP接收 /// /// /// /// private async void Management_ReceivedEvent(Guid robotid, object arg2, TouchSocket.Sockets.ReceivedDataEventArgs e) { try { if (!RobotTCPCollection.ContainsKey(robotid)) RobotTCPCollection.Add(robotid, new CancellationTokenSource()); else { if (RobotTCPCollection[robotid].IsCancellationRequested) { RobotTCPCollection[robotid] = new CancellationTokenSource(); } } var robot = await _robotService.GetRobotAsync(robotid); //从服务器收到信息。但是一般byteBlock和requestInfo会根据适配器呈现不同的值。 var buffer = e.ByteBlock.Span.ToString(robot.GetEncoding()); SendTaskMessage($"{robot.Name}Received:{buffer}", MessageLevel.Info); var _ = _remoteCommandService.ExecuteAsync(buffer, RobotTCPCollection[robotid].Token, async msg => { try { if (robot.ConnectType == TCPConnectType.Client) { if (robot.IsConnected) { await robot.SendAsync($"{msg}"); } } else { var cient = (ITcpSessionClient)arg2; if (cient.Online) { await robot.SendAsync(cient, $"{msg}"); } } } catch (Exception ex) { LogHelper.WriteLogError("TCP发送数据时出错!", ex); SendTaskMessage(ex.Message, MessageLevel.Alarm); } }); } catch (Exception ex) { LogHelper.WriteLogError("处理机器人接收的命令时出错!", ex); SendTaskMessage(ex.Message, MessageLevel.Alarm); } } #endregion #region 机器人&Feeder&相机连接状态事件 /// /// 机器人发送事件 /// /// /// /// /// private void Management_SendEvent(Guid robotid, object arg2, string arg3) { var r = _robotService.GetRobot(robotid); SendTaskMessage($"{r.Name}Send:{arg3}", MessageLevel.Info); } /// /// 机器人断开连接时 /// /// /// /// /// private void Management_DisconnectedEvent(Guid robotid, object arg2, ClosedEventArgs arg3) { if (RobotTCPCollection.ContainsKey(robotid)) { RobotTCPCollection[robotid].Cancel(); } var r = _configService.GetRobot(robotid); if (r.ConnectType == TCPConnectType.Server) { ITcpSessionClient socketClient = arg2 as ITcpSessionClient; SendTaskMessage($"{r.RobotName}[{socketClient.Id}:{socketClient.IP}]{Lang.断开连接}!", MessageLevel.Error); var robot = _robotService.GetRobot(robotid); if (robot.TcpService.Count < 1) { var sta = Status.FirstOrDefault(s => s.ID == robotid); App.Current.Dispatcher.Invoke(new Action(() => { sta.Message = $"{r.RobotName}{Lang.未连接}"; sta.Background = new SolidColorBrush(Colors.Red); })); } } else { SendTaskMessage($"{r.RobotName}{Lang.断开连接}!", MessageLevel.Error); var sta = Status.FirstOrDefault(s => s.ID == robotid); App.Current.Dispatcher.Invoke(new Action(() => { sta.Message = $"{r.RobotName}{Lang.断开连接}"; sta.Background = new SolidColorBrush(Colors.Red); })); } } /// /// 机器人连接成功时 /// /// /// /// /// private void Management_ConnectedEvent(Guid robotid, object arg2, ConnectedEventArgs arg3) { var r = _configService.GetRobot(robotid); if (r.ConnectType == TCPConnectType.Server) { ITcpSessionClient socketClient = arg2 as ITcpSessionClient; SendTaskMessage($"{r.RobotName}[{socketClient.Id}:{socketClient.IP}]{Lang.已连接}!", MessageLevel.Debug); var robot = _robotService.GetRobot(robotid); if (robot.TcpService.Count > 0) { var sta = Status.FirstOrDefault(s => s.ID == robotid); App.Current.Dispatcher.Invoke(new Action(() => { sta.Message = $"{r.RobotName}{Lang.已连接}"; sta.Background = new SolidColorBrush(Colors.Green); })); } } else { SendTaskMessage($"{r.RobotName}{Lang.已连接}!", MessageLevel.Debug); var sta = Status.FirstOrDefault(s => s.ID == robotid); App.Current.Dispatcher.Invoke(new Action(() => { sta.Message = $"{r.RobotName}{Lang.已连接}"; sta.Background = new SolidColorBrush(Colors.Green); })); } } /// /// Feeder连接状态改变时 /// /// /// private void Management_FeederConnectionStatusChanged(object sender, bool state) { IFeeder feeder = sender as IFeeder; var sta = Status.FirstOrDefault(s => s.ID == feeder.Id); if (state) { App.Current.Dispatcher.Invoke(new Action(() => { sta.Message = $"{feeder.Name}{Lang.已连接}"; sta.Background = new SolidColorBrush(Colors.Green); })); SendTaskMessage($"{feeder.Name}{Lang.已连接}!", MessageLevel.Debug); } else { App.Current.Dispatcher.Invoke(new Action(() => { sta.Message = $"{feeder.Name}{Lang.未连接}"; sta.Background = new SolidColorBrush(Colors.Red); })); SendTaskMessage($"{feeder.Name}{Lang.断开连接}!", MessageLevel.Error); } } /// /// 相机连接或者断开时 /// /// /// private void Management_CameraConnectChangedEvent(Guid id, bool state) { var sta = Status.FirstOrDefault(s => s.ID == id); var camera = _configService.GetCamera(id); if (sta != null && camera != null) { if (state) { App.Current.Dispatcher.Invoke(new Action(() => { sta.Message = $"{camera.CameraName}{Lang.已连接}"; sta.Background = new SolidColorBrush(Colors.Green); })); } else { App.Current.Dispatcher.Invoke(new Action(() => { sta.Message = $"{camera.CameraName}{Lang.断开连接}"; sta.Background = new SolidColorBrush(Colors.Red); })); } } } /// /// PLC连接状态改变事件 /// /// /// private void Management_PlcConnectChangedEvent(object sender, bool isconnected) { IPlc plc = sender as IPlc; var sta = Status.FirstOrDefault(s => s.ID == plc.Id); if (plc.IsConnected) { SendTaskMessage($"{plc.Name}{Lang.已连接}!", MessageLevel.Debug); if (sta == null) return; App.Current.Dispatcher.Invoke(new Action(() => { sta.Message = $"{plc.Name}{Lang.已连接}"; sta.Background = new SolidColorBrush(Colors.Green); })); } else { SendTaskMessage($"{plc.Name}{Lang.断开连接}!", MessageLevel.Error); if (sta == null) return; App.Current.Dispatcher.Invoke(new Action(() => { sta.Message = $"{plc.Name}{Lang.未连接}"; sta.Background = new SolidColorBrush(Colors.Red); })); } } /// /// 电批连接状态改变时 /// /// /// private void ScrewDriver_ConnectStateChangedEvent(object screwDevice, bool state) { try { XYD_ScrewDriver screwDriver = screwDevice as XYD_ScrewDriver; if (state) { SendTaskMessage($"电批{Lang.已连接}!", MessageLevel.Debug); var sta = Status.FirstOrDefault(s => s.ID == screwDriver.Id); App.Current.Dispatcher.Invoke(new Action(() => { sta.Message = $"电批{Lang.已连接}"; sta.Background = new SolidColorBrush(Colors.Green); })); } else { SendTaskMessage($"电批{Lang.未连接}!", MessageLevel.Error); var sta = Status.FirstOrDefault(s => s.ID == screwDriver.Id); App.Current.Dispatcher.Invoke(new Action(() => { sta.Message = $"电批{Lang.未连接}"; sta.Background = new SolidColorBrush(Colors.Red); })); } } catch (Exception ex) { LogHelper.WriteLogError("电批连接状态改变时出错了", ex); } } #endregion #region 后台服务器通讯事件 private void BgCommunicate_SendEvent(ITcpSessionClient client, string msg) { SendTaskMessage($"{Lang.服务器}[{client.ServicePort}] Send To {Lang.客户端}[{client.Id}:{client.IP}]:{msg}", MessageLevel.Info); } public Dictionary BgCommunicateollection = new Dictionary(); private async void BgCommunicate_ReceivedEvent(ITcpSessionClient client, string msg) { try { if (!BgCommunicateollection.ContainsKey(client.Id)) { BgCommunicateollection.Add(client.Id, new CancellationTokenSource()); } SendTaskMessage($"{Lang.服务器}[{client.ServicePort}]ReceiveFor{Lang.客户端}[{client.Id}:{client.IP}]:{msg}", MessageLevel.Info); var _ = _remoteCommandService.ExecuteAsync(msg, BgCommunicateollection[client.Id].Token, async response => { try { if (!client.Online) { return; } await BgCommunicate.SendAsync(client, $"{response}"); } catch (Exception ex) { LogHelper.WriteLogError("后台TCP发送数据时出错!", ex); SendTaskMessage(ex.Message, MessageLevel.Alarm); } }); } catch (Exception ex) { LogHelper.WriteLogError("处理后台服务器接收的命令时出错!", ex); SendTaskMessage(ex.Message, MessageLevel.Alarm); } } private void BgCommunicate_DisconnectedEvent(ITcpSessionClient client, ClosedEventArgs e) { SendTaskMessage($"{Lang.服务器}[{client.ServicePort}]{Lang.客户端}[{client.Id}:{client.IP}]{Lang.断开连接}!", MessageLevel.Alarm); if (BgCommunicateollection.ContainsKey(client.Id)) { BgCommunicateollection[client.Id].Cancel(); } } private void BgCommunicate_ConnectedEvent(ITcpSessionClient client, ConnectedEventArgs e) { SendTaskMessage($"{Lang.服务器}[{client.ServicePort}]{Lang.客户端}[{client.Id}:{client.IP}]{Lang.连接成功}!", MessageLevel.Debug); } #endregion #region PLC /// /// 将系统参数写入PLC /// /// /// public async Task WriteSystemParameterToPlcAsync(SystemConfiguration systemConfiguration) { var addressConfig = _configService.GetPlcAddresses(); var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC; if (plc == null || !plc.IsConnected) return; Dictionary nodeValues = new Dictionary(); nodeValues.Add(addressConfig.Out_WorkMode.Address, (Int16)systemConfiguration.WorkMode); nodeValues.Add(addressConfig.Out_PickPointNum.Address, (Int16)systemConfiguration.PickPointNum); nodeValues.Add(addressConfig.Out_DowmCameraNum.Address, (Int16)systemConfiguration.DowmCameraNum); nodeValues.Add(addressConfig.Out_UpCameraPickNum.Address, (Int16)systemConfiguration.UpCameraPickNum); nodeValues.Add(addressConfig.Out_UpCameraPutNum.Address, (Int16)systemConfiguration.UpCameraPutNum); nodeValues.Add(addressConfig.Out_UPCameracheckNum.Address, (Int16)systemConfiguration.UPCameracheckNum); nodeValues.Add(addressConfig.Out_FixedCameraPickNum.Address, (Int16)systemConfiguration.FixedCameraPickNum); nodeValues.Add(addressConfig.Out_FixedCameraPutNum.Address, (Int16)systemConfiguration.FixedCameraPutNum); nodeValues.Add(addressConfig.Out_FixedCameracheckNum.Address, (Int16)systemConfiguration.FixedCameracheckNum); var res = await plc.WriteNodesAsync(nodeValues); } /// /// 注册需要监控的PLC地址 /// public void RegisterPlcMonitorAddress() { var addressConfig = _configService.GetPlcAddresses(); var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC; if (plc == null || !plc.IsConnected) return; //PLC地址数组 List monitorNodeIds = new List() { addressConfig.In_DowmCameraExe.Address, addressConfig.In_UpCameraPickExe.Address, addressConfig.In_UpCameraPutExe.Address, addressConfig.In_UPCameracheckExe.Address, addressConfig.In_FixedCameraPickExe.Address, addressConfig.In_FixedCameraPutExe.Address, addressConfig.In_FixedCameracheckExe.Address, addressConfig.In_WorkStart.Address, addressConfig.In_WorkDone.Address, addressConfig.In_MesCheck.Address, addressConfig.In_RequestPosition.Address, }; for (int i = 0; i < 10; i++) { monitorNodeIds.Add(string.Format(addressConfig.In_MesCheck.Address, i)); } //订阅PLC地址变化 plc.SubscribeNodes("AutoSensor", monitorNodeIds, PlcCommandTrigger); } /// /// 写入点位信息给PLC /// /// public async Task WritePositionToPlcAsync() { var addressConfig = _configService.GetPlcAddresses(); var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC; if (plc == null || !plc.IsConnected) return; var current = _productService.GetCurrentProduct(); if (current == null) return; if (current.PickCameraPoints != null && current.PickCameraPoints.Count > 0) { foreach (var item in current.PickCameraPoints) { await item.WriteToPlcAddress(addressConfig.Out_PickCamera, plc); } } if (current.PickPoints != null && current.PickPoints.Count > 0) { foreach (var item in current.PickPoints) { await item.WriteToPlcAddress(addressConfig.Out_Pick, plc); } } if (current.SecPosCameraPoints != null && current.SecPosCameraPoints.Count > 0) { foreach (var item in current.SecPosCameraPoints) { await item.WriteToPlcAddress(addressConfig.Out_SecPosCamera, plc); } } if (current.ScrewCameraPoints != null && current.ScrewCameraPoints.Count > 0) { foreach (var item in current.ScrewCameraPoints) { await item.WriteToPlcAddress(addressConfig.Out_ScrewCamera, plc); } } //if (current.ScrewPoints != null && current.ScrewPoints.Count > 0) //{ // foreach (var item in current.ScrewPoints) // { // await item.WriteToPlcAddress(addressConfig.Out_Screw, plc); // } // await plc.WriteNodeAsync(addressConfig.Out_WorkNum.Address, (Int16)current.ScrewPoints.Count); //} if (current.CheckCameraPoints != null && current.CheckCameraPoints.Count > 0) { foreach (var item in current.CheckCameraPoints) { await item.WriteToPlcAddress(addressConfig.Out_CheckCamera, plc); } } if (current.AoiPoints != null && current.AoiPoints.Count > 0) { await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickNum.Address, (Int16)current.AoiPoints.Count); foreach (var item in current.AoiPoints) { await item.WriteToPlcAddress(addressConfig.Out_AoiCamera, plc); } } else { await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickNum.Address, 0); } } PointF[] DowmCameraResults = new PointF[10]; PointF[] UpCameraPutResults = new PointF[10]; bool _LastDowmCameraExe = false; bool _LastScrewTeachExe = false; bool _LastUpCameraPickExe = false; bool _LastUpCameraPutExe = false; bool _LastUPCameracheckExe = false; bool _LastFixedCameraPickExe = false; bool _LastFixedCameraPutExe = false; bool _LastFixedCameracheckExe = false; Int16 _LastWorkStart = 0; Int16 _LastWorkDone = 0; Int16 _LastRequestPosition = 0; Int16[] _LastMesCheck = new Int16[10]; Int16 _LastPickINC = 0; DateTime[] _LastMesCheckTime = new DateTime[10]; List> _PrcTaskList = new List>(); private readonly object _stateLock = new object(); /// /// PLC命令触发时 /// /// private async void PlcCommandTrigger((string key, string nodeId, object value) tuple) { try { if (tuple.key != "AutoSensor") { return; } var addressConfig = _configService.GetPlcAddresses(); var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC; if (plc == null || !plc.IsConnected) return; // 获取当前产品 var currentProduct = _productService.GetCurrentProduct(); if (currentProduct == null) { return; } ////获取产品编码 //_productService.CurrentProductCode = currentProduct.Name; //string productCode = plc.ReadNode(addressConfig.In_Code.Address); ////如果产品编码为空,则以当前的时间戳作为编码 //if (string.IsNullOrEmpty(productCode)) //{ // productCode = DateTime.Now.ToString("yyyyMMddHHmmssfff"); //} // 写入3D相机长度 if (addressConfig.In_UPCameracheckExe.Address.Contains(tuple.nodeId)) { if (tuple.value is bool state) { if (_LastUPCameracheckExe != state) { _LastUPCameracheckExe = state; } else { return; } if (state) { SendTaskMessage($"写入3D相机长度...", MessageLevel.Debug); //相机的编号 //Int16 cameraIndex = plc.ReadNode(addressConfig.In_FixedCameracheckNum.Address); // 读取相机编号 Int16 cameraIndex = plc.ReadNode(addressConfig.In_FixedCameracheckNum.Address); SendTaskMessage($"编号:{cameraIndex}", MessageLevel.Info); // 找到对应编号的 PlcPoint var targetPoint = currentProduct.AoiPoints?.FirstOrDefault(p => p.Number == cameraIndex); if (targetPoint == null) { SendTaskMessage($"未找到 AOI 点位,编号:{cameraIndex}", MessageLevel.Alarm); await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)2); return; } SetBatchPoints(new int[] { targetPoint.Camera_Data1, targetPoint.Camera_Data2, targetPoint.Camera_Data3, targetPoint.Camera_Data4 }); await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)1); } else { SendTaskMessage($"写入3D相机长度信号已关闭", MessageLevel.Alarm); await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)0); } } } // 发送点位个数 else if (addressConfig.In_RequestPosition.Address.Contains(tuple.nodeId)) { if (tuple.value is Int16 state) { if (_LastRequestPosition != state) { _LastRequestPosition = state; } else { return; } if (state == 1) { var current = _productService.GetCurrentProduct(); if (current == null) return; await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)1); await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickNum.Address, (Int16)current.AoiPoints.Count); } else { SendTaskMessage($"多相机坐标合并请求已结束或被取消,state={state}", MessageLevel.Alarm); await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)0); } } } // 固定相机检测拍照 else if (addressConfig.In_FixedCameracheckExe.Address.Contains(tuple.nodeId)) { if (tuple.value is bool state) { if (_LastFixedCameracheckExe != state) { _LastFixedCameracheckExe = state; } else { return; } if (state) { LockResult lockResult = new LockResult(); lockResult.TimeStart = DateTime.Now; SendTaskMessage($"触发固定相机检测拍照...", MessageLevel.Debug); // 读取相机编号 Int16 cameraIndex = plc.ReadNode(addressConfig.In_FixedCameracheckNum.Address); SendTaskMessage($"编号:{cameraIndex}", MessageLevel.Info); // 找到对应编号的 PlcPoint var targetPoint = currentProduct.AoiPoints?.FirstOrDefault(p => p.Number == cameraIndex); if (targetPoint == null) { SendTaskMessage($"未找到 AOI 点位,编号:{cameraIndex}", MessageLevel.Alarm); await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)2); return; } // 收集要执行的流程 id(仅添加大于0的) var procIds = new List(); try { if (targetPoint.CameraProcedureId1 != Guid.Empty) procIds.Add(targetPoint.CameraProcedureId1); } catch { } try { if (targetPoint.CameraProcedureId2 != Guid.Empty) procIds.Add(targetPoint.CameraProcedureId2); } catch { } try { if (targetPoint.CameraProcedureId3 != Guid.Empty) procIds.Add(targetPoint.CameraProcedureId3); } catch { } try { if (targetPoint.CameraProcedureId4 != Guid.Empty) procIds.Add(targetPoint.CameraProcedureId4); } catch { } try { if (targetPoint.CameraProcedureId5 != Guid.Empty) procIds.Add(targetPoint.CameraProcedureId5); } catch { } try { if (targetPoint.CameraProcedureId6 != Guid.Empty) procIds.Add(targetPoint.CameraProcedureId6); } catch { } try { if (targetPoint.CameraProcedureId7 != Guid.Empty) procIds.Add(targetPoint.CameraProcedureId7); } catch { } try { if (targetPoint.CameraProcedureId8 != Guid.Empty) procIds.Add(targetPoint.CameraProcedureId8); } catch { } if (procIds.Count == 0) { SendTaskMessage($"Point#{cameraIndex} 未配置任何视觉流程 (CameraProcedureId1/2/3)", MessageLevel.Alarm); await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2); return; } var cameraProcedures = currentProduct.CameraProcedures; if (cameraProcedures == null || cameraProcedures.Count == 0) { SendTaskMessage($"当前产品未配置 CameraProcedures,无法执行视觉流程", MessageLevel.Alarm); await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2); return; } if (cameraIndex == currentProduct.PhotoCount) { _PrcTaskList.Clear(); lock (_stateLock) { lockResultsAll.Clear(); } App.Current.Dispatcher.Invoke(() => { _eventAggregator.GetEvent().Publish(); }); } var sysConfig = _configService.GetSystemConfiguration(); if (sysConfig.CodeUse==true && cameraIndex == 1) { var cts = new CancellationTokenSource(); // CameraProcedureId 存储的是具体的视觉流程 Id(ProcedureModel.Id), // 需要在所有 CameraProcedures 的 ProcedureModels 中查找匹配的流程。 ProcedureModel selectedProcedure = null; try { cameraProcedures = currentProduct.CameraProcedures; if (cameraProcedures != null) { foreach (var cp in cameraProcedures) { if (cp?.ProcedureModels == null) continue; selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == targetPoint.CameraProcedureId1); if (selectedProcedure != null) break; } } } catch (Exception ex) { LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex); } if (selectedProcedure == null) { SendTaskMessage($"未找到 AOI 点位对应的视觉流程,Point#{cameraIndex} ProcedureId={targetPoint.CameraProcedureId1}", MessageLevel.Alarm); await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2); return; } if (selectedProcedure.Id == currentProduct.FixedDownCameraProcedureId && sysConfig.TurnOnAllLightUse == true) { await _remoteCommandService.SetLightBeforePhoto(selectedProcedure); } var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint2(selectedProcedure, null, null, cts.Token); if (visionResult.IsSucceed) { code = visionResult.X.ToUpper(); SendTaskMessage($"扫码成功,SN:{code}", MessageLevel.Info); //这里缺少从MES获取产品配方的内容,需要补充 _LastMesCheckTime[0] = (await _mesService.GetServerTimeAsync(code, 2)).Now; LogHelper.WriteLogMes($"【mes开始QUERY】"); SendTaskMessage($"mes开始QUERY", MessageLevel.Info); //(bool isSuccess, string response) = await _mesService.StationGetAsync(code, "", 2);//询问mes (bool isSuccess, string response) = await _mesService.StationGetExAsync(code, "", 2);//基于电池的SN获取产品SN,询问mes if (isSuccess) { //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改 string ProductMainSN_Temp = ""; LogHelper.WriteLogMes($"询问mes成功"); SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug); if (response != "MES功能未启用!") { string[] item = response.Split('\n'); if (item[2].Contains("sn=")) { ProductMainSN_Temp = item[2].Replace("sn=", ""); SendTaskMessage($"sn:{ProductMainSN_Temp}", MessageLevel.Info); } } LogHelper.WriteLogMes($"询问mes成功"); SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug); //20260214,特别版(电池组装) (bool isSuccess2, string response2) = await _mesService.StationGetAsync(ProductMainSN_Temp, "", 2);//询问mes if (isSuccess2) { LogHelper.WriteLogMes($"询问mes成功"); SendTaskMessage($"询问mes成功:{response2}", MessageLevel.Debug); if (response2 != "MES功能未启用!") { string[] item = response2.Split('\n'); if (item[3].Contains("sn=")) { ProductMainSN = item[3].Replace("sn=", ""); _productService.CurrentProductCode = ProductMainSN; SendTaskMessage($"产品主sn:{ProductMainSN}", MessageLevel.Info); } if (item[5].Contains("wo=")) { wo = item[5].Replace("wo=", ""); SendTaskMessage($"产品主wo:{wo}", MessageLevel.Info); } } LogHelper.WriteLogMes($"第二次询问mes成功"); SendTaskMessage($"第二次询问mes成功:{response2}", MessageLevel.Debug); await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1); } else { LogHelper.WriteLogMes($"第二次询问mes失败"); SendTaskMessage($"第二次询问mes失败:{response2}", MessageLevel.Error); await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)3); } } else { //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改 await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)3); LogHelper.WriteLogMes($"询问mes失败"); SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error); } } else { SendTaskMessage($"扫码失败", MessageLevel.Alarm); await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)3); } return; } if (sysConfig.CodeUse2 == true && cameraIndex == 1) { var cts = new CancellationTokenSource(); // CameraProcedureId 存储的是具体的视觉流程 Id(ProcedureModel.Id), // 需要在所有 CameraProcedures 的 ProcedureModels 中查找匹配的流程。 ProcedureModel selectedProcedure = null; try { cameraProcedures = currentProduct.CameraProcedures; if (cameraProcedures != null) { foreach (var cp in cameraProcedures) { if (cp?.ProcedureModels == null) continue; selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == targetPoint.CameraProcedureId1); if (selectedProcedure != null) break; } } } catch (Exception ex) { LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex); } if (selectedProcedure == null) { SendTaskMessage($"未找到 AOI 点位对应的视觉流程,Point#{cameraIndex} ProcedureId={targetPoint.CameraProcedureId1}", MessageLevel.Alarm); await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2); return; } var ctsAll = new CancellationTokenSource(); if (selectedProcedure.Id == currentProduct.FixedDownCameraProcedureId && sysConfig.TurnOnAllLightUse == true) { await _remoteCommandService.SetLightBeforePhoto(selectedProcedure); } var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint2(selectedProcedure, null, null, ctsAll.Token); if (visionResult.IsSucceed) { code = visionResult.X; ProductMainSN = visionResult.X; SendTaskMessage($"扫码成功,SN:{code}", MessageLevel.Info); //这里缺少从MES获取产品配方的内容,需要补充 _LastMesCheckTime[0] = (await _mesService.GetServerTimeAsync(code, 2)).Now; //_LastMesCheckTime[1] = DateTime.Now; LogHelper.WriteLogMes($"【mes开始QUERY】"); SendTaskMessage($"mes开始QUERY", MessageLevel.Info); (bool isSuccess, string response) = await _mesService.StationGetAsync(code, "", 2);//询问mes if (isSuccess) { //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改 LogHelper.WriteLogMes($"询问mes成功"); SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug); if (response != "MES功能未启用!") { string[] items = response.Split('\n'); if (items[3].Contains("sn=")) { ProductMainSN = items[3].Replace("sn=", ""); _productService.CurrentProductCode = ProductMainSN; } SendTaskMessage($"产品主sn:{ProductMainSN}", MessageLevel.Info); if (items[5].Contains("wo=")) { wo = items[5].Replace("wo=", ""); } SendTaskMessage($"产品wo:{wo}", MessageLevel.Info); } LogHelper.WriteLogMes($"【mes结束QUERY】"); SendTaskMessage($"mes结束QUERY", MessageLevel.Info); await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1); return; } else { //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改 await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)3); LogHelper.WriteLogMes($"询问mes失败"); SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error); } } else { SendTaskMessage($"扫码失败", MessageLevel.Alarm); await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)3); } return; } foreach (var prcId in procIds) { if (Is3D(prcId)) { _PrcTaskList.Add(ExecuteProcedureAsync(cameraIndex, prcId)); } else { //2d相机时,需要先等待图像采集完成 var imageData = await GrabImage(cameraIndex, prcId); if (imageData.IsSucceed) { _PrcTaskList.Add(ExecuteProcedureAsync(cameraIndex, prcId, imageData.imges)); } else { SendTaskMessage($"图像采集失败!{cameraIndex}: {prcId}", MessageLevel.Alarm); } } } //如果最后一个拍照点,则需要等待前面所有的拍照处理完成 if (cameraIndex == currentProduct.PhotoCountStop) { //等待所有的图像处理流程处理完成 var results = await Task.WhenAll(_PrcTaskList); //结果输出 bool resultFlog = true; foreach (var item in results) { if (!item.IsSucceed || item.Result == null) { resultFlog = false; } else { foreach (var item_1 in item.Result) { if (!item_1) { resultFlog = false; break; } } } } //全部OK if (resultFlog) { SendTaskMessage($"检测执行成功", MessageLevel.Debug); await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1); } //存在NG else { SendTaskMessage($"检测执行失败", MessageLevel.Alarm); await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2); } } else { //直接放行,执行下一个检测点 //SendTaskMessage($"流程执行成功", MessageLevel.Info); await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1); } } else { SendTaskMessage($"触发固定相机检测拍照信号已关闭", MessageLevel.Alarm); await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)0); } } } // 过站检查 else { for (int i = 0; i < 10; i++) { if (string.Format(addressConfig.In_MesCheck.Address, i).Contains(tuple.nodeId)) { if (tuple.value is Int16 state) { if (_LastMesCheck[i] != state) { _LastMesCheck[i] = state; } else { return; } var sysConfig = _configService.GetSystemConfiguration(); if (sysConfig.CodeUse == true && state == 1) { await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1); return; } if (sysConfig.CodeUse2 == true && state == 1) { await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1); return; } if (sysConfig.CodeUse == false && sysConfig.CodeUse2 == false) { code = plc.ReadNode(string.Format(addressConfig.In_Code.Address, i)); } var homeview = _container.Resolve(); //过站检查 if (state == 1) { //这里缺少从MES获取产品配方的内容,需要补充 _LastMesCheckTime[i] = (await _mesService.GetServerTimeAsync(code, 2)).Now; LogHelper.WriteLogMes($"【mes开始QUERY】"); SendTaskMessage($"mes开始QUERY", MessageLevel.Info); ShowMes_Query = false; (bool isSuccess, string response) = await _mesService.StationGetAsync(code, "", 2);//询问mes if (i == 0) { SendTaskMessage($"收到当前过站检查请求(当站是否生产)...", MessageLevel.Debug); } else { SendTaskMessage($"收到{i}过站检查请求(当站是否生产)...", MessageLevel.Debug); } if (isSuccess) { string[] item = response.Split('\n'); //获取产品主sn和wo用于后续上传数据使用 string snItem = item.FirstOrDefault(f => f.Contains("sn=")); if (snItem != null) { ProductMainSN = snItem.Replace("sn=", "").Trim(); if (i == 0) { _productService.CurrentProductCode = ProductMainSN; } SendTaskMessage($"产品主sn:{ProductMainSN[i]}", MessageLevel.Info); } string woItem = item.FirstOrDefault(f => f.Contains("wo=")); if (woItem != null) { wo = woItem.Replace("wo=", "").Trim(); SendTaskMessage($"工单信息:{wo[i]}", MessageLevel.Info); } ShowMes_Query = true; //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改 await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1); LogHelper.WriteLogMes($"【mes结束QUERY】"); SendTaskMessage($"mes结束QUERY", MessageLevel.Info); return; } else { //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改 await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2); LogHelper.WriteLogMes($"询问mes失败"); SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error); } LogHelper.WriteLogMes($"【mes结束QUERY】"); SendTaskMessage($"mes结束QUERY", MessageLevel.Info); } // 上传本站数据 else if (state == 2) { //获取当前工位的配置 var stationConfig = _configService.GetDeviceInfo(); List DFC = new List(); SendTaskMessage($"收到{i}上传本站数据请求...", MessageLevel.Debug); //这里缺少上传MES的本站数据结果及开始和结束时间,需要补充 //从服务器中获取当前时间 var serverTimeResult = await _mesService.GetServerTimeAsync(code, 2); double ct = serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds; if (i == 0) { CTtime = ct; } //读取产品结果 Int16 resultIndex = plc.ReadNode(string.Format(addressConfig.In_Result.Address, i)); if (homeview.IsResultTrue == false) { resultIndex = 1; } //Int16 resultIndex = 1; //目前只记录当前站 if (i == 0) await _systemDatabaseService.RecordProductionAsync(new ProductionRecord() { ProductName = currentProduct.Name, ProductCode = code, DeviceId = i, DeviceName = "", Category = resultIndex == 1 ? "OK" : "NG", Quantity = 1, Remark = $"TotalSeconds:{DateTime.UtcNow.Subtract(_LastMesCheckTime[i]).TotalSeconds.ToString("F2")}", }); LogHelper.WriteLogMes($"【mes开始ADD】"); SendTaskMessage($"mes开始ADD", MessageLevel.Info); StringBuilder submitData = new StringBuilder(); foreach (var item in lockResultsAll) { submitData.Append($"{item.PhotoName}-{item.ResultData}"); } ShowMes_Result = resultIndex == 1 ? true : false; //(bool isSuccess, string response) = await _mesService.SubmitGetAsync(ProductMainSN, "", MesData.Replace("--", "-"), resultIndex == 1 ? true : false, _LastMesCheckTime[i], DateTime.UtcNow); (bool isSuccess, string response) = await _mesService.SubmitGetAsync(ProductMainSN, "", submitData.ToString(), resultIndex == 1 ? true : false, _LastMesCheckTime[i], serverTimeResult.Now); if (isSuccess) { LogHelper.WriteLogMes($"上传mes成功"); SendTaskMessage($"上传mes成功", MessageLevel.Debug); //ProductMainSN = ""; } else { LogHelper.WriteLogMes($"上传mes失败"); SendTaskMessage($"上传mes失败", MessageLevel.Error); //ProductMainSN = ""; } await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)3); //是否保存当前的产品记录至CSV? if (stationConfig.SaveCsv) { //判断锁付路径字符串是否为空,如果不为空则保存,否则不保存 if (!string.IsNullOrEmpty(stationConfig.SaveCsvPath)) { foreach (var item in lockResultsAll) { DFC.Add(new DataFormCtq { PPID = ProductMainSN, PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME, PROCESS_START_TIME = _LastMesCheckTime[i].ToString(), CTQ_NAME = item.PhotoName, CTQ_VALUE = item.ResultData.Replace(",", ";"), CTQ_LSL = item.DownLimit, CTQ_USL = item.UpLimit, PROCESS_END_TIME = serverTimeResult.Now.ToString(), SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME, COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE, REVISION = stationConfig.DataInfo.REVISION, WO = wo, MFG_LOT = stationConfig.DataInfo.MFG_LOT, MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE, PROCESS_OUTCOME = item.PhotoPassed == "OK" ? "PASS" : "FAIL", PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID, CTQ_UNIT_OF_MEASURE = "mm", ERROR_MESSAGE = item.PhotoPassed == "OK" ? "" : $"{item.PhotoName} OOS", PD_ATTR_01= "xxxxxxxx1", PD_ATTR_02 = item.MidLimit, PD_ATTR_03 = "", PD_ATTR_04 = "", PD_ATTR_05 = "" }); } bool recordResult = RecordStationResult(i, DFC, ProductMainSN, serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds, _LastMesCheckTime[i], stationConfig.SaveCsvPath); if (recordResult) { SendTaskMessage($"{i}:{stationConfig.DeviceName}产品记录保存成功", MessageLevel.Debug); } else { SendTaskMessage($"{i}:{stationConfig.DeviceName}产品记录保存失败", MessageLevel.Error); } } else { SendTaskMessage($"{i}:{stationConfig.DeviceName}工位未配置保存路径,无法保存产品记录", MessageLevel.Error); } } else { SendTaskMessage($"{i}:{stationConfig.DeviceName}工位未配置保存产品记录", MessageLevel.Debug); } //WriteProductLog(lockResultsAll, code, CTtime); lock (_stateLock) { lockResultsAll.Clear(); } ProductMainSN = ""; LogHelper.WriteLogMes($"【mes结束ADD】"); SendTaskMessage($"mes结束ADD", MessageLevel.Info); } else { SendTaskMessage($"{i}过站检查信号:state={state},处理为默认状态", MessageLevel.Alarm); await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)0); } } } } } } catch (Exception ex) { SendTaskMessage(ex.Message, MessageLevel.Error); } } /// /// 异步执行流程拍照 /// /// /// /// private Task<(bool IsSucceed, bool[] Result, string Message)> ExecuteProcedureAsync(int pointIndex, Guid procedureId) { return Task.Run(async () => { List results = new List(); // 获取当前产品 var currentProduct = _productService.GetCurrentProduct(); if (currentProduct == null) { return (false, null, "当前产品为空,未加载产品!"); } var cameraProcedures = currentProduct.CameraProcedures; if (cameraProcedures == null || cameraProcedures.Count == 0) { SendTaskMessage($"当前产品未配置 CameraProcedures,无法执行视觉流程", MessageLevel.Alarm); return (false, null, $"当前产品未配置 CameraProcedures,无法执行视觉流程"); } var ctsAll = new CancellationTokenSource(); try { ProcedureModel selectedProcedure = null; try { foreach (var cp in cameraProcedures) { if (cp?.ProcedureModels == null) continue; selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == procedureId); if (selectedProcedure != null) break; } } catch (Exception ex) { LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex); } if (selectedProcedure == null) { SendTaskMessage($"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={pointIndex}", MessageLevel.Alarm); return (false, null, $"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={procedureId}"); } SendTaskMessage($"开始执行 AOI 流程 (Point#{pointIndex}) 流程Id={pointIndex}", MessageLevel.Debug); try { //1. 执行拍照,图像处理 var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint1(selectedProcedure, null, null, ctsAll.Token); if (visionResult.Count == 0) { SendTaskMessage("Count值为0", MessageLevel.Alarm); return (false, null, $"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={procedureId}"); } //2. 结果分析 for (int i = 1; i <= visionResult.Count; i++) { LockResult lockResult1 = new LockResult(); //if (pointIndex == currentProduct.PhotoCount && selectedProcedure.Id == currentProduct.FixedUpCamera1ProcedureId && i == 1) //{ // lockResult1.Number = 1; //} string[] strpoints1 = visionResult.Items[i].Split(','); lockResult1.PhotoName = strpoints1[0]; lockResult1.ResultData = strpoints1[1]; lockResult1.PhotoCode = ProductMainSN; var globalParam = currentProduct.GlobalParamListCollection.FirstOrDefault(p => p.Name == strpoints1[0]); if (globalParam != null) { lockResult1.UpLimit = globalParam.Param1; lockResult1.DownLimit = globalParam.Param2; lockResult1.MidLimit = globalParam.Param5; string ResData = strpoints1[1]; if (ResData.Contains("NA")) { ResData = "-1000"; } string[] body = ResData.Split(";"); bool resultflog = true; foreach (var item in body) { if (Convert.ToDouble(item) >= Convert.ToDouble(globalParam.Param2) && Convert.ToDouble(item) <= Convert.ToDouble(globalParam.Param1)) { } else { resultflog = false; } } if (resultflog) { lockResult1.PhotoPassed = "OK"; results.Add(true); } else { lockResult1.PhotoPassed = "NG"; results.Add(false); } } lock (_stateLock) { lockResultsAll.Add(lockResult1); } App.Current.Dispatcher.Invoke(() => { _eventAggregator.GetEvent().Publish(lockResult1); }); } //排序 //lock (_stateLock) //{ // var bf1 = lockResultsAll.OrderBy(p => p.Number); // lockResultsAll = new List(bf1); //} } catch (Exception ex) { LogHelper.WriteLogError("执行 AOI 视觉流程时出错", ex); SendTaskMessage($"执行 AOI 视觉流程异常: {ex.Message}", MessageLevel.Alarm); } return (true, results.ToArray(), $"成功"); } catch (Exception ex) { LogHelper.WriteLogError("处理固定相机检测拍照时出错", ex); return (false, null, $"处理固定相机检测拍照时出错"); } }); } /// /// 异步执行流程拍照 /// /// /// /// private Task<(bool IsSucceed, bool[] Result, string Message)> ExecuteProcedureAsync(int pointIndex, Guid procedureId, ICogImage[] images) { return Task.Run(async () => { List results = new List(); // 获取当前产品 var currentProduct = _productService.GetCurrentProduct(); if (currentProduct == null) { return (false, null, "当前产品为空,未加载产品!"); } var cameraProcedures = currentProduct.CameraProcedures; if (cameraProcedures == null || cameraProcedures.Count == 0) { SendTaskMessage($"当前产品未配置 CameraProcedures,无法执行视觉流程", MessageLevel.Alarm); return (false, null, $"当前产品未配置 CameraProcedures,无法执行视觉流程"); } var ctsAll = new CancellationTokenSource(); try { ProcedureModel selectedProcedure = null; try { foreach (var cp in cameraProcedures) { if (cp?.ProcedureModels == null) continue; selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == procedureId); if (selectedProcedure != null) break; } } catch (Exception ex) { LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex); } if (selectedProcedure == null) { SendTaskMessage($"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={pointIndex}", MessageLevel.Alarm); return (false, null, $"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={procedureId}"); } SendTaskMessage($"开始执行 AOI 流程 (Point#{pointIndex}) 流程Id={pointIndex}", MessageLevel.Debug); try { var sysConfig = _configService.GetSystemConfiguration(); if (selectedProcedure.Id == currentProduct.MoveDownCameraLockPhotoProcedureId && sysConfig.TurnOffAllLightUse == true) { await _remoteCommandService.TurnOffLightAfterPhoto(selectedProcedure); } //1. 执行拍照,图像处理 var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint1(selectedProcedure, images, null, null, ctsAll.Token); if (visionResult.Count == 0) { SendTaskMessage("Count值为0", MessageLevel.Alarm); return (false, null, $"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={procedureId}"); } //2. 结果分析 for (int i = 1; i <= visionResult.Count; i++) { LockResult lockResult1 = new LockResult(); //if (pointIndex == currentProduct.PhotoCount && selectedProcedure.Id == currentProduct.FixedUpCamera1ProcedureId && i == 1) //{ // lockResult1.Number = 1; // lock (_stateLock) // { // lockResultsAll.Clear(); // } //} string[] strpoints1 = visionResult.Items[i].Split(','); lockResult1.PhotoName = strpoints1[0]; lockResult1.ResultData = strpoints1[1]; lockResult1.PhotoCode = ProductMainSN; var globalParam = currentProduct.GlobalParamListCollection.FirstOrDefault(p => p.Name == strpoints1[0]); if (globalParam != null) { lockResult1.UpLimit = globalParam.Param1; lockResult1.DownLimit = globalParam.Param2; lockResult1.MidLimit = globalParam.Param5; string ResData = strpoints1[1]; if (ResData.Contains("NA")) { ResData = "-1000"; } string[] body = ResData.Split(";"); bool resultflog = true; foreach (var item in body) { if (Convert.ToDouble(item) >= Convert.ToDouble(globalParam.Param2) && Convert.ToDouble(item) <= Convert.ToDouble(globalParam.Param1)) { } else { resultflog = false; } } if (resultflog) { lockResult1.PhotoPassed = "OK"; results.Add(true); } else { lockResult1.PhotoPassed = "NG"; results.Add(false); } } lock (_stateLock) { lockResultsAll.Add(lockResult1); } App.Current.Dispatcher.Invoke(() => { _eventAggregator.GetEvent().Publish(lockResult1); }); } ////排序 //lock (_stateLock) //{ // var bf1 = lockResultsAll.OrderBy(p => int.Parse(p.PhotoName)); // lockResultsAll = new List(bf1); //} } catch (Exception ex) { LogHelper.WriteLogError("执行 AOI 视觉流程时出错", ex); SendTaskMessage($"执行 AOI 视觉流程异常: {ex.Message}", MessageLevel.Alarm); } return (true, results.ToArray(), $"成功"); } catch (Exception ex) { LogHelper.WriteLogError("处理固定相机检测拍照时出错", ex); return (false, null, $"处理固定相机检测拍照时出错"); } }); } /// /// 是否是3D相机 /// /// /// private bool Is3D(Guid procedureId) { // 获取当前产品 var currentProduct = _productService.GetCurrentProduct(); if (currentProduct == null) { return false; } var cameraProcedures = currentProduct.CameraProcedures; if (cameraProcedures == null || cameraProcedures.Count == 0) { return false; } ProcedureModel selectedProcedure = null; try { foreach (var cp in cameraProcedures) { if (cp?.ProcedureModels == null) continue; selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == procedureId); if (selectedProcedure != null) break; } } catch (Exception ex) { LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex); } if (selectedProcedure == null) { return false; } var camera = _cameraService.GetCamera(selectedProcedure.CameraId); if (camera == null) { return false; } return camera.Is3D; } /// /// 2D相机先采集图像 /// /// /// private async Task<(bool IsSucceed, ICogImage[] imges, string Message)> GrabImage(int pointIndex, Guid procedureId) { // 获取当前产品 var currentProduct = _productService.GetCurrentProduct(); if (currentProduct == null) { return (false, null, "当前产品为空,未加载产品!"); } var cameraProcedures = currentProduct.CameraProcedures; if (cameraProcedures == null || cameraProcedures.Count == 0) { SendTaskMessage($"当前产品未配置 CameraProcedures,无法执行视觉流程", MessageLevel.Alarm); return (false, null, $"当前产品未配置 CameraProcedures,无法执行视觉流程"); } try { ProcedureModel selectedProcedure = null; try { foreach (var cp in cameraProcedures) { if (cp?.ProcedureModels == null) continue; selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == procedureId); if (selectedProcedure != null) break; } } catch (Exception ex) { LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex); } if (selectedProcedure == null) { SendTaskMessage($"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={pointIndex}", MessageLevel.Alarm); return (false, null, $"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={procedureId}"); } SendTaskMessage($"开始执行 AOI 流程 (Point#{pointIndex}) 流程Id={pointIndex}", MessageLevel.Debug); try { var sysConfig = _configService.GetSystemConfiguration(); if (selectedProcedure.Id == currentProduct.FixedDownCameraProcedureId && sysConfig.TurnOnAllLightUse == true) { await _remoteCommandService.SetLightBeforePhoto(selectedProcedure); } //1. 执行拍照 return await _remoteCommandService.ExecuteGrabImageAsync(selectedProcedure); } catch (Exception ex) { LogHelper.WriteLogError("执行 AOI 视觉图像采集时出错", ex); SendTaskMessage($"执行 AOI 视觉图像采集时出错: {ex.Message}", MessageLevel.Alarm); } return (false, null, $"图像采集失败"); } catch (Exception ex) { LogHelper.WriteLogError("处理固定相机检测拍照时出错", ex); return (false, null, $"处理固定相机检测拍照时出错"); } } /// /// 为所有相机设置批处理点数(会调用具体相机实现的 SetBatchPoints) /// /// public void SetBatchPoints(int CameraNum, int points) { try { if (points == 0 || points < 0) { return; } var cameras = _cameraService.GetCameraByNumber(CameraNum); if (cameras == null) return; try { // 优先针对已知的 SSZNCamera 类型直接调用 if (cameras is TeamAAS_VP.Core.Cameras.SSZNCamera sszn) { sszn.CameraRevFinish = false; sszn.SetBatchPoints(points); } } catch (Exception ex) { LogHelper.WriteLogError($"SetBatchPoints to camera {cameras?.Name} failed", ex); } } catch (Exception ex) { LogHelper.WriteLogError("SetBatchPoints failed", ex); } } public void SetBatchPoints(int[] CameraSpoints) { try { for (int i = 0; i < CameraSpoints.Length; i++) { SetBatchPoints(i + 1, CameraSpoints[i]); } } catch (Exception ex) { LogHelper.WriteLogError("SetBatchPoints failed", ex); } } #endregion #region 方法 private void SendTaskMessage(string msg, MessageLevel level) { App.Current.Dispatcher.Invoke(() => { _eventAggregator.GetEvent().Publish(new Models.MessageStruct() { Message = msg, level = level }); }); } private async void DoYieldTime(object state) { try { //获取当前产品 CurrentProduct= _productService.GetCurrentProduct(); var currentproduct = _productService.GetCurrentProduct(); if (currentproduct == null) return; TotalQuantity = await _systemDatabaseService.GetOverallProductionAsync(currentproduct.Name); TotalQuantityToday = await _systemDatabaseService.GetTodayProductionAsync(currentproduct.Name); CurrentUPH = await _systemDatabaseService.GetLastHourProductionAsync(currentproduct.Name); NgNumber = await _systemDatabaseService.GetNGProductionAsync (currentproduct.Name); Yield = ((double)TotalQuantityToday - (double)NgNumber) / (double)TotalQuantityToday * 100; } catch (Exception) { } } #region vm启动检测 /// /// 杀死所有VM有关进程 /// public void KillVMProcess() { KillProcess("VisionMasterServerApp"); KillProcess("VisionMaster"); KillProcess("VmModuleProxy.exe"); KillProcess("vServerApp.exe"); } /// /// 杀死指定进程名的进程 /// /// public void KillProcess(string strKillName) { foreach (System.Diagnostics.Process p in System.Diagnostics.Process.GetProcesses()) { if (p.ProcessName.Contains(strKillName)) { try { p.Kill(); p.WaitForExit(); } catch (Exception ex) { LogHelper.WriteLogError($"杀死进程:{strKillName}时失败!", ex); } } } } #endregion /// /// 记录工位的结果,其他工位要存储的数据项按照键值对集合的形式传入,键为数据项名称,值为数据项的值 /// /// /// /// /// /// /// /// /// private bool RecordStationResult(int stationIndex, IEnumerable dfcs, string productMainSN, double ct, DateTime timestamp, string savePath, bool isFirstEnter = true) { try { //获取当前工位的配置 var stationConfig = _configService.GetDeviceInfo(); if (stationConfig == null) return false; //如果保存路径为空,则不保存 if (string.IsNullOrEmpty(savePath)) return false; string fullPath = savePath; //如果保存路径是一个文件路径,则直接保存,否则按照工位和日期进行保存 if (File.Exists(savePath) || Path.HasExtension(savePath)) { fullPath = savePath; //如果路径不存在,则创建 // 创建目录 string directory = Path.GetDirectoryName(fullPath); if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) { Directory.CreateDirectory(directory); } } else { //结果保存至CSV文件,文件名格式:savePath\yyyy-MM\工位编号_工位名称_yyyy-MM-dd.csv string datePath = timestamp.ToString("yyyy-MM") + "\\"; string dirPath = Path.Combine(savePath, datePath); if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath); string fileName = $"{stationIndex}_{stationConfig.DeviceName}_{timestamp.ToString("yyyy-MM-dd")}.csv"; fullPath = Path.Combine(dirPath, fileName); } StringBuilder sb = new StringBuilder(); if (!File.Exists(fullPath)) { sb.Append("PPID,PROCESS_NAME,PROCESS_START_TIME,CTQ_NAME,CTQ_VALUE,CTQ_LSL,CTQ_USL,PROCESS_END_TIME,SUPPLIER_NAME,COMMODITY_TYPE,REVISION,WO#,MFG_LOT#," + "MFG_ASSY_LINE,PROCESS_OUTCOME,PROCESS_MACHINE_ID,CTQ_UNIT_OF_MEASURE,ERROR_MESSAGE,PD_ATTR_01,PD_ATTR_02,PD_ATTR_03,PD_ATTR_04,PD_ATTR_05"); sb.AppendLine(); } if (dfcs == null || dfcs.Count() == 0) { return false; } foreach (var dfc in dfcs) { sb.Append($"{dfc.PPID},{dfc.PROCESS_NAME},{dfc.PROCESS_START_TIME},{dfc.CTQ_NAME},{dfc.CTQ_VALUE},{dfc.CTQ_LSL},{dfc.CTQ_USL},{dfc.PROCESS_END_TIME},{dfc.SUPPLIER_NAME},{dfc.COMMODITY_TYPE},{dfc.REVISION},{dfc.WO},{dfc.MFG_LOT},{dfc.MFG_ASSY_LINE},{dfc.PROCESS_OUTCOME},{dfc.PROCESS_MACHINE_ID},{dfc.CTQ_UNIT_OF_MEASURE},{dfc.ERROR_MESSAGE},{dfc.PD_ATTR_01},{dfc.PD_ATTR_02},{dfc.PD_ATTR_03},{dfc.PD_ATTR_04},{dfc.PD_ATTR_05}"); sb.AppendLine(); } // 使用 StreamWriter 以追加模式打开文件 StreamWriter sw = new StreamWriter(fullPath, true, Encoding.UTF8); sw.Write(sb.ToString()); sw.Close(); sw.Dispose(); return true; } catch (Exception ex) { if (!isFirstEnter) { return false; } LogHelper.WriteLogError("记录其他工位结果时出错!", ex); //我希望在这里生成一个临时文件来保存这次的记录,因为如果本地文件被打开时可能会导致无法写入,如果不保存的话可能会丢失这次的记录,所以我想在这里生成一个临时文件来保存这次的记录 //生成临时文件的路径,格式为savePath\yyyy-MM\工位编号_yyyy-MM-dd_temp\工位编号_yyyy-MM-dd_HH-mm-ss-fff_temp.csv string datePath = timestamp.ToString("yyyy-MM") + "\\"; string tempDirPath = Path.Combine(savePath, datePath, $"{stationIndex}_{timestamp.ToString("yyyy-MM-dd")}_temp"); string tempFileName = $"{stationIndex}_{timestamp.ToString("yyyy-MM-dd_HH-mm-ss-fff")}_temp.csv"; RecordStationResult(stationIndex, dfcs, productMainSN, ct, timestamp, tempFileName, false); return false; } } #endregion // 用于等待“指定相机的下一张图到达” private readonly object _imageSyncLock = new object(); private readonly Dictionary> _nextImageTcsByCamera = new Dictionary>(); private Task PrepareNextImageWait(Guid cameraId) { lock (_imageSyncLock) { var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); _nextImageTcsByCamera[cameraId] = tcs; return tcs.Task; } } public async Task SignalImageArrived(Guid cameraId, ICogImage image) { await Task.Delay(500); TaskCompletionSource tcs = null; lock (_imageSyncLock) { _nextImageTcsByCamera.TryGetValue(cameraId, out tcs); } tcs?.TrySetResult(image); } public async Task WaitNextImageAsync(Guid cameraId, int timeoutMs, CancellationToken token) { var waitTask = PrepareNextImageWait(cameraId); var completed = await Task.WhenAny(waitTask, Task.Delay(timeoutMs, token)).ConfigureAwait(false); if (completed != waitTask) return null; return await waitTask.ConfigureAwait(false); } //public async Task WaitImageFlagAsync(int cameraNo, int timeoutMs, CancellationToken token) //{ // if (cameraNo < 0 || cameraNo >= ImageData.Length) // { // SendTaskMessage($"等待相机图像失败:CameraNo={cameraNo} 越界", MessageLevel.Alarm); // return false; // } // var start = DateTime.UtcNow; // while (ImageData[cameraNo] == 0) // { // token.ThrowIfCancellationRequested(); // if ((DateTime.UtcNow - start).TotalMilliseconds >= timeoutMs) // { // SendTaskMessage($"等待相机图像超时:CameraNo={cameraNo} Timeout={timeoutMs}ms", MessageLevel.Alarm); // return false; // } // await Task.Delay(100, token).ConfigureAwait(false); // } // return true; //} } }