# -*- coding: utf-8 -*- # /processors/processor_utils.py # Procesador de utilidades para el procesamiento de archivos XML de Simatic import re # --- Copia aquí las funciones auxiliares --- # get_scl_representation, format_variable_name, # generate_temp_var_name, get_target_scl_name # Asegúrate de que no dependen de variables globales de x2_process.py # (como 'data' o 'network_access_maps' - esas se pasarán como argumentos) # Ejemplo de una función (asegúrate de copiar todas las necesarias) def format_variable_name(name): """Limpia el nombre de la variable para SCL.""" if not name: return "_INVALID_NAME_" if name.startswith('"') and name.endswith('"'): return name prefix = "" if name.startswith("#"): prefix = "#" name = name[1:] if name and name[0].isdigit(): name = "_" + name name = re.sub(r"[^a-zA-Z0-9_]", "_", name) return prefix + name # --- Helper Functions --- # (get_scl_representation, format_variable_name, generate_temp_var_name, get_target_scl_name - sin cambios) def get_scl_representation(source_info, network_id, scl_map, access_map): if not source_info: return None if isinstance(source_info, list): scl_parts = [] all_resolved = True for sub_source in source_info: sub_scl = get_scl_representation( sub_source, network_id, scl_map, access_map ) if sub_scl is None: all_resolved = False break if ( sub_scl in ["TRUE", "FALSE"] or (sub_scl.startswith('"') and sub_scl.endswith('"')) or sub_scl.isdigit() or (sub_scl.startswith("(") and sub_scl.endswith(")")) ): scl_parts.append(sub_scl) else: scl_parts.append(f"({sub_scl})") return ( " OR ".join(scl_parts) if len(scl_parts) > 1 else (scl_parts[0] if scl_parts else "FALSE") if all_resolved else None ) source_type = source_info.get("type") if source_type == "powerrail": return "TRUE" elif source_type == "variable": name = source_info.get("name") # Asegurar que los nombres de variables se formatean correctamente aquí también return ( format_variable_name(name) if name else f"_ERR_VAR_NO_NAME_{source_info.get('uid')}_" ) elif source_type == "constant": dtype = str(source_info.get("datatype", "")).upper() value = source_info.get("value") try: if dtype == "BOOL": return str(value).upper() elif dtype in [ "INT", "DINT", "SINT", "USINT", "UINT", "UDINT", "LINT", "ULINT", "WORD", "DWORD", "LWORD", "BYTE", ]: return str(value) elif dtype in ["REAL", "LREAL"]: s_val = str(value) return s_val if "." in s_val or "e" in s_val.lower() else s_val + ".0" elif dtype == "STRING": # Escapar comillas simples dentro del string si es necesario str_val = str(value).replace("'", "''") return f"'{str_val}'" elif dtype == "TYPEDCONSTANT": # Podría necesitar formateo específico basado en el tipo real return str(value) else: # Otros tipos (TIME, DATE, etc.) - devolver como string por ahora str_val = str(value).replace("'", "''") return f"'{str_val}'" except Exception as e: print(f"Advertencia: Error formateando constante {source_info}: {e}") return f"_ERR_CONST_FORMAT_{source_info.get('uid')}_" elif source_type == "connection": map_key = ( network_id, source_info.get("source_instruction_uid"), source_info.get("source_pin"), ) return scl_map.get(map_key) elif source_type == "unknown_source": print( f"Advertencia: Refiriendo a fuente desconocida UID: {source_info.get('uid')}" ) return f"_ERR_UNKNOWN_SRC_{source_info.get('uid')}_" else: print(f"Advertencia: Tipo de fuente desconocido: {source_info}") return f"_ERR_INVALID_SRC_TYPE_" def format_variable_name(name): """Limpia el nombre de la variable para SCL.""" if not name: return "_INVALID_NAME_" # Si ya está entre comillas dobles, asumimos que es un nombre complejo (ej. "DB"."Variable") # y lo devolvemos tal cual para SCL. if name.startswith('"') and name.endswith('"'): # Podríamos añadir validación extra aquí si fuera necesario return name # Si no tiene comillas, es un nombre simple (ej. Tag_1, #tempVar) # Reemplazar caracteres no válidos (excepto '_') por '_' # Permitir '#' al inicio para variables temporales prefix = "" if name.startswith("#"): prefix = "#" name = name[1:] # Permitir letras, números y guiones bajos. Reemplazar el resto. # Asegurarse de que no empiece con número (después del # si existe) if name and name[0].isdigit(): name = "_" + name # Reemplazar caracteres no válidos name = re.sub(r"[^a-zA-Z0-9_]", "_", name) return prefix + name def generate_temp_var_name(network_id, instr_uid, pin_name): net_id_clean = str(network_id).replace("-", "_") instr_uid_clean = str(instr_uid).replace("-", "_") pin_name_clean = str(pin_name).replace("-", "_").lower() # Usar # para variables temporales SCL estándar return f"#_temp_{net_id_clean}_{instr_uid_clean}_{pin_name_clean}" def get_target_scl_name(instruction, output_pin_name, network_id, default_to_temp=True): instr_uid = instruction["instruction_uid"] output_pin_data = instruction["outputs"].get(output_pin_name) target_scl = None if ( output_pin_data and isinstance(output_pin_data, list) and len(output_pin_data) == 1 ): dest_access = output_pin_data[0] if dest_access.get("type") == "variable": target_scl = dest_access.get("name") if target_scl: target_scl = format_variable_name(target_scl) # Formatear nombre else: print( f"Error: Var destino {instr_uid}.{output_pin_name} sin nombre (UID: {dest_access.get('uid')}). {'Usando temp.' if default_to_temp else 'Ignorando.'}" ) target_scl = ( generate_temp_var_name(network_id, instr_uid, output_pin_name) if default_to_temp else None ) elif dest_access.get("type") == "constant": print( f"Advertencia: Instr {instr_uid} escribe en const UID {dest_access.get('uid')}. {'Usando temp.' if default_to_temp else 'Ignorando.'}" ) target_scl = ( generate_temp_var_name(network_id, instr_uid, output_pin_name) if default_to_temp else None ) else: print( f"Advertencia: Destino {instr_uid}.{output_pin_name} no es var/const: {dest_access.get('type')}. {'Usando temp.' if default_to_temp else 'Ignorando.'}" ) target_scl = ( generate_temp_var_name(network_id, instr_uid, output_pin_name) if default_to_temp else None ) elif default_to_temp: target_scl = generate_temp_var_name(network_id, instr_uid, output_pin_name) # Si target_scl sigue siendo None y no se debe usar temp, devolver None if target_scl is None and not default_to_temp: return None # Si target_scl es None pero sí se permite temp, generar uno ahora if target_scl is None and default_to_temp: target_scl = generate_temp_var_name(network_id, instr_uid, output_pin_name) return target_scl