diff --git a/LSL2/STPROC/GAN_SERVICES.txt b/LSL2/STPROC/GAN_SERVICES.txt index 255e063..1b3335b 100644 --- a/LSL2/STPROC/GAN_SERVICES.txt +++ b/LSL2/STPROC/GAN_SERVICES.txt @@ -593,13 +593,7 @@ Service RemoveRunID(RunID) LogData<2> = @USER4 LogData<3> = EtchID Machine = Environment_Services('GetServer') - If Machine NE 'MESSA01EC' then - EmailAddr = 'dstieber@srpcs.com,Dan.Crisp@infineon.com,4805890050@vtext.com,6613649828@txt.att.net' - EmailMsg = 'Error removing Run ID: ':RunID:' from APP_INFO*PRERUN_GAN_RUN_IDS' - Logging_Services('AppendLog', ObjLog, LogData, @RM, @FM, False$, EmailAddr, EmailMsg) - end else - Logging_Services('AppendLog', ObjLog, LogData, @RM, @FM, False$) - end + Logging_Services('AppendLog', ObjLog, LogData, @RM, @FM, False$) end end @@ -1763,14 +1757,7 @@ Service RemoveCassFromWIP(WOMatKey) end else LogData<6> = 'Error removing Cass ID ':WOMatKey:' from queue ':CassQueue:'. Number of attempts: ':NumAttempts:'.' end - Machine = Environment_Services('GetServer') - If Machine NE 'MESSA01EC' then - EmailAddr = 'dstieber@srpcs.com,6613649828@txt.att.net' - EmailMsg = 'Error removing Cass ID ':WOMatKey:' from queue ':CassQueue:'.' - Logging_Services('AppendLog', objWIPLog, LogData, @RM, @FM, False$, EmailAddr, EmailMsg) - end else - Logging_Services('AppendLog', objWIPLog, LogData, @RM, @FM, False$) - end + Logging_Services('AppendLog', objWIPLog, LogData, @RM, @FM, False$) end end else // Cass not in queue that was passed in. Log this information. @@ -1781,14 +1768,7 @@ Service RemoveCassFromWIP(WOMatKey) LogData<4> = CassQueue LogData<5> = CassQueue LogData<6> = 'Error in ':Service:' service. Cass not in QueueID ':CassQueue:'.' - Machine = Environment_Services('GetServer') - If Machine NE 'MESSA01EC' then - EmailAddr = 'dstieber@srpcs.com,6613649828@txt.att.net' - EmailMsg = 'Error in ':Service:' service. Cass not in QueueID ':CassQueue:'.' - Logging_Services('AppendLog', objWIPLog, LogData, @RM, @FM, False$, EmailAddr, EmailMsg) - end else - Logging_Services('AppendLog', objWIPLog, LogData, @RM, @FM, False$) - end + Logging_Services('AppendLog', objWIPLog, LogData, @RM, @FM, False$) end end else // WOMatKey is null diff --git a/LSL2/STPROC/GAN_SERVICES_DEV.txt b/LSL2/STPROC/GAN_SERVICES_DEV.txt deleted file mode 100644 index 62d5f11..0000000 --- a/LSL2/STPROC/GAN_SERVICES_DEV.txt +++ /dev/null @@ -1,6025 +0,0 @@ -Function GaN_Services_Dev(@Service, @Params) -/*********************************************************************************************************************** - - Name : GaN_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) - 01/11/19 djs Original programmer. - 07/23/19 djs Added check within UpdateDisposition service to see if an NCR has been added to External - wafers before marking DISP complete and removing the wafers from the WIP. - Added check within UpdateDisposition service to see if the DISP_COMPLETE flag has been - marked for that wafer before marking the DISP stage complete and moving the wafer out of - the DISP Location queue. - 12/17/19 dpc Removed G_REACT filter from the GetToolList service to allow R69 and R71 to show in Tool - filter dropdown. - 07/21/20 djs Updated the AutoDisposition service to require retained wafers to be signed (i.e. physically - retained by an operator) before the wafer is marked as ready to close. - 08/20/20 djs Removed unnecessary inserts and declarations. Created Disposition_Services which contains - new services for dispositioning production and engineering wafers. The AutoDisposition and - UpdateDisposition services within this service module are now deprecated and should no - longer be used. Gan_Services is approaching the maximum executable size. As a result - GaN_Services may need to be refactored and split into multiple service modules in the - future. - - -***********************************************************************************************************************/ -#pragma precomp SRP_PreCompiler - -$insert APP_INSERTS -$insert SERVICE_SETUP -$insert PROD_SPEC_EQUATES -$insert TOOL_CLASS_EQUATES -$insert REACT_RUN_EQUATES -$insert REACTOR_EQUATES -$insert PRS_STAGE_EQUATES -$insert WO_LOG_EQUATES -$insert WO_MAT_EQUATES -$insert RLIST_EQUATES -$insert TOOL_EQUATES -$insert GAN_ETCH_EQUATES -$insert WO_WFR_EQUATES -$insert TOOL_WFR_EQUATES -$insert LOCATION_EQUATES -$insert WO_MAT_WFR_EQUATES -$insert RUN_STAGE_EQUATES -$insert RUN_STAGE_WFR_EQUATES -$insert GAN_RUN_INFO_REQUESTS_EQUATES -$insert GAN_SCHEDULE_EQUATES -$insert GAN_PARAMS_EQUATES -$insert RETAINED_WAFERS_EQUATES -$insert DISPOSITION_REQUESTS_EQUATES -$insert TOOL_ETCH_EQUATES - -Declare subroutine Error_Services, SRP_JSON, End_Window, Database_Services, Btree.Extract, SQL_Services -Declare subroutine Logging_Services, SRP_Array, GaN_Services, Sleepery, WinYield, Yield, Set_Status, Excel_Services -Declare subroutine Disposition_Services, Engineering_Services -Declare function Database_Services, SRP_JSON, Logging_Services, Environment_Services, Error_Services -Declare function SQL_Services, SRP_Array, NextKey, DateTime, GaN_Services, Excel_Services, Max, SRP_Math -Declare function GetTickCount - -LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\Thruput' -LogDate = Oconv(Date(), 'D4/') -LogTime = Oconv(Time(), 'MTS') -LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' ThruPut Log - GaN.csv' -Headers = 'Logging DTM':@FM:'RDS Key ID':@FM:'GRWfrQty':@FM:'ScrapQty':@FM:'ProdTWQty':@FM:'DummyQty' -objLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$) -LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM - -LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\GaNWIP' -LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' WfrQueueLog.csv' -Headers = 'Logging DTM':@FM:'UserID':@FM:'WfrID':@FM:'Param Queue':@FM:'Wafer Queue':@FM:'Error Message' -objWIPLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$) - -LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\GaNWIP' -LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' PocketLog.csv' -Headers = 'Logging DTM':@FM:'RunID':@FM:'Pockets' -objPocketLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$) - -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 STAGETYPE = 'Reactor', 'Metrology', 'Disposition' - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Services -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -//---------------------------------------------------------------------------------------------------------------------- -// GetGaNGRProps -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetGaNGRProps(WOMatKey) - - If WOMatKey NE '' then - ReactorType = Xlate('WO_MAT', WOMatKey, 'REACTOR_TYPE', 'X') - // The following NCR and TW counting logic is ran against all RDS, for that WorkOrder, everytime a GaN cassette - // is FQA signed. - If (ReactorType _EQC 'GAN') then - - GRWfrQty = 0 - ScrapQty = 0 - ProdTWQty = 0 - DummyQty = 0 - EmptyQty = 0 - - WONo = Field(WOMatKey, '*', 1) - WOStepKey = Xlate('WO_MAT', WOMatKey, 'WO_STEP_KEYS', 'X') - WOStepRec = Database_Services('ReadDataRow', 'WO_STEP', WOStepKey) - WOMatKeys = Xlate('WO_LOG', WONo, 'WO_MAT_KEY', 'X') - CurrDTM = Datetime() - GRWfrQty = Xlate('WO_MAT_WFR', WOMatKey, 'OUT_WFR_QTY', 'X') - - // Scan through each wafer in this work order to count the number of WMI, RDS, and WMO NCRs which have - // not been reported to SAP yet and report them with this outbound cassette batch ID. - For each InboundMatKey in WOMatKeys using @VM - CassNo = Field(InboundMatKey, '*', 2) - SlotNos = Xlate('WO_MAT', InboundMatKey, 'SLOT_NO', 'X') - For each SlotNo in SlotNos using @VM - WOWfrKey = WONo:'*':CassNo:'*':SlotNo - Database_Services('ActivateRecord', 'WO_WFR', WOWfrKey) - OrigRec = @Record - If ( ({WMI_NCR_NO} NE '') and ({WMI_NCR_SAP_DTM} EQ '') ) then - {WMI_NCR_SAP_DTM} = CurrDTM - ScrapQty += 1 - end - If ( ({RDS_NCR_NO} NE '') and ({RDS_NCR_SAP_DTM} EQ '') ) then - {RDS_NCR_SAP_DTM} = CurrDTM - ScrapQty += 1 - end - If ( ({WMO_NCR_NO} NE '') and ({WMO_NCR_SAP_DTM} EQ '') ) then - {WMO_NCR_SAP_DTM} = CurrDTM - ScrapQty += 1 - end - If OrigRec NE @Record then - Database_Services('WriteDataRow', 'WO_WFR', WOWfrKey, @Record, True$, False$, True$) - end - Next SlotNo - Next InboundMatKey - - - // Scan through all RDS records in this work order to count the number of test wafers which have not - // yet been reported to SAP. - RDSKeys = WOStepRec - For each RDSKey in RDSKeys using @VM - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSKey) - GaNRunID = ReactRunRec - Scribes = Xlate('REACT_RUN', RDSKey, 'WFR_SCRIBES', 'X') - DummyQty = 0 - EmptyQty = 0 - - For each Scribe in Scribes using @VM setting vPos - DummyID = GanRunID[1,7]:'D' - EmptyID = GaNRunID[1,7]:'E' - EmptyFlag = (Indexc(Scribe, 'EMPTY', 1) > 0) - If Scribe[1,8] EQ DummyID then - DummyQty += 1 - end - If ( (Scribe[1,8] EQ EmptyID) or (EmptyFlag EQ True$) ) then - EmptyQty += 1 - end - Next Scribe - - SigProfile = ReactRunRec - SigProfileCnt = DCount(SigProfile, @VM) - NeedToWrite = False$ - - InWfrIDs = ReactRunRec - For each InWfrID in InWfrIDs using @VM setting vPos - If InWfrID NE '' then - // Count the number of TWs which have not been reported to SAP yet - For SigProfileIndex = 1 to SigProfileCnt - Destroyed = False$ - Stage = SigProfile<1, SigProfileIndex> - WfrKID = InWfrID - Convert '*' to '.' in WfrKID - WfrStageKey = RDSKey:'*':Stage:'*':WfrKID - - StageDestTest = XLATE('RUN_STAGE_WFR',WfrStageKey,'DEST_TEST','X') - StageCompSig = XLATE('RUN_STAGE_WFR',WfrStageKey,'COMP_BY','X') - If ( (StageDestTest EQ True$) AND (StageCompSig NE '') ) then - Database_Services('ActivateRecord', 'WO_WFR', InWfrID) - If {TW_SAP_DTM} EQ '' then - ProdTWQty += 1 - {TW_SAP_DTM} = CurrDTM - Database_Services('WriteDataRow', 'WO_WFR', InWfrID, @Record, True$, False$, True$) - end - end - until Destroyed EQ True$ - next SigProfileIndex - end - Next InWfrID - next RDSKey - end else - Error_Services('Add', 'WO_MAT ':WOMatKey:' is not of reactor type GAN.') - end - end else - Error_Services('Add', 'Null WO_MAT key supplied to ':Service:'.') - end - - Response = GRWfrQty:@FM:ScrapQty:@FM:ProdTWQty - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetYieldInfo -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetYieldInfo(RDSNo, WOMatKey) - - Response = '' - If RDSNo NE '' then WOMatKey = Xlate('REACT_RUN', RDSNo, 'WO_MAT_KEY', 'X') - If WOMatKey NE '' then - - WOMatRec = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey) - If Error_Services('NoError') then - If RDSNo EQ '' then RDSNo = WOMatRec - GRWfrQty = 0 - ScrapQty = 0 - ProdTWQty = 0 - DummyQty = 0 - EmptyQty = 0 - - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - GaNRunID = ReactRunRec - Scribes = Xlate('REACT_RUN', RDSNo, 'WFR_SCRIBES', 'X') - GRWfrQty = DCount(Scribes, @VM) - - For each Scribe in Scribes using @VM setting vPos - DummyID = GanRunID[1,7]:'D' - EmptyID = GaNRunID[1,7]:'E' - EmptyFlag = (Indexc(Scribe, 'EMPTY', 1) > 0) - - If Scribe[1,8] EQ DummyID then - DummyQty += 1 - end - If ( (Scribe[1,8] EQ EmptyID) or (EmptyFlag EQ True$) ) then - EmptyQty += 1 - end - Next Scribe - - GRWfrQty -= EmptyQty - - // The following NCR and TW counting logic is ran against all RDS, for that WorkOrder, - // everytime a GaN cassette is FQA signed. - - SigProfile = ReactRunRec - SigProfileCnt = DCount(SigProfile, @VM) - - // Count the number of NCRs - NCRKeys = Xlate('REACT_RUN', RDSNo, 'NCR_NOS', 'X') - If (NCRKeys NE '') then - ScrapQty += SUM(XLATE('NCR', NCRKeys, 'REJ_CNT', 'X')) - end - - // Count the number of Test Wafers - InWfrIDs = ReactRunRec - For each InWfrID in InWfrIDs using @VM setting vPos - If InWfrID NE '' then - Scribe = Scribes<0, vPos> - ScrapID = GaNRunID[1,7]:'W' - If (Scribe[1, 8] EQ ScrapID) then - ProdTWQty += 1 - end else - For SigProfileIndex = 1 to SigProfileCnt - Destroyed = False$ - Stage = SigProfile<1, SigProfileIndex> - WfrKID = InWfrID - Convert '*' to '.' in WfrKID - WfrStageKey = RDSNo:'*':Stage:'*':WfrKID - - StageDestTest = XLATE('RUN_STAGE_WFR',WfrStageKey,'DEST_TEST','X') - StageCompSig = XLATE('RUN_STAGE_WFR',WfrStageKey,'COMP_BY','X') - StageStatus = Xlate('RUN_STAGE_WFR',WfrStageKey,'STATUS','X') - StageSkipped = StageStatus EQ 'SKIP' - If ( (StageDestTest EQ True$) AND (StageCompSig NE '') and (StageSkipped EQ False$) ) then - ProdTWQty += 1 - Destroyed = True$ - end - until Destroyed EQ True$ - next SigProfileIndex - end - end - Next InWfrID - - LogData = '' - LogData<1> = LoggingDTM - LogData<2> = RDSNo - LogData<3> = GRWfrQty - LogData<4> = ScrapQty - LogData<5> = ProdTWQty - LogData<6> = DummyQty - Logging_Services('AppendLog', objLog, LogData, @RM, @FM) - Response = GRWfrQty:@FM:ScrapQty:@FM:ProdTWQty:@FM:DummyQty - end else - Error_Services('Add', 'Error reading WO_MAT record in ':Service:'.') - end - end else - Error_Services('Add', 'Error reading WO_MAT_KEY from REACT_RUN table in ':Service:'.') - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetRunInfo -// -// Input: -// GaNRunID - [Required] -// -// Output: -// Returns the following information from the Wafer Track database: -// 1 - GaN Run/Etch ID Recipe -// 2 - GaN Susc Serial Number -// 3 - Pocket Numbers -// 4 - Wafer Scribes -// 5 - Sattelite Serial Numbers -// 6 - Part Number -// 7 - Reactor Number -// Output Format: -// Rows are @FM delimited, Columns are @VM delimited -// -// Note: -// This service cannot run directly on the App server due to the fact that the Wafer Track database -// is within the EC domain. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetRunInfo(GaNRunID) - - Response = '' - Query = 'Declare @RunNumber varchar(50) ' | - : "Set @RunNumber = '":GaNRunID:"' " | - : 'SELECT ' | - : '[Recipe] ' | - : ',[Platter S/N] ' | - : ',[Pocket_Number] ' | - : ',[Wafer_Lot] ' | - : ',[Satellite S/N] ' | - : ',[Part Number] ' | - : 'FROM [G4Wafers_01].[dbo].[Prerun Info] ' | - : 'WHERE [Run Number] = @RunNumber ' | - : 'ORDER BY [Pocket_Number]' - - GaNRunData = SQL_Services('PostSQLRequest', 'IQSDMS1', Query) - If Error_Services('NoError') then - Convert @FM to @VM in GaNRunData - Convert @RM to @FM in GaNRunData - NumRows = DCount(GaNRunData, @FM) - For RowIndex = 1 to NumRows - GaNRunData = GaNRunID[1, 2] - Next RowIndex - GaNRunData = SRP_Array('Rotate', GaNRunData, @FM, @VM) - Response = GaNRunData - PocketNos = Response<3> - If ( (PocketNos EQ 0) or (PocketNos EQ '') ) then - // Log error and hardcode the pockets - LogData = '' - LogData<1> = LoggingDTM - LogData<2> = GaNRunID - Convert @VM to ' ' in PocketNos - LogData<3> = PocketNos - Logging_Services('AppendLog', objPocketLog, LogData, @RM, @FM) - Scribes = Response<4> - For each Scribe in Scribes using @VM setting vPos - PocketNos<0, vPos> = Fmt(vPos,"R(0)#2") - Next Scribe - Response<3> = PocketNos - end - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetToolList -// -// Output: -// Returns a @FM delimited array of GaN related tools. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetToolList(ReactorFlag) - - Tool = '' - If ReactorFlag EQ True$ then - GaNToolQuery = "SELECT TOOL WITH TOOL_TYPE EQ 'G5' OR WITH TOOL_TYPE EQ 'G5+' OR WITH TOOL_TYPE EQ 'char' " - GaNToolQuery := "OR WITH TOOL_TYPE EQ 'GaN' OR WITH TOOL_TYPE EQ 'Transfer'" - end else - GaNToolQuery = 'SELECT TOOL WITH TOOL_PROC "G" BY TOOL_WH BY TOOL_TYPE' - end - Set_Status(0) - RList(GaNToolQuery, TARGET_SAVELIST$, 'GAN_TOOL_LIST', 'Current List of GaN Tools', False$) - GaNToolList = Database_Services('ReadDataRow', 'SYSLISTS', 'GAN_TOOL_LIST') - // Remove field containing list description - GaNToolList = Delete(GaNToolList, 1, 0, 0) - errCode = '' - If Get_Status(errCode) then - ErrorMsg = 'Error retrieving GaN tool list from the ':Service:' module. Error code':errCode - Error_Services('Add', ErrorMsg) - end - Response = GaNToolList - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetAvailableRunIDs -// -// Output: -// Returns a @FM delimited list of GaN Run IDs, which have not yet been bound to an RDS. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetAvailableRunIDs(Reactor, WorkOrder) - - Response = '' - AllRunIDs = Database_Services('ReadDataRow', 'APP_INFO', 'PRERUN_GAN_RUN_IDS') - For each RunID in AllRunIDs using @FM setting fPos - Convert @Lower.Case to @Upper.Case in RunID - If RunID[1, 2] EQ Reactor then - If WorkOrder NE '' then - GaNSchedWorkOrder = Xlate('GAN_SCHEDULE', RunID, 'WORK_ORDER', 'X') - If WorkOrder EQ GaNSchedWorkOrder then - Convert @Upper.Case to @Lower.Case in RunID - Response<-1> = RunID - end - end else - Convert @Upper.Case to @Lower.Case in RunID - Response<-1> = RunID - end - end - Next RunID - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetAvailableEtchIDs -// -// Output: -// Returns a @FM delimited list of GaN Etch IDs, which have not yet been bound to an RDS. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetAvailableEtchIDs(Reactor) - - Response = '' - AllEtchIDs = Database_Services('ReadDataRow', 'APP_INFO', 'PRERUN_GAN_ETCH_IDS') - For each EtchID in AllEtchIDs using @FM setting fPos - If EtchID[1, 2] EQ Reactor then - Response<-1> = EtchID - end - Next EtchID - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// ConsumeExtEtchID -// -// Input: ExtEtchID [Required] -// -// Output: -// True$ (1) if successful, False$ (0) otherwise. -// -//---------------------------------------------------------------------------------------------------------------------- -Service ConsumeExtEtchID(ExtEtchID) - - Reponse = False$ - ElapTime = 0 - If ExtEtchID NE '' then - RequestTime = Time() - Loop - ElapTime = Time() - RequestTime - HaveLock = Database_Services('GetKeyIDLock', 'APP_INFO', 'PRERUN_GAN_ETCH_IDS') - Until HaveLock or ElapTime GT 5 - Repeat - - If HaveLock then - AvailableEtchIDs = Database_Services('ReadDataRow', 'APP_INFO', 'PRERUN_GAN_ETCH_IDS') - Locate ExtEtchID in AvailableEtchIDs using @FM setting fPos then - AvailableEtchIDs = Delete(AvailableEtchIDs, fPos, 0, 0) - Database_Services('WriteDataRow', 'APP_INFO', 'PRERUN_GAN_ETCH_IDS', AvailableEtchIDs, True$, False$, True$) - Reponse = True$ - ConsumedEtchIDs = Database_Services('ReadDataRow', 'APP_INFO', 'PRERUN_ETCH_IDS_CONSUMED') - // Add this Etch ID to the consumed Etch ID list to use for filtering the combo box on the REACT_RUN - // form. - Locate ExtEtchID in ConsumedEtchIDs using @FM setting cPos else - ConsumedEtchIDs<-1> = ExtEtchID - ConsumedEtchIDs = SRP_Array('SortRows', ConsumedEtchIDs, 'AR1', 'LIST') - Database_Services('WriteDataRow', 'APP_INFO', 'PRERUN_ETCH_IDS_CONSUMED', ConsumedEtchIDs, True$, False$, True$) - end - end - Database_Services('ReleaseKeyIDLock', 'APP_INFO', 'PRERUN_GAN_ETCH_IDS') - end - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// RemoveRunID -// -// Input: RunID [Required] -// -// Output: -// True$ (1) if successful, False$ (0) otherwise. -// -//---------------------------------------------------------------------------------------------------------------------- -Service RemoveRunID(RunID) - - Reponse = False$ - If RunID NE '' then - RequestTime = Time() - Loop - ElapTime = Time() - RequestTime - HaveLock = Database_Services('GetKeyIDLock', 'APP_INFO', 'PRERUN_GAN_RUN_IDS', True$) - Until HaveLock or ElapTime GT 5 - Repeat - - If HaveLock then - AvailableRunIDs = Database_Services('ReadDataRow', 'APP_INFO', 'PRERUN_GAN_RUN_IDS') - Locate RunID in AvailableRunIDs using @FM setting fPos then - AvailableRunIDs = Delete(AvailableRunIDs, fPos, 0, 0) - Database_Services('WriteDataRow', 'APP_INFO', 'PRERUN_GAN_RUN_IDS', AvailableRunIDs, True$, False$, False$) - Response = True$ - end - Database_Services('ReleaseKeyIDLock', 'APP_INFO', 'PRERUN_GAN_RUN_IDS') - ConsumedRunIDs = Database_Services('ReadDataRow', 'APP_INFO', 'PRERUN_RUN_IDS_CONSUMED') - // Add this Run ID to the consumed Run ID list to use for filtering the combo box on the REACT_RUN form. - Locate RunID in ConsumedRunIDs using @FM setting cPos else - ConsumedRunIDs<-1> = RunID - ConsumedRunIDs = SRP_Array('SortSimpleList', ConsumedRunIDs) - Database_Services('WriteDataRow', 'APP_INFO', 'PRERUN_RUN_IDS_CONSUMED', ConsumedRunIDs, True$, False$, True$) - end - end - - If ElapTime GT 5 then - Error_Services('Add', 'Error removing Run ID ':RunID: ' from PRERUN_GAN_RUN_IDS') - LogData = '' - LogData<1> = LoggingDTM - LogData<2> = @USER4 - LogData<3> = EtchID - Machine = Environment_Services('GetServer') - If Machine NE 'MESSA01EC' then - EmailAddr = 'dstieber@srpcs.com,Francois.Rivard@infineon.com,Dan.Crisp@infineon.com,4805890050@vtext.com,6613649828@txt.att.net' - EmailMsg = 'Error removing Run ID: ':RunID:' from APP_INFO*PRERUN_GAN_RUN_IDS' - Logging_Services('AppendLog', ObjLog, LogData, @RM, @FM, False$, EmailAddr, EmailMsg) - end else - Logging_Services('AppendLog', ObjLog, LogData, @RM, @FM, False$) - end - end - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// UpdateAvailableRunIDs -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service UpdateAvailableRunIDs() - - hSysLists = Database_Services('GetTableHandle', 'SYSLISTS') - Lock hSysLists, ServiceKeyID then - SearchDTM = OConv( (DateTime() - 2) , 'DT') - Response = '' - WaferTrackDB = Environment_Services('GetWaferTrackProductionPath') - Query = 'Declare @RunDTM varchar(50) ' | - : "Set @RunDTM = '":SearchDTM:"' " | - : 'SELECT DISTINCT ' | - : '[Run Number] ' | - : 'FROM [G4Wafers_01].[dbo].[Prerun Info] ' | - : "WHERE [Date] >= @RunDTM and ([Run Number] like '%mvfet' or [Run Number] like '%hvfet') " | - : "ORDER BY [Run Number] " - - NewGaNRunIDs = SQL_Services('GetDataRows', 'IQSDMS1', Query, 10) - Convert @FM to @VM in NewGaNRunIDs - Convert @RM to @FM in NewGanRunIDs - CurrGaNRunIDs = Database_Services('ReadDataRow', 'APP_INFO', 'PRERUN_GAN_RUN_IDS') - HaveLock = Database_Services('GetKeyIDLock', 'APP_INFO', 'PRERUN_GAN_RUN_IDS', True$) - ConsumedRunIDs = Database_Services('ReadDataRow', 'APP_INFO', 'PRERUN_RUN_IDS_CONSUMED') - NeedToWrite = False$ - If HaveLock EQ True$ then - // OK to update - If (NewGaNRunIDs NE '') and (NewGaNRunIDs NE 0) then - // Merge new and current list ensuring unique values - For each GaNRunID in NewGaNRunIDs using @FM setting gPos - Locate GaNRunID in CurrGaNRunIDs using @FM setting fPos else - // Check if etch ID has already been consumed. Only add the etch ID to the available list if - // it has not yet been consumed. - Locate GaNRunID in ConsumedRunIDs using @FM setting cPos else - CurrGaNRunIDs<-1> = GaNRunID - end - end - Next GaNRunID - // Sort list to ensure list is sorted - CurrGaNRunIDs = SRP_Array('SortRows', CurrGanRunIDs, 'AL1', 'LIST', @FM, '') - Database_Services('WriteDataRow', 'APP_INFO', 'PRERUN_GAN_RUN_IDS', CurrGaNRunIDs, True$, False$, True$) - end - Database_Services('ReleaseKeyIDLock', 'APP_INFO', 'PRERUN_GAN_RUN_IDS') - end - Unlock hSysLists, ServiceKeyID else Null - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetReactor -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetReactor(WorkOrderNo) - - Reactor = '' - If (WorkOrderNo NE '') then - If RowExists('WO_LOG', WorkOrderNo) then - PVDesc = Xlate('WO_LOG', WorkOrderNo, 'PROD_VER_DESC', 'X') - Begin Case - Case Indexc(PVDesc, 'G5+', 1) - Reactor = 69 - Case Indexc(PVDesc, 'G5', 1) - Reactor = 71 - Case Otherwise$ - Error_Services('Add', 'Error in ':Service:'. PROD_VER_DESC does not match any GaN reactors.') - End Case - end else - Error_Services('Add', 'Error in ':Service:'. WO_LOG record ':WorkOrderNo:' does not exist.') - end - end - Response = Reactor - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// UpdateAvailableEtchIDs -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service UpdateAvailableEtchIDs() - - hSysLists = Database_Services('GetTableHandle', 'SYSLISTS') - Lock hSysLists, ServiceKeyID then - SearchDTM = OConv( (DateTime() - 1) , 'DT') - Response = '' - WaferTrackDB = Environment_Services('GetWaferTrackProductionPath') - Query = 'Declare @RunDTM varchar(50) ' | - : "Set @RunDTM = '":SearchDTM:"' " | - : 'SELECT DISTINCT ' | - : '[Run Number] ' | - : 'FROM [G4Wafers_01].[dbo].[Prerun Info] ' | - : "WHERE [Date] > @RunDTM and [Run Number] like '%etch' " | - : "ORDER BY [Run Number] " - - NewGaNEtchIDs = SQL_Services('GetDataRows', 'IQSDMS1', Query) - Convert @FM to @VM in NewGaNEtchIDs - Convert @RM to @FM in NewGanEtchIDs - CurrGaNEtchIDs = Database_Services('ReadDataRow', 'APP_INFO', 'PRERUN_GAN_ETCH_IDS') - HaveLock = Database_Services('GetKeyIDLock', 'APP_INFO', 'PRERUN_GAN_ETCH_IDS', True$) - ConsumedEtchIDs = Database_Services('ReadDataRow', 'APP_INFO', 'PRERUN_ETCH_IDS_CONSUMED') - NeedToWrite = False$ - If HaveLock EQ True$ then - // OK to update - If (NewGaNEtchIDs NE '') and (NewGaNEtchIDs NE 0) then - // Merge new and current list ensuring unique values - For each GaNEtchID in NewGaNEtchIDs using @FM setting gPos - Locate GaNEtchID in CurrGaNEtchIDs using @FM setting fPos else - // Check if etch ID has already been consumed. Only add the etch ID to the available list if - // it has not yet been consumed. - Locate GaNEtchID in ConsumedEtchIDs using @FM setting cPos else - CurrGaNEtchIDs<-1> = GaNEtchID - end - end - Next GaNEtchID - // Sort list to ensure list is sorted - CurrGaNEtchIDs = SRP_Array('SortRows', CurrGanEtchIDs, 'AL1', 'LIST', @FM, '') - Database_Services('WriteDataRow', 'APP_INFO', 'PRERUN_GAN_ETCH_IDS', CurrGaNEtchIDs, True$, False$, True$) - end - Database_Services('ReleaseKeyIDLock', 'APP_INFO', 'PRERUN_GAN_ETCH_IDS') - end - Unlock hSysLists, ServiceKeyID else Null - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// UpdateGaNScheduleInfo -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service UpdateGaNScheduleInfo() - - hSysLists = Database_Services('GetTableHandle', 'SYSLISTS') - Lock hSysLists, ServiceKeyID then - GanSchedRec = '' - GaNReactors = '' - Query = "SELECT REACTOR WITH REACT_TYPE EQ 'GAN'" - GoSub ClearCursors - Rlist(Query, Target_ActiveList$, '', '', '') - EOF = False$ - If @RecCount then - Loop - Until EOF EQ True$ - ReadNext ReactorID else EOF = True$ - Locate ReactorID in GaNReactors using @FM setting rPos else - GaNReactors<-1> = ReactorID - end - Repeat - end - GoSub ClearCursors - SchedPath = Environment_Services('GetGaNSchedulePath') - // GaN Reactor Scheduler Excel Spreadsheet --------------------- - For each Reactor in GaNReactors using @FM setting fPos - SchedFilename = 'R':Reactor:' Growth Schedule.xls' - SchedFilePath = SchedPath:'\':SchedFilename - SchedExcelHandle = Excel_Services('OpenDocument', SchedFilePath) - If Error_Services('NoError') then - SchedWorksheet = 'Schedule' - NumExcelRows = Excel_Services('GetNumRows', SchedExcelHandle, SchedWorksheet) - For Row = (NumExcelRows - 500) to (NumExcelRows - 1) - ExcelRunID = Excel_Services('GetCellValue', SchedExcelHandle, SchedWorksheet, 'E', Row) - ValidRunID = (ExcelRunID[1,2] EQ Reactor) - If ValidRunID EQ True$ then - GaNSchedKey = ExcelRunID - // WT = WaferTrack - ExcelWTPart = Excel_Services('GetCellValue', SchedExcelHandle, SchedWorksheet, 'H', Row) - ExcelOIPart = Excel_Services('GetCellValue', SchedExcelHandle, SchedWorksheet, 'I', Row) - ExcelRecipe = Excel_Services('GetCellValue', SchedExcelHandle, SchedWorksheet, 'L', Row) - ExcelWorkOrder = Excel_Services('GetCellValue', SchedExcelHandle, SchedWorkSheet, 'G', Row) - If RowExists('GAN_SCHEDULE', GaNSchedKey) then - // Row exists, check if recipe has been changed. - GaNSchedRec = Database_Services('ReadDataRow', 'GAN_SCHEDULE', GanSchedKey) - GaNWTPart = GanSchedRec - GaNOIPart = GanSchedRec - GaNRecipe = GanSchedRec - GaNWorkOrder = GanSchedRec - If (GaNWTPart NE ExcelWTPart) or (GaNOIPart NE ExcelOIPart) or (GaNRecipe NE ExcelRecipe) or (GaNWorkOrder NE ExcelWorkOrder) then - // GaN Schedule updated, update OpenInsight - GanSchedRec = ExcelWTPart - GanSchedRec = ExcelOIPart - GaNSchedRec = ExcelRecipe - GaNSchedRec = ExcelWorkOrder - Database_Services('WriteDataRow','GAN_SCHEDULE',GaNSchedKey,GanSchedRec,True$,False$,True$) - end - end else - // Row does not yet exist, so create it. - GanSchedRec = ExcelRecipe - GanSchedRec = ExcelWTPart - GanSchedRec = ExcelOIPart - GanSchedRec = ExcelWorkOrder - Database_Services('WriteDataRow','GAN_SCHEDULE',GaNSchedKey,GanSchedRec,True$,False$,True$) - end - end - Next Row - Excel_Services('CloseDocument', SchedExcelHandle) - end - Next Reactor - - Unlock hSysLists, ServiceKeyID else Null - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// UpdateDisposition -// -// This service contains automatic disposition logic for engineering lots. -// -//---------------------------------------------------------------------------------------------------------------------- -Service UpdateDisposition(RDSNo) - - CurrDTM = DateTime() - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - OrigReactRunRec = ReactRunRec - InWfrIDs = ReactRunRec - ShipFlags = ReactRunRec - RetainFlags = ReactRunRec - InternalFlags = ReactRunRec - ExternalFlags = ReactRunRec - CassDispComp = ReactRunRec - WfrsDispReady = ReactRunRec - NCRReqFlags = ReactRunRec - CharFlags = ReactRunRec - NumWfrs = DCount(InWfrIDs, @VM) - For WfrIndex = 1 to NumWfrs - WfrID = InWfrIDs<0, WfrIndex> - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WfrID) - OrigWOWfrRec = WOWfrRec - ShipFlag = ShipFlags<0, WfrIndex> - RetainFlag = RetainFlags<0, WfrIndex> - InternalFlag = InternalFlags<0, WfrIndex> - ExternalFlag = ExternalFlags<0, WfrIndex> - CharFlag = CharFlags<0, WfrIndex> - DispReady = WfrsDispReady<0, WfrIndex> - NCRNo = WOWfrRec - NCRStatus = Xlate('NCR', NCRNo, 'STATUS', 'X') - CriticalFailFlag = WOWfrRec - NCRReq = NCRReqFlags<0, WfrIndex> - DestStatus = GaN_Services('GetDestroyedStatus', WfrID) - If ( (CharFlag EQ 'DUMMY') or (CharFlag EQ 'EMPTY') ) then - DispReady = True$ - WfrsDispReady<0, WfrIndex> = DispReady - ReactRunRec = WfrsDispReady - WOWfrRec = 'Ready to close' - end - If DestStatus EQ True$ then - // Mark wafer's internal flag. Clear all other flags. - If ( (InternalFlag EQ False$) or (InternalFlag EQ '') ) then - ShipFlag = False$ - RetainFlag = False$ - InternalFlag = True$ - ExternalFlag = False$ - ShipFlags<0, WfrIndex> = ShipFlag - RetainFlags<0, WfrIndex> = RetainFlag - InternalFlags<0, WfrIndex> = InternalFlag - ExternalFlags<0, WfrIndex> = ExternalFlag - ReactRunRec = ShipFlags - ReactRunRec = RetainFlags - ReactRunRec = InternalFlags - ReactRunRec = ExternalFlags - end - end - - MetStatus = GaN_Services('GetMetrologyStatus', WfrID) - DispStatus = GaN_Services('GetDispStatus', WfrID) - - Begin Case - Case CriticalFailFlag EQ True$ - // Bow and/or warp critical limit exceeded, so the wafer must be - // destroyed to prevent damage to candela tools - Reason = 'Bow and/or warp critical limit exceeded' - Begin Case - Case ( (NCRNo NE '') and (NCRStatus EQ 'C') ) - WOWfrRec = 'Ready to close' - Case ( (NCRNo NE '') and (NCRStatus NE 'C') ) - WOWfrRec = 'NCR must be closed' - Case NCRNo EQ '' - WOWfrRec = 'Wafer requires an NCR' - End Case - DispReady = ( (NCRNo NE '') and (NCRStatus EQ 'C') ) - WfrsDispReady<0, WfrIndex> = DispReady - ReactRunRec = WfrsDispReady - - Case ( (MetStatus EQ True$) or (DispStatus EQ True$) ) - // Check Ship, Interal, External, and Retain conditions to determine if wafer should be removed from the WIP - FormattedWfrID = WfrID - Convert '*' to '.' in FormattedWfrID - Begin Case - Case ShipFlag EQ True$ - GPackQ = GaN_Services('GetLocQueueID', 'G_PACK') - ShipID = ReactRunRec - RunStageWfrKey = RDSNo:'*DISP*':FormattedWfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - StageStatus = RunStageWfrRec - If StageStatus _EQC 'INIT' then - // Mark DISP stage as complete - RunStageWfrRec = @USER4 - RunStageWfrRec = CurrDTM - RunStageWfrRec = 'COMP' - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$) - end - Begin Case - Case (ShipID EQ '') - LocQ = GaN_Services('GetWfrQueue', WfrID) - WOWfrRec = 'Wafer needs to be placed in an outbound cassette' - If LocQ _EQC GPackQ then - // Wafer is being removed from an outbound cassette, so place the wafer back into the G_PACK - // queue and reset the G_PACK RUN_STAGE_WFR record to 'INIT'. - RunStageWfrKey = RDSNo:'*G_PACK*':FormattedWfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - StageStatus = RunStageWfrRec - If StageStatus _EQC 'COMP' then - RunStageWfrRec = '' - RunStageWfrRec = '' - RunStageWfrRec = 'INIT' - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$) - Gan_Services('MoveWfrToQueue', WfrID, GPackQ) - end - end else - // Wafer has been marked as shipped in the Disposition Report (Excel spreadsheet), but has - // not yet been added to an outbound cassette. Remove the wafer from its current location - // (which likely is DISP), then place the wafer in the G_PACK location queue and update - // the wafer trace (WO_WFR record). - Gan_Services('RemoveWfrFromWIP', WfrID) - Gan_Services('MoveWfrToQueue', WfrID, GPackQ) - // Update wafer trace (WO_WFR record) - LocDTM = WOWfrRec - NextPos = DCount(LocDTM, @VM) + 1 - WOWfrRec = CurrDTM - WOWfrRec = @USER4 - WOWfrRec = 'COMP' - WOWfrRec = '' - WOWfrRec = GPackQ - end - Case ( (ShipID NE '') and ( (CassDispComp EQ False$) or (CassDispComp EQ '') ) ) - // Wafer is ready for disposition, so mark it as such. Once user marks the cassette - // disposition complete, then the wafer will move off the WIP. Move wafer to the G_PACK - // location queue if it is not there and update the wafer trace (WO_WFR record). - If (NCRReq EQ False$) or ( (NCRReq EQ True$) and (NCRNo NE '') ) then - LocQ = Gan_Services('GetWfrQueue', WfrID) - Gan_Services('RemoveWfrFromWIP', WfrID) - Gan_Services('MoveWfrToQueue', WfrID, GPackQ) - // Update wafer trace (WO_WFR record) - LocDTM = WOWfrRec - NextPos = DCount(LocDTM, @VM) + 1 - WOWfrRec = CurrDTM - WOWfrRec = @USER4 - WOWfrRec = 'G_PACK' - WOWfrRec = '' - WOWfrRec = GPackQ - WOWfrRec = 'Ready to close' - DispReady = True$ - WfrsDispReady<0, WfrIndex> = DispReady - ReactRunRec = WfrsDispReady - end - Case ( (ShipID NE '') and (CassDispComp EQ True$) ) - // A ship ID has been added (i.e. the wafer has been placed in an outbound cassette and the - // user has marked the cassette disposition as complete, so remove the wafer from the - // GaN WIP and mark the G_PACK stage as complete.) - RunStageWfrKey = RDSNo:'*G_PACK*':FormattedWfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - StageStatus = RunStageWfrRec - LocQ = Gan_Services('GetWfrQueue', WfrID) - WOWfrRec = 'Run closed' - Gan_Services('RemoveWfrFromWIP', WfrID) - If StageStatus _EQC 'INIT' then - // Mark G_PACK stage as complete - RunStageWfrRec = @USER4 - RunStageWfrRec = CurrDTM - RunStageWfrRec = 'COMP' - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$) - end - Case Otherwise$ - // No action necessary at this time. - Null - End Case - - Case RetainFlag EQ True$ - - RetainSlot = WOWfrRec - RetainBox = WOWfrRec - RetainSig = WOWfrRec - RetainQ = GaN_Services('GetLocQueueID', 'RETAIN') - RunStageWfrKey = RDSNo:'*DISP*':FormattedWfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - StageStatus = RunStageWfrRec - If StageStatus _EQC 'INIT' then - // Retain flag has been set and metrology is complete, so mark DISP stage as complete. - RunStageWfrRec = @User4 - RunStageWfrRec = CurrDTM - RunStageWfrRec = 'COMP' - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$) - end - Begin Case - - Case ( (RetainSlot EQ '') or (RetainBox EQ '') ) - // Wafer needs to go into RETAIN queue until it receives a Retain Slot and Retain Box - // If wafer is not at RETAIN, then update wafer trace (WO_WFR record) and move the wafer. - WOWfrRec = 'Wafer requires a retain box and retain slot' - CurrStage = GaN_Services('GetCurrStage', WfrID) - LocQ = GaN_Services('GetWfrQueue', WfrID) - Gan_Services('RemoveWfrFromWIP', WfrID) - Gan_Services('MoveWfrToQueue', WfrID, RetainQ) - If CurrStage NE 'RETAIN' then - LocDTM = WOWfrRec - NextPos = DCount(LocDTM, @VM) + 1 - WOWfrRec = CurrDTM - WOWfrRec = @USER4 - WOWfrRec = 'COMP' - WOWfrRec = '' - WOWfrRec = RetainQ - end - Case ( (RetainSlot NE '') and (RetainBox NE '') and (CassDispComp NE True$) ) - // Wafer is ready for disposition, so mark it as such. Once user marks the cassette - // disposition complete, then the wafer will move off the WIP. Move wafer into RETAIN stage - // if it is not currently there. This can occur if an RDS is opened after being closed. - If ( ( (NCRReq EQ False$) or ( (NCRReq EQ True$) and (NCRNo NE '') ) ) and (RetainSig NE '') ) then - WOWfrRec = 'Ready to close' - DispReady = True$ - end else - WOWfrRec = 'Wafer has not yet been retained' - DispReady = False$ - end - RetainQ = 'GCH*Q_RETAIN' - LocQ = Gan_Services('GetWfrQueue', WfrID) - Gan_Services('RemoveWfrFromWIP', WfrID) - Gan_Services('MoveWfrToQueue', WfrID, RetainQ) - LocDTM = WOWfrRec - NextPos = DCount(LocDTM, @VM) + 1 - WOWfrRec = CurrDTM - WOWfrRec = @USER4 - WOWfrRec = 'RETAIN' - WOWfrRec = '' - WOWfrRec = RetainQ - WfrsDispReady<0, WfrIndex> = DispReady - ReactRunRec = WfrsDispReady - Case ( ( (RetainSlot NE '') and (RetainBox NE '') and (RetainSig NE '') ) and (CassDispComp EQ True$) ) - // Retain slot and retain box are populated and the user has marked disposition complete -> - // mark RETAIN stage complete and remove the wafer from the GaN WIP. - RunStageWfrKey = RDSNo:'*RETAIN*':FormattedWfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - StageStatus = RunStageWfrRec - LocQ = Gan_Services('GetWfrQueue', WfrID) - WOWfrRec = 'Run closed' - Gan_Services('RemoveWfrFromWIP', WfrID) - If StageStatus _EQC 'INIT' then - RunStageWfrRec = @User4 - RunStageWfrRec = CurrDTM - RunStageWfrRec = 'COMP' - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$) - end - Case Otherwise$ - // No action necessary at this time. - Null - - End Case - - Case InternalFlag EQ True$ - Begin Case - Case ( (CassDispComp EQ False$) or (CassDispComp EQ '') ) - // Wafer is ready for disposition, so mark it as such. Once user marks the cassette - // disposition complete, then the wafer will move off the WIP. - DispReady = True$ - WfrsDispReady<0, WfrIndex> = DispReady - ReactRunRec = WfrsDispReady - WOWfrRec = 'Ready to close' - Case CassDispComp EQ True$ - // Remove the wafer from the GaN WIP and mark DISP stage as complete. - RunStageWfrKey = RDSNo:'*DISP*':FormattedWfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - StageStatus = RunStageWfrRec - LocQ = GaN_Services('GetWfrQueue', WfrID) - WOWfrRec = 'Run closed' - Gan_Services('RemoveWfrFromWIP', WfrID) - If StageStatus _EQC 'INIT' then - // Mark DISP stage as complete - RunStageWfrRec = @User4 - RunStageWfrRec = CurrDTM - RunStageWfrRec = 'COMP' - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$) - end - End Case - - Case ExternalFlag EQ True$ - - Begin Case - Case ( (CassDispComp EQ False$) or (CassDispComp EQ '') ) - // Check to see if an NCR has been added to this wafer before marking this wafer as ready - // to be dispositioned. - If ( (NCRReq EQ False$) or ( (NCRReq EQ True$) and (NCRNo NE '') ) ) then - // Wafer is ready for disposition, so mark it as such. Once user marks the cassette - // disposition complete, then the wafer will move off the WIP. - DispReady = True$ - WfrsDispReady<0, WfrIndex> = DispReady - ReactRunRec = WfrsDispReady - WOWfrRec = 'Ready to close' - end - Case CassDispComp EQ True$ - // Remove the wafer from the GaN WIP and mark DISP stage as complete. - RunStageWfrKey = RDSNo:'*DISP*':FormattedWfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - StageStatus = RunStageWfrRec - WOWfrRec = 'Run closed' - LocQ = Gan_Services('GetWfrQueue', WfrID) - Gan_Services('RemoveWfrFromWIP', WfrID) - If StageStatus _EQC 'INIT' then - // Mark DISP stage as complete - RunStageWfrRec = @User4 - RunStageWfrRec = CurrDTM - RunStageWfrRec = 'COMP' - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$) - end - End Case - - Case Otherwise$ - // All flags false. Lot aborted or disposition report not found. - Begin Case - Case ( (CassDispComp EQ False$) or (CassDispComp EQ '') ) - // Move wafer to DISP queue if it is not there - DispQ = 'GGR*Q_DISP' - CurrQ = Gan_Services('GetWfrQueue', WfrID) - If CurrQ _NEC DispQ then - Gan_Services('RemoveWfrFromWIP', WfrID) - Gan_Services('MoveWfrToQueue', WfrID, DispQ) - end - // Check to see if an NCR has been added to this wafer before marking this wafer as ready - // to be dispositioned. - If ( (NCRReq EQ False$) or ( (NCRReq EQ True$) and (NCRNo NE '') ) ) then - // Wafer is ready for disposition, so mark it as such. Once user marks the cassette - // disposition complete, then the wafer will move off the WIP. - DispReady = True$ - WfrsDispReady<0, WfrIndex> = DispReady - ReactRunRec = WfrsDispReady - WOWfrRec = 'Ready to close' - end else - If NCRReq EQ True$ then - WOWfrRec = 'NCR required' - end else - WOWfrRec = 'Disposition report not found' - end - end - Case CassDispComp EQ True$ - // Remove the wafer from the GaN WIP and mark DISP stage as complete. - RunStageWfrKey = RDSNo:'*DISP*':FormattedWfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - StageStatus = RunStageWfrRec - WOWfrRec = 'Run closed' - LocQ = GaN_Services('GetWfrQueue', WfrID) - Gan_Services('RemoveWfrFromWIP', WfrID) - If StageStatus _EQC 'INIT' then - // Mark DISP stage as complete - RunStageWfrRec = @User4 - RunStageWfrRec = CurrDTM - RunStageWfrRec = 'COMP' - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$) - end - End Case - End Case - - Case Otherwise$ - // Metrology or Disposition not complete - WOWfrRec = 'Metrology incomplete' - - End Case - - If OrigWOWfrRec NE WOWfrRec then Database_Services('WriteDataRow', 'WO_WFR', WfrID, WOWfrRec, True$, False$, True$) - - Next WfrIndex - If OrigReactRunRec NE ReactRunRec then Database_Services('WriteDataRow', 'REACT_RUN', RDSNo, ReactRunRec, True$, False$, True$) - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetStageDesc -// -// Input: -// StageID - [Required] -// -// Output: -// Returns the GaN stage description associated with the StageID passed in. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetStageDesc(StageID) - - Response = '' - Done = False$ - GaNStageInfo = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_STAGES') - For each StageRow in GanStageInfo using @FM setting fPos - Locate StageID in StageRow using @VM setting vPos then - StageDesc = StageRow<0, 2> - Response = StageDesc - Done = True$ - end - Until Done EQ True$ - Next StageRow - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetStageID -// -// Input: -// StageDesc - [Required] -// -// Output: -// Returns the GaN stage ID associated with the stage description passed in. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetStageID(StageDesc, StageQ, ToolClass) - - Response = '' - If ( (StageDesc NE '') or (StageQ NE '') or (ToolClass NE '') )then - Done = False$ - GaNStageInfo = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_STAGES') - For each StageRow in GanStageInfo using @FM setting fPos - Begin Case - Case StageDesc NE '' - Locate StageDesc in StageRow using @VM setting vPos then - StageID = StageRow<0, 1> - Response = StageID - Done = True$ - end - Case StageQ NE '' - Locate StageQ in StageRow using @VM setting vPos then - StageID = StageRow<0, 1> - Response = StageID - Done = True$ - end - Case ToolClass NE '' - Locate ToolClass in StageRow using @VM setting vPos then - StageID = StageRow<0, 1> - Response = StageID - Done = True$ - end - End Case - Until Done EQ True$ - Next StageRow - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetStageIndex -// -// Input: -// StageID - [Required] -// or -// StageDesc - [Required] -// -// Output: -// Returns the GaN stage index associated with the stage ID/description passed in. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetStageIndex(StageID, StageDesc) - - Response = '' - If (StageID NE '') or (StageDesc NE '') then - If StageID NE '' then - StageKey = StageID - end else - StageKey = StageDesc - end - Done = False$ - GaNStageInfo = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_STAGES') - For each StageRow in GanStageInfo using @FM setting fPos - Locate StageKey in StageRow using @VM setting vPos then - StageIndex = fPos - Response = StageIndex - Done = True$ - end - Until Done EQ True$ - Next StageRow - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetRunType -// -// Input: -// StageID - [Required] -// or -// StageDesc - [Required] -// -// Output: -// Returns the GaN run type (i.e. CASS or WFR) associated with the given stage description/ID. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetRunType(StageID, StageDesc) - - Response = '' - Done = False$ - GaNStageInfo = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_STAGES') - Begin Case - Case StageID NE '' - For each StageRow in GanStageInfo using @FM setting fPos - Locate StageID in StageRow using @VM setting vPos then - RunType = StageRow<0, 4> - Response = RunType - Done = True$ - end - Until Done EQ True$ - Next StageRow - Case StageDesc NE '' - For each StageRow in GanStageInfo using @FM setting fPos - Locate StageDesc in StageRow using @VM setting vPos then - RunType = StageRow<0, 4> - Response = RunType - Done = True$ - end - Until Done EQ True$ - Next StageRow - End Case - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetStageType -// -// Input: -// StageID - [Required] -// or -// StageDesc - [Required] -// -// Output: -// Returns the GaN stage type (i.e. Reactor, Metrology, or Disposition) associated with the given stage -// description/ID. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetStageType(StageID, StageDesc) - - Response = '' - Done = False$ - GaNStageInfo = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_STAGES') - Begin Case - Case StageID NE '' - For each StageRow in GanStageInfo using @FM setting fPos - Locate StageID in StageRow using @VM setting vPos then - StageType = StageRow<0, 5> - Response = StageType - Done = True$ - end - Until Done EQ True$ - Next StageRow - Case StageDesc NE '' - For each StageRow in GanStageInfo using @FM setting fPos - Locate StageDesc in StageRow using @VM setting vPos then - StageType = StageRow<0, 5> - Response = StageType - Done = True$ - end - Until Done EQ True$ - Next StageRow - End Case - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetCassStages -// -// Input: -// ReactRunID - [Required] -// -// Output: -// Response - @VM delimited array of GaN cassette-level stages associated with the given REACT_RUN ID. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetCassStages(ReactRunID) - - Response = '' - PSNo = Xlate('REACT_RUN', ReactRunID, 'PS_NO', 'X') - If PSNo NE '' then - GaNStageInfo = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_STAGES') - PRSStageKeys = Xlate('PROD_SPEC', PSNo, 'PRS_STAGE_KEY', 'X') - CassStages = '' - For each PRSStageKey in PRSStageKeys using @VM - StageID = Field(PRSStageKey, '*', 2) - Done = False$ - For each GaNStageRow in GaNStageInfo using @FM setting fPos - Locate StageID in GaNStageRow using @VM setting vPos then - RunType = GaNStageRow<0, 4> - If RunType EQ 'CASS' then - CassStages<1, fPos> = StageID - Done = True$ - end - end - Until Done EQ True$ - Next GaNStageRow - Next PRSStageKey - Convert @VM to ' ' in CassStages - CassStages = Trim(CassStages) - Convert ' ' to @VM in CassStages - Response = CassStages - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetWfrStages -// -// Input: -// ReactRunID - [Required] -// -// Output: -// Response - @VM delimited array of GaN wafer-level stages associated with the given REACT_RUN ID. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetWfrStages(ReactRunID) - - Response = '' - PSNo = Xlate('REACT_RUN', ReactRunID, 'PS_NO', 'X') - If PSNo NE '' then - GaNStageInfo = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_STAGES') - PRSStageKeys = Xlate('PROD_SPEC', PSNo, 'PRS_STAGE_KEY', 'X') - WfrStages = '' - For each PRSStageKey in PRSStageKeys using @VM - StageID = Field(PRSStageKey, '*', 2) - Done = False$ - For each GaNStageRow in GaNStageInfo using @FM setting fPos - Locate StageID in GaNStageRow using @VM setting vPos then - RunType = GaNStageRow<0, 4> - If RunType EQ 'WFR' then - WfrStages<1, fPos> = StageID - Done = True$ - end - end - Until Done EQ True$ - Next GaNStageRow - Next PRSStageKey - Convert @VM to ' ' in WfrStages - WfrStages = Trim(WfrStages) - Convert ' ' to @VM in WfrStages - Response = WfrStages - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetGaNStages -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetGaNStages(StageType=STAGETYPE, PSNo) - - If StageType NE '' then - StageOrderKeys = '' - If PSNo NE '' then StageOrderKeys = Xlate('PROD_SPEC', PSNo, 'PRS_STAGE_ROUTE', 'X') - If StageOrderKeys EQ '' then - // Use default stage configuration because no route is defined in the PSN - GaNStageArray = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_STAGES') - For each Row in GaNStageArray using @FM setting RowIndex - RunType = Row<0, 5> - If RunType EQ StageType then Response<0, -1> = Row<0, 1> - Next Row - end else - StageOrderKeys = SRP_Array('Rotate', StageOrderKeys, @VM, '*') - StageOrderList = StageOrderKeys<0, 1> - Swap '*' with @VM in StageOrderList - For each StageID in StageOrderList using @VM - ThisStageType = GaN_Services('GetStageType', StageID) - If ThisStageType EQ StageType then Response<0, -1> = StageID - Next StageID - end - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// CreateEtchRun -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service CreateEtchRun(Reactor) - - // Place Etch ID into GaN WIP under LOCATION*GCH*Q_ETCH - CurrDTM = DateTime() - LocID = 'GCH*Q_ETCH' - EtchID = NextKey('GAN_ETCH') - ToolID = 'R':Reactor - GanEtchRec = '' - GanEtchRec = Reactor - GanEtchRec = @USER4 - GanEtchRec = True$ - GanEtchRec = CurrDTM - GanEtchRec = @User4 - GanEtchRec = 'CREATE' - GanEtchRec = ToolID - GanEtchRec = LocID - Database_Services('WriteDataRow', 'GAN_ETCH', EtchID, GanEtchRec, True$, False$, True$) - LocRec = Database_Services('ReadDataRow', 'LOCATION', LocID) - LocQ = LocRec - DisplayEtchID = Xlate('GAN_ETCH', EtchID, 'DISPLAY_ETCH_ID', 'X') - Locate DisplayEtchID in LocQ using @VM setting vPos else - LocQ<1,-1> = DisplayEtchID - LocRec = LocQ - Database_Services('WriteDataRow', 'LOCATION', LocID, LocRec, True$, False$, True$) - end - Response = EtchID - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// StartEtchRun -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service StartEtchRun(EtchID) - - CurrDTM = DateTime() - GanEtchRec = Database_Services('ReadDataRow', 'GAN_ETCH', EtchID) - Reactor = GanEtchRec - ToolID = 'R':Reactor - GanEtchRec = DateTime() - GanEtchRec = CurrDTM - GanEtchRec = @User4 - GanEtchRec = 'START' - GanEtchRec = ToolID - Database_Services('WriteDataRow', 'GAN_ETCH', EtchID, GanEtchRec, True$, False$, True$) - DisplayEtchID = Xlate('GAN_ETCH', EtchID, 'DISPLAY_ETCH_ID', 'X') - // Remove from Location queue - LocID = 'GCH*Q_ETCH' - LocRec = Database_Services('ReadDataRow', 'LOCATION', LocID) - LocQ = LocRec - Locate DisplayEtchID in LocQ using @VM setting vPos then - LocQ = Delete(LocQ, 1, vPos, 0) - LocRec = LocQ - Database_Services('WriteDataRow', 'LOCATION', LocID, LocRec, True$, False$, True$) - end - // Add to Tool queue - ToolEtchRec = Database_Services('ReadDataRow', 'TOOL_ETCH', ToolID) - ToolQ = ToolEtchRec - Locate DisplayEtchID in ToolQ using @VM setting vPos else - ToolQ<1,-1> = DisplayEtchID - ToolEtchRec = ToolQ - Database_Services('WriteDataRow', 'TOOL_ETCH', ToolID, ToolEtchRec, True$, False$, True$) - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// StopEtchRun -// -// Input: -// EtchID - [Required] -// -//---------------------------------------------------------------------------------------------------------------------- -Service StopEtchRun(EtchID) - - CurrDTM = DateTime() - Reactor = Xlate('GAN_ETCH', EtchID, GAN_ETCH_REACTOR$, 'X') - ToolID = 'R':Reactor - GanEtchRec = Database_Services('ReadDataRow', 'GAN_ETCH', EtchID) - GanEtchRec = DateTime() - GanEtchRec = True$ - GanEtchRec = CurrDTM - GanEtchRec = @User4 - GanEtchRec = 'STOP' - GanEtchRec = ToolID - Database_Services('WriteDataRow', 'GAN_ETCH', EtchID, GanEtchRec, True$, False$, True$) - GaN_Services('RemoveEtchFromWIP', EtchID) - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// DeleteEtchRun -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service DeleteEtchRun(EtchID) - - GaN_Services('RemoveEtchFromWIP', EtchID) - Database_Services('DeleteDataRow', 'GAN_ETCH', EtchID, True$, False$) - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// MoveCassToQueue -// -// Input: -// WOMatKey - [Required] -// QueueID - [Required] -// -// Output: -// Response - -// -//---------------------------------------------------------------------------------------------------------------------- -Service MoveCassToQueue(WOMatKey, QueueID) - - Success = False$ - - If WOMatKey NE '' and QueueID NE '' then - QType = GaN_Services('GetQueueType', QueueID) - If QType EQ 'Location' then - QRec = Database_Services('ReadDataRow', 'LOCATION', QueueID) - CassQ = QRec - Locate WOMatKey in CassQ using @VM setting vPos else - CassQ<1, -1> = WOMatKey - QRec = CassQ - Database_Services('WriteDataRow', 'LOCATION', QueueID, QRec, True$, False$, True$) - Success = True$ - end - end else - Error_Services('Add', 'Queue ID of type "Location" not supplied') - end - end - - Response = Success - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// RemoveCassFromQueue -// -// Input: -// WOMatKey - [Required] -// QueueID - [Required] -// -// Output: -// Response - -// -//---------------------------------------------------------------------------------------------------------------------- -Service RemoveCassFromQueue(WOMatKey, QueueID) - - Success = False$ - - If WOMatKey NE '' and QueueID NE '' then - QType = GaN_Services('GetQueueType', QueueID) - If QType EQ 'Location' then - QRec = Database_Services('ReadDataRow', 'LOCATION', QueueID) - CassQ = QRec - Locate WOMatKey in CassQ using @VM setting vPos then - CassQ = Delete(CassQ, 1, vPos, 0) - QRec = CassQ - Database_Services('WriteDataRow', 'LOCATION', QueueID, QRec, True$, False$, True$) - Success = True$ - end - end else - Error_Services('Add', 'Queue ID of type "Location" not supplied') - end - - end - - Response = Success - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetCassQueue -// -// Input: -// WOMatKey - [Required] -// -// Output: -// Response - LOCATION or TOOL_WFR queue ID -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetCassQueue(WOMatKey) - - Done = False$ - CassQ = '' - GaNStages = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_STAGES') - GaNStages = SRP_Array('Rotate', GaNStages, @FM, @VM) - // Need to scan all LOCATION queues for the cassette - LocQs = GaNStages<6> - ToolClasses = GaNStages<3> - For each LocQKey in LocQs using @VM setting vPos - If LocQKey NE '' then - LocQRec = Database_Services('ReadDataRow', 'LOCATION', LocQKey) - CassettesInQ = LocQRec - Locate WOMatKey in CassettesInQ using @VM setting wPos then - Done = True$ - CassQ = LocQKey - end - end - Until Done EQ True$ - Next LocQRec - Response = CassQ - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// RemoveCassFromWIP -// -// Input: -// WOMatKey - [Required] -// -// Output: -// Response - True$ (1) if the WOMatKey was removed from the WIP, False$ (0) otherwise. -// -//---------------------------------------------------------------------------------------------------------------------- -Service RemoveCassFromWIP(WOMatKey) - - Success = False$ - If WOMatKey NE '' then - CassQueue = GaN_Services('GetCassQueue', WOMatKey) - CassInQueue = (CassQueue NE '') - If CassInQueue EQ True$ then - NumAttempts = 0 - Loop - Error_Services('Clear') - // Location queues exist perpetually, so no need to check if the row exists. - QRec = Database_Services('ReadDataRow', 'LOCATION', CassQueue) - LocQ = QRec - Locate WOMatKey in LocQ using @VM setting vPos then - LocQ = Delete(LocQ, 0, vPos, 0) - QRec = LocQ - Database_Services('WriteDataRow', 'LOCATION', CassQueue, QRec, True$, False$, True$) - Success = True$ - end else - Error_Services('Add', 'Error locating Cass ID ':WOMatKey:' in location queue ':LocQ:'.') - end - - NumAttempts += 1 - CassQueue = GaN_Services('GetCassQueue', WOMatKey) - CassInQueue = (CassQueue NE '') - Until ( (CassInQueue EQ False$) or (NumAttempts GT 5) ) - Repeat - - LogData = '' - LogData<1> = LoggingDTM - LogData<2> = @USER4 - LogData<3> = WOMatKey - LogData<4> = CassQueue - LogData<5> = CassQueue - If Success EQ True$ then - LogData<6> = 'Successfully removed Cass ID ':WOMatKey: ' from queue ':CassQueue:'. Number of attempts: ':NumAttempts:'.' - Logging_Services('AppendLog', objWIPLog, LogData, @RM, @FM, False$) - end else - If Error_Services('HasError') then - LogData<6> = Error_Services('GetMessage'):' Number of attempts: ':NumAttempts:'.' - end else - LogData<6> = 'Error removing Cass ID ':WOMatKey:' from queue ':CassQueue:'. Number of attempts: ':NumAttempts:'.' - end - Machine = Environment_Services('GetServer') - If Machine NE 'MESSA01EC' then - EmailAddr = 'dstieber@srpcs.com,Francois.Rivard@infineon.com,6613649828@txt.att.net' - EmailMsg = 'Error removing Cass ID ':WOMatKey:' from queue ':CassQueue:'.' - Logging_Services('AppendLog', objWIPLog, LogData, @RM, @FM, False$, EmailAddr, EmailMsg) - end else - Logging_Services('AppendLog', objWIPLog, LogData, @RM, @FM, False$) - end - end - end else - // Cass not in queue that was passed in. Log this information. - LogData = '' - LogData<1> = LoggingDTM - LogData<2> = @USER4 - LogData<3> = WOMatKey - LogData<4> = CassQueue - LogData<5> = CassQueue - LogData<6> = 'Error in ':Service:' service. Cass not in QueueID ':CassQueue:'.' - Machine = Environment_Services('GetServer') - If Machine NE 'MESSA01EC' then - EmailAddr = 'dstieber@srpcs.com,Francois.Rivard@infineon.com,6613649828@txt.att.net' - EmailMsg = 'Error in ':Service:' service. Cass not in QueueID ':CassQueue:'.' - Logging_Services('AppendLog', objWIPLog, LogData, @RM, @FM, False$, EmailAddr, EmailMsg) - end else - Logging_Services('AppendLog', objWIPLog, LogData, @RM, @FM, False$) - end - end - end else - // WOMatKey is null - LogData = '' - LogData<1> = LoggingDTM - LogData<2> = @USER4 - LogData<3> = WOMatKey - LogData<4> = CassQueue - LogData<5> = CassQueue - LogData<6> = 'Error in ':Service:' service. WOMatKey is null.' - Logging_Services('AppendLog', objWIPLog, LogData, @RM, @FM, False$) - end - Response = Success - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// MoveWfrToQueue -// -// Input: -// WOWfrID - [Required] -// QueueID - [Required] -// -// Output: -// Response - True$ (1) if successful, False$ (0) otherwise. -// -//---------------------------------------------------------------------------------------------------------------------- -Service MoveWfrToQueue(WOWfrID, QueueID) - - Success = False$ - - If WOWfrID NE '' and QueueID NE '' then - QType = GaN_Services('GetQueueType', QueueID) - Begin Case - Case QType EQ 'Tool' - If RowExists('TOOL_WFR', QueueID) then - // Tool Queue already exists, so append wafer to the end of the queue - QRec = Database_Services('ReadDataRow', 'TOOL_WFR', QueueID) - ToolQ = QRec - Locate WOWfrID in ToolQ using @VM setting vPos else - ToolQ<1, -1> = WOWfrID - QRec = ToolQ - Database_Services('WriteDataRow', 'TOOL_WFR', QueueID, QRec, True$, False$, True$) - Success = True$ - end - end else - // Tool Queue is empty (i.e. the record does not exists), so create the TOOL_WFR record (i.e. TOOL Queue). - QRec = '' - QRec = WOWfrID - Database_Services('WriteDataRow', 'TOOL_WFR', QueueID, QRec, True$, False$, True$) - Success = True$ - end - Case QType EQ 'Location' - // Location queues exist perpetually, so no need to check if the row exists. - QRec = Database_Services('ReadDataRow', 'LOCATION', QueueID) - LocQ = QRec - Locate WOWfrID in LocQ using @VM setting vPos else - LocQ<0, -1> = WOWfrID - QRec = LocQ - Database_Services('WriteDataRow', 'LOCATION', QueueID, QRec, True$, False$, True$) - Success = True$ - end - Case Otherwise$ - Error_Services('Add', 'Unrecognized QueueID ':QueueID:' of type ':QType:' supplied.') - End Case - end - - Response = Success - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// RemoveWfrFromWIP -// -// Input: -// WfrID - [Required] -// -// Output: -// Response - True$ (1) if successful, False$ (0) otherwise. -// -//---------------------------------------------------------------------------------------------------------------------- -Service RemoveWfrFromWIP(WfrID) - - Success = False$ - WfrQueue = '' - If WfrID NE '' then - WfrQueue = Gan_Services('GetWfrQueue', WfrID) - WfrQueueOrig = WfrQueue - WfrInQueue = (WfrQueue NE '') - If WfrInQueue EQ True$ then - NumAttempts = 0 - Loop - Error_Services('Clear') - QType = GaN_Services('GetQueueType', WfrQueue) - Begin Case - Case QType EQ 'Tool' - If RowExists('TOOL_WFR', WfrQueue) then - QRec = Database_Services('ReadDataRow', 'TOOL_WFR', WfrQueue) - ToolQ = QRec - Locate WfrID in ToolQ using @VM setting vPos then - ToolQ = Delete(ToolQ, 0, vPos, 0) - QRec = ToolQ - Database_Services('WriteDataRow', 'TOOL_WFR', WfrQueue, QRec, True$, False$, True$) - Success = True$ - end else - Error_Services('Add', 'Error locating wafer ID ':WfrID:' in tool queue ':ToolQ:'.') - end - end else - // Tool Queue is empty (i.e. the record does not exists), so return error. - Error_Services('Add', 'Cannot remove WO_WFR: ':WfrID:' from the TOOL_WFR queue ':WfrQueue | - ' because it is empty.') - end - Case QType EQ 'Location' - // Location queues exist perpetually, so no need to check if the row exists. - QRec = Database_Services('ReadDataRow', 'LOCATION', WfrQueue) - LocQ = QRec - Locate WfrID in LocQ using @VM setting vPos then - LocQ = Delete(LocQ, 0, vPos, 0) - QRec = LocQ - Database_Services('WriteDataRow', 'LOCATION', WfrQueue, QRec, True$, False$, True$) - Success = True$ - end else - Error_Services('Add', 'Error locating wafer ID ':WfrID:' in location queue ':LocQ:'.') - end - Case Otherwise$ - Error_Services('Add', 'Unrecognized QueueID ':WfrQueue:' of type ':QType:' supplied.') - End Case - NumAttempts += 1 - WfrQueue = Gan_Services('GetWfrQueue', WfrID) - WfrInQueue = (WfrQueue NE '') - Until ( (WfrInQueue EQ False$) or (NumAttempts GT 5) ) - Repeat - LogData = '' - LogData<1> = LoggingDTM - LogData<2> = @USER4 - LogData<3> = WfrID - LogData<4> = '' - LogData<5> = WfrQueueOrig - If Success EQ True$ then - LogData<6> = 'Successfully removed wafer ID ':WfrID: ' from queue ':WfrQueueOrig:'. Number of attempts: ':NumAttempts:'.' - Logging_Services('AppendLog', objWIPLog, LogData, @RM, @FM, False$) - end else - If Error_Services('HasError') then - LogData<6> = Error_Services('GetMessage'):' Number of attempts: ':NumAttempts:'.' - end else - LogData<6> = 'Error removing wafer ID ':WfrID:' from queue ':WfrQueueOrig:'. Number of attempts: ':NumAttempts:'.' - end - Logging_Services('AppendLog', objWIPLog, LogData, @RM, @FM, False$) - end - end else - LogData = '' - LogData<1> = LoggingDTM - LogData<2> = @USER4 - LogData<3> = WfrID - LogData<4> = '' - LogData<5> = '' - LogData<6> = 'Error in ':Service:' service. Wafer ID ':WfrID:' not found in any queue.' - Logging_Services('AppendLog', objWIPLog, LogData, @RM, @FM, False$) - end - end else - // WfrID is null. This is likely from routines trying to remove wafers after the RDS has been - // closed the wafers are off of the WIP. - LogData = '' - LogData<1> = LoggingDTM - LogData<2> = @USER4 - LogData<3> = WfrID - LogData<4> = '' - LogData<5> = '' - LogData<6> = 'Error in ':Service:' service. WfrID is null.' - Logging_Services('AppendLog', objWIPLog, LogData, @RM, @FM, False$) - end - Response = Success - -end service - - -Service RemoveEtchFromWIP(EtchID) - - Success = False$ - EtchQueue = '' - If EtchID NE '' then - DisplayEtchID = Xlate('GAN_ETCH', EtchID, 'DISPLAY_ETCH_ID', 'X') - EtchQueue = Gan_Services('GetEtchQueue', DisplayEtchID) - EtchQueueOrig = EtchQueue - EtchInQueue = (EtchQueue NE '') - If EtchInQueue EQ True$ then - NumAttempts = 0 - Loop - QType = GaN_Services('GetQueueType', EtchQueue) - Begin Case - Case QType EQ 'Tool' - If RowExists('TOOL_ETCH', EtchQueue) then - QRec = Database_Services('ReadDataRow', 'TOOL_ETCH', EtchQueue) - ToolQ = QRec - Locate DisplayEtchID in ToolQ using @VM setting vPos then - ToolQ = Delete(ToolQ, 0, vPos, 0) - QRec = ToolQ - Database_Services('WriteDataRow', 'TOOL_ETCH', EtchQueue, QRec, True$, False$, True$) - Success = True$ - end else - Error_Services('Add', 'Error locating etch ID ':DisplayEtchID:' in tool queue ':ToolQ:'.') - end - end else - // Tool Queue is empty (i.e. the record does not exists), so return error. - Error_Services('Add', 'Cannot remove etch ID ':DisplayEtchID:' from the TOOL_WFR queue ':EtchQueue | - ' because it is empty.') - end - Case QType EQ 'Location' - // Location queues exist perpetually, so no need to check if the row exists. - QRec = Database_Services('ReadDataRow', 'LOCATION', EtchQueue) - LocQ = QRec - Locate DisplayEtchID in LocQ using @VM setting vPos then - LocQ = Delete(LocQ, 0, vPos, 0) - QRec = LocQ - Database_Services('WriteDataRow', 'LOCATION', EtchQueue, QRec, True$, False$, True$) - Success = True$ - end else - Error_Services('Add', 'Error locating etch ID ':DisplayEtchID:' in location queue ':LocQ:'.') - end - Case Otherwise$ - Error_Services('Add', 'Unrecognized QueueID ':EtchQueue:' of type ':QType:' supplied.') - End Case - NumAttempts += 1 - EtchQueue = Gan_Services('GetEtchQueue', DisplayEtchID) - EtchInQueue = (EtchQueue NE '') - Until ( (EtchInQueue EQ False$) or (NumAttempts GT 5) ) - Repeat - - LogData = '' - LogData<1> = LoggingDTM - LogData<2> = @USER4 - LogData<3> = DisplayEtchID - LogData<4> = '' - LogData<5> = EtchQueueOrig - If Success EQ True$ then - LogData<6> = 'Successfully removed etch ID ':DisplayEtchID: ' from queue ':EtchQueueOrig:'. Number of attempts: ':NumAttempts:'.' - Logging_Services('AppendLog', objWIPLog, LogData, @RM, @FM, False$) - end else - If Error_Services('HasError') then - LogData<6> = Error_Services('GetMessage'):' Number of attempts: ':NumAttempts:'.' - end else - LogData<6> = 'Error removing etch ID ':DisplayEtchID:' from queue ':EtchQueueOrig:'. Number of attempts: ':NumAttempts:'.' - end - Logging_Services('AppendLog', objWIPLog, LogData, @RM, @FM, False$) - end - end else - LogData = '' - LogData<1> = LoggingDTM - LogData<2> = @USER4 - LogData<3> = DisplayEtchID - LogData<4> = '' - LogData<5> = '' - LogData<6> = 'Error in ':Service:' service. Etch ID ':DisplayEtchID:' not found in any queue.' - Logging_Services('AppendLog', objWIPLog, LogData, @RM, @FM, False$) - end - end else - LogData = '' - LogData<1> = LoggingDTM - LogData<2> = @USER4 - LogData<3> = DisplayEtchID - LogData<4> = '' - LogData<5> = '' - LogData<6> = 'Error in ':Service:' service. DisplayEtchID is null.' - Logging_Services('AppendLog', objWIPLog, LogData, @RM, @FM, False$) - end - Response = Success - - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetQueueType -// -// Input: -// QueueID - [Required] -// -// Output: -// Response - Queue type - 'Location' or 'Tool' -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetQueueType(QueueID) - - QueueType = '' - NumFields = Count(QueueID, '*') - If NumFields EQ 0 then - QueueType = 'Tool' - end else - QueueType = 'Location' - end - Response = QueueType - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetLocQueueID -// -// Input: -// StageID - [Required] -// -// Output: -// Response - LOCATION QueueID -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetLocQueueID(StageID) - - QueueID = '' - Done = False$ - GaNStages = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_STAGES') - GaNStages = SRP_Array('Rotate', GaNStages, @FM, @VM) - LocQs = GaNStages<6> - StageIDs = GaNStages<1> - Locate StageID in StageIDs using @VM setting vPos then - QueueID = LocQs<0, vPos> - end - Response = QueueID - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetPreEpiWfrs -// -// Input: -// WONo - [Required] -// NumWfrs - [Required] -// -// Output: -// Response - NumWfrs of InWfrIDs if enough inbound material available, else null and error set. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetPreEpiWfrs(WONo, NumWfrs) - - Response = '' - ConsumedWfrCnt = 0 - If (WONo NE '') and (NumWfrs GT 0) then - CassNos = Xlate('WO_LOG', WONo, 'WO_MAT_CASS_NO', 'X') - CassCnt = DCount(CassNos, @VM) - ConsumedWfrCnt = 0 - CassIndex = 1 - Loop - HaveCassettes = (CassIndex LE CassCnt) - While HaveCassettes - CassNo = CassNos<1,CassIndex> - WOMatKey = WONo:'*':CassNo - WOMatRec = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey) - If (WOMatRec EQ '') or (WOMatRec EQ False$) then - WOWfrIDs = Xlate('WO_MAT_WFR', WONo:'*':CassNo, WO_MAT_WFR_IN_WFR_ID$, 'X') - SlotCnt = WOMatRec - SlotIndex = 1 - Loop - Finished = (SlotIndex GT SlotCnt) or (ConsumedWfrCnt GE NumWfrs) - While Not(Finished) - If WOWfrIDs<1,SlotIndex> NE '' then - SlotID = WONo:'*':CassNo:'*':SlotIndex - Response = Insert(Response, 0, -1, 0, SlotID) - ConsumedWfrCnt += 1 - end - SlotIndex += 1 - Repeat - end - CassIndex += 1 - Repeat - end - If ConsumedWfrCnt NE NumWfrs then - Response = '' - ErrorMessage = 'Not enough inbound material available.' - Error_Services('Add', ErrorMessage) - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// UnloadSusceptor -// -// Input: -// RDSNo - [Required] -// -// Output: -// Response - True$ (1) if successful, False$ (0) otherwise -// -//---------------------------------------------------------------------------------------------------------------------- -Service UnloadSusceptor(RDSNo) - - Response = False$ - If RDSNo NE '' then - CurrDTM = DateTime() - // Update REACT_RUN record - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - If ReactRunRec NE '' then - GaNRunID = ReactRunRec - WONo = ReactRunRec - WOStep = ReactRunRec - Reactor = ReactRunRec - InWfrIDs = ReactRunRec - CarrSlotNos = ReactRunRec - ToolID = 'R':Reactor - NextLocQ = 'GCH*Q_RATE' - CarrSlotIDs = '' - For each CarrSlotNo in CarrSlotNos using @VM setting vPos - If CarrSlotNo NE '' then - CarrSlotIDs<0, vPos> = RDSNo:'.':CarrSlotNo - end - Next CarrSlotNo - ReactRunRec = CarrSlotIDs - ReactRunRec = InWfrIDs - Database_Services('WriteDataRow', 'REACT_RUN', RDSNo, ReactRunRec, True$, False$, True$) - If Error_Services('NoError') then - // Update WO_WFR record(s) and move WO_WFR(s) from TOOL_WFR queue to G_RATE queue - For each InWfrID in InWfrIDs using @VM setting vPos - If InWfrID NE '' then - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', InWfrID) - If WOWfrRec NE '' then - LocDTMs = WOWfrRec - NextIndex = DCount(LocDTMs, @VM) + 1 - WOWfrRec = CurrDTM - WOWfrRec = @USER4 - WOWfrRec = 'UNLOAD' - WOWfrRec = CarrSlotIDs<0, vPos> - WOWfrRec = NextLocQ - Database_Services('WriteDataRow', 'WO_WFR', InWfrID, WOWfrRec, True$, False$, True$) - GaN_Services('RemoveWfrFromWIP', WfrID) - GaN_Services('MoveWfrToQueue', InWfrID, NextLocQ) - end else - Error_Services('Add', 'Failed to read WO_WFR record ':InWfrID:' in ':Service:' service.') - end - end - Next InWfrID - // Update RUN_STAGE record (i.e. sign UNLOAD IA and stage complete field) - RunStageKey = RDSNo:'*GROWTH' - RunStageRec = Database_Services('ReadDataRow', 'RUN_STAGE', RunStageKey) - If RunStageRec NE '' then - InvActions = RunStageRec - IACompBy = RunStageRec - IACompDTM = RunStageRec - Locate 'UNLOAD' in InvActions using @VM setting vPos then - IACompBy<0, vPos> = @User4 - IACompDTM<0, vPos> = CurrDTM - end - RunStageRec = IACompBy - RunStageRec = IACompDTM - RunStageRec = @User4 - RunStageRec = CurrDTM - RunStageRec = 'COMP' - Database_Services('WriteDataRow', 'RUN_STAGE', RunStageKey, RunStageRec, True$, False$, True$) - end else - Error_Services('Add', 'Failed to read RUN_STAGE record ':RunStageKey:' in ':Service:' service.') - end - end else - Error_Services('Add', 'Failed to write REACT_RUN record ':RDSNo:' in ':Service:' service.') - end - end else - Error_Services('Add', 'Failed to read REACT_RUN record ':RDSNo:' in ':Service:' service.') - end - If Error_Services('NoError') then Response = True$ - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetNextStage -// -// Input: -// WOWfrID - [Required] -// -// Output: -// Response - Next WFR_STAGE that is prescribed and has not yet been completed. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetNextStage(WOWfrID) - - Convert '.' to '*' in WOWfrID - CurrStage = GaN_Services('GetCurrStage', WOWfrID) - ReactRunKey = Xlate('WO_WFR', WOWfrID, 'RDS_NO', 'X') - WfrStage = Xlate('REACT_RUN', ReactRunKey, 'WFR_STAGE', 'X') - FormatWfrID = WOWfrID - Done = False$ - Convert '*' to '.' in FormatWfrID - Begin Case - Case CurrStage EQ 'G_RATE' - // Lookup first stage in WFR_STAGE column within associated REACT_RUN record - Response = WfrStage<0, 1> - Case Otherwise$ - For each Stage in WfrStage using @VM setting vPos - RunStageWfrKey = ReactRunKey:'*':Stage:'*':FormatWfrID - StageStatus = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'STATUS', 'X') - If StageStatus _EQC 'INIT' then - Response = Stage - Done = True$ - end - Until Done EQ True$ - Next Stage - End Case - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetNextRxStage -// -// Input: -// RDSNo - [Required] -// CurrStage - [Required] -// -// Output: -// Response - Next WFR_STAGE that is prescribed in the REACT_RUN record -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetNextRxStage(RDSNo, CurrStage) - - Response = '' - If ( (RDSNo NE '') and (CurrStage NE '') ) then - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - StageRoute = ReactRunRec - RxStages = ReactRunRec - NextStage = '' - If StageRoute NE '' then - Done = False$ - Locate CurrStage in StageRoute using @VM setting vPos then - NumStages = DCount(StageRoute, @VM) - For StageIndex = (vPos + 1) to NumStages - NextStage = StageRoute<0, StageIndex> - Locate NextStage in RxStages using @VM setting rPos then - Done = True$ - end - Until Done EQ True$ - Next StageIndex - Response = NextStage - end - end else - Locate CurrStage in RxStages using @VM setting vPos then - NextStage = RxStages<0, vPos + 1> - Response = NextStage - end - end - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetCurrStage -// -// Input: -// WOWfrID - [Required] -// -// Output: -// Response - Current queue a wafer is in. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetCurrStage(WOWfrID) - - Response = '' - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WOWfrID) - InvLocs = WOWfrRec - ToolLocs = WOWfrRec - NumInvLocs = DCount(InvLocs, @VM) - NumToolLocs = DCount(ToolLocs, @VM) - CurrStep = Max(NumInvLocs, NumToolLocs) - LastToolLoc = ToolLocs<0, CurrStep> - LastInvLoc = InvLocs<0, CurrStep> - Begin Case - Case LastToolLoc NE '' and LastInvLoc EQ '' - ToolID = LastToolLoc - Response = Gan_Services('GetStageFromToolID', ToolID) - Case LastToolLoc EQ '' and LastInvLoc NE '' - LocQ = LastInvLoc - Response = GaN_Services('GetStageID', '', LocQ) - Case Otherwise$ - // Error - End Case - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetStageFromToolID -// -// Input: -// ToolID - [Required] -// -// Output: -// Response - Stage ID associated with the given Tool ID. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetStageFromToolID(ToolID) - - Stage = '' - If ToolID NE '' then - Query = 'SELECT TOOL_CLASS CONTAINING "G_"' - GoSub ClearCursors - Rlist(Query, Target_ActiveList$, '', '', '') - EOF = False$ - Done = False$ - If @RecCount then - Loop - While EOF EQ False$ - ReadNext ToolClassID else EOF = True$ - Tools = Xlate('TOOL_CLASS', ToolClassID, 'TOOL', 'X') - If Indexc(Tools, ToolID, 1) GT 0 then - LocWH = Xlate('TOOL_CLASS', ToolClassID, 'QIN_WH', 'X') - Loc = Xlate('TOOL_CLASS', ToolClassID, 'QIN_LOC', 'X') - LocQ = LocWH:'*':Loc - Stage = Gan_Services('GetStageID', '', LocQ) - Done = True$ - end - Until Done EQ True$ - Repeat - end - GoSub ClearCursors - end - Response = Stage - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetNextEtchRun -// -// Input: -// RDSNo - [Required] -// -// Output: -// Response - True$ (1) if successful, False$ (0) otherwise -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetNextEtchRun(Reactor) - - Response = '' - If Reactor NE '' then - EtchIDs = '' - EtchQList = '' - RowIndex = 1 - GoSub ClearCursors - Query = 'SELECT GAN_ETCH WITH AVAILABLE EQ ':True$:' AND WITH END_DTM NE "" AND WITH REACTOR EQ ' | - :Reactor:' BY REACTOR BY START_DTM' - Rlist(Query, Target_ActiveList$, '', '', '') - EOF = False$ - If @RecCount then - ReadNext GaNEtchID then Response = GaNEtchID - end - end - GoSub ClearCursors - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// ConsumeIntEtchID -// -// Input: -// IntEtchID - [Required] -// -// Output: -// Response - True$ (1) if successful, False$ (0) otherwise -// -//---------------------------------------------------------------------------------------------------------------------- -Service ConsumeIntEtchID(IntEtchID) - - Response = False$ - If IntEtchID NE '' then - IntEtchRec = Database_Services('ReadDataRow', 'GAN_ETCH', IntEtchID) - If IntEtchRec NE '' then - IntEtchRec = False$ - Database_Services('WriteDataRow', 'GAN_ETCH', IntEtchID, IntEtchRec, True$, False$, True$) - Response = True$ - end - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// CreateRunStageWfr -// -// Input: -// RDSNo - [Required] -// -// Output: -// Response - True$ (1) if successful, False$ (0) otherwise -// -//---------------------------------------------------------------------------------------------------------------------- -Service CreateRunStageWfr(RDSNo, Stage, WfrID) - - Response = False$ - PSN = Xlate('RDS', RDSNo, 'PROD_SPEC_ID', 'X') - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - WfrStages = ReactRunRec - Locate Stage in WfrStages using @VM setting sPos else - // Stage has not yet been added to the REACT_RUN WFR_STAGE field - UnRxStage = Gan_Services('GetUnRxStatus', RDSNo, Stage) - If UnRxStage EQ True$ then - UnRxStages = ReactRunRec - GaNStageInfo = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_STAGES') - GaNStageInfo = SRP_Array('Rotate', GaNStageInfo, @FM, @VM) - AllStages = GaNStageInfo<1> - NewStageIndex = Gan_Services('GetStageIndex', Stage) - Found = False$ - For PrevStageIndex = (NewStageIndex - 1) to 1 Step -1 - PrevStage = AllStages<0, PrevStageIndex> - Locate PrevStage in WfrStages using @VM setting vPos then - WfrStages = Insert(WfrStages, 0, vPos + 1, 0, Stage) - UnRxStages = Insert(UnRxStages, 0, vPos + 1, 0, True$) - Found = True$ - end - Until Found EQ True$ - Next PrevStageIndex - If Found EQ False$ then - WfrStages = Insert(WfrStages, 0, 1, 0, Stage) - UnRxStages = Insert(UnRxStages, 0, 1, 0, True$) - end - ReactRunRec = WfrStages - ReactRunRec = UnRxStages - Database_Services('WriteDataRow', 'REACT_RUN', RDSNo, ReactRunRec, True$, False$, True$) - end - end - RunStageWfrRec = '' - RunStageWfrRec = GaN_Services('GetToolClassIDs', Stage) - RunStageWfrRec = GaN_Services('GetInvActions', Stage) - RunStageWfrRec = 'INIT' - - WfrKID = WfrID - // WfrID may be passed in using an asterisk as the Delimiter instead of a period - // Convert asterisks to periods just to be safe - Convert '*' to '.' in WfrKID - RunStageWfrKey = RDSNo:'*':Stage:'*':WfrKID - If Not(RowExists('RUN_STAGE_WFR', RunStageWfrKey)) then - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$) - end - If Error_Services('NoError') then Response = True$ - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// CreateAllRunStageWfr -// -// Input: -// RDSNo - [Required] -// StopStageID - [Optional] -// -// Output: -// Response - True$ (1) if successful, False$ (0) otherwise -// -//---------------------------------------------------------------------------------------------------------------------- -Service CreateAllRunStageWfr(RDSNo, StopStageID, InWfrIDs) - - If (RDSNo NE '') then - WfrStages = Xlate('REACT_RUN', RDSNo, 'WFR_STAGE', 'X') - UnRxStages = Xlate('REACT_RUN', RDSNo, 'UNPRESCRIBED_WFR_STAGE', 'X') - If StopStageID EQ '' then - StopStageID = WfrStages[-1, 'B':@VM] - end - // If wafer IDs are not passed in, then the code assumes all prescribed stages are to be - // created if they have not yet already been created. - If InWfrIDs EQ '' then InWfrIDs = Xlate('REACT_RUN', RDSNo, 'IN_WFR_ID', 'X') - Response = False$ - NumStages = DCount(WfrStages, @VM) - NumWfrs = DCount(InWfrIDs, @VM) - WfrIndex = 1 - Loop - WfrID = InWfrIDs<0, WfrIndex> - If WfrID NE '' then - StageIndex = 1 - FormattedWfrID = WfrID - Convert '*' to '.' in FormattedWfrID - Loop - Stage = WfrStages<0, StageIndex> - UnRxStage = UnRxStages<0, StageIndex> - // Create RUN_STAGE_WFR record - RunStageWfrKey = RDSNo:'*':Stage:'*':FormattedWfrID - If Not(RowExists('RUN_STAGE_WFR', RunStageWfrKey)) and (UnRxStage EQ '') then - GaN_Services('CreateRunStageWfr', RDSNo, Stage, WfrID) - end - Until Stage EQ StopStageID - StageIndex += 1 - Repeat - end - WfrIndex += 1 - Until WfrIndex GT NumWfrs - Repeat - end - If Error_Services('NoError') then Response = True$ - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// DispositionWfr -// -// Input: -// RDSNo - [Required] -// WfrID - [Required] -// -// Output: -// Response - True$ (1) if successful, False$ (0) otherwise -// -//---------------------------------------------------------------------------------------------------------------------- -Service DispositionWfr(RDSNo, WfrID, Auto) - - Response = False$ - If (RDSNo NE '') and (WfrID NE '') then - ReadyToSplit = Gan_Services('ReadyToSplit', WfrID) - If ReadyToSplit EQ True$ then - If Auto NE '' then - User = 'AUTO' - end else - User = @User4 - end - CurrDTM = Datetime() - PSNo = Xlate('REACT_RUN', RDSNo, 'PS_NO', 'X') - ANKO = Xlate('PROD_SPEC', PSNo, 'ANKO', 'X') - If ANKO EQ True$ then - DispStages = 'DISP':@VM:'RETAIN' - end else - DispStages = 'DISP':@VM:'G_PACK':@VM:'RETAIN' - end - For each Stage in DispStages using @VM setting vPos - FormattedWfrID = WfrID - Convert '*' to '.' in FormattedWfrID - RunStageWfrKey = RDSNo:'*':Stage:'*':FormattedWfrID - If Not(RowExists('RUN_STAGE_WFR', RunStageWfrKey)) then - GaN_Services('CreateRunStageWfr', RDSNo, Stage, WfrID) - end - Next Stage - // Update RUN_STAGE_WFR record (Set Status to 'COMP', Fill in CompBy and CompDTM) - FormatWfrID = WfrID - Convert '*' to '.' in FormatWfrID - RunStageWfrKey = RDSNo:'*SPLIT*':FormatWfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - RunStageWfrRec = User - RunStageWfrRec = CurrDTM - RunStageWfrRec = 'DISP' - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$) - // Update the WO_WFR record with the LOC_BY, LOC_DTM, INV_LOC (the next prescribed location queue), - // and LOC_EVENT (DISPOSITION) - WOWfrKey = WfrID - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WOWfrKey) - LocDTMs = WOWfrRec - NextStep = DCount(LocDTMs, @VM) + 1 - WOWfrRec = CurrDTM - WOWfrRec = User - WOWfrRec = 'DISPOSITION' - WOWfrRec = '' - CurrStage = Gan_Services('GetCurrStage', WfrID) - CurrLocQ = Gan_Services('GetLocQueueID', CurrStage) - NextStage = Gan_Services('GetNextStage', WfrID) - NextLocQ = Gan_Services('GetLocQueueID', NextStage) - WoWfrRec = NextLocQ - // Move wafer to the next prescribed location queue - Gan_Services('RemoveWfrFromWIP', WfrID) - Gan_Services('MoveWfrToQueue', WfrID, NextLocQ) - Database_Services('WriteDataRow', 'WO_WFR', WOWfrKey, WOWfrRec, True$, False$, True$) - // Update the Disposition DTM for all wafers that have been through or are at disposition - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - InWfrIDs = ReactRunRec - For each WOWfrID in InWfrIDs using @VM setting vPos - ThisWOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WOWfrID) - LocDTMs = ThisWOWfrRec - LocQs = ThisWOWfrRec - Locate 'GGR*Q_DISP' in LocQs using @VM setting vPos then - // Wafer has been dispositioned at some point, so update the disposition DTM - LocDTMs<0, vPos> = CurrDTM - ThisWOWfrRec = LocDTMs - Database_Services('WriteDataRow', 'WO_WFR', WOWfrID, ThisWOWfrRec, True$, False$, True$) - end - Next WOWfrID - end - If Error_Services('NoError') then Response = True$ - end else - ErrorMsg = 'This wafer is not ready to split. One or more previous stages have not been completed.' - Error_Services('Add', ErrorMsg) - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// StartWaferStage -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service StartWaferStage(RDSNo, WfrID, StageID, ToolID) - - // 1. Find which queue the wafers are currently in. - // 2. Move wafers to the new queue. - // 3. Update all RUN_STAGE_WFR records. (i.e. update the status from INIT to START) - // 4. Update WO_WFR records for wafer trace purposes. (i.e. location DTM, event, queue, etc.) - // 5. Refresh the UI to display the new wafer statuses. - Response = False$ - If (RDSNo NE '') and (WfrID NE '') and (StageID NE '') and (ToolID NE '') then - CurrDTM = Datetime() - LocQ = Gan_Services('GetWfrQueue', WfrID) - Gan_Services('RemoveWfrFromWIP', WfrID) - Gan_Services('MoveWfrToQueue', WfrID, ToolID) - FormattedWfrID = WfrID - Convert '*' to '.' in FormattedWfrID - RunStageWfrKey = RDSNo:'*':StageID:'*':FormattedWfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - InvAction = 'START' - RunStageWfrRec = 'START' - // Sign InvAction, Fill InvAction DTM - SpecInvActions = RunStageWfrRec - SIACompBy = RunStageWfrRec - SIACompDTM = RunStageWfrRec - Locate InvAction in SpecInvActions using @VM setting vPos then - SIACompBy<0, vPos> = @USER4 - SIACompDTM<0, vPos> = CurrDTM - end - RunStageWfrRec = SIACompBy - RunStageWfrRec = SIACompDTM - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$) - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WfrID) - LocDTM = WOWfrRec - NextPos = DCount(LocDTM, @VM) + 1 - WOWfrRec = CurrDTM - WOWfrRec = @USER4 - WOWfrRec = 'START' - WOWfrRec = ToolID - WOWfrRec = '' - Database_Services('WriteDataRow', 'WO_WFR', WfrID, WOWfrRec, True$, False$, True$) - If Error_Services('NoError') then Response = True$ - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// StopWaferStage -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service StopWaferStage(RDSNo, WfrID, StageID) - - // 1. Find which queue the wafers are currently in. - // 2. Move wafers to the new queue. - // 3. Update all RUN_STAGE_WFR record. (i.e. update the status from INIT to STOP) - // 4. Update WO_WFR records for wafer trace purposes. (i.e. location DTM, event, queue, etc.) - Response = False$ - If (RDSNo NE '') and (WfrID NE '') and (StageID NE '') then - CurrDTM = Datetime() - FormattedWfrID = WfrID - Convert '*' to '.' in FormattedWfrID - RunStageWfrKey = RDSNo:'*':StageID:'*':FormattedWfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - StageStatus = RunStageWfrRec - If StageStatus _EQC 'START' then - ToolQ = Gan_Services('GetWfrQueue', WfrID) - Gan_Services('RemoveWfrFromWIP', WfrID) - NextStageID = Gan_Services('GetNextStage', WfrID) - NextLocQ = Gan_Services('GetLocQueueID', NextStageID) - Gan_Services('MoveWfrToQueue', WfrID, NextLocQ) - InvAction = 'STOP' - // Sign InvAction, Fill InvAction DTM, - SpecInvActions = RunStageWfrRec - SIACompBy = RunStageWfrRec - SIACompDTM = RunStageWfrRec - CompBy = RunStageWfrRec - CompDTM = RunStageWfrRec - Locate InvAction in SpecInvActions using @VM setting vPos then - SIACompBy<0, vPos> = @USER4 - SIACompDTM<0, vPos> = CurrDTM - end - RunStageWfrRec = SIACompBy - RunStageWfrRec = SIACompDTM - // Set the status - RunStageWfrRec = 'STOP' - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$) - - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WfrID) - LocDTM = WOWfrRec - NextPos = DCount(LocDTM, @VM) + 1 - WOWfrRec = CurrDTM - WOWfrRec = @User4 - WOWfrRec = 'STOP' - WOWfrRec = '' - WOWfrRec = NextLocQ - Database_Services('WriteDataRow', 'WO_WFR', WfrID, WOWfrRec, True$, False$, True$) - If Error_Services('NoError') then Response = True$ - end - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// CompleteWaferStage -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service CompleteWaferStage(RDSNo, WfrID, StageID) - - Response = False$ - If (RDSNo NE '') and (WfrID NE '') and (StageID NE '') then - CurrDTM = Datetime() - FormattedWfrID = WfrID - Convert '*' to '.' in FormattedWfrID - RunStageWfrKey = RDSNo:'*':StageID:'*':FormattedWfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - StageStatus = RunStageWfrRec - If StageStatus _EQC 'STOP' then - // Mark RUN_STAGE_WFR as complete - RunStageWfrRec = @User4 - RunStageWfrRec = CurrDTM - RunStageWfrRec = 'COMP' - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$) - If Error_Services('NoError') then - Response = True$ - DestStage = GaN_Services('IsDestStage', StageID) - If DestStage EQ True$ then - // Update EA spreadsheet with all fully characterized wafers (i.e. destroyed wafers) - Engineering_Services('PostEARequest', RDSNo, 'CHAR') - end - end - end - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// SkipWaferStage -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service SkipWaferStage(RDSNo, WfrID, StageID) - - Response = False$ - If (RDSNo NE '') and (WfrID NE '') and (StageID NE '') then - CurrDTM = Datetime() - NextLocQ = '' - CurrStageID = Gan_Services('GetCurrStage', WfrID) - FormattedWfrID = WfrID - Convert '*' to '.' in FormattedWfrID - RunStageWfrKey = RDSNo:'*':StageID:'*':FormattedWfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - // Mark RUN_STAGE_WFR as complete - RunStageWfrRec = @USER4 - RunStageWfrRec = CurrDTM - // Set the wafer status - RunStageWfrRec = 'SKIP' - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$) - // Are we in the same queue that we are trying to skip? If so, then need to move the wafers to the - // next prescribed stage, otherwise, we do not. - If CurrStageID _EQC StageID then - LocQ = Gan_Services('GetWfrQueue', WfrID) - Gan_Services('RemoveWfrFromWIP', WfrID) - NextStageID = Gan_Services('GetNextStage', WfrID) - NextLocQ = Gan_Services('GetLocQueueID', NextStageID) - Gan_Services('MoveWfrToQueue', WfrID, NextLocQ) - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WfrID) - LocDTM = WOWfrRec - NextPos = DCount(LocDTM, @VM) + 1 - WOWfrRec = CurrDTM - WOWfrRec = @USER4 - WOWfrRec = 'SKIP' - WOWfrRec = '' - WOWfrRec = NextLocQ - Database_Services('WriteDataRow', 'WO_WFR', WfrID, WOWfrRec, True$, False$, True$) - end - If Error_Services('NoError') then Response = True$ - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// UnskipWaferStage -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service UnskipWaferStage(RDSNo, WfrID, StageID) - - Response = False$ - If (RDSNo NE '') and (WfrID NE '') and (StageID NE '') then - CurrDTM = Datetime() - FormattedWfrID = WfrID - Convert '*' to '.' in FormattedWfrID - RunStageWfrKey = RDSNo:'*':StageID:'*':FormattedWfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - // Mark RUN_STAGE_WFR as not complete - RunStageWfrRec = '' - RunStageWfrRec = '' - // Set the wafer status - RunStageWfrRec = 'INIT' - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$) - // Move wafer to the next scheduled queue - Gan_Services('RemoveWfrFromWIP', WfrID) - NextStageID = Gan_Services('GetNextStage', WfrID) - NextLocQ = Gan_Services('GetLocQueueID', NextStageID) - Gan_Services('MoveWfrToQueue', WfrID, NextLocQ) - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WfrID) - LocDTM = WOWfrRec - NextPos = DCount(LocDTM, @VM) + 1 - WOWfrRec = CurrDTM - WOWfrRec = @USER4 - WOWfrRec = 'UNSKIP' - WOWfrRec = '' - WOWfrRec = NextLocQ - Database_Services('WriteDataRow', 'WO_WFR', WfrID, WOWfrRec, True$, False$, True$) - If Error_Services('NoError') then Response = True$ - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// AddWaferStage -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service AddWaferStage(RDSNo, WfrID, StageID, ToolID) - - Response = False$ - If (RDSNo NE '') and (WfrID NE '') and (StageID NE '') and (ToolID NE '') and (ToolID _NEC 'Select') then - FormattedWfrID = WfrID - Swap '*' with '.' in FormattedWfrID - RunStageWfrKey = RDSNo:'*':StageID:'*':FormattedWfrID - Gan_Services('CreateRunStageWfr', RDSNo, StageID, WfrID) - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - RunStageWfrRec = ToolID - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$) - If Error_Services('NoError') then Response = True$ - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// RemoveWaferStage -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service RemoveWaferStage(RDSNo, WfrID, StageID) - - Response = False$ - If (RDSNo NE '') and (WfrID NE '') and (StageID NE '') then - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - WfrStages = ReactRunRec - UnRxStages = ReactRunRec - // Remove the stage from the REACT_RUN stage list - Locate StageID in WfrStages using @VM setting vPos then - WfrStages = Delete(WfrStages, 0, vPos, 0) - UnRxStages = Delete(UnRxStages, 0, vPos, 0) - ReactRunRec = WfrStages - ReactRunRec = UnRxStages - Database_Services('WriteDataRow', 'REACT_RUN', RDSNo, ReactRunRec, True$, False$, True$) - end - FormattedWfrID = WfrID - Swap '*' with '.' in FormattedWfrID - RunStageWfrKey = RDSNo:'*':StageID:'*':FormattedWfrID - // Are we in the same queue that we are trying to remove? If so, then need to move the wafers to the - // next prescribed stage, otherwise, we do not. - CurrStageID = Gan_Services('GetCurrStage', WfrID) - NextStageID = Gan_Services('GetNextStage', WfrID) - NextLocQ = Gan_Services('GetLocQueueID', NextStageID) - If CurrStageID _EQC StageID then - LocQ = Gan_Services('GetWfrQueue', WfrID) - Gan_Services('RemoveWfrFromWIP', WfrID) - Gan_Services('MoveWfrToQueue', WfrID, NextLocQ) - end - // Update the WO_WFR record with the LOC_BY, LOC_DTM, INV_LOC (the next prescribed location queue), - // and LOC_EVENT (DISPOSITION) - WOWfrKey = WfrID - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WOWfrKey) - LocDTMs = WOWfrRec - NextStep = DCount(LocDTMs, @VM) + 1 - WOWfrRec = Datetime() - WOWfrRec = @USER4 - WOWfrRec = 'REMOVE' - WOWfrRec = '' - WOWfrRec = NextLocQ - Database_Services('WriteDataRow', 'WO_WFR', WOWfrKey, WOWfrRec, True$, False$, True$) - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - // Delete the RUN_STAGE_WFR record - If RowExists('RUN_STAGE_WFR', RunStageWfrKey) then - Database_Services('DeleteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, True$, False$) - end - If Error_Services('NoError') then Response = True$ - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// CharacterizeWafer -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service CharacterizeWafer(RDSNo, WfrID, Auto) - - Response = False$ - If (RDSNo NE '') and (WfrID NE '') then - If Auto NE '' then - User = 'AUTO' - end else - User = @User4 - end - ReadyToSplit = Gan_Services('ReadyToSplit', WfrID) - If ReadyToSplit EQ True$ then - CurrDTM = Datetime() - // Create remaining prescribed RUN_STAGE_WFR records for the selected wafer. - Gan_Services('CreateAllRunStageWfr', RDSNo, '', WfrID) - // Update RUN_STAGE_WFR record (Set Status to 'COMP', Fill in CompBy and CompDTM) - FormatWfrID = WfrID - Convert '*' to '.' in FormatWfrID - RunStageWfrKey = RDSNo:'*SPLIT*':FormatWfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - RunStageWfrRec = User - RunStageWfrRec = CurrDTM - RunStageWfrRec = 'CHAR' - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$) - // Update the WO_WFR record with the LOC_BY, LOC_DTM, INV_LOC (the next prescribed location queue), - // and LOC_EVENT (CHARACTERIZE) - WOWfrKey = WfrID - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WOWfrKey) - LocDTMs = WOWfrRec - NextStep = DCount(LocDTMs, @VM) + 1 - WOWfrRec = CurrDTM - WOWfrRec = User - WOWfrRec = 'CHARACTERIZE' - WOWfrRec = '' - CurrStage = Gan_Services('GetCurrStage', WfrID) - CurrLocQ = Gan_Services('GetLocQueueID', CurrStage) - NextStage = Gan_Services('GetNextStage', WfrID) - NextLocQ = Gan_Services('GetLocQueueID', NextStage) - WoWfrRec = NextLocQ - // Move wafer to the next prescribed location queue - Gan_Services('RemoveWfrFromWIP', WfrID) - Gan_Services('MoveWfrToQueue', WfrID, NextLocQ) - Database_Services('WriteDataRow', 'WO_WFR', WOWfrKey, WOWfrRec, True$, False$, True$) - If Error_Services('NoError') then - Response = True$ - // Mark the wafer as characterized in the REACT_RUN record. - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - InWfrIDs = ReactRunRec - Locate WfrID in InWfrIDs using @VM setting wPos then - ReactRunRec = True$ - // Add this wafer ID to the list of characterized wafers so that we can - // determine primary and secondary characterization. - Locate WfrID in ReactRunRec using @VM setting dummy else - ReactRunRec = WfrID - Database_Services('WriteDataRow', 'REACT_RUN', RDSNo, ReactRunRec, True$, False$, True$) - end - end - // Record the run number in the work order so that we can calculate when - // the next characterization should take place. - WONo = Field(WfrID, '*', 1) - WOLogRec = Database_Services('ReadDataRow', 'WO_LOG', WONo) - RunNo = ReactRunRec - LastCharRun = WOLogRec[-1, 'B':@VM] - If ( (LastCharRun EQ '') or (RunNo GT LastCharRun) ) then - LastCharRun = RunNo - WOLogRec = LastCharRun - Database_Services('WriteDataRow', 'WO_LOG', WONo, WOLogRec, True$, False$, True$) - end - end - end else - ErrorMsg = 'This wafer is not ready to split. One or more previous stages have not been completed.' - Error_Services('Add', ErrorMsg) - end - end - -end service - - -Service CharEquation(RDSNo) - - return 0 - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// EligibleToWithdrawWfr -// -// Input: -// RDSNo - [Required] -// WfrID - [Required] -// -// Output: -// Response - True$ (1) if eligible, False$ (0) otherwise -// -//---------------------------------------------------------------------------------------------------------------------- -Service EligibleToWithdrawWfr(RDSNo, WfrID) - - Response = True$ - If (RDSNo NE '') and (WfrID NE '') then - WfrStages = Xlate('REACT_RUN', RDSNo, 'WFR_STAGE', 'X') - Response = True$ - CharDue = False$ - Locate 'SPLIT' in WfrStages using @VM setting StartPos then - // Was the wafer characterized or dispositioned? - FormattedWfrID = WfrID - Convert '*' to '.' in FormattedWfrID - SplitKey = RDSNo:'*SPLIT*':FormattedWfrID - SplitStatus = Xlate('RUN_STAGE_WFR', SplitKey, 'STATUS', 'X') - - // Check to see if characterization is due for this wafer. - // If so, this wafer is not eligble to be withdrawn. - WONo = Field(WfrID, '*', 1) - WOLogRec = Database_Services('ReadDataRow', 'WO_LOG', WONo) - PrevCharRuns = WOLogRec - NumCharRuns = DCount(PrevCharRuns, @VM) - LastCharRun = PrevCharRuns<0, NumCharRuns> - If LastCharRun EQ '' then LastCharRun = 0 - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - InWfrIDs = ReactRunRec - LastWafer = DCount(InWfrIDs, @VM) - RunNo = ReactRunRec - PSNo = Xlate('REACT_RUN', RDSNo, 'PS_NO', 'X') - CharFreq = Xlate('PROD_SPEC', PSNo, 'CHAR_FREQ', 'X') - If ( (RunNo - LastCharRun) EQ CharFreq ) then - // Characterization is due for this run - SelectedWafer = GaN_Services('CharEquation', RDSNo) - If SelectedWafer EQ 0 then SelectedWafer = LastWafer - If SelectedWafer EQ WfrID then - // Characterization is due for this wafer - CharDue = True$ - end - end - - Begin Case - - Case CharDue EQ True$ - Response = False$ - - Case SplitStatus _EQC 'CHAR' - // Wafer was characterized. Ensure no metrology stages have started or been completed. - NextStage = StartPos + 1 - NumStages = DCount(WfrStages, @VM) - For StageIndex = NextStage to NumStages - Stage = WfrStages<0, StageIndex> - RunStageWfrKey = RDSNo:'*':Stage:'*':FormattedWfrID - StageStatus = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'STATUS', 'X') - If StageStatus _EQC 'START' or StageStatus _EQC 'COMP' then - Response = False$ - end - Until Response EQ False$ - Next StageIndex - - Case SplitStatus _EQC 'DISP' - // Wafer was dispositioned. Ensure G_PACK and RETAIN have not been completed. - GPackKey = RDSNo:'*G_PACK*':FormattedWfrID - GPackStatus = Xlate('RUN_STAGE_WFR', GPackKey, 'STATUS', 'X') - RetainSig = Xlate('WO_WFR', WfrID, 'RETAIN_SIG', 'X') - If ( (GPackStatus _EQC 'COMP') or (RetainSig NE '') ) then - Response = False$ - end - - End Case - end - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// WithdrawWfr -// -// Input: -// RDSNo - [Required] -// WfrID - [Required] -// -// Output: -// Response - True$ (1) if successful, False$ (0) otherwise -// -//---------------------------------------------------------------------------------------------------------------------- -Service WithdrawWfr(RDSNo, WfrID) - CurrDTM = DateTime() - Response = False$ - If (RDSNo NE '') and (WfrID NE '') then - WfrStages = Xlate('REACT_RUN', RDSNo, 'WFR_STAGE', 'X') - FormattedWfrID = WfrID - Convert '*' to '.' in FormattedWfrID - Locate 'SPLIT' in WfrStages using @VM setting StartPos then - NumStages = DCount(WfrStages, @VM) - For StageIndex = StartPos to NumStages - Stage = WfrStages<0, StageIndex> - FormattedWfrID = WfrID - Convert '*' to '.' in FormattedWfrID - RunStageWfrKey = RDSNo:'*':Stage:'*':FormattedWfrID - If Stage _EQC 'SPLIT' then - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - OrigReactRunRec = ReactRunRec - // Set RUN_STAGE_WFR record back to INIT status - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - RunStageWfrRec = '' - RunStageWfrRec = '' - RunStageWfrRec = 'INIT' - Database_Services('WriteDataRow','RUN_STAGE_WFR',RunStageWfrKey,RunStageWfrRec,True$,False$,True$) - CurrStage = Gan_Services('GetCurrStage', WfrID) - CurrLocQ = Gan_Services('GetLocQueueID', CurrStage) - ReturnStage = 'SPLIT' - NextLocQ = Gan_Services('GetLocQueueID', ReturnStage) - Gan_Services('RemoveWfrFromWIP', WfrID) - Gan_Services('MoveWfrToQueue', WfrID, NextLocQ) - // Update the WO_WFR record with the LOC_BY, LOC_DTM, INV_LOC (the next prescribed location queue), - // and LOC_EVENT (DISPOSITION) - WOWfrKey = WfrID - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WOWfrKey) - LocDTMs = WOWfrRec - NextStep = DCount(LocDTMs, @VM) + 1 - WOWfrRec = CurrDTM - WOWfrRec = @User4 - WOWfrRec = 'WITHDRAW' - WOWfrRec = '' - WOWfrRec = NextLocQ - Database_Services('WriteDataRow', 'WO_WFR', WOWfrKey, WOWfrRec, True$, False$, True$) - // Mark the wafer as NOT characterized in the REACT_RUN record. - InWfrIDs = ReactRunRec - CharList = ReactRunRec - Locate WfrID in InWfrIDs using @VM setting wPos then - ReactRunRec = False$ - end - Locate WfrID in CharList using @VM setting cPos then - CharList = Delete(CharList, 0, cPos, 0) - ReactRunRec = CharList - end - If OrigReactRunRec NE ReactRunRec then - Database_Services('WriteDataRow', 'REACT_RUN', RDSNo, ReactRunRec, True$, False$, True$) - end - // Locate this run in the in the WO_LOG record and remove it - WONo = Field(WfrID, '*', 1) - WOLogRec = Database_Services('ReadDataRow', 'WO_LOG', WONo) - RunNo = ReactRunRec - PrevCharRuns = WOLogRec - Locate RunNo in PrevCharRuns using @VM setting vPos then - // Only remove this run number if no other wafers are characterizated in this run - WfrCharFlags = ReactRunRec - TotalCharWfrs = Sum(WfrCharFlags) - If TotalCharWfrs EQ 0 then - PrevCharRuns = Delete(PrevCharRuns, 0, vPos, 0) - WOLogRec = PrevCharRuns - Database_Services('WriteDataRow', 'WO_LOG', WONo, WOLogRec, True$, False$, True$) - end - end - end else - // Remove subsequent stages - If RowExists('RUN_STAGE_WFR', RunStageWfrKey) then - Database_Services('DeleteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, True$, False$) - end - end - Next StageIndex - end - end - If Error_Services('NoError') then Response = True$ - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetWfrQueue -// -// Input: -// WfrID - [Required] -// -// Output: -// Response - LOCATION or TOOL_WFR queue ID -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetWfrQueue(WfrID) - - Done = False$ - WfrQ = '' - GaNStages = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_STAGES') - GaNStages = SRP_Array('Rotate', GaNStages, @FM, @VM) - // Need to scan all LOCATION queues for the wafer. - LocQs = GaNStages<6> - ToolClasses = GaNStages<3> - For each LocQKey in LocQs using @VM setting vPos - If LocQKey NE '' then - LocQRec = Database_Services('ReadDataRow', 'LOCATION', LocQKey) - WfrsInQ = LocQRec - Locate WfrID in WfrsInQ using @VM setting wPos then - Done = True$ - WfrQ = LocQKey - end - end - Until Done EQ True$ - Next LocQRec - If Done EQ False$ then - // Wafer not yet found. Scan all TOOL_WFR queues for the wafer. - // Get tool class, then look up associated tool IDs. - For each ToolClassID in ToolClasses using @VM setting vPos - If ToolClassID NE '' then - ToolIDs = Xlate('TOOL_CLASS', ToolClassID, 'TOOL', 'X') - For each ToolID in ToolIDs using @VM setting tPos - If (ToolID NE '') and (RowExists('TOOL_WFR', ToolID)) then - ToolQRec = Database_Services('ReadDataRow', 'TOOL_WFR', ToolID) - WfrsInQ = ToolQRec - Locate WfrID in WfrsInQ using @VM setting wPos then - Done = True$ - WfrQ = ToolID - end - end - Until Done EQ True$ - Next ToolID - end - Until Done EQ True$ - Next ToolClassID - end - - Response = WfrQ - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetEtchQueue -// -// Input: -// EtchID - [Required] -// -// Output: -// Response - LOCATION or TOOL_WFR queue ID -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetEtchQueue(EtchID) - - Done = False$ - EtchQ = '' - GaNStages = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_STAGES') - GaNStages = SRP_Array('Rotate', GaNStages, @FM, @VM) - // Need to scan all LOCATION queues for the etch. - LocQs = GaNStages<6> - ToolClasses = GaNStages<3> - For each LocQKey in LocQs using @VM setting vPos - If LocQKey NE '' then - LocQRec = Database_Services('ReadDataRow', 'LOCATION', LocQKey) - ItemsInQ = LocQRec - Locate EtchID in ItemsInQ using @VM setting wPos then - Done = True$ - EtchQ = LocQKey - end - end - Until Done EQ True$ - Next LocQRec - If Done EQ False$ then - // Etch not yet found. Scan all TOOL_WFR queues for the wafer. - // Get tool class, then look up associated tool IDs. - For each ToolClassID in ToolClasses using @VM setting vPos - If ToolClassID NE '' then - ToolIDs = Xlate('TOOL_CLASS', ToolClassID, 'TOOL', 'X') - For each ToolID in ToolIDs using @VM setting tPos - If (ToolID NE '') and (RowExists('TOOL_ETCH', ToolID)) then - ToolQRec = Database_Services('ReadDataRow', 'TOOL_ETCH', ToolID) - ItemsInQ = ToolQRec - Locate EtchID in ItemsInQ using @VM setting wPos then - Done = True$ - EtchQ = ToolID - end - end - Until Done EQ True$ - Next ToolID - end - Until Done EQ True$ - Next ToolClassID - end - - Response = EtchQ - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetToolClassIDs -// -// Input: -// StageID - [Required] -// -// Output: -// Response - Tool class associated with the given stage ID. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetToolClassIDs(StageID) - - ToolClasses = '' - If StageID NE '' then - GaNStageInfo = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_STAGES') - GaNStageInfo = SRP_Array('Rotate', GaNStageInfo, @FM, @VM) - StageIDs = GaNStageInfo<1> - AllToolClasses = GaNStageInfo<3> - Locate StageID in StageIDs using @VM setting vPos then - ToolClasses = AllToolClasses<0, vPos> - end - end - Response = ToolClasses - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetToolIDs -// -// Input: -// StageID - [Required] -// ToolMode - [Optional] -// -// Output: -// Response - Tool IDs associated with the given stage ID. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetToolIDs(StageID, ToolMode) - - ToolIDs = '' - If StageID NE '' then - ToolClassIDs = Gan_Services('GetToolClassIDs', StageID) - If ToolClassIDs NE '' then - For each ToolClassID in ToolClassIDs using @SVM setting svPos - TempArray = Xlate('TOOL_CLASS', ToolClassID, 'TOOL', 'X') - If ToolMode NE '' then - // Filter on ToolMode - FilteredArray = '' - For each ToolID in TempArray using @VM - CurrMode = Xlate('TOOL', ToolID, 'CURR_MODE', 'X') - If CurrMode EQ ToolMode then - FilteredArray<0, -1> = ToolID - end - Next ToolID - TempArray = FilteredArray - end - ToolIDs = SRP_Array('Join', ToolIDs, TempArray, 'OR', @VM) - Next ToolClassID - If ToolIDs[-1, 1] EQ @VM then ToolIDs[-1, 1] = '' - end - end - - Response = ToolIDs - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// IsDestStage -// -// Input: -// StageID - [Required] -// -// Output: -// Response - True$ (1) if stage is destructive, False$ (0) otherwise. -// -//---------------------------------------------------------------------------------------------------------------------- -Service IsDestStage(StageID) - - Destructive = False$ - ToolClassIDs = Gan_Services('GetToolClassIDs', StageID) - For each ToolClassID in ToolClassIDs using @VM setting vPos - DestClass = Xlate('TOOL_CLASS', ToolClassID, 'DEST_TEST', 'X') - If DestClass EQ True$ then Destructive = True$ - Until Destructive EQ True$ - Next ToolClassID - Response = Destructive - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// ReadyToSplit -// -// Input: -// WfrID - [Required] -// -// Output: -// Response - True$ (1) if WfrID is ready for characterization (i.e. SPLIT) and/or disposition (i.e. DISP), -// False$ (0) otherwise. -// -//---------------------------------------------------------------------------------------------------------------------- -Service ReadyToSplit(WfrID) - - Response = 1 -end service - Done = False$ - ReadyToSplit = True$ - If WfrID NE '' then - // Convert delimiters in case the key is passed in with the wrong format - Convert '.' to '*' in WfrID - GaNStageInfo = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_STAGES') - GaNStageInfo = SRP_Array('Rotate', GaNStageInfo, @FM, @VM) - StageIDs = GaNStageInfo<1> - StageTypes = GaNStageInfo<5> - // 1. Check that all reactor stages (RUN_STAGE) are complete - // 2. Check that all prescribed metrology stages up to, but not including, SPLIT are complete - ReactRunNo = Xlate('WO_WFR', WfrID, 'RDS_NO', 'X') - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', ReactRunNo) - RunStages = ReactRunRec - WfrStages = ReactRunRec - UnRxStages = ReactRunRec - For each RunStageKey in RunStages using @VM setting vPos - StageID = RunStageKey[-1, 'B*'] - Locate StageID in StageIDs using @VM setting vPos then - StageType = StageTypes<0, vPos> - If StageType _EQC 'REACTOR' then - CompBy = Xlate('RUN_STAGE', RunStageKey, 'COMP_BY', 'X') - If CompBy EQ '' then ReadyToSplit = False$ - end - end - Until ReadyToSplit EQ False$ - Next RunStageKey - If ReadyToSplit EQ True$ then - For each WfrStage in WfrStages using @VM setting vPos - Until WfrStage _EQC 'SPLIT' - Skip = False$ - StageUnRx = UnRxStages<0, vPos> - If StageUnRx EQ True$ then Skip = True$ - If Skip EQ False$ then - Convert '*' to '.' in WfrID - RunStageWfrKey = ReactRunNo:'*':WfrStage:'*':WfrID - CompBy = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'COMP_BY', 'X') - If CompBy EQ '' then ReadyToSplit = False$ - end - Until ReadyToSplit EQ False$ - Next WfrStage - end - end - Response = ReadyToSplit - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// ReadyToSplit -// -// Input: -// WfrID - [Required] -// -// Output: -// Response - True$ (1) if any WfrID has been characterized or dispositioned, False$ (0) otherwise. -// -//---------------------------------------------------------------------------------------------------------------------- -Service IsCassSplit(RDSNo) - - Done = False$ - CassSplit = False$ - If RDSNo NE '' then - WfrIDs = Xlate('REACT_RUN', RDSNo, 'IN_WFR_ID', 'X') - Stage = 'SPLIT' - For each WfrID in WfrIDs using @VM setting vPos - Convert '*' to '.' in WfrID - RunStageWfrKey = RDSNo:'*':Stage:'*':WfrID - SplitStatus = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'STATUS', 'X') - If SplitStatus _EQC 'CHAR' or SplitStatus _EQC 'DISP' then - CassSplit = True$ - Done = True$ - end - Until Done EQ True$ - Next WfrID - end - Response = CassSplit - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetRunSplitStatus -// -// Input: -// RDSNo - [Required] -// -// Output: -// Response - True$ (1) if all wafers in the run have been characterized or dispositioned, False$ (0) otherwise. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetRunSplitStatus(RDSNo) - - SplitComp = True$ - If RDSNo NE '' then - WfrIDs = Xlate('REACT_RUN', RDSNo, 'IN_WFR_ID', 'X') - Stage = 'SPLIT' - For each WfrID in WfrIDs using @VM setting vPos - Convert '*' to '.' in WfrID - RunStageWfrKey = RDSNo:'*':Stage:'*':WfrID - SplitStatus = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'STATUS', 'X') - If SplitStatus _EQC 'CHAR' or SplitStatus _EQC 'DISP' then - Null - end else - SplitComp = False$ - end - Until SplitComp EQ False$ - Next WfrID - end - Response = SplitComp - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// ReadyToStart -// -// Input: -// WfrID - [Required] -// -// Output: -// Response - True$ (1) if any WfrID is ready to start a stage (i.e. it has not already started on another -// stage, False$ (0) otherwise. -// -//---------------------------------------------------------------------------------------------------------------------- -Service ReadyToStart(RDSNo, WfrID) - - Done = False$ - ReadyToStart = True$ - Convert '*' to '.' in WfrID - If WfrID NE '' then - - WfrStages = Xlate('REACT_RUN', RDSNo, 'WFR_STAGE', 'X') - For each Stage in WfrStages using @VM setting vPos - RunStageWfrKey = RDSNo:'*':Stage:'*':WfrID - StageStatus = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'STATUS', 'X') - If StageStatus _EQC 'START' then - ReadyToStart = False$ - Done = True$ - end - Until Done EQ True$ - Next Stage - end - Response = ReadyToStart - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetUnRxStatus -// -// Input: -// RDSNo - [Required] -// StageID - [Required] -// -// Output: -// Response - True$ (1) if StageID is unprescribed by the PSN, False$ (0) otherwise. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetUnRxStatus(RDSNo, StageID) - - UnRxStage = False$ - If (RDSNo NE '') and (StageID NE '') then - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - WfrStages = ReactRunRec - UnRxStages = ReactRunRec - Locate StageID in WfrStages using @VM setting vPos then - UnRxStage = UnRxStages<0, vPos> - If UnRxStage EQ '' then UnRxStage = 0 - end else - // Stage not yet added, so we know it is unprescribed. - UnRxStage = True$ - end - end - Response = UnRxStage - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetMetrologyStatus -// -// Input: -// WfrID - [Required] -// -// Output: -// Response - True$ (1) if all metrology stages prescribed and unprescribed have been skipped or completed, -// False$ (0) otherwise. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetMetrologyStatus(WfrID) - - MetStatus = '' - If (WfrID NE '') then - FormattedWfrID = WfrID - Convert '*' to '.' in FormattedWfrID - RDSNo = Xlate('WO_WFR', WfrID, 'RDS_NO', 'X') - GRateKey = RDSNo:'*G_RATE' - GRateStatus = Xlate('RUN_STAGE', GRateKey, 'STATUS', 'X') - If GRateStatus NE 'COMP' then MetStatus = False$ - If ( (RDSNo NE '') and (GRateStatus _EQC 'COMP') ) then - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - WfrStages = ReactRunRec - For each MetStage in WfrStages using @VM setting StageIndex - Until MetStage _EQC 'DISP' - RunStageWfrKey = RDSNo:'*':MetStage:'*':FormattedWfrID - If RowExists('RUN_STAGE_WFR', RunStageWfrKey) then - StageStatus = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'STATUS', 'X') - If StageStatus _EQC 'START' or StageStatus _EQC 'INIT' then - MetStatus = False$ - end - end - Until MetStatus EQ False$ - Next MetStage - If MetStatus EQ '' then MetStatus = True$ - end - end - Response = MetStatus - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetDispositionStatus -// -// Input: -// WfrID - [Required] -// -// Output: -// Response - True$ (1) if wafer is currently at or has previously been at the DISP stage, False$ (0) otherwise. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetDispStatus(WfrID) - - DispStatus = False$ - If (WfrID NE '') then - FormattedWfrID = WfrID - Convert '*' to '.' in FormattedWfrID - RDSNo = Xlate('WO_WFR', WfrID, 'RDS_NO', 'X') - If (RDSNo NE '') then - DispStageKey = RDSNo:'*DISP*':FormattedWfrID - If RowExists('RUN_STAGE_WFR', DispStageKey) then - StageStatus = Xlate('RUN_STAGE_WFR', DispStageKey, 'STATUS', 'X') - CurrLoc = Gan_Services('GetCurrStage', WfrID) - If ( (StageStatus _EQC 'COMP') or (CurrLoc _EQC 'DISP') ) then - DispStatus = True$ - end - end - end - end - Response = DispStatus - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetDestroyedStatus -// -// Input: -// WfrID - [Required] -// -// Output: -// Response - True$ (1) if a destructive metrology stage has been completed, False$ (0) otherwise. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetDestroyedStatus(WfrID) - - DestStatus = False$ - If (WfrID NE '') then - FormattedWfrID = WfrID - Convert '*' to '.' in FormattedWfrID - RDSNo = Xlate('WO_WFR', WfrID, 'RDS_NO', 'X') - If (RDSNo NE '') then - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - WfrIDs = ReactRunRec - ExternalFlags = ReactRunRec - Locate WfrID in WfrIDs using @VM setting WaferPos then - ExternalFlag = ExternalFlags<0, WaferPos> - If ExternalFlag EQ True$ then DestStatus = True$ - end - If DestStatus EQ False$ then - WfrStages = ReactRunRec - For each MetStage in WfrStages using @VM setting StageIndex - If GaN_Services('IsDestStage', MetStage) then - RunStageWfrKey = RDSNo:'*':MetStage:'*':FormattedWfrID - If RowExists('RUN_STAGE_WFR', RunStageWfrKey) then - StageStatus = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'STATUS', 'X') - If StageStatus _EQC 'START' or StageStatus _EQC 'COMP' then - DestStatus = True$ - end - end - end - Until DestStatus EQ True$ - Next MetStage - end - end - end - Response = DestStatus - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetDestroyedWafers -// -// Input: -// RDSNo - [Required] -// -// Output: -// Response - A list of wafer IDs of destroyed wafers in the cassette. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetDestroyedWafers(RDSNo) - - DestroyedWfrs = '' - If RDSNo NE '' then - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - If Error_Services('NoError') then - WfrIDs = ReactRunRec - For each WfrID in WfrIDs using @VM setting wPos - WfrDestroyed = GaN_Services('GetDestroyedStatus', WfrID) - If WfrDestroyed EQ True$ then DestroyedWfrs<0, -1> = WfrID - Next WfrID - end - end - Response = DestroyedWfrs - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetGaNWIPJSON -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetGaNWIPJSON() - - JSON = '' - TableList = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_WIP') - TableList = Delete(TableList, 1, 0, 0) - hStatusObj = '' - hStageArray = '' - hStageObject = '' - hRDSArray = '' - hRDSObject = '' - If SRP_JSON(hStatusObj, 'NEW', 'OBJECT') then - If SRP_JSON(hStageArray, 'NEW', 'ARRAY') then - PreviousStage = '' - For Each StatusLine in TableList using @FM - Stage = StatusLine<0, 1> - If Stage NE '' then - // New stage being introduced. Close the previous stage if one exists. - If PreviousStage NE '' then - SRP_JSON(hStageObject, 'SET', 'RDS Items', hRDSArray) - SRP_JSON(hRDSArray, 'RELEASE') - SRP_JSON(hStageArray, 'ADD', hStageObject) - SRP_JSON(hStageObject, 'RELEASE') - end - SRP_JSON(hStageObject, 'NEW', 'OBJECT') - SRP_JSON(hStageObject, 'SETVALUE', 'stage', Stage) - SRP_JSON(hRDSArray, 'NEW', 'ARRAY') - PreviousStage = Stage - end else - RDSNo = StatusLine<0, 2> - If RDSNo NE '' then - // RDS / Wafer line being added to the current stage. - SRP_JSON(hRDSObject, 'NEW', 'OBJECT') - SRP_JSON(hRDSObject, 'SETVALUE', 'RDS No', RDSNo, 'STRING') - SRP_JSON(hRDSObject, 'SETVALUE', 'Run/Etch ID', StatusLine<0, 3>, 'STRING') - SRP_JSON(hRDSObject, 'SETVALUE', 'Part No', StatusLine<0, 4>, 'STRING') - SRP_JSON(hRDSObject, 'SETVALUE', 'Wait Pri', StatusLine<0, 5>, 'STRING') - SRP_JSON(hRDSObject, 'SETVALUE', 'Wait Wfrs', StatusLine<0, 6>, 'STRING') - SRP_JSON(hRDSObject, 'SETVALUE', 'Wait Hrs', StatusLine<0, 7>, 'STRING') - SRP_JSON(hRDSObject, 'SETVALUE', 'Wait Wfr ID', StatusLine<0, 8>, 'STRING') - SRP_JSON(hRDSObject, 'SETVALUE', 'Tool ID', StatusLine<0, 9>, 'STRING') - SRP_JSON(hRDSObject, 'SETVALUE', 'Run Wfrs', StatusLine<0, 10>, 'STRING') - SRP_JSON(hRDSObject, 'SETVALUE', 'Run Hrs', StatusLine<0, 11>, 'STRING') - SRP_JSON(hRDSObject, 'SETVALUE', 'Run Wfr ID', StatusLine<0, 12>, 'STRING') - SRP_JSON(hRDSArray, 'ADD', hRDSObject) - SRP_JSON(hRDSObject, 'RELEASE') - end - end - Next StatusLine - // Add the last stage object to the stage array. - SRP_JSON(hStageObject, 'SET', 'RDS Items', hRDSArray) - SRP_JSON(hRDSArray, 'RELEASE') - SRP_JSON(hStageArray, 'ADD', hStageObject) - SRP_JSON(hStageObject, 'RELEASE') - SRP_JSON(hStatusObj, 'SET', 'stages', hStageArray) - SRP_JSON(hStageArray, 'RELEASE') - end - JSON = SRP_JSON(hStatusObj, 'STRINGIFY', 'FAST') - SRP_JSON(hStatusObj, 'RELEASE') - end else - Error_Services('Add', 'Error creating the GAN WIP Status JSON object.') - end - - Response = JSON - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// SelectGaNEtchRuns -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service SelectGaNEtchRuns(ParentWindow, GaNEtchID, Reactor) - - // Close Etch Manager if it is already open so that we can launch it in COMMIT mode. - EtchManVis = Get_Property('NDW_INTERNAL_ETCH_MANAGER', 'VISIBLE') - If EtchManVis EQ True$ then End_Window('NDW_INTERNAL_ETCH_MANAGER') - Response = Dialog_Box('NDW_INTERNAL_ETCH_MANAGER', ParentWindow, 'COMMIT':@FM:GaNEtchID:@FM:Reactor) - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// AddWfrsToOutCass -// -// Input: -// OutCassID - [Required] - -// SelInWfrIDs - [Required] - Inbound wafer IDs to be be added to the outbound cassette, OutCassID. -// -//---------------------------------------------------------------------------------------------------------------------- -Service AddWfrsToOutCass(OutCassID, SelInWfrIDs) - - CurrDTM = Datetime() - WOMatWfrKey = OutCassID - WOMatWfrRec = Database_Services('ReadDataRow', 'WO_MAT_WFR', WOMatWfrKey) - OutWfrIDs = WOMatWfrRec - AvailSlots = '' - // Count empty (i.e. available) slots to fill - NumWfrs = 25 - For WfrIndex = 1 to NumWfrs - If OutWfrIDs<0, WfrIndex> EQ '' then AvailSlots<0, -1> = OutCassID:'*':WfrIndex - Next WaferIndex - NumAvailSlots = DCount(AvailSlots, @VM) - NumAddWfrs = DCount(SelInWfrIDs, @VM) - If NumAddWfrs LE NumAvailSlots then - - FOR AddWfrIndex = 1 TO NumAddWfrs - WfrID = SelInWfrIDs<1, AddWfrIndex> - RDSNo = Xlate('WO_WFR', WfrID, 'RDS_NO', 'X') - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - // Place IN_WFR_ID into outbound cassette - OutWfrID = AvailSlots<0, AddWfrIndex> - OutSlot = Field(OutWfrID, '*', 3, 1) - OutWfrIDs<0, OutSlot> = WfrID - // Place wafer into REACT_RUN outbound wafer field - LOCATE WfrID IN ReactRunRec USING @VM SETTING Pos THEN - ReactRunRec = OutWfrID - END - // Update REACT_RUN table (RDS table) - Database_Services('WriteDataRow', 'REACT_RUN', RDSNo, ReactRunRec, True$, False$, True$) - // Update WO_WFR table (wafer trace table) - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WfrID) - LOCATE WfrID IN ReactRunRec USING @VM SETTING cPos THEN - CurrCarrSlot = ReactRunRec - END ELSE - CurrCarrSlot = '' - END - EventDTMs = WOWfrRec - CurrEventIndex = DCount(EventDTMs, @VM) - WOWfrRec = OutWfrID - WOWfrRec = CurrCarrSlot - Database_Services('WriteDataRow', 'WO_WFR', WfrID, WOWfrRec, True$, False$, True$) - NEXT I - - // Update WO_MAT_WFR table (outbound cassette table) - WOMatWfrRec = OutWfrIDs - Database_Services('WriteDataRow', 'WO_MAT_WFR', WOMatWfrKey, WOMatWfrRec, True$, False$, True$) - - end else - ErrorMessage = 'Add wafer operation failed. ':NumAddWfrs:' wafer(s) selected, but only ':NumAvailSlots: ' ' | - : 'slot(s) are available.' - Error_Services('Add', ErrorMessage) - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// AddWfrToOutCass -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service AddWfrToOutCass(WfrID) - - If WfrID NE '' then - WONo = Field(WfrID, '*', 1) - RDSNo = Xlate('WO_WFR', WfrID, 'RDS_NO', 'X') - WORec = Database_Services('ReadDataRow', 'WO_LOG', WONo) - - // Get next outbound slot - OutSlotID = WORec - OutCassNo = OutSlotID[1, 'F*'] - OutSlotNo = OutSlotID[Col2()+1, 2] - OutSlotKey = WONo:'*':OutCassNo:'*':OutSlotNo - - // Update next outbound slot - MaxShipQty = Xlate('WO_LOG', WONo, 'CUST_EPI_PART_SHIP_QTY', 'X') - If ( (OutSlotNo) GE MaxShipQty ) then - - // Is there another outbound cassette available? - NextCassNo = OutCassNo + 1 - NextCassKey = WONo:'*':NextCassNo - If ( RowExists('WO_MAT_WFR', NextCassKey) EQ True$ ) then - // We have another outbound cassette - Null - end else - // No more outbound cassettes available, so create one now - * 1. Add WO_MAT key to WO_LOG - WORec = NextCassKey - * 2. Create WO_MAT_WFR record - NextWOMatWfrRec = '' - * 3. Populate WO_MAT_WFR record with outbound slots ONLY - * (i.e. do not populate inbound slot columns as this would be equivalent to releasing new material) - For Slot = 1 to MaxShipQty - NextWOMatWfrRec = WONo:'*':NextCassNo:'*':Slot - Next Slot - Database_Services('WriteDataRow', 'WO_MAT_WFR', NextCassKey, NextWOMatWfrRec) - end - NextOutSlot = NextCassNo:'*':1 - end else - NextOutSlot = OutCassNo:'*':(OutSlotNo + 1) - end - - WORec = NextOutSlot - Database_Services('WriteDataRow', 'WO_LOG', WONo, WORec, True$, False$, True$) - - // Update WO_MAT_WFR table (outbound cassette table) - CurrDTM = Datetime() - WOMatWfrKey = WONo:'*':OutCassNo - WOMatWfrRec = Database_Services('ReadDataRow', 'WO_MAT_WFR', WOMatWfrKey) - OutWfrIDs = WOMatWfrRec - OutWfrIDs<0, OutSlotNo> = WfrID - WOMatWfrRec = OutWfrIDs - Database_Services('WriteDataRow', 'WO_MAT_WFR', WOMatWfrKey, WOMatWfrRec, True$, False$, True$) - - // Place wafer into REACT_RUN outbound wafer field - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - LOCATE WfrID IN ReactRunRec USING @VM SETTING Pos THEN - ReactRunRec = OutSlotKey - END - Database_Services('WriteDataRow', 'REACT_RUN', RDSNo, ReactRunRec, True$, False$, True$) - - // Move wafer into the G_PACK queue - PackQ = 'GCH*Q_PACK' - CurrQ = Gan_Services('GetWfrQueue', WfrID) - Gan_Services('RemoveWfrFromWIP', WfrID) - Gan_Services('MoveWfrToQueue', WfrID, PackQ) - - // Update WO_WFR table (wafer trace table) - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WfrID) - LOCATE WfrID IN ReactRunRec USING @VM SETTING cPos THEN - CurrCarrSlot = ReactRunRec - END ELSE - CurrCarrSlot = '' - END - EventDTMs = WOWfrRec - NextPos = DCount(EventDTMs, @VM) + 1 - WOWfrRec = OutSlotKey - WOWfrRec = CurrCarrSlot - WOWfrRec = CurrDTM - WOWfrRec = @USER4 - WOWfrRec = 'COMP' - WOWfrRec = '' - WOWfrRec = PackQ - Database_Services('WriteDataRow', 'WO_WFR', WfrID, WOWfrRec, True$, False$, True$) - // Mark DISP complete - Convert '*' to '.' in WfrID - RunStageWfrKey = RDSNo:'*DISP*':WfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - StageStatus = RunStageWfrRec - If StageStatus _EQC 'INIT' then - // Mark DISP stage as complete - RunStageWfrRec = @USER4 - RunStageWfrRec = CurrDTM - RunStageWfrRec = 'COMP' - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$) - end - - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// RemoveWfrsFromOutCass -// -// Input: -// OutCassID - [Required] - Outbound GaN cassette ID from which SelInWfrIDs will be removed. -// SelInWfrIDs - [Required] - Inbound wafer IDs to be removed from the outbound cassette, OutCassID. -// -//---------------------------------------------------------------------------------------------------------------------- -Service RemoveWfrsFromOutCass(OutCassID, SelInWfrIDs) - - CurrDTM = Datetime() - WOMatWfrKey = OutCassID - WOMatWfrRec = Database_Services('ReadDataRow', 'WO_MAT_WFR', WOMatWfrKey) - OutWfrIDs = WOMatWfrRec - NumRemWfrs = DCount(SelInWfrIDs, @VM) - FOR RemWfrIndex = 1 TO NumRemWfrs - WfrID = SelInWfrIDs<1, RemWfrIndex> - RDSNo = Xlate('WO_WFR', WfrID, 'RDS_NO', 'X') - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - // Remove IN_WFR_ID from outbound cassette - Locate WfrID in OutWfrIDs using @VM setting vPos then - OutWfrIDs<0, vPos> = '' - end - // Remove wafer from REACT_RUN outbound wafer field - LOCATE WfrID IN ReactRunRec USING @VM SETTING Pos THEN - ReactRunRec = '' - END - // Update REACT_RUN table (RDS table) - Database_Services('WriteDataRow', 'REACT_RUN', RDSNo, ReactRunRec, True$, False$, True$) - // Update WO_WFR table (wafer trace table) - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WfrID) - EventDTMs = WOWfrRec - CurrEventIndex = DCount(EventDTMs, @VM) - WOWfrRec = '' - WOWfrRec = '' - Database_Services('WriteDataRow', 'WO_WFR', WfrID, WOWfrRec, True$, False$, True$) - NEXT I - - // Update WO_MAT_WFR table (outbound cassette table) - WOMatWfrRec = OutWfrIDs - Database_Services('WriteDataRow', 'WO_MAT_WFR', WOMatWfrKey, WOMatWfrRec, True$, False$, True$) - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetOutOfSpecStatus -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetOutOfSpecStatus(RDSNo, WfrID, Split) - - If ( (RDSNo NE '') and (WfrID NE '') and (Split NE '') ) then - DataOutOfSpec = '' - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - WfrStages = ReactRunRec - StageList = '' - Begin Case - Case Split EQ 'PRE' - For each Stage in WfrStages using @VM setting StagePos - Until Stage EQ 'SPLIT' - StageList<0, -1> = Stage - Next Stage - - Case Split EQ 'POST' - Locate 'SPLIT' in WfrStages using @VM setting StartPos then - StartPos += 1 - NumStages = DCount(WfrStages, @VM) - For StageIndex = StartPos to NumStages - Stage = WfrStages<0, StageIndex> - Until Stage EQ 'DISP' - StageList<0, -1> = Stage - Next StageIndex - end - - Case Otherwise$ - Error_Services('Add', 'Invalid Split value supplied to service ':Service:'.') - End Case - - If Error_Services('NoError') then - Convert '*' to '.' in WfrID - For each Stage in StageList using @VM - RunStageWfrKey = RDSNo:'*':Stage:'*':WfrID - OutOfSpecArray = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'PARAM_OUT_OF_SPEC', 'X') - DataOutOfSpec = ( Index(OutOfSpecArray, 1, 1) > 0 ) - Until DataOutOfSpec EQ True$ - Next Stage - end - Response = DataOutOfSpec - end else - Error_Services('Add', 'Null RDSNo, WfrID, or Split value supplied to service ':Service:'.') - end -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// SplitSelection -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service SplitSelection(RDSNo) - - // Check if we need to auto-characterize the wafer. - If RDSNo NE '' then - PSNo = Xlate('RDS', RDSNo, 'PROD_SPEC_ID', 'X') - ANKO = Xlate('PROD_SPEC', PSNo, 'ANKO', 'X') - ANKOMetPockets = Xlate('PROD_SPEC', PSNo, 'ANKO_MET_POCKETS', 'X') - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - InWfrIDs = ReactRunRec - OutOfSpecArray = ReactRunRec - CassNo = ReactRunRec - WONo = ReactRunRec - GaNCritStages = ReactRunRec - GaNParamKeys = ReactRunRec - RunNo = CassNo - WOLogRec = Database_Services('ReadDataRow', 'WO_LOG', WONo) - SplitArray = '' - - // Is characterization due for this run? - CharReq = ( Xlate('REACT_RUN', RDSNo, 'CHAR_STATUS', 'X') _EQC 'Sched' ) - - If CharReq EQ True$ then - CharWfrIndex = '' - If ANKO EQ True$ then - For each Value in OutOfSpecArray using @VM setting vPos - ANKOPocket = ANKOMetPockets<0, vPos> - If ( (ANKOPocket EQ True$) and (Value EQ True$) ) then - NumWfrsOOS += Value - end - Next Value - end else - NumWfrsOOS = Sum(OutOfSpecArray) - end - If ANKO EQ True$ then - NumCriticalFailWfrs = Xlate('REACT_RUN', RDSNo, 'NUM_ANKO_CRITICAL_FAIL_WFRS', 'X') - end else - NumCriticalFailWfrs = Xlate('REACT_RUN', RDSNo, 'NUM_CRITICAL_FAIL_WFRS', 'X') - end - NumWfrsOOS -= NumCriticalFailWfrs - Begin Case - - Case NumWfrsOOS EQ 0 - // Select the wafer with the highest candela total defects value - DefectArray = '' - WorstWfrIndex = 1 - For each WfrID in InWfrIDs using @VM setting WfrIndex - ANKOPocket = ANKOMetPockets<0, WfrIndex> - If ( (ANKO EQ True$) and (ANKOPocket NE True$) ) then - // Don't consider this wafer for split selection - Null - end else - // Consider this wafer for split selection - CriticalFailure = Xlate('WO_WFR', WfrID, 'CRITICAL_FAILURE', 'X') - If CriticalFailure NE True$ then - CANTotalDefects = 0 - Convert '*' to '.' in WfrID - // Try to use CAN_PST data if it exists, otherwise fallback on CAN_PRE data. - Locate 'CAN_PST' in GaNCritStages using @VM setting sPos then - GaNParamKey = GanParamKeys<0, sPos> - MetNames = Xlate('GAN_PARAMS', GaNParamKey, 'MET_NAME', 'X') - Locate 'Candela Total Defects Post' in MetNames using @VM setting mPos then - RunStageWfrKey = RDSNo:'*CAN_PST*':WfrID - If RowExists('RUN_STAGE_WFR', RunStageWfrKey) then - MetValues = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'MET_PARAM_VALUES', 'X') - CANTotalDefects = MetValues<0, mPos> - If CANTotalDefects NE '' then - DefectArray<0, WfrIndex> = CANTotalDefects - WorstWfrDefects = DefectArray<0, WorstWfrIndex> - If CANTotalDefects GT WorstWfrDefects then - WorstWfrIndex = WfrIndex - end - end - end else - Locate 'CAN_PRE' in GaNCritStages using @VM setting sPos then - GaNParamKey = GanParamKeys<0, sPos> - MetNames = Xlate('GAN_PARAMS', GaNParamKey, 'MET_NAME', 'X') - Locate 'Candela Total Defects' in MetNames using @VM setting mPos then - RunStageWfrKey = RDSNo:'*CAN_PRE*':WfrID - If RowExists('RUN_STAGE_WFR', RunStageWfrKey) then - MetValues = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'MET_PARAM_VALUES', 'X') - CANTotalDefects = MetValues<0, mPos> - If CANTotalDefects NE '' then - DefectArray<0, WfrIndex> = CANTotalDefects - WorstWfrDefects = DefectArray<0, WorstWfrIndex> - If CANTotalDefects GT WorstWfrDefects then - WorstWfrIndex = WfrIndex - end - end - end - end - end - end - end - end else - Locate 'CAN_PRE' in GaNCritStages using @VM setting sPos then - GaNParamKey = GanParamKeys<0, sPos> - MetNames = Xlate('GAN_PARAMS', GaNParamKey, 'MET_NAME', 'X') - Locate 'Candela Total Defects' in MetNames using @VM setting mPos then - RunStageWfrKey = RDSNo:'*CAN_PRE*':WfrID - If RowExists('RUN_STAGE_WFR', RunStageWfrKey) then - MetValues = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'MET_PARAM_VALUES', 'X') - CANTotalDefects = MetValues<0, mPos> - If CANTotalDefects NE '' then - DefectArray<0, WfrIndex> = CANTotalDefects - WorstWfrDefects = DefectArray<0, WorstWfrIndex> - If CANTotalDefects GT WorstWfrDefects then - WorstWfrIndex = WfrIndex - end - end - end - end - end - end - end - end - Next WfrID - - CharWfrIndex = WorstWfrIndex - - Case NumWfrsOOS EQ 1 - ANKOPocket = ANKOMetPockets<0, WfrIndex> - If ( (ANKO EQ True$) and (ANKOPocket NE True$) ) then - // Don't consider this wafer for split selection - Null - end else - // Consider this wafer for split selection - // Use the out of spec wafer that hasn't failed critically - For each WfrID in InWfrIDs using @VM setting WfrIndex - CriticalFailure = Xlate('WO_WFR', WfrID, 'CRITICAL_FAILURE', 'X') - If ( (OutOfSpecArray<0, WfrIndex> EQ True$) and (CriticalFailure NE True$) ) then - CharWfrIndex = WfrIndex - end - Until CharWfrIndex NE '' - Next WfrID - end - - Case NumWfrsOOS GT 1 - // Select the out of spec wafer with the highest candela total defects value - DefectArray = '' - WorstWfrIndex = 1 - For each WfrID in InWfrIDs using @VM setting WfrIndex - ANKOPocket = ANKOMetPockets<0, WfrIndex> - If ( (ANKO EQ True$) and (ANKOPocket NE True$) ) then - // Don't consider this wafer for split selection - Null - end else - // Consider this wafer for split selection - CriticalFailure = Xlate('WO_WFR', WfrID, 'CRITICAL_FAILURE', 'X') - If CriticalFailure NE True$ then - WfrOOS = OutOfSpecArray<0, WfrIndex> - If WfrOOS EQ True$ then - CANTotalDefects = 0 - Convert '*' to '.' in WfrID - // Try to use CAN_PST data if it exists, otherwise fallback on CAN_PRE data. - Locate 'CAN_PST' in GaNCritStages using @VM setting sPos then - GaNParamKey = GanParamKeys<0, sPos> - MetNames = Xlate('GAN_PARAMS', GaNParamKey, 'MET_NAME', 'X') - Locate 'Candela Total Defects Post' in MetNames using @VM setting mPos then - RunStageWfrKey = RDSNo:'*CAN_PST*':WfrID - If RowExists('RUN_STAGE_WFR', RunStageWfrKey) then - MetValues = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'MET_PARAM_VALUES', 'X') - CANTotalDefects = MetValues<0, mPos> - If CANTotalDefects NE '' then - DefectArray<0, WfrIndex> = CANTotalDefects - WorstWfrDefects = DefectArray<0, WorstWfrIndex> - If CANTotalDefects GT WorstWfrDefects then - WorstWfrIndex = WfrIndex - end - end - end else - Locate 'CAN_PRE' in GaNCritStages using @VM setting sPos then - GaNParamKey = GanParamKeys<0, sPos> - MetNames = Xlate('GAN_PARAMS', GaNParamKey, 'MET_NAME', 'X') - Locate 'Candela Total Defects' in MetNames using @VM setting mPos then - RunStageWfrKey = RDSNo:'*CAN_PRE*':WfrID - If RowExists('RUN_STAGE_WFR', RunStageWfrKey) then - MetValues = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'MET_PARAM_VALUES', 'X') - CANTotalDefects = MetValues<0, mPos> - If CANTotalDefects NE '' then - DefectArray<0, WfrIndex> = CANTotalDefects - WorstWfrDefects = DefectArray<0, WorstWfrIndex> - If CANTotalDefects GT WorstWfrDefects then - WorstWfrIndex = WfrIndex - end - end - end - end - end - end - end - end else - Locate 'CAN_PRE' in GaNCritStages using @VM setting sPos then - GaNParamKey = GanParamKeys<0, sPos> - MetNames = Xlate('GAN_PARAMS', GaNParamKey, 'MET_NAME', 'X') - Locate 'Candela Total Defects' in MetNames using @VM setting mPos then - RunStageWfrKey = RDSNo:'*CAN_PRE*':WfrID - If RowExists('RUN_STAGE_WFR', RunStageWfrKey) then - MetValues = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'MET_PARAM_VALUES', 'X') - CANTotalDefects = MetValues<0, mPos> - If CANTotalDefects NE '' then - DefectArray<0, WfrIndex> = CANTotalDefects - WorstWfrDefects = DefectArray<0, WorstWfrIndex> - If CANTotalDefects GT WorstWfrDefects then - WorstWfrIndex = WfrIndex - end - end - end - end - end - end - end - end - end - Next WfrID - CharWfrIndex = WorstWfrIndex - End Case - - For each WfrID in InWfrIDs using @VM setting WfrIndex - If WfrIndex EQ CharWfrIndex then - SplitArray<0, WfrIndex> = 'CHAR' - end else - SplitArray<0, WfrIndex> = 'DISP' - end - Next WfrID - - end else - // Disposition all wafers - For each WfrID in InWfrIDs using @VM setting WfrIndex - SplitArray<0, WfrIndex> = 'DISP' - Next WfrID - end - - // Disposition and characterize wafers according to the data from our split array. - Auto = True$ - For each WfrID in InWfrIDs using @VM setting WfrIndex - SplitAction = SplitArray<0, WfrIndex> - Begin Case - Case SplitAction EQ 'CHAR' - Gan_Services('CharacterizeWafer', RDSNo, WfrID, Auto) - Case SplitAction EQ 'DISP' - Gan_Services('DispositionWfr', RDSNo, WfrID, Auto) - Case Otherwise$ - ErrorMsg = 'Error splitting wafer ':WfrID:' in the ':Service:' service.' - Error_Services('Add', ErrorMsg) - End Case - Next WfrID - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetCharType -// -// Input: -// WfrID - [Required] -// -// Output: -// Response - 'Light' if light characterization performed on wafer, 'Full' if destructive characterization -// performed on wafer, or '' if no characterization perfomed on wafer. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetCharType(WfrID) - - CharType = '' - If WfrID NE '' then - RDSNo = Xlate('WO_WFR', WfrID, 'RDS_NO', 'X') - If (RDSNo NE '') then - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - InWfrIDs = ReactRunRec - CharFlags = ReactRunRec - Locate WfrID in InWfrIDs using @VM setting WfrIndex then - WfrCharacterized = CharFlags<0, WfrIndex> - If WfrCharacterized EQ True$ then - WfrDestroyed = Gan_Services('GetDestroyedStatus', WfrID) - If WfrDestroyed EQ True$ then - CharType = 'Full' - end else - CharType = 'Light' - end - end - end else - Error_Services('Add', 'Error locating WfrID ':WfrID:' in RDS record ':RDSNo:' in service ':Service:'.') - end - end else - Error_Services('Add', 'Error retrieving RDS number from WO_WFR record ':WfrID:' in service ':Service:'.') - end - end else - Error_Services('Add', 'Null WfrID key supplied to service ':Service:'.') - end - Response = CharType - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// ReadyToClose -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service ReadyToClose(RDSNo) - - Response = False$ - If RDSNo NE '' then - ReadyToClose = True$ - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - WfrsDispReady = ReactRunRec - For each WfrStatus in WfrsDispReady using @VM - If WfrStatus NE True$ then - ReadyToClose = False$ - end - Until ReadyToClose = False$ - Next WfrStatus - Response = ReadyToClose - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// CloseRDS -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service CloseRDS(RDSNo) - - If RDSNo NE '' then - // Is the RDS eligible to be closed? - CurrDTM = Datetime() - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - WfrsDispReady = ReactRunRec - InWfrIDs = ReactRunRec - EligibleToClose = True$ ; // Assume ready to close until proven otherwise - For each WfrStatus in WfrsDispReady using @VM setting WfrIndex - If WfrStatus NE True$ then EligibleToClose = False$ - Until EligibleToClose EQ False$ - Next WfrStatus - If EligibleToClose EQ True$ then - // 1. Move eligble wafers to outbound box. - ShipFlags = ReactRunRec - OutSlotIDs = ReactRunRec - WONo = ReactRunRec - WOLogRec = Database_Services('ReadDataRow', 'WO_LOG', WONo) - WOMatKeys = WOLogRec - CustNo = WOLogRec - EpiPartNo = WOLogRec - CustEpiNo = CustNo:'*':EpiPartNo - SchedQty = Xlate('CUST_EPI_PART', CustEpiNo, 'CASS_SHIP_QTY', 'X') - NumCass = DCount(WOMatKeys, @VM) - OutCassQtys = Xlate('WO_MAT_WFR', WOMatKeys, 'OUT_WFR_QTY', 'X') - FQASigs = Xlate('WO_MAT', WOMatKeys, 'CASS_FINAL_SIG', 'X') - PSNo = Xlate('REACT_RUN', RDSNo, 'PS_NO', 'X') - ANKO = Xlate('PROD_SPEC', PSNo, 'ANKO', 'X') - CurrPartNo = Xlate('PROD_SEPC', PSNo, 'CURR_PART_NO', 'X') - - For each InWfrID in InWfrIDs using @VM setting WfrIndex - NextOutSlotID = '' - ShipFlag = ShipFlags<0, WfrIndex> - OutSlotID = OutSlotIDs<0, WfrIndex> - If ( (ShipFlag EQ True$) and (OutSlotID EQ '') and (ANKO NE True$) ) then -* If ( (ShipFlag EQ True$) and (OutSlotID EQ '') and (ANKO NE True$) and (CurrPartNo NE 'U314') ) then - Gan_Services('AddWfrToOutCass', InWfrID) - end else - // Remove the wafer from the WIP. These wafers should be in either DISP or RETAIN - CurrStage = GaN_Services('GetCurrStage', InWfrID) - CurrQ = GaN_Services('GetWfrQueue', InWfrID) - If CurrQ NE '' then Gan_Services('RemoveWfrFromWIP', InWfrID) - If CurrStage NE '' then - // Mark current stage complete - Convert '*' to '.' in InWfrID - RunStageWfrKey = RDSNo:'*':CurrStage:'*':InWfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - StageStatus = RunStageWfrRec - If StageStatus _EQC 'INIT' then - // Mark DISP stage as complete - RunStageWfrRec = @USER4 - RunStageWfrRec = CurrDTM - RunStageWfrRec = 'COMP' - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$) - end - end - end - Next InWfrID - - If Error_Services('NoError') then - // Get an up-to-date copy of the REACT_RUN record - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - // Mark the RDS "Closed" - ReactRunRec = True$ - Database_Services('WriteDataRow', 'REACT_RUN', RDSNo, ReactRunRec, True$, False$, True$) - Engineering_Services('ClearEARequests', RDSNo) - end - end else - If Assigned(WfrIndex) then - WfrID = InWfrIDs<0, WfrIndex> - Error_Services('Add', 'Error closing RDS. Wafer ':WfrID:' has incomplete metrology stages.') - end else - Error_Services('Add', 'Error closing RDS') - end - end - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// UpdateDataFlags -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service UpdateDataFlags(RDSNo) - - Response = '' - If RDSNo NE '' then - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - OrigReactRunRec = ReactRunRec - InWfrIDs = ReactRunRec - CharFlags = ReactRunRec - CritStages = ReactRunRec - RunScrapped = False$ - // Clear failure flags - ReactRunRec = RunScrapped - ReactRunRec = '' - GaNMetStages = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_MET_STAGES') - - For each WfrID in InWfrIDs using @VM setting WaferPos - // Assume flags are false for this wafer until proven otherwise. - DataValidationDisabled = ReactRunRec - DataIsMissing = False$ - DataOutOfSpec = False$ - For each Stage in GaNMetStages using @FM setting StagePos - Abort = False$ - If Abort EQ False$ then - Locate Stage in CritStages using @VM setting vPos then - PostSplit = '' - PostSplitFailure = False$ - WaferCharacterized = '' - PostSplit = (StagePos GT 4) - WaferCharacterized = CharFlags<0, WaferPos> - Convert '*' to '.' in WfrID - - RunStageWfrKey = RDSNo:'*':Stage:'*':WfrID - If RowExists('RUN_STAGE_WFR', RunStageWfrKey) then - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - OutOfSpecArray = RunStageWfrRec - - For each Parameter in OutOfSpecArray using @VM setting vPos - If DataIsMissing EQ False$ then - // Check if we need to set the flag to true - Locate '-1' in Parameter using @SVM setting pPos then - DataIsMissing = True$ - end - end - Locate '1' in Parameter using @SVM setting pPos then - DataOutOfSpec = True$ - If PostSplit EQ True$ then PostSplitFailure = True$ - end - Next Parameter - - If RunScrapped NE True$ then - // Check if we need to set the flag to true - If ( (PostSplitFailure EQ True$) and (WaferCharacterized EQ True$) and (DataValidationDisabled NE True$) ) then - RunScrapped = True$ - ReactRunRec = RunScrapped - end - end - end - end - end - Next Stage - - ReactRunRec = DataIsMissing - ReactRunRec = DataOutOfSpec - If ( (DataIsMissing EQ False$) and (DataOutOfSpec EQ False$) ) then - ReactRunRec = False$ - ReactRunRec = '' - ReactRunRec = '' - end - - Next WfrID - - If OrigReactRunRec NE ReactRunRec then - Database_Services('WriteDataRow', 'REACT_RUN', RDSNo, ReactRunRec, True$, False$, True$) - end - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetGaNMetrologyData -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetGaNMetrologyData(RDSNo, Stage, Tool, WfrID) - - Response = '' - ErrorMsg = '' - OICandelaStage = '' - Abort = False$ - If ( (RDSNo NE '') and (Stage NE '') ) then - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - OrigReactRunRec = ReactRunRec - PSNo = Xlate('REACT_RUN', RDSNo, 'PS_NO', 'X') - NCRFlags = ReactRunRec - InWfrIDs = ReactRunRec - DispFlags = ReactRunRec - Grades = ReactRunRec - Reasons = ReactRunRec - CharFlags = ReactRunRec - RunScrapped = ReactRunRec - - If Abort EQ False$ then - TechType = Xlate('PROD_SPEC', PSNo, 'TECH_TYPE', 'X') - GaNMetStages = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_MET_STAGES') - If WfrID NE '' then Scribe = Xlate('WO_WFR', WfrID, 'SCRIBE', 'X') - - GaNParamKey = '' - GaNParamKeys = Xlate('REACT_RUN', RDSNo, 'GAN_PARAM_KEYS', 'X') - Found = False$ - For each GaNParamKey in GaNParamKeys using @VM setting vPos - Loc = Index(GaNParamKey, Stage, 1) - If Loc GT 0 then Found = True$ - Until Found EQ True$ - Next GaNParamKey - - GaNParamRec = Database_Services('ReadDataRow', 'GAN_PARAMS', GaNParamKey) - MetNames = GaNParamRec - LSLs = GaNParamRec - USLs = GaNParamRec - Targets = GaNParamRec - RunNo = ReactRunRec - Reactor = 'R':ReactRunRec - PartNo = Xlate('REACT_RUN', RDSNo, 'EPI_PART_NO', 'X') - - Query = '' - IQSToolID = Xlate('TOOL', Tool, 'IQS_ID', 'X') - - Query = "SELECT td.F_NAME, se.F_TSNO, SE.F_SBNO, se.F_VAL " - Query := "FROM [IRMNSPC].[dbo].[SGRP_EXT] se " - Query := "JOIN [IRMNSPC].[dbo].[PART_LOT] pl on se.F_LOT = pl.F_LOT " - Query := "JOIN [IRMNSPC].[dbo].[TEST_DAT] td on se.F_TEST = td.F_TEST " - Query := "JOIN [IRMNSPC].[dbo].[PART_DAT] pd on se.F_PART = pd.F_PART " - Query := "JOIN [IRMNSPC].[dbo].[PRCS_DAT] pr on se.F_PRCS = pr.F_PRCS " - If ( (Stage NE 'GROWTH') and (Stage NE 'TEMP') ) then - Query := "JOIN [IRMNSPC].[dbo].[SGRP_DSC] sd on se.F_SGRP = sd.F_SGRP " - Query := "LEFT JOIN [IRMNSPC].[dbo].[DESC_DAT] dd on sd.F_DESC = dd.F_DESC " - end - Query := "WHERE pd.F_NAME = '":PartNo:"' AND " - Query := " pr.F_NAME = '":Reactor:"' AND " - Query := " pl.F_NAME = '":RunNo:"' AND " - Query := " se.F_FLAG = 0 AND " - Begin Case - Case ( (Stage EQ 'WARP') or (Stage EQ 'GROWTH') or (Stage EQ 'TEMP') ) - Query := " (" - Case ( (Stage EQ 'CAN') or (Stage EQ 'UV') or (Stage EQ 'UV_PRE') or (Stage EQ 'UV_PST') or (Stage EQ 'CAN_PRE') or (Stage EQ 'CAN_PST') ) - Query := " dd.F_NAME = '":IQSToolID:"' AND (" - Case Otherwise$ - Query := " dd.F_NAME = '":Scribe:"' AND (" - End Case - - NumMetNames = DCount(MetNames, @VM) - For each MetName in MetNames using @VM setting vPos - If vPos EQ NumMetNames then - Query := "td.F_NAME = '":MetName:"') " - end else - Query := "td.F_NAME = '":MetName:"' or " - end - Next MetName - - If ( (Stage NE 'GROWTH') and (Stage NE 'TEMP') ) then - Query := "AND dd.F_NAME IS NOT NULL " - end - Query := "ORDER BY td.F_NAME" - - If Query NE '' then Response = SQL_Services('PostSQLRequest', 'IQSDMS1', Query) - - Convert @FM to @VM in Response - Convert @RM to @FM in Response - ParamValues = '' - - For each MetName in MetNames using @VM setting mPos - - For each Row in Response using @FM setting fPos - Locate MetName in Row using @VM setting vPos then - DataPointIndex = Response - If ( (Index(Row, @SVM, 1) GT 0) and (DataPointIndex EQ 0) ) else - // Data point at index 0 for parameters with multiple data points is an average. - // Ignore this data point. - WaferPos = Response - ParamValues = Response - end - end - Next Row - - Next MetName - - ChangeDetected = False$ - - If ( (Stage EQ 'UV') or (Stage EQ 'UV_PRE') or (Stage EQ 'UV_PST') or (Stage EQ 'WARP') or (Stage EQ 'CAN') or (Stage EQ 'CAN_PRE') or (Stage EQ 'CAN_PST') or (Stage EQ 'GROWTH') or (Stage EQ 'TEMP') ) then - - For each WfrID in InWfrIDs using @VM setting WaferPos - ValueSet = ParamValues - Delimiter = @VM - Convert '*' to '.' in WfrID - RunStageWfrKey = RDSNo:'*':Stage:'*':WfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - RunStageWfrRec = ValueSet - OutOfSpecArray = '' - For each Parameter in MetNames using @VM setting vPos - Value = ValueSet<0, vPos> - LSL = LSLs<0, vPos> - USL = USLs<0, vPos> - Target = Targets<0, vPos> - MaxDecimals = GaN_Services('GetMaxDecimals', LSL:@VM:USL:@VM:Target) - If Value NE '' then - Value = SRP_Math('ROUND', Value, MaxDecimals) - // Ensures decimal places are retained and zeros are padded. - Value = Oconv(Iconv(Value, 'MD':MaxDecimals:'L'), 'MD':MaxDecimals:'L') - end - ValueSet<0,vPos> = Value - - // One value per parameter - Begin Case - Case (LSL NE '') and (Value NE '') - OutOfSpecArray<0, vPos> = (Value LT LSL) - Case (LSL NE '') and (Value EQ '') - OutOfSpecArray<0, vPos> = -1 ; // -1 = data value is missing - ErrorMsg = 'Error retrieving metrology data from SPC for RDS ':RDSNo:'.' - Case Otherwise$ - OutOfSpecArray<0, vPos> = False$ - End Case - - // Need to check if we have already failed - If (OutOfSpecArray<0, vPos> NE True$) then - Begin Case - Case (USL NE '') and (Value NE '') - OutOfSpecArray<0, vPos> = (Value GT USL) - Case (USL NE '') and (Value EQ '') - OutOfSpecArray<0, vPos> = -1 ; // -1 = data value is missing - ErrorMsg = 'Error retrieving metrology data from SPC for RDS ':RDSNo:'.' - Case Otherwise$ - OutOfSpecArray<0, vPos> = False$ - End Case - end - - Next Parameter - - RunStageWfrRec = ValueSet - RunStageWfrRec = OutOfSpecArray - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$) - - Next WfrID - - end else - - Delimiter = @VM - PostSplit = '' - WaferCharacterized = '' - Locate Stage in GaNMetStages using @FM setting fPos then - If fPos LT 4 then - PostSplit = False$ - end else - PostSplit = True$ - end - end - - Locate WfrID in InWfrIDs using @VM setting WaferPos then - WaferCharacterized = CharFlags<0, WaferPos> - end - Convert '*' to '.' in WfrID - RunStageWfrKey = RDSNo:'*':Stage:'*':WfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey) - RunStageWfrRec = ParamValues - OutOfSpecArray = '' - For each Parameter in MetNames using @VM setting vPos - Value = ParamValues<0, vPos> - LSL = LSLs<0, vPos> - USL = USLs<0, vPos> - Target = Targets<0, vPos> - MaxDecimals = GaN_Services('GetMaxDecimals', LSL:@VM:USL:@VM:Target) - If Index(Value, @SVM, 1) GT 0 then - // Multiple values per parameter - RoundedValues = '' - For each SubValue in Value using @SVM setting svPos - Begin Case - Case (LSL NE '') and (SubValue NE '') - OutOfSpecArray<0, vPos, svPos> = (SubValue LT LSL) - Case (LSL NE '') and (Subvalue EQ '') - OutOfSpecArray<0, vPos, svPos> = -1 ; // -1 = data value is missing - ErrorMsg = 'Error retrieving metrology data from SPC for RDS ':RDSNo:'.' - Case Otherwise$ - OutOfSpecArray<0, vPos, svPos> = False$ - End Case - - // Need to check if we have already failed - If (OutOfSpecArray<0, vPos, svPos> NE True$) then - Begin Case - Case (USL NE '') and (SubValue NE '') - OutOfSpecArray<0, vPos, svPos> = (SubValue GT USL) - Case (USL NE '') and (Subvalue EQ '') - OutOfSpecArray<0, vPos, svPos> = -1 ; // -1 = data value is missing - ErrorMsg = 'Error retrieving metrology data from SPC for RDS ':RDSNo:'.' - Case Otherwise$ - OutOfSpecArray<0, vPos, svPos> = False$ - End Case - end - - Next SubValue - - end else - // One value per parameter - If Value NE '' then - Value = SRP_Math('ROUND', Value, MaxDecimals) - // Ensures decimal places are retained and zeros are padded. - Value = Oconv(Iconv(Value, 'MD':MaxDecimals:'L'), 'MD':MaxDecimals:'L') - end - - Begin Case - Case (LSL NE '') and (Value NE '') - OutOfSpecArray<0, vPos> = (Value LT LSL) - Case (LSL NE '') and (Value EQ '') - OutOfSpecArray<0, vPos> = -1 ; // -1 = data value is missing - ErrorMsg = 'Error retrieving metrology data from SPC for RDS ':RDSNo:'.' - Case Otherwise$ - OutOfSpecArray<0, vPos> = False$ - End Case - - // Need to check if we have already failed - If (OutOfSpecArray<0, vPos> NE True$) then - Begin Case - Case (USL NE '') and (Value NE '') - OutOfSpecArray<0, vPos> = (Value GT USL) - Case (USL NE '') and (Value EQ '') - OutOfSpecArray<0, vPos> = -1 ; // -1 = data value is missing - ErrorMsg = 'Error retrieving metrology data from SPC for RDS ':RDSNo:'.' - Case Otherwise$ - OutOfSpecArray<0, vPos> = False$ - End Case - end - end - - Next Parameter - RunStageWfrRec = ParamValues - RunStageWfrRec = OutOfSpecArray - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$) - end - If OrigReactRunRec NE ReactRunRec then - Database_Services('WriteDataRow', 'REACT_RUN', RDSNo, ReactRunRec, True$, False$, True$) - end - If Stage EQ 'WARP' then GaN_Services('CheckForCriticalFailures', RDSNo, Tool) - end - end - If ErrorMsg NE '' then Error_Services('Add', ErrorMsg) - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// CheckForCriticalFailures -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service CheckForCriticalFailures(RDSNo, Tool) - - If RDSNo NE '' then - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - OrigReactRunRec = ReactRunRec - InWfrIDs = ReactRunRec - PSNo = Xlate('REACT_RUN', RDSNo, 'PS_NO', 'X') - TechType = Xlate('PROD_SPEC', PSNo, 'TECH_TYPE', 'X') - GaNMetStages = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_MET_STAGES') - RunNo = ReactRunRec - Reactor = 'R':ReactRunRec - PartNo = Xlate('REACT_RUN', RDSNo, 'EPI_PART_NO', 'X') - IQSToolID = Xlate('TOOL', Tool, 'IQS_ID', 'X') - - Query = "SELECT td.F_NAME, se.F_TSNO, SE.F_SBNO, se.F_VAL " - Query := "FROM [IRMNSPC].[dbo].[SGRP_EXT] se " - Query := "JOIN [IRMNSPC].[dbo].[PART_LOT] pl on se.F_LOT = pl.F_LOT " - Query := "JOIN [IRMNSPC].[dbo].[TEST_DAT] td on se.F_TEST = td.F_TEST " - Query := "JOIN [IRMNSPC].[dbo].[PART_DAT] pd on se.F_PART = pd.F_PART " - Query := "JOIN [IRMNSPC].[dbo].[PRCS_DAT] pr on se.F_PRCS = pr.F_PRCS " - Query := "JOIN [IRMNSPC].[dbo].[SGRP_DSC] sd on se.F_SGRP = sd.F_SGRP " - Query := "LEFT JOIN [IRMNSPC].[dbo].[DESC_DAT] dd on sd.F_DESC = dd.F_DESC " - Query := "WHERE pd.F_NAME = '":PartNo:"' AND " - Query := " pr.F_NAME = '":Reactor:"' AND " - Query := " pl.F_NAME = '":RunNo:"' AND " - Query := " se.F_FLAG = 0 AND " - Query := " (" - - MetNames = 'Bow':@VM:'Warp' - NumMetNames = DCount(MetNames, @VM) - For each MetName in MetNames using @VM setting vPos - If vPos EQ NumMetNames then - Query := "td.F_NAME = '":MetName:"') AND " - end else - Query := "td.F_NAME = '":MetName:"' or " - end - Next MetName - - Query := "dd.F_NAME IS NOT NULL " - Query := "ORDER BY td.F_NAME" - - If Query NE '' then Response = SQL_Services('PostSQLRequest', 'IQSDMS1', Query) - - If ( (Response NE '') and (Response NE 0) ) then - Convert @FM to @VM in Response - Convert @RM to @FM in Response - ParamValues = '' - - For each MetName in MetNames using @VM setting mPos - For each Row in Response using @FM setting fPos - Locate MetName in Row using @VM setting vPos then - DataPointIndex = Response - If ( (Index(Row, @SVM, 1) GT 0) and (DataPointIndex EQ 0) ) else - // Data point at index 0 for parameters with multiple data points is an average. - // Ignore this data point. - WaferPos = Response - ParamValues = Response - end - end - - Next Row - Next MetName - - For each WfrID in InWfrIDs using @VM setting WaferPos - - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WfrID) - OrigCritFailure = WOWfrRec - CriticalFailure = False$ - ValueSet = ParamValues - Delimiter = @VM - OutOfSpecArray = '' - For each Parameter in MetNames using @VM setting vPos - Value = ValueSet<0, vPos> - // Check critical parameters - If Parameter EQ 'Bow' then - CriticalMin = Xlate('PROD_SPEC', PSNo, 'CRITICAL_BOW_MIN', 'X') - CriticalMax = Xlate('PROD_SPEC', PSNo, 'CRITICAL_BOW_MAX', 'X') - If ( (CriticalMin NE '') and (CriticalMax NE '') ) then - If Value LT CriticalMin or Value GT CriticalMax then CriticalFailure = True$ - end - end - - If Parameter EQ 'Warp' then - CriticalMax = Xlate('PROD_SPEC', PSNo, 'CRITICAL_WARP_MAX', 'X') - If CriticalMax NE '' then - If Value GT CriticalMax then CriticalFailure = True$ - end - end - - Next Parameter - - Begin Case - Case ( (CriticalFailure EQ True$) and (OrigCritFailure NE True$) ) - GaN_Services('AbortWafer', WfrID) - Case ( (CriticalFailure EQ False$) and (OrigCritFailure EQ True$) ) - GaN_Services('RestoreWafer', WfrID) - Case Otherwise$ - Null - End Case - - Next WfrID - end - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// ConsumeInboundMaterial -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service ConsumeInboundMaterial(InWfrIDs) - - If InWfrIDs NE ''then - For each InWfrID in InWfrIDs using @VM - // Mark inbound material consumed (i.e. move WfrID to PrevWfrID within WO_MAT_WFR record) - WONo = Field(InWfrID, '*', 1, 1) - InboundCass = Field(InWfrID, '*', 2, 1) - SlotNo = Field(InWfrID, '*', 3, 1) - WOMatWfrKey = WONo:'*':InboundCass - WOMatWfrRec = Database_Services('ReadDataRow', 'WO_MAT_WFR', WOMatWfrKey) - ReadyQ = WOMatWfrRec - ConsumedQ = WOMatWfrRec - ReadyQ<0, SlotNo> = '' - ConsumedQ<0, SlotNo> = InWfrID - WOMatWfrRec = ReadyQ - WOMatWfrRec = ConsumedQ - Database_Services('WriteDataRow', 'WO_MAT_WFR', WOMatWfrKey, WOMatWfrRec, True$, False$, True$) - Next InWfrID - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetInvActions -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetInvActions(StageID) - - If StageID NE '' then - GaNStageInfo = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_STAGES') - GaNStageInfo = SRP_Array('Rotate', GaNStageInfo, @FM, @VM) - StageIDs = GaNStageInfo<1> - InvActions = GaNStageInfo<7> - Locate StageID in StageIDs using @VM setting vPos then - Response = InvActions<0, vPos> - Convert @SVM to @VM in Response - end - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetSigReq -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetSigReq(StageID) - - If StageID NE '' then - GaNStageInfo = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_STAGES') - GaNStageInfo = SRP_Array('Rotate', GaNStageInfo, @FM, @VM) - StageIDs = GaNStageInfo<1> - SigReqs = GaNStageInfo<8> - Locate StageID in StageIDs using @VM setting vPos then - Response = SigReqs<0, vPos> - end - end - If Response EQ '' then Response = False$ - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetReqStages -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetReqStages() - - Response = '' - GaNStageInfo = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_STAGES') - GaNStageInfo = SRP_Array('Rotate', GaNStageInfo, @FM, @VM) - StageIDs = GaNStageInfo<1> - StageReq = GaNStageInfo<9> - For each StageID in StageIDs using @VM setting vPos - If StageReq<0, vPos> EQ True$ then Response<0, -1> = StageID - Next StageID - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// AddStageToPSN -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service AddStageToPSN(PSNo, StageID) - - Response = False$ - If ( (PSNo NE '') and (StageID NE '') ) then - PSRec = Database_Services('ReadDataRow', 'PROD_SPEC', PSNo) - PRSStageKeys = PSRec - PRSStageKeysPrime = SRP_Array('Rotate', PRSStageKeys, @VM, '*') - PRSStages = PRSStageKeysPrime<0, 2> - Locate StageID in PRSStages using @VM setting vPos else - // Stage not yet in the PSN, so add it now - ToolClasses = GaN_Services('GetToolClassIDs', StageID) - InvActions = GaN_Services('GetInvActions', StageID) - SigReq = GaN_Services('GetSigReq', StageID) - PRSStageKey = PSNo:'*':StageID - PRSStageRec = '' - PRSStageRec = ToolClasses - If InvActions NE '' then - PRSStageRec = InvActions - If SigReq EQ True$ then - For each InvAction in InvActions using @VM setting vPos - PRSStageRec = True$ - Next InvAction - end - end - Database_Services('WriteDataRow', 'PRS_STAGE', PRSStageKey, PRSStageRec, True$, False$, True$) - If Error_Services('NoError') then Response = True$ - end - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// RemoveStageFromPSN -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service RemoveStageFromPSN(PSNo, StageID) - - Response = False$ - If ( (PSNo NE '') and (StageID NE '') ) then - PRSStageKey = PSNo:'*':StageID - If RowExists('PRS_STAGE', PRSStageKey) then - Database_Services('DeleteDataRow', 'PRS_STAGE', PRSStageKey, True$, False$) - If Error_Services('NoError') then Response = True$ - end - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// UpdateRetainedWafers -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service UpdateRetainedWafers() - - hSysLists = Database_Services('GetTableHandle', 'SYSLISTS') - Lock hSysLists, ServiceKeyID then - UpdateFlag = Database_Services('ReadDataRow', 'APP_INFO', 'UPDATE_RETAINED_WAFERS_FLAG') - If UpdateFlag EQ True$ then - // Clear update flag - UpdateFlag = False$ - Database_Services('WriteDataRow', 'APP_INFO', 'UPDATE_RETAINED_WAFERS_FLAG', UpdateFlag, True$, False$, True$) - // Update wafer lists - hDict = Database_Services('GetTableHandle', 'DICT.RETAINED_WAFERS') - If Error_Services('NoError') then - Database_Services('WriteDataRow', 'APP_INFO', 'UPDATE_RETAINED_WAFERS_FLAG', False$, True$, False$, True$) - WaferSizes = '150 mm 6 in' : @VM : '200 mm 8 in' - WaferListKeys = 'RETAINED_WAFERS_6IN' : @VM : 'RETAINED_WAFERS_8IN' - // Update 6 and 8 inch wafer lists - For each WaferSize in WaferSizes using @VM setting SizePos - WaferListKey = WaferListKeys<0, SizePos> - HaveLock = Database_Services('GetKeyIDLock', 'APP_INFO', WaferListKey, True$) - If HaveLock EQ True$ then - // OK to update - WaferList = '' - Query = 'WAFER_SIZE' : @VM : WaferSize : @FM - KeyList = '' - Option = '' - Flag = '' - Btree.Extract(Query, 'RETAINED_WAFERS', hDict, KeyList, Option, Flag) - NumKeys = DCount(KeyList, @VM) - If Get_Status(ErrCode) else - For each WfrID in keylist using @VM setting RowIndex - WfrRec = Database_Services('ReadDataRow', 'RETAINED_WAFERS', WfrID) - WaferList = WfrRec - WaferList = WfrRec - WaferList = WfrRec - WaferList = WfrRec - WaferList = WfrRec - WaferList = WfrRec - WaferList = Field(WfrID, '*', 1) - WaferList = WfrRec - WaferList = WfrRec - WaferList = WfrRec - WaferList = WfrRec - WaferList = WfrRec - WaferList = WfrRec - WaferList = WfrRec - WaferList = WfrRec - WaferList = WfrRec - WaferList = WfrID - Next WfrID - end - Database_Services('WriteDataRow', 'APP_INFO', WaferListKey, WaferList, True$, False$, True$) - Database_Services('ReleaseKeyIDLock', 'APP_INFO', WaferListKey) - end - Next WaferSize - end - end - Unlock hSysLists, ServiceKeyID else Null - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// UpdateRetainedWaferDetails -// -// Input: -// WaferID - [Required] -// Location - [Optional] -// Status - [Optional] -// Comments - [Optional] -// -// Output: -// Response - True$ (1) if successful, False$ (0) otherwise -// -//---------------------------------------------------------------------------------------------------------------------- -Service UpdateRetainedWaferDetails(InboundWfrID, Location, Status, Comments) - - Response = False$ - If InboundWfrID NE '' then - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', InboundWfrID) - If Error_Services('NoError') then - WOWfrRec = Location - WOWfrRec = Status - WOWfrRec = Comments - Database_Services('WriteDataRow', 'WO_WFR', InboundWfrID, WOWfrRec, True$, False$, True$) - If Error_Services('NoError') then Response = True$ - end - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetCurrPartParams -// -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetCurrPartParams(PartNo) - - Stages = Database_Services('ReadDataRow', 'APP_INFO', 'GAN_IQS_STAGES') - - ParameterList = '' - - Query = "SELECT pr.Process_Name, pr.IQS_Name, pp.Parameter " - Query := "FROM [ControlPlans].[dbo].[Part_Parameter] pp " - Query := "JOIN [ControlPlans].[dbo].[Parameter] pr on pp.Parameter = pr.Parameter " - Query := "WHERE pp.Part = '":PartNo:"' AND (" - For each Stage in Stages using @VM - Query := "pr.Process_Name = '":Stage:"' OR " - Next Stage - Query[-1, -4] = "" - Query := ") ORDER BY pr.Process_Name, pr.IQS_Name" - - Response = SQL_Services('PostSQLRequest', 'IQSDMS1', Query) - RowCount = 0 - - If Response NE 0 then - For each Row in Response using @RM setting RowPos - RowCount += 1 - ProcName = Row<1> - MetName = Row<2> - ParamName = Row<3> - Locate ProcName in Stages using @VM setting fPos then - vPos = DCount(ParameterList, @VM) - vPos += 1 - ParameterList = MetName - ParameterList = ParamName - end - Next Row - end - -* Response = ParameterList - // Copy UV to UV_PST - ParameterList<7> = ParameterList<3> - UVData = ParameterList<7> - For each Row in UVData using @VM setting vPos - MetName = ParameterList<7, vPos, 1> - MetName = MetName:' Post' - ParameterList<7, vPos, 1> = MetName - Next Row - // Copy CAN to CAN_PST - ParameterList<8> = ParameterList<6> - CANData = ParameterList<8> - For each Row in CANData using @VM setting vPos - MetName = ParameterList<8, vPos, 1> - MetName = MetName:' Post' - ParameterList<8, vPos, 1> = MetName - Next Row - -* // Get GROWTH parameters -* Query = 'SELECT DISTINCT pr.Process_Name, pr.IQS_Name, pp.Parameter ' -* Query := 'From [ControlPlans].[dbo].[Part_Parameter] pp ' -* Query := 'JOIN [ControlPlans].[dbo].[Parameter] pr on pp.Parameter = pr.Parameter ' -* Query := "WHERE pr.Process_Name = 'Epi' AND pp.Part = '":PartNo:"'" -* Query := 'ORDER BY pr.IQS_Name' -* Response = SQL_Services('PostSQLRequest', 'IQSDMS1', Query) -* -* If Response NE 0 then -* For each Row in Response using @RM setting RowPos -* RowCount += 1 -* ProcName = Row<1> -* MetName = Row<2> -* ParamName = Row<3> -* Locate ProcName in Stages using @VM setting fPos then -* vPos = DCount(ParameterList, @VM) -* vPos += 1 -* ParameterList = MetName -* ParameterList = ParamName -* end -* Next Row -* end -* -* // Get TEMP parameters -* Query = 'SELECT DISTINCT pr.Process_Name, pr.IQS_Name, pp.Parameter ' -* Query := 'From [ControlPlans].[dbo].[Part_Parameter] pp ' -* Query := 'JOIN [ControlPlans].[dbo].[Parameter] pr on pp.Parameter = pr.Parameter ' -* Query := "WHERE pr.Process_Name = 'Temperature' " -* Query := 'ORDER BY pr.IQS_Name' -* Response = SQL_Services('PostSQLRequest', 'IQSDMS1', Query) -* If Response NE 0 then -* For each Row in Response using @RM setting RowPos -* RowCount += 1 -* ProcName = Row<1> -* MetName = Row<2> -* ParamName = Row<3> -* Locate ProcName in Stages using @VM setting fPos then -* vPos = DCount(ParameterList, @VM) -* vPos += 1 -* ParameterList = MetName -* ParameterList = ParamName -* end -* Next Row -* end - Response = ParameterList - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetCurrLimits -// -// Input - PartNo -// Output - LSL, Target, and USL from the Control Plan SQL DB. -//---------------------------------------------------------------------------------------------------------------------- -Service GetCurrLimits(PartNo) - - Query = "SELECT [Parameter] " | - : ",[LSL] " | - : ",[Target] " | - : ",[USL] " | - : "FROM [ControlPlans].[dbo].[Part_Parameter] " | - : "WHERE [Part] = '":PartNo:"' " | - : "ORDER BY [Parameter]" - Response = SQL_Services('PostSQLRequest', 'IQSDMS1', Query) - Convert @FM to @VM in Response - Convert @RM to @FM in Response - - Response = SRP_Array('Rotate', Response, @FM, @VM) - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetMaxDecimals -// -// Input - @VM delimited array of values containing decimals -// Output - Maximum number of decimal places found between all values in the array. -//---------------------------------------------------------------------------------------------------------------------- -Service GetMaxDecimals(Array) - - MaxDecimals = 0 - If Array NE '' then - For each Value in Array using @VM - DecimalFound = Index(Value, '.', 1) - If DecimalFound then - NumDecimalPlaces = Len(Value[-1, 'B.']) - If NumDecimalPlaces GT MaxDecimals then MaxDecimals = NumDecimalPlaces - end - Next Value - end - Response = MaxDecimals - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// ClearRetainInfo -// -// Input: -// InboundWfrID - [Required] -// -// Output: -// Response - True$ (1) if successful, False$ (0) otherwise. -// -//---------------------------------------------------------------------------------------------------------------------- -Service ClearRetainInfo(InboundWfrID) - - Response = False$ - If InboundWfrID NE '' then - // InboundWfrID may have been passed in with '.' instead of '*' - Convert '.' to '*' in InboundWfrID - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', InboundWfrID) - If Error_Services('NoError') then - RetainBox = WOWfrRec - RetainSlot = WOWfrRec - If ( (RetainBox NE '') and (RetainSlot NE '') ) then - WOWfrRec = '' - WOWfrRec = '' - Database_Services('WriteDataRow', 'WO_WFR', InboundWfrID, WOWfrRec, True$, False$, True$) - If Error_Services('NoError') then - RDSNo = Xlate('WO_WFR', InboundWfrID, 'RDS_NO', 'X') - If RDSNo NE '' then - RetainStageKey = RDSNo:'*RETAIN*':InboundWfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RetainStageKey) - RunStageWfrRec = '' - RunStageWfrRec = '' - RunStageWfrRec = 'INIT' - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RetainKey, RunStageWfrRec, True$, False$, True$) - // Move wafer into the DISP queue, if it isn't already there - CurrQ = GaN_Services('GetWfrQueue', InboundWfrID) - DispQ = GaN_Services('GetLocQueueID', 'DISP') - If CurrQ NE DispQ then - Gan_Services('RemoveWfrFromWIP', WfrID) - GaN_Services('MoveWfrToQueue', InboundWfrID, DispQ) - end - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - InWfrIDs = ReactRunRec - Locate InboundWfrID in InWfrIDs using @VM setting vPos then - ReactRunRec = False$ - Database_Services('WriteDataRow', 'REACT_RUN', RDSNo, ReactRunRec, True$, False$, True$) - end - Response = True$ - end - end - end - end - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// RetainWafer -// -// Input: -// WaferID - [Required] -// -// Output: -// Response - True$ (1) if successful, False$ (0) otherwise -// -//---------------------------------------------------------------------------------------------------------------------- -Service RetainWafer(InboundWfrID) - - Response = False$ - If InboundWfrID NE '' then - WfrSize = Xlate('WO_WFR', InboundWfrID, 'WFR_SIZE', 'X') - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', InboundWfrID) - If Error_Services('NoError') then - OrigRetainBox = WOWfrRec - OrigRetainSlot = WOWfrRec - If ( (OrigRetainBox EQ '') and (OrigRetainSlot EQ '') ) then - // Wafer not yet retained, so proceed - RetainKey = Gan_Services('GetNextRetainKey', WfrSize) - If RetainKey NE '' then - RetainBox = RetainKey<1> - RetainSlot = RetainKey<2> - WOWfrRec = RetainBox - WOWfrRec = RetainSlot - Database_Services('WriteDataRow', 'WO_WFR', InboundWfrID, WOWfrRec, True$, False$, True$) - If Error_Services('NoError') then - // Move wafer to RETAIN queue - // Move wafer into the RETAIN queue, if it isn't already there - CurrQ = GaN_Services('GetWfrQueue', InboundWfrID) - RetainQ = GaN_Services('GetLocQueueID', 'RETAIN') - If CurrQ NE RetainQ then - GaN_Services('RemoveWfrFromWIP', WfrID) - GaN_Services('MoveWfrToQueue', InboundWfrID, RetainQ) - end - If Error_Services('NoError') then - RDSNo = Xlate('WO_WFR', InboundWfrID, 'RDS_NO', 'X') - If RDSNo NE '' then - Convert '*' to '.' in InboundWfrID - RetainStageKey = RDSNo:'*RETAIN*':InboundWfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RetainStageKey) - StageStatus = RunStageWfrRec - If StageStatus NE 'COMP' then - RunStageWfrRec = 'AUTO' - RunStageWfrRec = Datetime() - RunStageWfrRec = 'COMP' - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RetainStageKey, RunStageWfrRec, True$, False$, True$) - end - DispStageKey = RDSNo:'*DISP*':InboundWfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', DispStageKey) - StageStatus = RunStageWfrRec - If StageStatus NE 'COMP' then - RunStageWfrRec = 'AUTO' - RunStageWfrRec = Datetime() - RunStageWfrRec = 'COMP' - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', DispStageKey, RunStageWfrRec, True$, False$, True$) - end - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - InWfrIDs = ReactRunRec - Convert '.' to '*' in InboundWfrID - Locate InboundWfrID in InWfrIDs using @VM setting vPos then - // This flag indicates the wafer is a retained wafer. - // This write to the REACT_RUN record will also trigger an MFS to copy the - // recipe and part number to the RETAINED_WAFERS record. - ReactRunRec = True$ - Database_Services('WriteDataRow', 'REACT_RUN', RDSNo, ReactRunRec, True$, False$, True$) - end - end - If Error_Services('NoError') then Response = True$ - end - end - end else - Error_Services('Add', 'Error retrieving retain key in the ':Service:' service.') - end - end - end - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// SignRetainedWafer -// -// Input: -// WaferID - [Required] -// -// Output: -// Response - True$ (1) if successful, False$ (0) otherwise -// -//---------------------------------------------------------------------------------------------------------------------- -Service SignRetainedWafer(InboundWfrID) - - Response = False$ - If InboundWfrID NE '' then - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', InboundWfrID) - If Error_Services('NoError') then - WOWfrRec = @User4 - WOWfrRec = Date() - WOWfrRec = 'Cleanroom' - Database_Services('WriteDataRow', 'WO_WFR', InboundWfrID, WOWfrRec, True$, False$, True$) - If Error_Services('NoError') then - Disposition_Services('AutoDispositionWfr', InboundWfrID) - If Error_Services('NoError') then Response = True$ - end - end - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// SignDestroyedWafer -// -// Input: -// WaferID - [Required] -// -// Output: -// Response - True$ (1) if successful, False$ (0) otherwise -// -//---------------------------------------------------------------------------------------------------------------------- -Service SignDestroyedWafer(InboundWfrID) - - Response = False$ - If InboundWfrID NE '' then - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', InboundWfrID) - If Error_Services('NoError') then - WOWfrRec = @User4 - WOWfrRec = Date() - WOWfrRec = 'Wafer Destroyed' - Database_Services('WriteDataRow', 'WO_WFR', InboundWfrID, WOWfrRec, True$, False$, True$) - If Error_Services('NoError') then Response = True$ - end - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetNextRetainKey -// -// Input: -// WfrSize - [Required] -// -// Output: -// Response - Next retain key for that wafer size. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetNextRetainKey(WfrSize) - - Response = '' - If WfrSize NE '' then - Begin Case - Case WfrSize EQ '150 mm 6 in' - RetainKeyID = 'RETAIN_KEY_6IN' - Case WfrSize EQ '200 mm 8 in' - RetainKeyID = 'RETAIN_KEY_8IN' - Case Otherwise$ - Error_Services('Add', 'Null or incompatible wafer size in ':Service:' service.') - End Case - If Error_Services('NoError') then - CurrRetainKey = Database_Services('ReadDataRow', 'APP_INFO', RetainKeyID) - CurrRetainBox = CurrRetainKey<1> - CurrRetainSlot = CurrRetainKey<2> - // Update Retain Key (i.e. Box and Slot) - NewRetainBox = CurrRetainBox - If CurrRetainSlot GT 1 then - NewRetainSlot = CurrRetainSlot - 1 - end else - NewRetainSlot = 25 - NewBoxIndex = CurrRetainBox[6, 3] - NewBoxIndex += 1 - NewBoxIndex = Fmt(NewBoxIndex,"R(0)#3") - NewRetainBox[6, 3] = NewBoxIndex - end - NewRetainKey = '' - NewRetainKey<1> = NewRetainBox - NewRetainKey<2> = NewRetainSlot - Database_Services('WriteDataRow', 'APP_INFO', RetainKeyID, NewRetainKey, True$, False$, True$) - If Error_Services('NoError') then Response = CurrRetainKey - end - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetAvailableTools -// -// Input: -// StageID - [Required] -// -// Output: -// Response - All tools for a given stage that are currently running in PROD mode. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetAvailableTools(StageID) - - Response = '' - If StageID NE '' then - ToolClassIDs = GaN_Services('GetToolClassIDs', StageID) - TempArray = '' - For each ToolClassID in ToolClassIDs using @SVM setting svPos - ToolIDs = Xlate('TOOL_CLASS', ToolClassID, 'TOOL', 'X') - ProdTools = '' - For each ToolID in ToolIDs using @VM setting vPos - CurrMode = Xlate('TOOL', ToolID, 'CURR_MODE', 'X') - If CurrMode EQ 'PROD' then ProdTools<0, -1> = ToolID - Next ToolID - TempArray = SRP_Array('Join', TempArray, ProdTools, 'OR', @VM) - Next ToolClassID - Response = TempArray - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// GetWaferStatusList -// -// Input: -// RDSNo - [Required] -// -// Output: -// Response - A list of wafers in a given RDS and their current status. -// -//---------------------------------------------------------------------------------------------------------------------- -Service GetWaferStatusList(RDSNo) - - Response = '' - If RDSNo NE '' then - WfrStatusList = '' - InWfrIDs = Xlate('REACT_RUN', RDSNo, 'IN_WFR_ID', 'X') - For each WfrID in InWfrIDs using @VM setting WfrIndex - WfrStatusList = WfrID - WfrStatusList = Xlate('WO_WFR', WfrID, 'STATUS', 'X') - Next WfrID - Response = WfrStatusList - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// AbortWafer -// -// Input: -// WfrID - [Required] -// -// Output: -// Response - True$ (1) if successful, False$ (0) otherwise. -// -//---------------------------------------------------------------------------------------------------------------------- -Service AbortWafer(WfrID) - - Response = False$ - If WfrID NE '' then - // WfrID may have been passed in with . instead of * - Convert '.' to '*' in WfrID - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WfrID) - RDSNo = Xlate('WO_WFR', WfrID, 'RDS_NO', 'X') - WfrStages = Xlate('REACT_RUN', RDSNo, 'WFR_STAGE', 'X') - Locate 'WARP' in WfrStages using @VM setting StageIndex then - // Skip all remaining stages, mark wafer as dispositioned at the SPLIT stage - Loop - StageIndex += 1 - StageID = WfrStages<0, StageIndex> - Until StageID EQ 'SPLIT' - GaN_Services('SkipWaferStage', RDSNo, WfrID, StageID) - Repeat - GaN_Services('DispositionWfr', RDSNo, WfrID, True$) - end - // Set critical failure flag (AutoDisposition will set the grades based on this flag) - WOWfrRec = True$ - Database_Services('WriteDataRow', 'WO_WFR', WfrID, WOWfrRec, True$, False$, True$) - If Error_Services('NoError') then Response = True$ - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// RestoreWafer -// -// Input: -// WfrID - [Required] -// -// Output: -// Response - True$ (1) if successful, False$ (0) otherwise. -// -//---------------------------------------------------------------------------------------------------------------------- -Service RestoreWafer(WfrID) - - Response = False$ - If WfrID NE '' then - // WfrID may have been passed in with . instead of * - Convert '.' to '*' in WfrID - RDSNo = Xlate('WO_WFR', WfrID, 'RDS_NO', 'X') - GaN_Services('WithdrawWfr', RDSNo, WfrID) - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WfrID) - WfrStages = Xlate('REACT_RUN', RDSNo, 'WFR_STAGE', 'X') - Convert '*' to '.' in WfrID - For each StageID in WfrStages using @VM setting StageIndex - Until StageID EQ 'SPLIT' - RunStageWfrKey = RDSNo:'*':StageID:'*':WfrID - StageStatus = Xlate('RUN_STAGE_WFR', RunStageWfrKey, 'STATUS', 'X') - If StageStatus EQ 'SKIP' then GaN_Services('UnskipWaferStage', RDSNo, WfrID, StageID) - Next StageID - Convert '.' to '*' in WfrID - // Set critical failure flag (AutoDisposition will set the grades based on this flag) - WOWfrRec = False$ - Database_Services('WriteDataRow', 'WO_WFR', WfrID, WOWfrRec, True$, False$, True$) - If Error_Services('NoError') then Response = True$ - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// PostDispositionRequest -// -// Input: -// RDSNo - [Required] -// -//---------------------------------------------------------------------------------------------------------------------- -Service PostDispositionRequest(RDSNo) - - Response = '' - If RDSNo NE '' then - RequestDate = Date() - RequestTime = Time() - RequestKeyID = RDSNo:'*':RequestDate :'*':RequestTime - RequestRow = '' - Database_Services('WriteDataRow', 'DISPOSITION_REQUESTS', RequestKeyID, RequestRow, False$, False$, False$) - If Error_Services('NoError') then - TimeExpired = False$ - Start = GetTickCount() - Loop - RequestRow = Database_Services('ReadDataRow', 'DISPOSITION_REQUESTS', RequestKeyID) - ResponseDate = RequestRow - Response = RequestRow - // Time will expire after 30 seconds. - If GetTickCount() - Start GE 30000 then TimeExpired = True$ - Until (ResponseDate NE '') OR TimeExpired - Sleepery(10) - WinYield() - Yield();Yield();Yield();Yield();Yield();Yield();Yield();Yield() - Repeat - If TimeExpired then - Error_Services('Add', 'Disposition request timed out in the ' : Service : ' service.') - end - Database_Services('DeleteDataRow', 'DISPOSITION_REQUESTS', RequestKeyID, True$) - end - end else - Error_Services('Add', 'Null parameter passed into service call. All parameters are required.') - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// ProcessDispositionRequests -// -//---------------------------------------------------------------------------------------------------------------------- -Service ProcessDispositionRequests() - - Tablename = 'DISPOSITION_REQUESTS' - hValidationRequests = Database_Services('GetTableHandle', Tablename) - If Error_Services('NoError') then - Sentence = 'SELECT ':Tablename:' WITH RESPONSE_DATE EQ "" BY REQUEST_DATE BY REQUEST_TIME' - Set_Status(0) - RList(Sentence, TARGET_ACTIVELIST$, '', '', '') - EOF = False$ - Loop - ReadNext RequestKeyID else EOF = True$ - Until EOF - Lock hValidationRequests, RequestKeyID then - RequestRow = Database_Services('ReadDataRow', 'DISPOSITION_REQUESTS', RequestKeyID) - RDSNo = Field(RequestKeyID, '*', 1) - GaN_Services('ProcessDispositionRequest', RDSNo) - If Error_Services('NoError') then - RequestRow = True$ - end else - RequestRow = Error_Services('GetMessage') - end - RequestRow = Date() - RequestRow = Time() - Database_Services('WriteDataRow', 'DISPOSITION_REQUESTS', RequestKeyID, RequestRow, True$, False$, True$) - Unlock hValidationRequests, RequestKeyID else - Error_Services('Add', 'Error unlocking ':RequestKeyID:', ':Tablename:' within ':Service) - end - end - Repeat - end else - ErrorMsg = Error_Services('GetMessage') - end - -end service - - -//---------------------------------------------------------------------------------------------------------------------- -// ProcessDispositionRequest -// -// Input: -// RDSNo - [Required] -// -//---------------------------------------------------------------------------------------------------------------------- -Service ProcessDispositionRequest(RDSNo) - - If RDSNo NE '' then - ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo) - If Error_Services('NoError') then - OrigReactRunRec = ReactRunRec - Reactor = ReactRunRec - Scribes = Xlate('REACT_RUN', RDSNo, 'WFR_SCRIBES', 'X') - NumWfrs = DCount(Scribes, @VM) - GanRunID = ReactRunRec - GaNRecipe = ReactRunRec - WfrIDs = ReactRunRec - CassDispComp = ReactRunRec - WONo = ReactRunRec - WaferTrackPart = Xlate('WO_LOG', WONo, 'WAFER_TRACK_PART', 'X') - If CassDispComp NE True$ then - ReportFound = False$ - // Search for GaN Disposition Report Excel Spreadsheet -------------------- - DispFilename = GanRunID:'_':WaferTrackPart:'_Disposition_Report.xlsm' - ReportPath = '\\messv02ecc1.ec.local\EC_Characterization_GaN\Disposition Reports\' - InitDir ReportPath:'\*.*' - RootFileList = DirList() - DispFilePath = ReportPath:'\':DispFilename - If Indexc(RootFileList, DispFileName, 1) then - ReportFound = True$ - end else - // Report not found in root "working" directory, so search the archives - ArchivePath = ReportPath:'\R':Reactor:' Reports\*.*' - InitDir ArchivePath - ArchiveFileList = DirList() - If Indexc(ArchiveFileList, DispFileName, 1) then - ReportFound = True$ - DispFilePath = ReportPath:'\R':Reactor:' Reports\':DispFilename - end else - // Disposition report not found. Set status line to inform user - Set_Property(@Window:'.STATUS_LINE', 'BACKCOLOR', YELLOW$) - Set_Property(@Window:'.STATUS_LINE', 'TEXT', 'Disposition report "':DispFileName:'" not found!') - end - end - If ReportFound EQ True$ then - Set_Property(@Window:'.STATUS_LINE', 'BACKCOLOR', GREEN$) - DispExcelHandle = Excel_Services('OpenDocument', DispFilePath) - DispWorksheet = 'Section E-Lot Summary Report' - ExcelScribes = '' - ExcelGrades = '' - ExcelShipFlags = '' - ExcelRetainFlags = '' - ExcelReasons = '' - ExcelNCRReqFlags = '' - For WfrIndex = 1 to NumWfrs - WfrID = WfrIDs<0, WfrIndex> - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WfrID) - FormattedWfrID = WfrID - Convert '*' to '.' in FormattedWfrID - CellRow = WfrIndex + 6 - ExcelScribe = Excel_Services('GetCellValue', DispExcelHandle, DispWorksheet, 'D', CellRow) - ExcelScribes<0, WfrIndex> = ExcelScribe - MetComp = Gan_Services('GetMetrologyStatus', WfrID) - DispComp = Gan_Services('GetDispStatus', WfrID) - - If ( (MetComp EQ True$) or (DispComp EQ True$) ) then - ExcelGrade = Excel_Services('GetCellValue', DispExcelHandle, DispWorksheet, 'O', CellRow) - ExcelReason = Excel_Services('GetCellValue', DispExcelHandle, DispWorksheet, 'P', CellRow) - ExcelRetainFlag = Excel_Services('GetCellValue', DispExcelHandle, DispWorksheet, 'R', CellRow) - ExcelGrades<0, WfrIndex> = ExcelGrade - ExcelShipFlag = (ExcelRetainFlag _EQC 'IFX-VIH') - ExcelShipFlags<0, WfrIndex> = ExcelShipFlag - ExcelRetainFlag = (ExcelRetainFlag _EQC 'Retained') - ExcelRetainFlags<0, WfrIndex> = ExcelRetainFlag - ExcelReasons<0, WfrIndex> = ExcelReason - ExcelNCRReqFlags<0, WfrIndex> = (ExcelReason _EQC 'Lot Aborted') or (ExcelReason _EQC 'Non-rotation') or (ExcelReason _EQC 'Broken') - WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WfrID) - RetainSlot = WOWfrRec - RetainBox = WOWfrRec - WOWfrGrade = WOWfrRec - If WOWfrGrade NE ExcelGrade then - WOWfrRec = ExcelGrade - Database_Services('WriteDataRow', 'WO_WFR', WfrID, WOWfrRec, True$, False$, True$) - end - OrigShipFlag = ReactRunRec - - If ( (ExcelRetainFlag EQ False$) and (RetainBox NE '') and (RetainSlot NE '') ) then - // Reset RETAIN stage back to INIT because the disposition report has been updated - GaN_Services('ClearRetainInfo', WfrID) - end - If ( (ExcelRetainFlag EQ True$ ) and (RetainBox EQ '') and (RetainSlot EQ '') ) then - GaN_Services('RetainWafer', WfrID) - end - - If ( (ExcelShipFlag EQ False$) and (OrigShipFlag EQ True$) ) then - // Reset G_PACK stage back to INIT because the disposition report has been updated - GPackKey = RDSNo:'*G_PACK*':FormattedWfrID - RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', GPackKey) - RunStageWfrRec = '' - RunStageWfrRec = '' - RunStageWfrRec = 'INIT' - Database_Services('WriteDataRow', 'RUN_STAGE_WFR', GPackKey, RunStageWfrRec, True$, False$, True$) - end - end - - Next WfrIndex - ReactRunRec = ExcelShipFlags - ReactRunRec = ExcelRetainFlags - ReactRunRec = ExcelNCRReqFlags - ReactRunRec = ExcelReasons - InternalFlags = ReactRunRec - ExternalFlags = ReactRunRec - For WfrIndex = 1 to NumWfrs - RetainFlag = ExcelRetainFlags<0, WfrIndex> - ShipFlag = ExcelShipFlags<0, WfrIndex> - If (RetainFlag EQ True$) or (ShipFlag EQ True$) then - InternalFlags<0, WfrIndex> = False$ - ExternalFlags<0, WfrIndex> = False$ - end - Next WfrIndex - ReactRunRec = InternalFlags - ReactRunRec = ExternalFlags - If OrigReactRunRec NE ReactRunRec then - Database_Services('WriteDataRow', 'REACT_RUN', RDSNo, ReactRunRec, True$, False$, True$) - end - Excel_Services('CloseDocument', DispExcelHandle) - end else - Error_Services('Add', 'Dispostion report not found!') - end - end else - Error_Services('Add', 'Cannot process disposition report due to run being closed.') - end - end - end else - Error_Services('Add', 'Null RDSNo passed into service ':Service:'.') - end - -end service - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Internal GoSubs -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -ClearCursors: - For counter = 0 to 8 - ClearSelect counter - Next counter -return -