Updated Metrology_Services to support importing Tencor data into CLEAN_INSP records associated with WM_OUT lots.

This commit is contained in:
Infineon\StieberD
2025-11-11 16:32:44 -07:00
parent 169fabdac6
commit 77d2f5f6ab
2 changed files with 240 additions and 196 deletions

View File

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

View File

@ -1012,7 +1012,7 @@ Service GetSODPerWafer(RDSKey, TencorRecipe, ScanDTM)
If RDSKey NE '' and TencorRecipe NE '' then If RDSKey NE '' and TencorRecipe NE '' then
If Num(ScanDTM) then ScanDTM = OConv(ScanDTM, 'DT/^S') 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 @RECIPE varchar(30) "
Query := "DECLARE @INSERT_DT datetime " Query := "DECLARE @INSERT_DT datetime "
Query := "SET @RDS = '":RDSKey:"' " Query := "SET @RDS = '":RDSKey:"' "
@ -1199,7 +1199,7 @@ Service ProcessWaferImageRequests()
PSN = Xlate('RDS', RDSNo, 'PROD_SPEC_ID', 'X') PSN = Xlate('RDS', RDSNo, 'PROD_SPEC_ID', 'X')
// Format Wafer Number for SQL Query // Format Wafer Number for SQL Query
WaferNo = Fmt(TrimF(WaferNo), 'R(0)#2') WaferNo = Fmt(TrimF(WaferNo), 'R(0)#2')
Query = "DECLARE @RDS varchar(10) " | Query = "DECLARE @RDS varchar(255) " |
: "DECLARE @RECIPE varchar(30) " | : "DECLARE @RECIPE varchar(30) " |
: "DECLARE @WFRID varchar(10) " | : "DECLARE @WFRID varchar(10) " |
: "SET @RDS = '":RDSNo:"' " | : "SET @RDS = '":RDSNo:"' " |
@ -3833,13 +3833,3 @@ ClearCursors:
return return