Version mejorada cuando los EN no estan definidos
This commit is contained in:
parent
d173278ce8
commit
5e4f351d29
Binary file not shown.
|
@ -86,7 +86,7 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// RLO updated by Contact 27: (\"Procedure_Variables\".\"Blender_Run\".\"Running\") AND \"CLK_1.0S\""
|
||||
"scl": "// RLO updated by Contact 27: \"Procedure_Variables\".\"Blender_Run\".\"Running\" AND \"CLK_1.0S\""
|
||||
},
|
||||
{
|
||||
"instruction_uid": "28",
|
||||
|
@ -122,7 +122,7 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"scl": "IF (\"Procedure_Variables\".\"Blender_Run\".\"Running\") AND \"CLK_1.0S\" THEN\n \"Blender_Variables_Pers\".\"gSLIM_Sec\" := (\"Blender_Variables_Pers\".\"gSLIM_Sec\") + (1);\nEND_IF;"
|
||||
"scl": "IF \"Procedure_Variables\".\"Blender_Run\".\"Running\" AND \"CLK_1.0S\" THEN\n \"Blender_Variables_Pers\".\"gSLIM_Sec\" := \"Blender_Variables_Pers\".\"gSLIM_Sec\" + 1;\nEND_IF;"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -220,7 +220,7 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// RLO updated by Contact 27: (\"gBlenderBlending\") AND \"CLK_1.0S\""
|
||||
"scl": "// RLO updated by Contact 27: \"gBlenderBlending\" AND \"CLK_1.0S\""
|
||||
},
|
||||
{
|
||||
"instruction_uid": "28",
|
||||
|
@ -256,7 +256,7 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"scl": "IF (\"gBlenderBlending\") AND \"CLK_1.0S\" THEN\n \"Blender_Variables_Pers\".\"gProdSec\" := (\"Blender_Variables_Pers\".\"gProdSec\") + (1);\nEND_IF;"
|
||||
"scl": "IF \"gBlenderBlending\" AND \"CLK_1.0S\" THEN\n \"Blender_Variables_Pers\".\"gProdSec\" := \"Blender_Variables_Pers\".\"gProdSec\" + 1;\nEND_IF;"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -287,7 +287,7 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// Comparison Eq 24: (\"Blender_Variables_Pers\".\"gProdSec\" = 60)"
|
||||
"scl": "// Comparison Eq 24: \"Blender_Variables_Pers\".\"gProdSec\" = 60"
|
||||
},
|
||||
{
|
||||
"instruction_uid": "25",
|
||||
|
@ -307,7 +307,7 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "\"m1MinONS\" := (\"Blender_Variables_Pers\".\"gProdSec\" = 60);"
|
||||
"scl": "\"m1MinONS\" := \"Blender_Variables_Pers\".\"gProdSec\" = 60;"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -365,7 +365,7 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "29",
|
||||
"type": "Add",
|
||||
"type": "Add_scl",
|
||||
"inputs": {
|
||||
"in1": {
|
||||
"uid": "24",
|
||||
|
@ -390,7 +390,8 @@
|
|||
"name": "\"Blender_Variables_Pers\".\"gProdMin\""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"scl": "\"Blender_Variables_Pers\".\"gProdMin\" := \"Blender_Variables_Pers\".\"gProdMin\" + 1;"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -421,7 +422,7 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// Comparison Eq 24: (\"Blender_Variables_Pers\".\"gProdMin\" = 60)"
|
||||
"scl": "// Comparison Eq 24: \"Blender_Variables_Pers\".\"gProdMin\" = 60"
|
||||
},
|
||||
{
|
||||
"instruction_uid": "25",
|
||||
|
@ -441,7 +442,7 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "\"m1HourONS\" := (\"Blender_Variables_Pers\".\"gProdMin\" = 60);"
|
||||
"scl": "\"m1HourONS\" := \"Blender_Variables_Pers\".\"gProdMin\" = 60;"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -499,7 +500,7 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "32",
|
||||
"type": "Add",
|
||||
"type": "Add_scl",
|
||||
"inputs": {
|
||||
"in1": {
|
||||
"uid": "24",
|
||||
|
@ -524,11 +525,12 @@
|
|||
"name": "\"Blender_Variables_Pers\".\"gProdHour\""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"scl": "\"Blender_Variables_Pers\".\"gProdHour\" := \"Blender_Variables_Pers\".\"gProdHour\" + 1;"
|
||||
},
|
||||
{
|
||||
"instruction_uid": "33",
|
||||
"type": "Add",
|
||||
"type": "Add_scl",
|
||||
"inputs": {
|
||||
"in1": {
|
||||
"uid": "27",
|
||||
|
@ -553,7 +555,8 @@
|
|||
"name": "\"Blender_Variables_Pers\".\"gBlendingMaintHour\""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"scl": "\"Blender_Variables_Pers\".\"gBlendingMaintHour\" := \"Blender_Variables_Pers\".\"gBlendingMaintHour\" + 1;"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -642,7 +645,7 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "33",
|
||||
"type": "Move",
|
||||
"type": "Move_scl",
|
||||
"inputs": {
|
||||
"in": {
|
||||
"uid": "25",
|
||||
|
@ -661,11 +664,12 @@
|
|||
"name": "\"Blender_Variables_Pers\".\"gProdMin\""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"scl": "\"Blender_Variables_Pers\".\"gProdMin\" := 0;"
|
||||
},
|
||||
{
|
||||
"instruction_uid": "34",
|
||||
"type": "Move",
|
||||
"type": "Move_scl",
|
||||
"inputs": {
|
||||
"in": {
|
||||
"uid": "27",
|
||||
|
@ -684,7 +688,8 @@
|
|||
"name": "\"Blender_Variables_Pers\".\"gProdHour\""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"scl": "\"Blender_Variables_Pers\".\"gProdHour\" := 0;"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -728,7 +733,7 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// RLO updated by Contact 27: (\"Procedure_Variables\".\"Blender_Run\".\"Running\") AND \"CLK_1.0S\""
|
||||
"scl": "// RLO updated by Contact 27: \"Procedure_Variables\".\"Blender_Run\".\"Running\" AND \"CLK_1.0S\""
|
||||
},
|
||||
{
|
||||
"instruction_uid": "28",
|
||||
|
@ -764,7 +769,7 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"scl": "IF (\"Procedure_Variables\".\"Blender_Run\".\"Running\") AND \"CLK_1.0S\" THEN\n \"Blender_Variables_Pers\".\"gRunningSeconds\" := (\"Blender_Variables_Pers\".\"gRunningSeconds\") + (1);\nEND_IF;"
|
||||
"scl": "IF \"Procedure_Variables\".\"Blender_Run\".\"Running\" AND \"CLK_1.0S\" THEN\n \"Blender_Variables_Pers\".\"gRunningSeconds\" := \"Blender_Variables_Pers\".\"gRunningSeconds\" + 1;\nEND_IF;"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -801,7 +806,7 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "36",
|
||||
"type": "Mod",
|
||||
"type": "Mod_scl",
|
||||
"inputs": {
|
||||
"en": {
|
||||
"type": "connection",
|
||||
|
@ -840,7 +845,8 @@
|
|||
"target_uid": "37",
|
||||
"target_name": "Eq"
|
||||
}
|
||||
]
|
||||
],
|
||||
"scl": "\"MOD60\" := \"I_DIRunning_sec\" MOD DINT#60;"
|
||||
},
|
||||
{
|
||||
"instruction_uid": "37",
|
||||
|
@ -867,7 +873,7 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// Comparison Eq 37: (\"MOD60\" = DINT#0)"
|
||||
"scl": "// Comparison Eq 37: \"MOD60\" = DINT#0"
|
||||
},
|
||||
{
|
||||
"instruction_uid": "38",
|
||||
|
@ -887,7 +893,7 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// RLO updated by Contact 38: (\"MOD60\" = DINT#0) AND \"Procedure_Variables\".\"Blender_Run\".\"Running\""
|
||||
"scl": "// RLO updated by Contact 38: \"MOD60\" = DINT#0 AND \"Procedure_Variables\".\"Blender_Run\".\"Running\""
|
||||
},
|
||||
{
|
||||
"instruction_uid": "39",
|
||||
|
@ -907,7 +913,7 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// RLO updated by Contact 39: ((\"MOD60\" = DINT#0) AND \"Procedure_Variables\".\"Blender_Run\".\"Running\") AND \"CLK_1.0S\""
|
||||
"scl": "// RLO updated by Contact 39: (\"MOD60\" = DINT#0 AND \"Procedure_Variables\".\"Blender_Run\".\"Running\") AND \"CLK_1.0S\""
|
||||
},
|
||||
{
|
||||
"instruction_uid": "40",
|
||||
|
@ -943,7 +949,7 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"scl": "IF ((\"MOD60\" = DINT#0) AND \"Procedure_Variables\".\"Blender_Run\".\"Running\") AND \"CLK_1.0S\" THEN\n \"Blender_Variables_Pers\".\"gRunningMinutes\" := (\"Blender_Variables_Pers\".\"gRunningMinutes\") + (1);\nEND_IF;"
|
||||
"scl": "IF (\"MOD60\" = DINT#0 AND \"Procedure_Variables\".\"Blender_Run\".\"Running\") AND \"CLK_1.0S\" THEN\n \"Blender_Variables_Pers\".\"gRunningMinutes\" := \"Blender_Variables_Pers\".\"gRunningMinutes\" + 1;\nEND_IF;"
|
||||
},
|
||||
{
|
||||
"instruction_uid": "41",
|
||||
|
@ -1032,7 +1038,7 @@
|
|||
},
|
||||
{
|
||||
"instruction_uid": "34",
|
||||
"type": "Mod",
|
||||
"type": "Mod_scl",
|
||||
"inputs": {
|
||||
"en": {
|
||||
"type": "connection",
|
||||
|
@ -1071,7 +1077,8 @@
|
|||
"target_uid": "35",
|
||||
"target_name": "Eq"
|
||||
}
|
||||
]
|
||||
],
|
||||
"scl": "IF \"mRunMin\" THEN\n \"MOD60\" := \"I_DIRunning_min\" MOD DINT#60;\nEND_IF;"
|
||||
},
|
||||
{
|
||||
"instruction_uid": "35",
|
||||
|
@ -1098,7 +1105,7 @@
|
|||
}
|
||||
},
|
||||
"outputs": {},
|
||||
"scl": "// Comparison Eq 35: (\"MOD60\" = DINT#0)"
|
||||
"scl": "// Comparison Eq 35: \"MOD60\" = DINT#0"
|
||||
},
|
||||
{
|
||||
"instruction_uid": "36",
|
||||
|
@ -1134,7 +1141,7 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"scl": "IF (\"MOD60\" = DINT#0) THEN\n \"Blender_Variables_Pers\".\"gRunningMaintHour\" := (\"Blender_Variables_Pers\".\"gRunningMaintHour\") + (1);\nEND_IF;"
|
||||
"scl": "IF \"MOD60\" = DINT#0 THEN\n \"Blender_Variables_Pers\".\"gRunningMaintHour\" := \"Blender_Variables_Pers\".\"gRunningMaintHour\" + 1;\nEND_IF;"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
450
process.py
450
process.py
|
@ -15,7 +15,7 @@ def get_scl_representation(source_info, network_id, scl_map, access_map):
|
|||
source_info: Puede ser {'type': 'powerrail'}, un Access dict, o un Connection dict, o una lista (OR).
|
||||
"""
|
||||
if not source_info:
|
||||
return None
|
||||
return None # Entrada no conectada o dependencia no lista
|
||||
|
||||
# Si es una lista (rama OR), procesarla recursivamente
|
||||
if isinstance(source_info, list):
|
||||
|
@ -25,21 +25,22 @@ def get_scl_representation(source_info, network_id, scl_map, access_map):
|
|||
sub_scl = get_scl_representation(sub_source, network_id, scl_map, access_map)
|
||||
if sub_scl is None:
|
||||
all_resolved = False
|
||||
# print(f"DEBUG: Dependencia no resuelta DENTRO de rama OR: {sub_source}")
|
||||
break
|
||||
scl_parts.append(f"({sub_scl})")
|
||||
if all_resolved:
|
||||
or_expr = " OR ".join(scl_parts)
|
||||
# print(f"DEBUG: Rama OR resuelta a: {or_expr}")
|
||||
return or_expr
|
||||
# Evitar paréntesis innecesarios si ya es una expresión simple o contenida
|
||||
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:
|
||||
return None
|
||||
scl_parts.append(f"({sub_scl})") # Añadir paréntesis por precaución de precedencia
|
||||
if all_resolved:
|
||||
return " OR ".join(scl_parts) if len(scl_parts) > 1 else (scl_parts[0] if scl_parts else None)
|
||||
else:
|
||||
return None # Dependencia en la rama no resuelta
|
||||
|
||||
# Si no es lista, procesar como fuente única
|
||||
source_type = source_info.get('type')
|
||||
|
||||
if source_type == 'powerrail':
|
||||
return "TRUE" # Condición inicial
|
||||
return "TRUE"
|
||||
|
||||
elif source_type == 'variable':
|
||||
return source_info.get('name', f"_ERR_VAR_{source_info.get('uid')}_")
|
||||
|
@ -47,28 +48,22 @@ def get_scl_representation(source_info, network_id, scl_map, access_map):
|
|||
elif source_type == 'constant':
|
||||
dtype = str(source_info.get('datatype', '')).upper()
|
||||
value = source_info.get('value')
|
||||
try: # Añadir try-except para robustez en formato
|
||||
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 else s_val + ".0"
|
||||
return s_val if '.' in s_val or 'e' in s_val.lower() else s_val + ".0"
|
||||
elif dtype == 'STRING': return f"'{str(value)}'"
|
||||
elif dtype == 'TYPEDCONSTANT': return str(value) # Ej: DINT#60
|
||||
else: return f"'{str(value)}'" # Otros tipos como string
|
||||
else: return f"'{str(value)}'"
|
||||
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'))
|
||||
if map_key in scl_map:
|
||||
# print(f"DEBUG: Valor encontrado en scl_map para {map_key}: {scl_map[map_key]}")
|
||||
return scl_map[map_key]
|
||||
else:
|
||||
# print(f"DEBUG: Valor NO encontrado en scl_map para {map_key}")
|
||||
return None # Dependencia no resuelta
|
||||
return scl_map.get(map_key) # Devuelve valor o None si no existe
|
||||
|
||||
else:
|
||||
print(f"Advertencia: Tipo de fuente desconocido o inválido: {source_info}")
|
||||
|
@ -78,8 +73,10 @@ def generate_temp_var_name(network_id, instr_uid, pin_name):
|
|||
"""Genera un nombre único para una variable temporal SCL."""
|
||||
net_id_clean = str(network_id).replace('-', '_')
|
||||
instr_uid_clean = str(instr_uid).replace('-', '_')
|
||||
pin_name_clean = str(pin_name).replace('-', '_').lower() # lower para consistencia
|
||||
return f"_temp_{net_id_clean}_{instr_uid_clean}_{pin_name_clean}"
|
||||
pin_name_clean = str(pin_name).replace('-', '_').lower()
|
||||
# Evitar nombres que empiecen con número si network_id es numérico
|
||||
prefix = "_" if str(net_id_clean)[0].isdigit() else ""
|
||||
return f"{prefix}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):
|
||||
"""Determina el nombre SCL del destino (variable o temporal)."""
|
||||
|
@ -91,19 +88,15 @@ def get_target_scl_name(instruction, output_pin_name, network_id, default_to_tem
|
|||
dest_access = output_pin_data[0]
|
||||
if dest_access.get('type') == 'variable':
|
||||
target_scl = dest_access.get('name')
|
||||
# print(f"DEBUG: Target para {instr_uid}.{output_pin_name} es variable directa: {target_scl}")
|
||||
elif dest_access.get('type') == 'constant':
|
||||
print(f"Advertencia: Instrucción {instr_uid} intenta escribir en constante UID {dest_access.get('uid')}. Usando temporal.")
|
||||
print(f"Advertencia: Instrucción {instr_uid} intenta escribir en constante UID {dest_access.get('uid')}. {'Usando temporal.' if default_to_temp else 'Ignorando.'}")
|
||||
if default_to_temp: target_scl = generate_temp_var_name(network_id, instr_uid, output_pin_name)
|
||||
else:
|
||||
print(f"Advertencia: Destino de {instr_uid}.{output_pin_name} no es variable: {dest_access.get('type')}. Usando temporal si aplica.")
|
||||
print(f"Advertencia: Destino de {instr_uid}.{output_pin_name} no es variable: {dest_access.get('type')}. {'Usando temporal.' if default_to_temp else 'Ignorando.'}")
|
||||
if default_to_temp: target_scl = generate_temp_var_name(network_id, instr_uid, output_pin_name)
|
||||
elif default_to_temp:
|
||||
# Si no hay salida, o va a múltiples sitios, o no es Access tipo variable, usar temporal
|
||||
# print(f"DEBUG: Usando temporal para {instr_uid}.{output_pin_name}")
|
||||
target_scl = generate_temp_var_name(network_id, instr_uid, output_pin_name)
|
||||
|
||||
# print(f"DEBUG: Target final para {instr_uid}.{output_pin_name}: {target_scl}")
|
||||
return target_scl
|
||||
|
||||
# --- Procesadores de Instrucciones ---
|
||||
|
@ -112,41 +105,42 @@ def process_contact(instruction, network_id, scl_map, access_map):
|
|||
"""Traduce Contact a una expresión booleana SCL y actualiza scl_map."""
|
||||
instr_uid = instruction['instruction_uid']
|
||||
instr_type = instruction['type']
|
||||
if instr_type.endswith(SCL_SUFFIX): return False
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False
|
||||
|
||||
# Asume Contact normal, necesitaría info adicional para negado
|
||||
# (Podría estar en 'Name' o TemplateValue si el JSON lo capturara)
|
||||
is_negated = False # TODO: Determinar si es negado (ej. check instruction['Name'] == 'ContactN')
|
||||
is_negated = False # TODO: Determinar si es negado
|
||||
|
||||
print(f"DEBUG: Intentando procesar CONTACT{' (N)' if is_negated else ''} - UID: {instr_uid} en Red: {network_id}")
|
||||
# print(f"DEBUG: Intentando procesar CONTACT{' (N)' if is_negated else ''} - UID: {instr_uid} en Red: {network_id}")
|
||||
|
||||
in_rlo_scl = get_scl_representation(instruction['inputs'].get('in'), network_id, scl_map, access_map)
|
||||
operand_scl = get_scl_representation(instruction['inputs'].get('operand'), network_id, scl_map, access_map)
|
||||
|
||||
if in_rlo_scl is None or operand_scl is None:
|
||||
print(f"DEBUG: Dependencia no resuelta para CONTACT UID: {instr_uid} (in={in_rlo_scl}, op={operand_scl})")
|
||||
# print(f"DEBUG: Dependencia no resuelta para CONTACT UID: {instr_uid} (in={in_rlo_scl}, op={operand_scl})")
|
||||
return False
|
||||
|
||||
# Construir nueva expresión RLO
|
||||
term = f"(NOT {operand_scl})" if is_negated else operand_scl
|
||||
term = f"NOT {operand_scl}" if is_negated else operand_scl
|
||||
# Asegurarse de que el operando esté entre paréntesis si no es una variable simple
|
||||
if not (term.startswith('"') and term.endswith('"')):
|
||||
if not (term.startswith('(') and term.endswith(')')):
|
||||
term = f"({term})"
|
||||
|
||||
|
||||
new_rlo_scl = ""
|
||||
if in_rlo_scl == "TRUE": # Inicio de línea o RLO anterior era TRUE
|
||||
if in_rlo_scl == "TRUE":
|
||||
new_rlo_scl = term
|
||||
else: # Combinar con RLO anterior
|
||||
# Quitar paréntesis externos si el RLO anterior ya los tiene
|
||||
if in_rlo_scl.startswith('(') and in_rlo_scl.endswith(')'):
|
||||
in_rlo_processed = in_rlo_scl
|
||||
else:
|
||||
in_rlo_processed = f"({in_rlo_scl})" # Asegurar paréntesis
|
||||
# Poner el RLO anterior entre paréntesis si es necesario
|
||||
if not (in_rlo_scl.startswith('(') and in_rlo_scl.endswith(')')) and 'AND' in in_rlo_scl or 'OR' in in_rlo_scl:
|
||||
in_rlo_processed = f"({in_rlo_scl})"
|
||||
else:
|
||||
in_rlo_processed = in_rlo_scl
|
||||
new_rlo_scl = f"{in_rlo_processed} AND {term}"
|
||||
|
||||
# Actualizar scl_map con el nuevo RLO resultante de este contacto
|
||||
|
||||
map_key = (network_id, instr_uid, 'out')
|
||||
scl_map[map_key] = new_rlo_scl
|
||||
# print(f"DEBUG: CONTACT UID: {instr_uid} - Nuevo RLO en scl_map[{map_key}] = {new_rlo_scl}")
|
||||
|
||||
# Los contactos no generan SCL directo, solo actualizan el flujo lógico (RLO)
|
||||
instruction['scl'] = f"// RLO updated by Contact {instr_uid}: {new_rlo_scl}" # Comentario opcional
|
||||
instruction['scl'] = f"// RLO updated by Contact {instr_uid}: {new_rlo_scl}"
|
||||
instruction['type'] = instr_type + SCL_SUFFIX
|
||||
return True
|
||||
|
||||
|
@ -154,29 +148,37 @@ def process_eq(instruction, network_id, scl_map, access_map):
|
|||
"""Traduce Eq (comparación) a una expresión booleana SCL y actualiza scl_map."""
|
||||
instr_uid = instruction['instruction_uid']
|
||||
instr_type = instruction['type']
|
||||
if instr_type.endswith(SCL_SUFFIX): return False
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False
|
||||
|
||||
print(f"DEBUG: Intentando procesar EQ - UID: {instr_uid} en Red: {network_id}")
|
||||
# print(f"DEBUG: Intentando procesar EQ - UID: {instr_uid} en Red: {network_id}")
|
||||
|
||||
in1_scl = get_scl_representation(instruction['inputs'].get('in1'), network_id, scl_map, access_map)
|
||||
in2_scl = get_scl_representation(instruction['inputs'].get('in2'), network_id, scl_map, access_map)
|
||||
# 'pre' generalmente no se traduce directamente a SCL para comparaciones simples
|
||||
# pre_scl = get_scl_representation(instruction['inputs'].get('pre'), network_id, scl_map, access_map)
|
||||
|
||||
if in1_scl is None or in2_scl is None: # Ignoramos 'pre' por ahora
|
||||
print(f"DEBUG: Dependencia no resuelta para EQ UID: {instr_uid} (in1={in1_scl}, in2={in2_scl})")
|
||||
if in1_scl is None or in2_scl is None:
|
||||
# print(f"DEBUG: Dependencia no resuelta para EQ UID: {instr_uid} (in1={in1_scl}, in2={in2_scl})")
|
||||
return False
|
||||
|
||||
# Generar expresión de comparación
|
||||
comparison_scl = f"({in1_scl} = {in2_scl})"
|
||||
# Poner operandos entre paréntesis si son complejos
|
||||
op1 = f"({in1_scl})" if ' ' in in1_scl else in1_scl
|
||||
op2 = f"({in2_scl})" if ' ' in in2_scl else in2_scl
|
||||
comparison_scl = f"{op1} = {op2}" # SCL usa '=' para comparación
|
||||
|
||||
# Actualizar scl_map con el resultado booleano
|
||||
map_key = (network_id, instr_uid, 'out')
|
||||
scl_map[map_key] = comparison_scl
|
||||
# print(f"DEBUG: EQ UID: {instr_uid} - Resultado en scl_map[{map_key}] = {comparison_scl}")
|
||||
map_key_out = (network_id, instr_uid, 'out')
|
||||
scl_map[map_key_out] = comparison_scl
|
||||
|
||||
# Eq no genera SCL directo, solo el resultado booleano
|
||||
instruction['scl'] = f"// Comparison Eq {instr_uid}: {comparison_scl}" # Comentario opcional
|
||||
# --- Manejo de ENO ---
|
||||
# El 'pre' en LAD para comparación a menudo actúa como el EN.
|
||||
pre_scl = get_scl_representation(instruction['inputs'].get('pre'), network_id, scl_map, access_map)
|
||||
# Si 'pre' no está conectado, asumimos TRUE.
|
||||
effective_en_scl = "TRUE" if pre_scl is None else pre_scl
|
||||
# El estado ENO de una comparación es TRUE si se ejecuta (EN=TRUE) y FALSE si no.
|
||||
map_key_eno = (network_id, instr_uid, 'eno')
|
||||
scl_map[map_key_eno] = effective_en_scl
|
||||
# print(f"DEBUG: EQ UID: {instr_uid} - Estado ENO en scl_map[{map_key_eno}] = {effective_en_scl}")
|
||||
# --- Fin Manejo de ENO ---
|
||||
|
||||
instruction['scl'] = f"// Comparison Eq {instr_uid}: {comparison_scl}"
|
||||
instruction['type'] = instr_type + SCL_SUFFIX
|
||||
return True
|
||||
|
||||
|
@ -184,207 +186,305 @@ def process_coil(instruction, network_id, scl_map, access_map):
|
|||
"""Traduce Coil a una asignación SCL."""
|
||||
instr_uid = instruction['instruction_uid']
|
||||
instr_type = instruction['type']
|
||||
if instr_type.endswith(SCL_SUFFIX): return False
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False
|
||||
|
||||
print(f"DEBUG: Intentando procesar COIL - UID: {instr_uid} en Red: {network_id}")
|
||||
# print(f"DEBUG: Intentando procesar COIL - UID: {instr_uid} en Red: {network_id}")
|
||||
|
||||
in_rlo_scl = get_scl_representation(instruction['inputs'].get('in'), network_id, scl_map, access_map)
|
||||
operand_scl = get_scl_representation(instruction['inputs'].get('operand'), network_id, scl_map, access_map)
|
||||
|
||||
if in_rlo_scl is None or operand_scl is None:
|
||||
print(f"DEBUG: Dependencia no resuelta para COIL UID: {instr_uid} (in={in_rlo_scl}, op={operand_scl})")
|
||||
# print(f"DEBUG: Dependencia no resuelta para COIL UID: {instr_uid} (in={in_rlo_scl}, op={operand_scl})")
|
||||
return False
|
||||
|
||||
# Verificar que el operando sea una variable
|
||||
operand_info = instruction['inputs'].get('operand')
|
||||
if not (operand_info and operand_info.get('type') == 'variable'):
|
||||
print(f"Error: Operando de COIL UID {instr_uid} no es una variable: {operand_info}")
|
||||
# No se puede asignar a una constante o algo desconocido
|
||||
instruction['scl'] = f"// ERROR: Coil {instr_uid} operando no es variable"
|
||||
instruction['type'] = instr_type + "_error" # Marcar como error
|
||||
return True # Marcado como procesado (con error)
|
||||
instruction['type'] = instr_type + "_error"
|
||||
return True
|
||||
|
||||
# Generar la asignación SCL
|
||||
scl_final = f"{operand_scl} := {in_rlo_scl};"
|
||||
|
||||
instruction['scl'] = scl_final
|
||||
instruction['type'] = instr_type + SCL_SUFFIX
|
||||
|
||||
# Coil consume el RLO, no añade nada al scl_map para la salida 'out' (que no tiene)
|
||||
print(f"INFO: COIL UID: {instr_uid} procesado. SCL: {scl_final}")
|
||||
# print(f"INFO: COIL UID: {instr_uid} procesado. SCL: {scl_final}")
|
||||
return True
|
||||
|
||||
def process_convert(instruction, network_id, scl_map, access_map):
|
||||
"""Traduce Convert a SCL, usando temporal si es necesario."""
|
||||
instr_uid = instruction['instruction_uid']
|
||||
instr_type = instruction['type']
|
||||
if instr_type.endswith(SCL_SUFFIX): return False
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False
|
||||
|
||||
print(f"DEBUG: Intentando procesar CONVERT - UID: {instr_uid} en Red: {network_id}")
|
||||
# print(f"DEBUG: Intentando procesar CONVERT - UID: {instr_uid} en Red: {network_id}")
|
||||
|
||||
# --- Manejo de EN ---
|
||||
en_input = instruction['inputs'].get('en')
|
||||
en_scl = None
|
||||
if en_input is None:
|
||||
# print(f"DEBUG: Asumiendo EN=TRUE para CONVERT UID {instr_uid} (pin 'en' no conectado)")
|
||||
en_scl = "TRUE"
|
||||
else:
|
||||
en_scl = get_scl_representation(en_input, network_id, scl_map, access_map)
|
||||
# --- Fin Manejo de EN ---
|
||||
|
||||
en_scl = get_scl_representation(instruction['inputs'].get('en'), network_id, scl_map, access_map)
|
||||
in_scl = get_scl_representation(instruction['inputs'].get('in'), network_id, scl_map, access_map)
|
||||
|
||||
if en_scl is None or in_scl is None:
|
||||
print(f"DEBUG: Dependencia no resuelta para CONVERT UID: {instr_uid} (en={en_scl}, in={in_scl})")
|
||||
# print(f"DEBUG: Dependencia no resuelta para CONVERT UID: {instr_uid} (en={en_scl}, in={in_scl})")
|
||||
return False
|
||||
|
||||
# Determinar destino (variable o temporal) - Usa pin 'out'
|
||||
target_scl = get_target_scl_name(instruction, 'out', network_id, default_to_temp=True)
|
||||
if target_scl is None: # Should not happen with default_to_temp=True
|
||||
if target_scl is None:
|
||||
print(f"Error Interno: No se pudo determinar destino para CONVERT UID {instr_uid}")
|
||||
return False
|
||||
instruction['scl'] = f"// ERROR: No se pudo determinar destino para Convert {instr_uid}"
|
||||
instruction['type'] += "_error"
|
||||
return True
|
||||
|
||||
# Determinar función de conversión (simplificado, requiere tipos exactos)
|
||||
# TODO: Necesitaría info de TemplateValue para tipos Src/Dest
|
||||
# Por ahora, asumimos conversión implícita o directa si no podemos determinar
|
||||
conversion_expr = in_scl # Asume asignación directa por defecto
|
||||
# Ejemplo (si tuviéramos tipos):
|
||||
# src_type = instruction['template_values'].get('SrcType')
|
||||
# dest_type = instruction['template_values'].get('DestType')
|
||||
# if src_type == 'Int' and dest_type == 'DInt': conversion_expr = f"INT_TO_DINT({in_scl})"
|
||||
# elif src_type == 'DInt' and dest_type == 'Real': conversion_expr = f"DINT_TO_REAL({in_scl})"
|
||||
# else: conversion_expr = in_scl # Si no hay conversión específica conocida
|
||||
conversion_expr = in_scl # Asume conversión implícita por ahora
|
||||
# TODO: Añadir lógica de conversión explícita si se extraen tipos de TemplateValue
|
||||
|
||||
# Generar SCL
|
||||
scl_core = f"{target_scl} := {conversion_expr};"
|
||||
scl_final = scl_core if en_scl == "TRUE" else f"IF {en_scl} THEN\n {scl_core}\nEND_IF;"
|
||||
|
||||
instruction['scl'] = scl_final
|
||||
instruction['type'] = instr_type + SCL_SUFFIX
|
||||
|
||||
# Actualizar scl_map con el resultado (nombre de la variable destino o temporal)
|
||||
map_key = (network_id, instr_uid, 'out')
|
||||
scl_map[map_key] = target_scl
|
||||
# print(f"DEBUG: CONVERT UID: {instr_uid} - Resultado en scl_map[{map_key}] = {target_scl}")
|
||||
map_key_out = (network_id, instr_uid, 'out')
|
||||
scl_map[map_key_out] = target_scl
|
||||
|
||||
print(f"INFO: CONVERT UID: {instr_uid} procesado. SCL: {scl_final.splitlines()[0]}...")
|
||||
map_key_eno = (network_id, instr_uid, 'eno')
|
||||
scl_map[map_key_eno] = en_scl # ENO sigue a EN
|
||||
# print(f"DEBUG: CONVERT UID: {instr_uid} - Estado ENO en scl_map[{map_key_eno}] = {en_scl}")
|
||||
|
||||
# print(f"INFO: CONVERT UID: {instr_uid} procesado. SCL: {scl_final.splitlines()[0]}...")
|
||||
return True
|
||||
|
||||
def process_mod(instruction, network_id, scl_map, access_map):
|
||||
"""Traduce Mod (módulo) a SCL, usando temporal si es necesario."""
|
||||
instr_uid = instruction['instruction_uid']
|
||||
instr_type = instruction['type']
|
||||
if instr_type.endswith(SCL_SUFFIX): return False
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False
|
||||
|
||||
print(f"DEBUG: Intentando procesar MOD - UID: {instr_uid} en Red: {network_id}")
|
||||
# print(f"DEBUG: Intentando procesar MOD - UID: {instr_uid} en Red: {network_id}")
|
||||
|
||||
# --- Manejo de EN ---
|
||||
en_input = instruction['inputs'].get('en')
|
||||
en_scl = None
|
||||
if en_input is None:
|
||||
# print(f"DEBUG: Asumiendo EN=TRUE para MOD UID {instr_uid} (pin 'en' no conectado)")
|
||||
en_scl = "TRUE"
|
||||
else:
|
||||
en_scl = get_scl_representation(en_input, network_id, scl_map, access_map)
|
||||
# --- Fin Manejo de EN ---
|
||||
|
||||
en_scl = get_scl_representation(instruction['inputs'].get('en'), network_id, scl_map, access_map)
|
||||
in1_scl = get_scl_representation(instruction['inputs'].get('in1'), network_id, scl_map, access_map)
|
||||
in2_scl = get_scl_representation(instruction['inputs'].get('in2'), network_id, scl_map, access_map)
|
||||
|
||||
if en_scl is None or in1_scl is None or in2_scl is None:
|
||||
print(f"DEBUG: Dependencia no resuelta para MOD UID: {instr_uid} (en={en_scl}, in1={in1_scl}, in2={in2_scl})")
|
||||
# print(f"DEBUG: Dependencia no resuelta para MOD UID: {instr_uid} (en={en_scl}, in1={in1_scl}, in2={in2_scl})")
|
||||
return False
|
||||
|
||||
# Determinar destino (variable o temporal) - Usa pin 'out'
|
||||
target_scl = get_target_scl_name(instruction, 'out', network_id, default_to_temp=True)
|
||||
if target_scl is None:
|
||||
print(f"Error Interno: No se pudo determinar destino para MOD UID {instr_uid}")
|
||||
return False
|
||||
instruction['scl'] = f"// ERROR: No se pudo determinar destino para Mod {instr_uid}"
|
||||
instruction['type'] += "_error"
|
||||
return True
|
||||
|
||||
# Generar SCL
|
||||
# Asegurar paréntesis por si las entradas son expresiones complejas
|
||||
scl_core = f"{target_scl} := ({in1_scl}) MOD ({in2_scl});"
|
||||
op1 = f"({in1_scl})" if ' ' in in1_scl else in1_scl
|
||||
op2 = f"({in2_scl})" if ' ' in in2_scl else in2_scl
|
||||
scl_core = f"{target_scl} := {op1} MOD {op2};"
|
||||
scl_final = scl_core if en_scl == "TRUE" else f"IF {en_scl} THEN\n {scl_core}\nEND_IF;"
|
||||
|
||||
instruction['scl'] = scl_final
|
||||
instruction['type'] = instr_type + SCL_SUFFIX
|
||||
|
||||
# Actualizar scl_map con el resultado (nombre de la variable destino o temporal)
|
||||
map_key = (network_id, instr_uid, 'out')
|
||||
scl_map[map_key] = target_scl
|
||||
# print(f"DEBUG: MOD UID: {instr_uid} - Resultado en scl_map[{map_key}] = {target_scl}")
|
||||
map_key_out = (network_id, instr_uid, 'out')
|
||||
scl_map[map_key_out] = target_scl
|
||||
|
||||
print(f"INFO: MOD UID: {instr_uid} procesado. SCL: {scl_final.splitlines()[0]}...")
|
||||
map_key_eno = (network_id, instr_uid, 'eno')
|
||||
scl_map[map_key_eno] = en_scl # ENO sigue a EN
|
||||
# print(f"DEBUG: MOD UID: {instr_uid} - Estado ENO en scl_map[{map_key_eno}] = {en_scl}")
|
||||
|
||||
# print(f"INFO: MOD UID: {instr_uid} procesado. SCL: {scl_final.splitlines()[0]}...")
|
||||
return True
|
||||
|
||||
|
||||
# --- (process_add, process_move sin cambios significativos respecto a la versión anterior) ---
|
||||
def process_add(instruction, network_id, scl_map, access_map):
|
||||
instr_uid = instruction['instruction_uid']
|
||||
instr_type = instruction['type']
|
||||
# No procesar si ya tiene sufijo _scl o _error
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False
|
||||
|
||||
print(f"DEBUG: Intentando procesar ADD - UID: {instr_uid} en Red: {network_id}")
|
||||
# print(f"DEBUG: Intentando procesar ADD - UID: {instr_uid} en Red: {network_id}")
|
||||
|
||||
# --- Manejo de EN ---
|
||||
en_input = instruction['inputs'].get('en')
|
||||
en_scl = None
|
||||
if en_input is None:
|
||||
# print(f"DEBUG: Asumiendo EN=TRUE para ADD UID {instr_uid} (pin 'en' no conectado)")
|
||||
en_scl = "TRUE"
|
||||
else:
|
||||
en_scl = get_scl_representation(en_input, network_id, scl_map, access_map)
|
||||
# --- Fin Manejo de EN ---
|
||||
|
||||
en_scl = get_scl_representation(instruction['inputs'].get('en'), network_id, scl_map, access_map)
|
||||
in1_scl = get_scl_representation(instruction['inputs'].get('in1'), network_id, scl_map, access_map)
|
||||
in2_scl = get_scl_representation(instruction['inputs'].get('in2'), network_id, scl_map, access_map)
|
||||
# TODO: Manejar más entradas (in3, in4...)
|
||||
|
||||
if en_scl is None or in1_scl is None or in2_scl is None:
|
||||
print(f"DEBUG: Dependencia no resuelta para ADD UID: {instr_uid} (en={en_scl}, in1={in1_scl}, in2={in2_scl})")
|
||||
return False # <<<--- Sale correctamente si hay dependencias
|
||||
|
||||
# Si llegamos aquí, TODAS las dependencias están resueltas
|
||||
print(f"DEBUG: Dependencias RESUELTAS para ADD UID: {instr_uid}")
|
||||
# print(f"DEBUG: Dependencia no resuelta para ADD UID: {instr_uid} (en={en_scl}, in1={in1_scl}, in2={in2_scl})")
|
||||
return False
|
||||
|
||||
target_scl = get_target_scl_name(instruction, 'out', network_id, default_to_temp=True)
|
||||
if target_scl is None:
|
||||
print(f"Error Interno: No se pudo determinar destino para ADD UID {instr_uid}")
|
||||
instruction['scl'] = f"// ERROR: No se pudo determinar destino para Add {instr_uid}"
|
||||
instruction['type'] += "_error"
|
||||
return True # Se procesó (con error)
|
||||
return True
|
||||
|
||||
# Generar SCL Core
|
||||
scl_core = f"{target_scl} := ({in1_scl}) + ({in2_scl});" # Paréntesis por seguridad
|
||||
|
||||
# Añadir IF si es necesario
|
||||
op1 = f"({in1_scl})" if ' ' in in1_scl else in1_scl
|
||||
op2 = f"({in2_scl})" if ' ' in in2_scl else in2_scl
|
||||
scl_core = f"{target_scl} := {op1} + {op2};"
|
||||
scl_final = scl_core if en_scl == "TRUE" else f"IF {en_scl} THEN\n {scl_core}\nEND_IF;"
|
||||
|
||||
# <<<--- ¡ACTUALIZAR EL JSON AQUÍ! --- >>>
|
||||
instruction['scl'] = scl_final
|
||||
instruction['type'] = instr_type + SCL_SUFFIX # Marcar como procesado
|
||||
instruction['type'] = instr_type + SCL_SUFFIX
|
||||
|
||||
# Actualizar el mapa SCL con el resultado de esta instrucción
|
||||
map_key = (network_id, instr_uid, 'out')
|
||||
scl_map[map_key] = target_scl # El valor es el nombre de la variable (temporal o destino)
|
||||
map_key_out = (network_id, instr_uid, 'out')
|
||||
scl_map[map_key_out] = target_scl
|
||||
|
||||
print(f"INFO: ADD UID: {instr_uid} procesado. SCL: {scl_final.splitlines()[0]}...")
|
||||
return True # <<<--- ¡DEVOLVER TRUE PORQUE HUBO CAMBIO! --- >>>
|
||||
map_key_eno = (network_id, instr_uid, 'eno')
|
||||
scl_map[map_key_eno] = en_scl # ENO sigue a EN
|
||||
# print(f"DEBUG: ADD UID: {instr_uid} - Estado ENO en scl_map[{map_key_eno}] = {en_scl}")
|
||||
|
||||
# print(f"INFO: ADD UID: {instr_uid} procesado. SCL: {scl_final.splitlines()[0]}...")
|
||||
return True
|
||||
|
||||
def process_move(instruction, network_id, scl_map, access_map):
|
||||
instr_uid = instruction['instruction_uid']
|
||||
instr_type = instruction['type']
|
||||
# No procesar si ya tiene sufijo _scl o _error
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False
|
||||
|
||||
print(f"DEBUG: Intentando procesar MOVE - UID: {instr_uid} en Red: {network_id}")
|
||||
# print(f"DEBUG: Intentando procesar MOVE - UID: {instr_uid} en Red: {network_id}")
|
||||
|
||||
# --- Manejo de EN ---
|
||||
en_input = instruction['inputs'].get('en')
|
||||
en_scl = None
|
||||
if en_input is None:
|
||||
# print(f"DEBUG: Asumiendo EN=TRUE para MOVE UID {instr_uid} (pin 'en' no conectado)")
|
||||
en_scl = "TRUE"
|
||||
else:
|
||||
en_scl = get_scl_representation(en_input, network_id, scl_map, access_map)
|
||||
# --- Fin Manejo de EN ---
|
||||
|
||||
en_scl = get_scl_representation(instruction['inputs'].get('en'), network_id, scl_map, access_map)
|
||||
in_scl = get_scl_representation(instruction['inputs'].get('in'), network_id, scl_map, access_map)
|
||||
|
||||
if en_scl is None or in_scl is None:
|
||||
print(f"DEBUG: Dependencia no resuelta para MOVE UID: {instr_uid} (en={en_scl}, in={in_scl})")
|
||||
return False # <<<--- Sale correctamente si hay dependencias
|
||||
# print(f"DEBUG: Dependencia no resuelta para MOVE UID: {instr_uid} (en={en_scl}, in={in_scl})")
|
||||
return False
|
||||
|
||||
# Si llegamos aquí, TODAS las dependencias están resueltas
|
||||
print(f"DEBUG: Dependencias RESUELTAS para MOVE UID: {instr_uid}")
|
||||
|
||||
# MOVE asigna, así que el destino NO debe ser temporal por defecto.
|
||||
target_scl = get_target_scl_name(instruction, 'out1', network_id, default_to_temp=False)
|
||||
target_scl = get_target_scl_name(instruction, 'out1', network_id, default_to_temp=False) # No usar temp por defecto
|
||||
|
||||
if target_scl is None:
|
||||
print(f"Advertencia: MOVE UID: {instr_uid} no tiene un destino variable único claro en out1. No se procesa.")
|
||||
# No marcamos como error necesariamente, simplemente no se pudo procesar.
|
||||
return False # <<<--- Devuelve False si no se puede procesar
|
||||
return False
|
||||
|
||||
# Generar SCL Core
|
||||
scl_core = f"{target_scl} := {in_scl};"
|
||||
|
||||
# Añadir IF si es necesario
|
||||
scl_final = scl_core if en_scl == "TRUE" else f"IF {en_scl} THEN\n {scl_core}\nEND_IF;"
|
||||
|
||||
# <<<--- ¡ACTUALIZAR EL JSON AQUÍ! --- >>>
|
||||
instruction['scl'] = scl_final
|
||||
instruction['type'] = instr_type + SCL_SUFFIX # Marcar como procesado
|
||||
instruction['type'] = instr_type + SCL_SUFFIX
|
||||
|
||||
# print(f"INFO: MOVE UID: {instr_uid} procesado. SCL: {scl_final.splitlines()[0]}...")
|
||||
return True
|
||||
|
||||
def process_o(instruction, network_id, scl_map, access_map):
|
||||
"""Traduce O (OR lógico) a una expresión booleana SCL."""
|
||||
instr_uid = instruction['instruction_uid']
|
||||
instr_type = instruction['type']
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False
|
||||
|
||||
# print(f"DEBUG: Intentando procesar O - UID: {instr_uid} en Red: {network_id}")
|
||||
|
||||
# Obtener todas las entradas (in1, in2, in3...)
|
||||
input_pins = [pin for pin in instruction['inputs'] if pin.startswith('in')]
|
||||
if not input_pins:
|
||||
print(f"Error: Instrucción O UID {instr_uid} no tiene pines de entrada 'inX'.")
|
||||
instruction['scl'] = f"// ERROR: O {instr_uid} sin pines de entrada"
|
||||
instruction['type'] += "_error"
|
||||
return True
|
||||
|
||||
scl_parts = []
|
||||
all_resolved = True
|
||||
for pin in sorted(input_pins): # Ordenar para consistencia
|
||||
in_scl = get_scl_representation(instruction['inputs'][pin], network_id, scl_map, access_map)
|
||||
if in_scl is None:
|
||||
all_resolved = False
|
||||
# print(f"DEBUG: Dependencia no resuelta para O UID: {instr_uid} (pin {pin})")
|
||||
break
|
||||
# Poner entre paréntesis si es complejo
|
||||
term = f"({in_scl})" if ' ' in in_scl else in_scl
|
||||
scl_parts.append(term)
|
||||
|
||||
if not all_resolved:
|
||||
return False
|
||||
|
||||
result_scl = " OR ".join(scl_parts) if len(scl_parts) > 1 else (scl_parts[0] if scl_parts else "FALSE")
|
||||
|
||||
map_key_out = (network_id, instr_uid, 'out')
|
||||
scl_map[map_key_out] = result_scl
|
||||
|
||||
instruction['scl'] = f"// Logic O {instr_uid}: {result_scl}"
|
||||
instruction['type'] = instr_type + SCL_SUFFIX
|
||||
return True
|
||||
|
||||
def process_pbox(instruction, network_id, scl_map, access_map):
|
||||
"""Traduce PBox (lectura de bit, posible flanco) a SCL."""
|
||||
instr_uid = instruction['instruction_uid']
|
||||
instr_type = instruction['type']
|
||||
if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False
|
||||
|
||||
# print(f"DEBUG: Intentando procesar PBOX - UID: {instr_uid} en Red: {network_id}")
|
||||
|
||||
# La entrada relevante es 'bit'
|
||||
bit_scl = get_scl_representation(instruction['inputs'].get('bit'), network_id, scl_map, access_map)
|
||||
|
||||
if bit_scl is None:
|
||||
# print(f"DEBUG: Dependencia no resuelta para PBOX UID: {instr_uid} (bit={bit_scl})")
|
||||
return False
|
||||
|
||||
# Lógica específica de PBox:
|
||||
# - Si solo lee un bit, la salida es ese bit.
|
||||
# - Si detecta flanco (P, N), necesita lógica adicional (variable estática)
|
||||
# TODO: Detectar si es detección de flanco (requiere más info del XML o nombre 'FP'/'FN')
|
||||
is_edge_detection = False # Asumir que no por ahora
|
||||
edge_type = '' # 'P' o 'N'
|
||||
|
||||
result_scl = bit_scl # Por defecto, la salida es el bit de entrada
|
||||
|
||||
if is_edge_detection:
|
||||
# Necesita una variable estática (en TEMP o STAT) para guardar el estado anterior
|
||||
static_var_name = f"stat_{network_id}_{instr_uid}_Flank"
|
||||
if edge_type == 'P':
|
||||
result_scl = f"({bit_scl} AND NOT {static_var_name})"
|
||||
# La actualización de la variable estática ocurriría al final del ciclo o red
|
||||
# scl_update = f"{static_var_name} := {bit_scl};"
|
||||
print(f"Advertencia: Detección de Flanco P (PBox {instr_uid}) requiere manejo de variable estática '{static_var_name}' (no implementado completamente).")
|
||||
elif edge_type == 'N':
|
||||
result_scl = f"(NOT {bit_scl} AND {static_var_name})"
|
||||
# scl_update = f"{static_var_name} := {bit_scl};"
|
||||
print(f"Advertencia: Detección de Flanco N (PBox {instr_uid}) requiere manejo de variable estática '{static_var_name}' (no implementado completamente).")
|
||||
else:
|
||||
result_scl = bit_scl # Volver al caso simple si no se reconoce el tipo
|
||||
|
||||
map_key_out = (network_id, instr_uid, 'out')
|
||||
scl_map[map_key_out] = result_scl
|
||||
|
||||
instruction['scl'] = f"// PBox {instr_uid} Output: {result_scl}" + (" (Edge detection logic simplified)" if is_edge_detection else "")
|
||||
instruction['type'] = instr_type + SCL_SUFFIX
|
||||
return True
|
||||
|
||||
# No añadir a scl_map ya que MOVE asigna directamente.
|
||||
print(f"INFO: MOVE UID: {instr_uid} procesado. SCL: {scl_final.splitlines()[0]}...")
|
||||
return True # <<<--- ¡DEVOLVER TRUE PORQUE HUBO CAMBIO! --- >>>
|
||||
|
||||
# --- Bucle Principal de Procesamiento ---
|
||||
|
||||
|
@ -401,45 +501,48 @@ def process_json_to_scl(json_filepath):
|
|||
print(f"Error al cargar o parsear JSON: {e}")
|
||||
return
|
||||
|
||||
# Reconstruir access_map dinámicamente (MEJOR SI VIENE DEL JSON)
|
||||
# Reconstruir access_map dinámicamente
|
||||
network_access_maps = {}
|
||||
print("Creando mapas de acceso por red...")
|
||||
# print("Creando mapas de acceso por red...")
|
||||
for network in data.get('networks', []):
|
||||
net_id = network['id']
|
||||
current_access_map = {}
|
||||
for instr in network.get('logic', []):
|
||||
# Chequear inputs
|
||||
for pin, source in instr.get('inputs', {}).items():
|
||||
sources_to_check = source if isinstance(source, list) else ([source] if isinstance(source, dict) else [])
|
||||
for src in sources_to_check:
|
||||
if isinstance(src, dict) and src.get('uid') and src.get('scope') and src.get('type') in ['variable', 'constant']:
|
||||
current_access_map[src['uid']] = src
|
||||
# Chequear outputs
|
||||
for pin, dest_list in instr.get('outputs', {}).items():
|
||||
if isinstance(dest_list, list):
|
||||
for dest in dest_list:
|
||||
if isinstance(dest, dict) and dest.get('uid') and dest.get('scope') and dest.get('type') in ['variable', 'constant']:
|
||||
current_access_map[dest['uid']] = dest
|
||||
network_access_maps[net_id] = current_access_map
|
||||
# print(f"Red {net_id}: {len(current_access_map)} accesos encontrados (aprox).")
|
||||
|
||||
scl_map = {}
|
||||
max_passes = 20
|
||||
passes = 0
|
||||
|
||||
# Lista de procesadores con nueva prioridad
|
||||
# Lista de procesadores actualizada
|
||||
processors = [
|
||||
process_convert, # Genera valores, posiblemente temporales
|
||||
process_mod, # Genera valores, posiblemente temporales
|
||||
process_eq, # Genera condiciones booleanas
|
||||
# Añadir otros comparadores (Ne, Gt, Lt...) aquí
|
||||
process_contact, # Combina condiciones booleanas (actualiza RLO)
|
||||
process_move, # Asigna valores (usa RLO de Contact/Eq)
|
||||
process_add, # Calcula (usa RLO de Contact/Eq)
|
||||
process_coil, # Asigna RLO final
|
||||
# Añadir process_pbox, process_O, etc.
|
||||
# Instrucciones que generan valores base o condiciones
|
||||
process_convert,
|
||||
process_mod,
|
||||
process_eq,
|
||||
process_pbox, # Procesa lectura de bit
|
||||
# Instrucciones que combinan lógica booleana
|
||||
process_contact,
|
||||
process_o, # Procesa OR
|
||||
# Instrucciones que usan resultados y condiciones
|
||||
process_add,
|
||||
process_move,
|
||||
process_coil,
|
||||
# Añadir más procesadores aquí (Sub, Mul, Div, GT, LT, temporizadores, contadores...)
|
||||
]
|
||||
|
||||
processor_map = {func.__name__.split('_')[1].capitalize(): func for func in processors}
|
||||
|
||||
print("\n--- Iniciando Bucle de Procesamiento Iterativo ---")
|
||||
while passes < max_passes:
|
||||
passes += 1
|
||||
|
@ -451,25 +554,25 @@ def process_json_to_scl(json_filepath):
|
|||
access_map = network_access_maps.get(network_id, {})
|
||||
|
||||
for instruction in network.get('logic', []):
|
||||
# Saltar si ya está procesado
|
||||
if instruction['type'].endswith(SCL_SUFFIX) or "_error" in instruction['type']:
|
||||
instr_type_original = instruction['type']
|
||||
if instr_type_original.endswith(SCL_SUFFIX) or "_error" in instr_type_original:
|
||||
continue
|
||||
|
||||
# Intentar aplicar cada procesador
|
||||
for processor_func in processors:
|
||||
if instruction['type'] == processor_func.__name__.split('_')[1].capitalize(): # Compara tipo con nombre de función
|
||||
processor_func = processor_map.get(instr_type_original)
|
||||
if processor_func:
|
||||
try:
|
||||
changed = processor_func(instruction, network_id, scl_map, access_map)
|
||||
if changed:
|
||||
made_change_in_pass = True
|
||||
break # Pasar a la siguiente instrucción
|
||||
except Exception as e:
|
||||
print(f"ERROR al ejecutar {processor_func.__name__} en UID {instruction.get('instruction_uid')} Red {network_id}: {e}")
|
||||
traceback.print_exc()
|
||||
instruction['scl'] = f"// ERROR during processing: {e}"
|
||||
instruction['type'] += "_error" # Marcar como error
|
||||
made_change_in_pass = True # Hubo un cambio (a estado de error)
|
||||
break # No intentar otros procesadores si hubo error
|
||||
instruction['type'] += "_error"
|
||||
made_change_in_pass = True
|
||||
# else: # Comentado para reducir ruido
|
||||
# print(f"DEBUG: No hay procesador para el tipo: {instr_type_original}")
|
||||
|
||||
|
||||
if not made_change_in_pass:
|
||||
print(f"\n--- No se hicieron cambios en el pase {passes}. Proceso completado. ---")
|
||||
|
@ -488,5 +591,6 @@ def process_json_to_scl(json_filepath):
|
|||
|
||||
# --- Ejecución ---
|
||||
if __name__ == "__main__":
|
||||
# Asegúrate de usar el JSON generado por el script anterior (el que tiene comentarios y eno_logic si aplica)
|
||||
input_json_file = 'BlenderRun_ProdTime_simplified.json'
|
||||
process_json_to_scl(input_json_file)
|
Loading…
Reference in New Issue