From 333612e0ebaf827ccfb42d586a772838ba47b906 Mon Sep 17 00:00:00 2001 From: Mike Phares Date: Tue, 27 May 2025 16:35:42 -0700 Subject: [PATCH] Common ResourceID and IsViewerFile Enable process-data-standard-format for HgCV and Tencor --- LSL2/STPROC/METROLOGY_SERVICES.txt | 1599 ++++++++++++++-------------- 1 file changed, 810 insertions(+), 789 deletions(-) diff --git a/LSL2/STPROC/METROLOGY_SERVICES.txt b/LSL2/STPROC/METROLOGY_SERVICES.txt index 43d5adf..af8b94e 100644 --- a/LSL2/STPROC/METROLOGY_SERVICES.txt +++ b/LSL2/STPROC/METROLOGY_SERVICES.txt @@ -398,10 +398,10 @@ Service ImportMetrologyFiles(Machine) Begin Case Case Machine _EQC 'Tencor' - SearchPattern = '*.txt'; + SearchPattern = '*.pdsf'; DataPath = Environment_Services('GetApplicationRootPath') : '\Metrology\MET08DDUPSFS6420\Source\MET08DDUPSFS6420\' Case Machine _EQC 'HgCV' - SearchPattern = '*.txt'; + SearchPattern = '*.pdsf'; DataPath = Environment_Services('GetApplicationRootPath') : '\Metrology\MET08RESIHGCV\Source\MET08RESIHGCV\' Case Machine _EQC 'CDE' SearchPattern = '*.pdsf'; @@ -647,21 +647,42 @@ Service ImportMetrologyRunData(Machine, DataPath, FileName, RunData) // Scan the run data for machine specific information. Then call the relevant update service for the specific // machine. + ResourceID = Field(FileName, ' ', 1, 1) + IsViewerFile = Index(FileName, 'Viewer', 1) Begin Case Case Machine _EQC 'Stratus' - Metrology_Services('ImportStratusData', RunData) + PSN = RunData<9> + Metrology_Services('ImportStratusData', RunData, ResourceID, PSN) MachineType@ = 'Stratus' Case Machine _EQC 'Biorad' - Metrology_Services('ImportBioRadData', RunData, FileName) + PSN = RunData<7> + QualFile = ( (PSN EQ 'T-Low') or (PSN EQ 'T-Mid') or (PSN EQ 'T-High') or (PSN EQ 'T_LOW') or (PSN EQ 'T_MID') or (PSN EQ 'T_HIGH') ) + IF QualFile THEN + Metrology_Services('ImportBioRadQualData', RunData, ResourceID, PSN) + END ELSE + Metrology_Services('ImportBioRadData', RunData, ResourceID, IsViewerFile, PSN, FileName) + END MachineType@ = 'Bio-Rad' Case Machine _EQC 'CDE' - Metrology_Services('ImportCDEData', RunData, FileName) + PSN = RunData<8> + QualFile = ( (PSN EQ 'RLOW_STD') or (PSN EQ 'RMID_STD') or (PSN EQ 'RHI_STD') or (PSN EQ 'THINSPC') ) + IF QualFile THEN + Metrology_Services('ImportCDEQualData', RunData, ResourceID, PSN) + END ELSE + Metrology_Services('ImportCDEData', RunData, ResourceID, IsViewerFile, PSN) + END MachineType@ = 'CDE' Case Machine _EQC 'HgCV' - Metrology_Services('ImportHgCVData', RunData, FileName) + PSN = RunData<5> + QualFile = ( (PSN EQ 'Low') or (PSN EQ 'Mid') or (PSN EQ 'High') or (PSN EQ 'Thin') ) + IF QualFile THEN + Metrology_Services('ImportHgCVQualData', RunData, ResourceID, PSN) + END ELSE + Metrology_Services('ImportHgCVData', RunData, ResourceID, IsViewerFile, PSN) + END MachineType@ = 'HgProbe' Case Machine _EQC 'SP1' @@ -692,7 +713,7 @@ Service ImportMetrologyRunData(Machine, DataPath, FileName, RunData) end service -Service ImportStratusData(RunData) +Service ImportStratusData(RunData, ResourceID, PSN) Machine = 'Stratus' ParseArray = '' @@ -707,7 +728,6 @@ Service ImportStratusData(RunData) Recipe = RunData<6> Reactor = RunData<7> RDSNo = RunData<8> ; // If Non-EpiPro this will be an RDS Key, otherwise it will be a work order key. - PSN = RunData<9> BatchID = RunData<10> Cassette = RunData<11> ThickAvg = RunData<12> @@ -866,7 +886,45 @@ Service ImportStratusData(RunData) end service -Service ImportBioRadData(RunData, FileName) +Service ImportBioRadQualData(RunData, ResourceID, PSN) + + Machine = 'BioRad' + URL = "https://oi-metrology-viewer-prod.mes.infineon.com/api/InfinityQSV3/":ResourceID:"/header" + TimeoutDuration = HTTPClient_Services('GetTimeoutDuration') + If TimeoutDuration NE 30 then Httpclient_Services('SetTimeoutDuration', 30) + Response = Httpclient_Services('SendHTTPRequest', 'GET', URL, '', '', '', '', '', '', '') + If Response NE '' then + objJSON = '' + If SRP_JSON(objJSON, 'Parse', Response) EQ '' then + SumOOS = SRP_JSON(objJSON, 'GetValue', 'Results[1].iq_sum') + ToolID = RunData<5> + TimeStamp = RunData<2> + If SumOOS NE '' then + Swap 'T_LOW' with 'T-Low' in PSN + Swap 'T_MID' with 'T-Mid' in PSN + Swap 'T_HIGH' with 'T-High' in PSN + Pass = (SumOOS EQ 0) + QualResponse = PM_Services('ProcessQual', PSN, ToolID, TimeStamp, Pass) + StatusCode = QualResponse<1> + Message = QualResponse<2> + Metrology_Services('LogResults', PSN, Machine, StatusCode, Service : ' : ' : Message) + end else + LogMessage = 'IQS response missing Results[1].iq_sum. Error message: ':SRP_JSON(objJSON, 'GetValue', 'message') + Metrology_Services('LogResults', PSN, Machine, 'UID002', Service : ' : ' : LogMessage) + end + SRP_JSON(objJSON, 'Release') + end else + Metrology_Services('LogResults', PSN, Machine, 'UID002', Service : ' : ' : 'Failed to parse IQS JSON response') + end + end else + Metrology_Services('LogResults', PSN, Machine, 'UID002', Service : ' : ' : 'Null response from IQS API.') + end + +end service + + +Service ImportBioRadData(RunData, ResourceID, IsViewerFile, PSN, FileName) + Machine = 'BioRad' IsProdTest = False$ ParseArray = '' @@ -874,420 +932,31 @@ Service ImportBioRadData(RunData, FileName) FieldPosIncrement = 2 Offset = 1 Decimals = 2 - PSN = RunData<7> - QualFile = ( (PSN EQ 'T-Low') or (PSN EQ 'T-Mid') or (PSN EQ 'T-High') or (PSN EQ 'T_LOW') or (PSN EQ 'T_MID') or (PSN EQ 'T_HIGH') ) - If QualFile then - ResourceID = Field(FileName, ' ', 1, 1) - URL = "https://oi-metrology-viewer-prod.mes.infineon.com/api/InfinityQSV3/":ResourceID:"/header" - TimeoutDuration = HTTPClient_Services('GetTimeoutDuration') - If TimeoutDuration NE 30 then Httpclient_Services('SetTimeoutDuration', 30) - Response = Httpclient_Services('SendHTTPRequest', 'GET', URL, '', '', '', '', '', '', '') - If Response NE '' then - objJSON = '' - If SRP_JSON(objJSON, 'Parse', Response) EQ '' then - SumOOS = SRP_JSON(objJSON, 'GetValue', 'Results[1].iq_sum') - ToolID = RunData<5> - TimeStamp = RunData<2> - If SumOOS NE '' then - Swap 'T_LOW' with 'T-Low' in PSN - Swap 'T_MID' with 'T-Mid' in PSN - Swap 'T_HIGH' with 'T-High' in PSN - Pass = (SumOOS EQ 0) - QualResponse = PM_Services('ProcessQual', PSN, ToolID, TimeStamp, Pass) - StatusCode = QualResponse<1> - Message = QualResponse<2> - Metrology_Services('LogResults', PSN, Machine, StatusCode, Service : ' : ' : Message) - end else - LogMessage = 'IQS response missing Results[1].iq_sum. Error message: ':SRP_JSON(objJSON, 'GetValue', 'message') - Metrology_Services('LogResults', PSN, Machine, 'UID002', Service : ' : ' : LogMessage) - end - SRP_JSON(objJSON, 'Release') - end else - Metrology_Services('LogResults', PSN, Machine, 'UID002', Service : ' : ' : 'Failed to parse IQS JSON response') - end - end else - Metrology_Services('LogResults', PSN, Machine, 'UID002', Service : ' : ' : 'Null response from IQS API.') - end + // RDS Biorad metrology file + Timestamp = RunData<2> + RDSKeyID = RunData<6> + RunDataLayer = RunData<8> + RunDataZone = RunData<9> + ReactorID = RunData<5> + ScanRecipe = RunData<4> + ToolClassID = 'FTIR' + PatternNameIndex = RDS_TEST_SPEC_THICK_MPATTERN$ + ToolClassIndex = RDS_TEST_SPEC_THICK_MTOOL$ + DataIndex = RDS_TEST_READ_THICK$ + DTMIndex = RDS_TEST_TEST_RUN_THICKNESS_DTM$ + // Clean the cassette user input. + Cassette = RDSKeyID + Swap '.' with '*' in Cassette + Swap 'o' with '' in Cassette + Swap 'O' with '' in Cassette + if RowExists('WM_OUT', Cassette) then + //Redirect to EPP FQA Import + Metrology_Services('ImportBioRadEPPFQAData', RunData, FileName) end else - // RDS Biorad metrology file - IsViewerFile = Index(FileName, 'Viewer', 1) - Timestamp = RunData<2> - RDSKeyID = RunData<6> - RunDataLayer = RunData<8> - RunDataZone = RunData<9> - ReactorID = RunData<5> - ScanRecipe = RunData<4> - ToolClassID = 'FTIR' - PatternNameIndex = RDS_TEST_SPEC_THICK_MPATTERN$ - ToolClassIndex = RDS_TEST_SPEC_THICK_MTOOL$ - DataIndex = RDS_TEST_READ_THICK$ - DTMIndex = RDS_TEST_TEST_RUN_THICKNESS_DTM$ - // Clean the cassette user input. - Cassette = RDSKeyID - Swap '.' with '*' in Cassette - Swap 'o' with '' in Cassette - Swap 'O' with '' in Cassette - if RowExists('WM_OUT', Cassette) then - //Redirect to EPP FQA Import - Metrology_Services('ImportBioRadEPPFQAData', RunData, FileName) - end else - RDSNo@ = RDSKeyID - RDSRec = Database_Services('ReadDataRow', 'RDS', RDSKeyID) - If Error_Services('NoError') then - WorkOrderNo = RDSRec - - // HgCV Project Development Code ------------------------------------------------------------------------------- - DevelopmentFlag = Xlate('DEVELOPMENT', 'HGCV', 'STATUS', 'X') - If (DevelopmentFlag EQ True$) then - IsProdTest = ( Indexc(ScanRecipe, 'PROD', 1) GT 0 ) - If IsProdTest EQ True$ then Metrology_Services('LogResults',RDSKeyID,Machine,'HgCV','Product test recognized. Recipe name: ':ScanRecipe) - end - // ------------------------------------------------------------------------------------------------------------- - CassNo = RDSRec - WorkOrder = Work_Order_Services('GetWorkOrder', WorkOrderNo, False$) - GoSub ParseWorkOrder - IsEpiPro = (WOReactorType _EQC 'EpiPro') OR (WOReactorType _EQC 'EPP') - - RunDataZone = Metrology_Services('FormatZoneKeyID', RunDataZone) ; // 1, 2 - RunDataLayer = Metrology_Services('FormatLayerKeyID', RunDataLayer) ; // L1, L2, 2 - - ZoneForValidation = RunDataZone - LayerForValidation = RunDataLayer - If LayerForValidation EQ '' then - LayerForValidation = 'L1' - end - - CalculatedZone = Metrology_Services('GetCalculatedZone', RDSKeyID, IsEpiPro, RunDataZone) - If RunDataZone NE CalculatedZone then - Error_Services('Add', 'Entered Zone [' : RunDataZone : '] and calculated Zone [' : CalculatedZone : '] do not match.') - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) - end - Transfer CalculatedZone to RunDataZone - - CalculatedLayer = Metrology_Services('GetCalculatedLayer', RDSKeyID, Machine, RunDataZone, IsEpiPro, RunDataLayer) - If (RunDataLayer NE CalculatedLayer) then - Error_Services('Add', 'Entered Layer [' : RunDataLayer : '] and calculated Layer [' : CalculatedLayer : '] do not match for the Zone [' : RunDataZone : '].') - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) - end - Transfer CalculatedLayer to RunDataLayer - - ReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactorID) - If Error_Services('NoError') then - ReactorType = ReactorRec - If ReactorType _EQC 'EpiPro' OR ReactorType _EQC 'EPP' OR ReactorType _EQC 'P' then - TestPointMapping = True$ - If RunDataLayer EQ '' OR RunDataZone EQ '' then - Message = 'Layer and Zone are required for EpiPro.' - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Message) - Error_Services('Add', Message) - end - end else - TestPointMapping = False$ - If RunDataLayer NE '' then - RunDataZone = '' - end else - Message = 'Layer is required for non-EpiPro.' - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Message) - Error_Services('Add', Message) - end - end - - If Error_Services('NoError') then - Positions = '' - DataPoints = '' - Loop - Position = Trim(RunData) - DataPoint = Trim(RunData) - Until Position EQ '' - Positions := Position : @VM - DataPoints := DataPoint : @VM - FieldPos += FieldPosIncrement - Repeat - Positions[-1, 1] = '' ; // Strip final @VM - DataPoints[-1, 1] = '' ; // Strip final @VM - RawDataPoints = DataPoints - DataPoints = Iconv(DataPoints, 'MD' : Decimals) - - Swap ' AM' with 'AM' in Timestamp - Swap ' PM' with 'PM' in Timestamp - Timestamp = IConv(Timestamp,'DT') - RDSLayerKeyID = RDSKeyID : '*' : RunDataLayer - NumDataPoints = DCount(DataPoints, @VM) - RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID) - If Error_Services('NoError') then - RDSTestKeyIDs = RDSLayerRec - Found = False$ - If RDSTestKeyIDs NE '' then - For Each RDSTestKeyID in RDSTestKeyIDs using @VM setting mkPos - RDSTestRec = Database_Services('ReadDataRow', 'RDS_TEST', RDSTestKeyID) - If Error_Services('NoError') then - RDSTestZoneID = RDSTestRec - // First test - Look for a Zone ID match. - If (RDSTestZoneID EQ RunDataZone) then - // A match has been found. No need to continue searching. - Found = True$ - end - end - Until Found - Next RDSTestKeyID - end else - Error_Services('Add', 'Unable to obtain a valid Metrology Test Key ID.') - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) - end - - // If not found this is because there was no zone. However, if this is not EpiPro, this is still a valid - // test so set the found flag to true. - If Not(Found) AND Not(IsEpiPro) then Found = True$ - - If (Found EQ True$) then - // Check if QA Metrology run or conventional RDS Metrology run. - // Recipe name match requirement has been turned off per Tom Tillery. djs 10/03/18 - Begin Case - Case IsProdTest - // WO_MAT_QA THICK_ONLY test -> import and send to SPC - LogPath = Environment_Services('GetSpcFilesharePath') - LogPath2 = Environment_Services('GetApplicationRootPath') : '\Metrology' - SendToSPC = False$ - Begin Case - Case NumDataPoints EQ 5 - // Create 5 point SPC file - objSPC = Logging_Services('NewLog', LogPath, OConv(Datetime(), 'DT_^1_HS_'):'_Thickness_5Points.txt', CRLF$, Comma$, '', '', False$, True$) - NotesLog = Logging_Services('NewLog', LogPath2, 'Thickness_5Points.txt', CRLF$, Comma$, '', '', False$, False$) - SendToSPC = True$ - Case NumDataPoints EQ 9 - // Create 9 point SPC file - objSPC = Logging_Services('NewLog', LogPath, OConv(Datetime(), 'DT_^1_HS_'):'_Thickness_9Points.txt', CRLF$, Comma$, '', '', False$, True$) - NotesLog = Logging_Services('NewLog', LogPath2, 'Thickness_9Points.txt', CRLF$, Comma$, '', '', False$, False$) - SendToSPC = True$ - Case NumDataPoints EQ 10 - objSPC = Logging_Services('NewLog', LogPath, OConv(Datetime(), 'DT_^1_HS_'):'_Thickness_10Points.txt', CRLF$, Comma$, '', '', False$, True$) - NotesLog = Logging_Services('NewLog', LogPath2, 'Thickness_10Points.txt', CRLF$, Comma$, '', '', False$, False$) - SendToSPC = True$ - Case NumDataPoints EQ 14 - objSPC = Logging_Services('NewLog', LogPath, OConv(Datetime(), 'DT_^1_HS_'):'_Thickness_14Points.txt', CRLF$, Comma$, '', '', False$, True$) - NotesLog = Logging_Services('NewLog', LogPath2, 'Thickness_14Points.txt', CRLF$, Comma$, '', '', False$, False$) - SendToSPC = True$ - Case Otherwise$ - // Log this as it is unexpected - NotesLog = Logging_Services('NewLog', LogPath2, 'Thickness_Points_Error.txt', CRLF$, Comma$, '', '', False$, False$) - End Case - - LogData = '' - LogData<1> = Oconv(Timestamp, 'DT/^HS') ; // Metrology date/time stamp - LogData<2> = ReactorID ; // Reactor - LogData<3> = RDSKeyID ; // RDS No - LogData<4> = RunData<7> ; // PSN - // Log data positions 5 through 10, 14, or 18 will be populated with data point measurements. - Convert @VM to @FM in RawDataPoints - Min = RawDataPoints<1> - Max = RawDataPoints<1> - For each DataPoint in RawDataPoints using @FM Setting DataPos - Min = Min(Min, DataPoint) - Max = Max(Max, DataPoint) - LogData = DataPoint - Next DataPoint - LogData := @RM : ' ' - If SendToSPC then Logging_Services('AppendLog', objSPC, LogData, @RM, @FM, True$) - Logging_Services('AppendLog', NotesLog, LogData, @RM, @FM, True$) - Average = Sum(RawDataPoints) / NumDataPoints - Average = Iconv(Average, 'MD3') - Average = Oconv(Average, 'MD3') - WOMatKey = Xlate('RDS', RDSKeyID, 'WO_MAT_KEY', 'X') - WOMatQAID = WorkOrderNo : '*' : CassNo - WOMatQARec = Database_Services('ReadDataRow', 'WO_MAT_QA', WOMatQAID) - SpecRecipes = WOMatQARec - - WOStepNo = RDSRec[-1, 'B*'] - ProfSteps = '' - ProfileCnt = DCount(WOMatQARec, @VM) - For vPos = 1 to ProfileCnt - ProfSteps<1, vPos> = WOMatQARec : '*' : WOMatQARec - Next vPos - LastProfSig = WOMatQARec - SigProfKeys = 'THICK_ONLY' - SigCnt = DCount(SigProfKeys, @VM) - Stages = 'UNLOAD' - SigProfFound = False$ - For Each SigProfKey in SigProfKeys using @VM setting vPos - Stage = Stages<1, vPos> - If Num(SigProfKey[1, 1]) else - SigProfKey = WOStepNo : SigProfKey - end - ProfStep = SigProfKey : '*' : Stage - Locate ProfStep in ProfSteps using @VM setting Pos then - SigProfFound = True$ - UnloadSigned = Signature_Services('GetStageSummary', WoMatKey, 'UNLOAD')<2> - IF (Stage EQ 'UNLOAD' AND UnloadSigned EQ True$) OR Stage NE 'UNLOAD' then - // verify recipe is correct - WoMatQaRecipe = WOMatQARec - WoMatQaRecipeMatchesScanRecipe = ScanRecipe _EQC WoMatQaRecipe - If WoMatQaRecipeMatchesScanRecipe EQ False$ then - ErrMsg = 'Scan recipe [ ' : ScanRecipe : ' ] does not match WoMatQa recipe [ ' : WoMatQaRecipe : ' ] for RDS [ ' : RDSKeyID : ' ] layer [ ' : CalculatedLayer : ' ].' - Error_Services('Add', ErrMsg) - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) - end - - // verify number of points is correct - WoMatQaToolClass = WOMatQARec - WoMatQaRecipePattern = WOMatQARec - NumDataPointsInSpec = Tool_Class_Services('GetNumberOfPointsForPattern', WoMatQaToolClass, WoMatQaRecipePattern) - WoMatQaRecipePatternNumPointsMatchesScanNumDataPoints = NumDataPointsInSpec EQ NumDataPoints - - If WoMatQaRecipePatternNumPointsMatchesScanNumDataPoints EQ False$ then - ErrMsg = 'Scan data point count [ ' : NumDataPoints : ' ] does not match WoMatQa recipe pattern data point count [ ' : NumDataPointsInSpec : ' ] for RDS [ ' : RDSKeyID : ' ] layer [ ' : CalculatedLayer : ' ].' - Error_Services('Add', ErrMsg) - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) - end - - If (WOMatQARec EQ '' OR IsViewerFile) then - If WoMatQaRecipeMatchesScanRecipe and WoMatQaRecipePatternNumPointsMatchesScanNumDataPoints then - WOMatQARec = Average - WOMatQARec = Oconv(Iconv(Min, 'MD3'), 'MD3') - WOMatQARec = Oconv(Iconv(Max, 'MD3'), 'MD3') - SpecMin = WOMatQARec - SpecMax = WOMatQARec - For each DataPoint in RawDataPoints using @FM setting SubValuePos - FormatedData = Oconv(Iconv(DataPoint, 'MD3'), 'MD3') - If NumDataPoints LT 14 then - If ( ( FormatedData LT SpecMin ) OR ( FormatedData GT SpecMax ) and (SubValuePos LT 10) ) then - WOMatQARec = True$ - end - end else - If ( FormatedData LT SpecMin ) OR ( FormatedData GT SpecMax ) then - WOMatQARec = True$ - end - end - WOMatQARec = FormatedData - Next DataPoint - WOMatQARec = '' - WOMatQARec = '' - Database_Services('WriteDataRow', 'WO_MAT_QA', WOMatQAID, WOMatQARec, True$, False$, True$) - end - end else - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : UID001 - Data for this metrology test already exists and is not from the metrology viewer.') - end - end else - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : UID001 - Unload signature must first be signed for this data to be uploaded.') - end - end - Until SigProfFound - Next SigProfKey - If SigProfFound EQ True$ then - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID000', Service : ' : Sig Prof. Found') - end else - Error_Services('Add', 'Unable to locate the signature profile [' : ProfStep : '].') - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) - end - Case Otherwise$ - // If not an above case, then the run is a conventional THICK_ONLY RDS metrology test. - - RDSLayerKeyID = RDSKeyID : '*' : LayerForValidation - RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID) - If Error_Services('NoError') then - RDSTestKeyIDs = RDSLayerRec - - // Verify the scan recipe matches the spec recipe - RecipeMatches = Metrology_Services('ScanRecipeMatchesRdsTestSpecThickMrecipe', RDSKeyID, LayerForValidation, ScanRecipe, RDSTestKeyIDs, ZoneForValidation) - If RecipeMatches EQ False$ then - ErrMsg = 'Scan recipe [ ' : ScanRecipe : ' ] does not match RDS Test recipe for RDS [ ' : RDSKeyID : ' ] layer [ ' : CalculatedLayer : ' ] zone [ ' : CalculatedZone : ' ].' - Error_Services('Add', ErrMsg) - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) - end - - // Verfiy the scan number of points matches the spec number of points - NumPointsMatches = Metrology_Services('ScanNumDataPointsMatchesRdsTestSpecThickMPattern', RDSKeyID, LayerForValidation, NumDataPoints, RDSTestKeyIDs, 'FTIR', ZoneForValidation) - If NumPointsMatches EQ False$ then - ErrMsg = 'Scan data point count [ ' : NumDataPoints : ' ] does not match RDS Test recipe pattern data point count for RDS [ ' : RDSKeyID : ' ] layer [ ' : CalculatedLayer : ' ] zone [ ' : CalculatedZone : ' ].' - Error_Services('Add', ErrMsg) - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) - end - - If RecipeMatches and NumPointsMatches then - GoSub LoadRunDataToDatabase - end - end else - ErrMsg = 'RDS Test scan failed for RDS [' : RDSKeyID : '] layer [' : LayerForValidation : '], because unable to get RDS_LAYER record [' : RDSLayerKeyID : ']' - Error_Services('Add', ErrMsg) - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) - end - End Case - end else - Error_Services('Add', 'Data type / Spec not found for Layer [' : RunDataLayer : '].') - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) - end - end else - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) - end - end - end else - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) - end - end else - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) - end - end - end - -end service - - -Service ImportCDEData(RunData, FileName) - - Machine = 'CDE' - ParseArray = '' - FieldPos = 23 - FieldPosIncrement = 5 - Offset = 3 - Decimals = 3 - Timestamp = RunData<3> - RDSKeyID = RunData<7> - RunDataLayer = RunData<9> - RunDataZone = RunData<10> - ReactorID = RunData<6> - ScanRecipe = RunData<5> - PSN = RunData<8> - QualFile = ( (PSN EQ 'RLOW_STD') or (PSN EQ 'RMID_STD') or (PSN EQ 'RHI_STD') or (PSN EQ 'THINSPC') ) - If QualFile then - ResourceID = Field(FileName, ' ', 1, 1) - URL = "https://oi-metrology-viewer-prod.mes.infineon.com/api/InfinityQSV3/":ResourceID:"/header" - TimeoutDuration = HTTPClient_Services('GetTimeoutDuration') - If TimeoutDuration NE 30 then Httpclient_Services('SetTimeoutDuration', 30) - Response = Httpclient_Services('SendHTTPRequest', 'GET', URL, '', '', '', '', '', '', '') - If Response NE '' then - If SRP_JSON(objJSON, 'Parse', Response) EQ '' then - SumOOS = SRP_JSON(objJSON, 'GetValue', 'Results[1].iq_sum') - ToolID = RunData<6> - TimeStamp = RunData<3> - If SumOOS NE '' then - Pass = (SumOOS EQ 0) - QualResponse = PM_Services('ProcessQual', PSN, ToolID, TimeStamp, Pass) - StatusCode = QualResponse<1> - Message = QualResponse<2> - Metrology_Services('LogResults', PSN, Machine, StatusCode, Service : ' : ' : Message) - end else - LogMessage = 'IQS response missing Results[1].iq_sum. Error message: ':SRP_JSON(objJSON, 'GetValue', 'message') - Metrology_Services('LogResults', PSN, Machine, 'UID002', Service : ' : ' : LogMessage) - end - SRP_JSON(objJSON, 'Release') - end else - Metrology_Services('LogResults', PSN, Machine, 'UID002', Service : ' : ' : 'Failed to parse IQS JSON response') - end - end else - Metrology_Services('LogResults', PSN, Machine, 'UID002', Service : ' : ' : 'Null response from IQS API.') - end - - end else - // Regular metrology file - IsViewerFile = Index(FileName, 'Viewer', 1) - ToolClassID = '4PP' - PatternNameIndex = RDS_TEST_SPEC_RES_MPATTERN$ - ToolClassIndex = RDS_TEST_SPEC_RES_MTOOL$ - DataIndex = RDS_TEST_READ_SHEET_RHO$ - DTMIndex = RDS_TEST_TEST_RUN_SHEET_RHO_DTM$ - IsProdTest = False$ - RDSNo@ = RDSKeyID - RDSRec = Database_Services('ReadDataRow', 'RDS', RDSKeyID) + RDSNo@ = RDSKeyID + RDSRec = Database_Services('ReadDataRow', 'RDS', RDSKeyID) If Error_Services('NoError') then + WorkOrderNo = RDSRec // HgCV Project Development Code ------------------------------------------------------------------------------- DevelopmentFlag = Xlate('DEVELOPMENT', 'HGCV', 'STATUS', 'X') @@ -1295,9 +964,7 @@ Service ImportCDEData(RunData, FileName) IsProdTest = ( Indexc(ScanRecipe, 'PROD', 1) GT 0 ) If IsProdTest EQ True$ then Metrology_Services('LogResults',RDSKeyID,Machine,'HgCV','Product test recognized. Recipe name: ':ScanRecipe) end - // ------------------------------------------------------------------------------------------------------------- - - WorkOrderNo = RDSRec + // ------------------------------------------------------------------------------------------------------------- CassNo = RDSRec WorkOrder = Work_Order_Services('GetWorkOrder', WorkOrderNo, False$) GoSub ParseWorkOrder @@ -1306,6 +973,12 @@ Service ImportCDEData(RunData, FileName) RunDataZone = Metrology_Services('FormatZoneKeyID', RunDataZone) ; // 1, 2 RunDataLayer = Metrology_Services('FormatLayerKeyID', RunDataLayer) ; // L1, L2, 2 + ZoneForValidation = RunDataZone + LayerForValidation = RunDataLayer + If LayerForValidation EQ '' then + LayerForValidation = 'L1' + end + CalculatedZone = Metrology_Services('GetCalculatedZone', RDSKeyID, IsEpiPro, RunDataZone) If RunDataZone NE CalculatedZone then Error_Services('Add', 'Entered Zone [' : RunDataZone : '] and calculated Zone [' : CalculatedZone : '] do not match.') @@ -1313,14 +986,14 @@ Service ImportCDEData(RunData, FileName) end Transfer CalculatedZone to RunDataZone - CalculatedLayer = Metrology_Services('GetCalculatedLayer', RDSKeyID, Machine, RunDataZone) - If RunDataLayer NE CalculatedLayer then + CalculatedLayer = Metrology_Services('GetCalculatedLayer', RDSKeyID, Machine, RunDataZone, IsEpiPro, RunDataLayer) + If (RunDataLayer NE CalculatedLayer) then Error_Services('Add', 'Entered Layer [' : RunDataLayer : '] and calculated Layer [' : CalculatedLayer : '] do not match for the Zone [' : RunDataZone : '].') Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) end Transfer CalculatedLayer to RunDataLayer - ReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactorID) + ReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactorID) If Error_Services('NoError') then ReactorType = ReactorRec If ReactorType _EQC 'EpiPro' OR ReactorType _EQC 'EPP' OR ReactorType _EQC 'P' then @@ -1342,8 +1015,8 @@ Service ImportCDEData(RunData, FileName) end If Error_Services('NoError') then - Positions = '' - DataPoints = '' + Positions = '' + DataPoints = '' Loop Position = Trim(RunData) DataPoint = Trim(RunData) @@ -1352,15 +1025,14 @@ Service ImportCDEData(RunData, FileName) DataPoints := DataPoint : @VM FieldPos += FieldPosIncrement Repeat - RawDataPoints = DataPoints Positions[-1, 1] = '' ; // Strip final @VM DataPoints[-1, 1] = '' ; // Strip final @VM + RawDataPoints = DataPoints DataPoints = Iconv(DataPoints, 'MD' : Decimals) Swap ' AM' with 'AM' in Timestamp Swap ' PM' with 'PM' in Timestamp Timestamp = IConv(Timestamp,'DT') - RDSLayerKeyID = RDSKeyID : '*' : RunDataLayer NumDataPoints = DCount(DataPoints, @VM) RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID) @@ -1390,75 +1062,177 @@ Service ImportCDEData(RunData, FileName) If Not(Found) AND Not(IsEpiPro) then Found = True$ If (Found EQ True$) then - If (IsProdTest EQ True$) then - // QA Metrology test (i.e. not RDS Metrology test) - Convert @VM to @FM in RawDataPoints - Min = RawDataPoints<1> - Max = RawDataPoints<1> - For each DataPoint in RawDataPoints using @FM Setting DataPos - Min = Min(Min, DataPoint) - Max = Max(Max, DataPoint) - Next DataPoint - Average = Sum(RawDataPoints) / NumDataPoints - Average = Iconv(Average, 'MD3') - Average = Oconv(Average, 'MD3') - WOMatQAID = WorkOrderNo : '*' : CassNo - WOMatQARec = Database_Services('ReadDataRow', 'WO_MAT_QA', WOMatQAID) - SpecRecipes = WOMatQARec - WOStepNo = RDSRec[-1, 'B*'] - ProfStep = '' - ProfSteps = '' - ProfileCnt = DCount(WOMatQARec, @VM) - For vPos = 1 to ProfileCnt - ProfSteps<1, vPos> = WOMatQARec : '*' : WOMatQARec - Next vPos - LastProfSig = WOMatQARec - SigProfKeys = '1LW_RHO' - SigCnt = DCount(SigProfKeys, @VM) - Stages = 'UNLOAD' - SigProfFound = False$ - UnloadSigned = Signature_Services('GetStageSummary', WOMatQAID, 'UNLOAD')<2> - For Each SigProfKey in SigProfKeys using @VM setting vPos - Stage = Stages<1, vPos> - if (Stage EQ 'UNLOAD' AND UnloadSigned EQ True$) OR Stage NE 'UNLOAD' then + // Check if QA Metrology run or conventional RDS Metrology run. + // Recipe name match requirement has been turned off per Tom Tillery. djs 10/03/18 + Begin Case + Case IsProdTest + // WO_MAT_QA THICK_ONLY test -> import and send to SPC + LogPath = Environment_Services('GetSpcFilesharePath') + LogPath2 = Environment_Services('GetApplicationRootPath') : '\Metrology' + SendToSPC = False$ + Begin Case + Case NumDataPoints EQ 5 + // Create 5 point SPC file + objSPC = Logging_Services('NewLog', LogPath, OConv(Datetime(), 'DT_^1_HS_'):'_Thickness_5Points.txt', CRLF$, Comma$, '', '', False$, True$) + NotesLog = Logging_Services('NewLog', LogPath2, 'Thickness_5Points.txt', CRLF$, Comma$, '', '', False$, False$) + SendToSPC = True$ + Case NumDataPoints EQ 9 + // Create 9 point SPC file + objSPC = Logging_Services('NewLog', LogPath, OConv(Datetime(), 'DT_^1_HS_'):'_Thickness_9Points.txt', CRLF$, Comma$, '', '', False$, True$) + NotesLog = Logging_Services('NewLog', LogPath2, 'Thickness_9Points.txt', CRLF$, Comma$, '', '', False$, False$) + SendToSPC = True$ + Case NumDataPoints EQ 10 + objSPC = Logging_Services('NewLog', LogPath, OConv(Datetime(), 'DT_^1_HS_'):'_Thickness_10Points.txt', CRLF$, Comma$, '', '', False$, True$) + NotesLog = Logging_Services('NewLog', LogPath2, 'Thickness_10Points.txt', CRLF$, Comma$, '', '', False$, False$) + SendToSPC = True$ + Case NumDataPoints EQ 14 + objSPC = Logging_Services('NewLog', LogPath, OConv(Datetime(), 'DT_^1_HS_'):'_Thickness_14Points.txt', CRLF$, Comma$, '', '', False$, True$) + NotesLog = Logging_Services('NewLog', LogPath2, 'Thickness_14Points.txt', CRLF$, Comma$, '', '', False$, False$) + SendToSPC = True$ + Case Otherwise$ + // Log this as it is unexpected + NotesLog = Logging_Services('NewLog', LogPath2, 'Thickness_Points_Error.txt', CRLF$, Comma$, '', '', False$, False$) + End Case + + LogData = '' + LogData<1> = Oconv(Timestamp, 'DT/^HS') ; // Metrology date/time stamp + LogData<2> = ReactorID ; // Reactor + LogData<3> = RDSKeyID ; // RDS No + LogData<4> = RunData<7> ; // PSN + // Log data positions 5 through 10, 14, or 18 will be populated with data point measurements. + Convert @VM to @FM in RawDataPoints + Min = RawDataPoints<1> + Max = RawDataPoints<1> + For each DataPoint in RawDataPoints using @FM Setting DataPos + Min = Min(Min, DataPoint) + Max = Max(Max, DataPoint) + LogData = DataPoint + Next DataPoint + LogData := @RM : ' ' + If SendToSPC then Logging_Services('AppendLog', objSPC, LogData, @RM, @FM, True$) + Logging_Services('AppendLog', NotesLog, LogData, @RM, @FM, True$) + Average = Sum(RawDataPoints) / NumDataPoints + Average = Iconv(Average, 'MD3') + Average = Oconv(Average, 'MD3') + WOMatKey = Xlate('RDS', RDSKeyID, 'WO_MAT_KEY', 'X') + WOMatQAID = WorkOrderNo : '*' : CassNo + WOMatQARec = Database_Services('ReadDataRow', 'WO_MAT_QA', WOMatQAID) + SpecRecipes = WOMatQARec + + WOStepNo = RDSRec[-1, 'B*'] + ProfSteps = '' + ProfileCnt = DCount(WOMatQARec, @VM) + For vPos = 1 to ProfileCnt + ProfSteps<1, vPos> = WOMatQARec : '*' : WOMatQARec + Next vPos + LastProfSig = WOMatQARec + SigProfKeys = 'THICK_ONLY' + SigCnt = DCount(SigProfKeys, @VM) + Stages = 'UNLOAD' + SigProfFound = False$ + For Each SigProfKey in SigProfKeys using @VM setting vPos + Stage = Stages<1, vPos> If Num(SigProfKey[1, 1]) else SigProfKey = WOStepNo : SigProfKey end ProfStep = SigProfKey : '*' : Stage Locate ProfStep in ProfSteps using @VM setting Pos then - SigProfFound = True$ - IF IsViewerFile OR WOMatQARec = '' then - WOMatQARec = Average - WOMatQARec = Oconv(Iconv(Min, 'MD3'), 'MD3') - WOMatQARec = Oconv(Iconv(Max, 'MD3'), 'MD3') - SpecMin = WOMatQARec - SpecMax = WOMatQARec - For each DataPoint in RawDataPoints using @FM setting SubValuePos - FormatedData = Oconv(Iconv(DataPoint, 'MD3'), 'MD3') - If ( ( FormatedData LT SpecMin ) OR ( FormatedData GT SpecMax ) and (SubValuePos LT 10) ) then - WOMatQARec = True$ + SigProfFound = True$ + UnloadSigned = Signature_Services('GetStageSummary', WoMatKey, 'UNLOAD')<2> + IF (Stage EQ 'UNLOAD' AND UnloadSigned EQ True$) OR Stage NE 'UNLOAD' then + // verify recipe is correct + WoMatQaRecipe = WOMatQARec + WoMatQaRecipeMatchesScanRecipe = ScanRecipe _EQC WoMatQaRecipe + If WoMatQaRecipeMatchesScanRecipe EQ False$ then + ErrMsg = 'Scan recipe [ ' : ScanRecipe : ' ] does not match WoMatQa recipe [ ' : WoMatQaRecipe : ' ] for RDS [ ' : RDSKeyID : ' ] layer [ ' : CalculatedLayer : ' ].' + Error_Services('Add', ErrMsg) + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + + // verify number of points is correct + WoMatQaToolClass = WOMatQARec + WoMatQaRecipePattern = WOMatQARec + NumDataPointsInSpec = Tool_Class_Services('GetNumberOfPointsForPattern', WoMatQaToolClass, WoMatQaRecipePattern) + WoMatQaRecipePatternNumPointsMatchesScanNumDataPoints = NumDataPointsInSpec EQ NumDataPoints + + If WoMatQaRecipePatternNumPointsMatchesScanNumDataPoints EQ False$ then + ErrMsg = 'Scan data point count [ ' : NumDataPoints : ' ] does not match WoMatQa recipe pattern data point count [ ' : NumDataPointsInSpec : ' ] for RDS [ ' : RDSKeyID : ' ] layer [ ' : CalculatedLayer : ' ].' + Error_Services('Add', ErrMsg) + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + + If (WOMatQARec EQ '' OR IsViewerFile) then + If WoMatQaRecipeMatchesScanRecipe and WoMatQaRecipePatternNumPointsMatchesScanNumDataPoints then + WOMatQARec = Average + WOMatQARec = Oconv(Iconv(Min, 'MD3'), 'MD3') + WOMatQARec = Oconv(Iconv(Max, 'MD3'), 'MD3') + SpecMin = WOMatQARec + SpecMax = WOMatQARec + For each DataPoint in RawDataPoints using @FM setting SubValuePos + FormatedData = Oconv(Iconv(DataPoint, 'MD3'), 'MD3') + If NumDataPoints LT 14 then + If ( ( FormatedData LT SpecMin ) OR ( FormatedData GT SpecMax ) and (SubValuePos LT 10) ) then + WOMatQARec = True$ + end + end else + If ( FormatedData LT SpecMin ) OR ( FormatedData GT SpecMax ) then + WOMatQARec = True$ + end + end + WOMatQARec = FormatedData + Next DataPoint + WOMatQARec = '' + WOMatQARec = '' + Database_Services('WriteDataRow', 'WO_MAT_QA', WOMatQAID, WOMatQARec, True$, False$, True$) end - WOMatQARec = FormatedData - Next DataPoint - Database_Services('WriteDataRow', 'WO_MAT_QA', WOMatQAID, WOMatQARec, True$, False$, True$) + end else + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : UID001 - Data for this metrology test already exists and is not from the metrology viewer.') + end end else - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : UID001 - Data for this metrology test already exists and is not from the metrology viewer.') + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : UID001 - Unload signature must first be signed for this data to be uploaded.') end end + Until SigProfFound + Next SigProfKey + If SigProfFound EQ True$ then + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID000', Service : ' : Sig Prof. Found') end else - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : UID001 - Unload signature must first be signed for this data to be uploaded.') + Error_Services('Add', 'Unable to locate the signature profile [' : ProfStep : '].') + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) end - Until SigProfFound - Next SigProfKey - If SigProfFound EQ True$ then - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID000', Service : ' : Success.') - end else - Error_Services('Add', 'Unable to locate the signature profile [' : ProfStep : '].') - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) - end - end else - GoSub LoadRunDataToDatabase - end + Case Otherwise$ + // If not an above case, then the run is a conventional THICK_ONLY RDS metrology test. + + RDSLayerKeyID = RDSKeyID : '*' : LayerForValidation + RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID) + If Error_Services('NoError') then + RDSTestKeyIDs = RDSLayerRec + + // Verify the scan recipe matches the spec recipe + RecipeMatches = Metrology_Services('ScanRecipeMatchesRdsTestSpecThickMrecipe', RDSKeyID, LayerForValidation, ScanRecipe, RDSTestKeyIDs, ZoneForValidation) + If RecipeMatches EQ False$ then + ErrMsg = 'Scan recipe [ ' : ScanRecipe : ' ] does not match RDS Test recipe for RDS [ ' : RDSKeyID : ' ] layer [ ' : CalculatedLayer : ' ] zone [ ' : CalculatedZone : ' ].' + Error_Services('Add', ErrMsg) + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + + // Verfiy the scan number of points matches the spec number of points + NumPointsMatches = Metrology_Services('ScanNumDataPointsMatchesRdsTestSpecThickMPattern', RDSKeyID, LayerForValidation, NumDataPoints, RDSTestKeyIDs, 'FTIR', ZoneForValidation) + If NumPointsMatches EQ False$ then + ErrMsg = 'Scan data point count [ ' : NumDataPoints : ' ] does not match RDS Test recipe pattern data point count for RDS [ ' : RDSKeyID : ' ] layer [ ' : CalculatedLayer : ' ] zone [ ' : CalculatedZone : ' ].' + Error_Services('Add', ErrMsg) + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + + If RecipeMatches and NumPointsMatches then + GoSub LoadRunDataToDatabase + end + end else + ErrMsg = 'RDS Test scan failed for RDS [' : RDSKeyID : '] layer [' : LayerForValidation : '], because unable to get RDS_LAYER record [' : RDSLayerKeyID : ']' + Error_Services('Add', ErrMsg) + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + End Case end else Error_Services('Add', 'Data type / Spec not found for Layer [' : RunDataLayer : '].') Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) @@ -1478,7 +1252,287 @@ Service ImportCDEData(RunData, FileName) end service -Service ImportHgCVData(RunData, FileName) +Service ImportCDEQualData(RunData, ResourceID, PSN) + + Machine = 'CDE' + ResourceID = Field(FileName, ' ', 1, 1) + URL = "https://oi-metrology-viewer-prod.mes.infineon.com/api/InfinityQSV3/":ResourceID:"/header" + TimeoutDuration = HTTPClient_Services('GetTimeoutDuration') + If TimeoutDuration NE 30 then Httpclient_Services('SetTimeoutDuration', 30) + Response = Httpclient_Services('SendHTTPRequest', 'GET', URL, '', '', '', '', '', '', '') + If Response NE '' then + If SRP_JSON(objJSON, 'Parse', Response) EQ '' then + SumOOS = SRP_JSON(objJSON, 'GetValue', 'Results[1].iq_sum') + ToolID = RunData<6> + TimeStamp = RunData<3> + If SumOOS NE '' then + Pass = (SumOOS EQ 0) + QualResponse = PM_Services('ProcessQual', PSN, ToolID, TimeStamp, Pass) + StatusCode = QualResponse<1> + Message = QualResponse<2> + Metrology_Services('LogResults', PSN, Machine, StatusCode, Service : ' : ' : Message) + end else + LogMessage = 'IQS response missing Results[1].iq_sum. Error message: ':SRP_JSON(objJSON, 'GetValue', 'message') + Metrology_Services('LogResults', PSN, Machine, 'UID002', Service : ' : ' : LogMessage) + end + SRP_JSON(objJSON, 'Release') + end else + Metrology_Services('LogResults', PSN, Machine, 'UID002', Service : ' : ' : 'Failed to parse IQS JSON response') + end + end else + Metrology_Services('LogResults', PSN, Machine, 'UID002', Service : ' : ' : 'Null response from IQS API.') + end + +end service + + +Service ImportCDEData(RunData, ResourceID, IsViewerFile, PSN) + + Machine = 'CDE' + ParseArray = '' + FieldPos = 23 + FieldPosIncrement = 5 + Offset = 3 + Decimals = 3 + Timestamp = RunData<3> + RDSKeyID = RunData<7> + RunDataLayer = RunData<9> + RunDataZone = RunData<10> + ReactorID = RunData<6> + ScanRecipe = RunData<5> + // Regular metrology file + ToolClassID = '4PP' + PatternNameIndex = RDS_TEST_SPEC_RES_MPATTERN$ + ToolClassIndex = RDS_TEST_SPEC_RES_MTOOL$ + DataIndex = RDS_TEST_READ_SHEET_RHO$ + DTMIndex = RDS_TEST_TEST_RUN_SHEET_RHO_DTM$ + IsProdTest = False$ + RDSNo@ = RDSKeyID + RDSRec = Database_Services('ReadDataRow', 'RDS', RDSKeyID) + If Error_Services('NoError') then + + // HgCV Project Development Code ------------------------------------------------------------------------------- + DevelopmentFlag = Xlate('DEVELOPMENT', 'HGCV', 'STATUS', 'X') + If (DevelopmentFlag EQ True$) then + IsProdTest = ( Indexc(ScanRecipe, 'PROD', 1) GT 0 ) + If IsProdTest EQ True$ then Metrology_Services('LogResults',RDSKeyID,Machine,'HgCV','Product test recognized. Recipe name: ':ScanRecipe) + end + // ------------------------------------------------------------------------------------------------------------- + + WorkOrderNo = RDSRec + CassNo = RDSRec + WorkOrder = Work_Order_Services('GetWorkOrder', WorkOrderNo, False$) + GoSub ParseWorkOrder + IsEpiPro = (WOReactorType _EQC 'EpiPro') OR (WOReactorType _EQC 'EPP') + + RunDataZone = Metrology_Services('FormatZoneKeyID', RunDataZone) ; // 1, 2 + RunDataLayer = Metrology_Services('FormatLayerKeyID', RunDataLayer) ; // L1, L2, 2 + + CalculatedZone = Metrology_Services('GetCalculatedZone', RDSKeyID, IsEpiPro, RunDataZone) + If RunDataZone NE CalculatedZone then + Error_Services('Add', 'Entered Zone [' : RunDataZone : '] and calculated Zone [' : CalculatedZone : '] do not match.') + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + Transfer CalculatedZone to RunDataZone + + CalculatedLayer = Metrology_Services('GetCalculatedLayer', RDSKeyID, Machine, RunDataZone) + If RunDataLayer NE CalculatedLayer then + Error_Services('Add', 'Entered Layer [' : RunDataLayer : '] and calculated Layer [' : CalculatedLayer : '] do not match for the Zone [' : RunDataZone : '].') + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + Transfer CalculatedLayer to RunDataLayer + + ReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactorID) + If Error_Services('NoError') then + ReactorType = ReactorRec + If ReactorType _EQC 'EpiPro' OR ReactorType _EQC 'EPP' OR ReactorType _EQC 'P' then + TestPointMapping = True$ + If RunDataLayer EQ '' OR RunDataZone EQ '' then + Message = 'Layer and Zone are required for EpiPro.' + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Message) + Error_Services('Add', Message) + end + end else + TestPointMapping = False$ + If RunDataLayer NE '' then + RunDataZone = '' + end else + Message = 'Layer is required for non-EpiPro.' + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Message) + Error_Services('Add', Message) + end + end + + If Error_Services('NoError') then + Positions = '' + DataPoints = '' + Loop + Position = Trim(RunData) + DataPoint = Trim(RunData) + Until Position EQ '' + Positions := Position : @VM + DataPoints := DataPoint : @VM + FieldPos += FieldPosIncrement + Repeat + RawDataPoints = DataPoints + Positions[-1, 1] = '' ; // Strip final @VM + DataPoints[-1, 1] = '' ; // Strip final @VM + DataPoints = Iconv(DataPoints, 'MD' : Decimals) + + Swap ' AM' with 'AM' in Timestamp + Swap ' PM' with 'PM' in Timestamp + Timestamp = IConv(Timestamp,'DT') + + RDSLayerKeyID = RDSKeyID : '*' : RunDataLayer + NumDataPoints = DCount(DataPoints, @VM) + RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID) + If Error_Services('NoError') then + RDSTestKeyIDs = RDSLayerRec + Found = False$ + If RDSTestKeyIDs NE '' then + For Each RDSTestKeyID in RDSTestKeyIDs using @VM setting mkPos + RDSTestRec = Database_Services('ReadDataRow', 'RDS_TEST', RDSTestKeyID) + If Error_Services('NoError') then + RDSTestZoneID = RDSTestRec + // First test - Look for a Zone ID match. + If (RDSTestZoneID EQ RunDataZone) then + // A match has been found. No need to continue searching. + Found = True$ + end + end + Until Found + Next RDSTestKeyID + end else + Error_Services('Add', 'Unable to obtain a valid Metrology Test Key ID.') + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + + // If not found this is because there was no zone. However, if this is not EpiPro, this is still a valid + // test so set the found flag to true. + If Not(Found) AND Not(IsEpiPro) then Found = True$ + + If (Found EQ True$) then + If (IsProdTest EQ True$) then + // QA Metrology test (i.e. not RDS Metrology test) + Convert @VM to @FM in RawDataPoints + Min = RawDataPoints<1> + Max = RawDataPoints<1> + For each DataPoint in RawDataPoints using @FM Setting DataPos + Min = Min(Min, DataPoint) + Max = Max(Max, DataPoint) + Next DataPoint + Average = Sum(RawDataPoints) / NumDataPoints + Average = Iconv(Average, 'MD3') + Average = Oconv(Average, 'MD3') + WOMatQAID = WorkOrderNo : '*' : CassNo + WOMatQARec = Database_Services('ReadDataRow', 'WO_MAT_QA', WOMatQAID) + SpecRecipes = WOMatQARec + WOStepNo = RDSRec[-1, 'B*'] + ProfStep = '' + ProfSteps = '' + ProfileCnt = DCount(WOMatQARec, @VM) + For vPos = 1 to ProfileCnt + ProfSteps<1, vPos> = WOMatQARec : '*' : WOMatQARec + Next vPos + LastProfSig = WOMatQARec + SigProfKeys = '1LW_RHO' + SigCnt = DCount(SigProfKeys, @VM) + Stages = 'UNLOAD' + SigProfFound = False$ + UnloadSigned = Signature_Services('GetStageSummary', WOMatQAID, 'UNLOAD')<2> + For Each SigProfKey in SigProfKeys using @VM setting vPos + Stage = Stages<1, vPos> + if (Stage EQ 'UNLOAD' AND UnloadSigned EQ True$) OR Stage NE 'UNLOAD' then + If Num(SigProfKey[1, 1]) else + SigProfKey = WOStepNo : SigProfKey + end + ProfStep = SigProfKey : '*' : Stage + Locate ProfStep in ProfSteps using @VM setting Pos then + SigProfFound = True$ + IF IsViewerFile OR WOMatQARec = '' then + WOMatQARec = Average + WOMatQARec = Oconv(Iconv(Min, 'MD3'), 'MD3') + WOMatQARec = Oconv(Iconv(Max, 'MD3'), 'MD3') + SpecMin = WOMatQARec + SpecMax = WOMatQARec + For each DataPoint in RawDataPoints using @FM setting SubValuePos + FormatedData = Oconv(Iconv(DataPoint, 'MD3'), 'MD3') + If ( ( FormatedData LT SpecMin ) OR ( FormatedData GT SpecMax ) and (SubValuePos LT 10) ) then + WOMatQARec = True$ + end + WOMatQARec = FormatedData + Next DataPoint + Database_Services('WriteDataRow', 'WO_MAT_QA', WOMatQAID, WOMatQARec, True$, False$, True$) + end else + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : UID001 - Data for this metrology test already exists and is not from the metrology viewer.') + end + end + end else + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : UID001 - Unload signature must first be signed for this data to be uploaded.') + end + Until SigProfFound + Next SigProfKey + If SigProfFound EQ True$ then + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID000', Service : ' : Success.') + end else + Error_Services('Add', 'Unable to locate the signature profile [' : ProfStep : '].') + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + GoSub LoadRunDataToDatabase + end + end else + Error_Services('Add', 'Data type / Spec not found for Layer [' : RunDataLayer : '].') + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end + end else + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + +end service + + +Service ImportHgCVQualData(RunData, ResourceID, PSN) + + Machine = 'HgCV' /* Resistivity */ + URL = "https://oi-metrology-viewer-prod.mes.infineon.com/api/InfinityQSV3/":ResourceID:"/header" + TimeoutDuration = HTTPClient_Services('GetTimeoutDuration') + If TimeoutDuration NE 30 then Httpclient_Services('SetTimeoutDuration', 30) + Response = Httpclient_Services('SendHTTPRequest', 'GET', URL, '', '', '', '', '', '', '') + If Response NE '' then + If SRP_JSON(objJSON, 'Parse', Response) EQ '' then + SumOOS = SRP_JSON(objJSON, 'GetValue', 'Results[1].iq_sum') + ToolID = RunData<2> + TimeStamp = RunData<11> + If SumOOS NE '' then + Pass = (SumOOS EQ 0) + QualResponse = PM_Services('ProcessQual', PSN, ToolID, TimeStamp, Pass) + StatusCode = QualResponse<1> + Message = QualResponse<2> + Metrology_Services('LogResults', PSN, Machine, StatusCode, Service : ' : ' : Message) + end else + LogMessage = 'IQS response missing Results[1].iq_sum. Error message: ':SRP_JSON(objJSON, 'GetValue', 'message') + Metrology_Services('LogResults', PSN, Machine, 'UID002', Service : ' : ' : LogMessage) + end + SRP_JSON(objJSON, 'Release') + end else + Metrology_Services('LogResults', PSN, Machine, 'UID002', Service : ' : ' : 'Failed to parse IQS JSON response') + end + end else + Metrology_Services('LogResults', PSN, Machine, 'UID002', Service : ' : ' : 'Null response from IQS API.') + end + +end service + + +Service ImportHgCVData(RunData, ResourceID, IsViewerFile, PSN) Machine = 'HgCV' /* Resistivity */ FieldPos = 53 @@ -1490,332 +1544,299 @@ Service ImportHgCVData(RunData, FileName) RDSKeyID = RunData<4> LayerZonePair = RunData<8> ReactorID = RunData<3> - PSN = RunData<5> - QualFile = ( (PSN EQ 'Low') or (PSN EQ 'Mid') or (PSN EQ 'High') or (PSN EQ 'Thin') ) - If QualFile then - ResourceID = Field(FileName, ' ', 1, 1) - URL = "https://oi-metrology-viewer-prod.mes.infineon.com/api/InfinityQSV3/":ResourceID:"/header" - TimeoutDuration = HTTPClient_Services('GetTimeoutDuration') - If TimeoutDuration NE 30 then Httpclient_Services('SetTimeoutDuration', 30) - Response = Httpclient_Services('SendHTTPRequest', 'GET', URL, '', '', '', '', '', '', '') - If Response NE '' then - If SRP_JSON(objJSON, 'Parse', Response) EQ '' then - SumOOS = SRP_JSON(objJSON, 'GetValue', 'Results[1].iq_sum') - ToolID = RunData<2> - TimeStamp = RunData<11> - If SumOOS NE '' then - Pass = (SumOOS EQ 0) - QualResponse = PM_Services('ProcessQual', PSN, ToolID, TimeStamp, Pass) - StatusCode = QualResponse<1> - Message = QualResponse<2> - Metrology_Services('LogResults', PSN, Machine, StatusCode, Service : ' : ' : Message) - end else - LogMessage = 'IQS response missing Results[1].iq_sum. Error message: ':SRP_JSON(objJSON, 'GetValue', 'message') - Metrology_Services('LogResults', PSN, Machine, 'UID002', Service : ' : ' : LogMessage) - end - SRP_JSON(objJSON, 'Release') - end else - Metrology_Services('LogResults', PSN, Machine, 'UID002', Service : ' : ' : 'Failed to parse IQS JSON response') - end - end else - Metrology_Services('LogResults', PSN, Machine, 'UID002', Service : ' : ' : 'Null response from IQS API.') - end - end else - // Regular metrology file - IsViewerFile = Index(FileName, 'Viewer', 1) - ToolClassID = 'HGCV' - PatternNameIndex = RDS_TEST_SPEC_RES_MPATTERN$ - ToolClassIndex = RDS_TEST_SPEC_RES_MTOOL$ - DataIndex = RDS_TEST_READ_HGCV1_RES$ - DTMIndex = RDS_TEST_TEST_RUN_HGCV_DTM$ - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID000', Service : ' : ' : 'Beginning ImportHgCVData') - RDSNo@ = RDSKeyID - RDSRec = Database_Services('ReadDataRow', 'RDS', RDSKeyID) + // Regular metrology file + ToolClassID = 'HGCV' + PatternNameIndex = RDS_TEST_SPEC_RES_MPATTERN$ + ToolClassIndex = RDS_TEST_SPEC_RES_MTOOL$ + DataIndex = RDS_TEST_READ_HGCV1_RES$ + DTMIndex = RDS_TEST_TEST_RUN_HGCV_DTM$ + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID000', Service : ' : ' : 'Beginning ImportHgCVData') + RDSNo@ = RDSKeyID + RDSRec = Database_Services('ReadDataRow', 'RDS', RDSKeyID) + If Error_Services('NoError') then + WorkOrderNo = RDSRec + CassNo = RDSRec + WorkOrder = Work_Order_Services('GetWorkOrder', WorkOrderNo, False$) + GoSub ParseWorkOrder + IsEpiPro = (WOReactorType _EQC 'EpiPro') OR (WOReactorType _EQC 'EPP') + + Convert @Lower_Case to @Upper_Case in LayerZonePair + Convert 'Z' to '-' in LayerZonePair + Swap '--' with '-' in LayerZonePair + RunDataLayer = Field(LayerZonePair, '-', 1) + RunDataZone = Field(LayerZonePair, '-', 2) + RunDataZone = Metrology_Services('FormatZoneKeyID', RunDataZone) ; // 1, 2 + RunDataLayer = Metrology_Services('FormatLayerKeyID', RunDataLayer) ; // L1, L2, 2 + + CalculatedZone = Metrology_Services('GetCalculatedZone', RDSKeyID, IsEpiPro, RunDataZone) + If RunDataZone NE CalculatedZone then + Error_Services('Add', 'Entered Zone [' : RunDataZone : '] and calculated Zone [' : CalculatedZone : '] do not match.') + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + Transfer CalculatedZone to RunDataZone + + CalculatedLayer = Metrology_Services('GetCalculatedLayer', RDSKeyID, Machine, RunDataZone) + If RunDataLayer NE CalculatedLayer then + Error_Services('Add', 'Entered Layer [' : RunDataLayer : '] and calculated Layer [' : CalculatedLayer : '] do not match for the Zone [' : RunDataZone : '].') + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + Transfer CalculatedLayer to RunDataLayer + + ReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactorID) If Error_Services('NoError') then - WorkOrderNo = RDSRec - CassNo = RDSRec - WorkOrder = Work_Order_Services('GetWorkOrder', WorkOrderNo, False$) - GoSub ParseWorkOrder - IsEpiPro = (WOReactorType _EQC 'EpiPro') OR (WOReactorType _EQC 'EPP') - - Convert @Lower_Case to @Upper_Case in LayerZonePair - Convert 'Z' to '-' in LayerZonePair - Swap '--' with '-' in LayerZonePair - RunDataLayer = Field(LayerZonePair, '-', 1) - RunDataZone = Field(LayerZonePair, '-', 2) - RunDataZone = Metrology_Services('FormatZoneKeyID', RunDataZone) ; // 1, 2 - RunDataLayer = Metrology_Services('FormatLayerKeyID', RunDataLayer) ; // L1, L2, 2 - - CalculatedZone = Metrology_Services('GetCalculatedZone', RDSKeyID, IsEpiPro, RunDataZone) - If RunDataZone NE CalculatedZone then - Error_Services('Add', 'Entered Zone [' : RunDataZone : '] and calculated Zone [' : CalculatedZone : '] do not match.') - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) - end - Transfer CalculatedZone to RunDataZone - - CalculatedLayer = Metrology_Services('GetCalculatedLayer', RDSKeyID, Machine, RunDataZone) - If RunDataLayer NE CalculatedLayer then - Error_Services('Add', 'Entered Layer [' : RunDataLayer : '] and calculated Layer [' : CalculatedLayer : '] do not match for the Zone [' : RunDataZone : '].') - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) - end - Transfer CalculatedLayer to RunDataLayer - - ReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactorID) - If Error_Services('NoError') then - ReactorType = ReactorRec - If ReactorType _EQC 'EpiPro' OR ReactorType _EQC 'EPP' OR ReactorType _EQC 'P' then - TestPointMapping = True$ - If RunDataLayer EQ '' OR RunDataZone EQ '' then - Message = 'Layer and Zone are required for EpiPro.' - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Message) - Error_Services('Add', Message) - end + ReactorType = ReactorRec + If ReactorType _EQC 'EpiPro' OR ReactorType _EQC 'EPP' OR ReactorType _EQC 'P' then + TestPointMapping = True$ + If RunDataLayer EQ '' OR RunDataZone EQ '' then + Message = 'Layer and Zone are required for EpiPro.' + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Message) + Error_Services('Add', Message) + end + end else + TestPointMapping = False$ + If RunDataLayer NE '' then + RunDataZone = '' end else - TestPointMapping = False$ - If RunDataLayer NE '' then - RunDataZone = '' - end else - Message = 'Layer is required for non-EpiPro.' - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Message) - Error_Services('Add', Message) - end - end + Message = 'Layer is required for non-EpiPro.' + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Message) + Error_Services('Add', Message) + end + end + If Error_Services('NoError') then + Position = '' + Positions = '' + DataPoints = '' + HgCVDataPoints = '' + Loop + Position = Trim(RunData) + HgCVDataPoint = Trim(RunData) + Until Position EQ '' + Positions := Position : @VM + HgCVDataPoints := HgCVDataPoint : @VM + FieldPos += FieldPosIncrement + Repeat + Positions[-1, 1] = '' ; // Strip final @VM + HgCVDataPoints[-1, 1] = '' ; // Strip final @VM + + HgCVDataPoints = Iconv(HgCVDataPoints, 'MD' : Decimals) + + Swap ' AM' with 'AM' in Timestamp + Swap ' PM' with 'PM' in Timestamp + Timestamp = IConv(Timestamp,'DT') + + RDSLayerKeyID = RDSKeyID : '*' : RunDataLayer + NumDataPoints = DCount(HgCVDataPoints, @VM) + RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID) If Error_Services('NoError') then - Position = '' - Positions = '' - DataPoints = '' - HgCVDataPoints = '' - Loop - Position = Trim(RunData) - HgCVDataPoint = Trim(RunData) - Until Position EQ '' - Positions := Position : @VM - HgCVDataPoints := HgCVDataPoint : @VM - FieldPos += FieldPosIncrement - Repeat - Positions[-1, 1] = '' ; // Strip final @VM - HgCVDataPoints[-1, 1] = '' ; // Strip final @VM - - HgCVDataPoints = Iconv(HgCVDataPoints, 'MD' : Decimals) - - Swap ' AM' with 'AM' in Timestamp - Swap ' PM' with 'PM' in Timestamp - Timestamp = IConv(Timestamp,'DT') - - RDSLayerKeyID = RDSKeyID : '*' : RunDataLayer - NumDataPoints = DCount(HgCVDataPoints, @VM) - RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID) - If Error_Services('NoError') then - RDSTestKeyIDs = RDSLayerRec - Found = False$ - If RDSTestKeyIDs NE '' then - For Each RDSTestKeyID in RDSTestKeyIDs using @VM setting mkPos - RDSTestRec = Database_Services('ReadDataRow', 'RDS_TEST', RDSTestKeyID) - If Error_Services('NoError') then - RDSTestZoneID = RDSTestRec - // Determine if this is Hg Concentration Resistivity. - IsHgCvCRes = RDSTestRec _EQC 'HGCV' - // First test - Look for a Zone ID match. - If (RDSTestZoneID EQ RunDataZone) then - // A match has been found. No need to continue searching. - Found = True$ - end + RDSTestKeyIDs = RDSLayerRec + Found = False$ + If RDSTestKeyIDs NE '' then + For Each RDSTestKeyID in RDSTestKeyIDs using @VM setting mkPos + RDSTestRec = Database_Services('ReadDataRow', 'RDS_TEST', RDSTestKeyID) + If Error_Services('NoError') then + RDSTestZoneID = RDSTestRec + // Determine if this is Hg Concentration Resistivity. + IsHgCvCRes = RDSTestRec _EQC 'HGCV' + // First test - Look for a Zone ID match. + If (RDSTestZoneID EQ RunDataZone) then + // A match has been found. No need to continue searching. + Found = True$ end - Until Found - Next RDSTestKeyID - If (Found EQ True$) then - // Only continue checking if there are data points. Otherwise, there is no data by which - // the code can calculate values to store. - If NumDataPoints GT 0 then - // Second test - If HgCv Res, dig deeper to see if this is a possible CRES entry.. - If IsHgCvCRes then - WOMatQAID = WorkOrderNo : '*' : CassNo - WOMatQARec = Database_Services('ReadDataRow', 'WO_MAT_QA', WOMatQAID) - If Error_Services('NoError') then - Locate 'CRES' in WOMatQARec using @VM setting vPos then - Stage = WOMatQARec - RequireUnload = False$ - IF (WOMatQARec EQ '' OR IsViewerFile) then - PhaseDataPoints = '' - Positions = '' - Position = '' - FieldPos = 53 - Loop - Position = Trim(RunData) - PhaseDataPoint = Trim(RunData) - Until Position EQ '' - Positions := Position : @VM - PhaseDataPoints := PhaseDataPoint : @VM - FieldPos += FieldPosIncrement - Repeat - Positions[-1, 1] = '' ; // Strip final @VM - PhaseDataPoints[-1, 1] = '' ; // Strip final @VM - PhaseDataPoints = Iconv(PhaseDataPoints, 'MD' : Decimals) - DataPoints = HgCVDataPoints - * GoSub CalculateQAData - Response = QA_Services('CalculateHgCVData', Datapoints) - HgCVMin = Response<0, 2> - HgCVMax = Response<0, 3> - HgCVAvg = Response<0, 1> - HgCVEdgeMean = Response<0, 4> - HgCVRangePct = Response<0, 5> - EdgeMean4mm = Response<0, 6> - Avg9Point = Response<0, 7> - EdgeMean10mm = Response<0, 8> - ResStdDev = Response<0, 9> + end + Until Found + Next RDSTestKeyID + If (Found EQ True$) then + // Only continue checking if there are data points. Otherwise, there is no data by which + // the code can calculate values to store. + If NumDataPoints GT 0 then + // Second test - If HgCv Res, dig deeper to see if this is a possible CRES entry.. + If IsHgCvCRes then + WOMatQAID = WorkOrderNo : '*' : CassNo + WOMatQARec = Database_Services('ReadDataRow', 'WO_MAT_QA', WOMatQAID) + If Error_Services('NoError') then + Locate 'CRES' in WOMatQARec using @VM setting vPos then + Stage = WOMatQARec + RequireUnload = False$ + IF (WOMatQARec EQ '' OR IsViewerFile) then + PhaseDataPoints = '' + Positions = '' + Position = '' + FieldPos = 53 + Loop + Position = Trim(RunData) + PhaseDataPoint = Trim(RunData) + Until Position EQ '' + Positions := Position : @VM + PhaseDataPoints := PhaseDataPoint : @VM + FieldPos += FieldPosIncrement + Repeat + Positions[-1, 1] = '' ; // Strip final @VM + PhaseDataPoints[-1, 1] = '' ; // Strip final @VM + PhaseDataPoints = Iconv(PhaseDataPoints, 'MD' : Decimals) + DataPoints = HgCVDataPoints + * GoSub CalculateQAData + Response = QA_Services('CalculateHgCVData', Datapoints) + HgCVMin = Response<0, 2> + HgCVMax = Response<0, 3> + HgCVAvg = Response<0, 1> + HgCVEdgeMean = Response<0, 4> + HgCVRangePct = Response<0, 5> + EdgeMean4mm = Response<0, 6> + Avg9Point = Response<0, 7> + EdgeMean10mm = Response<0, 8> + ResStdDev = Response<0, 9> - DataPoints = PhaseDataPoints - Response = QA_Services('CalculateHgCVData', Datapoints) - * GoSub CalculateQAData - PhaseMin = Response<0, 2> - PhaseMax = Response<0, 3> - PhaseAvg = Response<0, 1> - PhaseEdgeMean = Response<0, 4> - PhaseRangePct = Response<0, 5> - // Format data. Round to significant digits. - * HgCVAvg = Oconv(Iconv(Oconv(HgCVAvg, 'MD3L'), 'MD3L'), 'MD3L') - * PhaseAvg = Oconv(Iconv(Oconv(PhaseAvg, 'MD3L'), 'MD3L'), 'MD3L') - * HgCVMin = Oconv(Iconv(Oconv(HgCVMin, 'MD3L'), 'MD3L'), 'MD3L') - * HgCVMax = Oconv(Iconv(Oconv(HgCVMax, 'MD3L'), 'MD3L'), 'MD3L') - * PhaseMin = Oconv(Iconv(Oconv(PhaseMin, 'MD3L'), 'MD3L'), 'MD3L') - * PhaseMax = Oconv(Iconv(Oconv(PhaseMax, 'MD3L'), 'MD3L'), 'MD3L') - * HgCVEdgeMean = OConv(IConv(HgCVEdgeMean, 'MD3L'), 'MD3L') - * PhaseEdgeMean = Oconv(IConv(PhaseEdgeMean, 'MD3L'), 'MD3L') - * HgCVRangePct = Oconv(Iconv(HgCVRangePct, 'MD3L'), 'MD3L') - * PhaseRangePct = Oconv(Iconv(PhaseRangePct, 'MD3L'), 'MD3L') - WOMatQARec = HgCVAvg : @SVM : PhaseAvg - WOMatQARec = HgCVMin : @SVM : PhaseMin - WOMatQARec = HgCVMax : @SVM : PhaseMax - WOMatQARec = HgCVRangePct : @SVM : PhaseRangePct - WOMatQARec = HgCVEdgeMean : @SVM : PhaseEdgeMean - SpecMin = WOMatQARec - SpecMax = WOMatQARec - SpecPhaseMin = WOMatQARec - If SpecPhaseMin EQ '' then - // Phase Min Spec was not added to WO_MAT_QA record when it should have been. - // This bug should be fixed now, but in the meantime current records in production - // may not have a phase min specification value. We need to add it here. - djs - 10/15/18 - PSN = Xlate('RDS', RDSKeyID, 'PROD_SPEC_ID', 'X') - If PSN NE '' then - PRSStageKey = PSN:'*UNLOAD' - Database_Services('ActivateRecord', 'PRS_STAGE', PRSStageKey) - MetProps = {MET_PROP} - Locate 'CRES' in MetProps using @VM setting PropPos then - SpecPhaseMinCol = {MET_PHASE_MIN} - SpecPhaseMin = SpecPhaseMinCol<1, PropPos> - WOMatQARec = SpecPhaseMin - end - end - end - CriticalPoints = '1,2,5,6,9' - // Store data points for HgCV Data Table Project -------------------------------------------------------------- - For Index = 1 to NumDataPoints - CriticalPoint = Index(CriticalPoints, Index, 1) - HgCVData = Oconv(Iconv(Oconv(HgCVDataPoints<0,Index>, 'MD3L'), 'MD3L'), 'MD3L') - PhaseData = Oconv(Iconv(Oconv(PhaseDataPoints<0,Index>, 'MD3L'), 'MD3L'), 'MD3L') - If ( (HgCVData LT SpecMin) OR (HgCVData GT SpecMax) OR (PhaseData LT SpecPhaseMin) ) and CriticalPoint then - // Data point out of spec - WOMatQARec = True$ - end - DataRow = HgCVData : @TM : PhaseData - WOMatQARec = DataRow - Next Index - // ------------------------------------------------------------------------------------------------------------ - - // Send data to SPC ------------------------------------------------------------------------------------------- - LogPath = Environment_Services('GetSpcFilesharePath') - SpcFileDtm = OConv(Datetime(), 'DT2^HS ') - Convert ' ' to '_' in SpcFileDtm - SpcLogFilename = 'HgCV_Unload_Res_9Points_':SpcFileDtm:'.txt' - objSPC = Logging_Services('NewLog', LogPath, SpcLogFilename, CRLF$, Comma$, '', '', False$, True$) - If Error_Services('NoError') then - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID000', Service : ' : Successfully created blank SPC file.') - end else - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID000', Service : ' : Failed to create blank SPC file. Error message: ':Error_Services('GetMessage')) - end - LogData = '' - LogData<1> = Oconv(Timestamp, 'DT/^HS') ; // Metrology date/time stamp - LogData<2> = ReactorID ; // Reactor - LogData<3> = RDSKeyID ; // RDS No - LogData<4> = Xlate('RDS', RDSKeyID, 'PROD_SPEC_ID', 'X'); // PSN - WaferSize = Xlate('RDS', RDSKeyID, 'WAFER_SIZE', 'X') - WaferSize = Field(WaferSize, ' ', 3) - LogData<5> = WaferSize:' Inch' ; // Wafer Size - FormattedData = Oconv(HgCVDataPoints, 'MD3L') - Swap @VM with ',' in FormattedData - LogData<6> = FormattedData - LogData<7> = OConv(PhaseAvg, 'MD43L') - LogData<8> = OConv(HgCVAvg, 'MD43L') ; // HgCV Res Avg - LogData<9> = OConv(ResStdDev, 'MD83L') ; // HgCV Res Std Dev - LogData<10> = HgCVRangePct ; // HgCV Res Range % - LogData<11> = OConv(EdgeMean4mm, 'MD43L') ; // HgCV 4mm Edge Mean - LogData<12> = OConv(Avg9Point, 'MD83L') ; // HgCV 9 Point Mean - LogData<13> = OConv(EdgeMean10mm, 'MD43L') ; // HgCV 10mm Edge Mean - LogData<14> = HgCVEdgeMean ; // HgCV Edge Mean Delta % - LogData := @RM : ' ' - Logging_Services('AppendLog', objSPC, LogData, @RM, @FM, True$) - If Error_Services('NoError') then - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID000', Service : ' : Successfully updated SPC file with metrology data.') - end else - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID000', Service : ' : Failed to update SPC file with metrology data. Error message: ':Error_Services('GetMessage')) - end - // ------------------------------------------------------------------------------------------------------------ - - WOMatQARec = '' - WOMatQARec = '' - Database_Services('WriteDataRow', 'WO_MAT_QA', WOMatQAID, WOMatQARec, True$, False$, True$) - If Error_Services('NoError') then - RDSTestRec = Timestamp - // Save results - Database_Services('WriteDataRow', 'RDS_TEST', RDSTestKeyID, RDSTestRec, True$, False$, True$) - If Error_Services('NoError') then - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID000', Service : ' : Success - Hg CRes.') - end else - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID002', Service : ' : UID002 - ' : Error_Services('GetMessage')) - end - end else - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) - end - // We know it is a CRES test, so we can now safely import the Phase Angle data - - end else - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : UID001 - Data for this metrology test already exists and is not from the metrology viewer.') + DataPoints = PhaseDataPoints + Response = QA_Services('CalculateHgCVData', Datapoints) + * GoSub CalculateQAData + PhaseMin = Response<0, 2> + PhaseMax = Response<0, 3> + PhaseAvg = Response<0, 1> + PhaseEdgeMean = Response<0, 4> + PhaseRangePct = Response<0, 5> + // Format data. Round to significant digits. + * HgCVAvg = Oconv(Iconv(Oconv(HgCVAvg, 'MD3L'), 'MD3L'), 'MD3L') + * PhaseAvg = Oconv(Iconv(Oconv(PhaseAvg, 'MD3L'), 'MD3L'), 'MD3L') + * HgCVMin = Oconv(Iconv(Oconv(HgCVMin, 'MD3L'), 'MD3L'), 'MD3L') + * HgCVMax = Oconv(Iconv(Oconv(HgCVMax, 'MD3L'), 'MD3L'), 'MD3L') + * PhaseMin = Oconv(Iconv(Oconv(PhaseMin, 'MD3L'), 'MD3L'), 'MD3L') + * PhaseMax = Oconv(Iconv(Oconv(PhaseMax, 'MD3L'), 'MD3L'), 'MD3L') + * HgCVEdgeMean = OConv(IConv(HgCVEdgeMean, 'MD3L'), 'MD3L') + * PhaseEdgeMean = Oconv(IConv(PhaseEdgeMean, 'MD3L'), 'MD3L') + * HgCVRangePct = Oconv(Iconv(HgCVRangePct, 'MD3L'), 'MD3L') + * PhaseRangePct = Oconv(Iconv(PhaseRangePct, 'MD3L'), 'MD3L') + WOMatQARec = HgCVAvg : @SVM : PhaseAvg + WOMatQARec = HgCVMin : @SVM : PhaseMin + WOMatQARec = HgCVMax : @SVM : PhaseMax + WOMatQARec = HgCVRangePct : @SVM : PhaseRangePct + WOMatQARec = HgCVEdgeMean : @SVM : PhaseEdgeMean + SpecMin = WOMatQARec + SpecMax = WOMatQARec + SpecPhaseMin = WOMatQARec + If SpecPhaseMin EQ '' then + // Phase Min Spec was not added to WO_MAT_QA record when it should have been. + // This bug should be fixed now, but in the meantime current records in production + // may not have a phase min specification value. We need to add it here. - djs - 10/15/18 + PSN = Xlate('RDS', RDSKeyID, 'PROD_SPEC_ID', 'X') + If PSN NE '' then + PRSStageKey = PSN:'*UNLOAD' + Database_Services('ActivateRecord', 'PRS_STAGE', PRSStageKey) + MetProps = {MET_PROP} + Locate 'CRES' in MetProps using @VM setting PropPos then + SpecPhaseMinCol = {MET_PHASE_MIN} + SpecPhaseMin = SpecPhaseMinCol<1, PropPos> + WOMatQARec = SpecPhaseMin + end + end end + CriticalPoints = '1,2,5,6,9' + // Store data points for HgCV Data Table Project -------------------------------------------------------------- + For Index = 1 to NumDataPoints + CriticalPoint = Index(CriticalPoints, Index, 1) + HgCVData = Oconv(Iconv(Oconv(HgCVDataPoints<0,Index>, 'MD3L'), 'MD3L'), 'MD3L') + PhaseData = Oconv(Iconv(Oconv(PhaseDataPoints<0,Index>, 'MD3L'), 'MD3L'), 'MD3L') + If ( (HgCVData LT SpecMin) OR (HgCVData GT SpecMax) OR (PhaseData LT SpecPhaseMin) ) and CriticalPoint then + // Data point out of spec + WOMatQARec = True$ + end + DataRow = HgCVData : @TM : PhaseData + WOMatQARec = DataRow + Next Index + // ------------------------------------------------------------------------------------------------------------ + + // Send data to SPC ------------------------------------------------------------------------------------------- + LogPath = Environment_Services('GetSpcFilesharePath') + SpcFileDtm = OConv(Datetime(), 'DT2^HS ') + Convert ' ' to '_' in SpcFileDtm + SpcLogFilename = 'HgCV_Unload_Res_9Points_':SpcFileDtm:'.txt' + objSPC = Logging_Services('NewLog', LogPath, SpcLogFilename, CRLF$, Comma$, '', '', False$, True$) + If Error_Services('NoError') then + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID000', Service : ' : Successfully created blank SPC file.') + end else + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID000', Service : ' : Failed to create blank SPC file. Error message: ':Error_Services('GetMessage')) + end + LogData = '' + LogData<1> = Oconv(Timestamp, 'DT/^HS') ; // Metrology date/time stamp + LogData<2> = ReactorID ; // Reactor + LogData<3> = RDSKeyID ; // RDS No + LogData<4> = Xlate('RDS', RDSKeyID, 'PROD_SPEC_ID', 'X'); // PSN + WaferSize = Xlate('RDS', RDSKeyID, 'WAFER_SIZE', 'X') + WaferSize = Field(WaferSize, ' ', 3) + LogData<5> = WaferSize:' Inch' ; // Wafer Size + FormattedData = Oconv(HgCVDataPoints, 'MD3L') + Swap @VM with ',' in FormattedData + LogData<6> = FormattedData + LogData<7> = OConv(PhaseAvg, 'MD43L') + LogData<8> = OConv(HgCVAvg, 'MD43L') ; // HgCV Res Avg + LogData<9> = OConv(ResStdDev, 'MD83L') ; // HgCV Res Std Dev + LogData<10> = HgCVRangePct ; // HgCV Res Range % + LogData<11> = OConv(EdgeMean4mm, 'MD43L') ; // HgCV 4mm Edge Mean + LogData<12> = OConv(Avg9Point, 'MD83L') ; // HgCV 9 Point Mean + LogData<13> = OConv(EdgeMean10mm, 'MD43L') ; // HgCV 10mm Edge Mean + LogData<14> = HgCVEdgeMean ; // HgCV Edge Mean Delta % + LogData := @RM : ' ' + Logging_Services('AppendLog', objSPC, LogData, @RM, @FM, True$) + If Error_Services('NoError') then + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID000', Service : ' : Successfully updated SPC file with metrology data.') + end else + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID000', Service : ' : Failed to update SPC file with metrology data. Error message: ':Error_Services('GetMessage')) + end + // ------------------------------------------------------------------------------------------------------------ + + WOMatQARec = '' + WOMatQARec = '' + Database_Services('WriteDataRow', 'WO_MAT_QA', WOMatQAID, WOMatQARec, True$, False$, True$) + If Error_Services('NoError') then + RDSTestRec = Timestamp + // Save results + Database_Services('WriteDataRow', 'RDS_TEST', RDSTestKeyID, RDSTestRec, True$, False$, True$) + If Error_Services('NoError') then + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID000', Service : ' : Success - Hg CRes.') + end else + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID002', Service : ' : UID002 - ' : Error_Services('GetMessage')) + end + end else + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + end + // We know it is a CRES test, so we can now safely import the Phase Angle data + + end else + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : UID001 - Data for this metrology test already exists and is not from the metrology viewer.') end - end else - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) end end else - // The correct RDSTestKeyID was found. If this is a HgCv measurement and HgConcentration RDS test, - // the data has already been written to the database in the above logic. In all other cases, the - // data needs to be written to the database using the following logic that works off of the test - // point map. - DataPoints = HgCVDataPoints - GoSub LoadRunDataToDatabase + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) end end else - Error_Services('Add', 'No data points found.') - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) + // The correct RDSTestKeyID was found. If this is a HgCv measurement and HgConcentration RDS test, + // the data has already been written to the database in the above logic. In all other cases, the + // data needs to be written to the database using the following logic that works off of the test + // point map. + DataPoints = HgCVDataPoints + GoSub LoadRunDataToDatabase end end else - Error_Services('Add', 'Data type / Spec not found for Layer [' : RunDataLayer : '].') + Error_Services('Add', 'No data points found.') Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) end end else - Error_Services('Add', 'Unable to obtain a valid Metrology Test Key ID.') + Error_Services('Add', 'Data type / Spec not found for Layer [' : RunDataLayer : '].') Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) end end else + Error_Services('Add', 'Unable to obtain a valid Metrology Test Key ID.') Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) end + end else + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) end - end else - Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) end end else Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) end + end else + Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) end end service