diff --git a/LSL2/STPROC/WAFERCOUNTER_API.txt b/LSL2/STPROC/WAFERCOUNTER_API.txt new file mode 100644 index 0000000..aa05c17 --- /dev/null +++ b/LSL2/STPROC/WAFERCOUNTER_API.txt @@ -0,0 +1,309 @@ +Function Wafercounter_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 : Wafercounter_API + + Description : API logic for the Wafercounter 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 Wafercounter[.ID.[]] + - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. + Examples: + - Wafercounter.POST + - Wafercounter.ID.PUT + - Wafercounter.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/04/25 xxx Original programmer. + +***********************************************************************************************************************/ + +#pragma precomp SRP_PreCompiler + +Declare function OI_Wizard_Services, Wafer_Counter_Services, Database_Services, Datetime, Wo_Mat_Services +Declare function Logging_Services, Environment_Services +Declare subroutine Logging_Services + + +$insert APP_INSERTS +$insert API_SETUP +$insert HTTP_INSERTS +$insert WAFER_COUNTER_EQUATES + +LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\API\WaferCounter'; +LogDate = Oconv(Date(), 'D4/') +LogTime = Oconv(Time(), 'MTS') +LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM + +LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' WaferCounter.csv' +Headers = 'Logging DTM' : @FM : 'User' : @FM : 'OI Wizard ID' : @FM : 'Message' +objLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$) + +GoToAPI else + // The specific resource endpoint doesn't have a API handler yet. + LogData = '' + LogData<1> = LoggingDTM;//Defined at entry of subroutine + LogData<2> = '' + LogData<3> = '' + LogData<4> = 'Web API not found.' + Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) + 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 wafercounter.startnewwafercount.POST + + ErrorMessage = '' + ResponseCode = '' + ResponseMessage = '' + Body = '' + OIWizardID = '' + UserId = '' + CassId = '' + 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> = 'New wafer counter transaction started.' + Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) + + If SRP_JSON(objBody, 'Parse', Body) EQ '' then + CassBarcodeData = SRP_JSON(objBody, 'GetValue', 'CassBarcodeData') + If CassBarcodeData NE '' then + CassData = Wafer_Counter_Services('ProcessCass2DBarcode', CassBarcodeData) + CassId = CassData<1,1> + ExpectedWfrQty = CassData<1,2> + CassType = CassData<1,3> + WoMatKey = '' + Begin Case + Case CassType EQ 'RDS' + WONo = XLATE('RDS', CassId, 'WO', 'X') + CassNo = XLATE('RDS', CassId, 'CASS_NO', 'X') + WoMatKey = WONo : '*' : CassNo + Case CassType EQ 'WM_OUT' OR CassType EQ 'WM_IN' + swap '.' with '*' in CassId + WONo = Field(CassId, '*', 1) + CassNo = Field(CassId, '*', 3) + WoMatKey = WONo : '*' : CassNo + End Case + ExpectedWfrMap = Wo_Mat_Services('GetWaferMap', WoMatKey) + ExpectedCassetteArray = '' + for i = 25 to 1 step -1 + Slot = i + WaferPresent = ExpectedWfrMap<1, i> + ExpectedCassetteArray<-1, 1> = Slot : @VM : WaferPresent + Next i + If Error_Services('NoError') then + SRP_Json(objBody, 'SetValue', 'CassId', CassId, 'String') + SRP_Json(objBody, 'SetValue', 'CassType', CassType, 'String') + SRP_Json(objBody, 'SetValue', 'ExpectedQty', ExpectedWfrQty, 'Number') + SRP_Json(objBody, 'SetValue', 'ScanDtm', OConv(Datetime(), 'DT4/'), 'String') + objExpCassArray = '' + IF SRP_Json(objExpCassArray, 'New', 'Array') then + for each SlotData in ExpectedCassetteArray using @FM setting sPos + Slot = SlotData<1, 1> + WaferPresent = SlotData<1, 2> + objSlot = '' + If SRP_Json(objSlot, 'New', 'Object') then + SRP_Json(objSlot, 'SetValue', 'SlotNo', Slot, 'Number') + SRP_Json(objSlot, 'SetValue', 'WaferPresent', WaferPresent, 'Boolean') + SRP_Json(objExpCassArray, 'Add', objSlot) + SRP_Json(objSlot, 'Release') + end + Next SlotData + SRP_Json(objBody, 'Set', 'ExpectedWaferArray', objExpCassArray) + SRP_Json(objExpCassArray, 'Release') + end + ResponseJson = SRP_Json(objBody, 'Stringify', 'Styled') + HTTP_Services('SetResponseBody', ResponseJson) + ResponseCode = 200 + end else + ErrorMessage = Error_Services('GetMessage') + ResponseCode = 500 + end + end else + ErrorMessage = 'Cassette ID Barcode data not detected.' + ResponseCode = 500 + end + SRP_Json(objBody, 'Release') + end + + If ErrorMessage EQ '' then + //Log Success + LogData = '' + LogData<1> = LoggingDTM + LogData<2> = UserId + LogData<3> = OIWizardId + LogData<4> = 'New wafer counter transaction started successfully. Barcode Data: ' : CassBarcodeData : '. Cass Id: ' : CassId + Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) + end else + //Log Failure + LogData = '' + LogData<1> = LoggingDTM + LogData<2> = UserId + LogData<3> = OIWizardId + LogData<4> = 'New wafer counter transaction finished with errors. Response Code: ' : ResponseCode : '. Error Message: ' : ErrorMessage : '. Barcode Data: ' : CassBarcodeData : '. Cass Id: ' : CassId + Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) + end + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage) + +end api + + +API wafercounter.completewafercount.POST + + ErrorMessage = '' + ResponseCode = '' + ResponseMessage = '' + WaferCounterId = '' + 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> = 'Complete wafer counter transaction started.' + Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) + + If SRP_JSON(objBody, 'Parse', Body) EQ '' then + CassId = SRP_JSON(objBody, 'GetValue', 'CassId') + CassType = SRP_Json(objBody, 'GetValue', 'CassType') + ToolBarcodeData = SRP_JSON(objBody, 'GetValue', 'ToolBarcodeData') + ExpectedQty = SRP_JSON(objBody, 'GetValue', 'ExpectedQty') + If CassId NE '' then + WaferCounterId = Wafer_Counter_Services('ProcessTool2DBarcode', ToolBarcodeData, CassId, CassType, UserId) + If Error_Services('NoError') then + WaferCounterRec = Database_Services('ReadDataRow', 'WAFER_COUNTER', WaferCounterId, True$, 0, False$) + ScanDtm = OConv(WaferCounterRec, 'DT4/') + ToolId = WaferCounterRec + WaferCount = WaferCounterRec + MatchingWfrCount = ExpectedQty EQ WaferCount + WaferCountData = WaferCounterRec + swap 1 with 1:@FM in WaferCountData + swap 0 with 0:@FM in WaferCountData + WaferCountData[-1, -1] = '' + CassetteArray = '' + for i = 25 to 1 step -1 + Slot = i + WaferPresent = WaferCountData + CassetteArray<-1, 1> = Slot : @VM : WaferPresent + Next i + + WaferCountArray = '' + SRP_Json(objBody, 'SetValue', 'WaferCounterId', WaferCounterId, 'String') + SRP_Json(objBody, 'SetValue', 'ScanDtm', ScanDtm, 'String') + SRP_Json(objBody, 'SetValue', 'WaferCount', WaferCount, 'Number') + SRP_Json(objBody, 'SetValue', 'ToolId', ToolId, 'String') + SRP_Json(objBody, 'SetValue', 'MatchingWaferCount', MatchingWfrCount, 'Boolean') + SRP_Json(objBody, 'SetValue', 'WaferCounterId', WaferCounterId, 'String') + objCassArray = '' + IF SRP_Json(objCassArray, 'New', 'Array') then + for each SlotData in CassetteArray using @FM setting sPos + Slot = SlotData<1, 1> + WaferPresent = SlotData<1, 2> + objSlot = '' + If SRP_Json(objSlot, 'New', 'Object') then + SRP_Json(objSlot, 'SetValue', 'SlotNo', Slot, 'Number') + SRP_Json(objSlot, 'SetValue', 'WaferPresent', WaferPresent, 'Boolean') + SRP_Json(objCassArray, 'Add', objSlot) + SRP_Json(objSlot, 'Release') + end + Next SlotData + SRP_Json(objBody, 'Set', 'WaferArray', objCassArray) + SRP_Json(objCassArray, 'Release') + end + ResponseJson = SRP_Json(objBody, 'Stringify', 'Styled') + HTTP_Services('SetResponseBody', ResponseJson) + ResponseCode = 200 + end else + ErrorMessage = Error_Services('GetMessage') + ResponseCode = 500 + end + end else + ErrorMessage = 'Cassette ID Barcode data not detected.' + ResponseCode = 500 + end + SRP_Json(objBody, 'Release') + end + + If ErrorMessage EQ '' then + //Log Success + LogData = '' + LogData<1> = LoggingDTM + LogData<2> = UserId + LogData<3> = OIWizardId + LogData<4> = 'Completed wafer counter transaction finished successfully. Barcode Data: ' : CassBarcodeData : '. WAFER_COUNTER Id: ' : WaferCounterId : '. Cass Id: ' : CassId + Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) + end else + //Log Failure + LogData = '' + LogData<1> = LoggingDTM + LogData<2> = UserId + LogData<3> = OIWizardId + LogData<4> = 'New wafer counter transaction finished with errors. Response Code: ' : ResponseCode : '. Error Message: ' : ErrorMessage : '. Barcode Data: ' : CassBarcodeData : '. Wafer Counter Id: ' : WaferCounterId : '. Cass Id: ' : CassId + Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) + end + + HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) + HTTP_Services('SetResponseStatus', ResponseCode, ErrorMessage) + +end api diff --git a/LSL2/STPROC/WAFER_COUNTER_SERVICES.txt b/LSL2/STPROC/WAFER_COUNTER_SERVICES.txt index 04bf573..35a43a4 100644 --- a/LSL2/STPROC/WAFER_COUNTER_SERVICES.txt +++ b/LSL2/STPROC/WAFER_COUNTER_SERVICES.txt @@ -32,6 +32,8 @@ $Insert WO_LOG_EQUATES $Insert WM_OUT_EQUATES $Insert RLIST_EQUATES $Insert WAFER_COUNTER_EQUATES +$Insert TOOL_EQUATES +$Insert TOOL_LOG_EQUATES Equ Tab$ to \09\ Equ CRLF$ to \0D0A\ @@ -43,8 +45,9 @@ Equ next_cur$ To 1 Equ add_exist$ to 2 Declare subroutine Error_Services, Database_Services, Logging_Services, Httpclient_Services, Reduce, SRP_JSON -Declare function Database_Services, Environment_Services, Logging_Services, Httpclient_Services -Declare function RTI_CreateGuid, SRP_JSON +Declare subroutine Wafer_Counter_Services, Lot_Event_Services +Declare function Database_Services, Environment_Services, Logging_Services, Httpclient_Services, OConv +Declare function RTI_CreateGuid, SRP_JSON, WO_Mat_Services, WM_Out_Services, Wafer_Counter_Services, Datetime LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\WaferCounter' LogDate = Oconv(Date(), 'D4/') @@ -263,6 +266,8 @@ Service AddScan(LotID, ScanQty, ScanDtm, ScanTool, ScanUser, ScanLocation, Wafer Record = WaferMap Database_Services('WriteDataRow', 'WAFER_COUNTER', KeyID, Record) + Response = KeyId + end service @@ -393,6 +398,161 @@ Service GetWaferCounterToolID(WaferSize=WAFER_SIZES, Location=LOCATIONS) end service +//---------------------------------------------------------------------------------------------------------------------- +// ProcessCass2DBarcode +// +// Takes in the raw barcode data for a 2D Cassette label. Returns a single field array with 3 field delimited by @VM +// CassId, Expected Qty, and Cass Type +//---------------------------------------------------------------------------------------------------------------------- +Service ProcessCass2DBarcode(BarcodeText) + + ErrorMessage = '' + ExpectedSlotWaferMap = '' + ExpectedQty = '' + CassId = '' + CassType = '' + If BarcodeText NE '' then + DelimCnt = DCount(BarcodeText, '|') + If DelimCnt EQ 8 then + CassId = Field(BarcodeText, '|', 3) + If CassId NE '' then + If CassId[1, 2] EQ '1T' then + CassId[1, 2] = '' + Begin Case + Case CassId[1, 1] EQ 'O' + CassId[1, 1] = '' + CassType = 'WM_OUT' + Case (CassId[1, 1] EQ 'I') + CassId[1, 1] = '' + CassType = 'WM_IN' + Case Otherwise$ + CassType = 'RDS' + End Case + Convert '.' to '*' in CassId + Begin Case + Case RowExists('RDS', CassId) + ExpectedQty = Xlate('RDS', CassId, 'WFRS_OUT', 'X') + Case RowExists('WM_OUT', CassId) + ExpectedQty = Xlate('WM_OUT', CassId, 'WAFER_CNT', 'X') + End Case + end + + end else + ErrorMessage = 'Invalid Lot Label Scan. Unable to determine Cass Id' + end + end else + ErrorMessage = 'Invalid Lot Label Scan.' + end + end else + ErrorMessage = 'Scan data was null.' + end + + If ErrorMessage EQ '' then + Response = CassId : @VM: ExpectedQty : @VM : CassType + end else + Error_Services('Add', ErrorMessage) + end + +end service + +//---------------------------------------------------------------------------------------------------------------------- +// ProcessTool2DBarcode +// +// Takes in the raw barcode data for a wafer counter label, Cassette Id, Cassette Type, and UserId(Optional) +// Returns a key ID for a completed WAFER_COUNTER record. +//---------------------------------------------------------------------------------------------------------------------- +Service ProcessTool2DBarcode(BarcodeText, CassId, CassType, UserId) + + ErrorMessage = '' + + If BarcodeText NE '' then + DelimCnt = DCount(BarcodeText, '|') + If DelimCnt EQ 2 then + WaferSize = Field(BarcodeText, '|', 1) + Area = Field(BarcodeText, '|', 2) + If Environment_Services('IsProd') then + WcJson = Wafer_Counter_Services('GetWaferCounterJSON', WaferSize, Area, CassID) + end else + WcJson = Wafer_Counter_Services('GetWaferCounterJSONTestData', WaferSize, Area, CassID) + end + + If Error_Services('NoError') then + objJSON = '' + If SRP_JSON(objJSON, 'Parse', WcJson) EQ '' then + ScanDtm = SRP_JSON(objJSON, 'GetValue', 'dateTimeFormatted') + ToolID = SRP_JSON(objJSON, 'GetValue', 'equipmentId') + WaferCount = SRP_JSON(objJSON, 'GetValue', 'total') + SlotMap = SRP_JSON(objJSON, 'GetValue', 'slotMap') + SRP_JSON(objJSON, 'Release') + ToolCurrModeKey = Database_Services('ReadDataColumn', 'TOOL', ToolId, TOOL_CURR_MODE_KEY$, True$, 0, False$) + ToolCurrMode = Database_Services('ReadDataColumn', 'TOOL_LOG', ToolCurrModeKey, TOOL_LOG_TOOL_MODE$, True$, 0, False$) + If ToolCurrMode EQ 'PROD' OR ToolCurrMode EQ 'LIM' then + WaferCounterId = Wafer_Counter_Services('AddScan', CassID, WaferCount, ScanDtm, ToolID, UserId, Area, SlotMap) + If Error_Services('NoError') then + Lot_Event_Services('CreateLotEvent', CassId, ScanDtm, 'WAFER_COUNTER', 'Wafer counter data received for lot. ' : WaferCount : ' wafers found.', ToolId, UserId, True$, CassType) + end + end else + ErrorMessage = 'Wafer counter is currently down and cannot be used to log wafer counts.' + end + end else + ErrorMessage = 'Error parsing response from wafer counter.' + end + end else + ErrorMessage = Error_Services('GetMessage') + end + end else + ErrorMessage = 'Invalid tool scan.' + end + end else + ErrorMessage = 'Scan data was null.' + end + + If ErrorMessage EQ '' then + Response = WaferCounterId + end else + Error_Services('Add', ErrorMessage) + end + +end service + +//---------------------------------------------------------------------------------------------------------------------- +// GetWaferCounterJSONTestData +// +// Emulates GetWaferCounterJson service. +//---------------------------------------------------------------------------------------------------------------------- +Service GetWaferCounterJSONTestData(WaferSize, ToolLocation, CassID) + + If ( (WaferSize NE '') and (ToolLocation NE '') and (CassID NE '') ) then + Response = '' + objJson = '' + If SRP_JSON(objJson, 'New', 'Object') then + SRP_JSON(objJson, 'SetValue', 'dateTimeFormatted', Datetime(), 'String') + SRP_JSON(objJson, 'SetValue', 'equipmentId', 'WC8INCH1', 'String') + SRP_JSON(objJson, 'SetValue', 'total', 24, 'Number') + SRP_JSON(objJson, 'SetValue', 'slotMap', '1111111110111111111111111', 'String') + Response = SRP_Json(objJson, 'Stringify', 'Styled') + SRP_JSON(objJSON, 'Release') + end + + If Error_Services('NoError') then + StatusCode = 200 + If StatusCode NE 200 then + Begin Case + Case Response EQ '' + ErrorMsg = 'Unexpected server error.' + Case Response EQ 'No files!' + ErrorMsg = 'No data. Please re-seat cassette and try again.' + Case Otherwise$ + // Use message in response body to populate error services + ErrorMsg = Response + End Case + Error_Services('Add', ErrorMsg) + end + end + end + +end service + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Internal GoSubs //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -405,3 +565,4 @@ ClearCursors: return +