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 // Internal GoSubs
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -136,4 +136,3 @@ CreateHALCollection:
end end
return 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 RETURN

View File

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

View File

@ -220,6 +220,13 @@ Service GetWeekNum(InputDate)
end service 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 // Internal GoSubs

View File

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

View File

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

View File

@ -161,7 +161,3 @@ API Lock.HEAD
end end
end api 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 #pragma precomp SRP_PreCompiler
Declare function OI_Wizard_Services, Lot_Services, Database_Services, PSN_Services, Clean_Services
$insert APP_INSERTS $insert APP_INSERTS
$insert API_SETUP $insert API_SETUP
$insert HTTP_INSERTS $insert HTTP_INSERTS
$Insert OI_WIZARD_EQUATES
GoToAPI else GoToAPI else
// The specific resource endpoint doesn't have a API handler yet. // 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 Error_Services, Logging_Services, Database_Services, Lot_Services, Service_Services
Declare subroutine Transaction_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 LOT_TYPES = 'TW', 'RDS', 'WM_OUT', 'WM_IN', 'WO_MAT', 'LOT'
Options LEGACY_LOT_TYPES = 'RDS', 'WM_OUT', 'WM_IN' Options LEGACY_LOT_TYPES = 'RDS', 'WM_OUT', 'WM_IN'
Options BOOLEAN = 'True', 'False' Options BOOLEAN = 'True', 'False'
@ -230,3 +230,6 @@ InitEventLog:
return 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 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 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 Declare subroutine Database_Services, Error_Services, SRP_JSON, Lot_Services, Lot_Event_Services, Lot_Operation_Services
$insert LOGICAL $insert LOGICAL
$insert LOT_EQUATES $insert LOT_EQUATES
$Insert LOT_OPERATION_EQUATES $Insert LOT_OPERATION_EQUATES
$Insert METROLOGY_DATA_EXAMPLE_EQUATES
$Insert OPERATION_EQUATES $Insert OPERATION_EQUATES
$Insert MET_TEST_EQUATES $Insert MET_TEST_EQUATES
$Insert WAFER_COUNTER_EQUATES $Insert WAFER_COUNTER_EQUATES
@ -30,7 +30,7 @@ Service AddOperationToLot(LotId, OperationId, PrescribedSequence, UserId)
If RowExists('LOT', LotId) then If RowExists('LOT', LotId) then
If RowExists('OPERATION', OperationId) then If RowExists('OPERATION', OperationId) then
If PrescribedSequence AND Num(PrescribedSequence) 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) LotCurrOperation = Lot_Services('GetLotCurrOperationId', LotId)
CurrOperationSequence = Xlate('LOT_OPERATION', LotCurrOperation, LOT_OPERATION_OPERATION_SEQUENCE$, 'X') CurrOperationSequence = Xlate('LOT_OPERATION', LotCurrOperation, LOT_OPERATION_OPERATION_SEQUENCE$, 'X')
If CurrOperationSequence LT PrescribedSequence then If CurrOperationSequence LT PrescribedSequence then
@ -74,7 +74,8 @@ Service AddOperationToLot(LotId, OperationId, PrescribedSequence, UserId)
IsOperationRework = Database_Services('ReadDataColumn', 'OPERATION', OperationId, OPERATION_REWORK$) IsOperationRework = Database_Services('ReadDataColumn', 'OPERATION', OperationId, OPERATION_REWORK$)
Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationRecId, LotOperationRec) Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationRecId, LotOperationRec)
If Error_Services('NoError') then 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 end else
ErrorMessage = Error_Services('GetMessage') ErrorMessage = Error_Services('GetMessage')
end end
@ -86,7 +87,7 @@ Service AddOperationToLot(LotId, OperationId, PrescribedSequence, UserId)
ErrorMessage = 'Not allowed to add new operations prior to current operation' ErrorMessage = 'Not allowed to add new operations prior to current operation'
end end
end else 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
end else end else
ErrorMessage = 'Invalid operation sequence entered.' ErrorMessage = 'Invalid operation sequence entered.'
@ -102,7 +103,6 @@ Service AddOperationToLot(LotId, OperationId, PrescribedSequence, UserId)
Response = Operation Response = Operation
end else end else
Error_Services('Add', 'Error in ' : Service : '.' : ErrorMessage) Error_Services('Add', 'Error in ' : Service : '.' : ErrorMessage)
// todo: add logging
end end
end service end service
@ -114,6 +114,7 @@ Service RemoveLotOperation(LotOperationId, UserId)
Success = False$ Success = False$
If RowExists('LOT_OPERATION', LotOperationId) then If RowExists('LOT_OPERATION', LotOperationId) then
If Lot_Services('CanUserModifyLot', UserId) then
LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$) LotOperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$)
LotId = LotOperationRec<LOT_OPERATION_LOT_ID$> LotId = LotOperationRec<LOT_OPERATION_LOT_ID$>
MoveInTime = LotOperationRec<LOT_OPERATION_DATETIME_IN$> MoveInTime = LotOperationRec<LOT_OPERATION_DATETIME_IN$>
@ -132,7 +133,8 @@ Service RemoveLotOperation(LotOperationId, UserId)
end else end else
ErrorMessage = Error_Services('GetMessage') ErrorMessage = Error_Services('GetMessage')
end 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 end else
ErrorMessage = Error_Services('GetMessage') ErrorMessage = Error_Services('GetMessage')
end end
@ -142,20 +144,23 @@ Service RemoveLotOperation(LotOperationId, UserId)
end else end else
ErrorMessage = 'Unable to remove default operations.' ErrorMessage = 'Unable to remove default operations.'
end end
end else
ErrorMessage = 'User ' : UserId : ' does not have permission modify lots.'
end
end else end else
ErrorMessage = 'Lot Operation record not found' ErrorMessage = 'Lot Operation record not found'
end end
If ErrorMessage NE '' then If ErrorMessage NE '' then
Error_Services('Add', 'Error in service ': Service : ' : ' : ErrorMessage) Error_Services('Add', ErrorMessage)
end end
Response = Success Response = Success
end service end service
Service UpdateLotOperationSequence(LotId, StartSequence) Service UpdateLotOperationSequence(LotId, StartSequence)
ErrorMessage = '' ErrorMessage = ''
If StartSequence EQ '' then If StartSequence EQ '' then
StartSequence = 1 StartSequence = 1
@ -189,17 +194,6 @@ Service UpdateLotOperationSequence(LotId, StartSequence)
end service end service
Service ModifyLotOperationSequence(LotOperationId, NewSequence, UserId)
ErrorMessage = ''
If ErrorMessage NE '' then
end
end service
Service GetAvailableSequences(LotId) Service GetAvailableSequences(LotId)
AvailableSequences = '' AvailableSequences = ''
@ -211,40 +205,14 @@ Service GetAvailableSequences(LotId)
OperationClass = Database_Services('ReadDataColumn', 'OPERATION', OperationId, OPERATION_CLASS_ID$) OperationClass = Database_Services('ReadDataColumn', 'OPERATION', OperationId, OPERATION_CLASS_ID$)
StartDtm = LotOperationRec<LOT_OPERATION_DATETIME_IN$> StartDtm = LotOperationRec<LOT_OPERATION_DATETIME_IN$>
If StartDTM EQ '' then If StartDTM EQ '' then
If OperationClass NE 'RTF_DEFAULT' then
AvailableSequences<1, -1> = Sequence + 1 AvailableSequences<1, -1> = Sequence + 1
end end
end
Next LotOperationId Next LotOperationId
end end
Response = AvailableSequences Response = AvailableSequences
end service 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) Service ConvertRecordToJson(LotOperationId)
JsonString = '' JsonString = ''
@ -258,8 +226,14 @@ Service ConvertRecordToJson(LotOperationId)
SRP_JSON(objJSON, 'SetValue', 'LotId', LotId, 'String') SRP_JSON(objJSON, 'SetValue', 'LotId', LotId, 'String')
SRP_JSON(objJSON, 'SetValue', 'LegacyLotId', LegacyLotId, 'String') SRP_JSON(objJSON, 'SetValue', 'LegacyLotId', LegacyLotId, 'String')
SRP_JSON(objJSON, 'SetValue', 'OperationId', LotOperationRec<LOT_OPERATION_OPERATION_ID$>, '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') OperationDesc = XLATE('OPERATION', LotOperationRec<LOT_OPERATION_OPERATION_ID$>, OPERATION_OPERATION_DESCRIPTION$, 'X')
SRP_JSON(objJSON, 'SetValue', 'DateTimeOut', OConv(LotOperationRec<LOT_OPERATION_DATETIME_OUT$>, 'DT'), 'String') 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$> EquipmentId = LotOperationRec<LOT_OPERATION_EQUIPMENT_ID$>
SRP_JSON(objJSON, 'SetValue', 'EquipmentId', EquipmentId) SRP_JSON(objJSON, 'SetValue', 'EquipmentId', EquipmentId)
SRP_JSON(objJSON, 'SetValue', 'WaferInQty', LotOperationRec<LOT_OPERATION_WAFER_IN_QTY$>, 'Number') 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', 'OperatorInId', LotOperationRec<LOT_OPERATION_OPERATOR_IN_ID$>)
SRP_JSON(objJSON, 'SetValue', 'OperatorOutId', LotOperationRec<LOT_OPERATION_OPERATOR_OUT_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', 'OperationSequence', LotOperationRec<LOT_OPERATION_OPERATION_SEQUENCE$>)
SRP_JSON(objJSON, 'SetValue', 'DateTimeStart', OConv(LotOperationRec<LOT_OPERATION_DATETIME_START$>, 'DT'), 'String') DatetimeStart = Date_Services('ConvertDateTimeToISO8601', LotOperationRec<LOT_OPERATION_DATETIME_START$>)
SRP_JSON(objJSON, 'SetValue', 'DateTimeStop', OConv(LotOperationRec<LOT_OPERATION_DATETIME_STOP$>, 'DT'), 'String') 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', 'MetTestId', LotOperationRec<LOT_OPERATION_MET_TEST_ID$>)
SRP_JSON(objJSON, 'SetValue', 'CleanId', LotOperationRec<LOT_OPERATION_CLEAN_ID$>) SRP_JSON(objJSON, 'SetValue', 'CleanId', LotOperationRec<LOT_OPERATION_CLEAN_ID$>)
SRP_JSON(objJSON, 'SetValue', 'PackagingId', LotOperationRec<LOT_OPERATION_PACKAGING_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', 'PackagingRequired', LotOperationRec<LOT_OPERATION_PACKAGING_REQUIRED$>, 'Boolean')
SRP_JSON(objJson, 'SetValue', 'CleanRequired', LotOperationRec<LOT_OPERATION_CLEAN_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') 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$>) SRP_JSON(objJSON, 'SetValue', 'OperationType', LotOperationRec<LOT_OPERATION_OPERATION_TYPE$>)
//Add OPERATION Object //Add OPERATION Object
OperationJson = Operation_Services('ConvertRecordToJSON', LotOperationRec<LOT_OPERATION_OPERATION_ID$>) OperationJson = Operation_Services('ConvertRecordToJSON', LotOperationRec<LOT_OPERATION_OPERATION_ID$>)
@ -302,7 +293,7 @@ Service ConvertRecordToJson(LotOperationId)
end end
//Add Available Met Test Record //Add Available Met Test Record
AvailMetTestIds = Met_Test_Services('GetMetTests', LotId, LegacyLotId, '', EquipmentId, True$) AvailMetTestIds = Met_Test_Services('GetMetTests', LotId, LegacyLotId, '', '', True$)
objAvailMetTest = '' objAvailMetTest = ''
If SRP_Json(objAvailMetTest, 'New', 'Array') then If SRP_Json(objAvailMetTest, 'New', 'Array') then
for each MetTestId in AvailMetTestIds using @VM for each MetTestId in AvailMetTestIds using @VM
@ -316,8 +307,6 @@ Service ConvertRecordToJson(LotOperationId)
SRP_Json(objAvailMetTest, 'Release') SRP_Json(objAvailMetTest, 'Release')
end end
//Add in relevant recipes //Add in relevant recipes
//OperationType = LotOperationRec<LOT_OPERATION_OPERATION_TYPE$>
//MetTestTypeRequired = LotOperationRec<LOT_OPERATION_MET_TEST_TYPE_REQUIRED$>
Recipes = '' Recipes = ''
ShowThickRecipes = False$ ShowThickRecipes = False$
ShowResRecipes = False$ ShowResRecipes = False$
@ -340,7 +329,7 @@ Service ConvertRecordToJson(LotOperationId)
ShowCleanRecipes = True$ ShowCleanRecipes = True$
end end
ProdSpecNo = XLATE('LOT', LotId, LOT_PROD_SPEC_ID$, 'X') 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 If SRP_JSON(objRecipes, 'New', 'Array') then
for each Recipe in Recipes using @FM for each Recipe in Recipes using @FM
//ToolClass : @VM : Recipe : @VM : Stage //ToolClass : @VM : Recipe : @VM : Stage
@ -358,9 +347,8 @@ Service ConvertRecordToJson(LotOperationId)
SRP_JSON(objJSON, 'Set', 'RecipeParams', objRecipes) SRP_JSON(objJSON, 'Set', 'RecipeParams', objRecipes)
SRP_JSON(objRecipes, 'Release') SRP_JSON(objRecipes, 'Release')
end end
JsonString = SRP_JSON(objJSON, 'Stringify', 'Styled') JsonString = SRP_JSON(objJSON, 'Stringify', 'Fast')
SRP_JSON(objJSON, 'Release') SRP_JSON(objJSON, 'Release')
end end
Response = JsonString Response = JsonString
@ -370,12 +358,6 @@ end service
Service StartLotOperation(LotOperationId, UserId) 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 = '' ErrorMessage = ''
If RowExists('LOT_OPERATION', LotOperationId) then If RowExists('LOT_OPERATION', LotOperationId) then
@ -415,10 +397,7 @@ end service
Service CompleteLotOperation(LotOperationId, UserId) Service CompleteLotOperation(LotOperationId, UserId)
//1. Validate that the lot is moved into the operation
//2. Validate that the lot
ErrorMessage = '' ErrorMessage = ''
If RowExists('LOT_OPERATION', LotOperationId) then If RowExists('LOT_OPERATION', LotOperationId) then
If RowExists('LSL_USERS', UserId) then If RowExists('LSL_USERS', UserId) then
//We can also add additional checks like security checks, training checks, etc here if needed. //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.' ErrorMessage = 'Lot Operation has not finished processing and cannot be moved out.'
end end
end else end else
ErrorMessage = 'Lot is already moved into this operation.' ErrorMessage = 'Cannot complete operation because lot is not currently moved in.'
end end
end else 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
end else end else
ErrorMessage = 'Invalid user passed to routine.' ErrorMessage = 'Invalid user passed to routine.'
@ -455,7 +436,7 @@ Service CompleteLotOperation(LotOperationId, UserId)
Response = True$ Response = True$
end else end else
Response = False$ Response = False$
Error_Services('Add', 'Error in ' : Service : '. ' : ErrorMessage) Error_Services('Add', ErrorMessage)
end end
end service end service
@ -472,14 +453,14 @@ Service ValidateLotOperation(LotOperationId)
PackagingRequired = LotOperationRec<LOT_OPERATION_PACKAGING_REQUIRED$> PackagingRequired = LotOperationRec<LOT_OPERATION_PACKAGING_REQUIRED$>
CleanRequired = LotOperationRec<LOT_OPERATION_CLEAN_REQUIRED$> CleanRequired = LotOperationRec<LOT_OPERATION_CLEAN_REQUIRED$>
WaferCountRequired = LotOperationRec<LOT_OPERATION_WAFER_COUNTER_REQUIRED$> WaferCountRequired = LotOperationRec<LOT_OPERATION_WAFER_COUNTER_REQUIRED$>
OperationClass = XLATE('OPERATION', OperationId, OPERATION_CLASS_ID$, 'X')
If MetTestRequired then If MetTestRequired then
MetTestsInSpec = True$ MetTestsInSpec = True$
AssociatedMetTestIds = LotOperationRec<LOT_OPERATION_MET_TEST_ID$> AssociatedMetTestIds = LotOperationRec<LOT_OPERATION_MET_TEST_ID$>
If AssociatedMetTestIds NE '' then If AssociatedMetTestIds NE '' then
for each MetTestId in AssociatedMetTestIds using @VM for each MetTestId in AssociatedMetTestIds using @VM
MetTestOoS = Database_Services('ReadDataColumn', 'MET_TEST', MetTestId, MET_TEST.OUT_OF_SPEC$, True$, 0, False) MetTestOoS = Database_Services('ReadDataColumn', 'MET_TEST', MetTestId, MET_TEST.OUT_OF_SPEC$, True$, 0, False)
If MetTestOoS then If MetTestOoS AND OperationClass NE 'RTF' AND OperationClass NE 'RTF_DEFAULT' then
//ToDo Check that the met tests meet the requirements.
MetTestsInSpec = False$ MetTestsInSpec = False$
ErrorMessage = 'An associated Met test record is out of spec.' ErrorMessage = 'An associated Met test record is out of spec.'
end end
@ -490,14 +471,29 @@ Service ValidateLotOperation(LotOperationId)
ErrorMessage = 'Met tests are required and none are assigned.' ErrorMessage = 'Met tests are required and none are assigned.'
end end
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 end
If CleanRequired then
end 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
end else end else
ErrorMessage = 'Lot Operation not found' ErrorMessage = 'Lot Operation not found'
@ -509,27 +505,3 @@ Service ValidateLotOperation(LotOperationId)
Response = IsValid Response = IsValid
end service 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 #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 LOT_EQUATES
$Insert TEST_WAFER_PROD_EQUATES $Insert TEST_WAFER_PROD_EQUATES
$Insert LOT_OPERATION_EQUATES $Insert Lot_Operation_Equates
$Insert PRODUCT_OPERATION_EQUATES $Insert PRODUCT_OPERATION_EQUATES
$Insert LOT_EVENT_EQUATES $Insert LOT_EVENT_EQUATES
$Insert NOTIFICATION_EQUATES $Insert NOTIFICATION_EQUATES
$Insert VOIDED_LOT_EQUATES $Insert VOIDED_LOT_EQUATES
$Insert IFX_EQUATES $Insert RDS_EQUATES
$Insert WO_LOG_EQUATES
Declare function TEST_WAFER_PROD_SERVICES, SRP_Datetime, Datetime, Database_Services, Lot_Services, Error_Services, RTI_CREATEGUID $Insert PROD_VER_EQUATES
Declare function SRP_Array, SRP_Json, Environment_Services, Logging_Services, MemberOf, Lot_Event_Services, GetTickCount $Insert OPERATION_EQUATES
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
LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\Lot' LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\Lot'
LogDate = Oconv(Date(), 'D4/') 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' 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' 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' LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' LotMove.csv'
Headers = 'Logging DTM' : @FM : 'Lot Id' : @FM : 'Username' : @FM : 'Message' 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' Headers = 'Logging DTM' : @FM : 'Lot Id' : @FM : 'Operator' : @FM : 'Message'
objLotClosureLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$) 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 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') IsProd = Environment_Services('IsProd')
If IsProd EQ True$ then If IsProd EQ True$ then
@ -177,16 +182,16 @@ Service GenerateNewLotId(LotType)
end service end service
Service GetLotIdByLegacyLotIdAndType(LegacyLotId, LegacyLotType=LEGACY_LOT_TYPES)
Service GetLotIdByLegacyLotIdAndType(LegacyLotId, LegacyLotType)
StartTick = GetTickCount() StartTick = GetTickCount()
MetricName = 'GetLotIdByLegacyLotIdAndType' MetricName = 'GetLotIdByLegacyLotIdAndType'
ErrorMsg = '' ErrorMsg = ''
Open 'DICT.LOT' to DictLot then Open 'DICT.LOT' to DictLot then
SearchString = '' SearchString = ''
SearchString := 'LEGACY_LOT_ID':@VM:LegacyLotId:@FM SearchString := 'LEGACY_LOT_ID':@VM:LegacyLotId:@FM
SearchString := 'TYPE':@VM:LegacyLotType:@FM SearchString := 'LEGACY_LOT_TYPE':@VM:LegacyLotType:@FM
LotIdKeys = '' LotIdKeys = ''
Btree.Extract(SearchString, 'LOT', DictLot, LotIdKeys, '', '') Btree.Extract(SearchString, 'LOT', DictLot, LotIdKeys, '', '')
ErrCode = '' ErrCode = ''
@ -195,6 +200,7 @@ Service GetLotIdByLegacyLotIdAndType(LegacyLotId, LegacyLotType)
end else end else
Response = LotIdKeys<1,1> Response = LotIdKeys<1,1>
end end
end else end else
ErrorMsg = 'Error in ':Service:' service. Error opening LOT dictionary.' ErrorMsg = 'Error in ':Service:' service. Error opening LOT dictionary.'
end end
@ -202,13 +208,14 @@ Service GetLotIdByLegacyLotIdAndType(LegacyLotId, LegacyLotType)
EndTick = GetTickCount() EndTick = GetTickCount()
Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick) 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 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() StartTick = GetTickCount()
MetricName = 'CreateNewLot' MetricName = 'CreateNewLot'
@ -216,30 +223,69 @@ Service CreateNewLot(LotType, ProdName, LotQty, VendorPartNo, VendorLotNo, Vendo
ErrorMessage = '' ErrorMessage = ''
Begin Case Begin Case
Case LotType EQ 'RDS' OR LotType EQ 'WM_IN' OR LotType EQ 'WM_OUT' OR LotType EQ 'WO_MAT' 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 // Case statement for legacy lot entity types
NewLotId = Lot_Services('GenerateNewLotId', LotType) NewLotId = Lot_Services('GenerateNewLotId', LegacyLotType)
If NewLotId NE '' then If NewLotId NE '' then
If RowExists('LOT', NewLotId) NE False$ 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 = ''
LotRec<LOT_TYPE$> = LotType LotRec<LOT_TYPE$> = 'PROD'
LotRec<LOT_PROD_ID$> = '' LotRec<LOT_PROD_ID$> = ProdId
LotRec<LOT_ORIG_WAFER_QTY$> = LotQty LotRec<LOT_ORIG_WAFER_QTY$> = LotQty
LotRec<LOT_WAFER_QTY$> = LotQty LotRec<LOT_WAFER_QTY$> = LotQty
LotRec<LOT_VENDOR_PART_NO$> = VendorPartNo LotRec<LOT_VENDOR_PART_NO$> = VendorPartNo
LotRec<LOT_VENDOR_LOT_NO$> = VendorLotNo LotRec<LOT_VENDOR_LOT_NO$> = VendorLotNo
LotRec<LOT_VENDOR_CODE$> = VendorCode 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) Database_Services('WriteDataRow', 'LOT', NewLotId, LotRec)
If Error_Services('HasError') then If Error_Services('NoError') then
ErrorMessage = 'Error in ':Service:' service. ':Error_Services('GetMessage')
end else
CreatedLotNumber = NewLotId CreatedLotNumber = NewLotId
end else
ErrorMessage = 'Error in ':Service:' service. ':Error_Services('GetMessage')
end end
end else 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
end else 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 end
Case LotType EQ 'TW' Case LotType EQ 'TW'
If ProdName NE '' then If ProdName NE '' then
@ -536,7 +582,6 @@ end service
Service CreateInitialLotOperationRecords(LotId) Service CreateInitialLotOperationRecords(LotId)
ErrorMessage = '' ErrorMessage = ''
If LotId NE '' then If LotId NE '' then
LotRec = Database_Services('ReadDataRow', 'LOT', LotId) LotRec = Database_Services('ReadDataRow', 'LOT', LotId)
@ -545,9 +590,11 @@ Service CreateInitialLotOperationRecords(LotId)
ThisInitialProdOperations = Lot_Services('GetPrescribedOperationsByProdId', ProdId, LotType) ThisInitialProdOperations = Lot_Services('GetPrescribedOperationsByProdId', ProdId, LotType)
If Error_Services('NoError') AND ThisInitialProdOperations NE '' then If Error_Services('NoError') AND ThisInitialProdOperations NE '' then
For each ProdOperation in ThisInitialProdOperations using @VM For each ProdOperation in ThisInitialProdOperations using @VM
ProdOperationRec = Database_Services('ReadDataRow', 'PRODUCT_OPERATION', ProdOperation) ProdOperationRec = Database_Services('ReadDataRow', 'PRODUCT_OPERATION', ProdOperation)
OperationID = ProdOperationRec<PRODUCT_OPERATION_OPERATION_ID$> OperationID = ProdOperationRec<PRODUCT_OPERATION_OPERATION_ID$>
OperationSequence = ProdOperationRec<PRODUCT_OPERATION_OPERATION_SEQUENCE$> OperationSequence = ProdOperationRec<PRODUCT_OPERATION_OPERATION_SEQUENCE$>
LotOperationRecID = Rti_Createguid() LotOperationRecID = Rti_Createguid()
If Not(RowExists('LOT_OPERATION', LotOperationRecID)) then If Not(RowExists('LOT_OPERATION', LotOperationRecID)) then
LotOperationRec = '' LotOperationRec = ''
@ -556,22 +603,25 @@ Service CreateInitialLotOperationRecords(LotId)
LotOperationRec<LOT_OPERATION_OPERATION_SEQUENCE$> = OperationSequence LotOperationRec<LOT_OPERATION_OPERATION_SEQUENCE$> = OperationSequence
LotOperationRec<LOT_OPERATION_REWORK$> = False$ LotOperationRec<LOT_OPERATION_REWORK$> = False$
Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationRecId, LotOperationRec) 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 end else
ErrorMessage = 'Error in ':Service:' service. Lot Operation already existed, cannot overwrite.' ErrorMessage = 'Lot Operation already existed, cannot overwrite'
end end
Next Operation Next Operation
end else end else
ErrorMessage = 'Error in ':Service:' service. Error getting prescribed operations for lot# ' : LotId ErrorMessage = 'Error getting prescribed operations for lot# ' : LotId
end end
end else 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 end
If ErrorMessage NE '' then Error_Services('Add', ErrorMessage)
end service end service
// Returns a @FM delimited list of operations in sequence // Returns a @FM delimited list of operations in sequence
Service GetLotOperationSequence(LotId) Service GetLotOperationSequence(LotId)
@ -604,9 +654,10 @@ end service
Service GetLotCurrOperationId(LotId) Service GetLotCurrOperationId(LotId)
ErrorMsg = ''
StartTick = GetTickCount() StartTick = GetTickCount()
MetricName = 'GetLotCurrOperationId' MetricName = 'GetLotCurrOperationId'
ErrorMsg = ''
CurrOperation = '' CurrOperation = ''
If LotID NE '' then If LotID NE '' then
// Get them in sequence first // Get them in sequence first
@ -1025,16 +1076,27 @@ Service ConvertLotRecordToJson(LotId, ItemURL, CurrUser, FullObject=BOOLEAN)
ErrorMessage = '' ErrorMessage = ''
JsonString = '' JsonString = ''
If FullObject EQ '' then FullObject = True$ If FullObject EQ '' then
FullObject = True$
end
If RowExists('LOT', LotId) then If RowExists('LOT', LotId) then
objJSON = '' objJSON = ''
If SRP_JSON(objJSON, 'New', 'Object') then If SRP_JSON(objJSON, 'New', 'Object') then
LotRec = Database_Services('ReadDataRow', 'LOT', LotId) LotRec = Database_Services('ReadDataRow', 'LOT', LotId)
If Error_Services('NoError') then If Error_Services('NoError') then
If SRP_JSON(objLot, 'New', 'Object') then If SRP_JSON(objLot, 'New', 'Object') then
SRP_JSON(objLot, 'SetValue', 'LotId', LotId) 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', 'Type', LotRec<LOT_TYPE$>)
SRP_JSON(objLot, 'SetValue', 'ProdId', LotRec<LOT_PROD_ID$>) SRP_JSON(objLot, 'SetValue', 'ProdId', LotRec<LOT_PROD_ID$>)
ProdSpecNo = LotRec<LOT_PROD_SPEC_ID$>
SRP_JSON(objLot, 'SetValue', 'ProdSpecNo', ProdSpecNo, 'String')
Begin Case Begin Case
Case LotRec<LOT_TYPE$> = 'TW' Case LotRec<LOT_TYPE$> = 'TW'
ProdName = XLATE('TEST_WAFER_PROD', LotRec<LOT_PROD_ID$>, TEST_WAFER_PROD_PART_NAME$, 'X') ProdName = XLATE('TEST_WAFER_PROD', LotRec<LOT_PROD_ID$>, TEST_WAFER_PROD_PART_NAME$, 'X')
@ -1047,13 +1109,22 @@ Service ConvertLotRecordToJson(LotId, ItemURL, CurrUser, FullObject=BOOLEAN)
SRP_JSON(objLot, 'SetValue', 'VendorPartNo', LotRec<LOT_VENDOR_PART_NO$>) SRP_JSON(objLot, 'SetValue', 'VendorPartNo', LotRec<LOT_VENDOR_PART_NO$>)
SRP_JSON(objLot, 'SetValue', 'VendorLotNo', LotRec<LOT_VENDOR_LOT_NO$>) SRP_JSON(objLot, 'SetValue', 'VendorLotNo', LotRec<LOT_VENDOR_LOT_NO$>)
SRP_JSON(objLot, 'SetValue', 'Vendor', LotRec<LOT_VENDOR_CODE$>) SRP_JSON(objLot, 'SetValue', 'Vendor', LotRec<LOT_VENDOR_CODE$>)
CurrOperation = Lot_Services('GetLotCurrOperationId', LotId) CurrLotOperationId = Lot_Services('GetLotCurrOperationId', LotId)
CurrOperation = XLATE('LOT_OPERATION', CurrOperation, LOT_OPERATION_OPERATION_ID$, 'X') 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', 'CurrOperation', CurrOperation)
SRP_JSON(objLot, 'SetValue', 'CurrOperationDesc', CurrOperationDesc, 'String')
MostRecentEventId = LotRec<LOT_MOST_RECENT_LOT_EVENT_ID$> MostRecentEventId = LotRec<LOT_MOST_RECENT_LOT_EVENT_ID$>
MostRecentEventDtmIConv = Xlate('LOT_EVENT', MostRecentEventId, LOT_EVENT_EVENT_DATETIME$, 'X') MostRecentEventDtmIConv = Xlate('LOT_EVENT', MostRecentEventId, LOT_EVENT_EVENT_DATETIME$, 'X')
MostRecentEventDtmOConv = OConv(MostRecentEventDtmIConv, 'DT') MostRecentEventDtmOConv = OConv(MostRecentEventDtmIConv, 'DT')
SRP_JSON(objLot, 'SetValue', 'MostRecentEventDateTime', MostRecentEventDtmOConv) 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 If FullObject then
//Events Array //Events Array
EventsArrayJson = '' EventsArrayJson = ''
@ -1085,40 +1156,41 @@ Service ConvertLotRecordToJson(LotId, ItemURL, CurrUser, FullObject=BOOLEAN)
end else end else
ErrorMessage = 'Error Creating Events JSON Array' ErrorMessage = 'Error Creating Events JSON Array'
end end
// Operations Array
OperationsArrayJson = '' OperationsArrayJson = ''
If SRP_Json(OperationsArrayJson, 'New', 'Array') then If SRP_Json(OperationsArrayJson, 'New', 'Array') then
LotOperationKeys = Lot_Services('GetLotOperationSequence', LotId) LotOperationKeys = Lot_Services('GetLotOperationSequence', LotId)
for each LotOperationKey in LotOperationKeys using @FM for each LotOperationKey in LotOperationKeys using @FM
objOperation = '' ThisLotOperationJsonString = Lot_Operation_Services('ConvertRecordToJson', LotOperationKey)
OperationRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationKey) If SRP_Json(objLotOperation, 'PARSE', ThisLotOperationJsonString) EQ '' then
If SRP_Json(objOperation, 'New', 'Object') then SRP_Json(OperationsArrayJson, 'Add', objLotOperation)
SRP_JSON(objOperation, 'SetValue', 'LotOperationId', LotOperationKey) SRP_Json(objLotOperation, 'Release')
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')
end end
Next LotOperationKey Next LotOperationKey
SRP_JSON(objLot, 'Set', 'LotOperations', OperationsArrayJson) SRP_JSON(objLot, 'Set', 'LotOperations', OperationsArrayJson)
SRP_JSON(OperationsArrayJson, 'Release') 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 end else
ErrorMessage = 'Error Creating Operations JSON Array' ErrorMessage = 'Error Creating Operations JSON Array'
end end
end end
SRP_JSON(objJSON, 'Set', 'Lot', objLot) SRP_JSON(objJSON, 'Set', 'Lot', objLot)
SRP_JSON(objLot, 'Release') SRP_JSON(objLot, 'Release')
end else end else
@ -1135,12 +1207,10 @@ Service ConvertLotRecordToJson(LotId, ItemURL, CurrUser, FullObject=BOOLEAN)
end else end else
ErrorMessage = 'Invalid or null lot number passed to routine.' ErrorMessage = 'Invalid or null lot number passed to routine.'
end end
If ErrorMessage NE '' then
If ErrorMessage EQ '' then
Response = JsonString
end else
Error_Services('Add', ErrorMessage) Error_Services('Add', ErrorMessage)
end end
Response = JsonString
end service end service
@ -1339,7 +1409,7 @@ Service ReduceLotWaferCount(LotId, ReductionQty, OperatorId)
// Write Lot Event // Write Lot Event
Lot_Event_Services('CreateLotEvent', LotId, Datetime(), 'REDUCE_WAFER_QTY', 'Reduced wafer count by ' : ReductionQty, '', OperatorId, False$, '') 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 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) Service_Services('PostProcedure', 'LOT_SERVICES', ServiceParms)
If Error_Services('HasError') then If Error_Services('HasError') then
Recipients = Xlate('NOTIFICATION', 'FI_SUPPORT', NOTIFICATION_USER_ID$, 'X') Recipients = Xlate('NOTIFICATION', 'FI_SUPPORT', NOTIFICATION_USER_ID$, 'X')
@ -1510,11 +1580,37 @@ Service CreateNewVoidedLotRecord(LotId, LegacyLotId, LotType=LOT_TYPES, Username
EndTick = GetTickCount() EndTick = GetTickCount()
Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick) Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick)
If ErrorMessage NE '' then Error_Services('Add', ErrorMessage) If ErrorMessage NE '' then Error_Services('Add', ErrorMessage)
end service 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 // Internal GoSubs
//---------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------

View File

@ -132,4 +132,3 @@ CreateHALItem:
end end
return 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 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. 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 : Parameters :
Service [in] -- Name of the service being requested Service [in] -- Name of the service being requested
Param1-10 [in/out] -- Additional request parameter holders Param1-10 [in/out] -- Additional request parameter holders
@ -70,7 +83,7 @@ $Insert RLIST_EQUATES
$Insert WM_OUT_EQUATES $Insert WM_OUT_EQUATES
$Insert IQS_VIOL_DATA_EQUATES $Insert IQS_VIOL_DATA_EQUATES
Common /MetrologyServices/ MachineType@, RDSNo@ Common /MetrologyServices/ MachineType@, LegacyLotId@
Equ RETRY_ATTEMPTS$ TO 3 Equ RETRY_ATTEMPTS$ TO 3
Equ MINUTES_UNTIL_RETRY$ 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 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 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 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 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 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 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 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 Declare function SRP_String
LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\Metrology' LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\Metrology'
@ -163,6 +176,12 @@ end
Return Response else '' Return Response else ''
//----------------------------------------------------------------------------------------------------------------------
// Service Parameter Options
//----------------------------------------------------------------------------------------------------------------------
Options MACHINE_TYPES = 'Tencor', 'HgCV', 'CDE', 'Biorad', 'Stratus', 'SP1', 'SPV', 'SRP'
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Services // Services
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -387,7 +406,7 @@ end service
// //
// Looks for available Metrology files that are ready to be imported into the MES system. // 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 If Machine NE '' then
hSysLists = Database_Services('GetTableHandle', 'SYSLISTS') hSysLists = Database_Services('GetTableHandle', 'SYSLISTS')
@ -743,7 +762,7 @@ Service ImportStratusData(RunData, ResourceID, PSN)
ThickAvg = RunData<12> ThickAvg = RunData<12>
Positions = '' Positions = ''
DataPoints = '' DataPoints = ''
ToolClass = Xlate('TOOL', Tool, 'CLASS', 'X')
Loop Loop
Position = Trim(RunData<FieldPos>) Position = Trim(RunData<FieldPos>)
DataPoint = Trim(RunData<FieldPos + Offset>) DataPoint = Trim(RunData<FieldPos + Offset>)
@ -767,17 +786,69 @@ Service ImportStratusData(RunData, ResourceID, PSN)
Case RowExists('WM_OUT', Cassette) Case RowExists('WM_OUT', Cassette)
WorkOrderNo = Field(Cassette, '*', 1) WorkOrderNo = Field(Cassette, '*', 1)
CassNo = Field(Cassette, '*', 3) CassNo = Field(Cassette, '*', 3)
RDSNo@ = Cassette ; // This is used for logging purposes. LegacyLotId@ = Cassette
IsEpiPro = true$ IsEpiPro = True$
LegacyLotType = 'WM_OUT'
Case RowExists('RDS', RDSNo) Case RowExists('RDS', RDSNo)
WorkOrderNo = Xlate('RDS', RDSNo, 'WO', 'X') WorkOrderNo = Xlate('RDS', RDSNo, 'WO', 'X')
CassNo = Xlate('RDS', RDSNo, 'CASS_NO', 'X') CassNo = Xlate('RDS', RDSNo, 'CASS_NO', 'X')
RDSNo@ = RDSNo ; // This is used for logging purposes. LegacyLotId@ = RDSNo
LegacyLotType = 'RDS'
Case Otherwise$ Case Otherwise$
Error_Services('Add', 'Unrecognized cassette ID ':Cassette:'.') Error_Services('Add', 'Unrecognized cassette ID ':Cassette:'.')
End Case End Case
If Error_Services('NoError') then 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 // Update WO_MAT record
StdDev = '' StdDev = ''
@ -804,15 +875,15 @@ Service ImportStratusData(RunData, ResourceID, PSN)
end end
Database_Services('WriteDataRow', 'WO_MAT', WOMatKey, WOMatRec, True$, False$, True$) Database_Services('WriteDataRow', 'WO_MAT', WOMatKey, WOMatRec, True$, False$, True$)
If Error_Services('HasError') then 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
end else end else
Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end end
// Update the WM_OUT record for EpiPro // Update the WM_OUT record for EpiPro
If IsEpiPro then If IsEpiPro then
NumVals = 0 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 For each Wafer in Positions using @VM setting dPos
If Wafer NE '' then If Wafer NE '' then
WMORec<WM_OUT_MU_WAFER_THK_RESULT$, Wafer> = DataPoints<0, dPos> 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 = Math_Services('GetStdDev', Vals, StdDevType)
StdDev = OConv(IConv(StdDev, 'MD3'), 'MD3') StdDev = OConv(IConv(StdDev, 'MD3'), 'MD3')
end end
Database_Services('WriteDataRow', 'WM_OUT', RDSNo@, WMORec, True$, False$, True$) Database_Services('WriteDataRow', 'WM_OUT', LegacyLotId@, WMORec, True$, False$, True$)
end end
// Update WO_MAT_QA record // Update WO_MAT_QA record
@ -882,15 +953,15 @@ Service ImportStratusData(RunData, ResourceID, PSN)
Next Profile Next Profile
Database_Services('WriteDataRow', 'WO_MAT_QA', WOMatQAID, WOMatQARec, True$, False$, True$) Database_Services('WriteDataRow', 'WO_MAT_QA', WOMatQAID, WOMatQARec, True$, False$, True$)
If Error_Services('NoError') then If Error_Services('NoError') then
Metrology_Services('LogResults', RDSNo@, Machine, 'UID000', Service : ' : Success.') Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID000', Service : ' : Success.')
end else end else
Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end end
end else end else
Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end end
end else end else
Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end end
end service end service
@ -1037,6 +1108,56 @@ Service ImportBioRadData(RunData, ResourceID, IsViewerFile, PSN, FileName)
Swap ' AM' with 'AM' in Timestamp Swap ' AM' with 'AM' in Timestamp
Swap ' PM' with 'PM' in Timestamp Swap ' PM' with 'PM' in Timestamp
Timestamp = IConv(Timestamp,'DT') 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 RDSLayerKeyID = RDSKeyID : '*' : RunDataLayer
NumDataPoints = DCount(DataPoints, @VM) NumDataPoints = DCount(DataPoints, @VM)
RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID) RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID)
@ -1255,7 +1376,6 @@ Service ImportBioRadData(RunData, ResourceID, IsViewerFile, PSN, FileName)
end service end service
Service ImportCDEQualData(RunData, ResourceID, PSN) Service ImportCDEQualData(RunData, ResourceID, PSN)
Machine = 'CDE' Machine = 'CDE'
@ -1288,7 +1408,6 @@ Service ImportCDEQualData(RunData, ResourceID, PSN)
end service end service
Service ImportCDEData(RunData, ResourceID, IsViewerFile, PSN) Service ImportCDEData(RunData, ResourceID, IsViewerFile, PSN)
Machine = 'CDE' Machine = 'CDE'
@ -1381,6 +1500,57 @@ Service ImportCDEData(RunData, ResourceID, IsViewerFile, PSN)
Swap ' PM' with 'PM' in Timestamp Swap ' PM' with 'PM' in Timestamp
Timestamp = IConv(Timestamp,'DT') 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 RDSLayerKeyID = RDSKeyID : '*' : RunDataLayer
NumDataPoints = DCount(DataPoints, @VM) NumDataPoints = DCount(DataPoints, @VM)
RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID) RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID)
@ -1549,7 +1719,7 @@ Service ImportHgCVData(RunData, ResourceID, IsViewerFile, PSN)
DataIndex = RDS_TEST_READ_HGCV1_RES$ DataIndex = RDS_TEST_READ_HGCV1_RES$
DTMIndex = RDS_TEST_TEST_RUN_HGCV_DTM$ DTMIndex = RDS_TEST_TEST_RUN_HGCV_DTM$
Metrology_Services('LogResults', RDSKeyID, Machine, 'UID000', Service : ' : ' : 'Beginning ImportHgCVData') Metrology_Services('LogResults', RDSKeyID, Machine, 'UID000', Service : ' : ' : 'Beginning ImportHgCVData')
RDSNo@ = RDSKeyID LegacyLotId@ = RDSKeyID
RDSRec = Database_Services('ReadDataRow', 'RDS', RDSKeyID) RDSRec = Database_Services('ReadDataRow', 'RDS', RDSKeyID)
If Error_Services('NoError') then If Error_Services('NoError') then
WorkOrderNo = RDSRec<RDS_WO$> WorkOrderNo = RDSRec<RDS_WO$>
@ -1606,23 +1776,83 @@ Service ImportHgCVData(RunData, ResourceID, IsViewerFile, PSN)
Positions = '' Positions = ''
DataPoints = '' DataPoints = ''
HgCVDataPoints = '' HgCVDataPoints = ''
PhaseDataPoints = ''
Loop Loop
Position = Trim(RunData<FieldPos>) Position = Trim(RunData<FieldPos>)
HgCVDataPoint = Trim(RunData<FieldPos + Offset>) HgCVDataPoint = Trim(RunData<FieldPos + Offset>)
PhaseDataPoint = Trim(RunData<FieldPos + PhaseOffset>)
Until Position EQ '' Until Position EQ ''
Positions := Position : @VM Positions := Position : @VM
HgCVDataPoints := HgCVDataPoint : @VM HgCVDataPoints := HgCVDataPoint : @VM
PhaseDataPoints := PhaseDataPoint : @VM
FieldPos += FieldPosIncrement FieldPos += FieldPosIncrement
Repeat Repeat
Positions[-1, 1] = '' ; // Strip final @VM Positions[-1, 1] = '' ; // Strip final @VM
HgCVDataPoints[-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) HgCVDataPoints = Iconv(HgCVDataPoints, 'MD' : Decimals)
PhaseDataPoints = Iconv(PhaseDataPoints, 'MD' : Decimals)
Swap ' AM' with 'AM' in Timestamp Swap ' AM' with 'AM' in Timestamp
Swap ' PM' with 'PM' in Timestamp Swap ' PM' with 'PM' in Timestamp
Timestamp = IConv(Timestamp,'DT') 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 RDSLayerKeyID = RDSKeyID : '*' : RunDataLayer
NumDataPoints = DCount(HgCVDataPoints, @VM) NumDataPoints = DCount(HgCVDataPoints, @VM)
RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID) RDSLayerRec = Database_Services('ReadDataRow', 'RDS_LAYER', RDSLayerKeyID)
@ -1673,7 +1903,6 @@ Service ImportHgCVData(RunData, ResourceID, IsViewerFile, PSN)
PhaseDataPoints[-1, 1] = '' ; // Strip final @VM PhaseDataPoints[-1, 1] = '' ; // Strip final @VM
PhaseDataPoints = Iconv(PhaseDataPoints, 'MD' : Decimals) PhaseDataPoints = Iconv(PhaseDataPoints, 'MD' : Decimals)
DataPoints = HgCVDataPoints DataPoints = HgCVDataPoints
* GoSub CalculateQAData
Response = QA_Services('CalculateHgCVData', Datapoints) Response = QA_Services('CalculateHgCVData', Datapoints)
HgCVMin = Response<0, 2> HgCVMin = Response<0, 2>
HgCVMax = Response<0, 3> HgCVMax = Response<0, 3>
@ -1687,23 +1916,12 @@ Service ImportHgCVData(RunData, ResourceID, IsViewerFile, PSN)
DataPoints = PhaseDataPoints DataPoints = PhaseDataPoints
Response = QA_Services('CalculateHgCVData', Datapoints) Response = QA_Services('CalculateHgCVData', Datapoints)
* GoSub CalculateQAData
PhaseMin = Response<0, 2> PhaseMin = Response<0, 2>
PhaseMax = Response<0, 3> PhaseMax = Response<0, 3>
PhaseAvg = Response<0, 1> PhaseAvg = Response<0, 1>
PhaseEdgeMean = Response<0, 4> PhaseEdgeMean = Response<0, 4>
PhaseRangePct = Response<0, 5> PhaseRangePct = Response<0, 5>
// Format data. Round to significant digits. // 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_RESULT$, vPos> = HgCVAvg : @SVM : PhaseAvg
WOMatQARec<WO_MAT_QA_MIN_RESULT$, vPos> = HgCVMin : @SVM : PhaseMin WOMatQARec<WO_MAT_QA_MIN_RESULT$, vPos> = HgCVMin : @SVM : PhaseMin
WOMatQARec<WO_MAT_QA_MAX_RESULT$, vPos> = HgCVMax : @SVM : PhaseMax WOMatQARec<WO_MAT_QA_MAX_RESULT$, vPos> = HgCVMax : @SVM : PhaseMax
@ -1853,13 +2071,98 @@ Service ImportTencorData(RunData)
SoDMin = RunData<41> SoDMin = RunData<41>
ScanTool = RunData<43> ScanTool = RunData<43>
Swap '%' with ' ' in ScanTool Swap '%' with ' ' in ScanTool
RDSNo@ = RDSKeyID LegacyLotId@ = RDSKeyID
Convert @Lower_Case to @Upper_Case in ScanTool Convert @Lower_Case to @Upper_Case in ScanTool
Swap ' AM' with 'AM' in Timestamp Swap ' AM' with 'AM' in Timestamp
Swap ' PM' with 'PM' in Timestamp Swap ' PM' with 'PM' in Timestamp
Timestamp = IConv(Timestamp,'DT') 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 If RowExists('RDS', RDSKeyID) then
// Try to read the CleanInsp datarow. Use this to identify the RDSKeyID. // Try to read the CleanInsp datarow. Use this to identify the RDSKeyID.
ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSKeyID) ReactRunRec = Database_Services('ReadDataRow', 'REACT_RUN', RDSKeyID)
@ -1893,30 +2196,11 @@ Service ImportTencorData(RunData)
NumWfrs = 0 NumWfrs = 0
Locate ScanRecipe In SpecRecipeList Using @VM Setting RecipeIndex then Locate ScanRecipe In SpecRecipeList Using @VM Setting RecipeIndex then
// Recipe found in spec list // 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 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 For each WaferNo in WaferNos using @VM
If WaferNo NE '' then If WaferNo NE '' then
CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$, ScanIndex, WaferNo> = SODVals<1,WaferNo> CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$, ScanIndex, WaferNo> = SODVals<1,WaferNo>
CleanInspRec<CLEAN_INSP_SCAN_SORT_PER_WAFER$, ScanIndex, WaferNo> = SortVals<1,WaferNo> CleanInspRec<CLEAN_INSP_SCAN_SORT_PER_WAFER$, ScanIndex, WaferNo> = SortVals<1,WaferNo>
QA_Services('PostWaferImageRequest', RDSKeyID, WaferNo, ScanRecipe)
end end
Next Wafer Next Wafer
end end
@ -2019,28 +2303,18 @@ Service ImportTencorData(RunData)
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_INSP_TEST_RUN_DTM$, -1, 0, Timestamp) 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_SURFSCAN_RECIPE$, -1, 0, ScanRecipe)
CleanInspRec = Insert(CleanInspRec, CLEAN_INSP_SPEC_SURF_DEFECTS$, -1, 0, DefectSpec) 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 If SODWaferArray NE '' then
WaferNos = SODWaferArray<1>
SODVals = SODWaferArray<2>
SortVals = SODWaferArray<3>
NumRecipes = DCount(CleanInspRec<CLEAN_INSP_SCAN_RECIPE$>, @VM) 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 For each WaferNo in WaferNos using @VM
If WaferNo NE '' then If WaferNo NE '' then
CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$, NumRecipes, WaferNo> = SODVals<1,WaferNo> CleanInspRec<CLEAN_INSP_SCAN_SOD_PER_WAFER$, NumRecipes, WaferNo> = SODVals<1,WaferNo>
CleanInspRec<CLEAN_INSP_SCAN_SORT_PER_WAFER$, NumRecipes, WaferNo> = SortVals<1,WaferNo> CleanInspRec<CLEAN_INSP_SCAN_SORT_PER_WAFER$, NumRecipes, WaferNo> = SortVals<1,WaferNo>
QA_Services('PostWaferImageRequest', RDSKeyID, WaferNo, ScanRecipe)
end end
Next Wafer Next Wafer
end end
if exists Eq False$ then If exists EQ False$ then
oCIParms := CleanInspRec ; oCIParms := CleanInspRec ;
CINo = obj_Clean_Insp('Create',oCIParms) CINo = obj_Clean_Insp('Create',oCIParms)
If Error_Services('NoError') then If Error_Services('NoError') then
@ -2053,7 +2327,7 @@ Service ImportTencorData(RunData)
LogData = '' LogData = ''
LogData<1> = Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTS') LogData<1> = Oconv(Date(), 'D4/') : ' ' : Oconv(Time(), 'MTS')
LogData<2> = MachineType@ LogData<2> = MachineType@
LogData<3> = RDSNo@ LogData<3> = LegacyLotId@
LogData<4> = 'Time taken to import POST data: ':TimeTaken:' seconds.' LogData<4> = 'Time taken to import POST data: ':TimeTaken:' seconds.'
Logging_Services('AppendLog', objPOSTPerfLog, LogData, @RM, @FM) Logging_Services('AppendLog', objPOSTPerfLog, LogData, @RM, @FM)
end else end else
@ -2062,7 +2336,7 @@ Service ImportTencorData(RunData)
ErrorMessage = 'Failed to create CLEAN_INSP record. Error UID002.' ErrorMessage = 'Failed to create CLEAN_INSP record. Error UID002.'
end end
end else end else
//write to existing CI rec. // Write to existing CI rec.
obj_Tables('WriteRec','CLEAN_INSP':@RM:CINo:@RM:@RM:CleanInspRec) obj_Tables('WriteRec','CLEAN_INSP':@RM:CINo:@RM:@RM:CleanInspRec)
end end
end else end else
@ -2117,17 +2391,64 @@ Service ImportSP1Data(RunData)
end end
ScanTool = RunData<43> ScanTool = RunData<43>
DCNMM2 = RunData<44> DCNMM2 = RunData<44>
* Swap '%' with ' ' in ScanTool
// The 4th character can be 0 or %, but needs to be ' ' in OpenInsight // The 4th character can be 0 or %, but needs to be ' ' in OpenInsight
ScanTool[4,1] = ' ' ScanTool[4,1] = ' '
Convert @Lower_Case to @Upper_Case in ScanTool Convert @Lower_Case to @Upper_Case in ScanTool
Convert @Lower_Case to @Upper_Case in CompareScanRecipe Convert @Lower_Case to @Upper_Case in CompareScanRecipe
* Convert ' ' to '' in CompareScanRecipe
Swap ' AM' with 'AM' in Timestamp Swap ' AM' with 'AM' in Timestamp
Swap ' PM' with 'PM' in Timestamp Swap ' PM' with 'PM' in Timestamp
Timestamp = IConv(Timestamp,'DT') 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) RDSRec = Database_Services('ReadDataRow', 'RDS', RDSKeyID)
If Error_Services('NoError') then If Error_Services('NoError') then
WorkOrderNo = RDSRec<RDS_WO$> 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 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. 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> Timestamp = RunData<2>
WMOKeyID = RunData<6> WMOKeyID = RunData<6>
@ -2552,20 +2873,66 @@ Service ImportBioRadEPPFQAData(RunData, FileName)
Positions[-1, 1] = '' ; // Strip final @VM Positions[-1, 1] = '' ; // Strip final @VM
DataPoints[-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 Error_Services('NoError') then
If DataSlotId NE '' then Met_Test_Services('SetPropsAndLimits', MetTestId)
If Num(DataSlotId) then 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 //Update the WM_OUT record for EpiPro
WMORec<WM_OUT_MU_WAFER_THK_RESULT$, Int(DataSlotId)> = DataPoints WMORec<WM_OUT_MU_WAFER_THK_RESULT$, DataSlotId> = DataPoints
Database_Services('WriteDataRow', 'WM_OUT', WMOKeyID, WMORec, True$, False$, True$) Database_Services('WriteDataRow', 'WM_OUT', WMOKeyID, WMORec, True$, False$, True$)
end else end else
Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : DataSlotId ':Quote(DataSlotId):' is not a number!') Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
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'))
end end
// Update WO_MAT_QA record // Update WO_MAT_QA record
WOMatQAID = Field(WMOKeyID, '*', 1) : '*' : Field(WMOKeyID, '*', 3) WOMatQAID = Field(WMOKeyID, '*', 1) : '*' : Field(WMOKeyID, '*', 3)
@ -2608,12 +2975,12 @@ Service ImportBioRadEPPFQAData(RunData, FileName)
Next Profile Next Profile
Database_Services('WriteDataRow', 'WO_MAT_QA', WOMatQAID, WOMatQARec, True$, False$, True$) Database_Services('WriteDataRow', 'WO_MAT_QA', WOMatQAID, WOMatQARec, True$, False$, True$)
If Error_Services('NoError') then If Error_Services('NoError') then
Metrology_Services('LogResults', RDSNo@, Machine, 'UID000', Service : ' : Success.') Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID000', Service : ' : Success.')
end else end else
Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end end
end else end else
Metrology_Services('LogResults', RDSNo@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage')) Metrology_Services('LogResults', LegacyLotId@, Machine, 'UID001', Service : ' : ' : Error_Services('GetMessage'))
end end
end service end service
@ -3277,3 +3644,6 @@ LoadRunDataToDatabase:
return 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
end api end api

View File

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

View File

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

View File

@ -300,3 +300,5 @@ SetDelay:
return 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 APP_INSERTS
$insert WO_MAT_EQUATES $insert WO_MAT_EQUATES
$insert NOTIFICATION_EQU $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 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 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 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 GoToService else
Error_Services('Add', Service : ' is not a valid service request within the ' : ServiceModule : ' module.') 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 RDSKey = CassetteID
WMOKey = CassetteID WMOKey = CassetteID
LotId = ''
Convert '.' to '*' in WMOKey Convert '.' to '*' in WMOKey
CommentEntity = '' CommentEntity = ''
Begin Case Begin Case
@ -70,11 +84,13 @@ Service CompletePackaging(CassetteID, OperatorID, BaggerIdentifier)
WOMatKey = Xlate('RDS', RDSKey, 'WO', 'X') WOMatKey = Xlate('RDS', RDSKey, 'WO', 'X')
WOMatKey = WoMatKey:'*':Xlate('RDS', RDSKey, 'CASS_NO', 'X') WOMatKey = WoMatKey:'*':Xlate('RDS', RDSKey, 'CASS_NO', 'X')
CommentEntity = 'RDS' CommentEntity = 'RDS'
LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', RDSKey, 'RDS')
Case RowExists('WM_OUT', WMOKey) EQ True$ Case RowExists('WM_OUT', WMOKey) EQ True$
// WM_OUT key // WM_OUT key
WOMatKey = Xlate('WM_OUT', WMOKey, 'WO_MAT_KEY', 'X') WOMatKey = Xlate('WM_OUT', WMOKey, 'WO_MAT_KEY', 'X')
CommentEntity = 'WM_OUT' CommentEntity = 'WM_OUT'
LotId = Lot_Services('GetLotIdByLegacyLotIdAndType', WMOKey, 'WM_OUT')
Case RowExists('WO_MAT', CassetteID) EQ True$ Case RowExists('WO_MAT', CassetteID) EQ True$
// WO_MAT key // WO_MAT key
@ -138,6 +154,24 @@ Service CompletePackaging(CassetteID, OperatorID, BaggerIdentifier)
// Add CassComp transaction to SAP queue // Add CassComp transaction to SAP queue
SAPBatchNo = Xlate('WO_MAT', WOMatKey, 'SAP_BATCH_NO', 'X') SAPBatchNo = Xlate('WO_MAT', WOMatKey, 'SAP_BATCH_NO', 'X')
If SAPBatchNo EQ '' then SAP_Services('AddCassCompTransaction', WOMatKey) 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
end end
@ -664,3 +698,72 @@ Service ProcessScanData(ScanData, ScanType = SCAN_TYPES, Param1, Param2, Param3)
end service 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') HTTP_Resource_Services('LoremIpsum')
end api end api

View File

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

View File

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

View File

@ -35,9 +35,11 @@ $Insert RDS_TEST_EQUATES
$Insert RDS_TEST_PROP_EQUATES $Insert RDS_TEST_PROP_EQUATES
$Insert PRS_LAYER_EQU $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 Database_Services, Psn_Services, obj_Prod_Spec, Error_Services, SRP_JSON, Cust_Epi_Part_Services
Declare function Prod_Ver_Services, PRS_Stage_Services Declare function Prod_Ver_Services, PRS_Stage_Services, SRP_Array
Declare subroutine Database_Services, Psn_Services, Error_Services, SRP_JSON Declare subroutine Database_Services, Psn_Services, Error_Services, SRP_JSON, Extract_Si_Keys
GoToService else GoToService else
Error_Services('Add', Service : ' is not a valid service request within the ' : ServiceModule : ' services module.') Error_Services('Add', Service : ' is not a valid service request within the ' : ServiceModule : ' services module.')
@ -72,6 +74,216 @@ Service InitializeCritParams(PSNo)
end service 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) Service CheckPSNStages(PSNo, Stage)
Begin Case Begin Case
@ -950,3 +1162,8 @@ CheckAdHoc:
return return

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -129,7 +129,7 @@ API returntofab.ID.GET
UserId = Xlate('OI_WIZARD', OIWizardID, 'EMPLOYEE_ID', 'X') UserId = Xlate('OI_WIZARD', OIWizardID, 'EMPLOYEE_ID', 'X')
RTFId = EndpointSegment RTFId = EndpointSegment
If Error_Services('NoError') AND RTFId NE '' then 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 If Error_Services('NoError') then
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseBody', RTFJson, False$, 'application/hal+json') HTTP_Services('SetResponseBody', RTFJson, False$, 'application/hal+json')
@ -247,7 +247,6 @@ end api
API returntofab.reportopenforms.HEAD API returntofab.reportopenforms.HEAD
API returntofab.reportopenforms.GET API returntofab.reportopenforms.GET
OIWizardID = '' OIWizardID = ''
Cookies = HTTP_Services('GetHTTPCookie') Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';' For each Cookie in Cookies using ';'
@ -259,12 +258,9 @@ API returntofab.reportopenforms.GET
ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID) ValidSession = OI_Wizard_Services('ValidateSession', OIWizardID)
If ValidSession then
UserId = Xlate('OI_WIZARD', OIWizardID, 'EMPLOYEE_ID', 'X') 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$) RTFJson = Return_To_Fab_Services('CreateReturnToFabReportJson', True$)
If Error_Services('NoError') then If RTFJson NE '' then
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseBody', RTFJson, False$, 'application/hal+json') HTTP_Services('SetResponseBody', RTFJson, False$, 'application/hal+json')
If Assigned(Message) then If Assigned(Message) then
@ -273,14 +269,7 @@ API returntofab.reportopenforms.GET
HTTP_Services('SetResponseStatus', 201) HTTP_Services('SetResponseStatus', 201)
end end
end else end else
ErrorMessage = 'Error getting report data.'
end
end else
HTTP_Services('SetResponseStatus', 400, Error_Services('GetMessage'))
end
end else
HTTP_Services('SetResponseStatus', 401, 'Invalid session. Reauthentication required.')
end end
end api end api
@ -288,7 +277,6 @@ end api
API returntofab.reportallforms.HEAD API returntofab.reportallforms.HEAD
API returntofab.reportallforms.GET API returntofab.reportallforms.GET
OIWizardID = '' OIWizardID = ''
Cookies = HTTP_Services('GetHTTPCookie') Cookies = HTTP_Services('GetHTTPCookie')
For each Cookie in Cookies using ';' For each Cookie in Cookies using ';'
@ -303,9 +291,9 @@ API returntofab.reportallforms.GET
If ValidSession then If ValidSession then
UserId = Xlate('OI_WIZARD', OIWizardID, 'EMPLOYEE_ID', 'X') UserId = Xlate('OI_WIZARD', OIWizardID, 'EMPLOYEE_ID', 'X')
RTFId = EndpointSegment RTFId = EndpointSegment
If Error_Services('NoError') AND RTFId NE '' then If RTFId NE '' then
RTFJson = Return_To_Fab_Services('CreateReturnToFabReportJson', False$) RTFJson = Return_To_Fab_Services('CreateReturnToFabReportJson', False$)
If Error_Services('NoError') then If RTFJson NE '' then
HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
HTTP_Services('SetResponseBody', RTFJson, False$, 'application/hal+json') HTTP_Services('SetResponseBody', RTFJson, False$, 'application/hal+json')
If Assigned(Message) then If Assigned(Message) then
@ -314,11 +302,10 @@ API returntofab.reportallforms.GET
HTTP_Services('SetResponseStatus', 201) HTTP_Services('SetResponseStatus', 201)
end end
end else end else
ErrorMessage = 'Error getting report data.'
end end
end else end else
HTTP_Services('SetResponseStatus', 400, Error_Services('GetMessage')) HTTP_Services('SetResponseStatus', 400, 'Return To Fab ID was null')
end end
end else end else
HTTP_Services('SetResponseStatus', 401, 'Invalid session. Reauthentication required.') HTTP_Services('SetResponseStatus', 401, 'Invalid session. Reauthentication required.')
@ -370,6 +357,37 @@ CreateResultOptionCollection:
return 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.HEAD
API returntofab.getreturntofablabelzpl.GET API returntofab.getreturntofablabelzpl.GET
@ -404,3 +422,26 @@ API returntofab.getreturntofablabelzpl.GET
HTTP_Services('SetResponseStatus', 401, 'Invalid session. Reauthentication required.') HTTP_Services('SetResponseStatus', 401, 'Invalid session. Reauthentication required.')
end end
end api 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) Logging_Services('AppendLog', objLog, LogData, @RM, @FM)
end end
end api end api

View File

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

View File

@ -113,7 +113,7 @@ Service GetTools(ToolClass)
Query = 'SELECT TOOL ' Query = 'SELECT TOOL '
If ToolClass NE '' then If ToolClass NE '' then
Query := 'WITH CLASS EQ ':ToolClass:' ' Query := 'WITH CLASS EQ ': Quote(ToolClass)
end end
Query := 'BY CLASS BY TOOL_ID' Query := 'BY CLASS BY TOOL_ID'
Set_Status(0) Set_Status(0)
@ -238,6 +238,33 @@ Service ChangeToolMode(ToolID, NewMode, NewReason, CurrUser, ForceModeChange)
end service 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 // Internal GoSubs
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -329,3 +356,4 @@ return

View File

@ -307,3 +307,72 @@ API wafercounter.completewafercount.POST
HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage) HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage)
end api 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 WAFER_COUNTER_EQUATES
$Insert TOOL_EQUATES $Insert TOOL_EQUATES
$Insert TOOL_LOG_EQUATES $Insert TOOL_LOG_EQUATES
$Insert LOT_OPERATION_EQUATES
$Insert LOT_EQUATES
Equ Tab$ to \09\ Equ Tab$ to \09\
Equ CRLF$ to \0D0A\ Equ CRLF$ to \0D0A\
@ -528,8 +530,8 @@ Service GetWaferCounterJSONTestData(WaferSize, ToolLocation, CassID)
If SRP_JSON(objJson, 'New', 'Object') then If SRP_JSON(objJson, 'New', 'Object') then
SRP_JSON(objJson, 'SetValue', 'dateTimeFormatted', Datetime(), 'String') SRP_JSON(objJson, 'SetValue', 'dateTimeFormatted', Datetime(), 'String')
SRP_JSON(objJson, 'SetValue', 'equipmentId', 'WC8INCH1', 'String') SRP_JSON(objJson, 'SetValue', 'equipmentId', 'WC8INCH1', 'String')
SRP_JSON(objJson, 'SetValue', 'total', 24, 'Number') SRP_JSON(objJson, 'SetValue', 'total', 25, 'Number')
SRP_JSON(objJson, 'SetValue', 'slotMap', '1111111110111111111111111', 'String') SRP_JSON(objJson, 'SetValue', 'slotMap', '1111111111111111111111111', 'String')
Response = SRP_Json(objJson, 'Stringify', 'Styled') Response = SRP_Json(objJson, 'Stringify', 'Styled')
SRP_JSON(objJSON, 'Release') SRP_JSON(objJSON, 'Release')
end end
@ -553,6 +555,181 @@ Service GetWaferCounterJSONTestData(WaferSize, ToolLocation, CassID)
end service 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 // Internal GoSubs
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -566,3 +743,5 @@ ClearCursors:
return return

View File

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

View File

@ -120,4 +120,3 @@ CreateHalItem:
LogData<5> = ResponseMessage LogData<5> = ResponseMessage
Logging_Services('AppendLog', ObjLog, LogData, @RM, @FM) Logging_Services('AppendLog', ObjLog, LogData, @RM, @FM)
return 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_MET_TEST_ID$ to 14
equ LOT_OPERATION_CLEAN_ID$ to 15 equ LOT_OPERATION_CLEAN_ID$ to 15
equ LOT_OPERATION_PACKAGING_ID$ to 16 equ LOT_OPERATION_PACKAGING_ID$ to 16
equ LOT_OPERATION_WAFER_COUNTER_ID$ to 17 equ LOT_OPERATION_WAFER_COUNTER_ID$ to 18
equ LOT_OPERATION_OPERATION_TYPE$ to 18 equ LOT_OPERATION_OPERATION_TYPE$ to 19
equ LOT_OPERATION_OPERATION_CLASS$ to 19 equ LOT_OPERATION_OPERATION_CLASS$ to 20
equ LOT_OPERATION_MET_TEST_TYPE_REQUIRED$ to 20 equ LOT_OPERATION_MET_TEST_TYPE_REQUIRED$ to 21
equ LOT_OPERATION_MET_TEST_REQUIRED$ to 21 equ LOT_OPERATION_MET_TEST_REQUIRED$ to 22
equ LOT_OPERATION_PACKAGING_REQUIRED$ to 22 equ LOT_OPERATION_PACKAGING_REQUIRED$ to 23
equ LOT_OPERATION_CLEAN_REQUIRED$ to 23 equ LOT_OPERATION_CLEAN_REQUIRED$ to 24
equ LOT_OPERATION_WAFER_COUNTER_REQUIRED$ to 24 equ LOT_OPERATION_WAFER_COUNTER_REQUIRED$ to 25
#endif #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 compile insert MET_TEST_DATA_EQUATES
/*---------------------------------------- /*----------------------------------------
Author : Table Create Insert Routine Author : Table Create Insert Routine
Written : 16/06/2025
Description : Insert for Table MET_TEST_DATA Description : Insert for Table MET_TEST_DATA
----------------------------------------*/ ----------------------------------------*/
#ifndef __MET_TEST_DATA_EQUATES__ #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 equ MET_TEST_DATA.PROPERTY_15_OUT_OF_SPEC$ to 32
#endif #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 compile insert PRODUCT_OPERATION_EQUATES
/*---------------------------------------- /*----------------------------------------
Author : Table Create Insert Routine Author : Table Create Insert Routine
Written : 11/10/2024 Written : 13/05/2025
Description : Insert for Table PRODUCT_OPERATION Description : Insert for Table PRODUCT_OPERATION
----------------------------------------*/ ----------------------------------------*/
#ifndef __PRODUCT_OPERATION_EQUATES__ #ifndef __PRODUCT_OPERATION_EQUATES__