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 EQ '' then CurrStage = Stages end Until Signatures 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, 'DT') CommentUsers = RDSRow Comments = RDSRow 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 WorkOrderRow = Database_Services('ReadDataRow', 'WO_LOG', WorkOrderNo) ReactType = WorkOrderRow // Check to see if the Final QA signature is in place. If ReactType EQ 'EPP' then CassetteNos = RDSRow For Each CassetteNo in CassetteNos using @VM WMOutKey = RDSRow : '*' : CassetteNo WMOutRow = Database_Services('ReadDataRow', 'WM_OUT', WMOutKey) If WMOutRow NE '' then FinalQA = true$ end Until FinalQA Next CassetteNo end else If RDSRow 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 WoCassNo = RDSRow 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 CassNo = RDSRec 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 = "Loading Run Data Sheets..." Def = "G" Def = NumRDS Def = 400 Def = -2 ;* message h-pos in pixels, or -2 (center screen, the default), -1 (center parent) Def = -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 = 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 = Hours:':':Minutes Case Otherwise$ RDSList = 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 ThisRDSPreEpiTM = ThisRDSRec 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 ReactNo = RDSRec 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 PSRec = Database_Services('ReadDataRow', 'PROD_SPEC', PSNo) PRSLayerKeys = PSRec 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 Start = PRSPropRec 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 = {RDS_LS_ID} LayerList = {LS_RECIPE} LayerList = {LS_RECIPE_NAME} LayerList = {LS_PARMS_COMP} LayerList = {PARAM_OUT_OF_SPEC} LayerList = '' LayerList = {MET_KEYS} LayerList = {TTHICK_AVG_ALL} LayerList = {TRES_AVG_ALL} LayerList = {MET_KEYS_Z1} LayerList = {TTHICK_AVG_ALL_Z1} LayerList = {TRES_AVG_ALL_Z1} LayerList = {MET_KEYS_Z2} LayerList = {TTHICK_AVG_ALL_Z2} LayerList = {TRES_AVG_ALL_Z2} LayerList = {MET_OUT_OF_SPEC} LayerList = {MET_OUT_OF_SPEC_Z1} LayerList = {MET_OUT_OF_SPEC_Z2} LayerList = {MET_TW_SIGNED} LayerList = {MET_TW_SIGNED_Z1} LayerList = {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,'B') = 1 ELSE IF ICONV(LayerList,'B') = 0 THEN ErrorMsg = 'Recipe Parameters incomplete for RDS: ':RDSNo END END * ASM Metrology IF LayerList NE '' THEN MetNo = LayerList 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 = '' AND LayerList = '' AND LayerList 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 NE '' THEN MetNo = LayerList 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 = '' AND LayerList = '' AND LayerList NE '' THEN ErrorMsg = 'Zone 1 Metrology is Incomplete for RDS: ':RDSNo END //Added check for missing res avg data - JRO /*IF LayerList NE '' AND LayerList = '' AND LayerList 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 NE '' THEN MetNo = LayerList 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 = '' AND LayerList = '' AND LayerList NE '' THEN ErrorMsg = 'Zone 2 Metrology is Incomplete for RDS: ':RDSNo END /* //Added check for missing res avg data - JRO IF LayerList NE '' AND LayerList = '' AND LayerList 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 = CopyRDSLayerRec DestRDSLayerRec = CopyRDSLayerRec DestRDSLayerRec = CopyRDSLayerRec DestRDSLayerRec = CopyRDSLayerRec DestRDSLayerRec = CopyRDSLayerRec DestRDSLayerRec = CopyRDSLayerRec DestRDSLayerRec = CopyRDSLayerRec DestRDSLayerRec = CopyRDSLayerRec DestRDSLayerRec = CopyRDSLayerRec DestRDSLayerRec = CopyRDSLayerRec DestRDSLayerRec = CopyRDSLayerRec DestRDSLayerRec = CopyRDSLayerRec DestRDSLayerRec = CopyRDSLayerRec DestRDSLayerRec = CopyRDSLayerRec DestRDSLayerRec = CopyRDSLayerRec DestRDSLayerRec = CopyRDSLayerRec DestRDSLayerRec = CopyRDSLayerRec DestRDSLayerRec = CopyRDSLayerRec DestRDSLayerRec = CopyRDSLayerRec DestRDSLayerRec = CopyRDSLayerRec DestRDSLayerRec = CopyRDSLayerRec DestRDSLayerRec = 'CopyService' DestRDSLayerRec = 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 = '' 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 = 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, 'DT')) SRP_JSON(objRTF, 'SetValue', 'Completed', RTFRecord, '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 = LSLUsername RDSRec = SRP_Date('Today') RDSRec = SRP_Time('Now') Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, True$) Reactor = RDSRec 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 If Reactor NE '' then CurrReactorLoadCapacity = Reactor_Services('GetReactorAvailChamberCount', Reactor) If CurrReactorLoadCapacity GT 0 then UnsignUnloadExtra1Ready = Qa_Services('UnsignUnloadExtra1stReady', RDSNo) if UnsignUnloadExtra1Ready then RDSRec = '' RDSRec = '' RDSRec = '' Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, True$) Reactor = RDSRec 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 If Reactor NE '' then CurrReactorLoadCapacity = Reactor_Services('GetReactorAvailChamberCount', Reactor) If CurrReactorLoadCapacity GT 0 then LoadExtra1Ready = Qa_Services('LoadExtra1stReady', RDSNo) If LoadExtra1Ready then RDSRec = LSLUsername RDSRec = SRP_Date('Today') RDSRec = 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 = '' RDSRec = '' RDSRec = '' Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, True$) Reactor = RDSRec 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 = LSLUsername RDSRec = SRP_Date('Today') RDSRec = SRP_Time('Now') Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, True$) Reactor = RDSRec 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 If Reactor NE '' then CurrReactorLoadCapacity = Reactor_Services('GetReactorAvailChamberCount', Reactor) If CurrReactorLoadCapacity GT 0 then UnsignUnloadExtra2Ready = Qa_Services('UnsignUnloadExtra2ndReady', RDSNo) if UnsignUnloadExtra2Ready then RDSRec = '' RDSRec = '' RDSRec = '' Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, True$) Reactor = RDSRec 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 If Reactor NE '' then CurrReactorLoadCapacity = Reactor_Services('GetReactorAvailChamberCount', Reactor) If CurrReactorLoadCapacity GT 0 then LoadExtra2Ready = Qa_Services('LoadExtra2ndReady', RDSNo) if LoadExtra2Ready then RDSRec = LSLUsername RDSRec = SRP_Date('Today') RDSRec = 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 = '' RDSRec = '' RDSRec = '' Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, True$) Reactor = RDSRec 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 = 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 WoMatQaProfiles = WoMatQaRec WoMatQaSlots = WoMatQaRec WoMatQaWfrQtys = WoMatQaRec WoMatQaProps = WoMatQaRec WoMatQaToolClasses = WoMatQaRec WoMatQaRecipes = WoMatQaRec WoMatQaRecipePatterns = WoMatQaRec WoMatQaMin = WoMatQaRec WoMatQaMax = WoMatQaRec WoMatQaOOS = WoMatQaRec 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 = WoMatQaStages WoMatQaRec = WoMatQaProfiles WoMatQaRec = WoMatQaSlots WoMatQaRec = WoMatQaWfrQtys WoMatQaRec = WoMatQaProps WoMatQaRec = WoMatQaToolClasses WoMatQaRec = WoMatQaRecipes WoMatQaRec = WoMatQaRecipePatterns WoMatQaRec = WoMatQaMin WoMatQaRec = WoMatQaMax WoMatQaRec = 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