110 lines
5.0 KiB
Python
110 lines
5.0 KiB
Python
# processors/process_counter.py
|
|
# -*- coding: utf-8 -*-
|
|
import sympy
|
|
import traceback
|
|
from .processor_utils import get_sympy_representation, sympy_expr_to_scl, format_variable_name, get_target_scl_name
|
|
from .symbol_manager import SymbolManager
|
|
|
|
SCL_SUFFIX = "_sympy_processed"
|
|
|
|
def process_counter(instruction, network_id, sympy_map, symbol_manager: SymbolManager, data):
|
|
"""
|
|
Genera SCL para Contadores (CTU, CTD, CTUD).
|
|
Requiere datos de instancia (DB o STAT).
|
|
"""
|
|
instr_uid = instruction["instruction_uid"]
|
|
instr_type_original = instruction.get("type", "") # CTU, CTD, CTUD
|
|
if instr_type_original.endswith(SCL_SUFFIX) or "_error" in instr_type_original:
|
|
return False
|
|
|
|
# 1. Definir pines de entrada esperados
|
|
input_pins_map = {
|
|
"CTU": ["CU", "R", "PV"],
|
|
"CTD": ["CD", "LD", "PV"],
|
|
"CTUD": ["CU", "CD", "R", "LD", "PV"]
|
|
}
|
|
input_pins = input_pins_map.get(instr_type_original.upper())
|
|
if not input_pins:
|
|
instruction["scl"] = f"// ERROR: Tipo de contador no soportado: {instr_type_original}"
|
|
instruction["type"] = instr_type_original + "_error"
|
|
return True
|
|
|
|
# 2. Procesar Parámetros de Entrada
|
|
scl_call_params = []
|
|
dependencies_resolved = True
|
|
optional_pins = {"R", "LD"} # Estos pueden no estar conectados
|
|
|
|
for pin in input_pins:
|
|
pin_info = instruction["inputs"].get(pin)
|
|
if pin_info: # Si el pin está definido en el JSON
|
|
source_sympy_or_const = get_sympy_representation(pin_info, network_id, sympy_map, symbol_manager)
|
|
if source_sympy_or_const is None:
|
|
# print(f"DEBUG Counter {instr_uid}: Input param '{pin}' dependency not ready.")
|
|
dependencies_resolved = False
|
|
break
|
|
# Convertir a SCL para la llamada (sin simplificar aquí)
|
|
param_scl_value = sympy_expr_to_scl(source_sympy_or_const, symbol_manager)
|
|
pin_name_scl = format_variable_name(pin) # Formatear nombre del parámetro
|
|
scl_call_params.append(f"{pin_name_scl} := {param_scl_value}")
|
|
elif pin not in optional_pins: # Si falta un pin requerido
|
|
print(f"Error: Falta entrada requerida '{pin}' para {instr_type_original} UID {instr_uid}.")
|
|
instruction["scl"] = f"// ERROR: Falta entrada requerida '{pin}' para {instr_type_original} UID {instr_uid}."
|
|
instruction["type"] = instr_type_original + "_error"
|
|
return True
|
|
|
|
if not dependencies_resolved:
|
|
return False
|
|
|
|
# 3. Obtener Nombre de Instancia
|
|
# Asumiendo que x1 o una fase previa llena 'instance_db' si es un FB multi-instancia
|
|
instance_name_raw = instruction.get("instance_db")
|
|
if not instance_name_raw:
|
|
# Asumiendo que es STAT si no hay DB instancia explícito (requiere declaración en x3)
|
|
instance_name_raw = instruction.get("instance_name") # Buscar nombre directo si x1 lo provee
|
|
if not instance_name_raw:
|
|
instance_name_raw = f"#CTR_INSTANCE_{instr_uid}" # Placeholder final
|
|
print(f"Advertencia: No se encontró nombre/instancia para {instr_type_original} UID {instr_uid}. Usando placeholder '{instance_name_raw}'.")
|
|
instance_name_scl = format_variable_name(instance_name_raw)
|
|
|
|
# 4. Generar la llamada SCL
|
|
param_string = ", ".join(scl_call_params)
|
|
scl_call = f"{instance_name_scl}({param_string}); // TODO: Declarar {instance_name_scl} : {instr_type_original.upper()}; en VAR_STAT o VAR"
|
|
|
|
# Contadores no suelen tener EN/ENO explícito en LAD, se asume siempre habilitado
|
|
instruction["scl"] = scl_call # SCL final generado
|
|
instruction["type"] = instr_type_original + SCL_SUFFIX
|
|
|
|
# 4. Actualizar sympy_map para las salidas (QU, QD, CV)
|
|
output_pins_map = {
|
|
"CTU": ["QU", "CV"],
|
|
"CTD": ["QD", "CV"],
|
|
"CTUD": ["QU", "QD", "CV"]
|
|
}
|
|
output_pins = output_pins_map.get(instr_type_original.upper(), [])
|
|
|
|
for pin in output_pins:
|
|
map_key = (network_id, instr_uid, pin)
|
|
output_scl_access = f"{instance_name_scl}.{pin.upper()}"
|
|
if pin.upper() in ["QU", "QD"]: # These are boolean outputs
|
|
# *** Store SymPy Symbol for boolean outputs QU/QD ***
|
|
sympy_out_symbol = symbol_manager.get_symbol(output_scl_access)
|
|
if sympy_out_symbol:
|
|
sympy_map[map_key] = sympy_out_symbol # Store SYMBOL
|
|
else:
|
|
print(f"Error: Could not create symbol for {output_scl_access} in {instr_type_original} {instr_uid}")
|
|
sympy_map[map_key] = None
|
|
else:
|
|
# For non-boolean (like CV - count value), store SCL access string
|
|
sympy_map[map_key] = output_scl_access
|
|
|
|
return True
|
|
|
|
|
|
# --- Processor Information Function ---
|
|
def get_processor_info():
|
|
"""Devuelve la información para los contadores CTU, CTD, CTUD."""
|
|
return [
|
|
{'type_name': 'ctu', 'processor_func': process_counter, 'priority': 5},
|
|
{'type_name': 'ctd', 'processor_func': process_counter, 'priority': 5},
|
|
{'type_name': 'ctud', 'processor_func': process_counter, 'priority': 5}
|
|
] |