open-insight/LSL2/STPROC/GAN_SERVICES_DEV.txt
2024-05-22 14:06:46 -07:00

6026 lines
291 KiB
Plaintext

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<WO_STEP_RDS_KEY$>
For each RDSKey in RDSKeys using @VM
ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSKey)
GaNRunID = ReactRunRec<REACT_RUN_GAN_RUN_ID$>
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<REACT_RUN_WFR_STAGE$>
SigProfileCnt = DCount(SigProfile, @VM)
NeedToWrite = False$
InWfrIDs = ReactRunRec<REACT_RUN_IN_WFR_ID$>
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<WO_MAT_RDS_NO$>
GRWfrQty = 0
ScrapQty = 0
ProdTWQty = 0
DummyQty = 0
EmptyQty = 0
ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo)
GaNRunID = ReactRunRec<REACT_RUN_GAN_RUN_ID$>
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<REACT_RUN_WFR_STAGE$>
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<REACT_RUN_IN_WFR_ID$>
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<RowIndex, 7> = 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<GAN_SCHEDULE_WAFER_TRACK_PART$>
GaNOIPart = GanSchedRec<GAN_SCHEDULE_OPENINSIGHT_PART$>
GaNRecipe = GanSchedRec<GAN_SCHEDULE_RECIPE$>
GaNWorkOrder = GanSchedRec<GAN_SCHEDULE_WORK_ORDER$>
If (GaNWTPart NE ExcelWTPart) or (GaNOIPart NE ExcelOIPart) or (GaNRecipe NE ExcelRecipe) or (GaNWorkOrder NE ExcelWorkOrder) then
// GaN Schedule updated, update OpenInsight
GanSchedRec<GAN_SCHEDULE_WAFER_TRACK_PART$> = ExcelWTPart
GanSchedRec<GAN_SCHEDULE_OPENINSIGHT_PART$> = ExcelOIPart
GaNSchedRec<GAN_SCHEDULE_RECIPE$> = ExcelRecipe
GaNSchedRec<GAN_SCHEDULE_WORK_ORDER$> = ExcelWorkOrder
Database_Services('WriteDataRow','GAN_SCHEDULE',GaNSchedKey,GanSchedRec,True$,False$,True$)
end
end else
// Row does not yet exist, so create it.
GanSchedRec<GAN_SCHEDULE_RECIPE$> = ExcelRecipe
GanSchedRec<GAN_SCHEDULE_WAFER_TRACK_PART$> = ExcelWTPart
GanSchedRec<GAN_SCHEDULE_OPENINSIGHT_PART$> = ExcelOIPart
GanSchedRec<GAN_SCHEDULE_WORK_ORDER$> = 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<REACT_RUN_IN_WFR_ID$>
ShipFlags = ReactRunRec<REACT_RUN_CARR_WFR_SHIP$>
RetainFlags = ReactRunRec<REACT_RUN_GAN_RET_WFR$>
InternalFlags = ReactRunRec<REACT_RUN_INTERNAL$>
ExternalFlags = ReactRunRec<REACT_RUN_EXTERNAL$>
CassDispComp = ReactRunRec<REACT_RUN_DISP_COMPLETE$>
WfrsDispReady = ReactRunRec<REACT_RUN_WFRS_DISP_READY$>
NCRReqFlags = ReactRunRec<REACT_RUN_NCR_REQ$>
CharFlags = ReactRunRec<REACT_RUN_IN_WFR_CHAR$>
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<WO_WFR_RDS_NCR_NO$>
NCRStatus = Xlate('NCR', NCRNo, 'STATUS', 'X')
CriticalFailFlag = WOWfrRec<WO_WFR_CRITICAL_FAILURE$>
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<REACT_RUN_WFRS_DISP_READY$> = WfrsDispReady
WOWfrRec<WO_WFR_STATUS$> = '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<REACT_RUN_CARR_WFR_SHIP$> = ShipFlags
ReactRunRec<REACT_RUN_GAN_RET_WFR$> = RetainFlags
ReactRunRec<REACT_RUN_INTERNAL$> = InternalFlags
ReactRunRec<REACT_RUN_EXTERNAL$> = 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<WO_WFR_STATUS$> = 'Ready to close'
Case ( (NCRNo NE '') and (NCRStatus NE 'C') )
WOWfrRec<WO_WFR_STATUS$> = 'NCR must be closed'
Case NCRNo EQ ''
WOWfrRec<WO_WFR_STATUS$> = 'Wafer requires an NCR'
End Case
DispReady = ( (NCRNo NE '') and (NCRStatus EQ 'C') )
WfrsDispReady<0, WfrIndex> = DispReady
ReactRunRec<REACT_RUN_WFRS_DISP_READY$> = 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<REACT_RUN_OUT_SLOT_ID$, WfrIndex>
RunStageWfrKey = RDSNo:'*DISP*':FormattedWfrID
RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey)
StageStatus = RunStageWfrRec<RUN_STAGE_WFR_STATUS$>
If StageStatus _EQC 'INIT' then
// Mark DISP stage as complete
RunStageWfrRec<RUN_STAGE_WFR_COMP_BY$> = @USER4
RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$> = CurrDTM
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = 'COMP'
Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$)
end
Begin Case
Case (ShipID EQ '')
LocQ = GaN_Services('GetWfrQueue', WfrID)
WOWfrRec<WO_WFR_STATUS$> = '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<RUN_STAGE_WFR_STATUS$>
If StageStatus _EQC 'COMP' then
RunStageWfrRec<RUN_STAGE_WFR_COMP_BY$> = ''
RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$> = ''
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = '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<WO_WFR_LOC_DTM$>
NextPos = DCount(LocDTM, @VM) + 1
WOWfrRec<WO_WFR_LOC_DTM$, NextPos> = CurrDTM
WOWfrRec<WO_WFR_LOC_BY$, NextPos> = @USER4
WOWfrRec<WO_WFR_LOC_EVENT$, NextPos> = 'COMP'
WOWfrRec<WO_WFR_TOOL_ID$, NextPos> = ''
WOWfrRec<WO_WFR_INV_LOC$, NextPos> = 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<WO_WFR_LOC_DTM$>
NextPos = DCount(LocDTM, @VM) + 1
WOWfrRec<WO_WFR_LOC_DTM$, NextPos> = CurrDTM
WOWfrRec<WO_WFR_LOC_BY$, NextPos> = @USER4
WOWfrRec<WO_WFR_LOC_EVENT$, NextPos> = 'G_PACK'
WOWfrRec<WO_WFR_TOOL_ID$, NextPos> = ''
WOWfrRec<WO_WFR_INV_LOC$, NextPos> = GPackQ
WOWfrRec<WO_WFR_STATUS$> = 'Ready to close'
DispReady = True$
WfrsDispReady<0, WfrIndex> = DispReady
ReactRunRec<REACT_RUN_WFRS_DISP_READY$> = 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<RUN_STAGE_WFR_STATUS$>
LocQ = Gan_Services('GetWfrQueue', WfrID)
WOWfrRec<WO_WFR_STATUS$> = 'Run closed'
Gan_Services('RemoveWfrFromWIP', WfrID)
If StageStatus _EQC 'INIT' then
// Mark G_PACK stage as complete
RunStageWfrRec<RUN_STAGE_WFR_COMP_BY$> = @USER4
RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$> = CurrDTM
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = '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<WO_WFR_RETAIN_SLOT$>
RetainBox = WOWfrRec<WO_WFR_RETAIN_BOX$>
RetainSig = WOWfrRec<WO_WFR_RETAIN_SIG$>
RetainQ = GaN_Services('GetLocQueueID', 'RETAIN')
RunStageWfrKey = RDSNo:'*DISP*':FormattedWfrID
RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey)
StageStatus = RunStageWfrRec<RUN_STAGE_WFR_STATUS$>
If StageStatus _EQC 'INIT' then
// Retain flag has been set and metrology is complete, so mark DISP stage as complete.
RunStageWfrRec<RUN_STAGE_WFR_COMP_BY$> = @User4
RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$> = CurrDTM
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = '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<WO_WFR_STATUS$> = '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<WO_WFR_LOC_DTM$>
NextPos = DCount(LocDTM, @VM) + 1
WOWfrRec<WO_WFR_LOC_DTM$, NextPos> = CurrDTM
WOWfrRec<WO_WFR_LOC_BY$, NextPos> = @USER4
WOWfrRec<WO_WFR_LOC_EVENT$, NextPos> = 'COMP'
WOWfrRec<WO_WFR_TOOL_ID$, NextPos> = ''
WOWfrRec<WO_WFR_INV_LOC$, NextPos> = 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<WO_WFR_STATUS$> = 'Ready to close'
DispReady = True$
end else
WOWfrRec<WO_WFR_STATUS$> = '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<WO_WFR_LOC_DTM$>
NextPos = DCount(LocDTM, @VM) + 1
WOWfrRec<WO_WFR_LOC_DTM$, NextPos> = CurrDTM
WOWfrRec<WO_WFR_LOC_BY$, NextPos> = @USER4
WOWfrRec<WO_WFR_LOC_EVENT$, NextPos> = 'RETAIN'
WOWfrRec<WO_WFR_TOOL_ID$, NextPos> = ''
WOWfrRec<WO_WFR_INV_LOC$, NextPos> = RetainQ
WfrsDispReady<0, WfrIndex> = DispReady
ReactRunRec<REACT_RUN_WFRS_DISP_READY$> = 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<RUN_STAGE_WFR_STATUS$>
LocQ = Gan_Services('GetWfrQueue', WfrID)
WOWfrRec<WO_WFR_STATUS$> = 'Run closed'
Gan_Services('RemoveWfrFromWIP', WfrID)
If StageStatus _EQC 'INIT' then
RunStageWfrRec<RUN_STAGE_WFR_COMP_BY$> = @User4
RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$> = CurrDTM
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = '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<REACT_RUN_WFRS_DISP_READY$> = WfrsDispReady
WOWfrRec<WO_WFR_STATUS$> = '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<RUN_STAGE_WFR_STATUS$>
LocQ = GaN_Services('GetWfrQueue', WfrID)
WOWfrRec<WO_WFR_STATUS$> = 'Run closed'
Gan_Services('RemoveWfrFromWIP', WfrID)
If StageStatus _EQC 'INIT' then
// Mark DISP stage as complete
RunStageWfrRec<RUN_STAGE_WFR_COMP_BY$> = @User4
RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$> = CurrDTM
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = '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<REACT_RUN_WFRS_DISP_READY$> = WfrsDispReady
WOWfrRec<WO_WFR_STATUS$> = '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<RUN_STAGE_WFR_STATUS$>
WOWfrRec<WO_WFR_STATUS$> = 'Run closed'
LocQ = Gan_Services('GetWfrQueue', WfrID)
Gan_Services('RemoveWfrFromWIP', WfrID)
If StageStatus _EQC 'INIT' then
// Mark DISP stage as complete
RunStageWfrRec<RUN_STAGE_WFR_COMP_BY$> = @User4
RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$> = CurrDTM
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = '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<REACT_RUN_WFRS_DISP_READY$> = WfrsDispReady
WOWfrRec<WO_WFR_STATUS$> = 'Ready to close'
end else
If NCRReq EQ True$ then
WOWfrRec<WO_WFR_STATUS$> = 'NCR required'
end else
WOWfrRec<WO_WFR_STATUS$> = '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<RUN_STAGE_WFR_STATUS$>
WOWfrRec<WO_WFR_STATUS$> = 'Run closed'
LocQ = GaN_Services('GetWfrQueue', WfrID)
Gan_Services('RemoveWfrFromWIP', WfrID)
If StageStatus _EQC 'INIT' then
// Mark DISP stage as complete
RunStageWfrRec<RUN_STAGE_WFR_COMP_BY$> = @User4
RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$> = CurrDTM
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = '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<WO_WFR_STATUS$> = '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<GAN_ETCH_REACTOR$> = Reactor
GanEtchRec<GAN_ETCH_USER$> = @USER4
GanEtchRec<GAN_ETCH_AVAILABLE$> = True$
GanEtchRec<GAN_ETCH_LOC_DTM$> = CurrDTM
GanEtchRec<GAN_ETCH_LOC_BY$> = @User4
GanEtchRec<GAN_ETCH_LOC_EVENT$> = 'CREATE'
GanEtchRec<GAN_ETCH_TOOL_ID$> = ToolID
GanEtchRec<GAN_ETCH_INV_LOC$> = LocID
Database_Services('WriteDataRow', 'GAN_ETCH', EtchID, GanEtchRec, True$, False$, True$)
LocRec = Database_Services('ReadDataRow', 'LOCATION', LocID)
LocQ = LocRec<LOCATION_ETCH_ID$>
DisplayEtchID = Xlate('GAN_ETCH', EtchID, 'DISPLAY_ETCH_ID', 'X')
Locate DisplayEtchID in LocQ using @VM setting vPos else
LocQ<1,-1> = DisplayEtchID
LocRec<LOCATION_ETCH_ID$> = 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<GAN_ETCH_REACTOR$>
ToolID = 'R':Reactor
GanEtchRec<GAN_ETCH_START_DTM$> = DateTime()
GanEtchRec<GAN_ETCH_LOC_DTM$, -1> = CurrDTM
GanEtchRec<GAN_ETCH_LOC_BY$, -1> = @User4
GanEtchRec<GAN_ETCH_LOC_EVENT$, -1> = 'START'
GanEtchRec<GAN_ETCH_TOOL_ID$, -1> = 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<LOCATION_WFR_ID$>
Locate DisplayEtchID in LocQ using @VM setting vPos then
LocQ = Delete(LocQ, 1, vPos, 0)
LocRec<LOCATION_ETCH_ID$> = LocQ
Database_Services('WriteDataRow', 'LOCATION', LocID, LocRec, True$, False$, True$)
end
// Add to Tool queue
ToolEtchRec = Database_Services('ReadDataRow', 'TOOL_ETCH', ToolID)
ToolQ = ToolEtchRec<TOOL_ETCH.ETCH_ID$>
Locate DisplayEtchID in ToolQ using @VM setting vPos else
ToolQ<1,-1> = DisplayEtchID
ToolEtchRec<TOOL_ETCH.ETCH_ID$> = 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<GAN_ETCH_END_DTM$> = DateTime()
GanEtchRec<GAN_ETCH_AVAILABLE$> = True$
GanEtchRec<GAN_ETCH_LOC_DTM$, -1> = CurrDTM
GanEtchRec<GAN_ETCH_LOC_BY$, -1> = @User4
GanEtchRec<GAN_ETCH_LOC_EVENT$, -1> = 'STOP'
GanEtchRec<GAN_ETCH_TOOL_ID$, -1> = 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<LOCATION_CASS_ID$>
Locate WOMatKey in CassQ using @VM setting vPos else
CassQ<1, -1> = WOMatKey
QRec<LOCATION_CASS_ID$> = 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<LOCATION_CASS_ID$>
Locate WOMatKey in CassQ using @VM setting vPos then
CassQ = Delete(CassQ, 1, vPos, 0)
QRec<LOCATION_CASS_ID$> = 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<LOCATION_CASS_ID$>
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<LOCATION_CASS_ID$>
Locate WOMatKey in LocQ using @VM setting vPos then
LocQ = Delete(LocQ, 0, vPos, 0)
QRec<LOCATION_CASS_ID$> = 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<TOOL_WFR_WFR_ID$>
Locate WOWfrID in ToolQ using @VM setting vPos else
ToolQ<1, -1> = WOWfrID
QRec<TOOL_WFR_WFR_ID$> = 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<TOOL_WFR_WFR_ID$> = 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<LOCATION_WFR_ID$>
Locate WOWfrID in LocQ using @VM setting vPos else
LocQ<0, -1> = WOWfrID
QRec<LOCATION_WFR_ID$> = 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<TOOL_WFR_WFR_ID$>
Locate WfrID in ToolQ using @VM setting vPos then
ToolQ = Delete(ToolQ, 0, vPos, 0)
QRec<TOOL_WFR_WFR_ID$> = 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<LOCATION_WFR_ID$>
Locate WfrID in LocQ using @VM setting vPos then
LocQ = Delete(LocQ, 0, vPos, 0)
QRec<LOCATION_WFR_ID$> = 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<TOOL_ETCH.ETCH_ID$>
Locate DisplayEtchID in ToolQ using @VM setting vPos then
ToolQ = Delete(ToolQ, 0, vPos, 0)
QRec<TOOL_ETCH.ETCH_ID$> = 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<LOCATION_ETCH_ID$>
Locate DisplayEtchID in LocQ using @VM setting vPos then
LocQ = Delete(LocQ, 0, vPos, 0)
QRec<LOCATION_ETCH_ID$> = 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<WO_MAT_HOLD$> EQ '') or (WOMatRec<WO_MAT_HOLD$> EQ False$) then
WOWfrIDs = Xlate('WO_MAT_WFR', WONo:'*':CassNo, WO_MAT_WFR_IN_WFR_ID$, 'X')
SlotCnt = WOMatRec<WO_MAT_WAFER_QTY$>
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<REACT_RUN_GAN_RUN_ID$>
WONo = ReactRunRec<REACT_RUN_WO_NO$>
WOStep = ReactRunRec<REACT_RUN_WO_STEP$>
Reactor = ReactRunRec<REACT_RUN_REACTOR$>
InWfrIDs = ReactRunRec<REACT_RUN_IN_WFR_ID$>
CarrSlotNos = ReactRunRec<REACT_RUN_CARR_SLOT_NO$>
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<REACT_RUN_CARR_SLOT_ID$> = CarrSlotIDs
ReactRunRec<REACT_RUN_CARR_WFR_ID$> = 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<WO_WFR_LOC_DTM$>
NextIndex = DCount(LocDTMs, @VM) + 1
WOWfrRec<WO_WFR_LOC_DTM$, NextIndex> = CurrDTM
WOWfrRec<WO_WFR_LOC_BY$, NextIndex> = @USER4
WOWfrRec<WO_WFR_LOC_EVENT$, NextIndex> = 'UNLOAD'
WOWfrRec<WO_WFR_CARR_SLOT$, NextIndex> = CarrSlotIDs<0, vPos>
WOWfrRec<WO_WFR_INV_LOC$, NextIndex> = 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<RUN_STAGE_SPEC_INV_ACTION$>
IACompBy = RunStageRec<RUN_STAGE_SIA_COMP_BY$>
IACompDTM = RunStageRec<RUN_STAGE_SIA_COMP_DTM$>
Locate 'UNLOAD' in InvActions using @VM setting vPos then
IACompBy<0, vPos> = @User4
IACompDTM<0, vPos> = CurrDTM
end
RunStageRec<RUN_STAGE_SIA_COMP_BY$> = IACompBy
RunStageRec<RUN_STAGE_SIA_COMP_DTM$> = IACompDTM
RunStageRec<RUN_STAGE_COMP_BY$> = @User4
RunStageRec<RUN_STAGE_COMP_DTM$> = CurrDTM
RunStageRec<RUN_STAGE_STATUS$> = '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<REACT_RUN_GAN_STAGE_ROUTE$>
RxStages = ReactRunRec<REACT_RUN_WFR_STAGE$>
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<WO_WFR_INV_LOC$>
ToolLocs = WOWfrRec<WO_WFR_TOOL_ID$>
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<GAN_ETCH_AVAILABLE$> = 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<REACT_RUN_WFR_STAGE$>
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<REACT_RUN_UNPRESCRIBED_WFR_STAGE$>
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<REACT_RUN_WFR_STAGE$> = WfrStages
ReactRunRec<REACT_RUN_UNPRESCRIBED_WFR_STAGE$> = UnRxStages
Database_Services('WriteDataRow', 'REACT_RUN', RDSNo, ReactRunRec, True$, False$, True$)
end
end
RunStageWfrRec = ''
RunStageWfrRec<RUN_STAGE_WFR_SPEC_TOOL_CLASS$> = GaN_Services('GetToolClassIDs', Stage)
RunStageWfrRec<RUN_STAGE_WFR_SPEC_INV_ACTION$> = GaN_Services('GetInvActions', Stage)
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = '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<RUN_STAGE_WFR_COMP_BY$> = User
RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$> = CurrDTM
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = '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<WO_WFR_LOC_DTM$>
NextStep = DCount(LocDTMs, @VM) + 1
WOWfrRec<WO_WFR_LOC_DTM$, NextStep> = CurrDTM
WOWfrRec<WO_WFR_LOC_BY$, NextStep> = User
WOWfrRec<WO_WFR_LOC_EVENT$, NextStep> = 'DISPOSITION'
WOWfrRec<WO_WFR_TOOL_ID$, NextStep> = ''
CurrStage = Gan_Services('GetCurrStage', WfrID)
CurrLocQ = Gan_Services('GetLocQueueID', CurrStage)
NextStage = Gan_Services('GetNextStage', WfrID)
NextLocQ = Gan_Services('GetLocQueueID', NextStage)
WoWfrRec<WO_WFR_INV_LOC$, NextStep> = 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<REACT_RUN_IN_WFR_ID$>
For each WOWfrID in InWfrIDs using @VM setting vPos
ThisWOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WOWfrID)
LocDTMs = ThisWOWfrRec<WO_WFR_LOC_DTM$>
LocQs = ThisWOWfrRec<WO_WFR_INV_LOC$>
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<WO_WFR_LOC_DTM$> = 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<RUN_STAGE_WFR_STATUS$> = 'START'
// Sign InvAction, Fill InvAction DTM
SpecInvActions = RunStageWfrRec<RUN_STAGE_WFR_SPEC_INV_ACTION$>
SIACompBy = RunStageWfrRec<RUN_STAGE_WFR_SIA_COMP_BY$>
SIACompDTM = RunStageWfrRec<RUN_STAGE_WFR_SIA_COMP_DTM$>
Locate InvAction in SpecInvActions using @VM setting vPos then
SIACompBy<0, vPos> = @USER4
SIACompDTM<0, vPos> = CurrDTM
end
RunStageWfrRec<RUN_STAGE_WFR_SIA_COMP_BY$> = SIACompBy
RunStageWfrRec<RUN_STAGE_WFR_SIA_COMP_DTM$> = SIACompDTM
Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$)
WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WfrID)
LocDTM = WOWfrRec<WO_WFR_LOC_DTM$>
NextPos = DCount(LocDTM, @VM) + 1
WOWfrRec<WO_WFR_LOC_DTM$, NextPos> = CurrDTM
WOWfrRec<WO_WFR_LOC_BY$, NextPos> = @USER4
WOWfrRec<WO_WFR_LOC_EVENT$, NextPos> = 'START'
WOWfrRec<WO_WFR_TOOL_ID$, NextPos> = ToolID
WOWfrRec<WO_WFR_INV_LOC$, NextPos> = ''
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<RUN_STAGE_WFR_STATUS$>
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<RUN_STAGE_WFR_SPEC_INV_ACTION$>
SIACompBy = RunStageWfrRec<RUN_STAGE_WFR_SIA_COMP_BY$>
SIACompDTM = RunStageWfrRec<RUN_STAGE_WFR_SIA_COMP_DTM$>
CompBy = RunStageWfrRec<RUN_STAGE_WFR_COMP_BY$>
CompDTM = RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$>
Locate InvAction in SpecInvActions using @VM setting vPos then
SIACompBy<0, vPos> = @USER4
SIACompDTM<0, vPos> = CurrDTM
end
RunStageWfrRec<RUN_STAGE_WFR_SIA_COMP_BY$> = SIACompBy
RunStageWfrRec<RUN_STAGE_WFR_SIA_COMP_DTM$> = SIACompDTM
// Set the status
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = 'STOP'
Database_Services('WriteDataRow', 'RUN_STAGE_WFR', RunStageWfrKey, RunStageWfrRec, True$, False$, True$)
WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WfrID)
LocDTM = WOWfrRec<WO_WFR_LOC_DTM$>
NextPos = DCount(LocDTM, @VM) + 1
WOWfrRec<WO_WFR_LOC_DTM$, NextPos> = CurrDTM
WOWfrRec<WO_WFR_LOC_BY$, NextPos> = @User4
WOWfrRec<WO_WFR_LOC_EVENT$, NextPos> = 'STOP'
WOWfrRec<WO_WFR_TOOL_ID$, NextPos> = ''
WOWfrRec<WO_WFR_INV_LOC$, NextPos> = 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<RUN_STAGE_WFR_STATUS$>
If StageStatus _EQC 'STOP' then
// Mark RUN_STAGE_WFR as complete
RunStageWfrRec<RUN_STAGE_WFR_COMP_BY$> = @User4
RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$> = CurrDTM
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = '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<RUN_STAGE_WFR_COMP_BY$> = @USER4
RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$> = CurrDTM
// Set the wafer status
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = '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<WO_WFR_LOC_DTM$>
NextPos = DCount(LocDTM, @VM) + 1
WOWfrRec<WO_WFR_LOC_DTM$, NextPos> = CurrDTM
WOWfrRec<WO_WFR_LOC_BY$, NextPos> = @USER4
WOWfrRec<WO_WFR_LOC_EVENT$, NextPos> = 'SKIP'
WOWfrRec<WO_WFR_TOOL_ID$, NextPos> = ''
WOWfrRec<WO_WFR_INV_LOC$, NextPos> = 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<RUN_STAGE_WFR_COMP_BY$> = ''
RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$> = ''
// Set the wafer status
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = '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<WO_WFR_LOC_DTM$>
NextPos = DCount(LocDTM, @VM) + 1
WOWfrRec<WO_WFR_LOC_DTM$, NextPos> = CurrDTM
WOWfrRec<WO_WFR_LOC_BY$, NextPos> = @USER4
WOWfrRec<WO_WFR_LOC_EVENT$, NextPos> = 'UNSKIP'
WOWfrRec<WO_WFR_TOOL_ID$, NextPos> = ''
WOWfrRec<WO_WFR_INV_LOC$, NextPos> = 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<RUN_STAGE_WFR_TOOL_ID$> = 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<REACT_RUN_WFR_STAGE$>
UnRxStages = ReactRunRec<REACT_RUN_UNPRESCRIBED_WFR_STAGE$>
// 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<REACT_RUN_WFR_STAGE$> = WfrStages
ReactRunRec<REACT_RUN_UNPRESCRIBED_WFR_STAGE$> = 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<WO_WFR_LOC_DTM$>
NextStep = DCount(LocDTMs, @VM) + 1
WOWfrRec<WO_WFR_LOC_DTM$, NextStep> = Datetime()
WOWfrRec<WO_WFR_LOC_BY$, NextStep> = @USER4
WOWfrRec<WO_WFR_LOC_EVENT$, NextStep> = 'REMOVE'
WOWfrRec<WO_WFR_TOOL_ID$, NextStep> = ''
WOWfrRec<WO_WFR_INV_LOC$, NextStep> = 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<RUN_STAGE_WFR_COMP_BY$> = User
RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$> = CurrDTM
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = '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<WO_WFR_LOC_DTM$>
NextStep = DCount(LocDTMs, @VM) + 1
WOWfrRec<WO_WFR_LOC_DTM$, NextStep> = CurrDTM
WOWfrRec<WO_WFR_LOC_BY$, NextStep> = User
WOWfrRec<WO_WFR_LOC_EVENT$, NextStep> = 'CHARACTERIZE'
WOWfrRec<WO_WFR_TOOL_ID$, NextStep> = ''
CurrStage = Gan_Services('GetCurrStage', WfrID)
CurrLocQ = Gan_Services('GetLocQueueID', CurrStage)
NextStage = Gan_Services('GetNextStage', WfrID)
NextLocQ = Gan_Services('GetLocQueueID', NextStage)
WoWfrRec<WO_WFR_INV_LOC$, NextStep> = 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<REACT_RUN_IN_WFR_ID$>
Locate WfrID in InWfrIDs using @VM setting wPos then
ReactRunRec<REACT_RUN_CHAR_WFR_FLAG$, wPos> = True$
// Add this wafer ID to the list of characterized wafers so that we can
// determine primary and secondary characterization.
Locate WfrID in ReactRunRec<REACT_RUN_CHAR_LIST$> using @VM setting dummy else
ReactRunRec<REACT_RUN_CHAR_LIST$, -1> = 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<REACT_RUN_CASS_NO$>
LastCharRun = WOLogRec<WO_LOG_LAST_CHAR_RUN$>[-1, 'B':@VM]
If ( (LastCharRun EQ '') or (RunNo GT LastCharRun) ) then
LastCharRun = RunNo
WOLogRec<WO_LOG_LAST_CHAR_RUN$, -1> = 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<WO_LOG_LAST_CHAR_RUN$>
NumCharRuns = DCount(PrevCharRuns, @VM)
LastCharRun = PrevCharRuns<0, NumCharRuns>
If LastCharRun EQ '' then LastCharRun = 0
ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo)
InWfrIDs = ReactRunRec<REACT_RUN_IN_WFR_ID$>
LastWafer = DCount(InWfrIDs, @VM)
RunNo = ReactRunRec<REACT_RUN_CASS_NO$>
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<RUN_STAGE_WFR_COMP_BY$> = ''
RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$> = ''
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = '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<WO_WFR_LOC_DTM$>
NextStep = DCount(LocDTMs, @VM) + 1
WOWfrRec<WO_WFR_LOC_DTM$, NextStep> = CurrDTM
WOWfrRec<WO_WFR_LOC_BY$, NextStep> = @User4
WOWfrRec<WO_WFR_LOC_EVENT$, NextStep> = 'WITHDRAW'
WOWfrRec<WO_WFR_TOOL_ID$, NextStep> = ''
WOWfrRec<WO_WFR_INV_LOC$, NextStep> = NextLocQ
Database_Services('WriteDataRow', 'WO_WFR', WOWfrKey, WOWfrRec, True$, False$, True$)
// Mark the wafer as NOT characterized in the REACT_RUN record.
InWfrIDs = ReactRunRec<REACT_RUN_IN_WFR_ID$>
CharList = ReactRunRec<REACT_RUN_CHAR_LIST$>
Locate WfrID in InWfrIDs using @VM setting wPos then
ReactRunRec<REACT_RUN_CHAR_WFR_FLAG$, wPos> = False$
end
Locate WfrID in CharList using @VM setting cPos then
CharList = Delete(CharList, 0, cPos, 0)
ReactRunRec<REACT_RUN_CHAR_LIST$> = 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<REACT_RUN_CASS_NO$>
PrevCharRuns = WOLogRec<WO_LOG_LAST_CHAR_RUN$>
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<REACT_RUN_CHAR_WFR_FLAG$>
TotalCharWfrs = Sum(WfrCharFlags)
If TotalCharWfrs EQ 0 then
PrevCharRuns = Delete(PrevCharRuns, 0, vPos, 0)
WOLogRec<WO_LOG_LAST_CHAR_RUN$> = 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<LOCATION_WFR_ID$>
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<TOOL_WFR_WFR_ID$>
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<LOCATION_ETCH_ID$>
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<TOOL_ETCH.ETCH_ID$>
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<REACT_RUN_RUN_STAGE_KEY$>
WfrStages = ReactRunRec<REACT_RUN_WFR_STAGE$>
UnRxStages = ReactRunRec<REACT_RUN_UNPRESCRIBED_WFR_STAGE$>
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<REACT_RUN_WFR_STAGE$>
UnRxStages = ReactRunRec<REACT_RUN_UNPRESCRIBED_WFR_STAGE$>
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<REACT_RUN_WFR_STAGE$>
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<REACT_RUN_IN_WFR_ID$>
ExternalFlags = ReactRunRec<REACT_RUN_EXTERNAL$>
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<REACT_RUN_WFR_STAGE$>
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<REACT_RUN_IN_WFR_ID$>
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<WO_MAT_WFR_OUT_WFR_ID$>
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<REACT_RUN_IN_WFR_ID$> USING @VM SETTING Pos THEN
ReactRunRec<REACT_RUN_OUT_SLOT_ID$, Pos> = 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<REACT_RUN_CARR_WFR_ID$> USING @VM SETTING cPos THEN
CurrCarrSlot = ReactRunRec<REACT_RUN_CARR_SLOT_ID$, cPos>
END ELSE
CurrCarrSlot = ''
END
EventDTMs = WOWfrRec<WO_WFR_LOC_DTM$>
CurrEventIndex = DCount(EventDTMs, @VM)
WOWfrRec<WO_WFR_SLOT_ID$, CurrEventIndex> = OutWfrID
WOWfrRec<WO_WFR_SLOT_ID$, CurrEventIndex> = CurrCarrSlot
Database_Services('WriteDataRow', 'WO_WFR', WfrID, WOWfrRec, True$, False$, True$)
NEXT I
// Update WO_MAT_WFR table (outbound cassette table)
WOMatWfrRec<WO_MAT_WFR_OUT_WFR_ID$> = 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<WO_LOG_NEXT_OUT_SLOT$>
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<WO_LOG_WO_MAT_KEY$, -1> = 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<WO_MAT_WFR_OUT_PREV_WFR_ID$, -1> = 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<WO_LOG_NEXT_OUT_SLOT$> = 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<WO_MAT_WFR_OUT_WFR_ID$>
OutWfrIDs<0, OutSlotNo> = WfrID
WOMatWfrRec<WO_MAT_WFR_OUT_WFR_ID$> = 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<REACT_RUN_IN_WFR_ID$> USING @VM SETTING Pos THEN
ReactRunRec<REACT_RUN_OUT_SLOT_ID$, Pos> = 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<REACT_RUN_CARR_WFR_ID$> USING @VM SETTING cPos THEN
CurrCarrSlot = ReactRunRec<REACT_RUN_CARR_SLOT_ID$, cPos>
END ELSE
CurrCarrSlot = ''
END
EventDTMs = WOWfrRec<WO_WFR_LOC_DTM$>
NextPos = DCount(EventDTMs, @VM) + 1
WOWfrRec<WO_WFR_SLOT_ID$, NextPos> = OutSlotKey
WOWfrRec<WO_WFR_CARR_SLOT$, NextPos> = CurrCarrSlot
WOWfrRec<WO_WFR_LOC_DTM$, NextPos> = CurrDTM
WOWfrRec<WO_WFR_LOC_BY$, NextPos> = @USER4
WOWfrRec<WO_WFR_LOC_EVENT$, NextPos> = 'COMP'
WOWfrRec<WO_WFR_TOOL_ID$, NextPos> = ''
WOWfrRec<WO_WFR_INV_LOC$, NextPos> = 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<RUN_STAGE_WFR_STATUS$>
If StageStatus _EQC 'INIT' then
// Mark DISP stage as complete
RunStageWfrRec<RUN_STAGE_WFR_COMP_BY$> = @USER4
RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$> = CurrDTM
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = '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<WO_MAT_WFR_OUT_WFR_ID$>
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<REACT_RUN_IN_WFR_ID$> USING @VM SETTING Pos THEN
ReactRunRec<REACT_RUN_OUT_SLOT_ID$, Pos> = ''
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<WO_WFR_LOC_DTM$>
CurrEventIndex = DCount(EventDTMs, @VM)
WOWfrRec<WO_WFR_SLOT_ID$, CurrEventIndex> = ''
WOWfrRec<WO_WFR_SLOT_ID$, CurrEventIndex> = ''
Database_Services('WriteDataRow', 'WO_WFR', WfrID, WOWfrRec, True$, False$, True$)
NEXT I
// Update WO_MAT_WFR table (outbound cassette table)
WOMatWfrRec<WO_MAT_WFR_OUT_WFR_ID$> = 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<REACT_RUN_WFR_STAGE$>
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<REACT_RUN_IN_WFR_ID$>
OutOfSpecArray = ReactRunRec<REACT_RUN_DATA_OUT_OF_SPEC$>
CassNo = ReactRunRec<REACT_RUN_CASS_NO$>
WONo = ReactRunRec<REACT_RUN_WO_NO$>
GaNCritStages = ReactRunRec<REACT_RUN_GAN_CRITICAL_STAGES$>
GaNParamKeys = ReactRunRec<REACT_RUN_GAN_PARAM_KEYS$>
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<REACT_RUN_IN_WFR_ID$>
CharFlags = ReactRunRec<REACT_RUN_CHAR_WFR_FLAG$>
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<REACT_RUN_WFRS_DISP_READY$>
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<REACT_RUN_WFRS_DISP_READY$>
InWfrIDs = ReactRunRec<REACT_RUN_IN_WFR_ID$>
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<REACT_RUN_CARR_WFR_SHIP$>
OutSlotIDs = ReactRunRec<REACT_RUN_OUT_SLOT_ID$>
WONo = ReactRunRec<REACT_RUN_WO_NO$>
WOLogRec = Database_Services('ReadDataRow', 'WO_LOG', WONo)
WOMatKeys = WOLogRec<WO_LOG_WO_MAT_KEY$>
CustNo = WOLogRec<WO_LOG_CUST_NO$>
EpiPartNo = WOLogRec<WO_LOG_EPI_PART_NO$>
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<RUN_STAGE_WFR_STATUS$>
If StageStatus _EQC 'INIT' then
// Mark DISP stage as complete
RunStageWfrRec<RUN_STAGE_WFR_COMP_BY$> = @USER4
RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$> = CurrDTM
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = '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<REACT_RUN_DISP_COMPLETE$> = 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<REACT_RUN_IN_WFR_ID$>
CharFlags = ReactRunRec<REACT_RUN_CHAR_WFR_FLAG$>
CritStages = ReactRunRec<REACT_RUN_GAN_CRITICAL_STAGES$>
RunScrapped = False$
// Clear failure flags
ReactRunRec<REACT_RUN_RUN_SCRAPPED$> = RunScrapped
ReactRunRec<REACT_RUN_DATA_MISSING$> = ''
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<REACT_RUN_MISSING_DATA_VALID_DISABLED$, WaferPos>
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<RUN_STAGE_WFR_PARAM_OUT_OF_SPEC$>
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<REACT_RUN_RUN_SCRAPPED$> = RunScrapped
end
end
end
end
end
Next Stage
ReactRunRec<REACT_RUN_DATA_MISSING$, WaferPos> = DataIsMissing
ReactRunRec<REACT_RUN_DATA_OUT_OF_SPEC$, WaferPos> = DataOutOfSpec
If ( (DataIsMissing EQ False$) and (DataOutOfSpec EQ False$) ) then
ReactRunRec<REACT_RUN_MISSING_DATA_VALID_DISABLED$, WaferPos> = False$
ReactRunRec<REACT_RUN_MISSING_DATA_VALID_USER$, WaferPos> = ''
ReactRunRec<REACT_RUN_MISSING_DATA_VALID_DTM$, WaferPos> = ''
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<REACT_RUN_NCR_REQ$>
InWfrIDs = ReactRunRec<REACT_RUN_IN_WFR_ID$>
DispFlags = ReactRunRec<REACT_RUN_WFRS_DISP_READY$>
Grades = ReactRunRec<REACT_RUN_CARR_WFR_GRADE$>
Reasons = ReactRunRec<REACT_RUN_DISP_REASON$>
CharFlags = ReactRunRec<REACT_RUN_CHAR_WFR_FLAG$>
RunScrapped = ReactRunRec<REACT_RUN_RUN_SCRAPPED$>
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<GAN_PARAMS.MET_NAME$>
LSLs = GaNParamRec<GAN_PARAMS.LSL$>
USLs = GaNParamRec<GAN_PARAMS.USL$>
Targets = GaNParamRec<GAN_PARAMS.TARGET$>
RunNo = ReactRunRec<REACT_RUN_GAN_RUN_ID$>
Reactor = 'R':ReactRunRec<REACT_RUN_REACTOR$>
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<fPos, 3>
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<fPos, 2>
ParamValues<WaferPos, mPos, DataPointIndex> = Response<fPos, 4>
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<WaferPos>
Delimiter = @VM
Convert '*' to '.' in WfrID
RunStageWfrKey = RDSNo:'*':Stage:'*':WfrID
RunStageWfrRec = Database_Services('ReadDataRow', 'RUN_STAGE_WFR', RunStageWfrKey)
RunStageWfrRec<RUN_STAGE_WFR_MET_PARAM_VALUES$> = 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<RUN_STAGE_WFR_MET_PARAM_VALUES$> = ValueSet
RunStageWfrRec<RUN_STAGE_WFR_PARAM_OUT_OF_SPEC$> = 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<RUN_STAGE_WFR_MET_PARAM_VALUES$> = 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<RUN_STAGE_WFR_MET_PARAM_VALUES$> = ParamValues
RunStageWfrRec<RUN_STAGE_WFR_PARAM_OUT_OF_SPEC$> = 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<REACT_RUN_IN_WFR_ID$>
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<REACT_RUN_GAN_RUN_ID$>
Reactor = 'R':ReactRunRec<REACT_RUN_REACTOR$>
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<fPos, 3>
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<fPos, 2>
ParamValues<WaferPos, mPos, DataPointIndex> = Response<fPos, 4>
end
end
Next Row
Next MetName
For each WfrID in InWfrIDs using @VM setting WaferPos
WOWfrRec = Database_Services('ReadDataRow', 'WO_WFR', WfrID)
OrigCritFailure = WOWfrRec<WO_WFR_CRITICAL_FAILURE$>
CriticalFailure = False$
ValueSet = ParamValues<WaferPos>
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<WO_MAT_WFR_IN_WFR_ID$>
ConsumedQ = WOMatWfrRec<WO_MAT_WFR_IN_PREV_WFR_ID$>
ReadyQ<0, SlotNo> = ''
ConsumedQ<0, SlotNo> = InWfrID
WOMatWfrRec<WO_MAT_WFR_IN_WFR_ID$> = ReadyQ
WOMatWfrRec<WO_MAT_WFR_IN_PREV_WFR_ID$> = 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<PROD_SPEC_PRS_STAGE_KEY$>
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<PRS_STAGE_PROC_TOOL_CLASS$> = ToolClasses
If InvActions NE '' then
PRSStageRec<PRS_STAGE_PROC_INV_ACTION$> = InvActions
If SigReq EQ True$ then
For each InvAction in InvActions using @VM setting vPos
PRSStageRec<PRS_STAGE_PROC_INV_SIG_REQ$, vPos> = 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<RowIndex, 1> = WfrRec<RETAINED_WAFERS.RUN_ID$>
WaferList<RowIndex, 2> = WfrRec<RETAINED_WAFERS.RECIPE$>
WaferList<RowIndex, 3> = WfrRec<RETAINED_WAFERS.POCKET$>
WaferList<RowIndex, 4> = WfrRec<RETAINED_WAFERS.SCRIBE$>
WaferList<RowIndex, 5> = WfrRec<RETAINED_WAFERS.GRADE$>
WaferList<RowIndex, 6> = WfrRec<RETAINED_WAFERS.PART_NO$>
WaferList<RowIndex, 7> = Field(WfrID, '*', 1)
WaferList<RowIndex, 8> = WfrRec<RETAINED_WAFERS.RETAIN_BOX$>
WaferList<RowIndex, 9> = WfrRec<RETAINED_WAFERS.RETAIN_SLOT$>
WaferList<RowIndex, 10> = WfrRec<RETAINED_WAFERS.LOCATION$>
WaferList<RowIndex, 11> = WfrRec<RETAINED_WAFERS.STATUS$>
WaferList<RowIndex, 12> = WfrRec<RETAINED_WAFERS.COMMENT$>
WaferList<RowIndex, 13> = WfrRec<RETAINED_WAFERS.RETAIN_SIG$>
WaferList<RowIndex, 14> = WfrRec<RETAINED_WAFERS.RETAIN_DT$>
WaferList<RowIndex, 15> = WfrRec<RETAINED_WAFERS.DESTROY_SIG$>
WaferList<RowIndex, 16> = WfrRec<RETAINED_WAFERS.DESTROY_DT$>
WaferList<RowIndex, 17> = 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<WO_WFR_RETAIN_LOC$> = Location
WOWfrRec<WO_WFR_RETAIN_STATUS$> = Status
WOWfrRec<WO_WFR_RETAIN_COMMENT$> = 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<fPos>, @VM)
vPos += 1
ParameterList<fPos, vPos, 1> = MetName
ParameterList<fPos, vPos, 2> = 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<fPos>, @VM)
* vPos += 1
* ParameterList<fPos, vPos, 1> = MetName
* ParameterList<fPos, vPos, 2> = 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<fPos>, @VM)
* vPos += 1
* ParameterList<fPos, vPos, 1> = MetName
* ParameterList<fPos, vPos, 2> = 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<WO_WFR_RETAIN_BOX$>
RetainSlot = WOWfrRec<WO_WFR_RETAIN_SLOT$>
If ( (RetainBox NE '') and (RetainSlot NE '') ) then
WOWfrRec<WO_WFR_RETAIN_BOX$> = ''
WOWfrRec<WO_WFR_RETAIN_SLOT$> = ''
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<RUN_STAGE_WFR_COMP_BY$> = ''
RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$> = ''
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = '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<REACT_RUN_IN_WFR_ID$>
Locate InboundWfrID in InWfrIDs using @VM setting vPos then
ReactRunRec<REACT_RUN_GAN_RET_WFR$, vPos> = 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<WO_WFR_RETAIN_BOX$>
OrigRetainSlot = WOWfrRec<WO_WFR_RETAIN_SLOT$>
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<WO_WFR_RETAIN_BOX$> = RetainBox
WOWfrRec<WO_WFR_RETAIN_SLOT$> = 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<RUN_STAGE_WFR_STATUS$>
If StageStatus NE 'COMP' then
RunStageWfrRec<RUN_STAGE_WFR_COMP_BY$> = 'AUTO'
RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$> = Datetime()
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = '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<RUN_STAGE_WFR_STATUS$>
If StageStatus NE 'COMP' then
RunStageWfrRec<RUN_STAGE_WFR_COMP_BY$> = 'AUTO'
RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$> = Datetime()
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = 'COMP'
Database_Services('WriteDataRow', 'RUN_STAGE_WFR', DispStageKey, RunStageWfrRec, True$, False$, True$)
end
ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSNo)
InWfrIDs = ReactRunRec<REACT_RUN_IN_WFR_ID$>
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<REACT_RUN_GAN_RET_WFR$, vPos> = 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<WO_WFR_RETAIN_SIG$> = @User4
WOWfrRec<WO_WFR_RETAIN_DT$> = Date()
WOWfrRec<WO_WFR_RETAIN_LOC$> = '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<WO_WFR_DESTROY_SIG$> = @User4
WOWfrRec<WO_WFR_DESTROY_DT$> = Date()
WOWfrRec<WO_WFR_RETAIN_LOC$> = '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<WfrIndex, 1> = WfrID
WfrStatusList<WfrIndex, 2> = 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<WO_WFR_CRITICAL_FAILURE$> = 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<WO_WFR_CRITICAL_FAILURE$> = 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<DISPOSITION_REQUESTS.RESPONSE_DATE$>
Response = RequestRow<DISPOSITION_REQUESTS.RESPONSE$>
// 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<DISPOSITION_REQUESTS.RESPONSE$> = True$
end else
RequestRow<DISPOSITION_REQUESTS.RESPONSE$> = Error_Services('GetMessage')
end
RequestRow<DISPOSITION_REQUESTS.RESPONSE_DATE$> = Date()
RequestRow<DISPOSITION_REQUESTS.RESPONSE_TIME$> = 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<REACT_RUN_REACTOR$>
Scribes = Xlate('REACT_RUN', RDSNo, 'WFR_SCRIBES', 'X')
NumWfrs = DCount(Scribes, @VM)
GanRunID = ReactRunRec<REACT_RUN_GAN_RUN_ID$>
GaNRecipe = ReactRunRec<REACT_RUN_GAN_RECIPE$>
WfrIDs = ReactRunRec<REACT_RUN_IN_WFR_ID$>
CassDispComp = ReactRunRec<REACT_RUN_DISP_COMPLETE$>
WONo = ReactRunRec<REACT_RUN_WO_NO$>
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<WO_WFR_RETAIN_SLOT$>
RetainBox = WOWfrRec<WO_WFR_RETAIN_BOX$>
WOWfrGrade = WOWfrRec<WO_WFR_GRADE$>
If WOWfrGrade NE ExcelGrade then
WOWfrRec<WO_WFR_GRADE$> = ExcelGrade
Database_Services('WriteDataRow', 'WO_WFR', WfrID, WOWfrRec, True$, False$, True$)
end
OrigShipFlag = ReactRunRec<REACT_RUN_CARR_WFR_SHIP$, WfrIndex>
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<RUN_STAGE_WFR_COMP_BY$> = ''
RunStageWfrRec<RUN_STAGE_WFR_COMP_DTM$> = ''
RunStageWfrRec<RUN_STAGE_WFR_STATUS$> = 'INIT'
Database_Services('WriteDataRow', 'RUN_STAGE_WFR', GPackKey, RunStageWfrRec, True$, False$, True$)
end
end
Next WfrIndex
ReactRunRec<REACT_RUN_CARR_WFR_SHIP$> = ExcelShipFlags
ReactRunRec<REACT_RUN_GAN_RET_WFR$> = ExcelRetainFlags
ReactRunRec<REACT_RUN_NCR_REQ$> = ExcelNCRReqFlags
ReactRunRec<REACT_RUN_DISP_REASON$> = ExcelReasons
InternalFlags = ReactRunRec<REACT_RUN_INTERNAL$>
ExternalFlags = ReactRunRec<REACT_RUN_EXTERNAL$>
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<REACT_RUN_INTERNAL$> = InternalFlags
ReactRunRec<REACT_RUN_EXTERNAL$> = 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