134 lines
5.2 KiB
Python
134 lines
5.2 KiB
Python
# processors/process_timer.py
|
|
# -*- coding: utf-8 -*-
|
|
import sympy
|
|
import traceback
|
|
|
|
# Usar las nuevas utilidades
|
|
from .processor_utils import (
|
|
get_sympy_representation,
|
|
sympy_expr_to_scl,
|
|
format_variable_name,
|
|
get_target_scl_name,
|
|
)
|
|
from .symbol_manager import SymbolManager, extract_plc_variable_name
|
|
|
|
SCL_SUFFIX = "_sympy_processed"
|
|
|
|
|
|
def process_timer(
|
|
instruction, network_id, sympy_map, symbol_manager: SymbolManager, data
|
|
):
|
|
"""
|
|
Genera SCL para Temporizadores (TON, TOF) directamente.
|
|
Requiere datos de instancia.
|
|
"""
|
|
instr_uid = instruction["instruction_uid"]
|
|
instr_type_original = (
|
|
instruction.get("type", "").replace(SCL_SUFFIX, "").replace("_error", "")
|
|
) # TON o TOF
|
|
if instruction.get("type", "").endswith(SCL_SUFFIX) or "_error" in instruction.get(
|
|
"type", ""
|
|
):
|
|
return False
|
|
|
|
scl_timer_type = instr_type_original.upper()
|
|
if scl_timer_type not in ["TON", "TOF", "TP"]:
|
|
instruction["scl"] = (
|
|
f"// ERROR: Tipo de temporizador directo no soportado: {instr_type_original}"
|
|
)
|
|
instruction["type"] = instr_type_original + "_error"
|
|
return True
|
|
|
|
# 1. Obtener Inputs: IN, PT, y nombre de instancia (implícito o explícito)
|
|
in_info = instruction["inputs"].get("IN")
|
|
pt_info = instruction["inputs"].get("PT")
|
|
# Buscar instancia: ¿está en inputs? ¿o como instance_db?
|
|
instance_plc_name = instruction.get("instance_db") # Buscar primero aquí
|
|
if not instance_plc_name:
|
|
# Si no, buscar un input llamado 'timer' o similar? No estándar.
|
|
# Asumir que debe estar declarado como STAT si no hay instance_db
|
|
instance_plc_name = instruction.get("instance_name") # Nombre directo?
|
|
if not instance_plc_name:
|
|
instance_plc_name = (
|
|
f"#{scl_timer_type}_INSTANCE_{instr_uid}" # Placeholder final
|
|
)
|
|
print(
|
|
f"Advertencia: No se encontró nombre/instancia para {instr_type_original} UID {instr_uid}. Usando placeholder '{instance_plc_name}'."
|
|
)
|
|
|
|
sympy_in_expr = get_sympy_representation(
|
|
in_info, network_id, sympy_map, symbol_manager
|
|
)
|
|
sympy_or_const_pt = get_sympy_representation(
|
|
pt_info, network_id, sympy_map, symbol_manager
|
|
)
|
|
|
|
# Verificar dependencias
|
|
if sympy_in_expr is None or sympy_or_const_pt is None or instance_plc_name is None:
|
|
return False
|
|
|
|
# Formatear nombre de instancia
|
|
instance_name_scl = format_variable_name(instance_plc_name)
|
|
|
|
# Convertir entradas SymPy/Constante a SCL strings
|
|
in_scl = sympy_expr_to_scl(sympy_in_expr, symbol_manager)
|
|
pt_scl = sympy_expr_to_scl(sympy_or_const_pt, symbol_manager)
|
|
|
|
# Generar la llamada SCL
|
|
# ENHANCED: Only add TODO comment if it's not an auto-generated placeholder
|
|
if instance_plc_name.startswith("#") and "_INSTANCE_" in instance_plc_name:
|
|
# It's an auto-generated placeholder, will be declared automatically in VAR_TEMP
|
|
scl_call = f"{instance_name_scl}(IN := {in_scl}, PT := {pt_scl});"
|
|
else:
|
|
# It's a named instance that might need manual declaration
|
|
scl_call = f"{instance_name_scl}(IN := {in_scl}, PT := {pt_scl}); // TODO: Declarar {instance_name_scl} : {scl_timer_type};"
|
|
|
|
# Actualizar instrucción
|
|
instruction["scl"] = scl_call # SCL final generado
|
|
instruction["type"] = instr_type_original + SCL_SUFFIX
|
|
|
|
# 7. Actualizar sympy_map para las salidas Q, ET y ENO
|
|
map_key_q = (network_id, instr_uid, "Q") # Pin estándar SCL
|
|
# *** Store SymPy Symbol for boolean output Q ***
|
|
q_output_scl_access = f"{instance_name_scl}.Q" # String for SCL access
|
|
sympy_q_symbol = symbol_manager.get_symbol(q_output_scl_access) # Get/Create Symbol
|
|
if sympy_q_symbol:
|
|
sympy_map[map_key_q] = sympy_q_symbol # Store the SYMBOL
|
|
else:
|
|
print(
|
|
f"Error: Could not create symbol for {q_output_scl_access} in {instr_type_original} {instr_uid}"
|
|
)
|
|
sympy_map[map_key_q] = None
|
|
|
|
map_key_et = (network_id, instr_uid, "ET") # Pin estándar SCL
|
|
# ET is TIME, store SCL access string
|
|
sympy_map[map_key_et] = f"{instance_name_scl}.ET"
|
|
|
|
# *** NEW: Handle ENO (Enable Output) pin ***
|
|
map_key_eno = (network_id, instr_uid, "eno")
|
|
# For timers, ENO is typically TRUE when the timer is properly executed
|
|
# In simplified logic, we can assume ENO = TRUE for well-formed timer calls
|
|
# Or we could make it conditional based on input validity
|
|
# For now, let's use TRUE as a reasonable default
|
|
sympy_map[map_key_eno] = sympy.true
|
|
|
|
# *** Also handle common aliases ***
|
|
map_key_out = (
|
|
network_id,
|
|
instr_uid,
|
|
"out",
|
|
) # Some connections might look for "out"
|
|
sympy_map[map_key_out] = sympy_q_symbol # Map "out" to Q output
|
|
|
|
return True
|
|
|
|
|
|
# --- Processor Information Function ---
|
|
def get_processor_info():
|
|
"""Devuelve info para TON, TOF y TP directos."""
|
|
return [
|
|
{"type_name": "ton", "processor_func": process_timer, "priority": 5},
|
|
{"type_name": "tof", "processor_func": process_timer, "priority": 5},
|
|
{"type_name": "tp", "processor_func": process_timer, "priority": 5},
|
|
]
|