408 lines
17 KiB
Plaintext
408 lines
17 KiB
Plaintext
Function Wafer_Counter_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 : Wafer_Counter_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)
|
|
09/26/23 djs Adapted from FlatFinder_Services.
|
|
|
|
***********************************************************************************************************************/
|
|
|
|
#pragma precomp SRP_PreCompiler
|
|
|
|
$Insert LOGICAL
|
|
$Insert SERVICE_SETUP
|
|
$Insert RDS_EQUATES
|
|
$Insert WO_LOG_EQUATES
|
|
$Insert WM_OUT_EQUATES
|
|
$Insert RLIST_EQUATES
|
|
$Insert WAFER_COUNTER_EQUATES
|
|
|
|
Equ Tab$ to \09\
|
|
Equ CRLF$ to \0D0A\
|
|
Equ LF$ to \0A\
|
|
Equ Comma$ to ','
|
|
* Reduce Modes
|
|
Equ new_exist$ To 0
|
|
Equ next_cur$ To 1
|
|
Equ add_exist$ to 2
|
|
|
|
Declare subroutine Error_Services, Database_Services, Logging_Services, Httpclient_Services, Reduce, SRP_JSON
|
|
Declare function Database_Services, Environment_Services, Logging_Services, Httpclient_Services
|
|
Declare function RTI_CreateGuid, SRP_JSON
|
|
|
|
LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\WaferCounter'
|
|
LogDate = Oconv(Date(), 'D4/')
|
|
LogTime = Oconv(Time(), 'MTS')
|
|
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Wafer Counter Import Log.csv'
|
|
Headers = 'Logging DTM':@FM:'ToolID':@FM:'Operation':@FM:'Datetime':@FM:'LotID':@FM:'CassNo':@FM:'Wafer Count':@FM:'Import Result'
|
|
objLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$)
|
|
LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM
|
|
|
|
GoToService else
|
|
Error_Services('Set', Service : ' is not a valid service request within the ' : ServiceModule : ' services module.')
|
|
end
|
|
|
|
Return Response else ''
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Service Parameter Options
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
Options BOOLEAN = True$, False$
|
|
Options WAFER_SIZES = '6INCH', '8INCH'
|
|
Options LOCATIONS = 'MU', 'QA', 'EPR-EAST', 'EPR-WEST'
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Services
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// ImportWaferCounterFiles
|
|
//
|
|
// Looks for available wafer counter CSV files that are ready to be imported into the RDS table.
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
Service ImportWaferCounterFiles()
|
|
|
|
hSysLists = Database_Services('GetTableHandle', 'SYSLISTS')
|
|
Lock hSysLists, ServiceKeyID then
|
|
DataPath = Environment_Services('GetApplicationRootPath') : '\WaferCounter\'
|
|
BackupPath = Environment_Services('GetApplicationRootPath') : '\WaferCounter\BackupFiles\'
|
|
InitDir DataPath : '*.csv'
|
|
FileList = DirList()
|
|
For Each File in FileList using @FM
|
|
OSRead WaferCounterData from DataPath : File then
|
|
BackupDate = Oconv(Date(), 'D4/')
|
|
BackupTime = Oconv(Time(), 'MTS')
|
|
Convert ':' to '-' in BackupTime
|
|
BackupFileName = BackupDate[7, 4] : '-' : BackupDate[1, 2] : '-' : BackupDate[4, 2] : '-' : BackupTime : ' ' : File
|
|
If Count(File, '-') LE 1 then
|
|
OSWrite WaferCounterData to BackupPath : BackupFileName
|
|
end
|
|
Swap CRLF$ with '' in WaferCounterData
|
|
Swap ',' with @FM in WaferCounterData
|
|
ToolID = Trim(WaferCounterData<2>)
|
|
Operation = Trim(WaferCounterData<3>)
|
|
Datetime = IConv(Trim(WaferCounterData<4>), 'DT')
|
|
ReferenceKeyID = Trim(WaferCounterData<5>)
|
|
CassetteNo = Trim(WaferCounterData<6>)
|
|
WaferCount = Trim(WaferCounterData<7>)
|
|
|
|
Result = False$
|
|
LogData = LoggingDTM
|
|
LogData<2> = ToolID
|
|
LogData<3> = Operation
|
|
LogData<4> = Trim(WaferCounterData<4>)
|
|
LogData<5> = ReferenceKeyID
|
|
LogData<6> = CassetteNo
|
|
LogData<7> = WaferCount
|
|
|
|
If ReferenceKeyID[1, 2] EQ '1T' or ReferenceKeyID[1, 1] EQ 'O' then
|
|
Convert 'O' to '' in ReferenceKeyID
|
|
Swap '1T' with '' in ReferenceKeyID
|
|
If Index(ReferenceKeyID, '.', 1) then
|
|
// A dot means this is a WorkOrderNo.Cassette value. Need to create a WM_OUT Key ID.
|
|
WorkOrderNo = ReferenceKeyID[1, '.']
|
|
WOStepKeyID = ReferenceKeyID[Col2() + 1, '.']
|
|
CassetteNo = ReferenceKeyID[Col2() + 1, '.']
|
|
WMOutKeyID = WorkOrderNo : '*' : WOStepKeyID : '*' : CassetteNo
|
|
WMOutRow = Database_Services('ReadDataRow', 'WM_OUT', WMOutKeyID)
|
|
If Error_Services('NoError') then
|
|
WMOutRow<WM_OUT_WAFER_COUNTER_DTM$> = DateTime
|
|
WMOutRow<WM_OUT_WAFER_COUNTER_QTY$> = WaferCount
|
|
Database_Services('WriteDataRow', 'WM_OUT', WMOutKeyID, WMOutRow, True$, False$, True$)
|
|
end
|
|
end else
|
|
// No dot in the reference key means this is an RDS Key ID.
|
|
Transfer ReferenceKeyID to RDSKeyID
|
|
If Num(RDSKeyID) then RDSKeyID = RDSKeyID + 0
|
|
RDSRow = Database_Services('ReadDataRow', 'RDS', RDSKeyID)
|
|
If Error_Services('NoError') then
|
|
RDSRow<RDS_WAFER_COUNTER_DTM$> = DateTime
|
|
RDSRow<RDS_WAFER_COUNTER_QTY$> = WaferCount
|
|
Database_Services('WriteDataRow', 'RDS', RDSKeyID, RDSRow, True$, False$, True$)
|
|
end
|
|
end
|
|
If Error_Services('NoError') then
|
|
Result = 'Success'
|
|
end else
|
|
Result = 'Failure: ':Error_Services('GetMessage')
|
|
end
|
|
end else
|
|
// Throw error - either invalid barcode scanned or user manually entered data
|
|
Result = 'Failure: ReferenceKeyID "':ReferenceKeyID:'" is invalid.'
|
|
end
|
|
|
|
LogData<8> = Result
|
|
Logging_Services('AppendLog', objLog, LogData, @RM, @FM)
|
|
|
|
OSDelete DataPath : File
|
|
end
|
|
Next File
|
|
|
|
Unlock hSysLists, ServiceKeyID else Null
|
|
end
|
|
|
|
end service
|
|
|
|
|
|
Service ConvertWaferData(FileData)
|
|
|
|
ErrorMsg = ''
|
|
WaferArray = ''
|
|
If FileData NE '' then
|
|
Swap CRLF$ with @FM in FileData
|
|
WaferTotal = FileData<1>
|
|
WaferData = FileData<2>
|
|
If ( (Len(WaferTotal) EQ 3) and (WaferTotal[1, 1] EQ 'T') and (Len(WaferData) EQ 8 ) and (WaferData[1, 1] EQ 'P') ) then
|
|
Convert 'T' to '' in WaferTotal
|
|
WaferArray = ''
|
|
For CharIndex = 2 to 8
|
|
Val = IConv(WaferData[CharIndex, 1], 'MX')
|
|
Val = OConv(Val, 'MB')
|
|
If CharIndex GT 2 then Val = Fmt(Val, 'R(0)#4')
|
|
WaferArray := Val
|
|
Next CharIndex
|
|
|
|
If (Len(WaferArray) NE 25) then
|
|
ErrorMsg = 'Error in ':Service:' service. Invalid wafer array length.'
|
|
end else
|
|
// Reverse the array so it is in order from slot 1 to 25
|
|
WaferArray = WaferArray[-1, -25]
|
|
// Return @VM delimited array for ease of use in OI BASIC+
|
|
DelimArray = ''
|
|
For CharIndex = 1 to 25
|
|
DelimArray<0, CharIndex> = WaferArray[CharIndex, 1]
|
|
Next CharIndex
|
|
If (Sum(DelimArray) EQ WaferTotal) then
|
|
Response = DelimArray
|
|
end else
|
|
ErrorMsg = 'Error in ':Service:' service. Wafer total does not match array total.'
|
|
end
|
|
end
|
|
|
|
end else
|
|
ErrorMsg = 'Error in ':Service:' service. Invalid data format passed in FileData variable.'
|
|
end
|
|
end else
|
|
ErrorMsg = 'Error in ':Service:' service. Null FileData passed into service.'
|
|
end
|
|
If ErrorMsg NE '' then
|
|
Error_Services('Add', ErrorMsg)
|
|
end
|
|
|
|
end service
|
|
|
|
|
|
Service GetWaferCounterJSON(WaferSize, ToolLocation, CassID)
|
|
|
|
If ( (WaferSize NE '') and (ToolLocation NE '') and (CassID NE '') ) then
|
|
URL = 'https://oi-metrology-viewer-prod.mes.infineon.com:4438/api/v1/WaferCounter/{waferSize}/last-quantity-and-slot-map/?area={area}&text={cassID}'
|
|
Swap '{waferSize}' with WaferSize in URL
|
|
Swap '{area}' with ToolLocation in URL
|
|
Swap '{cassID}' with CassID in URL
|
|
// Set timeout to 24 seconds. This value was decided upon with Mike Phares to allow time
|
|
// for EAF to receive the new wafer counter file from the tool and serve it up.
|
|
Httpclient_Services('SetTimeoutDuration', 24)
|
|
Response = Httpclient_Services('SendHTTPRequest', 'GET', URL, '', '', '', '', False$, False$, '')
|
|
If Error_Services('NoError') then
|
|
StatusCode = Httpclient_Services('GetResponseStatusCode')
|
|
If StatusCode NE 200 then
|
|
Begin Case
|
|
Case Response EQ ''
|
|
ErrorMsg = 'Unexpected server error.'
|
|
Case Response EQ 'No files!'
|
|
ErrorMsg = 'No data. Please re-seat cassette and try again.'
|
|
Case Otherwise$
|
|
// Use message in response body to populate error services
|
|
ErrorMsg = Response
|
|
End Case
|
|
Error_Services('Add', ErrorMsg)
|
|
end
|
|
end
|
|
end
|
|
|
|
end service
|
|
|
|
|
|
Service AddScan(LotID, ScanQty, ScanDtm, ScanTool, ScanUser, ScanLocation, WaferMap)
|
|
|
|
KeyID = RTI_CreateGuid()
|
|
Record = ''
|
|
Record<WAFER_COUNTER.LOT_ID$> = LotID
|
|
Record<WAFER_COUNTER.SCAN_QTY$> = ScanQty
|
|
If Not(Num(ScanDtm)) then
|
|
ScanYear = ScanDtm[1, 'F-']
|
|
ScanMonth = ScanDtm[Col2() + 1, 'F-']
|
|
ScanDay = ScanDtm[Col2() + 1, 'F ']
|
|
ScanTime = ScanDtm[Col2() + 1, 999]
|
|
Convert ' ' to '' in ScanTime
|
|
ScanDtm = ScanMonth:'/':ScanDay:'/':ScanYear:' ':ScanTime
|
|
ScanDtm = IConv(ScanDtm, 'DT')
|
|
end
|
|
Record<WAFER_COUNTER.SCAN_DTM$> = ScanDtm
|
|
Record<WAFER_COUNTER.SCAN_TOOL$> = ScanTool
|
|
Record<WAFER_COUNTER.SCAN_USER$> = ScanUser
|
|
If ScanLocation EQ 'FQA' then ScanLocation = 'QA'
|
|
Record<WAFER_COUNTER.SCAN_LOCATION$> = ScanLocation
|
|
Record<WAFER_COUNTER.SCAN_WAFER_MAP$> = WaferMap
|
|
Database_Services('WriteDataRow', 'WAFER_COUNTER', KeyID, Record)
|
|
|
|
end service
|
|
|
|
|
|
Service GetLastScan(LotID, ScanLocation=LOCATIONS)
|
|
|
|
ErrorMsg = ''
|
|
WCRec = ''
|
|
If LotID NE '' then
|
|
Tablename = "WAFER_COUNTER"
|
|
Flag = ""
|
|
Done = False$
|
|
CursorVar = ""
|
|
|
|
GoSub ClearCursors
|
|
|
|
SortList = "#SCAN_DTM"
|
|
ReduceScript = 'WITH {LOT_ID} EQ ':Quote(LotID)
|
|
If ScanLocation NE '' then
|
|
ReduceScript := ' AND WITH {SCAN_LOCATION} EQ ':Quote(ScanLocation)
|
|
end
|
|
Mode = NEXT_CUR$
|
|
|
|
Reduce(ReduceScript, SortList, Mode, Tablename, Cursorvar, Flag)
|
|
If Flag then
|
|
Select Tablename By SortList Using Cursorvar then
|
|
Open Tablename To hTable then
|
|
KeyID = ''
|
|
Loop
|
|
ReadNext KeyID Using Cursorvar By AT Else Done = TRUE$
|
|
If KeyID NE '' then
|
|
Done = True$
|
|
Read WCRec from hTable, KeyID then
|
|
WCRec<WAFER_COUNTER.SCAN_DTM$> = OConv(WCRec<WAFER_COUNTER.SCAN_DTM$>, 'DT/^2H')
|
|
end else
|
|
ErrorMsg = 'Error in ':Service:' service. Error reading ':KeyID:' from ':Tablename:' table.'
|
|
end
|
|
end
|
|
Until Done or (KeyID NE '')
|
|
Repeat
|
|
End Else
|
|
ErrorMsg = 'Error in ':Service:' service. Error in opening ':Tablename:'.'
|
|
End
|
|
End Else
|
|
ErrorMsg = 'Error in ':Service:' service. Error in selecting ':Tablename:'.'
|
|
end
|
|
End Else
|
|
ErrorMsg = 'Error in ':Service:' service. Error in Reduce call.'
|
|
End
|
|
end else
|
|
ErrorMsg = 'Error in ':Service:' service. Null LotID passed into service.'
|
|
end
|
|
|
|
If ErrorMsg NE '' then
|
|
Error_Services('Add', ErrorMsg)
|
|
end
|
|
|
|
Response = WCRec
|
|
|
|
end service
|
|
|
|
|
|
Service GetProdWaferCounter(WaferSize=WAFER_SIZES, Location=LOCATIONS)
|
|
|
|
ToolID = ''
|
|
ErrorMsg = ''
|
|
If ( (WaferSize NE '') and (Location NE '') ) then
|
|
Query = "SELECT TOOL WITH @ID CONTAINING 'WC":WaferSize:"' AND WITH TOOL_LOC EQ '":Location:"' AND WITH CURR_MODE EQ 'PROD'"
|
|
GoSub ClearCursors
|
|
RList(Query, TARGET_ACTIVELIST$, '', '', '')
|
|
ErrCode = ''
|
|
If Not(Get_Status(ErrCode)) then
|
|
Begin Case
|
|
Case @RecCount EQ 0
|
|
ErrorMsg = 'Error in ':Service:' service. No production wafer counter found!'
|
|
Case @RecCount EQ 1
|
|
ReadNext ToolID else
|
|
ErrorMsg = 'Error in ':Service:' service. Error reading production wafer counter tool ID!'
|
|
end
|
|
Case @RecCount GT 1
|
|
ErrorMsg = 'Error in ':Service:' service. More than one production wafer counter found!'
|
|
End Case
|
|
GoSub ClearCursors
|
|
end else
|
|
ErrorMsg = 'Error in ':Service:' service. Error calling RList. Error code: ':ErrCode:'.'
|
|
end
|
|
end else
|
|
ErrorMsg = 'Error in ':Service:' service. Null WaferSize or Location passed into service.'
|
|
end
|
|
If ErrorMsg NE '' then
|
|
Error_Services('Add', ErrorMsg)
|
|
end
|
|
Response = ToolID
|
|
|
|
end service
|
|
|
|
|
|
Service GetWaferCounterToolID(WaferSize=WAFER_SIZES, Location=LOCATIONS)
|
|
|
|
ToolID = ''
|
|
ErrorMsg = ''
|
|
If ( (WaferSize NE '') and (Location NE '') ) then
|
|
Query = "SELECT TOOL WITH @ID CONTAINING 'WC":WaferSize:"' AND WITH TOOL_LOC EQ '":Location:"'"
|
|
GoSub ClearCursors
|
|
RList(Query, TARGET_ACTIVELIST$, '', '', '')
|
|
ErrCode = ''
|
|
If Not(Get_Status(ErrCode)) then
|
|
Begin Case
|
|
Case @RecCount EQ 0
|
|
ErrorMsg = 'Error in ':Service:' service. No wafer counter tool found for ':WaferSize:' ':Location:'.'
|
|
Case @RecCount EQ 1
|
|
ReadNext ToolID else
|
|
ErrorMsg = 'Error in ':Service:' service. Error reading wafer counter tool ID!'
|
|
end
|
|
Case @RecCount GT 1
|
|
ErrorMsg = 'Error in ':Service:' service. More than one wafer counter tool found for ':WaferSize:' ':Location:'.'
|
|
End Case
|
|
GoSub ClearCursors
|
|
end else
|
|
ErrorMsg = 'Error in ':Service:' service. Error calling RList. Error code: ':ErrCode:'.'
|
|
end
|
|
end else
|
|
ErrorMsg = 'Error in ':Service:' service. Null WaferSize or Location passed into service.'
|
|
end
|
|
If ErrorMsg NE '' then
|
|
Error_Services('Add', ErrorMsg)
|
|
end
|
|
Response = ToolID
|
|
|
|
end service
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Internal GoSubs
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ClearCursors:
|
|
|
|
For counter = 0 to 8
|
|
ClearSelect counter
|
|
Next counter
|
|
|
|
return
|
|
|