Description Created method to determine if a TW is required. HTR and ASM type reactors will required a test wafer to be logged on runs where a test wafer is prescribed. ASM+ type reactors will require a test wafer to be logged on one run prior to a run where a test wafer is prescribed for metrology. This code is gated by an active switch which will be removed when the system goes live. EpiPro is not effected Related work items: #222043
1781 lines
70 KiB
Plaintext
1781 lines
70 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
|
|
|
|
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
|
|
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
|
|
|
|
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)
|
|
|
|
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)
|
|
|
|
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
|
|
|
|
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)
|
|
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>
|
|
end service
|
|
|
|
|
|
Service IsTWLoggingReqd(RDSNo)
|
|
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' 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
|
|
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)
|
|
|
|
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
|
|
|
|
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 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
|
|
// Change the QA metrology requirements to all wafers
|
|
CassNo = Xlate('RDS', RdsKey, 'CASS_NO', 'X')
|
|
WoMatQaKey = WoNo : '*' : CassNo
|
|
WoMatQaRec = Xlate('WO_MAT_QA', WoMatQaKey, '', 'X')
|
|
WoWaferQty = Xlate('WO_MAT', WoMatQaKey, WO_MAT_WAFER_QTY$, 'X')
|
|
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
|
|
Database_Services('WriteDataRow', 'WO_MAT_QA', WoMatQaKey, WoMatQaRec, True$, False$, False$)
|
|
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
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Internal GoSubs
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ClearCursors:
|
|
|
|
For counter = 0 to 8
|
|
ClearSelect counter
|
|
Next counter
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|