using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Security.Cryptography; using System.Text; using AR; using Project.Class; namespace Project { public partial class FMain { public enum EResultKeyence { Wait = 0, Complete, TimeOut, MultiSID, Nothing, } public EResultKeyence KEYENCE_READ(eWorkPort target, eSMStep cmdIndex) { UInt16 idx = 1; var mv = PUB.Result.vModel; var mc = PUB.Result.mModel; var funcName = System.Reflection.MethodBase.GetCurrentMethod().Name; var seqTime = PUB.sm.seq.GetTime(cmdIndex); var msgType = (Class.eStatusMesage)target; var itemC = PUB.Result.ItemDataC; if (PUB.sm.getNewStep != eSMStep.RUN) return EResultKeyence.Wait; //var Jobtype = VAR.STR[eVarString.JOB_TYPE]; var CVMode = VAR.BOOL[eVarBool.Use_Conveyor]; var OPT_PrinterOff = PUB.OPT_PRINTEROFF(target); var OPT_CameraOff = PUB.OPT_CAMERA(); var OPT_BYPASS = PUB.OPT_BYPASS(); //데이터가 완료되었는지 확인 if (itemC.VisionData.Confirm) { PUB.log.AddAT("Removing barcode messages due to vision data completion"); itemC.VisionData.bcdMessage.Clear(); return EResultKeyence.Complete; } //사용자 입력 대기중이면 아에 처리하지 않는다 210203 if (PUB.flag.get(eVarBool.FG_WAIT_LOADERINFO) == true) { PUB.WaitMessage[1] = "Wait for User Confirm Interface"; return EResultKeyence.Wait; } //#################################################### //### 작업시작 //#################################################### if (PUB.sm.seq.Get(cmdIndex) == idx++) { if (PUB.Result.DryRun) { PUB.log.Add($"[{target}] Completed due to DRY-RUN"); SetDryrunData(); } else { PUB.logDbg.Add($"[{target}] Keyence reading started"); if (PUB.keyenceF != null) PUB.keyenceF.Trigger(true); if (PUB.keyenceR != null) PUB.keyenceR.Trigger(true); } VAR.BOOL[eVarBool.Need_UserConfirm_Data] = false; VAR.STR[eVarString.MULTISID_FIELDS] = string.Empty; VAR.STR[eVarString.MULTISID_QUERY] = string.Empty; VAR.TIME.Update(eVarTime.KEYENCEWAIT); PUB.sm.seq.Update(cmdIndex); return EResultKeyence.Wait; } //#################################################### //### //#################################################### if (PUB.sm.seq.Get(cmdIndex) == idx++) { //아무것도안함 PUB.sm.seq.Update(cmdIndex); return EResultKeyence.Wait; } //#################################################### //### 키엔스데이터를 처리해준다. //#################################################### if (PUB.sm.seq.Get(cmdIndex) == idx++) { bool vQtyOK = false; var vdata = itemC.VisionData; //동작중이아니라면 처리하지 않음 if (PUB.sm.getNewStep != eSMStep.RUN) return EResultKeyence.Wait; //바이패스라면 무조건ok한다. var systembypassmode = SETTING.Data.SystemBypass; if (systembypassmode && PUB.flag.get(eVarBool.FG_RDY_PORT_PC)) { vdata.SetRID("BP" + DateTime.Now.ToString("yyyyMMddHHmmss"), "bp"); vdata.SID = ("100000000"); vdata.VNAME = "BYPASS"; vdata.MFGDATE = DateTime.Now.ToString("yyyy-MM-dd"); vdata.VLOT = "BYPASS"; vdata.CUSTCODE = "0000"; vdata.CUSTNAME = "BYPASS"; vdata.QTY = "10000"; vdata.ConfirmUser = true; vdata.PrintPositionData = "1"; vdata.PrintPositionCheck = true; vdata.MFGDATE_Trust = true; vdata.PARTNO_Trust = true; vdata.QTY_Trust = true; vdata.RID_Trust = true; vdata.SID_Trust = true; vdata.VLOT_Trust = true; vdata.VNAME_Trust = true; return EResultKeyence.Complete; } //로더정보를 사용자가 처리중이면 동작 안함 if (VAR.BOOL[eVarBool.FG_WAIT_LOADERINFO]) return EResultKeyence.TimeOut; //다중SID환경에서 데이터를 선택하고 있다. if (VAR.BOOL[eVarBool.FG_WAIT_INFOSELECT]) return EResultKeyence.Wait; //데이터 처리 시간을 넘어서면 사용자 확인 창을 띄운다 220621 var ts = VAR.TIME.RUN((int)eVarTime.KEYENCEWAIT); if (VAR.BOOL[eVarBool.FG_RDY_PORT_PC] && ts.TotalMilliseconds > AR.SETTING.Data.Timeout_VisionProcessL) { //화면업데이트를 종료한다 if (PUB.keyenceF != null) PUB.keyenceF.Trigger(false); if (PUB.keyenceR != null) PUB.keyenceR.Trigger(false); //이미지저장용 작업시작 var tempfileF = System.IO.Path.Combine(UTIL.CurrentPath, "Temp", "Image", DateTime.Now.ToString("yyyMMddHhmmss_fff" + "F.bmp")); var tempfileR = System.IO.Path.Combine(UTIL.CurrentPath, "Temp", "Image", DateTime.Now.ToString("yyyMMddHhmmss_fff" + "R.bmp")); var tempfiF = new System.IO.FileInfo(tempfileF); var tempfiR = new System.IO.FileInfo(tempfileR); if (tempfiF.Directory.Exists == false) tempfiF.Directory.Create(); if (tempfiR.Directory.Exists == false) tempfiR.Directory.Create(); //마지막 사진을 추출한다 var CurImageF = PUB.keyenceF.SaveImage(tempfiF.FullName); var CurImageR = false; if (PUB.keyenceR != null) CurImageR = PUB.keyenceR.SaveImage(tempfiR.FullName); if (CurImageF && CurImageR) { itemC.VisionData.SetImage( new Emgu.CV.Mat(tempfiF.FullName, Emgu.CV.CvEnum.ImreadModes.Grayscale), new Emgu.CV.Mat(tempfiR.FullName, Emgu.CV.CvEnum.ImreadModes.Grayscale)); } else if (CurImageF) { itemC.VisionData.SetImage(new Emgu.CV.Mat(tempfiF.FullName, Emgu.CV.CvEnum.ImreadModes.Grayscale)); } PUB.keyenceF.Trigger(true); PUB.keyenceR.Trigger(true); return EResultKeyence.TimeOut; } var prcResult = BCDProcess_ALL(itemC, "SEQ", true); if (prcResult != EResultKeyence.Nothing) return prcResult; PUB.sm.seq.Update(cmdIndex); return EResultKeyence.Wait; } //#################################################### //### //#################################################### if (PUB.sm.seq.Get(cmdIndex) == idx++) { PUB.sm.seq.Update(cmdIndex); return EResultKeyence.Wait; } PUB.sm.seq.Clear(cmdIndex); return EResultKeyence.Complete; } /// /// 데이터입력이 완료되었는지 확인 합니다 /// /// /// /// void CheckDataComplte(Class.JobData item, string Source, bool mainjob) { Boolean NeedConfirm = false; //var Jobtype = VAR.STR[eVarString.JOB_TYPE]; var OPT_BYPASS = SETTING.Data.SystemBypass;// Jobtype == "BP"; var CVMode = VAR.BOOL[eVarBool.Use_Conveyor]; var CustomerCode = VAR.STR[eVarString.JOB_CUSTOMER_CODE]; if (item.VisionData.Confirm) { //사용자에의해 완성된 자료는 완료된 자료이다 if (item.VisionData.bcdMessage.Count > 0) item.VisionData.bcdMessage.Clear(); return; } //처음작업이면 반드시 확인을 한다 if (OPT_BYPASS == false && PUB.Result.JobFirst) { //사용자확인이 필요없는 상태라면 활성화해준다 //프린트를 하지 않는다면 처리하지 않는다. if (VAR.BOOL[eVarBool.Opt_DisablePrinter] == false) { if (mainjob && item.VisionData.bcdMessage.ContainsKey(6) == false) item.VisionData.bcdMessage.Add(6, "First reel confirmation required"); NeedConfirm = true; } } //서버의수량업데이트기능 if (OPT_BYPASS == false && VAR.BOOL[eVarBool.Opt_ServerQty]) { //수량원본이 없는 경우 if (item.VisionData.QTY0.isEmpty()) { string msg = "Server quantity update feature is not applicable to WMS, contact developer if needed"; var cnt = 0;// (int)(Amkor.RestfulService.get_stock_count(item.VisionData.RID, out msg)); if (mainjob) { PUB.log.AddE("Server quantity update feature is not applicable to WMS, contact developer if needed"); } if (cnt > 0) { //새로받은 데이터를 실제 수량에 추가한다 item.VisionData.QTY0 = item.VisionData.QTY; item.VisionData.QTY = cnt.ToString(); if (mainjob) PUB.log.Add($"Server quantity update RID:{item.VisionData.RID} Old:{item.VisionData.QTY}, New:{cnt}"); } else { if (mainjob) PUB.log.AddE($"Quantity update failed rID:{item.VisionData.RID}, Message={msg}"); NeedConfirm = true; if (mainjob && item.VisionData.bcdMessage.ContainsKey(1) == false) item.VisionData.bcdMessage.Add(1, "Quantity update failed"); } } } //수량입력 210708 if (OPT_BYPASS == false && VAR.BOOL[eVarBool.Opt_UserQtyRQ]) { if (item.VisionData.QTYRQ && item.VisionData.QTY.isEmpty() == false) { //RQ값이 이전 값이 오기도 하니 바코드 목록에서 값을 다시 써준다. 210825 var rqBcd = PUB.Result.ItemDataC.VisionData.barcodelist.Where(t => t.Value.Data.StartsWith("RQ")).FirstOrDefault(); if (rqBcd.Value != null) { var newqty = rqBcd.Value.Data.Substring(2).Trim(); if (mainjob) PUB.log.Add($"Quantity update (01) {item.VisionData.QTY}->{newqty}"); item.VisionData.QTY = newqty; if (mainjob) PUB.log.AddI("Manual quantity input mode but RQ value confirmed, no user confirmation required"); } else { if (mainjob && item.VisionData.bcdMessage.ContainsKey(2) == false) item.VisionData.bcdMessage.Add(2, "RQ value error (auto mode not possible)"); NeedConfirm = true; } } else { if (mainjob && item.VisionData.bcdMessage.ContainsKey(3) == false) item.VisionData.bcdMessage.Add(3, "Manual quantity input required"); NeedConfirm = true; } } //프린트위치확인 BCDProcess_BCDPrint(item); if (item.VisionData.PrintPositionData.isEmpty() == true || item.VisionData.PrintPositionCheck == false) { if (mainjob && item.VisionData.bcdMessage.ContainsKey(4) == false) item.VisionData.bcdMessage.Add(4, "Attachment position not found"); NeedConfirm = true; } //SID 존재여부 확인 if (OPT_BYPASS == false && item.VisionData.SID_Trust && VAR.BOOL[eVarBool.Opt_CheckSIDExist]) { //ECS목록에 데이터가 업다면 오류로 처리한다 var SID = item.VisionData.SID; var ta = new DataSet1TableAdapters.QueriesTableAdapter(); var exist = ta.CheckSIDExist(SID) > 0; PUB.log.Add($"SID Exist Check SID:{item.VisionData.SID},Result={exist}"); if (exist == false) { PUB.Result.SetResultMessage(eResult.OPERATION, eECode.NOSIDINFOFROMDB, eNextStep.PAUSE, SID); return; } } //sid변환기능확인 var SIDOK = false; if (OPT_BYPASS == false && VAR.BOOL[eVarBool.Opt_SIDConvert] && PUB.flag.get(eVarBool.FG_WAIT_LOADERINFO) == false && VAR.BOOL[eVarBool.JOB_Empty_SIDConvertInfo] == false) { //시드값이 유효한지 확인한다. SIDOK = item.VisionData.SID_Trust && item.VisionData.SID0.isEmpty() == false && item.VisionData.SID.isEmpty() == false; } else SIDOK = (item.VisionData.SID_Trust && item.VisionData.SID.isEmpty() == false); //시드변환을 사용하지 않으므로 시드값여부에따라 다르다 //수량확인 if (OPT_BYPASS == false) { if(double.TryParse(item.VisionData.QTY,out double qtyvalue)==false) { if (mainjob && item.VisionData.bcdMessage.ContainsKey(8) == false) item.VisionData.bcdMessage.Add(8, "Qty invalid"); NeedConfirm = true; } } //사용자확인이 필요한 옵션이라면 사용한다 if (OPT_BYPASS == false && VAR.BOOL[eVarBool.Opt_UserConfim]) { if (mainjob && item.VisionData.bcdMessage.ContainsKey(5) == false) item.VisionData.bcdMessage.Add(5, "User confirmation required"); NeedConfirm = true; } //변환작업인데 원본 값이 없다. //혹은 변환값과 원본이 같다 if (OPT_BYPASS == false && VAR.BOOL[eVarBool.Opt_SIDConvert] && (item.VisionData.SID0.isEmpty() == true || item.VisionData.SID0 == item.VisionData.SID)) { if (mainjob && item.VisionData.bcdMessage.ContainsKey(7) == false) item.VisionData.bcdMessage.Add(7, "SID conversion value confirmation required"); NeedConfirm = true; } //데이터의 신뢰성을 확인하고 모두 입력되었다면 자동 확정을 진행한다 if (item.VisionData.MFGDATE_Trust && item.VisionData.PARTNO_Trust && item.VisionData.QTY_Trust && item.VisionData.RID_Trust && item.VisionData.SID_Trust && SIDOK && item.VisionData.VLOT_Trust && item.VisionData.VNAME_Trust) { //데이터를 확정짓는다 다만 화면을 표시하지 않아야하는 경우에만 처리해준다 if (NeedConfirm == false) { if (OPT_BYPASS) { PUB.log.Add("All data confirmed, proceeding with automatic confirmation (bypass mode)"); if (item.VisionData.bcdMessage.Count > 0) item.VisionData.bcdMessage.Clear(); item.VisionData.ConfirmBypass = true; } else if (item.VisionData.ConfirmAuto == false) { PUB.log.Add("All data confirmed, proceeding with automatic confirmation"); if (item.VisionData.bcdMessage.Count > 0) item.VisionData.bcdMessage.Clear(); item.VisionData.ConfirmAuto = true; } } } else if (item.VisionData.QRInputRaw.isEmpty() == false) { if (mainjob) { NeedConfirm = true; PUB.log.AddAT($"Data incomplete but QR has been read, showing confirmation window immediately"); } } //확인창을 띄우기 위해 Timeout 오류를 발생시킨다. VAR.BOOL[eVarBool.Need_UserConfirm_Data] = NeedConfirm; if (NeedConfirm) { if (mainjob) { var newtime = DateTime.Now.AddMilliseconds(-AR.SETTING.Data.Timeout_VisionProcessL); VAR.TIME.Set(eVarTime.KEYENCEWAIT, newtime); } } else if (PUB.Result.ItemDataC.VisionData.ConfirmAuto == false) { PUB.logDbg.Add($"Vision automatic confirmation processing {Source}"); PUB.Result.ItemDataC.VisionData.ConfirmAuto = true; } } List warninactivelist = new List(); private void SetDryrunData() { var item = PUB.Result.ItemDataC; PUB.log.AddAT("Dry run basic data input"); if (item.VisionData.QTY.isEmpty()) item.VisionData.QTY = DateTime.Now.ToString("HHmm"); if (item.VisionData.MFGDATE.isEmpty()) item.VisionData.MFGDATE = DateTime.Now.ToString("yy-MM-dd"); if (item.VisionData.SID.isEmpty()) item.VisionData.SID = "108" + "0" + DateTime.Now.ToString("HH").PadLeft(2, '0') + DateTime.Now.ToString("fff").PadLeft(3, '0'); if (item.VisionData.VLOT.isEmpty()) item.VisionData.VLOT = "SUPNAME" + DateTime.Now.ToString("fff"); if (item.VisionData.PARTNO.isEmpty()) item.VisionData.PARTNO = "PARTNO" + DateTime.Now.ToString("yyyyMMddHHmmss.fff"); if (item.VisionData.RID.isEmpty()) { var newid = PUB.MakeNewREELID(item.VisionData.SID);// Amkor.RestfulService.Allocation_Unique_ReelID_AmkorSTD("1234", "4", "A", out string err); if (newid.success == false) item.VisionData.SetRID("RID" + DateTime.Now.ToString("yyyyMMddHHmmss.fff"), "DRY"); else item.VisionData.SetRID(newid.newid, "DRY"); } if (item.VisionData.PrintPositionData.isEmpty()) item.VisionData.PrintPositionData = "2"; item.VisionData.PrintPositionCheck = true; item.VisionData.ConfirmAuto = true; } } }