open-insight/LSL2/STPROC/REACTOR_SERVICES.txt
2025-05-28 01:29:32 +02:00

4324 lines
223 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
$Insert REACT_PROB_CAT_EQUATES
$Insert NICA_ORDERS_EQUATES
$Insert REACTOR_INJECTOR_SETTINGS_EQUATES
$Insert REACTOR_RATIOS_EQUATES
$Insert REACT_STATE_EQUATES
Equ WOCust$ to 2
Equ SECONDS_IN_DAY$ to 86400
// 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, Reactor_Log_Services, obj_Post_Log
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, Max, RTI_CreateGUID
// 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', 'EXHAUST_CHAMBER_THK'
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 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$>
CurrExhaustThk = OldReactorRec<REACTOR_EXHAUST_CHAMBER_THK$>
// 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
If CurrExhaustThk = '' then CurrExhaustThk = 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
NewReactorRec<REACTOR_EXHAUST_CHAMBER_THK$> = CurrExhaustThk + TargetThickness
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
NewReactorRec<REACTOR_EXHAUST_CHAMBER_THK$> = CurrExhaustThk + ThkAddition
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
NewReactorRec<REACTOR_EXHAUST_CHAMBER_THK$> = CurrExhaustThk + ThkAddition
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
NewReactorRec<REACTOR_EXHAUST_CHAMBER_THK$> = CurrExhaustThk + ThkAddition
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$>
ResponseData<1, 7> = ReactorRec<REACTOR_EXHAUST_CHAMBER_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> = 'TubeWaferCount'
ResponseData<2, 5> = 'TubeThickness'
ResponseData<2, 6> = 'ArmsWaferCount'
ResponseData<2, 7> = 'ExhuastChamberThickness'
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$>
ResponseData<1, 7> = ReactorRec<REACTOR_EXHAUST_CHAMBER_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> = 'TubeWaferCount'
ResponseData<2, 5> = 'TubeThickness'
ResponseData<2, 6> = 'ArmsWaferCount'
ResponseData<2, 7> = 'ExhuastChamberThickness'
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$>
ResponseData<1, 8> = ReactorRec<REACTOR_EXHAUST_CHAMBER_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'
ResponseData<2, 8> = 'ExhuastChamberThickness'
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$>
CurrExhaustThk = OldReactorRec<REACTOR_EXHAUST_CHAMBER_THK$>
// 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
If CurrExhaustThk = '' then CurrExhaustThk = 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
NewReactorRec<REACTOR_EXHAUST_CHAMBER_THK$> = CurrExhaustThk - TargetThickness
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
NewReactorRec<REACTOR_EXHAUST_CHAMBER_THK$> = CurrExhaustThk - ThkAddition
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
NewReactorRec<REACTOR_EXHAUST_CHAMBER_THK$> = CurrExhaustThk - ThkAddition
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
NewReactorRec<REACTOR_EXHAUST_CHAMBER_THK$> = CurrExhaustThk - ThkAddition
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$>
CurrExhaustThk = OldReactorRec<REACTOR_EXHAUST_CHAMBER_THK$>
// 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
NewReactorRec<REACTOR_EXHAUST_CHAMBER_THK$> = CurrExhaustThk + TargetThickness
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
NewReactorRec<REACTOR_EXHAUST_CHAMBER_THK$> = CurrExhaustThk + ThkAddition
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
NewReactorRec<REACTOR_EXHAUST_CHAMBER_THK$> = CurrExhaustThk + ThkAddition
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
NewReactorRec<REACTOR_EXHAUST_CHAMBER_THK$> = CurrExhaustThk + ThkAddition
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$>
CurrExhaustThk = OldReactorRec<REACTOR_EXHAUST_CHAMBER_THK$>
// 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
If CurrExhaustThk = '' then CurrExhaustThk = 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
NewReactorRec<REACTOR_EXHAUST_CHAMBER_THK$> = CurrExhaustThk - TargetThickness
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
NewReactorRec<REACTOR_EXHAUST_CHAMBER_THK$> = CurrExhaustThk - ThkAddition
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
NewReactorRec<REACTOR_EXHAUST_CHAMBER_THK$> = CurrExhaustThk - ThkAddition
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
NewReactorRec<REACTOR_EXHAUST_CHAMBER_THK$> = CurrExhaustThk - ThkAddition
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', EXHAUST_CHAMBER_THK)
//
// 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
Case MetricType = 'EXHAUST_CHAMBER_THK'
ReactorRec<REACTOR_EXHAUST_CHAMBER_THK$> = 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$>
RlComment = ''
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
AbortAlarmFeatureFlag = Xlate('FEATURE_FLAGS', 'NICA_ABORT_ALARM', FEATURE_FLAGS.ENABLED$, 'X')
If AbortAlarmFeatureFlag EQ True$ then
ModeSubCatFlowId = Xlate('REACT_PROB_CAT', ModeSubCatId, REACT_PROB_CAT_ABORT_ALARM_FLOW_ID$, 'X')
ModeSubCatRespLvl = Xlate('REACT_PROB_CAT', ModeSubCatId, REACT_PROB_CAT_ABORT_ALARM_RESPONSE_LEVEL$, 'X')
AbortAlarmComp = Xlate('REACTOR', ReactNo, REACTOR_ABORT_ALARM_COMPLETE$, 'X')
ActiveAbortAlarmOrders = Nica_Orders_Services('GetActiveOrders', 'REACTOR', ReactNo, 'ABORT_ALARM')
AbortAlarmOrderActive = (ActiveAbortAlarmOrders NE '')
Begin Case
Case ( AbortAlarmOrderActive and (SelE10State _EQC 'Productive') )
ErrorMsg = "An ABORT/ALARM Checklist is active for this reactor and must be completed or overridden in order to change to a productive state."
Case ( AbortAlarmOrderActive and IndexC(ModeSubCat, 'ABORT/ALARM', 1) and (ModeSubCatFlowId NE '') )
// If there is an active ABORT/ALARM NICA order, then we need to check if the new sub mode is different than the sub mode entered when the ABORT/ALARM
// NICA order was created and is of a higher response level or the new mode is WAITING_FOR_OPERATOR and the sub mode has changed. This means the maintenance
// team deemed the true ABORT/ALARM root cause was different than the cause the operators selected.
ActiveAbortAlarmFlowIds = Xlate('NICA_ORDERS', ActiveAbortAlarmOrders, NICA_ORDERS.ORDER_FLOW_IDS$, 'X')
ActiveAbortAlarmRespLvls = Xlate('NICA_ORDERS', ActiveAbortAlarmOrders, NICA_ORDERS.ORDER_RESPONSE_LEVEL$, 'X')
MaxActiveRespLvl = ''
For each ActiveAbortAlarmRespLvl in ActiveAbortAlarmRespLvls using @VM
MaxActiveRespLvl = Max(MaxActiveRespLvl, ActiveAbortAlarmRespLvl)
Next ActiveAbortAlarmRespLvl
If ( (Mode _EQC 'WAITING_FOR_OPERATOR') and (ModeSubCatFlowId NE ActiveAbortAlarmFlowIds) ) |
or ( (ModeSubCatFlowId NE ActiveAbortAlarmFlowIds) and (ModeSubCatRespLvl GT MaxActiveRespLvl) ) then
ReactorType = Xlate('REACTOR', ReactNo, REACTOR_REACT_TYPE$, 'X')
ChecklistIds = Nica_Orders_Services('GetFlowChecklistIds', ModeSubCatFlowId, 'ABORT_ALARM', ReactorType)
If ChecklistIds NE '' then
Nica_Orders_Services('CreateNewOrder', 'REACTOR', ReactNo, 'ABORT_ALARM', ModeSubCatFlowId, ModeSubCatRespLvl, ChecklistIds)
RlComment = 'ABORT/ALARM initiated for flow ':ModeSubCatFlowId:'.'
end
end
Case ( Not(AbortAlarmComp) and Not(AbortAlarmOrderActive) and IndexC(ModeSubCat, 'ABORT/ALARM', 1) and (ModeSubCatFlowId NE '') )
ReactorType = Xlate('REACTOR', ReactNo, REACTOR_REACT_TYPE$, 'X')
ChecklistIds = Nica_Orders_Services('GetFlowChecklistIds', ModeSubCatFlowId, 'ABORT_ALARM', ReactorType)
If ChecklistIds NE '' then
Nica_Orders_Services('CreateNewOrder', 'REACTOR', ReactNo, 'ABORT_ALARM', ModeSubCatFlowId, ModeSubCatRespLvl, ChecklistIds)
RlComment = 'ABORT/ALARM initiated for flow ':ModeSubCatFlowId:'.'
end
Case Otherwise$
// Don't create an ABORT/ALARM NICA order
Null
End Case
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
CurrWoNo = Xlate('CONFIG', 'WO_DAILY_SCHED':ReactNo, 'F2', 'X')
CurrWoNo = CurrWoNo[1, 'F ']
If CurrWoNo NE '' then
CurrPSNo = Xlate('WO_LOG', CurrWoNo, 'PS_NO', 'X')
end else
CurrPSNo = ''
end
RLRec<REACTOR_LOG_PROD_SPEC_NO$> = CurrPSNo
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
If RlComment NE '' then Reactor_Log_Services('AddComment', ReactNo, RlComment, UserID)
If SelE10State _EQC 'Productive' then
// Reset ABORT/ALARM flag
Open 'REACTOR' to hReactor then
WriteV False$ to hReactor, ReactNo, REACTOR_ABORT_ALARM_COMPLETE$ then
LogData = ''
LogData<1> = Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTS') ; // Logging DTM
LogData<2> = 'Successfully set ABORT_ALARM_COMPLETE flag to false for Reactor No: ' : ReactNo
Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$)
end else
LogData = ''
LogData<1> = Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTS') ; // Logging DTM
LogData<2> = 'Failed set ABORT_ALARM_COMPLETE flag to false for Reactor No: ' : ReactNo
Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$)
end
end
end
// 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
Service GetCurrentInjectorSettings(ReactorNo)
ErrorMsg = ''
CurrInjSettings = ''
If ReactorNo NE '' then
If RowExists('REACTOR', ReactorNo) then
Open 'DICT.REACTOR_INJECTOR_SETTINGS' to hDict then
Query = 'REACTOR_NO':@VM:ReactorNo:@FM
Query := 'ACTIVE':@VM:True$:@FM
KeyList = ''
Option = 'E'
Flag = ''
Btree.Extract(Query, 'REACTOR_INJECTOR_SETTINGS', hDict, KeyList, Option, Flag)
If Flag EQ 0 then
Begin Case
Case DCount(KeyList, @VM) EQ 0
CurrInjSettings<0, 1> = ''
CurrInjSettings<0, 2> = ''
CurrInjSettings<0, 3> = ''
CurrInjSettings<0, 4> = ''
CurrInjSettings<0, 5> = ''
Case DCount(KeyList, @VM) EQ 1
SettingsRec = Database_Services('ReadDataRow', 'REACTOR_INJECTOR_SETTINGS', KeyList)
If Error_Services('NoError') then
CurrInjSettings<0, 1> = SettingsRec<REACTOR_INJECTOR_SETTINGS.INJECTOR_1$>
CurrInjSettings<0, 2> = SettingsRec<REACTOR_INJECTOR_SETTINGS.INJECTOR_2$>
CurrInjSettings<0, 3> = SettingsRec<REACTOR_INJECTOR_SETTINGS.INJECTOR_3$>
CurrInjSettings<0, 4> = SettingsRec<REACTOR_INJECTOR_SETTINGS.INJECTOR_4$>
CurrInjSettings<0, 5> = SettingsRec<REACTOR_INJECTOR_SETTINGS.INJECTOR_5$>
end
Case DCount(KeyList, @VM) GT 1
ErrorMsg = 'Error in ':Service:' service. Multiple active REACTOR_INJECTOR_SETTINGS records returned.'
End Case
end else
ErrorMsg = 'Error in ':Service:' service. Error calling Btree.Extract.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Error opening DICT.REACTOR_INJECTOR_SETTINGS.'
end
end else
ErrorMsg = 'Error in ':Service:' service. REACTOR, ':ReactorNo:', does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null ReactorNo passed into service.'
end
If ErrorMsg EQ '' then
Response = CurrInjSettings
end else
Error_Services('Add', ErrorMsg)
end
end service
Service GetCurrentRatios(ReactorNo)
ErrorMsg = ''
CurrRatios = ''
If ReactorNo NE '' then
If RowExists('REACTOR', ReactorNo) then
Open 'DICT.REACTOR_RATIOS' to hDict then
Query = 'REACTOR_NO':@VM:ReactorNo:@FM
Query := 'ACTIVE':@VM:True$:@FM
KeyList = ''
Option = 'E'
Flag = ''
Btree.Extract(Query, 'REACTOR_RATIOS', hDict, KeyList, Option, Flag)
If Flag EQ 0 then
NumRatios = ''
ReactorType = Xlate('REACTOR', ReactorNo, REACTOR_REACT_TYPE$, 'X')
Begin Case
Case ReactorNo EQ 73
// OpenInsight needs to be updated to support reactor type HTR+, which requires 16 ratios.
NumRatios = 16
Case ReactorType EQ 'ASM' or ReactorType EQ 'ASM+'
NumRatios = 10
Case ReactorType EQ 'HTR'
NumRatios = 12
Case Otherwise$
ErrorMsg = 'Error in ':Service:' service. Error determining number '
ErrorMsg := 'of Ratios required for reactor ':ReactorNo:'.'
End Case
If ErrorMsg EQ '' then
Begin Case
Case DCount(KeyList, @VM) EQ 0
For RatioIndex = 1 to NumRatios
CurrRatios<0, RatioIndex> = ''
Next RatioIndex
Case DCount(KeyList, @VM) EQ 1
SettingsRec = Database_Services('ReadDataRow', 'REACTOR_RATIOS', KeyList)
If Error_Services('NoError') then
For RatioIndex = 0 to (NumRatios - 1)
CurrRatios<0, RatioIndex + 1> = SettingsRec<REACTOR_RATIOS.RATIO_1$ + RatioIndex>
Next RatioIndex
end
Case DCount(KeyList, @VM) GT 1
ErrorMsg = 'Error in ':Service:' service. Multiple active REACTOR_RATIOS records returned.'
End Case
end
end else
ErrorMsg = 'Error in ':Service:' service. Error calling Btree.Extract.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Error opening DICT.REACTOR_RATIOS.'
end
end else
ErrorMsg = 'Error in ':Service:' service. REACTOR, ':ReactorNo:', does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null ReactorNo passed into service.'
end
If ErrorMsg EQ '' then
Response = CurrRatios
end else
Error_Services('Add', ErrorMsg)
end
end service
Service GetRatiosByReactorLog(ReactorLogId)
RatiosKey = ''
Ratios = ''
ErrorMsg = ''
ReactorNo = ''
If ReactorLogId NE '' then
If RowExists('REACTOR_LOG', ReactorLogId) then
Query = 'SELECT REACTOR_RATIOS WITH REACTOR_LOG_ID EQ ':Quote(ReactorLogId)
Query := ' BY-DSND RATIO_SET_DTM'
RList(Query, TARGET_ACTIVELIST$)
ErrCode = ''
If Not(Get_Status(ErrCode)) then
If @RecCount GT 0 then
ReadNext RatiosKey else
ErrorMsg = 'Error in ':Service:' service. Error looking up reactor '
ErrorMsg := 'ratios associated with REACTOR_LOG ':ReactorLogId:'.'
end
ClearSelect TARGET_ACTIVELIST$
end
end else
ErrorMsg = 'Error in ':Service:' service. Error looking up reactor '
ErrorMsg := 'ratios associated with REACTOR_LOG ':ReactorLogId:'.'
end
end else
ErrorMsg = 'Error in ':Service:' service. REACTOR_LOG ':ReactorLogId:' does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null ReactorLogId passed into service.'
end
If ErrorMsg EQ '' then
If RatiosKey NE '' then
RatiosRec = Database_Services('ReadDataRow', 'REACTOR_RATIOS', RatiosKey)
If Error_Services('NoError') then
If ReactorNo EQ '' then ReactorNo = Xlate('REACTOR_LOG', ReactorLogId, 'REACTOR', 'X')
If ReactorNo NE '' then
NumRatios = Reactor_Services('GetNumRatios', ReactorNo)
For RatioIndex = 0 to (NumRatios - 1)
Ratios<0, RatioIndex + 1> = RatiosRec<REACTOR_RATIOS.RATIO_1$ + RatioIndex>
Next RatioIndex
end else
ErrorMsg = 'Error in ':Service:' service. Null Reactor in REACTOR_LOG ':ReactorLogId:'.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Error reading REACTOR_RATIOS record ':RatiosKey:'.'
end
end
end
If ErrorMsg EQ '' then
Response = Ratios
end else
Error_Services('Add', ErrorMsg)
end
end service
Service GetInjectorSettingsByReactorLog(ReactorLogId)
ReactInjSetKey = ''
InjSettings = ''
ErrorMsg = ''
If ReactorLogId NE '' then
If RowExists('REACTOR_LOG', ReactorLogId) then
Query = 'SELECT REACTOR_INJECTOR_SETTINGS WITH REACTOR_LOG_ID EQ ':Quote(ReactorLogId)
Query := ' BY-DSND INJ_SET_DTM'
RList(Query, TARGET_ACTIVELIST$)
ErrCode = ''
If Not(Get_Status(ErrCode)) then
If @RecCount GT 0 then
ReadNext ReactInjSetKey else
ErrorMsg = 'Error in ':Service:' service. Error looking up reactor injector '
ErrorMsg := 'settings associated with REACTOR_LOG ':ReactorLogId:'.'
end
ClearSelect TARGET_ACTIVELIST$
end
end else
ErrorMsg = 'Error in ':Service:' service. Error looking up reactor injector '
ErrorMsg := 'settings associated with REACTOR_LOG ':ReactorLogId:'.'
end
end else
ErrorMsg = 'Error in ':Service:' service. REACTOR_LOG ':ReactorLogId:' does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null ReactorLogId passed into service.'
end
If ErrorMsg EQ '' then
If ReactInjSetKey NE '' then
ReactInjSetRec = Database_Services('ReadDataRow', 'REACTOR_INJECTOR_SETTINGS', ReactInjSetKey)
If Error_Services('NoError') then
For InjIndex = 0 to 4
InjSettings<0, InjIndex + 1> = ReactInjSetRec<REACTOR_INJECTOR_SETTINGS.INJECTOR_1$ + InjIndex>
Next InjIndex
end else
ErrorMsg = 'Error in ':Service:' service. Error reading REACTOR_INJECTOR_SETTINGS record ':ReactInjSetKey:'.'
end
end
end
If ErrorMsg EQ '' then
Response = InjSettings
end else
Error_Services('Add', ErrorMsg)
end
end service
Service SetNewInjectorSettings(ReactorNo, InjSettings)
// Injector settings should be passed in internal format (MD3)
ErrorMsg = ''
If ReactorNo NE '' then
If RowExists('REACTOR', ReactorNo) then
If InjSettings NE '' then
If DCount(InjSettings, @VM) EQ 5 then
For each InjSetting in InjSettings using @VM setting vPos
If InjSettings EQ '' then ErrorMsg = 'Error in ':Service:' service. Injector setting ':vPos:' is missing.'
Until ErrorMsg NE ''
Next InjSetting
If ErrorMsg EQ '' then
CurrInjSettings = Reactor_Services('GetCurrentInjectorSettings', ReactorNo)
If (CurrInjSettings NE InjSettings) then
CurrRlId = Xlate('CONFIG', 'REACT_MODE':ReactorNo, 8, 'X')
If CurrRlId NE '' then
Query = 'REACTOR_NO':@VM:ReactorNo:@FM:'ACTIVE':@VM:True$:@FM
Open 'DICT.REACTOR_INJECTOR_SETTINGS' to hDict then
Option = 'E'
ActiveInjSettingsKeys = ''
Flag = ''
Btree.Extract(Query, 'REACTOR_INJECTOR_SETTINGS', hDict, ActiveInjSettingsKeys, Option, Flag)
If Flag EQ 0 then
If ActiveInjSettingsKeys NE '' then
Open 'REACTOR_INJECTOR_SETTINGS' to hTable then
For each ActiveInjSettingsKey in ActiveInjSettingsKeys using @VM
WriteV False$ on hTable, ActiveInjSettingsKey, REACTOR_INJECTOR_SETTINGS.ACTIVE$ else
ErrorMsg = 'Error in ':Service:' service. Error setting previous injector '
ErrorMsg := 'settings to inactive. File error: ':@File_Error
end
Until ErrorMsg NE ''
Next ActiveInjSettingsKey
end else
ErrorMsg = 'Error in ':Service:' service. Error opening REACTOR_INJECTOR_SETTINGS to '
ErrorMsg := 'invalidate previous settings.'
end
end
If ErrorMsg EQ '' then
NewInjSettingsKey = RTI_CreateGUID()
If NewInjSettingsKey NE '' then
NewInjSettingsRec = ''
NewInjSettingsRec<REACTOR_INJECTOR_SETTINGS.REACTOR_LOG_ID$> = CurrRlId
NewInjSettingsRec<REACTOR_INJECTOR_SETTINGS.REACTOR_NO$> = ReactorNo
NewInjSettingsRec<REACTOR_INJECTOR_SETTINGS.INJ_SET_DTM$> = Datetime()
NewInjSettingsRec<REACTOR_INJECTOR_SETTINGS.ACTIVE$> = True$
For InjIndex = 0 to 4
NewInjSettingsRec<REACTOR_INJECTOR_SETTINGS.INJECTOR_1$ + InjIndex> = InjSettings<0, InjIndex + 1>
Next InjIndex
Database_Services('WriteDataRow', 'REACTOR_INJECTOR_SETTINGS', NewInjSettingsKey, NewInjSettingsRec)
If Error_Services('NoError') then
plParms = 'REACT_STATE':@RM
plParms := ReactorNo:@RM
plParms := REACT_STATE_CURR_INJ_RL_ID$:@RM
plParms := CurrRlId:@RM
obj_Post_Log('Create',plParms)
If Get_Status(ErrCode) then
ErrorMsg = 'Error in ':Service:' service. Error calling obj_Post_Log("Create"). '
ErrorMsg := 'Error code: ':ErrCode:'.'
end
end else
ErrorMsg = Error_Services('GetMessage')
end
end else
ErrorMsg = 'Error in ':Service:' service. Error creating new REACTOR_INJECTOR_SETTINGS record.'
end
end
end else
ErrorMsg = 'Error in ':Service:' service. Error calling Btree.Extract.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Error opening DICT.REACTOR_INJECTOR_SETTINGS'
end
end else
ErrorMsg = 'Error in ':Service:' service. Error reading current REACTOR_LOG Id.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Input InjSettings are the same as the current InjSettings.'
end
end
end else
ErrorMsg = 'Error in ':Service:' service. All five injector settings are required.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null InjSettings passed into service.'
end
end else
ErrorMsg = 'Error in ':Service:' service. REACTOR, ':ReactorNo:', does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null ReactorNo passed into service.'
end
If ErrorMsg EQ '' then
Response = True$
end else
Error_Services('Add', ErrorMsg)
Response = False$
end
end service
Service SetNewRatios(ReactorNo, Ratios)
// Ratios should be passed in internal format (MD3)
ErrorMsg = ''
If ReactorNo NE '' then
If RowExists('REACTOR', ReactorNo) then
If Ratios NE '' then
Ratios = SRP_Array('Clean', Ratios, 'Trim', @VM)
NumRatios = Reactor_Services('GetNumRatios', ReactorNo)
If Error_Services('NoError') then
If DCount(Ratios, @VM) EQ NumRatios then
For each Ratio in Ratios using @VM setting vPos
Begin Case
Case Ratio EQ ''
ErrorMsg = 'Error in ':Service:' service. Ratio ':vPos:' is missing.'
Case OConv(Ratio, 'MD3') LT 30
ErrorMsg = 'Error in ':Service:' service. Invalid Ratio value. Ratio ':vPos:' is less than 30.'
Case OConv(Ratio, 'MD3') GT 100
ErrorMsg = 'Error in ':Service:' service. Invalid Ratio value. Ratio ':vPos:' is greater than 100.'
End Case
Until ErrorMsg NE ''
Next Ratio
If ErrorMsg EQ '' then
CurrRatios = Reactor_Services('GetCurrentRatios', ReactorNo)
If (CurrRatios NE Ratios) then
CurrRlId = Xlate('CONFIG', 'REACT_MODE':ReactorNo, 8, 'X')
If CurrRlId NE '' then
Query = 'REACTOR_NO':@VM:ReactorNo:@FM:'ACTIVE':@VM:True$:@FM
Open 'DICT.REACTOR_RATIOS' to hDict then
Option = 'E'
ActiveRatiosKeys = ''
Flag = ''
Btree.Extract(Query, 'REACTOR_RATIOS', hDict, ActiveRatiosKeys, Option, Flag)
If Flag EQ 0 then
If ActiveRatiosKeys NE '' then
Open 'REACTOR_RATIOS' to hTable then
For each ActiveRatiosKey in ActiveRatiosKeys using @VM
WriteV False$ on hTable, ActiveRatiosKey, REACTOR_RATIOS.ACTIVE$ else
ErrorMsg = 'Error in ':Service:' service. Error setting previous ratios '
ErrorMsg := 'record to inactive. File error: ':@File_Error
end
Until ErrorMsg NE ''
Next ActiveRatiosKey
end else
ErrorMsg = 'Error in ':Service:' service. Error opening REACTOR_RATIOS table to '
ErrorMsg := 'invalidate previous ratios.'
end
end
If ErrorMsg EQ '' then
NewRatiosKey = RTI_CreateGUID()
If NewRatiosKey NE '' then
NewRatiosRec = ''
NewRatiosRec<REACTOR_RATIOS.REACTOR_LOG_ID$> = CurrRlId
NewRatiosRec<REACTOR_RATIOS.REACTOR_NO$> = ReactorNo
NewRatiosRec<REACTOR_RATIOS.RATIO_SET_DTM$> = Datetime()
NewRatiosRec<REACTOR_RATIOS.ACTIVE$> = True$
For RatioIndex = 0 to (NumRatios - 1)
NewRatiosRec<REACTOR_RATIOS.RATIO_1$ + RatioIndex> = Ratios<0, RatioIndex + 1>
Next RatioIndex
Database_Services('WriteDataRow', 'REACTOR_RATIOS', NewRatiosKey, NewRatiosRec)
If Error_Services('NoError') then
plParms = 'REACT_STATE':@RM
plParms := ReactorNo:@RM
plParms := REACT_STATE_CURR_RATIO_RL_ID$:@RM
plParms := CurrRlId:@RM
obj_Post_Log('Create',plParms)
If Get_Status(ErrCode) then
ErrorMsg = 'Error in ':Service:' service. Error calling obj_Post_Log("Create"). '
ErrorMsg = 'Error code: ':ErrCode:'.'
end
end else
ErrorMsg = Error_Services('GetMessage')
end
end else
ErrorMsg = 'Error in ':Service:' service. Error creating new REACTOR_RATIOS record.'
end
end
end else
ErrorMsg = 'Error in ':Service:' service. Error calling Btree.Extract.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Error opening DICT.REACTOR_RATIOS'
end
end else
ErrorMsg = 'Error in ':Service:' service. Error reading current REACTOR_LOG Id.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Input Ratios are the same as the current Ratios.'
end
end
end else
ErrorMsg = 'Error in ':Service:' service. Reactor ':ReactorNo:' requires ':NumRatios:' values '
ErrorMsg := 'for ratios. Only ':DCount(Ratios, @VM):' were supplied.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Error determining number of required ratios '
ErrorMsg := 'for reactor ':ReactorNo:'. Error message: ':Error_Services("GetMessage")
end
end else
ErrorMsg = 'Error in ':Service:' service. Null Ratios passed into service.'
end
end else
ErrorMsg = 'Error in ':Service:' service. REACTOR, ':ReactorNo:', does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null ReactorNo passed into service.'
end
If ErrorMsg EQ '' then
Response = True$
end else
Error_Services('Add', ErrorMsg)
Response = False$
end
end service
Service GetNumRatios(ReactorNo)
ErrorMsg = ''
NumRatios = ''
If (ReactorNo NE '') then
If RowExists('REACTOR', ReactorNo) then
ReactorType = Xlate('REACTOR', ReactorNo, REACTOR_REACT_TYPE$, 'X')
Begin Case
Case ReactorNo EQ 73
// OpenInsight needs to be updated to support reactor type HTR+, which requires 16 ratios.
NumRatios = 16
Case ReactorType EQ 'ASM' or ReactorType EQ 'ASM+'
NumRatios = 10
Case ReactorType EQ 'HTR'
NumRatios = 12
Case Otherwise$
ErrorMsg = 'Error in ':Service:' service. Error determining number '
ErrorMsg := 'of Ratios required for reactor ':ReactorNo:'.'
End Case
end else
ErrorMsg = 'Error in ':Service:' service. REACTOR, ':ReactorNo:', does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null ReactorNo passed into service.'
end
If ErrorMsg EQ '' then
Response = NumRatios
end else
Error_Services('Add', ErrorMsg)
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