using Autofac; using Bro.Common.Base; using Bro.Common.Helper; using Bro.Common.Interface; using Bro.Common.Model; using Bro.Common.Model.Interface; using Bro.Common.PubSub; using Bro.Common.UI; using Bro.Device.AuboRobot; using Bro.Device.OmronFins; using Bro.Device.SeerAGV; using Bro.Device.Station.Forms; using HalconDotNet; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Configuration; using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.ExceptionServices; using System.Threading; using System.Threading.Tasks; using static Bro.Common.Helper.EnumHelper; namespace A032.Process { public partial class ProcessControl : IStationProcess { ContainerBuilder builder = new ContainerBuilder(); private void AutoFacRegister(bool isBuild = true) { #region AutoFac注册 builder.RegisterInstance(StationConfig as ProcessConfig); builder.RegisterInstance>(GetDeviceList()); builder.RegisterInstance>(CollectProcessMethods()); if (isBuild) { GlobalVar.Container = builder.Build(); } #endregion } public IStationConfig StationConfig { get; set; } string CONFIG_PATH = ""; private string productionCode = ""; public string ProductionCode { get => productionCode; set { if (productionCode != value) { productionCode = value; string baseDir = ""; string configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"); if (File.Exists(configPath)) { using (StreamReader reader = new StreamReader(configPath, System.Text.Encoding.UTF8)) { string dataStr = reader.ReadToEnd(); JObject data = JsonConvert.DeserializeObject(dataStr); baseDir = data.Value("ConfigPath"); } } if (string.IsNullOrWhiteSpace(baseDir)) { baseDir = AppDomain.CurrentDomain.BaseDirectory; } if (!string.IsNullOrWhiteSpace(productionCode) && productionCode != "Default") { CONFIG_PATH = Path.Combine(baseDir, $"Config_{productionCode}.json"); } else { CONFIG_PATH = Path.Combine(baseDir, "Config.json"); } } } } #region Event public Action OnBitmapOutput { get; set; } public Action OnBitmapClear { get; set; } public Action OnObjectOutput { get; set; } public Action OnExceptionOccured { get; set; } public Action OnProcessStateChanged { get; set; } #endregion #region Property & Field private DeviceState processState = DeviceState.DSUninit; public DeviceState ProcessState { get => processState; set { if (processState != value) { processState = value; Task.Run(() => { OnProcessStateChanged?.Invoke(value); }); //OnProcessStateChanged?.BeginInvoke(value, null, null); } } } Dictionary PLCDict = new Dictionary(); Dictionary RobotDict = new Dictionary(); Dictionary AGVDict = new Dictionary(); Dictionary CameraDict = new Dictionary(); private ProcessConfig Config { get => StationConfig as ProcessConfig; } string _configBackupStr = ""; PubSubCenter PubSubCenter = PubSubCenter.GetInstance(); #region constance variables //const int OFFLINE_FLAG = -999; //const int IGNORE_FEEDBACK = -999; #endregion #endregion public ProcessControl() { InitialStationProcess(); } public ProcessControl(string productionCode, string configPath = "") { ProductionCode = productionCode; InitialStationProcess(configPath); } public virtual void Close() { if (ProcessState == DeviceState.DSClose) return; CloseDevice(PLCDict.Values.ToList()); CloseDevice(RobotDict.Values.ToList()); CloseDevice(AGVDict.Values.ToList()); CloseDevice(CameraDict.Values.ToList()); ProcessState = DeviceState.DSClose; LogAsync(DateTime.Now, "Process Closed", ""); } public virtual void Open() { if (ProcessState == DeviceState.DSOpen) return; InitialProcessMethods(); OpenDevices(RobotDict.Values.ToList()); OpenDevices(AGVDict.Values.ToList()); OpenCameras(); PubSubCenter.Subscribe(PubTag.DeviceOperation.ToString(), OnCameraOp); OpenDevices(PLCDict.Values.ToList()); ProcessState = DeviceState.DSOpen; QueryRobotIO(); //Task.Run(() => //{ // //PLCMonitor(); //}); LogAsync(DateTime.Now, "Process Opened", ""); } private object OnCameraOp(ISubscriber arg1, object arg2, object arg3) { string cameraId = arg2.ToString(); if (CameraDict.ContainsKey(cameraId)) { CameraDict[cameraId].Snapshot(); } return null; } public virtual void OpenCameras() { //Config.CameraConfigs.ForEach(c => //{ // CameraBase camera = CameraHelper.GetCameraInstance(c.DriverType); // camera.InitialConfig = c; // OpenCamera(camera); // CameraDict[camera.InitialConfig.ID] = camera; //}); CameraDict.Values.ToList().ForEach(c => { OpenCamera(c); }); } protected void OpenCamera(CameraBase camera) { if (camera.InitialConfig?.IsEnabled ?? false) { camera.UpdateShowImage -= CameraUpdateImage; camera.UpdateShowImage += CameraUpdateImage; camera.OnLog = OnDeviceLog; camera.StateChange(DeviceState.DSInit); camera.StateChange(DeviceState.DSOpen); (camera as Bro.Device.HikCamera.HikCameraDriver).HImageOutput = HikCameraHImageOutput; } } private void HikCameraHImageOutput(HImage arg1, string arg2) { } private void OpenDevices(List devices) where T : IDevice { devices.ForEach(d => { if (d.InitialConfig?.IsEnabled ?? false) { d.OnLog = OnDeviceLog; d.StateChange(DeviceState.DSInit); d.StateChange(DeviceState.DSOpen); } }); } private void CloseDevice(List devices) where T : IDevice { devices.ForEach(d => { if (d.CurrentState != DeviceState.DSClose) { d.StateChange(DeviceState.DSClose); } }); } public List CollectProcessMethods() { List resultList = new List(); var methods = this.GetType().GetMethods().ToList(); methods.ForEach(m => { var attr = m.GetCustomAttribute(); if (attr != null) { resultList.Add(attr); } }); return resultList; } public void InitialStationProcess(string configPath = "") { ProcessException.OnExceptionNotice = LogAsync; StationConfig = LoadStationConfig(configPath); #region 个别配置的特别处理 #endregion _warningRemains.CollectionChanged -= _warningRemains_CollectionChanged; _warningRemains.CollectionChanged += _warningRemains_CollectionChanged; InitialPLCs(); InitialRobots(); InitialAGVs(); InitialCameras(); AutoFacRegister(); LogAsync(DateTime.Now, "Process Initialized", ""); } private void InitialCameras() { Config.CameraConfigCollection.ForEach(c => { CameraBase camera = CameraHelper.GetCameraInstance(c.DriverType); camera.InitialConfig = c; CameraDict[camera.InitialConfig.ID] = camera; }); } private void InitialPLCs() { Config.PLCConfigCollection.ForEach(c => { OmronFinsDriver plc = new OmronFinsDriver(); plc.InitialConfig = c; PLCDict[plc.InitialConfig.ID] = plc; plc.OnMonitorAlarm -= Plc_OnMonitorAlarm; plc.OnMonitorInvoke -= Plc_OnMonitorInvoke; plc.OnMonitorAlarm += Plc_OnMonitorAlarm; plc.OnMonitorInvoke += Plc_OnMonitorInvoke; }); } private void InitialRobots() { Config.RobotConfigCollection.ForEach(c => { AuboRobotDriver robot = new AuboRobotDriver(); robot.InitialConfig = c; RobotDict[robot.InitialConfig.ID] = robot; }); } private void InitialAGVs() { Config.AGVConfigCollection.ForEach(c => { SeerAGVDriver agv = new SeerAGVDriver(); agv.InitialConfig = c; AGVDict[agv.InitialConfig.ID] = agv; }); } public void InitialStationProcess() { InitialStationProcess(""); } private ProcessConfig LoadStationConfig(string configPath = "") { ProcessConfig config = new ProcessConfig(); if (string.IsNullOrWhiteSpace(configPath)) { configPath = CONFIG_PATH; } try { if (File.Exists(configPath)) { using (StreamReader reader = new StreamReader(configPath, System.Text.Encoding.UTF8)) { _configBackupStr = reader.ReadToEnd(); config = JsonConvert.DeserializeObject(_configBackupStr, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All }); } } if (config == null) { config = new ProcessConfig(); } } catch (Exception ex) { } return config; } public void Pause() { } public void Resume() { } public void SaveStationConfig(IStationConfig config) { AutoFacRegister(false); ProcessConfig pConfig = config as ProcessConfig; if (pConfig == null) throw new ProcessException("目前只支持ProcessConfig类型的非空内容保存", null); string newConfig = JsonConvert.SerializeObject(pConfig, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto }); using (StreamWriter writer = new StreamWriter(CONFIG_PATH, false, System.Text.Encoding.UTF8)) { writer.Write(newConfig); writer.Flush(); writer.Close(); } if (_configBackupStr != newConfig) { SaveBackupConfig(); } } private void SaveBackupConfig() { string backPath = Path.GetDirectoryName(CONFIG_PATH); backPath = Path.Combine(backPath, ProductionCode + "_bk"); if (!Directory.Exists(backPath)) { Directory.CreateDirectory(backPath); } backPath = Path.Combine(backPath, $"Config_{ProductionCode}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.json"); using (StreamWriter writer = new StreamWriter(backPath, false, System.Text.Encoding.UTF8)) { writer.Write(_configBackupStr); writer.Flush(); writer.Close(); } } /// /// 调用方法的字典集合 /// Key:MethodCode,Value:MethodInfo /// public Dictionary _processMethodDict = new Dictionary(); /// /// Halcon算法工具字典,在初始化时统一一次性载入 /// Key:MethodCode,Value:HalconTool /// protected Dictionary _halconToolDict = new Dictionary(); private void InitialProcessMethods() { _processMethodDict = new Dictionary(); var methods = this.GetType().GetMethods().ToList(); methods.ForEach(m => { var attr = m.GetCustomAttribute(); if (attr != null) { _processMethodDict[attr.MethodCode] = m; #region 初始化HalconTool //if (attr.DeviceType.EndsWith("Camera")) //{ // if (StationConfig.ProcessOpConfigDict.Keys.Contains(attr.MethodCode)) // { // var opConfig = StationConfig.ProcessOpConfigDict[attr.MethodCode] as HalconRelatedCameraOprerationConfigBase; // if (opConfig != null) // { // if (!string.IsNullOrWhiteSpace(opConfig.AlgorithemPath)) // { // string directoryPath = Path.GetDirectoryName(opConfig.AlgorithemPath); // string fileName = Path.GetFileNameWithoutExtension(opConfig.AlgorithemPath); // HDevEngineTool tool = new HDevEngineTool(directoryPath); // tool.LoadProcedure(fileName); // _halconToolDict[attr.MethodCode] = tool; // } // } // } //} #endregion } }); #region 初始化HalconTool _halconToolDict = new Dictionary(); Config.PLCConfigCollection.SelectMany(plcConfig => plcConfig.MonitorSetCollection).Select(ms => ms.OpConfig).ToList().ForEach(c => { IHalconToolPath toolPath = c as IHalconToolPath; if (toolPath != null) { toolPath.GetHalconToolPathList().ForEach(path => { if (!string.IsNullOrWhiteSpace(path)) { string directoryPath = Path.GetDirectoryName(path); string fileName = Path.GetFileNameWithoutExtension(path); HDevEngineTool tool = new HDevEngineTool(directoryPath); tool.LoadProcedure(fileName); _halconToolDict[path] = tool; } }); } }); #endregion } public List GetDeviceList() { List list = new List(); list.AddRange(PLCDict.Values); list.AddRange(RobotDict.Values); list.AddRange(AGVDict.Values); list.AddRange(CameraDict.Values); return list; } #region PLC监听 private void Plc_OnMonitorInvoke(DateTime dt, MonitorSet monitorSet) { IOperationConfig config = monitorSet.OpConfig; string methodCode = monitorSet.MethodCode; object res = null; int reTryTimes = config.ReTryTimes; do { try { //有IOperationConfig参数的调用 res = _processMethodDict[methodCode].Invoke(this, new object[] { config }); reTryTimes = -1; } catch (Exception invokeEX) //流程动作异常失败 { Exception ex = invokeEX.InnerException == null ? invokeEX : invokeEX.InnerException; reTryTimes--; if (reTryTimes <= 0) //如果没有重试次数了就通知PLC { if (config == null || config.ExceptionValue == 0) { if (!(ex is ProcessException)) { //如果是算法异常,返回NG值;否则返回异常值 if (ex is HDevEngineException) { res = new ProcessResponse((int)ReturnValue.NGVALUE); } else { res = new ProcessResponse((int)ReturnValue.EXCEPTIONVALUE); } var newEx = new ProcessException("函数" + methodCode + "执行异常", ex); } else { if ((ex as ProcessException).OriginalException != null) { res = new ProcessResponse((int)ReturnValue.EXCEPTIONVALUE); } else { res = new ProcessResponse((int)ReturnValue.NGVALUE); } } } else { res = new ProcessResponse(config.ExceptionValue); } LogAsync(DateTime.Now, methodCode + "异常信息", ex.GetExceptionMessage()); } } if (reTryTimes > 0) { LogAsync(DateTime.Now, methodCode + " reTryTimes", reTryTimes.ToString()); } } while (reTryTimes > 0); #region 设置返回值 monitorSet.Response = res as ProcessResponse; //测试模式下始终反馈OK信号 if (StationConfig.IsDemoMode && monitorSet.Response.ResultValue <= 0) { monitorSet.Response.ResultValue = (int)ReturnValue.OKVALUE; } #endregion //sw.Stop(); //LogAsync(DateTime.Now, methodCode + " 调用耗时: " + sw.ElapsedMilliseconds.ToString() + "ms", ""); //TimeRecordCSV(DateTime.Now, methodCode + "调用", (int)sw.ElapsedMilliseconds); //sw.Start(); #region 原有PLC写入结果操作,现转到异步调用后回调去执行 //ProcessResponse resValues = res as ProcessResponse; //if (resValues.ResultValue == (int)PLCReplyValue.IGNORE) //{ // return; //} //if (monitorSet.ReplyDataAddress != -1 && resValues.DataList.Count > 0) //{ // PLC_ITEM item = new PLC_ITEM(); // item.OP_TYPE = 2; // item.ITEM_LENGTH = resValues.DataList.Count; // item.ADDRESS = monitorSet.ReplyDataAddress.ToString(); // item.ITEM_VALUE = String.Join(",", resValues.DataList); // PLC.WriteItem(item, false); //} //if (monitorSet.NoticeAddress != -1) //{ // //测试模式下始终反馈OK信号 // if (StationConfig.IsDemoMode && resValues.ResultValue <= 0) // { // resValues.ResultValue = (int)ReturnValue.OKVALUE; // } // int repeatTime = 5; // //LogAsync(DateTime.Now, methodCode + "开始反馈", ""); // do // { // try // { // PLC.WriteSingleAddress(set.NoticeAddress, resValues.ResultValue, false); // repeatTime = 0; // } // catch (Exception ex) // { // repeatTime--; // if (repeatTime <= 0) // { // new ProcessException("PLC反馈写入异常", ex); // } // } // } while (repeatTime > 0); //} #endregion } private void Plc_OnMonitorAlarm(DateTime dt, WarningSet warning, bool isAlarmRaised) { } //List _monitorList = new List(); //List _monitorSetList = new List(); //List _methodCodeList = new List(); //ConcurrentDictionary _halconTaskDict = new ConcurrentDictionary(); //ConcurrentDictionary _halconHandleDict = new ConcurrentDictionary(); ///// ///// PLC监听 ///// //private void PLCMonitor() //{ // _monitorSetList = StationConfig.PLCMonitorSet.Values.ToList(); // _methodCodeList = StationConfig.PLCMonitorSet.Keys.ToList(); // while (PLC.CurrentState == DeviceState.DSOpen) // { // try // { // List newMonitorList = PLC.Monitor(PLC.IConfig.EventStartAddress, PLC.IConfig.EventLength); // if (newMonitorList == null || newMonitorList.Count == 0) // continue; // Stopwatch sw = new Stopwatch(); // sw.Start(); // if (_monitorList.Count == newMonitorList.Count) // { // var tempNew = new List(newMonitorList); // var tempOld = new List(_monitorList); // //Task.Run(() => // //{ // MonitorCheckAndInvoke(tempNew, tempOld); // //}); // } // _monitorList = new List(newMonitorList); // sw.Stop(); // if (sw.ElapsedMilliseconds > 10) // { // LogAsync(DateTime.Now, $"轮询时间:{sw.ElapsedMilliseconds}", ""); // TimeRecordCSV(DateTime.Now, "轮询时间", (int)sw.ElapsedMilliseconds); // } // Thread.Sleep(PLC.IConfig.ScanInterval); // } // catch (Exception ex) // { // LogAsync(DateTime.Now, "PLC监听异常", ex.GetExceptionMessage()); // } // }; //} //private void MonitorCheckAndInvoke(List newMonitorList, List monitorList) //{ // //await Task.Run(() => // { // Parallel.For(0, monitorList.Count, (index) => // //for (int index = 0; index < monitorList.Count; index++) // { // int plcValue = newMonitorList[index]; // int plcOldValue = monitorList[index]; // #region PLC警报信息 // //bool warningSignal = (index >= Config.PLCConfig.WarningStartIndex && index < Config.PLCConfig.WarningStartIndex + Config.PLCConfig.WarningLength); // // if (warningSignal) // // { // // if (plcValue != plcOldValue) // // { // // int warningIndex = index - Config.PLCConfig.WarningStartIndex; // // for (int i = 0; i < 16; i++) // // { // // var ws = StationConfig.WarningSets.FirstOrDefault(w => w.WaringIndex == (warningIndex * 16) + i); // // if (ws != null) // // { // // int newValue = plcValue >> i & 1; // // int oldValue = plcOldValue >> i & 1; // // if (newValue != oldValue) // // { // // //CurrentPubSub.Publish(PubTag.PLCWarningUpdate.ToString(), newValue == 1, ws, true); // // //仅保存警报信息,不保存提示信息 // // if (ws.WarningLvl == 0) // // { // // if (newValue == 1) // // { // // if (!_warningRemains.Contains(ws.WarningCode)) // // { // // _warningRemains.Add(ws.WarningCode); // // } // // } // // else // // { // // if (_warningRemains.Contains(ws.WarningCode)) // // { // // _warningRemains.Remove(ws.WarningCode); // // } // // } // // SaveAlarm(Config.StationCode, ws, newValue); // // } // // } // // } // // } // // } // // //continue; // // return; // // } // #endregion // if (plcValue != plcOldValue) // { // _monitorSetList.Where(u => u.TriggerIndex == index).ToList().ForEach(monitorSet => // { // int monitorSetIndex = _monitorSetList.IndexOf(monitorSet); // string methodCode = _methodCodeList[monitorSetIndex]; // LogAsync(DateTime.Now, $"索引{monitorSet.TriggerIndex}变动,方法:{methodCode}", $"原先值:{plcOldValue},变化值:{plcValue}"); // //触发值为-999时,监听地址数据变动即触发函数 // if (monitorSet != null && (plcValue == monitorSet.TriggerValue || monitorSet.TriggerValue == -999)) // { // List inputData = new List(); // if (monitorSet.InputDataIndex != null && monitorSet.InputDataIndex.Count > 0) // { // monitorSet.InputDataIndex.ForEach(p => // { // inputData.Add(newMonitorList[p]); // }); // } // LogAsync(DateTime.Now, "PLC触发", methodCode + "触发\r\n触发值:" + plcValue + ";传入值:" + (inputData == null || inputData.Count == 0 ? "NA" : string.Join(",", inputData))); // if (_halconToolDict.Keys.Contains(methodCode)) // { // if (!_halconTaskDict.Keys.Contains(methodCode)) // { // _halconHandleDict[methodCode] = new AutoResetEvent(false); // _halconTaskDict[methodCode] = new Task((obj) => // { // while (true) // { // _halconHandleDict[methodCode].WaitOne(); // if (PLC.CurrentState != DeviceState.DSOpen) // continue; // object[] objs = obj as object[]; // int msIndex = Convert.ToInt32(objs[0]); // MonitorSet set = objs[1] as MonitorSet; // List inputDataIndex = objs[2] as List; // List datas = new List(); // if (inputDataIndex != null) // { // inputDataIndex.ForEach(p => // { // datas.Add(newMonitorList[p]); // }); // } // MethodHandle(msIndex, set, datas, plcValue); // } // }, new object[] { monitorSetIndex, monitorSet, monitorSet.InputDataIndex }); // _halconTaskDict[methodCode].Start(); // } // _halconHandleDict[methodCode].Set(); // } // else // { // ThreadPool.QueueUserWorkItem(MethodHandle, new object[] { monitorSetIndex, monitorSet, inputData, plcValue }); // } // } // }); // } // } // ); // } // //); //} //private void MethodHandle(object obj) //{ // object[] objs = obj as object[]; // int monitorSetIndex = Convert.ToInt32(objs[0]); // MonitorSet set = objs[1] as MonitorSet; // List inputDataValue = objs[2] as List; // int triggerValue = Convert.ToInt32(objs[3]); // MethodHandle(monitorSetIndex, set, inputDataValue, triggerValue); //} //private void MethodHandle(int monitorSetIndex, MonitorSet set, List inputDataValue, int triggerValue) //{ // //await Task.Run(() => // //Task.Run(() => // { // string methodCode = _methodCodeList[monitorSetIndex]; // Stopwatch sw = new Stopwatch(); // sw.Start(); // try // { // if (_processMethodDict.Keys.Contains(methodCode)) // { // IOperationConfig config = null; // if (StationConfig.ProcessOpConfigDict.Keys.Contains(methodCode)) // { // config = StationConfig.ProcessOpConfigDict[methodCode]; // } // else // { // config = new OperationConfigBase(); // } // config.InputPara = inputDataValue; // object res = null; // int reTryTimes = config.ReTryTimes; // do // { // try // { // //有IOperationConfig参数的调用 // res = _processMethodDict[methodCode].Invoke(this, new object[] { config }); // reTryTimes = -1; // } // catch (Exception invokeEX) //流程动作异常失败 // { // Exception ex = invokeEX.InnerException == null ? invokeEX : invokeEX.InnerException; // reTryTimes--; // if (reTryTimes <= 0) //如果没有重试次数了就通知PLC // { // //保存最后一次NG的图片 // //SaveNGImage(_processMethodDict[methodCode]); // if (config == null || config.ExceptionValue == 0) // { // if (!(ex is ProcessException)) // { // //CurrentPubSub.Publish(PubTag.ExceptionUpdate.ToString(), "函数" + methodCode + "执行异常", ex, true); // //如果是算法异常,返回NG值;否则返回异常值 // if (ex is HDevEngineException) // { // res = new ProcessResponse((int)ReturnValue.NGVALUE); // } // else // { // res = new ProcessResponse((int)ReturnValue.EXCEPTIONVALUE); // } // var newEx = new ProcessException("函数" + methodCode + "执行异常", ex); // } // else // { // if ((ex as ProcessException).OriginalException != null) // { // res = new ProcessResponse((int)ReturnValue.EXCEPTIONVALUE); // } // else // { // res = new ProcessResponse((int)ReturnValue.NGVALUE); // } // } // } // else // { // res = new ProcessResponse(config.ExceptionValue); // } // LogAsync(DateTime.Now, methodCode + "异常信息", ex.GetExceptionMessage()); // } // } // if (reTryTimes > 0) // { // LogAsync(DateTime.Now, methodCode + " reTryTimes", reTryTimes.ToString()); // } // } while (reTryTimes > 0); // sw.Stop(); // LogAsync(DateTime.Now, methodCode + " 调用耗时: " + sw.ElapsedMilliseconds.ToString() + "ms", ""); // TimeRecordCSV(DateTime.Now, methodCode + "调用", (int)sw.ElapsedMilliseconds); // sw.Start(); // ProcessResponse resValues = res as ProcessResponse; // //if (resValues != null) // //{ // if (resValues.ResultValue == (int)PLCReplyValue.IGNORE) // { // return; // } // if (set.ReplyDataAddress != -1 && resValues.DataList.Count > 0) // { // //int stepLength = 120; // //int startAdd = set.ReplyDataAddress; // //while (resValues.DataList.Count > 0) // //{ // // var data = resValues.DataList.Take(stepLength).ToList(); // // PLC_ITEM item = new PLC_ITEM(); // // item.OP_TYPE = 2; // // item.ITEM_LENGTH = data.Count; // // item.ADDRESS = startAdd.ToString(); // // item.ITEM_VALUE = String.Join(",", data); // // PLC.WriteItem(item); // // if (resValues.DataList.Count > stepLength) // // { // // startAdd += stepLength; // // resValues.DataList = resValues.DataList.Skip(stepLength).ToList(); // // } // //} // //if (resValues.DataList.Count > 0) // //{ // PLC_ITEM item = new PLC_ITEM(); // item.OP_TYPE = 2; // item.ITEM_LENGTH = resValues.DataList.Count; // item.ADDRESS = set.ReplyDataAddress.ToString(); // item.ITEM_VALUE = String.Join(",", resValues.DataList); // PLC.WriteItem(item, false); // //} // } // if (set.NoticeAddress != -1) // { // //测试模式下始终反馈OK信号 // if (StationConfig.IsDemoMode && resValues.ResultValue <= 0) // { // resValues.ResultValue = (int)ReturnValue.OKVALUE; // } // int repeatTime = 5; // //LogAsync(DateTime.Now, methodCode + "开始反馈", ""); // do // { // try // { // PLC.WriteSingleAddress(set.NoticeAddress, resValues.ResultValue, false); // repeatTime = 0; // } // catch (Exception ex) // { // repeatTime--; // if (repeatTime <= 0) // { // new ProcessException("PLC反馈写入异常", ex); // } // } // } while (repeatTime > 0); // //LogAsync(DateTime.Now, methodCode + "结束反馈", ""); // } // //} // } // } // catch (Exception ex) // { // LogAsync(DateTime.Now, _methodCodeList[monitorSetIndex] + "调用异常", ex.GetExceptionMessage()); // } // //finally // //{ // // //IdleFlag--; // // //_idleTimer.Change(BaseConfig.IdleTimeThreshold * 1000, Timeout.Infinite); // //} // sw.Stop(); // LogAsync(DateTime.Now, methodCode + " Elapsed: " + sw.ElapsedMilliseconds.ToString() + "ms", ""); // TimeRecordCSV(DateTime.Now, methodCode + "完成", (int)sw.ElapsedMilliseconds); // } // //); //} //private async void CTHandle(OperationCTCollection ct, int plcValue) //{ // await Task.Run(() => // { // if (plcValue == 0) // { // ct.CSVOutput(StationConfig.CSVFilePath); // //ct.CTList.ForEach(u => // foreach (var u in ct.CTList) // { // u.StartTime = null; // u.EndTime = null; // } // //); // //CurrentPubSub.Publish(PubTag.CTUpdate.ToString(), ct, null, true); // } // else // { // for (int i = 0; i < ct.CTList.Count; i++) // { // if (plcValue == ct.CTList[i].OpTrigger) // { // DateTime dt = DateTime.Now; // if (i < ct.CTList.Count - 1) // { // ct.CTList[i].StartTime = dt; // } // if (i > 1) // { // ct.CTList[i - 1].EndTime = dt; // } // //CurrentPubSub.Publish(PubTag.CTUpdate.ToString(), ct, null, true); // break; // } // } // } // }); //} //public virtual ProcessResponse MonitorMethodInvoke(string methodCode, IOperationConfig config) //{ // return _processMethodDict[methodCode].Invoke(this, new object[] { config }) as ProcessResponse; // //return null; //} #endregion #region 图像处理 protected Dictionary> CameraBitmapDict = new Dictionary>(); //protected Dictionary CameraBitmapDict = new Dictionary(); protected HObject CollectHImage(CameraBase camera, IOperationConfig opConfig, string cameraId, string methodCode) { HObject hImage = null; if (StationConfig.IsImageOffline) { using (OfflineImageFrm oiF = new OfflineImageFrm()) { if (oiF.ShowDialog() == System.Windows.Forms.DialogResult.OK) { hImage = oiF.HImg; } else { //MessageBox.Show("未能获取离线图片!"); throw new ProcessException("未能获取离线图片!", null); } } } else { Stopwatch sw = new Stopwatch(); sw.Start(); var cameraConifg = opConfig as HalconRelatedCameraOprerationConfigBase; if (cameraConifg.DelayBefore > 0) { Thread.Sleep(cameraConifg.DelayBefore); } camera.UploadOperationConfig(opConfig); camera.Snapshot(opConfig, out hImage); //SaveTempImage(cameraName, camera.ImageFilePath); //SaveTempImage(camera, cameraId); if (cameraConifg.DelayAfter > 0) { Thread.Sleep(cameraConifg.DelayAfter); } sw.Stop(); LogAsync(DateTime.Now, $"{methodCode}采图耗时:{sw.ElapsedMilliseconds}ms", ""); TimeRecordCSV(DateTime.Now, methodCode + "采图", (int)sw.ElapsedMilliseconds); } return hImage; } //private async void SaveTempImage(string cameraName, string imgFilePath) //{ // await Task.Run(() => // { // //if (!string.IsNullOrWhiteSpace(cameraId)) // //{ // // //if (CameraBitmapDict.ContainsKey(cameraId) && CameraBitmapDict[cameraId] != null) // // //{ // // // CameraBitmapDict[cameraId].Dispose(); // // // CameraBitmapDict[cameraId] = null; // // //} // // CameraBitmapDict[cameraId] = imgFilePath; // //} // CameraBitmapDict[cameraName] = imgFilePath; // }); //} private async void SaveTempImage(CameraBase camera, string cameraId) { await Task.Run(() => { //if (!string.IsNullOrWhiteSpace(cameraId)) //{ // //if (CameraBitmapDict.ContainsKey(cameraId) && CameraBitmapDict[cameraId] != null) // //{ // // CameraBitmapDict[cameraId].Dispose(); // // CameraBitmapDict[cameraId] = null; // //} // CameraBitmapDict[cameraId] = imgFilePath; //} //camera.ImageGetHandle.WaitOne(); //CameraBitmapDict[cameraName] = camera.ShowImage; if (string.IsNullOrWhiteSpace(cameraId)) return; camera.ImageSaveDoneHandle.WaitOne(); if (!CameraBitmapDict.ContainsKey(cameraId)) { CameraBitmapDict.Add(cameraId, new Queue()); } CameraBitmapDict[cameraId].Enqueue(camera.ImageFilePath); }); } protected async void CameraUpdateImage(CameraBase camera, Bitmap image, string imageFilePath) { await Task.Run(() => { OnBitmapOutput?.Invoke(camera.InitialConfig.ID, image); }); } //protected async void SaveNGImage(MethodInfo methodInfo) //{ // await Task.Run(() => // { // try // { // if (string.IsNullOrWhiteSpace(Config.NGImageFolderPath)) // return; // var attr = methodInfo.GetCustomAttribute(); // if (attr == null) // return; // SaveCameraImage(attr.CameraName); // } // catch (Exception ex) // { // LogAsync(DateTime.Now, "保存NG图片异常", ex.GetExceptionMessage()); // } // }); //} //protected void SaveCameraImage(string cameraName) //{ // try // { // if (CameraBitmapDict.ContainsKey(cameraName)) // { // DirectoryInfo dir = new DirectoryInfo(Path.Combine(Config.NGImageFolderPath, DateTime.Now.ToString("yyyyMMdd"))); // if (!dir.Exists) // dir.Create(); // //string imageFilePath = Path.Combine(dir.FullName, DateTime.Now.ToString("HHmmssfff") + ".jpg"); // //if (CameraBitmapDict[cameraName] != null) // // CameraBitmapDict[cameraName].Save(imageFilePath, ImageFormat.Jpeg); // FileInfo file = new FileInfo(CameraBitmapDict[cameraName]); // if (file.Exists) // { // file.CopyTo(Path.Combine(dir.FullName, file.Name)); // } // } // } // catch (Exception ex) // { // LogAsync(DateTime.Now, "保存相机图片异常", ex.GetExceptionMessage()); // } //} //private async void SaveFitImage(CameraBase camera, HalconRelatedCameraOprerationConfigBase config, List list) //{ // await Task.Run(() => // { // if (!config.IsSaveFitImage) // return; // if (string.IsNullOrWhiteSpace(config.FitImagePath)) // return; // string imageFilePath = ""; // int repeatTime = 15; // do // { // if (CameraBitmapDict.ContainsKey(camera.InitialConfig.ID) && CameraBitmapDict[camera.InitialConfig.ID].Count > 0) // { // imageFilePath = CameraBitmapDict[camera.InitialConfig.ID].Dequeue(); // } // if (string.IsNullOrWhiteSpace(imageFilePath) || !File.Exists(imageFilePath)) // { // repeatTime--; // Thread.Sleep(50); // } // else // { // repeatTime = 0; // } // } while (repeatTime > 0); // if (string.IsNullOrWhiteSpace(imageFilePath)) // return; // var dir = new DirectoryInfo(Path.Combine(config.FitImagePath, DateTime.Now.ToString("yyyyMMdd"))); // if (!dir.Exists) // { // dir.Create(); // } // repeatTime = 10; // do // { // try // { // string fileName = Path.GetFileNameWithoutExtension(imageFilePath); // fileName = Path.Combine(dir.FullName, fileName + ".jpg"); // Bitmap image = (Bitmap)Image.FromFile(imageFilePath); // SaveFitImage(image, list, fileName); // repeatTime = 0; // } // catch (Exception ex) // { // repeatTime--; // LogAsync(DateTime.Now, "保存拟合图片异常1", ex.GetExceptionMessage()); // Thread.Sleep(500); // } // } while (repeatTime > 0); // }); //} //[HandleProcessCorruptedStateExceptions] //private async void SaveFitImage(Bitmap image, List eleList, string fileName) //{ // await Task.Run(() => // { // if (image == null) // return; // Bitmap map = new Bitmap(image.Width, image.Height); // using (Graphics g = Graphics.FromImage(map)) // { // int saveRetry = 15; // do // { // try // { // g.DrawImage(image, 0, 0); // eleList.ForEach(e => // { // int repeatTime = 5; // do // { // try // { // e.State = ElementState.Normal; // e.Draw(g); // repeatTime = 0; // } // catch (Exception) // { // repeatTime--; // } // } while (repeatTime > 0); // }); // map.Save(fileName, ImageFormat.Jpeg); // saveRetry = 0; // } // //catch (System.AccessViolationException ex) // //{ // // saveRetry--; // // LogAsync(DateTime.Now, "保存拟合图片异常2", ex.GetExceptionMessage()); // // Thread.Sleep(100); // //} // catch (Exception ex) // { // saveRetry--; // LogAsync(DateTime.Now, "保存拟合图片异常2", ex.GetExceptionMessage()); // Thread.Sleep(100); // } // } while (saveRetry > 0); // } // map.Dispose(); // image.Dispose(); // }); //} #endregion #region 报警和DownTime public ObservableCollection _warningRemains = new ObservableCollection(); bool warningRemainFlag = false; bool WarningRemainFlag { get { return warningRemainFlag; } set { if (value && !warningRemainFlag) { //CurrentPubSub.Publish(EnumHelper.PubTag.DownTimeNotice.ToString(), true, null, true); //SaveDownTime(DateTime.Now, true); } if (!value) { //CurrentPubSub.Publish(EnumHelper.PubTag.DownTimeNotice.ToString(), false, null, true); //SaveDownTime(DateTime.Now, false); } warningRemainFlag = value; } } private void _warningRemains_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { //lock (_idleTimeLock) //{ // if (_warningRemains.Count == 0) // { // if (!_idleFlag) // { // StartIdleRecordAsync(); // } // WarningRemainFlag = false; // } // else // { // if (_idleFlag) // { // //_idleFlag = false; // EndIdleRecordAsync(); // } // WarningRemainFlag = true; // } //} } private void SaveAlarm(string stationCode, WarningSet ws, int newValue) { } #endregion #region Log static object logObj = new object(); public Action OnLog; public virtual async void LogAsync(DateTime dt, string prefix, string msg) { await Task.Run(() => { OnLog?.BeginInvoke(dt, prefix, msg, null, null); if (!StationConfig.IsLogEnabled) return; DirectoryInfo dir = new DirectoryInfo(StationConfig.LogPath); if (!dir.Exists) { dir.Create(); } string logPath = Path.Combine(StationConfig.LogPath, DateTime.Today.ToString("yyyyMMdd") + ".txt"); lock (logObj) { using (StreamWriter writer = new StreamWriter(logPath, true, System.Text.Encoding.UTF8)) { //writer.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); writer.WriteLine(dt.ToString("yyyy-MM-dd HH:mm:ss.fff")); writer.WriteLine(prefix); writer.Write(msg); writer.WriteLine(); writer.WriteLine(); writer.Flush(); writer.Close(); } } }); } protected void OnDeviceLog(DateTime dt, IDevice device, string msg) { LogAsync(dt, device.InitialConfig.Name, msg); } static object csvLock = new object(); private async void TimeRecordCSV(DateTime dt, string desc, int ms) { await Task.Run(() => { lock (csvLock) { string filePath = Path.Combine(Config.LogPath, $"TimeRecords_{DateTime.Now.ToString("yyyyMMdd")}.csv"); bool isFileExisted = File.Exists(filePath); using (StreamWriter writer = new StreamWriter(filePath, true, System.Text.Encoding.UTF8)) { if (!isFileExisted) { writer.WriteLine("Time,Prefix,Consumed"); } writer.WriteLine($"{dt.ToString("HH:mm:ss.fff")},{desc},{ms}"); writer.Flush(); writer.Close(); } } }); } #endregion #region 临时数据保存和读取 protected static Dictionary _tempDataLock = new Dictionary(); protected string _tempFileDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TempData"); protected virtual T ReadTempDataFromHistory(T t, string propertyName) where T : class { if (!_tempDataLock.ContainsKey(propertyName)) { _tempDataLock[propertyName] = new object(); } if (t != null) { return t; } else { if (!Directory.Exists(_tempFileDirectory)) { Directory.CreateDirectory(_tempFileDirectory); } string filePath = Path.Combine(_tempFileDirectory, propertyName); if (!File.Exists(filePath)) { return null; } lock (_tempDataLock[propertyName]) { using (StreamReader reader = new StreamReader(filePath, System.Text.Encoding.UTF8)) { string content = reader.ReadToEnd(); var result = JsonConvert.DeserializeObject(content); return result; } } } } protected virtual void SaveTempData(T t, string propertyName, string defaultStr = "") { //await Task.Run(() => { if (!_tempDataLock.ContainsKey(propertyName)) { _tempDataLock[propertyName] = new object(); } lock (_tempDataLock[propertyName]) { try { if (!Directory.Exists(_tempFileDirectory)) { Directory.CreateDirectory(_tempFileDirectory); } string serialStr = JsonConvert.SerializeObject(t); if (!string.IsNullOrWhiteSpace(defaultStr)) { if (t == null) { serialStr = defaultStr; } } else { if (t == null) return; } string filePath = Path.Combine(_tempFileDirectory, propertyName); using (StreamWriter writer = new StreamWriter(filePath, false, System.Text.Encoding.UTF8)) { writer.Write(serialStr); writer.Flush(); writer.Close(); } } catch (Exception) { } } } //); } #endregion } public enum ReturnValue { OKVALUE = 1, NGVALUE = -1, EXCEPTIONVALUE = -2, LEVEL3EXCEPTION = -3, INCOMINGMATERIALEXCEPTION = -4, } }