Function REACT_RUN_Actions(Action, CalcColName, FSList, Handle, Name, FMC, Record, Status, OrigRecord, Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10) /*********************************************************************************************************************** This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written permission from Infineon. Name : REACT_RUN_Actions Description : Handles calculated columns and MFS calls for the current table. Notes : This function uses @ID, @RECORD, and @DICT to make sure {ColumnName} references work correctly. If called from outside of a calculated column these will need to be set and restored. Parameters : Action [in] -- Name of the action to be taken CalcColName [in] -- Name of the calculated column that needs to be processed. Normally this should only be populated when the CalcField action is being used. FSList [in] -- The list of MFSs and the BFS name for the current file or volume. This is an @SVM delimited array, with the current MFS name as the first value in the array, and the BFS name as the last value. Normally set by a calling MFS. Handle [in] -- The file handle of the file or media map being accessed. Note, this does contain the entire handle structure that the Basic+ Open statement would provide. Normally set by a calling MFS. Name [in] -- The name (key) of the record or file being accessed. Normally set by a calling MFS. FMC [in] -- Various functions. Normally set by a calling MFS. Record [in] -- The entire record (for record-oriented functions) or a newly-created handle (for "get handle" functions). Normally set by a calling MFS. Status [in/out] -- Indicator of the success or failure of an action. Normally set by the calling MFS but for some actions can be set by the action handler to indicate failure. OrigRecord [in] -- Original content of the record being processed by the current action. This is automatically being assigned by the WRITE_RECORD and DELETE_RECORD actions within BASE_MFS. Param1-10 [in/out] -- Additional request parameter holders ActionFlow [out] -- Used to control the action chain (see the ACTION_SETUP insert for more information.) Can also be used to return a special value, such as the results of the CalcField method. History : (Date, Initials, Notes) 04/10/18 dmb Original programmer. 10/04/18 djs Added a trigger within the WRITE_RECORD event, which fires when the reactor number has changed. When this occurs the related RDS_LAYER records for this RDS record are populated with the most recent associated TOOL_PARMS record. (related by PSN and Reactor) ***********************************************************************************************************************/ #pragma precomp SRP_PreCompiler $Insert FILE.SYSTEM.EQUATES $Insert ACTION_SETUP $Insert RDS_EQUATES $Insert CLEAN_INSP_EQUATES $Insert COMPANY_EQUATES $Insert RDS_LAYER_EQUATES $Insert TOOL_PARMS_EQUATES $Insert RLIST_EQUATES $Insert APP_INSERTS $Insert QA_MET_EQUATES $Insert PRS_STAGE_EQUATES $Insert REACT_RUN_EQUATES $Insert RETAINED_WAFERS_EQUATES $Insert WO_LOG_EQUATES $Insert GAN_STAGE_CYCLE_TIME_EQUATES Equ COMMA$ to ',' Declare function Error_Services, Database_Services, obj_RDS_Test, Environment_Services, GaN_Services Declare function Tool_Parms_Services, Datetime Declare subroutine Error_Services, Database_Services, Set_Status, Engineering_Services, Obj_Tables, Material_Services If KeyID then GoSub Initialize_System_Variables Begin Case Case Action _EQC 'CalculateColumn' ; GoSub CalculateColumn Case Action _EQC 'READ_RECORD_PRE' ; GoSub READ_RECORD_PRE Case Action _EQC 'READ_RECORD' ; GoSub READ_RECORD Case Action _EQC 'READONLY_RECORD_PRE' ; GoSub READONLY_RECORD_PRE Case Action _EQC 'READONLY_RECORD' ; GoSub READONLY_RECORD Case Action _EQC 'WRITE_RECORD_PRE' ; GoSub WRITE_RECORD_PRE Case Action _EQC 'WRITE_RECORD' ; GoSub WRITE_RECORD Case Action _EQC 'DELETE_RECORD_PRE' ; GoSub DELETE_RECORD_PRE Case Action _EQC 'DELETE_RECORD' ; GoSub DELETE_RECORD Case Otherwise$ ; Status = 'Invalid Action' End Case If KeyID then GoSub Restore_System_Variables If Assigned(ActionFlow) else ActionFlow = ACTION_CONTINUE$ Return ActionFlow //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Calculated Columns // // The typical structure of a calculated column will look like this: // // Declare function Database_Services // // @ANS = Database_Services('CalculateColumn') //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// CalculateColumn: // Make sure the ActionFlow return variable is cleared in case nothing is calculated. ActionFlow = '' Begin Case Case CalcColName EQ 'UNLOAD_DT' ; GoSub UNLOAD_DT Case CalcColName EQ 'CHAR_STATUS' ; GoSub CHAR_STATUS Case CalcColName EQ 'NUM_ANKO_CRITICAL_FAIL_WFRS' ; GoSub NUM_ANKO_CRITICAL_FAIL_WFRS Case CalcColName EQ 'NUM_CRITICAL_FAIL_WFRS' ; GoSub NUM_CRITICAL_FAIL_WFRS Case CalcColName EQ 'WFR_GRADES' ; GoSub WFR_GRADES Case CalcColName EQ 'WFR_RETAIN_BOX' ; GoSub WFR_RETAIN_BOX Case CalcColName EQ 'WFR_RETAIN_SLOT' ; GoSub WFR_RETAIN_SLOT Case CalcColName EQ 'WFR_SCRIBES' ; GoSub WFR_SCRIBES Case CalcColName EQ 'WFR_TRACK_PART' ; GoSub WFR_TRACK_PART End Case return NUM_CRITICAL_FAIL_WFRS: NumFailures = 0 InWfrIDs = {IN_WFR_ID} For each WfrID in InWfrIDs using @VM setting vPos NumFailures += ( Xlate('WO_WFR', WfrID, 'CRITICAL_FAILURE', 'X') EQ True$ ) Next WfrID ActionFlow = NumFailures return NUM_ANKO_CRITICAL_FAIL_WFRS: NumCritFailWfrs = 0 InWfrIDs = {IN_WFR_ID} PSNo = Xlate('RDS', @ID, 'PROD_SPEC_ID', 'X') ANKOMetPockets = Xlate('PROD_SPEC', PSNo, 'ANKO_MET_POCKETS', 'X') For each WfrID in InWfrIDs using @VM setting vPos ANKOMetPocket = ANKOMetPockets<0, vPos> If ANKOMetPocket EQ True$ then NumCritFailWfrs += ( Xlate('WO_WFR', WfrID, 'CRITICAL_FAILURE', 'X') EQ True$ ) end Next WfrID ActionFlow = NumCritFailWfrs return WFR_GRADES: InWfrIDs = {IN_WFR_ID} For each WfrID in InWfrIDs using @VM setting vPos ActionFlow<0, -1> = Xlate('WO_WFR', WfrID, 'GRADE', 'X') Next WfrID return WFR_RETAIN_BOX: InWfrIDs = {IN_WFR_ID} For each WfrID in InWfrIDs using @VM setting vPos ActionFlow<0, -1> = Xlate('WO_WFR', WfrID, 'RETAIN_BOX', 'X') Next WfrID return WFR_RETAIN_SLOT: InWfrIDs = {IN_WFR_ID} For each WfrID in InWfrIDs using @VM setting vPos ActionFlow<0, -1> = Xlate('WO_WFR', WfrID, 'RETAIN_SLOT', 'X') Next WfrID return WFR_SCRIBES: InWfrIDs = {IN_WFR_ID} For each WfrID in InWfrIDs using @VM setting vPos ActionFlow<0, -1> = Xlate('WO_WFR', WfrID, 'SCRIBE', 'X') Next WfrID return CHAR_STATUS: RDSClosed = {DISP_COMPLETE} * CharDone = ( Sum({CHAR_WFR_FLAG}) GT 0 ) CharDone = False$ PrevCharRuns = Xlate('WO_LOG', {WO_NO}, 'LAST_CHAR_RUN', 'X') If PrevCharRuns EQ '' then PrevCharRuns = 1 NumCharRuns = DCount(PrevCharRuns, @VM) LastCharRun = PrevCharRuns<0, NumCharRuns> If LastCharRun EQ '' then LastCharRun = 1 CharInterval = Xlate('PROD_SPEC', {PS_NO}, 'CHAR_INTERVAL', 'X') RunNo = {CASS_NO} Begin Case Case RunNo EQ 1 CharReq = True$ Case RunNo LT LastCharRun PrevCharRun = '' RDSNos = Xlate('WO_STEP', {WO_NO}:"*":1, 'RDS_KEY', 'X') For RunIndex = RunNo - 1 to 1 Step - 1 RunRDSNo = RDSNos<0, RunIndex> WfrIDs = Xlate('REACT_RUN', RunRDSNo, 'IN_WFR_ID', 'X') RunCharFlags = Xlate('REACT_RUN', RunRDSNo, 'CHAR_WFR_FLAG', 'X') RunCharacterized = False$ For each WfrID in WfrIDs using @VM setting WfrIndex WfrChar = RunCharFlags<0, WfrIndex> If WfrChar then CharType = GaN_Services('GetCharType', WfrID) If CharType EQ 'Full' then RunCharacterized = True$ end Until RunCharacterized = True$ Next WfrID If RunCharacterized EQ True$ then PrevCharRun = RunIndex Until PrevCharRun NE '' Next RunIndex If PrevCharRun EQ '' then PrevCharRun = 1 CharReq = ( Mod( ( (RunNo) - PrevCharRun), CharInterval ) EQ 0 ) Case Otherwise$ CharReq = ( Mod( ( (RunNo) - LastCharRun), CharInterval ) EQ 0 ) End Case WfrIDs = {IN_WFR_ID} CharFlags = {CHAR_WFR_FLAG} For each WfrID in WfrIDs using @VM setting WfrIndex WfrChar = CharFlags<0, WfrIndex> If WfrChar then CharType = GaN_Services('GetCharType', WfrID) If CharType EQ 'Full' then CharDone = True$ end Until CharDone EQ True$ Next WfrID Begin Case Case ( (CharDone EQ True$) and (CharReq EQ True$) ) ActionFlow = 'Sched-Done' Case CharDone EQ True$ ActionFlow = 'Done' Case ( (CharReq EQ True$) and (RDSClosed EQ True$) ) ActionFlow = 'Skipped' Case CharReq EQ True$ ActionFlow = 'Sched' Case Otherwise$ ActionFlow = '' End Case return UNLOAD_DT: UnloadDt = {UNLOAD_SIG_DTM}[1,'.'] ActionFlow = UnloadDt return WFR_TRACK_PART: WONo = {WO_NO} ActionFlow = Xlate('WO_LOG', WONo, 'WAFER_TRACK_PART', 'X') return // ----- MFS calls ----------------------------------------------------------------------------------------------------- READ_RECORD_PRE: // In order to stop a record from being read in this action these lines of code must be used: // // OrigFileError = 100 : @FM : KeyID // Status = 0 // Record = '' // ActionFlow = ACTION_STOP$ * This code prevents an anomaly where an @SVM appears when the value is read * and causes an error when copying the record to SQL. LoadWfrCnt = Record LoadWfrCnt = LoadWfrCnt<1, 1, 1> Record = LoadWfrCnt return READ_RECORD: // In order to stop a record from being read in this action these lines of code must be used: // // OrigFileError = 100 : @FM : KeyID // Status = 0 // Record = '' Shift = Record If Num(Shift) then Begin Case Case Shift EQ 1 Record = 'A' Case Shift EQ 2 Record = 'B' Case Shift EQ 3 Record = 'C' Case Shift EQ 4 Record = 'D' Case Otherwise$ Null End Case end return READONLY_RECORD_PRE: // In order to stop a record from being read in this action these lines of code must be used: // // OrigFileError = 100 : @FM : KeyID // Status = 0 // Record = '' // ActionFlow = ACTION_STOP$ return READONLY_RECORD: // In order to stop a record from being read in this action these lines of code must be used: // // OrigFileError = 100 : @FM : KeyID // Status = 0 // Record = '' Shift = Record If Num(Shift) then Begin Case Case Shift EQ 1 Record = 'A' Case Shift EQ 2 Record = 'B' Case Shift EQ 3 Record = 'C' Case Shift EQ 4 Record = 'D' Case Otherwise$ Null End Case end return WRITE_RECORD_PRE: Shift = Record If Num(Shift) then Begin Case Case Shift EQ 1 Record = 'A' Case Shift EQ 2 Record = 'B' Case Shift EQ 3 Record = 'C' Case Shift EQ 4 Record = 'D' Case Otherwise$ Null End Case end SaveRecord = Record If OrigRecord NE Record then RDSNo = Name ProdTWs = '' GaNRunID = Record Scribes = {WFR_SCRIBES} SigProfile = Record SigProfileCnt = DCount(SigProfile, @VM) // Count the number of Test Wafers InWfrIDs = Record For each InWfrID in InWfrIDs using @VM setting vPos // Presume false until proven otherwise ProdTWs<0, vPos> = False$ If InWfrID NE '' then Scribe = Scribes<0, vPos> ScrapID = GaNRunID[1,7]:'W' If (Scribe[1, 8] EQ ScrapID) then ProdTWs<0, vPos> = True$ 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 ProdTWs<0, vPos> = True$ Destroyed = True$ end until Destroyed EQ True$ next SigProfileIndex end end Next InWfrID SaveRecord = ProdTWs end return WRITE_RECORD: WfrIDs = {IN_WFR_ID} For each WfrID in WfrIDs using @VM setting WfrIndex RetainBox = Xlate('WO_WFR', WfrID, 'RETAIN_BOX', 'X') If RetainBox NE '' then // Copy recipe and part number to RETAINED_WAFERS table RetWfrRec = Database_Services('ReadDataRow', 'RETAINED_WAFERS', WfrID) RetWfrRec = {GAN_RECIPE} RetWfrRec = {EPI_PART_NO} Database_Services('WriteDataRow', 'RETAINED_WAFERS', WfrID, RetWfrRec, True$, False$, True$) end Next WfrID *JRO WO_NO = {WO_NO} ReactType = XLATE('WO_LOG', WO_NO,67,'X') OrigUnloadDTMs = OrigRecord : @VM NewUnloadDTMs = Record : @VM //JRO 10/22/2020 IF ReactType EQ 'GAN' then //Jro IF OrigUnloadDTMs NE NewUnloadDTMs then StartDTM = Record StopDTM = Record OperatorStart = Record OperatorStop = Record StageName = 'EPI_DEPOSITION' Tool = 'R':Record ToolClass = 'GAN REACTOR' Exported = 0 RecordTime = Datetime() GanStageCycleTimeRecKey = @ID : '*EPI_DEPOSITION' GanStageCycleTimeRec = XLATE('GAN_STAGE_CYCLE_TIME', GanStageCycleTimeRecKey, '', 'X') GanStageCycleTimeRec = Insert(GanStageCycleTimeRec, GAN_STAGE_CYCLE_TIME_STAGE$, 1, 0, StageName) GanStageCycleTimeRec = Insert(GanStageCycleTimeRec, GAN_STAGE_CYCLE_TIME_START$, 1, 0, StartDTM) GanStageCycleTimeRec = Insert(GanStageCycleTimeRec, GAN_STAGE_CYCLE_TIME_STOP$, 1, 0, StopDTM) GanStageCycleTimeRec = Insert(GanStageCycleTimeRec, GAN_STAGE_CYCLE_TIME_WFR_ID$, 1, 0, '') GanStageCycleTimeRec = RecordTime GanStageCycleTimeRec = OperatorStart GanStageCycleTimeRec = OperatorStop GanStageCycleTimeRec = Tool GanStageCycleTimeRec = ToolClass GanStageCycleTimeRec = @ID IF StopDTM NE '' then Obj_Tables('WriteRec', 'GAN_STAGE_CYCLE_TIME':@RM:GanStageCycleTimeRecKey:@RM:@RM:GanStageCycleTimeRec) end //Jro end null end //JRO 10/22/2020 return DELETE_RECORD_PRE: return DELETE_RECORD: return //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Internal GoSubs //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ClearCursors: For counter = 0 to 8 ClearSelect counter Next counter return Initialize_System_Variables: // Save these for restoration later SaveDict = @DICT SaveID = @ID SaveRecord = @RECORD OrigFileError = @FILE.ERROR // Now make sure @DICT, ID, and @RECORD are populated CurrentDictName = '' If @DICT then DictHandle = @DICT<1, 2> Locate DictHandle in @TABLES(5) Using @FM Setting fPos then CurrentDictName = Field(@TABLES(0), @FM, fPos, 1) end end If CurrentDictName NE DictName then Open DictName to @DICT else Status = 'Unable to initialize @DICT' end @ID = KeyID If Record else // Record might not have been passed in. Read the record from the database table just to make sure. @FILE.ERROR = '' Open TableName to hTable then FullFSList = hTable[1, 'F' : @VM] BFS = FullFSList[-1, 'B' : @SVM] LastHandle = hTable[-1, 'B' : \0D\] FileHandle = \0D\ : LastHandle[1, @VM] Call @BFS(READO.RECORD, BFS, FileHandle, KeyID, FMC, Record, ReadOStatus) end end @RECORD = Record return Restore_System_Variables: Transfer SaveDict to @DICT Transfer SaveID to @ID Transfer SaveRecord to @RECORD @FILE.ERROR = OrigFileError return