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

554 lines
26 KiB
C#
Raw Normal View History

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}");
}
}
}
}