Merged PR 21151: Return To Fab Operations and Processing

This commit is contained in:
Ouellette Jonathan (CSC FI SPS MESLEO)
2025-07-16 21:17:07 +02:00
parent b607432be4
commit aabd4c3a91
56 changed files with 8856 additions and 2508 deletions

File diff suppressed because it is too large Load Diff

View File

@ -149,4 +149,3 @@ end api
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Internal GoSubs
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -136,4 +136,3 @@ CreateHALCollection:
end
return

258
LSL2/STPROC/CLEAN_API.txt Normal file
View File

@ -0,0 +1,258 @@
Function Clean_API(@API)
/***********************************************************************************************************************
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 : Clean_API
Description : API logic for the Clean resource.
Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables:
HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.)
APIURL - The URL for the API entry point (e.g., api.mysite.com/v1).
FullEndpointURL - The URL submitted by the client, including query params.
FullEndpointURLNoQuery - The URL submitted by the client, excluding query params.
EndpointSegment - The URL endpoint segment.
ParentURL - The URL path preceeding the current endpoint.
CurrentAPI - The name of this stored procedure.
Parameters :
API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]:
- APIPattern must follow this structure Clean[.ID.[<Property>]]
- HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc.
Examples:
- Clean.POST
- Clean.ID.PUT
- Clean.ID.firstName.GET
Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API
services do not rely upon anything being returned in the response. This is what the
various services like SetResponseBody and SetResponseStatus services are for. A response
value is only helpful if the developers want to use it for debug purposes.
History : (Date, Initials, Notes)
06/18/25 xxx Original programmer.
***********************************************************************************************************************/
#pragma precomp SRP_PreCompiler
Declare function OI_Wizard_Services, Lot_Operation_Services, Database_Services, Lot_Services, Clean_Services
Declare subroutine Clean_Services, Lot_Services
$insert APP_INSERTS
$insert API_SETUP
$insert HTTP_INSERTS
$insert OI_WIZARD_EQUATES
$insert LOT_OPERATION_EQUATES
GoToAPI else
// The specific resource endpoint doesn't have a API handler yet.
HTTP_Services('SetResponseStatus', 204, 'This is a valid endpoint but a web API handler has not yet been created.')
end
Return Response OR ''
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Endpoint Handlers
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
API clean.ID.HEAD
API clean.ID.GET
ErrorMessage = ''
ResponseCode = ''
ResponseMessage = ''
Body = ''
OIWizardID = ''
Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';'
Key = Field(Cookie, '=', 1)
If Key EQ 'sessionID' then
OIWizardID = Field(Cookie, '=', 2)
end
Next Cookie
ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID)
If ValidSession then
UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X')
StatusCode = ''
CleanRecId = EndpointSegment
CleanRecJson = Clean_Services('ConvertCleanRecToJson', CleanRecId)
If Error_Services('NoError') then
Http_Services('SetResponseBody', CleanRecJson, False$, 'application/hal+json')
ResponseCode = 200
end else
ErrorMessage = Error_Services('GetMessage')
ResponseCode = 500
end
end else
ErrorMessage = 'Invalid session. Reauthentication required.'
ResponseCode = 401
end
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage)
end api
API clean.ID.markcleanrecordcomplete.POST
ErrorMessage = ''
ResponseCode = ''
ResponseMessage = ''
Body = ''
OIWizardID = ''
Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';'
Key = Field(Cookie, '=', 1)
If Key EQ 'sessionID' then
OIWizardID = Field(Cookie, '=', 2)
end
Next Cookie
ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID)
If ValidSession then
UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X')
StatusCode = ''
Body = HTTP_Services('GetHTTPPostString', True$)
// The POST string will have been encoded so use percent (URL) decoding.
DecodedJSON = HTTP_Services('DecodePercentString', Body)
If SRP_JSON(objBody, 'Parse', Body) EQ '' then
CleanRecId = ParentSegment
LotOperationId = SRP_JSON(objBody, 'GetValue', 'LotOperationId')
CleanTool = SRP_JSON(objBody, 'GetValue', 'CleanTool')
CleanRecipe = SRP_JSON(objBody, 'GetValue', 'CleanRecipe')
SRP_JSON(objBody, 'Release')
Clean_Services('MarkCleanRecComplete', CleanRecId, CleanRecipe, CleanTool, UserId)
If Error_Services('NoError') then
CleanRecJson = Clean_Services('ConvertCleanRecToJson', CleanRecId)
HTTP_Services('SetResponseBody', CleanRecJson, False$, 'application/hal+json')
ResponseCode = 200
end else
ErrorMessage = Error_Services('GetMessage')
ResponseCode = 500
end
end
end else
ErrorMessage = 'Invalid session. Reauthentication required.'
ResponseCode = 401
end
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage)
end api
API clean.createcleanrecord.POST
ErrorMessage = ''
ResponseCode = ''
ResponseMessage = ''
Body = ''
OIWizardID = ''
Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';'
Key = Field(Cookie, '=', 1)
If Key EQ 'sessionID' then
OIWizardID = Field(Cookie, '=', 2)
end
Next Cookie
ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID)
If ValidSession then
UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X')
StatusCode = ''
Body = HTTP_Services('GetHTTPPostString', True$)
// The POST string will have been encoded so use percent (URL) decoding.
DecodedJSON = HTTP_Services('DecodePercentString', Body)
If SRP_JSON(objBody, 'Parse', Body) EQ '' then
LotId = SRP_JSON(objBody, 'GetValue', 'LotId')
LotOperationId = SRP_JSON(objBody, 'GetValue', 'LotOperationId')
SRP_JSON(objBody, 'Release')
end
CleanRecId = Clean_Services('CreateNewCleanRecord', LotId, LotOperationId, UserId)
If Error_Services('NoError') then
CleanRecJson = Clean_Services('ConvertCleanRecToJson', CleanRecId)
HTTP_Services('SetResponseBody', CleanRecJson, False$, 'application/hal+json')
ResponseCode = 200
end else
ErrorMessage = Error_Services('GetMessage')
ResponseCode = 500
end
end else
ErrorMessage = 'Invalid session. Reauthentication required.'
ResponseCode = 401
end
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage)
end api
API clean.getnewcleanoperationparams.HEAD
API clean.getnewcleanoperationparams.GET
JSONCollection = ''
OIWizardID = ''
Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';'
Key = Field(Cookie, '=', 1)
If Key EQ 'sessionID' then
OIWizardID = Field(Cookie, '=', 2)
end
Next Cookie
ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID)
If ValidSession then
Body = HTTP_Services('GetHTTPGetString')
If Body NE '' then
RequestJson = HTTP_Services('DecodePercentString', Body)
LotId = Http_Services('GetQueryField', 'LotId')
objJSONResponse = ''
If SRP_Json(objJSONResponse, 'New', 'Object') then
//Available Tools
If SRP_Json(objCleanTools, 'New', 'Array') then
CleanTools = Clean_Services('GetCleanToolOptions')
for each CleanTool in CleanTools using @FM
SRP_Json(objCleanTools, 'AddValue', CleanTool, 'String')
Next CleanTool
SRP_Json(objJsonResponse, 'Set', 'CleanToolOptions', objCleanTools)
SRP_Json(objCleanTools, 'Release')
end
//Available Recipes
If SRP_Json(objCleanRecipes, 'New', 'Array') then
CleanRecipes = Clean_Services('GetCleanRecipeOptions')
for each Recipe in CleanRecipes using @VM
SRP_Json(objCleanRecipes, 'AddValue', Recipe, 'String')
Next Recipe
SRP_Json(objJsonResponse, 'Set', 'CleanRecipeOptions', objCleanRecipes)
SRP_Json(objCleanRecipes, 'Release')
end
JsonResponse = SRP_Json(objJsonResponse, 'Stringify', 'Styled')
SRP_Json(objJsonResponse, 'Release')
end else
Error_Services('Add', 'Error when creating JSON response.')
end
end else
Error_Services('Add', 'No body was sent with the request.')
end
If Error_Services('NoError') then
HTTP_Services('SetResponseStatus', 201, 'Success')
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseBody', JsonResponse, False$, 'application/hal+json')
end else
HTTP_Services('SetResponseStatus', 400, Error_Services('GetMessage'))
end
end else
HTTP_Services('SetResponseStatus', 401, 'Invalid session. Reauthentication required.')
end
end api

View File

@ -0,0 +1,217 @@
Compile function Clean_Services(@Service, @Params)
#pragma precomp SRP_PreCompiler
Declare Function Database_Services, Error_Services, Logging_Services, Datetime
Declare Function RTI_CreateGUID, Tool_Services, SRP_Json, Date_Services
Declare Subroutine Database_Services, Error_Services, Logging_Services, SRP_Json, Lot_Event_Services
$insert LOGICAL
$Insert CLEAN_EQUATES
$Insert LOT_EQUATES
$Insert LOT_OPERATION_EQUATES
$Insert TOOL_EQUATES
$Insert TOOL_CLASS_EQUATES
Options Stage = 'LWI',
GoToService
Return Response or ""
//-----------------------------------------------------------------------------
// SERVICES
//-----------------------------------------------------------------------------
Service CreateNewCleanRecord(LotId, LotOperationId, UserId)
ErrorMessage = ''
CleanRecId = ''
If RowExists('LOT', LotId) then
//ToDo check Lot Operation Exists
//Checks complete, create the CLEAN record
TransDtm = Datetime()
CleanRecId = RTI_CreateGUID()
CleanRec = ''
CleanRec<CLEAN_LOT_ID$> = LotId
CleanRec<CLEAN_LOT_OPERATION_ID$> = LotOperationId
CleanRec<CLEAN_CLEAN_START_DTM$> = TransDtm
CleanRec<CLEAN_CLEAN_START_USER_ID$> = UserId
Database_Services('WriteDataRow', 'CLEAN', CleanRecId, CleanRec)
If Error_Services('NoError') then
If LotOperationId NE '' then
LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$)
LotOperationRec<LOT_OPERATION_CLEAN_ID$> = CleanRecId
Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationId, LotOperationRec)
If Error_Services('NoError') then
Lot_Event_Services('CreateLotEvent', LotId, TransDtm, 'CLEAN_START', 'Created clean record.', '', UserId)
end else
ErrorMessage = Error_Services('GetMessage')
end
end
end else
ErrorMessage = Error_Services('GetMessage')
end
end else
//Todo add error message
end
If ErrorMessage EQ '' then
Response = CleanRecId
end else
// Todo: Add logging
ErrorMessage = 'Error Creating a new clean record: ' : ErrorMessage
Error_Services('Add', ErrorMessage)
end
End Service
Service ConvertCleanRecToJson(CleanRecId)
ErrorMessage = ''
CleanRecJson = ''
If RowExists('CLEAN', CleanRecId) then
CleanRec = Database_Services('ReadDataRow', 'CLEAN', CleanRecId, True$, 0, False$)
If Error_Services('NoError') then
objJson = ''
If SRP_Json(objJson, 'New', 'Object') then
SRP_Json(objJson, 'SetValue', 'CleanId', CleanRecId, 'String')
SRP_Json(objJson, 'SetValue', 'LotId', CleanRec<CLEAN_LOT_ID$>, 'String')
LegacyLotId = Database_Services('ReadDataColumn', 'LOT', CleanRec<CLEAN_LOT_ID$>, LOT_LEGACY_LOT_ID$)
SRP_Json(objJson, 'SetValue', 'LegacyLotId', LegacyLotId, 'String')
SRP_Json(objJson, 'SetValue', 'Recipe', CleanRec<CLEAN_RECIPE$>, 'String')
SRP_Json(objJson, 'SetValue', 'Tool', CleanRec<CLEAN_TOOL$>, 'String')
SRP_Json(objJson, 'SetValue', 'StartUser', CleanRec<CLEAN_CLEAN_START_USER_ID$>, 'String')
StartDtm = Date_Services('ConvertDateTimeToISO8601', CleanRec<CLEAN_CLEAN_START_DTM$>)
if StartDtm NE '' then
SRP_Json(objJson, 'SetValue', 'StartDtm', StartDtm)
end
SRP_Json(objJson, 'SetValue', 'StopUser', CleanRec<CLEAN_CLEAN_STOP_USER_ID$>, 'String')
StopDtm = Date_Services('ConvertDateTimeToISO8601', CleanRec<CLEAN_CLEAN_STOP_DTM$>)
if StopDtm NE '' then
SRP_Json(objJson, 'SetValue', 'StopDtm', StopDtm, 'String')
end
SRP_Json(objJson, 'SetValue', 'LotOperationId', CleanRec<CLEAN_LOT_OPERATION_ID$>, 'String')
CleanRecJson = SRP_Json(objJson, 'Stringify', 'Styled')
SRP_Json(objJson, 'Release')
end else
ErrorMessage = 'Error creating clean record json'
end
end else
ErrorMessage = Error_Services('GetMessage')
end
end else
ErrorMessage = 'Clean record not found.'
end
If ErrorMessage EQ '' then
Response = CleanRecJson
end else
Error_Services('Add', 'Error getting clean record : ' : ErrorMessage)
end
end service
Service MarkCleanRecComplete(CleanRecId, CleanRecipe, CleanTool, CleanUser)
ErrorMessage = ''
TransDtm = Datetime()
If RowExists('CLEAN', CleanRecId) then
CleanRec = Database_Services('ReadDataRow', 'CLEAN', CleanRecId, True$, 0, False$)
If CleanRec<CLEAN_CLEAN_START_DTM$> NE '' then
If CleanRec<CLEAN_TOOL$> EQ '' AND CleanRec<CLEAN_RECIPE$> EQ '' then
if RowExists('LSL_USERS', CleanUser) then
If CleanRec<CLEAN_COMPLETE_DTM$> EQ '' then
CleanRec<CLEAN_TOOL$> = CleanTool
CleanRec<CLEAN_RECIPE$> = CleanRecipe
CleanRec<CLEAN_CLEAN_STOP_USER_ID$> = CleanUser
CleanRec<CLEAN_CLEAN_STOP_DTM$> = TransDtm
Database_Services('WriteDataRow', 'CLEAN', CleanRecId, CleanRec)
If Error_Services('NoError') then
LotId = CleanRec<CLEAN_LOT_ID$>
Lot_Event_Services('CreateLotEvent', LotId, TransDtm, 'CLEAN', 'Clean completed', CleanTool, CleanUser)
end else
ErrorMessage = Error_Services('GetMessage')
end
end else
ErrorMessage = 'Clean is already signed off.'
end
end else
ErrorMessage = 'Clean tool or clean recipe is missing.'
end
end else
ErrorMessage = 'Clean has already been logged.'
end
end else
ErrorMessage = 'Clean has not been started.'
end
end else
ErrorMessage = 'Clean record not found.'
end
If ErrorMessage NE '' then
Error_Services('Add', ErrorMessage)
end
end service
Service ValidateCleanRecord(CleanRecId)
//ErrorMessage = ''
CleanRecValid = False$
* If CleanRecId NE '' then
* If RowExists('CLEAN', CleanRecId) then
* CleanRec = Database_Services('ReadDataRow', 'CLEAN', CleanRecId, True$, 0, False$)
* SpecTool = CleanRec<CLEAN_TOOL$>
* ToolUsed = CleanRec<CLEAN_RECIPE$>
* If ToolUsed EQ SpecTool AND ToolUsed NE '' then
* SpecRecipe = CleanRec<CLEAN_SPEC_RECIPE$>
* RecipeUsed = CleanRec<CLEAN_RECIPE$>
* If RecipeUsed EQ SpecRecipe AND RecipeUsed NE '' then
* CleanRecValid = True$
* end
* end
* end else
* ErrorMessage = 'Clean record not found in CLEAN database.'
* end
* end else
* ErrorMessage = 'Clean ID was null.'
* end
*
* If ErrorMessage EQ '' then
* Response = CleanRecValid
* end else
* // Todo: Add logging
* ErrorMessage = 'Error validating clean record: ' : ErrorMessage
* Error_Services('Add', ErrorMessage)
* end
Response = CleanRecValid
End Service
Service GetCleanToolOptions(CleanRecId)
If RowExists('CLEAN', CleanRecId) then
CleanTools = Database_Services('ReadDataColumn', 'CLEAN', CleanRecId, CLEAN_SPEC_CLEAN_TOOL$, True$, 0, False$)
end else
CleanTools = Tool_Services('GetTools', 'AKRION')
end
Response = CleanTools
end service
Service GetCleanRecipeOptions(CleanRecId)
If RowExists('CLEAN', CleanRecId) then
Recipes = Database_Services('ReadDataColumn', 'CLEAN', CleanRecId, CLEAN_SPEC_CLEAN_RECIPE$, True$, 0, False$)
end else
//Todo: Make this smarter, so as to block out pre-epi recipes
Recipes = XLATE('TOOL_CLASS','AKRION',TOOL_CLASS_RECIPES$,'X')
end
Response = Recipes
end service

View File

@ -858,3 +858,4 @@ Result = ReturnData
RETURN

View File

@ -213,4 +213,3 @@ UpdateHALItem:
end
return

View File

@ -220,6 +220,13 @@ Service GetWeekNum(InputDate)
end service
Service ConvertDateTimeToISO8601(DatetimeToConv)
Response = OConv(DatetimeToConv, "[SRP_DATETIME,()YYYY-MM-DD hh:mm:ss.000Z]")
swap ' ' with 'T' in Response
end service
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Internal GoSubs

View File

@ -94,4 +94,3 @@ API engineinfo.ID.GET
end
end api

View File

@ -69,4 +69,3 @@ API healthinfo.GET
HTTP_Resource_Services('LoremIpsum')
end api

View File

@ -161,7 +161,3 @@ API Lock.HEAD
end
end api

View File

@ -0,0 +1,460 @@
Function Lotoperation_API(@API)
/***********************************************************************************************************************
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 : Lotoperation_API
Description : API logic for the Lotoperation resource.
Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables:
HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.)
APIURL - The URL for the API entry point (e.g., api.mysite.com/v1).
FullEndpointURL - The URL submitted by the client, including query params.
FullEndpointURLNoQuery - The URL submitted by the client, excluding query params.
EndpointSegment - The URL endpoint segment.
ParentURL - The URL path preceeding the current endpoint.
CurrentAPI - The name of this stored procedure.
Parameters :
API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]:
- APIPattern must follow this structure Lotoperation[.ID.[<Property>]]
- HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc.
Examples:
- Lotoperation.POST
- Lotoperation.ID.PUT
- Lotoperation.ID.firstName.GET
Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API
services do not rely upon anything being returned in the response. This is what the
various services like SetResponseBody and SetResponseStatus services are for. A response
value is only helpful if the developers want to use it for debug purposes.
History : (Date, Initials, Notes)
05/20/25 xxx Original programmer.
***********************************************************************************************************************/
#pragma precomp SRP_PreCompiler
Declare function OI_Wizard_Services, Lot_Operation_Services, Database_Services, Lot_Services, Clean_Services
Declare function Met_Test_Services
Declare subroutine Lot_Services, Met_Test_Services, Wafer_Counter_Services
$insert APP_INSERTS
$insert API_SETUP
$insert HTTP_INSERTS
$insert OI_WIZARD_EQUATES
$insert LOT_OPERATION_EQUATES
GoToAPI else
// The specific resource endpoint doesn't have a API handler yet.
HTTP_Services('SetResponseStatus', 204, 'This is a valid endpoint but a web API handler has not yet been created.')
end
Return Response OR ''
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Endpoint Handlers
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
API lotoperation.HEAD
API lotoperation.GET
HTTP_Resource_Services('LoremIpsum')
end api
API lotoperation.addoperation.POST
ErrorMessage = ''
ResponseCode = ''
ResponseMessage = ''
Body = ''
OIWizardID = ''
Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';'
Key = Field(Cookie, '=', 1)
If Key EQ 'sessionID' then
OIWizardID = Field(Cookie, '=', 2)
end
Next Cookie
ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID)
If ValidSession then
UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X')
StatusCode = ''
Body = HTTP_Services('GetHTTPPostString', True$)
// The POST string will have been encoded so use percent (URL) decoding.
DecodedJSON = HTTP_Services('DecodePercentString', Body)
If SRP_JSON(objBody, 'Parse', Body) EQ '' then
LotId = SRP_JSON(objBody, 'GetValue', 'NewLotOperationData.LotId')
OperationId = SRP_JSON(objBody, 'GetValue', 'NewLotOperationData.OperationId')
Sequence = SRP_JSON(objBody, 'GetValue', 'NewLotOperationData.Sequence')
SRP_JSON(objBody, 'Release')
end
If RowExists('LOT', LotId) then
If RowExists('OPERATION', OperationId) then
If Sequence NE '' then
NewOperationId = Lot_Operation_Services('AddOperationToLot', LotId, OperationId, Sequence, UserId)
If Error_Services('NoError') then
LotJsonString = Lot_Services('ConvertLotRecordToJson', LotId, '', UserId)
HTTP_Services('SetResponseBody', LotJsonString, False$, 'application/hal+json')
ResponseCode = 200
end else
ErrorMessage = Error_Services('GetMessage')
ResponseCode = 500
end
end else
ErrorMessage = 'Invalid Sequence.'
ResponseCode = 500
end
end else
ErrorMessage = 'Invalid Operation.'
ResponseCode = 500
end
end else
ErrorMessage = 'Invalid Lot.'
ResponseCode = 500
end
end else
ErrorMessage = 'Invalid session. Reauthentication required.'
ResponseCode = 401
end
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage)
end api
API lotoperation.removeoperation.POST
ErrorMessage = ''
ResponseCode = ''
ResponseMessage = ''
Body = ''
OIWizardID = ''
Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';'
Key = Field(Cookie, '=', 1)
If Key EQ 'sessionID' then
OIWizardID = Field(Cookie, '=', 2)
end
Next Cookie
ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID)
If ValidSession then
UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X')
StatusCode = ''
Body = HTTP_Services('GetHTTPPostString', True$)
// The POST string will have been encoded so use percent (URL) decoding.
DecodedJSON = HTTP_Services('DecodePercentString', Body)
If SRP_JSON(objBody, 'Parse', Body) EQ '' then
LotOperationId = SRP_JSON(objBody, 'GetValue', 'LotOperationIdToRemove')
SRP_JSON(objBody, 'Release')
end
If RowExists('LOT_OPERATION', LotOperationId) then
LotId = Database_Services('ReadDataColumn', 'LOT_OPERATION', LotOperationId, LOT_OPERATION_LOT_ID$, True$, 0, False$)
Removed = Lot_Operation_Services('RemoveLotOperation', LotOperationId, UserId)
If Error_Services('NoError') then
LotJsonString = Lot_Services('ConvertLotRecordToJson', LotId, '', UserId)
HTTP_Services('SetResponseBody', LotJsonString, False$, 'application/hal+json')
ResponseCode = 200
end else
ErrorMessage = Error_Services('GetMessage')
ResponseCode = 500
end
end else
ErrorMessage = 'Invalid Operation.'
ResponseCode = 500
end
end else
ErrorMessage = 'Invalid session. Reauthentication required.'
ResponseCode = 401
end
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage)
end api
API lotoperation.startlotoperation.POST
ErrorMessage = ''
ResponseCode = ''
ResponseMessage = ''
Body = ''
OIWizardID = ''
Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';'
Key = Field(Cookie, '=', 1)
If Key EQ 'sessionID' then
OIWizardID = Field(Cookie, '=', 2)
end
Next Cookie
ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID)
If ValidSession then
UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X')
StatusCode = ''
Body = HTTP_Services('GetHTTPPostString', True$)
// The POST string will have been encoded so use percent (URL) decoding.
DecodedJSON = HTTP_Services('DecodePercentString', Body)
If SRP_JSON(objBody, 'Parse', Body) EQ '' then
LotOperationId = SRP_JSON(objBody, 'GetValue', 'lotOperationId')
SRP_JSON(objBody, 'Release')
end
LotProcessStarted = Lot_Operation_Services('StartLotOperation', LotOperationId, UserId)
If Error_Services('NoError') then
LotOperationJson = Lot_Operation_Services('ConvertRecordToJson', LotOperationId)
HTTP_Services('SetResponseBody', LotOperationJson,False$, 'application/hal+json')
ResponseCode = 200
end else
ErrorMessage = 'Error while moving lot in. ' : Error_Services('GetMessage')
ResponseCode = 500
end
end else
ErrorMessage = 'Invalid session. Reauthentication required.'
ResponseCode = 401
end
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage)
end api
API lotoperation.completelotoperation.POST
ErrorMessage = ''
ResponseCode = ''
ResponseMessage = ''
Body = ''
OIWizardID = ''
Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';'
Key = Field(Cookie, '=', 1)
If Key EQ 'sessionID' then
OIWizardID = Field(Cookie, '=', 2)
end
Next Cookie
ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID)
If ValidSession then
UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X')
StatusCode = ''
Body = HTTP_Services('GetHTTPPostString', True$)
// The POST string will have been encoded so use percent (URL) decoding.
DecodedJSON = HTTP_Services('DecodePercentString', Body)
If SRP_JSON(objBody, 'Parse', Body) EQ '' then
LotOperationId = SRP_JSON(objBody, 'GetValue', 'lotOperationId')
SRP_JSON(objBody, 'Release')
end
LotProcessCompleted = Lot_Operation_Services('CompleteLotOperation', LotOperationId, UserId)
If Error_Services('NoError') then
LotOperationJson = Lot_Operation_Services('ConvertRecordToJson', LotOperationId)
HTTP_Services('SetResponseBody', LotOperationJson)
ResponseCode = 200
end else
ErrorMessage = Error_Services('GetMessage')
ResponseCode = 500
end
end else
ErrorMessage = 'Invalid session. Reauthentication required.'
ResponseCode = 401
end
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage)
end api
API lotoperation.ID.HEAD
API lotoperation.ID.GET
ErrorMessage = ''
ResponseCode = ''
ResponseMessage = ''
Body = ''
OIWizardID = ''
Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';'
Key = Field(Cookie, '=', 1)
If Key EQ 'sessionID' then
OIWizardID = Field(Cookie, '=', 2)
end
Next Cookie
ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID)
If ValidSession then
LotOperationId = EndpointSegment
If RowExists('LOT_OPERATION', LotOperationId) then
LotOperationJson = Lot_Operation_Services('ConvertRecordToJson', LotOperationId)
HTTP_Services('SetResponseBody', LotOperationJson, False$, 'application/hal+json')
ResponseCode = 200
end else
ErrorMessage = 'Lot Operation not found in database.'
end
end else
ErrorMessage = 'Invalid session. Reauthentication required.'
ResponseCode = 401
end
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage)
end api
API lotoperation.associatemettest.POST
ErrorMessage = ''
ResponseCode = ''
ResponseMessage = ''
Body = ''
OIWizardID = ''
Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';'
Key = Field(Cookie, '=', 1)
If Key EQ 'sessionID' then
OIWizardID = Field(Cookie, '=', 2)
end
Next Cookie
ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID)
If ValidSession then
UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X')
StatusCode = ''
Body = HTTP_Services('GetHTTPPostString', True$)
// The POST string will have been encoded so use percent (URL) decoding.
DecodedJSON = HTTP_Services('DecodePercentString', Body)
If SRP_JSON(objBody, 'Parse', Body) EQ '' then
LotOperationId = SRP_JSON(objBody, 'GetValue', 'LotOperationId')
MetTestId = SRP_JSON(objBody, 'GetValue', 'MetTestId')
SRP_JSON(objBody, 'Release')
end
Met_Test_Services('AttachMetTestToLotOperation', MetTestId, LotOperationId, UserId)
If Error_Services('NoError') then
ResponseCode = 200
end else
ErrorMessage = Error_Services('GetMessage')
ResponseCode = 500
end
end else
ErrorMessage = 'Invalid session. Reauthentication required.'
ResponseCode = 401
end
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage)
end api
API lotoperation.removemettest.POST
ErrorMessage = ''
ResponseCode = ''
ResponseMessage = ''
Body = ''
OIWizardID = ''
Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';'
Key = Field(Cookie, '=', 1)
If Key EQ 'sessionID' then
OIWizardID = Field(Cookie, '=', 2)
end
Next Cookie
ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID)
If ValidSession then
UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X')
StatusCode = ''
Body = HTTP_Services('GetHTTPPostString', True$)
// The POST string will have been encoded so use percent (URL) decoding.
DecodedJSON = HTTP_Services('DecodePercentString', Body)
If SRP_JSON(objBody, 'Parse', Body) EQ '' then
LotOperationId = SRP_JSON(objBody, 'GetValue', 'LotOperationId')
MetTestId = SRP_JSON(objBody, 'GetValue', 'MetTestId')
SRP_JSON(objBody, 'Release')
end
Met_Test_Services('RemoveMetTestFromLotOperation', MetTestId, LotOperationId, UserId)
If Error_Services('NoError') then
HTTP_Services('SetResponseBody', LotJsonString, False$, 'application/hal+json')
ResponseCode = 200
end else
ErrorMessage = Error_Services('GetMessage')
ResponseCode = 500
end
end else
ErrorMessage = 'Invalid session. Reauthentication required.'
ResponseCode = 401
end
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage)
end api
API lotoperation.associatewafercounter.POST
ErrorMessage = ''
ResponseCode = ''
ResponseMessage = ''
Body = ''
OIWizardID = ''
Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';'
Key = Field(Cookie, '=', 1)
If Key EQ 'sessionID' then
OIWizardID = Field(Cookie, '=', 2)
end
Next Cookie
ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID)
If ValidSession then
UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X')
StatusCode = ''
Body = HTTP_Services('GetHTTPPostString', True$)
// The POST string will have been encoded so use percent (URL) decoding.
DecodedJSON = HTTP_Services('DecodePercentString', Body)
If SRP_JSON(objBody, 'Parse', Body) EQ '' then
LotOperationId = SRP_JSON(objBody, 'GetValue', 'LotOperationId')
WaferCounterId = SRP_JSON(objBody, 'GetValue', 'WaferCounterId')
SRP_JSON(objBody, 'Release')
end
Wafer_Counter_Services('AssociateWaferCounter', LotOperationId, WaferCounterId, UserId)
If Error_Services('NoError') then
ResponseCode = 200
end else
ErrorMessage = Error_Services('GetMessage')
ResponseCode = 500
end
end else
ErrorMessage = 'Invalid session. Reauthentication required.'
ResponseCode = 401
end
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage)
end api

View File

@ -38,9 +38,12 @@ Function Lot_API(@API)
#pragma precomp SRP_PreCompiler
Declare function OI_Wizard_Services, Lot_Services, Database_Services, PSN_Services, Clean_Services
$insert APP_INSERTS
$insert API_SETUP
$insert HTTP_INSERTS
$Insert OI_WIZARD_EQUATES
GoToAPI else
// The specific resource endpoint doesn't have a API handler yet.
@ -55,3 +58,159 @@ Return Response OR ''
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
API lot.ID.HEAD
API lot.ID.GET
ErrorMessage = ''
ResponseCode = ''
ResponseMessage = ''
Body = ''
OIWizardID = ''
UserId = ''
Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';'
Key = Field(Cookie, '=', 1)
If Key EQ 'sessionID' then
OIWizardID = Field(Cookie, '=', 2)
end
Next Cookie
ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID)
If ValidSession then
UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X')
LotId = EndpointSegment
If RowExists('LOT', LotId) then
LotJson = Lot_Services('ConvertLotRecordToJson', LotId, '', UserId)
HTTP_Services('SetResponseBody', LotJson, False$, 'application/hal+json')
ResponseCode = 200
end else
ResponseCode = 500
ErrorMessage = 'Lot not found in database.'
end
end else
ErrorMessage = 'Invalid session. Reauthentication required.'
ResponseCode = 401
end
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage)
end api
API lot.getlotbylegacylotid.HEAD
API lot.getlotbylegacylotid.GET
ErrorMessage = ''
ResponseCode = ''
ResponseMessage = ''
Body = ''
OIWizardID = ''
Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';'
Key = Field(Cookie, '=', 1)
If Key EQ 'sessionID' then
OIWizardID = Field(Cookie, '=', 2)
end
Next Cookie
ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID)
If ValidSession then
UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X')
StatusCode = ''
Body = HTTP_Services('GetHTTPGetString')
LegacyLotId = Http_Services('GetQueryField', 'LegacyLotId')
LegacyLotType = Http_Services('GetQueryField', 'LegacyLotType')
LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', LegacyLotId, LegacyLotType)
LotJson = Lot_Services('ConvertLotRecordToJson', LotId, '', UserId)
If Error_Services('NoError') then
HTTP_Services('SetResponseBody', LotJson, False$, 'application/hal+json')
ResponseCode = 200
end else
ErrorMessage = Error_Services('GetMessage')
ResponseCode = 500
end
end else
ErrorMessage = 'Invalid session. Reauthentication required.'
ResponseCode = 401
end
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage)
end api
end api
API lot.ID.getrecipeoptions.HEAD
API lot.ID.getrecipeoptions.GET
JSONCollection = ''
OIWizardID = ''
Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';'
Key = Field(Cookie, '=', 1)
If Key EQ 'sessionID' then
OIWizardID = Field(Cookie, '=', 2)
end
Next Cookie
ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID)
If ValidSession then
LotId = EndpointSegment
PSN = Database_Services('ReadDataColumn', 'LOT', LotId, LOT_PROD_SPEC_ID$, True$, 0, False$)
RecipeParameters = PSN_Services('GetAllMetrologyRecipes', PSN, True$, True$, True$, True$)
If Error_Services('NoError') then
If Body NE '' then
RequestJson = HTTP_Services('DecodePercentString', Body)
objJSONResponse = ''
If SRP_Json(objJSONResponse, 'New', 'Object') then
//Available Tools
If SRP_Json(objCleanTools, 'New', 'Array') then
CleanTools = Clean_Services('GetCleanToolOptions')
for each CleanTool in CleanTools using @FM
SRP_Json(objCleanTools, 'AddValue', CleanTool, 'String')
Next CleanTool
SRP_Json(objJsonResponse, 'Set', 'CleanToolOptions', objCleanTools)
SRP_Json(objCleanTools, 'Release')
end
//Available Recipes
If SRP_Json(objCleanRecipes, 'New', 'Array') then
CleanRecipes = Clean_Services('GetCleanRecipeOptions')
for each Recipe in CleanRecipes using @VM
SRP_Json(objCleanRecipes, 'AddValue', Recipe, 'String')
Next Recipe
SRP_Json(objJsonResponse, 'Set', 'CleanRecipeOptions', objCleanRecipes)
SRP_Json(objCleanRecipes, 'Release')
end
JsonResponse = SRP_Json(objJsonResponse, 'Stringify', 'Styled')
SRP_Json(objJsonResponse, 'Release')
end else
Error_Services('Add', 'Error when creating JSON response.')
end
end else
Error_Services('Add', 'No body was sent with the request.')
end
end else
ErrorMessage = Error_Services('GetMessage')
end
If Error_Services('NoError') then
HTTP_Services('SetResponseStatus', 201, 'Success')
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseBody', JsonResponse, False$, 'application/hal+json')
end else
HTTP_Services('SetResponseStatus', 400, Error_Services('GetMessage'))
end
end else
HTTP_Services('SetResponseStatus', 401, 'Invalid session. Reauthentication required.')
end
end api

View File

@ -59,7 +59,7 @@ Declare function Lot_Event_Services, Lot_Services
Declare subroutine Error_Services, Logging_Services, Database_Services, Lot_Services, Service_Services
Declare subroutine Transaction_Services
Options EVENT_TYPES = 'MOVE_IN', 'MOVE_OUT', 'HOLD_ON', 'HOLD_OFF', 'REDUCE_WAFER_QTY', 'BONUS_WAFER_QTY', 'COMMENT', 'LOCATION', 'LOAD', 'UNSIGN_LOAD', 'TW_USE', 'CLOSE', 'SIGN_FQA', 'UNSIGN_FQA'
Options EVENT_TYPES = 'MOVE_IN', 'MOVE_OUT', 'HOLD_ON', 'HOLD_OFF', 'REDUCE_WAFER_QTY', 'BONUS_WAFER_QTY', 'COMMENT', 'LOCATION', 'LOAD', 'UNSIGN_LOAD', 'TW_USE', 'CLOSE', 'SIGN_FQA', 'UNSIGN_FQA', 'ADD_LOT_OPERATION', 'REMOVE_LOT_OPERATION', 'MET_TEST', 'LOG_WAFER_COUNT', 'PACKAGING'
Options LOT_TYPES = 'TW', 'RDS', 'WM_OUT', 'WM_IN', 'WO_MAT', 'LOT'
Options LEGACY_LOT_TYPES = 'RDS', 'WM_OUT', 'WM_IN'
Options BOOLEAN = 'True', 'False'
@ -230,3 +230,6 @@ InitEventLog:
return

View File

@ -3,12 +3,12 @@ Compile function Lot_Operation_Services(@Service, @Params)
Declare function Lot_Services, Database_Services, Error_Services, Srp_Sort_Array, Lot_Operation_Services
Declare function RTI_CreateGUID, MemberOf, SRP_JSON, Operation_Services, Datetime, Met_Test_Services, PSN_Services
Declare function Date_Services
Declare subroutine Database_Services, Error_Services, SRP_JSON, Lot_Services, Lot_Event_Services, Lot_Operation_Services
$insert LOGICAL
$insert LOT_EQUATES
$Insert LOT_OPERATION_EQUATES
$Insert METROLOGY_DATA_EXAMPLE_EQUATES
$Insert OPERATION_EQUATES
$Insert MET_TEST_EQUATES
$Insert WAFER_COUNTER_EQUATES
@ -30,7 +30,7 @@ Service AddOperationToLot(LotId, OperationId, PrescribedSequence, UserId)
If RowExists('LOT', LotId) then
If RowExists('OPERATION', OperationId) then
If PrescribedSequence AND Num(PrescribedSequence) then
If Lot_Operation_Services('CanUserAddLotOperation', UserId) then
If Lot_Services('CanUserModifyLot', UserId) then
LotCurrOperation = Lot_Services('GetLotCurrOperationId', LotId)
CurrOperationSequence = Xlate('LOT_OPERATION', LotCurrOperation, LOT_OPERATION_OPERATION_SEQUENCE$, 'X')
If CurrOperationSequence LT PrescribedSequence then
@ -74,7 +74,8 @@ Service AddOperationToLot(LotId, OperationId, PrescribedSequence, UserId)
IsOperationRework = Database_Services('ReadDataColumn', 'OPERATION', OperationId, OPERATION_REWORK$)
Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationRecId, LotOperationRec)
If Error_Services('NoError') then
Lot_Event_Services('CreateLotEvent', LotId, Datetime(), 'ADD_LOT_OPERATION', 'Added operation ' : Operation : ' to lot.', '', UserId)
OperationDesc = XLATE('OPERATION', OperationId, OPERATION_OPERATION_DESCRIPTION$, 'X')
Lot_Event_Services('CreateLotEvent', LotId, Datetime(), 'ADD_LOT_OPERATION', 'Added operation ' : Quote(OperationDesc) : ' to lot.', '', UserId)
end else
ErrorMessage = Error_Services('GetMessage')
end
@ -86,7 +87,7 @@ Service AddOperationToLot(LotId, OperationId, PrescribedSequence, UserId)
ErrorMessage = 'Not allowed to add new operations prior to current operation'
end
end else
ErrorMessage = 'User ' : UserId : ' does not have permission to add operations to lots.'
ErrorMessage = 'User ' : UserId : ' does not have permission to modify lots.'
end
end else
ErrorMessage = 'Invalid operation sequence entered.'
@ -102,7 +103,6 @@ Service AddOperationToLot(LotId, OperationId, PrescribedSequence, UserId)
Response = Operation
end else
Error_Services('Add', 'Error in ' : Service : '.' : ErrorMessage)
// todo: add logging
end
end service
@ -114,6 +114,7 @@ Service RemoveLotOperation(LotOperationId, UserId)
Success = False$
If RowExists('LOT_OPERATION', LotOperationId) then
If Lot_Services('CanUserModifyLot', UserId) then
LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$)
LotId = LotOperationRec<LOT_OPERATION_LOT_ID$>
MoveInTime = LotOperationRec<LOT_OPERATION_DATETIME_IN$>
@ -132,7 +133,8 @@ Service RemoveLotOperation(LotOperationId, UserId)
end else
ErrorMessage = Error_Services('GetMessage')
end
Lot_Event_Services('CreateLotEvent', LotId, Datetime(), 'REMOVE_LOT_OPERATION', 'Removed operation ' : OperationId : ' from lot.', '', UserId)
OperationDesc = XLATE('OPERATION', OperationId, OPERATION_OPERATION_DESCRIPTION$, 'X')
Lot_Event_Services('CreateLotEvent', LotId, Datetime(), 'REMOVE_LOT_OPERATION', 'Removed operation ' : Quote(OperationDesc) : ' from lot.', '', UserId)
end else
ErrorMessage = Error_Services('GetMessage')
end
@ -142,20 +144,23 @@ Service RemoveLotOperation(LotOperationId, UserId)
end else
ErrorMessage = 'Unable to remove default operations.'
end
end else
ErrorMessage = 'User ' : UserId : ' does not have permission modify lots.'
end
end else
ErrorMessage = 'Lot Operation record not found'
end
If ErrorMessage NE '' then
Error_Services('Add', 'Error in service ': Service : ' : ' : ErrorMessage)
Error_Services('Add', ErrorMessage)
end
Response = Success
end service
Service UpdateLotOperationSequence(LotId, StartSequence)
ErrorMessage = ''
If StartSequence EQ '' then
StartSequence = 1
@ -189,17 +194,6 @@ Service UpdateLotOperationSequence(LotId, StartSequence)
end service
Service ModifyLotOperationSequence(LotOperationId, NewSequence, UserId)
ErrorMessage = ''
If ErrorMessage NE '' then
end
end service
Service GetAvailableSequences(LotId)
AvailableSequences = ''
@ -211,40 +205,14 @@ Service GetAvailableSequences(LotId)
OperationClass = Database_Services('ReadDataColumn', 'OPERATION', OperationId, OPERATION_CLASS_ID$)
StartDtm = LotOperationRec<LOT_OPERATION_DATETIME_IN$>
If StartDTM EQ '' then
If OperationClass NE 'RTF_DEFAULT' then
AvailableSequences<1, -1> = Sequence + 1
end
end
Next LotOperationId
end
Response = AvailableSequences
end service
Service AddSpecsToLotOperation(LotOperationId)
end service
Service CanUserAddLotOperation(UserId)
If UserId NE '' then
Begin Case
Case MemberOf(UserId, 'LEAD')
Response = True$
Case MemberOf(UserId, 'SUPERVISOR')
Response = True$
Case MemberOf(UserId, 'ENGINEER')
Response = True$
Case MemberOf(UserId, 'ENG_TECH')
Response = True$
Case Otherwise$
Response = False$
End Case
end
end service
Service ConvertRecordToJson(LotOperationId)
JsonString = ''
@ -258,8 +226,14 @@ Service ConvertRecordToJson(LotOperationId)
SRP_JSON(objJSON, 'SetValue', 'LotId', LotId, 'String')
SRP_JSON(objJSON, 'SetValue', 'LegacyLotId', LegacyLotId, 'String')
SRP_JSON(objJSON, 'SetValue', 'OperationId', LotOperationRec<LOT_OPERATION_OPERATION_ID$>, 'String')
SRP_JSON(objJSON, 'SetValue', 'DateTimeIn', OConv(LotOperationRec<LOT_OPERATION_DATETIME_IN$>, 'DT'), 'String')
SRP_JSON(objJSON, 'SetValue', 'DateTimeOut', OConv(LotOperationRec<LOT_OPERATION_DATETIME_OUT$>, 'DT'), 'String')
OperationDesc = XLATE('OPERATION', LotOperationRec<LOT_OPERATION_OPERATION_ID$>, OPERATION_OPERATION_DESCRIPTION$, 'X')
SRP_JSON(objJSON, 'SetValue', 'Description', OperationDesc, 'String')
OperationClass = XLATE('OPERATION', LotOperationRec<LOT_OPERATION_OPERATION_ID$>, OPERATION_CLASS_ID$, 'X')
SRP_JSON(objJSON, 'SetValue', 'OperationClass', OperationClass)
DatetimeIn = Date_Services('ConvertDateTimeToISO8601', LotOperationRec<LOT_OPERATION_DATETIME_IN$>)
SRP_JSON(objJSON, 'SetValue', 'DateTimeIn', DatetimeIn)
DatetimeOut = Date_Services('ConvertDateTimeToISO8601', LotOperationRec<LOT_OPERATION_DATETIME_OUT$>)
SRP_JSON(objJSON, 'SetValue', 'DateTimeOut', DatetimeOut)
EquipmentId = LotOperationRec<LOT_OPERATION_EQUIPMENT_ID$>
SRP_JSON(objJSON, 'SetValue', 'EquipmentId', EquipmentId)
SRP_JSON(objJSON, 'SetValue', 'WaferInQty', LotOperationRec<LOT_OPERATION_WAFER_IN_QTY$>, 'Number')
@ -267,8 +241,10 @@ Service ConvertRecordToJson(LotOperationId)
SRP_JSON(objJSON, 'SetValue', 'OperatorInId', LotOperationRec<LOT_OPERATION_OPERATOR_IN_ID$>)
SRP_JSON(objJSON, 'SetValue', 'OperatorOutId', LotOperationRec<LOT_OPERATION_OPERATOR_OUT_ID$>)
SRP_JSON(objJSON, 'SetValue', 'OperationSequence', LotOperationRec<LOT_OPERATION_OPERATION_SEQUENCE$>)
SRP_JSON(objJSON, 'SetValue', 'DateTimeStart', OConv(LotOperationRec<LOT_OPERATION_DATETIME_START$>, 'DT'), 'String')
SRP_JSON(objJSON, 'SetValue', 'DateTimeStop', OConv(LotOperationRec<LOT_OPERATION_DATETIME_STOP$>, 'DT'), 'String')
DatetimeStart = Date_Services('ConvertDateTimeToISO8601', LotOperationRec<LOT_OPERATION_DATETIME_START$>)
SRP_JSON(objJSON, 'SetValue', 'DateTimeStart', DatetimeStart)
DatetimeStop = Date_Services('ConvertDateTimeToISO8601', LotOperationRec<LOT_OPERATION_DATETIME_STOP$>)
SRP_JSON(objJSON, 'SetValue', 'DateTimeStop', DatetimeStop)
SRP_JSON(objJSON, 'SetValue', 'MetTestId', LotOperationRec<LOT_OPERATION_MET_TEST_ID$>)
SRP_JSON(objJSON, 'SetValue', 'CleanId', LotOperationRec<LOT_OPERATION_CLEAN_ID$>)
SRP_JSON(objJSON, 'SetValue', 'PackagingId', LotOperationRec<LOT_OPERATION_PACKAGING_ID$>)
@ -278,7 +254,22 @@ Service ConvertRecordToJson(LotOperationId)
SRP_JSON(objJson, 'SetValue', 'PackagingRequired', LotOperationRec<LOT_OPERATION_PACKAGING_REQUIRED$>, 'Boolean')
SRP_JSON(objJson, 'SetValue', 'CleanRequired', LotOperationRec<LOT_OPERATION_CLEAN_REQUIRED$>, 'Boolean')
SRP_JSON(objJson, 'SetValue', 'WaferCounterRequired', LotOperationRec<LOT_OPERATION_WAFER_COUNTER_REQUIRED$>, 'Boolean')
PSNo = Xlate('LOT', LotId, LOT_PROD_SPEC_ID$, 'X')
RecipeToolInfo = PSN_Services('GetAllMetrologyRecipes', PSNo, True$, True$, True$, True$)
objRecipeInfo = ''
If SRP_Json(objRecipeInfo, 'New', 'Array') then
for each RecipeLine in RecipeToolInfo using @FM
If SRP_Json(objRecipeLine, 'New', 'Object') then
SRP_Json(objRecipeLine, 'SetValue', 'ToolClass', RecipeLine<1,1>, 'String')
SRP_Json(objRecipeLine, 'SetValue', 'Recipe', RecipeLine<1,2>, 'String')
SRP_Json(objRecipeLine, 'SetValue', 'Stage', RecipeLine<1,3>, 'String')
SRP_Json(objRecipeInfo, 'Add', objRecipeLine)
SRP_Json(objRecipeLine, 'Release')
end
Next RecipeLine
SRP_Json(objJSON, 'Set', 'RecipeInfo', objRecipeInfo)
SRP_Json(objRecipeInfo, 'Release')
end
SRP_JSON(objJSON, 'SetValue', 'OperationType', LotOperationRec<LOT_OPERATION_OPERATION_TYPE$>)
//Add OPERATION Object
OperationJson = Operation_Services('ConvertRecordToJSON', LotOperationRec<LOT_OPERATION_OPERATION_ID$>)
@ -302,7 +293,7 @@ Service ConvertRecordToJson(LotOperationId)
end
//Add Available Met Test Record
AvailMetTestIds = Met_Test_Services('GetMetTests', LotId, LegacyLotId, '', EquipmentId, True$)
AvailMetTestIds = Met_Test_Services('GetMetTests', LotId, LegacyLotId, '', '', True$)
objAvailMetTest = ''
If SRP_Json(objAvailMetTest, 'New', 'Array') then
for each MetTestId in AvailMetTestIds using @VM
@ -316,8 +307,6 @@ Service ConvertRecordToJson(LotOperationId)
SRP_Json(objAvailMetTest, 'Release')
end
//Add in relevant recipes
//OperationType = LotOperationRec<LOT_OPERATION_OPERATION_TYPE$>
//MetTestTypeRequired = LotOperationRec<LOT_OPERATION_MET_TEST_TYPE_REQUIRED$>
Recipes = ''
ShowThickRecipes = False$
ShowResRecipes = False$
@ -340,7 +329,7 @@ Service ConvertRecordToJson(LotOperationId)
ShowCleanRecipes = True$
end
ProdSpecNo = XLATE('LOT', LotId, LOT_PROD_SPEC_ID$, 'X')
Recipes = PSN_Services('GetAllMetrologoyRecipes', ProdSpecNo, ShowSurfscanRecipes, ShowCleanRecipes, ShowResRecipes, ShowThickRecipes)
Recipes = PSN_Services('GetAllMetrologyRecipes', ProdSpecNo, ShowSurfscanRecipes, ShowCleanRecipes, ShowResRecipes, ShowThickRecipes)
If SRP_JSON(objRecipes, 'New', 'Array') then
for each Recipe in Recipes using @FM
//ToolClass : @VM : Recipe : @VM : Stage
@ -358,9 +347,8 @@ Service ConvertRecordToJson(LotOperationId)
SRP_JSON(objJSON, 'Set', 'RecipeParams', objRecipes)
SRP_JSON(objRecipes, 'Release')
end
JsonString = SRP_JSON(objJSON, 'Stringify', 'Styled')
JsonString = SRP_JSON(objJSON, 'Stringify', 'Fast')
SRP_JSON(objJSON, 'Release')
end
Response = JsonString
@ -370,12 +358,6 @@ end service
Service StartLotOperation(LotOperationId, UserId)
//1. Validate that it can be moved into the operation passed in.
//2. Move in the lot
//3. Return true is move in successfully
//4. Return false if error moving in
ErrorMessage = ''
If RowExists('LOT_OPERATION', LotOperationId) then
@ -415,10 +397,7 @@ end service
Service CompleteLotOperation(LotOperationId, UserId)
//1. Validate that the lot is moved into the operation
//2. Validate that the lot
ErrorMessage = ''
If RowExists('LOT_OPERATION', LotOperationId) then
If RowExists('LSL_USERS', UserId) then
//We can also add additional checks like security checks, training checks, etc here if needed.
@ -439,10 +418,12 @@ Service CompleteLotOperation(LotOperationId, UserId)
ErrorMessage = 'Lot Operation has not finished processing and cannot be moved out.'
end
end else
ErrorMessage = 'Lot is already moved into this operation.'
ErrorMessage = 'Cannot complete operation because lot is not currently moved in.'
end
end else
CurrOperationId = Xlate('LOT_OPERATION', LotCurrentLotOpId, LOT_OPERATION_OPERATION_ID$, 'X')
CurrOperationDesc = Xlate('OPERATION', CurrOperationId, OPERATION_OPERATION_DESCRIPTION$, 'X')
ErrorMessage = 'Cannot complete operation. Lot is currently at ' : CurrOperationDesc
end
end else
ErrorMessage = 'Invalid user passed to routine.'
@ -455,7 +436,7 @@ Service CompleteLotOperation(LotOperationId, UserId)
Response = True$
end else
Response = False$
Error_Services('Add', 'Error in ' : Service : '. ' : ErrorMessage)
Error_Services('Add', ErrorMessage)
end
end service
@ -472,14 +453,14 @@ Service ValidateLotOperation(LotOperationId)
PackagingRequired = LotOperationRec<LOT_OPERATION_PACKAGING_REQUIRED$>
CleanRequired = LotOperationRec<LOT_OPERATION_CLEAN_REQUIRED$>
WaferCountRequired = LotOperationRec<LOT_OPERATION_WAFER_COUNTER_REQUIRED$>
OperationClass = XLATE('OPERATION', OperationId, OPERATION_CLASS_ID$, 'X')
If MetTestRequired then
MetTestsInSpec = True$
AssociatedMetTestIds = LotOperationRec<LOT_OPERATION_MET_TEST_ID$>
If AssociatedMetTestIds NE '' then
for each MetTestId in AssociatedMetTestIds using @VM
MetTestOoS = Database_Services('ReadDataColumn', 'MET_TEST', MetTestId, MET_TEST.OUT_OF_SPEC$, True$, 0, False)
If MetTestOoS then
//ToDo Check that the met tests meet the requirements.
If MetTestOoS AND OperationClass NE 'RTF' AND OperationClass NE 'RTF_DEFAULT' then
MetTestsInSpec = False$
ErrorMessage = 'An associated Met test record is out of spec.'
end
@ -490,14 +471,29 @@ Service ValidateLotOperation(LotOperationId)
ErrorMessage = 'Met tests are required and none are assigned.'
end
end
If PackagingRequired then
If PackagingRequired AND IsValid then
AssociatedPackagingIds = LotOperationRec<LOT_OPERATION_PACKAGING_ID$>
If AssociatedPackagingIds NE '' then
end else
IsValid = False$
end
If CleanRequired then
end
If WaferCountRequired then
If CleanRequired AND IsValid then
AssociatedCleanIds = LotOperationRec<LOT_OPERATION_CLEAN_ID$>
If AssociatedCleanIds NE '' then
IsValid = True$
end else
IsValid = False$
end
end
If WaferCountRequired AND IsValid then
AssociatedWaferCountIds = LotOperationRec<LOT_OPERATION_WAFER_COUNTER_ID$>
If AssociatedWaferCountIds NE '' then
IsValid = True$
end else
IsValid = False$
end
end
end else
ErrorMessage = 'Lot Operation not found'
@ -509,27 +505,3 @@ Service ValidateLotOperation(LotOperationId)
Response = IsValid
end service
Service ValidateFQA(LotOperationId)
Response = False$
LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$)
LotId = LotOperationRec<LOT_OPERATION_LOT_ID$>
OperationStartDtm = LotOperationRec<LOT_OPERATION_DATETIME_IN$>
RelevantMetTests = ''
MetTests = Met_Test_Services('GetMetTestsByLotId', LotId)
For each MetTestId in MetTests using @VM
ThisMetTestRec = Database_Services('ReadDataRow', 'MET_TEST', MetTestId, True$, 0, False$)
Next MetTestId
end service
Service AssociateClean(LotOperationId, CleanId, UserId)
end service
Service GetFinalQAOperationJson(LotId, Stage)
end service

View File

@ -46,21 +46,25 @@ Compile function Lot_Services(@Service, @Params)
***********************************************************************************************************************/
#pragma precomp SRP_PreCompiler
$Insert SERVICE_SETUP
$Insert APP_INSERTS
Declare function TEST_WAFER_PROD_SERVICES, SRP_Datetime, Datetime, Database_Services, Lot_Services, Error_Services, RTI_CREATEGUID
Declare function SRP_Array, SRP_Json, Environment_Services, Logging_Services, MemberOf, Lot_Event_Services, GetTickCount, Lot_Operation_Services
Declare function PSN_Services, Return_To_Fab_Services
Declare subroutine Database_Services, Btree.Extract, Lot_Services, Error_Services, Labeling_Services, SRP_Json, Logging_Services
Declare subroutine SRP_Run_Command, Service_Services, obj_notes, Lot_Event_Services, Mona_Services
$insert APP_INSERTS
$Insert LOT_EQUATES
$Insert TEST_WAFER_PROD_EQUATES
$Insert LOT_OPERATION_EQUATES
$Insert Lot_Operation_Equates
$Insert PRODUCT_OPERATION_EQUATES
$Insert LOT_EVENT_EQUATES
$Insert NOTIFICATION_EQUATES
$Insert VOIDED_LOT_EQUATES
$Insert IFX_EQUATES
Declare function TEST_WAFER_PROD_SERVICES, SRP_Datetime, Datetime, Database_Services, Lot_Services, Error_Services, RTI_CREATEGUID
Declare function SRP_Array, SRP_Json, Environment_Services, Logging_Services, MemberOf, Lot_Event_Services, GetTickCount
Declare subroutine Database_Services, Btree.Extract, Lot_Services, Error_Services, Labeling_Services, SRP_Json, Logging_Services
Declare subroutine SRP_Run_Command, Service_Services, obj_notes, Lot_Event_Services, Mona_Services
$Insert RDS_EQUATES
$Insert WO_LOG_EQUATES
$Insert PROD_VER_EQUATES
$Insert OPERATION_EQUATES
LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\Lot'
LogDate = Oconv(Date(), 'D4/')
@ -77,7 +81,7 @@ objLotStartLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', He
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' LotRun.csv'
Headers = 'Logging DTM' : @FM : 'Lot Id' : @FM : 'Username' : @FM : 'Tool Id' : @FM : 'Message'
objLotRunLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$)
objRunLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$)
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' LotMove.csv'
Headers = 'Logging DTM' : @FM : 'Lot Id' : @FM : 'Username' : @FM : 'Message'
@ -91,8 +95,9 @@ LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' T
Headers = 'Logging DTM' : @FM : 'Lot Id' : @FM : 'Operator' : @FM : 'Message'
objLotClosureLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$)
Options EVENT_TYPES = 'MOVE_IN', 'MOVE_OUT', 'HOLD_ON', 'HOLD_OFF', 'REDUCE_WAFER_QTY', 'BONUS_WAFER_QTY', 'COMMENT', 'LOCATION', 'LOAD', 'UNSIGN_LOAD', 'TW_USE', 'CLOSE', 'SIGN_FQA', 'UNSIGN_FQA'
Options EVENT_TYPES = 'MOVE_IN', 'MOVE_OUT', 'HOLD_ON', 'HOLD_OFF', 'REDUCE_WAFER_QTY', 'BONUS_WAFER_QTY', 'COMMENT', 'LOCATION', 'LOAD', 'UNSIGN_LOAD', 'TW_USE', 'CLOSE', 'SIGN_FQA', 'UNSIGN_FQA', 'SYSTEM_COMMENT'
Options LOT_TYPES = 'TW', 'RDS', 'WM_OUT', 'WM_IN', 'WO_MAT', 'LOT'
Options LEGACY_LOT_TYPES = 'RDS', 'WM_OUT', 'WM_IN', 'WO_MAT'
IsProd = Environment_Services('IsProd')
If IsProd EQ True$ then
@ -177,16 +182,16 @@ Service GenerateNewLotId(LotType)
end service
Service GetLotIdByLegacyLotIdAndType(LegacyLotId, LegacyLotType)
Service GetLotIdByLegacyLotIdAndType(LegacyLotId, LegacyLotType=LEGACY_LOT_TYPES)
StartTick = GetTickCount()
MetricName = 'GetLotIdByLegacyLotIdAndType'
ErrorMsg = ''
Open 'DICT.LOT' to DictLot then
SearchString = ''
SearchString := 'LEGACY_LOT_ID':@VM:LegacyLotId:@FM
SearchString := 'TYPE':@VM:LegacyLotType:@FM
SearchString := 'LEGACY_LOT_TYPE':@VM:LegacyLotType:@FM
LotIdKeys = ''
Btree.Extract(SearchString, 'LOT', DictLot, LotIdKeys, '', '')
ErrCode = ''
@ -195,6 +200,7 @@ Service GetLotIdByLegacyLotIdAndType(LegacyLotId, LegacyLotType)
end else
Response = LotIdKeys<1,1>
end
end else
ErrorMsg = 'Error in ':Service:' service. Error opening LOT dictionary.'
end
@ -202,13 +208,14 @@ Service GetLotIdByLegacyLotIdAndType(LegacyLotId, LegacyLotType)
EndTick = GetTickCount()
Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick)
If ErrorMsg NE '' then Error_Services('Add', ErrorMsg)
If ErrorMsg NE '' then
Error_Services('Add', ErrorMsg)
end
end service
Service CreateNewLot(LotType, ProdName, LotQty, VendorPartNo, VendorLotNo, VendorCode, Username, PrinterID, LotId)
Service CreateNewLot(LotType, ProdName, LotQty, VendorPartNo, VendorLotNo, VendorCode, Username, PrinterID, LegacyLotId)
StartTick = GetTickCount()
MetricName = 'CreateNewLot'
@ -216,30 +223,69 @@ Service CreateNewLot(LotType, ProdName, LotQty, VendorPartNo, VendorLotNo, Vendo
ErrorMessage = ''
Begin Case
Case LotType EQ 'RDS' OR LotType EQ 'WM_IN' OR LotType EQ 'WM_OUT' OR LotType EQ 'WO_MAT'
If LegacyLotId NE '' then
LegacyLotType = LotType
LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', LegacyLotId, LegacyLotType)
If LotId EQ '' then
LotType = 'PROD'
// Case statement for legacy lot entity types
NewLotId = Lot_Services('GenerateNewLotId', LotType)
NewLotId = Lot_Services('GenerateNewLotId', LegacyLotType)
If NewLotId NE '' then
If RowExists('LOT', NewLotId) NE False$ then
WoNo = ''
EpiPartNo = ''
ProdVerNo = ''
Begin Case
Case LegacyLotType EQ 'RDS'
WoNo = XLATE('RDS', LegacyLotId, RDS_WO$, 'X')
Case LegacyLotType EQ 'WM_IN' OR LegacyLotType EQ 'WM_OUT' OR LegacyLotType EQ 'WO_MAT'
WoNo = Field(LegacyLotId, '*', 1)
End Case
ProdVerNo = XLATE('WO_LOG', WoNo, WO_LOG_PROD_VER_NO$, 'X')
EpiPartNo = XLATE('WO_LOG', WoNo, WO_LOG_EPI_PART_NO$, 'X')
ProdId = EpiPartNo : '*' : ProdVerNo
ProdSpecId = XLATE('WO_LOG', WoNo, WO_LOG_PROD_SPEC_ID$, 'X')
If ProdSpecId EQ '' then
Begin Case
Case LegacyLotType EQ 'RDS'
ProdSpecId = XLATE('RDS', LegacyLotId, RDS_PROD_SPEC_ID$, 'X')
Case Otherwise$
ProdSpecId = XLATE('PROD_VER', ProdVerNo, PROD_VER_PROC_STEP_PSN$, 'X')
End Case
end
If Not(RowExists('PRODUCT', ProdId)) then ProdId = ''
LotRec = ''
LotRec<LOT_TYPE$> = LotType
LotRec<LOT_PROD_ID$> = ''
LotRec<LOT_TYPE$> = 'PROD'
LotRec<LOT_PROD_ID$> = ProdId
LotRec<LOT_ORIG_WAFER_QTY$> = LotQty
LotRec<LOT_WAFER_QTY$> = LotQty
LotRec<LOT_VENDOR_PART_NO$> = VendorPartNo
LotRec<LOT_VENDOR_LOT_NO$> = VendorLotNo
LotRec<LOT_VENDOR_CODE$> = VendorCode
LotRec<LOT_LEGACY_LOT_ID$> = LotId
LotRec<LOT_LEGACY_LOT_ID$> = LegacyLotId
LotRec<LOT_LEGACY_LOT_TYPE$> = LegacyLotType
LotRec<LOT_WO_LOG_ID$> = WONo
LotRec<LOT_PROD_SPEC_ID$> = ProdSpecId
LotRec<LOT_EPI_PART_NO$> = EpiPartNo
LotRec<LOT_PROD_VER_NO$> = ProdVerNo
Database_Services('WriteDataRow', 'LOT', NewLotId, LotRec)
If Error_Services('HasError') then
ErrorMessage = 'Error in ':Service:' service. ':Error_Services('GetMessage')
end else
If Error_Services('NoError') then
CreatedLotNumber = NewLotId
end else
ErrorMessage = 'Error in ':Service:' service. ':Error_Services('GetMessage')
end
end else
ErrorMessage = 'Error in ':Service:' service. LOT record "':NewLotId:'" already exists.'
ErrorMessage = 'Error in ':Service:' service. Failed to generate new LOT id. LOT record "':NewLotId:'" already exists.'
end
end else
ErrorMessage = 'Error in ':Service:' service. No lot ID passed in.'
ErrorMessage = 'Error in ':Service:' service. Failed to generate new LOT id.'
end
end else
ErrorMessage = 'Error in ':Service:' service. Lot Id ':LotId:' already exists for LegacyLotId ':LegacyLotId:'.'
end
end else
ErrorMessage = 'Error in ':Service:' service. Null LegacyLotId passed in.'
end
Case LotType EQ 'TW'
If ProdName NE '' then
@ -536,7 +582,6 @@ end service
Service CreateInitialLotOperationRecords(LotId)
ErrorMessage = ''
If LotId NE '' then
LotRec = Database_Services('ReadDataRow', 'LOT', LotId)
@ -545,9 +590,11 @@ Service CreateInitialLotOperationRecords(LotId)
ThisInitialProdOperations = Lot_Services('GetPrescribedOperationsByProdId', ProdId, LotType)
If Error_Services('NoError') AND ThisInitialProdOperations NE '' then
For each ProdOperation in ThisInitialProdOperations using @VM
ProdOperationRec = Database_Services('ReadDataRow', 'PRODUCT_OPERATION', ProdOperation)
OperationID = ProdOperationRec<PRODUCT_OPERATION_OPERATION_ID$>
OperationSequence = ProdOperationRec<PRODUCT_OPERATION_OPERATION_SEQUENCE$>
LotOperationRecID = Rti_Createguid()
If Not(RowExists('LOT_OPERATION', LotOperationRecID)) then
LotOperationRec = ''
@ -556,22 +603,25 @@ Service CreateInitialLotOperationRecords(LotId)
LotOperationRec<LOT_OPERATION_OPERATION_SEQUENCE$> = OperationSequence
LotOperationRec<LOT_OPERATION_REWORK$> = False$
Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationRecId, LotOperationRec)
TestRec = Database_Services('ReadDataRow', 'LOT', LotId)
If Error_Services('HasError') then
ErrorMessage = 'Error Writing Lot Operation Record.'
end
end else
ErrorMessage = 'Error in ':Service:' service. Lot Operation already existed, cannot overwrite.'
ErrorMessage = 'Lot Operation already existed, cannot overwrite'
end
Next Operation
end else
ErrorMessage = 'Error in ':Service:' service. Error getting prescribed operations for lot# ' : LotId
ErrorMessage = 'Error getting prescribed operations for lot# ' : LotId
end
end else
ErrorMessage = 'Error in ':Service:' service. Null LotID passed into service.'
ErrorMessage = 'Lot ID was null'
end
If ErrorMessage NE '' then
Error_Services('Add', ErrorMessage)
end
If ErrorMessage NE '' then Error_Services('Add', ErrorMessage)
end service
// Returns a @FM delimited list of operations in sequence
Service GetLotOperationSequence(LotId)
@ -604,9 +654,10 @@ end service
Service GetLotCurrOperationId(LotId)
ErrorMsg = ''
StartTick = GetTickCount()
MetricName = 'GetLotCurrOperationId'
ErrorMsg = ''
CurrOperation = ''
If LotID NE '' then
// Get them in sequence first
@ -1025,16 +1076,27 @@ Service ConvertLotRecordToJson(LotId, ItemURL, CurrUser, FullObject=BOOLEAN)
ErrorMessage = ''
JsonString = ''
If FullObject EQ '' then FullObject = True$
If FullObject EQ '' then
FullObject = True$
end
If RowExists('LOT', LotId) then
objJSON = ''
If SRP_JSON(objJSON, 'New', 'Object') then
LotRec = Database_Services('ReadDataRow', 'LOT', LotId)
If Error_Services('NoError') then
If SRP_JSON(objLot, 'New', 'Object') then
SRP_JSON(objLot, 'SetValue', 'LotId', LotId)
SRP_JSON(objLot, 'SetValue', 'LegacyLotId', LotRec<LOT_LEGACY_LOT_ID$>, 'String')
SRP_JSON(objLot, 'SetValue', 'LegacyLotType', LotRec<LOT_LEGACY_LOT_TYPE$>, 'String')
CanUserModifyLot = Lot_Services('CanUserModifyLot', CurrUser)
SRP_JSON(objLot, 'SetValue', 'CanUserModifyLot', CanUserModifyLot, 'Boolean')
SRP_JSON(objLot, 'SetValue', 'WorkOrderNo', LotRec<LOT_WO_LOG_ID$>, 'String')
SRP_JSON(objLot, 'SetValue', 'EpiPartNo', LotRec<LOT_EPI_PART_NO$>, 'String')
SRP_JSON(objLot, 'SetValue', 'Type', LotRec<LOT_TYPE$>)
SRP_JSON(objLot, 'SetValue', 'ProdId', LotRec<LOT_PROD_ID$>)
ProdSpecNo = LotRec<LOT_PROD_SPEC_ID$>
SRP_JSON(objLot, 'SetValue', 'ProdSpecNo', ProdSpecNo, 'String')
Begin Case
Case LotRec<LOT_TYPE$> = 'TW'
ProdName = XLATE('TEST_WAFER_PROD', LotRec<LOT_PROD_ID$>, TEST_WAFER_PROD_PART_NAME$, 'X')
@ -1047,15 +1109,24 @@ Service ConvertLotRecordToJson(LotId, ItemURL, CurrUser, FullObject=BOOLEAN)
SRP_JSON(objLot, 'SetValue', 'VendorPartNo', LotRec<LOT_VENDOR_PART_NO$>)
SRP_JSON(objLot, 'SetValue', 'VendorLotNo', LotRec<LOT_VENDOR_LOT_NO$>)
SRP_JSON(objLot, 'SetValue', 'Vendor', LotRec<LOT_VENDOR_CODE$>)
CurrOperation = Lot_Services('GetLotCurrOperationId', LotId)
CurrOperation = XLATE('LOT_OPERATION', CurrOperation, LOT_OPERATION_OPERATION_ID$, 'X')
CurrLotOperationId = Lot_Services('GetLotCurrOperationId', LotId)
CurrOperation = XLATE('LOT_OPERATION', CurrLotOperationId, LOT_OPERATION_OPERATION_ID$, 'X')
CurrOperationDesc = XLATE('OPERATION', CurrOperation, OPERATION_OPERATION_DESCRIPTION$, 'X')
SRP_JSON(objLot, 'SetValue', 'CurrLotOperationId', CurrLotOperationId)
SRP_JSON(objLot, 'SetValue', 'CurrOperation', CurrOperation)
SRP_JSON(objLot, 'SetValue', 'CurrOperationDesc', CurrOperationDesc, 'String')
MostRecentEventId = LotRec<LOT_MOST_RECENT_LOT_EVENT_ID$>
MostRecentEventDtmIConv = Xlate('LOT_EVENT', MostRecentEventId, LOT_EVENT_EVENT_DATETIME$, 'X')
MostRecentEventDtmOConv = OConv(MostRecentEventDtmIConv, 'DT')
SRP_JSON(objLot, 'SetValue', 'MostRecentEventDateTime', MostRecentEventDtmOConv)
if LotRec<LOT_LEGACY_LOT_ID$> NE '' then
ActiveRTFId = Return_To_Fab_Services('GetOpenReturnToFabRecordIdByCassId', LotRec<LOT_LEGACY_LOT_ID$>)
end else
ActiveRTFId = Return_To_Fab_Services('GetOpenReturnToFabRecordIdByCassId', LotId)
end
SRP_JSON(objLot, 'SetValue', 'ActiveRTFId', ActiveRTFId, 'String')
If FullObject then
// Events Array
//Events Array
EventsArrayJson = ''
If SRP_Json(EventsArrayJson, 'New', 'Array') then
LotEventKeys = Lot_Event_Services('GetLotEventsInSequence', LotId)
@ -1085,40 +1156,41 @@ Service ConvertLotRecordToJson(LotId, ItemURL, CurrUser, FullObject=BOOLEAN)
end else
ErrorMessage = 'Error Creating Events JSON Array'
end
// Operations Array
OperationsArrayJson = ''
If SRP_Json(OperationsArrayJson, 'New', 'Array') then
LotOperationKeys = Lot_Services('GetLotOperationSequence', LotId)
for each LotOperationKey in LotOperationKeys using @FM
objOperation = ''
OperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationKey)
If SRP_Json(objOperation, 'New', 'Object') then
SRP_JSON(objOperation, 'SetValue', 'LotOperationId', LotOperationKey)
SRP_JSON(objOperation, 'SetValue', 'LotId', OperationRec<LOT_OPERATION_LOT_ID$>)
SRP_JSON(objOperation, 'SetValue', 'OperationId', OperationRec<LOT_OPERATION_OPERATION_ID$>)
SRP_JSON(objOperation, 'SetValue', 'DatetimeIn', OConv(OperationRec<LOT_OPERATION_DATETIME_IN$>, 'DT'))
SRP_JSON(objOperation, 'SetValue', 'DatetimeOut', Oconv(OperationRec<LOT_OPERATION_DATETIME_OUT$>, 'DT'))
SRP_JSON(objOperation, 'SetValue', 'EquipmentId', OperationRec<LOT_OPERATION_EQUIPMENT_ID$>)
SRP_JSON(objOperation, 'SetValue', 'WaferInQty', OperationRec<LOT_OPERATION_WAFER_IN_QTY$>)
SRP_JSON(objOperation, 'SetValue', 'WaferOutQty', OperationRec<LOT_OPERATION_WAFER_OUT_QTY$>)
SRP_JSON(objOperation, 'SetValue', 'OperatorInId', OperationRec<LOT_OPERATION_OPERATOR_IN_ID$>)
SRP_JSON(objOperation, 'SetValue', 'OperatorOutId', OperationRec<LOT_OPERATION_OPERATOR_OUT_ID$>)
SRP_JSON(objOperation, 'SetValue', 'OperationSequence', OperationRec<LOT_OPERATION_OPERATION_SEQUENCE$>)
SRP_JSON(objOperation, 'SetValue', 'Rework', OperationRec<LOT_OPERATION_REWORK$>)
SRP_JSON(objOperation, 'SetValue', 'DatetimeStart', OConv(OperationRec<LOT_OPERATION_DATETIME_START$>, 'DT'))
SRP_JSON(objOperation, 'SetValue', 'DatetimeStop', OConv(OperationRec<LOT_OPERATION_DATETIME_STOP$>, 'DT'))
SRP_JSON(OperationsArrayJson, 'Add', objOperation)
SRP_JSON(objOperation, 'Release')
ThisLotOperationJsonString = Lot_Operation_Services('ConvertRecordToJson', LotOperationKey)
If SRP_Json(objLotOperation, 'PARSE', ThisLotOperationJsonString) EQ '' then
SRP_Json(OperationsArrayJson, 'Add', objLotOperation)
SRP_Json(objLotOperation, 'Release')
end
Next LotOperationKey
SRP_JSON(objLot, 'Set', 'LotOperations', OperationsArrayJson)
SRP_JSON(OperationsArrayJson, 'Release')
Recipes = PSN_Services('GetAllMetrologyRecipes', ProdSpecNo, True$, True$, True$, True$)
//Add in all lot recipe parameters
If SRP_JSON(objRecipes, 'New', 'Array') then
for each Recipe in Recipes using @FM
//ToolClass : @VM : Recipe : @VM : Stage
ToolClass = Recipe<1,1>
RecipeName = Recipe<1,2>
Stage = Recipe<1,3>
If SRP_JSON(objRecipe, 'New', 'Object') then
SRP_JSON(objRecipe, 'SetValue', 'ToolClass', ToolClass, 'String')
SRP_JSON(objRecipe, 'SetValue', 'RecipeName', RecipeName, 'String')
SRP_JSON(objRecipe, 'SetValue', 'StageName', Stage, 'String')
SRP_JSON(objRecipes, 'Add', objRecipe)
SRP_JSON(objRecipe, 'Release')
end
Next Recipe
SRP_JSON(objLot, 'Set', 'AllRecipes', objRecipes)
SRP_JSON(objRecipes, 'Release')
end
end else
ErrorMessage = 'Error Creating Operations JSON Array'
end
end
SRP_JSON(objJSON, 'Set', 'Lot', objLot)
SRP_JSON(objLot, 'Release')
end else
@ -1135,12 +1207,10 @@ Service ConvertLotRecordToJson(LotId, ItemURL, CurrUser, FullObject=BOOLEAN)
end else
ErrorMessage = 'Invalid or null lot number passed to routine.'
end
If ErrorMessage EQ '' then
Response = JsonString
end else
If ErrorMessage NE '' then
Error_Services('Add', ErrorMessage)
end
Response = JsonString
end service
@ -1339,7 +1409,7 @@ Service ReduceLotWaferCount(LotId, ReductionQty, OperatorId)
// Write Lot Event
Lot_Event_Services('CreateLotEvent', LotId, Datetime(), 'REDUCE_WAFER_QTY', 'Reduced wafer count by ' : ReductionQty, '', OperatorId, False$, '')
if LotNewWfrQty EQ 0 AND LotType EQ 'TW' then
ServiceParms = 'AutoCloseTestWaferLot' : SD$ : LotId : SD$ : 'SYSTEM'
ServiceParms = 'AutoCloseTestWaferLot' : @VM : LotId : @VM : 'SYSTEM'
Service_Services('PostProcedure', 'LOT_SERVICES', ServiceParms)
If Error_Services('HasError') then
Recipients = Xlate('NOTIFICATION', 'FI_SUPPORT', NOTIFICATION_USER_ID$, 'X')
@ -1510,11 +1580,37 @@ Service CreateNewVoidedLotRecord(LotId, LegacyLotId, LotType=LOT_TYPES, Username
EndTick = GetTickCount()
Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick)
If ErrorMessage NE '' then Error_Services('Add', ErrorMessage)
end service
Service CanUserModifyLot(UserId)
Begin Case
Case MemberOf(UserId, 'OI_ADMIN')
Response = true$
Case MemberOf(UserId, 'ENGINEERING')
Response = true$
Case MemberOf(UserId, 'ENG_TECH')
Response = true$
Case MemberOf(UserId, 'SUPERVISOR')
Response = true$
Case MemberOf(UserId, 'LEAD')
Response = true$
Case UserId EQ 'SYSTEM'
Response = true$
Case Otherwise$
Response = false$
End Case
end service
//----------------------------------------------------------------------------------------------------------------------
// Internal GoSubs
//----------------------------------------------------------------------------------------------------------------------

View File

@ -132,4 +132,3 @@ CreateHALItem:
end
return

View File

@ -11,6 +11,19 @@ Function Metrology_Services(@Service, @Params)
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.
Surface Scan Tool Types:
Tencor
SP1
Thickness tool types:
Biorad
Stratus
Resistivity (HgCV) Tool Types:
CDE
4PP
SRP
Parameters :
Service [in] -- Name of the service being requested
Param1-10 [in/out] -- Additional request parameter holders
@ -70,7 +83,7 @@ $Insert RLIST_EQUATES
$Insert WM_OUT_EQUATES
$Insert IQS_VIOL_DATA_EQUATES
Common /MetrologyServices/ MachineType@, RDSNo@
Common /MetrologyServices/ MachineType@, LegacyLotId@
Equ RETRY_ATTEMPTS$ TO 3
Equ MINUTES_UNTIL_RETRY$ TO 3
@ -93,12 +106,12 @@ Equ Comma$ to ','
Declare subroutine SRP_Stopwatch, Error_Services, obj_Tables, Metrology_Services, obj_RDS_Test, SRP_JSON
Declare subroutine RTI_Set_Debugger, Database_Services, Btree.Extract, Set_Status, QA_Services, obj_Notes
Declare subroutine Logging_Services, SRP_Send_Mail, SRP_Run_Command, PM_Services, Httpclient_Services
Declare subroutine Tool_Services, Mona_Services, Reactor_Services
Declare subroutine Tool_Services, Mona_Services, Reactor_Services, Met_Test_Services, Met_Test_Services
Declare function SRP_Sort_Array, Metrology_Services, obj_RDS_Test, obj_Test_Point_Map, Database_Services, UCase
Declare function Work_Order_Services, SRP_JSON, Logging_Services, Environment_Services, SRP_Trim, Min, Max
Declare function QA_Services, SRP_Join_Arrays, Get_Status, Obj_Clean_Insp, Datetime, SRP_Datetime
Declare function Httpclient_Services, PM_Services, Signature_Services, SRP_Array, Math_Services
Declare function Tool_Class_Services, obj_wo_mat
Declare function Tool_Class_Services, obj_Wo_Mat, Met_Test_Services, Lot_Services
Declare function SRP_String
LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\Metrology'
@ -163,6 +176,12 @@ end
Return Response else ''
//----------------------------------------------------------------------------------------------------------------------
// Service Parameter Options
//----------------------------------------------------------------------------------------------------------------------
Options MACHINE_TYPES = 'Tencor', 'HgCV', 'CDE', 'Biorad', 'Stratus', 'SP1', 'SPV', 'SRP'
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Services
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -387,7 +406,7 @@ end service
//
// Looks for available Metrology files that are ready to be imported into the MES system.
//----------------------------------------------------------------------------------------------------------------------
Service ImportMetrologyFiles(Machine)
Service ImportMetrologyFiles(Machine=MACHINE_TYPES)
If Machine NE '' then
hSysLists = Database_Services('GetTableHandle', 'SYSLISTS')
@ -743,7 +762,7 @@ Service ImportStratusData(RunData, ResourceID, PSN)
ThickAvg = RunData<12>
Positions = ''
DataPoints = ''
ToolClass = Xlate('TOOL', Tool, 'CLASS', 'X')
Loop
Position = Trim(RunData<FieldPos>)
DataPoint = Trim(RunData<FieldPos + Offset>)
@ -767,17 +786,69 @@ Service ImportStratusData(RunData, ResourceID, PSN)
Case RowExists('WM_OUT', Cassette)
WorkOrderNo = Field(Cassette, '*', 1)
CassNo = Field(Cassette, '*', 3)
RDSNo@ = Cassette ; // This is used for logging purposes.
IsEpiPro = true$
LegacyLotId@ = Cassette
IsEpiPro = True$
LegacyLotType = 'WM_OUT'
Case RowExists('RDS', RDSNo)
WorkOrderNo = Xlate('RDS', RDSNo, 'WO', 'X')
CassNo = Xlate('RDS', RDSNo, 'CASS_NO', 'X')
RDSNo@ = RDSNo ; // This is used for logging purposes.
LegacyLotId@ = RDSNo
LegacyLotType = 'RDS'
Case Otherwise$
Error_Services('Add', 'Unrecognized cassette ID ':Cassette:'.')
End Case
If Error_Services('NoError') then
LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', LegacyLotId@, LegacyLotType)
If LotId NE '' then
If DCount(LotId, @VM) EQ 1 then
// Import into new metrology data structures
If Datapoints NE '' then
Done = False$
For each DataPoint in DataPoints using @VM setting vPos
Slot = Positions<0, vPos>
MetTestId = Met_Test_Services('CreateMetTest', LotId, LegacyLotId@, ToolClass, Recipe)
If Error_Services('NoError') then
Met_Test_Services('SetPropsAndLimits', MetTestId)
If Error_Services('HasError') then
// Failed to set property names and limits based on input data from metrology file. Log this and continue importing data.
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
Error_Services('Clear')
end
Met_Test_Services('SetMetTestTool', MetTestId, Tool)
If Error_Services('NoError') then
Met_Test_Services('SetMetTestDtm', MetTestId, TimeStamp)
If Error_Services('NoError') then
Met_Test_Services('SetMetTestSlot', MetTestId, Slot)
If Error_Services('NoError') then
Met_Test_Services('AddMetTestData', MetTestId, '', DataPoint)
If Error_Services('HasError') then
Done = True$
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
Next DataPoint
end else
ErrorMsg = 'Error in ':Service:' service. No DataPoints to import.'
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg)
end
end else
Swap @VM with ',' in LotId
ErrorMsg = 'Error in ':Service:' service. Number of lot ids returned does not equal 1. Lot ids: ':LotId
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg)
end
end
// Update WO_MAT record
StdDev = ''
@ -804,15 +875,15 @@ Service ImportStratusData(RunData, ResourceID, PSN)
end
Database_Services('WriteDataRow', 'WO_MAT', WOMatKey, WOMatRec, True$, False$, True$)
If Error_Services('HasError') then
Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
// Update the WM_OUT record for EpiPro
If IsEpiPro then
NumVals = 0
WMORec = Database_Services('ReadDataRow', 'WM_OUT', RDSNo@)
WMORec = Database_Services('ReadDataRow', 'WM_OUT', LegacyLotId@)
For each Wafer in Positions using @VM setting dPos
If Wafer NE '' then
WMORec<WM_OUT_MU_WAFER_THK_RESULT$, Wafer> = DataPoints<0, dPos>
@ -830,7 +901,7 @@ Service ImportStratusData(RunData, ResourceID, PSN)
StdDev = Math_Services('GetStdDev', Vals, StdDevType)
StdDev = OConv(IConv(StdDev, 'MD3'), 'MD3')
end
Database_Services('WriteDataRow', 'WM_OUT', RDSNo@, WMORec, True$, False$, True$)
Database_Services('WriteDataRow', 'WM_OUT', LegacyLotId@, WMORec, True$, False$, True$)
end
// Update WO_MAT_QA record
@ -882,15 +953,15 @@ Service ImportStratusData(RunData, ResourceID, PSN)
Next Profile
Database_Services('WriteDataRow', 'WO_MAT_QA', WOMatQAID, WOMatQARec, True$, False$, True$)
If Error_Services('NoError') then
Metrology_Services('LogResults', RDSNo@, Machine, 'UID000', Service : ' : Success.')
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID000', Service : ' : Success.')
end else
Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end service
@ -1037,6 +1108,56 @@ Service ImportBioRadData(RunData, ResourceID, IsViewerFile, PSN, FileName)
Swap ' AM' with 'AM' in Timestamp
Swap ' PM' with 'PM' in Timestamp
Timestamp = IConv(Timestamp,'DT')
LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', RDSKeyID, 'RDS')
If LotId NE '' then
If DCount(LotId, @VM) EQ 1 then
// Import into new metrology data structures
ToolId = Field(Filename, ' ', 2, 1)
ToolClass = Xlate('TOOL', ToolId, 'CLASS', 'X')
MetTestId = Met_Test_Services('CreateMetTest', LotId, RDSKeyID, ToolClass, ScanRecipe, '', RunDataLayer, RunDataZone, '')
If Error_Services('NoError') then
Met_Test_Services('SetPropsAndLimits', MetTestId)
If Error_Services('HasError') then
// Failed to set property names and limits based on input data from metrology file. Log this and continue importing data.
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
Error_Services('Clear')
end
Met_Test_Services('SetMetTestTool', MetTestId, ToolId)
If Error_Services('NoError') then
Met_Test_Services('SetMetTestDtm', MetTestId, TimeStamp)
If Error_Services('NoError') then
If RawDataPoints NE '' then
Done = False$
For each DataPoint in RawDataPoints using @VM setting vPos
Position = Positions<0, vPos>
Met_Test_Services('AddMetTestData', MetTestId, Position, DataPoint)
If Error_Services('HasError') then
Done = True$
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
Until Done
Next DataPoint
end else
ErrorMsg = 'Error in ':Service:' service. No DataPoints to import.'
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg)
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Swap @VM with ',' in LotId
ErrorMsg = 'Error in ':Service:' service. Number of lot ids returned does not equal 1. Lot ids: ':LotId
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg)
end
end
RDSLayerKeyID = RDSKeyID : '*' : RunDataLayer
NumDataPoints = DCount(DataPoints, @VM)
RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID)
@ -1255,7 +1376,6 @@ Service ImportBioRadData(RunData, ResourceID, IsViewerFile, PSN, FileName)
end service
Service ImportCDEQualData(RunData, ResourceID, PSN)
Machine = 'CDE'
@ -1288,7 +1408,6 @@ Service ImportCDEQualData(RunData, ResourceID, PSN)
end service
Service ImportCDEData(RunData, ResourceID, IsViewerFile, PSN)
Machine = 'CDE'
@ -1381,6 +1500,57 @@ Service ImportCDEData(RunData, ResourceID, IsViewerFile, PSN)
Swap ' PM' with 'PM' in Timestamp
Timestamp = IConv(Timestamp,'DT')
LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', RDSKeyID, 'RDS')
If LotId NE '' then
If DCount(LotId, @VM) EQ 1 then
// Import into new metrology data structures
ToolRecipe = Trim(Field(ScanRecipe, '\', 1, 1))
ToolPattern = Trim(Field(ScanRecipe, '\', 2, 1))
ToolClass = Xlate('TOOL', ToolId, 'CLASS', 'X')
MetTestId = Met_Test_Services('CreateMetTest', LotId, RDSKeyID, ToolClass, ToolRecipe, ToolPattern, RunDataLayer, RunDataZone)
If Error_Services('NoError') then
Met_Test_Services('SetPropsAndLimits', MetTestId)
If Error_Services('HasError') then
// Failed to set property names and limits based on input data from metrology file. Log this and continue importing data.
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
Error_Services('Clear')
end
Met_Test_Services('SetMetTestTool', MetTestId, ToolId)
If Error_Services('NoError') then
Met_Test_Services('SetMetTestDtm', MetTestId, TimeStamp)
If Error_Services('NoError') then
If RawDatapoints NE '' then
Done = False$
TempDataPoints = OConv(IConv(RawDatapoints, 'MD':Decimals), 'MD':Decimals)
For each DataPoint in TempDataPoints using @VM setting vPos
Position = Positions<0, vPos>
Met_Test_Services('AddMetTestData', MetTestId, Position, DataPoint)
If Error_Services('HasError') then
Done = True$
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
Until Done
Next DataPoint
end else
ErrorMsg = 'Error in ':Service:' service. No DataPoints to import.'
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg)
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Swap @VM with ',' in LotId
ErrorMsg = 'Error in ':Service:' service. Number of lot ids returned does not equal 1. Lot ids: ':LotId
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg)
end
end
RDSLayerKeyID = RDSKeyID : '*' : RunDataLayer
NumDataPoints = DCount(DataPoints, @VM)
RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID)
@ -1549,7 +1719,7 @@ Service ImportHgCVData(RunData, ResourceID, IsViewerFile, PSN)
DataIndex = RDS_TEST_READ_HGCV1_RES$
DTMIndex = RDS_TEST_TEST_RUN_HGCV_DTM$
Metrology_Services('LogResults', RDSKeyID, Machine, 'UID000', Service : ' : ' : 'Beginning ImportHgCVData')
RDSNo@ = RDSKeyID
LegacyLotId@ = RDSKeyID
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSKeyID)
If Error_Services('NoError') then
WorkOrderNo = RDSRec<RDS_WO$>
@ -1606,23 +1776,83 @@ Service ImportHgCVData(RunData, ResourceID, IsViewerFile, PSN)
Positions = ''
DataPoints = ''
HgCVDataPoints = ''
PhaseDataPoints = ''
Loop
Position = Trim(RunData<FieldPos>)
HgCVDataPoint = Trim(RunData<FieldPos + Offset>)
PhaseDataPoint = Trim(RunData<FieldPos + PhaseOffset>)
Until Position EQ ''
Positions := Position : @VM
HgCVDataPoints := HgCVDataPoint : @VM
PhaseDataPoints := PhaseDataPoint : @VM
FieldPos += FieldPosIncrement
Repeat
Positions[-1, 1] = '' ; // Strip final @VM
HgCVDataPoints[-1, 1] = '' ; // Strip final @VM
PhaseDataPoints[-1, 1] = '' ; // Strip final @VM
RawDataPoints = HgCVDataPoints
RawPhaseDataPoints = PhaseDataPoints
HgCVDataPoints = Iconv(HgCVDataPoints, 'MD' : Decimals)
PhaseDataPoints = Iconv(PhaseDataPoints, 'MD' : Decimals)
Swap ' AM' with 'AM' in Timestamp
Swap ' PM' with 'PM' in Timestamp
Timestamp = IConv(Timestamp,'DT')
// Recipe field 21
// Pattern field 24
LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', RDSKeyID, 'RDS')
If LotId NE '' then
If DCount(LotId, @VM) EQ 1 then
// Import into new metrology data structures
ToolId = RunData<2>
ToolRecipe = RunData<21>
ToolPattern = RunData<24>
ToolClass = Xlate('TOOL', ToolId, 'CLASS', 'X')
MetTestId = Met_Test_Services('CreateMetTest', LotId, RDSKeyID, ToolClass, ToolRecipe, ToolPattern, RunDataLayer, RunDataZone)
If Error_Services('NoError') then
Met_Test_Services('SetPropsAndLimits', MetTestId)
If Error_Services('HasError') then
// Failed to set property names and limits based on input data from metrology file. Log this and continue importing data.
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
Error_Services('Clear')
end
Met_Test_Services('SetMetTestTool', MetTestId, ToolId)
If Error_Services('NoError') then
Met_Test_Services('SetMetTestDtm', MetTestId, TimeStamp)
If Error_Services('NoError') then
If RawDataPoints NE '' then
Done = False$
For each DataPoint in RawDataPoints using @VM setting vPos
Position = Positions<0, vPos>
PhaseDataPoint = RawPhaseDataPoints<0, vPos>
Met_Test_Services('AddMetTestData', MetTestId, Position, DataPoint, PhaseDataPoint)
If Error_Services('HasError') then
Done = True$
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
Until Done
Next DataPoint
end else
ErrorMsg = 'Error in ':Service:' service. No DataPoints to import.'
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg)
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Swap @VM with ',' in LotId
ErrorMsg = 'Error in ':Service:' service. Number of lot ids returned does not equal 1. Lot ids: ':LotId
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg)
end
end
RDSLayerKeyID = RDSKeyID : '*' : RunDataLayer
NumDataPoints = DCount(HgCVDataPoints, @VM)
RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID)
@ -1673,7 +1903,6 @@ Service ImportHgCVData(RunData, ResourceID, IsViewerFile, PSN)
PhaseDataPoints[-1, 1] = '' ; // Strip final @VM
PhaseDataPoints = Iconv(PhaseDataPoints, 'MD' : Decimals)
DataPoints = HgCVDataPoints
* GoSub CalculateQAData
Response = QA_Services('CalculateHgCVData', Datapoints)
HgCVMin = Response<0, 2>
HgCVMax = Response<0, 3>
@ -1687,23 +1916,12 @@ Service ImportHgCVData(RunData, ResourceID, IsViewerFile, PSN)
DataPoints = PhaseDataPoints
Response = QA_Services('CalculateHgCVData', Datapoints)
* GoSub CalculateQAData
PhaseMin = Response<0, 2>
PhaseMax = Response<0, 3>
PhaseAvg = Response<0, 1>
PhaseEdgeMean = Response<0, 4>
PhaseRangePct = Response<0, 5>
// Format data. Round to significant digits.
* HgCVAvg = Oconv(Iconv(Oconv(HgCVAvg, 'MD3L'), 'MD3L'), 'MD3L')
* PhaseAvg = Oconv(Iconv(Oconv(PhaseAvg, 'MD3L'), 'MD3L'), 'MD3L')
* HgCVMin = Oconv(Iconv(Oconv(HgCVMin, 'MD3L'), 'MD3L'), 'MD3L')
* HgCVMax = Oconv(Iconv(Oconv(HgCVMax, 'MD3L'), 'MD3L'), 'MD3L')
* PhaseMin = Oconv(Iconv(Oconv(PhaseMin, 'MD3L'), 'MD3L'), 'MD3L')
* PhaseMax = Oconv(Iconv(Oconv(PhaseMax, 'MD3L'), 'MD3L'), 'MD3L')
* HgCVEdgeMean = OConv(IConv(HgCVEdgeMean, 'MD3L'), 'MD3L')
* PhaseEdgeMean = Oconv(IConv(PhaseEdgeMean, 'MD3L'), 'MD3L')
* HgCVRangePct = Oconv(Iconv(HgCVRangePct, 'MD3L'), 'MD3L')
* PhaseRangePct = Oconv(Iconv(PhaseRangePct, 'MD3L'), 'MD3L')
WOMatQARec<WO_MAT_QA_RESULT$, vPos> = HgCVAvg : @SVM : PhaseAvg
WOMatQARec<WO_MAT_QA_MIN_RESULT$, vPos> = HgCVMin : @SVM : PhaseMin
WOMatQARec<WO_MAT_QA_MAX_RESULT$, vPos> = HgCVMax : @SVM : PhaseMax
@ -1853,13 +2071,98 @@ Service ImportTencorData(RunData)
SoDMin = RunData<41>
ScanTool = RunData<43>
Swap '%' with ' ' in ScanTool
RDSNo@ = RDSKeyID
LegacyLotId@ = RDSKeyID
Convert @Lower_Case to @Upper_Case in ScanTool
Swap ' AM' with 'AM' in Timestamp
Swap ' PM' with 'PM' in Timestamp
Timestamp = IConv(Timestamp,'DT')
SODWaferArray = ''
WaferNos = ''
SODVals = ''
SortVals = ''
SODStartTime = Time()
SODWaferArray = QA_Services('GetSODPerWafer', RDSKeyID, ScanRecipe, Timestamp)
SODStopTime = Time()
TimeTaken = SODStopTime - SODStartTime
LogData = ''
LogData<1> = Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTS')
LogData<2> = MachineType@
LogData<3> = LegacyLotId@
LogData<4> = 'Time taken to import SOD data: ':TimeTaken:' seconds.'
Logging_Services('AppendLog', objSODPerfLog, LogData, @RM, @FM)
If SODWaferArray NE '' then
WaferNos = SODWaferArray<1>
SODVals = SODWaferArray<2>
SortVals = SODWaferArray<3>
For each WaferNo in WaferNos using @VM
If WaferNo NE '' then QA_Services('PostWaferImageRequest', RDSKeyID, WaferNo, ScanRecipe)
Next Wafer
end
LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', RDSKeyID, 'RDS')
If LotId NE '' then
If DCount(LotId, @VM) EQ 1 then
// Import into new metrology data structures
MetTestId = Met_Test_Services('CreateMetTest', LotId, RDSKeyID, '', ScanRecipe)
If Error_Services('NoError') then
Met_Test_Services('SetPropsAndLimits', MetTestId)
If Error_Services('HasError') then
// Failed to set property names and limits based on input data from metrology file. Log this and continue importing data.
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
Error_Services('Clear')
end
Met_Test_Services('SetMetTestTool', MetTestId, ScanTool)
If Error_Services('NoError') then
Met_Test_Services('SetMetTestDtm', MetTestId, TimeStamp)
If Error_Services('NoError') then
// Add SORT property to Tencor surfscan MET_TEST - 'PASS' or 'FAIL' - no min or max
//Met_Test_Services('AddProperty', MetTestId, 'SURFACE_SCAN_SORT')
If Error_Services('NoError') then
// Prop 1: SURFACE_SCAN_SUM_OF_DEFECTS_MIN
// Prop 2: SURFACE_SCAN_SUM_OF_DEFECTS_MAX
// Prop 3: SURFACE_SCAN_SUM_OF_DEFECTS_AVG
// Prop 4: SURFACE_SCAN_SUM_OF_DEFECTS (per wafer)
// Prop 5: SURFACE_SCAN_HAZE_AVG
// Prop 6: SURFACE_SCAN_SORT (per wafer)
Met_Test_Services('AddProperty', MetTestId, 'SURFACE_SCAN_SUM_OF_DEFECTS_MIN')
Met_Test_Services('AddProperty', MetTestId, 'SURFACE_SCAN_SUM_OF_DEFECTS_MAX')
Met_Test_Services('AddProperty', MetTestId, 'SURFACE_SCAN_SUM_OF_DEFECTS_AVG')
Met_Test_Services('AddProperty', MetTestId, 'SURFACE_SCAN_SUM_OF_DEFECTS')
Met_Test_Services('AddProperty', MetTestId, 'SURFACE_SCAN_HAZE_AVG')
Met_Test_Services('AddProperty', MetTestId, 'SURFACE_SCAN_SORT')
Met_Test_Services('AddMetTestData', MetTestId, '', SoDMin, SoDMax, SoDAvg, '', HazeAvg)
If Error_Services('HasError') then
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
For each WaferNo in WaferNos using @VM setting vPos
If WaferNo NE '' then
Met_Test_Services('AddMetTestData', MetTestId, WaferNo, '', '', '', SODVals<0, vPos>, '', SortVals<0, vPos>)
If Error_Services('HasError') then
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end
Next WaferNo
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Swap @VM with ',' in LotId
ErrorMsg = 'Error in ':Service:' service. Number of lot ids returned does not equal 1. Lot ids: ':LotId
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg)
end
end
If RowExists('RDS', RDSKeyID) then
// Try to read the CleanInsp datarow. Use this to identify the RDSKeyID.
ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSKeyID)
@ -1893,30 +2196,11 @@ Service ImportTencorData(RunData)
NumWfrs = 0
Locate ScanRecipe In SpecRecipeList Using @VM Setting RecipeIndex then
// Recipe found in spec list
SpecSampleQty = CleanInspRec<CLEAN_INSP_SPEC_SS_SAMP_QTY$, RecipeIndex>
SODWaferArray = ''
SODStartTime = Time()
SODWaferArray = QA_Services('GetSODPerWafer', RDSKeyID, ScanRecipe, Timestamp)
SODStopTime = Time()
TimeTaken = SODStopTime - SODStartTime
LogData = ''
LogData<1> = Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTS')
LogData<2> = MachineType@
LogData<3> = RDSNo@
LogData<4> = 'Time taken to import SOD data: ':TimeTaken:' seconds.'
Logging_Services('AppendLog', objSODPerfLog, LogData, @RM, @FM)
If SODWaferArray NE '' then
WaferNos = SODWaferArray<1>
SODVals = SODWaferArray<2>
SortVals = SODWaferArray<3>
For each Wfr in SODVals using @VM setting vPos
NumWfrs += (Wfr NE '')
Next Wfr
For each WaferNo in WaferNos using @VM
If WaferNo NE '' then
CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$, ScanIndex, WaferNo> = SODVals<1,WaferNo>
CleanInspRec<CLEAN_INSP_SCAN_SORT_PER_WAFER$, ScanIndex, WaferNo> = SortVals<1,WaferNo>
QA_Services('PostWaferImageRequest', RDSKeyID, WaferNo, ScanRecipe)
end
Next Wafer
end
@ -1969,7 +2253,7 @@ Service ImportTencorData(RunData)
// If statement to gate from production below
PostStartTime = Time()
if Indexc(ScanRecipe, 'POST', 1) then
//Locate 'POST' in ScanRecipe Using "" setting pPos then
// Locate 'POST' in ScanRecipe Using "" setting pPos then
ReactRunRec = Xlate('REACT_RUN',RDSKeyID, '', 'X')
WONo = ReactRunRec<REACT_RUN_WO_NO$>;//WONo
WOStep = ReactRunRec<REACT_RUN_WO_STEP$>;//WOStep
@ -1978,19 +2262,19 @@ Service ImportTencorData(RunData)
PSNo = XLATE('RDS',RDSKeyID,RDS_PROD_SPEC_ID$,'X');//PSNo
DefectSpec = Xlate('PRS_STAGE', PSNo : '*LWI', PRS_STAGE_SURF_DEFECTS$, 'X');//Since there is no set spec for a non-existent stage we need to take one from the unloading step.
HazeSpec = Xlate('PRS_STAGE', PSNo : '*LWI', PRS_STAGE_SURF_HAZE$, 'X');//Since there is no set spec for a non-existent stage we need to take one from the unloading step.
//Check if CI was created already(usually during cleans) JRO-9-28
// Check if CI was created already(usually during cleans) JRO-9-28
CIStages = ReactRunRec<REACT_RUN_CI_STAGE$>
Locate 'POST' in CIStages using @VM setting sPos then
//Existing POST CI record found, fetch it.
// Existing POST CI record found, fetch it.
CINo = ReactRunRec<REACT_RUN_CI_NO$,sPos>
CleanInspRec = Xlate('CLEAN_INSP', CINo,'','X')
IF CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$> NE '' THEN
//Append a value mark to the end of the field so that we can add another set of data
// Append a value mark to the end of the field so that we can add another set of data
CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$> = CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$> : @VM
END
exists = True$
end else
//No Exisiting POST CI record found, Create new CI record
// No Exisiting POST CI record found, Create new CI record
exists = False$
oCIParms = ''
oCIParms = WONo:@RM
@ -2019,28 +2303,18 @@ Service ImportTencorData(RunData)
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_INSP_TEST_RUN_DTM$, -1, 0, Timestamp)
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SPEC_SURFSCAN_RECIPE$, -1, 0, ScanRecipe)
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SPEC_SURF_DEFECTS$, -1, 0, DefectSpec)
//Here I am attempting to create the scan details.
SODWaferArray = ''
SODWaferArray = QA_Services('GetSODPerWafer', RDSKeyID, ScanRecipe, Timestamp)
// Here I am attempting to create the scan details.
If SODWaferArray NE '' then
WaferNos = SODWaferArray<1>
SODVals = SODWaferArray<2>
SortVals = SODWaferArray<3>
NumRecipes = DCount(CleanInspRec<CLEAN_INSP_SCAN_RECIPE$>, @VM)
NumWfrs = ''
For each Wfr in SODVals using @VM setting vPos
NumWfrs += (Wfr NE '')
Next Wfr
For each WaferNo in WaferNos using @VM
If WaferNo NE '' then
CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$, NumRecipes, WaferNo> = SODVals<1,WaferNo>
CleanInspRec<CLEAN_INSP_SCAN_SORT_PER_WAFER$, NumRecipes, WaferNo> = SortVals<1,WaferNo>
QA_Services('PostWaferImageRequest', RDSKeyID, WaferNo, ScanRecipe)
end
Next Wafer
end
if exists Eq False$ then
If exists EQ False$ then
oCIParms := CleanInspRec ;
CINo = obj_Clean_Insp('Create',oCIParms)
If Error_Services('NoError') then
@ -2053,7 +2327,7 @@ Service ImportTencorData(RunData)
LogData = ''
LogData<1> = Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTS')
LogData<2> = MachineType@
LogData<3> = RDSNo@
LogData<3> = LegacyLotId@
LogData<4> = 'Time taken to import POST data: ':TimeTaken:' seconds.'
Logging_Services('AppendLog', objPOSTPerfLog, LogData, @RM, @FM)
end else
@ -2062,7 +2336,7 @@ Service ImportTencorData(RunData)
ErrorMessage = 'Failed to create CLEAN_INSP record. Error UID002.'
end
end else
//write to existing CI rec.
// Write to existing CI rec.
obj_Tables('WriteRec','CLEAN_INSP':@RM:CINo:@RM:@RM:CleanInspRec)
end
end else
@ -2117,17 +2391,64 @@ Service ImportSP1Data(RunData)
end
ScanTool = RunData<43>
DCNMM2 = RunData<44>
* Swap '%' with ' ' in ScanTool
// The 4th character can be 0 or %, but needs to be ' ' in OpenInsight
ScanTool[4,1] = ' '
Convert @Lower_Case to @Upper_Case in ScanTool
Convert @Lower_Case to @Upper_Case in CompareScanRecipe
* Convert ' ' to '' in CompareScanRecipe
Swap ' AM' with 'AM' in Timestamp
Swap ' PM' with 'PM' in Timestamp
Timestamp = IConv(Timestamp,'DT')
RDSNo@ = RDSKeyID
LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', RDSKeyID, 'RDS')
If LotId NE '' then
If DCount(LotId, @VM) EQ 1 then
// Import into new metrology data structures
MetTestId = Met_Test_Services('CreateMetTest', LotId, RDSKeyID, '', ScanRecipe)
If Error_Services('NoError') then
Met_Test_Services('SetPropsAndLimits', MetTestId)
If Error_Services('HasError') then
// Failed to set property names and limits based on input data from metrology file. Log this and continue importing data.
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
Error_Services('Clear')
end
Met_Test_Services('SetMetTestTool', MetTestId, ScanTool)
If Error_Services('NoError') then
Met_Test_Services('SetMetTestDtm', MetTestId, TimeStamp)
If Error_Services('NoError') then
// Prop 1: SURFACE_SCAN_SUM_OF_DEFECTS_MIN
// Prop 2: SURFACE_SCAN_SUM_OF_DEFECTS_MAX
// Prop 3: SURFACE_SCAN_SUM_OF_DEFECTS_AVG
// Prop 4: SURFACE_SCAN_SUM_OF_DEFECTS (per wafer) - Currently not captured for SP1
// Prop 5: SURFACE_SCAN_HAZE_AVG
Met_Test_Services('RemoveProperty', MetTestId, 'SURFACE_SCAN_SUM_OF_DEFECTS')
If Error_Services('NoError') then
// Set SOD min, SOD max, SOD avg, and Haze Avg
Met_Test_Services('AddMetTestData', MetTestId, '', SoDMin, SoDMax, SoDAvg, '', HazeAvg)
If Error_Services('HasError') then
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Swap @VM with ',' in LotId
ErrorMsg = 'Error in ':Service:' service. Number of lot ids returned does not equal 1. Lot ids: ':LotId
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg)
end
end
LegacyLotId@ = RDSKeyID
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSKeyID)
If Error_Services('NoError') then
WorkOrderNo = RDSRec<RDS_WO$>
@ -2519,7 +2840,7 @@ The service does the following actions:
5. Determines the spec slot by reading the WO_MAT_QA record -> SLOT field
6. If the detected RunDataSlot matches the spec slot, writes the datapoint to the WO_MAT_QA record - > RESULT field in the same @VM that the iterator is currently set to.
*/
Service ImportBioRadEPPFQAData(RunData, FileName)
Service ImportBioRadEPPFQAData(RunData, Filename)
Timestamp = RunData<2>
WMOKeyID = RunData<6>
@ -2552,20 +2873,66 @@ Service ImportBioRadEPPFQAData(RunData, FileName)
Positions[-1, 1] = '' ; // Strip final @VM
DataPoints[-1, 1] = '' ; // Strip final @VM
LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', WMOKeyID, 'WM_OUT')
If LotId NE '' then
If DCount(LotId, @VM) EQ 1 then
// Import into new metrology data structures
ToolId = Field(Filename, ' ', 2, 1)
ToolClass = Xlate('TOOL', ToolId, 'CLASS', 'X')
If DataPoints NE '' then
For each DataPoint in DataPoints using @VM setting vPos
Slot = Positions<0, vPos>
MetTestId = Met_Test_Services('CreateMetTest', LotId, WMOKeyID, ToolClass, ScanRecipe, '', RunDataLayer)
If Error_Services('NoError') then
If DataSlotId NE '' then
If Num(DataSlotId) then
// Update the WM_OUT record for EpiPro
WMORec<WM_OUT_MU_WAFER_THK_RESULT$, Int(DataSlotId)> = DataPoints
Met_Test_Services('SetPropsAndLimits', MetTestId)
If Error_Services('HasError') then
// Failed to set property names and limits based on input data from metrology file. Log this and continue importing data.
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
Error_Services('Clear')
end
Met_Test_Services('SetMetTestTool', MetTestId, ToolId)
If Error_Services('NoError') then
Met_Test_Services('SetMetTestDtm', MetTestId, TimeStamp)
If Error_Services('NoError') then
Met_Test_Services('SetMetTestSlot', MetTestId, Slot)
If Error_Services('NoError') then
Met_Test_Services('AddMetTestData', MetTestId, '', DataPoint)
If Error_Services('HasError') then
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
Next DataPoint
end else
ErrorMsg = 'Error in ':Service:' service. No DataPoints to import.'
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg)
end
end else
Swap @VM with ',' in LotId
ErrorMsg = 'Error in ':Service:' service. Number of lot ids returned does not equal 1. Lot ids: ':LotId
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : ErrorMsg)
end
end
If Error_Services('NoError') then
If Error_Services('HasError') then
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
//Update the WM_OUT record for EpiPro
WMORec<WM_OUT_MU_WAFER_THK_RESULT$, DataSlotId> = DataPoints
Database_Services('WriteDataRow', 'WM_OUT', WMOKeyID, WMORec, True$, False$, True$)
end else
Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : DataSlotId ':Quote(DataSlotId):' is not a number!')
end
end else
Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : DataSlotId is null!')
end
end else
Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
// Update WO_MAT_QA record
WOMatQAID = Field(WMOKeyID, '*', 1) : '*' : Field(WMOKeyID, '*', 3)
@ -2608,12 +2975,12 @@ Service ImportBioRadEPPFQAData(RunData, FileName)
Next Profile
Database_Services('WriteDataRow', 'WO_MAT_QA', WOMatQAID, WOMatQARec, True$, False$, True$)
If Error_Services('NoError') then
Metrology_Services('LogResults', RDSNo@, Machine, 'UID000', Service : ' : Success.')
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID000', Service : ' : Success.')
end else
Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end else
Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end
end service
@ -3277,3 +3644,6 @@ LoadRunDataToDatabase:
return

View File

@ -0,0 +1,98 @@
Function Mettests_API(@API)
/***********************************************************************************************************************
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 : Mettests_API
Description : API logic for the Mettests resource.
Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables:
HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.)
APIURL - The URL for the API entry point (e.g., api.mysite.com/v1).
FullEndpointURL - The URL submitted by the client, including query params.
FullEndpointURLNoQuery - The URL submitted by the client, excluding query params.
EndpointSegment - The URL endpoint segment.
ParentURL - The URL path preceeding the current endpoint.
CurrentAPI - The name of this stored procedure.
Parameters :
API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]:
- APIPattern must follow this structure Mettests[.ID.[<Property>]]
- HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc.
Examples:
- Mettests.POST
- Mettests.ID.PUT
- Mettests.ID.firstName.GET
Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API
services do not rely upon anything being returned in the response. This is what the
various services like SetResponseBody and SetResponseStatus services are for. A response
value is only helpful if the developers want to use it for debug purposes.
History : (Date, Initials, Notes)
05/20/25 xxx Original programmer.
***********************************************************************************************************************/
#pragma precomp SRP_PreCompiler
$insert APP_INSERTS
$insert API_SETUP
$insert HTTP_INSERTS
Declare function Met_Test_Services
GoToAPI else
// The specific resource endpoint doesn't have a API handler yet.
HTTP_Services('SetResponseStatus', 204, 'This is a valid endpoint but a web API handler has not yet been created.')
end
Return Response OR ''
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Endpoint Handlers
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
API mettests.ID.HEAD
API mettests.ID.GET
// Return JSON payload containing RDS record details
StatusCode = 200
GoSub CreateHALItem
end api
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Internal GoSubs
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//----------------------------------------------------------------------------------------------------------------------
// CreateHALItem
//
// Creates a HAL+JSON object based on the OpenInsight data row representation of the scan.
//----------------------------------------------------------------------------------------------------------------------
CreateHALItem:
MetTestId = EndpointSegment
MetTestJSON = Met_Test_Services('ConvertRecordToJSON', MetTestId, '', FullEndpointURL)
If Error_Services('NoError') then
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseBody', MetTestJSON, False$, 'application/hal+json')
If Assigned(Message) then
HTTP_Services('SetResponseStatus', StatusCode, Message)
end else
HTTP_Services('SetResponseStatus', StatusCode)
end
end else
Message = Error_Services('GetMessage')
HTTP_Services('SetResponseStatus', 500, 'Error in the ' : CurrentAPI : ' API. Message: ': Message)
end
return

View File

@ -0,0 +1,257 @@
Function MET_TEST_Actions(Action, CalcColName, FSList, Handle, Name, FMC, Record, Status, OrigRecord, Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10)
/***********************************************************************************************************************
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 Infineon.
Name : Met_Test_Actions
Description : Handles calculated columns and MFS calls for the current table.
Notes : This function uses @ID, @RECORD, and @DICT to make sure {ColumnName} references work correctly.
If called from outside of a calculated column these will need to be set and restored.
Parameters :
Action [in] -- Name of the action to be taken
CalcColName [in] -- Name of the calculated column that needs to be processed. Normally this should only be
populated when the CalcField action is being used.
FSList [in] -- The list of MFSs and the BFS name for the current file or volume. This is an @SVM
delimited array, with the current MFS name as the first value in the array, and the BFS
name as the last value. Normally set by a calling MFS.
Handle [in] -- The file handle of the file or media map being accessed. Note, this does contain the
entire handle structure that the Basic+ Open statement would provide. Normally set by a
calling MFS.
Name [in] -- The name (key) of the record or file being accessed. Normally set by a calling MFS.
FMC [in] -- Various functions. Normally set by a calling MFS.
Record [in] -- The entire record (for record-oriented functions) or a newly-created handle (for
"get handle" functions). Normally set by a calling MFS.
Status [in/out] -- Indicator of the success or failure of an action. Normally set by the calling MFS but
for some actions can be set by the action handler to indicate failure.
OrigRecord [in] -- Original content of the record being processed by the current action. This is
automatically being assigned by the WRITE_RECORD and DELETE_RECORD actions within
BASE_MFS.
Param1-10 [in/out] -- Additional request parameter holders
ActionFlow [out] -- Used to control the action chain (see the ACTION_SETUP insert for more information.)
Can also be used to return a special value, such as the results of the CalcField
method.
History : (Date, Initials, Notes)
05/14/25 djs Original programmer.
***********************************************************************************************************************/
#pragma precomp SRP_PreCompiler
$Insert FILE.SYSTEM.EQUATES
$Insert ACTION_SETUP
$Insert APP_INSERTS
$Insert MET_TEST_EQUATES
$Insert MET_TEST_DATA_EQUATES
$Insert MET_TEST_INSERTS
$Insert DICT_EQUATES
Declare function Database_Services, SRP_Array, Read_Column
Declare subroutine Database_Services, RTI_Xlate_Controller
If KeyID then GoSub Initialize_System_Variables
Begin Case
Case Action _EQC 'CalculateColumn' ; GoSub CalculateColumn
Case Action _EQC 'READ_RECORD_PRE' ; GoSub READ_RECORD_PRE
Case Action _EQC 'READ_RECORD' ; GoSub READ_RECORD
Case Action _EQC 'READONLY_RECORD_PRE' ; GoSub READONLY_RECORD_PRE
Case Action _EQC 'READONLY_RECORD' ; GoSub READONLY_RECORD
Case Action _EQC 'WRITE_RECORD_PRE' ; GoSub WRITE_RECORD_PRE
Case Action _EQC 'WRITE_RECORD' ; GoSub WRITE_RECORD
Case Action _EQC 'DELETE_RECORD_PRE' ; GoSub DELETE_RECORD_PRE
Case Action _EQC 'DELETE_RECORD' ; GoSub DELETE_RECORD
Case Otherwise$ ; Status = 'Invalid Action'
End Case
If KeyID then GoSub Restore_System_Variables
If Assigned(ActionFlow) else ActionFlow = ACTION_CONTINUE$
Return ActionFlow
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Calculated Columns
//
// The typical structure of a calculated column will look like this:
//
// Declare function Database_Services
//
// @ANS = Database_Services('CalculateColumn')
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CalculateColumn:
// Make sure the ActionFlow return variable is cleared in case nothing is calculated.
ActionFlow = ''
return
// ----- MFS calls -----------------------------------------------------------------------------------------------------
READ_RECORD_PRE:
// In order to stop a record from being read in this action these lines of code must be used:
//
// OrigFileError = 100 : @FM : KeyID
// Status = 0
// Record = ''
// ActionFlow = ACTION_STOP$
return
READ_RECORD:
// In order to stop a record from being read in this action these lines of code must be used:
//
// OrigFileError = 100 : @FM : KeyID
// Status = 0
// Record = ''
return
READONLY_RECORD_PRE:
// In order to stop a record from being read in this action these lines of code must be used:
//
// OrigFileError = 100 : @FM : KeyID
// Status = 0
// Record = ''
// ActionFlow = ACTION_STOP$
return
READONLY_RECORD:
// In order to stop a record from being read in this action these lines of code must be used:
//
// OrigFileError = 100 : @FM : KeyID
// Status = 0
// Record = ''
return
WRITE_RECORD_PRE:
MetTestDataIds = {MET_TEST_DATA_IDS}
If MetTestDataIds NE '' then
// Evaluate if MET_TEST is out of spec
RTI_Xlate_Controller('DisableCache')
For PropertyIndex = 1 to NUM_PROPERTIES$
MetTestOutofSpec = (Sum(Xlate('MET_TEST_DATA', MetTestDataIds, "PROPERTY_":PropertyIndex:'_OUT_OF_SPEC', 'X')) GT 0)
Until MetTestOutofSpec
Next PropertyIndex
Record<MET_TEST.OUT_OF_SPEC$> = MetTestOutofSpec
// Evaluate if MET_TEST is complete (all required data has been recorded)
// If Sample Size set, then each defined property should have that number of related data points (MET_TEST_DATA) records.
// If Sample Size is not set, then each defined property should have at least one related data point (MET_TEST_DATA) record.
MetComplete = True$
SampleSize = {SAMPLE_SIZE}
If SampleSize EQ '' then SampleSize = 1
For PropertyIndex = 1 to NUM_PROPERTIES$
PropColNo = Xlate('DICT.MET_TEST', 'PROPERTY_':PropertyIndex, DICT_COLUMN_NO$, 'X')
If (Record<PropColNo> NE '') then
// Property is defined, check if number of data points matches SAMPLE_SIZE
PropVals = Xlate('MET_TEST_DATA', MetTestDataIds, 'PROPERTY_':PropertyIndex:'_VALUE', 'X')
PropVals = SRP_Array('Clean', PropVals, 'Trim')
MetComplete = (DCount(PropVals, @VM) GE SampleSize)
end
Until Not(MetComplete)
Next PropertyIndex
Record<MET_TEST.COMPLETE$> = MetComplete
RTI_Xlate_Controller('EnableCache')
end else
Record<MET_TEST.OUT_OF_SPEC$> = False$
Record<MET_TEST.COMPLETE$> = False$
end
SaveRecord = Record
return
WRITE_RECORD:
return
DELETE_RECORD_PRE:
return
DELETE_RECORD:
return
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Internal GoSubs
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ClearCursors:
For counter = 0 to 8
ClearSelect counter
Next counter
return
Initialize_System_Variables:
// Save these for restoration later
SaveDict = @DICT
SaveID = @ID
SaveRecord = @RECORD
OrigFileError = @FILE.ERROR
// Now make sure @DICT, ID, and @RECORD are populated
CurrentDictName = ''
If @DICT then
DictHandle = @DICT<1, 2>
Locate DictHandle in @TABLES(5) Using @FM Setting fPos then
CurrentDictName = Field(@TABLES(0), @FM, fPos, 1)
end
end
If CurrentDictName NE DictName then
Open DictName to @DICT else Status = 'Unable to initialize @DICT'
end
@ID = KeyID
If Record else
// Record might not have been passed in. Read the record from the database table just to make sure.
@FILE.ERROR = ''
Open TableName to hTable then
FullFSList = hTable[1, 'F' : @VM]
BFS = FullFSList[-1, 'B' : @SVM]
LastHandle = hTable[-1, 'B' : \0D\]
FileHandle = \0D\ : LastHandle[1, @VM]
Call @BFS(READO.RECORD, BFS, FileHandle, KeyID, FMC, Record, ReadOStatus)
end
end
@RECORD = Record
return
Restore_System_Variables:
Transfer SaveDict to @DICT
Transfer SaveID to @ID
Transfer SaveRecord to @RECORD
@FILE.ERROR = OrigFileError
return

View File

@ -0,0 +1,276 @@
Function MET_TEST_DATA_Actions(Action, CalcColName, FSList, Handle, Name, FMC, Record, Status, OrigRecord, Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8, Param9, Param10)
/***********************************************************************************************************************
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 Infineon.
Name : Met_Test_Data_Actions
Description : Handles calculated columns and MFS calls for the current table.
Notes : This function uses @ID, @RECORD, and @DICT to make sure {ColumnName} references work correctly.
If called from outside of a calculated column these will need to be set and restored.
Parameters :
Action [in] -- Name of the action to be taken
CalcColName [in] -- Name of the calculated column that needs to be processed. Normally this should only be
populated when the CalcField action is being used.
FSList [in] -- The list of MFSs and the BFS name for the current file or volume. This is an @SVM
delimited array, with the current MFS name as the first value in the array, and the BFS
name as the last value. Normally set by a calling MFS.
Handle [in] -- The file handle of the file or media map being accessed. Note, this does contain the
entire handle structure that the Basic+ Open statement would provide. Normally set by a
calling MFS.
Name [in] -- The name (key) of the record or file being accessed. Normally set by a calling MFS.
FMC [in] -- Various functions. Normally set by a calling MFS.
Record [in] -- The entire record (for record-oriented functions) or a newly-created handle (for
"get handle" functions). Normally set by a calling MFS.
Status [in/out] -- Indicator of the success or failure of an action. Normally set by the calling MFS but
for some actions can be set by the action handler to indicate failure.
OrigRecord [in] -- Original content of the record being processed by the current action. This is
automatically being assigned by the WRITE_RECORD and DELETE_RECORD actions within
BASE_MFS.
Param1-10 [in/out] -- Additional request parameter holders
ActionFlow [out] -- Used to control the action chain (see the ACTION_SETUP insert for more information.)
Can also be used to return a special value, such as the results of the CalcField
method.
History : (Date, Initials, Notes)
05/14/25 djs Original programmer.
***********************************************************************************************************************/
#pragma precomp SRP_PreCompiler
$Insert FILE.SYSTEM.EQUATES
$Insert ACTION_SETUP
$Insert APP_INSERTS
$Insert MET_TEST_EQUATES
$Insert MET_TEST_DATA_EQUATES
$Insert MET_TEST_INSERTS
$Insert DICT_EQUATES
Declare function Database_Services
Declare subroutine Database_Services
If KeyID then GoSub Initialize_System_Variables
Begin Case
Case Action _EQC 'CalculateColumn' ; GoSub CalculateColumn
Case Action _EQC 'READ_RECORD_PRE' ; GoSub READ_RECORD_PRE
Case Action _EQC 'READ_RECORD' ; GoSub READ_RECORD
Case Action _EQC 'READONLY_RECORD_PRE' ; GoSub READONLY_RECORD_PRE
Case Action _EQC 'READONLY_RECORD' ; GoSub READONLY_RECORD
Case Action _EQC 'WRITE_RECORD_PRE' ; GoSub WRITE_RECORD_PRE
Case Action _EQC 'WRITE_RECORD' ; GoSub WRITE_RECORD
Case Action _EQC 'DELETE_RECORD_PRE' ; GoSub DELETE_RECORD_PRE
Case Action _EQC 'DELETE_RECORD' ; GoSub DELETE_RECORD
Case Otherwise$ ; Status = 'Invalid Action'
End Case
If KeyID then GoSub Restore_System_Variables
If Assigned(ActionFlow) else ActionFlow = ACTION_CONTINUE$
Return ActionFlow
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Calculated Columns
//
// The typical structure of a calculated column will look like this:
//
// Declare function Database_Services
//
// @ANS = Database_Services('CalculateColumn')
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CalculateColumn:
// Make sure the ActionFlow return variable is cleared in case nothing is calculated.
ActionFlow = ''
return
// ----- MFS calls -----------------------------------------------------------------------------------------------------
READ_RECORD_PRE:
// In order to stop a record from being read in this action these lines of code must be used:
//
// OrigFileError = 100 : @FM : KeyID
// Status = 0
// Record = ''
// ActionFlow = ACTION_STOP$
return
READ_RECORD:
// In order to stop a record from being read in this action these lines of code must be used:
//
// OrigFileError = 100 : @FM : KeyID
// Status = 0
// Record = ''
return
READONLY_RECORD_PRE:
// In order to stop a record from being read in this action these lines of code must be used:
//
// OrigFileError = 100 : @FM : KeyID
// Status = 0
// Record = ''
// ActionFlow = ACTION_STOP$
return
READONLY_RECORD:
// In order to stop a record from being read in this action these lines of code must be used:
//
// OrigFileError = 100 : @FM : KeyID
// Status = 0
// Record = ''
return
WRITE_RECORD_PRE:
// Validate Property Values against specs defined in MET_TEST parent record
MetTestId = {MET_TEST_ID}
If MetTestId NE '' then
MetTestRec = Database_Services('ReadDataRow', 'MET_TEST', MetTestId)
If Error_Services('NoError') then
MetTestOutofSpecOrig = MetTestRec<MET_TEST.OUT_OF_SPEC$>
MetTestOutofSpec = False$
For PropertyIndex = 1 to NUM_PROPERTIES$
PropOutofSpec = False$
Prop = Xlate('MET_TEST', MetTestId, 'PROPERTY_':PropertyIndex, 'X')
If Prop NE '' then
PropMin = Xlate('MET_TEST', MetTestId, 'PROPERTY_':PropertyIndex:'_SPEC_MIN', 'X')
PropMax = Xlate('MET_TEST', MetTestId, 'PROPERTY_':PropertyIndex:'_SPEC_MAX', 'X')
PropValColNo = Xlate('DICT.MET_TEST_DATA', 'PROPERTY_':PropertyIndex:'_VALUE', DICT_COLUMN_NO$, 'X')
PropVal = Record<PropValColNo>
Begin Case
Case (PropVal EQ '')
PropOutofSpec = False$
Case ( (PropMin NE '') and (PropMax NE '') )
PropOutofSpec = ( (PropVal LT PropMin) or (PropVal GT PropMax) )
Case (PropMin NE '')
PropOutofSpec = (PropVal LT PropMin)
Case (PropMax NE '')
PropOutofSpec = (PropVal GT PropMax)
Case (Prop EQ 'SURFACE_SCAN_SORT')
PropOutofSpec = Not((PropVal _EQC 'PASS'))
Case Otherwise$
Null
End Case
PropOOSColNo = Xlate('DICT.MET_TEST_DATA', 'PROPERTY_':PropertyIndex:'_OUT_OF_SPEC', DICT_COLUMN_NO$, 'X')
Record<PropOOSColNo> = PropOutofSpec
end
If PropOutofSpec then MetTestOutofSpec = True$
Next PropertyIndex
SaveRecord = Record
end
end
return
WRITE_RECORD:
// Trigger MET_TEST_ACTIONS to re-evaluate if the entire MET_TEST record is in spec and comlete
MetTestRec = Database_Services('ReadDataRow', 'MET_TEST', {MET_TEST_ID})
If Error_Services('NoError') then
Database_Services('WriteDataRow', 'MET_TEST', {MET_TEST_ID}, MetTestRec, True$, False$, False$)
end
return
DELETE_RECORD_PRE:
return
DELETE_RECORD:
return
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Internal GoSubs
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ClearCursors:
For counter = 0 to 8
ClearSelect counter
Next counter
return
Initialize_System_Variables:
// Save these for restoration later
SaveDict = @DICT
SaveID = @ID
SaveRecord = @RECORD
OrigFileError = @FILE.ERROR
// Now make sure @DICT, ID, and @RECORD are populated
CurrentDictName = ''
If @DICT then
DictHandle = @DICT<1, 2>
Locate DictHandle in @TABLES(5) Using @FM Setting fPos then
CurrentDictName = Field(@TABLES(0), @FM, fPos, 1)
end
end
If CurrentDictName NE DictName then
Open DictName to @DICT else Status = 'Unable to initialize @DICT'
end
@ID = KeyID
If Record else
// Record might not have been passed in. Read the record from the database table just to make sure.
@FILE.ERROR = ''
Open TableName to hTable then
FullFSList = hTable[1, 'F' : @VM]
BFS = FullFSList[-1, 'B' : @SVM]
LastHandle = hTable[-1, 'B' : \0D\]
FileHandle = \0D\ : LastHandle[1, @VM]
Call @BFS(READO.RECORD, BFS, FileHandle, KeyID, FMC, Record, ReadOStatus)
end
end
@RECORD = Record
return
Restore_System_Variables:
Transfer SaveDict to @DICT
Transfer SaveID to @ID
Transfer SaveRecord to @RECORD
@FILE.ERROR = OrigFileError
return

File diff suppressed because it is too large Load Diff

View File

@ -135,4 +135,3 @@ API monaengines.ID.GET
end
end api

View File

@ -61,4 +61,3 @@ API mona.GET
HTTP_Resource_Services('LoremIpsum')
end api

View File

@ -190,9 +190,3 @@ return

View File

@ -300,3 +300,5 @@ SetDelay:
return

View File

@ -0,0 +1,130 @@
Function Operation_API(@API)
/***********************************************************************************************************************
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 : Operation_API
Description : API logic for the Operation resource.
Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables:
HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.)
APIURL - The URL for the API entry point (e.g., api.mysite.com/v1).
FullEndpointURL - The URL submitted by the client, including query params.
FullEndpointURLNoQuery - The URL submitted by the client, excluding query params.
EndpointSegment - The URL endpoint segment.
ParentURL - The URL path preceeding the current endpoint.
CurrentAPI - The name of this stored procedure.
Parameters :
API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]:
- APIPattern must follow this structure Operation[.ID.[<Property>]]
- HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc.
Examples:
- Operation.POST
- Operation.ID.PUT
- Operation.ID.firstName.GET
Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API
services do not rely upon anything being returned in the response. This is what the
various services like SetResponseBody and SetResponseStatus services are for. A response
value is only helpful if the developers want to use it for debug purposes.
History : (Date, Initials, Notes)
05/19/25 xxx Original programmer.
***********************************************************************************************************************/
#pragma precomp SRP_PreCompiler
Declare function OI_Wizard_Services, Operation_Services, Clean_Services, Lot_Operation_Services
$insert APP_INSERTS
$insert API_SETUP
$insert HTTP_INSERTS
GoToAPI else
// The specific resource endpoint doesn't have a API handler yet.
HTTP_Services('SetResponseStatus', 204, 'This is a valid endpoint but a web API handler has not yet been created.')
end
Return Response OR ''
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Endpoint Handlers
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
API operation.HEAD
API operation.GET
JSONCollection = ''
OIWizardID = ''
Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';'
Key = Field(Cookie, '=', 1)
If Key EQ 'sessionID' then
OIWizardID = Field(Cookie, '=', 2)
end
Next Cookie
ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID)
If ValidSession then
Body = HTTP_Services('GetHTTPGetString')
If Body NE '' then
RequestJson = HTTP_Services('DecodePercentString', Body)
ClassFilter = Http_Services('GetQueryField', 'Class')
ActiveFilter = Http_Services('GetQueryField', 'Active')
LotId = Http_Services('GetQueryField', 'LotId')
Operations = Operation_Services('GetOperations', ClassFilter, ActiveFilter)
objJSONResponse = ''
If SRP_Json(objJSONResponse, 'New', 'Object') then
//Available Operations
If SRP_Json(objOperations, 'New', 'Array') then
for each Operation in Operations using @VM
OperationJSONString = Operation_Services('ConvertRecordToJSON', Operation)
objOperation = ''
If SRP_Json(objOperation, 'Parse', OperationJSONString) EQ '' then
SRP_Json(objOperations, 'Add', objOperation)
SRP_Json(objOperation, 'Release')
end
Next Operation
SRP_Json(objJsonResponse, 'Set', 'Operations', objOperations)
SRP_Json(objOperations, 'Release')
end else
Error_Services('Add', 'Error when creating Operation array in JSON response.')
end
//Available Sequences
Sequences = Lot_Operation_Services('GetAvailableSequences', LotId)
If SRP_Json(objSequences, 'New', 'Array') then
for each Sequence in Sequences using @VM
SRP_Json(objSequences, 'AddValue', Sequence, 'Number')
Next Sequence
SRP_Json(objJsonResponse, 'Set', 'AvailableSequences', objSequences)
SRP_Json(objSequences, 'Release')
end else
Error_Services('Add', 'Error when creating Operation array in JSON response.')
end
JsonResponse = SRP_Json(objJsonResponse, 'Stringify', 'Styled')
SRP_Json(objJsonResponse, 'Release')
end else
Error_Services('Add', 'Error when creating JSON response.')
end
end else
Error_Services('Add', 'No body was sent with the request.')
end
If Error_Services('NoError') then
HTTP_Services('SetResponseStatus', 201, 'Success')
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseBody', JsonResponse, False$, 'application/hal+json')
end else
HTTP_Services('SetResponseStatus', 400, Error_Services('GetMessage'))
end
end else
HTTP_Services('SetResponseStatus', 401, 'Invalid session. Reauthentication required.')
end
end api

View File

@ -0,0 +1,21 @@
compile insert OPERATION_EQUATES
/*----------------------------------------
Author : Table Create Insert Routine
Written : 29/05/2025
Description : Insert for Table OPERATION
----------------------------------------*/
#ifndef __OPERATION_EQUATES__
#define __OPERATION_EQUATES__
equ OPERATION_ACTIVE$ to 1
equ OPERATION_CLASS_ID$ to 2
equ OPERATION_OPERATION_DESCRIPTION$ to 3
equ OPERATION_TYPE$ to 4
equ OPERATION_REWORK$ to 5
equ OPERATION_MET_TEST_TYPE_REQUIRED$ to 6
equ OPERATION_MET_TEST_REQUIRED$ to 7
equ OPERATION_PACKAGING_REQUIRED$ to 8
equ OPERATION_CLEAN_REQUIRED$ to 9
equ OPERATION_WAFER_COUNTER_REQUIRED$ to 10
#endif

View File

@ -0,0 +1,57 @@
Compile function Operation_Services(@Service, @Params)
#pragma precomp SRP_PreCompiler
Declare function Database_Services, SRP_Json
Declare subroutine Database_Services, SRP_Json, Btree.Extract
$insert LOGICAL
$Insert OPERATION_EQUATES
Options OPERATION_TYPE = 'CLEAN', 'THICK_METROLOGY', 'RES_METROLOGY', 'SURFACE_METROLOGY', 'VISUAL_INSPECTION', 'PACKAGING'
GoToService
Return Response or ""
//-----------------------------------------------------------------------------
// SERVICES
//-----------------------------------------------------------------------------
Service ConvertRecordToJson(OperationId)
JsonString = ''
objJSON = ''
OperationRec = Database_Services('ReadDataRow', 'OPERATION', OperationId, True$, 0, False$)
If SRP_JSON(objJSON, 'New', 'Object') then
SRP_JSON(objJSON, 'SetValue', 'OperationId', OperationId)
SRP_JSON(objJSON, 'SetValue', 'Active', OperationRec<OPERATION_ACTIVE$>, 'Boolean')
SRP_JSON(objJSON, 'SetValue', 'ClassId', OperationRec<OPERATION_CLASS_ID$>, 'String')
SRP_JSON(objJSON, 'SetValue', 'Description', OperationRec<OPERATION_OPERATION_DESCRIPTION$>, 'String')
SRP_JSON(objJSON, 'SetValue', 'Type', OperationRec<OPERATION_TYPE$>, 'String')
JsonString = SRP_JSON(objJSON, 'Stringify', 'Styled')
SRP_JSON(objJSON, 'Release')
end
Response = JsonString
End Service
Service GetOperations(Class, ActiveFlag)
ErrorMessage = ''
RTFOperationKeys = ''
Open 'DICT.OPERATION' to DICT then
SearchString = 'CLASS_ID':@VM:Class:@FM
SearchString := 'ACTIVE':@VM:True$:@FM
Option = ''
Flag = ''
Btree.Extract(SearchString, 'OPERATION', DICT, RTFOperationKeys, Option, Flag)
end else
ErrorMessage = 'Error opening OPERATION table dictionary.'
end
Response = RTFOperationKeys
end service

View File

@ -32,11 +32,24 @@ $insert SCANS_EQUATES
$insert APP_INSERTS
$insert WO_MAT_EQUATES
$insert NOTIFICATION_EQU
$insert PACKAGING_EQUATES
$insert LOT_OPERATION_EQUATES
$Insert LOT_EQUATES
Declare function Scan_Services, Memory_Services, Database_Services, SRP_JSON, RTI_CreateGUID, Memberof
Declare function Get_Property, RDS_Services, EpiPro_Services, DateTime, Signature_Services
Declare function Get_Property, RDS_Services, EpiPro_Services, DateTime, Signature_Services, Packaging_Services
Declare function Lot_Services, Environment_Services, Logging_Services
Declare subroutine Scan_Services, Memory_Services, Database_Services, SRP_JSON, Security_Services, obj_Notes
Declare subroutine obj_WO_Mat_Log, obj_WO_Mat, Set_Status, SAP_Services, Rds_Services, Wm_Out_Services, Hold_Services
Declare subroutine Lot_Event_Services, Lot_Services, Packaging_Services, Logging_Services
LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\Packaging'
LogDate = Oconv(Date(), 'D4/')
LogTime = Oconv(Time(), 'MTS')
LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Packaging Log.csv'
Headers = 'Logging DTM' : @FM : 'Message'
objLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$)
GoToService else
Error_Services('Add', Service : ' is not a valid service request within the ' : ServiceModule : ' module.')
@ -62,6 +75,7 @@ Service CompletePackaging(CassetteID, OperatorID, BaggerIdentifier)
RDSKey = CassetteID
WMOKey = CassetteID
LotId = ''
Convert '.' to '*' in WMOKey
CommentEntity = ''
Begin Case
@ -70,11 +84,13 @@ Service CompletePackaging(CassetteID, OperatorID, BaggerIdentifier)
WOMatKey = Xlate('RDS', RDSKey, 'WO', 'X')
WOMatKey = WoMatKey:'*':Xlate('RDS', RDSKey, 'CASS_NO', 'X')
CommentEntity = 'RDS'
LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', RDSKey, 'RDS')
Case RowExists('WM_OUT', WMOKey) EQ True$
// WM_OUT key
WOMatKey = Xlate('WM_OUT', WMOKey, 'WO_MAT_KEY', 'X')
CommentEntity = 'WM_OUT'
LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', WMOKey, 'WM_OUT')
Case RowExists('WO_MAT', CassetteID) EQ True$
// WO_MAT key
@ -138,6 +154,24 @@ Service CompletePackaging(CassetteID, OperatorID, BaggerIdentifier)
// Add CassComp transaction to SAP queue
SAPBatchNo = Xlate('WO_MAT', WOMatKey, 'SAP_BATCH_NO', 'X')
If SAPBatchNo EQ '' then SAP_Services('AddCassCompTransaction', WOMatKey)
//Handle NG lot functions.
If LotId NE '' then
NewPackRecId = Packaging_Services('CreatePackagingRecord', LotId, UserID, ToolID)
CurrOperationId = Lot_Services('GetLotCurrOperationId', LotId)
If CurrOperationId NE '' then
Packaging_Services('AddPackToLotOperation', CurrOperationId, NewPackRecId, UserID)
If Error_Services('NoError') then
Lot_Services('MoveOutLot', LotId, UserId)
end
end
If Error_Services('HasError') then
//Remove any error messages as a result of NG Lot functions. At the moment we don't want them interrupting production when they occur.
Error_Services('Clear')
end
end
end
end
@ -664,3 +698,72 @@ Service ProcessScanData(ScanData, ScanType = SCAN_TYPES, Param1, Param2, Param3)
end service
Service CreatePackagingRecord(LotId, UserId, EqpId)
NewRecId = ''
ErrorMessage = ''
If RowExists('LOT', LotId) then
NewRecId = RTI_CreateGuid()
TransDtm = Datetime()
NewPackagingRec = ''
NewPackagingRec<PACKAGING_LOT_ID$> = LotId
NewPackagingRec<PACKAGING_COMPLETE$> = True$
NewPackagingRec<PACKAGING_COMPLETE_DTM$> = TransDtm
Database_Services('WriteDataRow', 'PACKAGING', NewRecId, NewPackagingRec, True$, 0, False$)
If Error_Services('NoError') then
Lot_Event_Services('CreateLotEvent', LotId, TransDtm, 'PACKAGING', 'Lot Packaged.', EqpId, UserId)
end else
ErrorMessage = Error_Services('GetMessage')
end
end else
ErrorMessage = 'LOT: ' LotId : ' not found'
end
If ErrorMessage NE '' then
LogData = ''
LogData<1> = LoggingDTM
LogData<2> = Error_Services('GetMessage')
Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$)
Error_Services('Clear')
end
Response = NewRecId
end service
Service AddPackToLotOperation(LotOperationId, PackagingId, UserId)
ErrorMessage = ''
If RowExists('LOT_OPERATION', LotOperationId) then
If RowExists('LSL_USERS', UserId) then
//Can add user group check here.
LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$)
LotId = LotOperationRec<LOT_OPERATION_LOT_ID$>
ExistingPackId = LotOperationRec<LOT_OPERATION_PACKAGING_ID$>
If ExistingPackId EQ '' then
LotOperationRec<LOT_OPERATION_PACKAGING_ID$> = PackagingId
Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationId, LotOperationRec)
If Error_Services('NoError') then
TransDtm = Datetime()
Lot_Event_Services('CreateLotEvent', LotId, TransDtm, 'COMMENT', 'PACKAGING record added to operation.', '', UserId)
end else
ErrorMessage = Error_Services('GetMessage')
end
end else
ErrorMessage = 'A pack scan already exists for the lot operation. Please remove the pack before adding a new one.'
end
end else
ErrorMessage = 'USER ID: ' UserId : ' not found.'
end
end else
ErrorMessage = 'LOT_OPERATION: ' LotOperationId : ' not found.'
end
If ErrorMessage NE '' then
Error_Services('Add', ErrorMessage)
end
end service

View File

@ -76,4 +76,3 @@ API pm.ID.POST
HTTP_Resource_Services('LoremIpsum')
end api

View File

@ -61,4 +61,3 @@ API pm_spec.GET
HTTP_Resource_Services('LoremIpsum')
end api

View File

@ -102,5 +102,3 @@ CreateHALItem:
end
return

View File

@ -35,9 +35,11 @@ $Insert RDS_TEST_EQUATES
$Insert RDS_TEST_PROP_EQUATES
$Insert PRS_LAYER_EQU
Options SpecTypes = 'CLEAN', 'SURFSCAN', 'THICK', 'THICKA', 'RES', 'SRES', 'CRES', 'CONC'
Declare function Database_Services, Psn_Services, obj_Prod_Spec, Error_Services, SRP_JSON, Cust_Epi_Part_Services
Declare function Prod_Ver_Services, PRS_Stage_Services
Declare subroutine Database_Services, Psn_Services, Error_Services, SRP_JSON
Declare function Prod_Ver_Services, PRS_Stage_Services, SRP_Array
Declare subroutine Database_Services, Psn_Services, Error_Services, SRP_JSON, Extract_Si_Keys
GoToService else
Error_Services('Add', Service : ' is not a valid service request within the ' : ServiceModule : ' services module.')
@ -72,6 +74,216 @@ Service InitializeCritParams(PSNo)
end service
Service GetRecipes(PSNo)
ErrorMsg = ''
Recipes = ''
If PSNo NE '' then
If RowExists('PROD_SPEC', PSNo) then
PropKeys = ''
Extract_Si_Keys('PRS_PROP', 'PS_NO', PSNo, PropKeys)
Recipes = Xlate('PRS_PROP', PropKeys, 'MET_RECIPE', 'X')
PRSStageKeys = ''
Extract_Si_Keys('PRS_STAGE', 'PS_NO', PSNo, PRSStageKeys)
Recipes<0, -1> = Xlate('PRS_STAGE', PRSStageKeys, 'MET_RECIPE', 'X')
Recipes<0, -1> = Xlate('PRS_STAGE', PRSStageKeys, 'SURFSCAN_RECIPE', 'X')
Recipes<0, -1> = @VM : Xlate('PRS_STAGE', PRSStageKeys, 'CLEAN_RECIPE', 'X')
Recipes = SRP_Array('Clean', Recipes, 'TrimAndMakeUnique', @VM)
end else
ErrorMsg = 'Error in ':Service:' service. PROD_SPEC record "':PSNo:'" does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null PSNo passed into service.'
end
If ErrorMsg EQ '' then
Response = Recipes
end else
Error_Services('Add', ErrorMsg)
end
end service
Service GetAllMetrologyRecipes(PSNo, GetSurfscan, GetClean, GetRes, GetThick)
Recipes = ''
If GetSurfscan EQ '' then GetSurfscan = True$
If GetClean EQ '' then GetClean = True$
If GetRes EQ '' then GetRes = True$
If GetThick EQ '' then GetThick = True$
If GetSurfscan then Recipes := PSN_Services('GetSurfscanRecipes', PSNo) : @FM
If GetClean then Recipes := PSN_Services('GetCleanRecipes', PSNo) :@FM
If GetRes then Recipes := PSN_Services('GetResRecipes', PSNo) :@FM
If GetThick then Recipes := PSN_Services('GetThicknessRecipes', PSNo)
Recipes = SRP_Array('Clean', Recipes, 'TrimAndMakeUnique', @FM)
Response = Recipes
end service
Service GetSurfscanRecipes(PSNo)
Recipes = ''
If PSNo NE '' then
If RowExists('PROD_SPEC', PSNo) then
PropKeys = ''
Extract_Si_Keys('PRS_PROP', 'PS_NO', PSNo, PropKeys)
PRSStageKeys = ''
Extract_Si_Keys('PRS_STAGE', 'PS_NO', PSNo, PRSStageKeys)
for each PRSStageKey in PRSStageKeys using @VM setting pPos
Stage = Xlate('PRS_STAGE', PRSStageKey, 'STAGE', 'X')
TencorRecipes = Xlate('PRS_STAGE', PRSStageKey, 'SURFSCAN_RECIPE', 'X')
for each Recipe in TencorRecipes using @VM
ToolClass = 'TENCOR'
Recipes<-1> = ToolClass : @VM : Recipe : @VM : Stage
Next TencorRecipe
Next PRSStageKey
Recipes = SRP_Array('Clean', Recipes, 'TrimAndMakeUnique', @FM)
end
end
Response = Recipes
end service
Service GetCleanRecipes(PSNo)
Recipes = ''
If PSNo NE '' then
If RowExists('PROD_SPEC', PSNo) then
PropKeys = ''
Extract_Si_Keys('PRS_PROP', 'PS_NO', PSNo, PropKeys)
PRSStageKeys = ''
Extract_Si_Keys('PRS_STAGE', 'PS_NO', PSNo, PRSStageKeys)
for each PRSStageKey in PRSStageKeys using @VM setting pPos
Stage = Xlate('PRS_STAGE', PRSStageKey, 'STAGE', 'X')
CleanRecipes = Xlate('PRS_STAGE', PRSStageKey, 'CLEAN_RECIPE', 'X')
for each Recipe in CleanRecipes using @VM
ToolClass = 'CLEAN'
Recipes<-1> = ToolClass : @VM : Recipe : @VM : Stage
Next TencorRecipe
Next PRSStageKey
Recipes = SRP_Array('Clean', Recipes, 'TrimAndMakeUnique', @FM)
end
end
Response = Recipes
end service
Service GetThicknessRecipes(PSNo)
ErrorMsg = ''
Recipes = ''
If PSNo NE '' then
If RowExists('PROD_SPEC', PSNo) then
//First get QA Recipes
PropKeys = ''
Extract_Si_Keys('PRS_PROP', 'PS_NO', PSNo, PropKeys)
Recipes = ''
PRSStageKeys = ''
Extract_Si_Keys('PRS_STAGE', 'PS_NO', PSNo, PRSStageKeys)
for each PRSStageKey in PRSStageKeys using @VM setting pPos
Stage = Xlate('PRS_STAGE', PRSStageKey, 'STAGE', 'X')
PRSStageRecipes = Xlate('PRS_STAGE', PRSStageKey, 'MET_RECIPE', 'X')
for each PRSStageRecipe in PRSStageRecipes using @VM setting rPos
PropType = Xlate('PRS_STAGE', PRSStageKey, 'MET_PROP', 'X')<1, rPos>
If PropType EQ 'THICK' OR PropType EQ 'THICKA' then
Recipe = PRSStageRecipe
ToolClass = 'FTIR'
Recipes<-1> = ToolClass : @VM : Recipe : @VM : Stage
end
Next PRSStageRecipe
Next PRSStageKey
//Next get Rathole recipes
SpecEpiData = XLATE('PROD_SPEC', PSNo, 'SPEC_EPI', 'X')
swap @VM with @FM in SpecEpiData
swap '~' with @VM in SpecEpiData
ThicknessData = SpecEpiData<13>
ToolClass = ThicknessData<1, 1>
Recipe = ThicknessData<1, 3>
Stage = 'RDS_TEST'
If ToolClass EQ 'FTIR' OR ToolClass EQ 'ADE' then
Recipes<-1> = ToolClass : @VM : Recipe : @VM : Stage
end
// Remove any duplicate entries
Recipes = SRP_Array('Clean', Recipes, 'TrimAndMakeUnique', @FM)
end else
ErrorMsg = 'Error in ':Service:' service. PROD_SPEC record "':PSNo:'" does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null PSNo passed into service.'
end
If ErrorMsg EQ '' then
Response = Recipes
end else
Error_Services('Add', ErrorMsg)
end
end service
Service GetResRecipes(PSNo)
ErrorMsg = ''
Recipes = ''
If PSNo NE '' then
If RowExists('PROD_SPEC', PSNo) then
//First get QA Recipes
PropKeys = ''
Extract_Si_Keys('PRS_PROP', 'PS_NO', PSNo, PropKeys)
Recipes = ''
PRSStageKeys = ''
Extract_Si_Keys('PRS_STAGE', 'PS_NO', PSNo, PRSStageKeys)
for each PRSStageKey in PRSStageKeys using @VM setting pPos
Stage = Xlate('PRS_STAGE', PRSStageKey, 'STAGE', 'X')
PRSStageRecipes = Xlate('PRS_STAGE', PRSStageKey, 'MET_RECIPE', 'X')
for each PRSStageRecipe in PRSStageRecipes using @VM setting rPos
PropType = Xlate('PRS_STAGE', PRSStageKey, 'MET_PROP', 'X')<1, rPos>
ToolClass = Xlate('PRS_STAGE', PRSStageKey, 'MET_TOOL_CLASS', 'X')<1, rPos>
If PropType EQ 'RES' OR PropType EQ 'SRES' OR PropType EQ 'CRES' OR PropType EQ 'CONC' then
Recipe = PRSStageRecipe
ToolClass = ToolClass
Recipes<-1> = ToolClass : @VM : Recipe : @VM : Stage
end
Next PRSStageRecipe
Next PRSStageKey
//Next get Rathole recipes
Stage = 'RDS_TEST'
SpecEpiData = XLATE('PROD_SPEC', PSNo, 'SPEC_EPI', 'X')
swap @VM with @FM in SpecEpiData
swap '~' with @VM in SpecEpiData
ResData1 = SpecEpiData<19>
If ResData1 NE '' then
ToolClass = ResData1<1, 1>
Recipe = ResData1<1, 3>
Recipes<-1> = ToolClass : @VM : Recipe : @VM : Stage
end
ResData2 = SpecEpiData<14>
If ResData2 NE '' then
ToolClass = ResData2<1, 1>
Recipe = ResData2<1, 3>
Recipes<-1> = ToolClass : @VM : Recipe : @VM : Stage
end
// Remove any duplicate entries
Recipes = SRP_Array('Clean', Recipes, 'TrimAndMakeUnique', @FM)
end else
ErrorMsg = 'Error in ':Service:' service. PROD_SPEC record "':PSNo:'" does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null PSNo passed into service.'
end
If ErrorMsg EQ '' then
Response = Recipes
end else
Error_Services('Add', ErrorMsg)
end
end service
Service CheckPSNStages(PSNo, Stage)
Begin Case
@ -950,3 +1162,8 @@ CheckAdHoc:
return

View File

@ -103,4 +103,3 @@ API reactorloadings.POST
end
end api

View File

@ -260,5 +260,3 @@ API reactorlogs.ID.nicaoverride.PUT
HTTP_Resource_Services('LoremIpsum')
end api

View File

@ -259,5 +259,3 @@ CreateHALCollection:
end
return

View File

@ -61,4 +61,3 @@ API remotehealthcheck.GET
HTTP_Resource_Services('LoremIpsum')
end api

View File

@ -233,5 +233,3 @@ API reports.GET
HTTP_Resource_Services('LoremIpsum')
end api

View File

@ -129,7 +129,7 @@ API returntofab.ID.GET
UserId = Xlate('OI_WIZARD', OIWizardID, 'EMPLOYEE_ID', 'X')
RTFId = EndpointSegment
If Error_Services('NoError') AND RTFId NE '' then
RTFJson = Return_To_Fab_Services('ConvertReturnToFabRecordToJSON', RTFId)
RTFJson = Return_To_Fab_Services('ConvertReturnToFabRecordToJSON', RTFId, UserId)
If Error_Services('NoError') then
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseBody', RTFJson, False$, 'application/hal+json')
@ -247,7 +247,6 @@ end api
API returntofab.reportopenforms.HEAD
API returntofab.reportopenforms.GET
OIWizardID = ''
Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';'
@ -259,12 +258,9 @@ API returntofab.reportopenforms.GET
ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID)
If ValidSession then
UserId = Xlate('OI_WIZARD', OIWizardID, 'EMPLOYEE_ID', 'X')
RTFId = EndpointSegment
If Error_Services('NoError') AND RTFId NE '' then
RTFJson = Return_To_Fab_Services('CreateReturnToFabReportJson', True$)
If Error_Services('NoError') then
If RTFJson NE '' then
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseBody', RTFJson, False$, 'application/hal+json')
If Assigned(Message) then
@ -273,14 +269,7 @@ API returntofab.reportopenforms.GET
HTTP_Services('SetResponseStatus', 201)
end
end else
end
end else
HTTP_Services('SetResponseStatus', 400, Error_Services('GetMessage'))
end
end else
HTTP_Services('SetResponseStatus', 401, 'Invalid session. Reauthentication required.')
ErrorMessage = 'Error getting report data.'
end
end api
@ -288,7 +277,6 @@ end api
API returntofab.reportallforms.HEAD
API returntofab.reportallforms.GET
OIWizardID = ''
Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';'
@ -303,9 +291,9 @@ API returntofab.reportallforms.GET
If ValidSession then
UserId = Xlate('OI_WIZARD', OIWizardID, 'EMPLOYEE_ID', 'X')
RTFId = EndpointSegment
If Error_Services('NoError') AND RTFId NE '' then
If RTFId NE '' then
RTFJson = Return_To_Fab_Services('CreateReturnToFabReportJson', False$)
If Error_Services('NoError') then
If RTFJson NE '' then
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseBody', RTFJson, False$, 'application/hal+json')
If Assigned(Message) then
@ -314,11 +302,10 @@ API returntofab.reportallforms.GET
HTTP_Services('SetResponseStatus', 201)
end
end else
ErrorMessage = 'Error getting report data.'
end
end else
HTTP_Services('SetResponseStatus', 400, Error_Services('GetMessage'))
HTTP_Services('SetResponseStatus', 400, 'Return To Fab ID was null')
end
end else
HTTP_Services('SetResponseStatus', 401, 'Invalid session. Reauthentication required.')
@ -370,6 +357,37 @@ CreateResultOptionCollection:
return
CreateOperationOptionCollection:
JSONCollection = ''
Abort = False$
OperationOptions = Return_To_Fab_Services('GetRTFOperationIDs')
hJSONCollection = ''
If SRP_JSON(hJSONCollection, 'New', 'Object') then
hOperationOptionCollection = ''
If SRP_JSON(hOperationOptionCollection, 'New', 'Array') then
For each OperationOptionId in OperationOptions using @VM setting fPos
SRP_Json(hOperationOptionCollection, 'AddValue', OperationOptionId, 'String')
Next OperationOptionId
SRP_JSON(hJSONCollection, 'Set', 'OperationOptions', hOperationOptionCollection)
SRP_JSON(hOperationOptionCollection, 'Release')
end
JSONCollection = SRP_JSON(hJSONCollection, 'Stringify', 'Fast')
SRP_JSON(hJSONCollection, 'Release')
end
If Error_Services('NoError') then
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseBody', JSONCollection, False$, 'application/hal+json')
If Assigned(Message) then
HTTP_Services('SetResponseStatus', 201, Message)
end else
HTTP_Services('SetResponseStatus', 201)
end
end else
Message = Error_Services('GetMessage')
HTTP_Services('SetResponseStatus', 500, 'Error in the ' : CurrentAPI : ' API. Message: ': Message)
end
return
API returntofab.getreturntofablabelzpl.HEAD
API returntofab.getreturntofablabelzpl.GET
@ -404,3 +422,26 @@ API returntofab.getreturntofablabelzpl.GET
HTTP_Services('SetResponseStatus', 401, 'Invalid session. Reauthentication required.')
end
end api
API returntofab.rtfoperations.HEAD
API returntofab.rtfoperations.GET
OIWizardID = ''
Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';'
Key = Field(Cookie, '=', 1)
If Key EQ 'sessionID' then
OIWizardID = Field(Cookie, '=', 2)
end
Next Cookie
ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID)
If ValidSession then
GoSub CreateOperationOptionCollection
end else
HTTP_Services('SetResponseStatus', 401, 'Invalid session. Reauthentication required.')
end
end api

File diff suppressed because it is too large Load Diff

View File

@ -127,5 +127,3 @@ API scrubber_pm.ID.GET
Logging_Services('AppendLog', objLog, LogData, @RM, @FM)
end
end api

View File

@ -830,8 +830,3 @@ end service

View File

@ -113,7 +113,7 @@ Service GetTools(ToolClass)
Query = 'SELECT TOOL '
If ToolClass NE '' then
Query := 'WITH CLASS EQ ':ToolClass:' '
Query := 'WITH CLASS EQ ': Quote(ToolClass)
end
Query := 'BY CLASS BY TOOL_ID'
Set_Status(0)
@ -238,6 +238,33 @@ Service ChangeToolMode(ToolID, NewMode, NewReason, CurrUser, ForceModeChange)
end service
Service GetNumPoints(ToolClass, ToolPattern)
ErrorMsg = ''
NumPoints = ''
If ( (ToolClass NE '') and (ToolPattern NE '') ) then
If RowExists('TOOL_CLASS', ToolClass) then
ToolPatterns = Xlate('TOOL_CLASS', ToolClass, 'PATTERN', 'X')
Locate ToolPattern in ToolPatterns using @VM setting PatternPos then
NumPoints = Xlate('TOOL_CLASS', ToolClass, 'PATTERN_SIZE', 'X')<0, PatternPos>
end else
ErrorMsg = 'Error in ':Service:' service. ToolPattern "':ToolPattern:'" not found in TOOL_CLASS "':ToolClass:'".'
end
end else
ErrorMsg = 'Error in ':Service:' service. ToolClass "':ToolClass:'" does not exist.'
end
end else
ErrorMsg = 'Error in ':Service:' service. Null ToolClass or ToolPattern passed into service.'
end
If ErrorMsg EQ '' then
Response = NumPoints
end else
Error_Services('Add', ErrorMsg)
end
end service
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Internal GoSubs
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -329,3 +356,4 @@ return

View File

@ -307,3 +307,72 @@ API wafercounter.completewafercount.POST
HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage)
end api
API wafercounter.ID.HEAD
API wafercounter.ID.GET
ErrorMessage = ''
ResponseCode = ''
WaferCounterId = EndPointSegment
CassId = ''
Body = ''
OIWizardID = ''
UserId = ''
Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';'
Key = Field(Cookie, '=', 1)
If Key EQ 'sessionID' then
OIWizardID = Field(Cookie, '=', 2)
end
Next Cookie
ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID)
CassBarcodeData = ''
UserId = Xlate('OI_WIZARD', OIWizardID, OI_WIZARD.EMPLOYEE_ID$, 'X')
StatusCode = ''
Body = HTTP_Services('GetHTTPPostString', True$)
DecodedJSON = HTTP_Services('DecodePercentString', Body)
//Log Entry into API -
LogData = ''
LogData<1> = LoggingDTM
LogData<2> = UserId
LogData<3> = OIWizardId
LogData<4> = 'Getting Wafer counter record. Record Id: ' : WaferCounterId
Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$)
If WaferCounterId NE '' then
WaferCounterJson = Wafer_Counter_Services('ConvertWaferCounterRecToJson', WaferCounterId)
If Error_Services('NoError') then
HTTP_Services('SetResponseBody', WaferCounterJson)
ResponseCode = 200
end else
ErrorMessage = Error_Services('GetMessage')
ResponseCode = 500
end
end else
ErrorMessage = 'Null wafer counter passed to endpoint.'
end
If ErrorMessage EQ '' then
//Log Success
LogData = ''
LogData<1> = LoggingDTM
LogData<2> = UserId
LogData<3> = OIWizardId
LogData<4> = 'Wafer Counter record successfully returned. Wafer Counter Id: ' : WaferCounterId
Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$)
end else
//Log Failure
LogData = ''
LogData<1> = LoggingDTM
LogData<2> = UserId
LogData<3> = OIWizardId
LogData<4> = 'Error returning wafer counter record. Wafer Counter Id: ' : WaferCounterId : ' . Error Message: ' : ErrorMessage
Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$)
end
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage)
end api

View File

@ -34,6 +34,8 @@ $Insert RLIST_EQUATES
$Insert WAFER_COUNTER_EQUATES
$Insert TOOL_EQUATES
$Insert TOOL_LOG_EQUATES
$Insert LOT_OPERATION_EQUATES
$Insert LOT_EQUATES
Equ Tab$ to \09\
Equ CRLF$ to \0D0A\
@ -528,8 +530,8 @@ Service GetWaferCounterJSONTestData(WaferSize, ToolLocation, CassID)
If SRP_JSON(objJson, 'New', 'Object') then
SRP_JSON(objJson, 'SetValue', 'dateTimeFormatted', Datetime(), 'String')
SRP_JSON(objJson, 'SetValue', 'equipmentId', 'WC8INCH1', 'String')
SRP_JSON(objJson, 'SetValue', 'total', 24, 'Number')
SRP_JSON(objJson, 'SetValue', 'slotMap', '1111111110111111111111111', 'String')
SRP_JSON(objJson, 'SetValue', 'total', 25, 'Number')
SRP_JSON(objJson, 'SetValue', 'slotMap', '1111111111111111111111111', 'String')
Response = SRP_Json(objJson, 'Stringify', 'Styled')
SRP_JSON(objJSON, 'Release')
end
@ -553,6 +555,181 @@ Service GetWaferCounterJSONTestData(WaferSize, ToolLocation, CassID)
end service
Service ConvertWaferCounterRecToJson(WaferCounterId)
ErrorMessage = ''
If WaferCounterId NE '' then
WaferCounterRec = Database_Services('ReadDataRow', 'WAFER_COUNTER', WaferCounterId, True$, 0, False$)
If Error_Services('NoError') then
//Fields within wafer counter rec
CassId = WaferCounterRec<WAFER_COUNTER.LOT_ID$>
swap '.' with '*' in CassId
WaferCount = WaferCounterRec<WAFER_COUNTER.SCAN_QTY$>
ScanDtm = WaferCounterRec<WAFER_COUNTER.SCAN_DTM$>
ToolID = WaferCounterRec<WAFER_COUNTER.SCAN_TOOL$>
WaferMapData = WaferCounterRec<WAFER_COUNTER.SCAN_WAFER_MAP$>
swap 1 with 1:@FM in WaferMapData
swap 0 with 0:@FM in WaferMapData
ActualWaferArray = ''
for i = 25 to 1 step -1
Slot = i
WaferPresent = WaferMapData<i>
ActualWaferArray<-1, 1> = Slot : @VM : WaferPresent
Next i
//Fields calculated at runtime.
CassType = ''
WONo = ''
CassNo = ''
ExpectedQty = ''
Begin Case
Case RowExists('RDS', CassId)
CassType = 'RDS'
WONo = XLATE('RDS', CassId, 'WO', 'X')
CassNo = XLATE('RDS', CassId, 'CASS_NO', 'X')
ExpectedQty = Xlate('RDS', CassId, 'WFRS_OUT', 'X')
Case RowExists('WM_OUT', CassId) OR RowExists('WM_IN', CassId)
CassType = 'WM_OUT'
WONo = Field(CassId, '*', 1)
CassNo = Field(CassId, '*', 3)
ExpectedQty = Xlate('WM_OUT', CassId, 'WAFER_CNT', 'X')
End Case
WoMatKey = WONo : '*' : CassNo
ExpectedWaferData = Wo_Mat_Services('GetWaferMap', WoMatKey)
ExpectedWaferArray = ''
for i = 25 to 1 step -1
Slot = i
WaferPresent = ExpectedWaferData<1, i>
ExpectedWaferArray<-1, 1> = Slot : @VM : WaferPresent
Next i
//Constructing the JSON Object
objJson = ''
If SRP_Json(objJson, 'New', 'Object') then
SRP_Json(objJson, 'SetValue', 'WaferCounterId', WaferCounterId, 'String')
SRP_Json(objJson, 'SetValue', 'CassId', CassId, 'String')
SRP_Json(objJson, 'SetValue', 'CassType', CassType, 'String')
SRP_Json(objJson, 'SetValue', 'ExpectedQty', ExpectedQty, 'Number')
SRP_Json(objJson, 'SetValue', 'ScanDtm', OConv(ScanDtm, 'DT4/'), 'String')
SRP_Json(objJson, 'SetValue', 'ToolId', ToolId, 'String')
SRP_Json(objJson, 'SetValue', 'WaferCount', WaferCount, 'Number')
//Wafer Counter Slot Array
objWaferCounterSlotArray = ''
IF SRP_Json(objWaferCounterSlotArray, 'New', 'Array') then
For each Slot in ActualWaferArray using @FM
SlotNo = Slot<1, 1>
WaferPresent = Slot<1, 2>
//Create the individiual slot object
objSlot = ''
If SRP_Json(objSlot, 'New', 'Object') then
SRP_Json(objSlot, 'SetValue', 'SlotNo', SlotNo, 'Number')
SRP_Json(objSlot, 'SetValue', 'WaferPresent', WaferPresent, 'Boolean')
SRP_Json(objWaferCounterSlotArray, 'Add', objSlot)
SRP_Json(objSlot, 'Release')
end
Next Slot
SRP_Json(objJson, 'Set', 'WaferArray', objWaferCounterSlotArray)
SRP_Json(objWaferCounterSlotArray, 'Release')
end
//OpenInsight Expected Slot Array
objOISlotArray = ''
IF SRP_Json(objOISlotArray, 'New', 'Array') then
For each Slot in ExpectedWaferArray using @FM
SlotNo = Slot<1, 1>
WaferPresent = Slot<1, 2>
//Create the individiual slot object
objSlot = ''
If SRP_Json(objSlot, 'New', 'Object') then
SRP_Json(objSlot, 'SetValue', 'SlotNo', SlotNo, 'Number')
SRP_Json(objSlot, 'SetValue', 'WaferPresent', WaferPresent, 'Boolean')
SRP_Json(objOISlotArray, 'Add', objSlot)
SRP_Json(objSlot, 'Release')
end
Next slot
SRP_Json(objJson, 'Set', 'ExpectedWaferArray', objOISlotArray)
SRP_Json(objWaferCounterSlotArray, 'Release')
end
Response = SRP_Json(objJson, 'Stringify', 'Styled')
SRP_Json(objJson, 'Release')
end else
ErrorMessage = 'Error initializing JSON object'
end
end else
ErrorMessage = 'Error reading wafer counter record. ' : Error_Services('GetMessage')
end
end else
ErrorMessage = 'Wafer counter id was null.'
end
If ErrorMessage NE '' then
Error_Services('Add', ErrorMessage)
end
end service
Service AssociateWaferCounter(LotOperationId, WaferCounterId, UserId)
ErrorMessage = ''
If RowExists('LSL_USERS', UserId) then
If RowExists('LOT_OPERATION', LotOperationId) then
If RowExists('WAFER_COUNTER', WaferCounterId) then
WaferCounterRec = Database_Services('ReadDataRow', 'WAFER_COUNTER', WaferCounterId, True$, 0, False$)
If Error_Services('NoError') then
WaferCounterToolId = WaferCounterRec<WAFER_COUNTER.SCAN_TOOL$>
ThisLotOpRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$)
If Error_Services('NoError') then
LotId = ThisLotOpRec<LOT_OPERATION_LOT_ID$>
If RowExists('LOT', LotId) then
ThisWaferCountCassId = WaferCounterRec<WAFER_COUNTER.LOT_ID$>
ThisLotId = ThisLotOpRec<LOT_OPERATION_LOT_ID$>
LegacyLotType = Xlate('LOT', ThisLotId, LOT_LEGACY_LOT_TYPE$, 'X')
LotIdToCompare = ''
If LegacyLotType NE '' then
LotIdToCompare = Xlate('LOT', ThisLotId, LOT_LEGACY_LOT_ID$, 'X')
end else
LotIdToCompare = ThisLotId
end
If ThisWaferCountCassId EQ LotIdToCompare then
ThisLotOpRec<LOT_OPERATION_WAFER_COUNTER_ID$> = WaferCounterId
Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationId, ThisLotOpRec)
If Error_Services('NoError') then
Lot_Event_Services('CreateLotEvent', LotId, Datetime(), 'LOG_WAFER_COUNT', 'Wafer Count logged.', WaferCounterToolId, UserId)
end
end else
ErrorMessage = 'Lot IDs do not match!'
end
end else
ErrorMessage = 'Lot not found.'
end
end else
ErrorMessage = Error_Services('GetMessage')
end
end else
ErrorMessage = Error_Services('GetMessage')
end
end else
ErrorMessage = 'Wafer counter record not found.'
end
end else
ErrorMessage = 'Lot Operation record not found.'
end
end else
ErrorMessage = 'User ID not found.'
end
If ErrorMessage NE '' then
Error_Services('Add', ErrorMessage)
end
end service
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Internal GoSubs
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -566,3 +743,5 @@ ClearCursors:
return

View File

@ -149,4 +149,3 @@ CreateHALItem:
HTTP_Services('SetResponseStatus', 500, 'Error in the ' : CurrentAPI : ' API. Message: ': Message)
end
return

View File

@ -120,4 +120,3 @@ CreateHalItem:
LogData<5> = ResponseMessage
Logging_Services('AppendLog', ObjLog, LogData, @RM, @FM)
return

View File

@ -0,0 +1,20 @@
compile insert CLEAN_EQUATES
/*----------------------------------------
Author : Table Create Insert Routine
Written : 17/06/2025
Description : Insert for Table CLEAN
----------------------------------------*/
#ifndef __CLEAN_EQUATES__
#define __CLEAN_EQUATES__
equ CLEAN_LOT_ID$ to 1
equ CLEAN_TOOL$ to 2
equ CLEAN_RECIPE$ to 3
equ CLEAN_COMPLETE_DTM$ to 4
equ CLEAN_LOT_OPERATION_ID$ to 5
equ CLEAN_CLEAN_START_DTM$ to 6
equ CLEAN_CLEAN_START_USER_ID$ to 7
equ CLEAN_CLEAN_STOP_DTM$ to 8
equ CLEAN_CLEAN_STOP_USER_ID$ to 9
#endif

View File

@ -23,13 +23,13 @@ compile insert LOT_OPERATION_EQUATES
equ LOT_OPERATION_MET_TEST_ID$ to 14
equ LOT_OPERATION_CLEAN_ID$ to 15
equ LOT_OPERATION_PACKAGING_ID$ to 16
equ LOT_OPERATION_WAFER_COUNTER_ID$ to 17
equ LOT_OPERATION_OPERATION_TYPE$ to 18
equ LOT_OPERATION_OPERATION_CLASS$ to 19
equ LOT_OPERATION_MET_TEST_TYPE_REQUIRED$ to 20
equ LOT_OPERATION_MET_TEST_REQUIRED$ to 21
equ LOT_OPERATION_PACKAGING_REQUIRED$ to 22
equ LOT_OPERATION_CLEAN_REQUIRED$ to 23
equ LOT_OPERATION_WAFER_COUNTER_REQUIRED$ to 24
equ LOT_OPERATION_WAFER_COUNTER_ID$ to 18
equ LOT_OPERATION_OPERATION_TYPE$ to 19
equ LOT_OPERATION_OPERATION_CLASS$ to 20
equ LOT_OPERATION_MET_TEST_TYPE_REQUIRED$ to 21
equ LOT_OPERATION_MET_TEST_REQUIRED$ to 22
equ LOT_OPERATION_PACKAGING_REQUIRED$ to 23
equ LOT_OPERATION_CLEAN_REQUIRED$ to 24
equ LOT_OPERATION_WAFER_COUNTER_REQUIRED$ to 25
#endif

View File

@ -1,21 +0,0 @@
compile insert METROLOGY_DATA_EXAMPLE_EQUATES
/*----------------------------------------
Author : Table Create Insert Routine
Written : 07/04/2025
Description : Insert for Table METROLOGY_DATA_EXAMPLE
----------------------------------------*/
#ifndef __METROLOGY_DATA_EXAMPLE_EQUATES__
#define __METROLOGY_DATA_EXAMPLE_EQUATES__
equ METROLOGY_DATA_EXAMPLE_INSPECTION_TYPE$ to 1
equ METROLOGY_DATA_EXAMPLE_TOOL_ID$ to 2
equ METROLOGY_DATA_EXAMPLE_DATA_ENTRY_DTM$ to 3
equ METROLOGY_DATA_EXAMPLE_DATA_ENTRY_USER$ to 4
equ METROLOGY_DATA_EXAMPLE_RAW_DATA_POINTS$ to 5
equ METROLOGY_DATA_EXAMPLE_DATA_AVERAGE$ to 6
equ METROLOGY_DATA_EXAMPLE_SPEC_LIMIT_UPPER$ to 7
equ METROLOGY_DATA_EXAMPLE_IN_SPEC$ to 8
equ METROLOGY_DATA_EXAMPLE_SPEC_LIMIT_LOWER$ to 9
#endif

View File

@ -1,7 +1,6 @@
compile insert MET_TEST_DATA_EQUATES
/*----------------------------------------
Author : Table Create Insert Routine
Written : 16/06/2025
Description : Insert for Table MET_TEST_DATA
----------------------------------------*/
#ifndef __MET_TEST_DATA_EQUATES__
@ -41,3 +40,4 @@ compile insert MET_TEST_DATA_EQUATES
equ MET_TEST_DATA.PROPERTY_15_OUT_OF_SPEC$ to 32
#endif

View File

@ -0,0 +1,16 @@
compile insert MET_TEST_INSERTS
/*----------------------------------------
Author : Daniel Stieber
Written : 20/05/2025
Description : Metadata Insert for
MET_TEST system.
----------------------------------------*/
#ifndef __MET_TEST_INSERTS__
#define __MET_TEST_INSERTS__
Declare subroutine Met_Test_Services
Declare function Met_Test_Services
Equ NUM_PROPERTIES$ to 15
#endif

View File

@ -0,0 +1,14 @@
compile insert PACKAGING_EQUATES
/*----------------------------------------
Author : Table Create Insert Routine
Written : 16/05/2025
Description : Insert for Table PACKAGING
----------------------------------------*/
#ifndef __PACKAGING_EQUATES__
#define __PACKAGING_EQUATES__
equ PACKAGING_LOT_ID$ to 1
equ PACKAGING_COMPLETE$ to 2
equ PACKAGING_COMPLETE_DTM$ to 3
#endif

View File

@ -1,7 +1,7 @@
compile insert PRODUCT_OPERATION_EQUATES
/*----------------------------------------
Author : Table Create Insert Routine
Written : 11/10/2024
Written : 13/05/2025
Description : Insert for Table PRODUCT_OPERATION
----------------------------------------*/
#ifndef __PRODUCT_OPERATION_EQUATES__