1281 lines
60 KiB
Plaintext
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
|
|
|
|
|
|
|
|
|
|
|