Fixed scheduler bug causing cassettes to be marked as complete if they have not been received yet. Updated WIP commuter module to handle old react item wafer size format.

This commit is contained in:
Infineon\StieberD
2025-10-02 14:02:16 -07:00
parent acd7949e85
commit a2f61d11c9
5 changed files with 181 additions and 111 deletions

View File

@ -905,11 +905,11 @@ WRITE_RECORD:
WMIKeys = {WM_IN_KEY} WMIKeys = {WM_IN_KEY}
For each WMIKey in WMIKeys using @VM setting vPos For each WMIKey in WMIKeys using @VM setting vPos
CassNo = Field(WMIKey, '*', 3) CassNo = Field(WMIKey, '*', 3)
Service_Services('PostProcedure', 'SCHEDULE_SERVICES', 'MarkCassProcessed':SD$:WONo:SD$:CassNo:SD$:DatetimeOut) Service_Services('PostProcedure', 'SCHEDULE_SERVICES', 'UpdateCassProcStatus':SD$:WONo:SD$:CassNo:SD$:DatetimeOut)
Next WMIKey Next WMIKey
end else end else
CassNo = Record<RDS_CASS_NO$> CassNo = Record<RDS_CASS_NO$>
Service_Services('PostProcedure', 'SCHEDULE_SERVICES', 'MarkCassProcessed':SD$:WONo:SD$:CassNo:SD$:DatetimeOut) Service_Services('PostProcedure', 'SCHEDULE_SERVICES', 'UpdateCassProcStatus':SD$:WONo:SD$:CassNo:SD$:DatetimeOut)
end end
end end

View File

@ -1287,10 +1287,8 @@ Service AdjustScheduleEvents(ReactNo)
EventRec<SCHED_DET_NG.EVENT_TOTAL_WFRS$> = EventWfrs EventRec<SCHED_DET_NG.EVENT_TOTAL_WFRS$> = EventWfrs
Database_Services('WriteDataRow', 'SCHED_DET_NG', EventKey, EventRec, True$, False$, True$) Database_Services('WriteDataRow', 'SCHED_DET_NG', EventKey, EventRec, True$, False$, True$)
// Check each unprocessed cassette to ensure it does not need to be moved to the processed column // Check each cassette in the event to see if it is now processed or unprocessed (i.e., unload un-signed)
For each CassNo in UnprocessedCass using @VM Schedule_Services('UpdateEventCassLists', EventKey)
Schedule_Services('MarkCassProcessed', WONo, CassNo, Datetime())
Next CassNo
EventRec = Schedule_Services('GetScheduleDetail', EventKey) EventRec = Schedule_Services('GetScheduleDetail', EventKey)
UnprocessedCass = EventRec<SCHED_DET_NG.UNPROCESSED_CASS$> UnprocessedCass = EventRec<SCHED_DET_NG.UNPROCESSED_CASS$>
@ -2549,7 +2547,7 @@ end service
// Modifies an event's details. // Modifies an event's details.
//---------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------
Service ModifySchedEvent(SchedDetNGKey, ReactorNo, WorkOrderNo, StartDTM, StopDTM, Description, WaferQty, AdjustNextEvent=BOOLEAN) Service ModifySchedEvent(SchedDetNGKey, ReactorNo, WorkOrderNo, StartDTM, StopDTM, Description, WaferQty, AdjustNextEvent=BOOLEAN)
Response = False$ Response = False$
If SchedDetNGKey NE '' then If SchedDetNGKey NE '' then
EventRec = Database_Services('ReadDataRow', 'SCHED_DET_NG', SchedDetNGKey) EventRec = Database_Services('ReadDataRow', 'SCHED_DET_NG', SchedDetNGKey)
@ -3261,87 +3259,155 @@ Service GetAvailableWorkOrders(ReactorType, SusceptorSize, ReactorNo)
end service end service
Service MarkCassProcessed(WONo, CassNo, ProcessedDTM) Service UpdateCassProcStatus(WONo, CassNo, ProcessedDTM)
ErrorMsg = ''
If ((WONo NE '') and (CassNo NE '') and (ProcessedDTM NE '') ) then If ((WONo NE '') and (CassNo NE '') and (ProcessedDTM NE '') ) then
If Num(ProcessedDTM) then ProcessedDTM = OConv(ProcessedDTM, 'DT2/^H') If Num(ProcessedDTM) then ProcessedDTM = OConv(ProcessedDTM, 'DT2/^H')
// Find the SCHED_DET_NG event record that contains the cassette number // Find the SCHED_DET_NG event record that contains the cassette number
Query = 'SELECT SCHED_DET_NG WITH WO_NO EQ ':WONo:' AND WITH START_DTM LE "':ProcessedDTM:'" ' Query = 'SELECT SCHED_DET_NG WITH WO_NO EQ ':WONo:' AND WITH START_DTM LE "':ProcessedDTM:'" '
Query := 'AND WITH UNPROCESSED_CASS EQ ':CassNo:' BY START_DTM' Query := 'AND WITH UNPROCESSED_CASS EQ ':CassNo:' OR WITH PROCESSED_CASS EQ ':CassNo:' BY START_DTM'
GoSub ClearCursors GoSub ClearCursors
RList(Query, TARGET_ACTIVELIST$, '', '', '') RList(Query, TARGET_ACTIVELIST$, '', '', '')
EOF = False$ EOF = False$
Done = False$ Done = False$
Loop Loop
Readnext SchedDetNGKey else EOF = True$ Readnext SchedDetNGKey else EOF = True$
Until EOF = True$ Until EOF
SchedDetNGRec = Database_Services('ReadDataRow', 'SCHED_DET_NG', SchedDetNGKey) Schedule_Services('UpdateEventCassProcStatus', WONo, CassNo, SchedDetNGKey)
CassComp = False$ If Error_Services('HasError') then ErrorMsg = Error_Services('GetMessage')
ReactType = Xlate('WO_LOG', WONo, 'REACT_TYPE', 'X') Done = True$
Until Done
Repeat
end else
ErrorMsg = 'Error in ':Service:' service. WONo, CassNo, and ProcessedDTM cannot be null'
end
If ErrorMsg NE '' then Error_Services('Add', ErrorMsg)
end service
Service UpdateEventCassProcStatus(WONo, CassNo, SchedDetNGKey)
ErrorMsg = ''
If ( (WONo NE '') and (CassNo NE '') and (SchedDetNGKey NE '') ) then
SchedDetNGRec = Database_Services('ReadDataRow', 'SCHED_DET_NG', SchedDetNGKey)
If Error_Services('NoError') then
RecChanged = False$
CassComp = False$
UnprocCassList = SchedDetNGRec<SCHED_DET_NG.UNPROCESSED_CASS$>
ProcCassList = SchedDetNGRec<SCHED_DET_NG.PROCESSED_CASS$>
AllSchedCass = SRP_Array('Join', UnprocCassList, ProcCassList, 'OR', @VM)
AllSchedCass = SRP_Array('SortSimpleList', AllSchedCass, 'AscendingNumbers', @VM)
ReactType = Xlate('WO_LOG', WONo, 'REACT_TYPE', 'X')
If ReactType EQ 'EPP' then If ReactType EQ 'EPP' then
// Since EpiPro splits WM_IN cassettes out into RDS runs, we need to determine if the
// cassette has been emptied out or if enough wafers have been consumed such that
// the wafer count equals the split work order event quantity.
StopDtm = SchedDetNGRec<SCHED_DET_NG.STOP_DTM$>
SchedWfrQty = Schedule_Services('GetScheduledWfrQty', WONo, StopDtm)
// Determine the cassette and slot this event should end on. This will be used to identify
// cassettes that should be marked as complete when the event ends in the middle of the cassette.
// That is, the EpiPro work order events should end on an RDS when they are split around block
// out events.
UnprocCassList = SchedDetNGRec<SCHED_DET_NG.UNPROCESSED_CASS$>
ProcCassList = SchedDetNGRec<SCHED_DET_NG.PROCESSED_CASS$>
AllSchedCass = SRP_Array('Join', UnprocCassList, ProcCassList, 'OR', @VM)
AllSchedCass = SRP_Array('SortSimpleList', AllSchedCass, 'AscendingNumbers', @VM)
NumSchedCass = DCount(AllSchedCass, @VM)
EndCassNo = AllSchedCass<0, NumSchedCass>
EndSlotNo = Mod(SchedWfrQty, 25)
If EndSlotNo EQ 0 then EndSlotNo = 25
WMIKey = WONo:'*1*':CassNo WMIKey = WONo:'*1*':CassNo
WMIRdsList = Xlate('WM_IN', WMIKey, 'RDS_NO', 'X') If RowExists('WM_IN', WMIKey) then
UnloadDtms = Xlate('RDS', WMIRdsList, 'DATETIME_OUT', 'X') // Since EpiPro splits WM_IN cassettes out into RDS runs, we need to determine if the
NumUnloadedWfrs = 0 // cassette has been emptied out or if enough wafers have been consumed such that
If UnloadDtms NE '' then // the wafer count equals the split work order event quantity.
For each UnloadDtm in UnloadDtms using @VM StopDtm = SchedDetNGRec<SCHED_DET_NG.STOP_DTM$>
NumUnloadedWfrs += (UnloadDtm NE '') SchedWfrQty = Schedule_Services('GetScheduledWfrQty', WONo, StopDtm)
Next UnloadDtm // Determine the cassette and slot this event should end on. This will be used to identify
end // cassettes that should be marked as complete when the event ends in the middle of the cassette.
CassRemWfrs = Xlate('WM_IN', WMIKey, 'REM_WFRS', 'X') // That is, the EpiPro work order events should end on an RDS when they are split around block
If ( (NumUnloadedWfrs EQ 25) or ( (CassNo EQ EndCassNo) and (NumUnloadedWfrs GE EndSlotNo) ) or (CassRemWfrs EQ 0) ) then // out events.
CassComp = True$ NumSchedCass = DCount(AllSchedCass, @VM)
EndCassNo = AllSchedCass<0, NumSchedCass>
EndSlotNo = Mod(SchedWfrQty, 25)
If EndSlotNo EQ 0 then EndSlotNo = 25
WMIRdsList = Xlate('WM_IN', WMIKey, 'RDS_NO', 'X')
UnloadDtms = Xlate('RDS', WMIRdsList, 'DATETIME_OUT', 'X')
NumUnloadedWfrs = 0
If UnloadDtms NE '' then
For each UnloadDtm in UnloadDtms using @VM
NumUnloadedWfrs += (UnloadDtm NE '')
Next UnloadDtm
end
CassRemWfrs = Xlate('WM_IN', WMIKey, 'REM_WFRS', 'X')
If ( (NumUnloadedWfrs EQ 25) or ( (CassNo EQ EndCassNo) and (NumUnloadedWfrs GE EndSlotNo) ) or (CassRemWfrs EQ 0) ) then
CassComp = True$
end
end end
end else end else
WOMatKey = WoNo:'*':CassNo WOMatKey = WoNo:'*':CassNo
CurrWaferCount = obj_WO_Mat('CurrWaferCnt', WOMatKey) If RowExists('WO_MAT', WOMatKey) then
RDSNo = Xlate('WO_MAT', WOMatKey, 'RDS_NO', 'X') CurrWaferCount = obj_WO_Mat('CurrWaferCnt', WOMatKey)
DateOut = Xlate('RDS', RDSNo, 'DATE_OUT', 'X') RDSNo = Xlate('WO_MAT', WOMatKey, 'RDS_NO', 'X')
CassComp = ( (CurrWaferCount EQ 0) or (DateOut NE '') ) DateOut = Xlate('RDS', RDSNo, 'DATE_OUT', 'X')
CassComp = ( (CurrWaferCount EQ 0) or (DateOut NE '') )
end
end end
If CassComp then If CassComp then
RecChanged = False$ Locate CassNo in UnprocCassList using @VM setting vPos then
UnprocessedCassettes = SchedDetNGRec<SCHED_DET_NG.UNPROCESSED_CASS$> UnprocCassList = Delete(UnprocCassList, 0, vPos, 0)
Locate CassNo in UnprocessedCassettes using @VM setting vPos then RecChanged = True$
UnprocessedCassettes = Delete(UnprocessedCassettes, 0, vPos, 0)
RecChanged = True$
end end
ProcessedCassettes = SchedDetNGRec<SCHED_DET_NG.PROCESSED_CASS$> Locate CassNo in ProcCassList using @VM setting vPos else
Locate CassNo in ProcessedCassettes using @VM setting vPos else ProcCassList<0, -1> = CassNo
ProcessedCassettes<0, -1> = CassNo ProcCassList = SRP_Array('Clean', ProcCassList, 'TrimAndMakeUnique', @VM)
ProcessedCassettes = SRP_Array('Clean', ProcessedCassettes, 'TrimAndMakeUnique', @VM) ProcCassList = SRP_Array('SortSimpleList', ProcCassList, 'AscendingNumbers', @VM)
ProcessedCassettes = SRP_Array('SortSimpleList', ProcessedCassettes, 'AscendingNumbers', @VM) RecChanged = True$
RecChanged = True$
end end
If RecChanged then end else
SchedDetNGRec<SCHED_DET_NG.UNPROCESSED_CASS$> = UnprocessedCassettes Locate CassNo in ProcCassList using @VM setting vPos then
SchedDetNGRec<SCHED_DET_NG.PROCESSED_CASS$> = ProcessedCassettes ProcCassList = Delete(ProcCassList, 0, vPos, 0)
Database_Services('WriteDataRow', 'SCHED_DET_NG', SchedDetNGKey, SchedDetNGRec, True$, False$, True$) RecChanged = True$
end
Locate CassNo in UnprocCassList using @VM setting vPos else
UnprocCassList<0, -1> = CassNo
UnprocCassList = SRP_Array('Clean', UnprocCassList, 'TrimAndMakeUnique', @VM)
UnprocCassList = SRP_Array('SortSimpleList', UnprocCassList, 'AscendingNumbers', @VM)
RecChanged = True$
end end
Done = True$
end end
Until Done EQ True$ end else
Repeat ErrorMsg = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
end
If RecChanged then
SchedDetNGRec<SCHED_DET_NG.UNPROCESSED_CASS$> = UnprocCassList
SchedDetNGRec<SCHED_DET_NG.PROCESSED_CASS$> = ProcCassList
Database_Services('WriteDataRow', 'SCHED_DET_NG', SchedDetNGKey, SchedDetNGRec, True$, False$, True$)
If Error_Services('HasError') then ErrorMsg = Error_Services('GetMessage')
end
end end
If ErrorMsg NE '' then Error_Services('Add', ErrorMsg)
end service
Service UpdateEventCassLists(SchedDetNGKey)
ErrorMsg = ''
If (SchedDetNGKey NE '') then
If RowExists('SCHED_DET_NG', SchedDetNGKey) then
SchedDetNGRec = Database_Services('ReadDataRow', 'SCHED_DET_NG', SchedDetNGKey)
If Error_Services('NoError') then
UnprocCassList = SchedDetNGRec<SCHED_DET_NG.UNPROCESSED_CASS$>
ProcCassList = SchedDetNGRec<SCHED_DET_NG.PROCESSED_CASS$>
AllSchedCass = SRP_Array('Join', UnprocCassList, ProcCassList, 'OR', @VM)
AllSchedCass = SRP_Array('SortSimpleList', AllSchedCass, 'AscendingNumbers', @VM)
WONo = SchedDetNGRec<SCHED_DET_NG.WO_NO$>
For each CassNo in AllSchedCass using @VM
Schedule_Services('UpdateEventCassProcStatus', WONo, CassNo, SchedDetNGKey)
If Error_Services('HasError') then ErrorMsg = Error_Services('GetMessage')
Until (ErrorMsg NE '')
Next CassNo
end else
ErrorMsg = 'Error in ':Service:' service. Error message: ':Error_Services('GetMessage')
end
end else
ErrorMsg = 'Error in ':Service:' service. SCHED_DET_NG ':SchedDetNGKey:' does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. SchedDetNGKey cannot be null.'
end
If ErrorMsg NE '' then Error_Services('Add', ErrorMsg)
end service end service

View File

@ -165,7 +165,7 @@ WRITE_RECORD:
CassNo = Field(Name, '*', 3) CassNo = Field(Name, '*', 3)
ProcessedDTM = Datetime() ProcessedDTM = Datetime()
// This service will determine if the cassette needs to be marked as complete. // This service will determine if the cassette needs to be marked as complete.
Service_Services('PostProcedure', 'SCHEDULE_SERVICES', 'MarkCassProcessed':SD$:WONo:SD$:CassNo:SD$:ProcessedDtm) Service_Services('PostProcedure', 'SCHEDULE_SERVICES', 'UpdateCassProcStatus':SD$:WONo:SD$:CassNo:SD$:ProcessedDtm)
WfrCount = DCount(Record<WM_IN_SLOT_NO$>, @VM) WfrCount = DCount(Record<WM_IN_SLOT_NO$>, @VM)
If WfrCount LT 25 then If WfrCount LT 25 then

View File

@ -215,15 +215,20 @@ FORM_CREATE:
END END
DailySchedName = 'WO_DAILY_SCHED':I DailySchedName = 'WO_DAILY_SCHED':I
DSR = XLATE( 'CONFIG', DailySchedName, '', 'X' ) DSR = XLATE( 'CONFIG', DailySchedName, '', 'X' )
WOCust = DSR<WOCust$> WOCust = DSR<WOCust$>
WO = FIELD( WOCust, ' ', 1 ) WO = FIELD( WOCust, ' ', 1 )
Cust = FIELD( WOCust, ' ', 2, 999 ) Cust = FIELD( WOCust, ' ', 2, 999 )
Size = Xlate('REACTOR', I, REACTOR_SUSC_POCKET_SIZE$, 'X') Size = Xlate('REACTOR', I, REACTOR_SUSC_POCKET_SIZE$, 'X')
Size = Field(Size, ' ' , 3, 2) Begin Case
Case Index(Size, '6', 1)
CONVERT ' ' TO '' IN Size Size = '6in'
Case Index(Size, '8', 1)
Size = '8in'
Case Otherwise$
Size = ''
End Case
WONo = WO[1,'.'] WONo = WO[1,'.']
@ -325,4 +330,3 @@ REACT_DETAIL:
return return
*===============================================================================================* *===============================================================================================*

View File

@ -269,45 +269,45 @@ return
WRITE_RECORD_PRE: WRITE_RECORD_PRE:
WOMatKeyID = Name WOMatKeyID = Name
Void = Record<WO_MAT_VOID$>
CriticalFields = WO_MAT_RDS_NO$:@VM:WO_MAT_LOT_NO$:@VM:WO_MAT_WAFER_QTY$:@VM:WO_MAT_CUST_PART_NO$:@VM If (Void NE True$) then
CriticalFields := WO_MAT_SUB_PART_NO$:@VM:WO_MAT_INV_ACTION$:@VM:WO_MAT_SLOT_NO$:@VM:WO_MAT_RX_DTM$:@VM CriticalFields = WO_MAT_RDS_NO$:@VM:WO_MAT_LOT_NO$:@VM:WO_MAT_WAFER_QTY$:@VM:WO_MAT_CUST_PART_NO$:@VM
CriticalFields := WO_MAT_RX_BY$:@VM:WO_MAT_REL_DTM$:@VM:WO_MAT_REL_BY$:@VM:WO_MAT_SUB_VEND_CD$:@VM CriticalFields := WO_MAT_SUB_PART_NO$:@VM:WO_MAT_INV_ACTION$:@VM:WO_MAT_SLOT_NO$:@VM:WO_MAT_RX_DTM$:@VM
CriticalFields := WO_MAT_CASS_SHIP_QTY$:@VM:WO_MAT_SHIP_SHORT$:@VM:WO_MAT_MU_WAFER_FLAG$ CriticalFields := WO_MAT_RX_BY$:@VM:WO_MAT_REL_DTM$:@VM:WO_MAT_REL_BY$:@VM:WO_MAT_SUB_VEND_CD$:@VM
CriticalFields := WO_MAT_CASS_SHIP_QTY$:@VM:WO_MAT_SHIP_SHORT$:@VM:WO_MAT_MU_WAFER_FLAG$
For each CriticalField in CriticalFields using @VM setting vPos
For each CriticalField in CriticalFields using @VM setting vPos
If ( (OrigRecord<CriticalField> NE '') and (Record<CriticalField> EQ '') ) then
WOMatFieldNos = Xlate('DICT.WO_MAT', '%FIELDS%', DICT_PART$, 'X') If ( (OrigRecord<CriticalField> NE '') and (Record<CriticalField> EQ '') ) then
WOMatFieldNames = Xlate('DICT.WO_MAT', '%FIELDS%', DICT_DISPLAY$, 'X') WOMatFieldNos = Xlate('DICT.WO_MAT', '%FIELDS%', DICT_PART$, 'X')
Locate CriticalField in WOMatFieldNos using @VM setting FieldNo then WOMatFieldNames = Xlate('DICT.WO_MAT', '%FIELDS%', DICT_DISPLAY$, 'X')
CriticalFieldName = WOMatFieldNames<0, FieldNo> Locate CriticalField in WOMatFieldNos using @VM setting FieldNo then
end else CriticalFieldName = WOMatFieldNames<0, FieldNo>
CriticalFieldName = 'Error determining field name' end else
end CriticalFieldName = 'Error determining field name'
end
Recipients = ''
SentFrom = 'SYSTEM' Recipients = ''
Subject = 'WO_MAT_ACTIONS - Critical Field Erased' SentFrom = 'SYSTEM'
Message = OConv(Datetime(), 'DT2/^H') Subject = 'WO_MAT_ACTIONS - Critical Field Erased'
Message<2> = 'Computer: ':@Station Message = OConv(Datetime(), 'DT2/^H')
Message<3> = 'User: ':@User4 Message<2> = 'Computer: ':@Station
Message<4> = 'WO_MAT key: ':Name Message<3> = 'User: ':@User4
NoteMessage = 'Readonly field ':CriticalField:' (':CriticalFieldName:') erased. Value erased ':Quote(OrigRecord<CriticalField>) Message<4> = 'WO_MAT key: ':Name
Message<5> = NoteMessage NoteMessage = 'Readonly field ':CriticalField:' (':CriticalFieldName:') erased. Value erased ':Quote(OrigRecord<CriticalField>)
Message<6> = 'Call Stack:':CRLF$:RetStack() Message<5> = NoteMessage
Swap @FM with \0D0A\ in Message Message<6> = 'Call Stack:':CRLF$:RetStack()
Swap @VM with ',' in Message Swap @FM with \0D0A\ in Message
AttachWindow = 'WO_MAT' Swap @VM with ',' in Message
AttachKey = Name AttachWindow = 'WO_MAT'
SendToGroup = 'OI_SYSADMIN' AttachKey = Name
Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup SendToGroup = 'OI_SYSADMIN'
obj_Notes('Create',Parms) Parms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup
end obj_Notes('Create',Parms)
end
Next CriticalField Next CriticalField
end
SaveRecord = Record
WaferQty = Record<WO_MAT_WAFER_QTY$> WaferQty = Record<WO_MAT_WAFER_QTY$>
If ( (WaferQty LT 0) or (WaferQty GT 25) ) then If ( (WaferQty LT 0) or (WaferQty GT 25) ) then
@ -878,7 +878,7 @@ WRITE_RECORD:
CurrWaferCount = obj_WO_Mat('CurrWaferCnt', WOMatKeyID) CurrWaferCount = obj_WO_Mat('CurrWaferCnt', WOMatKeyID)
If CurrWaferCount EQ 0 then If CurrWaferCount EQ 0 then
// This should catch cases where the entire cassette is "peeled off", NCR'ed, or used for destructive testing. // This should catch cases where the entire cassette is "peeled off", NCR'ed, or used for destructive testing.
Service_Services('PostProcedure', 'SCHEDULE_SERVICES', 'MarkCassProcessed':SD$:WONo:SD$:CassNo:SD$:Datetime()) Service_Services('PostProcedure', 'SCHEDULE_SERVICES', 'UpdateCassProcStatus':SD$:WONo:SD$:CassNo:SD$:Datetime())
end end
return return