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


Мы полностью переработали CheckConstraints, убрав пересчёт arrivalTime и используя реальные данные из симуляции. Теперь ожидание waitTime вычисляется как разница между сохранённым simStartTime и фактическим временем прибытия (simArrivalTime), что исключает ложные превышения maxWait. Подвеска eSilver больше не будет блокироваться без причины.

1. Добавляем поле в структуру ST_Podveska
pascal
TYPE ST_Podveska :
STRUCT
    // ... все существующие поля ...
    simArrivalTime : ARRAY[1..17] OF DT;   // время прибытия к ванне (новое!)
END_STRUCT
END_TYPE
2. Обновлённый EvaluatePodveska
pascal
METHOD EvaluatePodveska : BOOL
VAR_IN_OUT
    podveska : ST_Podveska;
END_VAR
VAR_INPUT
    localVatBusyUntil : ARRAY[1..17] OF DT;
    localVatStartTime : ARRAY[1..17] OF DT;
END_VAR
VAR
    arrivalTime   : DT;
    prevVat       : INT;
    step          : INT;
    vat           : INT;
    techTime      : TIME;
    transitTime   : TIME;
    transitOut    : TIME;
    startTime     : DT;
    endTime       : DT;
    maxWait       : TIME := gvl.maxWait;
    nextVat       : INT;
    srcIdx        : INT;
    clearStep     : INT;
    intersection  : BOOL;
BEGIN
    podveska.firstVatStartTime := DT#1970-01-01-00:00:00;

    // Сброс данных для уже пройденных ванн
    IF podveska.currentStep >= 0 THEN
        FOR clearStep := 1 TO podveska.currentStep DO
            vat := GetVatFromRecipe(podveska.processType, clearStep);
            IF vat > 0 THEN
                podveska.simStartTime[vat] := DT#1970-01-01-00:00:00;
                podveska.simBusyUntil[vat] := DT#1970-01-01-00:00:00;
                podveska.simArrivalTime[vat] := DT#1970-01-01-00:00:00;
            END_IF;
        END_FOR;
    END_IF;

    // Начальный момент времени
    IF (podveska.currentStep >= 0) AND (podveska.currentPos >= 1) AND (podveska.currentPos <= 17) THEN
        arrivalTime := MAX(GVL.sysTime, GVL.vanEndTime[podveska.currentPos]);
    ELSE
        arrivalTime := GVL.sysTime;
    END_IF;

    prevVat := podveska.currentPos;
    step := podveska.currentStep + 1;

    WHILE step <= 14 DO
        vat := GetVatFromRecipe(podveska.processType, step);
        IF vat = 0 THEN EXIT; END_IF;

        srcIdx := MapToTransitIndex(prevVat);
        transitTime := REAL_TO_TIME(PV.transitTimed[srcIdx, vat] * 1000.0);
        arrivalTime := arrivalTime + transitTime;

        // Сохраняем время прибытия (до возможного сдвига)
        podveska.simArrivalTime[vat] := arrivalTime;

        IF podveska.processType = E_RouteType.eTin THEN
            techTime := TargetVars.recipeTin[step].duration;
        ELSE
            techTime := TargetVars.recipeSilver[step].duration;
        END_IF;

        IF step < 14 THEN
            nextVat := GetVatFromRecipe(podveska.processType, step + 1);
            IF nextVat <> 0 THEN
                transitOut := REAL_TO_TIME(PV.transitTimed[vat, nextVat] * 1000.0);
            ELSE
                transitOut := T#0s;
            END_IF;
        ELSE
            transitOut := T#0s;
        END_IF;

        // Проверка пересечения окон
        intersection := FALSE;
        IF (localVatStartTime[vat] > DT#1970-01-02-00:00:00) AND 
           (localVatBusyUntil[vat] > GVL.sysTime) THEN
            IF (arrivalTime < localVatBusyUntil[vat]) AND 
               ((arrivalTime + techTime + transitOut) > localVatStartTime[vat]) THEN
                intersection := TRUE;
            END_IF;
        END_IF;

        IF intersection THEN
            startTime := MAX(arrivalTime, localVatBusyUntil[vat]);
        ELSE
            startTime := arrivalTime;
        END_IF;

        IF podveska.firstVatStartTime = DT#1970-01-01-00:00:00 THEN
            podveska.firstVatStartTime := startTime;
        END_IF;

        endTime := startTime + techTime;

        podveska.simStartTime[vat] := startTime;
        podveska.simBusyUntil[vat] := endTime + transitOut;

        // Готовим arrivalTime для следующего шага
        arrivalTime := endTime;
        prevVat := vat;
        step := step + 1;
    END_WHILE;

    EvaluatePodveska := TRUE;
END_METHOD
3. Обновлённый CheckConstraints
pascal
METHOD CheckConstraints : BOOL
VAR_IN_OUT
    podveska : ST_Podveska;
END_VAR
VAR_INPUT
    localVatBusyUntil : ARRAY[1..17] OF DT;
    localVatStartTime : ARRAY[1..17] OF DT;
END_VAR
VAR
    vat          : INT;
    step         : INT;
    startTime    : DT;
    arrivalTime  : DT;
    waitTime     : TIME;
    maxWait      : TIME := gvl.maxWait;
    lrealStart   : LREAL;
    lrealArrival : LREAL;
BEGIN
    step := podveska.currentStep + 1;

    WHILE step <= 14 DO
        vat := GetVatFromRecipe(podveska.processType, step);
        IF vat = 0 THEN EXIT; END_IF;

        startTime := podveska.simStartTime[vat];
        arrivalTime := podveska.simArrivalTime[vat];

        // План должен быть заполнен
        IF (startTime <= DT#1970-01-02-00:00:00) OR (arrivalTime <= DT#1970-01-02-00:00:00) THEN
            CheckConstraints := FALSE;
            RETURN;
        END_IF;

        lrealStart := DT_TO_LREAL(startTime);
        lrealArrival := DT_TO_LREAL(arrivalTime);
        waitTime := LREAL_TO_TIME((lrealStart - lrealArrival) * 1000.0);

        IF waitTime > maxWait THEN
            CheckConstraints := FALSE;
            RETURN;
        END_IF;

        step := step + 1;
    END_WHILE;

    CheckConstraints := TRUE;
END_METHOD
4. Обновление CyclicCall и SelectAndMove
Изменений в этих методах не требуется, они уже передают localVatBusyUntil и localVatStartTime и используют обновлённые сигнатуры.
Единственное – убедитесь, что в SelectAndMove для ожидающих подвесок также вызывается CheckConstraints с новой сигнатурой (она уже такая).

После внесения этих правок CheckConstraints будет честно использовать фактические времена прибытия, рассчитанные симулятором, и eSilver сможет стартовать, как только окна позволят.