Con script para la generacion del SCL
This commit is contained in:
parent
f090305574
commit
94163baee0
|
@ -0,0 +1,112 @@
|
||||||
|
// Block Name (Original): BlenderRun_ProdTime
|
||||||
|
// Block Number: 2040
|
||||||
|
// Original Language: LAD
|
||||||
|
|
||||||
|
FUNCTION_BLOCK "BlenderRun_ProdTime"
|
||||||
|
{ S7_Optimized_Access := 'TRUE' }
|
||||||
|
VERSION : 0.1
|
||||||
|
|
||||||
|
VAR_INPUT
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
VAR_OUTPUT
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
VAR_IN_OUT
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
VAR_TEMP
|
||||||
|
m1MinONS : Bool;
|
||||||
|
m1HourONS : Bool;
|
||||||
|
Buffer : Bool;
|
||||||
|
mRunMin : Bool;
|
||||||
|
mRunHr : Bool;
|
||||||
|
I_DIRunning_sec : DInt;
|
||||||
|
I_DIRunning_min : DInt;
|
||||||
|
MOD60 : DInt;
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
// Network 1: Seconds
|
||||||
|
|
||||||
|
IF "Procedure_Variables"."Blender_Run"."Running" AND "CLK_1.0S" THEN
|
||||||
|
"Blender_Variables_Pers"."gSLIM_Sec" := "Blender_Variables_Pers"."gSLIM_Sec" + 1;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 2: Reset Hours
|
||||||
|
|
||||||
|
IF "SLIM_Variables"."ResetHour" THEN
|
||||||
|
"Blender_Variables_Pers"."gSLIM_Sec" := 0;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 3: Seconds Counter
|
||||||
|
|
||||||
|
IF "gBlenderBlending" AND "CLK_1.0S" THEN
|
||||||
|
"Blender_Variables_Pers"."gProdSec" := "Blender_Variables_Pers"."gProdSec" + 1;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 4: Minute
|
||||||
|
|
||||||
|
"m1MinONS" := "Blender_Variables_Pers"."gProdSec" = 60;
|
||||||
|
|
||||||
|
// Network 5: Minute Counter
|
||||||
|
|
||||||
|
IF "m1MinONS" THEN
|
||||||
|
"Blender_Variables_Pers"."gProdSec" := 0;
|
||||||
|
END_IF;
|
||||||
|
"Blender_Variables_Pers"."gProdMin" := "Blender_Variables_Pers"."gProdMin" + 1;
|
||||||
|
|
||||||
|
// Network 6: Hour
|
||||||
|
|
||||||
|
"m1HourONS" := "Blender_Variables_Pers"."gProdMin" = 60;
|
||||||
|
|
||||||
|
// Network 7: Hour Counter
|
||||||
|
|
||||||
|
IF "m1HourONS" THEN
|
||||||
|
"Blender_Variables_Pers"."gProdMin" := 0;
|
||||||
|
END_IF;
|
||||||
|
"Blender_Variables_Pers"."gProdHour" := "Blender_Variables_Pers"."gProdHour" + 1;
|
||||||
|
"Blender_Variables_Pers"."gBlendingMaintHour" := "Blender_Variables_Pers"."gBlendingMaintHour" + 1;
|
||||||
|
|
||||||
|
// Network 8: Counter reset
|
||||||
|
|
||||||
|
IF "gBlenderCIPMode" OR "gBlenderRinseMode" THEN
|
||||||
|
"Blender_Variables_Pers"."gProdSec" := 0;
|
||||||
|
END_IF;
|
||||||
|
"Blender_Variables_Pers"."gProdMin" := 0;
|
||||||
|
"Blender_Variables_Pers"."gProdHour" := 0;
|
||||||
|
|
||||||
|
// Network 9: Running Seconds
|
||||||
|
|
||||||
|
IF "Procedure_Variables"."Blender_Run"."Running" AND "CLK_1.0S" THEN
|
||||||
|
"Blender_Variables_Pers"."gRunningSeconds" := "Blender_Variables_Pers"."gRunningSeconds" + 1;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 10: Running Minutes
|
||||||
|
|
||||||
|
"I_DIRunning_sec" := "Blender_Variables_Pers"."gRunningSeconds";
|
||||||
|
"MOD60" := "I_DIRunning_sec" MOD DINT#60;
|
||||||
|
IF ("MOD60" = DINT#0 AND "Procedure_Variables"."Blender_Run"."Running") AND "CLK_1.0S" THEN
|
||||||
|
"Blender_Variables_Pers"."gRunningMinutes" := "Blender_Variables_Pers"."gRunningMinutes" + 1;
|
||||||
|
END_IF;
|
||||||
|
// Edge detection PBox 41 -> P_TRIG_FUNC(CLK := (("MOD60" = DINT#0 AND "Procedure_Variables"."Blender_Run"."Running") AND "CLK_1.0S"), M := "M19012") (CLK source inferred)
|
||||||
|
"mRunMin" := P_TRIG_FUNC(CLK := (("MOD60" = DINT#0 AND "Procedure_Variables"."Blender_Run"."Running") AND "CLK_1.0S"), M := "M19012");
|
||||||
|
|
||||||
|
// Network 11: Running Hours for Maintenance
|
||||||
|
|
||||||
|
IF "mRunMin" THEN
|
||||||
|
"I_DIRunning_min" := "Blender_Variables_Pers"."gRunningMinutes";
|
||||||
|
END_IF;
|
||||||
|
IF "mRunMin" THEN
|
||||||
|
"MOD60" := "I_DIRunning_min" MOD DINT#60;
|
||||||
|
END_IF;
|
||||||
|
IF "MOD60" = DINT#0 THEN
|
||||||
|
"Blender_Variables_Pers"."gRunningMaintHour" := "Blender_Variables_Pers"."gRunningMaintHour" + 1;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Network 12: Running Hours for Maintenance
|
||||||
|
|
||||||
|
"HMI_Variables_Status"."System"."BlendingMaintHour" := "Blender_Variables_Pers"."gRunningMaintHour";
|
||||||
|
|
||||||
|
END_FUNCTION_BLOCK
|
|
@ -584,7 +584,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"instruction_uid": "30",
|
"instruction_uid": "30",
|
||||||
"type": "Contact",
|
"type": "Contact_scl",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"operand": {
|
"operand": {
|
||||||
"uid": "22",
|
"uid": "22",
|
||||||
|
@ -593,11 +593,12 @@
|
||||||
"name": "\"gBlenderRinseMode\""
|
"name": "\"gBlenderRinseMode\""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {}
|
"outputs": {},
|
||||||
|
"scl": "// RLO updated by Contact 30: \"gBlenderRinseMode\""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"instruction_uid": "31",
|
"instruction_uid": "31",
|
||||||
"type": "O",
|
"type": "O_scl",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"in1": {
|
"in1": {
|
||||||
"type": "connection",
|
"type": "connection",
|
||||||
|
@ -612,11 +613,12 @@
|
||||||
"source_pin": "out"
|
"source_pin": "out"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": {}
|
"outputs": {},
|
||||||
|
"scl": "// Logic O 31: \"gBlenderCIPMode\" OR \"gBlenderRinseMode\""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"instruction_uid": "32",
|
"instruction_uid": "32",
|
||||||
"type": "Move",
|
"type": "Move_scl",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"in": {
|
"in": {
|
||||||
"uid": "23",
|
"uid": "23",
|
||||||
|
@ -641,7 +643,8 @@
|
||||||
"name": "\"Blender_Variables_Pers\".\"gProdSec\""
|
"name": "\"Blender_Variables_Pers\".\"gProdSec\""
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"scl": "IF \"gBlenderCIPMode\" OR \"gBlenderRinseMode\" THEN\n \"Blender_Variables_Pers\".\"gProdSec\" := 0;\nEND_IF;"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"instruction_uid": "33",
|
"instruction_uid": "33",
|
||||||
|
|
259
json_to_scl.py
259
json_to_scl.py
|
@ -1,259 +0,0 @@
|
||||||
import json
|
|
||||||
import os
|
|
||||||
|
|
||||||
# --- Funciones Procesadoras por Tipo de Instrucción ---
|
|
||||||
# Cada función recibe el diccionario de la instrucción del JSON.
|
|
||||||
# Por ahora, solo imprimen información.
|
|
||||||
|
|
||||||
def process_contact(instruction):
|
|
||||||
"""Procesa una instrucción 'Contact'."""
|
|
||||||
print(f" [Contact] UID: {instruction['instruction_uid']}")
|
|
||||||
operand = instruction['inputs'].get('operand', {})
|
|
||||||
print(f" - Checks: {operand.get('scope', '?')} UID: {operand.get('uid', '?')}") # Adaptar si 'unknown_access' se resuelve
|
|
||||||
in_source = instruction['inputs'].get('in', {})
|
|
||||||
if in_source.get('type') == 'powerrail':
|
|
||||||
print(" - Input: Power Rail")
|
|
||||||
elif in_source.get('type') == 'connection':
|
|
||||||
print(f" - Input: From instruction {in_source.get('source_instruction_uid', '?')} (Pin: {in_source.get('source_pin', '?')})")
|
|
||||||
else:
|
|
||||||
print(f" - Input: {in_source}")
|
|
||||||
|
|
||||||
def process_coil(instruction):
|
|
||||||
"""Procesa una instrucción 'Coil'."""
|
|
||||||
print(f" [Coil] UID: {instruction['instruction_uid']}")
|
|
||||||
operand = instruction['inputs'].get('operand', {})
|
|
||||||
print(f" - Assigns to: {operand.get('scope', '?')} UID: {operand.get('uid', '?')}")
|
|
||||||
in_source = instruction['inputs'].get('in', {})
|
|
||||||
if in_source.get('type') == 'connection':
|
|
||||||
print(f" - Condition from: instruction {in_source.get('source_instruction_uid', '?')} (Pin: {in_source.get('source_pin', '?')})")
|
|
||||||
else:
|
|
||||||
print(f" - Condition: {in_source}")
|
|
||||||
|
|
||||||
def process_add(instruction):
|
|
||||||
"""Procesa una instrucción 'Add'."""
|
|
||||||
print(f" [Add] UID: {instruction['instruction_uid']}")
|
|
||||||
in1 = instruction['inputs'].get('in1', {})
|
|
||||||
in2 = instruction['inputs'].get('in2', {})
|
|
||||||
en = instruction['inputs'].get('en', {})
|
|
||||||
outputs = instruction['outputs'].get('out', [])
|
|
||||||
|
|
||||||
print(f" - Input 1: {in1.get('scope', '?')} UID: {in1.get('uid', '?')}")
|
|
||||||
print(f" - Input 2: {in2.get('scope', '?')} UID: {in2.get('uid', '?')}")
|
|
||||||
if en.get('type') == 'powerrail':
|
|
||||||
print(" - Enabled by: Power Rail (Direct)") # Si Add pudiera conectarse directo
|
|
||||||
elif en.get('type') == 'connection':
|
|
||||||
print(f" - Enabled by: instruction {en.get('source_instruction_uid', '?')} (Pin: {en.get('source_pin', '?')})")
|
|
||||||
elif en: # Si 'en' no está presente o no es conexión/powerrail (poco común en Add)
|
|
||||||
print(f" - Enabled by: {en}")
|
|
||||||
else:
|
|
||||||
print(" - Enabled by: Power Rail (Implícito, sin EN)") # Asumir si no hay pin 'en'
|
|
||||||
|
|
||||||
for output in outputs:
|
|
||||||
print(f" - Output to: {output.get('scope', '?')} UID: {output.get('uid', '?')}")
|
|
||||||
|
|
||||||
def process_move(instruction):
|
|
||||||
"""Procesa una instrucción 'Move'."""
|
|
||||||
print(f" [Move] UID: {instruction['instruction_uid']}")
|
|
||||||
in_val = instruction['inputs'].get('in', {})
|
|
||||||
en = instruction['inputs'].get('en', {})
|
|
||||||
outputs = instruction['outputs'].get('out1', []) # Asumiendo pin 'out1' para Move
|
|
||||||
|
|
||||||
print(f" - Input Value: {in_val.get('scope', '?')} UID: {in_val.get('uid', '?')}")
|
|
||||||
if en.get('type') == 'powerrail':
|
|
||||||
print(" - Enabled by: Power Rail")
|
|
||||||
elif en.get('type') == 'connection':
|
|
||||||
print(f" - Enabled by: instruction {en.get('source_instruction_uid', '?')} (Pin: {en.get('source_pin', '?')})")
|
|
||||||
elif en:
|
|
||||||
print(f" - Enabled by: {en}")
|
|
||||||
else:
|
|
||||||
print(" - Enabled by: Power Rail (Implícito, sin EN)")
|
|
||||||
|
|
||||||
for output in outputs:
|
|
||||||
print(f" - Output to: {output.get('scope', '?')} UID: {output.get('uid', '?')}")
|
|
||||||
|
|
||||||
def process_eq(instruction):
|
|
||||||
"""Procesa una instrucción 'Eq' (Equal)."""
|
|
||||||
print(f" [Compare EQ] UID: {instruction['instruction_uid']}")
|
|
||||||
in1 = instruction['inputs'].get('in1', {})
|
|
||||||
in2 = instruction['inputs'].get('in2', {})
|
|
||||||
pre = instruction['inputs'].get('pre', {}) # Condición previa (usualmente PowerRail o conexión)
|
|
||||||
|
|
||||||
print(f" - Input 1: {in1.get('scope', '?')} UID: {in1.get('uid', '?')}")
|
|
||||||
print(f" - Input 2: {in2.get('scope', '?')} UID: {in2.get('uid', '?')}")
|
|
||||||
if pre.get('type') == 'powerrail':
|
|
||||||
print(" - Pre-condition: Power Rail")
|
|
||||||
elif pre.get('type') == 'connection':
|
|
||||||
print(f" - Pre-condition: instruction {pre.get('source_instruction_uid', '?')} (Pin: {pre.get('source_pin', '?')})")
|
|
||||||
else:
|
|
||||||
print(f" - Pre-condition: {pre}")
|
|
||||||
|
|
||||||
# La salida 'out' de Eq usualmente va a otra instrucción (Contact, Coil, Enable pin)
|
|
||||||
# Lo veremos cuando procesemos la instrucción destino
|
|
||||||
|
|
||||||
def process_mod(instruction):
|
|
||||||
"""Procesa una instrucción 'Mod' (Modulo)."""
|
|
||||||
print(f" [Modulo] UID: {instruction['instruction_uid']}")
|
|
||||||
in1 = instruction['inputs'].get('in1', {})
|
|
||||||
in2 = instruction['inputs'].get('in2', {})
|
|
||||||
en = instruction['inputs'].get('en', {})
|
|
||||||
outputs = instruction['outputs'].get('out', [])
|
|
||||||
eno_outputs = instruction['outputs'].get('eno', []) # Mod también puede tener ENO
|
|
||||||
|
|
||||||
print(f" - Input 1 (Dividend): {in1.get('scope', '?')} UID: {in1.get('uid', '?')}")
|
|
||||||
print(f" - Input 2 (Divisor): {in2.get('scope', '?')} UID: {in2.get('uid', '?')}")
|
|
||||||
if en.get('type') == 'powerrail':
|
|
||||||
print(" - Enabled by: Power Rail")
|
|
||||||
elif en.get('type') == 'connection':
|
|
||||||
print(f" - Enabled by: instruction {en.get('source_instruction_uid', '?')} (Pin: {en.get('source_pin', '?')})")
|
|
||||||
elif en:
|
|
||||||
print(f" - Enabled by: {en}")
|
|
||||||
else:
|
|
||||||
print(" - Enabled by: Power Rail (Implícito, sin EN)")
|
|
||||||
|
|
||||||
for output in outputs:
|
|
||||||
print(f" - Output (Remainder) to: {output.get('scope', '?')} UID: {output.get('uid', '?')}")
|
|
||||||
# ENO normalmente se conecta a pines 'en' o 'pre' de la siguiente instrucción
|
|
||||||
|
|
||||||
def process_convert(instruction):
|
|
||||||
"""Procesa una instrucción 'Convert'."""
|
|
||||||
print(f" [Convert] UID: {instruction['instruction_uid']}")
|
|
||||||
in_val = instruction['inputs'].get('in', {})
|
|
||||||
en = instruction['inputs'].get('en', {})
|
|
||||||
outputs = instruction['outputs'].get('out', [])
|
|
||||||
# Podríamos extraer los tipos de datos de TemplateValue si estuvieran en el JSON
|
|
||||||
# template_vals = instruction.get('template_values', {})
|
|
||||||
|
|
||||||
print(f" - Input Value: {in_val.get('scope', '?')} UID: {in_val.get('uid', '?')}")
|
|
||||||
if en.get('type') == 'powerrail':
|
|
||||||
print(" - Enabled by: Power Rail")
|
|
||||||
elif en.get('type') == 'connection':
|
|
||||||
print(f" - Enabled by: instruction {en.get('source_instruction_uid', '?')} (Pin: {en.get('source_pin', '?')})")
|
|
||||||
elif en:
|
|
||||||
print(f" - Enabled by: {en}")
|
|
||||||
else:
|
|
||||||
print(" - Enabled by: Power Rail (Implícito, sin EN)")
|
|
||||||
|
|
||||||
for output in outputs:
|
|
||||||
print(f" - Output to: {output.get('scope', '?')} UID: {output.get('uid', '?')}")
|
|
||||||
# print(f" (Expected DestType: {template_vals.get('DestType', '?')})")
|
|
||||||
|
|
||||||
|
|
||||||
def process_or(instruction):
|
|
||||||
"""Procesa una instrucción 'O' (OR)."""
|
|
||||||
# Las instrucciones 'O' en LAD suelen representar la unión de ramas paralelas.
|
|
||||||
# Este parser simple solo muestra las entradas directas. Reconstruir la lógica OR completa requeriría más análisis.
|
|
||||||
print(f" [OR Logic] UID: {instruction['instruction_uid']}")
|
|
||||||
in1 = instruction['inputs'].get('in1', {})
|
|
||||||
in2 = instruction['inputs'].get('in2', {})
|
|
||||||
# Podría haber in3, in4... si Cardinality > 2
|
|
||||||
|
|
||||||
if in1.get('type') == 'connection':
|
|
||||||
print(f" - Input 1 from: instruction {in1.get('source_instruction_uid', '?')} (Pin: {in1.get('source_pin', '?')})")
|
|
||||||
else:
|
|
||||||
print(f" - Input 1: {in1}")
|
|
||||||
if in2.get('type') == 'connection':
|
|
||||||
print(f" - Input 2 from: instruction {in2.get('source_instruction_uid', '?')} (Pin: {in2.get('source_pin', '?')})")
|
|
||||||
else:
|
|
||||||
print(f" - Input 2: {in2}")
|
|
||||||
|
|
||||||
# La salida 'out' de O usualmente va a otra instrucción (Contact, Coil, Enable pin)
|
|
||||||
|
|
||||||
def process_pbox(instruction):
|
|
||||||
"""Procesa una instrucción 'PBox'."""
|
|
||||||
# PBox puede ser muchas cosas (Rising Edge, Falling Edge, Set, Reset, etc.)
|
|
||||||
# Necesitaríamos más información o convenciones para saber qué hace exactamente.
|
|
||||||
print(f" [PBox - Special?] UID: {instruction['instruction_uid']}")
|
|
||||||
inputs = instruction.get('inputs', {})
|
|
||||||
outputs = instruction.get('outputs', {})
|
|
||||||
for pin, source in inputs.items():
|
|
||||||
if source.get('type') == 'connection':
|
|
||||||
print(f" - Input Pin '{pin}' from: instruction {source.get('source_instruction_uid', '?')} (Pin: {source.get('source_pin', '?')})")
|
|
||||||
elif source.get('type') == 'powerrail':
|
|
||||||
print(f" - Input Pin '{pin}': Power Rail")
|
|
||||||
else:
|
|
||||||
print(f" - Input Pin '{pin}': {source.get('scope', '?')} UID: {source.get('uid', '?')}")
|
|
||||||
|
|
||||||
# La salida de PBox la veremos en el destino
|
|
||||||
|
|
||||||
def process_unknown(instruction):
|
|
||||||
"""Procesa una instrucción de tipo desconocido."""
|
|
||||||
print(f" [Unknown Type: {instruction.get('type', 'N/A')}] UID: {instruction['instruction_uid']}")
|
|
||||||
print(f" - Inputs: {instruction.get('inputs')}")
|
|
||||||
print(f" - Outputs: {instruction.get('outputs')}")
|
|
||||||
|
|
||||||
# --- Mapeo de Tipos a Funciones ---
|
|
||||||
instruction_handlers = {
|
|
||||||
"Contact": process_contact,
|
|
||||||
"Coil": process_coil,
|
|
||||||
"Add": process_add,
|
|
||||||
"Move": process_move,
|
|
||||||
"Eq": process_eq,
|
|
||||||
"Mod": process_mod,
|
|
||||||
"Convert": process_convert,
|
|
||||||
"O": process_or, # 'O' representa un OR lógico en FlgNet
|
|
||||||
"PBox": process_pbox, # Tipo genérico, tratar como desconocido por ahora
|
|
||||||
# Añade más tipos aquí si aparecen
|
|
||||||
}
|
|
||||||
|
|
||||||
# --- Función Principal de Procesamiento ---
|
|
||||||
|
|
||||||
def process_logic_data(data):
|
|
||||||
"""Itera sobre el JSON cargado y procesa cada instrucción."""
|
|
||||||
print("=" * 40)
|
|
||||||
print(f"Processing Block: {data.get('block_name')} ({data.get('block_number')})")
|
|
||||||
print(f"Language: {data.get('language')}")
|
|
||||||
print("-" * 40)
|
|
||||||
|
|
||||||
# Opcional: Imprimir interfaz
|
|
||||||
print("Interface:")
|
|
||||||
for section, members in data.get('interface', {}).items():
|
|
||||||
if members:
|
|
||||||
print(f" {section}:")
|
|
||||||
for member in members:
|
|
||||||
print(f" - {member['name']} ({member['datatype']})")
|
|
||||||
print("-" * 40)
|
|
||||||
|
|
||||||
# Procesar Redes
|
|
||||||
print("Networks:")
|
|
||||||
for network in data.get('networks', []):
|
|
||||||
print(f"\nNetwork ID: {network.get('id')} - Title: '{network.get('title', '')}'")
|
|
||||||
if 'error' in network:
|
|
||||||
print(f" ERROR en esta red: {network['error']}")
|
|
||||||
continue
|
|
||||||
if not network.get('logic'):
|
|
||||||
print(" (No logic instructions found in JSON for this network)")
|
|
||||||
continue
|
|
||||||
|
|
||||||
for instruction in network.get('logic', []):
|
|
||||||
instruction_type = instruction.get('type')
|
|
||||||
# Obtener el handler adecuado, o el default si no se encuentra
|
|
||||||
handler = instruction_handlers.get(instruction_type, process_unknown)
|
|
||||||
try:
|
|
||||||
handler(instruction)
|
|
||||||
except Exception as e:
|
|
||||||
print(f" ERROR procesando instrucción UID {instruction.get('instruction_uid')} (Tipo: {instruction_type}): {e}")
|
|
||||||
# Considerar imprimir más detalles del error o de la instrucción
|
|
||||||
# import traceback
|
|
||||||
# traceback.print_exc()
|
|
||||||
|
|
||||||
|
|
||||||
# --- Ejecución ---
|
|
||||||
if __name__ == "__main__":
|
|
||||||
json_file = 'BlenderRun_ProdTime_simplified.json' # El archivo generado por el script anterior
|
|
||||||
|
|
||||||
if not os.path.exists(json_file):
|
|
||||||
print(f"Error: Archivo JSON no encontrado en {json_file}")
|
|
||||||
print("Asegúrate de haber ejecutado el script de conversión XML a JSON primero.")
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
with open(json_file, 'r', encoding='utf-8') as f:
|
|
||||||
logic_data = json.load(f)
|
|
||||||
|
|
||||||
process_logic_data(logic_data)
|
|
||||||
|
|
||||||
except json.JSONDecodeError as e:
|
|
||||||
print(f"Error: El archivo JSON ({json_file}) no es válido: {e}")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Ocurrió un error inesperado al cargar o procesar el JSON: {e}")
|
|
||||||
import traceback
|
|
||||||
traceback.print_exc()
|
|
|
@ -130,32 +130,40 @@ def process_contact(instruction, network_id, scl_map, access_map):
|
||||||
|
|
||||||
# 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)
|
# --- INICIO CORRECCIÓN ---
|
||||||
|
in_input = instruction['inputs'].get('in')
|
||||||
|
in_rlo_scl = None
|
||||||
|
if in_input is None:
|
||||||
|
# Si no hay pin 'in' conectado explícitamente, asumir TRUE (conectado a powerrail/riel vertical)
|
||||||
|
# print(f"DEBUG: Asumiendo IN=TRUE para CONTACT UID {instr_uid} (pin 'in' no conectado)")
|
||||||
|
in_rlo_scl = "TRUE"
|
||||||
|
else:
|
||||||
|
# Si hay pin 'in', intentar resolverlo
|
||||||
|
in_rlo_scl = get_scl_representation(in_input, network_id, scl_map, access_map)
|
||||||
|
# --- FIN CORRECCIÓN ---
|
||||||
|
|
||||||
operand_scl = get_scl_representation(instruction['inputs'].get('operand'), 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:
|
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
|
return False
|
||||||
|
|
||||||
|
# ... (resto de process_contact sin cambios: construir RLO, actualizar scl_map y JSON, retornar True) ...
|
||||||
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('"')):
|
||||||
if not (term.startswith('(') and term.endswith(')')):
|
if not (term.startswith('(') and term.endswith(')')):
|
||||||
term = f"({term})"
|
term = f"({term})"
|
||||||
|
|
||||||
|
|
||||||
new_rlo_scl = ""
|
new_rlo_scl = ""
|
||||||
if in_rlo_scl == "TRUE":
|
if in_rlo_scl == "TRUE":
|
||||||
new_rlo_scl = term
|
new_rlo_scl = term
|
||||||
else:
|
else:
|
||||||
# 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:
|
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})"
|
in_rlo_processed = f"({in_rlo_scl})"
|
||||||
else:
|
else:
|
||||||
in_rlo_processed = in_rlo_scl
|
in_rlo_processed = in_rlo_scl
|
||||||
new_rlo_scl = f"{in_rlo_processed} AND {term}"
|
new_rlo_scl = f"{in_rlo_processed} AND {term}"
|
||||||
|
|
||||||
|
|
||||||
map_key = (network_id, instr_uid, 'out')
|
map_key = (network_id, instr_uid, 'out')
|
||||||
scl_map[map_key] = new_rlo_scl
|
scl_map[map_key] = new_rlo_scl
|
||||||
|
|
||||||
|
@ -266,7 +274,11 @@ def process_convert(instruction, network_id, scl_map, access_map):
|
||||||
# TODO: Añadir lógica de conversión explícita si se extraen tipos de TemplateValue
|
# TODO: Añadir lógica de conversión explícita si se extraen tipos de TemplateValue
|
||||||
|
|
||||||
scl_core = f"{target_scl} := {conversion_expr};"
|
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;"
|
if en_scl != "TRUE":
|
||||||
|
scl_final = f"IF {en_scl} THEN\n {scl_core}\nEND_IF;"
|
||||||
|
else:
|
||||||
|
# Si en_scl ES "TRUE", no se necesita IF
|
||||||
|
scl_final = scl_core
|
||||||
|
|
||||||
instruction['scl'] = scl_final
|
instruction['scl'] = scl_final
|
||||||
instruction['type'] = instr_type + SCL_SUFFIX
|
instruction['type'] = instr_type + SCL_SUFFIX
|
||||||
|
@ -316,7 +328,11 @@ def process_mod(instruction, network_id, scl_map, access_map):
|
||||||
op1 = f"({in1_scl})" if ' ' in in1_scl else in1_scl
|
op1 = f"({in1_scl})" if ' ' in in1_scl else in1_scl
|
||||||
op2 = f"({in2_scl})" if ' ' in in2_scl else in2_scl
|
op2 = f"({in2_scl})" if ' ' in in2_scl else in2_scl
|
||||||
scl_core = f"{target_scl} := {op1} MOD {op2};"
|
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;"
|
if en_scl != "TRUE":
|
||||||
|
scl_final = f"IF {en_scl} THEN\n {scl_core}\nEND_IF;"
|
||||||
|
else:
|
||||||
|
# Si en_scl ES "TRUE", no se necesita IF
|
||||||
|
scl_final = scl_core
|
||||||
|
|
||||||
instruction['scl'] = scl_final
|
instruction['scl'] = scl_final
|
||||||
instruction['type'] = instr_type + SCL_SUFFIX
|
instruction['type'] = instr_type + SCL_SUFFIX
|
||||||
|
@ -365,7 +381,11 @@ def process_add(instruction, network_id, scl_map, access_map):
|
||||||
op1 = f"({in1_scl})" if ' ' in in1_scl else in1_scl
|
op1 = f"({in1_scl})" if ' ' in in1_scl else in1_scl
|
||||||
op2 = f"({in2_scl})" if ' ' in in2_scl else in2_scl
|
op2 = f"({in2_scl})" if ' ' in in2_scl else in2_scl
|
||||||
scl_core = f"{target_scl} := {op1} + {op2};"
|
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;"
|
if en_scl != "TRUE":
|
||||||
|
scl_final = f"IF {en_scl} THEN\n {scl_core}\nEND_IF;"
|
||||||
|
else:
|
||||||
|
# Si en_scl ES "TRUE", no se necesita IF
|
||||||
|
scl_final = scl_core
|
||||||
|
|
||||||
instruction['scl'] = scl_final
|
instruction['scl'] = scl_final
|
||||||
instruction['type'] = instr_type + SCL_SUFFIX
|
instruction['type'] = instr_type + SCL_SUFFIX
|
||||||
|
@ -410,7 +430,11 @@ def process_move(instruction, network_id, scl_map, access_map):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
scl_core = f"{target_scl} := {in_scl};"
|
scl_core = f"{target_scl} := {in_scl};"
|
||||||
scl_final = scl_core if en_scl == "TRUE" else f"IF {en_scl} THEN\n {scl_core}\nEND_IF;"
|
if en_scl != "TRUE":
|
||||||
|
scl_final = f"IF {en_scl} THEN\n {scl_core}\nEND_IF;"
|
||||||
|
else:
|
||||||
|
# Si en_scl ES "TRUE", no se necesita IF
|
||||||
|
scl_final = scl_core
|
||||||
|
|
||||||
instruction['scl'] = scl_final
|
instruction['scl'] = scl_final
|
||||||
instruction['type'] = instr_type + SCL_SUFFIX
|
instruction['type'] = instr_type + SCL_SUFFIX
|
|
@ -0,0 +1,202 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
# --- Helper Functions ---
|
||||||
|
|
||||||
|
def format_variable_name(name):
|
||||||
|
"""Limpia el nombre de la variable quitando comillas y espacios."""
|
||||||
|
if not name:
|
||||||
|
return "_INVALID_NAME_"
|
||||||
|
# Quita comillas dobles iniciales/finales
|
||||||
|
name = name.strip('"')
|
||||||
|
# Reemplaza comillas dobles internas y puntos por guión bajo
|
||||||
|
name = name.replace('"."', '_').replace('.', '_')
|
||||||
|
# Quita comillas restantes (si las hubiera)
|
||||||
|
name = name.replace('"', '')
|
||||||
|
# Asegurarse de que no empiece con número (aunque raro con comillas iniciales)
|
||||||
|
if name and name[0].isdigit():
|
||||||
|
name = "_" + name
|
||||||
|
return name
|
||||||
|
|
||||||
|
def generate_scl(processed_json_filepath, output_scl_filepath):
|
||||||
|
"""Genera un archivo SCL a partir del JSON procesado."""
|
||||||
|
|
||||||
|
if not os.path.exists(processed_json_filepath):
|
||||||
|
print(f"Error: Archivo JSON procesado no encontrado en '{processed_json_filepath}'")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"Cargando JSON procesado desde: {processed_json_filepath}")
|
||||||
|
try:
|
||||||
|
with open(processed_json_filepath, 'r', encoding='utf-8') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error al cargar o parsear JSON: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# --- Extracción de Información del Bloque ---
|
||||||
|
block_name = data.get('block_name', 'UnknownBlock')
|
||||||
|
block_number = data.get('block_number')
|
||||||
|
block_lang = data.get('language', 'LAD') # Lenguaje original
|
||||||
|
block_comment = data.get('block_comment', '')
|
||||||
|
|
||||||
|
# Limpiar nombre del bloque para usarlo en SCL
|
||||||
|
scl_block_name = format_variable_name(block_name)
|
||||||
|
print(f"Generando SCL para el bloque: {scl_block_name} (Original: {block_name})")
|
||||||
|
|
||||||
|
# --- Identificación de Variables Temporales y Estáticas ---
|
||||||
|
temp_vars = set()
|
||||||
|
stat_vars = set() # Para flancos, si se implementan completamente
|
||||||
|
# Usar regex para encontrar variables _temp_... y stat_...
|
||||||
|
temp_pattern = re.compile(r'"?(_temp_[a-zA-Z0-9_]+)"?')
|
||||||
|
stat_pattern = re.compile(r'"?(stat_[a-zA-Z0-9_]+)"?')
|
||||||
|
|
||||||
|
for network in data.get('networks', []):
|
||||||
|
for instruction in network.get('logic', []):
|
||||||
|
scl_code = instruction.get('scl', '')
|
||||||
|
if scl_code:
|
||||||
|
# Buscar temporales en el código SCL generado
|
||||||
|
found_temps = temp_pattern.findall(scl_code)
|
||||||
|
for temp_name in found_temps:
|
||||||
|
temp_vars.add(temp_name) # Añadir al set (evita duplicados)
|
||||||
|
# Buscar estáticas (para flancos)
|
||||||
|
found_stats = stat_pattern.findall(scl_code)
|
||||||
|
for stat_name in found_stats:
|
||||||
|
stat_vars.add(stat_name)
|
||||||
|
|
||||||
|
print(f"Variables temporales detectadas: {len(temp_vars)}")
|
||||||
|
# print(f"Variables estáticas detectadas (para flancos): {len(stat_vars)}")
|
||||||
|
|
||||||
|
# --- Construcción del String SCL ---
|
||||||
|
scl_output = []
|
||||||
|
|
||||||
|
# Cabecera del Bloque
|
||||||
|
scl_output.append(f"// Block Name (Original): {block_name}")
|
||||||
|
if block_number:
|
||||||
|
scl_output.append(f"// Block Number: {block_number}")
|
||||||
|
scl_output.append(f"// Original Language: {block_lang}")
|
||||||
|
if block_comment:
|
||||||
|
scl_output.append(f"// Block Comment: {block_comment}")
|
||||||
|
scl_output.append("")
|
||||||
|
scl_output.append(f"FUNCTION_BLOCK \"{scl_block_name}\"") # Asumir FB por variables Temp/Stat
|
||||||
|
scl_output.append("{ S7_Optimized_Access := 'TRUE' }") # Opcional, común
|
||||||
|
scl_output.append("VERSION : 0.1") # Opcional
|
||||||
|
scl_output.append("")
|
||||||
|
|
||||||
|
# Declaraciones de Interfaz
|
||||||
|
scl_output.append("VAR_INPUT")
|
||||||
|
# Iterar sobre data['interface']['Input'] si existe
|
||||||
|
# for var in data.get('interface', {}).get('Input', []):
|
||||||
|
# scl_output.append(f" {format_variable_name(var['name'])} : {var['datatype']};")
|
||||||
|
scl_output.append("END_VAR")
|
||||||
|
scl_output.append("")
|
||||||
|
|
||||||
|
scl_output.append("VAR_OUTPUT")
|
||||||
|
# Iterar sobre data['interface']['Output'] si existe
|
||||||
|
# for var in data.get('interface', {}).get('Output', []):
|
||||||
|
# scl_output.append(f" {format_variable_name(var['name'])} : {var['datatype']};")
|
||||||
|
scl_output.append("END_VAR")
|
||||||
|
scl_output.append("")
|
||||||
|
|
||||||
|
scl_output.append("VAR_IN_OUT")
|
||||||
|
# Iterar sobre data['interface']['InOut'] si existe
|
||||||
|
# for var in data.get('interface', {}).get('InOut', []):
|
||||||
|
# scl_output.append(f" {format_variable_name(var['name'])} : {var['datatype']};")
|
||||||
|
scl_output.append("END_VAR")
|
||||||
|
scl_output.append("")
|
||||||
|
|
||||||
|
# Declaraciones Estáticas (para flancos)
|
||||||
|
if stat_vars:
|
||||||
|
scl_output.append("VAR_STAT")
|
||||||
|
# Asumir Bool para flancos, se podría inferir mejor si PBox lo indicara
|
||||||
|
for var_name in sorted(list(stat_vars)):
|
||||||
|
scl_output.append(f" \"{var_name}\" : Bool; // Memory for edge detection")
|
||||||
|
scl_output.append("END_VAR")
|
||||||
|
scl_output.append("")
|
||||||
|
|
||||||
|
# Declaraciones Temporales
|
||||||
|
# Incluir las variables de la sección Temp del JSON original
|
||||||
|
# y las generadas automáticamente (_temp_...)
|
||||||
|
scl_output.append("VAR_TEMP")
|
||||||
|
declared_temps = set()
|
||||||
|
interface_temps = data.get('interface', {}).get('Temp', [])
|
||||||
|
if interface_temps:
|
||||||
|
for var in interface_temps:
|
||||||
|
formatted_name = format_variable_name(var['name'])
|
||||||
|
# Añadir comillas si el nombre original las tenía o si contiene caracteres especiales
|
||||||
|
scl_name = f'"{formatted_name}"' if '"' in var['name'] or '.' in var['name'] else formatted_name
|
||||||
|
scl_output.append(f" {scl_name} : {var['datatype']};")
|
||||||
|
declared_temps.add(scl_name) # Marcar como declarada
|
||||||
|
|
||||||
|
# Declarar las _temp_ generadas si no estaban ya en la interfaz Temp
|
||||||
|
if temp_vars:
|
||||||
|
# Intentar inferir tipo (difícil sin más info), por ahora usar Variant o Bool/DInt
|
||||||
|
for var_name in sorted(list(temp_vars)):
|
||||||
|
scl_name = f'"{var_name}"' # Asegurar comillas para _temp_
|
||||||
|
if scl_name not in declared_temps:
|
||||||
|
# Inferencia básica de tipo por nombre de pin (muy heurístico)
|
||||||
|
inferred_type = "Variant" # Tipo seguro por defecto
|
||||||
|
if var_name.endswith("_out"): # Salida de bloque lógico/comparación?
|
||||||
|
inferred_type = "Bool"
|
||||||
|
elif var_name.endswith("_out_num"): # Salida de bloque numérico?
|
||||||
|
inferred_type = "DInt" # O Real? O Int? Difícil saber
|
||||||
|
# Se podría mejorar si los procesadores añadieran info de tipo
|
||||||
|
scl_output.append(f" {scl_name} : {inferred_type}; // Auto-generated temporary")
|
||||||
|
declared_temps.add(scl_name) # Marcar como declarada
|
||||||
|
scl_output.append("END_VAR")
|
||||||
|
scl_output.append("")
|
||||||
|
|
||||||
|
# Cuerpo del Bloque
|
||||||
|
scl_output.append("BEGIN")
|
||||||
|
scl_output.append("")
|
||||||
|
|
||||||
|
# Iterar por redes y lógica
|
||||||
|
for i, network in enumerate(data.get('networks', [])):
|
||||||
|
network_title = network.get('title', f'Network {network.get("id")}')
|
||||||
|
network_comment = network.get('comment', '')
|
||||||
|
scl_output.append(f" // Network {i+1}: {network_title}")
|
||||||
|
if network_comment:
|
||||||
|
# Añadir comentario de red indentado
|
||||||
|
for line in network_comment.splitlines():
|
||||||
|
scl_output.append(f" // {line}")
|
||||||
|
scl_output.append("") # Línea en blanco antes del código de la red
|
||||||
|
|
||||||
|
network_has_code = False
|
||||||
|
for instruction in network.get('logic', []):
|
||||||
|
scl_code = instruction.get('scl')
|
||||||
|
if scl_code:
|
||||||
|
network_has_code = True
|
||||||
|
# Indentar y añadir el código SCL de la instrucción
|
||||||
|
# Quitar comentarios "// RLO updated..." o "// Comparison..."
|
||||||
|
# ya que el código SCL resultante es la representación final.
|
||||||
|
# Mantener comentarios de PBox por claridad.
|
||||||
|
is_rlo_update_comment = scl_code.strip().startswith("// RLO updated")
|
||||||
|
is_comparison_comment = scl_code.strip().startswith("// Comparison")
|
||||||
|
is_logic_o_comment = scl_code.strip().startswith("// Logic O")
|
||||||
|
|
||||||
|
if not (is_rlo_update_comment or is_comparison_comment or is_logic_o_comment) or "PBox" in scl_code :
|
||||||
|
for line in scl_code.splitlines():
|
||||||
|
scl_output.append(f" {line}") # Indentación de 2 espacios
|
||||||
|
|
||||||
|
if network_has_code:
|
||||||
|
scl_output.append("") # Añadir línea en blanco después del código de la red
|
||||||
|
|
||||||
|
scl_output.append("END_FUNCTION_BLOCK")
|
||||||
|
|
||||||
|
# --- Escritura del Archivo SCL ---
|
||||||
|
print(f"Escribiendo archivo SCL en: {output_scl_filepath}")
|
||||||
|
try:
|
||||||
|
with open(output_scl_filepath, 'w', encoding='utf-8') as f:
|
||||||
|
for line in scl_output:
|
||||||
|
f.write(line + '\n')
|
||||||
|
print("Generación de SCL completada.")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error al escribir el archivo SCL: {e}")
|
||||||
|
|
||||||
|
# --- Ejecución ---
|
||||||
|
if __name__ == "__main__":
|
||||||
|
input_json_file = 'BlenderRun_ProdTime_simplified_scl_processed.json' # Usar el JSON procesado
|
||||||
|
output_scl_file = input_json_file.replace('_simplified_scl_processed.json', '.scl') # Nombre de salida
|
||||||
|
|
||||||
|
generate_scl(input_json_file, output_scl_file)
|
Loading…
Reference in New Issue