|
|
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
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|