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 SERVICE_SETUP $Insert APP_INSERTS $Insert MSG_EQUATES $Insert RTI_DEBUG_COMMON $Insert RDS_EQUATES $Insert PROD_SPEC_EQUATES $Insert RDS_LAYER_EQUATES $Insert PRS_LAYER_EQUATES $Insert RDS_TEST_EQUATES $Insert TOOL_CLASS_EQUATES $Insert TEST_POINT_MAP_EQUATES $Insert CLEAN_INSP_EQUATES $Insert REACT_RUN_EQUATES $Insert REACTOR_EQUATES $Insert WO_MAT_QA_EQUATES $Insert PRS_STAGE_EQUATES $Insert PRS_PROP_EQUATES $Insert WO_LOG_EQUATES $Insert WM_OUT_EQUATES $Insert REACT_UTIL_EQU $Insert WO_MAT_EQUATES $Insert RLIST_EQUATES $Insert REACT_MODE_EQUATES $Insert LSL_USERS_EQUATES $Insert TOOL_EQUATES $Insert POPUP_EQUATES $Insert NOTIFICATION_EQUATES $Insert DICT_EQUATES $Insert COMPANY_EQUATES $Insert RETURN_TO_FAB_LOTS_EQUATES $Insert TEST_RUN_EQUATES $Insert RDS_LAYER_INFO_EQU $Insert EPI_PART_EQUATES $Insert CUST_EPI_PART_EQUATES $Insert UNIT_EQUATES $Insert QUOTE_SPEC_EQU 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 PI$LEFT TO 1 EQU PI$TOP TO 2 EQU PI$RIGHT TO 3 EQU PI$BOTTOM TO 4 EQU PI$WIDTH TO 5 EQU PI$HEIGHT TO 6 EQU PI$SIZE TO 7 EQU PS$TOOL TO 1 EQU PS$TYPE TO 2 EQU PS$RECIPE TO 3 EQU PS$FREQ TO 4 EQU PS$PATTERN TO 11 EQU COMMA$ to ',' EQU NEW_EXIST$ To 0 ; * Reduce Mode 0 equ NEXT_CUR$ To 1 equ ADD_EXIST$ to 2 Equ NUM_ATTEMPTS$ to 60 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, Delay Declare subroutine Rds_Services, Obj_Post_Log, Mona_Services, Transaction_Services, Reduce, Update_Index 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 Declare function obj_Vendor_Code LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\RDS' LogDate = Oconv(Date(), 'D4/') LogTime = Oconv(Time(), 'MTS') LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Ctrl Performance Log.csv' Headers = 'Logging DTM':@FM:'Ctrl':@FM:'Load/Calculate Time' objCtrlLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, COMMA$, Headers, '', False$, False$) LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM IsProd = Environment_Services('IsProd') If IsProd EQ True$ then MonaResource = 'GRP_OPENINSIGHT_MES_OP_FE_RDSSERVICES' end else MonaResource = 'GRP_OPENINSIGHT_MES_OP_FE_DEV_RDSSERVICES' end GoToService else Error_Services('Set', Service : ' is not a valid service request within the ' : ServiceModule : ' services module.') end Return Response else '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Service Parameter Options //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Options BOOLEAN = True$, False$ Options STAGES = 'PRE', 'FWI', 'LWI', 'QA', 'LOAD', 'UNLOAD' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Services //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //---------------------------------------------------------------------------------------------------------------------- // GetCurrentStage // // RDSNo. - [Required] // // Returns the current stage of a lot. Replaces CURR_STAGE calculated column. //---------------------------------------------------------------------------------------------------------------------- Service GetCurrentStage(RDSNo) If RDSNo NE '' then RDSCheck = Xlate('RDS', RDSNo, '', 'X', '') If RDSCheck NE '' then CurrStage = '' WOMatKey = Xlate('RDS', RDSNo, 'WO_MAT_KEY', 'X') SigProfile = Signature_Services('GetSigProfile', WOMatKey, FALSE$, RDSNo) Stages = SigProfile<1> Signatures = SigProfile<2> SigCount = DCount(Signatures, @VM) StageCount = DCount(Stages, @VM) Swap @VM with @FM in Stages Swap @VM with @FM in Signatures For I = 1 to StageCount If Signatures 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) StartTick = GetTickCount() MetricName = 'AddComment' RDSRow = Database_Services('ReadDataRow', 'RDS', RDSNo) Username = @USER4 If Assigned(UsernameOpt) then If UsernameOpt NE '' then Username = UsernameOpt end end CommentTime = Datetime() Fields = RDS_COMMENT_DATE$:@VM ; Values = CommentTime:@VM Fields := RDS_COMMENT_USER$:@VM ; Values := UserName:@VM Fields := RDS_COMMENT_NOTE$ ; Values := Comment oblParms = 'RDS':@RM oblParms := RDSNo:@RM oblParms := Fields:@RM oblParms := Values:@RM oblParms := "TOP" :@VM: "TOP" :@VM: "TOP" obj_Post_Log('Create',oblParms) EndTick = GetTickCount() Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick) End Service //---------------------------------------------------------------------------------------------------------------------- // GetFinalQAStatus // // RDSNo. - [Required] // // Returns the boolean value of the Final QA status of a given RDS record. Returns True$ if // the Final QA step is signed and False$ if it is not signed. //---------------------------------------------------------------------------------------------------------------------- Service GetFinalQAStatus(RDSNo) FinalQA = False$ RDSRow = Database_Services('ReadDataRow', 'RDS', RDSNo) WorkOrderNo = RDSRow 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$ // 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 //Sort based on cassette number Locate 'RUN_ORDER_NUM' in Columns using @VM setting ColNoCassNo else ColNoCassNo = 1 RDSList = SRP_Sort_Array(RDSList, 'AR' : ColNoCassNo, True$, @FM) Response = RDSList end service //---------------------------------------------------------------------------------------------------------------------- // SetSupplement // // SupplementList. - [Required] // Username. - [Optional] // // Accepts a list with the following structure: // <1> Row Text // <1,1> Column Text RDSNo // <1,2> Column Text Supplement Instructions //---------------------------------------------------------------------------------------------------------------------- Service SetSupplement(SupplementList, Username) RDSNotificationListAdd = '' RDSNotificationListRemove = '' Action = '' If SupplementList NE '' then @DICT = Database_Services('GetTableHandle', 'DICT.' : 'RDS') If Error_Services('NoError') then For Each Row in SupplementList using @FM ChangeDetected = False$ @ID = Row<1,1> SupplementInst = Row<1,2> @RECORD = Database_Services('ReadDataRow', 'RDS', @ID) If Error_Services('NoError') then If SupplementInst NE '' then If SupplementInst NE {SUPPL_INST} then // Supplement information has been added or updated. ChangeDetected = True$ Action = 'Add' {SUPPLEMENT} = True$ {SUPPL_INST} = SupplementInst {SUPPL_ENTRY_DATE} = date() {SUPPL_ENTRY_TIME} = time() If Username NE '' then {SUPPL_ENTRY_ID} = Username end else {SUPPL_ENTRY_ID} = @User4 end end end else If SupplementInst NE {SUPPL_INST} then // Supplement information has been removed. ChangeDetected = True$ Action = 'Remove' {SUPPLEMENT} = False$ {SUPPL_INST} = '' {SUPPL_ENTRY_DATE} = '' {SUPPL_ENTRY_TIME} = '' {SUPPL_ENTRY_ID} = '' end end If ChangeDetected And Action EQ 'Add' then Database_Services('WriteDataRow', 'RDS', @ID, @RECORD) RDSNotificationListAdd<-1> = @ID end If ChangeDetected And Action EQ 'Remove' then Database_Services('WriteDataRow', 'RDS', @ID, @RECORD) RDSNotificationListRemove<-1> = @ID end end else Error_Services('Add', 'Error reading RDS Record ' : @ID : ' in the ' : Service : ' service.') end Next Row end else Error_Services('Add', 'Error opening RDS dictionary in the ' : Service : ' service.') end end else Error_Services('Add', 'SupplementList argument was missing from the ' : Service : ' service.') end // Now send an email notification IF RDSNotificationListAdd NE '' then Instructions = XLATE('RDS', RDSNotificationListAdd<1>, RDS_SUPPL_INST$, 'X') PSN = XLATE('RDS', RDSNotificationListAdd<1>, RDS_PROD_SPEC_ID$, 'X') WoNo = XLATE('RDS', RDSNotificationListAdd<1>, RDS_WO$, 'X') ReactorNo = XLATE('RDS', RDSNotificationListAdd<1>, RDS_REACTOR$, 'X'); Message = 'This Supplement was created or updated by ':oconv( @user4, '[XLATE_CONV,LSL_USERS*FIRST_LAST]' ):' on ':OCONV( DATE(), 'D2/' ):' at ':OCONV( TIME(), 'MTH' ):'.' : CRLF$ Message := 'WO# : ' : WoNo : CRLF$ Message := 'PSN : ' : PSN : CRLF$ Message := 'Reactor No : ' : ReactorNo : CRLF$ //Message := 'Instructions : ' : Instructions Message := CRLF$ Message := 'RDS #s : ' : CRLF$ for each RDSNo in RDSNotificationListAdd using @FM Message := RDSNo : ' - ': XLATE('RDS', RDSNo, RDS_SUPPL_INST$, 'X') :CRLF$ Next RDSNo Recipients = XLATE('NOTIFICATION','SUPPLEMENTS',NOTIFICATION_USER_ID$,'X') SendFrom = 'System' Subject = 'New or Updated Supplement Created for WO# ': WoNo AttachWindow = '' AttachKey = '' SendToGroup = '' Parms = Recipients:@RM:SendFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup obj_Notes('Create',Parms) end IF RDSNotificationListRemove NE '' then Instructions = XLATE('RDS', RDSNotificationListRemove<1>, RDS_SUPPL_INST$, 'X') PSN = XLATE('RDS', RDSNotificationListRemove<1>, RDS_PROD_SPEC_ID$, 'X') WoNo = XLATE('RDS', RDSNotificationListRemove<1>, RDS_WO$, 'X') ReactorNo = XLATE('RDS', RDSNotificationListRemove<1>, RDS_REACTOR$, 'X'); Message = 'This Supplement was removed by ':oconv( @user4, '[XLATE_CONV,LSL_USERS*FIRST_LAST]' ):' on ':OCONV( DATE(), 'D2/' ):' at ':OCONV( TIME(), 'MTH' ):'.' : CRLF$ Message := 'WO# : ' : WoNo : CRLF$ Message := 'PSN : ' : PSN : CRLF$ Message := 'Reactor No : ' : ReactorNo : CRLF$ //Message := 'Instructions : ' : Instructions Message := CRLF$ Message := 'RDS #s : ' : CRLF$ for each RDSNo in RDSNotificationListRemove using @FM Message := RDSNo :CRLF$ Next RDSNo Recipients = XLATE('NOTIFICATION','SUPPLEMENTS',NOTIFICATION_USER_ID$,'X') SendFrom = 'System' Subject = 'Supplement Removed for WO# ': WoNo AttachWindow = '' AttachKey = '' SendToGroup = '' Parms = Recipients:@RM:SendFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup obj_Notes('Create',Parms) end end service //---------------------------------------------------------------------------------------------------------------------- // IsEpiPro // // RDSNo. - [Required] // // Returns True$ if RDS is an EpiPro run, False$ otherwise. //---------------------------------------------------------------------------------------------------------------------- Service IsEpiPro(RDSNo) ReactorType = Xlate('RDS', RDSNo, 'PS_REACTOR_TYPE', 'X') IsEpiPro = ( (ReactorType _EQC 'EPP') or (ReactorType _EQC 'P') or (ReactorType _EQC 'EpiPro') ) 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) // Note: We need to use the Quote function before comparing values because OpenInsight // fails to compare strings that start with numbers. IsValid = False$ Begin Case Case RDSType EQ 'SIC' CompareLot = Xlate('RDS', RDSNo, RDS_LOT_NUM$, 'X') If Quote(CompareLot) EQ Quote(SupplierLot) then IsValid = True$ Case RDSType EQ 'EPP' Convert '.' to '*' in RDSNo CompareLot = Xlate('WM_IN', RDSNo, 'LOT_NO', 'X') If Quote(CompareLot) EQ Quote(SupplierLot) then IsValid = True$ Case RDSType EQ 'GAN' Convert '.' to '*' in RDSNo CompareLot = Xlate('WO_MAT', RDSNo, WO_MAT_LOT_NO$, 'X') If Quote(CompareLot) EQ Quote(SupplierLot) then IsValid = True$ End Case Response = IsValid end service Service GetRDSRunHistoryByReactorAndWO(ReactorNo, WO) StartTick = GetTickCount() MetricName = 'GetRDSRunHistoryByReactorAndWO' table = "RDS" ErrorMessage = '' RDSRecords = '' RDSSortedByAssignmentDTM = '' Open "DICT ":table To @DICT Else ErrorMessage = 'Error opening RDS dictionary' End If ErrorMessage EQ '' then srch_strng = "WO":@VM:WO:@FM:"REACTOR":@VM:ReactorNo:@FM option = "" flag = "" Btree.Extract(srch_strng, table, @DICT, RDSRecords, option, flag) end RDSRecordsWithPreEpiSig = '' for each RDSKey in RDSRecords using @VM setting RDSPos ThisRDSRec = Database_Services('ReadDataRow', 'RDS', RDSKey, True$, 0, False$) ThisRDSPreEpiDT = ThisRDSRec 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> EndTick = GetTickCount() Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick) end service Service IsTWLoggingReqd(RDSNo) StartTick = GetTickCount() MetricName = 'IsTWLoggingReqd' IsTWReqd = False$ ExistingTWRuns = Test_Run_Services('GetTestRunKeysByRDS', RDSNo) If ExistingTWRuns EQ '' then RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo) WONo = RDSRec 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' AND WaferType NE '' then BEGIN CASE CASE MeasureFreq = 'F' AND ThisReactorRunOrder = 1 ; IsTWReqd = 1 CASE ThisReactorRunOrder = Start ; IsTWReqd = 1 CASE NUM(MeasureFreq) Begin Case Case ReactorType EQ 'HTR' //Logging required on lot the data gets logged to IF MOD(ThisReactorRunOrder,MeasureFreq) - Start = 0 THEN IsTWReqd = True$ END Case ReactorType EQ 'ASM' //Logging required on lot the data gets logged to IF MOD(ThisReactorRunOrder,MeasureFreq) - Start = 0 THEN IsTWReqd = True$ END Case ReactorType EQ 'ASM+' //Logging required on lot prior to the one the data gets logged to. IF MOD(ThisReactorRunOrder,MeasureFreq) = 0 THEN IsTWReqd = True$ END End Case END CASE end Until IsTWReqd EQ True$ Next PRSPropKey Until IsTWReqd EQ True$ Next PRSLayerKey end else IsTWReqd = False$ end //The code below will be removed upon final production usage. TWTrackingSystemActive = Database_Services('ReadDataColumn', 'APP_INFO', 'NEW_TW_SYSTEM_ACTIVE_SWITCH', 1, True$, 0, False$) If TWTrackingSystemActive EQ False$ then IsTWReqd = False$ end Response = IsTWReqd EndTick = GetTickCount() Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick) end service Service TestWaferRanAfterLoad(RDSNo) TestWaferRanAfterLoad = False$ TestWaferKeys = Test_Run_Services('GetTestRunKeysByRDS', RDSNo) for each Key in TestWaferKeys using @VM TestWaferDtm = Xlate('TEST_RUN', Key, TEST_RUN_RUN_DTM$, 'X') TestWaferDate = SRP_DateTime('Date', TestWaferDtm) TestWaferTime = SRP_DateTime('Time', TestWaferDtm) RdsDateIn = Xlate('RDS', RDSNo, RDS_DATE_IN$, 'X') RdsTimeIn = Xlate('RDS', RDSNo, RDS_TIME_IN$, 'X') TestWaferRanAfterLoad = TestWaferDate > RdsDateIn If TestWaferRanAfterLoad EQ False$ then TestWaferRanAfterLoad = (TestWaferDate EQ RdsDateIn) and TestWaferTime GT RdsTimeIn end Until TestWaferRanAfterLoad EQ True$ Next Key Response = TestWaferRanAfterLoad end service //---------------------------------------------------------------------------------------------------------------------- // VerifyEPPMetrology // // RDSNo. - [Required] // // Sets an error in Error_Services if there is an issue with the metrology data. //---------------------------------------------------------------------------------------------------------------------- Service VerifyEPPMetrology(RDSNo) If RDSNo NE '' then ErrorMsg = '' // ActivateRecord allows for the use of the curly brace notation {} Database_Services('ActivateRecord', 'RDS', RDSNo) If {REACTOR_TYPE} EQ 'EPP' then LayerList = '' LayerList = {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 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 END END END NEXT I end else ErrorMsg = 'Non-EpiPro RDS passed to RDS_Services(':Service:')' end end else ErrorMsg = 'Null RDS value passed to RDS_Services(':Service:')' end If ErrorMsg NE '' then Error_Services('Add', ErrorMsg) end service Service RDSVerifyInst(RDSNo, Stage=STAGES) Database_Services('ActivateRecord', 'RDS', RDSNo) VerInst = '' Begin Case Case Stage EQ 'PRE' VerInst = {PRE_INST} Case Stage EQ 'FWI' VerInst = {FWI_INST} Case Stage EQ 'LWI' VerInst = {LWI_INST} Case Stage EQ 'QA' VerInst = {QA_INST} Case Stage EQ 'LOAD' VerInst = {LOAD_INST} Case Stage EQ 'UNLOAD' VerInst = {UNLOAD_INST} Case Stage EQ 'POST' VerInst = {POST_INST} End Case Response = Dialog_Box('RDS_VER', @Window, VerInst) Begin Case Case Stage EQ 'PRE' {PRE_INST_ACK} = Response Case Stage EQ 'FWI' {FWI_INST_ACK} = Response Case Stage EQ 'LWI' {LWI_INST_ACK} = Response Case Stage EQ 'QA' {QA_INST_ACK} = Response Case Stage EQ 'LOAD' {LOAD_INST_ACK} = Response Case Stage EQ 'UNLOAD' {UNLOAD_INST_ACK} = Response Case Stage EQ 'POST' {POST_INST_ACK} = Response End Case Database_Services('WriteDataRow', 'RDS', RDSNo, @Record, True$, False$, True$) end service Service CopyRDSLayerParameters(RDSNo) StartTick = GetTickCount() MetricName = 'CopyRDSLayerParameters' ErrMsg = '' 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 Until ErrMsg NE '' // Copy RDS layer records LayerID = Field(CopyRDSLayerKey, '*', 2) DestRDSLayerKey = RDSNo:'*':LayerID CopyRDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', CopyRDSLayerKey) if Error_Services('NoError') then DestRDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', DestRDSLayerKey) If Error_Services('NoError') then 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$) If Error_Services('HasError') then ErrMsg = Error_Services('GetMessage') end end else ErrMsg = Error_Services('GetMessage') end end else ErrMsg = Error_Services('GetMessage') end Next CopyRDSLayerKey end end else ErrMsg = 'No previous run to copy RDS layer parameters from in ':Service:' service.' end end else ErrMsg = 'RDSNo not supplied in ':Service:' service.' end EndTick = GetTickCount() Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick) If ErrMsg NE '' then Error_Services('Add', ErrMsg) 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) ErrorMsg = '' 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$, False$) If Error_Services('NoError') then Reactor = RDSRec Reactor_Services('RemoveRDSFromReactorLoad', RDSNo, Reactor, LSLUserName) end else ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = 'Unload Extra 1 is not able to be signed at this stage' end end else ErrorMsg = 'RDS ' : RDSNo : ' does not exist.' end end else ErrorMsg = 'Invalid user passed to Sign Unload Extra 1 routine' end If ErrorMsg NE '' then Error_Services('Add', 'Error signing Unload Extra 1 : ' : ErrorMsg) end end service Service UnsignUnloadExtra1(RDSNo, LSLUserName) ErrorMsg = '' 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 = '' Reactor = RDSRec Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, False$) If Error_Services('NoError') then Reactor_Services('AddRDSToReactorLoad', RDSNo, Reactor) end else ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = 'Unsign Load Extra 1 is not able to be unsigned.' end end else ErrorMsg = 'Reactor #' : Reactor : ' does not currently have the capacity to be loaded. Unload a lot to allow.' end end else ErrorMsg = 'RDS is not assigned to a reactor.' end end else ErrorMsg = 'RDS ' : RDSNo : ' does not exist.' end end else ErrorMsg = 'Invalid user passed to Unsign Load Extra 1 routine' end If ErrorMsg NE '' then Error_Services('Add', ErrorMsg) end end service Service SignLoadExtra1(RDSNo,LSLUserName) ErrorMsg = '' 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$, False$) If Error_Services('NoError') then Reactor_Services('AddRDSToReactorLoad', RDSNo, Reactor) end else ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = 'Load Extra 1 is not able to be signed at this stage' end end else ErrorMsg = 'Reactor #' : Reactor : ' does not currently have the capacity to be loaded. Unload a lot to allow.' end end else ErrorMsg = 'RDS is not assigned to a reactor.' end end else ErrorMsg = 'RDS ' : RDSNo : ' does not exist.' end end else ErrorMsg = 'Invalid user passed to Sign Unload Extra 1 routine' end If ErrorMsg NE '' then Error_Services('GetMessage') end end service Service UnsignLoadExtra1(RDSNo, LSLUserName) ErrorMsg = '' 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 = '' Reactor = RDSRec Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, False$) If Error_Services('NoError') then Reactor_Services('RemoveRDSFromReactorLoad', RDSNo, Reactor, LSLUserName) end else ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = 'Unsign Load Extra 1 is not able to be unsigned.' end end else ErrorMsg = 'RDS ' : RDSNo : ' does not exist.' end end else ErrorMsg = 'Invalid user passed to Unsign Load Extra 1 routine' end If ErrorMsg NE '' then Error_Services('Add', ErrorMsg) end end service Service SignUnloadExtra2(RDSNo,LSLUserName) ErrorMsg = '' 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$, False$) If Error_Services('NoError') then Reactor = RDSRec Reactor_Services('RemoveRDSFromReactorLoad', RDSNo, Reactor, LSLUserName) end else ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = 'Unload Extra 2 is not able to be signed at this stage' end end else ErrorMsg = 'RDS ' : RDSNo : ' does not exist.' end end else ErrorMsg = 'Invalid user passed to Sign Unload Extra 1 routine' end If ErrorMsg NE '' then Error_Services('Add', ErrorMsg) end end service Service UnsignUnloadExtra2(RDSNo, LSLUserName) ErrorMsg = '' 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 = '' Reactor = RDSRec Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, False$) If Error_Services('NoError') then Reactor_Services('AddRDSToReactorLoad', RDSNo, Reactor) end else ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = 'Unsign Load Extra 2 is not able to be unsigned.' end end else ErrorMsg = 'Reactor #' : Reactor : ' does not currently have the capacity to be loaded. Unload a lot to allow.' end end else ErrorMsg = 'RDS is not assigned to a reactor.' end end else ErrorMsg = 'RDS ' : RDSNo : ' does not exist.' end end else ErrorMsg = 'Invalid user passed to Unsign Unload Extra 1 routine' end If ErrorMsg NE '' then Error_Services('Add', ErrorMsg) end end service Service SignLoadExtra2(RDSNo,LSLUserName) ErrorMsg = '' 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$, False$) If Error_Services('NoError') then Reactor_Services('AddRDSToReactorLoad', RDSNo, Reactor) end else ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = 'Load Extra 2 is not able to be signed at this stage' end end else ErrorMsg = 'Reactor #' : Reactor : ' does not currently have the capacity to be loaded. Unload a lot to allow.' end end else ErrorMsg = 'RDS is not assigned to a reactor.' end end else ErrorMsg = 'RDS ' : RDSNo : ' does not exist.' end end else ErrorMsg = 'Invalid user passed to Sign Unload Extra 2 routine' end If ErrorMsg NE '' then Error_Services('Add', ErrorMsg) end end service Service UnsignLoadExtra2(RDSNo, LSLUserName) ErrorMsg = '' 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 = '' Reactor = RDSRec Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, False$) If Error_Services('NoError') then Reactor_Services('RemoveRDSFromReactorLoad', RDSNo, Reactor, LSLUserName) end else ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = 'Unsign Load Extra 2 is not able to be unsigned.' end end else ErrorMsg = 'RDS ' : RDSNo : ' does not exist.' end end else ErrorMsg = 'Invalid user passed to Unsign Unload Extra 1 routine' end If ErrorMsg NE '' then Error_Services('Add', ErrorMsg) end end service Service ApplyQA100PercentADE(RDSNo) Result = False$ ErrorMsg = '' If RDSNo NE '' then // Change the QA metrology requirements to all wafers WoNo = Xlate('RDS', RDSNo, RDS_WO$, 'X') CassNo = Xlate('RDS', RDSNo, 'CASS_NO', 'X') WoMatQaKey = WoNo : '*' : CassNo WoMatQaRec = Xlate('WO_MAT_QA', WoMatQaKey, '', 'X') EpiCheck = Rds_Services('IsEpiPro', RDSNo) If EpiCheck EQ True$ then WoWaferQty = Xlate('WO_MAT', WoMatQaKey, WO_MAT_WAFER_QTY$, 'X') end else WoWaferQty = Xlate('RDS', RDSNo, 'WFRS_OUT', 'X') end WoMatQaStages = WoMatQaRec WoMatQaProfiles = WoMatQaRec WoMatQaProps = WoMatQaRec WoMatQaToolClasses = WoMatQaRec WoMatQaRecipes = WoMatQaRec WoMatQaRecipePatterns = WoMatQaRec WoMatQaMin = WoMatQaRec WoMatQaMax = WoMatQaRec WoMatQaSlots = WoMatQaRec WoMatQaSlotTests = WoMatQaRec WoMatQaResults = WoMatQaRec WoMatQaStdMaxes = WoMatQaRec WoMatQaStdResults = WoMatQaRec WoMatQaSigs = WoMatQaRec WoMatQaSigDtms = WoMatQaRec WoMatQaWfrQtys = WoMatQaRec WoMatQaWfrTypes = WoMatQaRec WoMatQaReactScheds = WoMatQaRec WoMatQaShipDocs = WoMatQaRec WoMatQaDataPoints = WoMatQaRec WoMatQaMinResults = WoMatQaRec WoMatQaMaxResults = WoMatQaRec WoMatQaRngResults = WoMatQaRec WoMatQaEdgeResults = WoMatQaRec WoMatQa5mmResults = WoMatQaRec WoMatQaOOS = WoMatQaRec WoMatQaPhaseMins = WoMatQaRec WoMatQaFailReasons = WoMatQaRec StageCount = DCount(WoMatQaStages, @VM) StageIdxToDelete = '' 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 WoMatQaSigs<0, stageIdx> = '' WoMatQaSigDtms<0, stageIdx> = '' WoMatQaResults<0, stageIdx> = '' WoMatQaDataPoints<0, stageIdx> = '' WoMatQaMinResults<0, stageIdx> = '' WoMatQaMaxResults<0, stageIdx> = '' WoMatQaRngResults<0, stageIdx> = '' WoMatQaEdgeResults<0, stageIdx> = '' WoMatQa5mmResults<0, stageIdx> = '' end If (Slot _EQC 'L') then StageIdxToDelete = stageIdx end end Next stageIdx If (StageIdxToDelete NE '') then WoMatQaStages = Delete(WoMatQaStages, 0, StageIdxToDelete, 0) WoMatQaProfiles = Delete(WoMatQaProfiles, 0, StageIdxToDelete, 0) WoMatQaProps = Delete(WoMatQaProps, 0, StageIdxToDelete, 0) WoMatQaToolClasses = Delete(WoMatQaToolClasses, 0, StageIdxToDelete, 0) WoMatQaRecipes = Delete(WoMatQaRecipes, 0, StageIdxToDelete, 0) WoMatQaRecipePatterns = Delete(WoMatQaRecipePatterns, 0, StageIdxToDelete, 0) WoMatQaMin = Delete(WoMatQaMin, 0, StageIdxToDelete, 0) WoMatQaMax = Delete(WoMatQaMax, 0, StageIdxToDelete, 0) WoMatQaSlots = Delete(WoMatQaSlots, 0, StageIdxToDelete, 0) WoMatQaSlotTests = Delete(WoMatQaSlotTests, 0, StageIdxToDelete, 0) WoMatQaResults = Delete(WoMatQaResults, 0, StageIdxToDelete, 0) WoMatQaSigs = Delete(WoMatQaSigs, 0, StageIdxToDelete, 0) WoMatQaSigDtms = Delete(WoMatQaSigDtms, 0, StageIdxToDelete, 0) WoMatQaStdMaxes = Delete(WoMatQaStdMaxes, 0, StageIdxToDelete, 0) WoMatQaStdResults = Delete(WoMatQaStdResults, 0, StageIdxToDelete, 0) WoMatQaWfrQtys = Delete(WoMatQaWfrQtys, 0, StageIdxToDelete, 0) WoMatQaWfrTypes = Delete(WoMatQaWfrTypes, 0, StageIdxToDelete, 0) WoMatQaReactScheds = Delete(WoMatQaReactScheds, 0, StageIdxToDelete, 0) WoMatQaShipDocs = Delete(WoMatQaShipDocs, 0, StageIdxToDelete, 0) WoMatQaDataPoints = Delete(WoMatQaDataPoints, 0, StageIdxToDelete, 0) WoMatQaMinResults = Delete(WoMatQaMinResults, 0, StageIdxToDelete, 0) WoMatQaMaxResults = Delete(WoMatQaMaxResults, 0, StageIdxToDelete, 0) WoMatQaRngResults = Delete(WoMatQaRngResults, 0, StageIdxToDelete, 0) WoMatQaEdgeResults = Delete(WoMatQaEdgeResults, 0, StageIdxToDelete, 0) WoMatQa5mmResults = Delete(WoMatQa5mmResults, 0, StageIdxToDelete, 0) WoMatQaOOS = Delete(WoMatQaOOS, 0, StageIdxToDelete, 0) WoMatQaPhaseMins = Delete(WoMatQaPhaseMins, 0, StageIdxToDelete, 0) WoMatQaFailReasons = Delete(WoMatQaFailReasons, 0, StageIdxToDelete, 0) end WoMatQaRec = WoMatQaStages WoMatQaRec = WoMatQaProfiles WoMatQaRec = WoMatQaProps WoMatQaRec = WoMatQaToolClasses WoMatQaRec = WoMatQaRecipes WoMatQaRec = WoMatQaRecipePatterns WoMatQaRec = WoMatQaMin WoMatQaRec = WoMatQaMax WoMatQaRec = WoMatQaSlots WoMatQaRec = WoMatQaSlotTests WoMatQaRec = WoMatQaResults WoMatQaRec = WoMatQaSigs WoMatQaRec = WoMatQaSigDtms WoMatQaRec = WoMatQaStdMaxes WoMatQaRec = WoMatQaStdResults WoMatQaRec = WoMatQaWfrQtys WoMatQaRec = WoMatQaWfrTypes WoMatQaRec = WoMatQaReactScheds WoMatQaRec = WoMatQaShipDocs WoMatQaRec = WoMatQaDataPoints WoMatQaRec = WoMatQaMinResults WoMatQaRec = WoMatQaMaxResults WoMatQaRec = WoMatQaRngResults WoMatQaRec = WoMatQaEdgeResults WoMatQaRec = WoMatQa5mmResults WoMatQaRec = WoMatQaOOS WoMatQaRec = WoMatQaPhaseMins WoMatQaRec = WoMatQaFailReasons Database_Services('WriteDataRow', 'WO_MAT_QA', WoMatQaKey, WoMatQaRec, True$, False$, False$) If Error_Services('HasError') then ErrorMsg = Error_Services('GetMessage') end else ErrorMsg = 'Error in ':Service:' service. Null RdsKey passed into service!' end If ErrorMsg NE '' then Error_Services('Add', ErrorMsg) end else Result = True$ end end service Service ApplyAbortMetrology(RdsKeys) Result = False$ ErrorMsg = '' If RdsKeys NE '' then Convert @VM to @FM in RdsKeys If RowExists('RDS', RdsKeys) then For each RdsKey in RdsKeys using @FM WoNo = Xlate('RDS', RdsKey, RDS_WO$, 'X') // Set a flag on the CI record indicating the run was aborted CleanInspKey = Xlate('RDS', RdsKey, 'LWI_CI_NO', 'X') CIRec = Database_Services('ReadDataRow', 'CLEAN_INSP', CleanInspKey) CIRec = True$ Database_Services('WriteDataRow', 'CLEAN_INSP', CleanInspKey, CIRec, True$, False$, False$) If Error_Services('HasError') then ErrorMsg = Error_Services('GetMessage') If ErrorMsg EQ '' then Result = Rds_Services('ApplyQA100PercentADE', RDSKey) If Error_Services('HasError') then ErrorMsg = Error_Services('GetMessage') end Next RdsKey end else Convert @FM to ',' in RdsKeys ErrorMsg = 'Error in ':Service:' service. One or more Rds records (':RdsKeys:') do not exist!' end end else ErrorMsg = 'Error in ':Service:' service. Null RdsKeys passed into service!' end If ErrorMsg NE '' then Error_Services('Add', ErrorMsg) end else Result = True$ end end service Service DetachRDSFromWO(RDSNo) ErrorMessage = '' If RowExists('RDS', RDSNo) then RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo) if Error_Services('NoError') then RDSRec = '' RDSRec = '' Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, False$, False$, False$) If Error_Services('HasError') then ErrorMessage = Error_Services('GetMessage') end end else ErrorMessage = Error_Services('GetMessage') end end else ErrorMessage = 'Error detaching RDS ' : RDSNo ' from work order. RDS No not found in RDS table.' end If ErrorMessage NE '' then Error_Services('Add', ErrorMessage) end end service Service ChangeReactor(RDSNo, NewReactorNo) ErrorMessage = '' If RDSNo NE '' AND NewReactorNo NE '' then RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo) WONo = RDSRec Query = 'SELECT REACT_STATE WITH SCHED_WO CONTAINING ':WONo ClearSelect Set_Status(0) RList(Query, TARGET_ACTIVELIST$, '', '' '') SchedReactors = '' EOF = False$ Loop ReadNext SchedReactor else EOF = True$ Until EOF SchedReactors<0, -1> = SchedReactor Repeat Locate NewReactorNo in SchedReactors using @VM setting vPos then RDSRec = NewReactorNo Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, False$) If Error_Services('NoError') then Response = True$ end else Response = False$ ErrorMessage = Error_Services('GetMessage') end end else Swap @VM with ',' in SchedReactors ErrorMessage = 'Assigned reactor, ':NewReactorNo:', does not equal any scheduled reactor(s), ':SchedReactors:'.' Response = False$ end end else ErrorMessage = 'Missing RDSNo or NewReactorNo param.' end If ErrorMessage NE '' then Error_Services('Set', ErrorMessage) end end service Service PushSigProfileToWoMat(RDSNo) ErrorMsg = '' If (RDSNo NE '') then If RowExists('RDS', RDSNo) then Record = Database_Services('ReadDataRow', 'RDS', RDSNo) If Error_Services('NoError') then WONo = Record ReactType = Xlate('WO_LOG', WONo, 'REACT_TYPE', 'X') EpiPro = (ReactType EQ 'EPP') GaN = (ReactType EQ 'GAN') NonEpiPro = ( (ReactType NE 'EPP') and (ReactType NE 'GAN') ) If NonEpiPro then // Sync up VER, LOAD, UNLOAD, POST, and QA signatures with WO_MAT signature profile. // The goal of signature services was to remove any dependency on the WO_MAT signature profile, // however Fabtime relies on this data being replicated to the Scrape SQL DB. WOMatKey = Xlate('RDS', RDSNo, 'WO_MAT_KEY', 'X') If WOMatKey NE '' then WOMatRec = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey) If Error_Services('NoError') then WOMatSigProf = obj_WO_Mat('CassSigProfile', WOMatKey) WOMatSig = WOMatRec WOMatSigDTM = WOMatRec WOMatSigProfOrig = WOMatSigProf WOMatSigOrig = WOMatSig WOMatSigDTMOrig = WOMatSigDTM // Update WO_MAT signature profile to match for the "1VER" stage Stage = '1VER' Locate Stage in WOMatSigProf using @VM setting vPos then WOMatSig<0, vPos> = Record PreEpiDate = Record If PreEpiDate NE '' then PreEpiTime = Record PreEpiSigDTM = PreEpiDate + (PreEpiTime/86400) end else PreEpiSigDTM = '' end WOMatSigDTM<0, vPos> = PreEpiSigDTM end // Update WO_MAT signature profile to match for "1LOAD" stage Stage = '1LOAD' Locate Stage in WOMatSigProf using @VM setting vPos then WOMatSig<0, vPos> = Record DateIn = Record If DateIn NE '' then LoadTime = Record LoadSigDTM = DateIn + (LoadTime/86400) end else LoadSigDTM = '' end WOMatSigDTM<0, vPos> = LoadSigDTM end // Update WO_MAT signature profile to match for the "1UNLOAD" stage Stage = '1UNLOAD' Locate Stage in WOMatSigProf using @VM setting vPos then WOMatSig<0, vPos> = Record DateOut = Record If DateOut NE '' then TimeOut = Record TimeOutSigDTM = DateOut + (TimeOut/86400) end else TimeOutSigDTM = '' end WOMatSigDTM<0, vPos> = TimeOutSigDTM end // Update WO_MAT signature profile to match for the "1POST" stage Stage = '1POST' Locate Stage in WOMatSigProf using @VM setting vPos then WOMatSig<0, vPos> = Record PostSigDate = Record If PostSigDate NE '' then PostSigTime = Record PostSigDTM = PostSigDate + (PostSigTime/86400) end else PostSigDTM = '' end WOMatSigDTM<0, vPos> = PostSigDTM end // Update WO_MAT signature profile to match for the "1QA" stage Stage = '1QA' Locate Stage in WOMatSigProf using @VM setting vPos then WOMatSig<0, vPos> = Record FQADate = Record If FQADate NE '' then FQASigTime = Record FQASigDTM = FQADate + (FQASigTime/86400) end else FQASigDTM = '' end WOMatSigDTM<0, vPos> = FQASigDTM end If WOMatSigProf NE WOMatSigProfOrig then Transaction_Services('PostWriteFieldTransaction', 'WO_MAT', WOMatKey, WO_MAT_SIG_PROFILE$, WOMatSigProf) end If WOMatSig NE WOMatSigOrig then Transaction_Services('PostWriteFieldTransaction', 'WO_MAT', WOMatKey, WO_MAT_SIGNATURE$, WOMatSig) end If WOMatSigDTM NE WOMatSigDTMOrig then Transaction_Services('PostWriteFieldTransaction', 'WO_MAT', WOMatKey, WO_MAT_SIG_DTM$, WOMatSigDTM) end end else ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = 'Error in ':Service:' service. Null WO_MAT_KEY returned for RDS ':RDSNo:'.' end end end else ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = 'Error in ':Service:' service. RDS ':RDSNo:' does not exist.' end end else ErrorMsg = 'Error in ':Service:' service. Null RDSNo passed into service.' end If ErrorMsg NE '' then Error_Services('Add', ErrorMsg) end service Service AllTWUseSigned(RDSNo) If RDSNo NE '' then LSKeys = Xlate('RDS', RDSNo, 'RDS_LS_SORTED', 'X') AllMetKeys = XLATE('RDS_LAYER', LSKeys, RDS_LAYER_RDS_TEST_KEYS$, 'X') AllSigned = 1 FOR I = 1 TO COUNT(AllMetKeys,@VM) + (AllMetKeys NE '') MetKey = AllMetKeys<1,I> AllSigned = obj_RDS_Test('TWSignedOff',MetKey) UNTIL NOT(AllSigned) NEXT I Transaction_Services('PostWriteFieldTransaction', 'RDS', RDSNo, RDS_ALL_TW_USE_SIGNED$, AllSigned) ErrorMessage = '' If Error_Services('HasError') then ErrorMessage = Error_Services('GetMessage') end If ErrorMessage NE '' then ErrorMessage = 'Unable to determine if all TW Use have been signed for RDS ':RDSNo:', because ':ErrorMessage Error_Services('Add', ErrorMessage) end end end service Service GetRDSKeys(WONo) Response = '' ErrorMsg = '' If (WONo NE '') then If RowExists('WO_LOG', WONo) then TableName = 'RDS' SortList = 'RUN_ORDER_NUM' ReduceScript = 'WITH {WO} EQ ':Quote(WONo) Mode = NEXT_CUR$ Flag = '' Cursor = '' GoSub ClearCursors Reduce(ReduceScript, SortList, Mode, TableName, Cursor, Flag) If Flag then Select TableName by SortList using Cursor then EOF = False$ Loop Readnext KeyId using Cursor by AT else EOF = True$ Until EOF Response<0, -1> = KeyId Repeat end else ErrorMsg = 'Error in ':Service:' service. Error selecting ':TableName:' table.' end end else ErrorMsg = 'Error in ':Service:' service. Error calling Reduce' end end else ErrorMsg = 'Error in ':Service:' service. WO_LOG ':WONo:' does not exist.' end end else ErrorMsg = 'Error in ':Service:' service. Null WONo passed into service.' end If ErrorMsg NE '' then Error_Services('Add', ErrorMsg) end service Service VerifyWOMatRDSNoIndex(RDSNo) LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\RDS' LogDate = Oconv(Date(), 'D4/') LogTime = Oconv(Time(), 'MTS') LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' !RDS WO_MAT{RDS_NO} Log.csv' Headers = 'Logging DTM':@FM:'RDSNo':@FM:'WOMatKey':@FM:'Result' objVerifyRDSNoLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, COMMA$, Headers, '', False$, False$) LogData = '' LogData<1> = OConv(Datetime(), 'DT/^S') LogData<2> = RDSNo LogData<4> = 'Begin ':Service Logging_Services('AppendLog', objVerifyRDSNoLog, LogData, @RM, @FM) ErrorMsg = '' If RDSNo NE '' then If RowExists('RDS', RDSNo) then WOMatKey = Xlate('RDS', RDSNo, 'WO_MAT_KEY', 'X') If WOMatKey NE '' then WOMatRDSNo = Xlate('WO_MAT', WOMatKey, 'RDS_NO', 'X') LogData<1> = OConv(Datetime(), 'DT/^S') LogData<3> = WOMatKey Logging_Services('AppendLog', objVerifyRDSNoLog, LogData, @RM, @FM) If WOMatRDSNo EQ '' then LogData<1> = OConv(Datetime(), 'DT/^S') LogData<4> = 'RDSNo missing from WO_MAT record. Generating index transaction.' Logging_Services('AppendLog', objVerifyRDSNoLog, LogData, @RM, @FM) // Add index transaction to update RDS_NO relational index (target WO_MAT table) IndexTransactionRow = 'WO_MAT*RDS_NO*AR':@FM:RDSNo:@FM:"":@FM:WOMatKey:@FM Open "!RDS" to BangTable then Done = False$ For AttemptNo = 1 to NUM_ATTEMPTS$ If AttemptNo GT 1 then Delay(1) Lock BangTable, 0 then Read PendingTrans from BangTable, 0 else PendingTrans = '0':@FM PendingTrans := IndexTransactionRow Write PendingTrans on BangTable, 0 then LogData<1> = OConv(Datetime(), 'DT/^S') LogData<4> = 'Index transaction successfully added.' Logging_Services('AppendLog', objVerifyRDSNoLog, LogData, @RM, @FM) Done = True$ end else ErrorMsg = 'Unable to write index transaction to !RDS. ':RDSNo end Unlock BangTable, 0 else ErrorMsg = 'Unable to Open !RDS to add index transaction. ':RDSNo end else If AttemptNo GE NUM_ATTEMPTS$ then ErrorMsg = 'Unable to Lock !RDS to add index transaction. ':RDSNo end end Until Done or ErrorMsg Next AttemptNo end else ErrorMsg = 'Unable to Open !RDS to add index transaction. ':RDSNo end end else LogData<1> = OConv(Datetime(), 'DT/^S') LogData<4> = 'Index ok. RDSNo not missing from WO_MAT record.' Logging_Services('AppendLog', objVerifyRDSNoLog, LogData, @RM, @FM) end end else LogData<1> = OConv(Datetime(), 'DT/^S') LogData<4> = 'WO_MAT key for RDS ':RDSNo:' is null. Nothing to update.' Logging_Services('AppendLog', objVerifyRDSNoLog, LogData, @RM, @FM) end end end If ErrorMsg NE '' then LogData<1> = OConv(Datetime(), 'DT/^S') LogData<4> = ErrorMsg Logging_Services('AppendLog', objVerifyRDSNoLog, LogData, @RM, @FM) end LogData<1> = OConv(Datetime(), 'DT/^S') LogData<4> = 'End ':Service Logging_Services('AppendLog', objVerifyRDSNoLog, LogData, @RM, @FM) If ErrorMsg NE '' then Error_Services('Add', ErrorMsg) end service Service VerifyWOStepRDSKeyIndex(RDSNo) LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\RDS' LogDate = Oconv(Date(), 'D4/') LogTime = Oconv(Time(), 'MTS') LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' !RDS WO_STEP{RDS_KEY} Log.csv' Headers = 'Logging DTM':@FM:'RDSNo':@FM:'WOStep':@FM:'Result' objVerifyRDSKeyLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, COMMA$, Headers, '', False$, False$) LogData = '' LogData<1> = OConv(Datetime(), 'DT/^S') LogData<2> = RDSNo LogData<4> = 'Begin ':Service Logging_Services('AppendLog', objVerifyRDSKeyLog, LogData, @RM, @FM) ErrorMsg = '' If RDSNo NE '' then If RowExists('RDS', RDSNo) then WOStepKey = Xlate('RDS', RDSNo, 'WO_STEP_KEY', 'X') If WOStepKey NE '' then WOStepRDSKeys = Xlate('WO_STEP', WOStepKey, 'RDS_KEY', 'X') LogData<1> = OConv(Datetime(), 'DT/^S') LogData<3> = WOStepKey Logging_Services('AppendLog', objVerifyRDSKeyLog, LogData, @RM, @FM) Locate RDSNo in WOStepRDSKeys using @VM setting vPos then LogData<1> = OConv(Datetime(), 'DT/^S') LogData<4> = 'Index ok. RDSNo not missing from WO_STEP record.' Logging_Services('AppendLog', objVerifyRDSKeyLog, LogData, @RM, @FM) end else LogData<1> = OConv(Datetime(), 'DT/^S') LogData<4> = 'RDSNo missing from WO_STEP record. Generating index transaction.' Logging_Services('AppendLog', objVerifyRDSKeyLog, LogData, @RM, @FM) // Add index transaction to update RDS_KEY relational index (target WO_STEP table) IndexTransactionRow = 'WO_STEP*RDS_KEY*AR':@FM:RDSNo:@FM:"":@FM:WOStepKey:@FM Open "!RDS" to BangTable then Done = False$ For AttemptNo = 1 to NUM_ATTEMPTS$ If AttemptNo GT 1 then Delay(1) Lock BangTable, 0 then Read PendingTrans from BangTable, 0 else PendingTrans = '0':@FM PendingTrans := IndexTransactionRow Write PendingTrans on BangTable, 0 then LogData<1> = OConv(Datetime(), 'DT/^S') LogData<4> = 'Index transaction successfully added.' Logging_Services('AppendLog', objVerifyRDSKeyLog, LogData, @RM, @FM) Done = True$ end else ErrorMsg = 'Unable to write index transaction to !RDS. ':RDSNo end Unlock BangTable, 0 else ErrorMsg = 'Unable to Open !RDS to add index transaction. ':RDSNo end else If AttemptNo GE NUM_ATTEMPTS$ then ErrorMsg = 'Unable to Lock !RDS to add index transaction. ':RDSNo end end Until Done or ErrorMsg Next AttemptNo end else ErrorMsg = 'Unable to Open !RDS to add index transaction. ':RDSNo end end end else LogData<1> = OConv(Datetime(), 'DT/^S') LogData<4> = 'WO_STEP key for RDS ':RDSNo:' is null. Nothing to update.' Logging_Services('AppendLog', objVerifyRDSKeyLog, LogData, @RM, @FM) end end end If ErrorMsg NE '' then LogData<1> = OConv(Datetime(), 'DT/^S') LogData<4> = ErrorMsg Logging_Services('AppendLog', objVerifyRDSKeyLog, LogData, @RM, @FM) end LogData<1> = OConv(Datetime(), 'DT/^S') LogData<4> = 'End ':Service Logging_Services('AppendLog', objVerifyRDSKeyLog, LogData, @RM, @FM) If ErrorMsg NE '' then Error_Services('Add', ErrorMsg) end service Service VerifyWOLogRDSKeyIndex(RDSNo) LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\RDS' LogDate = Oconv(Date(), 'D4/') LogTime = Oconv(Time(), 'MTS') LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' !RDS RDS{WO} Log.csv' Headers = 'Logging DTM':@FM:'RDSNo':@FM:'WOStep':@FM:'Result' objVerifyRDSWoIndexLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, COMMA$, Headers, '', False$, False$) LogData = '' LogData<1> = OConv(Datetime(), 'DT/^S') LogData<2> = RDSNo LogData<4> = 'Begin ':Service Logging_Services('AppendLog', objVerifyRDSWoIndexLog, LogData, @RM, @FM) ErrorMsg = '' If RDSNo NE '' then If RowExists('RDS', RDSNo) then WONo = Xlate('RDS', RDSNo, 'WO', 'X') If WONo NE '' then WOLogRDSKeys = '' Extract_Si_Keys('RDS', 'WO', WONo, WOLogRDSKeys) LogData<3> = WONo Logging_Services('AppendLog', objVerifyRDSWoIndexLog, LogData, @RM, @FM) Locate RDSNo in WOLogRDSKeys using @VM setting vPos then LogData<1> = OConv(Datetime(), 'DT/^S') LogData<4> = 'Index ok. RDSNo not missing from Btree index.' Logging_Services('AppendLog', objVerifyRDSWoIndexLog, LogData, @RM, @FM) end else LogData<1> = OConv(Datetime(), 'DT/^S') LogData<4> = 'RDSNo missing from Btree index. Generating index transaction.' Logging_Services('AppendLog', objVerifyRDSWoIndexLog, LogData, @RM, @FM) // Add index transaction to update RDS_KEY relational index (target WO_STEP table) IndexTransactionRow = 'WO':@FM:RDSNo:@FM:"":@FM:WONo:@FM Open "!RDS" to BangTable then Done = False$ For AttemptNo = 1 to NUM_ATTEMPTS$ If AttemptNo GT 1 then Delay(1) Lock BangTable, 0 then Read PendingTrans from BangTable, 0 else PendingTrans = '0':@FM PendingTrans := IndexTransactionRow Write PendingTrans on BangTable, 0 then LogData<1> = OConv(Datetime(), 'DT/^S') LogData<4> = 'Index transaction successfully added.' Logging_Services('AppendLog', objVerifyRDSWoIndexLog, LogData, @RM, @FM) Done = True$ end else ErrorMsg = 'Error in ':Service:' service. Unable to write index transaction to !RDS. ':RDSNo end Unlock BangTable, 0 else ErrorMsg = 'Error in ':Service:' service. Unable to Open !RDS to add index transaction. ':RDSNo end else If AttemptNo GE NUM_ATTEMPTS$ then ErrorMsg = 'Error in ':Service:' service. Unable to Lock !RDS to add index transaction. ':RDSNo end end Until Done or ErrorMsg Next AttemptNo end else ErrorMsg = 'Error in ':Service:' service. Unable to Open !RDS to add index transaction. ':RDSNo end end end else LogData<1> = OConv(Datetime(), 'DT/^S') LogData<4> = 'WONo for RDS ':RDSNo:' is null. Nothing to update.' Logging_Services('AppendLog', objVerifyRDSWoIndexLog, LogData, @RM, @FM) end end end else ErrorMsg = 'Error in ':Service:' service. Null RDSNo passed in.' end If ErrorMsg NE '' then LogData<1> = OConv(Datetime(), 'DT/^S') LogData<4> = ErrorMsg Logging_Services('AppendLog', objVerifyRDSWoIndexLog, LogData, @RM, @FM) end LogData<1> = OConv(Datetime(), 'DT/^S') LogData<4> = 'End ':Service Logging_Services('AppendLog', objVerifyRDSWoIndexLog, LogData, @RM, @FM) If ErrorMsg NE '' then Error_Services('Add', ErrorMsg) end service Service CheckUserRDSModificationPerm(UserId) ErrorMsg = '' CanUserModify = False$ If UserId NE '' then If RowExists('LSL_USERS', UserId) then Begin Case Case MemberOf(UserId, 'ENGINEERING') CanUserModify = True$ Case MemberOf(UserId, 'OI_ADMIN') CanUserModify = True$ Case MemberOf(UserId, 'SUPERVISOR') CanUserModify = True$ Case MemberOf(UserId, 'LEAD') CanUserModify = True$ Case MemberOf(UserId, 'ENG_TECH') CanUserModify = True$ Case Otherwise$ CanUserModify = False$ End Case end else ErrorMsg = 'User not found in Users table.' end end else ErrorMsg = 'User Id was null.' end If ErrorMsg NE '' then Error_Services('Add', ErrorMsg) end Response = CanUserModify end service Service UnsignPreEpiSignature(RDSNo, UserId) LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\RDS\Signatures' LogDate = Oconv(Date(), 'D4/') LogTime = Oconv(Time(), 'MTS') LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Pre-Epi-Unsign.csv' Headers = 'Logging DTM':@FM:'RDS No.':@FM:'User':@FM:'Message' objPreEpiUnsignLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, COMMA$, Headers, '', False$, False$) LoggingDTM = LogDate : ' ' : LogTime ErrorMsg = '' PreEpiUnsign = False$ If RDSNo NE '' then If RowExists('RDS', RDSNo) then if UserId NE '' then if RowExists('LSL_USERS', UserId) then CanUserModifyRDS = RDS_Services('CheckUserRDSModificationPerm', UserId) If Error_Services('NoError') then If CanUserModifyRDS then UnsignPreEpiReady = QA_Services('UnsignPreEpiReady', RDSNo) if Error_Services('NoError') then If UnsignPreEpiReady then RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo, True$, 0, False$) if Error_Services('NoError') then RDSRec = '' RDSRec = '' RDSRec = '' RDSRec = '' RDSRec = '' Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, False$) If Error_Services('NoError') then PreEpiUnsign = True$ end else ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = 'Pre Epi is unable to be unsigned because a signature beyond pre-epi exists.' end end else ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = 'User does not have permissions to perform a Pre-Epi Unsign' end end else ErrorMsg = Error_Services('GetMessage') end end else ErrorMsg = 'User ' : UserId : ' not found in database.' end end else ErrorMsg = 'User Id was null.' end end else ErrorMsg = 'RDS ' : RDSNo : ' not found in database.' end end else ErrorMsg = 'RDS Number was null.' end If ErrorMsg EQ '' then LogData = '' LogData<1> = LoggingDTM LogData<2> = RDSNo LogData<3> = UserId LogData<4> = 'Successfully unsigned pre-epi signature.' Logging_Services('AppendLog', objPreEpiUnsignLog, LogData, @RM, @FM, False$) end else LogData = '' LogData<1> = LoggingDTM LogData<2> = RDSNo LogData<3> = UserId LogData<4> = ErrorMsg Logging_Services('AppendLog', objPreEpiUnsignLog, LogData, @RM, @FM, False$) Error_Services('Add', ErrorMsg) end Response = PreEpiUnsign end service Service GetRdsZpl(RdsKey) ZPL = '' ErrorMsg = '' If RdsKey NE '' then If RowExists('RDS', RdsKey) then Update_Index ("RDS", "WO", "") UniqueWOs = '' CustNos = '' CompositeKeys = '' WONo = XLATE('RDS',RdsKey,RDS_WO$,'X') WOStepKey = Xlate('RDS', RdsKey, 'WO_STEP_KEY', 'X') CustNo = XLATE('WO_LOG',WONo,WO_LOG_CUST_NO$,'X') WOLogRec = XLATE('WO_LOG',WONo,'','X') CassNo = XLATE('RDS',RdsKey,'CASS_NO','X') WOMatRec = XLATE('WO_MAT',WONo:'*':CassNo,'','X') ReShipCustNo = WOMatRec ReShipDate = WOMatRec ReShipCustEpiPartNo = WOMatRec ReShipCustPO = WOMatRec ReShipCustPartNo = WOMatRec If ReShipCustNo EQ '' then CustNo = WOLogRec CustName = XLATE( 'RDS', RdsKey, 'ABBREV_OR_CO_NAME', 'X' ) CustName = XLATE( 'COMPANY', CustNo, 'ABBREV_OR_CO_NAME', 'X' ) end else CustNo = ReShipCustNo CompRec = XLATE('COMPANY',CustNo,'','X') CustName = CompRec end If ReShipCustEpiPartNo EQ '' then EpiPartNo = WOLogRec end else EpiPartNo = ReShipCustEpiPartNo end EpiPartRec = XLATE('EPI_PART',EpiPartNo,'','X') CustEpiPartRec = XLATE('CUST_EPI_PART',CustNo:'*':EpiPartNo,'','X') CustEpiPartSpecNo = CustEpiPartRec[-1,'B':@VM] ;* Last (current) Customer Spec Number ShipBagReq = CustEpiPartRec If ReShipDate EQ '' then ReqShipDate = OCONV( XLATE( 'WO_LOG', WO, WO_LOG_PROMISE_SHIP_DT$, 'X' ), 'D2/' ) end else ReqShipDate = ReShipDate end If ReShipCustPO EQ '' then IF CustNo = '7108' THEN PO = '' ;* Changed for "Foundry" customer additions 8/28/2012 JCH ********** END ELSE PO = XLATE( 'RDS', RdsKey, rds_po$, 'X' ) END end else PO = ReShipCustPO end If ReShipCustPartNo EQ '' then PartNum = XLATE( 'RDS', RdsKey, rds_part_num$, 'X' ) end else PartNum = ReShipCustPartNo end ThickTarget = OCONV( XLATE( 'RDS', RdsKey, 'THICK_TARGET_ALL', 'X' ), 'MD3' ) ThickUnit = XLATE( 'RDS', RdsKey, 'THICK_UNITS_ALL', 'X' ) Dopant = XLATE( 'RDS', RdsKey, 'DOPANT_L1', 'X' ) ResTarget = OCONV( XLATE( 'RDS', RdsKey, 'RES_TARGET_ALL', 'X' ), 'MD3' ) ResUnit = XLATE( 'RDS', RdsKey, 'RES_UNITS_ALL', 'X' ) RecipeIDS = XLATE( 'RDS', RdsKey, 'RECIPE_NO', 'X' ) LotNum = XLATE( 'RDS', RdsKey, rds_lot_num$, 'X' ) RONum = XLATE( 'RDS', RdsKey, 'RUN_ORDER_NUM', 'X' ) PSNo = XLATE( 'RDS', RdsKey, rds_prod_spec_id$, 'X' ) SpecType = OCONV( XLATE( 'RDS', RdsKey, 'SPEC_TYPE', 'X' ), '[SPEC_TYPE_CONV]' ) SubPartNum = XLATE( 'RDS', RdsKey, 'SUB_PART_NUM', 'X' ) RecipeInfo = XLATE( 'RECIPE', RecipeIDS, 'RECIPE_NAME_NO', 'X' ) ThickVar = XLATE( 'PROD_SPEC', PSNo, 'THICK_MEASURE_L1', 'X' ) ResVar = XLATE( 'PROD_SPEC', PSNo, 'RES_MEASURE_L1', 'X' ) ConVar = XLATE( 'PROD_SPEC', PSNo, 'CON_MEASURE_L1', 'X' ) StressVar = XLATE( 'PROD_SPEC', PSNo, 'STRESS_MEASURE', 'X' ) TransVar = XLATE( 'PROD_SPEC', PSNo, 'TRANS_MEASURE', 'X' ) ReactTypes = OCONV( XLATE( 'PROD_SPEC', PSNo, 'REACTOR_TYPE', 'X' ), '[REACT_TYPE_CONV,CODE]') SubOxide = OCONV(EpiPartRec,'B') SubPreCleans = '' SubPostCleans = '' PreAkrionRecipes = '' PostAkrionRecipes = '' SubPreCleans = XLATE('PRS_STAGE',PSNo:'*PRE','TOOL_DISPLAY','X') SubPostCleans = XLATE('PRS_STAGE',PSNo:'*POST','TOOL_DISPLAY','X') PreAkrionRecipes = XLATE('PRS_STAGE',PSNo:'*PRE',PRS_STAGE_CLEAN_RECIPE$,'X') PostAkrionRecipes = XLATE('PRS_STAGE',PSNo:'*POST',PRS_STAGE_CLEAN_RECIPE$,'X') SWAP 'AKRION' WITH 'Akr' IN SubPreCleans SWAP 'AKRION' WITH 'Akr' IN SubPostCleans SWAP ' or ' WITH '/' IN SubPreCleans SWAP ' or ' WITH '/' IN SubPostCleans ;* To wide for field on small label "squeezed" data to fit JCH SubPartNum = XLATE( 'RDS', RdsKey, 'SUB_PART_NUM', 'X' ) WOStepKeys = XLATE( 'RDS',RdsKey,RDS_WO_STEP_KEY$,'X' ) ;* 05/21/2005 - JCH - Added for Order Entry/Vision upgrade IF CustNo = '7108' THEN CustPNDescs = '' ;* 8/28/2012 - JCH Added for new "Foundry" customer ****************** END ELSE CustPNDescs = XLATE('EPI_PART',EpiPartNo,EPI_PART_EPI_PART_DESC$,'X') ;* 12/2/2011 - JCH Added for SAP interface END ************************************ PreSurfscan = XLATE( 'PRS_STAGE', PSNo:'*PRE' , PRS_STAGE_SURFSCAN_SIG_REQ$ , 'X' ) FirstSurfscan = XLATE( 'PRS_STAGE', PSNo:'*FWI' , PRS_STAGE_SURFSCAN_SIG_REQ$ , 'X' ) PostCleanSurfscan = XLATE( 'PRS_STAGE', PSNo:'*POST' , PRS_STAGE_SURFSCAN_SIG_REQ$ , 'X' ) CleaningReqs = '' SRPFlag = XLATE( 'PROD_SPEC', PSNo, 'SRP_REQ', 'X' ) ;* Updated in PROD_SPEC dictionary JCH 4/21/2015 Qtys = XLATE( 'RDS', RdsKey, 'WAFERS_SCHEDULED', 'X' ) MultilayVar = XLATE( 'RDS', RdsKey, 'MULTI_LAYER', 'X' ) * Lets break out thick and res and see if it gets measured based on frequency * Thickness ThickPrintVar = '' ResPrintVar = '' SRPPrintVar = '' SRPTypePrintVar = '' ThisThickVar = ThickVar ThisResVar = ResVar ThisConVar = ConVar ThisStressVar = StressVar ThisTransVar = TransVar ThisRunOrdNum = RONum ThisWO = WONo ThisWOStepKey = WOStepKey ;* 5/21/2005 - JCH - Added for Order Entry/Vision upgrade MultiStep = 0 IF MultiStep > 0 THEN ThisWO = ThisWOStepKey[1,'*'] ;* 5/21/2005 - JCH - Added for Order Entry/Vision upgrade ThickTool = field( ThisThickVar, '~', 1 ) ThickType = field( ThisThickVar, '~', 2 ) ThickRecipe = field( ThisThickVar, '~', 3 ) ThickFreq = field( ThisThickVar, '~', 4 ) ThickFirst = field( ThisThickVar, '~', 6 ) ThickLast = field( ThisThickVar, '~', 7 ) ResTool = field( ThisResVar, '~', 1 ) ResType = field( ThisResVar, '~', 2 ) ResRecipe = field( ThisResVar, '~', 3 ) ResFreq = field( ThisResVar, '~', 4 ) ResFirst = field( ThisResVar, '~', 6 ) ResLast = field( ThisResVar, '~', 7 ) ConTool = field( ThisConVar, '~', 1 ) ConType = field( ThisConVar, '~', 2 ) ConRecipe = field( ThisConVar, '~', 3 ) ConFreq = field( ThisConVar, '~', 4 ) ConFirst = field( ThisConVar, '~', 6 ) ConLast = field( ThisConVar, '~', 7 ) StressTool = field( ThisStressVar, '~', 1 ) StressType = field( ThisStressVar, '~', 2 ) StressRecipe = field( ThisStressVar, '~', 3 ) StressFreq = field( ThisStressVar, '~', 4 ) StressFirst = field( ThisStressVar, '~', 6 ) StressLast = field( ThisStressVar, '~', 7 ) TransTool = field( ThisTransVar, '~', 1 ) TransType = field( ThisTransVar, '~', 2 ) TransRecipe = field( ThisTransVar, '~', 3 ) TransFreq = field( ThisTransVar, '~', 4 ) TransFirst = field( ThisTransVar, '~', 6 ) TransLast = field( ThisTransVar, '~', 7 ) IF MultiStep > 0 THEN WOBoxCnt = COUNT(XLATE('WO_STEP',ThisWOStepKey,6,'X'),@VM) ;* 5/21/2005 - JCH - Added for Order Entry/Vision upgrade END ELSE EXTRACT_SI_KEYS( 'RDS', 'WO', ThisWO, RDSsInWO ) ;* Original Code WOBoxCnt = FIELDCOUNT( RDSsInWO, @VM ) ;* Original Code END * First check thickness PrintThickness = false$ IF ( ThisRunOrdNum = 1 ) AND ( ThickFirst ) THEN PrintThickness = true$ IF ( ThisRunOrdNum = WOBoxCnt ) AND ( ThickLast ) THEN PrintThickness = true$ IF ThickFreq THEN * Need to check run order and see if it needs to be printed IF ThickFreq = 1 THEN PrintThickness = true$ END ELSE * Generate @FM delim of runs that should print RoPrintFlag = str( @FM, WOBoxCnt-1 ) FOR J = 1 TO WOBoxCnt step ThickFreq RoPrintFlag = 1 NEXT J IF ( RoPrintFlag = 1 ) THEN PrintThickness = true$ END END IF PrintThickness THEN PSNRec = XLATE( 'PROD_SPEC', PSNo, '', 'X' ) SpecSub = PSNRec TOrient = SpecSub<1,QSSubOrientation$> convert '<' TO '' in TOrient convert '>' TO '' in TOrient Orient = TOrient ThickPrintVar = ThickTool:'~':ThickType:'~':Orient:'~':ThickRecipe END ELSE ThickPrintVar = '' END * Now check resistivity PrintResistivity = false$ IF ( ThisRunOrdNum = 1 ) and ( ResFirst ) THEN PrintResistivity = true$ IF ( ThisRunOrdNum = WOBoxCnt ) and ( ResLast ) THEN PrintResistivity = true$ IF ResFreq THEN * NEED TO CHECK RUN ORDER AND SEE IF IT NEEDS TO BE PRINTED IF ResFreq = 1 THEN PrintResistivity = true$ END ELSE * Generate @FM delim of runs that should print RoPrintFlag = str( @FM, WOBoxCnt-1 ) FOR J = 1 TO WOBoxCnt step ResFreq RoPrintFlag = 1 NEXT J IF ( RoPrintFlag = 1 ) THEN PrintResistivity = true$ END END IF PrintResistivity THEN PSNRec = XLATE( 'PROD_SPEC', PSNo, '', 'X' ) SpecSub = PSNRec ;******* Moved to EPI_PART TOrient = SpecSub<1,QSSubOrientation$> convert '<' TO '' in TOrient convert '>' TO '' in TOrient Orient = TOrient ResPrintVar = ResTool:'~':ResType:'~':Orient:'~':ResRecipe END ELSE ResPrintVar = '' END PrintSRP = false$ SRPType = '' IF SRPFlag THEN * We know that SRP is one of the tools IF PrintThickness THEN IF ThickTool = 'SRP' THEN PrintSRP = true$ SRPType = ThickType END END IF PrintResistivity THEN IF ResTool = 'SRP' THEN PrintSRP = true$ SRPType = ResType END END IF NOT(PrintSRP) THEN * Now need to check concentration IF ConTool = 'SRP' THEN IF ( ThisRunOrdNum = 1 ) and ( ConFirst ) THEN PrintSRP = true$ IF ( ThisRunOrdNum = WOBoxCnt ) and ( ConLast ) THEN PrintSRP = true$ IF ConFreq THEN * Need to check run order and see if it needs to be printed IF ConFreq = 1 THEN PrintSRP = true$ END ELSE * Generate fm delim of runs that should print RoPrintFlag = str( @FM, WOBoxCnt-1 ) FOR J = 1 TO WOBoxCnt step ConFreq RoPrintFlag = 1 NEXT J IF ( RoPrintFlag = 1 ) THEN PrintSRP = true$ END END END IF PrintSRP THEN SRPType = ConType END IF NOT(PrintSRP) THEN * Now need to check stress IF StressTool = 'SRP' THEN IF ( ThisRunOrdNum = 1 ) AND ( StressFirst ) THEN PrintSRP = true$ IF ( ThisRunOrdNum = WOBoxCnt ) AND ( StressLast ) THEN PrintSRP = true$ IF StressFreq THEN * Need to check run order and see if it needs to be printed IF StressFreq = 1 THEN PrintSRP = true$ END ELSE * Generate @FM delim of runs that should print RoPrintFlag = str( @FM, WOBoxCnt-1 ) FOR J = 1 TO WOBoxCnt step StressFreq RoPrintFlag = 1 NEXT J IF ( RoPrintFlag = 1 ) THEN PrintSRP = true$ END END END IF PrintSRP THEN SRPType = StressType END IF NOT(PrintSRP) THEN * Now need to check transition IF TransTool = 'SRP' THEN IF ( ThisRunOrdNum = 1 ) AND ( TransFirst ) THEN PrintSRP = true$ IF ( ThisRunOrdNum = WOBoxCnt ) AND ( TransLast ) THEN PrintSRP = true$ IF TransFreq THEN * Need to check run order and see if it needs to be printed IF TransFreq = 1 THEN PrintSRP = true$ END ELSE * Generate fm delim of runs that should print RoPrintFlag = str( @FM, WOBoxCnt-1 ) FOR J = 1 TO WOBoxCnt step TransFreq RoPrintFlag = 1 NEXT J IF ( ROPrintFlag = 1 ) THEN PrintSRP = true$ END IF PrintSRP THEN SRPType = TransType END END END IF PrintSRP THEN SRPPrintVar = true$ SRPTypePrintVar = SRPType END ELSE SRPPrintVar = false$ SRPTypePrintVar = '' END END ELSE SRPPrintVar = false$ SRPTypePrintVar = '' END * Got all data now we can print PrintCustName = CustName IF MultiStep > 0 THEN WONo = WONo:'.':MultiStep ;* 5/21/2005 - JCH - Added for Order Entry/Vision upgrade WONo = WOStepKeys CONVERT '*' TO '.' IN WONo END PrintWO = WoNo ;* 5/21/2005 - JCH - Changed for Order Entry/Vision upgrade PrintPSNNo = PSNo ;* 6/10/2005 - JCH - Added per manufacturing manager request PrintLotNum = LotNum PrintRecipeInfo = RecipeInfo PrintSpecType = SpecType PrintRONum = RONum PrintRdsId = RdsKey PrintThickPrintVar = ThickPrintVar PrintResPrintVar = ResPrintVar PrintMultiLayVar = MultiLayVar PrintSRPPrintVar = SRPPrintVar PrintSRPTypePrintVar = SRPTypePrintVar PrintQty = Qtys PrintThickTargets = '' PrintThickTargets = ThickTarget:ThickUnit PrintResTargets = '' IF ResTarget[1,1] = '.' THEN TargetVal = '0':ResTarget END ELSE TargetVal = ResTarget END PrintResTargets = TargetVal:ResUnit PrintPO = PO PrintPartNum = PartNum:' ':CustPNDescs PrintPartNo = PartNum PrintSubPartNum = SubPartNum SubSupplier = obj_Vendor_Code('SemiToEpi',WOMatRec) VendCd = XLATE('COMPANY',CustNo,COMPANY_VEND_CD$,'X') PrintCompany = XLATE('COMPANY', CustNo, COMPANY_CO_NAME$, 'X') IF VendCd NE '' THEN SubSupplier = VendCd ;* Substrate supplier code found in the EPI_PART window. 12/9/2011 for cust 7067 END PrintSuppCd = SubSupplier PrintDopant = Dopant PrintShipBagReq = ShipBagReq ;* Changed to single value ShipBagReq 9/27/2012 JCH PrintReqShipDate = ReqShipDate PrintSubOxide = SubOxide PrintReactType = ReactTypes PrintSubPreClean = SubPreCleans PrintSubPostClean = SubPostCleans PrintPreAkrionRecipe = PreAkrionRecipes PrintPostAkrionRecipe = PostAkrionRecipes APreRec = '' APostRec = '' IF ( PreAkrionRecipes <> '' ) THEN APreRec = ' ':PreAkrionRecipes:' ' SubOxide = 'No' ;* IF AKRION THEN NO OXIDE STRIP END IF ( PostAkrionRecipes <> '' ) THEN APostRec = ' ':PostAkrionRecipes END swap '~' with fmt( ' ', 'L#2' ) in PrintThickPrintVar swap UNIT_MICROMETER$ with 'um' in PrintThickTargets swap UNIT_OHM_CM$ with 'ohm.cm' in PrintThickTargets swap UNIT_OHM_PER_SQ$ with 'ohm/sq' in PrintThickTargets swap UNIT_A$ with 'A' in PrintThickTargets swap '~' with fmt( ' ', 'L#2' ) in PrintResPrintVar swap UNIT_MICROMETER$ with 'um' in PrintResTargets swap UNIT_OHM_CM$ with 'ohm.cm' in PrintResTargets swap UNIT_OHM_PER_SQ$ with 'ohm/sq' in PrintResTargets swap UNIT_A$ with 'A' in PrintResTargets //only print cheat sheet label on cassette #1 IF CassNo EQ 1 then PsnRec = XLATE('PROD_SPEC', PSNo, '', 'X') SpecEpi = PsnRec SpecSub = PsnRec ThkSmile = PsnRec ThkShift = Field(PsnRec, @FM, PROD_SPEC_THICK_LIMIT_SHIFT$) ResShift = Field(PsnRec, @FM, PROD_SPEC_RES_LIMIT_SHIFT$) SSRecipe = XLATE('PRS_STAGE', PSNo:'*LWI', 5, 'X') PCRecipe = XLATE('PRS_STAGE', PSNo, 'POST_CLEAN_SURFSCAN_RECIPE', 'X') CustPart = PsnRec WaferSize = XLATE('EPI_PART', CustPart, EPI_PART_SUB_WAFER_SIZE$, 'X') *Field(SpecSub, @VM, QSSubWafersize$) convert char(248) to @fm in SpecEpi ;* char(248) is used to separate layers layerCount = fieldcount( SpecEpi, @fm ) layerInfo = SpecEpi //if this is just 1 layer, we're returning that info, if 3 layers, we're returning layer 3 (combo) ThkData = Field(layerInfo, @VM, QSEpiThickMeasure$) ResData = Field(layerInfo, @VM, QSEpiResMeasure$) ConData = Field(layerInfo, @VM, QSEpiConcMeasure$) CResData = Field(layerInfo, @VM, QSEpiCresMeasure$) ThkMin = OCONV(Field(layerInfo, @VM, QSEpiMinThick$), 'MD3') ThkMax = OCONV(Field(layerInfo, @VM, QSEpiMaxThick$), 'MD3') ThkTarg = '' If ThkMin NE '' Then ThkTarg = oConv(iconv((ThkMin+ThkMax)/2, 'MD3'), 'MD3') ResMin = OCONV(Field(layerInfo, @VM, QSEpiResMinThick$), 'MD3') ResMax = OCONV(Field(layerInfo, @VM, QSEpiResMaxThick$), 'MD3') ResTarg = '' If ResMin NE '' Then ResTarg = oConv(iconv((ResMin+ResMax)/2, 'MD3'), 'MD3') ConMin = OCONV(Field(layerInfo, @VM, QSEpiConcMinThick$), 'MD3') ConMax = OCONV(Field(layerInfo, @VM, QSEpiConcMaxThick$), 'MD3') ConTarg = '' If ConMin NE '' Then ConTarg = oConv(iconv((ConMin+ConMax)/2, 'MD3'), 'MD3') CResMin = OCONV(Field(layerInfo, @VM, QSEpiCresMin$), 'MD3') CResMax = OCONV(Field(layerInfo, @VM, QSEpiCresMax$), 'MD3') CResTarg = '' If CResMin NE '' Then CResTarg = oConv(iconv((CResMin+CResMax)/2, 'MD3'), 'MD3') ThkTool = Field(ThkData, '~', PS$TOOL) ThkType = Field(ThkData, '~', PS$TYPE) ThkRecipe = Field(ThkData, '~', PS$RECIPE) ThkFreq = Field(ThkData, '~', PS$FREQ) ThkPattern = Field(ThkData, '~', PS$PATTERN) ResTool = Field(ResData, '~', PS$TOOL) ResType = Field(ResData, '~', PS$TYPE) ResRecipe = Field(ResData, '~', PS$RECIPE) ResFreq = Field(ResData, '~', PS$FREQ) ResPattern = Field(ResData, '~', PS$PATTERN) ConTool = Field(ConData, '~', PS$TOOL) ConType = Field(ConData, '~', PS$TYPE) ConRecipe = Field(ConData, '~', PS$RECIPE) ConFreq = Field(ConData, '~', PS$FREQ) ConPattern = Field(ConData, '~', PS$PATTERN) CResTool = Field(CResData, '~', PS$TOOL) CResType = Field(CResData, '~', PS$TYPE) CResRecipe = Field(CResData, '~', PS$RECIPE) CResFreq = Field(CResData, '~', PS$FREQ) CResPattern = Field(CResData, '~', PS$PATTERN) IF ThkMin EQ '' THEN ThkMin = '--' IF ThkMax EQ '' THEN ThkMax = '--' IF ThkTarg EQ '' THEN ThkTarg = '--' IF ThkTool EQ '' THEN ThkTool = '--' IF ThkType EQ '' THEN ThkType = '--' IF ThkRecipe EQ '' THEN ThkRecipe = '--' IF ThkPattern EQ '' THEN ThkPattern = '--' IF ThkFreq EQ '' THEN ThkFreq = '--' IF ResMin EQ '' THEN ResMin = '--' IF ResMax EQ '' THEN ResMax = '--' IF ResTarg EQ '' THEN ResTarg = '--' IF ResTool EQ '' THEN ResTool = '--' IF ResType EQ '' THEN ResType = '--' IF ResRecipe EQ '' THEN ResRecipe = '--' IF ResPattern EQ '' THEN ResPattern = '--' IF ResFreq EQ '' THEN ResFreq = '--' IF ConMin EQ '' THEN ConMin = '--' IF ConMax EQ '' THEN ConMax = '--' IF ConTarg EQ '' THEN ConTarg = '--' IF ConTool EQ '' THEN ConTool = '--' IF ConType EQ '' THEN ConType = '--' IF ConRecipe EQ '' THEN ConRecipe = '--' IF ConPattern EQ '' THEN ConPattern = '--' IF ConFreq EQ '' THEN ConFreq = '--' IF CResMin EQ '' THEN CResMin = '--' IF CResMax EQ '' THEN CResMax = '--' IF CResTarg EQ '' THEN CResTarg = '--' IF CResTool EQ '' THEN CResTool = '--' IF CResType EQ '' THEN CResType = '--' IF CResRecipe EQ '' THEN CResRecipe = '--' IF CResPattern EQ '' THEN CResPattern = '--' IF CResFreq EQ '' THEN CResFreq = '--' Swap @VM with ' / ' in SSRecipe IF PCRecipe EQ '' Then PCRecipe = '--' If ThkSmile EQ '' OR ThkSmile EQ '0' then ThkSmile = 'N' end else ThkSmile = 'Y' end If ThkShift EQ '' OR ThkShift EQ '0' then ThkShift = 'N' end else ThkShift = 'Y' end If ResShift EQ '' OR ResShift EQ '0' then ResShift = 'N' end else ResShift = 'Y' end if Len(ThkMin) > 6 then ThkMin = ThkMin[1,6] end if Len(ThkMax) > 6 then ThkMax = ThkMax[1,6] end if Len(ThkTarg) > 6 then ThkTarg = ThkTarg[1,6] end if Len(ResMin) > 6 then ResMin = ResMin[1,6] end if Len(ResMax) > 6 then ResMax = ResMax[1,6] end if Len(ResTarg) > 6 then ResTarg = ResTarg[1,6] end if Len(ConMin) > 6 then ConMin = ConMin[1,6] end if Len(ConMax) > 6 then ConMax = ConMax[1,6] end if Len(ConTarg) > 6 then ConTarg = ConTarg[1,6] end if Len(CResMin) > 6 then CResMin = CResMin[1,6] end if Len(CResMax) > 6 then CResMax = CResMax[1,6] end if Len(CResTarg) > 6 then CResTarg = CResTarg[1,6] end ****** Begin ZPL ZPL := '^XA' ZPL := '^LH10,0' ZPL := '^PR2' ;* Print speed 2 inches per second ZPL := '^LL406' ;* Label length @203 dpi ZPL := '^PW900' ZPL := '^MD0' ;* Media darkness ZPL := '^MMT' ;* Media mode t=tear off mode ****** 1st/2nd Line ZPL := '^FO30,20^A0,,40^FDWO ':PrintWO:'^FS' ZPL := '^FO590,10^A050,30^FDPSN ':PrintPSNNo:'^FS' ZPL := '^FO555,40^A050,30^FDDopant ':PrintDopant:'^FS' ****** 3rd Line - headers ZPL := '^FO85,100^A050,23^FDMin^FS' ZPL := '^FO145,100^A050,23^FDTarg^FS' ZPL := '^FO210,100^A050,23^FDMax^FS' ZPL := '^FO280,100^A050,23^FDTool^FS' ZPL := '^FO330,100^A050,23^FDType^FS' ZPL := '^FO470,100^A050,23^FDRecipe^FS' ZPL := '^FO600,100^A050,23^FDPattern^FS' ZPL := '^FO740,100^A050,23^FDFreq^FS' ****** 4th Line - Thickness (Thk) ZPL := '^FO70,130^GB720,0,3^FS' ZPL := '^FO70,130^GB0,160,3^FS' ZPL := '^FO10,140^A050,23^FDThk:^FS' ZPL := '^FO80,140^A050,23^FD':ThkMin:'^FS' ZPL := '^FO145,140^A050,23^FD':ThkTarg:'^FS' ZPL := '^FO210,140^A050,23^FD':ThkMax:'^FS' ZPL := '^FO280,140^A050,23^FD':ThkTool[1,5]:'^FS' ZPL := '^FO330,140^A050,23^FD':ThkType[1,11]:'^FS' ZPL := '^FO470,140^A050,23^FD':ThkRecipe[1,11]:'^FS' ZPL := '^FO600,140^A050,23^FD':ThkPattern[1,11]:'^FS' ZPL := '^FO750,140^A050,23^FD':ThkFreq:'^FS' ****** 5th Line - Resistivity (Res) ZPL := '^FO10,170^GB780,0,3^FS' ZPL := '^FO10,180^A050,23^FDRes:^FS' ZPL := '^FO80,180^A050,23^FD':ResMin:'^FS' ZPL := '^FO145,180^A050,23^FD':ResTarg:'^FS' ZPL := '^FO210,180^A050,23^FD':ResMax:'^FS' ZPL := '^FO280,180^A050,23^FD':ResTool[1,5]:'^FS' ZPL := '^FO330,180^A050,23^FD':ResType[1,11]:'^FS' ZPL := '^FO470,180^A050,23^FD':ResRecipe[1,11]:'^FS' ZPL := '^FO600,180^A050,23^FD':ResPattern[1,11]:'^FS' ZPL := '^FO750,180^A050,23^FD':ResFreq:'^FS' ****** 6th Line - Contact (Con) ZPL := '^FX***LINE 4' ZPL := '^FO10,210^GB780,0,3^FS' ZPL := '^FO10,220^A050,23^FDCon:^FS' ZPL := '^FO80,220^A050,23^FD':ConMin:'^FS' ZPL := '^FO145,220^A050,23^FD':ConTarg:'^FS' ZPL := '^FO210,220^A050,23^FD':ConMax:'^FS' ZPL := '^FO280,220^A050,23^FD':ConTool[1,5]:'^FS' ZPL := '^FO330,220^A050,23^FD':ConType[1,11]:'^FS' ZPL := '^FO470,220^A050,23^FD':ConRecipe[1,11]:'^FS' ZPL := '^FO600,220^A050,23^FD':ConPattern[1,11]:'^FS' ZPL := '^FO750,220^A050,23^FD':ConFreq:'^FS' ****** 7th Line - Contact Resistance (CRes) ZPL := '^FO10,250^GB780,0,3^FS' ZPL := '^FO10,260^A050,23^FDCRes:^FS' ZPL := '^FO80,260^A050,23^FD':CResMin:'^FS' ZPL := '^FO145,260^A050,23^FD':CResTarg:'^FS' ZPL := '^FO210,260^A050,23^FD':CResMax:'^FS' ZPL := '^FO280,260^A050,23^FD':CResTool[1,5]:'^FS' ZPL := '^FO330,260^A050,23^FD':CResType[1,11]:'^FS' ZPL := '^FO470,260^A050,23^FD':CResRecipe[1,11]:'^FS' ZPL := '^FO600,260^A050,23^FD':CResPattern[1,11]:'^FS' ZPL := '^FO750,260^A050,23^FD':CResFreq:'^FS' ZPL := '^FO10,290^GB780,0,3^FS' ****** 8th Line - Special Instructions ZPL := '^FO10,310^A050,23^FDSurfScan: ':SSRecipe:'^FS' ZPL := '^FO10,340^A050,23^FDPostClean: ':PCRecipe:'^FS' ZPL := '^FO10,370^A050,23^FDWafer Size: ':WaferSize:'^FS' ZPL := '^FO560,310^A050,23^FDSmile Required: ':ThkSmile:'^FS' ZPL := '^FO560,340^A050,23^FDSPC Thk Shift: ':ThkShift:'^FS' ZPL := '^FO560,370^A050,23^FDSPC Res Shift: ':ResShift:'^FS' ZPL:= '^XZ':CRLF$ ****** End ZPL end * Standard RDS Label print method IF PrintSpecType EQ 'Production' THEN PrintSpecType = 'Prod' IF PrintSpecType EQ 'Pre-Production' THEN PrintSpecType = 'Pre' EpiPartRec = XLATE('EPI_PART',EpiPartNo,'','X') IsExportControl = EpiPartRec CustEpiPartRec = XLATE('CUST_EPI_PART',CustNo:'*':EpiPartNo,'','X') CustEpiPartSpecNo = CustEpiPartRec[-1,'B':@VM] ;* Last (current) Customer Spec Number PrintPSN = XLATE('RDS',PrintRDSId,'PROD_SPEC_ID', 'X') PrintRecipe = '' PSStageKey = PrintPSN:'*QA' PrintRecipe = XLATE('PRS_STAGE',PSStageKey,'MET_RECIPE','X') PrintQARecipe = FIELD(PrintRecipe, @VM, 1) PrintCompany = PrintCompany[1,32] // Looping instead of using ^PQ2 since I have to set sequential key in 2D barcode For cnt = 1 to 2 ZPL := '^XA' ZPL := '^LH0,0' ZPL := '^PR1' ;* Print speed 2 inches per second ZPL := '^LL406' ;* Label length @203 dpi ZPL := '^PW900' ZPL := '^MD5' ;* Media darkness ZPL := '^MMT' ;* Media mode t=tear off mode ****** First Line, Cust, WO and RO ZPL := '^FO25,25^AC,18^FDCust: ^FS':CRLF$ ZPL := '^FO95,14^A045,35^FD':PrintCompany:'^FS':CRLF$ ZPL := '^FO570,25^AC18^FDWO: ^FS':CRLF$ ZPL := '^FO610,14^A045,35^FD':PrintWO:'^FS':CRLF$ ZPL := '^FO730,25^AC18^FDRO: ^FS':CRLF$ ZPL := '^FO770,14^A045,35^FD':PrintRONum:'^FS':CRLF$ ****** Second Line, Cust Spec, PSN and Type ZPL := '^FO25,75^AC18^FD(P)Cust Spec: ^FS':CRLF$ ZPL := '^FO185,65^A045,35^FD':CustEpiPartSpecNo:'^FS':CRLF$ ZPL := '^FO25,95^BY2,2.0^B3,,50,N^FDP':CustEpiPartSpecNo:'^FS':CRLF$ ZPL := '^FO640,75^AC18^FDPSN:^FS':CRLF$ ZPL := '^FO690,65^A045,35^FD':PrintPSN:'^FS':CRLF$ ZPL := '^FO630,125^AC18^FDType:^FS':CRLF$ ZPL := '^FO690,115^A045,30^FD':PrintSpecType:'^FS':CRLF$ ****** Third Line, Sub Lot, Qty and RDS ZPL := '^FO25,175^AC18^FD(2T)Sub Lot:^FS':CRLF$ ZPL := '^FO175,165^A045,35^FD':PrintLotNum:'^FS':CRLF$ ZPL := '^FO25,195^BY1,3.0^B3,,50,N^FD2T':PrintLotNum:'^FS':CRLF$ ZPL := '^FO400,175^AC18^FD(Q)Qty:^FS':CRLF$ ZPL := '^FO500,165^A045,35^FD':PrintQty:'^FS':CRLF$ ZPL := '^FO400,195^B3,,50,N^FDQ':PrintQty:'^FS':CRLF$ ZPL := '^FO590,175^AC18^FD(1T)RDS: ^FS':CRLF$ ZPL := '^FO690,165^A045,35^FD':PrintRDSId:'^FS':CRLF$ ZPL := '^FO630,195^B3,,50,N^FD1T':PrintRDSId:'^FS':CRLF$ ****** Fourth Line, SubPN, Vendor and QA Metrology recipe ZPL := '^FO25,275^AC18^FD(S)Sub PN:^FS':CRLF$ ZPL := '^FO145,265^A045,35^FD':PrintSubPartNum:'^FS':CRLF$ ZPL := '^FO25,295^B3,,50,N^FDS':PrintSubPartNum:'^FS':CRLF$ ZPL := '^FO400,275^AC18^FD(1V)Vend:^FS':CRLF$ ZPL := '^FO510,265^A045,35^FD':PrintSuppCd:'^FS':CRLF$ ZPL := '^FO400,295^B3,,50,N^FD1V':PrintSuppCd:'^FS':CRLF$ ZPL := '^FO590,275^AC18^FD':PrintQARecipe:'^FS':CRLF$ ****** Fifth Line, Motto and Data Matrix barcode ZPL := '^FO25,370^A045,28':CRLF$ ZPL := "^FDWe do what we promise. That's quality made by Infineon.^FS":CRLF$ ZPL := '^FO725,320^CI28':CRLF$ ZPL := '^BXN,2,200^FDP':CustEpiPartSpecNo:'|S':PrintSubPartNum:'|1T':PrintRDSId:'|2T':PrintLotNum:'|':PrintPSN:'|Q':PrintQty:'|1V':PrintSuppCd:'|SEQ':cnt:'^FS':CRLF$ ****** End the print job (ZPL script) ZPL:= '^XZ' Next end else ErrorMsg = 'Error in ':Service:' service. RDS ':RdsKey:' does not exist.' end end else ErrorMsg = 'Error in ':Service:' service. Null RdsKey passed in.' end If ErrorMsg EQ '' then Response = ZPL end else Error_Services('Add', ErrorMsg) end end service //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Internal GoSubs //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ClearCursors: For counter = 0 to 8 ClearSelect counter Next counter return