1790 lines
118 KiB
Plaintext
1790 lines
118 KiB
Plaintext
Function Scan_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 : Scan_Services
|
|
|
|
Description : Handler program for all Scan services.
|
|
|
|
Notes :
|
|
|
|
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)
|
|
09/07/18 dmb Original programmer.
|
|
|
|
***********************************************************************************************************************/
|
|
|
|
#pragma precomp SRP_PreCompiler
|
|
|
|
$insert LOGICAL
|
|
$insert SERVICE_SETUP
|
|
$insert SCANS_EQUATES
|
|
$insert RDS_EQUATES
|
|
$insert RDS_LAYER_EQUATES
|
|
$insert DICT_EQUATES
|
|
$insert WO_MAT_EQUATES
|
|
$insert OVERRIDE_LOG_EQUATES
|
|
$insert REACTOR_EQUATES
|
|
$INSERT REACT_LL_EQUATES
|
|
$insert RLIST_EQUATES
|
|
$Insert ROTR_OVERRIDE_COMMENT_OPTIONS_EQUATES
|
|
|
|
Common /ScanServices/ NotAcceptableReasons@, Unused2@, Unused3@, Unused4@, Unused5@, Unused6@, Unused7@, Unused8@
|
|
|
|
Declare Function Scan_Services, Memory_Services, Database_Services, SRP_JSON, RTI_CreateGUID, Rds_Services, Datetime
|
|
Declare Function QA_Services, Error_Services, Security_Services, SRP_Array, obj_WO_Mat, Memberof, Override_Log_Services
|
|
Declare Function Keyboard_Sim_Services, Environment_Services, Logging_Services, Reactor_Services
|
|
Declare Subroutine Scan_Services, Memory_Services, Database_Services, SRP_JSON, QA_Services, Error_Services
|
|
Declare Subroutine obj_WO_Mat_Log, Tool_Parms_Services, RDS_Services, Logging_Services
|
|
|
|
Equ CRLF$ to \0D0A\
|
|
|
|
LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\ScanAPI'
|
|
LogDate = Oconv(Date(), 'D4/')
|
|
LogTime = Oconv(Time(), 'MTS')
|
|
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Load-Unload Log.csv'
|
|
Headers = 'Logging DTM' : @FM : 'RDS Key ID' : @FM : 'User' : @FM : 'CurrStage' : @FM : 'Scan ID' : @FM : 'Action' : @FM : 'Result'
|
|
objLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$)
|
|
LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM
|
|
|
|
GoToService else
|
|
Error_Services('Add', Service : ' is not a valid service request within the ' : ServiceModule : ' module.')
|
|
end
|
|
|
|
Return Response OR ''
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Service Parameter Options
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
Options BOOLEAN = True$, False$
|
|
Options SCAN_TYPES = 'LOCATION', 'TOOL'
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Services
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
Service AddNotAcceptableReason(Reason)
|
|
|
|
If Len(NotAcceptableReasons@) then
|
|
NotAcceptableReasons@ := @FM : Reason
|
|
end else
|
|
NotAcceptableReasons@ = Reason
|
|
end
|
|
|
|
end service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// GetNotAcceptableReason
|
|
//
|
|
// Returns the most current not acceptable reason.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service GetNotAcceptableReason()
|
|
|
|
Response = NotAcceptableReasons@[-1, 'B' : @FM]
|
|
|
|
End Service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// GetNotAcceptableReasons
|
|
//
|
|
// Returns the stack of not acceptable reasons. This will be @FM delimited.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service GetNotAcceptableReasons()
|
|
|
|
Response = NotAcceptableReasons@
|
|
|
|
End Service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// ClearNotAcceptableReasons
|
|
//
|
|
// Clears all not acceptable reasons.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service ClearNotAcceptableReasons()
|
|
|
|
NotAcceptableReasons@ = ''
|
|
|
|
End Service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// HasNotAcceptableReason
|
|
//
|
|
// Returns True if there is an error condition, False if there is no error condition. Caller will still need to use
|
|
// the GetMessage or GetMessages service to determine what the error is. The HasError service allows the caller to
|
|
// embed the Error_Services service call inside of a conditional statement like this:
|
|
//
|
|
// If Error_Services('HasError') then
|
|
// * An error has occured. Proceed accordingly.
|
|
// ErrorMessage = Error_Services('GetMessage')
|
|
// end else
|
|
// * No error has occured.
|
|
// end
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service HasNotAcceptableReason()
|
|
|
|
If Len(NotAcceptableReasons@) then
|
|
Response = True$
|
|
end else
|
|
Response = False$
|
|
end
|
|
|
|
End Service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// NoNotAcceptableReason
|
|
//
|
|
// Returns True if there are no error conditions, False if there is an error condition. This is the opposite of the
|
|
// HasError service and exists for improved readability.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service NoNotAcceptableReason()
|
|
|
|
If Len(NotAcceptableReasons@) then
|
|
Response = False$
|
|
end else
|
|
Response = True$
|
|
end
|
|
|
|
End Service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// CreateScansRow
|
|
//
|
|
// Creates a new database row in the SCANS table. Retruns the Key ID to the SCANS table if successful.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service CreateScansRow(ScanType=SCAN_TYPES)
|
|
|
|
ScanID = RTI_CreateGUID()
|
|
|
|
If ScanID NE '' then
|
|
ScansRow = ''
|
|
ScansRow<SCANS.CREATED_DATE$> = Date()
|
|
ScansRow<SCANS.CREATED_TIME$> = Time()
|
|
ScansRow<SCANS.SCAN_TYPE$> = ScanType
|
|
ScansRow<SCANS.ACCEPTED$> = False$
|
|
Database_Services('WriteDataRow', 'SCANS', ScanID, ScansRow, True$, False$, True$)
|
|
end else
|
|
Error_Services('Add', 'ScanID was not created in the ' : Service : ' service.')
|
|
end
|
|
|
|
Response = ScanID
|
|
|
|
end service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// GetScansRow
|
|
//
|
|
// Returns the database row from the SCANS table for the indicated Scan ID. The default format is MultiValue.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service GetScansRow(ScanID, ReturnJSON)
|
|
|
|
ScansRow = ''
|
|
|
|
If ScanID NE '' then
|
|
ScansRow = Database_Services('ReadDataRow', 'SCANS', ScanID)
|
|
If ReturnJSON EQ True$ then
|
|
ScansRow = Scan_Services('ConvertMVScanToJSON', ScanID, ScansRow)
|
|
end
|
|
end else
|
|
Error_Services('Add', 'ScanID argument was missing in the ' : Service : ' service.')
|
|
end
|
|
|
|
Response = ScansRow
|
|
|
|
end service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// SetScansRow
|
|
//
|
|
// Returns the database row from the SCANS table for the indicated Scan ID. The default format is MultiValue.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service SetScansRow(ScanID, ScansRow)
|
|
|
|
If (ScanID NE '') AND (ScansRow NE '') then
|
|
Database_Services('WriteDataRow', 'SCANS', ScanID, ScansRow)
|
|
end else
|
|
Error_Services('Add', 'ScanID or ScansRow argument was missing in the ' : Service : ' service.')
|
|
end
|
|
|
|
end service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// ProcessScanData
|
|
//
|
|
// Processes new scan data and updates the SCANS database row for the indicated Scan ID. This service should parse the
|
|
// scan data and identify its intended field and then evaluate if the scan data is valid. Note: just because the scan
|
|
// resource is not ready to be accepted, it does not mean this scan data is invalid. Each scan data will have to be
|
|
// evaluated on a case by case basis.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service ProcessScanData(ScanID, ScanJSON)
|
|
|
|
If ( (ScanID NE '') AND (ScanJSON NE '') ) then
|
|
hScanJSON = ''
|
|
ParseResponse = SRP_JSON(hScanJSON, 'PARSE', ScanJSON)
|
|
If (ParseResponse EQ '') then
|
|
|
|
ScanData = SRP_JSON(hScanJSON, 'GetValue', 'scanData')
|
|
// Code 3of9 encodes the asterisk and underscore characters. These need to be decoded.
|
|
If ScanData NE '' then Scan_Services('DecodeScanData', ScanData)
|
|
// Confirm that this is a valid Scan ID.
|
|
ScansRow = Database_Services('ReadDataRow', 'SCANS', ScanID)
|
|
If Error_Services('NoError') then
|
|
// Use the system variables to evaluate calculated columns easily.
|
|
@DICT = Database_Services('GetTableHandle', 'DICT.SCANS')
|
|
@ID = ScanID
|
|
@RECORD = ScansRow
|
|
Action = ''
|
|
ColumnIndex = ''
|
|
ColumnValue = ''
|
|
|
|
// Identify the scan data based on the data identifier prefix (if any). Otherwise, assume this is a
|
|
// type of cassette ID (i.e., RDS or WMO).
|
|
Begin Case
|
|
|
|
//DPC - 3/18/20 - added validation to allow 1T scans to be interpreted as RDS or Supplier Lot code
|
|
//1T could be supplier lot (Global Wafer and Sumco Japan) or could be IFX internal lot (RDS)
|
|
//2T is always supplier lot
|
|
Case ( (ScanData[1, 2] EQ '1T') or (ScanData[1, 2] EQ '2T') )
|
|
// Supplier lot scan.
|
|
Convert '_' to '-' in ScanData
|
|
SupplierLotID = ScanData[3, 999]
|
|
If ( RowExists('RDS', SupplierLotID) EQ True$ AND ScanData[1, 2] EQ '1T') then
|
|
ScansRow<SCANS.CASSETTE_IDS$> = SupplierLotID
|
|
//If ( RowExists('RDS', SupplierLotID) EQ True$ ) then
|
|
// Error_Services('Add', 'Not a valid supplier lot')
|
|
end else
|
|
ScansRow<SCANS.SUPPLIER_LOT$> = SupplierLotID
|
|
end
|
|
|
|
Case ScanData[1, 5] EQ 'RESET'
|
|
|
|
ScansRow<SCANS.SCAN_TYPE$> = 'RESET'
|
|
ScansRow<SCANS.EMPLOYEE_ID$> = ''
|
|
ScansRow<SCANS.LOCATION_ID$> = ''
|
|
ScansRow<SCANS.TOOL_ID$> = ''
|
|
ScansRow<SCANS.LOAD_LOCK$> = ''
|
|
|
|
Case ScanData[1, 2] EQ '1H'
|
|
// Employee ID scan. Set the EMPLOYEE_ID column and check the
|
|
// EMPLOYEE_AUTHORIZED and EMPLOYEE_NOT_AUTHORIZED_REASON column values to determine if the
|
|
// scan data is valid.
|
|
{EMPLOYEE_ID} = ScanData[3, 999]
|
|
EmployeeAuthorized = {EMPLOYEE_AUTHORIZED}
|
|
EmployeeActive = Xlate('LSL_USERS', {EMPLOYEE_ID}, 'ACTIVE', 'X')
|
|
|
|
ScansRow<SCANS.AUTHENTICATED$> = 0
|
|
Begin Case
|
|
Case EmployeeAuthorized NE True$
|
|
// Regardless of the not authorized reason, the scan data will be considered invalid.
|
|
EmployeeNotAuthorizedReason = {EMPLOYEE_NOT_AUTHORIZED_REASON}
|
|
Error_Services('Add', EmployeeNotAuthorizedReason)
|
|
Case EmployeeActive NE True$
|
|
Error_Services('Add', 'Inactive employee.')
|
|
Case Otherwise$
|
|
ScansRow<SCANS.EMPLOYEE_ID$> = {EMPLOYEE_ID}
|
|
End Case
|
|
|
|
Case ScanData[1, 3] EQ '10S'
|
|
|
|
// Tool ID scan. A determination needs to be made to see if this is a transfer tool or a process
|
|
// tool. Transfer tools do not require employee authorization, but process tools do.
|
|
//
|
|
// If this is a non-existent tool or if the current Employee ID is not authorized
|
|
// will the scan data be considered invalid. However, if there is no Employee ID, then do not
|
|
// use this to invalidate the scan data.
|
|
ScanData = ScanData[4, 999]
|
|
ToolID = ScanData[1, '.']
|
|
LoadLock = ScanData[Col2() + 1, 1]
|
|
ToolRow = Database_Services('ReadDataRow', 'TOOL', ToolID)
|
|
If Error_Services('NoError') then
|
|
ScansRow<SCANS.SCAN_TYPE$> = 'TOOL'
|
|
ToolType = ToolRow<2>
|
|
Begin Case
|
|
Case ToolType _EQC 'Reactor'
|
|
// Clear the Location ID and set the Tool ID column to determine if the current Employee ID
|
|
// is authorized.
|
|
{LOCATION_ID} = ''
|
|
{TOOL_ID} = ToolID
|
|
EmployeeAuthorized = {EMPLOYEE_AUTHORIZED}
|
|
If (EmployeeAuthorized NE True$) AND ({EMPLOYEE_ID} NE '') then
|
|
// Regardless of the not authorized reason, the scan data will be considered invalid.
|
|
EmployeeNotAuthorizedReason = {EMPLOYEE_NOT_AUTHORIZED_REASON}
|
|
Error_Services('Add', EmployeeNotAuthorizedReason)
|
|
end else
|
|
* If LoadLock EQ '' then LoadLock = 'NA' ; // NA means Not Applicable.
|
|
ReactorID = ToolID[2, 999]
|
|
LoadLockReq = Xlate('REACTOR', ReactorID, 'LOAD_LOCK_REQ', 'X')
|
|
//LoadLockReq = Xlate('REACTOR', ReactorID, REACTOR_PICK_PLACE$, 'X')
|
|
|
|
Begin Case
|
|
Case (LoadLockReq EQ True$)
|
|
If (LoadLock NE '') then
|
|
If ( (LoadLock EQ 'L') or (LoadLock EQ 'R') ) then
|
|
If ScansRow<SCANS.LOCATION_ID$> NE '' then
|
|
ScansRow<SCANS.CASSETTE_IDS$> = ''
|
|
end else
|
|
ScansRow<SCANS.CASSETTE_IDS$> = ScansRow<SCANS.CASSETTE_IDS$, 1> ; // Make sure only the first Cassette ID is tracked.
|
|
end
|
|
ScansRow<SCANS.LOCATION_ID$> = '' ; // Make sure the Location ID is cleared.
|
|
ScansRow<SCANS.TOOL_ID$> = ToolID
|
|
ScansRow<SCANS.LOAD_LOCK$> = LoadLock
|
|
end else
|
|
Error_Services('Add', 'Invalid load lock value "':LoadLock:'".')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'A load lock side "L" or "R" is required for reactor ':ReactorID:'.')
|
|
end
|
|
Case (LoadLockReq EQ False$)
|
|
If ScansRow<SCANS.LOCATION_ID$> NE '' then
|
|
ScansRow<SCANS.CASSETTE_IDS$> = ''
|
|
end else
|
|
ScansRow<SCANS.CASSETTE_IDS$> = ScansRow<SCANS.CASSETTE_IDS$, 1> ; // Make sure only the first Cassette ID is tracked.
|
|
end
|
|
ScansRow<SCANS.LOCATION_ID$> = '' ; // Make sure the Location ID is cleared.
|
|
ScansRow<SCANS.TOOL_ID$> = ToolID
|
|
ScansRow<SCANS.LOAD_LOCK$> = LoadLock
|
|
End Case
|
|
|
|
end
|
|
Case ToolType _EQC 'Transfer'
|
|
Error_Services('Add', 'Tool type ':ToolType:' is not currently supported by the barcode application.')
|
|
// Code below may be implemented down the road.
|
|
// This is a transfer tool. Just update the scan resource.
|
|
* ScansRow<SCANS.LOCATION_ID$> = '' ; // Make sure the Location ID is cleared.
|
|
* ScansRow<SCANS.CASSETTE_IDS$> = ScansRow<SCANS.CASSETTE_IDS$, 1> ; // Make sure only the first Cassette ID is tracked.
|
|
* ScansRow<SCANS.TRANSFER_TOOL_ID$> = ToolID
|
|
Case Otherwise$
|
|
Error_Services('Add', 'Tool type ':ToolType:' is not currently supported by the barcode application.')
|
|
End Case
|
|
end else
|
|
Error_Services('Add', ToolID : ' is not a valid tool ID.')
|
|
end
|
|
|
|
Case ScanData[1, 2] EQ '1L'
|
|
// Location ID scan. Only if this is a non-existent location will the scan data be considered
|
|
// invalid.
|
|
LocationID = ScanData[3, 999]
|
|
Convert '.' to '*' in LocationID
|
|
LocationRow = Database_Services('ReadDataRow', 'LOCATION', LocationID)
|
|
Convert '*' to '.' in LocationID
|
|
If Error_Services('NoError') then
|
|
ScansRow<SCANS.SCAN_TYPE$> = 'LOCATION'
|
|
If ScansRow<SCANS.TOOL_ID$> NE '' then ScansRow<SCANS.CASSETTE_IDS$> = ''
|
|
ScansRow<SCANS.TOOL_ID$> = '' ; // Make sure the Tool ID is cleared.
|
|
ScansRow<SCANS.LOAD_LOCK$> = '' ; // Make sure the Tool Load Lock is cleared.
|
|
ScansRow<SCANS.TRANSFER_TOOL_ID$> = '' ; // Make sure the Transfer Tool ID is cleared.
|
|
ScansRow<SCANS.LOCATION_ID$> = LocationID
|
|
end else
|
|
Error_Services('Add', LocationID : ' is not a valid location ID.')
|
|
end
|
|
|
|
Case ScanData[1, 2] EQ '1B'
|
|
// Carrier/boat ID scan. Only if this is a non-existent carrier will the scan data be considered
|
|
// invalid.
|
|
ScanData = ScanData[3, 999]
|
|
PLNo = ScanData[1, '.']
|
|
BoatID = ScanData[Col2() + 1, '.']
|
|
If BoatID NE '' then
|
|
ScansRow<SCANS.LOCATION_ID$> = '' ; // Make sure the Location ID is cleared.
|
|
ScansRow<SCANS.CASSETTE_IDS$> = ScansRow<SCANS.CASSETTE_IDS$, 1> ; // Make sure only the first Cassette ID is tracked.
|
|
ScansRow<SCANS.BOAT_ID$> = BoatID
|
|
ScansRow<SCANS.PL_NUMBER$> = PLNo
|
|
end else
|
|
Error_Services('Add', ScanData : ' is not a valid boat ID.')
|
|
end
|
|
Case ScanData[1, 3] EQ 'PWD'
|
|
// Password/Signature scan. If the scan is not ready to be accepted or the password does
|
|
// not match the password of the employee ID scanned then this will be an invalid scan,
|
|
// otherwise the scan will be accepted.
|
|
Password = ScanData[4, 999]
|
|
If Password NE '' then
|
|
EmployeeID = ScansRow<SCANS.EMPLOYEE_ID$>
|
|
If EmployeeID NE '' then
|
|
Authenticated = Security_Services('AuthenticateLSLCredentials', EmployeeID, Password)
|
|
If Authenticated EQ True$ then
|
|
ScansRow<SCANS.AUTHENTICATED$> = 1
|
|
end else
|
|
ScansRow<SCANS.AUTHENTICATED$> = 0
|
|
Error_Services('Add', 'Invalid password for user ':EmployeeID:'.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'An employee ID must be scanned before scanning a password.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'Invalid password scanned.')
|
|
end
|
|
Case ScanData[1, 8] EQ 'OVERRIDE'
|
|
|
|
Type = ScansRow<SCANS.OVERRIDE_TYPE$>
|
|
|
|
if {EMPLOYEE_ID} NE '' AND ScansRow<SCANS.AUTHENTICATED$> EQ 1 then
|
|
|
|
Username = {EMPLOYEE_ID}
|
|
|
|
|
|
Member = False$
|
|
Groups = 'LEAD':@VM:'SUPERVISOR':@VM:'ENGINEER':@VM:'ENG_TECH':@VM:'ROTR_OVERRIDE'
|
|
|
|
For each Group in Groups using @VM
|
|
Member = MemberOf(Username, Group)
|
|
Until Member EQ True$
|
|
Next Group
|
|
|
|
if Member EQ True$ then
|
|
|
|
IF Type EQ 'ROTR' then
|
|
|
|
|
|
Reactor = {TOOL_ID}[2,999]
|
|
RDSNo = {CASSETTE_IDS}
|
|
Comment = ScanData[13, 999]
|
|
//Perform the Override here
|
|
overrideLogTable = 'RDS':@VM:'REACTOR'
|
|
overrideLogKey = RDSNo:@VM:Reactor
|
|
overrideLogUser = {EMPLOYEE_ID}
|
|
overrideLogComment = Comment
|
|
overrideLogCategory = 'ROTR_BLOCK'
|
|
overrideLogCause = Xlate('REACTOR', Reactor, REACTOR_ROTR_STATUS_REASON$, 'X')
|
|
orKey = Override_Log_Services('Create', overrideLogTable, overrideLogKey, overrideLogUser, overrideLogComment, overrideLogCategory, overrideLogCause)
|
|
|
|
|
|
//Add override key to RDS
|
|
RDSRec = Xlate('RDS', RDSNo, '', 'X')
|
|
RDSRec = Insert(RDSRec, RDS_OVERRIDE_KEYS$, 1, 0, orKey)
|
|
|
|
//Clear Set ROTR status to Passing and clear reason
|
|
ReactorRec = XLATE('REACTOR', Reactor, '', 'X')
|
|
ReactorRec<REACTOR_ROTR_STATUS$> = 'P'
|
|
|
|
rotrStatusReason = ReactorRec<REACTOR_ROTR_STATUS_REASON$>
|
|
ReactorRec<REACTOR_PREVIOUS_ROTR_STATUS_REASON$> = rotrStatusReason
|
|
ReactorRec<REACTOR_ROTR_STATUS_REASON$> = ''
|
|
|
|
ReactorRec<REACTOR_PREVIOUS_ROTR_OVERRIDE_RDS$> = RDSNo
|
|
|
|
rotrOverrideCount = ReactorRec<REACTOR_ROTR_OVERRIDE_COUNT$>
|
|
ReactorRec<REACTOR_ROTR_OVERRIDE_COUNT$> = rotrOverrideCount + 1
|
|
Database_Services('WriteDataRow', 'REACTOR', Reactor, ReactorRec, True$, False$, True$)
|
|
Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, True$)
|
|
|
|
ScansRow<SCANS.EMPLOYEE_ID$>= ''
|
|
Result = 'Override Performed successfully'
|
|
end
|
|
|
|
end else
|
|
Error_Services('Add', 'Selected Employee is not authorized to perform an override')
|
|
end
|
|
end
|
|
Case ScanData[1, 2] EQ '5T'
|
|
//Tencor Scan - Note this is only for loading cassette ID into Tencor tool
|
|
ScansRow<SCANS.SCAN_TYPE$> = 'TENCOR_LOAD'
|
|
ScansRow<SCANS.TOOL_ID$>= ScanData[3,99]
|
|
Case ScanData EQ ''
|
|
// Most likely receiving RDS data, so nothing to do here.
|
|
Null
|
|
Case Otherwise$
|
|
// Assume this is intended to be a Cassette ID scan (either WMO or RDS). Only if this is a
|
|
// non-existent carrier will the scan data be considered invalid.
|
|
ColumnIndex = SCANS.CASSETTE_IDS$
|
|
CassetteID = ScanData
|
|
|
|
ValidCassetteID = False$ ; // Assume Cassette ID is not valid for now.
|
|
If Num(CassetteID) then
|
|
// Might be an RDS number.
|
|
RDSRow = Database_Services('ReadDataRow', 'RDS', CassetteID)
|
|
If Error_Services('NoError') then
|
|
ValidCassetteID = True$
|
|
end
|
|
end else
|
|
// Might be a WMO number.
|
|
If DCount(CassetteID, '.') EQ 3 then
|
|
// Passes the format test.
|
|
If ( (CassetteID[1, 1] EQ 'O') or (CassetteID[1, 1] EQ 'I') ) then
|
|
IOFlag = CassetteID[1, 1]
|
|
CassetteID = CassetteID[2, 999]
|
|
end else
|
|
IOFlag = ''
|
|
end
|
|
Convert '.' to '*' in CassetteID
|
|
WMOutRow = Database_Services('ReadDataRow', 'WM_OUT', CassetteID)
|
|
Convert '*' to '.' in CassetteID
|
|
If Error_Services('NoError') then
|
|
ValidCassetteID = True$
|
|
end
|
|
end
|
|
end
|
|
If ValidCassetteID EQ True$ then
|
|
// This is a valid Cassette ID that needs to be added to this resource. If the Tool
|
|
// ID is not populated, then append this Cassette ID to the array, otherwise replace
|
|
// the existing Cassette ID with this one.
|
|
If ScansRow<SCANS.TOOL_ID$> EQ '' then
|
|
// Only append if it doesn't already exists.
|
|
Locate CassetteID in ScansRow<SCANS.CASSETTE_IDS$> using @VM setting vPos else
|
|
ScansRow<SCANS.CASSETTE_IDS$, -1> = CassetteID
|
|
end
|
|
end else
|
|
ScansRow<SCANS.CASSETTE_IDS$> = CassetteID
|
|
end
|
|
end else
|
|
Error_Services('Add', CassetteID : ' is not a valid Cassette ID.')
|
|
end
|
|
End Case
|
|
|
|
If Error_Services('NoError') then
|
|
// Process Scan row data here to determine the type of scan (i.e. Location, Pre-Epi + Load, or Unload).
|
|
ScanType = ScansRow<SCANS.SCAN_TYPE$>
|
|
CassetteIDs = ScansRow<SCANS.CASSETTE_IDS$>
|
|
NumCass = DCount(CassetteIDs, @VM)
|
|
EmployeeID = ScansRow<SCANS.EMPLOYEE_ID$>
|
|
Begin Case
|
|
Case ScanType EQ 'RESET'
|
|
Action = 'RESET'
|
|
|
|
Case ScanType EQ 'TENCOR_LOAD'
|
|
Action = 'TENCOR_LOAD'
|
|
If (CassetteIDs EQ '') then
|
|
Scan_Services('AddNotAcceptableReason', 'At least one cassette must be scanned to complete a Tencor scan.')
|
|
end
|
|
|
|
Case ScanType EQ 'LOCATION'
|
|
Action = 'PLACE'
|
|
If (EmployeeID EQ '') then
|
|
Scan_Services('AddNotAcceptableReason', 'EmployeeID required to complete a location scan.')
|
|
end
|
|
If (CassetteIDs EQ '') then
|
|
Scan_Services('AddNotAcceptableReason', 'At least one cassette must be scanned to complete a location scan.')
|
|
end
|
|
LastCassScanned = CassetteIDs<0, NumCass>
|
|
CurrStage = Xlate('RDS', LastCassScanned, 'CURR_STAGE', 'X')
|
|
If CurrStage EQ 'UNLOAD' then
|
|
Error_Services('Add', '(':LastCassScanned:') Cassette is currently loaded on a tool and is ineligble for a location scan.')
|
|
end
|
|
|
|
Case ScanType EQ 'TOOL'
|
|
// Check if cassette field is populated. If so, then check the cassette's current status to
|
|
// determine what the next action will be (i.e. Pre-Epi+Load, Unload, etc.). Ensure we are
|
|
// working with an RDS and not a WM_IN or WM_OUT cassette ID. They are not used during the
|
|
// "RDS" process.
|
|
|
|
If (CassetteIDs NE '') then
|
|
// Ensure only one cassette is scanned
|
|
If (NumCass EQ 1) then
|
|
CassetteID = CassetteIDs<0, NumCass>
|
|
// Ensure we are working with an RDS and not a WM_OUT/WM_IN cassette
|
|
If (Count(CassetteID, '.') EQ 0) then
|
|
|
|
RDSNo = CassetteID
|
|
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo)
|
|
|
|
WONo = RDSRec<RDS_WO$>
|
|
CassNo = RDSRec<RDS_CASS_NO$>
|
|
CurrStatus = obj_WO_Mat('CurrStatus', WONo:'*':CassNo)
|
|
|
|
// RDS Format
|
|
IsEpiPro = RDS_Services('IsEpiPro', CassetteID)
|
|
If IsEpiPro EQ False$ then
|
|
// Non-EpiPro RDS
|
|
WONo = Xlate('RDS', CassetteID, 'WO', 'X')
|
|
CassNo = Xlate('RDS', CassetteID, 'CASS_NO', 'X')
|
|
WOMatKey = WONo:'*':CassNo
|
|
WOMatLocs = Xlate('WO_MAT', WOMatKey, WO_MAT_INV_LOCATION$, 'X')
|
|
If Index(WOMatLocs,'PTI',1) else Error_Services('Add', 'Cassette ':CassetteID:' failed due to missing PTI.')
|
|
end else
|
|
// EpiPro RDS
|
|
OutCassNos = Xlate('RDS', CassetteID, 'OUT_CASS_NO', 'X')
|
|
OutCassNos = SRP_Array('Clean', OutCassNos, 'TrimAndMakeUnique', @VM)
|
|
For each OutCassNo in OutCassNos using @VM setting oPos
|
|
WONo = Xlate('RDS', CassetteID, 'WO', 'X')
|
|
CassNo = OutCassNo
|
|
WOMatKey = WONo:'*':CassNo
|
|
WOMatLocs = Xlate('WO_MAT', WOMatKey, WO_MAT_INV_LOCATION$, 'X')
|
|
If Index(WOMatLocs,'PTI',1) else Error_Services('Add', 'Cassette ':CassetteID:' failed due to missing PTI.')
|
|
Next OutCassNo
|
|
end
|
|
|
|
If Error_Services('NoError') then
|
|
If CurrStatus NE 'HOLD' then
|
|
If (EmployeeID NE '') then
|
|
|
|
SupplInstAckReq = Xlate('RDS', RDSNo, 'SUPPL_ACK_REQ' , 'X')
|
|
RDSLayerInstAckReq = Xlate('RDS', RDSNo, 'RDS_LAYER_ACK_REQ' , 'X')
|
|
PreInstAckReq = Xlate('RDS', RDSNo, 'PRE_INST_ACK_REQ' , 'X')
|
|
FwiInstAckReq = Xlate('RDS', RDSNo, 'FWI_INST_ACK_REQ' , 'X')
|
|
LwiInstAckReq = Xlate('RDS', RDSNo, 'LWI_INST_ACK_REQ' , 'X')
|
|
QAInstAckReq = Xlate('RDS', RDSNo, 'QA_INST_ACK_REQ' , 'X')
|
|
LoadInstAckReq = Xlate('RDS', RDSNo, 'LOAD_INST_ACK_REQ' , 'X')
|
|
UnloadInstAckReq = Xlate('RDS', RDSNo, 'UNLOAD_INST_ACK_REQ' , 'X')
|
|
PostInstAckReq = Xlate('RDS', RDSno, 'POST_INST_ACK_REQ' , 'X')
|
|
WaferCountInstAckReq = Xlate('RDS', RDSNo, 'WAFER_COUNT_ACK_REQ' , 'X')
|
|
// Parse JSON objects
|
|
hRDS = SRP_JSON(hScanJSON, 'Get', 'rds')
|
|
If (hRDS NE 0) then
|
|
If (SupplInstAckReq EQ True$) then
|
|
SupplAck = SRP_JSON(hRDS, 'GetValue', 'supplInstAck')
|
|
If (SupplAck EQ True$) then
|
|
RDSRec<RDS_SUPPL_ACK$> = True$
|
|
RDSRec<RDS_SUPPL_SIG$> = ScansRow<SCANS.EMPLOYEE_ID$>
|
|
RDSRec<RDS_SUPPL_SIG_DATE$> = Date()
|
|
RDSRec<RDS_SUPPL_SIG_TIME$> = Time()
|
|
end
|
|
end
|
|
If RDSLayerInstAckReq then RDSRec<RDS_RDS_LAYER_ACK$> = SRP_JSON(hRDS, 'GetValue', 'rdsLayerInstAck')
|
|
If PreInstAckReq then RDSRec<RDS_PRE_INST_ACK$> = SRP_JSON(hRDS, 'GetValue', 'preInstAck')
|
|
If FwiInstAckReq then RDSRec<RDS_FWI_INST_ACK$> = SRP_JSON(hRDS, 'GetValue', 'fwiInstAck')
|
|
If LwiInstAckReq then RDSRec<RDS_LWI_INST_ACK$> = SRP_JSON(hRDS, 'GetValue', 'lwiInstAck')
|
|
If QAInstAckReq then RDSRec<RDS_QA_INST_ACK$> = SRP_JSON(hRDS, 'GetValue', 'qaInstAck')
|
|
If LoadInstAckReq then RDSRec<RDS_LOAD_INST_ACK$> = SRP_JSON(hRDS, 'GetValue', 'loadInstAck')
|
|
If UnloadInstAckReq then RDSRec<RDS_UNLOAD_INST_ACK$> = SRP_JSON(hRDS, 'GetValue', 'unloadInstAck')
|
|
If PostInstAckReq then RDSRec<RDS_POST_INST_ACK$> = SRP_JSON(hRDS, 'GetValue', 'postInstAck')
|
|
If WaferCountInstAckReq then RDSRec<RDS_WAFER_COUNT_ACK$> = SRP_JSON(hRDS, 'GetValue', 'waferCountInstAck')
|
|
|
|
Database_Services('WriteDataRow', 'RDS', RDSNo, RDSRec, True$, False$, True$)
|
|
|
|
SupplInstAckReq = Xlate('RDS', RDSNo, 'SUPPL_ACK_REQ' , 'X')
|
|
RDSLayerInstAckReq = Xlate('RDS', RDSNo, 'RDS_LAYER_ACK_REQ' , 'X')
|
|
PreInstAckReq = Xlate('RDS', RDSNo, 'PRE_INST_ACK_REQ' , 'X')
|
|
FwiInstAckReq = Xlate('RDS', RDSNo, 'FWI_INST_ACK_REQ' , 'X')
|
|
LwiInstAckReq = Xlate('RDS', RDSNo, 'LWI_INST_ACK_REQ' , 'X')
|
|
QAInstAckReq = Xlate('RDS', RDSNo, 'QA_INST_ACK_REQ' , 'X')
|
|
LoadInstAckReq = Xlate('RDS', RDSNo, 'LOAD_INST_ACK_REQ' , 'X')
|
|
UnloadInstAckReq = Xlate('RDS', RDSNo, 'UNLOAD_INST_ACK_REQ' , 'X')
|
|
PostInstAckReq = Xlate('RDS', RDSNo, 'POST_INST_ACK_REQ' , 'X')
|
|
WaferCountInstAckReq = Xlate('RDS', RDSNo, 'WAFER_COUNT_ACK_REQ' , 'X')
|
|
|
|
SRP_JSON(hRDS, 'Release')
|
|
end
|
|
|
|
ToolID = ScansRow<SCANS.TOOL_ID$>
|
|
Reactor = ToolID[-1, 'BR']
|
|
Username = ScansRow<SCANS.EMPLOYEE_ID$>
|
|
WaferCountAck = RDSRec<RDS_WAFER_COUNT_ACK$>
|
|
LLSide = ScansRow<SCANS.LOAD_LOCK$>
|
|
WaferQty = ''
|
|
If WaferCountAck EQ True$ then
|
|
WaferQty = RDSRec<RDS_CASS_WAFER_QTY$>
|
|
end else
|
|
WaferQty = RDSRec<RDS_VERIFY_QTY$>
|
|
end
|
|
// Check signature fields to determine where the lot is in the RDS process. The service should
|
|
// use the signatures in the RDS table, not the WO_MAT table, so that we can support both
|
|
// EpiPro and non-EpiPro lots.
|
|
WONo = RDSRec<RDS_WO$>
|
|
CassNo = RDSRec<RDS_CASS_NO$>
|
|
CurrStatus = obj_WO_Mat('CurrStatus', WONo:'*':CassNo)
|
|
CurrStage = Xlate('RDS', RDSNo, 'CURR_STAGE', 'X')
|
|
|
|
Begin Case
|
|
|
|
Case CurrStage _EQC 'PRE'
|
|
Action = 'LOAD'
|
|
|
|
// Check if both the PRE and LOAD stages are ready to sign
|
|
// If a Pre Clean is required, then the OpenInsight UI must be used for now until support for cleans operations
|
|
// is added to the barcode web application.
|
|
LotNo = RDSRec<RDS_LOT_NUM$>
|
|
PreCleanReq = False$
|
|
CleanInspKeyID = Xlate('RDS', RDSNo, 'PRE_CI_NO', 'X')
|
|
* If CleanInspKeyID NE '' then PreCleanReq = Xlate('CLEAN_INSP', CleanInspKeyID, 'SPEC_CLEAN_REQ', 'X')
|
|
PSN = RDSRec<RDS_PROD_SPEC_ID$>
|
|
PrePRSStageKey = PSN:'*PRE'
|
|
PreCleanReq = Xlate('PRS_STAGE', PrePRSStageKey, 'CLEAN_SIG_REQ', 'X')
|
|
|
|
If ( (PreCleanReq EQ False$) or (PreCleanReq EQ '') ) then
|
|
// The first run on a reactor requires that RDS Layer parameters be entered manually. This is when Prove-in
|
|
// occurs.
|
|
RunOrderNo = Xlate('RDS', RDSNo, 'RUN_ORDER_NUM', 'X')
|
|
If RunOrderNo GT 1 then
|
|
// Wafer is eligible to have recipe parameters automatically applied from the previous cassette.
|
|
// Only copy RDS layer parameters if they do not already exist. This way we do not overwrite
|
|
// manually entered parameters.
|
|
LSParmsComp = Xlate('RDS', RDSNo, 'LS_PARMS_COMP', 'X')
|
|
FirstParmsComp = LSParmsComp<1,1>
|
|
If (FirstParmsComp EQ False$) then RDS_Services('CopyRDSLayerParameters', RDSNo)
|
|
// Supplier lot verification
|
|
ScannedSuppLot = ScansRow<SCANS.SUPPLIER_LOT$>
|
|
RDSSuppLot = RDSRec<RDS_LOT_NUM$>
|
|
If (ScannedSuppLot NE '') then
|
|
If (ScannedSuppLot _EQC RDSSuppLot) then
|
|
WaferCountAckReq = Xlate('RDS', RDSNo, 'WAFER_COUNT_ACK_REQ', 'X')
|
|
If WaferCountAckReq EQ False$ then
|
|
PreStageReady = ''
|
|
LoadStageReady = ''
|
|
PreStageReady = QA_Services('PreEpiSignatureReady', RDSNo, Username, WaferQty, Reactor)
|
|
If PreStageReady EQ True$ then
|
|
LoadStageReady = QA_Services('LoadSignatureReady', RDSNo, Username, WaferQty, LLSide, True$, Reactor)
|
|
ROTRBlock = XLATE('REACTOR', Reactor, 47, 'X')
|
|
ROTRBlockReason = XLATE('REACTOR', Reactor, REACTOR_ROTR_STATUS_REASON$, 'X')
|
|
ROTREnabled = XLATE('REACTOR', Reactor, 49, 'X')
|
|
|
|
If ROTRBlock NE 'P' AND ROTREnabled EQ true$ then
|
|
ScansRow<SCANS.OVERRIDE_REQD$> = 1
|
|
ScansRow<SCANS.OVERRIDE_REASON$> = ROTRBlockReason
|
|
ScansRow<SCANS.OVERRIDE_TYPE$> = 'ROTR'
|
|
Error_Services('Clear')
|
|
Scan_Services('AddNotAcceptableReason', "ROTR Load Block Enabled")
|
|
|
|
end else
|
|
ScansRow<SCANS.OVERRIDE_REQD$> = 0
|
|
ScansRow<SCANS.OVERRIDE_REASON$> = ''
|
|
ScansRow<SCANS.OVERRIDE_TYPE$> = ''
|
|
end
|
|
end
|
|
end else
|
|
Scan_Services('AddNotAcceptableReason', 'The cassette wafer count must be verified against the scheduled wafer count to proceed.')
|
|
end
|
|
end else
|
|
ScansRow<SCANS.SUPPLIER_LOT$> = ''
|
|
Error_Services('Add', '(':CassetteID:') Supplier lot mismatch.')
|
|
end
|
|
end else
|
|
Scan_Services('AddNotAcceptableReason', 'Supplier lot scan required in order to complete a tool scan.')
|
|
end
|
|
|
|
end else
|
|
Error_Services('Add', '(':CassetteID:') The first run must be completed using the OpenInsight user interface.')
|
|
end
|
|
end else
|
|
Error_Services('Add', '(':CassetteID:') A pre-clean is required for this RDS. The OpenInsight user interface must be used to proceed.')
|
|
end
|
|
Case CurrStage _EQC 'LOAD'
|
|
Action = 'LOAD'
|
|
ScannedSuppLot = ScansRow<SCANS.SUPPLIER_LOT$>
|
|
RDSSuppLot = RDSRec<RDS_LOT_NUM$>
|
|
If (ScannedSuppLot NE '') then
|
|
If (ScannedSuppLot _EQC RDSSuppLot) then
|
|
// Scheduled tool verification (only supports reactors at the moment)
|
|
SchedTool = Xlate('RDS', RDSNo, 'SCHED_REACTOR', 'X')
|
|
SchedTool = 'R':SchedTool
|
|
ScanTool = ScansRow<SCANS.TOOL_ID$>
|
|
If SchedTool EQ ScanTool then
|
|
// Check if LOAD stage is ready to sign
|
|
RDSLayerAckReq = Xlate('RDS', RDSNo, 'RDS_LAYER_ACK_REQ', 'X')
|
|
If RDSLayerAckReq EQ False$ then
|
|
If LWIInstAckReq EQ False$ then
|
|
If LoadInstAckReq EQ False$ then
|
|
LoadStageReady = QA_Services('LoadSignatureReady', RDSNo, Username, WaferQty, LLSide)
|
|
|
|
ROTRBlock = XLATE('REACTOR', Reactor, 47, 'X')
|
|
ROTRBlockReason = XLATE('REACTOR', Reactor, REACTOR_ROTR_STATUS_REASON$, 'X')
|
|
ROTREnabled = XLATE('REACTOR', Reactor, 49, 'X')
|
|
|
|
If LoadStageReady EQ False$ AND ROTRBlock NE 'P' AND ROTREnabled EQ true$ then
|
|
ScansRow<SCANS.OVERRIDE_REQD$> = 1
|
|
ScansRow<SCANS.OVERRIDE_TYPE$> = 'ROTR'
|
|
ScansRow<SCANS.OVERRIDE_REASON$> = ROTRBlockReason
|
|
Error_Services('Clear')
|
|
Scan_Services('AddNotAcceptableReason', "ROTR Load Block Enabled")
|
|
|
|
end else
|
|
ScansRow<SCANS.OVERRIDE_REQD$> = 0
|
|
ScansRow<SCANS.OVERRIDE_REASON$> = ''
|
|
ScansRow<SCANS.OVERRIDE_TYPE$> = ''
|
|
end
|
|
end else
|
|
Scan_Services('AddNotAcceptableReason', 'The LOAD stage engineering instructions must be acknowledged before the load operation can be signed.')
|
|
end
|
|
end else
|
|
Scan_Services('AddNotAcceptableReason', 'The LWI stage engineering instructions must be acknowledged before the load operation can be signed.')
|
|
end
|
|
end else
|
|
ErrorMessage = 'RDS layer parameters must be reviewed for accuracy and acknowledged before the load operation can be signed.'
|
|
Scan_Services('AddNotAcceptableReason', ErrorMessage)
|
|
end
|
|
end else
|
|
Error_Services('Add', 'Scanned tool ':ScanTool:' does not match the scheduled tool ':SchedTool:'. (':RDSNo:')')
|
|
end
|
|
end else
|
|
ScansRow<SCANS.SUPPLIER_LOT$> = ''
|
|
Error_Services('Add', '(':CassetteID:') Supplier lot mismatch.')
|
|
end
|
|
end else
|
|
Scan_Services('AddNotAcceptableReason', 'Supplier lot scan required in order to complete a tool scan.')
|
|
end
|
|
|
|
Case CurrStage _EQC 'UNLOAD'
|
|
Action = 'UNLOAD'
|
|
// Check if UNLOAD stage is ready to sign
|
|
If ( (LWIInstAckReq EQ False$) or (LWIInstAckReq EQ '') ) then
|
|
|
|
If ( (UnloadInstAckReq EQ False$) or (UnloadInstAckReq EQ '') ) then
|
|
If ( (PostInstAckReq EQ False$) or (PostInstAckReq EQ '') ) then
|
|
UnloadStageReady = QA_Services('UnloadSignatureReady', RDSNo, Username, Reactor)
|
|
end else
|
|
ScanMsg = 'The POST stage engineering instructions must be acknowledged before the load operation can be signed.'
|
|
Scan_Services('AddNotAcceptableReason', ScanMsg)
|
|
end
|
|
end else
|
|
ScanMsg = 'The UNLOAD stage engineering instructions must be acknowledged before the load operation can be signed.'
|
|
Scan_Services('AddNotAcceptableReason', ScanMsg)
|
|
end
|
|
end else
|
|
ScanMsg = 'The LWI stage engineering instructions must be acknowledged before the load operation can be signed.'
|
|
Scan_Services('AddNotAcceptableReason', ScanMsg)
|
|
end
|
|
Case CurrStage _EQC 'LWIS'
|
|
Action = 'LWIS'
|
|
Error_Services('Add', '(':CassetteID:') The ':CurrStage:' is not currently supported by the barcode application. The OpenInsight user interface must be used in order to proceed.')
|
|
Case CurrStage _EQC 'LWII'
|
|
Action = 'LWII'
|
|
Error_Services('Add', '(':CassetteID:') The ':CurrStage:' is not currently supported by the barcode application. The OpenInsight user interface must be used in order to proceed.')
|
|
Case CurrStage _EQC 'FQA'
|
|
Action = 'FQA'
|
|
Error_Services('Add', '(':CassetteID:') The ':CurrStage:' is not currently supported by the barcode application. The OpenInsight user interface must be used in order to proceed.')
|
|
Case CurrStage _EQC 'COMP'
|
|
Action = 'COMP'
|
|
Error_Services('Add', '(':CassetteID:") Cassette has already been FQA'd.")
|
|
Case Otherwise$
|
|
End Case
|
|
end else
|
|
Scan_Services('AddNotAcceptableReason', 'EmployeeID required to complete a tool scan.')
|
|
end
|
|
end else
|
|
Error_Services('Add', '(':CassetteID:') Process Error: cassette is on Hold and may not be signed off.')
|
|
end
|
|
end
|
|
end else
|
|
Error_Services('Add', '(':CassetteID:') WMI/WMO cassette are not currently supported for tool scans. The OpenInsight user interface must be used in order to proceed.')
|
|
end
|
|
end else
|
|
// Currently we are only supporting loading one cassette onto a tool at a time.
|
|
Error_Services('Add', '(':CassetteID:') Only one cassette can be loaded onto a tool at a time.')
|
|
end
|
|
end else
|
|
Scan_Services('AddNotAcceptableReason', 'A cassette must be scanned in order to complete a tool scan.')
|
|
end
|
|
|
|
Case Otherwise$
|
|
Scan_Services('AddNotAcceptableReason', 'A location ID or tool ID must be scanned to proceed.')
|
|
End Case
|
|
end
|
|
// If the the scan data is valid, update the scan log before returning to the calling process.
|
|
|
|
If Error_Services('NoError') then
|
|
If Scan_Services('NoNotAcceptableReason') then
|
|
ScansRow<SCANS.ACCEPTABLE$> = True$
|
|
ScansRow<SCANS.NOT_ACCEPTABLE_REASON$> = ''
|
|
end else
|
|
ScansRow<SCANS.ACCEPTABLE$> = False$
|
|
ScansRow<SCANS.NOT_ACCEPTABLE_REASON$> = Scan_Services('GetNotAcceptableReason')
|
|
end
|
|
end else
|
|
ScansRow<SCANS.ACCEPTABLE$> = False$
|
|
ScansRow<SCANS.NOT_ACCEPTABLE_REASON$> = Error_Services('GetMessage')
|
|
end
|
|
If ScanData NE '' then
|
|
ScansRow<SCANS.SCANNED_DATES$, -1> = Date()
|
|
ScansRow<SCANS.SCANNED_TIMES$, -1> = Time()
|
|
ScansRow<SCANS.SCANNED_DATA$, -1> = ScanData
|
|
end
|
|
ScansRow<SCANS.ACTION$> = Action
|
|
// Save error message if present as Database_Services will clear any errors.
|
|
ErrorMessage = ''
|
|
If Error_Services('HasError') then
|
|
ErrorMessage = Error_Services('GetMessage')
|
|
end
|
|
Database_Services('WriteDataRow', 'SCANS', ScanID, ScansRow, True$, False$, True$)
|
|
// Restore pre-existing error message if present.
|
|
If ErrorMessage NE '' then Error_Services('Add', ErrorMessage)
|
|
end
|
|
end else
|
|
Error_Services('Add', 'Unable to parse the JSON scan data in the ':Service:' service.')
|
|
end
|
|
SRP_JSON(hScanJSON, 'Release')
|
|
end else
|
|
Error_Services('Add', 'ScanID or ScanJSON argument was missing in the ' : Service : ' service.')
|
|
end
|
|
|
|
end service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// AcceptScan
|
|
//
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service AcceptScan(ScanID, ScanJSON)
|
|
|
|
If ( (ScanID NE '') and (ScanJSON NE '') ) then
|
|
hBody = ''
|
|
ParseResponse = SRP_JSON(hBody, 'PARSE', ScanJSON)
|
|
If ParseResponse EQ '' then
|
|
AcceptedStatus = SRP_JSON(hBody, 'GetValue', 'accepted.status')
|
|
If AcceptedStatus NE '' then
|
|
ScansRow = Scan_Services('GetScansRow', ScanID, False$)
|
|
ScansRow<SCANS.ACCEPTED$> = AcceptedStatus
|
|
Result = ''
|
|
If AcceptedStatus EQ True$ then
|
|
// Scan is acceptable and has been accepted on the web app. Sign stage now if tool scan.
|
|
AcceptedDate = Date()
|
|
AcceptedTime = Time()
|
|
LogDate = OCONV( AcceptedDate, 'D2/' )
|
|
LogTime = OCONV( AcceptedTime, 'MTS' )
|
|
LogDTM = LogDate:' ':LogTime
|
|
ScansRow<SCANS.ACCEPTED_DATE$> = AcceptedDate
|
|
ScansRow<SCANS.ACCEPTED_TIME$> = AcceptedTime
|
|
CassetteIDs = ScansRow<SCANS.CASSETTE_IDS$>
|
|
ScanType = ScansRow<SCANS.SCAN_TYPE$>
|
|
Begin Case
|
|
Case ScanType _EQC 'RESET'
|
|
Scan_Services('ResetDevData', CassetteIDs)
|
|
If Error_Services('NoError') then Result = 'Reset scan complete'
|
|
|
|
Case ScanType _EQC 'TENCOR_LOAD'
|
|
Tencor= ScansRow<SCANS.TOOL_ID$>
|
|
RDSNo= ScansRow<SCANS.CASSETTE_IDS$>
|
|
SendStatus = Keyboard_Sim_Services('SendTencor', Tencor, RDSNo)
|
|
If Error_Services('NoError') AND SendStatus EQ 'Success' then
|
|
Result = 'Tencor Data Sent Successfully'
|
|
end else
|
|
Error_Services('Add', SendStatus)
|
|
end
|
|
|
|
Case ScanType _EQC 'LOCATION'
|
|
|
|
//DPC - 2/10/20 - need to check for existence of 1K*PTI scan before location scan is allowed
|
|
LocID = ScansRow<SCANS.LOCATION_ID$>
|
|
ErrorCassIDs = ''
|
|
WONos = ''
|
|
CassNos = ''
|
|
For each CassetteID in CassetteIDs using @VM setting vPos
|
|
Begin Case
|
|
Case Count(CassetteID, '.') EQ 0
|
|
// RDS Format
|
|
IsEpiPro = RDS_Services('IsEpiPro', CassetteID)
|
|
If IsEpiPro EQ False$ then
|
|
// Non-EpiPro RDS
|
|
WONo = Xlate('RDS', CassetteID, 'WO', 'X')
|
|
CassNo = Xlate('RDS', CassetteID, 'CASS_NO', 'X')
|
|
WOMatKey = WONo:'*':CassNo
|
|
WOMatLocs = Xlate('WO_MAT', WOMatKey, WO_MAT_INV_LOCATION$, 'X')
|
|
If Index(WOMatLocs,'PTI',1) then
|
|
WONos<0, -1> = WONo
|
|
CassNos<0, -1> = CassNo
|
|
end else
|
|
// Cassette has not yet been through passthrough (PTI), so it is not eligible for location scanning.
|
|
// Add it to the invalid cassette list (error list).
|
|
ErrorCassIDs<0, -1> = CassetteID
|
|
end
|
|
end else
|
|
// EpiPro RDS
|
|
OutCassNos = Xlate('RDS', CassetteID, 'OUT_CASS_NO', 'X')
|
|
OutCassNos = SRP_Array('Clean', OutCassNos, 'TrimAndMakeUnique', @VM)
|
|
For each OutCassNo in OutCassNos using @VM setting oPos
|
|
WONo = Xlate('RDS', CassetteID, 'WO', 'X')
|
|
CassNo = OutCassNo
|
|
WOMatKey = WONo:'*':CassNo
|
|
WOMatLocs = Xlate('WO_MAT', WOMatKey, WO_MAT_INV_LOCATION$, 'X')
|
|
If Index(WOMatLocs,'PTI',1) then
|
|
WONos<0, -1> = WONo
|
|
CassNos<0, -1> = CassNo
|
|
end else
|
|
// Cassette has not yet been through passthrough (PTI), so it is not eligible for location scanning.
|
|
// Add it to the invalid cassette list (error list).
|
|
ErrorCassIDs<0, -1> = CassetteID
|
|
end
|
|
Next OutCassNo
|
|
end
|
|
Case DCount(CassetteID, '.') EQ 3
|
|
// WM_IN / WM_OUT Format
|
|
WONo = Field(CassetteID, '.', 1, 1)
|
|
CassNo = Field(CassetteID, '.', 3, 1)
|
|
WOMatKey = WONo:'*':CassNo
|
|
WOMatLocs = Xlate('WO_MAT', WOMatKey, WO_MAT_INV_LOCATION$, 'X')
|
|
If Index(WOMatLocs,'PTI',1) then
|
|
WONos<0, -1> = WONo
|
|
CassNos<0, -1> = CassNo
|
|
end else
|
|
// Cassette has not yet been through passthrough (PTI), so it is not eligible for location scanning.
|
|
// Add it to the invalid cassette list (error list).
|
|
ErrorCassIDs<0, -1> = CassetteID
|
|
end
|
|
Case Otherwise$
|
|
// Unsupported format
|
|
Null
|
|
End Case
|
|
|
|
Next CassetteID
|
|
|
|
For each CassetteID in ErrorCassIDs using @VM
|
|
// Remove erroneous cassettes from the valid cassette list
|
|
Locate CassetteID in CassetteIDs using @VM setting vPos then
|
|
CassetteIDs = Delete(CassetteIDS, 0, vPos, 0)
|
|
end
|
|
Next CassetteID
|
|
|
|
If ( (WONos NE '') and (CassNos NE '') ) then
|
|
// Move the cassettes (i.e. log their movement in the material log)
|
|
LogFile = 'WO_MAT'
|
|
LogDTM = LogDate:' ':LogTime
|
|
Action = 'PLACE'
|
|
WhCd = Field(LocID, '.', 1, 1)
|
|
LocCd = Field(LocID, '.', 2, 1)
|
|
UserID = ScansRow<SCANS.EMPLOYEE_ID$>
|
|
Tags = ''
|
|
ToolID = ''
|
|
ScanEntry = 1
|
|
|
|
WOMLParms = LogFile:@RM
|
|
WOMLParms := LogDTM:@RM
|
|
WOMLParms := Action:@RM
|
|
WOMLParms := WhCd:@RM
|
|
WOMLParms := LocCd:@RM
|
|
WOMLParms := WONos:@RM
|
|
WOMLParms := CassNos:@RM
|
|
WOMLParms := UserID:@RM
|
|
WOMLParms := Tags:@RM
|
|
WOMLParms := ToolID:@RM
|
|
WOMLParms := ScanEntry
|
|
|
|
obj_WO_Mat_Log('Create',WOMLParms)
|
|
errCode = ''
|
|
end
|
|
|
|
IF Get_Status(errCode) THEN
|
|
ErrorMsg = 'Error calling obj_WO_Mat_Log("Create"). Error code: ':errCode
|
|
Error_Services('Add', ErrorMsg)
|
|
END else
|
|
NumCass = DCount(CassetteIDs, @VM)
|
|
If NumCass EQ 1 then
|
|
CassetteID = CassetteIDs<0, 1>
|
|
Result = '(':CassetteID:') Location scan complete. '
|
|
end else
|
|
Result = '(Multi) Location scan complete. '
|
|
end
|
|
If ErrorCassIDs NE '' then
|
|
Convert @VM to ',' in ErrorCassIDs
|
|
Result := 'Cassette(s) ':ErrorCassIDs:' failed due to missing PTI.'
|
|
end
|
|
end
|
|
|
|
|
|
Case ScanType _EQC 'TOOL'
|
|
// Check if cassette field is populated. If so, then check the cassette's current status to
|
|
// determine what the next action will be (i.e. Pre-Epi+Load, Unload, etc.)
|
|
CassetteID = CassetteIDs<0, 1>
|
|
RDSNo = CassetteID
|
|
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo)
|
|
ToolID = ScansRow<SCANS.TOOL_ID$>
|
|
Reactor = ToolID[-1, 'BR']
|
|
Username = ScansRow<SCANS.EMPLOYEE_ID$>
|
|
LLSide = ScansRow<SCANS.LOAD_LOCK$>
|
|
WaferQty = RDSRec<RDS_CASS_WAFER_QTY$>
|
|
// Check signature fields to determine where the lot is in the RDS process. The service should
|
|
// use the signatures in the RDS table, not the WO_MAT table, so that we can support both
|
|
// EpiPro and non-EpiPro lots.
|
|
CurrStage = Xlate('RDS', RDSNo, 'CURR_STAGE', 'X')
|
|
CurrDTM = Datetime()
|
|
LogData = ''
|
|
LogData<1> = OConv(CurrDTM, 'DT')
|
|
LogData<2> = RDSNo
|
|
LogData<3> = Username
|
|
LogData<4> = CurrStage
|
|
LogData<5> = ScanID
|
|
Begin Case
|
|
Case CurrStage _EQC 'PRE'
|
|
Action = 'LOAD'
|
|
// Check if both the PRE and LOAD stages are ready to sign
|
|
PreStageSigned = False$
|
|
LoadStageSigned = False$
|
|
PreStageSigned = QA_Services('SignPreEpiStage', RDSNo, Username, WaferQty, Reactor, 1)
|
|
If PreStageSigned EQ True$ then
|
|
LoadStageSigned = QA_Services('SignLoadStage', RDSNo, USername, WaferQty, LLSide, 1)
|
|
end
|
|
If ( (PreStageSigned EQ True$) and (LoadStageSigned EQ True$) ) then
|
|
Result = '(':CassetteID:') Load stage signed.'
|
|
end
|
|
LogData<6> = Action
|
|
LogData<7> = Result
|
|
Logging_Services('AppendLog', objLog, LogData, @RM, @FM)
|
|
Case CurrStage _EQC 'LOAD'
|
|
Action = 'LOAD'
|
|
// Check if LOAD stage is ready to sign
|
|
LoadStageSigned = QA_Services('SignLoadStage', RDSNo, Username, WaferQty, LLSide, 1)
|
|
If LoadStageSigned EQ True$ then
|
|
Result = '(':CassetteID:') Load stage signed.'
|
|
end
|
|
LogData<6> = Action
|
|
LogData<7> = Result
|
|
Logging_Services('AppendLog', objLog, LogData, @RM, @FM)
|
|
Case CurrStage _EQC 'UNLOAD'
|
|
Action = 'UNLOAD'
|
|
// Check if UNLOAD stage is ready to sign
|
|
UnloadStageSigned = QA_Services('SignUnloadStage', RDSNo, Username, 1)
|
|
If UnloadStageSigned EQ True$ then
|
|
Result = '(':CassetteID:') Unload stage signed.'
|
|
end
|
|
LogData<6> = Action
|
|
LogData<7> = Result
|
|
Logging_Services('AppendLog', objLog, LogData, @RM, @FM)
|
|
Case CurrStage _EQC 'LWIS'
|
|
Action = 'LWIS'
|
|
Error_Services('Set', '(':CassetteID:') The ':CurrStage:' is not currently supported by the barcode application.')
|
|
Case CurrStage _EQC 'LWII'
|
|
Action = 'LWII'
|
|
Error_Services('Set', '(':CassetteID:') The ':CurrStage:' is not currently supported by the barcode application.')
|
|
Case CurrStage _EQC 'FQA'
|
|
Action = 'FQA'
|
|
Error_Services('Set', '(':CassetteID:') The ':CurrStage:' is not currently supported by the barcode application.')
|
|
Case CurrStage _EQC 'COMP'
|
|
Action = 'COMP'
|
|
Error_Services('Set', '(':CassetteID:") Cassette has already been FQA'd.")
|
|
Case Otherwise$
|
|
End Case
|
|
End Case
|
|
end
|
|
|
|
If Error_Services('NoError') then
|
|
ScansRow<SCANS.NOT_ACCEPTABLE_REASON$> = 'This scan has already been accepted.'
|
|
end else
|
|
ScansRow<SCANS.NOT_ACCEPTABLE_REASON$> = Error_Services('GetMessage')
|
|
end
|
|
ScansRow<SCANS.ACCEPTABLE$> = False$
|
|
If Assigned(Result) then ScansRow<SCANS.RESULT$> = Result
|
|
// Save error message if present as Database_Services will clear any errors.
|
|
ErrorMessage = ''
|
|
If Error_Services('HasError') then
|
|
ErrorMessage = Error_Services('GetMessage')
|
|
end
|
|
Scan_Services('SetScansRow', ScanID, ScansRow)
|
|
// Restore pre-existing error message if present.
|
|
If ErrorMessage NE '' then Error_Services('Add', ErrorMessage)
|
|
end else
|
|
Error_Services('Add', 'The accepted.status field is missing from the JSON object in the ':Service:' service.')
|
|
end
|
|
SRP_JSON(hBody, 'Release')
|
|
end else
|
|
Error_Services('Add', 'Unable to parse the JSON scan resource in the ':Service:' service.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'ScanID or ScanJSON argument was missing in the ' : Service : ' service.')
|
|
end
|
|
|
|
end service
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// ConvertMVScanToJSON
|
|
//
|
|
// Converts a MultiValue formatted SCANS row into a serialized JSON object and returns the result. If the mvScan
|
|
// argument is empty, the service will attempt to get it from the SCANS table. If the itemURL argument is not empty,
|
|
// HAL+JSON properties will be added to the JSON object.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service ConvertMVScanToJSON(ScanID, mvScan, itemURL)
|
|
|
|
jsonScan = ''
|
|
|
|
If ScanID NE '' then
|
|
|
|
If mvScan EQ '' then mvScan = Database_Services('ReadDataRow', 'SCANS', ScanID)
|
|
If Error_Services('NoError') then
|
|
@DICT = Database_Services('GetTableHandle', 'DICT.SCANS')
|
|
@ID = ScanID
|
|
@RECORD = mvScan
|
|
objJSONScan = ''
|
|
If SRP_JSON(objJSONScan, 'New', 'Object') then
|
|
// Scan object.
|
|
If SRP_JSON(objScan, 'New', 'Object') then
|
|
SRP_JSON(objScan, 'SetValue', 'ID', @ID, 'String')
|
|
SRP_JSON(objScan, 'SetValue', 'type', {SCAN_TYPE}, 'String')
|
|
SRP_JSON(objScan, 'SetValue', 'action', {ACTION}, 'String')
|
|
SRP_JSON(objScan, 'SetValue', 'acceptable', {ACCEPTABLE}, 'Boolean')
|
|
SRP_JSON(objScan, 'SetValue', 'notAcceptableReason', {NOT_ACCEPTABLE_REASON}, 'String')
|
|
SRP_JSON(objScan, 'SetValue', 'result', {RESULT}, 'String')
|
|
If SRP_JSON(arrayScanLog, 'New', 'Array') then
|
|
If {SCANNED_DATES} NE '' then
|
|
ScannedDates = {SCANNED_DATES}
|
|
For Each ScannedDate in scannedDates using @VM setting vPos
|
|
objScanSession = ''
|
|
If SRP_JSON(objScanSession, 'New', 'Object') then
|
|
SRP_JSON(objScanSession, 'SetValue', 'date', Oconv({SCANNED_DATES}<0, vPos>, 'D4/'), 'String')
|
|
SRP_JSON(objScanSession, 'SetValue', 'time', Oconv({SCANNED_TIMES}<0, vPos>, 'MTH'), 'String')
|
|
SRP_JSON(objScanSession, 'SetValue', 'data', {SCANNED_DATA}<0, vPos>, 'String')
|
|
SRP_JSON(arrayScanLog, 'Add', objScanSession)
|
|
SRP_JSON(objScanSession, 'Release')
|
|
end
|
|
Next ScannedDate
|
|
end
|
|
SRP_JSON(objScan, 'Set', 'scanLog', arrayScanLog)
|
|
SRP_JSON(arrayScanLog, 'Release')
|
|
end
|
|
|
|
SRP_JSON(objJSONScan, 'Set', 'scan', objScan)
|
|
SRP_JSON(objScan, 'Release')
|
|
end
|
|
// Supplier Lot object.
|
|
objSupplierLot = ''
|
|
If SRP_JSON(objSupplierLot, 'New', 'Object') then
|
|
SRP_JSON(objSupplierLot, 'SetValue', 'ID', {SUPPLIER_LOT}, 'String')
|
|
SRP_JSON(objJSONScan, 'Set', 'supplierLot', objSupplierLot)
|
|
SRP_JSON(objSupplierLot, 'Release')
|
|
end
|
|
// Created object.
|
|
objCreated = ''
|
|
If SRP_JSON(objCreated, 'New', 'Object') then
|
|
SRP_JSON(objCreated, 'SetValue', 'date', Oconv({CREATED_DATE}, 'D4/'), 'String')
|
|
SRP_JSON(objCreated, 'SetValue', 'time', Oconv({CREATED_TIME}, 'MTH'), 'String')
|
|
SRP_JSON(objJSONScan, 'Set', 'created', objCreated)
|
|
SRP_JSON(objCreated, 'Release')
|
|
end
|
|
// Employee object
|
|
objEmployee = ''
|
|
If SRP_JSON(objEmployee, 'New', 'Object') then
|
|
|
|
SRP_JSON(objEmployee, 'SetValue', 'ID', {EMPLOYEE_ID}, 'String')
|
|
SRP_JSON(objEmployee, 'SetValue', 'name', {EMPLOYEE_NAME}, 'String')
|
|
SRP_JSON(objEmployee, 'SetValue', 'authorized', {EMPLOYEE_AUTHORIZED}, 'Boolean')
|
|
SRP_JSON(objEmployee, 'SetValue', 'notAuthorizedReason', {EMPLOYEE_NOT_AUTHORIZED_REASON}, 'String')
|
|
SRP_JSON(objEmployee, 'SetValue', 'authenticated' , @Record<SCANS.AUTHENTICATED$> , 'Boolean');//JRO Change
|
|
SRP_JSON(objJSONScan, 'Set', 'employee', objEmployee)
|
|
SRP_JSON(objEmployee, 'Release')
|
|
|
|
end
|
|
// Cassettes object.
|
|
arrayCassetteIDs = ''
|
|
If SRP_JSON(arrayCassetteIDs, 'New', 'Array') then
|
|
If {CASSETTE_IDS} NE '' then
|
|
CassetteIDs = {CASSETTE_IDS}
|
|
For Each CassetteID in CassetteIDs using @VM
|
|
SRP_JSON(arrayCassetteIDs, 'AddValue', CassetteID, 'String')
|
|
Next CassetteID
|
|
end
|
|
SRP_JSON(objJSONScan, 'Set', 'cassetteIDs', arrayCassetteIDs)
|
|
SRP_JSON(arrayCassetteIDs, 'Release')
|
|
end
|
|
// Location object.
|
|
objLocation = ''
|
|
If SRP_JSON(objLocation, 'New', 'Object') then
|
|
SRP_JSON(objLocation, 'SetValue', 'ID', {LOCATION_ID}, 'String')
|
|
SRP_JSON(objLocation, 'SetValue', 'name', {LOCATION_NAME}, 'String')
|
|
SRP_JSON(objJSONScan, 'Set', 'location', objLocation)
|
|
SRP_JSON(objLocation, 'Release')
|
|
end
|
|
// Tool object.
|
|
objTool = ''
|
|
If SRP_JSON(objTool, 'New', 'Object') then
|
|
SRP_JSON(objTool, 'SetValue', 'ID', {TOOL_ID}, 'String')
|
|
SRP_JSON(objTool, 'SetValue', 'name', {TOOL_NAME}, 'String')
|
|
SRP_JSON(objTool, 'SetValue', 'loadLock', {LOAD_LOCK}, 'String')
|
|
SRP_JSON(objJSONScan, 'Set', 'tool', objTool)
|
|
SRP_JSON(objTool, 'Release')
|
|
end
|
|
// Accepted object.
|
|
objAccepted = ''
|
|
If SRP_JSON(objAccepted, 'New', 'Object') then
|
|
SRP_JSON(objAccepted, 'SetValue', 'status', {ACCEPTED}, 'Boolean')
|
|
SRP_JSON(objAccepted, 'SetValue', 'date', Oconv({ACCEPTED_DATE}, 'D4/'), 'String')
|
|
SRP_JSON(objAccepted, 'SetValue', 'time', Oconv({ACCEPTED_TIME}, 'MTH'), 'String')
|
|
SRP_JSON(objEmployee, 'SetValue', 'notAcceptedReason', {NOT_ACCEPTABLE_REASON}, 'String')
|
|
SRP_JSON(objJSONScan, 'Set', 'accepted', objAccepted)
|
|
SRP_JSON(objAccepted, 'Release')
|
|
end
|
|
// Wafer Count object.
|
|
objWaferCount = ''
|
|
If SRP_JSON(objWaferCount, 'New', 'Object') then
|
|
SRP_JSON(objWaferCount, 'SetValue', 'scheduler', {SCHEDULER_WAFER_COUNT}, 'Number')
|
|
SRP_JSON(objWaferCount, 'SetValue', 'confirmed', {WAFER_COUNT_CONFIRMED}, 'Boolean')
|
|
SRP_JSON(objJSONScan, 'Set', 'waferCount', objWaferCount)
|
|
SRP_JSON(objWaferCount, 'Release')
|
|
end
|
|
// Transfer object.
|
|
objTransfer = ''
|
|
If SRP_JSON(objTransfer, 'New', 'Object') then
|
|
// Transfer Tool sub-object.
|
|
objTool = ''
|
|
If SRP_JSON(objTool, 'New', 'Object') then
|
|
SRP_JSON(objTool, 'SetValue', 'ID', {TRANSFER_TOOL_ID}, 'String')
|
|
SRP_JSON(objTool, 'SetValue', 'name', {TRANSFER_TOOL_NAME}, 'String')
|
|
SRP_JSON(objTransfer, 'Set', 'tool', objTool)
|
|
SRP_JSON(objTool, 'Release')
|
|
end
|
|
SRP_JSON(objTransfer, 'SetValue', 'boatID', {BOAT_ID}, 'String')
|
|
SRP_JSON(objTransfer, 'SetValue', 'plNumber', {PL_NUMBER}, 'String')
|
|
SRP_JSON(objTransfer, 'SetValue', 'unloadplConfirmed', {UNLOAD_PL_CONFIRMED}, 'Boolean')
|
|
SRP_JSON(objJSONScan, 'Set', 'transfer', objTransfer)
|
|
SRP_JSON(objTransfer, 'Release')
|
|
end
|
|
SRP_JSON(objJSONScan, 'SetValue', 'lastModified', {LAST_MODIFIED}, 'String')
|
|
|
|
If {SCAN_TYPE} EQ 'TOOL' then
|
|
CassIDs = {CASSETTE_IDS}
|
|
RDSNo = CassIDs<0, 1>
|
|
CurrStage = Xlate('RDS', RDSNo, 'CURR_STAGE', 'X')
|
|
If ( ({EMPLOYEE_ID} NE '') and ({TOOL_ID} NE '') and ({SUPPLIER_LOT} NE '') and ({CASSETTE_IDS} NE '') and ( (CurrStage EQ 'LOAD') or (CurrStage EQ 'PRE') ) ) |
|
|
or ( ({EMPLOYEE_ID} NE '') and ({TOOL_ID} NE '') and ({CASSETTE_IDS} NE '') and (CurrStage EQ 'UNLOAD') ) then
|
|
// RDS object
|
|
objRDS = ''
|
|
If SRP_JSON(objRDS, 'New', 'Object') then
|
|
|
|
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSNo)
|
|
|
|
SupplInstAckReq = Xlate('RDS', RDSNo, 'SUPPL_ACK_REQ' , 'X')
|
|
RDSLayerInstAckReq = Xlate('RDS', RDSNo, 'RDS_LAYER_ACK_REQ' , 'X')
|
|
RDSLayerIDs = Xlate('RDS', RDSNo, 'RDS_LS_ID' , 'X')
|
|
PreInstAckReq = Xlate('RDS', RDSNo, 'PRE_INST_ACK_REQ' , 'X')
|
|
PreInst = Xlate('RDS', RDSNo, 'PRE_INST' , 'X')
|
|
FwiInstAckReq = Xlate('RDS', RDSNo, 'FWI_INST_ACK_REQ' , 'X')
|
|
FwiInst = Xlate('RDS', RDSNo, 'FWI_INST' , 'X')
|
|
LwiInstAckReq = Xlate('RDS', RDSNo, 'LWI_INST_ACK_REQ' , 'X')
|
|
LwiInst = Xlate('RDS', RDSNo, 'LWI_INST' , 'X')
|
|
QAInstAckReq = Xlate('RDS', RDSNo, 'QA_INST_ACK_REQ' , 'X')
|
|
QAInst = Xlate('RDS', RDSNo, 'QA_INST' , 'X')
|
|
LoadInstAckReq = Xlate('RDS', RDSNo, 'LOAD_INST_ACK_REQ' , 'X')
|
|
LoadInst = Xlate('RDS', RDSNo, 'LOAD_INST' , 'X')
|
|
UnloadInstAckReq = Xlate('RDS', RDSNo, 'UNLOAD_INST_ACK_REQ' , 'X')
|
|
UnloadInst = Xlate('RDS', RDSNo, 'UNLOAD_INST' , 'X')
|
|
PostInstAckReq = Xlate('RDS', RDSNo, 'POST_INST_ACK_REQ' , 'X')
|
|
PostInst = Xlate('RDS', RDSNo, 'POST_INST' , 'X')
|
|
WaferCountInstAckReq = Xlate('RDS', RDSNo, 'WAFER_COUNT_ACK_REQ' , 'X')
|
|
WaferCountInst = 'Please verify the wafer quantity in the cassette matches the ' |
|
|
: 'scheduled wafer quantity, ':{SCHEDULER_WAFER_COUNT}:'.'
|
|
|
|
SRP_JSON(objRDS, 'SetValue', 'supplInstAckReq' , SupplInstAckReq , 'Boolean')
|
|
SRP_JSON(objRDS, 'SetValue', 'supplInstAck' , RDSRec<RDS_SUPPL_ACK$> , 'Boolean')
|
|
SRP_JSON(objRDS, 'SetValue', 'supplInst' , RDSRec<RDS_SUPPL_INST$> , 'String')
|
|
SRP_JSON(objRDS, 'SetValue', 'preInstAckReq' , PreInstAckReq , 'Boolean')
|
|
SRP_JSON(objRDS, 'SetValue', 'preInstAck' , RDSRec<RDS_PRE_INST_ACK$> , 'Boolean')
|
|
SRP_JSON(objRDS, 'SetValue', 'preInst' , PreInst , 'String')
|
|
SRP_JSON(objRDS, 'SetValue', 'fwiInstAckReq' , FwiInstAckReq , 'Boolean')
|
|
SRP_JSON(objRDS, 'SetValue', 'fwiInstAck' , RDSRec<RDS_FWI_INST_ACK$> , 'Boolean')
|
|
SRP_JSON(objRDS, 'SetValue', 'fwiInst' , FwiInst , 'String')
|
|
SRP_JSON(objRDS, 'SetValue', 'lwiInstAckReq' , LwiInstAckReq , 'Boolean')
|
|
SRP_JSON(objRDS, 'SetValue', 'lwiInstAck' , RDSRec<RDS_LWI_INST_ACK$> , 'Boolean')
|
|
SRP_JSON(objRDS, 'SetValue', 'lwiInst' , LwiInst , 'String')
|
|
SRP_JSON(objRDS, 'SetValue', 'qaInstAckReq' , QAInstAckReq , 'Boolean')
|
|
SRP_JSON(objRDS, 'SetValue', 'qaInstAck' , RDSRec<RDS_QA_INST_ACK$> , 'Boolean')
|
|
SRP_JSON(objRDS, 'SetValue', 'qaInst' , QAInst , 'String')
|
|
SRP_JSON(objRDS, 'SetValue', 'loadInstAckReq' , LoadInstAckReq , 'Boolean')
|
|
SRP_JSON(objRDS, 'SetValue', 'loadInstAck' , RDSRec<RDS_LOAD_INST_ACK$> , 'Boolean')
|
|
SRP_JSON(objRDS, 'SetValue', 'loadInst' , LoadInst , 'String')
|
|
SRP_JSON(objRDS, 'SetValue', 'unloadInstAckReq' , UnloadInstAckReq , 'Boolean')
|
|
SRP_JSON(objRDS, 'SetValue', 'unloadInstAck' , RDSRec<RDS_UNLOAD_INST_ACK$> , 'Boolean')
|
|
SRP_JSON(objRDS, 'SetValue', 'unloadInst' , UnloadInst , 'String')
|
|
SRP_JSON(objRDS, 'SetValue', 'postInstAckReq' , PostInstAckReq , 'Boolean')
|
|
SRP_JSON(objRDS, 'SetValue', 'postInstAck' , RDSRec<RDS_POST_INST_ACK$> , 'Boolean')
|
|
SRP_JSON(objRDS, 'SetValue', 'postInst' , PostInst , 'String')
|
|
SRP_JSON(objRDS, 'SetValue', 'waferCountInstAckReq' , WaferCountInstAckReq , 'Boolean')
|
|
SRP_JSON(objRDS, 'SetValue', 'waferCountInstAck' , RDSRec<RDS_WAFER_COUNT_ACK$> , 'Boolean')
|
|
SRP_JSON(objRDS, 'SetValue', 'waferCountInst' , WaferCountInst , 'String')
|
|
SRP_JSON(objRDS, 'SetValue', 'rdsLayerInstAckReq' , RDSLayerInstAckReq , 'Boolean')
|
|
SRP_JSON(objRDS, 'SetValue', 'rdsLayerInstAck' , RDSRec<RDS_RDS_LAYER_ACK$> , 'Boolean')
|
|
|
|
OverrideRequired = @Record<SCANS.OVERRIDE_REQD$>
|
|
OverrideType = @Record<SCANS.OVERRIDE_TYPE$>
|
|
OverrideReason = @Record<SCANS.OVERRIDE_REASON$>
|
|
SRP_JSON(objRDS, 'SetValue', 'overRideAckReq' , OverrideRequired , 'Boolean')
|
|
SRP_JSON(objRDS, 'SetValue', 'overRideType' , OverrideType , 'string')
|
|
SRP_JSON(objRDS, 'SetValue', 'overRideReason', @Record<SCANS.OVERRIDE_REASON$>, 'string')
|
|
If ((OverrideRequired EQ True$) and (OverrideType EQ 'ROTR')) then
|
|
Swap " " with "" in OverrideReason
|
|
OverrideComments = Xlate("ROTR_OVERRIDE_COMMENT_OPTIONS", OverrideReason, ROTR_OVERRIDE_COMMENT_OPTIONS_COMMENT_OPTIONS$, 'X')
|
|
SRP_JSON(objRds, "SetValueArray", "overRideComments", OverrideComments, @VM)
|
|
|
|
Reactor = {TOOL_ID}[2,999]
|
|
rotrOverrideCount = Xlate('REACTOR', Reactor, REACTOR_ROTR_OVERRIDE_COUNT$, 'X')
|
|
if rotrOverrideCount EQ '' then rotrOverrideCount = 0
|
|
SRP_JSON(objRds, "SetValue", "rotrOverrideCount", rotrOverrideCount, 'Number')
|
|
end
|
|
arrayRDSLayers = ''
|
|
// Add RDSLayers (recipe parameters) array
|
|
If SRP_JSON(arrayRDSLayers, 'New', 'Array') then
|
|
For each RDSLayerID in RDSLayerIDs using @VM setting vPos
|
|
arrayParameters = ''
|
|
If SRP_JSON(arrayParameters, 'New', 'Array') then
|
|
RDSLayerKey = RDSNo:'*':RDSLayerID
|
|
ColNames = 'LS_ID,RECIPE_NO,RECIPE_NAME,DOPANT,EPI_DILUENT,EPI_TIME,' |
|
|
: 'DILUENT_ADJ_PARAM,DOPANT_FLOW,HCL_FLOW,BAKE_TIME,EPI_H2_FLOW,' |
|
|
: 'TCS_FLOW,DCS_FLOW,AUX1,AUX2,F_OFFSET,S_OFFSET,R_OFFSET,' |
|
|
: 'SUSC_ETCH,ETCH1,ETCH2,ETCH3,UL_TEMP'
|
|
ParamList = 'Layer ID,Recipe,Recipe Name,Dopant,Epi Diluent,Deposit,' |
|
|
: 'Diluent,Dopant Flow,HCL Flow,Bake Time,H2 Flow,TCS Flow,' |
|
|
: 'DCS Flow,Aux 1 Flow,Aux 2 flow,F Offset,S Offset,R Offset,' |
|
|
: 'Susc Etch,Etch 1,Etch 2,Etch 3,Unload Temp'
|
|
pos = ''
|
|
For each Parameter in ParamList using ',' setting pos
|
|
ColName = Field(ColNames, ',', pos)
|
|
ParamData = Xlate('RDS_LAYER', RDSLayerKey, ColName, 'X')
|
|
Conversion = Xlate('DICT.RDS_LAYER', ColName, DICT_CONV$, 'X')
|
|
If ParamData NE '' then
|
|
If Conversion NE '' then ParamData = OConv(ParamData, Conversion)
|
|
objParameter = ''
|
|
If SRP_JSON(objParameter, 'New', 'Object') then
|
|
Success = SRP_JSON(objParameter, 'SetValue', 'Parameter', Parameter)
|
|
Success = SRP_JSON(objParameter, 'SetValue', 'Value', ParamData)
|
|
// Add parameter object to parameter array
|
|
Success = SRP_JSON(arrayParameters, 'Add', objParameter)
|
|
SRP_JSON(objParameter, 'Release')
|
|
end
|
|
end
|
|
Next Value
|
|
end
|
|
// Add parameter array to RDS Layer array
|
|
Success = SRP_JSON(arrayRDSLayers, 'Add', arrayParameters)
|
|
SRP_JSON(arrayParameters, 'Release')
|
|
Next RDSLayerID
|
|
Success = SRP_JSON(objRDS, 'Set', 'rdsLayers', arrayRDSLayers)
|
|
SRP_JSON(arrayRDSLayers, 'Release')
|
|
end
|
|
|
|
SRP_JSON(objJSONScan, 'Set', 'rds', objRDS)
|
|
SRP_JSON(objRDS, 'Release')
|
|
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(objJSONScan, 'Set', '_links', objLinks)
|
|
SRP_JSON(objLinks, 'Release')
|
|
end
|
|
objForm = ''
|
|
// Create the _form property to help UIs determine what to display.
|
|
If SRP_JSON(objForm, 'New', 'Object') then
|
|
arrayFields = ''
|
|
If SRP_JSON(arrayFields, 'New', 'Array') then
|
|
If {EMPLOYEE_ID} NE '' then
|
|
objField = ''
|
|
If SRP_JSON(objField, 'New', 'Object') then
|
|
SRP_JSON(objField, 'SetValue', 'label', 'Employee', 'String')
|
|
SRP_JSON(objField, 'SetValue', 'value', {EMPLOYEE_NAME}, 'String')
|
|
SRP_JSON(arrayFields, 'Add', objField)
|
|
SRP_JSON(objField, 'Release')
|
|
end
|
|
end
|
|
If {LOCATION_ID} NE '' then
|
|
If SRP_JSON(objField, 'New', 'Object') then
|
|
SRP_JSON(objField, 'SetValue', 'label', 'Location', 'String')
|
|
SRP_JSON(objField, 'SetValue', 'value', {LOCATION_NAME}, 'String')
|
|
SRP_JSON(arrayFields, 'Add', objField)
|
|
SRP_JSON(objField, 'Release')
|
|
end
|
|
end
|
|
If {TOOL_ID} NE '' then
|
|
If SRP_JSON(objField, 'New', 'Object') then
|
|
SRP_JSON(objField, 'SetValue', 'label', 'Tool', 'String')
|
|
ToolName = {TOOL_NAME}
|
|
If {LOAD_LOCK} NE '' then ToolName := ' ( ' : {LOAD_LOCK} : ' )'
|
|
SRP_JSON(objField, 'SetValue', 'value', ToolName, 'String')
|
|
SRP_JSON(arrayFields, 'Add', objField)
|
|
SRP_JSON(objField, 'Release')
|
|
end
|
|
* If {LOAD_LOCK} NE '' then
|
|
* If SRP_JSON(objField, 'New', 'Object') then
|
|
* SRP_JSON(objField, 'SetValue', 'label', 'Load Lock', 'String')
|
|
* SRP_JSON(objField, 'SetValue', 'value', {LOAD_LOCK}, 'String')
|
|
* SRP_JSON(arrayFields, 'Add', objField)
|
|
* SRP_JSON(objField, 'Release')
|
|
* end
|
|
* end
|
|
end
|
|
If {TRANSFER_TOOL_ID} NE '' then
|
|
If SRP_JSON(objField, 'New', 'Object') then
|
|
SRP_JSON(objField, 'SetValue', 'label', 'Transfer', 'String')
|
|
SRP_JSON(objField, 'SetValue', 'value', {TRANSFER_TOOL_NAME}, 'String')
|
|
SRP_JSON(arrayFields, 'Add', objField)
|
|
SRP_JSON(objField, 'Release')
|
|
end
|
|
end
|
|
If {CASSETTE_IDS} NE '' then
|
|
If SRP_JSON(objField, 'New', 'Object') then
|
|
SRP_JSON(objField, 'SetValue', 'label', 'Cassette ID', 'String')
|
|
If SRP_JSON(arrayCassetteIDs, 'New', 'Array') then
|
|
For Each CassetteID in CassetteIDs using @VM
|
|
SRP_JSON(arrayCassetteIDs, 'AddValue', CassetteID, 'String')
|
|
Next CassetteID
|
|
SRP_JSON(objField, 'Set', 'values', arrayCassetteIDs)
|
|
SRP_JSON(arrayCassetteIDs, 'Release')
|
|
end
|
|
SRP_JSON(arrayFields, 'Add', objField)
|
|
SRP_JSON(objField, 'Release')
|
|
end
|
|
end
|
|
SRP_JSON(objForm, 'Set', 'fields', arrayFields)
|
|
SRP_JSON(arrayFields, 'Release')
|
|
end
|
|
SRP_JSON(objJSONScan, 'Set', '_form', objForm)
|
|
SRP_JSON(objForm, 'Release')
|
|
end
|
|
// Create the _class property for this resource.
|
|
SRP_JSON(objJSONScan, 'SetValue', '_class', 'resource')
|
|
end
|
|
jsonScan = SRP_JSON(objJSONScan, 'Stringify', 'Styled')
|
|
SRP_JSON(objJSONScan, 'Release')
|
|
end else
|
|
Error_Services('Add', 'Unable to create JSON representation in the ' : Service : ' service.')
|
|
end
|
|
end
|
|
end else
|
|
Error_Services('Add', 'ScanID argument was missing in the ' : Service : ' service.')
|
|
end
|
|
|
|
Response = jsonScan
|
|
|
|
end service
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// ConvertJSONScanToMV
|
|
//
|
|
// Converts a serialized JSON scan object into a MultiValue formatted SCANS row and returns the result.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service ConvertJSONScanToMV(jsonScan)
|
|
|
|
mvScan = ''
|
|
|
|
If jsonScan NE '' then
|
|
If SRP_JSON(objJSONScan, 'Parse', jsonScan) EQ '' then
|
|
|
|
mvScan<SCANS.CREATED_DATE$> = SRP_JSON(objJSONScan, 'GetValue', 'created.date')
|
|
mvScan<SCANS.CREATED_TIME$> = SRP_JSON(objJSONScan, 'GetValue', 'created.time')
|
|
mvScan<SCANS.SCAN_TYPE$> = SRP_JSON(objJSONScan, 'GetValue', 'scan.type')
|
|
mvScan<SCANS.EMPLOYEE_ID$> = SRP_JSON(objJSONScan, 'GetValue', 'employee.ID')
|
|
mvScan<SCANS.LOCATION_ID$> = SRP_JSON(objJSONScan, 'GetValue', 'location.ID')
|
|
mvScan<SCANS.TOOL_ID$> = SRP_JSON(objJSONScan, 'GetValue', 'tool.ID')
|
|
mvScan<SCANS.LOAD_LOCK$> = SRP_JSON(objJSONScan, 'GetValue', 'tool.loadLock')
|
|
mvScan<SCANS.ACCEPTED$> = SRP_JSON(objJSONScan, 'GetValue', 'accepted.status', False$)
|
|
mvScan<SCANS.ACCEPTED_DATE$> = SRP_JSON(objJSONScan, 'GetValue', 'accepted.date')
|
|
mvScan<SCANS.ACCEPTED_TIME$> = SRP_JSON(objJSONScan, 'GetValue', 'accepted.time')
|
|
mvScan<SCANS.ACTION$> = SRP_JSON(objJSONScan, 'GetValue', 'action')
|
|
mvScan<SCANS.WAFER_COUNT_CONFIRMED$> = SRP_JSON(objJSONScan, 'GetValue', 'waferCount.confirmed', False$)
|
|
mvScan<SCANS.BOAT_ID$> = SRP_JSON(objJSONScan, 'GetValue', 'transfer.boatID')
|
|
mvScan<SCANS.PL_NUMBER$> = SRP_JSON(objJSONScan, 'GetValue', 'transfer.plNumber')
|
|
mvScan<SCANS.UNLOAD_PL_CONFIRMED$> = SRP_JSON(objJSONScan, 'GetValue', 'transfer.unloadplConfirmed', False$)
|
|
mvScan<SCANS.TRANSFER_TOOL_ID$> = SRP_JSON(objJSONScan, 'GetValue', 'transfer.tool.ID')
|
|
|
|
arrayCassettes = SRP_JSON(objJSONScan, 'Get', 'cassetteIDs')
|
|
NumCassettes = SRP_JSON(arrayCassettes, 'GetCount')
|
|
For CassetteCnt = 1 to NumCassettes
|
|
mvScan<SCANS.CASSETTE_IDS$, CassetteCnt> = SRP_JSON(arrayCassettes, 'GetValue', CassetteCnt)
|
|
Next CassetteCnt
|
|
SRP_JSON(arrayCassettes, 'Release')
|
|
|
|
arrayScanLog = SRP_JSON(objJSONScan, 'Get', 'scan.scanLog')
|
|
NumScanSessions = SRP_JSON(arrayScanLog, 'GetCount')
|
|
For ScanSessionCnt = 1 to NumScanSessions
|
|
objScan = SRP_JSON(arrayScanLog, 'Get', ScanSessionCnt)
|
|
mvScan<SCANS.SCANNED_DATES$, ScanSessionCnt> = SRP_JSON(objScan, 'GetValue', 'date')
|
|
mvScan<SCANS.SCANNED_TIMES$, ScanSessionCnt> = SRP_JSON(objScan, 'GetValue', 'time')
|
|
mvScan<SCANS.SCANNED_DATA$, ScanSessionCnt> = SRP_JSON(objScan, 'GetValue', 'data')
|
|
SRP_JSON(objScan, 'Release')
|
|
Next ScanSessionCnt
|
|
SRP_JSON(arrayScanLog, 'Release')
|
|
|
|
SRP_JSON(objJSONScan, 'Release')
|
|
|
|
end else
|
|
Error_Services('Add', 'Error parsing jsonScan in the ' : Service : ' service.')
|
|
end
|
|
end else
|
|
Error_Services('Add', 'jsonScan argument was missing in the ' : Service : ' service.')
|
|
end
|
|
|
|
Response = mvScan
|
|
|
|
end service
|
|
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// DecodeScanData
|
|
//
|
|
// ScanData - The scan data containing encoded characters. - [Required]
|
|
//
|
|
// Decodes the scan data so that encoded characters are restored to their regular form. This returns the decoded scan
|
|
// data.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service DecodeScanData(ScanData)
|
|
|
|
DecodedScanData = ''
|
|
|
|
If Len(ScanData) then
|
|
DecodedScanData = ScanData
|
|
Swap '/A' with '!' in DecodedScanData
|
|
Swap '/B' with '"' in DecodedScanData
|
|
Swap '/C' with '#' in DecodedScanData
|
|
Swap '/D' with '$' in DecodedScanData
|
|
Swap '/E' with '%' in DecodedScanData
|
|
Swap '/F' with '&' in DecodedScanData
|
|
Swap '/G' with "'" in DecodedScanData
|
|
Swap '/H' with '(' in DecodedScanData
|
|
Swap '/I' with ')' in DecodedScanData
|
|
Swap '/J' with '*' in DecodedScanData
|
|
Swap '/K' with '+' in DecodedScanData
|
|
Swap '/L' with ',' in DecodedScanData
|
|
Swap '/O' with '/' in DecodedScanData
|
|
Swap '/Z' with ':' in DecodedScanData
|
|
Swap '%F' with ';' in DecodedScanData
|
|
Swap '%G' with '<' in DecodedScanData
|
|
Swap '%H' with '=' in DecodedScanData
|
|
Swap '%I' with '>' in DecodedScanData
|
|
Swap '%J' with '?' in DecodedScanData
|
|
Swap '%O' with '_' in DecodedScanData
|
|
end else
|
|
Error_Services('Add', 'The ScanData argument was missing in the ' : Service : ' service.')
|
|
end
|
|
|
|
Response = DecodedScanData
|
|
|
|
end service
|
|
|
|
|
|
Service ResetDevData(CassetteIDs)
|
|
|
|
DevCassettes = '277147,277425,277074,277265,277107,277106,276833,277006,277005,276833,276832,276895,276701,276700,277308,277118,277117,276604'
|
|
Swap ',' with @VM in DevCassettes
|
|
If CassetteIDs EQ '' then CassetteIDs = DevCassettes
|
|
|
|
For each CassetteID in CassetteIDs using @VM
|
|
// Reset RDS record
|
|
RDSRec = Database_Services('ReadDataRow', 'RDS', CassetteID)
|
|
If Error_Services('NoError') then
|
|
If CassetteID EQ 277147 then
|
|
RDSRec<RDS_DATE_OUT$> = ''
|
|
RDSRec<RDS_TIME_OUT$> = ''
|
|
RDSRec<RDS_OPERATOR_OUT$> = ''
|
|
RDSRec<RDS_WAFERS_OUT$> = ''
|
|
RDSRec<RDS_LWI_INST_ACK$> = ''
|
|
RDSRec<RDS_UNLOAD_INST_ACK$> = ''
|
|
Database_Services('WriteDataRow', 'RDS', CassetteID, RDSRec, True$, False$, True$)
|
|
If Error_Services('NoError') then
|
|
WOMatKey = Xlate('RDS', CassetteID, 'WO_MAT_KEY', 'X')
|
|
WOMatRec = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey)
|
|
If Error_Services('NoError') then
|
|
WOMatRec<WO_MAT_SIGNATURE$, 3> = ''
|
|
WOMatRec<WO_MAT_SIG_DTM$, 3> = ''
|
|
Database_Services('WriteDataRow', 'WO_MAT', WOMatKey, WOMatRec, True$, False$, True$)
|
|
end
|
|
end
|
|
end else
|
|
RDSRec<RDS_REACTOR$> = ''
|
|
RDSRec<RDS_DATE_IN$> = ''
|
|
RDSRec<RDS_DATE_OUT$> = ''
|
|
RDSRec<RDS_TIME_IN$> = ''
|
|
RDSRec<RDS_TIME_OUT$> = ''
|
|
RDSRec<RDS_OPERATOR_IN$> = ''
|
|
RDSRec<RDS_OPERATOR_OUT$> = ''
|
|
RDSRec<RDS_WAFERS_IN$> = ''
|
|
RDSRec<RDS_WAFERS_OUT$> = ''
|
|
RDSRec<RDS_VERIFY_QTY$> = ''
|
|
RDSRec<RDS_PRE_EPI_SIG$> = ''
|
|
RDSRec<RDS_PRE_EPI_SIG_DATE$> = ''
|
|
RDSRec<RDS_PRE_EPI_SIG_TIME$> = ''
|
|
RDSRec<RDS_LOAD_LOCK_SIDE$> = ''
|
|
RDSRec<RDS_SUPPL_ACK$> = ''
|
|
RDSRec<RDS_RDS_LAYER_ACK$> = ''
|
|
RDSRec<RDS_PRE_INST_ACK$> = ''
|
|
RDSRec<RDS_FWI_INST_ACK$> = ''
|
|
RDSRec<RDS_LWI_INST_ACK$> = ''
|
|
RDSRec<RDS_QA_INST_ACK$> = ''
|
|
RDSRec<RDS_LOAD_INST_ACK$> = ''
|
|
RDSRec<RDS_UNLOAD_INST_ACK$> = ''
|
|
RDSRec<RDS_WAFER_COUNT_ACK$> = ''
|
|
RDSRec<RDS_SUPPL_SIG$> = ''
|
|
RDSRec<RDS_SUPPL_SIG_DATE$> = ''
|
|
RDSRec<RDS_SUPPL_SIG_TIME$> = ''
|
|
Database_Services('WriteDataRow', 'RDS', CassetteID, RDSRec, True$, False$, True$)
|
|
If Error_Services('NoError') then
|
|
WOMatKey = Xlate('RDS', CassetteID, 'WO_MAT_KEY', 'X')
|
|
WOMatRec = Database_Services('ReadDataRow', 'WO_MAT', WOMatKey)
|
|
If Error_Services('NoError') then
|
|
WOMatRec<WO_MAT_SIGNATURE$> = ''
|
|
WOMatRec<WO_MAT_SIG_DTM$> = ''
|
|
Database_Services('WriteDataRow', 'WO_MAT', WOMatKey, WOMatRec, True$, False$, True$)
|
|
end
|
|
end
|
|
RDSLayerKeys = RDSRec<RDS_RDS_LAYER_KEYS$>
|
|
For each RDSLayerKey in RDSLayerKeys using @VM
|
|
RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKey)
|
|
* RDSLayerRec<RDS_LAYER_DOPANT$> = ''
|
|
* RDSLayerRec<RDS_LAYER_EPI_DILUENT$> = ''
|
|
RDSLayerRec<RDS_LAYER_EPI_TIME$> = ''
|
|
RDSLayerRec<RDS_LAYER_DILUENT_ADJ_PARAM$> = ''
|
|
RDSLayerRec<RDS_LAYER_DOPANT_FLOW$> = ''
|
|
RDSLayerRec<RDS_LAYER_HCL_FLOW$> = ''
|
|
RDSLayerRec<RDS_LAYER_BAKE_TIME$> = ''
|
|
RDSLayerRec<RDS_LAYER_EPI_H2_FLOW$> = ''
|
|
RDSLayerRec<RDS_LAYER_TCS_FLOW$> = ''
|
|
RDSLayerRec<RDS_LAYER_DCS_FLOW$> = ''
|
|
RDSLayerRec<RDS_LAYER_AUX1$> = ''
|
|
RDSLayerRec<RDS_LAYER_AUX2$> = ''
|
|
RDSLayerRec<RDS_LAYER_F_OFFSET$> = ''
|
|
RDSLayerRec<RDS_LAYER_S_OFFSET$> = ''
|
|
RDSLayerRec<RDS_LAYER_R_OFFSET$> = ''
|
|
RDSLayerRec<RDS_LAYER_ETCH1$> = ''
|
|
RDSLayerRec<RDS_LAYER_ETCH2$> = ''
|
|
RDSLayerRec<RDS_LAYER_ETCH3$> = ''
|
|
RDSLayerRec<RDS_LAYER_OVERGROW_REQ$> = ''
|
|
RDSLayerRec<RDS_LAYER_SUSC_ETCH$> = ''
|
|
RDSLayerRec<RDS_LAYER_UL_TEMP$> = ''
|
|
Database_Services('WriteDataRow', 'RDS_LAYER', RDSLayerKey, RDSLayerRec, True$, False$, True$)
|
|
Next RDSLayerKey
|
|
end
|
|
end
|
|
Next CassetteID
|
|
|
|
end service
|
|
|
|
|
|
Service RemoveOldScans()
|
|
|
|
CleanDate = OConv((Date() - 30), 'D4/')
|
|
Query = 'SELECT SCANS WITH CREATED_DATE LT ':Quote(CleanDate)
|
|
GoSub ClearCursors
|
|
RList(Query, TARGET_ACTIVELIST$, '', '', '')
|
|
If Not(Get_Status(errCode)) then
|
|
Done = False$
|
|
Loop
|
|
Readnext KeyID else Done = True$
|
|
Until Done
|
|
Database_Services('DeleteDataRow', 'SCANS', KeyID)
|
|
Repeat
|
|
end
|
|
|
|
end service
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Internal GoSubs
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
ClearCursors:
|
|
|
|
For counter = 0 to 8
|
|
ClearSelect counter
|
|
Next counter
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|