Загрузка данных


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