open-insight/LSL2/STPROC/SIGNATURE_SERVICES.txt

2848 lines
137 KiB
Plaintext

Compile function Signature_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 : Signature_Services
Description : Handler program for all module related services.
Notes : Service module to support environmental state issues. Environmental refers to the state of the
operating system, which includes version, client vs. server, and path to critical systems.
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
Metadata :
History : (Date, Initials, Notes)
11/07/19 djs Original programmer.
08/21/20 djs Updated GetSigInfo to support multiple CLEAN_INSP scans. The code will return the
signature info for the most recently signed scan.
07/13/21 djs Removed caching code (Memory_Services) so that users can sign multiple stages in quick
succession without causing issues related to caching the signature profile.
08/03/21 djs Restored caching code because it was causing the application to perform very poorly during
certain operations (e.g. releasing material). Added a UseCaching variable to all services,
so that developers can choose to use caching or not.
06/13/24 djm Add support for EPP signature profile.
***********************************************************************************************************************/
#pragma precomp SRP_PreCompiler
$insert POPUP_EQUATES
$INSERT LOGICAL
$Insert WO_MAT_EQUATES
$insert SERVICE_SETUP
$insert RLIST_EQUATES
$insert WO_MAT_QA_EQUATES
$insert RDS_EQUATES
$insert COMPANY_EQUATES
$insert APP_INSERTS
$insert CLEAN_INSP_EQUATES
$insert NCR_EQUATES
$insert WM_OUT_EQUATES
Equ SS_PASS$ To 1
Equ SS_SIG$ To 2
Equ SS_DATA$ To 3
Equ SS_NA$ To 4
Equ COL$LOG_FILE to 1
Equ COL$LOG_DTM to 2
Equ COL$ACTION to 3
Equ COL$WH_CD to 4
Equ COL$LOC_CD to 5
Equ COL$WO_NOS to 6
Equ COL$CASS_NOS to 7
Equ COL$USER_ID to 8
Equ COL$TAGS to 9
Equ COL$TOOL_ID to 10
Declare function obj_Prod_Spec, RDS_Services, Error_Services, Signature_Services, Memory_Services, obj_RDS_Test
Declare function Database_Services, obj_WO_Mat, Dialog_Box, MemberOf, Msg, QA_Services, Datetime, Supplement_Services
Declare subroutine Error_Services, Popup, Memory_Services, SRP_Stopwatch, Set_Status, Database_Services, obj_WO_Mat
Declare subroutine Obj_Notes, Signature_Services, Obj_WO_Mat_Log, ErrMsg
PSNKey = ServiceKeyID
ReactorKey = ServiceKeyID
GoToService
Return Response or ""
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Service Parameter Options
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Options CI_STAGES = 'PREI,PREC,PRES,FWII,FWIC,FWIS,LWII,LWIC,LWIS,PSTI,PSTC,PSTS'
Options QA_STAGES = 'LOAD,UNLOAD,QA'
Options SLOTS = '1,2,3,4,5,6,F,L,A' ; // From SYSREPOSPOPUPS LSL2**TEST_SLOTS
//-----------------------------------------------------------------------------
// SERVICES
//-----------------------------------------------------------------------------
Service FQAReady(WOMatKey, UseCaching)
If UseCaching EQ '' then UseCaching = True$
Response = False$
SigProfile = Signature_Services('GetSigProfile', WOMatKey, UseCaching)
Stages = SigProfile<1>
Sigs = SigProfile<2>
SigDTMs = SigProfile<3>
NumStages = DCount(Stages, @VM)
If NumStages GT 1 then
Done = False$
For StageIndex = 1 to (NumStages - 1)
Stage = Stages<0, StageIndex>
StageComp = Signature_Services('CheckSignature', WOMatKey, Stage)
If StageComp EQ False$ then
Done = True$
ErrorMsg = 'Unable to sign FQA due to incomplete Signature Profile at ':Stage:' stage.'
Error_Services('Add', ErrorMsg)
end
Until Done EQ True$
Next StageIndex
end
If Error_Services('NoError') then Response = True$
end service
Service CheckQALabelStatus(WOMatKey)
rec = Xlate('WO_MAT', WoMatKey,'', '')
locRec = rec<WO_MAT_INV_LOCATION$>
actionRec = rec<WO_MAT_INV_ACTION$>
retVal = 0
Locate 'LBLCHK' In actionRec Using @VM Setting locIdx Then
Locate 'PKO' in locRec Using @VM Setting idx Then
if idx GE 1 then
If (rec<WO_MAT_INV_USER$, idx> NE '' AND rec<WO_MAT_INV_DTM$, idx> NE '') then
retVal = 1
end
end
end
end
Response = retVal
end service
Service GetSigProfile(WOMatKey, UseCaching, RDSNo)
If UseCaching EQ '' then UseCaching = True$
SigProfile = ''
Signatures = ''
SigDTMs = ''
If RDSNo NE '' then
WONo = Xlate('RDS', RDSNo, 'WO', 'X')
end else
WONo = Field(WOMatKey, '*', 1)
end
PSNo = Xlate('WO_LOG', WONo, 'PS_NO', 'X')
SigProfKey = PSNo:'*':WOMatKey:'*':RDSNo
ReactorKey = PSNo :'*Reactor'
If UseCaching and Memory_Services('IsValueCurrent', SigProfKey, 60, True$) then
SigProfile = Memory_Services('GetValue', SigProfKey)
end else
SigProfile = obj_Prod_Spec('GetSigProfile', PSNo:@RM:'':@RM:WOMatKey:@RM:RDSNo)
Memory_Services('SetValue', SigProfKey, SigProfile)
end
If UseCaching and Memory_Services('IsValueCurrent', ReactorKey, 60, True$) then
ReactorType = Memory_Services('GetValue', ReactorKey)
end else
ReactorType = Xlate('PROD_SPEC', PSNo, 'REACTOR_TYPE', 'X')
Memory_Services('SetValue', ReactorKey, ReactorType)
end
For each Stage in SigProfile using @VM setting LineNo
SigInfo = Signature_Services('GetSigInfo', WOMatKey, Stage, UseCaching, RDSNo)
Signatures<0, LineNo> = SigInfo<1>
SigDTMs<0, LineNo> = SigInfo<2>
Next Stage
SigDTMs = OCONV(SigDTMs,'DT4/^S')
Response = SigProfile:@FM:Signatures:@FM:SigDTMs
end service
Service FinalSigComp(WOMatKey, UseCaching)
If UseCaching EQ '' then UseCaching = True$
Response = False$
WONo = Field(WOMatKey, '*', 1)
ReactorType = Xlate('WO_LOG', WONo, 'REACTOR_TYPE', 'X')
PSNo = Xlate('WO_LOG', WONo, 'PS_NO', 'X')
ReactorType = Xlate('PROD_SPEC', PSNo, 'REACTOR_TYPE', 'X')
SigProfile = Signature_Services('GetSigProfile', WOMatKey, UseCaching)
NumStages = DCount(SigProfile, @VM)
FinalStage = SigProfile<0, NumStages>
Response = Signature_Services('CheckSignature', WOMatKey, FinalStage, UseCaching)
end service
Service FinalSigDTM(WOMatKey, UseCaching)
If UseCaching EQ '' then UseCaching = True$
Response = False$
WONo = Field(WOMatKey, '*', 1)
ReactorType = Xlate('WO_LOG', WONo, 'REACTOR_TYPE', 'X')
PSNo = Xlate('WO_LOG', WONo, 'PS_NO', 'X')
ReactorType = Xlate('PROD_SPEC', PSNo, 'REACTOR_TYPE', 'X')
SigProfile = Signature_Services('GetSigProfile', WOMatKey, UseCaching)
NumStages = DCount(SigProfile, @VM)
FinalStage = SigProfile<0, NumStages>
Response = Signature_Services('GetSigInfo', WOMatKey, FinalStage, UseCaching)<2>
end service
Service CheckSigOrder(WOMatKey, CurrStage, UseCaching, RDSNo)
If UseCaching EQ '' then UseCachine = True$
Response = False$
If RDSNo NE '' then
WONo = Xlate('RDS', RDSNo, 'WO', 'X')
end else
WONo = Field(WOMatKey, '*', 1)
end
ReactorType = Xlate('WO_LOG', WONo, 'REACTOR_TYPE', 'X')
PSNo = Xlate('WO_LOG', WONo, 'PS_NO', 'X')
SigProfile = obj_Prod_Spec('GetSigProfile', PSNo:@RM:'':@RM:WOMatKey:@RM:RDSNo)
Locate CurrStage in SigProfile using @VM setting sPos then
If sPos GT 1 then
PrevStage = SigProfile<0, sPos-1>
end else
// There is no previous stage
PrevStage = ''
end
// Check previous stage is complete
If PrevStage NE '' then
PrevStageSigInfo = Signature_Services('GetSigInfo', WOMatKey, PrevStage, UseCaching, RDSNo)
PrevStageSig = PrevStageSigInfo<1>
PrevStageComp = (PrevStageSig NE '')
end else
PrevStageSig = ''
PrevStageComp = True$
end
CurrStageComp = Signature_Services('CheckSignature', WOMatKey, CurrStage, UseCaching, RDSNo)
Begin Case
Case ( Not(MemberOf(@User4, 'BYPASS') ) and ( (CurrStage EQ 'QA') or (CurrStage EQ 'MO_QA') ) and (PrevStageSig EQ @User4) )
ErrorMsg = 'FQA stage signature cannot match previous step ':PrevStage:' signature. ':WOMatKey:' (':Service:')'
Error_Services('Add', ErrorMsg)
Case PrevStageComp EQ False$
ErrorMsg = 'Previous step ':PrevStage:' is not signed. ':WOMatKey:' (':Service:')'
Error_Services('Add', ErrorMsg)
Case CurrStageComp EQ True$
// Allow user to re-sign. This may be necessary in certain cases such as when multiple surfscans
// have taken place and one still needs to be signed.
Response = True$
Case Error_Services('HasError') EQ True$
// Error message already in stack.
Null
Case Otherwise$
// Ok
Response = True$
End Case
end else
// Stage not prescribed in the PSN, so ignore the signature order.
Response = True$
end
End Service
Service CheckSignature(WOMatKey, Stage, UseCaching, RDSNo)
If UseCaching EQ '' then UseCaching = True$
Response = False$
SigInfo = Signature_Services('GetSigInfo', WOMatKey, Stage, UseCaching, RDSNo)
If Error_Services('NoError') then
Signature = SigInfo<1>
SigDTM = SigInfo<2>
If Signature NE '' then Response = True$
end
end service
Service GetSigInfo(WOMatKey, Stage, UseCaching, RDSNo)
If UseCaching EQ '' then UseCaching = True$
Signature = ''
SigDTM = ''
If RDSNo NE '' then
WONo = Xlate('RDS', RDSNo, 'WO', 'X')
end else
WONo = Field(WOMatKey, '*', 1)
end
PSNo = Xlate('WO_LOG', WONo, 'PS_NO', 'X')
SigProfKey = PSNo:'*':WOMatKey:'*':RDSNo
ReactorKey = PSNo:'*Reactor'
If UseCaching and Memory_Services('IsValueCurrent', SigProfKey, 60, True$) then
SigProfile = Memory_Services('GetValue', SigProfKey)
end else
SigProfile = obj_Prod_Spec('GetSigProfile', PSNo:@RM:'':@RM:WOMatKey:@RM:RDSNo)
Memory_Services('SetValue', SigProfKey, SigProfile)
end
If UseCaching and Memory_Services('IsValueCurrent', ReactorKey, 60, True$) then
ReactorType = Memory_Services('GetValue', ReactorKey)
end else
ReactorType = Xlate('PROD_SPEC', PSNo, 'REACTOR_TYPE', 'X')
Memory_Services('SetValue', ReactorKey, ReactorType)
end
Locate Stage in SigProfile using @VM setting sPos then
Begin Case
* * EpiPro * *
Case ( (ReactorType EQ 'EPP') or (ReactorType EQ 'P') )
CassNo = Field(WOMatKey, '*', 2)
WMOKey = WONo:'*1*':CassNo
PostCINo = Xlate('WM_OUT', WMOKey, 'EPO_CI_NO', 'X')
Begin Case
* * Verify wafer quantity stage (aka PRE) * *
Case Stage EQ 'VER'
Signature = Xlate('RDS', RDSNo, 'PRE_EPI_SIG', 'X')
SigDate = OConv(Xlate('RDS', RDSNo, 'PRE_EPI_SIG_DT', 'X'), 'D')
SigTime = OConv(Xlate('RDS', RDSNo, 'PRE_EPI_SIG_TIME', 'X'), 'MTS')
SigDTM = IConv(SigDate:' ':SigTime, 'DT')
* * Pre Epi Cleaning and Inspection Stages * *
Case Stage EQ 'PREC'
PreCINo = Xlate('RDS', RDSNo, 'PRE_CI_NO', 'X')
StageRows = Xlate('CLEAN_INSP', PreCINo, 'CLEAN_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', PreCINo, 'CLEAN_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', PreCINo, 'CLEAN_SIG_DTM', 'X')
GoSub GetMostRecentSig
Case Stage EQ 'PREI'
PreCINo = Xlate('RDS', RDSNo, 'PRE_CI_NO', 'X')
StageRows = Xlate('CLEAN_INSP', PreCINo, 'INSP_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', PreCINo, 'INSP_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', PreCINo, 'INSP_SIG_DTM', 'X')
GoSub GetMostRecentSig
Case Stage EQ 'PRES'
PreCINo = Xlate('RDS', RDSNo, 'PRE_CI_NO', 'X')
StageRows = Xlate('CLEAN_INSP', PreCINo, 'SCAN_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', PreCINo, 'SCAN_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', PreCINo, 'SCAN_SIG_DTM', 'X')
GoSub GetMostRecentSig
* * Reactor Load * *
Case Stage EQ 'LOAD'
Signature = Xlate('RDS', RDSNo, 'OPERATOR_IN', 'X')
SigDate = OConv(Xlate('RDS', RDSNo, 'DATE_IN', 'X'), 'D')
SigTime = OConv(Xlate('RDS', RDSNo, 'TIME_IN', 'X'), 'MTS')
SigDTM = IConv(SigDate:' ':SigTime, 'DT')
* * First Wafer Inspection and Surfscan Stages * *
Case Stage EQ 'FWII'
FWICINo = Xlate('RDS', RDSNo, 'FWI_CI_NO', 'X')
StageRows = Xlate('CLEAN_INSP', FWICINo, 'INSP_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', FWICINo, 'INSP_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', FWICINo, 'INSP_SIG_DTM', 'X')
GoSub GetMostRecentSig
Case Stage EQ 'FWIS'
FWICINo = Xlate('RDS', RDSNo, 'FWI_CI_NO', 'X')
StageRows = Xlate('CLEAN_INSP', FWICINo, 'SCAN_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', FWICINo, 'SCAN_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', FWICINo, 'SCAN_SIG_DTM', 'X')
GoSub GetMostRecentSig
* * Reactor Unload * *
Case Stage EQ 'UNLOAD'
Signature = Xlate('RDS', RDSNo, 'OPERATOR_OUT', 'X')
SigDate = OConv(Xlate('RDS', RDSNo, 'DATE_OUT', 'X'), 'D')
SigTime = OConv(Xlate('RDS', RDSNo, 'TIME_OUT', 'X'), 'MTS')
SigDTM = IConv(SigDate:' ':SigTime, 'DT')
* * Last Wafer Inspection and Surfscan Stages * *
Case Stage EQ 'LWII'
LWICINo = Xlate('RDS', RDSNo, 'LWI_CI_NO', 'X')
StageRows = Xlate('CLEAN_INSP', LWICINo, 'INSP_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', LWICINo, 'INSP_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', LWICINo, 'INSP_SIG_DTM', 'X')
GoSub GetMostRecentSig
Case Stage EQ 'LWIS'
LWICINo = Xlate('RDS', RDSNo, 'LWI_CI_NO', 'X')
StageRows = Xlate('CLEAN_INSP', LWICINo, 'SCAN_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', LWICINo, 'SCAN_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', LWICINo, 'SCAN_SIG_DTM', 'X')
GoSub GetMostRecentSig
Case Stage EQ 'POST'
Signature = Xlate('RDS', RDSNo, 'POST_EPI_SIG', 'X')
SigDate = OConv(Xlate('RDS', RDSNo, 'POST_EPI_SIG_DATE', 'X'), 'D')
SigTime = OConv(Xlate('RDS', RDSNo, 'POST_EPI_SIG_TIME', 'X'), 'MTS')
SigDTM = IConv(SigDate:' ':SigTime, 'DT')
* * Post Epi Clean and Inspection Stages * *
Case Stage EQ 'PSTC'
PostCINo = Xlate('RDS', RDSNo, 'POST_CI_NO', 'X')
StageRows = Xlate('CLEAN_INSP', PostCINo, 'CLEAN_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', PostCINo, 'CLEAN_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', PostCINo, 'CLEAN_SIG_DTM', 'X')
GoSub GetMostRecentSig
Case Stage EQ 'PSTI'
PostCINo = Xlate('RDS', RDSNo, 'POST_CI_NO', 'X')
StageRows = Xlate('CLEAN_INSP', PostCINo, 'INSP_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', PostCINo, 'INSP_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', PostCINo, 'INSP_SIG_DTM', 'X')
GoSub GetMostRecentSig
Case Stage EQ 'PSTS'
PostCINo = Xlate('RDS', RDSNo, 'POST_CI_NO', 'X')
StageRows = Xlate('CLEAN_INSP', PostCINo, 'SCAN_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', PostCINo, 'SCAN_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', PostCINo, 'SCAN_SIG_DTM', 'X')
GoSub GetMostRecentSig
Case Stage EQ 'MO_PSTC'
StageRows = Xlate('CLEAN_INSP', PostCINo, 'CLEAN_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', PostCINo, 'CLEAN_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', PostCINo, 'CLEAN_SIG_DTM', 'X')
GoSub GetMostRecentSig
Case Stage EQ 'MO_PSTI'
StageRows = Xlate('CLEAN_INSP', PostCINo, 'INSP_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', PostCINo, 'INSP_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', PostCINo, 'INSP_SIG_DTM', 'X')
GoSub GetMostRecentSig
Case Stage EQ 'MO_PSTS'
StageRows = Xlate('CLEAN_INSP', PostCINo, 'SCAN_RECIPE', 'X')
Signatures = Xlate('CLEAN_INSP', PostCINo, 'SCAN_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', PostCINo, 'SCAN_SIG_DTM', 'X')
GoSub GetMostRecentSig
Case Stage EQ 'MO_QA'
Signature = Xlate('WM_OUT', WMOKey, 'SUP_VER_SIG', 'X')
SigDTM = Xlate('WM_OUT', WMOKey, 'SUP_VER_SIG_DTM', 'X')
End Case
* * GaN * *
Case (ReactorType EQ 'GAN')
If Stage EQ 'G_FQA' then
Signature = Xlate('WO_MAT', WOMatKey, 'CASS_FINAL_SIG', 'X')
SigDTM = Xlate('WO_MAT', WOMatKey, 'CASS_FINAL_SIG_DTM', 'X')
end
* * Silicon (aka Non-EpiPro) * *
Case Otherwise$
RDSNo = Xlate('WO_MAT', WOMatKey, 'RDS_NO', 'X')
Begin Case
* * Verify wafer quantity stage (aka PRE) * *
Case Stage EQ 'VER'
Signature = Xlate('RDS', RDSNo, 'PRE_EPI_SIG', 'X')
SigDate = OConv(Xlate('RDS', RDSNo, 'PRE_EPI_SIG_DT', 'X'), 'D')
SigTime = OConv(Xlate('RDS', RDSNo, 'PRE_EPI_SIG_TIME', 'X'), 'MTS')
SigDTM = IConv(SigDate:' ':SigTime, 'DT')
* * Pre Epi Cleaning and Inspection Stages * *
Case Stage EQ 'PREC'
PreCINo = Xlate('RDS', RDSNo, 'PRE_CI_NO', 'X')
StageRows = Xlate('CLEAN_INSP', PreCINo, 'CLEAN_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', PreCINo, 'CLEAN_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', PreCINo, 'CLEAN_SIG_DTM', 'X')
GoSub GetMostRecentSig
Case Stage EQ 'PREI'
PreCINo = Xlate('RDS', RDSNo, 'PRE_CI_NO', 'X')
StageRows = Xlate('CLEAN_INSP', PreCINo, 'INSP_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', PreCINo, 'INSP_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', PreCINo, 'INSP_SIG_DTM', 'X')
GoSub GetMostRecentSig
Case Stage EQ 'PRES'
PreCINo = Xlate('RDS', RDSNo, 'PRE_CI_NO', 'X')
StageRows = Xlate('CLEAN_INSP', PreCINo, 'SCAN_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', PreCINo, 'SCAN_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', PreCINo, 'SCAN_SIG_DTM', 'X')
GoSub GetMostRecentSig
* * Reactor Load * *
Case Stage EQ 'LOAD'
Signature = Xlate('RDS', RDSNo, 'OPERATOR_IN', 'X')
SigDate = OConv(Xlate('RDS', RDSNo, 'DATE_IN', 'X'), 'D')
SigTime = OConv(Xlate('RDS', RDSNo, 'TIME_IN', 'X'), 'MTS')
SigDTM = IConv(SigDate:' ':SigTime, 'DT')
* * First Wafer Inspection and Surfscan Stages * *
Case Stage EQ 'FWII'
FWICINo = Xlate('RDS', RDSNo, 'FWI_CI_NO', 'X')
StageRows = Xlate('CLEAN_INSP', FWICINo, 'INSP_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', FWICINo, 'INSP_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', FWICINo, 'INSP_SIG_DTM', 'X')
GoSub GetMostRecentSig
Case Stage EQ 'FWIS'
FWICINo = Xlate('RDS', RDSNo, 'FWI_CI_NO', 'X')
StageRows = Xlate('CLEAN_INSP', FWICINo, 'SCAN_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', FWICINo, 'SCAN_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', FWICINo, 'SCAN_SIG_DTM', 'X')
GoSub GetMostRecentSig
* * Reactor Unload * *
Case Stage EQ 'UNLOAD'
Signature = Xlate('RDS', RDSNo, 'OPERATOR_OUT', 'X')
SigDate = OConv(Xlate('RDS', RDSNo, 'DATE_OUT', 'X'), 'D')
SigTime = OConv(Xlate('RDS', RDSNo, 'TIME_OUT', 'X'), 'MTS')
SigDTM = IConv(SigDate:' ':SigTime, 'DT')
* * Last Wafer Inspection and Surfscan Stages * *
Case Stage EQ 'LWII'
LWICINo = Xlate('RDS', RDSNo, 'LWI_CI_NO', 'X')
StageRows = Xlate('CLEAN_INSP', LWICINo, 'INSP_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', LWICINo, 'INSP_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', LWICINo, 'INSP_SIG_DTM', 'X')
GoSub GetMostRecentSig
Case Stage EQ 'LWIS'
LWICINo = Xlate('RDS', RDSNo, 'LWI_CI_NO', 'X')
StageRows = Xlate('CLEAN_INSP', LWICINo, 'SCAN_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', LWICINo, 'SCAN_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', LWICINo, 'SCAN_SIG_DTM', 'X')
GoSub GetMostRecentSig
Case Stage EQ 'POST'
Signature = Xlate('RDS', RDSNo, 'POST_EPI_SIG', 'X')
SigDate = OConv(Xlate('RDS', RDSNo, 'POST_EPI_SIG_DATE', 'X'), 'D')
SigTime = OConv(Xlate('RDS', RDSNo, 'POST_EPI_SIG_TIME', 'X'), 'MTS')
SigDTM = IConv(SigDate:' ':SigTime, 'DT')
* * Post Epi Clean and Inspection Stages * *
Case Stage EQ 'PSTC'
PostCINo = Xlate('RDS', RDSNo, 'POST_CI_NO', 'X')
StageRows = Xlate('CLEAN_INSP', PostCINo, 'CLEAN_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', PostCINo, 'CLEAN_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', PostCINo, 'CLEAN_SIG_DTM', 'X')
GoSub GetMostRecentSig
Case Stage EQ 'PSTI'
PostCINo = Xlate('RDS', RDSNo, 'POST_CI_NO', 'X')
StageRows = Xlate('CLEAN_INSP', PostCINo, 'INSP_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', PostCINo, 'INSP_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', PostCINo, 'INSP_SIG_DTM', 'X')
GoSub GetMostRecentSig
Case Stage EQ 'PSTS'
PostCINo = Xlate('RDS', RDSNo, 'POST_CI_NO', 'X')
StageRows = Xlate('CLEAN_INSP', PostCINo, 'SCAN_TOOL', 'X')
Signatures = Xlate('CLEAN_INSP', PostCINo, 'SCAN_SIG', 'X')
SigDTMs = Xlate('CLEAN_INSP', PostCINo, 'SCAN_SIG_DTM', 'X')
GoSub GetMostRecentSig
* * Final QA Stage * *
Case Stage EQ 'QA'
Signature = Xlate('RDS', RDSNo, 'SUP_VER_SIG', 'X')
SigDate = OConv(Xlate('RDS', RDSNo, 'SUP_VER_SIG_DATE', 'X'), 'D')
SigTime = OConv(Xlate('RDS', RDSNo, 'SUP_VER_SIG_TIME', 'X'), 'MTS')
SigDTM = IConv(SigDate:' ':SigTime, 'DT')
End Case
End Case
end else
ErrorMsg = Stage:' stage not found in signature profile. ':WOMatKey:' (':Service:')'
Error_Services('Add', ErrorMsg)
end
Response = Signature:@FM:SigDTM
end service
//----------------------------------------------------------------------------------------------------------------------
// GetStageSummary
//
// Input:
// WOMatKey - [Required]
// Stage - [Required]
//
// Output:
// Response<1> - True$ if stage passes all requirements, False$ otherwise.
// Response<2> - True$ if stage has been signed, False$ otherwise.
// Response<3> - True$ if stage requires data and has data, False$ otherwise.
// Response<4> - True$ if stage not defined in the PSN, False$ otherwise.
//
//----------------------------------------------------------------------------------------------------------------------
Service GetStageSummary(WOMatKey, Stage)
StageSummary = ''
Error = ''
RDSNo = Xlate('WO_MAT', WOMatKey, 'RDS_NO', 'X')
SigProf = Signature_Services('GetSigProfile', WOMatKey, False$)
SigProfStages = SigProf<1>
SigProfSigs = SigProf<2>
If (RowExists('WO_MAT', WOMatKey) and (Stage NE '') ) then
Begin Case
Case Stage EQ 'VER'
// Ensure "Verify Wafers" quantity is not null
// Ensure VER signature is not null
If RDSNo NE '' then
VerSig = Xlate('RDS', RDSNo, 'PRE_EPI_SIG', 'X')
VerifyQty = Xlate('RDS', RDSNo, 'VERIFY_QTY', 'X')
StageSummary<SS_PASS$> = ( (VerSig NE '') and (VerifyQty NE '') )
StageSummary<SS_SIG$> = (VerSig NE '')
StageSummary<SS_DATA$> = (VerifyQty NE '')
Locate Stage in SigProfStages using @VM setting vPos then
StageSummary<SS_NA$> = False$
end else
StageSummary<SS_NA$> = True$
end
end else
Error = 'Error in ':Service:' service. Null RDSNo for WO_MAT record ':WOMatKey:'!'
end
Case Stage EQ 'SUPP'
// Verify RDS supplement information has been acknowledged
If RDSNo NE '' then
SupplFlag = Xlate('RDS', RDSNo, 'SUPPLEMENT', 'X')
SupplAckReq = Xlate('RDS', RDSNo, 'SUPPL_ACK_REQ', 'X')
SupplSig = Xlate('RDS', RDSNo, 'SUPPL_SIG', 'X')
StageSummary<SS_PASS$> = (SupplFlag EQ True$) and (SupplAckReq EQ False$)
StageSummary<SS_SIG$> = (SupplSig NE '')
StageSummary<SS_DATA$> = (SupplFlag EQ True$)
StageSummary<SS_NA$> = (SupplFlag NE True$) ; // Stage only applicable if supplement flag is true
end else
Error = 'Error in ':Service:' service. Null RDSNo for WO_MAT record ':WOMatKey:'!'
end
Case Stage EQ 'LOAD'
// Verify "Wafers In" quantity is not null
// Ensure LOAD signature is not null
If RDSNo NE '' then
LoadSig = Xlate('RDS', RDSNo, 'OPERATOR_IN', 'X')
WafersIn = Xlate('RDS', RDSNo, 'WAFERS_IN', 'X')
StageSummary<SS_PASS$> = ( (LoadSig NE '') and (WafersIn NE '') )
StageSummary<SS_SIG$> = (LoadSig NE '')
StageSummary<SS_DATA$> = (WafersIn NE '')
Locate Stage in SigProfStages using @VM setting vPos then
StageSummary<SS_NA$> = False$
end else
StageSummary<SS_NA$> = True$
end
end else
Error = 'Error in ':Service:' service. Null RDSNo for WO_MAT record ':WOMatKey:'!'
end
Case Stage EQ 'UNLOAD'
// Ensure UNLOAD signature is not null
If RDSNo NE '' then
UnloadSig = Xlate('RDS', RDSNo, 'OPERATOR_OUT', 'X')
StageSummary<SS_PASS$> = (UnloadSig NE '')
StageSummary<SS_SIG$> = (UnloadSig NE '')
StageSummary<SS_DATA$> = True$ ; // No data for this stage entered by user
Locate Stage in SigProfStages using @VM setting vPos then
StageSummary<SS_NA$> = False$
end else
StageSummary<SS_NA$> = True$
end
end else
Error = 'Error in ':Service:' service. Null RDSNo for WO_MAT record ':WOMatKey:'!'
end
Case Stage EQ 'POST'
// Ensure POST signature is not null
If RDSNo NE '' then
PostEpiSig = Xlate('RDS', RDSNo, 'POST_EPI_SIG', 'X')
StageSummary<SS_PASS$> = (PostEpiSig NE '')
StageSummary<SS_SIG$> = (PostEpiSig NE '')
StageSummary<SS_DATA$> = True$ ; // No data for this stage entered by user
StageSummary<SS_NA$> = False$ ; // This stage is essentially never required by the PSN, but is required by some code.
end else
Error = 'Error in ':Service:' service. Null RDSNo for WO_MAT record ':WOMatKey:'!'
end
Case Stage EQ 'QA'
// Verify QA signature is not null
If RDSNo NE '' then
FQASig = Xlate('RDS', RDSNo, 'SUP_VER_SIG', 'X')
StageSummary<SS_PASS$> = (FQASig NE '')
StageSummary<SS_SIG$> = (FQASig NE '')
StageSummary<SS_DATA$> = True$ ; //Signature_Services('QASigReady', RDSNo)
Locate Stage in SigProfStages using @VM setting vPos then
StageSummary<SS_NA$> = False$
end else
StageSummary<SS_NA$> = True$
end
end else
Error = 'Error in ':Service:' service. Null RDSNo for WO_MAT record ':WOMatKey:'!'
end
Case Stage EQ 'RDS_TEST'
// Gather RDS metrology information
StageComplete = False$
If RDSNo NE '' then
MetNo = Xlate('RDS', RDSNo, 'MET_KEYS', 'X')
If MetNo NE '' then
MetRec = Database_Services('ReadDataRow', 'RDS_TEST', MetNo)
TWSigned = obj_RDS_Test('TWSignedOff', MetNo:@RM:MetRec)
TestComp = obj_RDS_Test('TestComplete', MetNo:@RM:MetRec)
OutOfSpec = obj_RDS_Test('OutOfSpec', MetNo:@RM:MetRec)
StageSummary<SS_PASS$> = (TWSigned and TestComp and Not(OutOfSpec))
StageSummary<SS_SIG$> = TestComp
StageSummary<SS_DATA$> = TestComp
StageSummary<SS_NA$> = False$ ; // I think RDS metrology is always required.
end
end
Case Stage EQ 'PREI'
Locate Stage in SigProfStages using @VM setting vPos then
StageSummary<SS_NA$> = False$
end else
StageSummary<SS_NA$> = True$
end
StageRx = StageSummary<SS_NA$>
CINo = Xlate('RDS', RDSNo, 'PRE_CI_NO', 'X')
If CINo NE '' then
CITool = Xlate('CLEAN_INSP', CINo, 'INSP_TOOL', 'X')
CISig = Xlate('CLEAN_INSP', CINo, 'INSP_SIG', 'X')
Begin Case
Case ( (CITool EQ '') and (StageRx EQ True$) )
// Required data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = (CISig NE '')
StageSummary<SS_PASS$> = False$
Case ( (CITool NE '') and (CISig EQ '') )
// Data is present, but signature missing
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
Case Otherwise$
// Full pass
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = True$
StageSummary<SS_PASS$> = True$
End Case
end else
If StageRx then
// Data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
end else
// Stage not applicable
StageSummary<SS_DATA$> = ''
StageSummary<SS_SIG$> = ''
StageSummary<SS_PASS$> = ''
end
end
Case Stage EQ 'PREC'
Locate Stage in SigProfStages using @VM setting vPos then
StageSummary<SS_NA$> = False$
end else
StageSummary<SS_NA$> = True$
end
StageRx = StageSummary<SS_NA$>
CINo = Xlate('RDS', RDSNo, 'PRE_CI_NO', 'X')
If (CINo NE '') then
CITool = Xlate('CLEAN_INSP', CINo, 'CLEAN_TOOL', 'X')
CISig = Xlate('CLEAN_INSP', CINo, 'CLEAN_SIG', 'X')
Begin Case
Case ( (CITool EQ '') and (StageRx EQ True$) )
// Required data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = (CISig NE '')
StageSummary<SS_PASS$> = False$
Case ( (CITool NE '') and (CISig EQ '') )
// Data is present, but signature missing
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
Case Otherwise$
// Full pass
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = True$
StageSummary<SS_PASS$> = True$
End Case
end else
If StageRx then
// Data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
end else
// Stage not applicable
StageSummary<SS_DATA$> = ''
StageSummary<SS_SIG$> = ''
StageSummary<SS_PASS$> = ''
end
end
Case Stage EQ 'PRES'
Locate Stage in SigProfStages using @VM setting vPos then
StageSummary<SS_NA$> = False$
end else
StageSummary<SS_NA$> = True$
end
CINo = Xlate('RDS', RDSNo, 'PRE_CI_NO', 'X')
StageRx = StageSummary<SS_NA$>
If (CINo NE '') then
CITool = Xlate('CLEAN_INSP', CINo, 'SPEC_SURFSCAN_RECIPE', 'X')
CISig = Xlate('CLEAN_INSP', CINo, 'SCAN_SIG', 'X')
Begin Case
Case ( (CITool EQ '') and (StageRx EQ True$) )
// Required data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = (CISig NE '')
StageSummary<SS_PASS$> = False$
Case ( (CITool NE '') and (CISig EQ '') )
// Data is present, but signature missing
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
Case Otherwise$
// Full pass
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = True$
StageSummary<SS_PASS$> = True$
End Case
end else
If StageRx then
// Data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
end else
// Stage not applicable
StageSummary<SS_DATA$> = ''
StageSummary<SS_SIG$> = ''
StageSummary<SS_PASS$> = ''
end
end
Case Stage EQ 'FWII'
Locate Stage in SigProfStages using @VM setting vPos then
StageSummary<SS_NA$> = False$
end else
StageSummary<SS_NA$> = True$
end
StageRx = StageSummary<SS_NA$>
CINo = Xlate('RDS', RDSNo, 'FWI_CI_NO', 'X')
If CINo NE '' then
CITool = Xlate('CLEAN_INSP', CINo, 'INSP_TOOL', 'X')
CISig = Xlate('CLEAN_INSP', CINo, 'INSP_SIG', 'X')
Begin Case
Case ( (CITool EQ '') and (StageRx EQ True$) )
// Required data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = (CISig NE '')
StageSummary<SS_PASS$> = False$
Case ( (CITool NE '') and (CISig EQ '') )
// Data is present, but signature missing
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
Case Otherwise$
// Full pass
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = True$
StageSummary<SS_PASS$> = True$
End Case
end else
If StageRx then
// Data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
end else
// Stage not applicable
StageSummary<SS_DATA$> = ''
StageSummary<SS_SIG$> = ''
StageSummary<SS_PASS$> = ''
end
end
Case Stage EQ 'FWIC'
Locate Stage in SigProfStages using @VM setting vPos then
StageSummary<SS_NA$> = False$
end else
StageSummary<SS_NA$> = True$
end
StageRx = StageSummary<SS_NA$>
CINo = Xlate('RDS', RDSNo, 'FWI_CI_NO', 'X')
If (CINo NE '') then
CITool = Xlate('CLEAN_INSP', CINo, 'CLEAN_TOOL', 'X')
CISig = Xlate('CLEAN_INSP', CINo, 'CLEAN_SIG', 'X')
Begin Case
Case ( (CITool EQ '') and (StageRx EQ True$) )
// Required data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = (CISig NE '')
StageSummary<SS_PASS$> = False$
Case ( (CITool NE '') and (CISig EQ '') )
// Data is present, but signature missing
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
Case Otherwise$
// Full pass
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = True$
StageSummary<SS_PASS$> = True$
End Case
end else
If StageRx then
// Data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
end else
// Stage not applicable
StageSummary<SS_DATA$> = ''
StageSummary<SS_SIG$> = ''
StageSummary<SS_PASS$> = ''
end
end
Case Stage EQ 'FWIS'
Locate Stage in SigProfStages using @VM setting vPos then
StageSummary<SS_NA$> = False$
end else
StageSummary<SS_NA$> = True$
end
CINo = Xlate('RDS', RDSNo, 'FWI_CI_NO', 'X')
StageRx = StageSummary<SS_NA$>
If (CINo NE '') then
CITool = Xlate('CLEAN_INSP', CINo, 'SPEC_SURFSCAN_RECIPE', 'X')
CISig = Xlate('CLEAN_INSP', CINo, 'SCAN_SIG', 'X')
Begin Case
Case ( (CITool EQ '') and (StageRx EQ True$) )
// Required data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = (CISig NE '')
StageSummary<SS_PASS$> = False$
Case ( (CITool NE '') and (CISig EQ '') )
// Data is present, but signature missing
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
Case Otherwise$
// Full pass
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = True$
StageSummary<SS_PASS$> = True$
End Case
end else
If StageRx then
// Data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
end else
// Stage not applicable
StageSummary<SS_DATA$> = ''
StageSummary<SS_SIG$> = ''
StageSummary<SS_PASS$> = ''
end
end
Case Stage EQ 'LOAD_QA_MET'
// Gather load QA metrology information
NumTests = 0
TestSigs = ''
TestOOSs = ''
TestResults = ''
Error = ''
NotApplicable = True$
StageComplete = False$
DataComp = False$
SigsComp = False$
WOMatKey = Xlate('RDS', RDSNo, 'WO_MAT_KEY', 'X')
If RowExists('WO_MAT', WOMatKey) then
WOMatQARec = Database_Services('ReadDataRow', 'WO_MAT_QA', WOMatKey)
QAMetStages = WOMatQARec<WO_MAT_QA_STAGE$>
QAMetSigs = WOMatQARec<WO_MAT_QA_SIG$>
QAMetOOSs = WOMatQARec<WO_MAT_QA_OUT_OF_SPEC$>
QAMetResults = WOMatQARec<WO_MAT_QA_RESULT$>
For each QAMetStage in QAMetStages using @VM setting vPos
If QAMetStage EQ 'FWI' then
NumTests += 1
NotApplicable = False$
TestSig = QAMetSigs<0, vPos>
TestOOS = QAMetOOSs<0, vPos>
TestResult = QAMetResults<0, vPos>
TestSigs<0, vPos> = (TestSig NE '')
TestOOSs<0, vPos> = TestOOS
TestResults<0, vPos> = (TestResult NE '')
end
Next QAMetStage
DataComp = ( ( NumTests EQ Sum(TestResults) ) and (NumTests GT 0) )
SigsComp = ( ( NumTests EQ Sum(TestSigs) ) and (NumTests GT 0) )
end
StageSummary<SS_DATA$> = DataComp
StageSummary<SS_SIG$> = SigsComp
StageSummary<SS_PASS$> = (DataComp and SigsComp)
StageSummary<SS_NA$> = NotApplicable
Case Stage EQ 'LWII'
Locate Stage in SigProfStages using @VM setting vPos then
StageSummary<SS_NA$> = False$
end else
StageSummary<SS_NA$> = True$
end
StageRx = StageSummary<SS_NA$>
CINo = Xlate('RDS', RDSNo, 'LWI_CI_NO', 'X')
If CINo NE '' then
CITool = Xlate('CLEAN_INSP', CINo, 'INSP_TOOL', 'X')
CISig = Xlate('CLEAN_INSP', CINo, 'INSP_SIG', 'X')
Begin Case
Case ( (CITool EQ '') and (StageRx EQ True$) )
// Required data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = (CISig NE '')
StageSummary<SS_PASS$> = False$
Case ( (CITool NE '') and (CISig EQ '') )
// Data is present, but signature missing
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
Case Otherwise$
// Full pass
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = True$
StageSummary<SS_PASS$> = True$
End Case
end else
If StageRx then
// Data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
end else
// Stage not applicable
StageSummary<SS_DATA$> = ''
StageSummary<SS_SIG$> = ''
StageSummary<SS_PASS$> = ''
end
end
Case Stage EQ 'LWIC'
Locate Stage in SigProfStages using @VM setting vPos then
StageSummary<SS_NA$> = False$
end else
StageSummary<SS_NA$> = True$
end
StageRx = StageSummary<SS_NA$>
CINo = Xlate('RDS', RDSNo, 'LWI_CI_NO', 'X')
If (CINo NE '') then
CITool = Xlate('CLEAN_INSP', CINo, 'CLEAN_TOOL', 'X')
CISig = Xlate('CLEAN_INSP', CINo, 'CLEAN_SIG', 'X')
Begin Case
Case ( (CITool EQ '') and (StageRx EQ True$) )
// Required data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = (CISig NE '')
StageSummary<SS_PASS$> = False$
Case ( (CITool NE '') and (CISig EQ '') )
// Data is present, but signature missing
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
Case Otherwise$
// Full pass
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = True$
StageSummary<SS_PASS$> = True$
End Case
end else
If StageRx then
// Data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
end else
// Stage not applicable
StageSummary<SS_DATA$> = ''
StageSummary<SS_SIG$> = ''
StageSummary<SS_PASS$> = ''
end
end
Case Stage EQ 'LWIS'
Locate Stage in SigProfStages using @VM setting vPos then
StageSummary<SS_NA$> = False$
end else
StageSummary<SS_NA$> = True$
end
CINo = Xlate('RDS', RDSNo, 'LWI_CI_NO', 'X')
StageRx = StageSummary<SS_NA$>
If (CINo NE '') then
CITool = Xlate('CLEAN_INSP', CINo, 'SPEC_SURFSCAN_RECIPE', 'X')
CISig = Xlate('CLEAN_INSP', CINo, 'SCAN_SIG', 'X')
Begin Case
Case ( (CITool EQ '') and (StageRx EQ True$) )
// Required data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = (CISig NE '')
StageSummary<SS_PASS$> = False$
Case ( (CITool NE '') and (CISig EQ '') )
// Data is present, but signature missing
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
Case Otherwise$
// Full pass
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = True$
StageSummary<SS_PASS$> = True$
End Case
end else
If StageRx then
// Data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
end else
// Stage not applicable
StageSummary<SS_DATA$> = ''
StageSummary<SS_SIG$> = ''
StageSummary<SS_PASS$> = ''
end
end
Case Stage EQ 'ROTR'
CINo = Xlate('RDS', RDSNo, 'LWI_CI_NO', 'X')
If (CINo NE '') then
CITool = Xlate('CLEAN_INSP', CINo, 'SPEC_SURFSCAN_RECIPE', 'X')
CISig = Xlate('CLEAN_INSP', CINo, 'SCAN_SIG', 'X')
ROTRAction = Xlate('CLEAN_INSP', CINo, 'RDS_ROTR_ACTION', 'X')
ROTRActionReason = Xlate('CLEAN_INSP', CINo, 'ROTR_ACTION_REASON', 'X')
Begin Case
Case ( (ROTRAction EQ 'F' ) and (CISig NE '') )
// ROTR Acceptance required
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
StageSummary<SS_NA$> = False$
Case ( (ROTRAction EQ 'F') and (CISig EQ '') and (ROTRActionReason EQ 'SurfScan signature is missing.') )
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
StageSummary<SS_NA$> = False$
Case ( (ROTRAction EQ 'F') and (CISig EQ '') )
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
StageSummary<SS_NA$> = False$
Case Otherwise$
// Pass
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = True$
StageSummary<SS_PASS$> = True$
StageSummary<SS_NA$> = False$
End Case
end else
If StageRx then
// Data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
end else
// Stage not applicable
StageSummary<SS_DATA$> = ''
StageSummary<SS_SIG$> = ''
StageSummary<SS_PASS$> = ''
end
end
Case Stage EQ 'UNLOAD_QA_MET'
// Gather unload QA metrology information
NumTests = 0
TestSigs = ''
TestOOSs = ''
TestResults = ''
Error = ''
NotApplicable = True$
StageComplete = False$
DataComp = False$
SigsComp = False$
WOMatKey = Xlate('RDS', RDSNo, 'WO_MAT_KEY', 'X')
If RowExists('WO_MAT', WOMatKey) then
WOMatQARec = Database_Services('ReadDataRow', 'WO_MAT_QA', WOMatKey)
QAMetStages = WOMatQARec<WO_MAT_QA_STAGE$>
QAMetSigs = WOMatQARec<WO_MAT_QA_SIG$>
QAMetOOSs = WOMatQARec<WO_MAT_QA_OUT_OF_SPEC$>
QAMetResults = WOMatQARec<WO_MAT_QA_RESULT$>
For each QAMetStage in QAMetStages using @VM setting vPos
If QAMetStage EQ 'UNLOAD' then
NumTests += 1
NotApplicable = False$
TestSig = QAMetSigs<0, vPos>
TestOOS = QAMetOOSs<0, vPos>
TestResult = QAMetResults<0, vPos>
TestSigs<0, vPos> = (TestSig NE '')
TestOOSs<0, vPos> = TestOOS
TestResults<0, vPos> = (TestResult NE '')
end
Next QAMetStage
DataComp = ( ( NumTests EQ Sum(TestResults) ) and (NumTests GT 0) )
SigsComp = ( ( NumTests EQ Sum(TestSigs) ) and (NumTests GT 0) )
end
StageSummary<SS_DATA$> = DataComp
StageSummary<SS_SIG$> = SigsComp
StageSummary<SS_PASS$> = (DataComp and SigsComp)
StageSummary<SS_NA$> = NotApplicable
Case Stage EQ 'PSTI'
Locate Stage in SigProfStages using @VM setting vPos then
StageSummary<SS_NA$> = False$
end else
StageSummary<SS_NA$> = True$
end
StageRx = StageSummary<SS_NA$>
CINo = Xlate('RDS', RDSNo, 'POST_CI_NO', 'X')
If CINo NE '' then
CITool = Xlate('CLEAN_INSP', CINo, 'INSP_TOOL', 'X')
CISig = Xlate('CLEAN_INSP', CINo, 'INSP_SIG', 'X')
Begin Case
Case ( (CITool EQ '') and (StageRx EQ True$) )
// Required data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = (CISig NE '')
StageSummary<SS_PASS$> = False$
Case ( (CITool NE '') and (CISig EQ '') )
// Data is present, but signature missing
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
Case Otherwise$
// Full pass
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = True$
StageSummary<SS_PASS$> = True$
End Case
end else
If StageRx then
// Data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
end else
// Stage not applicable
StageSummary<SS_DATA$> = ''
StageSummary<SS_SIG$> = ''
StageSummary<SS_PASS$> = ''
end
end
Case Stage EQ 'PSTC'
Locate Stage in SigProfStages using @VM setting vPos then
StageSummary<SS_NA$> = False$
end else
StageSummary<SS_NA$> = True$
end
StageRx = StageSummary<SS_NA$>
CINo = Xlate('RDS', RDSNo, 'POST_CI_NO', 'X')
If (CINo NE '') then
CITool = Xlate('CLEAN_INSP', CINo, 'CLEAN_TOOL', 'X')
CISig = Xlate('CLEAN_INSP', CINo, 'CLEAN_SIG', 'X')
Begin Case
Case ( (CITool EQ '') and (StageRx EQ True$) )
// Required data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = (CISig NE '')
StageSummary<SS_PASS$> = False$
Case ( (CITool NE '') and (CISig EQ '') )
// Data is present, but signature missing
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
Case Otherwise$
// Full pass
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = True$
StageSummary<SS_PASS$> = True$
End Case
end else
If StageRx then
// Data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
end else
// Stage not applicable
StageSummary<SS_DATA$> = ''
StageSummary<SS_SIG$> = ''
StageSummary<SS_PASS$> = ''
end
end
Case Stage EQ 'PSTS'
Locate Stage in SigProfStages using @VM setting vPos then
StageSummary<SS_NA$> = False$
end else
StageSummary<SS_NA$> = True$
end
CINo = Xlate('RDS', RDSNo, 'POST_CI_NO', 'X')
StageRx = StageSummary<SS_NA$>
If (CINo NE '') then
CITool = Xlate('CLEAN_INSP', CINo, 'SPEC_SURFSCAN_RECIPE', 'X')
CISig = Xlate('CLEAN_INSP', CINo, 'SCAN_SIG', 'X')
Begin Case
Case ( (CITool EQ '') and (StageRx EQ True$) )
// Required data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = (CISig NE '')
StageSummary<SS_PASS$> = False$
Case ( (CITool NE '') and (CISig EQ '') )
// Data is present, but signature missing
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
Case Otherwise$
// Full pass
StageSummary<SS_DATA$> = True$
StageSummary<SS_SIG$> = True$
StageSummary<SS_PASS$> = True$
End Case
end else
If StageRx then
// Data is missing
StageSummary<SS_DATA$> = False$
StageSummary<SS_SIG$> = False$
StageSummary<SS_PASS$> = False$
end else
// Stage not applicable
StageSummary<SS_DATA$> = ''
StageSummary<SS_SIG$> = ''
StageSummary<SS_PASS$> = ''
end
end
Case Stage EQ 'POST_QA_MET'
// Gather post-epi QA metrology information
NumTests = 0
TestSigs = ''
TestOOSs = ''
TestResults = ''
Error = ''
NotApplicable = True$
StageComplete = False$
DataComp = False$
SigsComp = False$
If RowExists('WO_MAT', WOMatKey) then
WOMatQARec = Database_Services('ReadDataRow', 'WO_MAT_QA', WOMatKey)
QAMetStages = WOMatQARec<WO_MAT_QA_STAGE$>
QAMetSigs = WOMatQARec<WO_MAT_QA_SIG$>
QAMetOOSs = WOMatQARec<WO_MAT_QA_OUT_OF_SPEC$>
QAMetResults = WOMatQARec<WO_MAT_QA_RESULT$>
For each QAMetStage in QAMetStages using @VM setting vPos
If QAMetStage EQ 'QA' then
NumTests += 1
NotApplicable = False$
TestSig = QAMetSigs<0, vPos>
TestOOS = QAMetOOSs<0, vPos>
TestResult = QAMetResults<0, vPos>
TestSigs<0, vPos> = (TestSig NE '')
TestOOSs<0, vPos> = TestOOS
TestResults<0, vPos> = (TestResult NE '')
end
Next QAMetStage
DataComp = ( ( NumTests EQ Sum(TestResults) ) and (NumTests GT 0) )
SigsComp = ( ( NumTests EQ Sum(TestSigs) ) and (NumTests GT 0) )
end
StageSummary<SS_DATA$> = DataComp
StageSummary<SS_SIG$> = SigsComp
StageSummary<SS_PASS$> = (DataComp and SigsComp)
StageSummary<SS_NA$> = NotApplicable
Case Stage EQ 'LBLCHK'
// Verify LBLCHK inv action exists in WO_MAT material log.
NotApplicable = False$
InvActions = Xlate('WO_MAT', WOMatKey, 'INV_ACTION', 'X')
Locate Stage in InvActions using @VM setting vPos then
DataComp = True$
SigsComp = True$
end else
DataComp = False$
SigsComp = False$
end
StageSummary<SS_DATA$> = DataComp
StageSummary<SS_SIG$> = SigsComp
StageSummary<SS_PASS$> = (DataComp and SigsComp)
StageSummary<SS_NA$> = NotApplicable
Case Stage EQ 'NCR'
// Gather NCR information
NotApplicable = True$
DataComp = False$
SigsComp = False$
NumSigs = 0
NumData = 0
NCRKeys = Xlate('WO_MAT', WOMatKey, 'NCR_KEYS', 'X')
NCRSigs = Xlate('WO_MAT', WOMatKey, 'NCR_FINAL_SIG', 'X')
If NCRKeys NE '' then
NotApplicable = False$
NumKeys = DCount(NCRKeys, @VM)
For each NCRNo in NCRKeys using @VM setting vPos
Sig = Xlate('NCR', NCRNo, 'AUTH_REJ_SIG', 'X')
If Sig NE '' then NumSigs += 1
Error = False$
ReqFields = 'SHIFT,DEPT,DEPT_RESP,LOSS_CODE,LOSS_COMMENTS,CONTAIN_ACTIONS,LOSS_STAGE,LOSS_BY'
For each ReqField in ReqFields using ',' setting cPos
Val = Xlate('NCR', NCRNo, ReqField, 'X')
If Val EQ '' then Error = True$
Until Error
Next ReqField
If Error EQ False$ then NumData += 1
Next NCRNo
SigsComp = (NumKeys EQ NumSigs)
DataComp = (NumKeys EQ NumData)
end
StageSummary<SS_DATA$> = DataComp
StageSummary<SS_SIG$> = SigsComp
StageSummary<SS_PASS$> = (DataComp and SigsComp)
StageSummary<SS_NA$> = NotApplicable
Case Stage EQ 'SAP_BATCH_ID'
// Verify SAP Batch ID is not null
SAPBatchNo = Xlate('WO_MAT', WOMatKey, 'SAP_BATCH_NO', 'X')
DataComp = (SapBatchNo NE '')
SigsComp = DataComp
StageSummary<SS_DATA$> = DataComp
StageSummary<SS_SIG$> = SigsComp
StageSummary<SS_PASS$> = (DataComp and SigsComp)
StageSummary<SS_NA$> = False$
Case Otherwise$
// Check stage signature to determine if it is complete.
StageComplete = True$
SigInfo = Signature_Services('GetSigInfo', WOMatKey, Stage, False$)
If Error_Services('NoError') then
Sig = SigInfo<1>
StageComplete = (Sig NE '')
end else
// Stage may not apply to this cassette
ErrorMessage = Error_Services('GetMessage')
NotApplicable = (IndexC(ErrorMessage, 'signature profile', 1) GT 0)
If NotApplicable EQ True$ then StageComplete = 2
end
If StageComplete EQ 0 then Error = Stage:' not signed.'
End Case
end
Response = StageSummary
end service
Service GetCassSummary(WOMatKey)
CassSummary = ''
If RowExists('WO_MAT', WOMatKey) then
// Collect signature and metrology pass/fail data.
Stages = Database_Services('ReadDataRow', 'APP_INFO', 'SILICON_STAGE_LIST')
For each Stage in Stages using @FM setting fPos
StageSummary = Signature_Services('GetStageSummary', WOMatKey, Stage)
CassSummary<fPos, 1> = Stage
CassSummary<fPos, 2> = StageSummary<SS_PASS$>
CassSummary<fPos, 3> = StageSummary<SS_SIG$>
CassSummary<fPos, 4> = StageSummary<SS_DATA$>
CassSummary<fPos, 5> = StageSummary<SS_NA$>
Next Stage
end
Response = CassSummary
end service
Service GetStageIDs()
Response = Database_Services('ReadDataRow', 'APP_INFO', 'SILICON_STAGE_LIST')
end service
Service PostEpiSigReady(RDSNo)
ErrCode = ''
ErrorMessage = ''
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo)
WONo = RDSRec<RDS_WO$>
CassNo = RDSRec<RDS_CASS_NO$>
Reactor = RDSRec<RDS_REACTOR$>
WOStep = 1
WOMatKey = WONo:'*':CassNo
ReprocessedMat = XLATE('WO_MAT', WOMatKey, 'REPROCESSED_MAT', 'X')
WOMatCurrStatus = obj_WO_Mat('CurrStatus', WOMatKey)
If (WOMatCurrStatus NE 'HOLD') then
Set_Status(0)
obj_WO_Mat('MQAComp', WOMatKey:@RM:WOStep:@RM:'UNLOAD')
If Not(Get_Status(ErrCode)) then
Response = True$
end else
ErrorMessage = 'Error in ':Service:' service. Error code: ':ErrCode
end
end else
ErrorMessage = 'Cassette is on hold and may not be signed off.'
end
If ErrorMessage NE '' then Error_Services('Add', ErrorMessage)
end service
Service SignPostEpiStage(RDSNo, User, WMOKey)
ErrorMessage = ''
Begin Case
Case (User EQ '')
ErrorMessage = 'Error in ':Service:' service. Null User passed into service.'
Case ( (RDSNo NE '') and (WMOKey NE '') )
ErrorMessage = 'Error in ':Service:' service. RDSNo and WMOKey cannot both be passed in.'
Case ( (RDSNo NE '') and (WMOKey EQ '') )
// Sign RDS post-epi signature
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo)
WONo = RDSRec<RDS_WO$>
CassNo = RDSRec<RDS_CASS_NO$>
WOMatKey = WONo:'*':CassNo
MakeupBox = Xlate('RDS', RDSNo, 'MAKEUP_BOX', 'X')
RawSigDt = Date()
RawSigTm = Time()
SigDt = OConv(Date(), 'D2/')
SigTm = Time()
SigTmPlusOne = OConv(SigTm + 1, 'MTS')
SigTmPlusTwo = OConv(SigTm + 2, 'MTS')
SigTmPlusFive = OConv(SigTm + 5, 'MTS')
SigTmPlusTen = OConv(SigTm + 10, 'MTS')
SigTm = OConv(SigTm,'MTS')
SigBy = User
WOStep = 1
EventParms = ''
EventCnt = 1
ToolID = ''
WHCd = 'CR'
LocCD = 'QA'
Tag = ''
EventParms<COL$LOG_FILE> = 'WO_MAT'
EventParms<COL$LOG_DTM> = SigDt:' ':SigTm
EventParms<COL$ACTION> = WOStep:'POST'
EventParms<COL$WH_CD> = 'CR'
EventParms<COL$LOC_CD> = 'POST'
EventParms<COL$WO_NOS> = WONo
EventParms<COL$CASS_NOS> = CassNo
EventParms<COL$USER_ID> = User
EventParms<COL$TAGS> = ''
EventParms<COL$TOOL_ID> = ''
CONVERT @FM TO @RM IN EventParms
obj_WO_Mat_Log('Create', EventParms)
IF Get_Status(ErrCode) THEN
ErrorMessage = 'Error in ':Service:' service. Error code: ':ErrCode
END
If ErrorMessage EQ '' then
IF MakeupBox EQ True$ THEN
EventParms<COL$LOG_FILE> = 'WO_MAT'
EventParms<COL$LOG_DTM> = SigDt:' ':SigTmPlusTwo
EventParms<COL$ACTION> = 'RTU'
EventParms<COL$WH_CD> = 'CR'
EventParms<COL$LOC_CD> = 'MU'
EventParms<COL$WO_NOS> = WONo
EventParms<COL$CASS_NOS> = CassNo
EventParms<COL$USER_ID> = User
EventParms<COL$TAGS> = ''
EventParms<COL$TOOL_ID> = ''
CONVERT @FM TO @RM IN EventParms
obj_WO_Mat_Log('Create', EventParms) ;* * * * * INV EVENT LOG * * * * *
IF Get_Status(ErrCode) THEN
ErrorMessage = 'Error in ':Service:' service. Error code: ':ErrCode
END
END
If ErrorMessage EQ '' then
RDSRec<RDS_POST_EPI_SIG$> = User
RDSRec<RDS_POST_EPI_SIG_DATE$> = IConv(SigDt, 'D')
RDSRec<RDS_POST_EPI_SIG_TIME$> = IConv(SigTm, 'MT') + 1
Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, False$)
If Error_Services('HasError') then
ErrorMessage = Error_Services('GetMessage')
end
end
end
Case ( (RDSNo EQ '') and (WMOKey NE '') )
// Sign WM_OUT post-epi signature
WMORec = Database_Services('ReadDataRow', 'WM_OUT', WMOKey)
If Error_Services('NoError') then
WMORec<WM_OUT_POST_EPI_SIG$> = User
WMORec<WM_OUT_POST_EPI_SIG_DTM$> = Datetime()
Database_Services('WriteDataRow', 'WM_OUT', WMOKey, WMORec, True$, False$, True$)
end
End Case
If ErrorMessage NE '' then Error_Services('Add', ErrorMessage)
end service
Service QASigReady(RDSNo)
ErrCode = ''
ErrorMessage = ''
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo)
WONo = RDSRec<RDS_WO$>
CassNo = RDSRec<RDS_CASS_NO$>
Reactor = RDSRec<RDS_REACTOR$>
WOStep = 1
WOMatKey = WONo:'*':CassNo
ReactorType = Xlate('RDS', RDSNo, 'REACTOR_TYPE', 'X')
******************************************
* Verify if the Post-EPI has been signed *
******************************************
PostEpiSig = Xlate('RDS', RDSNo, 'POST_EPI_SIG', 'X')
IF (PostEpiSig = '') THEN
ErrorMessage = 'Process Error':@SVM:'Technician Signature Required before Final QA Verification.'
END
If ErrorMessage EQ '' then
IF Not(MemberOf(@USER4,'BYPASS')) THEN
IF (PostEpiSig EQ @USER4) THEN
ErrorMessage = 'User ':QUOTE(PostEpiSig):' has signed this RDS for Post-Epi.'
ErrorMessage := 'Another qualified user must sign FQA verification'
END
END
end
***************************************
* Verify Metrology has been completed *
***************************************
If ErrorMessage EQ '' then
Set_Status(0)
obj_WO_Mat('MQAComp',WONo:'*':CassNo:@RM:WOStep:@RM:'QA')
ErrCode = ''
IF Get_Status(ErrCode) THEN
ErrorMessage = 'Error in ':Service:' service. Error code: ':ErrCode
END
end
***********************************************
* Verify RDS_TEST record has measurement data *
***********************************************
If ErrorMessage EQ '' then
ThickAvg = Xlate('RDS', RDSNo, 'TTHICK_AVG_ALL', 'X')
If ThickAvg EQ '' then
ErrorMessage = 'RDS metrology measurement data is missing. FQA cannot be signed.'
end
ResAvg = Xlate('RDS', RDSNo, 'TRES_AVG_ALL', 'X')
If ResAvg EQ '' then
ErrorMessage = 'RDS Resistivity measurement data is missing. FQA cannot be signed.'
Recipients = XLATE('SEC_GROUPS', 'OI_ADMIN', 'USER', 'X')
SentFrom = 'OI Admin'
Subject = 'Missing Resistivity Avg data'
Message = RDSNo: ' failed FQA due to missing resistivity average data.'
AttachWindow = ''
AttachKey = ''
SendToGroup = ''
Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup
obj_Notes('Create',Parms)
end
end
************************************************
* Verify Signatures Profile has been fulfilled *
************************************************
If ErrorMessage EQ '' then
Signature_Services('CheckSigOrder', WOMatKey, 'QA')
If Error_Services('HasError') then
ErrorMessage = Error_Services('GetMessage')
end
end
If ErrorMessage EQ '' then
Signature_Services('FQAReady', WOMatKey)
If Error_Services('HasError') then
ErrorMessage = Error_Services('GetMessage')
end
end
WafersOut = Xlate('RDS', RDSNo, 'WFRS_OUT', 'X')
**********************************************
* Verify the FlatFinder information *
**********************************************
If ErrorMessage EQ '' then
EpiPartNo = Xlate('RDS', RDSNo, 'EPI_PART_NO', 'X')
WaferSize = Xlate('EPI_PART', EpiPartNo, 'SUB_WAFER_SIZE', 'X')
WaferSizeInch = Field(WaferSize, ' ', 3, 1)
CustNo = Xlate('RDS', RDSNo, 'CUST_NO', 'X')
CompanyRow = Xlate('COMPANY', CustNo, '', 'X')
WaferFlatSizeInches = CompanyRow<COMPANY_WAFER_FLAT_WAFER_SIZE_INCH$>
WaferFlatLengthMins = Oconv(CompanyRow<COMPANY_WAFER_FLAT_LENGTH_MIN$>, 'MD1')
WaferFlatLengthMaxes = Oconv(CompanyRow<COMPANY_WAFER_FLAT_LENGTH_MAX$>, 'MD1')
Locate 6 in WaferFlatSizeInches using @VM setting vPos then
WaferFlatLengthMin = WaferFlatLengthMins<0, vPos>
WaferFlatLengthMax = WaferFlatLengthMaxes<0, vPos>
end else
WaferFlatLengthMin = ''
WaferFlatLengthMax = ''
end
WafersOut = Xlate('RDS', RDSNo, 'WFRS_OUT', 'X')
// Get FlatFinder Read Value
* FlatFinderWafersQty = RDSRec<RDS_FLATFINDER_WAFER_CNT$>
FlatFinderWaferLength = RDSRec<RDS_FLATFINDER_FLAT_LENGTH$>
If (WaferSizeInch EQ 6) then
****************************************
* FlatFinder - Wafers Quantity Section *
****************************************
* If (FlatFinderWafersQty NE '') then
* If (FlatFinderWafersQty NE WafersOut) then
* ErrMsg('Unable to sign FQA because Flat Finder and Wafers Out quantities do not match.')
* RETURN 0
* end
* end else
* ErrMsg('Unable to sign FQA because the Flat Finder quantity is missing.')
* RETURN 0
* end
************************************
* FlatFinder - Flat Length Section *
************************************
If (WaferFlatLengthMin NE '') AND (WaferFlatLengthMax NE '') then
If (FlatFinderWaferLength NE '') then
If (FlatFinderWaferLength GE WaferFlatLengthMin) AND (FlatFinderWaferLength LE WaferFlatLengthMax) then
end else
ErrMsg('Unable to sign FQA because Flat Finder wafer lengths are out of bounds.')
RETURN 0
end
end else
ErrMsg('Unable to sign FQA because the Flat Finder wafer length is missing.')
RETURN 0
end
end
end
Begin Case
Case WaferSizeInch = '6'
WaferFlatSizeInches = CompanyRow<COMPANY_WAFER_FLAT_WAFER_SIZE_INCH$>
WaferFlatLengthMins = Oconv(CompanyRow<COMPANY_WAFER_FLAT_LENGTH_MIN$>, 'MD1')
WaferFlatLengthMaxes = Oconv(CompanyRow<COMPANY_WAFER_FLAT_LENGTH_MAX$>, 'MD1')
Locate WaferSizeInch in WaferFlatSizeInches using @VM setting vPos then
WaferFlatLengthMin = WaferFlatLengthMins<0, vPos>
WaferFlatLengthMax = WaferFlatLengthMaxes<0, vPos>
end else
WaferFlatLengthMin = ''
WaferFlatLengthMax = ''
end
***************************************
* FlatFinder - Wafers Quatity Section *
***************************************
* If (FlatFinderWafersQty NE '') then
* If (FlatFinderWafersQty NE WafersOut) then
* ErrorMessage = 'Unable to sign FQA because Flat Finder and Wafers Out quantities do not match.'
* end
* end else
* ErrorMessage = 'Unable to sign FQA because the Flat Finder quantity is missing.'
* end
************************************
* FlatFinder - Flat Length Section *
************************************
If (WaferFlatLengthMin NE '') AND (WaferFlatLengthMax NE '') then
If (FlatFinderWaferLength NE '') then
If (FlatFinderWaferLength GE WaferFlatLengthMin) AND (FlatFinderWaferLength LE WaferFlatLengthMax) then
end else
ErrorMessage = 'Unable to sign FQA because Flat Finder wafer lengths are out of bounds.'
end
end else
ErrorMessage = 'Unable to sign FQA because the Flat Finder wafer length is missing.'
end
end
Case WaferSizeInch = '8'
// Get NotchFinder Read Value
* NotchFinderWafersQty = FlatFinderWafersQty
***************************************
* NotchFinder - Wafers Quatity Section *
***************************************
* If (NotchFinderWafersQty NE '') then
* If (NotchFinderWafersQty NE WafersOut) then
* ErrorMsg = 'Unable to sign FQA because Notch Finder and Wafers Out quantities do not match.'
* Error_Services('Add', ErrorMsg)
* return
* end
* end else
* ErrorMsg = 'Unable to sign FQA because the Notch Finder quantity is missing.'
* Error_Services('Add', ErrorMsg)
* return
* end
Case Otherwise$
End Case
end
*************************
* Verify Wafer Quantity *
*************************
If ErrorMessage EQ '' then
CassSchedWafers = Xlate('RDS', RDSNo, 'WAFERS_SCHEDULED', 'X')
If CassSchedWafers NE WafersOut then
Message = 'Unable to sign FQA because the Scheduled' : CRLF$ : 'Qty does not equal the '
Message := 'Wafers Out Qty.' : CRLF$ : 'Lead or supervisor must override.'
LeadMessage = 'Scheduled Wafers Quantity does not equal the Wafers Out Quantity.'
If NOT( MemberOf(@USER4, 'LEAD') OR MemberOf(@USER4, 'SUPERVISOR') ) then
Response = Msg(@Window, '', 'POST_EPI_WAFER_OUT', '', Message)
end else
Response = Msg(@Window, '', 'POST_EPI_WAFER_OUT', '', LeadMessage)
end
Begin Case
Case Response EQ 1
Response = True$ ; // User Clicked Override
Case Response EQ 2
Response = False$ ; // User Clicked Cancel
Case Response EQ char(27)
Response = False$ ; // User Pressed Escape Key
End Case
If Response EQ True$ then
Response = Dialog_Box('NDW_VERIFY_USER', @WINDOW, @USER4 : @FM : 'LEAD' : @VM : 'SUPERVISOR')
Valid = Response<1>
Username = Response<2>
If Valid then
RDSRec<RDS_WAFER_OUT_SIG$> = Username
RDSRec<RDS_WAFER_OUT_DATE$> = Date()
RDSRec<RDS_WAFER_OUT_TIME$> = Time()
Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec)
If Error_Services('HasError') then
ErrorMessage = Error_Services('GetMessage')
end
end else
ErrorMessage = 'Unable to sign FQA because the Scheduled' : CRLF$ : 'Qty does not equal the '
ErrorMessage := 'Wafers Out Qty.' : CRLF$ : 'Lead or supervisor must override.'
end
end else
ErrorMessage = 'Unable to sign FQA because the Scheduled' : CRLF$ : 'Qty does not equal the '
ErrorMessage := 'Wafers Out Qty.' : CRLF$ : 'Lead or supervisor must override.'
end
end
end
*********************************
* Verify NCR total >= USL Fails *
*********************************
If ErrorMessage EQ '' then
ROTREnabled = Xlate('REACTOR', Reactor, 'ENABLE_ROTR', 'X')
If (ROTREnabled EQ True$) then
LWICIKey = Xlate('RDS', RDSNo, 'LWI_CI_NO', 'X')
NumUSLFailValues = Xlate('CLEAN_INSP', LWICIKey, 'NUM_FAILED_WAFERS', 'X')
NumUSLFailCount = COUNT(NumUSLFailValues,@VM) + (NumUSLFailValues NE '')
NumUSLFail = NumUSLFailValues<1,NumUSLFailCount>
If NumUSLFail EQ '' then NumUSLFail = 0
TotalNCR = Xlate('RDS', RDSNo, 'TOT_REJ', 'X')
If TotalNCR EQ '' then TotalNCR = 0
If NumUSLFail GT TotalNCR then
Message = 'Unable to sign FQA because the total quantity of NCR wafers':CRLF$:'is less than the '|
: 'number of wafers above the USL threshold.' : CRLF$ : 'A lead or supervisor must override.'
LeadMessage = 'Total quantity of NCR wafers is less than the number of wafers above the USL threshold.'
If NOT( MemberOf(@USER4, 'LEAD') OR MemberOf(@USER4, 'SUPERVISOR') ) then
Response = Msg(@Window, '', 'POST_EPI_WAFER_OUT', '', Message)
end else
Response = Msg(@Window, '', 'POST_EPI_WAFER_OUT', '', LeadMessage)
end
Begin Case
Case Response EQ 1
Response = True$ ; // User Clicked Override
Case Response EQ 2
Response = False$ ; // User Clicked Cancel
Case Response EQ char(27)
Response = False$ ; // User Pressed Escape Key
End Case
If Response EQ True$ then
Response = Dialog_Box('NDW_VERIFY_USER', @WINDOW, @USER4:@FM:'LEAD':@VM:'SUPERVISOR':@VM:'ENGINEER')
Valid = Response<1>
If NOT(Valid) then
ErrorMessage = Message
end
end else
ErrorMessage = Message
end
end
end
end
********************************************
* Verify NCR wafer qty >= Failed wafer qty *
********************************************
If ErrorMessage EQ '' then
NCRReq = QA_Services('GetNCRRequired', WOMatKey)
If NCRReq then
Message = 'Unable to sign FQA because the total quantity of NCR wafers':CRLF$:'is less than the '|
: 'number of wafers that failed surfscan.' : CRLF$ : 'A lead or supervisor must override.'
LeadMessage = 'Total quantity of NCR wafers is less than the number of wafers that failed surfscan.'
If NOT( MemberOf(@USER4, 'LEAD') OR MemberOf(@USER4, 'SUPERVISOR') ) then
Response = Msg(@Window, '', 'POST_EPI_WAFER_OUT', '', Message)
end else
Response = Msg(@Window, '', 'POST_EPI_WAFER_OUT', '', LeadMessage)
end
Begin Case
Case Response EQ 1
Response = True$ ; // User Clicked Override
Case Response EQ 2
Response = False$ ; // User Clicked Cancel
Case Response EQ char(27)
Response = False$ ; // User Pressed Escape Key
End Case
If Response EQ True$ then
Response = Dialog_Box('NDW_VERIFY_USER', @WINDOW, @USER4:@FM:'LEAD':@VM:'SUPERVISOR':@VM:'ENGINEER')
Valid = Response<1>
If NOT(Valid) then
ErrorMessage = Message
end
end else
ErrorMessage = Message
end
end
end
*************************
* Verify if Shift exist *
*************************
If ErrorMessage EQ '' then
Shift = RDSRec<RDS_SHIFT$>
IF Shift EQ '' THEN
ErrorMessage = 'Error in ':Service:' servce. Shift is required before signing.'
END
end
****************************
* Verify if lot is on Hold *
****************************
If ErrorMessage EQ '' then
WOMatCurrStatus = obj_WO_Mat('CurrStatus', WOMatKey)
IF WOMatCurrStatus EQ 'HOLD' THEN
ErrorMessage = 'Error in ':Service:' service. Cassette is on Hold and may not be signed off.'
END
end
**********************
* Check ROTR Failure *
**********************
If ErrorMessage EQ '' then
ROTRAction = Xlate('RDS', RDSNo, 'ROTR_ACTION', 'X')
If (ROTRAction NE 'P') AND (ROTRAction NE 'A') AND (ROTRAction NE '') then
ErrorMessage = 'Error in ':Service:' service. ROTR does not meet all requirements.'
end
end
***************************************
* Verify Metrology has been completed *
***************************************
If ErrorMessage EQ '' then
QAMetTests = Xlate('RDS', RDSNo, 'MET_TEST_QA', 'X')
If QAMetTests NE '' then
QAMetMins = Xlate('RDS', RDSNo, 'MET_MIN_QA', 'X')
QAMetMaxes = Xlate('RDS', RDSNo, 'MET_MAX_QA', 'X')
QAMetResults = Xlate('RDS', RDSNo, 'MET_RESULT_QA', 'X')
QAMetSigs = Xlate('RDS', RDSNo, 'MET_SIG_QA', 'X')
For each QAMetTest in QAMetTests using @VM setting vPos
QAMetMin = QAMetMins<0, vPos>
QAMetMax = QAMetMaxes<0, vPos>
QAMetResult = QAMetResults<0, vPos>
QAMetSig = QAMetSigs<0, vPos>
If QAMetTest NE '' then
Begin Case
Case ( (QAMetMin EQ '') and (QAMetMax EQ '') )
Null
Case (QAMetResult EQ '')
ErrorMessage = 'Error in ':Service:' service. Required QA Metrology results have not been entered.'
Case ( (QAMetResult LT QAMetMin) or (QAMetResult GT QAMetMax) )
ErrorMessage = 'Error in ':Service:' service. One or more QA Metrology results is out of specification.'
Case ( (QAMetResult NE '') and (QAMetSig EQ '') )
ErrorMessage = 'Error in ':Service:' service. One or more QA Metrology results are not signed off.'
End Case
end
Next QAMetTest
end
end
******************************************
* Verify Unload Stage QA Metrology Tests *
******************************************
If ErrorMessage EQ '' then
DevelopmentFlag = Xlate('DEVELOPMENT', 'HGCV', 'STATUS', 'X')
If (DevelopmentFlag EQ True$) then
WOMatQAKey = WOMatKey
WOMatQARec = Database_Services('ReadDataRow', 'WO_MAT_QA', WOMatQAKey)
OutOfSpec = WOMatQARec<WO_MAT_QA_OUT_OF_SPEC$>
OutOfSpec = Sum(OutOfSpec)
If OutOfSpec GT 0 then
FailReasons = WOMatQARec<WO_MAT_QA_FAIL_REASON$>
ErrorMessage = 'Error in ':Service:' service. '
For each FailReason in FailReasons using @VM
ErrorMessage := FailReason:' '
Next FailReason
end
end
end
************************************************************************
* Prompt user to validate the Process Specification Stage Instructions *
************************************************************************
If ErrorMessage EQ '' then
PSNo = RDSRec<RDS_PROD_SPEC_ID$>
VerInst = Xlate('PRS_STAGE', PSNo:'*QA', 'INST', 'X')
VerInst = Trim(VerInst)
IF LEN(VerInst) > 5 THEN
Yes = Dialog_Box( 'RDS_VER', @WINDOW, VerInst )
IF NOT(Yes) THEN
ErrorMessage = 'Error in ':Service:'. PRS_STAGE instructions must be accepted.'
END
END
end
If ErrorMessage NE '' then
Response = False$
Error_Services('Add', ErrorMessage)
end else
Response = True$
end
end service
Service SignQAStage(RDSNo, User)
ErrorMessage = ''
If RDSNo NE '' then
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo)
WONo = RDSRec<RDS_WO$>
CassNo = RDSRec<RDS_CASS_NO$>
WOMatKey = WONo:'*':CassNo
MakeupBox = Xlate('RDS', RDSNo, 'MAKEUP_BOX', 'X')
RawSigDt = Date()
RawSigTm = Time()
SigDt = OConv(Date(), 'D2/')
SigTm = Time()
SigTmPlusOne = OConv(SigTm + 1, 'MTS')
SigTmPlusTwo = OConv(SigTm + 2, 'MTS')
SigTmPlusFive = OConv(SigTm + 5, 'MTS')
SigTmPlusTen = OConv(SigTm + 10, 'MTS')
SigTm = OConv(SigTm,'MTS')
SigBy = User
WOStep = 1
EventParms = ''
EventCnt = 1
ToolID = ''
WHCd = 'CR'
LocCD = 'QA'
Tag = ''
EventParms<COL$LOG_FILE> = 'WO_MAT'
EventParms<COL$LOG_DTM> = SigDt:' ':SigTm
EventParms<COL$ACTION> = WOStep:'QA'
EventParms<COL$WH_CD> = 'CR'
EventParms<COL$LOC_CD> = 'QA'
EventParms<COL$WO_NOS> = WONo
EventParms<COL$CASS_NOS> = CassNo
EventParms<COL$USER_ID> = User
EventParms<COL$TAGS> = ''
EventParms<COL$TOOL_ID> = ''
CONVERT @FM TO @RM IN EventParms
obj_WO_Mat_Log('Create', EventParms)
IF Get_Status(ErrCode) THEN
ErrorMessage = 'Error in ':Service:' service. Error code: ':ErrCode
END
If ErrorMessage EQ '' then
IF MakeupBox EQ True$ THEN
EventParms<COL$LOG_FILE> = 'WO_MAT'
EventParms<COL$LOG_DTM> = SigDt:' ':SigTmPlusTwo
EventParms<COL$ACTION> = 'RTU'
EventParms<COL$WH_CD> = 'CR'
EventParms<COL$LOC_CD> = 'MU'
EventParms<COL$WO_NOS> = WONo
EventParms<COL$CASS_NOS> = CassNo
EventParms<COL$USER_ID> = User
EventParms<COL$TAGS> = ''
EventParms<COL$TOOL_ID> = ''
CONVERT @FM TO @RM IN EventParms
obj_WO_Mat_Log('Create', EventParms) ;* * * * * INV EVENT LOG * * * * *
IF Get_Status(ErrCode) THEN
ErrorMessage = 'Error in ':Service:' service. Error code: ':ErrCode
END
END
If ErrorMessage EQ '' then
RDSRec<RDS_SUP_VER_SIG$> = User
RDSRec<RDS_SUP_VER_SIG_DATE$> = IConv(SigDt, 'D')
RDSRec<RDS_SUP_VER_SIG_TIME$> = IConv(SigTm, 'MT') + 1
Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, False$)
If Error_Services('HasError') then
ErrorMessage = Error_Services('GetMessage')
end
end
end
end else
ErrorMessage = 'Error in ':Service:' service. Null RDSNo passed into service.'
end
If ErrorMessage NE '' then Error_Services('Add', ErrorMessage)
end service
Service CleanInspSigReady(RDSNo, Stage)
ErrorMessage = ''
If ( (RDSNo NE '') and (Stage NE '') ) then
WONo = Xlate('RDS', RDSNo, 'WO', 'X')
CassNo = Xlate('RDS', RDSNo, 'CASS_NO', 'X')
WOMatKey = WONo:'*':CassNo
Signature_Services('CheckSigOrder', WOMatKey, Stage)
If Error_Services('HasError') then ErrorMessage = Error_Services('GetMessage')
Begin Case
Case ( (Stage EQ 'PREI') or (Stage EQ 'PREC') or (Stage EQ 'PRES') )
CINo = Xlate('RDS', RDSNo, 'PRE_CI_NO', 'X')
Case ( (Stage EQ 'FWII') or (Stage EQ 'FWIC') or (Stage EQ 'FWIS') )
CINo = Xlate('RDS', RDSNo, 'FWI_CI_NO', 'X')
Case ( (Stage EQ 'LWII') or (Stage EQ 'LWIC') or (Stage EQ 'LWIS') )
CINo = Xlate('RDS', RDSNo, 'LWI_CI_NO', 'X')
Case ( (Stage EQ 'PSTI') or (Stage EQ 'PSTC') or (Stage EQ 'PSTS') )
CINo = Xlate('RDS', RDSNo, 'POST_CI_NO', 'X')
Case Otherwise$
ErrorMessage = 'Error in ':Service:' service. Invalid stage ID passed into service.'
End Case
If ErrorMessage EQ '' then
If RowExists('CLEAN_INSP', CINo) then
CIRow = Database_Services('ReadDataRow', 'CLEAN_INSP', CINo)
If Error_Services('HasError') then
ErrorMessage = Error_Services('GetMessage')
end
end else
ErrorMessage = 'Error in ':Service:' service. No ':Stage:' record on file for RDS ':RDSNo:'!'
end
end
Begin Case
Case ErrorMessage NE ''
Null
Case ( (Stage EQ 'PREI') or (Stage EQ 'FWII') or (Stage EQ 'LWII') or (Stage EQ 'PSTI') )
// Verify each inspection row has data.
// Front side data
InspTools = CIRow<CLEAN_INSP_INSP_TOOL$>
InspLPDs = CIRow<CLEAN_INSP_INSP_LPD$>
InspScratches = CIRow<CLEAN_INSP_INSP_SCRATCHES$>
InspScratchLengths = CIRow<CLEAN_INSP_INSP_SCRATCH_LEN$>
InspPits = CIRow<CLEAN_INSP_INSP_PITS$>
InspMounds = CIRow<CLEAN_INSP_INSP_MOUNDS$>
InspStackFaults = CIRow<CLEAN_INSP_INSP_STACK_FAULTS$>
InspSpikes = CIRow<CLEAN_INSP_INSP_SPIKES$>
InspSpots = CIRow<CLEAN_INSP_INSP_SPOTS$>
InspFOVs = CIRow<CLEAN_INSP_INSP_FOV$>
InspBLDefects = CIRow<CLEAN_INSP_INSP_BL_DEFECTS$>
InspSigs = CIRow<CLEAN_INSP_INSP_SIG$>
InspSigDTMs = CIRow<CLEAN_INSP_INSP_SIG_DTM$>
// Front side specs
SpecLPD = CIRow<CLEAN_INSP_SPEC_LPD$>
SpecScratches = CIRow<CLEAN_INSP_SPEC_SCRATCHES$>
SpecScratchLen = CIRow<CLEAN_INSP_SPEC_SCRATCH_LEN$>
SpecPits = CIRow<CLEAN_INSP_SPEC_PITS$>
SpecMounds = CIRow<CLEAN_INSP_SPEC_MOUNDS$>
SpecStackFaults = CIRow<CLEAN_INSP_SPEC_STACK_FAULTS$>
SpecSpikes = CIRow<CLEAN_INSP_SPEC_SPIKES$>
SpecSpots = CIRow<CLEAN_INSP_SPEC_SPOTS$>
SpecFOV = CIRow<CLEAN_INSP_SPEC_FOV$>
SpecBLDefects = CIRow<CLEAN_INSP_SPEC_BL_DEFECTS$>
// Backside data
InspBsideScratches = CIRow<CLEAN_INSP_INSP_BSIDE_SCRATCHES$>
InspBsideScratchLen = CIRow<CLEAN_INSP_INSP_BSIDE_SCRATCH_LEN$>
InspBsideNodules = CIRow<CLEAN_INSP_INSP_BSIDE_NODULES$>
InspBsideSpikes = CIRow<CLEAN_INSP_INSP_BSIDE_SPIKES$>
// Backside specs
SpecBsideScratches = CIRow<CLEAN_INSP_SPEC_BSIDE_SCRATCHES$>
SpecBsideScratchLen = CIRow<CLEAN_INSP_SPEC_BSIDE_SCRATCH_LEN$>
SpecBsideNodules = CIRow<CLEAN_INSP_SPEC_BSIDE_NODULES$>
SpecBsideSpikes = CIRow<CLEAN_INSP_SPEC_BSIDE_SPIKES$>
// Verify front side and back side data
NumRows = DCount(InspTools, @VM)
If NumRows GT 0 then
For RowIndex = 1 to NumRows
RowLPD = InspLPDs<0, RowIndex>
RowScratches = InspScratches<0, RowIndex>
RowScratchLen = InspScratchLengths<0, RowIndex>
RowPits = InspPits<0, RowIndex>
RowMounds = InspMounds<0, RowIndex>
RowStackFaults = InspStackFaults<0, RowIndex>
RowSpikes = InspSpikes<0, RowIndex>
RowSpots = InspSpots<0, RowIndex>
RowFOV = InspFOVs<0, RowIndex>
RowBLDefects = InspBLDefects<0, RowIndex>
RowBsideScratches = InspBsideScratches<0, RowIndex>
RowBsideScratchLen = InspBsideScratchLen<0, RowIndex>
RowBsideNodules = InspBsideNodules<0, RowIndex>
RowBsideSpikes = InspBsideSpikes<0, RowIndex>
If ( (SpecLPD NE '') and (RowLPD EQ '') ) then
ErrorMessage = 'Error in ':Service:' service. Inspection LPD data is missing.'
end
If ( (ErrorMessage EQ '') and (SpecScratches NE '') and (RowScratches EQ '') ) then
ErrorMessage = 'Error in ':Service:' service. Inspection scratches data is missing.'
end
If ( ( ErrorMessage EQ '') and (SpecScratchLen NE '') and (RowScratchLen EQ '' ) ) then
ErrorMessage = 'Error in ':Service:' service. Inspection scratches data is missing.'
end
If ( (ErrorMessage EQ '') and (SpecPits NE '') and (RowPits EQ '') ) then
ErrorMessage = 'Error in ':Service:' service. Inspection pits data is missing.'
end
If ( (ErrorMessage EQ '') and (SpecMounds NE '') and (RowMounds EQ '') ) then
ErrorMessage = 'Error in ':Service:' service. Inspection mounds data is missing.'
end
If ( (ErrorMessage EQ '') and (SpecStackFaults NE '') and (RowStackFaults EQ '') ) then
ErrorMessage = 'Error in ':Service:' service. Inspection stack faults data is missing.'
end
If ( (ErrorMessage EQ '') and (SpecSpikes NE '') and (RowSpikes EQ '') ) then
ErrorMessage = 'Error in ':Service:' service. Inspection spikes data is missing.'
end
If ( (ErrorMessage EQ '') and (SpecSpots NE '') and (RowSpots EQ '' ) ) then
ErrorMessage = 'Error in ':Service:' service. Inspection spots data is missing.'
end
If ( (ErrorMessage EQ '') and (SpecFOV NE '') and (RowFOV EQ '') ) then
ErrorMessage = 'Error in ':Service:' service. Inspection FOV data is missing.'
end
If ( (ErrorMessage EQ '') and (SpecBLDefects NE '') and (RowBLDefects EQ '') ) then
ErrorMessage = 'Error in ':Service:' service. Inspection BL defects data is missing.'
end
If ( (ErrorMessage EQ '') and (SpecBsideScratches NE '') and (RowBsideScratches EQ '') ) then
ErrorMessage = 'Error in ':Service:' service. Inspection back side scratches data is missing.'
end
If ( (ErrorMessage EQ '') and (SpecBsideScratchLen NE '') and (RowBsideScratchLen EQ '') ) then
ErrorMessage = 'Error in ':Service:' service. Inspection back side scratch length data is missing.'
end
If ( (ErrorMessage EQ '') and (SpecBsideNodules NE '') and (RowBsideNodules EQ '') ) then
ErrorMessage = 'Error in ':Service:' service. Inspection back side nodules data is missing.'
end
If ( (ErrorMessage EQ '') and (SpecBsideSpikes NE '') and (RowBsideSpikes EQ '') ) then
ErrorMessage = 'Error in ':Service:' service. Inspection back side spikes data is missing.'
end
Until ErrorMessage NE ''
Next RowIndex
end
Case ( (Stage EQ 'PREC') or (Stage EQ 'FWIC') or (Stage EQ 'LWIC') or (Stage EQ 'PSTC') )
// Verify each cleans row has a tool.
CleanTools = CIRow<CLEAN_INSP_CLEAN_TOOL$>
NumRows = DCount(CleanTools, @VM)
If NumRows GT 0 then
For RowIndex = 1 to NumRows
RowTool = CleanTools<0, RowIndex>
If RowTool EQ '' then
ErrorMessage = 'Error in ':Service:' service. Clean tool ID is missing.'
end
Until ErrorMessage NE ''
Next RowIndex
end
Case ( (Stage EQ 'PRES') or (Stage EQ 'FWIS') or (Stage EQ 'LWIS') or (Stage EQ 'PSTS') )
// Verify surfscan row has a tool.
ScanTools = CIRow<CLEAN_INSP_SCAN_TOOL$>
NumRows = DCount(ScanTools, @VM)
If NumRows GT 0 then
For RowIndex = 1 to NumRows
RowTool = ScanTools<0, RowIndex>
If RowTool EQ '' then
ErrorMessage = 'Error in ':Service:' service. Scan tool ID is missing.'
end
Until ErrorMessage NE ''
Next RowIndex
end
End Case
end
If ErrorMessage EQ '' then
Response = True$
end else
Error_Services('Add', ErrorMessage)
Response = False$
end
end service
Service SignCleanInsp(RDSNo, Stage=CI_STAGES, User)
ErrorMessage = ''
If ( (RDSNo NE '') and (Stage NE '') and (User NE '') ) then
SigDTM = Datetime()
WONo = Xlate('RDS', RDSNo, 'WO', 'X')
CassNo = Xlate('RDS', RDSNo, 'CASS_NO', 'X')
WOMatKey = WONo:'*':CassNo
Begin Case
Case ( (Stage EQ 'PREI') or (Stage EQ 'PREC') or (Stage EQ 'PRES') )
CINo = Xlate('RDS', RDSNo, 'PRE_CI_NO', 'X')
Case ( (Stage EQ 'FWII') or (Stage EQ 'FWIC') or (Stage EQ 'FWIS') )
CINo = Xlate('RDS', RDSNo, 'FWI_CI_NO', 'X')
Case ( (Stage EQ 'LWII') or (Stage EQ 'LWIC') or (Stage EQ 'LWIS') )
CINo = Xlate('RDS', RDSNo, 'LWI_CI_NO', 'X')
Case ( (Stage EQ 'PSTI') or (Stage EQ 'PSTC') or (Stage EQ 'PSTS') )
CINo = Xlate('RDS', RDSNo, 'POST_CI_NO', 'X')
Case Otherwise$
ErrorMessage = 'Error in ':Service:' service. Invalid stage ID passed into service.'
End Case
If ErrorMessage EQ '' then
If RowExists('CLEAN_INSP', CINo) then
CIRow = Database_Services('ReadDataRow', 'CLEAN_INSP', CINo)
If Error_Services('HasError') then
ErrorMessage = Error_Services('GetMessage')
end else
OrigCIRow = CIRow
end
end else
ErrorMessage = 'Error in ':Service:' service. No ':Stage:' record on file for RDS ':RDSNo:'!'
end
end
Begin Case
Case ErrorMessage NE ''
Null
Case ( (Stage EQ 'PREI') or (Stage EQ 'FWII') or (Stage EQ 'LWII') or (Stage EQ 'PSTI') )
InspTools = CIRow<CLEAN_INSP_INSP_TOOL$>
InspSigs = CIRow<CLEAN_INSP_INSP_SIG$>
InspSigDTMs = CIRow<CLEAN_INSP_INSP_SIG_DTM$>
NumRows = DCount(InspTools, @VM)
If NumRows GT 0 then
For RowIndex = 1 to NumRows
// Sign each row if no signature present
If InspSigs<0, RowIndex> EQ '' then
InspSigs<0, RowIndex> = User
InspSigDTMs<0, RowIndex> = SigDTM
end
Until ErrorMessage NE ''
Next RowIndex
end
CIRow<CLEAN_INSP_INSP_SIG$> = InspSigs
CIRow<CLEAN_INSP_INSP_SIG_DTM$> = InspSigDTMs
Case ( (Stage EQ 'PREC') or (Stage EQ 'FWIC') or (Stage EQ 'LWIC') or (Stage EQ 'PSTC') )
CleanTools = CIRow<CLEAN_INSP_CLEAN_TOOL$>
CleanSigs = CIRow<CLEAN_INSP_CLEAN_SIG$>
CleanSigDTMs = CIRow<CLEAN_INSP_CLEAN_SIG_DTM$>
NumRows = DCount(CleanTools, @VM)
If NumRows GT 0 then
For RowIndex = 1 to NumRows
// Sign each row if no signature present
If CleanSigs<0, RowIndex> EQ '' then
CleanSigs<0, RowIndex> = User
CleanSigDTMs<0, RowIndex> = SigDTM
end
Until ErrorMessage NE ''
Next RowIndex
end
CIRow<CLEAN_INSP_CLEAN_SIG$> = CleanSigs
CIRow<CLEAN_INSP_CLEAN_SIG_DTM$> = CleanSigDTMs
Case ( (Stage EQ 'PRES') or (Stage EQ 'FWIS') or (Stage EQ 'LWIS') or (Stage EQ 'PSTS') )
ScanTools = CIRow<CLEAN_INSP_SCAN_TOOL$>
SurfSigs = CIRow<CLEAN_INSP_SCAN_SIG$>
SurfSigDTMs = CIRow<CLEAN_INSP_SCAN_SIG_DTM$>
NumRows = DCount(ScanTools, @VM)
If NumRows GT 0 then
For RowIndex = 1 to NumRows
// Sign each row if no signature present
If SurfSigs<0, RowIndex> EQ '' then
SurfSigs<0, RowIndex> = User
SurfSigDTMs<0, RowIndex> = SigDTM
end
Until ErrorMessage NE ''
Next RowIndex
end
CIRow<CLEAN_INSP_SCAN_SIG$> = SurfSigs
CIRow<CLEAN_INSP_SCAN_SIG_DTM$> = SurfSigDTMs
End Case
end else
ErrorMessage = 'Error in ':Service:' service. Null RDSNo, user, or stage passed in.'
end
If ErrorMessage EQ '' then
If CIRow NE OrigCIRow then Database_Services('WriteDataRow', 'CLEAN_INSP', CINo, CIRow)
If Error_Services('NoError') then
Response = True$
end else
ErrorMessage = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
Error_Services('Add', ErrorMessage)
Response = False$
end
end else
Error_Services('Add', ErrorMessage)
Response = False$
end
end service
Service QAMetSigReady(RDSNo, QAStage=QA_STAGES, Slot=SLOTS, WOMatQAKey)
ErrorMessage = ''
If ( (RDSNo NE '' or WOMatQAKey NE '') and (QAStage NE '') and (Slot NE '') ) then
If RDSNo NE '' then
WOMatKey = Xlate('RDS', RDSNo, 'WO_MAT_KEY', 'X')
end else
WOMatKey = WOMatQAKey
end
If WOMatKey NE '' then
If RowExists('WO_MAT_QA', WOMatKey) then
WOMatQARec = Database_Services('ReadDataRow', 'WO_MAT_QA', WOMatKey)
If Error_Services('HasError') then
ErrorMessage = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
end else
WOMatQAStages = WOMatQARec<WO_MAT_QA_STAGE$>
end
end else
ErrorMessage = 'Error in ':Service:' service. No WO_MAT_QA record on file for RDS ':RDSNo:'!'
end
end else
ErrorMessage = 'Error in ':Service:' service. Null WO_MAT_KEY returned for RDS ':RDSNo:'!'
end
Begin Case
Case ErrorMessage NE ''
Null
Case ( (QAStage EQ 'LOAD') or (QAStage EQ 'QA') or (QAStage EQ 'MO_QA') )
Done = False$
WOMatRec = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey)
ReactorType = Xlate('WO_MAT', WOMatKey, 'REACTOR_TYPE', 'X')
TestSlots = WOMatQARec<WO_MAT_QA_SLOT$>
// Check for QA Stage Supplements
UnacknowledgedSupp = Supplement_Services('UnacknowledgedSupplementCheck', 'WO_MAT', WOMatKey, 'QA')
If UnacknowledgedSupp NE FALSE$ then
ErrorMessage = 'The QA stage supplements must be acknowledged before the load operation can be signed.'
end
If ReactorType EQ 'EPP' then
WMOKey = WOMatRec<WO_MAT_WMO_KEY$>
WMORec = Database_Services('ReadDataRow', 'WM_OUT', WMOKey)
MUWfrIDs = WOMatRec<WO_MAT_EPOS_REP_WAFER_ID$>
MUWfrResults = WMORec<WM_OUT_MU_WAFER_THK_RESULT$>
end else
MUWfrIDs = WOMatRec<WO_MAT_SLOT_REP_WAFER_ID$>
MUWfrResults = WOMatRec<WO_MAT_MU_WAFER_THK_RESULT$>
end
For each WOMatQAStage in WOMatQAStages using @VM setting vPos
TestSlot = TestSlots<0, vPos>
If ( (WOMatQAStage EQ QAStage) and (Slot EQ TestSlot) ) then
Done = True$
// Compare Met Result to Met Min and Met Max
TestProp = WOMatQARec<WO_MAT_QA_PROP$, vPos>
MetResult = WOMatQARec<WO_MAT_QA_RESULT$, vPos>
MetMin = WOMatQARec<WO_MAT_QA_MIN$, vPos>
MetMax = WOMatQARec<WO_MAT_QA_MAX$, vPos>
Begin Case
Case MetResult EQ ''
ErrorMessage = 'Error in ':Service:' service. Metrology result for stage ':QAStage:' slot ':Slot:' is missing.'
Case ( (MetResult LT MetMin) or (MetResult GT MetMax) )
ErrorMessage = 'Error in ':Service:' service. Metrology result is out of spec for stage ':QAStage:' slot ':Slot:'.'
End Case
// Compare Std Dev Result to Std Dev Max
StdDevResult = WOMatQARec<WO_MAT_QA_STD_RESULT$, vPos>
StdDevMax = WOMatQARec<WO_MAT_QA_STD_MAX$, vPos>
Begin Case
Case StdDevResult EQ ''
// Std Dev data is not always supplied.
Null
Case StdDevResult GT StdDevMax
ErrorMessage = 'Error in ':Service:' service. StdDev exceeds spec for stage ':QAStage:'.'
End Case
If TestProp EQ 'THICK' then
// Ensure makeup wafer thickness values are in spec and that at least one wafer
// from each makeup box has a thickness result.
// Build a list of unique makeup boxes
MUBoxes = ''
MUThickTests = ''
If MUWfrIDs NE '' then
For each MUWfrID in MUWfrIDs using @VM setting vPos
If MUWfrID NE '' then
MUBox = Field(MUWfrID, '.', 1, 2)
Locate MUBox in MUBoxes using @VM setting MUIndex else
MUBoxes<0, -1> = MUBox
end
end
Next MUWfrID
// Verify makeup wafers are also within spec
For each MUWfrID in MuWfrIDs using @VM setting vPos
If MUWfrID NE '' then
MUBox = Field(MUWfrID, '.', 1, 2)
MUWfrResult = MUWfrResults<0, vPos>
Locate MUBox in MUBoxes using @VM setting MUIndex then
MUThickTests<0, MUIndex> = True$
end
If MUWfrResult NE '' then
If ( (MUWfrResult LT MetMin) or (MUWfrResult GT MetMax) ) then
ErrorMessage = 'Error in ':Service:' service. Metrology result is out of spec for stage ':QAStage:' makeup wafer ID ':MUWfrID:'.'
end
end
end
Next MUWfrID
end
If MUBoxes NE '' then
// Verify each MU Box has at least one thickness result
For each MUBox in MUBoxes using @VM setting MUBoxIndex
If MUThickTests<0, MUBoxIndex> NE True$ then
ErrorMessage = 'Error in ':Service:' service. At least one metrology result is required for stage ':QAStage:' makeup box ID ':MUBox:'.'
end
Next MUBox
end
end
end
Until ( (ErrorMessage NE '') or (Done EQ True$) )
Next WOMatQAStage
Case QAStage EQ 'UNLOAD'
// Leverage fail reason column calculated by WO_MAT_QA_ACTIONS
For each WOMatQAStage in WOMatQAStages using @VM setting vPos
If WOMatQAStage EQ QAStage then
FailReason = WOMatQARec<WO_MAT_QA_FAIL_REASON$, vPos>
If ( (FailReason NE '') |
and (FailReason NE 'THICK_ONLY UNLOAD product measurement test has not been signed.') |
and (FailReason NE 'CRES UNLOAD product measurement test has not been signed.') |
and (FailReason NE 'UNLOAD LW_RHO product measurement test has not been signed.' ) ) then
ErrorMessage = 'Error in ':Service:' service. ':FailReason
end
end
Until ErrorMessage NE ''
Next WOMatQAStage
End Case
end else
ErrorMessage = 'Error in ':Service:' service. Null RDSNo or stage passed in.'
end
If ErrorMessage NE '' then
Error_Services('Add', ErrorMessage)
Response = False$
end else
Response = True$
end
end service
Service SignQAMet(RDSNo, QAStage=QA_STAGES, User, Slot=SLOTS, WOMatQAKey)
ErrorMessage = ''
If ( (RDSNo NE '' or WOMatQAKey NE '') and (QAStage NE '') ) then
If RDSNo NE '' then
WOMatKey = Xlate('RDS', RDSNo, 'WO_MAT_KEY', 'X')
end else
WOMatKey = WOMatQAKey
end
If WOMatKey NE '' then
If RowExists('WO_MAT_QA', WOMatKey) then
WOMatQARec = Database_Services('ReadDataRow', 'WO_MAT_QA', WOMatKey)
If Error_Services('HasError') then
ErrorMessage = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
end else
WOMatQAStages = WOMatQARec<WO_MAT_QA_STAGE$>
WOMatQASlots = WOMatQARec<WO_MAT_QA_SLOT$>
end
end else
ErrorMessage = 'Error in ':Service:' service. No WO_MAT_QA record on file for RDS ':RDSNo:'!'
end
end else
ErrorMessage = 'Error in ':Service:' service. Null WO_MAT_KEY returned for RDS ':RDSNo:'!'
end
If ErrorMessage EQ '' then
SigDTM = Datetime()
For each WOMatQAStage in WOMatQAStages using @VM setting vPos
TestSlot = WOMatQASlots<0, vPos>
If ( (WOMatQAStage EQ QAStage) and (TestSlot EQ Slot) ) then
// Sign each row if no signature present.
If WOMatQARec<WO_MAT_QA_SIG$, vPos> EQ '' then
WOMatQARec<WO_MAT_QA_SIG$, vPos> = User
WOMatQARec<WO_MAT_QA_SIG_DTM$, vPos> = SigDTM
end
end
Next WOMatQAStage
Database_Services('WriteDataRow', 'WO_MAT_QA', WOMatKey, WOMatQARec)
If Error_Services('HasError') then
ErrorMessage = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
end
end
end else
ErrorMessage = 'Error in ':Service:' service. Null RDSNo or stage passed into service.'
end
If ErrorMessage NE '' then
Error_Services('Add', ErrorMessage)
Response = False$
end else
Response = True$
end
end service
Service ROTRSigReady(RDSNo)
ErrorMessage = ''
If RDSNo NE '' then
LWICINo = Xlate('RDS', RDSNo, 'LWI_CI_NO', 'X')
If LWICINo NE '' then
LWICIRec = Database_Services('ReadDataRow', 'CLEAN_INSP', LWICINo)
If Error_Services('NoError') then
ROTRAction = LWICIRec<CLEAN_INSP_ROTR_ACTION$>
If ROTRAction NE 'F' then
ErrorMessage = 'Error in ':Service:' service. ROTR does not require acceptance.'
end
end else
ErrorMessage = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
end
end else
ErrorMessage = 'Error in ':Service:' service. No LWI CLEAN_INSP record on file for RDS ':RDSNo:'!'
end
end else
ErrorMessage = 'Error in ':Service:' service. Null RDSNo passed into service.'
end
If ErrorMessage NE '' then
Error_Services('Add', ErrorMessage)
Response = False$
end else
Response = True$
end
end service
Service SignROTR(RDSNo, User, ROTRReason)
ErrorMessage = ''
If ( (RDSNo NE '') and (User NE '') and (ROTRReason NE '') ) then
LWICINo = Xlate('RDS', RDSNo, 'LWI_CI_NO', 'X')
If LWICINo NE '' then
LWICIRec = Database_Services('ReadDataRow', 'CLEAN_INSP', LWICINo)
If Error_Services('NoError') then
ROTRSig = LWICIRec<CLEAN_INSP_SIGN_ROTR_SIGNATURE$>
If ROTRSig EQ '' then
// Only sign ROTR Acceptance if no signature present.
LWICIRec<CLEAN_INSP_SIGN_ROTR_SIGNATURE$> = User
LWICIRec<CLEAN_INSP_SIGN_ROTR_DTM$> = Datetime()
LWICIRec<CLEAN_INSP_SIGN_ROTR_REASON$> = ROTRReason
LWICIRec<CLEAN_INSP_ROTR_ACTION$> = 'A' ; // Accepted
Database_Services('WriteDataRow', 'CLEAN_INSP', LWICINo, LWICIRec)
If Error_Services('HasError') then
ErrorMessage = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
end
end
end else
ErrorMessage = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
end
end else
ErrorMessage = 'Error in ':Service:' service. No LWI CLEAN_INSP record on file for RDS ':RDSNo:'!'
end
end else
ErrorMessage = 'Error in ':Service:' service. Null RDSNo passed into service.'
end
If ErrorMessage NE '' then
Error_Services('Add', ErrorMessage)
Response = False$
end else
Response = True$
end
end service
Service NCRSigReady(RDSNo)
ErrorMessage = ''
If RDSNo NE '' then
WOMatKey = Xlate('RDS', RDSNo, 'WO_MAT_KEY', 'X')
If WOMatKey NE '' then
NCRKeys = Xlate('WO_MAT', WOMatKey, 'NCR_KEYS', 'X')
If NCRKeys NE '' then
For each NCRKey in NCRKeys using @VM setting vPos
Error = False$
ReqFields = 'SHIFT,DEPT,DEPT_RESP,LOSS_CODE,LOSS_COMMENTS,CONTAIN_ACTIONS,LOSS_STAGE,LOSS_BY'
For each ReqField in ReqFields using ',' setting cPos
Val = Xlate('NCR', NCRKey, ReqField, 'X')
If Val EQ '' then
ErrorMessage = 'Error in ':Service:' service. No NCRs on file for RDS ':RDSNo:'!'
end
Until ErrorMessage NE ''
Next ReqField
Until ErrorMessage NE ''
Next NCRKey
end else
ErrorMessage = 'Error in ':Service:' service. No NCRs on file for RDS ':RDSNo:'!'
end
end else
ErrorMessage = 'Error in ':Service:' service. No WO_MAT_KEY on file for RDS ':RDSNo:'!'
end
end else
ErrorMessage = 'Error in ':Service:' service. Null RDSNo passed into service.'
end
If ErrorMessage NE '' then
Error_Services('Add', ErrorMessage)
Response = False$
end else
Response = True$
end
end service
Service SignNCRs(RDSNo, User)
ErrorMessage = ''
If RDSNo NE '' then
WOMatKey = Xlate('RDS', RDSNo, 'WO_MAT_KEY', 'X')
If WOMatKey NE '' then
NCRKeys = Xlate('WO_MAT', WOMatKey, 'NCR_KEYS', 'X')
If NCRKeys NE '' then
SigDTM = Datetime()
WOMatRec = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey)
If Error_Services('NoError') then
For each NCRKey in NCRKeys using @VM setting vPos
// Sign each NCR
NCRRec = Database_Services('ReadDataRow', 'NCR', NCRKey)
If Error_Services('NoError') then
NCRRec<NCR_AUTH_SHIP_SIG$> = User
NCRRec<NCR_AUTH_REJ_SIG$> = User
NCRRec<NCR_AUTH_SHIP_SIG_DTM$> = SigDTM
NCRRec<NCR_STATUS$> = 'C'
Database_Services('WriteDataRow', 'NCR', NCRKey, NCRRec)
If Error_Services('NoError') then
// Sign WO_MAT NCR sig column
Locate NCRKey in WOMatRec<WO_MAT_NCR_KEYS$> using @VM setting Pos then
CurrSig = Trim(WOMatRec<WO_MAT_NCR_FINAL_SIG$, Pos>)
If CurrSig EQ '' then
WOMatRec<WO_MAT_NCR_FINAL_SIG$, Pos> = User
WOMatRec<WO_MAT_NCR_FINAL_SIG_DTM$, Pos> = SigDTM
Database_Services('WriteDataRow', 'WO_MAT', WOMatKey, WOMatRec)
If Error_Services('HasError') then
ErrorMessage = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
end
end
end else
ErrorMessage = 'Error in ':Service:' service. Failed to locate NCR key ':NCRKey:' in WO_MAT record ':WOMatKey:'!'
end
end else
ErrorMessage = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
end
end else
ErrorMessage = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
end
Until ErrorMessage NE ''
Next NCRKey
end else
ErrorMessage = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
end
end else
ErrorMessage = 'Error in ':Service:' service. No NCRs on file for RDS ':RDSNo:'!'
end
end else
ErrorMessage = 'Error in ':Service:' service. No WO_MAT_KEY on file for RDS ':RDSNo:'!'
end
end else
ErrorMessage = 'Error in ':Service:' service. Null RDSNo passed into service.'
end
If ErrorMessage NE '' then
Error_Services('Add', ErrorMessage)
Response = False$
end else
Response = True$
end
end service
Service SignSupplement(RDSNo, User)
ErrorMessage = ''
If RDSNo NE '' then
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo)
If Error_Services('NoError') then
RDSRec<RDS_SUPPL_SIG$> = User
RDSRec<RDS_SUPPL_SIG_DATE$> = Date()
RDSRec<RDS_SUPPL_SIG_TIME$> = Time()
RDSRec<RDS_SUPPL_ACK$> = True$
Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, True$)
If Error_Services('HasError') then
ErrorMessage = Error_Services('GetMessage')
end
end else
ErrorMessage = Error_Services('GetMessage')
end
end else
ErrorMessage = 'Error in ':Service:' service. Null RDSNo passed into service.'
end
If ErrorMessage NE '' then
Error_Services('Add', ErrorMessage)
Response = False$
end else
Response = True$
end
end service
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Internal GoSubs
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
GetMostRecentSig:
NumRows = DCount(StageRows, @VM)
SignatureFound = False$
For RowIndex = NumRows to 1 Step -1
Signature = Signatures<0, RowIndex>
SigDTM = SigDTMs<0, RowIndex>
If Signature NE '' then SignatureFound = True$
Until SignatureFound EQ True$
Next RowIndex
return