Initial commit. Create FQASignatureReady service in QA_SERVICES. Create SignFQA service in SIGNATURE_SERVICES. Commit remaining portion of project. Implement changes requested in review meeting. Fix typo. Add new MU logic to final entry point. Restrict logic to only apply to 'THICK' inspections. Bypass new logic if Biorad 4 and 5 are down.
1886 lines
74 KiB
Plaintext
1886 lines
74 KiB
Plaintext
Function RDS_Services(@Service, @Params)
|
|
/***********************************************************************************************************************
|
|
|
|
Name : RDS_Services
|
|
|
|
Description : Handler program for all RDS services.
|
|
|
|
Notes : Application errors should be logged using the Error Services module. There are a few methodological
|
|
assumptions built into way errors are managed which are important to understand in order to properly
|
|
work with Error Services:
|
|
|
|
- The term 'top' refers to the originating procedure of a call stack and the term 'bottom' refers to
|
|
the last routine (or the current routine) within a call stack. Within the OpenInsight Debugger
|
|
this will appear backwards since the originating procedure always appears at the bottom of the
|
|
list and the current routine appears at the top of the list. We are using this orientation because
|
|
it is common to refer to the process of calling other procedures as 'drilling down'.
|
|
|
|
- The reason for defining the orientation of the call stack is because Error_Services allows for
|
|
multiple error conditions to be appended to an original error. In most cases this will happen when
|
|
a procedure at the bottom of the stack generates an error condition and then returns to its
|
|
calling procedure. This higher level procedure can optionally add more information relevant to
|
|
itself. This continues as the call stack 'bubbles' its way back to the top to where the
|
|
originating procedure is waiting.
|
|
|
|
- Native OpenInsight commands that handle errors (e.g., Set_Status, Set_FSError, Set_EventStatus)
|
|
preserve their error state until explicitly cleared. This can hinder the normal execution of code
|
|
since subsequent procedures (usually SSPs) will fail if a pre-existing error condition exists.
|
|
Our philosophy is that error conditions should automatically be cleared before a new procedure
|
|
is executed to avoid this problem. However, the nature of Basic+ does not make this easy to
|
|
automate for any given stored procedure. Therefore, if a stored procedure wants to conform to our
|
|
philosophy then it should include a call into the 'Clear' service request at the top of the
|
|
program. Alternatively this can be done through a common insert (see SERVICE_SETUP for example.)
|
|
|
|
- Service modules will use the SERVICE_SETUP insert and therefore automatically clear out any
|
|
error conditions that were set before.
|
|
|
|
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)
|
|
05/14/18 djs Original programmer.
|
|
09/18/18 djs Added the IsEpiPro service.
|
|
08/23/21 dpc Added validation routine IsPackaged
|
|
08/28/23 djm Added view/add comment functions.
|
|
06/13/24 djm Add GetCurrentStatus service.
|
|
07/18/24 djm Update AddComment to use Obj_Post_Log to reduce lag.
|
|
|
|
***********************************************************************************************************************/
|
|
#pragma precomp SRP_PreCompiler
|
|
|
|
$Insert APP_INSERTS
|
|
$Insert MSG_EQUATES
|
|
$Insert RTI_DEBUG_COMMON
|
|
$Insert SRPMail_Inserts
|
|
$Insert LOGICAL
|
|
$Insert SERVICE_SETUP
|
|
$Insert RDS_EQUATES
|
|
$Insert PROD_SPEC_EQUATES
|
|
$Insert RDS_LAYER_EQUATES
|
|
$Insert PRS_LAYER_EQUATES
|
|
$Insert RDS_TEST_EQUATES
|
|
$Insert TOOL_CLASS_EQUATES
|
|
$Insert TEST_POINT_MAP_EQUATES
|
|
$Insert CLEAN_INSP_EQUATES
|
|
$Insert REACT_RUN_EQUATES
|
|
$Insert REACTOR_EQUATES
|
|
$Insert WO_MAT_QA_EQUATES
|
|
$Insert PRS_STAGE_EQUATES
|
|
$Insert PRS_PROP_EQUATES
|
|
$Insert WO_LOG_EQUATES
|
|
$Insert WM_OUT_EQUATES
|
|
$Insert REACT_UTIL_EQU
|
|
$Insert WO_MAT_EQUATES
|
|
$Insert RLIST_EQUATES
|
|
$Insert REACT_MODE_EQUATES
|
|
$Insert LSL_USERS_EQUATES
|
|
$Insert TOOL_EQUATES
|
|
$Insert POPUP_EQUATES
|
|
$Insert NOTIFICATION_EQUATES
|
|
$Insert DICT_EQUATES
|
|
$Insert COMPANY_EQUATES
|
|
$Insert RETURN_TO_FAB_LOTS_EQUATES
|
|
$Insert TEST_RUN_EQUATES
|
|
|
|
EQU COL$LSID TO 1
|
|
EQU COL$RECIPE TO 2
|
|
EQU COL$RECIPE_NAME TO 3
|
|
EQU COL$PARAMS TO 4
|
|
EQU COL$PARMS_OUT TO 5
|
|
EQU COL$BLANK_COL TO 6
|
|
EQU COL$MET_NO TO 7
|
|
EQU COL$THICK_AVG TO 8
|
|
EQU COL$RRHO_AVG TO 9
|
|
EQU COL$MET_NO_Z1 TO 10
|
|
EQU COL$THICK_AVG_Z1 TO 11
|
|
EQU COL$RRHO_AVG_Z1 TO 12
|
|
EQU COL$MET_NO_Z2 TO 13
|
|
EQU COL$THICK_AVG_Z2 TO 14
|
|
EQU COL$RRHO_AVG_Z2 TO 15
|
|
EQU COL$MET_OUT TO 16
|
|
EQU COL$MET_OUT_Z1 TO 17
|
|
EQU COL$MET_OUT_Z2 TO 18
|
|
EQU COL$MET_TWSIG TO 19
|
|
EQU COL$MET_TWSIG_Z1 TO 20
|
|
EQU COL$MET_TWSIG_Z2 TO 21
|
|
|
|
EQU COMMA$ to ','
|
|
|
|
AutoDisplayErrors = FALSE$ ; // Set this to True$ when debugging so all errors will automatically display.
|
|
|
|
Declare subroutine SRP_Stopwatch, Error_Services, obj_Tables, Metrology_Services, obj_RDS_Test, SRP_JSON, Logging_Services
|
|
Declare subroutine RTI_Set_Debugger, Database_Services, Btree.Extract, Extract_SI_Keys, Obj_WO_Mat, Obj_WO_Mat_Log
|
|
Declare subroutine Dialog_Box, Obj_Notes, RList, Set_Status, Errmsg, Obj_React_Status , Reactor_Services
|
|
Declare subroutine Rds_Services, Obj_Post_Log, Mona_Services
|
|
Declare function SRP_Sort_Array, Metrology_Services, obj_RDS_Test, obj_Test_Point_Map, Database_Services
|
|
Declare function Work_Order_Services, SRP_JSON, Logging_Services, Environment_Services, SRP_Trim, Error_Services
|
|
Declare function Memberof, Obj_WO_Mat, Obj_WO_Mat_Log, SRP_Array, DateTime, Dialog_Box, obj_Prod_Spec
|
|
Declare function RDS_Services, RTI_DistinctList, GetTickCount, Clean_Insp_Services, WO_Mat_QA_Services
|
|
Declare function PSN_Services, Rds_Layer_Services, SRP_Rotate_Array, Qa_Services, SRP_Date, SRP_Time, SRP_Datetime
|
|
Declare function Reactor_Services, Signature_Services, obj_rds, Test_Run_Services, Return_To_Fab_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] : ' Ctrl Performance Log.csv'
|
|
Headers = 'Logging DTM':@FM:'Ctrl':@FM:'Load/Calculate Time'
|
|
objCtrlLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, COMMA$, Headers, '', False$, False$)
|
|
LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM
|
|
|
|
IsProd = Environment_Services('IsProd')
|
|
If IsProd EQ True$ then
|
|
MonaResource = 'GRP_OPENINSIGHT_MES_OP_FE_RDSSERVICES'
|
|
end else
|
|
MonaResource = 'GRP_OPENINSIGHT_MES_OP_FE_DEV_RDSSERVICES'
|
|
end
|
|
|
|
GoToService else
|
|
Error_Services('Set', Service : ' is not a valid service request within the ' : ServiceModule : ' services module.')
|
|
end
|
|
|
|
Return Response else ''
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Service Parameter Options
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
Options BOOLEAN = True$, False$
|
|
Options STAGES = 'PRE', 'FWI', 'LWI', 'QA', 'LOAD', 'UNLOAD'
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Services
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// GetCurrentStage
|
|
//
|
|
// RDSNo. - [Required]
|
|
//
|
|
// Returns the current stage of a lot. Replaces CURR_STAGE calculated column.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service GetCurrentStage(RDSNo)
|
|
|
|
If RDSNo NE '' then
|
|
RDSCheck = Xlate('RDS', RDSNo, '', 'X', '')
|
|
If RDSCheck NE '' then
|
|
CurrStage = ''
|
|
WOMatKey = Xlate('RDS', RDSNo, 'WO_MAT_KEY', 'X')
|
|
SigProfile = Signature_Services('GetSigProfile', WOMatKey, FALSE$, RDSNo)
|
|
Stages = SigProfile<1>
|
|
Signatures = SigProfile<2>
|
|
SigCount = DCount(Signatures, @VM)
|
|
StageCount = DCount(Stages, @VM)
|
|
Swap @VM with @FM in Stages
|
|
Swap @VM with @FM in Signatures
|
|
For I = 1 to StageCount
|
|
If Signatures<I> EQ '' then
|
|
CurrStage = Stages<I>
|
|
end
|
|
Until Signatures<I> EQ ''
|
|
Next I
|
|
|
|
If CurrStage EQ '' then CurrStage = 'COMP'
|
|
Response = CurrStage
|
|
end else
|
|
ErrorMessage = 'Invalid RDSNo.'
|
|
Error_Services('Add', ErrorMessage)
|
|
end
|
|
end else
|
|
ErrorMessage = 'This service requires an RDSNo to be passed in.'
|
|
Error_Services('Add', ErrorMessage)
|
|
end
|
|
|
|
End Service
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// GetComments
|
|
//
|
|
// RDSNo. - [Required]
|
|
//
|
|
// Returns a delimited array of all COMMENT, COMMENT_USER, and COMMENT_DATE OR
|
|
// EPP_COMMENT, EPP_COMMENT_USER, and EPP_COMMENT_DATE associated with an RDS record. Note: Dates are returned Oconv'd.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service GetComments(RDSNo)
|
|
|
|
CommentArray = ''
|
|
RDSRow = Database_Services('ReadDataRow', 'RDS', RDSNo)
|
|
|
|
CommentDates = Oconv(RDSRow<RDS_COMMENT_DATE$>, 'DT')
|
|
CommentUsers = RDSRow<RDS_COMMENT_USER$>
|
|
Comments = RDSRow<RDS_COMMENT_NOTE$>
|
|
|
|
CommentList = CommentDates :@FM: CommentUsers :@FM: Comments
|
|
CommentArray = SRP_Rotate_Array(CommentList)
|
|
Response = CommentArray
|
|
|
|
End Service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// AddComment
|
|
//
|
|
// RDSNo. - [Required]
|
|
// Comment - [Required]
|
|
// UsernameOpt - [Optional]
|
|
//
|
|
// Adds a COMMENT, COMMENT_USER, and COMMENT_DATE OR an EPP_COMMENT, EPP_COMMENT_USER, and EPP_COMMENT_DATE
|
|
// to an RDS record.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service AddComment(RDSNo, Comment, UsernameOpt)
|
|
StartTick = GetTickCount()
|
|
MetricName = 'AddComment'
|
|
|
|
RDSRow = Database_Services('ReadDataRow', 'RDS', RDSNo)
|
|
Username = @USER4
|
|
If Assigned(UsernameOpt) then
|
|
If UsernameOpt NE '' then
|
|
Username = UsernameOpt
|
|
end
|
|
end
|
|
CommentTime = Datetime()
|
|
|
|
Fields = RDS_COMMENT_DATE$:@VM ; Values = CommentTime:@VM
|
|
Fields := RDS_COMMENT_USER$:@VM ; Values := UserName:@VM
|
|
Fields := RDS_COMMENT_NOTE$ ; Values := Comment
|
|
|
|
|
|
oblParms = 'RDS':@RM
|
|
oblParms := RDSNo:@RM
|
|
oblParms := Fields:@RM
|
|
oblParms := Values:@RM
|
|
oblParms := "TOP" :@VM: "TOP" :@VM: "TOP"
|
|
obj_Post_Log('Create',oblParms)
|
|
|
|
EndTick = GetTickCount()
|
|
Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick)
|
|
End Service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// GetFinalQAStatus
|
|
//
|
|
// RDSNo. - [Required]
|
|
//
|
|
// Returns the boolean value of the Final QA status of a given RDS record. Returns True$ if
|
|
// the Final QA step is signed and False$ if it is not signed.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service GetFinalQAStatus(RDSNo)
|
|
|
|
FinalQA = False$
|
|
RDSRow = Database_Services('ReadDataRow', 'RDS', RDSNo)
|
|
WorkOrderNo = RDSRow<RDS_WO$>
|
|
WorkOrderRow = Database_Services('ReadDataRow', 'WO_LOG', WorkOrderNo)
|
|
ReactType = WorkOrderRow<WO_LOG_REACT_TYPE$>
|
|
// Check to see if the Final QA signature is in place.
|
|
If ReactType EQ 'EPP' then
|
|
CassetteNos = RDSRow<RDS_OUT_CASS_NO$>
|
|
For Each CassetteNo in CassetteNos using @VM
|
|
WMOutKey = RDSRow<RDS_WO_STEP_KEY$> : '*' : CassetteNo
|
|
WMOutRow = Database_Services('ReadDataRow', 'WM_OUT', WMOutKey)
|
|
If WMOutRow<WM_OUT_SUP_VER_SIG$> NE '' then
|
|
FinalQA = true$
|
|
end
|
|
Until FinalQA
|
|
Next CassetteNo
|
|
end else
|
|
If RDSRow<RDS_SUP_VER_SIG$> NE '' then
|
|
FinalQA = True$
|
|
end
|
|
end
|
|
Response = FinalQA
|
|
|
|
End Service
|
|
|
|
Service IsPackaged(RDSNo, RDSType)
|
|
|
|
isPackaged = False$
|
|
//ReactType = XLATE('RDS', RDSNo, 'REACTOR_TYPE', '')
|
|
// Check to see if the Final QA signature is in place.
|
|
If RDSType EQ 'EPP' then
|
|
Convert '.' TO '*' in RDSNo
|
|
WMOutKey = Xlate('WM_OUT', RDSNo, 'WO_MAT_KEY', 'X')
|
|
WoMatAction = Database_Services('ReadDataColumn', 'WO_MAT',WMOutKey, 8)
|
|
isPackaged = Index(WoMatAction, 'PACK', 1) > 0
|
|
end else if RDSType EQ 'GAN' then
|
|
Convert '.' TO '*' in RDSNo
|
|
WoMatAction = Database_Services('ReadDataColumn', 'WO_MAT',RDSNo, 8)
|
|
isPackaged = Index(WoMatAction, 'PACK', 1) > 0
|
|
end else
|
|
RDSRow = Database_Services('ReadDataRow', 'RDS', RDSNo)
|
|
WoNo = RDSRow<RDS_WO$>
|
|
WoCassNo = RDSRow<RDS_CASS_NO$>
|
|
WoMatKey = WoNo:'*':WoCassNo
|
|
WoMatAction = Database_Services('ReadDataColumn', 'WO_MAT',WoMatKey, 8)
|
|
isPackaged = Index(WoMatAction, 'PACK', 1) > 0
|
|
end
|
|
Response = isPackaged
|
|
|
|
End Service
|
|
|
|
Service GetHoldStatus(RDSNo, RDSType)
|
|
Response = False$
|
|
If Error_Services('NoError') then
|
|
IF RDSType EQ 'EPP' then
|
|
Convert '.' to '*' in RDSNo
|
|
WOMatKey = Xlate('WM_OUT', RDSNo, 'WO_MAT_KEY', 'X')
|
|
end else iF RDSType EQ 'GAN' then
|
|
Convert '.' to '*' in RDSNo
|
|
WOMatKey = RDSNo
|
|
end else
|
|
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo)
|
|
WONo = RDSRec<RDS_WO$>
|
|
CassNo = RDSRec<RDS_CASS_NO$>
|
|
WOMatKey = WONo:'*':CassNo
|
|
end
|
|
|
|
If WOMatKey NE '' then
|
|
WOMatCurrStatus = obj_WO_Mat('CurrStatus', WOMatKey)
|
|
If WOMatCurrStatus EQ 'HOLD' then Response = True$
|
|
end else
|
|
ErrorMessage = 'Null work order or cassette number in ':Service' for RDS ':RDSNo:'.'
|
|
Error_Services('Add', ErrorMessage)
|
|
end
|
|
end
|
|
|
|
End Service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// GetRDSList
|
|
//
|
|
// WorkOrderNo. - [Required]
|
|
// KeysOnly. - [Optional]
|
|
//
|
|
// Returns a list of RDS records within a supplied Work Order.
|
|
// Rows are @FM delimted while columns are @VM delimited.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service GetRDSList(WorkOrderNo, KeysOnly=BOOLEAN)
|
|
|
|
RDSList = ''
|
|
|
|
If WorkOrderNo NE '' then
|
|
rv = Set_Status(0)
|
|
RDSKeys = ''
|
|
extract_si_keys('RDS', 'WO', WorkOrderNo, RDSKeys)
|
|
StatusCode = ''
|
|
If Get_Status(StatusCode) then
|
|
Error_Services('Add', 'Error calling Extract_SI_Keys in the ' : Service : ' service. StatusCode: ' : StatusCode)
|
|
end else
|
|
NumRDS = DCount(RDSKeys, @VM)
|
|
@DICT = Database_Services('GetTableHandle', 'DICT.' : 'RDS')
|
|
If Error_Services('NoError') then
|
|
For Each @ID in RDSKeys using @VM
|
|
@RECORD = Database_Services('ReadDataRow', 'RDS', @ID)
|
|
If Error_Services('NoError') then
|
|
RDSDet = {ABBREV_OR_CO_NAME} : @VM
|
|
RDSDet := {WO} : @VM
|
|
RDSDet := {WO_STEP} : @VM
|
|
RDSDet := {RUN_ORDER_NUM} : @VM
|
|
RDSDet := @ID : @VM
|
|
RDSDet := {REACTOR} : @VM
|
|
RDSDet := {REACT_IDLE_TIME} : @VM
|
|
RDSDet := {HGCV_TEST} : @VM
|
|
RDSDet := {DATE_IN} : @VM
|
|
RDSDet := {TIME_IN} : @VM
|
|
RDSDet := {DATE_OUT} : @VM
|
|
RDSDet := {TIME_OUT} : @VM
|
|
RDSDet := {ELAPSED_HOURS} : @VM
|
|
RDSDet := {PO} : @VM
|
|
RDSDet := {PART_NUM} : @VM
|
|
RDSDet := {LOT_NUM} : @VM
|
|
RDSDet := {COMB_STATUS} : @VM
|
|
RDSDet := {NCR_SUM} : @VM
|
|
RDSDet := {HOLD_STATUS} : @VM
|
|
RDSDet := {SUPPL_INST}
|
|
If KeysOnly EQ True$ then
|
|
RDSList = Insert(RDSList, -1, 0, 0, @ID)
|
|
end else
|
|
RDSList = Insert(RDSList, -1, 0, 0, RDSDet)
|
|
end
|
|
end else
|
|
Error_Services('Add', 'Error reading RDS Record ' : @ID : ' in the ' : Service : ' service.')
|
|
end
|
|
Next @ID
|
|
end else
|
|
Error_Services('Add', 'Error opening RDS dictionary in the ' : Service : ' service.')
|
|
end
|
|
end
|
|
end else
|
|
Error_Services('Add', 'WorkOrderNo argument was missing from the ' : Service : ' service.')
|
|
end
|
|
|
|
Response = RDSList
|
|
|
|
end service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// GetRDSData
|
|
//
|
|
// WorkOrderNo. - [Required]
|
|
// KeysOnly. - [Optional]
|
|
//
|
|
// Returns a list of RDS records within a supplied Work Order.
|
|
// Rows are @FM delimted while columns are @VM delimited.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service GetRDSData(WorkOrderNo, Columns, ShowGasGauge, RDSOverrideList)
|
|
|
|
RDSList = ''
|
|
|
|
If ( (WorkOrderNo NE '') or (RDSOverrideList NE '') ) then
|
|
If ShowGasGauge NE True$ then ShowGasGauge = False$
|
|
rv = Set_Status(0)
|
|
RDSKeys = ''
|
|
|
|
If WorkOrderNo NE '' then
|
|
Extract_Si_Keys('RDS', 'WO', WorkOrderNo, RDSKeys)
|
|
end else
|
|
Swap @FM with @VM in RDSOverrideList
|
|
RDSKeys = RDSOverrideList
|
|
end
|
|
|
|
StatusCode = ''
|
|
If Get_Status(StatusCode) then
|
|
Error_Services('Add', 'Error calling Extract_SI_Keys in the ' : Service : ' service. StatusCode: ' : StatusCode)
|
|
end else
|
|
If RDSKeys NE '' then
|
|
NumRDS = DCount(RDSKeys, @VM)
|
|
|
|
If ShowGasGauge then
|
|
Def = ""
|
|
Def<MCAPTION$> = "Loading Run Data Sheets..."
|
|
Def<MTYPE$> = "G"
|
|
Def<MEXTENT$> = NumRDS
|
|
Def<MTEXTWIDTH$> = 400
|
|
Def<MCOL$> = -2 ;* message h-pos in pixels, or -2 (center screen, the default), -1 (center parent)
|
|
Def<MROW$> = -2 ;* message v-pos in pixels
|
|
MsgUp = Msg(@Window, Def)
|
|
end
|
|
|
|
@DICT = Database_Services('GetTableHandle', 'DICT.' : 'RDS')
|
|
If Error_Services('NoError') then
|
|
For each @ID in RDSKeys using @VM setting fPos
|
|
@RECORD = Database_Services('ReadDataRow', 'RDS', @ID)
|
|
If Error_Services('NoError') then
|
|
For each Column in Columns using @VM setting vPos
|
|
LoadTimeStart = GetTickCount()
|
|
Begin Case
|
|
Case Column EQ 'HOLD_STATUS'
|
|
HoldStatus = Calculate(Column)
|
|
If HoldStatus EQ 'No' then HoldStatus = 'Off Hold'
|
|
RDSList<fPos, vPos> = HoldStatus
|
|
Case Column EQ 'ELAPSED_HOURS'
|
|
Val = OConv(Calculate(Column), 'MD2L')
|
|
Hours = Field(Val, '.', 1)
|
|
Minutes = '0.':Field(Val, '.', 2)
|
|
Minutes = 60 * Minutes
|
|
Minutes = Minutes[1, 'F.']
|
|
Minutes = Fmt(Minutes, 'R(0)#2')
|
|
RDSList<fPos, vPos> = Hours:':':Minutes
|
|
Case Otherwise$
|
|
RDSList<fPos, vPos> = Calculate(Column)
|
|
|
|
End Case
|
|
Next Column
|
|
end else
|
|
Error_Services('Add', 'Error reading RDS Record ' : @ID : ' in the ' : Service : ' service.')
|
|
end
|
|
* update the gauge
|
|
If ShowGasGauge then Msg(@Window, MsgUp, fPos, MSGINSTUPDATE$)
|
|
Next @ID
|
|
end else
|
|
Error_Services('Add', 'Error opening RDS dictionary in the ' : Service : ' service.')
|
|
end
|
|
If ShowGasGauge then Msg(@Window, MsgUp) ;* take down the gauge
|
|
end
|
|
end
|
|
end else
|
|
Error_Services('Add', 'WorkOrderNo or RDSOverrideList argument was missing from the ' : Service : ' service.')
|
|
end
|
|
//Sort based on cassette number
|
|
Locate 'RUN_ORDER_NUM' in Columns using @VM setting ColNoCassNo else ColNoCassNo = 1
|
|
RDSList = SRP_Sort_Array(RDSList, 'AR' : ColNoCassNo, True$, @FM)
|
|
Response = RDSList
|
|
|
|
end service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// SetSupplement
|
|
//
|
|
// SupplementList. - [Required]
|
|
// Username. - [Optional]
|
|
//
|
|
// Accepts a list with the following structure:
|
|
// <1> Row Text
|
|
// <1,1> Column Text RDSNo
|
|
// <1,2> Column Text Supplement Instructions
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service SetSupplement(SupplementList, Username)
|
|
RDSNotificationListAdd = ''
|
|
RDSNotificationListRemove = ''
|
|
Action = ''
|
|
If SupplementList NE '' then
|
|
@DICT = Database_Services('GetTableHandle', 'DICT.' : 'RDS')
|
|
If Error_Services('NoError') then
|
|
For Each Row in SupplementList using @FM
|
|
ChangeDetected = False$
|
|
@ID = Row<1,1>
|
|
SupplementInst = Row<1,2>
|
|
@RECORD = Database_Services('ReadDataRow', 'RDS', @ID)
|
|
If Error_Services('NoError') then
|
|
If SupplementInst NE '' then
|
|
If SupplementInst NE {SUPPL_INST} then
|
|
// Supplement information has been added or updated.
|
|
ChangeDetected = True$
|
|
Action = 'Add'
|
|
{SUPPLEMENT} = True$
|
|
{SUPPL_INST} = SupplementInst
|
|
{SUPPL_ENTRY_DATE} = date()
|
|
{SUPPL_ENTRY_TIME} = time()
|
|
If Username NE '' then
|
|
{SUPPL_ENTRY_ID} = Username
|
|
end else
|
|
{SUPPL_ENTRY_ID} = @User4
|
|
end
|
|
end
|
|
end else
|
|
If SupplementInst NE {SUPPL_INST} then
|
|
// Supplement information has been removed.
|
|
ChangeDetected = True$
|
|
Action = 'Remove'
|
|
{SUPPLEMENT} = False$
|
|
{SUPPL_INST} = ''
|
|
{SUPPL_ENTRY_DATE} = ''
|
|
{SUPPL_ENTRY_TIME} = ''
|
|
{SUPPL_ENTRY_ID} = ''
|
|
end
|
|
end
|
|
If ChangeDetected And Action EQ 'Add' then
|
|
Database_Services('WriteDataRow', 'RDS', @ID, @RECORD)
|
|
RDSNotificationListAdd<-1> = @ID
|
|
end
|
|
If ChangeDetected And Action EQ 'Remove' then
|
|
Database_Services('WriteDataRow', 'RDS', @ID, @RECORD)
|
|
RDSNotificationListRemove<-1> = @ID
|
|
end
|
|
end else
|
|
Error_Services('Add', 'Error reading RDS Record ' : @ID : ' in the ' : Service : ' service.')
|
|
end
|
|
Next Row
|
|
end else
|
|
Error_Services('Add', 'Error opening RDS dictionary in the ' : Service : ' service.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'SupplementList argument was missing from the ' : Service : ' service.')
|
|
end
|
|
|
|
* //Now send an email notification
|
|
IF RDSNotificationListAdd NE '' then
|
|
Instructions = XLATE('RDS', RDSNotificationListAdd<1>, RDS_SUPPL_INST$, 'X')
|
|
PSN = XLATE('RDS', RDSNotificationListAdd<1>, RDS_PROD_SPEC_ID$, 'X')
|
|
WoNo = XLATE('RDS', RDSNotificationListAdd<1>, RDS_WO$, 'X')
|
|
ReactorNo = XLATE('RDS', RDSNotificationListAdd<1>, RDS_REACTOR$, 'X');
|
|
|
|
Message = 'This Supplement was created or updated by ':oconv( @user4, '[XLATE_CONV,LSL_USERS*FIRST_LAST]' ):' on ':OCONV( DATE(), 'D2/' ):' at ':OCONV( TIME(), 'MTH' ):'.' : CRLF$
|
|
Message := 'WO# : ' : WoNo : CRLF$
|
|
Message := 'PSN : ' : PSN : CRLF$
|
|
Message := 'Reactor No : ' : ReactorNo : CRLF$
|
|
//Message := 'Instructions : ' : Instructions
|
|
Message := CRLF$
|
|
Message := 'RDS #s : ' : CRLF$
|
|
for each RDSNo in RDSNotificationListAdd using @FM
|
|
Message := RDSNo : ' - ': XLATE('RDS', RDSNo, RDS_SUPPL_INST$, 'X') :CRLF$
|
|
Next RDSNo
|
|
|
|
Recipients = XLATE('NOTIFICATION','SUPPLEMENTS',NOTIFICATION_USER_ID$,'X')
|
|
SendFrom = 'System'
|
|
Subject = 'New or Updated Supplement Created for WO# ': WoNo
|
|
AttachWindow = ''
|
|
AttachKey = ''
|
|
SendToGroup = ''
|
|
|
|
Parms = Recipients:@RM:SendFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup
|
|
obj_Notes('Create',Parms)
|
|
end
|
|
IF RDSNotificationListRemove NE '' then
|
|
|
|
Instructions = XLATE('RDS', RDSNotificationListRemove<1>, RDS_SUPPL_INST$, 'X')
|
|
PSN = XLATE('RDS', RDSNotificationListRemove<1>, RDS_PROD_SPEC_ID$, 'X')
|
|
WoNo = XLATE('RDS', RDSNotificationListRemove<1>, RDS_WO$, 'X')
|
|
ReactorNo = XLATE('RDS', RDSNotificationListRemove<1>, RDS_REACTOR$, 'X');
|
|
|
|
Message = 'This Supplement was removed by ':oconv( @user4, '[XLATE_CONV,LSL_USERS*FIRST_LAST]' ):' on ':OCONV( DATE(), 'D2/' ):' at ':OCONV( TIME(), 'MTH' ):'.' : CRLF$
|
|
Message := 'WO# : ' : WoNo : CRLF$
|
|
Message := 'PSN : ' : PSN : CRLF$
|
|
Message := 'Reactor No : ' : ReactorNo : CRLF$
|
|
//Message := 'Instructions : ' : Instructions
|
|
Message := CRLF$
|
|
Message := 'RDS #s : ' : CRLF$
|
|
for each RDSNo in RDSNotificationListRemove using @FM
|
|
Message := RDSNo :CRLF$
|
|
Next RDSNo
|
|
|
|
Recipients = XLATE('NOTIFICATION','SUPPLEMENTS',NOTIFICATION_USER_ID$,'X')
|
|
SendFrom = 'System'
|
|
Subject = 'Supplement Removed for WO# ': WoNo
|
|
AttachWindow = ''
|
|
AttachKey = ''
|
|
SendToGroup = ''
|
|
|
|
Parms = Recipients:@RM:SendFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup
|
|
obj_Notes('Create',Parms)
|
|
end
|
|
end service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// IsEpiPro
|
|
//
|
|
// RDSNo. - [Required]
|
|
//
|
|
// Returns True$ if RDS is an EpiPro run, False$ otherwise.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service IsEpiPro(RDSNo)
|
|
|
|
IsEpiPro = False$
|
|
ReactorKey = Xlate('RDS', RDSNo, 'REACTOR', 'X')
|
|
ReactorType = Xlate('REACTOR', ReactorKey, 'REACT_TYPE', 'X')
|
|
If ReactorType _EQC 'EPP' or ReactorType _EQC 'P' or ReactorType _EQC 'EpiPro' then
|
|
IsEpiPro = True$
|
|
end
|
|
Response = IsEpiPro
|
|
|
|
End Service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// IsEpiProTestRun
|
|
//
|
|
// RDSNo. - [Required]
|
|
//
|
|
// Returns True$ if RDS is an EpiPro test run, False$ otherwise.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service IsEpiProTestRun(RDSNo)
|
|
|
|
TestRun = True$
|
|
If RDSNo NE '' then
|
|
EpiPro = RDS_Services('IsEpiPro', RDSNo)
|
|
If EpiPro then
|
|
WaferChars = Xlate('RDS', RDSNo, 'WAFER_CHAR', 'X')
|
|
PocketChars = Xlate('RDS', RDSNo, 'POCKET_CHAR', 'X')
|
|
For each WaferChar in WaferChars using @VM setting vPos
|
|
If WaferChar EQ 'PROD' then
|
|
PocketChar = PocketChars<0, vPos>
|
|
If PocketChar NE 'TEST' then TestRun = False$
|
|
end
|
|
Until TestRun EQ False$
|
|
Next WaferChar
|
|
end else
|
|
Error_Services('Add', 'Error in ':Service:' service. This service only supports EpiPro runs.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'Error in ':Service:' service. Null RDSNo passed in.')
|
|
end
|
|
Response = TestRun
|
|
|
|
end service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// IsValidRDS
|
|
//
|
|
// Params - RDSNo, RDSType
|
|
// RDSNo can be acutal RDS or WMI for EPP (WO_NO.1.CASS_NO, e.g. 169515.1.20) or WO_MAT for GAN (WO_NO.CASS_NO, e.g. 169410.6)
|
|
// Returns True$ if RDS is valid
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service IsValidRDS(RDSNo, RDSType)
|
|
IsValid = False$
|
|
FirstChar = RDSNo[1,1]
|
|
*debug
|
|
Begin Case
|
|
|
|
Case RDSType EQ 'SIC'
|
|
If Num(RDSNo) then
|
|
If XLate('RDS', RDSNo, 'SEQ', 'X') NE '' then
|
|
IsValid = True$
|
|
end
|
|
end
|
|
|
|
Case RDSType EQ 'EPP'
|
|
CONVERT '.' TO '*' IN RDSNo
|
|
If XLATE('WM_OUT',RDSNo,'SLOT_NO','X') NE '' then
|
|
IsValid = True$
|
|
end
|
|
|
|
Case RDSTYpe EQ 'GAN'
|
|
CONVERT '.' TO '*' IN RDSNo
|
|
If XLATE('WO_MAT', RDSNo, 'RDS_NO', 'X') NE '' then
|
|
IsValid = True$
|
|
end
|
|
End Case
|
|
|
|
Response = IsValid
|
|
end service
|
|
|
|
Service IsValidSubLot(RDSNo, RDSType, SupplierLot)
|
|
IsValid = False$
|
|
rec = ''
|
|
*debug
|
|
Begin Case
|
|
|
|
Case RDSType EQ 'SIC'
|
|
compareLot = XLATE('RDS', RDSNo, RDS_LOT_NUM$, 'X')
|
|
if compareLot EQ SupplierLot then
|
|
IsValid = True$
|
|
end
|
|
|
|
Case RDSType EQ 'EPP'
|
|
CONVERT '.' TO '*' IN RDSNo
|
|
compareLot = XLATE('WM_IN', RDSNo, 'LOT_NO', 'X')
|
|
if compareLot EQ SupplierLot then
|
|
IsValid = True$
|
|
end
|
|
|
|
Case RDSType EQ 'GAN'
|
|
CONVERT '.' TO '*' IN RDSNo
|
|
compareLot = XLATE('WO_MAT', RDSNo, WO_MAT_LOT_NO$, 'X')
|
|
if compareLot EQ SupplierLot then
|
|
IsValid = True$
|
|
end
|
|
|
|
End Case
|
|
|
|
Response = IsValid
|
|
end service
|
|
|
|
Service GetRDSRunHistoryByReactorAndWO(ReactorNo, WO)
|
|
StartTick = GetTickCount()
|
|
MetricName = 'GetRDSRunHistoryByReactorAndWO'
|
|
|
|
table = "RDS"
|
|
ErrorMessage = ''
|
|
RDSRecords = ''
|
|
RDSSortedByAssignmentDTM = ''
|
|
Open "DICT ":table To @DICT Else
|
|
ErrorMessage = 'Error opening RDS dictionary'
|
|
End
|
|
If ErrorMessage EQ '' then
|
|
srch_strng = "WO":@VM:WO:@FM:"REACTOR":@VM:ReactorNo:@FM
|
|
option = ""
|
|
flag = ""
|
|
Btree.Extract(srch_strng, table, @DICT, RDSRecords, option, flag)
|
|
end
|
|
RDSRecordsWithPreEpiSig = ''
|
|
for each RDSKey in RDSRecords using @VM setting RDSPos
|
|
ThisRDSRec = Database_Services('ReadDataRow', 'RDS', RDSKey, True$, 0, False$)
|
|
ThisRDSPreEpiDT = ThisRDSRec<RDS_PRE_EPI_SIG_DATE$>
|
|
ThisRDSPreEpiTM = ThisRDSRec<RDS_PRE_EPI_SIG_TIME$>
|
|
ThisRDSPreEpiDTM = SRP_Datetime('Combine', ThisRDSPreEpiDT, ThisRDSPreEpiTM)
|
|
RDSRecordsWithPreEpiSig<1, RDSPos> = RDSKey
|
|
RDSRecordsWithPreEpiSig<2, RDSPos> = ThisRDSPreEpiDTM
|
|
Next RDSKey
|
|
RDSSortedByAssignmentDTM = SRP_Sort_Array(RDSRecordsWithPreEpiSig, 'AN2', 0)
|
|
FinalRDSSortedByAssignmentDTM = ''
|
|
|
|
for each RDS in RDSSortedByAssignmentDTM<1> using @VM setting SortedRDSPos
|
|
ThisRDSDtm = RDSSortedByAssignmentDTM<2, SortedRDSPos>
|
|
if ThisRDSDtm GT 0 then
|
|
FinalRDSSortedByAssignmentDTM<1, -1> = RDS
|
|
FinalRDSSortedByAssignmentDTM<2, -1> = OConv(ThisRDSDtm, 'DT')
|
|
end
|
|
Next RDS
|
|
Response = FinalRDSSortedByAssignmentDTM<1>
|
|
|
|
EndTick = GetTickCount()
|
|
Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick)
|
|
end service
|
|
|
|
|
|
Service IsTWLoggingReqd(RDSNo)
|
|
StartTick = GetTickCount()
|
|
MetricName = 'IsTWLoggingReqd'
|
|
|
|
IsTWReqd = False$
|
|
ExistingTWRuns = Test_Run_Services('GetTestRunKeysByRDS', RDSNo)
|
|
If ExistingTWRuns EQ '' then
|
|
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo)
|
|
WONo = RDSRec<RDS_WO$>
|
|
ReactNo = RDSRec<RDS_REACTOR$>
|
|
ReactorType = Database_Services('ReadDataColumn', 'REACTOR', ReactNo, REACTOR_REACT_TYPE$, True$, 0, False$)
|
|
ThisReactorRunOrder = 0
|
|
ReactRDSNos = RDS_Services('GetRDSRunHistoryByReactorAndWO', ReactNo, WONo)
|
|
LOCATE RDSNo IN ReactRDSNos USING @VM SETTING ThisReactorRunOrder ELSE Return
|
|
PSNo = RDSRec<RDS_PROD_SPEC_ID$>
|
|
PSRec = Database_Services('ReadDataRow', 'PROD_SPEC', PSNo)
|
|
PRSLayerKeys = PSRec<PROD_SPEC_PRS_LAYER_KEY$>
|
|
for each PRSLayerKey in PRSLayerKeys using @VM
|
|
PRSPropKeys = Database_Services('ReadDataColumn', 'PRS_LAYER', PRSLayerKey, 5)
|
|
for each PRSPropKey in PRSPropKeys using @VM
|
|
PRSPropRec = Database_Services('ReadDataRow', 'PRS_PROP', PRSPropKey)
|
|
WaferType = PRSPropRec<6>
|
|
TestType = Field(PRSPropKey, '*', 3)
|
|
Layer = Field(PRSPropKey, '*', 2)
|
|
MeasureFreq = PRSPropRec<PRS_PROP_FREQ$>
|
|
Start = PRSPropRec<PRS_PROP_MET_START$>
|
|
If WaferType NE 'Product' AND WaferType NE 'Prod' AND WaferType NE '' then
|
|
BEGIN CASE
|
|
CASE MeasureFreq = 'F' AND ThisReactorRunOrder = 1 ; IsTWReqd = 1
|
|
CASE ThisReactorRunOrder = Start ; IsTWReqd = 1
|
|
CASE NUM(MeasureFreq)
|
|
Begin Case
|
|
Case ReactorType EQ 'HTR'
|
|
//Logging required on lot the data gets logged to
|
|
IF MOD(ThisReactorRunOrder,MeasureFreq) - Start = 0 THEN
|
|
IsTWReqd = True$
|
|
END
|
|
Case ReactorType EQ 'ASM'
|
|
//Logging required on lot the data gets logged to
|
|
IF MOD(ThisReactorRunOrder,MeasureFreq) - Start = 0 THEN
|
|
IsTWReqd = True$
|
|
END
|
|
Case ReactorType EQ 'ASM+'
|
|
//Logging required on lot prior to the one the data gets logged to.
|
|
IF MOD(ThisReactorRunOrder,MeasureFreq) = 0 THEN
|
|
IsTWReqd = True$
|
|
END
|
|
End Case
|
|
|
|
END CASE
|
|
end
|
|
Until IsTWReqd EQ True$
|
|
Next PRSPropKey
|
|
Until IsTWReqd EQ True$
|
|
Next PRSLayerKey
|
|
end else
|
|
IsTWReqd = False$
|
|
end
|
|
//The code below will be removed upon final production usage.
|
|
TWTrackingSystemActive = Database_Services('ReadDataColumn', 'APP_INFO', 'NEW_TW_SYSTEM_ACTIVE_SWITCH', 1, True$, 0, False$)
|
|
If TWTrackingSystemActive EQ False$ then
|
|
IsTWReqd = False$
|
|
end
|
|
Response = IsTWReqd
|
|
|
|
EndTick = GetTickCount()
|
|
Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick)
|
|
end service
|
|
|
|
Service TestWaferRanAfterLoad(RDSNo)
|
|
TestWaferRanAfterLoad = False$
|
|
TestWaferKeys = Test_Run_Services('GetTestRunKeysByRDS', RDSNo)
|
|
for each Key in TestWaferKeys using @VM
|
|
TestWaferDtm = Xlate('TEST_RUN', Key, TEST_RUN_RUN_DTM$, 'X')
|
|
TestWaferDate = SRP_DateTime('Date', TestWaferDtm)
|
|
TestWaferTime = SRP_DateTime('Time', TestWaferDtm)
|
|
|
|
RdsDateIn = Xlate('RDS', RDSNo, RDS_DATE_IN$, 'X')
|
|
RdsTimeIn = Xlate('RDS', RDSNo, RDS_TIME_IN$, 'X')
|
|
|
|
TestWaferRanAfterLoad = TestWaferDate > RdsDateIn
|
|
If TestWaferRanAfterLoad EQ False$ then
|
|
TestWaferRanAfterLoad = (TestWaferDate EQ RdsDateIn) and TestWaferTime GT RdsTimeIn
|
|
end
|
|
Until TestWaferRanAfterLoad EQ True$
|
|
Next Key
|
|
|
|
Response = TestWaferRanAfterLoad
|
|
end service
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// VerifyEPPMetrology
|
|
//
|
|
// RDSNo. - [Required]
|
|
//
|
|
// Sets an error in Error_Services if there is an issue with the metrology data.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service VerifyEPPMetrology(RDSNo)
|
|
|
|
If RDSNo NE '' then
|
|
ErrorMsg = ''
|
|
// ActivateRecord allows for the use of the curly brace notation {}
|
|
Database_Services('ActivateRecord', 'RDS', RDSNo)
|
|
|
|
If {REACTOR_TYPE} EQ 'EPP' then
|
|
LayerList = ''
|
|
LayerList<COL$LSID> = {RDS_LS_ID}
|
|
LayerList<COL$RECIPE> = {LS_RECIPE}
|
|
LayerList<COL$RECIPE_NAME> = {LS_RECIPE_NAME}
|
|
LayerList<COL$PARAMS> = {LS_PARMS_COMP}
|
|
LayerList<COL$PARMS_OUT> = {PARAM_OUT_OF_SPEC}
|
|
LayerList<COL$BLANK_COL> = ''
|
|
LayerList<COL$MET_NO> = {MET_KEYS}
|
|
LayerList<COL$THICK_AVG> = {TTHICK_AVG_ALL}
|
|
LayerList<COL$RRHO_AVG> = {TRES_AVG_ALL}
|
|
LayerList<COL$MET_NO_Z1> = {MET_KEYS_Z1}
|
|
LayerList<COL$THICK_AVG_Z1> = {TTHICK_AVG_ALL_Z1}
|
|
LayerList<COL$RRHO_AVG_Z1> = {TRES_AVG_ALL_Z1}
|
|
LayerList<COL$MET_NO_Z2> = {MET_KEYS_Z2}
|
|
LayerList<COL$THICK_AVG_Z2> = {TTHICK_AVG_ALL_Z2}
|
|
LayerList<COL$RRHO_AVG_Z2> = {TRES_AVG_ALL_Z2}
|
|
LayerList<COL$MET_OUT> = {MET_OUT_OF_SPEC}
|
|
LayerList<COL$MET_OUT_Z1> = {MET_OUT_OF_SPEC_Z1}
|
|
LayerList<COL$MET_OUT_Z2> = {MET_OUT_OF_SPEC_Z2}
|
|
LayerList<COL$MET_TWSIG> = {MET_TW_SIGNED}
|
|
LayerList<COL$MET_TWSIG_Z1> = {MET_TW_SIGNED_Z1}
|
|
LayerList<COL$MET_TWSIG_Z2> = {MET_TW_SIGNED_Z2}
|
|
LayerList = SRP_Array('Rotate', LayerList, @FM, @VM)
|
|
|
|
// Improvement for EpiPro to not consider a metrology zone "Out of Spec" if all wafers from that zone
|
|
// have been scrapped (i.e. the wafers were either test wafers or were NCR'd)
|
|
|
|
! WM_OUT data is duplicated here in the RDS and cannot be trusted (i.e., it is not kept in sync properly).
|
|
! We should consider modifying this to look at WM_OUT for NCR keys associated with the pocket.
|
|
|
|
Pockets = {POCKET}
|
|
Zones = {ZONE}
|
|
PocketChars = {POCKET_CHAR}
|
|
OutNCRs = {OUT_NCR}
|
|
Zone1Scrapped = False$
|
|
Zone2Scrapped = False$
|
|
NumZone1Wfrs = 0
|
|
NumZone2Wfrs = 0
|
|
NumZone1Scraps = 0
|
|
NumZone2Scraps = 0
|
|
Pocket = ''
|
|
For each Pocket in Pockets using @VM setting vPos
|
|
Zone = Zones<0, vPos>
|
|
PocketChar = PocketChars<0, vPos>
|
|
OutNCR = OutNCRs<0, vPos>
|
|
Begin Case
|
|
Case Zone EQ 1
|
|
If PocketChar NE 'DUMMY' then NumZone1Wfrs += 1
|
|
Case Zone EQ 2
|
|
If PocketChar NE 'DUMMY' then NumZone2Wfrs += 1
|
|
End Case
|
|
Begin Case
|
|
Case ( ( (PocketChar EQ 'TEST') or (OutNCR NE '') ) and (Zone EQ 1) )
|
|
NumZone1Scraps += 1
|
|
Case ( ( (PocketChar EQ 'TEST') or (OutNCR NE '') ) and (Zone EQ 2) )
|
|
NumZone2Scraps += 1
|
|
End Case
|
|
Next Pocket
|
|
|
|
If NumZone1Wfrs EQ NumZone1Scraps then Zone1Scrapped = True$
|
|
If NumZone2Wfrs EQ NumZone2Scraps then Zone2Scrapped = True$
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
FOR I = 1 TO COUNT(LayerList,@FM) + (LayerList NE '')
|
|
|
|
* Layer Set Parameters
|
|
|
|
IF ICONV(LayerList<I,COL$PARMS_OUT>,'B') = 1 ELSE
|
|
IF ICONV(LayerList<I,COL$PARAMS>,'B') = 0 THEN
|
|
ErrorMsg = 'Recipe Parameters incomplete for RDS: ':RDSNo
|
|
END
|
|
END
|
|
|
|
* ASM Metrology
|
|
|
|
IF LayerList<I,COL$MET_NO> NE '' THEN
|
|
MetNo = LayerList<I,COL$MET_NO>
|
|
MetRec = XLATE('RDS_TEST',MetNo,'','X')
|
|
|
|
TWSigned = obj_RDS_Test('TWSignedOff',MetNo:@RM:MetRec)
|
|
TestComp = obj_RDS_Test('TestComplete',MetNo:@RM:MetRec)
|
|
OutOfSpec = obj_RDS_Test('OutOfSpec',MetNo:@RM:MetRec)
|
|
|
|
IF NOT(obj_RDS_Test('TestComplete',MetNo:@RM:MetRec)) THEN
|
|
ErrorMsg = 'Metrology not signed off for Met No: ':MetNo: 'for RDS: ':RDSNo
|
|
END ELSE
|
|
|
|
IF (obj_RDS_Test('OutOfSpec',MetNo:@RM:MetRec) = 1) THEN
|
|
ErrorMsg = 'Metrology ':MetNo:' is out of spec for RDS: ':RDSNo
|
|
|
|
END ELSE
|
|
IF LayerList<I,COL$THICK_AVG> = '' AND LayerList<I,COL$RRHO_AVG> = '' AND LayerList<I,COL$MET_NO> NE '' THEN
|
|
ErrorMsg = 'Metrology incomplete for RDS: ':RDSNo
|
|
END
|
|
END
|
|
END
|
|
end
|
|
|
|
* Zone 1 EpiPRO Metrology
|
|
// Update logic to not throw an error if wafers from a failed zone are NCR'd
|
|
IF LayerList<I,COL$MET_NO_Z1> NE '' THEN
|
|
MetNo = LayerList<I,COL$MET_NO_Z1>
|
|
MetRec = XLATE('RDS_TEST',MetNo,'','X')
|
|
|
|
TWSigned = obj_RDS_Test('TWSignedOff',MetNo:@RM:MetRec)
|
|
TestComp = obj_RDS_Test('TestComplete',MetNo:@RM:MetRec)
|
|
OutOfSpec = obj_RDS_Test('OutOfSpec',MetNo:@RM:MetRec)
|
|
|
|
IF NOT(obj_RDS_Test('TestComplete',MetNo:@RM:MetRec)) THEN
|
|
ErrorMsg = 'Zone 1 Metrology is Incomplete for RDS: ':RDSNo
|
|
END ELSE
|
|
|
|
IF ( (obj_RDS_Test('OutOfSpec',MetNo:@RM:MetRec) = 1) and (Zone1Scrapped EQ False$) ) THEN
|
|
ErrorMsg = 'Zone 1 Metrology is Out of Spec for RDS: ':RDSNo
|
|
END ELSE
|
|
IF LayerList<I,COL$THICK_AVG_Z1> = '' AND LayerList<I,COL$RRHO_AVG_Z1> = '' AND LayerList<I,COL$MET_NO_Z1> NE '' THEN
|
|
ErrorMsg = 'Zone 1 Metrology is Incomplete for RDS: ':RDSNo
|
|
END
|
|
//Added check for missing res avg data - JRO
|
|
/*IF LayerList<I,COL$THICK_AVG_Z1> NE '' AND LayerList<I,COL$RRHO_AVG_Z1> = '' AND LayerList<I,COL$MET_NO_Z1> NE '' THEN
|
|
If Error_Services('NoError') then Error_Services('Add', 'Zone 1 Metrology is missing Resistivity data for RDS: ':RDSNo)
|
|
END
|
|
*/
|
|
END
|
|
END
|
|
END
|
|
|
|
* Zone 2 EpiPRO Metrology
|
|
// Update logic to not throw an error if wafers from a failed zone are NCR'd
|
|
IF LayerList<I,COL$MET_NO_Z2> NE '' THEN
|
|
MetNo = LayerList<I,COL$MET_NO_Z2>
|
|
MetRec = XLATE('RDS_TEST',MetNo,'','X')
|
|
|
|
TWSigned = obj_RDS_Test('TWSignedOff',MetNo:@RM:MetRec)
|
|
TestComp = obj_RDS_Test('TestComplete',MetNo:@RM:MetRec)
|
|
OutOfSpec = obj_RDS_Test('OutOfSpec',MetNo:@RM:MetRec)
|
|
|
|
IF NOT(obj_RDS_Test('TestComplete',MetNo:@RM:MetRec)) THEN
|
|
ErrorMsg = 'Zone 2 Metrology is Incomplete for RDS: ':RDSNo
|
|
END ELSE
|
|
|
|
IF ( (obj_RDS_Test('OutOfSpec',MetNo:@RM:MetRec) = 1) and (Zone2Scrapped EQ False$) ) THEN
|
|
ErrorMsg = 'Zone 2 Metrology is Out of Spec for RDS: ':RDSNo
|
|
END ELSE
|
|
IF LayerList<I,COL$THICK_AVG_Z2> = '' AND LayerList<I,COL$RRHO_AVG_Z2> = '' AND LayerList<I,COL$MET_NO_Z2> NE '' THEN
|
|
ErrorMsg = 'Zone 2 Metrology is Incomplete for RDS: ':RDSNo
|
|
END
|
|
/*
|
|
//Added check for missing res avg data - JRO
|
|
IF LayerList<I,COL$THICK_AVG_Z2> NE '' AND LayerList<I,COL$RRHO_AVG_Z2> = '' AND LayerList<I,COL$MET_NO_Z2> NE '' THEN
|
|
If Error_Services('NoError') then Error_Services('Add', 'Zone 2 Metrology is missing Resistivity data for RDS: ':RDSNo)
|
|
END
|
|
*/
|
|
END
|
|
END
|
|
END
|
|
|
|
NEXT I
|
|
end else
|
|
ErrorMsg = 'Non-EpiPro RDS passed to RDS_Services(':Service:')'
|
|
end
|
|
end else
|
|
ErrorMsg = 'Null RDS value passed to RDS_Services(':Service:')'
|
|
end
|
|
If ErrorMsg NE '' then Error_Services('Add', ErrorMsg)
|
|
|
|
end service
|
|
|
|
|
|
Service RDSVerifyInst(RDSNo, Stage=STAGES)
|
|
|
|
Database_Services('ActivateRecord', 'RDS', RDSNo)
|
|
VerInst = ''
|
|
Begin Case
|
|
Case Stage EQ 'PRE'
|
|
VerInst = {PRE_INST}
|
|
Case Stage EQ 'FWI'
|
|
VerInst = {FWI_INST}
|
|
Case Stage EQ 'LWI'
|
|
VerInst = {LWI_INST}
|
|
Case Stage EQ 'QA'
|
|
VerInst = {QA_INST}
|
|
Case Stage EQ 'LOAD'
|
|
VerInst = {LOAD_INST}
|
|
Case Stage EQ 'UNLOAD'
|
|
VerInst = {UNLOAD_INST}
|
|
Case Stage EQ 'POST'
|
|
VerInst = {POST_INST}
|
|
End Case
|
|
Response = Dialog_Box('RDS_VER', @Window, VerInst)
|
|
Begin Case
|
|
Case Stage EQ 'PRE'
|
|
{PRE_INST_ACK} = Response
|
|
Case Stage EQ 'FWI'
|
|
{FWI_INST_ACK} = Response
|
|
Case Stage EQ 'LWI'
|
|
{LWI_INST_ACK} = Response
|
|
Case Stage EQ 'QA'
|
|
{QA_INST_ACK} = Response
|
|
Case Stage EQ 'LOAD'
|
|
{LOAD_INST_ACK} = Response
|
|
Case Stage EQ 'UNLOAD'
|
|
{UNLOAD_INST_ACK} = Response
|
|
Case Stage EQ 'POST'
|
|
{POST_INST_ACK} = Response
|
|
End Case
|
|
|
|
Database_Services('WriteDataRow', 'RDS', RDSNo, @Record, True$, False$, True$)
|
|
|
|
end service
|
|
|
|
|
|
Service CopyRDSLayerParameters(RDSNo)
|
|
StartTick = GetTickCount()
|
|
MetricName = 'CopyRDSLayerParameters'
|
|
|
|
If (RDSNo NE '') then
|
|
RunOrderNo = Xlate('RDS', RDSNo, 'RUN_ORDER_NUM', 'X')
|
|
If (RunOrderNo GT 1) then
|
|
PrevRunNo = RunOrderNo - 1
|
|
WONo = Xlate('RDS', RDSNo, 'WO', 'X')
|
|
CopyWOMatKey = WONo:'*':PrevRunNo
|
|
CopyRDSNo = Xlate('WO_MAT', CopyWOMatKey, 'RDS_NO', 'X')
|
|
// Get RDSLayer keys -> copy tool parameters to each layer
|
|
CopyRDSLayerKeys = Xlate('RDS', CopyRDSNo, 'RDS_LAYER_KEYS', 'X')
|
|
If CopyRDSLayerKeys NE '' then
|
|
For each CopyRDSLayerKey in CopyRDSLayerKeys
|
|
// Copy RDS layer records
|
|
LayerID = Field(CopyRDSLayerKey, '*', 2)
|
|
DestRDSLayerKey = RDSNo:'*':LayerID
|
|
CopyRDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', CopyRDSLayerKey)
|
|
DestRDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', DestRDSLayerKey)
|
|
|
|
DestRDSLayerRec<RDS_LAYER_DOPANT$> = CopyRDSLayerRec<RDS_LAYER_DOPANT$>
|
|
DestRDSLayerRec<RDS_LAYER_EPI_DILUENT$> = CopyRDSLayerRec<RDS_LAYER_EPI_DILUENT$>
|
|
DestRDSLayerRec<RDS_LAYER_EPI_TIME$> = CopyRDSLayerRec<RDS_LAYER_EPI_TIME$>
|
|
DestRDSLayerRec<RDS_LAYER_DILUENT_ADJ_PARAM$> = CopyRDSLayerRec<RDS_LAYER_DILUENT_ADJ_PARAM$>
|
|
DestRDSLayerRec<RDS_LAYER_DOPANT_FLOW$> = CopyRDSLayerRec<RDS_LAYER_DOPANT_FLOW$>
|
|
DestRDSLayerRec<RDS_LAYER_HCL_FLOW$> = CopyRDSLayerRec<RDS_LAYER_HCL_FLOW$>
|
|
DestRDSLayerRec<RDS_LAYER_BAKE_TIME$> = CopyRDSLayerRec<RDS_LAYER_BAKE_TIME$>
|
|
DestRDSLayerRec<RDS_LAYER_EPI_H2_FLOW$> = CopyRDSLayerRec<RDS_LAYER_EPI_H2_FLOW$>
|
|
DestRDSLayerRec<RDS_LAYER_TCS_FLOW$> = CopyRDSLayerRec<RDS_LAYER_TCS_FLOW$>
|
|
DestRDSLayerRec<RDS_LAYER_DCS_FLOW$> = CopyRDSLayerRec<RDS_LAYER_DCS_FLOW$>
|
|
DestRDSLayerRec<RDS_LAYER_AUX1$> = CopyRDSLayerRec<RDS_LAYER_AUX1$>
|
|
DestRDSLayerRec<RDS_LAYER_AUX2$> = CopyRDSLayerRec<RDS_LAYER_AUX2$>
|
|
DestRDSLayerRec<RDS_LAYER_F_OFFSET$> = CopyRDSLayerRec<RDS_LAYER_F_OFFSET$>
|
|
DestRDSLayerRec<RDS_LAYER_S_OFFSET$> = CopyRDSLayerRec<RDS_LAYER_S_OFFSET$>
|
|
DestRDSLayerRec<RDS_LAYER_R_OFFSET$> = CopyRDSLayerRec<RDS_LAYER_R_OFFSET$>
|
|
DestRDSLayerRec<RDS_LAYER_ETCH1$> = CopyRDSLayerRec<RDS_LAYER_ETCH1$>
|
|
DestRDSLayerRec<RDS_LAYER_ETCH2$> = CopyRDSLayerRec<RDS_LAYER_ETCH2$>
|
|
DestRDSLayerRec<RDS_LAYER_ETCH3$> = CopyRDSLayerRec<RDS_LAYER_ETCH3$>
|
|
DestRDSLayerRec<RDS_LAYER_OVERGROW_REQ$> = CopyRDSLayerRec<RDS_LAYER_OVERGROW_REQ$>
|
|
DestRDSLayerRec<RDS_LAYER_SUSC_ETCH$> = CopyRDSLayerRec<RDS_LAYER_SUSC_ETCH$>
|
|
DestRDSLayerRec<RDS_LAYER_UL_TEMP$> = CopyRDSLayerRec<RDS_LAYER_UL_TEMP$>
|
|
DestRDSLayerRec<RDS_LAYER_MODIFY_USER$, -1> = 'CopyService'
|
|
DestRDSLayerRec<RDS_LAYER_MODIFY_DTM$, -1> = DateTime()
|
|
Database_Services('WriteDataRow', 'RDS_LAYER', DestRDSLayerKey, DestRDSLayerRec, True$, True$, True$)
|
|
|
|
Next CopyRDSLayerKey
|
|
end
|
|
end else
|
|
Error_Services('Add', 'No previous run to copy RDS layer parameters from in ':Service:' service.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'RDSNo not supplied in ':Service:' service.')
|
|
end
|
|
|
|
EndTick = GetTickCount()
|
|
Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick)
|
|
end service
|
|
|
|
|
|
Service RemovePocketNCR(RDSNo, Pocket)
|
|
|
|
If ( (RDSNo NE '') and (Pocket NE '') ) then
|
|
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo)
|
|
If Error_Services('NoError') then
|
|
RDSRec<RDS_OUT_NCR$, Pocket> = ''
|
|
Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec)
|
|
end
|
|
end
|
|
|
|
end service
|
|
|
|
|
|
Service AddPocketNCR(RDSNo, Pocket, NCRNo)
|
|
|
|
If ( (RDSNo NE '') and (Pocket NE '') and (NCRNo NE '') ) then
|
|
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo)
|
|
If Error_Services('NoError') then
|
|
RDSRec<RDS_OUT_NCR$, Pocket> = NCRNo
|
|
Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec)
|
|
end
|
|
end
|
|
|
|
end service
|
|
|
|
|
|
Service ConvertRecordToJSON(KeyID, Record, itemURL)
|
|
jsonRecord = ''
|
|
If KeyID NE '' then
|
|
|
|
If Record EQ '' then Record = Database_Services('ReadDataRow', 'RDS', KeyID)
|
|
If Error_Services('NoError') then
|
|
@DICT = Database_Services('GetTableHandle', 'DICT.RDS')
|
|
@ID = KeyID
|
|
@RECORD = Record
|
|
If SRP_JSON(objJSON, 'New', 'Object') then
|
|
|
|
If SRP_JSON(objRDS, 'New', 'Object') then
|
|
WOMatKey = {WO_MAT_KEY}
|
|
SAPBatchNo = Database_Services('ReadDataColumn', 'WO_MAT', WOMatKey, WO_MAT_SAP_BATCH_NO$, True$, 0, False$)
|
|
SRP_JSON(objRDS, 'SetValue', 'keyId', @ID)
|
|
SRP_JSON(objRDS, 'SetValue', 'reactor', {REACTOR})
|
|
SRP_JSON(objRDS, 'SetValue', 'workOrder', {WO})
|
|
SRP_JSON(objRDS, 'SetValue', 'cassNo', {CASS_NO})
|
|
SRP_JSON(objRDS, 'SetValue', 'combStatus', {COMB_STATUS})
|
|
SRP_JSON(objRDS, 'SetValue', 'partNo', {PART_NUM})
|
|
SRP_JSON(objRDS, 'SetValue', 'PSN', {PROD_SPEC_ID})
|
|
SRP_JSON(objRDS, 'SetValue', 'cassNo', {CASS_NO})
|
|
SRP_JSON(objRDS, 'SetValue', 'entryId', {ENTRY_ID})
|
|
SRP_JSON(objRDS, 'SetValue', 'entryDtm', Trim(OConv({ENTRY_DATE}, 'D4/H'):' ':OConv({ENTRY_TIME}, 'MTHS')))
|
|
SRP_JSON(objRDS, 'SetValue', 'preEpiSig', {PRE_EPI_SIG})
|
|
SRP_JSON(objRDS, 'SetValue', 'preEpiSigDtm', Trim(OConv({PRE_EPI_SIG_DATE}, 'D4/H'):' ':OConv({PRE_EPI_SIG_TIME}, 'MTHS')))
|
|
SRP_JSON(objRDS, 'SetValue', 'operatorIn', {OPERATOR_IN})
|
|
SRP_JSON(objRDS, 'SetValue', 'dtmIn', Trim(OConv({DATE_IN}, 'D4/H'):' ':OConv({TIME_IN}, 'MTHS')))
|
|
SRP_JSON(objRDS, 'SetValue', 'operatorOut', {OPERATOR_OUT})
|
|
SRP_JSON(objRDS, 'SetValue', 'dtmOut', Trim(OConv({DATE_OUT}, 'D4/H'):' ':OConv({TIME_OUT}, 'MTHS')))
|
|
SRP_JSON(objRDS, 'SetValue', 'postEpiSig', {POST_EPI_SIG})
|
|
SRP_JSON(objRDS, 'SetValue', 'postEpiSigDtm', Trim(OConv({POST_EPI_SIG_DATE}, 'D4/H'):' ':OConv({POST_EPI_SIG_TIME}, 'MTHS')))
|
|
SRP_JSON(objRDS, 'SetValue', 'SapBatchNo', SAPBatchNo)
|
|
SAPTxDtm = Xlate('WO_MAT', {WO_MAT_KEY}, 'SAP_TX_DTM', 'X')
|
|
SRP_JSON(objRDS, 'SetValue', 'sapTxDtm', Trim(OConv(SAPTxDtm, 'DT2/^H')))
|
|
SRP_JSON(objRDS, 'SetValue', 'supVerSig', {SUP_VER_SIG})
|
|
SRP_JSON(objRDS, 'SetValue', 'supVerSigDtm', Trim(OConv({SUP_VER_SIG_DATE}, 'D4/H'):' ':OConv({SUP_VER_SIG_TIME}, 'MTHS')))
|
|
SRP_JSON(objRDS, 'SetValue', 'shipDtm', Trim(OConv({SHIP_DATE}, 'D4/H'):' ':OConv({SHIP_TIME}, 'MTHS')))
|
|
SRP_JSON(objRDS, 'SetValue', 'subPartNo', {SUB_PART_NO})
|
|
SRP_JSON(objRDS, 'SetValue', 'shipNo', {SHIP_NO})
|
|
SRP_JSON(objRDS, 'SetValue', 'cassWaferQty', {CASS_WAFER_QTY})
|
|
SRP_JSON(objRDS, 'SetValue', 'loadLockSide', {LOAD_LOCK_SIDE})
|
|
SRP_JSON(objRDS, 'SetValue', 'waferSize', {WAFER_SIZE})
|
|
SRP_JSON(objRDS, 'SetValue', 'reactorType', {REACTOR_TYPE})
|
|
CurrWfrCnt = Xlate('WO_MAT', {WO_MAT_KEY}, 'CURR_WFR_CNT', 'X')
|
|
SRP_JSON(objRDS, 'SetValue', 'CURR_WFR_CNT', CurrWfrCnt)
|
|
CustNo = Database_Services('ReadDataColumn', 'WO_LOG', {WO}, WO_LOG_CUST_NO$, True$, 0, False$)
|
|
CustReshipNo = Database_Services('ReadDataColumn', 'WO_MAT', {WO_MAT_KEY}, WO_MAT_RESHIP_CUST_NO$, True$, 0, False$)
|
|
If CustReshipNo NE '' then
|
|
CustNo = CustReshipNo
|
|
end
|
|
CustName = Database_Services('ReadDataColumn', 'COMPANY', CustNo, COMPANY_CO_NAME$, True$, 0, False$)
|
|
CustAbbrev = Database_Services('ReadDataColumn', 'COMPANY', CustNo, COMPANY_ABBREV$, True$, 0, False$)
|
|
SRP_JSON(objRDS, 'SetValue', 'CustNo', CustNo)
|
|
SRP_JSON(objRDS, 'SetValue', 'CustName', CustName)
|
|
SRP_JSON(objRDS, 'SetValue', 'CustAbbrev', CustAbbrev)
|
|
|
|
// Save system variables
|
|
AtID = @ID
|
|
AtRecord = @Record
|
|
AtDict = @Dict
|
|
|
|
// Add a PSN object
|
|
ProdSpecJSON = PSN_Services('ConvertRecordToJSON', {PROD_SPEC_ID})
|
|
If SRP_JSON(objProdSpecResponse, 'Parse', ProdSpecJSON) EQ '' then
|
|
objProdSpec = SRP_JSON(objProdSpecResponse, 'Get', 'prodSpec')
|
|
SRP_JSON(objRDS, 'Set', 'prodSpec', objProdSpec)
|
|
SRP_JSON(objProdSpec, 'Release')
|
|
SRP_JSON(objProdSpecResponse, 'Release')
|
|
end
|
|
|
|
// Restore system variables
|
|
@ID = AtID
|
|
@Record = AtRecord
|
|
@Dict = AtDict
|
|
|
|
// Add CLEAN_INSP objects
|
|
CINos = ''
|
|
CINos<0, -1> = {PRE_CI_NO}
|
|
CINos<0, -1> = {FWI_CI_NO}
|
|
CINos<0, -1> = {LWI_CI_NO}
|
|
CINos<0, -1> = {POST_CI_NO}
|
|
|
|
If CINos NE '' then
|
|
If SRP_JSON(objCleanInspArray, 'New', 'Array') then
|
|
For each CINo in CINos using @VM setting vPos
|
|
If CINo NE '' then
|
|
CleanInspJSON = Clean_Insp_Services('ConvertRecordToJSON', CINo)
|
|
If SRP_JSON(objCleanInsp, 'Parse', CleanInspJSON) EQ '' then
|
|
objTemp = SRP_JSON(objCleanInsp, 'Get', 'cleanInsp')
|
|
SRP_JSON(objCleanInspArray, 'Add', objTemp)
|
|
SRP_JSON(objTemp, 'Release')
|
|
SRP_JSON(objCleanInsp, 'Release')
|
|
end
|
|
end
|
|
Next CINo
|
|
SRP_JSON(objRDS, 'Set', 'cleanInsp', objCleanInspArray)
|
|
SRP_JSON(objCleanInspArray, 'Release')
|
|
end
|
|
end
|
|
// Save system variables
|
|
// Restore system variables
|
|
@ID = AtID
|
|
@Record = AtRecord
|
|
@Dict = AtDict
|
|
AtID = @ID
|
|
AtRecord = @Record
|
|
AtDict = @Dict
|
|
|
|
If RowExists('WO_MAT_QA', WOMatKey) then
|
|
// Add WO_MAT_QA object
|
|
WOMatQAJSON = WO_Mat_QA_Services('ConvertRecordToJSON', WOMatKey)
|
|
If SRP_JSON(objWOMatQA, 'Parse', WOMatQAJSON) EQ '' then
|
|
objTemp = SRP_JSON(objWOMatQA, 'Get', 'woMatQa')
|
|
SRP_JSON(objRDS, 'Set', 'woMatQA', objTemp)
|
|
SRP_JSON(objTemp, 'Release')
|
|
SRP_JSON(objWOMatQA, 'Release')
|
|
end
|
|
end else
|
|
If SRP_JSON(objWOMatQA, 'New', 'Object') then
|
|
SRP_JSON(objRDS, 'Set', 'woMatQA', objWOMatQA)
|
|
SRP_JSON(objWOMatQA, 'Release')
|
|
end
|
|
|
|
end
|
|
// Restore system variables
|
|
|
|
@ID = AtID
|
|
@Record = AtRecord
|
|
@Dict = AtDict
|
|
|
|
If SRP_JSON(objRDSLayerArray, 'New', 'Array') then
|
|
RDSLayerKeys = {RDS_LAYER_KEYS}
|
|
For each RDSLayerKey in RDSLayerKeys using @VM setting vPos
|
|
//If SRP_JSON(objRDSLayer, 'New', 'Object') then
|
|
//SRP_JSON(objRDSLayer, 'SetValue', 'keyId', RDSLayerKey)
|
|
//SRP_JSON(objRDSLayerArray, 'Add', objRDSLayer)
|
|
rdsLayerJson = Rds_Layer_Services('ConvertRecordToJSON', RDSLayerKey)
|
|
If SRP_Json(objTempHandle, 'Parse', rdsLayerJson) EQ '' then
|
|
SRP_JSON(objRDSLayerArray, 'Add', objTempHandle)
|
|
SRP_JSON(objTempHandle, 'Release')
|
|
end
|
|
|
|
//SRP_JSON(objRDSLayer, 'Release')
|
|
//end
|
|
Next RDSLayerKey
|
|
//SRP_JSON(objRDS, 'Set', 'rdsLayerIds', objRDSLayerArray)
|
|
SRP_JSON(objRDS, 'Set', 'rdsLayers', objRDSLayerArray)
|
|
SRP_JSON(objRDSLayerArray, 'Release')
|
|
end
|
|
AllRTFRecords = Return_To_Fab_Services('GetReturnToFabRecordIdByCassId', KeyID)
|
|
If AllRTFRecords NE '' then
|
|
objRTFRecords = ''
|
|
If SRP_JSON(objRTFRecords, 'New', 'Array') then
|
|
For each RTFRecordId in AllRTFRecords using @VM setting vPos
|
|
objRTF = ''
|
|
If SRP_JSON(objRTF, 'New', 'Object') then
|
|
RTFRecord = Database_Services('ReadDataRow', 'RETURN_TO_FAB_LOTS', RTFRecordId, True$, 0, False$)
|
|
SRP_JSON(objRTF, 'SetValue', 'ReturnToFabLotsId', RTFRecordId)
|
|
SRP_JSON(objRTF, 'SetValue', 'StartDtm', OConv(RTFRecord<RETURN_TO_FAB_LOTS_MH_INIT_DTM$>, 'DT'))
|
|
SRP_JSON(objRTF, 'SetValue', 'Completed', RTFRecord<RETURN_TO_FAB_LOTS_COMPLETED$>, 'Boolean')
|
|
SRP_JSON(objRTFRecords, 'Set', 'ReturnToFabRecord', objRTF)
|
|
SRP_JSON(objRTFRecords, 'Add', objRTF)
|
|
SRP_JSON(objRTF, 'Release')
|
|
end
|
|
Next RTFRecordId
|
|
|
|
SRP_JSON(objRDS, 'Set', 'ReturnToFabRecords', objRTFRecords)
|
|
SRP_JSON(objRTFRecords, 'Release')
|
|
end
|
|
end else
|
|
SRP_JSON(objRDS, 'SetValue', 'ReturnToFabRecords', '')
|
|
end
|
|
SRP_JSON(objJSON, 'Set', 'rds', objRDS)
|
|
SRP_JSON(objRDS, 'Release')
|
|
end
|
|
|
|
If itemURL NE '' then
|
|
// The itemURL was passed in so add HAL+JSON properties.
|
|
|
|
// Create the _links property and then all link objects needed for this resource.
|
|
If SRP_JSON(objLinks, 'New', 'Object') then
|
|
// Create a self link.
|
|
If SRP_JSON(objLink, 'New', 'Object') then
|
|
SRP_JSON(objLink, 'SetValue', 'href', ItemURL, 'String')
|
|
SRP_JSON(objLink, 'SetValue', 'title', 'Self', 'String')
|
|
SRP_JSON(objLinks, 'Set', 'self', objLink)
|
|
SRP_JSON(objLink, 'Release')
|
|
end
|
|
SRP_JSON(objJSON, 'Set', '_links', objLinks)
|
|
SRP_JSON(objLinks, 'Release')
|
|
end
|
|
|
|
// Create the _class property for this resource.
|
|
SRP_JSON(objJSON, 'SetValue', '_class', 'resource')
|
|
end
|
|
jsonRecord = SRP_JSON(objJSON, 'Stringify', 'Styled')
|
|
SRP_JSON(objJSON, 'Release')
|
|
end else
|
|
Error_Services('Add', 'Unable to create JSON representation in the ' : Service : ' service.')
|
|
end
|
|
end
|
|
end else
|
|
Error_Services('Add', 'KeyID argument was missing in the ' : Service : ' service.')
|
|
end
|
|
|
|
Response = jsonRecord
|
|
|
|
end service
|
|
|
|
|
|
Service GetRDSMoves(ReportDTM)
|
|
|
|
DatesToSearch = ''
|
|
ReportDTM = FIELD(ReportDTM, ' ', 1)
|
|
query = 'SELECT RDS WITH DATE_OUT EQ ': QUOTE(ReportDTM)
|
|
|
|
Set_Status(0)
|
|
RList(query, TARGET_ACTIVELIST$, "", "", "")
|
|
IF Get_Status(errCode) THEN
|
|
ErrMsg(errCode)
|
|
RETURN
|
|
END
|
|
RDSList = ''
|
|
IF @RecCount then
|
|
EoF = 0
|
|
NumKeys = @RecCount
|
|
Cnt = 0
|
|
|
|
Loop
|
|
ReadNext RDSKey Else EoF = 1
|
|
until EoF
|
|
RDSList<-1> = RDSKey
|
|
|
|
Repeat
|
|
|
|
end
|
|
GoSub ClearCursors
|
|
Response = RDSList
|
|
|
|
end service
|
|
|
|
|
|
Service SignUnloadExtra1(RDSNo, LSLUserName)
|
|
|
|
IF LSLUserName NE '' AND RowExists('LSL_USERS', LSLUserName) then
|
|
If RowExists('RDS', RDSNo) then
|
|
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo)
|
|
UnloadExtra1Ready = Qa_Services('UnloadExtra1stReady', RDSNo)
|
|
If UnloadExtra1Ready then
|
|
RDSRec<RDS_OP_OUT_EX1$> = LSLUsername
|
|
RDSRec<RDS_OP_OUT_EX1_DATE$> = SRP_Date('Today')
|
|
RDSRec<RDS_OP_OUT_EX1_TIME$> = SRP_Time('Now')
|
|
Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, True$)
|
|
Reactor = RDSRec<RDS_REACTOR$>
|
|
If Error_Services('NoError') then
|
|
Rds_Services('AddComment', RDSNo, 'Unload Extra 1 Signed from Reactor ' : Reactor, LSLUserName)
|
|
end
|
|
Reactor_Services('RemoveRDSFromReactorLoad', RDSNo, Reactor, LSLUserName)
|
|
end else
|
|
Error_Services('Add', 'Unload Extra 1 is not able to be signed at this stage')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'RDS ' : RDSNo : ' does not exist.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'Invalid user passed to Sign Unload Extra 1 routine')
|
|
end
|
|
|
|
end service
|
|
|
|
|
|
Service UnsignUnloadExtra1(RDSNo, LSLUserName)
|
|
|
|
IF LSLUserName NE '' AND RowExists('LSL_USERS', LSLUserName) then
|
|
If RowExists('RDS', RDSNo) then
|
|
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo)
|
|
Reactor = RDSRec<RDS_REACTOR$>
|
|
If Reactor NE '' then
|
|
CurrReactorLoadCapacity = Reactor_Services('GetReactorAvailChamberCount', Reactor)
|
|
If CurrReactorLoadCapacity GT 0 then
|
|
UnsignUnloadExtra1Ready = Qa_Services('UnsignUnloadExtra1stReady', RDSNo)
|
|
if UnsignUnloadExtra1Ready then
|
|
RDSRec<RDS_OP_OUT_EX1$> = ''
|
|
RDSRec<RDS_OP_OUT_EX1_DATE$> = ''
|
|
RDSRec<RDS_OP_OUT_EX1_TIME$> = ''
|
|
Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, True$)
|
|
Reactor = RDSRec<RDS_REACTOR$>
|
|
If Error_Services('NoError') then
|
|
Rds_Services('AddComment', RDSNo, 'Unload Extra 1 Unsigned on Reactor ' : Reactor, LSLUserName)
|
|
end
|
|
Reactor_Services('AddRDSToReactorLoad', RDSNo, Reactor)
|
|
end else
|
|
Error_Services('Add', 'Unsign Load Extra 1 is not able to be unsigned.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'Reactor #' : Reactor : ' does not currently have the capacity to be loaded. Unload a lot to allow.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'RDS is not assigned to a reactor.')
|
|
end
|
|
|
|
end else
|
|
Error_Services('Add', 'RDS ' : RDSNo : ' does not exist.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'Invalid user passed to Unsign Load Extra 1 routine')
|
|
end
|
|
|
|
end service
|
|
|
|
|
|
Service SignLoadExtra1(RDSNo,LSLUserName)
|
|
|
|
IF LSLUserName NE '' AND RowExists('LSL_USERS', LSLUserName) then
|
|
If RowExists('RDS', RDSNo) then
|
|
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo)
|
|
Reactor = RDSRec<RDS_REACTOR$>
|
|
If Reactor NE '' then
|
|
CurrReactorLoadCapacity = Reactor_Services('GetReactorAvailChamberCount', Reactor)
|
|
If CurrReactorLoadCapacity GT 0 then
|
|
LoadExtra1Ready = Qa_Services('LoadExtra1stReady', RDSNo)
|
|
If LoadExtra1Ready then
|
|
RDSRec<RDS_OP_IN_EX2$> = LSLUsername
|
|
RDSRec<RDS_OP_IN_EX2_DATE$> = SRP_Date('Today')
|
|
RDSRec<RDS_OP_IN_EX2_TIME$> = SRP_Time('Now')
|
|
Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, True$)
|
|
If Error_Services('NoError') then
|
|
Rds_Services('AddComment', RDSNo, 'Load Extra 1 Signed to Reactor ' : Reactor, LSLUserName)
|
|
end
|
|
Reactor_Services('AddRDSToReactorLoad', RDSNo, Reactor)
|
|
end else
|
|
Error_Services('Add', 'Load Extra 1 is not able to be signed at this stage')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'Reactor #' : Reactor : ' does not currently have the capacity to be loaded. Unload a lot to allow.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'RDS is not assigned to a reactor.')
|
|
end
|
|
|
|
end else
|
|
Error_Services('Add', 'RDS ' : RDSNo : ' does not exist.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'Invalid user passed to Sign Unload Extra 1 routine')
|
|
end
|
|
|
|
end service
|
|
|
|
|
|
Service UnsignLoadExtra1(RDSNo, LSLUserName)
|
|
|
|
IF LSLUserName NE '' AND RowExists('LSL_USERS', LSLUserName) then
|
|
If RowExists('RDS', RDSNo) then
|
|
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo)
|
|
UnsignLoadExtra1Ready = Qa_Services('UnsignLoadExtra1stReady', RDSNo)
|
|
if UnsignLoadExtra1Ready then
|
|
RDSRec<RDS_OP_IN_EX2$> = ''
|
|
RDSRec<RDS_OP_IN_EX2_DATE$> = ''
|
|
RDSRec<RDS_OP_IN_EX2_TIME$> = ''
|
|
Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, True$)
|
|
Reactor = RDSRec<RDS_REACTOR$>
|
|
If Error_Services('NoError') then
|
|
Rds_Services('AddComment', RDSNo, 'Load Extra 1 Unsigned on Reactor ' : Reactor, LSLUserName)
|
|
end
|
|
Reactor_Services('RemoveRDSFromReactorLoad', RDSNo, Reactor, LSLUserName)
|
|
end else
|
|
Error_Services('Add', 'Unsign Load Extra 1 is not able to be unsigned.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'RDS ' : RDSNo : ' does not exist.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'Invalid user passed to Unsign Load Extra 1 routine')
|
|
end
|
|
|
|
end service
|
|
|
|
|
|
Service SignUnloadExtra2(RDSNo,LSLUserName)
|
|
|
|
IF LSLUserName NE '' AND RowExists('LSL_USERS', LSLUserName) then
|
|
If RowExists('RDS', RDSNo) then
|
|
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo)
|
|
UnloadExtra2ndReady = Qa_Services('UnloadExtra2ndReady', RDSNo)
|
|
If UnloadExtra2ndReady then
|
|
RDSRec<RDS_OP_OUT_EX2$> = LSLUsername
|
|
RDSRec<RDS_OP_OUT_EX2_DATE$> = SRP_Date('Today')
|
|
RDSRec<RDS_OP_OUT_EX2_TIME$> = SRP_Time('Now')
|
|
Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, True$)
|
|
Reactor = RDSRec<RDS_REACTOR$>
|
|
If Error_Services('NoError') then
|
|
Rds_Services('AddComment', RDSNo, 'Unload Extra 2 Signed from Reactor ' : Reactor, LSLUserName)
|
|
end
|
|
Reactor_Services('RemoveRDSFromReactorLoad', RDSNo, Reactor, LSLUserName)
|
|
end else
|
|
Error_Services('Add', 'Unload Extra 2 is not able to be signed at this stage')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'RDS ' : RDSNo : ' does not exist.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'Invalid user passed to Sign Unload Extra 1 routine')
|
|
end
|
|
|
|
end service
|
|
|
|
|
|
Service UnsignUnloadExtra2(RDSNo, LSLUserName)
|
|
|
|
IF LSLUserName NE '' AND RowExists('LSL_USERS', LSLUserName) then
|
|
If RowExists('RDS', RDSNo) then
|
|
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo)
|
|
Reactor = RDSRec<RDS_REACTOR$>
|
|
If Reactor NE '' then
|
|
CurrReactorLoadCapacity = Reactor_Services('GetReactorAvailChamberCount', Reactor)
|
|
If CurrReactorLoadCapacity GT 0 then
|
|
UnsignUnloadExtra2Ready = Qa_Services('UnsignUnloadExtra2ndReady', RDSNo)
|
|
if UnsignUnloadExtra2Ready then
|
|
RDSRec<RDS_OP_OUT_EX2$> = ''
|
|
RDSRec<RDS_OP_OUT_EX2_DATE$> = ''
|
|
RDSRec<RDS_OP_OUT_EX2_TIME$> = ''
|
|
Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, True$)
|
|
Reactor = RDSRec<RDS_REACTOR$>
|
|
If Error_Services('NoError') then
|
|
Rds_Services('AddComment', RDSNo, 'Unload Extra 2 Unsigned on Reactor ' : Reactor, LSLUserName)
|
|
end
|
|
Reactor_Services('AddRDSToReactorLoad', RDSNo, Reactor)
|
|
end else
|
|
Error_Services('Add', 'Unsign Load Extra 2 is not able to be unsigned.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'Reactor #' : Reactor : ' does not currently have the capacity to be loaded. Unload a lot to allow.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'RDS is not assigned to a reactor.')
|
|
end
|
|
|
|
end else
|
|
Error_Services('Add', 'RDS ' : RDSNo : ' does not exist.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'Invalid user passed to Unsign Unload Extra 1 routine')
|
|
end
|
|
|
|
end service
|
|
|
|
|
|
Service SignLoadExtra2(RDSNo,LSLUserName)
|
|
|
|
IF LSLUserName NE '' AND RowExists('LSL_USERS', LSLUserName) then
|
|
If RowExists('RDS', RDSNo) then
|
|
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo)
|
|
Reactor = RDSRec<RDS_REACTOR$>
|
|
If Reactor NE '' then
|
|
CurrReactorLoadCapacity = Reactor_Services('GetReactorAvailChamberCount', Reactor)
|
|
If CurrReactorLoadCapacity GT 0 then
|
|
LoadExtra2Ready = Qa_Services('LoadExtra2ndReady', RDSNo)
|
|
if LoadExtra2Ready then
|
|
RDSRec<RDS_OP_IN_EX3$> = LSLUsername
|
|
RDSRec<RDS_OP_IN_EX3_DATE$> = SRP_Date('Today')
|
|
RDSRec<RDS_OP_IN_EX3_TIME$> = SRP_Time('Now')
|
|
Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, True$)
|
|
If Error_Services('NoError') then
|
|
Rds_Services('AddComment', RDSNo, 'Load Extra 2 Signed to Reactor ' : Reactor, LSLUserName)
|
|
end
|
|
Reactor_Services('AddRDSToReactorLoad', RDSNo, Reactor)
|
|
end else
|
|
Error_Services('Add', 'Load Extra 2 is not able to be signed at this stage')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'Reactor #' : Reactor : ' does not currently have the capacity to be loaded. Unload a lot to allow.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'RDS is not assigned to a reactor.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'RDS ' : RDSNo : ' does not exist.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'Invalid user passed to Sign Unload Extra 1 routine')
|
|
end
|
|
|
|
end service
|
|
|
|
|
|
Service UnsignLoadExtra2(RDSNo, LSLUserName)
|
|
|
|
IF LSLUserName NE '' AND RowExists('LSL_USERS', LSLUserName) then
|
|
If RowExists('RDS', RDSNo) then
|
|
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo)
|
|
UnsignLoadExtra2Ready = Qa_Services('UnsignLoadExtra2ndReady', RDSNo)
|
|
if UnsignLoadExtra2Ready then
|
|
RDSRec<RDS_OP_IN_EX3$> = ''
|
|
RDSRec<RDS_OP_IN_EX3_DATE$> = ''
|
|
RDSRec<RDS_OP_IN_EX3_TIME$> = ''
|
|
Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, True$)
|
|
Reactor = RDSRec<RDS_REACTOR$>
|
|
If Error_Services('NoError') then
|
|
Rds_Services('AddComment', RDSNo, 'Load Extra 2 Unsigned on Reactor ' : Reactor, LSLUserName)
|
|
end
|
|
Reactor_Services('RemoveRDSFromReactorLoad', RDSNo, Reactor, LSLUserName)
|
|
end else
|
|
Error_Services('Add', 'Unsign Load Extra 2 is not able to be unsigned.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'RDS ' : RDSNo : ' does not exist.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'Invalid user passed to Unsign Unload Extra 1 routine')
|
|
end
|
|
|
|
end service
|
|
|
|
Service ApplyQA100PercentADE(RDSNo)
|
|
|
|
Result = False$
|
|
ErrorMsg = ''
|
|
If RDSNo NE '' then
|
|
// Change the QA metrology requirements to all wafers
|
|
WoNo = Xlate('RDS', RDSNo, RDS_WO$, 'X')
|
|
CassNo = Xlate('RDS', RDSNo, 'CASS_NO', 'X')
|
|
WoMatQaKey = WoNo : '*' : CassNo
|
|
WoMatQaRec = Xlate('WO_MAT_QA', WoMatQaKey, '', 'X')
|
|
EpiCheck = Rds_Services('IsEpiPro', RDSNo)
|
|
If EpiCheck EQ True$ then
|
|
WoWaferQty = Xlate('WO_MAT', WoMatQaKey, WO_MAT_WAFER_QTY$, 'X')
|
|
end else
|
|
WoWaferQty = Xlate('RDS', RDSNo, 'WFRS_OUT', 'X')
|
|
end
|
|
|
|
WoMatQaStages = WoMatQaRec<WO_MAT_QA_STAGE$>
|
|
WoMatQaProfiles = WoMatQaRec<WO_MAT_QA_PROFILE$>
|
|
WoMatQaSlots = WoMatQaRec<WO_MAT_QA_SLOT$>
|
|
WoMatQaWfrQtys = WoMatQaRec<WO_MAT_QA_WFR_QTY$>
|
|
WoMatQaProps = WoMatQaRec<WO_MAT_QA_PROP$>
|
|
WoMatQaToolClasses = WoMatQaRec<WO_MAT_QA_TOOL_CLASS$>
|
|
WoMatQaRecipes = WoMatQaRec<WO_MAT_QA_RECIPE$>
|
|
WoMatQaRecipePatterns = WoMatQaRec<WO_MAT_QA_RECIPE_PATTERN$>
|
|
WoMatQaMin = WoMatQaRec<WO_MAT_QA_MIN$>
|
|
WoMatQaMax = WoMatQaRec<WO_MAT_QA_MAX$>
|
|
WoMatQaOOS = WoMatQaRec<WO_MAT_QA_OUT_OF_SPEC$>
|
|
StageCount = DCount(WoMatQaStages, @VM)
|
|
For stageIdx = 1 to StageCount
|
|
If (WoMatQaStages<0, stageIdx> _EQC 'QA') and (WoMatQaProfiles<0, stageIdx> _EQC '1ADE') then
|
|
Slot = WoMatQaSlots<0, stageIdx>
|
|
If (Slot _NEC 'L') then
|
|
WoMatQaSlots<0, stageIdx> = 'A'
|
|
WoMatQaWfrQtys<0, stageIdx> = WoWaferQty
|
|
end
|
|
If (Slot _EQC 'L') then
|
|
WoMatQaStages<0, stageIdx> = ''
|
|
WoMatQaProfiles<0, stageIdx> = ''
|
|
WoMatQaSlots<0, stageIdx> = ''
|
|
WoMatQaWfrQtys<0, stageIdx> = ''
|
|
WoMatQaProps<0, stageIdx> = ''
|
|
WoMatQaToolClasses<0, stageIdx> = ''
|
|
WoMatQaRecipes<0, stageIdx> = ''
|
|
WoMatQaRecipePatterns<0, stageIdx> = ''
|
|
WoMatQaMin<0, stageIdx> = ''
|
|
WoMatQaMax<0, stageIdx> = ''
|
|
WoMatQaOOS<0, stageIdx> = ''
|
|
end
|
|
end
|
|
Next stageIdx
|
|
WoMatQaRec<WO_MAT_QA_STAGE$> = WoMatQaStages
|
|
WoMatQaRec<WO_MAT_QA_PROFILE$> = WoMatQaProfiles
|
|
WoMatQaRec<WO_MAT_QA_SLOT$> = WoMatQaSlots
|
|
WoMatQaRec<WO_MAT_QA_WFR_QTY$> = WoMatQaWfrQtys
|
|
WoMatQaRec<WO_MAT_QA_PROP$> = WoMatQaProps
|
|
WoMatQaRec<WO_MAT_QA_TOOL_CLASS$> = WoMatQaToolClasses
|
|
WoMatQaRec<WO_MAT_QA_RECIPE$> = WoMatQaRecipes
|
|
WoMatQaRec<WO_MAT_QA_RECIPE_PATTERN$> = WoMatQaRecipePatterns
|
|
WoMatQaRec<WO_MAT_QA_MIN$> = WoMatQaMin
|
|
WoMatQaRec<WO_MAT_QA_MAX$> = WoMatQaMax
|
|
WoMatQaRec<WO_MAT_QA_OUT_OF_SPEC$> = WoMatQaOOS
|
|
WoMatQaRec<WO_MAT_QA_SIG$> = ''
|
|
WoMatQaRec<WO_MAT_QA_SIG_DTM$> = ''
|
|
WoMatQaRec<WO_MAT_QA_RESULT$> = ''
|
|
Database_Services('WriteDataRow', 'WO_MAT_QA', WoMatQaKey, WoMatQaRec, True$, False$, False$)
|
|
If Error_Services('HasError') then ErrorMsg = Error_Services('GetMessage')
|
|
end else
|
|
ErrorMsg = 'Error in ':Service:' service. Null RdsKey passed into service!'
|
|
end
|
|
|
|
If ErrorMsg NE '' then
|
|
Error_Services('Add', ErrorMsg)
|
|
end else
|
|
Result = True$
|
|
end
|
|
|
|
end service
|
|
|
|
Service ApplyAbortMetrology(RdsKeys)
|
|
|
|
Result = False$
|
|
ErrorMsg = ''
|
|
If RdsKeys NE '' then
|
|
Convert @VM to @FM in RdsKeys
|
|
If RowExists('RDS', RdsKeys) then
|
|
For each RdsKey in RdsKeys using @FM
|
|
|
|
WoNo = Xlate('RDS', RdsKey, RDS_WO$, 'X')
|
|
// Set a flag on the CI record indicating the run was aborted
|
|
CleanInspKey = Xlate('RDS', RdsKey, 'LWI_CI_NO', 'X')
|
|
CIRec = Database_Services('ReadDataRow', 'CLEAN_INSP', CleanInspKey)
|
|
CIRec<CLEAN_INSP_WAFERS_REMOVED$> = True$
|
|
Database_Services('WriteDataRow', 'CLEAN_INSP', CleanInspKey, CIRec, True$, False$, False$)
|
|
If Error_Services('HasError') then ErrorMsg = Error_Services('GetMessage')
|
|
|
|
If ErrorMsg EQ '' then
|
|
Result = Rds_Services('ApplyQA100PercentADE', RDSKey)
|
|
If Error_Services('HasError') then ErrorMsg = Error_Services('GetMessage')
|
|
end
|
|
|
|
Next RdsKey
|
|
end else
|
|
Convert @FM to ',' in RdsKeys
|
|
ErrorMsg = 'Error in ':Service:' service. One or more Rds records (':RdsKeys:') do not exist!'
|
|
end
|
|
end else
|
|
ErrorMsg = 'Error in ':Service:' service. Null RdsKeys passed into service!'
|
|
end
|
|
|
|
If ErrorMsg NE '' then
|
|
Error_Services('Add', ErrorMsg)
|
|
end else
|
|
Result = True$
|
|
end
|
|
|
|
end service
|
|
|
|
Service DetachRDSFromWO(RDSNo)
|
|
ErrorMessage = ''
|
|
If RowExists('RDS', RDSNo) then
|
|
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo)
|
|
if Error_Services('NoError') then
|
|
RDSRec<RDS_WO$> = ''
|
|
RDSRec<RDS_WO_STEP_KEY$> = ''
|
|
Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, False$, False$, False$)
|
|
If Error_Services('HasError') then
|
|
ErrorMessage = Error_Services('GetMessage')
|
|
end
|
|
end else
|
|
ErrorMessage = Error_Services('GetMessage')
|
|
end
|
|
end else
|
|
ErrorMessage = 'Error detaching RDS ' : RDSNo ' from work order. RDS No not found in RDS table.'
|
|
end
|
|
If ErrorMessage NE '' then
|
|
Error_Services('Add', ErrorMessage)
|
|
end
|
|
end service
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Internal GoSubs
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ClearCursors:
|
|
|
|
For counter = 0 to 8
|
|
ClearSelect counter
|
|
Next counter
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|