Files
open-insight/LSL2/STPROC/MET_TEST_SERVICES.txt

1281 lines
60 KiB
Plaintext

Compile function Met_Test_Services(@Service, @Params)
/***********************************************************************************************************************
This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written
permission from SRP Computer Solutions, Inc.
Name : Met_Test_Services
Description : Handler program for all module related services.
Notes : The generic parameters should contain all the necessary information to process the services. Often
this will be information like the data Record and Key ID.
Parameters :
Service [in] -- Name of the service being requested
Param1-10 [in/out] -- Additional request parameter holders
Response [out] -- Response to be sent back to the Controller (MCP) or requesting procedure
History : (Date, Initials, Notes)
05/13/25 djs Original developer
***********************************************************************************************************************/
#pragma precomp SRP_PreCompiler
$Insert SERVICE_SETUP
$Insert APP_INSERTS
$Insert MET_TEST_EQUATES
$Insert MET_TEST_DATA_EQUATES
$Insert MET_TEST_INSERTS
$Insert DICT_EQUATES
$Insert TOOL_EQUATES
$Insert LOT_OPERATION_EQUATES
Declare function RTI_CreateGuid, Error_Services, Tool_Services, Database_Services, SRP_Array, SRP_JSON, Datetime
Declare function Met_Test_Services, Date_Services
Declare subroutine Database_Services, Error_Services, Btree.Extract, SRP_JSON, Extract_Si_Keys, Lot_Event_Services
GoToService
Return Response or ""
//----------------------------------------------------------------------------------------------------------------------
// Service Parameter Options
//----------------------------------------------------------------------------------------------------------------------
Options LAYERS = '1', '2', '3'
Options ZONES = '1', '2'
Options INSPECTION_RECIPES = 'PRE', 'LOAD', 'FWI', 'UNLOAD', 'LWI', 'POST', 'QA'
//----------------------------------------------------------------------------------------------------------------------
// Services
//----------------------------------------------------------------------------------------------------------------------
Service ManualMetTestEntry(ToolId, LotId, Recipe, Pattern, RunDataLayer, RunDataZone, Positions, RawDataPoints)
ToolClass = XLATE('TOOL', ToolId, 'CLASS', 'X')
RDSKeyId = ''
MetTestId = Met_Test_Services('CreateMetTest', LotId, RDSKeyId, ToolClass, Recipe, Pattern, Layer, RunDataZone)
Met_Test_Services('SetPropsAndLimits', MetTestId)
Met_Test_Services('SetMetTestTool', MetTestId, ToolId)
Met_Test_Services('SetMetTestDtm', MetTestId, DateTime())
for each DataPoint in RawDataPoints using @VM setting vPos
position = Positions<0, vPos>
Met_Test_Services('AddMetTestData', MetTestId, Position, DataPoint)
Next DataPoint
end service
//----------------------------------------------------------------------------------------------------------------------
// CreateMetTest
//
// Input:
// LotId [Required] - Key of LOT_ID record to relate MET_TEST record to.
// LegacyLotId [Optional] - Key of legacy lot id (e.g., RDS, WO_MAT, WM_OUT) to relate MET_TEST record to
// ToolClass [Optional] - TOOL_CLASS of metrology test. Used for PRS_PROP spec lookup.
// Required parameter for RDS_TEST metrology.
// ToolRecipe [Optional] - Recipe of metrology test prescribed in PSN and selected on metrology tool.
// This can be a recipe from an RDS_TEST, CLEAN_INSP, or WO_MAT_QA metrology test.
// Required parameter for metrology tests (i.e., not visual inspections)!
// ToolPattern [Optional] - Pattern of metrology test prescribed in PSN and selected on metrology tool.
// This will drive the sample size (i.e., number of data points) to require in order
// for the test to be considered "complete".
// Layer [Optional] - Layer of metrology test. Required for RDS_TEST metrology.
// Note: This should be 1, 2, or 3 to match PRS_PROP keys. Not L1, L2, or 2.
// Zone [Optional] - Zone of metrology test. Should be null (""), 1, or 2
// InspectionRecipe [Optional] - PRS_STAGE to retrieve visual inspection specs from.
// Required parameter for CLEAN_INSP visual inspections.
//
// Output:
// If successful, returns the key of the MET_TEST record created.
//
// Note:
// The SAMPLE_SIZE field derived from the ToolPattern may refer to the number of data points on a
// single wafer (e.g., RDS_TEST metrology) or the number of wafers in a cassette (e.g., surfscan).
//
// Creates a parent MET_TEST record related to a LOT_ID record.
//----------------------------------------------------------------------------------------------------------------------
Service CreateMetTest(LotId, LegacyLotId, ToolClass, ToolRecipe, ToolPattern, Layer=LAYERS, Zone=ZONES, InspectionRecipe=INSPECTION_RECIPES)
MetTestRec = ''
MetTestId = ''
ErrorMsg = ''
If (LotId NE '') then
If RowExists('LOT', LotId) then
If Layer NE '' then
Swap 2 with 3 in Layer
Swap 'L2' with 2 in Layer
Swap 'L1' with 1 in Layer
end
// Create MET_TEST key and write record
MetTestId = RTI_CreateGuid()
MetTestRec<MET_TEST.LOT_ID$> = LotId
MetTestRec<MET_TEST.LEGACY_LOT_ID$> = LegacyLotId
MetTestRec<MET_TEST.TOOL_CLASS$> = ToolClass
MetTestRec<MET_TEST.TOOL_RECIPE$> = ToolRecipe
MetTestRec<MET_TEST.TOOL_PATTERN$> = ToolPattern
MetTestRec<MET_TEST.LAYER$> = Layer
MetTestRec<MET_TEST.ZONE$> = Zone
MetTestRec<MET_TEST.INSPECTION_RECIPE$> = InspectionRecipe
Database_Services('WriteDataRow', 'MET_TEST', MetTestId, MetTestRec)
If Error_Services('HasError') then
ErrorMsg = 'Error in ':Service:' service. Error writing MET_TEST record. Error message: ':Error_Services('GetMessage')
end
end else
ErrorMsg = 'Error in ':Service:' service. LotId "':LotId:'" does not exist in the LOT table.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null LotId passed into service.'
end
If ErrorMsg EQ '' then
Response = MetTestId
end else
Error_Services('Add', ErrorMsg)
end
End Service
//----------------------------------------------------------------------------------------------------------------------
// AddMetTestData
//
// Description:
// Creates a child MET_TEST_DATA record related to a parent MET_TEST record.
//
// Input:
// MetTestId [Required] - Key of MET_TEST parent record
// Position [Optional] - Integer indicating an order or values (e.g., wafer slot or point value of point map)
// PropertyVal1 [Optional] - Metrology value associated with PROPERTY_1 of parent MET_TEST record
// ...
// ...
// ...
// PropertyVal15 [Optional] - Metrology value associated with PROPERTY_15 of parent MET_TEST record
//
// Output:
// Returns true if successful, false otherwise.
//
// Notes:
// At least one property value is required
// Extend PropertyVal input fields as MET_TEST PropertyVal fields are added (e.g., PropertyVal16, PropertyVal17, ...)
//----------------------------------------------------------------------------------------------------------------------
Service AddMetTestData(MetTestId, Position, PropertyVal1, PropertyVal2, PropertyVal3, PropertyVal4, PropertyVal5, PropertyVal6, PropertyVal7, PropertyVal8, PropertyVal9, PropertyVal10, PropertyVal11, PropertyVal12, PropertyVal13, PropertyVal14, PropertyVal15)
ErrorMsg = ''
If ( (MetTestId NE '') and (PropertyVal1 NE '') or (PropertyVal2 NE '') or (PropertyVal3 NE '') or (PropertyVal4 NE '') |
or (PropertyVal5 NE '') or (PropertyVal6 NE '') or (PropertyVal7 NE '') or (PropertyVal8 NE '') or (PropertyVal9 NE '') |
or (PropertyVal10 NE '') or (PropertyVal11 NE '') or (PropertyVal12 NE '') or (PropertyVal13 NE '') or (PropertyVal14 NE '') |
or (PropertyVal15 NE '') ) then
If RowExists('MET_TEST', MetTestId) then
MetTestDataKey = RTI_CreateGuid()
MetTestDataRec = ''
MetTestDataRec<MET_TEST_DATA.MET_TEST_ID$> = MetTestId
MetTestDataRec<MET_TEST_DATA.POSITION$> = Position
MetTestDataRec<MET_TEST_DATA.PROPERTY_1_VALUE$> = PropertyVal1
MetTestDataRec<MET_TEST_DATA.PROPERTY_2_VALUE$> = PropertyVal2
MetTestDataRec<MET_TEST_DATA.PROPERTY_3_VALUE$> = PropertyVal3
MetTestDataRec<MET_TEST_DATA.PROPERTY_4_VALUE$> = PropertyVal4
MetTestDataRec<MET_TEST_DATA.PROPERTY_5_VALUE$> = PropertyVal5
MetTestDataRec<MET_TEST_DATA.PROPERTY_6_VALUE$> = PropertyVal6
MetTestDataRec<MET_TEST_DATA.PROPERTY_7_VALUE$> = PropertyVal7
MetTestDataRec<MET_TEST_DATA.PROPERTY_8_VALUE$> = PropertyVal8
MetTestDataRec<MET_TEST_DATA.PROPERTY_9_VALUE$> = PropertyVal9
MetTestDataRec<MET_TEST_DATA.PROPERTY_10_VALUE$> = PropertyVal10
MetTestDataRec<MET_TEST_DATA.PROPERTY_11_VALUE$> = PropertyVal11
MetTestDataRec<MET_TEST_DATA.PROPERTY_12_VALUE$> = PropertyVal12
MetTestDataRec<MET_TEST_DATA.PROPERTY_13_VALUE$> = PropertyVal13
MetTestDataRec<MET_TEST_DATA.PROPERTY_14_VALUE$> = PropertyVal14
MetTestDataRec<MET_TEST_DATA.PROPERTY_14_VALUE$> = PropertyVal15
Database_Services('WriteDataRow', 'MET_TEST_DATA', MetTestDataKey, MetTestDataRec)
If Error_Services('HasError') then
ErrorMsg = 'Error in ':Service:' service. Failed to write MET_TEST_DATA record. Error message: ':Error_Services('GetMessage')
end
end else
ErrorMsg = 'Error in ':Service:' service. Parent MET_TEST record "':MetTestId:'" does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null MetTestId, PropertyVal1, PropertyVal2, PropertyVal3, or PropertyVal4 passed into service'
end
If ErrorMsg EQ '' then
Response = True$
end else
Error_Services('Add', ErrorMsg)
Response = False$
end
end service
//----------------------------------------------------------------------------------------------------------------------
// SetPropsAndLimits
//
// Input:
// MetTestId [Required] - Key of MET_TEST record to update.
//
// Output:
// Returns true if successful, false otherwise.
//
// Searches PROD_SPEC, PRS_PROP, and PRS_STAGe for matching property names and limits to apply to columns
// PROPERTY_1, PROPERTY_1_MIN, PROPERTY_1_MAX, ... PROPERTY_N, PROPERTY_N_MIN, PROPERTY_N_MAX.
//----------------------------------------------------------------------------------------------------------------------
Service SetPropsAndLimits(MetTestId)
ErrorMsg = ''
If (MetTestId NE '') then
If RowExists('MET_TEST', MetTestId) then
Open 'MET_TEST' to hTable then
Met_Test_Services('ClearPropsAndLimits', MetTestId)
If Error_Services('NoError') then
MetTestRec = Database_Services('ReadDataRow', 'MET_TEST', MetTestId)
If Error_Services('NoError') then
LotId = MetTestRec<MET_TEST.LOT_ID$>
If (LotId NE '') then
If RowExists('LOT', LotId) then
// Find specs from provided recipe, pattern, tool class, layer, etc.
PSNo = Xlate('LOT', LotId, 'PROD_SPEC_ID', 'X')
If PSNo NE '' then
If RowExists('PROD_SPEC', PSNo) then
SpecFound = False$
Layer = MetTestRec<MET_TEST.LAYER$>
ToolRecipe = MetTestRec<MET_TEST.TOOL_RECIPE$>
ToolPattern = MetTestRec<MET_TEST.TOOL_PATTERN$>
Tool = MetTestRec<MET_TEST.TOOL$>
ToolClass = MetTestRec<MET_TEST.TOOL_CLASS$>
InspectionRecipe = MetTestRec<MET_TEST.INSPECTION_RECIPE$>
If InspectionRecipe NE '' then
// Get Inspection values from PRS_STAGE record
PRSStageKey = PSNo:'*':InspectionRecipe
If RowExists('PRS_STAGE', PRSStageKey) then
MetTestRec<MET_TEST.PROPERTY_1_SPEC_MAX$> = Xlate('PRS_PROP', PRSPropKey, 'LPD', 'X')
If MetTestRec<MET_TEST.PROPERTY_1_SPEC_MAX$> NE '' then MetTestRec<MET_TEST.PROPERTY_1$> = 'LPD'
MetTestRec<MET_TEST.PROPERTY_2_SPEC_MAX$> = Xlate('PRS_PROP', PRSPropKey, 'SCRATCHES', 'X')
If MetTestRec<MET_TEST.PROPERTY_2_SPEC_MAX$> NE '' then MetTestRec<MET_TEST.PROPERTY_2$> = 'Scratches'
MetTestRec<MET_TEST.PROPERTY_3_SPEC_MAX$> = Xlate('PRS_PROP', PRSPropKey, 'SCRATCH_LEN', 'X')
If MetTestRec<MET_TEST.PROPERTY_3_SPEC_MAX$> NE '' then MetTestRec<MET_TEST.PROPERTY_3$> = 'Scratch Len'
MetTestRec<MET_TEST.PROPERTY_4_SPEC_MAX$> = Xlate('PRS_PROP', PRSPropKey, 'PITS', 'X')
If MetTestRec<MET_TEST.PROPERTY_4_SPEC_MAX$> NE '' then MetTestRec<MET_TEST.PROPERTY_4$> = 'Pits'
MetTestRec<MET_TEST.PROPERTY_5_SPEC_MAX$> = Xlate('PRS_PROP', PRSPropKey, 'MOUNDS', 'X')
If MetTestRec<MET_TEST.PROPERTY_5_SPEC_MAX$> NE '' then MetTestRec<MET_TEST.PROPERTY_5$> = 'Mounds'
MetTestRec<MET_TEST.PROPERTY_6_SPEC_MAX$> = Xlate('PRS_PROP', PRSPropKey, 'STACK_FAULTS', 'X')
If MetTestRec<MET_TEST.PROPERTY_6_SPEC_MAX$> NE '' then MetTestRec<MET_TEST.PROPERTY_6$> = 'Stack Faults'
MetTestRec<MET_TEST.PROPERTY_7_SPEC_MAX$> = Xlate('PRS_PROP', PRSPropKey, 'SPIKES', 'X')
If MetTestRec<MET_TEST.PROPERTY_7_SPEC_MAX$> NE '' then MetTestRec<MET_TEST.PROPERTY_7$> = 'Spikes'
MetTestRec<MET_TEST.PROPERTY_8_SPEC_MAX$> = Xlate('PRS_PROP', PRSPropKey, 'SPOTS', 'X')
If MetTestRec<MET_TEST.PROPERTY_8_SPEC_MAX$> NE '' then MetTestRec<MET_TEST.PROPERTY_8$> = 'Spots'
MetTestRec<MET_TEST.PROPERTY_9_SPEC_MAX$> = Xlate('PRS_PROP', PRSPropKey, 'FOV', 'X')
If MetTestRec<MET_TEST.PROPERTY_9_SPEC_MAX$> NE '' then MetTestRec<MET_TEST.PROPERTY_9$> = 'FOV'
MetTestRec<MET_TEST.PROPERTY_10_SPEC_MAX$> = Xlate('PRS_PROP', PRSPropKey, 'BL_DEFECTS', 'X')
If MetTestRec<MET_TEST.PROPERTY_10_SPEC_MAX$> NE '' then MetTestRec<MET_TEST.PROPERTY_10$> = 'BL Defects'
MetTestRec<MET_TEST.PROPERTY_11_SPEC_MAX$> = Xlate('PRS_PROP', PRSPropKey, 'BSIDE_SCRATCHES', 'X')
If MetTestRec<MET_TEST.PROPERTY_11_SPEC_MAX$> NE '' then MetTestRec<MET_TEST.PROPERTY_11$> = 'Backside Scratches'
MetTestRec<MET_TEST.PROPERTY_12_SPEC_MAX$> = Xlate('PRS_PROP', PRSPropKey, 'BSIDE_SCRATCH_LEN', 'X')
If MetTestRec<MET_TEST.PROPERTY_12_SPEC_MAX$> NE '' then MetTestRec<MET_TEST.PROPERTY_12$> = 'Backside Scratch Len'
MetTestRec<MET_TEST.PROPERTY_13_SPEC_MAX$> = Xlate('PRS_PROP', PRSPropKey, 'BSIDE_NODULES', 'X')
If MetTestRec<MET_TEST.PROPERTY_13_SPEC_MAX$> NE '' then MetTestRec<MET_TEST.PROPERTY_13$> = 'Backside Nodules'
MetTestRec<MET_TEST.PROPERTY_14_SPEC_MAX$> = Xlate('PRS_PROP', PRSPropKey, 'BSIDE_SPIKES', 'X')
If MetTestRec<MET_TEST.PROPERTY_14_SPEC_MAX$> NE '' then MetTestRec<MET_TEST.PROPERTY_14$> = 'Backside Spikes'
If ( Xlate('PRS_PROP', PRSPropKey, 'EDGE', 'X') EQ 1 ) then MetTestRec<MET_TEST.PROPERTY_15_SPEC_MAX$> = 0
If MetTestRec<MET_TEST.PROPERTY_15_SPEC_MAX$> NE '' then MetTestRec<MET_TEST.PROPERTY_14$> = 'Edge Defects'
MetTestRec<MET_TEST.SAMPLE_SIZE$> = 1
end else
ErrorMsg = 'Error in ':Service:' service. Error finding inspection specs. PRS_STAGE record "':PRSStageKey:'" does not exist.'
end
end else
Open 'DICT.PRS_PROP' to dPRSProp then
Open 'DICT.PRS_STAGE' to dPRSStage then
// Search PRS_PROP for matching layer, recipe, tool class, and tool pattern
Query = 'PS_NO':@VM:PSNo:@FM
If Layer NE '' then Query := 'LAYER_NO':@VM:Layer:@FM
If ToolRecipe NE '' then Query := 'MET_RECIPE':@VM:ToolRecipe:@FM
If ToolClass NE '' then Query := 'TOOL':@VM:ToolClass:@FM
If ToolPattern NE '' then Query := 'MET_RECIPE_PATTERN':@VM:ToolPattern:@FM
PRSPropKey = ''
PRSPropKeys = ''
Flag = ''
Btree.Extract(Query, 'PRS_PROP', dPRSProp, PRSPropKeys, 'E', Flag)
If Flag EQ 0 then
If (DCount(PRSPropKeys, @VM) EQ 1) then
SpecFound = True$
PRSPropKey = PRSPropKeys
// Get RAW_MIN and RAW_MAX from PRS_PROP record (MD5)
MetTestRec<MET_TEST.PROPERTY_1$> = Field(PRSPropKey, '*', 3, 1)
MetTestRec<MET_TEST.PROPERTY_1_SPEC_MIN$> = OConv(Xlate('PRS_PROP', PRSPropKey, 'RAW_MIN', 'X'), 'MD5')
MetTestRec<MET_TEST.PROPERTY_1_SPEC_MAX$> = OConv(Xlate('PRS_PROP', PRSPropKey, 'RAW_MAX', 'X'), 'MD5')
SpecToolPattern = Xlate('PRS_PROP', PRSPropKey, 'MET_RECIPE_PATTERN', 'X')
If SpecToolPattern NE '' then
SpecToolClass = Xlate('PRS_PROP', PRSPropKey, 'TOOL', 'X')
If SpecToolClass NE '' then
SampleSize = Tool_Services('GetNumPoints', SpecToolClass, SpecToolPattern)
If Error_Services('NoError') then
If SampleSize EQ '' then SampleSize = 1
MetTestRec<MET_TEST.SAMPLE_SIZE$> = SampleSize
end else
ErrorMsg = Error_Services('GetMessage')
end
end else
ErrorMsg = 'Error in ':Service:' service. TOOL (i.e., TOOL_CLASS) in PRS_PROP "':PRSPropKey:'" not set.'
end
end else
ErrorMsg = 'Error in ':Service:' service. MET_RECIPE_PATTERN in PRS_PROP "':PRSPropKey:'" not set.'
end
end
end
If Not(SpecFound) then
// Search PRS Stage for matching SURFSCAN_RECIPE
Query = 'PS_NO':@VM:PSNo:@FM
If ToolRecipe NE '' then Query := 'SURFSCAN_RECIPE':@VM:ToolRecipe:@FM
PRSStageKey = ''
PRSStageKeys = ''
Flag = ''
Btree.Extract(Query, 'PRS_STAGE', dPRSStage, PRSStageKeys, 'E', Flag)
If Flag EQ 0 then
If (DCount(PRSStageKeys, @VM) EQ 1) then
PRSStageKey = PRSStageKeys
PRSStageSpecSurfscanRecipes = Xlate('PRS_STAGE', PRSStageKey, 'SURFSCAN_RECIPE', 'X')
If PRSStageSpecSurfscanRecipes NE '' then
For each PRSStageSpecSurfscanRecipe in PRSStageSpecSurfscanRecipes using @VM Setting SpecSurfIndex
SpecFound = (PRSStageSpecSurfscanRecipe EQ ToolRecipe)
If SpecFound then
// Get sum of defects max (SURF_DEFECTS - MD0) and haze max (SURF_HAZE - MD2) from PRS_STAGE record (there is no min spec)
MetTestRec<MET_TEST.PROPERTY_1$> = 'SURFACE_SCAN_SUM_OF_DEFECTS_MIN'
MetTestRec<MET_TEST.PROPERTY_1_SPEC_MAX$> = Xlate('PRS_STAGE', PRSStageKey, 'SURF_DEFECTS', 'X')<0, SpecSurfIndex>
MetTestRec<MET_TEST.PROPERTY_2$> = 'SURFACE_SCAN_SUM_OF_DEFECTS_MAX'
MetTestRec<MET_TEST.PROPERTY_2_SPEC_MAX$> = Xlate('PRS_STAGE', PRSStageKey, 'SURF_DEFECTS', 'X')<0, SpecSurfIndex>
MetTestRec<MET_TEST.PROPERTY_3$> = 'SURFACE_SCAN_SUM_OF_DEFECTS_AVG'
MetTestRec<MET_TEST.PROPERTY_3_SPEC_MAX$> = Xlate('PRS_STAGE', PRSStageKey, 'SURF_DEFECTS', 'X')<0, SpecSurfIndex>
MetTestRec<MET_TEST.PROPERTY_4$> = 'SURFACE_SCAN_SUM_OF_DEFECTS'
MetTestRec<MET_TEST.PROPERTY_4_SPEC_MAX$> = Xlate('PRS_STAGE', PRSStageKey, 'SURF_DEFECTS', 'X')<0, SpecSurfIndex>
MetTestRec<MET_TEST.PROPERTY_5$> = 'SURFACE_SCAN_HAZE_AVG'
MetTestRec<MET_TEST.PROPERTY_5_SPEC_MAX$> = IConv(Xlate('PRS_STAGE', PRSStageKey, 'SURF_HAZE', 'X')<0, SpecSurfIndex>, 'MD2')
MetTestRec<MET_TEST.SAMPLE_SIZE$> = Xlate('PRS_STAGE', PRSStageKey, 'SS_SAMP_QTY', 'X')<0, SpecSurfIndex>
end
Until SpecFound
Next PRSStageSpecSurfscanRecipe
end
end
end else
ErrorMsg = 'Error in ':Service:' service. Error calling Btree.Extract on PRS_STAGE table.'
end
end
If Not(SpecFound) then
// Search PRS Stage for matching MET_RECIPE and optionally, matching MET_PATTERN
Query = 'PS_NO':@VM:PSNo:@FM
If ToolRecipe NE '' then Query := 'MET_RECIPE':@VM:ToolRecipe:@FM
If ToolPattern NE '' then Query := 'MET_RECIPE_PATTERN':@VM:ToolPattern:@FM
PRSStageKey = ''
PRSStageKeys = ''
Flag = ''
Btree.Extract(Query, 'PRS_STAGE', dPRSStage, PRSStageKeys, 'E', Flag)
If Flag EQ 0 then
If (DCount(PRSStageKeys, @VM) EQ 1) then
PRSStageKey = PRSStageKeys
PRSStageSpecMetRecipes = Xlate('PRS_STAGE', PRSStageKey, 'MET_RECIPE', 'X')
PRSStageSpecMetPatterns = Xlate('PRS_STAGE', PRSStageKey, 'MET_RECIPE_PATTERN', 'X')
If PRSStageSpecMetRecipes NE '' then
For each PRSStageSpecMetRecipe in PRSStageSpecMetRecipes using @VM setting SpecMetIndex
If ToolPattern NE '' then
PRSStageSpecMetPattern = PRSStageSpecMetPatterns<0, SpecMetIndex>
SpecFound = ( (PRSStageSpecMetRecipe EQ ToolRecipe) and (PRSStageSpecMetPattern = ToolPattern) )
end else
SpecFound = (PRSStageSpecMetRecipe EQ ToolRecipe)
end
If SpecFound then
// Get min and max from MET_MIN and MET_MAX in PRS_STAGE record (MD0)
MetTestRec<MET_TEST.PROPERTY_1$> = Xlate('PRS_STAGE', PRSStageKey, 'MET_PROP', 'X')<0, SpecMetIndex>
MetTestRec<MET_TEST.PROPERTY_1_SPEC_MIN$> = Xlate('PRS_STAGE', PRSStageKey, 'MET_MIN', 'X')<0, SpecMetIndex>
MetTestRec<MET_TEST.PROPERTY_1_SPEC_MAX$> = Xlate('PRS_STAGE', PRSStageKey, 'MET_MAX', 'X')<0, SpecMetIndex>
If MetTestRec<MET_TEST.PROPERTY_1$> EQ 'CRES' then
MetTestRec<MET_TEST.PROPERTY_2$> = 'PHASE'
MetTestRec<MET_TEST.PROPERTY_2_SPEC_MIN$> = Xlate('PRS_STAGE', PRSStageKey, 'MET_PHASE_MIN', 'X')<0, SpecMetIndex>
end
SpecToolPattern = Xlate('PRS_STAGE', PRSStageKey, 'MET_RECIPE_PATTERN', 'X')<0, SpecMetIndex>
If SpecToolPattern NE '' then
SpecToolClass = Xlate('PRS_STAGE', PRSStageKey, 'MET_TOOL_CLASS', 'X')<0, SpecMetIndex>
If SpecToolClass NE '' then
SampleSize = Tool_Services('GetNumPoints', SpecToolClass, SpecToolPattern)
If Error_Services('NoError') then
If SampleSize EQ '' then SampleSize = 1
MetTestRec<MET_TEST.SAMPLE_SIZE$> = SampleSize
end else
ErrorMsg = Error_Services('GetMessage')
end
end else
ErrorMsg = 'Error in ':Service:' service. MET_TOOL_CLASS in PRS_STAGE "':PRSStageKey:'" not set.'
end
end else
ErrorMsg = 'Error in ':Service:' service. MET_RECIPE_PATTERN in PRS_STAGE "':PRSStageKey:'" not set.'
end
end
Until SpecFound
Next PRSStageSpecMetRecipe
end
end
end else
ErrorMsg = 'Error in ':Service:' service. Error calling Btree.Extract on PRS_STAGE table.'
end
end
If Not(SpecFound) then
// Last resort - look up matching spec limits by PSN and tool class
Query = 'PS_NO':@VM:PSNo:@FM
If ToolClass NE '' then Query := 'MET_TOOL_CLASS':@VM:ToolClass:@FM
PRSStageKey = ''
PRSStageKeys = ''
Flag = ''
Btree.Extract(Query, 'PRS_STAGE', dPRSStage, PRSStageKeys, 'E', Flag)
If Flag EQ 0 then
If (DCount(PRSStageKeys, @VM) EQ 1) then
PRSStageKey = PRSStageKeys
PRSStageSpecToolClasses = Xlate('PRS_STAGE', PRSStageKey, 'MET_TOOL_CLASS', 'X')
If PRSStageSpecToolClasses NE '' then
For each PRSStageSpecToolClass in PRSStageSpecToolClasses using @VM setting SpecMetIndex
SpecFound = (PRSStageSpecToolClass EQ ToolClass)
If SpecFound then
// Get min and max from MET_MIN and MET_MAX in PRS_STAGE record (MD0)
MetTestRec<MET_TEST.PROPERTY_1$> = Xlate('PRS_STAGE', PRSStageKey, 'MET_PROP', 'X')<0, SpecMetIndex>
MetTestRec<MET_TEST.PROPERTY_1_SPEC_MIN$> = Xlate('PRS_STAGE', PRSStageKey, 'MET_MIN', 'X')<0, SpecMetIndex>
MetTestRec<MET_TEST.PROPERTY_1_SPEC_MAX$> = Xlate('PRS_STAGE', PRSStageKey, 'MET_MAX', 'X')<0, SpecMetIndex>
If MetTestRec<MET_TEST.PROPERTY_1$> EQ 'CRES' then
MetTestRec<MET_TEST.PROPERTY_2$> = 'PHASE'
MetTestRec<MET_TEST.PROPERTY_2_SPEC_MIN$> = Xlate('PRS_STAGE', PRSStageKey, 'MET_PHASE_MIN', 'X')<0, SpecMetIndex>
end
SpecToolPattern = Xlate('PRS_STAGE', PRSStageKey, 'MET_RECIPE_PATTERN', 'X')<0, SpecMetIndex>
If SpecToolPattern NE '' then
SpecToolClass = Xlate('PRS_STAGE', PRSStageKey, 'MET_TOOL_CLASS', 'X')<0, SpecMetIndex>
If SpecToolClass NE '' then
SampleSize = Tool_Services('GetNumPoints', SpecToolClass, SpecToolPattern)
If Error_Services('NoError') then
If SampleSize EQ '' then SampleSize = 1
MetTestRec<MET_TEST.SAMPLE_SIZE$> = SampleSize
end else
ErrorMsg = Error_Services('GetMessage')
end
end else
ErrorMsg = 'Error in ':Service:' service. MET_TOOL_CLASS in PRS_STAGE "':PRSStageKey:'" not set.'
end
end else
ErrorMsg = 'Error in ':Service:' service. MET_RECIPE_PATTERN in PRS_STAGE "':PRSStageKey:'" not set.'
end
end
Until SpecFound
Next PRSStageSpecMetRecipe
end
end
end else
ErrorMsg = 'Error in ':Service:' service. Error calling Btree.Extract on PRS_STAGE table.'
end
If Not(SpecFound) then
// Search PRS_PROP for matching PSN, layer, and tool class
Query = 'PS_NO':@VM:PSNo:@FM
If Layer NE '' then Query := 'LAYER_NO':@VM:Layer:@FM
If ToolClass NE '' then Query := 'TOOL':@VM:ToolClass:@FM
PRSPropKey = ''
PRSPropKeys = ''
Flag = ''
Btree.Extract(Query, 'PRS_PROP', dPRSProp, PRSPropKeys, 'E', Flag)
If Flag EQ 0 then
If (DCount(PRSPropKeys, @VM) EQ 1) then
SpecFound = True$
PRSPropKey = PRSPropKeys
// Get RAW_MIN and RAW_MAX from PRS_PROP record (MD5)
MetTestRec<MET_TEST.PROPERTY_1$> = Field(PRSPropKey, '*', 3, 1)
MetTestRec<MET_TEST.PROPERTY_1_SPEC_MIN$> = OConv(Xlate('PRS_PROP', PRSPropKey, 'RAW_MIN', 'X'), 'MD5')
MetTestRec<MET_TEST.PROPERTY_1_SPEC_MAX$> = OConv(Xlate('PRS_PROP', PRSPropKey, 'RAW_MAX', 'X'), 'MD5')
SpecToolPattern = Xlate('PRS_PROP', PRSPropKey, 'MET_RECIPE_PATTERN', 'X')
If SpecToolPattern NE '' then
SpecToolClass = Xlate('PRS_PROP', PRSPropKey, 'TOOL', 'X')
If SpecToolClass NE '' then
SampleSize = Tool_Services('GetNumPoints', SpecToolClass, SpecToolPattern)
If Error_Services('NoError') then
If SampleSize EQ '' then SampleSize = 1
MetTestRec<MET_TEST.SAMPLE_SIZE$> = SampleSize
end else
ErrorMsg = Error_Services('GetMessage')
end
end else
ErrorMsg = 'Error in ':Service:' service. TOOL (i.e., TOOL_CLASS) in PRS_PROP "':PRSPropKey:'" not set.'
end
end else
ErrorMsg = 'Error in ':Service:' service. MET_RECIPE_PATTERN in PRS_PROP "':PRSPropKey:'" not set.'
end
end
end else
ErrorMsg = 'Error in ':Service:' service. Error calling Btree.Extract on PRS_PROP table.'
end
end
end
end else
ErrorMsg = 'Error in ':Service:' service. Error opening DICT.PRS_STAGE table.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Error opening DICT.PRS_PROP table.'
end
If ErrorMsg EQ '' then
If SpecFound then
// Update MET_TEST record
Database_Services('WriteDataRow', 'MET_TEST', MetTestId, MetTestRec)
If Error_Services('HasError') then
ErrorMsg = 'Error in ':Service:' service. Error writing MET_TEST record. Error message: ':Error_Services('GetMessage')
end
end else
ErrorMsg = 'Error in ':Service:' service. Error finding metrology specs.'
end
end
end
end else
ErrorMsg = 'Error in ':Service:' service. Error retrieving metrology specs. PROD_SPEC "':PSNo:'" does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Error retrieving metrology specs. Null PROD_SPEC_ID in LOT record "':LotId:'".'
end
end else
ErrorMsg = 'Error in ':Service:' service. LotId "':LotId:'" does not exist in the LOT table.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null LotId passed into service.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
end
end else
ErrorMsg = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
end
end else
ErrorMsg = 'Error in ':Service:' service. Failed to open MET_TEST table.'
end
end else
ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null MetTestId passed into service.'
end
If ErrorMsg EQ '' then
Response = True$
end else
Error_Services('Add', ErrorMsg)
Response = False$
end
end service
//----------------------------------------------------------------------------------------------------------------------
// ClearPropsAndLimits
//
// Input:
// MetTestId [Required] - Key of MET_TEST record to update.
//
// Output:
// Returns true if successful, false otherwise.
//
// Clears columns PROPERTY_1, PROPERTY_1_MIN, PROPERTY_1_MAX, ... PROPERTY_N, PROPERTY_N_MIN, PROPERTY_N_MAX.
//----------------------------------------------------------------------------------------------------------------------
Service ClearPropsAndLimits(MetTestId)
ErrorMsg = ''
If (MetTestId NE '') then
If RowExists('MET_TEST', MetTestId) then
MetTestRec = Database_Services('ReadDataRow', 'MET_TEST', MetTestId)
If Error_Services('NoError') then
For PropertyIndex = 1 to NUM_PROPERTIES$
PropColNo = Xlate('DICT.MET_TEST', 'PROPERTY_':PropertyIndex, DICT_COLUMN_NO$, 'X')
PropMinColNo = Xlate('DICT.MET_TEST', 'PROPERTY_':PropertyIndex:'_SPEC_MIN', DICT_COLUMN_NO$, 'X')
PropMaxColNo = Xlate('DICT.MET_TEST', 'PROPERTY_':PropertyIndex:'_SPEC_MAX', DICT_COLUMN_NO$, 'X')
MetTestRec<PropColNo> = ''
MetTestRec<PropMinColNo> = ''
MetTestRec<PropMaxColNo> = ''
Next PropertyIndex
Database_Services('WriteDataRow', 'MET_TEST', MetTestId, MetTestRec, True$, False$, False$)
If Error_Services('HasError') then
ErrorMsg = Error_Services('GetMessage')
end
end else
ErrorMsg = Error_Services('GetMessage')
end
end else
ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null MetTestId or ToolId passed into service.'
end
If ErrorMsg EQ '' then
Response = True$
end else
Error_Services('Add', ErrorMsg)
Response = False$
end
end service
//----------------------------------------------------------------------------------------------------------------------
// SetMetTestRecipe
//
// Input:
// MetTestId [Required] - Key of MET_TEST record to update.
// MetRecipe [Required] - Recipe name of metrology test.
//
// Output:
// Returns true if successful, false otherwise.
//
// Sets the TOOL_RECIPE column of a MET_TEST record.
//----------------------------------------------------------------------------------------------------------------------
Service SetMetTestRecipe(MetTestId, MetRecipe)
ErrorMsg = ''
If ( (MetTestId NE '') and (MetRecipe NE '') ) then
If RowExists('MET_TEST', MetTestId) then
Open 'MET_TEST' to hTable then
WriteV MetRecipe on hTable, MetTestId, MET_TEST.TOOL_RECIPE$ else
ErrorMsg = 'Error in ':Service:' service. Failed to write ':MetRecipe:' on TOOL_RECIPE column for MET_TEST ':MetTestId
end
end else
ErrorMsg = 'Error in ':Service:' service. Failed to open MET_TEST table.'
end
end else
ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null MetTestId or ToolId passed into service.'
end
If ErrorMsg EQ '' then
Response = True$
end else
Error_Services('Add', ErrorMsg)
Response = False$
end
end service
//----------------------------------------------------------------------------------------------------------------------
// SetMetTestPattern
//
// Input:
// MetTestId [Required] - Key of MET_TEST record to update.
// MetPattern [Required] - Pattern name of metrology test.
//
// Output:
// Returns true if successful, false otherwise.
//
// Sets the TOOL_PATTERN column of a MET_TEST record.
//----------------------------------------------------------------------------------------------------------------------
Service SetMetTestPattern(MetTestId, MetPattern)
ErrorMsg = ''
If ( (MetTestId NE '') and (MetPattern NE '') ) then
If RowExists('MET_TEST', MetTestId) then
Open 'MET_TEST' to hTable then
WriteV MetPattern on hTable, MetTestId, MET_TEST.TOOL_PATTERN$ else
ErrorMsg = 'Error in ':Service:' service. Failed to write ':MetPattern:' on TOOL_PATTERN column for MET_TEST ':MetTestId
end
end else
ErrorMsg = 'Error in ':Service:' service. Failed to open MET_TEST table.'
end
end else
ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null MetTestId or ToolId passed into service.'
end
If ErrorMsg EQ '' then
Response = True$
end else
Error_Services('Add', ErrorMsg)
Response = False$
end
end service
//----------------------------------------------------------------------------------------------------------------------
// SetMetTestTool
//
// Input:
// MetTestId [Required] - Key of MET_TEST record to update.
// ToolId [Required] - Key of TOOL record, which represents the tool the metrology test was performed on.
//
// Output:
// Returns true if successful, false otherwise.
//
// Sets the TOOL column of a MET_TEST record.
//----------------------------------------------------------------------------------------------------------------------
Service SetMetTestTool(MetTestId, ToolId)
ErrorMsg = ''
If ( (MetTestId NE '') and (ToolId NE '') ) then
If RowExists('MET_TEST', MetTestId) then
Open 'MET_TEST' to hTable then
WriteV ToolId on hTable, MetTestId, MET_TEST.TOOL$ else
ErrorMsg = 'Error in ':Service:' service. Failed to write ':ToolId:' on TOOL column for MET_TEST ':MetTestId
end
end else
ErrorMsg = 'Error in ':Service:' service. Failed to open MET_TEST table.'
end
end else
ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null MetTestId or ToolId passed into service.'
end
If ErrorMsg EQ '' then
Response = True$
end else
Error_Services('Add', ErrorMsg)
Response = False$
end
end service
//----------------------------------------------------------------------------------------------------------------------
// SetMetTestDtm
//
// Input:
// MetTestId [Required] - Key of MET_TEST record to update.
// TestDtm [Required] - Datetime of the metrology test. Can be internal or external datetime value.
//
// Output:
// Returns true if successful, false otherwise.
//
// Sets the TEST_DTM column of a MET_TEST record.
//----------------------------------------------------------------------------------------------------------------------
Service SetMetTestDtm(MetTestId, TestDtm)
ErrorMsg = ''
If ( (MetTestId NE '') and (TestDtm NE '') ) then
If RowExists('MET_TEST', MetTestId) then
Open 'MET_TEST' to hTable then
If Not(Num(TestDtm)) then
Swap ' AM' with 'AM' in TestDtm
Swap ' PM' with 'PM' in TestDtm
TestDtm = IConv(TestDtm,'DT')
end
WriteV TestDtm on hTable, MetTestId, MET_TEST.TEST_DTM$ else
ErrorMsg = 'Error in ':Service:' service. Failed to write ':OConv(TestDtm, 'DT2/^H')
ErrorMsg := ' on TEST_DTM column for MET_TEST ':MetTestId
end
end else
ErrorMsg = 'Error in ':Service:' service. Failed to open MET_TEST table.'
end
end else
ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null MetTestId or ToolId passed into service.'
end
If ErrorMsg EQ '' then
Response = True$
end else
Error_Services('Add', ErrorMsg)
Response = False$
end
end service
//----------------------------------------------------------------------------------------------------------------------
// SetMetTestSlot
//
// Input:
// MetTestId [Required] - Key of MET_TEST record to update.
// Slot [Required] - Slot number of metrology test. N/A to cassette level tests like Tencor surface scans.
//
// Output:
// Returns true if successful, false otherwise.
//
// Sets the SLOT column of a MET_TEST record.
//----------------------------------------------------------------------------------------------------------------------
Service SetMetTestSlot(MetTestId, Slot)
ErrorMsg = ''
If ( (MetTestId NE '') and (Slot NE '') ) then
If RowExists('MET_TEST', MetTestId) then
Open 'MET_TEST' to hTable then
WriteV Slot on hTable, MetTestId, MET_TEST.SLOT$ else
ErrorMsg = 'Error in ':Service:' service. Failed to write ':Slot:' on SLOT column for MET_TEST ':MetTestId
end
end else
ErrorMsg = 'Error in ':Service:' service. Failed to open MET_TEST table.'
end
end else
ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null MetTestId or ToolId passed into service.'
end
If ErrorMsg EQ '' then
Response = True$
end else
Error_Services('Add', ErrorMsg)
Response = False$
end
end service
//----------------------------------------------------------------------------------------------------------------------
// AddProperty (aka parameter)
//
// Input:
// MetTestId [Required] - Key of MET_TEST record to update.
// PropName [Required] - Slot number of metrology test. N/A to cassette level tests like Tencor surface scans.
// PropMin [Optional] - Spec minimum value to validate the property values against.
// PropMax [Optional] - Spec maxiumum value to validate the property values against.
//
// Output:
// Returns true if successful, false otherwise.
//
// Adds a property to a MET_TEST record.
// Note: If a PropMin and PropMax are not set for the property, it will not be validated within MET_TEST_DATA actions.
//----------------------------------------------------------------------------------------------------------------------
Service AddProperty(MetTestId, PropName, PropMin, PropMax)
ErrorMsg = ''
If ( (MetTestId NE '') and (PropName NE '') ) then
If RowExists('MET_TEST', MetTestId) then
MetTestRec = Database_Services('ReadDataRow', 'MET_TEST', MetTestId)
If Error_Services('NoError') then
PosFound = False$
PropAlreadyPresent = False$
For PropertyIndex = 1 to NUM_PROPERTIES$
ThisPropName = Xlate('MET_TEST', MetTestId, "PROPERTY_":PropertyIndex, 'X')
If ( (ThisPropName EQ '') and Not(PropAlreadyPresent) ) then
PosFound = True$
PropNameIndex = Xlate('DICT.MET_TEST', 'PROPERTY_':PropertyIndex, DICT_COLUMN_NO$, 'X')
PropMinIndex = Xlate('DICT.MET_TEST', 'PROPERTY_':PropertyIndex:'_SPEC_MIN', DICT_COLUMN_NO$, 'X')
PropMaxIndex = Xlate('DICT.MET_TEST', 'PROPERTY_':PropertyIndex:'_SPEC_MAX', DICT_COLUMN_NO$, 'X')
end
If (ThisPropName EQ PropName) then PropAlreadyPresent = True$
Until PropAlreadyPresent or PosFound
Next PropertyIndex
Begin Case
Case PropAlreadyPresent
ErrorMsg = 'Error in ':Service:' service. Property ':PropName:' already exists in MET_TEST ':MetTestId
Case PosFound
MetTestRec<PropNameIndex> = PropName
MetTestRec<PropMinIndex> = PropMin
MetTestRec<PropMaxIndex> = PropMax
Database_Services('WriteDataRow', 'MET_TEST', MetTestId, MetTestRec, True$, False$, False$)
Case Otherwise$
ErrorMsg = 'Error in ':Service:' service. Failed to find empty property column in MET_TEST ':MetTestId
End Case
end else
ErrorMsg = 'Error in ':Service:' service. Error reading MET_TEST ':MetTestId:'. Error message: ':Error_Services('GetMessage')
end
end else
ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null MetTestId, PropName, or PropMin/PropMax passed into service.'
end
If ErrorMsg EQ '' then
Response = True$
end else
Error_Services('Add', ErrorMsg)
Response = False$
end
end service
//----------------------------------------------------------------------------------------------------------------------
// RemoveProperty
//
// Input:
// MetTestId [Required] - Key of MET_TEST record to update.
// PropName [Required] - Slot number of metrology test. N/A to cassette level tests like Tencor surface scans.
//
// Output:
// Returns true if successful, false otherwise.
//
// Removes a property from a MET_TEST record.
//----------------------------------------------------------------------------------------------------------------------
Service RemoveProperty(MetTestId, PropName)
ErrorMsg = ''
If ( (MetTestId NE '') and (PropName NE '') ) then
If RowExists('MET_TEST', MetTestId) then
MetTestRec = Database_Services('ReadDataRow', 'MET_TEST', MetTestId)
If Error_Services('NoError') then
PosFound = False$
For PropertyIndex = 1 to NUM_PROPERTIES$
ThisPropName = Xlate('MET_TEST', MetTestId, "PROPERTY_":PropertyIndex, 'X')
If (ThisPropName EQ PropName) then
PosFound = True$
PropNameIndex = Xlate('DICT.MET_TEST', 'PROPERTY_':PropertyIndex, DICT_COLUMN_NO$, 'X')
PropMinIndex = Xlate('DICT.MET_TEST', 'PROPERTY_':PropertyIndex:'_SPEC_MIN', DICT_COLUMN_NO$, 'X')
PropMaxIndex = Xlate('DICT.MET_TEST', 'PROPERTY_':PropertyIndex:'_SPEC_MAX', DICT_COLUMN_NO$, 'X')
end
Until PosFound
Next PropertyIndex
If PosFound then
MetTestRec<PropNameIndex> = ''
MetTestRec<PropMinIndex> = ''
MetTestRec<PropMaxIndex> = ''
Database_Services('WriteDataRow', 'MET_TEST', MetTestId, MetTestRec, True$, False$, False$)
end else
ErrorMsg = 'Error in ':Service:' service. Failed to find property column containing "':PropName:'" in MET_TEST record ':MetTestId
end
end else
ErrorMsg = 'Error in ':Service:' service. Error reading MET_TEST ':MetTestId:'. Error message: ':Error_Services('GetMessage')
end
end else
ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null MetTestId, PropName, or PropMin/PropMax passed into service.'
end
If ErrorMsg EQ '' then
Response = True$
end else
Error_Services('Add', ErrorMsg)
Response = False$
end
end service
//----------------------------------------------------------------------------------------------------------------------
// ConvertRecordToJson
//
// Input:
// MetTestId [Required] - Key of MET_TEST record to update.
//
// Output:
// metTest JSON object containing parent and child record details
//
// Converts a MET_TEST and its child MET_TEST_DATA records into a JSON object.
//----------------------------------------------------------------------------------------------------------------------
Service ConvertRecordToJson(MetTestId)
MetTestJSON = ''
ErrorMsg = ''
If MetTestId NE '' then
If RowExists('MET_TEST', MetTestId) then
Database_Services('ActivateRecord', 'MET_TEST', MetTestId)
If Error_Services('NoError') then
objJSON = ''
If SRP_JSON(objJSON, 'New', 'Object') then
MetTestDataIds = {MET_TEST_DATA_IDS}
SRP_JSON(objJSON, 'SetValue', 'keyId', @ID, 'String')
SRP_JSON(objJSON, 'SetValue', 'lotId', {LOT_ID}, 'String')
SRP_JSON(objJSON, 'SetValue', 'legacyLotId', {LEGACY_LOT_ID}, 'String')
SRP_JSON(objJSON, 'SetValue', 'lotOperationId', {LOT_OPERATION_ID}, 'String')
TestDtm = Date_Services('ConvertDateTimeToISO8601', {TEST_DTM})
SRP_JSON(objJSON, 'SetValue', 'testDtm', TestDtm)
SRP_JSON(objJSON, 'SetValue', 'toolRecipe', {TOOL_RECIPE}, 'String')
SRP_JSON(objJSON, 'SetValue', 'toolPattern', {TOOL_PATTERN}, 'String')
SRP_JSON(objJSON, 'SetValue', 'inspectionRecipe', {INSPECTION_RECIPE}, 'String')
SRP_JSON(objJSON, 'SetValue', 'sampleSize', {SAMPLE_SIZE}, 'Number')
SRP_JSON(objJSON, 'SetValue', 'tool', {TOOL}, 'String')
ToolClass = XLATE('TOOL', {TOOL}, TOOL_CLASS$, 'X')
SRP_JSON(objJSON, 'SetValue', 'toolClass', ToolClass, 'String')
SRP_JSON(objJSON, 'SetValue', 'layer', {LAYER})
SRP_JSON(objJSON, 'SetValue', 'zone', {ZONE})
SRP_JSON(objJSON, 'SetValue', 'slot', {SLOT}, 'Number')
SRP_JSON(objJSON, 'SetValue', 'outOfSpec', {OUT_OF_SPEC}, 'Boolean')
SRP_JSON(objJSON, 'SetValue', 'complete', {COMPLETE}, 'Boolean')
objMetPropArray = ''
If SRP_JSON(objMetPropArray, 'New', 'Array') then
For PropIndex = 1 to NUM_PROPERTIES$
PropName = Xlate('MET_TEST', MetTestId, 'PROPERTY_':PropIndex, 'X')
PropVals = Xlate('MET_TEST_DATA', MetTestDataIds, 'PROPERTY_':PropIndex:'_VALUE', 'X')
If ( (PropName NE '') or (PropVals NE '') ) then
objMetProp = ''
If SRP_JSON(objMetProp, 'New', 'Object') then
PropSpecMin = Xlate('MET_TEST', MetTestId, 'PROPERTY_':PropIndex:'_SPEC_MIN', 'X')
PropSpecMax = Xlate('MET_TEST', MetTestId, 'PROPERTY_':PropIndex:'_SPEC_MAX', 'X')
PropPositions = Xlate('MET_TEST_DATA', MetTestDataIds, 'POSITION', 'X')
PropOutOfSpecs = Xlate('MET_TEST_DATA', MetTestDataIds, 'PROPERTY_':PropIndex:'_OUT_OF_SPEC', 'X')
SRP_JSON(objMetProp, 'SetValue', 'property', PropName)
SRP_JSON(objMetProp, 'SetValue', 'propertySpecMin', PropSpecMin, 'Number')
SRP_JSON(objMetProp, 'SetValue', 'propertySpecMax', PropSpecMax, 'Number')
objDatapointsArray = ''
If SRP_JSON(objDatapointsArray, 'New', 'Array') then
For each Datapoint in PropVals using @VM setting vPos
If Datapoint NE '' then
objDatapoint = ''
If SRP_JSON(objDatapoint, 'New', 'Object') then
Position = PropPositions<0, vPos>
OutOfSpec = PropOutofSpecs<0, vPos>
SRP_JSON(objDatapoint, 'SetValue', 'position', Position, 'Number')
SRP_JSON(objDatapoint, 'SetValue', 'value', Datapoint, 'Number')
SRP_JSON(objDatapoint, 'SetValue', 'outOfSpec', OutOfSpec, 'Boolean')
SRP_JSON(objDatapointsArray, 'Add', objDatapoint)
SRP_JSON(objDatapoint, 'Release')
end else
ErrorMsg = 'Error in ':Service:' service. Error initializing objDatapoint object.'
end
end
Next Datapoint
SRP_JSON(objMetProp, 'Set', 'datapoints', objDataPointsArray)
SRP_JSON(objDatapointsArray, 'Release')
end else
ErrorMsg = 'Error in ':Service:' service. Error initializing objDatapointsArray object.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Error initializing objMetProp object.'
end
SRP_JSON(objMetPropArray, 'Add', objMetProp)
SRP_JSON(objMetProp, 'Release')
end
Next PropIndex
SRP_JSON(objJSON, 'Set', 'properties', objMetPropArray)
SRP_JSON(objMetPropArray, 'Release')
end else
ErrorMsg = 'Error in ':Service:' service. Error initializing objMetPropArray object.'
end
MetTestJSON = SRP_JSON(objJSON, 'Stringify', 'Styled')
SRP_JSON(objJSON, 'Release')
end else
ErrorMsg = 'Error in ':Service:' service. Error initializing objJSON object.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Error reading MET_TEST ':MetTestId:'.'
end
end else
ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null MetTestId passed into service'
end
If ErrorMsg EQ '' then
Response = MetTestJSON
end else
Error_Services('Add', ErrorMsg)
end
end service
//----------------------------------------------------------------------------------------------------------------------
// GetMetTestsByLotId
//
// Input:
// LotId [Required] - Key of LOT record to search MET_TEST table for related records.
//
// Output:
// MET_TEST key ids.
//
//----------------------------------------------------------------------------------------------------------------------
Service GetMetTestsByLotId(LotId)
ErrorMsg = ''
MetTestIds = ''
If LotId NE '' then
If RowExists('LOT', LotId) then
Extract_Si_Keys('MET_TEST', 'LOT_ID', LotId, MetTestIds)
end else
ErrorMsg = 'Error in ':Service:' service. LOT ':LotId:' does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null LotId passed into service.'
end
If ErrorMsg EQ '' then
Response = MetTestIds
end else
Error_Services('Add', ErrorMsg)
end
end service
//----------------------------------------------------------------------------------------------------------------------
// GetMetTestsByLotId
//
// Input:
// LotId [Required] - Key of LOT record to search MET_TEST table for related records.
//
// Output:
// MET_TEST key ids.
//
//----------------------------------------------------------------------------------------------------------------------
Service GetMetTests(LotId, LegacyLotId, ToolId, ExcludeAssociated, MatchClass, FromDtm, ToDtm)
ErrorMsg = ''
MetTestIds = ''
RespMetTestIds = ''
If LotId NE '' then
If RowExists('LOT', LotId) then
Open 'DICT.MET_TEST' to DictVar then
SearchString = ''
If MatchClass NE '' then
If DCount(MatchClass, @VM) GT 1 then
SearchString := 'TOOL_CLASS':@VM:MatchClass<1,1>
for i = 2 to DCount(MatchClass, @VM)
SearchString := @VM : ';':MatchClass<1,i>
Next i
SearchString := @FM
end else
SearchString := 'TOOL_CLASS':@VM:MatchClass:@FM
end
end
If LotId NE '' then
SearchString := 'LOT_ID':@VM:LotId:@FM
end
If LegacyLotId NE '' then
SearchString := 'LEGACY_LOT_ID':@VM:LegacyLotId:@FM
end
If ToolId NE '' then
SearchString := 'TOOL':@VM:ToolId:@FM
end
if FromDtm NE '' then
FromDtm = FromDtm + 0.000001
If ToDtm NE '' then
ToDtm = ToDtm + 0.000001
end else
ToDtm = DateTime()
end
SearchString := 'TEST_DTM':@VM:FromDtm:'~':ToDtm:@FM
end
Btree.Extract(SearchString, 'MET_TEST', DictVar, MetTestIds, '', '')
If Not(Get_status(errCode)) then
If MetTestIds NE '' then
If ExcludeAssociated then
for each MetTestId in MetTestIds using @VM setting mPos
MetTestLotOperationId = Database_Services('ReadDataColumn', 'MET_TEST', MetTestId, MET_TEST.LOT_OPERATION_ID$, True$, 0, False$)
If MetTestLotOperationId EQ '' then
RespMetTestIds<1,-1> = MetTestId
end
Next MetTestId
end else
RespMetTestIds = MetTestIds
end
end
end else
ErrorMsg = ErrCode
end
end else
ErrorMsg = 'Error in ' : Service : ' service. Error opening MET_TEST dictionary.'
end
end else
ErrorMsg = 'Error in ':Service:' service. LOT ':LotId:' does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null LotId passed into service.'
end
If ErrorMsg EQ '' then
Response = RespMetTestIds
end else
Error_Services('Add', ErrorMsg)
end
end service
//----------------------------------------------------------------------------------------------------------------------
// AttachMetTestToLotOperation
//
// Input:
// MetTestId [Required] - Key of MET_TEST record to relate.
// LotOperationId [Required] - Key of LOT_OPERATION record to relate.
//
// Output:
// True$ (1) if successful, False$ (0) otherwise.
//
//----------------------------------------------------------------------------------------------------------------------
Service AttachMetTestToLotOperation(MetTestId, LotOperationId, UserId)
ErrorMsg = ''
If ( (MetTestId NE '') and (LotOperationId NE '') ) then
If RowExists('MET_TEST', MetTestId) then
If RowExists('LOT_OPERATION', LotOperationId) then
Open 'MET_TEST' to hTable then
WriteV LotOperationId on hTable, MetTestId, MET_TEST.LOT_OPERATION_ID$ then
LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$)
LotOperationRec<LOT_OPERATION_MET_TEST_ID$> = Insert(LotOperationRec<LOT_OPERATION_MET_TEST_ID$>, 1, -1, 1, MetTestId)
Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationId, LotOperationRec)
LotId = LotOperationRec<LOT_OPERATION_LOT_ID$>
EquipmentId = Database_Services('ReadDataColumn', 'MET_TEST', MetTestId, MET_TEST.TOOL$, True$, 0, False$)
Lot_Event_Services('CreateLotEvent', LotId, DateTime(), 'MET_TEST', 'Metrology attached to lot.', EquipmentId, UserId)
end else
ErrorMsg = 'Error in ':Service:' service. Failed to write ':LotOperationId
ErrorMsg := ' on LOT_OPERATION_ID column for MET_TEST ':MetTestId
end
end else
ErrorMsg = 'Error in ':Service:' service. Failed to open MET_TEST table.'
end
end else
ErrorMsg = 'Error in ':Service:' service. LOT_OPERATION ':LotOperationId:' does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null MetTestId or LotOperationId passed into service.'
end
If ErrorMsg EQ '' then
Response = True$
end else
Error_Services('Add', ErrorMsg)
Response = False$
end
end service
Service RemoveMetTestFromLotOperation(MetTestId, LotOperationId, UserId)
ErrorMsg = ''
If ( (MetTestId NE '') and (LotOperationId NE '') ) then
If RowExists('MET_TEST', MetTestId) then
If RowExists('LOT_OPERATION', LotOperationId) then
MetTestRec = Database_Services('ReadDataRow', 'MET_TEST', MetTestId, True$, 0, False$)
MetTestRec<MET_TEST.LOT_OPERATION_ID$> = ''
Database_Services('WriteDataRow', 'MET_TEST', MetTestId, MetTestRec)
If Error_Services('NoError') then
LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$)
Locate MetTestId in LotOperationRec<LOT_OPERATION_MET_TEST_ID$> using @VM setting MetTestPos then
LotOperationRec<LOT_OPERATION_MET_TEST_ID$> = Delete(LotOperationRec<LOT_OPERATION_MET_TEST_ID$>, 1, MetTestPos, 1)
end
Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationId, LotOperationRec)
LotId = LotOperationRec<LOT_OPERATION_LOT_ID$>
EquipmentId = Database_Services('ReadDataColumn', 'MET_TEST', MetTestId, MET_TEST.TOOL$, True$, 0, False$)
Lot_Event_Services('CreateLotEvent', LotId, DateTime(), 'MET_TEST', 'Metrology attached to lot.', EquipmentId, UserId)
end else
ErrorMsg = 'Error in ':Service:' service. Error removing MET_TEST ':MetTestId:' from operation.'
end
end
end else
ErrorMsg = 'Error in ':Service:' service. MET_TEST ':MetTestId:' does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null MetTestId or LotOperationId passed into service.'
end
If ErrorMsg EQ '' then
Response = True$
end else
Error_Services('Add', ErrorMsg)
Response = False$
end
end service