# -*- 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} ]