AOI_Saki_RackParser.cs
*AOI_Saki_RackParser.cs*
using Bartech.SGCore.Base;
using Bartech.SGCore.Base.Web;
using Bartech.SGCore.Helpers;
using Bartech.SGCore.Local;
using Bartech.SGCore.Local.DataObjects;
using Bartech.SGCore.Logic.NVCZ.Modules.AOI.Model;
using Bartech.SGCore.Model;
using Bartech.SGCore.Model.ContextData;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using PartDataStatus = Bartech.SGCore.Local.DataObjects.PartDataStatus;
namespace Bartech.SGCore.Logic.NVCZ.Modules.AOI
{
[XModule("NVCZ_AOI_Saki_Pcb_Parser", "Modul pro zpracování jednotlivých pcb na AOI Saki pomocí nástroje.", ModuleGroupType.External)]
public class AOI_Saki_RackParser : SGPartStart
{
#region Constructor
public AOI_Saki_RackParser(SGSession session)
: base(session)
{
m_checkedPars = new List<DOPart>();
m_prevCheckedPars = new List<long>();
m_dxSession = Session.Resolve<SGDxSessionLocker>();
AllowedInDevs = new SGDeviceType[] { SGDeviceType.Scanner, SGDeviceType.FileSystem };
Session.Initialized += delegate (object s, EventArgs e)
{
if (Session.IsStudioSession) return;
m_checkedPars.Clear();
m_rack = new DORack(this);
m_testAoi = new SakiCsvData();
};
}
#endregion
#region Private variables
private SGDxSessionLocker m_dxSession;
private int m_frameCapacity { get; set; }
private List<DOPart> m_checkedPars;
private List<long> m_prevCheckedPars;
private BusOperation m_lastOperationOverride;
private long m_lastJobID;
private int m_masterCommand = 1;
private int m_endLoadingPartsCommand = 400;
private int m_removePartCommand = 401;
private Bartech.SGCore.Logic.NVCZ.Modules.AOI.Model.SakiCsvData m_testAoi;
private bool m_waitForFile = false;
private DORack m_rack;
private WhatHappenToParts m_partInRackAction = WhatHappenToParts.onlyNgInFrame;
private int m_ngMSStatus = 35;
private bool m_allowRetestImmediately = true;
#endregion
#region Module overrides
protected override bool OnSetParameters()
{
m_partInRackAction = Session.SysParams.GetEnum(this, "PartInFrameAction", m_partInRackAction, string.Format("Které díly mají zístat v rámečku po dokončení testu. Hodnoty: {0}", string.Join(", ", Enum.GetNames(typeof(WhatHappenToParts)))));
m_ngMSStatus = Session.SysParams.GetInt32(this, "AoiNgGSStatus", m_ngMSStatus, "Hodnota udávající jaký status se nastaví dílu při NOT OK testu dílu na pracovišti.");
m_allowRetestImmediately = Session.SysParams.GetBoolean(this, "AllowRetestImmediately", m_allowRetestImmediately, "Pokud je true tak je možné načíst stejné sériová čísla hned v dalším pracovním cyklu, jinak je nutné provést cyklus s jinými díly.");
LogResult();
return base.OnSetParameters();
}
public override void StartLevel(SGTreeModuleData mdata)
{
if (Session.CycleContext.Tools.Count() == 1)
{
var toolKat = new DOKatalogParams(this, "Tool");
toolKat.Load(Session.CycleContext.Tools[0].OID);
m_frameCapacity = toolKat.GetValue("Kapacita", 1, false);
}
else
{
m_frameCapacity = 0;
}
if ((Session.Job.GetEffectiveDOJob().JobID != m_lastJobID) || (Session.CycleContext.OperationOverride != m_lastOperationOverride))
{
m_lastJobID = Session.Job.GetEffectiveDOJob().JobID;
m_lastOperationOverride = Session.CycleContext.OperationOverride;
m_checkedPars.Clear();
m_prevCheckedPars.Clear();
m_rack.Clear();
}
base.StartLevel(mdata);
}
public override SGLMState HandlePortData(SGTreeModuleData mdata, SGReceivedData data)
{
SGLMState s = SGLMState.NotHandled;
if (mdata.LevelState == SGLevelState.Echo)
{
if (m_waitForFile == true)
{
Log(LogMsg.FILE_WaitForFile);
}
else if (m_frameCapacity == 0)
{
Message = Log(LogMsg.PART_WaitSN);
}
else
{
Message = Log(LogMsg.PV_WaitFillFrame, Session.CycleContext.Tools[0].ToolCD, m_checkedPars.Count(), m_frameCapacity);
}
s = SGLMState.Handled;
}
else if ((mdata.LevelState == SGLevelState.WaitingForData) && (data.DeviceType == SGDeviceType.Scanner) && (m_waitForFile == false)) // nacitame dily
{
if (Session.Data.CheckData(DataType.Command, data) && Session.SysCommands.IsSysCommand(this, data, (SGSysCommandType)(int)m_endLoadingPartsCommand)) // command na ukonceni nacitani
{
if (m_checkedPars.Count > 0)
{
m_waitForFile = true;
s = SGLMState.Handled | SGLMState.OK;
}
else
{
Log(LogMsg.FRAME_Empty, Session.CycleContext.Tools[0].ToolCD);
s = SGLMState.Handled | SGLMState.OK;
}
}
else if (Session.Data.CheckData(DataType.Command, data) && Session.SysCommands.IsSysCommand(this, data, (SGSysCommandType)(int)m_removePartCommand)) // command na odebrani dilu
{
if (m_checkedPars.Count > 0)
{
int indexOfPartToRemove = m_checkedPars.Count() - 1;
Log(LogMsg.FRAME_PartRemove, m_checkedPars[indexOfPartToRemove].CurBarcode, Session.CycleContext.Tools[0].ToolCD);
m_checkedPars.RemoveAt(indexOfPartToRemove);
}
else
{
Log(LogMsg.FRAME_CantRemovePart, Session.CycleContext.Tools[0].ToolCD);
}
s = SGLMState.Handled | SGLMState.OK;
}
else if (Session.Data.CheckData(DataType.Command, data) && Session.SysCommands.IsSysCommand(this, data, (SGSysCommandType)(int)m_masterCommand)) // neskutečný ojeb pro funkčnost commandu C0001
{
m_lastJobID = 0;
if (m_lastOperationOverride != null)
{
m_lastOperationOverride.Clear();
}
}
else if (Session.Data.CheckData(DataType.Rack, data))
{
m_rack.Load(data.Text, true);
if (m_rack.IsEmpty)
{
Message = Log(LogMsg.RACK_IsEmpty);
m_rack.Clear();
return SGLMState.Handled | SGLMState.Fail;
}
m_rack.RemoveAllParts();
m_rack.Clear();
}
else if (Session.Data.CheckData(DataType.SerialNo, data)) // prislo SN
{
if (!Session.Data.CheckData(DataType.Job, data.Text)) // zakaznicky kod jobu
{
string dataText = data.Text;
DOJob j = new DOJob(this);
if (j.LoadByCustomerJob(dataText, false))
{
dataText = j.Barcode;
Session.SetNextData(Session.Data.CreateReceivedData(SGDeviceType.Scanner, dataText, true));
return SGLMState.Handled | SGLMState.OK;
}
}
if (IsPartInQueue(data.Text) == true) // kontrola zda neprislo sn ktere je jiz v ramecku
{
Log(LogMsg.PV_PartWasAlreadyScanned, data.Text);
s = SGLMState.Handled | SGLMState.Fail;
}
else if (m_checkedPars.Count < m_frameCapacity) // SN neni v ramecku a jeste se tam vleze
{
s = base.HandlePortData(mdata, data);
if (Session.Part.DoPart.IsPanel)
{
Message = Log(LogMsg.AOISAKI_BadScript, data.Text);
s = SGLMState.Handled | SGLMState.Fail;
}
if (Session.Part.DoPart.IsPartChecked)
{
var dop = new DOPart(this);
Session.Part.DoPart.Clone(dop);
m_checkedPars.Add(dop);
Log(LogMsg.FRAME_AddPartToFrame, dop.CurBarcode, Session.CycleContext.Tools[0].ToolCD);
Session.Part.Clear();
if (m_checkedPars.Count == m_frameCapacity || m_frameCapacity == 0)
{
m_waitForFile = true;
return SGLMState.Handled | SGLMState.OK;
}
else
{
s = SGLMState.Handled | SGLMState.OK;
}
}
}
else // SN neni v ramecku a ten je plny => nemelo by se stat
{
Message = LogResult();
s = SGLMState.Handled | SGLMState.Fail;
}
}
}
else if ((mdata.LevelState == SGLevelState.WaitingForData) && (data.DeviceType == SGDeviceType.FileSystem) && (m_waitForFile == true)) // mame nactene dily a cekame na soubor
{
m_testAoi.Clear();
if (m_testAoi.ParseCsvFile(data.Text).Item1 == false)
{
Message = Log(LogMsg.FILE_ERROR, data.Text);
return SGLMState.Handled | SGLMState.Fail | SGLMState.ResetLevel;
}
if (m_testAoi.SubboardResults.Count() != m_checkedPars.Count())
{
Message = Log(LogMsg.AOISAKI_BadPcbCount);
return SGLMState.Handled | SGLMState.Fail | SGLMState.ResetLevel;
}
if (m_rack.Load(m_testAoi.ManageCode, false) == false)
{
Message = Log(LogMsg.RACK_FailedToLoad, m_testAoi.ManageCode);
return SGLMState.Handled | SGLMState.Fail | SGLMState.ResetLevel;
}
if (m_rack.Qty > 0)
{
Message = Log(LogMsg.AOISAKI_NotEmptyRack);
m_rack.RemoveAllParts();
}
m_waitForFile = false;
SaveParts();
if (string.IsNullOrEmpty(Session.FileGuard?.BackupPath) == false)
{
if (File.Exists(data.Text))
{
string fileName = Path.GetFileName(data.Text);
string backupFolder = fileName.Substring(0, 4) + "-" + fileName.Substring(4, 2); // bereme rok a měsíc z názvu souboru
string backupPath = Path.Combine(Session.FileGuard.BackupPath, backupFolder);
Message = Log(LogMsg.FILEBACKUP_TryBackupFile, data.Text, backupPath);
FileHelper.BackupFile(data.Text, backupPath, Session.FileGuard.DeleteOrigin, OnBackupError);
}
}
s = SGLMState.Handled | SGLMState.OK | SGLMState.UpLevel;
}
return s;
}
public override void Clear()
{
base.Clear();
}
#endregion
#region Helper functions
private bool IsPartInQueue(string sn)
{
// over, jestli dil existuje
var p = new DOPart(this);
if (!p.PartExistsCheck(sn)) return false;
// pokud je v aktualnim seznamu, tak se jedna o duplicitni nacteni
if (m_checkedPars.Any(x => x.PartID == p.PartID)) return true;
// pokud je v predeslem seznamu, tak se jedna take o duplicitni nacteni
if (m_prevCheckedPars.Any(x => x == p.PartID)) return true;
return false;
}
private void SaveParts()
{
(m_checkedPars.FirstOrDefault(x => x.MustShiftRouting) ?? m_checkedPars.FirstOrDefault())
?.Clone(Session.Part.DoPart);
List<int> okParts = new List<int>();
List<int> nokParts = new List<int>();
List<long> partForProcess = new List<long>();
int offset = 0;
bool incToolUsage = true;
if (m_testAoi.SubboardResults.ContainsKey(0) == false)
{
offset = 1;
}
// rozdeleni dilu na OK a NOK
DivideParts(ref okParts, ref nokParts, offset);
PrepareParts(ref partForProcess, okParts);
Session.Rack.DoRack.Copy(m_rack);
// Ulozeni OK dilu
if (partForProcess.Count() > 0)
{
ProcessParts(1, partForProcess, incToolUsage, okParts, offset, "Ok");
incToolUsage = false;
}
PrepareParts(ref partForProcess, nokParts);
// Ulozeni NOK dilu
if (partForProcess.Count() > 0)
{
ProcessParts(m_ngMSStatus, partForProcess, incToolUsage, nokParts, offset, "Ng");
}
PartsToRack(nokParts);
Session.Rack.DoRack.Clear();
m_rack.Clear();
Session.Part.DoPart.Clear();
// nahrad predchozi seznam OID dilu aktualnimi pouze pokud nelze hned retestovat stejné díly
if (!m_allowRetestImmediately)
{
m_prevCheckedPars.Clear();
m_prevCheckedPars.AddRange(m_checkedPars.Select(x => x.PartID));
}
// a vymaz seznam aktualne nactenych dilu
m_checkedPars.Clear();
}
private void ProcessParts(int partMSStatus, List<long> partsForProcess, bool incrementToolUsage, List<int> listOfParts, int offset, string result)
{
var ll = new List<Bartech.SGCore.Model.ContextData.PartData>();
Session.Part.DoPart.MS = partMSStatus;
// nastartuj dily
Session.Part.DoPart.MassStartEnd(partsForProcess, Session.UserWorkGroup.UserWorkGroupID, 0, false, incrementToolUsage: incrementToolUsage,
okLog: (args) =>
{
var uu = args[0] as PartOperationData;
foreach (var part in uu.Parts)
{
ll.Add(part);
}
Message = Log(LogMsg.PV_PartsSaved, Session.CycleContext.Tools[0].ToolCD, m_checkedPars.Count());
return null;
});
// zapis dilum procesni data
for (int i = 0; i < ll.Count(); i++)
{
Session.Part.DoPart.SaveProcessDataAfterPartEnd(m_testAoi.CreateProcessData(listOfParts[i] + offset, result, m_checkedPars[listOfParts[i]].CurBarcode), string.Empty, ll[i].OID, (long)ll[i].DetailID, partMSStatus == 1 ? PartDataStatus.OK : PartDataStatus.Fail, DateTime.MinValue);
}
}
private void DivideParts(ref List<int> okParts, ref List<int> nokParts, int offset)
{
foreach (var item in m_testAoi.SubboardResults)
{
if (item.Value.Last() == "FAIL")
{
nokParts.Add(item.Key - offset);
}
else if (item.Value.Last() == "GOOD")
{
okParts.Add(item.Key - offset);
}
}
}
private void PartsToRack(List<int> nokParts)
{
if (m_partInRackAction == WhatHappenToParts.allInFrame)
{
if (nokParts.Count() > 0) // pokud je alespoň jeden díl NOK, tak dáme do RACKu všechny, jinak tam nedáme nic
{
for (int i = 0; i < m_checkedPars.Count(); i++)
{
Session.Rack.DoRack.AddPart(m_checkedPars[i].PartID);
}
}
}
else
{
for (int i = 0; i < nokParts.Count(); i++)
{
Session.Rack.DoRack.AddPart(m_checkedPars[nokParts[i]].PartID);
}
}
}
private void PrepareParts(ref List<long> partsForProcess, List<int> parts)
{
partsForProcess.Clear();
foreach (var index in parts)
{
partsForProcess.Add(m_checkedPars[index].PartID);
}
}
private void OnBackupError(Exception e) => Message = Log(LogMsg.FILE_FileBackupNotOk, e.Message);
#endregion
}
#region Enum
public enum WhatHappenToParts
{
allInFrame,
onlyNgInFrame,
}
#endregion
}