open-insight/LSL2/STPROC/REACTOR_SERVICES.txt
Infineon\StieberD 9d4ae3c5b3 added intrusive maintenance flow logic
updated headers for nica order request

Added reactor type support to nica checklists. Refactored flow logic to just use NICA_CHECKLISTS table.

added feature flag support

gated Feature Flags menu item to supervisors

removed debug

added auto comment for intr maint flows on reactor log, intr maint flow id to react servs form, and cancel order on unsign reactor log

added exceptions for lamp and tc services, added control to edit flow id on react servs form, added auto-reactor log comment, added cancel order on unsign event

removed debug

modified NicaOrdersServices to use env variables for group resource name

added logic to filter out service flow ids for servics with is_intrusive set to false, modified security group for feature flag menu, added ability to clear intr main flow id to react serv form

removed unused equates
2025-03-12 16:28:52 -07:00

3722 lines
189 KiB
Plaintext

Function Reactor_Services(@Service, @Params)
/***********************************************************************************************************************
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 SRP Computer Solutions, Inc.
Name : Reactor_Services
Description : Handler program for all module related services.
Notes : The generic parameters should contain all the necessary information to process the services. Often
this will be information like the data Record and Key ID.
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)
08/10/17 dmb Original programmer. Adapted from Scheduling_Services. - [IREPIOI-8]
01/08/18 dmb Update the CreatePerformanceTrackers service so the CreateWeeklyPerformanceReport is called
on Friday mornings for the upcoming week rather than Monday mornings for the current week.
- [IREPIOI-14]
02/17/18 dmb Add logging to track reactor performance activities. - [IREPIOI-14]
05/30/18 dmb Update various services to allow newer reactors to be used for reporting. - [IREPIOI-17]
06/21/18 dmb Update the path where templates and reports are stored. - [IREPIOI-33]
06/26/18 dmb Add logging to track when this service is being called. - [IREPIOI-56]
06/26/18 dmb Update logic on how reactors are selected for reporting. - [IREPIOI-56]
04/20/21 djs Added PickPlace to objReactor JSON object in GetReactor service.
12/06/23 djm Add MD3 conversion to TargetThickness in metric increment and decrement services.
***********************************************************************************************************************/
#pragma precomp SRP_PreCompiler
$insert APP_INSERTS
$insert SERVICE_SETUP
$insert REACTOR_EQUATES
$insert RDS_EQUATES
$insert RLIST_EQUATES
$insert TOOL_EQUATES
$Insert REACTOR_LOG_EQUATES
$Insert REACTOR_CHILD_KEY_IDS_EQUATES
$Insert REACTOR_MODES_EQUATES
$Insert REACT_MODE_EQU ;* THESE ARE NOT THE SAME jch, Update 9/15/21. These are the equates for the CONFIG records
$Insert REACT_MODE_NG_EQUATES
$Insert REACT_UTIL_EQU
$Insert SCHED_DET_NG_EQUATES
$Insert REACT_STATUS_EQUATES
$Insert WO_LOG_EQUATES
$Insert REACTOR_DAILY_UPTIME_EQUATES
$Insert REACT_LL_EQUATES
$Insert IQS_VIOL_DATA_EQUATES
$Insert FEATURE_FLAGS_EQUATES
Equ WOCust$ to 2
// Uptime Percentage Equates
Equ PRODUCTIVE$ to 1
Equ UNSCHED$ to 2
Equ SCHED$ to 3
Equ NONSCHED$ to 4
Equ ENG$ to 5
Declare subroutine Error_Services, Reactor_Services, Memory_Services, RList, Database_Services, SRP_JSON
Declare subroutine Excel_Services, Schedule_Services, Logging_Services, Set_Status, obj_React_Status, Errmsg
Declare subroutine Obj_Notes, Btree.Extract, SRP_Fastarray, Delay, Mona_Services, SRP_List, Msg, Rds_Services
Declare subroutine React_Assign_Conv, Nica_Orders_Services, obj_React_Mode
Declare function SRP_Array, Reactor_Services, Memory_Services, Database_Services, SRP_Sort_Array, Excel_Services
Declare function SRP_Math, SRP_Hash, SRP_JSON, Epi_Part_Services, Schedule_Services, Date_Services, Environment_Services
Declare function Logging_Services, GetCommandLine, NextKey, Reactor_Log_Services, SRP_DateTime, ole_getwebpage
Declare function Datetime, Reactor_Modes_Services, Work_Order_Services, React_Mode_NG_Services, Lsl_Users_Services
Declare function SRP_Time, Rds_Services, SRP_Fastarray, Httpclient_Services, SRP_List, Utility, Memberof, Error_Services
Declare function Nica_Orders_Services
// Report paths for various performance report services.
TemplatesFolder = Environment_Services('GetApplicationRootPath') : '\Reports\Scheduler\Templates\'
DailyReportsFolder = Environment_Services('GetApplicationRootPath') : '\Reports\Scheduler\Daily\'
WeeklyReportsFolder = Environment_Services('GetApplicationRootPath') : '\Reports\Scheduler\Weekly\'
CommandLine = GetCommandLine()
Machine = Environment_Services('GetServer')
LogDate = Oconv(Date(), 'D4/')
LogTime = Oconv(Time(), 'MTS')
LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM
GoToService else
end
Return Response else ''
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Service Parameter Options
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Options BOOLEAN = True$, False$
Options REACTORMETRIC = 'TUBE_BELL_JAR_THK', 'TUBE_BELL_JAR_WFR_CNT', 'SUSC_THK', 'SUSC_WFR_CNT', 'LOWER_QUARTZ_THK', 'LOWER_QUARTZ_WFR', 'ARMS_WFR_CNT'
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Services
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//----------------------------------------------------------------------------------------------------------------------
// IncrementWfrMetrics
//
// RDSNo. - [Required]
//
// Increment the REACTOR wafer count and thickness when RDS unload is signed.
//
//----------------------------------------------------------------------------------------------------------------------
Service IncrementWfrMetrics(RDSNo)
// Get Reactor and run count details
RDSRec = Xlate('RDS', RDSNo, '', 'X', '')
TargetThickness = Xlate('RDS', RDSNo, 'THICK_TARGET_TOT', 'X', '')
TargetThickness = OConv(TargetThickness, 'MD3')
WaferCount = RDSRec<RDS_WAFERS_IN$>
ReactorNo = RDSRec<RDS_REACTOR$>
OldReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactorNo)
NewReactorRec = OldReactorRec
ReactorType = OldReactorRec<REACTOR_REACT_TYPE$>
SusceptorSize = OldReactorRec<REACTOR_SUSC_POCKET_SIZE$>
SusceptorSize = SusceptorSize[-4,1]
// Get Old Values
CurrTubeBellJarThk = OldReactorRec<REACTOR_TUBE_BELL_JAR_THK$>
CurrTubeBellJarCnt = OldReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$>
CurrSuscThk = OldReactorRec<REACTOR_SUSC_THK$>
CurrSuscWfrCnt = OldReactorRec<REACTOR_SUSC_WFR_CNT$>
CurrLowerQuartzThk = OldReactorRec<REACTOR_LOWER_QUARTZ_THK$>
CurrLowerQuartzWfr = OldReactorRec<REACTOR_LOWER_QUARTZ_WFR$>
// Arms are not used for EPP
If ReactorType NE 'EPP' then
CurrArmsWfrCnt = OldReactorRec<REACTOR_ARMS_WFR_CNT$>
If CurrArmsWfrCnt = '' then CurrArmsWfrCnt = 0
end
// Set values to 0 if blank
If CurrTubeBellJarThk = '' then CurrTubeBellJarThk = 0
If CurrTubeBellJarCnt = '' then CurrTubeBellJarCnt = 0
If CurrSuscThk = '' then CurrSuscThk = 0
If CurrSuscWfrCnt = '' then CurrSuscWfrCnt = 0
If CurrLowerQuartzThk = '' then CurrLowerQuartzThk = 0
If CurrLowerQuartzWfr = '' then CurrLowerQuartzWfr = 0
Begin Case
Case ReactorType = 'EPP'
NewReactorRec<REACTOR_TUBE_BELL_JAR_THK$> = CurrTubeBellJarThk + TargetThickness
NewReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$> = CurrTubeBellJarCnt + 1
NewReactorRec<REACTOR_SUSC_THK$> = CurrSuscThk + TargetThickness
NewReactorRec<REACTOR_SUSC_WFR_CNT$> = CurrSuscWfrCnt + 1
NewReactorRec<REACTOR_LOWER_QUARTZ_THK$> = CurrLowerQuartzThk + TargetThickness
NewReactorRec<REACTOR_LOWER_QUARTZ_WFR$> = CurrLowerQuartzWfr + 1
Case ReactorType = 'HTR'
Begin Case
Case SusceptorSize = 6
CntAddition = (WaferCount / 5)
ThkAddition = (WaferCount / 5) * TargetThickness
NewReactorRec<REACTOR_TUBE_BELL_JAR_THK$> = CurrTubeBellJarThk + ThkAddition
NewReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$> = CurrTubeBellJarCnt + CntAddition
NewReactorRec<REACTOR_SUSC_THK$> = CurrSuscThk + ThkAddition
NewReactorRec<REACTOR_SUSC_WFR_CNT$> = CurrSuscWfrCnt + CntAddition
NewReactorRec<REACTOR_LOWER_QUARTZ_THK$> = CurrLowerQuartzThk + ThkAddition
NewReactorRec<REACTOR_LOWER_QUARTZ_WFR$> = CurrLowerQuartzWfr + CntAddition
NewReactorRec<REACTOR_ARMS_WFR_CNT$> = CurrArmsWfrCnt + WaferCount
Case SusceptorSize = 8
// Round up
CntAddition = (WaferCount / 3)
If Count(CntAddition, '.') EQ 1 Then
CntAddition = Int(CntAddition) + 1
end
ThkAddition = (WaferCount / 3) * TargetThickness
NewReactorRec<REACTOR_TUBE_BELL_JAR_THK$> = CurrTubeBellJarThk + ThkAddition
NewReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$> = CurrTubeBellJarCnt + CntAddition
NewReactorRec<REACTOR_SUSC_THK$> = CurrSuscThk + ThkAddition
NewReactorRec<REACTOR_SUSC_WFR_CNT$> = CurrSuscWfrCnt + CntAddition
NewReactorRec<REACTOR_LOWER_QUARTZ_THK$> = CurrLowerQuartzThk + ThkAddition
NewReactorRec<REACTOR_LOWER_QUARTZ_WFR$> = CurrLowerQuartzWfr + CntAddition
NewReactorRec<REACTOR_ARMS_WFR_CNT$> = CurrArmsWfrCnt + WaferCount
End Case
Case ReactorType = 'ASM' OR ReactorType = 'ASM+'
ThkAddition = WaferCount * TargetThickness
NewReactorRec<REACTOR_TUBE_BELL_JAR_THK$> = CurrTubeBellJarThk + ThkAddition
NewReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$> = CurrTubeBellJarCnt + WaferCount
NewReactorRec<REACTOR_SUSC_THK$> = CurrSuscThk + ThkAddition
NewReactorRec<REACTOR_SUSC_WFR_CNT$> = CurrSuscWfrCnt + WaferCount
NewReactorRec<REACTOR_LOWER_QUARTZ_THK$> = CurrLowerQuartzThk + ThkAddition
NewReactorRec<REACTOR_LOWER_QUARTZ_WFR$> = CurrLowerQuartzWfr + WaferCount
NewReactorRec<REACTOR_ARMS_WFR_CNT$> = CurrArmsWfrCnt + WaferCount
End Case
Database_Services('WriteDataRow', 'REACTOR', ReactorNo, NewReactorRec, 1, 0, 0)
end service
Service GetWaferCntMetricsByReactorID(ReactorID)
If ReactorID NE '' then
If RowExists('REACTOR', ReactorID) then
ReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactorID)
ReactorType = ReactorRec<REACTOR_REACT_TYPE$>
ResponseData = ''
Begin Case
Case ReactorType EQ 'ASM' OR ReactorType EQ 'ASM+'
ResponseData<1, 1> = ReactorID
ResponseData<1, 2> = ReactorRec<REACTOR_SUSC_WFR_CNT$>
ResponseData<1, 3> = ReactorRec<REACTOR_SUSC_THK$>
ResponseData<1, 4> = ReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$>
ResponseData<1, 5> = ReactorRec<REACTOR_TUBE_BELL_JAR_THK$>
ResponseData<1, 6> = ReactorRec<REACTOR_ARMS_WFR_CNT$>
//These are the column titles to help us with API Responses
ResponseData<2, 1> = 'ReactorID'
ResponseData<2, 2> = 'SusceptorWaferCount'
ResponseData<2, 3> = 'SusceptorThickness'
ResponseData<2, 4> = 'TubeWaferCount'
ResponseData<2, 5> = 'TubeThickness'
ResponseData<2, 6> = 'ArmsWaferCount'
Case ReactorType EQ 'HTR'
ResponseData<1, 1> = ReactorID
ResponseData<1, 2> = ReactorRec<REACTOR_SUSC_WFR_CNT$>
ResponseData<1, 3> = ReactorRec<REACTOR_SUSC_THK$>
ResponseData<1, 4> = ReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$>
ResponseData<1, 5> = ReactorRec<REACTOR_TUBE_BELL_JAR_THK$>
ResponseData<1, 6> = ReactorRec<REACTOR_ARMS_WFR_CNT$>
//These are the column titles to help us with API Responses
ResponseData<2, 1> = 'ReactorID'
ResponseData<2, 2> = 'SusceptorWaferCount'
ResponseData<2, 3> = 'SusceptorThickness'
ResponseData<2, 4> = 'TubeWaferCount'
ResponseData<2, 5> = 'TubeThickness'
ResponseData<2, 6> = 'ArmsWaferCount'
Case ReactorType EQ 'EPP'
ResponseData<1, 1> = ReactorID
ResponseData<1, 2> = ReactorRec<REACTOR_SUSC_WFR_CNT$>
ResponseData<1, 3> = ReactorRec<REACTOR_SUSC_THK$>
ResponseData<1, 4> = ReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$>
ResponseData<1, 5> = ReactorRec<REACTOR_TUBE_BELL_JAR_THK$>
ResponseData<1, 6> = ReactorRec<REACTOR_LOWER_QUARTZ_WFR$>
ResponseData<1, 7> = ReactorRec<REACTOR_LOWER_QUARTZ_THK$>
//These are the column titles to help us with API Responses
ResponseData<2, 1> = 'ReactorID'
ResponseData<2, 2> = 'SusceptorWaferCount'
ResponseData<2, 3> = 'SusceptorThickness'
ResponseData<2, 4> = 'BellJarWaferCount'
ResponseData<2, 5> = 'BellJarThickness'
ResponseData<2, 6> = 'LowerQuartzWaferCount'
ResponseData<2, 7> = 'LowerQuartzThickness'
End Case
Response = ResponseData
end else
Error_Services('Add', 'Error: Invalid Reactor ID passed to REACTOR_SERVICES("GetWaferMetricsByReactorID"')
end
end else
Error_Services('Add', 'Error: Null Reactor ID passed to REACTOR_SERVICES("GetWaferMetricsByReactorID"')
end
end service
//----------------------------------------------------------------------------------------------------------------------
// DecrementWfrMetrics
//
// RDSNo. - [Required]
//
// Decrement the REACTOR wafer count and thickness when RDS unload is unsigned.
//
//----------------------------------------------------------------------------------------------------------------------
Service DecrementWfrMetrics(RDSNo)
// Get Reactor and run count details
RDSRec = Xlate('RDS', RDSNo, '', 'X', '')
TargetThickness = Xlate('RDS', RDSNo, 'THICK_TARGET_TOT', 'X', '')
TargetThickness = OConv(TargetThickness, 'MD3')
WaferCount = RDSRec<RDS_WAFERS_IN$>
ReactorNo = RDSRec<RDS_REACTOR$>
OldReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactorNo)
NewReactorRec = OldReactorRec
ReactorType = OldReactorRec<REACTOR_REACT_TYPE$>
SusceptorSize = OldReactorRec<REACTOR_SUSC_POCKET_SIZE$>
SusceptorSize = SusceptorSize[-4,1]
// Get Old Values
CurrTubeBellJarThk = OldReactorRec<REACTOR_TUBE_BELL_JAR_THK$>
CurrTubeBellJarCnt = OldReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$>
CurrSuscThk = OldReactorRec<REACTOR_SUSC_THK$>
CurrSuscWfrCnt = OldReactorRec<REACTOR_SUSC_WFR_CNT$>
CurrLowerQuartzThk = OldReactorRec<REACTOR_LOWER_QUARTZ_THK$>
CurrLowerQuartzWfr = OldReactorRec<REACTOR_LOWER_QUARTZ_WFR$>
// Arms are not used for EPP
If ReactorType NE 'EPP' then
CurrArmsWfrCnt = OldReactorRec<REACTOR_ARMS_WFR_CNT$>
If CurrArmsWfrCnt = '' then CurrArmsWfrCnt = 0
end
// Set values to 0 if blank
If CurrTubeBellJarThk = '' then CurrTubeBellJarThk = 0
If CurrTubeBellJarCnt = '' then CurrTubeBellJarCnt = 0
If CurrSuscThk = '' then CurrSuscThk = 0
If CurrSuscWfrCnt = '' then CurrSuscWfrCnt = 0
If CurrLowerQuartzThk = '' then CurrLowerQuartzThk = 0
If CurrLowerQuartzWfr = '' then CurrLowerQuartzWfr = 0
Begin Case
Case ReactorType = 'EPP'
NewReactorRec<REACTOR_TUBE_BELL_JAR_THK$> = CurrTubeBellJarThk - TargetThickness
NewReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$> = CurrTubeBellJarCnt - 1
NewReactorRec<REACTOR_SUSC_THK$> = CurrSuscThk - TargetThickness
NewReactorRec<REACTOR_SUSC_WFR_CNT$> = CurrSuscWfrCnt - 1
NewReactorRec<REACTOR_LOWER_QUARTZ_THK$> = CurrLowerQuartzThk - TargetThickness
NewReactorRec<REACTOR_LOWER_QUARTZ_WFR$> = CurrLowerQuartzWfr - 1
Case ReactorType = 'HTR'
Begin Case
Case SusceptorSize = 6
CntAddition = (WaferCount / 5)
ThkAddition = (WaferCount / 5) * TargetThickness
NewReactorRec<REACTOR_TUBE_BELL_JAR_THK$> = CurrTubeBellJarThk - ThkAddition
NewReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$> = CurrTubeBellJarCnt - CntAddition
NewReactorRec<REACTOR_SUSC_THK$> = CurrSuscThk + ThkAddition
NewReactorRec<REACTOR_SUSC_WFR_CNT$> = CurrSuscWfrCnt - CntAddition
NewReactorRec<REACTOR_LOWER_QUARTZ_THK$> = CurrLowerQuartzThk - ThkAddition
NewReactorRec<REACTOR_LOWER_QUARTZ_WFR$> = CurrLowerQuartzWfr - CntAddition
NewReactorRec<REACTOR_ARMS_WFR_CNT$> = CurrArmsWfrCnt - WaferCount
Case SusceptorSize = 8
// Round up
CntAddition = (WaferCount / 3)
If Count(CntAddition, '.') EQ 1 Then
CntAddition = Int(CntAddition) + 1
end
ThkAddition = (WaferCount / 3) * TargetThickness
NewReactorRec<REACTOR_TUBE_BELL_JAR_THK$> = CurrTubeBellJarThk - ThkAddition
NewReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$> = CurrTubeBellJarCnt - CntAddition
NewReactorRec<REACTOR_SUSC_THK$> = CurrSuscThk - ThkAddition
NewReactorRec<REACTOR_SUSC_WFR_CNT$> = CurrSuscWfrCnt - CntAddition
NewReactorRec<REACTOR_LOWER_QUARTZ_THK$> = CurrLowerQuartzThk - ThkAddition
NewReactorRec<REACTOR_LOWER_QUARTZ_WFR$> = CurrLowerQuartzWfr - CntAddition
NewReactorRec<REACTOR_ARMS_WFR_CNT$> = CurrArmsWfrCnt - WaferCount
End Case
Case ReactorType = 'ASM' OR ReactorType = 'ASM+'
ThkAddition = WaferCount * TargetThickness
NewReactorRec<REACTOR_TUBE_BELL_JAR_THK$> = CurrTubeBellJarThk - ThkAddition
NewReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$> = CurrTubeBellJarCnt - WaferCount
NewReactorRec<REACTOR_SUSC_THK$> = CurrSuscThk - ThkAddition
NewReactorRec<REACTOR_SUSC_WFR_CNT$> = CurrSuscWfrCnt - WaferCount
NewReactorRec<REACTOR_LOWER_QUARTZ_THK$> = CurrLowerQuartzThk - ThkAddition
NewReactorRec<REACTOR_LOWER_QUARTZ_WFR$> = CurrLowerQuartzWfr - WaferCount
NewReactorRec<REACTOR_ARMS_WFR_CNT$> = CurrArmsWfrCnt - WaferCount
End Case
Database_Services('WriteDataRow', 'REACTOR', ReactorNo, NewReactorRec, 1, 0, 0)
end service
//----------------------------------------------------------------------------------------------------------------------
// IncrementTestWfrMetrics
//
// TargetThickness - [Required]
// WaferCount - [Required]
// ReactorNo - [Required]
//
// Increment the REACTOR wafer count and thickness for test wafers.
//
//----------------------------------------------------------------------------------------------------------------------
Service IncrementTestWfrMetrics(TargetThickness, WaferCount, ReactorNo)
OldReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactorNo)
NewReactorRec = OldReactorRec
ReactorType = OldReactorRec<REACTOR_REACT_TYPE$>
SusceptorSize = OldReactorRec<REACTOR_SUSC_POCKET_SIZE$>
SusceptorSize = SusceptorSize[-4,1]
// Get Old Values
CurrTubeBellJarThk = OldReactorRec<REACTOR_TUBE_BELL_JAR_THK$>
CurrTubeBellJarCnt = OldReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$>
CurrSuscThk = OldReactorRec<REACTOR_SUSC_THK$>
CurrSuscWfrCnt = OldReactorRec<REACTOR_SUSC_WFR_CNT$>
CurrLowerQuartzThk = OldReactorRec<REACTOR_LOWER_QUARTZ_THK$>
CurrLowerQuartzWfr = OldReactorRec<REACTOR_LOWER_QUARTZ_WFR$>
// Arms are not used for EPP
If ReactorType NE 'EPP' then
CurrArmsWfrCnt = OldReactorRec<REACTOR_ARMS_WFR_CNT$>
If CurrArmsWfrCnt = '' then CurrArmsWfrCnt = 0
end
// Set values to 0 if blank
If CurrTubeBellJarThk = '' then CurrTubeBellJarThk = 0
If CurrTubeBellJarCnt = '' then CurrTubeBellJarCnt = 0
If CurrSuscThk = '' then CurrSuscThk = 0
If CurrSuscWfrCnt = '' then CurrSuscWfrCnt = 0
If CurrLowerQuartzThk = '' then CurrLowerQuartzThk = 0
If CurrLowerQuartzWfr = '' then CurrLowerQuartzWfr = 0
Begin Case
Case ReactorType = 'EPP'
NewReactorRec<REACTOR_TUBE_BELL_JAR_THK$> = CurrTubeBellJarThk + TargetThickness
NewReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$> = CurrTubeBellJarCnt + 1
NewReactorRec<REACTOR_SUSC_THK$> = CurrSuscThk + TargetThickness
NewReactorRec<REACTOR_SUSC_WFR_CNT$> = CurrSuscWfrCnt + 1
NewReactorRec<REACTOR_LOWER_QUARTZ_THK$> = CurrLowerQuartzThk + TargetThickness
NewReactorRec<REACTOR_LOWER_QUARTZ_WFR$> = CurrLowerQuartzWfr + 1
Case ReactorType = 'HTR'
Begin Case
Case SusceptorSize = 6
CntAddition = (WaferCount / 5)
ThkAddition = (WaferCount / 5) * TargetThickness
NewReactorRec<REACTOR_TUBE_BELL_JAR_THK$> = CurrTubeBellJarThk + ThkAddition
NewReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$> = CurrTubeBellJarCnt + CntAddition
NewReactorRec<REACTOR_SUSC_THK$> = CurrSuscThk + ThkAddition
NewReactorRec<REACTOR_SUSC_WFR_CNT$> = CurrSuscWfrCnt + CntAddition
NewReactorRec<REACTOR_LOWER_QUARTZ_THK$> = CurrLowerQuartzThk + ThkAddition
NewReactorRec<REACTOR_LOWER_QUARTZ_WFR$> = CurrLowerQuartzWfr + CntAddition
NewReactorRec<REACTOR_ARMS_WFR_CNT$> = CurrArmsWfrCnt + WaferCount
Case SusceptorSize = 8
// Round up
CntAddition = (WaferCount / 3)
If Count(CntAddition, '.') EQ 1 Then
CntAddition = Int(CntAddition) + 1
end
ThkAddition = (WaferCount / 3) * TargetThickness
NewReactorRec<REACTOR_TUBE_BELL_JAR_THK$> = CurrTubeBellJarThk + ThkAddition
NewReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$> = CurrTubeBellJarCnt + CntAddition
NewReactorRec<REACTOR_SUSC_THK$> = CurrSuscThk + ThkAddition
NewReactorRec<REACTOR_SUSC_WFR_CNT$> = CurrSuscWfrCnt + CntAddition
NewReactorRec<REACTOR_LOWER_QUARTZ_THK$> = CurrLowerQuartzThk + ThkAddition
NewReactorRec<REACTOR_LOWER_QUARTZ_WFR$> = CurrLowerQuartzWfr + CntAddition
NewReactorRec<REACTOR_ARMS_WFR_CNT$> = CurrArmsWfrCnt + WaferCount
End Case
Case ReactorType = 'ASM' OR ReactorType = 'ASM+'
ThkAddition = WaferCount * TargetThickness
NewReactorRec<REACTOR_TUBE_BELL_JAR_THK$> = CurrTubeBellJarThk + ThkAddition
NewReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$> = CurrTubeBellJarCnt + WaferCount
NewReactorRec<REACTOR_SUSC_THK$> = CurrSuscThk + ThkAddition
NewReactorRec<REACTOR_SUSC_WFR_CNT$> = CurrSuscWfrCnt + WaferCount
NewReactorRec<REACTOR_LOWER_QUARTZ_THK$> = CurrLowerQuartzThk + ThkAddition
NewReactorRec<REACTOR_LOWER_QUARTZ_WFR$> = CurrLowerQuartzWfr + WaferCount
NewReactorRec<REACTOR_ARMS_WFR_CNT$> = CurrArmsWfrCnt + WaferCount
End Case
Database_Services('WriteDataRow', 'REACTOR', ReactorNo, NewReactorRec, 1, 0, 0)
end service
//----------------------------------------------------------------------------------------------------------------------
// DecrementTestWfrMetrics
//
// TargetThickness - [Required]
// WaferCount - [Required]
// ReactorNo - [Required]
//
// Decrement the REACTOR wafer count and thickness for test wafers.
//
//----------------------------------------------------------------------------------------------------------------------
Service DecrementTestWfrMetrics(TargetThickness, WaferCount, ReactorNo)
OldReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactorNo)
NewReactorRec = OldReactorRec
ReactorType = OldReactorRec<REACTOR_REACT_TYPE$>
SusceptorSize = OldReactorRec<REACTOR_SUSC_POCKET_SIZE$>
SusceptorSize = SusceptorSize[-4,1]
// Get Old Values
CurrTubeBellJarThk = OldReactorRec<REACTOR_TUBE_BELL_JAR_THK$>
CurrTubeBellJarCnt = OldReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$>
CurrSuscThk = OldReactorRec<REACTOR_SUSC_THK$>
CurrSuscWfrCnt = OldReactorRec<REACTOR_SUSC_WFR_CNT$>
CurrLowerQuartzThk = OldReactorRec<REACTOR_LOWER_QUARTZ_THK$>
CurrLowerQuartzWfr = OldReactorRec<REACTOR_LOWER_QUARTZ_WFR$>
// Arms are not used for EPP
If ReactorType NE 'EPP' then
CurrArmsWfrCnt = OldReactorRec<REACTOR_ARMS_WFR_CNT$>
If CurrArmsWfrCnt = '' then CurrArmsWfrCnt = 0
end
// Set values to 0 if blank
If CurrTubeBellJarThk = '' then CurrTubeBellJarThk = 0
If CurrTubeBellJarCnt = '' then CurrTubeBellJarCnt = 0
If CurrSuscThk = '' then CurrSuscThk = 0
If CurrSuscWfrCnt = '' then CurrSuscWfrCnt = 0
If CurrLowerQuartzThk = '' then CurrLowerQuartzThk = 0
If CurrLowerQuartzWfr = '' then CurrLowerQuartzWfr = 0
Begin Case
Case ReactorType = 'EPP'
NewReactorRec<REACTOR_TUBE_BELL_JAR_THK$> = CurrTubeBellJarThk - TargetThickness
NewReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$> = CurrTubeBellJarCnt - 1
NewReactorRec<REACTOR_SUSC_THK$> = CurrSuscThk - TargetThickness
NewReactorRec<REACTOR_SUSC_WFR_CNT$> = CurrSuscWfrCnt - 1
NewReactorRec<REACTOR_LOWER_QUARTZ_THK$> = CurrLowerQuartzThk - TargetThickness
NewReactorRec<REACTOR_LOWER_QUARTZ_WFR$> = CurrLowerQuartzWfr - 1
Case ReactorType = 'HTR'
Begin Case
Case SusceptorSize = 6
CntAddition = (WaferCount / 5)
ThkAddition = (WaferCount / 5) * TargetThickness
NewReactorRec<REACTOR_TUBE_BELL_JAR_THK$> = CurrTubeBellJarThk - ThkAddition
NewReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$> = CurrTubeBellJarCnt - CntAddition
NewReactorRec<REACTOR_SUSC_THK$> = CurrSuscThk + ThkAddition
NewReactorRec<REACTOR_SUSC_WFR_CNT$> = CurrSuscWfrCnt - CntAddition
NewReactorRec<REACTOR_LOWER_QUARTZ_THK$> = CurrLowerQuartzThk - ThkAddition
NewReactorRec<REACTOR_LOWER_QUARTZ_WFR$> = CurrLowerQuartzWfr - CntAddition
NewReactorRec<REACTOR_ARMS_WFR_CNT$> = CurrArmsWfrCnt - WaferCount
Case SusceptorSize = 8
// Round up
CntAddition = (WaferCount / 3)
If Count(CntAddition, '.') EQ 1 Then
CntAddition = Int(CntAddition) + 1
end
ThkAddition = (WaferCount / 3) * TargetThickness
NewReactorRec<REACTOR_TUBE_BELL_JAR_THK$> = CurrTubeBellJarThk - ThkAddition
NewReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$> = CurrTubeBellJarCnt - CntAddition
NewReactorRec<REACTOR_SUSC_THK$> = CurrSuscThk - ThkAddition
NewReactorRec<REACTOR_SUSC_WFR_CNT$> = CurrSuscWfrCnt - CntAddition
NewReactorRec<REACTOR_LOWER_QUARTZ_THK$> = CurrLowerQuartzThk - ThkAddition
NewReactorRec<REACTOR_LOWER_QUARTZ_WFR$> = CurrLowerQuartzWfr - CntAddition
NewReactorRec<REACTOR_ARMS_WFR_CNT$> = CurrArmsWfrCnt - WaferCount
End Case
Case ReactorType = 'ASM' OR ReactorType = 'ASM+'
ThkAddition = WaferCount * TargetThickness
NewReactorRec<REACTOR_TUBE_BELL_JAR_THK$> = CurrTubeBellJarThk - ThkAddition
NewReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$> = CurrTubeBellJarCnt - WaferCount
NewReactorRec<REACTOR_SUSC_THK$> = CurrSuscThk - ThkAddition
NewReactorRec<REACTOR_SUSC_WFR_CNT$> = CurrSuscWfrCnt - WaferCount
NewReactorRec<REACTOR_LOWER_QUARTZ_THK$> = CurrLowerQuartzThk - ThkAddition
NewReactorRec<REACTOR_LOWER_QUARTZ_WFR$> = CurrLowerQuartzWfr - WaferCount
NewReactorRec<REACTOR_ARMS_WFR_CNT$> = CurrArmsWfrCnt - WaferCount
End Case
Database_Services('WriteDataRow', 'REACTOR', ReactorNo, NewReactorRec, 1, 0, 0)
end service
//----------------------------------------------------------------------------------------------------------------------
// ResetWfrMetric
//
// RDSNo. - [Required]
// MetricType - [Required]('TUBE_BELL_JAR_THK', 'TUBE_BELL_JAR_WFR_CNT', 'SUSC_THK', 'SUSC_WFR_CNT', 'LOWER_QUARTZ_THK', 'LOWER_QUARTZ_WFR', 'ARMS_WFR_CNT')
//
// Reset a specified REACTOR metric to 0.
//
//----------------------------------------------------------------------------------------------------------------------
Service ResetWfrMetric(ReactorNo, MetricType = REACTORMETRIC)
ReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactorNo)
Begin Case
Case MetricType = 'TUBE_BELL_JAR_THK'
ReactorRec<REACTOR_TUBE_BELL_JAR_THK$> = 0
Case MetricType = 'TUBE_BELL_JAR_WFR_CNT'
ReactorRec<REACTOR_TUBE_BELL_JAR_WFR_CNT$> = 0
Case MetricType = 'SUSC_THK'
ReactorRec<REACTOR_SUSC_THK$> = 0
Case MetricType = 'SUSC_WFR_CNT'
ReactorRec<REACTOR_SUSC_WFR_CNT$> = 0
Case MetricType = 'LOWER_QUARTZ_THK'
ReactorRec<REACTOR_LOWER_QUARTZ_THK$> = 0
Case MetricType = 'LOWER_QUARTZ_WFR'
ReactorRec<REACTOR_LOWER_QUARTZ_WFR$> = 0
Case MetricType = 'ARMS_WFR_CNT'
ReactorRec<REACTOR_ARMS_WFR_CNT$> = 0
End Case
Database_Services('WriteDataRow', 'REACTOR', ReactorNo, ReactorRec, 1, 0, 0)
end service
//----------------------------------------------------------------------------------------------------------------------
// GetReactors
//
// Returns a JSON formatted array of reactor objects. Reactor number 0 will be ommitted. If the MatchType or MatchSize
// arguments are populated, the array will be filterd accordingly.
//----------------------------------------------------------------------------------------------------------------------
Service GetReactors(MatchType, MatchSize)
ServiceKeyID := '*' : MatchType : '*' : MatchSize
Reactors = ''
If Memory_Services('IsValueCurrent', ServiceKeyID, 3600, True$) then
Reactors = Memory_Services('GetValue', ServiceKeyID)
end else
objReactors = ''
If SRP_JSON(objReactors, 'NEW', 'OBJECT') then
objReactorArray = ''
If SRP_JSON(objReactorArray, 'NEW', 'ARRAY') then
hReactors = Database_Services('GetTableHandle', 'REACTOR')
If Error_Services('NoError') then
rv = Set_Status(0)
RList('SELECT REACTOR BY REACT_NO', 5, '', '', '')
Done = False$
Reactors = ''
Loop
Readnext ReactorNo else Done = True$
Until Done
Reactor = Reactor_Services('GetReactor', ReactorNo)
If SRP_JSON(objReactor, 'PARSE', Reactor) EQ '' then
ReactorType = SRP_JSON(objReactor, 'GETVALUE', 'Type')
ReactorSize = SRP_JSON(objReactor, 'GETVALUE', 'SusceptorSize')
IncludeReactor = True$ ; // Assume reactor will be included in the response.
Begin Case
Case ReactorNo EQ 0
// Reactor number 0 is not a real reactor.
IncludeReactor = False$
Case MatchType NE ''
Begin Case
Case MatchType[1, 3] EQ 'ASM' AND Not((ReactorType[1, 3] EQ 'ASM' OR ReactorType EQ 'EPS'))
IncludeReactor = False$
Case MatchType EQ 'EPS' AND Not((ReactorType[1, 3] EQ 'ASM' OR ReactorType EQ 'EPS'))
IncludeReactor = False$
Case MatchType EQ 'EPP' AND Not((ReactorType EQ 'EPP' OR ReactorType EQ 'EpiPro'))
IncludeReactor = False$
Case MatchType EQ 'EpiPro' AND Not((ReactorType EQ 'EPP' OR ReactorType EQ 'EpiPro'))
IncludeReactor = False$
Case MatchType _EQC 'GAN' AND Not(ReactorType _EQC 'GAN')
IncludeReactor = False$
Case MatchType NE ReactorType
IncludeReactor = False$
End Case
Case MatchSize NE ''
If MatchSize NE ReactorSize then IncludeReactor = False$
Case Not(RowExists('TOOL', 'R':ReactorNo))
// This tool does not exist
IncludeReactor = False$
End Case
If IncludeReactor then
SRP_JSON(objReactorArray, 'ADD', objReactor)
end
SRP_JSON(objReactor, 'RELEASE')
end
Repeat
SRP_JSON(objReactors, 'SET', 'Reactors', objReactorArray)
Reactors = SRP_JSON(objReactors, 'STRINGIFY', 'FAST')
Memory_Services('SetValue', ServiceKeyID, Reactors)
end
SRP_JSON(objReactorArray, 'RELEASE')
end else
Error_Services('Add', 'Error creating objReactorArray in the ' : Service : ' service.')
end
SRP_JSON(objReactors, 'RELEASE')
end else
Error_Services('Add', 'Error creating objReactors in the ' : Service : ' service.')
end
end
Response = Reactors
end service
//----------------------------------------------------------------------------------------------------------------------
// GetReactorNumbers
//
// Returns an @FM delimited list of Reactor Numbers.
//----------------------------------------------------------------------------------------------------------------------
Service GetReactorNumbers(MatchType, MatchSize)
ServiceKeyID := '*' : MatchType : '*' : MatchSize
ReactorNumbers = ''
If Memory_Services('IsValueCurrent', ServiceKeyID, 3600, True$) then
ReactorNumbers = Memory_Services('GetValue', ServiceKeyID)
end else
hReactors = Database_Services('GetTableHandle', 'REACTOR')
If Error_Services('NoError') then
rv = Set_Status(0)
RList('SELECT REACTOR BY REACT_NO', 5, '', '', '')
Done = False$
Reactors = ''
Loop
Readnext ReactorNo else Done = True$
Until Done
Reactor = Reactor_Services('GetReactor', ReactorNo)
If SRP_JSON(objReactor, 'PARSE', Reactor) EQ '' then
ReactorType = SRP_JSON(objReactor, 'GETVALUE', 'Type')
ReactorSize = SRP_JSON(objReactor, 'GETVALUE', 'SusceptorSize')
IncludeReactor = True$ ; // Assume reactor will be included in the response.
Begin Case
Case ReactorType EQ ''
IncludeReactor = False$
Case MatchType NE ''
Begin Case
Case MatchType[1, 3] EQ 'ASM' AND Not((ReactorType[1, 3] EQ 'ASM' OR ReactorType EQ 'EPS'))
IncludeReactor = False$
Case MatchType EQ 'EPS' AND Not((ReactorType[1, 3] EQ 'ASM' OR ReactorType EQ 'EPS'))
IncludeReactor = False$
Case MatchType EQ 'EPP' AND Not((ReactorType EQ 'EPP' OR ReactorType EQ 'EpiPro'))
IncludeReactor = False$
Case MatchType EQ 'EpiPro' AND Not((ReactorType EQ 'EPP' OR ReactorType EQ 'EpiPro'))
IncludeReactor = False$
Case MatchType _EQC 'GAN' AND Not(ReactorType _EQC 'GAN')
IncludeReactor = False$
Case MatchType NE ReactorType
IncludeReactor = False$
End Case
Case MatchSize NE ''
If MatchSize NE ReactorSize then IncludeReactor = False$
End Case
If IncludeReactor then
ReactorNumbers := ReactorNo : @FM
end
end
Repeat
ReactorNumbers[-1, 1] = ''
Memory_Services('SetValue', ServiceKeyID, ReactorNumbers)
end
end
Response = ReactorNumbers
end service
//----------------------------------------------------------------------------------------------------------------------
// GetReactor
//
// Returns a JSON formatted object of information related to the indicated reactor number.
//----------------------------------------------------------------------------------------------------------------------
Service GetReactor(ReactorNo)
ServiceKeyID := '*' : ReactorNo
Reactor = ''
If Memory_Services('IsValueCurrent', ServiceKeyID, 3600, True$) then
Reactor = Memory_Services('GetValue', ServiceKeyID)
end else
If (ReactorNo NE '') AND (ReactorNo NE 0) then
ReactorRow = Database_Services('ReadDataRow', 'REACTOR', ReactorNo)
If SRP_JSON(objReactor, 'NEW', 'OBJECT') then
ReactorType = ReactorRow<REACTOR_REACT_TYPE$>
SRP_JSON(objReactor, 'SETVALUE', 'ReactorNumber', ReactorNo, 'STRING')
SRP_JSON(objReactor, 'SETVALUE', 'Type', ReactorType, 'STRING')
Begin Case
Case ReactorType _EQC 'ASM' ; ReactorTypeVerbose = 'ASM'
Case ReactorType _EQC 'ASM+'; ReactorTypeVerbose = 'ASM+'
Case ReactorType _EQC 'EPP' ; ReactorTypeVerbose = 'EpiPro'
Case ReactorType _EQC 'EPS' ; ReactorTypeVerbose = 'ASM'
Case ReactorType _EQC 'HTR' ; ReactorTypeVerbose = 'HTR'
Case ReactorType _EQC 'GAN' ; ReactorTypeVerbose = 'GaN'
Case ReactorType _EQC '' ; ReactorTypeVerbose = '***'
End Case
SRP_JSON(objReactor, 'SETVALUE', 'TypeVerbose', ReactorTypeVerbose, 'STRING')
SRP_JSON(objReactor, 'SETVALUE', 'AssignmentCode', ReactorRow<REACTOR_REACT_ASSIGNMENT$>, 'STRING')
SRP_JSON(objReactor, 'SETVALUE', 'AssignmentDescription', Oconv(ReactorRow<REACTOR_REACT_ASSIGNMENT$>, '[REACT_ASSIGN_CONV]'), 'STRING')
SRP_JSON(objReactor, 'SETVALUE', 'Location', ReactorRow<REACTOR_LOCATIONX$>, 'STRING')
SRP_JSON(objReactor, 'SETVALUE', 'SusceptorSize', ReactorRow<REACTOR_SUSC_POCKET_SIZE$>, 'STRING')
SRP_JSON(objReactor, 'SETVALUE', 'SecondChamber', ReactorRow<REACTOR_SECOND_CHAMBER$>, 'STRING')
SRP_JSON(objReactor, 'SETVALUE', 'PickPlace', ReactorRow<REACTOR_PICK_PLACE$>, 'STRING')
SRP_JSON(objReactor, 'SETVALUE', 'NotRepairable', ReactorRow<REACTOR_NOT_REPAIRABLE$>, 'STRING')
Reactor = SRP_JSON(objReactor, 'STRINGIFY', 'FAST')
Memory_Services('SetValue', ServiceKeyID, Reactor)
SRP_JSON(objReactor, 'RELEASE')
end else
Error_Services('Add', 'Error creating objReactor in the ' : Service : ' service.')
end
end else
Error_Services('Add', 'ReactorNo argument was missing from the ' : Service : ' service.')
end
end
Response = Reactor
end service
//----------------------------------------------------------------------------------------------------------------------
// CreatePerformanceTrackers
//
// Creates performance tracking database rows in the REACTOR_PERFORMANCE table. This creates a unique tracker for each
// Reactor/Part pair based on the indicated dates scheduled work orders.
//----------------------------------------------------------------------------------------------------------------------
Service CreatePerformanceTrackers(ScheduleDate, CreateReports)
// Force the auto scheduler to run to make sure that all adjustments are being made to the scheduler.
* Schedule_Services('AutoScheduler')
If Num(ScheduleDate) else ScheduleDate = Iconv(ScheduleDate, 'D')
If ScheduleDate EQ '' then ScheduleDate = Date()
If CreateReports NE False$ then CreateReports = True$
// There will be two procedures. The first is a pass through the scheduled events to create the Reactor Performance
// rows. The second is a pass through the recently created Reactor Performance records to adjust the expected
// wafer count based part changes.
// Get a list of all the scheduled events for the indicated schedule date. Note: this service expects to be ran
// shortly after midnight for the indicated schedule date.
ScheduleEvents = Schedule_Services('GetScheduleEvents', ScheduleDate, ScheduleDate, '', '', False$)
If ScheduleEvents NE '' then
PerfKeyIDs = ''
For Each ScheduleEvent in ScheduleEvents using @FM
KeyIDs = ScheduleEvent<0, 2>
WorkOrderNo = KeyIDs[1, '*']
EpiPartNo = KeyIDs[Col2() + 1, '*']
ReactorNo = KeyIDs[Col2() + 1, '*']
ScheduleDate = KeyIDs[Col2() + 1, '*']
Sequence = KeyIDs[Col2() + 1, '*']
If EpiPartNo NE '' then
PartUsedKeyID = Service : '*' : ReactorNo : '*' : ScheduleDate : '*' : EpiPartNo
If Memory_Services('KeyExists', PartUsedKeyID) EQ False$ then
PartCountKeyID = Service : '*' : ReactorNo : '*' : ScheduleDate
NumParts = Memory_Services('GetValue', PartCountKeyID)
NumParts += 1
Memory_Services('SetValue', PartCountKeyID, NumParts)
Memory_Services('SetValue', PartUsedKeyID, True$)
end
// This is a work order event rather than a block out event.
ScheduleEventSummary = Schedule_Services('GetScheduleEventSummary', ReactorNo, WorkOrderNo, ScheduleDate, Sequence, True$)
StartDate = Iconv(ScheduleEventSummary<6>, 'D')
ReactorType = ScheduleEventSummary<1>
EndDate = Iconv(ScheduleEventSummary<7>, 'D')
TotalWafers = ScheduleEventSummary<9>
Begin Case
Case ReactorType _eqc 'ASM+' ; ReactorType = 'ASM+'
Case ReactorType _eqc 'EPP' ; ReactorType = 'EpiPro'
Case ReactorType _eqc 'EPS' ; ReactorType = 'ASM'
Case ReactorType _eqc 'HTR' ; ReactorType = 'HTR'
Case ReactorType _eqc 'GAN' ; ReactorType = 'GaN'
Case ReactorType _eqc '' ; ReactorType = '***'
End Case
MinutesPerWafer = Epi_Part_Services('GetMinutesPerWaferScheduler', EpiPartNo, ReactorType)
WafersPerDay = Epi_Part_Services('GetAdjustedWafersPerDayScheduler', EpiPartNo, ReactorType, MinutesPerWafer)
If ScheduleDate LT EndDate then
// The end date of this schedule event is still in the future. Therefore, the current event is expected
// to run the whole day. Use the calculated wafers per day.
WafersExpected = WafersPerDay
end else
// This is the end of the schedule event. Wafers expected will be the remaining total wafers after
// all previous wafers per day have been deducted.
TotalPreviousDays = EndDate - StartDate
TotalPreviousWafers = TotalPreviousDays * WafersPerDay
WafersExpected = TotalWafers - TotalPreviousWafers
If WafersExpected GT WafersPerDay then WafersExpected = WafersPerDay ; // Cap to the wafers per day.
end
If WafersExpected LT 0 then WafersExpected = 0
// Full KeyID = {REACTOR_NO} * {EPI_PART_NO} * {WEEK_YEAR} * {WEEK_NO} * {SCHEDULE_DATE}
WeekDate = Date_Services('GetISOWeekDate', ScheduleDate)
WeekYear = WeekDate[1, '-']
WeekNo = WeekDate[Col2() + 1, '-']
PerfKeyID = ReactorNo : '*' : EpiPartNo : '*' : WeekYear : '*' : WeekNo : '*' : ScheduleDate
PerfRow = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, True$, 0)
PerfRow<2> = PerfRow<2> + Iconv(WafersExpected, 'MD2')
Database_Services('WriteDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, PerfRow, True$, False$, True$)
Locate PerfKeyID in PerfKeyIDs using @FM setting fPos else PerfKeyIDs := PerfKeyID : @FM
end
Next ScheduleEvent
// Pass through each Reactor Performance row. For every part being run on a given reactor, the following
// adjustment is required:
//
// 1. Total expected amount per part should be prorated by the number of parts. This accounts for the fact
// that one reactor will be splitting its time for each part. For example, if Part A is normally estimated
// to run 200 parts and Part B is normally estimated to run 300 parts, they will each be prorated by .5.
// Thus, Part A will now be estimated to run 100 parts and Part B will be estimated to run 150 parts.
//
// 2. Since each part change requires an average of 6 hours of down time to prepare the reactor, the amount
// per part should be prorated by the remaining hours in the day. For example, if there are two parts being
// ran on the reactor, this only allows 18 hours (out of 24) to run parts, which is a prorated value of
// .75. Using the above example, Part A would then have 100 parts prorated to 75 (100 * .75) and Part would
// then have 150 parts prorated to 112.50 (150 * .75).
If PerfKeyIDs NE '' then
For Each PerfKeyID in PerfKeyIDs using @FM
ReactorNo = PerfKeyID[1, '*']
EpiPartNo = PerfKeyID[Col2() + 1, '*']
WeekYear = PerfKeyID[Col2() + 1, '*']
WeekNo = PerfKeyID[Col2() + 1, '*']
ScheduleDate = PerfKeyID[Col2() + 1, '*']
PartCountKeyID = Service : '*' : ReactorNo : '*' : ScheduleDate
NumParts = Memory_Services('GetValue', PartCountKeyID)
If NumParts GT 1 then
// Only prorate if there is more then one part.
Prorate1 = 1 / NumParts ; // Adjust for the number of parts.
Prorate2 = ((24 - ((NumParts - 1) * 6) ) / 24) ; // Adjust for the number of hours remaining in the day.
Prorate = Prorate1 * Prorate2
PerfRow = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, True$, 0)
PerfRow<2> = PerfRow<2> * ProRate
Database_Services('WriteDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, PerfRow, True$, False$, True$)
end
Next PerfKeyID
// Clear out all cached data.
Memory_Services('ReleaseHashTable')
end
end
If CreateReports then
Reactor_Services('CreateDailyPerformanceReport', ScheduleDate)
If Mod(ScheduleDate, 7) EQ 5 then
// This is early Friday. Create the weekly performance report for the upcoming week. First, the
// CreatePerformanceTrackers must be called for all days in the upcoming week.
NextMonday = ScheduleDate + 3
NextSunday = ScheduleDate + 9
For ScheduleDate = NextMonday to NextSunday
Reactor_Services('CreatePerformanceTrackers', ScheduleDate, False$)
Next ScheduleDate
// Create the weekly performance report based on the daily performance tracking data.
YearWeekNo = Date_Services('GetISOWeekDate', NextMonday)
YearWeekNo = Field(YearWeekNo, '-', 1, 2)
Reactor_Services('CreateWeeklyPerformanceReport', YearWeekNo)
// Clear the daily performance tracking data for the upcoming week since these will be recreated
// automatically on the morning of each date.
For ScheduleDate = NextMonday to NextSunday
Reactor_Services('ClearWafersExpected', ScheduleDate)
Next ScheduleDate
end
end
end service
//----------------------------------------------------------------------------------------------------------------------
// UpdatePerformanceTrackers
//
// Updates the wafers processed column in the performance tracking database rows.
//----------------------------------------------------------------------------------------------------------------------
Service UpdatePerformanceTrackers(ScheduleDate, CreateReports)
If Num(ScheduleDate) else ScheduleDate = Iconv(ScheduleDate, 'D')
If ScheduleDate EQ '' then ScheduleDate = Date()
If CreateReports NE False$ then CreateReports = True$
rv = Set_Status(0)
Sentence = 'SELECT RDS WITH DATE_OUT EQ ' : Quote(Oconv(ScheduleDate, 'D4/'))
RList(Sentence, 5, '', '', '')
EOF = False$
Loop
Readnext RDSID else EOF = True$
Until EOF
RDSRow = Database_Services('ReadDataRow', 'RDS', RDSID)
If Error_Services('NoError') then
WeekDate = Date_Services('GetISOWeekDate', ScheduleDate)
WeekYear = WeekDate[1, '-']
WeekNo = WeekDate[Col2() + 1, '-']
ReactorNo = RDSRow<RDS_REACTOR$>
ReactorRow = Database_Services('ReadDataRow', 'REACTOR', ReactorNo, True$, 60, False$)
ReactorType = ReactorRow<REACTOR_REACT_TYPE$>
If ReactorType EQ 'EPP' then
// This is an EpiPro reactor. Check to see if has a second chamber. If so, then this is the primary
// reactor. If not, then check the previous reactor to see if it references this current reactor as its
// second chamber. If so then use the previous reactor to track the wafers processed.
SecondChamber = ReactorRow<REACTOR_SECOND_CHAMBER$>
If SecondChamber EQ '' then
CompareReactorNo = ReactorNo - 2
CompareReactorRow = Database_Services('ReadDataRow', 'REACTOR', CompareReactorNo, True$, 60, False$)
CompareSecondChamber = CompareReactorRow<REACTOR_SECOND_CHAMBER$>
If CompareSecondChamber EQ ReactorNo then Transfer CompareReactorNo to ReactorNo
end
end
* EpiPartNo = RDSRow<RDS_PART_NUM$>
EpiPartNo = Xlate('RDS', RDSID, 'EPI_PART_NO', 'X')
// Full KeyID = {REACTOR_NO} * {EPI_PART_NO} * {WEEK_YEAR} * {WEEK_NO} * {SCHEDULE_DATE}
PerfKeyID = ReactorNo : '*' : EpiPartNo : '*' : WeekYear : '*' : WeekNo : '*' : ScheduleDate
PerfRow = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, True$, 0)
If Error_Services('NoError') then
WafersProcessed = RDSRow<RDS_WAFERS_IN$>
PerfRow<3> = PerfRow<3> + Iconv(WafersProcessed, 'MD2')
Database_Services('WriteDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, PerfRow, True$, False$, True$)
end
end
Repeat
If CreateReports then
Reactor_Services('UpdateDailyPerformanceReport', ScheduleDate)
If Mod(ScheduleDate, 7) EQ 0 then
// This is a Sunday, which means the last day of a work week has been updated. Update the weekly performance
// report but set the date to the previous Monday.
YearWeekNo = Date_Services('GetISOWeekDate', ScheduleDate - 6)
YearWeekNo = Field(YearWeekNo, '-', 1, 2)
Reactor_Services('UpdateWeeklyPerformanceReport', ScheduleDate - 6)
end
end
end service
//----------------------------------------------------------------------------------------------------------------------
// ClearWafersExpected
//
// Clears the expected wafers for all database rows the REACTOR_PERFORMANCE table based on the indicated schedule date.
//----------------------------------------------------------------------------------------------------------------------
Service ClearWafersExpected(ScheduleDate)
If Num(ScheduleDate) else ScheduleDate = Iconv(ScheduleDate, 'D')
If ScheduleDate EQ '' then ScheduleDate = Date()
hReactors = Database_Services('GetTableHandle', 'REACTOR')
If Error_Services('NoError') then
If Error_Services('NoError') then
rv = Set_Status(0)
RList('SELECT REACTOR BY REACT_NO', 5, '', '', '')
Done = False$
ReportData = ''
Loop
Readnext ReactorNo else Done = True$
Until Done
ReactorRow = Database_Services('ReadDataRow', 'REACTOR', ReactorNo, True$, 0)
ReactorType = ReactorRow<REACTOR_REACT_TYPE$>
SecondChamber = ReactorRow<REACTOR_SECOND_CHAMBER$>
@DICT = Database_Services('GetTableHandle', 'DICT.REACTOR_PERFORMANCE')
If (((ReactorNo GT 0) AND (ReactorNo LE 79))) AND ((ReactorType EQ 'EPP' AND SecondChamber NE '') OR (ReactorType NE 'EPP')) then
* If (ReactorNo NE 0) AND (ReactorNo LE 74) AND ((ReactorType EQ 'EPP' AND SecondChamber NE '') OR (ReactorType NE 'EPP')) AND (ReactorType NE 'GAN') then
@ID = ReactorNo : '****' : ScheduleDate
@RECORD = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', @ID, True$, 0)
If Error_Services('NoError') then
DetailPerfKeyIDs = {ALL_DETAIL_CHILD_KEY_IDS}
If DetailPerfKeyIDs NE '' then
For Each PerfKeyID in DetailPerfKeyIDs using @VM
PerfRow = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, True$, 0)
PerfRow<2> = ''
Database_Services('WriteDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, PerfRow, True$, False$, True$)
Next DetailPerfKeyID
end
end
end
Repeat
end
end
end service
//----------------------------------------------------------------------------------------------------------------------
// ClearWafersProcessed
//
// Clears the processed wafers for all database rows the REACTOR_PERFORMANCE table based on the indicated schedule date.
//----------------------------------------------------------------------------------------------------------------------
Service ClearWafersProcessed(ScheduleDate)
If Num(ScheduleDate) else ScheduleDate = Iconv(ScheduleDate, 'D')
If ScheduleDate EQ '' then ScheduleDate = Date()
hReactors = Database_Services('GetTableHandle', 'REACTOR')
If Error_Services('NoError') then
If Error_Services('NoError') then
rv = Set_Status(0)
RList('SELECT REACTOR BY REACT_NO', 5, '', '', '')
Done = False$
ReportData = ''
Loop
Readnext ReactorNo else Done = True$
Until Done
ReactorRow = Database_Services('ReadDataRow', 'REACTOR', ReactorNo, True$, 0)
ReactorType = ReactorRow<REACTOR_REACT_TYPE$>
SecondChamber = ReactorRow<REACTOR_SECOND_CHAMBER$>
@DICT = Database_Services('GetTableHandle', 'DICT.REACTOR_PERFORMANCE')
If (((ReactorNo GT 0) AND (ReactorNo LE 79))) AND ((ReactorType EQ 'EPP' AND SecondChamber NE '') OR (ReactorType NE 'EPP')) then
* If (ReactorNo NE 0) AND (ReactorNo LE 74) AND ((ReactorType EQ 'EPP' AND SecondChamber NE '') OR (ReactorType NE 'EPP')) AND (ReactorType NE 'GAN') then
@ID = ReactorNo : '****' : ScheduleDate
@RECORD = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', @ID, True$, 0)
If Error_Services('NoError') then
DetailPerfKeyIDs = {ALL_DETAIL_CHILD_KEY_IDS}
If DetailPerfKeyIDs NE '' then
For Each PerfKeyID in DetailPerfKeyIDs using @VM
PerfRow = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, True$, 0)
PerfRow<3> = ''
Database_Services('WriteDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, PerfRow, True$, False$, True$)
Next DetailPerfKeyID
end
end
end
Repeat
end
end
end service
//----------------------------------------------------------------------------------------------------------------------
// CreateDailyPerformanceReport
//
// Creates daily performance tracking report using the database rows in the REACTOR_PERFORMANCE table. This creates an
// Excel spreadsheet using the "Fab Performance Daily Template.xlsx" file as a template.
//----------------------------------------------------------------------------------------------------------------------
Service CreateDailyPerformanceReport(ScheduleDate)
If Num(ScheduleDate) else ScheduleDate = Iconv(ScheduleDate, 'D')
If ScheduleDate EQ '' then ScheduleDate = Date()
DisplayDate = Oconv(ScheduleDate, 'D4/')
XLSXTemplate = 'Fab Performance Daily Template.xlsx'
objDocument = Excel_Services('OpenDocument', TemplatesFolder : XLSXTemplate)
If Error_Services('NoError') then
hReactors = Database_Services('GetTableHandle', 'REACTOR')
If Error_Services('NoError') then
If Error_Services('NoError') then
rv = Set_Status(0)
RList('SELECT REACTOR BY REACT_NO', 5, '', '', '')
Done = False$
ReportData = ''
Loop
Readnext ReactorNo else Done = True$
Until Done
ReactorRow = Database_Services('ReadDataRow', 'REACTOR', ReactorNo, True$, 0)
ReactorType = ReactorRow<REACTOR_REACT_TYPE$>
SecondChamber = ReactorRow<REACTOR_SECOND_CHAMBER$>
@DICT = Database_Services('GetTableHandle', 'DICT.REACTOR_PERFORMANCE')
If (((ReactorNo GT 0) AND (ReactorNo LE 79))) AND ((ReactorType EQ 'EPP' AND SecondChamber NE '') OR (ReactorType NE 'EPP')) then
* If (ReactorNo NE 0) AND (ReactorNo LE 74) AND ((ReactorType EQ 'EPP' AND SecondChamber NE '') OR (ReactorType NE 'EPP')) AND (ReactorType NE 'GAN') then
PerfKeyID = ReactorNo : '****' : ScheduleDate
PerfRow = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, True$, 0)
DetailPerfKeyIDs = PerfRow<1>
If DetailPerfKeyIDs NE '' then
For Each @ID in DetailPerfKeyIDs using @VM
@RECORD = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', @ID, True$, 0)
ReactorName = {REACTOR_NAME}
EpiPartNo = {EPI_PART_NO}
WafersExpected = Oconv({TOTAL_WAFERS_EXPECTED}, 'MD2')
WafersExpectedRounded = Oconv({TOTAL_WAFERS_EXPECTED_ROUNDED}, 'MD2')
ReportData := ReactorType : @VM : ReactorName : @VM : DisplayDate : @VM : EpiPartNo : @VM : WafersExpected : @VM : WafersExpectedRounded : @VM : ReactorNo : @FM
Next DetailPerfKeyID
end else
ReportData := ReactorType : @VM : ReactorNo : @VM : DisplayDate : @VM : '' : @VM : '' : @VM : '' : @VM : ReactorNo : @FM
end
end
Repeat
ReportData[-1, 1] = '' ; // Strip off the last @FM
ReportData = SRP_Array('SortRows', ReportData, 'AR7' : @VM : 'AL4', 'LIST', @FM, @VM)
CellRow = 1 ; // Initialize the cell row to start entering data into.
If ReportData NE '' then
For Each ReportRow in ReportData using @FM
ReactorType = ReportRow[1, @VM]
ReactorName = ReportRow[Col2() + 1, @VM]
DisplayDate = ReportRow[Col2() + 1, @VM]
EpiPartNo = ReportRow[Col2() + 1, @VM]
WafersExpected = ReportRow[Col2() + 1, @VM]
WafersExpectedRounded = ReportRow[Col2() + 1, @VM]
CellRow += 1
Excel_Services('SetCellValue', objDocument, 'SSR', 'A', CellRow, ReactorType)
Excel_Services('SetCellValue', objDocument, 'SSR', 'B', CellRow, ReactorName)
Excel_Services('SetCellValue', objDocument, 'SSR', 'E', CellRow, DisplayDate)
Excel_Services('SetCellValue', objDocument, 'SSR', 'F', CellRow, EpiPartNo)
Excel_Services('SetCellValue', objDocument, 'SSR', 'G', CellRow, WafersExpected)
Excel_Services('SetCellValue', objDocument, 'SSR', 'H', CellRow, WafersExpectedRounded)
Next ReportRow
end
end
NewDocument = DisplayDate[7, 4] : '-' : DisplayDate[1, 2] : '-' : DisplayDate[4, 2] : ' Fab Performance.xlsx'
Excel_Services('SaveDocument', objDocument, DailyReportsFolder : NewDocument)
If Error_Services('NoError') then
Call Send_SRP_Mail(DailyReportsFolder : NewDocument)
rv = Set_Status(0)
OSRead PerformanceReport from DailyReportsFolder : NewDocument then
OSWrite PerformanceReport to DailyReportsFolder : NewDocument
If Status() then
Error_Services('Add', 'Error writing ' : DailyReportsFolder : NewDocument : ' in the ' : Service : ' service. Status: ' : Status())
end
end else
Error_Services('Add', 'Error reading ' : DailyReportsFolder : NewDocument : ' in the ' : Service : ' service. Status: ' : Status())
end
end
end
end
end service
//----------------------------------------------------------------------------------------------------------------------
// UpdateDailyPerformanceReport
//
// Creates daily performance tracking report using the database rows in the REACTOR_PERFORMANCE table. This creates an
// Excel spreadsheet using the "Fab Performance Daily Template.xlsx" file as a template.
//----------------------------------------------------------------------------------------------------------------------
Service UpdateDailyPerformanceReport(ScheduleDate)
If Num(ScheduleDate) else ScheduleDate = Iconv(ScheduleDate, 'D')
If ScheduleDate EQ '' then ScheduleDate = Date()
DisplayDate = Oconv(ScheduleDate, 'D4/')
Document = DisplayDate[7, 4] : '-' : DisplayDate[1, 2] : '-' : DisplayDate[4, 2] : ' Fab Performance.xlsx'
If Excel_Services('DocumentExists', DailyReportsFolder : Document) then
objDocument = Excel_Services('OpenDocument', DailyReportsFolder : Document)
end else
Error_Services('Add', 'Unable to find ' : Document : ' in the ' : Service : ' service.')
end
If Error_Services('NoError') then
@DICT = Database_Services('GetTableHandle', 'DICT.REACTOR_PERFORMANCE')
If Error_Services('NoError') then
CellRow = 1 ; // Initialize the cell row to start entering data into.
Loop
CellRow += 1
Date = Excel_Services('GetCellValue', objDocument, 'SSR', 'E', CellRow)
Until Date EQ ''
ReactorName = Excel_Services('GetCellValue', objDocument, 'SSR', 'B', CellRow)
ReactorNo = ReactorName[1, 'F/']
EpiPartNo = Excel_Services('GetCellValue', objDocument, 'SSR', 'F', CellRow)
WeekDate = Date_Services('GetISOWeekDate', ScheduleDate)
WeekYear = WeekDate[1, '-']
WeekNo = WeekDate[Col2() + 1, '-']
// Full KeyID = {REACTOR_NO} * {EPI_PART_NO} * {WEEK_YEAR} * {WEEK_NO} * {SCHEDULE_DATE}
@ID = ReactorNo : '*' : EpiPartNo : '*' : WeekYear : '*' : WeekNo : '*' : ScheduleDate
@RECORD = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', @ID, True$, 0)
WafersProcessed = Oconv({TOTAL_WAFERS_PROCESSED}, 'MD2')
WafersDelta = Oconv({TOTAL_WAFERS_DELTA}, 'MD2')
WafersDeltaRounded = Oconv({TOTAL_WAFERS_DELTA_ROUNDED}, 'MD2')
Excel_Services('SetCellValue', objDocument, 'SSR', 'I', CellRow, WafersProcessed)
Excel_Services('SetCellValue', objDocument, 'SSR', 'K', CellRow, WafersDelta)
Excel_Services('SetCellValue', objDocument, 'SSR', 'L', CellRow, WafersDeltaRounded)
//Comment = Excel_Services('GetCellValue', objDocument, 'SSR', 'M', CellRow)
//Excel_Services('SetCellValue', objDocument, 'SSR', 'M', CellRow, Comment)
Repeat
Excel_Services('SaveDocument', objDocument)
If Error_Services('NoError') then
Call Send_SRP_Mail(DailyReportsFolder : Document)
rv = Set_Status(0)
OSRead PerformanceReport from DailyReportsFolder : Document then
OSWrite PerformanceReport to DailyReportsFolder : Document
If Status() then
Error_Services('Add', 'Error writing ' : DailyReportsFolder : Document : ' in the ' : Service : ' service. Status: ' : Status())
end
end else
Error_Services('Add', 'Error reading ' : DailyReportsFolder : Document : ' in the ' : Service : ' service. Status: ' : Status())
end
end else
ErrorMessage = Error_Services('GetMessage')
end
end
end
end service
//----------------------------------------------------------------------------------------------------------------------
// CreateWeeklyPerformanceReport
//
// Creates weekly performance tracking report using the database rows in the REACTOR_PERFORMANCE table. This creates an
// Excel spreadsheet using the "Fab Performance Weekly Template.xlsx" file as a template.
//----------------------------------------------------------------------------------------------------------------------
Service CreateWeeklyPerformanceReport(YearWeekNo)
// YearWeekNo looks like 2017-W44. For testing purposes it might be easier to pass in a date and the YearWeekNo
// will be calculated.
If (Num(Iconv(YearWeekNo, 'D')) AND (Iconv(YearWeekNo, 'D') NE '')) OR Num(YearWeekNo) then
// A internal or external formatted date was passed in.
YearWeekNo = Date_Services('GetISOWeekDate', YearWeekNo)
YearWeekNo = Field(YearWeekNo, '-', 1, 2)
end
WeekYear = YearWeekNo[1, '-']
WeekNo = YearWeekNo[Col2() + 1, '-']
XLSXTemplate = 'Fab Performance Weekly Template.xlsx'
objDocument = Excel_Services('OpenDocument', TemplatesFolder : XLSXTemplate)
If Error_Services('NoError') then
hReactors = Database_Services('GetTableHandle', 'REACTOR')
If Error_Services('NoError') then
If Error_Services('NoError') then
rv = Set_Status(0)
RList('SELECT REACTOR BY REACT_NO', 5, '', '', '')
Done = False$
ReportData = ''
Loop
Readnext ReactorNo else Done = True$
Until Done
ReactorRow = Database_Services('ReadDataRow', 'REACTOR', ReactorNo, True$, 0)
ReactorType = ReactorRow<REACTOR_REACT_TYPE$>
SecondChamber = ReactorRow<REACTOR_SECOND_CHAMBER$>
@DICT = Database_Services('GetTableHandle', 'DICT.REACTOR_PERFORMANCE')
If (((ReactorNo GT 0) AND (ReactorNo LE 79))) AND ((ReactorType EQ 'EPP' AND SecondChamber NE '') OR (ReactorType NE 'EPP')) then
* If (ReactorNo NE 0) AND (ReactorNo LE 74) AND ((ReactorType EQ 'EPP' AND SecondChamber NE '') OR (ReactorType NE 'EPP')) AND (ReactorType NE 'GAN') then
PerfKeyID = ReactorNo : '**' : WeekYear : '*' : WeekNo : '*'
PerfRow = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', PerfKeyID, True$, 0)
DetailPerfKeyIDs = PerfRow<1>
If DetailPerfKeyIDs NE '' then
DetailPerfKeyIDs = SRP_Array('SortRows', DetailPerfKeyIDs, 'AL2', 'LIST', @VM, '*')
PrevEpiPartNo = ''
TotalWafersExpected = 0
TotalWafersExpectedRounded = 0
For Each @ID in DetailPerfKeyIDs using @VM
@RECORD = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', @ID, True$, 0)
ReactorName = {REACTOR_NAME}
EpiPartNo = {EPI_PART_NO}
If (EpiPartNo NE PrevEpiPartNo) AND (PrevepiPartNo NE '') then
// Epi Part No has changed. Add the current totals for the previous Epi Part No to
// the report and reset the variables.
ReportData := ReactorType : @VM : ReactorName : @VM : YearWeekNo : @VM : PrevEpiPartNo : @VM : TotalWafersExpected : @VM : TotalWafersExpectedRounded : @VM : ReactorNo : @FM
TotalWafersExpected = 0
TotalWafersExpectedRounded = 0
end
PrevEpiPartNo = EpiPartNo
TotalWafersExpected += Oconv({TOTAL_WAFERS_EXPECTED}, 'MD2')
TotalWafersExpectedRounded += Oconv({TOTAL_WAFERS_EXPECTED_ROUNDED}, 'MD2')
Next DetailPerfKeyID
// Add the final total values to the report.
ReportData := ReactorType : @VM : ReactorName : @VM : YearWeekNo : @VM : PrevEpiPartNo : @VM : TotalWafersExpected : @VM : TotalWafersExpectedRounded : @VM : ReactorNo : @FM
end else
ReportData := ReactorType : @VM : ReactorNo : @VM : YearWeekNo : @VM : '' : @VM : '' : @VM : '' : @VM : ReactorNo : @FM
end
end
Repeat
ReportData[-1, 1] = '' ; // Strip off the last @FM
ReportData = SRP_Array('SortRows', ReportData, 'AR7' : @VM : 'AL4', 'LIST', @FM, @VM)
CellRow = 1 ; // Initialize the cell row to start entering data into.
If ReportData NE '' then
For Each ReportRow in ReportData using @FM
ReactorType = ReportRow[1, @VM]
ReactorName = ReportRow[Col2() + 1, @VM]
YearWeekNo = ReportRow[Col2() + 1, @VM]
EpiPartNo = ReportRow[Col2() + 1, @VM]
WafersExpected = ReportRow[Col2() + 1, @VM]
WafersExpectedRounded = ReportRow[Col2() + 1, @VM]
CellRow += 1
Excel_Services('SetCellValue', objDocument, 'SSR', 'A', CellRow, ReactorType)
Excel_Services('SetCellValue', objDocument, 'SSR', 'B', CellRow, ReactorName)
Excel_Services('SetCellValue', objDocument, 'SSR', 'E', CellRow, YearWeekNo)
Excel_Services('SetCellValue', objDocument, 'SSR', 'F', CellRow, EpiPartNo)
Excel_Services('SetCellValue', objDocument, 'SSR', 'G', CellRow, WafersExpected)
Excel_Services('SetCellValue', objDocument, 'SSR', 'H', CellRow, WafersExpectedRounded)
Next ReportRow
end
end
NewDocument = YearWeekNo : ' Fab Performance.xlsx'
Excel_Services('SaveDocument', objDocument, WeeklyReportsFolder : NewDocument)
If Error_Services('NoError') then
Call Send_SRP_Mail(WeeklyReportsFolder : NewDocument)
rv = Set_Status(0)
OSRead PerformanceReport from WeeklyReportsFolder : NewDocument then
OSWrite PerformanceReport to WeeklyReportsFolder : NewDocument
If Status() then
Error_Services('Add', 'Error writing ' : WeeklyReportsFolder : NewDocument : ' in the ' : Service : ' service. Status: ' : Status())
end
end else
Error_Services('Add', 'Error reading ' : WeeklyReportsFolder : NewDocument : ' in the ' : Service : ' service. Status: ' : Status())
end
end
end
end
end service
//----------------------------------------------------------------------------------------------------------------------
// UpdateWeeklyPerformanceReport
//
// Creates daily performance tracking report using the database rows in the REACTOR_PERFORMANCE table. This creates an
// Excel spreadsheet using the "Fab Performance Daily Template.xlsx" file as a template.
//----------------------------------------------------------------------------------------------------------------------
Service UpdateWeeklyPerformanceReport(YearWeekNo)
// YearWeekNo looks like 2017-W44. For testing purposes it might be easier to pass in a date and the YearWeekNo
// will be calculated.
If (Num(Iconv(YearWeekNo, 'D')) AND (Iconv(YearWeekNo, 'D') NE '')) OR Num(YearWeekNo) then
// A internal or external formatted date was passed in.
YearWeekNo = Date_Services('GetISOWeekDate', YearWeekNo)
YearWeekNo = Field(YearWeekNo, '-', 1, 2)
end
WeekYear = YearWeekNo[1, '-']
WeekNo = YearWeekNo[Col2() + 1, '-']
Document = YearWeekNo : ' Fab Performance.xlsx'
If Excel_Services('DocumentExists', WeeklyReportsFolder : Document) then
objDocument = Excel_Services('OpenDocument', WeeklyReportsFolder : Document)
end else
Error_Services('Add', 'Unable to find ' : Document : ' in the ' : Service : ' service.')
end
If Error_Services('NoError') then
@DICT = Database_Services('GetTableHandle', 'DICT.REACTOR_PERFORMANCE')
If Error_Services('NoError') then
CellRow = 1 ; // Initialize the cell row to start entering data into.
Loop
CellRow += 1
Date = Excel_Services('GetCellValue', objDocument, 'SSR', 'E', CellRow)
Until Date EQ ''
ReactorName = Excel_Services('GetCellValue', objDocument, 'SSR', 'B', CellRow)
ReactorNo = ReactorName[1, 'F/']
EpiPartNo = Excel_Services('GetCellValue', objDocument, 'SSR', 'F', CellRow)
// Full KeyID = {REACTOR_NO} * {EPI_PART_NO} * {WEEK_YEAR} * {WEEK_NO} * {SCHEDULE_DATE}
@ID = ReactorNo : '*' : EpiPartNo : '*' : WeekYear : '*' : WeekNo : '*'
@RECORD = Database_Services('ReadDataRow', 'REACTOR_PERFORMANCE', @ID, True$, 0)
WafersProcessed = Oconv({TOTAL_WAFERS_PROCESSED}, 'MD2')
WafersDelta = Oconv({TOTAL_WAFERS_DELTA}, 'MD2')
WafersDeltaRounded = Oconv({TOTAL_WAFERS_DELTA_ROUNDED}, 'MD2')
Excel_Services('SetCellValue', objDocument, 'SSR', 'J', CellRow, WafersProcessed)
Excel_Services('SetCellValue', objDocument, 'SSR', 'K', CellRow, WafersDelta)
Excel_Services('SetCellValue', objDocument, 'SSR', 'L', CellRow, WafersDeltaRounded)
Repeat
Excel_Services('SaveDocument', objDocument)
If Error_Services('NoError') then
Call Send_SRP_Mail(WeeklyReportsFolder : Document)
rv = Set_Status(0)
OSRead PerformanceReport from WeeklyReportsFolder : Document then
OSWrite PerformanceReport to WeeklyReportsFolder : Document
If Status() then
Error_Services('Add', 'Error writing ' : WeeklyReportsFolder : Document : ' in the ' : Service : ' service. Status: ' : Status())
end
end else
Error_Services('Add', 'Error reading ' : WeeklyReportsFolder : Document : ' in the ' : Service : ' service. Status: ' : Status())
end
end
end
end
end service
Service GetReactorCurrLoad(ReactNo)
Response = ''
ReactStatusRec = Database_Services('ReadDataRow', 'REACT_STATUS', ReactNo)
LoadedCassettes = ReactStatusRec<REACT_STATUS_LOAD_CASS_ID$>
Response = LoadedCassettes
end service
Service GetReactorCurrLoadRDS(ReactNo)
Response = ''
ReactStatusRec = Database_Services('ReadDataRow', 'REACT_STATUS', ReactNo)
LoadedCassettes = ReactStatusRec<REACT_STATUS_LOAD_RDS$>
Response = LoadedCassettes
Response = ''
ReactStatusRec = Database_Services('ReadDataRow', 'REACT_STATUS', ReactNo)
LoadedCassettes = ReactStatusRec<REACT_STATUS_LOAD_RDS$>
Response = LoadedCassettes
end service
Service GetReactCurrModeRec(ReactNo)
Response = ''
ReactModeRecKey = Xlate('REACTOR_CHILD_KEY_IDS_NG', ReactNo, REACTOR_CHILD_KEY_IDS_REACT_MODE_KEY_IDS$, 'X')
ReactModeRec = Database_Services('ReadDataRow', 'REACT_MODE_NG', ReactModeRecKey)
Response = ReactModeRec
end service
Service GetReactCurrModeId(ReactNo)
Response = ''
ReactModeRecKey = Xlate('REACTOR_CHILD_KEY_IDS_NG', ReactNo, REACTOR_CHILD_KEY_IDS_REACT_MODE_KEY_IDS$, 'X')
Response = ReactModeRecKey
end service
Service GetReactCurrModeName(ReactNo)
Response = ''
ReactModeRec = Reactor_Services('GetReactCurrModeRec', ReactNo)
Response = ReactModeRec<REACT_MODE_NG_MODE$>
end service
Service GetReactModeHistory(ReactNo, DaysToReport)
StartDt = Date() - DaysToReport
Response = ''
LegacyDate = 19749
If ( (ReactNo NE '') and (DaysToReport NE '') ) then
If Date() - DaysToReport LE LegacyDate then
modeArray = ''
// New Modes
SelectSent = 'SELECT REACT_MODE_NG WITH REACT_NO = ':QUOTE(ReactNo):' AND WITH START_DT > ':QUOTE(OConv(StartDt, 'D4/')):' BY-DSND START_DTM '
Set_Status(0)
RList(SelectSent, TARGET_ACTIVELIST$, "", "", "")
IF Get_Status(errCode) THEN
ErrMsg(errCode)
RETURN
END
IF @RecCount then
EoF = 0
NumKeys = @RecCount
Cnt = 0
Loop
ReadNext Mode Else EoF = 1
until EoF
RowToAdd = ''
ServiceCategories = XLATE('REACT_MODE_NG', Mode, 'PROB_CAT_DESC', 'X')
swap @VM with @svm in ServiceCategories
ServiceDescs = XLATE('REACT_MODE_NG', Mode, 'SERV_DESC', 'X')
ReactorLogID = XLATE('REACT_MODE_NG', Mode, 'START_RL_ID', 'X')
StartDTM = OCONV(XLATE('REACT_MODE_NG', Mode, 'START_DTM', 'X'),'DT2/^HS')
ServiceNotes = XLATE('REACTOR_LOG',ReactorLogID, REACTOR_LOG_NOTES$, 'X')
swap @VM with @svm in ServiceDescs
RowToAdd <1,1> = StartDTM
RowToAdd <1,2> = OCONV(XLATE('REACT_MODE_NG', Mode,'ELAP_HRS','X'),'MD2,')
RowToAdd <1,3> = OCONV(XLATE('REACT_MODE_NG', Mode, 'MODE', 'X' ),'[REACT_MODE_CONV]')
RowToAdd <1,4> = XLATE('REACT_MODE_NG', Mode, 'START_NOTES', 'X')
RowToAdd <1,5> = ServiceCategories
RowToAdd <1,6> = XLATE('REACT_MODE_NG', Mode, 'START_USER', 'X')
RowToAdd <1,7> = ReactorLogID
RowToAdd <1,8> = ServiceDescs
ServiceNotesDtms = Xlate('REACTOR_LOG', ReactorLogID, REACTOR_LOG_NOTES_DTMS$, 'X')
ServiceNotesUsers = Xlate('REACTOR_LOG', ReactorLogID, REACTOR_LOG_NOTES_USERS$, 'X')
ServiceNotesFormatted = ''
For each ServiceNote in ServiceNotes using @VM setting vPos
ServiceNotesFormatted<0, vPos> = OConv(ServiceNotesDtms<0, vPos>, 'DT2/^H') : ' - ' : OConv(ServiceNotesUsers<0, vPos>, '[CONV_XLATE,LSL_USERS*FIRST_LAST]') : ' - ' : ServiceNote
Next ServiceNote
NumNotes = DCount(ServiceNotesFormatted, @VM)
// Wrap text using CRLF$
For NoteIndex = 1 to NumNotes
Note = ServiceNotesFormatted<0, NoteIndex>
NoteLen = Len(Note)
If NoteLen GT 100 then
NumLoops = Int(NoteLen/100)
For LoopIndex = 1 to NumLoops
Dummy = Note[LoopIndex * 100, 'F ']
Loc = Col2()
Note[Loc, 0] = CRLF$
Next LoopIndex
ServiceNotesFormatted<0, NoteIndex> = Note : CRLF$
end
Next NoteIndex
ServiceNotes = ServiceNotesFormatted
Swap @VM with CRLF$ in ServiceNotes
RowToAdd <1,9> = ServiceNotes
modeArray := RowToAdd : @FM
Repeat
end
GoSub ClearCursors
ClearSelect TARGET_ACTIVELIST$
// Old Modes
SelectSent = 'SELECT REACT_MODE WITH REACT_NO = ':QUOTE(ReactNo):' AND WITH START_DT > ':QUOTE(OConv(StartDt, 'D4/')):' BY-DSND START_DTM '
Set_Status(0)
RList(SelectSent, TARGET_ACTIVELIST$, "", "", "")
IF Get_Status(errCode) THEN
ErrMsg(errCode)
RETURN
END
IF @RecCount then
EoF = 0
NumKeys = @RecCount
Cnt = 0
Loop
ReadNext Mode Else EoF = 1
until EoF
RowToAdd = ''
ServiceCategories = XLATE('REACT_MODE', Mode, 'PROB_CAT_DESC', 'X')
swap @VM with @svm in ServiceCategories
ServiceDescs = XLATE('REACT_MODE', Mode, 'SERV_DESC', 'X')
ReactorLogID = XLATE('REACT_MODE', Mode, 'START_RL_ID', 'X')
StartDTM = OCONV(XLATE('REACT_MODE', Mode, 'START_DTM', 'X'),'DT2/^HS')
ServiceNotes = XLATE('REACTOR_LOG',ReactorLogID, REACTOR_LOG_NOTES$, 'X')
swap @VM with @svm in ServiceDescs
RowToAdd <1,1> = StartDTM
RowToAdd <1,2> = OCONV(XLATE('REACT_MODE', Mode,'ELAP_HRS','X'),'MD2,')
RowToAdd <1,3> = OCONV(XLATE('REACT_MODE', Mode, 'MODE', 'X' ),'[REACT_MODE_CONV]')
RowToAdd <1,4> = XLATE('REACT_MODE', Mode, 'START_NOTES', 'X')
RowToAdd <1,5> = ServiceCategories
RowToAdd <1,6> = XLATE('REACT_MODE', Mode, 'START_USER', 'X')
RowToAdd <1,7> = ReactorLogID
RowToAdd <1,8> = ServiceDescs
ServiceNotesDtms = Xlate('REACTOR_LOG', ReactorLogID, REACTOR_LOG_NOTES_DTMS$, 'X')
ServiceNotesUsers = Xlate('REACTOR_LOG', ReactorLogID, REACTOR_LOG_NOTES_USERS$, 'X')
ServiceNotesFormatted = ''
For each ServiceNote in ServiceNotes using @VM setting vPos
ServiceNotesFormatted<0, vPos> = OConv(ServiceNotesDtms<0, vPos>, 'DT2/^H') : ' - ' : OConv(ServiceNotesUsers<0, vPos>, '[CONV_XLATE,LSL_USERS*FIRST_LAST]') : ' - ' : ServiceNote
Next ServiceNote
NumNotes = DCount(ServiceNotesFormatted, @VM)
// Wrap text using CRLF$
For NoteIndex = 1 to NumNotes
Note = ServiceNotesFormatted<0, NoteIndex>
NoteLen = Len(Note)
If NoteLen GT 100 then
NumLoops = Int(NoteLen/100)
For LoopIndex = 1 to NumLoops
Dummy = Note[LoopIndex * 100, 'F ']
Loc = Col2()
Note[Loc, 0] = CRLF$
Next LoopIndex
ServiceNotesFormatted<0, NoteIndex> = Note : CRLF$
end
Next NoteIndex
ServiceNotes = ServiceNotesFormatted
Swap @VM with @SVM in ServiceNotes
RowToAdd <1,9> = ServiceNotes
modeArray := RowToAdd : @FM
Repeat
response = modeArray
end
end else
Open 'REACT_MODE_NG' to ReactModeTable then
OPEN 'DICT.REACT_MODE_NG' TO @DICT then
//StartDt = OCONV(StartDt,'D4/')
SelectSent = 'SELECT REACT_MODE_NG WITH REACT_NO = ':QUOTE(ReactNo):' AND WITH START_DT > ':QUOTE(OConv(StartDt, 'D4/')):' BY-DSND START_DTM '
Set_Status(0)
errCode = ''
RList(SelectSent, TARGET_ACTIVELIST$, "", "", "")
If Not(Get_Status(errCode)) then
@RecCount = 0
EOF = False$
Loop
Readnext @ID else EOF = True$
While EOF EQ False$
READO @RECORD FROM ReactModeTable,@ID then
@RecCount += 1
StartDTM = OCONV({START_DTM},'DT2/^HS')
StopDTM = OCONV({STOP_DTM},'DT2/^HS')
ElapsedHrs = OCONV({ELAP_HRS},'MD2,')
Mode = OCONV({MODE},'[REACT_MODE_CONV]')
StartRLID = {START_RL_ID}
ProbCatIDs = {PROB_CAT_ID}
ProbCatDescs = {PROB_CAT_DESC}
ServIDs = {SERV_ID}
ServDescs = {SERV_DESC}
StartUser = {START_USER}
StopUser = {STOP_USER}
Notes = {START_NOTES}
ServiceNotes = XLATE('REACTOR_LOG', StartRLID, REACTOR_LOG_NOTES$, 'X')
ServiceNotesDtms = Xlate('REACTOR_LOG', StartRLID, REACTOR_LOG_NOTES_DTMS$, 'X')
ServiceNotesUsers = Xlate('REACTOR_LOG', StartRLID, REACTOR_LOG_NOTES_USERS$, 'X')
ServiceNotesFormatted = ''
For each ServiceNote in ServiceNotes using @VM setting vPos
ServiceNotesFormatted<0, vPos> = OConv(ServiceNotesDtms<0, vPos>, 'DT2/^H') : ' - ' : OConv(ServiceNotesUsers<0, vPos>, '[CONV_XLATE,LSL_USERS*FIRST_LAST]') : ' - ' : ServiceNote
Next ServiceNote
NumNotes = DCount(ServiceNotesFormatted, @VM)
// Wrap text using CRLF$
For NoteIndex = 1 to NumNotes
Note = ServiceNotesFormatted<0, NoteIndex>
NoteLen = Len(Note)
If NoteLen GT 100 then
NumLoops = Int(NoteLen/100)
For LoopIndex = 1 to NumLoops
Dummy = Note[LoopIndex * 100, 'F ']
Loc = Col2()
Note[Loc, 0] = CRLF$
Next LoopIndex
ServiceNotesFormatted<0, NoteIndex> = Note : CRLF$
end
Next NoteIndex
ServiceNotes = ServiceNotesFormatted
FOR I = 1 TO COUNT(ProbCatIDs,@VM) + (ProbCatIDs NE '')
ProbCatDescs<1,I> = ProbCatIDs<1,I>:' - ':ProbCatDescs<1,I>
NEXT I
FOR I = 1 TO COUNT(ServIDs,@VM) + (ServIDs NE '')
ServDescs<1,I> = ServIDs<1,I>:' - ':ServDescs<1,I>
NEXT I
SWAP @VM WITH CRLF$ IN ProbCatDescs
SWAP @VM WITH CRLF$ IN ServDescs
Swap @VM with CRLF$ in ServiceNotes
Response<@RecCount, 1> = StartDTM
Response<@RecCount, 2> = ElapsedHrs
Response<@RecCount, 3> = Mode
Response<@RecCount, 4> = Notes
Response<@RecCount, 5> = ProbCatDescs
Response<@RecCount, 6> = StartUser
Response<@RecCount, 7> = StartRLID
Response<@RecCount, 8> = ServDescs
Response<@RecCount, 9> = ServiceNotes
end
Repeat
end else
ErrMsg = 'Error in service ':Service:'. Error code: ':errCode:'.'
Error_Services('Add', ErrorMsg)
end
end else
ErrorMsg = 'Unable to Open "DICT.REACT_MODE_NG" table!'
Error_Services('Add', ErrorMsg)
end
end else
ErrorMsg = 'Unable to Open "REACT_MODE_NG" table!'
Error_Services('Add', ErrorMsg)
end
end
end
end service
Service GetReactorCassLoadHistory(ReactNo, DaysToReport)
Response = ''
If ( (ReactNo NE '') and (DaysToReport NE '') ) then
Open 'RDS' to RDSTable then
OPEN 'DICT.RDS' TO @DICT then
StartDt = Date() - DaysToReport
SelectSent = 'SELECT RDS WITH REACTOR = ':QUOTE(ReactNo):' AND WITH DATE_IN > ':QUOTE(OConv(StartDt, 'D4/')):' BY-DSND DATETIME_IN '
Set_Status(0)
errCode = ''
RList(SelectSent, TARGET_ACTIVELIST$, "", "", "")
If Not(Get_Status(errCode)) then
@RecCount = 0
EOF = False$
Loop
Readnext @ID else EOF = True$
While EOF EQ False$
READO @RECORD FROM RDSTable,@ID then
@RecCount += 1
RDSNo = {SEQ}
DateIn = OCONV({DATETIME_IN},'DT2/^HS')
DateOut = OCONV({DATETIME_OUT},'DT2/^HS')
LoadOperator = {OPERATOR_IN}
UnLoadOperator = {OPERATOR_OUT}
Response<@RecCount, 1> = RDSNo
Response<@RecCount, 2> = DateIn
Response<@RecCount, 3> = DateOut
Response<@RecCount, 4> = LoadOperator
Response<@RecCount, 5> = UnLoadOperator
end
Repeat
end else
ErrMsg = 'Error in service ':Service:'. Error code: ':errCode:'.'
Error_Services('Add', ErrorMsg)
end
end else
ErrorMsg = 'Unable to Open "DICT.RDS" table!'
Error_Services('Add', ErrorMsg)
end
end else
ErrorMsg = 'Unable to Open "RDS" table!'
Error_Services('Add', ErrorMsg)
end
end
end service
Service GetReactorCassLoadHistoryRange(ReactNo, StartDTM, StopDTM)
Response = ''
If ( (ReactNo NE '') and (StartDTM NE '') and (StopDTM NE '')) then
Open 'RDS' to RDSTable then
OPEN 'DICT.RDS' TO @DICT then
SelectSent = 'SELECT RDS WITH REACTOR EQ ':ReactNo:' AND WITH DATETIME_IN GE ':StartDTM:' AND WITH DATETIME_IN LE ':StopDTM:' BY-DSND DATETIME_IN '
Set_Status(0)
errCode = ''
RList(SelectSent, TARGET_ACTIVELIST$, "", "", "")
If Not(Get_Status(errCode)) then
@RecCount = 0
EOF = False$
Loop
Readnext @ID else EOF = True$
While EOF EQ False$
READO @RECORD FROM RDSTable,@ID then
@RecCount += 1
RDSNo = {SEQ}
DateIn = OCONV({DATETIME_IN},'DT2/^HS')
DateOut = OCONV({DATETIME_OUT},'DT2/^HS')
LoadOperator = {OPERATOR_IN}
UnLoadOperator = {OPERATOR_OUT}
Response<@RecCount, 1> = RDSNo
Response<@RecCount, 2> = DateIn
Response<@RecCount, 3> = DateOut
Response<@RecCount, 4> = LoadOperator
Response<@RecCount, 5> = UnLoadOperator
end
Repeat
end else
ErrMsg = 'Error in service ':Service:'. Error code: ':errCode:'.'
Error_Services('Add', ErrorMsg)
end
end else
ErrorMsg = 'Unable to Open "DICT.RDS" table!'
Error_Services('Add', ErrorMsg)
end
end else
ErrorMsg = 'Unable to Open "RDS" table!'
Error_Services('Add', ErrorMsg)
end
end
end service
Service IncrementCycleCount(ToolID)
If ToolID NE '' then
// A reactor number may be passed in. Convert it to the corresponding tool ID if necessary.
If Num(ToolID) then ToolID = 'R':ToolID
ToolRec = Database_Services('ReadDataRow', 'TOOL', ToolID)
If Error_Services('NoError') then
CycleCnt = ToolRec<TOOL_CYCLE_CNT$>
CycleCnt += 1
ToolRec<TOOL_CYCLE_CNT$> = CycleCnt
Database_Services('WriteDataRow', 'TOOL', ToolID, ToolRec, True$, False$, True$)
end
end
end service
Service CreateReactModeChange(UserID, ReactNo, Mode, ModeSubCat, ModeText, ForceModeChange)
LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\ReactorModeChg'
LogDate = Oconv(Date(), 'D4/')
LogTime = Oconv(Time(), 'MTS')
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Mode Change Log.csv'
Headers = 'Logging DTM' : @FM : 'Notes'
objLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ' ', Headers, '', False$, False$, True$)
LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM
ErrorMsg = ''
IF ForceModeChange NE True$ then ForceModeChange = False$
If ( (UserID NE '') and (ReactNo NE '') and (Mode NE '') and (ModeSubCat NE '')) then
CurTime = Time()
CurDate = Date()
NGPrevModeKey = Xlate('REACTOR_CHILD_KEY_IDS_NG', ReactNo, REACTOR_CHILD_KEY_IDS_REACT_MODE_KEY_IDS$, 'X')<1, 1>
PrevModeRec = Reactor_Services('GetReactCurrModeRec', ReactNo)
SelectedModeRec = Database_Services('ReadDataRow', 'REACTOR_MODES', Mode)
SelE10State = SelectedModeRec<REACTOR_MODES_E10_STATE$>
CommentException = False$
Begin Case
Case PrevModeRec<REACT_MODE_NG_MODE$> EQ 'WAITING_FOR_MAINTENANCE_UNSCHEDULED' AND Mode EQ 'MAINTENANCE_UNSCHEDULED'
CommentException = True$
Case PrevModeRec<REACT_MODE_NG_MODE$> EQ 'WAITING_FOR_MAINTENANCE_SCHEDULED' AND Mode EQ 'MAINTENANCE_SCHEDULED'
CommentException = True$
Case PrevModeRec<REACT_MODE_NG_MODE$> EQ 'WAITING_FOR_ENGINEER_UNSCHEDULED' AND Mode EQ 'ENGINEERING_INVESTIGATION'
CommentException = True$
Case PrevModeRec<REACT_MODE_NG_MODE$> EQ 'WAITING_FOR_ENGINEER_SCHEDULED' AND Mode EQ 'ENGINEERING_DEVELOPMENT'
CommentException = True$
Case PrevModeRec<REACT_MODE_NG_MODE$> EQ 'WAITING_FOR_ENGTECH_UNSCHEDULED' AND (Mode EQ 'TROUBLESHOOT_ENGTECH' OR Mode EQ 'ENGINEERING_INVESTIGATION')
CommentException = True$
Case PrevModeRec<REACT_MODE_NG_MODE$> EQ 'WAITING_FOR_ENGTECH_SCHEDULED' AND Mode EQ 'ENGINEERING_DEVELOPMENT'
CommentException = True$
End Case
If ((ModeText NE '') and (Len(ModeText) GE 4)) OR CommentException then
NewModeCategory = SelectedModeRec<REACTOR_MODES_MODE_CATEGORY$>
OldRlRecordKey = PrevModeRec<REACT_MODE_NG_START_RL_ID$>
If Reactor_Log_Services('IsMaint', OldRlRecordKey) AND ForceModeChange EQ False$ then
If (NOT(Reactor_Log_Services('IsSigned', OldRlRecordKey))) then
ErrorMsg = 'The current mode cannot be changed until the technician has signed off on the Reactor Log.'
end
end
ModeSubCatID = ''
Locate ModeSubCat in SelectedModeRec<REACTOR_MODES_SERVICE_CATEGORIES$> using @VM setting SvcPos then
NewModeSvcList = SelectedModeRec<REACTOR_MODES_SERVICE_CATEGORY_ID$>
ModeSubCatID = NewModeSvcList<1,SvcPos>
end else
ErrorMsg = 'Failed to locate ModeSubCat.'
end
CurrentMode = PrevModeRec<REACT_MODE_NG_MODE$>
ActiveProveInPreventsModeChange = Reactor_Services('ActiveProveInPreventsModeChange', ReactNo, Mode, CurrentMode)
If Error_Services('HasError') then
ErrorMsg = Error_Services('GetMessage')
end else
If ActiveProveInPreventsModeChange EQ True$ then
ErrorMsg = 'A reactor prove in is required before changing the mode. Active prove in types: '
TypeList = ''
ProveInTypes = Reactor_Services('GetActiveProveInTypes', ReactNo)
for each ProveInType in ProveInTypes using @VM setting Idx
If Idx GT 1 then
TypeList := ', '
end
TypeList := ProveInType
Next ProveInType
ErrorMsg := TypeList
end
end
IdleStartupRequired = Reactor_Services('GetIdleStartupRequired', ReactNo)
If ErrorMsg EQ '' and IdleStartupRequired and Mode[1, 2] EQ 'UP' then
ProveInTypes = Reactor_Services('GetActiveProveInTypes', ReactNo)
IdleStartupActive = False$
For each ProveInType in ProveInTypes using @VM setting Idx
If ProveInType EQ 'IDLE' then
IdleStartupActive = True$
end
Next ProveInType
If IdleStartupActive EQ True$ then
ErrorMsg = "You must complete the IDLE_STARTUP prove in checklist before putting the reactor UP."
end else
ErrorMsg = "An IDLE_STARTUP prove in checklist is required before putting the reactor UP. Change the mode to IDLE_STARTUP, then complete the checklist."
end
end
If ErrorMsg EQ '' then
ActiveHgCVChecklists = Nica_Orders_Services('GetActiveOrders', 'REACTOR', ReactNo, 'IQS_HGCV_ALARM')
HgCVChecklistActive = (ActiveHgCVChecklists NE '')
If ( HgCVChecklistActive and (SelE10State _EQC 'Productive') ) then
ErrorMsg = "An HgCV OCAP Checklist is active for this reactor and must be completed or overridden in order to change to a productive state."
end
end
If ErrorMsg EQ '' then
IntrMaintFeatureFlag = Xlate('FEATURE_FLAGS', 'NICA_INTRUSIVE_MAINTENANCE', FEATURE_FLAGS.ENABLED$, 'X')
If IntrMaintFeatureFlag EQ True$ then
ActiveIntrusiveMaintChecklists = Nica_Orders_Services('GetActiveOrders', 'REACTOR', ReactNo, 'INTRUSIVE_MAINT')
IntrusiveMaintChecklistActive = (ActiveIntrusiveMaintChecklists NE '')
If ( IntrusiveMaintChecklistActive and (SelE10State _EQC 'Productive') ) then
ErrorMsg = "An Intrusive Maintenance Checklist is active for this reactor and must be completed or overridden in order to change to a productive state."
end
end
end
If ErrorMsg EQ '' then
If Len(Mode) GT 10 and Mode[1, 10] EQ 'CHANGEOVER' then
Nica_Orders_Services('CreateNewOrder', 'REACTOR', ReactNo, 'CHANGEOVER')
end
If Mode EQ 'INITIATE_IDLE' then
Nica_Orders_Services('CreateNewOrder', 'REACTOR', ReactNo, 'INITIATE_IDLE')
end
If Mode EQ 'IDLE_STARTUP' then
Nica_Orders_Services('CreateNewOrder', 'REACTOR', ReactNo, 'IDLE')
end
end
If ErrorMsg EQ '' then
//Log the current Mode Change
LogData = ''
LogData<1> = Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTS') ; // Logging DTM
LogData<2> = 'Reactor No: ' : ReactNo : ' - Requested Mode Change: ' : Mode
Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$)
OldReactUtilID = PrevModeRec<REACT_MODE_NG_START_RU_ID$>
if OldReactUtilID NE '' then
OldReactUtilRec = Database_Services('ReadDataRow', 'REACT_UTIL', OldReactUtilID)
OldReactUtilRec<react_util_end_date$> = CurDate
OldReactUtilRec<react_util_end_time$> = CurTime
OldReactUtilRec<react_util_mode_finish_user$> = UserId
Database_Services('WriteDataRow', 'REACT_UTIL', OldReactUtilID, OldReactUtilRec)
end
If Error_Services('NoError') then
**********************************************************************************
* WRITE OUT NEW MODE INFORMATION
//Create new React_Util record
NewRUKey = NextKey('REACT_UTIL')
If Error_Services('NoError') then
NewRLKey = NextKey('REACTOR_LOG')
If Error_Services('NoError') then
RUtilRec = ''
RUtilRec<react_util_reactor$> = ReactNo
RUtilRec<REACT_UTIL_NOTES$> = ModeText
RMode = ''
RUtilRec<react_util_mode$> = Mode
RUtilRec<react_util_start_date$> = CurDate
RUtilRec<react_util_start_time$> = CurTime
RUtilRec<react_util_mode_start_user$> = UserID
RUtilRec<react_util_reactor_log_id$> = NewRLKey
// Get current work order from the CONFIG table
DailySchedName = 'WO_DAILY_SCHED':ReactNo
DSR = XLATE('CONFIG', DailySchedName, '', 'X')
WOCust = DSR<WOCust$>
WorkOrder = Field(WOCust, ' ', 1)
RUtilRec<react_util_wo$> = WorkOrder
RUtilRec<react_util_cust_no$> = xlate( 'WO_LOG', WorkOrder, wo_log_cust_no$, 'X' ) ;
********************************************************************************************************
//Create a new Reactor_Log Entry
EntryId = UserID
RLRec = ''
RLRec<reactor_log_start_date$> = CurDate
RLRec<reactor_log_start_time$> = CurTime
RLRec<reactor_log_reactor$> = ReactNo
if NewModeCategory EQ 'MAINTENANCE' then
RLRec<reactor_log_category$> = 'M' ;* for maintenance
end
RLRec<reactor_log_entry_id$> = UserID
RLRec<reactor_log_entry_date$> = CurDate
RLRec<reactor_log_react_util_id$> = NewRUKey
RLRec<reactor_log_react_prob_cat_id$> = ModeSubCatID
Database_Services('WriteDataRow', 'REACTOR_LOG', NewRLKey, RLRec)
If Error_Services('NoError') then
Database_Services('WriteDataRow', 'REACT_UTIL', NewRUKey, RUtilRec)
If Error_Services('NoError') then
Rec = ''
Rec<Mode$> = Mode
Rec<Username$> = oconv( UserID, '[XLATE_CONV,LSL_USERS*FIRST_LAST]' )
Rec<Date$> = oconv( CurDate, 'D4/' )
Rec<Time$> = oconv( CurTime, 'MTH' )
Rec<ReactUtilID$> = NewRUKey
Rec<ReactorLogID$> = NewRLKey
Rec<Service$> = ModeSubCat
Rec<Note$> = ModeText
CurrDTM = Rec<Date$>:" ":Rec<Time$>
NGPrevModeDTM = Field(NGPrevModeKey, '*', 2)
PrevModeKey = NGPrevModeKey
OldMode = OCONV(XLATE('REACTOR',ReactNo,'CURR_MODE','X'),'[REACT_MODE_CONV]')
OpenDTM = FIELD(PrevModeKey,'*',2)
OpenDTM = OCONV(OpenDTM,'DT4/^S')
Mode = Rec<Mode$>
RecName = 'REACT_MODE':ReactNo
* * * * * Changes by JCH on 11/5/2007 * * * * *
ProdModes = 'Production':@VM
ProdModes := 'Production (incr sampling)':@VM
ProdModes := 'UP_WITH_RESTRICTIONS':@VM
ProdModes := 'UP':@VM
ProdModes := 'UP_WITH_INCREASED_SAMPLING':@VM
ProdModes := 'UP_WITH_INCREASED_SAMPLING_SAMPLING':@VM
ProdModes := 'UP_WITH_INCREASED_SAMPLING_METROLOGY':@VM
ProdModes := 'UP_NOT_RUNNING':@VM
LogData = ''
LogData<1> = Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTS') ; // Logging DTM
LogData<2> = 'Reactor No: ' : ReactNo : ' - Current Mode: ' : OldMode : ' - New Mode: ' : Mode
Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$)
LOCATE OldMode IN ProdModes USING @VM SETTING DUMMY THEN
LOCATE Mode IN ProdModes USING @VM SETTING DUMMY ELSE
OutOfProdDTM = Rec<Date$>:' ':Rec<Time$>
obj_React_Status('SetOutOfProdDTM',ReactNo:@RM:OutOfProdDTM)
IF Get_Status(errCode) THEN ErrorMsg = errCode
END ;* End of check on New Mode
END ;* End of check on Current Mode
* * * End of changes * * * * *
//Write new mode info to config table.
OrigConfigRec = Database_Services('ReadDataRow', 'CONFIG', RecName)
Database_Services('WriteDataRow', 'CONFIG', RecName, Rec)
If Error_Services('NoError') then
IF OldMode NE '' THEN
crParms = ReactNo
crParms := @RM:OpenDTM
crParms := @RM:CurrDTM
crParms := @RM:UserID
crParms := @RM:Rec<Note$>
crParms := @RM:Rec<ReactUtilID$>
crParms := @RM:Rec<ReactorLogID$>
LogData = ''
LogData<1> = Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTS') ; // Logging DTM
LogData<2> = 'Reactor No: ' : ReactNo : ' - obj_React_Mode("Close") - Key ID: ' : ReactNo : '*' : Iconv(OpenDTM, 'DT')
Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$)
obj_React_Mode('Close',crParms) ;* Close the currently active mode
END
If Not(Get_Status(errCode)) then
crParms = ReactNo
crParms := @RM:CurrDTM
crParms := @RM:UserID
crParms := @RM:Mode
crParms := @RM:Rec<Note$>
crParms := @RM:Rec<ReactUtilID$>
crParms := @RM:Rec<ReactorLogID$>
crParms := @RM:ModeSubCat
LogData = ''
LogData<1> = Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTS') ; // Logging DTM
LogData<2> = 'Reactor No: ' : ReactNo : ' - obj_React_Mode("Create") - Key ID: ' : ReactNo : '*' : Iconv(CurrDTM, 'DT')
Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$)
obj_React_Mode('Create',crParms) ;* Create new active mode record
IF Get_Status(errCode) THEN
// Failed to create new react mode
ErrorMsg = errCode
GoSub RollbackReactUtil
// Delete new REACTOR_LOG record
Database_Services('DeleteDataRow', 'REACTOR_LOG', NewRLKey)
// Delete new REACT_UTIL record
Database_Services('DeleteDataRow', 'REACT_UTIL', NewRUKey)
// Rollback CONFIG record
Database_Services('WriteDataRow', 'CONFIG', RecName, OrigConfigRec)
// Reopen previous react mode
Database_Services('WriteDataRow', 'REACT_MODE_NG', NGPrevModeKey, PrevModeRec)
end else
// Check to see if notifications are active for this mode
If SelectedModeRec<REACTOR_MODES_NOTIFICATION_ACTIVE$> then
//If notifications are active get the classes from the REACTOR_MODE record
SendToClasses = SelectedModeRec<REACTOR_MODES_NOTIFY_CLASS$>
For each class in SendToClasses using @VM
//Send to all the classes
notesParms = ''
IncludeNextShift = False$
//If we are close to shift change we want to add in the next shift.
CurrTime = Time()
if SRP_Time('Hour', CurrTime) EQ 17 OR SRP_Time('Hour', CurrTime) EQ 5 then
IncludeNextShift = True$
end
Recipients = LSL_USERS_SERVICES('GetOnShiftUsersByClass', class, IncludeNextShift); *Get all the on shift recipients
SentFrom = 'OI_ADMIN'
Subject = 'Reactor Mode Notification - ': ReactNo : ' ' : Mode
Message = 'Reactor: ' :ReactNo: ' has been placed into ' : Mode :'.'
Message := CRLF$ : 'Sub-Category: ' : ModeSubCat
Message := CRLF$ : 'User: ' : UserID
Message := CRLF$ : 'Notes: '
Message := CRLF$ : ModeText
AttachWindow = ''
AttachKey = ''
SendToGroup = ''
notesParms = Recipients:@RM:SentFrom:@RM:Subject:@RM:Message:@RM:AttachWindow:@RM:AttachKey:@RM:SendToGroup
Obj_Notes('Create', notesParms)
Next class
end
// If new mode sub category is an ABORT/ALARM or particular Facilities Failure, then apply abort metrology to the oldest loaded RDS
ReactType = Xlate('REACTOR', ReactNo, 'REACT_TYPE', 'X')
If ReactType NE 'EPP' then
Begin Case
Case ModeSubCat _EQC 'ABORT/ALARM - TC Failure'
ApplyAbortMet = True$
Case ModeSubCat _EQC 'ABORT/ALARM - Contactor Not Sensed On'
ApplyAbortMet = True$
Case ModeSubCat _EQC 'ABORT/ALARM - Temp Up Failure'
ApplyAbortMet = True$
Case ModeSubCat _EQC 'Gas Delivery Issue'
ApplyAbortMet = True$
Case ModeSubCat _EQC 'Toxic Gas Alarm'
ApplyAbortMet = True$
Case ModeSubCat _EQC 'ABORT/ALARM - Facilities Level Failure'
ApplyAbortMet = True$
Case ModeSubCat _EQC 'ABORT/ALARM - Exhaust System Failure (Scrubber Toxic)'
ApplyAbortMet = True$
Case ModeSubCat _EQC 'ABORT/ALARM - Gas Flow - TCS'
ApplyAbortMet = True$
Case ModeSubCat _EQC 'ABORT/ALARM - Gas Flow - Dopant'
ApplyAbortMet = True$
Case ModeSubCat _EQC 'ABORT/ALARM - Gas Flow - Hydrogen'
ApplyAbortMet = True$
Case ModeSubCat _EQC 'ABORT/ALARM - Susceptor Faults'
ApplyAbortMet = True$
Case ModeSubCat _EQC 'ABORT/ALARM - 24V. Interlock Abort'
ApplyAbortMet = True$
Case ModeSubCat _EQC 'ABORT/ALARM - Wafer Handling'
ApplyAbortMet = True$
Case Otherwise$
ApplyAbortMet = False$
End Case
If ApplyAbortMet then
LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\ReactorAborts'
LogDate = Oconv(Date(), 'D4/')
LogTime = Oconv(Time(), 'MTS')
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Reactor Abort Log.csv'
Headers = 'Logging DTM' : @FM : 'ReactorNo' : @FM : 'Notes'
objAbortLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ' ', Headers, '', False$, False$, True$)
LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM
LogMsg = 'Intermediate or Major ABORT/ALARM mode sub category, ':ModeSubCat:'. '
LogMsg := 'Attempting to apply abort metrology to loaded RDS.'
LogData = ''
LogData<1> = LoggingDtm
LogData<2> = ReactNo
LogData<3> = LogMsg
Logging_Services('AppendLog', objAbortLog, LogData, @RM, @FM)
// Get the loaded RDS key(s) and apply abort metrology. If two are loaded, select the one loaded first.
LoadedRdsKeys = Xlate('REACT_STATUS', ReactNo, 'LOAD_RDS', 'X')
If LoadedRdsKeys NE '' then
AbortRds = ''
Begin Case
Case DCount(LoadedRdsKeys, @VM) EQ 2
// Select the oldest one
LoadDtms = Xlate('RDS', LoadedRdsKeys, 'DATETIME_IN', 'X')
If LoadDtms<0, 2> GT LoadDtms<0, 1> then
AbortRds = LoadedRdsKeys<0, 1>
end else
AbortRds = LoadedRdsKeys<0, 2>
end
Swap @VM with ' ' in LoadedRdsKeys
LogMsg = 'Two loaded RDS keys, ':LoadedRdsKeys:', found in REACT_STATUS record.'
LogData = ''
LogData<1> = LoggingDtm
LogData<2> = ReactNo
LogData<3> = LogMsg
Logging_Services('AppendLog', objAbortLog, LogData, @RM, @FM)
LogMsg = 'Selecting RDS ':AbortRDS:' as it was loaded earlier.'
LogData = ''
LogData<1> = LoggingDtm
LogData<2> = ReactNo
LogData<3> = LogMsg
Logging_Services('AppendLog', objAbortLog, LogData, @RM, @FM)
Case DCount(LoadedRdsKeys, @VM) EQ 1
// Only one loaded, so use that
AbortRds = LoadedRdsKeys
LogMsg = 'One loaded RDS key, ':AbortRds:', found in REACT_STATUS record.'
LogData = ''
LogData<1> = LoggingDtm
LogData<2> = ReactNo
LogData<3> = LogMsg
Logging_Services('AppendLog', objAbortLog, LogData, @RM, @FM)
Case Otherwise$
// Unexpected condition - log error
Swap @VM with ' ' in LoadedRdsKeys
LogMsg = 'Error selecting RDS to apply abort metrology to. Loaded RDS keys, ':LoadedRdsKeys:', found in REACT_STATUS record.'
LogData = ''
LogData<1> = LoggingDtm
LogData<2> = ReactNo
LogData<3> = LogMsg
Logging_Services('AppendLog', objAbortLog, LogData, @RM, @FM)
End Case
If AbortRds NE '' then
LogMsg = 'Attempting to apply abort metrology to RDS ':AbortRds:'.'
LogData = ''
LogData<1> = LoggingDtm
LogData<2> = ReactNo
LogData<3> = LogMsg
Logging_Services('AppendLog', objAbortLog, LogData, @RM, @FM)
Rds_Services('ApplyAbortMetrology', AbortRds)
If Error_Services('NoError') then
LogMsg = 'Successfully applied abort metrology to RDS ':AbortRds:'.'
LogData = ''
LogData<1> = LoggingDtm
LogData<2> = ReactNo
LogData<3> = LogMsg
Logging_Services('AppendLog', objAbortLog, LogData, @RM, @FM)
end else
ErrorMsg = Error_Services('GetMessage')
LogMsg = 'Error occurred while applying abort metrology to RDS ':AbortRds:'. Error message: ':ErrorMsg
LogData = ''
LogData<1> = LoggingDtm
LogData<2> = ReactNo
LogData<3> = LogMsg
Logging_Services('AppendLog', objAbortLog, LogData, @RM, @FM)
end
end
end else
// No loaded RDS runs detected
LogMsg = 'No loaded RDS keys found in REACT_STATUS record.'
LogData = ''
LogData<1> = LoggingDtm
LogData<2> = ReactNo
LogData<3> = LogMsg
Logging_Services('AppendLog', objAbortLog, LogData, @RM, @FM)
end
end
end
end
end else
// Failed to close previous react mode
ErrorMsg = errCode
GoSub RollbackReactUtil
// Delete new REACTOR_LOG record
Database_Services('DeleteDataRow', 'REACTOR_LOG', NewRLKey)
// Delete new REACT_UTIL record
Database_Services('DeleteDataRow', 'REACT_UTIL', NewRUKey)
// Rollback CONFIG record
Database_Services('WriteDataRow', 'CONFIG', RecName, OrigConfigRec)
end
END ELSE
ErrorMsg = 'Reactor No: ' : ReactNo : 'Unable to write ':RecName:' on CONFIG table...' : ReactNo : '*' : Iconv(CurrDTM, 'DT')
LogData = ''
LogData<1> = Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTS') ; // Logging DTM
LogData<2> = ErrorMsg
Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$)
GoSub RollbackReactUtil
// Delete new REACTOR_LOG record
Database_Services('DeleteDataRow', 'REACTOR_LOG', NewRLKey)
// Delete new REACT_UTIL record
Database_Services('DeleteDataRow', 'REACT_UTIL', NewRUKey)
end
end else
// Failed to write REACT_UTIL record
ErrorMsg = Error_Services('GetMessage')
GoSub RollbackReactUtil
// Delete new REACTOR_LOG record
Database_Services('DeleteDataRow', 'REACTOR_LOG', NewRLKey)
end
end else
// Failed to write REACTOR_LOG record
ErrorMsg = Error_Services('GetMessage')
GoSub RollbackReactUtil
end
end else
// Failed to get new REACTOR_LOG key
ErrorMsg = Error_Services('GetMessage')
GoSub RollbackReactUtil
end
end else
// Failed to get new REACT_UTIL key
ErrorMsg = Error_Services('GetMessage')
GoSub RollbackReactUtil
end
end else
ErrorMsg = Error_Services('GetMessage')
end
end
end else
Begin Case
Case ModeText EQ ''
ErrorMsg = 'You must enter a comment.'
Case Len(ModeText) LT 5
ErrorMsg = 'Comments must be more than 4 characters...'
End Case
end
end else
Begin Case
Case UserID EQ ''
ErrorMsg = 'Null UserID passed into service.'
Case ReactNo EQ ''
ErrorMsg = 'You must choose a Reactor.'
Case Mode EQ ''
ErrorMsg = 'You must choose a VALID Reactor Mode.'
Case ModeSubCat EQ ''
ErrorMsg = 'You must choose a VALID Reactor Problem Category.'
End Case
end
If ErrorMsg EQ '' then
Response = True$
end else
Error_Services('Add', 'Error in ':Service:' service. ':ErrorMsg)
Response = False$
end
end service
Service FormatReactStatusSingle(ReactNo)
Response = ''
CurrModeRec = Reactor_Services('GetReactCurrModeRec', ReactNo)
CurrLoadings = Reactor_Services('GetReactorCurrLoad', ReactNo)
ReactStatusArray = CurrModeRec
ReactStatusArray<12> = CurrLoadings; *Currently loaded cassettes
Response = ReactStatusArray
end service
Service GetSingleReactStatusJson(reactNo)
response = ''
// Create the root object JSON
If SRP_Json(objReactor, "New") then
// Create the array of reactors
If SRP_Json(objReactorArray, "New", "Array") then
ReactStatusArray = Reactor_Services('FormatReactStatusSingle', reactNo)
CurrE10State = Xlate('REACTOR_MODES', ReactStatusArray<REACT_MODE_NG_MODE$>, REACTOR_MODES_E10_STATE$, 'X')
ModeIconName = Xlate('REACTOR_MODES', ReactStatusArray<REACT_MODE_NG_MODE$>, REACTOR_MODES_ICON$, 'X')
RunningStatus = false$
CurrLoad = Reactor_Services('GetReactorCurrLoad', ReactNo)
CurrSubCat = ReactStatusArray<REACT_MODE_NG_SERVICE_DESC$>
if CurrLoad NE '' then
RunningStatus = true$
end
objSingleReactor = ''
If SRP_Json(objSingleReactor, "New") then
SRP_JSON(objSingleReactor, 'SETVALUE', 'ReactorNumber', reactNo, 'STRING')
SRP_JSON(objSingleReactor, 'SETVALUE', 'ReactorMode', ReactStatusArray<REACT_MODE_NG_MODE$>, 'STRING')
SRP_JSON(objSingleReactor, 'SETVALUE', 'E10State', CurrE10State, 'STRING')
SRP_JSON(objSingleReactor, 'SETVALUE', 'ModeIconName', ModeIconName, 'STRING')
SRP_JSON(objSingleReactor, 'SETVALUE', 'IsRunning', RunningStatus, 'BOOLEAN')
SRP_JSON(objSingleReactor, 'SETVALUE', 'ModeSubCat', CurrSubCat, 'STRING')
SRP_Json(objReactorArray, "Add", objSingleReactor)
SRP_Json(objSingleReactor, "Release")
end
// Now add the array as a member of the root object
SRP_Json(objReactor, "Set", "reactors", objReactorArray)
// All done with the array object
SRP_Json(objReactorArray, "Release")
end
// Now get the actual JSON
resultingJSON = SRP_Json(objReactor, "Stringify", "STYLED")
// All done with the root object
SRP_Json(objReactor, "Release")
end
response = resultingJSON
end service
Service GetAllReactStatusJson()
Response = ''
AllReactNos = Reactor_Services('GetReactorNumbers')
//Create the root objec JSON
If SRP_Json(objReactor, "New") then
//Create the array of reactors
If SRP_Json(objReactorArray, "New", "Array") then
//Loop through all reactor nums and add to the array
for each reactNo in AllReactNos using @FM
if reactNo NE 'Cln' OR reactNo NE '140' then
ReactStatusArray = Reactor_Services('FormatReactStatusSingle', reactNo)
CurrE10State = Xlate('REACTOR_MODES', ReactStatusArray<REACT_MODE_NG_MODE$>, REACTOR_MODES_E10_STATE$, 'X')
ModeIconName = Xlate('REACTOR_MODES', ReactStatusArray<REACT_MODE_NG_MODE$>, REACTOR_MODES_ICON$, 'X')
RunningStatus = false$
CurrLoad = Reactor_Services('GetReactorCurrLoad', ReactNo)
if CurrLoad NE '' then
RunningStatus = true$
end
If SRP_Json(objSingleReactor, "New") then
SRP_JSON(objSingleReactor, 'SETVALUE', 'ReactorNumber', reactNo, 'STRING')
SRP_JSON(objSingleReactor, 'SETVALUE', 'ReactorMode', ReactStatusArray<REACT_MODE_NG_MODE$>, 'STRING')
SRP_JSON(objSingleReactor, 'SETVALUE', 'E10State', CurrE10State, 'STRING')
SRP_JSON(objSingleReactor, 'SETVALUE', 'ModeIconName', ModeIconName, 'STRING')
SRP_JSON(objSingleReactor, 'SETVALUE', 'IsRunning', RunningStatus, 'BOOLEAN')
SRP_Json(objReactorArray, "Add", objSingleReactor)
SRP_Json(objSingleReactor, "Release")
end
end
Next reactNo
// Now add the array as a member of the root object
SRP_Json(objReactor, "Set", "reactors", objReactorArray)
// All done with the array object
SRP_Json(objReactorArray, "Release")
end
// Now get the actual JSON
resultingJSON = SRP_Json(objReactor, "Stringify", "STYLED")
// All done with the root object
SRP_Json(objReactor, "Release")
end
response = resultingJSON
end service
Service IsReactorLoaded(ReactNo)
ErrorMsg = ''
Response = False$
If ReactNo NE '' then
LoadedRDS = Xlate('REACT_STATUS', ReactNo, 'LOAD_RDS', 'X')
If LoadedRDS NE '' then Response = True$
end else
ErrorMsg = 'Error in ':Service:' service. Null ReactNo passed in.'
end
If ErrorMsg NE '' then
Error_Services('Add', ErrorMsg)
end
end service
Service GetReactorTimeSinceUnload(ReactNo)
ErrorMsg = ''
Response = 0
If ReactNo NE '' then
LastUnloadTime = Xlate('REACT_STATUS', ReactNo, 'UNLOAD_DTM', 'X')
Response = SRP_DateTime("MinuteSpan", LastUnloadTime, Datetime(), 0)
end else
ErrorMsg = 'Error in ':Service:' service. Null ReactNo passed in.'
end
If ErrorMsg NE '' then
Error_Services('Add', ErrorMsg)
end
end service
Service ConvertRecordToJSON(ReactorNo, ItemURL, CurrUser, FullObject=BOOLEAN)
If FullObject EQ '' then FullObject = True$
ErrorMsg = ''
JSON = ''
If ReactorNo then
objJSON = ''
If SRP_JSON(objJSON, 'New', 'Object') then
// Add in reactor current mode, available modes, and available sub categories.
CurrModeKey = Reactor_Services('GetReactCurrModeId', ReactorNo)
CurrMode = Xlate('REACT_MODE_NG', CurrModeKey, REACT_MODE_NG_MODE$, 'X')
ServiceDesc = Xlate('REACT_MODE_NG', CurrModeKey, REACT_MODE_NG_SERVICE_DESC$, 'X')
If (CurrUser NE '') then AvailModes = Reactor_Modes_Services('AvailableModes', CurrMode, CurrUser)
CurrRLKey = Xlate('REACT_MODE_NG', CurrModeKey, REACT_MODE_NG_START_RL_ID$ , 'X')
ReactorType = Xlate('REACTOR', ReactorNo, 'REACT_TYPE', 'X')
ReactAssign = Xlate('REACTOR', ReactorNo, 'REACT_ASSIGNMENT', 'X')
React_Assign_Conv('OCONV', ReactAssign, '', ReactAssign)
// Create reactor object
If SRP_JSON(objReactor, 'New', 'Object') then
SRP_JSON(objReactor, 'SetValue', 'reactorNo', ReactorNo)
SRP_JSON(objReactor, 'SetValue', 'reactType', ReactorType)
SRP_JSON(objReactor, 'SetValue', 'reactAssignment', ReactAssign)
PickPlace = Xlate('REACTOR', ReactorNo, 'PICK_PLACE', 'X')
SRP_JSON(objReactor, 'SetValue', 'pickPlace', PickPlace, 'Boolean')
LLDisabledKey = Xlate('REACTOR', ReactorNo, 'ACTIVE_LL_DISABLED', 'X')
LoadLockDisabled = Xlate('REACT_LL', LLDisabledKey, 'DISABLED', 'X')
SRP_JSON(objReactor, 'SetValue', 'loadLockDown', LoadLockDisabled)
SRP_JSON(objReactor, 'SetValue', '0311Active', Xlate('REACTOR', ReactorNo, '0311_ACTIVE', 'X'), 'Boolean')
SRP_JSON(objReactor, 'SetValue', 'active0311Checklist', Xlate('REACTOR', ReactorNo, '0311_ACTIVE', 'X'), 'Boolean')
SRP_JSON(objReactor, 'SetValue', 'TubeBellJarCnt', Xlate('REACTOR', ReactorNo, REACTOR_TUBE_BELL_JAR_THK$, 'X'))
SRP_JSON(objReactor, 'SetValue', 'TubeBellJarThk', Xlate('REACTOR', ReactorNo, REACTOR_TUBE_BELL_JAR_WFR_CNT$, 'X'))
SRP_JSON(objReactor, 'SetValue', 'SusceptorCnt', Xlate('REACTOR', ReactorNo, REACTOR_SUSC_WFR_CNT$, 'X'))
SRP_JSON(objReactor, 'SetValue', 'SusceptorThk', Xlate('REACTOR', ReactorNo, REACTOR_SUSC_THK$, 'X'))
SRP_JSON(objReactor, 'SetValue', 'LowerQuartzCnt', Xlate('REACTOR', ReactorNo, REACTOR_LOWER_QUARTZ_WFR$, 'X'))
SRP_JSON(objReactor, 'SetValue', 'LowerQuartzThk', Xlate('REACTOR', ReactorNo, REACTOR_LOWER_QUARTZ_THK$, 'X'))
SRP_JSON(objReactor, 'SetValue', 'ArmsCnt', Xlate('REACTOR', ReactorNo, REACTOR_ARMS_WFR_CNT$, 'X'))
// Add Current Run Status (Current Loaded Cassettes)
LoadedRDS = Xlate('REACT_STATUS', ReactorNo, 'LOAD_RDS', 'X')
If LoadedRDS NE '' then
objLoadedRDS = ''
If SRP_JSON(objLoadedRDS, 'New', 'Array') then
For each RDS in LoadedRDS using @VM setting vPos
SRP_JSON(objLoadedRDS, 'AddValue', RDS)
Next RDS
SRP_JSON(objReactor, 'Set', 'loadedRDS', objLoadedRDS)
SRP_JSON(objLoadedRDS, 'Release')
end
end else
SRP_JSON(objReactor, 'SetValue', 'loadedRDS', '')
end
// Add new reactor items here
InstItems = Xlate('REACTOR', ReactorNo, REACTOR_CURR_INST_ITEMS$, 'X')
If InstItems NE '' then
objInstItems = ''
If SRP_JSON(objInstItems, 'New', 'Array') then
For each Item in InstItems using @VM setting vPos
swap '*' with @VM in Item
SRP_JSON(objInstItems, 'AddValue', Item<1, 2>)
Next Item
SRP_JSON(objReactor, 'Set', 'installedReactItems', objInstItems)
SRP_JSON(objInstItems, 'Release')
end
end else
SRP_JSON(objReactor, 'SetValue', 'installedReactItems', '')
end
// Add Current Run Status (Is running)
ReactorRunning = (LoadedRDS NE '')
SRP_JSON(objReactor, 'SetValue', 'isRunning', ReactorRunning, 'Boolean')
// Add Out of prod time
OutofProdDTM = Xlate('REACT_STATUS', ReactorNo, 'OUT_OF_PROD_DTM', 'X')
SRP_JSON(objReactor, 'SetValue', 'outOfProdDTM', OConv(OutofProdDTM, 'DT2/^H'))
If FullObject then
// Add Last Unload Time
LastUnloadDTM = Xlate('REACT_STATUS', ReactorNo, 'UNLOAD_RDS_DTM', 'X')
SRP_JSON(objReactor, 'SetValue', 'unloadDTM', OConv(LastUnloadDTM, 'DT2/^H'))
// Add Last Load Time
LastLoadDTM = Xlate('REACT_STATUS', ReactorNo, 'LOAD_RDS_DTM', 'X')
LastLoadDTM = LastLoadDTM[-1, 'B':@VM]
SRP_JSON(objReactor, 'SetValue', 'loadDTM', OConv(LastLoadDTM, 'DT2/^H'))
// Add Last Reactor Readings
LastReadWfrsDTM = Xlate('REACTOR', ReactorNo, 'LAST_READ_WFRS_DTM', 'X')
LastReadWfrs = Xlate('REACT_READS', ReactorNo:'*':LastReadWfrsDTM, 'WAFER_CNT', 'X')
SRP_JSON(objReactor, 'SetValue', 'lastReadWafersDTM', OConv(LastReadWfrsDTM, 'DT2/^H'))
SRP_JSON(objReactor, 'SetValue', 'lastReadWafers', LastReadWfrs)
end
// Add work order object
SchedConfigRec = Database_Services('ReadDataRow', 'CONFIG', 'WO_DAILY_SCHED':ReactorNo)
WorkOrderCust = SchedConfigRec<WOCust$>
CurrWorkOrder = Field(WorkOrderCust, ' ', 1)
SRP_JSON(objReactor, 'SetValue', 'workOrder', CurrWorkOrder)
WOHotStatus = Xlate('WO_LOG', CurrWorkOrder, 'HOT_FLAG', 'X')
SRP_JSON(objReactor, 'SetValue', 'workOrderHotStatus', WOHotStatus)
WOCustomer = Field(WorkOrderCust, ' ', 2)
SRP_JSON(objReactor, 'SetValue', 'workOrderCustomer', WOCustomer)
If FullObject then
JSONWorkOrder = Work_Order_Services('ConvertRecordToJSON', CurrWorkOrder)
objWorkOrder = ''
If SRP_JSON(objWorkOrder, 'Parse', JSONWorkOrder) EQ '' then
objTemp = SRP_JSON(objWorkOrder, 'Get', 'workOrder')
SRP_JSON(objReactor, 'Set', 'workOrder', objTemp)
SRP_JSON(objTemp, 'Release')
SRP_JSON(objWorkOrder, 'Release')
end
end
// Reactor Mode object/properties
If FullObject then
// Add reactor mode object
JSONReactorMode = React_Mode_NG_Services('ConvertRecordToJSON', CurrModeKey, '', CurrUser)
objReactorMode = ''
If SRP_JSON(objReactorMode, 'Parse', JSONReactorMode) EQ '' then
objTemp = SRP_JSON(objReactorMode, 'Get', 'reactorMode')
SRP_JSON(objReactor, 'Set', 'reactorMode', objTemp)
SRP_JSON(objTemp, 'Release')
SRP_JSON(objReactorMode, 'Release')
end
end else
CurrMode = Xlate('REACT_MODE_NG', CurrModeKey, 'MODE', 'X')
SubCat = Xlate('REACT_MODE_NG', CurrModeKey, 'SERVICE_DESC', 'X')
E10State = Xlate('REACTOR_MODES', CurrMode, 'E10_STATE', 'X')
SRP_JSON(objReactor, 'SetValue', 'currMode', CurrMode)
SRP_JSON(objReactor, 'SetValue', 'serviceDesc', SubCat)
SRP_JSON(objReactor, 'SetValue', 'e10State', E10State)
end
If Not(FullObject) then
// Add reactor log properties
CurrRlKey = Xlate('REACTOR', ReactorNo, 'CURR_MODE_RL_ID', 'X')
If CurrRLKey NE '' then
RlChecklistActive = Xlate('REACTOR_LOG', CurrRlKey, 'CHECKLIST_ACTIVE', 'X')
SRP_JSON(objReactor, 'SetValue', 'reactorLogChecklistActive', RlChecklistActive, 'Boolean')
If RlChecklistActive then
RlChecklistTypes = Xlate('REACTOR_LOG', CurrRlKey, 'CHECKLIST_TYPE', 'X')
RlChecklistOrderIds = Xlate('REACTOR_LOG', CurrRlKey, 'CHECKLIST_ORDER_ID', 'X')
objRlChecklistArray = ''
If SRP_JSON(objRlChecklistArray, 'New', 'Array') then
objChecklist = ''
For each RlChecklistType in RlChecklistTypes using @VM setting vPos
If SRP_JSON(objChecklist, 'New', 'Object') then
SRP_JSON(objChecklist, 'SetValue', 'reactorLogChecklistType', RlChecklistType)
RlChecklistOrderId = RlChecklistOrderIds<0, vPos>
SRP_JSON(objChecklist, 'SetValue', 'reactorLogChecklistOrderId', RlChecklistOrderId)
SRP_JSON(objRlChecklistArray, 'Add', objChecklist)
SRP_JSON(objChecklist, 'Release')
end
Next RlChecklistType
SRP_JSON(objReactor, 'Set', 'reactorLogChecklists', objRlChecklistArray)
SRP_JSON(objRlChecklistArray, 'Release')
end
end
end
// Add prove in checklist properties
PiChecklistActive = Xlate('REACTOR', ReactorNo, 'PROVE_IN_ACTIVE', 'X')
SRP_JSON(objReactor, 'SetValue', 'proveInChecklistActive', PiChecklistActive, 'Boolean')
If PiChecklistActive then
PiTypes = Xlate('REACTOR', ReactorNo, 'PROVE_IN_TYPE', 'X')
PiChecklistOrderIds = Xlate('REACTOR', ReactorNo, 'PROVE_IN_ORDER_ID', 'X')
objPiChecklistArray = ''
If SRP_JSON(objPiChecklistArray, 'New', 'Array') then
objProveIn = ''
For each PiType in PiTypes using @VM setting vPos
If SRP_JSON(objProveIn, 'New', 'Object') then
SRP_JSON(objProveIn, 'SetValue', 'proveInType', PiType)
PiChecklistOrderId = PiCheckListOrderIds<0, vPos>
SRP_JSON(objProveIn, 'SetValue', 'proveInOrderId', PiChecklistOrderId)
SRP_JSON(objPiChecklistArray, 'Add', objProveIn)
SRP_JSON(objProveIn, 'Release')
end
Next PiType
SRP_JSON(objReactor, 'Set', 'proveInChecklists', objPiChecklistArray)
SRP_JSON(objPiChecklistArray)
end
end
end
If itemURL NE '' then
// The itemURL was passed in so add HAL+JSON properties.
objLinks = ''
// Create the _links property and then all link objects needed for this resource.
If SRP_JSON(objLinks, 'New', 'Object') then
// Create a self link.
objLink = ''
If SRP_JSON(objLink, 'New', 'Object') then
SRP_JSON(objLink, 'SetValue', 'href', ItemURL, 'String')
SRP_JSON(objLink, 'SetValue', 'title', 'Self', 'String')
SRP_JSON(objLinks, 'Set', 'self', objLink)
SRP_JSON(objLink, 'Release')
end
SRP_JSON(objReactor, 'Set', '_links', objLinks)
SRP_JSON(objLinks, 'Release')
end
// Create the _class property for this resource.
SRP_JSON(objReactor, 'SetValue', '_class', 'resource')
end
SRP_JSON(objJSON, 'Set', 'reactor', objReactor)
SRP_JSON(objReactor, 'Release')
end
JSON = SRP_JSON(objJSON, 'Stringify', 'Styled')
SRP_JSON(objJSON, 'Release')
end else
ErrorMsg = 'Error in ':Service:' service. Error creating JSON object.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null ReactNo passed in.'
end
If ErrorMsg EQ '' then
Response = JSON
end else
Error_Services('Add', ErrorMsg)
end
end service
Service ConvertJSONToRecord(KeyID, JSON)
Record = ''
If JSON NE '' then
If SRP_JSON(objJSON, 'Parse', JSON) EQ '' then
objReactor = SRP_JSON(objJSON, 'Get', 'reactor')
Record = Database_Services('ReadDataRow', 'REACTOR', KeyID)
If Error_Services('NoError') then
// Add code to update additional columns as needed.
// If property is "" then clear the field.
// If property is null then do not update it.
NewVal = SRP_JSON(objReactor, 'GetValue', '0311Active')
If NewVal NE 'null' then
Record<REACTOR_0311_ACTIVE$> = NewVal
end
end
SRP_JSON(objReactor, 'Release')
SRP_JSON(objJSON, 'Release')
end else
Error_Services('Add', 'Error in ':Service:' service. Unable to parse JSON payload.')
end
end else
Error_Services('Add', 'Error in ':Service:' service. Null JSON passed in.')
end
Response = Record
end service
Service CleanReactStatus()
hSysLists = Database_Services('GetTableHandle', 'SYSLISTS')
Lock hSysLists, ServiceKeyID then
ReactNos = Reactor_Services('GetReactorNumbers')
For each ReactNo in ReactNos using @FM
HaveLock = Database_Services('GetKeyIDLock', 'REACT_STATUS', ReactNo)
If HaveLock then
OrigReactStatRec = Database_Services('ReadDataRow', 'REACT_STATUS', ReactNo)
ReactStatRec = OrigReactStatRec
If Error_Services('NoError') then
For Col = 1 to 9
OrigList = OrigReactStatRec<Col>
If OrigList NE '' then
CleanList = ''
For each Val in OrigList using @VM
If Val NE 1 then CleanList<0, -1> = Val
Next Val
ReactStatRec<Col> = CleanList
end
Next Col
If OrigReactStatRec NE ReactStatRec then
Database_Services('WriteDataRow', 'REACT_STATUS', ReactNo, ReactStatRec, True$, False$, False$)
end else
Database_Services('ReleaseKeyIDLock', 'REACT_STATUS', ReactNo)
end
end
end
Next ReactNo
Unlock hSysLists, ServiceKeyID else Null
end
end service
Service GetReactModeKeysByTimeSpan(ReactorNo, StartDtm, StopDtm)
Begin Case
Case ReactorNo Eq ''
Error_Services('Add', 'Error in ' : Service : ' service. ReactorNo not supplied.')
Case StartDtm Eq ''
Error_Services('Add', 'Error in ' : Service : ' service. StartDtm not supplied.')
Case StopDtm Eq ''
Error_Services('Add', 'Error in ' : Service : ' service. StopDtm not supplied.')
End Case
If Error_Services('NoError') then
//Get all modes within the StartDtm and StopDtm
StartDt = FIELD(StartDtm, '.', 1)
StopDt = Field(StopDtm, '.', 1)
keys = ''
OPEN 'DICT.REACT_MODE_NG' TO @DICT then
SearchString = ''
SearchString := "START_DTM" :@VM: StartDtm : '~' : StopDtm: @FM
SearchString := "STOP_DTM" :@VM: ';' : StartDtm : '~' : StopDtm : @FM
SearchString := "REACT_NO" :@VM: ReactorNo : @FM
keylist = ""
option = ""
flag = ""
Btree.Extract(SearchString, 'REACT_MODE_NG', @DICT, keylist, option, flag)
for each key in keylist
keys<-1> = key
Next key
end
if keys<1> EQ '' then
//Get Current Mode because it started before report date and has yet to finish
//Is the report time for the current mode?
CurrReactorModeKey = Reactor_Services('GetReactCurrModeId', ReactorNo)
CurrReactorModeStartDtm = Field(CurrReactorModeKey, '*', 2)
IF StopDtm GT CurrReactorModeStartDtm then
keys<-1> = CurrReactorModeKey
end else
//
SearchString = ''
SearchString := "START_DTM" :@VM: '<=' : StartDtm: @FM
SearchString := "STOP_DTM" :@VM: '>=' : StopDtm : @FM
SearchString := "REACT_NO" :@VM: ReactorNo : @FM
SubKeyList = ""
option = ""
flag = ""
Btree.Extract(SearchString, 'REACT_MODE_NG', @DICT, SubKeyList, option, flag)
for each SubKey in SubKeyList
keys<-1> = SubKey
Next SubKey
end
//Is the report time outside of the current mode
end
Response = keys
end else
Response = Error_Services('GetMessage')
end
end service
Service GetReactorUptimeMetricsByTimeSpan(ReactorNo, StartDtm, StopDtm)
ToolData = ''
TotalProductiveMinutes = 0
TotalUnscheduledDownMinutes = 0
TotalScheduledDownMinutes = 0
TotalNonSchedMinutes = 0
TotalEngMinutes = 0
Begin Case
Case ReactorNo Eq ''
Error_Services('Add', 'Error in ' : Service : ' service. ReactorNo not supplied.')
Case StartDtm Eq ''
Error_Services('Add', 'Error in ' : Service : ' service. StartDtm not supplied.')
Case StopDtm Eq ''
Error_Services('Add', 'Error in ' : Service : ' service. StopDtm not supplied.')
End Case
//If StopDtm is in future then set it to current time.
If StopDtm GT Datetime() then
StopDtm = Datetime()
end
If Error_Services('NoError') then
//Get Keys for the supplied time span
ReactModeNGKeys = Reactor_Services('GetReactModeKeysByTimeSpan', ReactorNo, StartDtm, StopDtm)
If Error_Services('NoError') then
//Get total minutes of timespan.
TotalReportMinutes = SRP_Datetime('MinuteSpan', StartDtm, StopDtm)
//Loop Through each mode key returned
for each key in ReactModeNGKeys using @VM
ReactModeNGRec = Database_Services('ReadDataRow', 'REACT_MODE_NG', key)
ModeStartDtm = Field(key, '*', 2)
ModeStopDtm = ReactModeNGRec<REACT_MODE_NG_STOP_DTM$>
ReactModeName = ReactModeNGRec<REACT_MODE_NG_MODE$>
E10State = Xlate('REACTOR_MODES', ReactModeName, REACTOR_MODES_E10_STATE$, 'X')
MinutesInMode = 0
Begin Case
CASE E10State EQ 'Productive'
//Begin Production
if ModeStartDtm LT StartDtm then
//Mode Started Earlier than report time
If ModeStopDtm LT StopDtm then
//Mode finished within the timespan
If ModeStopDtm NE '' then
MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, ModeStopDtm)
end else
//Mode is not closed
If ModeStartDtm LT StartDtm then
//if ModeStartDtm is before StartDtm and is not close used the total report timespan
MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, StopDtm)
end else
//Use the ModeStartDtm and the StopDtm
MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm)
end
end
end else
//Mode finished after the timespan
MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, StopDtm)
end
end else
//Mode started after report time
If ModeStopDtm LT StopDtm then
//Mode finished within the timespan OR isn't yet closed
If ModeStopDtm NE '' then
//Mode is closed. Started and finished within the report time so use the Mode's start and stop
MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, ModeStopDtm)
end else
//Mode is not closed. Started within the report time but has yet to stop.
MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm)
end
end else
//Mode finished after the timespan
MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm)
end
end
TotalProductiveMinutes += MinutesInMode
Case E10State EQ 'Unscheduled Down'
//Begin Production
if ModeStartDtm LT StartDtm then
//Mode Started Earlier than report time
If ModeStopDtm LT StopDtm then
//Mode finished within the timespan
If ModeStopDtm NE '' then
MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, ModeStopDtm)
end else
//Mode is not closed
If ModeStartDtm LT StartDtm then
//if ModeStartDtm is before StartDtm and is not close used the total report timespan
MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, StopDtm)
end else
//Use the ModeStartDtm and the StopDtm
MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm)
end
end
end else
//Mode finished after the timespan
MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, StopDtm)
end
end else
//Mode started after report time
If ModeStopDtm LT StopDtm then
//Mode finished within the timespan OR isn't yet closed
If ModeStopDtm NE '' then
//Mode is closed. Started and finished within the report time so use the Mode's start and stop
MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, ModeStopDtm)
end else
//Mode is not closed. Started within the report time but has yet to stop.
MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm)
end
end else
//Mode finished after the timespan
MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm)
end
end
TotalUnscheduledDownMinutes += MinutesInMode
Case E10State EQ 'Scheduled Down'
//Begin Production
if ModeStartDtm LT StartDtm then
//Mode Started Earlier than report time
If ModeStopDtm LT StopDtm then
//Mode finished within the timespan
If ModeStopDtm NE '' then
MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, ModeStopDtm)
end else
//Mode is not closed
If ModeStartDtm LT StartDtm then
//if ModeStartDtm is before StartDtm and is not close used the total report timespan
MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, StopDtm)
end else
//Use the ModeStartDtm and the StopDtm
MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm)
end
end
end else
//Mode finished after the timespan
MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, StopDtm)
end
end else
//Mode started after report time
If ModeStopDtm LT StopDtm then
//Mode finished within the timespan OR isn't yet closed
If ModeStopDtm NE '' then
//Mode is closed. Started and finished within the report time so use the Mode's start and stop
MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, ModeStopDtm)
end else
//Mode is not closed. Started within the report time but has yet to stop.
MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm)
end
end else
//Mode finished after the timespan
MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm)
end
end
TotalScheduledDownMinutes += MinutesInMode
Case E10State EQ 'Non-Scheduled' OR E10State EQ 'Standby'
if ModeStartDtm LT StartDtm then
//Mode Started Earlier than report time
If ModeStopDtm LT StopDtm then
//Mode finished within the timespan
If ModeStopDtm NE '' then
MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, ModeStopDtm)
end else
//Mode is not closed
If ModeStartDtm LT StartDtm then
//if ModeStartDtm is before StartDtm and is not close used the total report timespan
MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, StopDtm)
end else
//Use the ModeStartDtm and the StopDtm
MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm)
end
end
end else
//Mode finished after the timespan
MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, StopDtm)
end
end else
//Mode started after report time
If ModeStopDtm LT StopDtm then
//Mode finished within the timespan OR isn't yet closed
If ModeStopDtm NE '' then
//Mode is closed. Started and finished within the report time so use the Mode's start and stop
MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, ModeStopDtm)
end else
//Mode is not closed. Started within the report time but has yet to stop.
MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm)
end
end else
//Mode finished after the timespan
MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm)
end
end
TotalNonSchedMinutes += MinutesInMode
Case E10State EQ 'Engineering'
if ModeStartDtm LT StartDtm then
//Mode Started Earlier than report time
If ModeStopDtm LT StopDtm then
//Mode finished within the timespan
If ModeStopDtm NE '' then
MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, ModeStopDtm)
end else
//Mode is not closed
If ModeStartDtm LT StartDtm then
//if ModeStartDtm is before StartDtm and is not close used the total report timespan
MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, StopDtm)
end else
//Use the ModeStartDtm and the StopDtm
MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm)
end
end
end else
//Mode finished after the timespan
MinutesInMode = SRP_Datetime('MinuteSpan', StartDTM, StopDtm)
end
end else
//Mode started after report time
If ModeStopDtm LT StopDtm then
//Mode finished within the timespan OR isn't yet closed
If ModeStopDtm NE '' then
//Mode is closed. Started and finished within the report time so use the Mode's start and stop
MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, ModeStopDtm)
end else
//Mode is not closed. Started within the report time but has yet to stop.
MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm)
end
end else
//Mode finished after the timespan
MinutesInMode = SRP_Datetime('MinuteSpan', ModeStartDtm, StopDtm)
end
end
TotalEngMinutes += MinutesInMode
End Case
Next key
ProdPercentage = (TotalProductiveMinutes / TotalReportMinutes) * 100
UnschedDownPercentage = (TotalUnscheduledDownMinutes / TotalReportMinutes) * 100
SchedDownPercentage = (TotalScheduledDownMinutes / TotalReportMinutes) * 100
NonSchedPercentage = (TotalNonSchedMinutes / TotalReportMinutes) * 100
EngPercentage = (TotalEngMinutes / TotalReportMinutes) * 100
//Percentages
ToolData<1, PRODUCTIVE$> = ProdPercentage
ToolData<1, UNSCHED$> = UnschedDownPercentage
ToolData<1, SCHED$> = SchedDownPercentage
ToolData<1, NONSCHED$> = NonSchedPercentage
ToolData<1, ENG$> = EngPercentage
//Total Minutes
ToolData<2, PRODUCTIVE$> = TotalProductiveMinutes
ToolData<2, UNSCHED$> = TotalUnscheduledDownMinutes
ToolData<2, SCHED$> = TotalScheduledDownMinutes
ToolData<2, NONSCHED$> = TotalNonSchedMinutes
ToolData<2, ENG$> = TotalEngMinutes
Response = ToolData
end else
Response = Error_Services('GetMessage')
end
end else
Response = Error_Services('GetMessage')
end
end service
Service GetReactorUptimeMetricsByTypeAndTimeSpan(startDtm, endDtm, reactType)
Begin Case
Case startDtm EQ ''
Error_Services('Add', 'Error getting reactor uptime metrics -> Report start date not supplied')
Case endDtm EQ ''
Error_Services('Add', 'Error getting reactor uptime metrics -> Report end date not supplied')
End Case
If reactType EQ '' then reactType = 'ALL'
If Error_Services('NoError') then
If endDtm GT Date() then
//This sets the current report end time to the current time.
endDtm = Datetime()
end
reportMinutes = SRP_Datetime('MinuteSpan', startDtm, endDtm)
if num(reportMinutes) then
Begin Case
Case reactType EQ 'ASM' or reactType EQ 'ASM+'
Reactors = Reactor_Services('GetReactorNumbers', 'ASM') : @FM : Reactor_Services('GetReactorNumbers', 'ASM+')
Case reactType EQ 'HTR'
Reactors = Reactor_Services('GetReactorNumbers', 'HTR')
Case reactType EQ 'EPP'
Reactors = Reactor_Services('GetReactorNumbers', 'EPP')
Case reactType EQ 'ALL'
Reactors = Reactor_Services('GetReactorNumbers', 'ASM') : @FM : Reactor_Services('GetReactorNumbers', 'ASM+') : @FM : Reactor_Services('GetReactorNumbers', 'HTR') : @FM : Reactor_Services('GetReactorNumbers', 'EPP')
End Case
AllReactorsScheduledMinutes = 0
AllReactorsUptimeMinutes = 0
AllReactorsProdMinutes = 0
AllReactorsUnschedDownMinutes = 0
AllReactorsSchedDownMinutes = 0
AllReactorsEngMinutes = 0
AllReactorsIdleMinutes = 0
AllReactorsSingleLL= 0
TotalMinutesUp = 0
ReactorsData = ''
ReactorsExcluded = ''
for each Reactor in Reactors using @FM
ReactorStateTimes = Reactor_Services('GetReactorUptimeMetricsByTimeSpan', Reactor, startDtm, endDtm)
PercentProd = ReactorStateTimes<1,PRODUCTIVE$>
MinuteProd = ReactorStateTimes<2,PRODUCTIVE$>
PercentUnSchedDown = ReactorStateTimes<1,UNSCHED$>
MinuteUnschedDown = ReactorStateTimes<2,UNSCHED$>
PercentSchedDown = ReactorStateTimes<1,SCHED$>
MinuteSchedDown = ReactorStateTimes<2,SCHED$>
PercentNonSched = ReactorStateTimes<1,NONSCHED$>
MinutesNonSched = ReactorStateTimes<2,NONSCHED$>
PercentEng = ReactorStateTimes<1, ENG$>
MinutesEng = ReactorStateTimes<2, ENG$>
if MinutesNonSched LT reportMinutes then
thisReactorExpectedAvailMinutes = reportMinutes - MinutesNonSched; * This is the amount of minutes the single reactor was scheduled to run work.
AllReactorsScheduledMinutes += thisReactorExpectedAvailMinutes; * Add it to the collective of reactors
thisReactorUptimeMinutes = MinuteProd + MinutesEng
AllReactorsUptimeMinutes = thisReactorUptimeMinutes + AllReactorsUptimeMinutes
AllReactorsProdMinutes += MinuteProd
AllReactorsUnschedDownMinutes += MinuteUnschedDown
AllReactorsSchedDownMinutes += MinuteSchedDown
AllReactorsEngMinutes += MinutesEng
AllReactorsIdleMinutes += MinutesNonSched
if reactType NE 'EPP' then
thisReactorDisabledLoadLock = Reactor_Services('GetReactorDownLL', Reactor) NE ''
AllReactorsSingleLL += thisReactorDisabledLoadLock
end else
thisReactorDisabledLoadLock = 0
end
ReactorsData<REACTOR_DAILY_UPTIME_INCL_REACTORS$,-1> = Reactor
ReactorsData<REACTOR_DAILY_UPTIME_INCL_REACTOR_PROD_PERCENTAGE$,-1> = PercentProd
ReactorsData<REACTOR_DAILY_UPTIME_INCL_REACTOR_PROD_MINUTES$,-1> = MinuteProd
ReactorsData<REACTOR_DAILY_UPTIME_INCL_REACTOR_ENG_PERCENTAGE$, -1> = PercentEng
ReactorsData<REACTOR_DAILY_UPTIME_INCL_REACTOR_ENG_MINUTES$, -1> = MinutesEng
ReactorsData<REACTOR_DAILY_UPTIME_INCL_REACTOR_DOWN_UNSCHED_PERCENTAGE$, -1> = PercentUnSchedDown
ReactorsData<REACTOR_DAILY_UPTIME_INCL_REACTOR_DOWN_UNSCHED_MINUTES$, -1> = MinuteUnschedDown
ReactorsData<REACTOR_DAILY_UPTIME_INCL_REACTOR_DOWN_SCHED_PERCENTAGE$, -1> = PercentSchedDown
ReactorsData<REACTOR_DAILY_UPTIME_INCL_REACTOR_DOWN_SCHED_MINUTES$, -1> = MinuteSchedDown
ReactorsData<REACTOR_DAILY_UPTIME_INCL_REACTOR_IDLE_PERCENTAGE$, -1> = PercentNonSched
ReactorsData<REACTOR_DAILY_UPTIME_INCL_REACTOR_IDLE_MINUTES$, -1> = MinutesNonSched
ReactorsData<REACTOR_DAILY_UPTIME_INCL_REACTOR_SINGLE_LL$, -1> = thisReactorDisabledLoadLock
end else
ReactorsData<REACTOR_DAILY_UPTIME_EXCLUDED_REACTORS$, -1> = Reactor
end
Next Reactor
if AllReactorsScheduledMinutes GT 0 then
TotalUptimePercent = SRP_Math('ROUND', AllReactorsUptimeMinutes / AllReactorsScheduledMinutes, 5)
TotalUptimeMinutes = SRP_Math('ROUND', AllReactorsUptimeMinutes, 5)
TotalAvailMinutes = SRP_Math('ROUND', AllReactorsScheduledMinutes, 5)
TotalProdPercent = SRP_Math('ROUND', AllReactorsProdMinutes / AllReactorsScheduledMinutes, 5)
TotalUnschedDownPercent = SRP_Math('ROUND', AllReactorsUnschedDownMinutes / AllReactorsScheduledMinutes, 5)
TotalSchedDownPercent = SRP_Math('ROUND', AllReactorsSchedDownMinutes / AllReactorsScheduledMinutes, 5)
TotalEngPercent = SRP_Math('ROUND', AllReactorsEngMinutes / AllReactorsScheduledMinutes, 5)
TotalIdlePercent = SRP_Math('ROUND', AllReactorsIdleMinutes / AllReactorsScheduledMinutes, 5)
end else
TotalUptimePercent = 0
TotalUptimeMinutes = 0
TotalAvailMinutes = 0
TotalProdPercent = 0
TotalUnschedDownPercent = 0
TotalSchedDownPercent = 0
TotalEngPercent = 0
TotalIdlePercent = 0
end
ReactorsData<REACTOR_DAILY_UPTIME_TOTAL_UPTIME_PERCENTAGE$> = TotalUptimePercent
ReactorsData<REACTOR_DAILY_UPTIME_TOTAL_PROD_PERCENTAGE$> = TotalProdPercent
ReactorsData<REACTOR_DAILY_UPTIME_TOTAL_PROD_MINUTES$> = AllReactorsProdMinutes
ReactorsData<REACTOR_DAILY_UPTIME_TOTAL_ENG_PERCENTAGE$> = TotalEngPercent
ReactorsData<REACTOR_DAILY_UPTIME_TOTAL_ENG_MINUTES$> = AllReactorsEngMinutes
ReactorsData<REACTOR_DAILY_UPTIME_TOTAL_DOWN_UNSCHED_PERCENTAGE$> = TotalUnschedDownPercent
ReactorsData<REACTOR_DAILY_UPTIME_TOTAL_DOWN_UNSCHED_MINUTES$> = AllReactorsUnschedDownMinutes
ReactorsData<REACTOR_DAILY_UPTIME_TOTAL_DOWN_SCHED_PERCENTAGE$> = TotalSchedDownPercent
ReactorsData<REACTOR_DAILY_UPTIME_TOTAL_DOWN_SCHED_MINUTES$> = AllReactorsSchedDownMinutes
ReactorsData<REACTOR_DAILY_UPTIME_TOTAL_IDLE_PERCENTAGE$> = TotalIdlePercent
ReactorsData<REACTOR_DAILY_UPTIME_TOTAL_IDLE_MINUTES$> = AllReactorsIdleMinutes
ReactorsData<REACTOR_DAILY_UPTIME_TOTAL_UPTIME_MINUTES$> = TotalUptimeMinutes
ReactorsData<REACTOR_DAILY_UPTIME_TOTAL_AVAIL_MINUTES$> = TotalAvailMinutes
ReactorsData<REACTOR_DAILY_UPTIME_TOTAL_SINGLE_LL$> = AllReactorsSingleLL
Response = ReactorsData
end else
Error_Services('Add', 'Error getting reactor uptime metrics -> Unable to get total report duration.')
end
end
end service
Service GetLoadedRds(ReactNo)
StopRDS = Xlate('REACT_STATE', ReactNo, 'LAST_RDS_NO', 'X')
// Get list of RDS on current reactor that are not FQA
ReactorConfigKey = 'WO_DAILY_SCHED':ReactNo
WoNo = Field(Xlate('CONFIG', ReactorConfigKey, WOCust$, 'X'), ' ', 1)
RDSColumns = ''
RDSColumns<0, 1> = 'SEQ'
RDSList = RDS_Services('GetRDSData', WoNo, RDSColumns, False$, '')
// Find the index of StopRDS
RDSList = SRP_Sort_Array(RDSList, "AN1")
RDSFastArray = SRP_Fastarray("Create", RDSList)
StopRDSIdx = 0
SRP_Fastarray("Match", RDSFastArray, StopRDS, StopRDSIdx)
RDSList = SRP_Fastarray("GetVariable", RDSFastArray)
RdsKeys = '':@FM:''
RdsKeysPosition = 1
RdsIdx = StopRDSIdx + 1
DateIn = ''
DateOut = ''
Loop
DateIn = Xlate('RDS', RDSList<RdsIdx>, RDS_DATE_IN$, 'X')
DateOut = Xlate('RDS', RDSList<RdsIdx>, RDS_DATE_OUT$, 'X')
While (DateIn NE '') and (DateOut EQ '')
RdsKeys<RdsKeysPosition> = RDSList<RdsIdx>
If (RdsKeysPosition EQ 1) then
RdsKeysPosition = 2
end else
RdsKeysPosition = 1
end
RdsIdx += 1
Repeat
Response = RdsKeys
end service
Service ActiveProveInPreventsModeChange(ReactNo, NewMode, CurrentMode)
If (ReactNo NE '') then
If (NewMode NE '') then
ReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactNo)
ActiveProveIn = Reactor_Services('GetProveInActive', ReactNo)
If ActiveProveIn EQ True$ then
Nica_Orders_Services('GetOrderUpdates')
ActiveProveIn = Reactor_Services('GetProveInActive', ReactNo)
If ActiveProveIn EQ True$ then
Begin Case
Case CurrentMode EQ 'INITIATE_IDLE'
IdleStartupActive = Reactor_Services('GetIdleStartupRequired', ReactNo)
If IdleStartupActive EQ True$ then
Response = True$
end else
Response = False$
end
Case Len(NewMode) GE 2 and NewMode[1, 2] EQ 'UP'
Response = True$
Case Otherwise$
Response = False$
End Case
end else
Response = False$
end
end else
Response = False$
end
end else
Error_Services('Add', 'Error in ' : Service : ' service. NewMode was empty')
end
end else
Error_Services('Add', 'Error in ' : Service : ' service. ReactNo was empty')
end
end service
Service GetReactorDownLL(ReactNo)
Response = ''
If RowExists('REACTOR', ReactNo) then
LLDisabledID = Database_Services('ReadDataColumn', 'REACTOR', ReactNo, REACTOR_ACTIVE_LL_DISABLED$, True$, 0)
If LLDisabledID NE '' then
If RowExists('REACT_LL', LLDisabledID) then
DownLoadLock = Database_Services('ReadDataColumn', 'REACT_LL', LLDisabledID, REACT_LL_DISABLED$, True$, 0)
Response = DownLoadLock
end
end
end
end service
Service GetReactorLoadCountLimit(ReactNo)
ErrMsg = 'Error in ReactorServices -> GetReactorLoadCountLimit: '
MaxLoadCount = 999
If ReactNo NE '' then
If RowExists('REACTOR', ReactNo) then
ReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactNo)
If Error_Services('NoError') then
ReactType = ReactorRec<REACTOR_REACT_TYPE$>
PickPlace = ReactorRec<REACTOR_PICK_PLACE$>
DisabledLoadLockCnt = DCount(ReactorRec<REACTOR_ACTIVE_LL_DISABLED$>, @VM)
Begin Case
Case ReactType EQ 'ASM'
If PickPlace then
MaxLoadCount = 2 - DisabledLoadLockCnt
end else
MaxLoadCount = 1
end
Case ReactType EQ 'ASM+'
If PickPlace then
MaxLoadCount = 2 - DisabledLoadLockCnt
end else
MaxLoadCount = 1
end
Case ReactType EQ 'HTR'
If PickPlace then
MaxLoadCount = 2 - DisabledLoadLockCnt
end else
MaxLoadCount = 1
end
Case ReactType EQ 'EPP'
MaxLoadCount = 2;*EPP needs to have an additional load capability.
End Case
end else
ErrMsg := Error_Services('GetMessage')
Error_Services('Add', ErrMsg)
end
end else
ErrMsg := 'Reactor ' : ReactNo : ' does not exist.'
Error_Services('Add', ErrMsg)
end
end else
ErrMsg := 'Reactor Number was null.'
Error_Services('Add', ErrMsg)
end
Response = MaxLoadCount
end service
Service GetReactorAvailChamberCount(ReactNo)
ErrMsg = 'Error in ReactorServices -> GetReactorAvailChamberCount: '
AvailableChamberCount = 0
If ReactNo NE '' then
If RowExists('REACTOR', ReactNo) then
LoadedRDS = Reactor_Services('GetReactorCurrLoadRDS', ReactNo)
ReactorCurrLoadCnt = DCount(LoadedRDS, @VM)
ReactorCurrCapacity = Reactor_Services('GetReactorLoadCountLimit', ReactNo)
AvailableChamberCount = ReactorCurrCapacity - ReactorCurrLoadCnt
end else
ErrMsg := 'Reactor ' : ReactNo : ' does not exist.'
Error_Services('Add', ErrMsg)
end
end else
ErrMsg := 'Reactor Number was null.'
Error_Services('Add', ErrMsg)
end
Response = AvailableChamberCount
end service
Service RemoveRDSFromReactorLoad(RDSNo, ReactorNo, User)
Response = 0
If User NE '' then
If RDSNo NE '' then
If ReactorNo NE '' then
ReactStatusRec = Database_Services('ReadDataRow', 'REACT_STATUS', ReactorNo)
If Error_Services('NoError') then
Locate RDSNo in ReactStatusRec<REACT_STATUS_LOAD_RDS$> setting RDSPos then
ReactStatusRec = Delete(ReactStatusREc, REACT_STATUS_LOAD_RDS$, RDSPos, 0)
ReactStatusRec = Delete(ReactStatusREc, REACT_STATUS_LOAD_RDS_DTM$, RDSPos, 0)
ReactStatusRec = Delete(ReactStatusREc, REACT_STATUS_LOAD_CASS_ID$, RDSPos, 0)
ReactStatusRec = Delete(ReactStatusREc, REACT_STATUS_LOAD_DTM$, RDSPos, 0)
Database_Services('WriteDataRow', 'REACT_STATUS', ReactorNo, ReactStatusRec, 1, 0, 1)
If Error_Services('NoError') then
Response = 1
end else
ErrMsg = Error_Services('GetMessage')
Error_Services('Add', ErrMsg)
end
end else
Error_Services('Add', 'Error in Reactor Services -> RemoveRDSFromReactorLoad: RDS was not found as a loaded lot.')
end
end else
ErrMsg = Error_Services('GetMessage')
Error_Services('Add', ErrMsg)
end
end else
Error_Services('Add', 'Error in Reactor Services -> RemoveRDSFromReactorLoad: No Reactor No was supplied.')
end
end else
Error_Services('Add', 'Error in Reactor Services -> RemoveRDSFromReactorLoad: No RDS No was supplied.')
end
end else
Error_Services('Add', 'Error in Reactor Services -> RemoveRDSFromReactorLoad: No Username was supplied.')
end
end service
Service AddRDSToReactorLoad(RDSNo, ReactorNo)
Response = 0
If RDSNo NE '' then
If ReactorNo NE '' then
ReactStatusRec = Database_Services('ReadDataRow', 'REACT_STATUS', ReactorNo)
If Error_Services('NoError') then
Locate RDSNo in ReactStatusRec<REACT_STATUS_LOAD_RDS$> using @VM setting iPos else
WONo = Xlate('RDS', RDSNo, 'WO_NO', 'X')
CassNo = Xlate('RDS', RDSNo, 'CASS_NO', 'X')
WOMatKey = WONo : '*' : CassNo
ThisDTM = SRP_Datetime('Now')
ReactStatusRec<REACT_STATUS_LOAD_RDS$, -1> = RDSNo
ReactStatusRec<REACT_STATUS_LOAD_RDS_DTM$, -1> = ThisDTM
ReactStatusRec<REACT_STATUS_LOAD_CASS_ID$, -1> = WOMatKey
ReactStatusRec<REACT_STATUS_LOAD_DTM$, -1> = ThisDTM
Database_Services('WriteDataRow', 'REACT_STATUS', ReactorNo, ReactStatusRec, 1, 0, 1)
end
end else
ErrMsg = Error_Services('GetMessage')
Error_Services('Add', ErrMsg)
end
end else
Error_Services('Add', 'Error in Reactor Services -> RemoveRDSFromReactorLoad: No Reactor No was supplied.')
end
end else
Error_Services('Add', 'Error in Reactor Services -> RemoveRDSFromReactorLoad: No RDS No was supplied.')
end
end service
Service UpdateReactorIQSViolations()
ReactNos = Reactor_Services('GetReactorNumbers')
If Error_Services('NoError') then
CurrViols = Database_Services('ReadDataRow', 'CONFIG', 'IQS_VIOL_DATA')
If Error_Services('NoError') then
ViolatingReactors = CurrViols<IQS_VIOL_DATA.REACTOR$>
ViolationDtms = CurrViols<IQS_VIOL_DATA.LAST_ALARM$>
ViolationTests = CurrViols<IQS_VIOL_DATA.TEST$>
Swap ' AM' with 'AM' in ViolationDtms
Swap ' PM' with 'PM' in ViolationDtms
ViolationDtms = IConv(ViolationDtms, 'DT')
For each ReactNo in ReactNos
ActiveAlarm = False$
For each ViolReactor in ViolatingReactors using @VM setting vPos
If ViolReactor EQ ReactNo then
ActiveAlarm = True$
ThisAlarmDtm = ViolationDtms<0, vPos>
ThisAlarmTest = ViolationTests<0, vPos>
// Check if a new alarm and update if necessary
LastAlarmDtm = Xlate('REACTOR', ReactNo, REACTOR_IQS_ALARM_DTM$, 'X')
If LastAlarmDtm LT ThisAlarmDtm then
// New alarm
HaveLock = Database_Services('GetKeyIDLock', 'REACTOR', ReactNo, True$)
If HaveLock then
ReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactNo)
If Error_Services('NoError') then
ReactorRec<REACTOR_IQS_ALARM_DTM$> = ThisAlarmDtm
ReactorRec<REACTOR_IQS_ALARM_TEST$> = ThisAlarmTest
// WriteDataRow will clear the lock as long as "IgnoreAllLocks" is false
// REACTOR_ACTIONS will be triggered, which will generate a NICA order if a new HgCV alarm is detected
Database_Services('WriteDataRow', 'REACTOR', ReactNo, ReactorRec, True$, False$, False$)
end
end
end
end
Next ViolReactor
If Not(ActiveAlarm) then
// Clear last active alarm
HaveLock = Database_Services('GetKeyIDLock', 'REACTOR', ReactNo, True$)
If HaveLock then
ReactorRec = Database_Services('ReadDataRow', 'REACTOR', ReactNo)
If Error_Services('NoError') then
ReactorRec<REACTOR_IQS_ALARM_DTM$> = ''
ReactorRec<REACTOR_IQS_ALARM_TEST$> = ''
// WriteDataRow will clear the lock as long as "IgnoreAllLocks" is false
Database_Services('WriteDataRow', 'REACTOR', ReactNo, ReactorRec, True$, False$, False$)
end
end
end
Next ReactNo
end
end
end service
Service GetProveInActive(ReactNo)
If ReactNo NE '' then
OrderTypes = 'CHANGEOVER' : @VM : 'INITIATE_IDLE' : @VM : 'IDLE'
ActiveProveInIds = Nica_Orders_Services('GetActiveOrders', 'REACTOR', ReactNo, OrderTypes)
Response = (ActiveProveInIds NE '')
end else
Error_Services('Add', 'Error in ':Service:' service. Null ReactNo passed into service.')
end
end service
Service GetActiveProveInTypes(ReactNo)
If ReactNo NE '' then
ActiveProveInOrderIds = Reactor_Services('GetActiveProveInOrderIds', ReactNo)
If ActiveProveInOrderIds NE '' then
Response = Xlate('NICA_ORDERS', ActiveProveInOrderIds, 'ORDER_TYPE', 'X')
end
end else
Error_Services('Add', 'Error in ':Service:' service. Null ReactNo passed into service.')
end
end service
Service GetActiveProveInProgresses(ReactNo)
Response = ''
If ReactNo NE '' then
ActiveProveInOrderIds = Reactor_Services('GetActiveProveInOrderIds', ReactNo)
If ActiveProveInOrderIds NE '' then
OrderTypes = Xlate('NICA_ORDERS', ActiveProveInOrderIds, 'ORDER_TYPE', 'X')
OrderCount = Dcount(OrderTypes, @VM)
For I = 1 to OrderCount
OrderType = OrderTypes<I>
ProgressPercentage = Xlate('NICA_ORDERS', ActiveProveInOrderIds<i>, 'PROGRESS_PERCENTAGE', 'X')
Response<-1> = OrderType : '- ' : ProgressPercentage :'% Complete.'
Next I
end
end else
Error_Services('Add', 'Error in ':Service:' service. Null ReactNo passed into service.')
end
end service
Service GetActiveProveInOrderIds(ReactNo)
If ReactNo NE '' then
OrderTypes = 'CHANGEOVER' : @VM : 'INITIATE_IDLE' : @VM : 'IDLE'
Response = Nica_Orders_Services('GetActiveOrders', 'REACTOR', ReactNo, OrderTypes)
end else
Error_Services('Add', 'Error in ':Service:' service. Null ReactNo passed into service.')
end
end service
Service GetIdleStartupRequired(ReactNo)
If ReactNo NE '' then
Response = Xlate('REACTOR', ReactNo, REACTOR_IDLE_STARTUP_REQUIRED$, 'X')
end else
Error_Services('Add', 'Error in ':Service:' service. Null ReactNo passed into service.')
end
end service
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Internal GoSubs
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
RollbackReactUtil:
// Reopen previous REACT_UTIL record
If OldReactUtilID NE '' then
OldReactUtilRec = Database_Services('ReadDataRow', 'REACT_UTIL', OldReactUtilID)
OldReactUtilRec<react_util_end_date$> = ''
OldReactUtilRec<react_util_end_time$> = ''
OldReactUtilRec<react_util_mode_finish_user$> = ''
Database_Services('WriteDataRow', 'REACT_UTIL', OldReactUtilID, OldReactUtilRec)
end
return
ClearCursors:
For counter = 0 to 8
ClearSelect counter
Next counter
return