Files
6098/Cowain.Bake.Main/Station/LoadingStation.cs

554 lines
26 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Cowain.Bake.BLL;
using Cowain.Bake.Common;
using Cowain.Bake.Common.Core;
using Cowain.Bake.Common.Enums;
using Cowain.Bake.Common.Interface;
using Cowain.Bake.Communication.Interface;
using Cowain.Bake.Communication.MOM;
using Cowain.Bake.Main.ViewModels;
using Cowain.Bake.Main.Views;
using Cowain.Bake.Model;
using Cowain.Bake.Model.Models;
using Cowain.Bake.UI.CsvMap;
using HslCommunication;
using Newtonsoft.Json;
using Prism.Ioc;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows;
using Unity;
using static Cowain.Bake.Common.Models.MESModel;
using JSON = Newtonsoft.Json.JsonConvert;
namespace Cowain.Bake.Main.Station
{
public class LoadingStation : IServerManager
{
private int _batteryCodeLen = 0;
public string Name { get; set; }
IPLCDevice PLC { get; set; }
readonly List<IScanCodeBase> _deviceScann = new List<IScanCodeBase>();
public IUnityContainer _unityContainer { get; set; }
public LoadingStation(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
TDeviceConfig config = _unityContainer.Resolve<DeviceConfigService>().GetConfig(EDeviceType.PLC, EDeviceName.Loading)[0];
Name = config.Name;
SetBatteryCodeLen();
Start();
}
public void SetBatteryCodeLen()
{
_batteryCodeLen = int.Parse(_unityContainer.Resolve<Cowain.Bake.BLL.SysSetupService>().GetValueByParaID(ESysSetup.BatteryCodeLen.ToString()));
}
bool IsConnectPLC()
{
if (null == PLC || !PLC.IsConnect)
{
LogHelper.Instance.Error($"PalletVirtualId:{PLC.Name},PLC为空!");
return false;
}
return true;
}
public void Start()
{
var configScann = _unityContainer.Resolve<DeviceConfigService>().GetConfig(EDeviceType.SCANNER).OrderBy(x => x.Id).Take((int)EScanCode.PalletScan2).ToList();
foreach (var item in configScann)
{
IScanCodeBase device = _unityContainer.Resolve<IScanCodeBase>(item.Name);
_deviceScann.Add(device);
}
PLC = _unityContainer.Resolve<IPLCDevice>(Name); //上料PLC
}
public void Stop()
{
}
/*
* 编译器自动在方法入口/出口加 lock(this),简单但锁粒度粗;
* 高频调用或重入场景容易成瓶颈,只适合做原型或低并发工具类。
*/
//托盘满盘信号
[MethodImpl(MethodImplOptions.Synchronized)]
public void ExecuteFullPallet(int curValue, string param, Variable node)
{
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
LogHelper.Instance.Warn($"LoadingStation:ExecuteFullPallet:开始,线程ID:{System.Threading.Thread.CurrentThread.ManagedThreadId}");
int result ;
int batteryQty;
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("开始:" + node.VarDesc);
int palletId = _unityContainer.Resolve<CavityInfoService>().GetPalletId((int)EStationType.Loading, int.Parse(param));
TPalletInfo palletInfo = _unityContainer.Resolve<BLL.PalletInfoService>().GetPalletInfo(palletId);
if (null == palletInfo) //如果当前夹具状态为"满夹具可取",就退出,上位机重启会重复触发!
{
LogHelper.Instance.Warn($"托盘满信号,上料平台无夹具,异常");
return;
}
if ((int)EPalletStatus.Advisable == palletInfo.PalletStatus) //如果当前夹具状态为"满夹具可取",就退出,上位机重启会重复触发!
{
//LogHelper.Instance.Warn($"托盘满信号,当前托盘为满夹具夹,异常");
//return;
}
try
{
int debugMode = int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.DebugMode.ToString())); //0
if (!IsConnectPLC()) return;
var resultBatterys = PLC.Read<int[]>((string)d.ReadVirtualIds); //可以改成直接读PLC
var resultPalletVirtualId = PLC.Read<int>((string)d.ReadPalletVirtualId); //这是直接读PLC
var lastFlag = PLC.Read<Int16>((string)d.ReadLastFlag).Content; //这是直接读PLC
if (!resultBatterys.IsSuccess || !resultPalletVirtualId.IsSuccess)
{
LogHelper.Instance.Error($"PalletVirtualId:{resultPalletVirtualId.Content},没有读取电芯信息或托盘信息!");
return;
}
if (0 == resultPalletVirtualId.Content ||
1 == resultPalletVirtualId.Content)
{
LogHelper.Instance.Error($"托盘满盘信号异常, 托盘虚拟码为【{resultPalletVirtualId.Content}】!", true);
return;
}
//批量更新电芯表
batteryQty = _unityContainer.Resolve<BatteryInfoService>().InsertBatch(resultBatterys.Content, resultPalletVirtualId.Content); //add by lsm 20250219 要300耗秒以上
SavePalletInfo(resultPalletVirtualId.Content);
if (0 == batteryQty)
{
//HandyControl.Controls.MessageBox.Error("触发满盘时没有电芯数据!"); //启动上位机时,会触发这个东西。
LogHelper.Instance.Error($"启动上位机时,上料:{resultPalletVirtualId.Content},电芯地址里没有电芯数据!");
return;
}
if (Global.PALLET_TOTAL_BATTERYS != batteryQty)
{
LogHelper.Instance.Error($"PalletVirtualId:{resultPalletVirtualId.Content},{batteryQty},上料电芯是{Global.PALLET_TOTAL_BATTERYS}!", false);
}
result = _unityContainer.Resolve<PalletInfoService>().LoadingUpdatePalletStatus(resultPalletVirtualId.Content, (int)EPalletStatus.Advisable, batteryQty, lastFlag == 1);
if (0 == result)
{
LogHelper.Instance.Error($"PalletVirtualId:{resultPalletVirtualId.Content},修改托盘状态失败!");
}
//writeResult = PLC.Write<bool>((string)d.WriteResult, true);//回复收到托盘1满盘信号
//if (!writeResult.IsSuccess)
//{
// LogHelper.Instance.GetCurrentClassWarn($"{(string)d.WriteResult}:{writeResult.Message}");
//}
}
catch(Exception ex)
{
LogHelper.Instance.GetCurrentClassWarn($",{ex.Message}:{ex.StackTrace}");
}
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束:" + node.VarDesc);
}
//假电芯扫码 验证数据库OK
public void ExecuteScanDummy(int curValue, string param, Variable node)
{
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
if (!IsConnectPLC()) return;
int virtualId;
OperateResult writeResult = null;
EScanCode scanName = EScanCode.DummyScan; //(EScanCode)(int.Parse(param));
IScanCodeBase scanDevice = _deviceScann.Find(x => x.Name == scanName.ToString());
HslCommunication.OperateResult<string> scanResult = new HslCommunication.OperateResult<string>()
{
IsSuccess = false,
};
scanResult.IsSuccess = true;
scanResult.Content = System.Guid.NewGuid().ToString("N").Substring(0, 12);
if (scanResult.IsSuccess)
{
virtualId = _unityContainer.Resolve<BatteryInfoService>().InsertBattery(scanResult.Content, (int)EBatteryStatus.ScanOver, (int)EDummyState.Have, "");
writeResult = PLC.Write<int>((string)d.WriteVirtualId, virtualId); //假电芯虚拟码
if (!writeResult.IsSuccess)
{
LogHelper.Instance.GetCurrentClassWarn($"写假电芯虚拟码失败,{(string)d.WriteVirtualId}:{writeResult.Message}");
}
}
writeResult = PLC.Write<Int16>((string)d.WriteResult, scanResult.IsSuccess ? (Int16)EResult.OK : (Int16)EResult.NG); //假电芯结果
if (!writeResult.IsSuccess)
{
LogHelper.Instance.GetCurrentClassWarn($"{(string)d.WriteResult}:{writeResult.Message}");
}
writeResult = PLC.Write<Int16>((string)d.WriteAsk, 1); //回复
if (!writeResult.IsSuccess)
{
LogHelper.Instance.Warn($"ExecuteScanDummy-{(string)d.WriteAsk}:{writeResult.Message}");
}
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束:" + node.VarDesc);
}
//托盘扫码
public void ExecuteScanPallet(int curValue, string param, Variable node)
{
string msg = "";
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
_unityContainer.Resolve<LogService>().AddLog("LoadingStation:ExecuteScanPallet:托盘扫码开始", E_LogType.Info.ToString());
string palletCode = "";
int VID = 0;
OperateResult writeResult = null;
HslCommunication.OperateResult<string> scanResult = new HslCommunication.OperateResult<string>()
{
IsSuccess = false,
};
EScanCode scanName = (EScanCode)((int)EScanCode.PalletScan1 + int.Parse(param) - 1); //param这个就是扫码枪的编号
try
{
IScanCodeBase scanDevice = _deviceScann.Find(x => x.Name == scanName.ToString());
while (!scanDevice.IsConnect)
{
msg = $"获取{scanName.GetDescription()}连接异常!";
LogHelper.Instance.Error(msg);
_unityContainer.Resolve<MainWindowViewModel>().AddPromptContent(msg);
scanDevice.Connect();
}
scanResult = scanDevice.ReadCode();
////------------------------ //add by lsm
//scanResult.IsSuccess = true;
//scanResult.Content = System.Guid.NewGuid().ToString("N").Substring(0, 6); // add by lsm测试用
//------------------------
palletCode = scanResult.Content;
//夹具扫码异常处理
while (string.IsNullOrEmpty(palletCode))
{
Application.Current.Dispatcher.Invoke((Action)(() =>
{
PalletIdInputWindow f = new PalletIdInputWindow("托盘码输入框", "请输入托盘码", "确定输入托盘码?")
{
WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen,
};
f.ShowDialog();
palletCode = f.PalletId;
}));
}
//绑定托盘
VID = _unityContainer.Resolve<PalletInfoService>().BindingPallet(palletCode, (int)EPalletStatus.Loading, (int)EStationType.Loading, int.Parse(param)); //防呆
if (0 == VID)
{
LogHelper.Instance.Debug($"===ProcBindPallet卡死,{palletCode},{int.Parse(param)},VID:{VID}");
return; //此时会卡死上位机
}
LogHelper.Instance.Debug($"===ProcBindPallet,{palletCode},{(int)EPalletStatus.Loading},{int.Parse(param)},VID:{VID}");
if (CurrentWeaterPallet())
{
Int16 DummyLocationX = Int16.Parse(_unityContainer.Resolve<Cowain.Bake.BLL.SysSetupService>().GetValueByParaID(ESysSetup.DummyLocationX.ToString()));
writeResult = PLC.Write<Int16>((string)d.WriteDummyX, DummyLocationX); //假电芯行号
if (!writeResult.IsSuccess)
{
LogHelper.Instance.GetCurrentClassWarn($"假电芯行号:{(string)d.WriteDummyX}:{writeResult.Message},失败");
}
Int16 DummyLocationY = Int16.Parse(_unityContainer.Resolve<Cowain.Bake.BLL.SysSetupService>().GetValueByParaID(ESysSetup.DummyLocationY.ToString()));
writeResult = PLC.Write<Int16>((string)d.WriteDummyY, DummyLocationY); //假电芯列号
if (!writeResult.IsSuccess)
{
LogHelper.Instance.GetCurrentClassWarn($"假电芯列号:{(string)d.WriteDummyY}:{writeResult.Message},失败");
}
}
writeResult = PLC.Write<int>((string)d.WritePattleVirtualId, VID); //托盘1托盘虚拟码
if (!writeResult.IsSuccess)
{
LogHelper.Instance.GetCurrentClassWarn($"{(string)d.WritePattleVirtualId}:{writeResult.Message}");
}
writeResult = PLC.Write<Int16>((string)d.WriteResult, 1); //托盘1扫码结果
if (!writeResult.IsSuccess)
{
LogHelper.Instance.GetCurrentClassWarn($"{(string)d.WriteResult}:{writeResult.Message}");
}
writeResult = PLC.Write<Int16>((string)d.WriteAsk, 1); //回复
if (!writeResult.IsSuccess)
{
LogHelper.Instance.Warn($"ExecuteScanPallet-{(string)d.WriteAsk}:{writeResult.Message}");
}
}
catch(Exception ex)
{
LogHelper.Instance.GetCurrentClassWarn($"ExecuteScanPallet:{ex},{scanResult.Content},{scanResult.Message}");
}
_unityContainer.Resolve<MainWindowViewModel>().DeletePromptContent();
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束:" + node.VarDesc);
}
/// <summary>
/// 根据工单判断是否放水含量
/// </summary>
/// <returns></returns>
public bool CurrentWeaterPallet()
{
bool IsWaertPallet = false;
var productionInformation = _unityContainer.Resolve<ProductionInformationService>().GetCurrentProductInfo();
if (productionInformation.DummyRule == (int)DummyPlaceRule.DEFAULT_EVERY_STOVE_LAYER_PLACED_ONE)
{
if (SettingProvider.Instance.WaterPallet % 2 == 1)
{
IsWaertPallet = true;
}
SettingProvider.Instance.WaterPallet++;
}
else if (productionInformation.DummyRule == (int)DummyPlaceRule.EVERY_PALLET_PLACED_ONE)
{
IsWaertPallet = true;
}
return IsWaertPallet;
}
//电芯扫码
public async Task ExecutScanBattery(int curValue, string param, Variable node)
{
dynamic d = JsonConvert.DeserializeObject<dynamic>(node.Json);
if (!IsConnectPLC()) return;
int scannIndex = 0;
OperateResult writeResult = null;
int mesIndex = 0;
int index = 1; //1..4,第0个索引不用
string[] codeBatterys = new string[Global.ONCE_SCAN_BATTERY + 1];
Int16[] result = new Int16[Global.ONCE_SCAN_BATTERY + 1];
Int16[] ask = new Int16[Global.ONCE_SCAN_BATTERY + 1];
int[] batteryVirtualIds = new int[Global.ONCE_SCAN_BATTERY + 1];
result = Enumerable.Repeat<Int16>(3, Global.ONCE_SCAN_BATTERY + 1).ToArray();
Array.Clear(ask, 0, Global.ONCE_SCAN_BATTERY + 1); //3:无电芯
Array.Clear(batteryVirtualIds, 0, Global.ONCE_SCAN_BATTERY + 1);
List<OperateResult<string>> scannList = new List<OperateResult<string>>();
List<MESReturnCmdModel> mesResultList = new List<MESReturnCmdModel>();
List<Task<OperateResult<string>>> scannTasks = new List<Task<OperateResult<string>>>();
List<Task<MESReturnCmdModel>> mesResultTasks = new List<Task<MESReturnCmdModel>>();
int mesEnable = int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.MOMEnable.ToString()));
int debugMode = int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.DebugMode.ToString())); //0为测试模式1为正式模式
Array.Clear(codeBatterys, 0, Global.ONCE_SCAN_BATTERY + 1); //几个条码一起保存
HslCommunication.OperateResult<string> scanResult = new HslCommunication.OperateResult<string>()
{
IsSuccess = false,
};
if (mesEnable == (int)EMOMEnable.Enable
&& (int)EProductionMode.Debug == debugMode)
{
LogHelper.Instance.Error($"MOM【在线模式】设备模式却是【调试模式】模式不匹配,请修改!", true);
return;
}
try
{
index = 1;
for (EScanCode s = EScanCode.LoadingBatteryScan1; s <= EScanCode.LoadingBatteryScan8; s++, index++)
{
if (((curValue >> index) & 1) != 1) //第index位不是1,就是不需要扫码
{
continue;
}
ask[(int)s] = 1;
IScanCodeBase scanDevice = _deviceScann.Find(x => x.Name == s.ToString());
if (!scanDevice.IsConnect)
{
string msg = $"获取{s.GetDescription()}失败,请检测线路!";
LogHelper.Instance.Error(msg, true); //弹屏,人为处理好后,再次触发
_unityContainer.Resolve<MainWindowViewModel>().AddPromptContent(msg);
scanDevice.Connect();
--s; //再次获取
continue;
}
if ((int)EProductionMode.Debug == debugMode) //调试模式
{
scanResult.IsSuccess = true;
scanResult.Content = System.Guid.NewGuid().ToString("N").Substring(0, _batteryCodeLen);
scannList.Add(scanResult);
}
else
{
//scanResult = scanDevice.ReadCode();
scannTasks.Add(Task.Run(() => scanDevice.ReadCode())); // 启动并行任务
}
}
if ((int)EProductionMode.Normal == debugMode)
{
await Task.WhenAll(scannTasks); //等待所有任务(扫码)完成
foreach (var task in scannTasks)
{
scannList.Add(task.Result);
}
}
#region MOM
if (mesEnable == (int)EMOMEnable.Enable)//生产模式才会请求MES(不是离线就要请求)
{
foreach (var item in scannList) //四个电芯扫码结果
{
if (item.IsSuccess) //可能是三个扫码OK一个扫码NG所以只有三个电芯请求到MOM
{
mesResultTasks.Add(Task.Run(() => _unityContainer.Resolve<MESProcess>().GetBatteryStatus(item.Content))); //多线程入库,会有先后顺序的
}
}
if (0 != mesResultTasks.Count)
{
MESReturnCmdModel[] tt = await Task.WhenAll(mesResultTasks); // //发送MES等待所有的MES请求。
foreach (var item in mesResultTasks) //发送MOM不一定是四个
{
mesResultList.Add(item.Result);
}
}
}
#endregion
index = 1; //1..4,第0个索引不用
for (EScanCode s = EScanCode.LoadingBatteryScan1; s <= EScanCode.LoadingBatteryScan8; s++, index++)
{
if (((curValue >> index) & 1) != 1) //第index位不是1,就是不需要扫码
{
continue;
}
scanResult = scannList[scannIndex++];
result[index] = scanResult.IsSuccess ? (Int16)EResult.OK : (Int16)EResult.NG;
if (scanResult.IsSuccess) //扫码成功
{
//长度判断
//if (_batteryCodeLen != scanResult.Content.Length)
//{
// result[index] = (Int32)EResult.NG; //长度不对赋NG
// _unityContainer.Resolve<BatteryNGService>().Insert("入站拦截", scanResult.Content, $"要求电芯条码长度为{_batteryCodeLen},实际长度为:{scanResult.Content.Length}");
// continue;
//}
//0:正常扫码1:复投扫码
if ("0" == _unityContainer.Resolve<Cowain.Bake.BLL.SysSetupService>().GetValueByParaID(Cowain.Bake.Common.Enums.ESysSetup.ScanCodeMode.ToString()))
{
if (_unityContainer.Resolve<BatteryInfoService>().IsBatteryCodeRepeat(scanResult.Content))
{
result[index] = (Int32)EResult.NG; //有相同电芯赋NG
LogHelper.Instance.Warn($"{s.GetDescription()},电芯条码:[{scanResult.Content}]重复扫码,将会排出到NG位;"); //不要弹屏
_unityContainer.Resolve<BatteryNGService>().Insert("入站拦截", scanResult.Content, $"重复扫码,将会排出到NG位");
}
}
//MES结果判断
if (mesEnable == (int)EMOMEnable.Enable) ////mes-mom 7.电芯状态获取 只有联机才调用MES接口MES返回成功失败
{
MESReturnCmdModel mesResult = mesResultList[mesIndex++];//_unityContainer.Resolve<MESProcess>().MESCellState(scanResult.Content);
if (mesResult == null)
{
result[index] = (int)EResult.NG;
_unityContainer.Resolve<BatteryNGService>().Insert("入站拦截", scanResult.Content, "MOM返回信息为空请判断MOM是否离线未离线则是MOM回复异常");
continue;
}
if (mesResult.Info.ResultFlag != EResultFlag.OK.ToString())
{
result[index] = (int)EResult.NG;
_unityContainer.Resolve<BatteryNGService>().Insert("入站拦截", scanResult.Content, JSON.SerializeObject(mesResult));
continue;
}
}
codeBatterys[index] = scanResult.Content; //MES判断OK的电芯才放到电芯表中。
}
}
batteryVirtualIds = _unityContainer.Resolve<BatteryInfoService>().InsertBattery(string.Join(",", codeBatterys)).ToArray(); //新加的,四个一起存,并返回虚拟码
//InsertBattery//四个电芯一起存数据库
LogHelper.Instance.Info($"电芯虚拟码写入到PLC:{string.Join(",", batteryVirtualIds)}codes={string.Join(",", codeBatterys)},扫码状态:{string.Join(",", result)}");
writeResult = PLC.Write<int[]>((string)d.WriteVirtualIds, batteryVirtualIds); //电芯1...4虚拟码
if (!writeResult.IsSuccess)
{
LogHelper.Instance.Warn($"写虚拟地址-{(string)d.WriteVirtualIds}:{writeResult.Message}");
}
//g_U01_HMI.UpLoadFromWcs.iCell_ScanCodeResults
writeResult = PLC.Write<Int16[]>((string)d.WriteResult, result); //电芯1...8扫码结果
if (!writeResult.IsSuccess)
{
LogHelper.Instance.Warn($"ExecutScanBattery-{(string)d.WriteResult}:{writeResult.Message}");
}
writeResult = PLC.Write<Int16[]>((string)d.WriteAsk, ask); //回复
if (!writeResult.IsSuccess)
{
LogHelper.Instance.Warn($"ExecutScanBattery-{(string)d.WriteAsk}:{writeResult.Message}");
}
_unityContainer.Resolve<MainWindowViewModel>().DeletePromptContent();
}
catch(Exception ex)
{
LogHelper.Instance.Fatal($"ExecutScanBattery-出错-param:{param}:{ex.Message},{index}");
}
_unityContainer.Resolve<BasicInfoViewModel>().SetEvent("结束:" + node.VarDesc);
}
//保存组盘信息
private void SavePalletInfo(int palletVID)
{
string dateFile;
string filePath;
try
{
List<TBatteryInfo> batterys = _unityContainer.Resolve<BatteryInfoService>().GetBatteryInfos(palletVID);
if (0 == batterys.Count)
{
return;
}
string path = _unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.DataFilePath.ToString());
path += "\\组盘";
dateFile = DateTime.Now.ToString("yyyyMMdd");
filePath = path + $"\\{dateFile}.csv";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
CSVHelper.WriteMap<TBatteryInfo, BatteryInfoMap>(batterys, filePath);
}
catch(Exception ex)
{
LogHelper.Instance.Error($"SavePalletInfo:{ex.Message},{ex.StackTrace}");
}
}
}
}