open-insight/LSL2/STPROC/RDS_ACTIONS.txt

1046 lines
38 KiB
Plaintext

Function RDS_Actions(Action, CalcColName, FSList, Handle, Name, FMC, Record, Status, OrigRecord, Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10)
/***********************************************************************************************************************
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 Infineon.
Name : RDS_Actions
Description : Handles calculated columns and MFS calls for the current table.
Notes : This function uses @ID, @RECORD, and @DICT to make sure {ColumnName} references work correctly.
If called from outside of a calculated column these will need to be set and restored.
Parameters :
Action [in] -- Name of the action to be taken
CalcColName [in] -- Name of the calculated column that needs to be processed. Normally this should only be
populated when the CalcField action is being used.
FSList [in] -- The list of MFSs and the BFS name for the current file or volume. This is an @SVM
delimited array, with the current MFS name as the first value in the array, and the BFS
name as the last value. Normally set by a calling MFS.
Handle [in] -- The file handle of the file or media map being accessed. Note, this does contain the
entire handle structure that the Basic+ Open statement would provide. Normally set by a
calling MFS.
Name [in] -- The name (key) of the record or file being accessed. Normally set by a calling MFS.
FMC [in] -- Various functions. Normally set by a calling MFS.
Record [in] -- The entire record (for record-oriented functions) or a newly-created handle (for
"get handle" functions). Normally set by a calling MFS.
Status [in/out] -- Indicator of the success or failure of an action. Normally set by the calling MFS but
for some actions can be set by the action handler to indicate failure.
OrigRecord [in] -- Original content of the record being processed by the current action. This is
automatically being assigned by the WRITE_RECORD and DELETE_RECORD actions within
BASE_MFS.
Param1-10 [in/out] -- Additional request parameter holders
ActionFlow [out] -- Used to control the action chain (see the ACTION_SETUP insert for more information.)
Can also be used to return a special value, such as the results of the CalcField
method.
History : (Date, Initials, Notes)
04/10/18 dmb Original programmer.
10/04/18 djs Added a trigger within the WRITE_RECORD event, which fires when the reactor number has
changed. When this occurs the related RDS_LAYER records for this RDS record are populated
with the most recent associated TOOL_PARMS record. (related by PSN and Reactor)
***********************************************************************************************************************/
#pragma precomp SRP_PreCompiler
$Insert FILE.SYSTEM.EQUATES
$Insert ACTION_SETUP
$Insert RDS_EQUATES
$Insert CLEAN_INSP_EQUATES
$Insert COMPANY_EQUATES
$Insert RDS_LAYER_EQUATES
$Insert TOOL_PARMS_EQUATES
$Insert RLIST_EQUATES
$Insert APP_INSERTS
$Insert QA_MET_EQUATES
$Insert PRS_STAGE_EQUATES
$Insert WO_MAT_EQUATES
$Insert WO_MAT_QA_EQUATES
$Insert LOT_EVENT_EQUATES
Equ COMMA$ to ','
Declare function Error_Services, Database_Services, obj_RDS_Test, Logging_Services, Environment_Services
Declare function Tool_Parms_Services, Signature_Services, obj_WO_Mat_QA, Datetime, Override_Services
Declare function Rds_Services, SRP_DateTime, SRP_Math, obj_WO_Mat, Lot_Services, SRP_Array
Declare subroutine Error_Services, Database_Services, Logging_Services, Service_Services
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$)
LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM
LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\RDS'
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' RDS Erase attempt.csv'
Headers = 'Logging DTM' : @FM : 'RDSNo' : @FM : 'WONo' : @FM : 'CassNo' : @FM : 'Reactor Type'
objLog3 = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$)
If KeyID then GoSub Initialize_System_Variables
Begin Case
Case Action _EQC 'CalculateColumn' ; GoSub CalculateColumn
Case Action _EQC 'READ_RECORD_PRE' ; GoSub READ_RECORD_PRE
Case Action _EQC 'READ_RECORD' ; GoSub READ_RECORD
Case Action _EQC 'READONLY_RECORD_PRE' ; GoSub READONLY_RECORD_PRE
Case Action _EQC 'READONLY_RECORD' ; GoSub READONLY_RECORD
Case Action _EQC 'WRITE_RECORD_PRE' ; GoSub WRITE_RECORD_PRE
Case Action _EQC 'WRITE_RECORD' ; GoSub WRITE_RECORD
Case Action _EQC 'DELETE_RECORD_PRE' ; GoSub DELETE_RECORD_PRE
Case Action _EQC 'DELETE_RECORD' ; GoSub DELETE_RECORD
Case Otherwise$ ; Status = 'Invalid Action'
End Case
If KeyID then GoSub Restore_System_Variables
If Assigned(ActionFlow) else ActionFlow = ACTION_CONTINUE$
Return ActionFlow
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Calculated Columns
//
// The typical structure of a calculated column will look like this:
//
// Declare function Database_Services
//
// @ANS = Database_Services('CalculateColumn')
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CalculateColumn:
// Make sure the ActionFlow return variable is cleared in case nothing is calculated.
ActionFlow = ''
Begin Case
Case CalcColName EQ 'CURR_STAGE' ; GoSub CURR_STAGE
Case CalcColName EQ 'DATETIME_IN' ; GoSub DATETIME_IN
CAse CalcColName EQ 'DATETIME_OUT' ; GoSub DATETIME_OUT
Case CalcColName EQ 'PRE_INST' ; GoSub PRE_INST
Case CalcColName EQ 'PRE_INST_ACK_REQ' ; GoSub PRE_INST_ACK_REQ
Case CalcColName EQ 'FWI_INST' ; GoSub FWI_INST
Case CalcColName EQ 'FWI_INST_ACK_REQ' ; GoSub FWI_INST_ACK_REQ
Case CalcColName EQ 'LWI_INST' ; GoSub LWI_INST
Case CalcColName EQ 'LWI_INST_ACK_REQ' ; GoSub LWI_INST_ACK_REQ
Case CalcColName EQ 'QA_INST' ; GoSub QA_INST
Case CalcColName EQ 'QA_INST_ACK_REQ' ; GoSub QA_INST_ACK_REQ
Case CalcColName EQ 'LOAD_INST' ; GoSub LOAD_INST
Case CalcColName EQ 'LOAD_INST_ACK_REQ' ; GoSub LOAD_INST_ACK_REQ
Case CalcColName EQ 'UNLOAD_INST' ; GoSub UNLOAD_INST
Case CalcColName EQ 'UNLOAD_INST_ACK_REQ' ; GoSub UNLOAD_INST_ACK_REQ
Case CalcColName EQ 'ON_TW_FREQ' ; GoSub ON_TW_FREQ
Case CalcColName EQ 'POST_INST' ; GoSub POST_INST
Case CalcColName EQ 'POST_INST_ACK_REQ' ; GoSub POST_INST_ACK_REQ
Case CalcColName EQ 'ROTR_ACTION' ; GoSub ROTR_ACTION
Case CalcColName EQ 'RDS_LAYER_ACK_REQ' ; GoSub RDS_LAYER_ACK_REQ
Case CalcColName EQ 'RUNTIME' ; GoSub RUNTIME
Case CalcColName EQ 'SUPPL_ACK_REQ' ; GoSub SUPPL_ACK_REQ
Case CalcColName EQ 'WAFER_COUNT_ACK_REQ' ; GoSub WAFER_COUNT_ACK_REQ
Case CalcColName EQ 'TW_PROD' ; GoSub TW_PROD
Case CalcColName EQ 'ABBREV_OR_CO_NAME' ; GoSub ABBREV_OR_CO_NAME
Case CalcColName EQ 'LOAD_LOCK_REQ' ; GoSub LOAD_LOCK_REQ
Case CalcColName EQ 'UNLOAD_THICK_TEST' ; GoSub UNLOAD_THICK_TEST
Case CalcColName EQ 'WO_MAT_KEY' ; GoSub WO_MAT_KEY
Case CalcColName EQ 'HOT_LOT' ; GoSub HOT_LOT
End Case
return
DATETIME_IN:
TimeIn = {TIME_IN}
TimeIn = TimeIn/86400
TimeIn = SRP_Math('ROUND', TimeIn, 5)
TimeIn = TimeIn[2, 6]
ActionFlow = {DATE_IN}:TimeIn
return
DATETIME_OUT:
TimeOut = {TIME_OUT}
TimeOut = TimeOut/86400
TimeOut = SRP_Math('ROUND', TimeOut, 5)
TimeOut = TimeOut[2, 6]
ActionFlow = {DATE_OUT}:TimeOut
return
LOAD_LOCK_REQ:
ActionFlow = False$
ReactorType = {REACTOR_TYPE}
LoadLock = {LOAD_LOCK_SIDE}
If ( ( (ReactorType EQ 'ASM+') or (ReactorType EQ 'HTR') ) and (LoadLock EQ '') ) then ActionFlow = True$
return
CURR_STAGE:
Stage = ''
RDSNo = @ID
Stage = Rds_Services('GetCurrentStage', RDSNo)
ActionFlow = Stage
return
PRE_INST:
PSN = {PROD_SPEC_ID}
StageInst = Xlate('PRS_STAGE', PSN:'*PRE', 'INST', 'X')
Convert @TM to ' ' in StageInst
ActionFlow = StageInst
return
PRE_INST_ACK_REQ:
If ( ({PRE_INST} NE '') and ( ({PRE_INST_ACK} EQ '') or ({PRE_INST_ACK} EQ False$) ) and ({CURR_STAGE} EQ 'VER') ) then
ActionFlow = True$
end else
ActionFlow = False$
end
return
FWI_INST:
PSN = {PROD_SPEC_ID}
StageInst = Xlate('PRS_STAGE', PSN:'*FWI', 'INST', 'X')
Convert @TM to ' ' in StageInst
ActionFlow = StageInst
return
FWI_INST_ACK_REQ:
If ( ({FWI_INST} NE '') and ( ({FWI_INST_ACK} EQ '') or ({FWI_INST_ACK} EQ False$) ) and ({CURR_STAGE} EQ 'LOAD') ) then
ActionFlow = True$
end else
ActionFlow = False$
end
return
LWI_INST:
PSN = {PROD_SPEC_ID}
StageInst = Xlate('PRS_STAGE', PSN:'*LWI', 'INST', 'X')
Convert @TM to ' ' in StageInst
ActionFlow = StageInst
return
LWI_INST_ACK_REQ:
If ( ({LWI_INST} NE '') and ( ({LWI_INST_ACK} EQ '') or ({LWI_INST_ACK} EQ False$) ) and ({CURR_STAGE} EQ 'UNLOAD') ) then
ActionFlow = True$
end else
ActionFlow = False$
end
return
POST_INST:
PSN = {PROD_SPEC_ID}
StageInst = Xlate('PRS_STAGE', PSN:'*POST', 'INST', 'X')
Convert @TM to ' ' in StageInst
ActionFlow = StageInst
return
POST_INST_ACK_REQ:
If ( ({POST_INST} NE '') and ( ({POST_INST_ACK} EQ '') or ({POST_INST_ACK} EQ False$) ) and ({CURR_STAGE} EQ 'POST') ) then
ActionFlow = True$
end else
ActionFlow = False$
end
return
QA_INST:
PSN = {PROD_SPEC_ID}
StageInst = Xlate('PRS_STAGE', PSN:'*QA', 'INST', 'X')
Convert @TM to ' ' in StageInst
ActionFlow = StageInst
return
QA_INST_ACK_REQ:
If ( ({QA_INST} NE '') and ( ({QA_INST_ACK} EQ '') or ({QA_INST_ACK} EQ False$) ) and ({CURR_STAGE} EQ 'QA') ) then
ActionFlow = True$
end else
ActionFlow = False$
end
return
LOAD_INST:
PSN = {PROD_SPEC_ID}
StageInst = Xlate('PRS_STAGE', PSN:'*LOAD', 'INST', 'X')
Convert @TM to ' ' in StageInst
ActionFlow = StageInst
return
LOAD_INST_ACK_REQ:
If ( ({LOAD_INST} NE '') and ( ({LOAD_INST_ACK} EQ '') or ({LOAD_INST_ACK} EQ False$) ) and ({CURR_STAGE} EQ 'LOAD') ) then
ActionFlow = True$
end else
ActionFlow = False$
end
return
UNLOAD_INST:
PSN = {PROD_SPEC_ID}
StageInst = Xlate('PRS_STAGE', PSN:'*UNLOAD', 'INST', 'X')
Convert @TM to ' ' in StageInst
ActionFlow = StageInst
return
UNLOAD_INST_ACK_REQ:
If ( ({UNLOAD_INST} NE '') and ( ({UNLOAD_INST_ACK} EQ '') or ({UNLOAD_INST_ACK} EQ False$) ) and ({CURR_STAGE} EQ 'UNLOAD') ) then
ActionFlow = True$
end else
ActionFlow = False$
end
return
UNLOAD_THICK_TEST:
UnloadThickTest = ''
Parms = {WO_MAT_KEY}:@RM
Parms := '':@RM
Parms := FIELD(@RECORD<256>,'*',2):@RM ;* WOStep
Parms := 'UNLOAD':@RM
Parms := WO_MAT_QA_PROFILE$
QAMetArray = obj_WO_Mat_QA('GetQAMet', Parms)
For each Row in QAMetArray using @FM setting fPos
Locate 'THICK_ONLY' in Row using @VM setting vPos then
UnloadThickTest = True$
end
Until UnloadThickTest EQ True$
Next Row
ActionFlow = UnloadThickTest
return
SUPPL_ACK_REQ:
ActionFlow = False$
SupplementFlag = {SUPPLEMENT}
SupplAck = {SUPPL_ACK}
If ( (SupplementFlag EQ True$) and ( (SupplAck EQ '') or (SupplAck EQ False$) ) ) then
ActionFlow = True$
end
return
RDS_LAYER_ACK_REQ:
ActionFlow = False$
IsTestWafer = {ON_TW_FREQ}
RDSLayerAck = {RDS_LAYER_ACK}
If ( (IsTestWafer EQ True$) and ( (RDSLayerAck EQ False$) or (RDSLayerAck EQ '') ) ) then
ActionFlow = True$
end
return
WAFER_COUNT_ACK_REQ:
ActionFlow = False$
If ( ({CURR_STAGE} EQ 'VER') and ( ({WAFER_COUNT_ACK} EQ False$) or ({WAFER_COUNT_ACK} EQ '') ) ) then
ActionFlow = True$
end
return
ON_TW_FREQ:
ActionFlow = False$
CassNo = {CASS_NO}
PSNo = {PROD_SPEC_ID}
UnloadKey = PSNo:'*UNLOAD'
UnloadRec = Database_Services('ReadDataRow', 'PRS_STAGE', UnloadKey)
Intervals = UnloadRec<PRS_STAGE_MET_INTERVAL$>
Starts = UnloadRec<PRS_STAGE_MET_START$>
MetTests = UnloadRec<PRS_STAGE_MET_TEST$>
TestSlots = UnloadRec<PRS_STAGE_MET_SLOT$>
Found = False$
For each MetTest in MetTests using @VM setting vPos
TestSlot = TestSlots<0, vPos>
If (MetTest EQ 'THICK_ONLY') and (TestSlot EQ 'L') then Found = True$
Until Found EQ True$
Next MetTest
If Found EQ True$ then
TestWaferFlag = 0
Interval = Intervals<0, vPos>
Start = Starts<0, vPos>
IF Interval NE '' AND Start NE '' THEN
IF Interval = Start THEN
IF REM(CassNo,Interval) = 0 THEN TestWaferFlag = 1
END ELSE
IF ABS((Start + INT(CassNo/Interval)*Interval) - CassNo) = 0 THEN TestWaferFlag = 1
END
end
ActionFlow = TestWaferFlag
end
return
ROTR_ACTION:
CleanInspRow = Database_Services('ReadDataRow', 'CLEAN_INSP', {LWI_CI_NO})
ROTRAction = CleanInspRow<CLEAN_INSP_ROTR_ACTION$>
If ROTRAction EQ 'F' then
// Before returning a Fail, check to see if there is an acceptance for the results.
AcceptedSignature = CleanInspRow<CLEAN_INSP_SIGN_ROTR_SIGNATURE$>
AcceptedReason = CleanInspRow<CLEAN_INSP_SIGN_ROTR_REASON$>
If (AcceptedSignature NE '') AND (AcceptedReason NE '') then ROTRAction = 'A'
end
ActionFlow = ROTRAction
return
TW_PROD:
IF {REACTOR_TYPE} = 'EPP' THEN
WaferChars = @RECORD<275>
PktChars = @RECORD<268>
OutCnt = COUNT(PktChars,@VM) + (PktChars NE '')
Ans = 0
FOR I = 1 TO OutCnt
PktChar = PktChars<1,I>
WfrChar = WaferChars<1,I>
IF PktChar = 'TEST' AND WfrChar = 'PROD' THEN Ans += 1
NEXT I
ActionFlow = Ans
END ELSE
TestKeys = XLATE('RDS_LAYER',@RECORD<150>,3,'X')
ActionFlow = obj_RDS_Test('ProdTestCount',TestKeys)
END
return
ABBREV_OR_CO_NAME:
CompRec = Database_Services('ReadDataRow', 'COMPANY', {CUST_NO})
CustomerName = CompRec<COMPANY_ABBREV$>
ActionFlow = CustomerName
return
WO_MAT_KEY:
ActionFlow = ''
ReactType = {REACTOR_TYPE}
IF {REACTOR_TYPE} NE 'EPP' THEN
WONo = @RECORD<6>
CassNo = @RECORD<260>
IF WONo NE '' AND CassNo NE '' THEN
ActionFlow = WONo:'*':CassNo
END
END
If ActionFlow EQ '' and ReactType NE 'EPP' and ReactType NE 'GAN' then
RDSNo = @ID
// Log the above data to troubleshoot.
LogData = ''
LogData<1> = LoggingDTM
LogData<2> = RDSNo
LogData<3> = @Record<RDS_WO$>
LogData<4> = @Record<RDS_CASS_NO$>
LogData<5> = ReactType
Logging_Services('AppendLog', objLog3, LogData, @RM, @FM)
end
return
RUNTIME:
LoadDTM = IConv(OConv({DATE_IN}, 'D'):' ':OConv({TIME_IN}, 'MT'), 'DT')
LoadEx2DTM = IConv(OConv({OP_IN_EX2_DATE}, 'D'):' ':OConv({OP_IN_EX2_TIME}, 'MT'), 'DT')
LoadEx3DTM = IConv(OConv({OP_IN_EX3_DATE}, 'D'):' ':OConv({OP_IN_EX3_TIME}, 'MT'), 'DT')
UnloadEx1DTM = IConv(OConv({OP_OUT_EX1_DATE}, 'D'):' ':OConv({OP_OUT_EX1_TIME}, 'MT'), 'DT')
UnloadEx2DTM = IConv(OConv({OP_OUT_EX2_DATE}, 'D'):' ':OConv({OP_OUT_EX2_TIME}, 'MT'), 'DT')
UnloadDTM = IConv(OConv({DATE_OUT}, 'D'):' ':OConv({TIME_OUT}, 'MT'), 'DT')
Begin Case
Case UnloadEx2DTM NE ''
Runtime = UnloadEx2DTM - LoadEx3DTM
Case UnloadEx1DTM NE ''
Runtime = UnloadEx1DTM - LoadEx2DTM
Case Otherwise$
Runtime = UnloadDTM - LoadDTM
End Case
ActionFlow = Runtime
return
HOT_LOT:
ActionFlow = Xlate('WO_LOG', {WO}, 'HOT_FLAG', 'X')
return
// ----- MFS calls -----------------------------------------------------------------------------------------------------
READ_RECORD_PRE:
// In order to stop a record from being read in this action these lines of code must be used:
//
// OrigFileError = 100 : @FM : KeyID
// Status = 0
// Record = ''
// ActionFlow = ACTION_STOP$
* This code prevents an anomaly where an @SVM appears when the value is read
* and causes an error when copying the record to SQL.
WafersIn = Record<RDS_WAFERS_IN$>
WafersIn = WafersIn<1, 1, 1>
Record<RDS_WAFERS_IN$> = WafersIn
return
READ_RECORD:
// In order to stop a record from being read in this action these lines of code must be used:
//
// OrigFileError = 100 : @FM : KeyID
// Status = 0
// Record = ''
Shift = Record<RDS_SHIFT$>
If Num(Shift) then
Begin Case
Case Shift EQ 1
Record<RDS_SHIFT$> = 'A'
Case Shift EQ 2
Record<RDS_SHIFT$> = 'B'
Case Shift EQ 3
Record<RDS_SHIFT$> = 'C'
Case Shift EQ 4
Record<RDS_SHIFT$> = 'D'
Case Otherwise$
Null
End Case
end
return
READONLY_RECORD_PRE:
// In order to stop a record from being read in this action these lines of code must be used:
//
// OrigFileError = 100 : @FM : KeyID
// Status = 0
// Record = ''
// ActionFlow = ACTION_STOP$
return
READONLY_RECORD:
// In order to stop a record from being read in this action these lines of code must be used:
//
// OrigFileError = 100 : @FM : KeyID
// Status = 0
// Record = ''
Shift = Record<RDS_SHIFT$>
If Num(Shift) then
Begin Case
Case Shift EQ 1
Record<RDS_SHIFT$> = 'A'
Case Shift EQ 2
Record<RDS_SHIFT$> = 'B'
Case Shift EQ 3
Record<RDS_SHIFT$> = 'C'
Case Shift EQ 4
Record<RDS_SHIFT$> = 'D'
Case Otherwise$
Null
End Case
end
return
WRITE_RECORD_PRE:
Shift = Record<RDS_SHIFT$>
If Num(Shift) then
Begin Case
Case Shift EQ 1
Record<RDS_SHIFT$> = 'A'
Case Shift EQ 2
Record<RDS_SHIFT$> = 'B'
Case Shift EQ 3
Record<RDS_SHIFT$> = 'C'
Case Shift EQ 4
Record<RDS_SHIFT$> = 'D'
Case Otherwise$
Null
End Case
end
SaveRecord = Record
RDSNo = Name
RDSKeyID = Name
OrigReactor = OrigRecord<RDS_REACTOR$>
NewReactor = Record<RDS_REACTOR$>
// Verify / Pre-Epi Signature
OrigVerSig = Trim(OrigRecord<RDS_PRE_EPI_SIG$>)
OrigVerDate = Trim(OrigRecord<RDS_PRE_EPI_SIG_DATE$>)
OrigVerTime = Trim(OrigRecord<RDS_PRE_EPI_SIG_TIME$>)
NewVerSig = Trim(Record<RDS_PRE_EPI_SIG$>)
NewVerDate = Trim(Record<RDS_PRE_EPI_SIG_DATE$>)
NewVerTime = Trim(Record<RDS_PRE_EPI_SIG_TIME$>)
If Not(Num(NewVerDate)) then Record<RDS_PRE_EPI_SIG_DATE$> = IConv(NewVerDate, 'D')
If Not(Num(NewVerTime)) then Record<RDS_PRE_EPI_SIG_TIME$> = IConv(NewVerTime, 'MT')
// Load Signature
OrigLoadSig = Trim(OrigRecord<RDS_OPERATOR_IN$>)
OrigLoadDate = Trim(OrigRecord<RDS_DATE_IN$>)
OrigLoadTime = Trim(OrigRecord<RDS_TIME_IN$>)
NewLoadSig = Trim(Record<RDS_OPERATOR_IN$>)
NewLoadDate = Trim(Record<RDS_DATE_IN$>)
NewLoadTime = Trim(Record<RDS_TIME_IN$>)
If Not(Num(NewLoadDate)) then Record<RDS_DATE_IN$> = IConv(NewLoadDate, 'D')
If Not(Num(NewLoadTime)) then Record<RDS_TIME_IN$> = IConv(NewLoadTime, 'MT')
// Unload signature
OrigDateOut = OrigRecord<RDS_DATE_OUT$>
OrigTimeOut = OrigRecord<RDS_TIME_OUT$>
OrigTimeOutSig = OrigRecord<RDS_OPERATOR_OUT$>
DateOut = Record<RDS_DATE_OUT$>
TimeOut = Record<RDS_TIME_OUT$>
TimeOutSig = Record<RDS_OPERATOR_OUT$>
If Not(Num(DateOut)) then Record<RDS_DATE_OUT$> = IConv(DateOut, 'D')
If Not(Num(TimeOut)) then Record<RDS_TIME_OUT$> = IConv(TimeOut, 'MT')
// FQA signature
OrigFQADate = OrigRecord<RDS_SUP_VER_SIG_DATE$>
OrigFQATime = OrigRecord<RDS_SUP_VER_SIG_TIME$>
OrigFQASig = OrigRecord<RDS_SUP_VER_SIG$>
FQADate = Record<RDS_SUP_VER_SIG_DATE$>
FQATime = Record<RDS_SUP_VER_SIG_TIME$>
FQASig = Record<RDS_SUP_VER_SIG$>
If Not(Num(FQADate)) then Record<RDS_SUP_VER_SIG_DATE$> = IConv(FQADate, 'D')
If Not(Num(FQATime)) then Record<RDS_SUP_VER_SIG_TIME$> = IConv(FQATime, 'MT')
CurrDTM = Datetime()
VerDTM = IConv(OConv(NewVerDate, 'D'):' ':OConv(NewVerTime, 'MT'), 'DT')
LoadDTM = IConv(OConv(NewLoadDate, 'D'):' ':OConv(NewLoadTime, 'MT'), 'DT')
LoadEx2DTM = IConv(OConv({OP_IN_EX2_DATE}, 'D'):' ':OConv({OP_IN_EX2_TIME}, 'MT'), 'DT')
LoadEx3DTM = IConv(OConv({OP_IN_EX3_DATE}, 'D'):' ':OConv({OP_IN_EX3_TIME}, 'MT'), 'DT')
UnloadEx1DTM = IConv(OConv({OP_OUT_EX1_DATE}, 'D'):' ':OConv({OP_OUT_EX1_TIME}, 'MT'), 'DT')
UnloadEx2DTM = IConv(OConv({OP_OUT_EX2_DATE}, 'D'):' ':OConv({OP_OUT_EX2_TIME}, 'MT'), 'DT')
UnloadDTM = IConv(OConv(DateOut, 'D'):' ':OConv(TimeOut, 'MT'), 'DT')
PostDTM = IConv(OConv({POST_EPI_SIG_DATE}, 'D'):' ':OConv({POST_EPI_SIG_TIME}, 'MT'), 'DT')
FQADTM = IConv(OConv({SUP_VER_SIG_DATE}, 'D'):' ':OConv({SUP_VER_SIG_TIME}, 'MT'), 'DT')
If NewLoadSig EQ '' then
// Audit the LOT_EVENT table for missing LOAD event (i.e., signature)
ExistingNGLotId = Lot_Services('GetLotIdByLegacyLotIdAndType', RDSNo, 'RDS')
If RowExists('LOT', ExistingNGLotId) then
LotEvents = Lot_Services('GetLotEventsInSequence', ExistingNGLotId)
If LotEvents NE '' then
LotEventsRev = SRP_Array('Reverse', LotEvents, @FM)
LotEventsTypesRev = Xlate('LOT_EVENT', LotEventsRev, LOT_EVENT_LOT_EVENT_TYPE$, 'X')
If LotEventsTypesRev NE '' then
Done = False$
For each LotEventType in LotEventsTypesRev using @FM setting EventPos
Begin Case
Case LotEventType EQ 'LOAD'
Done = True$
If NewLoadSig EQ '' then
// Load signature is missing from RDS record
NewLoadSig = Xlate('LOT_EVENT', LotEventsRev<EventPos>, LOT_EVENT_EVENT_OPERATOR_ID$, 'X')
NewLoadSigDtm = Xlate('LOT_EVENT', LotEventsRev<EventPos>, LOT_EVENT_EVENT_DATETIME$, 'X')
NewLoadDate = SRP_DateTime("Date", NewLoadSigDtm)
NewLoadTime = SRP_DateTime("Time", NewLoadSigDtm)
Record<RDS_OPERATOR_IN$> = NewLoadSig
Record<RDS_DATE_IN$> = NewLoadDate
Record<RDS_TIME_IN$> = NewLoadTime
LogData = ''
LogData<1> = LoggingDTM
LogData<2> = @User4
LogData<3> = RDSKeyID
LogData<4> = 'Detected missing LOAD signature from RDS record. Restored signature from LOT_EVENT table.'
Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$)
end
Case LotEventType EQ 'UNSIGN_LOAD'
Done = True$
// No need to check for missing load signature
End Case
Until Done
Next LotEventType
end
end
end
end
Begin Case
Case LoadDTM NE '' and UnloadDTM EQ '' and UnloadEx1DTM EQ ''
// Cassette still running...
Runtime = 0
Case LoadEx2DTM NE '' and UnloadEx2DTM EQ ''
// Cassette still running...
Runtime = 0
Case LoadEx3DTM NE '' and UnloadDTM EQ ''
// Cassette still running...
Runtime = 0
Case UnloadDTM NE '' and LoadEx3DTM EQ ''
// No extra load/unload (typical path)
Runtime = UnloadDTM - LoadDTM
Case UnloadDTM NE '' and LoadEx3DTM NE ''
// Three extra load/unloads
RunTime = UnloadDTM - LoadEx3DTM
Case UnloadEx2DTM NE ''
// Two extra load/unloads
Runtime = UnloadEx2DTM - LoadEx2DTM
Case UnloadEx1DTM NE ''
// One extra load/unload
Runtime = UnloadEx1DTM - LoadDTM
Case Otherwise$
Runtime = 0
End Case
// Look for UNLOAD_DTM override
Override = Override_Services('GetOverride', 'RDS', RDSNo, 'UNLOAD_DTM')
Begin Case
Case ( (OrigLoadSig NE '') and (OrigReactor NE NewReactor) )
LogData = ''
LogData<1> = LoggingDTM
LogData<2> = @USER4
LogData<3> = RDSKeyID
LogData<4> = 'Reactor number cannot be changed or removed once the load signature is set!'
Logging_Services('AppendLog', ObjLog, LogData, @RM, @FM, False$)
// User is attempting to erase data that is prohibited from being erased Set the FS104 error and block the write.
Error_Services('Add', 'Reactor number cannot be changed or removed once the load signature is set!')
OrigFileError = 104:': Reactor number cannot be changed or removed once the load signature is set!'
Status = 0
Record = ''
ActionFlow = ACTION_STOP$
Case ( (OrigVerSig NE '') and (NewVerSig EQ '') ) or ( (OrigVerDate NE '') and (NewVerDate EQ '') ) |
or ( (OrigVerTime NE '') and (NewVerTime EQ '') ) or ( (NewVerDate EQ '') and (NewVerTime NE '') ) |
or ( (NewVerDate NE '') and (NewVerTime EQ '') )
LogData = ''
LogData<1> = LoggingDTM
LogData<2> = @USER4
LogData<3> = RDSKeyID
LogData<4> = 'Signature data cannot be removed!'
Logging_Services('AppendLog', ObjLog, LogData, @RM, @FM, False$)
// User is attempting to erase data that is prohibited from being erased Set the FS104 error and block the write.
Error_Services('Add', 'Signature data cannot be removed!')
OrigFileError = 104:': Signature data cannot be removed!'
Status = 0
Record = ''
ActionFlow = ACTION_STOP$
Case ( (VerDTM GT CurrDTM) or (LoadDTM GT CurrDTM) or (LoadEx2DTM GT CurrDTM) or (LoadEx3DTM GT CurrDTM) |
or (UnloadEx1DTM GT CurrDTM) or (UnloadEx2DTM GT CurrDTM) or (UnloadDTM GT CurrDTM) |
or (PostDTM GT CurrDTM) or (FQADTM GT CurrDTM) )
RDSKeyID = Name
LogData = ''
LogData<1> = LoggingDTM
LogData<2> = @USER4
LogData<3> = RDSKeyID
LogData<4> = 'Signature datetime is greater than current datetime!'
Logging_Services('AppendLog', ObjLog, LogData, @RM, @FM, False$)
Error_Services('Add', 'Signature datetime is greater than current datetime!')
OrigFileError = 104:': Signature datetime is greater than current datetime!'
Status = 0
Record = ''
ActionFlow = ACTION_STOP$
Case ( ((VerDTM NE '' and LoadDTM NE '') and (LoadDTM LE VerDTM)) |
or (LoadDTM NE '' and UnloadDTM NE '') and (UnloadDTM LT LoadDTM) |
or (UnloadEx1DTM NE '' and LoadDTM NE '') and (UnloadEx1DTM LT LoadDTM) |
or (LoadEx2DTM NE '' and UnloadEx1DTM NE '') and (LoadEx2DTM LT UnloadEx1DTM) |
or (UnloadEx2DTM NE '' and LoadEx3DTM NE '') and (LoadEx3DTM LT UnloadEx2DTM) |
or (UnloadDTM NE '' and LoadEx3DTM NE '') and (UnloadDTM LT LoadEx3DTM) )
// QA > POST > Unload > LoadEx3 > UnloadEx2 > LoadEx2 > UnloadEx1 > Load
RDSKeyID = Name
LogData = ''
LogData<1> = LoggingDTM
LogData<2> = @USER4
LogData<3> = RDSKeyID
LogData<4> = 'Signature datetime is less than a previous signature datetime!'
Logging_Services('AppendLog', ObjLog, LogData, @RM, @FM, False$)
Error_Services('Add', 'Signature datetime is less than a previous signature datetime!')
OrigFileError = 104:': Signature datetime is less than a previous signature datetime!'
Status = 0
Record = ''
ActionFlow = ACTION_STOP$
Case ( (RunTime GT 3) and (Override EQ False$) )
RDSKeyID = Name
LogData = ''
LogData<1> = LoggingDTM
LogData<2> = @USER4
LogData<3> = RDSKeyID
LogData<4> = 'Cassette runtime exceeds three days!'
Logging_Services('AppendLog', ObjLog, LogData, @RM, @FM, False$)
Error_Services('Add', 'Cassette runtime exceeds three days!')
OrigFileError = 104:': Cassette runtime exceeds three days!'
Status = 0
Record = ''
ActionFlow = ACTION_STOP$
Case Otherwise$
SaveRecord = Record
End Case
return
WRITE_RECORD:
WONo = Record<RDS_WO$>
ReactType = Xlate('WO_LOG', WONo, 'REACT_TYPE', 'X')
EpiPro = (ReactType EQ 'EPP')
GaN = (ReactType EQ 'GAN')
NonEpiPro = ( (ReactType NE 'EPP') and (ReactType NE 'GAN') )
If NonEpiPro then
// Sync up VER, LOAD, UNLOAD, POST, and QA signatures with WO_MAT signature profile.
// The goal of signature services was to remove any dependency on the WO_MAT signature profile,
// however Fabtime relies on this data being replicated to the Scrape SQL DB.
WOMatKey = {WO_MAT_KEY}
WOMatRec = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey)
WOMatSigProf = obj_WO_Mat('CassSigProfile', WOMatKey)
WOMatSig = WOMatRec<WO_MAT_SIGNATURE$>
WOMatSigDTM = WOMatRec<WO_MAT_SIG_DTM$>
// Update WO_MAT signature profile to match for the "1VER" stage
Stage = '1VER'
Locate Stage in WOMatSigProf using @VM setting vPos then
WOMatSig<0, vPos> = Record<RDS_PRE_EPI_SIG$>
PreEpiDate = Record<RDS_PRE_EPI_SIG_DATE$>
If PreEpiDate NE '' then
PreEpiTime = Record<RDS_PRE_EPI_SIG_TIME$>
PreEpiSigDTM = PreEpiDate + (PreEpiTime/86400)
end else
PreEpiSigDTM = ''
end
WOMatSigDTM<0, vPos> = PreEpiSigDTM
end
// Update WO_MAT signature profile to match for "1LOAD" stage
Stage = '1LOAD'
Locate Stage in WOMatSigProf using @VM setting vPos then
WOMatSig<0, vPos> = Record<RDS_OPERATOR_IN$>
DateIn = Record<RDS_DATE_IN$>
If DateIn NE '' then
LoadTime = Record<RDS_TIME_IN$>
LoadSigDTM = DateIn + (LoadTime/86400)
end else
LoadSigDTM = ''
end
WOMatSigDTM<0, vPos> = LoadSigDTM
end
// Update WO_MAT signature profile to match for the "1UNLOAD" stage
Stage = '1UNLOAD'
Locate Stage in WOMatSigProf using @VM setting vPos then
WOMatSig<0, vPos> = Record<RDS_OPERATOR_OUT$>
DateOut = Record<RDS_DATE_OUT$>
If DateOut NE '' then
TimeOut = Record<RDS_TIME_OUT$>
TimeOutSigDTM = DateOut + (TimeOut/86400)
end else
TimeOutSigDTM = ''
end
WOMatSigDTM<0, vPos> = TimeOutSigDTM
end
// Update WO_MAT signature profile to match for the "1POST" stage
Stage = '1POST'
Locate Stage in WOMatSigProf using @VM setting vPos then
WOMatSig<0, vPos> = Record<RDS_POST_EPI_SIG$>
PostSigDate = Record<RDS_POST_EPI_SIG_DATE$>
If PostSigDate NE '' then
PostSigTime = Record<RDS_POST_EPI_SIG_TIME$>
PostSigDTM = PostSigDate + (PostSigTime/86400)
end else
PostSigDTM = ''
end
WOMatSigDTM<0, vPos> = PostSigDTM
end
// Update WO_MAT signature profile to match for the "1QA" stage
Stage = '1QA'
Locate Stage in WOMatSigProf using @VM setting vPos then
WOMatSig<0, vPos> = Record<RDS_SUP_VER_SIG$>
FQADate = Record<RDS_SUP_VER_SIG_DATE$>
If FQADate NE '' then
FQASigTime = Record<RDS_SUP_VER_SIG_TIME$>
FQASigDTM = FQADate + (FQASigTime/86400)
end else
FQASigDTM = ''
end
WOMatSigDTM<0, vPos> = FQASigDTM
end
WOMatRec<WO_MAT_SIG_PROFILE$> = WOMatSigProf
WOMatRec<WO_MAT_SIGNATURE$> = WOMatSig
WOMatRec<WO_MAT_SIG_DTM$> = WOMatSigDTM
Database_Services('WriteDataRow', 'WO_MAT', WOMatKey, WOMatRec, True$, False$, True$)
end
OrigDateOut = OrigRecord<RDS_DATE_OUT$>
NewDateOut = Record<RDS_DATE_OUT$>
If ( ( (OrigDateOut EQ '') and (NewDateOut NE '') ) ) then
// Mark this cassette as processed in the schedule event record
DatetimeOut = {DATETIME_OUT}
If EpiPro then
WMIKeys = {WM_IN_KEY}
For each WMIKey in WMIKeys using @VM setting vPos
CassNo = Field(WMIKey, '*', 3)
Service_Services('PostProcedure', 'SCHEDULE_SERVICES':@VM:'MarkCassProcessed':@VM:WONo:@VM:CassNo:@VM:DatetimeOut)
Next WMIKey
end else
CassNo = Record<RDS_CASS_NO$>
Service_Services('PostProcedure', 'SCHEDULE_SERVICES':@VM:'MarkCassProcessed':@VM:WONo:@VM:CassNo:@VM:DatetimeOut)
end
end
return
DELETE_RECORD_PRE:
Notes = RetStack()
Swap @FM with ' | ' in Notes
LogData = ''
LogData<1> = LoggingDTM
LogData<2> = @User4
LogData<3> = Name
LogData<4> = Notes
Logging_Services('AppendLog', objLog, LogData, @RM, @FM)
return
DELETE_RECORD:
return
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Internal GoSubs
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ClearCursors:
For counter = 0 to 8
ClearSelect counter
Next counter
return
Initialize_System_Variables:
// Save these for restoration later
SaveDict = @DICT
SaveID = @ID
SaveRecord = @RECORD
OrigFileError = @FILE.ERROR
// Now make sure @DICT, ID, and @RECORD are populated
CurrentDictName = ''
If @DICT then
DictHandle = @DICT<1, 2>
Locate DictHandle in @TABLES(5) Using @FM Setting fPos then
CurrentDictName = Field(@TABLES(0), @FM, fPos, 1)
end
end
If CurrentDictName NE DictName then
Open DictName to @DICT else Status = 'Unable to initialize @DICT'
end
@ID = KeyID
If Record else
// Record might not have been passed in. Read the record from the database table just to make sure.
@FILE.ERROR = ''
Open TableName to hTable then
FullFSList = hTable[1, 'F' : @VM]
BFS = FullFSList[-1, 'B' : @SVM]
LastHandle = hTable[-1, 'B' : \0D\]
FileHandle = \0D\ : LastHandle[1, @VM]
Call @BFS(READO.RECORD, BFS, FileHandle, KeyID, FMC, Record, ReadOStatus)
end
end
@RECORD = Record
return
Restore_System_Variables:
Transfer SaveDict to @DICT
Transfer SaveID to @ID
Transfer SaveRecord to @RECORD
@FILE.ERROR = OrigFileError
return