using CCDCount.DLL.Tools; using CCDCount.MODEL.CameraClass; using CCDCount.MODEL.ConfigModel; using CCDCount.MODEL.ShuLiClass; using LogClass; using MvCameraControl; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Remoting.Messaging; using System.Text; using System.Threading; namespace CCDCount.DLL { public class MainThreadClass { #region 变量与实例 Thread SwitchIdentifyImageThread = null; private bool IsSwitch = false; public ShuLiClass shuLiClass = null; CameraClass cameraClass = new CameraClass(); public ShuLiConfigClass shuLiConfig = null; public CameraConfig cameraConfig = null; public bool CameraConfigIsChange = false; public int ThisCamerNo = -1; public bool CameraStatic { get { return _CameraStatic; } } private bool _CameraStatic = false; // 返回交换线程状态 public bool CameraRunStatic { get { return IsSwitch; } } public bool IsOpenLoadThread { get { return _IsOpenLoadThread; }} private bool _IsOpenLoadThread = false; public int HistoryActiveNum { get { return shuLiClass.GetHistoryActiveNum(); } } public int OkHistoryNum { get { return shuLiClass.GetOkHistoryNum(); } } public int NgHistoryNum { get { return shuLiClass.GetNgHistoryNum(); } } // 数粒信息发送线程 Thread SendBottLogicMessageThread = null; bool IsSend = false; // Modbus客户端实例 ModbusTcpClient modbusTcpClient = null; // 颗粒结果待发送队列 ConcurrentQueue SendQueue = new ConcurrentQueue(); /// /// 数粒状态计时器 /// Stopwatch stopwatch = Stopwatch.StartNew(); /// /// 数粒状态 /// private bool _ShuLiState = true; public bool ShuLiState { get { return _ShuLiState; } } private bool IsDebug = false; private bool IsConnectModbus = false; #endregion #region 公共方法 /// /// 设置ModbusTcpClient /// /// public void SetModbusClient(ModbusTcpClient modbusTcpClient) { this.modbusTcpClient = modbusTcpClient; if (!this.modbusTcpClient.IsTcpClientConnected()) { FaultLog.RecordErrorMessage("ModbusTcpClient Connect Failed!"); } else { FaultLog.RecordLogMessage("ModbusTcpClient Connect Success!", 6); IsConnectModbus = true; } } /// /// 初始化构造方法 /// /// /// public MainThreadClass(ShuLiConfigClass configClass,CameraConfig CameraConfig) { shuLiConfig = configClass; cameraConfig = CameraConfig; // 数粒配置文件地址 if (configClass!=null) { // 创建数粒对象(配置文件) shuLiClass = new ShuLiClass(shuLiConfig); } else { // 创建数粒对象(默认) shuLiClass = new ShuLiClass(); } _IsOpenLoadThread = cameraConfig.IsOpenLoad; ThisCamerNo = cameraConfig.CamerNo; } public bool LoadCamera() { bool result = false; // 相机列表 try { // 获取相机列表 cameraClass.GetCameraList(out List list); if (list.Count == 0) { FaultLog.RecordErrorMessage(string.Format("{0}:没有相机", "MainThreadClass-StartMianThread")); // 如果没有相机,则退出 return result; } // 加载相机 // cameraClass.LoadCamereDevice(list.First().DeviceSN); if (!cameraClass.LoadCamereDevice(cameraConfig)) { FaultLog.RecordErrorMessage(string.Format("{0}:相机加载失败", "MainThreadClass-StartMianThread")); return result; } CameraConfigIsChange = false; } catch { } return result; } public void ReLoadCameraConfig() { if(CameraConfigIsChange) { CameraConfig OldcameraConfig = cameraClass.GetConfigValue(); if(OldcameraConfig.CameraSNNum != cameraConfig.CameraSNNum) { cameraClass.LoadCamereDevice(cameraConfig); } else { cameraClass.ReLoadCameraConfig(cameraConfig); } } } /// /// 开始主线程 /// public bool StartMianThread() { bool result = false; try { // 取图线程开启 cameraClass.StartCamera(); _CameraStatic = true; StartSendBottLogicMessageThread(); // 数据交换线程开启 StartSwitchThread(); // 为数粒算法的识别成功一粒回调函数添加方法 shuLiClass.WorkCompleted += Worker_OneGrainCompleted; // 开启识别线程 shuLiClass.StartIdentifyFuntion(cameraClass.GetCamereImageSize().Width); result = true; } catch { } return result; } /// /// 停止主线程 /// public bool StopMianThread() { bool result = false; try { _CameraStatic = false; shuLiClass.WorkCompleted -= Worker_OneGrainCompleted; // 相机取图关闭 cameraClass.StopCamera(); // 数据交换线程关闭 StopSwitchThread(); // 数粒识别线程关闭 shuLiClass.StopIdentifyFuntion(); StopSendBottLogicMessageThread(); result = true; } catch { } return result; } /// /// 释放相机资源 /// public void DisposeCamera() { cameraClass.StopCamera(); cameraClass.DisPoseCamera(); } /// /// 重加载相机 /// /// /// public bool ReLoadCamera(string CameraSN) { bool result = false; result = cameraClass.ReLoadCameraDevice(CameraSN); if (result) { cameraConfig = cameraClass.GetConfigValue(); } return result; } /// /// 获取显示用的图片数据 /// /// /// public void GetShowImage(int ImageHeight,out Bitmap ImageData) { List RowsShowList = new List(); ActiveObjectClass NewActive = shuLiClass.GetLastActive(); if (NewActive == null) { LOG.log(string.Format("{0}:没有获取到数粒数据", "MainThreadClass-GetShowImage")); ImageData = null; return; } List Data = shuLiClass.GetHistoryActive().Where(o => o.LastSeenLine > NewActive.LastSeenLine - ImageHeight).ToList(); Data.ForEach(o => o.RowsData.ForEach(p => RowsShowList.Add(p))); Bitmap BitmapImage = new Bitmap(NewActive.ImageWidth, ImageHeight); using (Graphics g = Graphics.FromImage(BitmapImage)) { g.Clear(Color.White); using (Pen RedPan = new Pen(Color.Red, 5)) { for (int i = 0; i < shuLiClass.ChannelsRoi.Count - 1; i++) { g.DrawLine(RedPan, new Point(shuLiClass.ChannelsRoi[i], 0), new Point(shuLiClass.ChannelsRoi[i], BitmapImage.Height)); } } using (Pen BlackPen = new Pen(Color.Black, 1)) { List ShowList = RowsShowList.Where(o => o.RowsCol > NewActive.LastSeenLine - BitmapImage.Height).ToList(); RowsShowList.Where(o => o.RowsCol < NewActive.LastSeenLine - BitmapImage.Height).ToList().ForEach(o => RowsShowList.Remove(o)); RowsShowList.Clear(); ShowList.ForEach(o => g.DrawLine(BlackPen, new Point(o.StartCol, (int)(NewActive.LastSeenLine - o.RowsCol)), new Point(o.EndCol, (int)(NewActive.LastSeenLine - o.RowsCol)))); ShowList.Clear(); } } ImageData = BitmapImage.Clone() as Bitmap; BitmapImage.Dispose(); //GC.Collect(); } /// /// 获取无数据的图片 /// /// /// /// public void GetNullShowImage(int ImageWidth, int ImageHeight, out Bitmap ImageData) { Bitmap BitmapImage = new Bitmap(ImageWidth, ImageHeight); using (Graphics g = Graphics.FromImage(BitmapImage)) { g.Clear(Color.White); using (Pen RedPan = new Pen(Color.Red, 8)) { for (int i = 0; i < shuLiClass.ChannelsRoi.Count - 1; i++) { g.DrawLine(RedPan, new Point(shuLiClass.ChannelsRoi[i], 0), new Point(shuLiClass.ChannelsRoi[i], BitmapImage.Height)); } } } ImageData = BitmapImage.Clone() as Bitmap; BitmapImage.Dispose(); } /// /// 获取此刻的Config数据 /// /// public void GetAllConfigValue(out CameraConfig Camconfig,out ShuLiConfigClass shuLiConfig) { //判断是否加载了相机 if(cameraClass.IsLoadCamera()) { //获取已经加载的相机的配置 cameraConfig = cameraClass.GetConfigValue(); Camconfig = cameraConfig; } else { cameraConfig = new CameraConfig(); Camconfig = cameraConfig; } //读取视觉配置 shuLiConfig = shuLiClass.GetConfigValue(); this.shuLiConfig = shuLiConfig; } /// /// 获取相机此刻的Config数据 /// /// public CameraConfig GetCameraConfig() { CameraConfig result = null; //判断是否加载了相机 if (cameraClass.IsLoadCamera()) { //获取已经加载的相机的配置 result = cameraClass.GetConfigValue(); cameraConfig = result; } return result; } /// /// 保存所有Config /// public void SaveAllConfig() { shuLiClass.SaveConfig(); } /// /// 获取相机连接状态 /// /// public bool GetCameraConnectStatic() { bool result = false; if(cameraClass != null) result = cameraClass.IsConnectCamera(); return result; } /// /// 清除历史数据 /// /// public bool ClearHistoryActive() { bool result = false; if(shuLiClass != null) result = shuLiClass.ClearHistoryActive(); return result; } /// /// 获取过去一秒内颗粒数量 /// /// public int GetOneSecondActiveNum() { int result = 0; if(shuLiClass != null) result = shuLiClass.GetHistoryActive().Where(o=>o.EndCheckTime>DateTime.Now-TimeSpan.FromSeconds(1)).Count(); return result; } #endregion #region 私有方法 //bool IsFill = false; //bool IsXuanZhuanCloseFaMen = false; /// /// 每数完一粒识别线程执行的事件 /// /// /// private void Worker_OneGrainCompleted(object sender, ActiveObjectEventArgsClass e) { LOG.log("有活跃物体转换为了历史物体,回调事件被触发!", 6); LOG.log(string.Format("图像处理实例中的待识别图像缓存队列长度{0}", shuLiClass.ImageNum), 6); if (e.Actives.Where(o => o.StateCode == 7).Count() > 0) { stopwatch.Restart(); _ShuLiState = false; } else if (stopwatch.ElapsedMilliseconds > 1000) { stopwatch.Stop(); _ShuLiState = true; } //往数组中计数 ushort result = new ushort(); // 事件处理逻辑 foreach (ActiveObjectClass oneActive in e.Actives) { Console.WriteLine(string.Format("输出当前颗粒信息,开始行:{0},结束行:{1},开始时间:{2}结束时间:{3},颗粒状态:{4},通道数:{5}", oneActive.StartLine, oneActive.LastSeenLine, oneActive.StartCheckTime.ToString("O"), oneActive.EndCheckTime.ToString("O"), oneActive.StateCode, oneActive.ChannelNO)); LOG.log(string.Format("输出当前颗粒信息,开始行:{0},结束行:{1},开始时间:{2}结束时间:{3},颗粒状态:{4},通道数:{5}", oneActive.StartLine, oneActive.LastSeenLine, oneActive.StartCheckTime.ToString("O"), oneActive.EndCheckTime.ToString("O"), oneActive.StateCode, oneActive.ChannelNO), 6); if (oneActive.StateCode == 0 && oneActive.ChannelNO != -1) { //单通道合格计数 result |= (ushort)(1 << (oneActive.ChannelNO)); } else { //单通道不合格计数 result |= (ushort)(1 << 8); } } LOG.log("当前待发送队列数量:" + SendQueue.Count, 6); if(IsSend) { SendQueue.Enqueue(result); } } #endregion #region 线程方法 /// /// 开启交换线程 /// private void StartSwitchThread() { IsSwitch = true; SwitchIdentifyImageThread = new Thread(SwitchIdentifyImageProcess); SwitchIdentifyImageThread.Start(); } /// /// 关闭交换线程 /// private void StopSwitchThread() { try { // 标志位设为false IsSwitch = false; if (SwitchIdentifyImageThread != null && SwitchIdentifyImageThread.IsAlive) SwitchIdentifyImageThread.Join(); } catch (Exception ex) { FaultLog.RecordErrorMessage("Start thread failed!, " + ex.Message); throw; } } /// /// 交换线程 /// private void SwitchIdentifyImageProcess() { IFrameOut IFramedata = null; Stopwatch stopwatch = Stopwatch.StartNew(); stopwatch.Start(); while (IsSwitch) { if (stopwatch.ElapsedMilliseconds > 1000) { //Console.WriteLine("交换线程-图像处理实例中的待识别图像缓存队列长度{0}", shuLiClass.ImageNum); GC.Collect(); stopwatch.Restart(); } //Thread.Sleep(5); bool result = cameraClass.GetOnceImage(out IFramedata); if (result) { //Debug模式,不进行图像处理 if (IsDebug) { continue; } if (IFramedata == null) continue; shuLiClass.SetOnceIdentifyImageData(IFramedata.Image); } else continue; IFramedata.Dispose(); } stopwatch.Stop(); } /// /// 启动发送消息线程 /// private void StartSendBottLogicMessageThread() { try { if(!IsConnectModbus) return; //zmcauxClass.OpenZmcauxCard(); timeBeginPeriod(1); // 设置为1ms精度 IsSend = true; SendBottLogicMessageThread = new Thread(SendBottLogicMessageProcess); SendBottLogicMessageThread.Start(); } catch (Exception ex) { FaultLog.RecordErrorMessage("Start thread failed!, " + ex.Message); throw; } } /// /// 停止发送消息线程 /// private void StopSendBottLogicMessageThread() { try { // 标志位设为false IsSend = false; if (SendBottLogicMessageThread != null && SendBottLogicMessageThread.IsAlive) SendBottLogicMessageThread.Join(); if (modbusTcpClient != null) modbusTcpClient.Disconnect(); } catch (Exception ex) { FaultLog.RecordErrorMessage("Start thread failed!, " + ex.Message); throw; } } /// /// 信息发送线程 /// private void SendBottLogicMessageProcess() { //获取数据 ushort sendMessage = 0; bool AllowTransfer = false; bool TransferDone = false; Stopwatch sw = Stopwatch.StartNew(); while (IsSend) { //LOG.log("进入线程", 6); sw.Restart(); sendMessage = new ushort(); //读取装瓶状态 AllowTransfer = false; TransferDone = false; bool[] ReadResult = modbusTcpClient.ReadCoilsRegister(slaveId: 1, startAddress: 11, numRegisters: 2); if (ReadResult == null) { continue; } AllowTransfer = ReadResult[1]; TransferDone = ReadResult[0]; //LOG.log(string.Format("读取值:AllowTransfer[0]:{0},TransferDone[1]:{1}", AllowTransfer, TransferDone), 6); //当允许写入且处于未写入的状态时 if (AllowTransfer && !TransferDone) { if (SendQueue.Count() > 0) { if (!SendQueue.TryDequeue(out sendMessage)) { FaultLog.RecordErrorMessage("MainThreadClass-SendBottLogicMessageProcess-SendQueue.TryDequeue failed!"); } } if (sendMessage != 0) { //写入数据 modbusTcpClient.WriteSingleRegister(slaveId: 1, registerAddress: 100, value: sendMessage); modbusTcpClient.WriteCoilsRegister(slaveId: 1, CoilsAddress: 11, values: true); } sw.Stop(); FaultLog.RecordLogMessage(string.Format("sendMessage[1]:{0},此次写值耗时:{1}", sendMessage, sw.Elapsed),1); } Thread.Sleep(1); } } #endregion #region 外部函数 [DllImport("winmm.dll")] static extern uint timeBeginPeriod(uint period); #endregion } }