142 lines
6.1 KiB
Python
142 lines
6.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
from .processor_utils import get_scl_representation, format_variable_name,get_target_scl_name
|
|
|
|
# TODO: Import necessary functions from processor_utils
|
|
# Example: from .processor_utils import get_scl_representation, format_variable_name
|
|
# Or: import processors.processor_utils as utils
|
|
|
|
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
|
|
SCL_SUFFIX = "_scl"
|
|
|
|
# --- Function code starts ---
|
|
def process_call(instruction, network_id, scl_map, access_map, data):
|
|
instr_uid = instruction["instruction_uid"]
|
|
instr_type = instruction.get("type", "") # Usar get con default
|
|
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type:
|
|
return False
|
|
|
|
block_name = instruction.get("block_name", f"UnknownCall_{instr_uid}")
|
|
block_type = instruction.get("block_type") # FC, FB
|
|
instance_db = instruction.get("instance_db") # Nombre del DB de instancia (para FB)
|
|
|
|
# Formatear nombres
|
|
block_name_scl = format_variable_name(block_name)
|
|
instance_db_scl = format_variable_name(instance_db) if instance_db else None
|
|
|
|
# --- Manejo de EN ---
|
|
en_input = instruction["inputs"].get("en")
|
|
en_scl = (
|
|
get_scl_representation(en_input, network_id, scl_map, access_map)
|
|
if en_input
|
|
else "TRUE"
|
|
)
|
|
if en_scl is None:
|
|
return False # Dependencia EN no resuelta
|
|
|
|
# --- Procesar Parámetros de Entrada/Salida ---
|
|
# Necesitamos iterar sobre los pines definidos en la interfaz del bloque llamado.
|
|
# Esta información no está directamente en la instrucción 'Call' del JSON simplificado.
|
|
# ¡Limitación! Sin la interfaz del bloque llamado, solo podemos manejar EN/ENO
|
|
# y asumir una llamada sin parámetros o con parámetros conectados implícitamente.
|
|
|
|
# Solución temporal: Buscar conexiones en 'inputs' y 'outputs' que NO sean 'en'/'eno'
|
|
# y construir la llamada basándose en eso. Esto es muy heurístico.
|
|
scl_call_params = []
|
|
processed_inputs = {"en"} # Marcar 'en' como ya procesado
|
|
for pin_name, source_info in instruction.get("inputs", {}).items():
|
|
if pin_name not in processed_inputs:
|
|
param_scl = get_scl_representation(
|
|
source_info, network_id, scl_map, access_map
|
|
)
|
|
if param_scl is None:
|
|
# print(f"DEBUG: Call {instr_uid} esperando parámetro de entrada {pin_name}")
|
|
return False # Dependencia de parámetro no resuelta
|
|
# Formatear si es variable
|
|
param_scl_formatted = (
|
|
format_variable_name(param_scl)
|
|
if source_info.get("type") == "variable"
|
|
else param_scl
|
|
)
|
|
scl_call_params.append(
|
|
f"{format_variable_name(pin_name)} := {param_scl_formatted}"
|
|
)
|
|
processed_inputs.add(pin_name)
|
|
|
|
# Procesar parámetros de salida (asignaciones después de la llamada o pasados como VAR_IN_OUT/VAR_OUTPUT)
|
|
# Esto es aún más complejo. SCL normalmente asigna salidas después o usa punteros/referencias.
|
|
# Simplificación: Asumir que las salidas se manejan por asignación posterior si es necesario,
|
|
# o que son VAR_OUTPUT y se acceden como instancia.salida.
|
|
# Por ahora, no generamos asignaciones explícitas para las salidas aquí.
|
|
|
|
# --- Construcción de la Llamada SCL ---
|
|
scl_call_body = ""
|
|
param_string = ", ".join(scl_call_params)
|
|
|
|
if block_type == "FB":
|
|
if not instance_db_scl:
|
|
print(
|
|
f"Error: Llamada a FB '{block_name_scl}' (UID {instr_uid}) sin DB de instancia especificado."
|
|
)
|
|
instruction["scl"] = f"// ERROR: FB Call {block_name_scl} sin instancia"
|
|
instruction["type"] = "Call_FB_error"
|
|
return True # Procesado con error
|
|
# Llamada a FB con DB de instancia
|
|
scl_call_body = f"{instance_db_scl}({param_string});"
|
|
elif block_type == "FC":
|
|
# Llamada a FC
|
|
scl_call_body = f"{block_name_scl}({param_string});"
|
|
else:
|
|
print(
|
|
f"Advertencia: Tipo de bloque no soportado para Call UID {instr_uid}: {block_type}"
|
|
)
|
|
scl_call_body = f"// ERROR: Call a bloque tipo '{block_type}' no soportado: {block_name_scl}"
|
|
instruction["type"] = f"Call_{block_type}_error" # Marcar como error parcial
|
|
|
|
# --- Aplicar Condición EN ---
|
|
scl_final = ""
|
|
if en_scl != "TRUE":
|
|
# Indentar la llamada dentro del IF
|
|
indented_call = "\n".join([f" {line}" for line in scl_call_body.splitlines()])
|
|
scl_final = f"IF {en_scl} THEN\n{indented_call}\nEND_IF;"
|
|
else:
|
|
scl_final = scl_call_body
|
|
|
|
# --- Actualizar JSON y Mapa SCL ---
|
|
instruction["scl"] = scl_final
|
|
instruction["type"] = (
|
|
f"Call_{block_type}_scl"
|
|
if "_error" not in instruction["type"]
|
|
else instruction["type"]
|
|
)
|
|
|
|
# Actualizar scl_map con el estado ENO (igual a EN para llamadas simples sin manejo explícito de ENO)
|
|
map_key_eno = (network_id, instr_uid, "eno")
|
|
scl_map[map_key_eno] = en_scl
|
|
|
|
# Propagar valores de salida (si pudiéramos determinarlos)
|
|
# Ejemplo: Si supiéramos que hay una salida 'Out1' de tipo INT
|
|
# map_key_out1 = (network_id, instr_uid, "Out1")
|
|
# if block_type == "FB" and instance_db_scl:
|
|
# scl_map[map_key_out1] = f"{instance_db_scl}.Out1" # Acceso a salida de instancia
|
|
# else:
|
|
# # Para FCs, necesitaríamos una variable temporal o asignación explícita
|
|
# temp_out1 = generate_temp_var_name(network_id, instr_uid, "Out1")
|
|
# # Modificar scl_call_body para incluir la asignación: Out1 => temp_out1
|
|
# scl_map[map_key_out1] = temp_out1
|
|
|
|
return True
|
|
|
|
# --- Procesador de Temporizadores (TON, TOF) ---
|
|
|
|
# --- Function code ends ---
|
|
|
|
# --- Processor Information Function ---
|
|
def get_processor_info():
|
|
"""Devuelve la información para las llamadas a FC y FB."""
|
|
# Esta función maneja tanto FC como FB. El despachador en x2_process.py
|
|
# usará 'call_fc' o 'call_fb' como clave basada en block_type.
|
|
return [
|
|
{'type_name': 'call_fc', 'processor_func': process_call, 'priority': 6},
|
|
{'type_name': 'call_fb', 'processor_func': process_call, 'priority': 6}
|
|
]
|