You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

447 lines
16 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using HslCommunication.Profinet.GE;
using Microsoft.Extensions.Logging;
using SlnMesnac.Common;
using SlnMesnac.Config;
using SlnMesnac.Model.domain;
using SlnMesnac.Plc;
using SlnMesnac.Repository.service;
using SlnMesnac.Repository.service.Impl;
using SlnMesnac.TouchSocket;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography.Xml;
using System.ServiceModel.Channels;
using System.Threading;
using System.Threading.Tasks;
using TouchSocket.Core;
namespace SlnMesnac.Business
{
public class LogoBusiness
{
private TcpServer tcpServer = null;
private ILogger<LogoBusiness> logger;
private PlcAbsractFactory plc = null;
private LightHelper lightHelper = LightHelper.Instance;
private DebugConfig config = DebugConfig.Instance;
private IBaseMaterialService baseMaterialService;
private ILogoIdentifyService logoIdentifyService;
private ILogoConfigService logoConfigService;
public PaddleOCRSharp.PaddleOCREngine engine = null;
private GunHelper gunHelper = GunHelper.Instance;
private static LogoBusiness instance;
// 存放照片路径
public static string PicturePath = System.Environment.CurrentDirectory + "/picture/";
/// <summary>
/// 存储海康相机识别结果
/// </summary>
private static bool HikCameraResult = false;
#region 委托定义 刷新界面扫描信息
public delegate void RefreshBoxInfo(string boxCode, string boxTime, string model, bool isSuccess);
public static event RefreshBoxInfo? RefreshBoxInfoEvent;
public delegate void RefreshPicture(byte[] imageData);
public static event RefreshPicture? RefreshPictureEvent;
public delegate void RefreshMessage(string message, bool isWarning = false);
public static event RefreshMessage? RefreshMessageEvent;
public delegate void RefreshDataGrid();
public static event RefreshDataGrid? RefreshDataGridEvent;
#endregion
private LogoBusiness(ILogger<LogoBusiness> logger, ILogoConfigService logoConfigService, IBaseMaterialService baseMaterialService, ILogoIdentifyService logoIdentifyService, PlcPool _plcPool, TcpServer _tcpServer)
{
this.logger = logger;
tcpServer = _tcpServer;
TcpServer.RefreshMaterialCodeStrEvent += BarCodeHandler;
TcpServer.CameraResultEvent += ReceiveCameraResult;
this.baseMaterialService = baseMaterialService;
this.logoIdentifyService = logoIdentifyService;
this.logoConfigService = logoConfigService;
gunHelper.InstanceSerialPort();
plc = _plcPool.GetPlcByKey("plc");
lightHelper.InstanceSerialPort();
}
private void ReceiveCameraResult(string result)
{
logger.LogInformation($"相机返回结果:{result}");
if (result == "OK")
{
HikCameraResult = true;
}
else
{
HikCameraResult = false;
}
}
public static LogoBusiness GetInstance(ILogger<LogoBusiness> logger, ILogoConfigService logoConfigService, IBaseMaterialService baseMaterialService, ILogoIdentifyService ocrVerfiyService, PlcPool _plcPool, TcpServer _tcpServer)
{
if (instance == null)
{
instance = new LogoBusiness(logger, logoConfigService, baseMaterialService, ocrVerfiyService, _plcPool, _tcpServer);
}
return instance;
}
/// <summary>
/// 条码触发相机拍照校验
/// </summary>
/// <param name="materialCodeStr"></param>
/// <param name="ip"></param>
public async void BarCodeHandler(string materialCodeStr, string ip)
{
//打开灯光
lightHelper.SendData("OPEN");
#region 复位报警灯
// 声光电报警复位
gunHelper.SendData("OK");
#endregion
logger.LogInformation("相机流程开始:");
// 传入照片
byte[] ImageData = null;
// 压缩后的图片
byte[] compressedImageData = null;
try
{
#region 初始操作:复位海康上次结果,删除海康上次保存文件
HikCameraResult = false;
FileHelper.DeleteAllPictures(config.CameraFilePath);
#endregion
bool judge = FoamtJudge(materialCodeStr);
if (!judge)
{
WarningAndStop($"箱体码{materialCodeStr}格式不正确,停线报警!");
return;
}
logger.LogInformation($"扫描到箱体码:{materialCodeStr}");
//2.根据箱体码查询型号根据型号判断是否需要校验LOGO
ProductModel mode = logoConfigService.GetMaterialTypeByBarCode(materialCodeStr);
if(mode == null)
{
// 根据成品码查询不到型号
Warning($"根据成品码{materialCodeStr}查询不到型号,判断该型号是否样机或检查网络!");
return;
}
LogoConfig logoConfig = logoConfigService.GetByMaterialType(mode.MaterialCode);
// 海康校验结果
bool hikFlag = false;
if (logoConfig.IsChecked == 0)
{
// 不需要校验
hikFlag = true;
RefreshMessageEvent?.Invoke("LOGO+PCI无需识别下发放行");
logger.LogInformation($"箱体码:{materialCodeStr}Logo无需识别下发放行");
}
else
{
// 需要检验但是还没设置配方
if(logoConfig.CheckKind == 0)
{
// 不需要校验
hikFlag = false;
Warning($"箱体码:{materialCodeStr}LOGO+PCI需要识别但是未设置PCI模版");
}
else
{
#region 拍照处理流程
Thread.Sleep(int.Parse(config.SleepStr));
// 1.触发相机拍照
tcpServer.SendCommand(config.CameraIP, logoConfig.CheckKind.ToString());
// 需要校验
// 2.等待接收海康结果
hikFlag = await JudgeIsSuccessAsync();
if (hikFlag)
{
//校验成功放行
RefreshMessageEvent?.Invoke("LOGO+PCI识别成功下发放行");
logger.LogInformation($"箱体码:{materialCodeStr}Logo识别成功下发放行");
}
else
{
//校验失败禁止放行
WarningAndStop($"LOGO+PCI识别失败禁止放行");
}
#endregion
}
}
// 刷新界面、刷新图片,照片按照日期存储本地
RefreshBoxInfoEvent?.Invoke(materialCodeStr, DateTime.Now.ToString(), logoConfig.MaterialName, hikFlag);
//需要检测并且设置过配方的条码等待照片
if(logoConfig.IsChecked == 1 && logoConfig.CheckKind != 0)
{
await Task.Run(() =>
{
Thread.Sleep(int.Parse(config.PictureSleep));
ImageData = FileHelper.FindPhoto(config.CameraFilePath);
if (ImageData != null)
{
// 图片压缩
compressedImageData = FileHelper.CompressImageData(ImageData, 20);
FileHelper.SaveImage(compressedImageData, materialCodeStr + ".jpg", PicturePath);
RefreshPictureEvent?.Invoke(ImageData);
}
else
{
// WarningAndStop($"读取相机保存照片文件夹失败,请检查文件夹:{config.CameraFilePath}是否存在");
}
});
}
#region 更新数据库
LogoIdentify record = new LogoIdentify();
record.ProductCode = materialCodeStr;
record.MaterialType = logoConfig.MaterialType;
record.MaterialName = logoConfig.MaterialName;
record.isChecked = logoConfig.IsChecked;
record.Result = hikFlag ? 1 : 0;
record.RecordTime = DateTime.Now;
record.ProductLine = config.ProductLine;
if (compressedImageData != null)
{
record.Picture = compressedImageData;
}
logoIdentifyService.InsertRecord(record);
#endregion
RefreshDataGridEvent?.Invoke();
}
catch (Exception ex)
{
Warning($"BarCodeHandler异常,识别Logo失败,原因:{ex.Message},箱体条码:{materialCodeStr}");
}
finally
{
lightHelper.SendData("CLOSE");
}
}
/// <summary>
/// 判断Logo校验是否成功
/// </summary>
/// <returns></returns>
public async Task<bool> JudgeIsSuccessAsync()
{
bool result = false;
// 设置计时器
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
//至多等待2.5s海康的校验结果
result = await Task.Run(() =>
{
while (true)
{
if (HikCameraResult == true)
{
return true;
}
// 检查是否超过两秒
if (stopwatch.ElapsedMilliseconds > 3000)
{
return false;
}
Thread.Sleep(100);
}
});
return result;
}
/// <summary>
/// 箱体码格式校验20位成品码B开头的21位箱体码为MES码
/// </summary>
/// <param name="code"></param>
/// <returns></returns>
private bool FoamtJudge(string code)
{
if (!string.IsNullOrEmpty(code))
{
if (code.Length == 20 || code.Length == 21&& code.Substring(0, 1) == "B")
{
return true;
}
}
return false;
}
/// <summary>
/// 截取两个逗号之间的字符串
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
static string GetSubstringBetweenCommas(string input)
{
if (input == null) return null;
// 找到第一个逗号的位置
int firstCommaIndex = input.IndexOf(',');
if (firstCommaIndex != -1)
{
// 找到第二个逗号的位置
int secondCommaIndex = input.IndexOf(',', firstCommaIndex + 1);
if (secondCommaIndex != -1)
{
// 使用Substring截取第一个逗号和第二个逗号之间的字符
return input.Substring(firstCommaIndex + 1, secondCommaIndex - firstCommaIndex - 1);
}
else
{
return null;
}
}
else
{
return null;
}
}
#region PLC交互部分
//M100停止点位
public void Pass()
{
try
{
if (plc != null && plc.IsConnected)
{
plc.writeInt16ByAddress("DB22.DBW2", 8);
Task.Run(() =>
{
// 设置计时器
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
while (true)
{
if (plc.readInt16ByAddress("DB22.DBW2") == 0)
{
logger.LogInformation("PLC复位成功,启动线体");
RefreshMessageEvent?.Invoke("PLC复位成功,启动线体");
break;
}
// 检查是否超过两秒
if (stopwatch.ElapsedMilliseconds > 3000)
{
logger.LogError("PLC复位超时");
RefreshMessageEvent?.Invoke("PLC复位超时", true);
break;
}
Thread.Sleep(100);
}
});
}
else
{
logger.LogError("PLC未连接请检查连接");
RefreshMessageEvent?.Invoke("PLC未连接请检查连接", true);
}
// 声光电报警复位
gunHelper.SendData("OK");
}
catch (Exception ex)
{
logger.LogError($"下发PLC复位方法Pass()异常:{ex.Message}");
}
}
public void Stop()
{
try
{
if (plc != null && plc.IsConnected)
{
plc.writeInt16ByAddress("DB22.DBW2", 9);
Task.Run(() =>
{
// 设置计时器
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
while (true)
{
if (plc.readInt16ByAddress("DB22.DBW2") == 1)
{
logger.LogInformation("PLC复位成功,启动线体");
RefreshMessageEvent?.Invoke("PLC复位成功,启动线体");
break;
}
// 检查是否超过两秒
if (stopwatch.ElapsedMilliseconds > 3000)
{
logger.LogError("PLC复位超时");
RefreshMessageEvent?.Invoke("PLC复位超时", true);
break;
}
Thread.Sleep(100);
}
});
}
// 声光电报警
gunHelper.SendData("NG");
}
catch (Exception ex)
{
logger.LogError($"下发PLC报警方法Stop()异常:{ex.Message}");
}
}
#endregion
#region 记录日志刷新界面及下发PLC报警
public void WarningAndStop(string message)
{
logger.LogError(message);
RefreshMessageEvent?.Invoke(message, true);
Stop();
}
public void Warning(string message)
{
logger.LogError(message);
RefreshMessageEvent?.Invoke(message, true);
}
#endregion
}
}