Updated Metrology_Services to support importing Tencor data into CLEAN_INSP records associated with WM_OUT lots.
This commit is contained in:
@ -2089,18 +2089,19 @@ end service
|
||||
|
||||
Service ImportTencorData(RunData)
|
||||
|
||||
|
||||
ErrorMessage = ''
|
||||
Machine = 'Tencor'
|
||||
Timestamp = RunData<9>
|
||||
HazeAvg = RunData<10>
|
||||
RDSKeyID = RunData<28>
|
||||
LegacyLotId = RunData<28>
|
||||
ScanRecipe = RunData<30>
|
||||
SoDAvg = RunData<39>
|
||||
SoDMax = RunData<40>
|
||||
SoDMin = RunData<41>
|
||||
ScanTool = RunData<43>
|
||||
Swap '%' with ' ' in ScanTool
|
||||
LegacyLotId@ = RDSKeyID
|
||||
LegacyLotId@ = LegacyLotId
|
||||
Convert @Lower_Case to @Upper_Case in ScanTool
|
||||
|
||||
Swap ' AM' with 'AM' in Timestamp
|
||||
@ -2112,7 +2113,7 @@ Service ImportTencorData(RunData)
|
||||
SODVals = ''
|
||||
SortVals = ''
|
||||
SODStartTime = Time()
|
||||
SODWaferArray = QA_Services('GetSODPerWafer', RDSKeyID, ScanRecipe, Timestamp)
|
||||
SODWaferArray = QA_Services('GetSODPerWafer', LegacyLotId, ScanRecipe, Timestamp)
|
||||
SODStopTime = Time()
|
||||
TimeTaken = SODStopTime - SODStartTime
|
||||
LogData = ''
|
||||
@ -2121,20 +2122,61 @@ Service ImportTencorData(RunData)
|
||||
LogData<3> = LegacyLotId@
|
||||
LogData<4> = 'Time taken to import SOD data: ':TimeTaken:' seconds.'
|
||||
Logging_Services('AppendLog', objSODPerfLog, LogData, @RM, @FM)
|
||||
|
||||
If SODWaferArray NE '' then
|
||||
WaferNos = SODWaferArray<1>
|
||||
SODVals = SODWaferArray<2>
|
||||
SortVals = SODWaferArray<3>
|
||||
For each WaferNo in WaferNos using @VM
|
||||
If WaferNo NE '' then QA_Services('PostWaferImageRequest', RDSKeyID, WaferNo, ScanRecipe)
|
||||
If WaferNo NE '' then QA_Services('PostWaferImageRequest', LegacyLotId, WaferNo, ScanRecipe)
|
||||
Next Wafer
|
||||
end
|
||||
LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', RDSKeyID, 'RDS')
|
||||
|
||||
|
||||
Swap '.' with '*' in LegacyLotId ; // Swap . with * used on labels
|
||||
Swap 'O' with '' in LegacyLotId ; // Remove 'O' prefix used on labels for WM_OUT lots
|
||||
|
||||
Begin Case
|
||||
Case RowExists('RDS', LegacyLotId)
|
||||
|
||||
LegacyLotType = 'RDS'
|
||||
ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', LegacyLotId)
|
||||
If Error_Services('NoError') then
|
||||
CIKeyStages = ReactRunRec<REACT_RUN_CI_STAGE$>
|
||||
CIKeyIDs = ReactRunRec<REACT_RUN_CI_NO$>
|
||||
PSN = Xlate('RDS', LegacyLotId, 'PROD_SPEC_ID', 'X')
|
||||
If PSN EQ '' then
|
||||
ErrorMessage = 'Error in ':Service:' service. Null PSN returned from RDS ':LegacyLotId
|
||||
Metrology_Services('LogResults', LegacyLotId, Machine, 'UID001', Service : ' : Error reading PSN from RDS.')
|
||||
end
|
||||
end else
|
||||
ErrorMessage = Error_Services('GetMessage')
|
||||
Metrology_Services('LogResults', LegacyLotId, Machine, 'UID001', Service : ' : ' : ErrorMessage)
|
||||
end
|
||||
|
||||
Case RowExists('WM_OUT', LegacyLotId)
|
||||
|
||||
LegacyLotType = 'WM_OUT'
|
||||
CIKeyStages = ''
|
||||
CIKeyIDs = Xlate('WM_OUT', LegacyLotId, 'EPO_CI_NO', 'X')
|
||||
If CIKeyIDs NE '' then CIKeyStages = Xlate('CLEAN_INSP', CIKeyIDs, CLEAN_INSP_STAGE$, 'X')
|
||||
PSN = Xlate('WM_OUT', LegacyLotId, 'PS_NO', 'X')
|
||||
If PSN EQ '' then
|
||||
ErrorMessage = 'Error in ':Service:' service. Null PSN returned from WM_OUT ':LegacyLotId
|
||||
Metrology_Services('LogResults', LegacyLotId, Machine, 'UID001', Service : ' : Error reading PSN from WM_OUT.')
|
||||
end
|
||||
|
||||
Case Otherwise$
|
||||
LegacyLotType = ''
|
||||
ErrorMessage = 'Error in ':Service:' services. Legacy lot id not found in RDS or WM_OUT tables.'
|
||||
|
||||
End Case
|
||||
|
||||
LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', LegacyLotId, LegacyLotType)
|
||||
|
||||
If LotId NE '' then
|
||||
If DCount(LotId, @VM) EQ 1 then
|
||||
// Import into new metrology data structures
|
||||
MetTestId = Met_Test_Services('CreateMetTest', LotId, RDSKeyID, '', ScanRecipe)
|
||||
MetTestId = Met_Test_Services('CreateMetTest', LotId, LegacyLotId, '', ScanRecipe)
|
||||
If Error_Services('NoError') then
|
||||
Met_Test_Services('SetPropsAndLimits', MetTestId)
|
||||
If Error_Services('HasError') then
|
||||
@ -2187,169 +2229,184 @@ Service ImportTencorData(RunData)
|
||||
end
|
||||
end else
|
||||
Swap @VM with ',' in LotId
|
||||
ErrorMsg = 'Error in ':Service:' service. Number of lot ids returned does not equal 1. Lot ids: ':LotId
|
||||
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg)
|
||||
MetTestErrorMessage = 'Error in ':Service:' service. Number of lot ids returned does not equal 1. Lot ids: ':LotId
|
||||
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : MetTestErrorMessage)
|
||||
end
|
||||
end
|
||||
|
||||
If RowExists('RDS', RDSKeyID) then
|
||||
// Try to read the CleanInsp datarow. Use this to identify the RDSKeyID.
|
||||
ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSKeyID)
|
||||
If Error_Services('NoError') then
|
||||
// Get the PSN to determine if this recipe is part of the LWI stage or the POST stage.
|
||||
PSN = Xlate('RDS', RDSKeyID, 'PROD_SPEC_ID', 'X')
|
||||
PRSStageKeys = Xlate('PROD_SPEC', PSN, 'PRS_STAGE_KEY', 'X')
|
||||
StageFound = False$
|
||||
Stage = ''
|
||||
For each PRSStageKey in PRSStageKeys using @VM setting kPos
|
||||
SSRecipes = Xlate('PRS_STAGE', PRSStageKey, 'SURFSCAN_RECIPE', 'X')
|
||||
Locate ScanRecipe in SSRecipes using @VM setting rPos then
|
||||
StageFound = True$
|
||||
Stage = Field(PRSStageKey, '*', 2, 1)
|
||||
end
|
||||
Next PRSStageKey
|
||||
CIKeyStages = ReactRunRec<REACT_RUN_CI_STAGE$>
|
||||
CIKeyIDs = ReactRunRec<REACT_RUN_CI_NO$>
|
||||
Locate Stage in CIKeyStages using @VM setting vPos then
|
||||
// Stage is prescribed or user created the record from the UI.
|
||||
CIKeyID = CIKeyIDs<0, vPos>
|
||||
If (CIKeyID NE '') then
|
||||
HaveLock = Database_Services('GetKeyIDLock', 'CLEAN_INSP', CIKeyID)
|
||||
If HaveLock EQ True$ then
|
||||
If ScanRecipe NE '' then
|
||||
CleanInspRec = Database_Services('ReadDataRow', 'CLEAN_INSP', CIKeyID)
|
||||
NumRecipes = DCount(CleanInspRec<CLEAN_INSP_SCAN_RECIPE$>, @VM)
|
||||
ScanIndex = NumRecipes + 1
|
||||
NumTools = DCount(CleanInspRec<CLEAN_INSP_SCAN_TOOL$>, @VM)
|
||||
SpecRecipeList = CleanInspRec<CLEAN_INSP_SPEC_SURFSCAN_RECIPE$>
|
||||
NumWfrs = 0
|
||||
Locate ScanRecipe In SpecRecipeList Using @VM Setting RecipeIndex then
|
||||
// Recipe found in spec list
|
||||
If SODWaferArray NE '' then
|
||||
For each WaferNo in WaferNos using @VM
|
||||
If WaferNo NE '' then
|
||||
CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$, ScanIndex, WaferNo> = SODVals<1,WaferNo>
|
||||
CleanInspRec<CLEAN_INSP_SCAN_SORT_PER_WAFER$, ScanIndex, WaferNo> = SortVals<1,WaferNo>
|
||||
end
|
||||
Next Wafer
|
||||
end
|
||||
// Since a matching recipe was found, clear the recipe mismatch field in case it was
|
||||
// previously set by a user attempting to load rundata with the wrong recipe name.
|
||||
CleanInspRec<CLEAN_INSP_SCAN_RECIPE_MISMATCH$> = ''
|
||||
If NumTools GT NumRecipes then
|
||||
NumRecipes = NumTools
|
||||
end
|
||||
NumRecipes += 1
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_RECIPE$, NumRecipes, 0, ScanRecipe)
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_TOOL$, NumRecipes, 0, ScanTool)
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SUM_OF_DEF_MIN$, NumRecipes, 0, SoDMin)
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SUM_OF_DEF_MAX$, NumRecipes, 0, SoDMax)
|
||||
SoDAvg = Iconv(SoDAvg, 'MD3')
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SUM_OF_DEF_AVG$, NumRecipes, 0, SoDAvg)
|
||||
HazeAvg = Iconv(HazeAvg, 'MD3')
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_HAZE_AVG_AVG$, NumRecipes, 0, HazeAvg)
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SIG$, NumRecipes, 0, '')
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SIG_DTM$, NumRecipes, 0, '')
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_INSP_TEST_RUN_DTM$, NumRecipes, 0, Timestamp)
|
||||
// Save results (this will trigger an ROTR_REQUEST via CLEAN_INSP_ACTIONS)
|
||||
Database_Services('WriteDataRow', 'CLEAN_INSP', CIKeyID, CleanInspRec, True$, False$, True$)
|
||||
end else
|
||||
ErrorMessage = 'Tencor recipe ' : ScanRecipe : ' not found in SurfScan recipe list.'
|
||||
Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : ErrorMessage)
|
||||
// Set recipe mismatch flag for MFS purposes
|
||||
CleanInspRec<CLEAN_INSP_SCAN_RECIPE_MISMATCH$> = ScanRecipe
|
||||
Database_Services('WriteDataRow', 'CLEAN_INSP', CIKeyID, CleanInspRec, True$, False$, True$)
|
||||
If (ErrorMessage EQ '') then
|
||||
PRSStageKeys = Xlate('PROD_SPEC', PSN, 'PRS_STAGE_KEY', 'X')
|
||||
StageFound = False$
|
||||
Stage = ''
|
||||
For each PRSStageKey in PRSStageKeys using @VM setting kPos
|
||||
SSRecipes = Xlate('PRS_STAGE', PRSStageKey, 'SURFSCAN_RECIPE', 'X')
|
||||
Locate ScanRecipe in SSRecipes using @VM setting rPos then
|
||||
StageFound = True$
|
||||
Stage = Field(PRSStageKey, '*', 2, 1)
|
||||
end
|
||||
Next PRSStageKey
|
||||
Locate Stage in CIKeyStages using @VM setting vPos then
|
||||
// Stage is prescribed or user created the record from the UI.
|
||||
CIKeyID = CIKeyIDs<0, vPos>
|
||||
If (CIKeyID NE '') then
|
||||
HaveLock = Database_Services('GetKeyIDLock', 'CLEAN_INSP', CIKeyID)
|
||||
If HaveLock EQ True$ then
|
||||
If ScanRecipe NE '' then
|
||||
CleanInspRec = Database_Services('ReadDataRow', 'CLEAN_INSP', CIKeyID)
|
||||
NumRecipes = DCount(CleanInspRec<CLEAN_INSP_SCAN_RECIPE$>, @VM)
|
||||
ScanIndex = NumRecipes + 1
|
||||
NumTools = DCount(CleanInspRec<CLEAN_INSP_SCAN_TOOL$>, @VM)
|
||||
SpecRecipeList = CleanInspRec<CLEAN_INSP_SPEC_SURFSCAN_RECIPE$>
|
||||
NumWfrs = 0
|
||||
Locate ScanRecipe In SpecRecipeList Using @VM Setting RecipeIndex then
|
||||
// Recipe found in spec list
|
||||
If SODWaferArray NE '' then
|
||||
For each WaferNo in WaferNos using @VM
|
||||
If WaferNo NE '' then
|
||||
CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$, ScanIndex, WaferNo> = SODVals<1,WaferNo>
|
||||
CleanInspRec<CLEAN_INSP_SCAN_SORT_PER_WAFER$, ScanIndex, WaferNo> = SortVals<1,WaferNo>
|
||||
end
|
||||
Next Wafer
|
||||
end
|
||||
// Since a matching recipe was found, clear the recipe mismatch field in case it was
|
||||
// previously set by a user attempting to load rundata with the wrong recipe name.
|
||||
CleanInspRec<CLEAN_INSP_SCAN_RECIPE_MISMATCH$> = ''
|
||||
If NumTools GT NumRecipes then
|
||||
NumRecipes = NumTools
|
||||
end
|
||||
NumRecipes += 1
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_RECIPE$, NumRecipes, 0, ScanRecipe)
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_TOOL$, NumRecipes, 0, ScanTool)
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SUM_OF_DEF_MIN$, NumRecipes, 0, SoDMin)
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SUM_OF_DEF_MAX$, NumRecipes, 0, SoDMax)
|
||||
SoDAvg = Iconv(SoDAvg, 'MD3')
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SUM_OF_DEF_AVG$, NumRecipes, 0, SoDAvg)
|
||||
HazeAvg = Iconv(HazeAvg, 'MD3')
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_HAZE_AVG_AVG$, NumRecipes, 0, HazeAvg)
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SIG$, NumRecipes, 0, '')
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SIG_DTM$, NumRecipes, 0, '')
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_INSP_TEST_RUN_DTM$, NumRecipes, 0, Timestamp)
|
||||
// Save results (this will trigger an ROTR_REQUEST via CLEAN_INSP_ACTIONS)
|
||||
Database_Services('WriteDataRow', 'CLEAN_INSP', CIKeyID, CleanInspRec, True$, False$, True$)
|
||||
end else
|
||||
ErrorMessage = 'Scan Recipe is missing.'
|
||||
Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : ErrorMessage)
|
||||
ErrorMessage = 'Tencor recipe ' : ScanRecipe : ' not found in SurfScan recipe list.'
|
||||
Metrology_Services('LogResults', LegacyLotId, Machine, 'UID001', Service : ' : ' : ErrorMessage)
|
||||
// Set recipe mismatch flag for MFS purposes
|
||||
CleanInspRec<CLEAN_INSP_SCAN_RECIPE_MISMATCH$> = ScanRecipe
|
||||
Database_Services('WriteDataRow', 'CLEAN_INSP', CIKeyID, CleanInspRec, True$, False$, True$)
|
||||
end
|
||||
Database_Services('ReleaseKeyIDLock', 'CLEAN_INSP', CIKeyID)
|
||||
end else
|
||||
// 01/31/23 - djs - Modified error message to use UID002 instead of UID001 to ensure the
|
||||
// metrology file is not deleted so that the service can try to import it
|
||||
// again once the lock is released.
|
||||
ErrorMessage = 'Error in service ':Service:'. Failed to lock CLEAN_INSP record: ':CIKeyID:'.'
|
||||
Metrology_Services('LogResults', RDSKeyID, Machine, 'UID002', Service : ' : ' : ErrorMessage)
|
||||
ErrorMessage = 'Scan Recipe is missing.'
|
||||
Metrology_Services('LogResults', LegacyLotId, Machine, 'UID001', Service : ' : ' : ErrorMessage)
|
||||
end
|
||||
Database_Services('ReleaseKeyIDLock', 'CLEAN_INSP', CIKeyID)
|
||||
end else
|
||||
ErrorMessage = 'CI Key ID is missing.'
|
||||
Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : ErrorMessage)
|
||||
// 01/31/23 - djs - Modified error message to use UID002 instead of UID001 to ensure the
|
||||
// metrology file is not deleted so that the service can try to import it
|
||||
// again once the lock is released.
|
||||
ErrorMessage = 'Error in service ':Service:'. Failed to lock CLEAN_INSP record: ':CIKeyID:'.'
|
||||
Metrology_Services('LogResults', LegacyLotId, Machine, 'UID002', Service : ' : ' : ErrorMessage)
|
||||
end
|
||||
end else
|
||||
// Added 8/13/2020 JRO
|
||||
// We can enter in some conditional logic here for Production UAT
|
||||
// If statement to gate from production below
|
||||
PostStartTime = Time()
|
||||
if Indexc(ScanRecipe, 'POST', 1) then
|
||||
// Locate 'POST' in ScanRecipe Using "" setting pPos then
|
||||
ReactRunRec = Xlate('REACT_RUN',RDSKeyID, '', 'X')
|
||||
WONo = ReactRunRec<REACT_RUN_WO_NO$>;//WONo
|
||||
WOStep = ReactRunRec<REACT_RUN_WO_STEP$>;//WOStep
|
||||
CassNo = ReactRunRec<REACT_RUN_CASS_NO$>;//CassNo
|
||||
Stage = 'POST';//Stages
|
||||
PSNo = XLATE('RDS',RDSKeyID,RDS_PROD_SPEC_ID$,'X');//PSNo
|
||||
DefectSpec = Xlate('PRS_STAGE', PSNo : '*LWI', PRS_STAGE_SURF_DEFECTS$, 'X');//Since there is no set spec for a non-existent stage we need to take one from the unloading step.
|
||||
HazeSpec = Xlate('PRS_STAGE', PSNo : '*LWI', PRS_STAGE_SURF_HAZE$, 'X');//Since there is no set spec for a non-existent stage we need to take one from the unloading step.
|
||||
// Check if CI was created already(usually during cleans) JRO-9-28
|
||||
CIStages = ReactRunRec<REACT_RUN_CI_STAGE$>
|
||||
Locate 'POST' in CIStages using @VM setting sPos then
|
||||
// Existing POST CI record found, fetch it.
|
||||
CINo = ReactRunRec<REACT_RUN_CI_NO$,sPos>
|
||||
CleanInspRec = Xlate('CLEAN_INSP', CINo,'','X')
|
||||
IF CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$> NE '' THEN
|
||||
// Append a value mark to the end of the field so that we can add another set of data
|
||||
CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$> = CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$> : @VM
|
||||
END
|
||||
exists = True$
|
||||
end else
|
||||
// No Exisiting POST CI record found, Create new CI record
|
||||
exists = False$
|
||||
oCIParms = ''
|
||||
oCIParms = WONo:@RM
|
||||
oCIParms := WOStep:@RM
|
||||
oCIParms := CassNo:@RM
|
||||
oCIParms := Stage:@RM
|
||||
oCIParms := RDSKeyID:@RM
|
||||
oCIParms := PSNo:@RM
|
||||
CleanInspRec = ''
|
||||
CleanInspRec<CLEAN_INSP_WO_NO$> = WONo
|
||||
CleanInspRec<CLEAN_INSP_WO_STEP$> = WOStep
|
||||
CleanInspRec<CLEAN_INSP_CASS_NO$> = CassNo
|
||||
CleanInspRec<CLEAN_INSP_STAGE$> = Stage
|
||||
CleanInspRec<CLEAN_INSP_RDS_NO$> = RDSKeyID
|
||||
end
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_RECIPE$, -1, 0, ScanRecipe)
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_TOOL$, -1, 0, ScanTool)
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SUM_OF_DEF_MIN$, -1, 0, SoDMin)
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SUM_OF_DEF_MAX$, -1, 0, SoDMax)
|
||||
SoDAvg = Iconv(SoDAvg, 'MD3')
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SUM_OF_DEF_AVG$, -1, 0, SoDAvg)
|
||||
HazeAvg = Iconv(HazeAvg, 'MD3')
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_HAZE_AVG_AVG$, -1, 0, HazeAvg)
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SIG$, -1, 0, '')
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SIG_DTM$, -1, 0, '')
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_INSP_TEST_RUN_DTM$, -1, 0, Timestamp)
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SPEC_SURFSCAN_RECIPE$, -1, 0, ScanRecipe)
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SPEC_SURF_DEFECTS$, -1, 0, DefectSpec)
|
||||
ErrorMessage = 'CI Key ID is missing.'
|
||||
Metrology_Services('LogResults', LegacyLotId, Machine, 'UID001', Service : ' : ' : ErrorMessage)
|
||||
end
|
||||
end else
|
||||
// Added 8/13/2020 JRO
|
||||
// Ad-hoc POST stage SURFSCAN logic
|
||||
PostStartTime = Time()
|
||||
if IndexC(ScanRecipe, 'POST', 1) then
|
||||
|
||||
Begin Case
|
||||
Case LegacyLotType EQ 'RDS'
|
||||
ReactRunRec = Xlate('REACT_RUN', LegacyLotId, '', 'X')
|
||||
WONo = ReactRunRec<REACT_RUN_WO_NO$>
|
||||
WOStep = ReactRunRec<REACT_RUN_WO_STEP$>
|
||||
CassNo = ReactRunRec<REACT_RUN_CASS_NO$>
|
||||
Case LegacyLotType EQ 'WM_OUT'
|
||||
WONo = Field(LegacyLotId, '*', 1, 1)
|
||||
WOStep = Field(LegacyLotId, '*', 2, 1)
|
||||
CassNo = Field(LegacyLotId, '*', 3, 1)
|
||||
Case Otherwise$
|
||||
ErrorMessage = 'Error in ':Service:' services. Invalid LegacyLotType.'
|
||||
End Case
|
||||
|
||||
Stage = 'POST'
|
||||
DefectSpec = Xlate('PRS_STAGE', PSN : '*LWI', PRS_STAGE_SURF_DEFECTS$, 'X');//Since there is no set spec for a non-existent stage we need to take one from the unloading step.
|
||||
HazeSpec = Xlate('PRS_STAGE', PSN : '*LWI', PRS_STAGE_SURF_HAZE$, 'X');//Since there is no set spec for a non-existent stage we need to take one from the unloading step.
|
||||
// Check if CI was created already(usually during cleans) JRO-9-28
|
||||
Locate 'POST' in CIKeyStages using @VM setting sPos then
|
||||
// Existing POST CI record found, fetch it.
|
||||
CINo = CIKeyIDs<0, sPos>
|
||||
CleanInspRec = Xlate('CLEAN_INSP', CINo,'','X')
|
||||
IF CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$> NE '' THEN
|
||||
// Append a value mark to the end of the field so that we can add another set of data
|
||||
CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$> = CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$> : @VM
|
||||
END
|
||||
Exists = True$
|
||||
end else
|
||||
// No Exisiting POST CI record found, Create new CI record
|
||||
Exists = False$
|
||||
oCIParms = ''
|
||||
oCIParms = WONo:@RM
|
||||
oCIParms := WOStep:@RM
|
||||
oCIParms := CassNo:@RM
|
||||
oCIParms := Stage:@RM
|
||||
If LegacyLotType EQ 'RDS' then oCIParms := LegacyLotId:@RM
|
||||
oCIParms := PSN:@RM
|
||||
CleanInspRec = ''
|
||||
CleanInspRec<CLEAN_INSP_WO_NO$> = WONo
|
||||
CleanInspRec<CLEAN_INSP_WO_STEP$> = WOStep
|
||||
CleanInspRec<CLEAN_INSP_CASS_NO$> = CassNo
|
||||
CleanInspRec<CLEAN_INSP_STAGE$> = Stage
|
||||
If LegacyLotType EQ 'RDS' then CleanInspRec<CLEAN_INSP_RDS_NO$> = LegacyLotId
|
||||
end
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_RECIPE$, -1, 0, ScanRecipe)
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_TOOL$, -1, 0, ScanTool)
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SUM_OF_DEF_MIN$, -1, 0, SoDMin)
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SUM_OF_DEF_MAX$, -1, 0, SoDMax)
|
||||
SoDAvg = Iconv(SoDAvg, 'MD3')
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SUM_OF_DEF_AVG$, -1, 0, SoDAvg)
|
||||
HazeAvg = Iconv(HazeAvg, 'MD3')
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_HAZE_AVG_AVG$, -1, 0, HazeAvg)
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SIG$, -1, 0, '')
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SCAN_SIG_DTM$, -1, 0, '')
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_INSP_TEST_RUN_DTM$, -1, 0, Timestamp)
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SPEC_SURFSCAN_RECIPE$, -1, 0, ScanRecipe)
|
||||
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SPEC_SURF_DEFECTS$, -1, 0, DefectSpec)
|
||||
|
||||
// Here I am attempting to create the scan details.
|
||||
If SODWaferArray NE '' then
|
||||
NumRecipes = DCount(CleanInspRec<CLEAN_INSP_SCAN_RECIPE$>, @VM)
|
||||
For each WaferNo in WaferNos using @VM
|
||||
If WaferNo NE '' then
|
||||
CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$, NumRecipes, WaferNo> = SODVals<1,WaferNo>
|
||||
CleanInspRec<CLEAN_INSP_SCAN_SORT_PER_WAFER$, NumRecipes, WaferNo> = SortVals<1,WaferNo>
|
||||
end
|
||||
Next Wafer
|
||||
end
|
||||
|
||||
If exists EQ False$ then
|
||||
|
||||
// Here I am attempting to create the scan details.
|
||||
If SODWaferArray NE '' then
|
||||
NumRecipes = DCount(CleanInspRec<CLEAN_INSP_SCAN_RECIPE$>, @VM)
|
||||
For each WaferNo in WaferNos using @VM
|
||||
If WaferNo NE '' then
|
||||
CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$, NumRecipes, WaferNo> = SODVals<1,WaferNo>
|
||||
CleanInspRec<CLEAN_INSP_SCAN_SORT_PER_WAFER$, NumRecipes, WaferNo> = SortVals<1,WaferNo>
|
||||
end
|
||||
Next Wafer
|
||||
end
|
||||
If exists EQ False$ then
|
||||
oCIParms := CleanInspRec
|
||||
CINo = obj_Clean_Insp('Create',oCIParms)
|
||||
If Error_Services('NoError') then
|
||||
ReactRunRec = INSERT(ReactRunRec,REACT_RUN_CI_NO$,-1,0,CINo)
|
||||
ReactRunRec = INSERT(ReactRunRec,REACT_RUN_CI_STAGE$,-1,0,Stage)
|
||||
obj_Tables('WriteRec','REACT_RUN':@RM:RDSKeyID:@RM:@RM:ReactRunRec)
|
||||
oCIParms := CleanInspRec ;
|
||||
CINo = obj_Clean_Insp('Create',oCIParms)
|
||||
If Error_Services('NoError') then
|
||||
Begin Case
|
||||
Case LegacyLotType EQ 'RDS'
|
||||
ReactRunRec = INSERT(ReactRunRec,REACT_RUN_CI_NO$,-1,0,CINo)
|
||||
ReactRunRec = INSERT(ReactRunRec,REACT_RUN_CI_STAGE$,-1,0,Stage)
|
||||
obj_Tables('WriteRec','REACT_RUN':@RM:LegacyLotId:@RM:@RM:ReactRunRec)
|
||||
Case LegacyLotType EQ 'WM_OUT'
|
||||
WOMatRec = Database_Services('ReadDataRow', 'WO_MAT', WONo:'*':CassNo)
|
||||
If Error_Services('NoError') then
|
||||
WOMatRec = Insert(WOMatRec, WO_MAT_EPO_CI_NO$, -1, 0, CINo)
|
||||
Database_Services('WriteDataRow', 'WO_MAT', WONo:'*':CassNo, WOMatRec, True$, False$, False$)
|
||||
end
|
||||
Case Otherwise$
|
||||
ErrorMessage = 'Error in ':Service:' services. Invalid LegacyLotType.'
|
||||
End Case
|
||||
|
||||
If ErrorMessage EQ '' then
|
||||
obj_Tables('WriteRec','CLEAN_INSP':@RM:CINo:@RM:@RM:CleanInspRec)
|
||||
PostStopTime = Time()
|
||||
TimeTaken = PostStopTime - PostStartTime
|
||||
@ -2359,39 +2416,35 @@ Service ImportTencorData(RunData)
|
||||
LogData<3> = LegacyLotId@
|
||||
LogData<4> = 'Time taken to import POST data: ':TimeTaken:' seconds.'
|
||||
Logging_Services('AppendLog', objPOSTPerfLog, LogData, @RM, @FM)
|
||||
end else
|
||||
// Record error. Ensure metrology run data file is not deleted by including UID002 in the
|
||||
// error message that is placed onto error stack in Error_Services.
|
||||
ErrorMessage = 'Failed to create CLEAN_INSP record. Error UID002.'
|
||||
end
|
||||
|
||||
end else
|
||||
// Write to existing CI rec.
|
||||
obj_Tables('WriteRec','CLEAN_INSP':@RM:CINo:@RM:@RM:CleanInspRec)
|
||||
// Record error. Ensure metrology run data file is not deleted by including UID002 in the
|
||||
// error message that is placed onto error stack in Error_Services.
|
||||
ErrorMessage = 'Failed to create CLEAN_INSP record. Error UID002.'
|
||||
end
|
||||
end else
|
||||
// Unexpected recipe -> notify users if not a QUAL scan
|
||||
QualScan = (Indexc(ScanRecipe, 'QUAL', 1) GT 0)
|
||||
If QualScan EQ False$ then
|
||||
Recipients = XLATE('NOTIFICATION','TENCOR_NOTIFICATIONS',NOTIFICATION_USER_ID$,'X')
|
||||
SentFrom = 'OI Admin'
|
||||
Subject = 'Tencor SurfScan Import Failure for RDS ':RDSKeyID:'.'
|
||||
Message = 'Scanned recipe ':ScanRecipe:' not found in PSN ':PSN:' for RDS ':RDSKeyID:'.'
|
||||
AttachWindow = ''
|
||||
AttachKey = ''
|
||||
SendToGroup = ''
|
||||
Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup
|
||||
obj_Notes('Create',Parms)
|
||||
end
|
||||
// Write to existing CI rec.
|
||||
obj_Tables('WriteRec','CLEAN_INSP':@RM:CINo:@RM:@RM:CleanInspRec)
|
||||
end
|
||||
end else
|
||||
// Unexpected recipe -> notify users if not a QUAL scan
|
||||
QualScan = (Indexc(ScanRecipe, 'QUAL', 1) GT 0)
|
||||
If QualScan EQ False$ then
|
||||
Recipients = XLATE('NOTIFICATION','TENCOR_NOTIFICATIONS',NOTIFICATION_USER_ID$,'X')
|
||||
SentFrom = 'OI Admin'
|
||||
Subject = 'Tencor SurfScan Import Failure for ':LegacyLotType:' ':LegacyLotId:'.'
|
||||
Message = 'Scanned recipe ':ScanRecipe:' not found in PSN ':PSN:' for ':LegacyLotType:' ':LegacyLotId:'.'
|
||||
AttachWindow = ''
|
||||
AttachKey = ''
|
||||
SendToGroup = ''
|
||||
Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup
|
||||
obj_Notes('Create',Parms)
|
||||
end
|
||||
end
|
||||
end else
|
||||
ErrorMessage = Error_Services('GetMessage')
|
||||
Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : ErrorMessage)
|
||||
end
|
||||
end else
|
||||
ErrorMessage = 'Invalid RDS Key ID.'
|
||||
Metrology_Services('LogResults', RDSKeyID, Machine, 'UID001', Service : ' : ' : ErrorMessage)
|
||||
end
|
||||
end
|
||||
|
||||
If ErrorMessage NE '' then Error_Services('Add', ErrorMessage)
|
||||
|
||||
end service
|
||||
@ -3680,3 +3733,4 @@ LoadRunDataToDatabase:
|
||||
|
||||
return
|
||||
|
||||
|
||||
|
||||
@ -1012,7 +1012,7 @@ Service GetSODPerWafer(RDSKey, TencorRecipe, ScanDTM)
|
||||
If RDSKey NE '' and TencorRecipe NE '' then
|
||||
|
||||
If Num(ScanDTM) then ScanDTM = OConv(ScanDTM, 'DT/^S')
|
||||
Query = "DECLARE @RDS varchar(10) "
|
||||
Query = "DECLARE @RDS varchar(255) "
|
||||
Query := "DECLARE @RECIPE varchar(30) "
|
||||
Query := "DECLARE @INSERT_DT datetime "
|
||||
Query := "SET @RDS = '":RDSKey:"' "
|
||||
@ -1199,7 +1199,7 @@ Service ProcessWaferImageRequests()
|
||||
PSN = Xlate('RDS', RDSNo, 'PROD_SPEC_ID', 'X')
|
||||
// Format Wafer Number for SQL Query
|
||||
WaferNo = Fmt(TrimF(WaferNo), 'R(0)#2')
|
||||
Query = "DECLARE @RDS varchar(10) " |
|
||||
Query = "DECLARE @RDS varchar(255) " |
|
||||
: "DECLARE @RECIPE varchar(30) " |
|
||||
: "DECLARE @WFRID varchar(10) " |
|
||||
: "SET @RDS = '":RDSNo:"' " |
|
||||
@ -3833,13 +3833,3 @@ ClearCursors:
|
||||
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user