open-insight/LSL2/STPROC/OBJ_RDS.txt
2025-02-20 18:23:06 +01:00

1482 lines
48 KiB
Plaintext

COMPILE FUNCTION obj_RDS(Method,Parms)
#pragma precomp SRP_PreCompiler
/*
Methods for RDS table
08/21/2004 JCH - Initial Coding
Properties:
Methods:
Create(DataStruct) ;* Create new record
*/
DECLARE FUNCTION Get_Status, Msg, Utility, obj_Tables, NextKey, obj_WO_Verify, obj_Prod_Spec, Send_Dyn, obj_RDS_Makeup
DECLARE FUNCTION obj_RDS2, obj_RDS_Test, obj_WO_Mat, obj_Clean_Insp, obj_PRS_Prop, Database_Services
DECLARE FUNCTION Logging_Services, Environment_Services, Error_Services, Signature_Services
DECLARE SUBROUTINE Set_Status, Msg, obj_Tables, Send_Dyn, obj_WO_Step, obj_RDS_Layer, obj_RDS_Test, obj_WM_In
DECLARE SUBROUTINE Btree.Extract, RDS_React_Run, Environment_Services, Logging_Services, Error_Services, Send_Info
DECLARE SUBROUTINE SRP_Stopwatch, Database_Services, Lot_Services
$INSERT MSG_EQUATES
$INSERT WO_VERIFY_EQU
$INSERT WO_LOG_EQUATES
$INSERT RDS_EQUATES
$INSERT RDS_MAKEUP_EQU
$INSERT RDS_LAYER_INFO_EQU
$INSERT QUOTE_SPEC_EQU
$INSERT PROD_SPEC_EQUATES
$INSERT SCHEDULE_EQU
$INSERT WO_STEP_EQU
$INSERT NCR_EQU
$INSERT WO_MAT_EQUATES
$INSERT REACT_RUN_EQUATES
$INSERT CLEAN_INSP_EQUATES
$INSERT EPI_PART_EQUATES
$INSERT WO_REACT_EQUATES
$INSERT PRS_LAYER_EQU ;* Used to return obj_Prod_Spec values
$INSERT LOGICAL
ErrTitle = 'Error in Stored Procedure "obj_RDS"'
ErrorMsg = ''
LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\RDS'
LogDate = Oconv(Date(), 'D4/')
LogTime = Oconv(Time(), 'MTS')
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' RDS Log.csv'
Headers = 'Logging DTM' : @FM : 'User' : @FM : 'RDS Key ID' : @FM : 'Notes'
objLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$)
LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\RemoveMetrology'
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : '.log'
Headers = 'Logging DTM' : @FM : 'Results'
ColumnWidths = 20 : @FM : 50
objLog2 = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ' ', Headers, ColumnWidths, False$, False$)
LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\WO_LOG'
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Release Log.csv'
Headers = 'Logging DTM' : @FM : 'User' : @FM : 'Work Order No' : @FM : 'Notes'
objReleaseLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, COMMA$, Headers, '', False$, False$)
LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\RDS'
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' WAFERS_IN.csv'
Headers = 'Logging DTM' : @FM : 'RDS Key ID' : @FM : 'WAFERS_IN'
objWafersLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$)
LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\RDS'
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' RDS_TEST_DELETE.csv'
Headers = 'Logging DTM' : @FM : 'RDS Test Key ID' : @FM : 'Message'
objRDSTestDeleteLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$)
LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM
IF NOT(ASSIGNED(Method)) THEN ErrorMsg = 'Unassigned parameter "Method" passed to subroutine'
IF NOT(ASSIGNED(Parms)) THEN Parms = ''
IF ErrorMsg NE '' THEN
Set_Status(-1,ErrTitle:@SVM:ErrorMsg)
RETURN ''
END
Result = ''
BEGIN CASE
CASE Method = 'CurrStatus' ; GOSUB CurrStatus
CASE Method = 'Create' ; GOSUB Create
CASE Method = 'VerifySpecInfo' ; GOSUB VerifySpecInfo
* CASE Method = 'Update' ; GOSUB Update
CASE Method = 'SchedWfrQty' ; GOSUB SchedWfrQty
CASE Method = 'TestRejWfrQty' ; GOSUB TestRejWfrQty
CASE Method = 'MUSrcWfrQty' ; GOSUB MUSrcWfrQty
CASE Method = 'MUDestWfrQty' ; GOSUB MUDestWfrQty
CASE Method = 'RemMUWafers' ; GOSUB RemMUWafers
CASE Method = 'WafersOut' ; GOSUB WafersOut
CASE Method = 'YieldOutThruput' ; GOSUB YieldOutThruput
CASE Method = 'WafersPerHour' ; GOSUB WafersPerHour
CASE Method = 'AddShip' ; GOSUB AddShip
CASE Method = 'RemShip' ; GOSUB RemShip
CASE Method = 'RefreshRDSSpec' ; GOSUB RefreshRDSSpec
CASE Method = 'WMInKeys' ; GOSUB WMInKeys
CASE Method = 'WMOutKeys' ; GOSUB WMOutKeys
CASE Method = 'SetSchedWfrQty' ; GOSUB SetSchedWfrQty
CASE Method = 'MU_ADE_Reads' ; GOSUB MU_ADE_Reads
CASE Method = 'MetPropFlag' ; GOSUB MetPropFlag
CASE 1
Result = obj_RDS2(Method,Parms)
END CASE
IF ErrorMsg NE '' THEN
Set_Status(-1,ErrTitle:@SVM:ErrorMsg)
END
RETURN Result
* * * * * * *
CurrStatus:
* * * * * * *
IF NOT(ASSIGNED(RDSNos)) THEN
RDSNos = Parms[1,@RM]
RDSRec = Parms[COL2()+1,@RM]
END
IF RDSNos = '' THEN RETURN ;* 9/9/2014 JCH *** This routine has multiple Keys in with only a single record **** AWS__T! needs to be fixed
ReturnVals = ''
RDSCnt = COUNT(RDSNos,@VM) + (RDSNos NE '')
FOR R = 1 TO RDSCnt
NCRStatuses = XLATE('NCR',RDSRec<RDS_NCR_KEYS$>,7,'X')
IF INDEX(NCRStatuses,'O',1) THEN
ReturnVals<1,R> = 'NCR' ;* Open NCR on RDS *
GOTO StatusHere
END
* ROTR inspection failure check -> Set status to PSTC (PostCleans)
RotrAction = XLATE('RDS',RDSNos,'ROTR_ACTION','X')
IF RotrAction = 'F' Then ;* Drive the CURR_STATUS to PostEpi Clean if the ROTR fails
ReturnVals<1,R> = 'PSTC'
GOTO StatusHere
END
* Check for out of spec
OutOfSpec = 0 ;
OutOfSpecThick = ''
OutOfSpecRes = ''
LSKeys = RDSRec<RDS_RDS_LAYER_KEYS$>
MetOutOfSpec = SUM(XLATE('RDS_LAYER',LSKeys,'TEST_OUT_OF_SPEC','X')) ;* Updated for Metrology update 4/16/2006 JCH
IF MetOutOfSpec > 0 THEN ;* Added check for F(ailed) ROTR_ACTION value.
ReturnVals<1,R> = 'SPEC' ;* Run is out of spec *
GOTO StatusHere
END
* Check for Metrology Complete
MetComplete = SUM(XLATE('RDS_LAYER',LSKeys,'TEST_MET_COMPLETE','X')) ;* Added with DKK 11/3/2015 JCH
IF NOT(MetComplete) THEN ;* Added check for F(ailed) ROTR_ACTION value.
ReturnVals<1,R> = 'MET' ;* Run is missing metrology *
GOTO StatusHere
END
* * * * * * *
WONo = RDSRec<RDS_WO$>
CassNo = RDSRec<RDS_CASS_NO$>
WOStepKey = RDSRec<RDS_WO_STEP_KEY$>
WOMatRec = XLATE('WO_MAT',WONo:'*':CassNo,'','X')
WOStep = FIELD(WOStepKey,'*',2)
RDSKeys = ''
RSCnt = 0
RunSigProfs = ''
RunSignatures = ''
RunSigDTMs = ''
WOMatKey = WONo:'*':CassNo
SigArray = Signature_Services('GetSigProfile', WOMatKey)
RunSigProfs = SigArray<1>
RunSignatures = SigArray<2>
ProcessStart = 0
ProcessComp = 0
LOOP
RunSignature = RunSignatures<1,1>
RunSigProf = RunSigProfs<1,1>
UNTIL RunSignature = ''
ProcessStart = 1
RunSignatures = DELETE(RunSignatures,1,1,0)
RunSigProfs = DELETE(RunSigProfs,1,1,0)
REPEAT
IF RunSignature = '' AND RunSigProf = '' AND ProcessStart = 1 THEN
ReturnVals<1,R> = 'COMP'
GOTO StatusHere
END ELSE
ReturnVals<1,R> = RunSigProf[2,20]
GOTO StatusHere
END
* EpiPRO specific (unload)
TestPockets = RDSRec<RDS_POCKET$>
TestOutCassNos = RDSRec<RDS_OUT_CASS_NO$>
CONVERT @VM TO '' IN TestPockets
CONVERT @VM TO '' IN TestOutCassNos
IF TestPockets NE '' AND TestOutCassNos NE '' THEN
ReturnVals<1,R> = 'COMP' ;* EpiPRO RDS is complete with wafer unload
END
StatusHere:
NEXT R
Result = ReturnVals
RETURN
* * * * * * *
Create:
* * * * * * *
WONo = Parms[1,@RM]
WOStep = Parms[COL2()+1,@RM]
LastStep = Parms[COL2()+1,@RM]
CassNo = Parms[COL2()+1,@RM]
QuoteNo = Parms[COL2()+1,@RM]
OrderNo = Parms[COL2()+1,@RM]
OrderItem = Parms[COL2()+1,@RM]
CustNo = Parms[COL2()+1,@RM]
PONo = Parms[COL2()+1,@RM]
PS_No = Parms[COL2()+1,@RM]
SubSuppliedBy = Parms[COL2()+1,@RM]
SubPreClean = Parms[COL2()+1,@RM]
SubPostClean = Parms[COL2()+1,@RM]
SchedDt = Parms[COL2()+1,@RM]
LotNo = Parms[COL2()+1,@RM]
CustPartNo = Parms[COL2()+1,@RM]
WaferQty = Parms[COL2()+1,@RM]
SubPartNo = Parms[COL2()+1,@RM]
QXJFlag = Parms[COL2()+1,@RM]
SubVendCd = Parms[COL2()+1,@RM]
ErrorMsg = ''
IF WONo = '' THEN ErrorMsg := 'Null Parameter "WONo" passed to routine. (':Method:')'
IF WOStep = '' THEN ErrorMsg := 'Null Parameter "WOStep" passed to routine. (':Method:')'
IF CassNo = '' THEN ErrorMsg := 'Null Parameter "CassNo" passed to routine. (':Method:')'
IF CustNo = '' THEN ErrorMsg := 'Null Parameter "CustNo" passed to routine. (':Method:')'
IF PS_No = '' THEN ErrorMsg := 'Null Parameter "PS_No" passed to routine. (':Method:')'
IF SchedDt = '' THEN ErrorMsg := 'Null Parameter "SchedDt" passed to routine. (':Method:')'
IF LotNo = '' THEN ErrorMsg := 'Null Parameter "LotNo" passed to routine. (':Method:')'
IF WaferQty = '' THEN ErrorMsg := 'Null Parameter "WaferQty" passed to routine. (':Method:')'
If ErrorMsg NE '' then
Logging_Services('AppendLog', objLog, LoggingDTM : ',' : @USER4 : ',' : 'RDSKey Not Yet Assigned' : ',' : 'Error occured in OBJ_RDS(CREATE): ' : ErrorMsg)
Return
end
RDSNo = NextKey('RDS')
errCode = ''
If RDSNo EQ '' or RDSNo EQ 0 or Error_Services('HasError') or Get_Status(errCode) then
Logging_Services('AppendLog', objLog, LoggingDTM : ',' : @USER4 : ',' : RDSNo : ',' : 'NextKey(RDS) returned NULL or 0 for KeyID')
Error_Services('Add', 'Error retrieving next RDS key from NextKey("RDS"). ' : Error_Services('GetMessage'))
Result = RDSNo
return
end
// Delete old instance of this RDS if it exists ------------------------------------------------------------------------
If RowExists('RDS', RDSNo) then
Database_Services('DeleteDataRow', 'RDS', RDSNo, True$, False$)
If Error_Services('NoError') then
Results = 'RDS ' : RDSNo : ' deleted'
end else
Results = 'RDS ' : RDSNo : ' not deleted. Error : ' : Error_Services('GetMessage')
end
end
// ---------------------------------------------------------------------------------------------------------------------
// Delete related RDS_LAYER records ------------------------------------------------------------------------------------
Layers = 'L1,L2,2'
For each Layer in Layers using ','
RDSLayerKey = RDSNo:'*':Layer
If RowExists('RDS_LAYER', RDSLayerKey) then
// Look for related RDS_TEST records and delete them first
RDSTestKeys = Xlate('RDS_LAYER', RDSLayerKey, 'RDS_TEST_KEYS', 'X')
If RDSTestKeys NE '' then
For each RDSTestKey in RDSTestKeys using @VM
// Look for related TW_USE records and delete them first
TWKeys = Xlate('RDS_TEST', RDSTestKey, 'TW_USE_ID', 'X')
If TWKeys NE '' then
For each TWKey in TWKeys using @VM
Database_Services('DeleteDataRow', 'TW_USE', TWKey, True$, True$)
Next TWKey
end
Database_Services('DeleteDataRow', 'RDS_TEST', RDSTestKey, True$, True$)
If Error_Services('NoError') then
LogData = ''
LogData<1> = LoggingDTM
LogData<2> = RDSTestKey
LogData<3> = 'RDS_Test record deleted without error.'
Logging_Services('AppendLog', objRDSTestDeleteLog , LogData, @RM, @FM, False$)
end else
ErrorMessage = Error_Services('GetMessage')
LogData = ''
LogData<1> = LoggingDTM
LogData<2> = ErrorMessage
Logging_Services('AppendLog', objRDSTestDeleteLog , LogData, @RM, @FM, False$)
end
Next RDSTestKey
end
Database_Services('DeleteDataRow', 'RDS_LAYER', RDSLayerKey, True$, False$)
If Error_Services('NoError') then
Results = 'RDS_LAYER ' : RDSLayerKey : ' deleted'
end else
Results = 'RDS_LAYER ' : RDSLayerKey : ' not deleted. Error : ' : Error_Services('GetMessage')
end
end
Next Layer
// ---------------------------------------------------------------------------------------------------------------------
// Delete old REACT_RUN record if it exists ----------------------------------------------------------------------------
If RowExists('REACT_RUN', RDSNo) then
// Delete old CLEAN_INSP record(s) if they exist
CIKeys = Xlate('REACT_RUN', RDSNo, 'CI_NO', 'X')
For each CIKey in CIKeys using @VM
If RowExists('CLEAN_INSP', CIKey) then
Database_Services('DeleteDataRow', 'CLEAN_INSP', CIKey, True$, False$)
If Error_Services('NoError') then
Results = 'CLEAN_INSP ' : CIKey : ' deleted'
end else
Results = 'CLEAN_INSP ' : CIKey : ' not deleted. Error : ' : Error_Services('GetMessage')
end
end
Next CIKey
Database_Services('DeleteDataRow', 'REACT_RUN', RDSNo, True$, False$)
If Error_Services('NoError') then
Results = 'REACT_RUN ' : RDSNo : ' deleted'
end else
Results = 'REACT_RUN ' : RDSNo : ' not deleted. Error : ' : Error_Services('GetMessage')
end
end
// ---------------------------------------------------------------------------------------------------------------------
// Create new record
RDSRec = ''
RDSRec<RDS_ENTRY_ID$> = @USER4
RDSRec<RDS_ENTRY_DATE$> = Date()
RDSRec<RDS_ENTRY_TIME$> = Time()
RDSRec<RDS_STATUS$> = 'C' ;* Received
RDSRec<RDS_WO$> = WONo
RDSRec<RDS_WO_STEP_KEY$> = WONo:'*':WOStep
RDSRec<RDS_CASS_NO$> = CassNo
RDSRec<RDS_QUOTE_NO$> = QuoteNo
RDSRec<RDS_ORDER_NO$> = OrderNo
RDSRec<RDS_ORDER_ITEM$> = OrderItem
RDSRec<RDS_CUST_NO$> = CustNo
RDSRec<RDS_PO$> = PONo
RDSRec<RDS_PROD_SPEC_ID$> = PS_No
RDSRec<RDS_COMMIT_DATE_FINAL$> = SchedDt
RDSRec<RDS_LOT_NUM$> = LotNo
RDSRec<RDS_PART_NUM$> = CustPartNo
RDSRec<RDS_CASS_WAFER_QTY$> = WaferQty
RDSRec<RDS_SUB_PART_NO$> = SubPartNo
RDSRec<RDS_LAST_STEP$> = LastStep
RDSRec<RDS_SUB_SUPPLIED_BY$> = SubSuppliedBy
RDSRec<RDS_SUB_PRE_CLEAN$> = SubPreClean
RDSRec<RDS_SUB_POST_CLEAN$> = SubPostClean
IF CassNo = 1 THEN
WOVStatus = 'O' ;* Open status (?)
WOVNotes = ''
WOVNo = obj_WO_Verify('Create',RDSNo:@RM:WOVStatus:@RM:WOVNotes) ;* Create a WO_Verify record on 1st run order
RDSRec<RDS_WO_VERIFY_ID$> = WOVNo ;* Add pointer to RDS record
IF Get_Status(errCode) THEN
Logging_Services('AppendLog', objLog, LoggingDTM : ',' : @USER4 : ',' : RDSNo : ',' : 'Error calling OBJ_WO_VERIFY within OBJ_RDS(CREATE)')
end
End
PSRec = XLATE('PROD_SPEC',PS_No,'','X')
ReactorType = PSRec<PROD_SPEC_REACTOR_TYPE$> ;* This isn't used anwhere in the program 8/27/2014 JCH
RDSRec<RDS_SPECIAL_INST$> = PSRec<PROD_SPEC_SPEC_INST$> ;* 3/25/2013 jch
RDSRec<RDS_SPEC_TYPE_ORIG$> = XLATE('PROD_SPEC',PS_No,'SPEC_TYPE','X')
Send_Info('Retrieving PSN Layer Properties...')
LayerSpecs = obj_Prod_Spec('GetLayerProp',PS_No:@RM:@RM:1) ;* Returns specs for all layers in internal format
* LayerSpecs is @RM between layers, @FM between fields, LayerSet ID is in the first Field and needs to peeled off
* before the equates match up correctly
* Prod_Spec table has layer specs all in one field
* RDS has First layer stuff in individual fields and then has 2 and 3 shoved into Field 33 (Layer Info)
LayerSpec = FIELD(LayerSpecs,@RM,1) ;* Take the first Layer
LayerSet = FIELD(LayerSpec,@FM,1) ;* Not used here but shown for clarity
LayerSpec = FIELD(LayerSpec,@FM,2,99) ;* LayerSpec without the LayerSet
RecipeNo = LayerSpec<PRS_LAYER_RECIPE$>
RecipeRec = XLATE('RECIPE',RecipeNo,'','X') ;* This used in 2nd and 3rd layer stuff (in error it appears)
RDSRec<RDS_OVERGROW_REQ$> = LayerSpec<PRS_LAYER_RES_MEASUREMENT$,9> ;* JCH 2/27/2006
IF QXJFlag THEN
RDSRec<RDS_QXJ_POST$> = 0 ;* And here a couple of minor cluster operations
END
IF CustNo = '621' AND CassNo = 1 THEN
RDSRec<RDS_QXJ_POST$> = 0
END
NoCombinedLayerFlag = ''
FOR I = 1 TO COUNT(LayerSpecs,@RM) + (LayerSpecs NE '')
LayerSpec = FIELD(LayerSpecs,@RM,I) ;* Take the Ith Layer
LayerSet = FIELD(LayerSpec,@FM,1)
LayerSpec = FIELD(LayerSpec,@FM,2,99) ;* LayerSpec without the LayerSet
IF LayerSet = I THEN NoCombinedLayerFlag = 1 ELSE NoCombinedLayerFlag = 0
Send_Info('Creating RDS Layer ':LayerSet:'...')
obj_RDS_Layer('Create',RDSNo:@RM:LayerSet:@RM:PS_No:@RM:NoCombinedLayerFlag)
RDSRec<RDS_RDS_LAYER_KEYS$,I> = RDSNo:'*':LayerSet ;* Added 4/17/2006 JCH
Send_Info('Creating Metrology for Layer Set ':LayerSet:'...')
obj_RDS_Test('Create',RDSNo:@RM:LayerSet:@RM:PS_No)
NEXT I
********************************
*Automatically Apply Supplement*
********************************
// If first cassette in work order, then there is no supplement in place, therefore skip this step.
If RDSRec<RDS_CASS_NO$> GT 1 then
WoStepKey = RDSRec<RDS_WO_STEP_KEY$>
WoStepRec = Database_Services('ReadDataRow', 'WO_STEP', WoStepKey)
If Error_Services('NoError') then
LastRDSKey = WoStepRec<WO_STEP_RDS_KEY$>[-1, 'B' : @VM]
LastRDSRec = Database_Services('ReadDataRow', 'RDS', LastRDSKey)
If Error_Services('NoError') then
HasSupplement = LastRDSRec<RDS_SUPPLEMENT$>
If HasSupplement then
RDSRec<RDS_SUPPLEMENT$> = True$
RDSRec<RDS_SUPPL_INST$> = LastRDSRec<RDS_SUPPL_INST$>
RDSRec<RDS_SUPPL_ENTRY_ID$> = LastRDSRec<RDS_SUPPL_ENTRY_ID$>
RDSRec<RDS_SUPPL_ENTRY_DATE$> = LastRDSRec<RDS_SUPPL_ENTRY_DATE$>
RDSRec<RDS_SUPPL_ENTRY_TIME$> = LastRDSRec<RDS_SUPPL_ENTRY_TIME$>
end
end else
Logging_Services('AppendLog', objLog, LoggingDTM : ',' : @USER4 : ',' : RDSNo : ',' : 'Error automatically applying supplement to new RDS.')
end
end else
Logging_Services('AppendLog', objLog, LoggingDTM : ',' : @USER4 : ',' : RDSNo : ',' : 'Error automatically applying supplement to new RDS.')
end
end
Send_Info('Saving RDS record...')
obj_Tables('WriteRec','RDS':@RM:RDSNo:@RM:@RM:RDSRec)
IF Get_Status(errCode) THEN
Logging_Services('AppendLog', objLog, LoggingDTM : ',' : @USER4 : ',' : RDSNo : ',' : 'Error writing new RDS record. Error code: ':errCode)
Result = ''
END ELSE
Lot_Services('CreateNewLot', 'RDS', '', WaferQty, SubPartNo, LotNo, SubVendCd, @User4, '', RDSNo)
Result = RDSNo
END
* * * * * * *
Send_Info('Conversion to REACT_RUN record...')
RDS_React_Run(RDSNo) ;********************************** Conversion stuff JCH 9/26/2008 *********************
RETURN
* * * * * * *
VerifySpecInfo:
* * * * * * *
RDSNo = Parms[1,@RM]
RDSRec = Parms[COL2()+1,@RM]
IF NOT(ASSIGNED(RDSNo)) THEN ErrorMsg = 'Unassigned Parm "RDSNo" passed to routine. (':Method:')'
IF NOT(ASSIGNED(RDSRec)) THEN RDSRec = ''
IF ErrorMsg NE '' THEN RETURN
IF RDSNo = '' THEN RETURN ;* used in dictionary - no error messages
IF RDSRec = '' THEN RDSRec = XLATE('RDS',RDSNo,'','X')
IF RDSRec = '' THEN RETURN
PS_No = RDSRec<RDS_PROD_SPEC_ID$>
PSRec = XLATE('PROD_SPEC',PS_No,'','X')
LayerSpecs = obj_Prod_Spec('GetLayerProp',PS_No) ;* Returns specs for all layers
IF RDSRec<RDS_SPECIAL_INST$> NE PSRec<PROD_SPEC_SPEC_INST$> THEN Matches = 0
LayerSpec = FIELD(LayerSpecs,@RM,1) ;* Take the first Layer
LayerSet = FIELD(LayerSpec,@FM,1) ;* Not used here but shown for clarity
LayerSpec = FIELD(LayerSpec,@FM,2,99) ;* LayerSpec without the LayerSet
RecipeNo = LayerSpec<PRS_LAYER_RECIPE$>
RecipeRec = XLATE('RECIPE',RecipeNo,'','X') ;* This used in 2nd and 3rd layer stuff (in error it appears)
ErrNum = 1
* IF RDSRec<RDS_RECIPE_NO$> NE RecipeNo THEN ErrNum = -11
* This section is here because the targets calculated in the existing SCHEDULE*WRITE event are not done correctly
* There is a last decimal point difference in the calculation that causes a mismatch whenever a remainder of .5
* is generated during the division by 2. WRITE event code doesn't drop the remainder like it should
* This section calculates the targets based on the min and max on the RDS. We can remove this after the WRITE
* event is replaced and the data has had enough time to move through the system.
* JCH 8/23/2004
RDSConMin = RDSRec<RDS_CON_MIN_ORG$,1> ;* Record in internal format
RDSConMax = RDSRec<RDS_CON_MAX_ORG$,1> ;* Record in internal format
GOSUB CalcConTarget ;* Returns RDSTarget in internal format
RDSResMin = RDSRec<RDS_RES_MIN_ORG$>
RDSResMax = RDSRec<RDS_RES_MAX_ORG$>
GOSUB CalcResTarget
RDSThickMin = RDSRec<RDS_THICK_MIN_ORG$>
RDSThickMax = RDSRec<RDS_THICK_MAX_ORG$>
GOSUB CalcThickTarget
IF OCONV(RDSRec<RDS_CON_MIN_ORG$,1>,'MS21') NE LayerSpec<PRS_LAYER_CONC_MIN$> THEN ErrNum = -12
IF OCONV(RDSRec<RDS_CON_MAX_ORG$,1>,'MS21') NE LayerSpec<PRS_LAYER_CONC_MAX$> THEN ErrNum = -13
IF RDSRec<RDS_CON_UNITS_ORG$> NE LayerSpec<PRS_LAYER_CONC_UNITS$> THEN ErrNum = -14
IF OCONV(RDSConTarget,'MS21') NE LayerSpec<PRS_LAYER_CONC_TARGET$> THEN ErrNum = -15
IF OCONV(RDSRec<RDS_RES_MIN_ORG$>,'MD3') NE LayerSpec<PRS_LAYER_RES_MIN$> THEN ErrNum = -16
IF OCONV(RDSRec<RDS_RES_MAX_ORG$>,'MD3') NE LayerSpec<PRS_LAYER_RES_MAX$> THEN ErrNum = -17
IF RDSRec<RDS_RES_UNITS_ORG$> NE LayerSpec<PRS_LAYER_RES_UNITS$> THEN ErrNum = -18
IF OCONV(RDSResTarget,'MD3') NE LayerSpec<PRS_LAYER_RES_TARGET$> THEN ErrNum = -19
IF OCONV(RDSRec<RDS_THICK_MIN_ORG$>,'MD2') NE LayerSpec<PRS_LAYER_THICK_MIN$> THEN ErrNum = -110
IF OCONV(RDSRec<RDS_THICK_MAX_ORG$>,'MD2') NE LayerSpec<PRS_LAYER_THICK_MAX$> THEN ErrNum = -111
IF RDSRec<RDS_THICK_UNITS_ORG$> NE LayerSpec<PRS_LAYER_THICK_UNITS$> THEN ErrNum = -112
IF OCONV(RDSThickTarget,'MD2') NE LayerSpec<PRS_LAYER_THICK_TARGET$> THEN ErrNum = -113
RDSLayerInfo = RDSRec<RDS_LAYER_INFO$> ;* All Layers beyond the first
FOR I = 2 TO COUNT(LayerSpecs,@RM) + (LayerSpecs NE '')
LayerSpec = FIELD(LayerSpecs,@RM,I) ;* Take the Ith Layer
LayerSet = LayerSpec<1>
LayerSpec = FIELD(LayerSpec,@FM,2,99) ;* LayerSpec without the LayerSet
thisLayerInfo = FIELD(RDSLayerInfo,CHAR(248),I-1,1) ;* L2 & 2 from the RDS
* Calculate RDS target using the same algorithm used in obj_Prod_Spec
RDSConMin = ICONV(thisLayerInfo<1,RLConMin$,1>,'MS')
RDSConMax = ICONV(thisLayerInfo<1,RLConMax$,1>,'MS')
GOSUB CalcConTarget
IF RDSConMin AND RDSConMax THEN
IF RDSConMin = RDSConMax THEN
RDSConTarget = RDSConMin
END ELSE
Delta = INT((RdsConMax-RDSConMin)/2)
RDSConTarget = OCONV(RDSConMin + Delta,'MS21')
END
END ELSE
RDSConTarget = ''
END
IF thisLayerInfo<1,RLRecipeNo$> NE RecipeNo THEN ErrNum = '-':I:1
IF thisLayerInfo<1,RLConMin$,1> NE LayerSpec<PRS_LAYER_CONC_MIN$> THEN ErrNum = '-':I:2
IF thisLayerInfo<1,RLConMax$,1> NE LayerSpec<PRS_LAYER_CONC_MAX$> THEN ErrNum = '-':I:3
IF thisLayerInfo<1,RLConUnits$> NE LayerSpec<PRS_LAYER_CONC_UNITS$> THEN ErrNum = '-':I:4
IF RDSConTarget NE LayerSpec<PRS_LAYER_CONC_TARGET$> THEN ErrNum = '-':I:5
IF OCONV(thisLayerInfo<1,RLResMin$>,'MD3') NE LayerSpec<PRS_LAYER_RES_MIN$> THEN ErrNum = '-':I:6
IF OCONV(thisLayerInfo<1,RLResMax$>,'MD3') NE LayerSpec<PRS_LAYER_RES_MAX$> THEN ErrNum = '-':I:7
IF thisLayerInfo<1,RLResUnits$> NE LayerSpec<PRS_LAYER_RES_UNITS$> THEN ErrNum = '-':I:8
IF OCONV(thisLayerInfo<1,RLResTarget$>,'MD3') NE LayerSpec<PRS_LAYER_RES_TARGET$> THEN ErrNum = '-':I:9
IF OCONV(thisLayerInfo<1,RLThickMin$>,'MD2') NE LayerSpec<PRS_LAYER_THICK_MIN$> THEN ErrNum = '-':I:10
IF OCONV(thisLayerInfo<1,RLThickMax$>,'MD2') NE LayerSpec<PRS_LAYER_THICK_MAX$> THEN ErrNum = '-':I:11
IF thisLayerInfo<1,RLThickUnits$> NE LayerSpec<PRS_LAYER_THICK_UNITS$> THEN ErrNum = '-':I:12
IF OCONV(thisLayerInfo<1,RLThickTarget$>,'MD2') NE LayerSpec<PRS_LAYER_THICK_TARGET$> THEN ErrNum = '-':I:13
NEXT I
SchedNo = RDSRec<RDS_SCHEDULE_NO$>
OrdNo = RDSRec<RDS_ORDER_NO$>
Result = ErrNum:@FM:'Sched No: ':SchedNo:@FM:' Order No: ':OrdNo
RETURN
* * * * * * *
* Update:
* * * * * * *
*
* RDSNo = Parms[1,@RM]
*
* IF NOT(ASSIGNED(RDSNo)) THEN ErrorMsg = 'Unassigned Parm "RDSNo" passed to routine. (':Method:')'
*
* IF ErrorMsg NE '' THEN RETURN
*
* IF RDSNo = '' THEN ErrorMsg = 'Null Parameter "RDSNo" passed to routine. (':Method:')'
*
* IF ErrorMsg NE '' THEN RETURN
*
* RDSRec<RDS_ENTRY_ID$> = @USER4
* RDSRec<RDS_ENTRY_DATE$> = Date()
* RDSRec<RDS_ENTRY_TIME$> = Time()
* RDSRec<RDS_SCHEDULE_NO$> = SchedNo
* RDSRec<RDS_WO$> = WONo
*
* WO Run Order number is not stored in the RDS
*
* RDSRec<RDS_QUOTE_NO$> = QuoteNo
* RDSRec<RDS_ORDER_NO$> = OrderNo
* RDSRec<RDS_CUST_NO$> = CustNo
* RDSRec<RDS_PO$> = PONo
* RDSRec<RDS_PROD_SPEC_ID$> = PS_No
* RDSRec<RDS_STATUS$> = RDSStatus ;* Usually passed as 'C' - Received
* RDSRec<RDS_COMMIT_DATE_FINAL$> = SchedDt
* RDSRec<RDS_LOT_NUM$> = LotNo
* RDSRec<RDS_PART_NUM$> = PartNo
*
* IF CassNo = 1 THEN
* WOVStatus = 'O' ;* Open status (?)
* WOVNotes = ''
* WOVNo = obj_WO_Verify('Create',RDSNo:@RM:WOVStatus:@RM:WOVNotes) ;* Create a WO_Verify record on 1st run order
* RDSRec<RDS_WO_VERIFY_ID$> = WOVNo ;* Add pointer to RDS record
* END
*
* PSRec = XLATE('PROD_SPEC',PS_No,'','X')
*
* RDSRec<RDS_SPECIAL_INST$> = PSRec<PROD_SPEC_SPEC_INST$>
* RDSRec<RDS_SPEC_TYPE_ORIG$> = XLATE('PROD_SPEC',PS_No,'SPEC_TYPE','X')
*
* LayerSpecs = obj_Prod_Spec('GetLayerProp',PS_No:@RM:@RM:1) ;* Returns specs for all layers without output conversion
*
* LayerSpecs is @RM between layers, @FM between fields, LayerSet ID is in the first Field and needs to peeled off
* before the equates match up correctly
*
* Prod_Spec table has layer specs all in one field
* RDS has First layer stuff in individual fields and then has 2 and 3 shoved into Field 33 (Layer Info)
*
* LayerSpec = FIELD(LayerSpecs,@RM,1) ;* Take the first Layer
* LayerSet = FIELD(LayerSpec,@FM,1) ;* Not used here but shown for clarity
* LayerSpec = FIELD(LayerSpec,@FM,2,99) ;* LayerSpec without the LayerSet
*
* RecipeNo = LayerSpec<PRS_LAYER_RECIPE$>
* RecipeRec = XLATE('RECIPE',RecipeNo,'','X') ;* This used in 2nd and 3rd layer stuff (in error it appears)
*
* RDSRec<RDS_RECIPE_NO$> = RecipeNo
* RDSRec<RDS_CON_MIN$> = LayerSpec<PRS_LAYER_CONC_MIN$>
* RDSRec<RDS_CON_MAX$> = LayerSpec<PRS_LAYER_CONC_MAX$>
* RDSRec<RDS_CON_UNITS$> = LayerSpec<PRS_LAYER_CONC_UNITS$>
* RDSRec<RDS_CON_TARGET$> = LayerSpec<PRS_LAYER_CONC_TARGET$>
*
* RDSRec<RDS_RES_MIN$> = LayerSpec<PRS_LAYER_RES_MIN$>
* RDSRec<RDS_RES_MAX$> = LayerSpec<PRS_LAYER_RES_MAX$>
* RDSRec<RDS_RES_UNITS$> = LayerSpec<PRS_LAYER_RES_UNITS$>
* RDSRec<RDS_RES_TARGET$> = LayerSpec<PRS_LAYER_RES_TARGET$>
*
* RDSRec<RDS_THICK_MIN$> = LayerSpec<PRS_LAYER_THICK_MIN$>
* RDSRec<RDS_THICK_MAX$> = LayerSpec<PRS_LAYER_THICK_MAX$>
* RDSRec<RDS_THICK_UNITS$> = LayerSpec<PRS_LAYER_THICK_UNITS$>
* RDSRec<RDS_THICK_TARGET$> = LayerSpec<PRS_LAYER_THICK_TARGET$>
*
* LayerInfo = ''
*
* FOR I = 2 TO COUNT(LayerSpecs,@RM) + (LayerSpecs NE '')
* LayerSpec = FIELD(LayerSpecs,@RM,I) ;* Take the Ith Layer
* LayerSpec = FIELD(LayerSpec,@FM,2,99) ;* LayerSpec without the LayerSet
*
* thisLayerInfo = '' ;* Empty bucket to parse into
*
* thisLayerInfo<1,RLConMin$> = LayerSpec<PRS_LAYER_CONC_MIN$>
* thisLayerInfo<1,RLConMax$> = LayerSpec<PRS_LAYER_CONC_MAX$>
* thisLayerInfo<1,RLConUnits$> = LayerSpec<PRS_LAYER_CONC_UNITS$>
* thisLayerInfo<1,RLConTarget$> = LayerSpec<PRS_LAYER_CONC_TARGET$>
*
* thisLayerInfo<1,RLRecipeNo$> = RecipeNo ;* Copied from the original in the WRITE event of the Schedule window
* thisLayerInfo<1,RLThickRead$> = STR(@SVM,16)
* thisLayerInfo<1,RLSheetRhoRead$> = STR(@SVM,16)
*
* thisLayerInfo<1,RLResMin$> = LayerSpec<PRS_LAYER_RES_MIN$>
* thisLayerInfo<1,RLResMax$> = LayerSpec<PRS_LAYER_RES_MAX$>
* thisLayerInfo<1,RLResUnits$> = LayerSpec<PRS_LAYER_RES_UNITS$>
* thisLayerInfo<1,RLResTarget$> = LayerSpec<PRS_LAYER_RES_TARGET$>
*
* thisLayerInfo<1,RLThickMin$> = LayerSpec<PRS_LAYER_THICK_MIN$>
* thisLayerInfo<1,RLThickMax$> = LayerSpec<PRS_LAYER_THICK_MAX$>
* thisLayerInfo<1,RLThickUnits$> = LayerSpec<PRS_LAYER_THICK_UNITS$>
* thisLayerInfo<1,RLThickTarget$> = LayerSpec<PRS_LAYER_THICK_TARGET$>
*
* LayerInfo := thisLayerInfo:CHAR(248)
*
* NEXT I
*
* LayerInfo[-1,1] = '' ;* Strip trailing CHAR(248)
*
*
* RDSRec<RDS_LAYER_INFO$> = LayerInfo ;* End of the great Layer cluster function
*
* IF QXJFlag THEN
* RDSRec<RDS_QXJ_POST$> = 0 ;* And here a couple of minor cluster operations
* END
*
* IF CustNo = '621' AND CassNo = 1 THEN
* RDSRec<RDS_QXJ_POST$> = 0
* END
*
* obj_Tables('WriteRec','RDS':@RM:RDSKey:@RM:@RM:RDSRec)
*
* IF Get_Status(errCode) THEN
* Result = ''
* END ELSE
* Result = RDSKey
* END
*
*
*
* RETURN
* * * * * * *
SchedWfrQty:
* * * * * * *
IF NOT(ASSIGNED(thisRDSNo)) THEN
thisRDSNo = Parms[1,@RM]
END
IF NOT(ASSIGNED(thisRDSRec)) THEN
thisRDSRec = Parms[COL2()+1,@RM]
END
IF thisRDSNo = '' THEN RETURN
IF thisRDSRec = '' THEN thisRDSRec = XLATE('RDS',thisRDSNo,'','X')
IF thisRDSRec = '' THEN RETURN
SchedNo = thisRDSRec<RDS_SCHEDULE_NO$>
SchedRec = XLATE('SCHEDULE',SchedNo,'','X')
LOCATE thisRDSNo IN SchedRec<SCHEDULE_RDS_IDS$> USING @VM SETTING Pos THEN
Result = SchedRec<SCHEDULE_WAFERS_IN$,Pos>
END
RETURN
* * * * * * *
TestRejWfrQty:
* * * * * * *
IF NOT(ASSIGNED(thisRDSNo)) THEN
thisRDSNo = Parms[1,@RM]
END
IF NOT(ASSIGNED(thisRDSRec)) THEN
thisRDSRec = Parms[COL2()+1,@RM]
END
IF thisRDSNo = '' THEN RETURN
IF thisRDSRec = '' THEN thisRDSRec = XLATE('RDS',thisRDSNo,'','X')
IF thisRDSRec = '' THEN RETURN
Tmp = 0
Tmp += XLATE('RDS',thisRDSNo,'TOT_REJ','X')
TestKeys = XLATE('RDS_LAYER',thisRDSRec<RDS_RDS_LAYER_KEYS$>,3,'X')
ProdTestWfrs = obj_RDS_Test('ProdTestCount',TestKeys)
Tmp += ProdTestWfrs
Tmp += thisRDSRec<RDS_WAF_BACK_TO_INVENTORY$> ;* <97>
Tmp += thisRDSRec<RDS_RESEARCH_SRP_BILLABLE$> ;* <221>
Result = Tmp
RETURN
* * * * * * *
MUSrcWfrQty:
* * * * * * *
IF NOT(ASSIGNED(thisRDSNo)) THEN
thisRDSNo = Parms[1,@RM]
END
IF NOT(ASSIGNED(thisRDSMakeupRec)) THEN
thisRDSMakeupRec = Parms[COL2()+1,@RM]
END
IF thisRDSNo = '' THEN RETURN
IF thisRDSMakeupRec = '' THEN thisRDSMakeupRec = XLATE('RDS_MAKEUP',thisRDSNo,'','X')
IF thisRDSMakeupRec NE '' THEN
Tmp = 0
FOR I = 1 TO COUNT(thisRDSMakeupRec<RDS_MAKEUP_SRC_SLOT$>,@VM) + (thisRDSMakeupRec<RDS_MAKEUP_SRC_SLOT$> NE '')
IF thisRDSMakeupRec<RDS_MAKEUP_SRC_SLOT$,I> NE '' THEN Tmp += 1
NEXT I
END
RETURN
* * * * * * *
MUDestWfrQty:
* * * * * * *
IF NOT(ASSIGNED(thisRDSNo)) THEN
thisRDSNo = Parms[1,@RM]
END
IF NOT(ASSIGNED(thisRDSMakeupRec)) THEN
thisRDSMakeupRec = Parms[COL2()+1,@RM]
END
IF thisRDSNo = '' THEN RETURN
IF thisRDSMakeupRec = '' THEN thisRDSMakeupRec = XLATE('RDS_MAKEUP',thisRDSNo,'','X')
IF thisRDSMakeupRec NE '' THEN
Tmp = 0
FOR I = 1 TO COUNT(thisRDSMakeupRec<RDS_MAKEUP_DEST_SLOT$>,@VM) + (thisRDSMakeupRec<RDS_MAKEUP_DEST_SLOT$> NE '')
IF thisRDSMakeupRec<RDS_MAKEUP_DEST_SLOT$,I> NE '' THEN Tmp += 1
NEXT I
Result = Tmp
END
RETURN
* * * * * * *
WafersOut:
* * * * * * *
IF NOT(ASSIGNED(RDSNo)) THEN RDSNo = Parms[1,@RM]
IF NOT(ASSIGNED(RDSRec)) THEN RDSRec = Parms[COL2()+1,@RM]
IF NOT(ASSIGNED(Filter)) THEN Filter = Parms[COL2()+1,@RM]
IF NOT(ASSIGNED(NoMU)) THEN NoMU = Parms[COL2()+1,@RM] ;* NoMU = No Makeup Wafer counts
IF RDSNo = '' THEN RETURN
IF RDSRec = '' THEN RDSRec = XLATE('RDS',RDSNo,'','X')
VerifyQty = RDSRec<RDS_VERIFY_QTY$>
WafersIn = RDSRec<RDS_WAFERS_IN$>
CassWfrQty = RDSRec<RDS_CASS_WAFER_QTY$>
NCRKeys = RDSRec<RDS_NCR_KEYS$>
If Not(Num(WafersIn)) then
// Log the WafersIn value
LogData = ''
LogData<1> = LoggingDTM
LogData<2> = RDSNo
LogData<3> = WafersIn
Logging_Services('AppendLog', objWafersLog, LogData, @RM, @FM)
WafersIn = WafersIn<1, 1, 1>
end
WONo = RDSRec<RDS_WO$>
CassNo = RDSRec<RDS_CASS_NO$>
MUWafersIn = XLATE('WO_MAT',WONo:'*':CassNo,'CURR_WFR_CNT_MU_ADDED','X')
MUWafersRemoved = XLATE('WO_MAT',WONo:'*':CassNo,'CURR_WFR_CNT_USED_MU','X')
CurrWfrCnt = XLATE('WO_MAT',WONo:'*':CassNo,'CURR_WFR_CNT','X') ;* Added 5/10/2011 JCH * * * * * * * * * * * * * *
IF NCRKeys NE '' THEN
* This happens when a box of wafers is bad upon opening in the cleanroom
* An NCR rejecting the entire cassette is generated and the box is returned to shipping/receiving
NCRStatuses = XLATE('NCR',NCRKeys,NCR_STATUS$,'X') ;* Added this section 09/17/2005 JCH - J.C. Henry & Co., Inc.
IF INDEX(NCRStatuses,'O',1) ELSE
* All NCR's are closed
RejectQty = XLATE('NCR',NCRKeys,'REJ_CNT','X')
* 11/17/22 - DJS/JRO - Updated the following line to check if CurrWfrCnt is equal to zero to prevent OI from
* erroneously returning zero. Consider refactoring WafersOut subroutine.
IF ( ( (SUM(RejectQty) = CassWfrQty) or (SUM(RejectQty) = WafersIn) ) and (CurrWfrCnt EQ 0) ) THEN
Result = 0
RETURN
end
END
END
TotRejects = SUM(XLATE('NCR',NCRKeys,'REJ_CNT','X'))
TestKeys = XLATE('RDS_LAYER',RDSRec<RDS_RDS_LAYER_KEYS$>,3,'X')
TWProd = obj_RDS_Test('ProdTestCount',TestKeys)
SRPBillable = RDSRec<RDS_RESEARCH_SRP_BILLABLE$>
IF NoMU THEN
Added = WafersIn
Removed = TotRejects + TWProd + SRPBillable
END ELSE
Added = WafersIn + MUWafersIn
Removed = TotRejects + TWProd + SRPBillable + MUWafersRemoved
END
IF Filter NE '' THEN
BEGIN CASE
CASE Filter = 'Q'
SignedOff = RDSRec<RDS_SUP_VER_SIG$> NE ''
CASE Filter = 'P'
SignedOff = RDSRec<RDS_POST_EPI_SIG$> NE ''
CASE 1
SignedOff = '' ;* This is an error
END CASE
END ELSE
SignedOff = (RDSRec<RDS_OPERATOR_OUT$> NE '')
END
IF (Removed <= Added) AND (Added NE 0) AND SignedOff THEN ;* Added SignedOff Flag for QA on 09/21/2005 JCH - J.C. Henry & Co., Inc.
Result = Added - Removed
IF Result NE CurrWfrCnt THEN Result = CurrWfrCnt
END ELSE
Result = ''
END
RETURN
****************
YieldOutThruput:
****************
RDSNo = Parms[1,@RM]
RDSRec = Parms[COL2()+1,@RM]
YieldOut = 0
If (RDSNo NE '') then
If (RDSRec = '') then
RDSRec = XLATE('RDS',RDSNo,'','X')
end
// Number of wafers out = Number of wafers in
WafersOut = RDSRec<RDS_WAFERS_IN$>
// Calculate the total number of rejected wafers
CustScrap = Xlate('RDS', RDSNo, 'CUST_TOT_REJ', 'X')
IFXScrap = Xlate('RDS', RDSNo, 'LSL_TOT_REJ', 'X')
TotalRejects = CustScrap + IFXScrap
// Determine the number of production test wafers
TestKeys = XLATE('RDS_LAYER',RDSRec<RDS_RDS_LAYER_KEYS$>, 3, 'X')
TWProd = obj_RDS_Test('ProdTestCount', TestKeys)
YieldOut = WafersOut - TotalRejects - TWProd
end
Result = YieldOut
return
* * * * * * *
RemMUWafers:
* * * * * * *
RETURN
* * * * * * *
WafersPerHour:
* * * * * * *
RDSNos = Parms[1,@RM]
IF NOT(ASSIGNED(RDSNos)) THEN RDSNos = ''
IF RDSNos = '' THEN RETURN
HoursTotal = 0
WafersInTotal = 0
TargetTotal = 0
RDSCount = COUNT(RDSNos,@VM) + (RDSNos NE '')
FOR I = 1 TO RDSCount
RDSRec = XLATE('RDS',RDSNos<1,I>,'','X')
LoadDTM = ICONV(OCONV(RDSRec<RDS_DATE_IN$>,'D4/'):' ':OCONV(RDSRec<RDS_TIME_IN$>,'MTS'),'DT')
UnLoadDTM = ICONV(OCONV(RDSRec<RDS_DATE_OUT$>,'D4/'):' ':OCONV(RDSRec<RDS_TIME_OUT$>,'MTS'),'DT')
WafersIn = RDSRec<RDS_WAFERS_IN$>
If Not(Num(WafersIn)) then
// Log the WafersIn value
LogData = ''
LogData<1> = LoggingDTM
LogData<2> = RDSNo
LogData<3> = WafersIn
Logging_Services('AppendLog', objWafersLog, LogData, @RM, @FM)
WafersIn = WafersIn<1, 1, 1>
end
IF UnloadDTM NE '' THEN
HoursTotal += (UnloadDTM - LoadDTM)*24
WafersInTotal += WafersIn
END
MinutesPerWfr = XLATE('PROD_SPEC',RDSRec<RDS_PROD_SPEC_ID$>,96,'X') ;* MD3 format
IF MinutesPerWfr = '' THEN MinutesPerWfr = ICONV('7.333','MD3') ;* Default per Todd to get us going with OEE
WfrsPerHour = ICONV(ICONV(60,'MD3')/MinutesPerWfr,'MD2') ;* Should be in MD2 format
TargetTotal += WfrsPerHour
NEXT I
IF HoursTotal = 0 THEN
Actual = ''
END ELSE
Actual = OCONV(ICONV(WafersInTotal/HoursTotal,'MD2'),'MD2') ;* Average Actual Wafers per Hour
END
IF RDSCount = 0 THEN
Target = ''
END ELSE
Target = OCONV(ICONV(TargetTotal/RDSCount,'MD0'),'MD2') ;* Average Target Wafers per Hour
END
Result = Actual:@RM:Target
RETURN
* * * * * * *
AddShip:
* * * * * * *
ShipNo = Parms[1,@RM]
RdsNo = Parms[COL2()+1,@RM]
ShipDt = Parms[COL2()+1,@RM]
ShipTm = Parms[COL2()+1,@RM]
Reship = Parms[COL2()+1,@RM]
If Reship EQ '' then
Reship = False$
end
IF NOT(ASSIGNED(RdsNo)) THEN ErrorMsg = 'Unassigned Parm "RdsNo" passed to routine. (':Method:')'
IF NOT(ASSIGNED(ShipNo)) THEN ErrorMsg = 'Unassigned Parm "ShipNo" passed to routine. (':Method:')'
IF NOT(ASSIGNED(ShipDt)) THEN ErrorMsg = 'Unassigned Parm "ShipDt" passed to routine. (':Method:')'
IF NOT(ASSIGNED(ShipTm)) THEN ErrorMsg = 'Unassigned Parm "ShipTm" passed to routine. (':Method:')'
IF ErrorMsg NE '' THEN RETURN
IF RdsNo = '' THEN ErrorMsg = 'Null Parm "RdsNo" passed to routine. (':Method:')'
IF ShipNo = '' THEN ErrorMsg = 'Null Parm "ShipNo" passed to routine. (':Method:')'
IF ShipDt = '' THEN ErrorMsg = 'Null Parm "ShipDt" passed to routine. (':Method:')'
IF ShipTm = '' THEN ErrorMsg = 'Null Parm "ShipTm" passed to routine. (':Method:')'
IF ErrorMsg NE '' THEN RETURN
thisShipDt = ICONV(ShipDt,'D')
IF thisShipDt = '' THEN
ErrorMsg = 'Invalid ShipDt ':QUOTE(ShipDt):' parameter passed to routine. (':Method:')'
RETURN
END
thisShipTm = ICONV(ShipTm,'MT')
IF thisShipTm = '' THEN
ErrorMsg = 'Invalid ShipTm ':QUOTE(ShipTm):' parameter passed to routine. (':Method:')'
RETURN
END
otParms = 'RDS':@RM:RdsNo
RDSRec = obj_Tables('ReadRec',otParms) ;* Reads and sets lock
IF Get_Status(errCode) THEN RETURN ;* Problems getting the lock
IF RDSRec<RDS_SHIP_NO$> = '' OR RDSRec<RDS_SHIP_NO$> = ShipNo or Reship EQ True$ THEN
RDSRec<RDS_SHIP_NO$> = ShipNo
RDSRec<RDS_SHIP_DATE$> = thisShipDt
RDSRec<RDS_SHIP_TIME$> = thisShipTm
RDSRec<RDS_STATUS$> = 'S'
otParms = FIELDSTORE(otParms,@RM,4,0,RDSRec)
obj_Tables('WriteRec',otParms)
END ELSE
obj_Tables('UnlockRec',otParms)
ErrorMsg = "RDS was already shipped on shipment" :QUOTE(RDSRec<RDS_SHIP_NO$>): ". (" :Method: ")"
END
RETURN
* * * * * * *
RemShip:
* * * * * * *
ShipNo = Parms[1,@RM]
RdsNo = Parms[COL2()+1,@RM]
IF NOT(ASSIGNED(RdsNo)) THEN ErrorMsg = 'Unassigned Parm "RdsNo" passed to routine. (':Method:')'
IF NOT(ASSIGNED(ShipNo)) THEN ErrorMsg = 'Unassigned Parm "ShipNo" passed to routine. (':Method:')'
IF ErrorMsg NE '' THEN RETURN
IF RdsNo = '' THEN ErrorMsg = 'Null Parm "RdsNo" passed to routine. (':Method:')'
IF ShipNo = '' THEN ErrorMsg = 'Null Parm "ShipNo" passed to routine. (':Method:')'
IF ErrorMsg NE '' THEN RETURN
otParms = 'RDS':@RM:RdsNo
RDSRec = obj_Tables('ReadRec',otParms) ;* Reads and sets lock
IF Get_Status(errCode) THEN RETURN ;* Problems getting the lock
IF RDSRec<RDS_SHIP_NO$> = ShipNo OR RDSRec<RDS_SHIP_NO$> = '' THEN
RDSRec<RDS_SHIP_NO$> = ''
RDSRec<RDS_SHIP_DATE$> = ''
RDSRec<RDS_SHIP_TIME$> = ''
RDSRec<RDS_STATUS$> = 'R'
otParms = FIELDSTORE(otParms,@RM,4,0,RDSRec)
obj_Tables('WriteRec',otParms)
END ELSE
obj_Tables('UnlockRec',otParms)
ErrorMsg = "Passed Ship No " :QUOTE(ShipNo): " doesn't match Ship No on RDS " :QUOTE(RdsNo): ". (" :Method: ")"
END
RETURN
* * * * * * *
RefreshRDSSpec:
* * * * * * *
RdsNos = Parms[1,@RM]
IF RdsNos = '' THEN RETURN
RTParms = 'RDS'
LockedRDSNos = ''
FOR I = 1 TO COUNT(RdsNos,@VM) + (RdsNos NE '')
RdsNo = RdsNos<1,I>
RTParms = FieldStore(RTParms, @RM, 2, 1, RdsNo)
obj_Tables('LockRec',RTParms)
IF Get_Status(errCode) THEN
FOR N = 1 TO COUNT(LockedRDSNos,@VM) + (LockedRDSNos NE '')
RTParms = FieldStore(RTParms, @RM, 2, 1, LockedRDSNos<1,N>)
obj_Tables('UnlockRec',RTParms) ;* Unlock everything locked up to here
NEXT N
ErrorMsg = 'Unable to lock RDS ':QUOTE(RdsNo):' for update.'
obj_Tables('UnlockRec',OTParms)
RETURN
END ELSE
LockedRDSNos<1,-1> = RdsNo
END
NEXT I
RDSTableVar = FIELD(RTParms,@RM,3)
FOR N = 1 TO COUNT(LockedRDSNos,@VM) + (LockedRDSNos NE '')
LockedRDSNo = LockedRDSNos<1,N>
READ RDSRec FROM RDSTableVar,LockedRDSNo THEN
PS_No = RDSRec<RDS_PROD_SPEC_ID$>
PSRec = XLATE('PROD_SPEC',PS_No,'','X')
RDSRec<RDS_SPECIAL_INST$> = PSRec<PROD_SPEC_SPEC_INST$>
RDSRec<RDS_SPEC_TYPE_ORIG$> = XLATE('PROD_SPEC',PS_No,'SPEC_TYPE','X')
LayerSpecs = obj_Prod_Spec('GetLayerProp',PS_No:@RM:@RM:1) ;* Returns specs for all layers
* LayerSpecs is @RM between layers, @FM between fields, LayerSet ID is in the first Field and needs to peeled off
* before the equates match up correctly
* Prod_Spec table has layer specs all in one field
* RDS has First layer stuff in individual fields and then has 2 and 3 shoved into Field 33 (Layer Info)
LayerSpec = FIELD(LayerSpecs,@RM,1) ;* Take the first Layer
LayerSet = FIELD(LayerSpec,@FM,1) ;* Not used here but shown for clarity
LayerSpec = FIELD(LayerSpec,@FM,2,99) ;* LayerSpec without the LayerSet
RecipeNo = LayerSpec<PRS_LAYER_RECIPE$>
RecipeRec = XLATE('RECIPE',RecipeNo,'','X') ;* This used in 2nd and 3rd layer stuff (in error it appears)
* IF RecipeNo NE RDSRec<RDS_RECIPE_NO$> THEN
* RDSRec<RDS_RECIPE_NO$> = RecipeNo
* END
RDSRec<RDS_CON_MIN_ORG$> = LayerSpec<PRS_LAYER_CONC_MIN$>
RDSRec<RDS_CON_MAX_ORG$> = LayerSpec<PRS_LAYER_CONC_MAX$>
RDSRec<RDS_CON_UNITS_ORG$> = LayerSpec<PRS_LAYER_CONC_UNITS$>
RDSRec<RDS_CON_TARGET_ORG$> = LayerSpec<PRS_LAYER_CONC_TARGET$>
RDSRec<RDS_RES_MIN_ORG$> = LayerSpec<PRS_LAYER_RES_MIN$>
RDSRec<RDS_RES_MAX_ORG$> = LayerSpec<PRS_LAYER_RES_MAX$>
RDSRec<RDS_RES_UNITS_ORG$> = LayerSpec<PRS_LAYER_RES_UNITS$>
RDSRec<RDS_RES_TARGET_ORG$> = LayerSpec<PRS_LAYER_RES_TARGET$>
RDSRec<RDS_THICK_MIN_ORG$> = LayerSpec<PRS_LAYER_THICK_MIN$>
RDSRec<RDS_THICK_MAX_ORG$> = LayerSpec<PRS_LAYER_THICK_MAX$>
RDSRec<RDS_THICK_UNITS_ORG$> = LayerSpec<PRS_LAYER_THICK_UNITS$>
RDSRec<RDS_THICK_TARGET_ORG$> = LayerSpec<PRS_LAYER_THICK_TARGET$>
LayerInfo = ''
FOR I = 2 TO COUNT(LayerSpecs,@RM) + (LayerSpecs NE '')
LayerSpec = FIELD(LayerSpecs,@RM,I) ;* Take the Ith Layer
LayerSpec = FIELD(LayerSpec,@FM,2,99) ;* LayerSpec without the LayerSet
thisLayerInfo = '' ;* Empty bucket to parse into
thisLayerInfo<1,RLConMin$> = LayerSpec<PRS_LAYER_CONC_MIN$>
thisLayerInfo<1,RLConMax$> = LayerSpec<PRS_LAYER_CONC_MAX$>
thisLayerInfo<1,RLConUnits$> = LayerSpec<PRS_LAYER_CONC_UNITS$>
thisLayerInfo<1,RLConTarget$> = LayerSpec<PRS_LAYER_CONC_TARGET$>
thisLayerInfo<1,RLRecipeNo$> = RecipeNo ;* Copied from the original in the WRITE event of the Schedule window
thisLayerInfo<1,RLThickRead$> = STR(@SVM,16)
thisLayerInfo<1,RLSheetRhoRead$> = STR(@SVM,16)
thisLayerInfo<1,RLResMin$> = LayerSpec<PRS_LAYER_RES_MIN$>
thisLayerInfo<1,RLResMax$> = LayerSpec<PRS_LAYER_RES_MAX$>
thisLayerInfo<1,RLResUnits$> = LayerSpec<PRS_LAYER_RES_UNITS$>
thisLayerInfo<1,RLResTarget$> = LayerSpec<PRS_LAYER_RES_TARGET$>
thisLayerInfo<1,RLThickMin$> = LayerSpec<PRS_LAYER_THICK_MIN$>
thisLayerInfo<1,RLThickMax$> = LayerSpec<PRS_LAYER_THICK_MAX$>
thisLayerInfo<1,RLThickUnits$> = LayerSpec<PRS_LAYER_THICK_UNITS$>
thisLayerInfo<1,RLThickTarget$> = LayerSpec<PRS_LAYER_THICK_TARGET$>
LayerInfo := thisLayerInfo:CHAR(248)
NEXT I
LayerInfo[-1,1] = '' ;* Strip trailing CHAR(248)
RDSRec<RDS_LAYER_INFO$> = LayerInfo ;* End of the great Layer cluster function
RTParms = FieldStore(RTParms, @RM, 2, 1, LockedRDSNo)
RTParms = FieldStore(RTParms, @RM, 4, 1, RDSRec)
obj_Tables('WriteRec',RTParms) ;* Write and unlock RDS records
END
NEXT N
RETURN
* * * * * * *
WMInKeys:
* * * * * * *
InFlag = 1
OutFlag = 0
GOTO WMKeys
* * * * * * *
WMOutKeys:
* * * * * * *
OutFlag = 1
InFlag = 0
* * * * * * *
WMKeys:
* * * * * * *
RDSNo = Parms[1,@RM]
RDSRec = Parms[COL2()+1,@RM]
IF RDSNo = '' THEN RETURN
IF RDSRec = '' THEN RDSRec = XLATE('RDS',RDSNo,'','X')
IF InFlag THEN
CassNos = RDSRec<RDS_IN_CASS_NO$>
END ELSE
CassNos = RDSRec<RDS_OUT_CASS_NO$>
END
WOStepKey = RDSRec<RDS_WO_STEP_KEY$>
CassIDS = ''
FOR I = 1 TO COUNT(CassNos,@VM) + (CassNos NE '')
CassNo = CassNos<1,I>
IF CassNo NE '' THEn
LOCATE WOStepKey:'*':CassNo IN CassIDS BY 'AR' USING @VM SETTING Pos ELSE
CassIDS = INSERT(CassIDS,1,Pos,0,WOStepKey:'*':CassNo)
END
END
NEXT I
Result = CassIDS
RETURN
* * * * * * *
SetSchedWfrQty:
* * * * * * *
RdsNo = Parms[1,@RM]
SchedWfrQty = Parms[COL2()+1,@RM]
IF RdsNo = '' THEN ErrorMsg = 'Null Parm "RdsNo" passed to routine. (':Method:')'
IF SchedWfrQty = '' THEN ErrorMsg = 'Null Parm "SchedWfrQty" passed to routine. (':Method:')'
IF ErrorMsg NE '' THEN RETURN
otParms = 'RDS':@RM:RdsNo
RDSRec = obj_Tables('ReadRec',otParms) ;* Reads and sets lock
IF Get_Status(errCode) THEN RETURN ;* Problems getting the lock
RDSRec<RDS_CASS_WAFER_QTY$> = SchedWfrQty
otParms = FIELDSTORE(otParms,@RM,4,0,RDSRec)
obj_Tables('WriteRec',otParms)
RETURN
* * * * * * *
MU_ADE_Reads:
* * * * * * *
RDSNo = Parms[1,@RM]
RDSRec = Parms[COL2()+1,@RM]
IF RDSNo = '' THEN RETURN
IF RDSRec = '' THEN RDSRec = XLATE('RDS',RDSNo,'','X')
IF RDSRec = '' THEN RETURN
WONo = RDSRec<RDS_WO$>
CassNo = RDSRec<RDS_CASS_NO$>
MUCassIDs = obj_WO_Mat('GetMUCassIDs',WONo:'*':CassNo)
Result = XLATE('WO_MAT',MUCassIDs,'ADE_READ','X')
RETURN
* * * * * * * *
MetPropFlag:
* * * * * * * *
RDSNo = Parms[1,@RM]
RDSRec = Parms[COL2()+1,@RM]
PropCd = Parms[COL2()+1,@RM]
IF RDSNo = '' THEN RETURN
IF PropCd = '' THEN RETURN
IF RDSRec = '' THEN RDSRec = XLATE('RDS',RDSNo,'','X')
IF RDSRec = '' THEN RETURN
WONo = RDSRec<RDS_WO$>
WOStepKey = RDSRec<RDS_WO_STEP_KEY$>
ReactNo = RDSRec<RDS_REACTOR$>
PSNo = RDSRec<RDS_PROD_SPEC_ID$>
WOStepNo = FIELD(WOStepKey,'*',2)
ReactRDSNos = XLATE('WO_REACT',WONo:'*':WOStepNo:'*':ReactNo,WO_REACT_RDS_NO$,'X')
LOCATE RDSNo IN ReactRDSNos USING @VM SETTING Pos THEN
Result = obj_PRS_Prop('GetIntervalFlag',PSNo:@RM:PropCd:@RM:Pos)
END
RETURN
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* P r i v a t e M e t h o d s *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * *
CalcConTarget:
* * * * * * *
IF RDSConMin AND RDSConMax THEN
IF RDSConMin = RDSConMax THEN
RDSConTarget = RDSConMin
END ELSE
Delta = INT((RdsConMax-RDSConMin)/2)
RDSConTarget = RDSConMin + Delta
END
END ELSE
RDSConTarget = ''
END
RETURN
* * * * * * *
CalcResTarget:
* * * * * * *
IF RDSResMin AND RDSResMax THEN
IF RDSResMin = RDSResMax THEN
RDSResTarget = RDSResMin
END ELSE
Delta = INT((RdsResMax-RDSResMin)/2)
RDSResTarget = RDSResMin + Delta
END
END ELSE
RDSResTarget = ''
END
RETURN
* * * * * * *
CalcThickTarget:
* * * * * * *
IF RDSThickMin AND RDSThickMax THEN
IF RDSThickMin = RDSThickMax THEN
RDSThickTarget = RDSThickMin
END ELSE
Delta = INT((RdsThickMax-RDSThickMin)/2)
RDSThickTarget = RDSThickMin + Delta
END
END ELSE
RDSThickTarget = ''
END
RETURN