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


 

// ============================================================
    // Синхронизация планового времени освобождения ванн
    // ============================================================
FOR i := 1 TO 17 DO
   IF GVL.vanBusy[i] THEN
        // Время горизонтального переезда от текущей позиции автооператора до ванны i
        travelToVat := REAL_TO_TIME(PV.transitTimed[MapToTransitIndex(gvl.aoPosition), i] * 1000.0);
        GVL.planVatFreeTime[i] := MAX(GVL.planVatFreeTime[i], MAX(GVL.vanEndTime[i] + GVL.vanTransitOut[i], GVL.sysTime + travelToVat));
    ELSE
        GVL.planVatFreeTime[i] := MAX(GVL.planVatFreeTime[i], GVL.sysTime);
    END_IF
END_FOR


    // ============================================================
    // Обработка кнопки 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 and not GVL.aoParkBusy THEN
        // Сброс переменных задания перед каждым поиском
		RebuildBufferAndLoadStatus();
        GVL.aoJobSource := -1;
        GVL.aoJobDest   := -1;
        GVL.candidate := 0;

        // ---------- Обработка кнопок "Загружена" / "Разгружена" ----------
        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;

                        route := GVL.podveskas[podAtPos0].processType;
                        firstVat := GetVatFromRecipe(route, 1);

                        IF firstVat > 0 THEN
                            IF (NOT GVL.vanBusy[firstVat]) AND
                               EvaluatePodveska(route := route,
                                                curStep := 0,
                                                sourcePos := 0,
                                                commit := FALSE) THEN
                                               
                                // Немедленный старт в линию
                                EvaluatePodveska(route := route,
                                                curStep := 0,
                                                sourcePos := 0,
                                                commit := TRUE);
                                                
                                GVL.aoJobSource := 0;
                                GVL.aoJobDest := firstVat;
                                GVL.candidate := podAtPos0;
                                GVL.aoBusy := TRUE;
                                RETURN;
                            ELSE
                                // Отправляем в буфер
                                IF Main.bufferHolds[1] = 0 THEN
                                    GVL.aoJobDest := 101;
                                ELSIF Main.bufferHolds[2] = 0 THEN
                                    GVL.aoJobDest := 102;
                                ELSIF Main.bufferHolds[3] = 0 THEN
                                    GVL.aoJobDest := 103;
                                ELSE
                                    GVL.aoJobDest := -1;
                                END_IF
                                IF GVL.aoJobDest > 0 THEN
                                    GVL.aoJobSource := 0;
                                    GVL.candidate := podAtPos0;
                                    GVL.aoBusy := TRUE;
                                    RETURN;
                                END_IF
                            END_IF
                        END_IF
                    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;
                END_IF
            ELSE
                // ----- Позиция 0 свободна -----
                
				IF GVL.PodLoaded THEN
					bestIdx := 0;
					bestTime := DT#2100-01-01-00:00:00;
					
					// Первый проход: ищем подвески с xUnloaded = FALSE (готовые к загрузке)
					FOR a := 1 TO 4 DO
						IF (GVL.podveskas[a].currentStep = -1) AND 
						   (GVL.podveskas[a].currentPos >= 101 AND GVL.podveskas[a].currentPos <= 103) AND
						   (NOT GVL.podveskas[a].xUnloaded) THEN
							IF (GVL.podveskas[a].bufferEntryTime < bestTime) THEN
								bestTime := GVL.podveskas[a].bufferEntryTime;
								bestIdx := a;
							END_IF
						END_IF
					END_FOR
					
					// Если не нашли готовых к загрузке, берём любую завершённую (xUnloaded = TRUE)
					IF bestIdx = 0 THEN
						FOR a := 1 TO 4 DO
							IF (GVL.podveskas[a].currentStep = -1) AND 
							   (GVL.podveskas[a].currentPos >= 101 AND GVL.podveskas[a].currentPos <= 103) THEN
								IF (GVL.podveskas[a].bufferEntryTime < bestTime) THEN
									bestTime := GVL.podveskas[a].bufferEntryTime;
									bestIdx := a;
								END_IF
							END_IF
						END_FOR
					END_IF
				
					IF bestIdx > 0 THEN
						GVL.aoJobSource := GVL.podveskas[bestIdx].currentPos;
						GVL.aoJobDest := 0;
						GVL.candidate := bestIdx;
						GVL.PodLoaded := FALSE;
						GVL.BtnLoaded_Sn_push := FALSE;
						GVL.BtnLoaded_Ag_push := FALSE;
						// Сбрасываем флаги: теперь подвеска будет считаться «пустой и вызванной»
						GVL.podveskas[bestIdx].xLoaded := FALSE;
						GVL.podveskas[bestIdx].xUnloaded := FALSE;
						GVL.aoBusy := TRUE;
						RETURN;
					ELSE
						GVL.PodLoaded := FALSE;
						GVL.BtnLoaded_Sn_push := FALSE;
						GVL.BtnLoaded_Ag_push := FALSE;
					END_IF
				END_IF
            END_IF
        END_IF

        // ---------- Основной цикл выбора подвески ----------
        highestPrio := -201;

        FOR a := 1 TO 4 DO
            sourcePos := GVL.podveskas[a].currentPos;
            route := GVL.podveskas[a].processType;
            curStep := GVL.podveskas[a].currentStep;

            expectedVat := GetVatFromRecipe(route, curStep);

            GetTargetVatForPodveska := 0;
            IF curStep >= 0 AND curStep <= 13 THEN
                CASE route OF
                    E_RouteType.eTin:
                        GetTargetVatForPodveska := TargetVars.recipeTin[curStep + 1].vatNo;
                    E_RouteType.eSilver:
                        GetTargetVatForPodveska := TargetVars.recipeSilver[curStep + 1].vatNo;
                END_CASE
            END_IF
            targetVat := GetTargetVatForPodveska;

            // ---------- Логика для завершённых подвесок ----------
            IF curStep < 0 THEN
                IF sourcePos = 0 THEN
                    IF GVL.podveskas[a].xUnloaded THEN
                        IF Main.bufferHolds[1] = 0 THEN
                            targetVat := 101;
                            IsPodveskaReadyToUnload := TRUE;
                        ELSIF Main.bufferHolds[2] = 0 THEN
                            targetVat := 102;
                            IsPodveskaReadyToUnload := TRUE;
                        ELSIF Main.bufferHolds[3] = 0 THEN
                            targetVat := 103;
                            IsPodveskaReadyToUnload := TRUE;
                        ELSE
                            IF NOT GVL.vanBusy[1] THEN
                                FOR a2 := 1 TO 4 DO
                                    IF (GVL.podveskas[a2].currentStep = -1) AND 
                                       (GVL.podveskas[a2].currentPos >= 101 AND GVL.podveskas[a2].currentPos <= 103) THEN
                                        GVL.vanBusy[1] := TRUE;
                                        GVL.vanEndTime[1] := DT#1970-01-01-00:00:00;
                                        GVL.aoJobSource := GVL.podveskas[a2].currentPos;
                                        GVL.aoJobDest := 1;
                                        GVL.candidate := a2;
                                        GVL.aoBusy := TRUE;
                                        RETURN;
                                    END_IF
                                END_FOR
                            END_IF
                            IsPodveskaReadyToUnload := FALSE;
                        END_IF
                    ELSE
                        IsPodveskaReadyToUnload := FALSE;
                        CONTINUE;
                    END_IF
                ELSIF sourcePos >= 101 AND sourcePos <= 103 THEN
                    CONTINUE;
                ELSIF sourcePos >= 1 AND sourcePos <= 17 THEN
                    IsPodveskaReadyToUnload := TRUE;
                    IF Main.bufferHolds[1] = 0 THEN
                        targetVat := 101;
                    ELSIF Main.bufferHolds[2] = 0 THEN
                        targetVat := 102;
                    ELSIF Main.bufferHolds[3] = 0 THEN
                        targetVat := 103;
                    ELSIF NOT GVL.loadPosBusy THEN
                        targetVat := 0;
                    ELSE
                        targetVat := -1;
                    END_IF
                ELSE
                    CONTINUE;
                END_IF
            ELSE
                // ---------- Проверка готовности активной подвески ----------
                IsPodveskaReadyToUnload := FALSE;

                IF sourcePos = 0 OR (sourcePos >= 101 AND sourcePos <= 103) THEN
                    IsPodveskaReadyToUnload := TRUE;
                END_IF

                IF sourcePos >= 1 AND sourcePos <= 17 THEN
                    IF sourcePos <> expectedVat THEN
                        IsPodveskaReadyToUnload := FALSE;
                    END_IF
                    IF GVL.vanEndTime[sourcePos] < GVL.sysTime THEN
                        IsPodveskaReadyToUnload := TRUE;
                    END_IF
                    IF (sourcePos = 4 OR sourcePos = 8 OR sourcePos = 13 OR sourcePos = 16) AND GVL.vanBusy[sourcePos - 1] THEN
                        IsPodveskaReadyToUnload := FALSE;
                    END_IF
                END_IF
            END_IF

            IF IsPodveskaReadyToUnload THEN
                // Проверка доступности целевой позиции
                IF targetVat < 0 THEN
                    CanLoadTargetVat := FALSE;
                ELSIF targetVat = 0 THEN
                    CanLoadTargetVat := (NOT GVL.loadPosBusy);
                ELSIF targetVat >= 1 AND targetVat <= 17 THEN
                    CanLoadTargetVat := NOT GVL.vanBusy[targetVat];
                ELSIF targetVat >= 101 AND targetVat <= 103 THEN
                    CanLoadTargetVat := (Main.bufferHolds[targetVat - 100] = 0);
                ELSE
                    CanLoadTargetVat := FALSE;
                END_IF

                IF ((sourcePos = 0) OR (sourcePos >= 101 AND sourcePos <= 103)) AND (curStep >= 0) THEN
                    IF NOT EvaluatePodveska(route := route,
                                            curStep := curStep,
                                            sourcePos := sourcePos,
                                            commit := FALSE) THEN
                                            
                        CanLoadTargetVat := FALSE;
                    END_IF
                END_IF

                IF (sourcePos >= 1 AND sourcePos <= 17) AND (curStep >= 0) AND (targetVat = 0) AND (NOT CanLoadTargetVat) THEN
                    IF Main.bufferHolds[1] = 0 THEN
                        targetVat := 101;
                        CanLoadTargetVat := TRUE;
                        GVL.podveskas[a].currentStep := -1;
                        GVL.podveskas[a].xLoaded := FALSE;
                    ELSIF Main.bufferHolds[2] = 0 THEN
                        targetVat := 102;
                        CanLoadTargetVat := TRUE;
                        GVL.podveskas[a].currentStep := -1;
                        GVL.podveskas[a].xLoaded := FALSE;
                    ELSIF Main.bufferHolds[3] = 0 THEN
                        targetVat := 103;
                        CanLoadTargetVat := TRUE;
                        GVL.podveskas[a].currentStep := -1;
                        GVL.podveskas[a].xLoaded := FALSE;
                    END_IF
                END_IF

                IF (sourcePos = 0) AND (curStep >= 0) AND (NOT CanLoadTargetVat) THEN
                    IF Main.bufferHolds[1] = 0 THEN
                        targetVat := 101;
                        CanLoadTargetVat := TRUE;
                    ELSIF Main.bufferHolds[2] = 0 THEN
                        targetVat := 102;
                        CanLoadTargetVat := TRUE;
                    ELSIF Main.bufferHolds[3] = 0 THEN
                        targetVat := 103;
                        CanLoadTargetVat := TRUE;
                    ELSE
                        CanLoadTargetVat := FALSE;
                    END_IF
                END_IF

                IF CanLoadTargetVat THEN
                     prio := 0;

                    IF (route = E_RouteType.eTin AND curStep = 8 AND sourcePos = 10) OR
                       (route = E_RouteType.eSilver AND curStep = 8 AND sourcePos = 6) THEN
                        prio := prio + 1000;
                    END_IF

                    IF sourcePos >= 1 AND sourcePos <= 17 AND curStep > 0 THEN
                        prio := prio + ULINT_TO_INT(TIME_TO_ULINT(GVL.sysTime - GVL.vanEndTime[sourcePos]) / 100);
                    END_IF

                    IF (route = E_RouteType.eTin AND targetVat = 11) OR
                       (route = E_RouteType.eSilver AND targetVat = 5) THEN
                        prio := prio + 500;
                    END_IF

                    IF ((sourcePos = 0) OR (sourcePos >= 101 AND sourcePos <= 103)) AND (curStep >= 0) THEN
                        IF EvaluatePodveska(route := route,
                                            curStep := curStep,
                                            sourcePos := sourcePos,
                                            commit := FALSE) THEN
                            prio := prio + 700;
                        END_IF
                    END_IF

                    IF sourcePos >= 101 AND sourcePos <= 103 THEN
						prio := prio - 200;
						// Бонус за ожидание в буфере: +1 за каждые 1с
						prio := prio + ULINT_TO_INT(TIME_TO_ULINT(GVL.sysTime - GVL.podveskas[a].bufferEntryTime) / 1000);
                    END_IF

                    IF (sourcePos = 3 OR sourcePos = 7 OR sourcePos = 12 OR sourcePos = 15) THEN
                        IF GVL.vanBusy[sourcePos + 1] THEN
                            prio := prio + 600;
                        END_IF
                    END_IF

                    IF (curStep < 0) AND (sourcePos = 0) THEN
                        prio := prio + 2000;
                    END_IF

                    IF (curStep < 0) AND (sourcePos >= 1 AND sourcePos <= 17) THEN
                        prio := prio + 2500;
                    END_IF

                    IF GVL.resetActive AND (curStep < 0) AND (sourcePos >= 1 AND sourcePos <= 17) THEN
                        prio := prio + 3000;
                    END_IF

                    IF prio > highestPrio THEN
                        highestPrio := prio;
                        GVL.candidate := a;
                        GVL.aoJobSource := sourcePos;
                        GVL.aoJobDest := targetVat;
                    END_IF
                END_IF
            END_IF
        END_FOR

        // ----------------------------------------------------------
        // Запуск движения для выбранного кандидата
        // ----------------------------------------------------------
        IF GVL.candidate > 0 THEN
            // Если подвеска завершённая и её везут на позицию 0 – завершаем
            IF (GVL.aoJobDest = 0) AND (GVL.podveskas[GVL.candidate].currentStep >= 0) THEN
                GVL.podveskas[GVL.candidate].currentStep := -1;
                GVL.podveskas[GVL.candidate].xLoaded := FALSE;
            END_IF;

            // Для активных подвесок, стартующих в технологическую ванну ИЗ БУФЕРА или ПОЗИЦИИ 0,
            // фиксируем план. При перемещениях между техваннами план не пересчитываем.
            IF (GVL.podveskas[GVL.candidate].currentStep >= 0) AND 
               (GVL.aoJobDest >= 1) AND (GVL.aoJobDest <= 17) AND
               ((GVL.podveskas[GVL.candidate].currentPos = 0) OR 
                (GVL.podveskas[GVL.candidate].currentPos >= 101 AND GVL.podveskas[GVL.candidate].currentPos <= 103)) THEN
                EvaluatePodveska(route := GVL.podveskas[GVL.candidate].processType,
                                 curStep := GVL.podveskas[GVL.candidate].currentStep,
                                 sourcePos := GVL.podveskas[GVL.candidate].currentPos,
                                 commit := TRUE);
                GVL.aoBusy := TRUE;
                // Сброс флага разгрузки, если подвеска стала завершённой и стоит на 0
                IF (GVL.podveskas[GVL.candidate].currentStep < 0) AND 
                   (GVL.podveskas[GVL.candidate].currentPos = 0) THEN
                    GVL.podveskas[GVL.candidate].xUnloaded := FALSE;
                END_IF;
            ELSE
                // Перемещение в буфер или на позицию 0 (не технологическая ванна) – фиксация плана не нужна
                GVL.aoBusy := TRUE;
            END_IF;
        END_IF;
    END_IF;   // конец IF NOT GVL.aoBusy