diff --git a/PLC/GVLs/GVL_Product.TcGVL b/PLC/GVLs/GVL_Product.TcGVL
new file mode 100644
index 0000000..77b1579
--- /dev/null
+++ b/PLC/GVLs/GVL_Product.TcGVL
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PLC/PLC.plcproj b/PLC/PLC.plcproj
index f0b56a0..55505d5 100644
--- a/PLC/PLC.plcproj
+++ b/PLC/PLC.plcproj
@@ -18,22 +18,20 @@
{c5c6b994-f2a1-4a71-b657-f282007c0cd2}
+
+ Code
+ true
+
Code
Code
-
+
Code
-
- Code
-
-
- Code
-
-
+
Code
@@ -43,7 +41,7 @@
Code
true
-
+
Code
@@ -54,18 +52,27 @@
Code
+ false
-
+
Code
+ false
Code
+ false
-
+
Code
+ false
-
+
Code
+ false
+
+
+ Code
+ true
Code
@@ -82,16 +89,26 @@
Code
+
+ Code
+
+
+ Code
+
-
+
+ false
+
-
+
+ false
+
@@ -118,8 +135,8 @@
-
-
+
+
"<ProjectRoot>"
{192FAD59-8248-4824-A8DE-9177C94C195A}
@@ -195,14 +212,14 @@
-
-
- System.Boolean
- System.Collections.Hashtable
- {54dd0eac-a6d8-46f2-8c27-2f43c7e49861}
- System.String
-
-
+
+
+ System.Boolean
+ System.Collections.Hashtable
+ {54dd0eac-a6d8-46f2-8c27-2f43c7e49861}
+ System.String
+
+
\ No newline at end of file
diff --git a/PLC/PLC.tmc b/PLC/PLC.tmc
index 1f4d9cb..6960092 100644
--- a/PLC/PLC.tmc
+++ b/PLC/PLC.tmc
@@ -1 +1,14 @@
-ST_LibVersion288iMajorUINT160iMinorUINT1616iBuildUINT1632iRevisionUINT1648nFlagsDWORD3264sVersionSTRING(23)19296I_Product64PVOID__getP_CurrNodeIDUINT16property__getP_ResultBOOL8property__setP_CurrNodeIDP_CurrNodeIDUINT16property__setP_ResultP_ResultBOOL8propertyTcPlcInterfaceTypeI_Station64PVOID__getP_AvailableBOOL8property__getP_BusyBOOL8property__getP_CapabilitiesDWORD32property__getP_HasErrorBOOL8property__getP_ResultUINT16propertyM_InsertProductBOOL8fbProductI_Product64M_RemoveProductI_Product64TcPlcInterfaceTypeFB_Scheduler768_aiStationsI_Station01064064_uiStationCountUINT167040M_RegisterfbStationI_Station64M_ClearStationsPouTypeFunctionBlockFB_StationBase320I_Station_xAvailableBOOL8128_xBusyBOOL8136_xDoneBOOL8144_xErrorBOOL8152_dwCapabilitiesDWORD32160_uiResultUINT16192_fbProductI_Product64256__getP_CapabilitiesDWORD32P_CapabilitiesDWORD32property__getP_ResultUINT16P_ResultUINT16property__getP_BusyBOOL8P_BusyBOOL8property__getP_HasErrorBOOL8P_HasErrorBOOL8propertyM_RemoveProductI_Product64M_InsertProductBOOL8fbProductI_Product64__getP_AvailableBOOL8P_AvailableBOOL8propertyPouTypeFunctionBlockFB_Input320FB_StationBasePouTypeFunctionBlockFB_Etcher320FB_StationBasePouTypeFunctionBlockFB_HVTest320FB_StationBasePouTypeFunctionBlockFB_Output320FB_StationBasePouTypeFunctionBlockE_TransitCond16INTALWAYS0RESULT_OK1RESULT_NIO2qualified_onlystrictto_stringgenerate_implicit_init_functionST_Transition32eConditionE_TransitCond160uiNextNodeIDUINT1616ST_RecipeNode416uiNodeIDUINT160dwReqCapDWORD3232uiTransCntUINT1664astTransitionsST_Transition01032080ST_Recipe4224uiRecipeIDUINT160uiStartNodeUINT16160uiNodeCntUINT16320astNodesST_RecipeNode010416064EPlcPersistentStatus8USINT012PlcAppSystemInfo2048ObjIdOTCID320TaskCntUDINT3232OnlineChangeCntUDINT3264FlagsDWORD3296AdsPortUINT16128BootDataLoadedBOOL8144OldBootDataBOOL8152AppTimestampDT32160KeepOutputsOnBPBOOL8192ShutdownInProgressBOOL8200LicensesPendingBOOL8208BSODOccuredBOOL8216LoggedInBOOL8224PersistentStatusEPlcPersistentStatus8232TComSrvPtrITComObjectServer32256TcComInterfaceAppNameSTRING(63)512512ProjectNameSTRING(63)5121024PlcTaskSystemInfo1024ObjIdOTCID320CycleTimeUDINT3232PriorityUINT1664AdsPortUINT1680CycleCountUDINT3296DcTaskTimeLINT64128LastExecTimeUDINT32192FirstCycleBOOL8224CycleTimeExceededBOOL8232InCallAfterOutputUpdateBOOL8240RTViolationBOOL8248TaskNameSTRING(63)512512_Implicit_KindOfTask16INT_implicit_cyclic0_implicit_event1_implicit_external2_implicit_freewheeling3signature_flag256hidegenerate_implicit_init_function_Implicit_Jitter_Distribution48wRangeMaxWORD160wCountJitterNegWORD1616wCountJitterPosWORD1632signature_flag256hide_Implicit_Task_Info896dwVersionDWORD320pszNameSTRING(80)6464nPriorityINT16128KindOf_Implicit_KindOfTask16144bWatchdogBOOL8160bProfilingTaskBOOL8168dwEventFunctionPointerBYTE64192pszExternalEventSTRING(80)64256dwTaskEntryFunctionPointerBYTE64320dwWatchdogSensitivityDWORD32384dwIntervalDWORD32416dwWatchdogTimeDWORD32448dwLastCycleTimeDWORD32480dwAverageCycleTimeDWORD32512dwMaxCycleTimeDWORD32544dwMinCycleTimeDWORD32576diJitterDINT32608diJitterMinDINT32640diJitterMaxDINT32672dwCycleCountDWORD32704wTaskStatusWORD16736wNumOfJitterDistributionsWORD16752pJitterDistribution_Implicit_Jitter_Distribution64768bWithinSPSTimeSlicingBOOL8832byDummyBYTE8840bShouldBlockBOOL8848bActiveBOOL8856dwIECCycleCountDWORD32864signature_flag256hideFB_NIO320FB_StationBasePouTypeFunctionBlockMAIN_fbSchedulerFB_Scheduler768_xInitDoneBOOL8_fbInputFB_Input320_fbEtcherFB_Etcher320_fbHVTestFB_HVTest320_fbOutputFB_Output320_stRecipeSimpleST_Recipe4224_fbNIOFB_NIO320A_InitTwinCAT_PreventOnlineChangeGvlWriteLineIDsBOOL8truePlcProfilerActiveBOOL8falsePlcProfilerConfigChecksumSTRING(64)520linkalwaysGVL_SchedulerMAX_RECIPE_TRANSITIONSUINT1610MAX_RECIPE_NODESUINT1610MAX_STATIONSUINT1610qualified_onlyPLC{08500001-0000-0000-F000-000000000064}0PlcTask#x02010030DeviceLog FilterUDINT#x08508045DeviceLog Filter000000003PlcTask Internal010616832Global_Version.stLibVersion_Tc2_Standard288ST_LibVersion.iMajor3.iMinor4.iBuild5.iRevision0.nFlags1.sVersion3.4.5.0const_non_replacedTcVarGlobal3072000Global_Version.stLibVersion_Tc2_System288ST_LibVersion.iMajor3.iMinor10.iBuild1.iRevision0.nFlags1.sVersion3.10.1.0const_non_replacedTcVarGlobal3072288Global_Version.stLibVersion_Tc3_Module288ST_LibVersion.iMajor3.iMinor4.iBuild5.iRevision0.nFlags1.sVersion3.4.5.0const_non_replacedTcVarGlobal3072576MAIN._fbScheduler768FB_Scheduler3101568MAIN._xInitDone8BOOL3102336TwinCAT_PreventOnlineChangeGvl.WriteLineIDs8BOOLtrueTcVarGlobal3102344TwinCAT_PreventOnlineChangeGvl.PlcProfilerActive8BOOLfalseTcVarGlobal3102352GVL_Scheduler.MAX_RECIPE_TRANSITIONS16UINT10TcVarGlobal3102384MAIN._fbInput320FB_Input3102400MAIN._fbEtcher320FB_Etcher3102720MAIN._fbHVTest320FB_HVTest3103040MAIN._fbOutput320FB_Output3103360MAIN._stRecipeSimple4224ST_Recipe3103680TwinCAT_PreventOnlineChangeGvl.PlcProfilerConfigChecksum520STRING(64)TcVarGlobal3108000GVL_Scheduler.MAX_RECIPE_NODES16UINT10TcVarGlobal3108528GVL_Scheduler.MAX_STATIONS16UINT10TcVarGlobal3108544TwinCAT_SystemInfoVarList._AppInfo2048PlcAppSystemInfono_initTcVarGlobal3108864TwinCAT_SystemInfoVarList._TaskInfo1024PlcTaskSystemInfo11no_initTcVarGlobal3110912TwinCAT_SystemInfoVarList._TaskPouOid_PlcTask32OTCIDno_initTcVarGlobal3111936TwinCAT_SystemInfoVarList._TaskOid_PlcTask32OTCIDno_initTcVarGlobal3111968TwinCAT_SystemInfoVarList.__PlcTask896_Implicit_Task_Info.dwVersion2TcContextNamePlcTaskTcVarGlobal3112000MAIN._fbNIO320FB_NIO3152832ApplicationNamePort_851ChangeDate2026-02-16T17:39:15DataID{14db9a6a-0000-0000-0000-000000000000}GeneratedCodeSize61440GlobalDataSize16384UTF8EncodedStringsfalse
\ No newline at end of file
+ST_LibVersion288iMajorUINT160iMinorUINT1616iBuildUINT1632iRevisionUINT1648nFlagsDWORD3264sVersionSTRING(23)19296I_Station64PVOID__getP_AvailableBOOL8property__getP_BusyBOOL8property__getP_CapabilitiesDWORD32property__getP_CurrFlowRecIdxINT16property__getP_HasErrorBOOL8property__getP_ProdAvailBOOL8property__getP_StationIDUINT16property__setP_StationIDP_StationIDUINT16propertyM_HasCapabiltyBOOL8dwReqCapDWORD32M_InsertProductBOOL8iFlowRecIdxINT16M_ReleaseBOOL8uiHandleUINT16M_RemoveProductINT16M_ReserveUINT16TcPlcInterfaceTypeI_Transport64PVOID__getP_AvailableBOOL8property__getP_HasErrorBOOL8propertyTcPlcInterfaceTypeST_FlowRecipeNode160uiPriorityUINT160100dwReqCapDWORD32320uiMaxRetriesUINT16640uiCurrRetriesUINT16800xSuccessBOOL896falseiNextNodeSuccessINT16112-1iNextNodeRetryINT16128-1iNextNodeFailINT16144-1ST_FlowRecipe1664iProdIdxINT160-1iCurrNodeINT16160iNextNodeINT16320uiNodeCntINT16480astNodesST_FlowRecipeNode010160064I_FlowRecHandler64PVOIDM_AddFlowRecINT16stFlowRecipeST_FlowRecipe1664M_GetFlowRecST_FlowRecipe64iIdxINT16M_GetNextProcReqBOOL8iIdxINT16dwProcReqDWORD32ItemTypeOutputM_RemFlowRecBOOL8iIdxINT16M_ReportResultBOOL8iIdxINT16xResultBOOL8TcPlcInterfaceTypeFB_FlowRecHandler168256I_FlowRecHandler_astFlowRecPoolST_FlowRecipe0100166400128_iFlowRecCntINT161665280_stDefaultRecipeST_FlowRecipe1664166560POOL_SIZEINT16168224100M_GetNextProcReqBOOL8iIdxINT16dwProcReqDWORD32ItemTypeOutput_iNextNodeIdxINT16M_AdvJobBOOL8iIdxINT16M_GetNextPrioUINT16iIdxINT16_iNextNodeIdxINT16M_RemFlowRecBOOL8iIdxINT16M_AddFlowRecINT16stFlowRecipeST_FlowRecipe1664iINT16M_CheckPoolBoundsBOOL8iIdxINT16M_CheckNextNodeIdxBOOL8iCurrNodeIdxINT16iNextNodeIdxINT16M_GetFlowRecST_FlowRecipe64iIdxINT16M_ReportResultBOOL8iIdxINT16xResultBOOL8_iCurrNodeIdxINT16_iNextNodeIdxINT16PouTypeFunctionBlockST_TransJob80uiFromStationUINT160uiToStationUINT1616uiFromStationHandleUINT1632uiToStationHandleUINT1648uiPrioUINT1664FB_JobQueue896xEnableAgingBOOL864falseItemTypeInput_astJobQueueST_TransJob01080080_uiJobCountUINT168800M_AddJobBOOL8stJobST_TransJob80M_GetHighestBOOL8stJobST_TransJob80ItemTypeOutput_uiIndexUINT16_rDynPrioREAL32_uiCntUINT16M_CalcAgingPrioiUINT16PouTypeFunctionBlockFB_Scheduler1152fbFlowRecHandlerFB_FlowRecHandler6464ItemTypeInOutfbJobQueueFB_JobQueue64128ItemTypeInOut_aiStationsI_Station110640192_uiStationCountUINT168320_fbTransportI_Transport64896_uiCntUINT16960_uiNextAvailStationUINT16976_iFlowRecIdxINT16992_dwNextProcReqDWORD321024_stTmpJobST_TransJob801056M_RegisterfbStationI_Station64M_FindNextAvailStationUINT16dwProcReqDWORD32_uiCntUINT16M_GetStationI_Station64iStationIdxINT16M_RegisterTransportfbTransportI_Transport64M_ClearStationsPouTypeFunctionBlockFB_BaseStation384I_StationfbFlowRecHandlerFB_FlowRecHandler64128ItemTypeInOut_iFlowRecIdxINT16192-1_xProdAvailBOOL8208_xEmptyBOOL8216_xBusyBOOL8224_xDoneBOOL8232_xErrorBOOL8240_uiStationIDUINT162560_dwCapabilitiesDWORD32288_xReservedBOOL8320_uiCurrHandleUINT16336_uiHandleCounterUINT163521M_RemoveProductINT16__getP_CapabilitiesDWORD32P_CapabilitiesDWORD32propertyM_HasCapabiltyBOOL8dwReqCapDWORD32M_InsertProductBOOL8iFlowRecIdxINT16M_ReleaseBOOL8uiHandleUINT16__getP_BusyBOOL8P_BusyBOOL8property__getP_CurrFlowRecIdxINT16P_CurrFlowRecIdxINT16property__getP_StationIDUINT16P_StationIDUINT16propertyM_ReserveUINT16__getP_HasProductBOOL8P_HasProductBOOL8property__getP_HasErrorBOOL8P_HasErrorBOOL8property__getP_ProdAvailBOOL8P_ProdAvailBOOL8property__getP_AvailableBOOL8P_AvailableBOOL8property__setP_StationIDP_StationIDUINT16propertyPouTypeFunctionBlockTON256INBOOL864ItemTypeInputPTTIME3296ItemTypeInputQBOOL8128ItemTypeOutputETTIME32160ItemTypeOutputMBOOL8192StartTimeTIME32224PouTypeFunctionBlockFB_Input2368FB_BaseStation_tonNewProductReadyTON256384_stFlowRecipeST_FlowRecipe1664640_xRecipeSetBOOL82304_xStartBOOL82312M_SetRecipestRecipeST_FlowRecipe1664PouTypeFunctionBlockFB_Etcher704FB_BaseStation_iStateINT16384_tonProcessDurationTON256448PouTypeFunctionBlockFB_HVTest704FB_BaseStation_iStateINT16384_tonProcessDurationTON256448PouTypeFunctionBlockFB_Output704FB_BaseStation_iStateINT16384_tonAutoRemoveTON256448PouTypeFunctionBlockFB_NIO704FB_BaseStation_iStateINT16384_tonAutoRemoveTON256448PouTypeFunctionBlockFB_BaseTransport320I_TransportfbJobQueueFB_JobQueue64128ItemTypeInOut_stTransJonST_TransJob80192_xAvailableBOOL8272true_xErrorBOOL8280__getP_AvailableBOOL8P_AvailableBOOL8property__getP_HasErrorBOOL8P_HasErrorBOOL8propertyPouTypeFunctionBlockFB_Robot896FB_BaseTransportfbSchedulerFB_Scheduler64320ItemTypeInOut_tonTransportDoneTON256384_timTransportTimeTIME32640T#5S_itfSourceStationI_Station64704_itfTargetStationI_Station64768_iFlowRecIdxINT16832_iStateINT16848PouTypeFunctionBlockEPlcPersistentStatus8USINT012PlcAppSystemInfo2048ObjIdOTCID320TaskCntUDINT3232OnlineChangeCntUDINT3264FlagsDWORD3296AdsPortUINT16128BootDataLoadedBOOL8144OldBootDataBOOL8152AppTimestampDT32160KeepOutputsOnBPBOOL8192ShutdownInProgressBOOL8200LicensesPendingBOOL8208BSODOccuredBOOL8216LoggedInBOOL8224PersistentStatusEPlcPersistentStatus8232TComSrvPtrITComObjectServer32256TcComInterfaceAppNameSTRING(63)512512ProjectNameSTRING(63)5121024PlcTaskSystemInfo1024ObjIdOTCID320CycleTimeUDINT3232PriorityUINT1664AdsPortUINT1680CycleCountUDINT3296DcTaskTimeLINT64128LastExecTimeUDINT32192FirstCycleBOOL8224CycleTimeExceededBOOL8232InCallAfterOutputUpdateBOOL8240RTViolationBOOL8248TaskNameSTRING(63)512512_Implicit_KindOfTask16INT_implicit_cyclic0_implicit_event1_implicit_external2_implicit_freewheeling3signature_flag256hidegenerate_implicit_init_function_Implicit_Jitter_Distribution48wRangeMaxWORD160wCountJitterNegWORD1616wCountJitterPosWORD1632signature_flag256hide_Implicit_Task_Info896dwVersionDWORD320pszNameSTRING(80)6464nPriorityINT16128KindOf_Implicit_KindOfTask16144bWatchdogBOOL8160bProfilingTaskBOOL8168dwEventFunctionPointerBYTE64192pszExternalEventSTRING(80)64256dwTaskEntryFunctionPointerBYTE64320dwWatchdogSensitivityDWORD32384dwIntervalDWORD32416dwWatchdogTimeDWORD32448dwLastCycleTimeDWORD32480dwAverageCycleTimeDWORD32512dwMaxCycleTimeDWORD32544dwMinCycleTimeDWORD32576diJitterDINT32608diJitterMinDINT32640diJitterMaxDINT32672dwCycleCountDWORD32704wTaskStatusWORD16736wNumOfJitterDistributionsWORD16752pJitterDistribution_Implicit_Jitter_Distribution64768bWithinSPSTimeSlicingBOOL8832byDummyBYTE8840bShouldBlockBOOL8848bActiveBOOL8856dwIECCycleCountDWORD32864signature_flag256hideMAIN_fbSchedulerFB_Scheduler1152_xInitDoneBOOL8_xStartBOOL8_fbInputFB_Input2368_fbEtcherFB_Etcher704_fbHVTestFB_HVTest704_fbOutputFB_Output704_fbNIOFB_NIO704_fbRobotFB_Robot896_fbJobQueueFB_JobQueue896_stRecipeSimpleST_FlowRecipe1664_fbFlowRecHandlerFB_FlowRecHandler168256A_InitTwinCAT_PreventOnlineChangeGvlWriteLineIDsBOOL8truePlcProfilerActiveBOOL8falsePlcProfilerConfigChecksumSTRING(64)520linkalwaysGVL_SchedulerMAX_RECIPE_TRANSITIONSUINT1610MAX_RECIPE_NODESUINT1610MAX_STATIONSUINT1610AGING_STEPUINT161MAX_PRIORITYUINT1665535MAX_JOBS_IN_QUEUEUINT1610qualified_onlyGVL_ProductaxProductInStationBOOL0540qualified_onlyPLC{08500001-0000-0000-F000-000000000064}0PlcTask#x02010030DeviceLog FilterUDINT#x08508045DeviceLog Filter000000003PlcTask Internal010616832Global_Version.stLibVersion_Tc2_Standard288ST_LibVersion.iMajor3.iMinor4.iBuild5.iRevision0.nFlags1.sVersion3.4.5.0const_non_replacedTcVarGlobal3072000Global_Version.stLibVersion_Tc2_System288ST_LibVersion.iMajor3.iMinor10.iBuild1.iRevision0.nFlags1.sVersion3.10.1.0const_non_replacedTcVarGlobal3072288Global_Version.stLibVersion_Tc3_Module288ST_LibVersion.iMajor3.iMinor4.iBuild5.iRevision0.nFlags1.sVersion3.4.5.0const_non_replacedTcVarGlobal3072576GVL_Product.axProductInStation40BOOL05TcVarGlobal3098368MAIN._fbScheduler1152FB_Scheduler3107648MAIN._xInitDone8BOOL3108800MAIN._xStart8BOOL3108808TwinCAT_PreventOnlineChangeGvl.WriteLineIDs8BOOLtrueTcVarGlobal3108816TwinCAT_PreventOnlineChangeGvl.PlcProfilerActive8BOOLfalseTcVarGlobal3108824GVL_Scheduler.MAX_RECIPE_TRANSITIONS16UINT10TcVarGlobal3108848MAIN._fbInput2368FB_Input3108864MAIN._fbEtcher704FB_Etcher3111232MAIN._fbHVTest704FB_HVTest3111936MAIN._fbOutput704FB_Output3112640MAIN._fbNIO704FB_NIO3113344MAIN._fbRobot896FB_Robot3114048MAIN._fbJobQueue896FB_JobQueue3114944MAIN._stRecipeSimple1664ST_FlowRecipe3115840MAIN._fbFlowRecHandler168256FB_FlowRecHandler3117504TwinCAT_PreventOnlineChangeGvl.PlcProfilerConfigChecksum520STRING(64)TcVarGlobal3285760GVL_Scheduler.MAX_RECIPE_NODES16UINT10TcVarGlobal3286288GVL_Scheduler.MAX_STATIONS16UINT10TcVarGlobal3286304GVL_Scheduler.AGING_STEP16UINT1TcVarGlobal3286320GVL_Scheduler.MAX_PRIORITY16UINT65535TcVarGlobal3286336GVL_Scheduler.MAX_JOBS_IN_QUEUE16UINT10TcVarGlobal3286352TwinCAT_SystemInfoVarList._TaskPouOid_PlcTask32OTCIDno_initTcVarGlobal3286688TwinCAT_SystemInfoVarList._AppInfo2048PlcAppSystemInfono_initTcVarGlobal3286720TwinCAT_SystemInfoVarList._TaskInfo1024PlcTaskSystemInfo11no_initTcVarGlobal3288768TwinCAT_SystemInfoVarList._TaskOid_PlcTask32OTCIDno_initTcVarGlobal3289792TwinCAT_SystemInfoVarList.__PlcTask896_Implicit_Task_Info.dwVersion2TcContextNamePlcTaskTcVarGlobal3289856ApplicationNamePort_851ChangeDate2026-02-19T15:37:52DataID{bc6b67c6-0000-0000-0000-000000000000}GeneratedCodeSize61440GlobalDataSize40960UTF8EncodedStringsfalse
\ No newline at end of file
diff --git a/PLC/POUs/MAIN.TcPOU b/PLC/POUs/MAIN.TcPOU
index 1089768..a056b1f 100644
--- a/PLC/POUs/MAIN.TcPOU
+++ b/PLC/POUs/MAIN.TcPOU
@@ -14,8 +14,18 @@ VAR
_fbOutput : FB_Output;
_fbNIO : FB_NIO;
+ // Transport
+ _fbRobot : FB_Robot;
+
+ // Job queue
+ _fbJobQueue : FB_JobQueue;
+
// Example recipe
- _stRecipeSimple : ST_Recipe;
+ _stRecipeSimple : ST_FlowRecipe;
+
+ _fbFlowRecHandler : FB_FlowRecHandler;
+
+ _xStart : BOOL;
END_VAR
]]>
@@ -25,18 +35,31 @@ END_VAR
END_IF
// Call all stations
-_fbInput();
-_fbEtcher();
-_fbHVTest();
-_fbOutput();
-_fbNIO();
+_fbInput(fbFlowRecHandler := _fbFlowRecHandler);
+GVL_Product.axProductInStation[0] := _fbInput.P_HasProduct;
+
+_fbEtcher(fbFlowRecHandler := _fbFlowRecHandler);
+GVL_Product.axProductInStation[1] := _fbEtcher.P_HasProduct;
+
+_fbHVTest(fbFlowRecHandler := _fbFlowRecHandler);
+GVL_Product.axProductInStation[2] := _fbHVTest.P_HasProduct;
+
+_fbOutput(fbFlowRecHandler := _fbFlowRecHandler);
+GVL_Product.axProductInStation[3] := _fbOutput.P_HasProduct;
+
+_fbNIO(fbFlowRecHandler := _fbFlowRecHandler);
+GVL_Product.axProductInStation[4] := _fbNIO.P_HasProduct;
+
// Call scheduler
-_fbScheduler();]]>
+_fbScheduler(fbFlowRecHandler := _fbFlowRecHandler, fbJobQueue := _fbJobQueue);
+
+// Call robot transport
+_fbRobot(fbJobQueue := _fbJobQueue, fbScheduler := _fbScheduler);]]>
-
+// Etching
+_stRecipeSimple.astNodes[0].dwReqCap := 16#0001;
+_stRecipeSimple.astNodes[0].iNextNodeSuccess := 1;
+_stRecipeSimple.astNodes[0].iNextNodeFail := 3;
+
+// HV Testing
+_stRecipeSimple.astNodes[1].dwReqCap := 16#0002;
+_stRecipeSimple.astNodes[1].iNextNodeSuccess := 2;
+_stRecipeSimple.astNodes[1].uiMaxRetries := 1;
+_stRecipeSimple.astNodes[1].iNextNodeRetry := 0;
+_stRecipeSimple.astNodes[1].iNextNodeFail := 3;
+
+// Output
+_stRecipeSimple.astNodes[2].dwReqCap := 16#0004;
+
+// NIO
+_stRecipeSimple.astNodes[3].dwReqCap := 16#0008;
+
+// Set flow recipe in input station
+_fbInput.M_SetRecipe(_stRecipeSimple);]]>
diff --git a/PLC/POUs/ST_RobotMoveData.TcDUT b/PLC/POUs/ST_RobotMoveData.TcDUT
new file mode 100644
index 0000000..28dda0b
--- /dev/null
+++ b/PLC/POUs/ST_RobotMoveData.TcDUT
@@ -0,0 +1,15 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PLC/POUs/Scheduler/DUTs/E_TransitCond.TcDUT b/PLC/POUs/Scheduler/DUTs/E_TransitCond.TcDUT
deleted file mode 100644
index 2decbda..0000000
--- a/PLC/POUs/Scheduler/DUTs/E_TransitCond.TcDUT
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/PLC/POUs/Scheduler/DUTs/ST_FlowRecipe.TcDUT b/PLC/POUs/Scheduler/DUTs/ST_FlowRecipe.TcDUT
new file mode 100644
index 0000000..7bd6660
--- /dev/null
+++ b/PLC/POUs/Scheduler/DUTs/ST_FlowRecipe.TcDUT
@@ -0,0 +1,31 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PLC/POUs/Scheduler/DUTs/ST_FlowRecipeNode.TcDUT b/PLC/POUs/Scheduler/DUTs/ST_FlowRecipeNode.TcDUT
new file mode 100644
index 0000000..fce120a
--- /dev/null
+++ b/PLC/POUs/Scheduler/DUTs/ST_FlowRecipeNode.TcDUT
@@ -0,0 +1,34 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PLC/POUs/Scheduler/DUTs/ST_Recipe.TcDUT b/PLC/POUs/Scheduler/DUTs/ST_Recipe.TcDUT
deleted file mode 100644
index 9a34c6e..0000000
--- a/PLC/POUs/Scheduler/DUTs/ST_Recipe.TcDUT
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/PLC/POUs/Scheduler/DUTs/ST_RecipeNode.TcDUT b/PLC/POUs/Scheduler/DUTs/ST_RecipeNode.TcDUT
deleted file mode 100644
index 44b241f..0000000
--- a/PLC/POUs/Scheduler/DUTs/ST_RecipeNode.TcDUT
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/PLC/POUs/Scheduler/DUTs/ST_TransJob.TcDUT b/PLC/POUs/Scheduler/DUTs/ST_TransJob.TcDUT
index 7db2753..12b111d 100644
--- a/PLC/POUs/Scheduler/DUTs/ST_TransJob.TcDUT
+++ b/PLC/POUs/Scheduler/DUTs/ST_TransJob.TcDUT
@@ -4,21 +4,19 @@
diff --git a/PLC/POUs/Scheduler/DUTs/ST_Transition.TcDUT b/PLC/POUs/Scheduler/DUTs/ST_Transition.TcDUT
deleted file mode 100644
index 4df5db4..0000000
--- a/PLC/POUs/Scheduler/DUTs/ST_Transition.TcDUT
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/PLC/POUs/Scheduler/GVLs/GVL_Scheduler.TcGVL b/PLC/POUs/Scheduler/GVLs/GVL_Scheduler.TcGVL
index 5db23dd..024aca0 100644
--- a/PLC/POUs/Scheduler/GVLs/GVL_Scheduler.TcGVL
+++ b/PLC/POUs/Scheduler/GVLs/GVL_Scheduler.TcGVL
@@ -10,8 +10,10 @@ VAR_GLOBAL CONSTANT
// Scheduler constants
MAX_STATIONS : UINT := 10;
- // Factor to calc dynmaic priority from age of job in prio/s
- AGE_FACTOR : REAL := 1.0;
+ // Factor to calc dynamic priority from age of job in prio/s
+ AGING_STEP : UINT := 1;
+
+ MAX_PRIORITY : UINT := 65535;
// Job queue constants
MAX_JOBS_IN_QUEUE : UINT := 10;
diff --git a/PLC/POUs/Scheduler/ITFs/I_FlowRecHandler.TcIO b/PLC/POUs/Scheduler/ITFs/I_FlowRecHandler.TcIO
new file mode 100644
index 0000000..cd81103
--- /dev/null
+++ b/PLC/POUs/Scheduler/ITFs/I_FlowRecHandler.TcIO
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PLC/POUs/Scheduler/ITFs/I_Product.TcIO b/PLC/POUs/Scheduler/ITFs/I_Product.TcIO
deleted file mode 100644
index 277987e..0000000
--- a/PLC/POUs/Scheduler/ITFs/I_Product.TcIO
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/PLC/POUs/Scheduler/ITFs/I_Station.TcIO b/PLC/POUs/Scheduler/ITFs/I_Station.TcIO
index a472466..388c5f5 100644
--- a/PLC/POUs/Scheduler/ITFs/I_Station.TcIO
+++ b/PLC/POUs/Scheduler/ITFs/I_Station.TcIO
@@ -10,26 +10,26 @@ VAR_INPUT
END_VAR
]]>
-
+
-
-
@@ -50,6 +50,12 @@ END_VAR
+
+
+
+
+
+
@@ -62,23 +68,16 @@ END_VAR
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
\ No newline at end of file
diff --git a/PLC/POUs/Scheduler/POUs/FB_StationBase.TcPOU b/PLC/POUs/Scheduler/POUs/FB_BaseStation.TcPOU
similarity index 61%
rename from PLC/POUs/Scheduler/POUs/FB_StationBase.TcPOU
rename to PLC/POUs/Scheduler/POUs/FB_BaseStation.TcPOU
index 0df4cac..f8e4ad0 100644
--- a/PLC/POUs/Scheduler/POUs/FB_StationBase.TcPOU
+++ b/PLC/POUs/Scheduler/POUs/FB_BaseStation.TcPOU
@@ -1,31 +1,45 @@
-
-
+
@@ -38,33 +52,47 @@ VAR_INPUT
END_VAR
]]>
-
+
- 0 AND _fbProduct = 0 THEN
- _fbProduct := fbProduct;
- M_InsertProduct := TRUE;
-ELSE
+ -1) OR (iFlowRecIdx = -1) THEN
M_InsertProduct := FALSE;
-END_IF]]>
+END_IF
+
+// Save product index
+_iFlowRecIdx := iFlowRecIdx;
+
+// Advance one step in the node control flow
+fbFlowRecHandler.M_AdvJob(iIdx := iFlowRecIdx);
+
+
+// Report success
+M_InsertProduct := TRUE;]]>
-
-
-
+
-
-
@@ -112,7 +147,10 @@ END_IF]]>
END_VAR
]]>
-
+
@@ -140,6 +178,18 @@ END_VAR
+
+
+
+
+
+
+
+
+
@@ -152,6 +202,17 @@ END_VAR
+
+
+
+
+
+ -1);]]>
+
+
+
@@ -164,30 +225,6 @@ END_VAR
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -199,6 +236,14 @@ END_VAR
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PLC/POUs/Scheduler/POUs/FB_TransportBase.TcPOU b/PLC/POUs/Scheduler/POUs/FB_BaseTransport.TcPOU
similarity index 82%
rename from PLC/POUs/Scheduler/POUs/FB_TransportBase.TcPOU
rename to PLC/POUs/Scheduler/POUs/FB_BaseTransport.TcPOU
index c95ec50..2563555 100644
--- a/PLC/POUs/Scheduler/POUs/FB_TransportBase.TcPOU
+++ b/PLC/POUs/Scheduler/POUs/FB_BaseTransport.TcPOU
@@ -1,13 +1,18 @@
-
-
+
diff --git a/PLC/POUs/Scheduler/POUs/FB_FlowRecHandler.TcPOU b/PLC/POUs/Scheduler/POUs/FB_FlowRecHandler.TcPOU
new file mode 100644
index 0000000..f869957
--- /dev/null
+++ b/PLC/POUs/Scheduler/POUs/FB_FlowRecHandler.TcPOU
@@ -0,0 +1,263 @@
+
+
+
+
+
+
+
+
+
+
+ = POOL_SIZE THEN
+ M_AddFlowRec := -1;
+ RETURN;
+END_IF
+
+// Find a free slot in the pool
+FOR i := 0 TO (POOL_SIZE - 1) DO
+ // If slot is free, set the flow recipe data
+ IF (_astFlowRecPool[i].iProdIdx = -1) THEN
+ _astFlowRecPool[i] := stFlowRecipe;
+ _astFlowRecPool[i].iProdIdx := i;
+ // Increment number of recipes in the pool
+ _iFlowRecCnt := _iFlowRecCnt + 1;
+ // Return index of the added flow recipe
+ M_AddFlowRec := i;
+ RETURN;
+ END_IF
+END_FOR]]>
+
+
+
+
+
+
+
+
+
+
+
+ (_astFlowRecPool[iCurrNodeIdx].uiNodeCnt - 1)) THEN
+ M_CheckNextNodeIdx := FALSE;
+ELSE
+ M_CheckNextNodeIdx := TRUE;
+END_IF]]>
+
+
+
+
+
+ (POOL_SIZE - 1)) THEN
+ M_CheckPoolBounds := FALSE;
+ELSE
+ M_CheckPoolBounds := TRUE;
+END_IF]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (_astFlowRecPool[iIdx].uiNodeCnt - 1)) THEN
+ // If there is no next node set to -1
+ // to indicate, that this was the last node in the
+ // flow recipe
+ _astFlowRecPool[iIdx].iNextNode := -1;
+ELSE
+ _astFlowRecPool[iIdx].iNextNode := _iNextNodeIdx;
+END_IF
+
+// Return success
+M_ReportResult := TRUE;]]>
+
+
+
+
\ No newline at end of file
diff --git a/PLC/POUs/Scheduler/POUs/FB_JobQueue.TcPOU b/PLC/POUs/Scheduler/POUs/FB_JobQueue.TcPOU
index 0f1c725..879dceb 100644
--- a/PLC/POUs/Scheduler/POUs/FB_JobQueue.TcPOU
+++ b/PLC/POUs/Scheduler/POUs/FB_JobQueue.TcPOU
@@ -3,6 +3,7 @@
-
+
-
@@ -50,22 +50,36 @@ IF _uiJobCount >= GVL_Scheduler.MAX_JOBS_IN_QUEUE THEN
RETURN;
END_IF
-_uiJobCount := _uiJobCount + 1;
_astJobQueue[_uiJobCount] := stJob;
-_astJobQueue[_uiJobCount].xValid := TRUE;
-_astJobQueue[_uiJobCount].uliTimeCreated := F_GetSystemTime();
+_uiJobCount := _uiJobCount + 1;
M_AddJob := TRUE;]]>
+
+
+
+ (GVL_Scheduler.MAX_PRIORITY - GVL_Scheduler.AGING_STEP) THEN
+ _astJobQueue[i].uiPrio := GVL_Scheduler.MAX_PRIORITY;
+ ELSE
+ _astJobQueue[i].uiPrio := _astJobQueue[i].uiPrio + GVL_Scheduler.AGING_STEP;
+ END_IF
+ END_IF
+END_FOR]]>
+
+
32767.0 THEN
- _rDynPrio := 32767.0;
- END_IF
- _astJobQueue[_uiCnt].iDynPrio := REAL_TO_INT(_rDynPrio);
-
+FOR _uiCnt := 0 TO (_uiJobCount-1) DO
// Check for highest priority
- IF (_astJobQueue[_uiCnt].iStatPrio + _astJobQueue[_uiCnt].iDynPrio) > _iMaxPrio THEN
- _iMaxPrio :=
+ IF _astJobQueue[_uiCnt].uiPrio > _astJobQueue[_uiIndex].uiPrio THEN
+ _uiIndex := _uiCnt;
END_IF
- END_IF
-
-END_FOR]]>
+END_FOR
+
+// Output job
+stJob := _astJobQueue[_uiIndex];
+
+// Close gap with last element
+_astJobQueue[_uiIndex] := _astJobQueue[_uiJobCount - 1];
+
+// Adjust job number in queue
+_uiJobCount := _uiJobCount - 1;
+
+// Repost success
+M_GetHighest := TRUE;]]>
diff --git a/PLC/POUs/Scheduler/POUs/FB_Product.TcPOU b/PLC/POUs/Scheduler/POUs/FB_Product.TcPOU
deleted file mode 100644
index 8020b4f..0000000
--- a/PLC/POUs/Scheduler/POUs/FB_Product.TcPOU
+++ /dev/null
@@ -1,87 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/PLC/POUs/Scheduler/POUs/FB_Scheduler.TcPOU b/PLC/POUs/Scheduler/POUs/FB_Scheduler.TcPOU
index a6a3ce9..a23a77d 100644
--- a/PLC/POUs/Scheduler/POUs/FB_Scheduler.TcPOU
+++ b/PLC/POUs/Scheduler/POUs/FB_Scheduler.TcPOU
@@ -6,35 +6,77 @@ VAR_INPUT
END_VAR
VAR_OUTPUT
END_VAR
+VAR_IN_OUT
+ fbFlowRecHandler : FB_FlowRecHandler;
+ fbJobQueue : FB_JobQueue;
+END_VAR
VAR
+ // Array needs to start at 1 so that 0 can be an invalid station
+ // Maybe later change this to int ant -1
_aiStations : ARRAY[1..(GVL_Scheduler.MAX_STATIONS)] OF I_Station;
_uiStationCount : UINT := 0;
- _fbTransport : I_Station;
- _uiTransportCnt : UINT := 0;
+ _fbTransport : I_Transport;
_uiCnt : UINT;
_uiNextAvailStation : UINT;
- _fbProduct : I_Product;
+ _iFlowRecIdx : INT;
+ _dwNextProcReq : DWORD;
+
+ _stTmpJob : ST_TransJob;
END_VAR]]>
- _dwNextProcReq)) THEN
+ CONTINUE;
+ END_IF
+
// Find next available station according to recipe and available station
- _uiNextAvailStation := M_FindNextAvailStation(_aiStations[_uiCnt].P_Product);
+ _uiNextAvailStation := M_FindNextAvailStation(_dwNextProcReq);
// Check if there is a station available
IF _uiNextAvailStation <> 0 THEN
- // Skip reservation for now
- // _aiStations[_uiNextAvailStation].M_Reserve();
- // Create transport job
+ // Reserve source station
+ _stTmpJob.uiFromStationHandle := _aiStations[_uiCnt].M_Reserve();
+
+ // Reserve target station
+ _stTmpJob.uiToStationHandle := _aiStations[_uiNextAvailStation].M_Reserve();
+
+ // Check if we could reserve the stations
+ IF (_stTmpJob.uiToStationHandle <> 0) AND (_stTmpJob.uiFromStationHandle <> 0) THEN
+ // Create transport job
+ _stTmpJob.uiFromStation := _uiCnt;
+ _stTmpJob.uiToStation := _uiNextAvailStation;
+ _stTmpJob.uiPrio := fbFlowRecHandler.M_GetNextPrio(iIdx := _iFlowRecIdx);
+
+ // Add job to job queue
+ fbJobQueue.M_AddJob(stJob := _stTmpJob);
+ ELSE
+ // Remove registrations from stations
+ _aiStations[_uiCnt].M_Release(_stTmpJob.uiFromStationHandle);
+ _aiStations[_uiNextAvailStation].M_Release(_stTmpJob.uiToStationHandle);
+ END_IF
END_IF
END_IF
END_FOR]]>
@@ -55,22 +97,37 @@ _uiStationCount := 0;]]>
+
+
+
+ (GVL_Scheduler.MAX_STATIONS - 1) THEN
+ M_GetStation := 0;
+ RETURN;
+END_IF
+
+M_GetStation := _aiStations[iStationIdx];]]>
+
+
@@ -102,11 +160,10 @@ IF fbTransport = 0 THEN
RETURN;
END_IF
-// Check if we have free slots
-IF _uiTransportCnt < GVL_Scheduler.MAX_STATIONS THEN
- _aiStations[_uiTransportCnt] := fbTransport;
- _uiTransportCnt := _uiTransportCnt + 1;
-END_IF]]>
+// Set transport interface
+_fbTransport := fbTransport;
+
+]]>
diff --git a/PLC/POUs/Scheduler/POUs/GVL_Test.TcGVL b/PLC/POUs/Scheduler/POUs/GVL_Test.TcGVL
new file mode 100644
index 0000000..f86d05a
--- /dev/null
+++ b/PLC/POUs/Scheduler/POUs/GVL_Test.TcGVL
@@ -0,0 +1,8 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PLC/POUs/Stations/FB_Etcher.TcPOU b/PLC/POUs/Stations/FB_Etcher.TcPOU
index d2a6512..1daef66 100644
--- a/PLC/POUs/Stations/FB_Etcher.TcPOU
+++ b/PLC/POUs/Stations/FB_Etcher.TcPOU
@@ -1,16 +1,61 @@
-
-
+ -1 THEN
+ _xDone := FALSE;
+ _xBusy := TRUE;
+ _iState := 10;
+ END_IF
+
+ // Simulate process
+ 10:
+ _tonProcessDuration(IN := TRUE, PT := T#10S);
+ IF _tonProcessDuration.Q THEN
+ _tonProcessDuration(IN := FALSE);
+ fbFlowRecHandler.M_ReportResult(iIdx := _iFlowRecIdx, xResult := TRUE);
+ _xProdAvail := TRUE;
+ _xBusy := FALSE;
+ _xDone := TRUE;
+ _iState := 20;
+ END_IF
+
+ // Wait for station to be empty again
+ 20:
+ IF _iFlowRecIdx = -1 THEN
+ _iState := 0;
+ END_IF
+END_CASE]]>
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PLC/POUs/Stations/FB_HVTest.TcPOU b/PLC/POUs/Stations/FB_HVTest.TcPOU
index ccbeb06..c4e780c 100644
--- a/PLC/POUs/Stations/FB_HVTest.TcPOU
+++ b/PLC/POUs/Stations/FB_HVTest.TcPOU
@@ -1,16 +1,60 @@
-
-
+ -1 THEN
+ _xDone := FALSE;
+ _xBusy := TRUE;
+ _iState := 10;
+ END_IF
+
+ // Simulate process
+ 10:
+ _tonProcessDuration(IN := TRUE, PT := T#10S);
+ IF _tonProcessDuration.Q THEN
+ _tonProcessDuration(IN := FALSE);
+ fbFlowRecHandler.M_ReportResult(iIdx := _iFlowRecIdx, xResult := TRUE);
+ _xProdAvail := TRUE;
+ _xBusy := FALSE;
+ _xDone := TRUE;
+ _iState := 20;
+ END_IF
+
+ // Wait for station to be empty again
+ 20:
+ IF _iFlowRecIdx = -1 THEN
+ _iState := 0;
+ END_IF
+END_CASE]]>
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PLC/POUs/Stations/FB_Input.TcPOU b/PLC/POUs/Stations/FB_Input.TcPOU
index d6026ce..136c196 100644
--- a/PLC/POUs/Stations/FB_Input.TcPOU
+++ b/PLC/POUs/Stations/FB_Input.TcPOU
@@ -1,16 +1,40 @@
-
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PLC/POUs/Stations/FB_NIO.TcPOU b/PLC/POUs/Stations/FB_NIO.TcPOU
index e98e907..16e4560 100644
--- a/PLC/POUs/Stations/FB_NIO.TcPOU
+++ b/PLC/POUs/Stations/FB_NIO.TcPOU
@@ -1,16 +1,51 @@
-
-
+ -1 THEN
+ _iState := 10;
+ END_IF
+
+ // Remove product from line
+ 10:
+ _tonAutoRemove(IN := TRUE, PT := T#5S);
+ IF _tonAutoRemove.Q THEN
+ _tonAutoRemove(IN := FALSE);
+
+ fbFlowRecHandler.M_RemFlowRec(iIdx := _iFlowRecIdx);
+ _iFlowRecIdx := -1;
+ _iState := 0;
+ END_IF
+END_CASE]]>
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PLC/POUs/Stations/FB_Output.TcPOU b/PLC/POUs/Stations/FB_Output.TcPOU
index c0231de..764abbb 100644
--- a/PLC/POUs/Stations/FB_Output.TcPOU
+++ b/PLC/POUs/Stations/FB_Output.TcPOU
@@ -1,16 +1,51 @@
-
-
+ -1 THEN
+ _iState := 10;
+ END_IF
+
+ // Remove product from line
+ 10:
+ _tonAutoRemove(IN := TRUE, PT := T#5S);
+ IF _tonAutoRemove.Q THEN
+ _tonAutoRemove(IN := FALSE);
+
+ fbFlowRecHandler.M_RemFlowRec(iIdx := _iFlowRecIdx);
+ _iFlowRecIdx := -1;
+ _iState := 0;
+ END_IF
+END_CASE]]>
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PLC/POUs/Stations/FB_Robot.TcPOU b/PLC/POUs/Stations/FB_Robot.TcPOU
new file mode 100644
index 0000000..87e8dc1
--- /dev/null
+++ b/PLC/POUs/Stations/FB_Robot.TcPOU
@@ -0,0 +1,71 @@
+
+
+
+
+
+ _stTransJon) THEN
+ _xAvailable := FALSE;
+
+ // Get station interfaces
+ _itfSourceStation := fbScheduler.M_GetStation(_stTransJon.uiFromStation);
+ _itfTargetStation := fbScheduler.M_GetStation(_stTransJon.uiToStation);
+
+ _iState := 10;
+ END_IF
+
+ // Move to pickup station
+ 10:
+ _tonTransportDone(IN := TRUE, PT := _timTransportTime);
+ IF _tonTransportDone.Q THEN
+ _tonTransportDone(IN := FALSE);
+
+ // Get product from station
+ _iFlowRecIdx := _itfSourceStation.M_RemoveProduct();
+
+ _iState := 20;
+ END_IF
+
+ // Move to drop station
+ 20:
+ _tonTransportDone(IN := TRUE, PT := _timTransportTime);
+ IF _tonTransportDone.Q THEN
+ _tonTransportDone(IN := FALSE);
+
+ // Put product into station
+ _itfTargetStation.M_InsertProduct(_iFlowRecIdx);
+
+ _iState := 30;
+ END_IF
+
+ // Release all station reservations
+ 30:
+ _itfSourceStation.M_Release(uiHandle := _stTransJon.uiFromStationHandle);
+ _itfTargetStation.M_Release(uiHandle := _stTransJon.uiToStationHandle);
+ _xAvailable := TRUE;
+ _iState := 0;
+END_CASE]]>
+
+
+
\ No newline at end of file
diff --git a/PLC/PlcTask.TcTTO b/PLC/PlcTask.TcTTO
index e169d9b..cf45cfc 100644
--- a/PLC/PlcTask.TcTTO
+++ b/PLC/PlcTask.TcTTO
@@ -12,6 +12,5 @@
{baf80adf-b0f3-4c1e-958c-6b1cb1610e8e}
{ff4c396c-9481-47ed-a237-b2f9054f4e68}
{e06145cf-bc12-4403-9e2e-7beeb337c603}
-
\ No newline at end of file
diff --git a/SchedulerTest.tsproj b/SchedulerTest.tsproj
index c5ed8cd..5d39319 100644
--- a/SchedulerTest.tsproj
+++ b/SchedulerTest.tsproj
@@ -1,6 +1,6 @@
-
+
diff --git a/_Config/PLC/PLC Instance.xti b/_Config/PLC/PLC Instance.xti
index 82f9731..09df090 100644
--- a/_Config/PLC/PLC Instance.xti
+++ b/_Config/PLC/PLC Instance.xti
@@ -1,6 +1,6 @@
-
+
__FILENAME__
{08500001-0000-0000-F000-000000000064}