Added JobScheduler and recipe data for stations

This commit is contained in:
2026-02-24 18:28:00 +01:00
parent c4044be7bd
commit 46e294d991
33 changed files with 1454 additions and 2837 deletions

View File

@@ -0,0 +1,116 @@
<?xml version="1.0" encoding="utf-8"?>
<TcPlcObject Version="1.1.0.1">
<POU Name="FB_JobQueue" Id="{b05c10aa-a132-426c-9adb-9c3d92e348cd}" SpecialFunc="None">
<Declaration><![CDATA[FUNCTION_BLOCK FB_JobQueue
VAR_INPUT
xEnableAging : BOOL := FALSE;
END_VAR
VAR_OUTPUT
END_VAR
VAR
_astJobQueue : ARRAY[0..(GVL_Scheduler.MAX_JOBS_IN_QUEUE - 1)] OF ST_TransJob;
_uiJobCount : UINT := 0;
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[// If aging is enable recalculate priorities
IF xEnableAging THEN
M_CalcAgingPrio();
END_IF
]]></ST>
</Implementation>
<Method Name="FB_Init" Id="{59b2fc0f-4c7e-4fd5-97a2-d54f83d37be4}">
<Declaration><![CDATA[//FB_Init is always available implicitly and it is used primarily for initialization.
//The return value is not evaluated. For a specific influence, you can also declare the
//methods explicitly and provide additional code there with the standard initialization
//code. You can evaluate the return value.
METHOD FB_Init: BOOL
VAR_INPUT
bInitRetains: BOOL; // TRUE: the retain variables are initialized (reset warm / reset cold)
bInCopyCode: BOOL; // TRUE: the instance will be copied to the copy code afterward (online change)
END_VAR
VAR
_uiCnt : UINT;
END_VAR]]></Declaration>
<Implementation>
<ST><![CDATA[// No jobs in queue
_uiJobCount := 0;]]></ST>
</Implementation>
</Method>
<Method Name="M_AddJob" Id="{c7959fb9-7c57-4429-b989-c0befdd4ac38}">
<Declaration><![CDATA[METHOD M_AddJob : BOOL
VAR_INPUT
stJob : ST_TransJob;
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[// Check if queue is full
IF _uiJobCount >= GVL_Scheduler.MAX_JOBS_IN_QUEUE THEN
M_AddJob := FALSE;
RETURN;
END_IF
_astJobQueue[_uiJobCount] := stJob;
_uiJobCount := _uiJobCount + 1;
M_AddJob := TRUE;]]></ST>
</Implementation>
</Method>
<Method Name="M_CalcAgingPrio" Id="{7ee1cc23-b7ac-4255-862a-74b0b696f2cb}">
<Declaration><![CDATA[METHOD PRIVATE M_CalcAgingPrio
VAR
i : UINT;
END_VAR]]></Declaration>
<Implementation>
<ST><![CDATA[// Calculate ageing priority with overflow check
FOR i := 0 TO _uiJobCount DO
IF _astJobQueue[i].uiPrio < GVL_Scheduler.MAX_PRIORITY THEN
IF _astJobQueue[i].uiPrio > (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]]></ST>
</Implementation>
</Method>
<Method Name="M_GetHighest" Id="{26fa0379-d921-41a3-a15c-b3ff597c1d37}">
<Declaration><![CDATA[METHOD M_GetHighest : BOOL
VAR_OUTPUT
stJob : ST_TransJob;
END_VAR
VAR
_uiIndex : UINT := 0;
_rDynPrio : REAL;
_uiCnt : UINT;
END_VAR]]></Declaration>
<Implementation>
<ST><![CDATA[// No jobs to return
IF _uiJobCount = 0 THEN
M_GetHighest := FALSE;
RETURN;
END_IF
// Find job with highest priority also update dyn prio
FOR _uiCnt := 0 TO (_uiJobCount-1) DO
// Check for highest priority
IF _astJobQueue[_uiCnt].uiPrio > _astJobQueue[_uiIndex].uiPrio THEN
_uiIndex := _uiCnt;
END_IF
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;]]></ST>
</Implementation>
</Method>
</POU>
</TcPlcObject>