Загрузка данных
Мы полностью переработали 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 сможет стартовать, как только окна позволят.