Загрузка данных
METHOD CyclicCall
VAR
i : INT;
a : INT;
a2 : INT;
podAtPos0 : INT;
bestIdx : INT;
bestTime : DT;
allEvacuated : BOOL;
sourcePos : INT;
route : E_RouteType;
curStep : INT;
expectedVat : INT;
targetVat : INT;
firstVat : INT;
GetTargetVatForPodveska : INT;
IsPodveskaReadyToUnload : BOOL;
CanLoadTargetVat : BOOL;
prio : INT;
highestPrio : INT;
candidateLocal : INT;
aoJobSourceLocal : INT;
aoJobDestLocal : INT;
savedBusy : ARRAY[1..17] OF DT;
savedStart : ARRAY[1..17] OF DT;
evacuateCandidate : BOOL;
evacuateLeader : BOOL;
BEGIN
// ============================================================================
// БЛОК 1: СИНХРОНИЗАЦИЯ С ФИЗИЧЕСКИМ СОСТОЯНИЕМ ЛИНИИ
// ============================================================================
FOR i := 1 TO 17 DO
IF GVL.vanBusy[i] THEN
GVL.planVatBusyUntil[i] := MAX(GVL.vanEndTime[i], GVL.sysTime);
ELSE
GVL.planVatBusyUntil[i] := GVL.sysTime;
END_IF;
END_FOR;
// ============================================================
// Однократная инициализация (firstScan – VAR_STAT в FB)
// ============================================================
IF gvl.firstScan THEN
FOR i := 1 TO 17 DO
GVL.planVatFreeTime[i] := GVL.sysTime;
GVL.planVatBusyUntil[i] := GVL.sysTime;
GVL.planVatStartTime[i] := GVL.sysTime;
END_FOR;
GVL.loadPosBusy := FALSE;
FOR a := 1 TO 4 DO
IF GVL.podveskas[a].currentPos = 0 THEN
GVL.loadPosBusy := TRUE;
EXIT;
END_IF
END_FOR
FOR a := 1 TO 4 DO
IF (GVL.podveskas[a].currentPos >= 101 AND GVL.podveskas[a].currentPos <= 103) THEN
GVL.podveskas[a].bufferEntryTime := GVL.sysTime;
END_IF
END_FOR
RebuildBufferAndLoadStatus();
GVL.aoJobSource := -1;
GVL.aoJobDest := -1;
gvl.firstScan := FALSE;
END_IF
// ============================================================
// Обработка кнопки Reset
// ============================================================
IF GVL.Reset THEN
GVL.Reset := FALSE;
GVL.resetActive := TRUE;
FOR a := 1 TO 4 DO
IF GVL.podveskas[a].currentStep >= 0 THEN
GVL.podveskas[a].currentStep := -1;
GVL.podveskas[a].xLoaded := FALSE;
GVL.podveskas[a].xUnloaded := FALSE;
END_IF
END_FOR
RebuildBufferAndLoadStatus();
END_IF
IF GVL.resetActive THEN
allEvacuated := TRUE;
FOR a := 1 TO 4 DO
IF NOT ((GVL.podveskas[a].currentPos = 0) OR
(GVL.podveskas[a].currentPos >= 101 AND GVL.podveskas[a].currentPos <= 103)) THEN
allEvacuated := FALSE;
EXIT;
END_IF
END_FOR
IF allEvacuated THEN
GVL.resetActive := FALSE;
END_IF
END_IF
// ============================================================
// Основной блок – только когда автооператор свободен
// ============================================================
IF NOT GVL.aoBusy THEN
RebuildBufferAndLoadStatus();
GVL.aoJobSource := -1;
GVL.aoJobDest := -1;
GVL.candidate := 0;
// ============================================================================
// БЛОК 2: КАСКАДНОЕ НАКОПЛЕНИЕ ПРОГНОЗОВ АКТИВНЫХ ПОДВЕСОК
// ============================================================================
FOR a := 1 TO 4 DO
IF GVL.podveskas[a].currentStep >= 0 THEN
EvaluatePodveska(podveska := GVL.podveskas[a]);
FOR i := 1 TO 17 DO
GVL.planVatBusyUntil[i] := MAX(GVL.planVatBusyUntil[i], GVL.podveskas[a].simBusyUntil[i]);
GVL.planVatStartTime[i] := MAX(GVL.planVatStartTime[i], GVL.podveskas[a].simStartTime[i]);
END_FOR;
END_IF;
END_FOR;
// ---------- Обработка кнопок "Загружена" / "Разгружена" ----------
IF NOT GVL.resetActive THEN
podAtPos0 := 0;
FOR a := 1 TO 4 DO
IF GVL.podveskas[a].currentPos = 0 THEN
podAtPos0 := a;
EXIT;
END_IF
END_FOR
IF podAtPos0 > 0 THEN
// ----- На позиции 0 уже стоит подвеска -----
IF GVL.PodLoaded AND (GVL.podveskas[podAtPos0].currentStep = -1) THEN
IF (Control_HMI.processType = E_RouteType.eTin) OR
(Control_HMI.processType = E_RouteType.eSilver) THEN
GVL.podveskas[podAtPos0].processType := Control_HMI.processType;
GVL.podveskas[podAtPos0].xLoaded := TRUE;
GVL.podveskas[podAtPos0].xUnloaded := FALSE;
GVL.podveskas[podAtPos0].currentStep := 0;
GVL.PodLoaded := FALSE;
GVL.BtnLoaded_Sn_push := FALSE;
GVL.BtnLoaded_Ag_push := FALSE;
// *** БЕЗ НЕМЕДЛЕННОГО ЗАПУСКА И ФИКСАЦИИ ПЛАНОВ ***
// Подвеска просто активируется, селектор приоритетов сам решит её судьбу
ELSE
GVL.PodLoaded := FALSE;
END_IF
END_IF
// *** ИЗМЕНЁННАЯ ОБРАБОТКА КНОПКИ "РАЗГРУЖЕНО" ***
IF GVL.PodUnLoaded AND (GVL.podveskas[podAtPos0].currentStep = -1) THEN
GVL.podveskas[podAtPos0].xUnloaded := TRUE;
GVL.podveskas[podAtPos0].xLoaded := FALSE;
GVL.PodUnLoaded := FALSE;
GVL.BtnUnLoaded_push := FALSE;
IF (Main.bufferHolds[1] <> 0) AND (Main.bufferHolds[2] <> 0) AND (Main.bufferHolds[3] <> 0) THEN
IF NOT GVL.vanBusy[1] THEN
GVL.aoJobSource := 0;
GVL.aoJobDest := 1;
GVL.candidate := podAtPos0;
GVL.aoBusy := TRUE;
gvl.AutoLoadFromBuffer := TRUE;
RETURN;
END_IF
END_IF
END_IF
ELSE
// ----- Позиция 0 свободна -----
// ... (логика автоматического вызова из буфера и ручной загрузки) ...
// *** БЕЗ ИЗМЕНЕНИЙ ***
END_IF
END_IF
// ---------- Основной цикл выбора победителя ----------
// ... (полностью без изменений, см. предыдущие версии) ...
// ----------------------------------------------------------
// Запуск движения для выбранного кандидата
// ... (полностью без изменений) ...
END_IF;
END_METHOD